@classytic/mongokit 3.29.0 → 3.31.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/README.md +43 -0
- package/dist/{PaginationEngine-CczbvCAq.mjs → PaginationEngine-CuONvwCM.mjs} +21 -1
- package/dist/{create-repository-D4ZU94b3.d.mts → Repository-BAzymuOz.d.mts} +31 -58
- package/dist/{Repository-DThvFCaV.mjs → Repository-BQ3FEnOa.mjs} +352 -56
- package/dist/actions/index.d.mts +1 -1
- package/dist/actions/index.mjs +1 -1
- package/dist/adapter/index.mjs +1 -1
- package/dist/{adapter-CLvUHiTW.mjs → adapter-BitHg-CN.mjs} +1 -1
- package/dist/ai/index.d.mts +1 -1
- package/dist/better-auth/index.d.mts +13 -0
- package/dist/better-auth/index.mjs +76 -6
- package/dist/{create-repository-uhKt_oUT.mjs → create-repository-BOTVMsIg.mjs} +3 -2
- package/dist/create-repository-mEdfH9sz.d.mts +54 -0
- package/dist/{index-DceInCTX.d.mts → index-Beyr1r4d.d.mts} +1 -1
- package/dist/index.d.mts +305 -43
- package/dist/index.mjs +118 -11
- package/dist/kernel-conformance/index.d.mts +217 -0
- package/dist/kernel-conformance/index.mjs +603 -0
- package/dist/method-registry.plugin-DblM7V6j.mjs +112 -0
- package/dist/model-registry-ClKtWiHa.mjs +67 -0
- package/dist/{mongooseToJsonSchema-CByt1VhQ.mjs → mongooseToJsonSchema-DKbnKduN.mjs} +14 -3
- package/dist/{multi-tenant.plugin-DVyVGREb.d.mts → multi-tenant.plugin-2VtSSm1Y.d.mts} +1 -1
- package/dist/{operations-C8IcCHF9.d.mts → operations-CuzX9m2Z.d.mts} +42 -3
- package/dist/outbox/index.d.mts +63 -0
- package/dist/outbox/index.mjs +239 -0
- package/dist/pagination/PaginationEngine.mjs +1 -1
- package/dist/{plugin-options-vFufQZMZ.d.mts → plugin-options-BsFH0sTi.d.mts} +1 -1
- package/dist/plugins/index.d.mts +4 -4
- package/dist/plugins/index.mjs +3 -2
- package/dist/{repository-DCHRWRXw.d.mts → repository-Q16ErTu8.d.mts} +19 -1
- package/dist/testkit/index.d.mts +8 -1
- package/dist/testkit/index.mjs +1 -1
- package/dist/{timestamp.plugin-CFL6LlYZ.mjs → timestamp.plugin-i9Qxm6kn.mjs} +32 -143
- package/dist/{to-plain-DkF5px0R.d.mts → to-plain-BuX1RUZV.d.mts} +12 -4
- package/dist/{update-CI2NdAW6.mjs → update-DAO5STDv.mjs} +62 -7
- package/dist/utils/index.d.mts +2 -2
- package/dist/utils/index.mjs +1 -1
- package/dist/{validation-chain.plugin-BLecaKa0.d.mts → validation-chain.plugin-BSshLJTA.d.mts} +3 -3
- package/dist/{validation-chain.plugin-CwOcUJC1.mjs → validation-chain.plugin-CpcB6dOd.mjs} +4 -3
- package/package.json +193 -187
package/README.md
CHANGED
|
@@ -430,6 +430,49 @@ Atlas **`$search` / `$vectorSearch`** indexes are Atlas-only and don't exist on
|
|
|
430
430
|
|
|
431
431
|
All accept `{ replset?, dbName?, uri? }`.
|
|
432
432
|
|
|
433
|
+
## Kernel Conformance — `@classytic/mongokit/kernel-conformance`
|
|
434
|
+
|
|
435
|
+
An **executable contract suite** for domain kernels built on `defineModels()`. A kernel that
|
|
436
|
+
follows the Describe → Bind → Verify → Serve → Close lifecycle wires this into its own test
|
|
437
|
+
directory; passing it IS conformance.
|
|
438
|
+
|
|
439
|
+
It asserts what ordinary kernel tests do not: that `defineX(shape)` registers nothing, that
|
|
440
|
+
`bind` registers exactly the declared models on the SUPPLIED connection and performs no index
|
|
441
|
+
I/O, that a second bind throws `ModelCollisionError`, that a host-supplied event transport is
|
|
442
|
+
never closed while an internally-created one is, that `close()` is idempotent, that no legacy
|
|
443
|
+
`createX`/`destroy`/`dispose` surface survives, and that a failing index sync REJECTS rather
|
|
444
|
+
than being swallowed.
|
|
445
|
+
|
|
446
|
+
**The test runner is injected, never imported** — mongokit takes no dependency (not even an
|
|
447
|
+
optional peer) on vitest, and the suite runs unmodified under any runner that exposes
|
|
448
|
+
`describe`/`it`. Assertions are internal, so no `expect` implementation is required.
|
|
449
|
+
|
|
450
|
+
```ts
|
|
451
|
+
import mongoose from 'mongoose';
|
|
452
|
+
import { describe, it } from 'vitest';
|
|
453
|
+
import { describeKernelConformance } from '@classytic/mongokit/kernel-conformance';
|
|
454
|
+
import * as kernel from '../../src/index.js';
|
|
455
|
+
|
|
456
|
+
describeKernelConformance({
|
|
457
|
+
name: 'party',
|
|
458
|
+
runner: { describe, it },
|
|
459
|
+
// A FACTORY — purity is only observable if the suite can call defineX itself.
|
|
460
|
+
blueprint: () => kernel.defineParty({ multiTenant: false, autoIndex: false }),
|
|
461
|
+
// Never connected: every check is registry-level, so no server is needed.
|
|
462
|
+
connect: async () => mongoose.createConnection(),
|
|
463
|
+
bind: (bp, conn, ctx) => bp.bind(conn, { eventTransport: ctx.transport }),
|
|
464
|
+
expectedModelNames: ['Party'],
|
|
465
|
+
moduleExports: kernel,
|
|
466
|
+
// Opt-outs are explicit, typed, and REQUIRE a reason; each one still emits a
|
|
467
|
+
// visible `[SKIPPED] <id> — <reason>` test. A silent skip is the bug this suite exists
|
|
468
|
+
// to prevent.
|
|
469
|
+
skip: [{ check: 'bind-verifies-requirements', reason: '…' }],
|
|
470
|
+
});
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
Check ids are exported as `KERNEL_CONFORMANCE_CHECKS` (a `const` tuple, so `skip` is a typed
|
|
474
|
+
union — a mistyped id is a compile error, not an ineffective skip).
|
|
475
|
+
|
|
433
476
|
## License
|
|
434
477
|
|
|
435
478
|
MIT
|
|
@@ -636,7 +636,27 @@ var PaginationEngine = class {
|
|
|
636
636
|
hasNext = data.length > sanitizedLimit;
|
|
637
637
|
if (hasNext) data.pop();
|
|
638
638
|
} else hasNext = sanitizedPage < totalPages;
|
|
639
|
-
|
|
639
|
+
/**
|
|
640
|
+
* A CLAMPED limit is reported, not swallowed.
|
|
641
|
+
*
|
|
642
|
+
* `validateLimit` caps silently by design — an over-ask is benign and rejecting it
|
|
643
|
+
* would be worse (that contradiction cost a day: the querystring schema's `maximum`
|
|
644
|
+
* made the parser's documented clamp unreachable, so `?limit=200` 400'd and two UI
|
|
645
|
+
* callers rendered the failure as an empty list).
|
|
646
|
+
*
|
|
647
|
+
* But clamping quietly has its own cost. A caller asking for 1000 and receiving 100
|
|
648
|
+
* gets an arbitrary slice with no signal — which is exactly how a bank-account
|
|
649
|
+
* picker rendered "No accounts found" against 696 accounts, because the rows it
|
|
650
|
+
* wanted were outside the first page. `limit` in the response already carries the
|
|
651
|
+
* effective value; nobody compares it. A warning is the channel that is actually
|
|
652
|
+
* read.
|
|
653
|
+
*
|
|
654
|
+
* Deep-pagination takes precedence when both apply: it is the more actionable of
|
|
655
|
+
* the two, and stacking warnings turns a signal into noise.
|
|
656
|
+
*/
|
|
657
|
+
const requestedLimit = Number(limit);
|
|
658
|
+
const wasClamped = Number.isFinite(requestedLimit) && requestedLimit > sanitizedLimit;
|
|
659
|
+
const warning = shouldWarnDeepPagination(sanitizedPage, this.config.deepPageThreshold) ? `Deep pagination (page ${sanitizedPage}). Consider getAll({ after, sort, limit }) for better performance.` : wasClamped ? `Requested limit ${Math.floor(requestedLimit)} exceeds this repository's cap; returning ${sanitizedLimit}. Filter server-side or sort deterministically — the returned page is otherwise an arbitrary slice.` : void 0;
|
|
640
660
|
return {
|
|
641
661
|
method: "offset",
|
|
642
662
|
data,
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { _ as WithTransactionOptions, a as DeleteManyResult, f as OperationOptions, g as UpdateOptions, h as UpdateManyResult, i as CreateOptions, l as LookupPopulateOptions, m as SessionOptions, o as DeleteResult, p as ReadOptions, r as CacheableOptions, s as FindOneAndUpdateOptions, t as AggregateOptions, u as LookupPopulateResult, v as LookupBuilder, y as LookupOptions } from "./operations-
|
|
1
|
+
import { _ as WithTransactionOptions, a as DeleteManyResult, f as OperationOptions, g as UpdateOptions, h as UpdateManyResult, i as CreateOptions, l as LookupPopulateOptions, m as SessionOptions, o as DeleteResult, p as ReadOptions, r as CacheableOptions, s as FindOneAndUpdateOptions, t as AggregateOptions, u as LookupPopulateResult, v as LookupBuilder, y as LookupOptions } from "./operations-CuzX9m2Z.mjs";
|
|
2
2
|
import { a as PopulateSpec, i as ObjectId, l as SortSpec$1, o as ReadPreferenceType, s as SelectSpec } from "./core-62oo3N1C.mjs";
|
|
3
3
|
import { c as PaginationConfig, r as CollationOptions, t as AggregatePaginationOptions } from "./pagination-jSUdrACK.mjs";
|
|
4
|
-
import { _ as RepositoryOptions, d as PluginType, f as PrioritizedHook, o as Middleware, p as RepositoryContext } from "./repository-
|
|
5
|
-
import { T as AuditTrailOptions, _ as RepositoryCachePluginOptions, i as CustomIdOptions, t as MultiTenantOptions } from "./multi-tenant.plugin-DVyVGREb.mjs";
|
|
4
|
+
import { _ as RepositoryOptions, d as PluginType, f as PrioritizedHook, o as Middleware, p as RepositoryContext } from "./repository-Q16ErTu8.mjs";
|
|
6
5
|
import { t as PaginationEngine } from "./PaginationEngine-CBS1XGzp.mjs";
|
|
7
|
-
import { i as Logger, o as SoftDeleteOptions } from "./plugin-options-vFufQZMZ.mjs";
|
|
8
6
|
import { AggPaginationRequest, AggRequest, AggResult, ArchiveOptions, ArchiveResult, ArchiveSink, ChangeEvent, FilterInput, KeysetAggPaginationResult, QueryOptions, RepoCapabilities, RepositoryBase, TenantPurgeOptions, TenantPurgeResult, TenantPurgeStrategy, WatchOptions } from "@classytic/repo-core/repository";
|
|
9
7
|
import { ClientSession, Expression, Model, PipelineStage, PopulateOptions } from "mongoose";
|
|
10
8
|
import { Filter } from "@classytic/repo-core/filter";
|
|
@@ -526,8 +524,29 @@ declare class Repository<TDoc = unknown> extends RepositoryBase {
|
|
|
526
524
|
* Runtime capability descriptor required by `StandardRepo<TDoc>`
|
|
527
525
|
* (repo-core 0.6.0). Hosts feature-detect once at boot instead of
|
|
528
526
|
* try/catching `UnsupportedOperationError` per call.
|
|
529
|
-
|
|
530
|
-
|
|
527
|
+
*
|
|
528
|
+
* **OBSERVED, not declared** (changed 2026-08-05). Until then this was a
|
|
529
|
+
* class field pointing at the static `MONGOKIT_CAPABILITIES`, so
|
|
530
|
+
* `transactions` read `true` for every mongoose-backed repository —
|
|
531
|
+
* including one pointed at a standalone `mongod`, which cannot run a
|
|
532
|
+
* transaction at all. Every kernel boot gate that reads it (wallet, party,
|
|
533
|
+
* invoice, purchase, flow, …) was therefore unfalsifiable decoration
|
|
534
|
+
* (AGENTS.md FAIL LOUD rule 4).
|
|
535
|
+
*
|
|
536
|
+
* Now it derives the deployment-dependent flags (`transactions`,
|
|
537
|
+
* `nestedTransactions`, `changeStreams`) from THIS model's connection and
|
|
538
|
+
* its live SDAM topology. A getter rather than a constructor snapshot on
|
|
539
|
+
* purpose: a repository built before `mongoose.connect()` resolves upgrades
|
|
540
|
+
* its own answer the moment the connection is up, with no invalidation step.
|
|
541
|
+
* When the topology cannot be read the answer is `transactions: false` +
|
|
542
|
+
* `transactionsResolution: 'unknown'` — fail closed, never an optimistic
|
|
543
|
+
* yes (rule 3). See `capabilities.ts` and `probeMongoCapabilities`.
|
|
544
|
+
*
|
|
545
|
+
* `options.capabilities` overrides the whole descriptor for hosts/tests that
|
|
546
|
+
* genuinely know better (a proxied connection, a non-mongoose driver seam).
|
|
547
|
+
*/
|
|
548
|
+
get capabilities(): RepoCapabilities;
|
|
549
|
+
private readonly _capabilitiesOverride;
|
|
531
550
|
readonly Model: Model<TDoc>;
|
|
532
551
|
/**
|
|
533
552
|
* Mongoose model name. Duplicated on the instance for BC — arc / catalog /
|
|
@@ -927,8 +946,9 @@ declare class Repository<TDoc = unknown> extends RepositoryBase {
|
|
|
927
946
|
/**
|
|
928
947
|
* Update a document by id and return the post-update doc.
|
|
929
948
|
*
|
|
930
|
-
* Compiles to `Model.findOneAndUpdate(filter, { $set: data },
|
|
931
|
-
*
|
|
949
|
+
* Compiles to `Model.findOneAndUpdate(filter, { $set: data },
|
|
950
|
+
* { returnDocument: 'after', runValidators: true })` under the hood and
|
|
951
|
+
* routes through the
|
|
932
952
|
* full plugin pipeline — `multiTenantPlugin` injects the tenant scope,
|
|
933
953
|
* `auditTrailPlugin` records the change, `cachePlugin` invalidates,
|
|
934
954
|
* `softDeletePlugin` etc. all compose. Returns `null` on miss (the
|
|
@@ -943,7 +963,7 @@ declare class Repository<TDoc = unknown> extends RepositoryBase {
|
|
|
943
963
|
* const doc = await CampaignModel.findOneAndUpdate(
|
|
944
964
|
* { _id: id, organizationId: ctx.orgId }, // hand-rolled tenant filter
|
|
945
965
|
* { $set: patch, $currentDate: { updatedAt: 1 } },
|
|
946
|
-
* {
|
|
966
|
+
* { returnDocument: 'after', runValidators: true }
|
|
947
967
|
* );
|
|
948
968
|
* return doc ? toEntity(doc) : null;
|
|
949
969
|
*
|
|
@@ -972,7 +992,7 @@ declare class Repository<TDoc = unknown> extends RepositoryBase {
|
|
|
972
992
|
* const doc = await CampaignModel.findOneAndUpdate(
|
|
973
993
|
* { _id: id, organizationId: ctx.orgId, status: 'pending' },
|
|
974
994
|
* { $set: { status: 'sent', sentAt: new Date() } },
|
|
975
|
-
* {
|
|
995
|
+
* { returnDocument: 'after' }
|
|
976
996
|
* );
|
|
977
997
|
* if (!doc) throw new ConcurrentTransitionError(id);
|
|
978
998
|
*
|
|
@@ -1826,51 +1846,4 @@ declare class Repository<TDoc = unknown> extends RepositoryBase {
|
|
|
1826
1846
|
_handleError(error: Error): HttpError;
|
|
1827
1847
|
}
|
|
1828
1848
|
//#endregion
|
|
1829
|
-
|
|
1830
|
-
/**
|
|
1831
|
-
* Audit config — either a `Logger` (routes to `auditLogPlugin`, which
|
|
1832
|
-
* writes structured log lines through your logger) or an
|
|
1833
|
-
* `AuditTrailOptions` object (routes to `auditTrailPlugin`, which
|
|
1834
|
-
* persists a queryable compliance ledger in its own collection).
|
|
1835
|
-
*
|
|
1836
|
-
* Discrimination: a value carrying any of the `Logger` function members
|
|
1837
|
-
* (`info` / `warn` / `error` / `debug`) is treated as a logger; anything
|
|
1838
|
-
* else is treated as `AuditTrailOptions` (all of whose members are
|
|
1839
|
-
* data-shaped except `metadata` / `onError`, which don't overlap with
|
|
1840
|
-
* the logger member names).
|
|
1841
|
-
*/
|
|
1842
|
-
type AuditConfig = Logger | AuditTrailOptions;
|
|
1843
|
-
/**
|
|
1844
|
-
* Declarative repository config. Every key is optional; a feature's
|
|
1845
|
-
* plugin is installed only when its key is present. The remaining
|
|
1846
|
-
* `RepositoryOptions` keys (`idField`, `hooks`, `schema`, `updateSchema`,
|
|
1847
|
-
* `events`, `requirePlugins`, ...) pass through to the `Repository`
|
|
1848
|
-
* constructor unchanged.
|
|
1849
|
-
*/
|
|
1850
|
-
interface CreateRepositoryConfig extends RepositoryOptions {
|
|
1851
|
-
/** Multi-tenant scoping — forwarded to `multiTenantPlugin`. */
|
|
1852
|
-
tenant?: MultiTenantOptions;
|
|
1853
|
-
/** Soft-delete — `true` for defaults, or `SoftDeleteOptions`. */
|
|
1854
|
-
softDelete?: boolean | SoftDeleteOptions;
|
|
1855
|
-
/** createdAt/updatedAt stamping — `timestampPlugin` takes no options. */
|
|
1856
|
-
timestamps?: boolean;
|
|
1857
|
-
/** Batch ops (`updateMany`/`deleteMany`/`bulkWrite`) via `batchOperationsPlugin`. */
|
|
1858
|
-
batch?: boolean;
|
|
1859
|
-
/** Read-through cache — forwarded to `cachePlugin`. */
|
|
1860
|
-
cache?: RepositoryCachePluginOptions;
|
|
1861
|
-
/** Audit — `Logger` → `auditLogPlugin`; `AuditTrailOptions` → `auditTrailPlugin`. */
|
|
1862
|
-
audit?: AuditConfig;
|
|
1863
|
-
/** Custom ID generation — forwarded to `customIdPlugin`. */
|
|
1864
|
-
customId?: CustomIdOptions;
|
|
1865
|
-
/** Extra plugins appended AFTER the canonical stack. */
|
|
1866
|
-
plugins?: PluginType[];
|
|
1867
|
-
/** Pagination engine config (defaultLimit, maxLimit, ...). */
|
|
1868
|
-
pagination?: PaginationConfig;
|
|
1869
|
-
}
|
|
1870
|
-
/**
|
|
1871
|
-
* Build a `Repository` from a declarative config. See module JSDoc for
|
|
1872
|
-
* ordering guarantees and an example.
|
|
1873
|
-
*/
|
|
1874
|
-
declare function createRepository<TDoc>(model: Model<TDoc, any, any, any>, config?: CreateRepositoryConfig): Repository<TDoc>;
|
|
1875
|
-
//#endregion
|
|
1876
|
-
export { Repository as a, HOOK_PRIORITY as i, CreateRepositoryConfig as n, TransitionMachine as o, createRepository as r, AggregationBuilder as s, AuditConfig as t };
|
|
1849
|
+
export { AggregationPlan as a, SortOrder as c, AggregationBuilder as i, SortSpec as l, Repository as n, GroupSpec as o, TransitionMachine as r, ProjectionSpec as s, HOOK_PRIORITY as t, VectorSearchOptions as u };
|