@astrale-os/sdk 0.6.0-beta.13 → 0.6.0-beta.14

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 (135) hide show
  1. package/README.md +4 -0
  2. package/dist/deployment/adapter/adapter.d.ts +1 -6
  3. package/dist/deployment/adapter/legacy/adapter.d.ts +0 -10
  4. package/dist/deployment/adapter/legacy/deploy/context.d.ts +0 -2
  5. package/dist/deployment/adapter/legacy/deploy/result.d.ts +2 -3
  6. package/dist/deployment/adapter/legacy/index.d.ts +10 -8
  7. package/dist/deployment/adapter/legacy/prepare/context.d.ts +0 -2
  8. package/dist/deployment/adapter/release/context.d.ts +16 -2
  9. package/dist/deployment/address/index.d.ts +1 -1
  10. package/dist/deployment/address/index.js +1 -0
  11. package/dist/deployment/address/summary.d.ts +30 -0
  12. package/dist/deployment/address/summary.js +117 -1
  13. package/dist/deployment/build/index.d.ts +1 -1
  14. package/dist/deployment/build/index.js +1 -1
  15. package/dist/deployment/build/manifest.d.ts +5 -0
  16. package/dist/deployment/build/manifest.js +10 -0
  17. package/dist/deployment/index.d.ts +1 -1
  18. package/dist/deployment/release/legacy/index.d.ts +15 -10
  19. package/dist/deployment/release/legacy/index.js +15 -10
  20. package/dist/deployment/verify/readiness/deployment.js +3 -13
  21. package/dist/deployment/verify/readiness/fetch.d.ts +13 -0
  22. package/dist/deployment/verify/readiness/fetch.js +26 -0
  23. package/dist/deployment/verify/readiness/identity.d.ts +3 -6
  24. package/dist/deployment/verify/readiness/identity.js +3 -3
  25. package/dist/deployment/verify/readiness/index.d.ts +12 -8
  26. package/dist/deployment/verify/readiness/index.js +15 -4
  27. package/dist/deployment/verify/readiness/legacy/index.d.ts +2 -0
  28. package/dist/deployment/verify/readiness/legacy/index.js +2 -0
  29. package/dist/deployment/verify/readiness/legacy/publication.d.ts +12 -0
  30. package/dist/deployment/verify/readiness/legacy/publication.js +23 -0
  31. package/dist/deployment/verify/readiness/release.d.ts +8 -0
  32. package/dist/deployment/verify/readiness/release.js +22 -0
  33. package/dist/execution/identity/authentication.d.ts +7 -0
  34. package/dist/execution/identity/authentication.js +7 -1
  35. package/dist/execution/identity/delivery.d.ts +11 -4
  36. package/dist/execution/identity/delivery.js +47 -20
  37. package/dist/execution/identity/identity.d.ts +7 -3
  38. package/dist/execution/identity/identity.js +2 -2
  39. package/dist/execution/invocation/admission/authentication.d.ts +1 -2
  40. package/dist/execution/invocation/admission/authentication.js +1 -2
  41. package/dist/execution/invocation/admission/authority.d.ts +10 -4
  42. package/dist/execution/invocation/admission/authority.js +5 -1
  43. package/dist/execution/invocation/invocation.js +51 -14
  44. package/dist/execution/runtime/index.d.ts +1 -0
  45. package/dist/execution/runtime/index.js +1 -0
  46. package/dist/execution/runtime/load.d.ts +3 -3
  47. package/dist/execution/runtime/load.js +3 -2
  48. package/dist/execution/runtime/release.d.ts +22 -0
  49. package/dist/execution/runtime/release.js +14 -0
  50. package/dist/execution/serve.d.ts +2 -2
  51. package/dist/execution/service/create.js +9 -7
  52. package/dist/execution/service/release.d.ts +2 -2
  53. package/dist/execution/service/release.js +3 -2
  54. package/dist/execution/service/service.d.ts +9 -5
  55. package/dist/execution/service/serving/delivery.d.ts +6 -0
  56. package/dist/execution/service/{publication → serving}/delivery.js +5 -1
  57. package/dist/execution/service/{publication → serving}/index.d.ts +1 -1
  58. package/dist/execution/service/serving/installation.d.ts +4 -0
  59. package/dist/execution/service/serving/installation.js +9 -0
  60. package/dist/execution/service/serving/legacy/index.d.ts +15 -0
  61. package/dist/execution/service/serving/legacy/index.js +19 -0
  62. package/dist/execution/service/serving/source.d.ts +18 -0
  63. package/dist/execution/service/serving/source.js +19 -0
  64. package/dist/project/define.js +57 -28
  65. package/dist/project/install-command.d.ts +10 -0
  66. package/dist/project/install-command.js +13 -0
  67. package/dist/project/project.d.ts +4 -2
  68. package/dist/tooling/cli/arguments.d.ts +0 -2
  69. package/dist/tooling/cli/arguments.js +22 -15
  70. package/dist/tooling/cli/commit.d.ts +23 -0
  71. package/dist/tooling/cli/commit.js +216 -0
  72. package/dist/tooling/cli/deploy-mode.d.ts +19 -12
  73. package/dist/tooling/cli/deploy-mode.js +14 -32
  74. package/dist/tooling/cli/deploy-result.d.ts +10 -7
  75. package/dist/tooling/cli/deploy-result.js +4 -3
  76. package/dist/tooling/cli/development/candidate.d.ts +2 -3
  77. package/dist/tooling/cli/development/candidate.js +2 -9
  78. package/dist/tooling/cli/development/deployment.d.ts +2 -8
  79. package/dist/tooling/cli/development/deployment.js +2 -21
  80. package/dist/tooling/cli/development/develop.d.ts +4 -3
  81. package/dist/tooling/cli/development/develop.js +8 -112
  82. package/dist/tooling/cli/development/report.d.ts +1 -3
  83. package/dist/tooling/cli/development/report.js +1 -4
  84. package/dist/tooling/cli/help.js +28 -26
  85. package/dist/tooling/cli/immutable-deployment.d.ts +27 -0
  86. package/dist/tooling/cli/immutable-deployment.js +95 -0
  87. package/dist/tooling/cli/index.d.ts +2 -4
  88. package/dist/tooling/cli/index.js +2 -3
  89. package/dist/tooling/cli/legacy/deploy-result.d.ts +5 -3
  90. package/dist/tooling/cli/legacy/deploy-result.js +5 -3
  91. package/dist/tooling/cli/legacy/stable-target-adapter.d.ts +5 -3
  92. package/dist/tooling/cli/legacy/stable-target-deploy.d.ts +42 -0
  93. package/dist/tooling/cli/legacy/stable-target-deploy.js +104 -0
  94. package/dist/tooling/cli/orchestrate.js +46 -97
  95. package/dist/tooling/cli/secrets.d.ts +9 -0
  96. package/dist/tooling/cli/secrets.js +19 -0
  97. package/package.json +1 -1
  98. package/dist/deployment/verify/readiness/publication.d.ts +0 -11
  99. package/dist/deployment/verify/readiness/publication.js +0 -41
  100. package/dist/execution/service/publication/delivery.d.ts +0 -2
  101. package/dist/execution/service/publication/installation.d.ts +0 -3
  102. package/dist/execution/service/publication/installation.js +0 -8
  103. package/dist/execution/service/publication/source.d.ts +0 -3
  104. package/dist/execution/service/publication/source.js +0 -11
  105. package/dist/tooling/cli/astrale/authority.d.ts +0 -5
  106. package/dist/tooling/cli/astrale/authority.js +0 -11
  107. package/dist/tooling/cli/astrale/executable.d.ts +0 -2
  108. package/dist/tooling/cli/astrale/executable.js +0 -47
  109. package/dist/tooling/cli/astrale/failure.d.ts +0 -6
  110. package/dist/tooling/cli/astrale/failure.js +0 -48
  111. package/dist/tooling/cli/astrale/instance.d.ts +0 -11
  112. package/dist/tooling/cli/astrale/instance.js +0 -52
  113. package/dist/tooling/cli/astrale/process.d.ts +0 -13
  114. package/dist/tooling/cli/astrale/process.js +0 -94
  115. package/dist/tooling/cli/astrale/version.d.ts +0 -18
  116. package/dist/tooling/cli/astrale/version.js +0 -55
  117. package/dist/tooling/cli/development/release-evidence.d.ts +0 -4
  118. package/dist/tooling/cli/development/release-evidence.js +0 -10
  119. package/dist/tooling/cli/development/session-file.d.ts +0 -53
  120. package/dist/tooling/cli/development/session-file.js +0 -337
  121. package/dist/tooling/cli/development/target-lock.d.ts +0 -16
  122. package/dist/tooling/cli/development/target-lock.js +0 -68
  123. package/dist/tooling/cli/development/view.d.ts +0 -28
  124. package/dist/tooling/cli/development/view.js +0 -151
  125. package/dist/tooling/cli/environment-release.d.ts +0 -24
  126. package/dist/tooling/cli/environment-release.js +0 -46
  127. package/dist/tooling/cli/evidence.d.ts +0 -14
  128. package/dist/tooling/cli/evidence.js +0 -53
  129. package/dist/tooling/cli/installation/index.d.ts +0 -2
  130. package/dist/tooling/cli/installation/index.js +0 -1
  131. package/dist/tooling/cli/installation/observation.d.ts +0 -10
  132. package/dist/tooling/cli/installation/observation.js +0 -44
  133. package/dist/tooling/cli/installation/reconcile.d.ts +0 -32
  134. package/dist/tooling/cli/installation/reconcile.js +0 -122
  135. /package/dist/execution/service/{publication → serving}/index.js +0 -0
