@astrale-os/cli 1.0.0-beta.3 → 1.0.0-beta.4

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.
@@ -52615,6 +52615,7 @@ var IdpSessionSchema = exports_external2.object({
52615
52615
  }).passthrough();
52616
52616
  var BUILTIN_WORKOS_IDP_NAME = "workos";
52617
52617
  var DEFAULT_WORKOS_API_HOST = "https://api.workos.com";
52618
+ var DEFAULT_WORKOS_CLIENT_ID = "client_01KC29HET5F3QAQ8GNTPZ7F320";
52618
52619
  var WORKOS_CLIENT_ID_ENV_NAMES = ["WORKOS_CLIENT_ID", "VITE_WORKOS_CLIENT_ID"];
52619
52620
  function idpDir(name) {
52620
52621
  return paths3.idpDir(name);
@@ -52747,7 +52748,7 @@ function builtinIdpConfig(name, clientIdOverride, env2 = process.env) {
52747
52748
  };
52748
52749
  }
52749
52750
  function workosClientIdFromEnv(env2 = process.env) {
52750
- return WORKOS_CLIENT_ID_ENV_NAMES.map((name) => env2[name]?.trim()).find((value) => typeof value === "string" && value.length > 0);
52751
+ return WORKOS_CLIENT_ID_ENV_NAMES.map((name) => env2[name]?.trim()).find((value) => typeof value === "string" && value.length > 0) ?? DEFAULT_WORKOS_CLIENT_ID;
52751
52752
  }
