@acid-cat/spec-ts 0.3.1 → 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 +2 -1
- package/dist/index.d.ts +14 -4
- package/dist/index.js +39 -14
- package/package.json +1 -1
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
|
|
29
|
-
export declare const fail: <
|
|
30
|
-
readonly _tag:
|
|
31
|
-
}
|
|
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. */
|
|
@@ -151,6 +153,14 @@ export declare function visitObjects(value: unknown, onObject: (node: JsonObject
|
|
|
151
153
|
export declare function typesUsedBy(schema: unknown, types: {
|
|
152
154
|
readonly [name: string]: JsonObject;
|
|
153
155
|
}): Map<string, JsonObject>;
|
|
156
|
+
/**
|
|
157
|
+
* An input schema that is a union of object schemas, with `"type": "object"`, so that it is an object schema
|
|
158
|
+
* (spec/catalog.md#capabilities). A union is `anyOf` or `oneOf`, directly or in the type that a `$ref` names. Each of
|
|
159
|
+
* its schemas is an object, or a `$ref` to a type that is an object. Other schemas do not change.
|
|
160
|
+
*/
|
|
161
|
+
export declare function objectInput(schema: JsonObject, types: {
|
|
162
|
+
readonly [name: string]: JsonObject;
|
|
163
|
+
}): JsonObject;
|
|
154
164
|
/** Bundle a schema (spec/catalog.md#bundling). */
|
|
155
165
|
export declare function bundle(schema: JsonObject, types: {
|
|
156
166
|
readonly [name: string]: JsonObject;
|
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
|
|
23
|
-
const fail = (
|
|
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
|
|
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]) ??
|
|
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
|
|
205
|
+
else if (isJsonObject(value)) {
|
|
202
206
|
onObject(value);
|
|
203
207
|
Object.values(value).forEach((item) => visitObjects(item, onObject));
|
|
204
208
|
}
|
|
@@ -217,6 +221,27 @@ function typesUsedBy(schema, types) {
|
|
|
217
221
|
collect(schema);
|
|
218
222
|
return used;
|
|
219
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* An input schema that is a union of object schemas, with `"type": "object"`, so that it is an object schema
|
|
226
|
+
* (spec/catalog.md#capabilities). A union is `anyOf` or `oneOf`, directly or in the type that a `$ref` names. Each of
|
|
227
|
+
* its schemas is an object, or a `$ref` to a type that is an object. Other schemas do not change.
|
|
228
|
+
*/
|
|
229
|
+
function objectInput(schema, types) {
|
|
230
|
+
const resolve = (node) => {
|
|
231
|
+
if (!isJsonObject(node)) return void 0;
|
|
232
|
+
const object = node;
|
|
233
|
+
const name = typeof object.$ref === "string" ? REFERENCE.exec(object.$ref)?.[1] : void 0;
|
|
234
|
+
return name === void 0 ? object : types[name];
|
|
235
|
+
};
|
|
236
|
+
const target = resolve(schema);
|
|
237
|
+
if (schema.type !== void 0 || target === void 0 || target.type !== void 0) return schema;
|
|
238
|
+
const union = target.anyOf ?? target.oneOf;
|
|
239
|
+
if (!Array.isArray(union) || union.length === 0) return schema;
|
|
240
|
+
return union.every((member) => resolve(member)?.type === "object") ? {
|
|
241
|
+
type: "object",
|
|
242
|
+
...schema
|
|
243
|
+
} : schema;
|
|
244
|
+
}
|
|
220
245
|
/** Bundle a schema (spec/catalog.md#bundling). */
|
|
221
246
|
function bundle(schema, types) {
|
|
222
247
|
const only = Object.keys(schema).length === 1 ? REFERENCE.exec(String(schema.$ref))?.[1] : void 0;
|
|
@@ -246,4 +271,4 @@ function viewOf(catalog, target) {
|
|
|
246
271
|
};
|
|
247
272
|
}
|
|
248
273
|
//#endregion
|
|
249
|
-
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, 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.
|
|
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",
|