@classytic/arc 2.21.0 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BaseController-BnLYgE9A.mjs → BaseController-BQ8KNvWC.mjs} +3 -2
- package/dist/{ResourceRegistry-7RnrEWNP.mjs → ResourceRegistry-y9Hnypus.mjs} +1 -0
- package/dist/{actionPermissions-ze70xXJi.mjs → actionPermissions-lszoJle1.mjs} +1 -1
- package/dist/applyPermissionResult-Tw4iXtlf.mjs +264 -0
- package/dist/audit/index.d.mts +2 -2
- package/dist/auth/index.d.mts +30 -2
- package/dist/auth/index.mjs +6 -3
- package/dist/cli/commands/describe.d.mts +1 -1
- package/dist/cli/commands/describe.mjs +1 -1
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/init.mjs +1 -1
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +3 -3
- package/dist/{core-DZ6Xe1jR.mjs → core-DQ6rDTyH.mjs} +126 -68
- package/dist/{createActionRouter-BWMDW-dL.mjs → createActionRouter-BuOv-m4Y.mjs} +10 -6
- package/dist/{createAggregationRouter-l5mNdYrZ.mjs → createAggregationRouter-CgJv_BU_.mjs} +3 -3
- package/dist/{createApp-Bi61XxqU.mjs → createApp-CjOeWJ9_.mjs} +252 -57
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +1 -1
- package/dist/encryption/index.mjs +9 -5
- package/dist/{errorHandler-Dxf6P_kV.mjs → errorHandler-Bq2OeEQL.mjs} +34 -10
- package/dist/{errorHandler-B0e-bq-O.d.mts → errorHandler-C6yv4ZTW.d.mts} +13 -0
- package/dist/events/index.mjs +5 -2
- package/dist/factory/index.d.mts +46 -9
- package/dist/factory/index.mjs +64 -13
- package/dist/{fastify-augmentation-DafigGQp.d.mts → fastify-augmentation-g_f9omSc.d.mts} +2 -2
- package/dist/fields-D3lhgzhD.d.mts +121 -0
- package/dist/health-ScyjIVo5.mjs +202 -0
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +7 -0
- package/dist/idempotency/index.mjs +7 -17
- package/dist/{index-Dtrj6XZk.d.mts → index-BBsvQt7U.d.mts} +1310 -1226
- package/dist/{types-DpxoNX5v.d.mts → index-Ba10fdKp.d.mts} +196 -66
- package/dist/{index-B5N-NaHs.d.mts → index-CC5ruDGh.d.mts} +3 -3
- package/dist/{index-B5PoNbfu.d.mts → index-wMoWBLkn.d.mts} +68 -2
- package/dist/index.d.mts +6 -5
- package/dist/index.mjs +6 -5
- package/dist/{init-0YhHkXGk.mjs → init-CjO4p_q1.mjs} +123 -4
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +67 -4
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/webhooks.d.mts +131 -7
- package/dist/integrations/webhooks.mjs +169 -10
- package/dist/interface-n5hpKg1d.mjs +16 -0
- package/dist/jsonBody-BlzAoGCe.mjs +43 -0
- package/dist/{loadResourcesFromEntry-OMCvIEE7.mjs → loadResourcesFromEntry-kvGT6EcO.mjs} +1 -1
- package/dist/logger/index.d.mts +26 -1
- package/dist/logger/index.mjs +39 -1
- package/dist/{mcpPlugin-B9XjjNVG.mjs → mcpPlugin-BtzIL_kM.mjs} +312 -39
- package/dist/middleware/index.d.mts +1 -1
- package/dist/{module-WeuU5jfd.d.mts → module-B4u10iOJ.d.mts} +26 -1
- package/dist/{openapi-Kyod_di6.mjs → openapi-jSDx-VDv.mjs} +3 -3
- package/dist/permissions/index.d.mts +4 -3
- package/dist/permissions/index.mjs +3 -2
- package/dist/{permissions-BJMuKMl7.mjs → permissions-tbxFHxjZ.mjs} +77 -264
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/plugins/index.d.mts +24 -7
- package/dist/plugins/index.mjs +14 -282
- package/dist/plugins/response-cache.mjs +1 -0
- package/dist/plugins/tracing-entry.mjs +7 -4
- package/dist/presets/filesUpload.d.mts +2 -2
- package/dist/presets/filesUpload.mjs +1 -1
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-gw0ciIUD.mjs → presets-BOe4Ugkl.mjs} +1 -1
- package/dist/rateLimitKey-BoWRH3e7.mjs +14 -0
- package/dist/realtime-I8OrfnMR.mjs +375 -0
- package/dist/{registerRoute-oGAl0oA8.mjs → registerRoute-CWO6mdYe.mjs} +38 -18
- package/dist/registry/index.d.mts +2 -2
- package/dist/registry/index.mjs +1 -1
- package/dist/requestId-5BhTVzBv.mjs +113 -0
- package/dist/schemaConverter-DJvodiHj.mjs +171 -0
- package/dist/{schemaIR-ajetw3Fv.mjs → schemaIR-Ca7ySNPx.mjs} +2 -2
- package/dist/scim/index.mjs +6 -7
- package/dist/scope/index.mjs +2 -76
- package/dist/scope-LONQ3mfZ.mjs +37 -0
- package/dist/simpleEqualityMatcher-Cg05HPsn.mjs +68 -0
- package/dist/{sse-CfUjwjDk.mjs → sse-0u4P4-OI.mjs} +7 -30
- package/dist/sseStream-BQ7Qaynp.mjs +57 -0
- package/dist/testing/index.d.mts +83 -3
- package/dist/testing/index.mjs +70 -3
- package/dist/types/index.d.mts +2 -2
- package/dist/{types-DRj-Ut4n.d.mts → types-5OuqeTDX.d.mts} +37 -2
- package/dist/{fields-BGqrAa_u.d.mts → types-Csxga7d3.d.mts} +1 -121
- package/dist/usage/index.d.mts +142 -0
- package/dist/usage/index.mjs +0 -0
- package/dist/utils/index.d.mts +101 -19
- package/dist/utils/index.mjs +5 -3
- package/dist/{utils-CO8a3B_1.mjs → utils-CZyeRXTh.mjs} +80 -82
- package/dist/{versioning-DQ4mCvg0.d.mts → versioning-D6PvCwpq.d.mts} +43 -9
- package/llms.txt +39 -0
- package/package.json +513 -447
- package/skills/arc/SKILL.md +14 -8
- package/skills/arc/references/api-reference.md +34 -0
- package/skills/arc/references/auth.md +21 -4
- package/skills/arc/references/mcp.md +1 -1
- package/skills/arc/references/production.md +734 -654
- package/skills/arc-code-review/SKILL.md +1 -1
- package/skills/arc-code-review/references/anti-patterns.md +71 -18
- package/skills/arc-code-review/references/arc-cheatsheet.md +15 -2
- package/skills/arc-code-review/references/migration-recipes.md +7 -7
- package/skills/arc-code-review/references/mongokit-migration.md +4 -3
- package/skills/arc-module-publishing/SKILL.md +2 -1
- package/skills/arc-module-publishing/references/authoring-modules.md +55 -0
- package/skills/arc-module-publishing/references/package-manifest.md +4 -2
- package/dist/preloadResources-CHw3_oA_.mjs +0 -45
- package/dist/schemaConverter-U0MnO9vd.mjs +0 -110
|
@@ -1,75 +1,8 @@
|
|
|
1
1
|
import { m as RESERVED_QUERY_PARAMS, t as CRUD_OPERATIONS } from "./constants-DNre0wRg.mjs";
|
|
2
2
|
import { arcLog } from "./logger/index.mjs";
|
|
3
3
|
import { t as ArcError } from "./errors-DkO8Nk6-.mjs";
|
|
4
|
-
import { r as getAvailablePresets } from "./presets-
|
|
4
|
+
import { r as getAvailablePresets } from "./presets-BOe4Ugkl.mjs";
|
|
5
5
|
import { errorContractSchema as errorContractSchema$1, errorDetailSchema as errorDetailSchema$1 } from "@classytic/repo-core/errors";
|
|
6
|
-
//#region src/utils/simpleEqualityMatcher.ts
|
|
7
|
-
/**
|
|
8
|
-
* `simpleEqualityMatcher` — a minimal, dialect-agnostic flat-key equality
|
|
9
|
-
* matcher for `DataAdapter.matchesFilter` / `BaseController({ matchesFilter })`.
|
|
10
|
-
*
|
|
11
|
-
* **What it does:** for each `[key, expected]` in the filter, compares
|
|
12
|
-
* `item[key]` to `expected` via string coercion (so Mongo `ObjectId` values
|
|
13
|
-
* match their string representation) and returns `true` only if every
|
|
14
|
-
* filter entry matches. Array item values are matched implicitly (contains).
|
|
15
|
-
*
|
|
16
|
-
* **What it does NOT do:**
|
|
17
|
-
* - No `$eq` / `$ne` / `$in` / `$nin` / `$gt` / `$lt` / `$regex` / `$exists`
|
|
18
|
-
* - No `$and` / `$or`
|
|
19
|
-
* - No dot-path traversal (`"owner.id"`)
|
|
20
|
-
* - No schema-specific coercion
|
|
21
|
-
*
|
|
22
|
-
* **Why it exists:** 95%+ of arc's `_policyFilters` are produced by built-in
|
|
23
|
-
* permission helpers and are shaped like `{ ownerId: "u1" }` or
|
|
24
|
-
* `{ organizationId: "org_x" }` — flat equality. For that common shape,
|
|
25
|
-
* this helper is a safe, tested, 15-line defense-in-depth matcher that
|
|
26
|
-
* hosts using minimal repos (no `getOne(compoundFilter)` DB path) can opt
|
|
27
|
-
* into without arc shipping a full Mongo-syntax engine.
|
|
28
|
-
*
|
|
29
|
-
* **When to use:**
|
|
30
|
-
* - Your adapter/repo doesn't natively filter on `getOne(compoundFilter)`
|
|
31
|
-
* - Your `_policyFilters` are flat equality (from arc's built-in permission helpers)
|
|
32
|
-
* - You want defense-in-depth on `validateItemAccess` / `fetchDetailed`'s `getById` fallback
|
|
33
|
-
*
|
|
34
|
-
* **When NOT to use:**
|
|
35
|
-
* - Your `_policyFilters` use operators (`$in`, `$ne`, etc.) — supply a
|
|
36
|
-
* native matcher (mongokit's repo does the filter at the DB layer; for
|
|
37
|
-
* custom repos, wrap the kit's own predicate engine).
|
|
38
|
-
* - You're a mongokit / sqlitekit / Prisma user — the DB-level filter
|
|
39
|
-
* applied by `getOne(compoundFilter)` already covers this.
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* ```ts
|
|
43
|
-
* import { simpleEqualityMatcher } from '@classytic/arc/utils';
|
|
44
|
-
*
|
|
45
|
-
* // On a custom adapter
|
|
46
|
-
* const adapter: DataAdapter = {
|
|
47
|
-
* repository,
|
|
48
|
-
* type: 'custom',
|
|
49
|
-
* name: 'in-memory',
|
|
50
|
-
* matchesFilter: simpleEqualityMatcher,
|
|
51
|
-
* };
|
|
52
|
-
*
|
|
53
|
-
* // Or directly on BaseController for ad-hoc controllers
|
|
54
|
-
* new BaseController(repo, { matchesFilter: simpleEqualityMatcher });
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
function simpleEqualityMatcher(item, filters) {
|
|
58
|
-
if (!item || typeof item !== "object") return false;
|
|
59
|
-
const obj = item;
|
|
60
|
-
for (const [key, expected] of Object.entries(filters)) {
|
|
61
|
-
if (expected && typeof expected === "object" && !Array.isArray(expected) && Object.getPrototypeOf(expected) === Object.prototype && Object.keys(expected).some((k) => k.startsWith("$"))) return false;
|
|
62
|
-
const actual = obj[key];
|
|
63
|
-
if (Array.isArray(actual)) {
|
|
64
|
-
const expectedStr = String(expected);
|
|
65
|
-
if (!actual.some((v) => String(v) === expectedStr)) return false;
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (String(actual) !== String(expected)) return false;
|
|
69
|
-
}
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
//#endregion
|
|
73
6
|
//#region src/core/validateResourceConfig.ts
|
|
74
7
|
/**
|
|
75
8
|
* Resource Configuration Validator
|
|
@@ -837,6 +770,25 @@ function handleRaw(handler, statusCode = 200) {
|
|
|
837
770
|
};
|
|
838
771
|
}
|
|
839
772
|
//#endregion
|
|
773
|
+
//#region src/utils/headers.ts
|
|
774
|
+
/**
|
|
775
|
+
* Read a single header value. Lowercases the name (Node normalizes incoming
|
|
776
|
+
* header names to lowercase) and returns the FIRST value when the header
|
|
777
|
+
* was repeated.
|
|
778
|
+
*
|
|
779
|
+
* Duplicate policy: first-value is deterministic, but for security-sensitive
|
|
780
|
+
* headers (authorization material, forwarded-for chains, content-length) a
|
|
781
|
+
* duplicate usually signals smuggling or a broken proxy — consumers that
|
|
782
|
+
* care should check `Array.isArray(headers[name])` and REJECT instead of
|
|
783
|
+
* picking a winner.
|
|
784
|
+
*/
|
|
785
|
+
function getHeader(headers, name) {
|
|
786
|
+
if (!headers) return void 0;
|
|
787
|
+
const value = headers[name.toLowerCase()];
|
|
788
|
+
if (Array.isArray(value)) return value[0];
|
|
789
|
+
return value;
|
|
790
|
+
}
|
|
791
|
+
//#endregion
|
|
840
792
|
//#region src/utils/queryParser.ts
|
|
841
793
|
/**
|
|
842
794
|
* Arc Query Parser - Default URL-to-Query Parser
|
|
@@ -1295,26 +1247,72 @@ const paginationSchema = {
|
|
|
1295
1247
|
]
|
|
1296
1248
|
};
|
|
1297
1249
|
/**
|
|
1298
|
-
* List response schema —
|
|
1299
|
-
*
|
|
1300
|
-
*
|
|
1250
|
+
* List response schema — accepts every wire shape `toCanonicalList` can
|
|
1251
|
+
* emit. Hosts who know their endpoint only ever produces one variant can
|
|
1252
|
+
* pin to a narrower helper (sharper OpenAPI docs, same serializer speed):
|
|
1301
1253
|
* - `offsetListResponse(item)` — `{ method: 'offset', data, page, limit, total, pages, hasNext, hasPrev }`
|
|
1302
1254
|
* - `keysetListResponse(item)` — `{ method: 'keyset', data, limit, hasMore, next: string|null }`
|
|
1303
1255
|
* - `aggregateListResponse(item)` — `{ method: 'aggregate', ...offset fields }`
|
|
1304
1256
|
* - `bareListResponse(item)` — `{ data }`
|
|
1305
1257
|
*
|
|
1306
|
-
*
|
|
1307
|
-
*
|
|
1308
|
-
*
|
|
1309
|
-
*
|
|
1258
|
+
* SHAPE: one merged permissive object, NOT a `oneOf` union (2.22). The
|
|
1259
|
+
* pre-2.22 union was semantically identical on the wire — every variant is
|
|
1260
|
+
* `additionalProperties: true` and the property definitions never conflict
|
|
1261
|
+
* (`next` only exists on keyset, the offset counters only on offset/
|
|
1262
|
+
* aggregate; fast-json-stringify skips undefined optionals) — but
|
|
1263
|
+
* fast-json-stringify implements top-level `oneOf` by running full AJV
|
|
1264
|
+
* validation PER RESPONSE to pick the branch, on the hottest route of
|
|
1265
|
+
* every arc app. The merge keeps the exact bytes (pinned by
|
|
1266
|
+
* `tests/utils/list-response-serialization.test.ts`) and drops the
|
|
1267
|
+
* per-response branch validation. Only `data` is required — the one field
|
|
1268
|
+
* all four variants share.
|
|
1310
1269
|
*/
|
|
1311
1270
|
function listResponse(itemSchema) {
|
|
1312
|
-
return {
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1271
|
+
return {
|
|
1272
|
+
type: "object",
|
|
1273
|
+
properties: {
|
|
1274
|
+
method: {
|
|
1275
|
+
type: "string",
|
|
1276
|
+
description: "Pagination method discriminant — 'offset' | 'keyset' | 'aggregate'; absent on bare lists.",
|
|
1277
|
+
example: "offset"
|
|
1278
|
+
},
|
|
1279
|
+
data: {
|
|
1280
|
+
type: "array",
|
|
1281
|
+
items: itemSchema
|
|
1282
|
+
},
|
|
1283
|
+
page: {
|
|
1284
|
+
type: "integer",
|
|
1285
|
+
example: 1
|
|
1286
|
+
},
|
|
1287
|
+
limit: {
|
|
1288
|
+
type: "integer",
|
|
1289
|
+
example: 20
|
|
1290
|
+
},
|
|
1291
|
+
total: {
|
|
1292
|
+
type: "integer",
|
|
1293
|
+
example: 100
|
|
1294
|
+
},
|
|
1295
|
+
pages: {
|
|
1296
|
+
type: "integer",
|
|
1297
|
+
example: 5
|
|
1298
|
+
},
|
|
1299
|
+
hasNext: {
|
|
1300
|
+
type: "boolean",
|
|
1301
|
+
example: false
|
|
1302
|
+
},
|
|
1303
|
+
hasPrev: {
|
|
1304
|
+
type: "boolean",
|
|
1305
|
+
example: false
|
|
1306
|
+
},
|
|
1307
|
+
hasMore: { type: "boolean" },
|
|
1308
|
+
next: {
|
|
1309
|
+
type: ["string", "null"],
|
|
1310
|
+
description: "Cursor token for the next page, or null."
|
|
1311
|
+
}
|
|
1312
|
+
},
|
|
1313
|
+
required: ["data"],
|
|
1314
|
+
additionalProperties: true
|
|
1315
|
+
};
|
|
1318
1316
|
}
|
|
1319
1317
|
/** Offset variant — `{ method: 'offset', data, page, limit, total, pages, hasNext, hasPrev }`. */
|
|
1320
1318
|
function offsetListResponse(itemSchema) {
|
|
@@ -1732,4 +1730,4 @@ function getUserId(user) {
|
|
|
1732
1730
|
return id ? String(id) : void 0;
|
|
1733
1731
|
}
|
|
1734
1732
|
//#endregion
|
|
1735
|
-
export {
|
|
1733
|
+
export { CircuitState as A, defineGuard as C, CircuitBreaker as D, withCompensation as E, validateResourceConfig as F, createCircuitBreakerRegistry as M, assertValidConfig as N, CircuitBreakerError as O, formatValidationErrors as P, NEUTRAL_DIALECT as S, defineCompensation as T, ArcQueryParser as _, bareListResponse as a, handleRaw as b, errorDetailSchema$1 as c, keysetListResponse as d, listResponse as f, responses as g, queryParams as h, aggregateListResponse as i, createCircuitBreaker as j, CircuitBreakerRegistry as k, getDefaultCrudSchemas as l, paginationSchema as m, createStateMachine as n, deleteResponse as o, offsetListResponse as p, scheduleBackground as r, errorContractSchema$1 as s, getUserId as t, getListQueryParams as u, createQueryParser as v, defineErrorMapper as w, MONGO_DIALECT as x, getHeader as y };
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { n as DomainEvent } from "./EventTransport-QmY7A258.mjs";
|
|
2
2
|
import { FastifyPluginAsync, FastifyRequest } from "fastify";
|
|
3
3
|
//#region src/plugins/health.d.ts
|
|
4
|
-
declare module "fastify" {
|
|
5
|
-
interface FastifyRequest {
|
|
6
|
-
_startTime?: number;
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
4
|
interface HealthCheck {
|
|
10
5
|
/** Name of the dependency */
|
|
11
6
|
name: string;
|
|
@@ -31,7 +26,7 @@ interface HealthOptions {
|
|
|
31
26
|
collectHttpMetrics?: boolean;
|
|
32
27
|
}
|
|
33
28
|
declare const healthPlugin: FastifyPluginAsync<HealthOptions>;
|
|
34
|
-
declare const _default$
|
|
29
|
+
declare const _default$5: FastifyPluginAsync<HealthOptions>;
|
|
35
30
|
//#endregion
|
|
36
31
|
//#region src/plugins/caching.d.ts
|
|
37
32
|
interface CachingRule {
|
|
@@ -59,7 +54,7 @@ interface CachingOptions {
|
|
|
59
54
|
rules?: CachingRule[];
|
|
60
55
|
}
|
|
61
56
|
declare const cachingPlugin: FastifyPluginAsync<CachingOptions>;
|
|
62
|
-
declare const _default$
|
|
57
|
+
declare const _default$4: FastifyPluginAsync<CachingOptions>;
|
|
63
58
|
//#endregion
|
|
64
59
|
//#region src/plugins/sse.d.ts
|
|
65
60
|
interface SSEOptions {
|
|
@@ -84,7 +79,46 @@ interface SSEOptions {
|
|
|
84
79
|
tokenQueryParam?: string | null;
|
|
85
80
|
}
|
|
86
81
|
declare const ssePlugin: FastifyPluginAsync<SSEOptions>;
|
|
87
|
-
declare const _default$
|
|
82
|
+
declare const _default$3: FastifyPluginAsync<SSEOptions>;
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/plugins/realtime.d.ts
|
|
85
|
+
declare const CHANGE_OPERATIONS: readonly ["created", "updated", "deleted"];
|
|
86
|
+
type ChangeOperation = (typeof CHANGE_OPERATIONS)[number];
|
|
87
|
+
interface RealtimeOptions {
|
|
88
|
+
/**
|
|
89
|
+
* Route path — must contain `:resource` (default: `/realtime/:resource`).
|
|
90
|
+
*/
|
|
91
|
+
path?: string;
|
|
92
|
+
/** Heartbeat interval in ms (default: 30000). */
|
|
93
|
+
heartbeat?: number;
|
|
94
|
+
/**
|
|
95
|
+
* Subscribable resources. Default: every registered resource — safe
|
|
96
|
+
* because each subscription runs that resource's own `list` permission;
|
|
97
|
+
* narrow it when only some resources should have a change feed at all.
|
|
98
|
+
*/
|
|
99
|
+
resources?: readonly string[];
|
|
100
|
+
/** Operations streamed (default: created + updated + deleted). */
|
|
101
|
+
operations?: readonly ChangeOperation[];
|
|
102
|
+
/**
|
|
103
|
+
* Query parameter carrying the bearer token for browser `EventSource`
|
|
104
|
+
* clients (default `'token'`, matching the sse plugin / arc-next).
|
|
105
|
+
* Set `null` to disable promotion.
|
|
106
|
+
*/
|
|
107
|
+
tokenQueryParam?: string | null;
|
|
108
|
+
/**
|
|
109
|
+
* Hard ceiling (ms) on any single connection's lifetime. Bounds
|
|
110
|
+
* permission STALENESS: the row filters are snapshotted at connect, so a
|
|
111
|
+
* caller whose permissions are revoked mid-connection keeps receiving
|
|
112
|
+
* their old view until they reconnect. Independently, arc ALWAYS closes
|
|
113
|
+
* the feed when the auth token's `exp` passes (forcing reconnect +
|
|
114
|
+
* re-authorization with fresh filters) — this option adds a cap for
|
|
115
|
+
* session/cookie auth that carries no `exp`, or to tighten below the
|
|
116
|
+
* token TTL. Omit for token-exp-only bounding.
|
|
117
|
+
*/
|
|
118
|
+
maxConnectionMs?: number;
|
|
119
|
+
}
|
|
120
|
+
declare const realtimePlugin: FastifyPluginAsync<RealtimeOptions>;
|
|
121
|
+
declare const _default$2: FastifyPluginAsync<RealtimeOptions>;
|
|
88
122
|
//#endregion
|
|
89
123
|
//#region src/plugins/metrics.d.ts
|
|
90
124
|
interface MetricsOptions {
|
|
@@ -153,4 +187,4 @@ declare module "fastify" {
|
|
|
153
187
|
declare const versioningPlugin: FastifyPluginAsync<VersioningOptions>;
|
|
154
188
|
declare const _default: FastifyPluginAsync<VersioningOptions>;
|
|
155
189
|
//#endregion
|
|
156
|
-
export {
|
|
190
|
+
export { healthPlugin as C, _default$5 as S, CachingRule as _, MetricsCollector as a, HealthCheck as b, metricsPlugin as c, _default$2 as d, realtimePlugin as f, CachingOptions as g, ssePlugin as h, MetricEntry as i, ChangeOperation as l, _default$3 as m, _default as n, MetricsOptions as o, SSEOptions as p, versioningPlugin as r, _default$1 as s, VersioningOptions as t, RealtimeOptions as u, _default$4 as v, HealthOptions as x, cachingPlugin as y };
|
package/llms.txt
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @classytic/arc
|
|
2
|
+
|
|
3
|
+
> Resource-oriented backend framework for Fastify. One `defineResource()` call =
|
|
4
|
+
> REST + validation + auth + permissions + events + caching + OpenAPI + MCP tools.
|
|
5
|
+
> DB-agnostic via @classytic/repo-core adapter kits (mongokit, sqlitekit, prismakit).
|
|
6
|
+
|
|
7
|
+
IMPORTANT for coding agents: hand-rolling is a bug in arc apps. Before writing any
|
|
8
|
+
route, validation, pagination, auth check, cron, queue worker, counter, or audit
|
|
9
|
+
code, check whether arc provides it — it almost certainly does:
|
|
10
|
+
|
|
11
|
+
- CRUD routes → defineResource({ name, adapter, permissions })
|
|
12
|
+
- Role/ownership checks → @classytic/arc/permissions (requireRoles, requireOwnership, permissionMatrix, requireQuota)
|
|
13
|
+
- Identity/tenant access → @classytic/arc/scope (getUserId, requireOrgId — never read scope fields directly)
|
|
14
|
+
- Body/response schemas → schemaOptions.fieldRules (customSchemas when wire ≠ model)
|
|
15
|
+
- Query filter/sort/page → the resource queryParser (allow-listed) + keyset cursors
|
|
16
|
+
- Soft delete/slug/tree/bulk/files/search → presets: [...]
|
|
17
|
+
- Recurring jobs → schedulesPlugin (@classytic/arc/plugins; LockAdapter leader safety)
|
|
18
|
+
- Durable queues → @classytic/arc/integrations/jobs (BullMQ/Redis) or @classytic/streamline (Mongo)
|
|
19
|
+
- Headless worker process→ createWorker(sameOptions) (@classytic/arc/factory)
|
|
20
|
+
- Usage counters/quotas → @classytic/arc/usage (usagePlugin, requireQuota) + rateLimit.plan
|
|
21
|
+
- Audit + record history → audit: true, history: true on the resource
|
|
22
|
+
- Idempotency → @classytic/arc/idempotency
|
|
23
|
+
- Events/outbox/webhooks → @classytic/arc/events, integrations/webhooks
|
|
24
|
+
- AI/MCP tools → generated from every resource (incl. _count/_exists/_distinct list verbs)
|
|
25
|
+
- App boot → createApp({ beforeBoot: connectDatabase, ... }) — DB connect goes IN beforeBoot
|
|
26
|
+
|
|
27
|
+
## Docs (inside this package)
|
|
28
|
+
|
|
29
|
+
- skills/arc/SKILL.md — full framework guide (boot, defineResource, presets, auth, testing)
|
|
30
|
+
- skills/arc/references/api-reference.md — every subpath import
|
|
31
|
+
- skills/arc-code-review/references/arc-cheatsheet.md — hand-rolled-code → arc-feature map
|
|
32
|
+
- skills/arc-code-review/SKILL.md — audit workflow for existing codebases
|
|
33
|
+
|
|
34
|
+
## Conventions that bite
|
|
35
|
+
|
|
36
|
+
- request.user is undefined on public routes — guard it.
|
|
37
|
+
- Custom endpoints go in the resource's routes:/actions: (inherit auth/OpenAPI/MCP);
|
|
38
|
+
bare fastify.get() bypasses everything.
|
|
39
|
+
- mongokit >=3.21 defaults schemaGenerator; schemaGenerator: false kills OpenAPI+MCP bodies.
|