@opalesce/core 0.0.0 → 0.1.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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -161
  3. package/dist/index.d.ts +7 -5
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +2 -2
  6. package/dist/interaction/build.d.ts +5 -0
  7. package/dist/interaction/build.d.ts.map +1 -0
  8. package/dist/interaction/build.js +315 -0
  9. package/dist/interaction/errors.d.ts +12 -0
  10. package/dist/interaction/errors.d.ts.map +1 -0
  11. package/dist/interaction/errors.js +12 -0
  12. package/dist/interaction/schema.d.ts +9 -0
  13. package/dist/interaction/schema.d.ts.map +1 -0
  14. package/dist/interaction/schema.js +178 -0
  15. package/dist/interaction/types.d.ts +69 -0
  16. package/dist/interaction/types.d.ts.map +1 -0
  17. package/dist/interaction/types.js +1 -0
  18. package/dist/orchestrator/artifacts.d.ts +1 -1
  19. package/dist/orchestrator/artifacts.d.ts.map +1 -1
  20. package/dist/orchestrator/artifacts.js +1 -1
  21. package/dist/orchestrator/errors.d.ts +1 -17
  22. package/dist/orchestrator/errors.d.ts.map +1 -1
  23. package/dist/orchestrator/errors.js +3 -27
  24. package/dist/orchestrator/run.d.ts.map +1 -1
  25. package/dist/orchestrator/run.js +35 -33
  26. package/dist/orchestrator/types.d.ts +6 -13
  27. package/dist/orchestrator/types.d.ts.map +1 -1
  28. package/dist/parseAsyncAPI.d.ts +2 -0
  29. package/dist/parseAsyncAPI.d.ts.map +1 -1
  30. package/dist/parseAsyncAPI.js +6 -0
  31. package/dist/source.d.ts +12 -0
  32. package/dist/source.d.ts.map +1 -0
  33. package/dist/source.js +39 -0
  34. package/package.json +19 -2
  35. package/dist/orchestrator/orderPlugins.d.ts +0 -3
  36. package/dist/orchestrator/orderPlugins.d.ts.map +0 -1
  37. package/dist/orchestrator/orderPlugins.js +0 -41
  38. package/dist/orchestrator/services.d.ts +0 -26
  39. package/dist/orchestrator/services.d.ts.map +0 -1
  40. package/dist/orchestrator/services.js +0 -42
