Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"options": {
"typeAware": true,
"typeCheck": true
},
"env": {
"browser": true,
"es2026": true,
"es6": true,
"node": true
},
"plugins": ["import", "jsdoc", "jsx-a11y", "node", "promise"],
"rules": {
"eslint/capitalized-comments": [
"warn",
"always",
{ "ignoreConsecutiveComments": true }
],
"eslint/eqeqeq": ["off", "smart"],
"eslint/func-style": ["warn", "declaration"],
"eslint/id-length": ["warn", { "exceptionPatterns": ["^_", "^[Trtv]$"] }],
"eslint/init-declarations": "off",
"eslint/max-params": ["warn", { "max": 4 }],
"eslint/max-statements": ["warn", { "max": 20 }],
"eslint/no-console": "warn",
"eslint/no-use-before-define": "off",
"eslint/prefer-destructuring": ["warn", { "object": true, "array": false }],
"eslint/no-continue": "off",
"eslint/no-eq-null": "off",
"eslint/no-magic-numbers": "warn",
"eslint/no-ternary": "off",
"eslint/no-undefined": "off",
"eslint/no-void": "off",
"eslint/sort-keys": "off",
"eslint/sort-imports": [
"error",
{ "allowSeparatedGroups": true, "ignoreDeclarationSort": true }
],
"import/consistent-type-specifier-style": "off",
"import/exports-last": "off",
"import/group-exports": "off",
"import/no-default-export": "off",
"import/no-named-export": "off",
"import/no-namespace": [
"error",
{ "ignore": ["@fedify/vocab", "./schema.ts"] }
],
"import/no-nodejs-modules": "off",
"import/prefer-default-export": "off",
"jsdoc/require-param-type": "off",
"jsdoc/require-returns-type": "off",
"promise/avoid-new": "warn"
},
"categories": {
"correctness": "error",
"suspicious": "error",
"pedantic": "error",
"perf": "error",
"style": "error",
"restriction": "error",
"nursery": "error"
}
}
9 changes: 9 additions & 0 deletions mise.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
min_version = "2026.6.10"

[settings.npm]
package_manager = "pnpm"

[tools]
"aqua:dahlia/hongdown" = "0.4.3"
"github:nushell/nushell" = "latest"
node = "26"
"npm:@typescript/native-preview" = "7.0.0-dev.20260620.1"
"npm:oxlint" = "latest"
"npm:oxlint-tsgolint" = "latest"
"npm:pglite-cli" = "latest"
oxfmt = "0.55.0"
pnpm = "11"
Expand All @@ -23,6 +28,10 @@ depends = ["check:*"]
description = "Check TypeScript types"
run = "pnpm --recursive exec tsgo --noEmit"

[tasks."check:lint"]
description = "Check linting"
run = "oxlint"

[tasks."check:fmt"]
description = "Check formatting"
run = "oxfmt --check"
Expand Down
1 change: 1 addition & 0 deletions packages/drfed/bin/drfed-server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// oxlint-disable-next-line import/no-relative-parent-imports
import { main } from "../dist/index.mjs";

await main();
16 changes: 9 additions & 7 deletions packages/drfed/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,35 @@ import { migrate } from "@drfed/models";
import { run } from "@optique/run";
import { serve } from "srvx";

// oxlint-disable-next-line import/no-relative-parent-imports
import metadata from "../package.json" with { type: "json" };
import type { Options } from "./parser.ts";
import program from "./program.ts";

export async function main() {
const options: Options = run(program, {
help: "option",
showChoices: true,
showDefault: true,
version: {
value: metadata.version,
option: true,
value: metadata.version,
},
showChoices: true,
showDefault: true,
});
if (options.drizzle.migrate) {
await migrate({ credentials: options.drizzle.credentials });
}
const yogaServer = createYogaServer(options.drizzle.db);
const server = serve({
fetch: yogaServer.fetch.bind(yogaServer),
hostname: options.address.host,
port: options.address.port,
manual: true,
fetch: yogaServer.fetch.bind(yogaServer),
port: options.address.port,
});
const shutdown = () => {
function shutdown() {
// oxlint-disable-next-line promise/catch-or-return promise/prefer-await-to-then no-magic-numbers
server.close().then(() => process.exit(0));
};
}
process.once("SIGINT", shutdown);
process.once("SIGTERM", shutdown);
await server.serve();
Expand Down
30 changes: 15 additions & 15 deletions packages/drfed/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ const pgliteParser = map(
description: message`The path to the directory where the PGlite database files will be stored. Mutually exclusive with ${optionNames(["--postgres-url", "--database-url", "-D"])}.`,
},
),
(path) => ({
db: drizzlePglite({
schema,
relations,
connection: { dataDir: path },
}),
(dbPath) => ({
credentials: {
driver: "pglite" as const,
url: path,
url: dbPath,
},
db: drizzlePglite({
connection: { dataDir: dbPath },
relations,
schema,
}),
}),
);

Expand All @@ -57,17 +57,17 @@ const postgresParser = map(
description: message`The URL of the PostgreSQL database to connect to. Mutually exclusive with ${optionNames(["--pglite-data-path", "--data-path", "-d"])}.`,
},
),
(url) => ({
(dbUrl) => ({
credentials: {
url: dbUrl.href,
},
db: drizzlePostgres({
schema,
relations,
connection: {
connectionString: url.href,
connectionString: dbUrl.href,
},
relations,
schema,
}),
credentials: {
url: url.href,
},
}),
);

Expand All @@ -88,7 +88,7 @@ export const parser = object({
option("--no-migrate", "-M", {
description: message`Disable automatic database migrations.`,
}),
(m) => !m,
(noMigrate) => !noMigrate,
),
}),
),
Expand Down
4 changes: 2 additions & 2 deletions packages/drfed/src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import type { Program } from "@optique/core/program";
import parser from "./parser.ts";

