@classytic/arc 2.3.0 → 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -18
- package/bin/arc.js +11 -3
- package/dist/BaseController-CkM5dUh_.mjs +1031 -0
- package/dist/{EventTransport-BkUDYZEb.d.mts → EventTransport-wc5hSLik.d.mts} +1 -1
- package/dist/{HookSystem-BsGV-j2l.mjs → HookSystem-COkyWztM.mjs} +2 -3
- package/dist/{ResourceRegistry-7Ic20ZMw.mjs → ResourceRegistry-DeCIFlix.mjs} +8 -5
- package/dist/adapters/index.d.mts +3 -5
- package/dist/adapters/index.mjs +2 -3
- package/dist/{prisma-DJbMt3yf.mjs → adapters-DTC4Ug66.mjs} +45 -12
- package/dist/audit/index.d.mts +4 -7
- package/dist/audit/index.mjs +2 -29
- package/dist/audit/mongodb.d.mts +1 -4
- package/dist/audit/mongodb.mjs +2 -3
- package/dist/auth/index.d.mts +7 -9
- package/dist/auth/index.mjs +65 -63
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/auth/redis-session.mjs +1 -2
- package/dist/{betterAuthOpenApi-DjWDddNc.mjs → betterAuthOpenApi-lz0IRbXJ.mjs} +4 -6
- package/dist/cache/index.d.mts +23 -23
- package/dist/cache/index.mjs +4 -6
- package/dist/{caching-GSDJcA6-.mjs → caching-BSXB-Xr7.mjs} +2 -24
- package/dist/chunk-BpYLSNr0.mjs +14 -0
- package/dist/circuitBreaker-BOBOpN2w.mjs +284 -0
- package/dist/circuitBreaker-JP2GdJ4b.d.mts +206 -0
- package/dist/cli/commands/describe.mjs +24 -7
- package/dist/cli/commands/docs.mjs +6 -7
- package/dist/cli/commands/doctor.d.mts +10 -0
- package/dist/cli/commands/doctor.mjs +156 -0
- package/dist/cli/commands/generate.mjs +66 -17
- package/dist/cli/commands/init.mjs +315 -45
- package/dist/cli/commands/introspect.mjs +2 -4
- package/dist/cli/index.d.mts +1 -10
- package/dist/cli/index.mjs +4 -153
- package/dist/{constants-DdXFXQtN.mjs → constants-Cxde4rpC.mjs} +1 -2
- package/dist/core/index.d.mts +3 -5
- package/dist/core/index.mjs +5 -4
- package/dist/core-C1XCMtqM.mjs +185 -0
- package/dist/{createApp-CgKOPhA4.mjs → createApp-ByWNRsZj.mjs} +64 -35
- package/dist/{defineResource-DWbpJYtm.mjs → defineResource-D9aY5Cy6.mjs} +108 -1157
- package/dist/discovery/index.mjs +37 -5
- package/dist/docs/index.d.mts +6 -9
- package/dist/docs/index.mjs +3 -21
- package/dist/dynamic/index.d.mts +93 -0
- package/dist/dynamic/index.mjs +122 -0
- package/dist/{elevation-DSTbVvYj.mjs → elevation-BEdACOLB.mjs} +5 -36
- package/dist/{elevation-DGo5shaX.d.mts → elevation-Ca_yveIO.d.mts} +41 -7
- package/dist/{errorHandler-C3GY3_ow.mjs → errorHandler--zp54tGc.mjs} +3 -5
- package/dist/errorHandler-Do4vVQ1f.d.mts +139 -0
- package/dist/{errors-DBANPbGr.mjs → errors-rxhfP7Hf.mjs} +1 -2
- package/dist/{eventPlugin-BEOvaDqo.mjs → eventPlugin-Ba00swHF.mjs} +25 -27
- package/dist/{eventPlugin-H6wDDjGO.d.mts → eventPlugin-iGrSEmwJ.d.mts} +105 -5
- package/dist/events/index.d.mts +72 -7
- package/dist/events/index.mjs +216 -4
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +19 -7
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/events/transports/redis.mjs +3 -4
- package/dist/factory/index.d.mts +23 -9
- package/dist/factory/index.mjs +48 -3
- package/dist/{fields-Bi_AVKSo.d.mts → fields-DFwdaWCq.d.mts} +1 -1
- package/dist/{fields-CTd_CrKr.mjs → fields-ipsbIRPK.mjs} +1 -2
- package/dist/hooks/index.d.mts +1 -3
- package/dist/hooks/index.mjs +2 -3
- package/dist/idempotency/index.d.mts +5 -5
- package/dist/idempotency/index.mjs +3 -7
- package/dist/idempotency/mongodb.d.mts +1 -1
- package/dist/idempotency/mongodb.mjs +4 -5
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/idempotency/redis.mjs +2 -5
- package/dist/{fastifyAdapter-6b_eRDBw.d.mts → index-BL8CaQih.d.mts} +56 -57
- package/dist/index-Diqcm14c.d.mts +369 -0
- package/dist/{prisma-Dy5S5F5i.d.mts → index-yhxyjqNb.d.mts} +4 -5
- package/dist/index.d.mts +100 -105
- package/dist/index.mjs +85 -58
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +8 -4
- package/dist/integrations/index.d.mts +4 -2
- package/dist/integrations/index.mjs +1 -1
- package/dist/integrations/jobs.d.mts +2 -2
- package/dist/integrations/jobs.mjs +63 -14
- package/dist/integrations/mcp/index.d.mts +219 -0
- package/dist/integrations/mcp/index.mjs +572 -0
- package/dist/integrations/mcp/testing.d.mts +53 -0
- package/dist/integrations/mcp/testing.mjs +104 -0
- package/dist/integrations/streamline.mjs +39 -19
- package/dist/integrations/webhooks.d.mts +56 -0
- package/dist/integrations/webhooks.mjs +139 -0
- package/dist/integrations/websocket-redis.d.mts +46 -0
- package/dist/integrations/websocket-redis.mjs +50 -0
- package/dist/integrations/websocket.d.mts +68 -2
- package/dist/integrations/websocket.mjs +96 -13
- package/dist/{interface-CSNjltAc.d.mts → interface-B4awm1RJ.d.mts} +2 -2
- package/dist/interface-DGmPxakH.d.mts +2213 -0
- package/dist/{keys-DhqDRxv3.mjs → keys-qcD-TVJl.mjs} +3 -4
- package/dist/{logger-ByrvQWZO.mjs → logger-Dz3j1ItV.mjs} +2 -4
- package/dist/{memory-B2v7KrCB.mjs → memory-Cb_7iy9e.mjs} +2 -4
- package/dist/metrics-Csh4nsvv.mjs +224 -0
- package/dist/migrations/index.d.mts +113 -44
- package/dist/migrations/index.mjs +84 -102
- package/dist/{mongodb-DNKEExbf.mjs → mongodb-BuQ7fNTg.mjs} +1 -4
- package/dist/{mongodb-ClykrfGo.d.mts → mongodb-CUpYfxfD.d.mts} +2 -3
- package/dist/{mongodb-Dg8O_gvd.d.mts → mongodb-bga9AbkD.d.mts} +2 -2
- package/dist/{openapi-9nB_kiuR.mjs → openapi-CBmZ6EQN.mjs} +4 -21
- package/dist/org/index.d.mts +12 -14
- package/dist/org/index.mjs +92 -119
- package/dist/org/types.d.mts +2 -2
- package/dist/org/types.mjs +1 -1
- package/dist/permissions/index.d.mts +4 -278
- package/dist/permissions/index.mjs +4 -579
- package/dist/permissions-CA5zg0yK.mjs +751 -0
- package/dist/plugins/index.d.mts +104 -107
- package/dist/plugins/index.mjs +203 -313
- package/dist/plugins/response-cache.mjs +4 -69
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +24 -11
- package/dist/{pluralize-CM-jZg7p.mjs → pluralize-CcT6qF0a.mjs} +12 -13
- package/dist/policies/index.d.mts +2 -2
- package/dist/policies/index.mjs +80 -83
- package/dist/presets/index.d.mts +26 -19
- package/dist/presets/index.mjs +2 -142
- package/dist/presets/multiTenant.d.mts +1 -4
- package/dist/presets/multiTenant.mjs +4 -6
- package/dist/presets-C9QXJV1u.mjs +422 -0
- package/dist/{queryCachePlugin-B6R0d4av.mjs → queryCachePlugin-ClosZdNS.mjs} +6 -27
- package/dist/{queryCachePlugin-Q6SYuHZ6.d.mts → queryCachePlugin-DcmETvcB.d.mts} +3 -3
- package/dist/queryParser-CgCtsjti.mjs +352 -0
- package/dist/{redis-UwjEp8Ea.d.mts → redis-CQ5YxMC5.d.mts} +2 -2
- package/dist/{redis-stream-CBg0upHI.d.mts → redis-stream-BW9UKLZM.d.mts} +9 -2
- package/dist/registry/index.d.mts +1 -4
- package/dist/registry/index.mjs +3 -4
- package/dist/{introspectionPlugin-B3JkrjwU.mjs → registry-I-ogLgL9.mjs} +1 -8
- package/dist/{requestContext-xi6OKBL-.mjs → requestContext-DYtmNpm5.mjs} +1 -3
- package/dist/resourceToTools-PMFE8HIv.mjs +533 -0
- package/dist/rpc/index.d.mts +90 -0
- package/dist/rpc/index.mjs +248 -0
- package/dist/{schemaConverter-Dtg0Kt9T.mjs → schemaConverter-DjzHpFam.mjs} +1 -2
- package/dist/schemas/index.d.mts +30 -30
- package/dist/schemas/index.mjs +2 -4
- package/dist/scope/index.d.mts +13 -2
- package/dist/scope/index.mjs +18 -5
- package/dist/{sessionManager-D_iEHjQl.d.mts → sessionManager-wbkYj2HL.d.mts} +2 -2
- package/dist/{sse-DkqQ1uxb.mjs → sse-BkViJPlT.mjs} +4 -25
- package/dist/testing/index.d.mts +551 -567
- package/dist/testing/index.mjs +1744 -1799
- package/dist/{tracing-8CEbhF0w.d.mts → tracing-bz_U4EM1.d.mts} +6 -1
- package/dist/{typeGuards-DwxA1t_L.mjs → typeGuards-Cj5Rgvlg.mjs} +1 -2
- package/dist/types/index.d.mts +4 -946
- package/dist/types/index.mjs +2 -4
- package/dist/types-BJmgxNbF.d.mts +275 -0
- package/dist/{types-RLkFVgaw.d.mts → types-BNUccdcf.d.mts} +2 -2
- package/dist/{types-Beqn1Un7.mjs → types-C6TQjtdi.mjs} +30 -2
- package/dist/{types-tKwaViYB.d.mts → types-Dt0-AI6E.d.mts} +68 -27
- package/dist/{types-DelU6kln.mjs → types-ZUu_h0jp.mjs} +1 -2
- package/dist/utils/index.d.mts +254 -351
- package/dist/utils/index.mjs +7 -6
- package/dist/utils-Dc0WhlIl.mjs +594 -0
- package/dist/versioning-BzfeHmhj.mjs +37 -0
- package/package.json +44 -10
- package/skills/arc/SKILL.md +518 -0
- package/skills/arc/references/auth.md +250 -0
- package/skills/arc/references/events.md +272 -0
- package/skills/arc/references/integrations.md +385 -0
- package/skills/arc/references/mcp.md +431 -0
- package/skills/arc/references/production.md +610 -0
- package/skills/arc/references/testing.md +183 -0
- package/dist/audited-CGdLiSlE.mjs +0 -140
- package/dist/chunk-C7Uep-_p.mjs +0 -20
- package/dist/circuitBreaker-CSS2VvL6.mjs +0 -1109
- package/dist/errorHandler-CW3OOeYq.d.mts +0 -72
- package/dist/interface-BtdYtQUA.d.mts +0 -1114
- package/dist/presets-BTeYbw7h.d.mts +0 -57
- package/dist/presets-CeFtfDR8.mjs +0 -119
- /package/dist/{errors-DAWRdiYP.d.mts → errors-CPpvPHT0.d.mts} +0 -0
- /package/dist/{externalPaths-SyPF2tgK.d.mts → externalPaths-DpO-s7r8.d.mts} +0 -0
- /package/dist/{interface-DTbsvIWe.d.mts → interface-D_BWALyZ.d.mts} +0 -0
|
@@ -29,14 +29,13 @@ function hashParams(params) {
|
|
|
29
29
|
function stableStringify(value) {
|
|
30
30
|
if (value === null || value === void 0) return "";
|
|
31
31
|
if (typeof value !== "object") return String(value);
|
|
32
|
-
if (Array.isArray(value)) return
|
|
33
|
-
return "{" + Object.keys(value).sort().map((k) => k
|
|
32
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
33
|
+
return "{" + Object.keys(value).sort().map((k) => `${k}:${stableStringify(value[k])}`).join(",") + "}";
|
|
34
34
|
}
|
|
35
35
|
function djb2(str) {
|
|
36
36
|
let hash = 5381;
|
|
37
37
|
for (let i = 0; i < str.length; i++) hash = (hash << 5) + hash + str.charCodeAt(i) >>> 0;
|
|
38
38
|
return hash;
|
|
39
39
|
}
|
|
40
|
-
|
|
41
40
|
//#endregion
|
|
42
|
-
export { versionKey as i, hashParams as n, tagVersionKey as r, buildQueryKey as t };
|
|
41
|
+
export { versionKey as i, hashParams as n, tagVersionKey as r, buildQueryKey as t };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { t as __exportAll } from "./chunk-
|
|
2
|
-
|
|
1
|
+
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
3
2
|
//#region src/logger/index.ts
|
|
4
3
|
var logger_exports = /* @__PURE__ */ __exportAll({
|
|
5
4
|
arcLog: () => arcLog,
|
|
@@ -73,6 +72,5 @@ function isSuppressed() {
|
|
|
73
72
|
const env = typeof process !== "undefined" ? process.env?.ARC_SUPPRESS_WARNINGS : void 0;
|
|
74
73
|
return env === "1" || env === "true";
|
|
75
74
|
}
|
|
76
|
-
|
|
77
75
|
//#endregion
|
|
78
|
-
export { configureArcLogger as n, logger_exports as r, arcLog as t };
|
|
76
|
+
export { configureArcLogger as n, logger_exports as r, arcLog as t };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { t as __exportAll } from "./chunk-
|
|
2
|
-
|
|
1
|
+
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
3
2
|
//#region src/cache/memory.ts
|
|
4
3
|
var memory_exports = /* @__PURE__ */ __exportAll({
|
|
5
4
|
MemoryCacheStore: () => MemoryCacheStore,
|
|
@@ -138,6 +137,5 @@ var MemoryCacheStore = class {
|
|
|
138
137
|
function clamp(value, min, max) {
|
|
139
138
|
return Math.min(max, Math.max(min, value));
|
|
140
139
|
}
|
|
141
|
-
|
|
142
140
|
//#endregion
|
|
143
|
-
export { memory_exports as n, MemoryCacheStore as t };
|
|
141
|
+
export { memory_exports as n, MemoryCacheStore as t };
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
+
import fp from "fastify-plugin";
|
|
3
|
+
//#region src/plugins/metrics.ts
|
|
4
|
+
var metrics_exports = /* @__PURE__ */ __exportAll({
|
|
5
|
+
default: () => metrics_default,
|
|
6
|
+
metricsPlugin: () => metricsPlugin
|
|
7
|
+
});
|
|
8
|
+
var Counter = class {
|
|
9
|
+
data = /* @__PURE__ */ new Map();
|
|
10
|
+
inc(labels, value = 1) {
|
|
11
|
+
const key = labelKey(labels);
|
|
12
|
+
const existing = this.data.get(key);
|
|
13
|
+
if (existing) existing.value += value;
|
|
14
|
+
else this.data.set(key, {
|
|
15
|
+
labels: { ...labels },
|
|
16
|
+
value
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
values() {
|
|
20
|
+
return [...this.data.values()];
|
|
21
|
+
}
|
|
22
|
+
reset() {
|
|
23
|
+
this.data.clear();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var Histogram = class {
|
|
27
|
+
data = /* @__PURE__ */ new Map();
|
|
28
|
+
observe(labels, value) {
|
|
29
|
+
const key = labelKey(labels);
|
|
30
|
+
const existing = this.data.get(key);
|
|
31
|
+
if (existing) {
|
|
32
|
+
existing.sum += value;
|
|
33
|
+
existing.count += 1;
|
|
34
|
+
} else this.data.set(key, {
|
|
35
|
+
labels: { ...labels },
|
|
36
|
+
sum: value,
|
|
37
|
+
count: 1
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
values() {
|
|
41
|
+
return [...this.data.values()].flatMap(({ labels, sum, count }) => [{
|
|
42
|
+
labels: {
|
|
43
|
+
...labels,
|
|
44
|
+
le: "sum"
|
|
45
|
+
},
|
|
46
|
+
value: sum
|
|
47
|
+
}, {
|
|
48
|
+
labels: {
|
|
49
|
+
...labels,
|
|
50
|
+
le: "count"
|
|
51
|
+
},
|
|
52
|
+
value: count
|
|
53
|
+
}]);
|
|
54
|
+
}
|
|
55
|
+
reset() {
|
|
56
|
+
this.data.clear();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var Gauge = class {
|
|
60
|
+
data = /* @__PURE__ */ new Map();
|
|
61
|
+
set(labels, value) {
|
|
62
|
+
const key = labelKey(labels);
|
|
63
|
+
this.data.set(key, {
|
|
64
|
+
labels: { ...labels },
|
|
65
|
+
value
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
values() {
|
|
69
|
+
return [...this.data.values()];
|
|
70
|
+
}
|
|
71
|
+
reset() {
|
|
72
|
+
this.data.clear();
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
function labelKey(labels) {
|
|
76
|
+
return Object.entries(labels).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}=${v}`).join(",");
|
|
77
|
+
}
|
|
78
|
+
function toPrometheusText(metrics) {
|
|
79
|
+
const lines = [];
|
|
80
|
+
for (const m of metrics) {
|
|
81
|
+
lines.push(`# HELP ${m.name} ${m.help}`);
|
|
82
|
+
lines.push(`# TYPE ${m.name} ${m.type}`);
|
|
83
|
+
for (const v of m.values) {
|
|
84
|
+
const labelStr = Object.entries(v.labels).map(([k, val]) => `${k}="${val}"`).join(",");
|
|
85
|
+
lines.push(`${m.name}{${labelStr}} ${v.value}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return `${lines.join("\n")}\n`;
|
|
89
|
+
}
|
|
90
|
+
const metricsPlugin = async (fastify, opts = {}) => {
|
|
91
|
+
const path = opts.path ?? "/_metrics";
|
|
92
|
+
const prefix = opts.prefix ?? "arc";
|
|
93
|
+
const httpRequestsTotal = new Counter();
|
|
94
|
+
const crudOpsTotal = new Counter();
|
|
95
|
+
const cacheHitsTotal = new Counter();
|
|
96
|
+
const cacheMissesTotal = new Counter();
|
|
97
|
+
const eventsPublishedTotal = new Counter();
|
|
98
|
+
const eventsConsumedTotal = new Counter();
|
|
99
|
+
const httpDuration = new Histogram();
|
|
100
|
+
const crudDuration = new Histogram();
|
|
101
|
+
const circuitBreakerState = new Gauge();
|
|
102
|
+
const collector = {
|
|
103
|
+
collect() {
|
|
104
|
+
const metrics = [
|
|
105
|
+
{
|
|
106
|
+
name: `${prefix}_http_requests_total`,
|
|
107
|
+
type: "counter",
|
|
108
|
+
help: "Total HTTP requests",
|
|
109
|
+
values: httpRequestsTotal.values()
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: `${prefix}_http_request_duration_seconds`,
|
|
113
|
+
type: "histogram",
|
|
114
|
+
help: "HTTP request duration in seconds",
|
|
115
|
+
values: httpDuration.values()
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: `${prefix}_crud_operations_total`,
|
|
119
|
+
type: "counter",
|
|
120
|
+
help: "Total CRUD operations by resource",
|
|
121
|
+
values: crudOpsTotal.values()
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: `${prefix}_crud_operation_duration_seconds`,
|
|
125
|
+
type: "histogram",
|
|
126
|
+
help: "CRUD operation duration in seconds",
|
|
127
|
+
values: crudDuration.values()
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: `${prefix}_cache_hits_total`,
|
|
131
|
+
type: "counter",
|
|
132
|
+
help: "Total cache hits by resource",
|
|
133
|
+
values: cacheHitsTotal.values()
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: `${prefix}_cache_misses_total`,
|
|
137
|
+
type: "counter",
|
|
138
|
+
help: "Total cache misses by resource",
|
|
139
|
+
values: cacheMissesTotal.values()
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: `${prefix}_events_published_total`,
|
|
143
|
+
type: "counter",
|
|
144
|
+
help: "Total events published",
|
|
145
|
+
values: eventsPublishedTotal.values()
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: `${prefix}_events_consumed_total`,
|
|
149
|
+
type: "counter",
|
|
150
|
+
help: "Total events consumed",
|
|
151
|
+
values: eventsConsumedTotal.values()
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: `${prefix}_circuit_breaker_state`,
|
|
155
|
+
type: "gauge",
|
|
156
|
+
help: "Circuit breaker state (0=closed, 1=open, 2=half-open)",
|
|
157
|
+
values: circuitBreakerState.values()
|
|
158
|
+
}
|
|
159
|
+
];
|
|
160
|
+
opts.onCollect?.(metrics);
|
|
161
|
+
return metrics;
|
|
162
|
+
},
|
|
163
|
+
reset() {
|
|
164
|
+
httpRequestsTotal.reset();
|
|
165
|
+
httpDuration.reset();
|
|
166
|
+
crudOpsTotal.reset();
|
|
167
|
+
crudDuration.reset();
|
|
168
|
+
cacheHitsTotal.reset();
|
|
169
|
+
cacheMissesTotal.reset();
|
|
170
|
+
eventsPublishedTotal.reset();
|
|
171
|
+
eventsConsumedTotal.reset();
|
|
172
|
+
circuitBreakerState.reset();
|
|
173
|
+
},
|
|
174
|
+
recordOperation(resource, operation, status, durationMs) {
|
|
175
|
+
crudOpsTotal.inc({
|
|
176
|
+
resource,
|
|
177
|
+
operation,
|
|
178
|
+
status: String(status)
|
|
179
|
+
});
|
|
180
|
+
crudDuration.observe({
|
|
181
|
+
resource,
|
|
182
|
+
operation
|
|
183
|
+
}, durationMs / 1e3);
|
|
184
|
+
},
|
|
185
|
+
recordCacheHit(resource) {
|
|
186
|
+
cacheHitsTotal.inc({ resource });
|
|
187
|
+
},
|
|
188
|
+
recordCacheMiss(resource) {
|
|
189
|
+
cacheMissesTotal.inc({ resource });
|
|
190
|
+
},
|
|
191
|
+
recordEventPublish(eventType) {
|
|
192
|
+
eventsPublishedTotal.inc({ event_type: eventType });
|
|
193
|
+
},
|
|
194
|
+
recordEventConsume(eventType) {
|
|
195
|
+
eventsConsumedTotal.inc({ event_type: eventType });
|
|
196
|
+
},
|
|
197
|
+
recordCircuitBreakerState(service, state) {
|
|
198
|
+
const stateValue = state === "open" ? 1 : state === "half-open" ? 2 : 0;
|
|
199
|
+
circuitBreakerState.set({ service }, stateValue);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
fastify.decorate("metrics", collector);
|
|
203
|
+
fastify.addHook("onResponse", async (request, reply) => {
|
|
204
|
+
if (request.url === path) return;
|
|
205
|
+
const duration = reply.elapsedTime / 1e3;
|
|
206
|
+
const labels = {
|
|
207
|
+
method: request.method,
|
|
208
|
+
route: request.routeOptions?.url ?? request.url,
|
|
209
|
+
status: String(reply.statusCode)
|
|
210
|
+
};
|
|
211
|
+
httpRequestsTotal.inc(labels);
|
|
212
|
+
httpDuration.observe(labels, duration);
|
|
213
|
+
});
|
|
214
|
+
fastify.get(path, async (_request, reply) => {
|
|
215
|
+
const text = toPrometheusText(collector.collect());
|
|
216
|
+
return reply.type("text/plain; charset=utf-8").send(text);
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
var metrics_default = fp(metricsPlugin, {
|
|
220
|
+
name: "arc-metrics",
|
|
221
|
+
fastify: "5.x"
|
|
222
|
+
});
|
|
223
|
+
//#endregion
|
|
224
|
+
export { metrics_default as n, metrics_exports as r, metricsPlugin as t };
|
|
@@ -1,6 +1,41 @@
|
|
|
1
|
-
import mongoose from "mongoose";
|
|
2
|
-
|
|
3
1
|
//#region src/migrations/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Schema Versioning and Migrations System
|
|
4
|
+
*
|
|
5
|
+
* Manages database schema changes over time with version tracking.
|
|
6
|
+
* Supports forward migrations, rollbacks, and schema compatibility layers.
|
|
7
|
+
*
|
|
8
|
+
* DB-agnostic: the `db` parameter is typed as `unknown` — the user passes
|
|
9
|
+
* whatever connection object their adapter uses (Mongoose db, Prisma client,
|
|
10
|
+
* Knex instance, etc.) and their `up`/`down` functions cast it internally.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* import { defineMigration, MigrationRunner } from '@classytic/arc/migrations';
|
|
14
|
+
*
|
|
15
|
+
* const productV2 = defineMigration({
|
|
16
|
+
* version: 2,
|
|
17
|
+
* resource: 'product',
|
|
18
|
+
* up: async (db) => {
|
|
19
|
+
* const mongo = db as import('mongoose').mongo.Db;
|
|
20
|
+
* await mongo.collection('products').updateMany(
|
|
21
|
+
* {},
|
|
22
|
+
* { $rename: { 'oldField': 'newField' } }
|
|
23
|
+
* );
|
|
24
|
+
* },
|
|
25
|
+
* down: async (db) => {
|
|
26
|
+
* const mongo = db as import('mongoose').mongo.Db;
|
|
27
|
+
* await mongo.collection('products').updateMany(
|
|
28
|
+
* {},
|
|
29
|
+
* { $rename: { 'newField': 'oldField' } }
|
|
30
|
+
* );
|
|
31
|
+
* },
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* const runner = new MigrationRunner(mongoose.connection.db, {
|
|
35
|
+
* store: new MongoMigrationStore(mongoose.connection.db),
|
|
36
|
+
* });
|
|
37
|
+
* await runner.up(migrations);
|
|
38
|
+
*/
|
|
4
39
|
interface Migration {
|
|
5
40
|
/** Migration version (sequential number) */
|
|
6
41
|
version: number;
|
|
@@ -9,17 +44,18 @@ interface Migration {
|
|
|
9
44
|
/** Description of the migration */
|
|
10
45
|
description?: string;
|
|
11
46
|
/**
|
|
12
|
-
* Forward migration (apply schema change)
|
|
47
|
+
* Forward migration (apply schema change).
|
|
48
|
+
* The `db` parameter is whatever connection object you pass to the runner.
|
|
13
49
|
*/
|
|
14
|
-
up: (db:
|
|
50
|
+
up: (db: unknown) => Promise<void>;
|
|
15
51
|
/**
|
|
16
|
-
* Backward migration (revert schema change)
|
|
52
|
+
* Backward migration (revert schema change).
|
|
17
53
|
*/
|
|
18
|
-
down: (db:
|
|
54
|
+
down: (db: unknown) => Promise<void>;
|
|
19
55
|
/**
|
|
20
56
|
* Optional validation that data is compatible after migration
|
|
21
57
|
*/
|
|
22
|
-
validate?: (db:
|
|
58
|
+
validate?: (db: unknown) => Promise<boolean>;
|
|
23
59
|
}
|
|
24
60
|
interface MigrationRecord {
|
|
25
61
|
version: number;
|
|
@@ -28,6 +64,54 @@ interface MigrationRecord {
|
|
|
28
64
|
appliedAt: Date;
|
|
29
65
|
executionTime: number;
|
|
30
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* DB-agnostic migration store interface.
|
|
69
|
+
*
|
|
70
|
+
* Users implement this for their database:
|
|
71
|
+
* - MongoMigrationStore (uses a `_migrations` collection)
|
|
72
|
+
* - PrismaMigrationStore (uses a `_migrations` table)
|
|
73
|
+
* - or any custom store
|
|
74
|
+
*/
|
|
75
|
+
interface MigrationStore {
|
|
76
|
+
/** Get all applied migration records, sorted by appliedAt ascending */
|
|
77
|
+
getApplied(): Promise<MigrationRecord[]>;
|
|
78
|
+
/** Record a completed migration */
|
|
79
|
+
record(migration: Migration, executionTime: number): Promise<void>;
|
|
80
|
+
/** Remove a migration record (for rollback) */
|
|
81
|
+
remove(migration: Migration): Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Minimal logger interface — matches Fastify's logger, pino, console, etc.
|
|
85
|
+
*/
|
|
86
|
+
interface MigrationLogger {
|
|
87
|
+
info(msg: string): void;
|
|
88
|
+
error(msg: string): void;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* MongoDB-backed migration store.
|
|
92
|
+
*
|
|
93
|
+
* Uses a `_migrations` collection in the same database.
|
|
94
|
+
* The `db` parameter accepts any object with a `.collection()` method
|
|
95
|
+
* (Mongoose db, native MongoDB Db, etc.)
|
|
96
|
+
*/
|
|
97
|
+
declare class MongoMigrationStore implements MigrationStore {
|
|
98
|
+
private readonly collectionName;
|
|
99
|
+
private readonly db;
|
|
100
|
+
constructor(db: {
|
|
101
|
+
collection(name: string): any;
|
|
102
|
+
}, opts?: {
|
|
103
|
+
collectionName?: string;
|
|
104
|
+
});
|
|
105
|
+
getApplied(): Promise<MigrationRecord[]>;
|
|
106
|
+
record(migration: Migration, executionTime: number): Promise<void>;
|
|
107
|
+
remove(migration: Migration): Promise<void>;
|
|
108
|
+
}
|
|
109
|
+
interface MigrationRunnerOptions {
|
|
110
|
+
/** Migration store (required — use MongoMigrationStore or implement your own) */
|
|
111
|
+
store: MigrationStore;
|
|
112
|
+
/** Logger (defaults to process.stdout/stderr) */
|
|
113
|
+
logger?: MigrationLogger;
|
|
114
|
+
}
|
|
31
115
|
/**
|
|
32
116
|
* Define a migration
|
|
33
117
|
*/
|
|
@@ -35,12 +119,30 @@ declare function defineMigration(migration: Migration): Migration;
|
|
|
35
119
|
/**
|
|
36
120
|
* Migration Runner
|
|
37
121
|
*
|
|
38
|
-
* Manages execution of migrations with tracking and rollback
|
|
122
|
+
* DB-agnostic. Manages execution of migrations with tracking and rollback.
|
|
123
|
+
* The `db` parameter is passed through to migration `up`/`down` functions
|
|
124
|
+
* as-is — the runner never touches it directly.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* // MongoDB
|
|
129
|
+
* const runner = new MigrationRunner(mongoose.connection.db, {
|
|
130
|
+
* store: new MongoMigrationStore(mongoose.connection.db),
|
|
131
|
+
* });
|
|
132
|
+
*
|
|
133
|
+
* // Prisma
|
|
134
|
+
* const runner = new MigrationRunner(prisma, {
|
|
135
|
+
* store: new PrismaMigrationStore(prisma), // user-implemented
|
|
136
|
+
* });
|
|
137
|
+
*
|
|
138
|
+
* await runner.up(migrations);
|
|
139
|
+
* ```
|
|
39
140
|
*/
|
|
40
141
|
declare class MigrationRunner {
|
|
41
|
-
private readonly collectionName;
|
|
42
142
|
private readonly db;
|
|
43
|
-
|
|
143
|
+
private readonly store;
|
|
144
|
+
private readonly log;
|
|
145
|
+
constructor(db: unknown, opts: MigrationRunnerOptions);
|
|
44
146
|
/**
|
|
45
147
|
* Run all pending migrations
|
|
46
148
|
*/
|
|
@@ -69,14 +171,6 @@ declare class MigrationRunner {
|
|
|
69
171
|
* Run a single migration
|
|
70
172
|
*/
|
|
71
173
|
private runMigration;
|
|
72
|
-
/**
|
|
73
|
-
* Record a completed migration
|
|
74
|
-
*/
|
|
75
|
-
private recordMigration;
|
|
76
|
-
/**
|
|
77
|
-
* Remove a migration record
|
|
78
|
-
*/
|
|
79
|
-
private removeMigration;
|
|
80
174
|
}
|
|
81
175
|
/**
|
|
82
176
|
* Schema version definition for resources
|
|
@@ -127,30 +221,5 @@ declare class MigrationRegistry {
|
|
|
127
221
|
*/
|
|
128
222
|
clear(): void;
|
|
129
223
|
}
|
|
130
|
-
/**
|
|
131
|
-
* Global migration registry instance
|
|
132
|
-
*/
|
|
133
|
-
declare const migrationRegistry: MigrationRegistry;
|
|
134
|
-
/**
|
|
135
|
-
* Common migration helpers
|
|
136
|
-
*/
|
|
137
|
-
declare const migrationHelpers: {
|
|
138
|
-
/**
|
|
139
|
-
* Rename a field across all documents
|
|
140
|
-
*/
|
|
141
|
-
renameField: (collection: string, oldName: string, newName: string) => Migration;
|
|
142
|
-
/**
|
|
143
|
-
* Add a new field with default value
|
|
144
|
-
*/
|
|
145
|
-
addField: (collection: string, fieldName: string, defaultValue: unknown) => Migration;
|
|
146
|
-
/**
|
|
147
|
-
* Remove a field
|
|
148
|
-
*/
|
|
149
|
-
removeField: (collection: string, fieldName: string) => Migration;
|
|
150
|
-
/**
|
|
151
|
-
* Create an index
|
|
152
|
-
*/
|
|
153
|
-
createIndex: (collection: string, fields: Record<string, 1 | -1>, options?: Record<string, unknown>) => Migration;
|
|
154
|
-
};
|
|
155
224
|
//#endregion
|
|
156
|
-
export { Migration, MigrationRecord, MigrationRegistry, MigrationRunner,
|
|
225
|
+
export { Migration, MigrationLogger, MigrationRecord, MigrationRegistry, MigrationRunner, MigrationRunnerOptions, MigrationStore, MongoMigrationStore, SchemaVersion, defineMigration, withSchemaVersion };
|