sh3-core 0.22.5 → 0.24.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 (89) hide show
  1. package/dist/Sh3.svelte +4 -4
  2. package/dist/actions/listActive.js +1 -0
  3. package/dist/actions/listActive.test.js +13 -0
  4. package/dist/actions/types.d.ts +12 -0
  5. package/dist/api.d.ts +3 -1
  6. package/dist/api.js +3 -1
  7. package/dist/app/admin/adminApp.js +2 -0
  8. package/dist/app/admin/adminShard.svelte.js +1 -0
  9. package/dist/app/store/StoreView.svelte +1 -1
  10. package/dist/app/store/storeApp.js +3 -1
  11. package/dist/app/store/storeShard.svelte.js +1 -0
  12. package/dist/app-appearance/appearanceShard.svelte.js +1 -0
  13. package/dist/apps/lifecycle.js +22 -10
  14. package/dist/apps/lifecycle.test.js +53 -1
  15. package/dist/apps/types.d.ts +9 -0
  16. package/dist/chrome/CompactChrome.svelte +11 -7
  17. package/dist/chrome/MenuSheet.svelte +19 -6
  18. package/dist/contributions/contextSource.d.ts +48 -0
  19. package/dist/contributions/contextSource.js +21 -0
  20. package/dist/createShell.js +40 -0
  21. package/dist/documents/picker-api.test.js +40 -0
  22. package/dist/documents/picker-primitive.d.ts +37 -8
  23. package/dist/documents/picker-primitive.js +5 -13
  24. package/dist/host.js +30 -7
  25. package/dist/layout/slotHostPool.svelte.d.ts +11 -0
  26. package/dist/layout/slotHostPool.svelte.js +41 -17
  27. package/dist/layout/slotHostPool.test.js +45 -1
  28. package/dist/layouts-shard/layoutsShard.svelte.js +1 -0
  29. package/dist/overlays/OverlayRoots.svelte +15 -4
  30. package/dist/overlays/__test__/OverlayBindHarness.svelte +20 -0
  31. package/dist/overlays/__test__/OverlayBindHarness.svelte.d.ts +3 -0
  32. package/dist/overlays/float-compact-bind.svelte.test.d.ts +1 -0
  33. package/dist/overlays/float-compact-bind.svelte.test.js +51 -0
  34. package/dist/overlays/modal.js +3 -0
  35. package/dist/overlays/modal.test.js +45 -0
  36. package/dist/overlays/types.d.ts +9 -0
  37. package/dist/primitives/widgets/DocumentFilePicker.svelte +9 -7
  38. package/dist/primitives/widgets/DocumentFilePicker.svelte.d.ts +44 -27
  39. package/dist/primitives/widgets/ShardPicker.svelte +38 -0
  40. package/dist/primitives/widgets/ShardPicker.svelte.d.ts +9 -0
  41. package/dist/primitives/widgets/_DocumentBrowser.svelte +15 -7
  42. package/dist/primitives/widgets/_DocumentBrowser.svelte.d.ts +2 -0
  43. package/dist/projects/scope-gate.d.ts +4 -0
  44. package/dist/projects/scope-gate.js +51 -0
  45. package/dist/projects/scope-gate.test.d.ts +1 -0
  46. package/dist/projects/scope-gate.test.js +92 -0
  47. package/dist/projects-shard/ProjectManage.svelte +42 -2
  48. package/dist/projects-shard/ProjectManage.svelte.test.js +10 -9
  49. package/dist/projects-shard/projectsApi.d.ts +3 -2
  50. package/dist/projects-shard/projectsApi.test.js +1 -1
  51. package/dist/projects-shard/projectsShard.svelte.js +1 -0
  52. package/dist/runtime/runVerb.d.ts +9 -0
  53. package/dist/runtime/runVerb.js +4 -4
  54. package/dist/runtime/runVerb.test.js +29 -0
  55. package/dist/sh3Api/headless.d.ts +7 -0
  56. package/dist/sh3Api/headless.js +3 -1
  57. package/dist/sh3Api/headless.svelte.test.js +42 -0
  58. package/dist/sh3core-shard/Sh3Home.svelte +3 -4
  59. package/dist/sh3core-shard/sh3coreShard.svelte.js +1 -0
  60. package/dist/shards/lifecycle.svelte.d.ts +8 -2
  61. package/dist/shards/lifecycle.svelte.js +65 -7
  62. package/dist/shards/lifecycle.test.js +110 -1
  63. package/dist/shards/types.d.ts +13 -0
  64. package/dist/shell-shard/Terminal.svelte +1 -4
  65. package/dist/shell-shard/Terminal.svelte.d.ts +0 -2
  66. package/dist/shell-shard/dispatch.d.ts +0 -2
  67. package/dist/shell-shard/dispatch.js +0 -2
  68. package/dist/shell-shard/display-cwd.test.js +4 -4
  69. package/dist/shell-shard/manifest.js +1 -0
  70. package/dist/shell-shard/shellShard.svelte.d.ts +1 -1
  71. package/dist/shell-shard/shellShard.svelte.js +9 -4
  72. package/dist/shell-shard/verbs/cat.js +3 -3
  73. package/dist/shell-shard/verbs/cat.test.js +1 -2
  74. package/dist/shell-shard/verbs/ls.js +2 -2
  75. package/dist/shell-shard/verbs/ls.test.js +1 -2
  76. package/dist/shell-shard/verbs/mkdir.js +3 -3
  77. package/dist/shell-shard/verbs/mkdir.test.js +1 -2
  78. package/dist/shell-shard/verbs/mv.js +3 -3
  79. package/dist/shell-shard/verbs/mv.test.js +1 -2
  80. package/dist/shell-shard/verbs/rm.js +3 -3
  81. package/dist/shell-shard/verbs/rm.test.js +1 -2
  82. package/dist/shell-shard/verbs/xfer.js +5 -5
  83. package/dist/shell-shard/verbs/xfer.test.js +2 -2
  84. package/dist/transport/apiFetch.js +21 -3
  85. package/dist/transport/apiFetch.test.js +63 -0
  86. package/dist/verbs/types.d.ts +10 -2
  87. package/dist/version.d.ts +1 -1
  88. package/dist/version.js +1 -1
  89. package/package.json +1 -1
