amalgm 0.1.238 → 0.1.240
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/lib/shared-realtime-tunnel.js +22 -14
- package/package.json +1 -1
- package/runtime/scripts/amalgm-mcp/browser/cookie-jar.js +68 -20
- package/runtime/scripts/amalgm-mcp/project-context/store.js +87 -19
- package/runtime/scripts/amalgm-mcp/state/attachments.js +40 -12
- package/runtime/scripts/amalgm-mcp/state/db.js +216 -17
- package/runtime/scripts/amalgm-mcp/state/doc-disk.js +550 -0
- package/runtime/scripts/amalgm-mcp/state/docs.js +1101 -301
- package/runtime/scripts/amalgm-mcp/state/mutation-contracts.js +99 -0
- package/runtime/scripts/amalgm-mcp/state/mutations.js +507 -130
- package/runtime/scripts/amalgm-mcp/state/promotions.js +21 -1
- package/runtime/scripts/amalgm-mcp/state/replicas.js +134 -13
- package/runtime/scripts/amalgm-mcp/state/shared-rest.js +14 -8
- package/runtime/scripts/amalgm-mcp/tests/browser-cookie-cloud.test.js +193 -0
- package/runtime/scripts/amalgm-mcp/tests/code-project-stream.test.js +313 -94
- package/runtime/scripts/amalgm-mcp/tests/fixtures/code-project-stream-v2.json +1 -0
- package/runtime/scripts/amalgm-mcp/tests/project-context.test.js +32 -17
- package/runtime/scripts/amalgm-mcp/tests/shared-tunnel-rehydration.test.js +84 -0
- package/runtime/scripts/amalgm-mcp/tests/state-docs.test.js +376 -13
- package/runtime/scripts/amalgm-mcp/tests/state-mutations.test.js +309 -0
- package/runtime/scripts/amalgm-mcp/tests/state-shared-replica.test.js +758 -30
- package/runtime/scripts/amalgm-mcp/tests/workspace-cards-store.test.js +72 -3
- package/runtime/scripts/amalgm-mcp/tests/workspace-cards.test.js +33 -6
- package/runtime/scripts/amalgm-mcp/tests/workspace-checkpoint-reducer.test.js +27 -0
- package/runtime/scripts/amalgm-mcp/tests/workspace-checkpoint.test.js +334 -191
- package/runtime/scripts/amalgm-mcp/tests/workspace-durable.test.js +24 -0
- package/runtime/scripts/amalgm-mcp/tests/workspace-local-intent.test.js +1999 -0
- package/runtime/scripts/amalgm-mcp/tests/workspace-native-file-transaction.test.js +364 -0
- package/runtime/scripts/amalgm-mcp/tests/workspace-object-tunnel.test.js +81 -3
- package/runtime/scripts/amalgm-mcp/tests/workspace-objects.test.js +114 -8
- package/runtime/scripts/amalgm-mcp/tests/workspace-provenance.test.js +185 -0
- package/runtime/scripts/amalgm-mcp/tests/workspace-publication-invariants.test.js +174 -269
- package/runtime/scripts/amalgm-mcp/tests/workspace-reducer-liveness.test.js +26 -0
- package/runtime/scripts/amalgm-mcp/tests/workspace-reducer.test.js +2060 -407
- package/runtime/scripts/amalgm-mcp/tests/workspace-sync-stats.test.js +119 -0
- package/runtime/scripts/amalgm-mcp/tests/workspace-transition.test.js +1446 -0
- package/runtime/scripts/amalgm-mcp/tests/workspace-tree-cloud.test.js +5319 -3
- package/runtime/scripts/amalgm-mcp/tests/workspace-tree-core.test.js +191 -1
- package/runtime/scripts/amalgm-mcp/tests/workspace-tree-store.test.js +3140 -17
- package/runtime/scripts/amalgm-mcp/tests/workspace-wall.test.js +135 -637
- package/runtime/scripts/amalgm-mcp/workspace/access-store.js +5 -1
- package/runtime/scripts/amalgm-mcp/workspace/card.js +7 -7
- package/runtime/scripts/amalgm-mcp/workspace/cards.js +36 -12
- package/runtime/scripts/amalgm-mcp/workspace/checkpoint.js +436 -173
- package/runtime/scripts/amalgm-mcp/workspace/content.js +32 -0
- package/runtime/scripts/amalgm-mcp/workspace/durable.js +45 -0
- package/runtime/scripts/amalgm-mcp/workspace/git.js +391 -37
- package/runtime/scripts/amalgm-mcp/workspace/intent.js +535 -0
- package/runtime/scripts/amalgm-mcp/workspace/merge.js +89 -6
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/BUILD.md +31 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/bin/darwin-arm64/amalgm-file-transaction +0 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/bin/linux-x64/amalgm-file-transaction +0 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/build.mjs +72 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/client.js +165 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/go.mod +5 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/go.sum +2 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/main.go +2201 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/manifest.json +19 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/move_darwin.go +18 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/move_linux.go +18 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/process_darwin.go +33 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/process_linux.go +47 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/verify.mjs +43 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/writers_darwin.go +114 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/writers_linux.go +84 -0
- package/runtime/scripts/amalgm-mcp/workspace/objects.js +119 -54
- package/runtime/scripts/amalgm-mcp/workspace/project-stream.js +616 -168
- package/runtime/scripts/amalgm-mcp/workspace/provenance.js +240 -0
- package/runtime/scripts/amalgm-mcp/workspace/reducer.js +1979 -570
- package/runtime/scripts/amalgm-mcp/workspace/rest.js +49 -28
- package/runtime/scripts/amalgm-mcp/workspace/store.js +77 -4
- package/runtime/scripts/amalgm-mcp/workspace/sync-stats.js +240 -0
- package/runtime/scripts/amalgm-mcp/workspace/transition.js +1729 -192
- package/runtime/scripts/amalgm-mcp/workspace/tree/floor.js +100 -0
- package/runtime/scripts/amalgm-mcp/workspace/tree/inclusion.js +7 -1
- package/runtime/scripts/amalgm-mcp/workspace/tree/local-state.js +73 -61
- package/runtime/scripts/amalgm-mcp/workspace/tree/observation-holds.js +127 -0
- package/runtime/scripts/amalgm-mcp/workspace/tree/path-state.js +12 -0
- package/runtime/scripts/amalgm-mcp/workspace/tree/reducer.js +51 -6
- package/runtime/scripts/amalgm-mcp/workspace/tree/root-binding.js +125 -0
- package/runtime/scripts/amalgm-mcp/workspace/tree/snapshot.js +79 -8
- package/runtime/scripts/amalgm-mcp/workspace/tree/symlinks.js +76 -0
- package/runtime/scripts/amalgm-mcp/workspace/tree-cloud.js +3480 -165
- package/runtime/scripts/amalgm-mcp/workspace/tree-materialization.js +3766 -0
- package/runtime/scripts/amalgm-mcp/workspace/tree-store.js +899 -71
- package/runtime/scripts/amalgm-mcp/workspace/wall.js +352 -497
|
@@ -8,12 +8,36 @@
|
|
|
8
8
|
* is already backed by this WAL database.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
const fs = require('fs');
|
|
11
12
|
const path = require('path');
|
|
12
13
|
const { ensureDir } = require('../lib/storage');
|
|
13
14
|
const { LOCAL_DB_FILE, STORAGE_DIR } = require('../config');
|
|
14
15
|
|
|
15
16
|
let db = null;
|
|
16
17
|
|
|
18
|
+
const SHARED_RESOURCE_ATTACHMENTS_TABLE_SQL = `
|
|
19
|
+
CREATE TABLE IF NOT EXISTS shared_resource_attachments (
|
|
20
|
+
attachment_id TEXT PRIMARY KEY,
|
|
21
|
+
resource_id TEXT NOT NULL UNIQUE,
|
|
22
|
+
local_path TEXT NOT NULL UNIQUE,
|
|
23
|
+
attachment_state TEXT NOT NULL DEFAULT 'pending'
|
|
24
|
+
CHECK (attachment_state IN ('pending', 'syncing', 'attached', 'rejected')),
|
|
25
|
+
attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
|
|
26
|
+
next_attempt_at TEXT,
|
|
27
|
+
last_error TEXT,
|
|
28
|
+
-- First-attachment fence: local document mutations after this cursor
|
|
29
|
+
-- are overlay work that the returned cloud snapshot cannot contain.
|
|
30
|
+
journal_cursor INTEGER NOT NULL DEFAULT 0,
|
|
31
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
32
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
33
|
+
);
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
const SHARED_RESOURCE_ATTACHMENTS_INDEX_SQL = `
|
|
37
|
+
CREATE INDEX IF NOT EXISTS shared_resource_attachments_outbox_idx
|
|
38
|
+
ON shared_resource_attachments (attachment_state, next_attempt_at, created_at);
|
|
39
|
+
`;
|
|
40
|
+
|
|
17
41
|
// Prepared statements cached per database handle: preparing is a parse+plan
|
|
18
42
|
// every time, and the realtime hot paths (event insert, replay reads, mirror
|
|
19
43
|
// upserts, doc persistence) run the same fixed SQL for the process lifetime.
|
|
@@ -110,10 +134,12 @@ function migrate(database = openLocalDb()) {
|
|
|
110
134
|
)),
|
|
111
135
|
local_revision INTEGER,
|
|
112
136
|
materialized_at TEXT,
|
|
137
|
+
official_projected_at TEXT,
|
|
113
138
|
event_seq INTEGER,
|
|
114
139
|
attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
|
|
115
140
|
next_attempt_at TEXT,
|
|
116
141
|
last_error TEXT,
|
|
142
|
+
failure_code TEXT,
|
|
117
143
|
cloud_committed_at TEXT,
|
|
118
144
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
119
145
|
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
@@ -202,22 +228,6 @@ function migrate(database = openLocalDb()) {
|
|
|
202
228
|
CREATE INDEX IF NOT EXISTS shared_resource_promotions_outbox_idx
|
|
203
229
|
ON shared_resource_promotions (promotion_state, next_attempt_at, created_at);
|
|
204
230
|
|
|
205
|
-
CREATE TABLE IF NOT EXISTS shared_resource_attachments (
|
|
206
|
-
attachment_id TEXT PRIMARY KEY,
|
|
207
|
-
resource_id TEXT NOT NULL UNIQUE,
|
|
208
|
-
local_path TEXT NOT NULL UNIQUE,
|
|
209
|
-
attachment_state TEXT NOT NULL DEFAULT 'pending'
|
|
210
|
-
CHECK (attachment_state IN ('pending', 'syncing', 'attached', 'rejected')),
|
|
211
|
-
attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
|
|
212
|
-
next_attempt_at TEXT,
|
|
213
|
-
last_error TEXT,
|
|
214
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
215
|
-
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
CREATE INDEX IF NOT EXISTS shared_resource_attachments_outbox_idx
|
|
219
|
-
ON shared_resource_attachments (attachment_state, next_attempt_at, created_at);
|
|
220
|
-
|
|
221
231
|
CREATE TABLE IF NOT EXISTS local_meta (
|
|
222
232
|
key TEXT PRIMARY KEY,
|
|
223
233
|
value TEXT,
|
|
@@ -557,6 +567,7 @@ function migrate(database = openLocalDb()) {
|
|
|
557
567
|
device_id TEXT,
|
|
558
568
|
inode TEXT,
|
|
559
569
|
trashed_at TEXT,
|
|
570
|
+
trash_component_id TEXT,
|
|
560
571
|
purged_at TEXT,
|
|
561
572
|
missing_at TEXT,
|
|
562
573
|
created_at TEXT NOT NULL,
|
|
@@ -566,7 +577,7 @@ function migrate(database = openLocalDb()) {
|
|
|
566
577
|
);
|
|
567
578
|
|
|
568
579
|
DROP INDEX IF EXISTS workspace_nodes_live_path_idx;
|
|
569
|
-
CREATE UNIQUE INDEX workspace_nodes_live_path_idx
|
|
580
|
+
CREATE UNIQUE INDEX IF NOT EXISTS workspace_nodes_live_path_idx
|
|
570
581
|
ON workspace_nodes(workspace_id, relative_path)
|
|
571
582
|
WHERE purged_at IS NULL AND missing_at IS NULL AND trashed_at IS NULL;
|
|
572
583
|
|
|
@@ -577,6 +588,23 @@ function migrate(database = openLocalDb()) {
|
|
|
577
588
|
ON workspace_nodes(workspace_id, device_id, inode)
|
|
578
589
|
WHERE device_id IS NOT NULL AND inode IS NOT NULL AND purged_at IS NULL;
|
|
579
590
|
|
|
591
|
+
-- A safe filesystem ambiguity is still a sync failure if it is visible
|
|
592
|
+
-- only in one observer's return value. Keep every nonterminal tree wait
|
|
593
|
+
-- durable and addressable so restart and Local Live diagnostics see the
|
|
594
|
+
-- same held state until a later observation clears it.
|
|
595
|
+
CREATE TABLE IF NOT EXISTS workspace_tree_observation_holds (
|
|
596
|
+
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
|
597
|
+
hold_key TEXT NOT NULL,
|
|
598
|
+
owner_kind TEXT NOT NULL DEFAULT 'observer',
|
|
599
|
+
owner_id TEXT NOT NULL DEFAULT 'workspace-tree-observer',
|
|
600
|
+
reason TEXT NOT NULL,
|
|
601
|
+
node_id TEXT,
|
|
602
|
+
operation_kind TEXT,
|
|
603
|
+
paths_json TEXT NOT NULL,
|
|
604
|
+
first_observed_at TEXT NOT NULL,
|
|
605
|
+
PRIMARY KEY (workspace_id, hold_key)
|
|
606
|
+
);
|
|
607
|
+
|
|
580
608
|
CREATE TABLE IF NOT EXISTS workspace_access_state (
|
|
581
609
|
workspace_id TEXT PRIMARY KEY REFERENCES workspaces(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
|
582
610
|
authority_epoch INTEGER NOT NULL DEFAULT 1 CHECK (authority_epoch > 0),
|
|
@@ -694,15 +722,40 @@ function migrate(database = openLocalDb()) {
|
|
|
694
722
|
ON browser_login_sessions(expires_at);
|
|
695
723
|
|
|
696
724
|
`);
|
|
725
|
+
database.exec(SHARED_RESOURCE_ATTACHMENTS_TABLE_SQL);
|
|
726
|
+
database.exec(SHARED_RESOURCE_ATTACHMENTS_INDEX_SQL);
|
|
697
727
|
|
|
698
728
|
// event_log is already present on every installed machine. These nullable
|
|
699
729
|
// projection fields are additive and leave every legacy row/wire shape
|
|
700
730
|
// untouched while new SDK mutations carry their stable identity.
|
|
701
731
|
ensureColumn(database, 'event_log', 'mutation_id', 'TEXT');
|
|
702
732
|
ensureColumn(database, 'event_log', 'shared_resource_id', 'TEXT');
|
|
733
|
+
ensureColumn(database, 'mutation_journal', 'failure_code', 'TEXT');
|
|
734
|
+
ensureColumn(database, 'mutation_journal', 'official_projected_at', 'TEXT');
|
|
735
|
+
ensureColumn(database, 'workspace_nodes', 'trash_component_id', 'TEXT');
|
|
736
|
+
ensureColumn(
|
|
737
|
+
database,
|
|
738
|
+
'workspace_tree_observation_holds',
|
|
739
|
+
'owner_kind',
|
|
740
|
+
"TEXT NOT NULL DEFAULT 'observer'",
|
|
741
|
+
);
|
|
742
|
+
ensureColumn(
|
|
743
|
+
database,
|
|
744
|
+
'workspace_tree_observation_holds',
|
|
745
|
+
'owner_id',
|
|
746
|
+
"TEXT NOT NULL DEFAULT 'workspace-tree-observer'",
|
|
747
|
+
);
|
|
748
|
+
backfillWorkspaceTrashComponents(database);
|
|
703
749
|
// Wave-3 canaries created shared_resource_promotions before the fence
|
|
704
750
|
// cursor existed.
|
|
705
751
|
ensureColumn(database, 'shared_resource_promotions', 'journal_cursor', 'INTEGER NOT NULL DEFAULT 0');
|
|
752
|
+
ensureColumn(
|
|
753
|
+
database,
|
|
754
|
+
'shared_resource_attachments',
|
|
755
|
+
'journal_cursor',
|
|
756
|
+
'INTEGER NOT NULL DEFAULT 0',
|
|
757
|
+
);
|
|
758
|
+
enforceAttachmentJournalFence(database);
|
|
706
759
|
ensureColumn(
|
|
707
760
|
database,
|
|
708
761
|
'shared_resource_replicas',
|
|
@@ -719,6 +772,108 @@ function ensureColumn(database, tableName, columnName, declaration) {
|
|
|
719
772
|
database.exec(`ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${declaration}`);
|
|
720
773
|
}
|
|
721
774
|
|
|
775
|
+
function backfillWorkspaceTrashComponents(database) {
|
|
776
|
+
database.prepare(`
|
|
777
|
+
UPDATE workspace_nodes
|
|
778
|
+
SET trash_component_id = NULL
|
|
779
|
+
WHERE purged_at IS NOT NULL AND trash_component_id IS NOT NULL
|
|
780
|
+
`).run();
|
|
781
|
+
const workspaces = database.prepare(
|
|
782
|
+
'SELECT id, path FROM workspaces WHERE path IS NOT NULL',
|
|
783
|
+
).all();
|
|
784
|
+
const update = database.prepare(`
|
|
785
|
+
UPDATE workspace_nodes SET trash_component_id = ? WHERE id = ?
|
|
786
|
+
`);
|
|
787
|
+
database.transaction(() => {
|
|
788
|
+
for (const workspace of workspaces) {
|
|
789
|
+
const allRows = database.prepare(`
|
|
790
|
+
SELECT id, parent_id, trashed_at
|
|
791
|
+
FROM workspace_nodes
|
|
792
|
+
WHERE workspace_id = ? AND trashed_at IS NOT NULL AND purged_at IS NULL
|
|
793
|
+
`).all(workspace.id);
|
|
794
|
+
const nodes = new Map(allRows.map((row) => [row.id, row]));
|
|
795
|
+
const unstamped = database.prepare(`
|
|
796
|
+
SELECT id FROM workspace_nodes
|
|
797
|
+
WHERE workspace_id = ? AND trashed_at IS NOT NULL
|
|
798
|
+
AND purged_at IS NULL AND trash_component_id IS NULL
|
|
799
|
+
`).all(workspace.id);
|
|
800
|
+
for (const { id } of unstamped) {
|
|
801
|
+
const row = nodes.get(id);
|
|
802
|
+
let current = row;
|
|
803
|
+
let physicalRoot = null;
|
|
804
|
+
while (current) {
|
|
805
|
+
const candidate = path.join(
|
|
806
|
+
path.dirname(path.resolve(workspace.path)),
|
|
807
|
+
`.amalgm-tree-trash-${workspace.id}`,
|
|
808
|
+
current.id,
|
|
809
|
+
);
|
|
810
|
+
if (fs.existsSync(candidate)) {
|
|
811
|
+
physicalRoot = current.id;
|
|
812
|
+
break;
|
|
813
|
+
}
|
|
814
|
+
current = nodes.get(current.parent_id) || null;
|
|
815
|
+
}
|
|
816
|
+
// Missing physical evidence is not permission to infer ownership
|
|
817
|
+
// from a timestamp. Recovery may temporarily hold the carrier in
|
|
818
|
+
// private staging; rerun this proof after recovery or remount.
|
|
819
|
+
if (physicalRoot) update.run(physicalRoot, row.id);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
})();
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
function enforceAttachmentJournalFence(database) {
|
|
826
|
+
const cursor = database.prepare('PRAGMA table_info(shared_resource_attachments)')
|
|
827
|
+
.all()
|
|
828
|
+
.find((column) => column.name === 'journal_cursor');
|
|
829
|
+
if (!cursor) {
|
|
830
|
+
throw new Error('shared attachment journal fence is missing');
|
|
831
|
+
}
|
|
832
|
+
database.prepare(`
|
|
833
|
+
UPDATE shared_resource_attachments
|
|
834
|
+
SET journal_cursor = 0
|
|
835
|
+
WHERE journal_cursor IS NULL
|
|
836
|
+
`).run();
|
|
837
|
+
if (cursor.notnull === 1 && String(cursor.dflt_value) === '0') return;
|
|
838
|
+
|
|
839
|
+
database.transaction(() => {
|
|
840
|
+
database.exec('DROP INDEX IF EXISTS shared_resource_attachments_outbox_idx');
|
|
841
|
+
database.exec(`
|
|
842
|
+
ALTER TABLE shared_resource_attachments
|
|
843
|
+
RENAME TO shared_resource_attachments_legacy_fence
|
|
844
|
+
`);
|
|
845
|
+
database.exec(SHARED_RESOURCE_ATTACHMENTS_TABLE_SQL);
|
|
846
|
+
database.exec(`
|
|
847
|
+
INSERT INTO shared_resource_attachments (
|
|
848
|
+
attachment_id,
|
|
849
|
+
resource_id,
|
|
850
|
+
local_path,
|
|
851
|
+
attachment_state,
|
|
852
|
+
attempt_count,
|
|
853
|
+
next_attempt_at,
|
|
854
|
+
last_error,
|
|
855
|
+
journal_cursor,
|
|
856
|
+
created_at,
|
|
857
|
+
updated_at
|
|
858
|
+
)
|
|
859
|
+
SELECT
|
|
860
|
+
attachment_id,
|
|
861
|
+
resource_id,
|
|
862
|
+
local_path,
|
|
863
|
+
attachment_state,
|
|
864
|
+
attempt_count,
|
|
865
|
+
next_attempt_at,
|
|
866
|
+
last_error,
|
|
867
|
+
COALESCE(journal_cursor, 0),
|
|
868
|
+
created_at,
|
|
869
|
+
updated_at
|
|
870
|
+
FROM shared_resource_attachments_legacy_fence
|
|
871
|
+
`);
|
|
872
|
+
database.exec('DROP TABLE shared_resource_attachments_legacy_fence');
|
|
873
|
+
database.exec(SHARED_RESOURCE_ATTACHMENTS_INDEX_SQL);
|
|
874
|
+
})();
|
|
875
|
+
}
|
|
876
|
+
|
|
722
877
|
// repo-card identity moved from the path to minted replica ids
|
|
723
878
|
// (repo-card@2). Cards are derived observations, so the v1 table is
|
|
724
879
|
// dropped rather than migrated — the next refresh rebuilds every card
|
|
@@ -764,7 +919,47 @@ function ensureDocStatesSchema(database = openLocalDb()) {
|
|
|
764
919
|
CREATE UNIQUE INDEX IF NOT EXISTS doc_states_node_id_idx
|
|
765
920
|
ON doc_states(node_id)
|
|
766
921
|
WHERE node_id IS NOT NULL;
|
|
922
|
+
|
|
923
|
+
CREATE TABLE IF NOT EXISTS doc_disk_materializations (
|
|
924
|
+
channel_id TEXT NOT NULL,
|
|
925
|
+
mutation_id TEXT NOT NULL,
|
|
926
|
+
local_resource TEXT NOT NULL,
|
|
927
|
+
root TEXT NOT NULL,
|
|
928
|
+
root_dev TEXT NOT NULL,
|
|
929
|
+
root_ino TEXT NOT NULL,
|
|
930
|
+
relative_path TEXT NOT NULL,
|
|
931
|
+
transaction_id TEXT NOT NULL,
|
|
932
|
+
operation_id TEXT NOT NULL,
|
|
933
|
+
expected_json TEXT,
|
|
934
|
+
observed_text TEXT,
|
|
935
|
+
mutation_source TEXT,
|
|
936
|
+
target_json TEXT,
|
|
937
|
+
target_content BLOB,
|
|
938
|
+
plan_kind TEXT NOT NULL DEFAULT 'mutation'
|
|
939
|
+
CHECK (plan_kind IN ('mutation', 'snapshot')),
|
|
940
|
+
snapshot_payload_json TEXT,
|
|
941
|
+
snapshot_event_seq INTEGER,
|
|
942
|
+
materialization_state TEXT NOT NULL DEFAULT 'based'
|
|
943
|
+
CHECK (materialization_state IN ('based', 'prepared', 'crossed', 'superseded')),
|
|
944
|
+
successor_channel_id TEXT,
|
|
945
|
+
successor_mutation_id TEXT,
|
|
946
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
947
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
948
|
+
PRIMARY KEY (channel_id, mutation_id)
|
|
949
|
+
);
|
|
950
|
+
|
|
951
|
+
CREATE INDEX IF NOT EXISTS doc_disk_materializations_resource_idx
|
|
952
|
+
ON doc_disk_materializations(local_resource, created_at);
|
|
767
953
|
`);
|
|
954
|
+
ensureColumn(
|
|
955
|
+
database,
|
|
956
|
+
'doc_disk_materializations',
|
|
957
|
+
'plan_kind',
|
|
958
|
+
"TEXT NOT NULL DEFAULT 'mutation' CHECK (plan_kind IN ('mutation', 'snapshot'))",
|
|
959
|
+
);
|
|
960
|
+
ensureColumn(database, 'doc_disk_materializations', 'snapshot_payload_json', 'TEXT');
|
|
961
|
+
ensureColumn(database, 'doc_disk_materializations', 'snapshot_event_seq', 'INTEGER');
|
|
962
|
+
ensureColumn(database, 'doc_disk_materializations', 'mutation_source', 'TEXT');
|
|
768
963
|
}
|
|
769
964
|
|
|
770
965
|
// App-registered resources (state/app-resources.js): the engine-side mirror
|
|
@@ -795,9 +990,13 @@ function closeLocalDb() {
|
|
|
795
990
|
}
|
|
796
991
|
|
|
797
992
|
module.exports = {
|
|
993
|
+
backfillWorkspaceTrashComponents,
|
|
798
994
|
cachedStatement,
|
|
799
995
|
closeLocalDb,
|
|
800
996
|
ensureAppResourcesSchema,
|
|
801
997
|
ensureDocStatesSchema,
|
|
802
998
|
openLocalDb,
|
|
999
|
+
_private: {
|
|
1000
|
+
migrate,
|
|
1001
|
+
},
|
|
803
1002
|
};
|