@astrale-os/adapter-cloudflare 0.1.1 → 0.1.3
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/dist/astrale.d.ts +27 -0
- package/dist/astrale.d.ts.map +1 -0
- package/dist/astrale.js +163 -0
- package/dist/astrale.js.map +1 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +43 -0
- package/dist/client.js.map +1 -0
- package/dist/cloudflare.d.ts +22 -0
- package/dist/cloudflare.d.ts.map +1 -0
- package/dist/cloudflare.js +186 -0
- package/dist/cloudflare.js.map +1 -0
- package/dist/codegen/identity.d.ts +10 -0
- package/dist/codegen/identity.d.ts.map +1 -0
- package/dist/codegen/identity.js +32 -0
- package/dist/codegen/identity.js.map +1 -0
- package/dist/codegen/merge.d.ts +20 -0
- package/dist/codegen/merge.d.ts.map +1 -0
- package/dist/codegen/merge.js +91 -0
- package/dist/codegen/merge.js.map +1 -0
- package/dist/codegen/worker.d.ts +31 -0
- package/dist/codegen/worker.d.ts.map +1 -0
- package/dist/codegen/worker.js +93 -0
- package/dist/codegen/worker.js.map +1 -0
- package/dist/codegen/wrangler.d.ts +34 -0
- package/dist/codegen/wrangler.d.ts.map +1 -0
- package/dist/codegen/wrangler.js +61 -0
- package/dist/codegen/wrangler.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/params.d.ts +69 -0
- package/dist/params.d.ts.map +1 -0
- package/dist/params.js +2 -0
- package/dist/params.js.map +1 -0
- package/dist/parse-output.d.ts +25 -0
- package/dist/parse-output.d.ts.map +1 -0
- package/dist/parse-output.js +53 -0
- package/dist/parse-output.js.map +1 -0
- package/dist/wrangler-cli.d.ts +74 -0
- package/dist/wrangler-cli.d.ts.map +1 -0
- package/dist/wrangler-cli.js +201 -0
- package/dist/wrangler-cli.js.map +1 -0
- package/package.json +2 -2
- package/src/astrale.ts +194 -0
- package/src/cloudflare.ts +2 -2
- package/src/index.ts +2 -1
- package/src/params.ts +20 -0
- package/src/wrangler-cli.ts +26 -1
- package/template/astrale.config.ts +9 -0
- package/template/package.json +10 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin wrapper around the `wrangler` binary — the only place the adapter shells
|
|
3
|
+
* out. `watch` runs `wrangler dev` (local workerd) and resolves once the worker
|
|
4
|
+
* reports its local URL; `deploy` runs `wrangler deploy` and parses the
|
|
5
|
+
* authoritative public URL from the output; secrets go through `wrangler secret
|
|
6
|
+
* bulk`. The wrangler binary is resolved from the project's `node_modules/.bin`,
|
|
7
|
+
* falling back to `npx wrangler`.
|
|
8
|
+
*/
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
11
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
12
|
+
import { tmpdir } from 'node:os';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { parseDeployUrl, parseDevReadyUrl } from './parse-output';
|
|
15
|
+
function wranglerCommand(projectDir) {
|
|
16
|
+
const local = join(projectDir, 'node_modules', '.bin', 'wrangler');
|
|
17
|
+
if (existsSync(local))
|
|
18
|
+
return { cmd: local, prefix: [] };
|
|
19
|
+
return { cmd: 'npx', prefix: ['--yes', 'wrangler'] };
|
|
20
|
+
}
|
|
21
|
+
export async function runWranglerDev(args) {
|
|
22
|
+
const { cmd, prefix } = wranglerCommand(args.projectDir);
|
|
23
|
+
const wranglerArgs = [
|
|
24
|
+
...prefix,
|
|
25
|
+
'dev',
|
|
26
|
+
'--config',
|
|
27
|
+
args.configPath,
|
|
28
|
+
'--port',
|
|
29
|
+
String(args.port),
|
|
30
|
+
'--local-protocol',
|
|
31
|
+
'http',
|
|
32
|
+
'--ip',
|
|
33
|
+
'127.0.0.1',
|
|
34
|
+
...(args.remote ? ['--remote'] : []),
|
|
35
|
+
];
|
|
36
|
+
const child = spawn(cmd, wranglerArgs, {
|
|
37
|
+
cwd: args.projectDir,
|
|
38
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
39
|
+
env: { ...process.env, WRANGLER_SEND_METRICS: 'false' },
|
|
40
|
+
});
|
|
41
|
+
const fallbackUrl = `http://localhost:${args.port}`;
|
|
42
|
+
let resolved = false;
|
|
43
|
+
const url = await new Promise((resolve, reject) => {
|
|
44
|
+
const onData = (buf) => {
|
|
45
|
+
const text = buf.toString();
|
|
46
|
+
for (const line of text.split('\n')) {
|
|
47
|
+
if (line.trim())
|
|
48
|
+
args.onLog?.(line);
|
|
49
|
+
}
|
|
50
|
+
if (!resolved) {
|
|
51
|
+
const ready = parseDevReadyUrl(text, args.port);
|
|
52
|
+
if (ready) {
|
|
53
|
+
resolved = true;
|
|
54
|
+
resolve(ready);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else if (/Reloading|Detected changes|Updated/i.test(text)) {
|
|
58
|
+
args.onReload();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
child.stdout?.on('data', onData);
|
|
62
|
+
child.stderr?.on('data', onData);
|
|
63
|
+
child.on('exit', (code) => {
|
|
64
|
+
if (!resolved) {
|
|
65
|
+
resolved = true;
|
|
66
|
+
reject(new Error(`wrangler dev exited before becoming ready (code ${code ?? 'null'}).`));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
child.on('error', (err) => {
|
|
70
|
+
if (!resolved) {
|
|
71
|
+
resolved = true;
|
|
72
|
+
reject(err);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
// Safety net: if we never matched a URL but the process is alive, assume the
|
|
76
|
+
// conventional localhost URL after a grace period.
|
|
77
|
+
setTimeout(() => {
|
|
78
|
+
if (!resolved && child.exitCode === null) {
|
|
79
|
+
resolved = true;
|
|
80
|
+
resolve(fallbackUrl);
|
|
81
|
+
}
|
|
82
|
+
}, 15_000).unref?.();
|
|
83
|
+
});
|
|
84
|
+
return { url, stop: () => stopChild(child) };
|
|
85
|
+
}
|
|
86
|
+
export async function runWranglerDeploy(args) {
|
|
87
|
+
const { cmd, prefix } = wranglerCommand(args.projectDir);
|
|
88
|
+
const deploy = (configPath) => runCapture(cmd, [...prefix, 'deploy', '--config', configPath], args.projectDir, args.onLog);
|
|
89
|
+
return deployWithSelfFallback(deploy, args);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Deploy with a one-time SELF-binding first-deploy recovery. A fresh worker that
|
|
93
|
+
* declares a `services: SELF` binding can't deploy (its own script doesn't exist
|
|
94
|
+
* yet); on THAT specific failure we deploy the SELF-less fallback to create the
|
|
95
|
+
* script, then redeploy WITH SELF so autobinding works. Steady state (every
|
|
96
|
+
* deploy after the first) is a single pass. The `deploy` runner is injected so
|
|
97
|
+
* the orchestration is unit-testable without shelling out.
|
|
98
|
+
*/
|
|
99
|
+
export async function deployWithSelfFallback(deploy, args) {
|
|
100
|
+
let { code, out } = await deploy(args.configPath);
|
|
101
|
+
if (code !== 0 && args.fallbackConfigPath && isSelfBindingMissing(out, args.workerName)) {
|
|
102
|
+
args.onLog?.('SELF service binding not resolvable yet (first deploy) — creating the worker, then re-binding SELF');
|
|
103
|
+
const first = await deploy(args.fallbackConfigPath);
|
|
104
|
+
if (first.code !== 0) {
|
|
105
|
+
throw new Error(`wrangler deploy (no-self pass) failed (code ${first.code}):\n${first.out.slice(-2000)}`);
|
|
106
|
+
}
|
|
107
|
+
;
|
|
108
|
+
({ code, out } = await deploy(args.configPath));
|
|
109
|
+
}
|
|
110
|
+
if (code !== 0) {
|
|
111
|
+
throw new Error(`wrangler deploy failed (code ${code}):\n${out.slice(-2000)}`);
|
|
112
|
+
}
|
|
113
|
+
const url = parseDeployUrl(out, args.route);
|
|
114
|
+
if (!url) {
|
|
115
|
+
throw new Error(`could not determine deployed URL from wrangler output:\n${out.slice(-2000)}`);
|
|
116
|
+
}
|
|
117
|
+
return { url, raw: out };
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* True when wrangler failed specifically because the worker's OWN `SELF` service
|
|
121
|
+
* binding can't resolve yet (first deploy of a fresh script). Requires the
|
|
122
|
+
* worker name so an unrelated missing-service error doesn't trigger the two-pass.
|
|
123
|
+
*/
|
|
124
|
+
export function isSelfBindingMissing(out, workerName) {
|
|
125
|
+
const bindingError = /could not resolve binding/i.test(out) ||
|
|
126
|
+
/service\b[^\n]*\bnot found/i.test(out) ||
|
|
127
|
+
/script\b[^\n]*\bnot found/i.test(out);
|
|
128
|
+
if (!bindingError || !/\bSELF\b/.test(out))
|
|
129
|
+
return false;
|
|
130
|
+
return workerName ? out.includes(workerName) : true;
|
|
131
|
+
}
|
|
132
|
+
export async function bulkPutSecrets(args) {
|
|
133
|
+
const names = Object.keys(args.secrets);
|
|
134
|
+
if (names.length === 0)
|
|
135
|
+
return;
|
|
136
|
+
const { cmd, prefix } = wranglerCommand(args.projectDir);
|
|
137
|
+
const dir = await mkdtemp(join(tmpdir(), 'astrale-secrets-'));
|
|
138
|
+
const file = join(dir, 'secrets.json');
|
|
139
|
+
try {
|
|
140
|
+
await writeFile(file, JSON.stringify(args.secrets));
|
|
141
|
+
const { code, out } = await runCapture(cmd, [...prefix, 'secret', 'bulk', file, '--config', args.configPath], args.projectDir, args.onLog);
|
|
142
|
+
if (code !== 0) {
|
|
143
|
+
throw new Error(`wrangler secret bulk failed (code ${code}):\n${out.slice(-1500)}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
await rm(dir, { recursive: true, force: true });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// ── internals ──────────────────────────────────────────────────────────────
|
|
151
|
+
function runCapture(cmd, args, cwd, onLog) {
|
|
152
|
+
return new Promise((resolve, reject) => {
|
|
153
|
+
const child = spawn(cmd, args, {
|
|
154
|
+
cwd,
|
|
155
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
156
|
+
env: { ...process.env, WRANGLER_SEND_METRICS: 'false' },
|
|
157
|
+
});
|
|
158
|
+
let out = '';
|
|
159
|
+
const onData = (buf) => {
|
|
160
|
+
const text = buf.toString();
|
|
161
|
+
out += text;
|
|
162
|
+
for (const line of text.split('\n'))
|
|
163
|
+
if (line.trim())
|
|
164
|
+
onLog?.(line);
|
|
165
|
+
};
|
|
166
|
+
child.stdout?.on('data', onData);
|
|
167
|
+
child.stderr?.on('data', onData);
|
|
168
|
+
child.on('exit', (code) => resolve({ code: code ?? 1, out }));
|
|
169
|
+
child.on('error', reject);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
async function stopChild(child) {
|
|
173
|
+
if (child.exitCode !== null)
|
|
174
|
+
return;
|
|
175
|
+
await new Promise((resolve) => {
|
|
176
|
+
child.on('exit', () => resolve());
|
|
177
|
+
child.kill('SIGTERM');
|
|
178
|
+
setTimeout(() => {
|
|
179
|
+
if (child.exitCode === null)
|
|
180
|
+
child.kill('SIGKILL');
|
|
181
|
+
resolve();
|
|
182
|
+
}, 4000).unref?.();
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Build the single-module worker bundle WITHOUT deploying — `wrangler deploy
|
|
187
|
+
* --dry-run --outdir` (no Cloudflare auth required). Returns the path of the
|
|
188
|
+
* bundled .js module (the managed adapter publishes its bytes).
|
|
189
|
+
*/
|
|
190
|
+
export async function runWranglerBundle(args) {
|
|
191
|
+
const { cmd, prefix } = wranglerCommand(args.projectDir);
|
|
192
|
+
const { code, out } = await runCapture(cmd, [...prefix, 'deploy', '--dry-run', '--outdir', args.outDir, '--config', args.configPath], args.projectDir, args.onLog);
|
|
193
|
+
if (code !== 0)
|
|
194
|
+
throw new Error(`wrangler bundle failed (exit ${code}): ${out.slice(-400)}`);
|
|
195
|
+
const js = readdirSync(args.outDir).filter((f) => f.endsWith('.js'));
|
|
196
|
+
if (js.length === 0)
|
|
197
|
+
throw new Error(`wrangler bundle produced no .js in ${args.outDir}`);
|
|
198
|
+
const preferred = js.find((f) => f.startsWith('worker')) ?? js[0];
|
|
199
|
+
return join(args.outDir, preferred);
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=wrangler-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrangler-cli.js","sourceRoot":"","sources":["../src/wrangler-cli.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrale-os/adapter-cloudflare",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
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.
|
|
31
|
+
"@astrale-os/devkit": "^0.1.2"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@astrale-os/ox": ">=0.1.0 <1.0.0",
|
package/src/astrale.ts
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `astrale(envs)` — the Astrale-managed deployment adapter.
|
|
3
|
+
*
|
|
4
|
+
* Ships the domain THROUGH the platform instead of to the author's own cloud
|
|
5
|
+
* account: `deploy` builds the same single-module workerd bundle the Cloudflare
|
|
6
|
+
* adapter ships (shared codegen + `wrangler deploy --dry-run`), then publishes
|
|
7
|
+
* it via the admin domain's catalog — `DomainPublished.register` →
|
|
8
|
+
* `::release { bundleBase64 }` (the worker stages the bytes in the platform
|
|
9
|
+
* registry) → `::install { instanceId, source: { kind: 'package' } }`, which
|
|
10
|
+
* deploys it as a host-local Service next to the target instance and installs
|
|
11
|
+
* the domain on it. No Cloudflare account, no wrangler auth — the only
|
|
12
|
+
* credential is the author's Astrale identity, supplied by the `astrale` CLI
|
|
13
|
+
* session this adapter shells out to (the same trust source as
|
|
14
|
+
* `astrale instance install`).
|
|
15
|
+
*
|
|
16
|
+
* `watch` is identical to the Cloudflare adapter's local dev (wrangler dev on
|
|
17
|
+
* localhost) — managed deploys change WHERE the worker runs, not how you
|
|
18
|
+
* iterate locally.
|
|
19
|
+
*
|
|
20
|
+
* Current limits (v1): client/ SPA assets are not shipped (managed packages
|
|
21
|
+
* serve no `/ui` yet) and no runtime secrets reach the service — the bundle
|
|
22
|
+
* must be self-contained (its signing identity is baked in by the codegen).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import type { DomainAdapter } from '@astrale-os/devkit'
|
|
26
|
+
|
|
27
|
+
import { defineAdapter } from '@astrale-os/devkit'
|
|
28
|
+
import { spawn } from 'node:child_process'
|
|
29
|
+
import { existsSync } from 'node:fs'
|
|
30
|
+
import { readFile } from 'node:fs/promises'
|
|
31
|
+
import { join } from 'node:path'
|
|
32
|
+
|
|
33
|
+
import type { AstraleParams } from './params'
|
|
34
|
+
|
|
35
|
+
import { logTo, prepare } from './cloudflare'
|
|
36
|
+
import { runWranglerBundle, runWranglerDev } from './wrangler-cli'
|
|
37
|
+
|
|
38
|
+
const DEFAULT_PORT = 8787
|
|
39
|
+
const DEFAULT_ADMIN_URL = 'https://admin.eu.astrale.ai/api'
|
|
40
|
+
const DEFAULT_REGION = 'eu'
|
|
41
|
+
const ADMIN_ORIGIN = 'admin.astrale.ai'
|
|
42
|
+
|
|
43
|
+
export function astrale(envs: Record<string, AstraleParams>): DomainAdapter<AstraleParams> {
|
|
44
|
+
return defineAdapter<AstraleParams>({
|
|
45
|
+
name: 'astrale',
|
|
46
|
+
envs,
|
|
47
|
+
|
|
48
|
+
// Local dev is unchanged: wrangler dev on localhost. Managed deploys change
|
|
49
|
+
// WHERE the worker ships, not the inner loop.
|
|
50
|
+
async watch(params, ctx) {
|
|
51
|
+
const { configPath } = await prepare(
|
|
52
|
+
{ ...(params.vars ? { vars: params.vars } : {}), port: params.port ?? DEFAULT_PORT },
|
|
53
|
+
ctx,
|
|
54
|
+
'dev',
|
|
55
|
+
)
|
|
56
|
+
const handle = await runWranglerDev({
|
|
57
|
+
projectDir: ctx.projectDir,
|
|
58
|
+
configPath,
|
|
59
|
+
port: params.port ?? DEFAULT_PORT,
|
|
60
|
+
remote: false,
|
|
61
|
+
onReload: ctx.onReload,
|
|
62
|
+
onLog: logTo(),
|
|
63
|
+
})
|
|
64
|
+
return { url: handle.url, stop: handle.stop }
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
async deploy(params, ctx) {
|
|
68
|
+
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).`,
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 1. Codegen + bundle: the exact worker module a Cloudflare deploy would
|
|
77
|
+
// ship, produced locally with `wrangler deploy --dry-run` (no auth).
|
|
78
|
+
// `clientDir` is stripped: managed packages don't ship SPA assets yet,
|
|
79
|
+
// and leaving it in would put a dangling `assets.directory` (the
|
|
80
|
+
// unbuilt dist-client) into the generated config.
|
|
81
|
+
const { clientDir: _omitted, ...bundleCtx } = ctx
|
|
82
|
+
const { configPath } = await prepare({}, bundleCtx, 'dev')
|
|
83
|
+
const outDir = join(ctx.projectDir, '.astrale', 'dist-managed')
|
|
84
|
+
const bundlePath = await runWranglerBundle({
|
|
85
|
+
projectDir: ctx.projectDir,
|
|
86
|
+
configPath,
|
|
87
|
+
outDir,
|
|
88
|
+
onLog: log,
|
|
89
|
+
})
|
|
90
|
+
const bundle = await readFile(bundlePath)
|
|
91
|
+
|
|
92
|
+
// 2. Publish through the platform, authenticated by the author's astrale
|
|
93
|
+
// CLI session. The release payload rides STDIN — a bundle is megabytes
|
|
94
|
+
// of base64, far past argv limits.
|
|
95
|
+
const name = params.name ?? packageNameFor(ctx.domain.origin)
|
|
96
|
+
const adminUrl = params.adminUrl ?? DEFAULT_ADMIN_URL
|
|
97
|
+
const version = `0.0.0-managed.${Date.now()}`
|
|
98
|
+
|
|
99
|
+
log(`registering "${name}" (${ctx.domain.origin}) in the platform catalog…`)
|
|
100
|
+
await astraleCall(ctx.projectDir, params, adminUrl, {
|
|
101
|
+
path: `/${ADMIN_ORIGIN}/class.DomainPublished/register`,
|
|
102
|
+
data: { origin: ctx.domain.origin, name },
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
log(`publishing ${name}@${version} (${bundle.length} bytes)…`)
|
|
106
|
+
await astraleCall(ctx.projectDir, params, adminUrl, {
|
|
107
|
+
path: `/admin/domains/${name}::release`,
|
|
108
|
+
data: { version, bundleBase64: bundle.toString('base64'), makeCurrent: true },
|
|
109
|
+
viaStdin: true,
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
log(`installing on instance "${params.instance}"…`)
|
|
113
|
+
const installed = (await astraleCall(ctx.projectDir, params, adminUrl, {
|
|
114
|
+
path: `/admin/domains/${name}::install`,
|
|
115
|
+
data: { instanceId: params.instance, source: { kind: 'package' } },
|
|
116
|
+
})) as { serviceSlug?: string; state?: string; error?: string | null }
|
|
117
|
+
|
|
118
|
+
if (installed.error || installed.state !== 'installed') {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`managed install failed: state=${installed.state ?? '?'} error=${installed.error ?? '?'}`,
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
if (!installed.serviceSlug) {
|
|
124
|
+
throw new Error('managed install returned no serviceSlug — cannot derive the service URL')
|
|
125
|
+
}
|
|
126
|
+
const region = params.region ?? DEFAULT_REGION
|
|
127
|
+
return { url: `https://${installed.serviceSlug}.svc.${region}.astrale.ai` }
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
secretsFile(params) {
|
|
131
|
+
return params.secrets
|
|
132
|
+
},
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Catalog package name from the origin: first DNS label (e.g. `my-notes.example.dev` → `my-notes`). */
|
|
137
|
+
function packageNameFor(origin: string): string {
|
|
138
|
+
const label = origin.split('.')[0] ?? origin
|
|
139
|
+
return label.toLowerCase().replace(/[^a-z0-9-]+/g, '-')
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Invoke the user's `astrale` CLI for one platform call and parse its JSON
|
|
144
|
+
* output. The CLI owns identity (IdP session, audience scoping, delegation
|
|
145
|
+
* minting) — reimplementing that here would fork the trust path.
|
|
146
|
+
*/
|
|
147
|
+
async function astraleCall(
|
|
148
|
+
projectDir: string,
|
|
149
|
+
params: AstraleParams,
|
|
150
|
+
adminUrl: string,
|
|
151
|
+
call: { path: string; data: unknown; viaStdin?: boolean },
|
|
152
|
+
): Promise<unknown> {
|
|
153
|
+
const args = ['call', call.path, '--url', adminUrl, '--json']
|
|
154
|
+
if (params.identity) args.push('--as', params.identity)
|
|
155
|
+
const payload = JSON.stringify(call.data)
|
|
156
|
+
if (!call.viaStdin) args.push('--data', payload)
|
|
157
|
+
|
|
158
|
+
const { code, out } = await new Promise<{ code: number; out: string }>((resolve, reject) => {
|
|
159
|
+
const child = spawn(astraleBin(projectDir), args, {
|
|
160
|
+
cwd: projectDir,
|
|
161
|
+
stdio: [call.viaStdin ? 'pipe' : 'ignore', 'pipe', 'pipe'],
|
|
162
|
+
})
|
|
163
|
+
let out = ''
|
|
164
|
+
child.stdout?.on('data', (b: Buffer) => (out += b.toString()))
|
|
165
|
+
child.stderr?.on('data', (b: Buffer) => (out += b.toString()))
|
|
166
|
+
child.on('exit', (c) => resolve({ code: c ?? 1, out }))
|
|
167
|
+
child.on('error', reject)
|
|
168
|
+
if (call.viaStdin) {
|
|
169
|
+
child.stdin?.write(payload)
|
|
170
|
+
child.stdin?.end()
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
if (code !== 0) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
`astrale call ${call.path} failed (exit ${code}): ${out.trim().slice(0, 500)}\n` +
|
|
176
|
+
`Is the astrale CLI installed and signed in? (astrale auth login)`,
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
return JSON.parse(out)
|
|
181
|
+
} catch {
|
|
182
|
+
throw new Error(`astrale call ${call.path}: could not parse CLI output: ${out.slice(0, 300)}`)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** The user's astrale CLI: ~/.astrale/bin/astrale when present, else PATH. */
|
|
187
|
+
function astraleBin(_projectDir: string): string {
|
|
188
|
+
const home = process.env.HOME
|
|
189
|
+
if (home) {
|
|
190
|
+
const installed = join(home, '.astrale', 'bin', 'astrale')
|
|
191
|
+
if (existsSync(installed)) return installed
|
|
192
|
+
}
|
|
193
|
+
return 'astrale'
|
|
194
|
+
}
|
package/src/cloudflare.ts
CHANGED
|
@@ -85,7 +85,7 @@ export function cloudflare(
|
|
|
85
85
|
|
|
86
86
|
// ── codegen orchestration ──────────────────────────────────────────────────
|
|
87
87
|
|
|
88
|
-
async function prepare(
|
|
88
|
+
export async function prepare(
|
|
89
89
|
params: CloudflareParams,
|
|
90
90
|
ctx: WatchCtx | DeployCtx,
|
|
91
91
|
mode: 'dev' | 'deploy',
|
|
@@ -223,6 +223,6 @@ export function workerName(params: CloudflareParams, origin: string): string {
|
|
|
223
223
|
.replace(/^-+|-+$/g, '')
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
-
function logTo(): (line: string) => void {
|
|
226
|
+
export function logTo(): (line: string) => void {
|
|
227
227
|
return (line: string) => process.stderr.write(`\x1b[2m ${line}\x1b[0m\n`)
|
|
228
228
|
}
|
package/src/index.ts
CHANGED
|
@@ -13,5 +13,6 @@
|
|
|
13
13
|
* `*.workers.dev`; an env with a `route` ships to that custom domain.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
export { astrale } from './astrale'
|
|
16
17
|
export { cloudflare } from './cloudflare'
|
|
17
|
-
export type { CloudflareParams } from './params'
|
|
18
|
+
export type { AstraleParams, CloudflareParams } from './params'
|
package/src/params.ts
CHANGED
|
@@ -47,3 +47,23 @@ export interface CloudflareParams {
|
|
|
47
47
|
*/
|
|
48
48
|
wrangler?: Record<string, unknown>
|
|
49
49
|
}
|
|
50
|
+
|
|
51
|
+
/** Params for the Astrale-managed adapter (`astrale(envs)`). */
|
|
52
|
+
export interface AstraleParams {
|
|
53
|
+
/** Target instance slug the domain installs onto (e.g. `'bryan-e2e5'`). */
|
|
54
|
+
instance: string
|
|
55
|
+
/** Catalog package name. Default: the origin's first DNS label. */
|
|
56
|
+
name?: string
|
|
57
|
+
/** Admin kernel URL the publish calls target. Default the platform admin. */
|
|
58
|
+
adminUrl?: string
|
|
59
|
+
/** Routing region of the `.svc` service URL. Default `'eu'`. */
|
|
60
|
+
region?: string
|
|
61
|
+
/** CLI identity (`--as`) for the publish calls. Default: the CLI's active identity. */
|
|
62
|
+
identity?: string
|
|
63
|
+
/** Gitignored secrets file — injected ONLY into local `watch` (managed services receive no secrets yet). */
|
|
64
|
+
secrets?: string
|
|
65
|
+
/** Local dev port for `wrangler dev`. Default 8787. */
|
|
66
|
+
port?: number
|
|
67
|
+
/** Extra plain vars for local `watch`. */
|
|
68
|
+
vars?: Record<string, string>
|
|
69
|
+
}
|
package/src/wrangler-cli.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import type { ChildProcess } from 'node:child_process'
|
|
11
11
|
|
|
12
12
|
import { spawn } from 'node:child_process'
|
|
13
|
-
import { existsSync } from 'node:fs'
|
|
13
|
+
import { existsSync, readdirSync } from 'node:fs'
|
|
14
14
|
import { mkdtemp, rm, writeFile } from 'node:fs/promises'
|
|
15
15
|
import { tmpdir } from 'node:os'
|
|
16
16
|
import { join } from 'node:path'
|
|
@@ -238,3 +238,28 @@ async function stopChild(child: ChildProcess): Promise<void> {
|
|
|
238
238
|
}, 4000).unref?.()
|
|
239
239
|
})
|
|
240
240
|
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Build the single-module worker bundle WITHOUT deploying — `wrangler deploy
|
|
244
|
+
* --dry-run --outdir` (no Cloudflare auth required). Returns the path of the
|
|
245
|
+
* bundled .js module (the managed adapter publishes its bytes).
|
|
246
|
+
*/
|
|
247
|
+
export async function runWranglerBundle(args: {
|
|
248
|
+
projectDir: string
|
|
249
|
+
configPath: string
|
|
250
|
+
outDir: string
|
|
251
|
+
onLog?: (line: string) => void
|
|
252
|
+
}): Promise<string> {
|
|
253
|
+
const { cmd, prefix } = wranglerCommand(args.projectDir)
|
|
254
|
+
const { code, out } = await runCapture(
|
|
255
|
+
cmd,
|
|
256
|
+
[...prefix, 'deploy', '--dry-run', '--outdir', args.outDir, '--config', args.configPath],
|
|
257
|
+
args.projectDir,
|
|
258
|
+
args.onLog,
|
|
259
|
+
)
|
|
260
|
+
if (code !== 0) throw new Error(`wrangler bundle failed (exit ${code}): ${out.slice(-400)}`)
|
|
261
|
+
const js = readdirSync(args.outDir).filter((f) => f.endsWith('.js'))
|
|
262
|
+
if (js.length === 0) throw new Error(`wrangler bundle produced no .js in ${args.outDir}`)
|
|
263
|
+
const preferred = js.find((f) => f.startsWith('worker')) ?? js[0]!
|
|
264
|
+
return join(args.outDir, preferred)
|
|
265
|
+
}
|
|
@@ -11,6 +11,15 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { cloudflare } from '@astrale-os/adapter-cloudflare'
|
|
13
13
|
import { defineDomain } from '@astrale-os/devkit'
|
|
14
|
+
// No Cloudflare account? Swap the adapter for the Astrale-managed one — it
|
|
15
|
+
// publishes the same bundle THROUGH the platform and installs it on your
|
|
16
|
+
// instance as a managed service (auth = your `astrale auth login` session):
|
|
17
|
+
//
|
|
18
|
+
// import { astrale } from '@astrale-os/adapter-cloudflare'
|
|
19
|
+
// adapter: astrale({
|
|
20
|
+
// dev: { secrets: '.env.dev' }, // local wrangler dev, unchanged
|
|
21
|
+
// prod: { instance: '<your-instance-slug>' } // pnpm prod → managed deploy
|
|
22
|
+
// }),
|
|
14
23
|
|
|
15
24
|
import { schema } from './schema'
|
|
16
25
|
|
package/template/package.json
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
"name": "astrale-domain",
|
|
3
3
|
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
|
+
"workspaces": [
|
|
6
|
+
"client"
|
|
7
|
+
],
|
|
5
8
|
"type": "module",
|
|
6
9
|
"scripts": {
|
|
7
10
|
"dev": "astrale-domain dev",
|
|
@@ -16,6 +19,7 @@
|
|
|
16
19
|
"@astrale-os/kernel-core": ">=0.3.0 <1.0.0",
|
|
17
20
|
"@astrale-os/kernel-dsl": ">=0.1.0 <1.0.0",
|
|
18
21
|
"@astrale-os/sdk": ">=0.1.0 <1.0.0",
|
|
22
|
+
"@hono/node-server": "^1.19.0",
|
|
19
23
|
"zod": "^4.3.6"
|
|
20
24
|
},
|
|
21
25
|
"devDependencies": {
|
|
@@ -26,5 +30,10 @@
|
|
|
26
30
|
},
|
|
27
31
|
"engines": {
|
|
28
32
|
"node": ">=22"
|
|
29
|
-
}
|
|
33
|
+
},
|
|
34
|
+
"trustedDependencies": [
|
|
35
|
+
"esbuild",
|
|
36
|
+
"sharp",
|
|
37
|
+
"workerd"
|
|
38
|
+
]
|
|
30
39
|
}
|