@astrale-os/adapter-cloudflare 0.1.3 → 0.1.5

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.
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Pack a built client SPA (`dist-client/`) into the host box's asset-archive
3
+ * format: `gzip(JSON [{ path, contentBase64 }])` — the exact shape
4
+ * `downloadAssets` on the box consumes (kernel/host workerd service layout).
5
+ */
6
+ /** Gzip the SPA dir into the box's asset archive. Returns null when empty. */
7
+ export declare function packAssets(distClientDir: string): Buffer | null;
8
+ //# sourceMappingURL=assets-pack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets-pack.d.ts","sourceRoot":"","sources":["../src/assets-pack.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqBH,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK/D"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Pack a built client SPA (`dist-client/`) into the host box's asset-archive
3
+ * format: `gzip(JSON [{ path, contentBase64 }])` — the exact shape
4
+ * `downloadAssets` on the box consumes (kernel/host workerd service layout).
5
+ */
6
+ import { readdirSync, readFileSync, statSync } from 'node:fs';
7
+ import { join, relative } from 'node:path';
8
+ import { gzipSync } from 'node:zlib';
9
+ function walk(dir, root, out) {
10
+ for (const name of readdirSync(dir)) {
11
+ const full = join(dir, name);
12
+ if (statSync(full).isDirectory())
13
+ walk(full, root, out);
14
+ else {
15
+ out.push({
16
+ path: relative(root, full).split('\\').join('/'),
17
+ contentBase64: readFileSync(full).toString('base64'),
18
+ });
19
+ }
20
+ }
21
+ }
22
+ /** Gzip the SPA dir into the box's asset archive. Returns null when empty. */
23
+ export function packAssets(distClientDir) {
24
+ const files = [];
25
+ walk(distClientDir, distClientDir, files);
26
+ if (files.length === 0)
27
+ return null;
28
+ return gzipSync(Buffer.from(JSON.stringify(files)));
29
+ }
30
+ //# sourceMappingURL=assets-pack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets-pack.js","sourceRoot":"","sources":["../src/assets-pack.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAIpC,SAAS,IAAI,CAAC,GAAW,EAAE,IAAY,EAAE,GAAgB;IACvD,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QAC5B,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE;YAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAA;aAClD,CAAC;YACJ,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;gBAChD,aAAa,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;aACrD,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,UAAU,CAAC,aAAqB;IAC9C,MAAM,KAAK,GAAgB,EAAE,CAAA;IAC7B,IAAI,CAAC,aAAa,EAAE,aAAa,EAAE,KAAK,CAAC,CAAA;IACzC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACnC,OAAO,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AACrD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"astrale.d.ts","sourceRoot":"","sources":["../src/astrale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAQvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAU7C,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,aAAa,CAAC,aAAa,CAAC,CA2FzF"}
1
+ {"version":3,"file":"astrale.d.ts","sourceRoot":"","sources":["../src/astrale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAQvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAY7C,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,aAAa,CAAC,aAAa,CAAC,CAsHzF"}
package/dist/astrale.js CHANGED
@@ -21,11 +21,13 @@
21
21
  * serve no `/ui` yet) and no runtime secrets reach the service — the bundle
22
22
  * must be self-contained (its signing identity is baked in by the codegen).
23
23
  */
24
- import { defineAdapter } from '@astrale-os/devkit';
24
+ import { defineAdapter, loadDotenvFile } from '@astrale-os/devkit';
25
25
  import { spawn } from 'node:child_process';
26
26
  import { existsSync } from 'node:fs';
27
27
  import { readFile } from 'node:fs/promises';
28
28
  import { join } from 'node:path';
29
+ import { packAssets } from './assets-pack';
30
+ import { buildClient } from './client';
29
31
  import { logTo, prepare } from './cloudflare';
30
32
  import { runWranglerBundle, runWranglerDev } from './wrangler-cli';
31
33
  const DEFAULT_PORT = 8787;
@@ -52,9 +54,18 @@ export function astrale(envs) {
52
54
  },
