@hot-updater/plugin-api-keys 1.0.0-rc.20

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.
@@ -0,0 +1,114 @@
1
+ //#region src/server/cli.ts
2
+ /** The environment variable init stores the app's API key in. */
3
+ const API_KEY_ENV = "HOT_UPDATER_API_KEY";
4
+ /** A new API key: 32 random bytes, base64url, as the plugin creates them. */
5
+ const generateApiKey = () => {
6
+ const bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(32));
7
+ return btoa(String.fromCharCode(...bytes)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
8
+ };
9
+ const formatList = (ui, records) => records.length === 0 ? ui.muted("(no API keys)") : ui.table([
10
+ {
11
+ key: "id",
12
+ label: "ID",
13
+ format: ui.id
14
+ },
15
+ {
16
+ key: "name",
17
+ label: "Name"
18
+ },
19
+ {
20
+ key: "prefix",
21
+ label: "Prefix",
22
+ format: ui.muted
23
+ },
24
+ {
25
+ key: "status",
26
+ label: "Status",
27
+ format: (value) => value.trim() === "active" ? ui.success(value) : ui.danger(value)
28
+ },
29
+ {
30
+ key: "created",
31
+ label: "Created",
32
+ format: ui.muted
33
+ }
34
+ ], records.map((record) => ({
35
+ created: new Date(record.created_at_ms).toISOString(),
36
+ id: record.id,
37
+ name: record.name,
38
+ prefix: record.prefix,
39
+ status: record.revoked_at_ms === null ? "active" : "revoked"
40
+ })));
41
+ /**
42
+ * `hot-updater api-key create|list|revoke`, and the API key that init
43
+ * provisions for an app, sent in `headerName`.
44
+ */
45
+ const apiKeysCli = (headerName) => ({
46
+ commands: [{
47
+ name: "api-key",
48
+ description: "Manage API keys",
49
+ commands: [
50
+ {
51
+ name: "create",
52
+ description: "Create an API key",
53
+ options: [{
54
+ flags: "--name <name>",
55
+ description: "name used to identify the API key",
56
+ required: true
57
+ }],
58
+ async run({ api, options, ui }) {
59
+ const created = await api.create({ name: String(options.name) });
60
+ ui.message(ui.block("API key created", [
61
+ ui.kv("Name", created.record.name),
62
+ ui.kv("ID", ui.id(created.record.id)),
63
+ ui.kv("API key", ui.warning(created.apiKey))
64
+ ]));
65
+ ui.warn("Save this API key now. It will not be shown again.");
66
+ }
67
+ },
68
+ {
69
+ name: "list",
70
+ description: "List API keys",
71
+ options: [{
72
+ flags: "--json",
73
+ description: "output API key metadata as JSON"
74
+ }],
75
+ async run({ api, options, ui }) {
76
+ const records = [...await api.list()].sort((left, right) => right.created_at_ms - left.created_at_ms);
77
+ if (options.json) ui.print(JSON.stringify(records, null, 2));
78
+ else ui.message(formatList(ui, records));
79
+ }
80
+ },
81
+ {
82
+ name: "revoke",
83
+ description: "Revoke an API key",
84
+ arguments: [{
85
+ name: "id",
86
+ description: "API key id"
87
+ }],
88
+ options: [{
89
+ flags: "-y, --yes",
90
+ description: "skip confirmation prompt"
91
+ }],
92
+ async run({ api, args, options, ui }) {
93
+ const id = String(args.id);
94
+ if (!options.yes) await ui.confirm(`Revoke API key ${id}?`);
95
+ const revoked = await api.revoke({ id });
96
+ if (revoked === null) throw new Error(`API key "${id}" was not found.`);
97
+ ui.message(ui.block("API key revoked", [ui.kv("Name", revoked.name), ui.kv("ID", ui.id(revoked.id))]));
98
+ }
99
+ }
100
+ ]
101
+ }],
102
+ clientCredential: {
103
+ label: "API key",
104
+ header: headerName,
105
+ env: API_KEY_ENV,
106
+ generate: generateApiKey,
107
+ provision: async (api, { existing, name }) => (await api.provision({
108
+ ...existing === void 0 ? {} : { existingApiKey: existing },
109
+ name
110
+ })).apiKey
111
+ }
112
+ });
113
+ //#endregion
114
+ export { API_KEY_ENV, apiKeysCli };
@@ -0,0 +1,55 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_apiKeys = require("./apiKeys.cjs");
3
+ const require_cli = require("./cli.cjs");
4
+ const require_model = require("./model.cjs");
5
+ const require_schema = require("./schema.cjs");
6
+ let _hot_updater_plugin_core_internal = require("@hot-updater/plugin-core/internal");
7
+ let _hot_updater_plugin_core_server_plugin = require("@hot-updater/plugin-core/server-plugin");
8
+ //#region src/server/index.ts
9
+ /**
10
+ * API keys: protects client routes with keys whose SHA-256 digests
11
+ * are stored, and manages them in-process.
12
+ */
13
+ const apiKeys = (options = {}) => {
14
+ const headerName = require_apiKeys.normalizeApiKeyHeaderName(options.headerName ?? "x-api-key");
15
+ const plugin = (0, _hot_updater_plugin_core_server_plugin.definePlugin)({
16
+ id: "apiKeys",
17
+ namespace: false,
18
+ provides: { clientAuth: true },
19
+ schemaVersion: "1.0.0",
20
+ schema: require_schema.apiKeysSchema,
21
+ init: ({ db }) => {
22
+ const model = require_model.createApiKeyModel(db);
23
+ return {
24
+ api: {
25
+ ...require_apiKeys.createApiKeyManagement({ apiKeys: model }),
26
+ /** Registers a known plaintext key idempotently, for managed init. */
27
+ register: (input) => require_apiKeys.registerApiKey({
28
+ ...input,
29
+ apiKeys: model
30
+ }),
31
+ /** Reuses a saved key or creates one, for managed init. */
32
+ provision: (input) => require_apiKeys.provisionApiKey({
33
+ ...input,
34
+ apiKeys: model
35
+ })
36
+ },
37
+ clientAuth: {
38
+ varyHeaders: [headerName],
39
+ authenticate: (headers) => require_apiKeys.authenticateApiKey({
40
+ apiKeys: model,
41
+ headerName,
42
+ request: { headers }
43
+ })
44
+ }
45
+ };
46
+ },
47
+ cli: require_cli.apiKeysCli(headerName)
48
+ });
49
+ return (0, _hot_updater_plugin_core_internal.markOfficial)(plugin);
50
+ };
51
+ //#endregion
52
+ exports.API_KEY_HEADER_NAME = require_apiKeys.API_KEY_HEADER_NAME;
53
+ exports.apiKeys = apiKeys;
54
+ exports.apiKeysSchema = require_schema.apiKeysSchema;
55
+ exports.createApiKeyModel = require_model.createApiKeyModel;
@@ -0,0 +1,81 @@
1
+ import { ApiKeysSchema, apiKeysSchema } from "./schema.cjs";
2
+ import { ApiKeyModel, ApiKeyRow, createApiKeyModel } from "./model.cjs";
3
+ import { API_KEY_HEADER_NAME, ApiKeyManagementAPI, ApiKeyMetadata, CreatedApiKey } from "./apiKeys.cjs";
4
+ //#region src/server/index.d.ts
5
+ interface ApiKeysOptions {
6
+ /** The request header that carries the key; defaults to `x-api-key`. */
7
+ readonly headerName?: string;
8
+ }
9
+ /**
10
+ * API keys: protects client routes with keys whose SHA-256 digests
11
+ * are stored, and manages them in-process.
12
+ */
13
+ declare const apiKeys: (options?: ApiKeysOptions) => import("@hot-updater/plugin-core/server-plugin").HotUpdaterPlugin<"apiKeys", {
14
+ readonly api_keys: import("@hot-updater/plugin-core/server-plugin").TableDefinition<{
15
+ readonly id: {
16
+ readonly type: "string";
17
+ readonly maxLength: 255;
18
+ };
19
+ readonly hash: {
20
+ readonly type: "string";
21
+ readonly maxLength: 64;
22
+ readonly unique: true;
23
+ };
24
+ readonly name: {
25
+ readonly type: "string";
26
+ readonly maxLength: 64;
27
+ };
28
+ readonly prefix: {
29
+ readonly type: "string";
30
+ readonly maxLength: 16;
31
+ };
32
+ readonly role: {
33
+ readonly type: "string";
34
+ readonly maxLength: 16;
35
+ };
36
+ readonly created_at_ms: {
37
+ readonly type: "integer";
38
+ };
39
+ readonly revoked_at_ms: {
40
+ readonly type: "integer";
41
+ readonly required: false;
42
+ };
43
+ }, {}, {
44
+ readonly byCreated: {
45
+ readonly eq: readonly [];
46
+ readonly sort: readonly ["created_at_ms"];
47
+ };
48
+ }, readonly ["id"]>;
49
+ }, {
50
+ api: {
51
+ /** Registers a known plaintext key idempotently, for managed init. */
52
+ register: (input: {
53
+ readonly apiKey: string;
54
+ readonly name: string;
55
+ readonly createdAtMs?: number;
56
+ }) => Promise<CreatedApiKey>;
57
+ /** Reuses a saved key or creates one, for managed init. */
58
+ provision: (input: {
59
+ readonly existingApiKey?: string;
60
+ readonly name: string;
61
+ }) => Promise<CreatedApiKey>;
62
+ create(input: {
63
+ readonly name: string;
64
+ }): Promise<{
65
+ readonly apiKey: string;
66
+ readonly record: ApiKeyMetadata;
67
+ }>;
68
+ list(): Promise<readonly ApiKeyMetadata[]>;
69
+ revoke(input: {
70
+ readonly id: string;
71
+ }): Promise<ApiKeyMetadata | null>;
72
+ };
73
+ clientAuth: {
74
+ varyHeaders: string[];
75
+ authenticate: (headers: Headers) => Promise<boolean>;
76
+ };
77
+ }, {
78
+ readonly clientAuth: true;
79
+ }>;
80
+ //#endregion
81
+ export { API_KEY_HEADER_NAME, type ApiKeyManagementAPI, type ApiKeyMetadata, type ApiKeyModel, type ApiKeyRow, ApiKeysOptions, type ApiKeysSchema, type CreatedApiKey, apiKeys, apiKeysSchema, createApiKeyModel };
@@ -0,0 +1,81 @@
1
+ import { ApiKeysSchema, apiKeysSchema } from "./schema.mjs";
2
+ import { ApiKeyModel, ApiKeyRow, createApiKeyModel } from "./model.mjs";
3
+ import { API_KEY_HEADER_NAME, ApiKeyManagementAPI, ApiKeyMetadata, CreatedApiKey } from "./apiKeys.mjs";
4
+ //#region src/server/index.d.ts
5
+ interface ApiKeysOptions {
6
+ /** The request header that carries the key; defaults to `x-api-key`. */
7
+ readonly headerName?: string;
8
+ }
9
+ /**
10
+ * API keys: protects client routes with keys whose SHA-256 digests
11
+ * are stored, and manages them in-process.
12
+ */
13
+ declare const apiKeys: (options?: ApiKeysOptions) => import("@hot-updater/plugin-core/server-plugin").HotUpdaterPlugin<"apiKeys", {
14
+ readonly api_keys: import("@hot-updater/plugin-core/server-plugin").TableDefinition<{
15
+ readonly id: {
16
+ readonly type: "string";
17
+ readonly maxLength: 255;
18
+ };
19
+ readonly hash: {
20
+ readonly type: "string";
21
+ readonly maxLength: 64;
22
+ readonly unique: true;
23
+ };
24
+ readonly name: {
25
+ readonly type: "string";
26
+ readonly maxLength: 64;
27
+ };
28
+ readonly prefix: {
29
+ readonly type: "string";
30
+ readonly maxLength: 16;
31
+ };
32
+ readonly role: {
33
+ readonly type: "string";
34
+ readonly maxLength: 16;
35
+ };
36
+ readonly created_at_ms: {
37
+ readonly type: "integer";
38
+ };
39
+ readonly revoked_at_ms: {
40
+ readonly type: "integer";
41
+ readonly required: false;
42
+ };
43
+ }, {}, {
44
+ readonly byCreated: {
45
+ readonly eq: readonly [];
46
+ readonly sort: readonly ["created_at_ms"];
47
+ };
48
+ }, readonly ["id"]>;
49
+ }, {
50
+ api: {
51
+ /** Registers a known plaintext key idempotently, for managed init. */
52
+ register: (input: {
53
+ readonly apiKey: string;
54
+ readonly name: string;
55
+ readonly createdAtMs?: number;
56
+ }) => Promise<CreatedApiKey>;
57
+ /** Reuses a saved key or creates one, for managed init. */
58
+ provision: (input: {
59
+ readonly existingApiKey?: string;
60
+ readonly name: string;
61
+ }) => Promise<CreatedApiKey>;
62
+ create(input: {
63
+ readonly name: string;
64
+ }): Promise<{
65
+ readonly apiKey: string;
66
+ readonly record: ApiKeyMetadata;
67
+ }>;
68
+ list(): Promise<readonly ApiKeyMetadata[]>;
69
+ revoke(input: {
70
+ readonly id: string;
71
+ }): Promise<ApiKeyMetadata | null>;
72
+ };
73
+ clientAuth: {
74
+ varyHeaders: string[];
75
+ authenticate: (headers: Headers) => Promise<boolean>;
76
+ };
77
+ }, {
78
+ readonly clientAuth: true;
79
+ }>;
80
+ //#endregion
81
+ export { API_KEY_HEADER_NAME, type ApiKeyManagementAPI, type ApiKeyMetadata, type ApiKeyModel, type ApiKeyRow, ApiKeysOptions, type ApiKeysSchema, type CreatedApiKey, apiKeys, apiKeysSchema, createApiKeyModel };
@@ -0,0 +1,51 @@
1
+ import { API_KEY_HEADER_NAME, authenticateApiKey, createApiKeyManagement, normalizeApiKeyHeaderName, provisionApiKey, registerApiKey } from "./apiKeys.mjs";
2
+ import { apiKeysCli } from "./cli.mjs";
3
+ import { createApiKeyModel } from "./model.mjs";
4
+ import { apiKeysSchema } from "./schema.mjs";
5
+ import { markOfficial } from "@hot-updater/plugin-core/internal";
6
+ import { definePlugin } from "@hot-updater/plugin-core/server-plugin";
7
+ //#region src/server/index.ts
8
+ /**
9
+ * API keys: protects client routes with keys whose SHA-256 digests
10
+ * are stored, and manages them in-process.
11
+ */
12
+ const apiKeys = (options = {}) => {
13
+ const headerName = normalizeApiKeyHeaderName(options.headerName ?? "x-api-key");
14
+ const plugin = definePlugin({
15
+ id: "apiKeys",
16
+ namespace: false,
17
+ provides: { clientAuth: true },
18
+ schemaVersion: "1.0.0",
19
+ schema: apiKeysSchema,
20
+ init: ({ db }) => {
21
+ const model = createApiKeyModel(db);
22
+ return {
23
+ api: {
24
+ ...createApiKeyManagement({ apiKeys: model }),
25
+ /** Registers a known plaintext key idempotently, for managed init. */
26
+ register: (input) => registerApiKey({
27
+ ...input,
28
+ apiKeys: model
29
+ }),
30
+ /** Reuses a saved key or creates one, for managed init. */
31
+ provision: (input) => provisionApiKey({
32
+ ...input,
33
+ apiKeys: model
34
+ })
35
+ },
36
+ clientAuth: {
37
+ varyHeaders: [headerName],
38
+ authenticate: (headers) => authenticateApiKey({
39
+ apiKeys: model,
40
+ headerName,
41
+ request: { headers }
42
+ })
43
+ }
44
+ };
45
+ },
46
+ cli: apiKeysCli(headerName)
47
+ });
48
+ return markOfficial(plugin);
49
+ };
50
+ //#endregion
51
+ export { API_KEY_HEADER_NAME, apiKeys, apiKeysSchema, createApiKeyModel };
@@ -0,0 +1,58 @@
1
+ let _hot_updater_plugin_core_server_plugin = require("@hot-updater/plugin-core/server-plugin");
2
+ //#region src/server/model.ts
3
+ const toRow = (row) => ({
4
+ id: row.id,
5
+ hash: row.hash,
6
+ name: row.name,
7
+ prefix: row.prefix,
8
+ role: row.role,
9
+ created_at_ms: row.created_at_ms,
10
+ revoked_at_ms: row.revoked_at_ms
11
+ });
12
+ /** Today's `ApiKeyModel` on the engine: one unique read by hash, keyed writes. */
13
+ const createApiKeyModel = (db) => ({
14
+ async create(row) {
15
+ try {
16
+ return await db.transaction(async (tx) => {
17
+ if (await tx.findOne("api_keys", { hash: row.hash }) !== null) return "existing";
18
+ tx.create("api_keys", row);
19
+ return "created";
20
+ });
21
+ } catch (error) {
22
+ if (error instanceof _hot_updater_plugin_core_server_plugin.DatabaseConstraintError && error.reason === "unique") return "existing";
23
+ throw error;
24
+ }
25
+ },
26
+ async findByHash(hash) {
27
+ const row = await db.findOne("api_keys", { hash });
28
+ return row === null ? null : toRow(row);
29
+ },
30
+ /** Every key, newest first, then by id; the whole list is the result. */
31
+ async list() {
32
+ const rows = [];
33
+ let cursor;
34
+ do {
35
+ const page = await db.findMany("api_keys", {
36
+ index: "byCreated",
37
+ where: {},
38
+ order: "desc",
39
+ limit: 500,
40
+ ...cursor === void 0 ? {} : { cursor }
41
+ });
42
+ rows.push(...page.rows.map(toRow));
43
+ cursor = page.next;
44
+ } while (cursor !== void 0);
45
+ return rows.sort((left, right) => right.created_at_ms - left.created_at_ms || (left.id < right.id ? -1 : left.id > right.id ? 1 : 0));
46
+ },
47
+ revoke: ({ id, revokedAtMs }) => db.transaction(async (tx) => {
48
+ const row = await tx.findOne("api_keys", { id });
49
+ if (row === null) return null;
50
+ tx.update("api_keys", row, { revoked_at_ms: revokedAtMs });
51
+ return toRow({
52
+ ...row,
53
+ revoked_at_ms: revokedAtMs
54
+ });
55
+ })
56
+ });
57
+ //#endregion
58
+ exports.createApiKeyModel = createApiKeyModel;
@@ -0,0 +1,26 @@
1
+ import { ApiKeysSchema } from "./schema.cjs";
2
+ import { HotUpdaterDatabase } from "@hot-updater/plugin-core/server-plugin";
3
+ //#region src/server/model.d.ts
4
+ interface ApiKeyRow {
5
+ readonly id: string;
6
+ readonly hash: string;
7
+ readonly name: string;
8
+ readonly prefix: string;
9
+ readonly role: "client";
10
+ readonly created_at_ms: number;
11
+ readonly revoked_at_ms: number | null;
12
+ }
13
+ /** The api-keys plugin's storage: key rows by id and by hash. */
14
+ interface ApiKeyModel {
15
+ create(row: ApiKeyRow): Promise<"created" | "existing">;
16
+ findByHash(hash: string): Promise<ApiKeyRow | null>;
17
+ list(): Promise<readonly ApiKeyRow[]>;
18
+ revoke(input: {
19
+ readonly id: string;
20
+ readonly revokedAtMs: number;
21
+ }): Promise<ApiKeyRow | null>;
22
+ }
23
+ /** Today's `ApiKeyModel` on the engine: one unique read by hash, keyed writes. */
24
+ declare const createApiKeyModel: (db: HotUpdaterDatabase<ApiKeysSchema>) => ApiKeyModel;
25
+ //#endregion
26
+ export { ApiKeyModel, ApiKeyRow, createApiKeyModel };
@@ -0,0 +1,26 @@
1
+ import { ApiKeysSchema } from "./schema.mjs";
2
+ import { HotUpdaterDatabase } from "@hot-updater/plugin-core/server-plugin";
3
+ //#region src/server/model.d.ts
4
+ interface ApiKeyRow {
5
+ readonly id: string;
6
+ readonly hash: string;
7
+ readonly name: string;
8
+ readonly prefix: string;
9
+ readonly role: "client";
10
+ readonly created_at_ms: number;
11
+ readonly revoked_at_ms: number | null;
12
+ }
13
+ /** The api-keys plugin's storage: key rows by id and by hash. */
14
+ interface ApiKeyModel {
15
+ create(row: ApiKeyRow): Promise<"created" | "existing">;
16
+ findByHash(hash: string): Promise<ApiKeyRow | null>;
17
+ list(): Promise<readonly ApiKeyRow[]>;
18
+ revoke(input: {
19
+ readonly id: string;
20
+ readonly revokedAtMs: number;
21
+ }): Promise<ApiKeyRow | null>;
22
+ }
23
+ /** Today's `ApiKeyModel` on the engine: one unique read by hash, keyed writes. */
24
+ declare const createApiKeyModel: (db: HotUpdaterDatabase<ApiKeysSchema>) => ApiKeyModel;
25
+ //#endregion
26
+ export { ApiKeyModel, ApiKeyRow, createApiKeyModel };
@@ -0,0 +1,58 @@
1
+ import { DatabaseConstraintError } from "@hot-updater/plugin-core/server-plugin";
2
+ //#region src/server/model.ts
3
+ const toRow = (row) => ({
4
+ id: row.id,
5
+ hash: row.hash,
6
+ name: row.name,
7
+ prefix: row.prefix,
8
+ role: row.role,
9
+ created_at_ms: row.created_at_ms,
10
+ revoked_at_ms: row.revoked_at_ms
11
+ });
12
+ /** Today's `ApiKeyModel` on the engine: one unique read by hash, keyed writes. */
13
+ const createApiKeyModel = (db) => ({
14
+ async create(row) {
15
+ try {
16
+ return await db.transaction(async (tx) => {
17
+ if (await tx.findOne("api_keys", { hash: row.hash }) !== null) return "existing";
18
+ tx.create("api_keys", row);
19
+ return "created";
20
+ });
21
+ } catch (error) {
22
+ if (error instanceof DatabaseConstraintError && error.reason === "unique") return "existing";
23
+ throw error;
24
+ }
25
+ },
26
+ async findByHash(hash) {
27
+ const row = await db.findOne("api_keys", { hash });
28
+ return row === null ? null : toRow(row);
29
+ },
30
+ /** Every key, newest first, then by id; the whole list is the result. */
31
+ async list() {
32
+ const rows = [];
33
+ let cursor;
34
+ do {
35
+ const page = await db.findMany("api_keys", {
36
+ index: "byCreated",
37
+ where: {},
38
+ order: "desc",
39
+ limit: 500,
40
+ ...cursor === void 0 ? {} : { cursor }
41
+ });
42
+ rows.push(...page.rows.map(toRow));
43
+ cursor = page.next;
44
+ } while (cursor !== void 0);
45
+ return rows.sort((left, right) => right.created_at_ms - left.created_at_ms || (left.id < right.id ? -1 : left.id > right.id ? 1 : 0));
46
+ },
47
+ revoke: ({ id, revokedAtMs }) => db.transaction(async (tx) => {
48
+ const row = await tx.findOne("api_keys", { id });
49
+ if (row === null) return null;
50
+ tx.update("api_keys", row, { revoked_at_ms: revokedAtMs });
51
+ return toRow({
52
+ ...row,
53
+ revoked_at_ms: revokedAtMs
54
+ });
55
+ })
56
+ });
57
+ //#endregion
58
+ export { createApiKeyModel };
@@ -0,0 +1,38 @@
1
+ //#region src/server/schema.ts
2
+ /** v1's `api_keys` columns; the plaintext key is never stored, only its SHA-256 digest. */
3
+ const apiKeysSchema = { api_keys: (0, require("@hot-updater/plugin-core/server-plugin").defineTable)({
4
+ id: {
5
+ type: "string",
6
+ maxLength: 255
7
+ },
8
+ hash: {
9
+ type: "string",
10
+ maxLength: 64,
11
+ unique: true
12
+ },
13
+ name: {
14
+ type: "string",
15
+ maxLength: 64
16
+ },
17
+ prefix: {
18
+ type: "string",
19
+ maxLength: 16
20
+ },
21
+ role: {
22
+ type: "string",
23
+ maxLength: 16
24
+ },
25
+ created_at_ms: { type: "integer" },
26
+ revoked_at_ms: {
27
+ type: "integer",
28
+ required: false
29
+ }
30
+ }, {
31
+ key: ["id"],
32
+ indexes: { byCreated: {
33
+ eq: [],
34
+ sort: ["created_at_ms"]
35
+ } }
36
+ }) };
37
+ //#endregion
38
+ exports.apiKeysSchema = apiKeysSchema;
@@ -0,0 +1,42 @@
1
+ //#region src/server/schema.d.ts
2
+ /** v1's `api_keys` columns; the plaintext key is never stored, only its SHA-256 digest. */
3
+ declare const apiKeysSchema: {
4
+ readonly api_keys: import("@hot-updater/plugin-core/server-plugin").TableDefinition<{
5
+ readonly id: {
6
+ readonly type: "string";
7
+ readonly maxLength: 255;
8
+ };
9
+ readonly hash: {
10
+ readonly type: "string";
11
+ readonly maxLength: 64;
12
+ readonly unique: true;
13
+ };
14
+ readonly name: {
15
+ readonly type: "string";
16
+ readonly maxLength: 64;
17
+ };
18
+ readonly prefix: {
19
+ readonly type: "string";
20
+ readonly maxLength: 16;
21
+ };
22
+ readonly role: {
23
+ readonly type: "string";
24
+ readonly maxLength: 16;
25
+ };
26
+ readonly created_at_ms: {
27
+ readonly type: "integer";
28
+ };
29
+ readonly revoked_at_ms: {
30
+ readonly type: "integer";
31
+ readonly required: false;
32
+ };
33
+ }, {}, {
34
+ readonly byCreated: {
35
+ readonly eq: readonly [];
36
+ readonly sort: readonly ["created_at_ms"];
37
+ };
38
+ }, readonly ["id"]>;
39
+ };
40
+ type ApiKeysSchema = typeof apiKeysSchema;
41
+ //#endregion
42
+ export { ApiKeysSchema, apiKeysSchema };
@@ -0,0 +1,42 @@
1
+ //#region src/server/schema.d.ts
2
+ /** v1's `api_keys` columns; the plaintext key is never stored, only its SHA-256 digest. */
3
+ declare const apiKeysSchema: {
4
+ readonly api_keys: import("@hot-updater/plugin-core/server-plugin").TableDefinition<{
5
+ readonly id: {
6
+ readonly type: "string";
7
+ readonly maxLength: 255;
8
+ };
9
+ readonly hash: {
10
+ readonly type: "string";
11
+ readonly maxLength: 64;
12
+ readonly unique: true;
13
+ };
14
+ readonly name: {
15
+ readonly type: "string";
16
+ readonly maxLength: 64;
17
+ };
18
+ readonly prefix: {
19
+ readonly type: "string";
20
+ readonly maxLength: 16;
21
+ };
22
+ readonly role: {
23
+ readonly type: "string";
24
+ readonly maxLength: 16;
25
+ };
26
+ readonly created_at_ms: {
27
+ readonly type: "integer";
28
+ };
29
+ readonly revoked_at_ms: {
30
+ readonly type: "integer";
31
+ readonly required: false;
32
+ };
33
+ }, {}, {
34
+ readonly byCreated: {
35
+ readonly eq: readonly [];
36
+ readonly sort: readonly ["created_at_ms"];
37
+ };
38
+ }, readonly ["id"]>;
39
+ };
40
+ type ApiKeysSchema = typeof apiKeysSchema;
41
+ //#endregion
42
+ export { ApiKeysSchema, apiKeysSchema };