sh3-core 0.22.0 → 0.22.1

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 (79) hide show
  1. package/dist/__test__/fixtures.js +1 -1
  2. package/dist/__test__/reset.js +1 -3
  3. package/dist/__test__/smoke.test.js +2 -2
  4. package/dist/actions/contextMenuModel.test.js +6 -3
  5. package/dist/actions/ctx-actions.svelte.test.js +9 -9
  6. package/dist/actions/dispatcher-v3.test.js +8 -0
  7. package/dist/actions/dispatcher.svelte.d.ts +1 -2
  8. package/dist/actions/dispatcher.svelte.js +6 -7
  9. package/dist/actions/dispatcher.test.js +9 -12
  10. package/dist/actions/listActionsFromEntries.test.js +1 -2
  11. package/dist/actions/listActive.test.js +2 -3
  12. package/dist/actions/menuBarModel.test.js +1 -7
  13. package/dist/actions/paletteModel.test.js +1 -3
  14. package/dist/actions/scope-helpers.test.js +4 -4
  15. package/dist/actions/shardContext.test.js +2 -2
  16. package/dist/actions/state.svelte.d.ts +12 -2
  17. package/dist/actions/state.svelte.js +15 -12
  18. package/dist/actions/state.test.js +4 -4
  19. package/dist/api.d.ts +3 -3
  20. package/dist/api.js +1 -1
  21. package/dist/app/admin/adminShard.svelte.js +1 -1
  22. package/dist/app/store/storeShard.svelte.js +10 -5
  23. package/dist/app-appearance/appearanceShard.svelte.js +1 -5
  24. package/dist/apps/lifecycle.js +49 -64
  25. package/dist/apps/lifecycle.test.js +30 -76
  26. package/dist/conflicts/adapter-documents.js +1 -2
  27. package/dist/createShell.js +1 -1
  28. package/dist/documents/handle.d.ts +9 -4
  29. package/dist/documents/handle.js +40 -29
  30. package/dist/documents/handle.test.js +60 -51
  31. package/dist/documents/index.d.ts +1 -1
  32. package/dist/documents/types.d.ts +16 -26
  33. package/dist/host.d.ts +1 -1
  34. package/dist/host.js +9 -56
  35. package/dist/host.svelte.test.js +31 -63
  36. package/dist/layouts-shard/LayoutsSection.svelte +1 -1
  37. package/dist/layouts-shard/layoutsShard.svelte.js +2 -5
  38. package/dist/layouts-shard/layoutsShard.svelte.test.js +2 -2
  39. package/dist/projects-shard/projectsShard.svelte.js +1 -5
  40. package/dist/registry/installer.js +1 -1
  41. package/dist/registry/loader.d.ts +1 -1
  42. package/dist/registry/loader.js +3 -3
  43. package/dist/registry/permission-descriptions.test.js +2 -2
  44. package/dist/registry/register.js +1 -1
  45. package/dist/registry/register.test.js +1 -1
  46. package/dist/runtime/runVerb-shell.test.js +1 -1
  47. package/dist/runtime/runVerb.js +2 -2
  48. package/dist/runtime/runVerb.test.js +9 -9
  49. package/dist/sh3Api/headless.js +1 -1
  50. package/dist/sh3core-shard/sh3coreShard.svelte.js +1 -6
  51. package/dist/shards/ctx-fetch.test.js +9 -9
  52. package/dist/shards/lifecycle.svelte.d.ts +108 -0
  53. package/dist/shards/lifecycle.svelte.js +551 -0
  54. package/dist/shards/lifecycle.test.js +139 -0
  55. package/dist/shards/types.d.ts +30 -63
  56. package/dist/shell-shard/shellShard.svelte.js +1 -4
  57. package/dist/version.d.ts +1 -1
  58. package/dist/version.js +1 -1
  59. package/package.json +1 -1
  60. package/dist/shards/activate-browse.test.js +0 -120
  61. package/dist/shards/activate-contributions.test.js +0 -141
  62. package/dist/shards/activate-error-isolation.test.d.ts +0 -1
  63. package/dist/shards/activate-error-isolation.test.js +0 -98
  64. package/dist/shards/activate-fields.svelte.test.d.ts +0 -1
  65. package/dist/shards/activate-fields.svelte.test.js +0 -121
  66. package/dist/shards/activate-on-key-revoked.test.d.ts +0 -1
  67. package/dist/shards/activate-on-key-revoked.test.js +0 -60
  68. package/dist/shards/activate-runtime.test.d.ts +0 -1
  69. package/dist/shards/activate-runtime.test.js +0 -344
  70. package/dist/shards/activate-scopeid.test.d.ts +0 -1
  71. package/dist/shards/activate-scopeid.test.js +0 -21
  72. package/dist/shards/activate.svelte.d.ts +0 -102
  73. package/dist/shards/activate.svelte.js +0 -407
  74. package/dist/shards/app-binding.svelte.d.ts +0 -8
  75. package/dist/shards/app-binding.svelte.js +0 -30
  76. package/dist/shards/app-binding.test.d.ts +0 -1
  77. package/dist/shards/app-binding.test.js +0 -25
  78. /package/dist/{shards/activate-browse.test.d.ts → actions/dispatcher-v3.test.d.ts} +0 -0
  79. /package/dist/shards/{activate-contributions.test.d.ts → lifecycle.test.d.ts} +0 -0
