@adminiumjs/meta 0.1.0-rc.1

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 (194) hide show
  1. package/LICENSE +661 -0
  2. package/dist/bootstrap.d.ts +103 -0
  3. package/dist/bootstrap.d.ts.map +1 -0
  4. package/dist/bootstrap.js +225 -0
  5. package/dist/bootstrap.js.map +1 -0
  6. package/dist/columns.d.ts +44 -0
  7. package/dist/columns.d.ts.map +1 -0
  8. package/dist/columns.js +57 -0
  9. package/dist/columns.js.map +1 -0
  10. package/dist/connect.d.ts +38 -0
  11. package/dist/connect.d.ts.map +1 -0
  12. package/dist/connect.js +57 -0
  13. package/dist/connect.js.map +1 -0
  14. package/dist/ids.d.ts +79 -0
  15. package/dist/ids.d.ts.map +1 -0
  16. package/dist/ids.js +165 -0
  17. package/dist/ids.js.map +1 -0
  18. package/dist/index.d.ts +21 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +21 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/migrations/0001_core_auth.d.ts +9 -0
  23. package/dist/migrations/0001_core_auth.d.ts.map +1 -0
  24. package/dist/migrations/0001_core_auth.js +102 -0
  25. package/dist/migrations/0001_core_auth.js.map +1 -0
  26. package/dist/migrations/0002_rbac.d.ts +8 -0
  27. package/dist/migrations/0002_rbac.d.ts.map +1 -0
  28. package/dist/migrations/0002_rbac.js +75 -0
  29. package/dist/migrations/0002_rbac.js.map +1 -0
  30. package/dist/migrations/0003_connections_schema.d.ts +9 -0
  31. package/dist/migrations/0003_connections_schema.d.ts.map +1 -0
  32. package/dist/migrations/0003_connections_schema.js +100 -0
  33. package/dist/migrations/0003_connections_schema.js.map +1 -0
  34. package/dist/migrations/0004_pages_views.d.ts +8 -0
  35. package/dist/migrations/0004_pages_views.d.ts.map +1 -0
  36. package/dist/migrations/0004_pages_views.js +59 -0
  37. package/dist/migrations/0004_pages_views.js.map +1 -0
  38. package/dist/migrations/0005_ops.d.ts +9 -0
  39. package/dist/migrations/0005_ops.d.ts.map +1 -0
  40. package/dist/migrations/0005_ops.js +104 -0
  41. package/dist/migrations/0005_ops.js.map +1 -0
  42. package/dist/migrations/0006_platform.d.ts +11 -0
  43. package/dist/migrations/0006_platform.d.ts.map +1 -0
  44. package/dist/migrations/0006_platform.js +259 -0
  45. package/dist/migrations/0006_platform.js.map +1 -0
  46. package/dist/migrations/0007_llm_runs.d.ts +33 -0
  47. package/dist/migrations/0007_llm_runs.d.ts.map +1 -0
  48. package/dist/migrations/0007_llm_runs.js +62 -0
  49. package/dist/migrations/0007_llm_runs.js.map +1 -0
  50. package/dist/migrations/0008_llm_overrides.d.ts +18 -0
  51. package/dist/migrations/0008_llm_overrides.d.ts.map +1 -0
  52. package/dist/migrations/0008_llm_overrides.js +24 -0
  53. package/dist/migrations/0008_llm_overrides.js.map +1 -0
  54. package/dist/migrations/0009_views_kind.d.ts +20 -0
  55. package/dist/migrations/0009_views_kind.d.ts.map +1 -0
  56. package/dist/migrations/0009_views_kind.js +24 -0
  57. package/dist/migrations/0009_views_kind.js.map +1 -0
  58. package/dist/migrations/0010_llm_prompt_version_width.d.ts +19 -0
  59. package/dist/migrations/0010_llm_prompt_version_width.d.ts.map +1 -0
  60. package/dist/migrations/0010_llm_prompt_version_width.js +28 -0
  61. package/dist/migrations/0010_llm_prompt_version_width.js.map +1 -0
  62. package/dist/migrations/index.d.ts +29 -0
  63. package/dist/migrations/index.d.ts.map +1 -0
  64. package/dist/migrations/index.js +43 -0
  65. package/dist/migrations/index.js.map +1 -0
  66. package/dist/migrator.d.ts +83 -0
  67. package/dist/migrator.d.ts.map +1 -0
  68. package/dist/migrator.js +173 -0
  69. package/dist/migrator.js.map +1 -0
  70. package/dist/prefix.d.ts +19 -0
  71. package/dist/prefix.d.ts.map +1 -0
  72. package/dist/prefix.js +33 -0
  73. package/dist/prefix.js.map +1 -0
  74. package/dist/repos/api-keys.d.ts +31 -0
  75. package/dist/repos/api-keys.d.ts.map +1 -0
  76. package/dist/repos/api-keys.js +62 -0
  77. package/dist/repos/api-keys.js.map +1 -0
  78. package/dist/repos/audit.d.ts +51 -0
  79. package/dist/repos/audit.d.ts.map +1 -0
  80. package/dist/repos/audit.js +78 -0
  81. package/dist/repos/audit.js.map +1 -0
  82. package/dist/repos/connections.d.ts +90 -0
  83. package/dist/repos/connections.d.ts.map +1 -0
  84. package/dist/repos/connections.js +191 -0
  85. package/dist/repos/connections.js.map +1 -0
  86. package/dist/repos/email-templates.d.ts +47 -0
  87. package/dist/repos/email-templates.d.ts.map +1 -0
  88. package/dist/repos/email-templates.js +93 -0
  89. package/dist/repos/email-templates.js.map +1 -0
  90. package/dist/repos/exports.d.ts +67 -0
  91. package/dist/repos/exports.d.ts.map +1 -0
  92. package/dist/repos/exports.js +132 -0
  93. package/dist/repos/exports.js.map +1 -0
  94. package/dist/repos/files.d.ts +52 -0
  95. package/dist/repos/files.d.ts.map +1 -0
  96. package/dist/repos/files.js +86 -0
  97. package/dist/repos/files.js.map +1 -0
  98. package/dist/repos/imports.d.ts +71 -0
  99. package/dist/repos/imports.d.ts.map +1 -0
  100. package/dist/repos/imports.js +111 -0
  101. package/dist/repos/imports.js.map +1 -0
  102. package/dist/repos/index.d.ts +26 -0
  103. package/dist/repos/index.d.ts.map +1 -0
  104. package/dist/repos/index.js +26 -0
  105. package/dist/repos/index.js.map +1 -0
  106. package/dist/repos/jobs.d.ts +71 -0
  107. package/dist/repos/jobs.d.ts.map +1 -0
  108. package/dist/repos/jobs.js +187 -0
  109. package/dist/repos/jobs.js.map +1 -0
  110. package/dist/repos/llm-overrides.d.ts +89 -0
  111. package/dist/repos/llm-overrides.d.ts.map +1 -0
  112. package/dist/repos/llm-overrides.js +205 -0
  113. package/dist/repos/llm-overrides.js.map +1 -0
  114. package/dist/repos/llm-runs.d.ts +114 -0
  115. package/dist/repos/llm-runs.d.ts.map +1 -0
  116. package/dist/repos/llm-runs.js +214 -0
  117. package/dist/repos/llm-runs.js.map +1 -0
  118. package/dist/repos/notification-prefs.d.ts +34 -0
  119. package/dist/repos/notification-prefs.d.ts.map +1 -0
  120. package/dist/repos/notification-prefs.js +80 -0
  121. package/dist/repos/notification-prefs.js.map +1 -0
  122. package/dist/repos/notifications.d.ts +60 -0
  123. package/dist/repos/notifications.d.ts.map +1 -0
  124. package/dist/repos/notifications.js +107 -0
  125. package/dist/repos/notifications.js.map +1 -0
  126. package/dist/repos/overrides.d.ts +59 -0
  127. package/dist/repos/overrides.d.ts.map +1 -0
  128. package/dist/repos/overrides.js +143 -0
  129. package/dist/repos/overrides.js.map +1 -0
  130. package/dist/repos/pages.d.ts +192 -0
  131. package/dist/repos/pages.d.ts.map +1 -0
  132. package/dist/repos/pages.js +374 -0
  133. package/dist/repos/pages.js.map +1 -0
  134. package/dist/repos/password-resets.d.ts +32 -0
  135. package/dist/repos/password-resets.d.ts.map +1 -0
  136. package/dist/repos/password-resets.js +56 -0
  137. package/dist/repos/password-resets.js.map +1 -0
  138. package/dist/repos/permissions.d.ts +28 -0
  139. package/dist/repos/permissions.d.ts.map +1 -0
  140. package/dist/repos/permissions.js +100 -0
  141. package/dist/repos/permissions.js.map +1 -0
  142. package/dist/repos/roles.d.ts +33 -0
  143. package/dist/repos/roles.d.ts.map +1 -0
  144. package/dist/repos/roles.js +89 -0
  145. package/dist/repos/roles.js.map +1 -0
  146. package/dist/repos/scheduled-reports.d.ts +73 -0
  147. package/dist/repos/scheduled-reports.d.ts.map +1 -0
  148. package/dist/repos/scheduled-reports.js +132 -0
  149. package/dist/repos/scheduled-reports.js.map +1 -0
  150. package/dist/repos/sessions.d.ts +33 -0
  151. package/dist/repos/sessions.d.ts.map +1 -0
  152. package/dist/repos/sessions.js +79 -0
  153. package/dist/repos/sessions.js.map +1 -0
  154. package/dist/repos/settings.d.ts +25 -0
  155. package/dist/repos/settings.d.ts.map +1 -0
  156. package/dist/repos/settings.js +73 -0
  157. package/dist/repos/settings.js.map +1 -0
  158. package/dist/repos/snapshots.d.ts +79 -0
  159. package/dist/repos/snapshots.d.ts.map +1 -0
  160. package/dist/repos/snapshots.js +191 -0
  161. package/dist/repos/snapshots.js.map +1 -0
  162. package/dist/repos/user-prefs.d.ts +56 -0
  163. package/dist/repos/user-prefs.d.ts.map +1 -0
  164. package/dist/repos/user-prefs.js +147 -0
  165. package/dist/repos/user-prefs.js.map +1 -0
  166. package/dist/repos/users.d.ts +38 -0
  167. package/dist/repos/users.d.ts.map +1 -0
  168. package/dist/repos/users.js +103 -0
  169. package/dist/repos/users.js.map +1 -0
  170. package/dist/repos/util.d.ts +45 -0
  171. package/dist/repos/util.d.ts.map +1 -0
  172. package/dist/repos/util.js +81 -0
  173. package/dist/repos/util.js.map +1 -0
  174. package/dist/repos/views.d.ts +75 -0
  175. package/dist/repos/views.d.ts.map +1 -0
  176. package/dist/repos/views.js +180 -0
  177. package/dist/repos/views.js.map +1 -0
  178. package/dist/schema/index.d.ts +4 -0
  179. package/dist/schema/index.d.ts.map +1 -0
  180. package/dist/schema/index.js +4 -0
  181. package/dist/schema/index.js.map +1 -0
  182. package/dist/schema/json-payloads.d.ts +479 -0
  183. package/dist/schema/json-payloads.d.ts.map +1 -0
  184. package/dist/schema/json-payloads.js +340 -0
  185. package/dist/schema/json-payloads.js.map +1 -0
  186. package/dist/schema/settings-registry.d.ts +187 -0
  187. package/dist/schema/settings-registry.d.ts.map +1 -0
  188. package/dist/schema/settings-registry.js +183 -0
  189. package/dist/schema/settings-registry.js.map +1 -0
  190. package/dist/schema/tables.d.ts +568 -0
  191. package/dist/schema/tables.d.ts.map +1 -0
  192. package/dist/schema/tables.js +51 -0
  193. package/dist/schema/tables.js.map +1 -0
  194. package/package.json +33 -0
