@lmzhen/dsh-evolution-state-json 0.3.32 → 0.3.34
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/index.js +47 -29
- package/package.json +6 -6
package/lib/index.js
CHANGED
|
@@ -95,25 +95,35 @@ function apply(ctx, rawConfig) {
|
|
|
95
95
|
}
|
|
96
96
|
const mutate = makeSerialQueue();
|
|
97
97
|
let legacyMigrated = false;
|
|
98
|
+
let archivedIdsCache = null;
|
|
99
|
+
async function readArchivedIds() {
|
|
100
|
+
if (archivedIdsCache !== null) return archivedIdsCache;
|
|
101
|
+
const ids = /* @__PURE__ */ new Set();
|
|
102
|
+
try {
|
|
103
|
+
const rawArchive = await readJson("pending-state-archive.json");
|
|
104
|
+
if (Array.isArray(rawArchive)) {
|
|
105
|
+
for (const entry of rawArchive) if (entry && typeof entry.id === "string") ids.add(entry.id);
|
|
106
|
+
}
|
|
107
|
+
} catch {}
|
|
108
|
+
archivedIdsCache = ids;
|
|
109
|
+
return ids;
|
|
110
|
+
}
|
|
111
|
+
function filterLegacy(legacy, current, archivedIds) {
|
|
112
|
+
const retired = {};
|
|
113
|
+
for (const [id, record] of Object.entries(legacy)) {
|
|
114
|
+
if (id in (current ?? {})) continue;
|
|
115
|
+
if (archivedIds.has(id)) continue;
|
|
116
|
+
retired[id] = record;
|
|
117
|
+
}
|
|
118
|
+
return retired;
|
|
119
|
+
}
|
|
98
120
|
async function retireLegacyOnce(legacy, current) {
|
|
99
121
|
if (legacyMigrated) return {};
|
|
100
122
|
try {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
const rawArchive = await readJson("pending-state-archive.json");
|
|
104
|
-
if (Array.isArray(rawArchive)) {
|
|
105
|
-
for (const entry of rawArchive) if (entry && typeof entry.id === "string") archivedIds.add(entry.id);
|
|
106
|
-
}
|
|
107
|
-
} catch {}
|
|
108
|
-
const retired = {};
|
|
109
|
-
for (const [id, record] of Object.entries(legacy)) {
|
|
110
|
-
if (id in (current ?? {})) continue;
|
|
111
|
-
if (archivedIds.has(id)) continue;
|
|
112
|
-
retired[id] = record;
|
|
113
|
-
}
|
|
114
|
-
await jsonTransact(io, root, "pending-state.json", () => ({
|
|
123
|
+
const retired = filterLegacy(legacy, current, await readArchivedIds());
|
|
124
|
+
await jsonTransact(io, root, "pending-state.json", (fresh) => ({
|
|
115
125
|
...retired,
|
|
116
|
-
...
|
|
126
|
+
...fresh ?? {}
|
|
117
127
|
}));
|
|
118
128
|
await io().rename(pathOf("pending.json"), pathOf("pending.json.migrated"));
|
|
119
129
|
legacyMigrated = true;
|
|
@@ -130,6 +140,17 @@ function apply(ctx, rawConfig) {
|
|
|
130
140
|
};
|
|
131
141
|
return { ...current ?? {} };
|
|
132
142
|
}
|
|
143
|
+
/** V6-01 (0.3.34): single-sourced legacy merge for the four mutation paths —
|
|
144
|
+
* the SAME exclusion as the retirement read path, so a mutation that runs
|
|
145
|
+
* before any retirement cannot fixate a ghost pending twin in current
|
|
146
|
+
* (the archive id set is cached once; current-wins covers stale misses). */
|
|
147
|
+
async function mergedWithFilteredLegacy(legacy, current) {
|
|
148
|
+
if (legacy === null) return current;
|
|
149
|
+
return {
|
|
150
|
+
...filterLegacy(legacy, current, await readArchivedIds()),
|
|
151
|
+
...current
|
|
152
|
+
};
|
|
153
|
+
}
|
|
133
154
|
/** 0.3.22 (F-336): when the live pending map holds more than
|
|
134
155
|
* `PENDING_RESOLVED_CAP` resolved records, drop the oldest (by resolvedAt,
|
|
135
156
|
* then insertion order on ties) from the map and return them for archiving.
|
|
@@ -175,6 +196,13 @@ function apply(ctx, rawConfig) {
|
|
|
175
196
|
const parsed = JSON.parse(current);
|
|
176
197
|
if (Array.isArray(parsed)) archive = parsed;
|
|
177
198
|
} catch {}
|
|
199
|
+
const archiveKeys = /* @__PURE__ */ new Set();
|
|
200
|
+
archive = archive.filter((entry) => {
|
|
201
|
+
const key = pendingArchiveKey(entry);
|
|
202
|
+
if (archiveKeys.has(key)) return false;
|
|
203
|
+
archiveKeys.add(key);
|
|
204
|
+
return true;
|
|
205
|
+
});
|
|
178
206
|
const seen = new Set(archive.map(pendingArchiveKey));
|
|
179
207
|
const fresh = records.filter((record) => !seen.has(pendingArchiveKey(record)));
|
|
180
208
|
if (fresh.length === 0) return current;
|
|
@@ -237,8 +265,7 @@ function apply(ctx, rawConfig) {
|
|
|
237
265
|
await mutate(async () => {
|
|
238
266
|
await jsonTransact(io, root, "pending-state.json", async (current) => {
|
|
239
267
|
return {
|
|
240
|
-
...(legacyMigrated ? null : await readJson("pending.json")
|
|
241
|
-
...current ?? {},
|
|
268
|
+
...await mergedWithFilteredLegacy(legacyMigrated ? null : await readJson("pending.json"), current ?? {}),
|
|
242
269
|
[record.id]: record
|
|
243
270
|
};
|
|
244
271
|
});
|
|
@@ -248,10 +275,7 @@ function apply(ctx, rawConfig) {
|
|
|
248
275
|
return await mutate(async () => {
|
|
249
276
|
const slot = { claimed: null };
|
|
250
277
|
await jsonTransact(io, root, "pending-state.json", async (current) => {
|
|
251
|
-
const map = {
|
|
252
|
-
...(legacyMigrated ? null : await readJson("pending.json")) ?? {},
|
|
253
|
-
...current ?? {}
|
|
254
|
-
};
|
|
278
|
+
const map = { ...await mergedWithFilteredLegacy(legacyMigrated ? null : await readJson("pending.json"), current ?? {}) };
|
|
255
279
|
const record = map[id] ?? null;
|
|
256
280
|
if (record === null || !canClaimPending(record.status)) return map;
|
|
257
281
|
const now = Date.now();
|
|
@@ -270,10 +294,7 @@ function apply(ctx, rawConfig) {
|
|
|
270
294
|
async releasePendingClaim(id, claimId) {
|
|
271
295
|
await mutate(async () => {
|
|
272
296
|
await jsonTransact(io, root, "pending-state.json", async (current) => {
|
|
273
|
-
const map = {
|
|
274
|
-
...(legacyMigrated ? null : await readJson("pending.json")) ?? {},
|
|
275
|
-
...current ?? {}
|
|
276
|
-
};
|
|
297
|
+
const map = { ...await mergedWithFilteredLegacy(legacyMigrated ? null : await readJson("pending.json"), current ?? {}) };
|
|
277
298
|
const record = map[id];
|
|
278
299
|
if (!record || record.claimedBy !== claimId) return map;
|
|
279
300
|
record.status = releasedStatus(record.status);
|
|
@@ -291,10 +312,7 @@ function apply(ctx, rawConfig) {
|
|
|
291
312
|
};
|
|
292
313
|
let evicted = [];
|
|
293
314
|
await jsonTransact(io, root, "pending-state.json", async (current) => {
|
|
294
|
-
const map = {
|
|
295
|
-
...(legacyMigrated ? null : await readJson("pending.json")) ?? {},
|
|
296
|
-
...current ?? {}
|
|
297
|
-
};
|
|
315
|
+
const map = { ...await mergedWithFilteredLegacy(legacyMigrated ? null : await readJson("pending.json"), current ?? {}) };
|
|
298
316
|
const record = map[id] ?? null;
|
|
299
317
|
if (record === null || !canResolvePending(record.status)) {
|
|
300
318
|
result = {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-state-json",
|
|
3
3
|
"description": "JSON-file evolution state provider over the IO seam (community build)",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.34",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -31,17 +31,17 @@
|
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
34
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
34
|
+
"@lmzhen/dsh-evolution-core": "^0.3.34"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
38
38
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
39
|
-
"@lmzhen/dsh-evolution-io": "^0.3.
|
|
40
|
-
"@lmzhen/dsh-evolution-state-storage": "^0.3.
|
|
39
|
+
"@lmzhen/dsh-evolution-io": "^0.3.34",
|
|
40
|
+
"@lmzhen/dsh-evolution-state-storage": "^0.3.34"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
44
|
-
"@lmzhen/dsh-evolution-io": "^0.3.
|
|
45
|
-
"@lmzhen/dsh-evolution-state-storage": "^0.3.
|
|
44
|
+
"@lmzhen/dsh-evolution-io": "^0.3.34",
|
|
45
|
+
"@lmzhen/dsh-evolution-state-storage": "^0.3.34"
|
|
46
46
|
}
|
|
47
47
|
}
|