52752
52753
  async function postForm(url3, params) {
52753
52754
  const response2 = await fetch(url3, {
@@ -53261,10 +53262,46 @@ function isRegionRoutedInstanceRoot(url3) {
53261
53262
  const labels = url3.hostname.toLowerCase().split(".");
53262
53263
  return (labels.length === 4 || labels.length === 5) && /^[a-z]{2}(?:-[a-z0-9]+)*$/u.test(labels[1] ?? "") && labels.at(-2) === "astrale" && labels.at(-1) === "ai";
53263
53264
  }
53265
+ // src/lib/update.ts
53266
+ var DEFAULT_REPO = "astrale-os/cli";
53267
+ var DEFAULT_UPDATE_CHANNEL = "beta";
53268
+ var InstallMetadataSchema = exports_external2.object({
53269
+ method: exports_external2.literal("script"),
53270
+ channel: exports_external2.string().min(1).default(DEFAULT_UPDATE_CHANNEL),
53271
+ version: exports_external2.string().min(1).optional(),
53272
+ repo: exports_external2.string().min(1).default(DEFAULT_REPO),
53273
+ bin: exports_external2.string().min(1),
53274
+ installedAt: exports_external2.string().optional()
53275
+ });
53276
+ var ManifestAssetSchema = exports_external2.object({
53277
+ name: exports_external2.string().min(1),
53278
+ sha256: exports_external2.string().regex(/^[a-fA-F0-9]{64}$/).optional()
53279
+ });
53280
+ var UpdateManifestSchema = exports_external2.object({
53281
+ version: exports_external2.string().min(1),
53282
+ binaryVersion: exports_external2.string().min(1).optional(),
53283
+ channel: exports_external2.string().min(1),
53284
+ repo: exports_external2.string().min(1).optional(),
53285
+ assets: exports_external2.record(exports_external2.string(), exports_external2.union([
53286
+ ManifestAssetSchema,
53287
+ exports_external2.string().min(1).transform((name) => ({ name }))
53288
+ ]))
53289
+ });
53290
+
53264
53291
  // src/lib/admin-target.ts
53265
53292
  var DEFAULT_ADMIN_TARGET_NAME = "admin";
53266
- var DEFAULT_ADMIN_TARGET_URL = "https://admin.eu.astrale.ai/api";
53267
- var DEFAULT_ADMIN_DOMAIN_ISSUER = "https://admin.beta.astrale.ai";
53293
+ function defaultAdminTargetForChannel(channel) {
53294
+ return channel === "stable" ? {
53295
+ url: "https://admin.eu.astrale.ai/api",
53296
+ domainIssuer: "https://admin.astrale.ai"
53297
+ } : {
53298
+ url: "https://admin.eu.beta.astrale.ai/api",
53299
+ domainIssuer: "https://admin.beta.astrale.ai"
53300
+ };
53301
+ }
53302
+ var DEFAULT_ADMIN_TARGET = defaultAdminTargetForChannel(DEFAULT_UPDATE_CHANNEL);
53303
+ var DEFAULT_ADMIN_TARGET_URL = DEFAULT_ADMIN_TARGET.url;
53304
+ var DEFAULT_ADMIN_DOMAIN_ISSUER = DEFAULT_ADMIN_TARGET.domainIssuer;
53268
53305
  var DEFAULT_ADMIN_TARGET_CONFIG = {
53269
53306
  name: DEFAULT_ADMIN_TARGET_NAME,
53270
53307
  url: DEFAULT_ADMIN_TARGET_URL,
@@ -2,8 +2,12 @@ import { z } from 'zod';
2
2
  import type { AstraleConfig } from './config';
3
3
  import type { InstanceStore } from './instance';
4
4
  export declare const DEFAULT_ADMIN_TARGET_NAME = "admin";
5
- export declare const DEFAULT_ADMIN_TARGET_URL = "https://admin.eu.astrale.ai/api";
6
- export declare const DEFAULT_ADMIN_DOMAIN_ISSUER = "https://admin.beta.astrale.ai";
5
+ export declare function defaultAdminTargetForChannel(channel: string): {
6
+ readonly url: string;
7
+ readonly domainIssuer: string;
8
+ };
9
+ export declare const DEFAULT_ADMIN_TARGET_URL: string;
10
+ export declare const DEFAULT_ADMIN_DOMAIN_ISSUER: string;
7
11
  export declare const DEFAULT_ADMIN_TARGET_CONFIG: {
8
12
  name: string;
9
13
  url: string;
@@ -0,0 +1,43 @@
1
+ import { type ChildProcess, type StdioOptions } from 'node:child_process';
2
+ export type RunResult = {
3
+ /** Exit code, or -1 when the process was killed by a signal. */
4
+ code: number;
5
+ stdout: string;
6
+ stderr: string;
7
+ };
8
+ /**
9
+ * Spawn a child process and capture stdout/stderr as UTF-8 text.
10
+ *
11
+ * Uses `node:child_process` rather than `Bun.spawn` so the exact same code runs
12
+ * under both the Bun-compiled standalone binary (Linux/macOS) and the Node/npm
13
+ * build (Windows and any Node user). The promise rejects only when the process
14
+ * fails to spawn (e.g. ENOENT); a non-zero exit resolves with that `code` so
15
+ * callers can branch on it.
16
+ */
17
+ export declare function run(file: string, args?: string[], opts?: {
18
+ cwd?: string;
19
+ }): Promise<RunResult>;
20
+ /**
21
+ * Spawn a child process with inherited stdio so its output streams live to the
22
+ * user's terminal. Used for hand-held installs (npm / npx) where progress
23
+ * matters and the output is for the human, not for parsing. Resolves with the
24
+ * exit code; rejects only when the process fails to spawn (e.g. ENOENT).
25
+ */
26
+ export declare function runInherit(file: string, args?: string[], opts?: {
27
+ cwd?: string;
28
+ }): Promise<number>;
29
+ /**
30
+ * Spawn a LONG-LIVED child and return the handle immediately so the caller can
31
+ * supervise it (wait for exit, forward signals, tear down siblings). Unlike
32
+ * run()/runInherit() — which resolve only once the child closes — this is for
33
+ * servers the command keeps attached to (e.g. `astrale studio`'s Bun server and
34
+ * Vite dev process). Same node:child_process basis (cross-runtime) and bare
35
+ * PATH-name lookup convention. Default stdio streams stdout/stderr live but
36
+ * ignores stdin, so two supervised children never contend for the TTY.
37
+ */
38
+ export declare function spawnHandle(file: string, args?: string[], opts?: {
39
+ cwd?: string;
40
+ env?: NodeJS.ProcessEnv;
41
+ stdio?: StdioOptions;
42
+ detached?: boolean;
43
+ }): ChildProcess;
@@ -0,0 +1,101 @@
1
+ import { z } from 'zod';
2
+ export declare const DEFAULT_UPDATE_CHANNEL = "beta";
3
+ export declare const InstallMetadataSchema: z.ZodObject<{
4
+ method: z.ZodLiteral<"script">;
5
+ channel: z.ZodDefault<z.ZodString>;
6
+ version: z.ZodOptional<z.ZodString>;
7
+ repo: z.ZodDefault<z.ZodString>;
8
+ bin: z.ZodString;
9
+ installedAt: z.ZodOptional<z.ZodString>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ method: "script";
12
+ channel: string;
13
+ version?: string | undefined;
14
+ repo: string;
15
+ bin: string;
16
+ installedAt?: string | undefined;
17
+ }, {
18
+ method: "script";
19
+ channel?: string | undefined;
20
+ version?: string | undefined;
21
+ repo?: string | undefined;
22
+ bin: string;
23
+ installedAt?: string | undefined;
24
+ }>;
25
+ export type InstallMetadata = z.infer<typeof InstallMetadataSchema>;
26
+ export declare const UpdateManifestSchema: z.ZodObject<{
27
+ version: z.ZodString;
28
+ binaryVersion: z.ZodOptional<z.ZodString>;
29
+ channel: z.ZodString;
30
+ repo: z.ZodOptional<z.ZodString>;
31
+ assets: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodObject<{
32
+ name: z.ZodString;
33
+ sha256: z.ZodOptional<z.ZodString>;
34
+ }, "strip", z.ZodTypeAny, {
35
+ name: string;
36
+ sha256?: string | undefined;
37
+ }, {
38
+ name: string;
39
+ sha256?: string | undefined;
40
+ }>, z.ZodEffects<z.ZodString, {
41
+ name: string;
42
+ }, string>]>>;
43
+ }, "strip", z.ZodTypeAny, {
44
+ version: string;
45
+ binaryVersion?: string | undefined;
46
+ channel: string;
47
+ repo?: string | undefined;
48
+ assets: Record<string, {
49
+ name: string;
50
+ sha256?: string | undefined;
51
+ } | {
52
+ name: string;
53
+ }>;
54
+ }, {
55
+ version: string;
56
+ binaryVersion?: string | undefined;
57
+ channel: string;
58
+ repo?: string | undefined;
59
+ assets: Record<string, string | {
60
+ name: string;
61
+ sha256?: string | undefined;
62
+ }>;
63
+ }>;
64
+ export type UpdateManifest = z.infer<typeof UpdateManifestSchema>;
65
+ export type Platform = {
66
+ os: 'darwin' | 'linux';
67
+ arch: 'arm64' | 'x64';
68
+ };
69
+ export type UpdateRequest = {
70
+ check?: boolean;
71
+ channel?: string;
72
+ version?: string;
73
+ currentVersion: string;
74
+ platform?: Platform;
75
+ installPath?: string;
76
+ };
77
+ export type UpdateResult = {
78
+ status: 'up-to-date';
79
+ currentVersion: string;
80
+ latestVersion: string;
81
+ channel: string;
82
+ } | {
83
+ status: 'available';
84
+ currentVersion: string;
85
+ latestVersion: string;
86
+ channel: string;
87
+ } | {
88
+ status: 'updated';
89
+ previousVersion: string;
90
+ currentVersion: string;
91
+ channel: string;
92
+ bin: string;
93
+ };
94
+ export declare function detectPlatform(): Platform;
95
+ export declare function platformKey(platform: Platform): string;
96
+ export declare function readInstallMetadata(path?: string): Promise<InstallMetadata>;
97
+ export declare function writeInstallMetadata(meta: InstallMetadata, path?: string): Promise<void>;
98
+ export declare function releaseBase(meta: InstallMetadata, req: Pick<UpdateRequest, 'channel' | 'version'>): string;
99
+ export declare function fetchManifest(base: string): Promise<UpdateManifest>;
100
+ export declare function shouldUpdate(currentVersion: string, manifestVersion: string): boolean;
101
+ export declare function updateAstrale(req: UpdateRequest): Promise<UpdateResult>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/cli",
3
- "version": "1.0.0-beta.3",
3
+ "version": "1.0.0-beta.4",
4
4
  "description": "Astrale CLI — connect to existing Astrale kernels",
5
5
  "keywords": [
6
6
  "astrale",
@@ -0,0 +1,38 @@
1
+ import type { ClientSession } from '@astrale-os/kernel-client/session'
2
+
3
+ import { defineDomain } from '@astrale-os/sdk'
4
+ import { issuer } from '@astrale-os/sdk/auth'
5
+ import { createDeployment } from '@astrale-os/sdk/deployment'
6
+ import { defineSchema } from '@astrale-os/sdk/schema/v1'
7
+ import { expect, mock, test } from 'bun:test'
8
+
9
+ import { bindAdmin } from '../binding'
10
+
11
+ const schema = defineSchema('admin.astrale.ai', {})
12
+ const deployment = createDeployment({
13
+ definition: defineDomain({
14
+ schema,
15
+ handlers: { functions: {}, classes: {}, interfaces: {} },
16
+ }),
17
+ issuer: issuer.accept('https://admin.beta.astrale.ai'),
18
+ bundleHref: 'https://admin.beta.astrale.ai/domain.bundle.json',
19
+ bindings: { callables: [] },
20
+ })
21
+
22
+ test('binds the installed Admin Domain instead of the source Kernel publication', async () => {
23
+ const installed = mock(async () => ({
24
+ state: 'ready' as const,
25
+ target: 'sha256:admin-target' as const,
26
+ source: { kind: 'remote' as const, publication: deployment.publication },
27
+ bundle: deployment.bundle,
28
+ readiness: 'sha256:admin-readiness' as const,
29
+ capabilities: { requested: [], materialized: [] },
30
+ }))
31
+ const session = { installed } as unknown as ClientSession
32
+
33
+ const binding = await bindAdmin(session)
34
+
35
+ expect(installed).toHaveBeenCalledWith('admin.astrale.ai')
36
+ expect(binding.$.origin).toBe('admin.astrale.ai')
37
+ expect(String(binding.$.publication?.identity.issuer)).toBe('https://admin.beta.astrale.ai')
38
+ })
@@ -1,168 +1,18 @@
1
- import type { Input, Result } from '@astrale-os/kernel-client'
2
- import type {
3
- ClientSession,
4
- SessionRequestOptions,
5
- SessionSnapshot,
6
- } from '@astrale-os/kernel-client/session'
7
- import type {
8
- Definition,
9
- Domain as RichDomain,
10
- InstanceMethod,
11
- StaticMethod,
12
- } from '@astrale-os/sdk/domain'
13
- import type { PathLike } from '@astrale-os/sdk/graph/path'
14
- import type { Key } from '@astrale-os/sdk/schema'
1
+ import type { DomainBinding } from '@astrale-os/kernel-client/domain'
2
+ import type { ClientSession } from '@astrale-os/kernel-client/session'
15
3
 
16
- import { call } from '@astrale-os/kernel-client'
17
- import * as sessionModule from '@astrale-os/kernel-client/session'
18
- import { Domain } from '@astrale-os/sdk/domain'
19
- import { Path } from '@astrale-os/sdk/graph/path'
4
+ import { bind } from '@astrale-os/kernel-client/domain'
20
5
 
21
6
  const ADMIN_ORIGIN = 'admin.astrale.ai'
22
7
 
23
- type DynamicCallable =
24
- | (Definition<'function'> & { readonly path: NonNullable<Definition<'function'>['path']> })
25
- | StaticMethod
26
- | InstanceMethod
8
+ export type AdminBinding = DomainBinding
27
9
 
28
- export interface AdminBindingOperations {
29
- readonly installation: unknown
30
- readonly publication: SessionSnapshot['publication']
31
- invoke(
32
- callable: DynamicCallable,
33
- receiverOrInput: PathLike | Input,
34
- inputOrOptions?: Input | SessionRequestOptions,
35
- options?: SessionRequestOptions,
36
- ): Promise<unknown>
37
- }
38
-
39
- export type AdminBinding = RichDomain & {
40
- readonly $: RichDomain['$'] & AdminBindingOperations
41
- }
42
-
43
- interface CompatibleCallableReference {
44
- readonly origin: typeof ADMIN_ORIGIN
45
- readonly revision: SessionSnapshot['publication']['schema']['revision']
46
- readonly callable: Key.Callable
47
- readonly target: PathLike
48
- readonly outputMode: DynamicCallable['definition']['output']['mode']
49
- }
50
-
51
- interface CompatibleSession {
52
- readonly installation?: (origin: typeof ADMIN_ORIGIN) => Promise<unknown>
53
- readonly installed?: (origin: typeof ADMIN_ORIGIN) => Promise<unknown>
54
- readonly invoke?: (
55
- reference: CompatibleCallableReference,
56
- input: Input,
57
- options?: SessionRequestOptions,
58
- ) => Promise<unknown>
59
- }
60
-
61
- type LegacyDispatchBound = (
62
- session: ClientSession,
63
- request: ReturnType<typeof call>,
64
- expected: {
65
- readonly schema: { readonly revision: CompatibleCallableReference['revision'] }
66
- readonly publication: {
67
- readonly origin: SessionSnapshot['publication']['origin']
68
- readonly identity: SessionSnapshot['publication']['identity']
69
- readonly revision: CompatibleCallableReference['revision']
70
- readonly etag: SessionSnapshot['publication']['etag']
71
- }
72
- },
73
- options?: SessionRequestOptions,
74
- ) => Promise<Result>
75
-
76
- /** Bind the Admin revision advertised by this exact Session snapshot. */
10
+ /** Bind the exact Admin revision installed on this source Kernel. */
77
11
  export async function bindAdmin(session: ClientSession): Promise<AdminBinding> {
78
- const snapshot = await session.snapshot()
79
- if (
80
- snapshot.publication.origin !== ADMIN_ORIGIN ||
81
- snapshot.bundle.root.origin !== ADMIN_ORIGIN
82
- ) {
12
+ const installed = await session.installed(ADMIN_ORIGIN)
13
+ const binding = bind(session, installed)
14
+ if (binding.$.publication?.origin !== ADMIN_ORIGIN || binding.$.origin !== ADMIN_ORIGIN) {
83
15
  throw new TypeError('Configured Admin target does not serve the Admin Domain.')
84
16
  }
85
- const compatible = session as unknown as CompatibleSession
86
- const resolveInstallation = compatible.installation ?? compatible.installed
87
- if (resolveInstallation === undefined) {
88
- throw new TypeError('Client Session cannot resolve an installed Admin Domain.')
89
- }
90
- const installation = await resolveInstallation.call(session, ADMIN_ORIGIN)
91
- const domain = Domain.fromSchema(snapshot.bundle.root)
92
- const invoke = ((
93
- callable: DynamicCallable,
94
- receiverOrInput: PathLike | Input,
95
- inputOrOptions?: Input | SessionRequestOptions,
96
- options?: SessionRequestOptions,
97
- ) => {
98
- const target =
99
- 'on' in callable ? callable.on(Path.from(receiverOrInput as PathLike)) : callable.path
100
- const reference: CompatibleCallableReference = Object.freeze({
101
- origin: ADMIN_ORIGIN,
102
- revision: snapshot.publication.schema.revision,
103
- callable: callable.key as Key.Callable,
104
- target,
105
- outputMode: callable.definition.output.mode,
106
- })
107
- return invokeCompatible(
108
- session,
109
- snapshot,
110
- reference,
111
- ('on' in callable ? inputOrOptions : receiverOrInput) as Input,
112
- ('on' in callable ? options : inputOrOptions) as SessionRequestOptions | undefined,
113
- )
114
- }) as AdminBindingOperations['invoke']
115
-
116
- return Object.freeze({
117
- ...domain,
118
- $: Object.freeze({
119
- ...domain.$,
120
- installation,
121
- publication: snapshot.publication,
122
- invoke,
123
- }),
124
- }) as AdminBinding
125
- }
126
-
127
- async function invokeCompatible(
128
- session: ClientSession,
129
- snapshot: SessionSnapshot,
130
- reference: CompatibleCallableReference,
131
- input: Input,
132
- options: SessionRequestOptions | undefined,
133
- ): Promise<unknown> {
134
- const current = session as unknown as CompatibleSession
135
- if (current.invoke !== undefined) return current.invoke(reference, input, options)
136
-
137
- const dispatchBound = (sessionModule as unknown as { dispatchBound?: LegacyDispatchBound })
138
- .dispatchBound
139
- if (dispatchBound === undefined) {
140
- throw new TypeError('Client Session cannot invoke an exact Admin publication.')
141
- }
142
- const result = await dispatchBound(
143
- session,
144
- call(reference.target, input),
145
- {
146
- schema: { revision: reference.revision },
147
- publication: {
148
- origin: snapshot.publication.origin,
149
- identity: snapshot.publication.identity,
150
- revision: snapshot.publication.schema.revision,
151
- etag: snapshot.publication.etag,
152
- },
153
- },
154
- options,
155
- )
156
- return requireOutput(reference.outputMode, result)
157
- }
158
-
159
- function requireOutput(
160
- expected: CompatibleCallableReference['outputMode'],
161
- result: Result,
162
- ): unknown {
163
- if (result.kind !== expected) {
164
- if (result.kind === 'stream') void result.stream.cancel(`Admin callable declared ${expected}.`)
165
- throw new TypeError(`Admin callable declared ${expected} output but returned ${result.kind}.`)
166
- }
167
- return result.kind === 'stream' ? result.stream : result.value
17
+ return binding
168
18
  }
@@ -6,6 +6,7 @@ import {
6
6
  DEFAULT_ADMIN_TARGET_NAME,
7
7
  DEFAULT_ADMIN_DOMAIN_ISSUER,
8
8
  DEFAULT_ADMIN_TARGET_URL,
9
+ defaultAdminTargetForChannel,
9
10
  resolveAdminTargetFromStore,
10
11
  } from '../admin-target'
11
12
  import { DEFAULT_CONFIG, type AstraleConfig } from '../config'
@@ -32,6 +33,17 @@ const instances: InstanceStore = {
32
33
  }
33
34
 
34
35
  describe('resolveAdminTargetFromStore', () => {
36
+ test('derives hosted Admin defaults from the release channel', () => {
37
+ expect(defaultAdminTargetForChannel('beta')).toEqual({
38
+ url: 'https://admin.eu.beta.astrale.ai/api',
39
+ domainIssuer: 'https://admin.beta.astrale.ai',
40
+ })
41
+ expect(defaultAdminTargetForChannel('stable')).toEqual({
42
+ url: 'https://admin.eu.astrale.ai/api',
43
+ domainIssuer: 'https://admin.astrale.ai',
44
+ })
45
+ })
46
+
35
47
  test('uses hosted admin default without active instance coupling', () => {
36
48
  expect(resolveAdminTargetFromStore({}, DEFAULT_CONFIG, instances)).toEqual({
37
49
  name: DEFAULT_ADMIN_TARGET_NAME,
@@ -63,8 +63,11 @@ describe('IdP schemas and token helpers', () => {
63
63
  expect(config?.client.token_request_format).toBe('json')
64
64
  })
65
65
 
66
- test('does not invent a WorkOS environment when no client id is configured', () => {
67
- expect(builtinIdpConfig('workos', undefined, {})).toBeNull()
66
+ test('builds the built-in WorkOS IdP with the public client id by default', () => {
67
+ const config = builtinIdpConfig('workos', undefined, {})
68
+
69
+ expect(config?.entry.builtIn).toBe(true)
70
+ expect(config?.client.client_id).toBe('client_01KC29HET5F3QAQ8GNTPZ7F320')
68
71
  })
69
72
 
70
73
  test('reads WorkOS client id from WORKOS_CLIENT_ID before VITE_WORKOS_CLIENT_ID', () => {
@@ -75,8 +78,10 @@ describe('IdP schemas and token helpers', () => {
75
78
  }),
76
79
  ).toBe('client_primary')
77
80
  expect(workosClientIdFromEnv({ VITE_WORKOS_CLIENT_ID: 'client_vite' })).toBe('client_vite')
78
- expect(workosClientIdFromEnv({})).toBeUndefined()
79
- expect(workosClientIdFromEnv({ WORKOS_CLIENT_ID: ' ' })).toBeUndefined()
81
+ expect(workosClientIdFromEnv({})).toBe('client_01KC29HET5F3QAQ8GNTPZ7F320')
82
+ expect(workosClientIdFromEnv({ WORKOS_CLIENT_ID: ' ' })).toBe(
83
+ 'client_01KC29HET5F3QAQ8GNTPZ7F320',
84
+ )
80
85
  })
81
86
 
82
87
  test('stores client secret env names, not secret material', () => {
@@ -5,11 +5,30 @@ import type { InstanceStore } from './instance'
5
5
 
6
6
  import { AstraleError } from '../errors'
7
7
  import { readInstances, resolveInstanceKey } from './instance'
8
+ import { DEFAULT_UPDATE_CHANNEL } from './update'
8
9
  import { isHttpUrl } from './validation'
9
10
 
10
11
  export const DEFAULT_ADMIN_TARGET_NAME = 'admin'
11
- export const DEFAULT_ADMIN_TARGET_URL = 'https://admin.eu.astrale.ai/api'
12
- export const DEFAULT_ADMIN_DOMAIN_ISSUER = 'https://admin.beta.astrale.ai'
12
+
13
+ export function defaultAdminTargetForChannel(channel: string): {
14
+ readonly url: string
15
+ readonly domainIssuer: string
16
+ } {
17
+ return channel === 'stable'
18
+ ? {
19
+ url: 'https://admin.eu.astrale.ai/api',
20
+ domainIssuer: 'https://admin.astrale.ai',
21
+ }
22
+ : {
23
+ url: 'https://admin.eu.beta.astrale.ai/api',
24
+ domainIssuer: 'https://admin.beta.astrale.ai',
25
+ }
26
+ }
27
+
28
+ const DEFAULT_ADMIN_TARGET = defaultAdminTargetForChannel(DEFAULT_UPDATE_CHANNEL)
29
+
30
+ export const DEFAULT_ADMIN_TARGET_URL = DEFAULT_ADMIN_TARGET.url
31
+ export const DEFAULT_ADMIN_DOMAIN_ISSUER = DEFAULT_ADMIN_TARGET.domainIssuer
13
32
 
14
33
  export const DEFAULT_ADMIN_TARGET_CONFIG = {
15
34
  name: DEFAULT_ADMIN_TARGET_NAME,
package/src/lib/idp.ts CHANGED
@@ -214,6 +214,7 @@ export type IdpConfig = {
214
214
 
215
215
  export const BUILTIN_WORKOS_IDP_NAME = 'workos'
216
216
  const DEFAULT_WORKOS_API_HOST = 'https://api.workos.com'
217
+ const DEFAULT_WORKOS_CLIENT_ID = 'client_01KC29HET5F3QAQ8GNTPZ7F320'
217
218
  const WORKOS_CLIENT_ID_ENV_NAMES = ['WORKOS_CLIENT_ID', 'VITE_WORKOS_CLIENT_ID'] as const
218
219
 
219
220
  export function idpDir(name: string): string {
@@ -413,8 +414,10 @@ export function builtinIdpConfig(
413
414
  }
414
415
 
415
416
  export function workosClientIdFromEnv(env: NodeJS.ProcessEnv = process.env): string | undefined {
416
- return WORKOS_CLIENT_ID_ENV_NAMES.map((name) => env[name]?.trim()).find(
417
- (value): value is string => typeof value === 'string' && value.length > 0,
417
+ return (
418
+ WORKOS_CLIENT_ID_ENV_NAMES.map((name) => env[name]?.trim()).find(
419
+ (value): value is string => typeof value === 'string' && value.length > 0,
420
+ ) ?? DEFAULT_WORKOS_CLIENT_ID
418
421
  )
419
422
  }
420
423