@lmzhen/dsh-evolution-state-json 0.32.3 → 0.32.4

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/README.md CHANGED
@@ -17,7 +17,7 @@ change.
17
17
  ## Known limitations
18
18
 
19
19
  - Both tables are capped (200 pending, 500 sessions), and past the pending cap the DOMAIN provider deletes instead of archiving: this provider keeps an audit sidecar. The `updatedAt` stamp is stripped on read, so the consumer-facing record shape is unchanged.
20
- - The one medium without cross-process write locking is the `storage-json` store behind the DOMAIN provider: route multi-process deployments to a backend with cross-process semantics such as SQLite or remote storage.
20
+ - All shipped JSON media are **single-process**: the IO backend has no cross-process lock. A second process sharing `DSH_HOME` is not coordinated; route multi-process deployments to a platform-provided cross-process backend before relying on this provider.
21
21
 
22
22
  **Runtime invariant:** No companion is published. The platform auto-assembles nothing and the family mounts no `<pkg>/invariant` cordis row, so a companion here would never execute (v37 S2.1 / I-3).
23
23
 
@@ -25,4 +25,4 @@ change.
25
25
 
26
26
  - P2-4 (v15): the live pending map is BOUNDED — resolved (approved/rejected) records are kept to the most recent `PENDING_RESOLVED_CAP` (200, seam constant in `evolution-state-storage`); the oldest by `resolvedAt` rotate into the `pending-state-archive.json` sidecar (with `.bak` rotation), which is JSON-provider-specific.
27
27
  - V25-11 (v25): the review-state table is likewise BOUNDED: `REVIEW_STATE_SESSION_CAP` (500, seam constant) rows keyed by session; on every save the least-recently-active sessions (provider-stamped `updatedAt`, stored on disk only) are pruned.
28
- - JSON provider serializes writers inside one process AND through the IO backend's cross-process transact lock (an internal transact wrapper (not public API, audit v10 S-03) wraps every mutation, 0.3.20/0.3.27) — this provider is NOT limited to single-process safety.
28
+ - The JSON provider serializes writers inside one process only (the internal transact wrapper is not public API, audit v10 S-03). It does **not** claim cross-process safety; the shipped IO backend declares single-process.
package/lib/index.js CHANGED
@@ -1,55 +1,7 @@
1
1
  import z from "@deepseek-ai/schemastery";
2
- import { evolutionHome, isAbsent, isPresent, isRecord, isUnknown, makeSerialQueue, probeText, transactIo, transactTaskGuard } from "@lmzhen/dsh-evolution-core";
2
+ import { WriteKernel, evolutionHome, isAbsent, isPresent, isRecord, isUnknown, makeSerialQueue, probeText, transactIo, transactTaskGuard } from "@lmzhen/dsh-evolution-core";
3
3
  import { CURATOR_STATE_FILE, CURATOR_STATE_KEY, CURATOR_STATE_TABLE, PENDING_ARCHIVE_BAK_FILE, PENDING_ARCHIVE_FILE, PENDING_LEGACY_FILE, PENDING_RESOLVED_CAP, PENDING_STATE_FILE, PENDING_TABLE, PROVIDER_JSON, REVIEW_STATE_FILE, REVIEW_STATE_SESSION_CAP, REVIEW_STATE_TABLE, assertCloneable, canClaimPending, canResolvePending, cloneRecord, recordIssue, releasedStatus, selectPendingOverflow, selectSessionOverflow } from "@lmzhen/dsh-evolution-state-storage";
4
4
  import { basename, dirname, isAbsolute, join } from "node:path";
5
- //#region lib/types/state-store.js
6
- const safeName = (collection) => String(collection).replace(/[^a-zA-Z0-9._-]/g, "_");
7
- var JsonStateStore = class {
8
- name = "json-state-store";
9
- capabilities = { crossProcess: false };
10
- io;
11
- root;
12
- serial = makeSerialQueue();
13
- constructor(io, root) {
14
- this.io = io;
15
- this.root = root;
16
- }
17
- path(collection) {
18
- return join(this.root, "state-store", safeName(collection) + ".json");
19
- }
20
- async load(collection) {
21
- const text = await this.io.readText(this.path(collection));
22
- if (text === null) return {
23
- schemaVersion: 1,
24
- records: {}
25
- };
26
- const parsed = JSON.parse(text);
27
- if (parsed.schemaVersion !== 1 || parsed.records === null || typeof parsed.records !== "object" || Array.isArray(parsed.records)) throw new Error("state-store collection is corrupt: " + String(collection));
28
- return parsed;
29
- }
30
- async read(collection, key) {
31
- return (await this.load(collection)).records[key];
32
- }
33
- async transact(collection, key, fn) {
34
- return this.serial(async () => {
35
- let next;
36
- await transactIo(this.io, this.path(collection), async (current) => {
37
- const file = current === null ? {
38
- schemaVersion: 1,
39
- records: {}
40
- } : JSON.parse(current);
41
- next = await fn(file.records[key]);
42
- file.records[key] = next;
43
- return JSON.stringify(file);
44
- });
45
- return next;
46
- });
47
- }
48
- async list(collection) {
49
- return Object.values((await this.load(collection)).records);
50
- }
51
- };
52
- //#endregion
53
5
  //#region lib/types/index.js
