@classytic/arc 2.8.0 → 2.8.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/README.md +10 -1
- package/dist/{BaseController-CpMfCXdn.mjs → BaseController-DAGGc5Xn.mjs} +76 -25
- package/dist/{EventTransport-n1KBxC_N.d.mts → EventTransport-CLXJUzyT.d.mts} +37 -1
- package/dist/{ResourceRegistry-BOtJuRCs.mjs → ResourceRegistry-Dtcojmu8.mjs} +14 -2
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +1 -1
- package/dist/{adapters-BxGgSHjj.mjs → adapters-BBqAVvPK.mjs} +11 -0
- package/dist/auth/index.d.mts +1 -1
- package/dist/auth/index.mjs +3 -3
- package/dist/{betterAuthOpenApi-CHCIuA-p.mjs → betterAuthOpenApi-C5lDyRH2.mjs} +1 -1
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +4 -4
- package/dist/{core-BfrfxNqO.mjs → core-CrLDuqoT.mjs} +1 -1
- package/dist/{createActionRouter-CbkIAaGh.mjs → createActionRouter-Df1BuawX.mjs} +87 -21
- package/dist/{createApp-Cy8eUNKQ.mjs → createApp-p2OThysU.mjs} +2 -2
- package/dist/{defineResource-CovBXvTB.mjs → defineResource-CqeUltrW.mjs} +19 -7
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +1 -1
- package/dist/dynamic/index.d.mts +1 -1
- package/dist/dynamic/index.mjs +1 -1
- package/dist/{errorHandler-BW08lEiy.mjs → errorHandler-Cw34h_om.mjs} +1 -1
- package/dist/{errorHandler-BeN-ERN7.d.mts → errorHandler-DJ7OAB2V.d.mts} +1 -1
- package/dist/{eventPlugin-CAOWMQS8.d.mts → eventPlugin-Cdjwo0Gv.d.mts} +1 -1
- package/dist/{eventPlugin-x4jo3sG0.mjs → eventPlugin-XijlQmlL.mjs} +19 -1
- package/dist/events/index.d.mts +399 -28
- package/dist/events/index.mjs +345 -29
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +1 -1
- package/dist/hooks/index.d.mts +1 -1
- package/dist/{index-BpMhrFgn.d.mts → index-0zj73o2U.d.mts} +1 -1
- package/dist/{index-qct60lnl.d.mts → index-DadoLP51.d.mts} +35 -3
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +7 -7
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +2 -2
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/{interface-IJqN3pXK.d.mts → interface-CS6d7HiB.d.mts} +549 -107
- package/dist/{openapi-AYLVjqVe.mjs → openapi-q6rNKfZy.mjs} +49 -2
- package/dist/org/index.d.mts +1 -1
- package/dist/plugins/index.d.mts +2 -2
- package/dist/plugins/index.mjs +3 -3
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/index.d.mts +3 -3
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/{redis-stream-CF1lrKVk.d.mts → redis-stream-BgrYzpeq.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +1 -1
- package/dist/{resourceToTools-C_1SMiCz.mjs → resourceToTools-DNNWnZtx.mjs} +193 -63
- package/dist/rpc/index.mjs +1 -1
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +1 -1
- package/dist/types/index.d.mts +2 -2
- package/dist/{types-gUxAIZHp.d.mts → types-BlOuKTPw.d.mts} +4 -4
- package/dist/{types-Ct0PUUSp.d.mts → types-D3b7hA00.d.mts} +1 -1
- package/dist/utils/index.d.mts +2 -14
- package/dist/utils/index.mjs +5 -5
- package/dist/{utils-B-l6410F.mjs → utils-7sJ8X83I.mjs} +1 -13
- package/package.json +4 -3
- /package/dist/{circuitBreaker-l18oRgL5.mjs → circuitBreaker-cmi5XDv5.mjs} +0 -0
- /package/dist/{errors-Cg58SLNi.mjs → errors-BF2bIOIS.mjs} +0 -0
- /package/dist/{requestContext-xHIKedG6.mjs → requestContext-DYvHl113.mjs} +0 -0
- /package/dist/{schemaConverter-Y5EejTnJ.mjs → schemaConverter-OxfCshus.mjs} +0 -0
|
@@ -5,7 +5,7 @@ import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, Rout
|
|
|
5
5
|
|
|
6
6
|
//#region src/hooks/HookSystem.d.ts
|
|
7
7
|
type HookPhase = "before" | "around" | "after";
|
|
8
|
-
type HookOperation = "create" | "update" | "delete" | "read" | "list";
|
|
8
|
+
type HookOperation = "create" | "update" | "delete" | "restore" | "read" | "list";
|
|
9
9
|
interface HookContext<T = AnyRecord> {
|
|
10
10
|
resource: string;
|
|
11
11
|
operation: HookOperation;
|
|
@@ -318,116 +318,479 @@ type PipelineConfig = PipelineStep[] | {
|
|
|
318
318
|
//#endregion
|
|
319
319
|
//#region src/types/repository.d.ts
|
|
320
320
|
/**
|
|
321
|
-
* Repository Interface
|
|
321
|
+
* Repository Interface — Database-Agnostic CRUD Contract
|
|
322
322
|
*
|
|
323
|
-
* This is the
|
|
324
|
-
*
|
|
323
|
+
* This is the canonical contract every arc-compatible repository follows.
|
|
324
|
+
* It is intentionally structural: any object matching the shape works,
|
|
325
|
+
* including the reference implementation at `@classytic/mongokit` and any
|
|
326
|
+
* future `prismakit` / `pgkit` / `sqlitekit` that mirrors it.
|
|
325
327
|
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
328
|
+
* ## Design
|
|
329
|
+
*
|
|
330
|
+
* The interface is tiered so a minimal adapter can ship with five methods
|
|
331
|
+
* while a mature one (mongokit 3.6+) can opt into the full surface without
|
|
332
|
+
* type assertions:
|
|
333
|
+
*
|
|
334
|
+
* 1. **Required** — `getAll`, `getById`, `create`, `update`, `delete`.
|
|
335
|
+
* Every resource needs these; arc's BaseController assumes they exist.
|
|
336
|
+
*
|
|
337
|
+
* 2. **Recommended** — `getOne` / `getByQuery`. Used by AccessControl to
|
|
338
|
+
* enforce compound filters (idField + org scope + policy). Without them,
|
|
339
|
+
* arc falls back to `getById` + post-fetch checks, which is slower and
|
|
340
|
+
* produces wrong 404s on custom idFields.
|
|
341
|
+
*
|
|
342
|
+
* 3. **Optional capabilities** — batch ops, soft delete, aggregation,
|
|
343
|
+
* transactions, etc. Declared as optional so kits implement only what
|
|
344
|
+
* their underlying DB supports. arc feature-detects at runtime.
|
|
345
|
+
*
|
|
346
|
+
* All options/results are named types so custom kits can import and
|
|
347
|
+
* implement them directly:
|
|
329
348
|
*
|
|
330
|
-
*
|
|
349
|
+
* ```ts
|
|
350
|
+
* import type {
|
|
351
|
+
* CrudRepository,
|
|
352
|
+
* DeleteOptions,
|
|
353
|
+
* DeleteResult,
|
|
354
|
+
* PaginationResult,
|
|
355
|
+
* UpdateManyResult,
|
|
356
|
+
* BulkWriteOperation,
|
|
357
|
+
* BulkWriteResult,
|
|
358
|
+
* } from '@classytic/arc';
|
|
359
|
+
*
|
|
360
|
+
* class PgRepository<TDoc> implements CrudRepository<TDoc> { … }
|
|
361
|
+
* ```
|
|
362
|
+
*
|
|
363
|
+
* @example Reference implementation
|
|
364
|
+
* ```ts
|
|
365
|
+
* import type { CrudRepository } from '@classytic/arc';
|
|
331
366
|
* const userRepo: CrudRepository<UserDocument> = new Repository(UserModel);
|
|
332
367
|
* ```
|
|
368
|
+
*
|
|
369
|
+
* ## Contract gotchas (learned from mongokit 3.6 integration)
|
|
370
|
+
*
|
|
371
|
+
* If you build a custom kit that implements this contract, these are the
|
|
372
|
+
* behaviors arc's tests specifically verify. Align your kit here and
|
|
373
|
+
* arc's `BaseController` + presets will work out of the box:
|
|
374
|
+
*
|
|
375
|
+
* 1. **`getById` / `getOne` miss semantics** — MAY return `null` or throw a
|
|
376
|
+
* 404-style error whose message contains "not found". Arc handles both.
|
|
377
|
+
* Pick one and document it in your kit.
|
|
378
|
+
*
|
|
379
|
+
* 2. **`deleteMany` with soft-delete** — if your kit intercepts
|
|
380
|
+
* `deleteMany` and rewrites it to `updateMany`, the returned
|
|
381
|
+
* `deletedCount` may be `0` even when N docs were soft-deleted. The
|
|
382
|
+
* authoritative count comes from a follow-up query. Consumers shouldn't
|
|
383
|
+
* rely on `deletedCount` reflecting soft-delete work unless your kit
|
|
384
|
+
* promises it.
|
|
385
|
+
*
|
|
386
|
+
* 3. **Lifecycle hooks are shared with plugins** — never use
|
|
387
|
+
* `removeAllListeners(event)` to clean up test hooks. That silently
|
|
388
|
+
* removes soft-delete, cascade, multi-tenant, and audit plugin
|
|
389
|
+
* listeners too, which then makes subsequent operations misbehave
|
|
390
|
+
* (e.g. a soft-delete becomes a hard delete). Always use
|
|
391
|
+
* `.off(event, fn)` with the specific handler reference you registered.
|
|
392
|
+
*
|
|
393
|
+
* 4. **Hard-delete mode** — `delete(id, { mode: 'hard' })` and
|
|
394
|
+
* `deleteMany(q, { mode: 'hard' })` MUST bypass soft-delete
|
|
395
|
+
* interception while still running policy / multi-tenant / cascade /
|
|
396
|
+
* audit hooks. Kits without soft-delete should accept and ignore the
|
|
397
|
+
* flag.
|
|
398
|
+
*
|
|
399
|
+
* 5. **Keyset pagination auto-detection** — `getAll({ sort, limit })`
|
|
400
|
+
* without `page` SHOULD return a `KeysetPaginatedResult` with
|
|
401
|
+
* `method: "keyset"`. Kits that only offer offset pagination can return
|
|
402
|
+
* the legacy offset shape; arc's types still satisfy.
|
|
403
|
+
*
|
|
404
|
+
* 6. **`idField` identity** — kits that key on anything other than `"_id"`
|
|
405
|
+
* MUST set `readonly idField` on the repository so arc's BaseController
|
|
406
|
+
* passes route params straight through to `update`/`delete`/`restore`
|
|
407
|
+
* without translating them.
|
|
408
|
+
*
|
|
409
|
+
* 7. **`before:restore` / `after:restore` hooks** — if you implement
|
|
410
|
+
* `restore`, fire these hooks symmetrically with `before:delete` /
|
|
411
|
+
* `after:delete` so hosts can wire cascade-restore flows.
|
|
412
|
+
*
|
|
413
|
+
* See `tests/core/repository-contract-mongokit.test.ts` for a runnable
|
|
414
|
+
* reference against mongokit 3.6. Copy it, swap in your kit's repository,
|
|
415
|
+
* and make it pass — if everything's green, arc will work against your
|
|
416
|
+
* kit.
|
|
333
417
|
*/
|
|
334
418
|
/**
|
|
335
|
-
*
|
|
419
|
+
* Opaque transaction session. Adapters bind this to their own type
|
|
420
|
+
* (Mongoose `ClientSession`, Prisma transaction client, `pg.Client`, …).
|
|
421
|
+
*/
|
|
422
|
+
type RepositorySession = unknown;
|
|
423
|
+
/**
|
|
424
|
+
* Query options for read operations. Extended ad-hoc by adapters via the
|
|
425
|
+
* index signature — kit authors should namespace custom flags (e.g.
|
|
426
|
+
* `__pgHint`) to avoid collisions.
|
|
336
427
|
*/
|
|
337
428
|
interface QueryOptions {
|
|
338
|
-
/** Transaction session —
|
|
339
|
-
session?:
|
|
340
|
-
/**
|
|
341
|
-
select?: string | string[] | Record<string, 0 | 1>;
|
|
342
|
-
/** Relations to populate - string, array, or Mongoose populate options */
|
|
343
|
-
populate?: string | string[] | Record<string, unknown>;
|
|
344
|
-
/** Return plain JS objects instead of Mongoose documents */
|
|
429
|
+
/** Transaction session — adapter-specific concrete type */
|
|
430
|
+
session?: RepositorySession;
|
|
431
|
+
/** Return plain objects instead of driver documents */
|
|
345
432
|
lean?: boolean;
|
|
346
|
-
/**
|
|
433
|
+
/** Include soft-deleted docs in reads (honored by soft-delete plugin) */
|
|
434
|
+
includeDeleted?: boolean;
|
|
435
|
+
/** Forwarded to policy/tenant hooks */
|
|
436
|
+
user?: Record<string, unknown>;
|
|
437
|
+
/** Arc request-scoped metadata (orgId, roles, requestId, …) */
|
|
438
|
+
context?: Record<string, unknown>;
|
|
439
|
+
/**
|
|
440
|
+
* Adapter-specific escape hatch — `select`, `populate`, `populateOptions`,
|
|
441
|
+
* `readPreference`, `maxTimeMS`, and every kit's driver-specific flags
|
|
442
|
+
* flow through here. Arc intentionally does NOT type these concretely
|
|
443
|
+
* because each kit's DB shapes them differently: mongoose uses
|
|
444
|
+
* `PopulateOptions[]`, prisma uses `{ include: {...} }`, pgkit uses SQL
|
|
445
|
+
* JOIN hints, etc. Typing them as (say) `string | Record<string, unknown>`
|
|
446
|
+
* would REJECT the narrower shapes real kits actually expose, breaking
|
|
447
|
+
* structural assignability of `Repository<T> → CrudRepository<T>`.
|
|
448
|
+
*/
|
|
347
449
|
[key: string]: unknown;
|
|
348
450
|
}
|
|
349
451
|
/**
|
|
350
|
-
*
|
|
452
|
+
* Options for write operations (create/update). Superset of QueryOptions
|
|
453
|
+
* so callers can pass a single options object.
|
|
454
|
+
*/
|
|
455
|
+
interface WriteOptions extends QueryOptions {
|
|
456
|
+
/** Upsert on update/replace operations */
|
|
457
|
+
upsert?: boolean;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Options for delete operations.
|
|
461
|
+
*
|
|
462
|
+
* `mode: 'hard'` opts out of the soft-delete interception when the adapter
|
|
463
|
+
* has a soft-delete plugin wired. Policy, cascade, audit, and cache hooks
|
|
464
|
+
* still fire — only the soft-delete rewrite is bypassed. Use for GDPR
|
|
465
|
+
* erasure or admin purge paths.
|
|
466
|
+
*/
|
|
467
|
+
interface DeleteOptions extends QueryOptions {
|
|
468
|
+
/**
|
|
469
|
+
* Force physical deletion even when soft-delete is active, or force soft
|
|
470
|
+
* when the default would be hard. Adapters without soft-delete support
|
|
471
|
+
* MUST ignore this flag (it is a hint, not a contract).
|
|
472
|
+
*/
|
|
473
|
+
mode?: "hard" | "soft";
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Result of a single delete operation.
|
|
477
|
+
*
|
|
478
|
+
* Matches mongokit's shape. Adapters without soft-delete awareness can omit
|
|
479
|
+
* `soft` and `count`. Arc's BaseController uses the `success` flag to decide
|
|
480
|
+
* whether to return 200 or 404.
|
|
481
|
+
*/
|
|
482
|
+
interface DeleteResult {
|
|
483
|
+
success: boolean;
|
|
484
|
+
message: string;
|
|
485
|
+
/** Primary key of the removed doc (string form) */
|
|
486
|
+
id?: string;
|
|
487
|
+
/** True when a soft-delete plugin intercepted the operation */
|
|
488
|
+
soft?: boolean;
|
|
489
|
+
/** For batch-variant implementations that return the delete count inline */
|
|
490
|
+
count?: number;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Result of a batch delete (`deleteMany`) — distinct from single `delete`
|
|
494
|
+
* because MongoDB's driver returns a different shape for batch operations.
|
|
495
|
+
*
|
|
496
|
+
* **Soft-delete gotcha** — when a soft-delete plugin intercepts
|
|
497
|
+
* `deleteMany` by rewriting it to `updateMany` internally (mongokit 3.6
|
|
498
|
+
* does this in `before:deleteMany`), the `deletedCount` returned here may
|
|
499
|
+
* be `0` because the underlying `Model.deleteMany` was never called. The
|
|
500
|
+
* affected-row count lives inside the hook's `updateMany` result and is
|
|
501
|
+
* not surfaced to the caller. Consumers that need the exact soft-deleted
|
|
502
|
+
* count should run a follow-up query (`repo.count({ deletedAt: { $ne:
|
|
503
|
+
* null }, ...filter })`). 3rd-party kits with soft-delete should document
|
|
504
|
+
* which convention they follow.
|
|
505
|
+
*/
|
|
506
|
+
interface DeleteManyResult {
|
|
507
|
+
/** Driver-reported acknowledgement */
|
|
508
|
+
acknowledged?: boolean;
|
|
509
|
+
/**
|
|
510
|
+
* Number of documents removed. May be 0 when soft-delete intercepts;
|
|
511
|
+
* see the "Soft-delete gotcha" note above.
|
|
512
|
+
*/
|
|
513
|
+
deletedCount: number;
|
|
514
|
+
/** True when a soft-delete plugin intercepted and did `updateMany` instead */
|
|
515
|
+
soft?: boolean;
|
|
516
|
+
}
|
|
517
|
+
/** Result of a bulk update operation. Matches MongoDB driver shape. */
|
|
518
|
+
interface UpdateManyResult {
|
|
519
|
+
acknowledged?: boolean;
|
|
520
|
+
matchedCount: number;
|
|
521
|
+
modifiedCount: number;
|
|
522
|
+
upsertedCount?: number;
|
|
523
|
+
upsertedId?: unknown;
|
|
524
|
+
}
|
|
525
|
+
/** Shape of a single operation passed to `bulkWrite`. */
|
|
526
|
+
type BulkWriteOperation<TDoc = unknown> = {
|
|
527
|
+
insertOne: {
|
|
528
|
+
document: Partial<TDoc>;
|
|
529
|
+
};
|
|
530
|
+
} | {
|
|
531
|
+
updateOne: {
|
|
532
|
+
filter: Record<string, unknown>;
|
|
533
|
+
update: Record<string, unknown>;
|
|
534
|
+
upsert?: boolean;
|
|
535
|
+
};
|
|
536
|
+
} | {
|
|
537
|
+
updateMany: {
|
|
538
|
+
filter: Record<string, unknown>;
|
|
539
|
+
update: Record<string, unknown>;
|
|
540
|
+
upsert?: boolean;
|
|
541
|
+
};
|
|
542
|
+
} | {
|
|
543
|
+
deleteOne: {
|
|
544
|
+
filter: Record<string, unknown>;
|
|
545
|
+
};
|
|
546
|
+
} | {
|
|
547
|
+
deleteMany: {
|
|
548
|
+
filter: Record<string, unknown>;
|
|
549
|
+
};
|
|
550
|
+
} | {
|
|
551
|
+
replaceOne: {
|
|
552
|
+
filter: Record<string, unknown>;
|
|
553
|
+
replacement: Partial<TDoc>;
|
|
554
|
+
upsert?: boolean;
|
|
555
|
+
};
|
|
556
|
+
};
|
|
557
|
+
/** Result of a heterogeneous bulk write. */
|
|
558
|
+
interface BulkWriteResult {
|
|
559
|
+
ok?: number;
|
|
560
|
+
insertedCount?: number;
|
|
561
|
+
matchedCount?: number;
|
|
562
|
+
modifiedCount?: number;
|
|
563
|
+
deletedCount?: number;
|
|
564
|
+
upsertedCount?: number;
|
|
565
|
+
insertedIds?: Record<number, unknown>;
|
|
566
|
+
upsertedIds?: Record<number, unknown>;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Pagination parameters for list operations.
|
|
570
|
+
*
|
|
571
|
+
* Supports three modes, auto-detected by the adapter:
|
|
572
|
+
* - **Offset** — pass `page` + `limit`.
|
|
573
|
+
* - **Keyset** — pass `sort` + `limit` (+ optional `after` cursor). Required
|
|
574
|
+
* for infinite scroll on large collections; O(1) per page.
|
|
575
|
+
* - **Raw** — pass neither; adapter returns all matching docs.
|
|
351
576
|
*/
|
|
352
577
|
interface PaginationParams<TDoc = unknown> {
|
|
353
578
|
/** Filter criteria */
|
|
354
579
|
filters?: Partial<TDoc> & Record<string, unknown>;
|
|
355
|
-
/** Sort
|
|
580
|
+
/** Sort spec — string (`"-createdAt"`) or object (`{ createdAt: -1 }`) */
|
|
356
581
|
sort?: string | Record<string, 1 | -1>;
|
|
357
|
-
/** Page number (1-indexed) */
|
|
582
|
+
/** Page number (1-indexed) — triggers offset pagination */
|
|
358
583
|
page?: number;
|
|
359
584
|
/** Items per page */
|
|
360
585
|
limit?: number;
|
|
361
|
-
/**
|
|
586
|
+
/** Opaque cursor from a prior `next` field — triggers keyset pagination */
|
|
587
|
+
after?: string;
|
|
588
|
+
/** Allow additional options (select, populate, search, …) */
|
|
362
589
|
[key: string]: unknown;
|
|
363
590
|
}
|
|
364
591
|
/**
|
|
365
|
-
*
|
|
592
|
+
* Offset-based paginated result (the default shape when `page` is provided).
|
|
593
|
+
*
|
|
594
|
+
* `method` is optional so legacy adapters returning the bare `{ docs, page,
|
|
595
|
+
* limit, total, pages, hasNext, hasPrev }` shape still satisfy the type.
|
|
366
596
|
*/
|
|
367
|
-
interface
|
|
368
|
-
/**
|
|
597
|
+
interface OffsetPaginatedResult<TDoc> {
|
|
598
|
+
/** Discriminator — omitted or `"offset"` */
|
|
599
|
+
method?: "offset";
|
|
369
600
|
docs: TDoc[];
|
|
370
|
-
/** Current page number */
|
|
371
601
|
page: number;
|
|
372
|
-
/** Items per page */
|
|
373
602
|
limit: number;
|
|
374
|
-
/** Total document count */
|
|
375
603
|
total: number;
|
|
376
|
-
/** Total page count */
|
|
377
604
|
pages: number;
|
|
378
|
-
/** Has next page */
|
|
379
605
|
hasNext: boolean;
|
|
380
|
-
/** Has previous page */
|
|
381
606
|
hasPrev: boolean;
|
|
382
607
|
}
|
|
608
|
+
/**
|
|
609
|
+
* Keyset-based paginated result (returned when `sort` is provided without
|
|
610
|
+
* `page`). Ideal for infinite scroll — no `count()` query, O(1) per page.
|
|
611
|
+
*/
|
|
612
|
+
interface KeysetPaginatedResult<TDoc> {
|
|
613
|
+
/** Discriminator — always `"keyset"` */
|
|
614
|
+
method: "keyset";
|
|
615
|
+
docs: TDoc[];
|
|
616
|
+
limit: number;
|
|
617
|
+
hasMore: boolean;
|
|
618
|
+
/** Opaque cursor token for the next page, or `null` at the end */
|
|
619
|
+
next: string | null;
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Discriminated union of all pagination result shapes.
|
|
623
|
+
* Consumers narrow on the `method` discriminator.
|
|
624
|
+
*
|
|
625
|
+
* @example
|
|
626
|
+
* ```ts
|
|
627
|
+
* const result = await repo.getAll(params);
|
|
628
|
+
* if (result.method === "keyset") {
|
|
629
|
+
* // result.next, result.hasMore
|
|
630
|
+
* } else {
|
|
631
|
+
* // result.page, result.total, result.pages
|
|
632
|
+
* }
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
type PaginationResult<TDoc> = OffsetPaginatedResult<TDoc> | KeysetPaginatedResult<TDoc>;
|
|
636
|
+
/**
|
|
637
|
+
* Legacy alias. Existing code typed as `PaginatedResult<TDoc>` continues
|
|
638
|
+
* to work unchanged — it resolves to the offset shape, which is the most
|
|
639
|
+
* common. New code should prefer `PaginationResult<TDoc>` for the full
|
|
640
|
+
* discriminated union.
|
|
641
|
+
*/
|
|
642
|
+
type PaginatedResult<TDoc> = OffsetPaginatedResult<TDoc>;
|
|
383
643
|
/**
|
|
384
644
|
* Standard CRUD Repository Interface
|
|
385
645
|
*
|
|
386
|
-
*
|
|
387
|
-
*
|
|
646
|
+
* The canonical contract arc consumes. Tiered so minimal adapters only
|
|
647
|
+
* implement the required five methods; richer kits declare the optional
|
|
648
|
+
* capabilities they support.
|
|
649
|
+
*
|
|
650
|
+
* Every optional method is feature-detected at runtime by arc's
|
|
651
|
+
* BaseController and presets — implement only what your DB can express.
|
|
388
652
|
*
|
|
389
653
|
* @typeParam TDoc - The document/entity type
|
|
390
654
|
*/
|
|
391
655
|
interface CrudRepository<TDoc> {
|
|
392
656
|
/**
|
|
393
|
-
*
|
|
657
|
+
* Native primary key field. Defaults to `"_id"` (Mongo convention).
|
|
658
|
+
*
|
|
659
|
+
* Set to match `defineResource({ idField })` for kits that key on a
|
|
660
|
+
* custom field (e.g. `"id"`, `"uuid"`, `"slug"`). Arc's BaseController
|
|
661
|
+
* reads this to decide whether to pass route params straight through
|
|
662
|
+
* to `update`/`delete`/`restore` or to translate them via a fetched
|
|
663
|
+
* doc's `_id` first.
|
|
394
664
|
*/
|
|
395
|
-
|
|
665
|
+
readonly idField?: string;
|
|
396
666
|
/**
|
|
397
|
-
*
|
|
667
|
+
* List documents with pagination. Adapter auto-selects offset vs keyset
|
|
668
|
+
* mode based on the presence of `page` or `after` in `params`.
|
|
669
|
+
*
|
|
670
|
+
* Return shapes (all valid under the contract):
|
|
671
|
+
* - `OffsetPaginatedResult<TDoc>` — when `page` is given
|
|
672
|
+
* - `KeysetPaginatedResult<TDoc>` — when `sort` + optional `after` are given
|
|
673
|
+
* - `TDoc[]` — raw array, when neither `page` nor `sort` drives pagination
|
|
674
|
+
*
|
|
675
|
+
* Arc's BaseController narrows the union before returning to clients.
|
|
676
|
+
*/
|
|
677
|
+
getAll(params?: PaginationParams<TDoc>, options?: QueryOptions): Promise<PaginationResult<TDoc> | TDoc[]>;
|
|
678
|
+
/**
|
|
679
|
+
* Fetch a single document by its primary key.
|
|
680
|
+
*
|
|
681
|
+
* **Miss semantics — kits may EITHER return `null` OR throw a 404-style
|
|
682
|
+
* error.** Arc's `BaseController` handles both: `AccessControl.fetchWith
|
|
683
|
+
* AccessControl` catches errors whose message contains "not found" and
|
|
684
|
+
* converts them to null. 3rd-party kit authors: pick one convention and
|
|
685
|
+
* document it. mongokit 3.6 throws by default; pass
|
|
686
|
+
* `{ throwOnNotFound: false }` to get null. A SQL kit that returns null
|
|
687
|
+
* directly is equally valid.
|
|
398
688
|
*/
|
|
399
689
|
getById(id: string, options?: QueryOptions): Promise<TDoc | null>;
|
|
690
|
+
/** Insert a single document. */
|
|
691
|
+
create(data: Partial<TDoc>, options?: WriteOptions): Promise<TDoc>;
|
|
692
|
+
/** Update a document by primary key. Returns the updated doc or null. */
|
|
693
|
+
update(id: string, data: Partial<TDoc>, options?: WriteOptions): Promise<TDoc | null>;
|
|
400
694
|
/**
|
|
401
|
-
*
|
|
695
|
+
* Delete a document by primary key. Pass `{ mode: 'hard' }` to bypass
|
|
696
|
+
* soft-delete interception.
|
|
402
697
|
*/
|
|
403
|
-
|
|
404
|
-
session?: unknown;
|
|
405
|
-
[key: string]: unknown;
|
|
406
|
-
}): Promise<TDoc>;
|
|
698
|
+
delete(id: string, options?: DeleteOptions): Promise<DeleteResult>;
|
|
407
699
|
/**
|
|
408
|
-
*
|
|
700
|
+
* Find a single doc by a compound filter. Used by arc's AccessControl to
|
|
701
|
+
* combine `idField + orgId + policy` in one query. Without it, arc falls
|
|
702
|
+
* back to `getById` + post-fetch scope checks (slower; 404s on custom
|
|
703
|
+
* idFields if the doc lives outside the user's scope).
|
|
704
|
+
*
|
|
705
|
+
* Miss semantics match `getById` — kits may return null or throw. Arc
|
|
706
|
+
* handles both. See the note on `getById` above.
|
|
409
707
|
*/
|
|
410
|
-
|
|
708
|
+
getOne?(filter: Record<string, unknown>, options?: QueryOptions): Promise<TDoc | null>;
|
|
709
|
+
/** Alias many kits expose alongside `getOne`. Arc checks both. */
|
|
710
|
+
getByQuery?(filter: Record<string, unknown>, options?: QueryOptions): Promise<TDoc | null>;
|
|
711
|
+
/** Count matching documents. Respects soft-delete when applicable. */
|
|
712
|
+
count?(filter?: Record<string, unknown>, options?: QueryOptions): Promise<number>;
|
|
411
713
|
/**
|
|
412
|
-
*
|
|
714
|
+
* Cheap existence check. Kits may return `boolean` or `{ _id }` — arc
|
|
715
|
+
* coerces to boolean at the call site.
|
|
413
716
|
*/
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
/**
|
|
717
|
+
exists?(filter: Record<string, unknown>, options?: QueryOptions): Promise<boolean | {
|
|
718
|
+
_id: unknown;
|
|
719
|
+
} | null>;
|
|
720
|
+
/** Return the distinct values of a field matching the filter. */
|
|
721
|
+
distinct?<T = unknown>(field: string, filter?: Record<string, unknown>, options?: QueryOptions): Promise<T[]>;
|
|
722
|
+
/** Return all matching docs as a raw array (no pagination metadata). */
|
|
723
|
+
findAll?(filter?: Record<string, unknown>, options?: QueryOptions): Promise<TDoc[]>;
|
|
724
|
+
/**
|
|
725
|
+
* Atomic "find or create" — return the doc matching the filter, or
|
|
726
|
+
* insert `data` and return it if none exists. MAY return `null` when
|
|
727
|
+
* neither path produces a document (e.g. race loss + validation error
|
|
728
|
+
* handling — mongokit returns null in this window).
|
|
729
|
+
*/
|
|
730
|
+
getOrCreate?(filter: Record<string, unknown>, data: Partial<TDoc>, options?: WriteOptions): Promise<TDoc | null>;
|
|
731
|
+
/** Insert multiple documents in one call. */
|
|
732
|
+
createMany?(items: Array<Partial<TDoc>>, options?: WriteOptions): Promise<TDoc[]>;
|
|
733
|
+
/**
|
|
734
|
+
* Update all documents matching `filter`. Should reject empty filters
|
|
735
|
+
* to prevent accidental mass updates (mongokit does this).
|
|
736
|
+
*/
|
|
737
|
+
updateMany?(filter: Record<string, unknown>, data: Record<string, unknown>, options?: WriteOptions): Promise<UpdateManyResult>;
|
|
738
|
+
/**
|
|
739
|
+
* Delete all documents matching `filter`. Soft-deletes when a soft-delete
|
|
740
|
+
* plugin is wired; pass `{ mode: 'hard' }` to force physical removal.
|
|
741
|
+
*/
|
|
742
|
+
deleteMany?(filter: Record<string, unknown>, options?: DeleteOptions): Promise<DeleteManyResult>;
|
|
743
|
+
/**
|
|
744
|
+
* Heterogeneous bulk write (insertOne / updateOne / deleteMany / …).
|
|
745
|
+
*
|
|
746
|
+
* Structurally typed as `unknown` because each kit uses its own operation
|
|
747
|
+
* shape — mongoose uses `AnyBulkWriteOperation[]`, prisma builds these
|
|
748
|
+
* from its client-extension API, pgkit uses SQL primitives. Arc does
|
|
749
|
+
* not call `bulkWrite` internally, so the exact shape is kit-specific.
|
|
750
|
+
* See `BulkWriteOperation<TDoc>` (exported from arc) for a reference
|
|
751
|
+
* shape you can use when implementing your own kit; mongokit-compatible
|
|
752
|
+
* callers should import its own operation types.
|
|
753
|
+
*/
|
|
754
|
+
bulkWrite?: unknown;
|
|
755
|
+
/** Restore a soft-deleted document. Should fire `before:restore` hooks. */
|
|
756
|
+
restore?(id: string, options?: QueryOptions): Promise<TDoc | null>;
|
|
757
|
+
/** Paginated list of soft-deleted documents. */
|
|
758
|
+
getDeleted?(params?: PaginationParams<TDoc>, options?: QueryOptions): Promise<PaginationResult<TDoc> | TDoc[]>;
|
|
759
|
+
/**
|
|
760
|
+
* Run an aggregation pipeline.
|
|
761
|
+
*
|
|
762
|
+
* Structurally typed as `unknown` because each kit uses a different
|
|
763
|
+
* stage type (mongoose's `PipelineStage`, prisma's client-extension
|
|
764
|
+
* builders, pgkit's query-builder primitives, …). Arc does not call
|
|
765
|
+
* `aggregate` internally — it's a capability consumers use directly on
|
|
766
|
+
* the repo. Cast or re-declare at the call site using your kit's types.
|
|
767
|
+
*/
|
|
768
|
+
aggregate?: unknown;
|
|
769
|
+
/**
|
|
770
|
+
* Paginated aggregation. Same kit-specificity reasoning as `aggregate`
|
|
771
|
+
* — structurally `unknown`, type-safe at the call site.
|
|
772
|
+
*/
|
|
773
|
+
aggregatePaginate?: unknown;
|
|
774
|
+
/**
|
|
775
|
+
* Run `callback` inside a transaction. Adapters should auto-retry on
|
|
776
|
+
* transient transaction errors and expose a `session` the callback can
|
|
777
|
+
* forward to subsequent repo calls.
|
|
778
|
+
*/
|
|
779
|
+
withTransaction?<T>(callback: (session: RepositorySession) => Promise<T>, options?: Record<string, unknown>): Promise<T>;
|
|
780
|
+
/** slugLookup preset — fetch by a business slug. */
|
|
781
|
+
getBySlug?(slug: string, options?: QueryOptions): Promise<TDoc | null>;
|
|
782
|
+
/** tree preset — return the full hierarchy. */
|
|
783
|
+
getTree?(options?: QueryOptions): Promise<TDoc[]>;
|
|
784
|
+
/** tree preset — return direct children of a node. */
|
|
785
|
+
getChildren?(parentId: string, options?: QueryOptions): Promise<TDoc[]>;
|
|
422
786
|
[key: string]: unknown;
|
|
423
787
|
}
|
|
424
788
|
/**
|
|
425
|
-
* Extract document type from a repository
|
|
789
|
+
* Extract document type from a repository.
|
|
426
790
|
*
|
|
427
791
|
* @example
|
|
428
|
-
* ```
|
|
792
|
+
* ```ts
|
|
429
793
|
* type UserDoc = InferDoc<typeof userRepository>;
|
|
430
|
-
* // UserDoc is now the document type of userRepository
|
|
431
794
|
* ```
|
|
432
795
|
*/
|
|
433
796
|
type InferDoc<R> = R extends CrudRepository<infer T> ? T : never;
|
|
@@ -465,6 +828,16 @@ declare class ResourceDefinition<TDoc = AnyRecord> {
|
|
|
465
828
|
readonly customSchemas: CrudSchemas;
|
|
466
829
|
readonly permissions: ResourcePermissions;
|
|
467
830
|
readonly additionalRoutes: AdditionalRoute[];
|
|
831
|
+
/**
|
|
832
|
+
* Original v2.8 `routes` declaration — retained for downstream consumers
|
|
833
|
+
* (OpenAPI, MCP, registry, CLI introspect). Preserves fields dropped during
|
|
834
|
+
* normalization to `additionalRoutes` (notably `mcp`, `description`,
|
|
835
|
+
* `annotations`). Undefined when the resource was defined with the legacy
|
|
836
|
+
* `additionalRoutes` shape.
|
|
837
|
+
*
|
|
838
|
+
* Added in 2.8.1 — the source-of-truth fix for "canonical resource manifest".
|
|
839
|
+
*/
|
|
840
|
+
readonly routes?: readonly RouteDefinition[];
|
|
468
841
|
readonly middlewares: MiddlewareConfig;
|
|
469
842
|
readonly disableDefaultRoutes: boolean;
|
|
470
843
|
readonly disabledRoutes: CrudRouteKey[];
|
|
@@ -845,8 +1218,8 @@ interface AccessControlConfig {
|
|
|
845
1218
|
}
|
|
846
1219
|
/** Minimal repository interface for access-controlled fetch operations */
|
|
847
1220
|
interface AccessControlRepository {
|
|
848
|
-
getById(id: string, options?:
|
|
849
|
-
getOne?: (filter: AnyRecord, options?:
|
|
1221
|
+
getById(id: string, options?: QueryOptions): Promise<unknown>;
|
|
1222
|
+
getOne?: (filter: AnyRecord, options?: QueryOptions) => Promise<unknown>;
|
|
850
1223
|
}
|
|
851
1224
|
declare class AccessControl {
|
|
852
1225
|
private readonly tenantField;
|
|
@@ -890,7 +1263,7 @@ declare class AccessControl {
|
|
|
890
1263
|
* Replaces the duplicated pattern in get/update/delete:
|
|
891
1264
|
* buildIdFilter -> getOne (or getById + checkOrgScope + checkPolicyFilters)
|
|
892
1265
|
*/
|
|
893
|
-
fetchWithAccessControl<TDoc>(id: string, req: IRequestContext, repository: AccessControlRepository, queryOptions?:
|
|
1266
|
+
fetchWithAccessControl<TDoc>(id: string, req: IRequestContext, repository: AccessControlRepository, queryOptions?: QueryOptions): Promise<TDoc | null>;
|
|
894
1267
|
/**
|
|
895
1268
|
* Post-fetch access control validation for items fetched by non-ID queries
|
|
896
1269
|
* (e.g., getBySlug, restore). Applies org scope, policy filters, and
|
|
@@ -1123,7 +1496,7 @@ declare class BaseController<TDoc = AnyRecord, TRepository extends RepositoryLik
|
|
|
1123
1496
|
soft?: boolean;
|
|
1124
1497
|
}>>;
|
|
1125
1498
|
getBySlug(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
|
|
1126
|
-
getDeleted(req: IRequestContext): Promise<IControllerResponse<
|
|
1499
|
+
getDeleted(req: IRequestContext): Promise<IControllerResponse<PaginationResult<TDoc>>>;
|
|
1127
1500
|
restore(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
|
|
1128
1501
|
getTree(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
|
|
1129
1502
|
getChildren(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
|
|
@@ -1958,6 +2331,24 @@ interface AdditionalRoute {
|
|
|
1958
2331
|
}>;
|
|
1959
2332
|
isError?: boolean;
|
|
1960
2333
|
}>;
|
|
2334
|
+
/**
|
|
2335
|
+
* MCP tool generation config preserved from v2.8 `routes`.
|
|
2336
|
+
* - `false`: skip MCP tool generation for this route
|
|
2337
|
+
* - `true` / omitted: auto-generate when the route goes through Arc's pipeline
|
|
2338
|
+
* - object: explicit description/annotations overrides
|
|
2339
|
+
*
|
|
2340
|
+
* Added in 2.8.1 — previously dropped during `routes → additionalRoutes`
|
|
2341
|
+
* normalization, breaking MCP opt-out and per-route annotations.
|
|
2342
|
+
*/
|
|
2343
|
+
mcp?: boolean | {
|
|
2344
|
+
readonly description?: string;
|
|
2345
|
+
readonly annotations?: {
|
|
2346
|
+
readonly readOnlyHint?: boolean;
|
|
2347
|
+
readonly destructiveHint?: boolean;
|
|
2348
|
+
readonly idempotentHint?: boolean;
|
|
2349
|
+
readonly openWorldHint?: boolean;
|
|
2350
|
+
};
|
|
2351
|
+
};
|
|
1961
2352
|
}
|
|
1962
2353
|
/** HTTP methods for custom routes */
|
|
1963
2354
|
type RouteMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
@@ -2075,9 +2466,17 @@ interface RouteSchemaOptions {
|
|
|
2075
2466
|
filterableFields?: string[];
|
|
2076
2467
|
fieldRules?: Record<string, {
|
|
2077
2468
|
systemManaged?: boolean;
|
|
2469
|
+
hidden?: boolean;
|
|
2078
2470
|
immutable?: boolean;
|
|
2079
2471
|
immutableAfterCreate?: boolean;
|
|
2080
|
-
optional?: boolean;
|
|
2472
|
+
optional?: boolean; /** String minimum length — auto-maps to OpenAPI `minLength` and MCP tool schema */
|
|
2473
|
+
minLength?: number; /** String maximum length — auto-maps to OpenAPI `maxLength` and MCP tool schema */
|
|
2474
|
+
maxLength?: number; /** Number minimum — auto-maps to OpenAPI `minimum` and MCP tool schema */
|
|
2475
|
+
min?: number; /** Number maximum — auto-maps to OpenAPI `maximum` and MCP tool schema */
|
|
2476
|
+
max?: number; /** Regex pattern — auto-maps to OpenAPI `pattern` and MCP tool schema */
|
|
2477
|
+
pattern?: string; /** Allowed values — auto-maps to OpenAPI `enum` and MCP tool schema */
|
|
2478
|
+
enum?: ReadonlyArray<string | number>; /** Human-readable description — auto-maps to OpenAPI `description` */
|
|
2479
|
+
description?: string;
|
|
2081
2480
|
[key: string]: unknown;
|
|
2082
2481
|
}>;
|
|
2083
2482
|
query?: Record<string, unknown>;
|
|
@@ -2544,6 +2943,33 @@ interface RegistryEntry extends ResourceMetadata {
|
|
|
2544
2943
|
audit?: boolean | {
|
|
2545
2944
|
operations?: ("create" | "update" | "delete")[];
|
|
2546
2945
|
};
|
|
2946
|
+
/**
|
|
2947
|
+
* v2.8 declarative actions metadata — populated from `ResourceConfig.actions`.
|
|
2948
|
+
*
|
|
2949
|
+
* Consumed by OpenAPI generation (renders `POST /:id/action` with a
|
|
2950
|
+
* discriminated body schema) and MCP tool generation.
|
|
2951
|
+
*
|
|
2952
|
+
* Added in 2.8.1.
|
|
2953
|
+
*/
|
|
2954
|
+
actions?: Array<{
|
|
2955
|
+
readonly name: string;
|
|
2956
|
+
readonly description?: string; /** Raw per-action schema (JSON Schema, Zod v4, or legacy field map) */
|
|
2957
|
+
readonly schema?: Record<string, unknown>; /** Per-action permission check (if different from resource-level `actionPermissions`) */
|
|
2958
|
+
readonly permissions?: PermissionCheck; /** MCP tool generation flag — `false` to skip, object for overrides */
|
|
2959
|
+
readonly mcp?: boolean | {
|
|
2960
|
+
readonly description?: string;
|
|
2961
|
+
readonly annotations?: Record<string, unknown>;
|
|
2962
|
+
};
|
|
2963
|
+
}>;
|
|
2964
|
+
/**
|
|
2965
|
+
* Resource-level fallback permission for actions without per-action
|
|
2966
|
+
* permissions. Used by OpenAPI to determine auth requirements and by MCP
|
|
2967
|
+
* as the fallback in `createActionToolHandler`.
|
|
2968
|
+
*
|
|
2969
|
+
* Added in 2.8.1 — previously not surfaced to downstream consumers,
|
|
2970
|
+
* causing OpenAPI to mark action endpoints as public when runtime required auth.
|
|
2971
|
+
*/
|
|
2972
|
+
actionPermissions?: PermissionCheck;
|
|
2547
2973
|
}
|
|
2548
2974
|
interface RegistryStats {
|
|
2549
2975
|
total?: number;
|
|
@@ -2601,68 +3027,84 @@ type TypedRepository<TDoc> = CrudRepository<TDoc>;
|
|
|
2601
3027
|
//#endregion
|
|
2602
3028
|
//#region src/adapters/interface.d.ts
|
|
2603
3029
|
/**
|
|
2604
|
-
* Minimal repository
|
|
2605
|
-
* Any repository with these method signatures is accepted — no `as any` needed.
|
|
3030
|
+
* Minimal structural repository shape for flexible adapter compatibility.
|
|
2606
3031
|
*
|
|
2607
|
-
*
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
*
|
|
2611
|
-
* Any repository with these method signatures is accepted.
|
|
3032
|
+
* `RepositoryLike` is the **loose** variant of `CrudRepository<TDoc>` — it
|
|
3033
|
+
* uses `unknown` for document payloads so any object with the right method
|
|
3034
|
+
* names satisfies it without type assertions. Prefer `CrudRepository<TDoc>`
|
|
3035
|
+
* for kits you own; use `RepositoryLike` when wrapping third-party repos.
|
|
2612
3036
|
*
|
|
2613
|
-
*
|
|
2614
|
-
* getAll, getById, create, update, delete
|
|
3037
|
+
* Both interfaces declare the same tiered capabilities:
|
|
2615
3038
|
*
|
|
2616
|
-
* **
|
|
2617
|
-
*
|
|
3039
|
+
* - **Required** — `getAll`, `getById`, `create`, `update`, `delete`
|
|
3040
|
+
* - **Recommended** — `getOne` / `getByQuery` (used by AccessControl for
|
|
3041
|
+
* compound filters like `idField + orgId + policy`)
|
|
3042
|
+
* - **Optional** — feature-detected at runtime by presets and the
|
|
3043
|
+
* BaseController. Declare only what your DB supports.
|
|
2618
3044
|
*
|
|
2619
|
-
*
|
|
2620
|
-
*
|
|
2621
|
-
* getDeleted — softDelete preset (list soft-deleted)
|
|
2622
|
-
* restore — softDelete preset (restore soft-deleted)
|
|
2623
|
-
* getTree — tree preset (hierarchical queries)
|
|
2624
|
-
* getChildren — tree preset (child nodes)
|
|
2625
|
-
* createMany — bulk preset (batch create)
|
|
2626
|
-
* updateMany — bulk preset (batch update by filter)
|
|
2627
|
-
* deleteMany — bulk preset (batch delete by filter)
|
|
3045
|
+
* See [CrudRepository](../types/repository.ts) for full prose-level docs
|
|
3046
|
+
* on each method and the design rationale behind the tiering.
|
|
2628
3047
|
*/
|
|
2629
3048
|
interface RepositoryLike {
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
update(id: string, data: unknown, options?: unknown): Promise<unknown>;
|
|
2634
|
-
delete(id: string, options?: unknown): Promise<unknown>;
|
|
2635
|
-
/**
|
|
2636
|
-
* The repository's native primary key field. When set, Arc's BaseController
|
|
2637
|
-
* will pass route params through to `update()`/`delete()`/`restore()` calls
|
|
3049
|
+
/**
|
|
3050
|
+
* The repository's native primary key field. When set, arc's BaseController
|
|
3051
|
+
* passes route params through to `update()`/`delete()`/`restore()` calls
|
|
2638
3052
|
* unchanged instead of translating them to `_id`.
|
|
2639
3053
|
*
|
|
2640
|
-
*
|
|
2641
|
-
* natively look up by a custom field (e.g.
|
|
2642
|
-
* `new Repository(Model, [], {}, { idField: 'id' })`). Without it,
|
|
2643
|
-
* try to translate route ids → fetched doc's `_id
|
|
2644
|
-
* don't key on `_id`.
|
|
3054
|
+
* Match this to your `defineResource({ idField })` for repositories that
|
|
3055
|
+
* natively look up by a custom field (e.g. mongokit's
|
|
3056
|
+
* `new Repository(Model, [], {}, { idField: 'id' })`). Without it, arc
|
|
3057
|
+
* will try to translate route ids → fetched doc's `_id`, which 404s on
|
|
3058
|
+
* repos that don't key on `_id`.
|
|
2645
3059
|
*
|
|
2646
|
-
* Defaults to `'_id'` (Mongo).
|
|
3060
|
+
* Defaults to `'_id'` (Mongo). Kits that always use `_id` may omit it.
|
|
2647
3061
|
*/
|
|
2648
3062
|
readonly idField?: string;
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
3063
|
+
getAll(params?: PaginationParams, options?: QueryOptions): Promise<unknown>;
|
|
3064
|
+
getById(id: string, options?: QueryOptions): Promise<unknown>;
|
|
3065
|
+
create(data: unknown, options?: WriteOptions): Promise<unknown>;
|
|
3066
|
+
update(id: string, data: unknown, options?: WriteOptions): Promise<unknown>;
|
|
3067
|
+
/**
|
|
3068
|
+
* Delete by primary key. Pass `{ mode: 'hard' }` to bypass soft-delete
|
|
3069
|
+
* interception (required by arc's hard-delete flow — `?hard=true` on
|
|
3070
|
+
* the DELETE route forwards this option).
|
|
3071
|
+
*/
|
|
3072
|
+
delete(id: string, options?: DeleteOptions): Promise<unknown>;
|
|
3073
|
+
/**
|
|
3074
|
+
* Find a single doc by compound filter. Used by AccessControl for
|
|
3075
|
+
* `idField + org + policy` scoping. Without this, arc falls back to
|
|
3076
|
+
* `getById` + post-fetch security checks (slower, and 404s on custom
|
|
3077
|
+
* idFields that live outside the user's scope).
|
|
3078
|
+
*/
|
|
3079
|
+
getOne?(filter: Record<string, unknown>, options?: QueryOptions): Promise<unknown>;
|
|
3080
|
+
/** Alias many kits expose alongside `getOne`. Arc checks both. */
|
|
3081
|
+
getByQuery?(filter: Record<string, unknown>, options?: QueryOptions): Promise<unknown>;
|
|
3082
|
+
count?(filter?: Record<string, unknown>, options?: QueryOptions): Promise<number>;
|
|
3083
|
+
exists?(filter: Record<string, unknown>, options?: QueryOptions): Promise<boolean | {
|
|
3084
|
+
_id: unknown;
|
|
3085
|
+
} | null>;
|
|
3086
|
+
distinct?<T = unknown>(field: string, filter?: Record<string, unknown>, options?: QueryOptions): Promise<T[]>;
|
|
3087
|
+
findAll?(filter?: Record<string, unknown>, options?: QueryOptions): Promise<unknown[]>;
|
|
3088
|
+
getOrCreate?(filter: Record<string, unknown>, data: unknown, options?: WriteOptions): Promise<unknown>;
|
|
3089
|
+
createMany?(items: unknown[], options?: WriteOptions): Promise<unknown[]>;
|
|
3090
|
+
updateMany?(filter: Record<string, unknown>, data: Record<string, unknown>, options?: WriteOptions): Promise<UpdateManyResult>;
|
|
3091
|
+
deleteMany?(filter: Record<string, unknown>, options?: DeleteOptions): Promise<DeleteManyResult>;
|
|
3092
|
+
bulkWrite?: unknown;
|
|
3093
|
+
restore?(id: string, options?: QueryOptions): Promise<unknown>;
|
|
3094
|
+
getDeleted?(params?: PaginationParams, options?: QueryOptions): Promise<PaginationResult<unknown> | unknown[]>;
|
|
3095
|
+
aggregate?: unknown;
|
|
3096
|
+
aggregatePaginate?: unknown;
|
|
3097
|
+
withTransaction?<T>(callback: (session: RepositorySession) => Promise<T>, options?: Record<string, unknown>): Promise<T>;
|
|
3098
|
+
getBySlug?(slug: string, options?: QueryOptions): Promise<unknown>;
|
|
3099
|
+
getTree?(options?: QueryOptions): Promise<unknown>;
|
|
3100
|
+
getChildren?(parentId: string, options?: QueryOptions): Promise<unknown>;
|
|
2660
3101
|
[key: string]: unknown;
|
|
2661
3102
|
}
|
|
2662
3103
|
interface DataAdapter<TDoc = unknown> {
|
|
2663
3104
|
/**
|
|
2664
|
-
* Repository implementing CRUD operations
|
|
2665
|
-
*
|
|
3105
|
+
* Repository implementing CRUD operations. Accepts the typed
|
|
3106
|
+
* `CrudRepository<TDoc>` or the loose `RepositoryLike` — arc checks
|
|
3107
|
+
* capabilities at runtime via feature detection.
|
|
2666
3108
|
*/
|
|
2667
3109
|
repository: CrudRepository<TDoc> | RepositoryLike;
|
|
2668
3110
|
/** Adapter identifier for introspection */
|
|
@@ -2753,4 +3195,4 @@ interface ValidationResult {
|
|
|
2753
3195
|
}
|
|
2754
3196
|
type AdapterFactory<TDoc> = (config: unknown) => DataAdapter<TDoc>;
|
|
2755
3197
|
//#endregion
|
|
2756
|
-
export { PresetFunction as $,
|
|
3198
|
+
export { PresetFunction as $, DeleteOptions as $t, EventsDecorator as A, beforeCreate as An, BaseController as At, InferResourceDoc as B, FastifyHandler as Bt, ConfigError as C, HookPhase as Cn, TypedResourceConfig as Ct, CrudRouterOptions as D, afterCreate as Dn, ValidationResult$1 as Dt, CrudRouteKey as E, HookSystemOptions as En, ValidateOptions as Et, GracefulShutdownOptions as F, BodySanitizerConfig as Ft, LookupOption as G, RegisterOptions as Gt, IntrospectionPluginOptions as H, IControllerResponse as Ht, HealthCheck as I, AccessControl as It, ObjectId as J, defineResource as Jt, MiddlewareConfig as K, ResourceRegistry as Kt, HealthOptions as L, AccessControlConfig as Lt, FastifyWithAuth as M, beforeUpdate as Mn, QueryResolver as Mt, FastifyWithDecorators as N, createHookSystem as Nn, QueryResolverConfig as Nt, CrudSchemas as O, afterDelete as On, envelope as Ot, FieldRule as P, defineHook as Pn, BodySanitizer as Pt, PopulateOption as Q, DeleteManyResult as Qt, InferAdapterDoc as R, ControllerHandler as Rt, AuthenticatorContext as S, HookOperation as Sn, TypedRepository as St, CrudController as T, HookSystem as Tn, UserOrganization as Tt, JWTPayload as U, IRequestContext as Ut, IntrospectionData as V, IController as Vt, JwtContext as W, RouteHandler as Wt, OwnershipCheck as X, BulkWriteResult as Xt, OpenApiSchemas as Y, BulkWriteOperation as Yt, ParsedQuery as Z, CrudRepository as Zt, ArcInternalMetadata as _, PipelineStep as _n, RouteMcpConfig as _t, RelationMetadata as a, PaginationParams as an, RegistryStats as at, AuthPluginOptions as b, HookContext as bn, TokenPair as bt, ValidationResult as c, RepositorySession as cn, RequestWithExtras as ct, ActionHandlerFn as d, Guard as dn, ResourceHookContext as dt, DeleteResult as en, PresetHook as et, ActionsMap as f, Interceptor as fn, ResourceHooks as ft, ArcDecorator as g, PipelineContext as gn, RouteHandlerMethod$1 as gt, ApiResponse as h, PipelineConfig as hn, RouteDefinition as ht, FieldMetadata as i, PaginatedResult as in, RegistryEntry as it, FastifyRequestExtras as j, beforeDelete as jn, BaseControllerOptions as jt, EventDefinition as k, afterUpdate as kn, getUserId as kt, ActionDefinition as l, UpdateManyResult as ln, ResourceCacheConfig as lt, AnyRecord as m, OperationFilter as mn, ResourcePermissions as mt, AdapterSchemaContext as n, KeysetPaginatedResult as nn, QueryParserInterface as nt, RepositoryLike as o, PaginationResult as on, RequestContext as ot, AdditionalRoute as p, NextFunction as pn, ResourceMetadata as pt, MiddlewareHandler as q, ResourceDefinition as qt, DataAdapter as r, OffsetPaginatedResult as rn, RateLimitConfig as rt, SchemaMetadata as s, QueryOptions as sn, RequestIdOptions as st, AdapterFactory as t, InferDoc as tn, PresetResult as tt, ActionEntry as u, WriteOptions as un, ResourceConfig as ut, ArcRequest as v, Transform as vn, RouteSchemaOptions as vt, ControllerQueryOptions as w, HookRegistration as wn, UserLike as wt, Authenticator as x, HookHandler as xn, TypedController as xt, AuthHelpers as y, DefineHookOptions as yn, ServiceContext as yt, InferDocType as z, ControllerLike as zt };
|