@@ -40,7 +40,7 @@ describe('describePermission — documents:read / documents:write', () => {
40
40
  function shardWithPerms(id, perms) {
41
41
  return {
42
42
  manifest: { id, label: id, version: '0.0.0', views: [], permissions: perms },
43
- activate: () => { },
43
+ register: () => { },
44
44
  };
45
45
  }
46
46
  function appWithPerms(id, perms) {
@@ -54,7 +54,7 @@ function appWithPerms(id, perms) {
54
54
  layoutVersion: 1,
55
55
  permissions: perms,
56
56
  },
57
- activate: () => { },
57
+ register: () => { },
58
58
  };
59
59
  }
60
60
  describe('extractBundlePermissions', () => {
@@ -8,7 +8,7 @@
8
8
  * manifests; the authoritative value comes from the persisted/server
9
9
  * metadata and must be stamped here before any consumer reads the manifest.
10
10
  */
11
- import { registerShard } from '../shards/activate.svelte';
11
+ import { registerShard } from '../shards/lifecycle.svelte';
12
12
  import { registerApp } from '../apps/registry.svelte';
13
13
  export function registerLoadedBundle(loaded, meta) {
14
14
  for (const shard of loaded.shards) {
@@ -3,7 +3,7 @@ import { resetFramework } from '../__test__/reset';
3
3
  import { makeApp, makeAppManifest, makeShard, makeShardManifest } from '../__test__/fixtures';
4
4
  import { registerLoadedBundle } from './register';
5
5
  import { registeredApps } from '../apps/registry.svelte';
6
- import { registeredShards } from '../shards/activate.svelte';
6
+ import { registeredShards } from '../shards/lifecycle.svelte';
7
7
  describe('registerLoadedBundle', () => {
8
8
  beforeEach(resetFramework);
9
9
  it('stamps meta.version onto every shard manifest before registering', () => {
@@ -12,7 +12,7 @@
12
12
  import { describe, it, expect, beforeEach } from 'vitest';
13
13
  import { MemoryDocumentBackend } from '../documents/backends';
14
14
  import { __setDocumentBackend, __setActiveScope } from '../documents/config';
15
- import { registerShard, activateShard, __resetShardRegistryForTest, } from '../shards/activate.svelte';
15
+ import { registerShard, activateShard, __resetShardRegistryForTest, } from '../shards/lifecycle.svelte';
16
16
  import { __resetViewRegistryForTest } from '../shards/registry';
17
17
  import { __resetActionsRegistryForTest } from '../actions/registry';
18
18
  import { runVerbProgrammatic } from './runVerb';
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * runVerbProgrammatic — programmatic verb dispatch with synthesized VerbContext.
3
3
  *
4
- * Used by `ctx.runVerb(...)` (see shards/activate.svelte.ts). Builds a
4
+ * Used by `ctx.runVerb(...)` (see shards/lifecycle.svelte.ts). Builds a
5
5
  * sink scrollback that captures entries into an array, a headless Sh3Api
6
6
  * (no terminal-bound state), a stub SessionClient, and a real TenantFsClient.
7
7
  * Verbs that opt in via `programmatic: true` run against this synthesized
@@ -15,7 +15,7 @@
15
15
  * Resolution: prefixed names (`'sh3-store:install'`) look up directly;
16
16
  * unprefixed sh3 names (`'apps'`) resolve against shardId 'sh3'.
17
17
  */
18
- import { activeShards } from '../shards/activate.svelte';
18
+ import { activeShards } from '../shards/lifecycle.svelte';
19
19
  import { getVerb, listVerbsWithShard } from '../shards/registry';
20
20
  import { makeSh3Api } from '../sh3Api/headless';
21
21
  import { Scrollback } from '../shell-shard/scrollback.svelte';
@@ -1,7 +1,7 @@
1
1
  import { describe, it, expect, beforeEach } from 'vitest';
2
2
  import { MemoryDocumentBackend } from '../documents/backends';
3
3
  import { __setDocumentBackend, __setActiveScope } from '../documents/config';
4
- import { registerShard, activateShard, __resetShardRegistryForTest, } from '../shards/activate.svelte';
4
+ import { registerShard, activateShard, __resetShardRegistryForTest, } from '../shards/lifecycle.svelte';
5
5
  import { __resetViewRegistryForTest } from '../shards/registry';
6
6
  import { runVerbProgrammatic } from './runVerb';
7
7
  function makeVerb(name, programmatic, body = async () => undefined) {
@@ -27,7 +27,7 @@ describe('runVerbProgrammatic', () => {
27
27
  it('rejects on unknown verb', async () => {
28
28
  registerShard({
29
29
  manifest: { id: 'tester', label: 'T', version: '0.0.0', views: [] },
30
- activate(ctx) {
30
+ register(ctx) {
31
31
  ctx.registerVerb(makeVerb('echo', true));
32
32
  },
33
33
  });
@@ -37,7 +37,7 @@ describe('runVerbProgrammatic', () => {
37
37
  it('rejects when verb is not programmatic', async () => {
38
38
  registerShard({
39
39
  manifest: { id: 'tester', label: 'T', version: '0.0.0', views: [] },
40
- activate(ctx) {
40
+ register(ctx) {
41
41
  ctx.registerVerb(makeVerb('plain', false));
42
42
  },
43
43
  });
@@ -47,7 +47,7 @@ describe('runVerbProgrammatic', () => {
47
47
  it('invokes a programmatic verb and resolves with { result, scrollback }', async () => {
48
48
  registerShard({
49
49
  manifest: { id: 'tester', label: 'T', version: '0.0.0', views: [] },
50
- activate(ctx) {
50
+ register(ctx) {
51
51
  ctx.registerVerb(makeVerb('echo', true, async (vctx, args) => {
52
52
  vctx.scrollback.push({
53
53
  kind: 'status',
@@ -71,7 +71,7 @@ describe('runVerbProgrammatic', () => {
71
71
  let observed = undefined;
72
72
  registerShard({
73
73
  manifest: { id: 'tester', label: 'T', version: '0.0.0', views: [] },
74
- activate(ctx) {
74
+ register(ctx) {
75
75
  ctx.registerVerb(makeVerb('capture', true, async (vctx) => {
76
76
  observed = vctx.structuredArgs;
77
77
  }));
@@ -85,7 +85,7 @@ describe('runVerbProgrammatic', () => {
85
85
  let received;
86
86
  registerShard({
87
87
  manifest: { id: 'tester', label: 'T', version: '0.0.0', views: [] },
88
- activate(ctx) {
88
+ register(ctx) {
89
89
  ctx.registerVerb(makeVerb('peek', true, async (vctx) => {
90
90
  received = vctx.signal;
91
91
  }));
@@ -99,7 +99,7 @@ describe('runVerbProgrammatic', () => {
99
99
  it('inner dispatch re-enters runVerb and merges scrollback into the outer capture', async () => {
100
100
  registerShard({
101
101
  manifest: { id: 'tester', label: 'T', version: '0.0.0', views: [] },
102
- activate(ctx) {
102
+ register(ctx) {
103
103
  ctx.registerVerb(makeVerb('inner', true, async (vctx) => {
104
104
  vctx.scrollback.push({ kind: 'status', text: 'inner-fired', level: 'info', ts: 0 });
105
105
  }));
@@ -120,7 +120,7 @@ describe('runVerbProgrammatic', () => {
120
120
  it('propagates an error thrown by the verb', async () => {
121
121
  registerShard({
122
122
  manifest: { id: 'tester', label: 'T', version: '0.0.0', views: [] },
123
- activate(ctx) {
123
+ register(ctx) {
124
124
  ctx.registerVerb(makeVerb('boom', true, async () => {
125
125
  throw new Error('kaboom');
126
126
  }));
@@ -133,7 +133,7 @@ describe('runVerbProgrammatic', () => {
133
133
  let observed = undefined;
134
134
  registerShard({
135
135
  manifest: { id: 'tester', label: 'T', version: '0.0.0', views: [] },
136
- activate(ctx) {
136
+ register(ctx) {
137
137
  ctx.registerVerb(makeVerb('peek-sh3', true, async (vctx) => {
138
138
  observed = vctx.sh3.dispatchToTerminal('foo');
139
139
  }));
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import { listRegisteredApps, getActiveApp } from '../apps/registry.svelte';
17
17
  import { launchApp } from '../apps/lifecycle';
18
- import { registeredShards, listStandaloneViews } from '../shards/activate.svelte';
18
+ import { registeredShards, listStandaloneViews } from '../shards/lifecycle.svelte';
19
19
  import { inspectActiveLayout, focusView, closeTab, popoutView, dockFloat, dockIntoActiveLayout, locateSlot as locateSlotInActiveLayout, } from '../layout/inspection';
20
20
  import { floatManager } from '../overlays/float';
21
21
  import { getUser, isAdmin } from '../auth/index';
@@ -65,7 +65,7 @@ export const sh3coreShard = {
65
65
  { id: 'sh3:keys-and-peers', label: 'Keys & Peers' },
66
66
  ],
67
67
  },
68
- activate(ctx) {
68
+ register(ctx) {
69
69
  const zones = ctx.state({
70
70
  user: {
71
71
  bindings: {},
@@ -165,9 +165,4 @@ export const sh3coreShard = {
165
165
  });
166
166
  });
167
167
  },
168
- autostart() {
169
- // Intentionally empty. Defining this field is what puts the sh3core
170
- // pseudo-shard on the self-starting path at boot (see bootstrap),
171
- // so `sh3core:home` is available before any app launches.
172
- },
173
168
  };
@@ -2,7 +2,7 @@ import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
2
2
  import { MemoryDocumentBackend } from '../documents/backends';
3
3
  import { __setDocumentBackend, __setActiveScope } from '../documents/config';
4
4
  import { __setEnvServerUrl } from '../env/index';
5
- import { registerShard, activateShard, __resetShardRegistryForTest, } from './activate.svelte';
5
+ import { registerShard, activateShard, __resetShardRegistryForTest, } from './lifecycle.svelte';
6
6
  import { __resetViewRegistryForTest } from './registry';
7
7
  describe('ctx.fetch', () => {
8
8
  let originalFetch;
@@ -27,7 +27,7 @@ describe('ctx.fetch', () => {
27
27
  let captured = null;
28
28
  registerShard({
29
29
  manifest: { id: 'test', label: 'test', version: '0.0.0', views: [] },
30
- activate(ctx) { captured = ctx; },
30
+ register(ctx) { captured = ctx; },
31
31
  });
32
32
  await activateShard('test');
33
33
  await captured.fetch('/api/foo');
@@ -42,7 +42,7 @@ describe('ctx.fetch', () => {
42
42
  let captured = null;
43
43
  registerShard({
44
44
  manifest: { id: 'test', label: 'test', version: '0.0.0', views: [] },
45
- activate(ctx) { captured = ctx; },
45
+ register(ctx) { captured = ctx; },
46
46
  });
47
47
  await activateShard('test');
48
48
  await captured.fetch('https://other.example.com/api/bar');
@@ -57,7 +57,7 @@ describe('ctx.fetch', () => {
57
57
  let captured = null;
58
58
  registerShard({
59
59
  manifest: { id: 'test', label: 'test', version: '0.0.0', views: [] },
60
- activate(ctx) { captured = ctx; },
60
+ register(ctx) { captured = ctx; },
61
61
  });
62
62
  await activateShard('test');
63
63
  await captured.fetch('api/baz');
@@ -79,7 +79,7 @@ describe('ctx.serverUrl', () => {
79
79
  let captured = null;
80
80
  registerShard({
81
81
  manifest: { id: 'test', label: 'test', version: '0.0.0', views: [] },
82
- activate(ctx) { captured = ctx; },
82
+ register(ctx) { captured = ctx; },
83
83
  });
84
84
  await activateShard('test');
85
85
  expect(captured.serverUrl).toBe('https://example.com');
@@ -89,7 +89,7 @@ describe('ctx.serverUrl', () => {
89
89
  let captured = null;
90
90
  registerShard({
91
91
  manifest: { id: 'test', label: 'test', version: '0.0.0', views: [] },
92
- activate(ctx) { captured = ctx; },
92
+ register(ctx) { captured = ctx; },
93
93
  });
94
94
  await activateShard('test');
95
95
  expect(captured.serverUrl).toBe('');
@@ -110,7 +110,7 @@ describe('ctx.resolveUrl', () => {
110
110
  let captured = null;
111
111
  registerShard({
112
112
  manifest: { id: 'test', label: 'test', version: '0.0.0', views: [] },
113
- activate(ctx) { captured = ctx; },
113
+ register(ctx) { captured = ctx; },
114
114
  });
115
115
  await activateShard('test');
116
116
  expect(captured.resolveUrl('/api/foo')).toBe('https://example.com/api/foo');
@@ -119,7 +119,7 @@ describe('ctx.resolveUrl', () => {
119
119
  let captured = null;
120
120
  registerShard({
121
121
  manifest: { id: 'test', label: 'test', version: '0.0.0', views: [] },
122
- activate(ctx) { captured = ctx; },
122
+ register(ctx) { captured = ctx; },
123
123
  });
124
124
  await activateShard('test');
125
125
  expect(captured.resolveUrl('https://other.example.com/ws')).toBe('https://other.example.com/ws');
@@ -128,7 +128,7 @@ describe('ctx.resolveUrl', () => {
128
128
  let captured = null;
129
129
  registerShard({
130
130
  manifest: { id: 'test', label: 'test', version: '0.0.0', views: [] },
131
- activate(ctx) { captured = ctx; },
131
+ register(ctx) { captured = ctx; },
132
132
  });
133
133
  await activateShard('test');
134
134
  expect(captured.resolveUrl('api/ws')).toBe('https://example.com/api/ws');
@@ -0,0 +1,108 @@
1
+ import type { Shard, ShardContext } from './types';
2
+ /**
3
+ * Reactive registry of every shard known to the host. Keys are shard ids.
4
+ * Populated by `registerShard`.
5
+ */
6
+ export declare const registeredShards: Map<string, Shard>;
7
+ /**
8
+ * Reactive map of shard ids that failed during the lifecycle. Populated
9
+ * by registerAllShards and related operations.
10
+ */
11
+ export interface ShardErrorEntry {
12
+ id: string;
13
+ error: unknown;
14
+ phase: 'register' | 'launch' | 'satellite';
15
+ timestamp: number;
16
+ }
17
+ export declare const erroredShards: Map<string, ShardErrorEntry>;
18
+ /** Read the app id currently bound to this shard, or null. */
19
+ export declare function getShardBinding(shardId: string): string | null;
20
+ /**
21
+ * Update which app's namespace this shard's `ctx.documents` resolves to.
22
+ * Pass `appId` to bind, `null` to unbind. Internal — only the lifecycle
23
+ * module and `apps/lifecycle.ts` call this.
24
+ */
25
+ export declare function rotateShardDocumentNamespace(shardId: string, appId: string | null): void;
26
+ export interface ShardEntry {
27
+ shard: Shard;
28
+ ctx: ShardContext;
29
+ viewIds: Set<string>;
30
+ verbNames: Set<string>;
31
+ /** Cleanup fns from things registered inside `register()`. Disposed only on shard re-register or framework teardown. */
32
+ bootCleanupFns: (() => Promise<void> | void)[];
33
+ /** Per-(shardId, appId) cleanup bags for things registered inside `onAppActivate`. Keyed by appId. */
34
+ appCleanupBags: Map<string, (() => Promise<void> | void)[]>;
35
+ /** Active appId during `onAppActivate` invocation, so register sites can route disposers to the right bag. */
36
+ activeAppId: string | null;
37
+ }
38
+ export declare function __setScopeResolver(resolver: (() => 'tenant' | 'project') | null): void;
39
+ /**
40
+ * Build a ShardContext for the given shard. The ctx is permanent for the
41
+ * shard's lifetime; the same instance is passed to `register`, every
42
+ * `onAppActivate`/`onAppDeactivate`, and every auxiliary hook.
43
+ *
44
+ * `entry` tracks cleanup bags. When the shard is inside an `onAppActivate`
45
+ * call, register sites route disposers to the per-app bag (keyed by
46
+ * `entry.activeAppId`); otherwise they go to the boot bag.
47
+ */
48
+ export declare function buildShardContext(shard: Shard, entry: ShardEntry): ShardContext;
49
+ export declare const shardEntries: Map<string, ShardEntry>;
50
+ export declare const activeShards: Map<string, Shard>;
51
+ /**
52
+ * Run `register(ctx)` on every registered shard. Idempotent — calling on
53
+ * an already-entered shard is a no-op. Errors are recorded in
54
+ * `erroredShards` with phase 'register'; one failure does not block others.
55
+ */
56
+ export declare function registerAllShards(): Promise<void>;
57
+ export declare function runAppActivate(shardId: string, appId: string): Promise<void>;
58
+ export declare function runAppDeactivate(shardId: string, appId: string): Promise<void>;
59
+ /**
60
+ * Tear down the active entry for a shard and rebuild it from the current
61
+ * `registeredShards.get(id)` value. Used by `registerShard` when replacing
62
+ * an existing shard with a fresh module (package update, dev hot-reload).
63
+ *
64
+ * Fires `onAppDeactivate` for every bound app, calls `deactivate?.()`,
65
+ * flushes all cleanup bags, builds a fresh ctx, then re-runs `register()`.
66
+ * Caller is responsible for re-invoking `runAppActivate` for any apps
67
+ * currently active that require this shard.
68
+ */
69
+ export declare function rebuildShardEntry(shardId: string): Promise<void>;
70
+ /**
71
+ * Register (or re-register) a shard. Records the shard in `registeredShards`.
72
+ * If the shard is already active (in `shardEntries`), triggers a hot-swap
73
+ * via `rebuildShardEntry` so the new module replaces the old one cleanly.
74
+ */
75
+ export declare function registerShard(shard: Shard): void;
76
+ /** True if the shard has been registered AND its register() has run. */
77
+ export declare function isActive(id: string): boolean;
78
+ /** Return the ShardContext for an active shard, or undefined. */
79
+ export declare function getShardContext(id: string): ShardContext | undefined;
80
+ /**
81
+ * Enumerate every view declared as `standalone` across the currently
82
+ * registered/active shards.
83
+ */
84
+ export declare function listStandaloneViews(): Array<{
85
+ shardId: string;
86
+ viewId: string;
87
+ label: string;
88
+ }>;
89
+ /** Test-only reset. */
90
+ export declare function __resetLifecycleForTest(): void;
91
+ /**
92
+ * Test-only reset for the full shard registry. Wipes all live entries,
93
+ * registered shards, and error records.
94
+ */
95
+ export declare function __resetShardRegistryForTest(): void;
96
+ /**
97
+ * @deprecated v2 compat shim — use `registerAllShards()` to run register
98
+ * for every registered shard. This shim activates a single shard by
99
+ * invoking its register hook directly. Retained for test fixtures during
100
+ * the migration; Phase 7 sweeps callers.
101
+ */
102
+ export declare function activateShard(id: string): Promise<void>;
103
+ /**
104
+ * @deprecated v2 compat shim — in v3, shards stay alive for the whole
105
+ * session. This shim performs a full teardown of the entry (for tests
106
+ * that explicitly want to verify cleanup paths).
107
+ */
108
+ export declare function deactivateShard(id: string): void;