@nwire/store-file 0.7.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alex Gefter / 200apps Ltd.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # @nwire/store-file
2
+
3
+ > File-snapshot `ActorStore` + `ProjectionStore` — survives process restart, no DB.
4
+
5
+ ## What it does
6
+
7
+ Persists actor state and projection rows to a single JSON file. Writes are debounced (50 ms) to coalesce bursts; tenant-partitioned. Not a production database — `@nwire/store-mongo` (or future `-postgres`, `-dynamodb`) for prod. Useful for dev/CI without infrastructure.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pnpm add @nwire/store-file
13
+ ```
14
+
15
+ ## Quick start
16
+
17
+ ```ts
18
+ import { FileSnapshotStore, FileSnapshotProjectionView } from "@nwire/store-file";
19
+ import { createApp } from "@nwire/forge";
20
+
21
+ const store = new FileSnapshotStore("./data/snapshot.json");
22
+ const projView = new FileSnapshotProjectionView(store);
23
+
24
+ const app = createApp("learnflow", {
25
+ modules,
26
+ actorStore: store,
27
+ projectionStore: projView,
28
+ });
29
+ ```
30
+
31
+ ## API surface
32
+
33
+ - `FileSnapshotStore(path)` — implements `ActorStore`.
34
+ - `FileSnapshotProjectionView(store)` — implements `ProjectionStore` against the same snapshot.
35
+
36
+ ## When to use
37
+
38
+ Dev environments without a database, CI pipelines that need persistence across test phases, tiny single-node apps. Fits L2/L3.
39
+
40
+ ## Standalone use
41
+
42
+ For developers using `@nwire/store-file` **without the rest of Nwire** — pair it with any TypeScript project, any container, any HTTP framework.
43
+
44
+ ```ts
45
+ // See the package's main entry (src/) for the standalone surface.
46
+ // The exports below work without @nwire/app or @nwire/forge.
47
+ import {} from /* ...standalone exports... */ "@nwire/store-file";
48
+ ```
49
+
50
+ ## Within nwire-app
51
+
52
+ For developers using this package as part of the Nwire stack — register it via `app.use(...)` or it auto-wires when you compose `createApp({ modules })`.
53
+
54
+ ```ts
55
+ import { createApp } from "@nwire/forge";
56
+
57
+ const app = createApp({
58
+ /* ...config... */
59
+ });
60
+ // Adapter/plugin wiring happens here when applicable.
61
+ ```
62
+
63
+ ## See also
64
+
65
+ - [Architecture sketch §05 — Adapters tier](../../architecture-sketch.html#packages)
66
+ - Sibling packages: [@nwire/store-mongo](../nwire-store-mongo)
@@ -0,0 +1,6 @@
1
+ /**
2
+ * File-snapshot store — persists actor + projection state to disk; survives
3
+ * a "process restart" (re-instantiating the store from the same path).
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=store-file.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-file.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/store-file.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * File-snapshot store — persists actor + projection state to disk; survives
3
+ * a "process restart" (re-instantiating the store from the same path).
4
+ */
5
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
6
+ import { z } from "zod";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+ import { mkdtemp, rm } from "node:fs/promises";
10
+ import { defineEvent } from "@nwire/messages";
11
+ import * as forge from "@nwire/forge";
12
+ import { FileSnapshotStore, FileSnapshotProjectionView } from "../store-file";
13
+ const { defineAction, defineActor, defineHandler, defineProjection, eventFactory, Runtime } = forge;
14
+ const TodoCreatedEventDef = defineEvent({
15
+ name: "todos.created",
16
+ schema: z.object({ todoId: z.string(), title: z.string() }),
17
+ });
18
+ const TodoCreated = eventFactory(TodoCreatedEventDef);
19
+ const TodoActorData = z.object({
20
+ todoId: z.string(),
21
+ title: z.string().optional(),
22
+ });
23
+ const Todo = defineActor("todo", {
24
+ schema: TodoActorData,
25
+ key: "todoId",
26
+ initial: "open",
27
+ states: {
28
+ open: {
29
+ on: {
30
+ [TodoCreated.name]: {
31
+ assign: (_, event) => {
32
+ const e = event;
33
+ return { todoId: e.todoId, title: e.title };
34
+ },
35
+ },
36
+ },
37
+ },
38
+ },
39
+ });
40
+ const TodosByOwner = defineProjection("todos-by-owner", {
41
+ listens: [TodoCreatedEventDef],
42
+ initial: () => ({}),
43
+ on: {
44
+ [TodoCreatedEventDef.name]: (state, event) => {
45
+ const e = event;
46
+ return { ...state, [e.todoId]: { todoId: e.todoId, title: e.title } };
47
+ },
48
+ },
49
+ });
50
+ const createTodo = defineAction({
51
+ name: "todos.create",
52
+ schema: z.object({ todoId: z.string(), title: z.string() }),
53
+ });
54
+ const createTodoHandler = defineHandler(createTodo, async (input) => TodoCreated({ todoId: input.todoId, title: input.title }));
55
+ describe("FileSnapshotStore — actor + projection state survives restart", () => {
56
+ let tmpDir;
57
+ let snapshotPath;
58
+ beforeEach(async () => {
59
+ tmpDir = await mkdtemp(join(tmpdir(), "amit-snapshot-"));
60
+ snapshotPath = join(tmpDir, "snapshot.json");
61
+ });
62
+ afterEach(async () => {
63
+ await rm(tmpDir, { recursive: true, force: true });
64
+ });
65
+ it("saves and reloads actor + projection state from the snapshot file", async () => {
66
+ const store1 = new FileSnapshotStore(snapshotPath);
67
+ const projView1 = new FileSnapshotProjectionView(store1);
68
+ const r1 = new Runtime({ actorStore: store1, projectionStore: projView1 });
69
+ r1.registerActor(Todo);
70
+ r1.registerHandler(createTodoHandler);
71
+ r1.registerProjection(TodosByOwner);
72
+ await r1.dispatch(createTodo, { todoId: "t-1", title: "Buy milk" });
73
+ await r1.dispatch(createTodo, { todoId: "t-2", title: "Walk dog" });
74
+ await store1.flush();
75
+ // "Restart" — fresh store + runtime against the same file.
76
+ const store2 = new FileSnapshotStore(snapshotPath);
77
+ const projView2 = new FileSnapshotProjectionView(store2);
78
+ const r2 = new Runtime({ actorStore: store2, projectionStore: projView2 });
79
+ r2.registerActor(Todo);
80
+ r2.registerProjection(TodosByOwner);
81
+ const t1 = await store2.load("todo", "t-1");
82
+ const t2 = await store2.load("todo", "t-2");
83
+ expect(t1).not.toBeNull();
84
+ expect(t2).not.toBeNull();
85
+ expect((t1?.data).title).toBe("Buy milk");
86
+ expect((t2?.data).title).toBe("Walk dog");
87
+ const proj = await projView2.load("todos-by-owner");
88
+ expect(proj).not.toBeNull();
89
+ expect(proj?.["t-1"]?.title).toBe("Buy milk");
90
+ expect(proj?.["t-2"]?.title).toBe("Walk dog");
91
+ });
92
+ it("preserves tenant partitioning across restart", async () => {
93
+ const store = new FileSnapshotStore(snapshotPath);
94
+ const proj = new FileSnapshotProjectionView(store);
95
+ const r = new Runtime({ actorStore: store, projectionStore: proj });
96
+ r.registerActor(Todo);
97
+ r.registerHandler(createTodoHandler);
98
+ const { seedEnvelope } = await import("@nwire/forge");
99
+ await r.dispatch(createTodo, { todoId: "t-1", title: "A" }, seedEnvelope({ tenant: "tlv" }));
100
+ await r.dispatch(createTodo, { todoId: "t-1", title: "B" }, seedEnvelope({ tenant: "jlm" }));
101
+ await store.flush();
102
+ const store2 = new FileSnapshotStore(snapshotPath);
103
+ const a = await store2.load("todo", "t-1", "tlv");
104
+ const b = await store2.load("todo", "t-1", "jlm");
105
+ expect((a?.data).title).toBe("A");
106
+ expect((b?.data).title).toBe("B");
107
+ });
108
+ });
109
+ //# sourceMappingURL=store-file.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-file.test.js","sourceRoot":"","sources":["../../src/__tests__/store-file.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * File-snapshot stores — persist actor + projection state to a JSON file on
3
+ * disk. Demonstrates the swappable-store contract; survives a process restart;
4
+ * not intended as a production database.
5
+ *
6
+ * Writes are debounced: every save schedules a flush 50ms in the future,
7
+ * coalescing bursts (e.g. inside a single dispatch's actor + projection + DLQ
8
+ * writes). `flush()` waits for any pending write to complete — call it before
9
+ * shutdown or before reading the file externally.
10
+ *
11
+ * For production: write `MongoActorStore` / `MongoProjectionStore` against
12
+ * the same `ActorStore` / `ProjectionStore` interfaces. Same shape; just
13
+ * different storage primitives.
14
+ */
15
+ import type * as forge from "@nwire/forge";
16
+ type ActorStore = forge.ActorStore;
17
+ type ActorInstance = forge.ActorInstance;
18
+ type ProjectionStore = forge.ProjectionStore;
19
+ /**
20
+ * File-backed actor store. Pair with `FileSnapshotProjectionView` (below)
21
+ * to share the same JSON file for projections — both stores use the same
22
+ * underlying `state` field via the view's wrapper.
23
+ */
24
+ export declare class FileSnapshotStore implements ActorStore {
25
+ private readonly path;
26
+ private state;
27
+ private loaded;
28
+ private pendingWrite;
29
+ private writePromise;
30
+ constructor(path: string);
31
+ private actorCacheKey;
32
+ private projectionCacheKey;
33
+ private ensureLoaded;
34
+ private scheduleFlush;
35
+ private persistNow;
36
+ /**
37
+ * Wait for any pending debounced write, then force a final write. Call
38
+ * before shutdown or before reading the file externally.
39
+ */
40
+ flush(): Promise<void>;
41
+ load(actorName: string, key: string, tenant?: string): Promise<ActorInstance | null>;
42
+ save(instance: ActorInstance): Promise<void>;
43
+ exists(actorName: string, key: string, tenant?: string): Promise<boolean>;
44
+ listInstances(actorName: string, tenant?: string): Promise<readonly ActorInstance[]>;
45
+ loadProjection<TState = unknown>(projectionName: string, tenant?: string): Promise<TState | null>;
46
+ saveProjection<TState = unknown>(projectionName: string, state: TState, tenant?: string): Promise<void>;
47
+ }
48
+ /**
49
+ * Adapter: `FileSnapshotStore` exposes both interfaces but `ProjectionStore`
50
+ * wants `load`/`save` (not the prefixed names that would clash with `ActorStore`).
51
+ * This thin wrapper presents the projection face.
52
+ */
53
+ export declare class FileSnapshotProjectionView implements ProjectionStore {
54
+ private readonly store;
55
+ constructor(store: FileSnapshotStore);
56
+ load<TState = unknown>(name: string, tenant?: string): Promise<TState | null>;
57
+ save<TState = unknown>(name: string, state: TState, tenant?: string): Promise<void>;
58
+ }
59
+ export {};
60
+ //# sourceMappingURL=file-snapshot-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-snapshot-store.d.ts","sourceRoot":"","sources":["../src/file-snapshot-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AAE3C,KAAK,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;AACnC,KAAK,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;AAEzC,KAAK,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC;AAU7C;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,UAAU;IAClD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,YAAY,CAAoC;gBAE5C,IAAI,EAAE,MAAM;IAIxB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,kBAAkB;YAIZ,YAAY;IAe1B,OAAO,CAAC,aAAa;YAWP,UAAU;IAMxB;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAWtB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAMxF,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB5C,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAK7E,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC;IAapF,cAAc,CAAC,MAAM,GAAG,OAAO,EACnC,cAAc,EAAE,MAAM,EACtB,MAAM,GAAE,MAAW,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAOnB,cAAc,CAAC,MAAM,GAAG,OAAO,EACnC,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,MAAW,GAClB,OAAO,CAAC,IAAI,CAAC;CAWjB;AAED;;;;GAIG;AACH,qBAAa,0BAA2B,YAAW,eAAe;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,iBAAiB;IAErD,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAG7E,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGpF"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * File-snapshot stores — persist actor + projection state to a JSON file on
3
+ * disk. Demonstrates the swappable-store contract; survives a process restart;
4
+ * not intended as a production database.
5
+ *
6
+ * Writes are debounced: every save schedules a flush 50ms in the future,
7
+ * coalescing bursts (e.g. inside a single dispatch's actor + projection + DLQ
8
+ * writes). `flush()` waits for any pending write to complete — call it before
9
+ * shutdown or before reading the file externally.
10
+ *
11
+ * For production: write `MongoActorStore` / `MongoProjectionStore` against
12
+ * the same `ActorStore` / `ProjectionStore` interfaces. Same shape; just
13
+ * different storage primitives.
14
+ */
15
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
16
+ import { dirname } from "node:path";
17
+ const EMPTY = { version: 1, actors: {}, projections: {} };
18
+ /**
19
+ * File-backed actor store. Pair with `FileSnapshotProjectionView` (below)
20
+ * to share the same JSON file for projections — both stores use the same
21
+ * underlying `state` field via the view's wrapper.
22
+ */
23
+ export class FileSnapshotStore {
24
+ path;
25
+ state = EMPTY;
26
+ loaded = false;
27
+ pendingWrite = null;
28
+ writePromise = Promise.resolve();
29
+ constructor(path) {
30
+ this.path = path;
31
+ }
32
+ actorCacheKey(name, key, tenant) {
33
+ return `${tenant}::${name}::${key}`;
34
+ }
35
+ projectionCacheKey(name, tenant) {
36
+ return `${tenant}::${name}`;
37
+ }
38
+ async ensureLoaded() {
39
+ if (this.loaded)
40
+ return;
41
+ try {
42
+ const raw = await readFile(this.path, "utf8");
43
+ const parsed = JSON.parse(raw);
44
+ if (parsed?.version === 1) {
45
+ this.state = parsed;
46
+ }
47
+ }
48
+ catch (err) {
49
+ // Missing or corrupt file → start empty.
50
+ void err;
51
+ }
52
+ this.loaded = true;
53
+ }
54
+ scheduleFlush() {
55
+ if (this.pendingWrite)
56
+ return;
57
+ this.pendingWrite = setTimeout(() => {
58
+ this.pendingWrite = null;
59
+ this.writePromise = this.writePromise.then(() => this.persistNow());
60
+ }, 50);
61
+ if (typeof this.pendingWrite.unref === "function") {
62
+ this.pendingWrite.unref();
63
+ }
64
+ }
65
+ async persistNow() {
66
+ await mkdir(dirname(this.path), { recursive: true }).catch(() => undefined);
67
+ const serialized = JSON.stringify(this.state);
68
+ await writeFile(this.path, serialized, "utf8");
69
+ }
70
+ /**
71
+ * Wait for any pending debounced write, then force a final write. Call
72
+ * before shutdown or before reading the file externally.
73
+ */
74
+ async flush() {
75
+ if (this.pendingWrite) {
76
+ clearTimeout(this.pendingWrite);
77
+ this.pendingWrite = null;
78
+ }
79
+ await this.writePromise;
80
+ await this.persistNow();
81
+ }
82
+ // ─── ActorStore ──────────────────────────────────────────────────
83
+ async load(actorName, key, tenant = "") {
84
+ await this.ensureLoaded();
85
+ const stored = this.state.actors[this.actorCacheKey(actorName, key, tenant)];
86
+ return stored ? structuredClone(stored) : null;
87
+ }
88
+ async save(instance) {
89
+ await this.ensureLoaded();
90
+ const cloned = {
91
+ actorName: instance.actorName,
92
+ key: instance.key,
93
+ tenant: instance.tenant,
94
+ state: instance.state,
95
+ data: structuredClone(instance.data),
96
+ activeTimers: structuredClone(instance.activeTimers),
97
+ };
98
+ this.state = {
99
+ ...this.state,
100
+ actors: {
101
+ ...this.state.actors,
102
+ [this.actorCacheKey(instance.actorName, instance.key, instance.tenant)]: cloned,
103
+ },
104
+ };
105
+ this.scheduleFlush();
106
+ }
107
+ async exists(actorName, key, tenant = "") {
108
+ await this.ensureLoaded();
109
+ return Boolean(this.state.actors[this.actorCacheKey(actorName, key, tenant)]);
110
+ }
111
+ async listInstances(actorName, tenant) {
112
+ await this.ensureLoaded();
113
+ const result = [];
114
+ for (const value of Object.values(this.state.actors)) {
115
+ if (value.actorName !== actorName)
116
+ continue;
117
+ if (tenant !== undefined && value.tenant !== tenant)
118
+ continue;
119
+ result.push(structuredClone(value));
120
+ }
121
+ return result;
122
+ }
123
+ // ─── ProjectionStore ─────────────────────────────────────────────
124
+ async loadProjection(projectionName, tenant = "") {
125
+ await this.ensureLoaded();
126
+ const k = this.projectionCacheKey(projectionName, tenant);
127
+ if (!(k in this.state.projections))
128
+ return null;
129
+ return structuredClone(this.state.projections[k]);
130
+ }
131
+ async saveProjection(projectionName, state, tenant = "") {
132
+ await this.ensureLoaded();
133
+ this.state = {
134
+ ...this.state,
135
+ projections: {
136
+ ...this.state.projections,
137
+ [this.projectionCacheKey(projectionName, tenant)]: structuredClone(state),
138
+ },
139
+ };
140
+ this.scheduleFlush();
141
+ }
142
+ }
143
+ /**
144
+ * Adapter: `FileSnapshotStore` exposes both interfaces but `ProjectionStore`
145
+ * wants `load`/`save` (not the prefixed names that would clash with `ActorStore`).
146
+ * This thin wrapper presents the projection face.
147
+ */
148
+ export class FileSnapshotProjectionView {
149
+ store;
150
+ constructor(store) {
151
+ this.store = store;
152
+ }
153
+ load(name, tenant) {
154
+ return this.store.loadProjection(name, tenant);
155
+ }
156
+ save(name, state, tenant) {
157
+ return this.store.saveProjection(name, state, tenant);
158
+ }
159
+ }
160
+ //# sourceMappingURL=file-snapshot-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-snapshot-store.js","sourceRoot":"","sources":["../src/file-snapshot-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `@nwire/store-file` — file-snapshot ActorStore + ProjectionStore.
3
+ *
4
+ * import { FileSnapshotStore, FileSnapshotProjectionView } from '@nwire/store-file'
5
+ *
6
+ * const store = new FileSnapshotStore('./data/snapshot.json')
7
+ * const projView = new FileSnapshotProjectionView(store)
8
+ *
9
+ * const app = createApp({ modules, actorStore: store, projectionStore: projView })
10
+ *
11
+ * Writes are debounced (50ms) to coalesce bursts; survives process restart;
12
+ * tenant-partitioned. Not a production database — `@nwire/store-mongo` (or
13
+ * `-postgres`, `-dynamodb`) for prod. Useful for dev/CI without infrastructure.
14
+ */
15
+ export { FileSnapshotStore, FileSnapshotProjectionView } from "./file-snapshot-store";
16
+ //# sourceMappingURL=store-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-file.d.ts","sourceRoot":"","sources":["../src/store-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `@nwire/store-file` — file-snapshot ActorStore + ProjectionStore.
3
+ *
4
+ * import { FileSnapshotStore, FileSnapshotProjectionView } from '@nwire/store-file'
5
+ *
6
+ * const store = new FileSnapshotStore('./data/snapshot.json')
7
+ * const projView = new FileSnapshotProjectionView(store)
8
+ *
9
+ * const app = createApp({ modules, actorStore: store, projectionStore: projView })
10
+ *
11
+ * Writes are debounced (50ms) to coalesce bursts; survives process restart;
12
+ * tenant-partitioned. Not a production database — `@nwire/store-mongo` (or
13
+ * `-postgres`, `-dynamodb`) for prod. Useful for dev/CI without infrastructure.
14
+ */
15
+ export { FileSnapshotStore, FileSnapshotProjectionView } from "./file-snapshot-store";
16
+ //# sourceMappingURL=store-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-file.js","sourceRoot":"","sources":["../src/store-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@nwire/store-file",
3
+ "version": "0.7.0",
4
+ "description": "Nwire — file-snapshot ActorStore + ProjectionStore. JSON snapshot persisted to disk with debounced writes. Survives process restart; tenant-partitioned. Dev/CI use, not production.",
5
+ "keywords": [
6
+ "actor-store",
7
+ "adapter",
8
+ "file",
9
+ "nwire",
10
+ "projection-store",
11
+ "snapshot",
12
+ "store"
13
+ ],
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "type": "module",
19
+ "main": "./dist/store-file.js",
20
+ "types": "./dist/store-file.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "import": "./dist/store-file.js",
24
+ "types": "./dist/store-file.d.ts"
25
+ }
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "dependencies": {
31
+ "@nwire/forge": "0.7.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^22.19.9",
35
+ "typescript": "^5.9.3",
36
+ "vitest": "^4.0.18",
37
+ "zod": "^4.0.0",
38
+ "@nwire/messages": "0.7.0"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc",
42
+ "dev": "tsc --watch",
43
+ "typecheck": "tsc --noEmit"
44
+ }
45
+ }