@classytic/repo-core 0.2.0 → 0.4.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 +363 -0
- package/README.md +28 -7
- package/dist/adapter/index.d.mts +3 -0
- package/dist/adapter/index.mjs +2 -0
- package/dist/adapter/types.d.mts +222 -0
- package/dist/adapter/widen.d.mts +22 -0
- package/dist/adapter/widen.mjs +26 -0
- package/dist/aggregate/index.d.mts +3 -0
- package/dist/aggregate/index.mjs +3 -0
- package/dist/aggregate/keyset.d.mts +57 -0
- package/dist/aggregate/keyset.mjs +45 -0
- package/dist/aggregate/normalize.d.mts +24 -0
- package/dist/aggregate/normalize.mjs +28 -0
- package/dist/better-auth/index.d.mts +110 -0
- package/dist/better-auth/index.mjs +71 -0
- package/dist/cache/engine.d.mts +127 -0
- package/dist/cache/engine.mjs +235 -0
- package/dist/cache/envelope.mjs +32 -0
- package/dist/cache/index.d.mts +7 -2
- package/dist/cache/index.mjs +6 -2
- package/dist/cache/keys.mjs +131 -0
- package/dist/cache/memory-adapter.mjs +41 -7
- package/dist/cache/options.d.mts +112 -0
- package/dist/cache/options.mjs +25 -0
- package/dist/cache/plugin/context.d.mts +18 -0
- package/dist/cache/plugin/context.mjs +121 -0
- package/dist/cache/plugin/index.d.mts +86 -0
- package/dist/cache/plugin/index.mjs +78 -0
- package/dist/cache/plugin/invalidation-hooks.mjs +35 -0
- package/dist/cache/plugin/read-hooks.mjs +96 -0
- package/dist/cache/plugin/swr.mjs +20 -0
- package/dist/cache/runtime.d.mts +43 -0
- package/dist/cache/runtime.mjs +14 -0
- package/dist/cache/tag-index.mjs +84 -0
- package/dist/cache/timeout-adapter.d.mts +30 -0
- package/dist/cache/timeout-adapter.mjs +58 -0
- package/dist/cache/types.d.mts +45 -0
- package/dist/cache/version-store.mjs +57 -0
- package/dist/errors/contract.d.mts +37 -0
- package/dist/errors/contract.mjs +75 -0
- package/dist/errors/index.d.mts +4 -2
- package/dist/errors/index.mjs +4 -1
- package/dist/errors/schema.d.mts +101 -0
- package/dist/errors/schema.mjs +78 -0
- package/dist/errors/types.d.mts +113 -8
- package/dist/errors/types.mjs +29 -0
- package/dist/filter/match.mjs +38 -2
- package/dist/pagination/canonical.d.mts +35 -0
- package/dist/pagination/canonical.mjs +26 -0
- package/dist/pagination/cursor.mjs +4 -1
- package/dist/pagination/index.d.mts +3 -2
- package/dist/pagination/index.mjs +2 -1
- package/dist/pagination/types.d.mts +57 -3
- package/dist/plugins/index.d.mts +2 -0
- package/dist/plugins/index.mjs +2 -0
- package/dist/plugins/tenant-helpers.d.mts +63 -0
- package/dist/plugins/tenant-helpers.mjs +84 -0
- package/dist/query-parser/index.d.mts +2 -1
- package/dist/query-parser/index.mjs +2 -1
- package/dist/query-parser/parse-url.mjs +13 -11
- package/dist/query-parser/reserved.d.mts +43 -0
- package/dist/query-parser/reserved.mjs +56 -0
- package/dist/repository/agg-output.d.mts +63 -0
- package/dist/repository/agg-output.mjs +89 -0
- package/dist/repository/base.mjs +21 -0
- package/dist/repository/index.d.mts +4 -2
- package/dist/repository/index.mjs +3 -1
- package/dist/repository/options.d.mts +62 -0
- package/dist/repository/options.mjs +57 -0
- package/dist/repository/types.d.mts +935 -48
- package/dist/schema/field-rules.d.mts +60 -9
- package/dist/schema/field-rules.mjs +121 -10
- package/dist/schema/generator.d.mts +72 -0
- package/dist/schema/generator.mjs +16 -0
- package/dist/schema/index.d.mts +3 -2
- package/dist/schema/index.mjs +3 -2
- package/dist/schema/types.d.mts +77 -3
- package/dist/tenant/index.d.mts +3 -0
- package/dist/tenant/index.mjs +2 -0
- package/dist/tenant/resolve.d.mts +27 -0
- package/dist/tenant/resolve.mjs +69 -0
- package/dist/tenant/types.d.mts +142 -0
- package/dist/testing/conformance.mjs +666 -17
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/types.d.mts +99 -2
- package/package.json +27 -1
- package/dist/cache/stable-stringify.d.mts +0 -15
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
//#region src/tenant/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Tenant scope configuration — canonical static contract for the org.
|
|
4
|
+
*
|
|
5
|
+
* **`@classytic/repo-core/tenant` is the single source of truth.** Every
|
|
6
|
+
* multi-tenant-capable package (`@classytic/mongokit`, `@classytic/sqlitekit`,
|
|
7
|
+
* future kits, arc presets, services) consumes {@link TenantConfig} for its
|
|
8
|
+
* static fields and extends with kit-specific runtime callbacks via
|
|
9
|
+
* `Pick<TenantConfig, ...>` to lock the field vocabulary by structural typing.
|
|
10
|
+
*
|
|
11
|
+
* Three strategies are supported:
|
|
12
|
+
* - `'field'` (default) — filter every query by a scalar field on documents.
|
|
13
|
+
* The common case; used by `multiTenantPlugin` in mongokit and sqlitekit.
|
|
14
|
+
* - `'none'` — disable scoping entirely (single-tenant app). Equivalent to
|
|
15
|
+
* `enabled: false`; `strategy: 'none'` is the explicit form.
|
|
16
|
+
* - `'custom'` — caller supplies a `resolve(ctx)` function that returns the
|
|
17
|
+
* filter shape to inject. **The escape hatch for custom systems** —
|
|
18
|
+
* covers multi-field composite tenants, context-derived filters
|
|
19
|
+
* (region + partner id), non-scalar scope keys, or any tenancy model that
|
|
20
|
+
* doesn't fit the simple `field === id` pattern.
|
|
21
|
+
*
|
|
22
|
+
* **Why this layer is static-only.** Runtime callbacks (`skipWhen(ctx, op)`,
|
|
23
|
+
* `resolveContext()`, `resolveTenantId(ctx)`) genuinely differ across kits
|
|
24
|
+
* because their `RepositoryContext` shapes differ — mongokit's resolver
|
|
25
|
+
* returns just an id, sqlitekit's takes a richer context object. Each kit
|
|
26
|
+
* extends `TenantConfig` with its own runtime-callback fields. Hosts who
|
|
27
|
+
* need a single config object can compose: pass the static `TenantConfig`
|
|
28
|
+
* through {@link resolveTenantConfig} once, then forward the resolved
|
|
29
|
+
* static fields into each kit's runtime options alongside the kit-specific
|
|
30
|
+
* callbacks.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Storage / cast strategy for the tenant identifier on documents.
|
|
34
|
+
*
|
|
35
|
+
* - `'objectId'` (recommended for new packages) — `Schema.Types.ObjectId`
|
|
36
|
+
* with `ref`. Enables `$lookup`, `.populate()`, QueryParser `?lookup=...`
|
|
37
|
+
* on Mongo-shaped kits. SQL kits typically ignore this and rely on
|
|
38
|
+
* schema-defined column types instead.
|
|
39
|
+
* - `'string'` — plain string. Use when the host auth system issues UUIDs
|
|
40
|
+
* or slugs rather than ObjectIds.
|
|
41
|
+
*/
|
|
42
|
+
type TenantFieldType = 'objectId' | 'string';
|
|
43
|
+
/** Scope resolution strategy. */
|
|
44
|
+
type TenantStrategy = 'field' | 'none' | 'custom';
|
|
45
|
+
interface TenantConfig {
|
|
46
|
+
/**
|
|
47
|
+
* Scope strategy. Omit for the common `'field'` case — explicit `'none'`
|
|
48
|
+
* / `'custom'` lets packages collapse what used to live in a separate
|
|
49
|
+
* `ScopeConfig` type.
|
|
50
|
+
*
|
|
51
|
+
* @default 'field'
|
|
52
|
+
*/
|
|
53
|
+
strategy?: TenantStrategy;
|
|
54
|
+
/**
|
|
55
|
+
* Whether tenant scoping is active. When `false`, the package runs in
|
|
56
|
+
* single-tenant mode — no filter injection, no tenant field on documents.
|
|
57
|
+
* Equivalent to `strategy: 'none'`.
|
|
58
|
+
*
|
|
59
|
+
* @default true
|
|
60
|
+
*/
|
|
61
|
+
enabled?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Document / column field name that stores the tenant id. Used when
|
|
64
|
+
* `strategy === 'field'`.
|
|
65
|
+
*
|
|
66
|
+
* @default 'organizationId'
|
|
67
|
+
*/
|
|
68
|
+
tenantField?: string;
|
|
69
|
+
/**
|
|
70
|
+
* How to store / cast the tenant id.
|
|
71
|
+
*
|
|
72
|
+
* @default 'objectId'
|
|
73
|
+
*/
|
|
74
|
+
fieldType?: TenantFieldType;
|
|
75
|
+
/**
|
|
76
|
+
* Mongoose ref for `'objectId'` types. Ignored by SQL kits and when
|
|
77
|
+
* `fieldType === 'string'`.
|
|
78
|
+
*
|
|
79
|
+
* @default 'organization'
|
|
80
|
+
*/
|
|
81
|
+
ref?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Which key on the repository context to read the tenant id from.
|
|
84
|
+
*
|
|
85
|
+
* Defaults cascade: if omitted, falls back to the caller's `tenantField`
|
|
86
|
+
* (if supplied), else to `'organizationId'`. Rationale: when a host renames
|
|
87
|
+
* `tenantField` to e.g. `'branchId'`, their context almost always carries
|
|
88
|
+
* the value under the same key — mirroring `tenantField` is the
|
|
89
|
+
* least-surprise behavior. Override explicitly if the context key diverges
|
|
90
|
+
* from the document field (e.g. `tenantField: 'branchId'`,
|
|
91
|
+
* `contextKey: 'organizationId'`).
|
|
92
|
+
*
|
|
93
|
+
* @default tenantField ?? 'organizationId'
|
|
94
|
+
*/
|
|
95
|
+
contextKey?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Whether the field is required. When `false`, the package permits
|
|
98
|
+
* unscoped / cross-tenant reads (typically only for admin paths).
|
|
99
|
+
*
|
|
100
|
+
* @default true
|
|
101
|
+
*/
|
|
102
|
+
required?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Custom resolver — called when `strategy === 'custom'` to produce the
|
|
105
|
+
* filter object injected into queries. Packages pass the request /
|
|
106
|
+
* repository context; the resolver returns the filter shape.
|
|
107
|
+
*
|
|
108
|
+
* Use for tenancy models that don't fit the simple `field === id`
|
|
109
|
+
* pattern: multi-field composites, context-derived filters
|
|
110
|
+
* (region + partner id), hash-derived shards, etc.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* {
|
|
115
|
+
* strategy: 'custom',
|
|
116
|
+
* resolve: (ctx) => ({
|
|
117
|
+
* organizationId: ctx.organizationId,
|
|
118
|
+
* region: ctx.region,
|
|
119
|
+
* partnerId: ctx.partnerId,
|
|
120
|
+
* }),
|
|
121
|
+
* }
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
resolve?: (ctx: Record<string, unknown>) => Record<string, unknown>;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Resolved shape returned by `resolveTenantConfig`. Always includes the
|
|
128
|
+
* field defaults (so packages can inspect field names even when
|
|
129
|
+
* `enabled: false`) and threads `resolve` when `strategy === 'custom'`.
|
|
130
|
+
*/
|
|
131
|
+
type ResolvedTenantConfig = {
|
|
132
|
+
strategy: TenantStrategy;
|
|
133
|
+
enabled: boolean;
|
|
134
|
+
tenantField: string;
|
|
135
|
+
fieldType: TenantFieldType;
|
|
136
|
+
ref: string;
|
|
137
|
+
contextKey: string;
|
|
138
|
+
required: boolean;
|
|
139
|
+
resolve?: TenantConfig['resolve'];
|
|
140
|
+
};
|
|
141
|
+
//#endregion
|
|
142
|
+
export { ResolvedTenantConfig, TenantConfig, TenantFieldType, TenantStrategy };
|