@astrale-os/sdk 0.5.0-beta.143 → 0.5.0-beta.144

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.
package/README.md CHANGED
@@ -46,6 +46,31 @@ Stop development watchers first, then run the project's checks and validate on d
46
46
  Nothing is committed or deployed. A Shell update also requires checking the installed Shell revision.
47
47
  Rerunning an upgrade synchronizes installation even when the manifest versions are already current.
48
48
 
49
+ ## Move a runtime without changing its Domain identity
50
+
51
+ A Domain issuer is retained across installation upgrades. To deploy a new Cloudflare runtime for
52
+ selected instances, keep the existing signing identity and issuer while selecting a new public origin:
53
+
54
+ ```ts
55
+ cloudflare({
56
+ route: 'services-v2.example.com',
57
+ workerName: 'services-v2',
58
+ identityIssuer: 'https://services.example.com',
59
+ signingIdentity: '.astrale/identity.json',
60
+ })
61
+ ```
62
+
63
+ The new Publication places its Bundle, Delivery, callables, Views and routes at the new origin.
64
+ Install that public URL on each intended instance. The Kernel verifies its Delivery against the
65
+ retained issuer's keys and preserves the Domain installation identity and owned data. Keep the
66
+ original issuer discovery endpoints and keys available; unadopted instances continue to use their
67
+ previous bindings. Deployment readiness checks the exact new Worker version separately from issuer
68
+ discovery. No uninstall or identity rotation is involved.
69
+
70
+ At the provider-neutral release boundary, use
71
+ `addressing('https://services.example.com', { publicUrl: 'https://services-v2.example.com' })`.
72
+ The one-argument form continues to use the issuer as the public URL.
73
+
49
74
  ## Handler authority and dependencies
50
75
 
51
76
  Authenticated handlers use Domain self authority for `kernel`, `graph`, `query`, and `mutate`.
@@ -1,7 +1,11 @@
1
1
  import type { IssuerId } from '../../platform/auth/index.js';
2
- /** Intended serving identity, independent of how a provider obtains it. */
2
+ /** Stable Domain identity and public placement, independent of how a provider obtains them. */
3
3
  export interface Addressing {
4
4
  readonly issuer: IssuerId;
5
+ /** Public origin serving this Release; the issuer can remain on an older deployment. */
6
+ readonly publicUrl: IssuerId;
5
7
  }
6
- export declare function addressing(input: string): Addressing;
8
+ export declare function addressing(input: string, options?: {
9
+ readonly publicUrl?: string;
10
+ }): Addressing;
7
11
  export declare function isAddressing(input: unknown): input is Addressing;
@@ -1,6 +1,13 @@
1
1
  import { issuer } from '../../platform/auth/index.js';
2
2
  const admittedAddressing = new WeakSet();
