@shardworks/stacks-apparatus 0.1.101

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.
Files changed (74) hide show
  1. package/LICENSE +15 -0
  2. package/dist/backend.d.ts +83 -0
  3. package/dist/backend.d.ts.map +1 -0
  4. package/dist/backend.js +11 -0
  5. package/dist/backend.js.map +1 -0
  6. package/dist/cdc.d.ts +63 -0
  7. package/dist/cdc.d.ts.map +1 -0
  8. package/dist/cdc.js +154 -0
  9. package/dist/cdc.js.map +1 -0
  10. package/dist/conformance/helpers.d.ts +56 -0
  11. package/dist/conformance/helpers.d.ts.map +1 -0
  12. package/dist/conformance/helpers.js +91 -0
  13. package/dist/conformance/helpers.js.map +1 -0
  14. package/dist/conformance/suite.d.ts +10 -0
  15. package/dist/conformance/suite.d.ts.map +1 -0
  16. package/dist/conformance/suite.js +22 -0
  17. package/dist/conformance/suite.js.map +1 -0
  18. package/dist/conformance/testable-stacks.d.ts +11 -0
  19. package/dist/conformance/testable-stacks.d.ts.map +1 -0
  20. package/dist/conformance/testable-stacks.js +13 -0
  21. package/dist/conformance/testable-stacks.js.map +1 -0
  22. package/dist/conformance/tier1-data-integrity.d.ts +8 -0
  23. package/dist/conformance/tier1-data-integrity.d.ts.map +1 -0
  24. package/dist/conformance/tier1-data-integrity.js +93 -0
  25. package/dist/conformance/tier1-data-integrity.js.map +1 -0
  26. package/dist/conformance/tier2-cdc.d.ts +8 -0
  27. package/dist/conformance/tier2-cdc.d.ts.map +1 -0
  28. package/dist/conformance/tier2-cdc.js +393 -0
  29. package/dist/conformance/tier2-cdc.js.map +1 -0
  30. package/dist/conformance/tier2.5-transactions.d.ts +6 -0
  31. package/dist/conformance/tier2.5-transactions.d.ts.map +1 -0
  32. package/dist/conformance/tier2.5-transactions.js +117 -0
  33. package/dist/conformance/tier2.5-transactions.js.map +1 -0
  34. package/dist/conformance/tier3-queries.d.ts +6 -0
  35. package/dist/conformance/tier3-queries.d.ts.map +1 -0
  36. package/dist/conformance/tier3-queries.js +338 -0
  37. package/dist/conformance/tier3-queries.js.map +1 -0
  38. package/dist/conformance/tier4-edge-cases.d.ts +6 -0
  39. package/dist/conformance/tier4-edge-cases.d.ts.map +1 -0
  40. package/dist/conformance/tier4-edge-cases.js +190 -0
  41. package/dist/conformance/tier4-edge-cases.js.map +1 -0
  42. package/dist/field-utils.d.ts +36 -0
  43. package/dist/field-utils.d.ts.map +1 -0
  44. package/dist/field-utils.js +61 -0
  45. package/dist/field-utils.js.map +1 -0
  46. package/dist/index.d.ts +14 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +14 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/memory-backend.d.ts +16 -0
  51. package/dist/memory-backend.d.ts.map +1 -0
  52. package/dist/memory-backend.js +186 -0
  53. package/dist/memory-backend.js.map +1 -0
  54. package/dist/query.d.ts +20 -0
  55. package/dist/query.d.ts.map +1 -0
  56. package/dist/query.js +69 -0
  57. package/dist/query.js.map +1 -0
  58. package/dist/sqlite-backend.d.ts +21 -0
  59. package/dist/sqlite-backend.d.ts.map +1 -0
  60. package/dist/sqlite-backend.js +265 -0
  61. package/dist/sqlite-backend.js.map +1 -0
  62. package/dist/stacks-core.d.ts +51 -0
  63. package/dist/stacks-core.d.ts.map +1 -0
  64. package/dist/stacks-core.js +357 -0
  65. package/dist/stacks-core.js.map +1 -0
  66. package/dist/stacks.d.ts +13 -0
  67. package/dist/stacks.d.ts.map +1 -0
  68. package/dist/stacks.js +77 -0
  69. package/dist/stacks.js.map +1 -0
  70. package/dist/types.d.ts +131 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +10 -0
  73. package/dist/types.js.map +1 -0
  74. package/package.json +38 -0
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 Sean Boots
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,83 @@
1
+ /**
2
+ * StacksBackend — persistence abstraction for The Stacks.
3
+ *
4
+ * All SQLite-specific types stay behind this interface. The apparatus
5
+ * and all consuming plugins depend only on these types. Backend
6
+ * implementations (SQLite, in-memory) implement this interface.
7
+ *
8
+ * See: docs/specification.md §8
9
+ */
10
+ import type { BookEntry, BookSchema, Scalar } from './types.ts';
11
+ export interface BookRef {
12
+ ownerId: string;
13
+ book: string;
14
+ }
15
+ export interface BackendOptions {
16
+ home: string;
17
+ }
18
+ export interface PutResult {
19
+ created: boolean;
20
+ prev?: BookEntry;
21
+ }
22
+ export interface PatchResult {
23
+ entry: BookEntry;
24
+ prev: BookEntry;
25
+ }
26
+ export interface DeleteResult {
27
+ found: boolean;
28
+ prev?: BookEntry;
29
+ }
30
+ export type InternalCondition = {
31
+ field: string;
32
+ op: 'eq' | 'neq';
33
+ value: Scalar;
34
+ } | {
35
+ field: string;
36
+ op: 'gt' | 'gte' | 'lt' | 'lte';
37
+ value: number | string;
38
+ } | {
39
+ field: string;
40
+ op: 'like';
41
+ value: string;
42
+ } | {
43
+ field: string;
44
+ op: 'in';
45
+ values: Scalar[];
46
+ } | {
47
+ field: string;
48
+ op: 'isNull' | 'isNotNull';
49
+ };
50
+ export interface InternalQuery {
51
+ where?: InternalCondition[];
52
+ orderBy?: Array<{
53
+ field: string;
54
+ dir: 'asc' | 'desc';
55
+ }>;
56
+ limit?: number;
57
+ offset?: number;
58
+ }
59
+ /** Narrowed query type for count() — conditions only, no pagination. */
60
+ export interface CountQuery {
61
+ where?: InternalCondition[];
62
+ }
63
+ export interface BackendTransaction {
64
+ put(ref: BookRef, entry: BookEntry, opts?: {
65
+ withPrev: boolean;
66
+ }): PutResult;
67
+ patch(ref: BookRef, id: string, fields: Record<string, unknown>): PatchResult;
68
+ delete(ref: BookRef, id: string, opts?: {
69
+ withPrev: boolean;
70
+ }): DeleteResult;
71
+ get(ref: BookRef, id: string): BookEntry | null;
72
+ find(ref: BookRef, query: InternalQuery): BookEntry[];
73
+ count(ref: BookRef, query: CountQuery): number;
74
+ commit(): void;
75
+ rollback(): void;
76
+ }
77
+ export interface StacksBackend {
78
+ open(options: BackendOptions): void;
79
+ close(): void;
80
+ ensureBook(ref: BookRef, schema: BookSchema): void;
81
+ beginTransaction(): BackendTransaction;
82
+ }
83
+ //# sourceMappingURL=backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * StacksBackend — persistence abstraction for The Stacks.
3
+ *
4
+ * All SQLite-specific types stay behind this interface. The apparatus
5
+ * and all consuming plugins depend only on these types. Backend
6
+ * implementations (SQLite, in-memory) implement this interface.
7
+ *
8
+ * See: docs/specification.md §8
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
package/dist/cdc.d.ts ADDED
@@ -0,0 +1,63 @@
1
+ /**
2
+ * CDC registry — handler registration, event buffering, and coalescing.
3
+ *
4
+ * Two-phase execution model:
5
+ * - Phase 1 (failOnError: true): runs INSIDE the transaction
6
+ * - Phase 2 (failOnError: false): runs AFTER commit with coalesced events
7
+ *
8
+ * See: docs/specification.md (stacks § CDC)
9
+ */
10
+ import type { BookEntry, ChangeEvent, ChangeHandler, WatchOptions } from './types.ts';
11
+ interface WatcherEntry {
12
+ handler: ChangeHandler;
13
+ failOnError: boolean;
14
+ }
15
+ export interface BufferedEvent {
16
+ ref: string;
17
+ ownerId: string;
18
+ book: string;
19
+ docId: string;
20
+ type: 'create' | 'update' | 'delete';
21
+ entry?: BookEntry;
22
+ prev?: BookEntry;
23
+ }
24
+ /**
25
+ * Coalesce buffered events per-document.
26
+ *
27
+ * Rules:
28
+ * create → create (final state)
29
+ * create → update(s) → create (final state)
30
+ * create → delete → (no event)
31
+ * update(s) → update (first prev, final state)
32
+ * update(s) → delete → delete (first prev)
33
+ * delete → delete (prev)
34
+ */
35
+ export declare function coalesceEvents(buffer: BufferedEvent[]): ChangeEvent<BookEntry>[];
36
+ export declare class CdcRegistry {
37
+ private readonly watchers;
38
+ private locked;
39
+ /**
40
+ * Register a CDC handler for a book.
41
+ * Must be called before any writes (enforced by `locked` flag).
42
+ */
43
+ watch(ownerId: string, bookName: string, handler: ChangeHandler, options?: WatchOptions): void;
44
+ /** Mark the registry as locked — called on first write. */
45
+ lock(): void;
46
+ /** Check if any handlers are registered for a book (controls pre-read). */
47
+ hasWatchers(ownerId: string, bookName: string): boolean;
48
+ /** Get Phase 1 handlers (failOnError: true) for a book. */
49
+ getPhase1Handlers(ownerId: string, bookName: string): WatcherEntry[];
50
+ /** Get Phase 2 handlers (failOnError: false) for a book. */
51
+ getPhase2Handlers(ownerId: string, bookName: string): WatcherEntry[];
52
+ /**
53
+ * Fire Phase 1 handlers for a single event. Throws on handler error
54
+ * (caller is responsible for rolling back the transaction).
55
+ */
56
+ firePhase1(ownerId: string, bookName: string, event: ChangeEvent<BookEntry>): Promise<void>;
57
+ /**
58
+ * Fire Phase 2 handlers for coalesced events. Errors are logged, not thrown.
59
+ */
60
+ firePhase2(events: ChangeEvent<BookEntry>[]): Promise<void>;
61
+ }
62
+ export {};
63
+ //# sourceMappingURL=cdc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdc.d.ts","sourceRoot":"","sources":["../src/cdc.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAItF,UAAU,YAAY;IACpB,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;CACtB;AAID,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACrC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAkBD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,EAAE,CA8DhF;AAID,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,OAAO,CAAC,MAAM,CAAS;IAEvB;;;OAGG;IACH,KAAK,CACH,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,YAAY,GACrB,IAAI;IAoBP,2DAA2D;IAC3D,IAAI,IAAI,IAAI;IAIZ,2EAA2E;IAC3E,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAMvD,2DAA2D;IAC3D,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE;IAKpE,4DAA4D;IAC5D,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE;IAKpE;;;OAGG;IACG,UAAU,CACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,GAC5B,OAAO,CAAC,IAAI,CAAC;IAMhB;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAelE"}
package/dist/cdc.js ADDED
@@ -0,0 +1,154 @@
1
+ /**
2
+ * CDC registry — handler registration, event buffering, and coalescing.
3
+ *
4
+ * Two-phase execution model:
5
+ * - Phase 1 (failOnError: true): runs INSIDE the transaction
6
+ * - Phase 2 (failOnError: false): runs AFTER commit with coalesced events
7
+ *
8
+ * See: docs/specification.md (stacks § CDC)
9
+ */
10
+ /**
11
+ * Coalesce buffered events per-document.
12
+ *
13
+ * Rules:
14
+ * create → create (final state)
15
+ * create → update(s) → create (final state)
16
+ * create → delete → (no event)
17
+ * update(s) → update (first prev, final state)
18
+ * update(s) → delete → delete (first prev)
19
+ * delete → delete (prev)
20
+ */
21
+ export function coalesceEvents(buffer) {
22
+ const states = new Map();
23
+ for (const event of buffer) {
24
+ const key = `${event.ref}:${event.docId}`;
25
+ const existing = states.get(key);
26
+ if (!existing) {
27
+ states.set(key, {
28
+ ownerId: event.ownerId,
29
+ book: event.book,
30
+ docId: event.docId,
31
+ firstType: event.type,
32
+ lastType: event.type,
33
+ prev: event.prev,
34
+ entry: event.entry,
35
+ });
36
+ }
37
+ else {
38
+ existing.lastType = event.type;
39
+ if (event.entry)
40
+ existing.entry = event.entry;
41
+ // prev stays as the first event's prev (pre-transaction state)
42
+ }
43
+ }
44
+ const events = [];
45
+ for (const state of states.values()) {
46
+ if (state.firstType === 'create' && state.lastType === 'delete') {
47
+ // create → delete: no event (document never existed from observer's perspective)
48
+ continue;
49
+ }
50
+ if (state.firstType === 'create') {
51
+ // create (possibly followed by updates): coalesces to create with final state
52
+ events.push({
53
+ type: 'create',
54
+ ownerId: state.ownerId,
55
+ book: state.book,
56
+ entry: state.entry,
57
+ });
58
+ }
59
+ else if (state.lastType === 'delete') {
60
+ // update(s) → delete: coalesces to delete with original prev
61
+ events.push({
62
+ type: 'delete',
63
+ ownerId: state.ownerId,
64
+ book: state.book,
65
+ id: state.docId,
66
+ prev: state.prev,
67
+ });
68
+ }
69
+ else {
70
+ // update(s): coalesces to single update with first prev, final entry
71
+ events.push({
72
+ type: 'update',
73
+ ownerId: state.ownerId,
74
+ book: state.book,
75
+ entry: state.entry,
76
+ prev: state.prev,
77
+ });
78
+ }
79
+ }
80
+ return events;
81
+ }
82
+ // ── CDC Registry ──────────────────────────────────────────────────────
83
+ export class CdcRegistry {
84
+ watchers = new Map();
85
+ locked = false;
86
+ /**
87
+ * Register a CDC handler for a book.
88
+ * Must be called before any writes (enforced by `locked` flag).
89
+ */
90
+ watch(ownerId, bookName, handler, options) {
91
+ if (this.locked) {
92
+ throw new Error(`[stacks] watch() called after writes have started. ` +
93
+ `Handlers must be registered during apparatus startup.`);
94
+ }
95
+ const key = `${ownerId}/${bookName}`;
96
+ let entries = this.watchers.get(key);
97
+ if (!entries) {
98
+ entries = [];
99
+ this.watchers.set(key, entries);
100
+ }
101
+ entries.push({
102
+ handler,
103
+ failOnError: options?.failOnError ?? true,
104
+ });
105
+ }
106
+ /** Mark the registry as locked — called on first write. */
107
+ lock() {
108
+ this.locked = true;
109
+ }
110
+ /** Check if any handlers are registered for a book (controls pre-read). */
111
+ hasWatchers(ownerId, bookName) {
112
+ const key = `${ownerId}/${bookName}`;
113
+ const entries = this.watchers.get(key);
114
+ return entries !== undefined && entries.length > 0;
115
+ }
116
+ /** Get Phase 1 handlers (failOnError: true) for a book. */
117
+ getPhase1Handlers(ownerId, bookName) {
118
+ const key = `${ownerId}/${bookName}`;
119
+ return (this.watchers.get(key) ?? []).filter((e) => e.failOnError);
120
+ }
121
+ /** Get Phase 2 handlers (failOnError: false) for a book. */
122
+ getPhase2Handlers(ownerId, bookName) {
123
+ const key = `${ownerId}/${bookName}`;
124
+ return (this.watchers.get(key) ?? []).filter((e) => !e.failOnError);
125
+ }
126
+ /**
127
+ * Fire Phase 1 handlers for a single event. Throws on handler error
128
+ * (caller is responsible for rolling back the transaction).
129
+ */
130
+ async firePhase1(ownerId, bookName, event) {
131
+ for (const entry of this.getPhase1Handlers(ownerId, bookName)) {
132
+ await entry.handler(event);
133
+ }
134
+ }
135
+ /**
136
+ * Fire Phase 2 handlers for coalesced events. Errors are logged, not thrown.
137
+ */
138
+ async firePhase2(events) {
139
+ for (const event of events) {
140
+ const key = `${event.ownerId}/${event.book}`;
141
+ const handlers = (this.watchers.get(key) ?? []).filter((e) => !e.failOnError);
142
+ for (const entry of handlers) {
143
+ try {
144
+ await entry.handler(event);
145
+ }
146
+ catch (err) {
147
+ const msg = err instanceof Error ? err.message : String(err);
148
+ console.warn(`[stacks] Phase 2 handler error (${key}): ${msg}`);
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ //# sourceMappingURL=cdc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdc.js","sourceRoot":"","sources":["../src/cdc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Conformance test helpers — create a StacksApi from a bare backend,
3
+ * bypassing the guild startup machinery.
4
+ *
5
+ * Each test gets a fresh backend + API instance. No state leaks.
6
+ */
7
+ import type { StacksBackend, BookRef } from '../backend.ts';
8
+ import type { BookEntry, StacksApi, ChangeEvent, CreateEvent, UpdateEvent, DeleteEvent, WatchOptions } from '../types.ts';
9
+ export interface TestStacks {
10
+ stacks: StacksApi;
11
+ backend: StacksBackend;
12
+ /** Ensure a book exists (bypasses kit contribution flow). */
13
+ ensureBook(ownerId: string, bookName: string, schema?: {
14
+ indexes?: (string | string[])[];
15
+ }): void;
16
+ }
17
+ export declare function createTestStacks(backendFactory: () => StacksBackend): TestStacks;
18
+ export declare function seedDocument(backend: StacksBackend, ref: BookRef, entry: BookEntry): void;
19
+ export declare function collectEvents<T extends BookEntry = BookEntry>(stacks: StacksApi, ownerId: string, bookName: string, options?: WatchOptions): ChangeEvent<T>[];
20
+ export interface PutCall {
21
+ ref: BookRef;
22
+ entry: BookEntry;
23
+ withPrev: boolean;
24
+ }
25
+ /**
26
+ * Wraps a backend factory to record put() calls on transactions,
27
+ * so tests can verify whether withPrev was requested.
28
+ */
29
+ export declare function spyingBackendFactory(factory: () => StacksBackend): {
30
+ factory: () => StacksBackend;
31
+ putCalls: PutCall[];
32
+ };
33
+ /** Assert the event is a `create` and check its fields. */
34
+ export declare function assertCreateEvent(event: ChangeEvent<BookEntry>, expected: {
35
+ entry: BookEntry;
36
+ ownerId?: string;
37
+ book?: string;
38
+ }): asserts event is CreateEvent<BookEntry>;
39
+ /** Assert the event is an `update` and check its fields. */
40
+ export declare function assertUpdateEvent(event: ChangeEvent<BookEntry>, expected: {
41
+ entry: BookEntry;
42
+ prev: BookEntry;
43
+ ownerId?: string;
44
+ book?: string;
45
+ }): asserts event is UpdateEvent<BookEntry>;
46
+ /** Assert the event is a `delete` and check its fields. */
47
+ export declare function assertDeleteEvent(event: ChangeEvent<BookEntry>, expected: {
48
+ id: string;
49
+ prev: BookEntry;
50
+ ownerId?: string;
51
+ book?: string;
52
+ }): asserts event is DeleteEvent<BookEntry>;
53
+ export declare const OWNER = "test-owner";
54
+ export declare const BOOK = "testbook";
55
+ export declare const REF: BookRef;
56
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/conformance/helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EACV,SAAS,EACT,SAAS,EACT,WAAW,EAEX,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACb,MAAM,aAAa,CAAC;AAKrB,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,aAAa,CAAC;IACvB,6DAA6D;IAC7D,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;CACnG;AAED,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,MAAM,aAAa,GAAG,UAAU,CAahF;AAID,wBAAgB,YAAY,CAC1B,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,SAAS,GACf,IAAI,CAIN;AAID,wBAAgB,aAAa,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,EAC3D,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,YAAY,GACrB,WAAW,CAAC,CAAC,CAAC,EAAE,CAMlB;AAID,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,aAAa,GAC3B;IAAE,OAAO,EAAE,MAAM,aAAa,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,CAuBvD;AAID,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,EAC7B,QAAQ,EAAE;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D,OAAO,CAAC,KAAK,IAAI,WAAW,CAAC,SAAS,CAAC,CAKzC;AAED,4DAA4D;AAC5D,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,EAC7B,QAAQ,EAAE;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/E,OAAO,CAAC,KAAK,IAAI,WAAW,CAAC,SAAS,CAAC,CAMzC;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,EAC7B,QAAQ,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACzE,OAAO,CAAC,KAAK,IAAI,WAAW,CAAC,SAAS,CAAC,CAMzC;AAID,eAAO,MAAM,KAAK,eAAe,CAAC;AAClC,eAAO,MAAM,IAAI,aAAa,CAAC;AAC/B,eAAO,MAAM,GAAG,EAAE,OAAwC,CAAC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Conformance test helpers — create a StacksApi from a bare backend,
3
+ * bypassing the guild startup machinery.
4
+ *
5
+ * Each test gets a fresh backend + API instance. No state leaks.
6
+ */
7
+ import assert from 'node:assert/strict';
8
+ import { createTestableStacks } from "./testable-stacks.js";
9
+ export function createTestStacks(backendFactory) {
10
+ const backend = backendFactory();
11
+ backend.open({ home: '/tmp/stacks-test' });
12
+ const stacks = createTestableStacks(backend);
13
+ return {
14
+ stacks,
15
+ backend,
16
+ ensureBook(ownerId, bookName, schema = {}) {
17
+ backend.ensureBook({ ownerId, book: bookName }, schema);
18
+ },
19
+ };
20
+ }
21
+ // ── Seed helper (bypasses CDC lock) ──────────────────────────────────
22
+ export function seedDocument(backend, ref, entry) {
23
+ const tx = backend.beginTransaction();
24
+ tx.put(ref, entry);
25
+ tx.commit();
26
+ }
27
+ // ── Event collector ──────────────────────────────────────────────────
28
+ export function collectEvents(stacks, ownerId, bookName, options) {
29
+ const events = [];
30
+ stacks.watch(ownerId, bookName, ((event) => {
31
+ events.push(event);
32
+ }), options);
33
+ return events;
34
+ }
35
+ /**
36
+ * Wraps a backend factory to record put() calls on transactions,
37
+ * so tests can verify whether withPrev was requested.
38
+ */
39
+ export function spyingBackendFactory(factory) {
40
+ const putCalls = [];
41
+ const wrappedFactory = () => {
42
+ const backend = factory();
43
+ const origBeginTransaction = backend.beginTransaction.bind(backend);
44
+ backend.beginTransaction = () => {
45
+ const tx = origBeginTransaction();
46
+ const origPut = tx.put.bind(tx);
47
+ tx.put = (ref, entry, opts) => {
48
+ putCalls.push({ ref, entry, withPrev: opts?.withPrev ?? false });
49
+ return origPut(ref, entry, opts);
50
+ };
51
+ return tx;
52
+ };
53
+ return backend;
54
+ };
55
+ return { factory: wrappedFactory, putCalls };
56
+ }
57
+ // ── CDC event assertion helpers ──────────────────────────────────────
58
+ /** Assert the event is a `create` and check its fields. */
59
+ export function assertCreateEvent(event, expected) {
60
+ assert.strictEqual(event.type, 'create');
61
+ assert.deepStrictEqual(event.entry, expected.entry);
62
+ if (expected.ownerId !== undefined)
63
+ assert.strictEqual(event.ownerId, expected.ownerId);
64
+ if (expected.book !== undefined)
65
+ assert.strictEqual(event.book, expected.book);
66
+ }
67
+ /** Assert the event is an `update` and check its fields. */
68
+ export function assertUpdateEvent(event, expected) {
69
+ assert.strictEqual(event.type, 'update');
70
+ assert.deepStrictEqual(event.entry, expected.entry);
71
+ assert.deepStrictEqual(event.prev, expected.prev);
72
+ if (expected.ownerId !== undefined)
73
+ assert.strictEqual(event.ownerId, expected.ownerId);
74
+ if (expected.book !== undefined)
75
+ assert.strictEqual(event.book, expected.book);
76
+ }
77
+ /** Assert the event is a `delete` and check its fields. */
78
+ export function assertDeleteEvent(event, expected) {
79
+ assert.strictEqual(event.type, 'delete');
80
+ assert.strictEqual(event.id, expected.id);
81
+ assert.deepStrictEqual(event.prev, expected.prev);
82
+ if (expected.ownerId !== undefined)
83
+ assert.strictEqual(event.ownerId, expected.ownerId);
84
+ if (expected.book !== undefined)
85
+ assert.strictEqual(event.book, expected.book);
86
+ }
87
+ // ── Default book ref ─────────────────────────────────────────────────
88
+ export const OWNER = 'test-owner';
89
+ export const BOOK = 'testbook';
90
+ export const REF = { ownerId: OWNER, book: BOOK };
91
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/conformance/helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Stacks conformance test suite — parametric registration.
3
+ *
4
+ * Exports a single function that registers all conformance tiers
5
+ * against a given backend factory. Each backend test file calls
6
+ * this with its own factory function.
7
+ */
8
+ import type { StacksBackend } from '../backend.ts';
9
+ export declare function runConformanceSuite(suiteName: string, backendFactory: () => StacksBackend): void;
10
+ //# sourceMappingURL=suite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suite.d.ts","sourceRoot":"","sources":["../../src/conformance/suite.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAQnD,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,aAAa,GAClC,IAAI,CAQN"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Stacks conformance test suite — parametric registration.
3
+ *
4
+ * Exports a single function that registers all conformance tiers
5
+ * against a given backend factory. Each backend test file calls
6
+ * this with its own factory function.
7
+ */
8
+ import { tier1DataIntegrity } from "./tier1-data-integrity.js";
9
+ import { tier2Cdc } from "./tier2-cdc.js";
10
+ import { tier25Transactions } from "./tier2.5-transactions.js";
11
+ import { tier3Queries } from "./tier3-queries.js";
12
+ import { tier4EdgeCases } from "./tier4-edge-cases.js";
13
+ export function runConformanceSuite(suiteName, backendFactory) {
14
+ // Node test runner uses the describe/it calls inside each tier function
15
+ // to register tests. The suite name is just for documentation.
16
+ tier1DataIntegrity(backendFactory);
17
+ tier2Cdc(backendFactory);
18
+ tier25Transactions(backendFactory);
19
+ tier3Queries(backendFactory);
20
+ tier4EdgeCases(backendFactory);
21
+ }
22
+ //# sourceMappingURL=suite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suite.js","sourceRoot":"","sources":["../../src/conformance/suite.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,cAAmC;IAEnC,wEAAwE;IACxE,+DAA+D;IAC/D,kBAAkB,CAAC,cAAc,CAAC,CAAC;IACnC,QAAQ,CAAC,cAAc,CAAC,CAAC;IACzB,kBAAkB,CAAC,cAAc,CAAC,CAAC;IACnC,YAAY,CAAC,cAAc,CAAC,CAAC;IAC7B,cAAc,CAAC,cAAc,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Testable Stacks — a minimal StacksApi wired directly to a backend,
3
+ * without requiring the guild startup machinery.
4
+ *
5
+ * Uses the same StacksCore as the production apparatus, ensuring
6
+ * behavioral identity by construction.
7
+ */
8
+ import type { StacksBackend } from '../backend.ts';
9
+ import type { StacksApi } from '../types.ts';
10
+ export declare function createTestableStacks(backend: StacksBackend): StacksApi;
11
+ //# sourceMappingURL=testable-stacks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testable-stacks.d.ts","sourceRoot":"","sources":["../../src/conformance/testable-stacks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,CAGtE"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Testable Stacks — a minimal StacksApi wired directly to a backend,
3
+ * without requiring the guild startup machinery.
4
+ *
5
+ * Uses the same StacksCore as the production apparatus, ensuring
6
+ * behavioral identity by construction.
7
+ */
8
+ import { StacksCore } from "../stacks-core.js";
9
+ export function createTestableStacks(backend) {
10
+ const core = new StacksCore(backend);
11
+ return core.createApi();
12
+ }
13
+ //# sourceMappingURL=testable-stacks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testable-stacks.js","sourceRoot":"","sources":["../../src/conformance/testable-stacks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,UAAU,oBAAoB,CAAC,OAAsB;IACzD,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Tier 1 — Data Integrity conformance tests.
3
+ *
4
+ * Failures here mean data loss or corruption. Non-negotiable.
5
+ */
6
+ import type { StacksBackend } from '../backend.ts';
7
+ export declare function tier1DataIntegrity(backendFactory: () => StacksBackend): void;
8
+ //# sourceMappingURL=tier1-data-integrity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tier1-data-integrity.d.ts","sourceRoot":"","sources":["../../src/conformance/tier1-data-integrity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAInD,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,MAAM,aAAa,GAAG,IAAI,CAmG5E"}