@astrale-os/kernel-protocol 0.5.0-beta.10

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 (224) hide show
  1. package/LICENSE +202 -0
  2. package/dist/artifact/index.d.ts +1 -0
  3. package/dist/artifact/index.js +1 -0
  4. package/dist/artifact/ref.d.ts +10 -0
  5. package/dist/artifact/ref.js +70 -0
  6. package/dist/codecs/codec.d.ts +13 -0
  7. package/dist/codecs/codec.js +6 -0
  8. package/dist/codecs/index.d.ts +4 -0
  9. package/dist/codecs/index.js +4 -0
  10. package/dist/codecs/json.d.ts +2 -0
  11. package/dist/codecs/json.js +20 -0
  12. package/dist/codecs/media-types.d.ts +2 -0
  13. package/dist/codecs/media-types.js +2 -0
  14. package/dist/codecs/msgpack.d.ts +4 -0
  15. package/dist/codecs/msgpack.js +50 -0
  16. package/dist/errors/codes.d.ts +23 -0
  17. package/dist/errors/codes.js +22 -0
  18. package/dist/errors/http-status.d.ts +2 -0
  19. package/dist/errors/http-status.js +25 -0
  20. package/dist/errors/index.d.ts +5 -0
  21. package/dist/errors/index.js +5 -0
  22. package/dist/errors/payload.d.ts +8 -0
  23. package/dist/errors/payload.js +37 -0
  24. package/dist/errors/protocol-error.d.ts +6 -0
  25. package/dist/errors/protocol-error.js +11 -0
  26. package/dist/errors/reason.d.ts +7 -0
  27. package/dist/errors/reason.js +43 -0
  28. package/dist/index.d.ts +8 -0
  29. package/dist/index.js +8 -0
  30. package/dist/invocation/admission.d.ts +23 -0
  31. package/dist/invocation/admission.js +177 -0
  32. package/dist/invocation/binary.d.ts +11 -0
  33. package/dist/invocation/binary.js +24 -0
  34. package/dist/invocation/binding-codecs.d.ts +8 -0
  35. package/dist/invocation/binding-codecs.js +27 -0
  36. package/dist/invocation/cancellation.d.ts +8 -0
  37. package/dist/invocation/cancellation.js +16 -0
  38. package/dist/invocation/correlation.d.ts +2 -0
  39. package/dist/invocation/correlation.js +7 -0
  40. package/dist/invocation/delegate.d.ts +24 -0
  41. package/dist/invocation/delegate.js +43 -0
  42. package/dist/invocation/http/binary.d.ts +12 -0
  43. package/dist/invocation/http/binary.js +132 -0
  44. package/dist/invocation/http/index.d.ts +4 -0
  45. package/dist/invocation/http/index.js +4 -0
  46. package/dist/invocation/http/negotiation.d.ts +3 -0
  47. package/dist/invocation/http/negotiation.js +207 -0
  48. package/dist/invocation/http/stream.d.ts +5 -0
  49. package/dist/invocation/http/stream.js +15 -0
  50. package/dist/invocation/http/trace.d.ts +6 -0
  51. package/dist/invocation/http/trace.js +24 -0
  52. package/dist/invocation/idempotency.d.ts +10 -0
  53. package/dist/invocation/idempotency.js +13 -0
  54. package/dist/invocation/identity.d.ts +16 -0
  55. package/dist/invocation/identity.js +55 -0
  56. package/dist/invocation/index.d.ts +20 -0
  57. package/dist/invocation/index.js +20 -0
  58. package/dist/invocation/miss.d.ts +9 -0
  59. package/dist/invocation/miss.js +17 -0
  60. package/dist/invocation/redirect.d.ts +40 -0
  61. package/dist/invocation/redirect.js +81 -0
  62. package/dist/invocation/request.d.ts +21 -0
  63. package/dist/invocation/request.js +54 -0
  64. package/dist/invocation/response.d.ts +19 -0
  65. package/dist/invocation/response.js +38 -0
  66. package/dist/invocation/routing.d.ts +14 -0
  67. package/dist/invocation/routing.js +34 -0
  68. package/dist/invocation/schema.d.ts +9 -0
  69. package/dist/invocation/schema.js +19 -0
  70. package/dist/invocation/service-reason.d.ts +48 -0
  71. package/dist/invocation/service-reason.js +85 -0
  72. package/dist/invocation/stale-route.d.ts +12 -0
  73. package/dist/invocation/stale-route.js +19 -0
  74. package/dist/invocation/stream.d.ts +27 -0
  75. package/dist/invocation/stream.js +44 -0
  76. package/dist/invocation/target.d.ts +3 -0
  77. package/dist/invocation/target.js +11 -0
  78. package/dist/invocation/trace.d.ts +9 -0
  79. package/dist/invocation/trace.js +86 -0
  80. package/dist/invocation/version.d.ts +2 -0
  81. package/dist/invocation/version.js +1 -0
  82. package/dist/invocation/websocket/binary.d.ts +3 -0
  83. package/dist/invocation/websocket/binary.js +71 -0
  84. package/dist/invocation/websocket/index.d.ts +2 -0
  85. package/dist/invocation/websocket/index.js +2 -0
  86. package/dist/invocation/websocket/subprotocol.d.ts +10 -0
  87. package/dist/invocation/websocket/subprotocol.js +29 -0
  88. package/dist/issuer/configuration.d.ts +14 -0
  89. package/dist/issuer/configuration.js +86 -0
  90. package/dist/issuer/error.d.ts +7 -0
  91. package/dist/issuer/error.js +11 -0
  92. package/dist/issuer/exchange.d.ts +25 -0
  93. package/dist/issuer/exchange.js +129 -0
  94. package/dist/issuer/hosted.d.ts +2 -0
  95. package/dist/issuer/hosted.js +7 -0
  96. package/dist/issuer/index.d.ts +6 -0
  97. package/dist/issuer/index.js +6 -0
  98. package/dist/issuer/key-set.d.ts +6 -0
  99. package/dist/issuer/key-set.js +48 -0
  100. package/dist/issuer/paths.d.ts +6 -0
  101. package/dist/issuer/paths.js +10 -0
  102. package/dist/issuer/url.d.ts +2 -0
  103. package/dist/issuer/url.js +34 -0
  104. package/dist/publication/bindings/callable.d.ts +8 -0
  105. package/dist/publication/bindings/callable.js +34 -0
  106. package/dist/publication/bindings/index.d.ts +3 -0
  107. package/dist/publication/bindings/index.js +3 -0
  108. package/dist/publication/bindings/invocation.d.ts +5 -0
  109. package/dist/publication/bindings/invocation.js +13 -0
  110. package/dist/publication/bindings/view.d.ts +7 -0
  111. package/dist/publication/bindings/view.js +28 -0
  112. package/dist/publication/bundle-admission.d.ts +4 -0
  113. package/dist/publication/bundle-admission.js +65 -0
  114. package/dist/publication/bundle-descriptor.d.ts +9 -0
  115. package/dist/publication/bundle-descriptor.js +19 -0
  116. package/dist/publication/bundle-evidence.d.ts +3 -0
  117. package/dist/publication/bundle-evidence.js +13 -0
  118. package/dist/publication/bundle.d.ts +9 -0
  119. package/dist/publication/bundle.js +44 -0
  120. package/dist/publication/content.d.ts +10 -0
  121. package/dist/publication/content.js +55 -0
  122. package/dist/publication/declaration.d.ts +11 -0
  123. package/dist/publication/declaration.js +1 -0
  124. package/dist/publication/delivery/attestation.d.ts +6 -0
  125. package/dist/publication/delivery/attestation.js +10 -0
  126. package/dist/publication/delivery/claims.d.ts +16 -0
  127. package/dist/publication/delivery/claims.js +61 -0
  128. package/dist/publication/delivery/delivery.d.ts +9 -0
  129. package/dist/publication/delivery/delivery.js +29 -0
  130. package/dist/publication/delivery/error.d.ts +7 -0
  131. package/dist/publication/delivery/error.js +11 -0
  132. package/dist/publication/delivery/index.d.ts +6 -0
  133. package/dist/publication/delivery/index.js +6 -0
  134. package/dist/publication/delivery/limits.d.ts +4 -0
  135. package/dist/publication/delivery/limits.js +4 -0
  136. package/dist/publication/delivery/request.d.ts +15 -0
  137. package/dist/publication/delivery/request.js +52 -0
  138. package/dist/publication/delivery-declaration.d.ts +4 -0
  139. package/dist/publication/delivery-declaration.js +25 -0
  140. package/dist/publication/delivery-endpoint.d.ts +11 -0
  141. package/dist/publication/delivery-endpoint.js +22 -0
  142. package/dist/publication/error.d.ts +7 -0
  143. package/dist/publication/error.js +11 -0
  144. package/dist/publication/etag.d.ts +6 -0
  145. package/dist/publication/etag.js +79 -0
  146. package/dist/publication/index.d.ts +17 -0
  147. package/dist/publication/index.js +10 -0
  148. package/dist/publication/manifest.d.ts +6 -0
  149. package/dist/publication/manifest.js +30 -0
  150. package/dist/publication/publication.d.ts +36 -0
  151. package/dist/publication/publication.js +133 -0
  152. package/dist/publication/reference.d.ts +17 -0
  153. package/dist/publication/reference.js +68 -0
  154. package/dist/publication/requirements.d.ts +26 -0
  155. package/dist/publication/requirements.js +180 -0
  156. package/dist/publication/route.d.ts +37 -0
  157. package/dist/publication/route.js +154 -0
  158. package/dist/publication/schema.d.ts +7 -0
  159. package/dist/publication/schema.js +15 -0
  160. package/dist/routes/admission.d.ts +3 -0
  161. package/dist/routes/admission.js +89 -0
  162. package/dist/routes/binding.d.ts +6 -0
  163. package/dist/routes/binding.js +27 -0
  164. package/dist/routes/collision.d.ts +2 -0
  165. package/dist/routes/collision.js +16 -0
  166. package/dist/routes/compiler.d.ts +8 -0
  167. package/dist/routes/compiler.js +50 -0
  168. package/dist/routes/credential.d.ts +8 -0
  169. package/dist/routes/credential.js +118 -0
  170. package/dist/routes/decode.d.ts +5 -0
  171. package/dist/routes/decode.js +147 -0
  172. package/dist/routes/encode.d.ts +4 -0
  173. package/dist/routes/encode.js +145 -0
  174. package/dist/routes/error-response.d.ts +5 -0
  175. package/dist/routes/error-response.js +31 -0
  176. package/dist/routes/error.d.ts +8 -0
  177. package/dist/routes/error.js +14 -0
  178. package/dist/routes/evidence.d.ts +5 -0
  179. package/dist/routes/evidence.js +38 -0
  180. package/dist/routes/index.d.ts +19 -0
  181. package/dist/routes/index.js +16 -0
  182. package/dist/routes/mapping.d.ts +5 -0
  183. package/dist/routes/mapping.js +126 -0
  184. package/dist/routes/match.d.ts +4 -0
  185. package/dist/routes/match.js +7 -0
  186. package/dist/routes/placement.d.ts +5 -0
  187. package/dist/routes/placement.js +18 -0
  188. package/dist/routes/plan.d.ts +24 -0
  189. package/dist/routes/plan.js +1 -0
  190. package/dist/routes/release-unavailable.d.ts +8 -0
  191. package/dist/routes/release-unavailable.js +32 -0
  192. package/dist/routes/request.d.ts +26 -0
  193. package/dist/routes/request.js +53 -0
  194. package/dist/routes/reservation.d.ts +3 -0
  195. package/dist/routes/reservation.js +37 -0
  196. package/dist/routes/routing.d.ts +22 -0
  197. package/dist/routes/routing.js +87 -0
  198. package/dist/routes/scalar.d.ts +7 -0
  199. package/dist/routes/scalar.js +61 -0
  200. package/dist/routes/select.d.ts +3 -0
  201. package/dist/routes/select.js +16 -0
  202. package/dist/routes/stream.d.ts +14 -0
  203. package/dist/routes/stream.js +50 -0
  204. package/dist/routes/table.d.ts +9 -0
  205. package/dist/routes/table.js +1 -0
  206. package/dist/routes/target.d.ts +13 -0
  207. package/dist/routes/target.js +3 -0
  208. package/dist/routes/template.d.ts +8 -0
  209. package/dist/routes/template.js +227 -0
  210. package/dist/runtime/artifact.d.ts +47 -0
  211. package/dist/runtime/artifact.js +176 -0
  212. package/dist/runtime/index.d.ts +1 -0
  213. package/dist/runtime/index.js +1 -0
  214. package/dist/schema/index.d.ts +1 -0
  215. package/dist/schema/index.js +1 -0
  216. package/dist/schema/installation/index.d.ts +1 -0
  217. package/dist/schema/installation/index.js +1 -0
  218. package/dist/schema/installation/introspection/codec.d.ts +5 -0
  219. package/dist/schema/installation/introspection/codec.js +272 -0
  220. package/dist/schema/installation/introspection/index.d.ts +2 -0
  221. package/dist/schema/installation/introspection/index.js +1 -0
  222. package/dist/schema/installation/introspection/result.d.ts +33 -0
  223. package/dist/schema/installation/introspection/result.js +1 -0
  224. package/package.json +163 -0
