@acid-cat/spec-ts 0.10.0 → 0.10.2

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/README.md CHANGED
@@ -17,5 +17,8 @@ pnpm add @acid-cat/spec-ts
17
17
  | `CALL_FAILURE_KINDS`, `CallFailureError` | The kinds of call failure, and the JavaScript error for one |
18
18
  | `AVAILABLE`, `unavailable` | Make [availability](../../spec/invocation.md#availability) values |
19
19
  | `viewOf`, `bundle` | The [view](../../spec/catalog.md#views) of a target, and a schema with its shared types |
20
+ | `resolveType` | The type that the `$ref` of a schema refers to, whatever other keys the schema has |
21
+ | `ownMember` | The member of an object with a key, or `undefined`. Inherited names, such as `constructor`, are not members |
22
+ | `byCodePoint` | Order strings by Unicode code point, as the [canonical form](../../spec/catalog.md#canonical-form) sorts keys |
20
23
 
21
24
  The other exports give the names, flags, exit codes and tool shapes of each [binding](../../spec/bindings/README.md).
package/dist/index.d.ts CHANGED
@@ -202,6 +202,11 @@ export declare function mcpSubscribeError(failure: CallFailure): {
202
202
  export declare function mcpEventEntry(id: string, description: string, input: JsonObject | undefined, payload: JsonObject | undefined, webhook?: boolean): JsonObject;
203
203
  /** The params of `notifications/events/event` for an occurrence: the occurrence without `truncated`. */
204
204
  export declare function mcpEventParams(occurrence: Occurrence, subscriptionId: string | number): JsonObject;
205
+ /**
206
+ * Order strings by Unicode code point. The `<` operator compares UTF-16 code units, which put a character after U+FFFF
207
+ * before a character from U+E000 to U+FFFF.
208
+ */
209
+ export declare function byCodePoint(left: string, right: string): number;
205
210
  /** The canonical JSON of a value (spec/bindings/mcp.md#canonical-json): no spaces, and the keys of each object in code point order. */
206
211
  export declare function canonicalJson(value: unknown): string;
207
212
  /** The defaults of poll delivery (spec/bindings/mcp.md#poll). */
@@ -304,6 +309,13 @@ export interface CatalogDocument extends JsonObject {
304
309
  export declare const REFERENCE: RegExp;
305
310
  /** Tell if a value is a JSON object: an object that is not `null` and not an array. */
306
311
  export declare const isJsonObject: (value: unknown) => value is JsonObject;
312
+ /**
313
+ * The member of an object with this key, or `undefined` when the object does not have it. Inherited names, such as
314
+ * `constructor` or `toString`, are not members.
315
+ */
316
+ export declare function ownMember<Value>(object: {
317
+ readonly [key: string]: Value;
318
+ }, key: string): Value | undefined;
307
319
  /** The schemas of a capability, each with the member that holds it. */
308
320
  export declare function schemasOf(capability: CatalogCapability): readonly (readonly [string, JsonObject])[];
309
321
  /** The schemas of an event, each with the member that holds it. */
@@ -322,6 +334,14 @@ export declare function typesUsedBy(schema: unknown, types: {
322
334
  export declare function objectInput(schema: JsonObject, types: {
323
335
  readonly [name: string]: JsonObject;
324
336
  }): JsonObject;
337
+ /**
338
+ * The type that a schema's `$ref` refers to, whatever other keys the schema has, or the schema itself when it has no
339
+ * `$ref` to a type in `types`. A catalog uses it to tell if an input or a payload is an object
340
+ * (spec/catalog.md#capabilities).
341
+ */
342
+ export declare function resolveType(schema: JsonObject, types: {
343
+ readonly [name: string]: JsonObject;
344
+ }): JsonObject;
325
345
  /** Bundle a schema (spec/catalog.md#bundling). */
326
346
  export declare function bundle(schema: JsonObject, types: {
327
347
  readonly [name: string]: JsonObject;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/index.ts
1
+ // src/index.ts
2
2
  /**
3
3
  * The fixed details of the AcidCat specification, as TypeScript data and pure functions, for the TypeScript reference
4
4
  * implementation. This package has no dependencies.
@@ -101,8 +101,7 @@ function cliFlags(input) {
101
101
  const properties = objectOrEmpty(input.properties);
102
102
  const definitions = objectOrEmpty(input.$defs);
103
103
  const required = new Set(stringsOf(input.required));
104
- const byName = (a, b) => a < b ? -1 : a > b ? 1 : 0;
105
- const names = Object.keys(properties).sort(byName);
104
+ const names = Object.keys(properties).sort(byCodePoint);
106
105
  return [...names.filter((name) => required.has(name)), ...names.filter((name) => !required.has(name))].map((name) => {
107
106
  const property = cliResolve(objectOrEmpty(properties[name]), definitions);
108
107
  const items = cliRepeatedItems(property, definitions);
@@ -112,8 +111,8 @@ function cliFlags(input) {
112
111
  }
113
112
  /** A property schema, or the type in `definitions` that its `$ref` refers to. */
114
113
  function cliResolve(property, definitions) {
115
- const target = typeof property.$ref === "string" ? REFERENCE.exec(property.$ref)?.[1] : void 0;
116
- return target === void 0 ? property : objectOrEmpty(definitions[target] ?? property);
114
+ const target = referenceName(property);
115
+ return target === void 0 ? property : objectOrEmpty(ownMember(definitions, target) ?? property);
117
116
  }
118
117
  /**
119
118
  * The schema of the items of a repeated flag (spec/bindings/cli.md#commands), or `undefined` when the property does
@@ -328,10 +327,23 @@ function mcpEventParams(occurrence, subscriptionId) {
328
327
  _meta: { [MCP_SUBSCRIPTION_ID]: subscriptionId }
329
328
  };
330
329
  }
330
+ /**
331
+ * Order strings by Unicode code point. The `<` operator compares UTF-16 code units, which put a character after U+FFFF
332
+ * before a character from U+E000 to U+FFFF.
333
+ */
334
+ function byCodePoint(left, right) {
335
+ const a = Array.from(left, (character) => character.codePointAt(0) ?? 0);
336
+ const b = Array.from(right, (character) => character.codePointAt(0) ?? 0);
337
+ for (let i = 0; i < Math.min(a.length, b.length); i += 1) {
338
+ const difference = (a[i] ?? 0) - (b[i] ?? 0);
339
+ if (difference !== 0) return difference;
340
+ }
341
+ return a.length - b.length;
342
+ }
331
343
  /** The canonical JSON of a value (spec/bindings/mcp.md#canonical-json): no spaces, and the keys of each object in code point order. */
332
344
  function canonicalJson(value) {
333
345
  if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
334
- if (isJsonObject(value)) return `{${Object.keys(value).sort((a, b) => a < b ? -1 : a > b ? 1 : 0).map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
346
+ if (isJsonObject(value)) return `{${Object.keys(value).sort(byCodePoint).map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
335
347
  return JSON.stringify(value) ?? "null";
336
348
  }
337
349
  /** The defaults of poll delivery (spec/bindings/mcp.md#poll). */
@@ -552,8 +564,17 @@ function mcpToolResult(outcome, hasOutputSchema) {
552
564
  } : { content: text(outcome.value) };
553
565
  }
554
566
  const REFERENCE = /^#\/\$defs\/([A-Za-z][A-Za-z0-9_]*)$/;
567
+ /** The name of the type that a schema's `$ref` refers to, or `undefined` when it has no `$ref` of that form. */
568
+ const referenceName = (schema) => typeof schema.$ref === "string" ? REFERENCE.exec(schema.$ref)?.[1] : void 0;
555
569
  /** Tell if a value is a JSON object: an object that is not `null` and not an array. */
556
570
  const isJsonObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
571
+ /**
572
+ * The member of an object with this key, or `undefined` when the object does not have it. Inherited names, such as
573
+ * `constructor` or `toString`, are not members.
574
+ */
575
+ function ownMember(object, key) {
576
+ return Object.hasOwn(object, key) ? object[key] : void 0;
577
+ }
557
578
  /** A value as a JSON object, or an empty object when it is not one. */
558
579
  const objectOrEmpty = (value) => isJsonObject(value) ? value : {};
559
580
  /** The strings in a value that is an array, or no strings when it is not an array. */
@@ -583,8 +604,8 @@ function visitObjects(value, onObject) {
583
604
  function typesUsedBy(schema, types) {
584
605
  const used = /* @__PURE__ */ new Map();
585
606
  const collect = (node) => visitObjects(node, (inner) => {
586
- const name = typeof inner.$ref === "string" ? REFERENCE.exec(inner.$ref)?.[1] : void 0;
587
- const type = name === void 0 ? void 0 : types[name];
607
+ const name = referenceName(inner);
608
+ const type = name === void 0 ? void 0 : ownMember(types, name);
588
609
  if (name !== void 0 && type !== void 0 && !used.has(name)) {
589
610
  used.set(name, type);
590
611
  collect(type);
@@ -601,9 +622,8 @@ function typesUsedBy(schema, types) {
601
622
  function objectInput(schema, types) {
602
623
  const resolve = (node) => {
603
624
  if (!isJsonObject(node)) return void 0;
604
- const object = node;
605
- const name = typeof object.$ref === "string" ? REFERENCE.exec(object.$ref)?.[1] : void 0;
606
- return name === void 0 ? object : types[name];
625
+ const name = referenceName(node);
626
+ return name === void 0 ? node : ownMember(types, name);
607
627
  };
608
628
  const target = resolve(schema);
609
629
  if (schema.type !== void 0 || target === void 0 || target.type !== void 0) return schema;
@@ -614,10 +634,18 @@ function objectInput(schema, types) {
614
634
  ...schema
615
635
  } : schema;
616
636
  }
637
+ /**
638
+ * The type that a schema's `$ref` refers to, whatever other keys the schema has, or the schema itself when it has no
639
+ * `$ref` to a type in `types`. A catalog uses it to tell if an input or a payload is an object
640
+ * (spec/catalog.md#capabilities).
641
+ */
642
+ function resolveType(schema, types) {
643
+ const name = referenceName(schema);
644
+ return (name === void 0 ? void 0 : ownMember(types, name)) ?? schema;
645
+ }
617
646
  /** Bundle a schema (spec/catalog.md#bundling). */
618
647
  function bundle(schema, types) {
619
- const only = Object.keys(schema).length === 1 ? REFERENCE.exec(String(schema.$ref))?.[1] : void 0;
620
- const base = only === void 0 ? schema : types[only] ?? schema;
648
+ const base = Object.keys(schema).length === 1 ? resolveType(schema, types) : schema;
621
649
  const used = typesUsedBy(base, types);
622
650
  return used.size === 0 ? base : {
623
651
  ...base,
@@ -639,7 +667,7 @@ function viewOf(catalog, target) {
639
667
  const schemas = [...Object.values(capabilities).flatMap(schemasOf), ...Object.values(events).flatMap(eventSchemasOf)];
640
668
  for (const [, schema] of schemas) for (const [name, type] of typesUsedBy(schema, types)) used.set(name, type);
641
669
  const { $defs: _, events: __, ...rest } = catalog;
642
- const declared = catalog.targets[target];
670
+ const declared = ownMember(catalog.targets, target);
643
671
  return {
644
672
  ...rest,
645
673
  targets: declared === void 0 ? {} : { [target]: declared },
@@ -648,5 +676,4 @@ function viewOf(catalog, target) {
648
676
  ...Object.keys(events).length > 0 ? { events } : {}
649
677
  };
650
678
  }
651
- //#endregion
652
- export { AVAILABLE, CALL_FAILURE_KINDS, CLI_EXIT_CODES, CLI_RESUME_FLAGS, CLI_WATCH_EXIT_CODES, CallFailureError, HTTP_STATUS, ID_PATTERN, KEEPALIVE_MS, MCP_EVENTS_EXTENSION, MCP_EVENT_ERRORS, MCP_POLL_DEFAULTS, MCP_PROTOCOL_VERSION, MCP_REJECTIONS, MCP_SUBSCRIPTION_ID, MCP_UNKNOWN_TOOL, MCP_WEBHOOK_DEFAULTS, REFERENCE, SSE_MEDIA_TYPE, SUBSCRIBE_FAILURE_KINDS, WEBHOOK_ERRORS, bundle, callFailure, canonicalJson, cliEventUsage, cliExitCode, cliFlags, cliJsonArray, cliRepeatedItems, cliResolve, cliUsage, commandPath, decodePollCursor, encodePollCursor, eventSchemasOf, fail, httpEventMessage, httpStatus, isCallFailure, isGloballyRoutable, isId, isJsonObject, isOccurrence, mcpEventEntry, mcpEventParams, mcpSubscribeError, mcpToolResult, objectInput, occurrenceOf, ok, readBounded, schemasOf, screenRequest, sseMessage, typesUsedBy, unavailable, viewOf, visitObjects, webhookGrantMs, webhookSecretBytes, webhookSignature, webhookSignedText, webhookSubscriptionId };
679
+ export { AVAILABLE, CALL_FAILURE_KINDS, CLI_EXIT_CODES, CLI_RESUME_FLAGS, CLI_WATCH_EXIT_CODES, CallFailureError, HTTP_STATUS, ID_PATTERN, KEEPALIVE_MS, MCP_EVENTS_EXTENSION, MCP_EVENT_ERRORS, MCP_POLL_DEFAULTS, MCP_PROTOCOL_VERSION, MCP_REJECTIONS, MCP_SUBSCRIPTION_ID, MCP_UNKNOWN_TOOL, MCP_WEBHOOK_DEFAULTS, REFERENCE, SSE_MEDIA_TYPE, SUBSCRIBE_FAILURE_KINDS, WEBHOOK_ERRORS, bundle, byCodePoint, callFailure, canonicalJson, cliEventUsage, cliExitCode, cliFlags, cliJsonArray, cliRepeatedItems, cliResolve, cliUsage, commandPath, decodePollCursor, encodePollCursor, eventSchemasOf, fail, httpEventMessage, httpStatus, isCallFailure, isGloballyRoutable, isId, isJsonObject, isOccurrence, mcpEventEntry, mcpEventParams, mcpSubscribeError, mcpToolResult, objectInput, occurrenceOf, ok, ownMember, readBounded, resolveType, schemasOf, screenRequest, sseMessage, typesUsedBy, unavailable, viewOf, visitObjects, webhookGrantMs, webhookSecretBytes, webhookSignature, webhookSignedText, webhookSubscriptionId };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acid-cat/spec-ts",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "The fixed details of the AcidCat specification as TypeScript data and pure functions, with no dependencies. Part of the TypeScript reference implementation.",
5
5
  "keywords": [
6
6
  "acidcat",
@@ -31,7 +31,7 @@
31
31
  "access": "public"
32
32
  },
33
33
  "devDependencies": {
34
- "@types/node": "26.6.5",
34
+ "@types/node": "26.6.6",
35
35
  "typescript": "7.0.2"
36
36
  }
37
37
  }