@jarenjs/contract 0.43.1

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.
Files changed (84) hide show
  1. package/README.md +508 -0
  2. package/dist/types/adapters/fetch.d.ts +27 -0
  3. package/dist/types/adapters/node.d.ts +47 -0
  4. package/dist/types/app/binding.d.ts +122 -0
  5. package/dist/types/app/effect.d.ts +77 -0
  6. package/dist/types/app/index.d.ts +31 -0
  7. package/dist/types/app/subscription.d.ts +82 -0
  8. package/dist/types/bundle.d.ts +43 -0
  9. package/dist/types/cli.d.ts +15 -0
  10. package/dist/types/client/http.d.ts +242 -0
  11. package/dist/types/client/outcome.d.ts +289 -0
  12. package/dist/types/compat.d.ts +36 -0
  13. package/dist/types/compile.d.ts +196 -0
  14. package/dist/types/describe.d.ts +115 -0
  15. package/dist/types/diff.d.ts +91 -0
  16. package/dist/types/errors.d.ts +205 -0
  17. package/dist/types/http/dispatch.d.ts +148 -0
  18. package/dist/types/http/serve.d.ts +154 -0
  19. package/dist/types/http/wire.d.ts +334 -0
  20. package/dist/types/index.d.ts +39 -0
  21. package/dist/types/ledger.d.ts +207 -0
  22. package/dist/types/local/index.d.ts +127 -0
  23. package/dist/types/messages.d.ts +63 -0
  24. package/dist/types/path.d.ts +119 -0
  25. package/dist/types/pipeline.d.ts +157 -0
  26. package/dist/types/port/client.d.ts +142 -0
  27. package/dist/types/port/frame.d.ts +195 -0
  28. package/dist/types/port/serve.d.ts +102 -0
  29. package/dist/types/project/index.d.ts +34 -0
  30. package/dist/types/project/markdown.d.ts +28 -0
  31. package/dist/types/project/openapi.d.ts +102 -0
  32. package/dist/types/project/tools.d.ts +57 -0
  33. package/dist/types/project/typescript.d.ts +59 -0
  34. package/dist/types/public.d.ts +73 -0
  35. package/dist/types/revision.d.ts +36 -0
  36. package/dist/types/stream/client.d.ts +104 -0
  37. package/dist/types/stream/server.d.ts +106 -0
  38. package/dist/types/stream/sse.d.ts +62 -0
  39. package/docs/APP-INTEGRATION.md +301 -0
  40. package/docs/CONTRACT-FORMAT.md +1923 -0
  41. package/package.json +110 -0
  42. package/schemas/jaren-contract-port.draft-07.schema.json +241 -0
  43. package/schemas/jaren-contract-port.schema.json +241 -0
  44. package/schemas/jaren-contract.draft-07.schema.json +287 -0
  45. package/schemas/jaren-contract.schema.json +287 -0
  46. package/src/adapters/fetch.js +109 -0
  47. package/src/adapters/node.js +238 -0
  48. package/src/app/binding.js +426 -0
  49. package/src/app/effect.js +190 -0
  50. package/src/app/index.js +26 -0
  51. package/src/app/subscription.js +130 -0
  52. package/src/bundle.js +168 -0
  53. package/src/cli.js +264 -0
  54. package/src/client/http.js +1150 -0
  55. package/src/client/outcome.js +364 -0
  56. package/src/compat.js +62 -0
  57. package/src/compile.js +1162 -0
  58. package/src/describe.js +109 -0
  59. package/src/diff.js +610 -0
  60. package/src/errors.js +236 -0
  61. package/src/http/dispatch.js +1054 -0
  62. package/src/http/serve.js +301 -0
  63. package/src/http/wire.js +469 -0
  64. package/src/index.js +33 -0
  65. package/src/ledger.js +225 -0
  66. package/src/local/index.js +363 -0
  67. package/src/messages.js +68 -0
  68. package/src/path.js +471 -0
  69. package/src/pipeline.js +241 -0
  70. package/src/port/client.js +518 -0
  71. package/src/port/frame.js +196 -0
  72. package/src/port/serve.js +442 -0
  73. package/src/project/index.js +29 -0
  74. package/src/project/markdown.js +244 -0
  75. package/src/project/openapi.js +564 -0
  76. package/src/project/openapi.jslt.json +149 -0
  77. package/src/project/tools.js +139 -0
  78. package/src/project/typescript.js +152 -0
  79. package/src/project/typescript.jtlt.json +72 -0
  80. package/src/public.js +206 -0
  81. package/src/revision.js +90 -0
  82. package/src/stream/client.js +212 -0
  83. package/src/stream/server.js +306 -0
  84. package/src/stream/sse.js +67 -0
