sh3-core 0.8.2 → 0.9.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/api.d.ts +3 -6
- package/dist/api.js +1 -3
- package/dist/apps/types.d.ts +3 -5
- package/dist/documents/backends.d.ts +2 -0
- package/dist/documents/backends.js +6 -0
- package/dist/documents/handle.js +13 -5
- package/dist/documents/handle.test.js +55 -0
- package/dist/documents/http-backend.d.ts +11 -4
- package/dist/documents/http-backend.js +37 -11
- package/dist/documents/index.d.ts +2 -1
- package/dist/documents/index.js +1 -1
- package/dist/documents/sync-types.d.ts +45 -0
- package/dist/documents/sync-types.js +11 -0
- package/dist/documents/types.d.ts +40 -2
- package/dist/documents/types.js +3 -2
- package/dist/keys/ConsentDialog.svelte +4 -4
- package/dist/keys/consent.test.js +4 -3
- package/dist/keys/types.d.ts +4 -2
- package/dist/server-shard/types.d.ts +55 -8
- package/dist/shards/activate.svelte.js +4 -29
- package/dist/shards/types.d.ts +0 -15
- package/dist/shell/views/KeysAndPeers.svelte +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -10
- package/dist/documents/journal-hook.d.ts +0 -6
- package/dist/documents/journal-hook.js +0 -16
- package/dist/documents/sync/activate-integration.test.d.ts +0 -1
- package/dist/documents/sync/activate-integration.test.js +0 -37
- package/dist/documents/sync/components/DocumentSyncExplorer.svelte +0 -99
- package/dist/documents/sync/components/DocumentSyncExplorer.svelte.d.ts +0 -15
- package/dist/documents/sync/components/SyncGrantPicker.svelte +0 -70
- package/dist/documents/sync/components/SyncGrantPicker.svelte.d.ts +0 -12
- package/dist/documents/sync/conflicts.d.ts +0 -30
- package/dist/documents/sync/conflicts.js +0 -77
- package/dist/documents/sync/conflicts.test.d.ts +0 -1
- package/dist/documents/sync/conflicts.test.js +0 -71
- package/dist/documents/sync/engine.d.ts +0 -19
- package/dist/documents/sync/engine.js +0 -188
- package/dist/documents/sync/engine.test.d.ts +0 -1
- package/dist/documents/sync/engine.test.js +0 -169
- package/dist/documents/sync/handle.d.ts +0 -11
- package/dist/documents/sync/handle.js +0 -79
- package/dist/documents/sync/handle.test.js +0 -56
- package/dist/documents/sync/hash.d.ts +0 -1
- package/dist/documents/sync/hash.js +0 -13
- package/dist/documents/sync/hash.test.d.ts +0 -1
- package/dist/documents/sync/hash.test.js +0 -20
- package/dist/documents/sync/index.d.ts +0 -5
- package/dist/documents/sync/index.js +0 -10
- package/dist/documents/sync/journal.d.ts +0 -30
- package/dist/documents/sync/journal.js +0 -179
- package/dist/documents/sync/journal.test.d.ts +0 -1
- package/dist/documents/sync/journal.test.js +0 -87
- package/dist/documents/sync/observer.d.ts +0 -3
- package/dist/documents/sync/observer.js +0 -45
- package/dist/documents/sync/registry.d.ts +0 -13
- package/dist/documents/sync/registry.js +0 -73
- package/dist/documents/sync/registry.test.d.ts +0 -1
- package/dist/documents/sync/registry.test.js +0 -53
- package/dist/documents/sync/serialization.d.ts +0 -5
- package/dist/documents/sync/serialization.js +0 -24
- package/dist/documents/sync/serialization.test.d.ts +0 -1
- package/dist/documents/sync/serialization.test.js +0 -26
- package/dist/documents/sync/singleton.d.ts +0 -11
- package/dist/documents/sync/singleton.js +0 -26
- package/dist/documents/sync/tombstones.d.ts +0 -19
- package/dist/documents/sync/tombstones.js +0 -58
- package/dist/documents/sync/tombstones.test.d.ts +0 -1
- package/dist/documents/sync/tombstones.test.js +0 -37
- package/dist/documents/sync/types.d.ts +0 -116
- package/dist/documents/sync/types.js +0 -27
- package/dist/documents/sync/write-hook.test.d.ts +0 -1
- package/dist/documents/sync/write-hook.test.js +0 -36
- package/dist/server-sync.d.ts +0 -6
- package/dist/server-sync.js +0 -634
- package/dist/server-sync.js.map +0 -7
- package/dist/shards/activate-sync-registry.test.d.ts +0 -1
- package/dist/shards/activate-sync-registry.test.js +0 -42
- package/dist/testing.d.ts +0 -3
- package/dist/testing.js +0 -77
- package/dist/testing.js.map +0 -7
- /package/dist/documents/{sync/handle.test.d.ts → handle.test.d.ts} +0 -0
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { MemoryDocumentBackend } from '../backends';
|
|
3
|
-
import { TombstoneStore } from './tombstones';
|
|
4
|
-
describe('TombstoneStore', () => {
|
|
5
|
-
let backend;
|
|
6
|
-
let store;
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
backend = new MemoryDocumentBackend();
|
|
9
|
-
store = new TombstoneStore(backend, 'tenant-a');
|
|
10
|
-
});
|
|
11
|
-
it('records and retrieves a tombstone', async () => {
|
|
12
|
-
await store.record('shard-x', 'dir/file.md', 'hash123', 1000);
|
|
13
|
-
const t = await store.get('shard-x', 'dir/file.md');
|
|
14
|
-
expect(t).toEqual({ deletedAt: 1000, lastHash: 'hash123' });
|
|
15
|
-
});
|
|
16
|
-
it('returns null for non-tombstoned paths', async () => {
|
|
17
|
-
expect(await store.get('shard-x', 'absent.md')).toBeNull();
|
|
18
|
-
});
|
|
19
|
-
it('clears a tombstone (on upsert of same path)', async () => {
|
|
20
|
-
await store.record('shard-x', 'a.md', 'h', 1);
|
|
21
|
-
await store.clear('shard-x', 'a.md');
|
|
22
|
-
expect(await store.get('shard-x', 'a.md')).toBeNull();
|
|
23
|
-
});
|
|
24
|
-
it('lists tombstones within a shard', async () => {
|
|
25
|
-
await store.record('shard-x', 'a.md', 'h1', 1);
|
|
26
|
-
await store.record('shard-x', 'b.md', 'h2', 2);
|
|
27
|
-
await store.record('shard-y', 'c.md', 'h3', 3);
|
|
28
|
-
const list = await store.listByShard('shard-x');
|
|
29
|
-
expect(list.map((t) => t.path).sort()).toEqual(['a.md', 'b.md']);
|
|
30
|
-
});
|
|
31
|
-
it('lists all tombstones across shards', async () => {
|
|
32
|
-
await store.record('shard-x', 'a.md', 'h1', 1);
|
|
33
|
-
await store.record('shard-y', 'c.md', 'h3', 3);
|
|
34
|
-
const all = await store.listAll();
|
|
35
|
-
expect(all.length).toBe(2);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/** Permission string required in a shard manifest to obtain ctx.sync(). */
|
|
2
|
-
export declare const PERMISSION_DOCUMENTS_SYNC = "documents:sync";
|
|
3
|
-
/** Reserved shardId used to persist sync metadata (journal, tombstones, cursors, grants). */
|
|
4
|
-
export declare const SYNC_RESERVED_SHARD_ID = "__sync__";
|
|
5
|
-
export type SyncScope = {
|
|
6
|
-
kind: 'shard';
|
|
7
|
-
shardId: string;
|
|
8
|
-
} | {
|
|
9
|
-
kind: 'tenant';
|
|
10
|
-
} | {
|
|
11
|
-
kind: 'path';
|
|
12
|
-
shardId: string;
|
|
13
|
-
prefix: string;
|
|
14
|
-
};
|
|
15
|
-
export interface ManifestEntry {
|
|
16
|
-
path: string;
|
|
17
|
-
shardId: string;
|
|
18
|
-
hash: string;
|
|
19
|
-
size: number;
|
|
20
|
-
lastModified: number;
|
|
21
|
-
tombstone?: {
|
|
22
|
-
deletedAt: number;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
export interface ApplyEntry {
|
|
26
|
-
path: string;
|
|
27
|
-
shardId: string;
|
|
28
|
-
op: 'upsert' | 'delete';
|
|
29
|
-
content?: string | ArrayBuffer;
|
|
30
|
-
remoteHash: string;
|
|
31
|
-
remoteMtime: number;
|
|
32
|
-
}
|
|
33
|
-
export interface ApplyOpts {
|
|
34
|
-
onConflict?: ConflictPolicy;
|
|
35
|
-
expectedLocalHash?: string;
|
|
36
|
-
}
|
|
37
|
-
export type ApplyOutcome = {
|
|
38
|
-
status: 'applied';
|
|
39
|
-
newHash: string;
|
|
40
|
-
} | {
|
|
41
|
-
status: 'skipped-identical';
|
|
42
|
-
} | {
|
|
43
|
-
status: 'conflict';
|
|
44
|
-
resolution: ConflictResolution;
|
|
45
|
-
};
|
|
46
|
-
export interface ApplyBatchResult {
|
|
47
|
-
applied: Array<{
|
|
48
|
-
path: string;
|
|
49
|
-
shardId: string;
|
|
50
|
-
newHash: string;
|
|
51
|
-
}>;
|
|
52
|
-
skipped: Array<{
|
|
53
|
-
path: string;
|
|
54
|
-
shardId: string;
|
|
55
|
-
reason: 'identical';
|
|
56
|
-
}>;
|
|
57
|
-
conflicts: ConflictResolution[];
|
|
58
|
-
}
|
|
59
|
-
export interface ConflictResolution {
|
|
60
|
-
path: string;
|
|
61
|
-
shardId: string;
|
|
62
|
-
localHash: string;
|
|
63
|
-
remoteHash: string;
|
|
64
|
-
conflictArtifactPath: string;
|
|
65
|
-
base?: {
|
|
66
|
-
hash: string;
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
export interface ConflictContext {
|
|
70
|
-
path: string;
|
|
71
|
-
shardId: string;
|
|
72
|
-
localHash: string;
|
|
73
|
-
remoteHash: string;
|
|
74
|
-
baseHash?: string;
|
|
75
|
-
}
|
|
76
|
-
export type ConflictPolicy = 'default' | 'remote-wins' | 'local-wins' | 'keep-both' | ((ctx: ConflictContext) => Promise<'remote-wins' | 'local-wins' | 'keep-both'>);
|
|
77
|
-
export interface JournalEntry {
|
|
78
|
-
seq: number;
|
|
79
|
-
ts: number;
|
|
80
|
-
shardId: string;
|
|
81
|
-
path: string;
|
|
82
|
-
op: 'upsert' | 'delete';
|
|
83
|
-
hash: string | null;
|
|
84
|
-
}
|
|
85
|
-
export interface ChangePage {
|
|
86
|
-
entries: JournalEntry[];
|
|
87
|
-
nextCursor: string;
|
|
88
|
-
hasMore: boolean;
|
|
89
|
-
truncated?: boolean;
|
|
90
|
-
}
|
|
91
|
-
export interface GrantRecord {
|
|
92
|
-
connectorId: string;
|
|
93
|
-
scope: SyncScope;
|
|
94
|
-
grantedAt: number;
|
|
95
|
-
}
|
|
96
|
-
export interface SyncHandle {
|
|
97
|
-
readonly connectorId: string;
|
|
98
|
-
grantedScopes(): Promise<SyncScope[]>;
|
|
99
|
-
getManifest(scope: SyncScope): Promise<ManifestEntry[]>;
|
|
100
|
-
changesSince(scope: SyncScope, cursor?: string): Promise<ChangePage>;
|
|
101
|
-
ack(scope: SyncScope, cursor: string): Promise<void>;
|
|
102
|
-
apply(scope: SyncScope, entry: ApplyEntry, opts?: ApplyOpts): Promise<ApplyOutcome>;
|
|
103
|
-
applyBatch(scope: SyncScope, manifest: ApplyEntry[], opts?: ApplyOpts): Promise<ApplyBatchResult>;
|
|
104
|
-
forget(scope: SyncScope, path: string): Promise<void>;
|
|
105
|
-
}
|
|
106
|
-
export declare class ScopeNotGrantedError extends Error {
|
|
107
|
-
readonly scope: SyncScope;
|
|
108
|
-
constructor(scope: SyncScope);
|
|
109
|
-
}
|
|
110
|
-
export declare class ScopeRevokedError extends Error {
|
|
111
|
-
readonly scope: SyncScope;
|
|
112
|
-
constructor(scope: SyncScope);
|
|
113
|
-
}
|
|
114
|
-
export declare class TenantMismatchError extends Error {
|
|
115
|
-
constructor();
|
|
116
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Document Sync API types. See docs/superpowers/specs/2026-04-14-document-sync-api-design.md.
|
|
3
|
-
*/
|
|
4
|
-
/** Permission string required in a shard manifest to obtain ctx.sync(). */
|
|
5
|
-
export const PERMISSION_DOCUMENTS_SYNC = 'documents:sync';
|
|
6
|
-
/** Reserved shardId used to persist sync metadata (journal, tombstones, cursors, grants). */
|
|
7
|
-
export const SYNC_RESERVED_SHARD_ID = '__sync__';
|
|
8
|
-
export class ScopeNotGrantedError extends Error {
|
|
9
|
-
constructor(scope) {
|
|
10
|
-
super(`Scope not granted: ${JSON.stringify(scope)}`);
|
|
11
|
-
this.scope = scope;
|
|
12
|
-
this.name = 'ScopeNotGrantedError';
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
export class ScopeRevokedError extends Error {
|
|
16
|
-
constructor(scope) {
|
|
17
|
-
super(`Scope revoked during operation: ${JSON.stringify(scope)}`);
|
|
18
|
-
this.scope = scope;
|
|
19
|
-
this.name = 'ScopeRevokedError';
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
export class TenantMismatchError extends Error {
|
|
23
|
-
constructor() {
|
|
24
|
-
super('Sync handle tenantId does not match current session');
|
|
25
|
-
this.name = 'TenantMismatchError';
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// packages/sh3-core/src/documents/sync/write-hook.test.ts
|
|
2
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
3
|
-
import { MemoryDocumentBackend } from '../backends';
|
|
4
|
-
import { __setDocumentBackend, __setTenantId } from '../config';
|
|
5
|
-
import { createDocumentHandle } from '../handle';
|
|
6
|
-
import { SyncEngine } from './engine';
|
|
7
|
-
import { setJournalAppender, clearJournalAppender } from '../journal-hook';
|
|
8
|
-
describe('regular document writes feed the sync journal', () => {
|
|
9
|
-
let backend;
|
|
10
|
-
let engine;
|
|
11
|
-
beforeEach(async () => {
|
|
12
|
-
backend = new MemoryDocumentBackend();
|
|
13
|
-
__setDocumentBackend(backend);
|
|
14
|
-
__setTenantId('tenant-a');
|
|
15
|
-
engine = new SyncEngine(backend, 'tenant-a');
|
|
16
|
-
await engine.init();
|
|
17
|
-
setJournalAppender(async (e) => { await engine.journal.append(e); });
|
|
18
|
-
});
|
|
19
|
-
it('appends upsert to journal when shard writes via ctx.documents()', async () => {
|
|
20
|
-
const h = createDocumentHandle('tenant-a', 'shard-x', backend, { format: 'text' });
|
|
21
|
-
await h.write('a.md', 'hello');
|
|
22
|
-
const page = await engine.journal.changesSince({ kind: 'tenant' });
|
|
23
|
-
expect(page.entries.map((e) => `${e.shardId}:${e.path}:${e.op}`)).toEqual([
|
|
24
|
-
'shard-x:a.md:upsert',
|
|
25
|
-
]);
|
|
26
|
-
clearJournalAppender();
|
|
27
|
-
});
|
|
28
|
-
it('appends delete to journal', async () => {
|
|
29
|
-
const h = createDocumentHandle('tenant-a', 'shard-x', backend, { format: 'text' });
|
|
30
|
-
await h.write('a.md', 'hello');
|
|
31
|
-
await h.delete('a.md');
|
|
32
|
-
const page = await engine.journal.changesSince({ kind: 'tenant' });
|
|
33
|
-
expect(page.entries.map((e) => e.op)).toEqual(['upsert', 'delete']);
|
|
34
|
-
clearJournalAppender();
|
|
35
|
-
});
|
|
36
|
-
});
|
package/dist/server-sync.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { getSyncBundle } from './documents/sync/singleton';
|
|
2
|
-
export { createSyncHandle } from './documents/sync/handle';
|
|
3
|
-
export { createSyncRegistry } from './documents/sync/registry';
|
|
4
|
-
export type { SyncHandle } from './documents/sync/types';
|
|
5
|
-
export type { SyncRegistry } from './documents/sync/registry';
|
|
6
|
-
export type { DocumentBackend, DocumentMeta } from './documents/types';
|