@classytic/repo-core 0.22.0 → 0.23.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/CHANGELOG.md +908 -890
- package/dist/errors/conflict.d.mts +84 -0
- package/dist/errors/conflict.mjs +63 -0
- package/dist/errors/index.d.mts +2 -1
- package/dist/errors/index.mjs +2 -1
- package/dist/lock/index.d.mts +21 -0
- package/dist/lock/index.mjs +10 -3
- package/dist/repository/capabilities.d.mts +44 -2
- package/dist/repository/index.d.mts +4 -2
- package/dist/repository/index.mjs +3 -1
- package/dist/repository/read-only.d.mts +60 -0
- package/dist/repository/read-only.mjs +80 -0
- package/dist/repository/resilience.d.mts +15 -1
- package/dist/repository/resilience.mjs +24 -1
- package/dist/repository/retrying-transaction.d.mts +48 -0
- package/dist/repository/retrying-transaction.mjs +35 -0
- package/dist/repository/types.d.mts +36 -2
- package/dist/testing/conformance.mjs +63 -0
- package/dist/testing/types.d.mts +11 -0
- package/package.json +182 -182
|
@@ -23,6 +23,20 @@ type FilterInput = Filter | Record<string, unknown>;
|
|
|
23
23
|
* the session through uses `unknown`; kits narrow at the boundary.
|
|
24
24
|
*/
|
|
25
25
|
type RepositorySession = unknown;
|
|
26
|
+
/**
|
|
27
|
+
* What a transaction callback receives BESIDE the tx-bound repository.
|
|
28
|
+
*
|
|
29
|
+
* `session` is the raw driver handle, exposed so work that lives OUTSIDE the
|
|
30
|
+
* repository can join the same transaction — the canonical consumer is an
|
|
31
|
+
* outbox writer: `outbox.store(event, { session: uow.session })` commits the
|
|
32
|
+
* event row atomically with the business write. Present when the driver has a
|
|
33
|
+
* per-transaction handle (Mongo's ClientSession); connection-bound backends
|
|
34
|
+
* (SQLite) pass an empty handle — their tx-bound repo IS the only join point.
|
|
35
|
+
* Kits MUST pass a handle object (possibly empty), never omit the argument.
|
|
36
|
+
*/
|
|
37
|
+
interface TransactionHandle {
|
|
38
|
+
session?: RepositorySession;
|
|
39
|
+
}
|
|
26
40
|
/**
|
|
27
41
|
* Read-operation options. The index signature is the escape hatch kits use
|
|
28
42
|
* for driver-specific flags (`populate`, `select`, `readPreference`,
|
|
@@ -72,6 +86,17 @@ interface QueryOptions {
|
|
|
72
86
|
interface WriteOptions extends QueryOptions {
|
|
73
87
|
/** Upsert on update/replace. */
|
|
74
88
|
upsert?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Optimistic-concurrency CAS. When set, the write applies ONLY if the
|
|
91
|
+
* stored version equals `ifVersion`; on mismatch the kit MUST throw
|
|
92
|
+
* `VersionConflictError` (`@classytic/repo-core/errors`) — never return
|
|
93
|
+
* `null`, which means not-found and would invite a blind retry that
|
|
94
|
+
* clobbers the concurrent write. A successful versioned write increments
|
|
95
|
+
* the stored version. Requires the `optimisticConcurrency` capability;
|
|
96
|
+
* kits without it MUST throw on the option rather than ignore it (a
|
|
97
|
+
* silently dropped guard is the defect, not a degraded mode).
|
|
98
|
+
*/
|
|
99
|
+
ifVersion?: number;
|
|
75
100
|
}
|
|
76
101
|
/**
|
|
77
102
|
* Options for the optional `findAll` verb.
|
|
@@ -1502,6 +1527,15 @@ interface StandardRepo<TDoc> extends MinimalRepo<TDoc> {
|
|
|
1502
1527
|
* lives in the kit that knows its driver.
|
|
1503
1528
|
*/
|
|
1504
1529
|
isDuplicateKeyError?(err: unknown): boolean;
|
|
1530
|
+
/**
|
|
1531
|
+
* Classify an error from a transactional write as a TRANSIENT concurrency
|
|
1532
|
+
* conflict — one the backend expects callers to recover from by re-running
|
|
1533
|
+
* the same work (Mongo `TransientTransactionError` label, PG 40001/40P01,
|
|
1534
|
+
* `SQLITE_BUSY`, Prisma P2034). Consumed by `retryingTransaction`; same
|
|
1535
|
+
* ownership rule as `isDuplicateKeyError` — the kit knows its driver.
|
|
1536
|
+
* Absent = nothing retries (`neverTransient`), the safe default.
|
|
1537
|
+
*/
|
|
1538
|
+
isTransientConflictError?(err: unknown): boolean;
|
|
1505
1539
|
/** Find a single doc by compound filter (used by arc's AccessControl). */
|
|
1506
1540
|
getOne?(filter: FilterInput, options?: QueryOptions): Promise<TDoc | null>;
|
|
1507
1541
|
/** Alias many kits expose alongside `getOne`. Arc checks both names. */
|
|
@@ -1810,7 +1844,7 @@ interface StandardRepo<TDoc> extends MinimalRepo<TDoc> {
|
|
|
1810
1844
|
* // Either both writes commit or neither does.
|
|
1811
1845
|
* ```
|
|
1812
1846
|
*/
|
|
1813
|
-
withTransaction?<T>(fn: (txRepo: StandardRepo<TDoc
|
|
1847
|
+
withTransaction?<T>(fn: (txRepo: StandardRepo<TDoc>, uow?: TransactionHandle) => Promise<T>, options?: Record<string, unknown>): Promise<T>;
|
|
1814
1848
|
/**
|
|
1815
1849
|
* Portable change feed — `for await` over committed mutations:
|
|
1816
1850
|
*
|
|
@@ -1870,4 +1904,4 @@ interface CursorOptions {
|
|
|
1870
1904
|
[key: string]: unknown;
|
|
1871
1905
|
}
|
|
1872
1906
|
//#endregion
|
|
1873
|
-
export { AggCacheOptions, AggDateBucket, AggDateBucketInterval, AggDateBucketUnit, AggExecutionHints, AggMeasure, AggPaginationRequest, AggRequest, AggResult, AggRow, AggTopN, AggTopNTies, BulkCreateResult, BulkWriteOperation, BulkWriteResult, ChangeEvent, ClaimTransition, ClaimVersionTransition, CursorOptions, DeleteManyResult, DeleteOptions, DeleteResult, FilterInput, FindAllOptions, FindOneAndUpdateOptions, InferDoc, KeysetAggPaginationResult, MinimalRepo, PaginationParams, QueryOptions, RepositorySession, StandardRepo, TenantPurgeOptions, TenantPurgeProgress, TenantPurgeResult, TenantPurgeStrategy, TransitionArgs, TransitionMachine, UpdateManyResult, WatchOptions, WriteOptions };
|
|
1907
|
+
export { AggCacheOptions, AggDateBucket, AggDateBucketInterval, AggDateBucketUnit, AggExecutionHints, AggMeasure, AggPaginationRequest, AggRequest, AggResult, AggRow, AggTopN, AggTopNTies, BulkCreateResult, BulkWriteOperation, BulkWriteResult, ChangeEvent, ClaimTransition, ClaimVersionTransition, CursorOptions, DeleteManyResult, DeleteOptions, DeleteResult, FilterInput, FindAllOptions, FindOneAndUpdateOptions, InferDoc, KeysetAggPaginationResult, MinimalRepo, PaginationParams, QueryOptions, RepositorySession, StandardRepo, TenantPurgeOptions, TenantPurgeProgress, TenantPurgeResult, TenantPurgeStrategy, TransactionHandle, TransitionArgs, TransitionMachine, UpdateManyResult, WatchOptions, WriteOptions };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isVersionConflictError } from "../errors/conflict.mjs";
|
|
1
2
|
import { and, anyOf as in_, eq, gt, isNull, like, ne, or } from "../filter/builders.mjs";
|
|
2
3
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
4
|
//#region src/testing/conformance.ts
|
|
@@ -1176,6 +1177,14 @@ function runStandardRepoConformance(harness) {
|
|
|
1176
1177
|
const rows = await ctx.repo.findAll({ name: "tx-rollback" });
|
|
1177
1178
|
expect(rows).toHaveLength(0);
|
|
1178
1179
|
});
|
|
1180
|
+
it("the callback receives a TransactionHandle — the outbox join point", async () => {
|
|
1181
|
+
let handle = "never-called";
|
|
1182
|
+
await ctx.repo.withTransaction(async (_txRepo, uow) => {
|
|
1183
|
+
handle = uow;
|
|
1184
|
+
});
|
|
1185
|
+
expect(typeof handle).toBe("object");
|
|
1186
|
+
expect(handle).not.toBeNull();
|
|
1187
|
+
});
|
|
1179
1188
|
it("reads inside the txRepo see writes inside the same callback", async () => {
|
|
1180
1189
|
await ctx.repo.withTransaction(async (txRepo) => {
|
|
1181
1190
|
const id = idOf(await txRepo.create(harness.makeDoc({
|
|
@@ -1186,6 +1195,60 @@ function runStandardRepoConformance(harness) {
|
|
|
1186
1195
|
expect(back?.name).toBe("tx-read");
|
|
1187
1196
|
});
|
|
1188
1197
|
});
|
|
1198
|
+
it("declares WHO retries a transient conflict — undeclared ownership stacks retry policies", () => {
|
|
1199
|
+
const caps = ctx.repo.capabilities;
|
|
1200
|
+
expect(caps?.transactionRetry, "a repository exposing withTransaction must declare capabilities.transactionRetry: 'managed' (the kit retries internally, callers invoke it once) or 'caller' (single attempt, an outer envelope owns the loop)").toMatch(/^(managed|caller)$/);
|
|
1201
|
+
});
|
|
1202
|
+
it("nestedTransactions matches what a nested call ACTUALLY does", async () => {
|
|
1203
|
+
const caps = ctx.repo.capabilities;
|
|
1204
|
+
let nestedWorked;
|
|
1205
|
+
try {
|
|
1206
|
+
await ctx.repo.withTransaction(async (txRepo) => {
|
|
1207
|
+
await txRepo.withTransaction?.(async () => {});
|
|
1208
|
+
});
|
|
1209
|
+
nestedWorked = true;
|
|
1210
|
+
} catch {
|
|
1211
|
+
nestedWorked = false;
|
|
1212
|
+
}
|
|
1213
|
+
expect(nestedWorked, `capabilities.nestedTransactions is ${String(caps?.nestedTransactions)} but a nested withTransaction ${nestedWorked ? "succeeded" : "threw"} — the descriptor must describe THIS repository, not the underlying driver`).toBe(caps?.nestedTransactions === true);
|
|
1214
|
+
});
|
|
1215
|
+
});
|
|
1216
|
+
describe.skipIf(!harness.features.optimisticConcurrency)("ifVersion CAS", () => {
|
|
1217
|
+
const versionOf = (doc) => Number(doc[harness.versionField ?? "version"]);
|
|
1218
|
+
it("a matching version applies the write and increments the version", async () => {
|
|
1219
|
+
const created = await ctx.repo.create(harness.makeDoc({
|
|
1220
|
+
name: "cas-ok",
|
|
1221
|
+
email: "cas@x.com"
|
|
1222
|
+
}));
|
|
1223
|
+
const id = idOf(created, harness.idField);
|
|
1224
|
+
const v0 = versionOf(created);
|
|
1225
|
+
const updated = await ctx.repo.update(id, { name: "cas-ok-2" }, { ifVersion: v0 });
|
|
1226
|
+
expect(updated?.name).toBe("cas-ok-2");
|
|
1227
|
+
expect(versionOf(updated)).toBe(v0 + 1);
|
|
1228
|
+
});
|
|
1229
|
+
it("a STALE version throws VersionConflictError — never null", async () => {
|
|
1230
|
+
const created = await ctx.repo.create(harness.makeDoc({
|
|
1231
|
+
name: "cas-stale",
|
|
1232
|
+
email: "stale@x.com"
|
|
1233
|
+
}));
|
|
1234
|
+
const id = idOf(created, harness.idField);
|
|
1235
|
+
const v0 = versionOf(created);
|
|
1236
|
+
await ctx.repo.update(id, { name: "cas-stale-2" }, { ifVersion: v0 });
|
|
1237
|
+
let caught;
|
|
1238
|
+
try {
|
|
1239
|
+
await ctx.repo.update(id, { name: "cas-stale-3" }, { ifVersion: v0 });
|
|
1240
|
+
} catch (e) {
|
|
1241
|
+
caught = e;
|
|
1242
|
+
}
|
|
1243
|
+
expect(isVersionConflictError(caught)).toBe(true);
|
|
1244
|
+
const current = await ctx.repo.getById(id);
|
|
1245
|
+
expect(current?.name).toBe("cas-stale-2");
|
|
1246
|
+
});
|
|
1247
|
+
it("not-found stays null — a missing record is NOT a version conflict", async () => {
|
|
1248
|
+
const ghost = harness.missingId ?? "000000000000000000000000";
|
|
1249
|
+
const out = await ctx.repo.update(ghost, { name: "x" }, { ifVersion: 1 });
|
|
1250
|
+
expect(out).toBeNull();
|
|
1251
|
+
});
|
|
1189
1252
|
});
|
|
1190
1253
|
describe("purgeByField (tenant cleanup)", () => {
|
|
1191
1254
|
const seedTwoTenants = async () => {
|
package/dist/testing/types.d.mts
CHANGED
|
@@ -97,6 +97,17 @@ interface ConformanceHarness<TDoc extends ConformanceDoc = ConformanceDoc> {
|
|
|
97
97
|
idField: string;
|
|
98
98
|
/** Feature support flags — skipped scenarios show as `skipped` in vitest output. */
|
|
99
99
|
features: ConformanceFeatures;
|
|
100
|
+
/**
|
|
101
|
+
* Field carrying the optimistic-concurrency version, when the
|
|
102
|
+
* `optimisticConcurrency` capability is declared. Default `'version'`.
|
|
103
|
+
*/
|
|
104
|
+
versionField?: string;
|
|
105
|
+
/**
|
|
106
|
+
* A syntactically valid id that matches no record — the ifVersion cases
|
|
107
|
+
* assert not-found stays `null` (never a version conflict). Default is a
|
|
108
|
+
* Mongo-shaped all-zero ObjectId; SQL/string-id kits supply their own.
|
|
109
|
+
*/
|
|
110
|
+
missingId?: string;
|
|
100
111
|
/** Create a fresh, isolated repo + cleanup closure. Called per test. */
|
|
101
112
|
setup(): Promise<ConformanceContext<TDoc>>;
|
|
102
113
|
/**
|
package/package.json
CHANGED
|
@@ -1,184 +1,184 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
2
|
+
"name": "@classytic/repo-core",
|
|
3
|
+
"version": "0.23.0",
|
|
4
|
+
"description": "Driver-agnostic repository primitives: hooks, Filter IR, operations, pagination, cache contract. Foundation for mongokit, sqlitekit, pgkit, and prismakit. Lean by design — no plugins ship here; each kit owns its own.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE",
|
|
11
|
+
"CHANGELOG.md"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=22"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
"./hooks": {
|
|
18
|
+
"types": "./dist/hooks/index.d.mts",
|
|
19
|
+
"default": "./dist/hooks/index.mjs"
|
|
20
|
+
},
|
|
21
|
+
"./operations": {
|
|
22
|
+
"types": "./dist/operations/index.d.mts",
|
|
23
|
+
"default": "./dist/operations/index.mjs"
|
|
24
|
+
},
|
|
25
|
+
"./errors": {
|
|
26
|
+
"types": "./dist/errors/index.d.mts",
|
|
27
|
+
"default": "./dist/errors/index.mjs"
|
|
28
|
+
},
|
|
29
|
+
"./pagination": {
|
|
30
|
+
"types": "./dist/pagination/index.d.mts",
|
|
31
|
+
"default": "./dist/pagination/index.mjs"
|
|
32
|
+
},
|
|
33
|
+
"./repository": {
|
|
34
|
+
"types": "./dist/repository/index.d.mts",
|
|
35
|
+
"default": "./dist/repository/index.mjs"
|
|
36
|
+
},
|
|
37
|
+
"./filter": {
|
|
38
|
+
"types": "./dist/filter/index.d.mts",
|
|
39
|
+
"default": "./dist/filter/index.mjs"
|
|
40
|
+
},
|
|
41
|
+
"./update": {
|
|
42
|
+
"types": "./dist/update/index.d.mts",
|
|
43
|
+
"default": "./dist/update/index.mjs"
|
|
44
|
+
},
|
|
45
|
+
"./query-parser": {
|
|
46
|
+
"types": "./dist/query-parser/index.d.mts",
|
|
47
|
+
"default": "./dist/query-parser/index.mjs"
|
|
48
|
+
},
|
|
49
|
+
"./context": {
|
|
50
|
+
"types": "./dist/context/index.d.mts",
|
|
51
|
+
"default": "./dist/context/index.mjs"
|
|
52
|
+
},
|
|
53
|
+
"./cache": {
|
|
54
|
+
"types": "./dist/cache/index.d.mts",
|
|
55
|
+
"default": "./dist/cache/index.mjs"
|
|
56
|
+
},
|
|
57
|
+
"./hash": {
|
|
58
|
+
"types": "./dist/hash/index.d.mts",
|
|
59
|
+
"default": "./dist/hash/index.mjs"
|
|
60
|
+
},
|
|
61
|
+
"./events": {
|
|
62
|
+
"types": "./dist/events/index.d.mts",
|
|
63
|
+
"default": "./dist/events/index.mjs"
|
|
64
|
+
},
|
|
65
|
+
"./schema": {
|
|
66
|
+
"types": "./dist/schema/index.d.mts",
|
|
67
|
+
"default": "./dist/schema/index.mjs"
|
|
68
|
+
},
|
|
69
|
+
"./testing": {
|
|
70
|
+
"types": "./dist/testing/index.d.mts",
|
|
71
|
+
"default": "./dist/testing/index.mjs"
|
|
72
|
+
},
|
|
73
|
+
"./tenant": {
|
|
74
|
+
"types": "./dist/tenant/index.d.mts",
|
|
75
|
+
"default": "./dist/tenant/index.mjs"
|
|
76
|
+
},
|
|
77
|
+
"./lookup": {
|
|
78
|
+
"types": "./dist/lookup/index.d.mts",
|
|
79
|
+
"default": "./dist/lookup/index.mjs"
|
|
80
|
+
},
|
|
81
|
+
"./adapter": {
|
|
82
|
+
"types": "./dist/adapter/index.d.mts",
|
|
83
|
+
"default": "./dist/adapter/index.mjs"
|
|
84
|
+
},
|
|
85
|
+
"./better-auth": {
|
|
86
|
+
"types": "./dist/better-auth/index.d.mts",
|
|
87
|
+
"default": "./dist/better-auth/index.mjs"
|
|
88
|
+
},
|
|
89
|
+
"./aggregate": {
|
|
90
|
+
"types": "./dist/aggregate/index.d.mts",
|
|
91
|
+
"default": "./dist/aggregate/index.mjs"
|
|
92
|
+
},
|
|
93
|
+
"./plugins": {
|
|
94
|
+
"types": "./dist/plugins/index.d.mts",
|
|
95
|
+
"default": "./dist/plugins/index.mjs"
|
|
96
|
+
},
|
|
97
|
+
"./lock": {
|
|
98
|
+
"types": "./dist/lock/index.d.mts",
|
|
99
|
+
"default": "./dist/lock/index.mjs"
|
|
100
|
+
},
|
|
101
|
+
"./usage": {
|
|
102
|
+
"types": "./dist/usage/index.d.mts",
|
|
103
|
+
"default": "./dist/usage/index.mjs"
|
|
104
|
+
},
|
|
105
|
+
"./package.json": "./package.json",
|
|
106
|
+
"./sync": {
|
|
107
|
+
"types": "./dist/sync/index.d.mts",
|
|
108
|
+
"default": "./dist/sync/index.mjs"
|
|
109
|
+
},
|
|
110
|
+
"./cleanup": {
|
|
111
|
+
"types": "./dist/cleanup/index.d.mts",
|
|
112
|
+
"default": "./dist/cleanup/index.mjs"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"keywords": [
|
|
116
|
+
"repository",
|
|
117
|
+
"repository-pattern",
|
|
118
|
+
"data-access",
|
|
119
|
+
"hooks",
|
|
120
|
+
"filter-ir",
|
|
121
|
+
"pagination",
|
|
122
|
+
"cursor-pagination",
|
|
123
|
+
"keyset-pagination",
|
|
124
|
+
"plugin-based",
|
|
125
|
+
"driver-agnostic",
|
|
126
|
+
"typescript",
|
|
127
|
+
"esm"
|
|
128
|
+
],
|
|
129
|
+
"author": "Classytic <classytic.dev@gmail.com> (https://github.com/classytic)",
|
|
130
|
+
"license": "MIT",
|
|
131
|
+
"repository": {
|
|
132
|
+
"type": "git",
|
|
133
|
+
"url": "git+https://github.com/classytic/repo-core.git"
|
|
134
|
+
},
|
|
135
|
+
"bugs": {
|
|
136
|
+
"url": "https://github.com/classytic/repo-core/issues"
|
|
137
|
+
},
|
|
138
|
+
"homepage": "https://github.com/classytic/repo-core#readme",
|
|
139
|
+
"scripts": {
|
|
140
|
+
"build": "tsdown",
|
|
141
|
+
"dev": "tsdown --watch",
|
|
142
|
+
"test": "vitest run --project unit --project integration",
|
|
143
|
+
"test:unit": "vitest run --project unit",
|
|
144
|
+
"test:integration": "vitest run --project integration",
|
|
145
|
+
"test:e2e": "vitest run --project e2e",
|
|
146
|
+
"test:all": "vitest run",
|
|
147
|
+
"test:watch": "vitest --project unit --project integration",
|
|
148
|
+
"bench": "vitest bench --run --project bench",
|
|
149
|
+
"test:coverage": "vitest run --coverage",
|
|
150
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
151
|
+
"lint": "biome check src tests",
|
|
152
|
+
"lint:fix": "biome check src tests --write",
|
|
153
|
+
"format": "biome format src tests --write",
|
|
154
|
+
"check": "biome ci src tests --diagnostic-level=error",
|
|
155
|
+
"knip": "knip",
|
|
156
|
+
"push": "classytic-push",
|
|
157
|
+
"prepublishOnly": "npm run check && npm run build && npm run typecheck && npm test",
|
|
158
|
+
"release:tag": "node -e \"require('child_process').execSync('npm run push -- v'+require('./package.json').version,{stdio:'inherit'})\"",
|
|
159
|
+
"release": "npm run push -- main && npm run release:tag && npm publish",
|
|
160
|
+
"publish:dry": "npm publish --dry-run --access public",
|
|
161
|
+
"publish:npm": "npm publish --access public"
|
|
162
|
+
},
|
|
163
|
+
"devDependencies": {
|
|
164
|
+
"@arethetypeswrong/cli": "^0.18.2",
|
|
165
|
+
"@biomejs/biome": "^2.4.12",
|
|
166
|
+
"@classytic/dev-tools": "^0.2.0",
|
|
167
|
+
"@types/node": "^22.0.0",
|
|
168
|
+
"@vitest/coverage-v8": "^4.1.4",
|
|
169
|
+
"fast-check": "^4.7.0",
|
|
170
|
+
"knip": "^6.3.0",
|
|
171
|
+
"publint": "^0.3.18",
|
|
172
|
+
"tsdown": "^0.22.14",
|
|
173
|
+
"typescript": "^7.0.2",
|
|
174
|
+
"vitest": "^4.1.4"
|
|
175
|
+
},
|
|
176
|
+
"peerDependencies": {
|
|
177
|
+
"vitest": "^3.0.0 || ^4.0.0"
|
|
178
|
+
},
|
|
179
|
+
"peerDependenciesMeta": {
|
|
180
|
+
"vitest": {
|
|
181
|
+
"optional": true
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
184
|
}
|