@@ -0,0 +1,315 @@
1
+ import { InteractionContractError } from "./errors.js";
2
+ import { createSchemaRegistry } from "./schema.js";
3
+ function parserObject(model) {
4
+ const value = model.json();
5
+ return typeof value === "object" && value !== null ? value : undefined;
6
+ }
7
+ function isRecord(value) {
8
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ }
10
+ // Collect every authored JSON pointer whose value is a `$ref`, using RFC 6901
11
+ // escaping so keys align with parser model pointers. This is provenance only;
12
+ // no parse, resolve, or fetch happens here.
13
+ function collectAuthoredReferences(data) {
14
+ const index = new Map();
15
+ const visit = (value, pointer) => {
16
+ if (Array.isArray(value)) {
17
+ value.forEach((item, index) => visit(item, `${pointer}/${index}`));
18
+ return;
19
+ }
20
+ if (!isRecord(value)) {
21
+ return;
22
+ }
23
+ const reference = value.$ref;
24
+ if (typeof reference === "string" && reference.length > 0) {
25
+ index.set(pointer === "" ? "/" : pointer, reference);
26
+ }
27
+ for (const [key, child] of Object.entries(value)) {
28
+ const escapedKey = key.replaceAll("~", "~0").replaceAll("/", "~1");
29
+ visit(child, `${pointer === "" ? "" : pointer}/${escapedKey}`);
30
+ }
31
+ };
32
+ visit(data, "");
33
+ return index;
34
+ }
35
+ function requireVersion(version) {
36
+ switch (version) {
37
+ case "2.6.0":
38
+ case "3.0.0":
39
+ case "3.1.0":
40
+ return version;
41
+ default:
42
+ throw new InteractionContractError("INTERACTION_VERSION_UNSUPPORTED", `AsyncAPI ${version} is not supported by the interaction contract.`, { pointer: "/asyncapi", details: { version } });
43
+ }
44
+ }
45
+ function requireName(value, kind, pointer) {
46
+ if (value !== undefined && value.length > 0) {
47
+ return value;
48
+ }
49
+ throw new InteractionContractError("INTERACTION_IDENTITY_MISSING", `The ${kind} at ${pointer} has no stable identity.`, { pointer, details: { kind } });
50
+ }
51
+ function normalizeAction(action, pointer) {
52
+ switch (action) {
53
+ case "publish":
54
+ case "send":
55
+ return "send";
56
+ case "receive":
57
+ case "subscribe":
58
+ return "receive";
59
+ default: {
60
+ const exhaustive = action;
61
+ throw new InteractionContractError("INTERACTION_IDENTITY_MISSING", `The operation at ${pointer} has an unsupported action.`, { pointer, details: { action: exhaustive } });
62
+ }
63
+ }
64
+ }
65
+ function uniqueSorted(values) {
66
+ return Object.freeze([...new Set(values)].sort((left, right) => left.localeCompare(right)));
67
+ }
68
+ function messageBaseName(message, pointer) {
69
+ const id = message.id();
70
+ if (typeof id === "string" && id.length > 0) {
71
+ return id;
72
+ }
73
+ const name = message.name();
74
+ if (name !== undefined && name.length > 0) {
75
+ return name;
76
+ }
77
+ return pointer;
78
+ }
79
+ function registerMessage(registry, message, identity, name, asyncapiVersion, createSchemaRole, ownerIdentity) {
80
+ const existing = registry.messages.get(identity);
81
+ if (existing !== undefined) {
82
+ return existing.identity;
83
+ }
84
+ const pointer = message.meta("pointer");
85
+ const payload = message.payload();
86
+ const headers = message.headers();
87
+ const description = message.description();
88
+ const contract = Object.freeze({
89
+ identity,
90
+ kind: "message",
91
+ name,
92
+ pointer,
93
+ asyncapiVersion,
94
+ ...(ownerIdentity === undefined ? {} : { ownerIdentity }),
95
+ ...(description === undefined ? {} : { description }),
96
+ ...(payload === undefined ? {} : { payload: createSchemaRole(payload) }),
97
+ ...(headers === undefined ? {} : { headers: createSchemaRole(headers) }),
98
+ });
99
+ registry.messages.set(identity, contract);
100
+ registry.identityByPointer.set(pointer, identity);
101
+ const object = parserObject(message);
102
+ if (object !== undefined) {
103
+ registry.identityByObject.set(object, identity);
104
+ }
105
+ return identity;
106
+ }
107
+ function existingMessageIdentity(registry, message) {
108
+ const object = parserObject(message);
109
+ if (object !== undefined) {
110
+ const identity = registry.identityByObject.get(object);
111
+ if (identity !== undefined) {
112
+ return identity;
113
+ }
114
+ }
115
+ return registry.identityByPointer.get(message.meta("pointer"));
116
+ }
117
+ function channelIdentity(channel) {
118
+ const pointer = channel.meta("pointer");
119
+ return `channel:${requireName(channel.id(), "channel", pointer)}`;
120
+ }
121
+ function authoredOperationId(operation) {
122
+ const value = operation.json();
123
+ if (typeof value === "object" &&
124
+ value !== null &&
125
+ "operationId" in value &&
126
+ typeof value.operationId === "string" &&
127
+ value.operationId.length > 0) {
128
+ return value.operationId;
129
+ }
130
+ return undefined;
131
+ }
132
+ function operationIdentityAndName(operation, operationChannelIdentity, asyncapiVersion) {
133
+ const pointer = operation.meta("pointer");
134
+ // AsyncAPI 2.6 without an authored operationId falls back to the parser action
135
+ // value such as "publish" or "subscribe", which collides across channels. Derive
136
+ // a collision-free identity from the exact channel identity plus authored role.
137
+ if (asyncapiVersion === "2.6.0" && authoredOperationId(operation) === undefined) {
138
+ const channel = operation.channels().all()[0];
139
+ if (channel !== undefined) {
140
+ const role = operation.action();
141
+ return {
142
+ identity: `operation:${operationChannelIdentity}:${role}`,
143
+ name: `${requireName(channel.id(), "operation channel", pointer)}-${role}`,
144
+ };
145
+ }
146
+ }
147
+ const name = operationName(operation);
148
+ return { identity: `operation:${name}`, name };
149
+ }
150
+ function operationName(operation) {
151
+ const id = operation.id();
152
+ if (typeof id === "string" && id.length > 0) {
153
+ return id;
154
+ }
155
+ const pointer = operation.meta("pointer");
156
+ return requireName(undefined, "operation", pointer);
157
+ }
158
+ function authoredSourceData(document, source) {
159
+ if (source !== undefined) {
160
+ return source.data;
161
+ }
162
+ const metadata = document.meta("asyncapi");
163
+ const input = metadata?.input;
164
+ return isRecord(input) || Array.isArray(input) ? input : undefined;
165
+ }
166
+ export function buildInteractionContract(document, source) {
167
+ const asyncapiVersion = requireVersion(document.version());
168
+ const authoredData = authoredSourceData(document, source);
169
+ const authoredReferences = collectAuthoredReferences(authoredData);
170
+ const schemaRegistry = createSchemaRegistry(document.components().schemas().all(), asyncapiVersion, authoredReferences);
171
+ const messageRegistry = {
172
+ messages: new Map(),
173
+ identityByObject: new WeakMap(),
174
+ identityByPointer: new Map(),
175
+ };
176
+ for (const message of document.components().messages().all()) {
177
+ const pointer = message.meta("pointer");
178
+ const name = requireName(message.id(), "component message", pointer);
179
+ registerMessage(messageRegistry, message, `message:component:${name}`, name, asyncapiVersion, schemaRegistry.createRole, undefined);
180
+ }
181
+ const channelIdentityByObject = new WeakMap();
182
+ const channelIdentityById = new Map();
183
+ const channels = [];
184
+ for (const channel of document.channels().all()) {
185
+ const identity = channelIdentity(channel);
186
+ const name = requireName(channel.id(), "channel", channel.meta("pointer"));
187
+ const object = parserObject(channel);
188
+ if (object !== undefined) {
189
+ channelIdentityByObject.set(object, identity);
190
+ }
191
+ channelIdentityById.set(name, identity);
192
+ const messageIdentities = channel
193
+ .messages()
194
+ .all()
195
+ .map((message) => {
196
+ const existing = existingMessageIdentity(messageRegistry, message);
197
+ if (existing !== undefined) {
198
+ return existing;
199
+ }
200
+ const pointer = message.meta("pointer");
201
+ return registerMessage(messageRegistry, message, `message:${identity}:${pointer}`, messageBaseName(message, pointer), asyncapiVersion, schemaRegistry.createRole, identity);
202
+ });
203
+ const parameters = channel
204
+ .parameters()
205
+ .all()
206
+ .map((parameter) => {
207
+ const schema = parameter.schema();
208
+ const description = parameter.description();
209
+ const location = parameter.location();
210
+ return Object.freeze({
211
+ name: requireName(parameter.id(), "channel parameter", parameter.meta("pointer")),
212
+ pointer: parameter.meta("pointer"),
213
+ ...(description === undefined ? {} : { description }),
214
+ ...(location === undefined ? {} : { location }),
215
+ ...(schema === undefined ? {} : { schema: schemaRegistry.createRole(schema) }),
216
+ });
217
+ });
218
+ const address = channel.address();
219
+ const description = channel.description();
220
+ channels.push(Object.freeze({
221
+ identity,
222
+ kind: "channel",
223
+ name,
224
+ pointer: channel.meta("pointer"),
225
+ asyncapiVersion,
226
+ ...(address === undefined ? {} : { address }),
227
+ ...(description === undefined ? {} : { description }),
228
+ parameters: Object.freeze([...parameters].sort((left, right) => left.name.localeCompare(right.name))),
229
+ messageIdentities: uniqueSorted(messageIdentities),
230
+ }));
231
+ }
232
+ const resolveChannelIdentity = (channel) => {
233
+ const object = parserObject(channel);
234
+ if (object !== undefined) {
235
+ const byObject = channelIdentityByObject.get(object);
236
+ if (byObject !== undefined) {
237
+ return byObject;
238
+ }
239
+ }
240
+ const byId = channelIdentityById.get(channel.id());
241
+ if (byId !== undefined) {
242
+ return byId;
243
+ }
244
+ throw new InteractionContractError("INTERACTION_REFERENCE_UNSUPPORTED", `The channel reference at ${channel.meta("pointer")} has no stable target.`, { pointer: channel.meta("pointer"), details: { referenceKind: "channel" } });
245
+ };
246
+ const resolveMessageIdentity = (message, ownerIdentity) => {
247
+ const existing = existingMessageIdentity(messageRegistry, message);
248
+ if (existing !== undefined) {
249
+ return existing;
250
+ }
251
+ const pointer = message.meta("pointer");
252
+ return registerMessage(messageRegistry, message, `message:${ownerIdentity}:${pointer}`, messageBaseName(message, pointer), asyncapiVersion, schemaRegistry.createRole, ownerIdentity);
253
+ };
254
+ const operations = [];
255
+ const replies = [];
256
+ for (const operation of document.operations().all()) {
257
+ const pointer = operation.meta("pointer");
258
+ const channel = operation.channels().all()[0];
259
+ if (channel === undefined) {
260
+ throw new InteractionContractError("INTERACTION_REFERENCE_UNSUPPORTED", `The operation at ${pointer} has no resolved channel.`, { pointer, details: { referenceKind: "channel" } });
261
+ }
262
+ const operationChannelIdentity = resolveChannelIdentity(channel);
263
+ const { identity, name } = operationIdentityAndName(operation, operationChannelIdentity, asyncapiVersion);
264
+ const messageIdentities = uniqueSorted(operation
265
+ .messages()
266
+ .all()
267
+ .map((message) => resolveMessageIdentity(message, operationChannelIdentity)));
268
+ const reply = operation.reply();
269
+ let replyIdentity;
270
+ if (reply !== undefined) {
271
+ replyIdentity = `reply:${identity}`;
272
+ const replyChannel = reply.channel();
273
+ const resolvedReplyChannelIdentity = replyChannel === undefined ? undefined : resolveChannelIdentity(replyChannel);
274
+ const explicitMessages = reply.messages().all();
275
+ const effectiveMessages = explicitMessages.length > 0
276
+ ? explicitMessages
277
+ : (replyChannel?.messages().all() ?? explicitMessages);
278
+ replies.push(Object.freeze({
279
+ identity: replyIdentity,
280
+ kind: "reply",
281
+ name: `${name}-reply`,
282
+ pointer: reply.meta("pointer"),
283
+ asyncapiVersion,
284
+ operationIdentity: identity,
285
+ ...(resolvedReplyChannelIdentity === undefined
286
+ ? {}
287
+ : { channelIdentity: resolvedReplyChannelIdentity }),
288
+ messageIdentities: uniqueSorted(effectiveMessages.map((message) => resolveMessageIdentity(message, replyIdentity ?? identity))),
289
+ }));
290
+ }
291
+ const description = operation.description();
292
+ const summary = operation.summary();
293
+ operations.push(Object.freeze({
294
+ identity,
295
+ kind: "operation",
296
+ name,
297
+ pointer,
298
+ asyncapiVersion,
299
+ action: normalizeAction(operation.action(), pointer),
300
+ channelIdentity: operationChannelIdentity,
301
+ messageIdentities,
302
+ ...(replyIdentity === undefined ? {} : { replyIdentity }),
303
+ ...(description === undefined ? {} : { description }),
304
+ ...(summary === undefined ? {} : { summary }),
305
+ }));
306
+ }
307
+ return Object.freeze({
308
+ asyncapiVersion,
309
+ schemas: schemaRegistry.roots,
310
+ messages: Object.freeze([...messageRegistry.messages.values()].sort((left, right) => left.identity.localeCompare(right.identity))),
311
+ channels: Object.freeze(channels.sort((left, right) => left.identity.localeCompare(right.identity))),
312
+ operations: Object.freeze(operations.sort((left, right) => left.identity.localeCompare(right.identity))),
313
+ replies: Object.freeze(replies.sort((left, right) => left.identity.localeCompare(right.identity))),
314
+ });
315
+ }
@@ -0,0 +1,12 @@
1
+ export type InteractionContractErrorCode = "INTERACTION_IDENTITY_MISSING" | "INTERACTION_REFERENCE_UNSUPPORTED" | "INTERACTION_VERSION_UNSUPPORTED";
2
+ export interface InteractionContractErrorOptions {
3
+ readonly pointer: string;
4
+ readonly details?: Readonly<Record<string, string>>;
5
+ }
6
+ export declare class InteractionContractError extends Error {
7
+ readonly code: InteractionContractErrorCode;
8
+ readonly pointer: string;
9
+ readonly details: Readonly<Record<string, string>>;
10
+ constructor(code: InteractionContractErrorCode, message: string, options: InteractionContractErrorOptions);
11
+ }
12
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/interaction/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,4BAA4B,GACpC,8BAA8B,GAC9B,mCAAmC,GACnC,iCAAiC,CAAC;AAEtC,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACrD;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;gBAGjD,IAAI,EAAE,4BAA4B,EAClC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,+BAA+B;CAQ3C"}
@@ -0,0 +1,12 @@
1
+ export class InteractionContractError extends Error {
2
+ code;
3
+ pointer;
4
+ details;
5
+ constructor(code, message, options) {
6
+ super(message);
7
+ this.name = "InteractionContractError";
8
+ this.code = code;
9
+ this.pointer = options.pointer;
10
+ this.details = Object.freeze({ ...options.details });
11
+ }
12
+ }
@@ -0,0 +1,9 @@
1
+ import type { SchemaInterface } from "@asyncapi/parser";
2
+ import type { InteractionAsyncAPIVersion, SchemaContract, SchemaRoleContract } from "./types.js";
3
+ export interface SchemaRegistry {
4
+ readonly roots: readonly SchemaContract[];
5
+ createRole(schema: SchemaInterface): SchemaRoleContract;
6
+ }
7
+ export type AuthoredReferenceIndex = ReadonlyMap<string, string>;
8
+ export declare function createSchemaRegistry(schemas: readonly SchemaInterface[], asyncapiVersion: InteractionAsyncAPIVersion, authoredReferences?: AuthoredReferenceIndex): SchemaRegistry;
9
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/interaction/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,KAAK,EACV,0BAA0B,EAC1B,cAAc,EAEd,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAOpB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAC1C,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,kBAAkB,CAAC;CACzD;AAED,MAAM,MAAM,sBAAsB,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AA6FjE,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,SAAS,eAAe,EAAE,EACnC,eAAe,EAAE,0BAA0B,EAC3C,kBAAkB,GAAE,sBAAkC,GACrD,cAAc,CA2HhB"}
@@ -0,0 +1,178 @@
1
+ import { InteractionContractError } from "./errors.js";
2
+ function isExternalReference(reference) {
3
+ return !reference.startsWith("#");
4
+ }
5
+ function parserObject(schema) {
6
+ const value = schema.json();
7
+ return typeof value === "object" && value !== null ? value : undefined;
8
+ }
9
+ function effectiveSchemaFormat(schema) {
10
+ const value = schema.json();
11
+ if (typeof value === "object" &&
12
+ value !== null &&
13
+ "schemaFormat" in value &&
14
+ typeof value.schemaFormat === "string") {
15
+ return value.schemaFormat;
16
+ }
17
+ return schema.schemaFormat();
18
+ }
19
+ function schemaChildren(schema) {
20
+ const children = [];
21
+ const append = (candidate) => {
22
+ if (candidate !== undefined) {
23
+ children.push(candidate);
24
+ }
25
+ };
26
+ const appendMany = (candidates) => {
27
+ if (candidates !== undefined) {
28
+ children.push(...candidates);
29
+ }
30
+ };
31
+ appendMany(schema.allOf());
32
+ appendMany(schema.anyOf());
33
+ appendMany(schema.oneOf());
34
+ append(schema.not());
35
+ append(schema.if());
36
+ append(schema.then());
37
+ append(schema.else());
38
+ append(schema.contains());
39
+ append(schema.propertyNames());
40
+ const items = schema.items();
41
+ if (Array.isArray(items)) {
42
+ appendMany(items);
43
+ }
44
+ else {
45
+ append(items);
46
+ }
47
+ const additionalItems = schema.additionalItems();
48
+ if (typeof additionalItems !== "boolean") {
49
+ append(additionalItems);
50
+ }
51
+ const additionalProperties = schema.additionalProperties();
52
+ if (typeof additionalProperties !== "boolean") {
53
+ append(additionalProperties);
54
+ }
55
+ const propertyGroups = [schema.properties(), schema.patternProperties(), schema.definitions()];
56
+ for (const group of propertyGroups) {
57
+ if (group !== undefined) {
58
+ children.push(...Object.values(group));
59
+ }
60
+ }
61
+ const dependencies = schema.dependencies();
62
+ if (dependencies !== undefined) {
63
+ for (const dependency of Object.values(dependencies)) {
64
+ if (!Array.isArray(dependency)) {
65
+ children.push(dependency);
66
+ }
67
+ }
68
+ }
69
+ return children;
70
+ }
71
+ function sortDependencies(dependencies) {
72
+ return Object.freeze([...dependencies.values()]
73
+ .sort((left, right) => left.targetIdentity.localeCompare(right.targetIdentity))
74
+ .map((dependency) => Object.freeze(dependency)));
75
+ }
76
+ export function createSchemaRegistry(schemas, asyncapiVersion, authoredReferences = new Map()) {
77
+ const identityByObject = new WeakMap();
78
+ const identityBySchemaId = new Map();
79
+ for (const schema of schemas) {
80
+ const name = schema.id();
81
+ const identity = `schema:component:${name}`;
82
+ const entry = Object.freeze({ identity, pointer: schema.meta("pointer") });
83
+ const object = parserObject(schema);
84
+ if (object !== undefined) {
85
+ identityByObject.set(object, entry);
86
+ }
87
+ identityBySchemaId.set(name, entry);
88
+ }
89
+ const findComponent = (schema) => {
90
+ const object = parserObject(schema);
91
+ if (object !== undefined) {
92
+ const byObject = identityByObject.get(object);
93
+ if (byObject !== undefined) {
94
+ return byObject;
95
+ }
96
+ }
97
+ return identityBySchemaId.get(schema.id());
98
+ };
99
+ // #17: fail closed when authored provenance proves this schema role originated
100
+ // from an external $ref and the resolved model maps to no stable component or
101
+ // owner-scoped local identity. Uses the already-retained pointer/URI only.
102
+ const assertProvenance = (schema, pointer) => {
103
+ const authoredReference = authoredReferences.get(pointer);
104
+ if (authoredReference === undefined || !isExternalReference(authoredReference)) {
105
+ return;
106
+ }
107
+ const target = findComponent(schema);
108
+ if (target === undefined) {
109
+ throw new InteractionContractError("INTERACTION_REFERENCE_UNSUPPORTED", `The schema reference at ${pointer} resolves to an unrepresentable external target.`, { pointer, details: { referenceKind: "schema", reference: authoredReference } });
110
+ }
111
+ };
112
+ const collectDependencies = (root) => {
113
+ const dependencies = new Map();
114
+ const visitedObjects = new WeakSet();
115
+ const visitedSchemas = new WeakSet();
116
+ const visit = (schema) => {
117
+ const object = parserObject(schema);
118
+ if (object === undefined) {
119
+ if (visitedSchemas.has(schema)) {
120
+ return;
121
+ }
122
+ visitedSchemas.add(schema);
123
+ }
124
+ else {
125
+ if (visitedObjects.has(object)) {
126
+ const target = findComponent(schema);
127
+ if (target !== undefined && !dependencies.has(target.identity)) {
128
+ dependencies.set(target.identity, Object.freeze({
129
+ targetIdentity: target.identity,
130
+ pointer: schema.meta("pointer"),
131
+ }));
132
+ }
133
+ return;
134
+ }
135
+ visitedObjects.add(object);
136
+ }
137
+ for (const child of schemaChildren(schema)) {
138
+ const target = findComponent(child);
139
+ if (target !== undefined && !dependencies.has(target.identity)) {
140
+ dependencies.set(target.identity, Object.freeze({
141
+ targetIdentity: target.identity,
142
+ pointer: child.meta("pointer"),
143
+ }));
144
+ }
145
+ visit(child);
146
+ }
147
+ };
148
+ visit(root);
149
+ return sortDependencies(dependencies);
150
+ };
151
+ const createRole = (schema) => {
152
+ const pointer = schema.meta("pointer");
153
+ assertProvenance(schema, pointer);
154
+ return Object.freeze({
155
+ pointer,
156
+ schemaFormat: effectiveSchemaFormat(schema),
157
+ schema,
158
+ dependencies: collectDependencies(schema),
159
+ });
160
+ };
161
+ const roots = Object.freeze([...schemas]
162
+ .map((schema) => {
163
+ const name = schema.id();
164
+ const role = createRole(schema);
165
+ return Object.freeze({
166
+ identity: `schema:component:${name}`,
167
+ kind: "schema",
168
+ name,
169
+ pointer: role.pointer,
170
+ asyncapiVersion,
171
+ schemaFormat: role.schemaFormat,
172
+ schema: role.schema,
173
+ dependencies: role.dependencies,
174
+ });
175
+ })
176
+ .sort((left, right) => left.identity.localeCompare(right.identity)));
177
+ return Object.freeze({ roots, createRole });
178
+ }
@@ -0,0 +1,69 @@
1
+ import type { SchemaInterface } from "@asyncapi/parser";
2
+ export type InteractionAsyncAPIVersion = "2.6.0" | "3.0.0" | "3.1.0";
3
+ export type InteractionAction = "send" | "receive";
4
+ export type InteractionRootKind = "schema" | "message" | "channel" | "operation" | "reply";
5
+ export interface InteractionRootMetadata {
6
+ readonly identity: string;
7
+ readonly kind: InteractionRootKind;
8
+ readonly name: string;
9
+ readonly pointer: string;
10
+ readonly asyncapiVersion: InteractionAsyncAPIVersion;
11
+ }
12
+ export interface SchemaDependencyContract {
13
+ readonly targetIdentity: string;
14
+ readonly pointer: string;
15
+ }
16
+ export interface SchemaRoleContract {
17
+ readonly pointer: string;
18
+ readonly schemaFormat: string;
19
+ readonly schema: SchemaInterface;
20
+ readonly dependencies: readonly SchemaDependencyContract[];
21
+ }
22
+ export interface SchemaContract extends InteractionRootMetadata, SchemaRoleContract {
23
+ readonly kind: "schema";
24
+ }
25
+ export interface MessageContract extends InteractionRootMetadata {
26
+ readonly kind: "message";
27
+ readonly ownerIdentity?: string;
28
+ readonly description?: string;
29
+ readonly payload?: SchemaRoleContract;
30
+ readonly headers?: SchemaRoleContract;
31
+ }
32
+ export interface ChannelParameterContract {
33
+ readonly name: string;
34
+ readonly pointer: string;
35
+ readonly description?: string;
36
+ readonly location?: string;
37
+ readonly schema?: SchemaRoleContract;
38
+ }
39
+ export interface ChannelContract extends InteractionRootMetadata {
40
+ readonly kind: "channel";
41
+ readonly address?: string | null;
42
+ readonly description?: string;
43
+ readonly parameters: readonly ChannelParameterContract[];
44
+ readonly messageIdentities: readonly string[];
45
+ }
46
+ export interface ReplyContract extends InteractionRootMetadata {
47
+ readonly kind: "reply";
48
+ readonly operationIdentity: string;
49
+ readonly channelIdentity?: string;
50
+ readonly messageIdentities: readonly string[];
51
+ }
52
+ export interface OperationContract extends InteractionRootMetadata {
53
+ readonly kind: "operation";
54
+ readonly action: InteractionAction;
55
+ readonly description?: string;
56
+ readonly summary?: string;
57
+ readonly channelIdentity: string;
58
+ readonly messageIdentities: readonly string[];
59
+ readonly replyIdentity?: string;
60
+ }
61
+ export interface InteractionContract {
62
+ readonly asyncapiVersion: InteractionAsyncAPIVersion;
63
+ readonly schemas: readonly SchemaContract[];
64
+ readonly messages: readonly MessageContract[];
65
+ readonly channels: readonly ChannelContract[];
66
+ readonly operations: readonly OperationContract[];
67
+ readonly replies: readonly ReplyContract[];
68
+ }
69
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/interaction/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -2,7 +2,7 @@ import type { GeneratedArtifact } from "./types.js";
2
2
  export declare class ArtifactStore {
3
3
  private readonly artifacts;
4
4
  private readonly paths;
5
- emit(artifact: GeneratedArtifact): void;
5
+ add(artifact: GeneratedArtifact): void;
6
6
  snapshot(): readonly GeneratedArtifact[];
7
7
  }
