@protobase/server 0.49.0 → 0.49.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/better-auth/auth-settings.d.ts +19 -0
- package/dist/better-auth/create-auth.d.ts +28 -0
- package/dist/better-auth/create-auth.js +12 -2
- package/dist/better-auth/secret-versions.d.ts +7 -0
- package/dist/better-auth/secret-versions.js +21 -0
- package/dist/better-auth/signing-keys.js +86 -0
- package/dist/better-auth/tokens.js +1 -0
- package/dist/files/store-file.d.ts +14 -2
- package/dist/files/store-file.js +8 -1
- package/dist/gotrue/sessions-plugin.js +3 -9
- package/dist/index.d.ts +2 -2
- package/dist/internal.js +1 -1
- package/dist/jobs/declared-job.d.ts +37 -2
- package/dist/jobs/declared-job.js +2 -1
- package/dist/jobs/job-types.d.ts +1 -1
- package/dist/package.js +1 -1
- package/package.json +4 -4
|
@@ -5,6 +5,7 @@ import { StaffSignIn } from "./staff-log.js";
|
|
|
5
5
|
import { RoleDefinitions } from "./organizations/role-definitions.js";
|
|
6
6
|
import { ConnectedApp } from "./mcp/connected-apps.js";
|
|
7
7
|
import { ReplacingContext } from "./end-replaced-session.js";
|
|
8
|
+
import { VersionedSecret } from "./secret-versions.js";
|
|
8
9
|
import { UserDeletionListener } from "./user-deletion.js";
|
|
9
10
|
import { OrganizationRole, StoredMember, StoredOrganization } from "./organizations/store.js";
|
|
10
11
|
import { OrganizationsOptions, ResolvedOrganizations } from "./organizations/options.js";
|
|
@@ -1090,6 +1091,8 @@ export declare const buildAppAuth: (settings: AuthSettings, input: AppAuthInput)
|
|
|
1090
1091
|
};
|
|
1091
1092
|
};
|
|
1092
1093
|
jwks: {
|
|
1094
|
+
rotationInterval: number;
|
|
1095
|
+
gracePeriod: number;
|
|
1093
1096
|
keyPairConfigs: {
|
|
1094
1097
|
readonly alg: "ES256";
|
|
1095
1098
|
}[];
|
|
@@ -1352,6 +1355,21 @@ export declare const buildAppAuth: (settings: AuthSettings, input: AppAuthInput)
|
|
|
1352
1355
|
};
|
|
1353
1356
|
};
|
|
1354
1357
|
};
|
|
1358
|
+
} | {
|
|
1359
|
+
id: "protobase-signing-keys";
|
|
1360
|
+
endpoints: {
|
|
1361
|
+
ensureSigningKey: import("better-call").StrictEndpoint<string, {
|
|
1362
|
+
method: "POST";
|
|
1363
|
+
}, {
|
|
1364
|
+
ok: boolean;
|
|
1365
|
+
}>;
|
|
1366
|
+
};
|
|
1367
|
+
hooks: {
|
|
1368
|
+
before: {
|
|
1369
|
+
matcher: (ctx: import("better-auth").HookEndpointContext) => boolean;
|
|
1370
|
+
handler: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>>;
|
|
1371
|
+
}[];
|
|
1372
|
+
};
|
|
1355
1373
|
} | {
|
|
1356
1374
|
hooks: {
|
|
1357
1375
|
after: {
|
|
@@ -8683,6 +8701,7 @@ export declare const buildAppAuth: (settings: AuthSettings, input: AppAuthInput)
|
|
|
8683
8701
|
};
|
|
8684
8702
|
basePath: string;
|
|
8685
8703
|
secret: string;
|
|
8704
|
+
secrets: VersionedSecret[];
|
|
8686
8705
|
trustedOrigins: string[] | ((request?: Request) => string[]);
|
|
8687
8706
|
emailAndPassword: {
|
|
8688
8707
|
onPasswordReset?: ((data: {
|
|
@@ -5,6 +5,7 @@ import { StaffSignIn } from "./staff-log.js";
|
|
|
5
5
|
import { RoleDefinitions, RolesInput } from "./organizations/role-definitions.js";
|
|
6
6
|
import { ConnectedApp } from "./mcp/connected-apps.js";
|
|
7
7
|
import { ReplacingContext } from "./end-replaced-session.js";
|
|
8
|
+
import { VersionedSecret } from "./secret-versions.js";
|
|
8
9
|
import { UserDeletionListener } from "./user-deletion.js";
|
|
9
10
|
import { OrganizationRole } from "./organizations/store.js";
|
|
10
11
|
import { OrganizationsOptions, ResolvedOrganizations } from "./organizations/options.js";
|
|
@@ -48,6 +49,15 @@ export type CreateAuthOptions = {
|
|
|
48
49
|
appName?: string;
|
|
49
50
|
/** Signs cookies and encrypts the JWT private keys. Generate with `openssl rand -base64 32`. */
|
|
50
51
|
secret: string;
|
|
52
|
+
/**
|
|
53
|
+
* The secrets the app had before `secret`, newest first, such as `PROTOBASE_PREVIOUS_SECRETS`: what they encrypted
|
|
54
|
+
* still decrypts, so the signing keys keep signing after the secret changes. Default none.
|
|
55
|
+
*/
|
|
56
|
+
previousSecrets?: string[];
|
|
57
|
+
/** Days a token signing key signs before a new one takes over; default 30. */
|
|
58
|
+
signingKeyDays?: number;
|
|
59
|
+
/** Days a replaced signing key still verifies the tokens it signed; default 7, at least 1. */
|
|
60
|
+
signingKeyGraceDays?: number;
|
|
51
61
|
/** Extra origins that may call the auth endpoints, such as the exact host of a dev tunnel. `baseURL` and `origins` are always trusted. */
|
|
52
62
|
trustedOrigins?: string[];
|
|
53
63
|
/**
|
|
@@ -1200,6 +1210,8 @@ export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlug
|
|
|
1200
1210
|
};
|
|
1201
1211
|
};
|
|
1202
1212
|
jwks: {
|
|
1213
|
+
rotationInterval: number;
|
|
1214
|
+
gracePeriod: number;
|
|
1203
1215
|
keyPairConfigs: {
|
|
1204
1216
|
readonly alg: "ES256";
|
|
1205
1217
|
}[];
|
|
@@ -1462,6 +1474,21 @@ export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlug
|
|
|
1462
1474
|
};
|
|
1463
1475
|
};
|
|
1464
1476
|
};
|
|
1477
|
+
} | {
|
|
1478
|
+
id: "protobase-signing-keys";
|
|
1479
|
+
endpoints: {
|
|
1480
|
+
ensureSigningKey: import("better-call").StrictEndpoint<string, {
|
|
1481
|
+
method: "POST";
|
|
1482
|
+
}, {
|
|
1483
|
+
ok: boolean;
|
|
1484
|
+
}>;
|
|
1485
|
+
};
|
|
1486
|
+
hooks: {
|
|
1487
|
+
before: {
|
|
1488
|
+
matcher: (ctx: import("better-auth").HookEndpointContext) => boolean;
|
|
1489
|
+
handler: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>>;
|
|
1490
|
+
}[];
|
|
1491
|
+
};
|
|
1465
1492
|
} | {
|
|
1466
1493
|
hooks: {
|
|
1467
1494
|
after: {
|
|
@@ -8787,6 +8814,7 @@ export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlug
|
|
|
8787
8814
|
};
|
|
8788
8815
|
basePath: string;
|
|
8789
8816
|
secret: string;
|
|
8817
|
+
secrets: VersionedSecret[];
|
|
8790
8818
|
trustedOrigins: string[] | ((request?: Request) => string[]);
|
|
8791
8819
|
emailAndPassword: {
|
|
8792
8820
|
onPasswordReset?: ((data: {
|
|
@@ -30,6 +30,8 @@ import { coreNames, pluginNames } from "./snake-case-names.js";
|
|
|
30
30
|
import { passkeyPlugin } from "./passkey-plugin.js";
|
|
31
31
|
import { passwordResetOptions } from "./password-reset.js";
|
|
32
32
|
import { rolesPlugin } from "./roles/roles-plugin.js";
|
|
33
|
+
import { versionedSecrets } from "./secret-versions.js";
|
|
34
|
+
import { signingKeyRotation, signingKeys } from "./signing-keys.js";
|
|
33
35
|
import { platformSignInFor, platformSignInProvider, readPlatformSignIn, resolvePlatformSignIn } from "./platform-sign-in.js";
|
|
34
36
|
import { appSignInPolicy } from "./app-sign-in-policy.js";
|
|
35
37
|
import { assertNoEndpointKeyClashes } from "./endpoint-key-clashes.js";
|
|
@@ -110,7 +112,10 @@ const betterAuthOptions = (options, { origins = [], passkeyDomain, roles, defini
|
|
|
110
112
|
};
|
|
111
113
|
const jwtOptions = {
|
|
112
114
|
schema: pluginNames.jwt,
|
|
113
|
-
jwks: {
|
|
115
|
+
jwks: {
|
|
116
|
+
keyPairConfigs: [goTrueKeyPair],
|
|
117
|
+
...signingKeyRotation(options)
|
|
118
|
+
},
|
|
114
119
|
jwt: {
|
|
115
120
|
expirationTime: tokenLifetime,
|
|
116
121
|
issuer: options.baseURL,
|
|
@@ -130,6 +135,8 @@ const betterAuthOptions = (options, { origins = [], passkeyDomain, roles, defini
|
|
|
130
135
|
},
|
|
131
136
|
disableSettingJwtHeader: true
|
|
132
137
|
};
|
|
138
|
+
const keys = signingKeys(jwtOptions);
|
|
139
|
+
const { secrets, legacySecret } = versionedSecrets(options.secret, options.previousSecrets);
|
|
133
140
|
const trusted = [
|
|
134
141
|
options.baseURL,
|
|
135
142
|
...origins,
|
|
@@ -146,7 +153,8 @@ const betterAuthOptions = (options, { origins = [], passkeyDomain, roles, defini
|
|
|
146
153
|
logger: authLogger,
|
|
147
154
|
baseURL: multiHostBaseURL(options.baseURL, origins),
|
|
148
155
|
basePath: authBasePath,
|
|
149
|
-
secret:
|
|
156
|
+
secret: legacySecret,
|
|
157
|
+
secrets,
|
|
150
158
|
trustedOrigins: mobile ? (request) => [...trusted, ...mobile.trusted(request)] : trusted,
|
|
151
159
|
emailAndPassword: {
|
|
152
160
|
enabled: true,
|
|
@@ -175,6 +183,7 @@ const betterAuthOptions = (options, { origins = [], passkeyDomain, roles, defini
|
|
|
175
183
|
roles: Object.fromEntries(roles.map((role) => [role, role === "admin" ? adminAc : userAc]))
|
|
176
184
|
}),
|
|
177
185
|
jwt(jwtOptions),
|
|
186
|
+
keys.plugin,
|
|
178
187
|
twoFactorAfterPasswordOrCode({
|
|
179
188
|
schema: pluginNames.twoFactor,
|
|
180
189
|
allowPasswordless: true,
|
|
@@ -201,6 +210,7 @@ const betterAuthOptions = (options, { origins = [], passkeyDomain, roles, defini
|
|
|
201
210
|
goTrueSessionsPlugin({
|
|
202
211
|
issuer: goTrueIssuer(options.baseURL),
|
|
203
212
|
jwt: jwtOptions,
|
|
213
|
+
signingKey: keys.ensure,
|
|
204
214
|
policy
|
|
205
215
|
}),
|
|
206
216
|
staffSignInPlugin({
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
//#region src/better-auth/secret-versions.ts
|
|
3
|
+
const versionOf = (secret) => Number.parseInt(createHash("sha256").update(`protobase-secret-version:${secret}`).digest("hex").slice(0, 7), 16);
|
|
4
|
+
/**
|
|
5
|
+
* Better Auth's options for the app's `secret` and its `previousSecrets`: `secrets`, which encrypt with the current
|
|
6
|
+
* one and decrypt with any of them, and `secret`, which Better Auth keeps for what was encrypted before secrets had
|
|
7
|
+
* versions. That is the oldest secret listed: the one in use when the app last ran without versions, unless it was
|
|
8
|
+
* changed since without being listed.
|
|
9
|
+
*/
|
|
10
|
+
const versionedSecrets = (secret, previousSecrets = []) => {
|
|
11
|
+
const all = [.../* @__PURE__ */ new Set([secret, ...previousSecrets])];
|
|
12
|
+
return {
|
|
13
|
+
secrets: all.map((value) => ({
|
|
14
|
+
version: versionOf(value),
|
|
15
|
+
value
|
|
16
|
+
})),
|
|
17
|
+
legacySecret: all.at(-1)
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { versionedSecrets };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createAuthEndpoint, createAuthMiddleware } from "better-auth/api";
|
|
2
|
+
import { createJwk } from "better-auth/plugins";
|
|
3
|
+
const daySeconds = 86400;
|
|
4
|
+
/** The JWT plugin's rotation for `options`: `rotationInterval` and `gracePeriod`, in seconds. */
|
|
5
|
+
const signingKeyRotation = ({ signingKeyDays = 30, signingKeyGraceDays = 7 } = {}) => {
|
|
6
|
+
if (!(signingKeyDays > 0)) throw new Error("signingKeyDays must be more than 0");
|
|
7
|
+
if (!(signingKeyGraceDays >= 1)) throw new Error("signingKeyGraceDays must be at least 1: tokens of `protobase token` last up to a day");
|
|
8
|
+
return {
|
|
9
|
+
rotationInterval: Math.round(signingKeyDays * daySeconds),
|
|
10
|
+
gracePeriod: Math.round(signingKeyGraceDays * daySeconds)
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
const isPrimary = (key) => key.alg === null || key.alg === void 0 || key.alg === "EdDSA";
|
|
14
|
+
const marginMs = 6e4;
|
|
15
|
+
const signingPaths = /* @__PURE__ */ new Set(["/token", "/oauth2/token"]);
|
|
16
|
+
/**
|
|
17
|
+
* Keeps a live EdDSA key for the app's tokens. The JWT plugin signs with the newest live key of the primary algorithm,
|
|
18
|
+
* else with the newest live key of any: once the EdDSA key expired while the ES256 one of the GoTrue-compatible
|
|
19
|
+
* tokens still lived, it would sign the app's tokens ES256 until that one expired too. So before every signing, a new
|
|
20
|
+
* EdDSA key is made when none lives; a key made before rotation was on (without an expiry) gets the one it would have
|
|
21
|
+
* had, its creation plus the rotation interval, so it rotates too. A key past its grace period, which no longer
|
|
22
|
+
* verifies, is deleted, so the store keeps a few keys (Better Auth reads at most 100). The key set is read once per
|
|
23
|
+
* key's lifetime: until the newest EdDSA key expires, signing reads nothing more.
|
|
24
|
+
*/
|
|
25
|
+
const signingKeys = (jwt) => {
|
|
26
|
+
const intervalMs = jwt.jwks.rotationInterval * 1e3;
|
|
27
|
+
const graceMs = jwt.jwks.gracePeriod * 1e3;
|
|
28
|
+
let liveUntil = 0;
|
|
29
|
+
let pending;
|
|
30
|
+
const check = async (ctx) => {
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
const { adapter } = ctx.context;
|
|
33
|
+
const dated = (await adapter.findMany({ model: "jwks" })).map((key) => ({
|
|
34
|
+
...key,
|
|
35
|
+
undated: !key.expiresAt,
|
|
36
|
+
expiresAt: key.expiresAt ?? new Date(key.createdAt.getTime() + intervalMs)
|
|
37
|
+
}));
|
|
38
|
+
const retired = dated.filter((key) => key.expiresAt.getTime() + graceMs <= now);
|
|
39
|
+
if (retired.length > 0) await adapter.deleteMany({
|
|
40
|
+
model: "jwks",
|
|
41
|
+
where: [{
|
|
42
|
+
field: "id",
|
|
43
|
+
operator: "in",
|
|
44
|
+
value: retired.map((key) => key.id)
|
|
45
|
+
}]
|
|
46
|
+
});
|
|
47
|
+
const keys = dated.filter((key) => !retired.includes(key));
|
|
48
|
+
await Promise.all(keys.filter((key) => key.undated).map((key) => adapter.update({
|
|
49
|
+
model: "jwks",
|
|
50
|
+
where: [{
|
|
51
|
+
field: "id",
|
|
52
|
+
value: key.id
|
|
53
|
+
}],
|
|
54
|
+
update: { expiresAt: key.expiresAt }
|
|
55
|
+
})));
|
|
56
|
+
liveUntil = (keys.filter((key) => isPrimary(key) && key.expiresAt.getTime() - marginMs > now).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())[0] ?? await createJwk(ctx, jwt)).expiresAt.getTime() - marginMs;
|
|
57
|
+
};
|
|
58
|
+
/** Makes sure a live EdDSA key signs the next token; concurrent callers share one check. */
|
|
59
|
+
const ensure = async (ctx) => {
|
|
60
|
+
if (Date.now() < liveUntil) return;
|
|
61
|
+
pending ??= check(ctx).finally(() => {
|
|
62
|
+
pending = void 0;
|
|
63
|
+
});
|
|
64
|
+
await pending;
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
plugin: {
|
|
68
|
+
id: "protobase-signing-keys",
|
|
69
|
+
endpoints: {
|
|
70
|
+
/** Makes sure a live EdDSA key signs the next token, for signing outside the plugin's paths (`issueToken`). */
|
|
71
|
+
ensureSigningKey: createAuthEndpoint.serverOnly({ method: "POST" }, async (ctx) => {
|
|
72
|
+
await ensure(ctx);
|
|
73
|
+
return ctx.json({ ok: true });
|
|
74
|
+
}) },
|
|
75
|
+
hooks: { before: [{
|
|
76
|
+
matcher: (ctx) => signingPaths.has(ctx.path ?? ""),
|
|
77
|
+
handler: createAuthMiddleware(async (ctx) => {
|
|
78
|
+
await ensure(ctx);
|
|
79
|
+
})
|
|
80
|
+
}] }
|
|
81
|
+
},
|
|
82
|
+
ensure
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
//#endregion
|
|
86
|
+
export { signingKeyRotation, signingKeys };
|
|
@@ -24,6 +24,7 @@ const issueToken = async (auth, options) => {
|
|
|
24
24
|
if (user.banned) throw new Error(`${options.email} is banned`);
|
|
25
25
|
const issuedAt = Math.floor(Date.now() / 1e3);
|
|
26
26
|
const { role } = narrowClaims({ role: parseRoles(user.role).join(",") }, [user.lastRole], Boolean(auth.organizations));
|
|
27
|
+
await auth.api.ensureSigningKey();
|
|
27
28
|
const { token } = await auth.api.signJWT({ body: { payload: {
|
|
28
29
|
iat: issuedAt,
|
|
29
30
|
exp: issuedAt + ttl,
|
|
@@ -1,13 +1,25 @@
|
|
|
1
|
+
import { FileProvider } from "./store.js";
|
|
1
2
|
import { FilesOptions } from "./options.js";
|
|
3
|
+
import { FileProviderSettings } from "./provider-settings.js";
|
|
2
4
|
//#region src/files/store-file.d.ts
|
|
5
|
+
/** A provider in `files.providers`: as the config writes it, or made. */
|
|
6
|
+
type ProviderEntry = FileProvider | FileProviderSettings | {
|
|
7
|
+
kind: 'custom';
|
|
8
|
+
};
|
|
3
9
|
export type StoreFileInput = {
|
|
4
10
|
/** The provider's name, as a stored value starts with it: `public` in `public:listings/house-1.png`. */
|
|
5
11
|
provider: string;
|
|
6
12
|
/** The path in the provider, such as `listings/house-1.png`. */
|
|
7
13
|
path: string;
|
|
8
14
|
body: Uint8Array | ReadableStream<Uint8Array>;
|
|
9
|
-
/**
|
|
10
|
-
|
|
15
|
+
/**
|
|
16
|
+
* `files` from `protobase.config.ts`, when it configures providers, as the config writes it (`{ kind: 'local', dir }`,
|
|
17
|
+
* `{ kind: 's3', bucket }`) or with its providers made; the environment's apply on top, as for the server.
|
|
18
|
+
*/
|
|
19
|
+
files?: Omit<FilesOptions, 'providers'> & {
|
|
20
|
+
providers?: Record<string, ProviderEntry>;
|
|
21
|
+
images?: string;
|
|
22
|
+
};
|
|
11
23
|
/** Where `PROTOBASE_FILES_<NAME>` and the credentials are read from, usually `process.env`. */
|
|
12
24
|
env: Record<string, string | undefined>;
|
|
13
25
|
};
|
package/dist/files/store-file.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { resolveProviders } from "./providers.js";
|
|
2
|
+
import { fileProviderOf } from "./provider-settings.js";
|
|
2
3
|
//#region src/files/store-file.ts
|
|
4
|
+
const providerOf = (name, entry) => {
|
|
5
|
+
if (!("kind" in entry)) return entry;
|
|
6
|
+
if (entry.kind === "custom") throw new Error(`files.providers.${name} is the default export of files/${name}.ts: import it and pass it in place of { kind: 'custom' }`);
|
|
7
|
+
return fileProviderOf(name, entry);
|
|
8
|
+
};
|
|
3
9
|
/**
|
|
4
10
|
* Writes a file into one of the app's providers outside a request, such as from a seed: the folder of a `file:`
|
|
5
11
|
* provider, the bucket of an `s3:` one, resolved as the server resolves them (`PROTOBASE_FILES_<NAME>`, else the
|
|
6
12
|
* config's, else `data/files/<name>` for `private` and `public`). A relative folder is taken from the working directory.
|
|
7
13
|
*/
|
|
8
14
|
const storeFile = async ({ provider, path, body, files = {}, env }) => {
|
|
9
|
-
const
|
|
15
|
+
const entry = files.providers?.[provider];
|
|
16
|
+
const providers = resolveProviders(entry ? { providers: { [provider]: providerOf(provider, entry) } } : {}, env, [provider]);
|
|
10
17
|
const stream = body instanceof ReadableStream ? body : new Blob([body]).stream();
|
|
11
18
|
return providers[provider].store.put(path, stream);
|
|
12
19
|
};
|
|
@@ -4,7 +4,7 @@ import { goTrueUser } from "./user-json.js";
|
|
|
4
4
|
import { accessClaims, goTrueSession } from "./session-json.js";
|
|
5
5
|
import * as z$1 from "zod";
|
|
6
6
|
import { APIError, createAuthEndpoint } from "better-auth/api";
|
|
7
|
-
import {
|
|
7
|
+
import { signJWT } from "better-auth/plugins";
|
|
8
8
|
import { generateRandomString } from "better-auth/crypto";
|
|
9
9
|
//#region src/gotrue/sessions-plugin.ts
|
|
10
10
|
const refreshTokenNotFound = () => new APIError("BAD_REQUEST", {
|
|
@@ -16,13 +16,7 @@ const refreshTokenNotFound = () => new APIError("BAD_REQUEST", {
|
|
|
16
16
|
* so signing out anywhere, a ban or a revoked session ends it, and refreshing gives the session a new token, so each
|
|
17
17
|
* refresh token works once. Server-side endpoints only, for `goTrueRoutes`.
|
|
18
18
|
*/
|
|
19
|
-
const goTrueSessionsPlugin = ({ issuer, jwt, policy }) => {
|
|
20
|
-
let primaryKeyMade = false;
|
|
21
|
-
const makePrimaryKey = async (ctx) => {
|
|
22
|
-
if (primaryKeyMade) return;
|
|
23
|
-
if (!(await ctx.context.adapter.findMany({ model: "jwks" })).some((key) => key.alg === null || key.alg === void 0 || key.alg === "EdDSA")) await createJwk(ctx, jwt);
|
|
24
|
-
primaryKeyMade = true;
|
|
25
|
-
};
|
|
19
|
+
const goTrueSessionsPlugin = ({ issuer, jwt, signingKey, policy }) => {
|
|
26
20
|
const sessionOf = async (ctx, sessionToken) => {
|
|
27
21
|
const found = await ctx.context.internalAdapter.findSession(sessionToken);
|
|
28
22
|
if (!found) throw refreshTokenNotFound();
|
|
@@ -31,7 +25,7 @@ const goTrueSessionsPlugin = ({ issuer, jwt, policy }) => {
|
|
|
31
25
|
if (refusal) throw new APIError("FORBIDDEN", refusal);
|
|
32
26
|
const accounts = await ctx.context.internalAdapter.findAccounts(user.id);
|
|
33
27
|
const now = Math.floor(Date.now() / 1e3);
|
|
34
|
-
await
|
|
28
|
+
await signingKey(ctx);
|
|
35
29
|
const accessToken = await signJWT(ctx, {
|
|
36
30
|
options: jwt,
|
|
37
31
|
payload: accessClaims({
|
package/dist/index.d.ts
CHANGED
|
@@ -154,7 +154,7 @@ import { FileRef, formatUri, variantPath } from "./files/uri.js";
|
|
|
154
154
|
import { aspectRatio, fileSize, fileType, imageSize, processor } from "./files/processors.js";
|
|
155
155
|
import { defineJob, isJobDefinition, jobDefinitions } from "./jobs/define-job.js";
|
|
156
156
|
import { FatalJobError } from "./jobs/run-job.js";
|
|
157
|
-
import { JobDeclaration, JobRun, enqueueJob } from "./jobs/declared-job.js";
|
|
157
|
+
import { ArgumentsPayload, EnqueueJob, JobDeclaration, JobName, JobPayload, JobRun, enqueueJob } from "./jobs/declared-job.js";
|
|
158
158
|
import { isSchedule } from "./jobs/schedule.js";
|
|
159
159
|
import { EmailComponent, EmailOptions, EmailTemplate, RenderedEmail, defineEmail } from "./mail/define-email.js";
|
|
160
160
|
import { DrainResult, JobsRuntime, StartJobsOptions, startJobs } from "./jobs/runtime.js";
|
|
@@ -164,4 +164,4 @@ import { MobileRelease, ReleaseFile, ServedReleaseFile, composeRelease, releaseM
|
|
|
164
164
|
import { MobileReleaseAppInput, OfferedRelease, mobileReleaseApp } from "./mobile-release/release-app.js";
|
|
165
165
|
import { mobileSigningKeyVariable, readSigningKey } from "./mobile-release/signing-key.js";
|
|
166
166
|
import { AdminAuth, CreateAuthOptions, UserCreatedHook, normalizeRoles } from "./better-auth/create-auth.js";
|
|
167
|
-
export { type Admin, type AdminAuth, type AdminOptions, type ApiFunction, type ApiKeys, type ApiKeysOptions, type ApnsEnvironment, type AppIcons, type AppIdentity, type AppPoolConfig, type ApplyOptions, type ApplyResult, type ApprovalAnswer, type ApprovalRequest, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type AuthHooks, type AuthSettings, type AuthenticateSettings, type Authenticator, type BatchOperation, type BatchResult, type BetterAuthAuthenticator, type BetterAuthAuthenticatorOptions, type Caller, type CallerOptions, type CapturedRow, type CascadingKey, type ChatMessage, type ChatTextPart, type CheckAiInput, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type CommentItem, type CommentUsers, type Completion, type CompletionOptions, ConnectionsBusy, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type Device, type DeviceColumn, type DeviceKind, type DeviceStore, DeviceStoreError, type DrainResult, type EmailComponent, type EmailOptions, type EmailTemplate, type EncryptionStatus, type EncryptionTools, type EncryptionToolsInput, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FieldApplied, type FieldStatus, type FileCleanupInput, type FileLimits, type FileObject, type FileProvider, type FileProviderSettings, type FileRef, type FileStore, type FileVariantObject, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSocket, type FunctionSource, type HistoryColumn, type HistoryOptions, type HistoryPosition, type HistoryStore, HistoryStoreError, type HookContext, HttpProblem, type IssueTokenOptions, type JobContext, type JobDeclaration, type JobDefinition, type JobOptions, type JobRun, type JobsRuntime, type JsonObject, type JsonValue, type JwtOptions, type JwtVerifyOptions, type KeyFunctionContext, type LinkedAccount, type ListParams, type LocalFilesOptions, type MailMessage, type Mailer, type MapLayer, type MapOptions, type MapSettings, type McpApprovals, type McpGateInput, type McpHandlerInput, type McpRoutesInput, type McpServerInput, type McpToolsInput, type McpWrites, type MemberInput, type Membership, MissingCredentials, type MobileConfig, type MobileRelease, type MobileReleaseAppInput, ModelError, type ModelSettings, type NewDevice, type NewNotification, type NewOrganization, type NewUser, type NotificationRecipients, NotificationSendError, type NotificationsOptions, type OfferedRelease, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PgModule, type PipelineHook, type PlatformSignIn, type PluginOption, type PluginRef, type PngIcon, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type PushAnswer, type PushMessage, PushMessageError, type PushSender, type QueryOptions, type QueryResult, type ReadableResources, type ReasoningDetail, type ReasoningEffort, type RebindOption, type RecordKeyInput, type RecordPage, type ReleaseFile, type RenderedEmail, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type S3Bucket, type S3FilesOptions, type S3ListPage, type S3Object, type ScanGuardMode, type ScheduledDelete, type SendNotification, type ServedReleaseFile, type Session, type SessionOrganization, type Sharp, type SignInPolicy, type SignInRule, type SignatureOptions, type SocketEvents, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StoreFileInput, type StoredMember, type StoredNotification, type StoredObject, type StoredOrganization, type StoredUser, type StrayValues, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolAnnotations, type ToolCall, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TrustedApp, type TurnOptions, type UnreadableEntry, type Urgency, type User, type UserCreatedHook, type VapidSettings, type ViewSource, type WebPushFields, type WebPushOptions, type WebhooksOptions, type WidgetOptions, type WriteEvent, type WriteOperation, type WriteRecordToolsInput, addAppRoleToOwners, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, capSocketMessages, changesMigration, checkAi, checkAuthSchema, checkChanges, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkResourcesOutsideAuthStore, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentsMigration, composeRelease, computedMigration, configExports, consoleAuditQueue, conversationKey, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, defineTool, deleteRecordTool, deleteUser, deviceIdParam, deviceStore, devicesPath, enqueueJob, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, generateVapidKeys, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, historyIdParam, historyIdPattern, historyLimits, historyPath, historyStore, honorSocketMessageCaps, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpRoutes, mcpServer, mcpToolContext, mcpTools, migrationCommand, mobileReleaseApp, mobileSigningKeyVariable, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notificationsMigration, oauthWellKnownPaths, objectKey, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readSigningKey, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, recordOf, releaseManifest, removeDevicesWithUsers, removeHistoryWithUsers, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, seesAssistant, seesRuntime, sendNotification, sessionOf, setMemberRoles, setUserBanned, setUserRole, shownAppName, signInPolicyMethods, socketMessageCapOf, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, writeRecordTools };
|
|
167
|
+
export { type Admin, type AdminAuth, type AdminOptions, type ApiFunction, type ApiKeys, type ApiKeysOptions, type ApnsEnvironment, type AppIcons, type AppIdentity, type AppPoolConfig, type ApplyOptions, type ApplyResult, type ApprovalAnswer, type ApprovalRequest, type ArgumentsPayload, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type AuthHooks, type AuthSettings, type AuthenticateSettings, type Authenticator, type BatchOperation, type BatchResult, type BetterAuthAuthenticator, type BetterAuthAuthenticatorOptions, type Caller, type CallerOptions, type CapturedRow, type CascadingKey, type ChatMessage, type ChatTextPart, type CheckAiInput, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type CommentItem, type CommentUsers, type Completion, type CompletionOptions, ConnectionsBusy, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type Device, type DeviceColumn, type DeviceKind, type DeviceStore, DeviceStoreError, type DrainResult, type EmailComponent, type EmailOptions, type EmailTemplate, type EncryptionStatus, type EncryptionTools, type EncryptionToolsInput, type EnqueueJob, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FieldApplied, type FieldStatus, type FileCleanupInput, type FileLimits, type FileObject, type FileProvider, type FileProviderSettings, type FileRef, type FileStore, type FileVariantObject, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSocket, type FunctionSource, type HistoryColumn, type HistoryOptions, type HistoryPosition, type HistoryStore, HistoryStoreError, type HookContext, HttpProblem, type IssueTokenOptions, type JobContext, type JobDeclaration, type JobDefinition, type JobName, type JobOptions, type JobPayload, type JobRun, type JobsRuntime, type JsonObject, type JsonValue, type JwtOptions, type JwtVerifyOptions, type KeyFunctionContext, type LinkedAccount, type ListParams, type LocalFilesOptions, type MailMessage, type Mailer, type MapLayer, type MapOptions, type MapSettings, type McpApprovals, type McpGateInput, type McpHandlerInput, type McpRoutesInput, type McpServerInput, type McpToolsInput, type McpWrites, type MemberInput, type Membership, MissingCredentials, type MobileConfig, type MobileRelease, type MobileReleaseAppInput, ModelError, type ModelSettings, type NewDevice, type NewNotification, type NewOrganization, type NewUser, type NotificationRecipients, NotificationSendError, type NotificationsOptions, type OfferedRelease, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PgModule, type PipelineHook, type PlatformSignIn, type PluginOption, type PluginRef, type PngIcon, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type PushAnswer, type PushMessage, PushMessageError, type PushSender, type QueryOptions, type QueryResult, type ReadableResources, type ReasoningDetail, type ReasoningEffort, type RebindOption, type RecordKeyInput, type RecordPage, type ReleaseFile, type RenderedEmail, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type S3Bucket, type S3FilesOptions, type S3ListPage, type S3Object, type ScanGuardMode, type ScheduledDelete, type SendNotification, type ServedReleaseFile, type Session, type SessionOrganization, type Sharp, type SignInPolicy, type SignInRule, type SignatureOptions, type SocketEvents, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StoreFileInput, type StoredMember, type StoredNotification, type StoredObject, type StoredOrganization, type StoredUser, type StrayValues, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolAnnotations, type ToolCall, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TrustedApp, type TurnOptions, type UnreadableEntry, type Urgency, type User, type UserCreatedHook, type VapidSettings, type ViewSource, type WebPushFields, type WebPushOptions, type WebhooksOptions, type WidgetOptions, type WriteEvent, type WriteOperation, type WriteRecordToolsInput, addAppRoleToOwners, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, capSocketMessages, changesMigration, checkAi, checkAuthSchema, checkChanges, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkResourcesOutsideAuthStore, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentsMigration, composeRelease, computedMigration, configExports, consoleAuditQueue, conversationKey, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, defineTool, deleteRecordTool, deleteUser, deviceIdParam, deviceStore, devicesPath, enqueueJob, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, generateVapidKeys, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, historyIdParam, historyIdPattern, historyLimits, historyPath, historyStore, honorSocketMessageCaps, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpRoutes, mcpServer, mcpToolContext, mcpTools, migrationCommand, mobileReleaseApp, mobileSigningKeyVariable, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notificationsMigration, oauthWellKnownPaths, objectKey, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readSigningKey, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, recordOf, releaseManifest, removeDevicesWithUsers, removeHistoryWithUsers, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, seesAssistant, seesRuntime, sendNotification, sessionOf, setMemberRoles, setUserBanned, setUserRole, shownAppName, signInPolicyMethods, socketMessageCapOf, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, writeRecordTools };
|
package/dist/internal.js
CHANGED
|
@@ -5,9 +5,9 @@ import { localFiles } from "./files/local-files.js";
|
|
|
5
5
|
import { s3Files } from "./files/s3-files.js";
|
|
6
6
|
import { appPool, longQueryPool } from "./app-pool.js";
|
|
7
7
|
import { betterAuthAuthenticator } from "./better-auth/authenticator.js";
|
|
8
|
+
import { fileProviderOf } from "./files/provider-settings.js";
|
|
8
9
|
import { declaredJob } from "./jobs/declared-job.js";
|
|
9
10
|
import { appAuthOptions, buildAppAuth } from "./better-auth/auth-settings.js";
|
|
10
11
|
import { buildAuthenticator } from "./better-auth/authenticate-settings.js";
|
|
11
|
-
import { fileProviderOf } from "./files/provider-settings.js";
|
|
12
12
|
import { webhooksModule } from "./webhooks/table/webhooks-module.js";
|
|
13
13
|
export { appAuthOptions, appPool, betterAuthAuthenticator, buildAppAuth, buildAuth, buildAuthenticator, checkNotificationsOptions, createAuth, declaredJob, fileProviderOf, isSubscription, loadAuthPlugins, localFiles, longQueryPool, s3Files, webhooksModule };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EnqueueOptions, JobContext, JobDefinition, JobOptions } from "./job-types.js";
|
|
2
|
-
import { ArgumentsSpec } from "@protobase/schema";
|
|
2
|
+
import { ArgumentType, ArgumentsSpec } from "@protobase/schema";
|
|
3
3
|
import { Db } from "@protobase/query";
|
|
4
4
|
//#region src/jobs/declared-job.d.ts
|
|
5
5
|
/**
|
|
@@ -18,7 +18,42 @@ export type JobRun<Payload = Record<string, unknown>> = (payload: Payload, conte
|
|
|
18
18
|
export declare const declaredJob: (name: string, { description: _, arguments: args, ...options }: JobDeclaration, load: () => Promise<JobRun>) => JobDefinition;
|
|
19
19
|
/**
|
|
20
20
|
* Enqueues the job named `name`, which the config declares, in `db`'s own transaction when it is one, and returns its
|
|
21
|
-
* id: what a write hook calls, so the job commits with the write or not at all.
|
|
21
|
+
* id: what a write hook calls, so the job commits with the write or not at all. `EnqueueJob<typeof config>` types it
|
|
22
|
+
* with the config's job names and arguments.
|
|
22
23
|
*/
|
|
23
24
|
export declare const enqueueJob: (db: Db, name: string, payload?: Record<string, unknown>, options?: EnqueueOptions) => Promise<string>;
|
|
25
|
+
type TypeValue<Type> = Type extends 'integer' ? number : Type extends 'boolean' ? boolean : Type extends 'json' ? unknown : string;
|
|
26
|
+
type ArgumentValue<Spec> = Spec extends ArgumentType ? TypeValue<Spec> : Spec extends {
|
|
27
|
+
type: 'enum';
|
|
28
|
+
values: readonly (infer Value)[];
|
|
29
|
+
} ? Value : Spec extends {
|
|
30
|
+
type: infer Type extends ArgumentType;
|
|
31
|
+
} ? TypeValue<Type> : unknown;
|
|
32
|
+
type Optional<Spec> = Spec extends {
|
|
33
|
+
optional: true;
|
|
34
|
+
} ? true : false;
|
|
35
|
+
type Flat<Type> = { [Key in keyof Type]: Type[Key]; };
|
|
36
|
+
/**
|
|
37
|
+
* The payload of a job with these arguments, as it is enqueued with it and its run gets it: `{ invoiceId: string }` for
|
|
38
|
+
* `{ invoiceId: 'bigint' }`, an argument with `optional: true` left out at will.
|
|
39
|
+
*/
|
|
40
|
+
export type ArgumentsPayload<Spec extends ArgumentsSpec> = Flat<{ -readonly [Name in keyof Spec as Optional<Spec[Name]> extends true ? never : Name]: ArgumentValue<Spec[Name]>; } & { -readonly [Name in keyof Spec as Optional<Spec[Name]> extends true ? Name : never]?: ArgumentValue<Spec[Name]>; }>;
|
|
41
|
+
type DeclaredJobs<Config> = (Config extends ((...args: never[]) => infer Returned) ? Awaited<Returned> : Config) extends {
|
|
42
|
+
jobs?: infer Jobs;
|
|
43
|
+
} ? NonNullable<Jobs> : never;
|
|
44
|
+
/** The names of the jobs a config declares, from `typeof config` of its `protobase.config.ts`. */
|
|
45
|
+
export type JobName<Config> = keyof DeclaredJobs<Config> & string;
|
|
46
|
+
/**
|
|
47
|
+
* The payload of the job `Name` a config declares, from its `arguments` (see `ArgumentsPayload`): what the job is
|
|
48
|
+
* enqueued with and what its `JobRun` gets. A job without `arguments` takes any payload, unchecked.
|
|
49
|
+
*/
|
|
50
|
+
export type JobPayload<Config, Name extends JobName<Config>> = DeclaredJobs<Config>[Name] extends {
|
|
51
|
+
arguments: infer Spec extends ArgumentsSpec;
|
|
52
|
+
} ? ArgumentsPayload<Spec> : Record<string, unknown>;
|
|
53
|
+
/**
|
|
54
|
+
* `enqueueJob`, typed with the jobs of a config, so a name it does not declare or a payload that does not fit its
|
|
55
|
+
* arguments fails to compile: `const enqueue: EnqueueJob<typeof config> = enqueueJob`. The payload may be left out when
|
|
56
|
+
* no argument is required.
|
|
57
|
+
*/
|
|
58
|
+
export type EnqueueJob<Config> = <Name extends JobName<Config>>(db: Db, name: Name, ...rest: {} extends JobPayload<Config, Name> ? [payload?: JobPayload<Config, Name>, options?: EnqueueOptions] : [payload: JobPayload<Config, Name>, options?: EnqueueOptions]) => Promise<string>;
|
|
24
59
|
//#endregion
|
|
@@ -14,7 +14,8 @@ const declaredJob = (name, { description: _, arguments: args, ...options }, load
|
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
16
|
* Enqueues the job named `name`, which the config declares, in `db`'s own transaction when it is one, and returns its
|
|
17
|
-
* id: what a write hook calls, so the job commits with the write or not at all.
|
|
17
|
+
* id: what a write hook calls, so the job commits with the write or not at all. `EnqueueJob<typeof config>` types it
|
|
18
|
+
* with the config's job names and arguments.
|
|
18
19
|
*/
|
|
19
20
|
const enqueueJob = (db, name, payload, options) => {
|
|
20
21
|
const runtime = currentJobs();
|
package/dist/jobs/job-types.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export type JobContext = {
|
|
|
17
17
|
};
|
|
18
18
|
/** Aborted when the job's timeout passes, or when the worker shuts down and its grace period ends. */
|
|
19
19
|
signal: AbortSignal;
|
|
20
|
-
/** Sends mail
|
|
20
|
+
/** Sends mail with the app's mailer: its auth/mailer.ts, else the SMTP server of `PROTOBASE_SMTP_URL` and `PROTOBASE_MAIL_FROM`; `undefined` when the app has no mail. */
|
|
21
21
|
mail?: Mailer;
|
|
22
22
|
/** Sends a notification as `sendNotification` does; `undefined` when the app has no `notifications`. */
|
|
23
23
|
sendNotification?: SendNotification;
|
package/dist/package.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/server",
|
|
3
|
-
"version": "0.49.
|
|
3
|
+
"version": "0.49.2",
|
|
4
4
|
"description": "The Protobase REST API as a Hono app, with Better Auth sign-in.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"@better-auth/passkey": "^1.7.12",
|
|
41
41
|
"@better-auth/sso": "^1.7.12",
|
|
42
42
|
"@modelcontextprotocol/server": "^2.3.1",
|
|
43
|
-
"@protobase/layout": "0.49.
|
|
44
|
-
"@protobase/query": "0.49.
|
|
45
|
-
"@protobase/schema": "0.49.
|
|
43
|
+
"@protobase/layout": "0.49.2",
|
|
44
|
+
"@protobase/query": "0.49.2",
|
|
45
|
+
"@protobase/schema": "0.49.2",
|
|
46
46
|
"@react-email/render": "^2.1.0",
|
|
47
47
|
"@scalar/hono-api-reference": "^0.12.10",
|
|
48
48
|
"@sentry/core": "^11.7.0",
|