@ikenga/contract 0.15.0 → 0.17.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/manifest.d.ts +232 -41
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +27 -4
- package/dist/manifest.js.map +1 -1
- package/dist/registry.d.ts +206 -34
- package/dist/registry.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/manifest.test.ts +50 -2
- package/src/manifest.ts +32 -4
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,uBAAuB,EAAG,CAAU,CAAC;AAIlD;;;;GAIG;AACH,eAAO,MAAM,YAAY;IACvB,4DAA4D;;IAE5D,0DAA0D;;;;;;;;EAE1D,CAAC;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;EAGjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,gBAAgB;IAC3B,4BAA4B;;IAE5B,iDAAiD;;IAEjD,yEAAyE;;IAEzE,2DAA2D;;IAE3D,mFAAmF;;IAEnF,4DAA4D
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAE5D,gFAAgF;;YA/BhF,4DAA4D;;YAE5D,0DAA0D;;;;;;;;;QA+B1D;;;;;;WAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAaH,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAIxD,eAAO,MAAM,mBAAmB;IAC9B,qBAAqB;;IAErB,qBAAqB;;IAErB;;;;;OAKG;;IAEH,4EAA4E;;IAE5E,2EAA2E;;IAE3E;;;;OAIG;;IAEH;;;;;;;OAOG;;;;;;;;;;;;;;;;;;EAEH,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,mBAAmB;;IAE9B,wDAAwD;;;QAnCxD,qBAAqB;;QAErB,qBAAqB;;QAErB;;;;;WAKG;;QAEH,4EAA4E;;QAE5E,2EAA2E;;QAE3E;;;;WAIG;;QAEH;;;;;;;WAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUH,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAIhE;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD"}
|
package/package.json
CHANGED
package/src/manifest.test.ts
CHANGED
|
@@ -89,8 +89,8 @@ test('Manifest: requires defaults to [] when absent (pre-Phase-4 manifest)', ()
|
|
|
89
89
|
|
|
90
90
|
// ─── WP-01 — trusted-cap tier (ADR-017): http / secrets / invoke + signature ─
|
|
91
91
|
|
|
92
|
-
test('IKENGA_API_VERSION is
|
|
93
|
-
assert.equal(IKENGA_API_VERSION,
|
|
92
|
+
test('IKENGA_API_VERSION is 4 (WP-01 Manifest v4)', () => {
|
|
93
|
+
assert.equal(IKENGA_API_VERSION, 4);
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
test('HttpCapability: auth_header defaults to Authorization; auth_secret optional', () => {
|
|
@@ -177,6 +177,26 @@ test('Manifest: api=1 manifest without new fields parses (back-compat)', () => {
|
|
|
177
177
|
assert.equal(m.capabilities, undefined);
|
|
178
178
|
});
|
|
179
179
|
|
|
180
|
+
test('Manifest: webview capability and partition route parses', () => {
|
|
181
|
+
const m = ManifestSchema.parse({
|
|
182
|
+
...BASE,
|
|
183
|
+
ui: {
|
|
184
|
+
routes: [
|
|
185
|
+
{ path: '/test', kind: 'webview', source: 'https://example.com', partition: 'test-part' }
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
capabilities: {
|
|
189
|
+
webview: {
|
|
190
|
+
child_webviews: true,
|
|
191
|
+
allowed_origins: ['https://example.com']
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
assert.equal(m.ui.routes[0].kind, 'webview');
|
|
196
|
+
assert.equal(m.ui.routes[0].partition, 'test-part');
|
|
197
|
+
assert.deepEqual(m.capabilities?.webview?.allowed_origins, ['https://example.com']);
|
|
198
|
+
});
|
|
199
|
+
|
|
180
200
|
test('Manifest: retired bundling fields are no longer part of the type (WP-17)', () => {
|
|
181
201
|
// ADR-015 decision 4: `skills`/`commands`/`agents` were hard-retired from the
|
|
182
202
|
// schema (lockstep with the Rust `deny_unknown_fields` Manifest, which REJECTS
|
|
@@ -190,3 +210,31 @@ test('Manifest: retired bundling fields are no longer part of the type (WP-17)',
|
|
|
190
210
|
assert.equal(m.skills, undefined);
|
|
191
211
|
assert.equal(m.commands, undefined);
|
|
192
212
|
});
|
|
213
|
+
|
|
214
|
+
test('Manifest: allowed_origins absent stays absent (not coerced to [])', () => {
|
|
215
|
+
// G-28 — absent must be distinguishable from an explicit deny-all lockdown.
|
|
216
|
+
// A `.default([])` here would silently turn every pre-v4 manifest into one.
|
|
217
|
+
const m = ManifestSchema.parse({
|
|
218
|
+
id: 'com.test.webview',
|
|
219
|
+
name: 'T',
|
|
220
|
+
version: '1.0.0',
|
|
221
|
+
ikenga_api: '4',
|
|
222
|
+
author: { name: 'T' },
|
|
223
|
+
ui: { routes: [{ path: '/', kind: 'webview', source: 'https://example.com' }] },
|
|
224
|
+
capabilities: { webview: { child_webviews: true, partitions: ['default'] } },
|
|
225
|
+
});
|
|
226
|
+
assert.equal(m.capabilities?.webview?.allowed_origins, undefined);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test('Manifest: allowed_origins empty array survives as an explicit lockdown', () => {
|
|
230
|
+
const m = ManifestSchema.parse({
|
|
231
|
+
id: 'com.test.webview',
|
|
232
|
+
name: 'T',
|
|
233
|
+
version: '1.0.0',
|
|
234
|
+
ikenga_api: '4',
|
|
235
|
+
author: { name: 'T' },
|
|
236
|
+
ui: { routes: [{ path: '/', kind: 'webview', source: 'https://example.com' }] },
|
|
237
|
+
capabilities: { webview: { child_webviews: true, partitions: ['default'], allowed_origins: [] } },
|
|
238
|
+
});
|
|
239
|
+
assert.deepEqual(m.capabilities?.webview?.allowed_origins, []);
|
|
240
|
+
});
|
package/src/manifest.ts
CHANGED
|
@@ -17,7 +17,7 @@ import { BrowserEngineSchema } from './browser.js';
|
|
|
17
17
|
// v3 (ADR-017): added capabilities.http / .secrets / .invoke (trusted-cap tier)
|
|
18
18
|
// + top-level optional `signature`. All additive; api=1/2 manifests parse
|
|
19
19
|
// unchanged. Elevated caps are inert unless the pkg is trusted.
|
|
20
|
-
export const IKENGA_API_VERSION =
|
|
20
|
+
export const IKENGA_API_VERSION = 4 as const;
|
|
21
21
|
export const IKENGA_API_MIN_SUPPORTED = 1 as const;
|
|
22
22
|
|
|
23
23
|
// ---------- Sub-schemas ----------
|
|
@@ -79,6 +79,13 @@ export const PermissionsSchema = z.object({
|
|
|
79
79
|
* (pkgDeclaresScope). Mirrors `Permissions.engine` in the shell's
|
|
80
80
|
* manifest.rs — keep in lockstep. */
|
|
81
81
|
engine: z.array(z.string()).default([]),
|
|
82
|
+
/** Notification scopes. `"send"` gates the FE-side `host.notify` verb
|
|
83
|
+
* (pkgDeclaresScope), which raises a real OS notification and therefore
|
|
84
|
+
* reaches the user even when Ikenga is not the focused window — which is
|
|
85
|
+
* why it is gated at all. Mirrors `Permissions.notify` in the shell's
|
|
86
|
+
* manifest.rs — keep in lockstep. */
|
|
87
|
+
notify: z.array(z.string()).default([]),
|
|
88
|
+
events: z.array(z.string()).default([]),
|
|
82
89
|
}).default({});
|
|
83
90
|
|
|
84
91
|
export const NavEntrySchema = z.object({
|
|
@@ -91,10 +98,11 @@ export const NavEntrySchema = z.object({
|
|
|
91
98
|
|
|
92
99
|
export const UiRouteSchema = z.object({
|
|
93
100
|
path: z.string(),
|
|
94
|
-
/** "iframe" | "component" (component is builtin-only) */
|
|
95
|
-
kind: z.enum(['iframe', 'component']),
|
|
96
|
-
/** iframe: URL or pkg-relative html path. component: identifier. */
|
|
101
|
+
/** "iframe" | "component" | "webview" (component is builtin-only) */
|
|
102
|
+
kind: z.enum(['iframe', 'component', 'webview']),
|
|
103
|
+
/** iframe/webview: URL or pkg-relative html path. component: identifier. */
|
|
97
104
|
source: z.string(),
|
|
105
|
+
partition: z.string().optional(),
|
|
98
106
|
});
|
|
99
107
|
|
|
100
108
|
export const CommandPaletteEntrySchema = z.object({
|
|
@@ -110,6 +118,11 @@ export const SidePaneViewerSchema = z.object({
|
|
|
110
118
|
route: z.string(),
|
|
111
119
|
});
|
|
112
120
|
|
|
121
|
+
export const ManifestUiSessionSchema = z.object({
|
|
122
|
+
persistence: z.enum(['keep', 'clear-on-exit', 'ask']),
|
|
123
|
+
});
|
|
124
|
+
export type ManifestUiSession = z.infer<typeof ManifestUiSessionSchema>;
|
|
125
|
+
|
|
113
126
|
export const UiBlockSchema = z.object({
|
|
114
127
|
nav: z.array(NavEntrySchema).default([]),
|
|
115
128
|
routes: z.array(UiRouteSchema).default([]),
|
|
@@ -119,6 +132,7 @@ export const UiBlockSchema = z.object({
|
|
|
119
132
|
csp: z.record(z.array(z.string())).optional(),
|
|
120
133
|
/** Per-directive Permission-Policy values. */
|
|
121
134
|
permissions: z.record(z.array(z.string())).optional(),
|
|
135
|
+
session: ManifestUiSessionSchema.optional(),
|
|
122
136
|
}).default({});
|
|
123
137
|
|
|
124
138
|
export const SettingsFieldSchema = z.object({
|
|
@@ -185,6 +199,13 @@ export const WebviewCapabilitySchema = z.object({
|
|
|
185
199
|
* own OS window). Defaults to `["webkit"]` so existing manifests are
|
|
186
200
|
* unchanged. Mirrors `engines` in `WebviewCapability` (manifest.rs). */
|
|
187
201
|
engines: z.array(BrowserEngineSchema).default(['webkit']),
|
|
202
|
+
/** Origins this pkg's webviews may load. **Absent is permissive** (with a
|
|
203
|
+
* host-side warning) so pre-v4 manifests keep mounting; `[]` is an explicit
|
|
204
|
+
* deny-all; entries match exactly, as `*`, or as a `https://*.example.com`
|
|
205
|
+
* subdomain glob. Mirrors `allowed_origins` in `manifest.rs` — absent and
|
|
206
|
+
* empty are deliberately distinct, so this must stay `.optional()`, never
|
|
207
|
+
* `.default([])`. */
|
|
208
|
+
allowed_origins: z.array(z.string()).optional(),
|
|
188
209
|
});
|
|
189
210
|
export type WebviewCapability = z.infer<typeof WebviewCapabilitySchema>;
|
|
190
211
|
|
|
@@ -314,6 +335,11 @@ export const RequiresEntrySchema = z
|
|
|
314
335
|
.strict();
|
|
315
336
|
export type RequiresEntry = z.infer<typeof RequiresEntrySchema>;
|
|
316
337
|
|
|
338
|
+
export const ManifestAuthBridgeSchema = z.object({
|
|
339
|
+
strategy: z.enum(['api-key', 'cdp', 'none']),
|
|
340
|
+
});
|
|
341
|
+
export type ManifestAuthBridge = z.infer<typeof ManifestAuthBridgeSchema>;
|
|
342
|
+
|
|
317
343
|
// ---------- Manifest ----------
|
|
318
344
|
|
|
319
345
|
export const ManifestSchema = z.object({
|
|
@@ -324,6 +350,8 @@ export const ManifestSchema = z.object({
|
|
|
324
350
|
/** Numeric string — host accepts versions in [MIN, CURRENT]. */
|
|
325
351
|
ikenga_api: z.string().regex(/^\d+$/),
|
|
326
352
|
|
|
353
|
+
auth_bridge: ManifestAuthBridgeSchema.optional(),
|
|
354
|
+
|
|
327
355
|
/** Hint, not enforced: "skill" | "embedded" | "windowed" | "engine". */
|
|
328
356
|
kind: z.string().optional(),
|
|
329
357
|
author: AuthorSchema.optional(),
|