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

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 (175) hide show
  1. package/README.md +4 -0
  2. package/dist/deployment/adapter/adapter.d.ts +9 -11
  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 +12 -12
  7. package/dist/deployment/adapter/legacy/prepare/context.d.ts +0 -2
  8. package/dist/deployment/adapter/release/context.d.ts +23 -3
  9. package/dist/deployment/adapter/release/index.d.ts +1 -0
  10. package/dist/deployment/adapter/release/list.d.ts +41 -0
  11. package/dist/deployment/adapter/release/list.js +1 -0
  12. package/dist/deployment/address/index.d.ts +1 -1
  13. package/dist/deployment/address/index.js +1 -0
  14. package/dist/deployment/address/summary.d.ts +31 -1
  15. package/dist/deployment/address/summary.js +117 -1
  16. package/dist/deployment/build/index.d.ts +1 -1
  17. package/dist/deployment/build/index.js +1 -1
  18. package/dist/deployment/build/manifest.d.ts +5 -0
  19. package/dist/deployment/build/manifest.js +10 -0
  20. package/dist/deployment/index.d.ts +1 -1
  21. package/dist/deployment/release/legacy/index.d.ts +17 -12
  22. package/dist/deployment/release/legacy/index.js +17 -12
  23. package/dist/deployment/verify/readiness/deployment.js +3 -13
  24. package/dist/deployment/verify/readiness/fetch.d.ts +13 -0
  25. package/dist/deployment/verify/readiness/fetch.js +26 -0
  26. package/dist/deployment/verify/readiness/identity.d.ts +3 -6
  27. package/dist/deployment/verify/readiness/identity.js +3 -3
  28. package/dist/deployment/verify/readiness/index.d.ts +12 -8
  29. package/dist/deployment/verify/readiness/index.js +15 -4
  30. package/dist/deployment/verify/readiness/legacy/index.d.ts +2 -0
  31. package/dist/deployment/verify/readiness/legacy/index.js +2 -0
  32. package/dist/deployment/verify/readiness/legacy/publication.d.ts +12 -0
  33. package/dist/deployment/verify/readiness/legacy/publication.js +23 -0
  34. package/dist/deployment/verify/readiness/release.d.ts +8 -0
  35. package/dist/deployment/verify/readiness/release.js +22 -0
  36. package/dist/execution/identity/authentication.d.ts +14 -3
  37. package/dist/execution/identity/authentication.js +16 -7
  38. package/dist/execution/identity/callback.d.ts +5 -2
  39. package/dist/execution/identity/callback.js +11 -5
  40. package/dist/execution/identity/delivery.d.ts +11 -4
  41. package/dist/execution/identity/delivery.js +47 -20
  42. package/dist/execution/identity/identity.d.ts +12 -6
  43. package/dist/execution/identity/identity.js +3 -3
  44. package/dist/execution/invocation/admission/authentication.d.ts +1 -2
  45. package/dist/execution/invocation/admission/authentication.js +1 -2
  46. package/dist/execution/invocation/admission/authority.d.ts +10 -4
  47. package/dist/execution/invocation/admission/authority.js +5 -1
  48. package/dist/execution/invocation/invocation.js +51 -14
  49. package/dist/execution/runtime/index.d.ts +1 -0
  50. package/dist/execution/runtime/index.js +1 -0
  51. package/dist/execution/runtime/load.d.ts +3 -3
  52. package/dist/execution/runtime/load.js +3 -2
  53. package/dist/execution/runtime/release.d.ts +22 -0
  54. package/dist/execution/runtime/release.js +14 -0
  55. package/dist/execution/serve.d.ts +2 -2
  56. package/dist/execution/service/create.js +9 -7
  57. package/dist/execution/service/release.d.ts +2 -2
  58. package/dist/execution/service/release.js +3 -2
  59. package/dist/execution/service/service.d.ts +9 -5
  60. package/dist/execution/service/serving/delivery.d.ts +6 -0
  61. package/dist/execution/service/{publication → serving}/delivery.js +5 -1
  62. package/dist/execution/service/{publication → serving}/index.d.ts +1 -1
  63. package/dist/execution/service/serving/installation.d.ts +4 -0
  64. package/dist/execution/service/serving/installation.js +9 -0
  65. package/dist/execution/service/serving/legacy/index.d.ts +15 -0
  66. package/dist/execution/service/serving/legacy/index.js +19 -0
  67. package/dist/execution/service/serving/source.d.ts +18 -0
  68. package/dist/execution/service/serving/source.js +19 -0
  69. package/dist/execution/workflows/run.js +1 -1
  70. package/dist/platform/versioning/name.d.ts +4 -3
  71. package/dist/platform/versioning/name.js +4 -3
  72. package/dist/project/define.js +58 -28
  73. package/dist/project/install-command.d.ts +10 -0
  74. package/dist/project/install-command.js +13 -0
  75. package/dist/project/project.d.ts +4 -2
  76. package/dist/tooling/cli/arguments.d.ts +1 -3
  77. package/dist/tooling/cli/arguments.js +51 -22
  78. package/dist/tooling/cli/commit.d.ts +23 -0
  79. package/dist/tooling/cli/commit.js +216 -0
  80. package/dist/tooling/cli/deploy-mode.d.ts +16 -13
  81. package/dist/tooling/cli/deploy-mode.js +45 -36
  82. package/dist/tooling/cli/deploy-result.d.ts +10 -7
  83. package/dist/tooling/cli/deploy-result.js +4 -3
  84. package/dist/tooling/cli/dotenv.d.ts +2 -2
  85. package/dist/tooling/cli/dotenv.js +3 -33
  86. package/dist/tooling/cli/help.js +73 -29
  87. package/dist/tooling/cli/immutable-deployment.d.ts +27 -0
  88. package/dist/tooling/cli/immutable-deployment.js +95 -0
  89. package/dist/tooling/cli/index.d.ts +3 -4
  90. package/dist/tooling/cli/index.js +2 -3
  91. package/dist/tooling/cli/legacy/deploy-result.d.ts +5 -3
  92. package/dist/tooling/cli/legacy/deploy-result.js +5 -3
  93. package/dist/tooling/cli/{development → legacy/development}/candidate.d.ts +3 -4
  94. package/dist/tooling/cli/{development → legacy/development}/candidate.js +7 -14
  95. package/dist/tooling/cli/legacy/development/deployment.d.ts +10 -0
  96. package/dist/tooling/cli/legacy/development/deployment.js +20 -0
  97. package/dist/tooling/cli/legacy/development/deprecation.d.ts +11 -0
  98. package/dist/tooling/cli/legacy/development/deprecation.js +13 -0
  99. package/dist/tooling/cli/legacy/development/develop.d.ts +15 -0
  100. package/dist/tooling/cli/legacy/development/develop.js +142 -0
  101. package/dist/tooling/cli/legacy/development/index.d.ts +21 -0
  102. package/dist/tooling/cli/legacy/development/index.js +21 -0
  103. package/dist/tooling/cli/legacy/development/report.d.ts +7 -0
  104. package/dist/tooling/cli/{development → legacy/development}/report.js +2 -5
  105. package/dist/tooling/cli/legacy/development/secrets-file.d.ts +2 -0
  106. package/dist/tooling/cli/legacy/development/secrets-file.js +33 -0
  107. package/dist/tooling/cli/legacy/stable-target-adapter.d.ts +5 -3
  108. package/dist/tooling/cli/legacy/stable-target-deploy.d.ts +40 -0
  109. package/dist/tooling/cli/legacy/stable-target-deploy.js +102 -0
  110. package/dist/tooling/cli/list.d.ts +114 -0
  111. package/dist/tooling/cli/list.js +297 -0
  112. package/dist/tooling/cli/orchestrate.d.ts +1 -1
  113. package/dist/tooling/cli/orchestrate.js +91 -95
  114. package/dist/tooling/cli/secrets.d.ts +9 -0
  115. package/dist/tooling/cli/secrets.js +19 -0
  116. package/package.json +7 -7
  117. package/dist/deployment/verify/readiness/publication.d.ts +0 -11
  118. package/dist/deployment/verify/readiness/publication.js +0 -41
  119. package/dist/execution/service/publication/delivery.d.ts +0 -2
  120. package/dist/execution/service/publication/installation.d.ts +0 -3
  121. package/dist/execution/service/publication/installation.js +0 -8
  122. package/dist/execution/service/publication/source.d.ts +0 -3
  123. package/dist/execution/service/publication/source.js +0 -11
  124. package/dist/tooling/cli/astrale/authority.d.ts +0 -5
  125. package/dist/tooling/cli/astrale/authority.js +0 -11
  126. package/dist/tooling/cli/astrale/executable.d.ts +0 -2
  127. package/dist/tooling/cli/astrale/executable.js +0 -47
  128. package/dist/tooling/cli/astrale/failure.d.ts +0 -6
  129. package/dist/tooling/cli/astrale/failure.js +0 -48
  130. package/dist/tooling/cli/astrale/instance.d.ts +0 -11
  131. package/dist/tooling/cli/astrale/instance.js +0 -52
  132. package/dist/tooling/cli/astrale/process.d.ts +0 -13
  133. package/dist/tooling/cli/astrale/process.js +0 -94
  134. package/dist/tooling/cli/astrale/version.d.ts +0 -18
  135. package/dist/tooling/cli/astrale/version.js +0 -55
  136. package/dist/tooling/cli/development/deployment.d.ts +0 -16
  137. package/dist/tooling/cli/development/deployment.js +0 -39
  138. package/dist/tooling/cli/development/develop.d.ts +0 -11
  139. package/dist/tooling/cli/development/develop.js +0 -243
  140. package/dist/tooling/cli/development/release-evidence.d.ts +0 -4
  141. package/dist/tooling/cli/development/release-evidence.js +0 -10
  142. package/dist/tooling/cli/development/report.d.ts +0 -9
  143. package/dist/tooling/cli/development/session-file.d.ts +0 -53
  144. package/dist/tooling/cli/development/session-file.js +0 -337
  145. package/dist/tooling/cli/development/target-lock.d.ts +0 -16
  146. package/dist/tooling/cli/development/target-lock.js +0 -68
  147. package/dist/tooling/cli/development/view.d.ts +0 -28
  148. package/dist/tooling/cli/development/view.js +0 -151
  149. package/dist/tooling/cli/environment-release.d.ts +0 -24
  150. package/dist/tooling/cli/environment-release.js +0 -46
  151. package/dist/tooling/cli/evidence.d.ts +0 -14
  152. package/dist/tooling/cli/evidence.js +0 -53
  153. package/dist/tooling/cli/installation/index.d.ts +0 -2
  154. package/dist/tooling/cli/installation/index.js +0 -1
  155. package/dist/tooling/cli/installation/observation.d.ts +0 -10
  156. package/dist/tooling/cli/installation/observation.js +0 -44
  157. package/dist/tooling/cli/installation/reconcile.d.ts +0 -32
  158. package/dist/tooling/cli/installation/reconcile.js +0 -122
  159. /package/dist/execution/service/{publication → serving}/index.js +0 -0
  160. /package/dist/tooling/cli/{credential.d.ts → legacy/development/credential.d.ts} +0 -0
  161. /package/dist/tooling/cli/{credential.js → legacy/development/credential.js} +0 -0
  162. /package/dist/tooling/cli/{development → legacy/development}/lease.d.ts +0 -0
  163. /package/dist/tooling/cli/{development → legacy/development}/lease.js +0 -0
  164. /package/dist/tooling/cli/{development → legacy/development}/lifecycle.d.ts +0 -0
  165. /package/dist/tooling/cli/{development → legacy/development}/lifecycle.js +0 -0
  166. /package/dist/tooling/cli/{development → legacy/development}/project-imports.d.ts +0 -0
  167. /package/dist/tooling/cli/{development → legacy/development}/project-imports.js +0 -0
  168. /package/dist/tooling/cli/{development → legacy/development}/project-lock.d.ts +0 -0
  169. /package/dist/tooling/cli/{development → legacy/development}/project-lock.js +0 -0
  170. /package/dist/tooling/cli/{development → legacy/development}/rebuild.d.ts +0 -0
  171. /package/dist/tooling/cli/{development → legacy/development}/rebuild.js +0 -0
  172. /package/dist/tooling/cli/{development → legacy/development}/source-watch.d.ts +0 -0
  173. /package/dist/tooling/cli/{development → legacy/development}/source-watch.js +0 -0
  174. /package/dist/tooling/cli/{development → legacy/development}/sources.d.ts +0 -0
  175. /package/dist/tooling/cli/{development → legacy/development}/sources.js +0 -0
