sh3-core 0.20.2 → 0.21.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.
- package/dist/BrandSlot.svelte +2 -2
- package/dist/actions/ctx-actions.svelte.test.js +2 -2
- package/dist/api.d.ts +2 -2
- package/dist/api.js +1 -1
- package/dist/app/store/StoreView.svelte +26 -35
- package/dist/app/store/storeShard.svelte.js +35 -49
- package/dist/app/store/verbs.js +24 -55
- package/dist/artifact.d.ts +2 -0
- package/dist/boot/satellitePayload.d.ts +2 -0
- package/dist/boot/satellitePayload.test.js +19 -0
- package/dist/build.d.ts +7 -1
- package/dist/build.js +34 -9
- package/dist/build.test.js +27 -1
- package/dist/createShell.js +34 -9
- package/dist/documents/browse.d.ts +20 -0
- package/dist/documents/browse.js +35 -0
- package/dist/documents/browse.test.js +125 -0
- package/dist/documents/config.d.ts +0 -4
- package/dist/documents/config.js +0 -8
- package/dist/documents/http-backend.d.ts +5 -0
- package/dist/documents/http-backend.js +25 -0
- package/dist/documents/http-backend.test.js +66 -0
- package/dist/documents/index.d.ts +1 -1
- package/dist/documents/index.js +1 -1
- package/dist/documents/types.d.ts +11 -0
- package/dist/env/client.d.ts +6 -10
- package/dist/env/client.js +11 -21
- package/dist/env/index.d.ts +2 -1
- package/dist/env/index.js +1 -1
- package/dist/host-entry.d.ts +1 -1
- package/dist/host-entry.js +1 -1
- package/dist/host.d.ts +1 -1
- package/dist/host.js +1 -1
- package/dist/layout/slotHostPool.svelte.js +2 -2
- package/dist/overlays/FloatFrame.svelte +1 -0
- package/dist/projects/session-state.svelte.d.ts +3 -0
- package/dist/projects/session-state.svelte.js +25 -0
- package/dist/projects/session-state.test.js +43 -2
- package/dist/projects-shard/ProjectsSection.svelte +14 -18
- package/dist/registry/archive.d.ts +12 -0
- package/dist/registry/archive.js +80 -0
- package/dist/registry/archive.test.d.ts +1 -0
- package/dist/registry/archive.test.js +84 -0
- package/dist/registry/client.d.ts +9 -29
- package/dist/registry/client.js +14 -60
- package/dist/registry/client.test.js +31 -21
- package/dist/registry/index.d.ts +2 -2
- package/dist/registry/index.js +1 -1
- package/dist/registry/installer.d.ts +4 -4
- package/dist/registry/installer.js +74 -45
- package/dist/registry/schema.js +4 -27
- package/dist/registry/schema.test.d.ts +1 -0
- package/dist/registry/schema.test.js +41 -0
- package/dist/registry/types.d.ts +16 -41
- package/dist/runtime/runVerb-shell.test.js +2 -2
- package/dist/runtime/runVerb.test.js +2 -2
- package/dist/sh3core-shard/appActions.js +5 -2
- package/dist/shards/activate-browse.test.js +2 -2
- package/dist/shards/activate-contributions.test.js +2 -2
- package/dist/shards/activate-error-isolation.test.js +3 -3
- package/dist/shards/activate-on-key-revoked.test.js +2 -2
- package/dist/shards/activate-runtime.test.js +2 -2
- package/dist/shards/activate.svelte.js +4 -4
- package/dist/shards/ctx-fetch.test.js +4 -4
- package/dist/shell-shard/verbs/xfer.js +13 -27
- package/dist/shell-shard/verbs/xfer.test.js +36 -25
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -2
|
@@ -3,7 +3,8 @@ export const xferVerb = {
|
|
|
3
3
|
name: 'xfer',
|
|
4
4
|
summary: [
|
|
5
5
|
'Transfer docs across scopes. Usage: xfer [-R] [-C] <src> <dst>',
|
|
6
|
-
' Scopes: @me | @project-<slug> (e.g. @project-acme:notes/draft.md)',
|
|
6
|
+
' Scopes: @me | @project-<slug> (e.g. @me:notes/draft.md, @project-acme:notes/draft.md)',
|
|
7
|
+
' Either side may be @me or @project-<slug>; bare paths resolve to the active scope.',
|
|
7
8
|
' -R recursive (src is a folder prefix)',
|
|
8
9
|
' -C copy only, do not delete source',
|
|
9
10
|
].join('\n'),
|
|
@@ -14,12 +15,10 @@ export const xferVerb = {
|
|
|
14
15
|
ctx.scrollback.push({ kind: 'status', text: 'xfer: document capability not available', level: 'error', ts });
|
|
15
16
|
return;
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
ctx.scrollback.push({ kind: 'status', text: 'xfer: only available when a project scope is active', level: 'error', ts });
|
|
18
|
+
if (!ctx.docs.transferBetweenScopes) {
|
|
19
|
+
ctx.scrollback.push({ kind: 'status', text: 'xfer: write permission not granted', level: 'error', ts });
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
|
-
// Parse flags
|
|
23
22
|
let recursive = false;
|
|
24
23
|
let copy = false;
|
|
25
24
|
const positional = [];
|
|
@@ -38,16 +37,13 @@ export const xferVerb = {
|
|
|
38
37
|
ctx.scrollback.push({ kind: 'status', text: 'usage: xfer [-R] [-C] <src> <dst>', level: 'error', ts });
|
|
39
38
|
return;
|
|
40
39
|
}
|
|
41
|
-
if (!ctx.docs.transferToScope) {
|
|
42
|
-
ctx.scrollback.push({ kind: 'status', text: 'xfer: write permission not granted', level: 'error', ts });
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
40
|
const srcParsed = parseScopePath(positional[0]);
|
|
46
41
|
const dstParsed = parseScopePath(positional[1]);
|
|
47
42
|
if (!srcParsed || !dstParsed) {
|
|
48
43
|
ctx.scrollback.push({ kind: 'status', text: 'xfer: invalid path', level: 'error', ts });
|
|
49
44
|
return;
|
|
50
45
|
}
|
|
46
|
+
const scope = ctx.sh3.getActiveScope();
|
|
51
47
|
let srcTenant;
|
|
52
48
|
let dstTenant;
|
|
53
49
|
try {
|
|
@@ -58,33 +54,23 @@ export const xferVerb = {
|
|
|
58
54
|
ctx.scrollback.push({ kind: 'status', text: `xfer: ${e.message}`, level: 'error', ts });
|
|
59
55
|
return;
|
|
60
56
|
}
|
|
61
|
-
|
|
62
|
-
if (srcTenant !== scope.id) {
|
|
63
|
-
ctx.scrollback.push({
|
|
64
|
-
kind: 'status',
|
|
65
|
-
text: 'xfer: source must be the active project scope in v1 — switch to the source scope first',
|
|
66
|
-
level: 'error',
|
|
67
|
-
ts,
|
|
68
|
-
});
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
const opts = { delete: !copy, targetShardId: dstParsed.shardId };
|
|
57
|
+
const moveOpts = { delete: !copy };
|
|
72
58
|
if (!recursive) {
|
|
73
59
|
if (!srcParsed.path) {
|
|
74
60
|
ctx.scrollback.push({ kind: 'status', text: 'xfer: path required (use -R for folder recursion)', level: 'error', ts });
|
|
75
61
|
return;
|
|
76
62
|
}
|
|
77
|
-
|
|
63
|
+
if (srcTenant === dstTenant && srcParsed.shardId === dstParsed.shardId && srcParsed.path === dstParsed.path) {
|
|
64
|
+
ctx.scrollback.push({ kind: 'status', text: 'xfer: source and destination are the same', level: 'error', ts });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
await ctx.docs.transferBetweenScopes(srcTenant, srcParsed.shardId, srcParsed.path, dstTenant, dstParsed.shardId, dstParsed.path, moveOpts);
|
|
78
68
|
const verb = copy ? 'copied' : 'moved';
|
|
79
69
|
ctx.scrollback.push({ kind: 'status', text: `xfer: ${verb} ${positional[0]} → ${positional[1]}`, level: 'info', ts });
|
|
80
70
|
return;
|
|
81
71
|
}
|
|
82
|
-
// Recursive: list all docs in srcTenant matching the prefix
|
|
83
|
-
// transferToScope uses getTenantId() (active scope) — to read from srcTenant
|
|
84
|
-
// we rely on the src scope being the active tenant or the capability seeing it.
|
|
85
|
-
// For v1 we use listDocuments (active tenant) and filter by shard + prefix.
|
|
86
72
|
const prefix = srcParsed.path;
|
|
87
|
-
const allDocs = await ctx.docs.
|
|
73
|
+
const allDocs = await ctx.docs.listDocumentsIn(srcTenant);
|
|
88
74
|
const matching = allDocs.filter((d) => d.shardId === srcParsed.shardId && (!prefix || d.path.startsWith(prefix)));
|
|
89
75
|
if (matching.length === 0) {
|
|
90
76
|
ctx.scrollback.push({ kind: 'status', text: `xfer: no documents found under ${positional[0]}`, level: 'info', ts });
|
|
@@ -92,7 +78,7 @@ export const xferVerb = {
|
|
|
92
78
|
}
|
|
93
79
|
let count = 0;
|
|
94
80
|
for (const doc of matching) {
|
|
95
|
-
await ctx.docs.
|
|
81
|
+
await ctx.docs.transferBetweenScopes(srcTenant, doc.shardId, doc.path, dstTenant, dstParsed.shardId, doc.path, moveOpts);
|
|
96
82
|
count++;
|
|
97
83
|
}
|
|
98
84
|
const verb = copy ? 'copied' : 'moved';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
import { xferVerb } from './xfer';
|
|
3
3
|
function makeDocs(overrides = {}) {
|
|
4
|
-
return Object.assign({ listDocuments: vi.fn(async () => []), listShards: vi.fn(async () => []), watchDocuments: vi.fn(() => () => { }), transferToScope: vi.fn(async () => { }) }, overrides);
|
|
4
|
+
return Object.assign({ listDocuments: vi.fn(async () => []), listShards: vi.fn(async () => []), watchDocuments: vi.fn(() => () => { }), transferToScope: vi.fn(async () => { }), listDocumentsIn: vi.fn(async () => []), transferBetweenScopes: vi.fn(async () => { }) }, overrides);
|
|
5
5
|
}
|
|
6
6
|
function makeSh3(scope) {
|
|
7
7
|
return {
|
|
@@ -32,13 +32,15 @@ describe('xfer verb', () => {
|
|
|
32
32
|
const err = pushed.find((e) => e.kind === 'status' && e.level === 'error');
|
|
33
33
|
expect(err).toBeDefined();
|
|
34
34
|
});
|
|
35
|
-
it('
|
|
35
|
+
it('works from personal (non-project) scope', async () => {
|
|
36
|
+
const transferBetweenScopes = vi.fn(async () => { });
|
|
37
|
+
const docs = makeDocs({ transferBetweenScopes });
|
|
36
38
|
const sh3 = makeSh3(personalScope);
|
|
37
|
-
const { ctx, pushed } = makeCtx(
|
|
38
|
-
await xferVerb.run(ctx, ['notes/draft.md', '@
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
expect(
|
|
39
|
+
const { ctx, pushed } = makeCtx(docs, sh3);
|
|
40
|
+
await xferVerb.run(ctx, ['@me:notes/draft.md', '@project-proj-abc:notes/draft.md']);
|
|
41
|
+
expect(transferBetweenScopes).toHaveBeenCalledWith('user-me', 'notes', 'draft.md', 'proj-abc', 'notes', 'draft.md', expect.objectContaining({ delete: true }));
|
|
42
|
+
const ok = pushed.find((e) => e.kind === 'status' && e.level === 'info');
|
|
43
|
+
expect(ok).toBeDefined();
|
|
42
44
|
});
|
|
43
45
|
it('emits usage error when fewer than two args', async () => {
|
|
44
46
|
const sh3 = makeSh3(projectScope);
|
|
@@ -47,50 +49,59 @@ describe('xfer verb', () => {
|
|
|
47
49
|
const err = pushed.find((e) => e.kind === 'status' && e.level === 'error');
|
|
48
50
|
expect(err.text).toMatch(/usage/i);
|
|
49
51
|
});
|
|
50
|
-
it('moves
|
|
51
|
-
const
|
|
52
|
-
const docs = makeDocs({
|
|
52
|
+
it('moves a doc from project to personal scope', async () => {
|
|
53
|
+
const transferBetweenScopes = vi.fn(async () => { });
|
|
54
|
+
const docs = makeDocs({ transferBetweenScopes });
|
|
53
55
|
const sh3 = makeSh3(projectScope);
|
|
54
56
|
const { ctx, pushed } = makeCtx(docs, sh3);
|
|
55
57
|
await xferVerb.run(ctx, ['@project-proj-abc:notes/draft.md', '@me:notes/draft.md']);
|
|
56
|
-
expect(
|
|
58
|
+
expect(transferBetweenScopes).toHaveBeenCalledWith('proj-abc', 'notes', 'draft.md', 'user-me', 'notes', 'draft.md', expect.objectContaining({ delete: true }));
|
|
57
59
|
const ok = pushed.find((e) => e.kind === 'status' && e.level === 'info');
|
|
58
60
|
expect(ok).toBeDefined();
|
|
59
61
|
});
|
|
60
62
|
it('-C flag copies without deleting source', async () => {
|
|
61
|
-
const
|
|
62
|
-
const docs = makeDocs({
|
|
63
|
+
const transferBetweenScopes = vi.fn(async () => { });
|
|
64
|
+
const docs = makeDocs({ transferBetweenScopes });
|
|
63
65
|
const sh3 = makeSh3(projectScope);
|
|
64
66
|
const { ctx } = makeCtx(docs, sh3);
|
|
65
67
|
await xferVerb.run(ctx, ['-C', '@project-proj-abc:notes/draft.md', '@me:notes/draft.md']);
|
|
66
|
-
expect(
|
|
68
|
+
expect(transferBetweenScopes).toHaveBeenCalledWith('proj-abc', 'notes', 'draft.md', 'user-me', 'notes', 'draft.md', expect.objectContaining({ delete: false }));
|
|
67
69
|
});
|
|
68
|
-
it('
|
|
69
|
-
const
|
|
70
|
-
const docs = makeDocs({
|
|
70
|
+
it('allows @me as source when project scope is active', async () => {
|
|
71
|
+
const transferBetweenScopes = vi.fn(async () => { });
|
|
72
|
+
const docs = makeDocs({ transferBetweenScopes });
|
|
71
73
|
const sh3 = makeSh3(projectScope);
|
|
72
74
|
const { ctx, pushed } = makeCtx(docs, sh3);
|
|
73
|
-
// @me src while project is active → src tenant differs from active
|
|
74
75
|
await xferVerb.run(ctx, ['@me:notes/draft.md', '@project-proj-abc:notes/draft.md']);
|
|
75
|
-
expect(
|
|
76
|
+
expect(transferBetweenScopes).toHaveBeenCalledWith('user-me', 'notes', 'draft.md', 'proj-abc', 'notes', 'draft.md', expect.objectContaining({ delete: true }));
|
|
77
|
+
const ok = pushed.find((e) => e.kind === 'status' && e.level === 'info');
|
|
78
|
+
expect(ok).toBeDefined();
|
|
79
|
+
});
|
|
80
|
+
it('emits error when source and destination are identical', async () => {
|
|
81
|
+
const transferBetweenScopes = vi.fn(async () => { });
|
|
82
|
+
const docs = makeDocs({ transferBetweenScopes });
|
|
83
|
+
const sh3 = makeSh3(projectScope);
|
|
84
|
+
const { ctx, pushed } = makeCtx(docs, sh3);
|
|
85
|
+
await xferVerb.run(ctx, ['@project-proj-abc:notes/draft.md', '@project-proj-abc:notes/draft.md']);
|
|
86
|
+
expect(transferBetweenScopes).not.toHaveBeenCalled();
|
|
76
87
|
const err = pushed.find((e) => e.kind === 'status' && e.level === 'error');
|
|
77
|
-
expect(err).
|
|
88
|
+
expect(err.text).toMatch(/same/i);
|
|
78
89
|
});
|
|
79
90
|
it('-R flag recurses over all docs matching src prefix', async () => {
|
|
80
|
-
const
|
|
91
|
+
const transferBetweenScopes = vi.fn(async () => { });
|
|
81
92
|
const allDocs = [
|
|
82
93
|
{ shardId: 'notes', path: 'ideas/a.md', size: 1, lastModified: 0 },
|
|
83
94
|
{ shardId: 'notes', path: 'ideas/b.md', size: 1, lastModified: 0 },
|
|
84
95
|
{ shardId: 'notes', path: 'other.md', size: 1, lastModified: 0 },
|
|
85
96
|
];
|
|
86
97
|
const docs = makeDocs({
|
|
87
|
-
|
|
88
|
-
|
|
98
|
+
transferBetweenScopes,
|
|
99
|
+
listDocumentsIn: vi.fn(async () => allDocs),
|
|
89
100
|
});
|
|
90
101
|
const sh3 = makeSh3(projectScope);
|
|
91
102
|
const { ctx } = makeCtx(docs, sh3);
|
|
92
103
|
await xferVerb.run(ctx, ['-R', '@project-proj-abc:notes/ideas', '@me:notes/ideas']);
|
|
93
|
-
|
|
94
|
-
expect(
|
|
104
|
+
expect(transferBetweenScopes).toHaveBeenCalledTimes(2);
|
|
105
|
+
expect(transferBetweenScopes).toHaveBeenCalledWith('proj-abc', 'notes', 'ideas/a.md', 'user-me', 'notes', 'ideas/a.md', expect.objectContaining({ delete: true }));
|
|
95
106
|
});
|
|
96
107
|
});
|
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.
|
|
2
|
+
export declare const VERSION = "0.21.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.
|
|
2
|
+
export const VERSION = '0.21.0';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sh3-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
"test:watch": "vitest"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"esm-env": "^1.1.0"
|
|
42
|
+
"esm-env": "^1.1.0",
|
|
43
|
+
"fflate": "^0.8.3"
|
|
43
44
|
},
|
|
44
45
|
"peerDependencies": {
|
|
45
46
|
"svelte": "^5.0.0",
|