@adminiumjs/manifest 0.3.0-rc.3 → 0.3.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 (57) hide show
  1. package/dist/booking.d.ts +100 -0
  2. package/dist/booking.d.ts.map +1 -0
  3. package/dist/booking.js +237 -0
  4. package/dist/booking.js.map +1 -0
  5. package/dist/index.d.ts +8 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +8 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/outbox.d.ts +198 -0
  10. package/dist/outbox.d.ts.map +1 -0
  11. package/dist/outbox.js +355 -0
  12. package/dist/outbox.js.map +1 -0
  13. package/dist/page-calendar.d.ts +42 -0
  14. package/dist/page-calendar.d.ts.map +1 -0
  15. package/dist/page-calendar.js +95 -0
  16. package/dist/page-calendar.js.map +1 -0
  17. package/dist/plan-context.d.ts +51 -0
  18. package/dist/plan-context.d.ts.map +1 -0
  19. package/dist/plan-context.js +356 -0
  20. package/dist/plan-context.js.map +1 -0
  21. package/dist/plan-model.d.ts +197 -0
  22. package/dist/plan-model.d.ts.map +1 -0
  23. package/dist/plan-model.js +11 -0
  24. package/dist/plan-model.js.map +1 -0
  25. package/dist/plan-types.d.ts +12 -0
  26. package/dist/plan-types.d.ts.map +1 -0
  27. package/dist/plan-types.js +71 -0
  28. package/dist/plan-types.js.map +1 -0
  29. package/dist/plan.d.ts +9 -90
  30. package/dist/plan.d.ts.map +1 -1
  31. package/dist/plan.js +48 -1
  32. package/dist/plan.js.map +1 -1
  33. package/dist/public-access.d.ts +167 -0
  34. package/dist/public-access.d.ts.map +1 -0
  35. package/dist/public-access.js +475 -0
  36. package/dist/public-access.js.map +1 -0
  37. package/dist/refs.d.ts +74 -0
  38. package/dist/refs.d.ts.map +1 -0
  39. package/dist/refs.js +70 -0
  40. package/dist/refs.js.map +1 -0
  41. package/dist/roles.d.ts +44 -0
  42. package/dist/roles.d.ts.map +1 -0
  43. package/dist/roles.js +75 -0
  44. package/dist/roles.js.map +1 -0
  45. package/dist/sample.d.ts +200 -0
  46. package/dist/sample.d.ts.map +1 -0
  47. package/dist/sample.js +208 -0
  48. package/dist/sample.js.map +1 -0
  49. package/dist/schema.d.ts +2031 -51
  50. package/dist/schema.d.ts.map +1 -1
  51. package/dist/schema.js +559 -18
  52. package/dist/schema.js.map +1 -1
  53. package/dist/semver.d.ts +28 -0
  54. package/dist/semver.d.ts.map +1 -0
  55. package/dist/semver.js +85 -0
  56. package/dist/semver.js.map +1 -0
  57. package/package.json +2 -2
