@adminiumjs/manifest 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +1253 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +439 -0
- package/dist/schema.js.map +1 -0
- package/dist/validate.d.ts +45 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +56 -0
- package/dist/validate.js.map +1 -0
- package/package.json +5 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest spec v1 (13-marketplace.md §2), frozen at `manifestVersion: 1` for
|
|
3
|
+
* all of Adminium 1.x. Pure Zod v4 + types — no `node:` imports — so the
|
|
4
|
+
* storefront and the Electron shell can validate a manifest in the browser
|
|
5
|
+
* (01-architecture.md §3, the `@adminium/manifest` package row).
|
|
6
|
+
*
|
|
7
|
+
* This module is the envelope: every block's shape and the cross-block rules.
|
|
8
|
+
* The install PLANNER (planInstall / requiredSchema → create-or-map diff) and
|
|
9
|
+
* the server-side installer are later layers that consume a validated manifest.
|
|
10
|
+
*/
|
|
11
|
+
import { addOnBlockSchema, addOnCategorySchema, isSlotId, } from '@adminium/add-on-contracts';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
/** Integer spec version, frozen at 1 for Adminium 1.x (§2, 01 §8). */
|
|
14
|
+
export const MANIFEST_VERSION = 1;
|
|
15
|
+
/**
|
|
16
|
+
* What kind of thing this manifest describes (24 §5.2). OPTIONAL, defaulting to
|
|
17
|
+
* `"app"` — which is the whole reason `manifestVersion` does not move: every
|
|
18
|
+
* manifest written before wave 4 stays valid unchanged, and an additive
|
|
19
|
+
* optional field with a back-compatible default is how a frozen spec grows
|
|
20
|
+
* without lying about its version.
|
|
21
|
+
*/
|
|
22
|
+
export const MANIFEST_KINDS = ['app', 'add-on'];
|
|
23
|
+
export const manifestKindSchema = z.enum(MANIFEST_KINDS);
|
|
24
|
+
/** strict semver — `major.minor.patch` with optional pre-release/build. */
|
|
25
|
+
const SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
26
|
+
const semver = z.string().regex(SEMVER, 'must be strict semver (major.minor.patch)');
|
|
27
|
+
/** An i18n message: a catalog key plus the English fallback rendered if absent. */
|
|
28
|
+
export const i18nMessageSchema = z
|
|
29
|
+
.object({
|
|
30
|
+
key: z.string().min(1).max(120),
|
|
31
|
+
fallback: z.string().min(1).max(400),
|
|
32
|
+
})
|
|
33
|
+
.strict();
|
|
34
|
+
// ── §2.3 identity ────────────────────────────────────────────────────────────
|
|
35
|
+
/** Closed v1 storefront facet set (§2.3). */
|
|
36
|
+
export const MANIFEST_CATEGORIES = [
|
|
37
|
+
'commerce',
|
|
38
|
+
'hospitality',
|
|
39
|
+
'operations',
|
|
40
|
+
'crm',
|
|
41
|
+
'internal-tools',
|
|
42
|
+
];
|
|
43
|
+
export const categorySchema = z.enum(MANIFEST_CATEGORIES);
|
|
44
|
+
/** The one publisher id v1 accepts unless `third-party-publishers` is on (§2.3/§9). */
|
|
45
|
+
export const FIRST_PARTY_PUBLISHER_ID = 'adminium';
|
|
46
|
+
export const publisherSchema = z
|
|
47
|
+
.object({
|
|
48
|
+
id: z.string().regex(/^[a-z][a-z0-9-]{1,39}$/, 'publisher id must be ^[a-z][a-z0-9-]{1,39}$'),
|
|
49
|
+
name: z.string().min(1).max(80),
|
|
50
|
+
url: z.url().max(200).optional(),
|
|
51
|
+
})
|
|
52
|
+
.strict();
|
|
53
|
+
/**
|
|
54
|
+
* Everything both kinds share. `categories` is deliberately NOT here: it splits
|
|
55
|
+
* by kind (an add-on is not a vertical — D2), so each branch adds its own.
|
|
56
|
+
*/
|
|
57
|
+
export const identityShape = {
|
|
58
|
+
key: z.string().regex(/^[a-z][a-z0-9-]{1,79}$/, 'key must be ^[a-z][a-z0-9-]{1,79}$'),
|
|
59
|
+
name: z.string().min(1).max(80),
|
|
60
|
+
version: semver,
|
|
61
|
+
publisher: publisherSchema,
|
|
62
|
+
// SPDX id — the FRONTEND's license (informational; core is AGPL-3.0).
|
|
63
|
+
license: z.string().min(1).max(80),
|
|
64
|
+
description: i18nMessageSchema,
|
|
65
|
+
};
|
|
66
|
+
export const identitySchema = z
|
|
67
|
+
.object({
|
|
68
|
+
...identityShape,
|
|
69
|
+
categories: z.array(categorySchema).min(1),
|
|
70
|
+
})
|
|
71
|
+
.strict();
|
|
72
|
+
/**
|
|
73
|
+
* Keys no app or add-on may ever take, because they would shadow a storefront
|
|
74
|
+
* route or a data file (D17). Apps and add-ons share one key namespace.
|
|
75
|
+
*/
|
|
76
|
+
export const RESERVED_KEYS = ['apps', 'add-on', 'add-ons', 'demo', 'index', 'search'];
|
|
77
|
+
// ── §2.11 capabilities ───────────────────────────────────────────────────────
|
|
78
|
+
export const MANIFEST_CAPABILITIES = [
|
|
79
|
+
'hosted-only',
|
|
80
|
+
'offline-required',
|
|
81
|
+
'receipt-printer',
|
|
82
|
+
'barcode-scanner',
|
|
83
|
+
'payments',
|
|
84
|
+
'file-storage',
|
|
85
|
+
'email-delivery',
|
|
86
|
+
'realtime',
|
|
87
|
+
// Added by wave 4 (24 D3). Adding a capability key is a THREE-place change
|
|
88
|
+
// and all three land together: here, `CAP_ICONS` in the website's
|
|
89
|
+
// marketplace data (note `CAP_META` derives from it), and a
|
|
90
|
+
// `marketplaceData.cap.<key>` label in all eight locales.
|
|
91
|
+
/** The add-on's server code calls a third-party API. */
|
|
92
|
+
'outbound-http',
|
|
93
|
+
/** The host runs an OAuth 2.0 authorization-code flow on the add-on's behalf. */
|
|
94
|
+
'oauth-connect',
|
|
95
|
+
];
|
|
96
|
+
export const capabilitySchema = z.enum(MANIFEST_CAPABILITIES);
|
|
97
|
+
// ── §2.4 compatibility ───────────────────────────────────────────────────────
|
|
98
|
+
export const compatibilitySchema = z
|
|
99
|
+
.object({
|
|
100
|
+
minAdminiumVersion: semver,
|
|
101
|
+
maxAdminiumVersion: semver.optional(), // exclusive upper bound
|
|
102
|
+
requires: z.array(capabilitySchema).optional(),
|
|
103
|
+
})
|
|
104
|
+
.strict();
|
|
105
|
+
// ── §2.5 requiredSchema (create-or-map) ──────────────────────────────────────
|
|
106
|
+
/** Abstract column types the introspection engine emits (§2.5, research §15.2). */
|
|
107
|
+
export const COLUMN_TYPES = [
|
|
108
|
+
'id',
|
|
109
|
+
'text',
|
|
110
|
+
'int',
|
|
111
|
+
'bigint',
|
|
112
|
+
'decimal',
|
|
113
|
+
'money',
|
|
114
|
+
'float',
|
|
115
|
+
'bool',
|
|
116
|
+
'enum',
|
|
117
|
+
'json',
|
|
118
|
+
'date',
|
|
119
|
+
'timestamptz',
|
|
120
|
+
'uuid',
|
|
121
|
+
'fk',
|
|
122
|
+
'blob',
|
|
123
|
+
];
|
|
124
|
+
/** Optional semantic pre-seed so widgets auto-instantiate (§2.5). */
|
|
125
|
+
export const COLUMN_SEMANTICS = [
|
|
126
|
+
'name',
|
|
127
|
+
'money',
|
|
128
|
+
'image',
|
|
129
|
+
'email',
|
|
130
|
+
'avatar',
|
|
131
|
+
'geo-lat',
|
|
132
|
+
'geo-lng',
|
|
133
|
+
];
|
|
134
|
+
/** Structural role markers (§2.5). */
|
|
135
|
+
export const COLUMN_ROLES = ['pk', 'created_at', 'updated_at'];
|
|
136
|
+
export const requiredColumnSchema = z
|
|
137
|
+
.object({
|
|
138
|
+
ref: z.string().regex(/^[a-z][a-z0-9_]*$/, 'column ref must be a snake_case identifier'),
|
|
139
|
+
type: z.enum(COLUMN_TYPES),
|
|
140
|
+
semantic: z.enum(COLUMN_SEMANTICS).optional(),
|
|
141
|
+
role: z.enum(COLUMN_ROLES).optional(),
|
|
142
|
+
nullable: z.boolean().optional(),
|
|
143
|
+
// enum values when `type: 'enum'`; fk target ref when `type: 'fk'`.
|
|
144
|
+
enum: z.array(z.string().min(1)).optional(),
|
|
145
|
+
references: z.string().optional(),
|
|
146
|
+
})
|
|
147
|
+
.strict()
|
|
148
|
+
.refine((c) => c.type !== 'enum' || (c.enum !== undefined && c.enum.length > 0), {
|
|
149
|
+
message: 'an enum column must list its enum values',
|
|
150
|
+
path: ['enum'],
|
|
151
|
+
})
|
|
152
|
+
.refine((c) => c.type !== 'fk' || c.references !== undefined, {
|
|
153
|
+
message: 'a fk column must name its references target',
|
|
154
|
+
path: ['references'],
|
|
155
|
+
});
|
|
156
|
+
export const requiredTableSchema = z
|
|
157
|
+
.object({
|
|
158
|
+
ref: z.string().regex(/^[a-z][a-z0-9_]*$/, 'table ref must be a snake_case identifier'),
|
|
159
|
+
columns: z.array(requiredColumnSchema).min(1),
|
|
160
|
+
})
|
|
161
|
+
.strict()
|
|
162
|
+
.refine((t) => new Set(t.columns.map((c) => c.ref)).size === t.columns.length, { message: 'duplicate column ref in table', path: ['columns'] });
|
|
163
|
+
export const requiredSchemaSchema = z
|
|
164
|
+
.object({
|
|
165
|
+
tables: z.array(requiredTableSchema).min(1),
|
|
166
|
+
})
|
|
167
|
+
.strict()
|
|
168
|
+
.refine((s) => new Set(s.tables.map((t) => t.ref)).size === s.tables.length, {
|
|
169
|
+
message: 'duplicate table ref in requiredSchema',
|
|
170
|
+
path: ['tables'],
|
|
171
|
+
});
|
|
172
|
+
// ── §2.6 pages ───────────────────────────────────────────────────────────────
|
|
173
|
+
export const pageNavSchema = z
|
|
174
|
+
.object({
|
|
175
|
+
group: z.string().min(1).max(80),
|
|
176
|
+
icon: z.string().min(1).max(60),
|
|
177
|
+
order: z.number().int(),
|
|
178
|
+
})
|
|
179
|
+
.strict();
|
|
180
|
+
export const pageSchema = z
|
|
181
|
+
.object({
|
|
182
|
+
ref: z.string().regex(/^[a-z][a-z0-9-]*$/, 'page ref must be a kebab-case identifier'),
|
|
183
|
+
template: z.string().min(1).max(80),
|
|
184
|
+
title: i18nMessageSchema,
|
|
185
|
+
nav: pageNavSchema,
|
|
186
|
+
// page-local table ref → requiredSchema table ref (resolved at install).
|
|
187
|
+
bindings: z.record(z.string(), z.string()).optional(),
|
|
188
|
+
config: z.record(z.string(), z.unknown()).optional(),
|
|
189
|
+
})
|
|
190
|
+
.strict();
|
|
191
|
+
// ── §2.7 roles ───────────────────────────────────────────────────────────────
|
|
192
|
+
export const roleSchema = z
|
|
193
|
+
.object({
|
|
194
|
+
key: z.string().regex(/^[a-z][a-z0-9-]*$/, 'role key must be a kebab-case identifier'),
|
|
195
|
+
name: z.string().min(1).max(80),
|
|
196
|
+
cloneFrom: z.string().optional(),
|
|
197
|
+
// grant strings validated against the RBAC grammar at install time.
|
|
198
|
+
permissions: z.array(z.string().min(1)).optional(),
|
|
199
|
+
})
|
|
200
|
+
.strict();
|
|
201
|
+
// ── §2.8 settings ────────────────────────────────────────────────────────────
|
|
202
|
+
const settingBase = {
|
|
203
|
+
key: z.string().regex(/^[a-z][a-z0-9_]*$/, 'setting key must be snake_case'),
|
|
204
|
+
required: z.boolean().optional(),
|
|
205
|
+
secret: z.boolean().optional(),
|
|
206
|
+
label: i18nMessageSchema.optional(),
|
|
207
|
+
};
|
|
208
|
+
export const settingSchema = z.discriminatedUnion('type', [
|
|
209
|
+
z.object({ ...settingBase, type: z.literal('string'), default: z.string().optional() }).strict(),
|
|
210
|
+
z
|
|
211
|
+
.object({
|
|
212
|
+
...settingBase,
|
|
213
|
+
type: z.literal('number'),
|
|
214
|
+
default: z.number().optional(),
|
|
215
|
+
min: z.number().optional(),
|
|
216
|
+
max: z.number().optional(),
|
|
217
|
+
unit: z.string().max(20).optional(),
|
|
218
|
+
})
|
|
219
|
+
.strict(),
|
|
220
|
+
z.object({ ...settingBase, type: z.literal('boolean'), default: z.boolean().optional() }).strict(),
|
|
221
|
+
z
|
|
222
|
+
.object({
|
|
223
|
+
...settingBase,
|
|
224
|
+
type: z.literal('enum'),
|
|
225
|
+
enum: z.array(z.string().min(1)).min(1),
|
|
226
|
+
default: z.string().optional(),
|
|
227
|
+
})
|
|
228
|
+
.strict(),
|
|
229
|
+
z
|
|
230
|
+
.object({
|
|
231
|
+
...settingBase,
|
|
232
|
+
type: z.literal('file'),
|
|
233
|
+
accept: z.array(z.string().min(1)).optional(),
|
|
234
|
+
})
|
|
235
|
+
.strict(),
|
|
236
|
+
z.object({ ...settingBase, type: z.literal('json'), default: z.unknown().optional() }).strict(),
|
|
237
|
+
]);
|
|
238
|
+
// ── §2.9 seeds ───────────────────────────────────────────────────────────────
|
|
239
|
+
export const seedSchema = z
|
|
240
|
+
.object({
|
|
241
|
+
table: z.string().min(1),
|
|
242
|
+
// inline rows, or a reference to a bundled seeds/<file> dataset (§2.9).
|
|
243
|
+
rows: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
244
|
+
file: z.string().min(1).optional(),
|
|
245
|
+
})
|
|
246
|
+
.strict()
|
|
247
|
+
.refine((s) => (s.rows === undefined) !== (s.file === undefined), {
|
|
248
|
+
message: 'a seed provides exactly one of `rows` or `file`',
|
|
249
|
+
});
|
|
250
|
+
// ── §2.10 widgets (optional custom bundles) ──────────────────────────────────
|
|
251
|
+
export const manifestWidgetSchema = z
|
|
252
|
+
.object({
|
|
253
|
+
id: z.string().min(1).max(80),
|
|
254
|
+
entry: z.string().min(1),
|
|
255
|
+
})
|
|
256
|
+
.strict();
|
|
257
|
+
// ── §2.12 frontend ───────────────────────────────────────────────────────────
|
|
258
|
+
export const FRONTEND_KINDS = ['spa', 'electron', 'none'];
|
|
259
|
+
export const frontendEnvVarSchema = z
|
|
260
|
+
.object({
|
|
261
|
+
required: z.boolean(),
|
|
262
|
+
example: z.string().optional(),
|
|
263
|
+
})
|
|
264
|
+
.strict();
|
|
265
|
+
export const frontendSchema = z
|
|
266
|
+
.object({
|
|
267
|
+
kind: z.enum(FRONTEND_KINDS),
|
|
268
|
+
entry: z.string().min(1).optional(),
|
|
269
|
+
env: z.record(z.string(), frontendEnvVarSchema).optional(),
|
|
270
|
+
})
|
|
271
|
+
.strict();
|
|
272
|
+
/** §2.11 — hosted-only and offline-required are mutually exclusive. */
|
|
273
|
+
const capabilitiesNotContradictory = (m) => !((m.capabilities?.includes('hosted-only') ?? false) &&
|
|
274
|
+
(m.capabilities?.includes('offline-required') ?? false));
|
|
275
|
+
/** maxAdminiumVersion (exclusive) must be strictly above the min. */
|
|
276
|
+
const compatibilityWindowOrdered = (m) => m.compatibility.maxAdminiumVersion === undefined ||
|
|
277
|
+
compareSemver(m.compatibility.maxAdminiumVersion, m.compatibility.minAdminiumVersion) > 0;
|
|
278
|
+
const CAPS_MESSAGE = {
|
|
279
|
+
message: 'hosted-only and offline-required are mutually exclusive',
|
|
280
|
+
path: ['capabilities'],
|
|
281
|
+
};
|
|
282
|
+
const WINDOW_MESSAGE = {
|
|
283
|
+
message: 'maxAdminiumVersion must be greater than minAdminiumVersion',
|
|
284
|
+
path: ['compatibility'],
|
|
285
|
+
};
|
|
286
|
+
export const appManifestSchema = z
|
|
287
|
+
.object({
|
|
288
|
+
kind: z.literal('app'),
|
|
289
|
+
manifestVersion: z.literal(MANIFEST_VERSION),
|
|
290
|
+
...identitySchema.shape,
|
|
291
|
+
compatibility: compatibilitySchema,
|
|
292
|
+
requiredSchema: requiredSchemaSchema,
|
|
293
|
+
pages: z.array(pageSchema).min(1),
|
|
294
|
+
roles: z.array(roleSchema).optional(),
|
|
295
|
+
settings: z.array(settingSchema).optional(),
|
|
296
|
+
seeds: z.array(seedSchema).optional(),
|
|
297
|
+
widgets: z.array(manifestWidgetSchema).optional(),
|
|
298
|
+
capabilities: z.array(capabilitySchema).optional(),
|
|
299
|
+
frontend: frontendSchema,
|
|
300
|
+
})
|
|
301
|
+
.strict()
|
|
302
|
+
.refine(capabilitiesNotContradictory, { ...CAPS_MESSAGE, path: [...CAPS_MESSAGE.path] })
|
|
303
|
+
.refine(compatibilityWindowOrdered, { ...WINDOW_MESSAGE, path: [...WINDOW_MESSAGE.path] });
|
|
304
|
+
/**
|
|
305
|
+
* `pages` and `frontend` are absent from this branch on purpose (24 §5.7 item
|
|
306
|
+
* 6): an add-on cannot install pages, roles or a frontend, and leaving the
|
|
307
|
+
* fields off the schema entirely is a stronger guarantee than a lint rule.
|
|
308
|
+
*/
|
|
309
|
+
export const addOnManifestSchema = z
|
|
310
|
+
.object({
|
|
311
|
+
kind: z.literal('add-on'),
|
|
312
|
+
manifestVersion: z.literal(MANIFEST_VERSION),
|
|
313
|
+
...identityShape,
|
|
314
|
+
categories: z.array(addOnCategorySchema).min(1),
|
|
315
|
+
compatibility: compatibilitySchema,
|
|
316
|
+
addOn: addOnBlockSchema,
|
|
317
|
+
// An add-on may bring its own tables — kept on disconnect (D16).
|
|
318
|
+
requiredSchema: requiredSchemaSchema.optional(),
|
|
319
|
+
settings: z.array(settingSchema).optional(),
|
|
320
|
+
capabilities: z.array(capabilitySchema).optional(),
|
|
321
|
+
widgets: z.array(manifestWidgetSchema).optional(),
|
|
322
|
+
})
|
|
323
|
+
.strict()
|
|
324
|
+
.refine(capabilitiesNotContradictory, { ...CAPS_MESSAGE, path: [...CAPS_MESSAGE.path] })
|
|
325
|
+
.refine(compatibilityWindowOrdered, { ...WINDOW_MESSAGE, path: [...WINDOW_MESSAGE.path] });
|
|
326
|
+
/**
|
|
327
|
+
* The envelope. A document with no `kind` is treated as an app before the union
|
|
328
|
+
* discriminates, which is what keeps every pre-wave-4 manifest valid.
|
|
329
|
+
*/
|
|
330
|
+
export const manifestSchema = z.preprocess((v) => typeof v === 'object' && v !== null && !Array.isArray(v) && v.kind === undefined
|
|
331
|
+
? { ...v, kind: 'app' }
|
|
332
|
+
: v, z.discriminatedUnion('kind', [appManifestSchema, addOnManifestSchema]));
|
|
333
|
+
/** Narrowing helper — the discriminant is the only thing worth branching on. */
|
|
334
|
+
export function isAddOnManifest(m) {
|
|
335
|
+
return m.kind === 'add-on';
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Cross-block rules the envelope cannot express, each with its issue code
|
|
339
|
+
* (24 §5.3). Runs only for `kind: "add-on"`; returns [] for an app.
|
|
340
|
+
*/
|
|
341
|
+
export function addOnIssues(m, ctx = {}) {
|
|
342
|
+
if (!isAddOnManifest(m))
|
|
343
|
+
return [];
|
|
344
|
+
const out = [];
|
|
345
|
+
const block = m.addOn;
|
|
346
|
+
// ATTACH_TARGET_UNKNOWN — every target is a known app key or "*".
|
|
347
|
+
if (ctx.knownAppKeys !== undefined) {
|
|
348
|
+
block.attaches.forEach((target, i) => {
|
|
349
|
+
if (target.app !== '*' && !ctx.knownAppKeys.includes(target.app)) {
|
|
350
|
+
out.push({
|
|
351
|
+
code: 'ATTACH_TARGET_UNKNOWN',
|
|
352
|
+
path: `addOn.attaches.${i}.app`,
|
|
353
|
+
message: `attaches to an unknown app key "${target.app}"`,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
// SLOT_UNKNOWN — belt and braces; the schema enum already refuses these.
|
|
359
|
+
(block.slots ?? []).forEach((fill, i) => {
|
|
360
|
+
if (!isSlotId(fill.slot)) {
|
|
361
|
+
out.push({
|
|
362
|
+
code: 'SLOT_UNKNOWN',
|
|
363
|
+
path: `addOn.slots.${i}.slot`,
|
|
364
|
+
message: `"${fill.slot}" is not in the closed slot registry`,
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
// SCOPE_OUT_OF_RANGE — a `records:<table>:<verb>` scope must name a table this
|
|
369
|
+
// add-on can actually reach: one of the host app's, or one of its own.
|
|
370
|
+
const reachable = new Set([
|
|
371
|
+
...(m.requiredSchema?.tables ?? []).map((t) => t.ref),
|
|
372
|
+
...(ctx.hostTables ?? []),
|
|
373
|
+
]);
|
|
374
|
+
(block.scopes ?? []).forEach((scope, i) => {
|
|
375
|
+
const [domain, table] = scope.split(':');
|
|
376
|
+
if (domain !== 'records')
|
|
377
|
+
return;
|
|
378
|
+
if (table === undefined || table.length === 0) {
|
|
379
|
+
out.push({
|
|
380
|
+
code: 'SCOPE_OUT_OF_RANGE',
|
|
381
|
+
path: `addOn.scopes.${i}`,
|
|
382
|
+
message: `"${scope}" names no table`,
|
|
383
|
+
});
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
if (ctx.hostTables !== undefined && !reachable.has(table)) {
|
|
387
|
+
out.push({
|
|
388
|
+
code: 'SCOPE_OUT_OF_RANGE',
|
|
389
|
+
path: `addOn.scopes.${i}`,
|
|
390
|
+
message: `"${scope}" reaches a table neither the host app nor this add-on declares`,
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
// NETWORK_ALLOW_REQUIRED — outbound-http without an allow-list is a hole.
|
|
395
|
+
const wantsHttp = m.capabilities?.includes('outbound-http') ?? false;
|
|
396
|
+
if (wantsHttp && (block.network?.allow.length ?? 0) === 0) {
|
|
397
|
+
out.push({
|
|
398
|
+
code: 'NETWORK_ALLOW_REQUIRED',
|
|
399
|
+
path: 'addOn.network.allow',
|
|
400
|
+
message: 'outbound-http requires a non-empty allow-list of exact https hostnames',
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
// CAPABILITY_CONFLICT — an oauth2 connect needs the capability that runs it.
|
|
404
|
+
if (block.connect.kind === 'oauth2' && !(m.capabilities?.includes('oauth-connect') ?? false)) {
|
|
405
|
+
out.push({
|
|
406
|
+
code: 'CAPABILITY_CONFLICT',
|
|
407
|
+
path: 'capabilities',
|
|
408
|
+
message: 'connect.kind "oauth2" requires the oauth-connect capability',
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
// FRONTEND_SECRET_LEAK — publicSettings may never name a secret setting.
|
|
412
|
+
const secrets = new Set((m.settings ?? []).filter((s) => s.secret === true).map((s) => s.key));
|
|
413
|
+
(block.publicSettings ?? []).forEach((key, i) => {
|
|
414
|
+
if (secrets.has(key)) {
|
|
415
|
+
out.push({
|
|
416
|
+
code: 'FRONTEND_SECRET_LEAK',
|
|
417
|
+
path: `addOn.publicSettings.${i}`,
|
|
418
|
+
message: `"${key}" is marked secret and must never reach the client bundle`,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
return out;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Numeric semver compare on the release triple (pre-release/build ignored —
|
|
426
|
+
* enough for the compatibility-window and upgrade ordering checks). Returns
|
|
427
|
+
* <0, 0, >0. Exported for the installer's upgrade rule (§4.3).
|
|
428
|
+
*/
|
|
429
|
+
export function compareSemver(a, b) {
|
|
430
|
+
const triple = (v) => v
|
|
431
|
+
.split('+')[0]
|
|
432
|
+
.split('-')[0]
|
|
433
|
+
.split('.')
|
|
434
|
+
.map((n) => Number.parseInt(n, 10));
|
|
435
|
+
const [a1 = 0, a2 = 0, a3 = 0] = triple(a);
|
|
436
|
+
const [b1 = 0, b2 = 0, b3 = 0] = triple(b);
|
|
437
|
+
return a1 - b1 || a2 - b2 || a3 - b3;
|
|
438
|
+
}
|
|
439
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest validation entry point (13-marketplace.md §2, §9). Layers the
|
|
3
|
+
* envelope schema with the v1 publisher policy: the installer rejects any
|
|
4
|
+
* `publisher.id` other than `adminium` unless the `third-party-publishers`
|
|
5
|
+
* feature flag is on (off in v1). Pure — safe in the browser storefront.
|
|
6
|
+
*/
|
|
7
|
+
import { type Manifest } from './schema.js';
|
|
8
|
+
export interface ManifestIssue {
|
|
9
|
+
/** Dotted path to the offending field, e.g. `publisher.id`. */
|
|
10
|
+
path: string;
|
|
11
|
+
message: string;
|
|
12
|
+
/** Issue code for the add-on rules (24 §5.3); absent for schema issues. */
|
|
13
|
+
code?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ValidateManifestOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Allow a non-`adminium` publisher. Wired to the `third-party-publishers`
|
|
18
|
+
* feature flag (§9); OFF in v1, so third-party manifests are rejected.
|
|
19
|
+
*
|
|
20
|
+
* For an add-on the gate matters MORE, not less: an add-on's server half runs
|
|
21
|
+
* in the host process with no sandbox (24 D13), so an unsandboxed in-process
|
|
22
|
+
* add-on from an unknown publisher would be remote code execution with a
|
|
23
|
+
* marketplace in front of it.
|
|
24
|
+
*/
|
|
25
|
+
allowThirdPartyPublishers?: boolean;
|
|
26
|
+
/** Installed app keys, so an add-on's `attaches` can be checked (24 §5.3). */
|
|
27
|
+
knownAppKeys?: readonly string[];
|
|
28
|
+
/** The host app's table refs, so an add-on's `scopes` can be bounded. */
|
|
29
|
+
hostTables?: readonly string[];
|
|
30
|
+
}
|
|
31
|
+
export type ValidateManifestResult = {
|
|
32
|
+
ok: true;
|
|
33
|
+
manifest: Manifest;
|
|
34
|
+
} | {
|
|
35
|
+
ok: false;
|
|
36
|
+
issues: ManifestIssue[];
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Validate an untrusted manifest document. Returns the typed manifest on
|
|
40
|
+
* success, or every issue found (schema + policy) on failure — never throws.
|
|
41
|
+
*/
|
|
42
|
+
export declare function validateManifest(input: unknown, opts?: ValidateManifestOptions): ValidateManifestResult;
|
|
43
|
+
/** Throwing variant for trusted callers (build tooling); use the safe form at runtime. */
|
|
44
|
+
export declare function parseManifest(input: unknown, opts?: ValidateManifestOptions): Manifest;
|
|
45
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;OAQG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,8EAA8E;IAC9E,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,yEAAyE;IACzE,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAChC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC;AAE3C;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,uBAA4B,GACjC,sBAAsB,CAwCxB;AAED,0FAA0F;AAC1F,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,GAAE,uBAA4B,GAAG,QAAQ,CAO1F"}
|
package/dist/validate.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest validation entry point (13-marketplace.md §2, §9). Layers the
|
|
3
|
+
* envelope schema with the v1 publisher policy: the installer rejects any
|
|
4
|
+
* `publisher.id` other than `adminium` unless the `third-party-publishers`
|
|
5
|
+
* feature flag is on (off in v1). Pure — safe in the browser storefront.
|
|
6
|
+
*/
|
|
7
|
+
import { FIRST_PARTY_PUBLISHER_ID, RESERVED_KEYS, addOnIssues, manifestSchema, } from './schema.js';
|
|
8
|
+
/**
|
|
9
|
+
* Validate an untrusted manifest document. Returns the typed manifest on
|
|
10
|
+
* success, or every issue found (schema + policy) on failure — never throws.
|
|
11
|
+
*/
|
|
12
|
+
export function validateManifest(input, opts = {}) {
|
|
13
|
+
const parsed = manifestSchema.safeParse(input);
|
|
14
|
+
if (!parsed.success) {
|
|
15
|
+
return {
|
|
16
|
+
ok: false,
|
|
17
|
+
issues: parsed.error.issues.map((issue) => ({
|
|
18
|
+
path: issue.path.map(String).join('.'),
|
|
19
|
+
message: issue.message,
|
|
20
|
+
})),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const manifest = parsed.data;
|
|
24
|
+
const issues = [];
|
|
25
|
+
if (!(opts.allowThirdPartyPublishers ?? false) && manifest.publisher.id !== FIRST_PARTY_PUBLISHER_ID) {
|
|
26
|
+
issues.push({
|
|
27
|
+
path: 'publisher.id',
|
|
28
|
+
message: `third-party publishers are not accepted in v1 (expected "${FIRST_PARTY_PUBLISHER_ID}")`,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
// D17 — apps and add-ons share one key namespace, and these keys shadow a
|
|
32
|
+
// storefront route or a data file.
|
|
33
|
+
if (RESERVED_KEYS.includes(manifest.key)) {
|
|
34
|
+
issues.push({
|
|
35
|
+
path: 'key',
|
|
36
|
+
message: `"${manifest.key}" is reserved and cannot be used as an app or add-on key`,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
issues.push(...addOnIssues(manifest, {
|
|
40
|
+
...(opts.knownAppKeys !== undefined ? { knownAppKeys: opts.knownAppKeys } : {}),
|
|
41
|
+
...(opts.hostTables !== undefined ? { hostTables: opts.hostTables } : {}),
|
|
42
|
+
}));
|
|
43
|
+
if (issues.length > 0)
|
|
44
|
+
return { ok: false, issues };
|
|
45
|
+
return { ok: true, manifest };
|
|
46
|
+
}
|
|
47
|
+
/** Throwing variant for trusted callers (build tooling); use the safe form at runtime. */
|
|
48
|
+
export function parseManifest(input, opts = {}) {
|
|
49
|
+
const result = validateManifest(input, opts);
|
|
50
|
+
if (!result.ok) {
|
|
51
|
+
const summary = result.issues.map((i) => `${i.path}: ${i.message}`).join('; ');
|
|
52
|
+
throw new Error(`invalid manifest: ${summary}`);
|
|
53
|
+
}
|
|
54
|
+
return result.manifest;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,wBAAwB,EACxB,aAAa,EACb,WAAW,EACX,cAAc,GAEf,MAAM,aAAa,CAAC;AA+BrB;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAc,EACd,OAAgC,EAAE;IAElC,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBAC1C,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;gBACtC,OAAO,EAAE,KAAK,CAAC,OAAO;aACvB,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;IAC7B,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,IAAI,CAAC,CAAC,IAAI,CAAC,yBAAyB,IAAI,KAAK,CAAC,IAAI,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,wBAAwB,EAAE,CAAC;QACrG,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,4DAA4D,wBAAwB,IAAI;SAClG,CAAC,CAAC;IACL,CAAC;IAED,0EAA0E;IAC1E,mCAAmC;IACnC,IAAK,aAAmC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,IAAI,QAAQ,CAAC,GAAG,0DAA0D;SACpF,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,IAAI,CACT,GAAG,WAAW,CAAC,QAAQ,EAAE;QACvB,GAAG,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1E,CAAC,CACH,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IACpD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAChC,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,OAAgC,EAAE;IAC9E,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/E,MAAM,IAAI,KAAK,CAAC,qBAAqB,OAAO,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adminiumjs/manifest",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,6 +19,10 @@
|
|
|
19
19
|
"default": "./dist/index.js"
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@adminium/add-on-contracts": "npm:@adminiumjs/add-on-contracts@0.2.1",
|
|
24
|
+
"zod": "^4.4.3"
|
|
25
|
+
},
|
|
22
26
|
"files": [
|
|
23
27
|
"dist"
|
|
24
28
|
]
|