@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,93 @@
1
+ /**
2
+ * emailTemplatesRepo — adminium_email_templates (07-meta-store.md §3.28):
3
+ * overrides of built-in email templates, unique on `(key, locale)`. The row
4
+ * IS the template the workspace edits; `is_builtin_copy` marks rows the
5
+ * server seeded verbatim from a built-in (true) versus rows a human has
6
+ * touched (false — every editor write clears it, §3.28).
7
+ *
8
+ * `blocks` is the ordered open-record array (`emailBlocksSchema`); the
9
+ * concrete block shape is owned by the email editor (09-generated-app.md
10
+ * §email-editor) — the repo validates the envelope, never the block bodies.
11
+ */
12
+ import { newId } from '../ids.js';
13
+ import { emailBlocksSchema } from '../schema/json-payloads.js';
14
+ import { affected, packJson, readBool, readJson, writeBool } from './util.js';
15
+ function decode(row) {
16
+ return {
17
+ id: row.id,
18
+ key: row.key,
19
+ locale: row.locale,
20
+ name: row.name,
21
+ subject: row.subject,
22
+ blocks: emailBlocksSchema.parse(readJson(row.blocks)),
23
+ enabled: readBool(row.enabled),
24
+ isBuiltinCopy: readBool(row.isBuiltinCopy),
25
+ updatedBy: row.updatedBy,
26
+ createdAt: row.createdAt,
27
+ updatedAt: row.updatedAt,
28
+ };
29
+ }
30
+ export function emailTemplatesRepo(meta) {
31
+ const { db } = meta;
32
+ async function findByKeyLocale(key, locale) {
33
+ const row = await db
34
+ .selectFrom('adminium_email_templates')
35
+ .selectAll()
36
+ .where('key', '=', key)
37
+ .where('locale', '=', locale)
38
+ .executeTakeFirst();
39
+ return row ? decode(row) : null;
40
+ }
41
+ return {
42
+ findByKeyLocale,
43
+ async list() {
44
+ const rows = await db
45
+ .selectFrom('adminium_email_templates')
46
+ .selectAll()
47
+ .orderBy('key', 'asc')
48
+ .orderBy('locale', 'asc')
49
+ .execute();
50
+ return rows.map(decode);
51
+ },
52
+ /**
53
+ * `(key, locale)` upsert, portably: UPDATE first, INSERT on zero affected
54
+ * rows (no cross-dialect ON CONFLICT — repos/util.ts convention).
55
+ */
56
+ async upsert(key, locale, input, at = Date.now()) {
57
+ const blocks = packJson(emailBlocksSchema.parse(input.blocks));
58
+ const shared = {
59
+ name: input.name,
60
+ subject: input.subject,
61
+ blocks,
62
+ enabled: writeBool(meta, input.enabled),
63
+ isBuiltinCopy: writeBool(meta, input.isBuiltinCopy ?? false),
64
+ updatedBy: input.updatedBy ?? null,
65
+ };
66
+ const res = await db
67
+ .updateTable('adminium_email_templates')
68
+ .set({ ...shared, updatedAt: at })
69
+ .where('key', '=', key)
70
+ .where('locale', '=', locale)
71
+ .executeTakeFirst();
72
+ if (affected(res.numUpdatedRows) === 0) {
73
+ await db
74
+ .insertInto('adminium_email_templates')
75
+ .values({ id: newId('tpl'), key, locale, ...shared, createdAt: at, updatedAt: at })
76
+ .execute();
77
+ }
78
+ const row = await findByKeyLocale(key, locale);
79
+ if (row === null)
80
+ throw new Error(`email template upsert lost its row: ${key}/${locale}`);
81
+ return row;
82
+ },
83
+ async remove(key, locale) {
84
+ const res = await db
85
+ .deleteFrom('adminium_email_templates')
86
+ .where('key', '=', key)
87
+ .where('locale', '=', locale)
88
+ .executeTakeFirst();
89
+ return affected(res.numDeletedRows) === 1;
90
+ },
91
+ };
92
+ }
93
+ //# sourceMappingURL=email-templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-templates.js","sourceRoot":"","sources":["../../src/repos/email-templates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * exportsRepo — adminium_exports (07-meta-store.md §3.25): one row per data
3
+ * export request. The row is the export's public state machine
4
+ * (`processing → ready | failed | cancelled | expired`); the artifact itself
5
+ * is an adminium_files row (`file_id`) written by the `export-run` job.
6
+ */
7
+ import type { MetaDb } from '../connect.js';
8
+ export type ExportFormat = 'csv' | 'json' | 'xlsx';
9
+ export type ExportStatus = 'processing' | 'ready' | 'failed' | 'cancelled' | 'expired';
10
+ export interface ExportSource {
11
+ kind: 'table' | 'view' | 'page';
12
+ table?: string | null | undefined;
13
+ viewId?: string | null | undefined;
14
+ filters?: unknown[] | undefined;
15
+ }
16
+ export interface DataExport {
17
+ id: string;
18
+ connectionId: string | null;
19
+ requestedBy: string;
20
+ source: ExportSource;
21
+ format: ExportFormat;
22
+ status: ExportStatus;
23
+ fileId: string | null;
24
+ rowCount: number | null;
25
+ error: string | null;
26
+ createdAt: number;
27
+ completedAt: number | null;
28
+ expiresAt: number | null;
29
+ }
30
+ export interface CreateExportInput {
31
+ connectionId?: string | null;
32
+ requestedBy: string;
33
+ source: ExportSource;
34
+ format: ExportFormat;
35
+ }
36
+ export declare function exportsRepo(meta: MetaDb): {
37
+ findById: (id: string) => Promise<DataExport | null>;
38
+ create(input: CreateExportInput, at?: number): Promise<DataExport>;
39
+ /** Newest first; `requestedBy` scopes to one user (the "mine" list). */
40
+ list(opts?: {
41
+ requestedBy?: string;
42
+ limit?: number;
43
+ }): Promise<DataExport[]>;
44
+ /** processing → ready, stamping the artifact + retention window. */
45
+ markReady(id: string, result: {
46
+ fileId: string;
47
+ rowCount: number;
48
+ expiresAt: number | null;
49
+ }, at?: number): Promise<boolean>;
50
+ markFailed(id: string, error: string, at?: number): Promise<boolean>;
51
+ markCancelled(id: string, at?: number): Promise<boolean>;
52
+ /** Retention sweep: ready rows past `expires_at` flip to `expired`. */
53
+ expireDue(at?: number): Promise<number>;
54
+ /**
55
+ * Byte-GC worklist (retention hygiene): expired exports whose artifact
56
+ * file row is not yet soft-deleted. The sweep marks each file deleted and
57
+ * removes its bytes — re-querying (instead of returning `expireDue`'s
58
+ * rows) makes the pass self-healing after a crash mid-GC.
59
+ */
60
+ listExpiredArtifacts(limit?: number): Promise<{
61
+ id: string;
62
+ fileId: string;
63
+ storageKey: string;
64
+ }[]>;
65
+ };
66
+ export type ExportsRepo = ReturnType<typeof exportsRepo>;
67
+ //# sourceMappingURL=exports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../../src/repos/exports.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAU5C,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AACnD,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAEvF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;CACtB;AAmBD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM;mBAGV,MAAM,KAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;kBAQzC,iBAAiB,OAAM,MAAM,GAAgB,OAAO,CAAC,UAAU,CAAC;IAmBpF,wEAAwE;gBAEhE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7C,OAAO,CAAC,UAAU,EAAE,CAAC;IAWxB,oEAAoE;kBAE9D,MAAM,UACF;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,OAClE,MAAM,GACT,OAAO,CAAC,OAAO,CAAC;mBAgBE,MAAM,SAAS,MAAM,OAAM,MAAM,GAAgB,OAAO,CAAC,OAAO,CAAC;sBAU9D,MAAM,OAAM,MAAM,GAAgB,OAAO,CAAC,OAAO,CAAC;IAU1E,uEAAuE;mBACnD,MAAM,GAAgB,OAAO,CAAC,MAAM,CAAC;IAWzD;;;;;OAKG;0CAGA,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;EAgBnE;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * exportsRepo — adminium_exports (07-meta-store.md §3.25): one row per data
3
+ * export request. The row is the export's public state machine
4
+ * (`processing → ready | failed | cancelled | expired`); the artifact itself
5
+ * is an adminium_files row (`file_id`) written by the `export-run` job.
6
+ */
7
+ import { newId } from '../ids.js';
8
+ import { exportFormatSchema, exportSourceSchema, exportStatusSchema, } from '../schema/json-payloads.js';
9
+ import { affected, packJson, readJson } from './util.js';
10
+ function decode(row) {
11
+ return {
12
+ id: row.id,
13
+ connectionId: row.connectionId,
14
+ requestedBy: row.requestedBy,
15
+ source: exportSourceSchema.parse(readJson(row.source)),
16
+ format: exportFormatSchema.parse(row.format),
17
+ status: exportStatusSchema.parse(row.status),
18
+ fileId: row.fileId,
19
+ rowCount: row.rowCount === null ? null : Number(row.rowCount),
20
+ error: row.error,
21
+ createdAt: row.createdAt,
22
+ completedAt: row.completedAt,
23
+ expiresAt: row.expiresAt,
24
+ };
25
+ }
26
+ export function exportsRepo(meta) {
27
+ const { db } = meta;
28
+ async function findById(id) {
29
+ const row = await db.selectFrom('adminium_exports').selectAll().where('id', '=', id).executeTakeFirst();
30
+ return row ? decode(row) : null;
31
+ }
32
+ return {
33
+ findById,
34
+ async create(input, at = Date.now()) {
35
+ const row = {
36
+ id: newId('exp'),
37
+ connectionId: input.connectionId ?? null,
38
+ requestedBy: input.requestedBy,
39
+ source: packJson(exportSourceSchema.parse(input.source)),
40
+ format: exportFormatSchema.parse(input.format),
41
+ status: 'processing',
42
+ fileId: null,
43
+ rowCount: null,
44
+ error: null,
45
+ createdAt: at,
46
+ completedAt: null,
47
+ expiresAt: null,
48
+ };
49
+ await db.insertInto('adminium_exports').values(row).execute();
50
+ return decode(row);
51
+ },
52
+ /** Newest first; `requestedBy` scopes to one user (the "mine" list). */
53
+ async list(opts = {}) {
54
+ let query = db.selectFrom('adminium_exports').selectAll();
55
+ if (opts.requestedBy !== undefined)
56
+ query = query.where('requestedBy', '=', opts.requestedBy);
57
+ const rows = await query
58
+ .orderBy('createdAt', 'desc')
59
+ .orderBy('id', 'desc')
60
+ .limit(opts.limit ?? 50)
61
+ .execute();
62
+ return rows.map(decode);
63
+ },
64
+ /** processing → ready, stamping the artifact + retention window. */
65
+ async markReady(id, result, at = Date.now()) {
66
+ const res = await db
67
+ .updateTable('adminium_exports')
68
+ .set({
69
+ status: 'ready',
70
+ fileId: result.fileId,
71
+ rowCount: result.rowCount,
72
+ completedAt: at,
73
+ expiresAt: result.expiresAt,
74
+ })
75
+ .where('id', '=', id)
76
+ .where('status', '=', 'processing')
77
+ .executeTakeFirst();
78
+ return affected(res.numUpdatedRows) === 1;
79
+ },
80
+ async markFailed(id, error, at = Date.now()) {
81
+ const res = await db
82
+ .updateTable('adminium_exports')
83
+ .set({ status: 'failed', error, completedAt: at })
84
+ .where('id', '=', id)
85
+ .where('status', '=', 'processing')
86
+ .executeTakeFirst();
87
+ return affected(res.numUpdatedRows) === 1;
88
+ },
89
+ async markCancelled(id, at = Date.now()) {
90
+ const res = await db
91
+ .updateTable('adminium_exports')
92
+ .set({ status: 'cancelled', completedAt: at })
93
+ .where('id', '=', id)
94
+ .where('status', '=', 'processing')
95
+ .executeTakeFirst();
96
+ return affected(res.numUpdatedRows) === 1;
97
+ },
98
+ /** Retention sweep: ready rows past `expires_at` flip to `expired`. */
99
+ async expireDue(at = Date.now()) {
100
+ const res = await db
101
+ .updateTable('adminium_exports')
102
+ .set({ status: 'expired' })
103
+ .where('status', '=', 'ready')
104
+ .where('expiresAt', 'is not', null)
105
+ .where('expiresAt', '<', at)
106
+ .executeTakeFirst();
107
+ return affected(res.numUpdatedRows);
108
+ },
109
+ /**
110
+ * Byte-GC worklist (retention hygiene): expired exports whose artifact
111
+ * file row is not yet soft-deleted. The sweep marks each file deleted and
112
+ * removes its bytes — re-querying (instead of returning `expireDue`'s
113
+ * rows) makes the pass self-healing after a crash mid-GC.
114
+ */
115
+ async listExpiredArtifacts(limit = 500) {
116
+ const rows = await db
117
+ .selectFrom('adminium_exports')
118
+ .innerJoin('adminium_files', 'adminium_files.id', 'adminium_exports.fileId')
119
+ .select([
120
+ 'adminium_exports.id as id',
121
+ 'adminium_files.id as fileId',
122
+ 'adminium_files.storageKey as storageKey',
123
+ ])
124
+ .where('adminium_exports.status', '=', 'expired')
125
+ .where('adminium_files.deletedAt', 'is', null)
126
+ .limit(limit)
127
+ .execute();
128
+ return rows;
129
+ },
130
+ };
131
+ }
132
+ //# sourceMappingURL=exports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exports.js","sourceRoot":"","sources":["../../src/repos/exports.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * filesRepo — adminium_files (07-meta-store.md §3.27): one row per stored
3
+ * artifact (export bundles, import uploads, error reports, branding assets…).
4
+ *
5
+ * The repo owns ROWS only — bytes live wherever `storage`/`storage_key` say
6
+ * (v1: `local` under `<dataDir>/files/<id>`, apps/server/src/files/storage.ts).
7
+ * Deletion is soft (`deleted_at`) so a GC pass can remove bytes first and rows
8
+ * second without ever leaving a row that points at nothing.
9
+ */
10
+ import type { MetaDb } from '../connect.js';
11
+ import { type RecordRef } from '../schema/json-payloads.js';
12
+ export type FileKind = 'upload' | 'export' | 'import' | 'branding' | 'schema' | 'archive';
13
+ export interface StoredFile {
14
+ id: string;
15
+ /** v1: always `local`. */
16
+ storage: string;
17
+ storageKey: string;
18
+ filename: string;
19
+ mime: string;
20
+ sizeBytes: number;
21
+ sha256: string;
22
+ kind: FileKind;
23
+ entity: RecordRef | null;
24
+ uploadedBy: string | null;
25
+ createdAt: number;
26
+ deletedAt: number | null;
27
+ }
28
+ export interface CreateFileInput {
29
+ /** Storage backend key; defaults to the row id (local layout). */
30
+ storageKey?: string;
31
+ filename: string;
32
+ mime: string;
33
+ sizeBytes: number;
34
+ sha256: string;
35
+ kind: FileKind;
36
+ entity?: RecordRef | null;
37
+ uploadedBy?: string | null;
38
+ /** Pre-minted id (lets the storage layer write bytes under the final id first). */
39
+ id?: string;
40
+ }
41
+ export declare function filesRepo(meta: MetaDb): {
42
+ findById: (id: string) => Promise<StoredFile | null>;
43
+ create(input: CreateFileInput, at?: number): Promise<StoredFile>;
44
+ /** Soft delete — bytes are removed by the storage GC, rows stay addressable. */
45
+ markDeleted(id: string, at?: number): Promise<boolean>;
46
+ /** Rows already soft-deleted before `cutoff` — the storage GC's worklist. */
47
+ listDeletedBefore(cutoff: number, limit?: number): Promise<StoredFile[]>;
48
+ /** Hard-delete a row (call only after the bytes are gone). */
49
+ purge(id: string): Promise<boolean>;
50
+ };
51
+ export type FilesRepo = ReturnType<typeof filesRepo>;
52
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/repos/files.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAmC,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAI7F,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE1F,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mFAAmF;IACnF,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAmBD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM;mBAGR,MAAM,KAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;kBAQzC,eAAe,OAAM,MAAM,GAAgB,OAAO,CAAC,UAAU,CAAC;IAqBlF,gFAAgF;oBAC1D,MAAM,OAAM,MAAM,GAAgB,OAAO,CAAC,OAAO,CAAC;IAUxE,6EAA6E;8BAC7C,MAAM,mBAAgB,OAAO,CAAC,UAAU,EAAE,CAAC;IAY3E,8DAA8D;cAC9C,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;EAK5C;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * filesRepo — adminium_files (07-meta-store.md §3.27): one row per stored
3
+ * artifact (export bundles, import uploads, error reports, branding assets…).
4
+ *
5
+ * The repo owns ROWS only — bytes live wherever `storage`/`storage_key` say
6
+ * (v1: `local` under `<dataDir>/files/<id>`, apps/server/src/files/storage.ts).
7
+ * Deletion is soft (`deleted_at`) so a GC pass can remove bytes first and rows
8
+ * second without ever leaving a row that points at nothing.
9
+ */
10
+ import { newId } from '../ids.js';
11
+ import { fileKindSchema, recordRefSchema } from '../schema/json-payloads.js';
12
+ import { affected, packJson, readJsonOrNull } from './util.js';
13
+ function decode(row) {
14
+ return {
15
+ id: row.id,
16
+ storage: row.storage,
17
+ storageKey: row.storageKey,
18
+ filename: row.filename,
19
+ mime: row.mime,
20
+ sizeBytes: Number(row.sizeBytes),
21
+ sha256: row.sha256,
22
+ kind: fileKindSchema.parse(row.kind),
23
+ entity: readJsonOrNull(row.entity),
24
+ uploadedBy: row.uploadedBy,
25
+ createdAt: row.createdAt,
26
+ deletedAt: row.deletedAt,
27
+ };
28
+ }
29
+ export function filesRepo(meta) {
30
+ const { db } = meta;
31
+ async function findById(id) {
32
+ const row = await db.selectFrom('adminium_files').selectAll().where('id', '=', id).executeTakeFirst();
33
+ return row ? decode(row) : null;
34
+ }
35
+ return {
36
+ findById,
37
+ async create(input, at = Date.now()) {
38
+ const id = input.id ?? newId('file');
39
+ const entity = input.entity == null ? null : recordRefSchema.parse(input.entity);
40
+ const row = {
41
+ id,
42
+ storage: 'local',
43
+ storageKey: input.storageKey ?? id,
44
+ filename: input.filename,
45
+ mime: input.mime,
46
+ sizeBytes: input.sizeBytes,
47
+ sha256: input.sha256,
48
+ kind: fileKindSchema.parse(input.kind),
49
+ entity: entity === null ? null : packJson(entity),
50
+ uploadedBy: input.uploadedBy ?? null,
51
+ createdAt: at,
52
+ deletedAt: null,
53
+ };
54
+ await db.insertInto('adminium_files').values(row).execute();
55
+ return decode(row);
56
+ },
57
+ /** Soft delete — bytes are removed by the storage GC, rows stay addressable. */
58
+ async markDeleted(id, at = Date.now()) {
59
+ const res = await db
60
+ .updateTable('adminium_files')
61
+ .set({ deletedAt: at })
62
+ .where('id', '=', id)
63
+ .where('deletedAt', 'is', null)
64
+ .executeTakeFirst();
65
+ return affected(res.numUpdatedRows) === 1;
66
+ },
67
+ /** Rows already soft-deleted before `cutoff` — the storage GC's worklist. */
68
+ async listDeletedBefore(cutoff, limit = 100) {
69
+ const rows = await db
70
+ .selectFrom('adminium_files')
71
+ .selectAll()
72
+ .where('deletedAt', 'is not', null)
73
+ .where('deletedAt', '<', cutoff)
74
+ .orderBy('deletedAt', 'asc')
75
+ .limit(limit)
76
+ .execute();
77
+ return rows.map(decode);
78
+ },
79
+ /** Hard-delete a row (call only after the bytes are gone). */
80
+ async purge(id) {
81
+ const res = await db.deleteFrom('adminium_files').where('id', '=', id).executeTakeFirst();
82
+ return affected(res.numDeletedRows) === 1;
83
+ },
84
+ };
85
+ }
86
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/repos/files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * importsRepo — adminium_imports (07-meta-store.md §3.26): the import wizard's
3
+ * server-side state machine
4
+ * (`validating → ready → running → succeeded | failed | cancelled`).
5
+ *
6
+ * `mapping`/`options` are validated against the §3.26 payload schemas on every
7
+ * write; `stats` carries the invariant the SPA asserts (09 §11.1):
8
+ * total = inserted + updated + skipped.
9
+ */
10
+ import type { MetaDb } from '../connect.js';
11
+ export type ImportStatus = 'validating' | 'ready' | 'running' | 'succeeded' | 'failed' | 'cancelled';
12
+ export interface ImportMapping {
13
+ columns: {
14
+ from: string;
15
+ to: string | null;
16
+ }[];
17
+ }
18
+ export interface ImportOptions {
19
+ mode?: 'insert' | 'upsert' | undefined;
20
+ matchColumn?: string | null | undefined;
21
+ skipInvalid?: boolean | undefined;
22
+ }
23
+ export interface ImportStats {
24
+ total: number;
25
+ inserted?: number | undefined;
26
+ updated?: number | undefined;
27
+ skipped?: number | undefined;
28
+ }
29
+ export interface DataImport {
30
+ id: string;
31
+ connectionId: string;
32
+ tableName: string;
33
+ requestedBy: string;
34
+ fileId: string;
35
+ mapping: ImportMapping;
36
+ options: ImportOptions;
37
+ status: ImportStatus;
38
+ stats: ImportStats | null;
39
+ errorReportFileId: string | null;
40
+ createdAt: number;
41
+ startedAt: number | null;
42
+ finishedAt: number | null;
43
+ }
44
+ export interface CreateImportInput {
45
+ connectionId: string;
46
+ tableName: string;
47
+ requestedBy: string;
48
+ fileId: string;
49
+ mapping: ImportMapping;
50
+ options: ImportOptions;
51
+ }
52
+ export declare function importsRepo(meta: MetaDb): {
53
+ findById: (id: string) => Promise<DataImport | null>;
54
+ create(input: CreateImportInput, at?: number): Promise<DataImport>;
55
+ /** Newest first; `requestedBy` scopes to one user (the "mine" list). */
56
+ list(opts?: {
57
+ requestedBy?: string;
58
+ limit?: number;
59
+ }): Promise<DataImport[]>;
60
+ /** validating → ready, stamping the validation stats (total parsed rows). */
61
+ markReady(id: string, stats: ImportStats, at?: number): Promise<boolean>;
62
+ /** ready → running (the import-run job's claim; double-runs are refused). */
63
+ markRunning(id: string, at?: number): Promise<boolean>;
64
+ markFinished(id: string, outcome: {
65
+ status: "succeeded" | "failed" | "cancelled";
66
+ stats?: ImportStats | null;
67
+ errorReportFileId?: string | null;
68
+ }, at?: number): Promise<boolean>;
69
+ };
70
+ export type ImportsRepo = ReturnType<typeof importsRepo>;
71
+ //# sourceMappingURL=imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/repos/imports.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAW5C,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAErG,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;CAChD;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACvC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxC,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;CACxB;AAuBD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM;mBAGV,MAAM,KAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;kBAQzC,iBAAiB,OAAM,MAAM,GAAgB,OAAO,CAAC,UAAU,CAAC;IAoBpF,wEAAwE;gBACvD;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAQ,OAAO,CAAC,UAAU,EAAE,CAAC;IAWtF,6EAA6E;kBACzD,MAAM,SAAS,WAAW,OAAM,MAAM,GAAgB,OAAO,CAAC,OAAO,CAAC;IAW1F,6EAA6E;oBACvD,MAAM,OAAM,MAAM,GAAgB,OAAO,CAAC,OAAO,CAAC;qBAWlE,MAAM,WACD;QACP,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;QAC7C,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;QAC3B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACnC,OACG,MAAM,GACT,OAAO,CAAC,OAAO,CAAC;EAiBtB;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * importsRepo — adminium_imports (07-meta-store.md §3.26): the import wizard's
3
+ * server-side state machine
4
+ * (`validating → ready → running → succeeded | failed | cancelled`).
5
+ *
6
+ * `mapping`/`options` are validated against the §3.26 payload schemas on every
7
+ * write; `stats` carries the invariant the SPA asserts (09 §11.1):
8
+ * total = inserted + updated + skipped.
9
+ */
10
+ import { newId } from '../ids.js';
11
+ import { importMappingSchema, importOptionsSchema, importStatsSchema, importStatusSchema, } from '../schema/json-payloads.js';
12
+ import { affected, packJson, readJson, readJsonOrNull } from './util.js';
13
+ function decode(row) {
14
+ return {
15
+ id: row.id,
16
+ connectionId: row.connectionId,
17
+ tableName: row.tableName,
18
+ requestedBy: row.requestedBy,
19
+ fileId: row.fileId,
20
+ mapping: importMappingSchema.parse(readJson(row.mapping)),
21
+ options: importOptionsSchema.parse(readJson(row.options)),
22
+ status: importStatusSchema.parse(row.status),
23
+ stats: (() => {
24
+ const raw = readJsonOrNull(row.stats);
25
+ return raw === null ? null : importStatsSchema.parse(raw);
26
+ })(),
27
+ errorReportFileId: row.errorReportFileId,
28
+ createdAt: row.createdAt,
29
+ startedAt: row.startedAt,
30
+ finishedAt: row.finishedAt,
31
+ };
32
+ }
33
+ export function importsRepo(meta) {
34
+ const { db } = meta;
35
+ async function findById(id) {
36
+ const row = await db.selectFrom('adminium_imports').selectAll().where('id', '=', id).executeTakeFirst();
37
+ return row ? decode(row) : null;
38
+ }
39
+ return {
40
+ findById,
41
+ async create(input, at = Date.now()) {
42
+ const row = {
43
+ id: newId('imp'),
44
+ connectionId: input.connectionId,
45
+ tableName: input.tableName,
46
+ requestedBy: input.requestedBy,
47
+ fileId: input.fileId,
48
+ mapping: packJson(importMappingSchema.parse(input.mapping)),
49
+ options: packJson(importOptionsSchema.parse(input.options)),
50
+ status: 'validating',
51
+ stats: null,
52
+ errorReportFileId: null,
53
+ createdAt: at,
54
+ startedAt: null,
55
+ finishedAt: null,
56
+ };
57
+ await db.insertInto('adminium_imports').values(row).execute();
58
+ return decode(row);
59
+ },
60
+ /** Newest first; `requestedBy` scopes to one user (the "mine" list). */
61
+ async list(opts = {}) {
62
+ let query = db.selectFrom('adminium_imports').selectAll();
63
+ if (opts.requestedBy !== undefined)
64
+ query = query.where('requestedBy', '=', opts.requestedBy);
65
+ const rows = await query
66
+ .orderBy('createdAt', 'desc')
67
+ .orderBy('id', 'desc')
68
+ .limit(opts.limit ?? 50)
69
+ .execute();
70
+ return rows.map(decode);
71
+ },
72
+ /** validating → ready, stamping the validation stats (total parsed rows). */
73
+ async markReady(id, stats, at = Date.now()) {
74
+ void at;
75
+ const res = await db
76
+ .updateTable('adminium_imports')
77
+ .set({ status: 'ready', stats: packJson(importStatsSchema.parse(stats)) })
78
+ .where('id', '=', id)
79
+ .where('status', '=', 'validating')
80
+ .executeTakeFirst();
81
+ return affected(res.numUpdatedRows) === 1;
82
+ },
83
+ /** ready → running (the import-run job's claim; double-runs are refused). */
84
+ async markRunning(id, at = Date.now()) {
85
+ const res = await db
86
+ .updateTable('adminium_imports')
87
+ .set({ status: 'running', startedAt: at })
88
+ .where('id', '=', id)
89
+ .where('status', '=', 'ready')
90
+ .executeTakeFirst();
91
+ return affected(res.numUpdatedRows) === 1;
92
+ },
93
+ async markFinished(id, outcome, at = Date.now()) {
94
+ const res = await db
95
+ .updateTable('adminium_imports')
96
+ .set({
97
+ status: outcome.status,
98
+ finishedAt: at,
99
+ ...(outcome.stats == null ? {} : { stats: packJson(importStatsSchema.parse(outcome.stats)) }),
100
+ ...(outcome.errorReportFileId === undefined
101
+ ? {}
102
+ : { errorReportFileId: outcome.errorReportFileId }),
103
+ })
104
+ .where('id', '=', id)
105
+ .where('status', 'in', ['running', 'validating', 'ready'])
106
+ .executeTakeFirst();
107
+ return affected(res.numUpdatedRows) === 1;
108
+ },
109
+ };
110
+ }
111
+ //# sourceMappingURL=imports.js.map