@@ -0,0 +1,195 @@
1
+ /**
2
+ * @file The frame grammar of the port binding (docs/CONTRACT-FORMAT.md
3
+ * §16), shared by `servePort` and `openPortClient`: JSON-safe plain
4
+ * objects marked `jaren: "contract/0.1"`, so contract traffic is
5
+ * distinguishable BY SHAPE from anything else on a shared channel — a
6
+ * frame without the marker is never touched, and never answered.
7
+ *
8
+ * Request ids are `"<clientId>:<seq>"` — the client id a UUID per
9
+ * client instance, the sequence a per-client counter — so two clients
10
+ * on one broadcast channel can never collide, and a client recognizes
11
+ * its own responses with one cheap prefix test before any map lookup.
12
+ * The request members `attempt` and `key` are reserved by the grammar
13
+ * (`schemas/jaren-contract-port.schema.json`) and ignored by this
14
+ * order's server: the attempt id stays caller-side in `meta` (D6 — the
15
+ * identities live in state, never in the transport) and idempotency is
16
+ * not carried on this binding (`capabilities` says so).
17
+ */
18
+ /** The frame marker: the protocol and its version. */
19
+ export declare const FRAME_MARKER = "contract/0.1";
20
+ export type RequestFrame = {
21
+ jaren: string;
22
+ id: string;
23
+ op: string;
24
+ input: unknown;
25
+ };
26
+ export type ResponseFrame = {
27
+ jaren: string;
28
+ id: string;
29
+ ok: true;
30
+ value: unknown;
31
+ trace: string;
32
+ } | {
33
+ jaren: string;
34
+ id: string;
35
+ ok: false;
36
+ error: {
37
+ code: string;
38
+ message: string;
39
+ details?: unknown;
40
+ retryable?: boolean;
41
+ };
42
+ trace: string;
43
+ };
44
+ export type CancelFrame = {
45
+ jaren: string;
46
+ cancel: string;
47
+ };
48
+ export type SubscribeFrame = {
49
+ jaren: string;
50
+ subscribe: string;
51
+ op: string;
52
+ input: unknown;
53
+ lastSeq?: number;
54
+ };
55
+ export type UnsubscribeFrame = {
56
+ jaren: string;
57
+ unsubscribe: string;
58
+ };
59
+ export type PushFrame = {
60
+ jaren: string;
61
+ id: string;
62
+ event: string;
63
+ seq: number;
64
+ data: unknown;
65
+ };
66
+ export type ChannelLike = {
67
+ postMessage: (message: any) => void;
68
+ addEventListener?: (type: string, listener: (event: any) => void) => void;
69
+ removeEventListener?: (type: string, listener: (event: any) => void) => void;
70
+ onmessage?: ((event: any) => void) | null;
71
+ start?: () => void;
72
+ };
73
+ /**
74
+ * A request frame. `input` is the whole (validated) input object, or
75
+ * `null` for an input-less operation.
76
+ * @typedef {{ jaren: string, id: string, op: string, input: unknown }} RequestFrame
77
+ */
78
+ /**
79
+ * A response frame: success with the value, or an error envelope —
80
+ * `code` a declared error code or a `JC2xxx` taxonomy/binding code,
81
+ * `details` present only when the failure carries some. Every response
82
+ * carries the server's `trace`.
83
+ * @typedef {{ jaren: string, id: string, ok: true, value: unknown, trace: string }
84
+ * | { jaren: string, id: string, ok: false, error: { code: string, message: string, details?: unknown, retryable?: boolean }, trace: string }} ResponseFrame
85
+ */
86
+ /**
87
+ * A cancel frame: aborts the server-side signal of the named request —
88
+ * an optimization; the client's id scoping is the guarantee. Never
89
+ * answered.
90
+ * @typedef {{ jaren: string, cancel: string }} CancelFrame
91
+ */
92
+ /**
93
+ * A subscribe frame: opens one stream (docs/CONTRACT-FORMAT.md §18.2).
94
+ * `input` is the whole (validated) input object or `null`; `lastSeq`,
95
+ * when present, asks to resume after that seq.
96
+ * @typedef {{ jaren: string, subscribe: string, op: string, input: unknown, lastSeq?: number }} SubscribeFrame
97
+ */
98
+ /**
99
+ * An unsubscribe frame: closes the named stream. Never answered.
100
+ * @typedef {{ jaren: string, unsubscribe: string }} UnsubscribeFrame
101
+ */
102
+ /**
103
+ * A push frame: one stream event, server → client. `event` is
104
+ * `snapshot | patch | error | end` with the §18 data shapes; `seq` is
105
+ * the event's seq (`error`/`end` carry the last delivered one).
106
+ * @typedef {{ jaren: string, id: string, event: string, seq: number, data: unknown }} PushFrame
107
+ */
108
+ /**
109
+ * The channel shape both halves accept: a `MessagePort`, a `Worker`, a
110
+ * `BroadcastChannel`, a worker's own `self`, or any object with
111
+ * `postMessage` and a message-listener surface. `start` is called when
112
+ * present (a `MessagePort` queues until it is).
113
+ * @typedef {{ postMessage: (message: any) => void,
114
+ * addEventListener?: (type: string, listener: (event: any) => void) => void,
115
+ * removeEventListener?: (type: string, listener: (event: any) => void) => void,
116
+ * onmessage?: ((event: any) => void) | null,
117
+ * start?: () => void }} ChannelLike
118
+ */
119
+ /**
120
+ * Whether a value is a contract frame at all — the marker test every
121
+ * listener applies first, so foreign traffic on a shared channel is
122
+ * ignored by shape. Reads one member of a plain object; total.
123
+ * @param {unknown} value
124
+ * @returns {value is { jaren: string }}
125
+ */
126
+ export declare function isContractFrame(value: unknown): value is {
127
+ jaren: string;
128
+ };
129
+ /**
130
+ * @param {string} id
131
+ * @param {string} op
132
+ * @param {unknown} input
133
+ * @returns {RequestFrame}
134
+ */
135
+ export declare function requestFrame(id: string, op: string, input: unknown): RequestFrame;
136
+ /**
137
+ * @param {string} id
138
+ * @param {unknown} value - `undefined` is carried as `null` (frames are JSON)
139
+ * @param {string} trace
140
+ * @returns {ResponseFrame}
141
+ */
142
+ export declare function valueFrame(id: string, value: unknown, trace: string): ResponseFrame;
143
+ /**
144
+ * @param {string} id
145
+ * @param {string} code
146
+ * @param {string} message
147
+ * @param {unknown} details - omitted from the frame when `undefined`
148
+ * @param {boolean} retryable
149
+ * @param {string} trace
150
+ * @returns {ResponseFrame}
151
+ */
152
+ export declare function errorFrame(id: string, code: string, message: string, details: unknown, retryable: boolean, trace: string): ResponseFrame;
153
+ /**
154
+ * @param {string} id
155
+ * @returns {CancelFrame}
156
+ */
157
+ export declare function cancelFrame(id: string): CancelFrame;
158
+ /**
159
+ * @param {string} id
160
+ * @param {string} op
161
+ * @param {unknown} input
162
+ * @param {number | null} lastSeq - omitted from the frame when `null`
163
+ * @returns {SubscribeFrame}
164
+ */
165
+ export declare function subscribeFrame(id: string, op: string, input: unknown, lastSeq: number | null): SubscribeFrame;
166
+ /**
167
+ * @param {string} id
168
+ * @returns {UnsubscribeFrame}
169
+ */
170
+ export declare function unsubscribeFrame(id: string): UnsubscribeFrame;
171
+ /**
172
+ * @param {string} id
173
+ * @param {string} event - `snapshot | patch | error | end`
174
+ * @param {number} seq
175
+ * @param {unknown} data
176
+ * @returns {PushFrame}
177
+ */
178
+ export declare function pushFrame(id: string, event: string, seq: number, data: unknown): PushFrame;
179
+ /**
180
+ * Attach a message listener to a channel: `addEventListener` where the
181
+ * channel has one (plus `start()`, which a `MessagePort` needs to begin
182
+ * delivery), the `onmessage` slot otherwise. Returns the detacher.
183
+ * @param {ChannelLike} channel
184
+ * @param {(event: any) => void} listener
185
+ * @returns {() => void}
186
+ */
187
+ export declare function attach(channel: ChannelLike, listener: (event: any) => void): () => void;
188
+ /**
189
+ * Whether a value is a usable channel. The listener surface is either
190
+ * `addEventListener` or an assignable `onmessage` slot — `in` sees the
191
+ * slot on platform channels and plain fakes alike.
192
+ * @param {unknown} value
193
+ * @returns {value is ChannelLike}
194
+ */
195
+ export declare function isChannel(value: unknown): value is ChannelLike;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * @file `servePort(contract, handlers, options)`: the server half of the
3
+ * port binding (docs/CONTRACT-FORMAT.md §16) — request/response over a
4
+ * `MessagePort`, a `Worker`, a `BroadcastChannel` or a worker's own
5
+ * `self`. Requests run through the same neutral pipeline as every other
6
+ * server binding, under one `AbortController` per request id; a cancel
7
+ * frame aborts it (an optimization — the client's id scoping is the
8
+ * guarantee), and the response is posted back on the same channel.
9
+ *
10
+ * The listener touches nothing without the frame marker — other traffic
11
+ * may share the channel and is never answered — and never answers a
12
+ * RESPONSE frame either, so two ends on one broadcast channel cannot
13
+ * echo at each other. A request naming an operation this channel does
14
+ * not serve (unknown, or opaque — a port carries JSON only) is answered
15
+ * `JC2071` without echoing what it asked for; an invalid input is
16
+ * `JC2006` with details by the operation's policy; a handler fault of
17
+ * any class is `JC2070` with the cause reported to `onError`, never
18
+ * onto the wire. Exactly ONE server should serve a shared channel — two
19
+ * would both answer every request.
20
+ */
21
+ import { PORT_LOCAL_ERRORS } from '../pipeline.js';
22
+ export { openPortClient } from './client.js';
23
+ export { FRAME_MARKER, isContractFrame } from './frame.js';
24
+ export { PORT_LOCAL_ERRORS };
25
+ export type Contract = import('../compile.js').Contract;
26
+ export type CompiledOperation = import('../compile.js').CompiledOperation;
27
+ export type Catalog = import('../http/wire.js').Catalog;
28
+ export type Handler = import('../http/dispatch.js').Handler;
29
+ export type PipelineRoute = import('../pipeline.js').PipelineRoute;
30
+ export type ChannelLike = import('./frame.js').ChannelLike;
31
+ export type ServePortOptions = {
32
+ /**
33
+ * - the channel to serve (required)
34
+ */
35
+ channel: ChannelLike;
36
+ /**
37
+ * - the server trace generator; default `crypto.randomUUID`
38
+ */
39
+ trace?: () => string;
40
+ /**
41
+ * - `'never'` is a declared
42
+ * downgrade, reported in `capabilities.validatedOutput`
43
+ */
44
+ validateOutput?: 'always' | 'never';
45
+ /**
46
+ * - a message catalog consulted before the English one
47
+ */
48
+ catalog?: Record<string, string | ((params: object) => string)>;
49
+ /**
50
+ * - observes the cause behind every `JC2070` frame, validator throws
51
+ * and a channel whose `postMessage` throws
52
+ */
53
+ onError?: (error: unknown, ctx: {
54
+ op: string;
55
+ trace: string;
56
+ } | null) => void;
57
+ };
58
+ export type PortServerCapabilities = {
59
+ name: 'port';
60
+ status: false;
61
+ headers: false;
62
+ media: false;
63
+ etag: false;
64
+ idempotency: false;
65
+ validatedOutput: boolean;
66
+ /**
67
+ * - subscribe operations stream as push frames (docs/CONTRACT-FORMAT.md §18.2)
68
+ */
69
+ stream: true;
70
+ cancel: 'message';
71
+ };
72
+ export type PortServer = {
73
+ capabilities: PortServerCapabilities;
74
+ contract: Contract;
75
+ describe: () => any;
76
+ /**
77
+ * - ends every live stream with `end`
78
+ * (`server-shutdown`), detaches the listener and aborts every in-flight request
79
+ */
80
+ close: () => void;
81
+ };
82
+ export type PortRoute = PipelineRoute & {
83
+ stream: boolean;
84
+ };
85
+ /**
86
+ * Serve a compiled contract over a message channel. Construction refuses
87
+ * host mistakes (`JC1001` handler table, channel or option, `JC1002`
88
+ * missing handler — an opaque operation is exempt, it is answered
89
+ * `JC2071` instead of served).
90
+ *
91
+ * @param {Contract} contract
92
+ * @param {Record<string, Handler>} handlers - operation id → handler
93
+ * @param {ServePortOptions} options
94
+ * @returns {PortServer}
95
+ * @throws {ContractHostError}
96
+ * @example
97
+ * // inside a worker: serve the worker's own channel
98
+ * servePort(contract, handlers, { channel: self });
99
+ * // and the same handlers to every tab on a BroadcastChannel
100
+ * servePort(contract, handlers, { channel: new BroadcastChannel('app') });
101
+ */
102
+ export declare function servePort(contract: Contract, handlers: Record<string, Handler>, options: ServePortOptions): PortServer;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @file The projections of a compiled contract (`@jarenjs/contract/project`):
3
+ * `publicProjection` (the browser-safe subset — itself a `$contract`
4
+ * document, and what the revision hashes), `toOpenApi` (OpenAPI 3.1
5
+ * through a JSLT stylesheet), `toTypeScript` and `toMarkdown` (on
6
+ * `@jarenjs/emit`'s type model), `contractTools` (`@jarenjs/ai` tool
7
+ * definitions, no import edge) and the same-document bundler they share.
8
+ * This is the one subpath that imports `@jarenjs/emit`; a consumer that
9
+ * never imports it never loads it.
10
+ */
11
+ export { publicProjection } from '../public.js';
12
+ export { toOpenApi } from './openapi.js';
13
+ export { toTypeScript } from './typescript.js';
14
+ export { toMarkdown } from './markdown.js';
15
+ export { contractTools } from './tools.js';
16
+ export { reachableDefs, bundleSameDocument } from '../bundle.js';
17
+ export type PublicProjectionOptions = import('../public.js').PublicProjectionOptions;
18
+ export type OpenApiOptions = import('./openapi.js').OpenApiOptions;
19
+ export type OpenApiResult = import('./openapi.js').OpenApiResult;
20
+ export type DroppedKeyword = import('./openapi.js').DroppedKeyword;
21
+ export type TypeScriptOptions = import('./typescript.js').TypeScriptOptions;
22
+ export type MarkdownOptions = import('./markdown.js').MarkdownOptions;
23
+ export type ToolDefinition = import('./tools.js').ToolDefinition;
24
+ export type ContractToolsOptions = import('./tools.js').ContractToolsOptions;
25
+ /**
26
+ * @typedef {import('../public.js').PublicProjectionOptions} PublicProjectionOptions
27
+ * @typedef {import('./openapi.js').OpenApiOptions} OpenApiOptions
28
+ * @typedef {import('./openapi.js').OpenApiResult} OpenApiResult
29
+ * @typedef {import('./openapi.js').DroppedKeyword} DroppedKeyword
30
+ * @typedef {import('./typescript.js').TypeScriptOptions} TypeScriptOptions
31
+ * @typedef {import('./markdown.js').MarkdownOptions} MarkdownOptions
32
+ * @typedef {import('./tools.js').ToolDefinition} ToolDefinition
33
+ * @typedef {import('./tools.js').ContractToolsOptions} ContractToolsOptions
34
+ */
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @file `toMarkdown`: a compiled contract as one reference document —
3
+ * the title and version, an operations table, one section per public
4
+ * operation (its doc, parameters, body, responses, errors) and the types
5
+ * rendered through `@jarenjs/emit`'s Markdown target over the SAME type
6
+ * model the TypeScript projection uses (`contractTypeModel`), so the
7
+ * names a reader meets in the operation sections are the names the
8
+ * `.d.ts` declares. The document shape is a JTLT stylesheet (compiled
9
+ * once at module scope); the JavaScript half derives the rows.
10
+ */
11
+ export type Contract = import('../compile.js').Contract;
12
+ export type CompiledOperation = import('../compile.js').CompiledOperation;
13
+ export type MarkdownOptions = {
14
+ /**
15
+ * - the document title (default: the contract id, or `jaren-contract`)
16
+ */
17
+ title?: string;
18
+ };
19
+ /**
20
+ * Project a compiled contract to Markdown reference documentation.
21
+ * @param {Contract} contract
22
+ * @param {MarkdownOptions} [options]
23
+ * @returns {string} Markdown
24
+ * @throws {ContractHostError} `JC1008` — not a compiled contract, or a malformed option
25
+ * @example
26
+ * writeFileSync('shop.md', toMarkdown(contract, { title: 'Shop API' }));
27
+ */
28
+ export declare function toMarkdown(contract: Contract, options?: MarkdownOptions): string;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * @file `toOpenApi`: the public projection of a compiled contract as a
3
+ * valid, deterministic OpenAPI 3.1 document (docs/CONTRACT-FORMAT.md
4
+ * §12.2), in two stages that each own one concern:
5
+ *
6
+ * 1. **The keyword policy** (this file, JavaScript) walks every schema
7
+ * the projection carries and maps it into the OpenAPI 3.1 dialect —
8
+ * `#/$defs/X` → `#/components/schemas/X`, `nullable: true` → `null`
9
+ * in `type` — or refuses what it cannot map honestly (`JC0060`: a
10
+ * boolean `required`, a `components` member inside a schema, a
11
+ * same-document `$ref` that lands outside `$defs`) or drops and
12
+ * REPORTS what is Jaren-side (`$query`, `$data`, `errorMessage`,
13
+ * `x-form` and other `x-*`) in the `dropped` list with the `docPath`
14
+ * of the keyword in the contract document. Nothing unsupported passes
15
+ * through silently. It also derives, per operation, the facts a
16
+ * document cannot carry for a `$ref` input — the member table with
17
+ * each member's location, requiredness and effective schema — from
18
+ * the compiled operation.
19
+ * 2. **The stylesheet** (`openapi.jslt.json`, a JSLT document compiled
20
+ * once at module scope) shapes the document: `paths` grouped by
21
+ * canonical path and sorted by path then method, the operation
22
+ * object in a fixed member order, parameters, the request body, the
23
+ * success response, the declared errors grouped by status into
24
+ * wire-error schemas (`code` enum-pinned, `details` the declared
25
+ * schema), the binding's own statuses as shared
26
+ * `components.responses`, `components.schemas` from `$defs`, and the
27
+ * `x-jaren-policy` extension.
28
+ *
29
+ * Rendered twice, the document is byte-identical; a test validates it
30
+ * against the vendored OpenAPI 3.1 meta-schema with `JarenValidator`.
31
+ */
32
+ export type Contract = import('../compile.js').Contract;
33
+ export type CompiledOperation = import('../compile.js').CompiledOperation;
34
+ export type DroppedKeyword = {
35
+ /**
36
+ * - JSON Pointer of the keyword in the contract document
37
+ */
38
+ docPath: string;
39
+ keyword: string;
40
+ reason: string;
41
+ };
42
+ export type OpenApiOptions = {
43
+ /**
44
+ * -
45
+ * the `info` object; `title` defaults to the contract id, `version` to
46
+ * the contract version
47
+ */
48
+ info?: {
49
+ title?: string;
50
+ version?: string;
51
+ [k: string]: unknown;
52
+ };
53
+ /**
54
+ * - the `servers` array, verbatim
55
+ */
56
+ servers?: {
57
+ url: string;
58
+ description?: string;
59
+ }[];
60
+ /**
61
+ * - drop and report a boolean `required`
62
+ * and an unmappable same-document `$ref` instead of refusing (`JC0060`)
63
+ */
64
+ lenient?: boolean;
65
+ };
66
+ export type OpenApiResult = {
67
+ /**
68
+ * - the OpenAPI 3.1 document
69
+ */
70
+ document: Record<string, unknown>;
71
+ /**
72
+ * - every keyword the keyword policy removed
73
+ */
74
+ dropped: DroppedKeyword[];
75
+ };
76
+ export type MapContext = {
77
+ lenient: boolean;
78
+ dropped: DroppedKeyword[];
79
+ /**
80
+ * - the `$defs` names the projection carries
81
+ */
82
+ defs: Set<string>;
83
+ /**
84
+ * - source schema node → its mapped
85
+ * copy; every node is mapped once (the projection's roots cover every
86
+ * member), so a member's mapped schema is a lookup, and a keyword is
87
+ * reported once
88
+ */
89
+ mapped: Map<object, any>;
90
+ };
91
+ /**
92
+ * Project a compiled contract to an OpenAPI 3.1 document.
93
+ * @param {Contract} contract
94
+ * @param {OpenApiOptions} [options]
95
+ * @returns {OpenApiResult}
96
+ * @throws {ContractHostError} `JC1008` — not a compiled contract, or a malformed option
97
+ * @throws {ContractCompileError} `JC0060` — a schema keyword the projection refuses (see `lenient`)
98
+ * @example
99
+ * const { document, dropped } = toOpenApi(contract, { info: { title: 'Shop', version: '5' } });
100
+ * document.paths['/api/catalog'].get.operationId; // 'catalog.load'
101
+ */
102
+ export declare function toOpenApi(contract: Contract, options?: OpenApiOptions): OpenApiResult;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @file `contractTools`: the public, invokable operations of a contract as
3
+ * tool definitions for `@jarenjs/ai`'s toolbox — `{ name, description,
4
+ * inputSchema, execute }`, a plain object the toolbox and a WebMCP host
5
+ * read, so this package never imports the ai package (the generated-
6
+ * document rule). `execute` calls the client's `invoke` and answers the
7
+ * outcome JSON, so a model sees the same `{ ok, value | error, meta }`
8
+ * an app does; the toolbox validates the arguments against `inputSchema`
9
+ * before `execute` runs, and `invoke` validates them again against the
10
+ * same schema (the contract's own validator) before anything is sent.
11
+ */
12
+ export type Contract = import('../compile.js').Contract;
13
+ export type CompiledOperation = import('../compile.js').CompiledOperation;
14
+ export type ToolDefinition = {
15
+ name: string;
16
+ description: string;
17
+ /**
18
+ * - the operation's input schema, self-contained
19
+ */
20
+ inputSchema: any;
21
+ /**
22
+ * - `client.invoke(op, args)`, resolving the outcome
23
+ */
24
+ execute: (args: any) => any;
25
+ };
26
+ export type ToolClient = {
27
+ invoke: (op: string, input: any, ctx?: any) => any;
28
+ };
29
+ export type ContractToolsOptions = {
30
+ /**
31
+ * - the operations to expose (default:
32
+ * every public, non-opaque, non-subscribe operation); an opaque,
33
+ * subscribe or unknown id is refused
34
+ */
35
+ ops?: readonly string[];
36
+ /**
37
+ * - the tool name of an
38
+ * operation (default: the id with `.` → `_`); must satisfy OpenAI's
39
+ * `^[a-zA-Z0-9_-]{1,64}$` and be distinct per operation
40
+ */
41
+ name?: (id: string) => string;
42
+ };
43
+ /**
44
+ * Tool definitions for the public, invokable operations of a contract.
45
+ * @param {Contract} contract
46
+ * @param {ToolClient} client - a client opened on the same contract (`openHttpClient`, or any binding's)
47
+ * @param {ContractToolsOptions} [options]
48
+ * @returns {ToolDefinition[]} in document order
49
+ * @throws {ContractHostError} `JC1008` — not a compiled contract, a client
50
+ * without `invoke`, `ops` naming an unknown or opaque operation, a tool
51
+ * name outside `^[a-zA-Z0-9_-]{1,64}$`, or two operations mapping to one name
52
+ * @example
53
+ * const toolbox = createToolbox(); // @jarenjs/ai
54
+ * for (const tool of contractTools(contract, client)) toolbox.add(tool);
55
+ * await toolbox.execute('product_save', { id: 1, revision: 2, product: { … } }); // → an outcome
56
+ */
57
+ export declare function contractTools(contract: Contract, client: ToolClient, options?: ContractToolsOptions): ToolDefinition[];
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @file `toTypeScript`: a compiled contract as one `.d.ts` — every public
3
+ * operation's input, output and error-details types through
4
+ * `@jarenjs/emit`'s type model (`compileEmitModel` + `renderTypeScript`,
5
+ * the suite's one declaration renderer), then a typed operation map and
6
+ * the client/handler declarations through a JTLT stylesheet
7
+ * (`typescript.jtlt.json`, compiled once at module scope).
8
+ *
9
+ * One emit model covers the whole contract: a synthetic root whose
10
+ * `$defs` holds the operation types first (`<PascalOp>Input`,
11
+ * `<PascalOp>Output`, `<PascalOp><PascalCode>Details`) and the reachable
12
+ * contract `$defs` after them. Emit declares `$defs` first and in
13
+ * document order and names each after its key, so the operation types
14
+ * keep the names this module gives them (a contract `$defs` entry that
15
+ * spells the same name is the one emit suffixes); their `#/$defs/X`
16
+ * references resolve against the same root, so a `Product` referenced
17
+ * from three operations is declared once. The root's own declaration
18
+ * (`unknown`) is not rendered.
19
+ *
20
+ * `Meta`, `WireError`, `Outcome<T>`, `InvokeContext`, `Client`,
21
+ * `Failure`, `HandlerContext` and `Handlers` are fixed text in the
22
+ * stylesheet — the D6 shapes as every binding carries them
23
+ * (`OUTCOME_META_MEMBERS` / `OUTCOME_ERROR_MEMBERS` in the client module
24
+ * are the runtime twins; a test holds the text to them).
25
+ */
26
+ export type Contract = import('../compile.js').Contract;
27
+ export type CompiledOperation = import('../compile.js').CompiledOperation;
28
+ export type TypeScriptOptions = {
29
+ /**
30
+ * - emit the do-not-edit header
31
+ */
32
+ banner?: boolean;
33
+ };
34
+ /**
35
+ * The type model of a contract: the synthetic `$defs` root, the row per
36
+ * operation the stylesheet renders, and the rendered declarations.
37
+ * @param {Contract} contract
38
+ * @param {CompiledOperation[]} ops
39
+ * @param {string} source - what the model records as its source
40
+ * @returns {{ types: string, rows: Record<string, unknown>[], model: import('@jarenjs/emit/model').EmitModel }}
41
+ */
42
+ export declare function contractTypeModel(contract: Contract, ops: CompiledOperation[], source: string): {
43
+ types: string;
44
+ rows: Record<string, unknown>[];
45
+ model: import('@jarenjs/emit/model').EmitModel;
46
+ };
47
+ /**
48
+ * Project a compiled contract to TypeScript declarations: the operation
49
+ * types, `Operations`, `UrlOperations`, `Meta`, `WireError`, `Outcome<T>`,
50
+ * `InvokeContext`, `Client`, `Failure`, `HandlerContext`, `Handlers`.
51
+ * @param {Contract} contract
52
+ * @param {TypeScriptOptions} [options]
53
+ * @returns {string} TypeScript source (`.d.ts`)
54
+ * @throws {ContractHostError} `JC1008` — not a compiled contract, or a malformed option
55
+ * @example
56
+ * writeFileSync('shop.d.ts', toTypeScript(contract));
57
+ * // import type { Client, Operations } from './shop.js';
58
+ */
59
+ export declare function toTypeScript(contract: Contract, options?: TypeScriptOptions): string;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @file `publicProjection`: the browser-safe subset of a compiled contract
3
+ * as a JSON document that is ITSELF a valid `$contract` 0.1 — what a
4
+ * client needs and no more, what the revision hashes, and what every other
5
+ * projection (OpenAPI, TypeScript, Markdown, tools) is built on.
6
+ *
7
+ * Retained: the operations whose `policy.audience` is not `server` (and,
8
+ * when the caller narrows with `ops`, only those), each with its resolved
9
+ * binding and policy minus the server-side knobs (`limits`,
10
+ * `errors.details`), plus the `$defs` the retained schemas reach. Member
11
+ * order is FIXED (docs/CONTRACT-FORMAT.md §12.1 — normative, because the
12
+ * revision is the SHA-256 of the canonical bytes of this document): root
13
+ * `$contract, id, version, compat, $defs, operations`; operation `kind,
14
+ * input, output, errors, policy, http, doc`; policy `task, idempotency,
15
+ * revision, cache, retry, stream, audience`; http `method, path, in, body, status,
16
+ * media`; error `status, schema`; operations in document order; `$defs` in
17
+ * first-reference order. Defaults are materialized (the projection says
18
+ * what the binding DOES, not what the author typed), so two documents
19
+ * that behave alike project alike, and the projection of a projection is
20
+ * the projection.
21
+ */
22
+ export type Contract = import('./compile.js').Contract;
23
+ export type CompiledOperation = import('./compile.js').CompiledOperation;
24
+ export type PublicProjectionOptions = {
25
+ /**
26
+ * - the operations to keep, a subset
27
+ * of the contract's ids (default: all); `server` operations are never
28
+ * kept, listed or not
29
+ */
30
+ ops?: readonly string[];
31
+ };
32
+ /**
33
+ * @typedef {import('./compile.js').Contract} Contract
34
+ * @typedef {import('./compile.js').CompiledOperation} CompiledOperation
35
+ */
36
+ /**
37
+ * @typedef {Object} PublicProjectionOptions
38
+ * @property {readonly string[]} [ops] - the operations to keep, a subset
39
+ * of the contract's ids (default: all); `server` operations are never
40
+ * kept, listed or not
41
+ */
42
+ /**
43
+ * Whether `value` is a compiled contract — reads the members every
44
+ * projection needs.
45
+ * @param {unknown} value
46
+ * @returns {value is Contract}
47
+ */
48
+ export declare function isCompiledContract(value: unknown): value is Contract;
49
+ /**
50
+ * The operations a projection retains, in document order: the public
51
+ * ones, narrowed by `ops` when given. Throws `JC1008` for a malformed
52
+ * `contract` or an `ops` entry that names no operation.
53
+ * @param {Contract} contract
54
+ * @param {readonly string[] | undefined} ops
55
+ * @param {string} who - the projection's name, for the message
56
+ * @returns {CompiledOperation[]}
57
+ */
58
+ export declare function retainedOperations(contract: Contract, ops: readonly string[] | undefined, who: string): CompiledOperation[];
59
+ /**
60
+ * The public projection of a compiled contract: a `$contract` 0.1
61
+ * document (it compiles) holding the public operations with their
62
+ * resolved bindings and policies and the `$defs` they reach, in the fixed
63
+ * member order the revision hashes. Schema subtrees are the contract's own
64
+ * (frozen); the composition is fresh.
65
+ * @param {Contract} contract
66
+ * @param {PublicProjectionOptions} [options]
67
+ * @returns {Record<string, unknown>}
68
+ * @throws {ContractHostError} `JC1008` — not a compiled contract, or `ops` names no operation
69
+ * @example
70
+ * const pub = publicProjection(contract);
71
+ * compileContract(pub).ids; // the public operations, in document order
72
+ */
73
+ export declare function publicProjection(contract: Contract, options?: PublicProjectionOptions): Record<string, unknown>;