@adminiumjs/meta 0.2.2-rc.0 → 0.2.3

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.
Files changed (81) hide show
  1. package/dist/ids.d.ts +6 -0
  2. package/dist/ids.d.ts.map +1 -1
  3. package/dist/ids.js +14 -0
  4. package/dist/ids.js.map +1 -1
  5. package/dist/migrations/0014_public_surface.d.ts +40 -0
  6. package/dist/migrations/0014_public_surface.d.ts.map +1 -0
  7. package/dist/migrations/0014_public_surface.js +186 -0
  8. package/dist/migrations/0014_public_surface.js.map +1 -0
  9. package/dist/migrations/0015_connection_tenant_config.d.ts +42 -0
  10. package/dist/migrations/0015_connection_tenant_config.d.ts.map +1 -0
  11. package/dist/migrations/0015_connection_tenant_config.js +53 -0
  12. package/dist/migrations/0015_connection_tenant_config.js.map +1 -0
  13. package/dist/migrations/0016_audit_entity.d.ts +33 -0
  14. package/dist/migrations/0016_audit_entity.d.ts.map +1 -0
  15. package/dist/migrations/0016_audit_entity.js +137 -0
  16. package/dist/migrations/0016_audit_entity.js.map +1 -0
  17. package/dist/migrations/0017_surface_binding.d.ts +23 -0
  18. package/dist/migrations/0017_surface_binding.d.ts.map +1 -0
  19. package/dist/migrations/0017_surface_binding.js +37 -0
  20. package/dist/migrations/0017_surface_binding.js.map +1 -0
  21. package/dist/migrations/0018_connection_timezone_source.d.ts +44 -0
  22. package/dist/migrations/0018_connection_timezone_source.d.ts.map +1 -0
  23. package/dist/migrations/0018_connection_timezone_source.js +51 -0
  24. package/dist/migrations/0018_connection_timezone_source.js.map +1 -0
  25. package/dist/migrations/0019_connection_disabled.d.ts +38 -0
  26. package/dist/migrations/0019_connection_disabled.d.ts.map +1 -0
  27. package/dist/migrations/0019_connection_disabled.js +43 -0
  28. package/dist/migrations/0019_connection_disabled.js.map +1 -0
  29. package/dist/migrations/0020_manifests_add_on.d.ts +71 -0
  30. package/dist/migrations/0020_manifests_add_on.d.ts.map +1 -0
  31. package/dist/migrations/0020_manifests_add_on.js +111 -0
  32. package/dist/migrations/0020_manifests_add_on.js.map +1 -0
  33. package/dist/migrations/0021_add_on_credentials.d.ts +50 -0
  34. package/dist/migrations/0021_add_on_credentials.d.ts.map +1 -0
  35. package/dist/migrations/0021_add_on_credentials.js +80 -0
  36. package/dist/migrations/0021_add_on_credentials.js.map +1 -0
  37. package/dist/migrations/0022_studio_namespace.d.ts +44 -0
  38. package/dist/migrations/0022_studio_namespace.d.ts.map +1 -0
  39. package/dist/migrations/0022_studio_namespace.js +113 -0
  40. package/dist/migrations/0022_studio_namespace.js.map +1 -0
  41. package/dist/migrations/index.d.ts.map +1 -1
  42. package/dist/migrations/index.js +18 -0
  43. package/dist/migrations/index.js.map +1 -1
  44. package/dist/relocate.d.ts +1 -1
  45. package/dist/relocate.js +1 -1
  46. package/dist/repos/audit.d.ts.map +1 -1
  47. package/dist/repos/audit.js +8 -2
  48. package/dist/repos/audit.js.map +1 -1
  49. package/dist/repos/connections.d.ts +62 -0
  50. package/dist/repos/connections.d.ts.map +1 -1
  51. package/dist/repos/connections.js +104 -0
  52. package/dist/repos/connections.js.map +1 -1
  53. package/dist/repos/index.d.ts +2 -0
  54. package/dist/repos/index.d.ts.map +1 -1
  55. package/dist/repos/index.js +2 -0
  56. package/dist/repos/index.js.map +1 -1
  57. package/dist/repos/manifests.d.ts +139 -0
  58. package/dist/repos/manifests.d.ts.map +1 -0
  59. package/dist/repos/manifests.js +279 -0
  60. package/dist/repos/manifests.js.map +1 -0
  61. package/dist/repos/pages.d.ts +7 -0
  62. package/dist/repos/pages.d.ts.map +1 -1
  63. package/dist/repos/pages.js +39 -8
  64. package/dist/repos/pages.js.map +1 -1
  65. package/dist/repos/public-api.d.ts +140 -0
  66. package/dist/repos/public-api.d.ts.map +1 -0
  67. package/dist/repos/public-api.js +299 -0
  68. package/dist/repos/public-api.js.map +1 -0
  69. package/dist/schema/json-payloads.d.ts +27 -2
  70. package/dist/schema/json-payloads.d.ts.map +1 -1
  71. package/dist/schema/json-payloads.js +41 -2
  72. package/dist/schema/json-payloads.js.map +1 -1
  73. package/dist/schema/settings-registry.d.ts +65 -0
  74. package/dist/schema/settings-registry.d.ts.map +1 -1
  75. package/dist/schema/settings-registry.js +183 -0
  76. package/dist/schema/settings-registry.js.map +1 -1
  77. package/dist/schema/tables.d.ts +177 -1
  78. package/dist/schema/tables.d.ts.map +1 -1
  79. package/dist/schema/tables.js +6 -0
  80. package/dist/schema/tables.js.map +1 -1
  81. package/package.json +1 -1
