@classytic/repo-core 0.8.1 → 0.10.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/adapter/types.d.mts +0 -1
  3. package/dist/adapter/widen.d.mts +0 -1
  4. package/dist/aggregate/normalize.d.mts +0 -1
  5. package/dist/better-auth/index.mjs +1 -1
  6. package/dist/cache/engine.d.mts +0 -1
  7. package/dist/cache/memory-adapter.d.mts +0 -1
  8. package/dist/cache/memory-adapter.mjs +13 -0
  9. package/dist/cache/plugin/context.mjs +1 -1
  10. package/dist/cache/plugin/index.d.mts +3 -4
  11. package/dist/cache/plugin/index.mjs +1 -1
  12. package/dist/cache/timeout-adapter.d.mts +0 -1
  13. package/dist/context/index.d.mts +1 -1
  14. package/dist/context/types.d.mts +0 -1
  15. package/dist/errors/contract.d.mts +4 -4
  16. package/dist/errors/contract.mjs +7 -4
  17. package/dist/errors/create-error.d.mts +0 -1
  18. package/dist/errors/duplicate-key.d.mts +0 -1
  19. package/dist/errors/schema.d.mts +27 -27
  20. package/dist/errors/types.d.mts +24 -11
  21. package/dist/events/emit.d.mts +0 -1
  22. package/dist/filter/builders.d.mts +2 -3
  23. package/dist/filter/builders.mjs +1 -1
  24. package/dist/filter/from-record.d.mts +0 -1
  25. package/dist/filter/from-record.mjs +2 -2
  26. package/dist/filter/guard.d.mts +0 -1
  27. package/dist/filter/guard.mjs +1 -1
  28. package/dist/filter/index.d.mts +1 -1
  29. package/dist/filter/index.mjs +1 -1
  30. package/dist/filter/match.d.mts +0 -1
  31. package/dist/filter/scope.d.mts +0 -1
  32. package/dist/filter/walk.d.mts +0 -1
  33. package/dist/hooks/engine.d.mts +0 -1
  34. package/dist/hooks/events.d.mts +51 -51
  35. package/dist/hooks/priority.d.mts +8 -4
  36. package/dist/hooks/priority.mjs +9 -0
  37. package/dist/lookup/index.d.mts +1 -1
  38. package/dist/lookup/types.d.mts +0 -1
  39. package/dist/operations/registry.d.mts +0 -1
  40. package/dist/pagination/canonical.d.mts +0 -1
  41. package/dist/pagination/cursor.d.mts +0 -1
  42. package/dist/pagination/keyset.d.mts +0 -1
  43. package/dist/pagination/offset.d.mts +0 -1
  44. package/dist/plugins/tenant-helpers.d.mts +0 -1
  45. package/dist/query-parser/coerce.d.mts +1 -2
  46. package/dist/query-parser/coerce.mjs +2 -2
  47. package/dist/query-parser/parse-url.d.mts +0 -1
  48. package/dist/query-parser/parse-url.mjs +2 -2
  49. package/dist/query-parser/reserved.mjs +1 -1
  50. package/dist/query-parser/types.d.mts +0 -1
  51. package/dist/repository/archive.d.mts +0 -1
  52. package/dist/repository/base.d.mts +0 -1
  53. package/dist/repository/distribution.d.mts +0 -1
  54. package/dist/repository/options.d.mts +1 -1
  55. package/dist/repository/plugin-types.d.mts +0 -1
  56. package/dist/repository/purge.d.mts +0 -1
  57. package/dist/repository/types.d.mts +38 -10
  58. package/dist/schema/field-rules.d.mts +0 -1
  59. package/dist/schema/field-rules.mjs +1 -1
  60. package/dist/schema/generator.d.mts +0 -1
  61. package/dist/schema/types.d.mts +14 -6
  62. package/dist/sync/index.d.mts +1 -1
  63. package/dist/sync/index.mjs +2 -0
  64. package/dist/tenant/resolve.d.mts +1 -2
  65. package/dist/testing/conformance.d.mts +0 -1
  66. package/dist/testing/conformance.mjs +1 -1
  67. package/dist/testing/lock-conformance.d.mts +0 -1
  68. package/dist/testing/types.d.mts +1 -2
  69. package/dist/update/builders.d.mts +0 -1
  70. package/dist/update/compile.d.mts +0 -1
  71. package/dist/update/guard.d.mts +0 -1
  72. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -4,6 +4,57 @@ 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.10.0] - 2026-07-13
