@ontrails/store 1.0.0-beta.15 → 1.0.0-beta.17
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/CHANGELOG.md +43 -0
- package/README.md +31 -15
- package/package.json +11 -3
- package/src/{internal/signal-identity.ts → adapter-support.ts} +15 -14
- package/src/crud-doctrine.ts +43 -0
- package/src/index.ts +6 -1
- package/src/jsonfile/runtime.ts +3 -5
- package/src/jsonfile/types.ts +2 -2
- package/src/store.ts +5 -6
- package/src/testing.ts +2 -2
- package/src/trails/crud.ts +4 -3
- package/src/trails/index.ts +5 -0
- package/src/trails/reconcile.ts +2 -2
- package/src/trails/utils.ts +1 -1
- package/src/types.ts +27 -26
- package/.agents/notes/2026-04-04/handoff-202604032309-9e85a104.md +0 -38
- package/.turbo/turbo-build.log +0 -1
- package/.turbo/turbo-lint.log +0 -3
- package/.turbo/turbo-typecheck.log +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
- package/dist/internal/signal-identity.d.ts +0 -17
- package/dist/internal/signal-identity.d.ts.map +0 -1
- package/dist/internal/signal-identity.js +0 -81
- package/dist/internal/signal-identity.js.map +0 -1
- package/dist/jsonfile/index.d.ts +0 -3
- package/dist/jsonfile/index.d.ts.map +0 -1
- package/dist/jsonfile/index.js +0 -2
- package/dist/jsonfile/index.js.map +0 -1
- package/dist/jsonfile/runtime.d.ts +0 -19
- package/dist/jsonfile/runtime.d.ts.map +0 -1
- package/dist/jsonfile/runtime.js +0 -403
- package/dist/jsonfile/runtime.js.map +0 -1
- package/dist/jsonfile/types.d.ts +0 -40
- package/dist/jsonfile/types.d.ts.map +0 -1
- package/dist/jsonfile/types.js +0 -2
- package/dist/jsonfile/types.js.map +0 -1
- package/dist/store.d.ts +0 -16
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -250
- package/dist/store.js.map +0 -1
- package/dist/testing.d.ts +0 -28
- package/dist/testing.d.ts.map +0 -1
- package/dist/testing.js +0 -90
- package/dist/testing.js.map +0 -1
- package/dist/trails/crud.d.ts +0 -38
- package/dist/trails/crud.d.ts.map +0 -1
- package/dist/trails/crud.js +0 -112
- package/dist/trails/crud.js.map +0 -1
- package/dist/trails/index.d.ts +0 -7
- package/dist/trails/index.d.ts.map +0 -1
- package/dist/trails/index.js +0 -4
- package/dist/trails/index.js.map +0 -1
- package/dist/trails/reconcile.d.ts +0 -36
- package/dist/trails/reconcile.d.ts.map +0 -1
- package/dist/trails/reconcile.js +0 -142
- package/dist/trails/reconcile.js.map +0 -1
- package/dist/trails/sync.d.ts +0 -25
- package/dist/trails/sync.d.ts.map +0 -1
- package/dist/trails/sync.js +0 -96
- package/dist/trails/sync.js.map +0 -1
- package/dist/trails/utils.d.ts +0 -51
- package/dist/trails/utils.d.ts.map +0 -1
- package/dist/trails/utils.js +0 -65
- package/dist/trails/utils.js.map +0 -1
- package/dist/types.d.ts +0 -394
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/src/__tests__/crud.test.ts +0 -346
- package/src/__tests__/jsonfile.test.ts +0 -502
- package/src/__tests__/store.test.ts +0 -539
- package/src/__tests__/sync-reconcile.test.ts +0 -646
- package/tsconfig.json +0 -9
- package/tsconfig.tests.json +0 -10
- package/tsconfig.tsbuildinfo +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# @ontrails/store
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.17
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [3dc8254]
|
|
8
|
+
- @ontrails/core@1.0.0-beta.17
|
|
9
|
+
|
|
10
|
+
## 1.0.0-beta.16
|
|
11
|
+
|
|
12
|
+
### Major Changes
|
|
13
|
+
|
|
14
|
+
- 3395234: Move store adapter-binding helpers to `@ontrails/store/adapter-support` and topographer direct database/admin helpers to `@ontrails/topographer/backend-support`, keeping root exports focused on contract-level APIs.
|
|
15
|
+
- 6300f70: BREAKING: rename the shared store backend option type from `StoreConnectorOptions` to `StoreAdapterOptions`.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- e898cc4: Add repo-level Knip dead-code detection and remove stale internal exports and unused package dependencies surfaced by the new check.
|
|
20
|
+
- 49c2e7d: Refresh published package README taxonomy to use adapter language instead of retired connector vocabulary.
|
|
21
|
+
- df9a7d0: Add project-aware public export-map governance for @ontrails workspace docs,
|
|
22
|
+
imports, root barrels, and bin-only package surfaces.
|
|
23
|
+
- Updated dependencies [73622ae]
|
|
24
|
+
- Updated dependencies [6300f70]
|
|
25
|
+
- Updated dependencies [d172013]
|
|
26
|
+
- Updated dependencies [c3fc5c3]
|
|
27
|
+
- Updated dependencies [20d7a5c]
|
|
28
|
+
- Updated dependencies [be5fb46]
|
|
29
|
+
- Updated dependencies [e898cc4]
|
|
30
|
+
- Updated dependencies [3395234]
|
|
31
|
+
- Updated dependencies [bcdc484]
|
|
32
|
+
- Updated dependencies [331e3a9]
|
|
33
|
+
- Updated dependencies [4399fdb]
|
|
34
|
+
- Updated dependencies [4b8d13b]
|
|
35
|
+
- Updated dependencies [112b9f2]
|
|
36
|
+
- Updated dependencies [893025e]
|
|
37
|
+
- Updated dependencies [eec5e9d]
|
|
38
|
+
- Updated dependencies [ebd4434]
|
|
39
|
+
- Updated dependencies [863d473]
|
|
40
|
+
- Updated dependencies [344f2f7]
|
|
41
|
+
- Updated dependencies [26f9ffd]
|
|
42
|
+
- Updated dependencies [10eae9a]
|
|
43
|
+
- Updated dependencies [22c6c06]
|
|
44
|
+
- @ontrails/core@1.0.0-beta.16
|
|
45
|
+
|
|
3
46
|
## 1.0.0-beta.15
|
|
4
47
|
|
|
5
48
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Schema-derived persistence for Trails.
|
|
4
4
|
|
|
5
|
-
The root package owns the
|
|
5
|
+
The root package owns the backend-agnostic `store(...)` declaration. External adapter packages such as `@ontrails/drizzle` bind that declaration to a concrete runtime, and first-party built-ins such as `@ontrails/store/jsonfile` live as opt-in subpaths on the same package.
|
|
6
6
|
|
|
7
7
|
## The two layers
|
|
8
8
|
|
|
@@ -100,7 +100,7 @@ export const db = jsonFile(definition, {
|
|
|
100
100
|
|
|
101
101
|
## Typed accessors
|
|
102
102
|
|
|
103
|
-
Every writable table on a bound connection exposes the
|
|
103
|
+
Every writable table on a bound connection exposes the backend-agnostic accessor contract:
|
|
104
104
|
|
|
105
105
|
```typescript
|
|
106
106
|
const conn = db.from(ctx);
|
|
@@ -135,7 +135,7 @@ const updatedHandle = definition.tables.gists.signals.updated;
|
|
|
135
135
|
const removedHandle = definition.tables.gists.signals.removed;
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
These pre-bind handles preserve payload shape, but the canonical signal id materializes only when
|
|
138
|
+
These pre-bind handles preserve payload shape, but the canonical signal id materializes only when an adapter binds the store to a resource. The bound form is always `resource:table.change`:
|
|
139
139
|
|
|
140
140
|
```typescript
|
|
141
141
|
const created = db.store.tables.gists.signals.created;
|
|
@@ -144,9 +144,24 @@ created.id;
|
|
|
144
144
|
// "db.main:gists.created"
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
+
## Adapter Support Subpath
|
|
148
|
+
|
|
149
|
+
Adapter authors who bind a `store(...)` definition to a concrete backend should
|
|
150
|
+
import signal-binding helpers from `@ontrails/store/adapter-support`:
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { bindStoreDefinition } from '@ontrails/store/adapter-support';
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The subpath owns `bindStoreDefinition`, `createStoreTableSignals`,
|
|
157
|
+
`composeStoreSignalId`, `isValidResourceId`, and `StoreSignalChange`. The root
|
|
158
|
+
package stays focused on backend-agnostic store contracts.
|
|
159
|
+
|
|
147
160
|
Writable bindings fire those canonical scoped signals automatically when you access the resource through `db.from(ctx)` inside a trail context.
|
|
148
161
|
|
|
149
|
-
|
|
162
|
+
See [Store Signal Identity Migration](../../docs/store-signal-identity-migration.md) when updating existing `on:` clauses, surface-map fixtures, or custom resource wrappers from bare ids to scoped ids.
|
|
163
|
+
|
|
164
|
+
Tabular adapters such as `@ontrails/drizzle` also expose `insert()` and `update()` as convenience methods when the backend natively distinguishes create and patch operations.
|
|
150
165
|
|
|
151
166
|
## Fixtures and mocks
|
|
152
167
|
|
|
@@ -165,13 +180,13 @@ export const db = store({
|
|
|
165
180
|
});
|
|
166
181
|
```
|
|
167
182
|
|
|
168
|
-
When
|
|
183
|
+
When an adapter binds the store, those fixtures feed the resource mock automatically. Adapter options can also add or override seed data for tests.
|
|
169
184
|
|
|
170
|
-
That means `testAll(app)` can auto-resolve
|
|
185
|
+
That means `testAll(app)` can auto-resolve adapter-bound store resources without extra ceremony, as long as the resource is registered in the topo.
|
|
171
186
|
|
|
172
187
|
## Read-only bindings
|
|
173
188
|
|
|
174
|
-
Use the Drizzle
|
|
189
|
+
Use the Drizzle adapter's read-only binding when a trail should inspect persisted state without exposing writes:
|
|
175
190
|
|
|
176
191
|
```typescript
|
|
177
192
|
import { connectReadOnlyDrizzle } from '@ontrails/drizzle';
|
|
@@ -186,17 +201,17 @@ Read-only bindings expose `get()`, `list()`, and `query()`, but not `upsert()`,
|
|
|
186
201
|
|
|
187
202
|
## Accessor contract testing
|
|
188
203
|
|
|
189
|
-
|
|
204
|
+
Adapters can reuse the shared writable-accessor contract tests from `@ontrails/store/testing`:
|
|
190
205
|
|
|
191
206
|
```typescript
|
|
192
207
|
import { createStoreAccessorContractCases } from '@ontrails/store/testing';
|
|
193
208
|
```
|
|
194
209
|
|
|
195
|
-
That helper provides reusable cases for the baseline `get()`, `list()`, `upsert()`, and `remove()` behavior so
|
|
210
|
+
That helper provides reusable cases for the baseline `get()`, `list()`, `upsert()`, and `remove()` behavior so adapter suites only need to wrap them with their normal `test(...)` calls and add backend-specific coverage on top.
|
|
196
211
|
|
|
197
212
|
## Drizzle escape hatch
|
|
198
213
|
|
|
199
|
-
Complex queries use the
|
|
214
|
+
Complex queries use the adapter-native query builder through `query()`:
|
|
200
215
|
|
|
201
216
|
```typescript
|
|
202
217
|
const conn = db.from(ctx);
|
|
@@ -208,9 +223,9 @@ const rows = await conn.query(({ drizzle, tables }) =>
|
|
|
208
223
|
);
|
|
209
224
|
```
|
|
210
225
|
|
|
211
|
-
This keeps the default happy path derived and typed, while still giving you full access to the underlying
|
|
226
|
+
This keeps the default happy path derived and typed, while still giving you full access to the underlying adapter when the CRUD accessors are not enough.
|
|
212
227
|
|
|
213
|
-
##
|
|
228
|
+
## Adapter binding
|
|
214
229
|
|
|
215
230
|
`@ontrails/drizzle` keeps the durable `store(...)` declaration in
|
|
216
231
|
`@ontrails/store` and binds it to a concrete runtime:
|
|
@@ -234,7 +249,7 @@ export const readonly = connectReadOnlyDrizzle(definition, {
|
|
|
234
249
|
});
|
|
235
250
|
```
|
|
236
251
|
|
|
237
|
-
The root package still owns the authored persistence model;
|
|
252
|
+
The root package still owns the authored persistence model; adapter packages
|
|
238
253
|
project that model into runnable resources.
|
|
239
254
|
|
|
240
255
|
## Schema export for external tooling
|
|
@@ -264,7 +279,7 @@ const schema = db.tables;
|
|
|
264
279
|
bun add @ontrails/store zod
|
|
265
280
|
```
|
|
266
281
|
|
|
267
|
-
Add Drizzle only when you want the external SQLite/ORM
|
|
282
|
+
Add Drizzle only when you want the external SQLite/ORM adapter:
|
|
268
283
|
|
|
269
284
|
```bash
|
|
270
285
|
bun add @ontrails/drizzle
|
|
@@ -274,5 +289,6 @@ bun add @ontrails/drizzle
|
|
|
274
289
|
|
|
275
290
|
The Drizzle binding now lives in `@ontrails/drizzle`.
|
|
276
291
|
|
|
292
|
+
<!-- warden-ignore-next-line -->
|
|
277
293
|
- Replace `import { ... } from '@ontrails/store/drizzle'` with `import { ... } from '@ontrails/drizzle'`
|
|
278
|
-
- Keep
|
|
294
|
+
- Keep backend-agnostic store declarations on `@ontrails/store`
|
package/package.json
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ontrails/store",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.17",
|
|
4
|
+
"files": [
|
|
5
|
+
"src/**/*.ts",
|
|
6
|
+
"!src/**/__tests__/**",
|
|
7
|
+
"!src/**/*.test.ts",
|
|
8
|
+
"!src/**/*.test-d.ts",
|
|
9
|
+
"README.md",
|
|
10
|
+
"CHANGELOG.md"
|
|
11
|
+
],
|
|
4
12
|
"type": "module",
|
|
5
13
|
"exports": {
|
|
6
14
|
".": "./src/index.ts",
|
|
7
|
-
"./
|
|
15
|
+
"./adapter-support": "./src/adapter-support.ts",
|
|
8
16
|
"./jsonfile": "./src/jsonfile/index.ts",
|
|
9
17
|
"./trails": "./src/trails/index.ts",
|
|
10
18
|
"./testing": "./src/testing.ts",
|
|
@@ -18,7 +26,7 @@
|
|
|
18
26
|
"clean": "rm -rf dist *.tsbuildinfo"
|
|
19
27
|
},
|
|
20
28
|
"dependencies": {
|
|
21
|
-
"@ontrails/core": "^1.0.0-beta.
|
|
29
|
+
"@ontrails/core": "^1.0.0-beta.16"
|
|
22
30
|
},
|
|
23
31
|
"peerDependencies": {
|
|
24
32
|
"zod": "^4.3.5"
|
|
@@ -1,28 +1,29 @@
|
|
|
1
|
-
import { signal, ValidationError } from '@ontrails/core';
|
|
2
|
-
import type { Signal } from '@ontrails/core';
|
|
3
1
|
import {
|
|
4
2
|
attachLateBoundSignalRef,
|
|
5
3
|
cloneSignalWithId,
|
|
6
|
-
|
|
4
|
+
signal,
|
|
5
|
+
ValidationError,
|
|
6
|
+
} from '@ontrails/core';
|
|
7
|
+
import type { Signal } from '@ontrails/core';
|
|
7
8
|
import type { z } from 'zod';
|
|
8
9
|
|
|
9
10
|
import type {
|
|
10
11
|
AnyStoreDefinition,
|
|
11
12
|
AnyStoreTable,
|
|
12
13
|
StoreTableSignals,
|
|
13
|
-
} from '
|
|
14
|
+
} from './types.js';
|
|
14
15
|
|
|
15
16
|
type MutableTables<TStore extends AnyStoreDefinition> = {
|
|
16
17
|
-readonly [TName in keyof TStore['tables']]: TStore['tables'][TName];
|
|
17
18
|
};
|
|
18
19
|
|
|
19
|
-
type
|
|
20
|
+
type StoreSignalChange = 'created' | 'removed' | 'updated';
|
|
20
21
|
|
|
21
22
|
const createStoreSignalDescription = (
|
|
22
23
|
tableName: string,
|
|
23
|
-
|
|
24
|
+
change: StoreSignalChange
|
|
24
25
|
): string => {
|
|
25
|
-
switch (
|
|
26
|
+
switch (change) {
|
|
26
27
|
case 'created': {
|
|
27
28
|
return `Fired after a "${tableName}" entity is created.`;
|
|
28
29
|
}
|
|
@@ -33,19 +34,19 @@ const createStoreSignalDescription = (
|
|
|
33
34
|
return `Fired after a "${tableName}" entity is updated.`;
|
|
34
35
|
}
|
|
35
36
|
default: {
|
|
36
|
-
throw new Error(`Unsupported store signal
|
|
37
|
+
throw new Error(`Unsupported store signal change: ${change as string}`);
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
const createStoreSignal = <TPayload>(
|
|
42
43
|
tableName: string,
|
|
43
|
-
|
|
44
|
+
change: StoreSignalChange,
|
|
44
45
|
payload: z.ZodType<TPayload>
|
|
45
46
|
): Signal<TPayload> =>
|
|
46
47
|
attachLateBoundSignalRef(
|
|
47
|
-
signal(`${tableName}.${
|
|
48
|
-
description: createStoreSignalDescription(tableName,
|
|
48
|
+
signal(`${tableName}.${change}`, {
|
|
49
|
+
description: createStoreSignalDescription(tableName, change),
|
|
49
50
|
payload,
|
|
50
51
|
}),
|
|
51
52
|
{
|
|
@@ -67,8 +68,8 @@ export const createStoreTableSignals = <TPayload>(
|
|
|
67
68
|
export const composeStoreSignalId = (
|
|
68
69
|
scope: string,
|
|
69
70
|
tableName: string,
|
|
70
|
-
|
|
71
|
-
): string => `${scope}:${tableName}.${
|
|
71
|
+
change: StoreSignalChange
|
|
72
|
+
): string => `${scope}:${tableName}.${change}`;
|
|
72
73
|
|
|
73
74
|
const bindTableSignals = (
|
|
74
75
|
scope: string,
|
|
@@ -159,4 +160,4 @@ export const bindStoreDefinition = <TStore extends AnyStoreDefinition>(
|
|
|
159
160
|
}) as TStore;
|
|
160
161
|
};
|
|
161
162
|
|
|
162
|
-
export type {
|
|
163
|
+
export type { StoreSignalChange };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export const crudOperations = [
|
|
2
|
+
'create',
|
|
3
|
+
'read',
|
|
4
|
+
'update',
|
|
5
|
+
'delete',
|
|
6
|
+
'list',
|
|
7
|
+
] as const;
|
|
8
|
+
|
|
9
|
+
export type CrudOperation = (typeof crudOperations)[number];
|
|
10
|
+
|
|
11
|
+
export interface CrudAccessorExpectation {
|
|
12
|
+
readonly fallback?: string | undefined;
|
|
13
|
+
readonly preferred: string;
|
|
14
|
+
readonly severityWhenNoFallback: 'error';
|
|
15
|
+
readonly severityWhenPreferredMissingWithFallback?: 'warn' | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const crudAccessorExpectations = {
|
|
19
|
+
create: {
|
|
20
|
+
fallback: 'upsert',
|
|
21
|
+
preferred: 'insert',
|
|
22
|
+
severityWhenNoFallback: 'error',
|
|
23
|
+
severityWhenPreferredMissingWithFallback: 'warn',
|
|
24
|
+
},
|
|
25
|
+
delete: {
|
|
26
|
+
preferred: 'remove',
|
|
27
|
+
severityWhenNoFallback: 'error',
|
|
28
|
+
},
|
|
29
|
+
list: {
|
|
30
|
+
preferred: 'list',
|
|
31
|
+
severityWhenNoFallback: 'error',
|
|
32
|
+
},
|
|
33
|
+
read: {
|
|
34
|
+
preferred: 'get',
|
|
35
|
+
severityWhenNoFallback: 'error',
|
|
36
|
+
},
|
|
37
|
+
update: {
|
|
38
|
+
fallback: 'upsert',
|
|
39
|
+
preferred: 'update',
|
|
40
|
+
severityWhenNoFallback: 'error',
|
|
41
|
+
severityWhenPreferredMissingWithFallback: 'warn',
|
|
42
|
+
},
|
|
43
|
+
} as const satisfies Record<CrudOperation, CrudAccessorExpectation>;
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export { crudAccessorExpectations, crudOperations } from './crud-doctrine.js';
|
|
2
|
+
export type {
|
|
3
|
+
CrudAccessorExpectation,
|
|
4
|
+
CrudOperation,
|
|
5
|
+
} from './crud-doctrine.js';
|
|
1
6
|
export { store, versionFieldName } from './store.js';
|
|
2
7
|
export type {
|
|
3
8
|
AnyStoreDefinition,
|
|
@@ -20,7 +25,7 @@ export type {
|
|
|
20
25
|
ReferencesOfInput,
|
|
21
26
|
StoreAccessMode,
|
|
22
27
|
StoreConnection,
|
|
23
|
-
|
|
28
|
+
StoreAdapterOptions,
|
|
24
29
|
StoreDefinition,
|
|
25
30
|
StoreFieldKey,
|
|
26
31
|
StoreFixtureInput,
|
package/src/jsonfile/runtime.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
StoreListOptions,
|
|
11
11
|
UpsertOf,
|
|
12
12
|
} from '../types.js';
|
|
13
|
-
import { bindStoreDefinition } from '../
|
|
13
|
+
import { bindStoreDefinition } from '../adapter-support.js';
|
|
14
14
|
import { versionFieldName } from '../store.js';
|
|
15
15
|
|
|
16
16
|
import type {
|
|
@@ -448,7 +448,7 @@ const executeRemove = async <TTable extends AnyStoreTable>(
|
|
|
448
448
|
|
|
449
449
|
// Module-level registry: ensures all connections to the same file share one
|
|
450
450
|
// in-memory table instance. Keyed by resolved file path.
|
|
451
|
-
// Note: entries are never evicted. This is acceptable for v1 — the
|
|
451
|
+
// Note: entries are never evicted. This is acceptable for v1 — the adapter
|
|
452
452
|
// targets single-process, short-lived servers where the number of distinct
|
|
453
453
|
// table paths is bounded by the store definition.
|
|
454
454
|
interface JsonFileTableRegistration<TTable extends AnyStoreTable> {
|
|
@@ -522,7 +522,7 @@ const buildAndRegisterTable = <TTable extends AnyStoreTable>(
|
|
|
522
522
|
* @remarks
|
|
523
523
|
* Tables are shared per resolved file path so multiple connections stay
|
|
524
524
|
* coherent in-process. Reuse is only allowed when table-affecting config
|
|
525
|
-
* matches exactly; otherwise the
|
|
525
|
+
* matches exactly; otherwise the adapter throws instead of silently
|
|
526
526
|
* inheriting the first connection's runtime semantics.
|
|
527
527
|
*/
|
|
528
528
|
const createJsonFileTable = <TTable extends AnyStoreTable>(
|
|
@@ -698,5 +698,3 @@ export const jsonFile = <TStore extends AnyStoreDefinition>(
|
|
|
698
698
|
signals: store.signals,
|
|
699
699
|
});
|
|
700
700
|
};
|
|
701
|
-
|
|
702
|
-
export { jsonFile as store };
|
package/src/jsonfile/types.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
AnyStoreDefinition,
|
|
4
4
|
AnyStoreTable,
|
|
5
5
|
StoreAccessor,
|
|
6
|
-
|
|
6
|
+
StoreAdapterOptions,
|
|
7
7
|
} from '../types.js';
|
|
8
8
|
|
|
9
9
|
/** Connection shape: one StoreAccessor per table name. */
|
|
@@ -13,7 +13,7 @@ export type JsonFileConnection<TStore extends Record<string, AnyStoreTable>> =
|
|
|
13
13
|
/** Options for creating a jsonfile store. */
|
|
14
14
|
export interface JsonFileStoreOptions<
|
|
15
15
|
TStore extends AnyStoreDefinition = AnyStoreDefinition,
|
|
16
|
-
> extends
|
|
16
|
+
> extends StoreAdapterOptions<TStore> {
|
|
17
17
|
/** Directory where JSON files are written. One `<tableName>.json` per table. */
|
|
18
18
|
readonly dir: string;
|
|
19
19
|
/**
|
package/src/store.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { ValidationError } from '@ontrails/core';
|
|
1
|
+
import { stripDefaultsFromShape, ValidationError } from '@ontrails/core';
|
|
2
2
|
import type { AnySignal } from '@ontrails/core';
|
|
3
|
-
import { stripDefaultsFromShape } from '@ontrails/core/internal/zod-wrappers';
|
|
4
3
|
import { z } from 'zod';
|
|
5
4
|
|
|
6
|
-
import { createStoreTableSignals } from './
|
|
5
|
+
import { createStoreTableSignals } from './adapter-support.js';
|
|
7
6
|
import type {
|
|
8
7
|
StoreDefinition,
|
|
9
8
|
StoreKind,
|
|
@@ -19,7 +18,7 @@ const isStoreObjectSchema = (schema: z.ZodType): schema is StoreObjectSchema =>
|
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
20
|
* Name of the framework-managed version column used by versioned tables for
|
|
22
|
-
* optimistic concurrency control. Exported so
|
|
21
|
+
* optimistic concurrency control. Exported so adapters can gate their own
|
|
23
22
|
* version-handling logic without duplicating the literal.
|
|
24
23
|
*/
|
|
25
24
|
export const versionFieldName = 'version';
|
|
@@ -499,10 +498,10 @@ const collectStoreSignals = <const TTables extends StoreTablesInput>(
|
|
|
499
498
|
);
|
|
500
499
|
|
|
501
500
|
/**
|
|
502
|
-
* Declare a
|
|
501
|
+
* Declare a backend-agnostic store definition from entity schemas and
|
|
503
502
|
* persistence metadata.
|
|
504
503
|
*
|
|
505
|
-
* The returned value is a normalized, read-only contract that
|
|
504
|
+
* The returned value is a normalized, read-only contract that adapters can
|
|
506
505
|
* bind to a concrete runtime later.
|
|
507
506
|
*/
|
|
508
507
|
export const store = <const TTables extends StoreTablesInput>(
|
package/src/testing.ts
CHANGED
|
@@ -84,9 +84,9 @@ const seedExistingEntity = async <TTable extends AnyStoreTable>(
|
|
|
84
84
|
};
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
|
-
* Shared contract cases for
|
|
87
|
+
* Shared contract cases for backend-agnostic writable store accessors.
|
|
88
88
|
*
|
|
89
|
-
*
|
|
89
|
+
* Adapters can register these with their own `test(...)` wrappers so the
|
|
90
90
|
* baseline `get/list/upsert/remove` contract stays aligned across runtimes
|
|
91
91
|
* without fighting repository-specific test-lint rules.
|
|
92
92
|
*/
|
package/src/trails/crud.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
StoreIdentifierOf,
|
|
16
16
|
UpdateOf,
|
|
17
17
|
} from '../types.js';
|
|
18
|
+
import type { CrudOperation } from '../crud-doctrine.js';
|
|
18
19
|
import { createTableContour } from './utils.js';
|
|
19
20
|
import type { TableContour } from './utils.js';
|
|
20
21
|
|
|
@@ -44,7 +45,7 @@ type GeneratedFieldsOf<TTable extends AnyStoreTable> =
|
|
|
44
45
|
*/
|
|
45
46
|
type DerivedInput<
|
|
46
47
|
TTable extends AnyStoreTable,
|
|
47
|
-
TOperation extends
|
|
48
|
+
TOperation extends CrudOperation,
|
|
48
49
|
> = DeriveTrailInput<
|
|
49
50
|
TableContour<TTable>,
|
|
50
51
|
TOperation,
|
|
@@ -57,7 +58,7 @@ type DerivedInput<
|
|
|
57
58
|
*/
|
|
58
59
|
type DerivedOutput<
|
|
59
60
|
TTable extends AnyStoreTable,
|
|
60
|
-
TOperation extends
|
|
61
|
+
TOperation extends CrudOperation,
|
|
61
62
|
> = DeriveTrailOutput<TableContour<TTable>, TOperation>;
|
|
62
63
|
|
|
63
64
|
type InternalCreateTrailOf<TTable extends AnyStoreTable> = Trail<
|
|
@@ -318,7 +319,7 @@ const buildCrudTrails = <TTable extends AnyStoreTable>(
|
|
|
318
319
|
* Produce the standard CRUD trail tuple for one normalized store table.
|
|
319
320
|
*
|
|
320
321
|
* The factory derives schemas, examples, resources, and contour linkage from
|
|
321
|
-
* the table metadata. Blazes default to the
|
|
322
|
+
* the table metadata. Blazes default to the backend-agnostic store accessor
|
|
322
323
|
* contract via `deriveTrail()`'s single-resource synthesis path. Per-operation
|
|
323
324
|
* blaze overrides stay available for callers that need custom persistence
|
|
324
325
|
* behavior and are layered onto the derived trails in a single pass.
|
package/src/trails/index.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export { crudAccessorExpectations, crudOperations } from '../crud-doctrine.js';
|
|
2
|
+
export type {
|
|
3
|
+
CrudAccessorExpectation,
|
|
4
|
+
CrudOperation,
|
|
5
|
+
} from '../crud-doctrine.js';
|
|
1
6
|
export { crud } from './crud.js';
|
|
2
7
|
export type { CrudBlazeOverrides, CrudOptions, CrudTrails } from './crud.js';
|
|
3
8
|
export { reconcile } from './reconcile.js';
|
package/src/trails/reconcile.ts
CHANGED
|
@@ -164,7 +164,7 @@ const recoverConflict = async <TTable extends AnyStoreTable>(
|
|
|
164
164
|
* Build the input schema for a reconcile trail.
|
|
165
165
|
*
|
|
166
166
|
* `fixtureSchema` makes generated fields (including `version` on versioned
|
|
167
|
-
* tables) optional because
|
|
167
|
+
* tables) optional because adapters populate them. Reconcile, however,
|
|
168
168
|
* relies on optimistic concurrency: the caller must pass the expected
|
|
169
169
|
* `version` so `assertExpectedVersionMatch` can detect stale payloads. We
|
|
170
170
|
* therefore extend `fixtureSchema` with a required `version` field so
|
|
@@ -244,7 +244,7 @@ const createReconcileDetour = <
|
|
|
244
244
|
* For versioned tables, the derived input schema requires an explicit
|
|
245
245
|
* `version` field so callers cannot sidestep optimistic concurrency at the
|
|
246
246
|
* input boundary. `fixtureSchema` alone makes `version` optional because
|
|
247
|
-
*
|
|
247
|
+
* adapters populate it for writes; reconcile must reject that relaxed
|
|
248
248
|
* shape.
|
|
249
249
|
*/
|
|
250
250
|
export const reconcile = <
|
package/src/trails/utils.ts
CHANGED
|
@@ -23,7 +23,7 @@ export type TableContour<TTable extends AnyStoreTable> = Contour<
|
|
|
23
23
|
* Contour validates every example against the shape passed in, so the shape
|
|
24
24
|
* must match how fixtures are actually shaped. Store fixtures may omit
|
|
25
25
|
* framework-generated fields (`createdAt`, `version`, ...) because the
|
|
26
|
-
*
|
|
26
|
+
* adapter populates them, so we mirror `fixtureSchema`'s treatment of
|
|
27
27
|
* generated fields: generated, non-identity fields are made optional; the
|
|
28
28
|
* identity field stays required because read/delete/update all derive their
|
|
29
29
|
* input from it. Previously reconcile.ts and sync.ts passed
|