sh3-core 0.22.0 → 0.22.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__test__/fixtures.js +1 -1
- package/dist/__test__/reset.js +1 -3
- package/dist/__test__/smoke.test.js +2 -2
- package/dist/actions/contextMenuModel.test.js +6 -3
- package/dist/actions/ctx-actions.svelte.test.js +9 -9
- package/dist/actions/dispatcher-v3.test.js +8 -0
- package/dist/actions/dispatcher.svelte.d.ts +1 -2
- package/dist/actions/dispatcher.svelte.js +6 -7
- package/dist/actions/dispatcher.test.js +9 -12
- package/dist/actions/listActionsFromEntries.test.js +1 -2
- package/dist/actions/listActive.test.js +2 -3
- package/dist/actions/menuBarModel.test.js +1 -7
- package/dist/actions/paletteModel.test.js +1 -3
- package/dist/actions/scope-helpers.test.js +4 -4
- package/dist/actions/shardContext.test.js +2 -2
- package/dist/actions/state.svelte.d.ts +12 -2
- package/dist/actions/state.svelte.js +15 -12
- package/dist/actions/state.test.js +4 -4
- package/dist/api.d.ts +4 -3
- package/dist/api.js +1 -1
- package/dist/app/admin/adminShard.svelte.js +1 -1
- package/dist/app/store/storeShard.svelte.js +10 -5
- package/dist/app-appearance/appearanceShard.svelte.js +1 -5
- package/dist/apps/lifecycle.js +49 -64
- package/dist/apps/lifecycle.test.js +30 -76
- package/dist/conflicts/adapter-documents.js +1 -2
- package/dist/createShell.js +1 -1
- package/dist/documents/handle.d.ts +9 -4
- package/dist/documents/handle.js +40 -29
- package/dist/documents/handle.test.js +60 -51
- package/dist/documents/index.d.ts +1 -1
- package/dist/documents/types.d.ts +16 -26
- package/dist/host.d.ts +1 -1
- package/dist/host.js +9 -56
- package/dist/host.svelte.test.js +31 -63
- package/dist/layouts-shard/LayoutsSection.svelte +1 -1
- package/dist/layouts-shard/layoutsShard.svelte.js +2 -5
- package/dist/layouts-shard/layoutsShard.svelte.test.js +2 -2
- package/dist/projects-shard/projectsShard.svelte.js +1 -5
- package/dist/registry/installer.js +1 -1
- package/dist/registry/loader.d.ts +1 -1
- package/dist/registry/loader.js +3 -3
- package/dist/registry/permission-descriptions.test.js +2 -2
- package/dist/registry/register.js +1 -1
- package/dist/registry/register.test.js +1 -1
- package/dist/runtime/runVerb-shell.test.js +1 -1
- package/dist/runtime/runVerb.js +2 -2
- package/dist/runtime/runVerb.test.js +9 -9
- package/dist/server-shard/types.d.ts +56 -0
- package/dist/sh3Api/headless.js +1 -1
- package/dist/sh3core-shard/sh3coreShard.svelte.js +1 -6
- package/dist/shards/ctx-fetch.test.js +9 -9
- package/dist/shards/lifecycle.svelte.d.ts +108 -0
- package/dist/shards/lifecycle.svelte.js +551 -0
- package/dist/shards/lifecycle.test.js +139 -0
- package/dist/shards/types.d.ts +30 -63
- package/dist/shell-shard/shellShard.svelte.js +1 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/shards/activate-browse.test.js +0 -120
- package/dist/shards/activate-contributions.test.js +0 -141
- package/dist/shards/activate-error-isolation.test.d.ts +0 -1
- package/dist/shards/activate-error-isolation.test.js +0 -98
- package/dist/shards/activate-fields.svelte.test.d.ts +0 -1
- package/dist/shards/activate-fields.svelte.test.js +0 -121
- package/dist/shards/activate-on-key-revoked.test.d.ts +0 -1
- package/dist/shards/activate-on-key-revoked.test.js +0 -60
- package/dist/shards/activate-runtime.test.d.ts +0 -1
- package/dist/shards/activate-runtime.test.js +0 -344
- package/dist/shards/activate-scopeid.test.d.ts +0 -1
- package/dist/shards/activate-scopeid.test.js +0 -21
- package/dist/shards/activate.svelte.d.ts +0 -102
- package/dist/shards/activate.svelte.js +0 -407
- package/dist/shards/app-binding.svelte.d.ts +0 -8
- package/dist/shards/app-binding.svelte.js +0 -30
- package/dist/shards/app-binding.test.d.ts +0 -1
- package/dist/shards/app-binding.test.js +0 -25
- /package/dist/{shards/activate-browse.test.d.ts → actions/dispatcher-v3.test.d.ts} +0 -0
- /package/dist/shards/{activate-contributions.test.d.ts → lifecycle.test.d.ts} +0 -0
|
@@ -25,7 +25,7 @@ export function makeShardManifest(overrides = {}) {
|
|
|
25
25
|
}
|
|
26
26
|
export function makeShard(overrides = {}) {
|
|
27
27
|
var _a;
|
|
28
|
-
return Object.assign({ manifest: makeShardManifest(overrides.manifest),
|
|
28
|
+
return Object.assign({ manifest: makeShardManifest(overrides.manifest), register: (_a = overrides.register) !== null && _a !== void 0 ? _a : (() => { }), deactivate: overrides.deactivate }, overrides);
|
|
29
29
|
}
|
|
30
30
|
export function makeSlotNode(slotId, viewId) {
|
|
31
31
|
const id = slotId !== null && slotId !== void 0 ? slotId : uid('slot');
|
package/dist/__test__/reset.js
CHANGED
|
@@ -8,8 +8,7 @@ import { __resetDragStateForTest } from '../layout/drag.svelte';
|
|
|
8
8
|
import { __resetLayoutStoreForTest } from '../layout/store.svelte';
|
|
9
9
|
import { resetSlotHostPool } from '../layout/slotHostPool.svelte';
|
|
10
10
|
import { __resetViewRegistryForTest } from '../shards/registry';
|
|
11
|
-
import { __resetShardRegistryForTest } from '../shards/
|
|
12
|
-
import { __resetShardBindingsForTest } from '../shards/app-binding.svelte';
|
|
11
|
+
import { __resetShardRegistryForTest } from '../shards/lifecycle.svelte';
|
|
13
12
|
import { __resetAppRegistryForTest } from '../apps/registry.svelte';
|
|
14
13
|
import { __resetDispatcherStateForTest } from '../actions/state.svelte';
|
|
15
14
|
import { __resetSelectionForTest } from '../actions/selection.svelte';
|
|
@@ -36,7 +35,6 @@ export function resetFramework() {
|
|
|
36
35
|
resetSlotHostPool();
|
|
37
36
|
__resetViewRegistryForTest();
|
|
38
37
|
__resetShardRegistryForTest();
|
|
39
|
-
__resetShardBindingsForTest();
|
|
40
38
|
__resetAppRegistryForTest();
|
|
41
39
|
__resetDispatcherStateForTest();
|
|
42
40
|
__resetSelectionForTest();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import { resetFramework } from './reset';
|
|
3
3
|
import { registeredApps, activeApp } from '../apps/registry.svelte';
|
|
4
|
-
import { registeredShards, activeShards } from '../shards/
|
|
4
|
+
import { registeredShards, activeShards } from '../shards/lifecycle.svelte';
|
|
5
5
|
import { layoutStore } from '../layout/store.svelte';
|
|
6
6
|
import { makeApp, makeShard } from './fixtures';
|
|
7
7
|
import { registerApp } from '../apps/registry.svelte';
|
|
8
|
-
import { registerShard } from '../shards/
|
|
8
|
+
import { registerShard } from '../shards/lifecycle.svelte';
|
|
9
9
|
describe('resetFramework', () => {
|
|
10
10
|
beforeEach(resetFramework);
|
|
11
11
|
it('returns all registries and the layout store to boot state', () => {
|
|
@@ -4,7 +4,7 @@ const mkEntry = (a, owner = 'shard.x') => ({
|
|
|
4
4
|
ownerShardId: owner,
|
|
5
5
|
action: Object.assign({ id: 'a', label: 'A', scope: 'home', run: () => { } }, a),
|
|
6
6
|
});
|
|
7
|
-
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(),
|
|
7
|
+
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(), mountedViewIds: new Set(), focusedViewId: null, selection: null, bindings: {}, platform: 'other' }, o));
|
|
8
8
|
describe('buildContextMenuModel', () => {
|
|
9
9
|
it('returns only actions with contextItem: true', () => {
|
|
10
10
|
const entries = [
|
|
@@ -59,7 +59,10 @@ describe('buildContextMenuModel', () => {
|
|
|
59
59
|
const model = buildContextMenuModel(entries, state, { element: 'cell' });
|
|
60
60
|
expect(model.tiers).toEqual([]);
|
|
61
61
|
});
|
|
62
|
-
it('app anchor
|
|
62
|
+
it('app anchor admits app-scoped actions from any shard once an app is active (v3)', () => {
|
|
63
|
+
// v3: scope 'app' means "active while any app is launched", regardless
|
|
64
|
+
// of which shard owns the action. The dispatcher no longer guards on
|
|
65
|
+
// ownerShardId / activeAppRequiredShards.
|
|
63
66
|
const state = mkState({
|
|
64
67
|
activeAppId: 'app.a',
|
|
65
68
|
activeAppRequiredShards: new Set(['shard.x']),
|
|
@@ -69,7 +72,7 @@ describe('buildContextMenuModel', () => {
|
|
|
69
72
|
mkEntry({ id: 'foreign', scope: 'app', contextItem: true, label: 'F' }, 'shard.y'),
|
|
70
73
|
];
|
|
71
74
|
const model = buildContextMenuModel(entries, state, 'app');
|
|
72
|
-
expect(model.tiers.flatMap((t) => t.items).map((i) => i.id)).toEqual(['mine']);
|
|
75
|
+
expect(model.tiers.flatMap((t) => t.items).map((i) => i.id).sort()).toEqual(['foreign', 'mine']);
|
|
73
76
|
});
|
|
74
77
|
it('home anchor only admits actions when no app is active', () => {
|
|
75
78
|
const noApp = mkState();
|
|
@@ -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/
|
|
4
|
+
import { registerShard, activateShard, __resetShardRegistryForTest, } from '../shards/lifecycle.svelte';
|
|
5
5
|
import { __resetViewRegistryForTest } from '../shards/registry';
|
|
6
6
|
import { __resetActionsRegistryForTest } from './registry';
|
|
7
7
|
import { __resetContributionsForTest } from '../contributions/registry';
|
|
@@ -19,7 +19,7 @@ describe('ShardContext.listActions / runAction (integration)', () => {
|
|
|
19
19
|
it('listActions enumerates actions registered by other shards', async () => {
|
|
20
20
|
registerShard({
|
|
21
21
|
manifest: { id: 'producer', label: 'P', version: '0.0.0', views: [] },
|
|
22
|
-
|
|
22
|
+
register(ctx) {
|
|
23
23
|
ctx.actions.register({
|
|
24
24
|
id: 'producer.do',
|
|
25
25
|
label: 'Do',
|
|
@@ -31,7 +31,7 @@ describe('ShardContext.listActions / runAction (integration)', () => {
|
|
|
31
31
|
let consumerCtx = null;
|
|
32
32
|
registerShard({
|
|
33
33
|
manifest: { id: 'consumer', label: 'C', version: '0.0.0', views: [] },
|
|
34
|
-
|
|
34
|
+
register(ctx) { consumerCtx = ctx; },
|
|
35
35
|
});
|
|
36
36
|
await activateShard('producer');
|
|
37
37
|
await activateShard('consumer');
|
|
@@ -45,7 +45,7 @@ describe('ShardContext.listActions / runAction (integration)', () => {
|
|
|
45
45
|
it('listActions({ activeOnly: true }) filters out inactive actions', async () => {
|
|
46
46
|
registerShard({
|
|
47
47
|
manifest: { id: 'producer', label: 'P', version: '0.0.0', views: [] },
|
|
48
|
-
|
|
48
|
+
register(ctx) {
|
|
49
49
|
ctx.actions.register({
|
|
50
50
|
id: 'home.go', label: 'H', scope: 'home', run: () => { },
|
|
51
51
|
});
|
|
@@ -58,7 +58,7 @@ describe('ShardContext.listActions / runAction (integration)', () => {
|
|
|
58
58
|
let consumerCtx = null;
|
|
59
59
|
registerShard({
|
|
60
60
|
manifest: { id: 'consumer', label: 'C', version: '0.0.0', views: [] },
|
|
61
|
-
|
|
61
|
+
register(ctx) { consumerCtx = ctx; },
|
|
62
62
|
});
|
|
63
63
|
await activateShard('producer');
|
|
64
64
|
await activateShard('consumer');
|
|
@@ -71,7 +71,7 @@ describe('ShardContext.listActions / runAction (integration)', () => {
|
|
|
71
71
|
let invokedVia = null;
|
|
72
72
|
registerShard({
|
|
73
73
|
manifest: { id: 'producer', label: 'P', version: '0.0.0', views: [] },
|
|
74
|
-
|
|
74
|
+
register(ctx) {
|
|
75
75
|
ctx.actions.register({
|
|
76
76
|
id: 'producer.go',
|
|
77
77
|
label: 'Go',
|
|
@@ -83,7 +83,7 @@ describe('ShardContext.listActions / runAction (integration)', () => {
|
|
|
83
83
|
let consumerCtx = null;
|
|
84
84
|
registerShard({
|
|
85
85
|
manifest: { id: 'consumer', label: 'C', version: '0.0.0', views: [] },
|
|
86
|
-
|
|
86
|
+
register(ctx) { consumerCtx = ctx; },
|
|
87
87
|
});
|
|
88
88
|
await activateShard('producer');
|
|
89
89
|
await activateShard('consumer');
|
|
@@ -93,7 +93,7 @@ describe('ShardContext.listActions / runAction (integration)', () => {
|
|
|
93
93
|
it('runAction rejects when the target action is inactive', async () => {
|
|
94
94
|
registerShard({
|
|
95
95
|
manifest: { id: 'producer', label: 'P', version: '0.0.0', views: [] },
|
|
96
|
-
|
|
96
|
+
register(ctx) {
|
|
97
97
|
ctx.actions.register({
|
|
98
98
|
id: 'gated.go', label: 'G', scope: 'app', run: () => { },
|
|
99
99
|
});
|
|
@@ -102,7 +102,7 @@ describe('ShardContext.listActions / runAction (integration)', () => {
|
|
|
102
102
|
let consumerCtx = null;
|
|
103
103
|
registerShard({
|
|
104
104
|
manifest: { id: 'consumer', label: 'C', version: '0.0.0', views: [] },
|
|
105
|
-
|
|
105
|
+
register(ctx) { consumerCtx = ctx; },
|
|
106
106
|
});
|
|
107
107
|
await activateShard('producer');
|
|
108
108
|
await activateShard('consumer');
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { getLiveDispatcherState } from './state.svelte';
|
|
3
|
+
describe('dispatcher state — v3', () => {
|
|
4
|
+
it('no longer exposes autostartShards', () => {
|
|
5
|
+
const state = getLiveDispatcherState();
|
|
6
|
+
expect('autostartShards' in state).toBe(false);
|
|
7
|
+
});
|
|
8
|
+
});
|
|
@@ -4,7 +4,6 @@ import type { Platform } from './shortcuts';
|
|
|
4
4
|
export interface DispatcherState {
|
|
5
5
|
activeAppId: string | null;
|
|
6
6
|
activeAppRequiredShards: Set<string>;
|
|
7
|
-
autostartShards: Set<string>;
|
|
8
7
|
mountedViewIds: Set<string>;
|
|
9
8
|
focusedViewId: string | null;
|
|
10
9
|
selection: Selection | null;
|
|
@@ -20,7 +19,7 @@ export interface TierIndex {
|
|
|
20
19
|
app: Map<string, string>;
|
|
21
20
|
home: Map<string, string>;
|
|
22
21
|
}
|
|
23
|
-
export declare function isScopeActive(scope: AtomicScope, state: DispatcherState,
|
|
22
|
+
export declare function isScopeActive(scope: AtomicScope, state: DispatcherState, _ownerShardId?: string): boolean;
|
|
24
23
|
export declare function buildTierIndex(entries: ActionEntry[], state: DispatcherState): TierIndex;
|
|
25
24
|
export interface KeydownEnv {
|
|
26
25
|
target: EventTarget | null;
|
|
@@ -8,17 +8,16 @@ import { resolveLabel } from './types';
|
|
|
8
8
|
import { effectiveShortcut } from './bindings';
|
|
9
9
|
import { scopeToTier, normalizeScope } from './scope-helpers';
|
|
10
10
|
export const TIER_ORDER = ['element', 'focus', 'view', 'app', 'home'];
|
|
11
|
-
export function isScopeActive(scope, state,
|
|
11
|
+
export function isScopeActive(scope, state, _ownerShardId) {
|
|
12
12
|
if (scope === 'home') {
|
|
13
13
|
return state.activeAppId === null;
|
|
14
14
|
}
|
|
15
15
|
if (scope === 'app') {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return
|
|
21
|
-
state.autostartShards.has(ownerShardId));
|
|
16
|
+
// v3: scope 'app' means "active while any app is launched", regardless
|
|
17
|
+
// of which shard owns the action. The dispatcher no longer gates on
|
|
18
|
+
// shard ownership — every shard registered with register() can
|
|
19
|
+
// contribute app-scoped actions that fire inside any app.
|
|
20
|
+
return state.activeAppId !== null;
|
|
22
21
|
}
|
|
23
22
|
if (typeof scope === 'string') {
|
|
24
23
|
if (scope.startsWith('view:')) {
|
|
@@ -4,28 +4,27 @@ const mkEntry = (action, owner = 'shard.x') => ({
|
|
|
4
4
|
ownerShardId: owner,
|
|
5
5
|
action: Object.assign({ id: 'a', label: 'A', scope: 'home', run: () => { } }, action),
|
|
6
6
|
});
|
|
7
|
-
const mkState = (overrides = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(),
|
|
7
|
+
const mkState = (overrides = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(), mountedViewIds: new Set(), focusedViewId: null, selection: null, bindings: {}, platform: 'other' }, overrides));
|
|
8
8
|
describe('isScopeActive', () => {
|
|
9
9
|
it('home active iff no app', () => {
|
|
10
10
|
expect(isScopeActive('home', mkState())).toBe(true);
|
|
11
11
|
expect(isScopeActive('home', mkState({ activeAppId: 'app.a' }))).toBe(false);
|
|
12
12
|
});
|
|
13
|
-
it('app active when app is loaded
|
|
13
|
+
it('app active for ANY shard when an app is loaded (v3 — owner gate removed)', () => {
|
|
14
14
|
const state = mkState({
|
|
15
15
|
activeAppId: 'app.a',
|
|
16
16
|
activeAppRequiredShards: new Set(['shard.x']),
|
|
17
17
|
});
|
|
18
18
|
expect(isScopeActive('app', state, 'shard.x')).toBe(true);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const state = mkState({
|
|
23
|
-
activeAppId: 'app.a',
|
|
24
|
-
activeAppRequiredShards: new Set(),
|
|
25
|
-
autostartShards: new Set(['__sh3core__']),
|
|
26
|
-
});
|
|
19
|
+
// v3: owner shard no longer gates app-scoped actions.
|
|
20
|
+
expect(isScopeActive('app', state, 'shard.y')).toBe(true);
|
|
21
|
+
// v3: no autostart concept — same rule applies.
|
|
27
22
|
expect(isScopeActive('app', state, '__sh3core__')).toBe(true);
|
|
28
23
|
});
|
|
24
|
+
it('app inactive when no app is loaded', () => {
|
|
25
|
+
const state = mkState({ activeAppId: null });
|
|
26
|
+
expect(isScopeActive('app', state, 'shard.x')).toBe(false);
|
|
27
|
+
});
|
|
29
28
|
it('view:X active iff X is mounted', () => {
|
|
30
29
|
const state = mkState({ mountedViewIds: new Set(['editor']) });
|
|
31
30
|
expect(isScopeActive('view:editor', state)).toBe(true);
|
|
@@ -66,7 +65,6 @@ describe('buildTierIndex', () => {
|
|
|
66
65
|
];
|
|
67
66
|
const state = mkState({
|
|
68
67
|
activeAppId: null, // home active
|
|
69
|
-
autostartShards: new Set(['shard.x']),
|
|
70
68
|
});
|
|
71
69
|
const idx = buildTierIndex(entries, state);
|
|
72
70
|
// Home is active; app is not (no app).
|
|
@@ -127,7 +125,6 @@ describe('dispatchKeydown', () => {
|
|
|
127
125
|
const state = mkState({
|
|
128
126
|
activeAppId: 'a',
|
|
129
127
|
activeAppRequiredShards: new Set(),
|
|
130
|
-
autostartShards: new Set(['__sh3core__']),
|
|
131
128
|
selection: { type: 'orb', ref: 1, ownerShardId: 's' },
|
|
132
129
|
});
|
|
133
130
|
const result = dispatchKeydown(mkEnv({ entries, runAction, state }));
|
|
@@ -4,7 +4,7 @@ const mkEntry = (a, owner = 'shard.x') => ({
|
|
|
4
4
|
ownerShardId: owner,
|
|
5
5
|
action: Object.assign({ id: 'a', label: 'A', scope: 'home', run: () => { } }, a),
|
|
6
6
|
});
|
|
7
|
-
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(),
|
|
7
|
+
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(), mountedViewIds: new Set(), focusedViewId: null, selection: null, bindings: {}, platform: 'other' }, o));
|
|
8
8
|
describe('listActionsFromEntries', () => {
|
|
9
9
|
it('returns [] for an empty registry', () => {
|
|
10
10
|
expect(listActionsFromEntries([], mkState())).toEqual([]);
|
|
@@ -55,7 +55,6 @@ describe('listActionsFromEntries', () => {
|
|
|
55
55
|
];
|
|
56
56
|
const state = mkState({
|
|
57
57
|
activeAppId: null, // app tier inactive
|
|
58
|
-
autostartShards: new Set(['__sh3core__']),
|
|
59
58
|
mountedViewIds: new Set(['editor']),
|
|
60
59
|
});
|
|
61
60
|
const out = listActionsFromEntries(entries, state);
|
|
@@ -4,7 +4,7 @@ const mkEntry = (a, owner = 'shard.x') => ({
|
|
|
4
4
|
ownerShardId: owner,
|
|
5
5
|
action: Object.assign({ id: 'a', label: 'A', scope: 'home', run: () => { } }, a),
|
|
6
6
|
});
|
|
7
|
-
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(),
|
|
7
|
+
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(), mountedViewIds: new Set(), focusedViewId: null, selection: null, bindings: {}, platform: 'other' }, o));
|
|
8
8
|
describe('listActiveFromEntries', () => {
|
|
9
9
|
it('omits actions whose scope is not active', () => {
|
|
10
10
|
const entries = [mkEntry({ id: 'p', scope: 'app' })];
|
|
@@ -27,7 +27,7 @@ describe('listActiveFromEntries', () => {
|
|
|
27
27
|
id: 'm', scope: ['app', 'view:editor'],
|
|
28
28
|
}, '__sh3core__')];
|
|
29
29
|
const state = mkState({
|
|
30
|
-
activeAppId: 'a',
|
|
30
|
+
activeAppId: 'a',
|
|
31
31
|
mountedViewIds: new Set(['editor']),
|
|
32
32
|
});
|
|
33
33
|
const out = listActiveFromEntries(entries, state);
|
|
@@ -76,7 +76,6 @@ describe('listActiveFromEntries', () => {
|
|
|
76
76
|
];
|
|
77
77
|
const state = mkState({
|
|
78
78
|
activeAppId: 'a',
|
|
79
|
-
autostartShards: new Set(['__sh3core__']),
|
|
80
79
|
mountedViewIds: new Set(['editor']),
|
|
81
80
|
});
|
|
82
81
|
const out = listActiveFromEntries(entries, state);
|
|
@@ -4,7 +4,7 @@ const mkEntry = (a, owner = 'shard.x') => ({
|
|
|
4
4
|
ownerShardId: owner,
|
|
5
5
|
action: Object.assign({ id: 'a', label: 'A', scope: 'home', run: () => { } }, a),
|
|
6
6
|
});
|
|
7
|
-
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(),
|
|
7
|
+
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(), mountedViewIds: new Set(), focusedViewId: null, selection: null, bindings: {}, platform: 'other' }, o));
|
|
8
8
|
describe('resolveMenuContainers', () => {
|
|
9
9
|
it('returns [] when no app is active', () => {
|
|
10
10
|
expect(resolveMenuContainers(null, undefined)).toEqual([]);
|
|
@@ -72,7 +72,6 @@ describe('resolveMenuItems', () => {
|
|
|
72
72
|
const state = mkState({
|
|
73
73
|
activeAppId: 'app.a',
|
|
74
74
|
activeAppRequiredShards: new Set(['shard.x']),
|
|
75
|
-
autostartShards: new Set(['shard.x']),
|
|
76
75
|
});
|
|
77
76
|
const entries = [
|
|
78
77
|
mkEntry({ id: 'p', scope: ['home', 'app'], menuItem: 'file', label: 'P' }),
|
|
@@ -161,7 +160,6 @@ describe("resolveMenuItems — required-shard menu filter (issue #32)", () => {
|
|
|
161
160
|
const state = mkState({
|
|
162
161
|
activeAppId: 'other-app',
|
|
163
162
|
activeAppRequiredShards: new Set(['other-shard']),
|
|
164
|
-
autostartShards: new Set(['guml.core']),
|
|
165
163
|
});
|
|
166
164
|
const entries = [
|
|
167
165
|
mkEntry({ id: 'guml.project.new', scope: 'app', menuItem: 'file', label: 'New Project…' }, 'guml.core'),
|
|
@@ -172,7 +170,6 @@ describe("resolveMenuItems — required-shard menu filter (issue #32)", () => {
|
|
|
172
170
|
const state = mkState({
|
|
173
171
|
activeAppId: 'guml-ide',
|
|
174
172
|
activeAppRequiredShards: new Set(['guml.core']),
|
|
175
|
-
autostartShards: new Set(['guml.core']),
|
|
176
173
|
});
|
|
177
174
|
const entries = [
|
|
178
175
|
mkEntry({ id: 'guml.project.new', scope: 'app', menuItem: 'file', label: 'New Project…' }, 'guml.core'),
|
|
@@ -184,7 +181,6 @@ describe("resolveMenuItems — required-shard menu filter (issue #32)", () => {
|
|
|
184
181
|
const state = mkState({
|
|
185
182
|
activeAppId: 'other-app',
|
|
186
183
|
activeAppRequiredShards: new Set(['other-shard']),
|
|
187
|
-
autostartShards: new Set(['guml.core']),
|
|
188
184
|
mountedViewIds: new Set(['editor']),
|
|
189
185
|
});
|
|
190
186
|
const entries = [
|
|
@@ -196,7 +192,6 @@ describe("resolveMenuItems — required-shard menu filter (issue #32)", () => {
|
|
|
196
192
|
const state = mkState({
|
|
197
193
|
activeAppId: 'other-app',
|
|
198
194
|
activeAppRequiredShards: new Set(['other-shard']),
|
|
199
|
-
autostartShards: new Set(['guml.core']),
|
|
200
195
|
});
|
|
201
196
|
const entries = [
|
|
202
197
|
mkEntry({ id: 'g.global', scope: ['home', 'app'], menuItem: 'file', label: 'Global' }, 'guml.core'),
|
|
@@ -207,7 +202,6 @@ describe("resolveMenuItems — required-shard menu filter (issue #32)", () => {
|
|
|
207
202
|
const state = mkState({
|
|
208
203
|
activeAppId: 'other-app',
|
|
209
204
|
activeAppRequiredShards: new Set(['other-shard']),
|
|
210
|
-
autostartShards: new Set(['guml.core']),
|
|
211
205
|
});
|
|
212
206
|
const entries = [
|
|
213
207
|
mkEntry({ id: 'g.parent', scope: 'app', menuItem: 'file', label: 'GUML', submenu: true }, 'guml.core'),
|
|
@@ -4,7 +4,7 @@ const mkEntry = (a, owner = 'shard.x') => ({
|
|
|
4
4
|
ownerShardId: owner,
|
|
5
5
|
action: Object.assign({ id: 'a', label: 'A', scope: 'home', run: () => { } }, a),
|
|
6
6
|
});
|
|
7
|
-
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(),
|
|
7
|
+
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(), mountedViewIds: new Set(), focusedViewId: null, selection: null, bindings: {}, platform: 'other' }, o));
|
|
8
8
|
describe('buildPaletteCandidates', () => {
|
|
9
9
|
it('includes actions with paletteItem default true', () => {
|
|
10
10
|
const entries = [mkEntry({ id: 'x', scope: 'home', label: 'X' })];
|
|
@@ -25,7 +25,6 @@ describe('buildPaletteCandidates', () => {
|
|
|
25
25
|
const entries = [mkEntry({ id: 'p', scope: ['home', 'app'], label: 'P' }, '__sh3core__')];
|
|
26
26
|
const state = mkState({
|
|
27
27
|
activeAppId: 'a',
|
|
28
|
-
autostartShards: new Set(['__sh3core__']),
|
|
29
28
|
});
|
|
30
29
|
const out = buildPaletteCandidates(entries, state);
|
|
31
30
|
expect(out).toHaveLength(1);
|
|
@@ -39,7 +38,6 @@ describe('buildPaletteCandidates', () => {
|
|
|
39
38
|
];
|
|
40
39
|
const state = mkState({
|
|
41
40
|
activeAppId: 'a',
|
|
42
|
-
autostartShards: new Set(['__sh3core__']),
|
|
43
41
|
mountedViewIds: new Set(['editor']),
|
|
44
42
|
});
|
|
45
43
|
const out = buildPaletteCandidates(entries, state);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { scopeToTier, normalizeScope, scopeBadge, innermostActiveScope, scopeEquals, scopeToString, parseScopeString, } from './scope-helpers';
|
|
3
|
-
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(),
|
|
3
|
+
const mkState = (o = {}) => (Object.assign({ activeAppId: null, activeAppRequiredShards: new Set(), mountedViewIds: new Set(), focusedViewId: null, selection: null, bindings: {}, platform: 'other' }, o));
|
|
4
4
|
describe('scopeToTier', () => {
|
|
5
5
|
it('maps atoms to tier names', () => {
|
|
6
6
|
expect(scopeToTier('home')).toBe('home');
|
|
@@ -37,7 +37,7 @@ describe('innermostActiveScope', () => {
|
|
|
37
37
|
});
|
|
38
38
|
it('picks the innermost active tier across a multi-scope action', () => {
|
|
39
39
|
const state = mkState({
|
|
40
|
-
activeAppId: 'a',
|
|
40
|
+
activeAppId: 'a',
|
|
41
41
|
mountedViewIds: new Set(['editor']),
|
|
42
42
|
});
|
|
43
43
|
const winner = innermostActiveScope(['app', 'view:editor'], state, 'owner');
|
|
@@ -45,14 +45,14 @@ describe('innermostActiveScope', () => {
|
|
|
45
45
|
});
|
|
46
46
|
it('falls back to outer tier when inner is inactive', () => {
|
|
47
47
|
const state = mkState({
|
|
48
|
-
activeAppId: 'a',
|
|
48
|
+
activeAppId: 'a',
|
|
49
49
|
});
|
|
50
50
|
const winner = innermostActiveScope(['app', 'view:editor'], state, 'owner');
|
|
51
51
|
expect(winner).toBe('app');
|
|
52
52
|
});
|
|
53
53
|
it('element scope beats view scope when both active', () => {
|
|
54
54
|
const state = mkState({
|
|
55
|
-
activeAppId: 'a',
|
|
55
|
+
activeAppId: 'a',
|
|
56
56
|
mountedViewIds: new Set(['editor']),
|
|
57
57
|
selection: { type: 'row', ref: {}, ownerShardId: 'owner' },
|
|
58
58
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { registerShard, activateShard, deactivateShard } from '../shards/
|
|
2
|
+
import { registerShard, activateShard, deactivateShard } from '../shards/lifecycle.svelte';
|
|
3
3
|
import { __resetContributionsForTest } from '../contributions/registry';
|
|
4
4
|
import { __resetActionsRegistryForTest, listActions } from './registry';
|
|
5
5
|
import { __resetSelectionForTest, getSelection } from './selection.svelte';
|
|
6
6
|
function mkShard(id, onActivate) {
|
|
7
7
|
return {
|
|
8
8
|
manifest: { id, label: id, version: '0.0.0-test', views: [] },
|
|
9
|
-
async
|
|
9
|
+
async register(ctx) { onActivate(ctx); },
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
describe('ctx.actions on ShardContext', () => {
|
|
@@ -12,7 +12,6 @@ export declare function __notifyActiveChange(): void;
|
|
|
12
12
|
/** Test-only alias for the internal notifier. */
|
|
13
13
|
export declare const __notifyActiveChangeForTest: typeof __notifyActiveChange;
|
|
14
14
|
export declare function setActiveApp(appId: string | null, requiredShards: Set<string>): void;
|
|
15
|
-
export declare function setAutostartShards(shards: Set<string>): void;
|
|
16
15
|
export declare function setMountedViewIds(ids: Set<string>): void;
|
|
17
16
|
/**
|
|
18
17
|
* One-shot snapshot: walk the active layout tree and update
|
|
@@ -24,5 +23,16 @@ export declare function syncMountedViewIdsFromLayout(): void;
|
|
|
24
23
|
export declare function setFocusedViewId(id: string | null): void;
|
|
25
24
|
export declare function setUserBindings(bindings: Record<string, string | null>): void;
|
|
26
25
|
export declare function getLiveDispatcherState(): DispatcherState;
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated v3: autostartShards has been removed. This is a no-op shim
|
|
28
|
+
* retained so existing test fixtures compile during the migration window.
|
|
29
|
+
* Phase 7 sweeps these call sites.
|
|
30
|
+
*/
|
|
31
|
+
export declare function addAutostartShard(_id: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* @deprecated v3: autostartShards has been removed. This is a no-op shim
|
|
34
|
+
* retained so existing test fixtures compile during the migration window.
|
|
35
|
+
* Phase 7 sweeps these call sites.
|
|
36
|
+
*/
|
|
37
|
+
export declare function setAutostartShards(_shards: Set<string>): void;
|
|
28
38
|
export declare function __resetDispatcherStateForTest(): void;
|
|
@@ -13,7 +13,6 @@ import { layoutStore } from '../layout/store.svelte';
|
|
|
13
13
|
import { collectTreeSlotRefs } from '../layout/tree-walk';
|
|
14
14
|
let activeAppId = $state(null);
|
|
15
15
|
let activeAppRequiredShards = $state(new Set());
|
|
16
|
-
let autostartShards = $state(new Set());
|
|
17
16
|
let mountedViewIds = $state(new Set());
|
|
18
17
|
let focusedViewId = $state(null);
|
|
19
18
|
let userBindings = $state({});
|
|
@@ -51,10 +50,6 @@ export function setActiveApp(appId, requiredShards) {
|
|
|
51
50
|
activeAppRequiredShards = new Set(requiredShards);
|
|
52
51
|
notifyActiveChange();
|
|
53
52
|
}
|
|
54
|
-
export function setAutostartShards(shards) {
|
|
55
|
-
autostartShards = new Set(shards);
|
|
56
|
-
notifyActiveChange();
|
|
57
|
-
}
|
|
58
53
|
export function setMountedViewIds(ids) {
|
|
59
54
|
mountedViewIds = new Set(ids);
|
|
60
55
|
notifyActiveChange();
|
|
@@ -87,7 +82,6 @@ export function getLiveDispatcherState() {
|
|
|
87
82
|
return {
|
|
88
83
|
activeAppId,
|
|
89
84
|
activeAppRequiredShards,
|
|
90
|
-
autostartShards,
|
|
91
85
|
mountedViewIds,
|
|
92
86
|
focusedViewId,
|
|
93
87
|
selection: getSelection(),
|
|
@@ -95,16 +89,25 @@ export function getLiveDispatcherState() {
|
|
|
95
89
|
platform,
|
|
96
90
|
};
|
|
97
91
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
92
|
+
/**
|
|
93
|
+
* @deprecated v3: autostartShards has been removed. This is a no-op shim
|
|
94
|
+
* retained so existing test fixtures compile during the migration window.
|
|
95
|
+
* Phase 7 sweeps these call sites.
|
|
96
|
+
*/
|
|
97
|
+
export function addAutostartShard(_id) {
|
|
98
|
+
/* no-op */
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* @deprecated v3: autostartShards has been removed. This is a no-op shim
|
|
102
|
+
* retained so existing test fixtures compile during the migration window.
|
|
103
|
+
* Phase 7 sweeps these call sites.
|
|
104
|
+
*/
|
|
105
|
+
export function setAutostartShards(_shards) {
|
|
106
|
+
/* no-op */
|
|
103
107
|
}
|
|
104
108
|
export function __resetDispatcherStateForTest() {
|
|
105
109
|
activeAppId = null;
|
|
106
110
|
activeAppRequiredShards = new Set();
|
|
107
|
-
autostartShards = new Set();
|
|
108
111
|
mountedViewIds = new Set();
|
|
109
112
|
focusedViewId = null;
|
|
110
113
|
userBindings = {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { setActiveApp,
|
|
2
|
+
import { setActiveApp, setFocusedViewId, setMountedViewIds, setUserBindings, getLiveDispatcherState, onActiveChange, __notifyActiveChangeForTest, __resetDispatcherStateForTest, } from './state.svelte';
|
|
3
3
|
import { __resetSelectionForTest, makeSelectionApi } from './selection.svelte';
|
|
4
4
|
describe('live dispatcher state', () => {
|
|
5
5
|
beforeEach(() => {
|
|
@@ -46,15 +46,15 @@ describe('onActiveChange', () => {
|
|
|
46
46
|
it('fires on every setter', () => {
|
|
47
47
|
let n = 0;
|
|
48
48
|
const off = onActiveChange(() => { n++; });
|
|
49
|
+
// v3: setAutostartShards is a no-op shim; 4 setters notify.
|
|
49
50
|
setActiveApp('a', new Set(['s']));
|
|
50
|
-
setAutostartShards(new Set(['s']));
|
|
51
51
|
setMountedViewIds(new Set(['v']));
|
|
52
52
|
setFocusedViewId('v');
|
|
53
53
|
setUserBindings({ foo: 'Ctrl+K' });
|
|
54
|
-
expect(n).toBe(
|
|
54
|
+
expect(n).toBe(4);
|
|
55
55
|
off();
|
|
56
56
|
setActiveApp(null, new Set());
|
|
57
|
-
expect(n).toBe(
|
|
57
|
+
expect(n).toBe(4);
|
|
58
58
|
});
|
|
59
59
|
it('fires on external notify (used for registry change)', () => {
|
|
60
60
|
let n = 0;
|
package/dist/api.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export { spawnSatellite } from './sh3Api/window';
|
|
|
27
27
|
export type { SpawnSatelliteOptions } from './sh3Api/window';
|
|
28
28
|
export type { SatellitePayload } from './boot/satellitePayload';
|
|
29
29
|
export { inspectActiveLayout, spliceIntoActiveLayout, dockIntoActiveLayout, focusTab, focusView, collapseChild, expandChild, closeTab, popoutView, dockFloat, locateSlot, } from './layout/inspection';
|
|
30
|
-
export type { DocumentHandle,
|
|
30
|
+
export type { DocumentHandle, DocumentMeta, DocumentChange, AutosaveController, } from './documents/types';
|
|
31
31
|
export { PERMISSION_DOCUMENTS_BROWSE, PERMISSION_DOCUMENTS_READ, PERMISSION_DOCUMENTS_WRITE, } from './documents/types';
|
|
32
32
|
export type { BrowseCapability } from './documents/browse';
|
|
33
33
|
export type { DocumentPickerApi, DocumentOpenOptions, DocumentSaveOptions } from './documents/picker-api';
|
|
@@ -38,8 +38,8 @@ export type { ConflictItem, ConflictBranch as ConflictManagerBranch, ResolveOpti
|
|
|
38
38
|
export { CONFLICT_RENDERER_POINT, ConflictPermissionError, ConflictSessionOrphanedError, } from './conflicts/api';
|
|
39
39
|
export type { ColorPickOptions, ColorContribution, ColorApi, } from './color/api';
|
|
40
40
|
export { COLOR_PICKER_POINT } from './color/api';
|
|
41
|
-
export { registeredShards, activeShards, erroredShards } from './shards/
|
|
42
|
-
export type { ShardErrorEntry } from './shards/
|
|
41
|
+
export { registeredShards, activeShards, erroredShards } from './shards/lifecycle.svelte';
|
|
42
|
+
export type { ShardErrorEntry } from './shards/lifecycle.svelte';
|
|
43
43
|
export type { RegistryIndex, PackageEntry, PackageVersion, RequiredDependency, InstalledPackage, InstallResult, PackageMeta, RemoteInstallRequest, } from './registry/types';
|
|
44
44
|
export type { ResolvedPackage } from './registry/client';
|
|
45
45
|
export { fetchRegistries, fetchArchive, buildPackageMeta } from './registry/client';
|
|
@@ -55,6 +55,7 @@ export declare const capabilities: {
|
|
|
55
55
|
readonly hotInstall: boolean;
|
|
56
56
|
};
|
|
57
57
|
export type { ServerShard, ServerShardContext, TenantDocumentAPI } from './server-shard/types';
|
|
58
|
+
export type { ApiKeyPublic as ServerApiKeyPublic } from './server-shard/types';
|
|
58
59
|
export type { Verb, VerbContext, Sh3Api, VerbSchema, PortableJSONSchema, DispatchToTerminalResult, } from './verbs/types';
|
|
59
60
|
export type { Scrollback } from './shell-shard/scrollback.svelte';
|
|
60
61
|
export type { SessionClient } from './shell-shard/session-client.svelte';
|
package/dist/api.js
CHANGED
|
@@ -42,7 +42,7 @@ export { COLOR_PICKER_POINT } from './color/api';
|
|
|
42
42
|
// and tooling shards that need to visualize framework state. Phase 9
|
|
43
43
|
// addition: diagnostic used to reach `activate.svelte` directly via $lib;
|
|
44
44
|
// the package boundary requires routing through the public surface.
|
|
45
|
-
export { registeredShards, activeShards, erroredShards } from './shards/
|
|
45
|
+
export { registeredShards, activeShards, erroredShards } from './shards/lifecycle.svelte';
|
|
46
46
|
export { fetchRegistries, fetchArchive, buildPackageMeta } from './registry/client';
|
|
47
47
|
export { validateRegistryIndex } from './registry/schema';
|
|
48
48
|
// Key mint/revoke types — client shards that declare `keys:mint` get ctx.keys.
|
|
@@ -69,7 +69,7 @@ export const storeShard = {
|
|
|
69
69
|
{ id: 'sh3-store:browse', label: 'Store' },
|
|
70
70
|
],
|
|
71
71
|
},
|
|
72
|
-
|
|
72
|
+
register(ctx) {
|
|
73
73
|
const env = ctx.env({ registries: [] });
|
|
74
74
|
const state = ctx.state({
|
|
75
75
|
ephemeral: {
|
|
@@ -260,9 +260,14 @@ export const storeShard = {
|
|
|
260
260
|
ctx.registerVerb(updateVerb);
|
|
261
261
|
// refreshInstalled can run immediately (hits server, no env needed).
|
|
262
262
|
refreshInstalled();
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
263
|
+
// v3: env hydration happens after register() returns. React via $effect
|
|
264
|
+
// so refreshCatalog fires once registries populate.
|
|
265
|
+
$effect.root(() => {
|
|
266
|
+
$effect(() => {
|
|
267
|
+
if (env.registries.length > 0) {
|
|
268
|
+
storeContext.refreshCatalog();
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
});
|
|
267
272
|
},
|
|
268
273
|
};
|