const program: Program<"sync", InferValue<typeof parser>> = {
parser,
metadata: {
name: "drfed-server",
description: message`Run a DrFed server.`,
name: "drfed-server",
},
parser,
};

export default program;
1 change: 1 addition & 0 deletions packages/drfed/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"types": ["node"],
"paths": {
"@drfed/graphql": ["../graphql/src/index.ts"],
"@drfed/models": ["../models/src/index.ts"]
Expand Down
34 changes: 17 additions & 17 deletions packages/graphql/src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,46 +16,46 @@
import builder from "./builder.ts";

export const Account = builder.drizzleNode("accounts", {
name: "Account",
description:
"Represents an `Account` in the DrFed platform. " +
"Note that it differs from the ActivityPub `Actor`s that belong to `Instance`s.",
id: {
column(account) {
return account.id;
},
description: "The unique identifier of the `Account`.",
},
fields: (t) => ({
uuid: t.expose("id", {
type: "UUID",
description: "The UUID of the `Account`.",
created: t.expose("created", {
type: "DateTime",
description: "The date/time when the `Account` was created.",
}),
email: t.expose("email", {
type: "Email",
description: "The email address of the `Account`.",
}),
created: t.expose("created", {
type: "DateTime",
description: "The date/time when the `Account` was created.",
uuid: t.expose("id", {
type: "UUID",
description: "The UUID of the `Account`.",
}),
}),
id: {
column(account) {
return account.id;
},
description: "The unique identifier of the `Account`.",
},
name: "Account",
});

builder.queryFields((t) => ({
accountByUuid: t.drizzleField({
type: Account,
description: "Get an `Account` by its UUID.",
args: {
uuid: t.arg({
type: "UUID",
required: true,
description: "The UUID of the `Account` to retrieve.",
required: true,
type: "UUID",
}),
},
description: "Get an `Account` by its UUID.",
nullable: true,
resolve(query, _, { uuid }, ctx) {
return ctx.db.query.accounts.findFirst(query({ where: { id: uuid } }));
},
type: Account,
}),
}));
4 changes: 2 additions & 2 deletions packages/graphql/src/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ export interface SchemaTypes {
* The GraphQL schema builder.
*/
export const builder = new SchemaBuilder<SchemaTypes>({
plugins: [DrizzlePlugin, RelayPlugin],
defaultFieldNullability: false,
drizzle: {
client(ctx) {
Expand All @@ -76,13 +75,14 @@ export const builder = new SchemaBuilder<SchemaTypes>({
getTableConfig,
relations,
},
plugins: [DrizzlePlugin, RelayPlugin],
});

builder.addScalarType("DateTime", DateTimeResolver);

builder.scalarType("Email", {
serialize: (v) => normalizeEmail(v),
parseValue: (v) => normalizeEmail(String(v)),
serialize: (v) => normalizeEmail(v),
});

builder.addScalarType("UUID", UUIDResolver);
Expand Down
14 changes: 9 additions & 5 deletions packages/graphql/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import type { Database } from "@drfed/models";
import { createYoga, useExecutionCancellation } from "graphql-yoga";
import type { YogaServerInstance } from "graphql-yoga";
import {
type YogaServerInstance,
createYoga,
useExecutionCancellation,
} from "graphql-yoga";

import type { ServerContext, UserContext } from "./builder.ts";
import { schema } from "./schema.ts";
Expand All @@ -30,10 +33,11 @@ export function createYogaServer(
db: Database,
): YogaServerInstance<ServerContext, UserContext> {
return createYoga({
plugins: [useExecutionCancellation()],
schema,
// oxlint-disable-next-line require-await
async context(ctx) {
return { request: ctx.request, db };
return { db, request: ctx.request };
},
plugins: [useExecutionCancellation()],
schema,
});
}
24 changes: 12 additions & 12 deletions packages/graphql/src/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,23 @@
import builder from "./builder.ts";

export const Instance = builder.drizzleNode("instances", {
name: "Instance",
description: "Represents an `Instance` in the DrFed platform.",
id: {
column(instance) {
return instance.id;
},
description: "The unique identifier of the `Instance`.",
},
fields: (t) => ({
slug: t.exposeString("slug"),
expires: t.expose("expires", {
type: "DateTime",
description: "The expiration date/time of the `Instance`.",
}),
created: t.expose("created", {
type: "DateTime",
description: "The creation date/time of the `Instance`.",
}),
expires: t.expose("expires", {
type: "DateTime",
description: "The expiration date/time of the `Instance`.",
}),
slug: t.exposeString("slug"),
}),
id: {
column(instance) {
return instance.id;
},
description: "The unique identifier of the `Instance`.",
},
name: "Instance",
});
3 changes: 2 additions & 1 deletion packages/graphql/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// oxlint-disable import/no-unassigned-import
import "./account.ts";
import "./instance.ts";
import builder from "./builder.ts";

builder.queryType({});
// builder.mutationType({});
// Builder.mutationType({});

export const schema = builder.toSchema();
1 change: 1 addition & 0 deletions packages/graphql/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"types": ["node"],
"paths": {
"@drfed/models": ["../models/src/index.ts"]
}
Expand Down
Loading