@ignex/ninox 0.1.6 → 0.2.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 +46 -22
- package/dist/index.d.ts +133 -102
- package/dist/index.js +840 -247
- package/dist/index.js.map +1 -1
- package/dist/{timeout-B10CTiGm.d.ts → timeout-BaP92Iyg.d.ts} +5 -15
- package/dist/utils.d.ts +4 -15
- package/dist/utils.js +91 -45
- package/dist/utils.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -281,7 +281,7 @@ builder, and the MongoDB `$jsonSchema` validator + indexes installed by
|
|
|
281
281
|
| field kind | `s.*` | inferred TS type |
|
|
282
282
|
| --- | --- | --- |
|
|
283
283
|
| string / int / number | `s.string()` / `s.integer()` / `s.number()` | `string` / `number` / `number` |
|
|
284
|
-
| exact BSON kinds | `s.double()` / `s.long()` / `s.decimal()` | `number` / `
|
|
284
|
+
| exact BSON kinds | `s.double()` / `s.long()` / `s.decimal()` | `number` / `Long` / `Decimal128` |
|
|
285
285
|
| other scalars | `s.boolean()` / `s.date()` / `s.objectId()` | `boolean` / `Date` / `ObjectId` |
|
|
286
286
|
| enum | `s.enum(['a', 'b'] as const)` | `'a' \| 'b'` (string or numeric literals) |
|
|
287
287
|
| array | `s.array(s.string())` | `string[]` |
|
|
@@ -293,8 +293,10 @@ builder, and the MongoDB `$jsonSchema` validator + indexes installed by
|
|
|
293
293
|
Constraints mirror `$jsonSchema`: strings (`minLength` / `maxLength` / `pattern`),
|
|
294
294
|
numbers (`minimum` / `maximum` / `multipleOf` / `exclusiveMinimum` /
|
|
295
295
|
`exclusiveMaximum`), arrays (`minItems` / `maxItems` / `uniqueItems`), objects
|
|
296
|
-
(`minProperties` / `maxProperties` / `additionalProperties`). `format`
|
|
297
|
-
|
|
296
|
+
(`minProperties` / `maxProperties` / `additionalProperties`). String `format`
|
|
297
|
+
is validated client-side for `email`, `uri`, `date-time`, `date`, `uuid`,
|
|
298
|
+
`hostname`, `ipv4`, and `ipv6`; it is not sent to MongoDB because the server
|
|
299
|
+
rejects that `$jsonSchema` keyword.
|
|
298
300
|
|
|
299
301
|
```ts
|
|
300
302
|
const userSchema = s.object({
|
|
@@ -342,7 +344,10 @@ do {
|
|
|
342
344
|
```
|
|
343
345
|
|
|
344
346
|
`paginateCursor` supports `after` (forward) and `before` (backward); a sort whose
|
|
345
|
-
keys don't match the cursor's is rejected at runtime.
|
|
347
|
+
keys don't match the cursor's is rejected at runtime. The final sort key must be
|
|
348
|
+
`_id` or an explicitly named `uniqueTiebreaker` with a unique index. Dotted paths
|
|
349
|
+
and BSON values are supported. Offset pagination rejects offsets above 10,000 by
|
|
350
|
+
default (`maxOffset` overrides); use keyset pagination for deep traversal.
|
|
346
351
|
|
|
347
352
|
## Geospatial
|
|
348
353
|
|
|
@@ -423,6 +428,11 @@ await db.populate(products, [
|
|
|
423
428
|
// orders[0].customer, orders[0].more, products[0].tags are all typed.
|
|
424
429
|
```
|
|
425
430
|
|
|
431
|
+
Populate reads are fresh by default. Pass `session`, `maxTimeMS`, read concern,
|
|
432
|
+
or read preference in the options. `maxDocs` is an optional safety cap that
|
|
433
|
+
throws on overflow rather than silently truncating a relation; `queryCache:
|
|
434
|
+
true` explicitly opts into the shared read cache.
|
|
435
|
+
|
|
426
436
|
## Repository layer
|
|
427
437
|
|
|
428
438
|
`createRepository(manager, 'collection')` wraps a manager + collection into a
|
|
@@ -454,12 +464,14 @@ const users = defineCollection('users', userSchema, {
|
|
|
454
464
|
|
|
455
465
|
## Transactions & migrations
|
|
456
466
|
|
|
457
|
-
- `db.transaction(async (session) => ...)`
|
|
458
|
-
|
|
459
|
-
|
|
467
|
+
- `db.transaction(async (session) => ...)` throws on standalone servers by
|
|
468
|
+
default. To accept non-atomic execution explicitly, pass
|
|
469
|
+
`{ allowNonTransactionalFallback: true }`; the callback then receives `null`.
|
|
460
470
|
- `createMongoMigrationRunner(service, { migrationDir })` — file-based migrations
|
|
461
|
-
(`NNN_name.ts`, each exporting `up` / `down`) with a
|
|
462
|
-
journal (`_migrations`), safe under concurrent runners
|
|
471
|
+
(`NNN_name.ts`, each exporting `up` / `down`) with a lease- and owner-token-
|
|
472
|
+
fenced journal (`_migrations`), safe under concurrent runners and stale-worker
|
|
473
|
+
takeover. Migrations should remain idempotent: file migrations are not
|
|
474
|
+
automatically wrapped in a database transaction.
|
|
463
475
|
|
|
464
476
|
```ts
|
|
465
477
|
const runner = createMongoMigrationRunner(service, { migrationDir: './migrations' });
|
|
@@ -501,8 +513,8 @@ reports current size plus lifetime `hits` / `misses` / `sets` / `deletes` /
|
|
|
501
513
|
> ⚠️ **Cache invalidation is write-through only.** Every ninox write drops that
|
|
502
514
|
> collection's cached reads, but reads are **not** invalidated by external
|
|
503
515
|
> writers — other processes, the raw `client` escape hatch, or direct DB
|
|
504
|
-
> writes.
|
|
505
|
-
>
|
|
516
|
+
> writes. The default `ttlMs: 30_000` bounds that staleness; `ttlMs: 0` is an
|
|
517
|
+
> explicit unbounded-cache opt-in. Multi-writer deployments can disable the cache,
|
|
506
518
|
> route latency-critical reads through the change-stream-aware
|
|
507
519
|
> [`createHotCache()`](#hot-cache-high-throughput), or — on a replica set — opt
|
|
508
520
|
> into `cacheWatch: true`:
|
|
@@ -786,16 +798,18 @@ you need the code → status mapping yourself.
|
|
|
786
798
|
> (at-least-once); opt in per op with `retryWrites: true`. Reads always retry
|
|
787
799
|
> transient errors.
|
|
788
800
|
|
|
789
|
-
Schema validation is enforced **by MongoDB** —
|
|
790
|
-
|
|
791
|
-
|
|
801
|
+
Schema validation is enforced **by ninox and MongoDB** — inserts and full
|
|
802
|
+
replacements are validated client-side by default (`validateWrites: false` opts
|
|
803
|
+
out), while the DB `$jsonSchema` validator remains the backstop for partial
|
|
804
|
+
updates, raw writes, and other clients. Violations raise `VALIDATION_FAILED`. `createSchema` is **idempotent and
|
|
792
805
|
self-reconciling**: it provisions a NEW collection, and when the collection
|
|
793
806
|
already exists it upgrades the DB schema to match the current ORM schema
|
|
794
807
|
(hot-swapping the validator via `collMod` only when it has drifted, and
|
|
795
808
|
creating any newly-declared indexes) — so calling it on every boot keeps
|
|
796
809
|
Mongo's schema in lockstep with your models as they change. `updateSchema`
|
|
797
|
-
hot-swaps a validator explicitly (via `collMod`)
|
|
798
|
-
|
|
810
|
+
hot-swaps a validator explicitly (via `collMod`) and updates the manager's
|
|
811
|
+
active schema. Client validation covers the DSL and raw `$jsonSchema` keywords;
|
|
812
|
+
partial update operators are still enforced by the database.
|
|
799
813
|
|
|
800
814
|
- **Strict by default** — `additionalProperties: false` is emitted unless a
|
|
801
815
|
field opts out (`s.object({ ... }, { additionalProperties: true })`), so
|
|
@@ -898,6 +912,8 @@ createMongoService(clients, {
|
|
|
898
912
|
cache: { maxSize: 1000, ttlMs: 30_000, clone: true }, // configure the default cache
|
|
899
913
|
cacheWatch: true, // change-stream invalidation of the cache (replica sets)
|
|
900
914
|
drift: 'report', // read-time schema-drift detection ('report'|'throw'|'off')
|
|
915
|
+
validateWrites: true, // validate inserts/replacements before the DB call
|
|
916
|
+
allowNonTransactionalFallback: false, // throw instead of losing atomicity
|
|
901
917
|
dedupeReads: true,
|
|
902
918
|
perf: true, // master switch for cache + dedup
|
|
903
919
|
});
|
|
@@ -908,8 +924,8 @@ createMongoService(clients, {
|
|
|
908
924
|
- `service.health()` — ping every connected DB and report `{ ok, latencyMs, dbs }`.
|
|
909
925
|
- **Multi-DB services** — define several clients in one service; each gets its own
|
|
910
926
|
typed manager (`service.db.primaryClient`, `service.db.auditClient`, …), one
|
|
911
|
-
connection pool per URL, and **cache/dedup keys are namespaced by
|
|
912
|
-
same-named collections
|
|
927
|
+
connection pool per URL, and **cache/dedup keys are namespaced by deployment,
|
|
928
|
+
database, and collection** so same-named collections never collide.
|
|
913
929
|
- `watchCollection` / repository `.watch()` — caller-owned change streams.
|
|
914
930
|
- `eachDb(fn)` — run a function over every connected manager.
|
|
915
931
|
|
|
@@ -1000,8 +1016,8 @@ bun run bench # → bench/results/summary.json
|
|
|
1000
1016
|
|
|
1001
1017
|
**Multi-DB cache isolation.** A single service can define several DB clients; the
|
|
1002
1018
|
query cache and in-flight dedup are shared across them, and their keys are
|
|
1003
|
-
namespaced by **database** —
|
|
1004
|
-
databases can never share (or coalesce) entries.
|
|
1019
|
+
namespaced by **deployment and database** — same-named physical collections in
|
|
1020
|
+
different databases or clusters can never share (or coalesce) entries.
|
|
1005
1021
|
|
|
1006
1022
|
**Standalone HotCache freshness is opt-in per query.** In standalone mode the
|
|
1007
1023
|
ticker only refreshes queries that set `refreshIntervalMs`. A query with neither
|
|
@@ -1037,9 +1053,16 @@ the cache-effectiveness signals to watch in production.
|
|
|
1037
1053
|
## Tests
|
|
1038
1054
|
|
|
1039
1055
|
```bash
|
|
1040
|
-
bun test
|
|
1056
|
+
bun test # unit + integration (Mongo suites skip when no server is reachable)
|
|
1057
|
+
bun run test:e2e # public-API workflows; fails unless MONGO_URL is reachable
|
|
1041
1058
|
```
|
|
1042
1059
|
|
|
1060
|
+
The e2e suite exercises real MongoDB schema validation, CRUD/repository flows,
|
|
1061
|
+
relations, aggregation, both pagination strategies, cache consistency,
|
|
1062
|
+
migrations, multi-DB behavior, and health checks. On a replica set it also
|
|
1063
|
+
verifies transaction commit/rollback; on standalone it verifies the explicit
|
|
1064
|
+
non-transactional fallback. Set `MONGO_URL` to select the server.
|
|
1065
|
+
|
|
1043
1066
|
## Development
|
|
1044
1067
|
|
|
1045
1068
|
```bash
|
|
@@ -1058,7 +1081,8 @@ npm pack --dry-run # inspect the published tarball contents
|
|
|
1058
1081
|
The `files` allowlist ships `dist/`, `LICENSE`, and `README.md` — no `src/`,
|
|
1059
1082
|
tests, or examples. CI enforces typecheck, lint, dependency audit, coverage
|
|
1060
1083
|
(≥ 85%), the full example suite, a replica-set job for the HotCache
|
|
1061
|
-
change-stream tests,
|
|
1084
|
+
change-stream tests, e2e compatibility jobs for MongoDB 4.4/5/6/7/8, and an
|
|
1085
|
+
`npm pack` → fresh Node consumer that runs real CRUD and pagination.
|
|
1062
1086
|
|
|
1063
1087
|
Release notes are kept in [`CHANGELOG.md`](./CHANGELOG.md). The publish gate
|
|
1064
1088
|
(`prepublishOnly`) runs typecheck + lint + build.
|