8
+
9
+ ### Added — `ValidationErrorMeta.path` + `.meta` (field-scoped validation errors)
10
+
11
+ - **`ValidationErrorMeta.path?: string`** — dot-path to the offending field
12
+ (e.g. `'journalItems.2.account'`). Set by kits with field-scoped validation
13
+ (ledger's `FieldError`, Mongoose `ValidationError`). Absent when the kit doesn't
14
+ have a field path.
15
+ - **`ValidationErrorMeta.meta?: Readonly<Record<string, unknown>>`** — non-PII
16
+ structured extra for the field (e.g. `{ value: 'bad' }`). Never include secrets.
17
+ - **`toErrorContract`** now forwards `path` and `meta` from each `validationErrors`
18
+ entry onto the wire `ErrorDetail`. Previously only `code` and `message` were mapped;
19
+ field paths were silently dropped. No breaking change — both fields are optional and
20
+ additive. Kits that don't set them produce the same wire shape as before.
21
+
22
+ ## [0.9.0] - 2026-07-11
23
+
24
+ ### Added — `StandardRepo.getByIds` (batch point-read)
25
+
26
+ - **`getByIds?(ids: readonly string[], options?: FindAllOptions): Promise<Map<string, TDoc>>`**
27
+ added to `StandardRepo` — the `$in` / `IN (...)` counterpart to `getById`. The N+1
28
+ killer for callers resolving many ids in one tick (order-line snapshotting, dashboard
29
+ row enrichment, reference expansion).
30
+
31
+ **Contract:**
32
+ - Kit de-duplicates ids before the driver round-trip.
33
+ - Ids with no matching doc are ABSENT from the returned `Map` — never throw on a miss.
34
+ - Structurally invalid ids are treated as misses (one malformed id must never fail the
35
+ batch).
36
+ - Tenant scoping, soft-delete, and hooks apply exactly as they would to `getById`.
37
+ - Empty input → empty Map, no round-trip.
38
+ - Optional: kits adopt incrementally. Callers feature-detect
39
+ (`repo.getByIds ?? per-id fallback`) until their kit floor ships it.
40
+ - Sizing is backend-bound (Mongo: 16 MB query document); keep batches ≤ ~10k ids and
41
+ chunk beyond.
42
+
43
+ - **`events.ts` clarification** — `getByIds` has no `BEFORE_GET_BY_IDS` event by design.
44
+ It routes through `findAll`, so observers see the batch as `before:findAll` / `after:findAll`
45
+ with an `$in` filter. The comment guards against accidentally adding a separate event.
46
+
47
+ - **New type-level contract test** (`tests/unit/repository/get-by-ids-contract.test.ts`) —
48
+ pins the `getByIds` shape for kits implementing it: `Map<string, TDoc>` keyed by
49
+ stringified id, `readonly string[]` input. Verifies that kits without `getByIds` still
50
+ conform (the member is optional).
51
+
52
+ ### Changed
53
+
54
+ - `ChangesPage.changes` type: `ReadonlyArray<ChangeEntry<TDoc>>` → `readonly ChangeEntry<TDoc>[]`
55
+ (canonical form — functionally identical).
56
+ - devDeps: `tsdown ^0.21.8 → ^0.22.5`, `typescript ^6.0.3 → ^7.0.2`.
57
+
7
58
  ## [0.8.1] - 2026-07-11
8
59
 
9
60
  ### Docs — `DataAdapter.close()` ownership rule
@@ -1,6 +1,5 @@
1
1
  import { DeleteResult, MinimalRepo, StandardRepo } from "../repository/types.mjs";
2
2
  import { SchemaBuilderOptions } from "../schema/types.mjs";
3
-
4
3
  //#region src/adapter/types.d.ts
5
4
  /**
6
5
  * Cross-kit repository contract.
@@ -1,5 +1,4 @@
1
1
  import { AdapterRepositoryInput, RepositoryLike } from "./types.mjs";
2
-
3
2
  //#region src/adapter/widen.d.ts
4
3
  /**
5
4
  * Widen a permissive `AdapterRepositoryInput<TDoc>` to the strict
@@ -1,5 +1,4 @@
1
1
  import { AggRequest } from "../repository/types.mjs";
2
-
3
2
  //#region src/aggregate/normalize.d.ts
4
3
  /**
5
4
  * Normalize `AggRequest['groupBy']` into a readonly string array.
@@ -53,7 +53,7 @@ function pluralizeBetterAuthCollection(name) {
53
53
  */
54
54
  function resolveBetterAuthCollections(options = {}) {
55
55
  const { plugins = [], extraCollections = [], usePlural = false, modelOverrides = {} } = options;
56
- const pluginSet = new Set(["core", ...plugins]);
56
+ const pluginSet = /* @__PURE__ */ new Set(["core", ...plugins]);
57
57
  const collected = [];
58
58
  for (const key of pluginSet) for (const name of BA_COLLECTIONS_BY_PLUGIN[key]) collected.push(name);
59
59
  for (const name of extraCollections) collected.push(name);
@@ -1,6 +1,5 @@
1
1
  import { CacheReadResult, ResolvedCacheOptions } from "./options.mjs";
2
2
  import { CacheAdapter } from "./types.mjs";
3
-
4
3
  //#region src/cache/engine.d.ts
5
4
  interface CacheEngineOptions {
6
5
  /** Cache key namespace prefix. Default: `'rc'`. */
@@ -1,5 +1,4 @@
1
1
  import { CacheAdapter } from "./types.mjs";
2
-
3
2
  //#region src/cache/memory-adapter.d.ts
4
3
  /** Minimal in-memory `Map`-backed adapter with per-key TTL + prefix invalidation. */
5
4
  declare function createMemoryCacheAdapter(): CacheAdapter;
@@ -36,6 +36,13 @@ function createMemoryCacheAdapter() {
36
36
  const prefix = pattern.endsWith("*") ? pattern.slice(0, -1) : pattern;
37
37
  for (const key of store.keys()) if (key.startsWith(prefix)) store.delete(key);
38
38
  },
39
+ /**
40
+ * Atomic add-to-set — `O(M)` per call where M is the number of
41
+ * new members. Stores the value as `Set<string>` internally for
42
+ * `O(1)` membership checks; `get` exposes it back as an array for
43
+ * cross-adapter portability. JS's single-thread guarantee makes
44
+ * the read-mutate-write race-free without locks.
45
+ */
39
46
  addToSet(key, members, ttlSeconds = 60) {
40
47
  const existing = readUnexpired(key);
41
48
  let set;
@@ -55,6 +62,12 @@ function createMemoryCacheAdapter() {
55
62
  }
56
63
  return added;
57
64
  },
65
+ /**
66
+ * Atomic increment — JS's single-threaded execution model makes
67
+ * this race-free without locks. Mirrors Redis's `INCRBY key by` +
68
+ * `EXPIRE key ttlSeconds NX`: TTL is applied only on key creation,
69
+ * existing keys keep their original expiry.
70
+ */
58
71
  increment(key, by = 1, ttlSeconds = 60) {
59
72
  const existing = readUnexpired(key);
60
73
  const next = (existing && typeof existing.value === "number" && Number.isFinite(existing.value) ? existing.value : 0) + by;
@@ -99,7 +99,7 @@ function stripAggOperationalSlots(value) {
99
99
  return rest;
100
100
  }
101
101
  /** Aggregate ops carry their cache slot inside the AggRequest IR. */
102
- const AGGREGATE_OPS = new Set(["aggregate", "aggregatePaginate"]);
102
+ const AGGREGATE_OPS = /* @__PURE__ */ new Set(["aggregate", "aggregatePaginate"]);
103
103
  /**
104
104
  * Extract per-call `CacheOptions` from a hook context. Three valid
105
105
  * locations covered (kit-dependent):
@@ -3,12 +3,11 @@ import { CacheOptions, CacheReadResult } from "../options.mjs";
3
3
  import { CacheAdapter } from "../types.mjs";
4
4
  import { CacheEngine } from "../engine.mjs";
5
5
  import { DEFAULT_SHAPE_KEYS_BY_OP } from "./context.mjs";
6
-
7
6
  //#region src/cache/plugin/index.d.ts
8
7
  /** Default read ops the plugin caches. Kits may override per resource. */
9
- declare const DEFAULT_CACHEABLE_OPS: readonly ["getById", "getAll", "getOne", "getByQuery", "count", "exists", "distinct", "aggregate", "aggregatePaginate"];
8
+ declare const DEFAULT_CACHEABLE_OPS: readonly ['getById', 'getAll', 'getOne', 'getByQuery', 'count', 'exists', 'distinct', 'aggregate', 'aggregatePaginate'];
10
9
  /** Default mutating ops that bump version + invalidate tags on success. */
11
- declare const DEFAULT_INVALIDATING_OPS: readonly ["create", "createMany", "update", "updateMany", "findOneAndUpdate", "upsert", "delete", "deleteMany", "restore", "claim", "claimVersion", "increment", "bulkWrite"];
10
+ declare const DEFAULT_INVALIDATING_OPS: readonly ['create', 'createMany', 'update', 'updateMany', 'findOneAndUpdate', 'upsert', 'delete', 'deleteMany', 'restore', 'claim', 'claimVersion', 'increment', 'bulkWrite'];
12
11
  /** Observability callbacks — pipe to metrics, traces, or stdout. */
13
12
  interface LogCallbacks {
14
13
  onHit?: (key: string, op: string, ageSeconds: number) => void;
@@ -83,4 +82,4 @@ interface RepositoryCacheHandle {
83
82
  */
84
83
  declare function cachePlugin(options: RepositoryCachePluginOptions): Plugin;
85
84
  //#endregion
86
- export { DEFAULT_CACHEABLE_OPS, DEFAULT_INVALIDATING_OPS, LogCallbacks, RepositoryCacheHandle, RepositoryCachePluginOptions, cachePlugin };
85
+ export { DEFAULT_CACHEABLE_OPS, DEFAULT_INVALIDATING_OPS, DEFAULT_SHAPE_KEYS_BY_OP, LogCallbacks, RepositoryCacheHandle, RepositoryCachePluginOptions, cachePlugin };
@@ -75,4 +75,4 @@ function cachePlugin(options) {
75
75
  };
76
76
  }
77
77
  //#endregion
78
- export { DEFAULT_CACHEABLE_OPS, DEFAULT_INVALIDATING_OPS, cachePlugin };
78
+ export { DEFAULT_CACHEABLE_OPS, DEFAULT_INVALIDATING_OPS, DEFAULT_SHAPE_KEYS_BY_OP, cachePlugin };
@@ -1,5 +1,4 @@
1
1
  import { CacheAdapter } from "./types.mjs";
2
-
3
2
  //#region src/cache/timeout-adapter.d.ts
4
3
  declare class CacheTimeoutError extends Error {
5
4
  readonly op: string;
@@ -1,2 +1,2 @@
1
1
  import { RepositoryContext } from "./types.mjs";
2
- export { type RepositoryContext };
2
+ export type { RepositoryContext };
@@ -1,5 +1,4 @@
1
1
  import { Filter } from "../filter/types.mjs";
2
-
3
2
  //#region src/context/types.d.ts
4
3
  /** The canonical lifecycle-hook context. */
5
4
  interface RepositoryContext {
@@ -1,5 +1,4 @@
1
1
  import { ErrorCode, ErrorContract } from "./types.mjs";
2
-
3
2
  //#region src/errors/contract.d.ts
4
3
  /**
5
4
  * Map an HTTP status code to the canonical {@link ErrorCode}. Used as a
@@ -24,9 +23,10 @@ declare function statusToErrorCode(status: number): ErrorCode;
24
23
  * `validationErrors` (mongokit-shaped throwable field) is mapped into the
25
24
  * canonical `details` array so wire consumers see one shape regardless
26
25
  * of which kit threw the error. Each `validationErrors[i]` becomes an
27
- * `ErrorDetail` with `code: validator`, `message: error`, `path` left
28
- * unset (kits that have field paths set them in their own ErrorDetail
29
- * mapping).
26
+ * `ErrorDetail` with `code: validator`, `message: error`, plus `path` and
27
+ * `meta` when the throwing kit populates them (field-scoped validators
28
+ * like ledger's `FieldError` — so a kernel's rich field errors reach the
29
+ * wire natively, with NO per-host errorMapper).
30
30
  *
31
31
  * `duplicate.fields` is similarly flattened into `details` with the
32
32
  * duplicate-key code so unique-constraint failures look uniform on the
@@ -36,9 +36,10 @@ function statusToErrorCode(status) {
36
36
  * `validationErrors` (mongokit-shaped throwable field) is mapped into the
37
37
  * canonical `details` array so wire consumers see one shape regardless
38
38
  * of which kit threw the error. Each `validationErrors[i]` becomes an
39
- * `ErrorDetail` with `code: validator`, `message: error`, `path` left
40
- * unset (kits that have field paths set them in their own ErrorDetail
41
- * mapping).
39
+ * `ErrorDetail` with `code: validator`, `message: error`, plus `path` and
40
+ * `meta` when the throwing kit populates them (field-scoped validators
41
+ * like ledger's `FieldError` — so a kernel's rich field errors reach the
42
+ * wire natively, with NO per-host errorMapper).
42
43
  *
43
44
  * `duplicate.fields` is similarly flattened into `details` with the
44
45
  * duplicate-key code so unique-constraint failures look uniform on the
@@ -59,8 +60,10 @@ function toErrorContract(error) {
59
60
  };
60
61
  const details = [];
61
62
  if (Array.isArray(e.validationErrors)) for (const v of e.validationErrors) details.push({
63
+ ...v.path ? { path: v.path } : {},
62
64
  code: v.validator,
63
- message: v.error
65
+ message: v.error,
66
+ ...v.meta ? { meta: v.meta } : {}
64
67
  });
65
68
  if (e.duplicate?.fields?.length) for (const field of e.duplicate.fields) details.push({
66
69
  path: field,
@@ -1,5 +1,4 @@
1
1
  import { HttpError } from "./types.mjs";
2
-
3
2
  //#region src/errors/create-error.d.ts
4
3
  /**
5
4
  * Create an error with an HTTP status code attached.
@@ -1,5 +1,4 @@
1
1
  import { DuplicateKeyMeta, HttpError } from "./types.mjs";
2
-
3
2
  //#region src/errors/duplicate-key.d.ts
4
3
  /** Predicate shape kits implement and repositories expose as `isDuplicateKeyError`. */
5
4
  type IsDuplicateKeyErrorFn = (err: unknown) => boolean;
@@ -17,24 +17,24 @@
17
17
  * {@link ./types.ts}.
18
18
  */
19
19
  declare const errorDetailSchema: {
20
- readonly type: "object";
20
+ readonly type: 'object';
21
21
  readonly properties: {
22
22
  readonly path: {
23
- readonly type: "string";
23
+ readonly type: 'string';
24
24
  readonly description: "Dot-path to the offending field, e.g. 'lines.0.quantity'.";
25
25
  };
26
26
  readonly code: {
27
- readonly type: "string";
27
+ readonly type: 'string';
28
28
  };
29
29
  readonly message: {
30
- readonly type: "string";
30
+ readonly type: 'string';
31
31
  };
32
32
  readonly meta: {
33
- readonly type: "object";
34
- readonly description: "Non-PII per-detail diagnostics (safe to log + return).";
33
+ readonly type: 'object';
34
+ readonly description: 'Non-PII per-detail diagnostics (safe to log + return).';
35
35
  };
36
36
  };
37
- readonly required: readonly ["code", "message"];
37
+ readonly required: readonly ['code', 'message'];
38
38
  };
39
39
  /**
40
40
  * Canonical error response. Mirrors `ErrorContract` in {@link ./types.ts}.
@@ -48,54 +48,54 @@ declare const errorDetailSchema: {
48
48
  * a separate path from success — HTTP status discriminates.
49
49
  */
50
50
  declare const errorContractSchema: {
51
- readonly type: "object";
51
+ readonly type: 'object';
52
52
  readonly properties: {
53
53
  readonly code: {
54
- readonly type: "string";
54
+ readonly type: 'string';
55
55
  readonly description: "Hierarchical machine-readable code (e.g. 'arc.not_found').";
56
56
  };
57
57
  readonly message: {
58
- readonly type: "string";
59
- readonly description: "Human-readable, safe-for-client message.";
58
+ readonly type: 'string';
59
+ readonly description: 'Human-readable, safe-for-client message.';
60
60
  };
61
61
  readonly status: {
62
- readonly type: "integer";
63
- readonly description: "Suggested HTTP status code (hosts may override).";
62
+ readonly type: 'integer';
63
+ readonly description: 'Suggested HTTP status code (hosts may override).';
64
64
  };
65
65
  readonly details: {
66
- readonly type: "array";
67
- readonly description: "Field-scoped structured details (validation failures, duplicate keys, multi-code domain errors).";
66
+ readonly type: 'array';
67
+ readonly description: 'Field-scoped structured details (validation failures, duplicate keys, multi-code domain errors).';
68
68
  readonly items: {
69
- readonly type: "object";
69
+ readonly type: 'object';
70
70
  readonly properties: {
71
71
  readonly path: {
72
- readonly type: "string";
72
+ readonly type: 'string';
73
73
  readonly description: "Dot-path to the offending field, e.g. 'lines.0.quantity'.";
74
74
  };
75
75
  readonly code: {
76
- readonly type: "string";
76
+ readonly type: 'string';
77
77
  };
78
78
  readonly message: {
79
- readonly type: "string";
79
+ readonly type: 'string';
80
80
  };
81
81
  readonly meta: {
82
- readonly type: "object";
83
- readonly description: "Non-PII per-detail diagnostics (safe to log + return).";
82
+ readonly type: 'object';
83
+ readonly description: 'Non-PII per-detail diagnostics (safe to log + return).';
84
84
  };
85
85
  };
86
- readonly required: readonly ["code", "message"];
86
+ readonly required: readonly ['code', 'message'];
87
87
  };
88
88
  };
89
89
  readonly correlationId: {
90
- readonly type: "string";
91
- readonly description: "Request id for support lookups.";
90
+ readonly type: 'string';
91
+ readonly description: 'Request id for support lookups.';
92
92
  };
93
93
  readonly meta: {
94
- readonly type: "object";
95
- readonly description: "Non-PII diagnostics (safe to log + return).";
94
+ readonly type: 'object';
95
+ readonly description: 'Non-PII diagnostics (safe to log + return).';
96
96
  };
97
97
  };
98
- readonly required: readonly ["code", "message"];
98
+ readonly required: readonly ['code', 'message'];
99
99
  };
100
100
  //#endregion
101
101
  export { errorContractSchema, errorDetailSchema };
@@ -39,6 +39,19 @@ interface DuplicateKeyMeta {
39
39
  interface ValidationErrorMeta {
40
40
  validator: string;
41
41
  error: string;
42
+ /**
43
+ * Dot-path to the offending field (e.g. `'journalItems.2.account'`).
44
+ * Optional — kits with field-scoped validation (ledger's `FieldError`,
45
+ * mongoose ValidationError) set it so it flows onto the wire
46
+ * {@link ErrorDetail.path} via {@link toErrorContract} instead of being
47
+ * dropped. Kits without a path leave it unset.
48
+ */
49
+ path?: string;
50
+ /**
51
+ * Non-PII structured extra for this field (e.g. the offending value under
52
+ * `{ value }`). Flows onto {@link ErrorDetail.meta}. Never include secrets.
53
+ */
54
+ meta?: Readonly<Record<string, unknown>>;
42
55
  }
43
56
  /**
44
57
  * HTTP-shaped error — the throwable envelope every repository error and
@@ -125,17 +138,17 @@ interface ErrorDetail {
125
138
  * codes on the wire so existing client switches keep working.
126
139
  */
127
140
  declare const ERROR_CODES: {
128
- readonly VALIDATION: "validation_error";
129
- readonly NOT_FOUND: "not_found";
130
- readonly CONFLICT: "conflict";
131
- readonly UNAUTHORIZED: "unauthorized";
132
- readonly FORBIDDEN: "forbidden";
133
- readonly RATE_LIMITED: "rate_limited";
134
- readonly IDEMPOTENCY_CONFLICT: "idempotency_conflict";
135
- readonly PRECONDITION_FAILED: "precondition_failed";
136
- readonly INTERNAL: "internal_error";
137
- readonly UNAVAILABLE: "service_unavailable";
138
- readonly TIMEOUT: "timeout";
141
+ readonly VALIDATION: 'validation_error';
142
+ readonly NOT_FOUND: 'not_found';
143
+ readonly CONFLICT: 'conflict';
144
+ readonly UNAUTHORIZED: 'unauthorized';
145
+ readonly FORBIDDEN: 'forbidden';
146
+ readonly RATE_LIMITED: 'rate_limited';
147
+ readonly IDEMPOTENCY_CONFLICT: 'idempotency_conflict';
148
+ readonly PRECONDITION_FAILED: 'precondition_failed';
149
+ readonly INTERNAL: 'internal_error';
150
+ readonly UNAVAILABLE: 'service_unavailable';
151
+ readonly TIMEOUT: 'timeout';
139
152
  };
140
153
  type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
141
154
  //#endregion
@@ -1,6 +1,5 @@
1
1
  import { EventMeta, RepositoryEventPublisher } from "./types.mjs";
2
2
  import { RepositoryBase } from "../repository/base.mjs";
3
-
4
3
  //#region src/events/emit.d.ts
5
4
  /** Construction-time event wiring. */
6
5
  interface RepositoryEventsOptions {
@@ -1,5 +1,4 @@
1
1
  import { Filter, FilterEq, FilterExists, FilterFalse, FilterGt, FilterGte, FilterIn, FilterLike, FilterLt, FilterLte, FilterNe, FilterNin, FilterRaw, FilterRegex, FilterTrue } from "./types.mjs";
2
-
3
2
  //#region src/filter/builders.d.ts
4
3
  declare const eq: (field: string, value: unknown) => FilterEq;
5
4
  declare const ne: (field: string, value: unknown) => FilterNe;
@@ -11,7 +10,7 @@ declare const lte: (field: string, value: unknown) => FilterLte;
11
10
  declare const in_: (field: string, values: readonly unknown[]) => FilterIn;
12
11
  /** Non-membership (`$nin` / `NOT IN (...)`). Aliased as `noneOf`. */
13
12
  declare const nin: (field: string, values: readonly unknown[]) => FilterNin;
14
- declare const like: (field: string, pattern: string, caseSensitivity?: "sensitive" | "insensitive") => FilterLike;
13
+ declare const like: (field: string, pattern: string, caseSensitivity?: 'sensitive' | 'insensitive') => FilterLike;
15
14
  declare const regex: (field: string, pattern: string, flags?: string) => FilterRegex;
16
15
  declare const exists: (field: string, present?: boolean) => FilterExists;
17
16
  /**
@@ -57,4 +56,4 @@ declare function isNotNull(field: string): FilterExists;
57
56
  */
58
57
  declare function raw(sql: string, params?: readonly unknown[]): FilterRaw;
59
58
  //#endregion
60
- export { FALSE, TRUE, and, between, contains, endsWith, eq, exists, gt, gte, iEq, in_, isNotNull, isNull, like, lt, lte, ne, nin, not, or, raw, regex, startsWith };
59
+ export { FALSE, type FilterRaw, TRUE, and, in_ as anyOf, in_, between, contains, endsWith, eq, exists, gt, gte, iEq, not as invert, not, isNotNull, isNull, like, lt, lte, ne, nin, nin as noneOf, or, raw, regex, startsWith };
@@ -169,4 +169,4 @@ function escapeLikePattern(value) {
169
169
  return value.replace(/[%_]/g, (c) => `\\${c}`);
170
170
  }
171
171
  //#endregion
172
- export { FALSE, TRUE, and, between, contains, endsWith, eq, exists, gt, gte, iEq, in_, isNotNull, isNull, like, lt, lte, ne, nin, not, or, raw, regex, startsWith };
172
+ export { FALSE, TRUE, and, in_ as anyOf, in_, between, contains, endsWith, eq, exists, gt, gte, iEq, not as invert, not, isNotNull, isNull, like, lt, lte, ne, nin, nin as noneOf, or, raw, regex, startsWith };
@@ -1,5 +1,4 @@
1
1
  import { Filter } from "./types.mjs";
2
-
3
2
  //#region src/filter/from-record.d.ts
4
3
  /**
5
4
  * Convert a plain record (Mongo-style query object) into a Filter IR
@@ -1,4 +1,4 @@
1
- import { TRUE, and, contains, endsWith, eq, gt, gte, in_, isNotNull, isNull, like, lt, lte, ne, nin, startsWith } from "./builders.mjs";
1
+ import { TRUE, and, anyOf as in_, contains, endsWith, eq, gt, gte, isNotNull, isNull, like, lt, lte, ne, nin, startsWith } from "./builders.mjs";
2
2
  //#region src/filter/from-record.ts
3
3
  /**
4
4
  * Plain-record → Filter IR conversion — the canonical normalizer every
@@ -40,7 +40,7 @@ function isOperatorObject(value) {
40
40
  if (keys.length === 0) return false;
41
41
  return keys.every((k) => KNOWN_OPS.has(k));
42
42
  }
43
- const KNOWN_OPS = new Set([
43
+ const KNOWN_OPS = /* @__PURE__ */ new Set([
44
44
  "eq",
45
45
  "ne",
46
46
  "gt",
@@ -1,5 +1,4 @@
1
1
  import { Filter } from "./types.mjs";
2
-
3
2
  //#region src/filter/guard.d.ts
4
3
  /**
5
4
  * True when `value` is a Filter IR node.
@@ -1,5 +1,5 @@
1
1
  //#region src/filter/guard.ts
2
- const FILTER_OPS = new Set([
2
+ const FILTER_OPS = /* @__PURE__ */ new Set([
3
3
  "eq",
4
4
  "ne",
5
5
  "gt",
@@ -1,5 +1,5 @@
1
1
  import { Filter, FilterAnd, FilterEq, FilterExists, FilterFalse, FilterGt, FilterGte, FilterIn, FilterLike, FilterLt, FilterLte, FilterNe, FilterNin, FilterNot, FilterOp, FilterOr, FilterRaw, FilterRegex, FilterTrue } from "./types.mjs";
2
- import { FALSE, TRUE, and, between, contains, endsWith, eq, exists, gt, gte, iEq, in_, isNotNull, isNull, like, lt, lte, ne, nin, not, or, raw, regex, startsWith } from "./builders.mjs";
2
+ import { FALSE, TRUE, and, anyOf as in_, between, contains, endsWith, eq, exists, gt, gte, iEq, invert as not, isNotNull, isNull, like, lt, lte, ne, nin, or, raw, regex, startsWith } from "./builders.mjs";
3
3
  import { recordToFilter } from "./from-record.mjs";
4
4
  import { isFilter } from "./guard.mjs";
5
5
  import { asPredicate, matchFilter } from "./match.mjs";
@@ -1,6 +1,6 @@
1
1
  import { isFilter } from "./guard.mjs";
2
2
  import { collectFields, mapFilter, walkFilter } from "./walk.mjs";
3
- import { FALSE, TRUE, and, between, contains, endsWith, eq, exists, gt, gte, iEq, in_, isNotNull, isNull, like, lt, lte, ne, nin, not, or, raw, regex, startsWith } from "./builders.mjs";
3
+ import { FALSE, TRUE, and, anyOf as in_, between, contains, endsWith, eq, exists, gt, gte, iEq, invert as not, isNotNull, isNull, like, lt, lte, ne, nin, or, raw, regex, startsWith } from "./builders.mjs";
4
4
  import { recordToFilter } from "./from-record.mjs";
5
5
  import { asPredicate, matchFilter } from "./match.mjs";
6
6
  import { SCOPE_ANY, buildTenantScope, mergeScope } from "./scope.mjs";
@@ -1,5 +1,4 @@
1
1
  import { Filter } from "./types.mjs";
2
-
3
2
  //#region src/filter/match.d.ts
4
3
  /** Evaluate a filter against a single document. Returns true iff the doc matches. */
5
4
  declare function matchFilter(doc: unknown, filter: Filter): boolean;
@@ -1,5 +1,4 @@
1
1
  import { Filter } from "./types.mjs";
2
-
3
2
  //#region src/filter/scope.d.ts
4
3
  /**
5
4
  * Inject a tenant-scope predicate into an existing filter.
@@ -1,5 +1,4 @@
1
1
  import { Filter } from "./types.mjs";
2
-
3
2
  //#region src/filter/walk.d.ts
4
3
  /**
5
4
  * Depth-first visit of every node. Visitor returns `false` to stop descent
@@ -1,5 +1,4 @@
1
1
  import { HookListener, HookMode, PrioritizedHook } from "./types.mjs";
2
-
3
2
  //#region src/hooks/engine.d.ts
4
3
  /** The default priority assigned when a user omits one on `on(...)`. */
5
4
  declare const DEFAULT_LISTENER_PRIORITY = 500;