@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.
- package/dist/booking.d.ts +100 -0
- package/dist/booking.d.ts.map +1 -0
- package/dist/booking.js +237 -0
- package/dist/booking.js.map +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/outbox.d.ts +198 -0
- package/dist/outbox.d.ts.map +1 -0
- package/dist/outbox.js +355 -0
- package/dist/outbox.js.map +1 -0
- package/dist/page-calendar.d.ts +42 -0
- package/dist/page-calendar.d.ts.map +1 -0
- package/dist/page-calendar.js +95 -0
- package/dist/page-calendar.js.map +1 -0
- 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/public-access.d.ts +167 -0
- package/dist/public-access.d.ts.map +1 -0
- package/dist/public-access.js +475 -0
- package/dist/public-access.js.map +1 -0
- package/dist/refs.d.ts +74 -0
- package/dist/refs.d.ts.map +1 -0
- package/dist/refs.js +70 -0
- package/dist/refs.js.map +1 -0
- package/dist/roles.d.ts +44 -0
- package/dist/roles.d.ts.map +1 -0
- package/dist/roles.js +75 -0
- package/dist/roles.js.map +1 -0
- package/dist/sample.d.ts +200 -0
- package/dist/sample.d.ts.map +1 -0
- package/dist/sample.js +208 -0
- package/dist/sample.js.map +1 -0
- package/dist/schema.d.ts +2031 -51
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +559 -18
- package/dist/schema.js.map +1 -1
- package/dist/semver.d.ts +28 -0
- package/dist/semver.d.ts.map +1 -0
- package/dist/semver.js +85 -0
- package/dist/semver.js.map +1 -0
- package/package.json +2 -2
package/dist/outbox.js
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
/**
|
|
3
|
+
* `outbox` and `emailTemplates` — the emails an app sends, declared with the
|
|
4
|
+
* app and versioned with it.
|
|
5
|
+
*
|
|
6
|
+
* The app's own table IS the outbox: every email is a row in it, queued by
|
|
7
|
+
* whatever wants it sent (a producer below, the desk's "Send now", an
|
|
8
|
+
* operator), then sent by Adminium, which records `sent`, `failed` or
|
|
9
|
+
* `skipped` on the row. So the table is the log a person reads, and a row of
|
|
10
|
+
* a kind already there for the same source is what stops a second send.
|
|
11
|
+
*
|
|
12
|
+
* Producers queue rows by themselves: when a row is created, when a column
|
|
13
|
+
* changes to a value, or a lead time before a timestamp (a reminder at the
|
|
14
|
+
* time each patient chose).
|
|
15
|
+
*
|
|
16
|
+
* Templates are stored with the app as their owner. An operator who edits
|
|
17
|
+
* one keeps the edit across the app's updates.
|
|
18
|
+
*/
|
|
19
|
+
import { z } from 'zod';
|
|
20
|
+
import { bcp47TagSchema, refSchema, scalarSchema, settingRefSchema, textOrLabels, valueFits, } from './refs.js';
|
|
21
|
+
/** The statuses an outbox table's status column must offer. */
|
|
22
|
+
export const OUTBOX_STATUSES = ['queued', 'sent', 'failed', 'skipped'];
|
|
23
|
+
/** One condition on a row: equal to a value, one of several, or empty (or not). */
|
|
24
|
+
const conditionSchema = z
|
|
25
|
+
.object({
|
|
26
|
+
column: refSchema,
|
|
27
|
+
eq: scalarSchema.optional(),
|
|
28
|
+
in: z.array(scalarSchema).min(1).max(32).optional(),
|
|
29
|
+
isNull: z.boolean().optional(),
|
|
30
|
+
})
|
|
31
|
+
.strict()
|
|
32
|
+
.refine((c) => [c.eq, c.in, c.isNull].filter((part) => part !== undefined).length === 1, {
|
|
33
|
+
message: 'a condition says one of eq, in or isNull',
|
|
34
|
+
});
|
|
35
|
+
const producerBase = {
|
|
36
|
+
/** The kind of row it queues (a key of `outbox.kinds`). */
|
|
37
|
+
kind: z.string().min(1).max(40),
|
|
38
|
+
/** The outbox column that links the queued row to the row that produced it. */
|
|
39
|
+
link: refSchema,
|
|
40
|
+
/** Paused while the settings row's `enabled` column is false. */
|
|
41
|
+
gate: z.literal('enabled').optional(),
|
|
42
|
+
/** Skipped for a recipient whose `recipient.optIn` column is false. */
|
|
43
|
+
optIn: z.literal(true).optional(),
|
|
44
|
+
};
|
|
45
|
+
const producerSchema = z.union([
|
|
46
|
+
z
|
|
47
|
+
.object({ ...producerBase, onCreate: z.object({ table: refSchema, where: conditionSchema.optional() }).strict() })
|
|
48
|
+
.strict(),
|
|
49
|
+
z
|
|
50
|
+
.object({
|
|
51
|
+
...producerBase,
|
|
52
|
+
onChange: z
|
|
53
|
+
.object({
|
|
54
|
+
table: refSchema,
|
|
55
|
+
column: refSchema,
|
|
56
|
+
to: z.union([scalarSchema, z.array(scalarSchema).min(1).max(16)]),
|
|
57
|
+
where: conditionSchema.optional(),
|
|
58
|
+
})
|
|
59
|
+
.strict(),
|
|
60
|
+
})
|
|
61
|
+
.strict(),
|
|
62
|
+
z
|
|
63
|
+
.object({
|
|
64
|
+
...producerBase,
|
|
65
|
+
before: z
|
|
66
|
+
.object({
|
|
67
|
+
table: refSchema,
|
|
68
|
+
/** The moment the email leads: a timestamptz. */
|
|
69
|
+
at: refSchema,
|
|
70
|
+
/** How many hours before: read through one link, with a settings fallback. */
|
|
71
|
+
lead: z
|
|
72
|
+
.object({
|
|
73
|
+
via: refSchema,
|
|
74
|
+
table: refSchema,
|
|
75
|
+
column: refSchema,
|
|
76
|
+
fallback: settingRefSchema.optional(),
|
|
77
|
+
/** The largest lead anyone may choose, in hours — how far ahead Adminium looks. */
|
|
78
|
+
max: z.number().int().min(1).max(24 * 14),
|
|
79
|
+
})
|
|
80
|
+
.strict(),
|
|
81
|
+
where: conditionSchema.optional(),
|
|
82
|
+
})
|
|
83
|
+
.strict(),
|
|
84
|
+
})
|
|
85
|
+
.strict(),
|
|
86
|
+
]);
|
|
87
|
+
const recipientSchema = z
|
|
88
|
+
.object({
|
|
89
|
+
/** The outbox column pointing at the person, and their table's columns. */
|
|
90
|
+
via: refSchema,
|
|
91
|
+
table: refSchema,
|
|
92
|
+
email: refSchema,
|
|
93
|
+
name: refSchema.optional(),
|
|
94
|
+
language: refSchema.optional(),
|
|
95
|
+
/** A bool the person sets: false means no reminders. */
|
|
96
|
+
optIn: refSchema.optional(),
|
|
97
|
+
/**
|
|
98
|
+
* Where the address comes from when `via` is empty — a first visit made
|
|
99
|
+
* by someone not yet on file carries their details on the row itself.
|
|
100
|
+
*/
|
|
101
|
+
fallback: z
|
|
102
|
+
.object({ via: refSchema, email: refSchema, name: refSchema.optional(), language: refSchema.optional() })
|
|
103
|
+
.strict()
|
|
104
|
+
.optional(),
|
|
105
|
+
})
|
|
106
|
+
.strict();
|
|
107
|
+
export const outboxSchema = z
|
|
108
|
+
.object({
|
|
109
|
+
table: refSchema,
|
|
110
|
+
columns: z
|
|
111
|
+
.object({
|
|
112
|
+
kind: refSchema,
|
|
113
|
+
status: refSchema,
|
|
114
|
+
to: refSchema,
|
|
115
|
+
language: refSchema.optional(),
|
|
116
|
+
due: refSchema.optional(),
|
|
117
|
+
sentAt: refSchema.optional(),
|
|
118
|
+
error: refSchema.optional(),
|
|
119
|
+
})
|
|
120
|
+
.strict(),
|
|
121
|
+
/**
|
|
122
|
+
* The outbox's foreign keys, by the name a template reads them under:
|
|
123
|
+
* `{appointment: 'appointment_id'}` gives a template `appointment.*`.
|
|
124
|
+
*/
|
|
125
|
+
links: z.record(z.string().regex(/^[a-z][a-z_]*$/, 'a link name is snake_case'), refSchema).optional(),
|
|
126
|
+
recipient: recipientSchema,
|
|
127
|
+
/**
|
|
128
|
+
* The app's one-row settings table, read as `practice.*` by every template;
|
|
129
|
+
* `name` is the column its emails are signed with (the sign-in code's too),
|
|
130
|
+
* and `phone` the number Adminium's own notices give a person to ring —
|
|
131
|
+
* the one sent to an old address after a change of email.
|
|
132
|
+
*/
|
|
133
|
+
settings: z
|
|
134
|
+
.object({ table: refSchema, enabled: refSchema.optional(), name: refSchema.optional(), phone: refSchema.optional() })
|
|
135
|
+
.strict()
|
|
136
|
+
.optional(),
|
|
137
|
+
/**
|
|
138
|
+
* Where a template's links lead on the app's guest side: `manage_url` and
|
|
139
|
+
* `booking_url`, as paths under its address (default: its front page).
|
|
140
|
+
*/
|
|
141
|
+
pages: z
|
|
142
|
+
.object({
|
|
143
|
+
manage: z.string().regex(/^\/[A-Za-z0-9/_-]{0,119}$/, 'a path on the guest side, e.g. /my-visits').optional(),
|
|
144
|
+
booking: z.string().regex(/^\/[A-Za-z0-9/_-]{0,119}$/, 'a path on the guest side, e.g. /').optional(),
|
|
145
|
+
})
|
|
146
|
+
.strict()
|
|
147
|
+
.optional(),
|
|
148
|
+
/** Each value of the kind column, and the template it is sent with. */
|
|
149
|
+
kinds: z.record(z.string().min(1).max(40), z.string().min(1).max(80)),
|
|
150
|
+
producers: z.array(producerSchema).max(16).optional(),
|
|
151
|
+
})
|
|
152
|
+
.strict();
|
|
153
|
+
/**
|
|
154
|
+
* One block of a template, in the shape the template store keeps. The `html`
|
|
155
|
+
* block is refused: its variables are not escaped, and a manifest's template
|
|
156
|
+
* renders values a stranger typed (a name on a first visit).
|
|
157
|
+
*/
|
|
158
|
+
const emailBlockSchema = z
|
|
159
|
+
.object({
|
|
160
|
+
block: z
|
|
161
|
+
.string()
|
|
162
|
+
.regex(/^email\.[a-z][a-z0-9-]*$/, 'an email block kind, e.g. email.text')
|
|
163
|
+
.refine((kind) => kind !== 'email.html', { message: 'an app template may not use the html block' }),
|
|
164
|
+
id: z.string().min(1).max(60).optional(),
|
|
165
|
+
label: z.string().min(1).max(120).optional(),
|
|
166
|
+
data: z.record(z.string(), z.unknown()).optional(),
|
|
167
|
+
})
|
|
168
|
+
.strict();
|
|
169
|
+
const emailContentSchema = z
|
|
170
|
+
.object({
|
|
171
|
+
subject: z.string().min(1).max(200),
|
|
172
|
+
preheader: z.string().min(1).max(200).optional(),
|
|
173
|
+
blocks: z.array(emailBlockSchema).min(1).max(40),
|
|
174
|
+
footer: z.string().min(1).max(1000).optional(),
|
|
175
|
+
})
|
|
176
|
+
.strict();
|
|
177
|
+
export const emailTemplateSchema = z
|
|
178
|
+
.object({
|
|
179
|
+
/** `<app key>-<name>`: an app names only its own templates. */
|
|
180
|
+
key: z.string().regex(/^[a-z][a-z0-9-]{1,79}$/, 'a template key is kebab-case'),
|
|
181
|
+
name: textOrLabels,
|
|
182
|
+
/** The variables it reads, for the editor's list. */
|
|
183
|
+
vars: z.array(z.string().regex(/^[a-z_]+(\.[a-z_]+)*$/, 'a variable such as patient.name')).max(60).optional(),
|
|
184
|
+
/** The template in each language it ships, US English always among them. */
|
|
185
|
+
locales: z
|
|
186
|
+
.record(bcp47TagSchema, emailContentSchema)
|
|
187
|
+
.refine((locales) => locales['en-US'] !== undefined, { message: 'a template includes en-US' }),
|
|
188
|
+
})
|
|
189
|
+
.strict();
|
|
190
|
+
/** Everything in `outbox` and `emailTemplates` that names something undeclared, or does not fit. */
|
|
191
|
+
export function outboxIssues(m, index) {
|
|
192
|
+
const out = [];
|
|
193
|
+
const templates = new Set();
|
|
194
|
+
(m.emailTemplates ?? []).forEach((template, i) => {
|
|
195
|
+
if (!template.key.startsWith(`${m.key}-`)) {
|
|
196
|
+
out.push({ path: ['emailTemplates', i, 'key'], message: `an app's template key starts with "${m.key}-"` });
|
|
197
|
+
}
|
|
198
|
+
if (templates.has(template.key))
|
|
199
|
+
out.push({ path: ['emailTemplates', i, 'key'], message: `"${template.key}" is declared twice` });
|
|
200
|
+
templates.add(template.key);
|
|
201
|
+
});
|
|
202
|
+
const box = m.outbox;
|
|
203
|
+
if (box === undefined) {
|
|
204
|
+
if (templates.size > 0)
|
|
205
|
+
out.push({ path: ['emailTemplates'], message: 'templates are sent through an outbox, and this app declares none' });
|
|
206
|
+
return out;
|
|
207
|
+
}
|
|
208
|
+
const at = (...rest) => ['outbox', ...rest];
|
|
209
|
+
if (index.table(box.table) === undefined) {
|
|
210
|
+
out.push({ path: at('table'), message: `"${box.table}" is not a table of this app` });
|
|
211
|
+
return out;
|
|
212
|
+
}
|
|
213
|
+
const col = (table, ref, types, path, what) => {
|
|
214
|
+
if (index.table(table) === undefined) {
|
|
215
|
+
out.push({ path, message: `"${table}" is not a table of this app` });
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
const found = index.column(table, ref);
|
|
219
|
+
if (found === undefined)
|
|
220
|
+
out.push({ path, message: `"${table}" has no column "${ref}"` });
|
|
221
|
+
else if (types !== null && !types.includes(found.type))
|
|
222
|
+
out.push({ path, message: `"${table}.${ref}" must be ${what}` });
|
|
223
|
+
else
|
|
224
|
+
return found;
|
|
225
|
+
return undefined;
|
|
226
|
+
};
|
|
227
|
+
const fk = (table, ref, target, path) => {
|
|
228
|
+
const found = col(table, ref, ['fk'], path, 'a foreign key');
|
|
229
|
+
if (found !== undefined && target !== undefined && found.references !== target) {
|
|
230
|
+
out.push({ path, message: `"${table}.${ref}" does not point at "${target}"` });
|
|
231
|
+
}
|
|
232
|
+
if (found !== undefined && found.nullable !== true && table === box.table) {
|
|
233
|
+
out.push({ path, message: `"${table}.${ref}" must be nullable: not every email is about one` });
|
|
234
|
+
}
|
|
235
|
+
return found;
|
|
236
|
+
};
|
|
237
|
+
const condition = (table, cond, path) => {
|
|
238
|
+
if (cond === undefined)
|
|
239
|
+
return;
|
|
240
|
+
const found = col(table, cond.column, null, [...path, 'column'], '');
|
|
241
|
+
const values = cond.eq !== undefined ? [cond.eq] : (cond.in ?? []);
|
|
242
|
+
if (found !== undefined)
|
|
243
|
+
for (const value of values) {
|
|
244
|
+
if (!valueFits(found, value))
|
|
245
|
+
out.push({ path, message: `${JSON.stringify(value)} is not a value of "${table}.${cond.column}"` });
|
|
246
|
+
}
|
|
247
|
+
if (found !== undefined && cond.isNull !== undefined && found.nullable !== true) {
|
|
248
|
+
out.push({ path, message: `"${table}.${cond.column}" is never empty` });
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const kind = col(box.table, box.columns.kind, ['enum'], at('columns', 'kind'), 'an enum of the kinds');
|
|
252
|
+
const status = col(box.table, box.columns.status, ['enum'], at('columns', 'status'), `an enum of ${OUTBOX_STATUSES.join(', ')}`);
|
|
253
|
+
if (status !== undefined) {
|
|
254
|
+
const missing = OUTBOX_STATUSES.filter((value) => !(status.enum ?? []).includes(value));
|
|
255
|
+
if (missing.length > 0)
|
|
256
|
+
out.push({ path: at('columns', 'status'), message: `"${box.table}.${status.ref}" lacks ${missing.join(', ')}` });
|
|
257
|
+
}
|
|
258
|
+
col(box.table, box.columns.to, ['text'], at('columns', 'to'), 'a text column');
|
|
259
|
+
if (box.columns.language !== undefined)
|
|
260
|
+
col(box.table, box.columns.language, ['text'], at('columns', 'language'), 'a text column');
|
|
261
|
+
if (box.columns.due !== undefined)
|
|
262
|
+
col(box.table, box.columns.due, ['timestamptz'], at('columns', 'due'), 'a timestamptz');
|
|
263
|
+
if (box.columns.sentAt !== undefined)
|
|
264
|
+
col(box.table, box.columns.sentAt, ['timestamptz'], at('columns', 'sentAt'), 'a timestamptz');
|
|
265
|
+
if (box.columns.error !== undefined)
|
|
266
|
+
col(box.table, box.columns.error, ['text'], at('columns', 'error'), 'a text column');
|
|
267
|
+
const linkTargets = new Map();
|
|
268
|
+
for (const [name, ref] of Object.entries(box.links ?? {})) {
|
|
269
|
+
linkTargets.set(ref, fk(box.table, ref, undefined, at('links', name))?.references);
|
|
270
|
+
}
|
|
271
|
+
const r = box.recipient;
|
|
272
|
+
fk(box.table, r.via, r.table, at('recipient', 'via'));
|
|
273
|
+
col(r.table, r.email, ['text'], at('recipient', 'email'), 'a text column');
|
|
274
|
+
if (r.name !== undefined)
|
|
275
|
+
col(r.table, r.name, ['text'], at('recipient', 'name'), 'a text column');
|
|
276
|
+
if (r.language !== undefined)
|
|
277
|
+
col(r.table, r.language, ['text'], at('recipient', 'language'), 'a text column');
|
|
278
|
+
if (r.optIn !== undefined)
|
|
279
|
+
col(r.table, r.optIn, ['bool'], at('recipient', 'optIn'), 'a bool');
|
|
280
|
+
if (r.fallback !== undefined) {
|
|
281
|
+
const via = fk(box.table, r.fallback.via, undefined, at('recipient', 'fallback', 'via'));
|
|
282
|
+
const holder = via?.references;
|
|
283
|
+
if (holder !== undefined) {
|
|
284
|
+
col(holder, r.fallback.email, ['text'], at('recipient', 'fallback', 'email'), 'a text column');
|
|
285
|
+
if (r.fallback.name !== undefined)
|
|
286
|
+
col(holder, r.fallback.name, ['text'], at('recipient', 'fallback', 'name'), 'a text column');
|
|
287
|
+
if (r.fallback.language !== undefined)
|
|
288
|
+
col(holder, r.fallback.language, ['text'], at('recipient', 'fallback', 'language'), 'a text column');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (box.settings !== undefined && index.table(box.settings.table) === undefined) {
|
|
292
|
+
out.push({ path: at('settings', 'table'), message: `"${box.settings.table}" is not a table of this app` });
|
|
293
|
+
}
|
|
294
|
+
else if (box.settings !== undefined) {
|
|
295
|
+
if (box.settings.enabled !== undefined)
|
|
296
|
+
col(box.settings.table, box.settings.enabled, ['bool'], at('settings', 'enabled'), 'a bool');
|
|
297
|
+
if (box.settings.name !== undefined)
|
|
298
|
+
col(box.settings.table, box.settings.name, ['text'], at('settings', 'name'), 'a text column');
|
|
299
|
+
if (box.settings.phone !== undefined)
|
|
300
|
+
col(box.settings.table, box.settings.phone, ['text'], at('settings', 'phone'), 'a text column');
|
|
301
|
+
}
|
|
302
|
+
for (const [value, template] of Object.entries(box.kinds)) {
|
|
303
|
+
if (kind !== undefined && !(kind.enum ?? []).includes(value)) {
|
|
304
|
+
out.push({ path: at('kinds', value), message: `"${value}" is not a value of "${box.table}.${kind.ref}"` });
|
|
305
|
+
}
|
|
306
|
+
if (!templates.has(template))
|
|
307
|
+
out.push({ path: at('kinds', value), message: `"${template}" is not one of the app's emailTemplates` });
|
|
308
|
+
}
|
|
309
|
+
(box.producers ?? []).forEach((producer, p) => {
|
|
310
|
+
const here = (...rest) => at('producers', p, ...rest);
|
|
311
|
+
if (box.kinds[producer.kind] === undefined)
|
|
312
|
+
out.push({ path: here('kind'), message: `"${producer.kind}" is not one of the outbox's kinds` });
|
|
313
|
+
if (producer.gate === 'enabled' && box.settings?.enabled === undefined) {
|
|
314
|
+
out.push({ path: here('gate'), message: 'the outbox names no settings column to be gated by' });
|
|
315
|
+
}
|
|
316
|
+
if (producer.optIn === true && r.optIn === undefined) {
|
|
317
|
+
out.push({ path: here('optIn'), message: 'the recipient names no opt-in column' });
|
|
318
|
+
}
|
|
319
|
+
const source = 'onCreate' in producer ? producer.onCreate : 'onChange' in producer ? producer.onChange : producer.before;
|
|
320
|
+
if (index.table(source.table) === undefined) {
|
|
321
|
+
out.push({ path: here(), message: `"${source.table}" is not a table of this app` });
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (!linkTargets.has(producer.link)) {
|
|
325
|
+
out.push({ path: here('link'), message: `"${producer.link}" is not one of the outbox's links` });
|
|
326
|
+
}
|
|
327
|
+
else if (linkTargets.get(producer.link) !== undefined && linkTargets.get(producer.link) !== source.table) {
|
|
328
|
+
out.push({ path: here('link'), message: `"${box.table}.${producer.link}" does not point at "${source.table}"` });
|
|
329
|
+
}
|
|
330
|
+
condition(source.table, source.where, here('where'));
|
|
331
|
+
if ('onChange' in producer) {
|
|
332
|
+
const change = producer.onChange;
|
|
333
|
+
const watched = col(change.table, change.column, null, here('onChange', 'column'), '');
|
|
334
|
+
if (watched !== undefined)
|
|
335
|
+
for (const value of Array.isArray(change.to) ? change.to : [change.to]) {
|
|
336
|
+
if (!valueFits(watched, value))
|
|
337
|
+
out.push({ path: here('onChange', 'to'), message: `${JSON.stringify(value)} is not a value of "${change.table}.${change.column}"` });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if ('before' in producer) {
|
|
341
|
+
const before = producer.before;
|
|
342
|
+
col(before.table, before.at, ['timestamptz'], here('before', 'at'), 'a timestamptz');
|
|
343
|
+
fk(before.table, before.lead.via, before.lead.table, here('before', 'lead', 'via'));
|
|
344
|
+
col(before.lead.table, before.lead.column, ['int', 'bigint'], here('before', 'lead', 'column'), 'an int');
|
|
345
|
+
if (before.lead.fallback !== undefined) {
|
|
346
|
+
col(before.lead.fallback.table, before.lead.fallback.column, ['int', 'bigint'], here('before', 'lead', 'fallback'), 'an int');
|
|
347
|
+
}
|
|
348
|
+
if (box.columns.due === undefined) {
|
|
349
|
+
out.push({ path: here('before'), message: 'a reminder records the moment it leads in the outbox\'s due column, and none is named' });
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
return out;
|
|
354
|
+
}
|
|
355
|
+
//# sourceMappingURL=outbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbox.js","sourceRoot":"","sources":["../src/outbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A calendar page's columns: `config.calendar` on a `page-calendar` page.
|
|
3
|
+
*
|
|
4
|
+
* Left to itself Adminium plots a calendar by the first date of the table it
|
|
5
|
+
* reads and titles it with the table's display column — on a table of
|
|
6
|
+
* appointments that also keeps a first visit's date of birth, every visit
|
|
7
|
+
* landed on a birthday. An app says which columns instead:
|
|
8
|
+
*
|
|
9
|
+
* ```json
|
|
10
|
+
* "config": { "calendar": { "start": "starts_at", "title": "patient_id.name", "category": "visit_type_id" } }
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* - `start` (required) and `end`: a `date` or `timestamptz` column of the
|
|
14
|
+
* page's table;
|
|
15
|
+
* - `title`: a column of the page's table, or `<fk column>.<column>` — a
|
|
16
|
+
* column of the table that foreign key points at (the patient's name);
|
|
17
|
+
* - `category`: a column of the page's table, what the rows are coloured and
|
|
18
|
+
* filtered by.
|
|
19
|
+
*
|
|
20
|
+
* Every name is the app's own (a column ref), checked here against
|
|
21
|
+
* `requiredSchema`, so an app's CI refuses a typo long before an install.
|
|
22
|
+
* Without it, a table with a booking rule is plotted by the booking's `start`.
|
|
23
|
+
*/
|
|
24
|
+
import { z } from 'zod';
|
|
25
|
+
import { type ColumnShape, type ReferenceIssue, type TableIndex } from './refs.js';
|
|
26
|
+
export declare const pageCalendarSchema: z.ZodObject<{
|
|
27
|
+
start: z.ZodString;
|
|
28
|
+
end: z.ZodOptional<z.ZodString>;
|
|
29
|
+
title: z.ZodOptional<z.ZodString>;
|
|
30
|
+
category: z.ZodOptional<z.ZodString>;
|
|
31
|
+
}, z.core.$strict>;
|
|
32
|
+
export type PageCalendar = z.infer<typeof pageCalendarSchema>;
|
|
33
|
+
/** What the check reads of a page. */
|
|
34
|
+
interface PageShape {
|
|
35
|
+
template: string;
|
|
36
|
+
bindings?: Readonly<Record<string, string>> | undefined;
|
|
37
|
+
config?: Readonly<Record<string, unknown>> | undefined;
|
|
38
|
+
}
|
|
39
|
+
/** Every problem with the pages' `config.calendar`, against the app's own tables. */
|
|
40
|
+
export declare function pageCalendarIssues<C extends ColumnShape>(pages: readonly PageShape[], index: TableIndex<C>): ReferenceIssue[];
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=page-calendar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-calendar.d.ts","sourceRoot":"","sources":["../src/page-calendar.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAa,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAK9F,eAAO,MAAM,kBAAkB;;;;;kBAOpB,CAAC;AACZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,sCAAsC;AACtC,UAAU,SAAS;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IACxD,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CACxD;AAQD,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,cAAc,EAAE,CA0C7H"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
/**
|
|
3
|
+
* A calendar page's columns: `config.calendar` on a `page-calendar` page.
|
|
4
|
+
*
|
|
5
|
+
* Left to itself Adminium plots a calendar by the first date of the table it
|
|
6
|
+
* reads and titles it with the table's display column — on a table of
|
|
7
|
+
* appointments that also keeps a first visit's date of birth, every visit
|
|
8
|
+
* landed on a birthday. An app says which columns instead:
|
|
9
|
+
*
|
|
10
|
+
* ```json
|
|
11
|
+
* "config": { "calendar": { "start": "starts_at", "title": "patient_id.name", "category": "visit_type_id" } }
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* - `start` (required) and `end`: a `date` or `timestamptz` column of the
|
|
15
|
+
* page's table;
|
|
16
|
+
* - `title`: a column of the page's table, or `<fk column>.<column>` — a
|
|
17
|
+
* column of the table that foreign key points at (the patient's name);
|
|
18
|
+
* - `category`: a column of the page's table, what the rows are coloured and
|
|
19
|
+
* filtered by.
|
|
20
|
+
*
|
|
21
|
+
* Every name is the app's own (a column ref), checked here against
|
|
22
|
+
* `requiredSchema`, so an app's CI refuses a typo long before an install.
|
|
23
|
+
* Without it, a table with a booking rule is plotted by the booking's `start`.
|
|
24
|
+
*/
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
import { refSchema } from './refs.js';
|
|
27
|
+
/** `patient_id.name`: a column of the table a foreign key points at. */
|
|
28
|
+
const titleSchema = z.string().regex(/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)?$/, 'a column, or <fk column>.<column>');
|
|
29
|
+
export const pageCalendarSchema = z
|
|
30
|
+
.object({
|
|
31
|
+
start: refSchema,
|
|
32
|
+
end: refSchema.optional(),
|
|
33
|
+
title: titleSchema.optional(),
|
|
34
|
+
category: refSchema.optional(),
|
|
35
|
+
})
|
|
36
|
+
.strict();
|
|
37
|
+
const DATE_TYPES = ['date', 'timestamptz'];
|
|
38
|
+
/** The table a page reads: its one binding, or the one keyed `rows`. */
|
|
39
|
+
function pageTable(page) {
|
|
40
|
+
const entries = Object.values(page.bindings ?? {});
|
|
41
|
+
return entries.length === 1 ? entries[0] : page.bindings?.['rows'];
|
|
42
|
+
}
|
|
43
|
+
/** Every problem with the pages' `config.calendar`, against the app's own tables. */
|
|
44
|
+
export function pageCalendarIssues(pages, index) {
|
|
45
|
+
const out = [];
|
|
46
|
+
pages.forEach((page, p) => {
|
|
47
|
+
const raw = page.config?.['calendar'];
|
|
48
|
+
if (raw === undefined)
|
|
49
|
+
return;
|
|
50
|
+
const at = (...rest) => ['pages', p, 'config', 'calendar', ...rest];
|
|
51
|
+
const parsed = pageCalendarSchema.safeParse(raw);
|
|
52
|
+
if (!parsed.success) {
|
|
53
|
+
for (const issue of parsed.error.issues)
|
|
54
|
+
out.push({ path: at(...issue.path.map((key) => (typeof key === 'symbol' ? String(key) : key))), message: issue.message });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (page.template !== 'page-calendar') {
|
|
58
|
+
out.push({ path: at(), message: `only a page-calendar plots by named columns, not a ${page.template}` });
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const table = pageTable(page);
|
|
62
|
+
if (table === undefined || index.table(table) === undefined) {
|
|
63
|
+
out.push({ path: at(), message: 'a calendar names its columns on a page bound to a table of the app' });
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const calendar = parsed.data;
|
|
67
|
+
for (const key of ['start', 'end']) {
|
|
68
|
+
const name = calendar[key];
|
|
69
|
+
if (name === undefined)
|
|
70
|
+
continue;
|
|
71
|
+
const column = index.column(table, name);
|
|
72
|
+
if (column === undefined)
|
|
73
|
+
out.push({ path: at(key), message: `"${table}" has no column "${name}"` });
|
|
74
|
+
else if (!DATE_TYPES.includes(column.type))
|
|
75
|
+
out.push({ path: at(key), message: `"${table}.${name}" is not a date or a timestamptz` });
|
|
76
|
+
}
|
|
77
|
+
if (calendar.category !== undefined && !index.has(table, calendar.category)) {
|
|
78
|
+
out.push({ path: at('category'), message: `"${table}" has no column "${calendar.category}"` });
|
|
79
|
+
}
|
|
80
|
+
if (calendar.title !== undefined) {
|
|
81
|
+
const [own, through] = calendar.title.split('.');
|
|
82
|
+
const column = index.column(table, own);
|
|
83
|
+
if (column === undefined)
|
|
84
|
+
out.push({ path: at('title'), message: `"${table}" has no column "${own}"` });
|
|
85
|
+
else if (through !== undefined) {
|
|
86
|
+
if (column.type !== 'fk' || column.references === undefined)
|
|
87
|
+
out.push({ path: at('title'), message: `"${table}.${own}" is not a foreign key` });
|
|
88
|
+
else if (!index.has(column.references, through))
|
|
89
|
+
out.push({ path: at('title'), message: `"${column.references}" has no column "${through}"` });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=page-calendar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-calendar.js","sourceRoot":"","sources":["../src/page-calendar.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,SAAS,EAA0D,MAAM,WAAW,CAAC;AAE9F,wEAAwE;AACxE,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,uCAAuC,EAAE,mCAAmC,CAAC,CAAC;AAEnH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC;KAChC,MAAM,CAAC;IACN,KAAK,EAAE,SAAS;IAChB,GAAG,EAAE,SAAS,CAAC,QAAQ,EAAE;IACzB,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE;IAC7B,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAAE;CAC/B,CAAC;KACD,MAAM,EAAE,CAAC;AAGZ,MAAM,UAAU,GAAsB,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAS9D,wEAAwE;AACxE,SAAS,SAAS,CAAC,IAAe;IAChC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IACnD,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;AACrE,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,kBAAkB,CAAwB,KAA2B,EAAE,KAAoB;IACzG,MAAM,GAAG,GAAqB,EAAE,CAAC;IACjC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,CAAC;QACtC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO;QAC9B,MAAM,EAAE,GAAG,CAAC,GAAG,IAAyB,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC;QACzF,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACjD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACnK,OAAO;QACT,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,KAAK,eAAe,EAAE,CAAC;YACtC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,sDAAsD,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YACzG,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,SAAS,EAAE,CAAC;YAC5D,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,oEAAoE,EAAE,CAAC,CAAC;YACxG,OAAO;QACT,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;QAC7B,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAU,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC3B,IAAI,IAAI,KAAK,SAAS;gBAAE,SAAS;YACjC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACzC,IAAI,MAAM,KAAK,SAAS;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,KAAK,oBAAoB,IAAI,GAAG,EAAE,CAAC,CAAC;iBAChG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,KAAK,IAAI,IAAI,kCAAkC,EAAE,CAAC,CAAC;QACxI,CAAC;QACD,IAAI,QAAQ,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5E,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,KAAK,oBAAoB,QAAQ,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC;QACjG,CAAC;QACD,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAiC,CAAC;YACjF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACxC,IAAI,MAAM,KAAK,SAAS;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,KAAK,oBAAoB,GAAG,GAAG,EAAE,CAAC,CAAC;iBACnG,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC/B,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS;oBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,KAAK,IAAI,GAAG,wBAAwB,EAAE,CAAC,CAAC;qBAC3I,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC;oBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,MAAM,CAAC,UAAU,oBAAoB,OAAO,GAAG,EAAE,CAAC,CAAC;YACjJ,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planning an APP install with what the server knows about this connection:
|
|
3
|
+
* the app's prefix, the tables it already recorded here, what other apps
|
|
4
|
+
* record here, and the operator's answers for the tables whose names are taken.
|
|
5
|
+
*
|
|
6
|
+
* ─── Why a context at all ───────────────────────────────────────────────────
|
|
7
|
+
*
|
|
8
|
+
* Without one, a table either exists (reuse) or does not (create), and that
|
|
9
|
+
* was the whole plan. It could not tell the app's own table from an earlier
|
|
10
|
+
* install apart from another app's table of the same name, could not offer
|
|
11
|
+
* to rename a stranger's table out of the way, and could not give an app its
|
|
12
|
+
* own prefix. Each table is now CLASSIFIED first, then given an ACTION:
|
|
13
|
+
*
|
|
14
|
+
* new the real name is free → create
|
|
15
|
+
* own-leftover this app recorded it (an earlier install) → reuse (default)
|
|
16
|
+
* shared another app recorded it under the SAME shape (`menu@1`)
|
|
17
|
+
* → share (default)
|
|
18
|
+
* taken it exists and nothing records it as this app's
|
|
19
|
+
* → the operator chooses
|
|
20
|
+
*
|
|
21
|
+
* For a taken table the operator chooses: REUSE it (offered only when it is
|
|
22
|
+
* not another app's in disguise and every change it needs is safe), RENAME the
|
|
23
|
+
* existing table out of the way (only when no other install records it), or
|
|
24
|
+
* give the whole app a DIFFERENT PREFIX (always offered, and it applies to
|
|
25
|
+
* every table at once). Until each taken table has an answer, the plan is not
|
|
26
|
+
* installable and says which table is waiting.
|
|
27
|
+
*
|
|
28
|
+
* ─── Edits ─────────────────────────────────────────────────────────────────
|
|
29
|
+
*
|
|
30
|
+
* A reused table may need changes before the app can write to it. Only changes
|
|
31
|
+
* that cannot lose data are ever offered: adding a missing column (nullable),
|
|
32
|
+
* widening a type along a fixed list (a longer varchar, varchar to text, int
|
|
33
|
+
* to bigint, a wider enum column), giving an int key the identity it lacks, and
|
|
34
|
+
* adding enum values. Anything else is refused on this screen, by name.
|
|
35
|
+
*
|
|
36
|
+
* Pure, like the planner it extends: no I/O. The server gathers the context.
|
|
37
|
+
*/
|
|
38
|
+
import type { InstallPlan, PlanContext, SchemaModelView } from './plan-model.js';
|
|
39
|
+
import type { Manifest } from './schema.js';
|
|
40
|
+
export type { ContextTableAction as TableAction, InstallTablePlan, PlanContext, PlanEdit, TableChoice, TableClass, TableOffer, } from './plan-model.js';
|
|
41
|
+
/** The longest identifier each engine accepts, in bytes. SQLite has none; the portable 63 holds. */
|
|
42
|
+
export declare const IDENTIFIER_LIMIT: Readonly<Record<PlanContext['dialect'], number>>;
|
|
43
|
+
/** `adminium_roles.slug` is 40 characters. */
|
|
44
|
+
export declare const ROLE_SLUG_LIMIT = 40;
|
|
45
|
+
/**
|
|
46
|
+
* The context half of `planInstall`. Called by it when a context is given;
|
|
47
|
+
* the returned plan keeps every field older callers read (`create`, `reuse`,
|
|
48
|
+
* `references`, `problems`) and adds `tables` and `names`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function planWithContext(manifest: Manifest, model: SchemaModelView, context: PlanContext): InstallPlan;
|
|
51
|
+
//# sourceMappingURL=plan-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-context.d.ts","sourceRoot":"","sources":["../src/plan-context.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAEV,WAAW,EAEX,WAAW,EAEX,eAAe,EAEhB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,QAAQ,EAAiC,MAAM,aAAa,CAAC;AAE3E,YAAY,EACV,kBAAkB,IAAI,WAAW,EACjC,gBAAgB,EAChB,WAAW,EACX,QAAQ,EACR,WAAW,EACX,UAAU,EACV,UAAU,GACX,MAAM,iBAAiB,CAAC;AAGzB,oGAAoG;AACpG,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,CAI7E,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,eAAe,KAAK,CAAC;AAuDlC;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,WAAW,GACnB,WAAW,CA0Qb"}
|