@@ -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',
@@ -1,7 +1,7 @@
1
1
  import type { Runtime } from '../../application/runtime/index.js';
2
2
  import type { Build } from '../../deployment/build/build.js';
3
- import type { Release } from '../../deployment/release/legacy/release.js';
4
3
  import type { schema } from '../../platform/schema/index.js';
5
- export type ReleaseForRuntime<RuntimeValue extends Runtime> = Release<Build<schema.DomainSchema, RuntimeValue>>;
4
+ import type { ServedRelease } from '../runtime/index.js';
5
+ export type ReleaseForRuntime<RuntimeValue extends Runtime> = ServedRelease<Build<schema.DomainSchema, RuntimeValue>>;
6
6
  export type ReleaseLoader<Environment, RuntimeValue extends Runtime = Runtime> = (environment: Environment) => ReleaseForRuntime<RuntimeValue> | Promise<ReleaseForRuntime<RuntimeValue>>;
7
7
  export declare function loadRelease<Environment, RuntimeValue extends Runtime>(load: ReleaseLoader<Environment, RuntimeValue>, environment: Environment, runtime: RuntimeValue): Promise<ReleaseForRuntime<RuntimeValue>>;
@@ -1,10 +1,11 @@
1
- import { isRelease } from '../../deployment/release/legacy/admission.js';
1
+ import { isServedRelease } from '../runtime/index.js';
2
2
  export async function loadRelease(load, environment, runtime) {
3
3
  if (typeof load !== 'function')
4
4
  throw new TypeError('Service Release loader is invalid.');
5
5
  const release = await load(environment);
6
- if (!isRelease(release))
6
+ if (!isServedRelease(release)) {
7
7
  throw new TypeError('Service loader returned an unadmitted Release.');
8
+ }
8
9
  if (release.build.runtime !== runtime) {
9
10
  throw new TypeError('Service Release Runtime differs from the generated entrypoint Runtime.');
10
11
  }
@@ -1,19 +1,23 @@
1
1
  import type { ApplicationHost, ServerCloseOptions, ServerOptions } 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
- import type { Release } from '../../deployment/release/legacy/index.js';
6
5
  import type { Identity } from '../identity/index.js';
6
+ import type { ServedRelease } from '../runtime/index.js';
7
7
  import type { DurableServing, DurableServingProvider } from '../workflows/index.js';
8
8
  import type { ReleaseLoader } from './release.js';
9
- export type ServiceServerOptions = Omit<ServerOptions, 'path' | 'invocation' | 'issuer' | 'publicOrigin' | 'tokenExchange' | 'publication' | 'delivery'>;
9
+ export type ServiceServerOptions = Omit<ServerOptions, 'path' | 'invocation' | 'issuer' | 'publicOrigin' | 'tokenExchange' | 'release' | 'publication' | 'delivery'>;
10
10
  export interface ServiceInput<Environment, RuntimeValue extends Runtime = Runtime> {
11
11
  readonly runtime: RuntimeValue;
12
12
  readonly environment: Environment;
13
13
  readonly load: ReleaseLoader<Environment, RuntimeValue>;
14
14
  readonly identity: Identity;
15
15
  readonly server: ServiceServerOptions;
16
- readonly delivery?: publication.delivery.Provider;
16
+ /**
17
+ * Answers Delivery in the request's version: v2 over an immutable deployment's release, v1 over
18
+ * the Publication (a release's frozen v3 projection). Defaults to the Identity's own.
19
+ */
20
+ readonly delivery?: release.delivery.Provider;
17
21
  readonly workflows?: WorkflowRunner;
18
22
  /**
19
23
  * Serve the Release's durable Workflows. A provider is resolved on the first engine request,
@@ -23,7 +27,7 @@ export interface ServiceInput<Environment, RuntimeValue extends Runtime = Runtim
23
27
  }
24
28
  export interface Service {
25
29
  fetch(request: Request, host?: ApplicationHost): Promise<Response>;
26
- release(): Promise<Release>;
30
+ release(): Promise<ServedRelease>;
27
31
  drain(): void;
28
32
  close(options: ServerCloseOptions): Promise<void>;
29
33
  }
@@ -0,0 +1,6 @@
1
+ import type { release } from '@astrale-os/kernel-server';
2
+ /**
3
+ * Capture an explicit Delivery Provider. It answers in the request's version: v2 over an immutable
4
+ * deployment's release, v1 over the Publication (a release's frozen v3 projection).
5
+ */
6
+ export declare function delivery(input: release.delivery.Provider | undefined): release.delivery.Provider | undefined;
@@ -1,8 +1,12 @@
1
+ /**
2
+ * Capture an explicit Delivery Provider. It answers in the request's version: v2 over an immutable
3
+ * deployment's release, v1 over the Publication (a release's frozen v3 projection).
4
+ */
1
5
  export function delivery(input) {
2
6
  if (input === undefined)
3
7
  return undefined;
4
8
  if (input === null || typeof input !== 'object' || typeof input.create !== 'function') {
5
- throw new TypeError('Publication delivery Provider is invalid.');
9
+ throw new TypeError('Delivery Provider is invalid.');
6
10
  }
7
11
  const create = input.create.bind(input);
8
12
  return Object.freeze({ create });
@@ -1,3 +1,3 @@
1
1
  export { delivery } from './delivery.js';
2
2
  export { installation } from './installation.js';
3
- export { source } from './source.js';
3
+ export { source, type ServingSource } from './source.js';
@@ -0,0 +1,4 @@
1
+ import type { release } from '@astrale-os/kernel-server';
2
+ import type { Serving } from '../../runtime/index.js';
3
+ /** A served document advertises Delivery exactly when the Service has a Provider for it. */
4
+ export declare function installation(served: Serving['document'], provider: release.delivery.Provider | undefined): void;
@@ -0,0 +1,9 @@
1
+ /** A served document advertises Delivery exactly when the Service has a Provider for it. */
2
+ export function installation(served, provider) {
3
+ const advertised = served.delivery !== undefined;
4
+ if (advertised !== (provider !== undefined)) {
5
+ throw new TypeError(advertised
6
+ ? 'Release advertises delivery without a Provider.'
7
+ : 'Delivery Provider has no Release endpoint.');
8
+ }
9
+ }
@@ -0,0 +1,15 @@
1
+ import type { PublicationSource } from '@astrale-os/kernel-server';
2
+ import type * as legacy from '../../../../deployment/release/legacy/index.js';
3
+ import type { LoadedRuntime } from '../../../runtime/index.js';
4
+ /**
5
+ * Serve a stable target's v3 Publication through the Kernel Server's v3-input source: `domain.json`
6
+ * only (404 at `release.json`), with the same-schema continuity of a stable Worker.
7
+ *
8
+ * @deprecated Replacement: the release source of `../source.ts`, which serves an immutable
9
+ * deployment's `DomainRelease` v4. Consumer: the stable Worker of the direct-mode path (the
10
+ * consumers of `deployment/release/legacy/index.ts`), whose host binds no build digest. Removal:
11
+ * D10, with `deployment/release/legacy/` and Kernel Server's `publication` source.
12
+ */
13
+ export declare function publicationSource(runtime: LoadedRuntime, served: legacy.Release): {
14
+ readonly publication: PublicationSource;
15
+ };
@@ -0,0 +1,19 @@
1
+ import { preparePublicationSnapshot } from '@astrale-os/kernel-server';
2
+ /**
3
+ * Serve a stable target's v3 Publication through the Kernel Server's v3-input source: `domain.json`
4
+ * only (404 at `release.json`), with the same-schema continuity of a stable Worker.
5
+ *
6
+ * @deprecated Replacement: the release source of `../source.ts`, which serves an immutable
7
+ * deployment's `DomainRelease` v4. Consumer: the stable Worker of the direct-mode path (the
8
+ * consumers of `deployment/release/legacy/index.ts`), whose host binds no build digest. Removal:
9
+ * D10, with `deployment/release/legacy/` and Kernel Server's `publication` source.
10
+ */
11
+ export function publicationSource(runtime, served) {
12
+ const snapshot = preparePublicationSnapshot({
13
+ publication: served.publication,
14
+ bundle: served.build.schema.bundle.bytes(),
15
+ table: served.routes,
16
+ domain: runtime.domain,
17
+ });
18
+ return Object.freeze({ publication: Object.freeze({ current: () => snapshot }) });
19
+ }
@@ -0,0 +1,18 @@
1
+ import type { PublicationSource, ReleaseSource } from '@astrale-os/kernel-server';
2
+ import type { LoadedRuntime } from '../../runtime/index.js';
3
+ /** The one source a Kernel Server serves, as `ServerOptions` takes it. */
4
+ export type ServingSource =
5
+ /** The release of an immutable deployment: `release.json` and its v3 projection. */
6
+ {
7
+ readonly release: ReleaseSource;
8
+ }
9
+ /** @deprecated A stable target's v3 Publication; see `legacy/index.ts`. */
10
+ | {
11
+ readonly publication: PublicationSource;
12
+ };
13
+ /**
14
+ * Prepare, once, the exact snapshot the loaded Release serves: an immutable deployment serves its
15
+ * `DomainRelease` through `prepareReleaseSnapshot`, which admits only routing naming that exact
16
+ * release or its exact v3 projection; a stable target keeps serving its v3 Publication.
17
+ */
18
+ export declare function source(runtime: LoadedRuntime): ServingSource;
@@ -0,0 +1,19 @@
1
+ import { prepareReleaseSnapshot } from '@astrale-os/kernel-server';
2
+ import { publicationSource } from './legacy/index.js';
3
+ /**
4
+ * Prepare, once, the exact snapshot the loaded Release serves: an immutable deployment serves its
5
+ * `DomainRelease` through `prepareReleaseSnapshot`, which admits only routing naming that exact
6
+ * release or its exact v3 projection; a stable target keeps serving its v3 Publication.
7
+ */
8
+ export function source(runtime) {
9
+ const served = runtime.release;
10
+ if (served.kind !== 'release')
11
+ return publicationSource(runtime, served);
12
+ const snapshot = prepareReleaseSnapshot({
13
+ release: served.document,
14
+ bundle: served.build.schema.bundle.bytes(),
15
+ table: served.routes,
16
+ domain: runtime.domain,
17
+ });
18
+ return Object.freeze({ release: Object.freeze({ current: () => snapshot }) });
19
+ }
@@ -84,7 +84,7 @@ function durableContext(input, context, envelope) {
84
84
  /** One journaled unit of work acting as the Domain, with keys derived from its name. */
85
85
  const journal = (name, execute) => Promise.resolve(context.run(name, async () => {
86
86
  const deadline = Date.now() + serving.stepTimeoutMs;
87
- const session = input.executor(execution.kernel, { deadline, signal });
87
+ const session = input.executor(execution.kernel, execution.id, { deadline, signal });
88
88
  try {
89
89
  const kernel = keyed(bindSessionOf(session, deadline, signal), await keySequence(execution.id, name));
90
90
  const output = await execute(Object.freeze({
@@ -15,12 +15,13 @@ import type { Digest } from '@astrale-os/kernel-protocol/artifact';
15
15
  * hexadecimal digits names a plain preview, and the commit token is always printed in lower case,
16
16
  * like `git describe`. An environment outside the `defineProject` grammar is rendered as `?`, so no
17
17
  * record can put control characters or a ` · ` of its own in the name. Likewise only canonical
18
- * published versions name a deployment.
18
+ * published versions name a deployment. A deployment named without its digests (one whose record
19
+ * is not admitted) is never named by a published version.
19
20
  */
20
21
  export declare function deploymentName(deployment: {
21
22
  readonly environment: string;
22
- readonly releaseDigest: Digest;
23
- readonly buildDigest: Digest;
23
+ readonly releaseDigest?: Digest;
24
+ readonly buildDigest?: Digest;
24
25
  readonly commit: {
25
26
  readonly sha: string;
26
27
  readonly dirty: boolean;
@@ -21,17 +21,18 @@ const UNKNOWN_ENVIRONMENT = '?';
21
21
  * hexadecimal digits names a plain preview, and the commit token is always printed in lower case,
22
22
  * like `git describe`. An environment outside the `defineProject` grammar is rendered as `?`, so no
23
23
  * record can put control characters or a ` · ` of its own in the name. Likewise only canonical
24
- * published versions name a deployment.
24
+ * published versions name a deployment. A deployment named without its digests (one whose record
25
+ * is not admitted) is never named by a published version.
25
26
  */
26
27
  export function deploymentName(deployment, publications) {
27
28
  const { commit } = deployment;
28
29
  const environment = typeof deployment.environment === 'string' && ENVIRONMENT_NAME.test(deployment.environment)
29
30
  ? deployment.environment
30
31
  : UNKNOWN_ENVIRONMENT;
31
- const release = highest(publications.filter(({ releaseDigest }) => releaseDigest === deployment.releaseDigest));
32
+ const release = highest(publications.filter(({ releaseDigest }) => deployment.releaseDigest !== undefined && releaseDigest === deployment.releaseDigest));
32
33
  if (release !== undefined)
33
34
  return release;
34
- const build = highest(publications.filter(({ buildDigest }) => buildDigest === deployment.buildDigest));
35
+ const build = highest(publications.filter(({ buildDigest }) => deployment.buildDigest !== undefined && buildDigest === deployment.buildDigest));
35
36
  if (build !== undefined)
36
37
  return `${build} · ${environment}`;
37
38
  if (commit === null || typeof commit.sha !== 'string' || !SHA.test(commit.sha)) {
@@ -2,7 +2,12 @@ import { isDomainDefinition } from '../application/index.js';
2
2
  import { isDeployment } from '../deployment/deployment.js';
3
3
  import { ENVIRONMENT_NAME } from '../deployment/environment.js';
4
4
  import { isTests } from '../testing/index.js';
5
+ import { installCommand } from './install-command.js';
5
6
  const admittedProjects = new WeakSet();
7
+ /** The adapter name of adapter-astrale, whose removed instance mode once read `installation`. */
8
+ const ASTRALE_ADAPTER = 'astrale';
9
+ /** The one Environment adapter-astrale deploys without an explicit organisation (AM-7). */
10
+ const ASTRALE_DEFAULT_ORGANIZATION_ENVIRONMENT = 'development';
6
11
  /** Capture one inert Project definition without loading entrypoints or performing effects. */
7
12
  export function defineProject(input) {
8
13
  const value = record(input, 'Project definition');
@@ -19,27 +24,28 @@ export function defineProject(input) {
19
24
  const names = Object.keys(environments);
20
25
  if (names.length === 0)
21
26
  throw new TypeError('Project must declare at least one Environment.');
22
- const captured = Object.create(null);
23
- for (const name of names) {
27
+ const declared = names.map((name) => {
24
28
  if (!ENVIRONMENT_NAME.test(name)) {
25
29
  throw new TypeError(`Project Environment name "${name}" is not normalized.`);
26
30
  }
27
- const environment = record(environments[name], `Project Environment ${name}`);
28
- exact(environment, ['deployment'], ['installation'], () => invalidEnvironment(name));
31
+ return [name, record(environments[name], `Project Environment ${name}`)];
32
+ });
33
+ // One refusal names every Environment that declares installation, each with its own commands.
34
+ const installations = declared
35
+ .filter(([, environment]) => Object.hasOwn(environment, 'installation'))
36
+ .map(([name, environment]) => installationRefusal(environment, name));
37
+ if (installations.length > 0)
38
+ throw new TypeError(installations.join('\n'));
39
+ const captured = Object.create(null);
40
+ for (const [name, environment] of declared) {
41
+ exact(environment, ['deployment'], [], () => invalidEnvironment(name));
29
42
  if (!isDeployment(environment.deployment)) {
30
43
  throw new TypeError(`Project Environment ${name} deployment is not admitted.`);
31
44
  }
32
- const installation = environment.installation === undefined
33
- ? undefined
34
- : admitInstallation(environment.installation, name);
35
45
  environment.deployment.adapter.admit?.(environment.deployment.parameters, {
36
46
  environment: name,
37
- ...(installation === undefined ? {} : { installation }),
38
- });
39
- captured[name] = Object.freeze({
40
- deployment: environment.deployment,
41
- ...(installation === undefined ? {} : { installation }),
42
47
  });
48
+ captured[name] = Object.freeze({ deployment: environment.deployment });
43
49
  }
44
50
  const entrypoints = input.entrypoints === undefined ? undefined : admitEntrypoints(input.entrypoints);
45
51
  if (input.tests !== undefined && !isTests(input.tests)) {
@@ -71,22 +77,46 @@ function admitEntrypoints(input) {
71
77
  }
72
78
  return Object.freeze({ runtime: input.runtime });
73
79
  }
74
- function admitInstallation(input, environment) {
75
- const value = record(input, `Project Environment ${environment} installation`);
76
- exact(value, ['instance'], ['identity'], () => {
77
- throw new TypeError(`Project Environment ${environment} installation may contain only instance and identity.`);
78
- });
79
- const instance = stableCoordinate(value.instance, 'installation instance');
80
- const identity = value.identity === undefined
81
- ? undefined
82
- : stableCoordinate(value.identity, 'installation identity');
83
- return Object.freeze({ instance, ...(identity === undefined ? {} : { identity }) });
84
- }
85
- function stableCoordinate(input, label) {
86
- if (typeof input !== 'string' || input.length === 0 || input.trim() !== input) {
87
- throw new TypeError(`Project ${label} must be a non-empty stable string.`);
80
+ /**
81
+ * A deploy no longer installs (DX [.81399], AM-72): an Environment that still declares
82
+ * `installation` is refused before any effect, with the commands that replace it. Its only
83
+ * consumer pins an SDK older than this refusal.
84
+ *
85
+ * adapter-astrale deploys on Admin's Services, never through the installation's instance: outside
86
+ * development its Environment also names the organisation that holds its deployment line (AM-7),
87
+ * which the guidance adds when the adapter names none. The installation's instance and identity
88
+ * move to the install command.
89
+ */
90
+ function installationRefusal(environment, name) {
91
+ const declared = environment.installation;
92
+ if (declared === undefined) {
93
+ return (`Project Environment ${name} declares \`installation\`, which a deploy no longer reads: a ` +
94
+ 'deploy never installs. Remove the key.');
88
95
  }
89
- return input;
96
+ const installation = declared !== null && typeof declared === 'object'
97
+ ? declared
98
+ : {};
99
+ const instance = stable(installation.instance);
100
+ const identity = stable(installation.identity);
101
+ const deployment = environment.deployment;
102
+ const organization = isDeployment(deployment) &&
103
+ deployment.adapter.name === ASTRALE_ADAPTER &&
104
+ name !== ASTRALE_DEFAULT_ORGANIZATION_ENVIRONMENT &&
105
+ deployment.parameters.organization === undefined
106
+ ? ", name the organisation that holds its deployment line in `astrale({ organization: '<Identity id>' })`"
107
+ : '';
108
+ return (`Project Environment ${name} declares installation, and a deploy no longer installs. ` +
109
+ `Remove \`installation\`${organization}, run \`astrale-domain deploy ${name}\`, ` +
110
+ `then install the URL it prints with \`${installCommand(instance, identity)}\`.`);
111
+ }
112
+ /** A declared coordinate worth repeating in guidance: a non-empty single-line trimmed string. */
113
+ function stable(input) {
114
+ return typeof input === 'string' &&
115
+ input.length > 0 &&
116
+ input.trim() === input &&
117
+ !/[\s`]/u.test(input)
118
+ ? input
119
+ : undefined;
90
120
  }
91
121
  function record(input, label) {
92
122
  if (input === null || typeof input !== 'object' || Array.isArray(input)) {
@@ -105,5 +135,5 @@ function invalid() {
105
135
  throw new TypeError('Project definition may contain only domain, environments, entrypoints, and tests.');
106
136
  }
107
137
  function invalidEnvironment(name) {
108
- throw new TypeError(`Project Environment ${name} may contain only deployment and installation.`);
138
+ throw new TypeError(`Project Environment ${name} may contain only deployment.`);
109
139
  }