@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.
- package/LICENSE +661 -0
- package/dist/bootstrap.d.ts +103 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +225 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/columns.d.ts +44 -0
- package/dist/columns.d.ts.map +1 -0
- package/dist/columns.js +57 -0
- package/dist/columns.js.map +1 -0
- package/dist/connect.d.ts +38 -0
- package/dist/connect.d.ts.map +1 -0
- package/dist/connect.js +57 -0
- package/dist/connect.js.map +1 -0
- package/dist/ids.d.ts +79 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +165 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations/0001_core_auth.d.ts +9 -0
- package/dist/migrations/0001_core_auth.d.ts.map +1 -0
- package/dist/migrations/0001_core_auth.js +102 -0
- package/dist/migrations/0001_core_auth.js.map +1 -0
- package/dist/migrations/0002_rbac.d.ts +8 -0
- package/dist/migrations/0002_rbac.d.ts.map +1 -0
- package/dist/migrations/0002_rbac.js +75 -0
- package/dist/migrations/0002_rbac.js.map +1 -0
- package/dist/migrations/0003_connections_schema.d.ts +9 -0
- package/dist/migrations/0003_connections_schema.d.ts.map +1 -0
- package/dist/migrations/0003_connections_schema.js +100 -0
- package/dist/migrations/0003_connections_schema.js.map +1 -0
- package/dist/migrations/0004_pages_views.d.ts +8 -0
- package/dist/migrations/0004_pages_views.d.ts.map +1 -0
- package/dist/migrations/0004_pages_views.js +59 -0
- package/dist/migrations/0004_pages_views.js.map +1 -0
- package/dist/migrations/0005_ops.d.ts +9 -0
- package/dist/migrations/0005_ops.d.ts.map +1 -0
- package/dist/migrations/0005_ops.js +104 -0
- package/dist/migrations/0005_ops.js.map +1 -0
- package/dist/migrations/0006_platform.d.ts +11 -0
- package/dist/migrations/0006_platform.d.ts.map +1 -0
- package/dist/migrations/0006_platform.js +259 -0
- package/dist/migrations/0006_platform.js.map +1 -0
- package/dist/migrations/0007_llm_runs.d.ts +33 -0
- package/dist/migrations/0007_llm_runs.d.ts.map +1 -0
- package/dist/migrations/0007_llm_runs.js +62 -0
- package/dist/migrations/0007_llm_runs.js.map +1 -0
- package/dist/migrations/0008_llm_overrides.d.ts +18 -0
- package/dist/migrations/0008_llm_overrides.d.ts.map +1 -0
- package/dist/migrations/0008_llm_overrides.js +24 -0
- package/dist/migrations/0008_llm_overrides.js.map +1 -0
- package/dist/migrations/0009_views_kind.d.ts +20 -0
- package/dist/migrations/0009_views_kind.d.ts.map +1 -0
- package/dist/migrations/0009_views_kind.js +24 -0
- package/dist/migrations/0009_views_kind.js.map +1 -0
- package/dist/migrations/0010_llm_prompt_version_width.d.ts +19 -0
- package/dist/migrations/0010_llm_prompt_version_width.d.ts.map +1 -0
- package/dist/migrations/0010_llm_prompt_version_width.js +28 -0
- package/dist/migrations/0010_llm_prompt_version_width.js.map +1 -0
- package/dist/migrations/index.d.ts +29 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +43 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrator.d.ts +83 -0
- package/dist/migrator.d.ts.map +1 -0
- package/dist/migrator.js +173 -0
- package/dist/migrator.js.map +1 -0
- package/dist/prefix.d.ts +19 -0
- package/dist/prefix.d.ts.map +1 -0
- package/dist/prefix.js +33 -0
- package/dist/prefix.js.map +1 -0
- package/dist/repos/api-keys.d.ts +31 -0
- package/dist/repos/api-keys.d.ts.map +1 -0
- package/dist/repos/api-keys.js +62 -0
- package/dist/repos/api-keys.js.map +1 -0
- package/dist/repos/audit.d.ts +51 -0
- package/dist/repos/audit.d.ts.map +1 -0
- package/dist/repos/audit.js +78 -0
- package/dist/repos/audit.js.map +1 -0
- package/dist/repos/connections.d.ts +90 -0
- package/dist/repos/connections.d.ts.map +1 -0
- package/dist/repos/connections.js +191 -0
- package/dist/repos/connections.js.map +1 -0
- package/dist/repos/email-templates.d.ts +47 -0
- package/dist/repos/email-templates.d.ts.map +1 -0
- package/dist/repos/email-templates.js +93 -0
- package/dist/repos/email-templates.js.map +1 -0
- package/dist/repos/exports.d.ts +67 -0
- package/dist/repos/exports.d.ts.map +1 -0
- package/dist/repos/exports.js +132 -0
- package/dist/repos/exports.js.map +1 -0
- package/dist/repos/files.d.ts +52 -0
- package/dist/repos/files.d.ts.map +1 -0
- package/dist/repos/files.js +86 -0
- package/dist/repos/files.js.map +1 -0
- package/dist/repos/imports.d.ts +71 -0
- package/dist/repos/imports.d.ts.map +1 -0
- package/dist/repos/imports.js +111 -0
- package/dist/repos/imports.js.map +1 -0
- package/dist/repos/index.d.ts +26 -0
- package/dist/repos/index.d.ts.map +1 -0
- package/dist/repos/index.js +26 -0
- package/dist/repos/index.js.map +1 -0
- package/dist/repos/jobs.d.ts +71 -0
- package/dist/repos/jobs.d.ts.map +1 -0
- package/dist/repos/jobs.js +187 -0
- package/dist/repos/jobs.js.map +1 -0
- package/dist/repos/llm-overrides.d.ts +89 -0
- package/dist/repos/llm-overrides.d.ts.map +1 -0
- package/dist/repos/llm-overrides.js +205 -0
- package/dist/repos/llm-overrides.js.map +1 -0
- package/dist/repos/llm-runs.d.ts +114 -0
- package/dist/repos/llm-runs.d.ts.map +1 -0
- package/dist/repos/llm-runs.js +214 -0
- package/dist/repos/llm-runs.js.map +1 -0
- package/dist/repos/notification-prefs.d.ts +34 -0
- package/dist/repos/notification-prefs.d.ts.map +1 -0
- package/dist/repos/notification-prefs.js +80 -0
- package/dist/repos/notification-prefs.js.map +1 -0
- package/dist/repos/notifications.d.ts +60 -0
- package/dist/repos/notifications.d.ts.map +1 -0
- package/dist/repos/notifications.js +107 -0
- package/dist/repos/notifications.js.map +1 -0
- package/dist/repos/overrides.d.ts +59 -0
- package/dist/repos/overrides.d.ts.map +1 -0
- package/dist/repos/overrides.js +143 -0
- package/dist/repos/overrides.js.map +1 -0
- package/dist/repos/pages.d.ts +192 -0
- package/dist/repos/pages.d.ts.map +1 -0
- package/dist/repos/pages.js +374 -0
- package/dist/repos/pages.js.map +1 -0
- package/dist/repos/password-resets.d.ts +32 -0
- package/dist/repos/password-resets.d.ts.map +1 -0
- package/dist/repos/password-resets.js +56 -0
- package/dist/repos/password-resets.js.map +1 -0
- package/dist/repos/permissions.d.ts +28 -0
- package/dist/repos/permissions.d.ts.map +1 -0
- package/dist/repos/permissions.js +100 -0
- package/dist/repos/permissions.js.map +1 -0
- package/dist/repos/roles.d.ts +33 -0
- package/dist/repos/roles.d.ts.map +1 -0
- package/dist/repos/roles.js +89 -0
- package/dist/repos/roles.js.map +1 -0
- package/dist/repos/scheduled-reports.d.ts +73 -0
- package/dist/repos/scheduled-reports.d.ts.map +1 -0
- package/dist/repos/scheduled-reports.js +132 -0
- package/dist/repos/scheduled-reports.js.map +1 -0
- package/dist/repos/sessions.d.ts +33 -0
- package/dist/repos/sessions.d.ts.map +1 -0
- package/dist/repos/sessions.js +79 -0
- package/dist/repos/sessions.js.map +1 -0
- package/dist/repos/settings.d.ts +25 -0
- package/dist/repos/settings.d.ts.map +1 -0
- package/dist/repos/settings.js +73 -0
- package/dist/repos/settings.js.map +1 -0
- package/dist/repos/snapshots.d.ts +79 -0
- package/dist/repos/snapshots.d.ts.map +1 -0
- package/dist/repos/snapshots.js +191 -0
- package/dist/repos/snapshots.js.map +1 -0
- package/dist/repos/user-prefs.d.ts +56 -0
- package/dist/repos/user-prefs.d.ts.map +1 -0
- package/dist/repos/user-prefs.js +147 -0
- package/dist/repos/user-prefs.js.map +1 -0
- package/dist/repos/users.d.ts +38 -0
- package/dist/repos/users.d.ts.map +1 -0
- package/dist/repos/users.js +103 -0
- package/dist/repos/users.js.map +1 -0
- package/dist/repos/util.d.ts +45 -0
- package/dist/repos/util.d.ts.map +1 -0
- package/dist/repos/util.js +81 -0
- package/dist/repos/util.js.map +1 -0
- package/dist/repos/views.d.ts +75 -0
- package/dist/repos/views.d.ts.map +1 -0
- package/dist/repos/views.js +180 -0
- package/dist/repos/views.js.map +1 -0
- package/dist/schema/index.d.ts +4 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +4 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/json-payloads.d.ts +479 -0
- package/dist/schema/json-payloads.d.ts.map +1 -0
- package/dist/schema/json-payloads.js +340 -0
- package/dist/schema/json-payloads.js.map +1 -0
- package/dist/schema/settings-registry.d.ts +187 -0
- package/dist/schema/settings-registry.d.ts.map +1 -0
- package/dist/schema/settings-registry.js +183 -0
- package/dist/schema/settings-registry.js.map +1 -0
- package/dist/schema/tables.d.ts +568 -0
- package/dist/schema/tables.d.ts.map +1 -0
- package/dist/schema/tables.js +51 -0
- package/dist/schema/tables.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rolesRepo — adminium_roles + adminium_user_roles
|
|
3
|
+
* (07-meta-store.md §3.8, §3.10).
|
|
4
|
+
*/
|
|
5
|
+
import type { MetaDb } from '../connect.js';
|
|
6
|
+
export interface Role {
|
|
7
|
+
id: string;
|
|
8
|
+
slug: string;
|
|
9
|
+
name: string;
|
|
10
|
+
description: string | null;
|
|
11
|
+
isBuiltin: boolean;
|
|
12
|
+
createdAt: number;
|
|
13
|
+
updatedAt: number;
|
|
14
|
+
}
|
|
15
|
+
export interface CreateRoleInput {
|
|
16
|
+
slug: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description?: string | null;
|
|
19
|
+
isBuiltin?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function rolesRepo(meta: MetaDb): {
|
|
22
|
+
create(input: CreateRoleInput, at?: number): Promise<Role>;
|
|
23
|
+
findBySlug(slug: string): Promise<Role | null>;
|
|
24
|
+
findById(id: string): Promise<Role | null>;
|
|
25
|
+
list(): Promise<Role[]>;
|
|
26
|
+
rename(roleId: string, name: string, at?: number): Promise<boolean>;
|
|
27
|
+
/** Idempotent grant of a role to a user. */
|
|
28
|
+
assignToUser(userId: string, roleId: string, grantedBy?: string | null, at?: number): Promise<void>;
|
|
29
|
+
removeFromUser(userId: string, roleId: string): Promise<boolean>;
|
|
30
|
+
rolesForUser(userId: string): Promise<Role[]>;
|
|
31
|
+
};
|
|
32
|
+
export type RolesRepo = ReturnType<typeof rolesRepo>;
|
|
33
|
+
//# sourceMappingURL=roles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roles.d.ts","sourceRoot":"","sources":["../../src/repos/roles.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAK5C,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAcD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM;kBAGd,eAAe,OAAM,MAAM,GAAgB,OAAO,CAAC,IAAI,CAAC;qBAcrD,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;iBAKjC,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;YAKlC,OAAO,CAAC,IAAI,EAAE,CAAC;mBAKR,MAAM,QAAQ,MAAM,OAAM,MAAM,GAAgB,OAAO,CAAC,OAAO,CAAC;IASrF,4CAA4C;yBACjB,MAAM,UAAU,MAAM,cAAa,MAAM,GAAG,IAAI,OAAa,MAAM,GAAgB,OAAO,CAAC,IAAI,CAAC;2BAc9F,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;yBAS3C,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;EAWtD;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rolesRepo — adminium_roles + adminium_user_roles
|
|
3
|
+
* (07-meta-store.md §3.8, §3.10).
|
|
4
|
+
*/
|
|
5
|
+
import { newId } from '../ids.js';
|
|
6
|
+
import { readBool, writeBool } from './util.js';
|
|
7
|
+
function mapRole(row) {
|
|
8
|
+
return {
|
|
9
|
+
id: row.id,
|
|
10
|
+
slug: row.slug,
|
|
11
|
+
name: row.name,
|
|
12
|
+
description: row.description,
|
|
13
|
+
isBuiltin: readBool(row.isBuiltin),
|
|
14
|
+
createdAt: row.createdAt,
|
|
15
|
+
updatedAt: row.updatedAt,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function rolesRepo(meta) {
|
|
19
|
+
const { db } = meta;
|
|
20
|
+
return {
|
|
21
|
+
async create(input, at = Date.now()) {
|
|
22
|
+
const row = {
|
|
23
|
+
id: newId('role'),
|
|
24
|
+
slug: input.slug,
|
|
25
|
+
name: input.name,
|
|
26
|
+
description: input.description ?? null,
|
|
27
|
+
isBuiltin: writeBool(meta, input.isBuiltin ?? false),
|
|
28
|
+
createdAt: at,
|
|
29
|
+
updatedAt: at,
|
|
30
|
+
};
|
|
31
|
+
await db.insertInto('adminium_roles').values(row).execute();
|
|
32
|
+
return mapRole(row);
|
|
33
|
+
},
|
|
34
|
+
async findBySlug(slug) {
|
|
35
|
+
const row = await db.selectFrom('adminium_roles').selectAll().where('slug', '=', slug).executeTakeFirst();
|
|
36
|
+
return row ? mapRole(row) : null;
|
|
37
|
+
},
|
|
38
|
+
async findById(id) {
|
|
39
|
+
const row = await db.selectFrom('adminium_roles').selectAll().where('id', '=', id).executeTakeFirst();
|
|
40
|
+
return row ? mapRole(row) : null;
|
|
41
|
+
},
|
|
42
|
+
async list() {
|
|
43
|
+
const rows = await db.selectFrom('adminium_roles').selectAll().orderBy('slug', 'asc').execute();
|
|
44
|
+
return rows.map(mapRole);
|
|
45
|
+
},
|
|
46
|
+
async rename(roleId, name, at = Date.now()) {
|
|
47
|
+
const res = await db
|
|
48
|
+
.updateTable('adminium_roles')
|
|
49
|
+
.set({ name, updatedAt: at })
|
|
50
|
+
.where('id', '=', roleId)
|
|
51
|
+
.executeTakeFirst();
|
|
52
|
+
return Number(res.numUpdatedRows) === 1;
|
|
53
|
+
},
|
|
54
|
+
/** Idempotent grant of a role to a user. */
|
|
55
|
+
async assignToUser(userId, roleId, grantedBy = null, at = Date.now()) {
|
|
56
|
+
const existing = await db
|
|
57
|
+
.selectFrom('adminium_user_roles')
|
|
58
|
+
.select('userId')
|
|
59
|
+
.where('userId', '=', userId)
|
|
60
|
+
.where('roleId', '=', roleId)
|
|
61
|
+
.executeTakeFirst();
|
|
62
|
+
if (existing)
|
|
63
|
+
return;
|
|
64
|
+
await db
|
|
65
|
+
.insertInto('adminium_user_roles')
|
|
66
|
+
.values({ userId, roleId, grantedBy, createdAt: at })
|
|
67
|
+
.execute();
|
|
68
|
+
},
|
|
69
|
+
async removeFromUser(userId, roleId) {
|
|
70
|
+
const res = await db
|
|
71
|
+
.deleteFrom('adminium_user_roles')
|
|
72
|
+
.where('userId', '=', userId)
|
|
73
|
+
.where('roleId', '=', roleId)
|
|
74
|
+
.executeTakeFirst();
|
|
75
|
+
return Number(res.numDeletedRows) === 1;
|
|
76
|
+
},
|
|
77
|
+
async rolesForUser(userId) {
|
|
78
|
+
const rows = await db
|
|
79
|
+
.selectFrom('adminium_user_roles')
|
|
80
|
+
.innerJoin('adminium_roles', 'adminium_roles.id', 'adminium_user_roles.roleId')
|
|
81
|
+
.selectAll('adminium_roles')
|
|
82
|
+
.where('adminium_user_roles.userId', '=', userId)
|
|
83
|
+
.orderBy('adminium_roles.slug', 'asc')
|
|
84
|
+
.execute();
|
|
85
|
+
return rows.map(mapRole);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=roles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roles.js","sourceRoot":"","sources":["../../src/repos/roles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scheduledReportsRepo — adminium_scheduled_reports (07-meta-store.md §3.24):
|
|
3
|
+
* one row per recurring report. The row stores WHAT and WHEN (`schedule` per
|
|
4
|
+
* `reportScheduleSchema`, `recipients`, `format`) plus the run bookkeeping
|
|
5
|
+
* (`last_run_at` / `next_run_at`); computing `next_run_at` from the schedule
|
|
6
|
+
* fields is the SERVER's job (croner lives there — apps/server/src/reports/),
|
|
7
|
+
* so the repo persists timestamps it is handed and never parses cron.
|
|
8
|
+
*
|
|
9
|
+
* `format` keeps the §3.24 `pdf | png` vocabulary even though the v1 runner
|
|
10
|
+
* delivers a data snapshot (no headless browser) — the stored intent survives
|
|
11
|
+
* the day rendering arrives, and the UI explains the degradation rather than
|
|
12
|
+
* hiding it (documented deviation in the M7 reports track).
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import type { MetaDb } from '../connect.js';
|
|
16
|
+
import { reportFormatSchema, reportScheduleSchema } from '../schema/json-payloads.js';
|
|
17
|
+
export type ReportSchedule = z.infer<typeof reportScheduleSchema>;
|
|
18
|
+
export type ReportFormat = z.infer<typeof reportFormatSchema>;
|
|
19
|
+
export interface ScheduledReport {
|
|
20
|
+
id: string;
|
|
21
|
+
pageId: string;
|
|
22
|
+
name: string;
|
|
23
|
+
schedule: ReportSchedule;
|
|
24
|
+
recipients: string[];
|
|
25
|
+
format: ReportFormat;
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
lastRunAt: number | null;
|
|
28
|
+
nextRunAt: number | null;
|
|
29
|
+
createdBy: string | null;
|
|
30
|
+
createdAt: number;
|
|
31
|
+
updatedAt: number;
|
|
32
|
+
}
|
|
33
|
+
export interface CreateScheduledReportInput {
|
|
34
|
+
pageId: string;
|
|
35
|
+
name: string;
|
|
36
|
+
schedule: ReportSchedule;
|
|
37
|
+
recipients: string[];
|
|
38
|
+
format: ReportFormat;
|
|
39
|
+
enabled?: boolean | undefined;
|
|
40
|
+
/** Computed by the caller (croner) — null parks the schedule. */
|
|
41
|
+
nextRunAt: number | null;
|
|
42
|
+
createdBy?: string | null | undefined;
|
|
43
|
+
}
|
|
44
|
+
export interface UpdateScheduledReportInput {
|
|
45
|
+
name?: string | undefined;
|
|
46
|
+
pageId?: string | undefined;
|
|
47
|
+
schedule?: ReportSchedule | undefined;
|
|
48
|
+
recipients?: string[] | undefined;
|
|
49
|
+
format?: ReportFormat | undefined;
|
|
50
|
+
enabled?: boolean | undefined;
|
|
51
|
+
/** Recompute + pass whenever `schedule`/`enabled` changes. */
|
|
52
|
+
nextRunAt?: number | null | undefined;
|
|
53
|
+
}
|
|
54
|
+
export declare function scheduledReportsRepo(meta: MetaDb): {
|
|
55
|
+
findById: (id: string) => Promise<ScheduledReport | null>;
|
|
56
|
+
create(input: CreateScheduledReportInput, at?: number): Promise<ScheduledReport>;
|
|
57
|
+
/** Newest first; `createdBy` scopes to one user (the "mine" list). */
|
|
58
|
+
list(opts?: {
|
|
59
|
+
createdBy?: string;
|
|
60
|
+
limit?: number;
|
|
61
|
+
}): Promise<ScheduledReport[]>;
|
|
62
|
+
update(id: string, patch: UpdateScheduledReportInput, at?: number): Promise<ScheduledReport | null>;
|
|
63
|
+
remove(id: string): Promise<boolean>;
|
|
64
|
+
/** Stamp a completed run and park the next one (the report-run job). */
|
|
65
|
+
recordRun(id: string, run: {
|
|
66
|
+
lastRunAt: number;
|
|
67
|
+
nextRunAt: number | null;
|
|
68
|
+
}): Promise<boolean>;
|
|
69
|
+
/** Enabled reports whose `next_run_at` has passed — the poll's worklist. */
|
|
70
|
+
listDue(at?: number): Promise<ScheduledReport[]>;
|
|
71
|
+
};
|
|
72
|
+
export type ScheduledReportsRepo = ReturnType<typeof scheduledReportsRepo>;
|
|
73
|
+
//# sourceMappingURL=scheduled-reports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled-reports.d.ts","sourceRoot":"","sources":["../../src/repos/scheduled-reports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EACL,kBAAkB,EAElB,oBAAoB,EACrB,MAAM,4BAA4B,CAAC;AAIpC,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,iEAAiE;IACjE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACvC;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAClC,MAAM,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACvC;AAmBD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM;mBAGnB,MAAM,KAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;kBAY9C,0BAA0B,OAAM,MAAM,GAAgB,OAAO,CAAC,eAAe,CAAC;IAmBlG,sEAAsE;gBACrD;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAQ,OAAO,CAAC,eAAe,EAAE,CAAC;eAYnF,MAAM,SACH,0BAA0B,OAC7B,MAAM,GACT,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;eAoBjB,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ1C,wEAAwE;kBAElE,MAAM,OACL;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GACnD,OAAO,CAAC,OAAO,CAAC;IASnB,4EAA4E;iBAC1D,MAAM,GAAgB,OAAO,CAAC,eAAe,EAAE,CAAC;EAYrE;AAED,MAAM,MAAM,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scheduledReportsRepo — adminium_scheduled_reports (07-meta-store.md §3.24):
|
|
3
|
+
* one row per recurring report. The row stores WHAT and WHEN (`schedule` per
|
|
4
|
+
* `reportScheduleSchema`, `recipients`, `format`) plus the run bookkeeping
|
|
5
|
+
* (`last_run_at` / `next_run_at`); computing `next_run_at` from the schedule
|
|
6
|
+
* fields is the SERVER's job (croner lives there — apps/server/src/reports/),
|
|
7
|
+
* so the repo persists timestamps it is handed and never parses cron.
|
|
8
|
+
*
|
|
9
|
+
* `format` keeps the §3.24 `pdf | png` vocabulary even though the v1 runner
|
|
10
|
+
* delivers a data snapshot (no headless browser) — the stored intent survives
|
|
11
|
+
* the day rendering arrives, and the UI explains the degradation rather than
|
|
12
|
+
* hiding it (documented deviation in the M7 reports track).
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { newId } from '../ids.js';
|
|
16
|
+
import { reportFormatSchema, reportRecipientsSchema, reportScheduleSchema, } from '../schema/json-payloads.js';
|
|
17
|
+
import { affected, packJson, readBool, readJson, writeBool } from './util.js';
|
|
18
|
+
function decode(row) {
|
|
19
|
+
return {
|
|
20
|
+
id: row.id,
|
|
21
|
+
pageId: row.pageId,
|
|
22
|
+
name: row.name,
|
|
23
|
+
schedule: reportScheduleSchema.parse(readJson(row.schedule)),
|
|
24
|
+
recipients: reportRecipientsSchema.parse(readJson(row.recipients)),
|
|
25
|
+
format: reportFormatSchema.parse(row.format),
|
|
26
|
+
enabled: readBool(row.enabled),
|
|
27
|
+
lastRunAt: row.lastRunAt,
|
|
28
|
+
nextRunAt: row.nextRunAt,
|
|
29
|
+
createdBy: row.createdBy,
|
|
30
|
+
createdAt: row.createdAt,
|
|
31
|
+
updatedAt: row.updatedAt,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function scheduledReportsRepo(meta) {
|
|
35
|
+
const { db } = meta;
|
|
36
|
+
async function findById(id) {
|
|
37
|
+
const row = await db
|
|
38
|
+
.selectFrom('adminium_scheduled_reports')
|
|
39
|
+
.selectAll()
|
|
40
|
+
.where('id', '=', id)
|
|
41
|
+
.executeTakeFirst();
|
|
42
|
+
return row ? decode(row) : null;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
findById,
|
|
46
|
+
async create(input, at = Date.now()) {
|
|
47
|
+
const row = {
|
|
48
|
+
id: newId('rep'),
|
|
49
|
+
pageId: input.pageId,
|
|
50
|
+
name: input.name,
|
|
51
|
+
schedule: packJson(reportScheduleSchema.parse(input.schedule)),
|
|
52
|
+
recipients: packJson(reportRecipientsSchema.parse(input.recipients)),
|
|
53
|
+
format: reportFormatSchema.parse(input.format),
|
|
54
|
+
enabled: writeBool(meta, input.enabled ?? true),
|
|
55
|
+
lastRunAt: null,
|
|
56
|
+
nextRunAt: input.nextRunAt,
|
|
57
|
+
createdBy: input.createdBy ?? null,
|
|
58
|
+
createdAt: at,
|
|
59
|
+
updatedAt: at,
|
|
60
|
+
};
|
|
61
|
+
await db.insertInto('adminium_scheduled_reports').values(row).execute();
|
|
62
|
+
return decode(row);
|
|
63
|
+
},
|
|
64
|
+
/** Newest first; `createdBy` scopes to one user (the "mine" list). */
|
|
65
|
+
async list(opts = {}) {
|
|
66
|
+
let query = db.selectFrom('adminium_scheduled_reports').selectAll();
|
|
67
|
+
if (opts.createdBy !== undefined)
|
|
68
|
+
query = query.where('createdBy', '=', opts.createdBy);
|
|
69
|
+
const rows = await query
|
|
70
|
+
.orderBy('createdAt', 'desc')
|
|
71
|
+
.orderBy('id', 'desc')
|
|
72
|
+
.limit(opts.limit ?? 100)
|
|
73
|
+
.execute();
|
|
74
|
+
return rows.map(decode);
|
|
75
|
+
},
|
|
76
|
+
async update(id, patch, at = Date.now()) {
|
|
77
|
+
const set = { updatedAt: at };
|
|
78
|
+
if (patch.name !== undefined)
|
|
79
|
+
set['name'] = patch.name;
|
|
80
|
+
if (patch.pageId !== undefined)
|
|
81
|
+
set['pageId'] = patch.pageId;
|
|
82
|
+
if (patch.schedule !== undefined)
|
|
83
|
+
set['schedule'] = packJson(reportScheduleSchema.parse(patch.schedule));
|
|
84
|
+
if (patch.recipients !== undefined) {
|
|
85
|
+
set['recipients'] = packJson(reportRecipientsSchema.parse(patch.recipients));
|
|
86
|
+
}
|
|
87
|
+
if (patch.format !== undefined)
|
|
88
|
+
set['format'] = reportFormatSchema.parse(patch.format);
|
|
89
|
+
if (patch.enabled !== undefined)
|
|
90
|
+
set['enabled'] = writeBool(meta, patch.enabled);
|
|
91
|
+
if (patch.nextRunAt !== undefined)
|
|
92
|
+
set['nextRunAt'] = patch.nextRunAt;
|
|
93
|
+
const res = await db
|
|
94
|
+
.updateTable('adminium_scheduled_reports')
|
|
95
|
+
.set(set)
|
|
96
|
+
.where('id', '=', id)
|
|
97
|
+
.executeTakeFirst();
|
|
98
|
+
if (affected(res.numUpdatedRows) === 0)
|
|
99
|
+
return null;
|
|
100
|
+
return findById(id);
|
|
101
|
+
},
|
|
102
|
+
async remove(id) {
|
|
103
|
+
const res = await db
|
|
104
|
+
.deleteFrom('adminium_scheduled_reports')
|
|
105
|
+
.where('id', '=', id)
|
|
106
|
+
.executeTakeFirst();
|
|
107
|
+
return affected(res.numDeletedRows) === 1;
|
|
108
|
+
},
|
|
109
|
+
/** Stamp a completed run and park the next one (the report-run job). */
|
|
110
|
+
async recordRun(id, run) {
|
|
111
|
+
const res = await db
|
|
112
|
+
.updateTable('adminium_scheduled_reports')
|
|
113
|
+
.set({ lastRunAt: run.lastRunAt, nextRunAt: run.nextRunAt, updatedAt: run.lastRunAt })
|
|
114
|
+
.where('id', '=', id)
|
|
115
|
+
.executeTakeFirst();
|
|
116
|
+
return affected(res.numUpdatedRows) === 1;
|
|
117
|
+
},
|
|
118
|
+
/** Enabled reports whose `next_run_at` has passed — the poll's worklist. */
|
|
119
|
+
async listDue(at = Date.now()) {
|
|
120
|
+
const rows = await db
|
|
121
|
+
.selectFrom('adminium_scheduled_reports')
|
|
122
|
+
.selectAll()
|
|
123
|
+
.where('enabled', '=', writeBool(meta, true))
|
|
124
|
+
.where('nextRunAt', 'is not', null)
|
|
125
|
+
.where('nextRunAt', '<=', at)
|
|
126
|
+
.orderBy('nextRunAt', 'asc')
|
|
127
|
+
.execute();
|
|
128
|
+
return rows.map(decode);
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=scheduled-reports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled-reports.js","sourceRoot":"","sources":["../../src/repos/scheduled-reports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sessionsRepo — adminium_sessions (07-meta-store.md §3.5).
|
|
3
|
+
* Cookie tokens are opaque; only their SHA-256 hex is stored (hashing in server).
|
|
4
|
+
*/
|
|
5
|
+
import type { Selectable } from 'kysely';
|
|
6
|
+
import type { MetaDb } from '../connect.js';
|
|
7
|
+
import type { AdminiumSessionsTable } from '../schema/tables.js';
|
|
8
|
+
/** `last_seen_at` updates are throttled to at most one per this interval (§3.5). */
|
|
9
|
+
export declare const SESSION_TOUCH_INTERVAL_MS = 60000;
|
|
10
|
+
export type Session = Selectable<AdminiumSessionsTable>;
|
|
11
|
+
export interface CreateSessionInput {
|
|
12
|
+
userId: string;
|
|
13
|
+
tokenHash: string;
|
|
14
|
+
expiresAt: number;
|
|
15
|
+
ip?: string | null;
|
|
16
|
+
userAgent?: string | null;
|
|
17
|
+
}
|
|
18
|
+
export declare function sessionsRepo(meta: MetaDb): {
|
|
19
|
+
create(input: CreateSessionInput, at?: number): Promise<Session>;
|
|
20
|
+
/** A session is valid when un-revoked and unexpired at `at`. */
|
|
21
|
+
findValidByTokenHash(tokenHash: string, at?: number): Promise<Session | null>;
|
|
22
|
+
/**
|
|
23
|
+
* Throttled `last_seen_at` bump: writes only when the previous value is at
|
|
24
|
+
* least {@link SESSION_TOUCH_INTERVAL_MS} old. Returns true when written.
|
|
25
|
+
*/
|
|
26
|
+
touch(sessionId: string, at?: number): Promise<boolean>;
|
|
27
|
+
revoke(sessionId: string, at?: number): Promise<boolean>;
|
|
28
|
+
revokeAllForUser(userId: string, at?: number): Promise<number>;
|
|
29
|
+
/** Retention §8 `sessions` policy: expired, or revoked > 24 h ago. */
|
|
30
|
+
gc(at?: number): Promise<number>;
|
|
31
|
+
};
|
|
32
|
+
export type SessionsRepo = ReturnType<typeof sessionsRepo>;
|
|
33
|
+
//# sourceMappingURL=sessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/repos/sessions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAGjE,oFAAoF;AACpF,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC,qBAAqB,CAAC,CAAC;AAExD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM;kBAGjB,kBAAkB,OAAM,MAAM,GAAgB,OAAO,CAAC,OAAO,CAAC;IAgBlF,gEAAgE;oCAC1B,MAAM,OAAM,MAAM,GAAgB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAW/F;;;OAGG;qBACoB,MAAM,OAAM,MAAM,GAAgB,OAAO,CAAC,OAAO,CAAC;sBAUjD,MAAM,OAAM,MAAM,GAAgB,OAAO,CAAC,OAAO,CAAC;6BAU3C,MAAM,OAAM,MAAM,GAAgB,OAAO,CAAC,MAAM,CAAC;IAUhF,sEAAsE;YACzD,MAAM,GAAgB,OAAO,CAAC,MAAM,CAAC;EAQrD;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sessionsRepo — adminium_sessions (07-meta-store.md §3.5).
|
|
3
|
+
* Cookie tokens are opaque; only their SHA-256 hex is stored (hashing in server).
|
|
4
|
+
*/
|
|
5
|
+
import { newId } from '../ids.js';
|
|
6
|
+
import { DAY_MS } from './util.js';
|
|
7
|
+
/** `last_seen_at` updates are throttled to at most one per this interval (§3.5). */
|
|
8
|
+
export const SESSION_TOUCH_INTERVAL_MS = 60_000;
|
|
9
|
+
export function sessionsRepo(meta) {
|
|
10
|
+
const { db } = meta;
|
|
11
|
+
return {
|
|
12
|
+
async create(input, at = Date.now()) {
|
|
13
|
+
const row = {
|
|
14
|
+
id: newId('sess'),
|
|
15
|
+
tokenHash: input.tokenHash,
|
|
16
|
+
userId: input.userId,
|
|
17
|
+
createdAt: at,
|
|
18
|
+
expiresAt: input.expiresAt,
|
|
19
|
+
lastSeenAt: at,
|
|
20
|
+
ip: input.ip ?? null,
|
|
21
|
+
userAgent: input.userAgent ?? null,
|
|
22
|
+
revokedAt: null,
|
|
23
|
+
};
|
|
24
|
+
await db.insertInto('adminium_sessions').values(row).execute();
|
|
25
|
+
return row;
|
|
26
|
+
},
|
|
27
|
+
/** A session is valid when un-revoked and unexpired at `at`. */
|
|
28
|
+
async findValidByTokenHash(tokenHash, at = Date.now()) {
|
|
29
|
+
const row = await db
|
|
30
|
+
.selectFrom('adminium_sessions')
|
|
31
|
+
.selectAll()
|
|
32
|
+
.where('tokenHash', '=', tokenHash)
|
|
33
|
+
.where('revokedAt', 'is', null)
|
|
34
|
+
.where('expiresAt', '>', at)
|
|
35
|
+
.executeTakeFirst();
|
|
36
|
+
return row ?? null;
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* Throttled `last_seen_at` bump: writes only when the previous value is at
|
|
40
|
+
* least {@link SESSION_TOUCH_INTERVAL_MS} old. Returns true when written.
|
|
41
|
+
*/
|
|
42
|
+
async touch(sessionId, at = Date.now()) {
|
|
43
|
+
const res = await db
|
|
44
|
+
.updateTable('adminium_sessions')
|
|
45
|
+
.set({ lastSeenAt: at })
|
|
46
|
+
.where('id', '=', sessionId)
|
|
47
|
+
.where('lastSeenAt', '<=', at - SESSION_TOUCH_INTERVAL_MS)
|
|
48
|
+
.executeTakeFirst();
|
|
49
|
+
return Number(res.numUpdatedRows) === 1;
|
|
50
|
+
},
|
|
51
|
+
async revoke(sessionId, at = Date.now()) {
|
|
52
|
+
const res = await db
|
|
53
|
+
.updateTable('adminium_sessions')
|
|
54
|
+
.set({ revokedAt: at })
|
|
55
|
+
.where('id', '=', sessionId)
|
|
56
|
+
.where('revokedAt', 'is', null)
|
|
57
|
+
.executeTakeFirst();
|
|
58
|
+
return Number(res.numUpdatedRows) === 1;
|
|
59
|
+
},
|
|
60
|
+
async revokeAllForUser(userId, at = Date.now()) {
|
|
61
|
+
const res = await db
|
|
62
|
+
.updateTable('adminium_sessions')
|
|
63
|
+
.set({ revokedAt: at })
|
|
64
|
+
.where('userId', '=', userId)
|
|
65
|
+
.where('revokedAt', 'is', null)
|
|
66
|
+
.executeTakeFirst();
|
|
67
|
+
return Number(res.numUpdatedRows);
|
|
68
|
+
},
|
|
69
|
+
/** Retention §8 `sessions` policy: expired, or revoked > 24 h ago. */
|
|
70
|
+
async gc(at = Date.now()) {
|
|
71
|
+
const res = await db
|
|
72
|
+
.deleteFrom('adminium_sessions')
|
|
73
|
+
.where((eb) => eb.or([eb('expiresAt', '<', at), eb('revokedAt', '<', at - DAY_MS)]))
|
|
74
|
+
.executeTakeFirst();
|
|
75
|
+
return Number(res.numDeletedRows);
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/repos/sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* settingsRepo — adminium_settings (07-meta-store.md §3.2, §7.1).
|
|
3
|
+
* Stores explicit overrides only; reads resolve `stored ?? registry default`.
|
|
4
|
+
*/
|
|
5
|
+
import type { MetaDb } from '../connect.js';
|
|
6
|
+
import { type SettingKey, type SettingValue } from '../schema/settings-registry.js';
|
|
7
|
+
export declare class UnknownSettingError extends Error {
|
|
8
|
+
name: string;
|
|
9
|
+
constructor(key: string);
|
|
10
|
+
}
|
|
11
|
+
export declare function settingsRepo(meta: MetaDb): {
|
|
12
|
+
/** Registry default merged with the stored override, validated on the way out. */
|
|
13
|
+
get<K extends SettingKey>(key: K): Promise<SettingValue<K>>;
|
|
14
|
+
/** Validate and upsert an explicit override. */
|
|
15
|
+
set<K extends SettingKey>(key: K, value: SettingValue<K>, opts?: {
|
|
16
|
+
updatedBy?: string | null;
|
|
17
|
+
at?: number;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
/** Remove an override — the key falls back to the registry default. */
|
|
20
|
+
unset(key: SettingKey): Promise<boolean>;
|
|
21
|
+
/** Explicit overrides only (validated); unknown/stale keys are skipped. */
|
|
22
|
+
overrides(): Promise<Partial<Record<SettingKey, unknown>>>;
|
|
23
|
+
};
|
|
24
|
+
export type SettingsRepo = ReturnType<typeof settingsRepo>;
|
|
25
|
+
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/repos/settings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,YAAY,EAClB,MAAM,gCAAgC,CAAC;AAGxC,qBAAa,mBAAoB,SAAQ,KAAK;IACnC,IAAI,SAAyB;gBAC1B,GAAG,EAAE,MAAM;CAGxB;AAMD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM;IAGrC,kFAAkF;QACxE,CAAC,SAAS,UAAU,OAAO,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAQjE,gDAAgD;QACtC,CAAC,SAAS,UAAU,OACvB,CAAC,SACC,YAAY,CAAC,CAAC,CAAC,SAChB;QAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/C,OAAO,CAAC,IAAI,CAAC;IAuBhB,uEAAuE;eACtD,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAM9C,2EAA2E;iBACxD,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;EAWnE;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* settingsRepo — adminium_settings (07-meta-store.md §3.2, §7.1).
|
|
3
|
+
* Stores explicit overrides only; reads resolve `stored ?? registry default`.
|
|
4
|
+
*/
|
|
5
|
+
import { SETTINGS_REGISTRY, isSettingKey, } from '../schema/settings-registry.js';
|
|
6
|
+
import { MetaValidationError, packJson, readJson } from './util.js';
|
|
7
|
+
export class UnknownSettingError extends Error {
|
|
8
|
+
name = 'UnknownSettingError';
|
|
9
|
+
constructor(key) {
|
|
10
|
+
super(`unknown settings key: ${JSON.stringify(key)}`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function assertKey(key) {
|
|
14
|
+
if (!isSettingKey(key))
|
|
15
|
+
throw new UnknownSettingError(key);
|
|
16
|
+
}
|
|
17
|
+
export function settingsRepo(meta) {
|
|
18
|
+
const { db } = meta;
|
|
19
|
+
return {
|
|
20
|
+
/** Registry default merged with the stored override, validated on the way out. */
|
|
21
|
+
async get(key) {
|
|
22
|
+
assertKey(key);
|
|
23
|
+
const def = SETTINGS_REGISTRY[key];
|
|
24
|
+
const row = await db.selectFrom('adminium_settings').selectAll().where('key', '=', key).executeTakeFirst();
|
|
25
|
+
if (!row)
|
|
26
|
+
return def.default;
|
|
27
|
+
return def.schema.parse(readJson(row.value));
|
|
28
|
+
},
|
|
29
|
+
/** Validate and upsert an explicit override. */
|
|
30
|
+
async set(key, value, opts = {}) {
|
|
31
|
+
assertKey(key);
|
|
32
|
+
const def = SETTINGS_REGISTRY[key];
|
|
33
|
+
const parsed = def.schema.safeParse(value);
|
|
34
|
+
if (!parsed.success) {
|
|
35
|
+
throw new MetaValidationError(`invalid value for setting ${key}`, parsed.error.issues);
|
|
36
|
+
}
|
|
37
|
+
const at = opts.at ?? Date.now();
|
|
38
|
+
const packed = packJson(parsed.data);
|
|
39
|
+
const updatedBy = opts.updatedBy ?? null;
|
|
40
|
+
const res = await db
|
|
41
|
+
.updateTable('adminium_settings')
|
|
42
|
+
.set({ value: packed, updatedAt: at, updatedBy })
|
|
43
|
+
.where('key', '=', key)
|
|
44
|
+
.executeTakeFirst();
|
|
45
|
+
if (Number(res.numUpdatedRows) === 0) {
|
|
46
|
+
await db
|
|
47
|
+
.insertInto('adminium_settings')
|
|
48
|
+
.values({ key, value: packed, updatedAt: at, updatedBy })
|
|
49
|
+
.execute();
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
/** Remove an override — the key falls back to the registry default. */
|
|
53
|
+
async unset(key) {
|
|
54
|
+
assertKey(key);
|
|
55
|
+
const res = await db.deleteFrom('adminium_settings').where('key', '=', key).executeTakeFirst();
|
|
56
|
+
return Number(res.numDeletedRows) === 1;
|
|
57
|
+
},
|
|
58
|
+
/** Explicit overrides only (validated); unknown/stale keys are skipped. */
|
|
59
|
+
async overrides() {
|
|
60
|
+
const rows = await db.selectFrom('adminium_settings').selectAll().execute();
|
|
61
|
+
const out = {};
|
|
62
|
+
for (const row of rows) {
|
|
63
|
+
if (!isSettingKey(row.key))
|
|
64
|
+
continue;
|
|
65
|
+
const parsed = SETTINGS_REGISTRY[row.key].schema.safeParse(readJson(row.value));
|
|
66
|
+
if (parsed.success)
|
|
67
|
+
out[row.key] = parsed.data;
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/repos/settings.ts"],"names":[],"mappings":"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"}
|