3
- export function addressing(input) {
3
+ export function addressing(input, options = {}) {
4
+ const admitted = origin(input);
5
+ const publicUrl = options.publicUrl === undefined ? admitted : origin(options.publicUrl);
6
+ const value = Object.freeze({ issuer: admitted, publicUrl });
7
+ admittedAddressing.add(value);
8
+ return value;
9
+ }
10
+ function origin(input) {
4
11
  let admitted;
5
12
  let url;
6
13
  try {
@@ -18,9 +25,7 @@ export function addressing(input) {
18
25
  url.hash !== '') {
19
26
  throw new TypeError('Addressing issuer must be an origin-only absolute HTTP(S) issuer.');
20
27
  }
21
- const value = Object.freeze({ issuer: admitted });
22
- admittedAddressing.add(value);
23
- return value;
28
+ return admitted;
24
29
  }
25
30
  export function isAddressing(input) {
26
31
  return input !== null && typeof input === 'object' && admittedAddressing.has(input);
@@ -2,7 +2,7 @@ import * as publication from '@astrale-os/kernel-protocol/publication';
2
2
  import { invocationPath } from '../invocation.js';
3
3
  export function callables(build, addressing) {
4
4
  const endpoint = publication.acceptInvocationEndpoints({
5
- http: new URL(invocationPath(), addressing.issuer).href,
5
+ http: new URL(invocationPath(), addressing.publicUrl).href,
6
6
  });
7
7
  return Object.freeze(build.callables.map((callable) => Object.freeze({ callable, endpoint })));
8
8
  }
@@ -1,4 +1,4 @@
1
1
  import * as protocolRoutes from '@astrale-os/kernel-protocol/routes';
2
2
  export function routes(build, addressing) {
3
- return protocolRoutes.place(build.routes, addressing.issuer);
3
+ return protocolRoutes.place(build.routes, addressing.publicUrl);
4
4
  }
@@ -18,7 +18,7 @@ export function seal(build, addressing) {
18
18
  schema: {
19
19
  revision: root.revision,
20
20
  bundle: {
21
- href: publication.bundleUrl(addressing.issuer, build.schema.bundle.ref),
21
+ href: publication.bundleUrl(addressing.publicUrl, build.schema.bundle.ref),
22
22
  ref: build.schema.bundle.ref,
23
23
  },
24
24
  },
@@ -28,12 +28,12 @@ export function seal(build, addressing) {
28
28
  callables: callables(build, addressing),
29
29
  views: views(build, addressing),
30
30
  },
31
- delivery: publication.placeDelivery({ path: DELIVERY_PATH, authentication: { kind: 'public' } }, addressing.issuer, publication.bundleUrl(addressing.issuer, build.schema.bundle.ref)),
31
+ delivery: publication.placeDelivery({ path: DELIVERY_PATH, authentication: { kind: 'public' } }, addressing.publicUrl, publication.bundleUrl(addressing.publicUrl, build.schema.bundle.ref)),
32
32
  routes: routes(build, addressing),
33
33
  });
34
34
  const { domain } = evidenceOf(build);
35
35
  return Object.freeze({
36
36
  publication: sealed,
37
- routes: protocolRoutes.bind(build.routes, sealed, domain),
37
+ routes: protocolRoutes.bind(build.routes, sealed, domain, addressing.publicUrl),
38
38
  });
39
39
  }
@@ -3,7 +3,7 @@ export function views(build, addressing) {
3
3
  return Object.freeze([]);
4
4
  const base = build.frontend.source.kind === 'external'
5
5
  ? `${build.frontend.source.origin}/`
6
- : `${addressing.issuer.replace(/\/+$/u, '')}/`;
6
+ : `${addressing.publicUrl.replace(/\/+$/u, '')}/`;
7
7
  return Object.freeze(build.frontend.routes.map((route) => Object.freeze({
8
8
  view: route.view,
9
9
  href: new URL(route.path.replace(/^\//u, ''), base).href,
@@ -89,7 +89,7 @@ function evidenceBytes(build, source) {
89
89
  bundle: build.schema.bundle.ref.digest,
90
90
  entrypoint: source.entrypoint,
91
91
  addressing: source.addressing.kind === 'configured'
92
- ? { kind: 'configured', issuer: source.addressing.addressing.issuer }
92
+ ? { kind: 'configured', ...source.addressing.addressing }
93
93
  : source.addressing,
94
94
  })),
95
95
  ];
@@ -50,7 +50,8 @@ function verifyRelease(artifact, release) {
50
50
  throw new TypeError('DeployResult Release differs from the PreparedArtifact Build.');
51
51
  }
52
52
  if (artifact.addressing.kind === 'configured' &&
53
- release.addressing.issuer !== artifact.addressing.addressing.issuer) {
53
+ (release.addressing.issuer !== artifact.addressing.addressing.issuer ||
54
+ release.addressing.publicUrl !== artifact.addressing.addressing.publicUrl)) {
54
55
  throw new TypeError('DeployResult Release differs from configured Addressing.');
55
56
  }
56
57
  return release;
@@ -4,7 +4,7 @@ const MAXIMUM_BUNDLE_BYTES = 16 * 1024 * 1024;
4
4
  /** Fetch and verify the exact live Publication and Bundle for one Release. */
5
5
  export async function verifyPublication(release, options = {}) {
6
6
  const fetcher = options.fetch ?? globalThis.fetch;
7
- const publicationUrl = publication.url(release.addressing.issuer);
7
+ const publicationUrl = publication.url(release.addressing.publicUrl);
8
8
  const response = await fetchRequired(fetcher, publicationUrl, options.signal);
9
9
  const deployed = publication.accept(JSON.parse(await text(response, publicationUrl, MAXIMUM_PUBLICATION_BYTES)));
10
10
  if (!publication.matchesReference(deployed, publication.reference(release.publication))) {
@@ -33,6 +33,7 @@ export function createService(input) {
33
33
  const prepared = prepareServer({
34
34
  ...serverOptions(input.server),
35
35
  path: invocationPath(),
36
+ publicOrigin: release.addressing.publicUrl,
36
37
  invocation: {
37
38
  source: selectedIdentity.issuer,
38
39
  next: () => crypto.randomUUID(),
@@ -92,6 +93,7 @@ function serverOptions(input) {
92
93
  'path',
93
94
  'invocation',
94
95
  'issuer',
96
+ 'publicOrigin',
95
97
  'tokenExchange',
96
98
  'publication',
97
99
  'delivery',
@@ -5,7 +5,7 @@ import type { WorkflowRunner } from '../../application/workflow/runner/index.js'
5
5
  import type { Release } from '../../deployment/release/index.js';
6
6
  import type { Identity } from '../identity/index.js';
7
7
  import type { ReleaseLoader } from './release.js';
8
- export type ServiceServerOptions = Omit<ServerOptions, 'path' | 'invocation' | 'issuer' | 'tokenExchange' | 'publication' | 'delivery'>;
8
+ export type ServiceServerOptions = Omit<ServerOptions, 'path' | 'invocation' | 'issuer' | 'publicOrigin' | 'tokenExchange' | 'publication' | 'delivery'>;
9
9
  export interface ServiceInput<Environment, RuntimeValue extends Runtime = Runtime> {
10
10
  readonly runtime: RuntimeValue;
11
11
  readonly environment: Environment;
@@ -6,7 +6,7 @@ export function reportDevelopmentDeployment(deployed, installation, adapter, inp
6
6
  if (deployed.progress.provider.evidence.preflight !== undefined) {
7
7
  info(`Preflight: ${deployed.progress.provider.evidence.preflight}; public readiness verified`);
8
8
  }
9
- info(`Public: ${deployed.release.addressing.issuer}`);
9
+ info(`Public: ${deployed.release.addressing.publicUrl}`);
10
10
  info(`Publication: ${deployed.release.publication.schema.revision} · ${deployed.release.publication.etag}`);
11
11
  info(installation === undefined
12
12
  ? `Installation: skipped${input.deployOnly ? ' (--deploy-only)' : ''}`
@@ -17,6 +17,7 @@ export async function writeDeploymentEvidence(input) {
17
17
  id: provider.deployment,
18
18
  artifact: provider.artifact,
19
19
  issuer: input.deployment.release.addressing.issuer,
20
+ publicUrl: input.deployment.release.addressing.publicUrl,
20
21
  origin: input.deployment.release.publication.origin,
21
22
  revision: input.deployment.release.publication.schema.revision,
22
23
  etag: input.deployment.release.publication.etag,
@@ -35,7 +35,7 @@ export async function reconcileInstallation(input, dependencies = {
35
35
  '--no-prompt',
36
36
  'domain',
37
37
  'install',
38
- issuer,
38
+ input.release.addressing.publicUrl,
39
39
  '--direct',
40
40
  '--allow-identity-override',
41
41
  '-i',
@@ -113,7 +113,7 @@ export async function run(argv) {
113
113
  if (result.progress.provider.evidence.preflight !== undefined) {
114
114
  info(`Preflight: ${result.progress.provider.evidence.preflight}; public readiness verified`);
115
115
  }
116
- info(`Public: ${result.release.addressing.issuer}`);
116
+ info(`Public: ${result.release.addressing.publicUrl}`);
117
117
  info(`Publication: ${result.release.publication.schema.revision} · ${result.release.publication.etag}`);
118
118
  const installed = await reconcileEnvironmentRelease({
119
119
  projectDir,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/sdk",
3
- "version": "0.5.0-beta.143",
3
+ "version": "0.5.0-beta.144",
4
4
  "description": "Schema-first SDK for defining, composing, and deploying Astrale domains",
5
5
  "keywords": [
6
6
  "astrale",
@@ -237,11 +237,11 @@
237
237
  "registry": "https://registry.npmjs.org/"
238
238
  },
239
239
  "dependencies": {
240
- "@astrale-os/kernel-client": "0.6.0-beta.62",
241
- "@astrale-os/kernel-core": "0.9.0-beta.47",
242
- "@astrale-os/kernel-dsl": "0.2.0-beta.33",
243
- "@astrale-os/kernel-protocol": "0.5.0-beta.53",
244
- "@astrale-os/kernel-server": "0.5.0-beta.55",
240
+ "@astrale-os/kernel-client": "0.6.0-beta.64",
241
+ "@astrale-os/kernel-core": "0.9.0-beta.49",
242
+ "@astrale-os/kernel-dsl": "0.2.0-beta.34",
243
+ "@astrale-os/kernel-protocol": "0.5.0-beta.55",
244
+ "@astrale-os/kernel-server": "0.5.0-beta.57",
245
245
  "@lucide/icons": "1.34.0",
246
246
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
247
247
  "cross-spawn": "7.0.6",