@astrale-os/sdk 0.1.5 → 0.1.7

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.
Files changed (108) hide show
  1. package/dist/auth/verify.d.ts +2 -0
  2. package/dist/auth/verify.d.ts.map +1 -1
  3. package/dist/auth/verify.js +81 -26
  4. package/dist/auth/verify.js.map +1 -1
  5. package/dist/cli/bin.d.ts +7 -0
  6. package/dist/cli/bin.d.ts.map +1 -0
  7. package/dist/cli/bin.js +15 -0
  8. package/dist/cli/bin.js.map +1 -0
  9. package/dist/cli/dotenv.d.ts +13 -0
  10. package/dist/cli/dotenv.d.ts.map +1 -0
  11. package/dist/cli/dotenv.js +46 -0
  12. package/dist/cli/dotenv.js.map +1 -0
  13. package/dist/cli/index.d.ts +15 -0
  14. package/dist/cli/index.d.ts.map +1 -0
  15. package/dist/cli/index.js +15 -0
  16. package/dist/cli/index.js.map +1 -0
  17. package/dist/cli/run.d.ts +79 -0
  18. package/dist/cli/run.d.ts.map +1 -0
  19. package/dist/cli/run.js +569 -0
  20. package/dist/cli/run.js.map +1 -0
  21. package/dist/cli/spec.d.ts +19 -0
  22. package/dist/cli/spec.d.ts.map +1 -0
  23. package/dist/cli/spec.js +31 -0
  24. package/dist/cli/spec.js.map +1 -0
  25. package/dist/config/adapter.d.ts +140 -0
  26. package/dist/config/adapter.d.ts.map +1 -0
  27. package/dist/config/adapter.js +40 -0
  28. package/dist/config/adapter.js.map +1 -0
  29. package/dist/config/define-domain.d.ts +112 -0
  30. package/dist/config/define-domain.d.ts.map +1 -0
  31. package/dist/config/define-domain.js +98 -0
  32. package/dist/config/define-domain.js.map +1 -0
  33. package/dist/config/deploy.d.ts +28 -0
  34. package/dist/config/deploy.d.ts.map +1 -0
  35. package/dist/config/deploy.js +24 -0
  36. package/dist/config/deploy.js.map +1 -0
  37. package/dist/config/index.d.ts +21 -0
  38. package/dist/config/index.d.ts.map +1 -0
  39. package/dist/config/index.js +18 -0
  40. package/dist/config/index.js.map +1 -0
  41. package/dist/define/remote-function.d.ts +19 -11
  42. package/dist/define/remote-function.d.ts.map +1 -1
  43. package/dist/define/remote-function.js.map +1 -1
  44. package/dist/dispatch/call-remote.d.ts +7 -3
  45. package/dist/dispatch/call-remote.d.ts.map +1 -1
  46. package/dist/dispatch/call-remote.js.map +1 -1
  47. package/dist/dispatch/dispatcher.d.ts.map +1 -1
  48. package/dist/dispatch/dispatcher.js +8 -4
  49. package/dist/dispatch/dispatcher.js.map +1 -1
  50. package/dist/dispatch/index.d.ts +1 -1
  51. package/dist/dispatch/index.d.ts.map +1 -1
  52. package/dist/dispatch/index.js.map +1 -1
  53. package/dist/dispatch/self.d.ts +46 -10
  54. package/dist/dispatch/self.d.ts.map +1 -1
  55. package/dist/dispatch/self.js +65 -8
  56. package/dist/dispatch/self.js.map +1 -1
  57. package/dist/domain/define.d.ts +3 -3
  58. package/dist/domain/define.js +3 -3
  59. package/dist/index.d.ts +5 -4
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +8 -2
  62. package/dist/index.js.map +1 -1
  63. package/dist/method/class.d.ts.map +1 -1
  64. package/dist/method/class.js.map +1 -1
  65. package/dist/method/context.d.ts +32 -7
  66. package/dist/method/context.d.ts.map +1 -1
  67. package/dist/method/index.d.ts +1 -1
  68. package/dist/method/index.d.ts.map +1 -1
  69. package/dist/method/single.d.ts +16 -11
  70. package/dist/method/single.d.ts.map +1 -1
  71. package/dist/method/single.js.map +1 -1
  72. package/dist/server/domain-entry.d.ts +67 -0
  73. package/dist/server/domain-entry.d.ts.map +1 -0
  74. package/dist/server/domain-entry.js +58 -0
  75. package/dist/server/domain-entry.js.map +1 -0
  76. package/dist/server/index.d.ts +3 -1
  77. package/dist/server/index.d.ts.map +1 -1
  78. package/dist/server/index.js +2 -1
  79. package/dist/server/index.js.map +1 -1
  80. package/dist/server/worker-entry.d.ts +57 -5
  81. package/dist/server/worker-entry.d.ts.map +1 -1
  82. package/dist/server/worker-entry.js +108 -24
  83. package/dist/server/worker-entry.js.map +1 -1
  84. package/package.json +12 -3
  85. package/src/auth/verify.ts +89 -28
  86. package/src/cli/bin.ts +15 -0
  87. package/src/cli/dotenv.ts +45 -0
  88. package/src/cli/index.ts +15 -0
  89. package/src/cli/run.ts +675 -0
  90. package/src/cli/spec.ts +42 -0
  91. package/src/config/adapter.ts +172 -0
  92. package/src/config/define-domain.ts +218 -0
  93. package/src/config/deploy.ts +35 -0
  94. package/src/config/index.ts +31 -0
  95. package/src/define/remote-function.ts +42 -13
  96. package/src/dispatch/call-remote.ts +7 -2
  97. package/src/dispatch/dispatcher.ts +8 -4
  98. package/src/dispatch/index.ts +1 -1
  99. package/src/dispatch/self.ts +96 -10
  100. package/src/domain/define.ts +3 -3
  101. package/src/index.ts +25 -4
  102. package/src/method/class.ts +4 -3
  103. package/src/method/context.ts +38 -7
  104. package/src/method/index.ts +1 -1
  105. package/src/method/single.ts +30 -11
  106. package/src/server/domain-entry.ts +113 -0
  107. package/src/server/index.ts +3 -1
  108. package/src/server/worker-entry.ts +122 -23
