@isahaq/kosh-server 0.0.0-stage → 0.1.0

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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -2
  3. package/dist/api/client.d.ts +18 -0
  4. package/dist/api/client.d.ts.map +1 -0
  5. package/dist/api/client.js +380 -0
  6. package/dist/api/client.js.map +1 -0
  7. package/dist/api/idempotency.d.ts +23 -0
  8. package/dist/api/idempotency.d.ts.map +1 -0
  9. package/dist/api/idempotency.js +52 -0
  10. package/dist/api/idempotency.js.map +1 -0
  11. package/dist/api/metadata.d.ts +65 -0
  12. package/dist/api/metadata.d.ts.map +1 -0
  13. package/dist/api/metadata.js +88 -0
  14. package/dist/api/metadata.js.map +1 -0
  15. package/dist/api/navigation.d.ts +46 -0
  16. package/dist/api/navigation.d.ts.map +1 -0
  17. package/dist/api/navigation.js +131 -0
  18. package/dist/api/navigation.js.map +1 -0
  19. package/dist/api/openapi.d.ts +22 -0
  20. package/dist/api/openapi.d.ts.map +1 -0
  21. package/dist/api/openapi.js +349 -0
  22. package/dist/api/openapi.js.map +1 -0
  23. package/dist/api/rest.d.ts +28 -0
  24. package/dist/api/rest.d.ts.map +1 -0
  25. package/dist/api/rest.js +435 -0
  26. package/dist/api/rest.js.map +1 -0
  27. package/dist/api/views.d.ts +67 -0
  28. package/dist/api/views.d.ts.map +1 -0
  29. package/dist/api/views.js +307 -0
  30. package/dist/api/views.js.map +1 -0
  31. package/dist/audit.d.ts +21 -0
  32. package/dist/audit.d.ts.map +1 -0
  33. package/dist/audit.js +26 -0
  34. package/dist/audit.js.map +1 -0
  35. package/dist/auth/admins.d.ts +26 -0
  36. package/dist/auth/admins.d.ts.map +1 -0
  37. package/dist/auth/admins.js +70 -0
  38. package/dist/auth/admins.js.map +1 -0
  39. package/dist/auth/base.d.ts +12 -0
  40. package/dist/auth/base.d.ts.map +1 -0
  41. package/dist/auth/base.js +192 -0
  42. package/dist/auth/base.js.map +1 -0
  43. package/dist/auth/crypto.d.ts +20 -0
  44. package/dist/auth/crypto.d.ts.map +1 -0
  45. package/dist/auth/crypto.js +100 -0
  46. package/dist/auth/crypto.js.map +1 -0
  47. package/dist/auth/install.d.ts +24 -0
  48. package/dist/auth/install.d.ts.map +1 -0
  49. package/dist/auth/install.js +18 -0
  50. package/dist/auth/install.js.map +1 -0
  51. package/dist/auth/routes.d.ts +20 -0
  52. package/dist/auth/routes.d.ts.map +1 -0
  53. package/dist/auth/routes.js +56 -0
  54. package/dist/auth/routes.js.map +1 -0
  55. package/dist/auth/service.d.ts +108 -0
  56. package/dist/auth/service.d.ts.map +1 -0
  57. package/dist/auth/service.js +477 -0
  58. package/dist/auth/service.js.map +1 -0
  59. package/dist/errors.d.ts +21 -0
  60. package/dist/errors.d.ts.map +1 -0
  61. package/dist/errors.js +78 -0
  62. package/dist/errors.js.map +1 -0
  63. package/dist/identity.d.ts +49 -0
  64. package/dist/identity.d.ts.map +1 -0
  65. package/dist/identity.js +58 -0
  66. package/dist/identity.js.map +1 -0
  67. package/dist/index.d.ts +26 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +26 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/orm.d.ts +14 -0
  72. package/dist/orm.d.ts.map +1 -0
  73. package/dist/orm.js +12 -0
  74. package/dist/orm.js.map +1 -0
  75. package/dist/registry.d.ts +19 -0
  76. package/dist/registry.d.ts.map +1 -0
  77. package/dist/registry.js +26 -0
  78. package/dist/registry.js.map +1 -0
  79. package/dist/server.d.ts +93 -0
  80. package/dist/server.d.ts.map +1 -0
  81. package/dist/server.js +223 -0
  82. package/dist/server.js.map +1 -0
  83. package/dist/telemetry.d.ts +23 -0
  84. package/dist/telemetry.d.ts.map +1 -0
  85. package/dist/telemetry.js +38 -0
  86. package/dist/telemetry.js.map +1 -0
  87. package/package.json +63 -3
