@procedures/client 0.2.3 → 0.4.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 +94 -0
- package/README.md +77 -44
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapters/http/client/transport.d.ts.map +1 -1
- package/dist/adapters/http/client/transport.js +35 -3
- package/dist/adapters/http/client/transport.js.map +1 -1
- package/dist/adapters/http/client/types.d.ts +3 -2
- package/dist/adapters/http/client/types.d.ts.map +1 -1
- package/dist/adapters/http/server/transport.d.ts +2 -2
- package/dist/adapters/http/server/transport.d.ts.map +1 -1
- package/dist/adapters/http/server/transport.js +54 -22
- package/dist/adapters/http/server/transport.js.map +1 -1
- package/dist/adapters/http/shared/headers.d.ts +1 -1
- package/dist/adapters/http/shared/headers.d.ts.map +1 -1
- package/dist/adapters/http/shared/headers.js +7 -6
- package/dist/adapters/http/shared/headers.js.map +1 -1
- package/dist/adapters/local/client/transport.d.ts +3 -0
- package/dist/adapters/local/client/transport.d.ts.map +1 -1
- package/dist/adapters/local/client/transport.js +67 -6
- package/dist/adapters/local/client/transport.js.map +1 -1
- package/dist/adapters/local/client/types.d.ts +15 -0
- package/dist/adapters/local/client/types.d.ts.map +1 -1
- package/dist/adapters/local/client/types.js.map +1 -1
- package/dist/adapters/mock/client/transport.d.ts +3 -2
- package/dist/adapters/mock/client/transport.d.ts.map +1 -1
- package/dist/adapters/mock/client/transport.js +8 -5
- package/dist/adapters/mock/client/transport.js.map +1 -1
- package/dist/adapters/mock/client/types.d.ts +7 -6
- package/dist/adapters/mock/client/types.d.ts.map +1 -1
- package/dist/adapters/port/transport.d.ts +62 -0
- package/dist/adapters/port/transport.d.ts.map +1 -0
- package/dist/adapters/port/transport.js +94 -0
- package/dist/adapters/port/transport.js.map +1 -0
- package/dist/adapters/websocket/client/index.d.ts +1 -1
- package/dist/adapters/websocket/client/index.d.ts.map +1 -1
- package/dist/adapters/websocket/client/index.js.map +1 -1
- package/dist/adapters/websocket/client/node.d.ts +30 -0
- package/dist/adapters/websocket/client/node.d.ts.map +1 -0
- package/dist/adapters/websocket/client/node.js +32 -0
- package/dist/adapters/websocket/client/node.js.map +1 -0
- package/dist/adapters/websocket/client/transport.d.ts +47 -7
- package/dist/adapters/websocket/client/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/client/transport.js +229 -75
- package/dist/adapters/websocket/client/transport.js.map +1 -1
- package/dist/adapters/websocket/client/types.d.ts +71 -21
- package/dist/adapters/websocket/client/types.d.ts.map +1 -1
- package/dist/adapters/websocket/client/types.js.map +1 -1
- package/dist/adapters/websocket/server/transport.d.ts +65 -24
- package/dist/adapters/websocket/server/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/server/transport.js +192 -263
- package/dist/adapters/websocket/server/transport.js.map +1 -1
- package/dist/adapters/websocket/server/types.d.ts +20 -1
- package/dist/adapters/websocket/server/types.d.ts.map +1 -1
- package/dist/adapters/websocket/shared/rpc.d.ts +129 -0
- package/dist/adapters/websocket/shared/rpc.d.ts.map +1 -0
- package/dist/adapters/websocket/shared/rpc.js +425 -0
- package/dist/adapters/websocket/shared/rpc.js.map +1 -0
- package/dist/browser.d.ts +29 -7
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +26 -3
- package/dist/browser.js.map +1 -1
- package/dist/client/call-types.d.ts +10 -10
- package/dist/client/call-types.d.ts.map +1 -1
- package/dist/client/call-types.js +1 -6
- package/dist/client/call-types.js.map +1 -1
- package/dist/client/client.d.ts +6 -1
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +23 -9
- package/dist/client/client.js.map +1 -1
- package/dist/client/deadline.d.ts +38 -0
- package/dist/client/deadline.d.ts.map +1 -0
- package/dist/client/deadline.js +60 -0
- package/dist/client/deadline.js.map +1 -0
- package/dist/client/errors/factory.d.ts.map +1 -1
- package/dist/client/errors/factory.js +11 -7
- package/dist/client/errors/factory.js.map +1 -1
- package/dist/client/errors/http-errors.d.ts.map +1 -1
- package/dist/client/errors/http-errors.js +6 -0
- package/dist/client/errors/http-errors.js.map +1 -1
- package/dist/client/errors/index.d.ts +1 -1
- package/dist/client/errors/index.js +1 -1
- package/dist/client/errors/registry.d.ts +2 -1
- package/dist/client/errors/registry.d.ts.map +1 -1
- package/dist/client/errors/registry.js +72 -22
- package/dist/client/errors/registry.js.map +1 -1
- package/dist/client/index.d.ts +9 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +8 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/middleware/cache.d.ts +19 -5
- package/dist/client/middleware/cache.d.ts.map +1 -1
- package/dist/client/middleware/cache.js +106 -18
- package/dist/client/middleware/cache.js.map +1 -1
- package/dist/client/middleware/circuit-breaker.d.ts +28 -10
- package/dist/client/middleware/circuit-breaker.d.ts.map +1 -1
- package/dist/client/middleware/circuit-breaker.js +35 -24
- package/dist/client/middleware/circuit-breaker.js.map +1 -1
- package/dist/client/middleware/contexts.d.ts +16 -10
- package/dist/client/middleware/contexts.d.ts.map +1 -1
- package/dist/client/middleware/contexts.js.map +1 -1
- package/dist/client/middleware/items.d.ts +31 -2
- package/dist/client/middleware/items.d.ts.map +1 -1
- package/dist/client/middleware/items.js +86 -6
- package/dist/client/middleware/items.js.map +1 -1
- package/dist/client/middleware/lru.d.ts +2 -0
- package/dist/client/middleware/lru.d.ts.map +1 -1
- package/dist/client/middleware/lru.js +11 -0
- package/dist/client/middleware/lru.js.map +1 -1
- package/dist/client/middleware/rate-limit.d.ts +7 -6
- package/dist/client/middleware/rate-limit.d.ts.map +1 -1
- package/dist/client/middleware/rate-limit.js +9 -7
- package/dist/client/middleware/rate-limit.js.map +1 -1
- package/dist/client/middleware/resilience.d.ts +61 -0
- package/dist/client/middleware/resilience.d.ts.map +1 -0
- package/dist/client/middleware/resilience.js +59 -0
- package/dist/client/middleware/resilience.js.map +1 -0
- package/dist/client/middleware/retry.d.ts +45 -11
- package/dist/client/middleware/retry.d.ts.map +1 -1
- package/dist/client/middleware/retry.js +102 -22
- package/dist/client/middleware/retry.js.map +1 -1
- package/dist/client/middleware/timeout.d.ts +15 -12
- package/dist/client/middleware/timeout.d.ts.map +1 -1
- package/dist/client/middleware/timeout.js +48 -46
- package/dist/client/middleware/timeout.js.map +1 -1
- package/dist/client/middleware/tracing.d.ts.map +1 -1
- package/dist/client/middleware/tracing.js +11 -3
- package/dist/client/middleware/tracing.js.map +1 -1
- package/dist/client/types.d.ts +9 -1
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/types.js.map +1 -1
- package/dist/clock.d.ts +19 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +18 -0
- package/dist/clock.js.map +1 -0
- package/dist/duration.d.ts +37 -0
- package/dist/duration.d.ts.map +1 -0
- package/dist/duration.js +44 -0
- package/dist/duration.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/machines.d.ts +90 -0
- package/dist/machines.d.ts.map +1 -0
- package/dist/machines.js +127 -0
- package/dist/machines.js.map +1 -0
- package/dist/node.d.ts +11 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +10 -0
- package/dist/node.js.map +1 -0
- package/dist/procedures/capability.d.ts +3 -6
- package/dist/procedures/capability.d.ts.map +1 -1
- package/dist/procedures/capability.js +7 -8
- package/dist/procedures/capability.js.map +1 -1
- package/dist/procedures/collection/index.d.ts +3 -3
- package/dist/procedures/collection/index.d.ts.map +1 -1
- package/dist/procedures/collection/index.js +1 -1
- package/dist/procedures/collection/index.js.map +1 -1
- package/dist/procedures/collection/procedures.d.ts.map +1 -1
- package/dist/procedures/collection/procedures.js +49 -1
- package/dist/procedures/collection/procedures.js.map +1 -1
- package/dist/procedures/collection/schemas.d.ts +33 -0
- package/dist/procedures/collection/schemas.d.ts.map +1 -1
- package/dist/procedures/collection/schemas.js +68 -0
- package/dist/procedures/collection/schemas.js.map +1 -1
- package/dist/procedures/collection/storage.d.ts +37 -0
- package/dist/procedures/collection/storage.d.ts.map +1 -1
- package/dist/procedures/core/array.d.ts +1 -1
- package/dist/procedures/core/array.d.ts.map +1 -1
- package/dist/procedures/core/array.js +81 -29
- package/dist/procedures/core/array.js.map +1 -1
- package/dist/procedures/core/index.d.ts.map +1 -1
- package/dist/procedures/core/index.js +17 -2
- package/dist/procedures/core/index.js.map +1 -1
- package/dist/procedures/core/logic.js +1 -1
- package/dist/procedures/core/logic.js.map +1 -1
- package/dist/procedures/core/math.d.ts.map +1 -1
- package/dist/procedures/core/math.js +5 -1
- package/dist/procedures/core/math.js.map +1 -1
- package/dist/procedures/core/meta.d.ts.map +1 -1
- package/dist/procedures/core/meta.js +43 -8
- package/dist/procedures/core/meta.js.map +1 -1
- package/dist/procedures/core/object.d.ts.map +1 -1
- package/dist/procedures/core/object.js +42 -13
- package/dist/procedures/core/object.js.map +1 -1
- package/dist/procedures/core/operands.d.ts.map +1 -1
- package/dist/procedures/core/operands.js +6 -1
- package/dist/procedures/core/operands.js.map +1 -1
- package/dist/procedures/core/string.d.ts.map +1 -1
- package/dist/procedures/core/string.js +4 -2
- package/dist/procedures/core/string.js.map +1 -1
- package/dist/procedures/core/type.d.ts.map +1 -1
- package/dist/procedures/core/type.js +4 -2
- package/dist/procedures/core/type.js.map +1 -1
- package/dist/procedures/define-procedure.d.ts +19 -7
- package/dist/procedures/define-procedure.d.ts.map +1 -1
- package/dist/procedures/define-procedure.js +57 -17
- package/dist/procedures/define-procedure.js.map +1 -1
- package/dist/procedures/discovery.d.ts +4 -6
- package/dist/procedures/discovery.d.ts.map +1 -1
- package/dist/procedures/discovery.js +4 -6
- package/dist/procedures/discovery.js.map +1 -1
- package/dist/procedures/effects.d.ts +16 -0
- package/dist/procedures/effects.d.ts.map +1 -1
- package/dist/procedures/effects.js +33 -0
- package/dist/procedures/effects.js.map +1 -1
- package/dist/procedures/idempotency.d.ts +73 -0
- package/dist/procedures/idempotency.d.ts.map +1 -0
- package/dist/procedures/idempotency.js +131 -0
- package/dist/procedures/idempotency.js.map +1 -0
- package/dist/procedures/index.d.ts +7 -3
- package/dist/procedures/index.d.ts.map +1 -1
- package/dist/procedures/index.js +6 -2
- package/dist/procedures/index.js.map +1 -1
- package/dist/procedures/interceptors.d.ts +17 -4
- package/dist/procedures/interceptors.d.ts.map +1 -1
- package/dist/procedures/interceptors.js +18 -7
- package/dist/procedures/interceptors.js.map +1 -1
- package/dist/procedures/invoke.d.ts +15 -3
- package/dist/procedures/invoke.d.ts.map +1 -1
- package/dist/procedures/invoke.js +8 -3
- package/dist/procedures/invoke.js.map +1 -1
- package/dist/procedures/manifest.d.ts +83 -0
- package/dist/procedures/manifest.d.ts.map +1 -0
- package/dist/procedures/manifest.js +90 -0
- package/dist/procedures/manifest.js.map +1 -0
- package/dist/procedures/ref.d.ts +4 -2
- package/dist/procedures/ref.d.ts.map +1 -1
- package/dist/procedures/ref.js +2 -1
- package/dist/procedures/ref.js.map +1 -1
- package/dist/procedures/runtime-programs.d.ts +19 -0
- package/dist/procedures/runtime-programs.d.ts.map +1 -0
- package/dist/procedures/runtime-programs.js +24 -0
- package/dist/procedures/runtime-programs.js.map +1 -0
- package/dist/procedures/types.d.ts +16 -0
- package/dist/procedures/types.d.ts.map +1 -1
- package/dist/procedures/types.js.map +1 -1
- package/dist/protocol.d.ts +47 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +68 -0
- package/dist/protocol.js.map +1 -0
- package/dist/server/host-policy.d.ts +4 -3
- package/dist/server/host-policy.d.ts.map +1 -1
- package/dist/server/host-policy.js +6 -3
- package/dist/server/host-policy.js.map +1 -1
- package/dist/server/host-procedures.d.ts +31 -0
- package/dist/server/host-procedures.d.ts.map +1 -0
- package/dist/server/host-procedures.js +75 -0
- package/dist/server/host-procedures.js.map +1 -0
- package/dist/server/index.d.ts +3 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/procedure-server.d.ts +112 -5
- package/dist/server/procedure-server.d.ts.map +1 -1
- package/dist/server/procedure-server.js +273 -19
- package/dist/server/procedure-server.js.map +1 -1
- package/dist/server/request-auth.d.ts +19 -0
- package/dist/server/request-auth.d.ts.map +1 -0
- package/dist/server/request-auth.js +32 -0
- package/dist/server/request-auth.js.map +1 -0
- package/dist/server/types.d.ts +32 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js.map +1 -1
- package/dist/timers.d.ts +60 -0
- package/dist/timers.d.ts.map +1 -0
- package/dist/timers.js +33 -0
- package/dist/timers.js.map +1 -0
- package/dist/tracing/traceparent.d.ts +26 -0
- package/dist/tracing/traceparent.d.ts.map +1 -0
- package/dist/tracing/traceparent.js +53 -0
- package/dist/tracing/traceparent.js.map +1 -0
- package/package.json +11 -4
- package/src/adapters/http/client/transport.ts +31 -3
- package/src/adapters/http/client/types.ts +3 -2
- package/src/adapters/http/server/transport.ts +61 -26
- package/src/adapters/http/shared/headers.ts +7 -6
- package/src/adapters/local/client/transport.ts +74 -7
- package/src/adapters/local/client/types.ts +18 -0
- package/src/adapters/mock/client/transport.ts +9 -6
- package/src/adapters/mock/client/types.ts +7 -6
- package/src/adapters/port/transport.ts +124 -0
- package/src/adapters/websocket/client/index.ts +1 -0
- package/src/adapters/websocket/client/node.ts +34 -0
- package/src/adapters/websocket/client/transport.ts +251 -81
- package/src/adapters/websocket/client/types.ts +81 -21
- package/src/adapters/websocket/server/transport.ts +199 -301
- package/src/adapters/websocket/server/types.ts +20 -1
- package/src/adapters/websocket/shared/rpc.ts +453 -0
- package/src/browser.ts +51 -3
- package/src/client/call-types.ts +10 -14
- package/src/client/client.ts +28 -9
- package/src/client/deadline.ts +64 -0
- package/src/client/errors/README.md +2 -0
- package/src/client/errors/factory.ts +12 -8
- package/src/client/errors/http-errors.ts +5 -0
- package/src/client/errors/index.ts +1 -1
- package/src/client/errors/registry.ts +79 -22
- package/src/client/index.ts +21 -3
- package/src/client/middleware/cache.ts +120 -23
- package/src/client/middleware/circuit-breaker.ts +65 -35
- package/src/client/middleware/contexts.ts +17 -10
- package/src/client/middleware/items.ts +101 -6
- package/src/client/middleware/lru.ts +12 -0
- package/src/client/middleware/rate-limit.ts +9 -9
- package/src/client/middleware/resilience.ts +81 -0
- package/src/client/middleware/retry.ts +146 -34
- package/src/client/middleware/timeout.ts +57 -55
- package/src/client/middleware/tracing.ts +13 -4
- package/src/client/types.ts +9 -1
- package/src/clock.ts +21 -0
- package/src/duration.ts +56 -0
- package/src/index.ts +4 -0
- package/src/machines.ts +186 -0
- package/src/node.ts +11 -0
- package/src/procedures/capability.ts +7 -8
- package/src/procedures/collection/index.ts +9 -1
- package/src/procedures/collection/procedures.ts +57 -0
- package/src/procedures/collection/schemas.ts +110 -0
- package/src/procedures/collection/storage.ts +38 -0
- package/src/procedures/core/array.ts +79 -31
- package/src/procedures/core/index.ts +17 -2
- package/src/procedures/core/logic.ts +1 -1
- package/src/procedures/core/math.ts +5 -1
- package/src/procedures/core/meta.ts +45 -8
- package/src/procedures/core/object.ts +48 -14
- package/src/procedures/core/operands.ts +7 -0
- package/src/procedures/core/string.ts +4 -2
- package/src/procedures/core/type.ts +4 -2
- package/src/procedures/define-procedure.ts +73 -20
- package/src/procedures/discovery.ts +4 -6
- package/src/procedures/effects.ts +35 -0
- package/src/procedures/idempotency.ts +152 -0
- package/src/procedures/index.ts +18 -2
- package/src/procedures/interceptors.ts +28 -11
- package/src/procedures/invoke.ts +19 -5
- package/src/procedures/manifest.ts +158 -0
- package/src/procedures/ref.ts +4 -2
- package/src/procedures/runtime-programs.ts +27 -0
- package/src/procedures/types.ts +16 -0
- package/src/protocol.ts +108 -0
- package/src/server/host-policy.ts +8 -5
- package/src/server/host-procedures.ts +102 -0
- package/src/server/index.ts +5 -2
- package/src/server/procedure-server.ts +328 -12
- package/src/server/request-auth.ts +35 -0
- package/src/server/types.ts +37 -0
- package/src/timers.ts +82 -0
- package/src/tracing/traceparent.ts +61 -0
- package/dist/procedures/cli/announce.d.ts +0 -67
- package/dist/procedures/cli/announce.d.ts.map +0 -1
- package/dist/procedures/cli/announce.js +0 -392
- package/dist/procedures/cli/announce.js.map +0 -1
- package/dist/procedures/cli/discover.d.ts +0 -66
- package/dist/procedures/cli/discover.d.ts.map +0 -1
- package/dist/procedures/cli/discover.js +0 -310
- package/dist/procedures/cli/discover.js.map +0 -1
- package/dist/procedures/cli/index.d.ts +0 -13
- package/dist/procedures/cli/index.d.ts.map +0 -1
- package/dist/procedures/cli/index.js +0 -203
- package/dist/procedures/cli/index.js.map +0 -1
- package/dist/procedures/cli/init.d.ts +0 -17
- package/dist/procedures/cli/init.d.ts.map +0 -1
- package/dist/procedures/cli/init.js +0 -336
- package/dist/procedures/cli/init.js.map +0 -1
- package/src/procedures/cli/announce.ts +0 -470
- package/src/procedures/cli/discover.ts +0 -390
- package/src/procedures/cli/index.ts +0 -231
- package/src/procedures/cli/init.ts +0 -370
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
parseProcedureJson,
|
|
15
15
|
stringifyProcedureJson,
|
|
16
16
|
isAnyProcedureRef,
|
|
17
|
+
isProcedureRef,
|
|
17
18
|
isOutputRef,
|
|
18
19
|
isPlainObject,
|
|
19
20
|
resolveOutputRef,
|
|
@@ -58,18 +59,37 @@ const ImportOutputSchema = z.looseObject({
|
|
|
58
59
|
|
|
59
60
|
type ImportProcedure = Procedure<ImportInput, ImportOutput, { description: string; tags: string[] }>;
|
|
60
61
|
|
|
62
|
+
/**
|
|
63
|
+
* This function gives true for the runtime form of a procedure reference whose path is a list of
|
|
64
|
+
* texts. `client.import` accepts only such a value at the top level.
|
|
65
|
+
*/
|
|
66
|
+
function isImportableRef(value: unknown): boolean {
|
|
67
|
+
if (!isProcedureRef(value)) return false;
|
|
68
|
+
const path = (value as { path?: unknown }).path;
|
|
69
|
+
return Array.isArray(path) && path.length > 0 && path.every((segment) => typeof segment === "string");
|
|
70
|
+
}
|
|
71
|
+
|
|
61
72
|
const importProcedure: ImportProcedure = defineProcedure({
|
|
62
73
|
path: ["import"],
|
|
63
74
|
input: ImportInputSchema,
|
|
64
75
|
output: ImportOutputSchema,
|
|
65
76
|
metadata: {
|
|
66
|
-
description:
|
|
77
|
+
description:
|
|
78
|
+
"Parse a procedure reference ({ $proc, input }) from JSON text. Other JSON, for example a number or a list, gives success false.",
|
|
67
79
|
tags: ["core", "meta"],
|
|
68
80
|
},
|
|
69
81
|
handler: async (input: ImportInput): Promise<ImportOutput> => {
|
|
70
82
|
try {
|
|
71
83
|
if (input.json) {
|
|
72
84
|
const procedure = parseProcedureJson(input.json);
|
|
85
|
+
// Before, each JSON value gave success true, for example 42 (catalog test, roadmap R29)
|
|
86
|
+
if (!isImportableRef(procedure)) {
|
|
87
|
+
return {
|
|
88
|
+
procedure: null,
|
|
89
|
+
success: false,
|
|
90
|
+
error: "The JSON is not a procedure reference. A reference is an object whose $proc is a list of texts.",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
73
93
|
return { procedure, success: true };
|
|
74
94
|
}
|
|
75
95
|
if (input.path) {
|
|
@@ -107,8 +127,19 @@ interface ExportInput {
|
|
|
107
127
|
pretty?: boolean | undefined;
|
|
108
128
|
}
|
|
109
129
|
|
|
130
|
+
/**
|
|
131
|
+
* This function gives a schema of a required value: undefined has no JSON text, so the input
|
|
132
|
+
* schema refuses it with `VALIDATION_ERROR`. Before, the call failed with
|
|
133
|
+
* `OUTPUT_VALIDATION_ERROR` (catalog test, roadmap R29).
|
|
134
|
+
*/
|
|
135
|
+
const definedValue = (description: string) =>
|
|
136
|
+
z
|
|
137
|
+
.unknown()
|
|
138
|
+
.refine((value) => value !== undefined, { message: "The value is missing: undefined has no JSON text" })
|
|
139
|
+
.describe(description);
|
|
140
|
+
|
|
110
141
|
const ExportInputSchema = z.object({
|
|
111
|
-
procedure:
|
|
142
|
+
procedure: definedValue("The procedure reference to serialize. The procedure refuses a missing value (undefined) with VALIDATION_ERROR, because undefined has no JSON text."),
|
|
112
143
|
pretty: z.boolean().optional().describe("Pretty print JSON output"),
|
|
113
144
|
});
|
|
114
145
|
|
|
@@ -134,13 +165,15 @@ const exportProcedure: ExportProcedure = defineProcedure({
|
|
|
134
165
|
input: ExportInputSchema,
|
|
135
166
|
output: ExportOutputSchema,
|
|
136
167
|
metadata: {
|
|
137
|
-
description: "Serialize procedure
|
|
168
|
+
description: "Serialize a procedure reference to JSON text. It refuses a missing procedure (undefined) with VALIDATION_ERROR.",
|
|
138
169
|
// The refs of the input are data: exec() must not run them (deep dive CORE-5)
|
|
139
170
|
tags: ["core", "meta", RAW_INPUT_TAG],
|
|
140
171
|
},
|
|
141
172
|
handler: async (input: ExportInput): Promise<ExportOutput> => {
|
|
142
173
|
try {
|
|
143
|
-
const json = stringifyProcedureJson(input.procedure, input.pretty ? 2 : undefined);
|
|
174
|
+
const json = stringifyProcedureJson(input.procedure, input.pretty ? 2 : undefined) as string | undefined;
|
|
175
|
+
// A function or a symbol has no JSON text either: an error result, not an invalid output
|
|
176
|
+
if (json === undefined) return { json: "", success: false, error: "The procedure has no JSON text" };
|
|
144
177
|
return { json, success: true };
|
|
145
178
|
} catch (error) {
|
|
146
179
|
return {
|
|
@@ -268,7 +301,7 @@ interface StringifyJsonInput {
|
|
|
268
301
|
}
|
|
269
302
|
|
|
270
303
|
const StringifyJsonInputSchema = z.object({
|
|
271
|
-
value:
|
|
304
|
+
value: definedValue("The value to write as JSON. The procedure refuses a missing value (undefined) with VALIDATION_ERROR, because undefined has no JSON text."),
|
|
272
305
|
pretty: z.boolean().optional().describe("Pretty print with indentation"),
|
|
273
306
|
indent: z.union([z.number(), z.string()]).optional().describe("Custom indentation (number of spaces or string)"),
|
|
274
307
|
});
|
|
@@ -280,13 +313,16 @@ const stringifyJsonProcedure: StringifyJsonProcedure = defineProcedure({
|
|
|
280
313
|
input: StringifyJsonInputSchema,
|
|
281
314
|
output: stringOutput("The JSON text"),
|
|
282
315
|
metadata: {
|
|
283
|
-
description: "Stringify value to JSON (with procedure ref support)",
|
|
316
|
+
description: "Stringify value to JSON (with procedure ref support). It refuses a missing value (undefined) with VALIDATION_ERROR.",
|
|
284
317
|
// The refs of the input are data: exec() must not run them (deep dive CORE-5)
|
|
285
318
|
tags: ["core", "meta", RAW_INPUT_TAG],
|
|
286
319
|
},
|
|
287
320
|
handler: async (input: StringifyJsonInput): Promise<string> => {
|
|
288
321
|
const indent = input.pretty ? (input.indent ?? 2) : input.indent;
|
|
289
|
-
|
|
322
|
+
const json = stringifyProcedureJson(input.value, indent as number) as string | undefined;
|
|
323
|
+
// A function or a symbol has no JSON text either: a clear error, not an invalid output
|
|
324
|
+
if (json === undefined) throw new Error("The value has no JSON text");
|
|
325
|
+
return json;
|
|
290
326
|
},
|
|
291
327
|
});
|
|
292
328
|
|
|
@@ -331,7 +367,8 @@ const lookupProcedure: LookupProcedure = defineProcedure({
|
|
|
331
367
|
handler: async (input: LookupInput, ctx): Promise<LookupOutput> => {
|
|
332
368
|
// The registry of the caller (a server or a client with its own registry)
|
|
333
369
|
const proc = (ctx?.registry ?? PROCEDURE_REGISTRY).get(input.path);
|
|
334
|
-
|
|
370
|
+
// A procedure outside the expose rule of the host does not exist for its callers (R17)
|
|
371
|
+
if (proc && (!ctx?.expose || ctx.expose(proc.path))) {
|
|
335
372
|
return {
|
|
336
373
|
exists: true,
|
|
337
374
|
metadata: proc.metadata,
|
|
@@ -11,15 +11,46 @@ import { defineProcedure, namespace } from "../define.js";
|
|
|
11
11
|
import type { AnyProcedure, Procedure } from "../types.js";
|
|
12
12
|
import { PURE_EFFECTS, withEffects } from "../effects.js";
|
|
13
13
|
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Helpers: own keys only (roadmap R6)
|
|
16
|
+
// =============================================================================
|
|
17
|
+
|
|
18
|
+
/** The path segments that reach a prototype. The registry refuses them in paths too. */
|
|
19
|
+
const PROTOTYPE_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The segments of a dotted path. A segment that reaches a prototype is an error: before,
|
|
23
|
+
* `client.set` with the path `__proto__.x` changed the prototype of its result (roadmap R6).
|
|
24
|
+
*/
|
|
25
|
+
function segmentsOf(path: string): string[] {
|
|
26
|
+
const parts = path.split(".");
|
|
27
|
+
for (const part of parts) {
|
|
28
|
+
if (PROTOTYPE_KEYS.has(part)) {
|
|
29
|
+
throw new Error(`The path "${path}" has the segment "${part}", which reaches a prototype`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return parts;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function hasOwn(obj: object, key: string): boolean {
|
|
36
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** This function sets an own data property: a "__proto__" key of the data stays data. */
|
|
40
|
+
function put(target: Record<string, unknown>, key: string, value: unknown): void {
|
|
41
|
+
Object.defineProperty(target, key, { value, writable: true, enumerable: true, configurable: true });
|
|
42
|
+
}
|
|
43
|
+
|
|
14
44
|
// =============================================================================
|
|
15
45
|
// Helper: Get nested value by path
|
|
16
46
|
// =============================================================================
|
|
17
47
|
|
|
18
48
|
function getByPath(obj: unknown, path: string): unknown {
|
|
19
|
-
const parts = path
|
|
49
|
+
const parts = segmentsOf(path);
|
|
20
50
|
let current: unknown = obj;
|
|
21
51
|
for (const part of parts) {
|
|
22
|
-
|
|
52
|
+
// Only own fields: before, "toString" gave a function of the prototype
|
|
53
|
+
if (current === null || typeof current !== "object" || !hasOwn(current, part)) {
|
|
23
54
|
return undefined;
|
|
24
55
|
}
|
|
25
56
|
current = (current as Record<string, unknown>)[part];
|
|
@@ -33,22 +64,22 @@ function getByPath(obj: unknown, path: string): unknown {
|
|
|
33
64
|
|
|
34
65
|
function setByPath(obj: Record<string, unknown>, path: string, value: unknown): Record<string, unknown> {
|
|
35
66
|
const result = { ...obj };
|
|
36
|
-
const parts = path
|
|
67
|
+
const parts = segmentsOf(path);
|
|
37
68
|
let current: Record<string, unknown> = result;
|
|
38
69
|
|
|
39
70
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
40
71
|
const part = parts[i]!;
|
|
41
|
-
if (!(part
|
|
42
|
-
current
|
|
72
|
+
if (!hasOwn(current, part) || typeof current[part] !== "object" || current[part] === null) {
|
|
73
|
+
put(current, part, {});
|
|
43
74
|
} else {
|
|
44
|
-
current
|
|
75
|
+
put(current, part, { ...(current[part] as Record<string, unknown>) });
|
|
45
76
|
}
|
|
46
77
|
current = current[part] as Record<string, unknown>;
|
|
47
78
|
}
|
|
48
79
|
|
|
49
80
|
const lastPart = parts[parts.length - 1];
|
|
50
81
|
if (lastPart !== undefined) {
|
|
51
|
-
current
|
|
82
|
+
put(current, lastPart, value);
|
|
52
83
|
}
|
|
53
84
|
return result;
|
|
54
85
|
}
|
|
@@ -139,16 +170,17 @@ function deepMerge(target: Record<string, unknown>, source: Record<string, unkno
|
|
|
139
170
|
typeof source[key] === "object" &&
|
|
140
171
|
source[key] !== null &&
|
|
141
172
|
!Array.isArray(source[key]) &&
|
|
173
|
+
hasOwn(result, key) &&
|
|
142
174
|
typeof result[key] === "object" &&
|
|
143
175
|
result[key] !== null &&
|
|
144
176
|
!Array.isArray(result[key])
|
|
145
177
|
) {
|
|
146
|
-
result
|
|
178
|
+
put(result, key, deepMerge(
|
|
147
179
|
result[key] as Record<string, unknown>,
|
|
148
180
|
source[key] as Record<string, unknown>
|
|
149
|
-
);
|
|
181
|
+
));
|
|
150
182
|
} else {
|
|
151
|
-
result
|
|
183
|
+
put(result, key, source[key]);
|
|
152
184
|
}
|
|
153
185
|
}
|
|
154
186
|
return result;
|
|
@@ -166,7 +198,8 @@ const mergeProcedure: MergeProcedure = defineProcedure({
|
|
|
166
198
|
if (input.deep) {
|
|
167
199
|
return input.objects.reduce((acc, obj) => deepMerge(acc, obj), {});
|
|
168
200
|
}
|
|
169
|
-
|
|
201
|
+
// Object.assign sets a "__proto__" key of the data as the prototype: spread keeps it data
|
|
202
|
+
return input.objects.reduce<Record<string, unknown>>((acc, obj) => ({ ...acc, ...obj }), {});
|
|
170
203
|
},
|
|
171
204
|
});
|
|
172
205
|
|
|
@@ -307,8 +340,9 @@ const pickProcedure: PickProcedure = defineProcedure({
|
|
|
307
340
|
handler: async (input: PickInput): Promise<Record<string, unknown>> => {
|
|
308
341
|
const result: Record<string, unknown> = {};
|
|
309
342
|
for (const key of input.keys) {
|
|
310
|
-
|
|
311
|
-
|
|
343
|
+
// Only own fields: before, "toString" picked a function of the prototype
|
|
344
|
+
if (hasOwn(input.object, key)) {
|
|
345
|
+
put(result, key, input.object[key]);
|
|
312
346
|
}
|
|
313
347
|
}
|
|
314
348
|
return result;
|
|
@@ -344,7 +378,7 @@ const omitProcedure: OmitProcedure = defineProcedure({
|
|
|
344
378
|
const result: Record<string, unknown> = {};
|
|
345
379
|
for (const key of Object.keys(input.object)) {
|
|
346
380
|
if (!keysToOmit.has(key)) {
|
|
347
|
-
result
|
|
381
|
+
put(result, key, input.object[key]);
|
|
348
382
|
}
|
|
349
383
|
}
|
|
350
384
|
return result;
|
|
@@ -7,6 +7,8 @@ import type { ProcedureContext, ProcedurePath } from "../types.js";
|
|
|
7
7
|
import { PROCEDURE_REGISTRY } from "../registry.js";
|
|
8
8
|
import {
|
|
9
9
|
isAnyProcedureRef,
|
|
10
|
+
getRefWhen,
|
|
11
|
+
WHEN_NEVER,
|
|
10
12
|
normalizeRef,
|
|
11
13
|
hydrateInput,
|
|
12
14
|
createRefScope,
|
|
@@ -73,6 +75,11 @@ export async function callOperand(
|
|
|
73
75
|
ctx: ProcedureContext,
|
|
74
76
|
options: { scope?: RefScope | undefined; extra?: Record<string, unknown> | undefined } = {},
|
|
75
77
|
): Promise<unknown> {
|
|
78
|
+
// A $never operand is data with its full input, as a $never call anywhere (roadmap R4: before,
|
|
79
|
+
// only a chain step obeyed it, and a $never branch, task or fn started)
|
|
80
|
+
if (getRefWhen(ref) === WHEN_NEVER) {
|
|
81
|
+
return ref;
|
|
82
|
+
}
|
|
76
83
|
const normalized = normalizeRef(ref);
|
|
77
84
|
const raw = rawRule(ctx)(normalized.path);
|
|
78
85
|
let input: unknown = raw ? normalized.input : await hydrateOperand(normalized.input, ctx, options.scope);
|
|
@@ -132,7 +132,9 @@ const replaceProcedure: ReplaceProcedure = defineProcedure({
|
|
|
132
132
|
if (input.all) {
|
|
133
133
|
return input.value.split(input.search).join(input.replace);
|
|
134
134
|
}
|
|
135
|
-
|
|
135
|
+
// A function gives the replacement as text. Before, "$$" became "$" and "$&" became the match
|
|
136
|
+
// (catalog test, roadmap R29).
|
|
137
|
+
return input.value.replace(input.search, () => input.replace);
|
|
136
138
|
},
|
|
137
139
|
});
|
|
138
140
|
|
|
@@ -382,7 +384,7 @@ interface TemplateInput {
|
|
|
382
384
|
}
|
|
383
385
|
|
|
384
386
|
const TemplateInputSchema = z.object({
|
|
385
|
-
template: z.string().describe("The template text, with {name} placeholders"),
|
|
387
|
+
template: z.string().describe("The template text, with {{name}} placeholders"),
|
|
386
388
|
values: z.record(z.string(), z.unknown()).describe("The values"),
|
|
387
389
|
});
|
|
388
390
|
|
|
@@ -10,6 +10,7 @@ import { anyOutput, booleanOutput, stringOutput } from "./outputs.js";
|
|
|
10
10
|
import { defineProcedure, namespace } from "../define.js";
|
|
11
11
|
import type { AnyProcedure, Procedure } from "../types.js";
|
|
12
12
|
import { PURE_EFFECTS, withEffects } from "../effects.js";
|
|
13
|
+
import { isPlainObject } from "../ref.js";
|
|
13
14
|
|
|
14
15
|
// =============================================================================
|
|
15
16
|
// Typeof Procedure
|
|
@@ -168,11 +169,12 @@ const isObjectProcedure: IsObjectProcedure = defineProcedure({
|
|
|
168
169
|
input: IsObjectInputSchema,
|
|
169
170
|
output: booleanOutput("True for a plain object"),
|
|
170
171
|
metadata: {
|
|
171
|
-
description: "Check if value is a plain object (not array, not null)",
|
|
172
|
+
description: "Check if value is a plain object (not array, not null, not a Date or another class instance)",
|
|
172
173
|
tags: ["core", "type"],
|
|
173
174
|
},
|
|
174
175
|
handler: async (input: IsObjectInput): Promise<boolean> => {
|
|
175
|
-
|
|
176
|
+
// Before, a Date or a Map gave true (catalog test, roadmap R29)
|
|
177
|
+
return isPlainObject(input.value);
|
|
176
178
|
},
|
|
177
179
|
});
|
|
178
180
|
|
|
@@ -34,6 +34,7 @@ import type {
|
|
|
34
34
|
ProcedureContext,
|
|
35
35
|
AnyProcedure,
|
|
36
36
|
ProcedureRegistryLike,
|
|
37
|
+
Effects,
|
|
37
38
|
} from "./types.js";
|
|
38
39
|
import { z } from "zod";
|
|
39
40
|
import { anySchema, zodAdapter } from "./core/schemas.js";
|
|
@@ -47,7 +48,10 @@ import {
|
|
|
47
48
|
rawInputRule,
|
|
48
49
|
RUNS_REFS_TAG,
|
|
49
50
|
} from "./ref.js";
|
|
50
|
-
import { PURE_EFFECTS, REGISTRY_READ_EFFECTS, withEffects } from "./effects.js";
|
|
51
|
+
import { INFERRED_EFFECTS_METADATA_KEY, PURE_EFFECTS, REGISTRY_READ_EFFECTS, effectsValue, withEffects } from "./effects.js";
|
|
52
|
+
import { MANIFEST_FORMAT, describeProcedure as describeEntry, describeRegistry, type ProcedureManifest } from "./manifest.js";
|
|
53
|
+
import type { JsonSchema } from "./schema.js";
|
|
54
|
+
import { isRuntimeDefined, markRuntimeProgram, runtimeProgramOfHandler } from "./runtime-programs.js";
|
|
51
55
|
|
|
52
56
|
// Input schemas of procedure.define and procedure.delete (roadmap 2.1)
|
|
53
57
|
const procedurePathField = z.array(z.string().min(1)).min(1);
|
|
@@ -151,7 +155,24 @@ const GetOutputSchema = z.looseObject({
|
|
|
151
155
|
metadata: descriptionFields.metadata,
|
|
152
156
|
hasInputSchema: z.boolean().optional().describe("True when the procedure has an input schema"),
|
|
153
157
|
hasOutputSchema: z.boolean().optional().describe("True when the procedure has an output schema"),
|
|
154
|
-
|
|
158
|
+
input: z.record(z.string(), z.unknown()).optional().describe("The JSON Schema of the input"),
|
|
159
|
+
output: z.record(z.string(), z.unknown()).optional().describe("The JSON Schema of the output"),
|
|
160
|
+
effects: z.unknown().optional().describe("The declared effects: reads, writes, idempotent, destructive"),
|
|
161
|
+
}) as z.ZodType<{ found: false } | (ProcedureDescription & GetSchemas & { found: true; hasInputSchema: boolean; hasOutputSchema: boolean })>;
|
|
162
|
+
|
|
163
|
+
/** The JSON Schemas and the effects that `procedure.get` gives (roadmap R17). */
|
|
164
|
+
interface GetSchemas {
|
|
165
|
+
input?: JsonSchema | undefined;
|
|
166
|
+
output?: JsonSchema | undefined;
|
|
167
|
+
effects?: Effects | undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** The output of `procedure.manifest` */
|
|
171
|
+
const ManifestOutputSchema = z.looseObject({
|
|
172
|
+
format: z.literal(MANIFEST_FORMAT).describe("The format of the manifest"),
|
|
173
|
+
hash: z.string().describe("A hash of the entries: two manifests with the same hash describe the same procedures"),
|
|
174
|
+
procedures: z.array(z.looseObject({ path: z.array(z.string()), key: z.string() })).describe("The procedures, in the order of their keys"),
|
|
175
|
+
}) as unknown as z.ZodType<ProcedureManifest>;
|
|
155
176
|
|
|
156
177
|
/** The output of `procedure.list` */
|
|
157
178
|
const ListOutputSchema = z.looseObject({
|
|
@@ -204,26 +225,15 @@ function createAggregationHandler(
|
|
|
204
225
|
// Runtime-Defined Procedures
|
|
205
226
|
// =============================================================================
|
|
206
227
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
* registry is the only store of the procedures: a procedure is runtime-defined when its handler
|
|
210
|
-
* is a key here. (Before, a separate map kept them, and `procedure.delete` removed only the map
|
|
211
|
-
* entry: deep dive CORE-3.) The program is kept here, not only in the metadata: a caller that
|
|
212
|
-
* gives its own metadata to `procedure.define` replaces the metadata.
|
|
213
|
-
*/
|
|
214
|
-
const RUNTIME_PROGRAMS = new WeakMap<object, AggregationDefinition>();
|
|
215
|
-
|
|
216
|
-
/** True for a procedure that `procedure.define` made. */
|
|
217
|
-
export function isRuntimeDefined(procedure: { handler?: unknown }): boolean {
|
|
218
|
-
return typeof procedure.handler === "function" && RUNTIME_PROGRAMS.has(procedure.handler);
|
|
219
|
-
}
|
|
228
|
+
// The store of the programs of procedure.define (runtime-programs.ts, which imports nothing)
|
|
229
|
+
export { isRuntimeDefined } from "./runtime-programs.js";
|
|
220
230
|
|
|
221
231
|
/**
|
|
222
232
|
* The program (the aggregation) of a procedure that `procedure.define` made, or undefined for a
|
|
223
233
|
* code procedure. A program store saves it and defines it again after a restart (roadmap 3.2).
|
|
224
234
|
*/
|
|
225
235
|
export function runtimeProgramOf(procedure: { handler?: unknown }): AggregationDefinition | undefined {
|
|
226
|
-
return
|
|
236
|
+
return runtimeProgramOfHandler(procedure.handler) as AggregationDefinition | undefined;
|
|
227
237
|
}
|
|
228
238
|
|
|
229
239
|
type RegistryOf = Pick<ProcedureRegistryLike, "get" | "getAll" | "unregister">;
|
|
@@ -327,6 +337,10 @@ export const defineProcedureProcedure: Procedure<
|
|
|
327
337
|
throw new Error(`Procedure already exists at path: ${pathKey}`);
|
|
328
338
|
}
|
|
329
339
|
|
|
340
|
+
// The effects of the body that the host found (roadmap R22). Only an interceptor of the host
|
|
341
|
+
// can give them: each transport removes the key from a request.
|
|
342
|
+
const inferred = effectsValue(ctx?.metadata?.[INFERRED_EFFECTS_METADATA_KEY]);
|
|
343
|
+
|
|
330
344
|
// Create the procedure
|
|
331
345
|
const procedure: AnyProcedure = defineProcedure({
|
|
332
346
|
path,
|
|
@@ -341,13 +355,15 @@ export const defineProcedureProcedure: Procedure<
|
|
|
341
355
|
// No effects of its own, as client.chain: the admission examines each nested call of a
|
|
342
356
|
// data-driven procedure. The framework sets it, so the metadata of a caller cannot claim less
|
|
343
357
|
effects: PURE_EFFECTS,
|
|
358
|
+
// The framework sets this field too: the effects of the body, for the tool hints
|
|
359
|
+
...(inferred ? { inferredEffects: inferred } : { inferredEffects: undefined }),
|
|
344
360
|
},
|
|
345
361
|
handler: createAggregationHandler(aggregation),
|
|
346
362
|
});
|
|
347
363
|
|
|
348
364
|
// Its behavior comes from data: a server with an expose rule lets it call only exposed procedures
|
|
349
365
|
markDataDriven(procedure);
|
|
350
|
-
|
|
366
|
+
markRuntimeProgram(procedure.handler!, aggregation);
|
|
351
367
|
|
|
352
368
|
// Validate the procedure
|
|
353
369
|
validateProcedure(procedure);
|
|
@@ -435,7 +451,7 @@ const getInputSchema: z.ZodType<ProcedureGetInput> = z.object({
|
|
|
435
451
|
*/
|
|
436
452
|
export const getProcedureProcedure: Procedure<
|
|
437
453
|
ProcedureGetInput,
|
|
438
|
-
{ found: false } | (ProcedureDescription & { found: true; hasInputSchema: boolean; hasOutputSchema: boolean }),
|
|
454
|
+
{ found: false } | (ProcedureDescription & GetSchemas & { found: true; hasInputSchema: boolean; hasOutputSchema: boolean }),
|
|
439
455
|
ProcedureMetadata
|
|
440
456
|
> = defineProcedure({
|
|
441
457
|
path: ["procedure", "get"],
|
|
@@ -450,14 +466,20 @@ export const getProcedureProcedure: Procedure<
|
|
|
450
466
|
handler: async (input: ProcedureGetInput, ctx?: ProcedureContext) => {
|
|
451
467
|
const path = typeof input.path === "string" ? keyToPath(input.path) : input.path;
|
|
452
468
|
const procedure = (ctx?.registry ?? PROCEDURE_REGISTRY).get(path);
|
|
453
|
-
|
|
469
|
+
// A procedure outside the expose rule of the host is not found (R17)
|
|
470
|
+
if (!procedure || (ctx?.expose && !ctx.expose(procedure.path))) {
|
|
454
471
|
return { found: false as const };
|
|
455
472
|
}
|
|
473
|
+
const entry = describeEntry(procedure);
|
|
456
474
|
return {
|
|
457
475
|
found: true as const,
|
|
458
476
|
...describeProcedure(procedure, true),
|
|
459
477
|
hasInputSchema: !!procedure.input,
|
|
460
478
|
hasOutputSchema: !!procedure.output,
|
|
479
|
+
// The JSON Schemas and the effects of the one manifest type (R17)
|
|
480
|
+
...(entry.input ? { input: entry.input } : {}),
|
|
481
|
+
...(entry.output ? { output: entry.output } : {}),
|
|
482
|
+
...(entry.effects ? { effects: entry.effects } : {}),
|
|
461
483
|
};
|
|
462
484
|
},
|
|
463
485
|
});
|
|
@@ -484,6 +506,8 @@ export const listProceduresProcedure: Procedure<
|
|
|
484
506
|
},
|
|
485
507
|
handler: async (input: ProcedureListInput, ctx?: ProcedureContext) => {
|
|
486
508
|
let all = (ctx?.registry ?? PROCEDURE_REGISTRY).getAll();
|
|
509
|
+
// Only the procedures that the host exposes (R17)
|
|
510
|
+
if (ctx?.expose) all = all.filter((procedure) => ctx.expose!(procedure.path));
|
|
487
511
|
if (input.runtime) all = all.filter(isRuntimeDefined);
|
|
488
512
|
if (input.namespace) all = all.filter((procedure) => procedure.path[0] === input.namespace);
|
|
489
513
|
const procedures = all.map((procedure) => describeProcedure(procedure, input.includeMetadata ?? false));
|
|
@@ -491,6 +515,31 @@ export const listProceduresProcedure: Procedure<
|
|
|
491
515
|
},
|
|
492
516
|
});
|
|
493
517
|
|
|
518
|
+
/**
|
|
519
|
+
* The manifest of the caller's registry (roadmap R17): each procedure that the host exposes, with
|
|
520
|
+
* its JSON Schemas, effects and command-line metadata, and a hash. The compiler and the SDK
|
|
521
|
+
* generators read it.
|
|
522
|
+
*/
|
|
523
|
+
export const manifestProcedure: Procedure<{ namespace?: string | undefined }, ProcedureManifest, ProcedureMetadata> = defineProcedure({
|
|
524
|
+
path: ["procedure", "manifest"],
|
|
525
|
+
input: zodAdapter(
|
|
526
|
+
z.object({ namespace: z.string().optional().describe("Only the procedures under this first path segment") }) as z.ZodType<{ namespace?: string | undefined }>,
|
|
527
|
+
),
|
|
528
|
+
output: ManifestOutputSchema,
|
|
529
|
+
metadata: {
|
|
530
|
+
description: "The manifest of the registry: each exposed procedure with its schemas and effects",
|
|
531
|
+
tags: ["core", "meta"],
|
|
532
|
+
args: [],
|
|
533
|
+
shorts: { namespace: "n" },
|
|
534
|
+
output: "json",
|
|
535
|
+
},
|
|
536
|
+
handler: async (input: { namespace?: string | undefined }, ctx?: ProcedureContext) =>
|
|
537
|
+
describeRegistry(ctx?.registry ?? PROCEDURE_REGISTRY, {
|
|
538
|
+
...(ctx?.expose ? { expose: ctx.expose } : {}),
|
|
539
|
+
...(input.namespace ? { include: (procedure: AnyProcedure) => procedure.path[0] === input.namespace } : {}),
|
|
540
|
+
}),
|
|
541
|
+
});
|
|
542
|
+
|
|
494
543
|
/**
|
|
495
544
|
* Delete a runtime-defined procedure.
|
|
496
545
|
*/
|
|
@@ -532,6 +581,10 @@ export const deleteProcedureProcedure: Procedure<
|
|
|
532
581
|
export const metaProcedures: AnyProcedure[] = [
|
|
533
582
|
// They read the registry. define and delete change it (CAPABILITIES-2026-10).
|
|
534
583
|
...withEffects({ reads: ["registry"], writes: ["registry"] }, [defineProcedureProcedure as AnyProcedure]),
|
|
535
|
-
...withEffects(REGISTRY_READ_EFFECTS, [
|
|
584
|
+
...withEffects(REGISTRY_READ_EFFECTS, [
|
|
585
|
+
getProcedureProcedure as AnyProcedure,
|
|
586
|
+
listProceduresProcedure as AnyProcedure,
|
|
587
|
+
manifestProcedure as AnyProcedure,
|
|
588
|
+
]),
|
|
536
589
|
...withEffects({ reads: ["registry"], writes: ["registry"] }, [deleteProcedureProcedure as AnyProcedure]),
|
|
537
590
|
];
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Procedure Registration Helpers
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* use the CLI: `npx client-registry discover`
|
|
4
|
+
* These helpers add procedures to the global registry.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* 3. Consumers run `npx client-registry discover` to generate imports
|
|
6
|
+
* A package with procedures declares `"client": { "procedures": "./dist/register.js" }` in its
|
|
7
|
+
* `package.json`. Its `src/register.ts` registers its module. `mark` finds the packages by the
|
|
8
|
+
* `client.procedures` field, and an app imports the `/register` entry of each package that it uses.
|
|
11
9
|
*/
|
|
12
10
|
|
|
13
11
|
import { PROCEDURE_REGISTRY } from "./registry.js";
|
|
@@ -11,6 +11,41 @@ export const PURE_EFFECTS: Effects = Object.freeze({ reads: Object.freeze([]), w
|
|
|
11
11
|
/** The effects of a procedure that reads the procedure registry and changes nothing. */
|
|
12
12
|
export const REGISTRY_READ_EFFECTS: Effects = Object.freeze({ reads: Object.freeze(["registry"]), writes: Object.freeze([]) });
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* The metadata key of the effects that a host found for the body of `procedure.define`
|
|
16
|
+
* (`programCheckInterceptor` of `@procedures/compiler`, roadmap R22). The key starts with `__`, so
|
|
17
|
+
* each transport removes it from a request: only an interceptor of the host can set it.
|
|
18
|
+
*/
|
|
19
|
+
export const INFERRED_EFFECTS_METADATA_KEY = "__inferredEffects";
|
|
20
|
+
|
|
21
|
+
function isNameList(value: unknown): value is string[] {
|
|
22
|
+
return Array.isArray(value) && value.every((name) => typeof name === "string");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The effects that a host found for a data-driven procedure (`metadata.inferredEffects`), or
|
|
27
|
+
* undefined. They are information for the tool hints and the explanations. The admission still
|
|
28
|
+
* examines each nested call of the procedure.
|
|
29
|
+
*/
|
|
30
|
+
export function inferredEffectsOf(source: { readonly metadata?: unknown } | Record<string, unknown> | undefined): Effects | undefined {
|
|
31
|
+
const metadata = source && "metadata" in source ? (source as { metadata?: unknown }).metadata : source;
|
|
32
|
+
const value = (metadata as { inferredEffects?: unknown } | undefined)?.inferredEffects;
|
|
33
|
+
return effectsValue(value);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** An `Effects` value with known reads and writes, or undefined. */
|
|
37
|
+
export function effectsValue(value: unknown): Effects | undefined {
|
|
38
|
+
if (value === null || typeof value !== "object") return undefined;
|
|
39
|
+
const { reads, writes, destructive, idempotent } = value as Record<string, unknown>;
|
|
40
|
+
if (!isNameList(reads) || !isNameList(writes)) return undefined;
|
|
41
|
+
return Object.freeze({
|
|
42
|
+
reads: Object.freeze([...reads]),
|
|
43
|
+
writes: Object.freeze([...writes]),
|
|
44
|
+
...(typeof destructive === "boolean" ? { destructive } : {}),
|
|
45
|
+
...(typeof idempotent === "boolean" ? { idempotent } : {}),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
14
49
|
/**
|
|
15
50
|
* This function gives copies of the procedures with the effects in their metadata. A procedure
|
|
16
51
|
* that declares its own effects keeps them.
|