@astrale-os/sdk 0.1.10 → 0.3.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/LICENSE +202 -0
- package/dist/auth/check.d.ts +1 -2
- package/dist/auth/check.d.ts.map +1 -1
- package/dist/auth/check.js +2 -6
- package/dist/auth/check.js.map +1 -1
- package/dist/auth/index.d.ts +3 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +2 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/issuer-mint.d.ts +53 -0
- package/dist/auth/issuer-mint.d.ts.map +1 -0
- package/dist/auth/issuer-mint.js +35 -0
- package/dist/auth/issuer-mint.js.map +1 -0
- package/dist/auth/kernel-client.d.ts +8 -2
- package/dist/auth/kernel-client.d.ts.map +1 -1
- package/dist/auth/kernel-client.js +22 -46
- package/dist/auth/kernel-client.js.map +1 -1
- package/dist/cli/dotenv.d.ts +8 -0
- package/dist/cli/dotenv.d.ts.map +1 -1
- package/dist/cli/dotenv.js +18 -0
- package/dist/cli/dotenv.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/log.d.ts +11 -0
- package/dist/cli/log.d.ts.map +1 -0
- package/dist/cli/log.js +17 -0
- package/dist/cli/log.js.map +1 -0
- package/dist/cli/publish.d.ts +35 -0
- package/dist/cli/publish.d.ts.map +1 -0
- package/dist/cli/publish.js +271 -0
- package/dist/cli/publish.js.map +1 -0
- package/dist/cli/run.d.ts +17 -2
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +102 -111
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/spec.d.ts.map +1 -1
- package/dist/cli/spec.js +1 -0
- package/dist/cli/spec.js.map +1 -1
- package/dist/config/adapter.d.ts +12 -11
- package/dist/config/adapter.d.ts.map +1 -1
- package/dist/config/adapter.js.map +1 -1
- package/dist/config/define-domain.d.ts +88 -27
- package/dist/config/define-domain.d.ts.map +1 -1
- package/dist/config/define-domain.js +79 -33
- package/dist/config/define-domain.js.map +1 -1
- package/dist/config/deploy.d.ts +1 -1
- package/dist/config/deploy.js +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/define/remote-function.d.ts +32 -17
- package/dist/define/remote-function.d.ts.map +1 -1
- package/dist/define/remote-function.js +10 -9
- package/dist/define/remote-function.js.map +1 -1
- package/dist/define/view.d.ts +8 -6
- package/dist/define/view.d.ts.map +1 -1
- package/dist/define/view.js +8 -6
- package/dist/define/view.js.map +1 -1
- package/dist/deploy/check.d.ts +6 -6
- package/dist/deploy/check.d.ts.map +1 -1
- package/dist/deploy/check.js +1 -1
- package/dist/deploy/check.js.map +1 -1
- package/dist/deploy/index.d.ts +0 -1
- package/dist/deploy/index.d.ts.map +1 -1
- package/dist/deploy/index.js +0 -1
- package/dist/deploy/index.js.map +1 -1
- package/dist/deploy/meta.d.ts +11 -0
- package/dist/deploy/meta.d.ts.map +1 -1
- package/dist/deploy/meta.js +23 -0
- package/dist/deploy/meta.js.map +1 -1
- package/dist/dispatch/dispatcher.d.ts +17 -4
- package/dist/dispatch/dispatcher.d.ts.map +1 -1
- package/dist/dispatch/dispatcher.js +15 -3
- package/dist/dispatch/dispatcher.js.map +1 -1
- package/dist/dispatch/execute.d.ts +6 -2
- package/dist/dispatch/execute.d.ts.map +1 -1
- package/dist/dispatch/execute.js +1 -0
- package/dist/dispatch/execute.js.map +1 -1
- package/dist/dispatch/identity.d.ts +12 -10
- package/dist/dispatch/identity.d.ts.map +1 -1
- package/dist/dispatch/identity.js +10 -15
- package/dist/dispatch/identity.js.map +1 -1
- package/dist/dispatch/index.d.ts +1 -1
- package/dist/dispatch/index.d.ts.map +1 -1
- package/dist/dispatch/index.js +1 -1
- package/dist/dispatch/index.js.map +1 -1
- package/dist/dispatch/self.d.ts +25 -37
- package/dist/dispatch/self.d.ts.map +1 -1
- package/dist/dispatch/self.js +60 -30
- package/dist/dispatch/self.js.map +1 -1
- package/dist/domain/binding.d.ts +18 -0
- package/dist/domain/binding.d.ts.map +1 -0
- package/dist/domain/binding.js +29 -0
- package/dist/domain/binding.js.map +1 -0
- package/dist/domain/build-spec.d.ts.map +1 -1
- package/dist/domain/build-spec.js +22 -7
- package/dist/domain/build-spec.js.map +1 -1
- package/dist/domain/define.d.ts +28 -43
- package/dist/domain/define.d.ts.map +1 -1
- package/dist/domain/define.js +23 -60
- package/dist/domain/define.js.map +1 -1
- package/dist/domain/extend-functions.d.ts +48 -0
- package/dist/domain/extend-functions.d.ts.map +1 -0
- package/dist/domain/extend-functions.js +84 -0
- package/dist/domain/extend-functions.js.map +1 -0
- package/dist/domain/extend-views.d.ts +45 -0
- package/dist/domain/extend-views.d.ts.map +1 -0
- package/dist/domain/extend-views.js +116 -0
- package/dist/domain/extend-views.js.map +1 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/method/class.d.ts +2 -2
- package/dist/method/class.d.ts.map +1 -1
- package/dist/method/class.js.map +1 -1
- package/dist/method/context.d.ts +18 -3
- package/dist/method/context.d.ts.map +1 -1
- package/dist/method/index.d.ts +2 -2
- package/dist/method/index.d.ts.map +1 -1
- package/dist/method/index.js.map +1 -1
- package/dist/method/single.d.ts +25 -38
- package/dist/method/single.d.ts.map +1 -1
- package/dist/method/single.js +1 -11
- package/dist/method/single.js.map +1 -1
- package/dist/server/auxiliary-routes.d.ts.map +1 -1
- package/dist/server/auxiliary-routes.js +14 -3
- package/dist/server/auxiliary-routes.js.map +1 -1
- package/dist/server/create.d.ts +2 -15
- package/dist/server/create.d.ts.map +1 -1
- package/dist/server/create.js +15 -51
- package/dist/server/create.js.map +1 -1
- package/dist/server/domain-entry.d.ts +10 -0
- package/dist/server/domain-entry.d.ts.map +1 -1
- package/dist/server/domain-entry.js +2 -0
- package/dist/server/domain-entry.js.map +1 -1
- package/dist/server/index.d.ts +0 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +0 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/worker-entry.d.ts +3 -3
- package/dist/server/worker-entry.js +3 -3
- package/package.json +10 -11
- package/src/auth/check.ts +2 -6
- package/src/auth/index.ts +3 -1
- package/src/auth/issuer-mint.ts +75 -0
- package/src/auth/kernel-client.ts +31 -63
- package/src/cli/dotenv.ts +20 -0
- package/src/cli/index.ts +1 -1
- package/src/cli/log.ts +18 -0
- package/src/cli/publish.ts +341 -0
- package/src/cli/run.ts +109 -125
- package/src/cli/spec.ts +1 -0
- package/src/config/adapter.ts +9 -11
- package/src/config/define-domain.ts +184 -53
- package/src/config/deploy.ts +1 -1
- package/src/config/index.ts +1 -1
- package/src/define/remote-function.ts +56 -21
- package/src/define/view.ts +8 -6
- package/src/deploy/check.ts +7 -7
- package/src/deploy/index.ts +0 -1
- package/src/deploy/meta.ts +25 -0
- package/src/dispatch/dispatcher.ts +32 -9
- package/src/dispatch/execute.ts +7 -2
- package/src/dispatch/identity.ts +17 -22
- package/src/dispatch/index.ts +1 -1
- package/src/dispatch/self.ts +117 -41
- package/src/domain/binding.ts +37 -0
- package/src/domain/build-spec.ts +32 -7
- package/src/domain/define.ts +71 -78
- package/src/domain/extend-functions.ts +106 -0
- package/src/domain/extend-views.ts +151 -0
- package/src/index.ts +36 -7
- package/src/method/class.ts +11 -7
- package/src/method/context.ts +19 -3
- package/src/method/index.ts +8 -2
- package/src/method/single.ts +35 -42
- package/src/server/auxiliary-routes.ts +14 -3
- package/src/server/create.ts +15 -51
- package/src/server/domain-entry.ts +12 -0
- package/src/server/index.ts +0 -1
- package/src/server/worker-entry.ts +3 -3
- package/src/deploy/hash-spec.ts +0 -31
- package/src/domain/extend-core.ts +0 -301
- package/src/server/worker-meta.ts +0 -25
package/src/cli/run.ts
CHANGED
|
@@ -18,7 +18,15 @@
|
|
|
18
18
|
* astrale-domain prod # = deploy prod
|
|
19
19
|
* astrale-domain deploy <env> # any env key
|
|
20
20
|
* astrale-domain build # rebuild spec only (placeholder URL)
|
|
21
|
-
* astrale-domain publish [env] #
|
|
21
|
+
* astrale-domain publish [env] # RELEASE: publish ./schema to npm (if any) + register the deployed URL
|
|
22
|
+
*
|
|
23
|
+
* A release has two halves that must stay in sync: the CONTRACT (`./schema` on
|
|
24
|
+
* npm) and the DEPLOYMENT (worker URL in the catalog). `publish` does both,
|
|
25
|
+
* npm-FIRST — `npm publish` is irreversible, so the catalog is registered only on
|
|
26
|
+
* schema-publish success, never pointing at an unpublished contract. The schema
|
|
27
|
+
* publish is idempotent (skips an unbumped version). Scope it with `--schema`
|
|
28
|
+
* (contract only — config-free) or `--skip-schema` (catalog only). All publish
|
|
29
|
+
* logic lives in `./publish.ts`; this file only parses args and dispatches.
|
|
22
30
|
*
|
|
23
31
|
* `publish` registers a domain's ALREADY-deployed URL in the admin catalog by
|
|
24
32
|
* SHELLING OUT to the operator CLI (`astrale domain publish --origin --name
|
|
@@ -31,8 +39,7 @@
|
|
|
31
39
|
* already points you at for `domain install`).
|
|
32
40
|
*/
|
|
33
41
|
|
|
34
|
-
import {
|
|
35
|
-
import { existsSync, readFileSync, watch as watchFs } from 'node:fs'
|
|
42
|
+
import { existsSync, watch as watchFs } from 'node:fs'
|
|
36
43
|
import { mkdir, writeFile } from 'node:fs/promises'
|
|
37
44
|
import { createRequire } from 'node:module'
|
|
38
45
|
import { basename, dirname, isAbsolute, join } from 'node:path'
|
|
@@ -41,7 +48,9 @@ import { pathToFileURL } from 'node:url'
|
|
|
41
48
|
import type { DeployResult, DomainAdapter, DomainInfo, WatchHandle } from '../config/adapter'
|
|
42
49
|
import type { DeployConfig } from '../config/deploy'
|
|
43
50
|
|
|
44
|
-
import {
|
|
51
|
+
import { loadDeclaredSecrets } from './dotenv'
|
|
52
|
+
import { BOLD, DIM, error, GREEN, info, RESET, warn } from './log'
|
|
53
|
+
import { publishSchema, runRelease, runReleaseAfterDeploy } from './publish'
|
|
45
54
|
import { buildProjectSpec } from './spec'
|
|
46
55
|
|
|
47
56
|
const CONFIG_NAMES = ['astrale.config.ts', 'astrale.config.js', 'astrale.config.mjs']
|
|
@@ -50,6 +59,14 @@ type ParsedArgs = {
|
|
|
50
59
|
command: 'dev' | 'build' | 'deploy' | 'publish'
|
|
51
60
|
env: string
|
|
52
61
|
watch: boolean
|
|
62
|
+
/** `--dry-run` (publish) — pack + `npm publish --dry-run` and skip the catalog register. */
|
|
63
|
+
dryRun?: boolean
|
|
64
|
+
/** `--schema` (publish) — publish ONLY the `./schema` package; no catalog, no config. */
|
|
65
|
+
schemaOnly?: boolean
|
|
66
|
+
/** `--otp <code>` (publish / deploy --publish) — 2FA OTP forwarded to `npm publish`. */
|
|
67
|
+
otp?: string
|
|
68
|
+
/** `--skip-schema` (publish / deploy --publish) — register the catalog only; don't publish `./schema`. */
|
|
69
|
+
skipSchema?: boolean
|
|
53
70
|
/** `--port <n>` (dev only) — overrides the env's local dev port. */
|
|
54
71
|
port?: number
|
|
55
72
|
/** `--host <url>` (dev only) — public URL of a tunnel/proxy front: binds 0.0.0.0 + pins WORKER_URL. */
|
|
@@ -79,6 +96,17 @@ export async function run(argv: readonly string[]): Promise<number> {
|
|
|
79
96
|
return 2
|
|
80
97
|
}
|
|
81
98
|
|
|
99
|
+
// `publish --schema` (schema only) operates on the schema PACKAGE, not
|
|
100
|
+
// astrale.config.ts — handle it before config discovery so it works in a folder
|
|
101
|
+
// that is purely a schema package and needs no adapter/Bun runtime.
|
|
102
|
+
if (parsed.command === 'publish' && parsed.schemaOnly) {
|
|
103
|
+
return await publishSchema({
|
|
104
|
+
projectDir: process.cwd(),
|
|
105
|
+
dryRun: parsed.dryRun ?? false,
|
|
106
|
+
...(parsed.otp !== undefined ? { otp: parsed.otp } : {}),
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
82
110
|
// The CLI imports the project's TypeScript modules (astrale.config.ts, the ★
|
|
83
111
|
// files) directly — that requires a TS-native runtime. Fail with the remedy
|
|
84
112
|
// instead of a cryptic ERR_UNKNOWN_FILE_EXTENSION deep in `import()`.
|
|
@@ -137,20 +165,16 @@ export async function run(argv: readonly string[]): Promise<number> {
|
|
|
137
165
|
}
|
|
138
166
|
|
|
139
167
|
if (parsed.command === 'publish') {
|
|
140
|
-
//
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
// only points the registry at an address the author already deployed.
|
|
145
|
-
const pkg = readPackageMeta(projectDir)
|
|
146
|
-
const name = parsed.name ?? def.origin.split('.')[0] ?? def.origin
|
|
147
|
-
const url = parsed.publicUrl ?? `https://${def.origin}`
|
|
148
|
-
info(`registering ${def.origin} → ${url} in the admin catalog (no deploy)`)
|
|
149
|
-
return await publishToAdmin({
|
|
168
|
+
// `--schema` (schema only) was handled before config discovery; this is the
|
|
169
|
+
// full release (schema + catalog) or `--skip-schema` (catalog only).
|
|
170
|
+
return await runRelease({
|
|
171
|
+
projectDir,
|
|
150
172
|
origin: def.origin,
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
...(
|
|
173
|
+
skipSchema: parsed.skipSchema ?? false,
|
|
174
|
+
dryRun: parsed.dryRun ?? false,
|
|
175
|
+
...(parsed.name !== undefined ? { name: parsed.name } : {}),
|
|
176
|
+
...(parsed.publicUrl !== undefined ? { publicUrl: parsed.publicUrl } : {}),
|
|
177
|
+
...(parsed.otp !== undefined ? { otp: parsed.otp } : {}),
|
|
154
178
|
...(parsed.installByDefault ? { installByDefault: true } : {}),
|
|
155
179
|
})
|
|
156
180
|
}
|
|
@@ -172,9 +196,6 @@ export async function run(argv: readonly string[]): Promise<number> {
|
|
|
172
196
|
|
|
173
197
|
const domain = toDomainInfo(def)
|
|
174
198
|
|
|
175
|
-
// The client SPA is a DECLARED binding (`defineDomain({ client })`), not a
|
|
176
|
-
// folder we sniff for: its presence + source dir come from the definition.
|
|
177
|
-
const clientDir = def.client ? join(projectDir, def.client.dir) : undefined
|
|
178
199
|
const secrets = loadSecrets(adapter, params, projectDir)
|
|
179
200
|
|
|
180
201
|
if (parsed.command === 'dev' || (parsed.command === 'deploy' && parsed.watch)) {
|
|
@@ -184,7 +205,6 @@ export async function run(argv: readonly string[]): Promise<number> {
|
|
|
184
205
|
paramOverrides,
|
|
185
206
|
projectDir,
|
|
186
207
|
specPath,
|
|
187
|
-
clientDir,
|
|
188
208
|
secrets,
|
|
189
209
|
domain,
|
|
190
210
|
env: parsed.env,
|
|
@@ -198,7 +218,6 @@ export async function run(argv: readonly string[]): Promise<number> {
|
|
|
198
218
|
projectDir,
|
|
199
219
|
specPath,
|
|
200
220
|
secrets,
|
|
201
|
-
...(clientDir ? { clientDir } : {}),
|
|
202
221
|
domain,
|
|
203
222
|
env: parsed.env,
|
|
204
223
|
schemaHashForUrl: async (url) => {
|
|
@@ -210,98 +229,34 @@ export async function run(argv: readonly string[]): Promise<number> {
|
|
|
210
229
|
printDeployed(result, def)
|
|
211
230
|
|
|
212
231
|
if (parsed.publish) {
|
|
213
|
-
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
// convention, e.g. `ai-gateway`); `--name` overrides.
|
|
218
|
-
const name = parsed.name ?? def.origin.split('.')[0] ?? def.origin
|
|
219
|
-
return await publishToAdmin({
|
|
232
|
+
// `--publish` = release after deploy: ship the schema (if any) THEN register
|
|
233
|
+
// the just-deployed URL — same npm-first ordering as `publish`.
|
|
234
|
+
return await runReleaseAfterDeploy({
|
|
235
|
+
projectDir,
|
|
220
236
|
origin: def.origin,
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
...(
|
|
237
|
+
deployedUrl: result.url,
|
|
238
|
+
skipSchema: parsed.skipSchema ?? false,
|
|
239
|
+
...(parsed.name !== undefined ? { name: parsed.name } : {}),
|
|
240
|
+
...(parsed.otp !== undefined ? { otp: parsed.otp } : {}),
|
|
224
241
|
...(parsed.installByDefault ? { installByDefault: true } : {}),
|
|
225
242
|
})
|
|
226
243
|
}
|
|
227
244
|
return 0
|
|
228
245
|
}
|
|
229
246
|
|
|
230
|
-
/**
|
|
231
|
-
* Register the just-deployed URL in the admin catalog by shelling out to the
|
|
232
|
-
* operator CLI (`astrale domain publish`). Deliberately a subprocess, not a
|
|
233
|
-
* library call: all credential/admin-target resolution lives in `@astrale-os/
|
|
234
|
-
* astrale` and we don't want it (or a kernel client) pulled into this build
|
|
235
|
-
* tool — we only own the fresh URL. A missing `astrale` is reported with the
|
|
236
|
-
* exact line to run by hand, so a deploy that already succeeded isn't a dead end.
|
|
237
|
-
*/
|
|
238
|
-
async function publishToAdmin(args: {
|
|
239
|
-
origin: string
|
|
240
|
-
name: string
|
|
241
|
-
url: string
|
|
242
|
-
description?: string
|
|
243
|
-
installByDefault?: boolean
|
|
244
|
-
}): Promise<number> {
|
|
245
|
-
// `--public-url`, not `--url`: the operator CLI reserves `--url` for kernel
|
|
246
|
-
// targeting, so the domain's public address rides its own flag.
|
|
247
|
-
const cliArgs = [
|
|
248
|
-
'domain',
|
|
249
|
-
'publish',
|
|
250
|
-
'--origin',
|
|
251
|
-
args.origin,
|
|
252
|
-
'--name',
|
|
253
|
-
args.name,
|
|
254
|
-
'--public-url',
|
|
255
|
-
args.url,
|
|
256
|
-
]
|
|
257
|
-
if (args.description) cliArgs.push('--description', args.description)
|
|
258
|
-
if (args.installByDefault) cliArgs.push('--install-by-default')
|
|
259
|
-
|
|
260
|
-
info(`publishing to the admin catalog → astrale ${cliArgs.join(' ')}`)
|
|
261
|
-
return await new Promise<number>((resolveCode) => {
|
|
262
|
-
const child = spawn('astrale', cliArgs, { stdio: 'inherit' })
|
|
263
|
-
child.on('error', (err) => {
|
|
264
|
-
if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
265
|
-
error(
|
|
266
|
-
`\`astrale\` CLI not found on PATH. The deploy succeeded — publish it by hand:\n` +
|
|
267
|
-
` astrale ${cliArgs.join(' ')}`,
|
|
268
|
-
)
|
|
269
|
-
} else {
|
|
270
|
-
error(`failed to run \`astrale domain publish\`: ${err.message}`)
|
|
271
|
-
}
|
|
272
|
-
resolveCode(1)
|
|
273
|
-
})
|
|
274
|
-
child.on('exit', (code) => resolveCode(code ?? 1))
|
|
275
|
-
})
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/** Best-effort read of the project's package.json `name`/`description` (publish defaults). */
|
|
279
|
-
function readPackageMeta(projectDir: string): { name?: string; description?: string } {
|
|
280
|
-
try {
|
|
281
|
-
const pkg = JSON.parse(readFileSync(join(projectDir, 'package.json'), 'utf8')) as {
|
|
282
|
-
name?: string
|
|
283
|
-
description?: string
|
|
284
|
-
}
|
|
285
|
-
return { name: pkg.name, description: pkg.description }
|
|
286
|
-
} catch {
|
|
287
|
-
return {}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
247
|
async function runWatch(args: {
|
|
292
248
|
adapter: DomainAdapter<unknown>
|
|
293
249
|
params: unknown
|
|
294
250
|
paramOverrides: Record<string, unknown>
|
|
295
251
|
projectDir: string
|
|
296
252
|
specPath: string
|
|
297
|
-
clientDir?: string
|
|
298
253
|
secrets: Record<string, string>
|
|
299
254
|
domain: DomainInfo
|
|
300
255
|
env: string
|
|
301
256
|
def: DeployConfig
|
|
302
257
|
configPath: string
|
|
303
258
|
}): Promise<number> {
|
|
304
|
-
const { adapter, params, projectDir, specPath,
|
|
259
|
+
const { adapter, params, projectDir, specPath, secrets, domain, env, def } = args
|
|
305
260
|
let reloads = 0
|
|
306
261
|
const onReload = () => {
|
|
307
262
|
reloads += 1
|
|
@@ -310,7 +265,6 @@ async function runWatch(args: {
|
|
|
310
265
|
const handle: WatchHandle = await adapter.watch(params, {
|
|
311
266
|
projectDir,
|
|
312
267
|
specPath,
|
|
313
|
-
...(clientDir ? { clientDir } : {}),
|
|
314
268
|
secrets,
|
|
315
269
|
domain,
|
|
316
270
|
env,
|
|
@@ -326,7 +280,6 @@ async function runWatch(args: {
|
|
|
326
280
|
paramOverrides: args.paramOverrides,
|
|
327
281
|
projectDir,
|
|
328
282
|
specPath,
|
|
329
|
-
...(clientDir ? { clientDir } : {}),
|
|
330
283
|
url: handle.url,
|
|
331
284
|
onReload,
|
|
332
285
|
})
|
|
@@ -368,7 +321,6 @@ export function watchConfigForRegen(args: {
|
|
|
368
321
|
paramOverrides: Record<string, unknown>
|
|
369
322
|
projectDir: string
|
|
370
323
|
specPath: string
|
|
371
|
-
clientDir?: string
|
|
372
324
|
url: string
|
|
373
325
|
onReload: () => void
|
|
374
326
|
}): () => void {
|
|
@@ -409,7 +361,6 @@ export function watchConfigForRegen(args: {
|
|
|
409
361
|
await adapter.regenerate(params, {
|
|
410
362
|
projectDir: args.projectDir,
|
|
411
363
|
specPath: args.specPath,
|
|
412
|
-
...(args.clientDir ? { clientDir: args.clientDir } : {}),
|
|
413
364
|
secrets: loadSecrets(adapter, params, args.projectDir),
|
|
414
365
|
domain,
|
|
415
366
|
env: args.env,
|
|
@@ -502,7 +453,7 @@ function loadSecrets(
|
|
|
502
453
|
const file = adapter.secretsFile?.(params)
|
|
503
454
|
if (!file) return {}
|
|
504
455
|
const abs = isAbsolute(file) ? file : join(projectDir, file)
|
|
505
|
-
return
|
|
456
|
+
return loadDeclaredSecrets(abs, file)
|
|
506
457
|
}
|
|
507
458
|
|
|
508
459
|
function findConfig(dir: string): string | undefined {
|
|
@@ -521,11 +472,26 @@ function toDomainInfo(def: DeployConfig): DomainInfo {
|
|
|
521
472
|
// Presence comes from the definition the author wired — never a folder probe.
|
|
522
473
|
hasViews: def.views !== undefined,
|
|
523
474
|
hasFunctions: def.functions !== undefined,
|
|
524
|
-
|
|
475
|
+
mountedViews: collectMountedViews(def.views),
|
|
525
476
|
hasDeps: def.deps !== undefined,
|
|
526
477
|
}
|
|
527
478
|
}
|
|
528
479
|
|
|
480
|
+
function collectMountedViews(views: DeployConfig['views']): DomainInfo['mountedViews'] {
|
|
481
|
+
if (!views) return []
|
|
482
|
+
const mounted: DomainInfo['mountedViews'] = []
|
|
483
|
+
for (const [slug, def] of Object.entries(views)) {
|
|
484
|
+
const mount = (def as { mount?: unknown }).mount
|
|
485
|
+
if (typeof mount !== 'string' || mount.length === 0) continue
|
|
486
|
+
mounted.push({ slug, mount: normalizeMount(mount) })
|
|
487
|
+
}
|
|
488
|
+
return mounted
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function normalizeMount(mount: string): string {
|
|
492
|
+
return `/${mount.replace(/^\/+/, '')}`
|
|
493
|
+
}
|
|
494
|
+
|
|
529
495
|
async function loadConfig(path: string, opts?: { fresh: boolean }): Promise<DeployConfig> {
|
|
530
496
|
// Re-importing an EDITED file: Bun's ESM registry is keyed by path and never
|
|
531
497
|
// re-reads the source — a `?reload=N` query re-EVALUATES but serves the
|
|
@@ -563,12 +529,19 @@ export function parseArgs(argv: readonly string[]): ParsedArgs {
|
|
|
563
529
|
// catalog after a successful deploy. The `publish` command implies it.
|
|
564
530
|
const publish = rest.includes('--publish')
|
|
565
531
|
const installByDefault = rest.includes('--install-by-default')
|
|
532
|
+
// `--dry-run` (publish): pack + `npm publish --dry-run` and skip the catalog
|
|
533
|
+
// register. A boolean flag, filtered out of `positionals` below.
|
|
534
|
+
const dryRun = rest.includes('--dry-run')
|
|
535
|
+
// Publish modes: `--schema` = schema only · `--skip-schema` = catalog only.
|
|
536
|
+
const schemaOnly = rest.includes('--schema')
|
|
537
|
+
const skipSchema = rest.includes('--skip-schema')
|
|
566
538
|
// `--port <n>` / `--port=<n>`: consume the flag AND its value so neither
|
|
567
539
|
// leaks into the positionals (a bare `8788` would be read as the env name).
|
|
568
540
|
let port: number | undefined
|
|
569
541
|
let host: string | undefined
|
|
570
542
|
let name: string | undefined
|
|
571
543
|
let publicUrl: string | undefined
|
|
544
|
+
let otp: string | undefined
|
|
572
545
|
const cleaned: string[] = []
|
|
573
546
|
for (let i = 0; i < rest.length; i++) {
|
|
574
547
|
const a = rest[i]!
|
|
@@ -596,17 +569,38 @@ export function parseArgs(argv: readonly string[]): ParsedArgs {
|
|
|
596
569
|
throw new Error('--public-url needs a value (the address the catalog points at)')
|
|
597
570
|
} else if (a.startsWith('--public-url=')) {
|
|
598
571
|
publicUrl = a.slice('--public-url='.length)
|
|
572
|
+
} else if (a === '--otp') {
|
|
573
|
+
otp = rest[++i]
|
|
574
|
+
if (!otp) throw new Error('--otp needs a value (your 2FA one-time password)')
|
|
575
|
+
} else if (a.startsWith('--otp=')) {
|
|
576
|
+
otp = a.slice('--otp='.length)
|
|
599
577
|
} else {
|
|
600
578
|
cleaned.push(a)
|
|
601
579
|
}
|
|
602
580
|
}
|
|
603
581
|
const positionals = cleaned.filter((a) => !a.startsWith('-'))
|
|
604
582
|
|
|
583
|
+
// `--dry-run` belongs ONLY to `publish` — never let it silently no-op a deploy.
|
|
584
|
+
if (dryRun && cmd !== 'publish') throw new Error('`--dry-run` is only valid for `publish`.')
|
|
585
|
+
// `--otp` feeds the schema publish (publish, or deploy/prod `--publish`).
|
|
586
|
+
if (otp !== undefined && !['publish', 'deploy', 'prod'].includes(cmd ?? ''))
|
|
587
|
+
throw new Error('`--otp` is only valid for the publish / deploy commands.')
|
|
588
|
+
// `--schema` (schema only) / `--skip-schema` (catalog only): publish-only, opposite.
|
|
589
|
+
if (schemaOnly && cmd !== 'publish') throw new Error('`--schema` is only valid for `publish`.')
|
|
590
|
+
if (schemaOnly && skipSchema)
|
|
591
|
+
throw new Error(
|
|
592
|
+
'`--schema` (schema only) and `--skip-schema` (catalog only) are mutually exclusive.',
|
|
593
|
+
)
|
|
594
|
+
|
|
605
595
|
// Publish-related fields shared by deploy/prod/publish (publish itself is
|
|
606
|
-
// gated per-command: opt-in via `--publish`, always-on for `publish`).
|
|
596
|
+
// gated per-command: opt-in via `--publish`, always-on for `publish`). `otp` /
|
|
597
|
+
// `skipSchema` ride along because the schema-publish step runs on the
|
|
598
|
+
// `publish` command AND the `deploy --publish` tail.
|
|
607
599
|
const pub = {
|
|
608
600
|
...(name !== undefined ? { name } : {}),
|
|
609
601
|
...(installByDefault ? { installByDefault } : {}),
|
|
602
|
+
...(otp !== undefined ? { otp } : {}),
|
|
603
|
+
...(skipSchema ? { skipSchema } : {}),
|
|
610
604
|
}
|
|
611
605
|
|
|
612
606
|
switch (cmd) {
|
|
@@ -626,15 +620,17 @@ export function parseArgs(argv: readonly string[]): ParsedArgs {
|
|
|
626
620
|
return { command: 'deploy', env, watch, ...(publish ? { publish } : {}), ...pub }
|
|
627
621
|
}
|
|
628
622
|
case 'publish':
|
|
629
|
-
//
|
|
630
|
-
//
|
|
631
|
-
//
|
|
623
|
+
// Release: publish ./schema + register the deployed URL (no deploy).
|
|
624
|
+
// `--schema` = schema only · `--skip-schema` = catalog only · `--dry-run`
|
|
625
|
+
// packs the schema and skips the catalog register.
|
|
632
626
|
return {
|
|
633
627
|
command: 'publish',
|
|
634
628
|
env: positionals[0] ?? 'prod',
|
|
635
629
|
watch: false,
|
|
636
630
|
...pub,
|
|
637
631
|
...(publicUrl !== undefined ? { publicUrl } : {}),
|
|
632
|
+
...(dryRun ? { dryRun } : {}),
|
|
633
|
+
...(schemaOnly ? { schemaOnly } : {}),
|
|
638
634
|
}
|
|
639
635
|
case 'build':
|
|
640
636
|
// Spec-only — no env resolution happens on this path.
|
|
@@ -650,23 +646,6 @@ function rel(from: string, to: string): string {
|
|
|
650
646
|
|
|
651
647
|
// ── output ───────────────────────────────────────────────────────────────
|
|
652
648
|
|
|
653
|
-
const GREEN = '\x1b[32m'
|
|
654
|
-
const DIM = '\x1b[2m'
|
|
655
|
-
const BOLD = '\x1b[1m'
|
|
656
|
-
const YELLOW = '\x1b[33m'
|
|
657
|
-
const RED = '\x1b[31m'
|
|
658
|
-
const RESET = '\x1b[0m'
|
|
659
|
-
|
|
660
|
-
function info(msg: string): void {
|
|
661
|
-
process.stdout.write(`${DIM}›${RESET} ${msg}\n`)
|
|
662
|
-
}
|
|
663
|
-
function warn(msg: string): void {
|
|
664
|
-
process.stderr.write(`${YELLOW}!${RESET} ${msg}\n`)
|
|
665
|
-
}
|
|
666
|
-
function error(msg: string): void {
|
|
667
|
-
process.stderr.write(`${RED}✗${RESET} ${msg}\n`)
|
|
668
|
-
}
|
|
669
|
-
|
|
670
649
|
function printDevReady(url: string, domain: DomainInfo): void {
|
|
671
650
|
process.stdout.write(
|
|
672
651
|
`\n${GREEN}✓${RESET} ${BOLD}${domain.origin}${RESET} running (dev, hot-reload)\n` +
|
|
@@ -702,13 +681,18 @@ function printUsage(msg?: string): void {
|
|
|
702
681
|
` astrale-domain dev # deploy dev --watch (hot-reload, prints URL)\n` +
|
|
703
682
|
` astrale-domain prod # deploy prod\n` +
|
|
704
683
|
` astrale-domain deploy <env> # deploy any env key (--watch optional)\n` +
|
|
705
|
-
` astrale-domain publish [env] #
|
|
684
|
+
` astrale-domain publish [env] # RELEASE: publish ./schema to npm (if any) + register the deployed URL\n` +
|
|
706
685
|
` astrale-domain build # rebuild the diagnostic spec only\n` +
|
|
707
686
|
`\nFlags:\n` +
|
|
708
|
-
` --publish # on deploy/prod: ALSO register the deployed URL
|
|
687
|
+
` --publish # on deploy/prod: ALSO release (publish ./schema + register the deployed URL)\n` +
|
|
688
|
+
` --schema # (publish) publish ONLY the ./schema package — no catalog, no config\n` +
|
|
689
|
+
` --skip-schema # (publish / deploy --publish) register the catalog only; don't publish ./schema\n` +
|
|
709
690
|
` --name <slug> # registry name to publish under (default: the origin's first label)\n` +
|
|
710
691
|
` --public-url <url> # (publish) address the catalog points at (default: https://<origin>)\n` +
|
|
711
692
|
` --install-by-default # mark the published domain for install on every new instance\n` +
|
|
712
|
-
|
|
693
|
+
` --dry-run # (publish) pack + npm publish --dry-run; never ships, skips catalog\n` +
|
|
694
|
+
` --otp <code> # (publish / deploy --publish) 2FA code for npm publish\n` +
|
|
695
|
+
`\n catalog register shells out to \`astrale domain publish\` (needs \`astrale\` on PATH).\n` +
|
|
696
|
+
` schema publish uses \`pnpm pack\` then \`npm publish\` (needs \`pnpm\` + \`npm\`; npm handles 2FA).\n\n`,
|
|
713
697
|
)
|
|
714
698
|
}
|
package/src/cli/spec.ts
CHANGED
|
@@ -33,6 +33,7 @@ export async function buildProjectSpec(
|
|
|
33
33
|
methods: def.methods,
|
|
34
34
|
...(def.views ? { views: def.views } : {}),
|
|
35
35
|
...(def.functions ? { remoteFunctions: def.functions } : {}),
|
|
36
|
+
...(def.path ? { path: def.path } : {}),
|
|
36
37
|
} as RemoteDomainConfig<Schema, unknown>
|
|
37
38
|
|
|
38
39
|
const domain = defineRemoteDomain<unknown>()(config)
|
package/src/config/adapter.ts
CHANGED
|
@@ -32,17 +32,18 @@ export interface DomainInfo {
|
|
|
32
32
|
/** Optional Astrale Path called by the kernel after install (as __SYSTEM__). */
|
|
33
33
|
postInstall?: string
|
|
34
34
|
/**
|
|
35
|
-
* Whether the domain declares
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* only when true. `hasClient` governs the WORKER's `/ui` hook specifically
|
|
39
|
-
* (present whenever the domain has a client, even on managed deploys that ship
|
|
40
|
-
* the built assets separately and pass no `clientDir`); the wrangler
|
|
41
|
-
* `assets.directory` binding tracks `clientDir` instead.
|
|
35
|
+
* Whether the domain declares Views / standalone Functions — read from the
|
|
36
|
+
* `defineDomain` definition, NOT probed from the filesystem. The adapter
|
|
37
|
+
* codegen imports the corresponding module only when true.
|
|
42
38
|
*/
|
|
43
39
|
hasViews: boolean
|
|
44
40
|
hasFunctions: boolean
|
|
45
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Views whose binding is backed by a worker-relative SPA mount. This is domain
|
|
43
|
+
* contract metadata (`defineView({ mount })`), not a frontend source folder:
|
|
44
|
+
* adapters decide, per env, which client assets serve these mounts.
|
|
45
|
+
*/
|
|
46
|
+
mountedViews: Array<{ slug: string; mount: string }>
|
|
46
47
|
/**
|
|
47
48
|
* Whether the domain declares a `deps` mapper (`defineDomain({ deps })`).
|
|
48
49
|
* When true the adapter codegen imports it from the domain's fixed `deps`
|
|
@@ -58,8 +59,6 @@ export interface WatchCtx {
|
|
|
58
59
|
projectDir: string
|
|
59
60
|
/** Absolute path where the CLI writes the diagnostic `spec.json`. */
|
|
60
61
|
specPath: string
|
|
61
|
-
/** Absolute path to the client SPA dir, when the domain declares a `client`. */
|
|
62
|
-
clientDir?: string
|
|
63
62
|
/** Flat secret map loaded from the env's `secrets` file — injected locally in dev. */
|
|
64
63
|
secrets: Record<string, string>
|
|
65
64
|
/** Domain metadata for codegen. */
|
|
@@ -75,7 +74,6 @@ export interface DeployCtx {
|
|
|
75
74
|
specPath: string
|
|
76
75
|
/** Flat secret map loaded from the env's `secrets` file (gitignored). */
|
|
77
76
|
secrets: Record<string, string>
|
|
78
|
-
clientDir?: string
|
|
79
77
|
domain: DomainInfo
|
|
80
78
|
/** The env key being deployed (e.g. 'dev' | 'prod' | 'canary'). */
|
|
81
79
|
env: string
|