@astrale-os/adapter-astrale 0.1.0
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 +32 -0
- package/dist/astrale.d.ts.map +1 -0
- package/dist/astrale.js +255 -0
- package/dist/astrale.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/params.d.ts +48 -0
- package/dist/params.d.ts.map +1 -0
- package/dist/params.js +2 -0
- package/dist/params.js.map +1 -0
- package/package.json +53 -0
- package/src/astrale.ts +309 -0
- package/src/index.ts +21 -0
- package/src/params.ts +47 -0
- package/template/astrale.config.ts +39 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `astrale(envs)` — the Astrale-managed deployment adapter.
|
|
3
|
+
*
|
|
4
|
+
* Ships the domain THROUGH the target instance's `services` domain instead of to
|
|
5
|
+
* the author's own cloud account. `deploy` builds the same single-module workerd
|
|
6
|
+
* bundle the Cloudflare adapter ships (shared codegen + `wrangler deploy
|
|
7
|
+
* --dry-run`), then:
|
|
8
|
+
*
|
|
9
|
+
* 1. hosts it on the instance's services domain — `CloudflareWorker.deploy
|
|
10
|
+
* { name, entry, modules, assets, vars }` → a public worker `url`;
|
|
11
|
+
* 2. (optional) pushes runtime secrets via the service's `setSecret`;
|
|
12
|
+
* 3. installs the domain on the instance from that `url`
|
|
13
|
+
* (`astrale domain install <url>` → the child kernel's `Root.installDomain`,
|
|
14
|
+
* which fetches + verifies the signed bundle and runs its `postInstall`).
|
|
15
|
+
*
|
|
16
|
+
* The admin control plane is NOT involved: hosting moved out of admin into the
|
|
17
|
+
* per-instance `services` domain (a separate bounded context). No Cloudflare
|
|
18
|
+
* account, no wrangler auth — the only credential is the author's Astrale
|
|
19
|
+
* identity, supplied by the `astrale` CLI session this adapter shells out to.
|
|
20
|
+
*
|
|
21
|
+
* REQUIRES the `services` domain installed on the target instance. An instance
|
|
22
|
+
* without it can't host managed deploys — `deploy` fails loud with that hint.
|
|
23
|
+
*
|
|
24
|
+
* `watch` is identical to the Cloudflare adapter's local dev (wrangler dev on
|
|
25
|
+
* localhost) — managed deploys change WHERE the worker runs, not how you iterate.
|
|
26
|
+
*/
|
|
27
|
+
import type { DomainAdapter } from '@astrale-os/sdk';
|
|
28
|
+
import type { AstraleParams } from './params';
|
|
29
|
+
export declare function astrale(envs: Record<string, AstraleParams>): DomainAdapter<AstraleParams>;
|
|
30
|
+
/** Service name from the origin: first DNS label (e.g. `my-notes.example.dev` → `my-notes`). */
|
|
31
|
+
export declare function serviceNameFor(origin: string): string;
|
|
32
|
+
//# sourceMappingURL=astrale.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astrale.d.ts","sourceRoot":"","sources":["../src/astrale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAmBpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAK7C,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,aAAa,CAAC,aAAa,CAAC,CA2JzF;AAwBD,gGAAgG;AAChG,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGrD"}
|
package/dist/astrale.js
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `astrale(envs)` — the Astrale-managed deployment adapter.
|
|
3
|
+
*
|
|
4
|
+
* Ships the domain THROUGH the target instance's `services` domain instead of to
|
|
5
|
+
* the author's own cloud account. `deploy` builds the same single-module workerd
|
|
6
|
+
* bundle the Cloudflare adapter ships (shared codegen + `wrangler deploy
|
|
7
|
+
* --dry-run`), then:
|
|
8
|
+
*
|
|
9
|
+
* 1. hosts it on the instance's services domain — `CloudflareWorker.deploy
|
|
10
|
+
* { name, entry, modules, assets, vars }` → a public worker `url`;
|
|
11
|
+
* 2. (optional) pushes runtime secrets via the service's `setSecret`;
|
|
12
|
+
* 3. installs the domain on the instance from that `url`
|
|
13
|
+
* (`astrale domain install <url>` → the child kernel's `Root.installDomain`,
|
|
14
|
+
* which fetches + verifies the signed bundle and runs its `postInstall`).
|
|
15
|
+
*
|
|
16
|
+
* The admin control plane is NOT involved: hosting moved out of admin into the
|
|
17
|
+
* per-instance `services` domain (a separate bounded context). No Cloudflare
|
|
18
|
+
* account, no wrangler auth — the only credential is the author's Astrale
|
|
19
|
+
* identity, supplied by the `astrale` CLI session this adapter shells out to.
|
|
20
|
+
*
|
|
21
|
+
* REQUIRES the `services` domain installed on the target instance. An instance
|
|
22
|
+
* without it can't host managed deploys — `deploy` fails loud with that hint.
|
|
23
|
+
*
|
|
24
|
+
* `watch` is identical to the Cloudflare adapter's local dev (wrangler dev on
|
|
25
|
+
* localhost) — managed deploys change WHERE the worker runs, not how you iterate.
|
|
26
|
+
*/
|
|
27
|
+
// The shared Cloudflare-Workers build toolkit — the managed adapter ships the
|
|
28
|
+
// SAME bundle the direct `cloudflare` adapter does, then routes it through the
|
|
29
|
+
// platform instead of `wrangler deploy`.
|
|
30
|
+
import { buildClient, CLIENT_DIST_DIR, logTo, prepare, runWranglerBundle, runWranglerDev, } from '@astrale-os/adapter-cloudflare/build';
|
|
31
|
+
import { defineAdapter } from '@astrale-os/sdk';
|
|
32
|
+
import { loadDotenvFile } from '@astrale-os/sdk/cli';
|
|
33
|
+
import { spawn } from 'node:child_process';
|
|
34
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
35
|
+
import { join, relative } from 'node:path';
|
|
36
|
+
const DEFAULT_PORT = 8787;
|
|
37
|
+
const DEFAULT_SERVICES_ORIGIN = 'services.astrale.ai';
|
|
38
|
+
export function astrale(envs) {
|
|
39
|
+
return defineAdapter({
|
|
40
|
+
name: 'astrale',
|
|
41
|
+
envs,
|
|
42
|
+
// Local dev is unchanged: wrangler dev on localhost. Managed deploys change
|
|
43
|
+
// WHERE the worker ships, not the inner loop.
|
|
44
|
+
async watch(params, ctx) {
|
|
45
|
+
const { configPath } = await prepare({
|
|
46
|
+
...(params.vars ? { vars: params.vars } : {}),
|
|
47
|
+
...(params.host ? { host: params.host } : {}),
|
|
48
|
+
port: params.port ?? DEFAULT_PORT,
|
|
49
|
+
}, ctx, 'dev');
|
|
50
|
+
const handle = await runWranglerDev({
|
|
51
|
+
projectDir: ctx.projectDir,
|
|
52
|
+
configPath,
|
|
53
|
+
port: params.port ?? DEFAULT_PORT,
|
|
54
|
+
remote: false,
|
|
55
|
+
autoPickPort: params.port === undefined,
|
|
56
|
+
...(params.host ? { ip: '0.0.0.0' } : {}),
|
|
57
|
+
onReload: ctx.onReload,
|
|
58
|
+
onLog: logTo(),
|
|
59
|
+
});
|
|
60
|
+
return { url: params.host ?? handle.url, stop: handle.stop };
|
|
61
|
+
},
|
|
62
|
+
// Config hot-regen for the local dev loop: same codegen as `watch` (the
|
|
63
|
+
// running `wrangler dev` reloads its generated config + entry itself) —
|
|
64
|
+
// the params mapping must stay identical to `watch`'s prepare call.
|
|
65
|
+
async regenerate(params, ctx) {
|
|
66
|
+
await prepare({
|
|
67
|
+
...(params.vars ? { vars: params.vars } : {}),
|
|
68
|
+
...(params.host ? { host: params.host } : {}),
|
|
69
|
+
port: params.port ?? DEFAULT_PORT,
|
|
70
|
+
}, ctx, 'dev');
|
|
71
|
+
},
|
|
72
|
+
async deploy(params, ctx) {
|
|
73
|
+
const log = logTo();
|
|
74
|
+
const instance = params.instance;
|
|
75
|
+
if (!instance) {
|
|
76
|
+
throw new Error(`astrale adapter: this env has no "instance" — managed deploys need the target ` +
|
|
77
|
+
`instance slug (e.g. prod: { instance: '<your-instance-slug>' }).`);
|
|
78
|
+
}
|
|
79
|
+
const servicesOrigin = params.servicesOrigin ?? DEFAULT_SERVICES_ORIGIN;
|
|
80
|
+
const name = params.name ?? serviceNameFor(ctx.domain.origin);
|
|
81
|
+
// Build + pack the client SPA: the services worker serves it under /ui.
|
|
82
|
+
let assetFiles = [];
|
|
83
|
+
if (ctx.clientDir) {
|
|
84
|
+
await buildClient(ctx.clientDir, ctx.projectDir, log);
|
|
85
|
+
assetFiles = readAssetFiles(join(ctx.projectDir, CLIENT_DIST_DIR));
|
|
86
|
+
if (assetFiles.length)
|
|
87
|
+
log(`packed client SPA (${assetFiles.length} files) — /ui ships managed`);
|
|
88
|
+
}
|
|
89
|
+
// 1. Codegen + bundle: the exact worker module a Cloudflare deploy would
|
|
90
|
+
// ship, produced locally with `wrangler deploy --dry-run` (no auth).
|
|
91
|
+
const { clientDir: _omitted, ...bundleCtx } = ctx;
|
|
92
|
+
const { configPath } = await prepare({}, bundleCtx, 'dev');
|
|
93
|
+
const outDir = join(ctx.projectDir, '.astrale', 'dist-managed');
|
|
94
|
+
const bundlePath = await runWranglerBundle({
|
|
95
|
+
projectDir: ctx.projectDir,
|
|
96
|
+
configPath,
|
|
97
|
+
outDir,
|
|
98
|
+
onLog: log,
|
|
99
|
+
});
|
|
100
|
+
const bundle = readFileSync(bundlePath);
|
|
101
|
+
// 2. Host it on the instance's services domain. `CloudflareWorker.deploy`
|
|
102
|
+
// upserts a worker by name on the platform's CF Workers-for-Platforms
|
|
103
|
+
// backend and returns its public URL. Payload rides STDIN — a bundle is
|
|
104
|
+
// megabytes of base64, far past argv limits.
|
|
105
|
+
log(`deploying "${name}" to the services domain on "${instance}"…`);
|
|
106
|
+
const deployed = (await astraleCall(ctx.projectDir, params, {
|
|
107
|
+
instance,
|
|
108
|
+
path: `/${servicesOrigin}/class.CloudflareWorker/deploy`,
|
|
109
|
+
data: {
|
|
110
|
+
name,
|
|
111
|
+
entry: 'index.mjs',
|
|
112
|
+
modules: [{ name: 'index.mjs', contentBase64: bundle.toString('base64'), kind: 'esm' }],
|
|
113
|
+
...(assetFiles.length
|
|
114
|
+
? {
|
|
115
|
+
assets: {
|
|
116
|
+
files: assetFiles,
|
|
117
|
+
notFound: 'single-page-application',
|
|
118
|
+
runWorkerFirst: true,
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
: {}),
|
|
122
|
+
...(params.vars ? { vars: params.vars } : {}),
|
|
123
|
+
},
|
|
124
|
+
viaStdin: true,
|
|
125
|
+
}));
|
|
126
|
+
if (deployed.error || !deployed.url) {
|
|
127
|
+
throw new Error(`services deploy failed: state=${deployed.state ?? '?'} error=${deployed.error ?? '?'}. ` +
|
|
128
|
+
`Is the services domain installed on "${instance}"?`);
|
|
129
|
+
}
|
|
130
|
+
const url = deployed.url;
|
|
131
|
+
// 3. Author runtime secrets: read the env's dotenv locally and push each
|
|
132
|
+
// via the service's write-only `setSecret` (values ride stdin, never argv).
|
|
133
|
+
if (params.secrets) {
|
|
134
|
+
const secrets = loadDotenvFile(join(ctx.projectDir, params.secrets));
|
|
135
|
+
const keys = Object.keys(secrets);
|
|
136
|
+
if (keys.length)
|
|
137
|
+
log(`setting ${keys.length} secret(s) from ${params.secrets}…`);
|
|
138
|
+
for (const [key, value] of Object.entries(secrets)) {
|
|
139
|
+
await astraleCall(ctx.projectDir, params, {
|
|
140
|
+
instance,
|
|
141
|
+
path: `/${servicesOrigin}/services/${name}/setSecret`,
|
|
142
|
+
data: { name: key, value },
|
|
143
|
+
viaStdin: true,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// 4. Install the domain on the instance from the hosted URL. The child
|
|
148
|
+
// kernel fetches the signed bundle, verifies it, and runs its postInstall.
|
|
149
|
+
log(`installing "${ctx.domain.origin}" on "${instance}" from ${url}…`);
|
|
150
|
+
await runAstrale(astraleBin(ctx.projectDir), ctx.projectDir, [
|
|
151
|
+
'instance',
|
|
152
|
+
'install',
|
|
153
|
+
url,
|
|
154
|
+
'-i',
|
|
155
|
+
instance,
|
|
156
|
+
'--json',
|
|
157
|
+
'--timeout',
|
|
158
|
+
'240000',
|
|
159
|
+
]);
|
|
160
|
+
return {
|
|
161
|
+
url,
|
|
162
|
+
nextSteps: ` installed on "${instance}" — call it:\n` +
|
|
163
|
+
` astrale call "/${ctx.domain.origin}/..." -i ${instance}`,
|
|
164
|
+
};
|
|
165
|
+
},
|
|
166
|
+
secretsFile(params) {
|
|
167
|
+
return params.secrets;
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
/** Walk a built SPA dir into the services schema's `AssetFileSchema[]` (paths rooted at `/`). */
|
|
172
|
+
function readAssetFiles(distClientDir) {
|
|
173
|
+
const out = [];
|
|
174
|
+
if (!existsSync(distClientDir))
|
|
175
|
+
return out;
|
|
176
|
+
const walk = (dir) => {
|
|
177
|
+
for (const entry of readdirSync(dir)) {
|
|
178
|
+
const full = join(dir, entry);
|
|
179
|
+
if (statSync(full).isDirectory())
|
|
180
|
+
walk(full);
|
|
181
|
+
else {
|
|
182
|
+
out.push({
|
|
183
|
+
path: `/${relative(distClientDir, full).split('\\').join('/')}`,
|
|
184
|
+
contentBase64: readFileSync(full).toString('base64'),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
walk(distClientDir);
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
/** Service name from the origin: first DNS label (e.g. `my-notes.example.dev` → `my-notes`). */
|
|
193
|
+
export function serviceNameFor(origin) {
|
|
194
|
+
const label = origin.split('.')[0] ?? origin;
|
|
195
|
+
return label.toLowerCase().replace(/[^a-z0-9-]+/g, '-');
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Invoke the user's `astrale` CLI for one platform call (against the target
|
|
199
|
+
* INSTANCE) and parse its JSON output. The CLI owns identity (IdP session,
|
|
200
|
+
* audience scoping, delegation minting) — reimplementing that here would fork
|
|
201
|
+
* the trust path.
|
|
202
|
+
*/
|
|
203
|
+
async function astraleCall(projectDir, params, call) {
|
|
204
|
+
// Saga-sized timeout: a cold managed deploy regularly exceeds the CLI's 30s
|
|
205
|
+
// default. Target the instance (`-i`), not admin — the services domain lives
|
|
206
|
+
// on the instance.
|
|
207
|
+
const args = ['call', call.path, '-i', call.instance, '--json', '--timeout', '240000'];
|
|
208
|
+
if (params.identity)
|
|
209
|
+
args.push('--as', params.identity);
|
|
210
|
+
const payload = JSON.stringify(call.data);
|
|
211
|
+
if (!call.viaStdin)
|
|
212
|
+
args.push('--data', payload);
|
|
213
|
+
const out = await runAstrale(astraleBin(projectDir), projectDir, args, call.viaStdin ? payload : undefined);
|
|
214
|
+
try {
|
|
215
|
+
return JSON.parse(out);
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
throw new Error(`astrale call ${call.path}: could not parse CLI output: ${out.slice(0, 300)}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/** Spawn the astrale CLI, feed optional stdin, return stdout+stderr. Throws on non-zero exit. */
|
|
222
|
+
async function runAstrale(bin, cwd, args, stdin) {
|
|
223
|
+
const { code, out } = await new Promise((resolve, reject) => {
|
|
224
|
+
const child = spawn(bin, args, {
|
|
225
|
+
cwd,
|
|
226
|
+
stdio: [stdin !== undefined ? 'pipe' : 'ignore', 'pipe', 'pipe'],
|
|
227
|
+
});
|
|
228
|
+
let out = '';
|
|
229
|
+
child.stdout?.on('data', (b) => (out += b.toString()));
|
|
230
|
+
child.stderr?.on('data', (b) => (out += b.toString()));
|
|
231
|
+
child.on('exit', (c) => resolve({ code: c ?? 1, out }));
|
|
232
|
+
child.on('error', reject);
|
|
233
|
+
if (stdin !== undefined) {
|
|
234
|
+
child.stdin?.write(stdin);
|
|
235
|
+
child.stdin?.end();
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
if (code !== 0) {
|
|
239
|
+
const authShaped = /AUTH_ERROR|expired|not signed in|credential/i.test(out);
|
|
240
|
+
throw new Error(`astrale ${args[0]} ${args[1] ?? ''} failed (exit ${code}): ${out.trim().slice(0, 500)}` +
|
|
241
|
+
(authShaped ? `\nIs the astrale CLI installed and signed in? (astrale auth login)` : ''));
|
|
242
|
+
}
|
|
243
|
+
return out;
|
|
244
|
+
}
|
|
245
|
+
/** The user's astrale CLI: ~/.astrale/bin/astrale when present, else PATH. */
|
|
246
|
+
function astraleBin(_projectDir) {
|
|
247
|
+
const home = process.env.HOME;
|
|
248
|
+
if (home) {
|
|
249
|
+
const installed = join(home, '.astrale', 'bin', 'astrale');
|
|
250
|
+
if (existsSync(installed))
|
|
251
|
+
return installed;
|
|
252
|
+
}
|
|
253
|
+
return 'astrale';
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=astrale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astrale.js","sourceRoot":"","sources":["../src/astrale.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@astrale-os/adapter-astrale` — deploy an Astrale domain as a MANAGED service
|
|
3
|
+
* through the Astrale platform (no Cloudflare account, no wrangler auth — the
|
|
4
|
+
* only credential is your `astrale auth login` session).
|
|
5
|
+
*
|
|
6
|
+
* import { astrale } from '@astrale-os/adapter-astrale'
|
|
7
|
+
*
|
|
8
|
+
* adapter: astrale({
|
|
9
|
+
* dev: { secrets: '.env.dev' }, // local wrangler dev, unchanged
|
|
10
|
+
* prod: { instance: '<your-instance-slug>' },
|
|
11
|
+
* })
|
|
12
|
+
*
|
|
13
|
+
* It builds the SAME Cloudflare Workers bundle the `cloudflare` adapter ships
|
|
14
|
+
* (via `@astrale-os/adapter-cloudflare/build`), then hosts it on the target
|
|
15
|
+
* instance's `services` domain and installs the domain from the resulting URL.
|
|
16
|
+
* For deploying to YOUR OWN Cloudflare account instead, use
|
|
17
|
+
* `@astrale-os/adapter-cloudflare`.
|
|
18
|
+
*/
|
|
19
|
+
export { astrale } from './astrale';
|
|
20
|
+
export type { AstraleParams } from './params';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@astrale-os/adapter-astrale` — deploy an Astrale domain as a MANAGED service
|
|
3
|
+
* through the Astrale platform (no Cloudflare account, no wrangler auth — the
|
|
4
|
+
* only credential is your `astrale auth login` session).
|
|
5
|
+
*
|
|
6
|
+
* import { astrale } from '@astrale-os/adapter-astrale'
|
|
7
|
+
*
|
|
8
|
+
* adapter: astrale({
|
|
9
|
+
* dev: { secrets: '.env.dev' }, // local wrangler dev, unchanged
|
|
10
|
+
* prod: { instance: '<your-instance-slug>' },
|
|
11
|
+
* })
|
|
12
|
+
*
|
|
13
|
+
* It builds the SAME Cloudflare Workers bundle the `cloudflare` adapter ships
|
|
14
|
+
* (via `@astrale-os/adapter-cloudflare/build`), then hosts it on the target
|
|
15
|
+
* instance's `services` domain and installs the domain from the resulting URL.
|
|
16
|
+
* For deploying to YOUR OWN Cloudflare account instead, use
|
|
17
|
+
* `@astrale-os/adapter-cloudflare`.
|
|
18
|
+
*/
|
|
19
|
+
export { astrale } from './astrale';
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA"}
|
package/dist/params.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `AstraleParams` — the provider-typed config for the Astrale-managed adapter.
|
|
3
|
+
*
|
|
4
|
+
* One type covers every env; per-env differences are just optional fields. The
|
|
5
|
+
* same `{ dev, prod, canary, … }` map a developer writes in `astrale.config.ts`
|
|
6
|
+
* is `Record<string, AstraleParams>`.
|
|
7
|
+
*
|
|
8
|
+
* `watch` is local `wrangler dev` (identical to the Cloudflare adapter's dev);
|
|
9
|
+
* `deploy` ships the bundle through the target instance's `services` domain and
|
|
10
|
+
* installs it — so `instance` is required for `deploy`, ignored by `watch`.
|
|
11
|
+
*/
|
|
12
|
+
export interface AstraleParams {
|
|
13
|
+
/**
|
|
14
|
+
* Target instance slug the domain installs onto (e.g. `'bryan-e2e5'`).
|
|
15
|
+
* Required for `deploy` (managed publish + install); ignored by `watch`
|
|
16
|
+
* (local dev) — so dev-only envs may omit it.
|
|
17
|
+
*/
|
|
18
|
+
instance?: string;
|
|
19
|
+
/** Service name on the platform. Default: the origin's first DNS label. */
|
|
20
|
+
name?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Origin of the `services` domain installed on the target instance — where the
|
|
23
|
+
* worker is hosted (`CloudflareWorker.deploy`). Default `'services.astrale.ai'`.
|
|
24
|
+
*/
|
|
25
|
+
servicesOrigin?: string;
|
|
26
|
+
/** @deprecated Unused since hosting moved to the per-instance services domain. */
|
|
27
|
+
adminUrl?: string;
|
|
28
|
+
/** @deprecated Unused since hosting moved to the per-instance services domain. */
|
|
29
|
+
region?: string;
|
|
30
|
+
/** CLI identity (`--as`) for the deploy/install calls. Default: the CLI's active identity. */
|
|
31
|
+
identity?: string;
|
|
32
|
+
/** 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). */
|
|
33
|
+
secrets?: string;
|
|
34
|
+
/** Local dev port for `wrangler dev`. Default 8787. */
|
|
35
|
+
port?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Public URL the dev server is reached through (tunnel / sandbox preview /
|
|
38
|
+
* reverse proxy), e.g. `'https://my-box.preview.dev'`. Sets BOTH effects an
|
|
39
|
+
* off-localhost dev needs: wrangler binds 0.0.0.0 (reachable from outside)
|
|
40
|
+
* and `WORKER_URL` is pinned to this URL so the worker's per-request-Host
|
|
41
|
+
* identity (`iss`) doesn't drift to the proxy's internal hostname.
|
|
42
|
+
* Usually injected by `pnpm dev --host <url>` rather than written here.
|
|
43
|
+
*/
|
|
44
|
+
host?: string;
|
|
45
|
+
/** Extra plain vars for local `watch`. */
|
|
46
|
+
vars?: Record<string, string>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=params.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../src/params.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wNAAwN;IACxN,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC9B"}
|
package/dist/params.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"params.js","sourceRoot":"","sources":["../src/params.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@astrale-os/adapter-astrale",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Deploy an Astrale domain as a managed service through the Astrale platform",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"adapter",
|
|
7
|
+
"astrale",
|
|
8
|
+
"domain",
|
|
9
|
+
"managed",
|
|
10
|
+
"workers"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "Astrale",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src",
|
|
17
|
+
"template"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "./src/index.ts",
|
|
21
|
+
"types": "./src/index.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./package.json": "./package.json"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@astrale-os/adapter-cloudflare": "^0.1.9",
|
|
31
|
+
"@astrale-os/sdk": "^0.1.7"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@astrale-os/ox": ">=0.1.0 <1.0.0",
|
|
35
|
+
"@types/node": "^22.0.0",
|
|
36
|
+
"@typescript/native-preview": "latest",
|
|
37
|
+
"oxfmt": "latest",
|
|
38
|
+
"oxlint": "latest",
|
|
39
|
+
"typescript": "~6.0.1-rc",
|
|
40
|
+
"vitest": "^3.0.0"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=22"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"typecheck": "tsgo --noEmit",
|
|
47
|
+
"test": "vitest run",
|
|
48
|
+
"lint": "oxlint .",
|
|
49
|
+
"format": "pnpm exec oxfmt --write .",
|
|
50
|
+
"format:check": "pnpm exec oxfmt --check .",
|
|
51
|
+
"build": "rm -rf dist && tsgo"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/src/astrale.ts
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `astrale(envs)` — the Astrale-managed deployment adapter.
|
|
3
|
+
*
|
|
4
|
+
* Ships the domain THROUGH the target instance's `services` domain instead of to
|
|
5
|
+
* the author's own cloud account. `deploy` builds the same single-module workerd
|
|
6
|
+
* bundle the Cloudflare adapter ships (shared codegen + `wrangler deploy
|
|
7
|
+
* --dry-run`), then:
|
|
8
|
+
*
|
|
9
|
+
* 1. hosts it on the instance's services domain — `CloudflareWorker.deploy
|
|
10
|
+
* { name, entry, modules, assets, vars }` → a public worker `url`;
|
|
11
|
+
* 2. (optional) pushes runtime secrets via the service's `setSecret`;
|
|
12
|
+
* 3. installs the domain on the instance from that `url`
|
|
13
|
+
* (`astrale domain install <url>` → the child kernel's `Root.installDomain`,
|
|
14
|
+
* which fetches + verifies the signed bundle and runs its `postInstall`).
|
|
15
|
+
*
|
|
16
|
+
* The admin control plane is NOT involved: hosting moved out of admin into the
|
|
17
|
+
* per-instance `services` domain (a separate bounded context). No Cloudflare
|
|
18
|
+
* account, no wrangler auth — the only credential is the author's Astrale
|
|
19
|
+
* identity, supplied by the `astrale` CLI session this adapter shells out to.
|
|
20
|
+
*
|
|
21
|
+
* REQUIRES the `services` domain installed on the target instance. An instance
|
|
22
|
+
* without it can't host managed deploys — `deploy` fails loud with that hint.
|
|
23
|
+
*
|
|
24
|
+
* `watch` is identical to the Cloudflare adapter's local dev (wrangler dev on
|
|
25
|
+
* localhost) — managed deploys change WHERE the worker runs, not how you iterate.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import type { DomainAdapter } from '@astrale-os/sdk'
|
|
29
|
+
|
|
30
|
+
// The shared Cloudflare-Workers build toolkit — the managed adapter ships the
|
|
31
|
+
// SAME bundle the direct `cloudflare` adapter does, then routes it through the
|
|
32
|
+
// platform instead of `wrangler deploy`.
|
|
33
|
+
import {
|
|
34
|
+
buildClient,
|
|
35
|
+
CLIENT_DIST_DIR,
|
|
36
|
+
logTo,
|
|
37
|
+
prepare,
|
|
38
|
+
runWranglerBundle,
|
|
39
|
+
runWranglerDev,
|
|
40
|
+
} from '@astrale-os/adapter-cloudflare/build'
|
|
41
|
+
import { defineAdapter } from '@astrale-os/sdk'
|
|
42
|
+
import { loadDotenvFile } from '@astrale-os/sdk/cli'
|
|
43
|
+
import { spawn } from 'node:child_process'
|
|
44
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'
|
|
45
|
+
import { join, relative } from 'node:path'
|
|
46
|
+
|
|
47
|
+
import type { AstraleParams } from './params'
|
|
48
|
+
|
|
49
|
+
const DEFAULT_PORT = 8787
|
|
50
|
+
const DEFAULT_SERVICES_ORIGIN = 'services.astrale.ai'
|
|
51
|
+
|
|
52
|
+
export function astrale(envs: Record<string, AstraleParams>): DomainAdapter<AstraleParams> {
|
|
53
|
+
return defineAdapter<AstraleParams>({
|
|
54
|
+
name: 'astrale',
|
|
55
|
+
envs,
|
|
56
|
+
|
|
57
|
+
// Local dev is unchanged: wrangler dev on localhost. Managed deploys change
|
|
58
|
+
// WHERE the worker ships, not the inner loop.
|
|
59
|
+
async watch(params, ctx) {
|
|
60
|
+
const { configPath } = await prepare(
|
|
61
|
+
{
|
|
62
|
+
...(params.vars ? { vars: params.vars } : {}),
|
|
63
|
+
...(params.host ? { host: params.host } : {}),
|
|
64
|
+
port: params.port ?? DEFAULT_PORT,
|
|
65
|
+
},
|
|
66
|
+
ctx,
|
|
67
|
+
'dev',
|
|
68
|
+
)
|
|
69
|
+
const handle = await runWranglerDev({
|
|
70
|
+
projectDir: ctx.projectDir,
|
|
71
|
+
configPath,
|
|
72
|
+
port: params.port ?? DEFAULT_PORT,
|
|
73
|
+
remote: false,
|
|
74
|
+
autoPickPort: params.port === undefined,
|
|
75
|
+
...(params.host ? { ip: '0.0.0.0' } : {}),
|
|
76
|
+
onReload: ctx.onReload,
|
|
77
|
+
onLog: logTo(),
|
|
78
|
+
})
|
|
79
|
+
return { url: params.host ?? handle.url, stop: handle.stop }
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
// Config hot-regen for the local dev loop: same codegen as `watch` (the
|
|
83
|
+
// running `wrangler dev` reloads its generated config + entry itself) —
|
|
84
|
+
// the params mapping must stay identical to `watch`'s prepare call.
|
|
85
|
+
async regenerate(params, ctx) {
|
|
86
|
+
await prepare(
|
|
87
|
+
{
|
|
88
|
+
...(params.vars ? { vars: params.vars } : {}),
|
|
89
|
+
...(params.host ? { host: params.host } : {}),
|
|
90
|
+
port: params.port ?? DEFAULT_PORT,
|
|
91
|
+
},
|
|
92
|
+
ctx,
|
|
93
|
+
'dev',
|
|
94
|
+
)
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
async deploy(params, ctx) {
|
|
98
|
+
const log = logTo()
|
|
99
|
+
const instance = params.instance
|
|
100
|
+
if (!instance) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`astrale adapter: this env has no "instance" — managed deploys need the target ` +
|
|
103
|
+
`instance slug (e.g. prod: { instance: '<your-instance-slug>' }).`,
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
const servicesOrigin = params.servicesOrigin ?? DEFAULT_SERVICES_ORIGIN
|
|
107
|
+
const name = params.name ?? serviceNameFor(ctx.domain.origin)
|
|
108
|
+
|
|
109
|
+
// Build + pack the client SPA: the services worker serves it under /ui.
|
|
110
|
+
let assetFiles: AssetFile[] = []
|
|
111
|
+
if (ctx.clientDir) {
|
|
112
|
+
await buildClient(ctx.clientDir, ctx.projectDir, log)
|
|
113
|
+
assetFiles = readAssetFiles(join(ctx.projectDir, CLIENT_DIST_DIR))
|
|
114
|
+
if (assetFiles.length)
|
|
115
|
+
log(`packed client SPA (${assetFiles.length} files) — /ui ships managed`)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 1. Codegen + bundle: the exact worker module a Cloudflare deploy would
|
|
119
|
+
// ship, produced locally with `wrangler deploy --dry-run` (no auth).
|
|
120
|
+
const { clientDir: _omitted, ...bundleCtx } = ctx
|
|
121
|
+
const { configPath } = await prepare({}, bundleCtx, 'dev')
|
|
122
|
+
const outDir = join(ctx.projectDir, '.astrale', 'dist-managed')
|
|
123
|
+
const bundlePath = await runWranglerBundle({
|
|
124
|
+
projectDir: ctx.projectDir,
|
|
125
|
+
configPath,
|
|
126
|
+
outDir,
|
|
127
|
+
onLog: log,
|
|
128
|
+
})
|
|
129
|
+
const bundle = readFileSync(bundlePath)
|
|
130
|
+
|
|
131
|
+
// 2. Host it on the instance's services domain. `CloudflareWorker.deploy`
|
|
132
|
+
// upserts a worker by name on the platform's CF Workers-for-Platforms
|
|
133
|
+
// backend and returns its public URL. Payload rides STDIN — a bundle is
|
|
134
|
+
// megabytes of base64, far past argv limits.
|
|
135
|
+
log(`deploying "${name}" to the services domain on "${instance}"…`)
|
|
136
|
+
const deployed = (await astraleCall(ctx.projectDir, params, {
|
|
137
|
+
instance,
|
|
138
|
+
path: `/${servicesOrigin}/class.CloudflareWorker/deploy`,
|
|
139
|
+
data: {
|
|
140
|
+
name,
|
|
141
|
+
entry: 'index.mjs',
|
|
142
|
+
modules: [{ name: 'index.mjs', contentBase64: bundle.toString('base64'), kind: 'esm' }],
|
|
143
|
+
...(assetFiles.length
|
|
144
|
+
? {
|
|
145
|
+
assets: {
|
|
146
|
+
files: assetFiles,
|
|
147
|
+
notFound: 'single-page-application',
|
|
148
|
+
runWorkerFirst: true,
|
|
149
|
+
},
|
|
150
|
+
}
|
|
151
|
+
: {}),
|
|
152
|
+
...(params.vars ? { vars: params.vars } : {}),
|
|
153
|
+
},
|
|
154
|
+
viaStdin: true,
|
|
155
|
+
})) as { name?: string; url?: string; state?: string; error?: string | null }
|
|
156
|
+
|
|
157
|
+
if (deployed.error || !deployed.url) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`services deploy failed: state=${deployed.state ?? '?'} error=${deployed.error ?? '?'}. ` +
|
|
160
|
+
`Is the services domain installed on "${instance}"?`,
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
const url = deployed.url
|
|
164
|
+
|
|
165
|
+
// 3. Author runtime secrets: read the env's dotenv locally and push each
|
|
166
|
+
// via the service's write-only `setSecret` (values ride stdin, never argv).
|
|
167
|
+
if (params.secrets) {
|
|
168
|
+
const secrets = loadDotenvFile(join(ctx.projectDir, params.secrets))
|
|
169
|
+
const keys = Object.keys(secrets)
|
|
170
|
+
if (keys.length) log(`setting ${keys.length} secret(s) from ${params.secrets}…`)
|
|
171
|
+
for (const [key, value] of Object.entries(secrets)) {
|
|
172
|
+
await astraleCall(ctx.projectDir, params, {
|
|
173
|
+
instance,
|
|
174
|
+
path: `/${servicesOrigin}/services/${name}/setSecret`,
|
|
175
|
+
data: { name: key, value },
|
|
176
|
+
viaStdin: true,
|
|
177
|
+
})
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 4. Install the domain on the instance from the hosted URL. The child
|
|
182
|
+
// kernel fetches the signed bundle, verifies it, and runs its postInstall.
|
|
183
|
+
log(`installing "${ctx.domain.origin}" on "${instance}" from ${url}…`)
|
|
184
|
+
await runAstrale(astraleBin(ctx.projectDir), ctx.projectDir, [
|
|
185
|
+
'instance',
|
|
186
|
+
'install',
|
|
187
|
+
url,
|
|
188
|
+
'-i',
|
|
189
|
+
instance,
|
|
190
|
+
'--json',
|
|
191
|
+
'--timeout',
|
|
192
|
+
'240000',
|
|
193
|
+
])
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
url,
|
|
197
|
+
nextSteps:
|
|
198
|
+
` installed on "${instance}" — call it:\n` +
|
|
199
|
+
` astrale call "/${ctx.domain.origin}/..." -i ${instance}`,
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
secretsFile(params) {
|
|
204
|
+
return params.secrets
|
|
205
|
+
},
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
type AssetFile = { path: string; contentBase64: string }
|
|
210
|
+
|
|
211
|
+
/** Walk a built SPA dir into the services schema's `AssetFileSchema[]` (paths rooted at `/`). */
|
|
212
|
+
function readAssetFiles(distClientDir: string): AssetFile[] {
|
|
213
|
+
const out: AssetFile[] = []
|
|
214
|
+
if (!existsSync(distClientDir)) return out
|
|
215
|
+
const walk = (dir: string): void => {
|
|
216
|
+
for (const entry of readdirSync(dir)) {
|
|
217
|
+
const full = join(dir, entry)
|
|
218
|
+
if (statSync(full).isDirectory()) walk(full)
|
|
219
|
+
else {
|
|
220
|
+
out.push({
|
|
221
|
+
path: `/${relative(distClientDir, full).split('\\').join('/')}`,
|
|
222
|
+
contentBase64: readFileSync(full).toString('base64'),
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
walk(distClientDir)
|
|
228
|
+
return out
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Service name from the origin: first DNS label (e.g. `my-notes.example.dev` → `my-notes`). */
|
|
232
|
+
export function serviceNameFor(origin: string): string {
|
|
233
|
+
const label = origin.split('.')[0] ?? origin
|
|
234
|
+
return label.toLowerCase().replace(/[^a-z0-9-]+/g, '-')
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Invoke the user's `astrale` CLI for one platform call (against the target
|
|
239
|
+
* INSTANCE) and parse its JSON output. The CLI owns identity (IdP session,
|
|
240
|
+
* audience scoping, delegation minting) — reimplementing that here would fork
|
|
241
|
+
* the trust path.
|
|
242
|
+
*/
|
|
243
|
+
async function astraleCall(
|
|
244
|
+
projectDir: string,
|
|
245
|
+
params: AstraleParams,
|
|
246
|
+
call: { instance: string; path: string; data: unknown; viaStdin?: boolean },
|
|
247
|
+
): Promise<unknown> {
|
|
248
|
+
// Saga-sized timeout: a cold managed deploy regularly exceeds the CLI's 30s
|
|
249
|
+
// default. Target the instance (`-i`), not admin — the services domain lives
|
|
250
|
+
// on the instance.
|
|
251
|
+
const args = ['call', call.path, '-i', call.instance, '--json', '--timeout', '240000']
|
|
252
|
+
if (params.identity) args.push('--as', params.identity)
|
|
253
|
+
const payload = JSON.stringify(call.data)
|
|
254
|
+
if (!call.viaStdin) args.push('--data', payload)
|
|
255
|
+
|
|
256
|
+
const out = await runAstrale(
|
|
257
|
+
astraleBin(projectDir),
|
|
258
|
+
projectDir,
|
|
259
|
+
args,
|
|
260
|
+
call.viaStdin ? payload : undefined,
|
|
261
|
+
)
|
|
262
|
+
try {
|
|
263
|
+
return JSON.parse(out)
|
|
264
|
+
} catch {
|
|
265
|
+
throw new Error(`astrale call ${call.path}: could not parse CLI output: ${out.slice(0, 300)}`)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** Spawn the astrale CLI, feed optional stdin, return stdout+stderr. Throws on non-zero exit. */
|
|
270
|
+
async function runAstrale(
|
|
271
|
+
bin: string,
|
|
272
|
+
cwd: string,
|
|
273
|
+
args: string[],
|
|
274
|
+
stdin?: string,
|
|
275
|
+
): Promise<string> {
|
|
276
|
+
const { code, out } = await new Promise<{ code: number; out: string }>((resolve, reject) => {
|
|
277
|
+
const child = spawn(bin, args, {
|
|
278
|
+
cwd,
|
|
279
|
+
stdio: [stdin !== undefined ? 'pipe' : 'ignore', 'pipe', 'pipe'],
|
|
280
|
+
})
|
|
281
|
+
let out = ''
|
|
282
|
+
child.stdout?.on('data', (b: Buffer) => (out += b.toString()))
|
|
283
|
+
child.stderr?.on('data', (b: Buffer) => (out += b.toString()))
|
|
284
|
+
child.on('exit', (c) => resolve({ code: c ?? 1, out }))
|
|
285
|
+
child.on('error', reject)
|
|
286
|
+
if (stdin !== undefined) {
|
|
287
|
+
child.stdin?.write(stdin)
|
|
288
|
+
child.stdin?.end()
|
|
289
|
+
}
|
|
290
|
+
})
|
|
291
|
+
if (code !== 0) {
|
|
292
|
+
const authShaped = /AUTH_ERROR|expired|not signed in|credential/i.test(out)
|
|
293
|
+
throw new Error(
|
|
294
|
+
`astrale ${args[0]} ${args[1] ?? ''} failed (exit ${code}): ${out.trim().slice(0, 500)}` +
|
|
295
|
+
(authShaped ? `\nIs the astrale CLI installed and signed in? (astrale auth login)` : ''),
|
|
296
|
+
)
|
|
297
|
+
}
|
|
298
|
+
return out
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** The user's astrale CLI: ~/.astrale/bin/astrale when present, else PATH. */
|
|
302
|
+
function astraleBin(_projectDir: string): string {
|
|
303
|
+
const home = process.env.HOME
|
|
304
|
+
if (home) {
|
|
305
|
+
const installed = join(home, '.astrale', 'bin', 'astrale')
|
|
306
|
+
if (existsSync(installed)) return installed
|
|
307
|
+
}
|
|
308
|
+
return 'astrale'
|
|
309
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@astrale-os/adapter-astrale` — deploy an Astrale domain as a MANAGED service
|
|
3
|
+
* through the Astrale platform (no Cloudflare account, no wrangler auth — the
|
|
4
|
+
* only credential is your `astrale auth login` session).
|
|
5
|
+
*
|
|
6
|
+
* import { astrale } from '@astrale-os/adapter-astrale'
|
|
7
|
+
*
|
|
8
|
+
* adapter: astrale({
|
|
9
|
+
* dev: { secrets: '.env.dev' }, // local wrangler dev, unchanged
|
|
10
|
+
* prod: { instance: '<your-instance-slug>' },
|
|
11
|
+
* })
|
|
12
|
+
*
|
|
13
|
+
* It builds the SAME Cloudflare Workers bundle the `cloudflare` adapter ships
|
|
14
|
+
* (via `@astrale-os/adapter-cloudflare/build`), then hosts it on the target
|
|
15
|
+
* instance's `services` domain and installs the domain from the resulting URL.
|
|
16
|
+
* For deploying to YOUR OWN Cloudflare account instead, use
|
|
17
|
+
* `@astrale-os/adapter-cloudflare`.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export { astrale } from './astrale'
|
|
21
|
+
export type { AstraleParams } from './params'
|
package/src/params.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `AstraleParams` — the provider-typed config for the Astrale-managed adapter.
|
|
3
|
+
*
|
|
4
|
+
* One type covers every env; per-env differences are just optional fields. The
|
|
5
|
+
* same `{ dev, prod, canary, … }` map a developer writes in `astrale.config.ts`
|
|
6
|
+
* is `Record<string, AstraleParams>`.
|
|
7
|
+
*
|
|
8
|
+
* `watch` is local `wrangler dev` (identical to the Cloudflare adapter's dev);
|
|
9
|
+
* `deploy` ships the bundle through the target instance's `services` domain and
|
|
10
|
+
* installs it — so `instance` is required for `deploy`, ignored by `watch`.
|
|
11
|
+
*/
|
|
12
|
+
export interface AstraleParams {
|
|
13
|
+
/**
|
|
14
|
+
* Target instance slug the domain installs onto (e.g. `'bryan-e2e5'`).
|
|
15
|
+
* Required for `deploy` (managed publish + install); ignored by `watch`
|
|
16
|
+
* (local dev) — so dev-only envs may omit it.
|
|
17
|
+
*/
|
|
18
|
+
instance?: string
|
|
19
|
+
/** Service name on the platform. Default: the origin's first DNS label. */
|
|
20
|
+
name?: string
|
|
21
|
+
/**
|
|
22
|
+
* Origin of the `services` domain installed on the target instance — where the
|
|
23
|
+
* worker is hosted (`CloudflareWorker.deploy`). Default `'services.astrale.ai'`.
|
|
24
|
+
*/
|
|
25
|
+
servicesOrigin?: string
|
|
26
|
+
/** @deprecated Unused since hosting moved to the per-instance services domain. */
|
|
27
|
+
adminUrl?: string
|
|
28
|
+
/** @deprecated Unused since hosting moved to the per-instance services domain. */
|
|
29
|
+
region?: string
|
|
30
|
+
/** CLI identity (`--as`) for the deploy/install calls. Default: the CLI's active identity. */
|
|
31
|
+
identity?: string
|
|
32
|
+
/** 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). */
|
|
33
|
+
secrets?: string
|
|
34
|
+
/** Local dev port for `wrangler dev`. Default 8787. */
|
|
35
|
+
port?: number
|
|
36
|
+
/**
|
|
37
|
+
* Public URL the dev server is reached through (tunnel / sandbox preview /
|
|
38
|
+
* reverse proxy), e.g. `'https://my-box.preview.dev'`. Sets BOTH effects an
|
|
39
|
+
* off-localhost dev needs: wrangler binds 0.0.0.0 (reachable from outside)
|
|
40
|
+
* and `WORKER_URL` is pinned to this URL so the worker's per-request-Host
|
|
41
|
+
* identity (`iss`) doesn't drift to the proxy's internal hostname.
|
|
42
|
+
* Usually injected by `pnpm dev --host <url>` rather than written here.
|
|
43
|
+
*/
|
|
44
|
+
host?: string
|
|
45
|
+
/** Extra plain vars for local `watch`. */
|
|
46
|
+
vars?: Record<string, string>
|
|
47
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astrale.config.ts — binds the worker-safe domain (`domain.ts`) to the managed
|
|
3
|
+
* Astrale deploy adapter for the `astrale-domain` CLI. This is a NODE-only
|
|
4
|
+
* module; the generated worker imports `domain.ts` directly, never this file.
|
|
5
|
+
*
|
|
6
|
+
* This variant ships THROUGH the Astrale platform (the managed `astrale`
|
|
7
|
+
* adapter) — no Cloudflare account needed.
|
|
8
|
+
*
|
|
9
|
+
* pnpm dev # wrangler dev → prints a local URL
|
|
10
|
+
* astrale domain install <url> --direct # mount the dev URL on an instance
|
|
11
|
+
* pnpm prod # managed deploy → prints a URL + installs
|
|
12
|
+
*/
|
|
13
|
+
import { astrale } from '@astrale-os/adapter-astrale'
|
|
14
|
+
import { deploy } from '@astrale-os/sdk'
|
|
15
|
+
// Have your own Cloudflare account and prefer deploying there directly? Swap
|
|
16
|
+
// the adapter — same bundle, shipped with wrangler under YOUR account (then
|
|
17
|
+
// mount it yourself: `astrale domain install <url> --direct`):
|
|
18
|
+
//
|
|
19
|
+
// import { cloudflare } from '@astrale-os/adapter-cloudflare'
|
|
20
|
+
// export default deploy(domain, cloudflare({
|
|
21
|
+
// dev: { secrets: '.env.dev' },
|
|
22
|
+
// prod: { route: 'astrale-domain.example.dev', secrets: '.env.prod' },
|
|
23
|
+
// }))
|
|
24
|
+
|
|
25
|
+
import { domain } from './domain'
|
|
26
|
+
|
|
27
|
+
export default deploy(
|
|
28
|
+
domain,
|
|
29
|
+
astrale({
|
|
30
|
+
// Local dev: `wrangler dev`. No route → URL is http://localhost:8787.
|
|
31
|
+
dev: { secrets: '.env.dev' },
|
|
32
|
+
// Managed deploy: `pnpm prod` publishes the bundle through the platform and
|
|
33
|
+
// installs the domain on this instance. The slug comes from
|
|
34
|
+
// `astrale instance create <slug>` / `astrale instance status`.
|
|
35
|
+
prod: { instance: 'my-instance-slug' },
|
|
36
|
+
// Author secrets ship via `secrets: '.env.prod'` on any env (encrypted at
|
|
37
|
+
// rest platform-side, re-applied on redeploys; omit = keep, `{}` = clear).
|
|
38
|
+
}),
|
|
39
|
+
)
|