@classytic/arc 2.8.5 → 2.10.3
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 +50 -38
- package/dist/{BaseController-DAGGc5Xn.mjs → BaseController-CbKKIflT.mjs} +193 -143
- package/dist/EventTransport-CUw5NNWe.d.mts +293 -0
- package/dist/{ResourceRegistry-C6uXlWe3.mjs → ResourceRegistry-BPd6NQDm.mjs} +1 -1
- package/dist/adapters/index.d.mts +3 -3
- package/dist/adapters/index.mjs +2 -2
- package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
- package/dist/audit/index.d.mts +135 -11
- package/dist/audit/index.mjs +107 -20
- package/dist/auth/index.d.mts +17 -9
- package/dist/auth/index.mjs +14 -7
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi-BuUcUEJq.mjs → betterAuthOpenApi-BBRVhjQN.mjs} +1 -1
- package/dist/cache/index.d.mts +17 -15
- package/dist/cache/index.mjs +15 -14
- package/dist/{caching-IMuYVjTL.mjs → caching-CBpK_SCM.mjs} +8 -3
- package/dist/cli/commands/describe.mjs +1 -1
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +1 -1
- package/dist/cli/commands/init.mjs +1 -1
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +4 -6
- package/dist/{defineResource-tcgySDo1.mjs → core-CcR01lup.mjs} +58 -61
- package/dist/{createActionRouter-BORM8f17.mjs → createActionRouter-Bp_5c_2b.mjs} +3 -3
- package/dist/{createApp-B1EY8zxa.mjs → createApp-BuvPma24.mjs} +15 -14
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-DtFxrG0s.mjs → elevation-C7hgL_aI.mjs} +22 -8
- package/dist/{errorHandler-f869_8PQ.mjs → errorHandler-Bb49BvPD.mjs} +59 -7
- package/dist/{errorHandler-Bah5JhBd.d.mts → errorHandler-DRQ3EqfL.d.mts} +37 -2
- package/dist/{eventPlugin-D9DKB2zM.d.mts → eventPlugin-CxWgpd6K.d.mts} +14 -2
- package/dist/{eventPlugin-CDjVTM82.mjs → eventPlugin-DCUjuiQT.mjs} +83 -5
- package/dist/events/index.d.mts +150 -36
- package/dist/events/index.mjs +355 -101
- 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 +2 -2
- package/dist/{types-DZi1aYhm.d.mts → fields-Lo1VUDpt.d.mts} +121 -1
- package/dist/{fields-ipsbIRPK.mjs → fields-bxkeltzz.mjs} +18 -5
- package/dist/{filesUpload-C7r7HIeA.mjs → filesUpload-t21LS-py.mjs} +65 -7
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +32 -5
- package/dist/idempotency/index.mjs +119 -12
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-DtDzOBn8.d.mts → index-8qw4y6ff.d.mts} +4 -135
- package/dist/{index-BLXBmWud.d.mts → index-ChIw3776.d.mts} +283 -408
- package/dist/{interface-CMRutPfe.d.mts → index-Cl0uoKd5.d.mts} +1758 -2506
- package/dist/{index-C1meYuDn.d.mts → index-DStwgFUK.d.mts} +81 -7
- package/dist/index.d.mts +7 -8
- package/dist/index.mjs +11 -12
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +26 -8
- package/dist/integrations/mcp/index.mjs +96 -17
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/webhooks.d.mts +5 -0
- package/dist/integrations/webhooks.mjs +6 -0
- package/dist/interface-D218ikEo.d.mts +77 -0
- package/dist/{memory-Cp7_cAko.mjs → memory-B5Amv9A1.mjs} +23 -8
- package/dist/{openapi-CbKUJY_m.mjs → openapi-B5F8AddX.mjs} +3 -3
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +3 -4
- package/dist/permissions/index.mjs +5 -5
- package/dist/{permissions-CH4cNwJi.mjs → permissions-Dk6mshja.mjs} +315 -397
- package/dist/plugins/index.d.mts +7 -7
- package/dist/plugins/index.mjs +14 -16
- package/dist/plugins/response-cache.mjs +2 -2
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/filesUpload.d.mts +27 -5
- package/dist/presets/filesUpload.mjs +1 -1
- package/dist/presets/index.d.mts +3 -2
- package/dist/presets/index.mjs +4 -3
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +2 -2
- package/dist/presets/search.d.mts +178 -0
- package/dist/presets/search.mjs +150 -0
- package/dist/{presets-C2xgzW6x.mjs → presets-fLJVXdVn.mjs} +1 -1
- package/dist/{queryCachePlugin-BJJGBTlu.d.mts → queryCachePlugin-BKbWjgDG.d.mts} +1 -1
- package/dist/{queryCachePlugin-BH-fidlv.mjs → queryCachePlugin-DQCEfJis.mjs} +9 -9
- package/dist/{queryParser-CgCtsjti.mjs → queryParser-DBqBB6AC.mjs} +1 -1
- package/dist/{redis-BM00zaPB.d.mts → redis-DqyeggCa.d.mts} +1 -1
- package/dist/{redis-stream-CrsfUmPt.d.mts → redis-stream-CakIQmwR.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/{resourceToTools-8s-EsCCe.mjs → resourceToTools-BElv3xPT.mjs} +65 -48
- package/dist/{schemaConverter-Y7nCYaLJ.mjs → schemaConverter-BxFDdtXu.mjs} +1 -1
- package/dist/scope/index.d.mts +1 -1
- package/dist/scope/index.mjs +2 -2
- package/dist/{sse-Ad7ypl9e.mjs → sse-yBCgOLGu.mjs} +1 -1
- package/dist/store-helpers-ZCSMJJAX.mjs +57 -0
- package/dist/testing/index.d.mts +9 -17
- package/dist/testing/index.mjs +27 -83
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/types/index.mjs +1 -31
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-BsbNMEDR.d.mts → types-Btdda02s.d.mts} +1 -1
- package/dist/{types-Ch9pTQbf.d.mts → types-Co8k3NyS.d.mts} +11 -9
- package/dist/types-Csi3FLfq.mjs +27 -0
- package/dist/utils/index.d.mts +208 -4
- package/dist/utils/index.mjs +5 -6
- package/dist/{utils-yYT3HDXt.mjs → utils-B2fNOD_i.mjs} +285 -2
- package/dist/{versioning-CDugduqI.mjs → versioning-C2U_bLY0.mjs} +3 -5
- package/package.json +20 -26
- package/skills/arc/SKILL.md +97 -23
- package/skills/arc/references/auth.md +94 -0
- package/skills/arc/references/events.md +200 -12
- package/skills/arc/references/mcp.md +4 -17
- package/skills/arc/references/multi-tenancy.md +43 -0
- package/skills/arc/references/production.md +34 -60
- package/dist/EventTransport-BXja8NOc.d.mts +0 -135
- package/dist/audit/mongodb.d.mts +0 -2
- package/dist/audit/mongodb.mjs +0 -2
- package/dist/circuitBreaker-cmi5XDv5.mjs +0 -284
- package/dist/circuitBreaker-dTtG-UyS.d.mts +0 -206
- package/dist/core-F0QoWBt2.mjs +0 -34
- package/dist/dynamic/index.d.mts +0 -93
- package/dist/dynamic/index.mjs +0 -122
- package/dist/fields-DpZQa_Q3.d.mts +0 -109
- package/dist/idempotency/mongodb.d.mts +0 -2
- package/dist/idempotency/mongodb.mjs +0 -123
- package/dist/interface-4y979v99.d.mts +0 -54
- package/dist/mongodb-BsP-WbhN.d.mts +0 -127
- package/dist/mongodb-CTcp0hQZ.d.mts +0 -80
- package/dist/mongodb-Utc5k_-0.mjs +0 -90
- package/dist/policies/index.d.mts +0 -432
- package/dist/policies/index.mjs +0 -318
- package/dist/rpc/index.d.mts +0 -90
- package/dist/rpc/index.mjs +0 -248
- /package/dist/{HookSystem-HprTmvVY.mjs → HookSystem-BNYKnrXF.mjs} +0 -0
- /package/dist/{applyPermissionResult-D6GPMsvh.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
- /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
- /package/dist/{elevation-B6S5csVA.d.mts → elevation-C5SwtkAn.d.mts} +0 -0
- /package/dist/{errors-Ck2h67pm.d.mts → errors-CCSsMpXE.d.mts} +0 -0
- /package/dist/{errors-BF2bIOIS.mjs → errors-D5c-5BJL.mjs} +0 -0
- /package/dist/{externalPaths-BnkYrNzp.d.mts → externalPaths-BQ8QijNH.d.mts} +0 -0
- /package/dist/{interface-DfLGcus7.d.mts → interface-CSbZdv_3.d.mts} +0 -0
- /package/dist/{loadResources-PWd0OCpV.mjs → loadResources-BAzJItAJ.mjs} +0 -0
- /package/dist/{logger-D1YrIImS.mjs → logger-DLg8-Ueg.mjs} +0 -0
- /package/dist/{metrics-B-PU4-Yu.mjs → metrics-DuhiSEZI.mjs} +0 -0
- /package/dist/{pluralize-CWP6MB39.mjs → pluralize-A0tWEl1K.mjs} +0 -0
- /package/dist/{registry-BiTKT1Dg.mjs → registry-B3lRFBWo.mjs} +0 -0
- /package/dist/{replyHelpers-CxkYGT81.mjs → replyHelpers-CXtJDAZ0.mjs} +0 -0
- /package/dist/{requestContext-DYvHl113.mjs → requestContext-xHIKedG6.mjs} +0 -0
- /package/dist/{sessionManager-DDCmiNIo.d.mts → sessionManager-BkzVU8h2.d.mts} +0 -0
- /package/dist/{storage-Dfzt4VTl.d.mts → storage-CVk_SEn2.d.mts} +0 -0
- /package/dist/{tracing-DdN2-wHJ.d.mts → tracing-65B51Dw3.d.mts} +0 -0
- /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-Cj5Rgvlg.mjs} +0 -0
- /package/dist/{types-ZUu_h0jp.mjs → types-DV9WDfeg.mjs} +0 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Database-agnostic resource framework for Fastify. Define resources, get CRUD routes, permissions, presets, caching, events, OpenAPI, and MCP tools — without boilerplate.
|
|
4
4
|
|
|
5
|
-
**v2.
|
|
5
|
+
**v2.10** | Fastify 5+ | Node.js 22+ | ESM only
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -65,8 +65,15 @@ const app = await createApp({
|
|
|
65
65
|
Clean DX without growing exclude lists:
|
|
66
66
|
|
|
67
67
|
```typescript
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
import { Repository, methodRegistryPlugin, batchOperationsPlugin } from '@classytic/mongokit';
|
|
69
|
+
|
|
70
|
+
// app.ts — pass any RepositoryLike (mongokit / prismakit / custom)
|
|
71
|
+
await fastify.register(auditPlugin, {
|
|
72
|
+
autoAudit: { perResource: true },
|
|
73
|
+
// batchOperationsPlugin enables deleteMany, required for purgeOlderThan()
|
|
74
|
+
repository: new Repository(AuditModel, [methodRegistryPlugin(), batchOperationsPlugin()]),
|
|
75
|
+
// or omit `repository` for in-memory dev
|
|
76
|
+
});
|
|
70
77
|
|
|
71
78
|
// order.resource.ts — opt in
|
|
72
79
|
defineResource({ name: 'order', audit: true });
|
|
@@ -99,8 +106,8 @@ const productResource = defineResource({
|
|
|
99
106
|
delete: roles('admin'),
|
|
100
107
|
},
|
|
101
108
|
cache: { staleTime: 30, gcTime: 300, tags: ['catalog'] }, // QueryCache (opt-in)
|
|
102
|
-
|
|
103
|
-
{ method: 'GET', path: '/featured', handler: 'getFeatured', permissions: allowPublic()
|
|
109
|
+
routes: [
|
|
110
|
+
{ method: 'GET', path: '/featured', handler: 'getFeatured', permissions: allowPublic() },
|
|
104
111
|
],
|
|
105
112
|
});
|
|
106
113
|
|
|
@@ -383,6 +390,29 @@ await app.events.subscribe('order.*', async (event) => { ... });
|
|
|
383
390
|
|
|
384
391
|
CRUD events (`product.created`, `product.updated`, `product.deleted`) emit automatically.
|
|
385
392
|
|
|
393
|
+
### Causation Chains & DLQ (v2.9)
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
import { createEvent, createChildEvent, type DeadLetteredEvent } from '@classytic/arc/events';
|
|
397
|
+
|
|
398
|
+
const placed = createEvent('order.placed', { orderId: 'o1' }, {
|
|
399
|
+
correlationId: req.id, userId: user.id,
|
|
400
|
+
});
|
|
401
|
+
await app.events.publish(placed.type, placed.payload, placed.meta);
|
|
402
|
+
|
|
403
|
+
// Downstream handler emits a child — correlation inherited, causation linked:
|
|
404
|
+
const reserved = createChildEvent(placed, 'inventory.reserved', { sku: 'a' });
|
|
405
|
+
// reserved.meta.correlationId === placed.meta.correlationId (stays stable across chain)
|
|
406
|
+
// reserved.meta.causationId === placed.meta.id (direct parent)
|
|
407
|
+
|
|
408
|
+
// Transports with native DLQ (Kafka, SQS) implement optional deadLetter():
|
|
409
|
+
class KafkaTransport implements EventTransport {
|
|
410
|
+
async deadLetter(dlq: DeadLetteredEvent) { /* route to .DLQ topic */ }
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
`EventMeta` also accepts `schemaVersion` (evolve event payloads) and `partitionKey` (ordered delivery hint for Kafka/Kinesis).
|
|
415
|
+
|
|
386
416
|
### defineEvent — Typed Events with Schema Validation
|
|
387
417
|
|
|
388
418
|
Declare events with schemas for runtime validation and introspection:
|
|
@@ -709,7 +739,6 @@ Arc sets `"sideEffects": false` in [package.json](package.json), so modern bundl
|
|
|
709
739
|
| `@classytic/arc/presets` | Preset functions + interfaces |
|
|
710
740
|
| `@classytic/arc/audit` | Audit trail |
|
|
711
741
|
| `@classytic/arc/idempotency` | Idempotency |
|
|
712
|
-
| `@classytic/arc/policies` | Policy engine |
|
|
713
742
|
| `@classytic/arc/schemas` | TypeBox helpers |
|
|
714
743
|
| `@classytic/arc/utils` | Errors, circuit breaker, state machine, query parser |
|
|
715
744
|
| `@classytic/arc/testing` | Test utilities, mocks, in-memory DB |
|
|
@@ -722,46 +751,29 @@ Arc sets `"sideEffects": false` in [package.json](package.json), so modern bundl
|
|
|
722
751
|
| `@classytic/arc/docs` | OpenAPI generation |
|
|
723
752
|
| `@classytic/arc/cli` | CLI commands (programmatic) |
|
|
724
753
|
|
|
725
|
-
##
|
|
754
|
+
## Type imports
|
|
726
755
|
|
|
727
|
-
|
|
756
|
+
Arc owns framework types (`IController`, `IRequestContext`, `ResourceConfig`, `RepositoryLike`, `PaginationResult`). The repository contract lives in `@classytic/repo-core` — import those types directly:
|
|
728
757
|
|
|
729
758
|
```typescript
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
annotations: { destructiveHint: true },
|
|
737
|
-
buildTool: (ctx) => buildTriggerJobTool(getUserId(ctx) ?? ''),
|
|
738
|
-
};
|
|
739
|
-
|
|
740
|
-
await app.register(mcpPlugin, {
|
|
741
|
-
resources,
|
|
742
|
-
extraTools: buildMcpToolsFromBridges([triggerJobBridge]),
|
|
743
|
-
});
|
|
759
|
+
// Arc framework types
|
|
760
|
+
import type { IRequestContext, RepositoryLike, PaginationResult } from '@classytic/arc';
|
|
761
|
+
|
|
762
|
+
// Repository contract (repo-core is the single source of truth)
|
|
763
|
+
import type { StandardRepo, WriteOptions, QueryOptions } from '@classytic/repo-core/repository';
|
|
764
|
+
import type { OffsetPaginationResult } from '@classytic/repo-core/pagination';
|
|
744
765
|
```
|
|
745
766
|
|
|
746
|
-
|
|
767
|
+
> Arc 2.10 dropped the legacy `CrudRepository`, `PaginatedResult`, and pass-through `WriteOptions`/`QueryOptions` re-exports. See [CHANGELOG.md](CHANGELOG.md#210) for the migration table.
|
|
747
768
|
|
|
748
|
-
|
|
749
|
-
- **Actions in OpenAPI** — `POST /:id/action` endpoint auto-generated from `ResourceDefinition.actions`, with per-action descriptions and the same discriminated body schema as the runtime router
|
|
750
|
-
- **Route/action metadata preserved** — `mcp: false`, `description`, `annotations` no longer dropped during `routes → additionalRoutes` normalization
|
|
751
|
-
- **Canonical source retained** — `ResourceDefinition.routes` and `ResourceDefinition.actions` now kept as declared, so OpenAPI/MCP/registry can read the original shape
|
|
752
|
-
- **Outbox hardening** — expanded `OutboxStore` contract (`claimPending`, `fail`, write options, dedupe, visibleAt), ownership-mismatch throws, onError reporting, safe multi-worker relay
|
|
753
|
-
- **`slugLookup` fallback** — works with MongoKit's default Repository (no custom `getBySlug` needed)
|
|
769
|
+
## v2.10 Highlights
|
|
754
770
|
|
|
755
|
-
|
|
771
|
+
- **Clean-break on repo-core types** — `CrudRepository` / `PaginatedResult` / pass-through repo options removed from arc's public surface. Import `StandardRepo`, `OffsetPaginationResult`, etc. directly from `@classytic/repo-core`. See [CHANGELOG.md](CHANGELOG.md) for the rewrite table.
|
|
772
|
+
- **Outbox bugfix** — `repositoryAsOutboxStore.fail()` now passes `updatePipeline: true` to `findOneAndUpdate`, so retry / DLQ transitions work on mongokit ≥3.10.
|
|
773
|
+
- **Plugin requirements documented** — audit / outbox / idempotency require mongokit's `methodRegistryPlugin` + `batchOperationsPlugin` for `deleteMany`; README snippets + production-ops docs now show the correct chain.
|
|
774
|
+
- **Removed** — `@classytic/arc/policies` (use `permissions/`), `@classytic/arc/rpc`, `@classytic/arc/dynamic` (use `factory/loadResources`).
|
|
756
775
|
|
|
757
|
-
|
|
758
|
-
- **Reply Helpers** — `reply.ok()`, `reply.fail()`, `reply.paginated()`, `reply.stream()` (opt-in)
|
|
759
|
-
- **Error Mappers** — class-based `instanceof` domain error → HTTP response mapping
|
|
760
|
-
- **Multipart Body** — `multipartBody()` middleware for file upload in CRUD routes
|
|
761
|
-
- **Service Scope** — `kind: "service"` RequestScope for machine-to-machine auth (MCP + WebSocket)
|
|
762
|
-
- **BigInt Serialization** — `serializeBigInt: true` auto-converts BigInt → Number
|
|
763
|
-
- **Event WAL** — skips internal `arc.*` events to prevent startup timeout with durable stores
|
|
764
|
-
- **Security** — `auth: false` produces null `ctx.user` (prevents anonymous bypass of `!!ctx.user` guards)
|
|
776
|
+
See [CHANGELOG.md](CHANGELOG.md) for the full v2.9 / v2.8 / v2.7 history.
|
|
765
777
|
|
|
766
778
|
## License
|
|
767
779
|
|