@astrale-os/cli 0.8.1-alpha.7 → 1.0.0-beta.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.
Files changed (64) hide show
  1. package/README.md +15 -3
  2. package/dist/astrale.js +86 -35
  3. package/package.json +5 -5
  4. package/src/commands/__tests__/domain-install-operation.test.ts +121 -0
  5. package/src/commands/__tests__/domain-install-owned.test.ts +66 -0
  6. package/src/commands/__tests__/install-direct.test.ts +3 -2
  7. package/src/commands/domain/install.ts +78 -15
  8. package/src/connection/__tests__/errors.test.ts +82 -6
  9. package/src/connection/command.ts +9 -1
  10. package/src/connection/errors.ts +19 -8
  11. package/src/connection/index.ts +1 -1
  12. package/src/connection/reasons.ts +26 -12
  13. package/src/program/__tests__/program.test.ts +1 -1
  14. package/studio/client/dist/assets/{elk-api-D0cBetPW.js → elk-api-D2xgMJvi.js} +1 -1
  15. package/studio/client/dist/assets/{index-BQnJ5sgd.css → index-BMdnsIJA.css} +1 -1
  16. package/studio/client/dist/assets/index-D-vRV8w7.js +8 -0
  17. package/studio/client/dist/assets/index-LGSWRrk8.js +81 -0
  18. package/studio/client/dist/index.html +2 -2
  19. package/studio/package.json +1 -1
  20. package/studio/server/agent/prompts/anchors.test.ts +74 -0
  21. package/studio/server/agent/prompts/anchors.ts +85 -15
  22. package/studio/server/agent/prompts/system.test.ts +12 -0
  23. package/studio/server/agent/prompts/system.ts +6 -6
  24. package/studio/server/api.ts +1 -5
  25. package/studio/server/cache.ts +5 -2
  26. package/studio/server/domain.test.ts +67 -0
  27. package/studio/server/domain.ts +29 -6
  28. package/studio/server/index.ts +1 -3
  29. package/studio/server/introspect/anatomy-extras.test.ts +104 -1
  30. package/studio/server/introspect/anatomy-extras.ts +340 -8
  31. package/studio/server/introspect/anatomy.test.ts +33 -0
  32. package/studio/server/introspect/anatomy.ts +22 -7
  33. package/studio/server/introspect/bundle.ts +7 -1
  34. package/studio/server/introspect/canonical-schema.test.ts +395 -0
  35. package/studio/server/introspect/canonical-schema.ts +751 -0
  36. package/studio/server/introspect/core-extractor.ts +30 -10
  37. package/studio/server/introspect/core.ts +4 -2
  38. package/studio/server/introspect/diff.test.ts +124 -0
  39. package/studio/server/introspect/diff.ts +252 -23
  40. package/studio/server/introspect/extractor.ts +46 -14
  41. package/studio/server/introspect/overlay-tsmorph.test.ts +164 -1
  42. package/studio/server/introspect/overlay-tsmorph.ts +381 -106
  43. package/studio/server/introspect/overlay.test.ts +72 -0
  44. package/studio/server/introspect/overlay.ts +16 -6
  45. package/studio/server/introspect/runtime.test.ts +217 -0
  46. package/studio/server/introspect/runtime.ts +18 -6
  47. package/studio/server/introspect/schema-refs.test.ts +100 -0
  48. package/studio/server/introspect/schema-refs.ts +23 -2
  49. package/studio/server/state/baseline.test.ts +51 -0
  50. package/studio/server/state/baseline.ts +31 -2
  51. package/studio/server/state/create.test.ts +37 -0
  52. package/studio/server/state/create.ts +21 -15
  53. package/studio/server/state/instance.test.ts +63 -0
  54. package/studio/server/state/instance.ts +65 -29
  55. package/studio/server/state/views.test.ts +209 -9
  56. package/studio/server/state/views.ts +176 -69
  57. package/studio/server/watch.test.ts +36 -0
  58. package/studio/server/watch.ts +24 -16
  59. package/studio/server/workspace-watch.ts +8 -3
  60. package/studio/shared/types.ts +164 -33
  61. package/studio/client/dist/assets/index-Dspir4w7.js +0 -81
  62. package/studio/client/dist/assets/index-bVD2KJgz.js +0 -8
  63. package/studio/server/view-dev-server.test.ts +0 -111
  64. package/studio/server/view-dev-server.ts +0 -372
@@ -6,6 +6,7 @@ import type { KernelCommandOpts } from '../../connection'
6
6
  import type { CommandDefinition } from '../../program/index'
7
7
 
8
8
  import { createPathCall, runKernelCommand, withAdminClientSession } from '../../connection'
9
+ import { formatKernelError } from '../../connection/errors'
9
10
  import { AstraleError } from '../../errors'
