@classytic/arc 2.19.0 → 2.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/arc.js +37 -0
- package/dist/{BaseController-Dy6EQHjM.mjs → BaseController-BnLYgE9A.mjs} +4 -4
- package/dist/{EventTransport-IEn7Tn-Q.d.mts → EventTransport-QmY7A258.d.mts} +0 -1
- package/dist/{QueryCache-TRfXau3W.d.mts → QueryCache-Z1B38koh.d.mts} +0 -1
- package/dist/{ResourceRegistry-5fKZwhK_.mjs → ResourceRegistry-7RnrEWNP.mjs} +1 -1
- package/dist/{actionPermissions-D7NGwcAR.mjs → actionPermissions-ze70xXJi.mjs} +1 -1
- package/dist/audit/index.d.mts +9 -5
- package/dist/audit/index.mjs +1 -1
- package/dist/auth/audit.d.mts +7 -4
- package/dist/auth/audit.mjs +5 -0
- package/dist/auth/index.d.mts +7 -14
- package/dist/auth/index.mjs +7 -5
- package/dist/auth/redis-session.d.mts +1 -2
- package/dist/{buildHandler-B0qvAguf.mjs → buildHandler-D_2ULWxZ.mjs} +3 -3
- package/dist/cache/index.d.mts +2 -3
- package/dist/cache/index.mjs +2 -2
- package/dist/cli/commands/describe.d.mts +1 -2
- package/dist/cli/commands/describe.mjs +2 -2
- 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 +4 -13
- package/dist/cli/index.mjs +2 -2
- package/dist/{constants-gaEeMlz-.mjs → constants-DNre0wRg.mjs} +1 -1
- package/dist/context/index.d.mts +2 -2
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +5 -5
- package/dist/{core-Ba-6Sue6.mjs → core-DZ6Xe1jR.mjs} +182 -55
- package/dist/{createActionRouter-B_WzBFyf.mjs → createActionRouter-BWMDW-dL.mjs} +4 -4
- package/dist/{createAggregationRouter-B_G_nIjm.mjs → createAggregationRouter-l5mNdYrZ.mjs} +5 -4
- package/dist/{createApp--703hQE1.mjs → createApp-Bi61XxqU.mjs} +229 -24
- package/dist/discovery/index.d.mts +0 -1
- package/dist/docs/index.d.mts +1 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/{elevation-xGUBq6p_.d.mts → elevation-C9s5hFP_.d.mts} +0 -1
- package/dist/encryption/index.d.mts +2 -144
- package/dist/{errorHandler-BtUUDPEa.d.mts → errorHandler-B0e-bq-O.d.mts} +0 -1
- package/dist/{errors-DOHkjQlD.d.mts → errors-DHcHVAgk.d.mts} +0 -1
- package/dist/{eventPlugin-DbBFd3x_.d.mts → eventPlugin-A6EbthXR.d.mts} +10 -6
- package/dist/events/index.d.mts +9 -6
- package/dist/events/index.mjs +9 -6
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -2
- package/dist/factory/index.d.mts +5 -4
- package/dist/factory/index.mjs +3 -3
- package/dist/{fastify-augmentation-D-5_yQJi.d.mts → fastify-augmentation-DafigGQp.d.mts} +12 -2
- package/dist/{fields-C7ahdGYf.d.mts → fields-BGqrAa_u.d.mts} +1 -2
- package/dist/{generate-Brans3fW.mjs → generate-usRSdQmP.mjs} +4 -3
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +4 -3
- package/dist/idempotency/index.mjs +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-CP6A1Ffj.d.mts → index-B5N-NaHs.d.mts} +88 -7
- package/dist/{index-CRKiiP5o.d.mts → index-B5PoNbfu.d.mts} +41 -7
- package/dist/{index-CUTG2Cuo.d.mts → index-Dtrj6XZk.d.mts} +90 -29
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +7 -7
- package/dist/{init-Bqpt1Hxf.mjs → init-0YhHkXGk.mjs} +239 -140
- package/dist/integrations/event-gateway.d.mts +2 -3
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/jobs.d.mts +0 -1
- package/dist/integrations/mcp/index.d.mts +6 -7
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -2
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/streamline.d.mts +19 -7
- package/dist/integrations/streamline.mjs +9 -5
- package/dist/integrations/webhooks.d.mts +0 -1
- package/dist/integrations/websocket-pushref-redis.d.mts +1 -2
- package/dist/integrations/websocket-redis.d.mts +1 -2
- package/dist/integrations/websocket.d.mts +2 -2
- package/dist/{loadResources-B8UmpITt.mjs → loadResources-DpU8pfjV.mjs} +4 -3
- package/dist/{loadResourcesFromEntry-BTlFEx05.mjs → loadResourcesFromEntry-OMCvIEE7.mjs} +1 -1
- package/dist/{mcpPlugin-C088Nd-G.mjs → mcpPlugin-B9XjjNVG.mjs} +148 -49
- package/dist/middleware/index.d.mts +1 -2
- package/dist/middleware/index.mjs +1 -1
- package/dist/module-WeuU5jfd.d.mts +429 -0
- package/dist/{openapi-DZ-5a5Op.mjs → openapi-Kyod_di6.mjs} +3 -3
- package/dist/permissions/index.d.mts +3 -3
- package/dist/permissions/index.mjs +2 -2
- package/dist/{permissions-BPB1xqGf.mjs → permissions-BJMuKMl7.mjs} +43 -3
- package/dist/pipeline/index.d.mts +1 -2
- package/dist/plugins/index.d.mts +87 -10
- package/dist/plugins/index.mjs +91 -4
- package/dist/plugins/response-cache.d.mts +5 -3
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/{pluralize-DccFV9R7.mjs → pluralize-BhrgwZb9.mjs} +3 -3
- package/dist/presets/filesUpload.d.mts +4 -5
- package/dist/presets/filesUpload.mjs +1 -1
- package/dist/presets/index.d.mts +16 -3
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -2
- package/dist/presets/multiTenant.mjs +1 -1
- package/dist/presets/search.d.mts +2 -3
- package/dist/presets/search.mjs +3 -2
- package/dist/{presets-BtyFwTO4.mjs → presets-gw0ciIUD.mjs} +1 -1
- package/dist/{pushref-registry-DnCqL3aa.d.mts → pushref-registry-BbcnpNTm.d.mts} +4 -2
- package/dist/{queryCachePlugin-xzFyKAjT.d.mts → queryCachePlugin-CfYWq-Ak.d.mts} +1 -2
- package/dist/{queryCachePlugin-emHb0CuX.mjs → queryCachePlugin-DzqLN904.mjs} +2 -2
- package/dist/{redis-C3W0qbz8.d.mts → redis-UDtLaNj6.d.mts} +0 -1
- package/dist/{redis-stream-DsP1vqZB.d.mts → redis-stream-iVR2l7aS.d.mts} +1 -2
- package/dist/{registerRoute-BdV8DDwU.mjs → registerRoute-oGAl0oA8.mjs} +1 -1
- package/dist/registry/index.d.mts +2 -2
- package/dist/registry/index.mjs +2 -2
- package/dist/{registry-Bm9LjWKs.mjs → registry-vcOCtPij.mjs} +1 -1
- package/dist/{schemaIR-D1MJwqmp.mjs → schemaIR-ajetw3Fv.mjs} +1 -42
- package/dist/schemas/index.d.mts +0 -1
- package/dist/scim/index.d.mts +0 -1
- package/dist/scim/index.mjs +2 -2
- package/dist/scope/index.d.mts +2 -3
- package/dist/{sessionManager-BXG-HGwG.d.mts → sessionManager-BHOM3N_0.d.mts} +10 -6
- package/dist/{storage-Co_PQpeQ.d.mts → storage-DLUZ04kK.d.mts} +8 -4
- package/dist/sync/changelog.d.mts +2 -0
- package/dist/sync/changelog.mjs +2 -0
- package/dist/testing/index.d.mts +2 -3
- package/dist/testing/index.mjs +6 -3
- package/dist/testing/storageContract.d.mts +1 -2
- package/dist/{tracing-D8jlGXP7.d.mts → tracing-CsGKQJGg.d.mts} +0 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/types/storage.d.mts +1 -1
- package/dist/types-Cc91nXuA.d.mts +132 -0
- package/dist/{types-LNebCoJx.d.mts → types-DH0GupI7.d.mts} +8 -4
- package/dist/{types-DpvSF5Hh.d.mts → types-DRj-Ut4n.d.mts} +1 -2
- package/dist/{types-9_wtNPsI.d.mts → types-DpxoNX5v.d.mts} +112 -214
- package/dist/utils/index.d.mts +182 -128
- package/dist/utils/index.mjs +2 -2
- package/dist/{utils-C6QQ9-hd.mjs → utils-CO8a3B_1.mjs} +1435 -1391
- package/dist/{validate-CRcaWzp2.mjs → validate-C2mGgSXg.mjs} +3 -3
- package/dist/{versioning-D_eBCfNr.d.mts → versioning-DQ4mCvg0.d.mts} +1 -2
- package/dist/{websocket-MlYlrYq0.d.mts → websocket-uuWqM6UY.d.mts} +5 -4
- package/package.json +18 -13
- package/skills/arc/SKILL.md +10 -0
- package/skills/arc/references/mcp.md +2 -0
- package/skills/arc-module-publishing/SKILL.md +242 -0
- package/skills/arc-module-publishing/references/authoring-modules.md +272 -0
- package/skills/arc-module-publishing/references/package-manifest.md +155 -0
- package/skills/arc-module-publishing/references/publishing-workflow.md +182 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import { n as ErrorMapper } from "./errorHandler-B0e-bq-O.mjs";
|
|
2
|
+
import { FastifyInstance } from "fastify";
|
|
3
|
+
//#region src/factory/loadResources.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* loadResources — Auto-discover resource files from a directory.
|
|
6
|
+
*
|
|
7
|
+
* Scans for `*.resource.{ts,js,mts,mjs}` files, imports each,
|
|
8
|
+
* and collects their default exports. No barrel file needed.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { createApp, loadResources } from '@classytic/arc/factory';
|
|
13
|
+
*
|
|
14
|
+
* // Recommended: import.meta.url — works in both src/ (dev) and dist/ (prod)
|
|
15
|
+
* const app = await createApp({
|
|
16
|
+
* resources: await loadResources(import.meta.url),
|
|
17
|
+
* auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } },
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // Or explicit path (must match runtime layout)
|
|
21
|
+
* const app2 = await createApp({
|
|
22
|
+
* resources: await loadResources('./src/resources'),
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* File convention:
|
|
27
|
+
* ```
|
|
28
|
+
* src/resources/
|
|
29
|
+
* product/product.resource.ts → export default defineResource({ name: 'product', ... })
|
|
30
|
+
* order/order.resource.ts → export default defineResource({ name: 'order', ... })
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Resource interface — the contract between `loadResources`/`createApp` and resource definitions.
|
|
35
|
+
*
|
|
36
|
+
* Matches the shape of `ResourceDefinition` from `defineResource()` without requiring
|
|
37
|
+
* the import. All properties except `toPlugin` are optional so plain objects work too:
|
|
38
|
+
*
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // Full resource (from defineResource)
|
|
41
|
+
* const product = defineResource({ name: 'product', ... }); // satisfies ResourceLike
|
|
42
|
+
*
|
|
43
|
+
* // Minimal resource (plain object)
|
|
44
|
+
* const simple: ResourceLike = { name: 'ping', toPlugin: () => () => {} };
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* **DO NOT add an index signature** (`[key: string]: unknown`) to this interface.
|
|
48
|
+
* Class instances (like `ResourceDefinition`) don't implicitly carry index signatures,
|
|
49
|
+
* so adding one here makes `ResourceDefinition` *unassignable* to `ResourceLike` —
|
|
50
|
+
* the exact opposite of the intent. TypeScript's structural typing already allows
|
|
51
|
+
* classes with extra properties to satisfy this interface without an index signature.
|
|
52
|
+
*/
|
|
53
|
+
interface ResourceLike {
|
|
54
|
+
/** Plugin factory — called by createApp to register routes */
|
|
55
|
+
toPlugin: () => unknown;
|
|
56
|
+
/** Resource name (used for route generation, logging, duplicate detection) */
|
|
57
|
+
name?: string;
|
|
58
|
+
/** Route prefix (default: `/${name}s`) */
|
|
59
|
+
prefix?: string;
|
|
60
|
+
/** Skip the global `resourcePrefix` from createApp — register at root */
|
|
61
|
+
skipGlobalPrefix?: boolean;
|
|
62
|
+
/** Display name for docs/OpenAPI */
|
|
63
|
+
displayName?: string;
|
|
64
|
+
/** Applied preset names */
|
|
65
|
+
_appliedPresets?: string[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resource module — what a `.resource.ts` file's default (or named) export
|
|
69
|
+
* may resolve to.
|
|
70
|
+
*
|
|
71
|
+
* Two shapes accepted:
|
|
72
|
+
* 1. **Plain `ResourceLike`** — the result of `defineResource({...})`.
|
|
73
|
+
* Used as-is; no engine wiring needed.
|
|
74
|
+
* 2. **Factory `(ctx: TContext) => ResourceLike | Promise<ResourceLike>`**
|
|
75
|
+
* — a function arc calls with the `context` from `LoadResourcesOptions`.
|
|
76
|
+
* Eliminates the parallel `createXResource(engine)` factory files +
|
|
77
|
+
* `exclude: [...]` bookkeeping that engine-bound resources used to need.
|
|
78
|
+
*
|
|
79
|
+
* Detection is by `typeof === 'function'`: `ResourceDefinition` instances
|
|
80
|
+
* (returned by `defineResource()`) are class instances (`typeof === 'object'`),
|
|
81
|
+
* so the two shapes are unambiguous in practice.
|
|
82
|
+
*/
|
|
83
|
+
type ResourceModule<TContext = unknown> = ResourceLike | ((ctx: TContext) => ResourceLike | Promise<ResourceLike>);
|
|
84
|
+
interface LoadResourcesOptions<TContext = unknown> {
|
|
85
|
+
/** File pattern suffix (default: '.resource'). Matches `*.resource.{ts,js,mts,mjs}`. */
|
|
86
|
+
suffix?: string;
|
|
87
|
+
/** Recurse into subdirectories (default: true) */
|
|
88
|
+
recursive?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Context passed to factory-style default exports. Resources whose default
|
|
91
|
+
* export is a function `(ctx) => ResourceLike` are called with this value;
|
|
92
|
+
* plain `ResourceLike` exports are returned unchanged.
|
|
93
|
+
*
|
|
94
|
+
* Use this to thread engine handles into engine-bound resources without
|
|
95
|
+
* creating parallel factory files outside `loadResources`'s sweep:
|
|
96
|
+
*
|
|
97
|
+
* ```ts
|
|
98
|
+
* // category.resource.ts
|
|
99
|
+
* import type { AppContext } from '#core/app/context.js';
|
|
100
|
+
* export default (ctx: AppContext) =>
|
|
101
|
+
* defineResource({
|
|
102
|
+
* name: 'category',
|
|
103
|
+
* adapter: createMongooseAdapter(
|
|
104
|
+
* ctx.catalog.models.Category,
|
|
105
|
+
* ctx.catalog.repositories.category,
|
|
106
|
+
* ),
|
|
107
|
+
* });
|
|
108
|
+
*
|
|
109
|
+
* // create-arc-app-options.ts
|
|
110
|
+
* resources: async () => {
|
|
111
|
+
* const [catalog, flow] = await Promise.all([
|
|
112
|
+
* ensureCatalogEngine(),
|
|
113
|
+
* ensureFlowEngine(),
|
|
114
|
+
* ]);
|
|
115
|
+
* return loadResources(import.meta.url, { context: { catalog, flow } });
|
|
116
|
+
* }
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* Backwards compatible — pre-2.11.1 callers omit `context`, plain exports
|
|
120
|
+
* keep working unchanged. Factories that need a context but receive
|
|
121
|
+
* `undefined` should narrow defensively.
|
|
122
|
+
*/
|
|
123
|
+
context?: TContext;
|
|
124
|
+
/**
|
|
125
|
+
* Resource names to exclude. Matched against the resource's `.name` property
|
|
126
|
+
* after import, so you use the resource name (not the filename).
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* await loadResources('./src/resources', { exclude: ['debug', 'legacy-report'] })
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
exclude?: string[];
|
|
134
|
+
/**
|
|
135
|
+
* Resource names to include. When set, only matching resources are returned.
|
|
136
|
+
* Takes priority over `exclude`.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* // Only load these two resources (useful for testing or microservice splits)
|
|
141
|
+
* await loadResources('./src/resources', { include: ['product', 'order'] })
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
include?: string[];
|
|
145
|
+
/**
|
|
146
|
+
* Path-level gate, called for every discovered file BEFORE it is imported.
|
|
147
|
+
* Return `false` to skip the file entirely — its module never evaluates,
|
|
148
|
+
* so top-level side effects (engine construction, model registration) of
|
|
149
|
+
* gated-off features never fire. That's the difference from
|
|
150
|
+
* `include`/`exclude`, which match resource NAMES after import.
|
|
151
|
+
*
|
|
152
|
+
* The feature-flag → resource-dir manifest every tiered SaaS host carries
|
|
153
|
+
* becomes one callback:
|
|
154
|
+
*
|
|
155
|
+
* ```ts
|
|
156
|
+
* await loadResources(import.meta.url, {
|
|
157
|
+
* filter: (path) => {
|
|
158
|
+
* if (path.includes(`${sep}loyalty${sep}`)) return isFeatureEnabled('loyalty');
|
|
159
|
+
* if (path.includes(`${sep}pos${sep}`)) return isFeatureEnabled('pos');
|
|
160
|
+
* return true;
|
|
161
|
+
* },
|
|
162
|
+
* });
|
|
163
|
+
* ```
|
|
164
|
+
*
|
|
165
|
+
* Receives the ABSOLUTE file path. Gating everything is legitimate — the
|
|
166
|
+
* result is an empty array (interacts with `strictResourceDir` like any
|
|
167
|
+
* other empty discovery).
|
|
168
|
+
*/
|
|
169
|
+
filter?: (absolutePath: string) => boolean;
|
|
170
|
+
/**
|
|
171
|
+
* Optional logger override for diagnostics. When omitted, warnings flow
|
|
172
|
+
* through arc's standard logger (`arcLog('loadResources')`) — same path
|
|
173
|
+
* as every other arc-internal warning, controlled by `ARC_SUPPRESS_WARNINGS=1`
|
|
174
|
+
* and routable via `configureArcLogger({ writer })`.
|
|
175
|
+
*
|
|
176
|
+
* Pass any object with `warn(msg)` to override (e.g. `fastify.log` —
|
|
177
|
+
* which is what `registerResources` passes automatically when arc's
|
|
178
|
+
* factory triggers auto-discovery via `resourceDir`).
|
|
179
|
+
*
|
|
180
|
+
* Pre-2.11.1 had a `silent: boolean` flag and "silent by default" semantics;
|
|
181
|
+
* both removed. Migration:
|
|
182
|
+
*
|
|
183
|
+
* ```ts
|
|
184
|
+
* // Pre-2.11.1 // 2.11.1+
|
|
185
|
+
* loadResources(url, { silent: true }); // ARC_SUPPRESS_WARNINGS=1 (env)
|
|
186
|
+
* // OR configureArcLogger({ writer })
|
|
187
|
+
* loadResources(url, { silent: !isDev }); // ARC_SUPPRESS_WARNINGS=1 in prod
|
|
188
|
+
* loadResources(url, { logger: pinoAdapter }); // unchanged — still works
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
logger?: {
|
|
192
|
+
warn: (msg: string) => void;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Scan a directory for resource files and import their default exports.
|
|
197
|
+
*
|
|
198
|
+
* Accepts a directory path OR `import.meta.url` (file:// URL).
|
|
199
|
+
* When given a URL, resolves to the directory containing that file —
|
|
200
|
+
* so `loadResources(import.meta.url)` works in both dev (`src/`) and
|
|
201
|
+
* production (`dist/`) without path gymnastics.
|
|
202
|
+
*
|
|
203
|
+
* @param dir - Directory path, or `import.meta.url` (file:// URL resolved to its dirname)
|
|
204
|
+
* @param options - Pattern and recursion options
|
|
205
|
+
* @returns Array of resource definitions (anything with `.toPlugin()`)
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```ts
|
|
209
|
+
* // Works from both src/ and dist/ — resolves relative to the calling file
|
|
210
|
+
* await loadResources(import.meta.url);
|
|
211
|
+
*
|
|
212
|
+
* // Subdirectory relative to the calling file
|
|
213
|
+
* await loadResources(import.meta.url, { suffix: '.resource' });
|
|
214
|
+
*
|
|
215
|
+
* // Explicit path (must match runtime layout)
|
|
216
|
+
* await loadResources('./src/resources');
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
declare function loadResources<TContext = unknown>(dir: string, options?: LoadResourcesOptions<TContext>): Promise<ResourceLike[]>;
|
|
220
|
+
//#endregion
|
|
221
|
+
//#region src/factory/module.d.ts
|
|
222
|
+
interface ArcModule<TExports = unknown> {
|
|
223
|
+
/** Stable identifier — appears in boot logs and duplicate-module detection. */
|
|
224
|
+
readonly name: string;
|
|
225
|
+
/**
|
|
226
|
+
* Names of modules this one must be composed AFTER. arc topologically orders
|
|
227
|
+
* the `modules` array from these edges before ANY phase runs, so a
|
|
228
|
+
* dependency's `bootstrap` (and thus its `fastify.arc.modules[dep]` export)
|
|
229
|
+
* is always live before this module's bootstrap, resources, or
|
|
230
|
+
* afterResources. Teardown (`onClose`) runs in the reverse of that order.
|
|
231
|
+
*
|
|
232
|
+
* Use this instead of relying on list position when a module reads another's
|
|
233
|
+
* public export — e.g. `@classytic/arc-reservation` wiring off
|
|
234
|
+
* `arc.modules.order`:
|
|
235
|
+
*
|
|
236
|
+
* ```ts
|
|
237
|
+
* defineModule({ name: "reservation", dependsOn: ["order"], bootstrap: (f) => {
|
|
238
|
+
* const order = getModuleExports<OrderEngine>(f, "order"); // guaranteed live
|
|
239
|
+
* …
|
|
240
|
+
* }});
|
|
241
|
+
* ```
|
|
242
|
+
*
|
|
243
|
+
* The order is a STABLE topological sort: modules with no `dependsOn` (and
|
|
244
|
+
* any two modules with no edge between them) keep their original list order,
|
|
245
|
+
* so adding `dependsOn` never silently reorders an unrelated module. All
|
|
246
|
+
* failure modes are fail-fast at boot: a name not in the composed set, a
|
|
247
|
+
* self-reference, and dependency CYCLES each throw with the offending path.
|
|
248
|
+
*
|
|
249
|
+
* **`dependsOn` is COMPOSITION order, not lazy loading.** Every module input
|
|
250
|
+
* (including dynamic-import thunks) is resolved — imported — up front via
|
|
251
|
+
* `Promise.all` BEFORE the sort; `dependsOn` then orders the *composition*
|
|
252
|
+
* (which module's `plugins`/`bootstrap` runs first), it does NOT delay
|
|
253
|
+
* *importing* a dependent until its dependency is ready. Use a thunk to gate
|
|
254
|
+
* whether a module is imported at all (region/tier packs); use `dependsOn`
|
|
255
|
+
* to order modules that are already selected.
|
|
256
|
+
*/
|
|
257
|
+
readonly dependsOn?: readonly string[];
|
|
258
|
+
/**
|
|
259
|
+
* Fastify plugins / decorators this module needs — the module-level analog
|
|
260
|
+
* of the app's `plugins()` slot. Runs in the plugins phase: AFTER the app's
|
|
261
|
+
* own `plugins()` (so module infra can build on app foundations like a DB
|
|
262
|
+
* connection) and in `dependsOn` order, but BEFORE any module `bootstrap` —
|
|
263
|
+
* so engines initialised in `bootstrap` can rely on what's registered here.
|
|
264
|
+
*
|
|
265
|
+
* Separating this from `bootstrap` keeps lifecycle intent explicit for
|
|
266
|
+
* published ecosystem packages: `plugins` = "register infra"; `bootstrap` =
|
|
267
|
+
* "initialise engines (and return the public export)". Registering a plugin
|
|
268
|
+
* inside `bootstrap` still works — this slot just makes the two distinct.
|
|
269
|
+
*/
|
|
270
|
+
plugins?: (fastify: FastifyInstance) => void | Promise<void>;
|
|
271
|
+
/**
|
|
272
|
+
* Domain error mappers this module ships (see `defineErrorMapper`). Merged
|
|
273
|
+
* into the app's error handler at boot, AFTER any host-declared mappers —
|
|
274
|
+
* host config keeps priority; module mappers follow in composition order.
|
|
275
|
+
*
|
|
276
|
+
* Closes the "composition root must know every domain's error classes"
|
|
277
|
+
* coupling: before this slot, adding `@classytic/arc-shipping` meant
|
|
278
|
+
* remembering to also register its `ShippingError` mapper in the host's
|
|
279
|
+
* `errorHandler.errorMappers` — forget it and the domain error crossed the
|
|
280
|
+
* wire as an opaque 500. Now the module carries its own mapper:
|
|
281
|
+
*
|
|
282
|
+
* ```ts
|
|
283
|
+
* defineModule({
|
|
284
|
+
* name: 'shipping',
|
|
285
|
+
* errorMappers: [shippingErrorMapper],
|
|
286
|
+
* ...
|
|
287
|
+
* })
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
readonly errorMappers?: readonly ErrorMapper[];
|
|
291
|
+
/**
|
|
292
|
+
* Domain init — runs in the `bootstrap` phase (after all `plugins`, before
|
|
293
|
+
* resources). Initialize engines / singletons / event subscriptions here so
|
|
294
|
+
* they are live when this module's `resources` factory runs.
|
|
295
|
+
*
|
|
296
|
+
* A returned value becomes the module's PUBLIC EXPORT, recorded at
|
|
297
|
+
* `fastify.arc.modules[name]` (wiki/modules.md — "no container", layer 2).
|
|
298
|
+
* Later modules' bootstraps can read it (list order = init order), which is
|
|
299
|
+
* how cross-module ports are wired without a DI container. Declare the
|
|
300
|
+
* export shape via `defineModule<TExports>` and read it back with the typed
|
|
301
|
+
* accessor — no cast at the consuming end:
|
|
302
|
+
*
|
|
303
|
+
* ```ts
|
|
304
|
+
* // arc-invoice bootstrap, composed AFTER arc-accounting:
|
|
305
|
+
* const acct = getModuleExports<AccountingEngine>(fastify, "accounting");
|
|
306
|
+
* ```
|
|
307
|
+
*/
|
|
308
|
+
bootstrap?: (fastify: FastifyInstance) => TExports | Promise<TExports>;
|
|
309
|
+
/**
|
|
310
|
+
* The module's resources. Array or factory — the factory form runs AFTER all
|
|
311
|
+
* bootstraps, so `defineResource(...)` receives fully-booted engines. Flows
|
|
312
|
+
* through arc's normal registration (prefix, dedup, docs), identical to a
|
|
313
|
+
* top-level `resources` entry.
|
|
314
|
+
*/
|
|
315
|
+
resources?: ReadonlyArray<ResourceLike> | ((fastify: FastifyInstance) => ReadonlyArray<ResourceLike> | Promise<ReadonlyArray<ResourceLike>>);
|
|
316
|
+
/**
|
|
317
|
+
* Post-registration wiring — runs in the `afterResources` phase, once this
|
|
318
|
+
* module's routes are mounted. Use for cross-resource event subscriptions the
|
|
319
|
+
* module owns.
|
|
320
|
+
*/
|
|
321
|
+
afterResources?: (fastify: FastifyInstance) => void | Promise<void>;
|
|
322
|
+
/**
|
|
323
|
+
* Teardown — registered as a Fastify `onClose` hook. Destroy engines, stop
|
|
324
|
+
* timers, flush the module's outbox. Modules close in REVERSE list order
|
|
325
|
+
* (last composed, first closed), mirroring init.
|
|
326
|
+
*/
|
|
327
|
+
onClose?: (fastify: FastifyInstance) => void | Promise<void>;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* A module in any of the forms `createApp({ modules })` accepts:
|
|
331
|
+
*
|
|
332
|
+
* - `ArcModule` — eager (already imported)
|
|
333
|
+
* - `Promise<ArcModule>` — an in-flight import
|
|
334
|
+
* - `() => ArcModule | Promise<…>` — a thunk, resolved at boot
|
|
335
|
+
*
|
|
336
|
+
* The **thunk of a dynamic import** is the point of this union — it lets a host
|
|
337
|
+
* compose modules *logically* and load them *lazily / conditionally*, the
|
|
338
|
+
* `next/dynamic` idea applied to backend domains. The module's code (and its
|
|
339
|
+
* heavy deps) is only pulled in when the thunk runs, so region- or tier-gated
|
|
340
|
+
* packs never enter the bundle path they aren't selected for:
|
|
341
|
+
*
|
|
342
|
+
* ```ts
|
|
343
|
+
* const taxPack =
|
|
344
|
+
* region === "BD"
|
|
345
|
+
* ? () => import("@classytic/bd-tax").then((m) => m.createBdTaxModule(deps))
|
|
346
|
+
* : () => import("@classytic/us-tax").then((m) => m.createUsTaxModule(deps));
|
|
347
|
+
*
|
|
348
|
+
* await createApp({ modules: [coreModule(deps), taxPack] });
|
|
349
|
+
* // only the selected tax package is imported + composed
|
|
350
|
+
* ```
|
|
351
|
+
*/
|
|
352
|
+
type ArcModuleInput<TExports = unknown> = ArcModule<TExports> | Promise<ArcModule<TExports>> | (() => ArcModule<TExports> | Promise<ArcModule<TExports>>);
|
|
353
|
+
/**
|
|
354
|
+
* Resolve any module-input form to a concrete `ArcModule`. A thunk is invoked
|
|
355
|
+
* (this is where a dynamic `import()` fires); a promise (or plain module) is
|
|
356
|
+
* awaited. Called once per module at the start of the bootstrap phase.
|
|
357
|
+
*/
|
|
358
|
+
declare function resolveModule(input: ArcModuleInput): Promise<ArcModule>;
|
|
359
|
+
/**
|
|
360
|
+
* Order modules for composition by their `dependsOn` edges — a STABLE
|
|
361
|
+
* topological sort. Called once at the start of the bootstrap phase; every
|
|
362
|
+
* subsequent phase (bootstrap, resources, afterResources, and reverse-order
|
|
363
|
+
* onClose) iterates the returned list, so a module's declared dependencies are
|
|
364
|
+
* always composed before it.
|
|
365
|
+
*
|
|
366
|
+
* "Stable" = modules with no edge between them keep their original list order,
|
|
367
|
+
* so declaring `dependsOn` on one module never silently reorders an unrelated
|
|
368
|
+
* one. Backward compatible: a `modules` array with NO `dependsOn` anywhere is
|
|
369
|
+
* returned unchanged.
|
|
370
|
+
*
|
|
371
|
+
* Fail-fast — throws (never reorders past a broken contract) on:
|
|
372
|
+
* - duplicate module names (the name is the graph key)
|
|
373
|
+
* - a `dependsOn` name not present in the composed set
|
|
374
|
+
* - a self-reference (`dependsOn` includes the module's own name)
|
|
375
|
+
* - a dependency cycle (reports the concrete `a → b → … → a` path)
|
|
376
|
+
*/
|
|
377
|
+
declare function orderModules(modules: readonly ArcModule[]): ArcModule[];
|
|
378
|
+
/**
|
|
379
|
+
* Typed module registry — hosts augment this via declaration merging so
|
|
380
|
+
* `getModuleExports(f, "order")` infers the export type without a manual type
|
|
381
|
+
* argument (the fastify / awilix pattern):
|
|
382
|
+
*
|
|
383
|
+
* ```ts
|
|
384
|
+
* declare module "@classytic/arc/factory" {
|
|
385
|
+
* interface ArcModuleRegistry {
|
|
386
|
+
* order: OrderEngine;
|
|
387
|
+
* accounting: AccountingEngine;
|
|
388
|
+
* }
|
|
389
|
+
* }
|
|
390
|
+
* ```
|
|
391
|
+
*
|
|
392
|
+
* Left empty here so the fallback `getModuleExports<T>(f, name: string)` stays
|
|
393
|
+
* available for apps that don't augment it.
|
|
394
|
+
*/
|
|
395
|
+
interface ArcModuleRegistry {}
|
|
396
|
+
/**
|
|
397
|
+
* Identity helper for authoring a typed module — mirrors `defineResource`.
|
|
398
|
+
* Gives inference + a single obvious construction site; does no work.
|
|
399
|
+
*
|
|
400
|
+
* `TExports` is inferred from the `bootstrap` return value, so a module
|
|
401
|
+
* author gets a typed public export for free:
|
|
402
|
+
*
|
|
403
|
+
* ```ts
|
|
404
|
+
* export const accountingModule = (deps: Deps) =>
|
|
405
|
+
* defineModule({
|
|
406
|
+
* name: "accounting",
|
|
407
|
+
* bootstrap: async () => createAccountingEngine(deps), // TExports inferred
|
|
408
|
+
* });
|
|
409
|
+
* ```
|
|
410
|
+
*/
|
|
411
|
+
declare function defineModule<TExports = unknown>(module: ArcModule<TExports>): ArcModule<TExports>;
|
|
412
|
+
/**
|
|
413
|
+
* Typed accessor for a module's public export (its `bootstrap` return value),
|
|
414
|
+
* recorded at `fastify.arc.modules[name]`.
|
|
415
|
+
*
|
|
416
|
+
* Throwing, in line with the fail-fast contract (and `requireOrgId`-style
|
|
417
|
+
* accessors): a missing entry means the module either isn't composed, is
|
|
418
|
+
* composed AFTER the caller (list order = init order), or returned nothing —
|
|
419
|
+
* all wiring bugs that must surface at boot, not as `undefined` downstream.
|
|
420
|
+
*
|
|
421
|
+
* The type parameter is an assertion, not a proof. Two ways to type it:
|
|
422
|
+
* - augment `ArcModuleRegistry` once — then the name alone infers the type:
|
|
423
|
+
* `getModuleExports(f, "accounting")` → `AccountingEngine`.
|
|
424
|
+
* - or pass it inline: `getModuleExports<AccountingEngine>(f, "accounting")`.
|
|
425
|
+
*/
|
|
426
|
+
declare function getModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): ArcModuleRegistry[K];
|
|
427
|
+
declare function getModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): TExports;
|
|
428
|
+
//#endregion
|
|
429
|
+
export { getModuleExports as a, LoadResourcesOptions as c, loadResources as d, defineModule as i, ResourceLike as l, ArcModuleInput as n, orderModules as o, ArcModuleRegistry as r, resolveModule as s, ArcModule as t, ResourceModule as u };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as getUserRoles } from "./types-XTApa8b6.mjs";
|
|
2
2
|
import { n as convertRouteSchema } from "./schemaConverter-U0MnO9vd.mjs";
|
|
3
|
-
import { t as resolveActionPermission } from "./actionPermissions-
|
|
4
|
-
import { t as pluralize } from "./pluralize-
|
|
5
|
-
import { t as buildActionBodySchema } from "./createActionRouter-
|
|
3
|
+
import { t as resolveActionPermission } from "./actionPermissions-ze70xXJi.mjs";
|
|
4
|
+
import { t as pluralize } from "./pluralize-BhrgwZb9.mjs";
|
|
5
|
+
import { t as buildActionBodySchema } from "./createActionRouter-BWMDW-dL.mjs";
|
|
6
6
|
import fp from "fastify-plugin";
|
|
7
7
|
//#region src/docs/openapi/canonical-schemas.ts
|
|
8
8
|
/**
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as applyFieldWritePermissions, c as PermissionCheck, d as UserBase, f as getUserRoles, i as applyFieldReadPermissions, l as PermissionContext, n as FieldPermissionMap, o as fields, p as normalizeRoles, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission, u as PermissionResult } from "../fields-
|
|
2
|
-
import { A as
|
|
3
|
-
export { type ConnectEventsOptions, type DynamicPermissionMatrix, type DynamicPermissionMatrixConfig, type FieldPermission, type FieldPermissionMap, type FieldPermissionType, type PermissionCheck, type PermissionContext, type PermissionEventBus, type PermissionResult, type RequireAgentScopeOptions, type RequireMandateOptions, type RoleHierarchy, type UserBase, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, presets_d_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
|
|
1
|
+
import { a as applyFieldWritePermissions, c as PermissionCheck, d as UserBase, f as getUserRoles, i as applyFieldReadPermissions, l as PermissionContext, n as FieldPermissionMap, o as fields, p as normalizeRoles, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission, u as PermissionResult } from "../fields-BGqrAa_u.mjs";
|
|
2
|
+
import { A as requireOwnership, B as requireMandate, C as createOrgPermissions, D as denyAll, E as anyOf, F as normalizePermissionResult, I as RequireAgentScopeOptions, L as RequireMandateOptions, M as roles, N as when, O as not, P as applyPermissionResult, R as requireAgentScope, S as createDynamicPermissionMatrix, T as allowPublic, _ as createRoleHierarchy, a as permissionMatrix, b as DynamicPermissionMatrixConfig, c as publicReadAdminWrite, d as requireOrgMembership, f as requireOrgRole, g as RoleHierarchy, h as requireTeamMembership, i as ownerWithAdminBypass, j as requireRoles, k as requireAuth, l as readOnly, m as requireServiceScope, n as authenticated, o as presets_d_exports, p as requireScopeContext, r as fullPublic, s as publicRead, t as adminOnly, u as requireOrgInScope, v as ConnectEventsOptions, w as allOf, x as PermissionEventBus, y as DynamicPermissionMatrix, z as requireDPoP } from "../index-B5PoNbfu.mjs";
|
|
3
|
+
export { type ConnectEventsOptions, type DynamicPermissionMatrix, type DynamicPermissionMatrixConfig, type FieldPermission, type FieldPermissionMap, type FieldPermissionType, type PermissionCheck, type PermissionContext, type PermissionEventBus, type PermissionResult, type RequireAgentScopeOptions, type RequireMandateOptions, type RoleHierarchy, type UserBase, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, permissionMatrix, presets_d_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as requireDPoP, C as not, D as roles, E as requireRoles, F as applyFieldReadPermissions, I as applyFieldWritePermissions, L as fields, M as applyPermissionResult, O as when, P as normalizePermissionResult, R as resolveEffectiveRoles, S as denyAll, T as requireOwnership, _ as requireServiceScope, a as permissionMatrix, b as allowPublic, c as publicReadAdminWrite, d as createDynamicPermissionMatrix, f as createOrgPermissions, g as requireScopeContext, h as requireOrgRole, i as ownerWithAdminBypass, j as requireMandate, k as requireAgentScope, l as readOnly, m as requireOrgMembership, n as authenticated, o as presets_exports, p as requireOrgInScope, r as fullPublic, s as publicRead, t as adminOnly, u as createRoleHierarchy, v as requireTeamMembership, w as requireAuth, x as anyOf, y as allOf } from "../permissions-BJMuKMl7.mjs";
|
|
2
2
|
import { n as normalizeRoles, t as getUserRoles } from "../types-XTApa8b6.mjs";
|
|
3
|
-
export { adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
|
|
3
|
+
export { adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, permissionMatrix, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
|
|
@@ -167,7 +167,7 @@ function applyFieldWritePermissions(body, fieldPermissions, userRoles) {
|
|
|
167
167
|
function resolveEffectiveRoles(userRoles, orgRoles) {
|
|
168
168
|
if (orgRoles.length === 0) return [...userRoles];
|
|
169
169
|
if (userRoles.length === 0) return [...orgRoles];
|
|
170
|
-
return [
|
|
170
|
+
return [.../* @__PURE__ */ new Set([...userRoles, ...orgRoles])];
|
|
171
171
|
}
|
|
172
172
|
//#endregion
|
|
173
173
|
//#region src/permissions/applyPermissionResult.ts
|
|
@@ -1382,6 +1382,7 @@ var presets_exports = /* @__PURE__ */ __exportAll({
|
|
|
1382
1382
|
authenticated: () => authenticated,
|
|
1383
1383
|
fullPublic: () => fullPublic,
|
|
1384
1384
|
ownerWithAdminBypass: () => ownerWithAdminBypass,
|
|
1385
|
+
permissionMatrix: () => permissionMatrix,
|
|
1385
1386
|
publicRead: () => publicRead,
|
|
1386
1387
|
publicReadAdminWrite: () => publicReadAdminWrite,
|
|
1387
1388
|
readOnly: () => readOnly
|
|
@@ -1450,6 +1451,37 @@ function adminOnly(roles = ["admin"], overrides) {
|
|
|
1450
1451
|
}, overrides);
|
|
1451
1452
|
}
|
|
1452
1453
|
/**
|
|
1454
|
+
* Arbitrary-gate CRUD matrix — the generalization every host and arc-*
|
|
1455
|
+
* module hand-rolls as `{ list: view, get: view, create: manage, ... }`.
|
|
1456
|
+
*
|
|
1457
|
+
* Unlike the fixed presets above, the gates are caller-supplied
|
|
1458
|
+
* `PermissionCheck`s, so ANY combinator plugs in — org roles, ownership,
|
|
1459
|
+
* `anyOf(...)`, service scopes, custom async checks. `delete` defaults to
|
|
1460
|
+
* the `write` gate.
|
|
1461
|
+
*
|
|
1462
|
+
* @example
|
|
1463
|
+
* ```typescript
|
|
1464
|
+
* // Two-gate (view/manage) — the arc-* module convention:
|
|
1465
|
+
* permissionMatrix({ read: requireAuth(), write: requireOrgRole('manager') })
|
|
1466
|
+
*
|
|
1467
|
+
* // Three-gate with a stricter delete:
|
|
1468
|
+
* permissionMatrix({
|
|
1469
|
+
* read: allowPublic(),
|
|
1470
|
+
* write: requireOrgRole('manager'),
|
|
1471
|
+
* delete: requireOrgRole('owner'),
|
|
1472
|
+
* })
|
|
1473
|
+
* ```
|
|
1474
|
+
*/
|
|
1475
|
+
function permissionMatrix(gates, overrides) {
|
|
1476
|
+
return withOverrides({
|
|
1477
|
+
list: gates.read,
|
|
1478
|
+
get: gates.read,
|
|
1479
|
+
create: gates.write,
|
|
1480
|
+
update: gates.write,
|
|
1481
|
+
delete: gates.delete ?? gates.write
|
|
1482
|
+
}, overrides);
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1453
1485
|
* Owner-scoped with admin bypass.
|
|
1454
1486
|
* list = auth (scoped to owner), get = auth, create = auth,
|
|
1455
1487
|
* update + delete = ownership check with admin bypass.
|
|
@@ -1482,12 +1514,20 @@ function fullPublic(overrides) {
|
|
|
1482
1514
|
/**
|
|
1483
1515
|
* Read-only: list + get authenticated, write operations denied.
|
|
1484
1516
|
* Useful for computed/derived resources.
|
|
1517
|
+
*
|
|
1518
|
+
* Writes carry an explicit `denyAll` check — an omitted CRUD permission
|
|
1519
|
+
* mounts the route with NO gate (public-by-omission), so leaving
|
|
1520
|
+
* create/update/delete undefined here would expose unauthenticated writes.
|
|
1521
|
+
* Hosts that disable write routes entirely (`disabledRoutes`) are unaffected.
|
|
1485
1522
|
*/
|
|
1486
1523
|
function readOnly(overrides) {
|
|
1487
1524
|
return withOverrides({
|
|
1488
1525
|
list: requireAuth(),
|
|
1489
|
-
get: requireAuth()
|
|
1526
|
+
get: requireAuth(),
|
|
1527
|
+
create: denyAll("Write operations are disabled on this read-only resource"),
|
|
1528
|
+
update: denyAll("Write operations are disabled on this read-only resource"),
|
|
1529
|
+
delete: denyAll("Write operations are disabled on this read-only resource")
|
|
1490
1530
|
}, overrides);
|
|
1491
1531
|
}
|
|
1492
1532
|
//#endregion
|
|
1493
|
-
export {
|
|
1533
|
+
export { requireDPoP as A, not as C, roles as D, requireRoles as E, applyFieldReadPermissions as F, applyFieldWritePermissions as I, fields as L, applyPermissionResult as M, evaluateAndApplyPermission as N, when as O, normalizePermissionResult as P, resolveEffectiveRoles as R, denyAll as S, requireOwnership as T, requireServiceScope as _, permissionMatrix as a, allowPublic as b, publicReadAdminWrite as c, createDynamicPermissionMatrix as d, createOrgPermissions as f, requireScopeContext as g, requireOrgRole as h, ownerWithAdminBypass as i, requireMandate as j, requireAgentScope as k, readOnly as l, requireOrgMembership as m, authenticated as n, presets_exports as o, requireOrgInScope as p, fullPublic as r, publicRead as s, adminOnly as t, createRoleHierarchy as u, requireTeamMembership as v, requireAuth as w, anyOf as x, allOf as y };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Bt as Transform, Ft as NextFunction, It as OperationFilter, Lt as PipelineConfig, Nt as Guard, Pt as Interceptor, Rt as PipelineContext, bt as IControllerResponse, zt as PipelineStep } from "../index-
|
|
2
|
-
|
|
1
|
+
import { Bt as Transform, Ft as NextFunction, It as OperationFilter, Lt as PipelineConfig, Nt as Guard, Pt as Interceptor, Rt as PipelineContext, bt as IControllerResponse, zt as PipelineStep } from "../index-Dtrj6XZk.mjs";
|
|
3
2
|
//#region src/pipeline/guard.d.ts
|
|
4
3
|
interface GuardOptions {
|
|
5
4
|
operations?: OperationFilter;
|