@@ -0,0 +1,140 @@
1
+ /**
2
+ * publicScopesRepo / publicKeysRepo — the public surface's meta rows
3
+ * (28-public-surface.md §3.2–§3.3, migration `0014_public_surface`).
4
+ *
5
+ * Deliberately NOT part of `apiKeysRepo`. A publishable key differs from an
6
+ * `adm_sk_` key in two ways that both reach the storage layer: its secret is
7
+ * re-readable, and it must never be resolvable as an `RbacPrincipal` (D3).
8
+ * Sharing a repo would put both kinds one `where` clause apart, which is how a
9
+ * later "unify the key lookup" change would quietly break the property the
10
+ * whole off switch rests on.
11
+ */
12
+ import type { Selectable } from 'kysely';
13
+ import type { MetaDb } from '../connect.js';
14
+ import type { AdminiumPublicKeysTable, AdminiumPublicScopesTable, AdminiumPublicSessionsTable } from '../schema/tables.js';
15
+ export type PublicScope = Selectable<AdminiumPublicScopesTable>;
16
+ export type PublicKey = Selectable<AdminiumPublicKeysTable>;
17
+ export type PublicSession = Selectable<AdminiumPublicSessionsTable>;
18
+ export interface CreatePublicScopeInput {
19
+ connectionId: string;
20
+ side: string;
21
+ name: string;
22
+ /** Canonical IANA zone; the compiler refuses anything else. */
23
+ timezone: string;
24
+ /** The scope document, already serialized. */
25
+ document: string;
26
+ proposedFromManifest?: string | null;
27
+ createdBy?: string | null;
28
+ }
29
+ export declare function publicScopesRepo(meta: MetaDb): {
30
+ create(input: CreatePublicScopeInput, at?: number): Promise<PublicScope>;
31
+ findById(id: string): Promise<PublicScope | null>;
32
+ list(): Promise<PublicScope[]>;
33
+ listByConnection(connectionId: string): Promise<PublicScope[]>;
34
+ update(id: string, patch: {
35
+ name?: string;
36
+ timezone?: string;
37
+ document?: string;
38
+ }, at?: number): Promise<boolean>;
39
+ /**
40
+ * Deleting a scope is refused while a key points at it — the FK is
41
+ * `restrict`, so this surfaces the constraint as `false` rather than as a
42
+ * driver error. Revoking the key first is the intended order, because it
43
+ * makes the operator see what they are about to break.
44
+ */
45
+ remove(id: string): Promise<boolean>;
46
+ };
47
+ export interface CreatePublicKeyInput {
48
+ name: string;
49
+ /** Display/lookup fragment, e.g. `adm_pub_4f2a91cd`. */
50
+ prefix: string;
51
+ tokenHash: string;
52
+ /** AES-GCM envelope of the full token — the re-readable copy. */
53
+ tokenEncrypted: string;
54
+ scopeId: string;
55
+ side: string;
56
+ /** Hosted app surface this key is bound to (29 D10), or absent/null. */
57
+ appKey?: string | null;
58
+ /** JSON array narrowing the instance origin list; `[]` = no narrowing. */
59
+ origins?: string[];
60
+ createdBy?: string | null;
61
+ expiresAt?: number | null;
62
+ }
63
+ export declare function publicKeysRepo(meta: MetaDb): {
64
+ create(input: CreatePublicKeyInput, at?: number): Promise<PublicKey>;
65
+ /**
66
+ * The AUTH lookup, by prefix.
67
+ *
68
+ * Returns every candidate rather than filtering on the hash in SQL, because
69
+ * the caller compares hashes in CONSTANT TIME. A `where tokenHash = ?`
70
+ * makes the database do a byte comparison whose timing an attacker can
71
+ * measure; the prefix is a public display fragment and leaks nothing.
72
+ *
73
+ * Revocation and expiry are NOT filtered here either — the caller decides,
74
+ * so it can answer every failure identically on the wire (§3.2) instead of
75
+ * letting "no row" and "revoked row" take different code paths.
76
+ */
77
+ findByPrefix(prefix: string): Promise<PublicKey[]>;
78
+ findById(id: string): Promise<PublicKey | null>;
79
+ listByScope(scopeId: string): Promise<PublicKey[]>;
80
+ /**
81
+ * The `surface-config.json` lookup (29 D10): the newest key for this app's
82
+ * side that is neither revoked nor expired. Rotation keeps the row (and so
83
+ * the binding); revoking the newest key falls back to the next live one, so
84
+ * an operator can stage a replacement before killing the old key.
85
+ */
86
+ /**
87
+ * The newest live key for an app whose SCOPE points at one connection.
88
+ *
89
+ * What `newestLiveByApp` answers once per app, this answers once per
90
+ * database — the customer half of app instances (29 D9). A customer surface
91
+ * has never named its connection directly and does not start now: its key
92
+ * names a scope and the scope names the connection, so selecting the right
93
+ * key IS selecting the right database, and nothing new has to be kept in
94
+ * sync with anything.
95
+ *
96
+ * A join, not two queries: the pair "newest, and belonging to this
97
+ * connection" has to be decided together, or a scope moved between
98
+ * connections could hand back a key that was newest but no longer relevant.
99
+ */
100
+ newestLiveByAppAndConnection(appKey: string, side: string, connectionId: string, at?: number): Promise<PublicKey | null>;
101
+ newestLiveByApp(appKey: string, side: string, at?: number): Promise<PublicKey | null>;
102
+ list(): Promise<PublicKey[]>;
103
+ /** Rotation: a new secret against the same row, keeping scope and origins. */
104
+ rotate(id: string, next: {
105
+ prefix: string;
106
+ tokenHash: string;
107
+ tokenEncrypted: string;
108
+ }, at?: number): Promise<boolean>;
109
+ revoke(id: string, at?: number): Promise<boolean>;
110
+ /** Throttled by the caller, like session and api-key touches. */
111
+ touchLastUsed(id: string, at?: number): Promise<void>;
112
+ };
113
+ export interface CreatePublicSessionInput {
114
+ keyId: string;
115
+ tokenHash: string;
116
+ /** The RESOLVED claim — see the table comment on why it is not re-derived. */
117
+ grants: string;
118
+ expiresAt: number;
119
+ }
120
+ export declare function publicSessionsRepo(meta: MetaDb): {
121
+ create(input: CreatePublicSessionInput, at?: number): Promise<PublicSession>;
122
+ /**
123
+ * Resolve a session token.
124
+ *
125
+ * Unlike `publicKeysRepo.findByPrefix`, matching on the hash in SQL is fine
126
+ * here: a session token has no public display fragment to look up by, so
127
+ * there is nothing to narrow on first. Expiry IS filtered, because an
128
+ * expired session and an unknown one are the same thing to the caller and
129
+ * there is no reason to carry the difference back up.
130
+ */
131
+ findValid(tokenHash: string, at?: number): Promise<PublicSession | null>;
132
+ touch(id: string, at?: number): Promise<void>;
133
+ remove(tokenHash: string): Promise<boolean>;
134
+ /** Housekeeping: drop everything that has lapsed. */
135
+ purgeExpired(at?: number): Promise<number>;
136
+ };
137
+ export type PublicSessionsRepo = ReturnType<typeof publicSessionsRepo>;
138
+ export type PublicScopesRepo = ReturnType<typeof publicScopesRepo>;
139
+ export type PublicKeysRepo = ReturnType<typeof publicKeysRepo>;
140
+ //# sourceMappingURL=public-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../../src/repos/public-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,299 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ /**
3
+ * publicScopesRepo / publicKeysRepo — the public surface's meta rows
4
+ * (28-public-surface.md §3.2–§3.3, migration `0014_public_surface`).
5
+ *
6
+ * Deliberately NOT part of `apiKeysRepo`. A publishable key differs from an
7
+ * `adm_sk_` key in two ways that both reach the storage layer: its secret is
8
+ * re-readable, and it must never be resolvable as an `RbacPrincipal` (D3).
9
+ * Sharing a repo would put both kinds one `where` clause apart, which is how a
10
+ * later "unify the key lookup" change would quietly break the property the
11
+ * whole off switch rests on.
12
+ */
13
+ import { newId } from '../ids.js';
14
+ /**
15
+ * A `json` column does not come back the same shape on every store.
16
+ *
17
+ * postgres and mysql hand back a PARSED value; sqlite hands back the text it
18
+ * stored. `PublicScope.document` is declared `string` and every caller treats
19
+ * it as one — `resolve.ts` calls `JSON.parse` on it, and the admin route
20
+ * returns it under a `z.string()` response schema — so on the two production
21
+ * stores that parse threw and that response failed validation, while the whole
22
+ * suite stayed green on sqlite. Found by CI, which runs all three; the local
23
+ * run skipped 334 store-gated tests.
24
+ *
25
+ * Normalising here rather than at each caller is the point of a repo layer:
26
+ * the driver difference is this file's business and nobody else's.
27
+ */
28
+ function jsonText(value) {
29
+ return typeof value === "string" ? value : JSON.stringify(value);
30
+ }
31
+ /** One scope row, with its document normalised to text whatever the store did. */
32
+ function scopeRow(row) {
33
+ return { ...row, document: jsonText(row.document) };
34
+ }
35
+ export function publicScopesRepo(meta) {
36
+ const { db } = meta;
37
+ return {
38
+ async create(input, at = Date.now()) {
39
+ const row = {
40
+ id: newId('psc'),
41
+ connectionId: input.connectionId,
42
+ side: input.side,
43
+ name: input.name,
44
+ timezone: input.timezone,
45
+ document: input.document,
46
+ proposedFromManifest: input.proposedFromManifest ?? null,
47
+ createdBy: input.createdBy ?? null,
48
+ createdAt: at,
49
+ updatedAt: at,
50
+ };
51
+ await db.insertInto('adminium_public_scopes').values(row).execute();
52
+ return row;
53
+ },
54
+ async findById(id) {
55
+ const row = await db
56
+ .selectFrom('adminium_public_scopes')
57
+ .selectAll()
58
+ .where('id', '=', id)
59
+ .executeTakeFirst();
60
+ return row === undefined ? null : scopeRow(row);
61
+ },
62
+ async list() {
63
+ const rows = await db
64
+ .selectFrom('adminium_public_scopes')
65
+ .selectAll()
66
+ .orderBy('createdAt', 'desc')
67
+ .execute();
68
+ return rows.map(scopeRow);
69
+ },
70
+ async listByConnection(connectionId) {
71
+ const rows = await db
72
+ .selectFrom('adminium_public_scopes')
73
+ .selectAll()
74
+ .where('connectionId', '=', connectionId)
75
+ .orderBy('createdAt', 'desc')
76
+ .execute();
77
+ return rows.map(scopeRow);
78
+ },
79
+ async update(id, patch, at = Date.now()) {
80
+ const res = await db
81
+ .updateTable('adminium_public_scopes')
82
+ .set({ ...patch, updatedAt: at })
83
+ .where('id', '=', id)
84
+ .executeTakeFirst();
85
+ return Number(res.numUpdatedRows) === 1;
86
+ },
87
+ /**
88
+ * Deleting a scope is refused while a key points at it — the FK is
89
+ * `restrict`, so this surfaces the constraint as `false` rather than as a
90
+ * driver error. Revoking the key first is the intended order, because it
91
+ * makes the operator see what they are about to break.
92
+ */
93
+ async remove(id) {
94
+ const attached = await db
95
+ .selectFrom('adminium_public_keys')
96
+ .select('id')
97
+ .where('scopeId', '=', id)
98
+ .executeTakeFirst();
99
+ if (attached !== undefined)
100
+ return false;
101
+ const res = await db
102
+ .deleteFrom('adminium_public_scopes')
103
+ .where('id', '=', id)
104
+ .executeTakeFirst();
105
+ return Number(res.numDeletedRows) === 1;
106
+ },
107
+ };
108
+ }
109
+ export function publicKeysRepo(meta) {
110
+ const { db } = meta;
111
+ return {
112
+ async create(input, at = Date.now()) {
113
+ const row = {
114
+ id: newId('pbk'),
115
+ name: input.name,
116
+ prefix: input.prefix,
117
+ tokenHash: input.tokenHash,
118
+ tokenEncrypted: input.tokenEncrypted,
119
+ scopeId: input.scopeId,
120
+ side: input.side,
121
+ appKey: input.appKey ?? null,
122
+ origins: JSON.stringify(input.origins ?? []),
123
+ expiresAt: input.expiresAt ?? null,
124
+ revokedAt: null,
125
+ lastUsedAt: null,
126
+ createdBy: input.createdBy ?? null,
127
+ createdAt: at,
128
+ updatedAt: at,
129
+ };
130
+ await db.insertInto('adminium_public_keys').values(row).execute();
131
+ return row;
132
+ },
133
+ /**
134
+ * The AUTH lookup, by prefix.
135
+ *
136
+ * Returns every candidate rather than filtering on the hash in SQL, because
137
+ * the caller compares hashes in CONSTANT TIME. A `where tokenHash = ?`
138
+ * makes the database do a byte comparison whose timing an attacker can
139
+ * measure; the prefix is a public display fragment and leaks nothing.
140
+ *
141
+ * Revocation and expiry are NOT filtered here either — the caller decides,
142
+ * so it can answer every failure identically on the wire (§3.2) instead of
143
+ * letting "no row" and "revoked row" take different code paths.
144
+ */
145
+ async findByPrefix(prefix) {
146
+ return db
147
+ .selectFrom('adminium_public_keys')
148
+ .selectAll()
149
+ .where('prefix', '=', prefix)
150
+ .execute();
151
+ },
152
+ async findById(id) {
153
+ const row = await db
154
+ .selectFrom('adminium_public_keys')
155
+ .selectAll()
156
+ .where('id', '=', id)
157
+ .executeTakeFirst();
158
+ return row ?? null;
159
+ },
160
+ async listByScope(scopeId) {
161
+ return db
162
+ .selectFrom('adminium_public_keys')
163
+ .selectAll()
164
+ .where('scopeId', '=', scopeId)
165
+ .orderBy('createdAt', 'desc')
166
+ .execute();
167
+ },
168
+ /**
169
+ * The `surface-config.json` lookup (29 D10): the newest key for this app's
170
+ * side that is neither revoked nor expired. Rotation keeps the row (and so
171
+ * the binding); revoking the newest key falls back to the next live one, so
172
+ * an operator can stage a replacement before killing the old key.
173
+ */
174
+ /**
175
+ * The newest live key for an app whose SCOPE points at one connection.
176
+ *
177
+ * What `newestLiveByApp` answers once per app, this answers once per
178
+ * database — the customer half of app instances (29 D9). A customer surface
179
+ * has never named its connection directly and does not start now: its key
180
+ * names a scope and the scope names the connection, so selecting the right
181
+ * key IS selecting the right database, and nothing new has to be kept in
182
+ * sync with anything.
183
+ *
184
+ * A join, not two queries: the pair "newest, and belonging to this
185
+ * connection" has to be decided together, or a scope moved between
186
+ * connections could hand back a key that was newest but no longer relevant.
187
+ */
188
+ async newestLiveByAppAndConnection(appKey, side, connectionId, at = Date.now()) {
189
+ const row = await db
190
+ .selectFrom('adminium_public_keys')
191
+ .innerJoin('adminium_public_scopes', 'adminium_public_scopes.id', 'adminium_public_keys.scopeId')
192
+ .selectAll('adminium_public_keys')
193
+ .where('adminium_public_keys.appKey', '=', appKey)
194
+ .where('adminium_public_keys.side', '=', side)
195
+ .where('adminium_public_scopes.connectionId', '=', connectionId)
196
+ .where('adminium_public_keys.revokedAt', 'is', null)
197
+ .where((eb) => eb.or([
198
+ eb('adminium_public_keys.expiresAt', 'is', null),
199
+ eb('adminium_public_keys.expiresAt', '>', at),
200
+ ]))
201
+ .orderBy('adminium_public_keys.createdAt', 'desc')
202
+ .executeTakeFirst();
203
+ return row ?? null;
204
+ },
205
+ async newestLiveByApp(appKey, side, at = Date.now()) {
206
+ const row = await db
207
+ .selectFrom('adminium_public_keys')
208
+ .selectAll()
209
+ .where('appKey', '=', appKey)
210
+ .where('side', '=', side)
211
+ .where('revokedAt', 'is', null)
212
+ .where((eb) => eb.or([eb('expiresAt', 'is', null), eb('expiresAt', '>', at)]))
213
+ .orderBy('createdAt', 'desc')
214
+ .executeTakeFirst();
215
+ return row ?? null;
216
+ },
217
+ async list() {
218
+ return db.selectFrom('adminium_public_keys').selectAll().orderBy('createdAt', 'desc').execute();
219
+ },
220
+ /** Rotation: a new secret against the same row, keeping scope and origins. */
221
+ async rotate(id, next, at = Date.now()) {
222
+ const res = await db
223
+ .updateTable('adminium_public_keys')
224
+ .set({ ...next, updatedAt: at })
225
+ .where('id', '=', id)
226
+ .where('revokedAt', 'is', null)
227
+ .executeTakeFirst();
228
+ return Number(res.numUpdatedRows) === 1;
229
+ },
230
+ async revoke(id, at = Date.now()) {
231
+ const res = await db
232
+ .updateTable('adminium_public_keys')
233
+ .set({ revokedAt: at, updatedAt: at })
234
+ .where('id', '=', id)
235
+ .where('revokedAt', 'is', null)
236
+ .executeTakeFirst();
237
+ return Number(res.numUpdatedRows) === 1;
238
+ },
239
+ /** Throttled by the caller, like session and api-key touches. */
240
+ async touchLastUsed(id, at = Date.now()) {
241
+ await db.updateTable('adminium_public_keys').set({ lastUsedAt: at }).where('id', '=', id).execute();
242
+ },
243
+ };
244
+ }
245
+ export function publicSessionsRepo(meta) {
246
+ const { db } = meta;
247
+ return {
248
+ async create(input, at = Date.now()) {
249
+ const row = {
250
+ id: newId('pss'),
251
+ keyId: input.keyId,
252
+ tokenHash: input.tokenHash,
253
+ grants: input.grants,
254
+ expiresAt: input.expiresAt,
255
+ createdAt: at,
256
+ lastSeenAt: null,
257
+ };
258
+ await db.insertInto('adminium_public_sessions').values(row).execute();
259
+ return row;
260
+ },
261
+ /**
262
+ * Resolve a session token.
263
+ *
264
+ * Unlike `publicKeysRepo.findByPrefix`, matching on the hash in SQL is fine
265
+ * here: a session token has no public display fragment to look up by, so
266
+ * there is nothing to narrow on first. Expiry IS filtered, because an
267
+ * expired session and an unknown one are the same thing to the caller and
268
+ * there is no reason to carry the difference back up.
269
+ */
270
+ async findValid(tokenHash, at = Date.now()) {
271
+ const row = await db
272
+ .selectFrom('adminium_public_sessions')
273
+ .selectAll()
274
+ .where('tokenHash', '=', tokenHash)
275
+ .where('expiresAt', '>', at)
276
+ .executeTakeFirst();
277
+ return row ?? null;
278
+ },
279
+ async touch(id, at = Date.now()) {
280
+ await db.updateTable('adminium_public_sessions').set({ lastSeenAt: at }).where('id', '=', id).execute();
281
+ },
282
+ async remove(tokenHash) {
283
+ const res = await db
284
+ .deleteFrom('adminium_public_sessions')
285
+ .where('tokenHash', '=', tokenHash)
286
+ .executeTakeFirst();
287
+ return Number(res.numDeletedRows) > 0;
288
+ },
289
+ /** Housekeeping: drop everything that has lapsed. */
290
+ async purgeExpired(at = Date.now()) {
291
+ const res = await db
292
+ .deleteFrom('adminium_public_sessions')
293
+ .where('expiresAt', '<=', at)
294
+ .executeTakeFirst();
295
+ return Number(res.numDeletedRows);
296
+ },
297
+ };
298
+ }
299
+ //# sourceMappingURL=public-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-api.js","sourceRoot":"","sources":["../../src/repos/public-api.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,30 @@ export declare const recordRefSchema: z.ZodObject<{
16
16
  label: z.ZodString;
