@classytic/arc 1.1.0 → 2.1.3
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 +247 -794
- package/bin/arc.js +91 -52
- package/dist/EventTransport-BkUDYZEb.d.mts +99 -0
- package/dist/HookSystem-BsGV-j2l.mjs +404 -0
- package/dist/ResourceRegistry-7Ic20ZMw.mjs +249 -0
- package/dist/adapters/index.d.mts +5 -0
- package/dist/adapters/index.mjs +3 -0
- package/dist/audit/index.d.mts +81 -0
- package/dist/audit/index.mjs +275 -0
- package/dist/audit/mongodb.d.mts +5 -0
- package/dist/audit/mongodb.mjs +3 -0
- package/dist/audited-CGdLiSlE.mjs +140 -0
- package/dist/auth/index.d.mts +188 -0
- package/dist/auth/index.mjs +1096 -0
- package/dist/auth/redis-session.d.mts +43 -0
- package/dist/auth/redis-session.mjs +75 -0
- package/dist/betterAuthOpenApi-DjWDddNc.mjs +249 -0
- package/dist/cache/index.d.mts +145 -0
- package/dist/cache/index.mjs +91 -0
- package/dist/caching-GSDJcA6-.mjs +93 -0
- package/dist/chunk-C7Uep-_p.mjs +20 -0
- package/dist/circuitBreaker-DYhWBW_D.mjs +1096 -0
- package/dist/cli/commands/describe.d.mts +18 -0
- package/dist/cli/commands/describe.mjs +238 -0
- package/dist/cli/commands/docs.d.mts +13 -0
- package/dist/cli/commands/docs.mjs +52 -0
- package/dist/cli/commands/{generate.d.ts → generate.d.mts} +3 -2
- package/dist/cli/commands/generate.mjs +357 -0
- package/dist/cli/commands/{init.d.ts → init.d.mts} +11 -8
- package/dist/cli/commands/{init.js → init.mjs} +807 -617
- package/dist/cli/commands/introspect.d.mts +10 -0
- package/dist/cli/commands/introspect.mjs +75 -0
- package/dist/cli/index.d.mts +16 -0
- package/dist/cli/index.mjs +156 -0
- package/dist/constants-DdXFXQtN.mjs +84 -0
- package/dist/core/index.d.mts +5 -0
- package/dist/core/index.mjs +4 -0
- package/dist/createApp-D2D5XXaV.mjs +559 -0
- package/dist/defineResource-PXzSJ15_.mjs +2197 -0
- package/dist/discovery/index.d.mts +46 -0
- package/dist/discovery/index.mjs +109 -0
- package/dist/docs/index.d.mts +162 -0
- package/dist/docs/index.mjs +74 -0
- package/dist/elevation-DGo5shaX.d.mts +87 -0
- package/dist/elevation-DSTbVvYj.mjs +113 -0
- package/dist/errorHandler-C3GY3_ow.mjs +108 -0
- package/dist/errorHandler-CW3OOeYq.d.mts +72 -0
- package/dist/errors-DAWRdiYP.d.mts +124 -0
- package/dist/errors-DBANPbGr.mjs +211 -0
- package/dist/eventPlugin-BEOvaDqo.mjs +229 -0
- package/dist/eventPlugin-H6wDDjGO.d.mts +124 -0
- package/dist/events/index.d.mts +53 -0
- package/dist/events/index.mjs +51 -0
- package/dist/events/transports/redis-stream-entry.d.mts +2 -0
- package/dist/events/transports/redis-stream-entry.mjs +177 -0
- package/dist/events/transports/redis.d.mts +76 -0
- package/dist/events/transports/redis.mjs +124 -0
- package/dist/externalPaths-SyPF2tgK.d.mts +50 -0
- package/dist/factory/index.d.mts +63 -0
- package/dist/factory/index.mjs +3 -0
- package/dist/fastifyAdapter-C8DlE0YH.d.mts +216 -0
- package/dist/fields-Bi_AVKSo.d.mts +109 -0
- package/dist/fields-CTd_CrKr.mjs +114 -0
- package/dist/hooks/index.d.mts +4 -0
- package/dist/hooks/index.mjs +3 -0
- package/dist/idempotency/index.d.mts +96 -0
- package/dist/idempotency/index.mjs +319 -0
- package/dist/idempotency/mongodb.d.mts +2 -0
- package/dist/idempotency/mongodb.mjs +114 -0
- package/dist/idempotency/redis.d.mts +2 -0
- package/dist/idempotency/redis.mjs +103 -0
- package/dist/index.d.mts +260 -0
- package/dist/index.mjs +104 -0
- package/dist/integrations/event-gateway.d.mts +46 -0
- package/dist/integrations/event-gateway.mjs +43 -0
- package/dist/integrations/index.d.mts +5 -0
- package/dist/integrations/index.mjs +1 -0
- package/dist/integrations/jobs.d.mts +103 -0
- package/dist/integrations/jobs.mjs +123 -0
- package/dist/integrations/streamline.d.mts +60 -0
- package/dist/integrations/streamline.mjs +125 -0
- package/dist/integrations/websocket.d.mts +82 -0
- package/dist/integrations/websocket.mjs +288 -0
- package/dist/interface-CSNjltAc.d.mts +77 -0
- package/dist/interface-DTbsvIWe.d.mts +54 -0
- package/dist/interface-e9XfSsUV.d.mts +1097 -0
- package/dist/introspectionPlugin-B3JkrjwU.mjs +53 -0
- package/dist/keys-DhqDRxv3.mjs +42 -0
- package/dist/logger-ByrvQWZO.mjs +78 -0
- package/dist/memory-B2v7KrCB.mjs +143 -0
- package/dist/migrations/index.d.mts +156 -0
- package/dist/migrations/index.mjs +260 -0
- package/dist/mongodb-ClykrfGo.d.mts +118 -0
- package/dist/mongodb-DNKEExbf.mjs +93 -0
- package/dist/mongodb-Dg8O_gvd.d.mts +71 -0
- package/dist/openapi-9nB_kiuR.mjs +525 -0
- package/dist/org/index.d.mts +68 -0
- package/dist/org/index.mjs +513 -0
- package/dist/org/types.d.mts +82 -0
- package/dist/org/types.mjs +1 -0
- package/dist/permissions/index.d.mts +278 -0
- package/dist/permissions/index.mjs +579 -0
- package/dist/plugins/index.d.mts +172 -0
- package/dist/plugins/index.mjs +522 -0
- package/dist/plugins/response-cache.d.mts +87 -0
- package/dist/plugins/response-cache.mjs +283 -0
- package/dist/plugins/tracing-entry.d.mts +2 -0
- package/dist/plugins/tracing-entry.mjs +185 -0
- package/dist/pluralize-CM-jZg7p.mjs +86 -0
- package/dist/policies/{index.d.ts → index.d.mts} +204 -170
- package/dist/policies/index.mjs +321 -0
- package/dist/presets/{index.d.ts → index.d.mts} +62 -131
- package/dist/presets/index.mjs +143 -0
- package/dist/presets/multiTenant.d.mts +24 -0
- package/dist/presets/multiTenant.mjs +113 -0
- package/dist/presets-BTeYbw7h.d.mts +57 -0
- package/dist/presets-CeFtfDR8.mjs +119 -0
- package/dist/prisma-C3iornoK.d.mts +274 -0
- package/dist/prisma-DJbMt3yf.mjs +627 -0
- package/dist/queryCachePlugin-B6R0d4av.mjs +138 -0
- package/dist/queryCachePlugin-Q6SYuHZ6.d.mts +71 -0
- package/dist/redis-UwjEp8Ea.d.mts +49 -0
- package/dist/redis-stream-CBg0upHI.d.mts +103 -0
- package/dist/registry/index.d.mts +11 -0
- package/dist/registry/index.mjs +4 -0
- package/dist/requestContext-xi6OKBL-.mjs +55 -0
- package/dist/schemaConverter-Dtg0Kt9T.mjs +98 -0
- package/dist/schemas/index.d.mts +63 -0
- package/dist/schemas/index.mjs +82 -0
- package/dist/scope/index.d.mts +21 -0
- package/dist/scope/index.mjs +65 -0
- package/dist/sessionManager-D_iEHjQl.d.mts +186 -0
- package/dist/sse-DkqQ1uxb.mjs +123 -0
- package/dist/testing/index.d.mts +907 -0
- package/dist/testing/index.mjs +1976 -0
- package/dist/tracing-8CEbhF0w.d.mts +70 -0
- package/dist/typeGuards-DwxA1t_L.mjs +9 -0
- package/dist/types/index.d.mts +946 -0
- package/dist/types/index.mjs +14 -0
- package/dist/types-B0dhNrnd.d.mts +445 -0
- package/dist/types-Beqn1Un7.mjs +38 -0
- package/dist/types-DelU6kln.mjs +25 -0
- package/dist/types-RLkFVgaw.d.mts +101 -0
- package/dist/utils/index.d.mts +747 -0
- package/dist/utils/index.mjs +6 -0
- package/package.json +194 -68
- package/dist/BaseController-DVAiHxEQ.d.ts +0 -233
- package/dist/adapters/index.d.ts +0 -237
- package/dist/adapters/index.js +0 -668
- package/dist/arcCorePlugin-CsShQdyP.d.ts +0 -273
- package/dist/audit/index.d.ts +0 -195
- package/dist/audit/index.js +0 -319
- package/dist/auth/index.d.ts +0 -47
- package/dist/auth/index.js +0 -174
- package/dist/cli/commands/docs.d.ts +0 -11
- package/dist/cli/commands/docs.js +0 -474
- package/dist/cli/commands/generate.js +0 -334
- package/dist/cli/commands/introspect.d.ts +0 -8
- package/dist/cli/commands/introspect.js +0 -338
- package/dist/cli/index.d.ts +0 -4
- package/dist/cli/index.js +0 -3269
- package/dist/core/index.d.ts +0 -220
- package/dist/core/index.js +0 -2786
- package/dist/createApp-Ce9wl8W9.d.ts +0 -77
- package/dist/docs/index.d.ts +0 -166
- package/dist/docs/index.js +0 -658
- package/dist/errors-8WIxGS_6.d.ts +0 -122
- package/dist/events/index.d.ts +0 -117
- package/dist/events/index.js +0 -89
- package/dist/factory/index.d.ts +0 -38
- package/dist/factory/index.js +0 -1652
- package/dist/hooks/index.d.ts +0 -4
- package/dist/hooks/index.js +0 -199
- package/dist/idempotency/index.d.ts +0 -323
- package/dist/idempotency/index.js +0 -500
- package/dist/index-B4t03KQ0.d.ts +0 -1366
- package/dist/index.d.ts +0 -135
- package/dist/index.js +0 -4756
- package/dist/migrations/index.d.ts +0 -185
- package/dist/migrations/index.js +0 -274
- package/dist/org/index.d.ts +0 -129
- package/dist/org/index.js +0 -220
- package/dist/permissions/index.d.ts +0 -144
- package/dist/permissions/index.js +0 -103
- package/dist/plugins/index.d.ts +0 -46
- package/dist/plugins/index.js +0 -1069
- package/dist/policies/index.js +0 -196
- package/dist/presets/index.js +0 -384
- package/dist/presets/multiTenant.d.ts +0 -39
- package/dist/presets/multiTenant.js +0 -112
- package/dist/registry/index.d.ts +0 -16
- package/dist/registry/index.js +0 -253
- package/dist/testing/index.d.ts +0 -618
- package/dist/testing/index.js +0 -48020
- package/dist/types/index.d.ts +0 -4
- package/dist/types/index.js +0 -8
- package/dist/types-B99TBmFV.d.ts +0 -76
- package/dist/types-BvckRbs2.d.ts +0 -143
- package/dist/utils/index.d.ts +0 -679
- package/dist/utils/index.js +0 -931
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-C7Uep-_p.mjs";
|
|
2
|
+
import { i as versionKey, r as tagVersionKey } from "./keys-DhqDRxv3.mjs";
|
|
3
|
+
import { t as hasEvents } from "./typeGuards-DwxA1t_L.mjs";
|
|
4
|
+
import { t as MemoryCacheStore } from "./memory-B2v7KrCB.mjs";
|
|
5
|
+
import fp from "fastify-plugin";
|
|
6
|
+
|
|
7
|
+
//#region src/cache/QueryCache.ts
|
|
8
|
+
var QueryCache = class {
|
|
9
|
+
store;
|
|
10
|
+
constructor(store) {
|
|
11
|
+
this.store = store;
|
|
12
|
+
}
|
|
13
|
+
async get(key) {
|
|
14
|
+
const envelope = await this.store.get(key);
|
|
15
|
+
if (!envelope || !envelope.createdAt) return {
|
|
16
|
+
data: void 0,
|
|
17
|
+
status: "miss"
|
|
18
|
+
};
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
if (now >= envelope.expiresAt) {
|
|
21
|
+
await this.store.delete(key);
|
|
22
|
+
return {
|
|
23
|
+
data: void 0,
|
|
24
|
+
status: "miss"
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (now < envelope.staleAfter) return {
|
|
28
|
+
data: envelope.data,
|
|
29
|
+
status: "fresh"
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
data: envelope.data,
|
|
33
|
+
status: "stale"
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async set(key, data, config) {
|
|
37
|
+
const staleTimeMs = (config.staleTime ?? 0) * 1e3;
|
|
38
|
+
const totalTtl = staleTimeMs + (config.gcTime ?? 60) * 1e3;
|
|
39
|
+
const now = Date.now();
|
|
40
|
+
const envelope = {
|
|
41
|
+
data,
|
|
42
|
+
createdAt: now,
|
|
43
|
+
staleAfter: now + staleTimeMs,
|
|
44
|
+
expiresAt: now + totalTtl,
|
|
45
|
+
tags: config.tags ?? []
|
|
46
|
+
};
|
|
47
|
+
await this.store.set(key, envelope, { ttlMs: totalTtl });
|
|
48
|
+
}
|
|
49
|
+
async invalidate(key) {
|
|
50
|
+
await this.store.delete(key);
|
|
51
|
+
}
|
|
52
|
+
/** Get current version for a resource (defaults to 0 if not set) */
|
|
53
|
+
async getResourceVersion(resource) {
|
|
54
|
+
return await this.store.get(versionKey(resource)) ?? 0;
|
|
55
|
+
}
|
|
56
|
+
/** Bump resource version — orphans all cached queries for this resource */
|
|
57
|
+
async bumpResourceVersion(resource) {
|
|
58
|
+
const key = versionKey(resource);
|
|
59
|
+
const newVersion = Date.now();
|
|
60
|
+
await this.store.set(key, newVersion, { ttlMs: 1440 * 60 * 1e3 });
|
|
61
|
+
}
|
|
62
|
+
/** Get current version for a tag */
|
|
63
|
+
async getTagVersion(tag) {
|
|
64
|
+
return await this.store.get(tagVersionKey(tag)) ?? 0;
|
|
65
|
+
}
|
|
66
|
+
/** Bump tag version — orphans all cached queries tagged with this tag */
|
|
67
|
+
async bumpTagVersion(tag) {
|
|
68
|
+
const key = tagVersionKey(tag);
|
|
69
|
+
const newVersion = Date.now();
|
|
70
|
+
await this.store.set(key, newVersion, { ttlMs: 1440 * 60 * 1e3 });
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/cache/queryCachePlugin.ts
|
|
76
|
+
/**
|
|
77
|
+
* QueryCache Fastify Plugin
|
|
78
|
+
*
|
|
79
|
+
* Registers QueryCache on `fastify.queryCache` and wires automatic
|
|
80
|
+
* cache invalidation via CRUD events. Zero config for memory mode.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* // Memory mode (default)
|
|
85
|
+
* await fastify.register(queryCachePlugin);
|
|
86
|
+
*
|
|
87
|
+
* // With Redis store
|
|
88
|
+
* await fastify.register(queryCachePlugin, {
|
|
89
|
+
* store: new RedisCacheStore({ client: redis, prefix: 'arc:qc:' }),
|
|
90
|
+
* defaults: { staleTime: 30, gcTime: 300 },
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
var queryCachePlugin_exports = /* @__PURE__ */ __exportAll({ queryCachePlugin: () => queryCachePlugin });
|
|
95
|
+
const CRUD_SUFFIXES = new Set([
|
|
96
|
+
"created",
|
|
97
|
+
"updated",
|
|
98
|
+
"deleted"
|
|
99
|
+
]);
|
|
100
|
+
const queryCachePluginImpl = async (fastify, opts = {}) => {
|
|
101
|
+
const store = opts.store ?? new MemoryCacheStore();
|
|
102
|
+
const queryCache = new QueryCache(store);
|
|
103
|
+
const defaults = {
|
|
104
|
+
staleTime: opts.defaults?.staleTime ?? 0,
|
|
105
|
+
gcTime: opts.defaults?.gcTime ?? 60
|
|
106
|
+
};
|
|
107
|
+
fastify.decorate("queryCache", queryCache);
|
|
108
|
+
fastify.decorate("queryCacheConfig", defaults);
|
|
109
|
+
const crossResourceRules = [];
|
|
110
|
+
fastify.decorate("registerCacheInvalidationRule", (rule) => {
|
|
111
|
+
crossResourceRules.push(rule);
|
|
112
|
+
});
|
|
113
|
+
fastify.addHook("onReady", async () => {
|
|
114
|
+
if (!hasEvents(fastify)) return;
|
|
115
|
+
await fastify.events.subscribe("*", async (event) => {
|
|
116
|
+
const type = event.type;
|
|
117
|
+
const dotIdx = type.lastIndexOf(".");
|
|
118
|
+
if (dotIdx === -1) return;
|
|
119
|
+
const suffix = type.slice(dotIdx + 1);
|
|
120
|
+
if (!CRUD_SUFFIXES.has(suffix)) return;
|
|
121
|
+
const resource = type.slice(0, dotIdx);
|
|
122
|
+
await queryCache.bumpResourceVersion(resource);
|
|
123
|
+
});
|
|
124
|
+
for (const rule of crossResourceRules) await fastify.events.subscribe(rule.pattern, async () => {
|
|
125
|
+
for (const tag of rule.tags) await queryCache.bumpTagVersion(tag);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
fastify.addHook("onClose", async () => {
|
|
129
|
+
if ("close" in store && typeof store.close === "function") await store.close();
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
const queryCachePlugin = fp(queryCachePluginImpl, {
|
|
133
|
+
name: "arc-query-cache",
|
|
134
|
+
fastify: "5.x"
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
//#endregion
|
|
138
|
+
export { queryCachePlugin_exports as n, QueryCache as r, queryCachePlugin as t };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { i as CacheStore } from "./interface-DTbsvIWe.mjs";
|
|
2
|
+
import { FastifyPluginAsync } from "fastify";
|
|
3
|
+
|
|
4
|
+
//#region src/cache/QueryCache.d.ts
|
|
5
|
+
/** Metadata wrapper stored in CacheStore */
|
|
6
|
+
interface CacheEnvelope<T = unknown> {
|
|
7
|
+
data: T;
|
|
8
|
+
createdAt: number;
|
|
9
|
+
staleAfter: number;
|
|
10
|
+
expiresAt: number;
|
|
11
|
+
tags: string[];
|
|
12
|
+
}
|
|
13
|
+
interface QueryCacheConfig {
|
|
14
|
+
/** Seconds data is "fresh" (no revalidation). Default: 0 */
|
|
15
|
+
staleTime?: number;
|
|
16
|
+
/** Seconds stale data stays cached (SWR window). Default: 60 */
|
|
17
|
+
gcTime?: number;
|
|
18
|
+
/** Tags for group invalidation */
|
|
19
|
+
tags?: string[];
|
|
20
|
+
}
|
|
21
|
+
type CacheStatus = 'fresh' | 'stale' | 'miss';
|
|
22
|
+
interface CacheResult<T> {
|
|
23
|
+
data: T;
|
|
24
|
+
status: CacheStatus;
|
|
25
|
+
}
|
|
26
|
+
declare class QueryCache {
|
|
27
|
+
private readonly store;
|
|
28
|
+
constructor(store: CacheStore);
|
|
29
|
+
get<T>(key: string): Promise<CacheResult<T>>;
|
|
30
|
+
set<T>(key: string, data: T, config: QueryCacheConfig): Promise<void>;
|
|
31
|
+
invalidate(key: string): Promise<void>;
|
|
32
|
+
/** Get current version for a resource (defaults to 0 if not set) */
|
|
33
|
+
getResourceVersion(resource: string): Promise<number>;
|
|
34
|
+
/** Bump resource version — orphans all cached queries for this resource */
|
|
35
|
+
bumpResourceVersion(resource: string): Promise<void>;
|
|
36
|
+
/** Get current version for a tag */
|
|
37
|
+
getTagVersion(tag: string): Promise<number>;
|
|
38
|
+
/** Bump tag version — orphans all cached queries tagged with this tag */
|
|
39
|
+
bumpTagVersion(tag: string): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/cache/queryCachePlugin.d.ts
|
|
43
|
+
interface QueryCachePluginOptions {
|
|
44
|
+
/** CacheStore instance. Default: MemoryCacheStore with default options. */
|
|
45
|
+
store?: CacheStore;
|
|
46
|
+
/** Global defaults for staleTime/gcTime (seconds) */
|
|
47
|
+
defaults?: {
|
|
48
|
+
staleTime?: number;
|
|
49
|
+
gcTime?: number;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
interface QueryCacheDefaults {
|
|
53
|
+
staleTime: number;
|
|
54
|
+
gcTime: number;
|
|
55
|
+
}
|
|
56
|
+
/** Cross-resource invalidation rules collected from resource configs */
|
|
57
|
+
interface CrossResourceRule {
|
|
58
|
+
pattern: string;
|
|
59
|
+
tags: string[];
|
|
60
|
+
}
|
|
61
|
+
declare module 'fastify' {
|
|
62
|
+
interface FastifyInstance {
|
|
63
|
+
queryCache: QueryCache;
|
|
64
|
+
queryCacheConfig: QueryCacheDefaults;
|
|
65
|
+
/** Register cross-resource invalidation rules (called by defineResource) */
|
|
66
|
+
registerCacheInvalidationRule?(rule: CrossResourceRule): void;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
declare const queryCachePlugin: FastifyPluginAsync<QueryCachePluginOptions>;
|
|
70
|
+
//#endregion
|
|
71
|
+
export { CacheEnvelope as a, QueryCache as c, queryCachePlugin as i, QueryCacheConfig as l, QueryCacheDefaults as n, CacheResult as o, QueryCachePluginOptions as r, CacheStatus as s, CrossResourceRule as t };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-CSNjltAc.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/idempotency/stores/redis.d.ts
|
|
4
|
+
interface RedisClient {
|
|
5
|
+
get(key: string): Promise<string | null>;
|
|
6
|
+
set(key: string, value: string, options?: {
|
|
7
|
+
EX?: number;
|
|
8
|
+
NX?: boolean;
|
|
9
|
+
}): Promise<string | null>;
|
|
10
|
+
del(key: string | string[]): Promise<number>;
|
|
11
|
+
exists(key: string | string[]): Promise<number>;
|
|
12
|
+
/** SCAN command — compatible with node-redis and ioredis varargs signatures. */
|
|
13
|
+
scan?(cursor: string | number, ...args: (string | number)[]): Promise<[string | number, string[]]>;
|
|
14
|
+
quit?(): Promise<string>;
|
|
15
|
+
disconnect?(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
interface RedisIdempotencyStoreOptions {
|
|
18
|
+
/** Redis client instance */
|
|
19
|
+
client: RedisClient;
|
|
20
|
+
/** Key prefix (default: 'idem:') */
|
|
21
|
+
prefix?: string;
|
|
22
|
+
/** Lock key prefix (default: 'idem:lock:') */
|
|
23
|
+
lockPrefix?: string;
|
|
24
|
+
/** Default TTL in ms (default: 86400000 = 24 hours) */
|
|
25
|
+
ttlMs?: number;
|
|
26
|
+
}
|
|
27
|
+
declare class RedisIdempotencyStore implements IdempotencyStore {
|
|
28
|
+
readonly name = "redis";
|
|
29
|
+
private client;
|
|
30
|
+
private prefix;
|
|
31
|
+
private lockPrefix;
|
|
32
|
+
private ttlMs;
|
|
33
|
+
constructor(options: RedisIdempotencyStoreOptions);
|
|
34
|
+
private resultKey;
|
|
35
|
+
private lockKey;
|
|
36
|
+
get(key: string): Promise<IdempotencyResult | undefined>;
|
|
37
|
+
set(key: string, result: Omit<IdempotencyResult, 'key'>): Promise<void>;
|
|
38
|
+
tryLock(key: string, requestId: string, ttlMs: number): Promise<boolean>;
|
|
39
|
+
unlock(key: string, requestId: string): Promise<void>;
|
|
40
|
+
isLocked(key: string): Promise<boolean>;
|
|
41
|
+
delete(key: string): Promise<void>;
|
|
42
|
+
deleteByPrefix(prefix: string): Promise<number>;
|
|
43
|
+
findByPrefix(prefix: string): Promise<IdempotencyResult | undefined>;
|
|
44
|
+
/** Scan Redis keys matching a prefix pattern. Falls back to empty if SCAN unavailable. */
|
|
45
|
+
private scanByPrefix;
|
|
46
|
+
close(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { RedisIdempotencyStore as n, RedisIdempotencyStoreOptions as r, RedisClient as t };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { i as EventTransport, n as EventHandler, r as EventLogger, t as DomainEvent } from "./EventTransport-BkUDYZEb.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/events/transports/redis-stream.d.ts
|
|
4
|
+
interface RedisStreamLike {
|
|
5
|
+
xadd(key: string, id: string, ...fieldValues: string[]): Promise<string | null>;
|
|
6
|
+
xreadgroup(command: 'GROUP', group: string, consumer: string, ...args: (string | number)[]): Promise<Array<[string, Array<[string, string[]]>]> | null>;
|
|
7
|
+
xack(key: string, group: string, ...ids: string[]): Promise<number>;
|
|
8
|
+
xgroup(command: string, key: string, group: string, ...args: string[]): Promise<unknown>;
|
|
9
|
+
xpending(key: string, group: string, ...args: (string | number)[]): Promise<Array<[string, string, number, number]>>;
|
|
10
|
+
xclaim(key: string, group: string, consumer: string, minIdleTime: number, ...ids: string[]): Promise<Array<[string, string[]]>>;
|
|
11
|
+
xlen(key: string): Promise<number>;
|
|
12
|
+
quit(): Promise<unknown>;
|
|
13
|
+
}
|
|
14
|
+
interface RedisStreamTransportOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Redis stream key name.
|
|
17
|
+
* @default 'arc:events'
|
|
18
|
+
*/
|
|
19
|
+
stream?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Consumer group name. Each group receives every event independently.
|
|
22
|
+
* Multiple instances of the same service should share a group name.
|
|
23
|
+
* @default 'default'
|
|
24
|
+
*/
|
|
25
|
+
group?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Consumer name within the group. Must be unique per instance.
|
|
28
|
+
* @default 'consumer-<random>'
|
|
29
|
+
*/
|
|
30
|
+
consumer?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Block time in ms when waiting for new events.
|
|
33
|
+
* @default 5000
|
|
34
|
+
*/
|
|
35
|
+
blockTimeMs?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Max events to read per batch.
|
|
38
|
+
* @default 10
|
|
39
|
+
*/
|
|
40
|
+
batchSize?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Max delivery attempts before moving to dead letter stream.
|
|
43
|
+
* @default 5
|
|
44
|
+
*/
|
|
45
|
+
maxRetries?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Idle time in ms before pending entries are claimed by this consumer.
|
|
48
|
+
* Handles crash recovery — if a consumer dies mid-processing, another
|
|
49
|
+
* consumer will claim its pending entries after this timeout.
|
|
50
|
+
* @default 30000
|
|
51
|
+
*/
|
|
52
|
+
claimTimeoutMs?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Dead letter stream name. Failed events are moved here after maxRetries.
|
|
55
|
+
* Set to `false` to disable DLQ (failed events are acked and dropped).
|
|
56
|
+
* @default 'arc:events:dlq'
|
|
57
|
+
*/
|
|
58
|
+
deadLetterStream?: string | false;
|
|
59
|
+
/**
|
|
60
|
+
* Max stream length (approximate). Uses XADD MAXLEN ~ to trim old entries.
|
|
61
|
+
* Set to 0 to disable trimming.
|
|
62
|
+
* @default 10000
|
|
63
|
+
*/
|
|
64
|
+
maxLen?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Logger for error messages (default: console).
|
|
67
|
+
* Pass `fastify.log` to integrate with your application logger.
|
|
68
|
+
*/
|
|
69
|
+
logger?: EventLogger;
|
|
70
|
+
}
|
|
71
|
+
declare class RedisStreamTransport implements EventTransport {
|
|
72
|
+
readonly name = "redis-stream";
|
|
73
|
+
private redis;
|
|
74
|
+
private stream;
|
|
75
|
+
private group;
|
|
76
|
+
private consumer;
|
|
77
|
+
private blockTimeMs;
|
|
78
|
+
private batchSize;
|
|
79
|
+
private maxRetries;
|
|
80
|
+
private claimTimeoutMs;
|
|
81
|
+
private deadLetterStream;
|
|
82
|
+
private maxLen;
|
|
83
|
+
private logger;
|
|
84
|
+
private handlers;
|
|
85
|
+
private running;
|
|
86
|
+
private pollPromise;
|
|
87
|
+
private groupCreated;
|
|
88
|
+
constructor(redis: RedisStreamLike, options?: RedisStreamTransportOptions);
|
|
89
|
+
publish(event: DomainEvent): Promise<void>;
|
|
90
|
+
subscribe(pattern: string, handler: EventHandler): Promise<() => void>;
|
|
91
|
+
close(): Promise<void>;
|
|
92
|
+
private ensureGroup;
|
|
93
|
+
private pollLoop;
|
|
94
|
+
private readNewMessages;
|
|
95
|
+
private claimPending;
|
|
96
|
+
private processEntry;
|
|
97
|
+
private getMatchingHandlers;
|
|
98
|
+
private matchesPattern;
|
|
99
|
+
private moveToDlq;
|
|
100
|
+
private sleep;
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
export { RedisStreamTransport as n, RedisStreamTransportOptions as r, RedisStreamLike as t };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import "../elevation-DGo5shaX.mjs";
|
|
2
|
+
import { C as RegisterOptions, w as ResourceRegistry } from "../interface-e9XfSsUV.mjs";
|
|
3
|
+
import "../types-RLkFVgaw.mjs";
|
|
4
|
+
import { IntrospectionPluginOptions } from "../types/index.mjs";
|
|
5
|
+
import { FastifyPluginAsync } from "fastify";
|
|
6
|
+
|
|
7
|
+
//#region src/registry/introspectionPlugin.d.ts
|
|
8
|
+
declare const introspectionPlugin: FastifyPluginAsync<IntrospectionPluginOptions>;
|
|
9
|
+
declare const _default: FastifyPluginAsync<IntrospectionPluginOptions>;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { type IntrospectionPluginOptions, type RegisterOptions, ResourceRegistry, _default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { t as ResourceRegistry } from "../ResourceRegistry-7Ic20ZMw.mjs";
|
|
2
|
+
import { n as introspectionPlugin_default, t as introspectionPlugin } from "../introspectionPlugin-B3JkrjwU.mjs";
|
|
3
|
+
|
|
4
|
+
export { ResourceRegistry, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
|
|
3
|
+
//#region src/context/requestContext.ts
|
|
4
|
+
/**
|
|
5
|
+
* Request Context via AsyncLocalStorage
|
|
6
|
+
*
|
|
7
|
+
* Provides request-scoped context accessible anywhere in the call stack
|
|
8
|
+
* without threading parameters through every function call.
|
|
9
|
+
*
|
|
10
|
+
* Uses Node.js native AsyncLocalStorage — zero-cost per request, no allocation
|
|
11
|
+
* beyond the store object, and fully supported since Node 16.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { requestContext } from '@classytic/arc';
|
|
16
|
+
*
|
|
17
|
+
* // Anywhere in the call stack — no parameter passing needed
|
|
18
|
+
* async function auditAction(action: string) {
|
|
19
|
+
* const ctx = requestContext.get();
|
|
20
|
+
* await auditLog.write({
|
|
21
|
+
* action,
|
|
22
|
+
* userId: ctx?.user?.id,
|
|
23
|
+
* orgId: ctx?.organizationId,
|
|
24
|
+
* requestId: ctx?.requestId,
|
|
25
|
+
* });
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* // Type-safe access to specific fields
|
|
29
|
+
* const userId = requestContext.get()?.user?.id;
|
|
30
|
+
* const orgId = requestContext.get()?.organizationId;
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
const storage = new AsyncLocalStorage();
|
|
34
|
+
/**
|
|
35
|
+
* Request context API.
|
|
36
|
+
*
|
|
37
|
+
* - `get()` — returns current store or undefined if outside request scope
|
|
38
|
+
* - `run(store, fn)` — run a function with a specific store (used by Arc internals)
|
|
39
|
+
* - `getStore()` — alias for get() (matches Node.js API naming)
|
|
40
|
+
*/
|
|
41
|
+
const requestContext = {
|
|
42
|
+
get() {
|
|
43
|
+
return storage.getStore();
|
|
44
|
+
},
|
|
45
|
+
getStore() {
|
|
46
|
+
return storage.getStore();
|
|
47
|
+
},
|
|
48
|
+
run(store, fn) {
|
|
49
|
+
return storage.run(store, fn);
|
|
50
|
+
},
|
|
51
|
+
storage
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { requestContext as t };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
//#region src/utils/schemaConverter.ts
|
|
2
|
+
let _toJSONSchema = null;
|
|
3
|
+
import("zod").then(({ z }) => {
|
|
4
|
+
if (typeof z?.toJSONSchema === "function") _toJSONSchema = (schema, opts) => z.toJSONSchema(schema, opts);
|
|
5
|
+
}).catch(() => {});
|
|
6
|
+
/**
|
|
7
|
+
* Check if an object is already a plain JSON Schema.
|
|
8
|
+
* Returns true if it has JSON Schema markers (`type`, `properties`, `$ref`,
|
|
9
|
+
* `allOf`, `anyOf`, `oneOf`, `items`, `enum`) and does NOT have Zod markers.
|
|
10
|
+
*/
|
|
11
|
+
function isJsonSchema(input) {
|
|
12
|
+
if (input === null || typeof input !== "object") return false;
|
|
13
|
+
const obj = input;
|
|
14
|
+
if ("_def" in obj || "_zod" in obj) return false;
|
|
15
|
+
return "type" in obj || "properties" in obj || "$ref" in obj || "allOf" in obj || "anyOf" in obj || "oneOf" in obj || "items" in obj || "enum" in obj;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if an object is a Zod schema (has `_zod` marker from Zod v4).
|
|
19
|
+
*/
|
|
20
|
+
function isZodSchema(input) {
|
|
21
|
+
return input !== null && typeof input === "object" && "_zod" in input;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convert any schema input to JSON Schema.
|
|
25
|
+
*
|
|
26
|
+
* Detection order:
|
|
27
|
+
* 1. `null`/`undefined` → `undefined`
|
|
28
|
+
* 2. Already JSON Schema → pass through as-is (zero overhead)
|
|
29
|
+
* 3. Zod v4 schema → `z.toJSONSchema(schema, { target: 'openapi-3.0' })`
|
|
30
|
+
* 4. Unrecognized object → return as-is (treat as opaque schema)
|
|
31
|
+
*/
|
|
32
|
+
function toJsonSchema(input) {
|
|
33
|
+
if (input == null) return void 0;
|
|
34
|
+
if (typeof input !== "object") return void 0;
|
|
35
|
+
if (isJsonSchema(input)) return input;
|
|
36
|
+
if (isZodSchema(input)) {
|
|
37
|
+
if (!_toJSONSchema) {
|
|
38
|
+
console.warn("[Arc] Zod schema detected but zod is not installed. Install zod v4: npm install zod");
|
|
39
|
+
return input;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
return _toJSONSchema(input, { target: "openapi-3.0" });
|
|
43
|
+
} catch {
|
|
44
|
+
return { type: "object" };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return input;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Convert all schema fields in an OpenApiSchemas object.
|
|
51
|
+
* JSON Schema values pass through unchanged. Only Zod schemas are converted.
|
|
52
|
+
*/
|
|
53
|
+
function convertOpenApiSchemas(schemas) {
|
|
54
|
+
const result = {};
|
|
55
|
+
const schemaFields = [
|
|
56
|
+
"entity",
|
|
57
|
+
"createBody",
|
|
58
|
+
"updateBody",
|
|
59
|
+
"params",
|
|
60
|
+
"listQuery",
|
|
61
|
+
"response"
|
|
62
|
+
];
|
|
63
|
+
for (const field of schemaFields) {
|
|
64
|
+
const value = schemas[field];
|
|
65
|
+
if (value !== void 0) result[field] = toJsonSchema(value) ?? value;
|
|
66
|
+
}
|
|
67
|
+
for (const [key, value] of Object.entries(schemas)) if (!schemaFields.includes(key)) result[key] = value;
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Convert schema values in a Fastify route schema record.
|
|
72
|
+
*
|
|
73
|
+
* Handles `body`, `querystring`, `params`, `headers` (top-level conversion)
|
|
74
|
+
* and `response` (iterates by status code — each value converted individually).
|
|
75
|
+
*
|
|
76
|
+
* JSON Schema values pass through unchanged. Only Zod schemas are converted.
|
|
77
|
+
*
|
|
78
|
+
* Used for both additionalRoutes and customSchemas (CRUD overrides).
|
|
79
|
+
*/
|
|
80
|
+
function convertRouteSchema(schema) {
|
|
81
|
+
const result = { ...schema };
|
|
82
|
+
for (const field of [
|
|
83
|
+
"body",
|
|
84
|
+
"querystring",
|
|
85
|
+
"params",
|
|
86
|
+
"headers"
|
|
87
|
+
]) if (result[field] !== void 0) result[field] = toJsonSchema(result[field]) ?? result[field];
|
|
88
|
+
if (result.response !== void 0 && typeof result.response === "object" && result.response !== null) {
|
|
89
|
+
const responseObj = result.response;
|
|
90
|
+
const convertedResponse = {};
|
|
91
|
+
for (const [statusCode, responseSchema] of Object.entries(responseObj)) convertedResponse[statusCode] = toJsonSchema(responseSchema) ?? responseSchema;
|
|
92
|
+
result.response = convertedResponse;
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
98
|
+
export { toJsonSchema as a, isZodSchema as i, convertRouteSchema as n, isJsonSchema as r, convertOpenApiSchemas as t };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as _sinclair_typebox0 from "@sinclair/typebox";
|
|
2
|
+
import { Static, TObject, TSchema, TSchema as TSchema$1, Type } from "@sinclair/typebox";
|
|
3
|
+
import { FastifyPluginAsyncTypebox, FastifyPluginCallbackTypebox, TypeBoxTypeProvider, TypeBoxValidatorCompiler } from "@fastify/type-provider-typebox";
|
|
4
|
+
|
|
5
|
+
//#region src/schemas/index.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Paginated list response — matches Arc's runtime format:
|
|
8
|
+
* `{ success, docs: [...], page, limit, total, pages, hasNext, hasPrev }`
|
|
9
|
+
*/
|
|
10
|
+
declare function ArcListResponse<T extends TSchema$1>(itemSchema: T): _sinclair_typebox0.TObject<{
|
|
11
|
+
success: _sinclair_typebox0.TBoolean;
|
|
12
|
+
docs: _sinclair_typebox0.TArray<T>;
|
|
13
|
+
page: _sinclair_typebox0.TInteger;
|
|
14
|
+
limit: _sinclair_typebox0.TInteger;
|
|
15
|
+
total: _sinclair_typebox0.TInteger;
|
|
16
|
+
pages: _sinclair_typebox0.TInteger;
|
|
17
|
+
hasNext: _sinclair_typebox0.TBoolean;
|
|
18
|
+
hasPrev: _sinclair_typebox0.TBoolean;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Single item response — `{ success, data: {...} }`
|
|
22
|
+
*/
|
|
23
|
+
declare function ArcItemResponse<T extends TSchema$1>(itemSchema: T): _sinclair_typebox0.TObject<{
|
|
24
|
+
success: _sinclair_typebox0.TBoolean;
|
|
25
|
+
data: T;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* Mutation (create/update) response — `{ success, data: {...}, message? }`
|
|
29
|
+
*/
|
|
30
|
+
declare function ArcMutationResponse<T extends TSchema$1>(itemSchema: T): _sinclair_typebox0.TObject<{
|
|
31
|
+
success: _sinclair_typebox0.TBoolean;
|
|
32
|
+
data: T;
|
|
33
|
+
message: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Delete response — `{ success, message }`
|
|
37
|
+
*/
|
|
38
|
+
declare function ArcDeleteResponse(): _sinclair_typebox0.TObject<{
|
|
39
|
+
success: _sinclair_typebox0.TBoolean;
|
|
40
|
+
message: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* Error response schema
|
|
44
|
+
*/
|
|
45
|
+
declare function ArcErrorResponse(): _sinclair_typebox0.TObject<{
|
|
46
|
+
success: _sinclair_typebox0.TLiteral<false>;
|
|
47
|
+
error: _sinclair_typebox0.TString;
|
|
48
|
+
code: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
|
|
49
|
+
message: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Standard pagination + sorting + filtering query parameters.
|
|
53
|
+
* Matches Arc's list endpoint conventions.
|
|
54
|
+
*/
|
|
55
|
+
declare function ArcPaginationQuery(): _sinclair_typebox0.TObject<{
|
|
56
|
+
page: _sinclair_typebox0.TOptional<_sinclair_typebox0.TInteger>;
|
|
57
|
+
limit: _sinclair_typebox0.TOptional<_sinclair_typebox0.TInteger>;
|
|
58
|
+
sort: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
|
|
59
|
+
select: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
|
|
60
|
+
populate: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>;
|
|
61
|
+
}>;
|
|
62
|
+
//#endregion
|
|
63
|
+
export { ArcDeleteResponse, ArcErrorResponse, ArcItemResponse, ArcListResponse, ArcMutationResponse, ArcPaginationQuery, type FastifyPluginAsyncTypebox, type FastifyPluginCallbackTypebox, type Static, type TObject, type TSchema, Type, type TypeBoxTypeProvider, TypeBoxValidatorCompiler };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Type, Type as Type$1 } from "@sinclair/typebox";
|
|
2
|
+
import { TypeBoxValidatorCompiler } from "@fastify/type-provider-typebox";
|
|
3
|
+
|
|
4
|
+
//#region src/schemas/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* Paginated list response — matches Arc's runtime format:
|
|
7
|
+
* `{ success, docs: [...], page, limit, total, pages, hasNext, hasPrev }`
|
|
8
|
+
*/
|
|
9
|
+
function ArcListResponse(itemSchema) {
|
|
10
|
+
return Type$1.Object({
|
|
11
|
+
success: Type$1.Boolean(),
|
|
12
|
+
docs: Type$1.Array(itemSchema),
|
|
13
|
+
page: Type$1.Integer(),
|
|
14
|
+
limit: Type$1.Integer(),
|
|
15
|
+
total: Type$1.Integer(),
|
|
16
|
+
pages: Type$1.Integer(),
|
|
17
|
+
hasNext: Type$1.Boolean(),
|
|
18
|
+
hasPrev: Type$1.Boolean()
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Single item response — `{ success, data: {...} }`
|
|
23
|
+
*/
|
|
24
|
+
function ArcItemResponse(itemSchema) {
|
|
25
|
+
return Type$1.Object({
|
|
26
|
+
success: Type$1.Boolean(),
|
|
27
|
+
data: itemSchema
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Mutation (create/update) response — `{ success, data: {...}, message? }`
|
|
32
|
+
*/
|
|
33
|
+
function ArcMutationResponse(itemSchema) {
|
|
34
|
+
return Type$1.Object({
|
|
35
|
+
success: Type$1.Boolean(),
|
|
36
|
+
data: itemSchema,
|
|
37
|
+
message: Type$1.Optional(Type$1.String())
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Delete response — `{ success, message }`
|
|
42
|
+
*/
|
|
43
|
+
function ArcDeleteResponse() {
|
|
44
|
+
return Type$1.Object({
|
|
45
|
+
success: Type$1.Boolean(),
|
|
46
|
+
message: Type$1.Optional(Type$1.String())
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Error response schema
|
|
51
|
+
*/
|
|
52
|
+
function ArcErrorResponse() {
|
|
53
|
+
return Type$1.Object({
|
|
54
|
+
success: Type$1.Literal(false),
|
|
55
|
+
error: Type$1.String(),
|
|
56
|
+
code: Type$1.Optional(Type$1.String()),
|
|
57
|
+
message: Type$1.Optional(Type$1.String())
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Standard pagination + sorting + filtering query parameters.
|
|
62
|
+
* Matches Arc's list endpoint conventions.
|
|
63
|
+
*/
|
|
64
|
+
function ArcPaginationQuery() {
|
|
65
|
+
return Type$1.Object({
|
|
66
|
+
page: Type$1.Optional(Type$1.Integer({
|
|
67
|
+
minimum: 1,
|
|
68
|
+
default: 1
|
|
69
|
+
})),
|
|
70
|
+
limit: Type$1.Optional(Type$1.Integer({
|
|
71
|
+
minimum: 1,
|
|
72
|
+
maximum: 100,
|
|
73
|
+
default: 20
|
|
74
|
+
})),
|
|
75
|
+
sort: Type$1.Optional(Type$1.String()),
|
|
76
|
+
select: Type$1.Optional(Type$1.String()),
|
|
77
|
+
populate: Type$1.Optional(Type$1.String())
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
export { ArcDeleteResponse, ArcErrorResponse, ArcItemResponse, ArcListResponse, ArcMutationResponse, ArcPaginationQuery, Type, TypeBoxValidatorCompiler };
|