@ankhorage/api 0.2.0 → 0.3.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 +6 -0
- package/dist/api.d.ts +2 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +2 -0
- package/dist/api.js.map +1 -1
- package/dist/capabilities/index.d.ts +8 -0
- package/dist/capabilities/index.d.ts.map +1 -0
- package/dist/capabilities/index.js +8 -0
- package/dist/capabilities/index.js.map +1 -0
- package/dist/features/execution/projectApiCapabilities.d.ts +5 -0
- package/dist/features/execution/projectApiCapabilities.d.ts.map +1 -0
- package/dist/features/execution/projectApiCapabilities.js +105 -0
- package/dist/features/execution/projectApiCapabilities.js.map +1 -0
- package/package.json +7 -3
package/CHANGELOG.md
CHANGED
package/dist/api.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
export { CAPABILITIES } from "./capabilities/index.js";
|
|
1
2
|
export { createApiRuntime } from "./features/execution/createApiRuntime.js";
|
|
2
3
|
export { createApiTransportHandler } from "./features/execution/createApiTransportHandler.js";
|
|
4
|
+
export { projectApiCapabilities } from "./features/execution/projectApiCapabilities.js";
|
|
3
5
|
export { resolveApiOperationBindings } from "./features/execution/resolveApiOperationBindings.js";
|
|
4
6
|
export type { ApiHandler, ApiHandlerContext, ApiHandlerRegistry, ApiHandlerResponse, ApiOperationBinding, ApiRequest, ApiResponse, ApiRuntime, ApiTransportAdapter, } from "./types/api.js";
|
|
5
7
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,yBAAyB,EAAE,MAAM,mDAAmD,CAAC;AAC9F,OAAO,EAAE,2BAA2B,EAAE,MAAM,qDAAqD,CAAC;AAClG,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,UAAU,EACV,mBAAmB,GACpB,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,yBAAyB,EAAE,MAAM,mDAAmD,CAAC;AAC9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAC;AACxF,OAAO,EAAE,2BAA2B,EAAE,MAAM,qDAAqD,CAAC;AAClG,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,UAAU,EACV,mBAAmB,GACpB,MAAM,gBAAgB,CAAC"}
|
package/dist/api.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
export { CAPABILITIES } from "./capabilities/index.js";
|
|
1
2
|
export { createApiRuntime } from "./features/execution/createApiRuntime.js";
|
|
2
3
|
export { createApiTransportHandler } from "./features/execution/createApiTransportHandler.js";
|
|
4
|
+
export { projectApiCapabilities } from "./features/execution/projectApiCapabilities.js";
|
|
3
5
|
export { resolveApiOperationBindings } from "./features/execution/resolveApiOperationBindings.js";
|
|
4
6
|
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,yBAAyB,EAAE,MAAM,mDAAmD,CAAC;AAC9F,OAAO,EAAE,2BAA2B,EAAE,MAAM,qDAAqD,CAAC","sourcesContent":["export { createApiRuntime } from \"./features/execution/createApiRuntime.js\";\nexport { createApiTransportHandler } from \"./features/execution/createApiTransportHandler.js\";\nexport { resolveApiOperationBindings } from \"./features/execution/resolveApiOperationBindings.js\";\nexport type {\n ApiHandler,\n ApiHandlerContext,\n ApiHandlerRegistry,\n ApiHandlerResponse,\n ApiOperationBinding,\n ApiRequest,\n ApiResponse,\n ApiRuntime,\n ApiTransportAdapter,\n} from \"./types/api.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,yBAAyB,EAAE,MAAM,mDAAmD,CAAC;AAC9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAC;AACxF,OAAO,EAAE,2BAA2B,EAAE,MAAM,qDAAqD,CAAC","sourcesContent":["export { CAPABILITIES } from \"./capabilities/index.js\";\nexport { createApiRuntime } from \"./features/execution/createApiRuntime.js\";\nexport { createApiTransportHandler } from \"./features/execution/createApiTransportHandler.js\";\nexport { projectApiCapabilities } from \"./features/execution/projectApiCapabilities.js\";\nexport { resolveApiOperationBindings } from \"./features/execution/resolveApiOperationBindings.js\";\nexport type {\n ApiHandler,\n ApiHandlerContext,\n ApiHandlerRegistry,\n ApiHandlerResponse,\n ApiOperationBinding,\n ApiRequest,\n ApiResponse,\n ApiRuntime,\n ApiTransportAdapter,\n} from \"./types/api.js\";\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static API package capabilities.
|
|
3
|
+
*
|
|
4
|
+
* Executable API operations are dynamic and are projected from authored API definitions by
|
|
5
|
+
* `projectApiCapabilities`; they are intentionally not duplicated in this static catalog.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CAPABILITIES: readonly [];
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capabilities/index.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,YAAY,aAA8C,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static API package capabilities.
|
|
3
|
+
*
|
|
4
|
+
* Executable API operations are dynamic and are projected from authored API definitions by
|
|
5
|
+
* `projectApiCapabilities`; they are intentionally not duplicated in this static catalog.
|
|
6
|
+
*/
|
|
7
|
+
export const CAPABILITIES = [];
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/capabilities/index.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,EAA2C,CAAC","sourcesContent":["import type { Capability } from \"@ankhorage/contracts/capabilities\";\n\n/**\n * Static API package capabilities.\n *\n * Executable API operations are dynamic and are projected from authored API definitions by\n * `projectApiCapabilities`; they are intentionally not duplicated in this static catalog.\n */\nexport const CAPABILITIES = [] as const satisfies readonly Capability[];\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Capability } from "@ankhorage/contracts/capabilities";
|
|
2
|
+
import type { InternalRestApiDefinition } from "@ankhorage/contracts/data";
|
|
3
|
+
/*** Project one internal REST API definition into canonical invocable API capabilities. */
|
|
4
|
+
export declare function projectApiCapabilities(definition: InternalRestApiDefinition): readonly Capability[];
|
|
5
|
+
//# sourceMappingURL=projectApiCapabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectApiCapabilities.d.ts","sourceRoot":"","sources":["../../../src/features/execution/projectApiCapabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EAEhB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAMV,yBAAyB,EAC1B,MAAM,2BAA2B,CAAC;AAEnC,2FAA2F;AAC3F,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,yBAAyB,GACpC,SAAS,UAAU,EAAE,CAWvB"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { isCapabilityId, } from "@ankhorage/contracts/capabilities";
|
|
2
|
+
/*** Project one internal REST API definition into canonical invocable API capabilities. */
|
|
3
|
+
export function projectApiCapabilities(definition) {
|
|
4
|
+
const capabilities = Object.values(definition.endpoints).flatMap((endpoint) => Object.values(endpoint.operations).map((operation) => projectApiOperationCapability(definition, operation)));
|
|
5
|
+
assertUniqueCapabilityIds(capabilities);
|
|
6
|
+
return [...capabilities].sort((left, right) => left.id.localeCompare(right.id));
|
|
7
|
+
}
|
|
8
|
+
/*** Project one authored API operation into its stable semantic capability descriptor. */
|
|
9
|
+
function projectApiOperationCapability(definition, operation) {
|
|
10
|
+
const id = `api.${definition.id}.${operation.id}`;
|
|
11
|
+
if (!isCapabilityId(id)) {
|
|
12
|
+
throw new Error(`API operation projects to an invalid capability id: ${definition.id} / ${operation.id}`);
|
|
13
|
+
}
|
|
14
|
+
const input = projectOperationInput(operation.request);
|
|
15
|
+
const output = projectSchemaSlot(operation.response);
|
|
16
|
+
return {
|
|
17
|
+
id,
|
|
18
|
+
owner: "@ankhorage/api",
|
|
19
|
+
access: ["invoke"],
|
|
20
|
+
binding: { kind: "api", bindableAs: ["target"] },
|
|
21
|
+
label: operation.name ?? operation.id,
|
|
22
|
+
...(operation.description === undefined
|
|
23
|
+
? {}
|
|
24
|
+
: { description: operation.description }),
|
|
25
|
+
...(input === undefined ? {} : { input }),
|
|
26
|
+
...(output === undefined ? {} : { output }),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/*** Project request parameters and request body into the flat operation input value space. */
|
|
30
|
+
function projectOperationInput(request) {
|
|
31
|
+
if (request === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
const bodySchema = projectSchemaSlotAsSchema(request);
|
|
34
|
+
const parameterSchema = projectOperationParameters(request.parameters);
|
|
35
|
+
if (bodySchema === undefined) {
|
|
36
|
+
return parameterSchema === undefined
|
|
37
|
+
? undefined
|
|
38
|
+
: { schema: parameterSchema };
|
|
39
|
+
}
|
|
40
|
+
if (parameterSchema === undefined)
|
|
41
|
+
return projectSchemaSlot(request);
|
|
42
|
+
return {
|
|
43
|
+
schema: {
|
|
44
|
+
allOf: [bodySchema, parameterSchema],
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/*** Project transport parameters into the flat object consumed by Runtime operation bindings. */
|
|
49
|
+
function projectOperationParameters(parameters) {
|
|
50
|
+
if (parameters === undefined || parameters.length === 0)
|
|
51
|
+
return undefined;
|
|
52
|
+
const properties = {};
|
|
53
|
+
const required = [];
|
|
54
|
+
for (const parameter of parameters) {
|
|
55
|
+
if (Object.hasOwn(properties, parameter.name)) {
|
|
56
|
+
throw new Error(`Duplicate API operation input parameter: ${parameter.name}`);
|
|
57
|
+
}
|
|
58
|
+
properties[parameter.name] = projectOperationParameterSchema(parameter);
|
|
59
|
+
if (parameter.required === true)
|
|
60
|
+
required.push(parameter.name);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties,
|
|
65
|
+
...(required.length === 0 ? {} : { required: [...required].sort() }),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/*** Preserve one parameter's schema reference plus parameter-specific description/default metadata. */
|
|
69
|
+
function projectOperationParameterSchema(parameter) {
|
|
70
|
+
const schema = projectSchemaSlotAsSchema(parameter) ?? {};
|
|
71
|
+
return {
|
|
72
|
+
...schema,
|
|
73
|
+
...(parameter.description === undefined
|
|
74
|
+
? {}
|
|
75
|
+
: { description: parameter.description }),
|
|
76
|
+
...(parameter.default === undefined ? {} : { default: parameter.default }),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/*** Preserve exactly one portable schema slot when the operation already owns one. */
|
|
80
|
+
function projectSchemaSlot(slot) {
|
|
81
|
+
if (slot?.schema !== undefined)
|
|
82
|
+
return { schema: slot.schema };
|
|
83
|
+
if (slot?.schemaRef !== undefined)
|
|
84
|
+
return { schemaRef: slot.schemaRef };
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
/*** Convert a schema slot to an embeddable schema while preserving authored schema references. */
|
|
88
|
+
function projectSchemaSlotAsSchema(slot) {
|
|
89
|
+
if (slot?.schema !== undefined)
|
|
90
|
+
return slot.schema;
|
|
91
|
+
if (slot?.schemaRef !== undefined)
|
|
92
|
+
return { ref: slot.schemaRef };
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
/*** Reject API definitions whose endpoint operations collide in the projected capability namespace. */
|
|
96
|
+
function assertUniqueCapabilityIds(capabilities) {
|
|
97
|
+
const seen = new Set();
|
|
98
|
+
for (const capability of capabilities) {
|
|
99
|
+
if (seen.has(capability.id)) {
|
|
100
|
+
throw new Error(`Duplicate projected API capability id: ${capability.id}`);
|
|
101
|
+
}
|
|
102
|
+
seen.add(capability.id);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=projectApiCapabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectApiCapabilities.js","sourceRoot":"","sources":["../../../src/features/execution/projectApiCapabilities.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Capability,\n isCapabilityId,\n} from \"@ankhorage/contracts/capabilities\";\nimport type {\n DataOperationConfig,\n DataOperationParameter,\n DataOperationRequest,\n DataSchema,\n DataSchemaSlot,\n InternalRestApiDefinition,\n} from \"@ankhorage/contracts/data\";\n\n/*** Project one internal REST API definition into canonical invocable API capabilities. */\nexport function projectApiCapabilities(\n definition: InternalRestApiDefinition,\n): readonly Capability[] {\n const capabilities = Object.values(definition.endpoints).flatMap((endpoint) =>\n Object.values(endpoint.operations).map((operation) =>\n projectApiOperationCapability(definition, operation),\n ),\n );\n\n assertUniqueCapabilityIds(capabilities);\n return [...capabilities].sort((left, right) =>\n left.id.localeCompare(right.id),\n );\n}\n\n/*** Project one authored API operation into its stable semantic capability descriptor. */\nfunction projectApiOperationCapability(\n definition: InternalRestApiDefinition,\n operation: DataOperationConfig,\n): Capability {\n const id = `api.${definition.id}.${operation.id}`;\n if (!isCapabilityId(id)) {\n throw new Error(\n `API operation projects to an invalid capability id: ${definition.id} / ${operation.id}`,\n );\n }\n\n const input = projectOperationInput(operation.request);\n const output = projectSchemaSlot(operation.response);\n\n return {\n id,\n owner: \"@ankhorage/api\",\n access: [\"invoke\"],\n binding: { kind: \"api\", bindableAs: [\"target\"] },\n label: operation.name ?? operation.id,\n ...(operation.description === undefined\n ? {}\n : { description: operation.description }),\n ...(input === undefined ? {} : { input }),\n ...(output === undefined ? {} : { output }),\n };\n}\n\n/*** Project request parameters and request body into the flat operation input value space. */\nfunction projectOperationInput(\n request: DataOperationRequest | undefined,\n): DataSchemaSlot | undefined {\n if (request === undefined) return undefined;\n\n const bodySchema = projectSchemaSlotAsSchema(request);\n const parameterSchema = projectOperationParameters(request.parameters);\n\n if (bodySchema === undefined) {\n return parameterSchema === undefined\n ? undefined\n : { schema: parameterSchema };\n }\n if (parameterSchema === undefined) return projectSchemaSlot(request);\n\n return {\n schema: {\n allOf: [bodySchema, parameterSchema],\n },\n };\n}\n\n/*** Project transport parameters into the flat object consumed by Runtime operation bindings. */\nfunction projectOperationParameters(\n parameters: readonly DataOperationParameter[] | undefined,\n): DataSchema | undefined {\n if (parameters === undefined || parameters.length === 0) return undefined;\n\n const properties: Record<string, DataSchema> = {};\n const required: string[] = [];\n for (const parameter of parameters) {\n if (Object.hasOwn(properties, parameter.name)) {\n throw new Error(\n `Duplicate API operation input parameter: ${parameter.name}`,\n );\n }\n properties[parameter.name] = projectOperationParameterSchema(parameter);\n if (parameter.required === true) required.push(parameter.name);\n }\n\n return {\n type: \"object\",\n properties,\n ...(required.length === 0 ? {} : { required: [...required].sort() }),\n };\n}\n\n/*** Preserve one parameter's schema reference plus parameter-specific description/default metadata. */\nfunction projectOperationParameterSchema(\n parameter: DataOperationParameter,\n): DataSchema {\n const schema = projectSchemaSlotAsSchema(parameter) ?? {};\n return {\n ...schema,\n ...(parameter.description === undefined\n ? {}\n : { description: parameter.description }),\n ...(parameter.default === undefined ? {} : { default: parameter.default }),\n };\n}\n\n/*** Preserve exactly one portable schema slot when the operation already owns one. */\nfunction projectSchemaSlot(\n slot: DataSchemaSlot | undefined,\n): DataSchemaSlot | undefined {\n if (slot?.schema !== undefined) return { schema: slot.schema };\n if (slot?.schemaRef !== undefined) return { schemaRef: slot.schemaRef };\n return undefined;\n}\n\n/*** Convert a schema slot to an embeddable schema while preserving authored schema references. */\nfunction projectSchemaSlotAsSchema(\n slot: DataSchemaSlot | undefined,\n): DataSchema | undefined {\n if (slot?.schema !== undefined) return slot.schema;\n if (slot?.schemaRef !== undefined) return { ref: slot.schemaRef };\n return undefined;\n}\n\n/*** Reject API definitions whose endpoint operations collide in the projected capability namespace. */\nfunction assertUniqueCapabilityIds(capabilities: readonly Capability[]): void {\n const seen = new Set<Capability[\"id\"]>();\n for (const capability of capabilities) {\n if (seen.has(capability.id)) {\n throw new Error(\n `Duplicate projected API capability id: ${capability.id}`,\n );\n }\n seen.add(capability.id);\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Framework-neutral executable API runtime and transport contract for Ankhorage.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,7 +34,11 @@
|
|
|
34
34
|
"types": "./dist/api.d.ts",
|
|
35
35
|
"import": "./dist/api.js"
|
|
36
36
|
},
|
|
37
|
-
"./package.json": "./package.json"
|
|
37
|
+
"./package.json": "./package.json",
|
|
38
|
+
"./capabilities": {
|
|
39
|
+
"types": "./dist/capabilities/index.d.ts",
|
|
40
|
+
"import": "./dist/capabilities/index.js"
|
|
41
|
+
}
|
|
38
42
|
},
|
|
39
43
|
"publishConfig": {
|
|
40
44
|
"access": "public"
|
|
@@ -58,7 +62,7 @@
|
|
|
58
62
|
"docs": "paradox"
|
|
59
63
|
},
|
|
60
64
|
"dependencies": {
|
|
61
|
-
"@ankhorage/contracts": "^
|
|
65
|
+
"@ankhorage/contracts": "^24.1.0"
|
|
62
66
|
},
|
|
63
67
|
"devDependencies": {
|
|
64
68
|
"@ankhorage/devtools": "^2.1.11",
|