@classytic/arc 2.8.4 → 2.9.1
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 +116 -5
- package/dist/{BaseController-DAGGc5Xn.mjs → BaseController-Vu2yc56T.mjs} +188 -102
- package/dist/EventTransport-CqZ8FyM_.d.mts +293 -0
- package/dist/adapters/index.d.mts +2 -2
- package/dist/audit/index.d.mts +100 -11
- package/dist/audit/index.mjs +71 -18
- package/dist/auth/index.d.mts +15 -7
- package/dist/auth/index.mjs +13 -6
- package/dist/{betterAuthOpenApi-C5lDyRH2.mjs → betterAuthOpenApi--rdY15Ld.mjs} +1 -1
- package/dist/cache/index.d.mts +71 -1
- package/dist/cache/index.mjs +96 -3
- package/dist/cli/commands/docs.mjs +1 -1
- package/dist/cli/commands/generate.mjs +1 -1
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +4 -5
- package/dist/{core-DKSwNSXf.mjs → core-DNncu0xF.mjs} +1 -1
- package/dist/{createActionRouter-Df1BuawX.mjs → createActionRouter-DH1YFL9m.mjs} +3 -3
- package/dist/{createApp-BOYjBgdI.mjs → createApp-CBJUJKGP.mjs} +6 -5
- package/dist/{defineResource-Bb_Bdhtw.mjs → defineResource-C__jkwvs.mjs} +22 -57
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +1 -1
- package/dist/dynamic/index.d.mts +2 -2
- package/dist/dynamic/index.mjs +3 -3
- package/dist/{elevation-BBGFjzIP.mjs → elevation-DxQ6ACbt.mjs} +20 -6
- package/dist/{errorHandler-mzqk4cGl.mjs → errorHandler-CZDW4EXS.mjs} +59 -7
- package/dist/{errorHandler-CdZDavNH.d.mts → errorHandler-DixGcttC.d.mts} +37 -2
- package/dist/{eventPlugin-CVxlE6De.d.mts → eventPlugin-BxvaCIZF.d.mts} +14 -2
- package/dist/{eventPlugin-D91S2YF4.mjs → eventPlugin-Dl7MoVWH.mjs} +83 -5
- package/dist/events/index.d.mts +147 -36
- package/dist/events/index.mjs +338 -101
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +1 -1
- package/dist/{fields-DC4So2M2.d.mts → fields-BC7zcmI9.d.mts} +15 -3
- package/dist/{fields-ipsbIRPK.mjs → fields-CU6FlaDV.mjs} +18 -5
- package/dist/filesUpload-q8oHt--L.mjs +377 -0
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +28 -4
- package/dist/idempotency/index.mjs +111 -2
- package/dist/idempotency/redis.d.mts +2 -2
- package/dist/idempotency/redis.mjs +134 -13
- package/dist/{index-CSkeivBx.d.mts → index-C-xjcA6F.d.mts} +2 -2
- package/dist/{index-CpTSDqmD.d.mts → index-Cibkchnx.d.mts} +5 -136
- package/dist/{index-BgmMdpm8.d.mts → index-CtGKT0lf.d.mts} +1 -1
- package/dist/index.d.mts +8 -8
- package/dist/index.mjs +8 -8
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/jobs.d.mts +25 -3
- package/dist/integrations/jobs.mjs +63 -4
- package/dist/integrations/mcp/index.d.mts +26 -8
- package/dist/integrations/mcp/index.mjs +96 -17
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/webhooks.d.mts +5 -0
- package/dist/integrations/webhooks.mjs +6 -0
- package/dist/{interface-BVuMfeVv.d.mts → interface-YrWsmKqE.d.mts} +324 -194
- package/dist/{openapi-CYCuekCn.mjs → openapi-CXuTG1M9.mjs} +3 -3
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +3 -3
- package/dist/permissions/index.mjs +3 -3
- package/dist/{permissions-CH4cNwJi.mjs → permissions-oNZawnkR.mjs} +1 -1
- package/dist/plugins/index.d.mts +6 -6
- package/dist/plugins/index.mjs +4 -4
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/policies/index.d.mts +26 -33
- package/dist/presets/filesUpload.d.mts +71 -0
- package/dist/presets/filesUpload.mjs +2 -0
- package/dist/presets/index.d.mts +4 -2
- package/dist/presets/index.mjs +4 -2
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +1 -1
- package/dist/presets/search.d.mts +91 -0
- package/dist/presets/search.mjs +150 -0
- package/dist/{presets-C2xgzW6x.mjs → presets-hM4WhNWY.mjs} +1 -1
- package/dist/{queryCachePlugin-D0iIVhW_.mjs → queryCachePlugin-DbUVroUG.mjs} +2 -2
- package/dist/redis-MXLp1oOf.d.mts +115 -0
- package/dist/{redis-stream-D54N5oXs.d.mts → redis-stream-Bz-4q96t.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/{resourceToTools-O_HwWXFa.mjs → resourceToTools-C3cWymnW.mjs} +65 -48
- package/dist/rpc/index.mjs +1 -1
- package/dist/{schemaConverter-OxfCshus.mjs → schemaConverter-BxFDdtXu.mjs} +25 -9
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +1 -1
- package/dist/storage-BwGQXUpd.d.mts +146 -0
- package/dist/store-helpers-DFiZl5TL.mjs +57 -0
- package/dist/testing/index.d.mts +7 -15
- package/dist/testing/index.mjs +23 -76
- package/dist/testing/storageContract.d.mts +26 -0
- package/dist/testing/storageContract.mjs +216 -0
- package/dist/types/index.d.mts +5 -5
- package/dist/types/storage.d.mts +2 -0
- package/dist/types/storage.mjs +1 -0
- package/dist/{types-CcG4avic.d.mts → types-CoSzA-s-.d.mts} +1 -1
- package/dist/{types-Bg2X42_m.d.mts → types-CunEX4UX.d.mts} +7 -5
- package/dist/{types-CVC4HOKi.d.mts → types-DZi1aYhm.d.mts} +1 -1
- package/dist/utils/index.d.mts +26 -8
- package/dist/utils/index.mjs +6 -6
- package/dist/{utils-yYT3HDXt.mjs → utils-B7FuRr9w.mjs} +1 -1
- package/package.json +23 -11
- package/skills/arc/SKILL.md +92 -14
- package/skills/arc/references/auth.md +94 -0
- package/skills/arc/references/events.md +229 -12
- package/skills/arc/references/mcp.md +4 -17
- package/skills/arc/references/multi-tenancy.md +43 -0
- package/skills/arc/references/production.md +34 -19
- package/dist/EventTransport-CinyO7zQ.d.mts +0 -135
- package/dist/audit/mongodb.d.mts +0 -2
- package/dist/audit/mongodb.mjs +0 -2
- package/dist/idempotency/mongodb.d.mts +0 -2
- package/dist/idempotency/mongodb.mjs +0 -123
- package/dist/mongodb-B5O6xaW1.mjs +0 -90
- package/dist/mongodb-B8U2xaLj.d.mts +0 -127
- package/dist/mongodb-X7LbEjTN.d.mts +0 -80
- package/dist/redis-z3sFr1UP.d.mts +0 -49
- /package/dist/{applyPermissionResult-D6GPMsvh.mjs → applyPermissionResult-bqGpo9ML.mjs} +0 -0
- /package/dist/{circuitBreaker-cmi5XDv5.mjs → circuitBreaker-l18oRgL5.mjs} +0 -0
- /package/dist/{elevation-s5ykdNHr.d.mts → elevation-B6S5csVA.d.mts} +0 -0
- /package/dist/{errors-Bmn3eZT6.d.mts → errors-BI8kEKsO.d.mts} +0 -0
- /package/dist/{errors-BF2bIOIS.mjs → errors-CqWnSqM-.mjs} +0 -0
- /package/dist/{memory-Cp7_cAko.mjs → memory-BFAYkf8H.mjs} +0 -0
- /package/dist/{pluralize-A0tWEl1K.mjs → pluralize-CWP6MB39.mjs} +0 -0
- /package/dist/{queryParser-CgCtsjti.mjs → queryParser-Cs-6SHQK.mjs} +0 -0
- /package/dist/{requestContext-DYvHl113.mjs → requestContext-DYtmNpm5.mjs} +0 -0
- /package/dist/{tracing-DxjKk7eW.d.mts → tracing-xqXzWeaf.d.mts} +0 -0
- /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-Cj5Rgvlg.mjs} +0 -0
- /package/dist/{types-C72d3NDn.d.mts → types-BD85MlEK.d.mts} +0 -0
package/dist/cache/index.d.mts
CHANGED
|
@@ -141,5 +141,75 @@ declare class RedisCacheStore<TValue = unknown> implements CacheStore<TValue> {
|
|
|
141
141
|
private scanAndDelete;
|
|
142
142
|
private withPrefix;
|
|
143
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Minimal ioredis shape we depend on. We don't import ioredis itself so the
|
|
146
|
+
* cache subpath stays peer-dep-free.
|
|
147
|
+
*/
|
|
148
|
+
interface IoredisLike {
|
|
149
|
+
get(key: string): Promise<string | null>;
|
|
150
|
+
set(...args: unknown[]): Promise<string | null>;
|
|
151
|
+
del(...keys: string[]): Promise<number>;
|
|
152
|
+
scan(cursor: string | number, ...args: (string | number)[]): Promise<[string, string[]]>;
|
|
153
|
+
pipeline?(): {
|
|
154
|
+
del(key: string): unknown;
|
|
155
|
+
exec(): Promise<unknown>;
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Wrap an ioredis instance as a `RedisCacheClient`.
|
|
160
|
+
*
|
|
161
|
+
* Why: arc's `RedisCacheClient` uses node-redis-v4 object-options style
|
|
162
|
+
* (`set(key, val, { PX })`), but ioredis expects positional flags
|
|
163
|
+
* (`set(key, val, 'PX', ms)`). Without this adapter every ioredis user
|
|
164
|
+
* reinvents the bridge.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* import Redis from 'ioredis';
|
|
169
|
+
* import { RedisCacheStore, ioredisAsCacheClient } from '@classytic/arc/cache';
|
|
170
|
+
*
|
|
171
|
+
* const redis = new Redis(process.env.REDIS_URL);
|
|
172
|
+
* const store = new RedisCacheStore({
|
|
173
|
+
* client: ioredisAsCacheClient(redis),
|
|
174
|
+
* prefix: 'arc:cache:',
|
|
175
|
+
* });
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
declare function ioredisAsCacheClient(client: IoredisLike): RedisCacheClient;
|
|
179
|
+
/**
|
|
180
|
+
* Minimal `@upstash/redis` REST SDK shape we depend on.
|
|
181
|
+
*
|
|
182
|
+
* `@upstash/redis` is HTTP-based and works on edge runtimes (Cloudflare
|
|
183
|
+
* Workers, Vercel Edge, Deno Deploy) where TCP connections — and thus
|
|
184
|
+
* ioredis — are unavailable.
|
|
185
|
+
*/
|
|
186
|
+
interface UpstashRedisLike {
|
|
187
|
+
get(key: string): Promise<string | null | unknown>;
|
|
188
|
+
set(key: string, value: unknown, opts?: Record<string, unknown>): Promise<unknown>;
|
|
189
|
+
del(...keys: string[]): Promise<number>;
|
|
190
|
+
scan(cursor: number | string, opts?: {
|
|
191
|
+
match?: string;
|
|
192
|
+
count?: number;
|
|
193
|
+
}): Promise<[number, string[]] | [string, string[]]>;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Wrap an `@upstash/redis` REST client as a `RedisCacheClient`.
|
|
197
|
+
*
|
|
198
|
+
* Enables running arc's cache layer on edge runtimes without ioredis.
|
|
199
|
+
* Requires `@upstash/redis` as an optional peer dependency.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* import { Redis } from '@upstash/redis';
|
|
204
|
+
* import { RedisCacheStore, upstashAsCacheClient } from '@classytic/arc/cache';
|
|
205
|
+
*
|
|
206
|
+
* const redis = Redis.fromEnv();
|
|
207
|
+
* const store = new RedisCacheStore({
|
|
208
|
+
* client: upstashAsCacheClient(redis),
|
|
209
|
+
* prefix: 'arc:cache:',
|
|
210
|
+
* });
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
declare function upstashAsCacheClient(client: UpstashRedisLike): RedisCacheClient;
|
|
144
214
|
//#endregion
|
|
145
|
-
export { type CacheEnvelope, type CacheLogger, type CacheResult, type CacheSetOptions, type CacheStats, type CacheStatus, type CacheStore, type CrossResourceRule, MemoryCacheStore, type MemoryCacheStoreOptions, QueryCache, type QueryCacheConfig, type QueryCacheDefaults, type QueryCachePluginOptions, type RedisCacheClient, RedisCacheStore, type RedisCacheStoreOptions, type RedisPipeline, buildQueryKey, hashParams, queryCachePlugin, tagVersionKey, versionKey };
|
|
215
|
+
export { type CacheEnvelope, type CacheLogger, type CacheResult, type CacheSetOptions, type CacheStats, type CacheStatus, type CacheStore, type CrossResourceRule, type IoredisLike, MemoryCacheStore, type MemoryCacheStoreOptions, QueryCache, type QueryCacheConfig, type QueryCacheDefaults, type QueryCachePluginOptions, type RedisCacheClient, RedisCacheStore, type RedisCacheStoreOptions, type RedisPipeline, type UpstashRedisLike, buildQueryKey, hashParams, ioredisAsCacheClient, queryCachePlugin, tagVersionKey, upstashAsCacheClient, versionKey };
|
package/dist/cache/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as versionKey, n as hashParams, r as tagVersionKey, t as buildQueryKey } from "../keys-qcD-TVJl.mjs";
|
|
2
|
-
import { t as MemoryCacheStore } from "../memory-
|
|
3
|
-
import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-
|
|
2
|
+
import { t as MemoryCacheStore } from "../memory-BFAYkf8H.mjs";
|
|
3
|
+
import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-DbUVroUG.mjs";
|
|
4
4
|
//#region src/cache/redis.ts
|
|
5
5
|
/**
|
|
6
6
|
* Redis-backed cache store.
|
|
@@ -85,5 +85,98 @@ var RedisCacheStore = class {
|
|
|
85
85
|
return `${this.prefix}${key}`;
|
|
86
86
|
}
|
|
87
87
|
};
|
|
88
|
+
/**
|
|
89
|
+
* Wrap an ioredis instance as a `RedisCacheClient`.
|
|
90
|
+
*
|
|
91
|
+
* Why: arc's `RedisCacheClient` uses node-redis-v4 object-options style
|
|
92
|
+
* (`set(key, val, { PX })`), but ioredis expects positional flags
|
|
93
|
+
* (`set(key, val, 'PX', ms)`). Without this adapter every ioredis user
|
|
94
|
+
* reinvents the bridge.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* import Redis from 'ioredis';
|
|
99
|
+
* import { RedisCacheStore, ioredisAsCacheClient } from '@classytic/arc/cache';
|
|
100
|
+
*
|
|
101
|
+
* const redis = new Redis(process.env.REDIS_URL);
|
|
102
|
+
* const store = new RedisCacheStore({
|
|
103
|
+
* client: ioredisAsCacheClient(redis),
|
|
104
|
+
* prefix: 'arc:cache:',
|
|
105
|
+
* });
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
function ioredisAsCacheClient(client) {
|
|
109
|
+
return {
|
|
110
|
+
async get(key) {
|
|
111
|
+
return client.get(key);
|
|
112
|
+
},
|
|
113
|
+
async set(key, value, options) {
|
|
114
|
+
if (options?.PX) return client.set(key, value, "PX", options.PX, ...options.NX ? ["NX"] : []);
|
|
115
|
+
if (options?.EX) return client.set(key, value, "EX", options.EX, ...options.NX ? ["NX"] : []);
|
|
116
|
+
if (options?.NX) return client.set(key, value, "NX");
|
|
117
|
+
return client.set(key, value);
|
|
118
|
+
},
|
|
119
|
+
async del(key) {
|
|
120
|
+
if (Array.isArray(key)) return client.del(...key);
|
|
121
|
+
return client.del(key);
|
|
122
|
+
},
|
|
123
|
+
async scan(cursor, ...args) {
|
|
124
|
+
const [next, keys] = await client.scan(cursor, ...args);
|
|
125
|
+
return [next, keys];
|
|
126
|
+
},
|
|
127
|
+
pipeline: client.pipeline ? () => client.pipeline() : void 0
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Wrap an `@upstash/redis` REST client as a `RedisCacheClient`.
|
|
132
|
+
*
|
|
133
|
+
* Enables running arc's cache layer on edge runtimes without ioredis.
|
|
134
|
+
* Requires `@upstash/redis` as an optional peer dependency.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* import { Redis } from '@upstash/redis';
|
|
139
|
+
* import { RedisCacheStore, upstashAsCacheClient } from '@classytic/arc/cache';
|
|
140
|
+
*
|
|
141
|
+
* const redis = Redis.fromEnv();
|
|
142
|
+
* const store = new RedisCacheStore({
|
|
143
|
+
* client: upstashAsCacheClient(redis),
|
|
144
|
+
* prefix: 'arc:cache:',
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
function upstashAsCacheClient(client) {
|
|
149
|
+
return {
|
|
150
|
+
async get(key) {
|
|
151
|
+
const raw = await client.get(key);
|
|
152
|
+
if (raw == null) return null;
|
|
153
|
+
return typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
154
|
+
},
|
|
155
|
+
async set(key, value, options) {
|
|
156
|
+
const opts = {};
|
|
157
|
+
if (options?.PX) opts.px = options.PX;
|
|
158
|
+
if (options?.EX) opts.ex = options.EX;
|
|
159
|
+
if (options?.NX) opts.nx = true;
|
|
160
|
+
if (options?.XX) opts.xx = true;
|
|
161
|
+
const res = await client.set(key, value, opts);
|
|
162
|
+
return res == null ? null : String(res);
|
|
163
|
+
},
|
|
164
|
+
async del(key) {
|
|
165
|
+
if (Array.isArray(key)) return client.del(...key);
|
|
166
|
+
return client.del(key);
|
|
167
|
+
},
|
|
168
|
+
async scan(cursor, ...args) {
|
|
169
|
+
const opts = {};
|
|
170
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
171
|
+
const flag = String(args[i]).toLowerCase();
|
|
172
|
+
const val = args[i + 1];
|
|
173
|
+
if (flag === "match" && typeof val === "string") opts.match = val;
|
|
174
|
+
if (flag === "count") opts.count = Number(val);
|
|
175
|
+
}
|
|
176
|
+
const [next, keys] = await client.scan(cursor, opts);
|
|
177
|
+
return [next, keys];
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
88
181
|
//#endregion
|
|
89
|
-
export { MemoryCacheStore, QueryCache, RedisCacheStore, buildQueryKey, hashParams, queryCachePlugin, tagVersionKey, versionKey };
|
|
182
|
+
export { MemoryCacheStore, QueryCache, RedisCacheStore, buildQueryKey, hashParams, ioredisAsCacheClient, queryCachePlugin, tagVersionKey, upstashAsCacheClient, versionKey };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as ResourceRegistry } from "../../ResourceRegistry-Dq3_zBQP.mjs";
|
|
2
|
-
import { t as buildOpenApiSpec } from "../../openapi-
|
|
2
|
+
import { t as buildOpenApiSpec } from "../../openapi-CXuTG1M9.mjs";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as pluralize } from "../../pluralize-
|
|
1
|
+
import { t as pluralize } from "../../pluralize-CWP6MB39.mjs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
//#region src/cli/commands/generate.ts
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { At as
|
|
2
|
-
import {
|
|
3
|
-
export { AccessControl, AccessControlConfig,
|
|
1
|
+
import { At as BaseControllerOptions, Ft as AccessControl, It as AccessControlConfig, Kt as ResourceDefinition, Mt as QueryResolverConfig, Nt as BodySanitizer, Pt as BodySanitizerConfig, jt as QueryResolver, kt as BaseController, qt as defineResource } from "../interface-YrWsmKqE.mjs";
|
|
2
|
+
import { C as MAX_REGEX_LENGTH, D as RESERVED_QUERY_PARAMS, E as MutationOperation, O as SYSTEM_FIELDS, S as MAX_FILTER_DEPTH, T as MUTATION_OPERATIONS, _ as DEFAULT_UPDATE_METHOD, a as getControllerScope, b as HookOperation, c as createCrudRouter, d as CrudOperation, f as DEFAULT_ID_FIELD, g as DEFAULT_TENANT_FIELD, h as DEFAULT_SORT, i as getControllerContext, l as createPermissionMiddleware, m as DEFAULT_MAX_LIMIT, n as createFastifyHandler, o as sendControllerResponse, p as DEFAULT_LIMIT, r as createRequestContext, s as defineResourceVariants, t as createCrudHandlers, u as CRUD_OPERATIONS, v as HOOK_OPERATIONS, w as MAX_SEARCH_LENGTH, x as HookPhase, y as HOOK_PHASES } from "../index-Cibkchnx.mjs";
|
|
3
|
+
export { AccessControl, AccessControlConfig, BaseController, BaseControllerOptions, BodySanitizer, BodySanitizerConfig, CRUD_OPERATIONS, CrudOperation, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, HookOperation, HookPhase, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
|
package/dist/core/index.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-Cxde4rpC.mjs";
|
|
2
|
-
import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-
|
|
3
|
-
import { n as
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export { AccessControl, BaseController, BodySanitizer, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, buildActionBodySchema, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
|
|
2
|
+
import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-Vu2yc56T.mjs";
|
|
3
|
+
import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-C__jkwvs.mjs";
|
|
4
|
+
import { t as defineResourceVariants } from "../core-DNncu0xF.mjs";
|
|
5
|
+
export { AccessControl, BaseController, BodySanitizer, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as defineResource } from "./defineResource-
|
|
1
|
+
import { n as defineResource } from "./defineResource-C__jkwvs.mjs";
|
|
2
2
|
//#region src/core/defineResourceVariants.ts
|
|
3
3
|
/**
|
|
4
4
|
* Define multiple resources from a shared base config and per-variant overrides.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-
|
|
3
|
-
import { a as toJsonSchema } from "./schemaConverter-
|
|
2
|
+
import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-bqGpo9ML.mjs";
|
|
3
|
+
import { a as toJsonSchema } from "./schemaConverter-BxFDdtXu.mjs";
|
|
4
4
|
//#region src/core/createActionRouter.ts
|
|
5
5
|
var createActionRouter_exports = /* @__PURE__ */ __exportAll({
|
|
6
6
|
buildActionBodySchema: () => buildActionBodySchema,
|
|
@@ -246,4 +246,4 @@ function buildActionDescription(actions, actionPermissions) {
|
|
|
246
246
|
return lines.join("\n");
|
|
247
247
|
}
|
|
248
248
|
//#endregion
|
|
249
|
-
export {
|
|
249
|
+
export { createActionRouter_exports as n, buildActionBodySchema as t };
|
|
@@ -207,7 +207,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
|
|
|
207
207
|
await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
|
|
208
208
|
trackPlugin("arc-core");
|
|
209
209
|
if (config.arcPlugins?.events !== false) {
|
|
210
|
-
const { default: eventPlugin } = await import("./eventPlugin-
|
|
210
|
+
const { default: eventPlugin } = await import("./eventPlugin-Dl7MoVWH.mjs").then((n) => n.n);
|
|
211
211
|
const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
|
|
212
212
|
await fastify.register(eventPlugin, {
|
|
213
213
|
...eventOpts,
|
|
@@ -249,9 +249,9 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
249
249
|
trackPlugin("arc-caching", opts);
|
|
250
250
|
}
|
|
251
251
|
if (config.arcPlugins?.queryCache) {
|
|
252
|
-
const { queryCachePlugin } = await import("./queryCachePlugin-
|
|
252
|
+
const { queryCachePlugin } = await import("./queryCachePlugin-DbUVroUG.mjs").then((n) => n.n);
|
|
253
253
|
const opts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
|
|
254
|
-
const store = config.stores?.queryCache ?? new (await (import("./memory-
|
|
254
|
+
const store = config.stores?.queryCache ?? new (await (import("./memory-BFAYkf8H.mjs").then((n) => n.n))).MemoryCacheStore();
|
|
255
255
|
await fastify.register(queryCachePlugin, {
|
|
256
256
|
store,
|
|
257
257
|
...opts
|
|
@@ -340,7 +340,7 @@ async function registerAuth(fastify, config, trackPlugin) {
|
|
|
340
340
|
*/
|
|
341
341
|
async function registerElevation(fastify, config, trackPlugin) {
|
|
342
342
|
if (!config.elevation) return;
|
|
343
|
-
const { elevationPlugin } = await import("./elevation-
|
|
343
|
+
const { elevationPlugin } = await import("./elevation-DxQ6ACbt.mjs").then((n) => n.r);
|
|
344
344
|
await fastify.register(elevationPlugin, config.elevation);
|
|
345
345
|
trackPlugin("arc-elevation", config.elevation);
|
|
346
346
|
fastify.log.debug("Elevation plugin enabled");
|
|
@@ -350,7 +350,7 @@ async function registerElevation(fastify, config, trackPlugin) {
|
|
|
350
350
|
*/
|
|
351
351
|
async function registerErrorHandler(fastify, config, trackPlugin) {
|
|
352
352
|
if (config.errorHandler === false) return;
|
|
353
|
-
const { errorHandlerPlugin } = await import("./errorHandler-
|
|
353
|
+
const { errorHandlerPlugin } = await import("./errorHandler-CZDW4EXS.mjs").then((n) => n.r);
|
|
354
354
|
const errorOpts = typeof config.errorHandler === "object" ? config.errorHandler : { includeStack: config.preset !== "production" };
|
|
355
355
|
await fastify.register(errorHandlerPlugin, errorOpts);
|
|
356
356
|
trackPlugin("arc-error-handler", errorOpts);
|
|
@@ -688,6 +688,7 @@ async function createApp(options) {
|
|
|
688
688
|
const fastify = Fastify({
|
|
689
689
|
logger: config.logger ?? true,
|
|
690
690
|
trustProxy: config.trustProxy ?? false,
|
|
691
|
+
pluginTimeout: config.pluginTimeout ?? 1e4,
|
|
691
692
|
routerOptions: { querystringParser: (str) => qs.parse(str) },
|
|
692
693
|
ajv: { customOptions: {
|
|
693
694
|
coerceTypes: true,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS } from "./constants-Cxde4rpC.mjs";
|
|
2
2
|
import { _ as isElevated, n as PUBLIC_SCOPE, v as isMember } from "./types-AOD8fxIw.mjs";
|
|
3
|
-
import { t as BaseController } from "./BaseController-
|
|
4
|
-
import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-
|
|
3
|
+
import { t as BaseController } from "./BaseController-Vu2yc56T.mjs";
|
|
4
|
+
import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-CU6FlaDV.mjs";
|
|
5
5
|
import { t as getUserRoles } from "./types-ZUu_h0jp.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { t as
|
|
9
|
-
import { i as getDefaultCrudSchemas } from "./utils-
|
|
10
|
-
import {
|
|
11
|
-
import { t as hasEvents } from "./typeGuards-
|
|
12
|
-
import { r as getAvailablePresets, t as applyPresets } from "./presets-
|
|
6
|
+
import { r as ForbiddenError } from "./errors-CqWnSqM-.mjs";
|
|
7
|
+
import { t as requestContext } from "./requestContext-DYtmNpm5.mjs";
|
|
8
|
+
import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-bqGpo9ML.mjs";
|
|
9
|
+
import { i as getDefaultCrudSchemas } from "./utils-B7FuRr9w.mjs";
|
|
10
|
+
import { n as convertRouteSchema, t as convertOpenApiSchemas } from "./schemaConverter-BxFDdtXu.mjs";
|
|
11
|
+
import { t as hasEvents } from "./typeGuards-Cj5Rgvlg.mjs";
|
|
12
|
+
import { r as getAvailablePresets, t as applyPresets } from "./presets-hM4WhNWY.mjs";
|
|
13
13
|
//#region src/pipeline/pipe.ts
|
|
14
14
|
/**
|
|
15
15
|
* Compose pipeline steps into an ordered array.
|
|
@@ -387,24 +387,26 @@ function buildPermissionMiddleware(permissionCheck, resourceName, action) {
|
|
|
387
387
|
};
|
|
388
388
|
}
|
|
389
389
|
/**
|
|
390
|
-
*
|
|
390
|
+
* Mount custom routes (from presets or user-defined `routes`) on Fastify.
|
|
391
|
+
* `wrapHandler` is derived inline from `!route.raw`.
|
|
391
392
|
*/
|
|
392
|
-
function
|
|
393
|
+
function createCustomRoutes(fastify, routes, controller, options) {
|
|
393
394
|
const { tag, resourceName, arcDecorator, rateLimitConfig, cacheMw, idempotencyMw, pipeline, routeGuards } = options;
|
|
394
395
|
for (const route of routes) {
|
|
395
396
|
const opName = route.operation ?? (typeof route.handler === "string" ? route.handler : `${route.method.toLowerCase()}${route.path.replace(/[/:]/g, "_")}`);
|
|
397
|
+
const wrapHandler = !route.raw;
|
|
396
398
|
let handler;
|
|
397
399
|
if (typeof route.handler === "string") {
|
|
398
400
|
if (!controller) throw new Error(`Route ${route.method} ${route.path}: string handler '${route.handler}' requires a controller. Either provide a controller or use a function handler instead.`);
|
|
399
401
|
const method = controller[route.handler];
|
|
400
402
|
if (typeof method !== "function") throw new Error(`Handler '${route.handler}' not found on controller`);
|
|
401
403
|
const boundMethod = method.bind(controller);
|
|
402
|
-
if (
|
|
404
|
+
if (wrapHandler) {
|
|
403
405
|
const steps = pipeline ? resolvePipelineSteps(pipeline, opName) : [];
|
|
404
406
|
if (steps.length > 0) handler = createPipelineHandler(boundMethod, steps, opName, resourceName);
|
|
405
407
|
else handler = createFastifyHandler(boundMethod);
|
|
406
408
|
} else handler = boundMethod;
|
|
407
|
-
} else if (
|
|
409
|
+
} else if (wrapHandler) {
|
|
408
410
|
const steps = pipeline ? resolvePipelineSteps(pipeline, opName) : [];
|
|
409
411
|
if (steps.length > 0) handler = createPipelineHandler(route.handler, steps, opName, resourceName);
|
|
410
412
|
else handler = createFastifyHandler(route.handler);
|
|
@@ -480,7 +482,7 @@ function createPipelineHandler(controllerMethod, steps, operation, resourceName)
|
|
|
480
482
|
* @param options - Router configuration
|
|
481
483
|
*/
|
|
482
484
|
function createCrudRouter(fastify, controller, options = {}) {
|
|
483
|
-
const { tag = "Resource", schemas = {}, permissions = {}, middlewares = {}, routeGuards = [],
|
|
485
|
+
const { tag = "Resource", schemas = {}, permissions = {}, middlewares = {}, routeGuards = [], routes: customRoutes = [], disableDefaultRoutes = false, disabledRoutes = [], resourceName = "unknown", schemaOptions, rateLimit, pipe: pipeline, fields: fieldPermissions, updateMethod = DEFAULT_UPDATE_METHOD } = options;
|
|
484
486
|
const rateLimitConfig = buildRateLimitConfig(rateLimit);
|
|
485
487
|
const cacheMw = !(fastify.hasDecorator("queryCache") && controller && typeof controller._cacheConfig !== "undefined" && controller._cacheConfig !== void 0) && fastify.hasDecorator("responseCache") ? fastify.responseCache.middleware : null;
|
|
486
488
|
const idempotencyMw = fastify.hasDecorator("idempotency") ? fastify.idempotency.middleware : null;
|
|
@@ -646,7 +648,7 @@ function createCrudRouter(fastify, controller, options = {}) {
|
|
|
646
648
|
});
|
|
647
649
|
}
|
|
648
650
|
}
|
|
649
|
-
if (
|
|
651
|
+
if (customRoutes.length > 0) createCustomRoutes(fastify, customRoutes, controller, {
|
|
650
652
|
tag,
|
|
651
653
|
resourceName,
|
|
652
654
|
arcDecorator,
|
|
@@ -941,6 +943,7 @@ function defineResource(config) {
|
|
|
941
943
|
idField: resolvedConfig.idField,
|
|
942
944
|
matchesFilter: config.adapter?.matchesFilter,
|
|
943
945
|
cache: resolvedConfig.cache,
|
|
946
|
+
onFieldWriteDenied: resolvedConfig.onFieldWriteDenied,
|
|
944
947
|
presetFields: resolvedConfig._controllerOptions ? {
|
|
945
948
|
slugField: resolvedConfig._controllerOptions.slugField,
|
|
946
949
|
parentField: resolvedConfig._controllerOptions.parentField
|
|
@@ -1088,16 +1091,6 @@ var ResourceDefinition = class {
|
|
|
1088
1091
|
schemaOptions;
|
|
1089
1092
|
customSchemas;
|
|
1090
1093
|
permissions;
|
|
1091
|
-
additionalRoutes;
|
|
1092
|
-
/**
|
|
1093
|
-
* Original v2.8 `routes` declaration — retained for downstream consumers
|
|
1094
|
-
* (OpenAPI, MCP, registry, CLI introspect). Preserves fields dropped during
|
|
1095
|
-
* normalization to `additionalRoutes` (notably `mcp`, `description`,
|
|
1096
|
-
* `annotations`). Undefined when the resource was defined with the legacy
|
|
1097
|
-
* `additionalRoutes` shape.
|
|
1098
|
-
*
|
|
1099
|
-
* Added in 2.8.1 — the source-of-truth fix for "canonical resource manifest".
|
|
1100
|
-
*/
|
|
1101
1094
|
routes;
|
|
1102
1095
|
middlewares;
|
|
1103
1096
|
routeGuards;
|
|
@@ -1130,8 +1123,7 @@ var ResourceDefinition = class {
|
|
|
1130
1123
|
this.schemaOptions = config.schemaOptions ?? {};
|
|
1131
1124
|
this.customSchemas = config.customSchemas ?? {};
|
|
1132
1125
|
this.permissions = config.permissions ?? {};
|
|
1133
|
-
this.routes = config.routes;
|
|
1134
|
-
this.additionalRoutes = config.routes ? convertRoutesToAdditionalRoutes(config.routes) : [];
|
|
1126
|
+
this.routes = config.routes ?? [];
|
|
1135
1127
|
this.middlewares = config.middlewares ?? {};
|
|
1136
1128
|
this.routeGuards = config.routeGuards;
|
|
1137
1129
|
this.disableDefaultRoutes = config.disableDefaultRoutes ?? false;
|
|
@@ -1150,7 +1142,6 @@ var ResourceDefinition = class {
|
|
|
1150
1142
|
this.queryParser = config.queryParser;
|
|
1151
1143
|
this._appliedPresets = config._appliedPresets ?? [];
|
|
1152
1144
|
this._pendingHooks = config._pendingHooks ?? [];
|
|
1153
|
-
if (config.onRegister) this._onRegister = config.onRegister;
|
|
1154
1145
|
}
|
|
1155
1146
|
/** Get repository from adapter (if available) */
|
|
1156
1147
|
get repository() {
|
|
@@ -1166,7 +1157,7 @@ var ResourceDefinition = class {
|
|
|
1166
1157
|
const ctrl = this.controller;
|
|
1167
1158
|
for (const method of enabledCrudRoutes) if (typeof ctrl[method] !== "function") errors.push(`CRUD method '${method}' not found on controller`);
|
|
1168
1159
|
}
|
|
1169
|
-
for (const route of this.
|
|
1160
|
+
for (const route of this.routes) if (typeof route.handler === "string") {
|
|
1170
1161
|
if (!this.controller) errors.push(`Route ${route.method} ${route.path}: string handler '${route.handler}' requires a controller`);
|
|
1171
1162
|
else if (typeof this.controller[route.handler] !== "function") errors.push(`Route ${route.method} ${route.path}: handler '${route.handler}' not found`);
|
|
1172
1163
|
}
|
|
@@ -1207,8 +1198,6 @@ var ResourceDefinition = class {
|
|
|
1207
1198
|
});
|
|
1208
1199
|
await fastify.register(async (instance) => {
|
|
1209
1200
|
const typedInstance = instance;
|
|
1210
|
-
const onRegister = self._onRegister;
|
|
1211
|
-
if (onRegister) await onRegister(instance);
|
|
1212
1201
|
let schemas = null;
|
|
1213
1202
|
const openApi = self._registryMeta?.openApiSchemas;
|
|
1214
1203
|
if (openApi && (!self.customSchemas || Object.keys(self.customSchemas).length === 0)) {
|
|
@@ -1281,14 +1270,13 @@ var ResourceDefinition = class {
|
|
|
1281
1270
|
schemas = schemas ?? {};
|
|
1282
1271
|
schemas.list = schemas.list ? deepMergeSchemas({ querystring: normalizedSchema }, schemas.list) : { querystring: normalizedSchema };
|
|
1283
1272
|
}
|
|
1284
|
-
const resolvedRoutes = self.additionalRoutes;
|
|
1285
1273
|
createCrudRouter(typedInstance, self.controller, {
|
|
1286
1274
|
tag: self.tag,
|
|
1287
1275
|
schemas: schemas ?? void 0,
|
|
1288
1276
|
permissions: self.permissions,
|
|
1289
1277
|
middlewares: self.middlewares,
|
|
1290
1278
|
routeGuards: self.routeGuards,
|
|
1291
|
-
|
|
1279
|
+
routes: self.routes,
|
|
1292
1280
|
disableDefaultRoutes: self.disableDefaultRoutes,
|
|
1293
1281
|
disabledRoutes: self.disabledRoutes,
|
|
1294
1282
|
resourceName: self.name,
|
|
@@ -1299,7 +1287,7 @@ var ResourceDefinition = class {
|
|
|
1299
1287
|
fields: self.fields
|
|
1300
1288
|
});
|
|
1301
1289
|
if (self.actions && Object.keys(self.actions).length > 0) {
|
|
1302
|
-
const { createActionRouter } = await import("./createActionRouter-
|
|
1290
|
+
const { createActionRouter } = await import("./createActionRouter-DH1YFL9m.mjs").then((n) => n.n);
|
|
1303
1291
|
createActionRouter(instance, normalizeActionsToRouterConfig(self.actions, self.actionPermissions, self.tag));
|
|
1304
1292
|
}
|
|
1305
1293
|
if (self.events && Object.keys(self.events).length > 0) typedInstance.log?.debug?.(`Resource '${self.name}' defined ${Object.keys(self.events).length} events`);
|
|
@@ -1366,29 +1354,6 @@ function capitalize(str) {
|
|
|
1366
1354
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1367
1355
|
}
|
|
1368
1356
|
/**
|
|
1369
|
-
* Convert v2.8 RouteDefinition[] to internal AdditionalRoute[] format.
|
|
1370
|
-
* The internal format is what createCrudRouter understands.
|
|
1371
|
-
*/
|
|
1372
|
-
function convertRoutesToAdditionalRoutes(routes) {
|
|
1373
|
-
return routes.map((route) => ({
|
|
1374
|
-
method: route.method,
|
|
1375
|
-
path: route.path,
|
|
1376
|
-
handler: route.handler,
|
|
1377
|
-
permissions: route.permissions,
|
|
1378
|
-
wrapHandler: !route.raw,
|
|
1379
|
-
operation: route.operation,
|
|
1380
|
-
summary: route.summary,
|
|
1381
|
-
description: route.description,
|
|
1382
|
-
tags: route.tags,
|
|
1383
|
-
preHandler: route.preHandler,
|
|
1384
|
-
preAuth: route.preAuth,
|
|
1385
|
-
streamResponse: route.streamResponse,
|
|
1386
|
-
schema: route.schema,
|
|
1387
|
-
mcpHandler: route.mcpHandler,
|
|
1388
|
-
mcp: route.mcp
|
|
1389
|
-
}));
|
|
1390
|
-
}
|
|
1391
|
-
/**
|
|
1392
1357
|
* Normalize ActionsMap into the ActionRouterConfig shape that createActionRouter expects.
|
|
1393
1358
|
*/
|
|
1394
1359
|
function normalizeActionsToRouterConfig(actions, globalAuth, tag) {
|
package/dist/docs/index.d.mts
CHANGED
package/dist/docs/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as getUserRoles } from "../types-ZUu_h0jp.mjs";
|
|
2
|
-
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-
|
|
2
|
+
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-CXuTG1M9.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/docs/scalar.ts
|
|
5
5
|
const scalarPlugin = async (fastify, opts = {}) => {
|
package/dist/dynamic/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as PermissionCheck } from "../types-
|
|
1
|
+
import { Kt as ResourceDefinition, r as DataAdapter } from "../interface-YrWsmKqE.mjs";
|
|
2
|
+
import { t as PermissionCheck } from "../types-DZi1aYhm.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/dynamic/ArcDynamicLoader.d.ts
|
|
5
5
|
interface ArcArchitectureSchema {
|
package/dist/dynamic/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as ArcQueryParser } from "../queryParser-
|
|
2
|
-
import { n as defineResource } from "../defineResource-
|
|
3
|
-
import { C as publicRead, T as readOnly, b as fullPublic, v as adminOnly, w as publicReadAdminWrite, x as ownerWithAdminBypass, y as authenticated } from "../permissions-
|
|
1
|
+
import { t as ArcQueryParser } from "../queryParser-Cs-6SHQK.mjs";
|
|
2
|
+
import { n as defineResource } from "../defineResource-C__jkwvs.mjs";
|
|
3
|
+
import { C as publicRead, T as readOnly, b as fullPublic, v as adminOnly, w as publicReadAdminWrite, x as ownerWithAdminBypass, y as authenticated } from "../permissions-oNZawnkR.mjs";
|
|
4
4
|
//#region src/dynamic/ArcDynamicLoader.ts
|
|
5
5
|
const VALID_FIELD_TYPES = new Set([
|
|
6
6
|
"string",
|
|
@@ -57,13 +57,27 @@ const elevationPlugin = async (fastify, opts = {}) => {
|
|
|
57
57
|
userId,
|
|
58
58
|
organizationId: orgId
|
|
59
59
|
});
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
const event = {
|
|
61
|
+
userId,
|
|
62
|
+
organizationId: orgId || void 0,
|
|
63
|
+
request,
|
|
64
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
65
|
+
};
|
|
66
|
+
const publish = fastify.events?.publish;
|
|
67
|
+
if (publish) try {
|
|
68
|
+
await publish("arc.scope.elevated", {
|
|
69
|
+
userId: event.userId,
|
|
70
|
+
organizationId: event.organizationId,
|
|
71
|
+
route: request.routeOptions?.url ?? request.url,
|
|
72
|
+
method: request.method,
|
|
73
|
+
requestId: request.id,
|
|
74
|
+
timestamp: event.timestamp.toISOString()
|
|
66
75
|
});
|
|
76
|
+
} catch (err) {
|
|
77
|
+
log.warn("Failed to publish arc.scope.elevated event", { error: err instanceof Error ? err.message : String(err) });
|
|
78
|
+
}
|
|
79
|
+
if (onElevation) try {
|
|
80
|
+
await onElevation(event);
|
|
67
81
|
} catch {
|
|
68
82
|
log.warn("onElevation callback threw — continuing request");
|
|
69
83
|
}
|
|
@@ -1,11 +1,61 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import { p as isArcError } from "./errors-
|
|
2
|
+
import { p as isArcError } from "./errors-CqWnSqM-.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/plugins/errorHandler.ts
|
|
5
|
-
var errorHandler_exports = /* @__PURE__ */ __exportAll({
|
|
5
|
+
var errorHandler_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
defaultIsDuplicateKeyError: () => defaultIsDuplicateKeyError,
|
|
7
|
+
errorHandlerPlugin: () => errorHandlerPlugin
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* Default duplicate-key detector covering the mainstream drivers arc sees
|
|
11
|
+
* most. Detection is strictly by known driver codes — never by message
|
|
12
|
+
* string matching — because false positives on dup-key silently mask real
|
|
13
|
+
* errors (WriteConflict, NotWritablePrimary, etc.) as 409s. For long-tail
|
|
14
|
+
* drivers (Neo4j, MSSQL, DynamoDB, custom kits), compose rather than
|
|
15
|
+
* replace:
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { defaultIsDuplicateKeyError } from '@classytic/arc/plugins';
|
|
19
|
+
*
|
|
20
|
+
* errorHandler: {
|
|
21
|
+
* isDuplicateKeyError: (err) =>
|
|
22
|
+
* defaultIsDuplicateKeyError(err) || isNeo4jDupKey(err),
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Drizzle apps get coverage transitively (Drizzle doesn't wrap driver
|
|
27
|
+
* errors — pg/mysql2/better-sqlite3 codes propagate as-is). Neon is
|
|
28
|
+
* Postgres-wire-compatible → `23505` covers `@neondatabase/serverless`.
|
|
29
|
+
*/
|
|
30
|
+
function defaultIsDuplicateKeyError(err) {
|
|
31
|
+
if (!err || typeof err !== "object") return false;
|
|
32
|
+
const e = err;
|
|
33
|
+
if (e.code === 11e3 || e.codeName === "DuplicateKey") return true;
|
|
34
|
+
if (e.code === "P2002") return true;
|
|
35
|
+
if (e.code === "23505") return true;
|
|
36
|
+
if (e.code === "ER_DUP_ENTRY" || e.errno === 1062) return true;
|
|
37
|
+
if (e.code === "SQLITE_CONSTRAINT_UNIQUE" || e.code === "SQLITE_CONSTRAINT_PRIMARYKEY") return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Extract the duplicate-field names for the `details.duplicateFields`
|
|
42
|
+
* response. Only called when the caller has opted into detail exposure
|
|
43
|
+
* (`includeStack: true`) — shape differs per driver.
|
|
44
|
+
*/
|
|
45
|
+
function extractDuplicateFields(err) {
|
|
46
|
+
if (!err || typeof err !== "object") return null;
|
|
47
|
+
const e = err;
|
|
48
|
+
if (e.keyValue && typeof e.keyValue === "object") return Object.keys(e.keyValue);
|
|
49
|
+
if (e.meta?.target) {
|
|
50
|
+
if (Array.isArray(e.meta.target)) return e.meta.target.map(String);
|
|
51
|
+
if (typeof e.meta.target === "string") return [e.meta.target];
|
|
52
|
+
}
|
|
53
|
+
if (typeof e.constraint === "string") return [e.constraint];
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
6
56
|
async function errorHandlerPluginFn(fastify, options = {}) {
|
|
7
57
|
const isProduction = process.env.NODE_ENV === "production";
|
|
8
|
-
const { includeStack = !isProduction, onError, errorMap = {}, errorMappers = [] } = options;
|
|
58
|
+
const { includeStack = !isProduction, onError, errorMap = {}, errorMappers = [], isDuplicateKeyError = defaultIsDuplicateKeyError } = options;
|
|
9
59
|
fastify.setErrorHandler(async (error, request, reply) => {
|
|
10
60
|
if (onError) try {
|
|
11
61
|
await onError(error, request);
|
|
@@ -75,12 +125,14 @@ async function errorHandlerPluginFn(fastify, options = {}) {
|
|
|
75
125
|
statusCode = 400;
|
|
76
126
|
response.code = "INVALID_ID";
|
|
77
127
|
response.error = "Invalid identifier format";
|
|
78
|
-
} else if (error
|
|
128
|
+
} else if (isDuplicateKeyError(error)) {
|
|
79
129
|
statusCode = 409;
|
|
80
130
|
response.code = "DUPLICATE_KEY";
|
|
81
131
|
response.error = "Resource already exists";
|
|
82
|
-
|
|
83
|
-
|
|
132
|
+
if (includeStack) {
|
|
133
|
+
const duplicateFields = extractDuplicateFields(error);
|
|
134
|
+
if (duplicateFields && duplicateFields.length > 0) response.details = { duplicateFields };
|
|
135
|
+
}
|
|
84
136
|
}
|
|
85
137
|
if (includeStack && error.stack) response.stack = error.stack;
|
|
86
138
|
if (statusCode >= 500) request.log.error({
|
|
@@ -118,4 +170,4 @@ const errorHandlerPlugin = fp(errorHandlerPluginFn, {
|
|
|
118
170
|
fastify: "5.x"
|
|
119
171
|
});
|
|
120
172
|
//#endregion
|
|
121
|
-
export {
|
|
173
|
+
export { errorHandlerPlugin as n, errorHandler_exports as r, defaultIsDuplicateKeyError as t };
|