@classytic/repo-core 0.10.0 → 0.11.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 +13 -0
- package/dist/testing/index.d.mts +2 -1
- package/dist/testing/index.mjs +2 -1
- package/dist/testing/usage-conformance.d.mts +18 -0
- package/dist/testing/usage-conformance.mjs +101 -0
- package/dist/usage/index.d.mts +77 -0
- package/dist/usage/index.mjs +36 -0
- package/package.json +176 -172
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to `@classytic/repo-core` are documented here.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.11.0] - 2026-07-15
|
|
8
|
+
|
|
9
|
+
### Added — `./usage` subpath (period-bucketed counter contract)
|
|
10
|
+
|
|
11
|
+
- **`UsageStore`** — driver-agnostic interface for atomic period-bucketed counters: `increment(bucket, amount)` + `summary(actor, period)`. The storage seam under platform accounting (quotas, plan enforcement, usage-based billing). One cell = `(actor, period, kind)`; one write = atomic upsert; one read = all counters for an actor-period pair. Kits ship adapters (`@classytic/mongokit/usage`, `@classytic/sqlitekit/usage`, …) without depending on arc; `@classytic/arc/usage` consumes this contract structurally.
|
|
12
|
+
- **`UsageBucket`** — `{ actor, period, kind }` tuple. `kind` is dot-namespaced: `api.requests`, `ai.tokens.input`, `storage.egress.bytes`.
|
|
13
|
+
- **`usagePeriod(date?)`** — canonical UTC calendar-month key (`"2026-07"`). Monthly is the billing-native granularity.
|
|
14
|
+
- **`createMemoryUsageStore()`** — in-process reference implementation for tests and single-instance apps. Returns `UsageStore & { clear() }`. Multi-replica deployments need a shared adapter.
|
|
15
|
+
|
|
16
|
+
### Added — `runUsageStoreContract` in `./testing`
|
|
17
|
+
|
|
18
|
+
- **`runUsageStoreContract(harness)`** — cross-kit conformance suite. Kits import once and pass their adapter; all canonical scenarios run automatically. Same pattern as `runLockAdapterConformance`. `UsageConformanceHarness` is exported from `./testing` for harness typing.
|
|
19
|
+
|
|
7
20
|
## [0.10.0] - 2026-07-13
|
|
8
21
|
|
|
9
22
|
### Added — `ValidationErrorMeta.path` + `.meta` (field-scoped validation errors)
|
package/dist/testing/index.d.mts
CHANGED
|
@@ -2,4 +2,5 @@ import { AggregateOpsSupport } from "../repository/capabilities.mjs";
|
|
|
2
2
|
import { ConformanceContext, ConformanceDoc, ConformanceFeatures, ConformanceHarness } from "./types.mjs";
|
|
3
3
|
import { runStandardRepoConformance } from "./conformance.mjs";
|
|
4
4
|
import { LockConformanceHarness, runLockAdapterConformance } from "./lock-conformance.mjs";
|
|
5
|
-
|
|
5
|
+
import { UsageConformanceHarness, runUsageStoreContract } from "./usage-conformance.mjs";
|
|
6
|
+
export { type AggregateOpsSupport, type ConformanceContext, type ConformanceDoc, type ConformanceFeatures, type ConformanceHarness, type LockConformanceHarness, type UsageConformanceHarness, runLockAdapterConformance, runStandardRepoConformance, runUsageStoreContract };
|
package/dist/testing/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { runStandardRepoConformance } from "./conformance.mjs";
|
|
2
2
|
import { runLockAdapterConformance } from "./lock-conformance.mjs";
|
|
3
|
-
|
|
3
|
+
import { runUsageStoreContract } from "./usage-conformance.mjs";
|
|
4
|
+
export { runLockAdapterConformance, runStandardRepoConformance, runUsageStoreContract };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { UsageStore } from "../usage/index.mjs";
|
|
2
|
+
//#region src/testing/usage-conformance.d.ts
|
|
3
|
+
interface UsageConformanceHarness {
|
|
4
|
+
/**
|
|
5
|
+
* Construct the store under test. May be async (SQL migrations,
|
|
6
|
+
* index creation). The same instance is shared by every test —
|
|
7
|
+
* `beforeEach` clears residual counters.
|
|
8
|
+
*/
|
|
9
|
+
createStore(): UsageStore | Promise<UsageStore>;
|
|
10
|
+
/**
|
|
11
|
+
* Wipe every counter between tests. Mongo: `deleteMany({})`.
|
|
12
|
+
* SQL: `DELETE FROM kit_usage`. Memory: `clear()`.
|
|
13
|
+
*/
|
|
14
|
+
beforeEach?(store: UsageStore): void | Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
declare function runUsageStoreContract(harness: UsageConformanceHarness): void;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { UsageConformanceHarness, runUsageStoreContract };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
//#region src/testing/usage-conformance.ts
|
|
3
|
+
/**
|
|
4
|
+
* `runUsageStoreContract` — cross-kit usage-store contract suite.
|
|
5
|
+
*
|
|
6
|
+
* Wires a kit-specific harness to the canonical scenarios every
|
|
7
|
+
* `UsageStore` implementation must pass — so "swap mongokit/usage for
|
|
8
|
+
* sqlitekit/usage" is a provable claim and drift shows up here before
|
|
9
|
+
* it ships. Written ONCE here; kits import it instead of hand-writing
|
|
10
|
+
* conformance (same shape as `runLockAdapterConformance`).
|
|
11
|
+
*
|
|
12
|
+
* ## Usage from a kit
|
|
13
|
+
*
|
|
14
|
+
* import { runUsageStoreContract } from '@classytic/repo-core/testing';
|
|
15
|
+
* import { createMongoUsageStore } from '../../src/usage/index.js';
|
|
16
|
+
*
|
|
17
|
+
* describe('mongokit/usage conformance', () => {
|
|
18
|
+
* runUsageStoreContract({
|
|
19
|
+
* createStore: () => createMongoUsageStore({ connection }),
|
|
20
|
+
* async beforeEach() { await clearCounters(); },
|
|
21
|
+
* });
|
|
22
|
+
* });
|
|
23
|
+
*/
|
|
24
|
+
function runUsageStoreContract(harness) {
|
|
25
|
+
describe("UsageStore contract", () => {
|
|
26
|
+
let store;
|
|
27
|
+
beforeEach(async () => {
|
|
28
|
+
store = await harness.createStore();
|
|
29
|
+
await harness.beforeEach?.(store);
|
|
30
|
+
});
|
|
31
|
+
it("accumulates increments per (actor, period, kind)", async () => {
|
|
32
|
+
const bucket = {
|
|
33
|
+
actor: "org-1",
|
|
34
|
+
period: "2026-07",
|
|
35
|
+
kind: "api.requests"
|
|
36
|
+
};
|
|
37
|
+
await store.increment(bucket, 1);
|
|
38
|
+
await store.increment(bucket, 2);
|
|
39
|
+
await store.increment({
|
|
40
|
+
...bucket,
|
|
41
|
+
kind: "ai.tokens.input"
|
|
42
|
+
}, 500);
|
|
43
|
+
expect(await store.summary("org-1", "2026-07")).toEqual({
|
|
44
|
+
"api.requests": 3,
|
|
45
|
+
"ai.tokens.input": 500
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
it("treats a missing bucket as 0 (first increment creates it)", async () => {
|
|
49
|
+
await store.increment({
|
|
50
|
+
actor: "a",
|
|
51
|
+
period: "2026-07",
|
|
52
|
+
kind: "k"
|
|
53
|
+
}, 7);
|
|
54
|
+
expect(await store.summary("a", "2026-07")).toEqual({ k: 7 });
|
|
55
|
+
});
|
|
56
|
+
it("isolates actors and periods", async () => {
|
|
57
|
+
await store.increment({
|
|
58
|
+
actor: "org-1",
|
|
59
|
+
period: "2026-06",
|
|
60
|
+
kind: "k"
|
|
61
|
+
}, 5);
|
|
62
|
+
await store.increment({
|
|
63
|
+
actor: "org-1",
|
|
64
|
+
period: "2026-07",
|
|
65
|
+
kind: "k"
|
|
66
|
+
}, 7);
|
|
67
|
+
await store.increment({
|
|
68
|
+
actor: "org-2",
|
|
69
|
+
period: "2026-07",
|
|
70
|
+
kind: "k"
|
|
71
|
+
}, 11);
|
|
72
|
+
expect(await store.summary("org-1", "2026-06")).toEqual({ k: 5 });
|
|
73
|
+
expect(await store.summary("org-1", "2026-07")).toEqual({ k: 7 });
|
|
74
|
+
expect(await store.summary("org-2", "2026-07")).toEqual({ k: 11 });
|
|
75
|
+
});
|
|
76
|
+
it("dotted kind names round-trip exactly (no path nesting)", async () => {
|
|
77
|
+
await store.increment({
|
|
78
|
+
actor: "a",
|
|
79
|
+
period: "2026-07",
|
|
80
|
+
kind: "storage.egress.bytes"
|
|
81
|
+
}, 42);
|
|
82
|
+
const summary = await store.summary("a", "2026-07");
|
|
83
|
+
expect(summary["storage.egress.bytes"]).toBe(42);
|
|
84
|
+
expect(Object.keys(summary)).toEqual(["storage.egress.bytes"]);
|
|
85
|
+
});
|
|
86
|
+
it("returns {} for unknown actors/periods (never throws)", async () => {
|
|
87
|
+
expect(await store.summary("nobody", "2099-01")).toEqual({});
|
|
88
|
+
});
|
|
89
|
+
it("increment is atomic per bucket under concurrency", async () => {
|
|
90
|
+
const bucket = {
|
|
91
|
+
actor: "org-c",
|
|
92
|
+
period: "2026-07",
|
|
93
|
+
kind: "api.requests"
|
|
94
|
+
};
|
|
95
|
+
await Promise.all(Array.from({ length: 50 }, () => store.increment(bucket, 1)));
|
|
96
|
+
expect((await store.summary("org-c", "2026-07"))["api.requests"]).toBe(50);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { runUsageStoreContract };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//#region src/usage/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Usage-counter contract for the @classytic ecosystem.
|
|
4
|
+
*
|
|
5
|
+
* Period-bucketed counters per actor — the storage seam under
|
|
6
|
+
* platform accounting (quotas, plan enforcement, usage-based
|
|
7
|
+
* billing). One cell = `(actor, period, kind)`; one write op =
|
|
8
|
+
* atomic increment; one read op = all counters for an actor-period.
|
|
9
|
+
*
|
|
10
|
+
* ## Why this lives in repo-core
|
|
11
|
+
*
|
|
12
|
+
* Same reasoning as `./lock`: the contract is driver-free — any
|
|
13
|
+
* store with an atomic increment-upsert implements it (Mongo `$inc`
|
|
14
|
+
* upsert, SQL `ON CONFLICT ... DO UPDATE SET n = n + ?`, Redis
|
|
15
|
+
* `HINCRBY`). Kits ship their adapters (`@classytic/mongokit/usage`,
|
|
16
|
+
* `@classytic/sqlitekit/usage`, ...) WITHOUT depending on arc;
|
|
17
|
+
* `@classytic/arc/usage`'s `usagePlugin` consumes the contract
|
|
18
|
+
* structurally (its local `UsageStore` mirrors this shape the same
|
|
19
|
+
* way its `ScheduleLockLike` mirrors `LockAdapter`) so arc's
|
|
20
|
+
* repo-core peer floor never bumps for it.
|
|
21
|
+
*
|
|
22
|
+
* Distinct from itemized event/usage RECORD stores (e.g.
|
|
23
|
+
* `@classytic/arc-ai/usage`'s per-run records): this contract holds
|
|
24
|
+
* AGGREGATES only. Itemized layers sink into it; they don't replace it.
|
|
25
|
+
*
|
|
26
|
+
* ## Semantics
|
|
27
|
+
*
|
|
28
|
+
* - `increment` MUST be atomic per bucket (concurrent writers never
|
|
29
|
+
* lose counts) and MUST treat a missing bucket as `0`.
|
|
30
|
+
* - `summary` returns `{}` (never throws) for unknown actors/periods.
|
|
31
|
+
* - `period` keys are opaque strings to the store; `usagePeriod()`
|
|
32
|
+
* is the ecosystem's canonical key (UTC calendar month, `2026-07`).
|
|
33
|
+
* Stores wanting finer windows shard internally without changing
|
|
34
|
+
* the contract.
|
|
35
|
+
* - Sync-or-async: memory adapter is sync; DB adapters async;
|
|
36
|
+
* consumers `await` either way.
|
|
37
|
+
*
|
|
38
|
+
* ## Why one file, not a barrel
|
|
39
|
+
*
|
|
40
|
+
* Contract + reference memory adapter + the period helper are under
|
|
41
|
+
* 100 LOC with no internal seams — same single-file rule as `./lock`.
|
|
42
|
+
*/
|
|
43
|
+
/** One counter cell: (actor, period, kind). */
|
|
44
|
+
interface UsageBucket {
|
|
45
|
+
/** Who consumed — org / user / client id, or a host-chosen fallback key. */
|
|
46
|
+
actor: string;
|
|
47
|
+
/** Aggregation period key — canonically `usagePeriod()`'s `YYYY-MM`. */
|
|
48
|
+
period: string;
|
|
49
|
+
/** Namespaced counter, dot-separated: `api.requests`, `ai.tokens.input`, `storage.egress.bytes`. */
|
|
50
|
+
kind: string;
|
|
51
|
+
}
|
|
52
|
+
/** Period-bucketed usage counters. See module header for semantics. */
|
|
53
|
+
interface UsageStore {
|
|
54
|
+
/** Store name for diagnostics (e.g. 'memory', 'mongo', 'redis'). */
|
|
55
|
+
readonly name: string;
|
|
56
|
+
/** Atomically add `amount` to the bucket's counter, creating it at 0. */
|
|
57
|
+
increment(bucket: UsageBucket, amount: number): Promise<void> | void;
|
|
58
|
+
/** Every counter for an actor in a period: `{ 'api.requests': 40231, ... }`. */
|
|
59
|
+
summary(actor: string, period: string): Promise<Record<string, number>>;
|
|
60
|
+
/** Optional cleanup hook (connections, timers). */
|
|
61
|
+
close?(): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Canonical period key for a date — calendar month, UTC: `2026-07`.
|
|
65
|
+
* Monthly is the billing-native granularity.
|
|
66
|
+
*/
|
|
67
|
+
declare function usagePeriod(date?: Date): string;
|
|
68
|
+
/**
|
|
69
|
+
* In-memory reference implementation — tests and single-instance
|
|
70
|
+
* apps. Counters are per-process; multi-replica deployments need a
|
|
71
|
+
* shared adapter (kit- or Redis-backed).
|
|
72
|
+
*/
|
|
73
|
+
declare function createMemoryUsageStore(): UsageStore & {
|
|
74
|
+
clear(): void;
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
77
|
+
export { UsageBucket, UsageStore, createMemoryUsageStore, usagePeriod };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/usage/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Canonical period key for a date — calendar month, UTC: `2026-07`.
|
|
4
|
+
* Monthly is the billing-native granularity.
|
|
5
|
+
*/
|
|
6
|
+
function usagePeriod(date = /* @__PURE__ */ new Date()) {
|
|
7
|
+
return `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, "0")}`;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* In-memory reference implementation — tests and single-instance
|
|
11
|
+
* apps. Counters are per-process; multi-replica deployments need a
|
|
12
|
+
* shared adapter (kit- or Redis-backed).
|
|
13
|
+
*/
|
|
14
|
+
function createMemoryUsageStore() {
|
|
15
|
+
/** actor → period → kind → count */
|
|
16
|
+
const counters = /* @__PURE__ */ new Map();
|
|
17
|
+
return {
|
|
18
|
+
name: "memory",
|
|
19
|
+
increment(bucket, amount) {
|
|
20
|
+
const periods = counters.get(bucket.actor) ?? /* @__PURE__ */ new Map();
|
|
21
|
+
const kinds = periods.get(bucket.period) ?? /* @__PURE__ */ new Map();
|
|
22
|
+
kinds.set(bucket.kind, (kinds.get(bucket.kind) ?? 0) + amount);
|
|
23
|
+
periods.set(bucket.period, kinds);
|
|
24
|
+
counters.set(bucket.actor, periods);
|
|
25
|
+
},
|
|
26
|
+
async summary(actor, period) {
|
|
27
|
+
const kinds = counters.get(actor)?.get(period);
|
|
28
|
+
return kinds ? Object.fromEntries(kinds) : {};
|
|
29
|
+
},
|
|
30
|
+
clear() {
|
|
31
|
+
counters.clear();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { createMemoryUsageStore, usagePeriod };
|
package/package.json
CHANGED
|
@@ -1,172 +1,176 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@classytic/repo-core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Driver-agnostic repository primitives: hooks, Filter IR, operations, pagination, cache contract. Foundation for mongokit, sqlitekit, pgkit, and prismakit. Lean by design
|
|
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
|
-
"./events": {
|
|
58
|
-
"types": "./dist/events/index.d.mts",
|
|
59
|
-
"default": "./dist/events/index.mjs"
|
|
60
|
-
},
|
|
61
|
-
"./schema": {
|
|
62
|
-
"types": "./dist/schema/index.d.mts",
|
|
63
|
-
"default": "./dist/schema/index.mjs"
|
|
64
|
-
},
|
|
65
|
-
"./testing": {
|
|
66
|
-
"types": "./dist/testing/index.d.mts",
|
|
67
|
-
"default": "./dist/testing/index.mjs"
|
|
68
|
-
},
|
|
69
|
-
"./tenant": {
|
|
70
|
-
"types": "./dist/tenant/index.d.mts",
|
|
71
|
-
"default": "./dist/tenant/index.mjs"
|
|
72
|
-
},
|
|
73
|
-
"./lookup": {
|
|
74
|
-
"types": "./dist/lookup/index.d.mts",
|
|
75
|
-
"default": "./dist/lookup/index.mjs"
|
|
76
|
-
},
|
|
77
|
-
"./adapter": {
|
|
78
|
-
"types": "./dist/adapter/index.d.mts",
|
|
79
|
-
"default": "./dist/adapter/index.mjs"
|
|
80
|
-
},
|
|
81
|
-
"./better-auth": {
|
|
82
|
-
"types": "./dist/better-auth/index.d.mts",
|
|
83
|
-
"default": "./dist/better-auth/index.mjs"
|
|
84
|
-
},
|
|
85
|
-
"./aggregate": {
|
|
86
|
-
"types": "./dist/aggregate/index.d.mts",
|
|
87
|
-
"default": "./dist/aggregate/index.mjs"
|
|
88
|
-
},
|
|
89
|
-
"./plugins": {
|
|
90
|
-
"types": "./dist/plugins/index.d.mts",
|
|
91
|
-
"default": "./dist/plugins/index.mjs"
|
|
92
|
-
},
|
|
93
|
-
"./lock": {
|
|
94
|
-
"types": "./dist/lock/index.d.mts",
|
|
95
|
-
"default": "./dist/lock/index.mjs"
|
|
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
|
-
"test
|
|
135
|
-
"test:
|
|
136
|
-
"
|
|
137
|
-
"test:
|
|
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
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@classytic/repo-core",
|
|
3
|
+
"version": "0.11.0",
|
|
4
|
+
"description": "Driver-agnostic repository primitives: hooks, Filter IR, operations, pagination, cache contract. Foundation for mongokit, sqlitekit, pgkit, and prismakit. Lean by design \u00e2\u20ac\u201d 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
|
+
"./events": {
|
|
58
|
+
"types": "./dist/events/index.d.mts",
|
|
59
|
+
"default": "./dist/events/index.mjs"
|
|
60
|
+
},
|
|
61
|
+
"./schema": {
|
|
62
|
+
"types": "./dist/schema/index.d.mts",
|
|
63
|
+
"default": "./dist/schema/index.mjs"
|
|
64
|
+
},
|
|
65
|
+
"./testing": {
|
|
66
|
+
"types": "./dist/testing/index.d.mts",
|
|
67
|
+
"default": "./dist/testing/index.mjs"
|
|
68
|
+
},
|
|
69
|
+
"./tenant": {
|
|
70
|
+
"types": "./dist/tenant/index.d.mts",
|
|
71
|
+
"default": "./dist/tenant/index.mjs"
|
|
72
|
+
},
|
|
73
|
+
"./lookup": {
|
|
74
|
+
"types": "./dist/lookup/index.d.mts",
|
|
75
|
+
"default": "./dist/lookup/index.mjs"
|
|
76
|
+
},
|
|
77
|
+
"./adapter": {
|
|
78
|
+
"types": "./dist/adapter/index.d.mts",
|
|
79
|
+
"default": "./dist/adapter/index.mjs"
|
|
80
|
+
},
|
|
81
|
+
"./better-auth": {
|
|
82
|
+
"types": "./dist/better-auth/index.d.mts",
|
|
83
|
+
"default": "./dist/better-auth/index.mjs"
|
|
84
|
+
},
|
|
85
|
+
"./aggregate": {
|
|
86
|
+
"types": "./dist/aggregate/index.d.mts",
|
|
87
|
+
"default": "./dist/aggregate/index.mjs"
|
|
88
|
+
},
|
|
89
|
+
"./plugins": {
|
|
90
|
+
"types": "./dist/plugins/index.d.mts",
|
|
91
|
+
"default": "./dist/plugins/index.mjs"
|
|
92
|
+
},
|
|
93
|
+
"./lock": {
|
|
94
|
+
"types": "./dist/lock/index.d.mts",
|
|
95
|
+
"default": "./dist/lock/index.mjs"
|
|
96
|
+
},
|
|
97
|
+
"./usage": {
|
|
98
|
+
"types": "./dist/usage/index.d.mts",
|
|
99
|
+
"default": "./dist/usage/index.mjs"
|
|
100
|
+
},
|
|
101
|
+
"./package.json": "./package.json",
|
|
102
|
+
"./sync": {
|
|
103
|
+
"types": "./dist/sync/index.d.mts",
|
|
104
|
+
"default": "./dist/sync/index.mjs"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"keywords": [
|
|
108
|
+
"repository",
|
|
109
|
+
"repository-pattern",
|
|
110
|
+
"data-access",
|
|
111
|
+
"hooks",
|
|
112
|
+
"filter-ir",
|
|
113
|
+
"pagination",
|
|
114
|
+
"cursor-pagination",
|
|
115
|
+
"keyset-pagination",
|
|
116
|
+
"plugin-based",
|
|
117
|
+
"driver-agnostic",
|
|
118
|
+
"typescript",
|
|
119
|
+
"esm"
|
|
120
|
+
],
|
|
121
|
+
"author": "Classytic <classytic.dev@gmail.com> (https://github.com/classytic)",
|
|
122
|
+
"license": "MIT",
|
|
123
|
+
"repository": {
|
|
124
|
+
"type": "git",
|
|
125
|
+
"url": "git+https://github.com/classytic/repo-core.git"
|
|
126
|
+
},
|
|
127
|
+
"bugs": {
|
|
128
|
+
"url": "https://github.com/classytic/repo-core/issues"
|
|
129
|
+
},
|
|
130
|
+
"homepage": "https://github.com/classytic/repo-core#readme",
|
|
131
|
+
"scripts": {
|
|
132
|
+
"build": "tsdown",
|
|
133
|
+
"dev": "tsdown --watch",
|
|
134
|
+
"test": "vitest run --project unit --project integration",
|
|
135
|
+
"test:unit": "vitest run --project unit",
|
|
136
|
+
"test:integration": "vitest run --project integration",
|
|
137
|
+
"test:e2e": "vitest run --project e2e",
|
|
138
|
+
"test:all": "vitest run",
|
|
139
|
+
"test:watch": "vitest --project unit --project integration",
|
|
140
|
+
"bench": "vitest bench --run --project bench",
|
|
141
|
+
"test:coverage": "vitest run --coverage",
|
|
142
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
143
|
+
"lint": "biome check src tests",
|
|
144
|
+
"lint:fix": "biome check src tests --write",
|
|
145
|
+
"format": "biome format src tests --write",
|
|
146
|
+
"check": "biome ci src tests --diagnostic-level=error",
|
|
147
|
+
"knip": "knip",
|
|
148
|
+
"push": "classytic-push",
|
|
149
|
+
"prepublishOnly": "npm run check && npm run build && npm run typecheck && npm test",
|
|
150
|
+
"release:tag": "node -e \"require('child_process').execSync('npm run push -- v'+require('./package.json').version,{stdio:'inherit'})\"",
|
|
151
|
+
"release": "npm run push -- main && npm run release:tag && npm publish",
|
|
152
|
+
"publish:dry": "npm publish --dry-run --access public",
|
|
153
|
+
"publish:npm": "npm publish --access public"
|
|
154
|
+
},
|
|
155
|
+
"devDependencies": {
|
|
156
|
+
"@arethetypeswrong/cli": "^0.18.2",
|
|
157
|
+
"@biomejs/biome": "^2.4.12",
|
|
158
|
+
"@classytic/dev-tools": "^0.2.0",
|
|
159
|
+
"@types/node": "^22.0.0",
|
|
160
|
+
"@vitest/coverage-v8": "^4.1.4",
|
|
161
|
+
"fast-check": "^4.7.0",
|
|
162
|
+
"knip": "^6.3.0",
|
|
163
|
+
"publint": "^0.3.18",
|
|
164
|
+
"tsdown": "^0.22.5",
|
|
165
|
+
"typescript": "^7.0.2",
|
|
166
|
+
"vitest": "^4.1.4"
|
|
167
|
+
},
|
|
168
|
+
"peerDependencies": {
|
|
169
|
+
"vitest": "^3.0.0 || ^4.0.0"
|
|
170
|
+
},
|
|
171
|
+
"peerDependenciesMeta": {
|
|
172
|
+
"vitest": {
|
|
173
|
+
"optional": true
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|