@classytic/arc 2.21.0 → 2.23.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-BnLYgE9A.mjs → BaseController-BQ8KNvWC.mjs} +3 -2
- package/dist/{ResourceRegistry-7RnrEWNP.mjs → ResourceRegistry-y9Hnypus.mjs} +1 -0
- package/dist/{actionPermissions-ze70xXJi.mjs → actionPermissions-lszoJle1.mjs} +1 -1
- package/dist/applyPermissionResult-Tw4iXtlf.mjs +264 -0
- package/dist/audit/index.d.mts +2 -2
- package/dist/auth/index.d.mts +30 -2
- package/dist/auth/index.mjs +6 -3
- 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/init.mjs +1 -1
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +3 -3
- package/dist/{core-DZ6Xe1jR.mjs → core-DQ6rDTyH.mjs} +126 -68
- package/dist/{createActionRouter-BWMDW-dL.mjs → createActionRouter-BuOv-m4Y.mjs} +10 -6
- package/dist/{createAggregationRouter-l5mNdYrZ.mjs → createAggregationRouter-CgJv_BU_.mjs} +3 -3
- package/dist/{createApp-Bi61XxqU.mjs → createApp-CjOeWJ9_.mjs} +252 -57
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +1 -1
- package/dist/encryption/index.mjs +9 -5
- package/dist/{errorHandler-Dxf6P_kV.mjs → errorHandler-Bq2OeEQL.mjs} +34 -10
- package/dist/{errorHandler-B0e-bq-O.d.mts → errorHandler-C6yv4ZTW.d.mts} +13 -0
- package/dist/events/index.mjs +5 -2
- package/dist/factory/index.d.mts +46 -9
- package/dist/factory/index.mjs +64 -13
- package/dist/{fastify-augmentation-DafigGQp.d.mts → fastify-augmentation-g_f9omSc.d.mts} +2 -2
- package/dist/fields-D3lhgzhD.d.mts +121 -0
- package/dist/health-ScyjIVo5.mjs +202 -0
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +7 -0
- package/dist/idempotency/index.mjs +7 -17
- package/dist/{index-Dtrj6XZk.d.mts → index-BBsvQt7U.d.mts} +1310 -1226
- package/dist/{types-DpxoNX5v.d.mts → index-Ba10fdKp.d.mts} +196 -66
- package/dist/{index-B5N-NaHs.d.mts → index-CC5ruDGh.d.mts} +3 -3
- package/dist/{index-B5PoNbfu.d.mts → index-wMoWBLkn.d.mts} +68 -2
- package/dist/index.d.mts +6 -5
- package/dist/index.mjs +6 -5
- package/dist/{init-0YhHkXGk.mjs → init-CjO4p_q1.mjs} +123 -4
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +67 -4
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/webhooks.d.mts +131 -7
- package/dist/integrations/webhooks.mjs +169 -10
- package/dist/interface-n5hpKg1d.mjs +16 -0
- package/dist/jsonBody-BlzAoGCe.mjs +43 -0
- package/dist/{loadResourcesFromEntry-OMCvIEE7.mjs → loadResourcesFromEntry-kvGT6EcO.mjs} +1 -1
- package/dist/logger/index.d.mts +26 -1
- package/dist/logger/index.mjs +39 -1
- package/dist/{mcpPlugin-B9XjjNVG.mjs → mcpPlugin-BtzIL_kM.mjs} +312 -39
- package/dist/middleware/index.d.mts +1 -1
- package/dist/{module-WeuU5jfd.d.mts → module-B4u10iOJ.d.mts} +26 -1
- package/dist/{openapi-Kyod_di6.mjs → openapi-jSDx-VDv.mjs} +3 -3
- package/dist/permissions/index.d.mts +4 -3
- package/dist/permissions/index.mjs +3 -2
- package/dist/{permissions-BJMuKMl7.mjs → permissions-tbxFHxjZ.mjs} +77 -264
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/plugins/index.d.mts +24 -7
- package/dist/plugins/index.mjs +14 -282
- package/dist/plugins/response-cache.mjs +1 -0
- package/dist/plugins/tracing-entry.mjs +7 -4
- package/dist/presets/filesUpload.d.mts +2 -2
- package/dist/presets/filesUpload.mjs +1 -1
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-gw0ciIUD.mjs → presets-BOe4Ugkl.mjs} +1 -1
- package/dist/rateLimitKey-BoWRH3e7.mjs +14 -0
- package/dist/realtime-I8OrfnMR.mjs +375 -0
- package/dist/{registerRoute-oGAl0oA8.mjs → registerRoute-CWO6mdYe.mjs} +38 -18
- package/dist/registry/index.d.mts +2 -2
- package/dist/registry/index.mjs +1 -1
- package/dist/requestId-5BhTVzBv.mjs +113 -0
- package/dist/schemaConverter-DJvodiHj.mjs +171 -0
- package/dist/{schemaIR-ajetw3Fv.mjs → schemaIR-Ca7ySNPx.mjs} +2 -2
- package/dist/scim/index.mjs +6 -7
- package/dist/scope/index.mjs +2 -76
- package/dist/scope-LONQ3mfZ.mjs +37 -0
- package/dist/simpleEqualityMatcher-Cg05HPsn.mjs +68 -0
- package/dist/{sse-CfUjwjDk.mjs → sse-0u4P4-OI.mjs} +7 -30
- package/dist/sseStream-BQ7Qaynp.mjs +57 -0
- package/dist/testing/index.d.mts +83 -3
- package/dist/testing/index.mjs +70 -3
- package/dist/types/index.d.mts +2 -2
- package/dist/{types-DRj-Ut4n.d.mts → types-5OuqeTDX.d.mts} +37 -2
- package/dist/{fields-BGqrAa_u.d.mts → types-Csxga7d3.d.mts} +1 -121
- package/dist/usage/index.d.mts +142 -0
- package/dist/usage/index.mjs +0 -0
- package/dist/utils/index.d.mts +101 -19
- package/dist/utils/index.mjs +5 -3
- package/dist/{utils-CO8a3B_1.mjs → utils-CZyeRXTh.mjs} +80 -82
- package/dist/{versioning-DQ4mCvg0.d.mts → versioning-D6PvCwpq.d.mts} +43 -9
- package/llms.txt +39 -0
- package/package.json +513 -447
- package/skills/arc/SKILL.md +14 -8
- package/skills/arc/references/api-reference.md +34 -0
- package/skills/arc/references/auth.md +21 -4
- package/skills/arc/references/mcp.md +1 -1
- package/skills/arc/references/production.md +734 -654
- package/skills/arc-code-review/SKILL.md +1 -1
- package/skills/arc-code-review/references/anti-patterns.md +71 -18
- package/skills/arc-code-review/references/arc-cheatsheet.md +15 -2
- package/skills/arc-code-review/references/migration-recipes.md +7 -7
- package/skills/arc-code-review/references/mongokit-migration.md +4 -3
- package/skills/arc-module-publishing/SKILL.md +2 -1
- package/skills/arc-module-publishing/references/authoring-modules.md +55 -0
- package/skills/arc-module-publishing/references/package-manifest.md +4 -2
- package/dist/preloadResources-CHw3_oA_.mjs +0 -45
- package/dist/schemaConverter-U0MnO9vd.mjs +0 -110
package/dist/plugins/index.mjs
CHANGED
|
@@ -3,14 +3,16 @@ import { c as getOrgId } from "../types-bHblZ9YN.mjs";
|
|
|
3
3
|
import { n as requestContext } from "../requestContext-BZKOr13H.mjs";
|
|
4
4
|
import { t as hasEvents } from "../typeGuards-C9KXUly6.mjs";
|
|
5
5
|
import { t as HookSystem } from "../HookSystem-C1vB_Gc9.mjs";
|
|
6
|
-
import { t as ResourceRegistry } from "../ResourceRegistry-
|
|
6
|
+
import { t as ResourceRegistry } from "../ResourceRegistry-y9Hnypus.mjs";
|
|
7
|
+
import { i as sanitizeRequestId, n as requestIdPlugin, r as requestId_default, t as createRequestIdGenerator } from "../requestId-5BhTVzBv.mjs";
|
|
8
|
+
import { n as health_default, t as healthPlugin } from "../health-ScyjIVo5.mjs";
|
|
7
9
|
import { n as caching_default, t as cachingPlugin } from "../caching-_NJeDd1_.mjs";
|
|
8
|
-
import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-
|
|
10
|
+
import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-Bq2OeEQL.mjs";
|
|
9
11
|
import { n as metrics_default, t as metricsPlugin } from "../metrics-fdxI5mn_.mjs";
|
|
12
|
+
import { n as realtime_default, t as realtimePlugin } from "../realtime-I8OrfnMR.mjs";
|
|
10
13
|
import { t as replyHelpersPlugin } from "../replyHelpers-67tRawQZ.mjs";
|
|
11
|
-
import { n as sse_default, t as ssePlugin } from "../sse-
|
|
14
|
+
import { n as sse_default, t as ssePlugin } from "../sse-0u4P4-OI.mjs";
|
|
12
15
|
import { n as versioning_default, t as versioningPlugin } from "../versioning-Dk-71iIz.mjs";
|
|
13
|
-
import { randomUUID } from "node:crypto";
|
|
14
16
|
import fp from "fastify-plugin";
|
|
15
17
|
//#region src/core/arcCorePlugin.ts
|
|
16
18
|
const arcCorePlugin = async (fastify, opts = {}) => {
|
|
@@ -24,6 +26,13 @@ const arcCorePlugin = async (fastify, opts = {}) => {
|
|
|
24
26
|
externalOpenApiPaths: [],
|
|
25
27
|
plugins: /* @__PURE__ */ new Map()
|
|
26
28
|
});
|
|
29
|
+
for (const field of [
|
|
30
|
+
"_policyFilters",
|
|
31
|
+
"_ownershipCheck",
|
|
32
|
+
"fieldMask",
|
|
33
|
+
"policyMetadata",
|
|
34
|
+
"document"
|
|
35
|
+
]) if (!fastify.hasRequestDecorator(field)) fastify.decorateRequest(field, void 0);
|
|
27
36
|
fastify.addHook("onRequest", (request, _reply, done) => {
|
|
28
37
|
const store = {
|
|
29
38
|
requestId: request.id,
|
|
@@ -192,283 +201,6 @@ var gracefulShutdown_default = fp(gracefulShutdownPlugin, {
|
|
|
192
201
|
fastify: "5.x"
|
|
193
202
|
});
|
|
194
203
|
//#endregion
|
|
195
|
-
//#region src/plugins/health.ts
|
|
196
|
-
function createHttpMetrics() {
|
|
197
|
-
return {
|
|
198
|
-
requestsTotal: {},
|
|
199
|
-
requestDurations: [],
|
|
200
|
-
_ringIndex: 0,
|
|
201
|
-
startTime: Date.now()
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
const healthPlugin = async (fastify, opts = {}) => {
|
|
205
|
-
const { prefix = "/_health", checks = [], metrics = false, metricsCollector, version, collectHttpMetrics = metrics } = opts;
|
|
206
|
-
const httpMetrics = createHttpMetrics();
|
|
207
|
-
fastify.get(prefix, { schema: {
|
|
208
|
-
tags: ["Health"],
|
|
209
|
-
summary: "Liveness probe (alias for /live)",
|
|
210
|
-
description: "Returns 200 if the process is alive",
|
|
211
|
-
response: { 200: {
|
|
212
|
-
type: "object",
|
|
213
|
-
properties: {
|
|
214
|
-
status: {
|
|
215
|
-
type: "string",
|
|
216
|
-
enum: ["ok"]
|
|
217
|
-
},
|
|
218
|
-
timestamp: { type: "string" },
|
|
219
|
-
version: { type: "string" }
|
|
220
|
-
}
|
|
221
|
-
} }
|
|
222
|
-
} }, async () => ({
|
|
223
|
-
status: "ok",
|
|
224
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
225
|
-
...version ? { version } : {}
|
|
226
|
-
}));
|
|
227
|
-
fastify.get(`${prefix}/live`, { schema: {
|
|
228
|
-
tags: ["Health"],
|
|
229
|
-
summary: "Liveness probe",
|
|
230
|
-
description: "Returns 200 if the process is alive",
|
|
231
|
-
response: { 200: {
|
|
232
|
-
type: "object",
|
|
233
|
-
properties: {
|
|
234
|
-
status: {
|
|
235
|
-
type: "string",
|
|
236
|
-
enum: ["ok"]
|
|
237
|
-
},
|
|
238
|
-
timestamp: { type: "string" },
|
|
239
|
-
version: { type: "string" }
|
|
240
|
-
}
|
|
241
|
-
} }
|
|
242
|
-
} }, async () => {
|
|
243
|
-
return {
|
|
244
|
-
status: "ok",
|
|
245
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
246
|
-
...version ? { version } : {}
|
|
247
|
-
};
|
|
248
|
-
});
|
|
249
|
-
fastify.get(`${prefix}/ready`, { schema: {
|
|
250
|
-
tags: ["Health"],
|
|
251
|
-
summary: "Readiness probe",
|
|
252
|
-
description: "Returns 200 if all dependencies are healthy",
|
|
253
|
-
response: {
|
|
254
|
-
200: {
|
|
255
|
-
type: "object",
|
|
256
|
-
properties: {
|
|
257
|
-
status: {
|
|
258
|
-
type: "string",
|
|
259
|
-
enum: ["ready", "not_ready"]
|
|
260
|
-
},
|
|
261
|
-
timestamp: { type: "string" },
|
|
262
|
-
checks: {
|
|
263
|
-
type: "array",
|
|
264
|
-
items: {
|
|
265
|
-
type: "object",
|
|
266
|
-
properties: {
|
|
267
|
-
name: { type: "string" },
|
|
268
|
-
healthy: { type: "boolean" },
|
|
269
|
-
duration: { type: "number" },
|
|
270
|
-
error: { type: "string" }
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
},
|
|
276
|
-
503: {
|
|
277
|
-
type: "object",
|
|
278
|
-
properties: {
|
|
279
|
-
status: {
|
|
280
|
-
type: "string",
|
|
281
|
-
enum: ["not_ready"]
|
|
282
|
-
},
|
|
283
|
-
timestamp: { type: "string" },
|
|
284
|
-
checks: { type: "array" }
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
} }, async (_, reply) => {
|
|
289
|
-
const results = await runChecks(checks);
|
|
290
|
-
const criticalFailed = results.some((r) => !r.healthy && (checks.find((c) => c.name === r.name)?.critical ?? true));
|
|
291
|
-
const response = {
|
|
292
|
-
status: criticalFailed ? "not_ready" : "ready",
|
|
293
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
294
|
-
checks: results
|
|
295
|
-
};
|
|
296
|
-
if (criticalFailed) reply.code(503);
|
|
297
|
-
return response;
|
|
298
|
-
});
|
|
299
|
-
if (metrics) fastify.get(`${prefix}/metrics`, async (_, reply) => {
|
|
300
|
-
reply.type("text/plain; charset=utf-8");
|
|
301
|
-
if (metricsCollector) return await metricsCollector();
|
|
302
|
-
const uptime = process.uptime();
|
|
303
|
-
const memory = process.memoryUsage();
|
|
304
|
-
const cpu = process.cpuUsage();
|
|
305
|
-
const lines = [
|
|
306
|
-
"# HELP process_uptime_seconds Process uptime in seconds",
|
|
307
|
-
"# TYPE process_uptime_seconds gauge",
|
|
308
|
-
`process_uptime_seconds ${uptime.toFixed(2)}`,
|
|
309
|
-
"",
|
|
310
|
-
"# HELP process_memory_heap_bytes Heap memory usage in bytes",
|
|
311
|
-
"# TYPE process_memory_heap_bytes gauge",
|
|
312
|
-
`process_memory_heap_bytes{type="used"} ${memory.heapUsed}`,
|
|
313
|
-
`process_memory_heap_bytes{type="total"} ${memory.heapTotal}`,
|
|
314
|
-
"",
|
|
315
|
-
"# HELP process_memory_rss_bytes RSS memory in bytes",
|
|
316
|
-
"# TYPE process_memory_rss_bytes gauge",
|
|
317
|
-
`process_memory_rss_bytes ${memory.rss}`,
|
|
318
|
-
"",
|
|
319
|
-
"# HELP process_memory_external_bytes External memory in bytes",
|
|
320
|
-
"# TYPE process_memory_external_bytes gauge",
|
|
321
|
-
`process_memory_external_bytes ${memory.external}`,
|
|
322
|
-
"",
|
|
323
|
-
"# HELP process_cpu_user_microseconds User CPU time in microseconds",
|
|
324
|
-
"# TYPE process_cpu_user_microseconds counter",
|
|
325
|
-
`process_cpu_user_microseconds ${cpu.user}`,
|
|
326
|
-
"",
|
|
327
|
-
"# HELP process_cpu_system_microseconds System CPU time in microseconds",
|
|
328
|
-
"# TYPE process_cpu_system_microseconds counter",
|
|
329
|
-
`process_cpu_system_microseconds ${cpu.system}`,
|
|
330
|
-
""
|
|
331
|
-
];
|
|
332
|
-
if (collectHttpMetrics && Object.keys(httpMetrics.requestsTotal).length > 0) {
|
|
333
|
-
lines.push("# HELP http_requests_total Total HTTP requests by status code", "# TYPE http_requests_total counter");
|
|
334
|
-
for (const [status, count] of Object.entries(httpMetrics.requestsTotal)) lines.push(`http_requests_total{status="${status}"} ${count}`);
|
|
335
|
-
lines.push("");
|
|
336
|
-
if (httpMetrics.requestDurations.length > 0) {
|
|
337
|
-
const sorted = [...httpMetrics.requestDurations].sort((a, b) => a - b);
|
|
338
|
-
const p50 = sorted[Math.floor(sorted.length * .5)] || 0;
|
|
339
|
-
const p95 = sorted[Math.floor(sorted.length * .95)] || 0;
|
|
340
|
-
const p99 = sorted[Math.floor(sorted.length * .99)] || 0;
|
|
341
|
-
const sum = sorted.reduce((a, b) => a + b, 0);
|
|
342
|
-
lines.push("# HELP http_request_duration_milliseconds HTTP request duration", "# TYPE http_request_duration_milliseconds summary", `http_request_duration_milliseconds{quantile="0.5"} ${p50.toFixed(2)}`, `http_request_duration_milliseconds{quantile="0.95"} ${p95.toFixed(2)}`, `http_request_duration_milliseconds{quantile="0.99"} ${p99.toFixed(2)}`, `http_request_duration_milliseconds_sum ${sum.toFixed(2)}`, `http_request_duration_milliseconds_count ${sorted.length}`, "");
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
return lines.join("\n");
|
|
346
|
-
});
|
|
347
|
-
if (collectHttpMetrics) {
|
|
348
|
-
fastify.addHook("onRequest", async (request) => {
|
|
349
|
-
request._startTime = Date.now();
|
|
350
|
-
});
|
|
351
|
-
fastify.addHook("onResponse", async (request, reply) => {
|
|
352
|
-
const duration = Date.now() - (request._startTime ?? Date.now());
|
|
353
|
-
const statusBucket = `${Math.floor(reply.statusCode / 100)}xx`;
|
|
354
|
-
httpMetrics.requestsTotal[statusBucket] = (httpMetrics.requestsTotal[statusBucket] || 0) + 1;
|
|
355
|
-
if (httpMetrics.requestDurations.length < 1e4) httpMetrics.requestDurations.push(duration);
|
|
356
|
-
else httpMetrics.requestDurations[httpMetrics._ringIndex % 1e4] = duration;
|
|
357
|
-
httpMetrics._ringIndex = httpMetrics._ringIndex + 1;
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
fastify.log?.debug?.(`Health plugin registered at ${prefix} (alias), ${prefix}/live, ${prefix}/ready${metrics ? `, ${prefix}/metrics` : ""}`);
|
|
361
|
-
};
|
|
362
|
-
/**
|
|
363
|
-
* Run all health checks with timeout
|
|
364
|
-
*/
|
|
365
|
-
async function runChecks(checks) {
|
|
366
|
-
const results = [];
|
|
367
|
-
for (const check of checks) {
|
|
368
|
-
const start = Date.now();
|
|
369
|
-
const timeout = check.timeout ?? 5e3;
|
|
370
|
-
let timer;
|
|
371
|
-
try {
|
|
372
|
-
const checkPromise = Promise.resolve(check.check());
|
|
373
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
374
|
-
timer = setTimeout(() => reject(/* @__PURE__ */ new Error("Health check timeout")), timeout);
|
|
375
|
-
});
|
|
376
|
-
const healthy = await Promise.race([checkPromise, timeoutPromise]);
|
|
377
|
-
results.push({
|
|
378
|
-
name: check.name,
|
|
379
|
-
healthy: Boolean(healthy),
|
|
380
|
-
duration: Date.now() - start
|
|
381
|
-
});
|
|
382
|
-
} catch (err) {
|
|
383
|
-
results.push({
|
|
384
|
-
name: check.name,
|
|
385
|
-
healthy: false,
|
|
386
|
-
duration: Date.now() - start,
|
|
387
|
-
error: err.message
|
|
388
|
-
});
|
|
389
|
-
} finally {
|
|
390
|
-
if (timer) clearTimeout(timer);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
return results;
|
|
394
|
-
}
|
|
395
|
-
var health_default = fp(healthPlugin, {
|
|
396
|
-
name: "arc-health",
|
|
397
|
-
fastify: "5.x"
|
|
398
|
-
});
|
|
399
|
-
//#endregion
|
|
400
|
-
//#region src/plugins/requestId.ts
|
|
401
|
-
/**
|
|
402
|
-
* Request ID Plugin
|
|
403
|
-
*
|
|
404
|
-
* Propagates request IDs for distributed tracing.
|
|
405
|
-
* - Accepts incoming x-request-id header
|
|
406
|
-
* - Generates UUID if not provided
|
|
407
|
-
* - Attaches to request.id and response header
|
|
408
|
-
*
|
|
409
|
-
* @example
|
|
410
|
-
* import { requestIdPlugin } from '@classytic/arc';
|
|
411
|
-
*
|
|
412
|
-
* await fastify.register(requestIdPlugin);
|
|
413
|
-
*
|
|
414
|
-
* // In handlers, access via request.id
|
|
415
|
-
* fastify.get('/', async (request) => {
|
|
416
|
-
* console.log(request.id); // UUID
|
|
417
|
-
* });
|
|
418
|
-
*/
|
|
419
|
-
/** W3C traceparent format: `version-traceid-parentid-flags` */
|
|
420
|
-
const TRACEPARENT_RE = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/i;
|
|
421
|
-
/** W3C spec: version ff is reserved and invalid; trace/parent IDs must not be all zeros */
|
|
422
|
-
const TRACEID_ZEROS = "0".repeat(32);
|
|
423
|
-
const PARENTID_ZEROS = "0".repeat(16);
|
|
424
|
-
/** tracestate: printable ASCII, <= 512 bytes */
|
|
425
|
-
const TRACESTATE_MAX = 512;
|
|
426
|
-
function isValidTraceparent(tp) {
|
|
427
|
-
const m = TRACEPARENT_RE.exec(tp);
|
|
428
|
-
if (!m) return false;
|
|
429
|
-
const version = m[1] ?? "";
|
|
430
|
-
const traceId = m[2] ?? "";
|
|
431
|
-
const parentId = m[3] ?? "";
|
|
432
|
-
if (version.toLowerCase() === "ff") return false;
|
|
433
|
-
if (traceId.toLowerCase() === TRACEID_ZEROS) return false;
|
|
434
|
-
if (parentId.toLowerCase() === PARENTID_ZEROS) return false;
|
|
435
|
-
return true;
|
|
436
|
-
}
|
|
437
|
-
const requestIdPlugin = async (fastify, opts = {}) => {
|
|
438
|
-
const { header = "x-request-id", generator = randomUUID, setResponseHeader = true, propagateTraceContext = true } = opts;
|
|
439
|
-
if (!fastify.hasRequestDecorator("requestId")) fastify.decorateRequest("requestId", "");
|
|
440
|
-
if (!fastify.hasRequestDecorator("traceContext")) fastify.decorateRequest("traceContext", void 0);
|
|
441
|
-
fastify.addHook("onRequest", async (request, reply) => {
|
|
442
|
-
const incomingId = request.headers[header];
|
|
443
|
-
const sanitized = typeof incomingId === "string" ? incomingId.trim() : "";
|
|
444
|
-
const requestId = sanitized.length > 0 && sanitized.length <= 128 && /^[\w.:-]+$/.test(sanitized) ? sanitized : generator();
|
|
445
|
-
request.id = requestId;
|
|
446
|
-
request.requestId = requestId;
|
|
447
|
-
if (setResponseHeader) reply.header(header, requestId);
|
|
448
|
-
if (propagateTraceContext) {
|
|
449
|
-
const rawTraceparent = request.headers["traceparent"];
|
|
450
|
-
const rawTracestate = request.headers["tracestate"];
|
|
451
|
-
if (typeof rawTraceparent === "string") {
|
|
452
|
-
const tp = rawTraceparent.trim();
|
|
453
|
-
if (isValidTraceparent(tp)) {
|
|
454
|
-
const ts = typeof rawTracestate === "string" && rawTracestate.length > 0 && rawTracestate.length <= TRACESTATE_MAX ? rawTracestate : void 0;
|
|
455
|
-
request.traceContext = {
|
|
456
|
-
traceparent: tp,
|
|
457
|
-
...ts ? { tracestate: ts } : {}
|
|
458
|
-
};
|
|
459
|
-
reply.header("traceparent", tp);
|
|
460
|
-
if (ts) reply.header("tracestate", ts);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
});
|
|
465
|
-
fastify.log?.debug?.("Request ID plugin registered");
|
|
466
|
-
};
|
|
467
|
-
var requestId_default = fp(requestIdPlugin, {
|
|
468
|
-
name: "arc-request-id",
|
|
469
|
-
fastify: "5.x"
|
|
470
|
-
});
|
|
471
|
-
//#endregion
|
|
472
204
|
//#region src/plugins/schedules.ts
|
|
473
205
|
const MIN_SAFE_INTERVAL_MS = 1e3;
|
|
474
206
|
const MAX_DEFAULT_LEASE_MS = 3e5;
|
|
@@ -556,4 +288,4 @@ var schedules_default = fp(schedulesPlugin, {
|
|
|
556
288
|
fastify: "5.x"
|
|
557
289
|
});
|
|
558
290
|
//#endregion
|
|
559
|
-
export { arcCorePlugin_default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, caching_default as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, defaultIsDuplicateKeyError, errorHandlerPlugin, errorHandlerPlugin as errorHandlerPluginFn, gracefulShutdown_default as gracefulShutdownPlugin, gracefulShutdownPlugin as gracefulShutdownPluginFn, health_default as healthPlugin, healthPlugin as healthPluginFn, metrics_default as metricsPlugin, metricsPlugin as metricsPluginFn, replyHelpersPlugin, requestId_default as requestIdPlugin, requestIdPlugin as requestIdPluginFn, schedules_default as schedulesPlugin, schedulesPlugin as schedulesPluginFn, sse_default as ssePlugin, ssePlugin as ssePluginFn, versioning_default as versioningPlugin, versioningPlugin as versioningPluginFn };
|
|
291
|
+
export { arcCorePlugin_default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, caching_default as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, createRequestIdGenerator, defaultIsDuplicateKeyError, errorHandlerPlugin, errorHandlerPlugin as errorHandlerPluginFn, gracefulShutdown_default as gracefulShutdownPlugin, gracefulShutdownPlugin as gracefulShutdownPluginFn, health_default as healthPlugin, healthPlugin as healthPluginFn, metrics_default as metricsPlugin, metricsPlugin as metricsPluginFn, realtime_default as realtimePlugin, realtimePlugin as realtimePluginFn, replyHelpersPlugin, requestId_default as requestIdPlugin, requestIdPlugin as requestIdPluginFn, sanitizeRequestId, schedules_default as schedulesPlugin, schedulesPlugin as schedulesPluginFn, sse_default as ssePlugin, ssePlugin as ssePluginFn, versioning_default as versioningPlugin, versioningPlugin as versioningPluginFn };
|
|
@@ -94,6 +94,7 @@ const responseCachePluginImpl = async (fastify, opts = {}) => {
|
|
|
94
94
|
], xCacheHeader = true, statsPath = null, keyFn } = opts;
|
|
95
95
|
const cache = new LRUCache(maxEntries);
|
|
96
96
|
const invalidateMethods = new Set(invalidateOn.map((m) => m.toUpperCase()));
|
|
97
|
+
if (!fastify.hasRequestDecorator("__arcCacheTTL")) fastify.decorateRequest("__arcCacheTTL", void 0);
|
|
97
98
|
/** Find TTL for a given URL path (seconds) */
|
|
98
99
|
function getTTL(url) {
|
|
99
100
|
const path = url.split("?")[0] ?? url;
|
|
@@ -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.23.0";
|
|
62
62
|
const exporter = new OTLPTraceExporter({ url: exporterUrl });
|
|
63
63
|
const provider = new NodeTracerProvider({ resource: { attributes: {
|
|
64
64
|
"service.name": serviceName,
|
|
@@ -92,8 +92,11 @@ async function tracingPlugin(fastify, options = {}) {
|
|
|
92
92
|
}
|
|
93
93
|
const tracer = otelTrace.getTracer(serviceName);
|
|
94
94
|
fastify.decorateRequest("tracer", void 0);
|
|
95
|
-
fastify.addHook("onRequest",
|
|
96
|
-
if (Math.random() > sampleRate)
|
|
95
|
+
fastify.addHook("onRequest", (request, _reply, done) => {
|
|
96
|
+
if (Math.random() > sampleRate) {
|
|
97
|
+
done();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
97
100
|
const span = tracer.startSpan(`HTTP ${request.method} ${request.url}`, {
|
|
98
101
|
kind: 1,
|
|
99
102
|
attributes: {
|
|
@@ -109,7 +112,7 @@ async function tracingPlugin(fastify, options = {}) {
|
|
|
109
112
|
tracer,
|
|
110
113
|
currentSpan: span
|
|
111
114
|
};
|
|
112
|
-
otelContext.with(otelTrace.setSpan(otelContext.active(), span),
|
|
115
|
+
otelContext.with(otelTrace.setSpan(otelContext.active(), span), done);
|
|
113
116
|
});
|
|
114
117
|
fastify.addHook("onResponse", async (request, reply) => {
|
|
115
118
|
if (!request.tracer?.currentSpan) return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Y as PresetResult } from "../index-BBsvQt7U.mjs";
|
|
2
2
|
import { i as RequestScope } from "../types-DH0GupI7.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { t as PermissionCheck } from "../types-Csxga7d3.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,6 +1,6 @@
|
|
|
1
1
|
import { i as NotFoundError, u as ValidationError } from "../errors-DkO8Nk6-.mjs";
|
|
2
2
|
import { c as getOrgId, g as getUserId } from "../types-bHblZ9YN.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { C as allowPublic, D as requireAuth } from "../permissions-tbxFHxjZ.mjs";
|
|
4
4
|
import { t as multipartBody } from "../multipartBody-CHEQSZ6G.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 { Jt as AnyRecord, Rt as IControllerResponse, U as ResourceConfig, Y as PresetResult, d as PaginationResult, zt as IRequestContext } from "../index-BBsvQt7U.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-BOe4Ugkl.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 {
|
|
1
|
+
import { X as CrudRouteKey, Y as PresetResult } from "../index-BBsvQt7U.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
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { At as RouteDefinition, Pt as ControllerHandler, Y as PresetResult, jt as RouteMcpConfig } from "../index-BBsvQt7U.mjs";
|
|
2
|
+
import { t as PermissionCheck } from "../types-Csxga7d3.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,6 +1,6 @@
|
|
|
1
1
|
import { b as isElevated, n as PUBLIC_SCOPE } from "./types-bHblZ9YN.mjs";
|
|
2
|
-
import { E as requireRoles, b as allowPublic, w as requireAuth } from "./permissions-BJMuKMl7.mjs";
|
|
3
2
|
import { multiTenantPreset } from "./presets/multiTenant.mjs";
|
|
3
|
+
import { C as allowPublic, D as requireAuth, k as requireRoles } from "./permissions-tbxFHxjZ.mjs";
|
|
4
4
|
//#region src/presets/ownedByUser.ts
|
|
5
5
|
/**
|
|
6
6
|
* Create ownership check middleware.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/scope/rateLimitKey.ts
|
|
2
|
+
function createTenantKeyGenerator(opts) {
|
|
3
|
+
if (opts?.strategy) return opts.strategy;
|
|
4
|
+
return (ctx) => {
|
|
5
|
+
const scope = ctx.scope;
|
|
6
|
+
if (!scope || scope.kind === "public") return ctx.ip;
|
|
7
|
+
if (scope.kind === "member") return scope.organizationId;
|
|
8
|
+
if (scope.kind === "service") return scope.organizationId;
|
|
9
|
+
if (scope.kind === "elevated") return scope.organizationId ?? scope.userId ?? ctx.ip;
|
|
10
|
+
return scope.userId ?? ctx.ip;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { createTenantKeyGenerator as t };
|