@acid-cat/spec-ts 0.4.0 → 0.5.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/README.md CHANGED
@@ -12,7 +12,8 @@ pnpm add @acid-cat/spec-ts
12
12
 
13
13
  | Export | Use |
14
14
  | --- | --- |
15
- | `ok`, `fail`, `callFailure`, `isCallFailure` | Make and test [outcomes](../../spec/invocation.md#outcomes) |
15
+ | `ok`, `fail`, `callFailure`, `isCallFailure` | Make and test [outcomes](../../spec/invocation.md#outcomes). `fail` takes the whole failure: `fail({ _tag: "Offline", since })` |
16
+ | `isJsonObject` | Tell if a value is a JSON object: not `null`, and not an array |
16
17
  | `CALL_FAILURE_KINDS`, `CallFailureError` | The kinds of call failure, and the JavaScript error for one |
17
18
  | `AVAILABLE`, `unavailable` | Make [availability](../../spec/invocation.md#availability) values |
18
19
  | `viewOf`, `bundle` | The [view](../../spec/catalog.md#views) of a target, and a schema with its shared types |
package/dist/index.d.ts CHANGED
@@ -25,10 +25,10 @@ export type Result<Value, Failure> = {
25
25
  /** The end of a call: a value, a failure or a call failure. */
26
26
  export type Outcome<Value, Failure> = Result<Value, Failure> | CallFailure;
27
27
  export declare const ok: <Value>(value: Value) => Result<Value, never>;
28
- /** A failure with its tag, as a result. */
29
- export declare const fail: <Tag extends string, Data extends object = {}>(tag: Tag, data?: Data) => Result<never, {
30
- readonly _tag: Tag;
31
- } & Data>;
28
+ /** A failure, with its tag in `_tag`, as a result: `fail({ _tag: "Offline" })`. */
29
+ export declare const fail: <const Failure extends {
30
+ readonly _tag: string;
31
+ }>(failure: Failure) => Result<never, Failure>;
32
32
  export declare const callFailure: (kind: CallFailureKind, message: string) => CallFailure;
33
33
  export declare const isCallFailure: (outcome: Outcome<unknown, unknown>) => outcome is CallFailure;
34
34
  /** The JavaScript error for a call failure (spec/bindings/typescript.md#handles). */
@@ -143,6 +143,8 @@ export interface CatalogDocument extends JsonObject {
143
143
  };
144
144
  }
145
145
  export declare const REFERENCE: RegExp;
146
+ /** Tell if a value is a JSON object: an object that is not `null` and not an array. */
147
+ export declare const isJsonObject: (value: unknown) => value is JsonObject;
146
148
  /** The schemas of a capability, each with the member that holds it. */
147
149
  export declare function schemasOf(capability: CatalogCapability): readonly (readonly [string, JsonObject])[];
148
150
  /** Every object in a JSON value, at all levels. */
package/dist/index.js CHANGED
@@ -19,13 +19,10 @@ const ok = (value) => ({
19
19
  ok: true,
20
20
  value
21
21
  });
22
- /** A failure with its tag, as a result. */
23
- const fail = (tag, data) => ({
22
+ /** A failure, with its tag in `_tag`, as a result: `fail({ _tag: "Offline" })`. */
23
+ const fail = (failure) => ({
24
24
  ok: false,
25
- error: {
26
- _tag: tag,
27
- ...data ?? {}
28
- }
25
+ error: failure
29
26
  });
30
27
  const callFailure = (kind, message) => ({
31
28
  kind,
@@ -65,15 +62,16 @@ const cliExitCode = (outcome) => isCallFailure(outcome) ? CLI_EXIT_CODES[outcome
65
62
  * code point order of the names. `input` is the bundled input schema.
66
63
  */
67
64
  function cliFlags(input) {
68
- const properties = input.properties ?? {};
69
- const definitions = input.$defs ?? {};
70
- const required = new Set(input.required ?? []);
65
+ const properties = objectOrEmpty(input.properties);
66
+ const definitions = objectOrEmpty(input.$defs);
67
+ const required = new Set(stringsOf(input.required));
71
68
  const byName = (a, b) => a < b ? -1 : a > b ? 1 : 0;
72
69
  const names = Object.keys(properties).sort(byName);
73
70
  return [...names.filter((name) => required.has(name)), ...names.filter((name) => !required.has(name))].map((name) => {
74
- const reference = properties[name].$ref;
71
+ const declared = objectOrEmpty(properties[name]);
72
+ const reference = declared.$ref;
75
73
  const target = typeof reference === "string" ? REFERENCE.exec(reference)?.[1] : void 0;
76
- const property = (target === void 0 ? void 0 : definitions[target]) ?? properties[name];
74
+ const property = objectOrEmpty((target === void 0 ? void 0 : definitions[target]) ?? declared);
77
75
  const flag = property.type === "boolean" ? `--${name}` : `--${name} <${flagValue(property)}>`;
78
76
  return required.has(name) ? flag : `[${flag}]`;
79
77
  });
@@ -112,7 +110,7 @@ function screenRequest(request, rules) {
112
110
  const origin = request.headers.get("Origin");
113
111
  if (origin !== null && !rules.allowedOrigins.includes(origin)) return "origin";
114
112
  if (request.method === "GET" || request.method === "HEAD") return void 0;
115
- if ((request.headers.get("Content-Type") ?? "").split(";")[0].trim().toLowerCase() !== rules.mediaType) return "media-type";
113
+ if (((request.headers.get("Content-Type") ?? "").split(";")[0] ?? "").trim().toLowerCase() !== rules.mediaType) return "media-type";
116
114
  const declared = Number(request.headers.get("Content-Length") ?? "");
117
115
  if (Number.isFinite(declared) && declared > rules.maximumBytes) return "too-large";
118
116
  }
@@ -186,6 +184,12 @@ function mcpToolResult(outcome, hasOutputSchema) {
186
184
  } : { content: text(outcome.value) };
187
185
  }
188
186
  const REFERENCE = /^#\/\$defs\/([A-Za-z][A-Za-z0-9_]*)$/;
187
+ /** Tell if a value is a JSON object: an object that is not `null` and not an array. */
188
+ const isJsonObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
189
+ /** A value as a JSON object, or an empty object when it is not one. */
190
+ const objectOrEmpty = (value) => isJsonObject(value) ? value : {};
191
+ /** The strings in a value that is an array, or no strings when it is not an array. */
192
+ const stringsOf = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
189
193
  /** The schemas of a capability, each with the member that holds it. */
190
194
  function schemasOf(capability) {
191
195
  return [
@@ -198,7 +202,7 @@ function schemasOf(capability) {
198
202
  /** Every object in a JSON value, at all levels. */
199
203
  function visitObjects(value, onObject) {
200
204
  if (Array.isArray(value)) value.forEach((item) => visitObjects(item, onObject));
201
- else if (value !== null && typeof value === "object") {
205
+ else if (isJsonObject(value)) {
202
206
  onObject(value);
203
207
  Object.values(value).forEach((item) => visitObjects(item, onObject));
204
208
  }
@@ -224,7 +228,7 @@ function typesUsedBy(schema, types) {
224
228
  */
225
229
  function objectInput(schema, types) {
226
230
  const resolve = (node) => {
227
- if (node === null || typeof node !== "object" || Array.isArray(node)) return void 0;
231
+ if (!isJsonObject(node)) return void 0;
228
232
  const object = node;
229
233
  const name = typeof object.$ref === "string" ? REFERENCE.exec(object.$ref)?.[1] : void 0;
230
234
  return name === void 0 ? object : types[name];
@@ -267,4 +271,4 @@ function viewOf(catalog, target) {
267
271
  };
268
272
  }
269
273
  //#endregion
270
- export { AVAILABLE, CALL_FAILURE_KINDS, CLI_EXIT_CODES, CallFailureError, HTTP_STATUS, ID_PATTERN, MCP_PROTOCOL_VERSION, MCP_REJECTIONS, MCP_UNKNOWN_TOOL, REFERENCE, bundle, callFailure, cliExitCode, cliFlags, cliUsage, commandPath, fail, httpStatus, isCallFailure, isId, mcpToolResult, objectInput, ok, readBounded, schemasOf, screenRequest, typesUsedBy, unavailable, viewOf, visitObjects };
274
+ export { AVAILABLE, CALL_FAILURE_KINDS, CLI_EXIT_CODES, CallFailureError, HTTP_STATUS, ID_PATTERN, MCP_PROTOCOL_VERSION, MCP_REJECTIONS, MCP_UNKNOWN_TOOL, REFERENCE, bundle, callFailure, cliExitCode, cliFlags, cliUsage, commandPath, fail, httpStatus, isCallFailure, isId, isJsonObject, mcpToolResult, objectInput, ok, readBounded, schemasOf, screenRequest, typesUsedBy, unavailable, viewOf, visitObjects };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acid-cat/spec-ts",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
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",