@classytic/arc 2.11.3 → 2.13.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 +27 -18
- package/dist/{BaseController-swXruJ2_.mjs → BaseController-DX_T-bDB.mjs} +388 -423
- package/dist/EventTransport-CT_52aWU.d.mts +34 -0
- package/dist/EventTransport-DLWoUMHy.mjs +103 -0
- package/dist/{QueryCache-DOBNHBE0.d.mts → QueryCache-D41bfdBB.d.mts} +1 -1
- package/dist/{ResourceRegistry-DkAeAuTX.mjs → ResourceRegistry-CTERg_2x.mjs} +139 -66
- package/dist/audit/index.d.mts +2 -2
- package/dist/audit/index.mjs +1 -1
- package/dist/auth/audit.d.mts +199 -0
- package/dist/auth/audit.mjs +288 -0
- package/dist/auth/index.d.mts +5 -5
- package/dist/auth/index.mjs +117 -191
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi-DwxtK3uG.mjs → betterAuthOpenApi--M_i87dQ.mjs} +1 -1
- package/dist/buildHandler-olo-gt94.mjs +610 -0
- package/dist/cache/index.d.mts +3 -3
- package/dist/cache/index.mjs +3 -3
- package/dist/cli/commands/describe.d.mts +89 -13
- package/dist/cli/commands/describe.mjs +56 -2
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +147 -48
- package/dist/cli/commands/init.d.mts +13 -0
- package/dist/cli/commands/init.mjs +237 -112
- package/dist/cli/commands/introspect.mjs +8 -1
- package/dist/context/index.mjs +1 -1
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +5 -5
- package/dist/core-D72ia0EH.mjs +1399 -0
- package/dist/{createActionRouter-u3ql2EDo.mjs → createActionRouter-CEvzKcy8.mjs} +7 -20
- package/dist/createAggregationRouter-CyecOxnO.mjs +114 -0
- package/dist/{createApp-BFxtdKy6.mjs → createApp-XX2-N0Yd.mjs} +31 -27
- package/dist/defineEvent-D5h7EvAx.mjs +188 -0
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-DOFoxoDs.mjs → elevation-DgoeTyfX.mjs} +1 -1
- package/dist/errorHandler-Bk-AGhkU.mjs +174 -0
- package/dist/errorHandler-DFr45ZG4.d.mts +45 -0
- package/dist/errors-j4aJm1Wg.mjs +184 -0
- package/dist/{eventPlugin-KrFIQ097.mjs → eventPlugin-CaKTYkYM.mjs} +35 -137
- package/dist/{eventPlugin-CUNjYYRY.d.mts → eventPlugin-qXpqTebY.d.mts} +57 -7
- package/dist/events/index.d.mts +164 -5
- package/dist/events/index.mjs +133 -209
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +204 -31
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +2 -2
- package/dist/factory/index.mjs +2 -2
- package/dist/{fields-C8Y0XLAu.d.mts → fields-COhcH3fk.d.mts} +23 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/index.mjs +1 -20
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/idempotency/redis.mjs +1 -1
- package/dist/{index-BYCqHCVu.d.mts → index-BTqLEvhu.d.mts} +164 -4
- package/dist/{index-6u4_Gg6G.d.mts → index-BtW7qYwa.d.mts} +661 -281
- package/dist/{index-BdXnTPRj.d.mts → index-Ds61mrJE.d.mts} +50 -4
- package/dist/{index-DdQ3O9Pg.d.mts → index-Dz5IKsrE.d.mts} +360 -219
- package/dist/index.d.mts +6 -7
- package/dist/index.mjs +9 -10
- package/dist/integrations/event-gateway.d.mts +2 -2
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +2 -2
- 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/integrations/streamline.d.mts +60 -11
- package/dist/integrations/streamline.mjs +75 -85
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +1 -1
- package/dist/integrations/websocket.mjs +2 -8
- package/dist/middleware/index.d.mts +1 -1
- package/dist/middleware/index.mjs +2 -2
- package/dist/migrations/index.d.mts +23 -3
- package/dist/migrations/index.mjs +0 -7
- package/dist/{multipartBody-CvTR1Un6.mjs → multipartBody-BOvVSVCD.mjs} +11 -8
- package/dist/{openapi-BGUn7Ki1.mjs → openapi-CiOMVW1p.mjs} +143 -13
- package/dist/org/index.d.mts +2 -2
- package/dist/org/index.mjs +1 -1
- package/dist/permissions/index.d.mts +3 -3
- package/dist/permissions/index.mjs +3 -3
- package/dist/{permissions-gd_aUWrR.mjs → permissions-ohQyv50e.mjs} +404 -176
- package/dist/{pipe-DVoIheVC.mjs → pipe-Zr0KXjQe.mjs} +1 -1
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +1 -1
- package/dist/plugins/index.d.mts +18 -33
- package/dist/plugins/index.mjs +33 -13
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/filesUpload.d.mts +5 -5
- package/dist/presets/filesUpload.mjs +6 -9
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +2 -2
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +6 -8
- package/dist/{presets-Z7P5w4gF.mjs → presets-BbkjdPeH.mjs} +6 -28
- package/dist/{queryCachePlugin-BUXBSm4F.d.mts → queryCachePlugin-CqMdLI2-.d.mts} +2 -2
- package/dist/{queryCachePlugin-Bq6bO6vc.mjs → queryCachePlugin-m1XsgAIJ.mjs} +3 -3
- package/dist/{redis-Cm1gnRDf.d.mts → redis-DiMkdHEl.d.mts} +1 -1
- package/dist/redis-stream-D6HzR1Z_.d.mts +232 -0
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/{replyHelpers-ByllIXXV.mjs → replyHelpers-CK-FNO8E.mjs} +3 -21
- package/dist/{resourceToTools-ByZpgjeH.mjs → resourceToTools-C5coh64w.mjs} +224 -71
- package/dist/{routerShared-BqLRb5l7.mjs → routerShared-D6_fEGHh.mjs} +40 -36
- package/dist/{schemaIR-BlG9bY7v.mjs → schemaIR-7Vl611Qs.mjs} +1 -1
- package/dist/schemas/index.d.mts +100 -30
- package/dist/schemas/index.mjs +86 -29
- package/dist/scim/index.d.mts +264 -0
- package/dist/scim/index.mjs +963 -0
- package/dist/scope/index.d.mts +3 -3
- package/dist/scope/index.mjs +4 -4
- package/dist/{sse-V7aXc3bW.mjs → sse-Bz-5ZeTt.mjs} +1 -1
- package/dist/{store-helpers-BhrzxvyQ.mjs → store-helpers-BkIN9-vu.mjs} +1 -1
- package/dist/testing/index.d.mts +2 -8
- package/dist/testing/index.mjs +16 -24
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-BH7dEGvU.d.mts → types-BvqwCCSx.d.mts} +77 -29
- package/dist/{types-tgR4Pt8F.d.mts → types-CTYvcwHe.d.mts} +195 -1
- package/dist/{types-AOD8fxIw.mjs → types-C_s5moIu.mjs} +117 -1
- package/dist/{types-9beEMe25.d.mts → types-DQHFc8PM.d.mts} +1 -1
- package/dist/utils/index.d.mts +2 -2
- package/dist/utils/index.mjs +5 -5
- package/dist/{utils-CcYTj09l.mjs → utils-_h9B3c57.mjs} +1269 -1334
- package/dist/{versioning-M9lNLhO8.d.mts → versioning-DTTvc80y.d.mts} +1 -1
- package/package.json +24 -34
- package/skills/arc/SKILL.md +521 -785
- package/skills/arc/references/agent-auth.md +238 -0
- package/skills/arc/references/api-reference.md +187 -0
- package/skills/arc/references/auth.md +354 -7
- package/skills/arc/references/enterprise-auth.md +94 -0
- package/skills/arc/references/events.md +8 -6
- package/skills/arc/references/mcp.md +2 -2
- package/skills/arc/references/multi-tenancy.md +11 -2
- package/skills/arc/references/production.md +10 -9
- package/skills/arc/references/scim.md +247 -0
- package/skills/arc/references/testing.md +1 -1
- package/skills/arc-code-review/SKILL.md +141 -0
- package/skills/arc-code-review/references/anti-patterns.md +911 -0
- package/skills/arc-code-review/references/arc-cheatsheet.md +380 -0
- package/skills/arc-code-review/references/migration-recipes.md +700 -0
- package/skills/arc-code-review/references/mongokit-migration.md +386 -0
- package/skills/arc-code-review/references/scaffolding.md +230 -0
- package/skills/arc-code-review/references/severity.md +127 -0
- package/dist/EventTransport-CfVEGaEl.d.mts +0 -293
- package/dist/adapters/index.d.mts +0 -3
- package/dist/adapters/index.mjs +0 -2
- package/dist/adapters-D0tT2Tyo.mjs +0 -949
- package/dist/auth/mongoose.d.mts +0 -191
- package/dist/auth/mongoose.mjs +0 -73
- package/dist/core-DnUsRpuX.mjs +0 -1049
- package/dist/errorHandler-BQm8ZxTK.mjs +0 -173
- package/dist/errorHandler-Co3lnVmJ.d.mts +0 -114
- package/dist/errors-D5c-5BJL.mjs +0 -232
- package/dist/index-BbMrcvGp.d.mts +0 -362
- package/dist/redis-stream-CM8TXTix.d.mts +0 -110
- /package/dist/{HookSystem-CGsMd6oK.mjs → HookSystem-Iiebom92.mjs} +0 -0
- /package/dist/{actionPermissions-sUUKDhtP.mjs → actionPermissions-CyUkQu6O.mjs} +0 -0
- /package/dist/{caching-CheW3m-S.mjs → caching-SM8gghN6.mjs} +0 -0
- /package/dist/{constants-BhY1OHoH.mjs → constants-Cxde4rpC.mjs} +0 -0
- /package/dist/{elevation-s5ykdNHr.d.mts → elevation-BXOWoGCF.d.mts} +0 -0
- /package/dist/{externalPaths-Bapitwvd.d.mts → externalPaths-BD5nw6St.d.mts} +0 -0
- /package/dist/{interface-CkkWm5uR.d.mts → interface-DfLGcus7.d.mts} +0 -0
- /package/dist/{interface-Da0r7Lna.d.mts → interface-beEtJyWM.d.mts} +0 -0
- /package/dist/{keys-CARyUjiR.mjs → keys-CGcCbNyu.mjs} +0 -0
- /package/dist/{loadResources-CPpkyKfM.mjs → loadResources-DBMQg_Aj.mjs} +0 -0
- /package/dist/{memory-DikHSvWa.mjs → memory-UBydS5ku.mjs} +0 -0
- /package/dist/{metrics-Csh4nsvv.mjs → metrics-Qnvwc-LQ.mjs} +0 -0
- /package/dist/{pluralize-BneOJkpi.mjs → pluralize-DQgqgifU.mjs} +0 -0
- /package/dist/{registry-D63ee7fl.mjs → registry-I-ogLgL9.mjs} +0 -0
- /package/dist/{requestContext-C5XeK3VA.mjs → requestContext-SSaaTgW8.mjs} +0 -0
- /package/dist/{schemaConverter-B0oKLuqI.mjs → schemaConverter-De34B1ZG.mjs} +0 -0
- /package/dist/{sessionManager-D-oNWHz3.d.mts → sessionManager-C4Le_UB3.d.mts} +0 -0
- /package/dist/{storage-BwGQXUpd.d.mts → storage-Dfzt4VTl.d.mts} +0 -0
- /package/dist/{tracing-DokiEsuz.d.mts → tracing-QJVprktp.d.mts} +0 -0
- /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-BzkXkvVv.mjs} +0 -0
- /package/dist/{types-DV9WDfeg.mjs → types-D57iXYb8.mjs} +0 -0
- /package/dist/{versioning-CGPjkqAg.mjs → versioning-BUrT5aP4.mjs} +0 -0
- /package/dist/{websocket-CyJ1VIFI.d.mts → websocket-ChC2rqe1.d.mts} +0 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# Agent Auth — DPoP + Capability Mandates
|
|
2
|
+
|
|
3
|
+
The 2025 stack for AI-agent-led actions on protected resources: **OAuth 2.1** (RFC 9700), **DPoP** (RFC 9449), **OAuth Protected Resource Metadata** (RFC 9728), **AP2** (Google + Anthropic + Stripe Agent Payments Protocol), **Stripe x402 / Agentic Commerce**, **MCP authorization**.
|
|
4
|
+
|
|
5
|
+
Arc 2.13 adds three permission helpers and two scope fields to model these patterns cleanly. **Arc doesn't parse JWTs or verify DPoP proofs** — that's a 1-2 line `jose` call in your authenticate function. Arc validates *what's already proved* against the action being attempted.
|
|
6
|
+
|
|
7
|
+
## The two new scope fields
|
|
8
|
+
|
|
9
|
+
`RequestScope.service` gains two optional fields (additive, no breaking change):
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
{
|
|
13
|
+
kind: 'service',
|
|
14
|
+
clientId,
|
|
15
|
+
organizationId,
|
|
16
|
+
scopes,
|
|
17
|
+
// ── new in 2.13 ──
|
|
18
|
+
mandate?: Mandate, // capability mandate (AP2 / x402 / MCP)
|
|
19
|
+
dpopJkt?: string, // DPoP key thumbprint (RFC 7638)
|
|
20
|
+
// existing fields preserved
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The `Mandate` type:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
interface Mandate {
|
|
28
|
+
id: string; // jti
|
|
29
|
+
capability: string; // 'payment.charge' / 'data.export' / 'inbox.send'
|
|
30
|
+
cap?: number; // numeric ceiling
|
|
31
|
+
currency?: string; // ISO 4217 when monetary
|
|
32
|
+
expiresAt?: number; // epoch ms
|
|
33
|
+
parent?: string; // delegation chain
|
|
34
|
+
audience?: string; // 'invoice:INV-7' — resource binding
|
|
35
|
+
meta?: Record<string, unknown>; // verifier-supplied extras
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Read with `getMandate(scope)` / `getDPoPJkt(scope)` from `@classytic/arc/scope`.
|
|
40
|
+
|
|
41
|
+
## Permission helpers
|
|
42
|
+
|
|
43
|
+
Three new combinators in `@classytic/arc/permissions`:
|
|
44
|
+
|
|
45
|
+
### `requireDPoP()` — sender-constrained credentials
|
|
46
|
+
|
|
47
|
+
The inbound credential must be DPoP-bound. Arc reads `scope.dpopJkt`; your authenticate function performs `jose.dpop.verify()` and sets the field.
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { requireDPoP } from "@classytic/arc/permissions";
|
|
51
|
+
|
|
52
|
+
permissions: {
|
|
53
|
+
charge: allOf(requireServiceScope("payment.write"), requireDPoP()),
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Pass behavior: service scope with `dpopJkt` set → grant. Elevated → grant. Anything else → deny.
|
|
58
|
+
|
|
59
|
+
### `requireMandate(capability, opts?)` — capability-scoped authorization
|
|
60
|
+
|
|
61
|
+
The presented mandate must:
|
|
62
|
+
1. Authorize the requested `capability`
|
|
63
|
+
2. Not be expired (with optional grace window)
|
|
64
|
+
3. Be bound to the right resource (when `audience` opt is set)
|
|
65
|
+
4. Pass `validateAmount(ctx, mandate)` (when set)
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { requireMandate } from "@classytic/arc/permissions";
|
|
69
|
+
|
|
70
|
+
permissions: {
|
|
71
|
+
pay: requireMandate("payment.charge", {
|
|
72
|
+
audience: (ctx) => `invoice:${ctx.params?.id}`,
|
|
73
|
+
validateAmount: (ctx, mandate) => {
|
|
74
|
+
const amount = (ctx.data as { amount?: number })?.amount ?? 0;
|
|
75
|
+
if (amount <= (mandate.cap ?? 0)) return true;
|
|
76
|
+
return `Amount ${amount} exceeds mandate cap ${mandate.cap}`;
|
|
77
|
+
},
|
|
78
|
+
ttlGraceMs: 30_000, // default: 30s clock skew
|
|
79
|
+
noElevatedBypass: false, // platform admins normally bypass; set true for break-glass audit flows
|
|
80
|
+
}),
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `requireAgentScope(opts)` — composite gate
|
|
85
|
+
|
|
86
|
+
Bundles the three things every high-value agent endpoint needs (service identity + capability mandate + DPoP binding) into one call:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { requireAgentScope } from "@classytic/arc/permissions";
|
|
90
|
+
|
|
91
|
+
defineResource({
|
|
92
|
+
name: "invoice",
|
|
93
|
+
actions: {
|
|
94
|
+
pay: {
|
|
95
|
+
handler: payInvoice,
|
|
96
|
+
permissions: requireAgentScope({
|
|
97
|
+
capability: "payment.charge",
|
|
98
|
+
scopes: ["payment.write"], // OAuth `scopes` the client must hold
|
|
99
|
+
requireDPoP: true, // default true
|
|
100
|
+
audience: (ctx) => `invoice:${ctx.params?.id}`,
|
|
101
|
+
validateAmount: (ctx, m) => (ctx.data as { amount: number }).amount <= (m.cap ?? 0),
|
|
102
|
+
}),
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Use this instead of hand-composing `allOf(requireServiceScope(...), requireMandate(...), requireDPoP())` — fewer ways to misconfigure, one metadata tag downstream tools (audit, MCP, OpenAPI) can read.
|
|
109
|
+
|
|
110
|
+
## Wiring — the authenticate callback
|
|
111
|
+
|
|
112
|
+
Arc takes no position on which credential format you use. Whatever your verifier produces — JWT, JWT-VC mandate, opaque API key with metadata sidecar — populates `RequestScope.service`:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { jwtVerify, createRemoteJWKSet } from "jose";
|
|
116
|
+
|
|
117
|
+
const JWKS = createRemoteJWKSet(new URL("https://idp.example.com/.well-known/jwks.json"));
|
|
118
|
+
|
|
119
|
+
await createApp({
|
|
120
|
+
auth: {
|
|
121
|
+
type: "authenticator",
|
|
122
|
+
authenticate: async (request) => {
|
|
123
|
+
const auth = request.headers.authorization?.split(" ");
|
|
124
|
+
if (auth?.[0] !== "Mandate") return null;
|
|
125
|
+
|
|
126
|
+
// 1. Verify the mandate JWT (signature, iss, aud, exp)
|
|
127
|
+
const { payload } = await jwtVerify(auth[1], JWKS, {
|
|
128
|
+
issuer: "https://idp.example.com",
|
|
129
|
+
audience: "https://api.example.com",
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// 2. Verify the DPoP proof header (RFC 9449)
|
|
133
|
+
// — pseudocode; use jose.dpop.verify() in production
|
|
134
|
+
const dpopJkt = await verifyDPoPProof(request, payload.cnf?.jkt);
|
|
135
|
+
if (!dpopJkt) return null;
|
|
136
|
+
|
|
137
|
+
// 3. Populate scope with mandate + DPoP fingerprint
|
|
138
|
+
request.scope = {
|
|
139
|
+
kind: "service",
|
|
140
|
+
clientId: payload.iss as string,
|
|
141
|
+
organizationId: (payload.org as string) ?? "",
|
|
142
|
+
scopes: ((payload.scope as string) ?? "").split(" ").filter(Boolean),
|
|
143
|
+
mandate: {
|
|
144
|
+
id: payload.jti as string,
|
|
145
|
+
capability: payload.cap as string,
|
|
146
|
+
cap: payload.amount as number | undefined,
|
|
147
|
+
currency: payload.currency as string | undefined,
|
|
148
|
+
expiresAt: (payload.exp as number) * 1000,
|
|
149
|
+
audience: payload.aud as string | undefined,
|
|
150
|
+
parent: payload.parent as string | undefined,
|
|
151
|
+
},
|
|
152
|
+
dpopJkt,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
return { id: payload.iss as string };
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Mandate flow — typical AP2 / x402 sequence
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
┌──────────────┐
|
|
165
|
+
user grants │ │
|
|
166
|
+
"charge up to │ Customer │
|
|
167
|
+
$50 on inv 7" │ │
|
|
168
|
+
└──────┬───────┘
|
|
169
|
+
│
|
|
170
|
+
┌─────────▼──────────┐
|
|
171
|
+
│ Issues mandate │
|
|
172
|
+
│ - cap: 50 USD │
|
|
173
|
+
│ - audience: │
|
|
174
|
+
│ "invoice:INV-7" │
|
|
175
|
+
│ - exp: now + 60s │
|
|
176
|
+
│ - cnf.jkt: agent │
|
|
177
|
+
└─────────┬──────────┘
|
|
178
|
+
│
|
|
179
|
+
▼
|
|
180
|
+
┌──────────────────────┐
|
|
181
|
+
│ AI Agent │
|
|
182
|
+
│ signs + presents │
|
|
183
|
+
│ mandate via DPoP │
|
|
184
|
+
└──────────┬───────────┘
|
|
185
|
+
│
|
|
186
|
+
▼
|
|
187
|
+
┌──────────────────────┐
|
|
188
|
+
│ Arc app │
|
|
189
|
+
│ authenticate fn: │
|
|
190
|
+
│ - verify mandate │
|
|
191
|
+
│ - verify DPoP │
|
|
192
|
+
│ - set scope.mandate │
|
|
193
|
+
│ + scope.dpopJkt │
|
|
194
|
+
└──────────┬───────────┘
|
|
195
|
+
│
|
|
196
|
+
▼
|
|
197
|
+
┌──────────────────────┐
|
|
198
|
+
│ requireAgentScope: │
|
|
199
|
+
│ - cap satisfied? │
|
|
200
|
+
│ - audience match? │
|
|
201
|
+
│ - DPoP bound? │
|
|
202
|
+
│ - not expired? │
|
|
203
|
+
└──────────┬───────────┘
|
|
204
|
+
│
|
|
205
|
+
✓ allow / ✗ deny
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Audit — every gated action gets a row
|
|
209
|
+
|
|
210
|
+
Pair with `@classytic/arc/auth/audit` to record every agent action through the canonical `auditPlugin` store. Mandate id, audience, cap, dpopJkt all flow into `metadata` on the audit row — full forensic chain.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
auditPlugin({
|
|
214
|
+
actor: (request) =>
|
|
215
|
+
request.scope?.kind === "service"
|
|
216
|
+
? {
|
|
217
|
+
kind: "service",
|
|
218
|
+
clientId: getClientId(request.scope),
|
|
219
|
+
mandateId: getMandate(request.scope)?.id,
|
|
220
|
+
dpopJkt: getDPoPJkt(request.scope),
|
|
221
|
+
}
|
|
222
|
+
: { kind: "user", userId: getUserId(request.scope) },
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## What's NOT in arc (deliberate)
|
|
227
|
+
|
|
228
|
+
- **DPoP proof verification** — one `jose.dpop.verify()` call in your authenticate function. Arc would have to peer-dep `jose`; the host already has it.
|
|
229
|
+
- **JWT-VC mandate parser** — host's verifier (your IdP / AP2 issuer / custom).
|
|
230
|
+
- **Mandate issuance** — that's the IdP's job (or your token endpoint when you mint per-action mandates).
|
|
231
|
+
- **Risk scoring / device trust** — out of framework scope. Layer Castle / Stytch / Auth0 Risk separately.
|
|
232
|
+
|
|
233
|
+
## See also
|
|
234
|
+
|
|
235
|
+
- [enterprise-auth.md](enterprise-auth.md) — full enterprise-auth surface
|
|
236
|
+
- [scim.md](scim.md) — IdP provisioning (the user-creation path agents authenticate against)
|
|
237
|
+
- [auth.md](auth.md) — Better Auth + service identity setup
|
|
238
|
+
- [`playground/enterprise-auth/`](../../../playground/enterprise-auth/) — runnable smoke
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Subpath Imports — Full Enumeration
|
|
2
|
+
|
|
3
|
+
Arc ships heavily tree-shaken: every feature has its own subpath. Pay only for what you import.
|
|
4
|
+
|
|
5
|
+
## Core
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { defineResource, BaseController, BaseCrudController, allowPublic } from '@classytic/arc';
|
|
9
|
+
import { createApp, loadResources } from '@classytic/arc/factory';
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Adapters (kit-owned, never arc)
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { createMongooseAdapter } from '@classytic/mongokit/adapter';
|
|
16
|
+
import { createDrizzleAdapter } from '@classytic/sqlitekit/adapter';
|
|
17
|
+
import { createPrismaAdapter } from '@classytic/prismakit/adapter';
|
|
18
|
+
|
|
19
|
+
import type {
|
|
20
|
+
DataAdapter,
|
|
21
|
+
RepositoryLike,
|
|
22
|
+
AdapterRepositoryInput,
|
|
23
|
+
AdapterFactory,
|
|
24
|
+
OpenApiSchemas,
|
|
25
|
+
SchemaMetadata,
|
|
26
|
+
FieldMetadata,
|
|
27
|
+
RelationMetadata,
|
|
28
|
+
} from '@classytic/repo-core/adapter';
|
|
29
|
+
import { asRepositoryLike, isRepository } from '@classytic/repo-core/adapter';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`MinimalRepo` / `StandardRepo` import directly from `@classytic/repo-core/repository`.
|
|
33
|
+
|
|
34
|
+
## Auth
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { createBetterAuthAdapter, extractBetterAuthOpenApi } from '@classytic/arc/auth';
|
|
38
|
+
|
|
39
|
+
// Kit-owned BA overlays:
|
|
40
|
+
import { createBetterAuthOverlay, registerBetterAuthStubs } from '@classytic/mongokit/better-auth';
|
|
41
|
+
import { resolveBetterAuthCollections, BA_COLLECTIONS_BY_PLUGIN } from '@classytic/repo-core/better-auth';
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Permissions + scope
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import {
|
|
48
|
+
allowPublic, requireAuth, requireRoles, requireOwnership,
|
|
49
|
+
requireOrgMembership, requireOrgRole, requireTeamMembership,
|
|
50
|
+
requireServiceScope, requireScopeContext, requireOrgInScope,
|
|
51
|
+
// Agent-auth (2.13) — DPoP + capability mandates (AP2 / x402 / MCP)
|
|
52
|
+
requireAgentScope, requireMandate, requireDPoP,
|
|
53
|
+
type RequireAgentScopeOptions, type RequireMandateOptions,
|
|
54
|
+
allOf, anyOf, when, denyAll,
|
|
55
|
+
createDynamicPermissionMatrix, createRoleHierarchy,
|
|
56
|
+
fields, roles,
|
|
57
|
+
} from '@classytic/arc/permissions';
|
|
58
|
+
|
|
59
|
+
import {
|
|
60
|
+
isMember, isService, isElevated, isAuthenticated, hasOrgAccess,
|
|
61
|
+
getUserId, getUserRoles, getOrgId, getOrgRoles, getTeamId, getClientId,
|
|
62
|
+
getServiceScopes, getScopeContext, getScopeContextMap,
|
|
63
|
+
getAncestorOrgIds, isOrgInScope, getRequestScope,
|
|
64
|
+
// Agent-auth scope accessors (2.13)
|
|
65
|
+
getMandate, getDPoPJkt, type Mandate,
|
|
66
|
+
requireUserId, requireClientId, // throw 401 (UnauthorizedError) if absent
|
|
67
|
+
requireOrgId, requireTeamId, // throw 403 (OrgRequiredError) if absent
|
|
68
|
+
createTenantKeyGenerator,
|
|
69
|
+
} from '@classytic/arc/scope';
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Cache
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// HOST-LEVEL cache (action results, custom routes — NOT repo-bound paths)
|
|
76
|
+
import { MemoryCacheStore, RedisCacheStore, QueryCache } from '@classytic/arc/cache';
|
|
77
|
+
|
|
78
|
+
// REPO-BOUND cache (canonical) — getById/getAll/aggregate/count/etc
|
|
79
|
+
// Install once on the kit's repo; arc forwards declarative `cache:`
|
|
80
|
+
// config to req.cache automatically.
|
|
81
|
+
import { cachePlugin, type CacheOptions } from '@classytic/repo-core/cache';
|
|
82
|
+
// Per-call shape (TanStack-shaped):
|
|
83
|
+
// { staleTime, gcTime, swr, tags, bypass, enabled, key }
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Events
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { eventPlugin, EventOutbox, MemoryOutboxStore } from '@classytic/arc/events';
|
|
90
|
+
import { RedisEventTransport } from '@classytic/arc/events/redis';
|
|
91
|
+
import { RedisStreamEventTransport } from '@classytic/arc/events/redis-stream';
|
|
92
|
+
|
|
93
|
+
// Event types live in primitives, NOT arc:
|
|
94
|
+
import type { EventMeta, DomainEvent, EventTransport, EventHandler } from '@classytic/primitives/events';
|
|
95
|
+
import { createEvent, createChildEvent, matchEventPattern } from '@classytic/primitives/events';
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Plugins
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import {
|
|
102
|
+
healthPlugin, gracefulShutdownPlugin, ssePlugin,
|
|
103
|
+
metricsPlugin, versioningPlugin,
|
|
104
|
+
} from '@classytic/arc/plugins';
|
|
105
|
+
import { tracingPlugin } from '@classytic/arc/plugins/tracing';
|
|
106
|
+
import { auditPlugin } from '@classytic/arc/audit';
|
|
107
|
+
import { idempotencyPlugin } from '@classytic/arc/idempotency';
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Integrations
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import { jobsPlugin } from '@classytic/arc/integrations/jobs';
|
|
114
|
+
import { websocketPlugin } from '@classytic/arc/integrations/websocket';
|
|
115
|
+
import { eventGatewayPlugin } from '@classytic/arc/integrations/event-gateway';
|
|
116
|
+
import { webhookPlugin } from '@classytic/arc/integrations/webhooks';
|
|
117
|
+
import { mcpPlugin, defineTool, definePrompt, fieldRulesToZod, resourceToTools } from '@classytic/arc/mcp';
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Enterprise auth (2.13)
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
// SCIM 2.0 — IdP provisioning
|
|
124
|
+
import {
|
|
125
|
+
scimPlugin,
|
|
126
|
+
type ScimPluginOptions,
|
|
127
|
+
type ScimResourceMapping,
|
|
128
|
+
parseScimFilter, parseScimPatch,
|
|
129
|
+
DEFAULT_USER_MAPPING, DEFAULT_GROUP_MAPPING,
|
|
130
|
+
SCIM_USER_SCHEMA, SCIM_GROUP_SCHEMA,
|
|
131
|
+
ScimError,
|
|
132
|
+
} from '@classytic/arc/scim';
|
|
133
|
+
|
|
134
|
+
// Better Auth → arc audit bridge
|
|
135
|
+
import {
|
|
136
|
+
wireBetterAuthAudit,
|
|
137
|
+
type AuthEvent, type AuthEventName,
|
|
138
|
+
type WireBetterAuthAuditOptions,
|
|
139
|
+
} from '@classytic/arc/auth/audit';
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Hooks + presets
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { createHookSystem, beforeCreate, afterCreate, beforeUpdate, afterUpdate } from '@classytic/arc/hooks';
|
|
146
|
+
import {
|
|
147
|
+
bulkPreset, softDeletePreset, slugLookupPreset, treePreset,
|
|
148
|
+
ownedByUserPreset, multiTenantPreset, auditedPreset, searchPreset,
|
|
149
|
+
filesUploadPreset,
|
|
150
|
+
type TenantFieldSpec,
|
|
151
|
+
} from '@classytic/arc/presets';
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Testing
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import {
|
|
158
|
+
createTestApp, expectArc, createHttpTestHarness,
|
|
159
|
+
TestAuthSession, TestAuthProvider, TestFixtures,
|
|
160
|
+
runStorageContract,
|
|
161
|
+
} from '@classytic/arc/testing';
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Utilities
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import {
|
|
168
|
+
createStateMachine, CircuitBreaker, withCompensation, defineGuard,
|
|
169
|
+
retry, queryParser,
|
|
170
|
+
} from '@classytic/arc/utils';
|
|
171
|
+
import { defineMigration, MigrationRunner } from '@classytic/arc/migrations';
|
|
172
|
+
import { Type, ArcListResponse } from '@classytic/arc/schemas';
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Type-only barrel
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// Type-only — produces `export {}` at runtime; this is correct
|
|
179
|
+
import type { ArcRequest, IRequestContext, IControllerResponse } from '@classytic/arc/types';
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Notes
|
|
183
|
+
|
|
184
|
+
- **No default exports** outside Fastify plugin entry files (`auditPlugin`, `authPlugin`, `eventPlugin`, `idempotencyPlugin`, `introspectionPlugin`).
|
|
185
|
+
- **Type-only subpaths** produce `export {}` at runtime — interfaces are erased.
|
|
186
|
+
- **Adapters live in kits**, not arc. Arc 2.12+ ships zero kit-bound adapters.
|
|
187
|
+
- **Event types live in `@classytic/primitives/events`**, not `@classytic/arc/events`. Arc re-exports the runtime `MemoryEventTransport` only.
|