10
11
  import {
11
12
  installAdminDomainInContext,
@@ -21,11 +22,7 @@ import { confirmWithInput, promptText, selectFrom } from '../../lib/prompt'
21
22
  import { isHttpUrl } from '../../lib/validation'
22
23
 
23
24
  /** Public Kernel install syscall input for one remote URL. */
24
- export function directInstallCallInput(
25
- url: string,
26
- token?: string,
27
- operation: string = crypto.randomUUID(),
28
- ) {
25
+ export function directInstallCallInput(url: string, operation: string, token?: string) {
29
26
  return Object.freeze({
30
27
  operation,
31
28
  domains: [
@@ -50,9 +47,28 @@ type DirectInstallResult = {
50
47
  }[]
51
48
  }
52
49
 
50
+ const OPERATION_ID_PATTERN =
51
+ /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u
52
+
53
+ function acceptOperationId(input: unknown): string {
54
+ if (typeof input !== 'string' || !OPERATION_ID_PATTERN.test(input)) {
55
+ throw new AstraleError(
56
+ 'INVALID_FLAG',
57
+ '--operation must be a canonical lowercase UUIDv4.',
58
+ 'Omit --operation for a fresh install; use it only with the exact UUID printed for recovery.',
59
+ )
60
+ }
61
+ return input
62
+ }
63
+
64
+ function createOperationId(): string {
65
+ return acceptOperationId(globalThis.crypto.randomUUID())
66
+ }
67
+
53
68
  type InstallOpts = KernelCommandOpts &
54
69
  AdminTargetCommandOpts & {
55
70
  direct?: boolean
71
+ operation?: string
56
72
  token?: string
57
73
  allowIdentityOverride?: boolean
58
74
  // Global flags (program.ts) that force non-interactive.
@@ -78,6 +94,10 @@ Behavior:
78
94
  origin differs from its serving host, it requires explicit consent (an
79
95
  interactive DANGER prompt, or --allow-identity-override in scripts).
80
96
 
97
+ A fresh, strong operation id is generated automatically. Use --operation
98
+ only to retry or recover the exact same direct install after an outcome-unknown
99
+ timeout or disconnect.
100
+
81
101
  Examples:
82
102
  $ astrale domain install crm.acme.dev -i staging # by origin, via admin
83
103
  $ astrale domain install https://crm.acme.dev # by url, via admin
@@ -103,12 +123,26 @@ Examples:
103
123
  flags: '--token <token>',
104
124
  description: 'Bearer token for private domain install endpoints (--direct only)',
105
125
  },
126
+ {
127
+ flags: '--operation <uuid>',
128
+ description: 'Reuse an exact direct-install operation id for explicit retry/recovery',
129
+ },
106
130
  {
107
131
  flags: '--allow-identity-override',
108
132
  description: 'Consent to a domain whose origin differs from its serving host (--direct only)',
109
133
  },
110
134
  ],
111
135
  action: async (target: string | undefined, opts: InstallOpts) => {
136
+ if (opts.operation !== undefined && !opts.direct) {
137
+ fatal(
138
+ new AstraleError(
139
+ 'INVALID_FLAG',
140
+ '--operation is valid only with --direct.',
141
+ 'Ordinary direct installs generate a fresh operation id automatically.',
142
+ ),
143
+ opts,
144
+ )
145
+ }
112
146
  if (opts.direct) {
113
147
  await installDirect(target, opts)
114
148
  return
@@ -197,8 +231,9 @@ export async function installViaAdmin(
197
231
  log.dim(` origin: ${result.origin}`)
198
232
  log.dim(` url: ${result.url}`)
199
233
  })
200
- } catch (e) {
201
- fatal(e, opts)
234
+ } catch (error) {
235
+ await formatKernelError(error, isMachine(opts), undefined, opts.debug)
236
+ process.exit(1)
202
237
  }
203
238
  }
204
239
 
@@ -326,9 +361,27 @@ async function activeSlug(): Promise<string | undefined> {
326
361
  * bypassing the admin catalog, with the identity-override
327
362
  * consent gate. Works on any instance the caller can authenticate to.
328
363
  */
329
- async function installDirect(target: string | undefined, opts: InstallOpts): Promise<void> {
364
+ interface DirectInstallDependencies {
365
+ readonly acceptOperationId: (input: unknown) => string
366
+ readonly createOperationId: () => string
367
+ readonly runKernelCommand: typeof runKernelCommand
368
+ }
369
+
370
+ const defaultDirectInstallDependencies: DirectInstallDependencies = Object.freeze({
371
+ acceptOperationId,
372
+ createOperationId,
373
+ runKernelCommand,
374
+ })
375
+
376
+ export async function installDirect(
377
+ target: string | undefined,
378
+ opts: InstallOpts,
379
+ dependencies: Partial<DirectInstallDependencies> = {},
380
+ ): Promise<void> {
381
+ const direct = { ...defaultDirectInstallDependencies, ...dependencies }
330
382
  let host = ''
331
383
  let consentedOrigin: string | undefined
384
+ let operation: string
332
385
  try {
333
386
  if (!target) {
334
387
  throw new AstraleError(
@@ -338,24 +391,30 @@ async function installDirect(target: string | undefined, opts: InstallOpts): Pro
338
391
  )
339
392
  }
340
393
  host = validateInstallUrl(target)
394
+ operation =
395
+ opts.operation === undefined
396
+ ? direct.createOperationId()
397
+ : direct.acceptOperationId(opts.operation)
341
398
  consentedOrigin = await ensureIdentityOverrideConsent(
342
399
  target,
343
400
  host,
344
401
  opts.allowIdentityOverride ?? false,
345
402
  )
346
403
  } catch (e) {
347
- fatal(e)
404
+ fatal(e, opts)
348
405
  }
349
406
  const url = target as string
407
+ const retry = directInstallRetry(url, operation, opts)
350
408
 
351
- await runKernelCommand<DirectInstallResult>({
409
+ await direct.runKernelCommand<DirectInstallResult>({
352
410
  opts,
353
- label: `Installing domain from ${url}`,
411
+ label: `Installing domain from ${url} (operation ${operation})`,
412
+ recovery: { operation, retry },
354
413
  fn: async ({ session }) =>
355
414
  (await session.call(
356
415
  createPathCall(
357
416
  Path.project(syscalls.install.ref).raw,
358
- directInstallCallInput(url, opts.token),
417
+ directInstallCallInput(url, operation, opts.token),
359
418
  ),
360
419
  )) as DirectInstallResult,
361
420
  format: (result, fmtOpts, isRaw) => {
@@ -364,11 +423,10 @@ async function installDirect(target: string | undefined, opts: InstallOpts): Pro
364
423
  return
365
424
  }
366
425
  const installed = result.transitions[0]?.intent
367
- if (installed === undefined) {
368
- throw new Error('Kernel install returned no committed Domain transition.')
369
- }
426
+ if (!installed) throw new Error('Kernel install returned no committed Domain transition.')
370
427
  const revision = installed.target?.schemaRevision ?? result.operation
371
428
  log.success(`Domain installed: ${installed.origin}@${revision}`)
429
+ log.dim(` operation: ${result.operation}`)
372
430
  // Belt-and-braces: the kernel-confirmed origin is authoritative. If it
373
431
  // aliases the host and the pre-install gate never consented to THAT
374
432
  // origin (lying or absent `/meta`), say so loudly after the fact.
@@ -383,6 +441,11 @@ async function installDirect(target: string | undefined, opts: InstallOpts): Pro
383
441
  })
384
442
  }
385
443
 
444
+ function directInstallRetry(url: string, operation: string, opts: InstallOpts): string {
445
+ const instance = opts.instance === undefined ? '' : ` -i ${opts.instance}`
446
+ return `astrale domain install ${url} --direct --operation ${operation}${instance}`
447
+ }
448
+
386
449
  function validateInstallUrl(value: string): string {
387
450
  let url: URL
388
451
  try {
@@ -37,6 +37,46 @@ describe('formatKernelError', () => {
37
37
  expect(writes[0]).not.toContain('ECONNREFUSED')
38
38
  })
39
39
 
40
+ test('retains operation recovery only for outcome-unknown transport failure', async () => {
41
+ const writes: string[] = []
42
+ const original = process.stderr.write
43
+ process.stderr.write = ((chunk: string | Uint8Array) => {
44
+ writes.push(typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk))
45
+ return true
46
+ }) as typeof process.stderr.write
47
+ try {
48
+ await formatKernelError(
49
+ new TransportError('Request timed out.', {
50
+ cause: new Error('timeout'),
51
+ phase: 'timeout',
52
+ delivery: 'unknown',
53
+ }),
54
+ true,
55
+ undefined,
56
+ false,
57
+ {
58
+ recovery: {
59
+ operation: '4a4c9a18-50f6-4d84-a7b7-2d83e3e45dc8',
60
+ retry:
61
+ 'astrale domain install https://crm.test --direct --operation 4a4c9a18-50f6-4d84-a7b7-2d83e3e45dc8',
62
+ },
63
+ },
64
+ )
65
+ } finally {
66
+ process.stderr.write = original
67
+ }
68
+
69
+ expect(writes).toHaveLength(1)
70
+ expect(JSON.parse(writes[0]!)).toMatchObject({
71
+ error: 'TIMEOUT',
72
+ phase: 'timeout',
73
+ delivery: 'unknown',
74
+ operation: '4a4c9a18-50f6-4d84-a7b7-2d83e3e45dc8',
75
+ retry:
76
+ 'astrale domain install https://crm.test --direct --operation 4a4c9a18-50f6-4d84-a7b7-2d83e3e45dc8',
77
+ })
78
+ })
79
+
40
80
  /** @evidence TEST-CLI-CONNECTION-PRESERVES-PUBLIC-SEMANTIC-REASON */
41
81
  test('preserves a Kernel-admitted semantic reason in machine output', async () => {
42
82
  const writes: string[] = []
@@ -275,8 +315,9 @@ describe('formatKernelError', () => {
275
315
  details: {
276
316
  phase: 'upgrade',
277
317
  origin: 'grc.example',
278
- expected: 'https://old.example',
279
- actual: 'https://new.example',
318
+ issue: 'issuer-changed',
319
+ installedIssuer: 'https://old.example',
320
+ replacementIssuer: 'https://new.example',
280
321
  },
281
322
  }),
282
323
  true,
@@ -294,18 +335,53 @@ describe('formatKernelError', () => {
294
335
  details: {
295
336
  phase: 'upgrade',
296
337
  origin: 'grc.example',
297
- expected: 'https://old.example',
298
- actual: 'https://new.example',
338
+ issue: 'issuer-changed',
339
+ installedIssuer: 'https://old.example',
340
+ replacementIssuer: 'https://new.example',
299
341
  },
300
342
  },
301
343
  hint: schemaUpgradeHint({
302
344
  origin: 'grc.example',
303
- expected: 'https://old.example',
304
- actual: 'https://new.example',
345
+ issue: 'issuer-changed',
346
+ installedIssuer: 'https://old.example',
347
+ replacementIssuer: 'https://new.example',
305
348
  }),
306
349
  })
307
350
  })
308
351
 
352
+ test('prints both issuers and the recovery command for an incompatible replacement', async () => {
353
+ const errors: string[] = []
354
+ const details: string[] = []
355
+ const originalError = console.error
356
+ const originalLog = console.log
357
+ console.error = (...values: unknown[]) => errors.push(values.map(String).join(' '))
358
+ console.log = (...values: unknown[]) => details.push(values.map(String).join(' '))
359
+ try {
360
+ await formatKernelError(
361
+ new ResponseError(5001, 'Schema operation is not supported.', {
362
+ code: 'SCHEMA_UPGRADE_INCOMPATIBLE',
363
+ details: {
364
+ phase: 'upgrade',
365
+ origin: 'grc.example',
366
+ issue: 'issuer-changed',
367
+ installedIssuer: 'https://old.example',
368
+ replacementIssuer: 'https://new.example',
369
+ },
370
+ }),
371
+ false,
372
+ )
373
+ } finally {
374
+ console.error = originalError
375
+ console.log = originalLog
376
+ }
377
+
378
+ expect(errors.join('\n')).toContain('RESPONSE_ERROR(5001)')
379
+ expect(details.join('\n')).toContain('reason: SCHEMA_UPGRADE_INCOMPATIBLE')
380
+ expect(details.join('\n')).toContain('installed issuer: https://old.example')
381
+ expect(details.join('\n')).toContain('replacement issuer: https://new.example')
382
+ expect(details.join('\n')).toContain('astrale domain uninstall grc.example')
383
+ })
384
+
309
385
  test('explains a private Domain source without exposing transport diagnostics', async () => {
310
386
  const writes: string[] = []
311
387
  const original = process.stderr.write
@@ -16,6 +16,11 @@ export interface KernelCommandOpts extends ConnectionOptions {
16
16
  readonly debug?: boolean
17
17
  }
18
18
 
19
+ export interface OperationRecovery {
20
+ readonly operation: string
21
+ readonly retry: string
22
+ }
23
+
19
24
  /**
20
25
  * Encapsulates the standard kernel command lifecycle:
21
26
  * spinner → connect → call → timing → output → error handling.
@@ -27,6 +32,7 @@ export interface KernelCommandOpts extends ConnectionOptions {
27
32
  export async function runKernelCommand<T>(input: {
28
33
  readonly opts: KernelCommandOpts
29
34
  readonly label: string
35
+ readonly recovery?: OperationRecovery
30
36
  readonly fn: (context: ConnectionContext) => Promise<T>
31
37
  readonly format?: (
32
38
  result: T,
@@ -53,7 +59,9 @@ export async function runKernelCommand<T>(input: {
53
59
  }
54
60
  } catch (error) {
55
61
  if (!isRaw && spin) spin.fail(`${label} failed`)
56
- await formatKernelError(error, isRaw, undefined, opts.debug)
62
+ await formatKernelError(error, isRaw, undefined, opts.debug, {
63
+ recovery: input.recovery,
64
+ })
57
65
  process.exit(1)
58
66
  }
59
67
  }
@@ -1,5 +1,7 @@
1
1
  import chalk from 'chalk'
2
2
 
3
+ import type { OperationRecovery } from './command'
4
+
3
5
  import { AstraleError } from '../errors'
4
6
  import { readLocalStatus, type LocalStatus } from '../lib/local-status'
5
7
  import { log } from '../lib/log'
@@ -28,6 +30,7 @@ export async function formatKernelError(
28
30
  isRaw: boolean,
29
31
  urlArg = '',
30
32
  debug = false,
33
+ opts: { recovery?: OperationRecovery } = {},
31
34
  ): Promise<void> {
32
35
  const url =
33
36
  urlArg || (error instanceof Error ? ((error as Error & { url?: string }).url ?? '') : '')
@@ -54,7 +57,7 @@ export async function formatKernelError(
54
57
 
55
58
  switch (name) {
56
59
  case 'TransportError':
57
- presentTransportError(error, isRaw, url, localContext)
60
+ presentTransportError(error, isRaw, url, localContext, opts.recovery)
58
61
  break
59
62
 
60
63
  case 'ResponseError': {
@@ -96,11 +99,9 @@ export async function formatKernelError(
96
99
  }
97
100
  presentFunctionInputIssues(inputIssues)
98
101
  if (queryRepair !== undefined) presentQueryInputRepair(queryRepair)
99
- if (upgrade?.expected !== undefined) {
100
- log.dim(` installed issuer: ${upgrade.expected}`)
101
- }
102
- if (upgrade?.actual !== undefined) {
103
- log.dim(` replacement issuer: ${upgrade.actual}`)
102
+ if (upgrade?.issue === 'issuer-changed') {
103
+ log.dim(` installed issuer: ${upgrade.installedIssuer}`)
104
+ log.dim(` replacement issuer: ${upgrade.replacementIssuer}`)
104
105
  }
105
106
  if (hint !== undefined) log.dim(` ${hint}`)
106
107
  }
@@ -194,6 +195,7 @@ function presentTransportError(
194
195
  isRaw: boolean,
195
196
  url: string,
196
197
  context: LocalStatus | undefined,
198
+ recovery: OperationRecovery | undefined,
197
199
  ): void {
198
200
  const phase = transportPhase(error)
199
201
  const delivery = transportDelivery(error)
@@ -213,6 +215,7 @@ function presentTransportError(
213
215
  ...(phase === undefined ? {} : { phase }),
214
216
  ...(delivery === undefined ? {} : { delivery }),
215
217
  ...(context === undefined ? {} : { context }),
218
+ ...(delivery === 'unknown' && recovery !== undefined ? recovery : {}),
216
219
  })
217
220
  return
218
221
  }
@@ -221,10 +224,18 @@ function presentTransportError(
221
224
  if (phase !== undefined) log.dim(` phase: ${phase}`)
222
225
  if (phase === 'connect') log.dim(' Check the target and run `astrale status`.')
223
226
  else if (phase === 'timeout') log.dim(' Try increasing `--timeout`.')
224
- else if (delivery === 'unknown') {
227
+ else if (delivery === 'unknown') printOperationRecovery(recovery)
228
+ printLocalContext(context)
229
+ }
230
+
231
+ function printOperationRecovery(recovery: OperationRecovery | undefined): void {
232
+ if (recovery === undefined) {
225
233
  log.dim(' Delivery is unknown; do not automatically retry a mutating call.')
234
+ return
226
235
  }
227
- printLocalContext(context)
236
+ log.dim(' Delivery is unknown; retry with the same operation id:')
237
+ log.dim(` operation: ${recovery.operation}`)
238
+ log.dim(` ${recovery.retry}`)
228
239
  }
229
240
 
230
241
  function presentFunctionInputIssues(issues: readonly FunctionInputIssue[]): void {
@@ -1,6 +1,6 @@
1
1
  export { createPathCall } from './call'
2
2
  export { runKernelCommand } from './command'
3
- export type { KernelCommandOpts } from './command'
3
+ export type { KernelCommandOpts, OperationRecovery } from './command'
4
4
  export { expandSelfInCall, expandSelfInPath, withSelfHint } from './self'
5
5
  export type { SelfExpansionMeta } from './self'
6
6
  export { withAdminClientSession, withClientSession, type ConnectionContext } from './session'
@@ -15,12 +15,17 @@ export type QueryInputRepair =
15
15
  path?: string
16
16
  }>
17
17
 
18
- export type SchemaUpgradeDetails = {
19
- readonly origin?: string
20
- readonly issue?: string
21
- readonly expected?: string
22
- readonly actual?: string
23
- }
18
+ export type SchemaUpgradeDetails =
19
+ | {
20
+ readonly origin?: string
21
+ readonly issue?: undefined
22
+ }
23
+ | {
24
+ readonly origin: string
25
+ readonly issue: 'issuer-changed'
26
+ readonly installedIssuer: string
27
+ readonly replacementIssuer: string
28
+ }
24
29
 
25
30
  const JSON_POINTER = /^(?:\/(?:[^~/]|~[01])*)*$/u
26
31
  const MAXIMUM_FUNCTION_ISSUES = 32
@@ -115,18 +120,27 @@ export function queryInputRepair(reason: unknown): QueryInputRepair | undefined
115
120
  export function schemaUpgradeDetails(reason: unknown): SchemaUpgradeDetails | undefined {
116
121
  if (!record(reason) || reason.code !== 'SCHEMA_UPGRADE_INCOMPATIBLE') return undefined
117
122
  const details = record(reason.details) ? reason.details : {}
118
- return {
119
- ...(typeof details.origin === 'string' ? { origin: details.origin } : {}),
120
- ...(typeof details.issue === 'string' ? { issue: details.issue } : {}),
121
- ...(typeof details.expected === 'string' ? { expected: details.expected } : {}),
122
- ...(typeof details.actual === 'string' ? { actual: details.actual } : {}),
123
+ const origin = typeof details.origin === 'string' ? details.origin : undefined
124
+ if (
125
+ details.issue === 'issuer-changed' &&
126
+ origin !== undefined &&
127
+ typeof details.installedIssuer === 'string' &&
128
+ typeof details.replacementIssuer === 'string'
129
+ ) {
130
+ return {
131
+ origin,
132
+ issue: details.issue,
133
+ installedIssuer: details.installedIssuer,
134
+ replacementIssuer: details.replacementIssuer,
135
+ }
123
136
  }
137
+ return origin === undefined ? {} : { origin }
124
138
  }
125
139
 
126
140
  export function schemaUpgradeHint(details: SchemaUpgradeDetails): string {
127
141
  const target = details.origin ?? '<origin>'
128
142
  const explanation =
129
- details.expected !== undefined && details.actual !== undefined
143
+ details.issue === 'issuer-changed'
130
144
  ? 'A replacement cannot change an installed Domain issuer.'
131
145
  : 'The replacement changes an immutable part of the installed Domain.'
132
146
  return (
@@ -187,7 +187,7 @@ describe('program composition', () => {
187
187
  'whoami',
188
188
  ])
189
189
  expect(createHash('sha256').update(JSON.stringify(surface)).digest('hex')).toBe(
190
- '73c4dc12159039257a1847701b16ef963f5c96a188f3656604dd2770e74c116e',
190
+ 'b21a8c98f0bb75432b460d4562c2d86f39ffb8e88349962e4611ccbf65fa9f73',
191
191
  )
192
192
  })
193
193
 
@@ -1 +1 @@
1
- import{m as L}from"./index-Dspir4w7.js";function S(y,b){for(var u=0;u<b.length;u++){const a=b[u];if(typeof a!="string"&&!Array.isArray(a)){for(const i in a)if(i!=="default"&&!(i in y)){const n=Object.getOwnPropertyDescriptor(a,i);n&&Object.defineProperty(y,i,n.get?n:{enumerable:!0,get:()=>a[i]})}}}return Object.freeze(Object.defineProperty(y,Symbol.toStringTag,{value:"Module"}))}function w(y){throw new Error('Could not dynamically require "'+y+'". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.')}var O={exports:{}},j;function C(){return j||(j=1,(function(y,b){(function(u){y.exports=u()})(function(){return(function(){function u(a,i,n){function d(f,_){if(!i[f]){if(!a[f]){var h=typeof w=="function"&&w;if(!_&&h)return h(f,!0);if(g)return g(f,!0);var o=new Error("Cannot find module '"+f+"'");throw o.code="MODULE_NOT_FOUND",o}var e=i[f]={exports:{}};a[f][0].call(e.exports,function(r){var t=a[f][1][r];return d(t||r)},e,e.exports,u,a,i,n)}return i[f].exports}for(var g=typeof w=="function"&&w,m=0;m<n.length;m++)d(n[m]);return d}return u})()({1:[function(u,a,i){Object.defineProperty(i,"__esModule",{value:!0}),i.default=void 0;function n(o){"@babel/helpers - typeof";return n=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(e){return typeof e}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n(o)}function d(o,e){if(!(o instanceof e))throw new TypeError("Cannot call a class as a function")}function g(o,e){for(var r=0;r<e.length;r++){var t=e[r];t.enumerable=t.enumerable||!1,t.configurable=!0,"value"in t&&(t.writable=!0),Object.defineProperty(o,f(t.key),t)}}function m(o,e,r){return e&&g(o.prototype,e),Object.defineProperty(o,"prototype",{writable:!1}),o}function f(o){var e=_(o,"string");return n(e)=="symbol"?e:e+""}function _(o,e){if(n(o)!="object"||!o)return o;var r=o[Symbol.toPrimitive];if(r!==void 0){var t=r.call(o,e);if(n(t)!="object")return t;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(o)}i.default=(function(){function o(){var e=this,r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},t=r.defaultLayoutOptions,s=t===void 0?{}:t,l=r.algorithms,v=l===void 0?["layered","stress","mrtree","radial","force","disco","sporeOverlap","sporeCompaction","rectpacking"]:l,c=r.workerFactory,p=r.workerUrl;if(d(this,o),this.defaultLayoutOptions=s,this.initialized=!1,typeof p>"u"&&typeof c>"u")throw new Error("Cannot construct an ELK without both 'workerUrl' and 'workerFactory'.");var k=c;typeof p<"u"&&typeof c>"u"&&(k=function(M){return new Worker(M)});var E=k(p);if(typeof E.postMessage!="function")throw new TypeError("Created worker does not provide the required 'postMessage' function.");this.worker=new h(E),this.worker.postMessage({cmd:"register",algorithms:v}).then(function(P){return e.initialized=!0}).catch(console.err)}return m(o,[{key:"layout",value:function(r){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},s=t.layoutOptions,l=s===void 0?this.defaultLayoutOptions:s,v=t.logging,c=v===void 0?!1:v,p=t.measureExecutionTime,k=p===void 0?!1:p;return r?this.worker.postMessage({cmd:"layout",graph:r,layoutOptions:l,options:{logging:c,measureExecutionTime:k}}):Promise.reject(new Error("Missing mandatory parameter 'graph'."))}},{key:"knownLayoutAlgorithms",value:function(){return this.worker.postMessage({cmd:"algorithms"})}},{key:"knownLayoutOptions",value:function(){return this.worker.postMessage({cmd:"options"})}},{key:"knownLayoutCategories",value:function(){return this.worker.postMessage({cmd:"categories"})}},{key:"terminateWorker",value:function(){this.worker&&this.worker.terminate()}}])})();var h=(function(){function o(e){var r=this;if(d(this,o),e===void 0)throw new Error("Missing mandatory parameter 'worker'.");this.resolvers={},this.worker=e,this.worker.onmessage=function(t){setTimeout(function(){r.receive(r,t)},0)}}return m(o,[{key:"postMessage",value:function(r){var t=this.id||0;this.id=t+1,r.id=t;var s=this;return new Promise(function(l,v){s.resolvers[t]=function(c,p){c?(s.convertGwtStyleError(c),v(c)):l(p)},s.worker.postMessage(r)})}},{key:"receive",value:function(r,t){var s=t.data,l=r.resolvers[s.id];l&&(delete r.resolvers[s.id],s.error?l(s.error):l(null,s.data))}},{key:"terminate",value:function(){this.worker&&this.worker.terminate()}},{key:"convertGwtStyleError",value:function(r){if(r){var t=r.__java$exception;t&&(t.cause&&t.cause.backingJsObject&&(r.cause=t.cause.backingJsObject,this.convertGwtStyleError(r.cause)),delete r.__java$exception)}}}])})()},{}],2:[function(u,a,i){var n=u("./elk-api.js").default;Object.defineProperty(a.exports,"__esModule",{value:!0}),a.exports=n,n.default=n},{"./elk-api.js":1}]},{},[2])(2)})})(O)),O.exports}var x=C();const A=L(x),q=S({__proto__:null,default:A},[x]);export{q as e};
1
+ import{m as L}from"./index-LGSWRrk8.js";function S(y,b){for(var u=0;u<b.length;u++){const a=b[u];if(typeof a!="string"&&!Array.isArray(a)){for(const i in a)if(i!=="default"&&!(i in y)){const n=Object.getOwnPropertyDescriptor(a,i);n&&Object.defineProperty(y,i,n.get?n:{enumerable:!0,get:()=>a[i]})}}}return Object.freeze(Object.defineProperty(y,Symbol.toStringTag,{value:"Module"}))}function w(y){throw new Error('Could not dynamically require "'+y+'". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.')}var O={exports:{}},j;function C(){return j||(j=1,(function(y,b){(function(u){y.exports=u()})(function(){return(function(){function u(a,i,n){function d(f,_){if(!i[f]){if(!a[f]){var h=typeof w=="function"&&w;if(!_&&h)return h(f,!0);if(g)return g(f,!0);var o=new Error("Cannot find module '"+f+"'");throw o.code="MODULE_NOT_FOUND",o}var e=i[f]={exports:{}};a[f][0].call(e.exports,function(r){var t=a[f][1][r];return d(t||r)},e,e.exports,u,a,i,n)}return i[f].exports}for(var g=typeof w=="function"&&w,m=0;m<n.length;m++)d(n[m]);return d}return u})()({1:[function(u,a,i){Object.defineProperty(i,"__esModule",{value:!0}),i.default=void 0;function n(o){"@babel/helpers - typeof";return n=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(e){return typeof e}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n(o)}function d(o,e){if(!(o instanceof e))throw new TypeError("Cannot call a class as a function")}function g(o,e){for(var r=0;r<e.length;r++){var t=e[r];t.enumerable=t.enumerable||!1,t.configurable=!0,"value"in t&&(t.writable=!0),Object.defineProperty(o,f(t.key),t)}}function m(o,e,r){return e&&g(o.prototype,e),Object.defineProperty(o,"prototype",{writable:!1}),o}function f(o){var e=_(o,"string");return n(e)=="symbol"?e:e+""}function _(o,e){if(n(o)!="object"||!o)return o;var r=o[Symbol.toPrimitive];if(r!==void 0){var t=r.call(o,e);if(n(t)!="object")return t;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(o)}i.default=(function(){function o(){var e=this,r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},t=r.defaultLayoutOptions,s=t===void 0?{}:t,l=r.algorithms,v=l===void 0?["layered","stress","mrtree","radial","force","disco","sporeOverlap","sporeCompaction","rectpacking"]:l,c=r.workerFactory,p=r.workerUrl;if(d(this,o),this.defaultLayoutOptions=s,this.initialized=!1,typeof p>"u"&&typeof c>"u")throw new Error("Cannot construct an ELK without both 'workerUrl' and 'workerFactory'.");var k=c;typeof p<"u"&&typeof c>"u"&&(k=function(M){return new Worker(M)});var E=k(p);if(typeof E.postMessage!="function")throw new TypeError("Created worker does not provide the required 'postMessage' function.");this.worker=new h(E),this.worker.postMessage({cmd:"register",algorithms:v}).then(function(P){return e.initialized=!0}).catch(console.err)}return m(o,[{key:"layout",value:function(r){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},s=t.layoutOptions,l=s===void 0?this.defaultLayoutOptions:s,v=t.logging,c=v===void 0?!1:v,p=t.measureExecutionTime,k=p===void 0?!1:p;return r?this.worker.postMessage({cmd:"layout",graph:r,layoutOptions:l,options:{logging:c,measureExecutionTime:k}}):Promise.reject(new Error("Missing mandatory parameter 'graph'."))}},{key:"knownLayoutAlgorithms",value:function(){return this.worker.postMessage({cmd:"algorithms"})}},{key:"knownLayoutOptions",value:function(){return this.worker.postMessage({cmd:"options"})}},{key:"knownLayoutCategories",value:function(){return this.worker.postMessage({cmd:"categories"})}},{key:"terminateWorker",value:function(){this.worker&&this.worker.terminate()}}])})();var h=(function(){function o(e){var r=this;if(d(this,o),e===void 0)throw new Error("Missing mandatory parameter 'worker'.");this.resolvers={},this.worker=e,this.worker.onmessage=function(t){setTimeout(function(){r.receive(r,t)},0)}}return m(o,[{key:"postMessage",value:function(r){var t=this.id||0;this.id=t+1,r.id=t;var s=this;return new Promise(function(l,v){s.resolvers[t]=function(c,p){c?(s.convertGwtStyleError(c),v(c)):l(p)},s.worker.postMessage(r)})}},{key:"receive",value:function(r,t){var s=t.data,l=r.resolvers[s.id];l&&(delete r.resolvers[s.id],s.error?l(s.error):l(null,s.data))}},{key:"terminate",value:function(){this.worker&&this.worker.terminate()}},{key:"convertGwtStyleError",value:function(r){if(r){var t=r.__java$exception;t&&(t.cause&&t.cause.backingJsObject&&(r.cause=t.cause.backingJsObject,this.convertGwtStyleError(r.cause)),delete r.__java$exception)}}}])})()},{}],2:[function(u,a,i){var n=u("./elk-api.js").default;Object.defineProperty(a.exports,"__esModule",{value:!0}),a.exports=n,n.default=n},{"./elk-api.js":1}]},{},[2])(2)})})(O)),O.exports}var x=C();const A=L(x),q=S({__proto__:null,default:A},[x]);export{q as e};