@classytic/arc 2.6.1 → 2.6.2
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 +37 -2
- package/dist/{ResourceRegistry-DeCIFlix.mjs → ResourceRegistry-C6ngvOnn.mjs} +1 -0
- package/dist/adapters/index.d.mts +2 -2
- package/dist/audit/index.d.mts +31 -5
- package/dist/audit/index.mjs +21 -3
- package/dist/auth/index.d.mts +1 -1
- package/dist/cli/commands/docs.mjs +1 -1
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +1 -1
- package/dist/{createApp-Bol7DLUf.mjs → createApp-D2w0LdYJ.mjs} +27 -11
- package/dist/{defineResource-bVKHjQzE.mjs → defineResource-Ckxg6HrZ.mjs} +9 -3
- package/dist/docs/index.d.mts +1 -1
- package/dist/dynamic/index.d.mts +1 -1
- package/dist/dynamic/index.mjs +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +31 -15
- package/dist/hooks/index.d.mts +1 -1
- package/dist/{index-Cb3gtbg7.d.mts → index-B4uZm82R.d.mts} +1 -1
- package/dist/{index-BIsZ_su5.d.mts → index-DrCqa3Jq.d.mts} +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +2 -2
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +2 -2
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/{interface-DDW43OmS.d.mts → interface-CrN45qz1.d.mts} +35 -0
- package/dist/org/index.d.mts +1 -1
- package/dist/plugins/index.d.mts +1 -1
- package/dist/plugins/index.mjs +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +1 -1
- package/dist/testing/index.d.mts +26 -3
- package/dist/testing/index.mjs +46 -2
- package/dist/types/index.d.mts +1 -1
- package/dist/{types-D5hJ-k_3.d.mts → types-C1Z28coa.d.mts} +7 -1
- package/dist/{types-D5rjsS_i.d.mts → types-DurlBP2N.d.mts} +1 -1
- package/dist/utils/index.d.mts +1 -1
- package/package.json +1 -1
- package/skills/arc/SKILL.md +55 -8
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ Three ways to register resources:
|
|
|
34
34
|
|
|
35
35
|
```typescript
|
|
36
36
|
// Auto-discover from directory (recommended)
|
|
37
|
-
resources: await loadResources(
|
|
37
|
+
resources: await loadResources(import.meta.url), // dev/prod parity
|
|
38
38
|
|
|
39
39
|
// Explicit array
|
|
40
40
|
resources: [productResource, orderResource],
|
|
@@ -43,7 +43,42 @@ resources: [productResource, orderResource],
|
|
|
43
43
|
plugins: async (f) => { await f.register(productResource.toPlugin()); },
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
`loadResources()` discovers `default` exports, `export const resource`, OR any named export with `toPlugin()` (e.g. `export const userResource`). Per-resource opt-out of `resourcePrefix` via `skipGlobalPrefix: true` for webhooks/admin routes.
|
|
47
|
+
|
|
48
|
+
> **Import compatibility:** Works with relative imports and Node.js `#` subpath imports. Does **not** support tsconfig path aliases (`@/*`, `~/`) — use explicit `resources: [...]` instead.
|
|
49
|
+
|
|
50
|
+
## Boot Sequence
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
const app = await createApp({
|
|
54
|
+
resourcePrefix: '/api/v1',
|
|
55
|
+
plugins: async (f) => { await connectDB(); }, // 1. infra (DB, docs)
|
|
56
|
+
bootstrap: [inventoryInit, accountingInit], // 2. domain init
|
|
57
|
+
resources: await loadResources(import.meta.url), // 3. routes
|
|
58
|
+
afterResources: async (f) => { subscribeEvents(f); }, // 4. post-wiring
|
|
59
|
+
onReady: async (f) => { logger.info('ready'); },
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Audit (per-resource opt-in)
|
|
64
|
+
|
|
65
|
+
Clean DX without growing exclude lists:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// app.ts — register once with perResource mode
|
|
69
|
+
await fastify.register(auditPlugin, { autoAudit: { perResource: true } });
|
|
70
|
+
|
|
71
|
+
// order.resource.ts — opt in
|
|
72
|
+
defineResource({ name: 'order', audit: true });
|
|
73
|
+
|
|
74
|
+
// payment.resource.ts — only audit deletes
|
|
75
|
+
defineResource({ name: 'payment', audit: { operations: ['delete'] } });
|
|
76
|
+
|
|
77
|
+
// Manual logging from MCP tools or custom routes
|
|
78
|
+
app.post('/orders/:id/refund', async (req) => {
|
|
79
|
+
await app.audit.custom('order', req.params.id, 'refund', { reason }, { user });
|
|
80
|
+
});
|
|
81
|
+
```
|
|
47
82
|
|
|
48
83
|
## defineResource
|
|
49
84
|
|
|
@@ -51,6 +51,7 @@ var ResourceRegistry = class {
|
|
|
51
51
|
fieldPermissions: extractFieldPermissions(resource.fields),
|
|
52
52
|
pipelineSteps: extractPipelineSteps(resource.pipe),
|
|
53
53
|
rateLimit: resource.rateLimit,
|
|
54
|
+
audit: resource.audit,
|
|
54
55
|
plugin: resource.toPlugin()
|
|
55
56
|
};
|
|
56
57
|
this._resources.set(resource.name, entry);
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as RepositoryLike, i as RelationMetadata, n as DataAdapter, o as SchemaMetadata, r as FieldMetadata, s as ValidationResult, t as AdapterFactory } from "../interface-
|
|
2
|
-
import { a as PrismaQueryParserOptions, c as MongooseAdapterOptions, i as PrismaQueryParser, l as createMongooseAdapter, n as PrismaAdapterOptions, o as createPrismaAdapter, r as PrismaQueryOptions, s as MongooseAdapter, t as PrismaAdapter } from "../index-
|
|
1
|
+
import { a as RepositoryLike, i as RelationMetadata, n as DataAdapter, o as SchemaMetadata, r as FieldMetadata, s as ValidationResult, t as AdapterFactory } from "../interface-CrN45qz1.mjs";
|
|
2
|
+
import { a as PrismaQueryParserOptions, c as MongooseAdapterOptions, i as PrismaQueryParser, l as createMongooseAdapter, n as PrismaAdapterOptions, o as createPrismaAdapter, r as PrismaQueryOptions, s as MongooseAdapter, t as PrismaAdapter } from "../index-DrCqa3Jq.mjs";
|
|
3
3
|
export { AdapterFactory, DataAdapter, FieldMetadata, MongooseAdapter, MongooseAdapterOptions, PrismaAdapter, PrismaAdapterOptions, PrismaQueryOptions, PrismaQueryParser, PrismaQueryParserOptions, RelationMetadata, RepositoryLike, SchemaMetadata, ValidationResult, createMongooseAdapter, createPrismaAdapter };
|
package/dist/audit/index.d.mts
CHANGED
|
@@ -19,14 +19,40 @@ interface AuditPluginOptions {
|
|
|
19
19
|
* Automatically audit CRUD operations via the hook system (default: true when enabled).
|
|
20
20
|
* When enabled, create/update/delete operations are auto-logged without manual calls.
|
|
21
21
|
*
|
|
22
|
-
* -
|
|
23
|
-
*
|
|
24
|
-
* -
|
|
25
|
-
*
|
|
22
|
+
* **Three opt-in patterns** — pick the one that matches your app:
|
|
23
|
+
*
|
|
24
|
+
* 1. **Per-resource opt-in (recommended for most apps)** — set `audit: true` on each
|
|
25
|
+
* resource. Audit only fires for those resources. No global `include`/`exclude` needed.
|
|
26
|
+
* ```ts
|
|
27
|
+
* defineResource({ name: 'order', audit: true });
|
|
28
|
+
* // auditPlugin auto-detects which resources opted in
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* 2. **Allowlist mode** — set `include: ['order', 'invoice']` for centralized config.
|
|
32
|
+
* Only listed resources are audited.
|
|
33
|
+
*
|
|
34
|
+
* 3. **Denylist mode** — set `exclude: ['health', 'metrics']` to audit everything except
|
|
35
|
+
* listed resources. Use sparingly — leads to growing exclude lists.
|
|
36
|
+
*
|
|
37
|
+
* Default behavior (`autoAudit: true`): denylist mode with no exclusions (audit everything).
|
|
38
|
+
* For most apps, switching to per-resource opt-in is cleaner.
|
|
39
|
+
*
|
|
40
|
+
* - `true`: Audit all CRUD operations on all resources (legacy default)
|
|
41
|
+
* - `{ operations: ['create', 'delete'] }`: Only specific operations
|
|
42
|
+
* - `{ include: ['order'] }`: Allowlist — only listed resources
|
|
43
|
+
* - `{ exclude: ['health'] }`: Denylist — all except listed
|
|
44
|
+
* - `{ perResource: true }`: Only resources with `audit: true` in their definition
|
|
45
|
+
* - `false`: Disable auto-audit (manual `fastify.audit.*()` calls only)
|
|
26
46
|
*/
|
|
27
47
|
autoAudit?: boolean | {
|
|
28
|
-
operations?: ("create" | "update" | "delete")[];
|
|
48
|
+
operations?: ("create" | "update" | "delete")[]; /** Allowlist — only listed resources are audited (mutually exclusive with exclude) */
|
|
49
|
+
include?: string[]; /** Denylist — audit everything except listed resources */
|
|
29
50
|
exclude?: string[];
|
|
51
|
+
/**
|
|
52
|
+
* Per-resource opt-in mode: only audit resources with `audit: true` in their
|
|
53
|
+
* `defineResource()` config. The cleanest pattern for most apps.
|
|
54
|
+
*/
|
|
55
|
+
perResource?: boolean;
|
|
30
56
|
};
|
|
31
57
|
}
|
|
32
58
|
declare module "fastify" {
|
package/dist/audit/index.mjs
CHANGED
|
@@ -180,16 +180,34 @@ const auditPlugin = async (fastify, opts = {}) => {
|
|
|
180
180
|
"update",
|
|
181
181
|
"delete"
|
|
182
182
|
];
|
|
183
|
-
const
|
|
184
|
-
const
|
|
183
|
+
const isObj = typeof autoAuditConfig === "object";
|
|
184
|
+
const ops = isObj ? autoAuditConfig.operations ?? defaultOps : defaultOps;
|
|
185
|
+
const includeResources = isObj && autoAuditConfig.include ? new Set(autoAuditConfig.include) : null;
|
|
186
|
+
const excludeResources = new Set(isObj ? autoAuditConfig.exclude ?? [] : []);
|
|
187
|
+
const perResourceMode = isObj ? autoAuditConfig.perResource === true : false;
|
|
188
|
+
if (includeResources && excludeResources.size > 0) fastify.log?.warn?.("Audit autoAudit: both 'include' and 'exclude' specified. Using 'include' (allowlist wins).");
|
|
185
189
|
fastify.addHook("onReady", async () => {
|
|
186
190
|
const arc = "arc" in fastify ? fastify.arc : void 0;
|
|
187
191
|
if (!arc?.hooks) {
|
|
188
192
|
fastify.log?.debug?.("Auto-audit skipped: arc-core plugin not registered");
|
|
189
193
|
return;
|
|
190
194
|
}
|
|
195
|
+
const optedInResources = /* @__PURE__ */ new Set();
|
|
196
|
+
const operationsByResource = /* @__PURE__ */ new Map();
|
|
197
|
+
if (perResourceMode && arc.registry) for (const entry of arc.registry.getAll()) {
|
|
198
|
+
const auditFlag = entry.audit;
|
|
199
|
+
if (!auditFlag) continue;
|
|
200
|
+
optedInResources.add(entry.name);
|
|
201
|
+
if (typeof auditFlag === "object" && auditFlag.operations) operationsByResource.set(entry.name, auditFlag.operations);
|
|
202
|
+
}
|
|
191
203
|
for (const op of ops) arc.hooks.after("*", op, async (ctx) => {
|
|
192
|
-
if (
|
|
204
|
+
if (perResourceMode) {
|
|
205
|
+
if (!optedInResources.has(ctx.resource)) return;
|
|
206
|
+
const allowedOps = operationsByResource.get(ctx.resource);
|
|
207
|
+
if (allowedOps && !allowedOps.includes(op)) return;
|
|
208
|
+
} else if (includeResources) {
|
|
209
|
+
if (!includeResources.has(ctx.resource)) return;
|
|
210
|
+
} else if (excludeResources.has(ctx.resource)) return;
|
|
193
211
|
const docId = autoAuditExtractId(ctx.result);
|
|
194
212
|
const scope = ctx.context?._scope;
|
|
195
213
|
const auditCtx = {
|
package/dist/auth/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h as AuthPluginOptions, m as AuthHelpers } from "../interface-
|
|
1
|
+
import { h as AuthPluginOptions, m as AuthHelpers } from "../interface-CrN45qz1.mjs";
|
|
2
2
|
import { t as PermissionCheck } from "../types-BNUccdcf.mjs";
|
|
3
3
|
import { t as ExternalOpenApiPaths } from "../externalPaths-DpO-s7r8.mjs";
|
|
4
4
|
import { a as SessionManagerOptions, c as createSessionManager, i as SessionData, n as MemorySessionStoreOptions, o as SessionManagerResult, r as SessionCookieOptions, s as SessionStore, t as MemorySessionStore } from "../sessionManager-wbkYj2HL.mjs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as ResourceRegistry } from "../../ResourceRegistry-
|
|
1
|
+
import { t as ResourceRegistry } from "../../ResourceRegistry-C6ngvOnn.mjs";
|
|
2
2
|
import { t as buildOpenApiSpec } from "../../openapi-CBmZ6EQN.mjs";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as ResourceRegistry } from "../../ResourceRegistry-
|
|
1
|
+
import { t as ResourceRegistry } from "../../ResourceRegistry-C6ngvOnn.mjs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
//#region src/cli/commands/introspect.ts
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { At as AccessControlConfig, Bt as ResourceDefinition, Ct as BaseController, Dt as BodySanitizer, Et as QueryResolverConfig, Ot as BodySanitizerConfig, Tt as QueryResolver, Vt as defineResource, kt as AccessControl, wt as BaseControllerOptions } from "../interface-
|
|
2
|
-
import { A as RESERVED_QUERY_PARAMS, C as HookOperation, D as MAX_SEARCH_LENGTH, E as MAX_REGEX_LENGTH, O as MUTATION_OPERATIONS, S as HOOK_PHASES, T as MAX_FILTER_DEPTH, _ as DEFAULT_MAX_LIMIT, a as getControllerScope, b as DEFAULT_UPDATE_METHOD, c as createPermissionMiddleware, d as IdempotencyService, f as createActionRouter, g as DEFAULT_LIMIT, h as DEFAULT_ID_FIELD, i as getControllerContext, j as SYSTEM_FIELDS, k as MutationOperation, l as ActionHandler, m as CrudOperation, n as createFastifyHandler, o as sendControllerResponse, p as CRUD_OPERATIONS, r as createRequestContext, s as createCrudRouter, t as createCrudHandlers, u as ActionRouterConfig, v as DEFAULT_SORT, w as HookPhase, x as HOOK_OPERATIONS, y as DEFAULT_TENANT_FIELD } from "../index-
|
|
1
|
+
import { At as AccessControlConfig, Bt as ResourceDefinition, Ct as BaseController, Dt as BodySanitizer, Et as QueryResolverConfig, Ot as BodySanitizerConfig, Tt as QueryResolver, Vt as defineResource, kt as AccessControl, wt as BaseControllerOptions } from "../interface-CrN45qz1.mjs";
|
|
2
|
+
import { A as RESERVED_QUERY_PARAMS, C as HookOperation, D as MAX_SEARCH_LENGTH, E as MAX_REGEX_LENGTH, O as MUTATION_OPERATIONS, S as HOOK_PHASES, T as MAX_FILTER_DEPTH, _ as DEFAULT_MAX_LIMIT, a as getControllerScope, b as DEFAULT_UPDATE_METHOD, c as createPermissionMiddleware, d as IdempotencyService, f as createActionRouter, g as DEFAULT_LIMIT, h as DEFAULT_ID_FIELD, i as getControllerContext, j as SYSTEM_FIELDS, k as MutationOperation, l as ActionHandler, m as CrudOperation, n as createFastifyHandler, o as sendControllerResponse, p as CRUD_OPERATIONS, r as createRequestContext, s as createCrudRouter, t as createCrudHandlers, u as ActionRouterConfig, v as DEFAULT_SORT, w as HookPhase, x as HOOK_OPERATIONS, y as DEFAULT_TENANT_FIELD } from "../index-B4uZm82R.mjs";
|
|
3
3
|
export { AccessControl, AccessControlConfig, ActionHandler, ActionRouterConfig, BaseController, BaseControllerOptions, BodySanitizer, BodySanitizerConfig, CRUD_OPERATIONS, CrudOperation, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, HookOperation, HookPhase, IdempotencyService, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, getControllerContext, getControllerScope, sendControllerResponse };
|
package/dist/core/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-Cxde4rpC.mjs";
|
|
2
2
|
import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-AbbRx3e0.mjs";
|
|
3
3
|
import { t as createActionRouter } from "../core-C1XCMtqM.mjs";
|
|
4
|
-
import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-
|
|
4
|
+
import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-Ckxg6HrZ.mjs";
|
|
5
5
|
export { AccessControl, BaseController, BodySanitizer, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, getControllerContext, getControllerScope, sendControllerResponse };
|
|
@@ -66,20 +66,36 @@ const productionPreset = {
|
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
68
|
/**
|
|
69
|
+
* Try to detect if `pino-pretty` is installed (devDep). Returns the transport
|
|
70
|
+
* config if available, or falls back to plain JSON logging. This prevents the
|
|
71
|
+
* common "pino-pretty not found" crash in production when someone uses the
|
|
72
|
+
* development preset by mistake (or via NODE_ENV-based preset selection).
|
|
73
|
+
*/
|
|
74
|
+
function devLoggerConfig() {
|
|
75
|
+
try {
|
|
76
|
+
const req = eval("require") ?? null;
|
|
77
|
+
if (req?.resolve) {
|
|
78
|
+
req.resolve("pino-pretty");
|
|
79
|
+
return {
|
|
80
|
+
level: "debug",
|
|
81
|
+
transport: {
|
|
82
|
+
target: "pino-pretty",
|
|
83
|
+
options: {
|
|
84
|
+
colorize: true,
|
|
85
|
+
translateTime: "SYS:HH:MM:ss",
|
|
86
|
+
ignore: "pid,hostname"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
} catch {}
|
|
92
|
+
return { level: "debug" };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
69
95
|
* Development preset - relaxed security, verbose logging
|
|
70
96
|
*/
|
|
71
97
|
const developmentPreset = {
|
|
72
|
-
logger:
|
|
73
|
-
level: "debug",
|
|
74
|
-
transport: {
|
|
75
|
-
target: "pino-pretty",
|
|
76
|
-
options: {
|
|
77
|
-
colorize: true,
|
|
78
|
-
translateTime: "SYS:HH:MM:ss",
|
|
79
|
-
ignore: "pid,hostname"
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
},
|
|
98
|
+
logger: devLoggerConfig(),
|
|
83
99
|
trustProxy: true,
|
|
84
100
|
helmet: { contentSecurityPolicy: false },
|
|
85
101
|
cors: {
|
|
@@ -1013,19 +1013,23 @@ function defineResource(config) {
|
|
|
1013
1013
|
resource._pendingHooks.push(...inlineHooks);
|
|
1014
1014
|
}
|
|
1015
1015
|
if (!config.skipRegistry) try {
|
|
1016
|
-
let openApiSchemas
|
|
1017
|
-
if (
|
|
1016
|
+
let openApiSchemas;
|
|
1017
|
+
if (config.adapter?.generateSchemas) {
|
|
1018
1018
|
const generated = config.adapter.generateSchemas(config.schemaOptions);
|
|
1019
1019
|
if (generated) openApiSchemas = generated;
|
|
1020
1020
|
}
|
|
1021
1021
|
const queryParser = config.queryParser;
|
|
1022
|
-
if (
|
|
1022
|
+
if (queryParser?.getQuerySchema) {
|
|
1023
1023
|
const querySchema = queryParser.getQuerySchema();
|
|
1024
1024
|
if (querySchema) openApiSchemas = {
|
|
1025
1025
|
...openApiSchemas,
|
|
1026
1026
|
listQuery: querySchema
|
|
1027
1027
|
};
|
|
1028
1028
|
}
|
|
1029
|
+
if (config.openApiSchemas) openApiSchemas = {
|
|
1030
|
+
...openApiSchemas,
|
|
1031
|
+
...config.openApiSchemas
|
|
1032
|
+
};
|
|
1029
1033
|
if (openApiSchemas) openApiSchemas = convertOpenApiSchemas(openApiSchemas);
|
|
1030
1034
|
resource._registryMeta = {
|
|
1031
1035
|
module: config.module,
|
|
@@ -1050,6 +1054,7 @@ var ResourceDefinition = class {
|
|
|
1050
1054
|
disabledRoutes;
|
|
1051
1055
|
events;
|
|
1052
1056
|
rateLimit;
|
|
1057
|
+
audit;
|
|
1053
1058
|
updateMethod;
|
|
1054
1059
|
pipe;
|
|
1055
1060
|
fields;
|
|
@@ -1078,6 +1083,7 @@ var ResourceDefinition = class {
|
|
|
1078
1083
|
this.disabledRoutes = config.disabledRoutes ?? [];
|
|
1079
1084
|
this.events = config.events ?? {};
|
|
1080
1085
|
this.rateLimit = config.rateLimit;
|
|
1086
|
+
this.audit = config.audit;
|
|
1081
1087
|
this.updateMethod = config.updateMethod;
|
|
1082
1088
|
this.pipe = config.pipe;
|
|
1083
1089
|
this.fields = config.fields;
|
package/dist/docs/index.d.mts
CHANGED
package/dist/dynamic/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bt as ResourceDefinition, n as DataAdapter } from "../interface-
|
|
1
|
+
import { Bt as ResourceDefinition, n as DataAdapter } from "../interface-CrN45qz1.mjs";
|
|
2
2
|
import { t as PermissionCheck } from "../types-BNUccdcf.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/dynamic/ArcDynamicLoader.d.ts
|
package/dist/dynamic/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as ArcQueryParser } from "../queryParser-CgCtsjti.mjs";
|
|
2
|
-
import { n as defineResource } from "../defineResource-
|
|
2
|
+
import { n as defineResource } from "../defineResource-Ckxg6HrZ.mjs";
|
|
3
3
|
import { S as readOnly, _ as fullPublic, b as publicRead, g as authenticated, h as adminOnly, v as ownerWithAdminBypass, x as publicReadAdminWrite } from "../permissions-C8ImI8gC.mjs";
|
|
4
4
|
//#region src/dynamic/ArcDynamicLoader.ts
|
|
5
5
|
const VALID_FIELD_TYPES = new Set([
|
package/dist/factory/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CustomPluginAuthOption, c as RawBodyOptions, d as ResourceLike, f as loadResources, i as CustomAuthenticatorOption, l as UnderPressureOptions, n as BetterAuthOption, o as JwtAuthOption, r as CreateAppOptions, s as MultipartOptions, t as AuthOption, u as LoadResourcesOptions } from "../types-
|
|
1
|
+
import { a as CustomPluginAuthOption, c as RawBodyOptions, d as ResourceLike, f as loadResources, i as CustomAuthenticatorOption, l as UnderPressureOptions, n as BetterAuthOption, o as JwtAuthOption, r as CreateAppOptions, s as MultipartOptions, t as AuthOption, u as LoadResourcesOptions } from "../types-C1Z28coa.mjs";
|
|
2
2
|
import { FastifyInstance } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/factory/createApp.d.ts
|
package/dist/factory/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as edgePreset, c as testingPreset, i as developmentPreset, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory } from "../createApp-
|
|
1
|
+
import { a as edgePreset, c as testingPreset, i as developmentPreset, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory } from "../createApp-D2w0LdYJ.mjs";
|
|
2
2
|
import { readdir } from "node:fs/promises";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -110,32 +110,48 @@ async function loadResources(dir, options = {}) {
|
|
|
110
110
|
const excludeSet = exclude ? new Set(exclude) : null;
|
|
111
111
|
const skipped = [];
|
|
112
112
|
const failed = [];
|
|
113
|
+
const isWindowsPath = (p) => /^[a-z]:[\\/]/i.test(p);
|
|
113
114
|
const results = await Promise.all(files.map(async (file) => {
|
|
115
|
+
let mod;
|
|
116
|
+
let primaryError;
|
|
114
117
|
try {
|
|
115
|
-
|
|
116
|
-
try {
|
|
117
|
-
mod = await import(pathToFileURL(file).href);
|
|
118
|
-
} catch (_importErr) {
|
|
119
|
-
mod = await import(file);
|
|
120
|
-
}
|
|
118
|
+
mod = await import(pathToFileURL(file).href);
|
|
121
119
|
return {
|
|
122
120
|
file,
|
|
123
121
|
mod
|
|
124
122
|
};
|
|
125
123
|
} catch (err) {
|
|
126
|
-
|
|
127
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
128
|
-
if (code === "ERR_MODULE_NOT_FOUND" && msg.includes(".js")) failed.push(`${file}: ${msg}\n Hint: This file uses .js extension imports (TypeScript ESM convention).
|
|
129
|
-
In production, ensure your build compiles .ts→.js before loadResources() runs.
|
|
130
|
-
In tests, use vitest/tsx which resolves .js→.ts automatically.`);
|
|
131
|
-
else failed.push(`${file}: ${msg}`);
|
|
132
|
-
return null;
|
|
124
|
+
primaryError = err;
|
|
133
125
|
}
|
|
126
|
+
if (!isWindowsPath(file)) try {
|
|
127
|
+
mod = await import(file);
|
|
128
|
+
return {
|
|
129
|
+
file,
|
|
130
|
+
mod
|
|
131
|
+
};
|
|
132
|
+
} catch {}
|
|
133
|
+
const err = primaryError;
|
|
134
|
+
const code = err.code;
|
|
135
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
136
|
+
if (code === "ERR_MODULE_NOT_FOUND" && msg.includes(".js")) failed.push(`${file}: ${msg}\n Hint: This file uses .js extension imports (TypeScript ESM convention).
|
|
137
|
+
• Production: ensure your build compiles .ts→.js before loadResources() runs.
|
|
138
|
+
• Node.js: use tsx, ts-node/esm, or a build step.
|
|
139
|
+
• Vitest: nested .js→.ts resolution may fail through dynamic imports.
|
|
140
|
+
Workaround: use import.meta.glob to preload resources statically.
|
|
141
|
+
See: https://github.com/classytic/arc/blob/main/docs/production-ops/factory.mdx#vitest-limitation`);
|
|
142
|
+
else failed.push(`${file}: ${msg}`);
|
|
143
|
+
return null;
|
|
134
144
|
}));
|
|
135
145
|
const resources = [];
|
|
136
146
|
for (const result of results) {
|
|
137
147
|
if (!result) continue;
|
|
138
|
-
|
|
148
|
+
let resource = result.mod.default ?? result.mod.resource;
|
|
149
|
+
if (!resource || typeof resource.toPlugin !== "function") {
|
|
150
|
+
for (const value of Object.values(result.mod)) if (value && typeof value === "object" && typeof value.toPlugin === "function") {
|
|
151
|
+
resource = value;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
139
155
|
if (!resource || typeof resource.toPlugin !== "function") {
|
|
140
156
|
skipped.push(result.file);
|
|
141
157
|
continue;
|
package/dist/hooks/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { an as HookPhase, cn as HookSystemOptions, dn as afterUpdate, fn as beforeCreate, gn as defineHook, hn as createHookSystem, in as HookOperation, ln as afterCreate, mn as beforeUpdate, nn as HookContext, on as HookRegistration, pn as beforeDelete, rn as HookHandler, sn as HookSystem, tn as DefineHookOptions, un as afterDelete } from "../interface-
|
|
1
|
+
import { an as HookPhase, cn as HookSystemOptions, dn as afterUpdate, fn as beforeCreate, gn as defineHook, hn as createHookSystem, in as HookOperation, ln as afterCreate, mn as beforeUpdate, nn as HookContext, on as HookRegistration, pn as beforeDelete, rn as HookHandler, sn as HookSystem, tn as DefineHookOptions, un as afterDelete } from "../interface-CrN45qz1.mjs";
|
|
2
2
|
export { type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { s as RequestScope } from "./elevation-C_taLQrM.mjs";
|
|
2
|
-
import { Ft as IControllerResponse, It as IRequestContext, O as FastifyWithDecorators, Pt as IController, S as CrudRouterOptions, b as CrudController, rt as RequestWithExtras, tt as RequestContext } from "./interface-
|
|
2
|
+
import { Ft as IControllerResponse, It as IRequestContext, O as FastifyWithDecorators, Pt as IController, S as CrudRouterOptions, b as CrudController, rt as RequestWithExtras, tt as RequestContext } from "./interface-CrN45qz1.mjs";
|
|
3
3
|
import { t as PermissionCheck } from "./types-BNUccdcf.mjs";
|
|
4
4
|
import { FastifyInstance, FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
|
|
5
5
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ht as CrudRepository, K as ParsedQuery, W as OpenApiSchemas, Z as QueryParserInterface, a as RepositoryLike, dt as RouteSchemaOptions, n as DataAdapter, o as SchemaMetadata, s as ValidationResult } from "./interface-
|
|
1
|
+
import { Ht as CrudRepository, K as ParsedQuery, W as OpenApiSchemas, Z as QueryParserInterface, a as RepositoryLike, dt as RouteSchemaOptions, n as DataAdapter, o as SchemaMetadata, s as ValidationResult } from "./interface-CrN45qz1.mjs";
|
|
2
2
|
import { Model } from "mongoose";
|
|
3
3
|
|
|
4
4
|
//#region src/adapters/mongoose.d.ts
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { $ as RegistryEntry, $t as PipelineStep, A as GracefulShutdownOptions, Bt as ResourceDefinition, C as CrudSchemas, Ct as BaseController, D as FastifyWithAuth, E as FastifyRequestExtras, F as InferResourceDoc, Ft as IControllerResponse, G as OwnershipCheck, H as MiddlewareHandler, Ht as CrudRepository, I as IntrospectionData, It as IRequestContext, J as PresetFunction, Jt as Interceptor, Kt as QueryOptions, L as IntrospectionPluginOptions, Lt as RouteHandler, M as HealthOptions, Mt as ControllerLike, N as InferAdapterDoc, O as FastifyWithDecorators, P as InferDocType, Pt as IController, Q as RateLimitConfig, Qt as PipelineContext, R as JWTPayload, S as CrudRouterOptions, V as MiddlewareConfig, Vt as defineResource, Wt as PaginatedResult, X as PresetResult, Xt as OperationFilter, Yt as NextFunction, Zt as PipelineConfig, a as RepositoryLike, at as ResourceConfig, b as CrudController, bt as ValidationResult$1, c as AdditionalRoute, ct as ResourceMetadata, dt as RouteSchemaOptions, en as Transform, et as RegistryStats, f as ArcInternalMetadata, ft as ServiceContext, gt as TypedResourceConfig, h as AuthPluginOptions, ht as TypedRepository, i as RelationMetadata, j as HealthCheck, k as FieldRule, l as AnyRecord, mt as TypedController, n as DataAdapter, nt as RequestIdOptions, o as SchemaMetadata, p as ArcRequest, qt as Guard, r as FieldMetadata, rt as RequestWithExtras, s as ValidationResult, tt as RequestContext, u as ApiResponse, ut as RouteHandlerMethod, v as ConfigError, vt as UserOrganization, w as EventDefinition, wt as BaseControllerOptions, x as CrudRouteKey, xt as envelope, yt as ValidateOptions } from "./interface-
|
|
1
|
+
import { $ as RegistryEntry, $t as PipelineStep, A as GracefulShutdownOptions, Bt as ResourceDefinition, C as CrudSchemas, Ct as BaseController, D as FastifyWithAuth, E as FastifyRequestExtras, F as InferResourceDoc, Ft as IControllerResponse, G as OwnershipCheck, H as MiddlewareHandler, Ht as CrudRepository, I as IntrospectionData, It as IRequestContext, J as PresetFunction, Jt as Interceptor, Kt as QueryOptions, L as IntrospectionPluginOptions, Lt as RouteHandler, M as HealthOptions, Mt as ControllerLike, N as InferAdapterDoc, O as FastifyWithDecorators, P as InferDocType, Pt as IController, Q as RateLimitConfig, Qt as PipelineContext, R as JWTPayload, S as CrudRouterOptions, V as MiddlewareConfig, Vt as defineResource, Wt as PaginatedResult, X as PresetResult, Xt as OperationFilter, Yt as NextFunction, Zt as PipelineConfig, a as RepositoryLike, at as ResourceConfig, b as CrudController, bt as ValidationResult$1, c as AdditionalRoute, ct as ResourceMetadata, dt as RouteSchemaOptions, en as Transform, et as RegistryStats, f as ArcInternalMetadata, ft as ServiceContext, gt as TypedResourceConfig, h as AuthPluginOptions, ht as TypedRepository, i as RelationMetadata, j as HealthCheck, k as FieldRule, l as AnyRecord, mt as TypedController, n as DataAdapter, nt as RequestIdOptions, o as SchemaMetadata, p as ArcRequest, qt as Guard, r as FieldMetadata, rt as RequestWithExtras, s as ValidationResult, tt as RequestContext, u as ApiResponse, ut as RouteHandlerMethod, v as ConfigError, vt as UserOrganization, w as EventDefinition, wt as BaseControllerOptions, x as CrudRouteKey, xt as envelope, yt as ValidateOptions } from "./interface-CrN45qz1.mjs";
|
|
2
2
|
import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, t as FieldPermission } from "./fields-DFwdaWCq.mjs";
|
|
3
3
|
import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "./types-BNUccdcf.mjs";
|
|
4
|
-
import { l as createMongooseAdapter, o as createPrismaAdapter, s as MongooseAdapter, t as PrismaAdapter } from "./index-
|
|
5
|
-
import { A as RESERVED_QUERY_PARAMS, C as HookOperation, D as MAX_SEARCH_LENGTH, E as MAX_REGEX_LENGTH, O as MUTATION_OPERATIONS, S as HOOK_PHASES, T as MAX_FILTER_DEPTH, _ as DEFAULT_MAX_LIMIT, a as getControllerScope, b as DEFAULT_UPDATE_METHOD, g as DEFAULT_LIMIT, h as DEFAULT_ID_FIELD, j as SYSTEM_FIELDS, k as MutationOperation, m as CrudOperation, p as CRUD_OPERATIONS, v as DEFAULT_SORT, w as HookPhase, x as HOOK_OPERATIONS, y as DEFAULT_TENANT_FIELD } from "./index-
|
|
4
|
+
import { l as createMongooseAdapter, o as createPrismaAdapter, s as MongooseAdapter, t as PrismaAdapter } from "./index-DrCqa3Jq.mjs";
|
|
5
|
+
import { A as RESERVED_QUERY_PARAMS, C as HookOperation, D as MAX_SEARCH_LENGTH, E as MAX_REGEX_LENGTH, O as MUTATION_OPERATIONS, S as HOOK_PHASES, T as MAX_FILTER_DEPTH, _ as DEFAULT_MAX_LIMIT, a as getControllerScope, b as DEFAULT_UPDATE_METHOD, g as DEFAULT_LIMIT, h as DEFAULT_ID_FIELD, j as SYSTEM_FIELDS, k as MutationOperation, m as CrudOperation, p as CRUD_OPERATIONS, v as DEFAULT_SORT, w as HookPhase, x as HOOK_OPERATIONS, y as DEFAULT_TENANT_FIELD } from "./index-B4uZm82R.mjs";
|
|
6
6
|
import { C as presets_d_exports, E as readOnly, S as ownerWithAdminBypass, T as publicReadAdminWrite, a as allOf, b as authenticated, c as createDynamicPermissionMatrix, d as requireAuth, f as requireOrgMembership, g as requireTeamMembership, h as requireRoles, l as createOrgPermissions, m as requireOwnership, n as DynamicPermissionMatrix, o as allowPublic, p as requireOrgRole, r as DynamicPermissionMatrixConfig, s as anyOf, u as denyAll, v as when, w as publicRead, x as fullPublic, y as adminOnly } from "./index-NGZksqM5.mjs";
|
|
7
7
|
import { a as NotFoundError, d as ValidationError, f as createDomainError, i as ForbiddenError, t as ArcError, u as UnauthorizedError } from "./errors-CcVbl1-T.mjs";
|
|
8
8
|
import { AsyncLocalStorage } from "node:async_hooks";
|
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { envelope } from "./types/index.mjs";
|
|
|
5
5
|
import { n as applyFieldWritePermissions, r as fields, t as applyFieldReadPermissions } from "./fields-ipsbIRPK.mjs";
|
|
6
6
|
import { t as requestContext } from "./requestContext-DYtmNpm5.mjs";
|
|
7
7
|
import { d as createDomainError, i as NotFoundError, l as UnauthorizedError, r as ForbiddenError, t as ArcError, u as ValidationError } from "./errors-NoQKsbAT.mjs";
|
|
8
|
-
import { a as validateResourceConfig, f as getControllerScope, i as formatValidationErrors, m as pipe, n as defineResource, r as assertValidConfig, t as ResourceDefinition } from "./defineResource-
|
|
8
|
+
import { a as validateResourceConfig, f as getControllerScope, i as formatValidationErrors, m as pipe, n as defineResource, r as assertValidConfig, t as ResourceDefinition } from "./defineResource-Ckxg6HrZ.mjs";
|
|
9
9
|
import { S as readOnly, _ as fullPublic, a as createOrgPermissions, b as publicRead, c as requireOrgMembership, d as requireRoles, f as requireTeamMembership, g as authenticated, h as adminOnly, i as createDynamicPermissionMatrix, l as requireOrgRole, m as when, n as allowPublic, o as denyAll, r as anyOf, s as requireAuth, t as allOf, u as requireOwnership, v as ownerWithAdminBypass, x as publicReadAdminWrite, y as presets_exports } from "./permissions-C8ImI8gC.mjs";
|
|
10
10
|
import { n as configureArcLogger, t as arcLog } from "./logger-Dz3j1ItV.mjs";
|
|
11
11
|
//#region src/middleware/middleware.ts
|
|
@@ -127,6 +127,6 @@ function transform(name, handlerOrOptions) {
|
|
|
127
127
|
}
|
|
128
128
|
//#endregion
|
|
129
129
|
//#region src/index.ts
|
|
130
|
-
const version = "2.6.
|
|
130
|
+
const version = "2.6.2";
|
|
131
131
|
//#endregion
|
|
132
132
|
export { ArcError, BaseController, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, ForbiddenError, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MongooseAdapter, NotFoundError, PrismaAdapter, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, UnauthorizedError, ValidationError, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, arcLog, assertValidConfig, authenticated, configureArcLogger, createDomainError, createDynamicPermissionMatrix, createMongooseAdapter, createOrgPermissions, createPrismaAdapter, defineResource, denyAll, envelope, fields, formatValidationErrors, fullPublic, getControllerScope, guard, intercept, middleware, ownerWithAdminBypass, presets_exports as permissions, pipe, publicRead, publicReadAdminWrite, readOnly, requestContext, requireAuth, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireTeamMembership, sortMiddlewares, transform, validateResourceConfig, version, when };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { WebSocketClient, WebSocketMessage, WebSocketPluginOptions } from "./websocket.mjs";
|
|
2
2
|
import { EventGatewayOptions } from "./event-gateway.mjs";
|
|
3
3
|
import { JobDefinition, JobDispatchOptions, JobDispatcher, JobMeta, JobsPluginOptions, QueueStats } from "./jobs.mjs";
|
|
4
|
-
import { c as McpResourceConfig, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler } from "../types-
|
|
4
|
+
import { c as McpResourceConfig, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler } from "../types-DurlBP2N.mjs";
|
|
5
5
|
import { StreamlinePluginOptions, WorkflowLike, WorkflowRunLike } from "./streamline.mjs";
|
|
6
6
|
import { WebhookDeliveryRecord, WebhookManager, WebhookPluginOptions, WebhookStore, WebhookSubscription } from "./webhooks.mjs";
|
|
7
7
|
export { type BetterAuthHandler, type CallToolResult, type CreateMcpServerConfig, type CrudOperation, type EventGatewayOptions, type JobDefinition, type JobDispatchOptions, type JobDispatcher, type JobMeta, type JobsPluginOptions, type McpAuthResult, type McpPluginOptions, type McpResourceConfig, type PromptDefinition, type QueueStats, type StreamlinePluginOptions, type ToolAnnotations, type ToolContext, type ToolDefinition, type WebSocketClient, type WebSocketMessage, type WebSocketPluginOptions, type WebhookDeliveryRecord, type WebhookManager, type WebhookPluginOptions, type WebhookStore, type WebhookSubscription, type WorkflowLike, type WorkflowRunLike };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Bt as ResourceDefinition } from "../../interface-
|
|
2
|
-
import { a as McpAuthResolver, c as McpResourceConfig, d as SessionEntry, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler, u as PromptResult } from "../../types-
|
|
1
|
+
import { Bt as ResourceDefinition } from "../../interface-CrN45qz1.mjs";
|
|
2
|
+
import { a as McpAuthResolver, c as McpResourceConfig, d as SessionEntry, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler, u as PromptResult } from "../../types-DurlBP2N.mjs";
|
|
3
3
|
import { FastifyPluginAsync } from "fastify";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
|
|
@@ -470,6 +470,9 @@ declare class ResourceDefinition<TDoc = AnyRecord> {
|
|
|
470
470
|
readonly disabledRoutes: CrudRouteKey[];
|
|
471
471
|
readonly events: Record<string, EventDefinition>;
|
|
472
472
|
readonly rateLimit?: RateLimitConfig | false;
|
|
473
|
+
readonly audit?: boolean | {
|
|
474
|
+
operations?: ("create" | "update" | "delete")[];
|
|
475
|
+
};
|
|
473
476
|
readonly updateMethod?: "PUT" | "PATCH" | "both";
|
|
474
477
|
readonly pipe?: PipelineConfig;
|
|
475
478
|
readonly fields?: FieldPermissionMap;
|
|
@@ -1558,6 +1561,34 @@ interface ResourceConfig<TDoc = AnyRecord> {
|
|
|
1558
1561
|
* Requires `queryCachePlugin` to be registered.
|
|
1559
1562
|
*/
|
|
1560
1563
|
cache?: ResourceCacheConfig;
|
|
1564
|
+
/**
|
|
1565
|
+
* Per-resource audit opt-in. When `auditPlugin` is registered with
|
|
1566
|
+
* `autoAudit: { perResource: true }`, only resources with this flag are audited.
|
|
1567
|
+
*
|
|
1568
|
+
* The cleanest pattern for apps where most resources don't need auditing —
|
|
1569
|
+
* no growing exclude lists, no centralized allowlist to maintain.
|
|
1570
|
+
*
|
|
1571
|
+
* - `true`: Audit create/update/delete on this resource
|
|
1572
|
+
* - `{ operations: ['delete'] }`: Audit only specific operations
|
|
1573
|
+
* - `false` or omit: Not audited (default)
|
|
1574
|
+
*
|
|
1575
|
+
* @example
|
|
1576
|
+
* ```ts
|
|
1577
|
+
* // app.ts
|
|
1578
|
+
* await fastify.register(auditPlugin, {
|
|
1579
|
+
* autoAudit: { perResource: true },
|
|
1580
|
+
* });
|
|
1581
|
+
*
|
|
1582
|
+
* // order.resource.ts
|
|
1583
|
+
* defineResource({ name: 'order', audit: true });
|
|
1584
|
+
*
|
|
1585
|
+
* // payment.resource.ts
|
|
1586
|
+
* defineResource({ name: 'payment', audit: { operations: ['delete'] } });
|
|
1587
|
+
* ```
|
|
1588
|
+
*/
|
|
1589
|
+
audit?: boolean | {
|
|
1590
|
+
operations?: ("create" | "update" | "delete")[];
|
|
1591
|
+
};
|
|
1561
1592
|
}
|
|
1562
1593
|
/**
|
|
1563
1594
|
* Resource-level permissions
|
|
@@ -2214,6 +2245,10 @@ interface RegistryEntry extends ResourceMetadata {
|
|
|
2214
2245
|
disabledRoutes?: string[];
|
|
2215
2246
|
/** Rate limit config */
|
|
2216
2247
|
rateLimit?: RateLimitConfig | false;
|
|
2248
|
+
/** Per-resource audit opt-in flag (read by auditPlugin perResource mode) */
|
|
2249
|
+
audit?: boolean | {
|
|
2250
|
+
operations?: ("create" | "update" | "delete")[];
|
|
2251
|
+
};
|
|
2217
2252
|
}
|
|
2218
2253
|
interface RegistryStats {
|
|
2219
2254
|
total?: number;
|
package/dist/org/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Lt as RouteHandler } from "../interface-
|
|
1
|
+
import { Lt as RouteHandler } from "../interface-CrN45qz1.mjs";
|
|
2
2
|
import { i as UserBase } from "../types-BNUccdcf.mjs";
|
|
3
3
|
import { InvitationAdapter, InvitationDoc, MemberDoc, OrgAdapter, OrgDoc, OrgPermissionStatement, OrgRole, OrganizationPluginOptions } from "./types.mjs";
|
|
4
4
|
import { FastifyPluginAsync, RouteHandlerMethod } from "fastify";
|
package/dist/plugins/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { V as MiddlewareConfig, Y as PresetHook, c as AdditionalRoute, dt as RouteSchemaOptions, l as AnyRecord, sn as HookSystem, zt as ResourceRegistry } from "../interface-
|
|
1
|
+
import { V as MiddlewareConfig, Y as PresetHook, c as AdditionalRoute, dt as RouteSchemaOptions, l as AnyRecord, sn as HookSystem, zt as ResourceRegistry } from "../interface-CrN45qz1.mjs";
|
|
2
2
|
import { t as ExternalOpenApiPaths } from "../externalPaths-DpO-s7r8.mjs";
|
|
3
3
|
import { _ as cachingPlugin, a as versioningPlugin, c as MetricsOptions, d as SSEOptions, f as _default$6, g as _default$1, h as CachingRule, i as _default$7, l as _default$4, m as CachingOptions, n as errorHandlerPlugin, o as MetricEntry, p as ssePlugin, r as VersioningOptions, s as MetricsCollector, t as ErrorHandlerOptions, u as metricsPlugin } from "../errorHandler-Do4vVQ1f.mjs";
|
|
4
4
|
import { t as TracingOptions } from "../tracing-bz_U4EM1.mjs";
|
package/dist/plugins/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { i as getOrgId } from "../types-BhtYdxZU.mjs";
|
|
|
3
3
|
import { t as requestContext } from "../requestContext-DYtmNpm5.mjs";
|
|
4
4
|
import { t as hasEvents } from "../typeGuards-Cj5Rgvlg.mjs";
|
|
5
5
|
import { t as HookSystem } from "../HookSystem-COkyWztM.mjs";
|
|
6
|
-
import { t as ResourceRegistry } from "../ResourceRegistry-
|
|
6
|
+
import { t as ResourceRegistry } from "../ResourceRegistry-C6ngvOnn.mjs";
|
|
7
7
|
import { n as caching_default, t as cachingPlugin } from "../caching-BSXB-Xr7.mjs";
|
|
8
8
|
import { t as errorHandlerPlugin } from "../errorHandler-r2595m8T.mjs";
|
|
9
9
|
import { n as metrics_default, t as metricsPlugin } from "../metrics-Csh4nsvv.mjs";
|
|
@@ -44,7 +44,7 @@ try {
|
|
|
44
44
|
function createTracerProvider(options) {
|
|
45
45
|
if (!isAvailable) return null;
|
|
46
46
|
const { serviceName = "@classytic/arc", serviceVersion, exporterUrl = "http://localhost:4318/v1/traces" } = options;
|
|
47
|
-
const resolvedVersion = serviceVersion ?? "2.6.
|
|
47
|
+
const resolvedVersion = serviceVersion ?? "2.6.2";
|
|
48
48
|
const exporter = new OTLPTraceExporter({ url: exporterUrl });
|
|
49
49
|
const provider = new NodeTracerProvider({ resource: { attributes: {
|
|
50
50
|
"service.name": serviceName,
|
package/dist/presets/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ft as IControllerResponse, It as IRequestContext, Wt as PaginatedResult, X as PresetResult, at as ResourceConfig, l as AnyRecord } from "../interface-
|
|
1
|
+
import { Ft as IControllerResponse, It as IRequestContext, Wt as PaginatedResult, X as PresetResult, at as ResourceConfig, l as AnyRecord } from "../interface-CrN45qz1.mjs";
|
|
2
2
|
import { MultiTenantOptions, multiTenantPreset } from "./multiTenant.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/presets/ownedByUser.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as IntrospectionPluginOptions, Rt as RegisterOptions, zt as ResourceRegistry } from "../interface-
|
|
1
|
+
import { L as IntrospectionPluginOptions, Rt as RegisterOptions, zt as ResourceRegistry } from "../interface-CrN45qz1.mjs";
|
|
2
2
|
import { FastifyPluginAsync } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/registry/introspectionPlugin.d.ts
|
package/dist/registry/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as introspectionPlugin_default, t as introspectionPlugin } from "../registry-I-ogLgL9.mjs";
|
|
2
|
-
import { t as ResourceRegistry } from "../ResourceRegistry-
|
|
2
|
+
import { t as ResourceRegistry } from "../ResourceRegistry-C6ngvOnn.mjs";
|
|
3
3
|
export { ResourceRegistry, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
|
package/dist/testing/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Bt as ResourceDefinition, Ht as CrudRepository, l as AnyRecord } from "../interface-
|
|
2
|
-
import { r as CreateAppOptions } from "../types-
|
|
1
|
+
import { Bt as ResourceDefinition, Ht as CrudRepository, l as AnyRecord } from "../interface-CrN45qz1.mjs";
|
|
2
|
+
import { d as ResourceLike, r as CreateAppOptions } from "../types-C1Z28coa.mjs";
|
|
3
3
|
import Fastify, { FastifyInstance, FastifyServerOptions } from "fastify";
|
|
4
4
|
import { Connection } from "mongoose";
|
|
5
5
|
import { Mock } from "vitest";
|
|
@@ -572,6 +572,29 @@ declare function createTestTimer(): {
|
|
|
572
572
|
reset: () => void;
|
|
573
573
|
};
|
|
574
574
|
//#endregion
|
|
575
|
+
//#region src/testing/preloadResources.d.ts
|
|
576
|
+
/** Eager glob result: `{ '/path/to/file.ts': resourceModule }` */
|
|
577
|
+
type EagerGlobResult = Record<string, unknown>;
|
|
578
|
+
/** Lazy glob result: `{ '/path/to/file.ts': () => Promise<unknown> }` */
|
|
579
|
+
type LazyGlobResult = Record<string, () => Promise<unknown>>;
|
|
580
|
+
/**
|
|
581
|
+
* Normalize an eager `import.meta.glob` result into a `ResourceLike[]`.
|
|
582
|
+
*
|
|
583
|
+
* Accepts either:
|
|
584
|
+
* - `{ import: 'default' }` form: values are the resource directly
|
|
585
|
+
* - default form: values are the full module — picks first export with `toPlugin()`
|
|
586
|
+
*
|
|
587
|
+
* Throws if any module doesn't yield a valid `ResourceLike`.
|
|
588
|
+
*/
|
|
589
|
+
declare function preloadResources(globResult: EagerGlobResult): ResourceLike[];
|
|
590
|
+
/**
|
|
591
|
+
* Normalize a lazy `import.meta.glob` result into a `Promise<ResourceLike[]>`.
|
|
592
|
+
*
|
|
593
|
+
* Use this when resources depend on prior bootstrap (e.g., engine init) and
|
|
594
|
+
* cannot be evaluated at import time of the preload file.
|
|
595
|
+
*/
|
|
596
|
+
declare function preloadResourcesAsync(globResult: LazyGlobResult): Promise<ResourceLike[]>;
|
|
597
|
+
//#endregion
|
|
575
598
|
//#region src/testing/TestHarness.d.ts
|
|
576
599
|
/**
|
|
577
600
|
* Test fixtures for a resource
|
|
@@ -898,4 +921,4 @@ declare class TestDataLoader {
|
|
|
898
921
|
cleanup(): Promise<void>;
|
|
899
922
|
}
|
|
900
923
|
//#endregion
|
|
901
|
-
export { type AuthProvider, type AuthResponse, type BetterAuthTestHelpers, type BetterAuthTestHelpersOptions, type CreateTestAppOptions, DatabaseSnapshot, TestFixtures as DbTestFixtures, type GenerateTestFileOptions, HttpTestHarness, type HttpTestHarnessOptions, InMemoryDatabase, type OrgResponse, type SetupBetterAuthOrgOptions, type SetupUserConfig, type TestAppResult, TestDataLoader, TestDatabase, type TestFixtures$1 as TestFixtures, TestHarness, type TestHarnessOptions, type TestOrgContext, TestRequestBuilder, TestSeeder, TestTransaction, type TestUserContext, createBetterAuthProvider, createBetterAuthTestHelpers, createConfigTestSuite, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSnapshotMatcher, createSpy, createTestApp, createTestAuth, createTestHarness, createTestTimer, generateTestFile, request, safeParseBody, setupBetterAuthOrg, waitFor, withTestDb };
|
|
924
|
+
export { type AuthProvider, type AuthResponse, type BetterAuthTestHelpers, type BetterAuthTestHelpersOptions, type CreateTestAppOptions, DatabaseSnapshot, TestFixtures as DbTestFixtures, type GenerateTestFileOptions, HttpTestHarness, type HttpTestHarnessOptions, InMemoryDatabase, type OrgResponse, type SetupBetterAuthOrgOptions, type SetupUserConfig, type TestAppResult, TestDataLoader, TestDatabase, type TestFixtures$1 as TestFixtures, TestHarness, type TestHarnessOptions, type TestOrgContext, TestRequestBuilder, TestSeeder, TestTransaction, type TestUserContext, createBetterAuthProvider, createBetterAuthTestHelpers, createConfigTestSuite, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSnapshotMatcher, createSpy, createTestApp, createTestAuth, createTestHarness, createTestTimer, generateTestFile, preloadResources, preloadResourcesAsync, request, safeParseBody, setupBetterAuthOrg, waitFor, withTestDb };
|
package/dist/testing/index.mjs
CHANGED
|
@@ -1066,6 +1066,50 @@ function createTestTimer() {
|
|
|
1066
1066
|
};
|
|
1067
1067
|
}
|
|
1068
1068
|
//#endregion
|
|
1069
|
+
//#region src/testing/preloadResources.ts
|
|
1070
|
+
/**
|
|
1071
|
+
* Normalize an eager `import.meta.glob` result into a `ResourceLike[]`.
|
|
1072
|
+
*
|
|
1073
|
+
* Accepts either:
|
|
1074
|
+
* - `{ import: 'default' }` form: values are the resource directly
|
|
1075
|
+
* - default form: values are the full module — picks first export with `toPlugin()`
|
|
1076
|
+
*
|
|
1077
|
+
* Throws if any module doesn't yield a valid `ResourceLike`.
|
|
1078
|
+
*/
|
|
1079
|
+
function preloadResources(globResult) {
|
|
1080
|
+
const resources = [];
|
|
1081
|
+
for (const [path, value] of Object.entries(globResult)) {
|
|
1082
|
+
const resource = pickResource(value);
|
|
1083
|
+
if (!resource) throw new Error(`preloadResources: ${path} does not export a valid resource.\n Expected: a default export OR a named export with toPlugin().`);
|
|
1084
|
+
resources.push(resource);
|
|
1085
|
+
}
|
|
1086
|
+
return resources.sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Normalize a lazy `import.meta.glob` result into a `Promise<ResourceLike[]>`.
|
|
1090
|
+
*
|
|
1091
|
+
* Use this when resources depend on prior bootstrap (e.g., engine init) and
|
|
1092
|
+
* cannot be evaluated at import time of the preload file.
|
|
1093
|
+
*/
|
|
1094
|
+
async function preloadResourcesAsync(globResult) {
|
|
1095
|
+
return (await Promise.all(Object.entries(globResult).map(async ([path, loader]) => {
|
|
1096
|
+
const resource = pickResource(await loader());
|
|
1097
|
+
if (!resource) throw new Error(`preloadResourcesAsync: ${path} does not export a valid resource.\n Expected: a default export OR a named export with toPlugin().`);
|
|
1098
|
+
return resource;
|
|
1099
|
+
}))).sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
|
|
1100
|
+
}
|
|
1101
|
+
function pickResource(value) {
|
|
1102
|
+
if (!value || typeof value !== "object") return void 0;
|
|
1103
|
+
if (typeof value.toPlugin === "function") return value;
|
|
1104
|
+
const mod = value;
|
|
1105
|
+
const candidates = [
|
|
1106
|
+
mod.default,
|
|
1107
|
+
mod.resource,
|
|
1108
|
+
...Object.values(mod)
|
|
1109
|
+
];
|
|
1110
|
+
for (const c of candidates) if (c && typeof c === "object" && typeof c.toPlugin === "function") return c;
|
|
1111
|
+
}
|
|
1112
|
+
//#endregion
|
|
1069
1113
|
//#region src/testing/TestHarness.ts
|
|
1070
1114
|
/**
|
|
1071
1115
|
* Resource Test Harness
|
|
@@ -1752,7 +1796,7 @@ function runEventTests(resourceName, displayName, events) {
|
|
|
1752
1796
|
* ```
|
|
1753
1797
|
*/
|
|
1754
1798
|
async function createTestApp(options = {}) {
|
|
1755
|
-
const { createApp } = await import("../createApp-
|
|
1799
|
+
const { createApp } = await import("../createApp-D2w0LdYJ.mjs").then((n) => n.r);
|
|
1756
1800
|
const { useInMemoryDb = true, mongoUri: providedMongoUri, ...appOptions } = options;
|
|
1757
1801
|
const defaultAuth = {
|
|
1758
1802
|
type: "jwt",
|
|
@@ -1950,4 +1994,4 @@ var TestDataLoader = class {
|
|
|
1950
1994
|
}
|
|
1951
1995
|
};
|
|
1952
1996
|
//#endregion
|
|
1953
|
-
export { DatabaseSnapshot, TestFixtures as DbTestFixtures, HttpTestHarness, InMemoryDatabase, TestDataLoader, TestDatabase, TestHarness, TestRequestBuilder, TestSeeder, TestTransaction, createBetterAuthProvider, createBetterAuthTestHelpers, createConfigTestSuite, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSnapshotMatcher, createSpy, createTestApp, createTestAuth, createTestHarness, createTestTimer, generateTestFile, request, safeParseBody, setupBetterAuthOrg, waitFor, withTestDb };
|
|
1997
|
+
export { DatabaseSnapshot, TestFixtures as DbTestFixtures, HttpTestHarness, InMemoryDatabase, TestDataLoader, TestDatabase, TestHarness, TestRequestBuilder, TestSeeder, TestTransaction, createBetterAuthProvider, createBetterAuthTestHelpers, createConfigTestSuite, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSnapshotMatcher, createSpy, createTestApp, createTestAuth, createTestHarness, createTestTimer, generateTestFile, preloadResources, preloadResourcesAsync, request, safeParseBody, setupBetterAuthOrg, waitFor, withTestDb };
|
package/dist/types/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { _ as isMember, a as AUTHENTICATED_SCOPE, d as getTeamId, g as isElevated, h as isAuthenticated, l as getOrgId, m as hasOrgAccess, n as ElevationOptions, o as PUBLIC_SCOPE, s as RequestScope, t as ElevationEvent, u as getOrgRoles } from "../elevation-C_taLQrM.mjs";
|
|
2
|
-
import { $ as RegistryEntry, A as GracefulShutdownOptions, B as LookupOption, C as CrudSchemas, D as FastifyWithAuth, E as FastifyRequestExtras, F as InferResourceDoc, Ft as IControllerResponse, G as OwnershipCheck, Gt as PaginationParams, H as MiddlewareHandler, Ht as CrudRepository, I as IntrospectionData, It as IRequestContext, J as PresetFunction, K as ParsedQuery, Kt as QueryOptions, L as IntrospectionPluginOptions, Lt as RouteHandler, M as HealthOptions, Mt as ControllerLike, N as InferAdapterDoc, Nt as FastifyHandler, O as FastifyWithDecorators, P as InferDocType, Pt as IController, Q as RateLimitConfig, R as JWTPayload, S as CrudRouterOptions, St as getUserId, T as EventsDecorator, U as ObjectId, Ut as InferDoc, V as MiddlewareConfig, W as OpenApiSchemas, Wt as PaginatedResult, X as PresetResult, Y as PresetHook, Z as QueryParserInterface, _ as AuthenticatorContext, _t as UserLike, at as ResourceConfig, b as CrudController, bt as ValidationResult, c as AdditionalRoute, ct as ResourceMetadata, d as ArcDecorator, dt as RouteSchemaOptions, et as RegistryStats, f as ArcInternalMetadata, ft as ServiceContext, g as Authenticator, gt as TypedResourceConfig, h as AuthPluginOptions, ht as TypedRepository, it as ResourceCacheConfig, j as HealthCheck, jt as ControllerHandler, k as FieldRule, l as AnyRecord, lt as ResourcePermissions, m as AuthHelpers, mt as TypedController, nt as RequestIdOptions, ot as ResourceHookContext, p as ArcRequest, pt as TokenPair, q as PopulateOption, rt as RequestWithExtras, st as ResourceHooks, tt as RequestContext, u as ApiResponse, ut as RouteHandlerMethod, v as ConfigError, vt as UserOrganization, w as EventDefinition, wt as BaseControllerOptions, x as CrudRouteKey, xt as envelope, y as ControllerQueryOptions, yt as ValidateOptions, z as JwtContext } from "../interface-
|
|
2
|
+
import { $ as RegistryEntry, A as GracefulShutdownOptions, B as LookupOption, C as CrudSchemas, D as FastifyWithAuth, E as FastifyRequestExtras, F as InferResourceDoc, Ft as IControllerResponse, G as OwnershipCheck, Gt as PaginationParams, H as MiddlewareHandler, Ht as CrudRepository, I as IntrospectionData, It as IRequestContext, J as PresetFunction, K as ParsedQuery, Kt as QueryOptions, L as IntrospectionPluginOptions, Lt as RouteHandler, M as HealthOptions, Mt as ControllerLike, N as InferAdapterDoc, Nt as FastifyHandler, O as FastifyWithDecorators, P as InferDocType, Pt as IController, Q as RateLimitConfig, R as JWTPayload, S as CrudRouterOptions, St as getUserId, T as EventsDecorator, U as ObjectId, Ut as InferDoc, V as MiddlewareConfig, W as OpenApiSchemas, Wt as PaginatedResult, X as PresetResult, Y as PresetHook, Z as QueryParserInterface, _ as AuthenticatorContext, _t as UserLike, at as ResourceConfig, b as CrudController, bt as ValidationResult, c as AdditionalRoute, ct as ResourceMetadata, d as ArcDecorator, dt as RouteSchemaOptions, et as RegistryStats, f as ArcInternalMetadata, ft as ServiceContext, g as Authenticator, gt as TypedResourceConfig, h as AuthPluginOptions, ht as TypedRepository, it as ResourceCacheConfig, j as HealthCheck, jt as ControllerHandler, k as FieldRule, l as AnyRecord, lt as ResourcePermissions, m as AuthHelpers, mt as TypedController, nt as RequestIdOptions, ot as ResourceHookContext, p as ArcRequest, pt as TokenPair, q as PopulateOption, rt as RequestWithExtras, st as ResourceHooks, tt as RequestContext, u as ApiResponse, ut as RouteHandlerMethod, v as ConfigError, vt as UserOrganization, w as EventDefinition, wt as BaseControllerOptions, x as CrudRouteKey, xt as envelope, y as ControllerQueryOptions, yt as ValidateOptions, z as JwtContext } from "../interface-CrN45qz1.mjs";
|
|
3
3
|
import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "../types-BNUccdcf.mjs";
|
|
4
4
|
export { AUTHENTICATED_SCOPE, AdditionalRoute, AnyRecord, ApiResponse, ArcDecorator, ArcInternalMetadata, ArcRequest, AuthHelpers, AuthPluginOptions, Authenticator, AuthenticatorContext, BaseControllerOptions, ConfigError, ControllerHandler, ControllerLike, ControllerQueryOptions, CrudController, CrudRepository, CrudRouteKey, CrudRouterOptions, CrudSchemas, ElevationEvent, ElevationOptions, EventDefinition, EventsDecorator, FastifyHandler, FastifyRequestExtras, FastifyWithAuth, FastifyWithDecorators, FieldRule, GracefulShutdownOptions, HealthCheck, HealthOptions, IController, IControllerResponse, IRequestContext, InferAdapterDoc, InferDoc, InferDocType, InferResourceDoc, IntrospectionData, IntrospectionPluginOptions, JWTPayload, JwtContext, LookupOption, MiddlewareConfig, MiddlewareHandler, ObjectId, OpenApiSchemas, OwnershipCheck, PUBLIC_SCOPE, PaginatedResult, PaginationParams, ParsedQuery, PermissionCheck, PermissionContext, PermissionResult, PopulateOption, PresetFunction, PresetHook, PresetResult, QueryOptions, QueryParserInterface, RateLimitConfig, RegistryEntry, RegistryStats, RequestContext, RequestIdOptions, RequestScope, RequestWithExtras, ResourceCacheConfig, ResourceConfig, ResourceHookContext, ResourceHooks, ResourceMetadata, ResourcePermissions, RouteHandler, RouteHandlerMethod, RouteSchemaOptions, ServiceContext, TokenPair, TypedController, TypedRepository, TypedResourceConfig, UserBase, UserLike, UserOrganization, ValidateOptions, ValidationResult, envelope, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as ElevationOptions } from "./elevation-C_taLQrM.mjs";
|
|
2
|
-
import { g as Authenticator } from "./interface-
|
|
2
|
+
import { g as Authenticator } from "./interface-CrN45qz1.mjs";
|
|
3
3
|
import { t as ExternalOpenApiPaths } from "./externalPaths-DpO-s7r8.mjs";
|
|
4
4
|
import { i as CacheStore } from "./interface-D_BWALyZ.mjs";
|
|
5
5
|
import { r as QueryCachePluginOptions } from "./queryCachePlugin-DcmETvcB.mjs";
|
|
@@ -52,6 +52,12 @@ import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, Fast
|
|
|
52
52
|
* // Minimal resource (plain object)
|
|
53
53
|
* const simple: ResourceLike = { name: 'ping', toPlugin: () => () => {} };
|
|
54
54
|
* ```
|
|
55
|
+
*
|
|
56
|
+
* **DO NOT add an index signature** (`[key: string]: unknown`) to this interface.
|
|
57
|
+
* Class instances (like `ResourceDefinition`) don't implicitly carry index signatures,
|
|
58
|
+
* so adding one here makes `ResourceDefinition` *unassignable* to `ResourceLike` —
|
|
59
|
+
* the exact opposite of the intent. TypeScript's structural typing already allows
|
|
60
|
+
* classes with extra properties to satisfy this interface without an index signature.
|
|
55
61
|
*/
|
|
56
62
|
interface ResourceLike {
|
|
57
63
|
/** Plugin factory — called by createApp to register routes */
|
package/dist/utils/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { K as ParsedQuery, W as OpenApiSchemas, Z as QueryParserInterface, l as AnyRecord } from "../interface-
|
|
1
|
+
import { K as ParsedQuery, W as OpenApiSchemas, Z as QueryParserInterface, l as AnyRecord } from "../interface-CrN45qz1.mjs";
|
|
2
2
|
import { a as NotFoundError, c as RateLimitError, d as ValidationError, i as ForbiddenError, l as ServiceUnavailableError, m as isArcError, n as ConflictError, o as OrgAccessDeniedError, p as createError, r as ErrorDetails, s as OrgRequiredError, t as ArcError, u as UnauthorizedError } from "../errors-CcVbl1-T.mjs";
|
|
3
3
|
import { a as CircuitBreakerStats, c as createCircuitBreakerRegistry, i as CircuitBreakerRegistry, n as CircuitBreakerError, o as CircuitState, r as CircuitBreakerOptions, s as createCircuitBreaker, t as CircuitBreaker } from "../circuitBreaker-JP2GdJ4b.mjs";
|
|
4
4
|
import { FastifyInstance } from "fastify";
|
package/package.json
CHANGED
package/skills/arc/SKILL.md
CHANGED
|
@@ -8,11 +8,11 @@ description: |
|
|
|
8
8
|
Triggers: arc, fastify resource, defineResource, createApp, BaseController, arc preset,
|
|
9
9
|
arc auth, arc events, arc jobs, arc websocket, arc mcp, arc plugin, arc testing, arc cli,
|
|
10
10
|
arc permissions, arc hooks, arc pipeline, arc factory, arc cache, arc QueryCache.
|
|
11
|
-
version: 2.6.
|
|
11
|
+
version: 2.6.2
|
|
12
12
|
license: MIT
|
|
13
13
|
metadata:
|
|
14
14
|
author: Classytic
|
|
15
|
-
version: "2.6.
|
|
15
|
+
version: "2.6.2"
|
|
16
16
|
tags:
|
|
17
17
|
- fastify
|
|
18
18
|
- rest-api
|
|
@@ -527,21 +527,68 @@ src/resources/order/
|
|
|
527
527
|
|
|
528
528
|
Generate: `arc generate resource order --mcp` | Wire: `extraTools: [fulfillOrderTool]`
|
|
529
529
|
|
|
530
|
-
**Auto-load resources**
|
|
530
|
+
**Auto-load resources** — no barrel files, no manual `toPlugin()`:
|
|
531
531
|
|
|
532
532
|
```typescript
|
|
533
533
|
import { createApp, loadResources } from '@classytic/arc/factory';
|
|
534
534
|
|
|
535
535
|
const app = await createApp({
|
|
536
|
-
|
|
536
|
+
resourcePrefix: '/api/v1', // optional URL prefix
|
|
537
|
+
resources: await loadResources(import.meta.url), // discovers *.resource.ts
|
|
537
538
|
auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } },
|
|
538
539
|
});
|
|
539
|
-
// loadResources options: exclude, include, suffix, recursive
|
|
540
540
|
```
|
|
541
541
|
|
|
542
|
-
|
|
542
|
+
`loadResources()` discovers files matching `*.resource.{ts,js,mts,mjs}`, recursively. Pass `import.meta.url` for dev/prod parity (resolves to `src/` in dev, `dist/` in prod automatically). Discovers `default` export, `export const resource`, OR any named export with `toPlugin()` (e.g., `export const userResource`).
|
|
543
543
|
|
|
544
|
-
|
|
544
|
+
Options: `exclude`, `include`, `suffix`, `recursive`, `silent`.
|
|
545
|
+
|
|
546
|
+
**Per-resource opt-out of `resourcePrefix`** — for webhooks, admin routes:
|
|
547
|
+
```typescript
|
|
548
|
+
defineResource({ name: 'webhook', prefix: '/hooks', skipGlobalPrefix: true })
|
|
549
|
+
// Registers at /hooks even with createApp({ resourcePrefix: '/api/v1' })
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
**Boot sequence:**
|
|
553
|
+
```typescript
|
|
554
|
+
const app = await createApp({
|
|
555
|
+
resourcePrefix: '/api/v1',
|
|
556
|
+
plugins: async (f) => { await connectDB(); }, // 1. infra (DB, docs)
|
|
557
|
+
bootstrap: [inventoryInit, accountingInit], // 2. domain init (engines)
|
|
558
|
+
resources: await loadResources(import.meta.url), // 3. routes
|
|
559
|
+
afterResources: async (f) => { subscribeEvents(f); }, // 4. post-wiring
|
|
560
|
+
onReady: async (f) => { logger.info('ready'); }, // 5. lifecycle
|
|
561
|
+
});
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
**Audit per-resource opt-in** — no growing exclude lists:
|
|
565
|
+
```typescript
|
|
566
|
+
// Register audit plugin with perResource mode
|
|
567
|
+
await fastify.register(auditPlugin, { autoAudit: { perResource: true } });
|
|
568
|
+
|
|
569
|
+
// Opt-in at the resource level
|
|
570
|
+
defineResource({ name: 'order', audit: true });
|
|
571
|
+
defineResource({ name: 'payment', audit: { operations: ['delete'] } });
|
|
572
|
+
defineResource({ name: 'product' }); // not audited
|
|
573
|
+
|
|
574
|
+
// Manual custom() for MCP/additionalRoutes/read auditing
|
|
575
|
+
app.post('/orders/:id/refund', async (req) => {
|
|
576
|
+
await app.audit.custom('order', req.params.id, 'refund', { reason }, { user });
|
|
577
|
+
});
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Import compatibility:** `loadResources()` uses runtime `import()`. Works with relative imports (`./foo.js`) and Node.js `#` subpath imports (`#shared/utils.js` via `package.json` `imports`). Does **NOT** work with tsconfig path aliases (`@/*`, `~/`) — those are compile-time only.
|
|
581
|
+
|
|
582
|
+
**Vitest workaround** (rare): if resources need engine bootstrap or transitive `node_modules` imports that don't compose with dynamic import:
|
|
583
|
+
```typescript
|
|
584
|
+
import { preloadResources } from '@classytic/arc/testing';
|
|
585
|
+
|
|
586
|
+
export const preloadedResources = preloadResources(
|
|
587
|
+
import.meta.glob('../../src/resources/**/*.resource.ts', { eager: true, import: 'default' }),
|
|
588
|
+
);
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
**Unified role check** — checks both platform AND org roles:
|
|
545
592
|
|
|
546
593
|
```typescript
|
|
547
594
|
import { roles } from '@classytic/arc/permissions';
|
|
@@ -552,7 +599,7 @@ permissions: {
|
|
|
552
599
|
// Also: requireRoles(['admin'], { includeOrgRoles: true }) for backward compat
|
|
553
600
|
```
|
|
554
601
|
|
|
555
|
-
**DX helpers
|
|
602
|
+
**DX helpers:**
|
|
556
603
|
|
|
557
604
|
```typescript
|
|
558
605
|
// Typed request for wrapHandler: false routes — no more (req as any).user
|