54
6
  /**
55
7
  * JSON-file evolution state provider over the IO seam.
@@ -228,7 +180,7 @@ async function ensureCorruptCopy(ctx, io, root, file, bad, memory) {
228
180
  return wrote;
229
181
  }
230
182
  async function jsonTransact(ctx, io, root, file, task, options) {
231
- await transactIo(io(), join(root, file), async (current) => {
183
+ await new WriteKernel({ io: io() }).run({ path: join(root, file) }, async (current) => {
232
184
  let parsed = null;
233
185
  if (current !== null) {
234
186
  try {
@@ -752,7 +704,6 @@ function apply(ctx, rawConfig = {}) {
752
704
  }
753
705
  };
754
706
  ctx.effect(() => ctx.evolutionStateStorage.registerProvider(provider), "evolution-state-json.provider");
755
- ctx.provide("evolutionStateStore", new JsonStateStore(io(), root));
756
707
  }
757
708
  //#endregion
758
- export { Config, JsonStateStore, apply, inject, jsonTransact, name, newQuarantineMemory };
709
+ export { Config, apply, inject, jsonTransact, name, newQuarantineMemory };
@@ -15,9 +15,10 @@ export interface Config {
15
15
  }
16
16
  export declare const Config: z<Config>;
17
17
  /**
18
- * Cross-process JSON-file RMW (v3-audit M-8): every read-modify-write state
19
- * mutation runs inside the IO backend's transact lock (via transactIo) so a
20
- * second process sharing DSH_HOME cannot interleave its claim/resolve.
18
+ * In-process JSON-file RMW (v3-audit M-8): every read-modify-write state
19
+ * mutation runs inside the IO backend's transact lock (via transactIo). The
20
+ * shipped backend is single-process; a second process sharing DSH_HOME is not
21
+ * coordinated and must not be assumed safe.
21
22
  * `task` returns the next value; null = ENSURE-ABSENT (the file is deleted
22
23
  * when it exists — the parity of the transact seam, V6-32). For a record-map
23
24
  * file the return must be null or a plain object map of records, and an
@@ -57,5 +58,4 @@ export declare function jsonTransact<T>(ctx: Context, io: () => EvolutionIoLike,
57
58
  memory: QuarantineMemory;
58
59
  }): Promise<void>;
59
60
  export declare function apply(ctx: Context, rawConfig?: Config): void;
60
- export { JsonStateStore } from './state-store.ts';
61
61
  //# sourceMappingURL=index.d.ts.map
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.32.3",
4
+ "version": "0.32.4",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -27,18 +27,17 @@
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "@deepseek-ai/schemastery": "^3.18.5",
30
- "@lmzhen/dsh-evolution-contract": "^0.32.3",
31
- "@lmzhen/dsh-evolution-core": "^0.32.3"
30
+ "@lmzhen/dsh-evolution-core": "^0.32.4"
32
31
  },
33
32
  "peerDependencies": {
34
33
  "@deepseek-ai/cordis": "^4.0.5",
35
- "@lmzhen/dsh-evolution-io": "^0.32.3",
36
- "@lmzhen/dsh-evolution-state-storage": "^0.32.3"
34
+ "@lmzhen/dsh-evolution-io": "^0.32.4",
35
+ "@lmzhen/dsh-evolution-state-storage": "^0.32.4"
37
36
  },
38
37
  "devDependencies": {
39
- "@lmzhen/dsh-evolution-io": "^0.32.3",
40
- "@lmzhen/dsh-evolution-state-storage": "^0.32.3",
41
- "@lmzhen/dsh-evolution-io-node": "^0.32.3"
38
+ "@lmzhen/dsh-evolution-io": "^0.32.4",
39
+ "@lmzhen/dsh-evolution-state-storage": "^0.32.4",
40
+ "@lmzhen/dsh-evolution-io-node": "^0.32.4"
42
41
  },
43
42
  "engines": {
44
43
  "dsh": ">=0.2.1-rc.2 <0.2.2-0"
@@ -1,23 +0,0 @@
1
- /**
2
- * Generic JSON-file implementation of the contract StateStore.
3
- *
4
- * One file per collection; records use a key map. `transact` delegates to the
5
- * IO seam's transact, so the medium's serialization/CAS behavior is preserved.
6
- * The node backend is process-local, so capabilities.crossProcess is false.
7
- */
8
- import type { EvolutionCollection, EvolutionStateCapabilities, EvolutionStateStore } from '@lmzhen/dsh-evolution-contract';
9
- import { type EvolutionIoLike } from '@lmzhen/dsh-evolution-core';
10
- export declare class JsonStateStore implements EvolutionStateStore {
11
- readonly name = "json-state-store";
12
- readonly capabilities: EvolutionStateCapabilities;
13
- private readonly io;
14
- private readonly root;
15
- private readonly serial;
16
- constructor(io: EvolutionIoLike, root: string);
17
- private path;
18
- private load;
19
- read<T>(collection: EvolutionCollection, key: string): Promise<T | undefined>;
20
- transact<T>(collection: EvolutionCollection, key: string, fn: (current: T | undefined) => Promise<T>): Promise<T>;
21
- list<T>(collection: EvolutionCollection): Promise<T[]>;
22
- }
23
- //# sourceMappingURL=state-store.d.ts.map