@@ -0,0 +1,207 @@
1
+ import { CONTENT_TYPE_JSON, CONTENT_TYPE_MSGPACK } from '../../codecs/index.js';
2
+ import { admitSupportedCodecs } from '../binding-codecs.js';
3
+ const TOKEN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/u;
4
+ const QVALUE = /^(?:0(?:\.\d{0,3})?|1(?:\.0{0,3})?)$/u;
5
+ export function codecForContentType(contentType, supported) {
6
+ const admitted = admitSupportedCodecs(supported);
7
+ if (contentType === null || contentType.trim() === '')
8
+ return undefined;
9
+ const mediaType = parseContentType(contentType);
10
+ if (mediaType === undefined)
11
+ return undefined;
12
+ const profile = mediaType === CONTENT_TYPE_JSON
13
+ ? 'json'
14
+ : mediaType === CONTENT_TYPE_MSGPACK
15
+ ? 'msgpack'
16
+ : undefined;
17
+ return admitted.find((entry) => entry.profile === profile)?.codec;
18
+ }
19
+ export function negotiateResponseCodec(accept, requestCodec, supported) {
20
+ const admitted = admitSupportedCodecs(supported);
21
+ const request = admitted.find((entry) => entry.codec === requestCodec);
22
+ if (request === undefined)
23
+ throw new TypeError('requestCodec must occur exactly once in supported.');
24
+ if (accept === null || accept.trim() === '')
25
+ return request.codec;
26
+ const ranges = parseAccept(accept);
27
+ if (ranges.length === 0)
28
+ return undefined;
29
+ const candidates = admitted.flatMap((entry) => {
30
+ const [type, subtype] = contentTypeOf(entry.profile).split('/');
31
+ const governing = ranges
32
+ .filter((range) => range.mediaParameters === 0 &&
33
+ (range.type === '*' || range.type === type) &&
34
+ (range.subtype === '*' || range.subtype === subtype))
35
+ .sort((left, right) => right.specificity - left.specificity || left.index - right.index)[0];
36
+ return governing === undefined || governing.quality === 0 ? [] : [{ ...entry, governing }];
37
+ });
38
+ if (candidates.length === 0)
39
+ return undefined;
40
+ candidates.sort((left, right) => {
41
+ const quality = right.governing.quality - left.governing.quality;
42
+ if (quality !== 0)
43
+ return quality;
44
+ if (left.codec === request.codec)
45
+ return -1;
46
+ if (right.codec === request.codec)
47
+ return 1;
48
+ const order = left.governing.index - right.governing.index;
49
+ if (order !== 0)
50
+ return order;
51
+ if (left.profile === 'json')
52
+ return -1;
53
+ if (right.profile === 'json')
54
+ return 1;
55
+ return 0;
56
+ });
57
+ return candidates[0]?.codec;
58
+ }
59
+ function contentTypeOf(profile) {
60
+ return profile === 'json' ? CONTENT_TYPE_JSON : CONTENT_TYPE_MSGPACK;
61
+ }
62
+ function parseContentType(input) {
63
+ if (splitOutsideQuotes(input, ',')?.length !== 1)
64
+ return undefined;
65
+ const parts = splitOutsideQuotes(input, ';');
66
+ if (parts === undefined)
67
+ return undefined;
68
+ const mediaType = parts.shift()?.trim().toLowerCase();
69
+ if (mediaType === undefined || parseType(mediaType, false) === undefined)
70
+ return undefined;
71
+ const names = new Set();
72
+ for (const part of parts) {
73
+ const parameter = parseParameter(part);
74
+ if (parameter === undefined || names.has(parameter.name))
75
+ return undefined;
76
+ names.add(parameter.name);
77
+ }
78
+ return mediaType;
79
+ }
80
+ function parseAccept(input) {
81
+ const members = splitOutsideQuotes(input, ',');
82
+ if (members === undefined)
83
+ return [];
84
+ const ranges = [];
85
+ for (const [index, member] of members.entries()) {
86
+ const parts = splitOutsideQuotes(member, ';');
87
+ if (parts === undefined)
88
+ continue;
89
+ const media = parseType(parts.shift()?.trim().toLowerCase() ?? '', true);
90
+ if (media === undefined)
91
+ continue;
92
+ let quality = 1;
93
+ let qualitySeen = false;
94
+ let mediaParameters = 0;
95
+ let invalid = false;
96
+ const names = new Set();
97
+ for (const part of parts) {
98
+ const parameter = parseParameter(part);
99
+ if (parameter === undefined || names.has(parameter.name)) {
100
+ invalid = true;
101
+ break;
102
+ }
103
+ names.add(parameter.name);
104
+ if (parameter.name === 'q') {
105
+ if (qualitySeen || !QVALUE.test(parameter.value)) {
106
+ invalid = true;
107
+ break;
108
+ }
109
+ qualitySeen = true;
110
+ quality = Number(parameter.value);
111
+ }
112
+ else if (!qualitySeen) {
113
+ mediaParameters += 1;
114
+ }
115
+ }
116
+ if (invalid)
117
+ continue;
118
+ ranges.push({
119
+ ...media,
120
+ quality,
121
+ specificity: media.type === '*' ? 0 : media.subtype === '*' ? 1 : 2,
122
+ index,
123
+ mediaParameters,
124
+ });
125
+ }
126
+ return ranges;
127
+ }
128
+ function parseType(input, wildcards) {
129
+ const separator = input.indexOf('/');
130
+ if (separator <= 0 || separator !== input.lastIndexOf('/'))
131
+ return undefined;
132
+ const type = input.slice(0, separator);
133
+ const subtype = input.slice(separator + 1);
134
+ if (subtype === '')
135
+ return undefined;
136
+ const typeValid = TOKEN.test(type) || (wildcards && type === '*');
137
+ const subtypeValid = TOKEN.test(subtype) || (wildcards && subtype === '*');
138
+ if (!typeValid || !subtypeValid || (type === '*' && subtype !== '*'))
139
+ return undefined;
140
+ return { type, subtype };
141
+ }
142
+ function parseParameter(input) {
143
+ const separator = input.indexOf('=');
144
+ if (separator <= 0)
145
+ return undefined;
146
+ const name = input.slice(0, separator).trim().toLowerCase();
147
+ const value = input.slice(separator + 1).trim();
148
+ if (!TOKEN.test(name) || (!TOKEN.test(value) && !quotedString(value)))
149
+ return undefined;
150
+ return { name, value: unquote(value) };
151
+ }
152
+ function quotedString(input) {
153
+ if (input.length < 2 || input[0] !== '"' || input.at(-1) !== '"')
154
+ return false;
155
+ for (let index = 1; index < input.length - 1; index += 1) {
156
+ const code = input.charCodeAt(index);
157
+ if (input[index] === '\\') {
158
+ index += 1;
159
+ if (index >= input.length - 1)
160
+ return false;
161
+ continue;
162
+ }
163
+ if (input[index] === '"' || code === 0x7f || (code < 0x20 && code !== 0x09))
164
+ return false;
165
+ }
166
+ return true;
167
+ }
168
+ function unquote(input) {
169
+ if (input[0] !== '"')
170
+ return input;
171
+ let output = '';
172
+ for (let index = 1; index < input.length - 1; index += 1) {
173
+ if (input[index] === '\\')
174
+ index += 1;
175
+ output += input[index];
176
+ }
177
+ return output;
178
+ }
179
+ function splitOutsideQuotes(input, separator) {
180
+ const parts = [];
181
+ let quoted = false;
182
+ let escaped = false;
183
+ let start = 0;
184
+ for (let index = 0; index < input.length; index += 1) {
185
+ const character = input[index];
186
+ if (escaped) {
187
+ escaped = false;
188
+ continue;
189
+ }
190
+ if (quoted && character === '\\') {
191
+ escaped = true;
192
+ continue;
193
+ }
194
+ if (character === '"') {
195
+ quoted = !quoted;
196
+ continue;
197
+ }
198
+ if (!quoted && character === separator) {
199
+ parts.push(input.slice(start, index));
200
+ start = index + 1;
201
+ }
202
+ }
203
+ if (quoted || escaped)
204
+ return undefined;
205
+ parts.push(input.slice(start));
206
+ return parts;
207
+ }
@@ -0,0 +1,5 @@
1
+ import type { Codec } from '../../codecs/index.js';
2
+ import type { StreamFrame } from '../stream.js';
3
+ export declare const STREAM_FRAMING_FIELD: 'x-astrale-stream-framing';
4
+ export declare const LENGTH_PREFIX_V1: 'length-prefix-v1';
5
+ export declare function encodeStreamFrame(codec: Codec, frame: StreamFrame): Uint8Array;
@@ -0,0 +1,15 @@
1
+ export const STREAM_FRAMING_FIELD = 'x-astrale-stream-framing';
2
+ export const LENGTH_PREFIX_V1 = 'length-prefix-v1';
3
+ const encoder = new TextEncoder();
4
+ const MAXIMUM_UINT32 = 0xffff_ffff;
5
+ export function encodeStreamFrame(codec, frame) {
6
+ const encoded = codec.encode(frame);
7
+ const payload = typeof encoded === 'string' ? encoder.encode(encoded) : encoded;
8
+ if (payload.byteLength > MAXIMUM_UINT32) {
9
+ throw new RangeError('stream frame exceeds the uint32 length-prefix-v1 payload bound.');
10
+ }
11
+ const output = new Uint8Array(4 + payload.byteLength);
12
+ new DataView(output.buffer).setUint32(0, payload.byteLength);
13
+ output.set(payload, 4);
14
+ return output;
15
+ }
@@ -0,0 +1,6 @@
1
+ import type { Trace } from '../trace.js';
2
+ export declare const TRACEPARENT_FIELD = "traceparent";
3
+ export declare const TRACESTATE_FIELD = "tracestate";
4
+ export declare const BAGGAGE_FIELD = "baggage";
5
+ export declare function decodeTraceHeaders(traceparent: string | null, tracestate: string | null): Trace | undefined;
6
+ export declare function encodeTraceHeaders(carrier: Trace | undefined): Readonly<Record<string, string>>;
@@ -0,0 +1,24 @@
1
+ import { admitTrace } from '../trace.js';
2
+ export const TRACEPARENT_FIELD = 'traceparent';
3
+ export const TRACESTATE_FIELD = 'tracestate';
4
+ export const BAGGAGE_FIELD = 'baggage';
5
+ const EMPTY_HEADERS = Object.freeze({});
6
+ export function decodeTraceHeaders(traceparent, tracestate) {
7
+ if (traceparent === null)
8
+ return undefined;
9
+ return admitTrace({
10
+ traceparent,
11
+ ...(tracestate === null ? {} : { tracestate }),
12
+ });
13
+ }
14
+ export function encodeTraceHeaders(carrier) {
15
+ if (carrier === undefined)
16
+ return EMPTY_HEADERS;
17
+ const admitted = admitTrace(carrier);
18
+ if (admitted === undefined)
19
+ return EMPTY_HEADERS;
20
+ return Object.freeze({
21
+ [TRACEPARENT_FIELD]: admitted.traceparent,
22
+ ...(admitted.tracestate === undefined ? {} : { [TRACESTATE_FIELD]: admitted.tracestate }),
23
+ });
24
+ }
@@ -0,0 +1,10 @@
1
+ declare const IDEMPOTENCY_KEY: unique symbol;
2
+ /** Caller-selected identity for one logical root invocation attempt group. */
3
+ export type IdempotencyKey = string & {
4
+ readonly [IDEMPOTENCY_KEY]: true;
5
+ };
6
+ export declare const HTTP_IDEMPOTENCY_KEY: 'x-astrale-idempotency-key';
7
+ export declare const MAXIMUM_IDEMPOTENCY_KEY_LENGTH = 128;
8
+ /** Admit an opaque URL-safe ASCII key without assigning it semantic structure. */
9
+ export declare function acceptIdempotencyKey(input: unknown, label?: string): IdempotencyKey;
10
+ export {};
@@ -0,0 +1,13 @@
1
+ import { invalid } from './admission.js';
2
+ export const HTTP_IDEMPOTENCY_KEY = 'x-astrale-idempotency-key';
3
+ export const MAXIMUM_IDEMPOTENCY_KEY_LENGTH = 128;
4
+ /** Admit an opaque URL-safe ASCII key without assigning it semantic structure. */
5
+ export function acceptIdempotencyKey(input, label = 'idempotency key') {
6
+ if (typeof input !== 'string' ||
7
+ input.length < 1 ||
8
+ input.length > MAXIMUM_IDEMPOTENCY_KEY_LENGTH ||
9
+ !/^[A-Za-z0-9._~-]+$/u.test(input)) {
10
+ invalid(`${label} must contain 1-128 URL-safe ASCII characters`);
11
+ }
12
+ return input;
13
+ }
@@ -0,0 +1,16 @@
1
+ import type { IssuerId } from '@astrale-os/kernel-core/auth';
2
+ export declare const MAXIMUM_INVOCATION_ID_LENGTH = 255;
3
+ /** Portable identity of one source-owned Invocation attempt; it grants no authority. */
4
+ export interface InvocationId {
5
+ readonly source: IssuerId;
6
+ readonly id: string;
7
+ }
8
+ export declare class InvocationError extends TypeError {
9
+ readonly input: unknown;
10
+ readonly code: 'INVOCATION_INVALID';
11
+ constructor(input: unknown, message?: string, options?: ErrorOptions);
12
+ }
13
+ /** Admit, canonicalize, detach, and freeze one exact source-qualified Invocation identity. */
14
+ export declare function acceptInvocationId(input: unknown): InvocationId;
15
+ /** Compare both canonical coordinate fields exactly. */
16
+ export declare function sameInvocationId(left: InvocationId, right: InvocationId): boolean;
@@ -0,0 +1,55 @@
1
+ import { issuer } from '@astrale-os/kernel-core/auth';
2
+ export const MAXIMUM_INVOCATION_ID_LENGTH = 255;
3
+ const INVALID_ID_CHARACTER = /[^A-Za-z0-9._-]/u;
4
+ const ID_ERROR_MESSAGE = 'InvocationId must contain 1-255 ASCII characters drawn from [A-Za-z0-9._-].';
5
+ export class InvocationError extends TypeError {
6
+ input;
7
+ code = 'INVOCATION_INVALID';
8
+ constructor(input, message = 'Invocation is invalid.', options) {
9
+ super(message, options);
10
+ this.input = input;
11
+ this.name = 'InvocationError';
12
+ }
13
+ }
14
+ /** Admit, canonicalize, detach, and freeze one exact source-qualified Invocation identity. */
15
+ export function acceptInvocationId(input) {
16
+ if (input === null || typeof input !== 'object' || Array.isArray(input))
17
+ invalid(input);
18
+ const candidate = input;
19
+ const source = Object.getOwnPropertyDescriptor(candidate, 'source');
20
+ const id = Object.getOwnPropertyDescriptor(candidate, 'id');
21
+ if (Reflect.ownKeys(candidate).some((key) => key !== 'source' && key !== 'id') ||
22
+ source === undefined ||
23
+ id === undefined ||
24
+ !source.enumerable ||
25
+ !id.enumerable ||
26
+ !('value' in source) ||
27
+ !('value' in id) ||
28
+ typeof source.value !== 'string' ||
29
+ typeof id.value !== 'string') {
30
+ invalid(input);
31
+ }
32
+ let admittedSource;
33
+ try {
34
+ admittedSource = issuer.accept(source.value);
35
+ }
36
+ catch (cause) {
37
+ throw new InvocationError(input, 'Invocation source is invalid.', { cause });
38
+ }
39
+ if (!isLocalInvocationId(id.value))
40
+ throw new InvocationError(input, ID_ERROR_MESSAGE);
41
+ return Object.freeze({ source: admittedSource, id: id.value });
42
+ }
43
+ /** Compare both canonical coordinate fields exactly. */
44
+ export function sameInvocationId(left, right) {
45
+ return left.source === right.source && left.id === right.id;
46
+ }
47
+ function isLocalInvocationId(input) {
48
+ return (typeof input === 'string' &&
49
+ input.length > 0 &&
50
+ input.length <= MAXIMUM_INVOCATION_ID_LENGTH &&
51
+ !INVALID_ID_CHARACTER.test(input));
52
+ }
53
+ function invalid(input) {
54
+ throw new InvocationError(input);
55
+ }
@@ -0,0 +1,20 @@
1
+ export { decodeBinaryResponse, type BinaryResponse } from './binary.js';
2
+ export { decodeCancelRequest, type CancelRequest } from './cancellation.js';
3
+ export { type RequestId } from './correlation.js';
4
+ export { acceptIdempotencyKey, HTTP_IDEMPOTENCY_KEY, MAXIMUM_IDEMPOTENCY_KEY_LENGTH, type IdempotencyKey, } from './idempotency.js';
5
+ export { acceptInvocationId, InvocationError, MAXIMUM_INVOCATION_ID_LENGTH, sameInvocationId, type InvocationId, } from './identity.js';
6
+ export * as http from './http/index.js';
7
+ export { acceptDelegate, type Delegate } from './delegate.js';
8
+ export { decodeMiss, miss, type Miss } from './miss.js';
9
+ export { acceptRoute, acceptRedirection, decodeRedirectResponse, remoteRoute, type RemoteBindingInput, type Redirection, type RedirectResponse, type Route, } from './redirect.js';
10
+ export { decodeRequest, type Request } from './request.js';
11
+ export { admitTrace, MAXIMUM_TRACEPARENT_BYTES, MAXIMUM_TRACESTATE_BYTES, MAXIMUM_TRACESTATE_MEMBERS, type Trace, } from './trace.js';
12
+ export { acceptRouting, type Refresh, type Routing, type Via } from './routing.js';
13
+ export { acceptSchemaTarget, type SchemaTarget } from './schema.js';
14
+ export { decodeResponse, type ErrorResponse, type Response, type ResponseContext, type SuccessResponse, } from './response.js';
15
+ export { SCHEMA_UPGRADE_REQUIRED, SCHEMA_REVISION_MISMATCH, SERVICE_CANDIDATE_INVALID, SERVICE_TRUST_REQUIRED, SERVICE_UNAVAILABLE, serviceErrorOf, type SchemaUpgradeRequiredDetails, type SchemaUpgradeRequiredReason, type SchemaRevisionMismatchDetails, type SchemaRevisionMismatchReason, type ServiceCandidateInvalidDetails, type ServiceCandidateInvalidReason, type ServiceErrorPayload, type ServiceReason, type ServiceTrustRequiredDetails, type ServiceTrustRequiredReason, type ServiceUnavailableDetails, type ServiceUnavailableReason, } from './service-reason.js';
16
+ export { decodeStale, stale, type Stale } from './stale-route.js';
17
+ export { decodeStreamFrame, type StreamEndFrame, type StreamErrorFrame, type StreamFrame, type StreamItemFrame, type StreamStartFrame, } from './stream.js';
18
+ export { acceptCall, type Call } from './target.js';
19
+ export { VERSION, type Version } from './version.js';
20
+ export * as websocket from './websocket/index.js';
@@ -0,0 +1,20 @@
1
+ export { decodeBinaryResponse } from './binary.js';
2
+ export { decodeCancelRequest } from './cancellation.js';
3
+ export {} from './correlation.js';
4
+ export { acceptIdempotencyKey, HTTP_IDEMPOTENCY_KEY, MAXIMUM_IDEMPOTENCY_KEY_LENGTH, } from './idempotency.js';
5
+ export { acceptInvocationId, InvocationError, MAXIMUM_INVOCATION_ID_LENGTH, sameInvocationId, } from './identity.js';
6
+ export * as http from './http/index.js';
7
+ export { acceptDelegate } from './delegate.js';
8
+ export { decodeMiss, miss } from './miss.js';
9
+ export { acceptRoute, acceptRedirection, decodeRedirectResponse, remoteRoute, } from './redirect.js';
10
+ export { decodeRequest } from './request.js';
11
+ export { admitTrace, MAXIMUM_TRACEPARENT_BYTES, MAXIMUM_TRACESTATE_BYTES, MAXIMUM_TRACESTATE_MEMBERS, } from './trace.js';
12
+ export { acceptRouting } from './routing.js';
13
+ export { acceptSchemaTarget } from './schema.js';
14
+ export { decodeResponse, } from './response.js';
15
+ export { SCHEMA_UPGRADE_REQUIRED, SCHEMA_REVISION_MISMATCH, SERVICE_CANDIDATE_INVALID, SERVICE_TRUST_REQUIRED, SERVICE_UNAVAILABLE, serviceErrorOf, } from './service-reason.js';
16
+ export { decodeStale, stale } from './stale-route.js';
17
+ export { decodeStreamFrame, } from './stream.js';
18
+ export { acceptCall } from './target.js';
19
+ export { VERSION } from './version.js';
20
+ export * as websocket from './websocket/index.js';
@@ -0,0 +1,9 @@
1
+ import type { RequestId } from './correlation.js';
2
+ import type { InvocationId } from './identity.js';
3
+ export interface Miss {
4
+ readonly kind: 'miss';
5
+ readonly requestId: RequestId;
6
+ readonly invocation: InvocationId;
7
+ }
8
+ export declare function decodeMiss(input: unknown): Miss;
9
+ export declare function miss(requestId: RequestId, assigned: InvocationId): Miss;
@@ -0,0 +1,17 @@
1
+ import { exactFields, invalid, invocation, portableObject, requestId, required, } from './admission.js';
2
+ const FIELDS = new Set(['kind', 'requestId', 'invocation']);
3
+ export function decodeMiss(input) {
4
+ const object = portableObject(input, 'miss control');
5
+ exactFields(object, FIELDS, 'miss control');
6
+ required(object, ['kind', 'requestId', 'invocation'], 'miss control');
7
+ if (object.kind !== 'miss')
8
+ invalid('miss control.kind must be "miss"');
9
+ return Object.freeze({
10
+ kind: 'miss',
11
+ requestId: requestId(object.requestId, 'miss control.requestId'),
12
+ invocation: invocation(object.invocation, 'miss control.invocation'),
13
+ });
14
+ }
15
+ export function miss(requestId, assigned) {
16
+ return decodeMiss({ kind: 'miss', requestId, invocation: assigned });
17
+ }
@@ -0,0 +1,40 @@
1
+ import type { IssuerId } from '@astrale-os/kernel-core/auth/issuer';
2
+ import type { Key } from '@astrale-os/kernel-dsl/v1';
3
+ import type { InvocationEndpoints } from '../publication/bindings/invocation.js';
4
+ import type { Etag } from '../publication/etag.js';
5
+ import type { PublicationRef } from '../publication/reference.js';
6
+ import type { RequestId } from './correlation.js';
7
+ import type { InvocationId } from './identity.js';
8
+ import type { Trace } from './trace.js';
9
+ export interface Route {
10
+ readonly endpoint: InvocationEndpoints;
11
+ readonly via: {
12
+ readonly kind: 'via';
13
+ readonly publication: PublicationRef;
14
+ readonly issuer: IssuerId;
15
+ };
16
+ }
17
+ export interface Redirection {
18
+ readonly route: Route;
19
+ readonly credential?: string;
20
+ /** Ephemeral one-hop correlation hint; never cached or treated as authority. */
21
+ readonly trace?: Trace;
22
+ }
23
+ export interface RedirectResponse {
24
+ readonly kind: 'redirect';
25
+ readonly requestId: RequestId;
26
+ readonly invocation: InvocationId;
27
+ readonly redirect: Redirection;
28
+ }
29
+ export interface RemoteBindingInput {
30
+ readonly endpoint: InvocationEndpoints;
31
+ readonly issuer: IssuerId;
32
+ readonly subject: string;
33
+ readonly revision: PublicationRef['revision'];
34
+ readonly etag: Etag;
35
+ }
36
+ export declare function acceptRoute(input: unknown): Route;
37
+ /** Project one semantic remote binding into its admitted protocol route representation. */
38
+ export declare function remoteRoute(origin: Key.Origin, binding: RemoteBindingInput, issuer: IssuerId): Route;
39
+ export declare function acceptRedirection(input: unknown): Redirection;
40
+ export declare function decodeRedirectResponse(input: unknown): RedirectResponse;
@@ -0,0 +1,81 @@
1
+ import { acceptInvocationEndpoints } from '../publication/bindings/invocation.js';
2
+ import { PublicationError } from '../publication/error.js';
3
+ import { acceptReference } from '../publication/reference.js';
4
+ import { exactFields, invalid, issuerId, invocation, portableObject, requestId, required, string, } from './admission.js';
5
+ import { admitTrace } from './trace.js';
6
+ const ROUTE_FIELDS = new Set(['endpoint', 'via']);
7
+ const VIA_FIELDS = new Set(['kind', 'publication', 'issuer']);
8
+ const REDIRECTION_FIELDS = new Set(['route', 'credential', 'trace']);
9
+ const REDIRECT_RESPONSE_FIELDS = new Set(['kind', 'requestId', 'invocation', 'redirect']);
10
+ export function acceptRoute(input) {
11
+ const object = portableObject(input, 'route');
12
+ exactFields(object, ROUTE_FIELDS, 'route');
13
+ required(object, ['endpoint', 'via'], 'route');
14
+ try {
15
+ const via = portableObject(object.via, 'route.via');
16
+ exactFields(via, VIA_FIELDS, 'route.via');
17
+ required(via, ['kind', 'publication', 'issuer'], 'route.via');
18
+ if (via.kind !== 'via')
19
+ invalid('route.via.kind must be "via"');
20
+ return Object.freeze({
21
+ endpoint: acceptInvocationEndpoints(object.endpoint),
22
+ via: Object.freeze({
23
+ kind: 'via',
24
+ publication: acceptReference(via.publication),
25
+ issuer: issuerId(via.issuer, 'route.via.issuer'),
26
+ }),
27
+ });
28
+ }
29
+ catch (cause) {
30
+ if (cause instanceof PublicationError) {
31
+ return invalid(`route is invalid: ${cause.message}`);
32
+ }
33
+ throw cause;
34
+ }
35
+ }
36
+ /** Project one semantic remote binding into its admitted protocol route representation. */
37
+ export function remoteRoute(origin, binding, issuer) {
38
+ return acceptRoute({
39
+ endpoint: binding.endpoint,
40
+ via: {
41
+ kind: 'via',
42
+ publication: {
43
+ origin,
44
+ identity: { issuer: binding.issuer, subject: binding.subject },
45
+ revision: binding.revision,
46
+ etag: binding.etag,
47
+ },
48
+ issuer,
49
+ },
50
+ });
51
+ }
52
+ export function acceptRedirection(input) {
53
+ const object = portableObject(input, 'redirection');
54
+ exactFields(object, REDIRECTION_FIELDS, 'redirection');
55
+ required(object, ['route'], 'redirection');
56
+ const route = acceptRoute(object.route);
57
+ const credential = object.credential === undefined
58
+ ? undefined
59
+ : string(object.credential, 'redirection.credential');
60
+ const trace = object.trace === undefined ? undefined : admitTrace(object.trace);
61
+ if (credential !== undefined && credential.length === 0)
62
+ invalid('redirection.credential must be non-empty');
63
+ return Object.freeze({
64
+ route,
65
+ ...(credential === undefined ? {} : { credential }),
66
+ ...(trace === undefined ? {} : { trace }),
67
+ });
68
+ }
69
+ export function decodeRedirectResponse(input) {
70
+ const object = portableObject(input, 'redirect response');
71
+ exactFields(object, REDIRECT_RESPONSE_FIELDS, 'redirect response');
72
+ required(object, ['kind', 'requestId', 'invocation', 'redirect'], 'redirect response');
73
+ if (object.kind !== 'redirect')
74
+ invalid('redirect response.kind must be "redirect"');
75
+ return Object.freeze({
76
+ kind: 'redirect',
77
+ requestId: requestId(object.requestId, 'redirect response.requestId'),
78
+ invocation: invocation(object.invocation, 'redirect response.invocation'),
79
+ redirect: acceptRedirection(object.redirect),
80
+ });
81
+ }
@@ -0,0 +1,21 @@
1
+ import type { RequestId } from './correlation.js';
2
+ import type { Delegate } from './delegate.js';
3
+ import type { IdempotencyKey } from './idempotency.js';
4
+ import type { Routing } from './routing.js';
5
+ import type { SchemaTarget } from './schema.js';
6
+ import type { Call } from './target.js';
7
+ import type { Trace } from './trace.js';
8
+ import type { Version } from './version.js';
9
+ export interface Request {
10
+ readonly version: Version;
11
+ readonly requestId: RequestId;
12
+ readonly call: Call;
13
+ readonly credential?: string;
14
+ readonly delegate?: Delegate;
15
+ readonly routing?: Routing;
16
+ /** Source-Kernel precondition; forbidden on an already-routed destination request. */
17
+ readonly schema?: SchemaTarget;
18
+ readonly idempotencyKey?: IdempotencyKey;
19
+ readonly trace?: Trace;
20
+ }
21
+ export declare function decodeRequest(input: unknown): Request;
@@ -0,0 +1,54 @@
1
+ import { exactFields, invalid, portableObject, requestId, required, string } from './admission.js';
2
+ import { acceptDelegate } from './delegate.js';
3
+ import { acceptIdempotencyKey } from './idempotency.js';
4
+ import { acceptRouting } from './routing.js';
5
+ import { acceptSchemaTarget } from './schema.js';
6
+ import { acceptCall } from './target.js';
7
+ import { admitTrace } from './trace.js';
8
+ const REQUEST_FIELDS = new Set([
9
+ 'version',
10
+ 'requestId',
11
+ 'call',
12
+ 'credential',
13
+ 'delegate',
14
+ 'routing',
15
+ 'schema',
16
+ 'idempotencyKey',
17
+ 'trace',
18
+ ]);
19
+ export function decodeRequest(input) {
20
+ const object = portableObject(input, 'request');
21
+ exactFields(object, REQUEST_FIELDS, 'request');
22
+ required(object, ['version', 'requestId', 'call'], 'request');
23
+ if (object.version !== 2)
24
+ invalid('request.version must be 2');
25
+ const credential = object.credential === undefined ? undefined : string(object.credential, 'request.credential');
26
+ const delegate = object.delegate === undefined ? undefined : acceptDelegate(object.delegate);
27
+ const routing = object.routing === undefined ? undefined : acceptRouting(object.routing);
28
+ const schema = object.schema === undefined ? undefined : acceptSchemaTarget(object.schema);
29
+ const trace = object.trace === undefined ? undefined : admitTrace(object.trace);
30
+ if (routing?.kind === 'via') {
31
+ if (delegate !== undefined)
32
+ invalid('destination requests with via routing forbid delegate');
33
+ if (schema !== undefined)
34
+ invalid('destination requests with via routing forbid schema target');
35
+ }
36
+ else if ((credential === undefined) !== (delegate === undefined)) {
37
+ invalid('source requests require credential and delegate together');
38
+ }
39
+ return Object.freeze({
40
+ version: 2,
41
+ requestId: requestId(object.requestId, 'request.requestId'),
42
+ call: acceptCall(object.call),
43
+ ...(credential === undefined ? {} : { credential }),
44
+ ...(delegate === undefined ? {} : { delegate }),
45
+ ...(routing === undefined ? {} : { routing }),
46
+ ...(schema === undefined ? {} : { schema }),
47
+ ...(object.idempotencyKey === undefined
48
+ ? {}
49
+ : {
50
+ idempotencyKey: acceptIdempotencyKey(object.idempotencyKey, 'request.idempotencyKey'),
51
+ }),
52
+ ...(trace === undefined ? {} : { trace }),
53
+ });
54
+ }
@@ -0,0 +1,19 @@
1
+ import type { Value } from '@astrale-os/kernel-dsl/value';
2
+ import type { ErrorPayload } from '../errors/index.js';
3
+ import type { RequestId } from './correlation.js';
4
+ import type { InvocationId } from './identity.js';
5
+ import type { Miss } from './miss.js';
6
+ import type { RedirectResponse } from './redirect.js';
7
+ import type { Stale } from './stale-route.js';
8
+ export interface ResponseContext {
9
+ readonly requestId: RequestId;
10
+ readonly invocation: InvocationId;
11
+ }
12
+ export interface SuccessResponse<Result extends Value = Value> extends ResponseContext {
13
+ readonly result: Result;
14
+ }
15
+ export interface ErrorResponse extends ResponseContext {
16
+ readonly error: ErrorPayload;
17
+ }
18
+ export type Response<Result extends Value = Value> = SuccessResponse<Result> | ErrorResponse | RedirectResponse | Stale | Miss;
19
+ export declare function decodeResponse(input: unknown): Response;