@@ -0,0 +1,307 @@
1
+ import { resolveView, validateAction, validateSearch, validateView, } from '@isahaq/kosh-views';
2
+ import { HttpProblem, ServerConfigError } from '../errors.js';
3
+ const VIEW_TYPES = [
4
+ 'list',
5
+ 'form',
6
+ 'kanban',
7
+ 'pivot',
8
+ 'graph',
9
+ 'calendar',
10
+ 'gantt',
11
+ 'map',
12
+ 'hierarchy',
13
+ 'cohort',
14
+ 'spreadsheet',
15
+ 'dashboard',
16
+ 'designer',
17
+ ];
18
+ function config(problem) {
19
+ return new ServerConfigError(problem, 'Fix the module manifest (views, actions, search).');
20
+ }
21
+ /** The views, actions and searches of a loaded module set. */
22
+ export class ViewRegistry {
23
+ views;
24
+ actions;
25
+ searches;
26
+ #models;
27
+ /** @throws {ServerConfigError} for invalid or conflicting views, actions and searches */
28
+ constructor(modules, models) {
29
+ this.#models = models;
30
+ const lookup = (name) => {
31
+ const m = models.get(name);
32
+ return m === undefined
33
+ ? undefined
34
+ : {
35
+ fields: new Map(m.fields.map((f) => [f.key, { kind: f.kind, target: f.target, stored: f.stored }])),
36
+ transitions: m.transitions,
37
+ };
38
+ };
39
+ const owners = new Map();
40
+ const raw = new Map();
41
+ for (const m of modules)
42
+ for (const [id, view] of Object.entries(m.views ?? {})) {
43
+ const owner = owners.get(id);
44
+ if (owner !== undefined)
45
+ throw config(`Modules ${owner} and ${m.name} both define the view '${id}'.`);
46
+ owners.set(id, m.name);
47
+ raw.set(id, { ...view, id });
48
+ }
49
+ const extensions = modules.flatMap((m) => (m.viewExtensions ?? []).map((extension) => {
50
+ if (!raw.has(extension.view))
51
+ throw config(`Module ${m.name} extends the unknown view '${extension.view}'.`);
52
+ return { module: m.name, extension };
53
+ }));
54
+ const views = new Map();
55
+ for (const [id, view] of raw) {
56
+ let resolved;
57
+ try {
58
+ resolved = resolveView(view, owners.get(id), extensions);
59
+ }
60
+ catch (error) {
61
+ throw config(error instanceof Error ? error.message : String(error));
62
+ }
63
+ const problems = validateView(resolved.view, lookup);
64
+ if (problems.length > 0)
65
+ throw config(`View '${id}': ${problems.join('; ')}.`);
66
+ views.set(id, resolved);
67
+ }
68
+ this.views = views;
69
+ const plain = new Map([...views].map(([id, r]) => [id, r.view]));
70
+ const actions = new Map();
71
+ for (const m of modules)
72
+ for (const [id, action] of Object.entries(m.actions ?? {})) {
73
+ const problems = validateAction(action, lookup, plain);
74
+ if (problems.length > 0)
75
+ throw config(`Action '${id}' of ${m.name}: ${problems.join('; ')}.`);
76
+ actions.set(id, action);
77
+ }
78
+ this.actions = actions;
79
+ const searches = new Map();
80
+ for (const m of modules)
81
+ for (const [model, spec] of Object.entries(m.search ?? {})) {
82
+ const problems = validateSearch(model, spec, lookup);
83
+ if (problems.length > 0)
84
+ throw config(`Search of ${model} in ${m.name}: ${problems.join('; ')}.`);
85
+ // Later modules add to earlier ones (fields, filters, group-by options).
86
+ const before = searches.get(model);
87
+ searches.set(model, before === undefined
88
+ ? spec
89
+ : {
90
+ fields: [...new Set([...before.fields, ...spec.fields])],
91
+ filters: { ...before.filters, ...spec.filters },
92
+ groupBy: [...new Set([...(before.groupBy ?? []), ...(spec.groupBy ?? [])])],
93
+ });
94
+ }
95
+ this.searches = searches;
96
+ }
97
+ /** The first view of `type` for `model`, in module order. */
98
+ defaultView(model, type) {
99
+ for (const [id, r] of this.views)
100
+ if (r.view.model === model && r.view.type === type)
101
+ return id;
102
+ return undefined;
103
+ }
104
+ /** The view for `env`'s user. @throws {AccessError} without read access */
105
+ serve(env, id) {
106
+ const resolved = this.views.get(id);
107
+ if (resolved === undefined)
108
+ throw new HttpProblem(404, 'unknown-view', 'Unknown view', `No view '${id}'.`);
109
+ const view = resolved.view;
110
+ env.access.check(view.model, 'read');
111
+ const model = this.#models.get(view.model);
112
+ const fields = {};
113
+ const meta = (owner, key) => {
114
+ const head = key.split('.')[0];
115
+ const field = owner.byKey.get(head);
116
+ if (field === undefined || !env.access.canField(owner.name, head, 'read'))
117
+ return null;
118
+ const served = describe(env, owner, field);
119
+ const byModel = fields[owner.name] ?? {};
120
+ byModel[head] = served;
121
+ fields[owner.name] = byModel;
122
+ return served;
123
+ };
124
+ const canWrite = env.access.can(view.model, 'write');
125
+ const keepField = (owner) => (node) => {
126
+ const served = meta(owner, node.field);
127
+ return served === null ? null : node;
128
+ };
129
+ const filterNodes = (nodes, owner) => nodes.flatMap((node) => {
130
+ switch (node.kind) {
131
+ case 'field': {
132
+ const kept = keepField(owner)(node);
133
+ return kept === null ? [] : [kept];
134
+ }
135
+ case 'group':
136
+ return [{ ...node, children: filterNodes(node.children, owner) }];
137
+ case 'notebook':
138
+ return [
139
+ {
140
+ ...node,
141
+ pages: node.pages.map((p) => ({ ...p, children: filterNodes(p.children, owner) })),
142
+ },
143
+ ];
144
+ case 'lines': {
145
+ const field = owner.byKey.get(node.field);
146
+ const target = field?.target === null || field === undefined
147
+ ? undefined
148
+ : this.#models.get(field.target);
149
+ if (meta(owner, node.field) === null ||
150
+ target === undefined ||
151
+ !env.access.can(target.name, 'read'))
152
+ return [];
153
+ return [
154
+ {
155
+ ...node,
156
+ columns: node.columns.flatMap((c) => (keepField(target)(c) === null ? [] : [c])),
157
+ },
158
+ ];
159
+ }
160
+ default:
161
+ return [node]; // components: rendered as they are
162
+ }
163
+ });
164
+ const transitions = model.transitionSpecs.filter((t) => canWrite && (t.requires === null || hasPermission(env, t.requires)));
165
+ const allowed = new Set(transitions.map((t) => t.name));
166
+ let served;
167
+ switch (view.type) {
168
+ case 'list':
169
+ served = {
170
+ ...view,
171
+ columns: view.columns.flatMap((c) => (keepField(model)(c) === null ? [] : [c])),
172
+ };
173
+ break;
174
+ case 'form': {
175
+ if (view.header.statusbar !== undefined)
176
+ meta(model, view.header.statusbar);
177
+ const buttons = view.header.buttons.filter((b) => allowed.has(b.transition));
178
+ served = {
179
+ ...view,
180
+ header: { ...view.header, buttons },
181
+ sheet: filterNodes(view.sheet, model),
182
+ };
183
+ break;
184
+ }
185
+ case 'kanban': {
186
+ meta(model, view.groupBy);
187
+ for (const key of [view.card.title, view.card.subtitle].filter((k) => k !== undefined))
188
+ meta(model, key);
189
+ const keep = (nodes) => (nodes ?? []).flatMap((c) => (keepField(model)(c) === null ? [] : [c]));
190
+ served = {
191
+ ...view,
192
+ card: { ...view.card, footer: keep(view.card.footer), badges: keep(view.card.badges) },
193
+ };
194
+ break;
195
+ }
196
+ default: {
197
+ // Report views: groups and measures on fields the user may not read are left out (the report query
198
+ // would refuse them); the metadata of every referenced field goes along.
199
+ const readable = (key) => meta(model, key.split(':')[0]) !== null;
200
+ const measureField = (m) => m.measure === 'count' ? undefined : Object.values(m.measure)[0];
201
+ const readableMeasure = (m) => {
202
+ const key = measureField(m);
203
+ return key === undefined || readable(key);
204
+ };
205
+ if (view.type === 'pivot')
206
+ served = {
207
+ ...view,
208
+ rows: view.rows.filter(readable),
209
+ cols: view.cols.filter(readable),
210
+ measures: view.measures.filter(readableMeasure),
211
+ };
212
+ else if (view.type === 'graph') {
213
+ if (!readableMeasure(view.measure) || !view.groupBy.every(readable))
214
+ throw new HttpProblem(403, 'access', 'Forbidden', 'This chart uses fields you may not read.');
215
+ served = view;
216
+ }
217
+ else {
218
+ for (const value of Object.values(view))
219
+ if (typeof value === 'string' && model.byKey.has(value.split('.')[0]))
220
+ meta(model, value);
221
+ served = view;
222
+ }
223
+ }
224
+ }
225
+ for (const key of ['id', 'displayName'])
226
+ meta(model, key);
227
+ return {
228
+ view: served,
229
+ fields,
230
+ transitions: transitions.map(({ name, field, from, to }) => ({ name, field, from, to })),
231
+ operations: {
232
+ create: env.access.can(view.model, 'create'),
233
+ write: canWrite,
234
+ unlink: env.access.can(view.model, 'unlink'),
235
+ },
236
+ onchange: model.onchange,
237
+ };
238
+ }
239
+ /** The search definition for `env`'s user: options on fields they may not read are left out. */
240
+ serveSearch(env, model) {
241
+ env.access.check(model, 'read');
242
+ const spec = this.searches.get(model) ?? { fields: this.#defaultSearchFields(model) };
243
+ const readable = (key) => {
244
+ const head = key.split(/[.:]/)[0];
245
+ return env.access.canField(model, head, 'read');
246
+ };
247
+ const filters = Object.fromEntries(Object.entries(spec.filters ?? {}).filter(([, f]) => Object.keys(f.domain).every((k) => ['and', 'or', 'not'].includes(k) || readable(k))));
248
+ return {
249
+ fields: spec.fields.filter(readable),
250
+ filters,
251
+ groupBy: (spec.groupBy ?? []).filter(readable),
252
+ };
253
+ }
254
+ #defaultSearchFields(model) {
255
+ const m = this.#models.get(model);
256
+ if (m === undefined)
257
+ return [];
258
+ return ['name', 'displayName'].filter((k) => m.byKey.get(k)?.stored === true).slice(0, 1);
259
+ }
260
+ /** Registers the routes. */
261
+ register(app) {
262
+ app.get('/api/v1/views/:id', async (request) => {
263
+ const id = String(request.params.id ?? '');
264
+ return request.env(async (env) => this.serve(env, id));
265
+ });
266
+ app.get('/api/v1/views', async (request) => {
267
+ const q = (request.query ?? {});
268
+ const model = String(q.model ?? '');
269
+ const type = String(q.type ?? '');
270
+ if (!VIEW_TYPES.includes(type))
271
+ throw new HttpProblem(400, 'invalid-type', 'Invalid view type', `type is one of ${VIEW_TYPES.join(', ')}.`);
272
+ const id = this.defaultView(model, type);
273
+ if (id === undefined)
274
+ throw new HttpProblem(404, 'unknown-view', 'No view', `${model} has no ${type} view.`, 'Define one in a module manifest.');
275
+ return request.env(async (env) => this.serve(env, id));
276
+ });
277
+ app.get('/api/v1/search/:model', async (request) => {
278
+ const model = String(request.params.model ?? '');
279
+ if (!this.#models.has(model))
280
+ throw new HttpProblem(404, 'unknown-model', 'Unknown model', `No model '${model}'.`);
281
+ return request.env(async (env) => this.serveSearch(env, model));
282
+ });
283
+ }
284
+ }
285
+ function hasPermission(env, code) {
286
+ try {
287
+ return env.access.has(code);
288
+ }
289
+ catch {
290
+ return false;
291
+ }
292
+ }
293
+ function describe(env, model, field) {
294
+ return {
295
+ key: field.key,
296
+ kind: field.kind,
297
+ label: field.label,
298
+ required: field.required,
299
+ // Field-level only: the UI combines it with `operations` (create for new records, write for existing ones).
300
+ readonly: field.readonly || !env.access.canField(model.name, field.key, 'write'),
301
+ ...(field.target === null ? {} : { target: field.target }),
302
+ ...(field.options === null
303
+ ? {}
304
+ : { options: field.options.map(([value, label]) => ({ value, label })) }),
305
+ };
306
+ }
307
+ //# sourceMappingURL=views.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"views.js","sourceRoot":"","sources":["../../src/api/views.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The security audit log (`audit.event`, CLAUDE.md: logins, permission changes, exports and sensitive actions),
3
+ * written in the caller's transaction so an event exists exactly when the change it records does.
4
+ */
5
+ import type { Env } from './orm.js';
6
+ /** One audit event. */
7
+ export interface AuditInput {
8
+ /** Dotted kind: `auth.login`, `auth.login_failed`, `admin.session`, `security.role`, `data.export`, ... */
9
+ readonly kind: string;
10
+ readonly summary: string;
11
+ /** Default: the environment's user (none for system scopes). */
12
+ readonly actor?: number | null;
13
+ readonly company?: number | null;
14
+ readonly targetModel?: string;
15
+ readonly targetId?: number;
16
+ readonly details?: unknown;
17
+ readonly ip?: string;
18
+ }
19
+ /** Writes an audit event in `env`'s transaction. */
20
+ export declare function audit(env: Env, input: AuditInput): Promise<void>;
21
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAGpC,uBAAuB;AACvB,MAAM,WAAW,UAAU;IACzB,2GAA2G;IAC3G,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,oDAAoD;AACpD,wBAAsB,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBtE"}
package/dist/audit.js ADDED
@@ -0,0 +1,26 @@
1
+ import { orm } from './orm.js';
2
+ /** Writes an audit event in `env`'s transaction. */
3
+ export async function audit(env, input) {
4
+ const actor = input.actor === undefined ? (env.uid === orm.SYSTEM_UID ? null : env.uid) : input.actor;
5
+ const row = {
6
+ kind: input.kind,
7
+ summary: input.summary.slice(0, 500),
8
+ actor,
9
+ company: input.company === undefined
10
+ ? env.uid === orm.SYSTEM_UID
11
+ ? null
12
+ : env.companyId
13
+ : input.company,
14
+ ...(input.targetModel === undefined ? {} : { targetModel: input.targetModel }),
15
+ ...(input.targetId === undefined ? {} : { targetId: input.targetId }),
16
+ ...(input.details === undefined ? {} : { details: input.details }),
17
+ ...(input.ip === undefined ? {} : { ip: input.ip }),
18
+ };
19
+ const write = (e) => e.model('audit.event').create([row]);
20
+ // Internal users may append events; anyone else (e.g. a user without groups) appends through a system scope.
21
+ if (env.su || env.access.can('audit.event', 'create'))
22
+ await write(env);
23
+ else
24
+ await env.asSuperuser({ reason: `audit ${input.kind}` }, write);
25
+ }
26
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAgB/B,oDAAoD;AACpD,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,GAAQ,EAAE,KAAiB;IACrD,MAAM,KAAK,GACT,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IAC1F,MAAM,GAAG,GAAG;QACV,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QACpC,KAAK;QACL,OAAO,EACL,KAAK,CAAC,OAAO,KAAK,SAAS;YACzB,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,UAAU;gBAC1B,CAAC,CAAC,IAAI;gBACN,CAAC,CAAC,GAAG,CAAC,SAAS;YACjB,CAAC,CAAC,KAAK,CAAC,OAAO;QACnB,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;QAC9E,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;QACrE,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QAClE,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;KACpD,CAAC;IACF,MAAM,KAAK,GAAG,CAAC,CAAM,EAAE,EAAE,CAErB,CAAC,CAAC,KAAK,CAAC,aAAsB,CAC/B,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClB,6GAA6G;IAC7G,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,aAAsB,EAAE,QAAQ,CAAC;QAAE,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;;QAC5E,MAAM,GAAG,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;AACvE,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { Env } from '../orm.js';
2
+ /** The ids of the active, 2FA-enabled administrators (read in a superuser scope). */
3
+ export declare function administrators(env: Env): Promise<number[]>;
4
+ /** True when the user holds an administrator group or role (in any company). */
5
+ export declare function isAdministratorUser(env: Env, user: number): Promise<boolean>;
6
+ export declare const LAST_ADMINISTRATOR = "This change would leave no active administrator with two-factor authentication.";
7
+ declare const HINT = "Make another user an administrator (with 2FA enabled) first.";
8
+ /**
9
+ * Runs `fn` and refuses (409) when it removed the last administrator. Admin APIs wrap every change of roles and
10
+ * assignments with it. @throws {HttpProblem} 409 `last-administrator`
11
+ */
12
+ export declare function keepingAdministrator<T>(env: Env, fn: () => Promise<T>): Promise<T>;
13
+ /**
14
+ * Shutro constraint check (on `res.users.active` and `auth.credential.totpEnabled`): the records that removed the
15
+ * last administrator. Only changes that take an administrator away count, so installing the first one is possible.
16
+ */
17
+ export declare function lastAdministratorRemoved(records: {
18
+ readonly env: Env;
19
+ readonly ids: readonly number[];
20
+ }, userOf: (env: Env, ids: readonly number[]) => Promise<{
21
+ id: number;
22
+ user: number;
23
+ removed: boolean;
24
+ }[]>): Promise<number[]>;
25
+ export { HINT as LAST_ADMINISTRATOR_HINT };
26
+ //# sourceMappingURL=admins.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admins.d.ts","sourceRoot":"","sources":["../../src/auth/admins.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAiBrC,qFAAqF;AACrF,wBAAsB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkBhE;AAED,gFAAgF;AAChF,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQlF;AAED,eAAO,MAAM,kBAAkB,oFACoD,CAAC;AACpF,QAAA,MAAM,IAAI,iEAAiE,CAAC;AAE5E;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAaxF;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EAC/D,MAAM,EAAE,CACN,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,SAAS,MAAM,EAAE,KACnB,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,EAAE,CAAC,GAC7D,OAAO,CAAC,MAAM,EAAE,CAAC,CAQnB;AAED,OAAO,EAAE,IAAI,IAAI,uBAAuB,EAAE,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * The "keep at least one administrator" guard (CLAUDE.md, RFC 0003 §5.2): an administrator is an active user with
3
+ * two-factor authentication on and an assignment of a group or role that makes its holder an administrator
4
+ * (`env.access.administratorGroups()`, code groups and runtime roles). A change that leaves none is refused, also
5
+ * for administrators and system scopes: the bypass skips permission checks, not integrity.
6
+ */
7
+ import { HttpProblem } from '../errors.js';
8
+ const search = (env, model, where) => env.model(model).search({ where });
9
+ async function rows(env, model, where, keys) {
10
+ const found = await search(env, model, where);
11
+ return found.length === 0 ? [] : (await found.load(keys)).read(keys);
12
+ }
13
+ /** The ids of the active, 2FA-enabled administrators (read in a superuser scope). */
14
+ export async function administrators(env) {
15
+ return env.asSuperuser({ reason: 'check administrators' }, async (su) => {
16
+ const codes = [...su.access.administratorGroups()];
17
+ if (codes.length === 0)
18
+ return [];
19
+ const holders = [
20
+ ...new Set((await rows(su, 'auth.user_group', { group: { in: codes } }, ['user'])).map((r) => r['user'])),
21
+ ];
22
+ if (holders.length === 0)
23
+ return [];
24
+ const active = (await search(su, 'res.users', { id: { in: holders } })).ids;
25
+ if (active.length === 0)
26
+ return [];
27
+ return (await rows(su, 'auth.credential', { user: { in: [...active] }, totpEnabled: true }, ['user'])).map((r) => r['user']);
28
+ });
29
+ }
30
+ /** True when the user holds an administrator group or role (in any company). */
31
+ export async function isAdministratorUser(env, user) {
32
+ return env.asSuperuser({ reason: 'check administrator' }, async (su) => {
33
+ const codes = [...su.access.administratorGroups()];
34
+ return (codes.length > 0 &&
35
+ (await search(su, 'auth.user_group', { user, group: { in: codes } })).length > 0);
36
+ });
37
+ }
38
+ export const LAST_ADMINISTRATOR = 'This change would leave no active administrator with two-factor authentication.';
39
+ const HINT = 'Make another user an administrator (with 2FA enabled) first.';
40
+ /**
41
+ * Runs `fn` and refuses (409) when it removed the last administrator. Admin APIs wrap every change of roles and
42
+ * assignments with it. @throws {HttpProblem} 409 `last-administrator`
43
+ */
44
+ export async function keepingAdministrator(env, fn) {
45
+ const before = (await administrators(env)).length;
46
+ const result = await fn();
47
+ await env.flush();
48
+ if (before > 0 && (await administrators(env)).length === 0)
49
+ throw new HttpProblem(409, 'last-administrator', 'Last administrator', LAST_ADMINISTRATOR, HINT);
50
+ return result;
51
+ }
52
+ /**
53
+ * Shutro constraint check (on `res.users.active` and `auth.credential.totpEnabled`): the records that removed the
54
+ * last administrator. Only changes that take an administrator away count, so installing the first one is possible.
55
+ */
56
+ export async function lastAdministratorRemoved(records, userOf) {
57
+ const env = records.env;
58
+ const changed = (await userOf(env, records.ids)).filter((c) => c.removed);
59
+ if (changed.length === 0)
60
+ return [];
61
+ const admins = [];
62
+ for (const c of changed)
63
+ if (await isAdministratorUser(env, c.user))
64
+ admins.push(c.id);
65
+ if (admins.length === 0)
66
+ return [];
67
+ return (await administrators(env)).length === 0 ? admins : [];
68
+ }
69
+ export { HINT as LAST_ADMINISTRATOR_HINT };
70
+ //# sourceMappingURL=admins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admins.js","sourceRoot":"","sources":["../../src/auth/admins.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The framework's `base` module (CLAUDE.md, Phase 1: users and companies): currencies, companies, users, and the
3
+ * private authentication models (credentials, sessions, per-company group assignments). Every Kosh application
4
+ * depends on it. Administrators (`base.admin`) need no grants (RFC 0003 §5.2).
5
+ */
6
+ import { defineModule as defineKoshModule } from '@isahaq/kosh-modules-sdk';
7
+ import { orm } from '../orm.js';
8
+ /** The Shutro module behind {@link base}. */
9
+ export declare const baseShutro: ReturnType<typeof orm.defineModule>;
10
+ /** The framework's base module: depend on it from every application module. */
11
+ export declare const base: ReturnType<typeof defineKoshModule>;
12
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/auth/base.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5E,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AA8KhC,6CAA6C;AAC7C,eAAO,MAAM,UAAU,EAAE,UAAU,CAAC,OAAO,GAAG,CAAC,YAAY,CAuBzD,CAAC;AAEH,+EAA+E;AAC/E,eAAO,MAAM,IAAI,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAcnD,CAAC"}