@classytic/arc 2.41.1 → 2.43.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/{EventTransport-CbUKDzZZ.d.mts → EventTransport-CiicKz2Z.d.mts} +1 -1
- package/dist/{EventTransport-DSqD_Xsg.mjs → EventTransport-tzA7CAB4.mjs} +22 -17
- package/dist/{HookSystem-CMF94SEA.mjs → HookSystem-B6UaKRbF.mjs} +2 -2
- package/dist/{QueryCache-DFA-QrU9.d.mts → QueryCache--5uAuYPW.d.mts} +7 -3
- package/dist/{ResourceRegistry-MGpXoxHZ.mjs → ResourceRegistry-CuCARu2B.mjs} +44 -13
- package/dist/actionPermissions-BotX1YOa.mjs +776 -0
- package/dist/audit/index.d.mts +43 -5
- package/dist/audit/index.mjs +48 -26
- package/dist/auth/audit.mjs +1 -1
- package/dist/auth/index.d.mts +43 -13
- package/dist/auth/index.mjs +130 -155
- package/dist/auth/redis-session.mjs +1 -1
- package/dist/{authorizationDecision-DawKGoXb.mjs → authorizationDecision-DQYrkl5f.mjs} +7 -102
- package/dist/{base-CxrV1LmG.d.mts → base-CZyixEQR.d.mts} +27 -5
- package/dist/boundedMap-BULzfXYU.mjs +57 -0
- package/dist/{buildHandler-CvxKOc0m.mjs → buildHandler-CRQ8EcX5.mjs} +4 -4
- package/dist/cache/index.d.mts +22 -34
- package/dist/cache/index.mjs +4 -4
- package/dist/{caching-DbCBxlgw.mjs → caching-Cc2M1DwO.mjs} +3 -3
- package/dist/claimed-B10RTfkM.mjs +8 -0
- package/dist/cleanup/index.d.mts +6 -10
- package/dist/cleanup/index.mjs +27 -73
- package/dist/cli/commands/describe.d.mts +4 -2
- package/dist/cli/commands/describe.mjs +7 -4
- package/dist/cli/commands/docs.mjs +3 -3
- package/dist/cli/commands/doctor.mjs +1 -1
- package/dist/cli/commands/generate.mjs +2 -2
- package/dist/cli/commands/init.mjs +2 -2
- package/dist/cli/commands/introspect.mjs +2 -2
- package/dist/cli/index.mjs +3 -3
- package/dist/{constants-D5Ubn1fe.mjs → constants-Cu7Mx7_U.mjs} +4 -2
- package/dist/context/index.d.mts +2 -5
- package/dist/context/index.mjs +18 -38
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +8 -8
- package/dist/{core-5lazhva9.mjs → core-Cb0LjccA.mjs} +5 -4
- package/dist/{createActionRouter-DNqoaK81.mjs → createActionRouter-xjqonMRO.mjs} +87 -39
- package/dist/{createAggregationRouter-BcbQJf10.mjs → createAggregationRouter-zRYWw_5D.mjs} +11 -8
- package/dist/{preloadResources-f3boenVZ.mjs → createApp-D-953ZAq.mjs} +299 -390
- package/dist/{createMcpServer-CbDWkZ1T.d.mts → createMcpServer-C9cxS8zt.d.mts} +1 -1
- package/dist/{defineAggregation-D_eJjm5A.mjs → defineAggregation-Bm8RjMbq.mjs} +1 -1
- package/dist/{defineResource-DxkMTjRn.mjs → defineResource-DIC7JZGU.mjs} +118 -1024
- package/dist/discovery/index.mjs +1 -1
- package/dist/docs/index.d.mts +10 -4
- package/dist/docs/index.mjs +4 -4
- package/dist/{elevation-BXCfVcNG.d.mts → elevation-BW2J3tNj.d.mts} +1 -2
- package/dist/{elevation-CkvG0LG2.mjs → elevation-DG8SrLN-.mjs} +41 -12
- package/dist/encryption/index.mjs +3 -3
- package/dist/{errorHandler-D1GHKGlV.mjs → errorHandler-BnfDviL1.mjs} +26 -5
- package/dist/{errors-BH7YU_9O.mjs → errors-CtrywMHP.mjs} +58 -23
- package/dist/{errors-BGdVwP25.d.mts → errors-JYc9vwqE.d.mts} +9 -0
- package/dist/{eventPlugin-B52abJ8W.d.mts → eventPlugin-BtmA4-3P.d.mts} +65 -9
- package/dist/{eventPlugin-zZY-unhr.mjs → eventPlugin-Q6BhzHzs.mjs} +82 -21
- package/dist/{subscribe-helpers-DatDkcuG.mjs → eventTypes-Cdhm6ZlV.mjs} +151 -17
- package/dist/events/index.d.mts +33 -8
- package/dist/events/index.mjs +49 -53
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +139 -157
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/events/transports/redis.mjs +2 -2
- package/dist/factory/index.d.mts +32 -17
- package/dist/factory/index.mjs +213 -32
- package/dist/{fastify-augmentation-Cq2nHVaW.d.mts → fastify-augmentation-DhUJ-mvo.d.mts} +11 -25
- package/dist/{fields-I_EeRWND.d.mts → fields-BBSpf8pS.d.mts} +1 -1
- package/dist/{fields-BHrkoF5y.mjs → fields-ToPYpMqS.mjs} +1 -1
- package/dist/filter-merge-IpGywvym.mjs +99 -0
- package/dist/{generate-BLRf2m3y.mjs → generate-DRTkLlIl.mjs} +2 -2
- package/dist/{headers-BIXWKrzQ.mjs → headers-BbkIF6vA.mjs} +2 -2
- package/dist/health-D-Ft6JM6.mjs +22 -0
- package/dist/{health-ZRHeDHXH.mjs → health-DqbsG-_w.mjs} +115 -55
- package/dist/hooks/index.d.mts +2 -2
- package/dist/hooks/index.mjs +2 -2
- package/dist/idempotency/index.d.mts +31 -7
- package/dist/idempotency/index.mjs +155 -98
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/idempotency/redis.mjs +48 -11
- package/dist/{index-BHdZD8zK.d.mts → index-Bxriq3so.d.mts} +84 -21
- package/dist/{preloadResources-CjS2OfpU.d.mts → index-C8zVGYsk.d.mts} +37 -38
- package/dist/{index-D4u76eQW.d.mts → index-CRoPtISf.d.mts} +23 -73
- package/dist/{index-CbJiYrfv.d.mts → index-Chgz3d0i.d.mts} +1 -1
- package/dist/index-JdbZAIsm.d.mts +510 -0
- package/dist/{index-DHbyPo5j.d.mts → index-mqaqZNpe.d.mts} +253 -254
- package/dist/index.d.mts +8 -8
- package/dist/index.mjs +11 -11
- package/dist/{init-CpLkjU18.mjs → init-B_oUYDXI.mjs} +1 -1
- package/dist/integrations/event-gateway.d.mts +8 -3
- package/dist/integrations/event-gateway.mjs +4 -4
- package/dist/integrations/index.d.mts +3 -3
- package/dist/integrations/index.mjs +1 -1
- package/dist/integrations/jobs/index.d.mts +1 -1
- package/dist/integrations/jobs/index.mjs +18 -5
- package/dist/integrations/mcp/index.d.mts +72 -59
- package/dist/integrations/mcp/index.mjs +19 -4
- package/dist/integrations/mcp/testing.d.mts +2 -2
- package/dist/integrations/mcp/testing.mjs +2 -2
- package/dist/integrations/streamline.d.mts +78 -136
- package/dist/integrations/streamline.mjs +116 -54
- package/dist/integrations/webhooks.d.mts +60 -120
- package/dist/integrations/webhooks.mjs +36 -80
- package/dist/integrations/websocket-pushref-redis.d.mts +1 -1
- package/dist/integrations/websocket-pushref-redis.mjs +1 -1
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket-redis.mjs +1 -1
- package/dist/integrations/websocket.d.mts +3 -3
- package/dist/integrations/websocket.mjs +2 -2
- package/dist/{interface-DEWNOMza.d.mts → interface-C0395yUN.d.mts} +13 -1
- package/dist/{jsonBody-ELR9lfeU.mjs → jsonBody-B4YVGcql.mjs} +2 -2
- package/dist/{keys-cpZCtcIE.mjs → keys-B2KtgMLJ.mjs} +7 -18
- package/dist/{loadResources-BPfWiI5s.mjs → loadResources-Dn4lalw2.mjs} +3 -3
- package/dist/{loadResourcesFromEntry-ixtfL3J2.mjs → loadResourcesFromEntry-3sLYbuse.mjs} +2 -2
- package/dist/logger/index.d.mts +1 -8
- package/dist/logger/index.mjs +3 -153
- package/dist/logger-DXjfIqjV.mjs +160 -0
- package/dist/{mcpPlugin-BX5PujI0.mjs → mcpPlugin-C08HalN5.mjs} +433 -170
- package/dist/{memory-Iotz0cCx.mjs → memory-9Cp7611C.mjs} +36 -34
- package/dist/{metrics-NMsmpRmY.mjs → metrics-CWI11eRu.mjs} +39 -72
- package/dist/middleware/index.d.mts +2 -2
- package/dist/middleware/index.mjs +3 -3
- package/dist/migrations/index.mjs +2 -2
- package/dist/{module-DpLJG2_N.mjs → module-BSvOQC7E.mjs} +8 -8
- package/dist/multiTenant-cY0FkDiA.d.mts +104 -0
- package/dist/{multipartBody-DtRWM6_U.mjs → multipartBody-CXM2a-Dy.mjs} +46 -7
- package/dist/{openapi-CmFf3yq_.mjs → openapi-DT_G4VhY.mjs} +48 -10
- package/dist/outbox-admin/index.d.mts +3 -3
- package/dist/outbox-admin/index.mjs +6 -18
- package/dist/{outbox-module-D2z5WkDY.mjs → outbox-module-Bjgzl6tg.mjs} +203 -33
- package/dist/{outbox-module-BHdUnuuK.d.mts → outbox-module-gZCHoE4H.d.mts} +79 -6
- package/dist/permissions/index.d.mts +5 -4
- package/dist/permissions/index.mjs +8 -6
- package/dist/{permissions-D8TBH44E.mjs → permissions-Cm0uYHvd.mjs} +149 -33
- package/dist/{pipe-FMWNheSO.mjs → pipe-BqeGT6UO.mjs} +2 -2
- package/dist/pipeline/index.d.mts +2 -2
- package/dist/pipeline/index.mjs +2 -2
- package/dist/plan-FVR6LP59.mjs +565 -0
- package/dist/{BaseController-CYEwjyjN.mjs → plugin-BccET1tL.mjs} +1256 -345
- package/dist/plugins/index.d.mts +14 -11
- package/dist/plugins/index.mjs +44 -22
- package/dist/plugins/response-cache.mjs +8 -14
- package/dist/plugins/tracing-entry.mjs +2 -2
- package/dist/{pluralize-CXWZIzTv.mjs → pluralize-CVIOcgMF.mjs} +1 -1
- package/dist/presets/filesUpload.d.mts +2 -2
- package/dist/presets/filesUpload.mjs +5 -5
- package/dist/presets/index.d.mts +26 -31
- package/dist/presets/index.mjs +4 -4
- package/dist/presets/multiTenant.d.mts +2 -107
- package/dist/presets/multiTenant.mjs +22 -162
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +2 -2
- package/dist/{presets-ZJSPgmT2.mjs → presets-Cpvj6fGO.mjs} +99 -107
- package/dist/{projection-BzIgzoKZ.mjs → projection-Ce4aQhQk.mjs} +2 -2
- package/dist/{pushref-registry-Dov9l4qE.d.mts → pushref-registry-UxCkoA4C.d.mts} +1 -1
- package/dist/{queryCachePlugin-BzqxconG.d.mts → queryCachePlugin-C2lZjTxk.d.mts} +1 -1
- package/dist/{queryCachePlugin-DZHPOm9p.mjs → queryCachePlugin-CFWNH8aT.mjs} +12 -14
- package/dist/{rateLimitKey-BvOvcBDi.mjs → rateLimitKey-C4O-kPm0.mjs} +1 -1
- package/dist/{realtime-8tIQWZz4.mjs → realtime-DmPE9S54.mjs} +25 -21
- package/dist/redis-stream-BMk-bpQS.d.mts +219 -0
- package/dist/{redis-Bzi1y3F9.d.mts → redis-vLvtcGy_.d.mts} +13 -24
- package/dist/redisShapes-CQksY67q.d.mts +55 -0
- package/dist/registry/index.d.mts +9 -4
- package/dist/registry/index.mjs +4 -4
- package/dist/{registry-DNkgGQcK.mjs → registry-Bcz9G1bh.mjs} +10 -8
- package/dist/{renewingLease-yF8BdW4b.mjs → renewingLease-qODa7KJQ.mjs} +1 -1
- package/dist/{replyHelpers-CNdvMfM4.mjs → replyHelpers-CG_VtVgS.mjs} +2 -2
- package/dist/{requestContext-cDkAUr-P.mjs → requestContext-Dsu9P1bV.mjs} +1 -1
- package/dist/requirement-CbiLdQ1n.d.mts +22 -0
- package/dist/requirement-KDdoRcOP.mjs +35 -0
- package/dist/resourceRateLimit-Wf6d6FL9.d.mts +30 -0
- package/dist/resourceRateLimit-dSjVr1pk.mjs +180 -0
- package/dist/{rolldown-runtime-eysyzFAF.mjs → rolldown-runtime-D1w9Y1VJ.mjs} +1 -1
- package/dist/routeValidator-D36SW8qt.mjs +70 -0
- package/dist/{runtimeCapabilities-CkhS6jn6.mjs → runtimeCapabilities-0tccjRlj.mjs} +1 -1
- package/dist/{schedules-j6uXXAeJ.mjs → schedules-C-OpmHBq.mjs} +46 -37
- package/dist/{schemaConverter-BVA7cFRG.mjs → schemaConverter-BORek3O-.mjs} +2 -2
- package/dist/{schemaIR-CTvPDoPB.mjs → schemaIR-C7Vbp71I.mjs} +2 -2
- package/dist/schemas/index.d.mts +10 -0
- package/dist/schemas/index.mjs +8 -3
- package/dist/scim/index.mjs +2 -2
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +6 -6
- package/dist/{scope-BUi1xV1I.mjs → scope-DQthe88b.mjs} +4 -4
- package/dist/shutdown-MqA81z_P.mjs +59 -0
- package/dist/{simpleEqualityMatcher-C9bzq2gO.mjs → simpleEqualityMatcher-auW8QjXN.mjs} +1 -1
- package/dist/{sse-BeqVKQKu.mjs → sse-CYzQBVFe.mjs} +11 -15
- package/dist/{sseStream-Ppzo-WUH.mjs → sseStream-B5_Afiqn.mjs} +2 -2
- package/dist/{store-helpers-dW71XVWL.mjs → store-helpers-BOzk-CuX.mjs} +1 -1
- package/dist/{streaming-IcRFjWQU.mjs → streaming-DjTQhZrN.mjs} +1 -1
- package/dist/subscriberIdentity-CW39uA8G.mjs +28 -0
- package/dist/tenancy--ed9eH_z.mjs +43 -0
- package/dist/tenantPreparation-BKon6Yox.mjs +67 -0
- package/dist/testing/cleanupStoreContract.mjs +1 -1
- package/dist/testing/index.d.mts +193 -175
- package/dist/testing/index.mjs +286 -212
- package/dist/testing/outboxStoreContract.mjs +137 -2
- package/dist/testing/requiredPorts.d.mts +17 -0
- package/dist/testing/requiredPorts.mjs +65 -0
- package/dist/testing/storageContract.mjs +1 -1
- package/dist/timing-qczZ0YC-.mjs +46 -0
- package/dist/{transactionContext-CPbdlnVw.mjs → transactionContext-DjFkrNG6.mjs} +1 -1
- package/dist/{typeGuards-BLjPgVBm.mjs → typeGuards-CySF12G-.mjs} +1 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/types/index.mjs +1 -1
- package/dist/types/storage.mjs +1 -1
- package/dist/{types-CWQn9-IC.d.mts → types-B4Aq4Sdj.d.mts} +22 -9
- package/dist/{types-DfVDvkdP.d.mts → types-BJ-2XqVF.d.mts} +189 -204
- package/dist/{types-CgenB1gv.mjs → types-Bk9NOgOC.mjs} +4 -4
- package/dist/usage/index.d.mts +2 -3
- package/dist/usage/index.mjs +5 -5
- package/dist/{userHelpers-ChRvkuSZ.mjs → userHelpers-aklawRaK.mjs} +1 -1
- package/dist/utils/index.d.mts +84 -223
- package/dist/utils/index.mjs +13 -12
- package/dist/{utils-CxcctrAh.mjs → utils-ec1oTo1n.mjs} +315 -404
- package/dist/{validate-DrYWnOzI.mjs → validate-9yzHC1e2.mjs} +6 -14
- package/dist/{versioning-D6JIK8Tk.d.mts → versioning-Bsb51gGT.d.mts} +28 -13
- package/dist/{versioning-DKkT4hNJ.mjs → versioning-fhhWHV74.mjs} +4 -4
- package/dist/{websocket-BOXVggMf.d.mts → websocket-Cs4awVyD.d.mts} +1 -1
- package/dist/{workScope-CxKqoIFn.mjs → workScope-zpPyge4t.mjs} +2 -2
- package/package.json +16 -12
- package/skills/arc/SKILL.md +13 -4
- package/skills/arc/references/auth.md +8 -5
- package/skills/arc/references/integrations.md +1 -1
- package/skills/arc/references/mcp.md +8 -6
- package/skills/arc/references/multi-tenancy.md +19 -14
- package/skills/arc/references/production.md +27 -10
- package/dist/actionPermissions-BoPGQ5-4.mjs +0 -350
- package/dist/index-CFfLKMH4.d.mts +0 -290
- package/dist/interface-YzIbF7Ii.mjs +0 -17
- package/dist/redis-stream-BPKscsTB.d.mts +0 -260
- package/dist/registerRoute-Bsnk6NiZ.mjs +0 -364
- package/dist/sync/changelog.d.mts +0 -3
- package/dist/sync/changelog.mjs +0 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
1
|
+
/*! @classytic/arc v2.43.0 | MIT | https://classytic.com */
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/plugins/requestId.ts
|
|
@@ -111,6 +111,115 @@ var requestId_default = fp(requestIdPlugin, {
|
|
|
111
111
|
fastify: "5.x"
|
|
112
112
|
});
|
|
113
113
|
//#endregion
|
|
114
|
+
//#region src/utils/metricSeries.ts
|
|
115
|
+
/** Retains a fixed number of label sets; excess observations share one overflow series. */
|
|
116
|
+
var MetricSeries = class {
|
|
117
|
+
data = /* @__PURE__ */ new Map();
|
|
118
|
+
overflow;
|
|
119
|
+
limit;
|
|
120
|
+
constructor(limit = 1e3) {
|
|
121
|
+
if (!Number.isSafeInteger(limit) || limit < 1) throw new RangeError("metrics.maxSeries must be a positive safe integer");
|
|
122
|
+
this.limit = limit;
|
|
123
|
+
}
|
|
124
|
+
get(labels, init) {
|
|
125
|
+
const key = JSON.stringify(Object.entries(labels).sort(([a], [b]) => a.localeCompare(b)));
|
|
126
|
+
const existing = this.data.get(key);
|
|
127
|
+
if (existing) return existing.value;
|
|
128
|
+
if (this.data.size >= this.limit) {
|
|
129
|
+
this.overflow ??= {
|
|
130
|
+
labels: { overflow: "true" },
|
|
131
|
+
value: init()
|
|
132
|
+
};
|
|
133
|
+
return this.overflow.value;
|
|
134
|
+
}
|
|
135
|
+
const entry = {
|
|
136
|
+
labels: { ...labels },
|
|
137
|
+
value: init()
|
|
138
|
+
};
|
|
139
|
+
this.data.set(key, entry);
|
|
140
|
+
return entry.value;
|
|
141
|
+
}
|
|
142
|
+
entries() {
|
|
143
|
+
return [...this.data.values(), ...this.overflow ? [this.overflow] : []];
|
|
144
|
+
}
|
|
145
|
+
reset() {
|
|
146
|
+
this.data.clear();
|
|
147
|
+
this.overflow = void 0;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const DURATION_BUCKETS_SECONDS = [
|
|
151
|
+
.001,
|
|
152
|
+
.002,
|
|
153
|
+
.005,
|
|
154
|
+
.01,
|
|
155
|
+
.025,
|
|
156
|
+
.05,
|
|
157
|
+
.1,
|
|
158
|
+
.25,
|
|
159
|
+
.5,
|
|
160
|
+
1,
|
|
161
|
+
2.5,
|
|
162
|
+
5,
|
|
163
|
+
10
|
|
164
|
+
];
|
|
165
|
+
/** Stores disjoint bucket counts; exported buckets are cumulative and include +Inf. */
|
|
166
|
+
var MetricHistogram = class {
|
|
167
|
+
series;
|
|
168
|
+
bounds;
|
|
169
|
+
constructor(bounds, maxSeries = 1e3) {
|
|
170
|
+
this.bounds = bounds;
|
|
171
|
+
this.series = new MetricSeries(maxSeries);
|
|
172
|
+
}
|
|
173
|
+
observe(labels, value) {
|
|
174
|
+
if (!Number.isFinite(value) || value < 0) return;
|
|
175
|
+
const state = this.series.get(labels, () => ({
|
|
176
|
+
buckets: new Array(this.bounds.length + 1).fill(0),
|
|
177
|
+
sum: 0,
|
|
178
|
+
count: 0
|
|
179
|
+
}));
|
|
180
|
+
const index = this.bounds.findIndex((bound) => value <= bound);
|
|
181
|
+
const bucket = index < 0 ? this.bounds.length : index;
|
|
182
|
+
state.buckets[bucket] = (state.buckets[bucket] ?? 0) + 1;
|
|
183
|
+
state.sum += value;
|
|
184
|
+
state.count++;
|
|
185
|
+
}
|
|
186
|
+
values() {
|
|
187
|
+
return this.series.entries().flatMap(({ labels, value }) => {
|
|
188
|
+
let cumulative = 0;
|
|
189
|
+
return [
|
|
190
|
+
...value.buckets.map((count, index) => {
|
|
191
|
+
cumulative += count;
|
|
192
|
+
return {
|
|
193
|
+
labels: {
|
|
194
|
+
...labels,
|
|
195
|
+
le: this.bounds[index]?.toString() ?? "+Inf"
|
|
196
|
+
},
|
|
197
|
+
value: cumulative,
|
|
198
|
+
suffix: "_bucket"
|
|
199
|
+
};
|
|
200
|
+
}),
|
|
201
|
+
{
|
|
202
|
+
labels: { ...labels },
|
|
203
|
+
value: value.sum,
|
|
204
|
+
suffix: "_sum"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
labels: { ...labels },
|
|
208
|
+
value: value.count,
|
|
209
|
+
suffix: "_count"
|
|
210
|
+
}
|
|
211
|
+
];
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
reset() {
|
|
215
|
+
this.series.reset();
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
function renderMetricSample(name, sample) {
|
|
219
|
+
const labels = Object.entries(sample.labels).map(([key, value]) => `${key}="${value.replaceAll("\\", "\\\\").replaceAll("\n", "\\n").replaceAll("\"", "\\\"")}"`).join(",");
|
|
220
|
+
return `${name}${sample.suffix ?? ""}${labels ? `{${labels}}` : ""} ${sample.value}`;
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
114
223
|
//#region src/plugins/health.ts
|
|
115
224
|
/**
|
|
116
225
|
* Merge health checks without losing ownership information.
|
|
@@ -130,47 +239,12 @@ function mergeHealthChecks(groups) {
|
|
|
130
239
|
}
|
|
131
240
|
return merged;
|
|
132
241
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Fixed histogram bucket upper bounds (ms). Recording is O(#buckets) per
|
|
135
|
-
* request; the scrape derives quantile UPPER BOUNDS from cumulative counts
|
|
136
|
-
* in O(#buckets) — no sample retention, no per-scrape sort (the previous
|
|
137
|
-
* 10k-sample ring buffer copied + sorted on EVERY scrape), and bucket
|
|
138
|
-
* counts aggregate correctly across instances.
|
|
139
|
-
*/
|
|
140
|
-
const DURATION_BUCKETS_MS = [
|
|
141
|
-
1,
|
|
142
|
-
2,
|
|
143
|
-
5,
|
|
144
|
-
10,
|
|
145
|
-
25,
|
|
146
|
-
50,
|
|
147
|
-
100,
|
|
148
|
-
250,
|
|
149
|
-
500,
|
|
150
|
-
1e3,
|
|
151
|
-
2500,
|
|
152
|
-
5e3,
|
|
153
|
-
1e4
|
|
154
|
-
];
|
|
155
242
|
function createHttpMetrics() {
|
|
156
243
|
return {
|
|
157
244
|
requestsTotal: {},
|
|
158
|
-
|
|
159
|
-
durationCount: 0,
|
|
160
|
-
durationSumMs: 0,
|
|
161
|
-
startTime: Date.now()
|
|
245
|
+
duration: new MetricHistogram(DURATION_BUCKETS_SECONDS.map((seconds) => seconds * 1e3))
|
|
162
246
|
};
|
|
163
247
|
}
|
|
164
|
-
/** Smallest bucket upper bound whose cumulative count reaches `q × total`. */
|
|
165
|
-
function bucketQuantile(metrics, q) {
|
|
166
|
-
const target = Math.ceil(metrics.durationCount * q);
|
|
167
|
-
let cumulative = 0;
|
|
168
|
-
for (let i = 0; i < metrics.durationBuckets.length; i++) {
|
|
169
|
-
cumulative += metrics.durationBuckets[i] ?? 0;
|
|
170
|
-
if (cumulative >= target) return DURATION_BUCKETS_MS[i] ?? DURATION_BUCKETS_MS[DURATION_BUCKETS_MS.length - 1] ?? 0;
|
|
171
|
-
}
|
|
172
|
-
return DURATION_BUCKETS_MS[DURATION_BUCKETS_MS.length - 1] ?? 0;
|
|
173
|
-
}
|
|
174
248
|
const healthPlugin = async (fastify, opts = {}) => {
|
|
175
249
|
const { prefix = "/_health", checks = [], metrics = false, metricsCollector, version, collectHttpMetrics = metrics } = opts;
|
|
176
250
|
const readinessChecks = mergeHealthChecks([{
|
|
@@ -315,12 +389,8 @@ const healthPlugin = async (fastify, opts = {}) => {
|
|
|
315
389
|
lines.push("# HELP http_requests_total Total HTTP requests by status code", "# TYPE http_requests_total counter");
|
|
316
390
|
for (const [status, count] of Object.entries(httpMetrics.requestsTotal)) lines.push(`http_requests_total{status="${status}"} ${count}`);
|
|
317
391
|
lines.push("");
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const p95 = bucketQuantile(httpMetrics, .95);
|
|
321
|
-
const p99 = bucketQuantile(httpMetrics, .99);
|
|
322
|
-
lines.push("# HELP http_request_duration_milliseconds HTTP request duration (bucket upper bounds)", "# 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 ${httpMetrics.durationSumMs.toFixed(2)}`, `http_request_duration_milliseconds_count ${httpMetrics.durationCount}`, "");
|
|
323
|
-
}
|
|
392
|
+
const samples = httpMetrics.duration.values();
|
|
393
|
+
if (samples.length > 0) lines.push("# HELP http_request_duration_milliseconds HTTP request duration in milliseconds", "# TYPE http_request_duration_milliseconds histogram", ...samples.map((sample) => renderMetricSample("http_request_duration_milliseconds", sample)), "");
|
|
324
394
|
}
|
|
325
395
|
return lines.join("\n");
|
|
326
396
|
});
|
|
@@ -328,17 +398,7 @@ const healthPlugin = async (fastify, opts = {}) => {
|
|
|
328
398
|
const duration = reply.elapsedTime;
|
|
329
399
|
const statusBucket = `${Math.floor(reply.statusCode / 100)}xx`;
|
|
330
400
|
httpMetrics.requestsTotal[statusBucket] = (httpMetrics.requestsTotal[statusBucket] || 0) + 1;
|
|
331
|
-
|
|
332
|
-
for (let i = 0; i < DURATION_BUCKETS_MS.length; i++) {
|
|
333
|
-
const bound = DURATION_BUCKETS_MS[i];
|
|
334
|
-
if (bound !== void 0 && duration <= bound) {
|
|
335
|
-
bucket = i;
|
|
336
|
-
break;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
httpMetrics.durationBuckets[bucket] = (httpMetrics.durationBuckets[bucket] ?? 0) + 1;
|
|
340
|
-
httpMetrics.durationCount++;
|
|
341
|
-
httpMetrics.durationSumMs += duration;
|
|
401
|
+
httpMetrics.duration.observe({}, duration);
|
|
342
402
|
});
|
|
343
403
|
fastify.log?.debug?.(`Health plugin registered at ${prefix} (alias), ${prefix}/live, ${prefix}/ready${metrics ? `, ${prefix}/metrics` : ""}`);
|
|
344
404
|
};
|
|
@@ -383,4 +443,4 @@ var health_default = fp(healthPlugin, {
|
|
|
383
443
|
fastify: "5.x"
|
|
384
444
|
});
|
|
385
445
|
//#endregion
|
|
386
|
-
export {
|
|
446
|
+
export { MetricHistogram as a, createRequestIdGenerator as c, DURATION_BUCKETS_SECONDS as i, requestId_default as l, health_default as n, MetricSeries as o, mergeHealthChecks as r, renderMetricSample as s, healthPlugin as t, sanitizeRequestId as u };
|
package/dist/hooks/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
|
|
2
|
-
import { an as HookRegistration, cn as afterCreate, dn as beforeCreate, en as DefineHookOptions, fn as beforeDelete, hn as defineHook, in as HookPhase, ln as afterDelete, mn as createHookSystem, nn as HookHandler, on as HookSystem, pn as beforeUpdate, rn as HookOperation, sn as HookSystemOptions, tn as HookContext, un as afterUpdate } from "../index-
|
|
3
|
-
export { type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
|
2
|
+
import { $t as AroundHookHandler, an as HookRegistration, cn as afterCreate, dn as beforeCreate, en as DefineHookOptions, fn as beforeDelete, hn as defineHook, in as HookPhase, ln as afterDelete, mn as createHookSystem, nn as HookHandler, on as HookSystem, pn as beforeUpdate, rn as HookOperation, sn as HookSystemOptions, tn as HookContext, un as afterUpdate } from "../index-mqaqZNpe.mjs";
|
|
3
|
+
export { type AroundHookHandler, type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
package/dist/hooks/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-
|
|
1
|
+
/*! @classytic/arc v2.43.0 | MIT | https://classytic.com */
|
|
2
|
+
import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-B6UaKRbF.mjs";
|
|
3
3
|
export { HookSystem, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
import { i as
|
|
2
|
+
import { t as RouteIdempotencyConfig } from "../requirement-CbiLdQ1n.mjs";
|
|
3
|
+
import { i as createIdempotencyResult, n as IdempotencyResult, r as IdempotencyStore, t as IdempotencyLock } from "../interface-C0395yUN.mjs";
|
|
4
|
+
import { i as RedisIdempotencyStoreOptions, n as RedisClient } from "../redis-vLvtcGy_.mjs";
|
|
4
5
|
import { FastifyPluginAsync } from "fastify";
|
|
5
6
|
import { RepositoryLike } from "@classytic/repo-core/adapter";
|
|
6
7
|
//#region src/idempotency/idempotencyPlugin.d.ts
|
|
@@ -13,7 +14,11 @@ interface IdempotencyPluginOptions {
|
|
|
13
14
|
ttlMs?: number;
|
|
14
15
|
/** Lock timeout in ms (default: 30000 = 30s) */
|
|
15
16
|
lockTimeoutMs?: number;
|
|
16
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* HTTP methods a key is honoured on when the route does not declare `config.idempotency`
|
|
19
|
+
* (default: ['POST', 'PUT', 'PATCH']). A route declaring `required: true` is fenced whatever
|
|
20
|
+
* its method — DELETE included — and whatever `include` / `exclude` say.
|
|
21
|
+
*/
|
|
17
22
|
methods?: string[];
|
|
18
23
|
/** URL patterns to include (regex). If set, only matching URLs use idempotency */
|
|
19
24
|
include?: RegExp[];
|
|
@@ -63,6 +68,8 @@ interface IdempotencyPluginOptions {
|
|
|
63
68
|
* remain as the runtime backstop.
|
|
64
69
|
*/
|
|
65
70
|
selfCheck?: boolean;
|
|
71
|
+
/** Migration escape for legacy custom stores without atomic completion fencing; warns at boot. */
|
|
72
|
+
allowUnfencedCompletion?: boolean;
|
|
66
73
|
}
|
|
67
74
|
declare module "fastify" {
|
|
68
75
|
interface FastifyRequest {
|
|
@@ -70,8 +77,20 @@ declare module "fastify" {
|
|
|
70
77
|
idempotencyKey?: string;
|
|
71
78
|
/** Whether this response was replayed from cache */
|
|
72
79
|
idempotencyReplayed?: boolean;
|
|
73
|
-
/** @internal
|
|
80
|
+
/** @internal The operation's storage key */
|
|
74
81
|
_idempotencyFullKey?: string;
|
|
82
|
+
/** @internal `fingerprintRequest` of this request's body, stored with its response */
|
|
83
|
+
_idempotencyFingerprint?: string;
|
|
84
|
+
}
|
|
85
|
+
interface FastifyContextConfig {
|
|
86
|
+
/**
|
|
87
|
+
* Per-route idempotency. `required: true` (or, on an action route, `requiredActions`
|
|
88
|
+
* naming the `body.action` values) refuses a call with no idempotency key (400
|
|
89
|
+
* `arc.idempotency_key_required`) and dedupes a keyed one, on any method. Boot refuses the
|
|
90
|
+
* declaration when nothing would enforce it: the plugin disabled, or the route's
|
|
91
|
+
* `preHandler` lacking `fastify.idempotency.middleware`.
|
|
92
|
+
*/
|
|
93
|
+
idempotency?: RouteIdempotencyConfig;
|
|
75
94
|
}
|
|
76
95
|
interface FastifyInstance {
|
|
77
96
|
/** Idempotency utilities */
|
|
@@ -93,7 +112,7 @@ declare module "fastify" {
|
|
|
93
112
|
* }, handler);
|
|
94
113
|
* ```
|
|
95
114
|
*/
|
|
96
|
-
middleware: (request: FastifyRequest, reply: FastifyReply) => Promise<
|
|
115
|
+
middleware: (request: FastifyRequest, reply: FastifyReply) => Promise<undefined | FastifyReply>;
|
|
97
116
|
/**
|
|
98
117
|
* The resolved backing store. Exposed so non-HTTP executors (MCP
|
|
99
118
|
* tools via `mcpPlugin`'s execution wiring, jobs, workflows) can run
|
|
@@ -101,10 +120,13 @@ declare module "fastify" {
|
|
|
101
120
|
* backend. `undefined` when the plugin is disabled.
|
|
102
121
|
*/
|
|
103
122
|
store?: IdempotencyStore;
|
|
123
|
+
/** Explicit migration escape shared with non-HTTP executors. */
|
|
124
|
+
readonly allowUnfencedCompletion?: boolean;
|
|
125
|
+
readonly ttlMs?: number;
|
|
126
|
+
readonly lockTimeoutMs?: number;
|
|
104
127
|
};
|
|
105
128
|
}
|
|
106
129
|
}
|
|
107
|
-
declare const idempotencyPlugin: FastifyPluginAsync<IdempotencyPluginOptions>;
|
|
108
130
|
declare const _default: FastifyPluginAsync<IdempotencyPluginOptions>;
|
|
109
131
|
//#endregion
|
|
110
132
|
//#region src/idempotency/repository-idempotency-adapter.d.ts
|
|
@@ -157,6 +179,8 @@ declare class MemoryIdempotencyStore implements IdempotencyStore {
|
|
|
157
179
|
constructor(options?: MemoryIdempotencyStoreOptions);
|
|
158
180
|
get(key: string): Promise<IdempotencyResult | undefined>;
|
|
159
181
|
set(key: string, result: Omit<IdempotencyResult, "key">): Promise<void>;
|
|
182
|
+
private writeResult;
|
|
183
|
+
setIfLocked(key: string, requestId: string, result: Omit<IdempotencyResult, "key">): Promise<boolean>;
|
|
160
184
|
tryLock(key: string, requestId: string, ttlMs: number): Promise<boolean>;
|
|
161
185
|
unlock(key: string, requestId: string): Promise<void>;
|
|
162
186
|
isLocked(key: string): Promise<boolean>;
|
|
@@ -173,4 +197,4 @@ declare class MemoryIdempotencyStore implements IdempotencyStore {
|
|
|
173
197
|
private evictOldest;
|
|
174
198
|
}
|
|
175
199
|
//#endregion
|
|
176
|
-
export { type IdempotencyLock, type IdempotencyPluginOptions, type IdempotencyResult, type IdempotencyStore, IdempotencyStoreMisconfiguredError, MemoryIdempotencyStore, type MemoryIdempotencyStoreOptions, type RedisClient, type RedisIdempotencyStoreOptions, createIdempotencyResult, _default as idempotencyPlugin,
|
|
200
|
+
export { type IdempotencyLock, type IdempotencyPluginOptions, type IdempotencyResult, type IdempotencyStore, IdempotencyStoreMisconfiguredError, MemoryIdempotencyStore, type MemoryIdempotencyStoreOptions, type RedisClient, type RedisIdempotencyStoreOptions, createIdempotencyResult, _default as idempotencyPlugin, repositoryAsIdempotencyStore };
|