8
8
  //# sourceMappingURL=artifacts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../src/orchestrator/artifacts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAkBpD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2B;IACrD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAE3C,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAkBvC,QAAQ,IAAI,SAAS,iBAAiB,EAAE;CAGzC"}
1
+ {"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../src/orchestrator/artifacts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAkBpD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2B;IACrD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAE3C,GAAG,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAkBtC,QAAQ,IAAI,SAAS,iBAAiB,EAAE;CAGzC"}
@@ -14,7 +14,7 @@ function isCanonicalArtifactPath(path) {
14
14
  export class ArtifactStore {
15
15
  artifacts = [];
16
16
  paths = new Set();
17
- emit(artifact) {
17
+ add(artifact) {
18
18
  if (!isCanonicalArtifactPath(artifact.path)) {
19
19
  throw new ArtifactError("invalid-path", artifact.path);
20
20
  }
@@ -1,18 +1,3 @@
1
- import type { PluginExecutionPhase } from "./types.js";
2
- export type PluginConfigurationErrorCode = "empty-name" | "duplicate-name" | "missing-dependency" | "dependency-cycle";
3
- export declare class PluginConfigurationError extends Error {
4
- readonly name = "PluginConfigurationError";
5
- readonly code: PluginConfigurationErrorCode;
6
- readonly pluginNames: readonly string[];
7
- constructor(code: PluginConfigurationErrorCode, message: string, pluginNames?: readonly string[]);
8
- }
9
- export type ServiceRegistryErrorCode = "duplicate-service" | "missing-service";
10
- export declare class ServiceRegistryError extends Error {
11
- readonly name = "ServiceRegistryError";
12
- readonly code: ServiceRegistryErrorCode;
13
- readonly serviceName: string;
14
- constructor(code: ServiceRegistryErrorCode, serviceName: string);
15
- }
16
1
  export type ArtifactErrorCode = "invalid-path" | "path-collision";
17
2
  export declare class ArtifactError extends Error {
18
3
  readonly name = "ArtifactError";
@@ -23,7 +8,6 @@ export declare class ArtifactError extends Error {
23
8
  export declare class PluginExecutionError extends Error {
24
9
  readonly name = "PluginExecutionError";
25
10
  readonly pluginName: string;
26
- readonly phase: PluginExecutionPhase;
27
- constructor(pluginName: string, phase: PluginExecutionPhase, cause: unknown);
11
+ constructor(pluginName: string, cause: unknown);
28
12
  }
29
13
  //# sourceMappingURL=errors.d.ts.map