@@ -1,10 +1,21 @@
1
1
  import { verifyIdentity } from './identity.js';
2
- import { verifyPublication } from './publication.js';
2
+ import { verifyPublication } from './legacy/index.js';
3
+ import { verifyRelease } from './release.js';
3
4
  export { verifyDeployment } from './deployment.js';
4
5
  export { verifyIdentity } from './identity.js';
5
- export { verifyPublication } from './publication.js';
6
- /** Read-only verification of one exact live Release and serving identity. */
6
+ export { verifyPublication } from './legacy/index.js';
7
+ export { verifyRelease } from './release.js';
8
+ /**
9
+ * Read-only verification of one exact live Release and its serving identity: an immutable
10
+ * deployment's `release.json` (release digest and build digest), or a stable target's
11
+ * `domain.json` (deprecated, `legacy/`).
12
+ */
7
13
  export async function readiness(release, options = {}) {
14
+ if (release.kind === 'release') {
15
+ await verifyRelease(release, options);
16
+ await verifyIdentity(release.url, options);
17
+ return;
18
+ }
8
19
  await verifyPublication(release, options);
9
- await verifyIdentity(release.addressing, options);
20
+ await verifyIdentity(release.addressing.issuer, options);
10
21
  }
@@ -0,0 +1,2 @@
1
+ /** @deprecated Stable-target readiness at `domain.json`; see `publication.ts` (removal D10). */
2
+ export { verifyPublication } from './publication.js';
@@ -0,0 +1,2 @@
1
+ /** @deprecated Stable-target readiness at `domain.json`; see `publication.ts` (removal D10). */
2
+ export { verifyPublication } from './publication.js';
@@ -0,0 +1,12 @@
1
+ import * as publication from '@astrale-os/kernel-protocol/release/legacy';
2
+ import type * as legacy from '../../../release/legacy/index.js';
3
+ import type { ReadinessOptions } from '../fetch.js';
4
+ /**
5
+ * Fetch and verify the exact live Publication and Bundle a stable target serves at `domain.json`.
6
+ *
7
+ * @deprecated Replacement: `verifyRelease`, the readiness of an immutable deployment at
8
+ * `release.json` (release digest and build digest). Consumer: the direct-mode deploy path of
9
+ * adapter-cloudflare and adapter-astrale (the consumers of `deployment/release/legacy/index.ts`).
10
+ * Removal: D10, with that path.
11
+ */
12
+ export declare function verifyPublication(release: legacy.Release, options?: ReadinessOptions): Promise<publication.Publication>;
@@ -0,0 +1,23 @@
1
+ import * as publication from '@astrale-os/kernel-protocol/release/legacy';
2
+ import { bounded, fetchRequired, MAXIMUM_BUNDLE_BYTES, MAXIMUM_DOCUMENT_BYTES, text, } from '../fetch.js';
3
+ /**
4
+ * Fetch and verify the exact live Publication and Bundle a stable target serves at `domain.json`.
5
+ *
6
+ * @deprecated Replacement: `verifyRelease`, the readiness of an immutable deployment at
7
+ * `release.json` (release digest and build digest). Consumer: the direct-mode deploy path of
8
+ * adapter-cloudflare and adapter-astrale (the consumers of `deployment/release/legacy/index.ts`).
9
+ * Removal: D10, with that path.
10
+ */
11
+ export async function verifyPublication(release, options = {}) {
12
+ const fetcher = options.fetch ?? globalThis.fetch;
13
+ const publicationUrl = publication.url(release.addressing.publicUrl);
14
+ const response = await fetchRequired(fetcher, publicationUrl, options.signal);
15
+ const deployed = publication.accept(JSON.parse(await text(response, publicationUrl, MAXIMUM_DOCUMENT_BYTES)));
16
+ if (!publication.matchesReference(deployed, publication.reference(release.publication))) {
17
+ throw new Error('Live Publication differs from the expected Release.');
18
+ }
19
+ const bundleResponse = await fetchRequired(fetcher, deployed.schema.bundle.href, options.signal);
20
+ const bytes = new Uint8Array(await bounded(bundleResponse, deployed.schema.bundle.href, MAXIMUM_BUNDLE_BYTES));
21
+ publication.decodeBundle(deployed, bytes);
22
+ return deployed;
23
+ }
@@ -0,0 +1,8 @@
1
+ import * as release from '@astrale-os/kernel-protocol/release';
2
+ import type { Release } from '../../release/index.js';
3
+ import type { ReadinessOptions } from './fetch.js';
4
+ /**
5
+ * Fetch and verify the exact live release of one immutable deployment at its `release.json`: its
6
+ * release digest and the build digest of its code, then its Bundle.
7
+ */
8
+ export declare function verifyRelease(expected: Release, options?: ReadinessOptions): Promise<release.DomainRelease>;
@@ -0,0 +1,22 @@
1
+ import * as release from '@astrale-os/kernel-protocol/release';
2
+ import { bounded, fetchRequired, MAXIMUM_BUNDLE_BYTES, MAXIMUM_DOCUMENT_BYTES, text, } from './fetch.js';
3
+ /**
4
+ * Fetch and verify the exact live release of one immutable deployment at its `release.json`: its
5
+ * release digest and the build digest of its code, then its Bundle.
6
+ */
7
+ export async function verifyRelease(expected, options = {}) {
8
+ const fetcher = options.fetch ?? globalThis.fetch;
9
+ const releaseUrl = release.url(expected.url);
10
+ const response = await fetchRequired(fetcher, releaseUrl, options.signal);
11
+ const deployed = release.accept(JSON.parse(await text(response, releaseUrl, MAXIMUM_DOCUMENT_BYTES)));
12
+ if (!release.matchesReference(deployed, release.reference(expected.document))) {
13
+ throw new Error('Live release differs from the expected Release.');
14
+ }
15
+ if (deployed.build.digest !== expected.buildDigest) {
16
+ throw new Error('Live release build digest differs from the expected build.');
17
+ }
18
+ const bundleResponse = await fetchRequired(fetcher, deployed.schema.bundle.href, options.signal);
19
+ const bytes = new Uint8Array(await bounded(bundleResponse, deployed.schema.bundle.href, MAXIMUM_BUNDLE_BYTES));
20
+ release.decodeBundle(deployed, bytes);
21
+ return deployed;
22
+ }
@@ -5,6 +5,13 @@ import type { InvocationAdmissionInput } from '../invocation/index.js';
5
5
  import type { IdentityNetworkPolicy, VerificationBasis, VerificationBasisResolver } from './jwks.js';