@@ -0,0 +1,374 @@
1
+ /**
2
+ * pagesRepo — adminium_pages (07-meta-store.md §3.16).
3
+ *
4
+ * Every navigable page of the Generated App, dashboards included. The
5
+ * `config` column is the opaque, already-validated envelope JSON
6
+ * (01-architecture.md §6.1) — `@adminium/meta` never imports the engine
7
+ * schemas; the server is the single write-time validator.
8
+ *
9
+ * Generator contract (M4-T08): `upsertGenerated` is idempotent — stable
10
+ * `page_<slug>` ids, unchanged documents are not rewritten, changed ones
11
+ * bump `revision`, rows the generator no longer emits are pruned (unless
12
+ * human-edited — see below), and rows whose `origin` is not `generated`
13
+ * (user/manifest/system pages) are never touched or pruned. The M5
14
+ * regeneration safety net keys on the `config.generatedHash` the engine
15
+ * embeds in each generated envelope (04-widget-registry.md §6.3 note: user
16
+ * delta wins): when the caller supplies the hash function, a stored document
17
+ * whose embedded hash no longer matches (a human edited it — `setLayout`
18
+ * deliberately leaves the hash stale) is skipped, not overwritten, and
19
+ * reported in `skippedEdited` — the full diff proposal UI is 04-T15. The
20
+ * same guard extends to deletion: an edited row missing from the new set is
21
+ * kept, not pruned, and reported in `keptEdited`; only unedited orphans
22
+ * (byte-identically regenerable) are deleted. Without `hashEnvelope` the
23
+ * legacy full prune applies.
24
+ */
25
+ import { newId } from '../ids.js';
26
+ import { MetaValidationError, jsonEquals, packJson, readBool, readJson, writeBool, } from './util.js';
27
+ export const PAGE_ORIGINS = ['generated', 'user', 'manifest', 'system', 'llm'];
28
+ /**
29
+ * True when a stored generated-origin envelope no longer matches its embedded
30
+ * `config.generatedHash` — the edited-page signal (human writes update the
31
+ * document but never the hash). Rows without a string hash are treated as
32
+ * untouched: only the generator embeds one, and regenerating restores it.
33
+ */
34
+ function isEditedEnvelope(stored, hashEnvelope) {
35
+ if (typeof stored !== 'object' || stored === null)
36
+ return false;
37
+ const envelope = stored;
38
+ const config = envelope['config'];
39
+ if (typeof config !== 'object' || config === null)
40
+ return false;
41
+ const embedded = config['generatedHash'];
42
+ if (typeof embedded !== 'string')
43
+ return false;
44
+ return hashEnvelope(envelope) !== embedded;
45
+ }
46
+ function decode(row) {
47
+ return {
48
+ id: row.id,
49
+ connectionId: row.connectionId,
50
+ slug: row.slug,
51
+ type: row.type,
52
+ title: row.title,
53
+ icon: row.icon,
54
+ navGroup: row.navGroup,
55
+ navOrder: row.navOrder,
56
+ config: readJson(row.config),
57
+ origin: row.origin,
58
+ manifestId: row.manifestId,
59
+ generatedFromSnapshotId: row.generatedFromSnapshotId,
60
+ revision: row.revision,
61
+ isEnabled: readBool(row.isEnabled),
62
+ createdBy: row.createdBy,
63
+ createdAt: row.createdAt,
64
+ updatedAt: row.updatedAt,
65
+ };
66
+ }
67
+ export function pagesRepo(meta) {
68
+ const { db } = meta;
69
+ return {
70
+ /**
71
+ * Idempotent bulk upsert of one generation run for a connection.
72
+ * Insert new rows, update changed ones (revision + 1), skip unchanged,
73
+ * prune generated rows missing from the new set. Non-generated rows are
74
+ * reported in `preserved` and never modified.
75
+ */
76
+ async upsertGenerated(connectionId, pages, opts = {}) {
77
+ const at = opts.at ?? Date.now();
78
+ const prune = opts.prune ?? true;
79
+ const ids = new Set(pages.map((p) => p.id));
80
+ if (ids.size !== pages.length) {
81
+ throw new MetaValidationError('duplicate page ids in one generation run');
82
+ }
83
+ for (const input of pages) {
84
+ if (input.id.length > 36) {
85
+ throw new MetaValidationError(`page id exceeds char(36): ${input.id}`);
86
+ }
87
+ }
88
+ return db.transaction().execute(async (trx) => {
89
+ const existing = await trx
90
+ .selectFrom('adminium_pages')
91
+ .selectAll()
92
+ .where('connectionId', '=', connectionId)
93
+ .execute();
94
+ const byId = new Map(existing.map((row) => [row.id, row]));
95
+ const result = {
96
+ created: 0,
97
+ updated: 0,
98
+ unchanged: 0,
99
+ pruned: 0,
100
+ preserved: [],
101
+ skippedEdited: [],
102
+ keptEdited: [],
103
+ };
104
+ for (const input of pages) {
105
+ const row = byId.get(input.id);
106
+ const packed = packJson(input.config);
107
+ if (row === undefined) {
108
+ await trx
109
+ .insertInto('adminium_pages')
110
+ .values({
111
+ id: input.id,
112
+ connectionId,
113
+ slug: input.slug,
114
+ type: input.type,
115
+ title: input.title,
116
+ icon: input.icon ?? null,
117
+ navGroup: input.navGroup ?? null,
118
+ navOrder: input.navOrder ?? 0,
119
+ config: packed,
120
+ origin: 'generated',
121
+ manifestId: null,
122
+ generatedFromSnapshotId: opts.snapshotId ?? null,
123
+ revision: 1,
124
+ isEnabled: writeBool(meta, true),
125
+ createdBy: opts.createdBy ?? null,
126
+ createdAt: at,
127
+ updatedAt: at,
128
+ })
129
+ .execute();
130
+ result.created += 1;
131
+ continue;
132
+ }
133
+ if (row.origin !== 'generated') {
134
+ // A user/manifest page claimed this id — regeneration never
135
+ // overwrites it (user delta wins, 04 §6.3).
136
+ result.preserved.push(row.id);
137
+ continue;
138
+ }
139
+ // Structural, not serialized-string, equality: pg jsonb / mysql json
140
+ // do not preserve key order, so the round-tripped document rarely
141
+ // re-serializes byte-identical to `packed` (util.ts jsonEquals).
142
+ const unchanged = jsonEquals(readJson(row.config), input.config) &&
143
+ row.slug === input.slug &&
144
+ row.type === input.type &&
145
+ row.title === input.title &&
146
+ (row.icon ?? null) === (input.icon ?? null) &&
147
+ (row.navGroup ?? null) === (input.navGroup ?? null) &&
148
+ row.navOrder === (input.navOrder ?? 0);
149
+ if (unchanged) {
150
+ result.unchanged += 1;
151
+ continue;
152
+ }
153
+ if (opts.hashEnvelope !== undefined &&
154
+ isEditedEnvelope(readJson(row.config), opts.hashEnvelope)) {
155
+ // User delta wins (04 §6.3): the stored document was edited after
156
+ // generation, so this run must not clobber it. The row keeps its
157
+ // snapshot lineage too — it no longer descends from this run.
158
+ result.skippedEdited.push(row.id);
159
+ continue;
160
+ }
161
+ await trx
162
+ .updateTable('adminium_pages')
163
+ .set({
164
+ slug: input.slug,
165
+ type: input.type,
166
+ title: input.title,
167
+ icon: input.icon ?? null,
168
+ navGroup: input.navGroup ?? null,
169
+ navOrder: input.navOrder ?? 0,
170
+ config: packed,
171
+ generatedFromSnapshotId: opts.snapshotId ?? null,
172
+ revision: row.revision + 1,
173
+ updatedAt: at,
174
+ })
175
+ .where('id', '=', row.id)
176
+ .execute();
177
+ result.updated += 1;
178
+ }
179
+ if (prune) {
180
+ for (const row of existing) {
181
+ if (row.origin !== 'generated' || ids.has(row.id))
182
+ continue;
183
+ if (opts.hashEnvelope !== undefined &&
184
+ isEditedEnvelope(readJson(row.config), opts.hashEnvelope)) {
185
+ // User delta wins extends to deletion (04 §6.3): the generator
186
+ // dropped this page (table removed/hidden between runs), but a
187
+ // human customized the stored document, so pruning would
188
+ // destroy work that cannot be regenerated. Keep the row exactly
189
+ // as-is — origin stays 'generated', it stays enabled, and its
190
+ // snapshot lineage is untouched. Unedited orphans are
191
+ // byte-identically regenerable and still delete below.
192
+ result.keptEdited.push(row.id);
193
+ continue;
194
+ }
195
+ await trx.deleteFrom('adminium_pages').where('id', '=', row.id).execute();
196
+ result.pruned += 1;
197
+ }
198
+ }
199
+ return result;
200
+ });
201
+ },
202
+ /** Create a non-generated page (user/manifest/system flows, seeds). */
203
+ async create(input, at = Date.now()) {
204
+ const origin = input.origin ?? 'user';
205
+ if (!PAGE_ORIGINS.includes(origin)) {
206
+ throw new MetaValidationError(`invalid page origin ${JSON.stringify(origin)}`);
207
+ }
208
+ const row = {
209
+ id: newId('page'),
210
+ connectionId: input.connectionId ?? null,
211
+ slug: input.slug,
212
+ type: input.type,
213
+ title: input.title,
214
+ icon: input.icon ?? null,
215
+ navGroup: input.navGroup ?? null,
216
+ navOrder: input.navOrder ?? 0,
217
+ config: packJson(input.config),
218
+ origin,
219
+ manifestId: null,
220
+ generatedFromSnapshotId: null,
221
+ revision: 1,
222
+ isEnabled: writeBool(meta, true),
223
+ createdBy: input.createdBy ?? null,
224
+ createdAt: at,
225
+ updatedAt: at,
226
+ };
227
+ await db.insertInto('adminium_pages').values(row).execute();
228
+ return decode(row);
229
+ },
230
+ async findById(id) {
231
+ const row = await db
232
+ .selectFrom('adminium_pages')
233
+ .selectAll()
234
+ .where('id', '=', id)
235
+ .executeTakeFirst();
236
+ return row === undefined ? null : decode(row);
237
+ },
238
+ /**
239
+ * Write the shared default dashboard layout into the envelope's
240
+ * `config.layout` slot (04-widget-registry.md §6.3; the renderer and engine
241
+ * envelope validator both read `envelope.config.layout`). Merges over the
242
+ * stored envelope so the rest of the document (title/source/nav and the
243
+ * other template config keys) is untouched, and bumps `updatedAt` so the
244
+ * bootstrap `configVersion` advances and clients re-fetch. `revision`
245
+ * bumps too — the counter tracks every changed document, human or machine
246
+ * (override-staleness and future H5 diff/telemetry read it) — while the
247
+ * embedded `config.generatedHash` deliberately stays stale: that mismatch
248
+ * IS the edited-page signal `upsertGenerated` keys on. The `layout` value
249
+ * is validated by the server route before it reaches here. Returns the
250
+ * reloaded page, or null if the id does not exist.
251
+ */
252
+ async setLayout(pageId, layout, at = Date.now()) {
253
+ const page = await this.findById(pageId);
254
+ if (page === null)
255
+ return null;
256
+ const envelope = typeof page.config === 'object' && page.config !== null
257
+ ? page.config
258
+ : {};
259
+ const templateConfig = typeof envelope['config'] === 'object' && envelope['config'] !== null
260
+ ? envelope['config']
261
+ : {};
262
+ const nextEnvelope = { ...envelope, config: { ...templateConfig, layout } };
263
+ await db
264
+ .updateTable('adminium_pages')
265
+ .set({ config: packJson(nextEnvelope), revision: page.revision + 1, updatedAt: at })
266
+ .where('id', '=', pageId)
267
+ .execute();
268
+ return this.findById(pageId);
269
+ },
270
+ /**
271
+ * Replace a page's whole config document — the 06-llm-assist.md §8.3
272
+ * materialization write: the apply executor seeds `origin: 'llm'` rows with
273
+ * a minimal `{source, llmRunId}` config and the regeneration hook expands
274
+ * it into the full validated envelope from the active snapshot. Bumps
275
+ * `revision` + `updatedAt` (configVersion advances → clients re-fetch);
276
+ * `icon` is back-filled only when the row has none. `title`/`navGroup`,
277
+ * when provided, sync the row's nav projection from the envelope — the
278
+ * bootstrap tree reads the ROW columns, so without this an expanded llm
279
+ * page would stay outside the nav (and `/p/$slug` resolves from the nav
280
+ * tree, leaving the page unreachable). Returns the reloaded page, or null
281
+ * if the id does not exist.
282
+ */
283
+ async replaceConfig(pageId, config, opts = {}) {
284
+ const page = await this.findById(pageId);
285
+ if (page === null)
286
+ return null;
287
+ const at = opts.at ?? Date.now();
288
+ const icon = opts.icon ?? null;
289
+ await db
290
+ .updateTable('adminium_pages')
291
+ .set({
292
+ config: packJson(config),
293
+ ...(page.icon === null && icon !== null ? { icon } : {}),
294
+ ...(opts.title === undefined ? {} : { title: opts.title }),
295
+ ...(opts.navGroup === undefined ? {} : { navGroup: opts.navGroup }),
296
+ revision: page.revision + 1,
297
+ updatedAt: at,
298
+ })
299
+ .where('id', '=', pageId)
300
+ .execute();
301
+ return this.findById(pageId);
302
+ },
303
+ /**
304
+ * Toggle a page's visibility (nav + GET both key on `isEnabled`). Bumps
305
+ * `updatedAt` only — the document itself is unchanged, so `revision`
306
+ * stays. Used by the §8.3 materialization pass to park an llm seed whose
307
+ * template cannot compose yet, instead of serving an invalid-config card.
308
+ */
309
+ async setEnabled(pageId, isEnabled, at = Date.now()) {
310
+ await db
311
+ .updateTable('adminium_pages')
312
+ .set({ isEnabled: writeBool(meta, isEnabled), updatedAt: at })
313
+ .where('id', '=', pageId)
314
+ .execute();
315
+ },
316
+ /** Slugs are unique per connection (uq_adminium_pages_conn_slug). */
317
+ async findBySlug(connectionId, slug) {
318
+ let q = db.selectFrom('adminium_pages').selectAll().where('slug', '=', slug);
319
+ q =
320
+ connectionId === null
321
+ ? q.where('connectionId', 'is', null)
322
+ : q.where('connectionId', '=', connectionId);
323
+ const row = await q.executeTakeFirst();
324
+ return row === undefined ? null : decode(row);
325
+ },
326
+ async listForConnection(connectionId) {
327
+ const rows = await db
328
+ .selectFrom('adminium_pages')
329
+ .selectAll()
330
+ .where('connectionId', '=', connectionId)
331
+ .orderBy('navOrder', 'asc')
332
+ .orderBy('slug', 'asc')
333
+ .execute();
334
+ return rows.map(decode);
335
+ },
336
+ /**
337
+ * The bootstrap nav projection — every page row, nav fields only
338
+ * (09-generated-app.md §2.2; the route buckets these into the five fixed
339
+ * groups and derives `configVersion` from max updatedAt).
340
+ */
341
+ async navRows() {
342
+ return db
343
+ .selectFrom('adminium_pages')
344
+ .select(['id', 'connectionId', 'slug', 'title', 'icon', 'navGroup', 'navOrder', 'isEnabled', 'updatedAt'])
345
+ .execute();
346
+ },
347
+ /** Generated-page counts per connection (connections-hub cards, 09 §8.1). */
348
+ async countGeneratedByConnection() {
349
+ const rows = await db
350
+ .selectFrom('adminium_pages')
351
+ .select(['connectionId'])
352
+ .select((eb) => eb.fn.countAll().as('pages'))
353
+ .where('origin', '=', 'generated')
354
+ .where('connectionId', 'is not', null)
355
+ .groupBy('connectionId')
356
+ .execute();
357
+ const out = {};
358
+ for (const row of rows) {
359
+ if (row.connectionId !== null)
360
+ out[row.connectionId] = Number(row.pages);
361
+ }
362
+ return out;
363
+ },
364
+ /** Max updatedAt over all pages — the bootstrap `configVersion` stamp. */
365
+ async configVersion() {
366
+ const row = await db
367
+ .selectFrom('adminium_pages')
368
+ .select((eb) => eb.fn.max('updatedAt').as('max'))
369
+ .executeTakeFirst();
370
+ return Number(row?.max ?? 0);
371
+ },
372
+ };
373
+ }
374
+ //# sourceMappingURL=pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/repos/pages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * passwordResetsRepo — adminium_password_resets (07-meta-store.md §3.6).
3
+ * Carries both reset and invite-activation tokens; single-use.
4
+ */
5
+ import type { Selectable } from 'kysely';
6
+ import { z } from 'zod';
7
+ import type { MetaDb } from '../connect.js';
8
+ import type { AdminiumPasswordResetsTable } from '../schema/tables.js';
9
+ export declare const resetKindSchema: z.ZodEnum<{
10
+ reset: "reset";
11
+ invite: "invite";
12
+ }>;
13
+ export type ResetKind = z.infer<typeof resetKindSchema>;
14
+ export type PasswordReset = Selectable<AdminiumPasswordResetsTable>;
15
+ export interface CreatePasswordResetInput {
16
+ userId: string;
17
+ kind: ResetKind;
18
+ tokenHash: string;
19
+ /** reset: +2 h; invite: +7 days — computed by the server (§3.6). */
20
+ expiresAt: number;
21
+ }
22
+ export declare function passwordResetsRepo(meta: MetaDb): {
23
+ create(input: CreatePasswordResetInput, at?: number): Promise<PasswordReset>;
24
+ /** Unused and unexpired at `at`. */
25
+ findValidByTokenHash(tokenHash: string, at?: number): Promise<PasswordReset | null>;
26
+ /** Single-use guard: only the first consume wins. */
27
+ consume(id: string, at?: number): Promise<boolean>;
28
+ /** Retention §8 `password-resets` policy: used, or expired > 24 h ago. */
29
+ gc(at?: number): Promise<number>;
30
+ };
31
+ export type PasswordResetsRepo = ReturnType<typeof passwordResetsRepo>;
32
+ //# sourceMappingURL=password-resets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-resets.d.ts","sourceRoot":"","sources":["../../src/repos/password-resets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAGvE,eAAO,MAAM,eAAe;;;EAA8B,CAAC;AAC3D,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,2BAA2B,CAAC,CAAC;AAEpE,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM;kBAGvB,wBAAwB,OAAM,MAAM,GAAgB,OAAO,CAAC,aAAa,CAAC;IAc9F,oCAAoC;oCACE,MAAM,OAAM,MAAM,GAAgB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAWrG,qDAAqD;gBACnC,MAAM,OAAM,MAAM,GAAgB,OAAO,CAAC,OAAO,CAAC;IAUpE,0EAA0E;YAC7D,MAAM,GAAgB,OAAO,CAAC,MAAM,CAAC;EAQrD;AAED,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * passwordResetsRepo — adminium_password_resets (07-meta-store.md §3.6).
3
+ * Carries both reset and invite-activation tokens; single-use.
4
+ */
5
+ import { z } from 'zod';
6
+ import { newId } from '../ids.js';
7
+ import { DAY_MS } from './util.js';
8
+ export const resetKindSchema = z.enum(['reset', 'invite']);
9
+ export function passwordResetsRepo(meta) {
10
+ const { db } = meta;
11
+ return {
12
+ async create(input, at = Date.now()) {
13
+ const row = {
14
+ id: newId('rst'),
15
+ userId: input.userId,
16
+ kind: resetKindSchema.parse(input.kind),
17
+ tokenHash: input.tokenHash,
18
+ expiresAt: input.expiresAt,
19
+ usedAt: null,
20
+ createdAt: at,
21
+ };
22
+ await db.insertInto('adminium_password_resets').values(row).execute();
23
+ return row;
24
+ },
25
+ /** Unused and unexpired at `at`. */
26
+ async findValidByTokenHash(tokenHash, at = Date.now()) {
27
+ const row = await db
28
+ .selectFrom('adminium_password_resets')
29
+ .selectAll()
30
+ .where('tokenHash', '=', tokenHash)
31
+ .where('usedAt', 'is', null)
32
+ .where('expiresAt', '>', at)
33
+ .executeTakeFirst();
34
+ return row ?? null;
35
+ },
36
+ /** Single-use guard: only the first consume wins. */
37
+ async consume(id, at = Date.now()) {
38
+ const res = await db
39
+ .updateTable('adminium_password_resets')
40
+ .set({ usedAt: at })
41
+ .where('id', '=', id)
42
+ .where('usedAt', 'is', null)
43
+ .executeTakeFirst();
44
+ return Number(res.numUpdatedRows) === 1;
45
+ },
46
+ /** Retention §8 `password-resets` policy: used, or expired > 24 h ago. */
47
+ async gc(at = Date.now()) {
48
+ const res = await db
49
+ .deleteFrom('adminium_password_resets')
50
+ .where((eb) => eb.or([eb('usedAt', 'is not', null), eb('expiresAt', '<', at - DAY_MS)]))
51
+ .executeTakeFirst();
52
+ return Number(res.numDeletedRows);
53
+ },
54
+ };
55
+ }
56
+ //# sourceMappingURL=password-resets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-resets.js","sourceRoot":"","sources":["../../src/repos/password-resets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAa3D,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IACpB,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,KAA+B,EAAE,KAAa,IAAI,CAAC,GAAG,EAAE;YACnE,MAAM,GAAG,GAAkB;gBACzB,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC;gBAChB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,IAAI,EAAE,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;gBACvC,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,MAAM,EAAE,IAAI;gBACZ,SAAS,EAAE,EAAE;aACd,CAAC;YACF,MAAM,EAAE,CAAC,UAAU,CAAC,0BAA0B,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;YACtE,OAAO,GAAG,CAAC;QACb,CAAC;QAED,oCAAoC;QACpC,KAAK,CAAC,oBAAoB,CAAC,SAAiB,EAAE,KAAa,IAAI,CAAC,GAAG,EAAE;YACnE,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,UAAU,CAAC,0BAA0B,CAAC;iBACtC,SAAS,EAAE;iBACX,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,SAAS,CAAC;iBAClC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC;iBAC3B,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,EAAE,CAAC;iBAC3B,gBAAgB,EAAE,CAAC;YACtB,OAAO,GAAG,IAAI,IAAI,CAAC;QACrB,CAAC;QAED,qDAAqD;QACrD,KAAK,CAAC,OAAO,CAAC,EAAU,EAAE,KAAa,IAAI,CAAC,GAAG,EAAE;YAC/C,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,WAAW,CAAC,0BAA0B,CAAC;iBACvC,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;iBACnB,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;iBACpB,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC;iBAC3B,gBAAgB,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QAED,0EAA0E;QAC1E,KAAK,CAAC,EAAE,CAAC,KAAa,IAAI,CAAC,GAAG,EAAE;YAC9B,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,UAAU,CAAC,0BAA0B,CAAC;iBACtC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;iBACvF,gBAAgB,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACpC,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * permissionsRepo — adminium_role_permissions (07-meta-store.md §3.9).
3
+ * The `actions` JSON is Zod-validated per resource kind and never queried in
4
+ * SQL (the server layers an in-memory cache on top).
5
+ */
6
+ import type { MetaDb } from '../connect.js';
7
+ import { type PermissionActions, type ResourceKind } from '../schema/json-payloads.js';
8
+ export interface RolePermission {
9
+ id: string;
10
+ roleId: string;
11
+ resourceKind: ResourceKind;
12
+ resourceRef: string;
13
+ actions: PermissionActions;
14
+ }
15
+ export declare function permissionsRepo(meta: MetaDb): {
16
+ find: (roleId: string, resourceKind: ResourceKind, resourceRef: string) => Promise<RolePermission | null>;
17
+ /** Upsert one matrix row keyed by (role, kind, ref). */
18
+ grant(roleId: string, resourceKind: ResourceKind, resourceRef: string, actions: PermissionActions): Promise<RolePermission>;
19
+ revoke(roleId: string, resourceKind: ResourceKind, resourceRef: string): Promise<boolean>;
20
+ listForRole(roleId: string): Promise<RolePermission[]>;
21
+ /**
22
+ * Single matrix-cell check: `action` is `read`/`update`/… for tables,
23
+ * `view`/`edit` for pages, and ignored (the ref IS the action) for system.
24
+ */
25
+ isAllowed(roleId: string, resourceKind: ResourceKind, resourceRef: string, action?: string): Promise<boolean>;
26
+ };
27
+ export type PermissionsRepo = ReturnType<typeof permissionsRepo>;
28
+ //# sourceMappingURL=permissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/repos/permissions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,YAAY,EAClB,MAAM,4BAA4B,CAAC;AAGpC,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM;mBAGd,MAAM,gBAAgB,YAAY,eAAe,MAAM,KAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAsBlH,wDAAwD;kBAE9C,MAAM,gBACA,YAAY,eACb,MAAM,WACV,iBAAiB,GACzB,OAAO,CAAC,cAAc,CAAC;mBAsBL,MAAM,gBAAgB,YAAY,eAAe,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;wBAUrE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAoB5D;;;OAGG;sBACqB,MAAM,gBAAgB,YAAY,eAAe,MAAM,WAAW,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;EAStH;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * permissionsRepo — adminium_role_permissions (07-meta-store.md §3.9).
3
+ * The `actions` JSON is Zod-validated per resource kind and never queried in
4
+ * SQL (the server layers an in-memory cache on top).
5
+ */
6
+ import { newId } from '../ids.js';
7
+ import { permissionActionsSchemaFor, resourceKindSchema, } from '../schema/json-payloads.js';
8
+ import { packJson, readJson } from './util.js';
9
+ export function permissionsRepo(meta) {
10
+ const { db } = meta;
11
+ async function find(roleId, resourceKind, resourceRef) {
12
+ const row = await db
13
+ .selectFrom('adminium_role_permissions')
14
+ .selectAll()
15
+ .where('roleId', '=', roleId)
16
+ .where('resourceKind', '=', resourceKind)
17
+ .where('resourceRef', '=', resourceRef)
18
+ .executeTakeFirst();
19
+ if (!row)
20
+ return null;
21
+ const kind = resourceKindSchema.parse(row.resourceKind);
22
+ return {
23
+ id: row.id,
24
+ roleId: row.roleId,
25
+ resourceKind: kind,
26
+ resourceRef: row.resourceRef,
27
+ actions: permissionActionsSchemaFor(kind).parse(readJson(row.actions)),
28
+ };
29
+ }
30
+ return {
31
+ find,
32
+ /** Upsert one matrix row keyed by (role, kind, ref). */
33
+ async grant(roleId, resourceKind, resourceRef, actions) {
34
+ const kind = resourceKindSchema.parse(resourceKind);
35
+ const validated = permissionActionsSchemaFor(kind).parse(actions);
36
+ const value = packJson(validated);
37
+ const res = await db
38
+ .updateTable('adminium_role_permissions')
39
+ .set({ actions: value })
40
+ .where('roleId', '=', roleId)
41
+ .where('resourceKind', '=', kind)
42
+ .where('resourceRef', '=', resourceRef)
43
+ .executeTakeFirst();
44
+ if (Number(res.numUpdatedRows) === 0) {
45
+ await db
46
+ .insertInto('adminium_role_permissions')
47
+ .values({ id: newId('perm'), roleId, resourceKind: kind, resourceRef, actions: value })
48
+ .execute();
49
+ }
50
+ const row = await find(roleId, kind, resourceRef);
51
+ if (!row)
52
+ throw new Error('permission row disappeared during grant');
53
+ return row;
54
+ },
55
+ async revoke(roleId, resourceKind, resourceRef) {
56
+ const res = await db
57
+ .deleteFrom('adminium_role_permissions')
58
+ .where('roleId', '=', roleId)
59
+ .where('resourceKind', '=', resourceKind)
60
+ .where('resourceRef', '=', resourceRef)
61
+ .executeTakeFirst();
62
+ return Number(res.numDeletedRows) === 1;
63
+ },
64
+ async listForRole(roleId) {
65
+ const rows = await db
66
+ .selectFrom('adminium_role_permissions')
67
+ .selectAll()
68
+ .where('roleId', '=', roleId)
69
+ .orderBy('resourceKind', 'asc')
70
+ .orderBy('resourceRef', 'asc')
71
+ .execute();
72
+ return rows.map((row) => {
73
+ const kind = resourceKindSchema.parse(row.resourceKind);
74
+ return {
75
+ id: row.id,
76
+ roleId: row.roleId,
77
+ resourceKind: kind,
78
+ resourceRef: row.resourceRef,
79
+ actions: permissionActionsSchemaFor(kind).parse(readJson(row.actions)),
80
+ };
81
+ });
82
+ },
83
+ /**
84
+ * Single matrix-cell check: `action` is `read`/`update`/… for tables,
85
+ * `view`/`edit` for pages, and ignored (the ref IS the action) for system.
86
+ */
87
+ async isAllowed(roleId, resourceKind, resourceRef, action) {
88
+ const row = await find(roleId, resourceKind, resourceRef);
89
+ if (!row)
90
+ return false;
91
+ if (resourceKind === 'system')
92
+ return row.actions.allowed;
93
+ if (action === undefined)
94
+ return false;
95
+ const value = row.actions[action];
96
+ return value === true;
97
+ },
98
+ };
99
+ }
100
+ //# sourceMappingURL=permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/repos/permissions.ts"],"names":[],"mappings":"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"}