@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,9 @@
1
+ import * as bundle from '@astrale-os/kernel-dsl/v1/bundle/transport';
2
+ import type { BundleDescriptor } from './bundle-descriptor.js';
3
+ import type { Publication } from './publication.js';
4
+ import { verifyBundleBytes } from './bundle-evidence.js';
5
+ export declare function describeBundle(input: bundle.Bundle, href: string): BundleDescriptor;
6
+ export declare function acceptBundleValue(input: unknown): bundle.Bundle;
7
+ export declare function decodeBundleValue(publication: Publication, bytes: Uint8Array): bundle.Bundle;
8
+ export { verifyBundleBytes };
9
+ export { admitBundleDescriptor, BUNDLE_MEDIA_TYPE, type BundleDescriptor, } from './bundle-descriptor.js';
@@ -0,0 +1,44 @@
1
+ import * as bundle from '@astrale-os/kernel-dsl/v1/bundle/transport';
2
+ import * as artifact from '../artifact/index.js';
3
+ import { BUNDLE_MEDIA_TYPE } from './bundle-descriptor.js';
4
+ import { verifyBundleBytes } from './bundle-evidence.js';
5
+ import { absoluteHttpUrl } from './content.js';
6
+ import { fail } from './error.js';
7
+ export function describeBundle(input, href) {
8
+ const bytes = bundle.encode(input);
9
+ return Object.freeze({
10
+ href: absoluteHttpUrl(href, true, 'PUBLICATION_INVALID'),
11
+ ref: Object.freeze({
12
+ ...artifact.identify(bytes, BUNDLE_MEDIA_TYPE),
13
+ mediaType: BUNDLE_MEDIA_TYPE,
14
+ }),
15
+ });
16
+ }
17
+ export function acceptBundleValue(input) {
18
+ try {
19
+ return bundle.accept(input);
20
+ }
21
+ catch (cause) {
22
+ if (cause instanceof bundle.Error) {
23
+ return fail('PUBLICATION_INVALID', 'Publication bundle is invalid.', cause);
24
+ }
25
+ throw cause;
26
+ }
27
+ }
28
+ export function decodeBundleValue(publication, bytes) {
29
+ if (!(bytes instanceof Uint8Array)) {
30
+ fail('PUBLICATION_INVALID', 'Bundle artifact bytes are invalid.');
31
+ }
32
+ verifyBundleBytes(publication, bytes);
33
+ try {
34
+ return bundle.decode(bytes);
35
+ }
36
+ catch (cause) {
37
+ if (cause instanceof bundle.Error) {
38
+ return fail('PUBLICATION_INVALID', 'Bundle artifact cannot be decoded.', cause);
39
+ }
40
+ throw cause;
41
+ }
42
+ }
43
+ export { verifyBundleBytes };
44
+ export { admitBundleDescriptor, BUNDLE_MEDIA_TYPE, } from './bundle-descriptor.js';
@@ -0,0 +1,10 @@
1
+ import type { PublicationErrorCode } from './error.js';
2
+ import type { Publication } from './publication.js';
3
+ export type Content = Omit<Publication, 'etag'>;
4
+ export declare function record(input: unknown, code: PublicationErrorCode, message: string): Record<string, unknown>;
5
+ export declare function exact(value: Record<string, unknown>, allowed: readonly string[], code: PublicationErrorCode): void;
6
+ export declare function array(input: unknown, code: PublicationErrorCode): readonly unknown[];
7
+ export declare function unique(values: readonly string[], code: PublicationErrorCode, label: string): void;
8
+ export declare function deepFreeze<T>(value: T): T;
9
+ export declare function absoluteHttpUrl(input: unknown, allowSearch: boolean, code: PublicationErrorCode, allowTemplate?: boolean): string;
10
+ export declare function absoluteUrl(input: unknown, protocols: readonly string[], allowSearch: boolean, code: PublicationErrorCode, allowTemplate?: boolean): string;
@@ -0,0 +1,55 @@
1
+ import { fail } from './error.js';
2
+ export function record(input, code, message) {
3
+ if (input === null || typeof input !== 'object' || Array.isArray(input))
4
+ fail(code, message);
5
+ return input;
6
+ }
7
+ export function exact(value, allowed, code) {
8
+ const admitted = new Set(allowed);
9
+ if (Object.keys(value).some((key) => !admitted.has(key))) {
10
+ fail(code, 'Object contains unknown fields.');
11
+ }
12
+ }
13
+ export function array(input, code) {
14
+ if (!Array.isArray(input))
15
+ fail(code, 'Expected an array.');
16
+ return input;
17
+ }
18
+ export function unique(values, code, label) {
19
+ if (new Set(values).size !== values.length)
20
+ fail(code, `Duplicate ${label}.`);
21
+ }
22
+ export function deepFreeze(value) {
23
+ if (value === null || typeof value !== 'object' || Object.isFrozen(value))
24
+ return value;
25
+ for (const nested of Object.values(value))
26
+ deepFreeze(nested);
27
+ return Object.freeze(value);
28
+ }
29
+ export function absoluteHttpUrl(input, allowSearch, code, allowTemplate = false) {
30
+ return absoluteUrl(input, ['http:', 'https:'], allowSearch, code, allowTemplate);
31
+ }
32
+ export function absoluteUrl(input, protocols, allowSearch, code, allowTemplate = false) {
33
+ if (typeof input !== 'string')
34
+ return fail(code, 'Expected an absolute URL.');
35
+ if (!allowTemplate && (input.includes('{') || input.includes('}'))) {
36
+ return fail(code, 'Only native route URLs may contain placeholders.');
37
+ }
38
+ let url;
39
+ try {
40
+ url = new URL(allowTemplate ? input.replaceAll(/\{[A-Za-z][A-Za-z0-9_]*\+?\}/gu, 'placeholder') : input);
41
+ }
42
+ catch (cause) {
43
+ if (cause instanceof TypeError)
44
+ return fail(code, 'Expected an absolute URL.', cause);
45
+ throw cause;
46
+ }
47
+ if (!protocols.includes(url.protocol) ||
48
+ url.username !== '' ||
49
+ url.password !== '' ||
50
+ url.hash !== '' ||
51
+ (!allowSearch && url.search !== '')) {
52
+ fail(code, 'URL has a forbidden protocol, credentials, query, or fragment.');
53
+ }
54
+ return input;
55
+ }
@@ -0,0 +1,11 @@
1
+ import type { Authentication as DeliveryAuthentication } from './delivery-endpoint.js';
2
+ import type { HttpRouteDeclaration } from './route.js';
3
+ export interface DeliveryDeclaration {
4
+ readonly path: string;
5
+ readonly authentication: DeliveryAuthentication;
6
+ }
7
+ /** Provider-neutral deployment input selected independently from Domain and Adapter. */
8
+ export interface Declaration {
9
+ readonly routes: readonly HttpRouteDeclaration[];
10
+ readonly delivery?: DeliveryDeclaration;
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ declare const ATTESTATION: unique symbol;
2
+ export type Attestation = string & {
3
+ readonly [ATTESTATION]: true;
4
+ };
5
+ export declare function acceptAttestation(input: unknown): Attestation;
6
+ export {};
@@ -0,0 +1,10 @@
1
+ import { fail } from './error.js';
2
+ import { ATTESTATION_MAX_BYTES } from './limits.js';
3
+ export function acceptAttestation(input) {
4
+ if (typeof input !== 'string' ||
5
+ input.length === 0 ||
6
+ new TextEncoder().encode(input).byteLength > ATTESTATION_MAX_BYTES) {
7
+ fail('DELIVERY_INVALID', 'Delivery attestation is invalid.');
8
+ }
9
+ return input;
10
+ }
@@ -0,0 +1,16 @@
1
+ import type { Subject } from '@astrale-os/kernel-core/auth/identity';
2
+ import type { Revision } from '@astrale-os/kernel-dsl/v1/addressing';
3
+ import { type IssuerId } from '@astrale-os/kernel-core/auth/issuer';
4
+ import type { Etag } from '../etag.js';
5
+ import { PURPOSE } from './limits.js';
6
+ export interface Claims {
7
+ readonly purpose: typeof PURPOSE;
8
+ readonly iss: IssuerId;
9
+ readonly sub: Subject;
10
+ readonly aud: IssuerId;
11
+ readonly nonce: string;
12
+ readonly etag: Etag;
13
+ readonly schemaRevision: Revision;
14
+ readonly exp: number;
15
+ }
16
+ export declare function acceptClaims(input: unknown): Claims;
@@ -0,0 +1,61 @@
1
+ import { AuthValueError } from '@astrale-os/kernel-core/auth/error';
2
+ import { accept as acceptIssuerId } from '@astrale-os/kernel-core/auth/issuer';
3
+ import { patterns } from '@astrale-os/kernel-dsl/v1/addressing';
4
+ import { fail } from './error.js';
5
+ import { NONCE_MAX_LENGTH, NONCE_MIN_LENGTH, PURPOSE } from './limits.js';
6
+ export function acceptClaims(input) {
7
+ if (input === null || typeof input !== 'object' || Array.isArray(input)) {
8
+ fail('DELIVERY_CLAIMS_INVALID', 'Expected delivery claims.');
9
+ }
10
+ const value = input;
11
+ const expected = ['purpose', 'iss', 'sub', 'aud', 'nonce', 'etag', 'schemaRevision', 'exp'];
12
+ if (Object.keys(value).some((field) => !expected.includes(field))) {
13
+ fail('DELIVERY_CLAIMS_INVALID', 'Delivery claims contain unknown fields.');
14
+ }
15
+ if (value.purpose !== PURPOSE ||
16
+ typeof value.sub !== 'string' ||
17
+ value.sub.length === 0 ||
18
+ typeof value.nonce !== 'string' ||
19
+ value.nonce.length < NONCE_MIN_LENGTH ||
20
+ value.nonce.length > NONCE_MAX_LENGTH ||
21
+ typeof value.exp !== 'number' ||
22
+ !Number.isSafeInteger(value.exp)) {
23
+ fail('DELIVERY_CLAIMS_INVALID', 'Delivery claims are invalid.');
24
+ }
25
+ const iss = acceptIssuer(value.iss);
26
+ const aud = acceptIssuer(value.aud);
27
+ if (typeof value.etag !== 'string' || !/^sha256:[0-9a-f]{64}$/u.test(value.etag)) {
28
+ fail('DELIVERY_CLAIMS_INVALID', 'Delivery claims ETag is invalid.');
29
+ }
30
+ if (typeof value.schemaRevision !== 'string' || !patterns.revision.test(value.schemaRevision)) {
31
+ fail('DELIVERY_CLAIMS_INVALID', 'Schema revision is invalid.');
32
+ }
33
+ return deepFreeze({
34
+ purpose: PURPOSE,
35
+ iss,
36
+ sub: value.sub,
37
+ aud,
38
+ nonce: value.nonce,
39
+ etag: value.etag,
40
+ schemaRevision: value.schemaRevision,
41
+ exp: value.exp,
42
+ });
43
+ }
44
+ function acceptIssuer(input) {
45
+ try {
46
+ return acceptIssuerId(String(input));
47
+ }
48
+ catch (cause) {
49
+ if (cause instanceof AuthValueError) {
50
+ return fail('DELIVERY_CLAIMS_INVALID', 'Delivery claims issuer is invalid.', cause);
51
+ }
52
+ throw cause;
53
+ }
54
+ }
55
+ function deepFreeze(value) {
56
+ if (value === null || typeof value !== 'object' || Object.isFrozen(value))
57
+ return value;
58
+ for (const nested of Object.values(value))
59
+ deepFreeze(nested);
60
+ return Object.freeze(value);
61
+ }
@@ -0,0 +1,9 @@
1
+ import type { Publication } from '../publication.js';
2
+ import type { Attestation } from './attestation.js';
3
+ export interface Delivery {
4
+ readonly format: 'astrale.domain.delivery';
5
+ readonly version: 1;
6
+ readonly publication: Publication;
7
+ readonly attestation: Attestation;
8
+ }
9
+ export declare function accept(input: unknown): Delivery;
@@ -0,0 +1,29 @@
1
+ import { accept as acceptPublication } from '../publication.js';
2
+ import { acceptAttestation } from './attestation.js';
3
+ import { fail } from './error.js';
4
+ export function accept(input) {
5
+ if (input === null || typeof input !== 'object' || Array.isArray(input)) {
6
+ fail('DELIVERY_INVALID', 'Expected a Delivery object.');
7
+ }
8
+ const value = input;
9
+ const expected = new Set(['format', 'version', 'publication', 'attestation']);
10
+ if (Object.keys(value).some((field) => !expected.has(field))) {
11
+ fail('DELIVERY_INVALID', 'Delivery contains unknown fields.');
12
+ }
13
+ if (value.format !== 'astrale.domain.delivery' || value.version !== 1) {
14
+ fail('DELIVERY_INVALID', 'Unsupported Delivery format or version.');
15
+ }
16
+ return deepFreeze({
17
+ format: 'astrale.domain.delivery',
18
+ version: 1,
19
+ publication: acceptPublication(value.publication),
20
+ attestation: acceptAttestation(value.attestation),
21
+ });
22
+ }
23
+ function deepFreeze(value) {
24
+ if (value === null || typeof value !== 'object' || Object.isFrozen(value))
25
+ return value;
26
+ for (const nested of Object.values(value))
27
+ deepFreeze(nested);
28
+ return Object.freeze(value);
29
+ }
@@ -0,0 +1,7 @@
1
+ export type DeliveryErrorCode = 'DELIVERY_INVALID' | 'DELIVERY_REQUEST_INVALID' | 'DELIVERY_CLAIMS_INVALID';
2
+ export declare class DeliveryError extends Error {
3
+ readonly code: DeliveryErrorCode;
4
+ readonly name = "DeliveryError";
5
+ constructor(code: DeliveryErrorCode, message: string, options?: ErrorOptions);
6
+ }
7
+ export declare function fail(code: DeliveryErrorCode, message: string, cause?: unknown): never;
@@ -0,0 +1,11 @@
1
+ export class DeliveryError extends Error {
2
+ code;
3
+ name = 'DeliveryError';
4
+ constructor(code, message, options) {
5
+ super(message, options);
6
+ this.code = code;
7
+ }
8
+ }
9
+ export function fail(code, message, cause) {
10
+ throw new DeliveryError(code, message, cause === undefined ? undefined : { cause });
11
+ }
@@ -0,0 +1,6 @@
1
+ export { type Attestation } from './attestation.js';
2
+ export { acceptClaims, type Claims } from './claims.js';
3
+ export { DeliveryError as Error, type DeliveryErrorCode as ErrorCode } from './error.js';
4
+ export { accept, type Delivery } from './delivery.js';
5
+ export { ATTESTATION_MAX_BYTES, NONCE_MAX_LENGTH, NONCE_MIN_LENGTH, PURPOSE } from './limits.js';
6
+ export { acceptRequest, type Token, type Request } from './request.js';
@@ -0,0 +1,6 @@
1
+ export {} from './attestation.js';
2
+ export { acceptClaims } from './claims.js';
3
+ export { DeliveryError as Error } from './error.js';
4
+ export { accept } from './delivery.js';
5
+ export { ATTESTATION_MAX_BYTES, NONCE_MAX_LENGTH, NONCE_MIN_LENGTH, PURPOSE } from './limits.js';
6
+ export { acceptRequest } from './request.js';
@@ -0,0 +1,4 @@
1
+ export declare const PURPOSE: 'astrale.domain.delivery.v1';
2
+ export declare const NONCE_MIN_LENGTH = 16;
3
+ export declare const NONCE_MAX_LENGTH = 256;
4
+ export declare const ATTESTATION_MAX_BYTES = 16384;
@@ -0,0 +1,4 @@
1
+ export const PURPOSE = 'astrale.domain.delivery.v1';
2
+ export const NONCE_MIN_LENGTH = 16;
3
+ export const NONCE_MAX_LENGTH = 256;
4
+ export const ATTESTATION_MAX_BYTES = 16_384;
@@ -0,0 +1,15 @@
1
+ import { type IssuerId } from '@astrale-os/kernel-core/auth/issuer';
2
+ import type { Etag } from '../etag.js';
3
+ export interface Request {
4
+ readonly version: 1;
5
+ readonly kernel: IssuerId;
6
+ readonly nonce: string;
7
+ readonly etag: Etag;
8
+ }
9
+ /** Exact bearer credential admitted by a Delivery transport boundary. */
10
+ export interface Token {
11
+ readonly kind: 'bearer';
12
+ readonly token: string;
13
+ }
14
+ /** Admit the exact request representation accepted by a Delivery transport boundary. */
15
+ export declare function acceptRequest(input: unknown): Request;
@@ -0,0 +1,52 @@
1
+ import { AuthValueError } from '@astrale-os/kernel-core/auth/error';
2
+ import { accept as acceptIssuer } from '@astrale-os/kernel-core/auth/issuer';
3
+ import { fail } from './error.js';
4
+ import { NONCE_MAX_LENGTH, NONCE_MIN_LENGTH } from './limits.js';
5
+ /** Admit the exact request representation accepted by a Delivery transport boundary. */
6
+ export function acceptRequest(input) {
7
+ if (input === null || typeof input !== 'object' || Array.isArray(input)) {
8
+ fail('DELIVERY_REQUEST_INVALID', 'Expected a Delivery request.');
9
+ }
10
+ const expected = ['version', 'kernel', 'nonce', 'etag'];
11
+ const value = {};
12
+ const fields = Reflect.ownKeys(input);
13
+ if (fields.length !== expected.length) {
14
+ fail('DELIVERY_REQUEST_INVALID', 'Delivery request is invalid.');
15
+ }
16
+ for (const field of fields) {
17
+ if (typeof field !== 'string' || !expected.includes(field)) {
18
+ fail('DELIVERY_REQUEST_INVALID', 'Delivery request is invalid.');
19
+ }
20
+ const descriptor = Object.getOwnPropertyDescriptor(input, field);
21
+ if (descriptor === undefined || !descriptor.enumerable || !('value' in descriptor)) {
22
+ fail('DELIVERY_REQUEST_INVALID', 'Delivery request is invalid.');
23
+ }
24
+ value[field] = descriptor.value;
25
+ }
26
+ if (expected.some((field) => !Object.hasOwn(value, field)) ||
27
+ value.version !== 1 ||
28
+ typeof value.kernel !== 'string' ||
29
+ typeof value.nonce !== 'string' ||
30
+ value.nonce.length < NONCE_MIN_LENGTH ||
31
+ value.nonce.length > NONCE_MAX_LENGTH ||
32
+ typeof value.etag !== 'string' ||
33
+ !/^sha256:[0-9a-f]{64}$/u.test(value.etag)) {
34
+ fail('DELIVERY_REQUEST_INVALID', 'Delivery request is invalid.');
35
+ }
36
+ let kernel;
37
+ try {
38
+ kernel = acceptIssuer(value.kernel);
39
+ }
40
+ catch (cause) {
41
+ if (cause instanceof AuthValueError) {
42
+ return fail('DELIVERY_REQUEST_INVALID', 'Delivery request issuer is invalid.', cause);
43
+ }
44
+ throw cause;
45
+ }
46
+ return Object.freeze({
47
+ version: 1,
48
+ kernel,
49
+ nonce: value.nonce,
50
+ etag: value.etag,
51
+ });
52
+ }
@@ -0,0 +1,4 @@
1
+ import type { DeliveryDeclaration } from './declaration.js';
2
+ import type { Endpoint } from './delivery-endpoint.js';
3
+ /** Place one provider-neutral Delivery declaration beneath an exact serving issuer. */
4
+ export declare function placeDelivery(input: DeliveryDeclaration, issuer: string, bundleHref: string): Endpoint;
@@ -0,0 +1,25 @@
1
+ import { admitEndpoint } from './delivery-endpoint.js';
2
+ import { fail } from './error.js';
3
+ /** Place one provider-neutral Delivery declaration beneath an exact serving issuer. */
4
+ export function placeDelivery(input, issuer, bundleHref) {
5
+ if (input === null || typeof input !== 'object' || Array.isArray(input)) {
6
+ fail('PUBLICATION_INVALID', 'Delivery declaration is invalid.');
7
+ }
8
+ if (Reflect.ownKeys(input).some((key) => key !== 'path' && key !== 'authentication') ||
9
+ typeof input.path !== 'string' ||
10
+ !input.path.startsWith('/')) {
11
+ fail('PUBLICATION_INVALID', 'Delivery declaration is invalid.');
12
+ }
13
+ let href;
14
+ try {
15
+ const url = new URL(input.path, issuer);
16
+ if (url.origin !== new URL(issuer).origin || url.search !== '' || url.hash !== '') {
17
+ fail('PUBLICATION_INVALID', 'Delivery declaration must be one relative path.');
18
+ }
19
+ href = url.href;
20
+ }
21
+ catch (cause) {
22
+ return fail('PUBLICATION_INVALID', 'Delivery declaration path is invalid.', cause);
23
+ }
24
+ return admitEndpoint({ href, method: 'POST', authentication: input.authentication }, bundleHref);
25
+ }
@@ -0,0 +1,11 @@
1
+ export type Authentication = {
2
+ readonly kind: 'public';
3
+ } | {
4
+ readonly kind: 'bearer';
5
+ };
6
+ export interface Endpoint {
7
+ readonly href: string;
8
+ readonly method: 'POST';
9
+ readonly authentication: Authentication;
10
+ }
11
+ export declare function admitEndpoint(input: unknown, publicUrl: string): Endpoint | undefined;
@@ -0,0 +1,22 @@
1
+ import { absoluteHttpUrl, exact, record } from './content.js';
2
+ import { fail } from './error.js';
3
+ export function admitEndpoint(input, publicUrl) {
4
+ if (input === undefined)
5
+ return undefined;
6
+ const value = record(input, 'PUBLICATION_INVALID', 'Delivery endpoint is invalid.');
7
+ exact(value, ['href', 'method', 'authentication'], 'PUBLICATION_INVALID');
8
+ const href = absoluteHttpUrl(value.href, true, 'PUBLICATION_INVALID');
9
+ if (new URL(href).origin !== new URL(publicUrl).origin || value.method !== 'POST') {
10
+ fail('PUBLICATION_INVALID', 'Delivery endpoint must be same-origin POST.');
11
+ }
12
+ const authentication = record(value.authentication, 'PUBLICATION_INVALID', 'Delivery authentication is invalid.');
13
+ exact(authentication, ['kind'], 'PUBLICATION_INVALID');
14
+ if (authentication.kind !== 'public' && authentication.kind !== 'bearer') {
15
+ fail('PUBLICATION_INVALID', 'Delivery authentication kind is invalid.');
16
+ }
17
+ return Object.freeze({
18
+ href,
19
+ method: 'POST',
20
+ authentication: Object.freeze({ kind: authentication.kind }),
21
+ });
22
+ }
@@ -0,0 +1,7 @@
1
+ export type PublicationErrorCode = 'PUBLICATION_INVALID' | 'PUBLICATION_ETAG_MISMATCH' | 'PUBLICATION_BINDING_INVALID' | 'PUBLICATION_ROUTE_INVALID' | 'PUBLICATION_VIEW_INVALID';
2
+ export declare class PublicationError extends Error {
3
+ readonly code: PublicationErrorCode;
4
+ readonly name = "PublicationError";
5
+ constructor(code: PublicationErrorCode, message: string, options?: ErrorOptions);
6
+ }
7
+ export declare function fail(code: PublicationErrorCode, message: string, cause?: unknown): never;
@@ -0,0 +1,11 @@
1
+ export class PublicationError extends Error {
2
+ code;
3
+ name = 'PublicationError';
4
+ constructor(code, message, options) {
5
+ super(message, options);
6
+ this.code = code;
7
+ }
8
+ }
9
+ export function fail(code, message, cause) {
10
+ throw new PublicationError(code, message, cause === undefined ? undefined : { cause });
11
+ }
@@ -0,0 +1,6 @@
1
+ import type { Content } from './content.js';
2
+ export type Sha256Digest = `sha256:${string}`;
3
+ export type Etag = Sha256Digest;
4
+ export declare function admitDigest(input: unknown): Sha256Digest;
5
+ export declare function computeEtag(input: Content): Etag;
6
+ export declare function sha256Hex(input: Uint8Array): string;
@@ -0,0 +1,79 @@
1
+ import * as portable from '@astrale-os/kernel-dsl/value';
2
+ import { fail } from './error.js';
3
+ const DIGEST = /^sha256:[0-9a-f]{64}$/u;
4
+ export function admitDigest(input) {
5
+ if (typeof input !== 'string' || !DIGEST.test(input)) {
6
+ fail('PUBLICATION_INVALID', 'Digest is invalid.');
7
+ }
8
+ return input;
9
+ }
10
+ export function computeEtag(input) {
11
+ const bytes = portable.json.encode(input);
12
+ return `sha256:${sha256Hex(bytes)}`;
13
+ }
14
+ export function sha256Hex(input) {
15
+ const bitLength = input.length * 8;
16
+ const paddedLength = Math.ceil((input.length + 9) / 64) * 64;
17
+ const bytes = new Uint8Array(paddedLength);
18
+ bytes.set(input);
19
+ bytes[input.length] = 0x80;
20
+ const view = new DataView(bytes.buffer);
21
+ view.setUint32(paddedLength - 8, Math.floor(bitLength / 0x1_0000_0000), false);
22
+ view.setUint32(paddedLength - 4, bitLength >>> 0, false);
23
+ const state = new Uint32Array(INITIAL);
24
+ const words = new Uint32Array(64);
25
+ for (let offset = 0; offset < paddedLength; offset += 64) {
26
+ for (let index = 0; index < 16; index += 1) {
27
+ words[index] = view.getUint32(offset + index * 4, false);
28
+ }
29
+ for (let index = 16; index < 64; index += 1) {
30
+ const x = words[index - 15];
31
+ const y = words[index - 2];
32
+ const s0 = rotate(x, 7) ^ rotate(x, 18) ^ (x >>> 3);
33
+ const s1 = rotate(y, 17) ^ rotate(y, 19) ^ (y >>> 10);
34
+ words[index] = (words[index - 16] + s0 + words[index - 7] + s1) >>> 0;
35
+ }
36
+ let [a, b, c, d, e, f, g, h] = state;
37
+ for (let index = 0; index < 64; index += 1) {
38
+ const s1 = rotate(e, 6) ^ rotate(e, 11) ^ rotate(e, 25);
39
+ const choice = (e & f) ^ (~e & g);
40
+ const temporary1 = (h + s1 + choice + ROUND[index] + words[index]) >>> 0;
41
+ const s0 = rotate(a, 2) ^ rotate(a, 13) ^ rotate(a, 22);
42
+ const majority = (a & b) ^ (a & c) ^ (b & c);
43
+ const temporary2 = (s0 + majority) >>> 0;
44
+ h = g;
45
+ g = f;
46
+ f = e;
47
+ e = (d + temporary1) >>> 0;
48
+ d = c;
49
+ c = b;
50
+ b = a;
51
+ a = (temporary1 + temporary2) >>> 0;
52
+ }
53
+ state[0] = (state[0] + a) >>> 0;
54
+ state[1] = (state[1] + b) >>> 0;
55
+ state[2] = (state[2] + c) >>> 0;
56
+ state[3] = (state[3] + d) >>> 0;
57
+ state[4] = (state[4] + e) >>> 0;
58
+ state[5] = (state[5] + f) >>> 0;
59
+ state[6] = (state[6] + g) >>> 0;
60
+ state[7] = (state[7] + h) >>> 0;
61
+ }
62
+ return [...state].map((word) => word.toString(16).padStart(8, '0')).join('');
63
+ }
64
+ function rotate(value, count) {
65
+ return (value >>> count) | (value << (32 - count));
66
+ }
67
+ const INITIAL = new Uint32Array([
68
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
69
+ ]);
70
+ const ROUND = new Uint32Array([
71
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
72
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
73
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
74
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
75
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
76
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
77
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
78
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
79
+ ]);
@@ -0,0 +1,17 @@
1
+ export { MEDIA_TYPE, PATH, url, seal, accept, encode, type Publication } from './publication.js';
2
+ export { acceptBundle, decodeBundle } from './bundle-admission.js';
3
+ export { BUNDLE_MEDIA_TYPE, describeBundle, type BundleDescriptor } from './bundle.js';
4
+ export { verifyBundleBytes } from './bundle-evidence.js';
5
+ export type { Content } from './content.js';
6
+ export type { Declaration, DeliveryDeclaration } from './declaration.js';
7
+ export { placeDelivery } from './delivery-declaration.js';
8
+ export type { Etag, Sha256Digest } from './etag.js';
9
+ export { PublicationError, type PublicationErrorCode } from './error.js';
10
+ export * as delivery from './delivery/index.js';
11
+ export type { Authentication as DeliveryAuthentication, Endpoint as DeliveryEndpoint, } from './delivery-endpoint.js';
12
+ export type { Manifest } from './manifest.js';
13
+ export { ClassOperationOrder, admitRequirements, validateRequirements, type CapabilityAdminRequirements, type CapabilityRequirements, type ClassCapabilityRequirement, type ClassOperation, type NonEmpty, type PublicationRequirements, } from './requirements.js';
14
+ export { acceptReference, compareReference, compareReferences, matchesReference, reference, type PublicationRef, type PublicationReferenceRelation, } from './reference.js';
15
+ export type { BodyPick, CredentialSource, HttpMethod, HttpRoute, HttpRouteDeclaration, RouteBody, RouteHeaders, SingleCredentialSource, } from './route.js';
16
+ export type { Schema } from './schema.js';
17
+ export { acceptInvocationEndpoints, type CallableBinding, type InvocationEndpoints, type ViewBinding, } from './bindings/index.js';
@@ -0,0 +1,10 @@
1
+ export { MEDIA_TYPE, PATH, url, seal, accept, encode } from './publication.js';
2
+ export { acceptBundle, decodeBundle } from './bundle-admission.js';
3
+ export { BUNDLE_MEDIA_TYPE, describeBundle } from './bundle.js';
4
+ export { verifyBundleBytes } from './bundle-evidence.js';
5
+ export { placeDelivery } from './delivery-declaration.js';
6
+ export { PublicationError } from './error.js';
7
+ export * as delivery from './delivery/index.js';
8
+ export { ClassOperationOrder, admitRequirements, validateRequirements, } from './requirements.js';
9
+ export { acceptReference, compareReference, compareReferences, matchesReference, reference, } from './reference.js';
10
+ export { acceptInvocationEndpoints, } from './bindings/index.js';
@@ -0,0 +1,6 @@
1
+ import { type ViewRef } from '@astrale-os/kernel-dsl/v1/addressing';
2
+ export interface Manifest {
3
+ readonly logo?: string;
4
+ readonly entrypoint?: ViewRef;
5
+ }
6
+ export declare function admitManifest(input: unknown): Manifest | undefined;
@@ -0,0 +1,30 @@
1
+ import { acceptDefinitionRef } from '@astrale-os/kernel-dsl/v1/addressing';
2
+ import { exact, record } from './content.js';
3
+ import { fail } from './error.js';
4
+ export function admitManifest(input) {
5
+ if (input === undefined)
6
+ return undefined;
7
+ const value = record(input, 'PUBLICATION_INVALID', 'Manifest is invalid.');
8
+ exact(value, ['logo', 'entrypoint'], 'PUBLICATION_INVALID');
9
+ if (value.logo !== undefined && typeof value.logo !== 'string') {
10
+ fail('PUBLICATION_INVALID', 'Manifest logo must be a string.');
11
+ }
12
+ let entrypoint;
13
+ if (value.entrypoint !== undefined) {
14
+ let ref;
15
+ try {
16
+ ref = acceptDefinitionRef(value.entrypoint);
17
+ }
18
+ catch (cause) {
19
+ return fail('PUBLICATION_INVALID', 'Manifest entrypoint must be a root View reference.', cause);
20
+ }
21
+ if (ref.kind !== 'view') {
22
+ fail('PUBLICATION_INVALID', 'Manifest entrypoint must be a root View reference.');
23
+ }
24
+ entrypoint = ref;
25
+ }
26
+ return Object.freeze({
27
+ ...(value.logo === undefined ? {} : { logo: value.logo }),
28
+ ...(entrypoint === undefined ? {} : { entrypoint }),
29
+ });
30
+ }