6
6
  import type { SigningMaterial } from './signing.js';
7
7
  import { ClientSession } from '../../platform/client/session/index.js';
8
+ /**
9
+ * How long a callback Session reuses a learned route. It stays at most the Kernel's in-flight
10
+ * issuer window (`KERNEL_INFLIGHT_ISSUER_MS`, Host default 300 s; CT11): a route learned to a
11
+ * deployment replaced by a consented install ages out while that deployment is still accepted and
12
+ * answers the reserved miss, never after its own credential is refused (AM-85).
13
+ */
14
+ export declare const DEFAULT_ROUTE_AGE_MS = 60000;
8
15
  export declare function admit(request: InvocationAdmissionInput, configuration: AuthenticationConfiguration): Promise<unknown>;
9
16
  export interface AuthenticationConfiguration {
10
17
  readonly issuer: IssuerId;
@@ -10,7 +10,13 @@ import { projectError, protocolError } from '../invocation/result/index.js';
10
10
  import { callbackIdentities, createCallbackCredentialResolver, maximumCallbackDelegationTtlSeconds, selfIdentity, signDomainCallback, } from './callback.js';
11
11
  import { CredentialRejected, IssuerUnavailable, boundedFetch, callbackTtl, httpIssuer, invocationUrl, admitEndpoint, requireLive, } from './errors.js';
12
12
  import { verifyCredential, verifyCredentialAgainst } from './jwks.js';
13
- const DEFAULT_ROUTE_AGE_MS = 60_000;
13
+ /**
14
+ * How long a callback Session reuses a learned route. It stays at most the Kernel's in-flight
15
+ * issuer window (`KERNEL_INFLIGHT_ISSUER_MS`, Host default 300 s; CT11): a route learned to a
16
+ * deployment replaced by a consented install ages out while that deployment is still accepted and
17
+ * answers the reserved miss, never after its own credential is refused (AM-85).
18
+ */
19
+ export const DEFAULT_ROUTE_AGE_MS = 60_000;
14
20
  export async function admit(request, configuration) {
15
21
  const execution = request.context.execution;
16
22
  requireLive(execution);
@@ -1,6 +1,13 @@
1
- import type { publication as serverPublication } from '@astrale-os/kernel-server';
2
- import * as publication from '@astrale-os/kernel-protocol/release/legacy';
1
+ import type { release as serverRelease } from '@astrale-os/kernel-server';
2
+ import * as release from '@astrale-os/kernel-protocol/release';
3
3
  import type { IssuerId } from '../../platform/auth/index.js';
4
4
  import type { SigningMaterial } from './signing.js';
5
- /** Create one stateless, nonce-bound public Delivery provider for an exact Publication. */
6
- export declare function publicationDelivery(signing: SigningMaterial, issuer: IssuerId, subject: string, deployed: publication.Publication): serverPublication.delivery.Provider;
5
+ type Served = release.DomainRelease | release.legacy.Publication;
6
+ /**
7
+ * Create one stateless, nonce-bound public Delivery provider for the exact document a deployment
8
+ * serves. It answers in the request's version: a Delivery v2 carrying the release for a v2
9
+ * request, and a Delivery v1 carrying the Publication (a release's frozen v3 projection) for the
10
+ * deprecated v1 request. A stable target's Publication answers v1 only.
11
+ */
12
+ export declare function releaseDelivery(signing: SigningMaterial, issuer: IssuerId, subject: string, deployed: Served): serverRelease.delivery.Provider;
13
+ export {};
@@ -1,34 +1,61 @@
1
- import * as publication from '@astrale-os/kernel-protocol/release/legacy';
1
+ import * as release from '@astrale-os/kernel-protocol/release';
2
2
  import { SignJWT } from 'jose';
3
3
  const ATTESTATION_TTL_SECONDS = 60;
4
- /** Create one stateless, nonce-bound public Delivery provider for an exact Publication. */
5
- export function publicationDelivery(signing, issuer, subject, deployed) {
4
+ /**
5
+ * Create one stateless, nonce-bound public Delivery provider for the exact document a deployment
6
+ * serves. It answers in the request's version: a Delivery v2 carrying the release for a v2
7
+ * request, and a Delivery v1 carrying the Publication (a release's frozen v3 projection) for the
8
+ * deprecated v1 request. A stable target's Publication answers v1 only.
9
+ */
10
+ export function releaseDelivery(signing, issuer, subject, deployed) {
11
+ const projection = deployed.version === 4 ? release.legacy.publication(deployed) : deployed;
6
12
  return Object.freeze({
7
13
  async create(request, context) {
8
14
  context.signal.throwIfAborted();
9
- const now = Math.floor(Date.now() / 1_000);
10
- const attestation = await new SignJWT({
11
- purpose: publication.delivery.PURPOSE,
15
+ if (request.version === 1) {
16
+ const attestation = await attest(signing, issuer, subject, request.kernel, {
17
+ purpose: release.legacy.delivery.PURPOSE,
18
+ nonce: request.nonce,
19
+ etag: projection.etag,
20
+ schemaRevision: projection.schema.revision,
21
+ });
22
+ context.signal.throwIfAborted();
23
+ return release.legacy.delivery.accept({
24
+ format: 'astrale.domain.delivery',
25
+ version: 1,
26
+ publication: projection,
27
+ attestation,
28
+ });
29
+ }
30
+ if (deployed.version !== 4) {
31
+ throw new TypeError('A Publication-backed deployment answers Delivery v1 only.');
32
+ }
33
+ const attestation = await attest(signing, issuer, subject, request.kernel, {
34
+ purpose: release.delivery.PURPOSE,
12
35
  nonce: request.nonce,
13
- etag: deployed.etag,
36
+ release: deployed.digest,
14
37
  schemaRevision: deployed.schema.revision,
15
- })
16
- .setProtectedHeader({
17
- alg: signing.algorithm,
18
- ...(signing.keyId === undefined ? {} : { kid: signing.keyId }),
19
- })
20
- .setIssuer(issuer)
21
- .setSubject(subject)
22
- .setAudience(request.kernel)
23
- .setExpirationTime(now + ATTESTATION_TTL_SECONDS)
24
- .sign(await signing.privateKey);
38
+ });
25
39
  context.signal.throwIfAborted();
26
- return publication.delivery.accept({
40
+ return release.delivery.accept({
27
41
  format: 'astrale.domain.delivery',
28
- version: 1,
29
- publication: deployed,
42
+ version: 2,
43
+ release: deployed,
30
44
  attestation,
31
45
  });
32
46
  },
33
47
  });
34
48
  }
49
+ async function attest(signing, issuer, subject, kernel, claims) {
50
+ const now = Math.floor(Date.now() / 1_000);
51
+ return new SignJWT(claims)
52
+ .setProtectedHeader({
53
+ alg: signing.algorithm,
54
+ ...(signing.keyId === undefined ? {} : { kid: signing.keyId }),
55
+ })
56
+ .setIssuer(issuer)
57
+ .setSubject(subject)
58
+ .setAudience(kernel)
59
+ .setExpirationTime(now + ATTESTATION_TTL_SECONDS)
60
+ .sign(await signing.privateKey);
61
+ }
@@ -1,6 +1,6 @@
1
1
  import type { Fetch } from '@astrale-os/kernel-client';
2
- import type * as publicationProtocol from '@astrale-os/kernel-protocol/release/legacy';
3
- import type { Issuer, exchange, publication } from '@astrale-os/kernel-server';
2
+ import type * as releaseProtocol from '@astrale-os/kernel-protocol/release';
3
+ import type { Issuer, exchange, release } from '@astrale-os/kernel-server';
4
4
  import type { IssuerId, JsonWebKey } from '../../platform/auth/index.js';
5
5
  import type { ClientSession } from '../../platform/client/session/index.js';
6
6
  import type { InvocationAuthority } from '../invocation/index.js';
@@ -10,7 +10,11 @@ import type { IdentityNetworkPolicy } from './jwks.js';
10
10
  export interface Identity extends Issuer, InvocationAuthority {
11
11
  readonly subject: string;
12
12
  readonly tokenExchange?: exchange.Provider;
13
- delivery(publication: publicationProtocol.Publication): publication.delivery.Provider;
13
+ /**
14
+ * Delivery for the exact document this deployment serves: Delivery v2 over its release and v1
15
+ * over its frozen v3 projection, or v1 over a stable target's Publication.
16
+ */
17
+ delivery(served: releaseProtocol.DomainRelease | releaseProtocol.legacy.Publication): release.delivery.Provider;
14
18
  /**
15
19
  * The Domain's own authority toward one Kernel for work no caller credential carries, such as a
16
20
  * durable run. Required to serve durable Workflows; the caller closes the Session.
@@ -1,5 +1,5 @@
1
1
  import { admit, authenticate, executorSession } from './authentication.js';
2
- import { publicationDelivery } from './delivery.js';
2
+ import { releaseDelivery } from './delivery.js';
3
3
  import { httpIssuer } from './errors.js';
4
4
  import { maximumExchangeTtl, tokenExchange } from './exchange.js';
5
5
  import { createVerificationBasisResolver } from './jwks.js';
@@ -49,7 +49,7 @@ export function createIdentity(input) {
49
49
  ? {}
50
50
  : { loadIssuerPublicKeys: input.loadIssuerPublicKeys }),
51
51
  ...(exchangeProvider === undefined ? {} : { tokenExchange: exchangeProvider }),
52
- delivery: (publication) => publicationDelivery(material, issuer, input.subject, publication),
52
+ delivery: (served) => releaseDelivery(material, issuer, input.subject, served),
53
53
  admit: (request) => admit(request, configuration),
54
54
  executor: (kernel, execution) => executorSession(kernel, execution, configuration),
55
55
  authenticate: (request) => authenticate(request.credential, request.via.issuer, request.context.execution, configuration),
@@ -1,6 +1,5 @@
1
1
  import type { HandlerRequest } from '@astrale-os/kernel-server';
2
2
  import type { AnonymousCaller, ResolvedCallable } from '../../../application/action/index.js';
3
- import type { Release } from '../../../deployment/release/legacy/index.js';
4
3
  import type { Domain } from '../../../platform/schema/index.js';
5
4
  import type { AuthenticatedInvocation, InvocationAuthority } from './authority.js';
6
5
  export interface AnonymousInvocation {
@@ -10,4 +9,4 @@ export interface AnonymousInvocation {
10
9
  close(): void;
11
10
  }
12
11
  export type InvocationAuthentication = AnonymousInvocation | AuthenticatedInvocation;
13
- export declare function authentication(callable: ResolvedCallable, request: HandlerRequest, release: Release, domain: Domain, authority: InvocationAuthority): Promise<InvocationAuthentication>;
12
+ export declare function authentication(callable: ResolvedCallable, request: HandlerRequest, domain: Domain, authority: InvocationAuthority): Promise<InvocationAuthentication>;
@@ -9,7 +9,7 @@ const ANONYMOUS = Object.freeze({
9
9
  graph: null,
10
10
  close() { },
11
11
  });
12
- export async function authentication(callable, request, release, domain, authority) {
12
+ export async function authentication(callable, request, domain, authority) {
13
13
  const credential = request.credential;
14
14
  if (callable.auth === 'anonymous' && credential === undefined)
15
15
  return ANONYMOUS;
@@ -21,7 +21,6 @@ export async function authentication(callable, request, release, domain, authori
21
21
  const authenticated = await authority.authenticate({
22
22
  credential,
23
23
  via: requireVia(request),
24
- publication: release.publication,
25
24
  domain,
26
25
  context: request.context,
27
26
  });
@@ -1,5 +1,4 @@
1
1
  import type * as invocation from '@astrale-os/kernel-protocol/invocation';
2
- import type * as publication from '@astrale-os/kernel-protocol/release/legacy';
3
2
  import type { HandlerRequest, InvocationContext } from '@astrale-os/kernel-server';
4
3
  import type { AuthenticatedCaller } from '../../../application/action/index.js';
5
4
  import type { BoundClientSession } from '../../../platform/client/session/index.js';
@@ -8,14 +7,12 @@ export interface InvocationAdmissionInput {
8
7
  readonly call: invocation.Call;
9
8
  readonly credential?: string;
10
9
  readonly via: invocation.Via | invocation.PublicationVia;
11
- readonly publication: publication.Publication;
12
10
  readonly domain: Domain;
13
11
  readonly context: InvocationContext;
14
12
  }
15
13
  export interface InvocationAuthenticationInput {
16
14
  readonly credential: string;
17
15
  readonly via: invocation.Via | invocation.PublicationVia;
18
- readonly publication: publication.Publication;
19
16
  readonly domain: Domain;
20
17
  readonly context: InvocationContext;
21
18
  }
@@ -26,10 +23,19 @@ export interface AuthenticatedInvocation {
26
23
  close(): void;
27
24
  }
28
25
  export interface InvocationAuthority {
26
+ /**
27
+ * The source Kernel's `Function.admit` of a remote call: resolves to the admitted target, or
28
+ * rejects with the public refusal. A refusal whose reason is `FUNCTION_MISS` (the Kernel no longer
29
+ * places the call on this deployment) is answered as the reserved miss, never as an error.
30
+ */
29
31
  admit(input: InvocationAdmissionInput): Promise<unknown>;
30
32
  authenticate(input: InvocationAuthenticationInput): Promise<AuthenticatedInvocation>;
31
33
  }
32
34
  /** Capture the execution Identity capability and receiver-bind both privileged operations. */
33
35
  export declare function authority(input: InvocationAuthority): InvocationAuthority;
34
- /** The routed witness of a remote call: a `ReleaseRef`, or the `PublicationRef` of a v3 pin. */
36
+ /**
37
+ * The routed witness of a remote call, already admitted by the Kernel Server against the served
38
+ * snapshot: the exact `ReleaseRef` of an immutable deployment, or the `PublicationRef` of a v3 pin
39
+ * (a release's exact projection, or a stable target's Publication).
40
+ */
35
41
  export declare function requireVia(request: HandlerRequest): invocation.Via | invocation.PublicationVia;
@@ -12,7 +12,11 @@ export function authority(input) {
12
12
  authenticate: receiver.authenticate.bind(receiver),
13
13
  });
14
14
  }
15
- /** The routed witness of a remote call: a `ReleaseRef`, or the `PublicationRef` of a v3 pin. */
15
+ /**
16
+ * The routed witness of a remote call, already admitted by the Kernel Server against the served
17
+ * snapshot: the exact `ReleaseRef` of an immutable deployment, or the `PublicationRef` of a v3 pin
18
+ * (a release's exact projection, or a stable target's Publication).
19
+ */
16
20
  export function requireVia(request) {
17
21
  if (request.via === undefined) {
18
22
  throw protocolError('VALIDATION_ERROR', 'Remote invocation requires Via.');
@@ -1,38 +1,39 @@
1
- import * as publication from '@astrale-os/kernel-protocol/release/legacy';
1
+ import * as errors from '@astrale-os/kernel-protocol/errors';
2
+ import * as release from '@astrale-os/kernel-protocol/release';
2
3
  import { authentication, input, requireVia, target } from './admission/index.js';
3
4
  import { action, context, select, workflow } from './dispatch/index.js';
4
5
  import { active, settle } from './lifecycle/index.js';
5
6
  import { project, protocolError } from './result/index.js';
7
+ /** The reserved answer of a deployment that does not serve the call: its caller re-routes. */
8
+ const MISS = Object.freeze({ kind: 'miss' });
9
+ const FUNCTION_MISS = 'FUNCTION_MISS';
6
10
  export async function invoke(request, inputConfig) {
7
11
  active(request.context);
8
- const release = inputConfig.runtime.loaded.release;
9
- const snapshot = request.publication;
10
- if (snapshot === undefined ||
11
- !publication.matchesReference(snapshot.publication, publication.reference(release.publication))) {
12
- throw protocolError('CONFLICT', 'Invocation Publication differs from the running Release.');
12
+ if (!pinsRunningRelease(request, inputConfig.runtime.loaded.release)) {
13
+ throw protocolError('CONFLICT', 'Invocation release differs from the running Release.');
13
14
  }
14
15
  if (request.credential !== undefined && typeof request.credential !== 'string') {
15
16
  throw protocolError('AUTH_INVALID', 'Credential is invalid.');
16
17
  }
17
- const via = requireVia(request);
18
- const selectedTarget = target(await inputConfig.authority.admit({
18
+ const admitted = await admit(inputConfig.authority, {
19
19
  call: request.call,
20
20
  ...(request.credential === undefined ? {} : { credential: request.credential }),
21
- via,
22
- publication: release.publication,
21
+ via: requireVia(request),
23
22
  domain: inputConfig.runtime.loaded.domain,
24
23
  context: request.context,
25
- }));
26
- const selected = select(inputConfig.runtime.loaded.registry, selectedTarget);
24
+ });
25
+ if (admitted === undefined)
26
+ return MISS;
27
+ const selected = select(inputConfig.runtime.loaded.registry, admitted);
27
28
  if (selected === undefined)
28
- return Object.freeze({ kind: 'miss' });
29
+ return MISS;
29
30
  if (selected.implementation.kind === 'workflow' && selected.implementation.durable) {
30
31
  // The Kernel records a durable call as an Execution and runs it on the engine; running it
31
32
  // inline here would silently drop durability.
32
33
  throw protocolError('UNSUPPORTED', 'A durable Workflow runs only as a Kernel Execution.');
33
34
  }
34
35
  input(selected.implementation.callable, request.call.input, request.context.binary);
35
- const admittedAuthentication = await authentication(selected.implementation.callable, request, release, inputConfig.runtime.loaded.domain, inputConfig.authority);
36
+ const admittedAuthentication = await authentication(selected.implementation.callable, request, inputConfig.runtime.loaded.domain, inputConfig.authority);
36
37
  const close = once(admittedAuthentication.close);
37
38
  try {
38
39
  active(request.context);
@@ -47,6 +48,42 @@ export async function invoke(request, inputConfig) {
47
48
  throw cause;
48
49
  }
49
50
  }
51
+ /**
52
+ * The source Kernel's `Function.admit` refuses `FUNCTION_MISS` when it no longer places the call on
53
+ * this deployment, as for a client whose learned route still names a deployment replaced by a
54
+ * consented install. That refusal is answered as the reserved miss, never as a public error, so
55
+ * the client re-routes through its source Kernel (AM-85). Every other refusal is unchanged.
56
+ */
57
+ async function admit(authority, admission) {
58
+ let admitted;
59
+ try {
60
+ admitted = await authority.admit(admission);
61
+ }
62
+ catch (cause) {
63
+ if (refusedAsMiss(cause))
64
+ return undefined;
65
+ throw cause;
66
+ }
67
+ return target(admitted);
68
+ }
69
+ function refusedAsMiss(cause) {
70
+ return (cause instanceof errors.ProtocolError &&
71
+ errors.reasonOf(cause.payload.data)?.code === FUNCTION_MISS);
72
+ }
73
+ /**
74
+ * The Kernel Server pins every request to the one snapshot it serves: the release of an immutable
75
+ * deployment, or a stable target's Publication. Execution answers only for that exact document.
76
+ */
77
+ function pinsRunningRelease(request, running) {
78
+ if (running.kind === 'release') {
79
+ return (request.publication === undefined &&
80
+ request.release !== undefined &&
81
+ release.matchesReference(request.release.release, release.reference(running.document)));
82
+ }
83
+ return (request.release === undefined &&
84
+ request.publication !== undefined &&
85
+ release.legacy.matchesReference(request.publication.publication, release.legacy.reference(running.publication)));
86
+ }
50
87
  function once(operation) {
51
88
  let called = false;
52
89
  return () => {
@@ -3,3 +3,4 @@ export { initialize, type InitializedRuntime } from './initialize.js';
3
3
  export { integrations } from './integrations.js';
4
4
  export { load, type LoadedRuntime } from './load.js';
5
5
  export { providers } from './providers.js';
6
+ export { isServedRelease, serving, type ServedRelease, type Serving } from './release.js';
@@ -3,3 +3,4 @@ export { initialize } from './initialize.js';
3
3
  export { integrations } from './integrations.js';
4
4
  export { load } from './load.js';
5
5
  export { providers } from './providers.js';
6
+ export { isServedRelease, serving } from './release.js';
@@ -2,13 +2,13 @@ import type { Domain } from '@astrale-os/kernel-dsl/v1/domain';
2
2
  import type { DomainSchema, DomainOf } from '@astrale-os/kernel-dsl/v1/schema';
3
3
  import type { RuntimeRegistry } from '../../application/runtime/index.js';
4
4
  import type { Build } from '../../deployment/build/build.js';
5
- import type { Release } from '../../deployment/release/legacy/release.js';
5
+ import type { ServedRelease } from './release.js';
6
6
  type DomainOfBuild<BuildValue extends Build> = BuildValue extends Build<infer Schema extends DomainSchema, object> ? Extract<DomainOf<Schema>, Domain> : Domain;
7
7
  export interface LoadedRuntime<BuildValue extends Build = Build> {
8
- readonly release: Release<BuildValue>;
8
+ readonly release: ServedRelease<BuildValue>;
9
9
  readonly domain: DomainOfBuild<BuildValue>;
10
10
  readonly registry: RuntimeRegistry;
11
11
  }
12
12
  /** Load one execution Runtime from the exact evidence retained by its admitted Build. */
13
- export declare function load<const BuildValue extends Build>(release: Release<BuildValue>): LoadedRuntime<BuildValue>;
13
+ export declare function load<const BuildValue extends Build>(release: ServedRelease<BuildValue>): LoadedRuntime<BuildValue>;
14
14
  export {};
@@ -1,10 +1,11 @@
1
1
  import { evidenceOf } from '../../deployment/build/admission.js';
2
- import { isRelease } from '../../deployment/release/legacy/admission.js';
3
2
  import { capture } from './admission.js';
3
+ import { isServedRelease } from './release.js';
4
4
  /** Load one execution Runtime from the exact evidence retained by its admitted Build. */
5
5
  export function load(release) {
6
- if (!isRelease(release))
6
+ if (!isServedRelease(release)) {
7
7
  throw new TypeError('Runtime loading requires an admitted Release.');
8
+ }
8
9
  const evidence = evidenceOf(release.build);
9
10
  const domain = evidence.domain;
10
11
  const { registry } = evidence;
@@ -0,0 +1,22 @@
1
+ import type * as release from '@astrale-os/kernel-protocol/release';
2
+ import type { Build } from '../../deployment/build/build.js';
3
+ import type * as legacy from '../../deployment/release/legacy/index.js';
4
+ import type { Release } from '../../deployment/release/release.js';
5
+ import type { IssuerId } from '../../platform/auth/index.js';
6
+ /**
7
+ * What one Service serves: the `DomainRelease` v4 Release of an immutable deployment, or the
8
+ * deprecated v3 Release of a stable target (`legacy`, its consumers and removal in
9
+ * `deployment/release/legacy/index.ts`, D10).
10
+ */
11
+ export type ServedRelease<BuildValue extends Build = Build> = Release<BuildValue> | legacy.Release<BuildValue>;
12
+ /** Where and as whom one served Release answers, and the document it serves. */
13
+ export interface Serving {
14
+ /** Domain identity issuer: a deployment's URL, or a stable target's configured issuer. */
15
+ readonly issuer: IssuerId;
16
+ /** Public origin the Server answers at: a deployment's URL, or a stable target's route. */
17
+ readonly publicUrl: IssuerId;
18
+ /** The document served at `release.json`, or a stable target's v3 Publication at `domain.json`. */
19
+ readonly document: release.DomainRelease | release.legacy.Publication;
20
+ }
21
+ export declare function isServedRelease(input: unknown): input is ServedRelease;
22
+ export declare function serving(served: ServedRelease): Serving;
@@ -0,0 +1,14 @@
1
+ import { isRelease } from '../../deployment/release/admission.js';
2
+ import { isRelease as isLegacyRelease } from '../../deployment/release/legacy/admission.js';
3
+ export function isServedRelease(input) {
4
+ return isRelease(input) || isLegacyRelease(input);
5
+ }
6
+ export function serving(served) {
7
+ return served.kind === 'release'
8
+ ? Object.freeze({ issuer: served.url, publicUrl: served.url, document: served.document })
9
+ : Object.freeze({
10
+ issuer: served.addressing.issuer,
11
+ publicUrl: served.addressing.publicUrl,
12
+ document: served.publication,
13
+ });
14
+ }
@@ -1,5 +1,5 @@
1
1
  import type { ServerCloseOptions } from '@astrale-os/kernel-server';
2
- import type { publication } from '@astrale-os/kernel-server';
2
+ import type { release } from '@astrale-os/kernel-server';
3
3
  import type { Runtime } from '../application/runtime/index.js';
4
4
  import type { WorkflowRunner } from '../application/workflow/runner/index.js';
5
5
  import type { Identity } from './identity/index.js';
@@ -16,7 +16,7 @@ export interface ServeInput<Environment, RuntimeValue extends Runtime, RuntimeEn
16
16
  identity(environment: Environment): Identity;
17
17
  readonly initialize?: (environment: Environment) => RuntimeEnvironment;
18
18
  readonly server: ServiceServerOptions;
19
- readonly delivery?: (environment: Environment) => publication.delivery.Provider | undefined;
19
+ readonly delivery?: (environment: Environment) => release.delivery.Provider | undefined;
20
20
  readonly workflows?: WorkflowRunner;
21
21
  /**
22
22
  * Serve durable Workflows to the workflow engine; required when the Release declares any.
@@ -3,12 +3,12 @@ import { isRuntime } from '../../application/runtime/index.js';
3
3
  import { invocationPath } from '../../deployment/release/invocation.js';
4
4
  import { identity as captureIdentity } from '../identity/index.js';
5
5
  import { createHandler } from '../invocation/index.js';
6
- import { initialize, load } from '../runtime/index.js';
6
+ import { initialize, load, serving as servedRelease } from '../runtime/index.js';
7
7
  import { createDurableReceiver, durableServing, isDurableRequest, } from '../workflows/index.js';
8
8
  import { initialization } from './initialization.js';
9
9
  import { lifecycle } from './lifecycle.js';
10
- import { delivery, installation, source } from './publication/index.js';
11
10
  import { loadRelease } from './release.js';
11
+ import { delivery, installation, source } from './serving/index.js';
12
12
  /** Create one lazy running Service around the exact current Release. */
13
13
  export function createService(input) {
14
14
  if (input === null || typeof input !== 'object' || Array.isArray(input))
@@ -24,20 +24,21 @@ export function createService(input) {
24
24
  const state = lifecycle(() => running?.server.drain());
25
25
  const realized = initialization(async () => {
26
26
  const release = await loadRelease(input.load, input.environment, input.runtime);
27
- if (release.addressing.issuer !== selectedIdentity.issuer) {
27
+ const served = servedRelease(release);
28
+ if (served.issuer !== selectedIdentity.issuer) {
28
29
  throw new TypeError('Service Identity differs from Release Addressing.');
29
30
  }
30
31
  if (selectedIdentity.subject !== release.build.schema.compiled.root.origin) {
31
32
  throw new TypeError('Service Identity subject differs from the Release Domain origin.');
32
33
  }
33
- const selectedDelivery = providedDelivery ?? selectedIdentity.delivery(release.publication);
34
- installation(release, selectedDelivery);
34
+ const selectedDelivery = providedDelivery ?? selectedIdentity.delivery(served.document);
35
+ installation(served.document, selectedDelivery);
35
36
  const loaded = load(release);
36
37
  const runtime = await initialize(loaded, input.environment);
37
38
  const prepared = prepareServer({
38
39
  ...serverOptions(input.server),
39
40
  path: invocationPath(),
40
- publicOrigin: release.addressing.publicUrl,
41
+ publicOrigin: served.publicUrl,
41
42
  invocation: {
42
43
  source: selectedIdentity.issuer,
43
44
  next: () => crypto.randomUUID(),
@@ -46,7 +47,7 @@ export function createService(input) {
46
47
  ...(selectedIdentity.tokenExchange === undefined
47
48
  ? {}
48
49
  : { tokenExchange: selectedIdentity.tokenExchange }),
49
- publication: source(loaded),
50
+ ...source(loaded),
50
51
  ...(selectedDelivery === undefined ? {} : { delivery: selectedDelivery }),
51
52
  });
52
53
  const server = prepared.create(createHandler({
@@ -119,6 +120,7 @@ function serverOptions(input) {
119
120
  'issuer',
120
121
  'publicOrigin',
121
122
  'tokenExchange',
123
+ 'release',
122
124
  'publication',
123
125
  'delivery',
124
126
  'handler',