@classytic/repo-core 0.5.0 → 0.6.1
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 +38 -1
- package/README.md +65 -3
- package/dist/events/emit.d.mts +22 -0
- package/dist/events/emit.mjs +105 -0
- package/dist/events/index.d.mts +3 -0
- package/dist/events/index.mjs +2 -0
- package/dist/events/types.d.mts +73 -0
- package/dist/filter/from-record.d.mts +13 -0
- package/dist/filter/from-record.mjs +135 -0
- package/dist/filter/index.d.mts +2 -1
- package/dist/filter/index.mjs +2 -1
- package/dist/hooks/priority.d.mts +7 -1
- package/dist/hooks/priority.mjs +1 -0
- package/dist/repository/base.d.mts +32 -0
- package/dist/repository/base.mjs +25 -0
- package/dist/repository/capabilities.d.mts +159 -0
- package/dist/repository/index.d.mts +4 -2
- package/dist/repository/index.mjs +2 -1
- package/dist/repository/options.d.mts +5 -1
- package/dist/repository/options.mjs +6 -1
- package/dist/repository/purge.mjs +21 -21
- package/dist/repository/resilience.d.mts +55 -0
- package/dist/repository/resilience.mjs +39 -0
- package/dist/repository/types.d.mts +73 -14
- package/dist/schema/index.d.mts +2 -1
- package/dist/schema/index.mjs +2 -1
- package/dist/schema/standard-schema.d.mts +89 -0
- package/dist/schema/standard-schema.mjs +59 -0
- package/dist/tenant/resolve.d.mts +2 -12
- package/dist/tenant/resolve.mjs +15 -29
- package/dist/tenant/types.d.mts +9 -9
- package/dist/testing/index.d.mts +2 -1
- package/dist/testing/types.d.mts +12 -112
- package/package.json +5 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ERROR_CODES } from "../errors/types.mjs";
|
|
2
|
+
//#region src/schema/standard-schema.ts
|
|
3
|
+
/**
|
|
4
|
+
* Standard Schema integration — the validator-agnostic validation slot.
|
|
5
|
+
*
|
|
6
|
+
* [Standard Schema](https://standardschema.dev) is the shared interface
|
|
7
|
+
* implemented by Zod 3.24+, Valibot 1.0+, ArkType 2.0+, Effect Schema and
|
|
8
|
+
* others. Vendoring the interface (officially encouraged — it's a
|
|
9
|
+
* types-only spec designed to be copied) keeps repo-core's zero-dependency
|
|
10
|
+
* guarantee while letting hosts plug ANY conforming validator into a
|
|
11
|
+
* repository:
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { z } from 'zod';
|
|
15
|
+
*
|
|
16
|
+
* const repo = createRepository(UserModel, {
|
|
17
|
+
* schema: z.object({ name: z.string(), email: z.string().email() }),
|
|
18
|
+
* });
|
|
19
|
+
* await repo.create({ name: 1 }); // throws HttpError 400 with validationErrors
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* `RepositoryBase` wires `schema` / `updateSchema` into `before:create` /
|
|
23
|
+
* `before:createMany` / `before:update` hooks at `HOOK_PRIORITY.VALIDATION`
|
|
24
|
+
* — after policy plugins (so tenant-stamped fields are present) and before
|
|
25
|
+
* cache/observability.
|
|
26
|
+
*/
|
|
27
|
+
/** Dot-path string from a Standard Schema issue path. */
|
|
28
|
+
function issuePath(issue) {
|
|
29
|
+
if (!issue.path || issue.path.length === 0) return "";
|
|
30
|
+
return issue.path.map((seg) => String(typeof seg === "object" && seg !== null && "key" in seg ? seg.key : seg)).join(".");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Validate `data` against a Standard Schema. Returns the schema's typed
|
|
34
|
+
* output (validators may coerce/transform) or throws an `HttpError` 400
|
|
35
|
+
* carrying `validationErrors` + structured `meta.issues` — the same wire
|
|
36
|
+
* shape every kit's own validation errors serialize to.
|
|
37
|
+
*/
|
|
38
|
+
async function validateStandardSchema(schema, data) {
|
|
39
|
+
let result = schema["~standard"].validate(data);
|
|
40
|
+
if (result instanceof Promise) result = await result;
|
|
41
|
+
if (result.issues) {
|
|
42
|
+
const validationErrors = result.issues.map((issue) => ({
|
|
43
|
+
validator: schema["~standard"].vendor,
|
|
44
|
+
error: issuePath(issue) ? `${issuePath(issue)}: ${issue.message}` : issue.message
|
|
45
|
+
}));
|
|
46
|
+
throw Object.assign(/* @__PURE__ */ new Error("Validation failed"), {
|
|
47
|
+
status: 400,
|
|
48
|
+
code: ERROR_CODES.VALIDATION,
|
|
49
|
+
validationErrors,
|
|
50
|
+
meta: { issues: result.issues.map((issue) => ({
|
|
51
|
+
path: issuePath(issue) || void 0,
|
|
52
|
+
message: issue.message
|
|
53
|
+
})) }
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return result.value;
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { validateStandardSchema };
|
|
@@ -10,18 +10,8 @@ import { ResolvedTenantConfig, TenantConfig } from "./types.mjs";
|
|
|
10
10
|
* runtime default — `Pick<TenantConfig, 'fieldType'>` extension preserves
|
|
11
11
|
* type-level alignment without forcing a runtime default change.
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* Resolve a possibly-partial {@link TenantConfig} against the defaults.
|
|
16
|
-
*
|
|
17
|
-
* - `false` → `enabled: false`, `strategy: 'none'`, `required: false`.
|
|
18
|
-
* - `true` / `undefined` → default field strategy.
|
|
19
|
-
* - Object with `strategy: 'custom'` → `resolve` is required; throws
|
|
20
|
-
* otherwise so the misconfiguration surfaces at boot, not runtime.
|
|
21
|
-
* - Object with `strategy: 'none'` → `enabled: false` (preserves
|
|
22
|
-
* user-supplied `tenantField` / `fieldType` / `ref` so the doc field
|
|
23
|
-
* stays correctly typed even with scoping off).
|
|
24
|
-
*/
|
|
13
|
+
type TenantDefaults = { [K in 'strategy' | 'enabled' | 'tenantField' | 'fieldType' | 'ref' | 'contextKey' | 'required']-?: Exclude<TenantConfig[K], undefined> };
|
|
14
|
+
declare const DEFAULT_TENANT_CONFIG: TenantDefaults;
|
|
25
15
|
declare function resolveTenantConfig(config?: TenantConfig | boolean): ResolvedTenantConfig;
|
|
26
16
|
//#endregion
|
|
27
17
|
export { DEFAULT_TENANT_CONFIG, resolveTenantConfig };
|
package/dist/tenant/resolve.mjs
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
//#region src/tenant/resolve.ts
|
|
2
|
-
/**
|
|
3
|
-
* Sensible defaults for a freshly-built package (field strategy).
|
|
4
|
-
*
|
|
5
|
-
* `fieldType: 'objectId'` is the recommended default for new Mongo-shaped
|
|
6
|
-
* kits because it enables `$lookup` / `.populate()`. Existing kits that
|
|
7
|
-
* historically defaulted to `'string'` (mongokit pre-3.x) keep their own
|
|
8
|
-
* runtime default — `Pick<TenantConfig, 'fieldType'>` extension preserves
|
|
9
|
-
* type-level alignment without forcing a runtime default change.
|
|
10
|
-
*/
|
|
11
2
|
const DEFAULT_TENANT_CONFIG = {
|
|
12
3
|
strategy: "field",
|
|
13
4
|
enabled: true,
|
|
@@ -17,17 +8,11 @@ const DEFAULT_TENANT_CONFIG = {
|
|
|
17
8
|
contextKey: "organizationId",
|
|
18
9
|
required: true
|
|
19
10
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* - Object with `strategy: 'custom'` → `resolve` is required; throws
|
|
26
|
-
* otherwise so the misconfiguration surfaces at boot, not runtime.
|
|
27
|
-
* - Object with `strategy: 'none'` → `enabled: false` (preserves
|
|
28
|
-
* user-supplied `tenantField` / `fieldType` / `ref` so the doc field
|
|
29
|
-
* stays correctly typed even with scoping off).
|
|
30
|
-
*/
|
|
11
|
+
function stripUndefined(obj) {
|
|
12
|
+
const out = {};
|
|
13
|
+
for (const [k, v] of Object.entries(obj)) if (v !== void 0) out[k] = v;
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
31
16
|
function resolveTenantConfig(config) {
|
|
32
17
|
if (config === false) return {
|
|
33
18
|
...DEFAULT_TENANT_CONFIG,
|
|
@@ -36,33 +21,34 @@ function resolveTenantConfig(config) {
|
|
|
36
21
|
required: false
|
|
37
22
|
};
|
|
38
23
|
if (config === true || config === void 0) return { ...DEFAULT_TENANT_CONFIG };
|
|
39
|
-
const
|
|
40
|
-
const
|
|
24
|
+
const cleaned = stripUndefined(config);
|
|
25
|
+
const strategy = cleaned.strategy ?? (cleaned.enabled === false ? "none" : "field");
|
|
26
|
+
const contextKey = cleaned.contextKey ?? cleaned.tenantField ?? DEFAULT_TENANT_CONFIG.contextKey;
|
|
41
27
|
if (strategy === "none") return {
|
|
42
28
|
...DEFAULT_TENANT_CONFIG,
|
|
43
|
-
...
|
|
29
|
+
...cleaned,
|
|
44
30
|
contextKey,
|
|
45
31
|
strategy: "none",
|
|
46
32
|
enabled: false,
|
|
47
33
|
required: false
|
|
48
34
|
};
|
|
49
35
|
if (strategy === "custom") {
|
|
50
|
-
if (typeof
|
|
36
|
+
if (typeof cleaned.resolve !== "function") throw new Error("[repo-core] TenantConfig.strategy 'custom' requires a 'resolve' function");
|
|
51
37
|
return {
|
|
52
38
|
...DEFAULT_TENANT_CONFIG,
|
|
53
|
-
...
|
|
39
|
+
...cleaned,
|
|
54
40
|
contextKey,
|
|
55
41
|
strategy: "custom",
|
|
56
|
-
enabled:
|
|
57
|
-
resolve:
|
|
42
|
+
enabled: cleaned.enabled ?? true,
|
|
43
|
+
resolve: cleaned.resolve
|
|
58
44
|
};
|
|
59
45
|
}
|
|
60
46
|
return {
|
|
61
47
|
...DEFAULT_TENANT_CONFIG,
|
|
62
|
-
...
|
|
48
|
+
...cleaned,
|
|
63
49
|
contextKey,
|
|
64
50
|
strategy: "field",
|
|
65
|
-
enabled:
|
|
51
|
+
enabled: cleaned.enabled ?? true
|
|
66
52
|
};
|
|
67
53
|
}
|
|
68
54
|
//#endregion
|
package/dist/tenant/types.d.mts
CHANGED
|
@@ -50,7 +50,7 @@ interface TenantConfig {
|
|
|
50
50
|
*
|
|
51
51
|
* @default 'field'
|
|
52
52
|
*/
|
|
53
|
-
strategy?: TenantStrategy;
|
|
53
|
+
strategy?: TenantStrategy | undefined;
|
|
54
54
|
/**
|
|
55
55
|
* Whether tenant scoping is active. When `false`, the package runs in
|
|
56
56
|
* single-tenant mode — no filter injection, no tenant field on documents.
|
|
@@ -58,27 +58,27 @@ interface TenantConfig {
|
|
|
58
58
|
*
|
|
59
59
|
* @default true
|
|
60
60
|
*/
|
|
61
|
-
enabled?: boolean;
|
|
61
|
+
enabled?: boolean | undefined;
|
|
62
62
|
/**
|
|
63
63
|
* Document / column field name that stores the tenant id. Used when
|
|
64
64
|
* `strategy === 'field'`.
|
|
65
65
|
*
|
|
66
66
|
* @default 'organizationId'
|
|
67
67
|
*/
|
|
68
|
-
tenantField?: string;
|
|
68
|
+
tenantField?: string | undefined;
|
|
69
69
|
/**
|
|
70
70
|
* How to store / cast the tenant id.
|
|
71
71
|
*
|
|
72
72
|
* @default 'objectId'
|
|
73
73
|
*/
|
|
74
|
-
fieldType?: TenantFieldType;
|
|
74
|
+
fieldType?: TenantFieldType | undefined;
|
|
75
75
|
/**
|
|
76
76
|
* Mongoose ref for `'objectId'` types. Ignored by SQL kits and when
|
|
77
77
|
* `fieldType === 'string'`.
|
|
78
78
|
*
|
|
79
79
|
* @default 'organization'
|
|
80
80
|
*/
|
|
81
|
-
ref?: string;
|
|
81
|
+
ref?: string | undefined;
|
|
82
82
|
/**
|
|
83
83
|
* Which key on the repository context to read the tenant id from.
|
|
84
84
|
*
|
|
@@ -92,14 +92,14 @@ interface TenantConfig {
|
|
|
92
92
|
*
|
|
93
93
|
* @default tenantField ?? 'organizationId'
|
|
94
94
|
*/
|
|
95
|
-
contextKey?: string;
|
|
95
|
+
contextKey?: string | undefined;
|
|
96
96
|
/**
|
|
97
97
|
* Whether the field is required. When `false`, the package permits
|
|
98
98
|
* unscoped / cross-tenant reads (typically only for admin paths).
|
|
99
99
|
*
|
|
100
100
|
* @default true
|
|
101
101
|
*/
|
|
102
|
-
required?: boolean;
|
|
102
|
+
required?: boolean | undefined;
|
|
103
103
|
/**
|
|
104
104
|
* Custom resolver — called when `strategy === 'custom'` to produce the
|
|
105
105
|
* filter object injected into queries. Packages pass the request /
|
|
@@ -121,7 +121,7 @@ interface TenantConfig {
|
|
|
121
121
|
* }
|
|
122
122
|
* ```
|
|
123
123
|
*/
|
|
124
|
-
resolve?: (ctx: Record<string, unknown>) => Record<string, unknown
|
|
124
|
+
resolve?: (ctx: Record<string, unknown>) => Record<string, unknown> | undefined;
|
|
125
125
|
}
|
|
126
126
|
/**
|
|
127
127
|
* Resolved shape returned by `resolveTenantConfig`. Always includes the
|
|
@@ -136,7 +136,7 @@ type ResolvedTenantConfig = {
|
|
|
136
136
|
ref: string;
|
|
137
137
|
contextKey: string;
|
|
138
138
|
required: boolean;
|
|
139
|
-
resolve?: TenantConfig['resolve'];
|
|
139
|
+
resolve?: TenantConfig['resolve'] | undefined;
|
|
140
140
|
};
|
|
141
141
|
//#endregion
|
|
142
142
|
export { ResolvedTenantConfig, TenantConfig, TenantFieldType, TenantStrategy };
|
package/dist/testing/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { AggregateOpsSupport
|
|
1
|
+
import { AggregateOpsSupport } from "../repository/capabilities.mjs";
|
|
2
|
+
import { ConformanceContext, ConformanceDoc, ConformanceFeatures, ConformanceHarness } from "./types.mjs";
|
|
2
3
|
import { runStandardRepoConformance } from "./conformance.mjs";
|
|
3
4
|
import { LockConformanceHarness, runLockAdapterConformance } from "./lock-conformance.mjs";
|
|
4
5
|
export { type AggregateOpsSupport, type ConformanceContext, type ConformanceDoc, type ConformanceFeatures, type ConformanceHarness, type LockConformanceHarness, runLockAdapterConformance, runStandardRepoConformance };
|
package/dist/testing/types.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AggregateOpsSupport, RepoCapabilities } from "../repository/capabilities.mjs";
|
|
1
2
|
import { MinimalRepo, StandardRepo } from "../repository/types.mjs";
|
|
2
3
|
|
|
3
4
|
//#region src/testing/types.d.ts
|
|
@@ -27,119 +28,18 @@ interface ConformanceDoc {
|
|
|
27
28
|
createdAt: string;
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
30
|
-
* Per-
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
31
|
+
* Per-backend feature flags — an alias of the runtime
|
|
32
|
+
* {@link RepoCapabilities} descriptor (one shape, no drift). Scenarios
|
|
33
|
+
* that exercise a non-universal capability (transactions in D1, upsert
|
|
34
|
+
* in narrow stores) check the flag and `it.skip` on the off branch — so
|
|
35
|
+
* the suite runs on every environment without "optional test failed"
|
|
36
|
+
* noise.
|
|
36
37
|
*
|
|
37
|
-
* **
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* change.
|
|
41
|
-
*
|
|
42
|
-
* **Naming convention.** Flag names match the IR field they gate
|
|
43
|
-
* (`percentile` → `AggMeasure.op === 'percentile'`). When in doubt,
|
|
44
|
-
* grep the IR types and use the same identifier.
|
|
45
|
-
*/
|
|
46
|
-
interface AggregateOpsSupport {
|
|
47
|
-
/**
|
|
48
|
-
* `{ op: 'percentile', field, p }` measure. Mongokit (Mongo 7+)
|
|
49
|
-
* supports it; sqlitekit throws by design (no native function).
|
|
50
|
-
* Hosts targeting percentile dashboards pin to a kit that supports it.
|
|
51
|
-
*/
|
|
52
|
-
percentile?: boolean;
|
|
53
|
-
/**
|
|
54
|
-
* `{ op: 'stddev', field }` / `{ op: 'stddevPop', field }` measures.
|
|
55
|
-
* Mongokit supports both via native `$stdDevSamp` / `$stdDevPop`
|
|
56
|
-
* (Welford). Sqlitekit throws — SQLite has no native STDDEV and
|
|
57
|
-
* the computational formula is numerically unstable. Hosts pin
|
|
58
|
-
* to mongokit / future pgkit when stddev is load-bearing.
|
|
59
|
-
*/
|
|
60
|
-
stddev?: boolean;
|
|
61
|
-
/**
|
|
62
|
-
* `topN: { partitionBy, sortBy, limit, ties }` filter. Both
|
|
63
|
-
* mongokit and sqlitekit support it as of repo-core 0.4.x; the
|
|
64
|
-
* flag exists for future kits that may not ship window-function
|
|
65
|
-
* equivalents.
|
|
66
|
-
*/
|
|
67
|
-
topN?: boolean;
|
|
68
|
-
/**
|
|
69
|
-
* `dateBuckets: { ..., interval: { every, unit } }` custom-bin
|
|
70
|
-
* form. Kits that only support named-bucket form can leave this
|
|
71
|
-
* `false`; tests for `'minute'` / `'hour'` named intervals are
|
|
72
|
-
* gated separately via `dateBucketSubMinute`.
|
|
73
|
-
*/
|
|
74
|
-
customDateBuckets?: boolean;
|
|
75
|
-
/**
|
|
76
|
-
* Sub-day-granularity named buckets (`'minute'` / `'hour'`).
|
|
77
|
-
* Older kits may only support day+ named intervals; flag exists
|
|
78
|
-
* to gate those scenarios cleanly.
|
|
79
|
-
*/
|
|
80
|
-
dateBucketSubMinute?: boolean;
|
|
81
|
-
/**
|
|
82
|
-
* Per-request `cache?: AggCacheOptions` slot — TTL / tags / SWR /
|
|
83
|
-
* bypass / `repo.invalidateAggregateCache(tags)`. Both mongokit
|
|
84
|
-
* and sqlitekit support it as of repo-core 0.4.x. Future kits
|
|
85
|
-
* without the wiring can leave this false to skip cache scenarios.
|
|
86
|
-
*
|
|
87
|
-
* Independent of which CACHE BACKEND the harness wires — test
|
|
88
|
-
* scenarios construct their own `createMemoryCacheAdapter()` so
|
|
89
|
-
* this flag is purely "does the kit honour the request slot".
|
|
90
|
-
*/
|
|
91
|
-
cache?: boolean;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Per-backend feature flags. Scenarios that exercise a non-universal
|
|
95
|
-
* capability (transactions in D1, upsert in narrow stores) check the
|
|
96
|
-
* flag and `it.skip` on the off branch — so the suite runs on every
|
|
97
|
-
* environment without "optional test failed" noise.
|
|
38
|
+
* **Single source of truth.** Kits declare `repo.capabilities` at
|
|
39
|
+
* runtime and pass the SAME object as the harness's `features` — what a
|
|
40
|
+
* kit claims to support is exactly what the conformance suite verifies.
|
|
98
41
|
*/
|
|
99
|
-
|
|
100
|
-
/** `withTransaction(fn)` — D1 throws, standalone Mongo throws 263. */
|
|
101
|
-
transactions: boolean;
|
|
102
|
-
/**
|
|
103
|
-
* True if calling `withTransaction` inside another `withTransaction`
|
|
104
|
-
* callback is expected to work. Mongo's driver supports it via the
|
|
105
|
-
* same session; SQL drivers typically reject it. Either behavior is
|
|
106
|
-
* valid — the scenario asserts whichever the harness declares.
|
|
107
|
-
*/
|
|
108
|
-
nestedTransactions: boolean;
|
|
109
|
-
/** `findOneAndUpdate` with upsert: true. */
|
|
110
|
-
upsert: boolean;
|
|
111
|
-
/** `isDuplicateKeyError(err)` classifier. */
|
|
112
|
-
duplicateKeyError: boolean;
|
|
113
|
-
/** `distinct(field)`. */
|
|
114
|
-
distinct: boolean;
|
|
115
|
-
/**
|
|
116
|
-
* Portable `aggregate({ measures, groupBy, having })`. Coarse
|
|
117
|
-
* top-level flag — gates the entire `describe('aggregate')` block.
|
|
118
|
-
* Per-op flags live on `aggregateOps` for asymmetric capabilities
|
|
119
|
-
* (percentile, custom date bins, etc.) that some kits skip while
|
|
120
|
-
* still supporting the core aggregate surface.
|
|
121
|
-
*/
|
|
122
|
-
aggregate: boolean;
|
|
123
|
-
/**
|
|
124
|
-
* Per-op feature matrix for the aggregate surface. Optional —
|
|
125
|
-
* absent matrix or absent key both mean "not supported", so kits
|
|
126
|
-
* opt INTO scenarios for ops they implement. This avoids the
|
|
127
|
-
* trap where a future kit silently fails percentile tests because
|
|
128
|
-
* it forgot to set the flag.
|
|
129
|
-
*/
|
|
130
|
-
aggregateOps?: AggregateOpsSupport;
|
|
131
|
-
/** `getOrCreate(filter, data)`. */
|
|
132
|
-
getOrCreate: boolean;
|
|
133
|
-
/** `count(filter)` and `exists(filter)`. */
|
|
134
|
-
countAndExists: boolean;
|
|
135
|
-
/**
|
|
136
|
-
* `purgeByField(field, value, strategy, options)` — compliance-grade
|
|
137
|
-
* tenant cleanup primitive. Both mongokit and sqlitekit ship this as
|
|
138
|
-
* of repo-core 0.x. Future kits without it leave the flag absent
|
|
139
|
-
* (defaults to false) and skip the cleanup scenarios.
|
|
140
|
-
*/
|
|
141
|
-
purgeByField?: boolean;
|
|
142
|
-
}
|
|
42
|
+
type ConformanceFeatures = RepoCapabilities;
|
|
143
43
|
/**
|
|
144
44
|
* One-shot context produced by `harness.setup()`. Scenarios receive a
|
|
145
45
|
* fresh context per test — the harness is responsible for isolation
|
|
@@ -214,4 +114,4 @@ interface ConformanceHarness<TDoc extends ConformanceDoc = ConformanceDoc> {
|
|
|
214
114
|
makeDoc(overrides?: Partial<ConformanceDoc>): Partial<TDoc>;
|
|
215
115
|
}
|
|
216
116
|
//#endregion
|
|
217
|
-
export {
|
|
117
|
+
export { ConformanceContext, ConformanceDoc, ConformanceFeatures, ConformanceHarness };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/repo-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
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
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -54,6 +54,10 @@
|
|
|
54
54
|
"types": "./dist/cache/index.d.mts",
|
|
55
55
|
"default": "./dist/cache/index.mjs"
|
|
56
56
|
},
|
|
57
|
+
"./events": {
|
|
58
|
+
"types": "./dist/events/index.d.mts",
|
|
59
|
+
"default": "./dist/events/index.mjs"
|
|
60
|
+
},
|
|
57
61
|
"./schema": {
|
|
58
62
|
"types": "./dist/schema/index.d.mts",
|
|
59
63
|
"default": "./dist/schema/index.mjs"
|