17
17
  }, z.core.$strip>;
18
18
  export type RecordRef = z.infer<typeof recordRefSchema>;
19
+ /**
20
+ * Width of the denormalized `adminium_audit_log.entity_table` / `entity_id`
21
+ * columns (30-record-pages.md WS-A). 200 chars keeps the composite index
22
+ * inside MySQL's 3072-byte InnoDB cap under utf8mb4 (2 × 200 × 4 + 8).
23
+ */
24
+ export declare const AUDIT_ENTITY_KEY_MAX = 200;
25
+ /**
26
+ * Canonical clamp for one audit entity key part. Applied on the WRITE side
27
+ * (append + backfill) and again on the QUERY side, so an over-long id still
28
+ * matches the row it wrote — truncation is consistent, never one-sided.
29
+ */
30
+ export declare function auditEntityKeyPart(value: string): string;
31
+ /**
32
+ * The denormalized per-record audit key derived from a RecordRef (30 WS-A).
33
+ *
34
+ * `entityId` reproduces the canonical `:recordId` string both sides already
35
+ * use — `pkLabel` on the server, `rowIdOf` in the grid: a single-column PK is
36
+ * its stringified value, a composite PK is the JSON tuple of its values in pk
37
+ * insertion order (the order both writers build the map in).
38
+ */
39
+ export declare function auditEntityKeyOf(ref: Pick<RecordRef, 'table' | 'pk'>): {
40
+ entityTable: string;
41
+ entityId: string;
42
+ };
19
43
  /** The eight COMPILED locales. Still a closed set — see `builtinLocaleSchema`. */