@@ -17,6 +17,8 @@ export type VerifiedInbound = {
17
17
  /** Delegation — scoped caller permissions as kernel-signed credential */
18
18
  delegation: Delegation;
19
19
  };
20
+ /** Clear cached JWKS resolvers. Used in tests when keys rotate between fixtures. */
21
+ export declare function clearJwksCache(): void;
20
22
  /**
21
23
  * Verify an inbound delegation credential using kernel-core's verification.
22
24
  *
@@ -1 +1 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/auth/verify.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,UAAU,EAEV,kBAAkB,EACnB,MAAM,yBAAyB,CAAA;AAUhC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAKtD,MAAM,MAAM,eAAe,GAAG;IAC5B,2DAA2D;IAC3D,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAA;IACd,2DAA2D;IAC3D,WAAW,EAAE,WAAW,CAAA;IACxB,yEAAyE;IACzE,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AA4DD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,eAAe,EAC3B,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,eAAe,CAAC,CA+B1B"}
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/auth/verify.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,UAAU,EAEV,kBAAkB,EACnB,MAAM,yBAAyB,CAAA;AAYhC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAKtD,MAAM,MAAM,eAAe,GAAG;IAC5B,2DAA2D;IAC3D,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAA;IACd,2DAA2D;IAC3D,WAAW,EAAE,WAAW,CAAA;IACxB,yEAAyE;IACzE,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAkBD,oFAAoF;AACpF,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAiFD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,eAAe,EAC3B,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,eAAe,CAAC,CA+C1B"}
@@ -5,19 +5,68 @@
5
5
  * (CredentialMethodResolver, MethodRegistry) instead of manual JWT handling.
6
6
  * Not tied to JWT — supports any credential method kernel-core provides.
7
7
  */
