@adminiumjs/manifest 0.3.0-rc.3 → 0.3.0-rc.4
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/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/plan-context.d.ts +51 -0
- package/dist/plan-context.d.ts.map +1 -0
- package/dist/plan-context.js +356 -0
- package/dist/plan-context.js.map +1 -0
- package/dist/plan-model.d.ts +197 -0
- package/dist/plan-model.d.ts.map +1 -0
- package/dist/plan-model.js +11 -0
- package/dist/plan-model.js.map +1 -0
- package/dist/plan-types.d.ts +12 -0
- package/dist/plan-types.d.ts.map +1 -0
- package/dist/plan-types.js +71 -0
- package/dist/plan-types.js.map +1 -0
- package/dist/plan.d.ts +9 -90
- package/dist/plan.d.ts.map +1 -1
- package/dist/plan.js +48 -1
- package/dist/plan.js.map +1 -1
- package/dist/sample.d.ts +100 -0
- package/dist/sample.d.ts.map +1 -0
- package/dist/sample.js +147 -0
- package/dist/sample.js.map +1 -0
- package/dist/schema.d.ts +992 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +498 -3
- package/dist/schema.js.map +1 -1
- package/package.json +2 -2
|
@@ -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';
|
|
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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
/**
|
|
3
|
+
* Whether an existing column can hold what a manifest stores in it — shared by
|
|
4
|
+
* both halves of the planner.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* The logical types an existing column may have for each declared type, on
|
|
8
|
+
* every engine. Deliberately generous: a column that can hold every value the
|
|
9
|
+
* app writes is not a conflict, whatever it is called. A foreign key is judged
|
|
10
|
+
* by the key it points at, which the DDL resolves, so it is never judged here.
|
|
11
|
+
*/
|
|
12
|
+
const ACCEPTS = {
|
|
13
|
+
id: ['varchar', 'text', 'uuid'],
|
|
14
|
+
text: ['text', 'varchar', 'enum'],
|
|
15
|
+
int: ['integer', 'bigint'],
|
|
16
|
+
bigint: ['bigint'],
|
|
17
|
+
decimal: ['decimal'],
|
|
18
|
+
money: ['decimal'],
|
|
19
|
+
float: ['float', 'decimal'],
|
|
20
|
+
bool: ['boolean'],
|
|
21
|
+
enum: ['enum', 'varchar', 'text'],
|
|
22
|
+
json: ['json'],
|
|
23
|
+
date: ['date', 'timestamp', 'timestamptz'],
|
|
24
|
+
timestamptz: ['timestamptz', 'timestamp'],
|
|
25
|
+
uuid: ['uuid', 'varchar', 'text'],
|
|
26
|
+
blob: ['binary'],
|
|
27
|
+
fk: null,
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* What SQLite reports for the columns the installer itself creates there: it
|
|
31
|
+
* has four storage classes, so `bool` is an `integer`, `money` a `float` (REAL)
|
|
32
|
+
* and `json` plain `text`. Without these, an app's own table would conflict
|
|
33
|
+
* with the app on every SQLite reinstall.
|
|
34
|
+
*/
|
|
35
|
+
const SQLITE_ALSO = {
|
|
36
|
+
bigint: ['integer'],
|
|
37
|
+
decimal: ['float'],
|
|
38
|
+
money: ['float'],
|
|
39
|
+
bool: ['integer'],
|
|
40
|
+
json: ['text'],
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Why an existing column cannot hold what the manifest stores in it — its type,
|
|
44
|
+
* named for a person — or `null` when it can (or cannot be judged).
|
|
45
|
+
*/
|
|
46
|
+
export function typeConflict(declared, existing, dialect) {
|
|
47
|
+
const accepts = ACCEPTS[declared.type];
|
|
48
|
+
const have = existing.logicalType;
|
|
49
|
+
if (accepts === null || have === undefined || have === 'unknown')
|
|
50
|
+
return null;
|
|
51
|
+
const also = dialect === 'sqlite' ? (SQLITE_ALSO[declared.type] ?? []) : [];
|
|
52
|
+
if (!accepts.includes(have) && !also.includes(have))
|
|
53
|
+
return have;
|
|
54
|
+
// A width narrower than the one the app declares. An app that declares no
|
|
55
|
+
// width is not judged: the installer itself keys MySQL text as varchar(255).
|
|
56
|
+
if (declared.type === 'text' &&
|
|
57
|
+
have === 'varchar' &&
|
|
58
|
+
typeof existing.maxLength === 'number' &&
|
|
59
|
+
declared.maxLength !== undefined &&
|
|
60
|
+
existing.maxLength < declared.maxLength) {
|
|
61
|
+
return `varchar(${String(existing.maxLength)})`;
|
|
62
|
+
}
|
|
63
|
+
// An enum column narrower than its longest value.
|
|
64
|
+
if (declared.type === 'enum' && have === 'varchar' && typeof existing.maxLength === 'number') {
|
|
65
|
+
const longest = Math.max(0, ...(declared.enum ?? []).map((value) => value.length));
|
|
66
|
+
if (existing.maxLength < longest)
|
|
67
|
+
return `varchar(${String(existing.maxLength)})`;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=plan-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-types.js","sourceRoot":"","sources":["../src/plan-types.ts"],"names":[],"mappings":"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"}
|
package/dist/plan.d.ts
CHANGED
|
@@ -46,96 +46,9 @@
|
|
|
46
46
|
* other tables — on MySQL, which has no transactional DDL, that leaves a
|
|
47
47
|
* half-installed add-on with no rollback.
|
|
48
48
|
*/
|
|
49
|
+
import type { InstallPlan, PlanContext, SchemaModelView } from './plan-model.js';
|
|
49
50
|
import type { Manifest } from './schema.js';
|
|
50
|
-
|
|
51
|
-
export interface SchemaModelView {
|
|
52
|
-
/** Every table name that already exists, however it got there. */
|
|
53
|
-
tables: readonly {
|
|
54
|
-
ref: string;
|
|
55
|
-
columns: readonly ExistingColumnView[];
|
|
56
|
-
}[];
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* One existing column. Only `ref` is required; the rest is what the database
|
|
60
|
-
* reports, and a caller that does not know it leaves it out. A column that
|
|
61
|
-
* says nothing is never treated as required.
|
|
62
|
-
*/
|
|
63
|
-
export interface ExistingColumnView {
|
|
64
|
-
ref: string;
|
|
65
|
-
nullable?: boolean;
|
|
66
|
-
/** The database fills it when an insert leaves it out (a default, a sequence). */
|
|
67
|
-
hasDefault?: boolean;
|
|
68
|
-
isPrimaryKey?: boolean;
|
|
69
|
-
isGenerated?: boolean;
|
|
70
|
-
}
|
|
71
|
-
/** What will happen to one table. */
|
|
72
|
-
export type TableAction = 'create' | 'reuse';
|
|
73
|
-
export interface PlannedColumn {
|
|
74
|
-
ref: string;
|
|
75
|
-
type: string;
|
|
76
|
-
/** Absent from an existing table, so the install would have to add it. */
|
|
77
|
-
missing: boolean;
|
|
78
|
-
}
|
|
79
|
-
export interface PlannedTable {
|
|
80
|
-
ref: string;
|
|
81
|
-
action: TableAction;
|
|
82
|
-
columns: PlannedColumn[];
|
|
83
|
-
/**
|
|
84
|
-
* Only on `reuse`: columns the manifest requires that the existing table does
|
|
85
|
-
* not have. A non-empty list is a PARTIAL MATCH — the table is there but does
|
|
86
|
-
* not carry what the add-on needs, which is a different situation from either
|
|
87
|
-
* "create it" or "it fits", and the operator should be told which.
|
|
88
|
-
*/
|
|
89
|
-
missingColumns: string[];
|
|
90
|
-
}
|
|
91
|
-
/** Where one declared foreign key ends up pointing. */
|
|
92
|
-
export interface PlannedReference {
|
|
93
|
-
fromTable: string;
|
|
94
|
-
fromColumn: string;
|
|
95
|
-
to: string;
|
|
96
|
-
/**
|
|
97
|
-
* `internal` — the target is another table in this manifest.
|
|
98
|
-
* `host` — the target already exists in the database (the add-on attaching to
|
|
99
|
-
* the host's data, which is the intended shape).
|
|
100
|
-
* `unresolved` — the target exists nowhere, and the plan is not installable.
|
|
101
|
-
*/
|
|
102
|
-
resolution: 'internal' | 'host' | 'unresolved';
|
|
103
|
-
}
|
|
104
|
-
/** A reason the plan cannot be applied, phrased for a person. */
|
|
105
|
-
export interface PlanProblem {
|
|
106
|
-
code: 'UNRESOLVED_REFERENCE' | 'COLUMN_TYPE_CONFLICT' | 'RESERVED_TABLE' | 'FOREIGN_TABLE';
|
|
107
|
-
message: string;
|
|
108
|
-
table: string;
|
|
109
|
-
column?: string;
|
|
110
|
-
}
|
|
111
|
-
export interface InstallPlan {
|
|
112
|
-
/**
|
|
113
|
-
* The manifest key this plan is for.
|
|
114
|
-
*
|
|
115
|
-
* Named `addOnKey` because add-ons were the only caller when it was written,
|
|
116
|
-
* and left named that because the wire DTOs each route builds are where a
|
|
117
|
-
* reader meets it — `routes/apps` spells it `key` on its own reply. Renaming
|
|
118
|
-
* it here would churn three call sites and a shipped dialog for a field only
|
|
119
|
-
* the server reads.
|
|
120
|
-
*/
|
|
121
|
-
addOnKey: string;
|
|
122
|
-
version: string;
|
|
123
|
-
/** Tables to create, in declaration order (targets before dependents). */
|
|
124
|
-
create: PlannedTable[];
|
|
125
|
-
/** Tables that already exist and will be reused rather than created. */
|
|
126
|
-
reuse: PlannedTable[];
|
|
127
|
-
references: PlannedReference[];
|
|
128
|
-
problems: PlanProblem[];
|
|
129
|
-
/**
|
|
130
|
-
* `true` when there is nothing standing in the way. A plan with problems is
|
|
131
|
-
* still RETURNED — the consent dialog has to be able to show WHY an add-on
|
|
132
|
-
* cannot be installed here, and an exception would leave it with nothing to
|
|
133
|
-
* render.
|
|
134
|
-
*/
|
|
135
|
-
installable: boolean;
|
|
136
|
-
/** No `requiredSchema` at all: install touches no data source. */
|
|
137
|
-
touchesData: boolean;
|
|
138
|
-
}
|
|
51
|
+
export type { ExistingColumnView, InstallPlan, PlannedColumn, PlannedReference, PlannedTable, PlanProblem, SchemaModelView, TableAction, } from './plan-model.js';
|
|
139
52
|
/**
|
|
140
53
|
* Diffs a manifest's `requiredSchema` against the database it would install
|
|
141
54
|
* into. Pure: no I/O, no side effects, safe to run for a preview.
|
|
@@ -145,5 +58,11 @@ export interface InstallPlan {
|
|
|
145
58
|
* an "add-on" cannot be installed while looking at an app's install dialog is
|
|
146
59
|
* the kind of small wrongness that makes someone distrust the whole screen.
|
|
147
60
|
*/
|
|
148
|
-
export declare function planInstall(manifest: Manifest, model: SchemaModelView
|
|
61
|
+
export declare function planInstall(manifest: Manifest, model: SchemaModelView,
|
|
62
|
+
/**
|
|
63
|
+
* What the server knows about this connection (prefix, the table record,
|
|
64
|
+
* other apps, the operator's answers). Absent — every add-on, and any older
|
|
65
|
+
* caller — the plan is exactly what it always was.
|
|
66
|
+
*/
|
|
67
|
+
context?: PlanContext): InstallPlan;
|
|
149
68
|
//# sourceMappingURL=plan.d.ts.map
|
package/dist/plan.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAGH,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EAKX,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,QAAQ,EAAiC,MAAM,aAAa,CAAC;AAE3E,YAAY,EACV,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,eAAe,EACf,WAAW,GACZ,MAAM,iBAAiB,CAAC;AA2BzB;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,eAAe;AACtB;;;;GAIG;AACH,OAAO,CAAC,EAAE,WAAW,GACpB,WAAW,CAoKb"}
|
package/dist/plan.js
CHANGED
|
@@ -47,6 +47,8 @@
|
|
|
47
47
|
* other tables — on MySQL, which has no transactional DDL, that leaves a
|
|
48
48
|
* half-installed add-on with no rollback.
|
|
49
49
|
*/
|
|
50
|
+
import { planWithContext } from './plan-context.js';
|
|
51
|
+
import { typeConflict } from './plan-types.js';
|
|
50
52
|
/**
|
|
51
53
|
* Table names an add-on may never claim, whatever its manifest says.
|
|
52
54
|
*
|
|
@@ -75,7 +77,15 @@ function planColumns(table, existing) {
|
|
|
75
77
|
* an "add-on" cannot be installed while looking at an app's install dialog is
|
|
76
78
|
* the kind of small wrongness that makes someone distrust the whole screen.
|
|
77
79
|
*/
|
|
78
|
-
export function planInstall(manifest, model
|
|
80
|
+
export function planInstall(manifest, model,
|
|
81
|
+
/**
|
|
82
|
+
* What the server knows about this connection (prefix, the table record,
|
|
83
|
+
* other apps, the operator's answers). Absent — every add-on, and any older
|
|
84
|
+
* caller — the plan is exactly what it always was.
|
|
85
|
+
*/
|
|
86
|
+
context) {
|
|
87
|
+
if (context !== undefined)
|
|
88
|
+
return planWithContext(manifest, model, context);
|
|
79
89
|
const required = manifest.requiredSchema?.tables ?? [];
|
|
80
90
|
const noun = manifest.kind === 'app' ? 'app' : 'add-on';
|
|
81
91
|
const existingByRef = new Map(model.tables.map((t) => [t.ref, t]));
|
|
@@ -140,6 +150,43 @@ export function planInstall(manifest, model) {
|
|
|
140
150
|
});
|
|
141
151
|
}
|
|
142
152
|
}
|
|
153
|
+
/*
|
|
154
|
+
* EVERY REFUSAL ON THE CHECK STEP.
|
|
155
|
+
*
|
|
156
|
+
* A reused table missing columns the app writes, and a column that exists
|
|
157
|
+
* with a type the app's values do not fit, used to plan as "installable" —
|
|
158
|
+
* the wizard showed "reuse" with Install enabled, and the install then
|
|
159
|
+
* refused with a bare error naming no table (the owner's own install hit
|
|
160
|
+
* exactly that). They are problems now, so the check step names the table
|
|
161
|
+
* and Install stays disabled until it is resolved.
|
|
162
|
+
*/
|
|
163
|
+
// Apps only, like FOREIGN_TABLE below: an add-on reuses its HOST's tables,
|
|
164
|
+
// and keeps its own refusal for a host missing columns.
|
|
165
|
+
if (existing !== undefined && manifest.kind === 'app' && missingColumns.length > 0) {
|
|
166
|
+
const list = missingColumns.map((ref) => `"${ref}"`).join(', ');
|
|
167
|
+
problems.push({
|
|
168
|
+
code: 'COLUMNS_REQUIRED',
|
|
169
|
+
table: table.ref,
|
|
170
|
+
column: missingColumns[0],
|
|
171
|
+
message: `This database already has a "${table.ref}" table, and it is missing ${list}, which ` +
|
|
172
|
+
`this ${noun} writes. Add ${missingColumns.length === 1 ? 'it' : 'them'} to the table, ` +
|
|
173
|
+
`or install against a different database.`,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
if (existing !== undefined && manifest.kind === 'app') {
|
|
177
|
+
for (const column of table.columns) {
|
|
178
|
+
const have = existing.columns.find((c) => c.ref === column.ref);
|
|
179
|
+
const conflict = have === undefined ? null : typeConflict(column, have, model.dialect);
|
|
180
|
+
if (conflict === null)
|
|
181
|
+
continue;
|
|
182
|
+
problems.push({
|
|
183
|
+
code: 'COLUMN_TYPE_CONFLICT',
|
|
184
|
+
table: table.ref,
|
|
185
|
+
column: column.ref,
|
|
186
|
+
message: `"${table.ref}.${column.ref}" already exists as ${conflict}, which cannot hold the ${column.type} values this ${noun} stores in it.`,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
143
190
|
for (const column of table.columns) {
|
|
144
191
|
if (column.type !== 'fk' || column.references === undefined)
|
|
145
192
|
continue;
|
package/dist/plan.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"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"}
|
package/dist/sample.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `adminium.sample/1` — an app's sample data, shipped in its package and named
|
|
3
|
+
* by the manifest's `sampleData.file`.
|
|
4
|
+
*
|
|
5
|
+
* Rows are written in the order the tables are listed, parents first, and
|
|
6
|
+
* removed in reverse. A value is a plain JSON value or one of five directives:
|
|
7
|
+
*
|
|
8
|
+
* `{"@ref": "<label>"}` the key of an earlier row with that `@label`
|
|
9
|
+
* `{"@ago": "PT19M"}` an ISO-8601 duration before now
|
|
10
|
+
* `{"@day": -1, "@time": "09:30"}` a wall time in the venue's own zone,
|
|
11
|
+
* days from today
|
|
12
|
+
* `{"@t": {"en-US": "…"}}` the adding person's language
|
|
13
|
+
* `{"@asset": "<label>"}` a file from `assets`, added to the Files library
|
|
14
|
+
*
|
|
15
|
+
* Pure: a format and its checks, no I/O. The server resolves the directives.
|
|
16
|
+
*/
|
|
17
|
+
import { z } from 'zod';
|
|
18
|
+
import type { Manifest } from './schema.js';
|
|
19
|
+
export declare const SAMPLE_FORMAT = "adminium.sample/1";
|
|
20
|
+
/** A column's value: a plain value, a directive, or (for a json column) any object or array. */
|
|
21
|
+
export declare const sampleValueSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, z.ZodUnion<readonly [z.ZodObject<{
|
|
22
|
+
'@ref': z.ZodString;
|
|
23
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
24
|
+
'@ago': z.ZodString;
|
|
25
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
26
|
+
'@day': z.ZodNumber;
|
|
27
|
+
'@time': z.ZodString;
|
|
28
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
29
|
+
'@t': z.ZodRecord<z.ZodString, z.ZodString>;
|
|
30
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
31
|
+
'@asset': z.ZodString;
|
|
32
|
+
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
|
|
33
|
+
export declare const sampleRowSchema: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, z.ZodUnion<readonly [z.ZodObject<{
|
|
34
|
+
'@ref': z.ZodString;
|
|
35
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
36
|
+
'@ago': z.ZodString;
|
|
37
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
38
|
+
'@day': z.ZodNumber;
|
|
39
|
+
'@time': z.ZodString;
|
|
40
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
41
|
+
'@t': z.ZodRecord<z.ZodString, z.ZodString>;
|
|
42
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
43
|
+
'@asset': z.ZodString;
|
|
44
|
+
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
45
|
+
export declare const sampleBundleSchema: z.ZodObject<{
|
|
46
|
+
format: z.ZodLiteral<"adminium.sample/1">;
|
|
47
|
+
app: z.ZodString;
|
|
48
|
+
assets: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
49
|
+
file: z.ZodString;
|
|
50
|
+
sha256: z.ZodString;
|
|
51
|
+
}, z.core.$strict>>>;
|
|
52
|
+
tables: z.ZodArray<z.ZodObject<{
|
|
53
|
+
ref: z.ZodString;
|
|
54
|
+
rows: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, z.ZodUnion<readonly [z.ZodObject<{
|
|
55
|
+
'@ref': z.ZodString;
|
|
56
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
57
|
+
'@ago': z.ZodString;
|
|
58
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
59
|
+
'@day': z.ZodNumber;
|
|
60
|
+
'@time': z.ZodString;
|
|
61
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
62
|
+
'@t': z.ZodRecord<z.ZodString, z.ZodString>;
|
|
63
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
64
|
+
'@asset': z.ZodString;
|
|
65
|
+
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
|
|
66
|
+
}, z.core.$strict>>;
|
|
67
|
+
}, z.core.$strict>;
|
|
68
|
+
export type SampleBundle = z.infer<typeof sampleBundleSchema>;
|
|
69
|
+
export type SampleValue = z.infer<typeof sampleValueSchema>;
|
|
70
|
+
/** A value's directive, when it is one. */
|
|
71
|
+
export declare function sampleDirective(value: unknown): {
|
|
72
|
+
kind: 'ref';
|
|
73
|
+
label: string;
|
|
74
|
+
} | {
|
|
75
|
+
kind: 'ago';
|
|
76
|
+
duration: string;
|
|
77
|
+
} | {
|
|
78
|
+
kind: 'wall';
|
|
79
|
+
day: number;
|
|
80
|
+
time: string;
|
|
81
|
+
} | {
|
|
82
|
+
kind: 't';
|
|
83
|
+
texts: Record<string, string>;
|
|
84
|
+
} | {
|
|
85
|
+
kind: 'asset';
|
|
86
|
+
label: string;
|
|
87
|
+
} | null;
|
|
88
|
+
/** An ISO-8601 duration in milliseconds. */
|
|
89
|
+
export declare function isoDurationMs(duration: string): number;
|
|
90
|
+
export interface SampleIssue {
|
|
91
|
+
path: string;
|
|
92
|
+
message: string;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Everything wrong with a bundle for this manifest: a table it does not
|
|
96
|
+
* declare, a column the table does not have, a label used twice, a `@ref` to
|
|
97
|
+
* a row that comes later or not at all, an `@asset` it does not list.
|
|
98
|
+
*/
|
|
99
|
+
export declare function sampleBundleIssues(bundle: SampleBundle, manifest: Manifest): SampleIssue[];
|
|
100
|
+
//# sourceMappingURL=sample.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample.d.ts","sourceRoot":"","sources":["../src/sample.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,eAAO,MAAM,aAAa,sBAAsB,CAAC;AAsBjD,gGAAgG;AAChG,eAAO,MAAM,iBAAiB;;;;;;;;;;;wFAAuF,CAAC;AAEtH,eAAO,MAAM,eAAe;;;;;;;;;;;yFAA0C,CAAC;AAEvE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;kBAWpB,CAAC;AAEZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,2CAA2C;AAC3C,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAC1C;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC,IAAI,CAaP;AAED,4CAA4C;AAC5C,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUtD;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,GAAG,WAAW,EAAE,CA0D1F"}
|