53
55
  async deploy(params, ctx) {
54
56
  const log = logTo();
57
+ if (!params.instance) {
58
+ throw new Error(`astrale adapter: this env has no "instance" — managed deploys need the target ` +
59
+ `instance slug (e.g. prod: { instance: '<your-instance-slug>' }).`);
60
+ }
61
+ // Build + pack the client SPA: managed services serve it under /ui (the
62
+ // platform stages the archive and the box downloads it at Service.init).
63
+ let assetsGz = null;
55
64
  if (ctx.clientDir) {
56
- log(`client/ detected — managed deploys do not ship SPA assets yet; ` +
57
- `/ui will not serve on the managed service (functions/methods are unaffected).`);
65
+ await buildClient(ctx.clientDir, ctx.projectDir, log);
66
+ assetsGz = packAssets(join(ctx.projectDir, 'dist-client'));
67
+ if (assetsGz)
68
+ log(`packed client SPA (${assetsGz.length} bytes gz) — /ui ships managed`);
58
69
  }
59
70
  // 1. Codegen + bundle: the exact worker module a Cloudflare deploy would
60
71
  // ship, produced locally with `wrangler deploy --dry-run` (no auth).
@@ -85,13 +96,31 @@ export function astrale(envs) {
85
96
  log(`publishing ${name}@${version} (${bundle.length} bytes)…`);
86
97
  await astraleCall(ctx.projectDir, params, adminUrl, {
87
98
  path: `/admin/domains/${name}::release`,
88
- data: { version, bundleBase64: bundle.toString('base64'), makeCurrent: true },
99
+ data: {
100
+ version,
101
+ bundleBase64: bundle.toString('base64'),
102
+ makeCurrent: true,
103
+ ...(assetsGz ? { assetsGzBase64: assetsGz.toString('base64') } : {}),
104
+ },
89
105
  viaStdin: true,
90
106
  });
107
+ // Author runtime secrets: read the env's dotenv locally, ship the map on
108
+ // the INSTALL call (never the release — secrets are per instance, never
109
+ // catalog-resident). Rides stdin so values never appear in argv.
110
+ let secrets;
111
+ if (params.secrets) {
112
+ secrets = loadDotenvFile(join(ctx.projectDir, params.secrets));
113
+ log(`shipping ${Object.keys(secrets).length} secret(s) from ${params.secrets}…`);
114
+ }
91
115
  log(`installing on instance "${params.instance}"…`);
92
116
  const installed = (await astraleCall(ctx.projectDir, params, adminUrl, {
93
117
  path: `/admin/domains/${name}::install`,
94
- data: { instanceId: params.instance, source: { kind: 'package' } },
118
+ data: {
119
+ instanceId: params.instance,
120
+ source: { kind: 'package' },
121
+ ...(secrets ? { secrets } : {}),
122
+ },
123
+ viaStdin: true,
95
124
  }));
96
125
  if (installed.error || installed.state !== 'installed') {
97
126
  throw new Error(`managed install failed: state=${installed.state ?? '?'} error=${installed.error ?? '?'}`);
@@ -1 +1 @@
1
- {"version":3,"file":"astrale.js","sourceRoot":"","sources":["../src/astrale.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"astrale.js","sourceRoot":"","sources":["../src/astrale.ts"],"names":[],"mappings":"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"}
package/dist/params.d.ts CHANGED
@@ -49,8 +49,12 @@ export interface CloudflareParams {
49
49
  }
50
50
  /** Params for the Astrale-managed adapter (`astrale(envs)`). */
51
51
  export interface AstraleParams {
52
- /** Target instance slug the domain installs onto (e.g. `'bryan-e2e5'`). */
53
- instance: string;
52
+ /**
53
+ * Target instance slug the domain installs onto (e.g. `'bryan-e2e5'`).
54
+ * Required for `deploy` (managed publish + install); ignored by `watch`
55
+ * (local dev) — so dev-only envs may omit it.
56
+ */
57
+ instance?: string;
54
58
  /** Catalog package name. Default: the origin's first DNS label. */
55
59
  name?: string;
56
60
  /** Admin kernel URL the publish calls target. Default the platform admin. */
@@ -59,7 +63,7 @@ export interface AstraleParams {
59
63
  region?: string;
60
64
  /** CLI identity (`--as`) for the publish calls. Default: the CLI's active identity. */
61
65
  identity?: string;
62
- /** Gitignored secrets file injected ONLY into local `watch` (managed services receive no secrets yet). */
66
+ /** Gitignored secrets file. `watch`: injected into local wrangler dev. `deploy`: shipped on the install call and applied to the managed service env (encrypted at rest platform-side; platform keys win precedence). */
63
67
  secrets?: string;
64
68
  /** Local dev port for `wrangler dev`. Default 8787. */
65
69
  port?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../src/params.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAED,gEAAgE;AAChE,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAA;IAChB,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4GAA4G;IAC5G,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC9B"}
1
+ {"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../src/params.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAED,gEAAgE;AAChE,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wNAAwN;IACxN,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC9B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/adapter-cloudflare",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Deploy an Astrale domain as a standalone Cloudflare Worker",
5
5
  "keywords": [
6
6
  "adapter",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "jose": "^6.1.3",
31
- "@astrale-os/devkit": "^0.1.2"
31
+ "@astrale-os/devkit": "^0.1.4"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@astrale-os/ox": ">=0.1.0 <1.0.0",
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Pack a built client SPA (`dist-client/`) into the host box's asset-archive
3
+ * format: `gzip(JSON [{ path, contentBase64 }])` — the exact shape
4
+ * `downloadAssets` on the box consumes (kernel/host workerd service layout).
5
+ */
6
+
7
+ import { readdirSync, readFileSync, statSync } from 'node:fs'
8
+ import { join, relative } from 'node:path'
9
+ import { gzipSync } from 'node:zlib'
10
+
11
+ type AssetFile = { path: string; contentBase64: string }
12
+
13
+ function walk(dir: string, root: string, out: AssetFile[]): void {
14
+ for (const name of readdirSync(dir)) {
15
+ const full = join(dir, name)
16
+ if (statSync(full).isDirectory()) walk(full, root, out)
17
+ else {
18
+ out.push({
19
+ path: relative(root, full).split('\\').join('/'),
20
+ contentBase64: readFileSync(full).toString('base64'),
21
+ })
22
+ }
23
+ }
24
+ }
25
+
26
+ /** Gzip the SPA dir into the box's asset archive. Returns null when empty. */
27
+ export function packAssets(distClientDir: string): Buffer | null {
28
+ const files: AssetFile[] = []
29
+ walk(distClientDir, distClientDir, files)
30
+ if (files.length === 0) return null
31
+ return gzipSync(Buffer.from(JSON.stringify(files)))
32
+ }
package/src/astrale.ts CHANGED
@@ -24,7 +24,7 @@
24
24
 
25
25
  import type { DomainAdapter } from '@astrale-os/devkit'
26
26
 
27
- import { defineAdapter } from '@astrale-os/devkit'
27
+ import { defineAdapter, loadDotenvFile } from '@astrale-os/devkit'
28
28
  import { spawn } from 'node:child_process'
29
29
  import { existsSync } from 'node:fs'
30
30
  import { readFile } from 'node:fs/promises'
@@ -32,6 +32,8 @@ import { join } from 'node:path'
32
32
 
33
33
  import type { AstraleParams } from './params'
34
34
 
35
+ import { packAssets } from './assets-pack'
36
+ import { buildClient } from './client'
35
37
  import { logTo, prepare } from './cloudflare'
36
38
  import { runWranglerBundle, runWranglerDev } from './wrangler-cli'
37
39
 
@@ -66,12 +68,20 @@ export function astrale(envs: Record<string, AstraleParams>): DomainAdapter<Astr
66
68
 
67
69
  async deploy(params, ctx) {
68
70
  const log = logTo()
69
- if (ctx.clientDir) {
70
- log(
71
- `client/ detected — managed deploys do not ship SPA assets yet; ` +
72
- `/ui will not serve on the managed service (functions/methods are unaffected).`,
71
+ if (!params.instance) {
72
+ throw new Error(
73
+ `astrale adapter: this env has no "instance" — managed deploys need the target ` +
74
+ `instance slug (e.g. prod: { instance: '<your-instance-slug>' }).`,
73
75
  )
74
76
  }
77
+ // Build + pack the client SPA: managed services serve it under /ui (the
78
+ // platform stages the archive and the box downloads it at Service.init).
79
+ let assetsGz: Buffer | null = null
80
+ if (ctx.clientDir) {
81
+ await buildClient(ctx.clientDir, ctx.projectDir, log)
82
+ assetsGz = packAssets(join(ctx.projectDir, 'dist-client'))
83
+ if (assetsGz) log(`packed client SPA (${assetsGz.length} bytes gz) — /ui ships managed`)
84
+ }
75
85
 
76
86
  // 1. Codegen + bundle: the exact worker module a Cloudflare deploy would
77
87
  // ship, produced locally with `wrangler deploy --dry-run` (no auth).
@@ -105,14 +115,33 @@ export function astrale(envs: Record<string, AstraleParams>): DomainAdapter<Astr
105
115
  log(`publishing ${name}@${version} (${bundle.length} bytes)…`)
106
116
  await astraleCall(ctx.projectDir, params, adminUrl, {
107
117
  path: `/admin/domains/${name}::release`,
108
- data: { version, bundleBase64: bundle.toString('base64'), makeCurrent: true },
118
+ data: {
119
+ version,
120
+ bundleBase64: bundle.toString('base64'),
121
+ makeCurrent: true,
122
+ ...(assetsGz ? { assetsGzBase64: assetsGz.toString('base64') } : {}),
123
+ },
109
124
  viaStdin: true,
110
125
  })
111
126
 
127
+ // Author runtime secrets: read the env's dotenv locally, ship the map on
128
+ // the INSTALL call (never the release — secrets are per instance, never
129
+ // catalog-resident). Rides stdin so values never appear in argv.
130
+ let secrets: Record<string, string> | undefined
131
+ if (params.secrets) {
132
+ secrets = loadDotenvFile(join(ctx.projectDir, params.secrets))
133
+ log(`shipping ${Object.keys(secrets).length} secret(s) from ${params.secrets}…`)
134
+ }
135
+
112
136
  log(`installing on instance "${params.instance}"…`)
113
137
  const installed = (await astraleCall(ctx.projectDir, params, adminUrl, {
114
138
  path: `/admin/domains/${name}::install`,
115
- data: { instanceId: params.instance, source: { kind: 'package' } },
139
+ data: {
140
+ instanceId: params.instance,
141
+ source: { kind: 'package' },
142
+ ...(secrets ? { secrets } : {}),
143
+ },
144
+ viaStdin: true,
116
145
  })) as { serviceSlug?: string; state?: string; error?: string | null }
117
146
 
118
147
  if (installed.error || installed.state !== 'installed') {
package/src/params.ts CHANGED
@@ -50,8 +50,12 @@ export interface CloudflareParams {
50
50
 
51
51
  /** Params for the Astrale-managed adapter (`astrale(envs)`). */
52
52
  export interface AstraleParams {
53
- /** Target instance slug the domain installs onto (e.g. `'bryan-e2e5'`). */
54
- instance: string
53
+ /**
54
+ * Target instance slug the domain installs onto (e.g. `'bryan-e2e5'`).
55
+ * Required for `deploy` (managed publish + install); ignored by `watch`
56
+ * (local dev) — so dev-only envs may omit it.
57
+ */
58
+ instance?: string
55
59
  /** Catalog package name. Default: the origin's first DNS label. */
56
60
  name?: string
57
61
  /** Admin kernel URL the publish calls target. Default the platform admin. */
@@ -60,7 +64,7 @@ export interface AstraleParams {
60
64
  region?: string
61
65
  /** CLI identity (`--as`) for the publish calls. Default: the CLI's active identity. */
62
66
  identity?: string
63
- /** Gitignored secrets file injected ONLY into local `watch` (managed services receive no secrets yet). */
67
+ /** Gitignored secrets file. `watch`: injected into local wrangler dev. `deploy`: shipped on the install call and applied to the managed service env (encrypted at rest platform-side; platform keys win precedence). */
64
68
  secrets?: string
65
69
  /** Local dev port for `wrangler dev`. Default 8787. */
66
70
  port?: number
@@ -0,0 +1,321 @@
1
+ ---
2
+ name: Astrale Domain
3
+ description: Develop, deploy, and iterate an Astrale domain end-to-end — schema modeling (classes, interfaces, edges, methods), handler implementation, calling the kernel and other domains from handlers, integrating external APIs (the core use case — DI, secrets, idempotency, sagas), views, testing, and the deploy/install loop with the cloudflare or astrale adapter. Use whenever creating a domain, adding classes/methods/views, structuring external API calls, or debugging install/dispatch/permission errors. Pairs with the astrale-cli skill (CLI ops) — together they cover working an Astrale instance autonomously.
4
+ ---
5
+
6
+ # Astrale Domain — the authoring bible
7
+
8
+ An Astrale **domain** is a typed contract installed into a kernel's graph plus a
9
+ **worker you own** that executes it. The kernel stores the schema (classes,
10
+ edges, function contracts), enforces permissions, and routes calls; every
11
+ method body runs on YOUR worker (Cloudflare worker or Astrale-managed service).
12
+ The graph is the database AND the bus: domains read/write nodes+edges through
13
+ the kernel and call each other's functions through it.
14
+
15
+ **Mental model:** schema = what exists and what's callable · graph = state ·
16
+ worker = behavior · kernel = router + authorizer. You never run a database or
17
+ an RPC layer; you declare a contract and implement handlers.
18
+
19
+ ## 0 · Start
20
+
21
+ ```bash
22
+ npx -y create-astrale-domain@latest my-domain --yes # scaffold
23
+ cd my-domain && pnpm install
24
+ pnpm dev # local wrangler dev (prints a URL; install it on an instance to test)
25
+ pnpm dev --port 8899 # when 8787 is taken (orphan wrangler etc.)
26
+ pnpm prod # deploy + (astrale adapter) auto-install on your instance
27
+ ```
28
+
29
+ Project anatomy (the scaffold is the reference — read its comments):
30
+
31
+ ```
32
+ astrale.config.ts # THE manifest: schema + postInstall + adapter (where it ships)
33
+ schema/ # classes/interfaces/edges — the contract (zod props, fn signatures)
34
+ methods/ # handler logic (transport-agnostic fns) + thin wiring (index.ts)
35
+ services/ # RECOMMENDED: ports + factories for external APIs (see §4)
36
+ functions/ # standalone remote functions (webhook-shaped endpoints)
37
+ views/ # iframe-mountable UI declarations (defineView)
38
+ client/ # the SPA served under /ui (vite)
39
+ env.ts # typed worker env — config + secrets arrive here, as ctx.deps
40
+ ```
41
+
42
+ Iteration loop: edit → `pnpm prod` → call it. Managed redeploys keep the same
43
+ service URL and reinstall the contract; schema changes are merge/reconcile
44
+ (removed entries can leave old nodes behind — see the astrale-live-domain-edit
45
+ skill for graph-level cleanup).
46
+
47
+ ## 1 · Schema modeling
48
+
49
+ ```ts
50
+ import { KernelSchema, defineSchema, edgeClass, nodeClass, nodeInterface } from '@astrale-os/kernel-core'
51
+ import { fn } from '@astrale-os/kernel-dsl'
52
+ import { z } from 'zod'
53
+
54
+ export const ContactOps = nodeInterface({ // interface = shared contract
55
+ methods: { createContact: fn({ static: true, params: {...}, returns: ... }) },
56
+ })
57
+ export const Contact = nodeClass({
58
+ implements: [ContactOps, KernelSchema.interfaces.Container], // Container → can hold children
59
+ props: { email: z.string(), company: z.string().optional() },
60
+ methods: { assign: fn({ params: { project: z.string(), role: z.string() }, returns: ... }) },
61
+ })
62
+ export const works_on = edgeClass( // edges are CLASSES with PROPS
63
+ { as: 'contact', types: [Contact] },
64
+ { as: 'project', types: [Project] },
65
+ { props: { role: z.string() } },
66
+ )
67
+ export const schema = defineSchema('my-domain.example.dev', {
68
+ interfaces: { ContactOps },
69
+ classes: { Contact, Project, works_on }, // EDGE classes register under `classes` too
70
+ imports: [KernelSchema],
71
+ })
72
+ ```
73
+
74
+ Conventions and rules:
75
+ - Naming: classes/interfaces `PascalCase`, methods `camelCase`, **edges `snake_case`**.
76
+ - `static: true` = called on the class (`/origin/class.X/method`); otherwise
77
+ instance-dispatched (`/path/to/node::method`, handler gets `self`). Statics
78
+ work on classes AND interfaces, wired through the same `method()` /
79
+ `classMethods()` helpers (the scaffold's `seed` is a class-hosted static).
80
+ - Model relations as **edges with props** (not foreign-key strings): create via
81
+ `::link {edgeClass, target, props}`, walk via `::getLinks`. Prefer FLAT nodes
82
+ + edges for peer resources; use Folders (Container) only for list-able
83
+ hierarchies (`::listChildren` works on Folders).
84
+ - Props are zod; they land in the graph under QUALIFIED keys
85
+ (`origin:class.X.property.y`). Never hand-write key strings — derive them
86
+ from the compiled schema: `D.Contact.email.key`, `K.Named.name.key`.
87
+ - Known sharp edges: `::update` currently drops `z.enum()` props silently
88
+ (create is fine — track status as plain string if you must update it); edge
89
+ prop accessors exist at runtime but not in types yet (cast).
90
+
91
+ ## 2 · Handlers
92
+
93
+ Separate LOGIC from WIRING. Logic = plain async functions taking the kernel
94
+ client + ports + params (testable with fakes). Wiring = `method()` /
95
+ `classMethods()` / `interfaceMethods()` in `methods/index.ts`:
96
+
97
+ ```ts
98
+ const kickoff = method(schema, 'Project', 'kickoff', {
99
+ authorize: async () => undefined, // see §6 for real authorization
100
+ execute: ({ kernel, self, params, deps }) => {
101
+ if (!kernel) throw new Error('kickoff requires a kernel credential')
102
+ return kickoffLogic(kernel, createWeatherClient(deps), self.path.raw, params)
103
+ },
104
+ })
105
+ ```
106
+
107
+ Handler context: `kernel` (callback client bound to the composed credential —
108
+ caller's delegated authority ∪ this function's own), `self` (instance methods),
109
+ `params` (zod-validated), `deps` (your typed `Env`), `auth` (principal,
110
+ verified claims). Construct external clients from `deps` per request — NEVER
111
+ at module load (workers must be import-side-effect-free).
112
+
113
+ ## 3 · Talking to the kernel (and other domains)
114
+
115
+ Everything is `kernel.call(path, params)`. Addressing forms:
116
+
117
+ | Form | Example | Use |
118
+ |---|---|---|
119
+ | tree path + `::method` | `/projects/apollo::get` | instance dispatch on a node |
120
+ | static slash form | `/origin/class.X/method` | static class/interface methods |
121
+ | colon MethodPath | `/:origin:class.X:method` | canonical form; REQUIRED in postInstall |
122
+ | `@<uuid>::method` | `@4548…::get` | by graph id (NOT slugs/paths) |
123
+
124
+ Core ops from handlers (all proven patterns):
125
+
126
+ ```ts
127
+ await kernel.call(K.Node.createNode.path.method.raw, { class: D.Contact.path.class.raw, path, props })
128
+ await kernel.call(`${path}::update`, { props: { [D.Project.title.key]: 'New' } })
129
+ // Edge props use QUALIFIED keys; the edge-prop TYPE accessor is missing today — use this cast:
130
+ const ROLE_KEY = (D.works_on as unknown as { role: { key: string } }).role.key
131
+ await kernel.call(`${path}::link`, { edgeClass: D.works_on.path.class.raw, target, props: { [ROLE_KEY]: role } })
132
+ const links = await kernel.call(`${path}::getLinks`, {}) // filter by edge class
133
+ await kernel.call('/other.domain/class.Echo/echo', { message }) // ANOTHER domain's function
134
+ ```
135
+
136
+ - **Cross-function calls work** (same- or cross-domain): the kernel redirects
137
+ to the target worker and your worker mints a next-hop delegation as ITSELF —
138
+ the receiver sees your function as the caller, with the original caller's
139
+ authority threaded through the grant chain. Design service-to-service flows
140
+ on this; no direct HTTP between workers.
141
+ - Upsert idiom: try `createNode`, on path-conflict fall back to `::update`.
142
+ - A missing parent yields `Permission denied: EDIT on /<parent>` — read that
143
+ error as "does the parent exist?" first. Seed required folders in postInstall.
144
+
145
+ ## 4 · External APIs — the core pattern
146
+
147
+ Almost every real domain wraps an external API (payment, calendar, LLM
148
+ gateway, cloud provider). The shape (see admin/domain for the full-scale
149
+ example — Scaleway/WorkOS/KV):
150
+
151
+ 1. **Port** — a narrow interface declaring only what the logic needs
152
+ (`WeatherClient { forecast(city) }`). Logic depends on the port, never on
153
+ fetch/SDKs/env.
154
+ 2. **Factory** — `createXClient(env)` in `services/`: reads config + secrets
155
+ from `env`, validates LOUDLY (`if (!env.X_API_KEY) throw`), sets base URLs
156
+ (overridable so tests point at a stub), timeouts (`AbortSignal.timeout`),
157
+ and maps upstream failures to meaningful errors with the upstream detail in
158
+ `cause` (the kernel threads cause chains to callers).
159
+ 3. **Wiring** — the `execute` hook builds the client from `deps` per request
160
+ and passes it to the logic.
161
+
162
+ Secrets & config:
163
+ - Declare every var as a typed field on `Env` in `env.ts`. Secrets ship via
164
+ the adapter's `secrets: '.env.dev' / '.env.prod'` (cloudflare adapter) —
165
+ never committed, never defaulted. Fail fast for root-of-trust values; allow
166
+ multi-name fallbacks only for developer convenience, never silently in prod.
167
+ - Both adapters ship secrets from `secrets: '.env.<env>'` — cloudflare via
168
+ wrangler secrets, astrale (managed) via the encrypted per-install store.
169
+
170
+ Reliability rules (learned from the admin provisioning engine):
171
+ - **Order effects**: external call FIRST, graph write AFTER when possible — a
172
+ failed upstream then leaves nothing to clean up. When you must write first
173
+ (reservations), write an INTENT record (state: 'provisioning'), make the
174
+ external call idempotent (tags/external ids so re-entry ADOPTS instead of
175
+ duplicating), and compensate on failure.
176
+ - **Sagas for multi-step flows**: ordered phases; record state transitions on
177
+ nodes (`provisioning → ready | failed`); compensation runs best-effort in
178
+ reverse and NEVER throws (each step returns ok/skipped/error). Document
179
+ which phases are safe to re-enter.
180
+ - **Idempotency before mutation**: check existing state before writing; design
181
+ re-runs of any handler to converge, not duplicate (postInstall seeds
182
+ especially — they re-run on every reinstall).
183
+
184
+ Anti-patterns (all observed in production code — don't):
185
+ - constructing clients at module load, or monkey-patching `globalThis.fetch`;
186
+ - scattering kernel-error message matching — the kernel exposes no stable
187
+ error codes to handlers yet, so when you must match (the PATH_CONFLICT
188
+ upsert), isolate it in ONE helper (the scaffold's `isPathConflict`) and
189
+ treat it as tech debt;
190
+ - god persistence files — split graph CRUD by entity;
191
+ - leaving state fields mid-transition with no failure path (`'installing'`
192
+ forever after a crash);
193
+ - stringly-typed prop keys or class paths (always compiled accessors).
194
+
195
+ ## 5 · Views & standalone functions (webhooks)
196
+
197
+ - `defineView({ auth, mount: '/ui/contact', viewFor: selfOf(Contact) })` in
198
+ `views/` + register in `views/index.ts` — the MAP KEY is the view's node
199
+ slug (`'ui-contact'` → `/<origin>/core/views/ui-contact`). Installs a View
200
+ node whose binding URL = `<serving url><mount>` (managed:
201
+ `https://<slug>.svc.<region>.astrale.ai/ui/contact`). The client/ SPA
202
+ serves `/ui/*` — BOTH adapters ship it (cloudflare via Workers Assets;
203
+ managed via the platform's per-version asset archive); the SPA must handle
204
+ any `/ui/<route>` via its fallback (the scaffold's vite config does).
205
+ - Discovery: clients/GUIs find a node's views via
206
+ `kernel.call('/kernel.astrale.ai/class.View/resolve', { node: <path> })` →
207
+ `[{ path, url, name, origin }]` — `url` is the mounted iframe target.
208
+ - `functions/` declares standalone callables (`defineRemoteFunction`) not
209
+ attached to a class — each serves at `POST <worker>/functions/<slug>` and
210
+ materializes a Function node under `/<origin>/core/functions/`. This is the
211
+ INBOUND integration surface (webhooks).
212
+
213
+ **The webhook-that-writes pattern** (validated): keep `auth: 'required'` and
214
+ configure the external system's auth header with a minted delegation token —
215
+ `astrale token --audience <service url> --ttl <seconds> --raw` (use a
216
+ dedicated, attenuated identity: grant it only what the webhook needs).
217
+ For `auth: 'public'` upstreams that can't carry a header (HMAC-signature
218
+ webhooks, Stripe-style): `kernel` is null, but `ctx.selfKernel()` gives a
219
+ session authenticated as THE FUNCTION'S OWN identity (its grants only) —
220
+ VERIFY THE UPSTREAM SIGNATURE FIRST, then act as yourself. Needs
221
+ `deps.INSTANCE_KERNEL_URL` (managed deploys set it) and the function identity
222
+ granted exactly what it writes (e.g. EDIT on the target folder + USE on
223
+ createNode + USE on the class — narrow, never root).
224
+
225
+ **Webhook idempotency** (senders retry — design for replays): derive a
226
+ DETERMINISTIC node path from the sender's id (`/contacts/lead-<externalId>`),
227
+ and make that key BOTH the existence check AND the write target. The classic
228
+ bug is checking one key and writing another (random-suffixed) — the replay
229
+ then duplicates. Custom `binding` supports REST-ish routes + header/body
230
+ capture when the sender's shape is fixed (see distribution's proxy functions).
231
+
232
+ ## 6 · Identity, auth, permissions
233
+
234
+ - Your worker IS an identity: at install, every callable gets `(iss = serving
235
+ URL, sub = function path)` stamped in the graph; the kernel verifies your
236
+ worker's signatures against your live JWKS. `astrale.config.ts` origin =
237
+ `schema.domain` (aliasing another origin triggers a DANGER prompt).
238
+ - Inbound calls carry a delegation of the caller; your handler's `kernel` acts
239
+ with `union(caller's delegated authority, your function's own grants)` —
240
+ attenuation is automatic (you can't exceed what the caller + you hold).
241
+ - `authorize` hook: return `undefined` to allow (relying on kernel-level
242
+ checks downstream), or assert claims/perms before `execute` runs.
243
+ - Permissions are bitmasks (READ/EDIT/USE/SHARE) on `has_perm` edges; grants
244
+ on a node cascade down the tree. Function identities get USE on
245
+ `mintDelegationCredential` at install (enables cross-function calls).
246
+
247
+ ## 7 · Deploy & install
248
+
249
+ Adapter choice in `astrale.config.ts`:
250
+ - `cloudflare({...})` — your CF account; `dev` (wrangler dev), `prod` (route or
251
+ workers.dev); ships secrets + SPA assets; extra bindings via a deep-merged
252
+ `wrangler` block.
253
+ - `astrale({ dev: {...}, prod: { instance: '<slug>' } })` — managed: publishes
254
+ the bundle THROUGH the platform and installs it as a host-local service next
255
+ to your instance (`https://<name>-<hash>.svc.<region>.astrale.ai`). No CF
256
+ account; auth = your `astrale auth login` session. Ships the client SPA
257
+ (`/ui` serves managed) and author secrets (`prod.secrets: '.env.prod'` —
258
+ encrypted at rest platform-side, re-applied on redeploys; omit = keep,
259
+ `{}` = clear; platform keys always win).
260
+
261
+ The first deploy generates `.astrale/identity.ts` — the domain's SIGNING
262
+ IDENTITY (its private key). Losing or regenerating it breaks reinstalls under
263
+ the same origin; back it up (or commit it knowingly for throwaway domains).
264
+
265
+ Dev-loop reality: `pnpm dev` serves on localhost — a REMOTE instance's kernel
266
+ cannot fetch its install bundle. Local URL installs only work against a kernel
267
+ that can reach you (local kernel, or a tunnel). Against a managed/remote
268
+ instance, iterate with `pnpm prod` (the managed loop is ~25s and keeps the
269
+ service URL stable).
270
+
271
+ `postInstall` runs after every install — MUST be a colon MethodPath
272
+ (`/:origin:class.X:seed`; tree paths are rejected) and MUST be idempotent
273
+ (catch path-conflicts). Seed folders, defaults, and demo data here.
274
+
275
+ Manual install of any served domain: `astrale instance install <url>`.
276
+
277
+ The managed catalog surface (what `pnpm prod` shells into) is callable
278
+ directly — useful for recovery and inspection:
279
+ `/admin/domains/<name>::install {instanceId, source:{kind:'package'}}` ·
280
+ `::uninstall {instanceId}` (the un-wedge recipe before a retry) ·
281
+ `::installations` · `::versions` — all on the admin instance (`-i admin`).
282
+
283
+ ## 8 · Testing
284
+
285
+ - **Logic**: unit-test with fake ports (the DI in §4 exists for this) and a
286
+ fake kernel — an in-memory `{ call(path, params) }` that records calls /
287
+ returns canned nodes. Assert call ORDER and failure paths (best-effort
288
+ flows: one failing step must not block the rest).
289
+ - **Wiring/contract**: typecheck is the contract test (`pnpm typecheck` /
290
+ `tsgo --noEmit`); the schema drives param validation at runtime.
291
+ - **Live smoke** (always finish with this): deploy, then drive the REAL surface
292
+ with the CLI — create a node, call an instance method, walk an edge, call a
293
+ cross-domain function. Fixture-green alone proves nothing about dispatch,
294
+ identity, or bindings.
295
+
296
+ ## 9 · Debugging quick table
297
+
298
+ | Symptom | Likely cause |
299
+ |---|---|
300
+ | `Permission denied: EDIT on /x (param-target)` | `/x` doesn't exist — seed the parent |
301
+ | `method "x" not found … call it as "/:o:class.C/x"` | instance form used for a static method |
302
+ | `Delegation mint failed for <url>` | check `--debug` cause chain; worker→worker call machinery |
303
+ | postInstall `not within origin` | tree path used — switch to `/:origin:class.X:method` |
304
+ | install: `missing remote binding` | a callable lacks `binding.remoteUrl` — build via the adapter, not hand-rolled specs |
305
+ | `ERR_PNPM_IGNORED_BUILDS` / approve-builds on `pnpm run` | template's pnpm-workspace.yaml needs `ignoredBuiltDependencies` + `verifyDepsBeforeRun: false` (recent scaffolds have it) |
306
+ | stale/broken package versions on scaffold | clear pnpm metadata cache; check template floors are current |
307
+ | TS: "Types of property '__brand' are incompatible" in untouched files | TWO copies of kernel-core/dsl in the tree (mixed link:/registry/override resolution) — unify versions, then `pnpm dedupe` |
308
+ | runtime 500: `MISSING_DEF: Def at path "…" is not registered` | SAME dual-copy disease at runtime (defineSchema wrote copy A, compile read copy B) — and on managed installs it presents as the service never turning ready / install stuck `installing`. Unify + dedupe. |
309
+ | managed install stuck at `installing` | check the SERVICE first: `curl <svc>/meta` (500 = the bundle itself is broken — run it locally with wrangler to see the real error); then `…::uninstall {instanceId}` and re-run the install |
310
+ | `Path not found: /admin/instances/<uuid>` on install | `instanceId` takes the instance SLUG, not the node UUID (`astrale instance status <slug>` shows both) |
311
+ | deploy: `Export named 'X' not found` from an @astrale-os module | a transitive dep resolved below its REAL floor — `pnpm add @astrale-os/<pkg>@<needed>` then `pnpm dedupe` |
312
+
313
+ Use `astrale call <path> --describe` for any callable's schema, `--debug` for
314
+ the full error chain, and `curl <worker>/meta` for what a worker serves
315
+ (domainName, schemaHash).
316
+
317
+ ## Related skills
318
+ - **astrale-cli** — every CLI command (auth, instances, calls, install).
319
+ - **astrale-live-domain-edit** — graph-level schema surgery on a live kernel
320
+ (no worker changes): temp specs, reinstall semantics, minimum class/method
321
+ graph material.
@@ -1,7 +1,16 @@
1
1
  # astrale-domain
2
2
 
3
+
3
4
  A standalone [Astrale](https://astrale.ai) domain, deployed as a Cloudflare Worker.
4
5
 
6
+ ## For AI agents
7
+
8
+ The complete domain-authoring guide ships with this project at
9
+ `.agents/skills/astrale-domain/SKILL.md` — schema modeling, handlers, kernel
10
+ calls, external-API patterns (DI, secrets, idempotency), views, webhooks,
11
+ deploys. Load it before making changes. For CLI operations (auth, instances,
12
+ calls), use the `astrale-cli` skill.
13
+
5
14
  > **Requires [Bun](https://bun.sh)** — the `astrale-domain` CLI behind `pnpm dev`
6
15
  > / `pnpm prod` imports `astrale.config.ts` and your ★ files directly, so it
7
16
  > needs a TypeScript-native runtime.
@@ -14,11 +14,11 @@
14
14
  "typecheck": "tsgo --noEmit"
15
15
  },
16
16
  "dependencies": {
17
- "@astrale-os/adapter-cloudflare": ">=0.1.0 <1.0.0",
18
- "@astrale-os/devkit": ">=0.1.0 <1.0.0",
19
- "@astrale-os/kernel-core": ">=0.3.0 <1.0.0",
20
- "@astrale-os/kernel-dsl": ">=0.1.0 <1.0.0",
21
- "@astrale-os/sdk": ">=0.1.0 <1.0.0",
17
+ "@astrale-os/adapter-cloudflare": ">=0.1.4 <1.0.0",
18
+ "@astrale-os/devkit": ">=0.1.3 <1.0.0",
19
+ "@astrale-os/kernel-core": ">=0.4.3 <1.0.0",
20
+ "@astrale-os/kernel-dsl": ">=0.1.2 <1.0.0",
21
+ "@astrale-os/sdk": ">=0.1.3 <1.0.0",
22
22
  "@hono/node-server": "^1.19.0",
23
23
  "zod": "^4.3.6"
24
24
  },
@@ -15,3 +15,26 @@ allowBuilds:
15
15
  esbuild: true
16
16
  sharp: true
17
17
  workerd: true
18
+ # Explicit `false` for the @astrale-os no-op preinstalls — without these,
19
+ # `pnpm add` of a new version re-prompts and writes placeholder entries here.
20
+ '@astrale-os/kernel-api': false
21
+ '@astrale-os/kernel-client': false
22
+ '@astrale-os/kernel-core': false
23
+ '@astrale-os/kernel-dsl': false
24
+ '@astrale-os/kernel-server': false
25
+ '@astrale-os/sdk': false
26
+
27
+ # @astrale-os packages ship a guarded no-op preinstall (a workspace-dev guard
28
+ # that exits instantly outside the monorepo); declare them intentionally
29
+ # ignored so pnpm's build gate stays quiet.
30
+ ignoredBuiltDependencies:
31
+ - '@astrale-os/kernel-api'
32
+ - '@astrale-os/kernel-client'
33
+ - '@astrale-os/kernel-core'
34
+ - '@astrale-os/kernel-dsl'
35
+ - '@astrale-os/kernel-server'
36
+ - '@astrale-os/sdk'
37
+
38
+ # pnpm v11 gates `pnpm run` on a deps-status check that misfires on the
39
+ # ignored preinstalls above.
40
+ verifyDepsBeforeRun: false