8
- import { CredentialMethodResolver, MethodRegistry, verifyAudience, verifyCredential, } from '@astrale-os/kernel-core';
8
+ import { CredentialMethodResolver, MethodRegistry, SignatureVerificationError, SigningKeyNotFoundError, verifyAudience, verifyCredential, } from '@astrale-os/kernel-core';
9
9
  import { createLocalJWKSet, createRemoteJWKSet } from 'jose';
10
10
  import { derivePublicJwk } from '../server/jwks';
11
11
  import { canonicalizeServingUrl } from '../server/serving-url';
12
12
  const methodResolver = new CredentialMethodResolver(new MethodRegistry());
13
+ // JWKS resolvers cached per JWKS URL (module-level, like the pools/selfIds
14
+ // Maps in kernel-client.ts). jose handles freshness WITHIN a resolver: 10min
15
+ // max-age, 30s fetch cooldown, and auto-refetch on kid-miss when not cooling
16
+ // down. The one gap — issuer restarts with new keys while the cooldown pins
17
+ // the old set (the incident that got a prior indefinite cache removed) — is
18
+ // covered by evict-and-retry-once in `verifyInboundCredential`, so indefinite
19
+ // Map residency is safe and the per-call JWKS fetch is gone.
20
+ const remoteResolvers = new Map();
21
+ // Self-issued credentials verify against the worker's own in-memory key;
22
+ // cache the local JWKS per canonical self-issuer (one key per worker) so the
23
+ // public-JWK derivation isn't redone on every request.
24
+ const localResolvers = new Map();
25
+ /** Clear cached JWKS resolvers. Used in tests when keys rotate between fixtures. */
26
+ export function clearJwksCache() {
27
+ remoteResolvers.clear();
28
+ localResolvers.clear();
29
+ }
30
+ /**
31
+ * M-28 fix: a bare-slug iss (`mails.localhost`) makes
32
+ * `new URL('mails.localhost/.well-known/jwks.json')` throw "Invalid URL
33
+ * string". The dispatcher's identity map normalizes the iss it signs with,
34
+ * but inbound creds from older clients may still carry the slug form. Coerce
35
+ * to a URL with a default `https://` scheme (matches kernel.astrale.ai
36
+ * canonical form). If the actual receiver is on http://localhost the
37
+ * receiver-side resolver still works because both endpoints are on localhost
38
+ * — but for prod targets requiring TLS this is the right default.
39
+ */
40
+ function jwksUrlFor(issuer) {
41
+ const normalized = /^https?:\/\//.test(issuer) ? issuer : `https://${issuer}`;
42
+ return `${normalized}/.well-known/jwks.json`;
43
+ }
44
+ function getRemoteResolver(jwksUrl) {
45
+ let resolver = remoteResolvers.get(jwksUrl);
46
+ if (!resolver) {
47
+ resolver = createRemoteJWKSet(new URL(jwksUrl));
48
+ remoteResolvers.set(jwksUrl, resolver);
49
+ }
50
+ return resolver;
51
+ }
52
+ function getLocalResolver(selfIssuer, privateKey) {
53
+ let resolver = localResolvers.get(selfIssuer);
54
+ if (!resolver) {
55
+ resolver = createLocalJWKSet({ keys: [derivePublicJwk(privateKey)] });
56
+ localResolvers.set(selfIssuer, resolver);
57
+ }
58
+ return resolver;
59
+ }
13
60
  /**
14
61
  * Build the key resolver for one verifying server. Captures `config` so it can
15
62
  * short-circuit the server's OWN issuer (`config.issuer`): a self-issued
16
63
  * credential is verified against the in-memory public key, never fetched — a
17
64
  * Worker can't fetch its own hostname, and it already holds the key. Every other
18
- * issuer is resolved live via JWKS (`createRemoteJWKSet`).
65
+ * issuer is resolved via the cached per-URL JWKS resolvers above; every JWKS
66
+ * URL touched is recorded in `resolvedJwksUrls` so the caller can evict
67
+ * exactly those resolvers if verification fails on an unknown signing key.
19
68
  */
