@classytic/arc 2.15.4 → 2.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/bin/arc.js +12 -0
- package/dist/{BaseController-dx3m2J8V.mjs → BaseController-Vk8I7C0x.mjs} +61 -19
- package/dist/{HookSystem-Iiebom92.mjs → HookSystem-Cmf7-Etp.mjs} +8 -4
- package/dist/{QueryCache-D41bfdBB.d.mts → QueryCache-8YmAQ-zW.d.mts} +1 -1
- package/dist/{ResourceRegistry-CTERg_2x.mjs → ResourceRegistry-CzSzVK1m.mjs} +55 -9
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +4 -2
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +4 -4
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi--M_i87dQ.mjs → betterAuthOpenApi-ClWxaceA.mjs} +10 -6
- package/dist/buildHandler-C_SkBNF3.mjs +302 -0
- package/dist/cache/index.d.mts +3 -3
- package/dist/cache/index.mjs +3 -3
- package/dist/{caching-SM8gghN6.mjs → caching-8MfrrUYU.mjs} +1 -1
- package/dist/cli/commands/describe.d.mts +35 -1
- package/dist/cli/commands/describe.mjs +52 -12
- package/dist/cli/commands/docs.d.mts +1 -4
- package/dist/cli/commands/docs.mjs +4 -16
- package/dist/cli/commands/generate.d.mts +2 -20
- package/dist/cli/commands/generate.mjs +1 -546
- package/dist/cli/commands/init.d.mts +2 -40
- package/dist/cli/commands/init.mjs +1 -3045
- package/dist/cli/commands/introspect.mjs +53 -64
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.mjs +2 -2
- package/dist/{constants-Cxde4rpC.mjs → constants-TrJVIJl0.mjs} +7 -0
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +5 -5
- package/dist/{core-CvmOqEms.mjs → core-wKeGXn38.mjs} +222 -44
- package/dist/createActionRouter-eiOFtnC3.mjs +288 -0
- package/dist/{createAggregationRouter-B0bPDf5b.mjs → createAggregationRouter-C4unhBnV.mjs} +3 -2
- package/dist/{createApp-PFegs47-.mjs → createApp-DdPBtmzp.mjs} +16 -14
- package/dist/{defineEvent-D5h7EvAx.mjs → defineEvent-NPKUJRt8.mjs} +1 -1
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/{errorHandler-Bk-AGhkU.mjs → errorHandler-DNPzqaTT.mjs} +17 -14
- package/dist/errors-4ZloYFvm.d.mts +91 -0
- package/dist/{eventPlugin-CaKTYkYM.mjs → eventPlugin-CnJCUyM0.mjs} +1 -1
- package/dist/{eventPlugin-qXpqTebY.d.mts → eventPlugin-DjEx_J3j.d.mts} +1 -1
- package/dist/events/index.d.mts +3 -3
- package/dist/events/index.mjs +5 -5
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +2 -2
- package/dist/factory/index.mjs +4 -3
- package/dist/fastify-augmentation-CJm0vh-l.d.mts +42 -0
- package/dist/{fields-COhcH3fk.d.mts → fields-DqZLp5d6.d.mts} +1 -1
- package/dist/generate-CcM24hoq.mjs +654 -0
- package/dist/generate-cRnsafMS.d.mts +38 -0
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +2 -2
- package/dist/idempotency/index.mjs +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-BTqLEvhu.d.mts → index-3L-adFJO.d.mts} +12 -12
- package/dist/{index-BstGxcc3.d.mts → index-CC_pgZjY.d.mts} +88 -17
- package/dist/{index-BswOSJCE.d.mts → index-DBDgy6Hw.d.mts} +430 -19
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +7 -8
- package/dist/init-D-vrTZ1G.d.mts +71 -0
- package/dist/init-DYzfniuX.mjs +3098 -0
- package/dist/integrations/event-gateway.d.mts +2 -2
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/jobs.mjs +3 -3
- package/dist/integrations/mcp/index.d.mts +239 -7
- package/dist/integrations/mcp/index.mjs +2 -528
- package/dist/integrations/mcp/testing.d.mts +2 -2
- package/dist/integrations/mcp/testing.mjs +6 -10
- package/dist/integrations/streamline.mjs +26 -1
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +1 -1
- package/dist/integrations/websocket.mjs +1 -0
- package/dist/loadResourcesFromEntry-DCjYMgfC.mjs +51 -0
- package/dist/{resourceToTools-tFYUNmM0.mjs → mcpPlugin-Dbgz9_Rj.mjs} +1021 -318
- package/dist/{memory-UBydS5ku.mjs → memory-QOLe11D5.mjs} +2 -0
- package/dist/middleware/index.d.mts +1 -1
- package/dist/middleware/index.mjs +1 -1
- package/dist/{openapi-BHXhoX8O.mjs → openapi-BRnd3pT7.mjs} +82 -44
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +1 -1
- package/dist/{permissions-ohQyv50e.mjs → permissions-CTxMrreC.mjs} +2 -2
- package/dist/{pipe-Zr0KXjQe.mjs → pipe-DiCyvyPN.mjs} +1 -0
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +1 -1
- package/dist/plugins/index.d.mts +5 -59
- package/dist/plugins/index.mjs +10 -10
- package/dist/plugins/response-cache.mjs +5 -5
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/{pluralize-DQgqgifU.mjs → pluralize-B9M8xvy-.mjs} +2 -1
- package/dist/preloadResources-BOXzPhKU.mjs +45 -0
- package/dist/presets/filesUpload.d.mts +4 -4
- package/dist/presets/filesUpload.mjs +2 -2
- 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 +4 -3
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-BbkjdPeH.mjs → presets-C9BE6WaZ.mjs} +2 -2
- package/dist/{queryCachePlugin-m1XsgAIJ.mjs → queryCachePlugin-B4XMSSe7.mjs} +2 -2
- package/dist/{queryCachePlugin-CqMdLI2-.d.mts → queryCachePlugin-Do4P_WBC.d.mts} +2 -2
- package/dist/{redis-DiMkdHEl.d.mts → redis-cpqVb85w.d.mts} +1 -1
- package/dist/{redis-stream-D6HzR1Z_.d.mts → redis-stream-BuiAS3aE.d.mts} +1 -1
- package/dist/registry/index.d.mts +341 -2
- package/dist/registry/index.mjs +3 -3
- package/dist/registry-BrlHkrRS.mjs +582 -0
- package/dist/{routerShared-DrOa-26E.mjs → routerShared-ClV4cCaa.mjs} +40 -16
- package/dist/scope/index.d.mts +3 -3
- package/dist/scope/index.mjs +3 -3
- package/dist/{sse-Bz-5ZeTt.mjs → sse-jh5OqFjR.mjs} +1 -1
- package/dist/testing/index.d.mts +2 -25
- package/dist/testing/index.mjs +17 -51
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +5 -5
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-BQsjgQzS.d.mts → types-BD0BCdf6.d.mts} +106 -12
- package/dist/{types-C_s5moIu.mjs → types-Bi0r0vjG.mjs} +53 -1
- package/dist/{types-CTYvcwHe.d.mts → types-CfapW2t8.d.mts} +42 -1
- package/dist/{types-DrBaUwyV.d.mts → types-Dw--SyTq.d.mts} +57 -11
- package/dist/utils/index.d.mts +1287 -2
- package/dist/utils/index.mjs +1 -1
- package/dist/{utils-_h9B3c57.mjs → utils-DPXZnZUx.mjs} +158 -41
- package/dist/{buildHandler-CcFOpJLh.mjs → validate-DFIP2VrM.mjs} +73 -302
- package/dist/{versioning-hmkPcDlX.d.mts → versioning-5H4930tj.d.mts} +1 -1
- package/package.json +22 -29
- package/skills/arc/SKILL.md +300 -706
- package/skills/arc/references/auth.md +19 -7
- package/skills/arc-code-review/SKILL.md +1 -1
- package/skills/arc-code-review/references/arc-cheatsheet.md +100 -322
- package/dist/createActionRouter-S3MLVYot.mjs +0 -220
- package/dist/index-bRjYu21O.d.mts +0 -1320
- package/dist/org/index.d.mts +0 -66
- package/dist/org/index.mjs +0 -486
- package/dist/org/types.d.mts +0 -82
- package/dist/org/types.mjs +0 -1
- package/dist/registry-I-ogLgL9.mjs +0 -46
- /package/dist/{EventTransport-CT_52aWU.d.mts → EventTransport-B1GFiYUy.d.mts} +0 -0
- /package/dist/{EventTransport-DLWoUMHy.mjs → EventTransport-ClEDfiMS.mjs} +0 -0
- /package/dist/{actionPermissions-CyUkQu6O.mjs → actionPermissions-Bjmvn7Eb.mjs} +0 -0
- /package/dist/{elevation-DgoeTyfX.mjs → elevation-Dci0AYLT.mjs} +0 -0
- /package/dist/{elevation-BXOWoGCF.d.mts → elevation-DvwtjDwu.d.mts} +0 -0
- /package/dist/{errorHandler-DFr45ZG4.d.mts → errorHandler-DuqTqeqn.d.mts} +0 -0
- /package/dist/{externalPaths-BD5nw6St.d.mts → externalPaths-ClykOQqa.d.mts} +0 -0
- /package/dist/{interface-beEtJyWM.d.mts → interface-BVkZsvEe.d.mts} +0 -0
- /package/dist/{interface-DfLGcus7.d.mts → interface-DoE6UoC2.d.mts} +0 -0
- /package/dist/{keys-CGcCbNyu.mjs → keys-DopsCuyQ.mjs} +0 -0
- /package/dist/{loadResources-DBMQg_Aj.mjs → loadResources-fol6JuvW.mjs} +0 -0
- /package/dist/{metrics-Qnvwc-LQ.mjs → metrics-B-PU4-Yu.mjs} +0 -0
- /package/dist/{replyHelpers-CK-FNO8E.mjs → replyHelpers-boS5Rx26.mjs} +0 -0
- /package/dist/{schemaIR-lYhC2gE5.mjs → schemaIR-DAOvBWgT.mjs} +0 -0
- /package/dist/{sessionManager-C4Le_UB3.d.mts → sessionManager-DlmaHUAl.d.mts} +0 -0
- /package/dist/{storage-Dfzt4VTl.d.mts → storage-HcAgP5Ni.d.mts} +0 -0
- /package/dist/{store-helpers-BkIN9-vu.mjs → store-helpers-5JgaxieH.mjs} +0 -0
- /package/dist/{tracing-QJVprktp.d.mts → tracing-bRqqUxFO.d.mts} +0 -0
- /package/dist/{versioning-BUrT5aP4.mjs → versioning-CuIwUQZ2.mjs} +0 -0
- /package/dist/{websocket-ChC2rqe1.d.mts → websocket-BJ0w-3Dt.d.mts} +0 -0
|
@@ -108,6 +108,7 @@ var MemoryCacheStore = class {
|
|
|
108
108
|
const oldestKey = this.cache.keys().next().value;
|
|
109
109
|
if (!oldestKey) break;
|
|
110
110
|
const entry = this.cache.get(oldestKey);
|
|
111
|
+
if (!entry) break;
|
|
111
112
|
this.removeEntry(oldestKey, entry);
|
|
112
113
|
this._evictions++;
|
|
113
114
|
}
|
|
@@ -118,6 +119,7 @@ var MemoryCacheStore = class {
|
|
|
118
119
|
const oldestKey = this.cache.keys().next().value;
|
|
119
120
|
if (!oldestKey) break;
|
|
120
121
|
const entry = this.cache.get(oldestKey);
|
|
122
|
+
if (!entry) break;
|
|
121
123
|
this.removeEntry(oldestKey, entry);
|
|
122
124
|
this._evictions++;
|
|
123
125
|
if (this.currentBytes <= target) break;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as MiddlewareHandler, L as RequestWithExtras, Q as MiddlewareConfig } from "../index-
|
|
1
|
+
import { I as MiddlewareHandler, L as RequestWithExtras, Q as MiddlewareConfig } from "../index-DBDgy6Hw.mjs";
|
|
2
2
|
import { RouteHandlerMethod } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/middleware/middleware.d.ts
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { t as getUserRoles } from "./types-D57iXYb8.mjs";
|
|
2
2
|
import { n as convertRouteSchema } from "./schemaConverter-De34B1ZG.mjs";
|
|
3
|
-
import { t as
|
|
4
|
-
import { t as
|
|
3
|
+
import { t as pluralize } from "./pluralize-B9M8xvy-.mjs";
|
|
4
|
+
import { t as resolveActionPermission } from "./actionPermissions-Bjmvn7Eb.mjs";
|
|
5
|
+
import { t as buildActionBodySchema } from "./createActionRouter-eiOFtnC3.mjs";
|
|
5
6
|
import fp from "fastify-plugin";
|
|
6
7
|
//#region src/docs/openapi/canonical-schemas.ts
|
|
7
8
|
/**
|
|
@@ -383,9 +384,11 @@ function createOperation(resource, operation, summary, extras, requiresAuthOverr
|
|
|
383
384
|
if (!s.operations) return true;
|
|
384
385
|
return s.operations.includes(operation);
|
|
385
386
|
});
|
|
387
|
+
const summaryNoun = (resource.displayName || resource.name).toLowerCase();
|
|
388
|
+
const finalNoun = operation === "list" ? pluralize(summaryNoun) : summaryNoun;
|
|
386
389
|
const op = {
|
|
387
390
|
tags: [resource.tag || "Resource"],
|
|
388
|
-
summary: `${summary} ${
|
|
391
|
+
summary: `${summary} ${finalNoun}`,
|
|
389
392
|
operationId: `${resource.name}_${operation}`,
|
|
390
393
|
...descParts.length > 0 && { description: descParts.join("\n\n") },
|
|
391
394
|
...requiresAuth && { security: [{ bearerAuth: [] }, ...additionalSecurity] },
|
|
@@ -509,49 +512,59 @@ function extractPathParams(path) {
|
|
|
509
512
|
//#endregion
|
|
510
513
|
//#region src/docs/openapi/action-paths.ts
|
|
511
514
|
/**
|
|
512
|
-
* Action endpoint emitter — `POST /:resource/:id/action
|
|
515
|
+
* Action endpoint emitter — `POST /:resource/:id/action` and/or
|
|
516
|
+
* `POST /:resource/action`.
|
|
513
517
|
*
|
|
514
|
-
* Generates a
|
|
515
|
-
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
*
|
|
518
|
+
* Generates a dispatch endpoint per mount point. Each mount has its own
|
|
519
|
+
* `oneOf` body schema containing only the actions that live at that
|
|
520
|
+
* mount — id-bound actions under `/:id/action`, id-less actions
|
|
521
|
+
* (`id: false`) under `/action`. Body schemas come from the SAME
|
|
522
|
+
* `buildActionBodySchema` the runtime uses, so docs and validation stay
|
|
523
|
+
* in sync.
|
|
519
524
|
*
|
|
520
525
|
* NOTE: action **response** shape varies per action — the dispatcher
|
|
521
526
|
* returns whatever the handler returned. We can't statically type the
|
|
522
|
-
* response without the handler exposing its return type,
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
* which `@hey-api/openapi-ts` and friends compile to `unknown` — that's
|
|
526
|
-
* the most accurate thing we can say without lying to consumers about
|
|
527
|
-
* shape. Per-action shape is documented in the `description` field;
|
|
528
|
-
* future work could let resource authors declare a per-action
|
|
529
|
-
* `responseSchema`.
|
|
527
|
+
* response without the handler exposing its return type, so the `200`
|
|
528
|
+
* body schema is `{}` (codegen → `unknown`). Per-action shape lives in
|
|
529
|
+
* the operation `description`.
|
|
530
530
|
*/
|
|
531
531
|
/**
|
|
532
|
-
* Append
|
|
533
|
-
*
|
|
532
|
+
* Append action-dispatch paths to `paths` for the resource. Emits one
|
|
533
|
+
* path per non-empty mount point — id-bound and/or id-less.
|
|
534
534
|
*/
|
|
535
535
|
function appendActionPaths(paths, resource, basePath, additionalSecurity) {
|
|
536
536
|
if (!resource.actions || resource.actions.length === 0) return;
|
|
537
|
-
const
|
|
538
|
-
const
|
|
537
|
+
const idBound = [];
|
|
538
|
+
const idLess = [];
|
|
539
|
+
for (const a of resource.actions) (a.id === false ? idLess : idBound).push(a);
|
|
540
|
+
if (idBound.length > 0) emitMount(paths, resource, basePath, additionalSecurity, idBound, true);
|
|
541
|
+
if (idLess.length > 0) emitMount(paths, resource, basePath, additionalSecurity, idLess, false);
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Emit one OpenAPI path for a single mount point's action subset.
|
|
545
|
+
* Centralises the shared rendering (body schema, description list,
|
|
546
|
+
* auth detection, response wiring) so id-bound and id-less mounts can't
|
|
547
|
+
* drift in shape.
|
|
548
|
+
*/
|
|
549
|
+
function emitMount(paths, resource, basePath, additionalSecurity, subsetActions, hasId) {
|
|
550
|
+
const actionPath = toOpenApiPath(`${basePath}${hasId ? "/:id/action" : "/action"}`);
|
|
551
|
+
const actionEnum = subsetActions.map((a) => a.name);
|
|
539
552
|
const actionSchemas = {};
|
|
540
|
-
for (const a of
|
|
553
|
+
for (const a of subsetActions) if (a.schema) actionSchemas[a.name] = a.schema;
|
|
541
554
|
const bodySchema = buildActionBodySchema(actionEnum, actionSchemas);
|
|
542
555
|
const descLines = [
|
|
543
|
-
"Unified action endpoint for state transitions.",
|
|
556
|
+
hasId ? "Unified action endpoint for state transitions on an existing entity." : "Resource-root action endpoint (no `:id` — operates on the collection or creates new entities).",
|
|
544
557
|
"",
|
|
545
558
|
"**Available actions:**"
|
|
546
559
|
];
|
|
547
|
-
for (const a of
|
|
560
|
+
for (const a of subsetActions) {
|
|
548
561
|
const roles = a.permissions?._roles;
|
|
549
562
|
const roleStr = roles?.length ? ` — requires: ${roles.join(" or ")}` : "";
|
|
550
563
|
const descStr = a.description ? ` — ${a.description}` : "";
|
|
551
564
|
descLines.push(`- \`${a.name}\`${roleStr}${descStr}`);
|
|
552
565
|
}
|
|
553
566
|
descLines.push("", "Response shape depends on the action handler — typically the mutated resource document or a kit-defined result envelope. See the per-action description above.");
|
|
554
|
-
const anyAuthRequired =
|
|
567
|
+
const anyAuthRequired = subsetActions.some((a) => {
|
|
555
568
|
const effective = resolveActionPermission({
|
|
556
569
|
action: { permissions: a.permissions },
|
|
557
570
|
resourcePermissions: resource.permissions,
|
|
@@ -561,13 +574,13 @@ function appendActionPaths(paths, resource, basePath, additionalSecurity) {
|
|
|
561
574
|
});
|
|
562
575
|
if (!paths[actionPath]) paths[actionPath] = {};
|
|
563
576
|
paths[actionPath].post = createOperation(resource, "action", `Perform action (${actionEnum.join(" / ")})`, {
|
|
564
|
-
parameters: [{
|
|
577
|
+
...hasId ? { parameters: [{
|
|
565
578
|
name: "id",
|
|
566
579
|
in: "path",
|
|
567
580
|
required: true,
|
|
568
581
|
schema: { type: "string" },
|
|
569
582
|
description: "Resource ID"
|
|
570
|
-
}],
|
|
583
|
+
}] } : {},
|
|
571
584
|
description: descLines.join("\n"),
|
|
572
585
|
requestBody: {
|
|
573
586
|
required: true,
|
|
@@ -579,7 +592,7 @@ function appendActionPaths(paths, resource, basePath, additionalSecurity) {
|
|
|
579
592
|
content: { "application/json": { schema: {} } }
|
|
580
593
|
},
|
|
581
594
|
"400": errorResponse("Invalid action or missing required fields"),
|
|
582
|
-
"404": errorResponse("Resource not found")
|
|
595
|
+
...hasId ? { "404": errorResponse("Resource not found") } : {}
|
|
583
596
|
}
|
|
584
597
|
}, anyAuthRequired, additionalSecurity);
|
|
585
598
|
}
|
|
@@ -634,13 +647,7 @@ function appendAggregationPaths(paths, resource, basePath, additionalSecurity) {
|
|
|
634
647
|
if (!paths[path]) paths[path] = {};
|
|
635
648
|
paths[path].get = createOperation(resource, `aggregation.${agg.name}`, agg.summary ?? `Aggregation: ${agg.name}`, {
|
|
636
649
|
description: descLines.join("\n"),
|
|
637
|
-
parameters:
|
|
638
|
-
name: "querystring",
|
|
639
|
-
in: "query",
|
|
640
|
-
required: false,
|
|
641
|
-
schema: querystring,
|
|
642
|
-
description: "Filter narrowing — composes with base filter + tenant scope."
|
|
643
|
-
}],
|
|
650
|
+
parameters: buildAggregationParameters(agg, querystring),
|
|
644
651
|
responses: {
|
|
645
652
|
"200": {
|
|
646
653
|
description: "Aggregation result",
|
|
@@ -688,6 +695,37 @@ function normalizeGroupByForOpenApi(groupBy) {
|
|
|
688
695
|
if (!groupBy) return [];
|
|
689
696
|
return typeof groupBy === "string" ? [groupBy] : groupBy;
|
|
690
697
|
}
|
|
698
|
+
/**
|
|
699
|
+
* Build the OpenAPI `parameters` array for an aggregation route.
|
|
700
|
+
*
|
|
701
|
+
* Always includes the filter-narrowing `querystring` slot. When the
|
|
702
|
+
* aggregation declares URL-driven paging (`defaultLimit`), adds an
|
|
703
|
+
* explicit `?limit` integer parameter with the declared default +
|
|
704
|
+
* maximum. Auto-generated FE clients pick the constraint up; humans
|
|
705
|
+
* reading the docs see the cap without reading source.
|
|
706
|
+
*/
|
|
707
|
+
function buildAggregationParameters(agg, querystring) {
|
|
708
|
+
const params = [{
|
|
709
|
+
name: "querystring",
|
|
710
|
+
in: "query",
|
|
711
|
+
required: false,
|
|
712
|
+
schema: querystring,
|
|
713
|
+
description: "Filter narrowing — composes with base filter + tenant scope."
|
|
714
|
+
}];
|
|
715
|
+
if (agg.defaultLimit !== void 0) params.push({
|
|
716
|
+
name: "limit",
|
|
717
|
+
in: "query",
|
|
718
|
+
required: false,
|
|
719
|
+
schema: {
|
|
720
|
+
type: "integer",
|
|
721
|
+
minimum: 1,
|
|
722
|
+
default: agg.defaultLimit,
|
|
723
|
+
maximum: agg.maxLimit ?? 1e3
|
|
724
|
+
},
|
|
725
|
+
description: `Result row cap. Default ${agg.defaultLimit}; values above ${agg.maxLimit ?? 1e3} are capped silently. Invalid values fall back to the default.`
|
|
726
|
+
});
|
|
727
|
+
return params;
|
|
728
|
+
}
|
|
691
729
|
function setNestedSchemaProp(target, path, leaf) {
|
|
692
730
|
if (path.length === 1) {
|
|
693
731
|
target[path[0]] = leaf;
|
|
@@ -837,7 +875,9 @@ function appendCustomRoutePaths(paths, resource, basePath, additionalSecurity) {
|
|
|
837
875
|
}
|
|
838
876
|
if (routeSchema?.response) {
|
|
839
877
|
const responseSchemas = routeSchema.response;
|
|
840
|
-
|
|
878
|
+
const responses = extras.responses ?? {};
|
|
879
|
+
extras.responses = responses;
|
|
880
|
+
for (const [statusCode, schema] of Object.entries(responseSchemas)) responses[statusCode] = {
|
|
841
881
|
description: schema.description || `Response ${statusCode}`,
|
|
842
882
|
content: { "application/json": { schema } }
|
|
843
883
|
};
|
|
@@ -921,14 +961,12 @@ function buildOpenApiSpec(resources, options = {}, externalPaths) {
|
|
|
921
961
|
for (const tag of ext.tags) if (!tags.find((t) => t.name === tag.name)) tags.push(tag);
|
|
922
962
|
}
|
|
923
963
|
}
|
|
924
|
-
const externalSecuritySchemes =
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
...ext.schemas
|
|
931
|
-
}), {}) ?? {};
|
|
964
|
+
const externalSecuritySchemes = {};
|
|
965
|
+
const externalSchemas = {};
|
|
966
|
+
for (const ext of externalPaths ?? []) {
|
|
967
|
+
if (ext.securitySchemes) Object.assign(externalSecuritySchemes, ext.securitySchemes);
|
|
968
|
+
if (ext.schemas) Object.assign(externalSchemas, ext.schemas);
|
|
969
|
+
}
|
|
932
970
|
return {
|
|
933
971
|
openapi: "3.0.3",
|
|
934
972
|
info: {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as applyFieldWritePermissions, c as PermissionCheck, d as UserBase, f as getUserRoles, i as applyFieldReadPermissions, l as PermissionContext, n as FieldPermissionMap, o as fields, p as normalizeRoles, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission, u as PermissionResult } from "../fields-
|
|
2
|
-
import { A as requireRoles, C as allOf, D as not, E as denyAll, F as RequireAgentScopeOptions, I as RequireMandateOptions, L as requireAgentScope, M as when, N as applyPermissionResult, O as requireAuth, P as normalizePermissionResult, R as requireDPoP, S as createOrgPermissions, T as anyOf, _ as ConnectEventsOptions, a as presets_d_exports, b as PermissionEventBus, c as readOnly, d as requireOrgRole, f as requireScopeContext, g as createRoleHierarchy, h as RoleHierarchy, i as ownerWithAdminBypass, j as roles, k as requireOwnership, l as requireOrgInScope, m as requireTeamMembership, n as authenticated, o as publicRead, p as requireServiceScope, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as requireOrgMembership, v as DynamicPermissionMatrix, w as allowPublic, x as createDynamicPermissionMatrix, y as DynamicPermissionMatrixConfig, z as requireMandate } from "../index-
|
|
1
|
+
import { a as applyFieldWritePermissions, c as PermissionCheck, d as UserBase, f as getUserRoles, i as applyFieldReadPermissions, l as PermissionContext, n as FieldPermissionMap, o as fields, p as normalizeRoles, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission, u as PermissionResult } from "../fields-DqZLp5d6.mjs";
|
|
2
|
+
import { A as requireRoles, C as allOf, D as not, E as denyAll, F as RequireAgentScopeOptions, I as RequireMandateOptions, L as requireAgentScope, M as when, N as applyPermissionResult, O as requireAuth, P as normalizePermissionResult, R as requireDPoP, S as createOrgPermissions, T as anyOf, _ as ConnectEventsOptions, a as presets_d_exports, b as PermissionEventBus, c as readOnly, d as requireOrgRole, f as requireScopeContext, g as createRoleHierarchy, h as RoleHierarchy, i as ownerWithAdminBypass, j as roles, k as requireOwnership, l as requireOrgInScope, m as requireTeamMembership, n as authenticated, o as publicRead, p as requireServiceScope, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as requireOrgMembership, v as DynamicPermissionMatrix, w as allowPublic, x as createDynamicPermissionMatrix, y as DynamicPermissionMatrixConfig, z as requireMandate } from "../index-3L-adFJO.mjs";
|
|
3
3
|
export { ConnectEventsOptions, DynamicPermissionMatrix, DynamicPermissionMatrixConfig, FieldPermission, FieldPermissionMap, FieldPermissionType, PermissionCheck, PermissionContext, PermissionEventBus, PermissionResult, RequireAgentScopeOptions, RequireMandateOptions, RoleHierarchy, UserBase, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, presets_d_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as roles, C as allowPublic, D as requireAuth, E as not, F as applyPermissionResult, L as normalizePermissionResult, M as requireAgentScope, N as requireDPoP, O as requireOwnership, P as requireMandate, S as allOf, T as denyAll, _ as requireOrgMembership, a as presets_exports, b as requireServiceScope, c as readOnly, d as applyFieldWritePermissions, f as fields, g as requireOrgInScope, h as createOrgPermissions, i as ownerWithAdminBypass, j as when, k as requireRoles, l as createRoleHierarchy, m as createDynamicPermissionMatrix, n as authenticated, o as publicRead, p as resolveEffectiveRoles, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as applyFieldReadPermissions, v as requireOrgRole, w as anyOf, x as requireTeamMembership, y as requireScopeContext } from "../permissions-
|
|
1
|
+
import { A as roles, C as allowPublic, D as requireAuth, E as not, F as applyPermissionResult, L as normalizePermissionResult, M as requireAgentScope, N as requireDPoP, O as requireOwnership, P as requireMandate, S as allOf, T as denyAll, _ as requireOrgMembership, a as presets_exports, b as requireServiceScope, c as readOnly, d as applyFieldWritePermissions, f as fields, g as requireOrgInScope, h as createOrgPermissions, i as ownerWithAdminBypass, j as when, k as requireRoles, l as createRoleHierarchy, m as createDynamicPermissionMatrix, n as authenticated, o as publicRead, p as resolveEffectiveRoles, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as applyFieldReadPermissions, v as requireOrgRole, w as anyOf, x as requireTeamMembership, y as requireScopeContext } from "../permissions-CTxMrreC.mjs";
|
|
2
2
|
import { n as normalizeRoles, t as getUserRoles } from "../types-D57iXYb8.mjs";
|
|
3
3
|
export { adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { C as isService, S as isOrgInScope, a as getDPoPJkt, b as isElevated, d as getScopeContext, f as getScopeContextMap, g as getUserId, m as getTeamId, o as getMandate, p as getServiceScopes, u as getRequestScope, v as hasOrgAccess, x as isMember } from "./types-Bi0r0vjG.mjs";
|
|
3
3
|
import { t as getUserRoles } from "./types-D57iXYb8.mjs";
|
|
4
|
-
import { t as MemoryCacheStore } from "./memory-
|
|
4
|
+
import { t as MemoryCacheStore } from "./memory-QOLe11D5.mjs";
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
6
6
|
//#region src/permissions/applyPermissionResult.ts
|
|
7
7
|
/**
|
|
@@ -53,6 +53,7 @@ async function executePipeline(steps, ctx, handler, operation) {
|
|
|
53
53
|
let chain = () => handler(currentCtx);
|
|
54
54
|
for (let i = interceptors.length - 1; i >= 0; i--) {
|
|
55
55
|
const interceptor = interceptors[i];
|
|
56
|
+
if (!interceptor) continue;
|
|
56
57
|
const next = chain;
|
|
57
58
|
chain = () => interceptor.handler(currentCtx, next);
|
|
58
59
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ft as OperationFilter, It as PipelineConfig, Lt as PipelineContext, Mt as Guard, Nt as Interceptor, Pt as NextFunction, Rt as PipelineStep, yt as IControllerResponse, zt as Transform } from "../index-DBDgy6Hw.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/pipeline/guard.d.ts
|
|
4
4
|
interface GuardOptions {
|
package/dist/pipeline/index.mjs
CHANGED
package/dist/plugins/index.d.mts
CHANGED
|
@@ -1,66 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as
|
|
3
|
-
import { _ as HealthOptions, a as MetricsCollector, c as metricsPlugin, d as ssePlugin, f as CachingOptions, g as HealthCheck, h as cachingPlugin, i as MetricEntry, l as SSEOptions, m as _default$1, n as _default$7, o as MetricsOptions, p as CachingRule, r as versioningPlugin, s as _default$4, t as VersioningOptions, u as _default$6, v as _default$3, y as healthPlugin } from "../versioning-
|
|
4
|
-
import { i as errorHandlerPlugin, n as ErrorMapper, r as defaultIsDuplicateKeyError, t as ErrorHandlerOptions } from "../errorHandler-
|
|
5
|
-
import { t as TracingOptions } from "../tracing-
|
|
1
|
+
import { Kt as AnyRecord, Q as MiddlewareConfig, dt as RouteDefinition, mt as RouteSchemaOptions, nt as PresetHook } from "../index-DBDgy6Hw.mjs";
|
|
2
|
+
import { a as arcCorePlugin, i as _default, n as ArcCorePluginOptions, r as PluginMeta, t as ArcCore } from "../fastify-augmentation-CJm0vh-l.mjs";
|
|
3
|
+
import { _ as HealthOptions, a as MetricsCollector, c as metricsPlugin, d as ssePlugin, f as CachingOptions, g as HealthCheck, h as cachingPlugin, i as MetricEntry, l as SSEOptions, m as _default$1, n as _default$7, o as MetricsOptions, p as CachingRule, r as versioningPlugin, s as _default$4, t as VersioningOptions, u as _default$6, v as _default$3, y as healthPlugin } from "../versioning-5H4930tj.mjs";
|
|
4
|
+
import { i as errorHandlerPlugin, n as ErrorMapper, r as defaultIsDuplicateKeyError, t as ErrorHandlerOptions } from "../errorHandler-DuqTqeqn.mjs";
|
|
5
|
+
import { t as TracingOptions } from "../tracing-bRqqUxFO.mjs";
|
|
6
6
|
import { PaginatedResult } from "@classytic/repo-core/pagination";
|
|
7
7
|
import { FastifyInstance, FastifyPluginAsync } from "fastify";
|
|
8
8
|
import * as _$node_stream0 from "node:stream";
|
|
9
9
|
|
|
10
|
-
//#region src/core/arcCorePlugin.d.ts
|
|
11
|
-
interface ArcCorePluginOptions {
|
|
12
|
-
/** Enable event emission for CRUD operations (requires eventPlugin) */
|
|
13
|
-
emitEvents?: boolean;
|
|
14
|
-
/** Hook system instance (for testing/custom setup) */
|
|
15
|
-
hookSystem?: HookSystem;
|
|
16
|
-
/** Resource registry instance (for testing/custom setup) */
|
|
17
|
-
registry?: ResourceRegistry;
|
|
18
|
-
}
|
|
19
|
-
interface PluginMeta {
|
|
20
|
-
name: string;
|
|
21
|
-
version?: string;
|
|
22
|
-
options?: Record<string, unknown>;
|
|
23
|
-
registeredAt: string;
|
|
24
|
-
}
|
|
25
|
-
interface ArcCore {
|
|
26
|
-
/** Instance-scoped hook system */
|
|
27
|
-
hooks: HookSystem;
|
|
28
|
-
/** Instance-scoped resource registry */
|
|
29
|
-
registry: ResourceRegistry;
|
|
30
|
-
/** Whether event emission is enabled */
|
|
31
|
-
emitEvents: boolean;
|
|
32
|
-
/** External OpenAPI paths contributed by auth adapters or third-party integrations */
|
|
33
|
-
externalOpenApiPaths: ExternalOpenApiPaths[];
|
|
34
|
-
/** Registered plugins for introspection */
|
|
35
|
-
plugins: Map<string, PluginMeta>;
|
|
36
|
-
}
|
|
37
|
-
declare module "fastify" {
|
|
38
|
-
interface FastifyInstance {
|
|
39
|
-
/**
|
|
40
|
-
* Arc core decorator. Optional because:
|
|
41
|
-
*
|
|
42
|
-
* 1. Consumers who import any `@classytic/arc/*` subpath get this module
|
|
43
|
-
* augmentation merged into every `FastifyInstance` they see — even
|
|
44
|
-
* instances on apps that never register {@link arcCorePlugin}. Making
|
|
45
|
-
* it required would force those apps to assert or guard every
|
|
46
|
-
* property access.
|
|
47
|
-
* 2. Hosts that extend `FastifyInstance` to narrow `arc` to their own
|
|
48
|
-
* type (`interface X extends FastifyInstance { arc?: MyArc }`) were
|
|
49
|
-
* previously blocked because non-optional `arc: ArcCore` conflicts
|
|
50
|
-
* with the re-declaration. An optional field lets hosts re-declare
|
|
51
|
-
* with a compatible subtype without fighting TS.
|
|
52
|
-
*
|
|
53
|
-
* Inside Arc's own code, any call site that runs *after* `arcCorePlugin`
|
|
54
|
-
* has registered treats this as non-null — see the call sites in
|
|
55
|
-
* `factory/registerAuth.ts` and `factory/createApp.ts` which assert
|
|
56
|
-
* with `fastify.arc!` or narrow explicitly.
|
|
57
|
-
*/
|
|
58
|
-
arc?: ArcCore;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
declare const arcCorePlugin: FastifyPluginAsync<ArcCorePluginOptions>;
|
|
62
|
-
declare const _default: FastifyPluginAsync<ArcCorePluginOptions>;
|
|
63
|
-
//#endregion
|
|
64
10
|
//#region src/plugins/createPlugin.d.ts
|
|
65
11
|
interface PluginResourceResult {
|
|
66
12
|
/** Additional routes to add to the resource (v2.8 `RouteDefinition` shape) */
|
package/dist/plugins/index.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { p as MUTATION_OPERATIONS } from "../constants-
|
|
2
|
-
import { c as getOrgId } from "../types-
|
|
1
|
+
import { p as MUTATION_OPERATIONS } from "../constants-TrJVIJl0.mjs";
|
|
2
|
+
import { c as getOrgId } from "../types-Bi0r0vjG.mjs";
|
|
3
3
|
import { t as requestContext } from "../requestContext-SSaaTgW8.mjs";
|
|
4
4
|
import { t as hasEvents } from "../typeGuards-BzkXkvVv.mjs";
|
|
5
|
-
import { t as HookSystem } from "../HookSystem-
|
|
6
|
-
import { t as ResourceRegistry } from "../ResourceRegistry-
|
|
7
|
-
import { n as caching_default, t as cachingPlugin } from "../caching-
|
|
8
|
-
import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-
|
|
9
|
-
import { n as metrics_default, t as metricsPlugin } from "../metrics-
|
|
10
|
-
import { t as replyHelpersPlugin } from "../replyHelpers-
|
|
11
|
-
import { n as sse_default, t as ssePlugin } from "../sse-
|
|
12
|
-
import { n as versioning_default, t as versioningPlugin } from "../versioning-
|
|
5
|
+
import { t as HookSystem } from "../HookSystem-Cmf7-Etp.mjs";
|
|
6
|
+
import { t as ResourceRegistry } from "../ResourceRegistry-CzSzVK1m.mjs";
|
|
7
|
+
import { n as caching_default, t as cachingPlugin } from "../caching-8MfrrUYU.mjs";
|
|
8
|
+
import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-DNPzqaTT.mjs";
|
|
9
|
+
import { n as metrics_default, t as metricsPlugin } from "../metrics-B-PU4-Yu.mjs";
|
|
10
|
+
import { t as replyHelpersPlugin } from "../replyHelpers-boS5Rx26.mjs";
|
|
11
|
+
import { n as sse_default, t as ssePlugin } from "../sse-jh5OqFjR.mjs";
|
|
12
|
+
import { n as versioning_default, t as versioningPlugin } from "../versioning-CuIwUQZ2.mjs";
|
|
13
13
|
import { randomUUID } from "node:crypto";
|
|
14
14
|
import fp from "fastify-plugin";
|
|
15
15
|
//#region src/core/arcCorePlugin.ts
|
|
@@ -48,7 +48,7 @@ var LRUCache = class {
|
|
|
48
48
|
let count = 0;
|
|
49
49
|
for (const key of this.cache.keys()) {
|
|
50
50
|
const colonIdx = key.indexOf(":");
|
|
51
|
-
if ((colonIdx >= 0 ? key.slice(colonIdx + 1) : key).split("?")[0].startsWith(prefix)) {
|
|
51
|
+
if (((colonIdx >= 0 ? key.slice(colonIdx + 1) : key).split("?")[0] ?? "").startsWith(prefix)) {
|
|
52
52
|
this.cache.delete(key);
|
|
53
53
|
count++;
|
|
54
54
|
}
|
|
@@ -60,7 +60,7 @@ var LRUCache = class {
|
|
|
60
60
|
isPrefixLocked(key) {
|
|
61
61
|
if (this.invalidatedPrefixes.size === 0) return false;
|
|
62
62
|
const colonIdx = key.indexOf(":");
|
|
63
|
-
const pathOnly = (colonIdx >= 0 ? key.slice(colonIdx + 1) : key).split("?")[0];
|
|
63
|
+
const pathOnly = (colonIdx >= 0 ? key.slice(colonIdx + 1) : key).split("?")[0] ?? "";
|
|
64
64
|
const now = Date.now();
|
|
65
65
|
for (const [prefix, expiresAt] of this.invalidatedPrefixes.entries()) if (now > expiresAt) this.invalidatedPrefixes.delete(prefix);
|
|
66
66
|
else if (pathOnly.startsWith(prefix)) return true;
|
|
@@ -96,7 +96,7 @@ const responseCachePluginImpl = async (fastify, opts = {}) => {
|
|
|
96
96
|
const invalidateMethods = new Set(invalidateOn.map((m) => m.toUpperCase()));
|
|
97
97
|
/** Find TTL for a given URL path (seconds) */
|
|
98
98
|
function getTTL(url) {
|
|
99
|
-
const path = url.split("?")[0];
|
|
99
|
+
const path = url.split("?")[0] ?? url;
|
|
100
100
|
for (const rule of rules) if (path.startsWith(rule.match)) return rule.ttl;
|
|
101
101
|
return defaultTTL;
|
|
102
102
|
}
|
|
@@ -123,7 +123,7 @@ const responseCachePluginImpl = async (fastify, opts = {}) => {
|
|
|
123
123
|
if (!invalidateMethods.has(request.method.toUpperCase())) return;
|
|
124
124
|
const statusCode = reply.statusCode;
|
|
125
125
|
if (statusCode < 200 || statusCode >= 300) return;
|
|
126
|
-
const path = request.url.split("?")[0];
|
|
126
|
+
const path = request.url.split("?")[0] ?? request.url;
|
|
127
127
|
const segments = path.split("/").filter(Boolean);
|
|
128
128
|
const lastSegment = segments[segments.length - 1];
|
|
129
129
|
if (segments.length >= 2 && lastSegment != null && /^[0-9a-f]{8,}$|^\d+$/.test(lastSegment)) {
|
|
@@ -189,7 +189,7 @@ const responseCachePluginImpl = async (fastify, opts = {}) => {
|
|
|
189
189
|
const parts = event.type.split(".");
|
|
190
190
|
if (parts.length !== 2) return;
|
|
191
191
|
const [resource, action] = parts;
|
|
192
|
-
if (!resource || ![
|
|
192
|
+
if (!resource || !action || ![
|
|
193
193
|
"created",
|
|
194
194
|
"updated",
|
|
195
195
|
"deleted"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as traced, i as isTracingAvailable, n as _default, r as createSpan, t as TracingOptions } from "../tracing-
|
|
1
|
+
import { a as traced, i as isTracingAvailable, n as _default, r as createSpan, t as TracingOptions } from "../tracing-bRqqUxFO.mjs";
|
|
2
2
|
export { type TracingOptions, createSpan, isTracingAvailable, traced, _default as tracingPlugin };
|
|
@@ -58,7 +58,7 @@ try {
|
|
|
58
58
|
function createTracerProvider(options) {
|
|
59
59
|
if (!isAvailable || !NodeTracerProvider || !BatchSpanProcessor || !OTLPTraceExporter) return null;
|
|
60
60
|
const { serviceName = "@classytic/arc", serviceVersion, exporterUrl = "http://localhost:4318/v1/traces" } = options;
|
|
61
|
-
const resolvedVersion = serviceVersion ?? "2.
|
|
61
|
+
const resolvedVersion = serviceVersion ?? "2.16.1";
|
|
62
62
|
const exporter = new OTLPTraceExporter({ url: exporterUrl });
|
|
63
63
|
const provider = new NodeTracerProvider({ resource: { attributes: {
|
|
64
64
|
"service.name": serviceName,
|
|
@@ -58,7 +58,8 @@ function pluralize(word) {
|
|
|
58
58
|
if (UNCOUNTABLES.has(lower)) return word;
|
|
59
59
|
if (IRREGULARS[lower]) {
|
|
60
60
|
const plural = IRREGULARS[lower];
|
|
61
|
-
|
|
61
|
+
const firstChar = word.charAt(0);
|
|
62
|
+
return firstChar === firstChar.toUpperCase() ? plural.charAt(0).toUpperCase() + plural.slice(1) : plural;
|
|
62
63
|
}
|
|
63
64
|
if (lower.endsWith("fe")) return `${word.slice(0, -2)}ves`;
|
|
64
65
|
if (lower.endsWith("f") && !lower.endsWith("ff") && !lower.endsWith("roof") && !lower.endsWith("chief") && !lower.endsWith("belief")) return `${word.slice(0, -1)}ves`;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/testing/preloadResources.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalize an eager `import.meta.glob` result into a `ResourceLike[]`.
|
|
4
|
+
*
|
|
5
|
+
* Accepts either:
|
|
6
|
+
* - `{ import: 'default' }` form: values are the resource directly
|
|
7
|
+
* - default form: values are the full module — picks first export with `toPlugin()`
|
|
8
|
+
*
|
|
9
|
+
* Throws if any module doesn't yield a valid `ResourceLike`.
|
|
10
|
+
*/
|
|
11
|
+
function preloadResources(globResult) {
|
|
12
|
+
const resources = [];
|
|
13
|
+
for (const [path, value] of Object.entries(globResult)) {
|
|
14
|
+
const resource = pickResource(value);
|
|
15
|
+
if (!resource) throw new Error(`preloadResources: ${path} does not export a valid resource.\n Expected: a default export OR a named export with toPlugin().`);
|
|
16
|
+
resources.push(resource);
|
|
17
|
+
}
|
|
18
|
+
return resources.sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Normalize a lazy `import.meta.glob` result into a `Promise<ResourceLike[]>`.
|
|
22
|
+
*
|
|
23
|
+
* Use this when resources depend on prior bootstrap (e.g., engine init) and
|
|
24
|
+
* cannot be evaluated at import time of the preload file.
|
|
25
|
+
*/
|
|
26
|
+
async function preloadResourcesAsync(globResult) {
|
|
27
|
+
return (await Promise.all(Object.entries(globResult).map(async ([path, loader]) => {
|
|
28
|
+
const resource = pickResource(await loader());
|
|
29
|
+
if (!resource) throw new Error(`preloadResourcesAsync: ${path} does not export a valid resource.\n Expected: a default export OR a named export with toPlugin().`);
|
|
30
|
+
return resource;
|
|
31
|
+
}))).sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
|
|
32
|
+
}
|
|
33
|
+
function pickResource(value) {
|
|
34
|
+
if (!value || typeof value !== "object") return void 0;
|
|
35
|
+
if (typeof value.toPlugin === "function") return value;
|
|
36
|
+
const mod = value;
|
|
37
|
+
const candidates = [
|
|
38
|
+
mod.default,
|
|
39
|
+
mod.resource,
|
|
40
|
+
...Object.values(mod)
|
|
41
|
+
];
|
|
42
|
+
for (const c of candidates) if (c && typeof c === "object" && typeof c.toPlugin === "function") return c;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { preloadResourcesAsync as n, preloadResources as t };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as RequestScope } from "../types-
|
|
3
|
-
import { c as PermissionCheck } from "../fields-
|
|
4
|
-
import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-
|
|
1
|
+
import { rt as PresetResult } from "../index-DBDgy6Hw.mjs";
|
|
2
|
+
import { i as RequestScope } from "../types-CfapW2t8.mjs";
|
|
3
|
+
import { c as PermissionCheck } from "../fields-DqZLp5d6.mjs";
|
|
4
|
+
import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-HcAgP5Ni.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/presets/filesUpload.d.ts
|
|
7
7
|
interface FilesUploadPresetRoutes {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as NotFoundError, u as ValidationError } from "../errors-j4aJm1Wg.mjs";
|
|
2
|
-
import { c as getOrgId,
|
|
3
|
-
import { C as allowPublic, D as requireAuth } from "../permissions-
|
|
2
|
+
import { c as getOrgId, g as getUserId } from "../types-Bi0r0vjG.mjs";
|
|
3
|
+
import { C as allowPublic, D as requireAuth } from "../permissions-CTxMrreC.mjs";
|
|
4
4
|
import { t as multipartBody } from "../multipartBody-BOvVSVCD.mjs";
|
|
5
5
|
//#region src/presets/filesUpload.ts
|
|
6
6
|
const DEFAULT_FIELD_NAME = "file";
|
package/dist/presets/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Kt as AnyRecord, bt as IRequestContext, d as PaginationResult, rt as PresetResult, st as ResourceConfig, yt as IControllerResponse } from "../index-DBDgy6Hw.mjs";
|
|
2
2
|
import { FilesUploadPresetOptions, FilesUploadPresetPermissions, FilesUploadPresetRoutes, filesUploadPreset } from "./filesUpload.mjs";
|
|
3
3
|
import { MultiTenantOptions, TenantFieldSpec, multiTenantPreset } from "./multiTenant.mjs";
|
|
4
4
|
import { SearchHandler, SearchPresetOptions, SearchRouteConfig, searchPreset } from "./search.mjs";
|
package/dist/presets/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { multiTenantPreset } from "./multiTenant.mjs";
|
|
2
|
-
import { a as registerPreset, c as auditedPreset, d as ownedByUserPreset, i as getPreset, l as softDeletePreset, n as flexibleMultiTenantPreset, o as treePreset, r as getAvailablePresets, s as bulkPreset, t as applyPresets, u as slugLookupPreset } from "../presets-
|
|
2
|
+
import { a as registerPreset, c as auditedPreset, d as ownedByUserPreset, i as getPreset, l as softDeletePreset, n as flexibleMultiTenantPreset, o as treePreset, r as getAvailablePresets, s as bulkPreset, t as applyPresets, u as slugLookupPreset } from "../presets-C9BE6WaZ.mjs";
|
|
3
3
|
import { filesUploadPreset } from "./filesUpload.mjs";
|
|
4
4
|
import { searchPreset } from "./search.mjs";
|
|
5
5
|
export { applyPresets, auditedPreset, bulkPreset, filesUploadPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, searchPreset, slugLookupPreset, softDeletePreset, treePreset };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "../constants-
|
|
2
|
-
import {
|
|
1
|
+
import "../constants-TrJVIJl0.mjs";
|
|
2
|
+
import { b as isElevated, c as getOrgId, d as getScopeContext, m as getTeamId, u as getRequestScope, v as hasOrgAccess } from "../types-Bi0r0vjG.mjs";
|
|
3
3
|
//#region src/presets/multiTenant.ts
|
|
4
4
|
/**
|
|
5
5
|
* Resolve a single TenantFieldSpec against the current scope.
|
|
@@ -186,7 +186,8 @@ function multiTenantPreset(options = {}) {
|
|
|
186
186
|
create: [tenantInjection],
|
|
187
187
|
update: [getFilter("update"), tenantInjection],
|
|
188
188
|
delete: [getFilter("delete")],
|
|
189
|
-
aggregations: [strictTenantFilter]
|
|
189
|
+
aggregations: [strictTenantFilter],
|
|
190
|
+
tenantScope: [strictTenantFilter, tenantInjection]
|
|
190
191
|
}
|
|
191
192
|
};
|
|
192
193
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { c as PermissionCheck } from "../fields-
|
|
1
|
+
import { dt as RouteDefinition, ft as RouteMcpConfig, ht as ControllerHandler, rt as PresetResult } from "../index-DBDgy6Hw.mjs";
|
|
2
|
+
import { c as PermissionCheck } from "../fields-DqZLp5d6.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/presets/search.d.ts
|
|
5
5
|
/**
|
package/dist/presets/search.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { C as allowPublic, D as requireAuth, k as requireRoles } from "./permissions-
|
|
1
|
+
import { b as isElevated, n as PUBLIC_SCOPE } from "./types-Bi0r0vjG.mjs";
|
|
2
|
+
import { C as allowPublic, D as requireAuth, k as requireRoles } from "./permissions-CTxMrreC.mjs";
|
|
3
3
|
import { multiTenantPreset } from "./presets/multiTenant.mjs";
|
|
4
4
|
//#region src/presets/ownedByUser.ts
|
|
5
5
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import { t as MemoryCacheStore } from "./memory-
|
|
2
|
+
import { t as MemoryCacheStore } from "./memory-QOLe11D5.mjs";
|
|
3
3
|
import { t as hasEvents } from "./typeGuards-BzkXkvVv.mjs";
|
|
4
|
-
import { i as versionKey, r as tagVersionKey } from "./keys-
|
|
4
|
+
import { i as versionKey, r as tagVersionKey } from "./keys-DopsCuyQ.mjs";
|
|
5
5
|
import fp from "fastify-plugin";
|
|
6
6
|
//#region src/cache/QueryCache.ts
|
|
7
7
|
var QueryCache = class {
|