@classytic/arc 2.4.3 → 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 +57 -6
- package/dist/{BaseController-CkM5dUh_.mjs → BaseController-AbbRx3e0.mjs} +5 -2
- package/dist/{ResourceRegistry-DeCIFlix.mjs → ResourceRegistry-C6ngvOnn.mjs} +1 -0
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +1 -1
- package/dist/{adapters-DTC4Ug66.mjs → adapters-CTn28N4y.mjs} +72 -11
- package/dist/audit/index.d.mts +32 -6
- package/dist/audit/index.mjs +32 -4
- package/dist/audit/mongodb.d.mts +1 -1
- package/dist/auth/index.d.mts +1 -1
- package/dist/auth/index.mjs +2 -2
- package/dist/cli/commands/docs.mjs +1 -1
- package/dist/cli/commands/init.mjs +12 -9
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +2 -2
- package/dist/{createApp-CBgVaFyh.mjs → createApp-D2w0LdYJ.mjs} +431 -290
- package/dist/{defineResource-B22gcNvn.mjs → defineResource-Ckxg6HrZ.mjs} +125 -22
- package/dist/discovery/index.mjs +1 -1
- package/dist/docs/index.d.mts +1 -1
- package/dist/dynamic/index.d.mts +1 -1
- package/dist/dynamic/index.mjs +2 -2
- package/dist/{elevation-Ca_yveIO.d.mts → elevation-C_taLQrM.d.mts} +27 -1
- package/dist/{errorHandler-DMbGdzBG.mjs → errorHandler-r2595m8T.mjs} +1 -1
- package/dist/{errors-CPpvPHT0.d.mts → errors-CcVbl1-T.d.mts} +17 -1
- package/dist/{errors-rxhfP7Hf.mjs → errors-NoQKsbAT.mjs} +23 -1
- package/dist/{eventPlugin-iGrSEmwJ.d.mts → eventPlugin-DW45v4V5.d.mts} +30 -2
- package/dist/events/index.d.mts +2 -2
- package/dist/events/index.mjs +40 -10
- package/dist/factory/index.d.mts +44 -23
- package/dist/factory/index.mjs +152 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/mongodb.d.mts +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-BL8CaQih.d.mts → index-B4uZm82R.d.mts} +2 -2
- package/dist/{index-yhxyjqNb.d.mts → index-DrCqa3Jq.d.mts} +4 -8
- package/dist/{index-Diqcm14c.d.mts → index-NGZksqM5.d.mts} +30 -1
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +8 -7
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +4 -2
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/{interface-DGmPxakH.d.mts → interface-CrN45qz1.d.mts} +229 -13
- package/dist/{mongodb-CUpYfxfD.d.mts → mongodb-kltrBPa1.d.mts} +10 -0
- package/dist/{mongodb-bga9AbkD.d.mts → mongodb-pMvOlR5_.d.mts} +1 -1
- package/dist/org/index.d.mts +1 -1
- package/dist/org/index.mjs +1 -1
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +2 -2
- package/dist/{permissions-Jk5x3sxz.mjs → permissions-C8ImI8gC.mjs} +44 -2
- package/dist/plugins/index.d.mts +1 -1
- package/dist/plugins/index.mjs +4 -4
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +1 -1
- package/dist/{presets-OMPaHMTY.mjs → presets-BMfdy34e.mjs} +2 -2
- package/dist/{redis-CQ5YxMC5.d.mts → redis-D0Qc-9EW.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +1 -1
- package/dist/{resourceToTools-PMFE8HIv.mjs → resourceToTools-DH3c3e-T.mjs} +81 -7
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +2 -2
- package/dist/{sse-BkViJPlT.mjs → sse-BF7GR7IB.mjs} +1 -1
- package/dist/testing/index.d.mts +26 -3
- package/dist/testing/index.mjs +46 -2
- package/dist/types/index.d.mts +3 -3
- package/dist/types/index.mjs +23 -2
- package/dist/{types-C6TQjtdi.mjs → types-BhtYdxZU.mjs} +26 -1
- package/dist/{types-Dt0-AI6E.d.mts → types-C1Z28coa.d.mts} +195 -6
- package/dist/{types-BJmgxNbF.d.mts → types-DurlBP2N.d.mts} +1 -1
- package/dist/utils/index.d.mts +2 -2
- package/dist/utils/index.mjs +1 -1
- package/package.json +6 -5
- package/skills/arc/SKILL.md +151 -4
- package/skills/arc/references/mcp.md +160 -2
- /package/dist/{interface-B4awm1RJ.d.mts → interface-gr-7qo9j.d.mts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as BaseController } from "./BaseController-
|
|
1
|
+
import { t as BaseController } from "./BaseController-AbbRx3e0.mjs";
|
|
2
2
|
import { t as pluralize } from "./pluralize-CcT6qF0a.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/integrations/mcp/createMcpServer.ts
|
|
@@ -148,16 +148,55 @@ function typeToZod(type) {
|
|
|
148
148
|
default: return z.string();
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
|
-
/**
|
|
151
|
+
/** Operators that apply to numeric/date fields */
|
|
152
|
+
const COMPARISON_OPS = new Set([
|
|
153
|
+
"gt",
|
|
154
|
+
"gte",
|
|
155
|
+
"lt",
|
|
156
|
+
"lte"
|
|
157
|
+
]);
|
|
158
|
+
/** Map operator to a human-readable description suffix */
|
|
159
|
+
function opDescription(op, fieldName) {
|
|
160
|
+
switch (op) {
|
|
161
|
+
case "gt": return `${fieldName} greater than`;
|
|
162
|
+
case "gte": return `${fieldName} greater than or equal`;
|
|
163
|
+
case "lt": return `${fieldName} less than`;
|
|
164
|
+
case "lte": return `${fieldName} less than or equal`;
|
|
165
|
+
case "ne": return `${fieldName} not equal to`;
|
|
166
|
+
case "in": return `${fieldName} in comma-separated list`;
|
|
167
|
+
case "nin": return `${fieldName} not in comma-separated list`;
|
|
168
|
+
case "exists": return `${fieldName} exists (true/false)`;
|
|
169
|
+
default: return `${fieldName} ${op}`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/** Build list/query shape with filterable fields, operators, and pagination */
|
|
152
173
|
function buildListShape(fieldRules, options) {
|
|
153
|
-
const { filterableFields = [], hiddenFields = [], extraHideFields = [] } = options;
|
|
174
|
+
const { filterableFields = [], hiddenFields = [], extraHideFields = [], allowedOperators } = options;
|
|
154
175
|
const allHidden = new Set([...hiddenFields, ...extraHideFields]);
|
|
155
176
|
const shape = { ...PAGINATION_SHAPE };
|
|
156
|
-
if (fieldRules)
|
|
177
|
+
if (!fieldRules) return shape;
|
|
178
|
+
for (const name of filterableFields) {
|
|
157
179
|
if (allHidden.has(name)) continue;
|
|
158
180
|
const rule = fieldRules[name];
|
|
159
181
|
if (!rule) continue;
|
|
160
|
-
|
|
182
|
+
const filterField = buildFieldSchema(rule);
|
|
183
|
+
shape[name] = filterField.optional();
|
|
184
|
+
if (allowedOperators?.length) {
|
|
185
|
+
const isNumericOrDate = rule.type === "number" || rule.type === "date";
|
|
186
|
+
for (const op of allowedOperators) {
|
|
187
|
+
if (COMPARISON_OPS.has(op) && !isNumericOrDate) continue;
|
|
188
|
+
if (op === "eq") continue;
|
|
189
|
+
if (op === "exists") {
|
|
190
|
+
shape[`${name}_${op}`] = z.boolean().optional().describe(opDescription(op, name));
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (op === "in" || op === "nin") {
|
|
194
|
+
shape[`${name}_${op}`] = z.string().optional().describe(opDescription(op, name));
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
shape[`${name}_${op}`] = filterField.optional().describe(opDescription(op, name));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
161
200
|
}
|
|
162
201
|
return shape;
|
|
163
202
|
}
|
|
@@ -193,7 +232,7 @@ function buildRequestContext(input, auth, operation, policyFilters) {
|
|
|
193
232
|
case "list": return {
|
|
194
233
|
...base,
|
|
195
234
|
params: {},
|
|
196
|
-
query:
|
|
235
|
+
query: expandOperatorKeys(input),
|
|
197
236
|
body: void 0
|
|
198
237
|
};
|
|
199
238
|
case "get": return {
|
|
@@ -225,6 +264,40 @@ function buildRequestContext(input, auth, operation, policyFilters) {
|
|
|
225
264
|
};
|
|
226
265
|
}
|
|
227
266
|
}
|
|
267
|
+
/** Convert MCP operator keys (`price_gt`) to MongoKit bracket notation (`price[gt]`). */
|
|
268
|
+
const OPERATOR_SUFFIXES = new Set([
|
|
269
|
+
"eq",
|
|
270
|
+
"ne",
|
|
271
|
+
"gt",
|
|
272
|
+
"gte",
|
|
273
|
+
"lt",
|
|
274
|
+
"lte",
|
|
275
|
+
"in",
|
|
276
|
+
"nin",
|
|
277
|
+
"exists"
|
|
278
|
+
]);
|
|
279
|
+
function expandOperatorKeys(input) {
|
|
280
|
+
const out = {};
|
|
281
|
+
for (const [key, value] of Object.entries(input)) {
|
|
282
|
+
const lastUnderscore = key.lastIndexOf("_");
|
|
283
|
+
if (lastUnderscore > 0) {
|
|
284
|
+
const op = key.slice(lastUnderscore + 1);
|
|
285
|
+
if (OPERATOR_SUFFIXES.has(op)) {
|
|
286
|
+
const field = key.slice(0, lastUnderscore);
|
|
287
|
+
const existing = out[field];
|
|
288
|
+
if (existing && typeof existing === "object" && existing !== null) existing[op] = value;
|
|
289
|
+
else if (existing === void 0) out[field] = { [op]: value };
|
|
290
|
+
else out[field] = {
|
|
291
|
+
eq: existing,
|
|
292
|
+
[op]: value
|
|
293
|
+
};
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
out[key] = value;
|
|
298
|
+
}
|
|
299
|
+
return out;
|
|
300
|
+
}
|
|
228
301
|
function buildScope(auth) {
|
|
229
302
|
if (!auth) return { kind: "public" };
|
|
230
303
|
if (auth.organizationId) return {
|
|
@@ -314,7 +387,8 @@ function resourceToTools(resource, config = {}) {
|
|
|
314
387
|
hiddenFields,
|
|
315
388
|
readonlyFields,
|
|
316
389
|
extraHideFields: config.hideFields,
|
|
317
|
-
filterableFields
|
|
390
|
+
filterableFields,
|
|
391
|
+
allowedOperators
|
|
318
392
|
}),
|
|
319
393
|
handler: createHandler(op, controller, resource.name, resource.permissions)
|
|
320
394
|
});
|
package/dist/scope/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as AUTHENTICATED_SCOPE, c as
|
|
1
|
+
import { _ as isMember, a as AUTHENTICATED_SCOPE, c as getOrgContext, d as getTeamId, f as getUserId, g as isElevated, h as isAuthenticated, i as elevationPlugin, l as getOrgId, m as hasOrgAccess, n as ElevationOptions, o as PUBLIC_SCOPE, p as getUserRoles, r as _default, s as RequestScope, t as ElevationEvent, u as getOrgRoles } from "../elevation-C_taLQrM.mjs";
|
|
2
2
|
import { FastifyReply, FastifyRequest } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/scope/rateLimitKey.d.ts
|
|
@@ -29,4 +29,4 @@ interface ResolveOrgFromHeaderOptions {
|
|
|
29
29
|
*/
|
|
30
30
|
declare function resolveOrgFromHeader(options: ResolveOrgFromHeaderOptions): (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
|
|
31
31
|
//#endregion
|
|
32
|
-
export { AUTHENTICATED_SCOPE, type ElevationEvent, type ElevationOptions, PUBLIC_SCOPE, type RateLimitKeyContext, type RequestScope, type ResolveOrgFromHeaderOptions, type TenantKeyGeneratorOptions, createTenantKeyGenerator, _default as elevationPlugin, elevationPlugin as elevationPluginFn, getOrgId, getOrgRoles, getTeamId, getUserId, getUserRoles, hasOrgAccess, isAuthenticated, isElevated, isMember, resolveOrgFromHeader };
|
|
32
|
+
export { AUTHENTICATED_SCOPE, type ElevationEvent, type ElevationOptions, PUBLIC_SCOPE, type RateLimitKeyContext, type RequestScope, type ResolveOrgFromHeaderOptions, type TenantKeyGeneratorOptions, createTenantKeyGenerator, _default as elevationPlugin, elevationPlugin as elevationPluginFn, getOrgContext, getOrgId, getOrgRoles, getTeamId, getUserId, getUserRoles, hasOrgAccess, isAuthenticated, isElevated, isMember, resolveOrgFromHeader };
|
package/dist/scope/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as getOrgRoles, c as getUserRoles, d as isElevated, f as isMember, i as getOrgId, l as hasOrgAccess, n as PUBLIC_SCOPE, o as getTeamId, r as getOrgContext, s as getUserId, t as AUTHENTICATED_SCOPE, u as isAuthenticated } from "../types-BhtYdxZU.mjs";
|
|
2
2
|
import { n as normalizeRoles } from "../types-ZUu_h0jp.mjs";
|
|
3
3
|
import { n as elevation_default, t as elevationPlugin } from "../elevation-BEdACOLB.mjs";
|
|
4
4
|
//#region src/scope/rateLimitKey.ts
|
|
@@ -75,4 +75,4 @@ function resolveOrgFromHeader(options) {
|
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
//#endregion
|
|
78
|
-
export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, createTenantKeyGenerator, elevation_default as elevationPlugin, elevationPlugin as elevationPluginFn, getOrgId, getOrgRoles, getTeamId, getUserId, getUserRoles, hasOrgAccess, isAuthenticated, isElevated, isMember, resolveOrgFromHeader };
|
|
78
|
+
export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, createTenantKeyGenerator, elevation_default as elevationPlugin, elevationPlugin as elevationPluginFn, getOrgContext, getOrgId, getOrgRoles, getTeamId, getUserId, getUserRoles, hasOrgAccess, isAuthenticated, isElevated, isMember, resolveOrgFromHeader };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { i as getOrgId, n as PUBLIC_SCOPE } from "./types-BhtYdxZU.mjs";
|
|
3
3
|
import { t as arcLog } from "./logger-Dz3j1ItV.mjs";
|
|
4
4
|
import fp from "fastify-plugin";
|
|
5
5
|
//#region src/plugins/sse.ts
|
package/dist/testing/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
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
|
-
import { a as AUTHENTICATED_SCOPE,
|
|
2
|
-
import { $ as
|
|
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-CrN45qz1.mjs";
|
|
3
3
|
import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "../types-BNUccdcf.mjs";
|
|
4
|
-
export { AUTHENTICATED_SCOPE, AdditionalRoute, AnyRecord, ApiResponse, ArcDecorator, ArcInternalMetadata, 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, ResourceHooks, ResourceMetadata, ResourcePermissions, RouteHandler, RouteHandlerMethod, RouteSchemaOptions, ServiceContext, TokenPair, TypedController, TypedRepository, TypedResourceConfig, UserBase, UserLike, UserOrganization, ValidateOptions, ValidationResult, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
|
|
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 };
|
package/dist/types/index.mjs
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as getOrgRoles, d as isElevated, f as isMember, i as getOrgId, l as hasOrgAccess, n as PUBLIC_SCOPE, o as getTeamId, t as AUTHENTICATED_SCOPE, u as isAuthenticated } from "../types-BhtYdxZU.mjs";
|
|
2
2
|
//#region src/types/index.ts
|
|
3
3
|
/**
|
|
4
|
+
* Response envelope helper — wraps data in Arc's standard `{ success, data }` format.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { envelope } from '@classytic/arc';
|
|
9
|
+
*
|
|
10
|
+
* handler: async (req, reply) => {
|
|
11
|
+
* const data = await getResults();
|
|
12
|
+
* return envelope(data);
|
|
13
|
+
* // → { success: true, data }
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
function envelope(data, meta) {
|
|
18
|
+
return {
|
|
19
|
+
success: true,
|
|
20
|
+
data,
|
|
21
|
+
...meta
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
4
25
|
* Extract user ID from a user object (supports both id and _id)
|
|
5
26
|
*/
|
|
6
27
|
function getUserId(user) {
|
|
@@ -9,4 +30,4 @@ function getUserId(user) {
|
|
|
9
30
|
return id ? String(id) : void 0;
|
|
10
31
|
}
|
|
11
32
|
//#endregion
|
|
12
|
-
export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
|
|
33
|
+
export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, envelope, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
|
|
@@ -58,9 +58,34 @@ function getUserRoles(scope) {
|
|
|
58
58
|
if (scope.kind === "member") return scope.userRoles;
|
|
59
59
|
return [];
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Org context — canonical extraction from a Fastify request.
|
|
63
|
+
*
|
|
64
|
+
* Works regardless of auth type (JWT, Better Auth, custom) by reading
|
|
65
|
+
* `request.scope` and `request.user`. Eliminates the need for each resource
|
|
66
|
+
* to re-invent org extraction from headers/user/scope.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* import { getOrgContext } from '@classytic/arc/scope';
|
|
71
|
+
*
|
|
72
|
+
* handler: async (request, reply) => {
|
|
73
|
+
* const { userId, organizationId, roles, orgRoles } = getOrgContext(request);
|
|
74
|
+
* }
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
function getOrgContext(request) {
|
|
78
|
+
const scope = request.scope ?? { kind: "public" };
|
|
79
|
+
return {
|
|
80
|
+
userId: getUserId(scope) ?? request.user?.id ?? request.user?._id,
|
|
81
|
+
organizationId: getOrgId(scope) ?? request.user?.organizationId ?? request.headers?.["x-organization-id"],
|
|
82
|
+
roles: getUserRoles(scope),
|
|
83
|
+
orgRoles: getOrgRoles(scope)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
61
86
|
/** Default public scope — used as initial decoration value */
|
|
62
87
|
const PUBLIC_SCOPE = Object.freeze({ kind: "public" });
|
|
63
88
|
/** Default authenticated scope — used when user is logged in but no org */
|
|
64
89
|
const AUTHENTICATED_SCOPE = Object.freeze({ kind: "authenticated" });
|
|
65
90
|
//#endregion
|
|
66
|
-
export {
|
|
91
|
+
export { getOrgRoles as a, getUserRoles as c, isElevated as d, isMember as f, getOrgId as i, hasOrgAccess as l, PUBLIC_SCOPE as n, getTeamId as o, getOrgContext as r, getUserId as s, AUTHENTICATED_SCOPE as t, isAuthenticated as u };
|
|
@@ -1,14 +1,139 @@
|
|
|
1
|
-
import { n as ElevationOptions } from "./elevation-
|
|
2
|
-
import {
|
|
1
|
+
import { n as ElevationOptions } from "./elevation-C_taLQrM.mjs";
|
|
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";
|
|
6
6
|
import { i as EventTransport } from "./EventTransport-wc5hSLik.mjs";
|
|
7
|
-
import { t as EventPluginOptions } from "./eventPlugin-
|
|
7
|
+
import { t as EventPluginOptions } from "./eventPlugin-DW45v4V5.mjs";
|
|
8
8
|
import { c as MetricsOptions, d as SSEOptions, m as CachingOptions, r as VersioningOptions, t as ErrorHandlerOptions } from "./errorHandler-Do4vVQ1f.mjs";
|
|
9
|
-
import { r as IdempotencyStore } from "./interface-
|
|
9
|
+
import { r as IdempotencyStore } from "./interface-gr-7qo9j.mjs";
|
|
10
10
|
import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
|
|
11
11
|
|
|
12
|
+
//#region src/factory/loadResources.d.ts
|
|
13
|
+
/**
|
|
14
|
+
* loadResources — Auto-discover resource files from a directory.
|
|
15
|
+
*
|
|
16
|
+
* Scans for `*.resource.{ts,js,mts,mjs}` files, imports each,
|
|
17
|
+
* and collects their default exports. No barrel file needed.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { createApp, loadResources } from '@classytic/arc/factory';
|
|
22
|
+
*
|
|
23
|
+
* // Recommended: import.meta.url — works in both src/ (dev) and dist/ (prod)
|
|
24
|
+
* const app = await createApp({
|
|
25
|
+
* resources: await loadResources(import.meta.url),
|
|
26
|
+
* auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } },
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // Or explicit path (must match runtime layout)
|
|
30
|
+
* const app2 = await createApp({
|
|
31
|
+
* resources: await loadResources('./src/resources'),
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* File convention:
|
|
36
|
+
* ```
|
|
37
|
+
* src/resources/
|
|
38
|
+
* product/product.resource.ts → export default defineResource({ name: 'product', ... })
|
|
39
|
+
* order/order.resource.ts → export default defineResource({ name: 'order', ... })
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Resource interface — the contract between `loadResources`/`createApp` and resource definitions.
|
|
44
|
+
*
|
|
45
|
+
* Matches the shape of `ResourceDefinition` from `defineResource()` without requiring
|
|
46
|
+
* the import. All properties except `toPlugin` are optional so plain objects work too:
|
|
47
|
+
*
|
|
48
|
+
* ```typescript
|
|
49
|
+
* // Full resource (from defineResource)
|
|
50
|
+
* const product = defineResource({ name: 'product', ... }); // satisfies ResourceLike
|
|
51
|
+
*
|
|
52
|
+
* // Minimal resource (plain object)
|
|
53
|
+
* const simple: ResourceLike = { name: 'ping', toPlugin: () => () => {} };
|
|
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.
|
|
61
|
+
*/
|
|
62
|
+
interface ResourceLike {
|
|
63
|
+
/** Plugin factory — called by createApp to register routes */
|
|
64
|
+
toPlugin: () => unknown;
|
|
65
|
+
/** Resource name (used for route generation, logging, duplicate detection) */
|
|
66
|
+
name?: string;
|
|
67
|
+
/** Route prefix (default: `/${name}s`) */
|
|
68
|
+
prefix?: string;
|
|
69
|
+
/** Skip the global `resourcePrefix` from createApp — register at root */
|
|
70
|
+
skipGlobalPrefix?: boolean;
|
|
71
|
+
/** Display name for docs/OpenAPI */
|
|
72
|
+
displayName?: string;
|
|
73
|
+
/** Applied preset names */
|
|
74
|
+
_appliedPresets?: string[];
|
|
75
|
+
}
|
|
76
|
+
interface LoadResourcesOptions {
|
|
77
|
+
/** File pattern suffix (default: '.resource'). Matches `*.resource.{ts,js,mts,mjs}`. */
|
|
78
|
+
suffix?: string;
|
|
79
|
+
/** Recurse into subdirectories (default: true) */
|
|
80
|
+
recursive?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Resource names to exclude. Matched against the resource's `.name` property
|
|
83
|
+
* after import, so you use the resource name (not the filename).
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* await loadResources('./src/resources', { exclude: ['debug', 'legacy-report'] })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
exclude?: string[];
|
|
91
|
+
/**
|
|
92
|
+
* Resource names to include. When set, only matching resources are returned.
|
|
93
|
+
* Takes priority over `exclude`.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* // Only load these two resources (useful for testing or microservice splits)
|
|
98
|
+
* await loadResources('./src/resources', { include: ['product', 'order'] })
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
include?: string[];
|
|
102
|
+
/**
|
|
103
|
+
* Suppress warning logs for skipped/failed files.
|
|
104
|
+
* Useful when your resources directory contains factory files or helpers
|
|
105
|
+
* that don't export a resource (e.g., `account.resource.ts` exporting a factory).
|
|
106
|
+
*
|
|
107
|
+
* @default false
|
|
108
|
+
*/
|
|
109
|
+
silent?: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Scan a directory for resource files and import their default exports.
|
|
113
|
+
*
|
|
114
|
+
* Accepts a directory path OR `import.meta.url` (file:// URL).
|
|
115
|
+
* When given a URL, resolves to the directory containing that file —
|
|
116
|
+
* so `loadResources(import.meta.url)` works in both dev (`src/`) and
|
|
117
|
+
* production (`dist/`) without path gymnastics.
|
|
118
|
+
*
|
|
119
|
+
* @param dir - Directory path, or `import.meta.url` (file:// URL resolved to its dirname)
|
|
120
|
+
* @param options - Pattern and recursion options
|
|
121
|
+
* @returns Array of resource definitions (anything with `.toPlugin()`)
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* // Works from both src/ and dist/ — resolves relative to the calling file
|
|
126
|
+
* await loadResources(import.meta.url);
|
|
127
|
+
*
|
|
128
|
+
* // Subdirectory relative to the calling file
|
|
129
|
+
* await loadResources(import.meta.url, { suffix: '.resource' });
|
|
130
|
+
*
|
|
131
|
+
* // Explicit path (must match runtime layout)
|
|
132
|
+
* await loadResources('./src/resources');
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
declare function loadResources(dir: string, options?: LoadResourcesOptions): Promise<ResourceLike[]>;
|
|
136
|
+
//#endregion
|
|
12
137
|
//#region src/factory/types.d.ts
|
|
13
138
|
type CorsOptions = Record<string, unknown> & {
|
|
14
139
|
origin?: unknown;
|
|
@@ -473,8 +598,72 @@ interface CreateAppOptions {
|
|
|
473
598
|
ajv?: {
|
|
474
599
|
keywords?: string[];
|
|
475
600
|
};
|
|
476
|
-
/**
|
|
601
|
+
/**
|
|
602
|
+
* Resources to register automatically.
|
|
603
|
+
* Each resource's `.toPlugin()` is called and registered for you.
|
|
604
|
+
*
|
|
605
|
+
* @example
|
|
606
|
+
* ```ts
|
|
607
|
+
* const app = await createApp({
|
|
608
|
+
* resources: [productResource, orderResource, userResource],
|
|
609
|
+
* auth: { type: 'jwt', jwt: { secret: 'xxx' } },
|
|
610
|
+
* });
|
|
611
|
+
* ```
|
|
612
|
+
*/
|
|
613
|
+
resources?: Array<ResourceLike>;
|
|
614
|
+
/**
|
|
615
|
+
* URL prefix for all auto-registered resources.
|
|
616
|
+
* Applied only to resources in the `resources` array — not to `plugins()`.
|
|
617
|
+
*
|
|
618
|
+
* @example
|
|
619
|
+
* ```ts
|
|
620
|
+
* const app = await createApp({
|
|
621
|
+
* resourcePrefix: '/api/v1',
|
|
622
|
+
* resources: await loadResources(import.meta.url),
|
|
623
|
+
* });
|
|
624
|
+
* // product → /api/v1/products, order → /api/v1/orders
|
|
625
|
+
* ```
|
|
626
|
+
*/
|
|
627
|
+
resourcePrefix?: string;
|
|
628
|
+
/**
|
|
629
|
+
* Custom plugin registration — runs after Arc core (security, auth, events)
|
|
630
|
+
* but before `bootstrap` and `resources`.
|
|
631
|
+
*
|
|
632
|
+
* Use this for infrastructure setup: database connections, OpenAPI docs,
|
|
633
|
+
* webhook plugins, SSE wiring, etc.
|
|
634
|
+
*/
|
|
477
635
|
plugins?: (fastify: FastifyInstance) => Promise<void>;
|
|
636
|
+
/**
|
|
637
|
+
* Bootstrap functions — run after `plugins()` but before `resources`.
|
|
638
|
+
*
|
|
639
|
+
* Use this for domain initialization that needs infrastructure ready
|
|
640
|
+
* (DB connected, events wired, Redis available) but must complete
|
|
641
|
+
* before resources register (e.g., engine singletons, event handlers,
|
|
642
|
+
* seed data, connection verification).
|
|
643
|
+
*
|
|
644
|
+
* Boot order:
|
|
645
|
+
* ```
|
|
646
|
+
* 1. Arc core (security, auth, events)
|
|
647
|
+
* 2. plugins() ← infra (DB, SSE, docs)
|
|
648
|
+
* 3. bootstrap[] ← domain init (singletons, event handlers)
|
|
649
|
+
* 4. resources[] ← auto-discovered routes
|
|
650
|
+
* ```
|
|
651
|
+
*
|
|
652
|
+
* @example
|
|
653
|
+
* ```ts
|
|
654
|
+
* const app = await createApp({
|
|
655
|
+
* plugins: async (f) => { await connectDB(); await f.register(docsPlugin); },
|
|
656
|
+
* bootstrap: [inventoryInit, accountingInit, loyaltyInit],
|
|
657
|
+
* resources: await loadResources(import.meta.url),
|
|
658
|
+
* });
|
|
659
|
+
* ```
|
|
660
|
+
*/
|
|
661
|
+
bootstrap?: Array<(fastify: FastifyInstance) => void | Promise<void>>;
|
|
662
|
+
/**
|
|
663
|
+
* Hook called after resources are registered but before the app is ready.
|
|
664
|
+
* Use for post-registration wiring (e.g., cross-resource event subscriptions).
|
|
665
|
+
*/
|
|
666
|
+
afterResources?: (fastify: FastifyInstance) => void | Promise<void>;
|
|
478
667
|
/** Hook called after all plugins are loaded and the app is ready */
|
|
479
668
|
onReady?: (fastify: FastifyInstance) => void | Promise<void>;
|
|
480
669
|
/** Hook called when the app is shutting down */
|
|
@@ -507,4 +696,4 @@ interface RawBodyOptions {
|
|
|
507
696
|
runFirst?: boolean;
|
|
508
697
|
}
|
|
509
698
|
//#endregion
|
|
510
|
-
export { CustomPluginAuthOption as a, RawBodyOptions as c, CustomAuthenticatorOption as i, UnderPressureOptions as l, BetterAuthOption as n, JwtAuthOption as o, CreateAppOptions as r, MultipartOptions as s, AuthOption as t };
|
|
699
|
+
export { CustomPluginAuthOption as a, RawBodyOptions as c, ResourceLike as d, loadResources as f, CustomAuthenticatorOption as i, UnderPressureOptions as l, BetterAuthOption as n, JwtAuthOption as o, CreateAppOptions as r, MultipartOptions as s, AuthOption as t, LoadResourcesOptions as u };
|
package/dist/utils/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as NotFoundError, c as RateLimitError, d as ValidationError,
|
|
1
|
+
import { K as ParsedQuery, W as OpenApiSchemas, Z as QueryParserInterface, l as AnyRecord } from "../interface-CrN45qz1.mjs";
|
|
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";
|
|
5
5
|
|
package/dist/utils/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as createQueryParser, t as ArcQueryParser } from "../queryParser-CgCtsjti.mjs";
|
|
2
2
|
import { a as createCircuitBreaker, i as CircuitState, n as CircuitBreakerError, o as createCircuitBreakerRegistry, r as CircuitBreakerRegistry, t as CircuitBreaker } from "../circuitBreaker-BOBOpN2w.mjs";
|
|
3
3
|
import { _ as defineCompensation, a as getListQueryParams, c as listResponse, d as paginateWrapper, f as paginationSchema, g as wrapResponse, h as successResponseSchema, i as getDefaultCrudSchemas, l as messageWrapper, m as responses, n as deleteResponse, o as itemResponse, p as queryParams, r as errorResponseSchema, s as itemWrapper, t as createStateMachine, u as mutationResponse, v as withCompensation } from "../utils-Dc0WhlIl.mjs";
|
|
4
|
-
import { a as OrgAccessDeniedError, c as ServiceUnavailableError,
|
|
4
|
+
import { a as OrgAccessDeniedError, c as ServiceUnavailableError, f as createError, i as NotFoundError, l as UnauthorizedError, n as ConflictError, o as OrgRequiredError, p as isArcError, r as ForbiddenError, s as RateLimitError, t as ArcError, u as ValidationError } from "../errors-NoQKsbAT.mjs";
|
|
5
5
|
import { a as toJsonSchema, i as isZodSchema, n as convertRouteSchema, r as isJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-DjzHpFam.mjs";
|
|
6
6
|
import { t as hasEvents } from "../typeGuards-Cj5Rgvlg.mjs";
|
|
7
7
|
export { ArcError, ArcQueryParser, CircuitBreaker, CircuitBreakerError, CircuitBreakerRegistry, CircuitState, ConflictError, ForbiddenError, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, UnauthorizedError, ValidationError, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createError, createQueryParser, createStateMachine, defineCompensation, deleteResponse, errorResponseSchema, getDefaultCrudSchemas, getListQueryParams, hasEvents, isArcError, isJsonSchema, isZodSchema, itemResponse, itemWrapper, listResponse, messageWrapper, mutationResponse, paginateWrapper, paginationSchema, queryParams, responses, successResponseSchema, toJsonSchema, withCompensation, wrapResponse };
|