20
- function makeResolveKeys(config) {
69
+ function makeResolveKeys(config, resolvedJwksUrls) {
21
70
  // The worker's own canonical iss. STRICT: `config.issuer` is the serving URL
22
71
  // by contract (both producers — buildIdentityMap / buildAuxIdentityMap — feed
23
72
  // it `canonicalizeServingUrl(config.url)`), so a value that doesn't parse is
@@ -26,13 +75,6 @@ function makeResolveKeys(config) {
26
75
  // worker's own hostname — which Cloudflare forbids — turning a config bug
27
76
  // into an opaque per-call failure.
28
77
  const selfIssuer = canonicalizeServingUrl(config.issuer);
29
- // TODO(cache): Re-add JWKS caching with a short TTL or kid-miss retry.
30
- // A prior implementation cached `createRemoteJWKSet` per issuer URL
31
- // indefinitely. jose's internal cache (30s cooldown, 10min max-age) caused
32
- // stale keys when the issuer restarted — the resolver served old keys and
33
- // jose refused to refetch within the cooldown window. On CF Workers the
34
- // module-level Map persisted across requests, making it worse. For now we
35
- // create a fresh resolver per call (jose deduplicates concurrent fetches).
36
78
  return async (issuer, _method, _kid) => {
37
79
  const url = issuer;
38
80
  // Self-issued credential (iss == this worker's own serving URL): resolve
@@ -47,20 +89,12 @@ function makeResolveKeys(config) {
47
89
  canonical = undefined;
48
90
  }
49
91
  if (canonical === selfIssuer) {
50
- return createLocalJWKSet({ keys: [derivePublicJwk(config.privateKey)] });
92
+ return getLocalResolver(selfIssuer, config.privateKey);
51
93
  }
52
94
  }
53
- // M-28 fix: a bare-slug iss (`mails.localhost`) makes
54
- // `new URL('mails.localhost/.well-known/jwks.json')` throw "Invalid
55
- // URL string". The dispatcher's identity map normalizes the iss it
56
- // signs with, but inbound creds from older clients may still carry
57
- // the slug form. Coerce to a URL with a default `https://` scheme
58
- // (matches kernel.astrale.ai canonical form). If the actual receiver
59
- // is on http://localhost the receiver-side resolver still works
60
- // because both endpoints are on localhost — but for prod targets
61
- // requiring TLS this is the right default.
62
- const normalized = /^https?:\/\//.test(url) ? url : `https://${url}`;
63
- return createRemoteJWKSet(new URL(`${normalized}/.well-known/jwks.json`));
95
+ const jwksUrl = jwksUrlFor(url);
96
+ resolvedJwksUrls.add(jwksUrl);
97
+ return getRemoteResolver(jwksUrl);
64
98
  };
65
99
  }
66
100
  /**
@@ -70,10 +104,31 @@ function makeResolveKeys(config) {
70
104
  */
71
105
  export async function verifyInboundCredential(credential, config) {
72
106
  // Verify using kernel-core's credential verification pipeline
73
- const verified = await verifyCredential({
74
- methodResolver,
75
- resolveKeys: makeResolveKeys(config),
76
- }, credential);
107
+ const resolvedJwksUrls = new Set();
108
+ const deps = { methodResolver, resolveKeys: makeResolveKeys(config, resolvedJwksUrls) };
109
+ let verified;
110
+ try {
111
+ verified = await verifyCredential(deps, credential);
112
+ }
113
+ catch (error) {
114
+ // A cached resolver can hold a stale key set after the issuer rotates:
115
+ // - new kid → jose kid-misses but its 30s fetch cooldown blocks the
116
+ // refetch (SigningKeyNotFoundError) — the incident that got a prior
117
+ // indefinite cache removed;
118
+ // - SAME kid, new key material (kernel kids derive from the subject, so
119
+ // a re-keyed issuer reuses its kid) → the signature check fails
120
+ // (SignatureVerificationError).
121
+ // Both: evict the resolver(s) this verification touched and retry ONCE
122
+ // with fresh ones. Forged-token spam thus costs at most one JWKS fetch
123
+ // per bad credential — equal to the uncached per-call baseline, never
124
+ // worse. An empty set means self-issued — refetching can't help, rethrow.
125
+ const staleKeySuspect = error instanceof SigningKeyNotFoundError || error instanceof SignatureVerificationError;
126
+ if (!staleKeySuspect || resolvedJwksUrls.size === 0)
127
+ throw error;
128
+ for (const url of resolvedJwksUrls)
129
+ remoteResolvers.delete(url);
130
+ verified = await verifyCredential(deps, credential);
131
+ }
77
132
  // Validate audience matches this function's issuer (its serving URL).
78
133
  // kernel-core's verifyAudience compares canonically.
79
134
  verifyAudience(verified, config.issuer);
@@ -1 +1 @@
1
- {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/auth/verify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/auth/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * `astrale-domain` bin entry. Runs under bun (native TS) so it can import the
4
+ * project's `astrale.config.ts` directly — matching the `astrale` CLI.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":";AACA;;;GAGG"}
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * `astrale-domain` bin entry. Runs under bun (native TS) so it can import the
4
+ * project's `astrale.config.ts` directly — matching the `astrale` CLI.
5
+ */
6
+ import { run } from './run';
7
+ run(process.argv.slice(2))
8
+ .then((code) => process.exit(code))
9
+ .catch((err) => {
10
+ process.stderr.write(`\x1b[31m✗\x1b[0m ${err.message ?? String(err)}\n`);
11
+ if (process.env.DEBUG)
12
+ process.stderr.write(`${err.stack ?? ''}\n`);
13
+ process.exit(1);
14
+ });
15
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAE3B,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KACvB,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;KAClC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAqB,GAAa,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACnF,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAI,GAAa,CAAC,KAAK,IAAI,EAAE,IAAI,CAAC,CAAA;IAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Minimal dotenv parser — the secrets-file boundary.
3
+ *
4
+ * `secrets: '.env.<env>'` in an adapter's params points a gitignored file whose
5
+ * entire contents are secrets. `loadDotenvFile` reads it into a flat
6
+ * `Record<string,string>` the CLI hands the adapter (injected into the local
7
+ * runtime in dev, pushed to a secret store in prod). No `process.env` mutation,
8
+ * no interpolation magic beyond `${VAR}` against earlier keys in the same file.
9
+ */
10
+ export declare function parseDotenv(contents: string): Record<string, string>;
11
+ /** Read + parse a dotenv file. Returns `{}` if the file is absent (CI-safe). */
12
+ export declare function loadDotenvFile(path: string): Record<string, string>;
13
+ //# sourceMappingURL=dotenv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dotenv.d.ts","sourceRoot":"","sources":["../../src/cli/dotenv.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBpE;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQnE"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Minimal dotenv parser — the secrets-file boundary.
3
+ *
4
+ * `secrets: '.env.<env>'` in an adapter's params points a gitignored file whose
5
+ * entire contents are secrets. `loadDotenvFile` reads it into a flat
6
+ * `Record<string,string>` the CLI hands the adapter (injected into the local
7
+ * runtime in dev, pushed to a secret store in prod). No `process.env` mutation,
8
+ * no interpolation magic beyond `${VAR}` against earlier keys in the same file.
9
+ */
10
+ import { readFileSync } from 'node:fs';
11
+ export function parseDotenv(contents) {
12
+ const out = {};
13
+ for (const raw of contents.split('\n')) {
14
+ const line = raw.trim();
15
+ if (!line || line.startsWith('#'))
16
+ continue;
17
+ const match = /^(?:export\s+)?([A-Za-z_]\w*)\s*=\s*(.*)$/.exec(line);
18
+ if (!match)
19
+ continue;
20
+ const [, key, rawValue] = match;
21
+ let value = rawValue.trim();
22
+ // Single quotes mean a LITERAL value (standard dotenv): no `${VAR}`
23
+ // interpolation, so a secret that legitimately contains a literal `${...}`
24
+ // (e.g. a password) survives intact instead of being silently blanked.
25
+ const singleQuoted = value.length >= 2 && value.startsWith("'") && value.endsWith("'");
26
+ if ((value.length >= 2 && value.startsWith('"') && value.endsWith('"')) || singleQuoted) {
27
+ value = value.slice(1, -1);
28
+ }
29
+ out[key] = singleQuoted
30
+ ? value
31
+ : value.replace(/\$\{(\w+)\}/g, (_, name) => out[name] ?? '');
32
+ }
33
+ return out;
34
+ }
35
+ /** Read + parse a dotenv file. Returns `{}` if the file is absent (CI-safe). */
36
+ export function loadDotenvFile(path) {
37
+ let contents;
38
+ try {
39
+ contents = readFileSync(path, 'utf-8');
40
+ }
41
+ catch {
42
+ return {};
43
+ }
44
+ return parseDotenv(contents);
45
+ }
46
+ //# sourceMappingURL=dotenv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dotenv.js","sourceRoot":"","sources":["../../src/cli/dotenv.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtC,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,GAAG,GAA2B,EAAE,CAAA;IACtC,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;QACvB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QAC3C,MAAM,KAAK,GAAG,2CAA2C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACpE,IAAI,CAAC,KAAK;YAAE,SAAQ;QACpB,MAAM,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAA;QAC/B,IAAI,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAA;QAC3B,oEAAoE;QACpE,2EAA2E;QAC3E,uEAAuE;QACvE,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;QACtF,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,YAAY,EAAE,CAAC;YACxF,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAC5B,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,GAAG,YAAY;YACrB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACzE,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,IAAI,QAAgB,CAAA;IACpB,IAAI,CAAC;QACH,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;IACD,OAAO,WAAW,CAAC,QAAQ,CAAC,CAAA;AAC9B,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `@astrale-os/sdk/cli` — the `astrale-domain` CLI (dev | build | deploy) and
3
+ * the dotenv secrets-file boundary, folded in from the former
4
+ * `@astrale-os/devkit` package.
5
+ *
6
+ * Node-only: the CLI imports `node:fs`/`node:module`/`node:url` and runs under
7
+ * Bun (it imports the project's `astrale.config.ts` directly). This subpath is
8
+ * deliberately NOT re-exported from the package barrel — pulling it into the
9
+ * isomorphic `.` entry would poison browser/worker bundlers that traverse every
10
+ * re-export (the same rule that keeps `./server` and `./deploy` off the barrel).
11
+ * The bin lives at `./bin`.
12
+ */
13
+ export { run, parseArgs } from './run';
14
+ export { parseDotenv, loadDotenvFile } from './dotenv';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `@astrale-os/sdk/cli` — the `astrale-domain` CLI (dev | build | deploy) and
3
+ * the dotenv secrets-file boundary, folded in from the former
4
+ * `@astrale-os/devkit` package.
5
+ *
6
+ * Node-only: the CLI imports `node:fs`/`node:module`/`node:url` and runs under
7
+ * Bun (it imports the project's `astrale.config.ts` directly). This subpath is
8
+ * deliberately NOT re-exported from the package barrel — pulling it into the
9
+ * isomorphic `.` entry would poison browser/worker bundlers that traverse every
10
+ * re-export (the same rule that keeps `./server` and `./deploy` off the barrel).
11
+ * The bin lives at `./bin`.
12
+ */
13
+ export { run, parseArgs } from './run';
14
+ export { parseDotenv, loadDotenvFile } from './dotenv';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The `astrale-domain` CLI — dev | build | deploy.
3
+ *
4
+ * Thin by design: it reads `astrale.config.ts`, resolves `envs[<env>] → params`
5
+ * via the adapter, loads the env's secrets file, then drives `adapter.watch`
6
+ * (dev) or `adapter.deploy` (build+ship). It prints the resulting URL and the
7
+ * exact `astrale domain install <url> --direct` line. It boots no kernel and knows
8
+ * nothing provider-specific — that all lives in the adapter.
9
+ *
10
+ * The diagnostic spec (`.astrale/spec.json`) is written AFTER watch/deploy
11
+ * returns, at the live URL: the install graph (and therefore `schemaHash`)
12
+ * embeds `binding.remoteUrl`s derived from the serving URL, so a spec built at
13
+ * a guessed URL would carry a hash that never matches the worker's `/meta`.
14
+ * Only `astrale-domain build` (no URL exists yet) uses an explicit placeholder
15
+ * and says so.
16
+ *
17
+ * astrale-domain dev # = deploy dev --watch
18
+ * astrale-domain prod # = deploy prod
19
+ * astrale-domain deploy <env> # any env key
20
+ * astrale-domain build # rebuild spec only (placeholder URL)
21
+ * astrale-domain publish [env] # = deploy [prod] then register the URL
22
+ *
23
+ * `publish` (and the `--publish` tail-flag on deploy) deploys, then registers
24
+ * the resulting URL in the admin catalog by SHELLING OUT to the operator CLI
25
+ * (`astrale domain publish --origin --name --public-url`). Auth lives entirely
26
+ * in that CLI — this build tool never touches credentials; it just hands off the
27
+ * fresh URL it alone knows. Requires `astrale` on PATH (the same CLI the deploy
28
+ * footer already points you at for `domain install`).
29
+ */
30
+ import type { DeployConfig } from '../config/deploy';
31
+ type ParsedArgs = {
32
+ command: 'dev' | 'build' | 'deploy';
33
+ env: string;
34
+ watch: boolean;
35
+ /** `--port <n>` (dev only) — overrides the env's local dev port. */
36
+ port?: number;
37
+ /** `--host <url>` (dev only) — public URL of a tunnel/proxy front: binds 0.0.0.0 + pins WORKER_URL. */
38
+ host?: string;
39
+ /** Register the deployed URL in the admin catalog (the `publish` command / `--publish` flag). */
40
+ publish?: boolean;
41
+ /** `--name <slug>` — registry name to publish under (default: package.json `name`). */
42
+ name?: string;
43
+ /** `--install-by-default` — mark the published domain for install on every new instance. */
44
+ installByDefault?: boolean;
45
+ };
46
+ export declare function run(argv: readonly string[]): Promise<number>;
47
+ /**
48
+ * Watch `astrale.config.ts` while `dev` runs: on change, re-import the config
49
+ * (cache-busted), re-resolve env params + secrets, and re-run the adapter's
50
+ * codegen via `adapter.regenerate` — the running dev server (e.g. `wrangler
51
+ * dev`, which watches its generated config + entry) reloads them itself, so a
52
+ * config edit lands without restarting the CLI.
53
+ *
54
+ * Watches the config's DIRECTORY, not the file: editors save via atomic
55
+ * rename, which silently kills an inode-bound watch.
56
+ *
57
+ * Deliberate limits, surfaced to the user instead of half-applied:
58
+ * • origin / adapter changes re-key the worker's identity → restart;
59
+ * • a mid-edit broken config (syntax error, bad env) warns and keeps the
60
+ * previous generation running;
61
+ * • modules the config IMPORTS (e.g. the schema) stay module-cached — only
62
+ * the config file itself is re-evaluated, which covers everything
63
+ * `defineDomain` owns (vars, requires, postInstall, wrangler overlay…).
64
+ */
65
+ export declare function watchConfigForRegen(args: {
66
+ configPath: string;
67
+ initial: DeployConfig;
68
+ env: string;
69
+ /** CLI flag overrides (dev --port / --host) — re-applied on every regen. */
70
+ paramOverrides: Record<string, unknown>;
71
+ projectDir: string;
72
+ specPath: string;
73
+ clientDir?: string;
74
+ url: string;
75
+ onReload: () => void;
76
+ }): () => void;
77
+ export declare function parseArgs(argv: readonly string[]): ParsedArgs;
78
+ export {};
79
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAUH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAOpD,KAAK,UAAU,GAAG;IAChB,OAAO,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,OAAO,CAAA;IACd,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uGAAuG;IACvG,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,iGAAiG;IACjG,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,4FAA4F;IAC5F,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAyIlE;AAqHD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,YAAY,CAAA;IACrB,GAAG,EAAE,MAAM,CAAA;IACX,4EAA4E;IAC5E,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB,GAAG,MAAM,IAAI,CAiFb;AAwGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CA6E7D"}