20
44
  export declare const LOCALES: readonly ["en_US", "de_DE", "ar_EG", "zh_CN", "zh_TW", "cs_CZ", "da_DK", "fr_FR"];
21
45
  export declare const builtinLocaleSchema: z.ZodEnum<{
@@ -140,7 +164,7 @@ export declare const systemActionKeySchema: z.ZodEnum<{
140
164
  * {@link GRANTABLE_SYSTEM_ACTION_KEYS}; move a key out of here in the same
141
165
  * change that lands its first enforcement point.
142
166
  */
143
- export declare const RESERVED_SYSTEM_ACTION_KEYS: readonly ["automations.manage", "webhooks.manage", "manifests.manage", "sql.run"];
167
+ export declare const RESERVED_SYSTEM_ACTION_KEYS: readonly ["automations.manage", "webhooks.manage", "sql.run"];
144
168
  export type ReservedSystemActionKey = (typeof RESERVED_SYSTEM_ACTION_KEYS)[number];
145
169
  /**
146
170
  * What a role editor / permissions surface may offer: the closed set minus
@@ -169,6 +193,7 @@ export declare const auditCategorySchema: z.ZodEnum<{
169
193
  rbac: "rbac";
170
194
  connection: "connection";
171
195
  llm: "llm";
196
+ "add-on": "add-on";
172
197
  }>;
173
198
  export type AuditCategory = z.infer<typeof auditCategorySchema>;
174
199
  /** `{ before, after }` images; PII-masked upstream; capped at 16 KB serialized. */
@@ -376,11 +401,11 @@ export declare const llmValidationStatusSchema: z.ZodEnum<{
376
401
  */
377
402
  export declare const llmRunStatusSchema: z.ZodEnum<{
378
403
  draft: "draft";
379
- applied: "applied";
380
404
  running: "running";
381
405
  failed: "failed";
382
406
  awaiting_response: "awaiting_response";
383
407
  validated: "validated";
408
+ applied: "applied";
384
409
  partially_applied: "partially_applied";
385
410
  discarded: "discarded";
386
411
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"json-payloads.d.ts","sourceRoot":"","sources":["../../src/schema/json-payloads.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,0EAA0E;AAC1E,eAAO,MAAM,eAAe;;;;;iBAQ1B,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,kFAAkF;AAClF,eAAO,MAAM,OAAO,mFAAoF,CAAC;AACzG,eAAO,MAAM,mBAAmB;;;;;;;;;EAAkB,CAAC;AACnD,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,8EAA8E;AAC9E,eAAO,MAAM,YAAY,QAAyC,CAAC;AAEnE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,aAAgD,CAAC;AAC1E,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,eAAO,MAAM,WAAW;;;;EAAsC,CAAC;AAC/D,eAAO,MAAM,YAAY;;;;;;;;;EAAiF,CAAC;AAC3G,eAAO,MAAM,aAAa;;;EAAqC,CAAC;AAChE,eAAO,MAAM,SAAS;;;EAAyB,CAAC;AAIhD,eAAO,MAAM,gBAAgB;;;;EAA6C,CAAC;AAC3E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,gCAAgC;AAChC,eAAO,MAAM,mBAAmB,yBAAsB,CAAC;AAEvD,sFAAsF;AACtF,eAAO,MAAM,aAAa,wCAAoC,CAAC;AAI/D,eAAO,MAAM,kBAAkB;;;;EAAsC,CAAC;AACtE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,kBAAkB;;;;;;;iBAO7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,iBAAiB;;;iBAG5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB;;iBAE9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,WAAW,GAAG,aAAa,CAAC;AAE3E,0EAA0E;AAC1E,eAAO,MAAM,kBAAkB,0TAkCrB,CAAC;AACX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAClE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;EAA6B,CAAC;AAEhE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,mFAKO,CAAC;AAChD,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnF;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,SAAS,OAAO,CACzD,eAAe,EACf,uBAAuB,CACxB,EAGA,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,YAAY,GAAG,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAS3F;AAID,eAAO,MAAM,eAAe;;;;;EAAsD,CAAC;AACnF,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,mBAAmB;;;;;;;;;;;EAW9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,mFAAmF;AACnF,eAAO,MAAM,kBAAkB;;;;iBAI7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,oEAAoE;AACpE,eAAO,MAAM,uBAAuB,QAAY,CAAC;AAIjD,eAAO,MAAM,eAAe;;;;;;EAAqE,CAAC;AAClG,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,8DAA8D;AAC9D,eAAO,MAAM,gBAAgB,wCAAoC,CAAC;AAIlE,eAAO,MAAM,sBAAsB;;;;EAA0C,CAAC;AAC9E,eAAO,MAAM,0BAA0B;;;EAAiC,CAAC;AACzE,eAAO,MAAM,sBAAsB;;;;EAAiD,CAAC;AAErF,eAAO,MAAM,mBAAmB;;;;;;;iBAG9B,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;;;iBAKnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAM1E,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBAiD9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB;;;;EAAkC,CAAC;AACpE,eAAO,MAAM,oBAAoB;;;EAAiC,CAAC;AAInE,eAAO,MAAM,gBAAgB;;;;;;EAA6D,CAAC;AAC3F,eAAO,MAAM,cAAc;;;;;;EAAoE,CAAC;AAEhG;;;GAGG;AACH,eAAO,MAAM,gBAAgB,wCAAoC,CAAC;AAElE,kCAAkC;AAClC,eAAO,MAAM,gBAAgB;;;;;;iBAM3B,CAAC;AAIH,eAAO,MAAM,0BAA0B;;;;iBAIrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAI9E,eAAO,MAAM,gBAAgB;;;EAA8B,CAAC;AAE5D;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB;;;;;EAAqD,CAAC;AAE5F;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;EAS7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,oGAAoG;AACpG,eAAO,MAAM,oBAAoB,yBAAsB,CAAC;AACxD,eAAO,MAAM,mBAAmB,yBAA6B,CAAC;AAC9D,eAAO,MAAM,oBAAoB;;kBAEpB,CAAC;AAEd,0FAA0F;AAC1F,eAAO,MAAM,kBAAkB;;;iBAG7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,eAAO,MAAM,uBAAuB;;;;iBAIlC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;iBAGhC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;EAAwD,CAAC;AAI/F,eAAO,MAAM,oBAAoB;;;;;;;;;;iBAM/B,CAAC;AAEH,eAAO,MAAM,sBAAsB,yBAAsB,CAAC;AAC1D,eAAO,MAAM,kBAAkB;;;EAAyB,CAAC;AAIzD,eAAO,MAAM,kBAAkB;;;;;;;;;iBAK7B,CAAC;AACH,eAAO,MAAM,kBAAkB;;;;EAAkC,CAAC;AAClE,eAAO,MAAM,kBAAkB;;;;;;EAAoE,CAAC;AAEpG,eAAO,MAAM,mBAAmB;;;;;iBAE9B,CAAC;AACH,eAAO,MAAM,mBAAmB;;;;;;;iBAI9B,CAAC;AACH,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AACH,eAAO,MAAM,kBAAkB;;;;;;;EAAiF,CAAC;AAIjH,eAAO,MAAM,cAAc;;;;;;;EAA0E,CAAC;AAItG,6FAA6F;AAC7F,eAAO,MAAM,iBAAiB,oDAA6C,CAAC;AAE5E,uFAAuF;AACvF,eAAO,MAAM,mBAAmB,yBAAsB,CAAC;AAEvD,eAAO,MAAM,4BAA4B;;;;iBAIvC,CAAC;AACH,eAAO,MAAM,6BAA6B;;;;kBAAqD,CAAC;AAEhG,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB;;;;iBAMpB,CAAC"}
1
+ {"version":3,"file":"json-payloads.d.ts","sourceRoot":"","sources":["../../src/schema/json-payloads.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,33 @@ export const recordRefSchema = z.object({
20
20
  /** Display snapshot taken at write time. */
21
21
  label: z.string(),
22
22
  });
23
+ /**
24
+ * Width of the denormalized `adminium_audit_log.entity_table` / `entity_id`
25
+ * columns (30-record-pages.md WS-A). 200 chars keeps the composite index
26
+ * inside MySQL's 3072-byte InnoDB cap under utf8mb4 (2 × 200 × 4 + 8).
27
+ */
28
+ export const AUDIT_ENTITY_KEY_MAX = 200;
29
+ /**
30
+ * Canonical clamp for one audit entity key part. Applied on the WRITE side
31
+ * (append + backfill) and again on the QUERY side, so an over-long id still
32
+ * matches the row it wrote — truncation is consistent, never one-sided.
33
+ */
34
+ export function auditEntityKeyPart(value) {
35
+ return value.length > AUDIT_ENTITY_KEY_MAX ? value.slice(0, AUDIT_ENTITY_KEY_MAX) : value;
36
+ }
37
+ /**
38
+ * The denormalized per-record audit key derived from a RecordRef (30 WS-A).
39
+ *
40
+ * `entityId` reproduces the canonical `:recordId` string both sides already
41
+ * use — `pkLabel` on the server, `rowIdOf` in the grid: a single-column PK is
42
+ * its stringified value, a composite PK is the JSON tuple of its values in pk
43
+ * insertion order (the order both writers build the map in).
44
+ */
45
+ export function auditEntityKeyOf(ref) {
46
+ const values = Object.values(ref.pk);
47
+ const id = values.length === 1 ? String(values[0]) : JSON.stringify(values);
48
+ return { entityTable: auditEntityKeyPart(ref.table), entityId: auditEntityKeyPart(id) };
49
+ }
23
50
  /** The eight COMPILED locales. Still a closed set — see `builtinLocaleSchema`. */
24
51
  export const LOCALES = ['en_US', 'de_DE', 'ar_EG', 'zh_CN', 'zh_TW', 'cs_CZ', 'da_DK', 'fr_FR'];
25
52
  export const builtinLocaleSchema = z.enum(LOCALES);
@@ -77,7 +104,7 @@ export const SYSTEM_ACTION_KEYS = [
77
104
  'automations.manage', // reserved — deferred feature, no v1 enforcement (RESERVED_SYSTEM_ACTION_KEYS)
78
105
  'webhooks.manage', // reserved — deferred feature, no v1 enforcement (RESERVED_SYSTEM_ACTION_KEYS)
79
106
  'api-keys.manage',
80
- 'manifests.manage', // reserved deferred feature, no v1 enforcement (RESERVED_SYSTEM_ACTION_KEYS)
107
+ 'manifests.manage', // add-on + micro-SaaS install/connect/uninstall (26 D3)
81
108
  'audit.read',
82
109
  'sql.run', // reserved — deferred feature, no v1 enforcement (RESERVED_SYSTEM_ACTION_KEYS)
83
110
  // M7 wave 2 — data-io (T5) + scheduled reports (T6). `exports.manage` /
@@ -119,7 +146,11 @@ export const systemActionKeySchema = z.enum(SYSTEM_ACTION_KEYS);
119
146
  export const RESERVED_SYSTEM_ACTION_KEYS = [
120
147
  'automations.manage',
121
148
  'webhooks.manage',
122
- 'manifests.manage',
149
+ // `manifests.manage` UN-RESERVED 2026-08-29 (26-add-on-runtime.md D3, 26-T05)
150
+ // in the same change that landed its first enforcement point — the
151
+ // `/api/v1/add-ons` routes. That is the rule this list documents, honoured
152
+ // rather than quoted: a key becomes grantable when something checks it, and
153
+ // not one commit earlier.
123
154
  'sql.run',
124
155
  ];
125
156
  /**
@@ -153,6 +184,14 @@ export const auditCategorySchema = z.enum([
153
184
  'automation',
154
185
  'export',
155
186
  'system',
187
+ // Add-on acquisition and lifecycle (32-add-on-distribution.md §4.3): catalog
188
+ // refresh, download, verify- and unpack-refusals, upload, staged, deleted,
189
+ // upgraded. Its own category rather than a `system` action because an add-on
190
+ // ships a server half that runs in-process (24 D13) — "what code arrived on
191
+ // this deployment, from where, and did anything refuse it" is the question an
192
+ // operator asks on its own, and it should not have to be sieved out of the
193
+ // system log.
194
+ 'add-on',
156
195
  ]);
157
196
  /** `{ before, after }` images; PII-masked upstream; capped at 16 KB serialized. */
158
197
  export const auditChangesSchema = z.object({