@ankhorage/zora 25.6.2 → 25.7.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/CHANGELOG.md +0 -18
- package/README.md +1 -1
- package/dist/capabilities/index.d.ts +74 -2
- package/dist/capabilities/index.d.ts.map +1 -1
- package/dist/capabilities/index.js +59 -6158
- package/dist/capabilities/index.js.map +1 -118
- package/dist/cli/index.d.ts +74 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -2
- package/dist/cli/index.js.map +1 -1
- package/package.json +4 -1822
- package/src/capabilities/index.test.ts +15 -87
- package/src/capabilities/index.ts +2 -5
- package/src/cli/index.test.ts +3 -5
- package/src/cli/index.ts +2 -5
- package/src/structureOwnership.test.ts +0 -5
- package/dist/features/registry/createEventCapabilities.d.ts +0 -4
- package/dist/features/registry/createEventCapabilities.d.ts.map +0 -1
- package/dist/features/registry/createEventCapabilities.js +0 -76
- package/dist/features/registry/createEventCapabilities.js.map +0 -1
- package/src/features/registry/createEventCapabilities.ts +0 -108
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
|
|
3
|
-
import { isCapability
|
|
4
|
-
import type { Capability } from '@ankhorage/contracts/capability';
|
|
3
|
+
import { isCapability } from '@ankhorage/contracts/capabilities';
|
|
5
4
|
import { isRecord } from '@ankhorage/utility/object';
|
|
6
5
|
import { expect, test } from 'bun:test';
|
|
7
6
|
|
|
8
|
-
import { ZORA_COMPONENT_META } from '../features/registry';
|
|
9
7
|
import { CAPABILITIES } from './index';
|
|
10
8
|
|
|
11
9
|
const packageJson: unknown = JSON.parse(
|
|
@@ -15,66 +13,11 @@ const packageCapabilities =
|
|
|
15
13
|
isRecord(packageJson) && isRecord(packageJson.ankh) ? packageJson.ankh.capabilities : undefined;
|
|
16
14
|
|
|
17
15
|
test('publishes valid, uniquely identified canonical ZORA capabilities', () => {
|
|
16
|
+
expect(CAPABILITIES).toHaveLength(2);
|
|
18
17
|
expect(CAPABILITIES.every(isCapability)).toBe(true);
|
|
19
18
|
expect(new Set(CAPABILITIES.map((capability) => capability.id)).size).toBe(CAPABILITIES.length);
|
|
20
19
|
});
|
|
21
20
|
|
|
22
|
-
test('projects each direct-manifest event metadata entry into one canonical event capability', () => {
|
|
23
|
-
const metadataEvents = Object.values(ZORA_COMPONENT_META)
|
|
24
|
-
.filter((component) => component.directManifestNode)
|
|
25
|
-
.flatMap((component) => Object.values(component.events ?? {}));
|
|
26
|
-
const eventCapabilities = CAPABILITIES.filter((capability) => capability.access.includes('emit'));
|
|
27
|
-
|
|
28
|
-
expect(eventCapabilities).toHaveLength(
|
|
29
|
-
new Set(metadataEvents.map((event) => event.eventType)).size,
|
|
30
|
-
);
|
|
31
|
-
const eventCapabilitiesById = new Map<Capability['id'], Capability>(
|
|
32
|
-
eventCapabilities.map((capability) => [capability.id, capability]),
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
for (const event of metadataEvents) {
|
|
36
|
-
if (!isCapabilityId(event.eventType)) throw new Error(`Invalid event id: ${event.eventType}`);
|
|
37
|
-
const capability = eventCapabilitiesById.get(event.eventType);
|
|
38
|
-
expect(capability?.owner).toBe('@ankhorage/zora');
|
|
39
|
-
expect(capability?.access).toEqual(['emit']);
|
|
40
|
-
expect(capability?.binding).toEqual({ kind: 'event', bindableAs: ['source'] });
|
|
41
|
-
expect(capability?.label).toBe(event.label);
|
|
42
|
-
expect(capability?.description).toBe(event.description);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test('projects event payload metadata into matching output schemas', () => {
|
|
47
|
-
const eventCapabilities = new Map<Capability['id'], Capability>(
|
|
48
|
-
CAPABILITIES.filter((capability) => capability.access.includes('emit')).map((capability) => [
|
|
49
|
-
capability.id,
|
|
50
|
-
capability,
|
|
51
|
-
]),
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
for (const component of Object.values(ZORA_COMPONENT_META)) {
|
|
55
|
-
if (!component.directManifestNode) continue;
|
|
56
|
-
for (const event of Object.values(component.events ?? {})) {
|
|
57
|
-
if (!isCapabilityId(event.eventType)) throw new Error(`Invalid event id: ${event.eventType}`);
|
|
58
|
-
const capability = eventCapabilities.get(event.eventType);
|
|
59
|
-
const schema = capability?.output?.schema;
|
|
60
|
-
expect(schema?.type).toBe('object');
|
|
61
|
-
|
|
62
|
-
for (const field of event.payloadFields ?? []) {
|
|
63
|
-
if (field.path.includes('.')) continue;
|
|
64
|
-
const fieldSchema = Object.entries(schema?.properties ?? {}).find(
|
|
65
|
-
([fieldName]) => fieldName === field.path,
|
|
66
|
-
)?.[1];
|
|
67
|
-
expect(fieldSchema?.type).toBe(
|
|
68
|
-
field.type === 'record' ? 'object' : field.type === 'unknown' ? undefined : field.type,
|
|
69
|
-
);
|
|
70
|
-
expect(fieldSchema?.additionalProperties).toBe(field.type === 'record' ? true : undefined);
|
|
71
|
-
expect(fieldSchema?.title).toBe(field.label);
|
|
72
|
-
expect(fieldSchema?.description).toBe(field.description);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
|
|
78
21
|
test('keeps Ankh package metadata identical to the canonical catalog', () => {
|
|
79
22
|
expect(Array.isArray(packageCapabilities)).toBe(true);
|
|
80
23
|
if (!Array.isArray(packageCapabilities)) {
|
|
@@ -94,33 +37,18 @@ test('exports the catalog from the public capabilities subpath', async () => {
|
|
|
94
37
|
});
|
|
95
38
|
|
|
96
39
|
test('preserves the executable action semantics of ZORA provider capabilities', () => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
'
|
|
109
|
-
|
|
110
|
-
'-e',
|
|
111
|
-
"import('./dist/capabilities/index.js').then(({ CAPABILITIES }) => { if (!Array.isArray(CAPABILITIES)) process.exit(1); });",
|
|
112
|
-
],
|
|
113
|
-
{
|
|
114
|
-
cwd: process.cwd(),
|
|
115
|
-
stderr: 'pipe',
|
|
116
|
-
stdout: 'pipe',
|
|
117
|
-
},
|
|
118
|
-
);
|
|
119
|
-
const [exitCode, stderr] = await Promise.all([
|
|
120
|
-
subprocess.exited,
|
|
121
|
-
new Response(subprocess.stderr).text(),
|
|
40
|
+
expect(CAPABILITIES).toEqual([
|
|
41
|
+
expect.objectContaining({
|
|
42
|
+
id: 'zora.create',
|
|
43
|
+
owner: '@ankhorage/zora',
|
|
44
|
+
access: ['invoke'],
|
|
45
|
+
binding: { kind: 'action', bindableAs: ['target'] },
|
|
46
|
+
}),
|
|
47
|
+
expect.objectContaining({
|
|
48
|
+
id: 'zora.sync',
|
|
49
|
+
owner: '@ankhorage/zora',
|
|
50
|
+
access: ['invoke'],
|
|
51
|
+
binding: { kind: 'action', bindableAs: ['target'] },
|
|
52
|
+
}),
|
|
122
53
|
]);
|
|
123
|
-
|
|
124
|
-
expect(stderr).toBe('');
|
|
125
|
-
expect(exitCode).toBe(0);
|
|
126
54
|
});
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import type { Capability } from '@ankhorage/contracts/
|
|
2
|
-
|
|
3
|
-
import { createEventCapabilities } from '../features/registry/createEventCapabilities.js';
|
|
1
|
+
import type { Capability } from '@ankhorage/contracts/capabilities';
|
|
4
2
|
|
|
5
3
|
export const CAPABILITIES = [
|
|
6
4
|
{
|
|
@@ -62,5 +60,4 @@ export const CAPABILITIES = [
|
|
|
62
60
|
},
|
|
63
61
|
},
|
|
64
62
|
},
|
|
65
|
-
|
|
66
|
-
] satisfies readonly Capability[];
|
|
63
|
+
] as const satisfies readonly Capability[];
|
package/src/cli/index.test.ts
CHANGED
|
@@ -6,9 +6,7 @@ import provider from './index';
|
|
|
6
6
|
test('publishes ZORA create and sync through the Ankh provider', () => {
|
|
7
7
|
expect(provider.id).toBe('@ankhorage/zora');
|
|
8
8
|
expect(provider.category).toBe('zora');
|
|
9
|
-
expect(provider.capabilities).
|
|
10
|
-
CAPABILITIES.filter((capability) => capability.access.includes('invoke')),
|
|
11
|
-
);
|
|
9
|
+
expect(provider.capabilities).toBe(CAPABILITIES);
|
|
12
10
|
expect(provider.commands).toEqual([
|
|
13
11
|
{
|
|
14
12
|
path: ['create'],
|
|
@@ -26,9 +24,9 @@ test('publishes ZORA create and sync through the Ankh provider', () => {
|
|
|
26
24
|
expect(provider.handlers[1]?.path).toEqual(['sync']);
|
|
27
25
|
});
|
|
28
26
|
|
|
29
|
-
test('maps every provider command to one
|
|
27
|
+
test('maps every provider command to one canonical capability independent of catalog order', () => {
|
|
30
28
|
const commandCapabilityIds = provider.commands.map((command) => command.capability);
|
|
31
|
-
const capabilityIds =
|
|
29
|
+
const capabilityIds = CAPABILITIES.map((capability) => capability.id);
|
|
32
30
|
|
|
33
31
|
expect(new Set(commandCapabilityIds).size).toBe(commandCapabilityIds.length);
|
|
34
32
|
expect(new Set(commandCapabilityIds)).toEqual(new Set(capabilityIds));
|
package/src/cli/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { dirname, resolve } from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
|
|
5
5
|
import type { AnkhRuntimeCommandProvider } from '@ankhorage/ankh';
|
|
6
|
-
import type { Capability } from '@ankhorage/contracts/
|
|
6
|
+
import type { Capability } from '@ankhorage/contracts/capabilities';
|
|
7
7
|
|
|
8
8
|
import { CAPABILITIES } from '../capabilities';
|
|
9
9
|
import { create } from './commands/create';
|
|
@@ -19,15 +19,12 @@ const SYNC_COMMAND = {
|
|
|
19
19
|
capability: 'zora.sync' satisfies Capability['id'],
|
|
20
20
|
summary: 'Regenerate the declared ZORA web materialization.',
|
|
21
21
|
} as const;
|
|
22
|
-
const COMMAND_CAPABILITIES = CAPABILITIES.filter((capability) =>
|
|
23
|
-
capability.access.includes('invoke'),
|
|
24
|
-
);
|
|
25
22
|
|
|
26
23
|
const provider = {
|
|
27
24
|
id: '@ankhorage/zora',
|
|
28
25
|
category: 'zora',
|
|
29
26
|
version: readPackageVersion(),
|
|
30
|
-
capabilities:
|
|
27
|
+
capabilities: CAPABILITIES,
|
|
31
28
|
commands: [CREATE_COMMAND, SYNC_COMMAND],
|
|
32
29
|
handlers: [
|
|
33
30
|
{
|
|
@@ -63,9 +63,4 @@ describe('src ownership', () => {
|
|
|
63
63
|
expect(existsSync(path), path).toBe(false);
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
|
-
|
|
67
|
-
test('keeps event capability projection with the registry metadata owner', () => {
|
|
68
|
-
expect(existsSync('src/features/registry/createEventCapabilities.ts')).toBe(true);
|
|
69
|
-
expect(existsSync('src/capabilities/createEventCapabilities.ts')).toBe(false);
|
|
70
|
-
});
|
|
71
66
|
});
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { Capability } from '@ankhorage/contracts/capability';
|
|
2
|
-
/*** Projects direct-manifest ZORA event metadata into unique portable event capabilities. */
|
|
3
|
-
export declare function createEventCapabilities(): readonly Capability[];
|
|
4
|
-
//# sourceMappingURL=createEventCapabilities.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createEventCapabilities.d.ts","sourceRoot":"","sources":["../../../src/features/registry/createEventCapabilities.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AASlE,6FAA6F;AAC7F,wBAAgB,uBAAuB,IAAI,SAAS,UAAU,EAAE,CAU/D"}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { areCapabilitiesEqual, isCapabilityId } from '@ankhorage/capability';
|
|
2
|
-
import { ZORA_COMPONENT_META } from './componentMeta';
|
|
3
|
-
/*** Projects direct-manifest ZORA event metadata into unique portable event capabilities. */
|
|
4
|
-
export function createEventCapabilities() {
|
|
5
|
-
const capabilitiesById = Object.values(ZORA_COMPONENT_META)
|
|
6
|
-
.filter((component) => component.directManifestNode)
|
|
7
|
-
.flatMap((component) => Object.values(component.events ?? {}))
|
|
8
|
-
.reduce((capabilities, event) => addEventCapability(capabilities, event), new Map());
|
|
9
|
-
return [...capabilitiesById.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
10
|
-
}
|
|
11
|
-
/*** Adds one namespaced metadata event while rejecting conflicting duplicate identities. */
|
|
12
|
-
function addEventCapability(capabilities, event) {
|
|
13
|
-
if (!isCapabilityId(event.eventType))
|
|
14
|
-
return capabilities;
|
|
15
|
-
const capability = createEventCapability(event);
|
|
16
|
-
const existing = capabilities.get(capability.id);
|
|
17
|
-
if (existing !== undefined && !areCapabilitiesEqual(existing, capability)) {
|
|
18
|
-
throw new Error(`ZORA event metadata defines conflicting capability "${capability.id}".`);
|
|
19
|
-
}
|
|
20
|
-
return new Map([...capabilities, [capability.id, capability]]);
|
|
21
|
-
}
|
|
22
|
-
/*** Converts one emitted component event into its serializable canonical descriptor. */
|
|
23
|
-
function createEventCapability(event) {
|
|
24
|
-
if (!isCapabilityId(event.eventType)) {
|
|
25
|
-
throw new Error(`ZORA event metadata must use a namespaced capability id: "${event.eventType}".`);
|
|
26
|
-
}
|
|
27
|
-
return {
|
|
28
|
-
id: event.eventType,
|
|
29
|
-
owner: '@ankhorage/zora',
|
|
30
|
-
access: ['emit'],
|
|
31
|
-
binding: { kind: 'event', bindableAs: ['source'] },
|
|
32
|
-
label: event.label,
|
|
33
|
-
...(event.description === undefined ? {} : { description: event.description }),
|
|
34
|
-
output: { schema: createEventPayloadSchema(event.payloadFields ?? []) },
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
/*** Projects the documented event payload fields into an open object schema. */
|
|
38
|
-
function createEventPayloadSchema(fields) {
|
|
39
|
-
return {
|
|
40
|
-
type: 'object',
|
|
41
|
-
properties: fields.reduce(addPayloadField, {}),
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
/*** Adds one dotted metadata path to an immutable object-schema property map. */
|
|
45
|
-
function addPayloadField(properties, field) {
|
|
46
|
-
return addPayloadFieldAtPath(properties, field.path.split('.'), createPayloadFieldSchema(field));
|
|
47
|
-
}
|
|
48
|
-
/*** Recursively embeds a leaf schema below its documented object-property path. */
|
|
49
|
-
function addPayloadFieldAtPath(properties, path, schema) {
|
|
50
|
-
const [key, ...remainingPath] = path;
|
|
51
|
-
if (key === undefined || key === '')
|
|
52
|
-
return properties;
|
|
53
|
-
if (remainingPath.length === 0)
|
|
54
|
-
return { ...properties, [key]: schema };
|
|
55
|
-
const current = Object.entries(properties).find(([propertyKey]) => propertyKey === key)?.[1];
|
|
56
|
-
const nestedProperties = addPayloadFieldAtPath(current?.properties ?? {}, remainingPath, schema);
|
|
57
|
-
return {
|
|
58
|
-
...properties,
|
|
59
|
-
[key]: { ...current, type: 'object', properties: nestedProperties },
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
/*** Maps one authoring payload-field type and annotations to its portable data schema. */
|
|
63
|
-
function createPayloadFieldSchema(field) {
|
|
64
|
-
return {
|
|
65
|
-
...(field.type === 'object'
|
|
66
|
-
? { type: 'object' }
|
|
67
|
-
: field.type === 'record'
|
|
68
|
-
? { type: 'object', additionalProperties: true }
|
|
69
|
-
: field.type === 'unknown'
|
|
70
|
-
? {}
|
|
71
|
-
: { type: field.type }),
|
|
72
|
-
...(field.label === undefined ? {} : { title: field.label }),
|
|
73
|
-
...(field.description === undefined ? {} : { description: field.description }),
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
//# sourceMappingURL=createEventCapabilities.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createEventCapabilities.js","sourceRoot":"","sources":["../../../src/features/registry/createEventCapabilities.ts"],"names":[],"mappings":"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","sourcesContent":["import { areCapabilitiesEqual, isCapabilityId } from '@ankhorage/capability';\nimport type { Capability } from '@ankhorage/contracts/capability';\nimport type { DataSchema } from '@ankhorage/contracts/data';\n\nimport type {\n ZoraComponentEventMeta,\n ZoraComponentEventPayloadFieldMeta,\n} from '../../types/authoring';\nimport { ZORA_COMPONENT_META } from './componentMeta';\n\n/*** Projects direct-manifest ZORA event metadata into unique portable event capabilities. */\nexport function createEventCapabilities(): readonly Capability[] {\n const capabilitiesById = Object.values(ZORA_COMPONENT_META)\n .filter((component) => component.directManifestNode)\n .flatMap((component) => Object.values(component.events ?? {}))\n .reduce<ReadonlyMap<Capability['id'], Capability>>(\n (capabilities, event) => addEventCapability(capabilities, event),\n new Map(),\n );\n\n return [...capabilitiesById.values()].sort((left, right) => left.id.localeCompare(right.id));\n}\n\n/*** Adds one namespaced metadata event while rejecting conflicting duplicate identities. */\nfunction addEventCapability(\n capabilities: ReadonlyMap<Capability['id'], Capability>,\n event: ZoraComponentEventMeta,\n): ReadonlyMap<Capability['id'], Capability> {\n if (!isCapabilityId(event.eventType)) return capabilities;\n\n const capability = createEventCapability(event);\n const existing = capabilities.get(capability.id);\n if (existing !== undefined && !areCapabilitiesEqual(existing, capability)) {\n throw new Error(`ZORA event metadata defines conflicting capability \"${capability.id}\".`);\n }\n\n return new Map([...capabilities, [capability.id, capability]]);\n}\n\n/*** Converts one emitted component event into its serializable canonical descriptor. */\nfunction createEventCapability(event: ZoraComponentEventMeta): Capability {\n if (!isCapabilityId(event.eventType)) {\n throw new Error(\n `ZORA event metadata must use a namespaced capability id: \"${event.eventType}\".`,\n );\n }\n\n return {\n id: event.eventType,\n owner: '@ankhorage/zora',\n access: ['emit'],\n binding: { kind: 'event', bindableAs: ['source'] },\n label: event.label,\n ...(event.description === undefined ? {} : { description: event.description }),\n output: { schema: createEventPayloadSchema(event.payloadFields ?? []) },\n };\n}\n\n/*** Projects the documented event payload fields into an open object schema. */\nfunction createEventPayloadSchema(\n fields: readonly ZoraComponentEventPayloadFieldMeta[],\n): DataSchema {\n return {\n type: 'object',\n properties: fields.reduce<Readonly<Record<string, DataSchema>>>(addPayloadField, {}),\n };\n}\n\n/*** Adds one dotted metadata path to an immutable object-schema property map. */\nfunction addPayloadField(\n properties: Readonly<Record<string, DataSchema>>,\n field: ZoraComponentEventPayloadFieldMeta,\n): Readonly<Record<string, DataSchema>> {\n return addPayloadFieldAtPath(properties, field.path.split('.'), createPayloadFieldSchema(field));\n}\n\n/*** Recursively embeds a leaf schema below its documented object-property path. */\nfunction addPayloadFieldAtPath(\n properties: Readonly<Record<string, DataSchema>>,\n path: readonly string[],\n schema: DataSchema,\n): Readonly<Record<string, DataSchema>> {\n const [key, ...remainingPath] = path;\n if (key === undefined || key === '') return properties;\n if (remainingPath.length === 0) return { ...properties, [key]: schema };\n\n const current = Object.entries(properties).find(([propertyKey]) => propertyKey === key)?.[1];\n const nestedProperties = addPayloadFieldAtPath(current?.properties ?? {}, remainingPath, schema);\n return {\n ...properties,\n [key]: { ...current, type: 'object', properties: nestedProperties },\n };\n}\n\n/*** Maps one authoring payload-field type and annotations to its portable data schema. */\nfunction createPayloadFieldSchema(field: ZoraComponentEventPayloadFieldMeta): DataSchema {\n return {\n ...(field.type === 'object'\n ? { type: 'object' as const }\n : field.type === 'record'\n ? { type: 'object' as const, additionalProperties: true }\n : field.type === 'unknown'\n ? {}\n : { type: field.type }),\n ...(field.label === undefined ? {} : { title: field.label }),\n ...(field.description === undefined ? {} : { description: field.description }),\n };\n}\n"]}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { areCapabilitiesEqual, isCapabilityId } from '@ankhorage/capability';
|
|
2
|
-
import type { Capability } from '@ankhorage/contracts/capability';
|
|
3
|
-
import type { DataSchema } from '@ankhorage/contracts/data';
|
|
4
|
-
|
|
5
|
-
import type {
|
|
6
|
-
ZoraComponentEventMeta,
|
|
7
|
-
ZoraComponentEventPayloadFieldMeta,
|
|
8
|
-
} from '../../types/authoring';
|
|
9
|
-
import { ZORA_COMPONENT_META } from './componentMeta';
|
|
10
|
-
|
|
11
|
-
/*** Projects direct-manifest ZORA event metadata into unique portable event capabilities. */
|
|
12
|
-
export function createEventCapabilities(): readonly Capability[] {
|
|
13
|
-
const capabilitiesById = Object.values(ZORA_COMPONENT_META)
|
|
14
|
-
.filter((component) => component.directManifestNode)
|
|
15
|
-
.flatMap((component) => Object.values(component.events ?? {}))
|
|
16
|
-
.reduce<ReadonlyMap<Capability['id'], Capability>>(
|
|
17
|
-
(capabilities, event) => addEventCapability(capabilities, event),
|
|
18
|
-
new Map(),
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
return [...capabilitiesById.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/*** Adds one namespaced metadata event while rejecting conflicting duplicate identities. */
|
|
25
|
-
function addEventCapability(
|
|
26
|
-
capabilities: ReadonlyMap<Capability['id'], Capability>,
|
|
27
|
-
event: ZoraComponentEventMeta,
|
|
28
|
-
): ReadonlyMap<Capability['id'], Capability> {
|
|
29
|
-
if (!isCapabilityId(event.eventType)) return capabilities;
|
|
30
|
-
|
|
31
|
-
const capability = createEventCapability(event);
|
|
32
|
-
const existing = capabilities.get(capability.id);
|
|
33
|
-
if (existing !== undefined && !areCapabilitiesEqual(existing, capability)) {
|
|
34
|
-
throw new Error(`ZORA event metadata defines conflicting capability "${capability.id}".`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return new Map([...capabilities, [capability.id, capability]]);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/*** Converts one emitted component event into its serializable canonical descriptor. */
|
|
41
|
-
function createEventCapability(event: ZoraComponentEventMeta): Capability {
|
|
42
|
-
if (!isCapabilityId(event.eventType)) {
|
|
43
|
-
throw new Error(
|
|
44
|
-
`ZORA event metadata must use a namespaced capability id: "${event.eventType}".`,
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
id: event.eventType,
|
|
50
|
-
owner: '@ankhorage/zora',
|
|
51
|
-
access: ['emit'],
|
|
52
|
-
binding: { kind: 'event', bindableAs: ['source'] },
|
|
53
|
-
label: event.label,
|
|
54
|
-
...(event.description === undefined ? {} : { description: event.description }),
|
|
55
|
-
output: { schema: createEventPayloadSchema(event.payloadFields ?? []) },
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/*** Projects the documented event payload fields into an open object schema. */
|
|
60
|
-
function createEventPayloadSchema(
|
|
61
|
-
fields: readonly ZoraComponentEventPayloadFieldMeta[],
|
|
62
|
-
): DataSchema {
|
|
63
|
-
return {
|
|
64
|
-
type: 'object',
|
|
65
|
-
properties: fields.reduce<Readonly<Record<string, DataSchema>>>(addPayloadField, {}),
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/*** Adds one dotted metadata path to an immutable object-schema property map. */
|
|
70
|
-
function addPayloadField(
|
|
71
|
-
properties: Readonly<Record<string, DataSchema>>,
|
|
72
|
-
field: ZoraComponentEventPayloadFieldMeta,
|
|
73
|
-
): Readonly<Record<string, DataSchema>> {
|
|
74
|
-
return addPayloadFieldAtPath(properties, field.path.split('.'), createPayloadFieldSchema(field));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/*** Recursively embeds a leaf schema below its documented object-property path. */
|
|
78
|
-
function addPayloadFieldAtPath(
|
|
79
|
-
properties: Readonly<Record<string, DataSchema>>,
|
|
80
|
-
path: readonly string[],
|
|
81
|
-
schema: DataSchema,
|
|
82
|
-
): Readonly<Record<string, DataSchema>> {
|
|
83
|
-
const [key, ...remainingPath] = path;
|
|
84
|
-
if (key === undefined || key === '') return properties;
|
|
85
|
-
if (remainingPath.length === 0) return { ...properties, [key]: schema };
|
|
86
|
-
|
|
87
|
-
const current = Object.entries(properties).find(([propertyKey]) => propertyKey === key)?.[1];
|
|
88
|
-
const nestedProperties = addPayloadFieldAtPath(current?.properties ?? {}, remainingPath, schema);
|
|
89
|
-
return {
|
|
90
|
-
...properties,
|
|
91
|
-
[key]: { ...current, type: 'object', properties: nestedProperties },
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/*** Maps one authoring payload-field type and annotations to its portable data schema. */
|
|
96
|
-
function createPayloadFieldSchema(field: ZoraComponentEventPayloadFieldMeta): DataSchema {
|
|
97
|
-
return {
|
|
98
|
-
...(field.type === 'object'
|
|
99
|
-
? { type: 'object' as const }
|
|
100
|
-
: field.type === 'record'
|
|
101
|
-
? { type: 'object' as const, additionalProperties: true }
|
|
102
|
-
: field.type === 'unknown'
|
|
103
|
-
? {}
|
|
104
|
-
: { type: field.type }),
|
|
105
|
-
...(field.label === undefined ? {} : { title: field.label }),
|
|
106
|
-
...(field.description === undefined ? {} : { description: field.description }),
|
|
107
|
-
};
|
|
108
|
-
}
|