@@ -11,11 +11,11 @@ export const xferVerb = {
11
11
  programmatic: true,
12
12
  async run(ctx, args) {
13
13
  const ts = Date.now();
14
- if (!ctx.docs) {
14
+ if (!ctx.sh3.docs) {
15
15
  ctx.scrollback.push({ kind: 'status', text: 'xfer: document capability not available', level: 'error', ts });
16
16
  return;
17
17
  }
18
- if (!ctx.docs.transferBetweenScopes) {
18
+ if (!ctx.sh3.docs.transferBetweenScopes) {
19
19
  ctx.scrollback.push({ kind: 'status', text: 'xfer: write permission not granted', level: 'error', ts });
20
20
  return;
21
21
  }
@@ -64,13 +64,13 @@ export const xferVerb = {
64
64
  ctx.scrollback.push({ kind: 'status', text: 'xfer: source and destination are the same', level: 'error', ts });
65
65
  return;
66
66
  }
67
- await ctx.docs.transferBetweenScopes(srcTenant, srcParsed.shardId, srcParsed.path, dstTenant, dstParsed.shardId, dstParsed.path, moveOpts);
67
+ await ctx.sh3.docs.transferBetweenScopes(srcTenant, srcParsed.shardId, srcParsed.path, dstTenant, dstParsed.shardId, dstParsed.path, moveOpts);
68
68
  const verb = copy ? 'copied' : 'moved';
69
69
  ctx.scrollback.push({ kind: 'status', text: `xfer: ${verb} ${positional[0]} → ${positional[1]}`, level: 'info', ts });
70
70
  return;
71
71
  }
72
72
  const prefix = srcParsed.path;
73
- const allDocs = await ctx.docs.listDocumentsIn(srcTenant);
73
+ const allDocs = await ctx.sh3.docs.listDocumentsIn(srcTenant);
74
74
  const matching = allDocs.filter((d) => d.shardId === srcParsed.shardId && (!prefix || d.path.startsWith(prefix)));
75
75
  if (matching.length === 0) {
76
76
  ctx.scrollback.push({ kind: 'status', text: `xfer: no documents found under ${positional[0]}`, level: 'info', ts });
@@ -78,7 +78,7 @@ export const xferVerb = {
78
78
  }
79
79
  let count = 0;
80
80
  for (const doc of matching) {
81
- await ctx.docs.transferBetweenScopes(srcTenant, doc.shardId, doc.path, dstTenant, dstParsed.shardId, doc.path, moveOpts);
81
+ await ctx.sh3.docs.transferBetweenScopes(srcTenant, doc.shardId, doc.path, dstTenant, dstParsed.shardId, doc.path, moveOpts);
82
82
  count++;
83
83
  }
84
84
  const verb = copy ? 'copied' : 'moved';
@@ -11,13 +11,13 @@ function makeSh3(scope) {
11
11
  }
12
12
  function makeCtx(docs, sh3) {
13
13
  const pushed = [];
14
+ const composedSh3 = Object.assign(Object.assign({}, (sh3 !== null && sh3 !== void 0 ? sh3 : {})), { docs });
14
15
  const ctx = {
15
- sh3: sh3 !== null && sh3 !== void 0 ? sh3 : {},
16
+ sh3: composedSh3,
16
17
  scrollback: { push: (e) => pushed.push(e) },
17
18
  session: {},
18
19
  cwd: '/',
19
20
  fs: {},
20
- docs,
21
21
  dispatch: async () => { },
22
22
  };
23
23
  return { ctx, pushed };
@@ -14,6 +14,7 @@
14
14
  * defensive pattern as `platform/index.ts`. Vite code-splits it
15
15
  * into a Tauri-only chunk that never loads in web builds.
16
16
  */
17
+ import { getEnvServerUrl } from '../env/serverUrl';
17
18
  import { getAuthToken } from './authToken';
18
19
  let tauriFetch = null;
19
20
  let tauriProbed = false;
@@ -43,8 +44,25 @@ async function getTauriFetch() {
43
44
  }
44
45
  return tauriFetch;
45
46
  }
47
+ // Resolve relative paths against the configured server URL so callers can
48
+ // use bare `/api/...` paths and have them hit the configured sh3-server
49
+ // regardless of the webview's origin. Mirrors ctx.fetch's resolveUrl —
50
+ // absolute URLs pass through, relatives get prefixed when a serverUrl is
51
+ // set. When no serverUrl is configured (e.g. early bootstrap, web builds
52
+ // hosted same-origin), the path is left untouched so `fetch` falls back
53
+ // to `window.location.origin` as before.
54
+ function resolveApiUrl(url) {
55
+ if (url.startsWith('http://') || url.startsWith('https://'))
56
+ return url;
57
+ const base = getEnvServerUrl();
58
+ if (!base)
59
+ return url;
60
+ const sep = url.startsWith('/') ? '' : '/';
61
+ return `${base}${sep}${url}`;
62
+ }
46
63
  export function apiFetch(url, init) {
47
64
  var _a;
65
+ const resolved = resolveApiUrl(url);
48
66
  // Inject Authorization: Bearer <session-token> if a session is active
49
67
  // and the caller didn't already supply one. Cookies don't survive the
50
68
  // cross-origin hop (SameSite=Lax + plugin-http has no cookie store),
@@ -62,11 +80,11 @@ export function apiFetch(url, init) {
62
80
  // call-timing assertions in tests still hold and web builds skip the
63
81
  // dynamic-import probe entirely.
64
82
  if (!inTauriRuntime()) {
65
- return fetch(url, Object.assign({ credentials: 'include' }, finalInit));
83
+ return fetch(resolved, Object.assign({ credentials: 'include' }, finalInit));
66
84
  }
67
85
  return getTauriFetch().then((tf) => {
68
86
  if (tf)
69
- return tf(url, finalInit);
70
- return fetch(url, Object.assign({ credentials: 'include' }, finalInit));
87
+ return tf(resolved, finalInit);
88
+ return fetch(resolved, Object.assign({ credentials: 'include' }, finalInit));
71
89
  });
72
90
  }
@@ -34,4 +34,67 @@ describe('apiFetch', () => {
34
34
  const [, init] = calls[0];
35
35
  expect(init.credentials).toBe('omit');
36
36
  });
37
+ it('resolves relative paths against the configured serverUrl', async () => {
38
+ const calls = [];
39
+ globalThis.fetch = vi.fn(async (input) => {
40
+ calls.push(String(input));
41
+ return new Response('ok');
42
+ });
43
+ const { __setEnvServerUrl } = await import('../env/serverUrl');
44
+ __setEnvServerUrl('https://remote.example.com');
45
+ try {
46
+ const { apiFetch } = await import('./apiFetch');
47
+ await apiFetch('/api/admin/users');
48
+ expect(calls[0]).toBe('https://remote.example.com/api/admin/users');
49
+ }
50
+ finally {
51
+ __setEnvServerUrl('');
52
+ }
53
+ });
54
+ it('prepends a slash to bare relative paths when serverUrl is set', async () => {
55
+ const calls = [];
56
+ globalThis.fetch = vi.fn(async (input) => {
57
+ calls.push(String(input));
58
+ return new Response('ok');
59
+ });
60
+ const { __setEnvServerUrl } = await import('../env/serverUrl');
61
+ __setEnvServerUrl('https://remote.example.com');
62
+ try {
63
+ const { apiFetch } = await import('./apiFetch');
64
+ await apiFetch('api/admin/users');
65
+ expect(calls[0]).toBe('https://remote.example.com/api/admin/users');
66
+ }
67
+ finally {
68
+ __setEnvServerUrl('');
69
+ }
70
+ });
71
+ it('passes absolute URLs through unchanged regardless of serverUrl', async () => {
72
+ const calls = [];
73
+ globalThis.fetch = vi.fn(async (input) => {
74
+ calls.push(String(input));
75
+ return new Response('ok');
76
+ });
77
+ const { __setEnvServerUrl } = await import('../env/serverUrl');
78
+ __setEnvServerUrl('https://remote.example.com');
79
+ try {
80
+ const { apiFetch } = await import('./apiFetch');
81
+ await apiFetch('https://other.example.com/api/bar');
82
+ expect(calls[0]).toBe('https://other.example.com/api/bar');
83
+ }
84
+ finally {
85
+ __setEnvServerUrl('');
86
+ }
87
+ });
88
+ it('leaves relative paths alone when no serverUrl is configured', async () => {
89
+ const calls = [];
90
+ globalThis.fetch = vi.fn(async (input) => {
91
+ calls.push(String(input));
92
+ return new Response('ok');
93
+ });
94
+ const { __setEnvServerUrl } = await import('../env/serverUrl');
95
+ __setEnvServerUrl('');
96
+ const { apiFetch } = await import('./apiFetch');
97
+ await apiFetch('/api/admin/users');
98
+ expect(calls[0]).toBe('/api/admin/users');
99
+ });
37
100
  });
@@ -174,6 +174,16 @@ export interface Sh3Api {
174
174
  id: string;
175
175
  name: string;
176
176
  }>;
177
+ /**
178
+ * Tenant-wide document observation surface for the caller. Present iff
179
+ * the caller's manifest declares `documents:browse`. Read methods
180
+ * (`readFrom`, …) require `documents:read`; write methods (`writeTo`,
181
+ * `transferBetweenScopes`, …) require `documents:write`. Verbs that need
182
+ * documents — `xfer`, `cat`, `ls`, `mv`, `mkdir`, `rm` — read it from
183
+ * here so programmatic dispatch (runVerb / pipelines) inherits the
184
+ * caller's gating.
185
+ */
186
+ docs?: BrowseCapability;
177
187
  }
178
188
  export type { DispatchToTerminalResult } from '../shell-shard/dispatch-to-terminal';
179
189
  export interface VerbContext {
@@ -182,8 +192,6 @@ export interface VerbContext {
182
192
  session: SessionClient;
183
193
  cwd: string;
184
194
  fs: TenantFsClient;
185
- /** Document zone browse capability. Present when shell-shard has documents:browse permission. */
186
- docs?: BrowseCapability;
187
195
  /** Invoke another registered verb programmatically (used by rich-entry clicks). */
188
196
  dispatch(line: string): Promise<void>;
189
197
  /**
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Auto-generated from package.json — do not edit manually. */
2
- export declare const VERSION = "0.22.5";
2
+ export declare const VERSION = "0.24.0";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Auto-generated from package.json — do not edit manually. */
2
- export const VERSION = '0.22.5';
2
+ export const VERSION = '0.24.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh3-core",
3
- "version": "0.22.5",
3
+ "version": "0.24.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"