@classytic/arc 2.22.0 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BaseController-C6FlRWxF.mjs → BaseController--M8EMzt0.mjs} +92 -22
- package/dist/QueryCache-DOMT_iq7.d.mts +72 -0
- package/dist/{ResourceRegistry-7RnrEWNP.mjs → ResourceRegistry-y9Hnypus.mjs} +1 -0
- package/dist/actionPermissions-CAphcmUG.mjs +24 -0
- package/dist/applyPermissionResult-Tw4iXtlf.mjs +264 -0
- package/dist/audit/index.d.mts +32 -3
- package/dist/audit/index.mjs +7 -4
- package/dist/auth/index.d.mts +2 -2
- package/dist/auth/index.mjs +264 -260
- package/dist/{buildHandler-D_2ULWxZ.mjs → buildHandler-Dtwd8fdz.mjs} +1 -1
- package/dist/cache/index.d.mts +41 -3
- package/dist/cache/index.mjs +33 -4
- package/dist/cli/commands/describe.d.mts +1 -1
- package/dist/cli/commands/describe.mjs +1 -1
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +1 -1
- package/dist/cli/commands/init.mjs +1 -1
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/cli/index.mjs +2 -2
- package/dist/context/index.mjs +2 -64
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +4 -4
- package/dist/{core-b6fgFgnd.mjs → core-EUNu0u07.mjs} +298 -12
- package/dist/{createActionRouter-h1cEEaEX.mjs → createActionRouter-B6GvAuAX.mjs} +4 -3
- package/dist/{createAggregationRouter-B1C0kvTL.mjs → createAggregationRouter-wzwFa_dW.mjs} +3 -3
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-COpYKt2h.mjs → elevation-CIz1GjGm.mjs} +4 -3
- package/dist/{errorHandler-BTzXSwIg.mjs → errorHandler-Bq2OeEQL.mjs} +10 -7
- package/dist/{eventPlugin-A6EbthXR.d.mts → eventPlugin-Bg3cP2_u.d.mts} +38 -3
- package/dist/{eventPlugin-DJG2D7sy.mjs → eventPlugin-DrQ_FesK.mjs} +22 -4
- package/dist/events/index.d.mts +57 -314
- package/dist/events/index.mjs +168 -93
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +24 -2
- package/dist/factory/index.d.mts +21 -6
- package/dist/factory/index.mjs +58 -18
- package/dist/{fastify-augmentation-9_fuetB4.d.mts → fastify-augmentation-dPNBVeIj.d.mts} +25 -2
- package/dist/{generate-usRSdQmP.mjs → generate-D0wZupBg.mjs} +1 -1
- package/dist/headers-BvlQSDMB.mjs +45 -0
- package/dist/health-CB_m4S32.mjs +377 -0
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +7 -0
- package/dist/idempotency/index.mjs +32 -20
- package/dist/{index-ogIHvOjo.d.mts → index-BMnbzvtO.d.mts} +70 -4
- package/dist/{integrations/jobs.d.mts → index-CG4yqMDB.d.mts} +82 -2
- package/dist/{index-DbtgCOCj.d.mts → index-DPRH0Cme.d.mts} +46 -94
- package/dist/{module-B4u10iOJ.d.mts → index-KUoxjIq1.d.mts} +263 -23
- package/dist/{index-D8MKYGDa.d.mts → index-f4PTrk3B.d.mts} +37 -5
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +6 -5
- package/dist/{init-DleK3p9f.mjs → init-tlRSt667.mjs} +206 -205
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +3 -3
- package/dist/integrations/jobs/index.d.mts +2 -0
- package/dist/integrations/{jobs.mjs → jobs/index.mjs} +110 -67
- package/dist/integrations/mcp/index.d.mts +68 -5
- package/dist/integrations/mcp/index.mjs +2 -2
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/webhooks.d.mts +149 -22
- package/dist/integrations/webhooks.mjs +186 -42
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +1 -1
- package/dist/integrations/websocket.mjs +41 -14
- package/dist/{interface-C1_WLTMK.d.mts → interface-BGZCzOGL.d.mts} +24 -31
- package/dist/interface-n5hpKg1d.mjs +16 -0
- package/dist/{loadResourcesFromEntry-OMCvIEE7.mjs → loadResourcesFromEntry-kvGT6EcO.mjs} +1 -1
- package/dist/{mcpPlugin-ByA2tf6D.mjs → mcpPlugin-Cb7olw0j.mjs} +316 -45
- package/dist/{memory-CLXA2VeJ.mjs → memory-CmnzXE5Z.mjs} +29 -0
- package/dist/middleware/index.d.mts +17 -1
- package/dist/middleware/index.mjs +1 -1
- package/dist/migrations/index.d.mts +94 -44
- package/dist/migrations/index.mjs +196 -44
- package/dist/{multipartBody-CHEQSZ6G.mjs → multipartBody-D0eBvkeq.mjs} +17 -0
- package/dist/{openapi-BRpMZD7C.mjs → openapi-DrLtog_B.mjs} +4 -4
- package/dist/permissions/index.d.mts +3 -3
- package/dist/permissions/index.mjs +4 -3
- package/dist/{permissions-BJMuKMl7.mjs → permissions-BrtiBKGs.mjs} +305 -492
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/{actionPermissions-ze70xXJi.mjs → pipeline-BN5G05rd.mjs} +4 -27
- package/dist/plugins/index.d.mts +7 -78
- package/dist/plugins/index.mjs +14 -97
- package/dist/plugins/response-cache.mjs +1 -0
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/{index-BEu4wjbL.d.mts → preloadResources-0oe-JSSS.d.mts} +59 -50
- package/dist/{createApp-Ci7yG5gv.mjs → preloadResources-DfyngIN9.mjs} +240 -68
- package/dist/presets/filesUpload.d.mts +3 -3
- package/dist/presets/filesUpload.mjs +3 -3
- package/dist/presets/index.d.mts +2 -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/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-gw0ciIUD.mjs → presets-DwFDVKP0.mjs} +2 -2
- package/dist/{queryCachePlugin-DzqLN904.mjs → queryCachePlugin-DSGuSVLW.mjs} +39 -8
- package/dist/{queryCachePlugin-CfYWq-Ak.d.mts → queryCachePlugin-br4otiqF.d.mts} +2 -2
- package/dist/{registerRoute-xHc42fwB.mjs → rateLimit-DrED-C4v.mjs} +2 -109
- package/dist/realtime-Cuw_deA-.mjs +375 -0
- package/dist/{redis-stream-iVR2l7aS.d.mts → redis-stream-uIaauNpZ.d.mts} +22 -0
- package/dist/registerRoute-v0Wb6Plt.mjs +108 -0
- package/dist/registry/index.d.mts +2 -2
- package/dist/registry/index.mjs +1 -1
- package/dist/renewingLease-3cuQH7h8.mjs +44 -0
- package/dist/{requestContext-BZKOr13H.mjs → requestContext-MrlJwECf.mjs} +2 -2
- package/dist/schedules-CjOd2MG9.mjs +113 -0
- package/dist/{schemaConverter-Ds5reSGs.mjs → schemaConverter-DJvodiHj.mjs} +4 -1
- package/dist/{schemaIR-B-6SPe7g.mjs → schemaIR-Ca7ySNPx.mjs} +1 -1
- package/dist/schemas/index.d.mts +67 -67
- package/dist/schemas/index.mjs +2 -3
- package/dist/scim/index.mjs +1 -2
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +4 -4
- package/dist/scope-DfaPntpo.mjs +36 -0
- package/dist/simpleEqualityMatcher-Cg05HPsn.mjs +68 -0
- package/dist/{sse-CfUjwjDk.mjs → sse-BQ1w0dfl.mjs} +8 -31
- package/dist/sseStream-BQ7Qaynp.mjs +57 -0
- package/dist/testing/index.d.mts +4 -3
- package/dist/testing/index.mjs +2 -2
- package/dist/transactionContext-PNdoyLLm.mjs +64 -0
- package/dist/types/index.d.mts +4 -4
- package/dist/{types-bHblZ9YN.mjs → types-CSyCxl2V.mjs} +38 -7
- package/dist/{types-DH0GupI7.d.mts → types-DjC-KUCz.d.mts} +118 -20
- package/dist/{types-Csxga7d3.d.mts → types-Dmw-6Qeo.d.mts} +96 -4
- package/dist/{types-Bc42CUyk.d.mts → types-QFGc3Cjv.d.mts} +37 -2
- package/dist/usage/index.d.mts +3 -52
- package/dist/usage/index.mjs +0 -0
- package/dist/userHelpers-Cg_y3fBz.mjs +29 -0
- package/dist/utils/index.d.mts +90 -57
- package/dist/utils/index.mjs +7 -3
- package/dist/{utils-FhJ88TJE.mjs → utils-taUVD4p3.mjs} +47 -385
- package/dist/{validate-C2mGgSXg.mjs → validate-Bk44F2yT.mjs} +1 -1
- package/dist/{versioning-DLwklPlG.d.mts → versioning-DXgY5BUm.d.mts} +52 -31
- package/dist/{versioning-Dk-71iIz.mjs → versioning-gKWyryT3.mjs} +8 -1
- package/dist/{websocket-uuWqM6UY.d.mts → websocket-_Pd0CgR0.d.mts} +15 -1
- package/package.json +526 -453
- package/skills/arc/references/api-reference.md +3 -1
- package/skills/arc/references/integrations.md +20 -11
- package/skills/arc/references/production.md +734 -696
- package/dist/QueryCache-Z1B38koh.d.mts +0 -40
- package/dist/betterAuthOpenApi-CV1lxpRX.mjs +0 -2
- package/dist/health-ScyjIVo5.mjs +0 -202
- package/dist/requestId-5BhTVzBv.mjs +0 -113
- package/dist/scope-k15RXfcq.mjs +0 -64
- package/dist/types-XTApa8b6.mjs +0 -24
|
@@ -1,66 +1,128 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
|
|
2
2
|
import { arcLog, configureArcLogger, createPinoWriter } from "./logger/index.mjs";
|
|
3
|
-
import { n as PUBLIC_SCOPE } from "./types-
|
|
3
|
+
import { n as PUBLIC_SCOPE } from "./types-CSyCxl2V.mjs";
|
|
4
4
|
import { t as createTenantKeyGenerator } from "./rateLimitKey-BoWRH3e7.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { i as createRequestIdGenerator, r as mergeHealthChecks } from "./health-CB_m4S32.mjs";
|
|
6
6
|
import { t as parseJsonBody } from "./jsonBody-BlzAoGCe.mjs";
|
|
7
7
|
import Fastify from "fastify";
|
|
8
8
|
import qs from "qs";
|
|
9
|
-
//#region src/
|
|
9
|
+
//#region src/factory/module/resolve.ts
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* - `{ import: 'default' }` form: values are the resource directly
|
|
15
|
-
* - default form: values are the full module — picks first export with `toPlugin()`
|
|
16
|
-
*
|
|
17
|
-
* Throws if any module doesn't yield a valid `ResourceLike`.
|
|
11
|
+
* Resolve any module-input form to a concrete `ArcModule`. A thunk is invoked
|
|
12
|
+
* (this is where a dynamic `import()` fires); a promise (or plain module) is
|
|
13
|
+
* awaited. Called once per module at the start of the bootstrap phase.
|
|
18
14
|
*/
|
|
19
|
-
function
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
async function resolveModule(input) {
|
|
16
|
+
const resolved = typeof input === "function" ? await input() : await input;
|
|
17
|
+
if (!resolved || typeof resolved !== "object" || typeof resolved.name !== "string") throw new Error("[arc] a `modules` entry resolved to something that is not an ArcModule (expected an object with a string `name`). Check dynamic-import thunks return `createXModule(deps)` (or the module object), not the namespace.");
|
|
18
|
+
return resolved;
|
|
19
|
+
}
|
|
20
|
+
/** Resolve a `ModuleContribution` to a concrete array (array passthrough or factory call). */
|
|
21
|
+
async function resolveContribution(contribution, fastify) {
|
|
22
|
+
if (!contribution) return [];
|
|
23
|
+
return typeof contribution === "function" ? await contribution(fastify) : contribution;
|
|
27
24
|
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/factory/module/contributions.ts
|
|
28
27
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
28
|
+
* Collect every module's `healthChecks` in the caller's order. Fails at boot
|
|
29
|
+
* on a duplicate check `name` across modules, naming BOTH owning modules.
|
|
30
|
+
* The host's app-level checks are appended AFTER this (modules-first,
|
|
31
|
+
* host-last) by the caller.
|
|
33
32
|
*/
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}))).sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
|
|
33
|
+
function collectModuleHealthChecks(modules) {
|
|
34
|
+
return mergeHealthChecks(modules.map((module) => ({
|
|
35
|
+
owner: `module "${module.name}"`,
|
|
36
|
+
checks: module.healthChecks
|
|
37
|
+
})));
|
|
40
38
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Collect every module's `workflows`. Resolves factory contributions (so a
|
|
41
|
+
* factory can close over a container the caller has already decorated on
|
|
42
|
+
* `fastify`) and flattens to a single opaque array. Arc core deliberately
|
|
43
|
+
* does NOT validate or interpret the values — the streamline integration
|
|
44
|
+
* owns name/shape checks and registration. Called by the integration at init
|
|
45
|
+
* time, not by arc's boot pipeline (workflows depend on the integration's
|
|
46
|
+
* container).
|
|
47
|
+
*/
|
|
48
|
+
async function collectModuleWorkflows(fastify, modules) {
|
|
49
|
+
const out = [];
|
|
50
|
+
for (const m of modules) {
|
|
51
|
+
const wfs = await resolveContribution(m.workflows, fastify);
|
|
52
|
+
out.push(...wfs);
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Collect every module's `scheduledJobs`. Resolves factory contributions
|
|
58
|
+
* (after bootstraps) and fails at boot on a duplicate job `name` across
|
|
59
|
+
* modules. The caller passes the returned definitions to the canonical
|
|
60
|
+
* schedules plugin; factories must therefore be resolved only once.
|
|
61
|
+
*/
|
|
62
|
+
async function collectModuleScheduledJobs(fastify, modules) {
|
|
63
|
+
const owner = /* @__PURE__ */ new Map();
|
|
64
|
+
const out = [];
|
|
65
|
+
for (const m of modules) {
|
|
66
|
+
const jobs = await resolveContribution(m.scheduledJobs, fastify);
|
|
67
|
+
for (const job of jobs) {
|
|
68
|
+
const prior = owner.get(job.name);
|
|
69
|
+
if (prior !== void 0) throw new Error(`[arc] duplicate scheduled-job name "${job.name}" — declared by module "${prior}" and module "${m.name}". Scheduled-job names must be unique across the module graph.`);
|
|
70
|
+
owner.set(job.name, m.name);
|
|
71
|
+
out.push(job);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
51
75
|
}
|
|
52
76
|
//#endregion
|
|
53
|
-
//#region src/factory/module.ts
|
|
77
|
+
//#region src/factory/module/lifecycle.ts
|
|
54
78
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
79
|
+
* Subscribe every module's `eventHandlers` in dependency order (pass the
|
|
80
|
+
* `orderModules`-sorted list). Returns the ordered list of unsubscribe
|
|
81
|
+
* functions so the caller can tear them down at shutdown BEFORE module
|
|
82
|
+
* `onClose` (while module deps are still alive). Fails at boot on:
|
|
83
|
+
* - a duplicate NAMED handler across modules (attributing both owners);
|
|
84
|
+
* - a module declaring handlers while the event subsystem is unavailable.
|
|
85
|
+
* Resolves factory contributions (after bootstraps) so a handler can close over
|
|
86
|
+
* booted engines rather than a global getter.
|
|
58
87
|
*/
|
|
59
|
-
async function
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
88
|
+
async function subscribeModuleEventHandlers(fastify, modules) {
|
|
89
|
+
const unsubscribes = [];
|
|
90
|
+
const owner = /* @__PURE__ */ new Map();
|
|
91
|
+
try {
|
|
92
|
+
for (const m of modules) {
|
|
93
|
+
const handlers = await resolveContribution(m.eventHandlers, fastify);
|
|
94
|
+
if (handlers.length === 0) continue;
|
|
95
|
+
const bus = fastify.events;
|
|
96
|
+
if (!bus) throw new Error(`[arc] module "${m.name}" declares eventHandlers but the event subsystem is unavailable (fastify.events). Enable arcPlugins.events.`);
|
|
97
|
+
for (const def of handlers) {
|
|
98
|
+
if (def.name !== void 0) {
|
|
99
|
+
const prior = owner.get(def.name);
|
|
100
|
+
if (prior !== void 0) throw new Error(`[arc] duplicate event-handler name "${def.name}" — declared by module "${prior}" and module "${m.name}". Named event handlers must be unique across the module graph; prefix names with the owning module.`);
|
|
101
|
+
owner.set(def.name, m.name);
|
|
102
|
+
}
|
|
103
|
+
const patterns = Array.isArray(def.event) ? def.event : [def.event];
|
|
104
|
+
for (const pattern of patterns) unsubscribes.push(await bus.subscribe(pattern, def.handler));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return unsubscribes;
|
|
108
|
+
} catch (err) {
|
|
109
|
+
const rollbackErrors = await unsubscribeModuleEventHandlers(unsubscribes);
|
|
110
|
+
for (const rollbackError of rollbackErrors) fastify.log.error({ err: rollbackError }, "[arc] module event-handler activation rollback failed");
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** Best-effort reverse-order teardown; every unsubscribe is attempted. */
|
|
115
|
+
async function unsubscribeModuleEventHandlers(unsubscribes) {
|
|
116
|
+
const errors = [];
|
|
117
|
+
for (let index = unsubscribes.length - 1; index >= 0; index--) try {
|
|
118
|
+
await unsubscribes[index]?.();
|
|
119
|
+
} catch (err) {
|
|
120
|
+
errors.push(err);
|
|
121
|
+
}
|
|
122
|
+
return errors;
|
|
63
123
|
}
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/factory/module/order.ts
|
|
64
126
|
/**
|
|
65
127
|
* Order modules for composition by their `dependsOn` edges — a STABLE
|
|
66
128
|
* topological sort. Called once at the start of the bootstrap phase; every
|
|
@@ -151,6 +213,8 @@ function describeModuleCycle(remaining, byName) {
|
|
|
151
213
|
}
|
|
152
214
|
return `[arc] module dependency cycle: ${cycle ? cycle.join(" → ") : [...remaining].join(", ")}. Modules cannot dependsOn each other circularly — break it with a shared module both point at, or wire the softer direction through an event/port instead of a hard dependsOn.`;
|
|
153
215
|
}
|
|
216
|
+
//#endregion
|
|
217
|
+
//#region src/factory/module/index.ts
|
|
154
218
|
/**
|
|
155
219
|
* Identity helper for authoring a typed module — mirrors `defineResource`.
|
|
156
220
|
* Gives inference + a single obvious construction site; does no work.
|
|
@@ -200,7 +264,7 @@ const productionPreset = {
|
|
|
200
264
|
censor: "[REDACTED]"
|
|
201
265
|
}
|
|
202
266
|
},
|
|
203
|
-
trustProxy:
|
|
267
|
+
trustProxy: false,
|
|
204
268
|
helmet: { contentSecurityPolicy: { directives: {
|
|
205
269
|
defaultSrc: ["'self'"],
|
|
206
270
|
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
@@ -237,6 +301,7 @@ const productionPreset = {
|
|
|
237
301
|
underPressure: {
|
|
238
302
|
exposeStatusRoute: true,
|
|
239
303
|
maxEventLoopDelay: 3e3,
|
|
304
|
+
maxEventLoopUtilization: .98,
|
|
240
305
|
maxHeapUsedBytes: 1024 * 1024 * 1024,
|
|
241
306
|
maxRssBytes: 1024 * 1024 * 1024
|
|
242
307
|
}
|
|
@@ -402,7 +467,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
|
|
|
402
467
|
await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
|
|
403
468
|
trackPlugin("arc-core");
|
|
404
469
|
if (config.arcPlugins?.events !== false) {
|
|
405
|
-
const { default: eventPlugin } = await import("./eventPlugin-
|
|
470
|
+
const { default: eventPlugin } = await import("./eventPlugin-DrQ_FesK.mjs").then((n) => n.n);
|
|
406
471
|
const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
|
|
407
472
|
await fastify.register(eventPlugin, {
|
|
408
473
|
...eventOpts,
|
|
@@ -423,16 +488,27 @@ async function registerArcCore(fastify, config, trackPlugin) {
|
|
|
423
488
|
*
|
|
424
489
|
* @param modules - Plugin modules loaded by registerArcCore (avoids re-importing)
|
|
425
490
|
*/
|
|
426
|
-
async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
491
|
+
async function registerArcPlugins(fastify, config, trackPlugin, modules, moduleHealthChecks = []) {
|
|
427
492
|
const { requestIdPlugin, healthPlugin, gracefulShutdownPlugin } = modules;
|
|
428
493
|
if (config.arcPlugins?.requestId !== false) {
|
|
429
494
|
await fastify.register(requestIdPlugin);
|
|
430
495
|
trackPlugin("arc-request-id");
|
|
431
496
|
}
|
|
432
497
|
if (config.arcPlugins?.health !== false) {
|
|
433
|
-
const
|
|
498
|
+
const appHealth = typeof config.arcPlugins?.health === "object" && config.arcPlugins.health !== null ? config.arcPlugins.health : {};
|
|
499
|
+
const checks = mergeHealthChecks([{
|
|
500
|
+
owner: "the module graph",
|
|
501
|
+
checks: moduleHealthChecks
|
|
502
|
+
}, {
|
|
503
|
+
owner: "arcPlugins.health",
|
|
504
|
+
checks: appHealth.checks
|
|
505
|
+
}]);
|
|
506
|
+
const healthOpts = {
|
|
507
|
+
...appHealth,
|
|
508
|
+
checks
|
|
509
|
+
};
|
|
434
510
|
await fastify.register(healthPlugin, healthOpts);
|
|
435
|
-
trackPlugin("arc-health", healthOpts);
|
|
511
|
+
trackPlugin("arc-health", { checkCount: healthOpts.checks?.length ?? 0 });
|
|
436
512
|
}
|
|
437
513
|
if (config.arcPlugins?.gracefulShutdown !== false) {
|
|
438
514
|
await fastify.register(gracefulShutdownPlugin);
|
|
@@ -445,9 +521,9 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
445
521
|
trackPlugin("arc-caching", opts);
|
|
446
522
|
}
|
|
447
523
|
if (config.arcPlugins?.queryCache) {
|
|
448
|
-
const { queryCachePlugin } = await import("./queryCachePlugin-
|
|
524
|
+
const { queryCachePlugin } = await import("./queryCachePlugin-DSGuSVLW.mjs").then((n) => n.n);
|
|
449
525
|
const opts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
|
|
450
|
-
const store = config.stores?.queryCache ?? new (await (import("./memory-
|
|
526
|
+
const store = config.stores?.queryCache ?? new (await (import("./memory-CmnzXE5Z.mjs").then((n) => n.n))).MemoryCacheStore();
|
|
451
527
|
await fastify.register(queryCachePlugin, {
|
|
452
528
|
store,
|
|
453
529
|
...opts
|
|
@@ -456,11 +532,18 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
456
532
|
}
|
|
457
533
|
if (config.arcPlugins?.sse) if (config.arcPlugins?.events === false) fastify.log.warn("SSE plugin requires events plugin (arcPlugins.events). SSE disabled.");
|
|
458
534
|
else {
|
|
459
|
-
const { default: ssePlugin } = await import("./sse-
|
|
535
|
+
const { default: ssePlugin } = await import("./sse-BQ1w0dfl.mjs").then((n) => n.r);
|
|
460
536
|
const opts = config.arcPlugins.sse === true ? {} : config.arcPlugins.sse;
|
|
461
537
|
await fastify.register(ssePlugin, opts);
|
|
462
538
|
trackPlugin("arc-sse", opts);
|
|
463
539
|
}
|
|
540
|
+
if (config.arcPlugins?.realtime) if (config.arcPlugins?.events === false) fastify.log.warn("Realtime plugin requires events plugin (arcPlugins.events). Realtime disabled.");
|
|
541
|
+
else {
|
|
542
|
+
const { default: realtimePlugin } = await import("./realtime-Cuw_deA-.mjs").then((n) => n.r);
|
|
543
|
+
const opts = config.arcPlugins.realtime === true ? {} : config.arcPlugins.realtime;
|
|
544
|
+
await fastify.register(realtimePlugin, opts);
|
|
545
|
+
trackPlugin("arc-realtime", opts);
|
|
546
|
+
}
|
|
464
547
|
if (config.arcPlugins?.metrics) {
|
|
465
548
|
const { default: metricsPlugin } = await import("./metrics-fdxI5mn_.mjs").then((n) => n.r);
|
|
466
549
|
const opts = config.arcPlugins.metrics === true ? {} : config.arcPlugins.metrics;
|
|
@@ -468,7 +551,7 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
468
551
|
trackPlugin("arc-metrics", opts);
|
|
469
552
|
}
|
|
470
553
|
if (config.arcPlugins?.versioning) {
|
|
471
|
-
const { default: versioningPlugin } = await import("./versioning-
|
|
554
|
+
const { default: versioningPlugin } = await import("./versioning-gKWyryT3.mjs").then((n) => n.r);
|
|
472
555
|
await fastify.register(versioningPlugin, config.arcPlugins.versioning);
|
|
473
556
|
trackPlugin("arc-versioning", config.arcPlugins.versioning);
|
|
474
557
|
}
|
|
@@ -537,7 +620,7 @@ async function registerAuth(fastify, config, trackPlugin) {
|
|
|
537
620
|
*/
|
|
538
621
|
async function registerElevation(fastify, config, trackPlugin) {
|
|
539
622
|
if (!config.elevation) return;
|
|
540
|
-
const { elevationPlugin } = await import("./elevation-
|
|
623
|
+
const { elevationPlugin } = await import("./elevation-CIz1GjGm.mjs").then((n) => n.r);
|
|
541
624
|
await fastify.register(elevationPlugin, config.elevation);
|
|
542
625
|
trackPlugin("arc-elevation", config.elevation);
|
|
543
626
|
fastify.log.debug("Elevation plugin enabled");
|
|
@@ -552,7 +635,7 @@ async function registerElevation(fastify, config, trackPlugin) {
|
|
|
552
635
|
*/
|
|
553
636
|
async function registerErrorHandler(fastify, config, trackPlugin, moduleErrorMappers) {
|
|
554
637
|
if (config.errorHandler === false) return;
|
|
555
|
-
const { errorHandlerPlugin } = await import("./errorHandler-
|
|
638
|
+
const { errorHandlerPlugin } = await import("./errorHandler-Bq2OeEQL.mjs").then((n) => n.r);
|
|
556
639
|
let errorOpts = typeof config.errorHandler === "object" ? config.errorHandler : { includeStack: config.preset !== "production" };
|
|
557
640
|
if (moduleErrorMappers && moduleErrorMappers.length > 0) errorOpts = {
|
|
558
641
|
...errorOpts,
|
|
@@ -773,9 +856,34 @@ async function registerResources(fastify, config, preResolvedModules) {
|
|
|
773
856
|
throw new Error(`[arc] module "${m.name}" afterResources() threw: ${msg}`, { cause: err });
|
|
774
857
|
}
|
|
775
858
|
}
|
|
776
|
-
|
|
859
|
+
const scheduledJobs = await collectModuleScheduledJobs(fastify, modules);
|
|
860
|
+
if (scheduledJobs.length > 0) {
|
|
861
|
+
if (config.arcPlugins?.schedules === false) throw new Error("[arc] modules declare scheduledJobs but arcPlugins.schedules is false. Enable the scheduler or remove the declarations.");
|
|
862
|
+
if (fastify.hasDecorator("getScheduleStats")) throw new Error("[arc] modules declare scheduledJobs but schedulesPlugin was already registered manually. Configure their runner through arcPlugins.schedules so Arc can compose one schedule table.");
|
|
863
|
+
const frozenJobs = Object.freeze(scheduledJobs.map((job) => Object.freeze({ ...job })));
|
|
864
|
+
const scheduleOptions = typeof config.arcPlugins?.schedules === "object" ? config.arcPlugins.schedules : {};
|
|
865
|
+
const { default: schedulesPlugin } = await import("./schedules-CjOd2MG9.mjs").then((n) => n.r);
|
|
866
|
+
await fastify.register(schedulesPlugin, {
|
|
867
|
+
...scheduleOptions,
|
|
868
|
+
schedules: frozenJobs
|
|
869
|
+
});
|
|
870
|
+
if (fastify.arc) {
|
|
871
|
+
fastify.arc.scheduledJobs = frozenJobs;
|
|
872
|
+
fastify.arc.plugins.set("arc-schedules", {
|
|
873
|
+
name: "arc-schedules",
|
|
874
|
+
options: { scheduleCount: frozenJobs.length },
|
|
875
|
+
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
const eventUnsubscribes = await subscribeModuleEventHandlers(fastify, modules);
|
|
880
|
+
if (config.afterResources) try {
|
|
777
881
|
await config.afterResources(fastify);
|
|
778
882
|
fastify.log.debug("afterResources hook executed");
|
|
883
|
+
} catch (err) {
|
|
884
|
+
const rollbackErrors = await unsubscribeModuleEventHandlers(eventUnsubscribes);
|
|
885
|
+
for (const rollbackError of rollbackErrors) fastify.log.error({ err: rollbackError }, "[arc] module event-handler rollback after afterResources failure failed");
|
|
886
|
+
throw err;
|
|
779
887
|
}
|
|
780
888
|
if (config.onReady) {
|
|
781
889
|
const onReady = config.onReady;
|
|
@@ -785,7 +893,9 @@ async function registerResources(fastify, config, preResolvedModules) {
|
|
|
785
893
|
}
|
|
786
894
|
const closers = modules.filter((m) => m.onClose).reverse();
|
|
787
895
|
const appOnClose = config.onClose;
|
|
788
|
-
if (closers.length || appOnClose) fastify.addHook("onClose", async () => {
|
|
896
|
+
if (closers.length || appOnClose || eventUnsubscribes.length) fastify.addHook("onClose", async () => {
|
|
897
|
+
const unsubscribeErrors = await unsubscribeModuleEventHandlers(eventUnsubscribes);
|
|
898
|
+
for (const err of unsubscribeErrors) fastify.log.error({ err }, "[arc] module event-handler shutdown unsubscribe failed");
|
|
789
899
|
for (const m of closers) await m.onClose?.(fastify);
|
|
790
900
|
if (appOnClose) await appOnClose(fastify);
|
|
791
901
|
});
|
|
@@ -1011,7 +1121,21 @@ async function registerUtilityPlugins(fastify, config) {
|
|
|
1011
1121
|
if (config.preset === "production") fastify.log.warn("Response compression is not enabled (Fastify 5 stream issues). Use a reverse proxy (Nginx, Caddy, Cloudflare) for gzip/brotli in production.");
|
|
1012
1122
|
if (config.underPressure !== false) {
|
|
1013
1123
|
const underPressure = await loadPlugin("underPressure");
|
|
1014
|
-
|
|
1124
|
+
const hostConfig = config.underPressure;
|
|
1125
|
+
const effective = hostConfig ?? {
|
|
1126
|
+
exposeStatusRoute: true,
|
|
1127
|
+
maxEventLoopDelay: 3e3,
|
|
1128
|
+
maxEventLoopUtilization: .98
|
|
1129
|
+
};
|
|
1130
|
+
if (config.preset === "production" && hostConfig && ![
|
|
1131
|
+
"maxEventLoopDelay",
|
|
1132
|
+
"maxEventLoopUtilization",
|
|
1133
|
+
"maxHeapUsedBytes",
|
|
1134
|
+
"maxRssBytes",
|
|
1135
|
+
"pressureHandler",
|
|
1136
|
+
"healthCheck"
|
|
1137
|
+
].some((key) => key in hostConfig)) fastify.log.warn("[arc] underPressure is configured without any pressure threshold (maxEventLoopDelay / maxEventLoopUtilization / maxHeapUsedBytes / maxRssBytes) — it will monitor but never shed load. Set at least an event-loop threshold, and size heap/RSS limits from your container memory limit.");
|
|
1138
|
+
await fastify.register(underPressure, effective);
|
|
1015
1139
|
fastify.log.debug("Health monitoring (under-pressure) enabled");
|
|
1016
1140
|
}
|
|
1017
1141
|
if (config.sensible !== false) {
|
|
@@ -1184,6 +1308,8 @@ function validateDistributedRuntime(options) {
|
|
|
1184
1308
|
hint: "a Redis-backed query-cache adapter"
|
|
1185
1309
|
});
|
|
1186
1310
|
}
|
|
1311
|
+
const schedules = options.arcPlugins?.schedules;
|
|
1312
|
+
if (schedules && typeof schedules === "object" && schedules.enabled !== false && !schedules.lock) deferredWarnings.push("runtime: 'distributed' — schedules configured without a `lock` adapter. EVERY replica will fire every schedule tick. Pass an ecosystem lock (e.g. createMongoLockAdapter) under arcPlugins.schedules.lock for single-firer leases.");
|
|
1187
1313
|
if (missing.length > 0) {
|
|
1188
1314
|
const lines = missing.map((m) => ` • ${m.key.padEnd(20)} → ${m.hint}`).join("\n");
|
|
1189
1315
|
throw new Error(`[Arc] runtime: 'distributed' requires durable (Redis/MongoDB) adapters, not memory.
|
|
@@ -1220,8 +1346,10 @@ async function createApp(options) {
|
|
|
1220
1346
|
...options.preset ? getPreset(options.preset) : {},
|
|
1221
1347
|
...options
|
|
1222
1348
|
};
|
|
1349
|
+
const inheritedTrustProxyDefault = options.preset === "production" && options.trustProxy === void 0;
|
|
1223
1350
|
const resolvedModules = orderModules(await Promise.all((config.modules ?? []).map((m) => resolveModule(m))));
|
|
1224
1351
|
const moduleErrorMappers = resolvedModules.flatMap((m) => m.errorMappers ?? []);
|
|
1352
|
+
const moduleHealthChecks = collectModuleHealthChecks(resolvedModules);
|
|
1225
1353
|
const resolvedLogger = resolveLoggerConfig(config.logger);
|
|
1226
1354
|
const fastify = Fastify({
|
|
1227
1355
|
logger: resolvedLogger,
|
|
@@ -1255,12 +1383,7 @@ async function createApp(options) {
|
|
|
1255
1383
|
writer: createPinoWriter(fastify.log)
|
|
1256
1384
|
});
|
|
1257
1385
|
for (const warning of deferredWarnings) fastify.log.warn(warning);
|
|
1258
|
-
if (
|
|
1259
|
-
const { TypeBoxValidatorCompiler } = await import("@fastify/type-provider-typebox");
|
|
1260
|
-
fastify.setValidatorCompiler(TypeBoxValidatorCompiler);
|
|
1261
|
-
} catch {
|
|
1262
|
-
fastify.log.warn("typeProvider: \"typebox\" requested but @fastify/type-provider-typebox is not installed.");
|
|
1263
|
-
}
|
|
1386
|
+
if (inheritedTrustProxyDefault) fastify.log.warn("[arc] preset: 'production' now defaults to trustProxy: false (fail-closed; was true before 2.24). If this app runs behind a load balancer or reverse proxy, request.ip is currently the PROXY's address — rate-limit keys collapse onto one bucket and audit logs record the wrong client. Set trustProxy explicitly: a hop count (trustProxy: 1), a CIDR allow-list ('10.0.0.0/8'), a resolver function, or false if clients truly connect directly.");
|
|
1264
1387
|
fastify.removeContentTypeParser("application/json");
|
|
1265
1388
|
fastify.addContentTypeParser("application/json", { parseAs: "string" }, (_req, body, done) => {
|
|
1266
1389
|
try {
|
|
@@ -1280,7 +1403,12 @@ async function createApp(options) {
|
|
|
1280
1403
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1281
1404
|
});
|
|
1282
1405
|
};
|
|
1283
|
-
|
|
1406
|
+
const arcModules = await registerArcCore(fastify, config, trackPlugin);
|
|
1407
|
+
if (fastify.arc) {
|
|
1408
|
+
fastify.arc.healthChecks = Object.freeze([...moduleHealthChecks]);
|
|
1409
|
+
fastify.arc.moduleDefinitions = Object.freeze([...resolvedModules]);
|
|
1410
|
+
}
|
|
1411
|
+
await registerArcPlugins(fastify, config, trackPlugin, arcModules, moduleHealthChecks);
|
|
1284
1412
|
decorateRequestScope(fastify);
|
|
1285
1413
|
await registerAuth(fastify, config, trackPlugin);
|
|
1286
1414
|
await registerElevation(fastify, config, trackPlugin);
|
|
@@ -1338,4 +1466,48 @@ const ArcFactory = {
|
|
|
1338
1466
|
}
|
|
1339
1467
|
};
|
|
1340
1468
|
//#endregion
|
|
1341
|
-
|
|
1469
|
+
//#region src/factory/preloadResources.ts
|
|
1470
|
+
/**
|
|
1471
|
+
* Normalize an eager `import.meta.glob` result into a `ResourceLike[]`.
|
|
1472
|
+
*
|
|
1473
|
+
* Accepts either:
|
|
1474
|
+
* - `{ import: 'default' }` form: values are the resource directly
|
|
1475
|
+
* - default form: values are the full module — picks first export with `toPlugin()`
|
|
1476
|
+
*
|
|
1477
|
+
* Throws if any module doesn't yield a valid `ResourceLike`.
|
|
1478
|
+
*/
|
|
1479
|
+
function preloadResources(globResult) {
|
|
1480
|
+
const resources = [];
|
|
1481
|
+
for (const [path, value] of Object.entries(globResult)) {
|
|
1482
|
+
const resource = pickResource(value);
|
|
1483
|
+
if (!resource) throw new Error(`preloadResources: ${path} does not export a valid resource.\n Expected: a default export OR a named export with toPlugin().`);
|
|
1484
|
+
resources.push(resource);
|
|
1485
|
+
}
|
|
1486
|
+
return resources.sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
|
|
1487
|
+
}
|
|
1488
|
+
/**
|
|
1489
|
+
* Normalize a lazy `import.meta.glob` result into a `Promise<ResourceLike[]>`.
|
|
1490
|
+
*
|
|
1491
|
+
* Use this when resources depend on prior bootstrap (e.g., engine init) and
|
|
1492
|
+
* cannot be evaluated at import time of the preload file.
|
|
1493
|
+
*/
|
|
1494
|
+
async function preloadResourcesAsync(globResult) {
|
|
1495
|
+
return (await Promise.all(Object.entries(globResult).map(async ([path, loader]) => {
|
|
1496
|
+
const resource = pickResource(await loader());
|
|
1497
|
+
if (!resource) throw new Error(`preloadResourcesAsync: ${path} does not export a valid resource.\n Expected: a default export OR a named export with toPlugin().`);
|
|
1498
|
+
return resource;
|
|
1499
|
+
}))).sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
|
|
1500
|
+
}
|
|
1501
|
+
function pickResource(value) {
|
|
1502
|
+
if (!value || typeof value !== "object") return void 0;
|
|
1503
|
+
if (typeof value.toPlugin === "function") return value;
|
|
1504
|
+
const mod = value;
|
|
1505
|
+
const candidates = [
|
|
1506
|
+
mod.default,
|
|
1507
|
+
mod.resource,
|
|
1508
|
+
...Object.values(mod)
|
|
1509
|
+
];
|
|
1510
|
+
for (const c of candidates) if (c && typeof c === "object" && typeof c.toPlugin === "function") return c;
|
|
1511
|
+
}
|
|
1512
|
+
//#endregion
|
|
1513
|
+
export { collectModuleScheduledJobs as _, createApp_exports as a, resolveModule as b, getPreset as c, workerPreset as d, defineModule as f, collectModuleHealthChecks as g, subscribeModuleEventHandlers as h, createApp as i, productionPreset as l, orderModules as m, preloadResourcesAsync as n, developmentPreset as o, getModuleExports as p, ArcFactory as r, edgePreset as s, preloadResources as t, testingPreset as u, collectModuleWorkflows as v, resolveContribution as y };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Y as PresetResult } from "../index-
|
|
2
|
-
import { i as RequestScope } from "../types-
|
|
3
|
-
import { t as PermissionCheck } from "../types-
|
|
1
|
+
import { Y as PresetResult } from "../index-DPRH0Cme.mjs";
|
|
2
|
+
import { i as RequestScope } from "../types-DjC-KUCz.mjs";
|
|
3
|
+
import { t as PermissionCheck } from "../types-Dmw-6Qeo.mjs";
|
|
4
4
|
import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-DLUZ04kK.mjs";
|
|
5
5
|
//#region src/presets/filesUpload.d.ts
|
|
6
6
|
interface FilesUploadPresetRoutes {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { i as NotFoundError, u as ValidationError } from "../errors-DkO8Nk6-.mjs";
|
|
2
|
-
import { c as getOrgId, g as getUserId } from "../types-
|
|
3
|
-
import {
|
|
4
|
-
import { t as multipartBody } from "../multipartBody-
|
|
2
|
+
import { c as getOrgId, g as getUserId } from "../types-CSyCxl2V.mjs";
|
|
3
|
+
import { A as requireAuth, E as allowPublic } from "../permissions-BrtiBKGs.mjs";
|
|
4
|
+
import { t as multipartBody } from "../multipartBody-D0eBvkeq.mjs";
|
|
5
5
|
//#region src/presets/filesUpload.ts
|
|
6
6
|
const DEFAULT_FIELD_NAME = "file";
|
|
7
7
|
const DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
|
package/dist/presets/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Rt as IControllerResponse, U as ResourceConfig, Y as PresetResult, d as PaginationResult,
|
|
1
|
+
import { Rt as IControllerResponse, U as ResourceConfig, Y as PresetResult, d as PaginationResult, zt as IRequestContext } from "../index-DPRH0Cme.mjs";
|
|
2
|
+
import { c as AnyRecord } from "../types-Dmw-6Qeo.mjs";
|
|
2
3
|
import { FilesUploadPresetOptions, FilesUploadPresetPermissions, FilesUploadPresetRoutes, filesUploadPreset } from "./filesUpload.mjs";
|
|
3
4
|
import { MultiTenantOptions, TenantFieldSpec, multiTenantPreset } from "./multiTenant.mjs";
|
|
4
5
|
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-DwFDVKP0.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,4 +1,4 @@
|
|
|
1
|
-
import { X as CrudRouteKey, Y as PresetResult } from "../index-
|
|
1
|
+
import { X as CrudRouteKey, Y as PresetResult } from "../index-DPRH0Cme.mjs";
|
|
2
2
|
//#region src/presets/multiTenant.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* One tenant dimension for multi-field filtering. Discriminated by source:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../constants-DNre0wRg.mjs";
|
|
2
|
-
import { b as isElevated, c as getOrgId, d as getScopeContext, m as getTeamId, u as getRequestScope, v as hasOrgAccess } from "../types-
|
|
2
|
+
import { b as isElevated, c as getOrgId, d as getScopeContext, m as getTeamId, u as getRequestScope, v as hasOrgAccess } from "../types-CSyCxl2V.mjs";
|
|
3
3
|
//#region src/presets/multiTenant.ts
|
|
4
4
|
/**
|
|
5
5
|
* Resolve a single TenantFieldSpec against the current scope.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { At as RouteDefinition, Pt as ControllerHandler, Y as PresetResult, jt as RouteMcpConfig } from "../index-
|
|
2
|
-
import { t as PermissionCheck } from "../types-
|
|
1
|
+
import { At as RouteDefinition, Pt as ControllerHandler, Y as PresetResult, jt as RouteMcpConfig } from "../index-DPRH0Cme.mjs";
|
|
2
|
+
import { t as PermissionCheck } from "../types-Dmw-6Qeo.mjs";
|
|
3
3
|
//#region src/presets/search.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Search Preset — backend-agnostic search / vector / embed routes
|
package/dist/presets/search.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as isElevated, n as PUBLIC_SCOPE } from "./types-
|
|
2
|
-
import {
|
|
1
|
+
import { b as isElevated, n as PUBLIC_SCOPE } from "./types-CSyCxl2V.mjs";
|
|
2
|
+
import { A as requireAuth, E as allowPublic, M as requireRoles } from "./permissions-BrtiBKGs.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 "./rolldown-runtime-8H4AJuhK.mjs";
|
|
2
|
-
import { t as MemoryCacheStore } from "./memory-CLXA2VeJ.mjs";
|
|
3
2
|
import { t as hasEvents } from "./typeGuards-C9KXUly6.mjs";
|
|
4
3
|
import { i as versionKey, r as tagVersionKey } from "./keys-Cd316u_y.mjs";
|
|
4
|
+
import { t as MemoryCacheStore } from "./memory-CmnzXE5Z.mjs";
|
|
5
5
|
import fp from "fastify-plugin";
|
|
6
6
|
//#region src/cache/QueryCache.ts
|
|
7
7
|
var QueryCache = class {
|
|
@@ -33,7 +33,9 @@ var QueryCache = class {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
async set(key, data, config) {
|
|
36
|
-
const
|
|
36
|
+
const baseStaleTimeSec = config.staleTime ?? 0;
|
|
37
|
+
const jitter = config.jitter ?? 0;
|
|
38
|
+
const staleTimeSec = jitter > 0 ? Math.max(0, baseStaleTimeSec * (1 + (Math.random() * 2 - 1) * jitter)) : baseStaleTimeSec;
|
|
37
39
|
const totalTtlSec = staleTimeSec + (config.gcTime ?? 60);
|
|
38
40
|
const now = Date.now();
|
|
39
41
|
const envelope = {
|
|
@@ -54,9 +56,7 @@ var QueryCache = class {
|
|
|
54
56
|
}
|
|
55
57
|
/** Bump resource version — orphans all cached queries for this resource */
|
|
56
58
|
async bumpResourceVersion(resource) {
|
|
57
|
-
|
|
58
|
-
const newVersion = Date.now();
|
|
59
|
-
await this.store.set(key, newVersion, 1440 * 60);
|
|
59
|
+
await this.bumpVersion(versionKey(resource));
|
|
60
60
|
}
|
|
61
61
|
/** Get current version for a tag */
|
|
62
62
|
async getTagVersion(tag) {
|
|
@@ -64,11 +64,42 @@ var QueryCache = class {
|
|
|
64
64
|
}
|
|
65
65
|
/** Bump tag version — orphans all cached queries tagged with this tag */
|
|
66
66
|
async bumpTagVersion(tag) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
await this.bumpVersion(tagVersionKey(tag));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Version-bump semantics:
|
|
71
|
+
*
|
|
72
|
+
* - `store.increment` present (Redis `INCR`) — atomic and strictly
|
|
73
|
+
* monotonic across replicas; concurrent bumps can never collide or
|
|
74
|
+
* go backwards.
|
|
75
|
+
* - fallback — read-modify-write with `max(now, current + 1)`: two
|
|
76
|
+
* bumps in the same millisecond and clock regressions still advance
|
|
77
|
+
* the version. Concurrent bumps from DIFFERENT replicas can lose one
|
|
78
|
+
* write, which is why distributed hosts should use an incrementing
|
|
79
|
+
* store (`runtime: 'distributed'` already requires a shared one).
|
|
80
|
+
*
|
|
81
|
+
* Version keys must outlive every derived cache entry — that invariant
|
|
82
|
+
* is what makes version invalidation sound (a version key expiring back
|
|
83
|
+
* to 0 would make entries written under the pre-reset version
|
|
84
|
+
* addressable again). The 1-year TTL applies with the repo-core
|
|
85
|
+
* TTL-ON-CREATE semantics, so a version key expires one year after its
|
|
86
|
+
* FIRST bump — safe, because a revived collision would need an entry to
|
|
87
|
+
* outlive that reset and entry TTLs are minutes-scale (staleTime +
|
|
88
|
+
* gcTime). The read-modify-write fallback uses plain `set`, which
|
|
89
|
+
* refreshes the TTL per bump — strictly longer-lived, equally safe.
|
|
90
|
+
*/
|
|
91
|
+
async bumpVersion(key) {
|
|
92
|
+
if (typeof this.store.increment === "function") {
|
|
93
|
+
await this.store.increment(key, 1, VERSION_TTL_SECONDS);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const current = await this.store.get(key);
|
|
97
|
+
const next = Math.max(Date.now(), (current ?? 0) + 1);
|
|
98
|
+
await this.store.set(key, next, VERSION_TTL_SECONDS);
|
|
70
99
|
}
|
|
71
100
|
};
|
|
101
|
+
/** See `bumpVersion` — effectively non-expiring, refreshed on every bump. */
|
|
102
|
+
const VERSION_TTL_SECONDS = 365 * 24 * 60 * 60;
|
|
72
103
|
//#endregion
|
|
73
104
|
//#region src/cache/queryCachePlugin.ts
|
|
74
105
|
var queryCachePlugin_exports = /* @__PURE__ */ __exportAll({ queryCachePlugin: () => queryCachePlugin });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as CacheStore } from "./interface-
|
|
2
|
-
import { i as QueryCache } from "./QueryCache-
|
|
1
|
+
import { r as CacheStore } from "./interface-BGZCzOGL.mjs";
|
|
2
|
+
import { i as QueryCache } from "./QueryCache-DOMT_iq7.mjs";
|
|
3
3
|
import { FastifyPluginAsync } from "fastify";
|
|
4
4
|
//#region src/cache/queryCachePlugin.d.ts
|
|
5
5
|
interface QueryCachePluginOptions {
|