@@ -0,0 +1,356 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ /**
3
+ * Planning an APP install with what the server knows about this connection:
4
+ * the app's prefix, the tables it already recorded here, what other apps
5
+ * record here, and the operator's answers for the tables whose names are taken.
6
+ *
7
+ * ─── Why a context at all ───────────────────────────────────────────────────
8
+ *
9
+ * Without one, a table either exists (reuse) or does not (create), and that
10
+ * was the whole plan. It could not tell the app's own table from an earlier
11
+ * install apart from another app's table of the same name, could not offer
12
+ * to rename a stranger's table out of the way, and could not give an app its
13
+ * own prefix. Each table is now CLASSIFIED first, then given an ACTION:
14
+ *
15
+ * new the real name is free → create
16
+ * own-leftover this app recorded it (an earlier install) → reuse (default)
17
+ * shared another app recorded it under the SAME shape (`menu@1`)
18
+ * → share (default)
19
+ * taken it exists and nothing records it as this app's
20
+ * → the operator chooses
21
+ *
22
+ * For a taken table the operator chooses: REUSE it (offered only when it is
23
+ * not another app's in disguise and every change it needs is safe), RENAME the
24
+ * existing table out of the way (only when no other install records it), or
25
+ * give the whole app a DIFFERENT PREFIX (always offered, and it applies to
26
+ * every table at once). Until each taken table has an answer, the plan is not
27
+ * installable and says which table is waiting.
28
+ *
29
+ * ─── Edits ─────────────────────────────────────────────────────────────────
30
+ *
31
+ * A reused table may need changes before the app can write to it. Only changes
32
+ * that cannot lose data are ever offered: adding a missing column (nullable),
33
+ * widening a type along a fixed list (a longer varchar, varchar to text, int
34
+ * to bigint, a wider enum column), giving an int key the identity it lacks, and
35
+ * adding enum values. Anything else is refused on this screen, by name.
36
+ *
37
+ * Pure, like the planner it extends: no I/O. The server gathers the context.
38
+ */
39
+ import { typeConflict } from './plan-types.js';
40
+ /** The longest identifier each engine accepts, in bytes. SQLite has none; the portable 63 holds. */
41
+ export const IDENTIFIER_LIMIT = {
42
+ postgres: 63,
43
+ mysql: 64,
44
+ sqlite: 63,
45
+ };
46
+ /** `adminium_roles.slug` is 40 characters. */
47
+ export const ROLE_SLUG_LIMIT = 40;
48
+ const IDENTIFIER = /^[a-z][a-z0-9_]*$/;
49
+ function byteLength(text) {
50
+ return new TextEncoder().encode(text).length;
51
+ }
52
+ /** The type a declared column is created with, for an edit's `to` — the installer's own vocabulary. */
53
+ function declaredShape(column) {
54
+ if (column.type === 'text' && column.maxLength !== undefined)
55
+ return `varchar(${String(column.maxLength)})`;
56
+ if (column.type === 'enum') {
57
+ const width = (column.enum ?? []).every((value) => value.length <= 32) ? 32 : 64;
58
+ return `varchar(${String(width)})`;
59
+ }
60
+ return column.type;
61
+ }
62
+ /**
63
+ * The widening that would let an existing column hold what the manifest
64
+ * stores, or null when there is no such safe change.
65
+ */
66
+ function wideningFor(declared, have, dialect) {
67
+ const type = have.logicalType;
68
+ const width = typeof have.maxLength === 'number' ? have.maxLength : null;
69
+ if (declared.type === 'text' && type === 'varchar' && width !== null) {
70
+ return { from: `varchar(${String(width)})`, to: declaredShape(declared) };
71
+ }
72
+ if (declared.type === 'enum' && type === 'varchar' && width !== null) {
73
+ return { from: `varchar(${String(width)})`, to: declaredShape(declared) };
74
+ }
75
+ if (declared.type === 'bigint' && type === 'integer') {
76
+ // MySQL cannot change the type of a key another table's foreign key points
77
+ // at; a primary key is where that is all but certain.
78
+ if (dialect === 'mysql' && have.isPrimaryKey === true)
79
+ return null;
80
+ return { from: 'integer', to: 'bigint' };
81
+ }
82
+ return null;
83
+ }
84
+ /**
85
+ * A column an update can add to a table that exists. A link (`fk`) can, when
86
+ * it is nullable: every existing row starts unlinked, and the schema editor
87
+ * adds the foreign key beside it. A required link cannot — the rows already
88
+ * there would have nothing to point at.
89
+ */
90
+ function isOfferable(column) {
91
+ if (column.type === 'fk')
92
+ return column.nullable === true;
93
+ return column.type !== 'id' && column.type !== 'blob';
94
+ }
95
+ /**
96
+ * The context half of `planInstall`. Called by it when a context is given;
97
+ * the returned plan keeps every field older callers read (`create`, `reuse`,
98
+ * `references`, `problems`) and adds `tables` and `names`.
99
+ */
100
+ export function planWithContext(manifest, model, context) {
101
+ const noun = manifest.kind === 'app' ? 'app' : 'add-on';
102
+ const required = manifest.requiredSchema?.tables ?? [];
103
+ const live = new Map(model.tables.map((t) => [t.ref, t]));
104
+ const limit = IDENTIFIER_LIMIT[context.dialect];
105
+ const problems = [];
106
+ const prefix = context.prefix === null ? null : (context.altPrefix ?? context.prefix);
107
+ if (context.altPrefix !== undefined && !/^[a-z][a-z0-9_]*_$/.test(context.altPrefix)) {
108
+ problems.push({
109
+ code: 'IDENTIFIER_TOO_LONG',
110
+ table: context.altPrefix,
111
+ message: `"${context.altPrefix}" is not a usable prefix: lower-case letters, digits and "_", ending in "_".`,
112
+ });
113
+ }
114
+ // 1. Real names. A record wins (it is what this app already uses here); an
115
+ // alternative prefix re-names everything that is not recorded.
116
+ const names = {};
117
+ for (const table of required) {
118
+ const record = context.records[table.ref];
119
+ const usable = record !== undefined && record.state !== 'dropped';
120
+ names[table.ref] = usable && context.altPrefix === undefined ? record.table : prefix === null ? table.ref : `${prefix}${table.ref}`;
121
+ }
122
+ const realNames = new Set(Object.values(names));
123
+ const tables = [];
124
+ for (const table of required) {
125
+ const real = names[table.ref];
126
+ const record = context.records[table.ref];
127
+ const existing = live.get(real);
128
+ const holders = context.others.filter((o) => o.table === real && o.state !== 'dropped');
129
+ const choice = context.choices?.[table.ref];
130
+ if (byteLength(real) > limit) {
131
+ problems.push({
132
+ code: 'IDENTIFIER_TOO_LONG',
133
+ table: table.ref,
134
+ message: `"${real}" is longer than this database allows (${String(limit)} bytes). Choose a shorter prefix.`,
135
+ });
136
+ }
137
+ for (const column of table.columns) {
138
+ if (column.type !== 'fk')
139
+ continue;
140
+ const fk = `fk_${real}_${column.ref}`;
141
+ if (byteLength(fk) > limit) {
142
+ problems.push({
143
+ code: 'IDENTIFIER_TOO_LONG',
144
+ table: table.ref,
145
+ column: column.ref,
146
+ message: `The foreign key "${fk}" would be longer than this database allows (${String(limit)} bytes). Choose a shorter prefix.`,
147
+ });
148
+ }
149
+ }
150
+ // 2. Classify.
151
+ const ownRecord = record !== undefined && record.state !== 'dropped' && context.altPrefix === undefined;
152
+ const sharer = table.shape === undefined ? undefined : holders.find((o) => o.shape === table.shape && o.state !== 'released');
153
+ const klass = existing === undefined ? 'new' : ownRecord ? 'own-leftover' : sharer !== undefined ? 'shared' : 'taken';
154
+ // Two apps whose prefixed names meet. A declared shape both share is the
155
+ // one way two apps may use one table.
156
+ if (holders.length > 0 && sharer === undefined && !ownRecord) {
157
+ problems.push({
158
+ code: 'PREFIX_COLLISION',
159
+ table: table.ref,
160
+ message: `"${real}" is already "${holders[0].appKey}"'s table, so this ${noun} cannot use that name. ` +
161
+ `Give this ${noun} a different prefix.`,
162
+ });
163
+ }
164
+ // Why reuse is not safe for a stranger's table.
165
+ const declaredColumns = new Set(table.columns.map((c) => c.ref));
166
+ const foreign = existing === undefined
167
+ ? []
168
+ : existing.columns.filter((c) => !declaredColumns.has(c.ref) &&
169
+ c.nullable === false &&
170
+ c.hasDefault !== true &&
171
+ c.isPrimaryKey !== true &&
172
+ c.isGenerated !== true);
173
+ const plan = {
174
+ ref: table.ref,
175
+ table: real,
176
+ class: klass,
177
+ action: 'create',
178
+ offers: [],
179
+ edits: [],
180
+ blocked: [],
181
+ };
182
+ if (klass === 'new') {
183
+ plan.action = 'create';
184
+ }
185
+ else if (klass === 'own-leftover') {
186
+ plan.offers = ['reuse', 'rename-existing', 'alt-prefix'];
187
+ if (record?.owned === false)
188
+ plan.adopted = true;
189
+ plan.action = choice?.action === 'rename-existing' ? 'rename-existing' : 'reuse';
190
+ }
191
+ else if (klass === 'shared') {
192
+ plan.offers = ['share', 'alt-prefix'];
193
+ plan.sharedWith = sharer.appKey;
194
+ plan.action = 'share';
195
+ }
196
+ else {
197
+ plan.offers = ['alt-prefix'];
198
+ if (foreign.length === 0)
199
+ plan.offers.unshift('reuse');
200
+ else {
201
+ plan.reuseRefusal =
202
+ `It requires ${foreign.map((c) => `"${c.ref}"`).join(', ')}, which this ${noun} never fills, ` +
203
+ `so every row the ${noun} saves there would be refused.`;
204
+ }
205
+ if (holders.length === 0)
206
+ plan.offers.splice(plan.offers.length - 1, 0, 'rename-existing');
207
+ if (choice === undefined)
208
+ plan.action = 'undecided';
209
+ else if (choice.action === 'reuse' && plan.offers.includes('reuse'))
210
+ plan.action = 'reuse';
211
+ else if (choice.action === 'rename-existing' && plan.offers.includes('rename-existing'))
212
+ plan.action = 'rename-existing';
213
+ else
214
+ plan.action = 'undecided';
215
+ }
216
+ if (plan.action === 'rename-existing') {
217
+ const to = choice?.action === 'rename-existing' ? choice.to : `${real}_old`;
218
+ plan.renameExistingTo = to;
219
+ if (!IDENTIFIER.test(to) || byteLength(to) > limit || live.has(to) || realNames.has(to)) {
220
+ problems.push({
221
+ code: 'TABLE_TAKEN',
222
+ table: table.ref,
223
+ message: `"${to}" cannot be the existing table's new name: it must be a free, lower-case name of at most ${String(limit)} bytes.`,
224
+ });
225
+ }
226
+ }
227
+ if (plan.action === 'undecided') {
228
+ problems.push({
229
+ code: 'TABLE_TAKEN',
230
+ table: table.ref,
231
+ message: `"${real}" already exists and was made by hand. Pick what to do with it before you install.`,
232
+ });
233
+ }
234
+ // 3. Edits, for a table the app will use as it is.
235
+ if ((plan.action === 'reuse' || plan.action === 'share') && existing !== undefined) {
236
+ for (const column of table.columns) {
237
+ const have = existing.columns.find((c) => c.ref === column.ref);
238
+ if (have === undefined) {
239
+ if (isOfferable(column))
240
+ plan.edits.push({ kind: 'add-column', column: column.ref });
241
+ else {
242
+ plan.blocked.push({
243
+ column: column.ref,
244
+ reason: column.type === 'id' ? 'primary-key' : column.type === 'fk' ? 'foreign-key' : 'unsupported-type',
245
+ });
246
+ }
247
+ continue;
248
+ }
249
+ const conflict = typeConflict(column, have, context.dialect);
250
+ if (conflict !== null) {
251
+ const widen = wideningFor(column, have, context.dialect);
252
+ if (widen !== null)
253
+ plan.edits.push({ kind: 'widen', column: column.ref, ...widen });
254
+ else {
255
+ problems.push({
256
+ code: 'COLUMN_TYPE_CONFLICT',
257
+ table: table.ref,
258
+ column: column.ref,
259
+ message: `"${real}.${column.ref}" already exists as ${conflict}, which cannot hold the ${column.type} values this ${noun} stores in it.`,
260
+ });
261
+ }
262
+ continue;
263
+ }
264
+ if (column.role === 'pk' && (column.type === 'int' || column.type === 'bigint') && have.isIdentity === false) {
265
+ plan.edits.push({ kind: 'set-identity', column: column.ref });
266
+ }
267
+ if (column.type === 'enum' && have.enumValues !== undefined) {
268
+ const missing = (column.enum ?? []).filter((value) => !have.enumValues.includes(value));
269
+ if (missing.length > 0)
270
+ plan.edits.push({ kind: 'enum-values', column: column.ref, values: missing });
271
+ }
272
+ }
273
+ if (plan.blocked.length > 0) {
274
+ problems.push({
275
+ code: 'COLUMNS_REQUIRED',
276
+ table: table.ref,
277
+ column: plan.blocked[0].column,
278
+ message: `"${real}" is missing ${plan.blocked.map((b) => `"${b.column}"`).join(', ')}, which cannot be added ` +
279
+ `to a table that already exists. Rename that table out of the way, or use a different prefix.`,
280
+ });
281
+ }
282
+ }
283
+ tables.push(plan);
284
+ }
285
+ // 4. References, against real names.
286
+ const references = [];
287
+ const declared = new Set(required.map((t) => t.ref));
288
+ for (const table of required) {
289
+ for (const column of table.columns) {
290
+ if (column.type !== 'fk' || column.references === undefined)
291
+ continue;
292
+ const target = column.references;
293
+ const resolution = declared.has(target) ? 'internal' : live.has(target) ? 'host' : 'unresolved';
294
+ references.push({ fromTable: table.ref, fromColumn: column.ref, to: target, resolution });
295
+ if (resolution === 'unresolved') {
296
+ problems.push({
297
+ code: 'UNRESOLVED_REFERENCE',
298
+ table: table.ref,
299
+ column: column.ref,
300
+ message: `"${table.ref}.${column.ref}" points at a table called "${target}", which this ` +
301
+ `${noun} does not create and this database does not have. Connect a database that ` +
302
+ `already has it, or create it first.`,
303
+ });
304
+ }
305
+ }
306
+ }
307
+ // 5. Role slugs fit their column.
308
+ if (manifest.kind === 'app') {
309
+ for (const role of manifest.roles ?? []) {
310
+ const slug = `${manifest.key}-${role.key}`;
311
+ if (slug.length > ROLE_SLUG_LIMIT) {
312
+ problems.push({
313
+ code: 'IDENTIFIER_TOO_LONG',
314
+ table: role.key,
315
+ message: `The role "${slug}" is longer than ${String(ROLE_SLUG_LIMIT)} characters.`,
316
+ });
317
+ }
318
+ }
319
+ }
320
+ for (const table of required) {
321
+ if (table.ref.startsWith('adminium_') || names[table.ref].startsWith('adminium_')) {
322
+ problems.push({
323
+ code: 'RESERVED_TABLE',
324
+ table: table.ref,
325
+ message: `"${names[table.ref]}" is in Adminium's own namespace.`,
326
+ });
327
+ }
328
+ }
329
+ const planned = (plan) => {
330
+ const spec = required.find((t) => t.ref === plan.ref);
331
+ const have = live.get(plan.table);
332
+ const missing = plan.action === 'reuse' || plan.action === 'share'
333
+ ? spec.columns.filter((c) => have !== undefined && !have.columns.some((x) => x.ref === c.ref)).map((c) => c.ref)
334
+ : [];
335
+ return {
336
+ ref: plan.ref,
337
+ table: plan.table,
338
+ action: plan.action === 'reuse' || plan.action === 'share' ? 'reuse' : 'create',
339
+ columns: spec.columns.map((c) => ({ ref: c.ref, type: c.type, missing: missing.includes(c.ref) })),
340
+ missingColumns: missing,
341
+ };
342
+ };
343
+ return {
344
+ addOnKey: manifest.key,
345
+ version: manifest.version,
346
+ create: tables.filter((t) => t.action === 'create' || t.action === 'rename-existing').map(planned),
347
+ reuse: tables.filter((t) => t.action === 'reuse' || t.action === 'share').map(planned),
348
+ references,
349
+ problems,
350
+ installable: problems.length === 0,
351
+ touchesData: required.length > 0,
352
+ tables,
353
+ names,
354
+ };
355
+ }
356
+ //# sourceMappingURL=plan-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-context.js","sourceRoot":"","sources":["../src/plan-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,197 @@
1
+ /**
2
+ * The install planner's shapes, on their own.
3
+ *
4
+ * Types only, so the planner (`plan.ts`), its context extension
5
+ * (`plan-context.ts`) and the type rules (`plan-types.ts`) can all name them
6
+ * without importing one another in a circle. `plan.ts` and `plan-context.ts`
7
+ * re-export them, so every importer outside keeps its path.
8
+ */
9
+ /** The existing database, as much of it as planning needs. */
10
+ export interface SchemaModelView {
11
+ /** Every table name that already exists, however it got there. */
12
+ tables: readonly {
13
+ ref: string;
14
+ columns: readonly ExistingColumnView[];
15
+ }[];
16
+ /**
17
+ * The engine the tables live on. Only the type check reads it: SQLite
18
+ * reports the installer's own `bool` as `integer` and its `money` as
19
+ * `float`, which would be a conflict anywhere else. Absent, a type is judged
20
+ * by the rules every engine shares.
21
+ */
22
+ dialect?: 'postgres' | 'mysql' | 'sqlite' | undefined;
23
+ }
24
+ /**
25
+ * One existing column. Only `ref` is required; the rest is what the database
26
+ * reports, and a caller that does not know it leaves it out. A column that
27
+ * says nothing is never treated as required.
28
+ */
29
+ export interface ExistingColumnView {
30
+ ref: string;
31
+ nullable?: boolean;
32
+ /** The database fills it when an insert leaves it out (a default, a sequence). */
33
+ hasDefault?: boolean;
34
+ isPrimaryKey?: boolean;
35
+ isGenerated?: boolean;
36
+ /** The engine's logical type (`integer`, `varchar`, …). Absent = not judged. */
37
+ logicalType?: string;
38
+ /** A `varchar`'s width, when it has one. */
39
+ maxLength?: number | null;
40
+ /** A key the database numbers itself. Absent = unknown, never offered a repair. */
41
+ isIdentity?: boolean;
42
+ /** The values an enum column's CHECK (or native enum) admits, when it has one. */
43
+ enumValues?: readonly string[];
44
+ }
45
+ /** What will happen to one table. */
46
+ export type TableAction = 'create' | 'reuse';
47
+ export interface PlannedColumn {
48
+ ref: string;
49
+ type: string;
50
+ /** Absent from an existing table, so the install would have to add it. */
51
+ missing: boolean;
52
+ }
53
+ export interface PlannedTable {
54
+ ref: string;
55
+ /** The real table name, when a plan context gave the table one (prefixed or recorded). */
56
+ table?: string;
57
+ action: TableAction;
58
+ columns: PlannedColumn[];
59
+ /**
60
+ * Only on `reuse`: columns the manifest requires that the existing table does
61
+ * not have. A non-empty list is a PARTIAL MATCH — the table is there but does
62
+ * not carry what the add-on needs, which is a different situation from either
63
+ * "create it" or "it fits", and the operator should be told which.
64
+ */
65
+ missingColumns: string[];
66
+ }
67
+ /** Where one declared foreign key ends up pointing. */
68
+ export interface PlannedReference {
69
+ fromTable: string;
70
+ fromColumn: string;
71
+ to: string;
72
+ /**
73
+ * `internal` — the target is another table in this manifest.
74
+ * `host` — the target already exists in the database (the add-on attaching to
75
+ * the host's data, which is the intended shape).
76
+ * `unresolved` — the target exists nowhere, and the plan is not installable.
77
+ */
78
+ resolution: 'internal' | 'host' | 'unresolved';
79
+ }
80
+ /** A reason the plan cannot be applied, phrased for a person. */
81
+ export interface PlanProblem {
82
+ code: 'UNRESOLVED_REFERENCE' | 'COLUMN_TYPE_CONFLICT' | 'COLUMNS_REQUIRED' | 'RESERVED_TABLE' | 'FOREIGN_TABLE' | 'TABLE_TAKEN' | 'IDENTIFIER_TOO_LONG' | 'PREFIX_COLLISION' | 'PAGE_SLUG_TAKEN' | 'PAGE_FORM_INVALID' | 'ROLE_INVALID' | 'EMAIL_TEMPLATE_INVALID';
83
+ message: string;
84
+ table: string;
85
+ column?: string;
86
+ }
87
+ export interface InstallPlan {
88
+ /**
89
+ * The manifest key this plan is for.
90
+ *
91
+ * Named `addOnKey` because add-ons were the only caller when it was written,
92
+ * and left named that because the wire DTOs each route builds are where a
93
+ * reader meets it — `routes/apps` spells it `key` on its own reply. Renaming
94
+ * it here would churn three call sites and a shipped dialog for a field only
95
+ * the server reads.
96
+ */
97
+ addOnKey: string;
98
+ version: string;
99
+ /** Tables to create, in declaration order (targets before dependents). */
100
+ create: PlannedTable[];
101
+ /** Tables that already exist and will be reused rather than created. */
102
+ reuse: PlannedTable[];
103
+ references: PlannedReference[];
104
+ problems: PlanProblem[];
105
+ /**
106
+ * `true` when there is nothing standing in the way. A plan with problems is
107
+ * still RETURNED — the consent dialog has to be able to show WHY an add-on
108
+ * cannot be installed here, and an exception would leave it with nothing to
109
+ * render.
110
+ */
111
+ installable: boolean;
112
+ /** No `requiredSchema` at all: install touches no data source. */
113
+ touchesData: boolean;
114
+ /** With a plan context: each table's class, action, offers and edits. */
115
+ tables?: InstallTablePlan[];
116
+ /** With a plan context: short name → real table. */
117
+ names?: Record<string, string>;
118
+ }
119
+ /** What the operator answered for one taken table. */
120
+ export type TableChoice = {
121
+ action: 'reuse';
122
+ } | {
123
+ action: 'share';
124
+ } | {
125
+ action: 'rename-existing';
126
+ to: string;
127
+ };
128
+ export interface PlanContext {
129
+ /** The app's own prefix (`pos_`), or null for an app whose tables are not prefixed. */
130
+ prefix: string | null;
131
+ /** A different prefix for every table of this app, chosen on the check step. */
132
+ altPrefix?: string | undefined;
133
+ /** This app's own records on this connection, by short name. */
134
+ records: Readonly<Record<string, {
135
+ table: string;
136
+ owned: boolean;
137
+ state: string;
138
+ }>>;
139
+ /** What OTHER apps record on this connection. */
140
+ others: readonly {
141
+ appKey: string;
142
+ table: string;
143
+ shape: string | null;
144
+ state: string;
145
+ }[];
146
+ /** The operator's answers, by short name. */
147
+ choices?: Readonly<Record<string, TableChoice>> | undefined;
148
+ dialect: 'postgres' | 'mysql' | 'sqlite';
149
+ }
150
+ export type TableClass = 'new' | 'own-leftover' | 'shared' | 'taken';
151
+ export type ContextTableAction = 'create' | 'reuse' | 'share' | 'rename-existing' | 'undecided';
152
+ export type TableOffer = 'reuse' | 'share' | 'rename-existing' | 'alt-prefix';
153
+ /** One change a reused table needs, every one of them unable to lose data. */
154
+ export type PlanEdit = {
155
+ kind: 'add-column';
156
+ column: string;
157
+ } | {
158
+ kind: 'widen';
159
+ column: string;
160
+ from: string;
161
+ to: string;
162
+ } | {
163
+ kind: 'set-identity';
164
+ column: string;
165
+ } | {
166
+ kind: 'enum-values';
167
+ column: string;
168
+ values: string[];
169
+ };
170
+ export interface InstallTablePlan {
171
+ /** The manifest's short name. */
172
+ ref: string;
173
+ /** The real table: prefixed, recorded, or the ref itself. */
174
+ table: string;
175
+ class: TableClass;
176
+ action: ContextTableAction;
177
+ /** What the check step offers for this table. */
178
+ offers: TableOffer[];
179
+ /** Why reuse is NOT offered on a taken table, for a person. */
180
+ reuseRefusal?: string | undefined;
181
+ /** For `rename-existing`: what the existing table is renamed to. */
182
+ renameExistingTo?: string | undefined;
183
+ /** For `share`: the app whose table this is. */
184
+ sharedWith?: string | undefined;
185
+ /**
186
+ * For `own-leftover`: the earlier install used a table that was already
187
+ * there rather than making it. The check step words the two apart.
188
+ */
189
+ adopted?: true | undefined;
190
+ edits: PlanEdit[];
191
+ /** Columns that cannot be added this way, and why. */
192
+ blocked: {
193
+ column: string;
194
+ reason: 'foreign-key' | 'primary-key' | 'unsupported-type';
195
+ }[];
196
+ }
197
+ //# sourceMappingURL=plan-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-model.d.ts","sourceRoot":"","sources":["../src/plan-model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ /**
3
+ * The install planner's shapes, on their own.
4
+ *
5
+ * Types only, so the planner (`plan.ts`), its context extension
6
+ * (`plan-context.ts`) and the type rules (`plan-types.ts`) can all name them
7
+ * without importing one another in a circle. `plan.ts` and `plan-context.ts`
8
+ * re-export them, so every importer outside keeps its path.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=plan-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-model.js","sourceRoot":"","sources":["../src/plan-model.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC;;;;;;;GAOG"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Whether an existing column can hold what a manifest stores in it — shared by
3
+ * both halves of the planner.
4
+ */
5
+ import type { ExistingColumnView, SchemaModelView } from './plan-model.js';
6
+ import type { RequiredColumn } from './schema.js';
7
+ /**
8
+ * Why an existing column cannot hold what the manifest stores in it — its type,
9
+ * named for a person — or `null` when it can (or cannot be judged).
10
+ */
11
+ export declare function typeConflict(declared: RequiredColumn, existing: ExistingColumnView, dialect: SchemaModelView['dialect']): string | null;
12
+ //# sourceMappingURL=plan-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-types.d.ts","sourceRoot":"","sources":["../src/plan-types.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAwClD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,GAClC,MAAM,GAAG,IAAI,CAuBf"}