@classytic/arc 2.21.0 → 2.22.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-C6FlRWxF.mjs} +1 -1
- package/dist/audit/index.d.mts +2 -2
- package/dist/auth/index.d.mts +30 -2
- package/dist/auth/index.mjs +5 -2
- package/dist/cli/commands/describe.d.mts +1 -1
- package/dist/cli/commands/docs.mjs +1 -1
- package/dist/cli/commands/init.mjs +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +2 -2
- package/dist/{core-DZ6Xe1jR.mjs → core-b6fgFgnd.mjs} +123 -66
- package/dist/{createActionRouter-BWMDW-dL.mjs → createActionRouter-h1cEEaEX.mjs} +9 -5
- package/dist/{createAggregationRouter-l5mNdYrZ.mjs → createAggregationRouter-B1C0kvTL.mjs} +3 -3
- package/dist/{createApp-Bi61XxqU.mjs → createApp-Ci7yG5gv.mjs} +242 -56
- 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-BTzXSwIg.mjs} +24 -3
- package/dist/{errorHandler-B0e-bq-O.d.mts → errorHandler-C6yv4ZTW.d.mts} +13 -0
- package/dist/factory/index.d.mts +29 -8
- package/dist/factory/index.mjs +34 -3
- package/dist/{fastify-augmentation-DafigGQp.d.mts → fastify-augmentation-9_fuetB4.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.mjs +2 -0
- package/dist/{types-DpxoNX5v.d.mts → index-BEu4wjbL.d.mts} +187 -66
- package/dist/{index-B5N-NaHs.d.mts → index-D8MKYGDa.d.mts} +3 -3
- package/dist/{index-Dtrj6XZk.d.mts → index-DbtgCOCj.d.mts} +1287 -1225
- package/dist/{index-B5PoNbfu.d.mts → index-ogIHvOjo.d.mts} +1 -1
- package/dist/index.d.mts +6 -5
- package/dist/index.mjs +3 -3
- package/dist/{init-0YhHkXGk.mjs → init-DleK3p9f.mjs} +118 -2
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +3 -3
- 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 +8 -4
- package/dist/integrations/webhooks.mjs +9 -5
- package/dist/jsonBody-BlzAoGCe.mjs +43 -0
- package/dist/logger/index.d.mts +26 -1
- package/dist/logger/index.mjs +39 -1
- package/dist/{mcpPlugin-B9XjjNVG.mjs → mcpPlugin-ByA2tf6D.mjs} +6 -2
- 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-BRpMZD7C.mjs} +2 -2
- package/dist/permissions/index.d.mts +3 -2
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/plugins/index.d.mts +22 -5
- package/dist/plugins/index.mjs +11 -280
- 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/index.d.mts +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/search.d.mts +2 -2
- package/dist/rateLimitKey-BoWRH3e7.mjs +14 -0
- package/dist/{registerRoute-oGAl0oA8.mjs → registerRoute-xHc42fwB.mjs} +37 -17
- package/dist/registry/index.d.mts +2 -2
- package/dist/requestId-5BhTVzBv.mjs +113 -0
- package/dist/schemaConverter-Ds5reSGs.mjs +168 -0
- package/dist/{schemaIR-ajetw3Fv.mjs → schemaIR-B-6SPe7g.mjs} +2 -2
- package/dist/scim/index.mjs +6 -7
- package/dist/scope/index.mjs +2 -76
- package/dist/scope-k15RXfcq.mjs +64 -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-Bc42CUyk.d.mts} +1 -1
- 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 +40 -18
- package/dist/utils/index.mjs +2 -2
- package/dist/{utils-CO8a3B_1.mjs → utils-FhJ88TJE.mjs} +59 -13
- package/dist/{versioning-DQ4mCvg0.d.mts → versioning-DLwklPlG.d.mts} +0 -5
- package/llms.txt +39 -0
- package/package.json +453 -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 +44 -2
- 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,6 +1,6 @@
|
|
|
1
1
|
import { r as CacheStore, t as CacheLogger } from "./interface-C1_WLTMK.mjs";
|
|
2
2
|
import { i as RequestScope, n as Mandate } from "./types-DH0GupI7.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "./types-Csxga7d3.mjs";
|
|
4
4
|
import { FastifyReply, FastifyRequest } from "fastify";
|
|
5
5
|
//#region src/permissions/agent.d.ts
|
|
6
6
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { $t as UserOrganization, A as RequestIdOptions, An as ArcCreateResult,
|
|
2
|
-
import {
|
|
3
|
-
import "./
|
|
4
|
-
import
|
|
5
|
-
import { A as
|
|
1
|
+
import { $t as UserOrganization, A as RequestIdOptions, An as ArcCreateResult, B as defineResource, Bt as RouteHandler, C as RequestContext, D as HealthCheck, E as GracefulShutdownOptions, F as FastifyWithDecorators, Fn as BaseControllerOptions, Ft as ControllerLike, H as CrudController, Ht as AuthPluginOptions, In as ControllerConfigurableOptions, Jt as ApiResponse, L as RequestWithExtras, Ln as ControllerConstructionOptions, Lt as IController, Mn as ArcGetResult, N as FastifyRequestExtras, Nn as ArcListResult, Nt as RateLimitConfig, O as HealthOptions, P as FastifyWithAuth, Pn as ArcUpdateResult, Q as MiddlewareConfig, Rn as ListResult, Rt as IControllerResponse, S as QueryParserInterface, T as CrudRouterOptions, U as ResourceConfig, V as ResourceDefinition, X as CrudRouteKey, Xt as JWTPayload, Y as PresetResult, Yt as ArcRequest, Z as CrudSchemas, a as InferAdapterDoc, an as SlugExt, c as TypedController, cn as BulkMixin, ct as AggMeasureShorthand, d as PaginationResult, dt as AggregationDateRangeRequirement, en as BaseController, et as RouteSchemaOptions, f as IntrospectionData, ft as AggregationIndexHint, g as ArcInternalMetadata, gt as AggregationsMap, h as ResourceMetadata, ht as AggregationRateLimit, i as ValidationResult, in as TreeMixin, jn as ArcDeleteResult, k as IntrospectionPluginOptions, l as TypedRepository, ln as BaseCrudController, lt as AggregationCacheConfig, m as RegistryStats, mt as AggregationMaterializedResult, n as ConfigError, nn as SoftDeleteMixin, nt as FieldRule, o as InferDocType, on as SlugMixin, ot as EventDefinition, p as RegistryEntry, pt as AggregationMaterializedContext, q as PresetFunction, qt as AnyRecord, r as ValidateOptions, rn as TreeExt, s as InferResourceDoc, sn as BulkExt, st as AggMeasureInput, t as RouteHandlerMethod, tn as SoftDeleteExt, u as TypedResourceConfig, ut as AggregationConfig, w as ServiceContext, y as OwnershipCheck, zt as IRequestContext } from "./index-DbtgCOCj.mjs";
|
|
2
|
+
import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "./types-Csxga7d3.mjs";
|
|
3
|
+
import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, t as FieldPermission } from "./fields-D3lhgzhD.mjs";
|
|
4
|
+
import "./fastify-augmentation-9_fuetB4.mjs";
|
|
5
|
+
import { A as HOOK_OPERATIONS, B as SYSTEM_FIELDS, C as CrudOperation, D as DEFAULT_SORT, E as DEFAULT_MAX_LIMIT, F as MAX_REGEX_LENGTH, I as MAX_SEARCH_LENGTH, L as MUTATION_OPERATIONS, M as HookOperation, N as HookPhase, O as DEFAULT_TENANT_FIELD, P as MAX_FILTER_DEPTH, R as MutationOperation, S as CRUD_OPERATIONS, T as DEFAULT_LIMIT, f as defineResourceVariants, g as mergeResourceConfig, h as SeamedResourceConfig, j as HOOK_PHASES, k as DEFAULT_UPDATE_METHOD, m as ResourceSeams, p as AdapterLike, s as getControllerScope, v as defineAction, w as DEFAULT_ID_FIELD, x as defineAggregation, z as RESERVED_QUERY_PARAMS } from "./index-D8MKYGDa.mjs";
|
|
6
|
+
import { A as requireOwnership, C as createOrgPermissions, D as denyAll, E as anyOf, N as when, S as createDynamicPermissionMatrix, T as allowPublic, b as DynamicPermissionMatrixConfig, c as publicReadAdminWrite, d as requireOrgMembership, f as requireOrgRole, h as requireTeamMembership, i as ownerWithAdminBypass, j as requireRoles, k as requireAuth, l as readOnly, m as requireServiceScope, n as authenticated, o as presets_d_exports, p as requireScopeContext, r as fullPublic, s as publicRead, t as adminOnly, u as requireOrgInScope, w as allOf, y as DynamicPermissionMatrix } from "./index-ogIHvOjo.mjs";
|
|
6
7
|
import { a as NotFoundError, d as ValidationError, f as createDomainError, i as ForbiddenError, t as ArcError, u as UnauthorizedError } from "./errors-DHcHVAgk.mjs";
|
|
7
8
|
//#region src/index.d.ts
|
|
8
9
|
declare const version: string;
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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-DNre0wRg.mjs";
|
|
2
2
|
import { d as createDomainError, i as NotFoundError, l as UnauthorizedError, r as ForbiddenError, t as ArcError, u as ValidationError } from "./errors-DkO8Nk6-.mjs";
|
|
3
|
-
import { a as BulkMixin, i as SlugMixin, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, t as BaseController } from "./BaseController-
|
|
3
|
+
import { a as BulkMixin, i as SlugMixin, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, t as BaseController } from "./BaseController-C6FlRWxF.mjs";
|
|
4
4
|
import { E as requireRoles, F as applyFieldReadPermissions, I as applyFieldWritePermissions, L as fields, O as when, S as denyAll, T as requireOwnership, _ as requireServiceScope, b as allowPublic, c as publicReadAdminWrite, d as createDynamicPermissionMatrix, f as createOrgPermissions, g as requireScopeContext, h as requireOrgRole, i as ownerWithAdminBypass, l as readOnly, m as requireOrgMembership, n as authenticated, o as presets_exports, p as requireOrgInScope, r as fullPublic, s as publicRead, t as adminOnly, v as requireTeamMembership, w as requireAuth, x as anyOf, y as allOf } from "./permissions-BJMuKMl7.mjs";
|
|
5
|
-
import { a as
|
|
5
|
+
import { a as defineResource, c as defineAction, d as defineAggregation, i as defineResourceVariants, o as ResourceDefinition, s as mergeResourceConfig } from "./core-b6fgFgnd.mjs";
|
|
6
6
|
import { l as getControllerScope } from "./actionPermissions-ze70xXJi.mjs";
|
|
7
7
|
//#region src/index.ts
|
|
8
|
-
const version = "2.
|
|
8
|
+
const version = "2.22.0";
|
|
9
9
|
//#endregion
|
|
10
10
|
export { ArcError, BaseController, BaseCrudController, BulkMixin, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, ForbiddenError, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, NotFoundError, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, SlugMixin, SoftDeleteMixin, TreeMixin, UnauthorizedError, ValidationError, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, authenticated, createDomainError, createDynamicPermissionMatrix, createOrgPermissions, defineAction, defineAggregation, defineResource, defineResourceVariants, denyAll, fields, fullPublic, getControllerScope, mergeResourceConfig, ownerWithAdminBypass, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, version, when };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
|
|
1
2
|
import * as fs from "node:fs/promises";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
import { dirname, join } from "node:path";
|
|
@@ -76,6 +77,60 @@ export function createAdapter${ts ? "<TDoc = unknown>" : ""}(
|
|
|
76
77
|
`;
|
|
77
78
|
}
|
|
78
79
|
//#endregion
|
|
80
|
+
//#region src/cli/commands/init/templates/agents.ts
|
|
81
|
+
function agentsGuideTemplate(config) {
|
|
82
|
+
return `# CLAUDE.md — agent guide for this app
|
|
83
|
+
|
|
84
|
+
> This file doubles as AGENTS.md — copy or symlink if your tool reads that name.
|
|
85
|
+
|
|
86
|
+
**This is an \`@classytic/arc\` application.** Resources are DECLARED, not hand-rolled:
|
|
87
|
+
one \`defineResource()\` = REST + validation + auth + permissions + events + caching +
|
|
88
|
+
OpenAPI + MCP tools. Data layer: ${config.adapter === "mongokit" ? "@classytic/mongokit (Mongoose)" : "a custom DataAdapter kit"}.
|
|
89
|
+
|
|
90
|
+
## The one rule
|
|
91
|
+
|
|
92
|
+
**Hand-rolling is a bug.** Before writing ANY route, validation, pagination, auth check,
|
|
93
|
+
cron, counter, or audit code by hand, prove arc lacks it — check the table below, then
|
|
94
|
+
\`node_modules/@classytic/arc/skills/arc/SKILL.md\` (full framework guide + references).
|
|
95
|
+
|
|
96
|
+
## About to write X? Arc already has Y
|
|
97
|
+
|
|
98
|
+
| If you're about to write… | Use instead |
|
|
99
|
+
|---|---|
|
|
100
|
+
| \`fastify.get/post/...\` CRUD routes for an entity | \`defineResource({ name, adapter, permissions })\` |
|
|
101
|
+
| \`if (req.user.role !== 'admin') return 403\` | \`permissions: { update: requireRoles(['admin']) }\` |
|
|
102
|
+
| Reading \`req.user._id\` / org id directly | \`getUserId(scope)\` / \`requireOrgId(scope)\` from \`@classytic/arc/scope\` |
|
|
103
|
+
| Hand-written \`schema: { body }\` / JSON Schema | \`schemaOptions.fieldRules\` (or \`customSchemas\` for wire≠model) |
|
|
104
|
+
| toJSON transforms hiding \`password\`/internals | \`fieldRules: { password: { hidden: true } }\` |
|
|
105
|
+
| Manual \`req.query\` filter/sort/pagination parsing | the resource's \`queryParser\` (allow-listed fields) |
|
|
106
|
+
| Soft delete / slug lookup / tree / bulk / file upload | \`presets: ['softDelete', 'slugLookup', ...]\` |
|
|
107
|
+
| \`setInterval\` sweeps + hand-rolled leader lock | \`schedulesPlugin\` (\`@classytic/arc/plugins\`) |
|
|
108
|
+
| A background/queue worker entrypoint | \`createWorker(sameOptions)\` (\`@classytic/arc/factory\`) |
|
|
109
|
+
| Usage counters / quotas / plan rate limits | \`usagePlugin\` + \`requireQuota\` + \`rateLimit.plan\` |
|
|
110
|
+
| Audit log rows / "who changed what" endpoints | \`audit: true\` + \`history: true\` on the resource |
|
|
111
|
+
| Manual idempotency keys / dedupe | \`idempotencyPlugin\` |
|
|
112
|
+
| Event emitters / webhooks plumbing | \`eventPlugin\` + resource \`events:\` (+ outbox for guarantees) |
|
|
113
|
+
| Custom MCP/AI tool handlers | generated automatically from every resource |
|
|
114
|
+
|
|
115
|
+
## Load-bearing conventions
|
|
116
|
+
|
|
117
|
+
- \`request.user\` is \`undefined\` on public routes — always guard.
|
|
118
|
+
- Never read \`scope.organizationId\` directly — use \`@classytic/arc/scope\` accessors.
|
|
119
|
+
- The DB connection belongs in \`createApp({ beforeBoot })\` — not before \`createApp\`.
|
|
120
|
+
- Custom endpoints: \`routes:\`/\`actions:\` on the resource (they inherit auth/permissions/
|
|
121
|
+
OpenAPI/MCP) — a bare \`fastify.get()\` gets none of that.
|
|
122
|
+
|
|
123
|
+
## Commands
|
|
124
|
+
|
|
125
|
+
\`\`\`bash
|
|
126
|
+
npm run dev # watch mode
|
|
127
|
+
npm test # vitest
|
|
128
|
+
npx arc generate resource <name> # scaffold a resource (model/repo/resource files)
|
|
129
|
+
npx arc describe # list registered resources + routes
|
|
130
|
+
\`\`\`
|
|
131
|
+
`;
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
79
134
|
//#region src/cli/commands/init/templates/app.ts
|
|
80
135
|
function indexTemplate(config) {
|
|
81
136
|
const ts = config.typescript;
|
|
@@ -442,8 +497,8 @@ function betterAuthSetupTemplate(config) {
|
|
|
442
497
|
import { mongodbAdapter } from '@better-auth/mongo-adapter';` : "";
|
|
443
498
|
const stubsImport = useStubs ? `import { registerBetterAuthStubs } from '@classytic/mongokit/better-auth';` : "";
|
|
444
499
|
const pluginImports = [
|
|
445
|
-
useOrg ? `import { organization } from 'better-auth/plugins';` : "",
|
|
446
|
-
useBearer ? `import { bearer } from 'better-auth/plugins';` : "",
|
|
500
|
+
useOrg ? `import { organization } from 'better-auth/plugins/organization';` : "",
|
|
501
|
+
useBearer ? `import { bearer } from 'better-auth/plugins/bearer';` : "",
|
|
447
502
|
useApiKey ? `import { apiKey } from '@better-auth/api-key';` : ""
|
|
448
503
|
].filter(Boolean).join("\n");
|
|
449
504
|
const dbAdapter = useMongo ? config.typescript ? `database: mongodbAdapter(mongoose.connection.getClient().db() as unknown as never),` : `database: mongodbAdapter(mongoose.connection.getClient().db()),` : `// Configure your database adapter here
|
|
@@ -985,6 +1040,11 @@ ${config.adapter === "mongokit" ? ` await mongoose.connection.collection('use
|
|
|
985
1040
|
* `installDependencies` (runs the package manager's `install` against
|
|
986
1041
|
* the declared ranges). One source — no drift.
|
|
987
1042
|
*/
|
|
1043
|
+
var dependency_plan_exports = /* @__PURE__ */ __exportAll({
|
|
1044
|
+
SCAFFOLD_DEP_VERSIONS: () => SCAFFOLD_DEP_VERSIONS,
|
|
1045
|
+
primeLatestScaffoldVersions: () => primeLatestScaffoldVersions,
|
|
1046
|
+
resolveScaffoldDependencies: () => resolveScaffoldDependencies
|
|
1047
|
+
});
|
|
988
1048
|
const SCAFFOLD_DEP_VERSIONS = {
|
|
989
1049
|
core: {
|
|
990
1050
|
"@classytic/arc": "^2.20.0",
|
|
@@ -1069,6 +1129,51 @@ function floorLessThan(a, b) {
|
|
|
1069
1129
|
* floor>` when the static pin's floor is BELOW the declared peer floor
|
|
1070
1130
|
* (never lowered — static pins may legitimately be ahead of the floor).
|
|
1071
1131
|
*/
|
|
1132
|
+
const latestCache = /* @__PURE__ */ new Map();
|
|
1133
|
+
function allScaffoldPackageNames() {
|
|
1134
|
+
const names = /* @__PURE__ */ new Set();
|
|
1135
|
+
for (const group of Object.values(SCAFFOLD_DEP_VERSIONS)) for (const name of Object.keys(group)) names.add(name);
|
|
1136
|
+
return [...names];
|
|
1137
|
+
}
|
|
1138
|
+
async function primeLatestScaffoldVersions(options) {
|
|
1139
|
+
const timeoutMs = options?.timeoutMs ?? 3500;
|
|
1140
|
+
const registry = (options?.registry ?? process.env.npm_config_registry ?? "https://registry.npmjs.org").replace(/\/$/, "");
|
|
1141
|
+
const names = allScaffoldPackageNames();
|
|
1142
|
+
const results = await Promise.allSettled(names.map(async (name) => {
|
|
1143
|
+
const res = await fetch(`${registry}/${name}/latest`, {
|
|
1144
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
1145
|
+
headers: { accept: "application/json" }
|
|
1146
|
+
});
|
|
1147
|
+
if (!res.ok) throw new Error(String(res.status));
|
|
1148
|
+
const body = await res.json();
|
|
1149
|
+
if (typeof body.version === "string" && /^\d+\.\d+\.\d+$/.test(body.version)) latestCache.set(name, body.version);
|
|
1150
|
+
}));
|
|
1151
|
+
return {
|
|
1152
|
+
resolved: latestCache.size,
|
|
1153
|
+
total: results.length
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
function parseBareVersion(v) {
|
|
1157
|
+
const m = /^(\d+)\.(\d+)\.(\d+)$/.exec(v);
|
|
1158
|
+
return m ? [
|
|
1159
|
+
Number(m[1]),
|
|
1160
|
+
Number(m[2]),
|
|
1161
|
+
Number(m[3])
|
|
1162
|
+
] : void 0;
|
|
1163
|
+
}
|
|
1164
|
+
function applyLatestOverlay(dependencies) {
|
|
1165
|
+
if (latestCache.size === 0) return;
|
|
1166
|
+
for (const [name, currentRange] of Object.entries(dependencies)) {
|
|
1167
|
+
const latest = latestCache.get(name);
|
|
1168
|
+
if (!latest || latest.includes("-")) continue;
|
|
1169
|
+
const latestV = parseBareVersion(latest);
|
|
1170
|
+
const currentFloor = parseFloor(currentRange);
|
|
1171
|
+
if (!latestV || !currentFloor) continue;
|
|
1172
|
+
if (!floorLessThan(currentFloor, latestV)) continue;
|
|
1173
|
+
if (latestV[0] !== currentFloor[0] && !name.startsWith("@classytic/")) continue;
|
|
1174
|
+
dependencies[name] = `^${latest}`;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1072
1177
|
function overlayLiveArcVersions(dependencies) {
|
|
1073
1178
|
const own = readOwnPackageJson();
|
|
1074
1179
|
if (!own) return;
|
|
@@ -1102,6 +1207,8 @@ function resolveScaffoldDependencies(config) {
|
|
|
1102
1207
|
}
|
|
1103
1208
|
if (config.adapter === "mongokit") Object.assign(dependencies, SCAFFOLD_DEP_VERSIONS.adapterMongokit);
|
|
1104
1209
|
if (config.typescript) Object.assign(devDependencies, SCAFFOLD_DEP_VERSIONS.devTypescript);
|
|
1210
|
+
applyLatestOverlay(dependencies);
|
|
1211
|
+
applyLatestOverlay(devDependencies);
|
|
1105
1212
|
overlayLiveArcVersions(dependencies);
|
|
1106
1213
|
return {
|
|
1107
1214
|
dependencies: sortByKey(dependencies),
|
|
@@ -3030,6 +3137,7 @@ async function createProjectStructure(projectPath, config) {
|
|
|
3030
3137
|
files["docker-compose.yml"] = dockerComposeTemplate(config);
|
|
3031
3138
|
}
|
|
3032
3139
|
if (config.edge) files["wrangler.toml"] = wranglerTemplate(config);
|
|
3140
|
+
files["CLAUDE.md"] = agentsGuideTemplate(config);
|
|
3033
3141
|
files[".arcrc"] = `${JSON.stringify({
|
|
3034
3142
|
adapter: config.adapter,
|
|
3035
3143
|
auth: config.auth,
|
|
@@ -3329,6 +3437,14 @@ async function init(options = {}) {
|
|
|
3329
3437
|
}
|
|
3330
3438
|
const packageManager = detectPackageManager();
|
|
3331
3439
|
console.log(`Using package manager: ${packageManager}\n`);
|
|
3440
|
+
if (!process.env.VITEST && process.env.ARC_INIT_OFFLINE !== "1") {
|
|
3441
|
+
const { primeLatestScaffoldVersions } = await Promise.resolve().then(() => dependency_plan_exports);
|
|
3442
|
+
const { resolved, total } = await primeLatestScaffoldVersions().catch(() => ({
|
|
3443
|
+
resolved: 0,
|
|
3444
|
+
total: 0
|
|
3445
|
+
}));
|
|
3446
|
+
console.log(resolved > 0 ? `Resolved ${resolved}/${total} dependency versions from npm (latest stable)\n` : "Registry unreachable — using pinned fallback versions\n");
|
|
3447
|
+
}
|
|
3332
3448
|
await createProjectStructure(projectPath, config);
|
|
3333
3449
|
if (!options.skipInstall) {
|
|
3334
3450
|
console.log("\n📥 Installing dependencies...\n");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { c as WebSocketClient, l as WebSocketMessage, u as WebSocketPluginOptions } from "../websocket-uuWqM6UY.mjs";
|
|
2
2
|
import { EventGatewayOptions } from "./event-gateway.mjs";
|
|
3
3
|
import { JobDefinition, JobDispatchOptions, JobDispatcher, JobMeta, JobsPluginOptions, QueueStats } from "./jobs.mjs";
|
|
4
|
-
import { c as McpAuthResult, d as PromptDefinition, g as ToolDefinition, h as ToolContext, l as McpPluginOptions, m as ToolAnnotations, n as CallToolResult, o as CrudOperation, r as CreateMcpServerConfig, t as BetterAuthHandler, u as McpResourceConfig } from "../types-
|
|
4
|
+
import { c as McpAuthResult, d as PromptDefinition, g as ToolDefinition, h as ToolContext, l as McpPluginOptions, m as ToolAnnotations, n as CallToolResult, o as CrudOperation, r as CreateMcpServerConfig, t as BetterAuthHandler, u as McpResourceConfig } from "../types-Bc42CUyk.mjs";
|
|
5
5
|
import { StreamlinePluginOptions, WorkflowLike, WorkflowRunLike } from "./streamline.mjs";
|
|
6
6
|
import { WebhookDeliveryRecord, WebhookManager, WebhookPluginOptions, WebhookStore, WebhookSubscription } from "./webhooks.mjs";
|
|
7
7
|
export type { BetterAuthHandler, CallToolResult, CreateMcpServerConfig, CrudOperation, EventGatewayOptions, JobDefinition, JobDispatchOptions, JobDispatcher, JobMeta, JobsPluginOptions, McpAuthResult, McpPluginOptions, McpResourceConfig, PromptDefinition, QueueStats, StreamlinePluginOptions, ToolAnnotations, ToolContext, ToolDefinition, WebSocketClient, WebSocketMessage, WebSocketPluginOptions, WebhookDeliveryRecord, WebhookManager, WebhookPluginOptions, WebhookStore, WebhookSubscription, WorkflowLike, WorkflowRunLike };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Rt as IControllerResponse, V as ResourceDefinition, zt as IRequestContext } from "../../index-DbtgCOCj.mjs";
|
|
2
2
|
import { i as RequestScope } from "../../types-DH0GupI7.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { a as CrudDescriptionOverride, c as McpAuthResult, d as PromptDefinition, f as PromptResult, g as ToolDefinition, h as ToolContext, i as CrudDescriptionMeta, l as McpPluginOptions, m as ToolAnnotations, n as CallToolResult, o as CrudOperation, p as SessionEntry, r as CreateMcpServerConfig, s as McpAuthResolver, t as BetterAuthHandler, u as McpResourceConfig } from "../../types-
|
|
3
|
+
import { t as PermissionCheck } from "../../types-Csxga7d3.mjs";
|
|
4
|
+
import { a as CrudDescriptionOverride, c as McpAuthResult, d as PromptDefinition, f as PromptResult, g as ToolDefinition, h as ToolContext, i as CrudDescriptionMeta, l as McpPluginOptions, m as ToolAnnotations, n as CallToolResult, o as CrudOperation, p as SessionEntry, r as CreateMcpServerConfig, s as McpAuthResolver, t as BetterAuthHandler, u as McpResourceConfig } from "../../types-Bc42CUyk.mjs";
|
|
5
5
|
import { ErrorContract } from "@classytic/repo-core/errors";
|
|
6
6
|
import { FastifyPluginAsync } from "fastify";
|
|
7
7
|
import { z } from "zod";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as defaultCrudDescription, c as mcpHandlerAdapter, d as toCallToolResult, f as toCallToolSuccess, h as resolveToolCollisions, i as fieldRulesToZod, l as permissionDeniedResult, m as createMcpServer, n as mcpPlugin, o as resolveCrudDescription, p as buildRequestContext, r as resourceToTools, s as invokeController, t as filterResourcesForMcp, u as toCallToolError } from "../../mcpPlugin-
|
|
1
|
+
import { a as defaultCrudDescription, c as mcpHandlerAdapter, d as toCallToolResult, f as toCallToolSuccess, h as resolveToolCollisions, i as fieldRulesToZod, l as permissionDeniedResult, m as createMcpServer, n as mcpPlugin, o as resolveCrudDescription, p as buildRequestContext, r as resourceToTools, s as invokeController, t as filterResourcesForMcp, u as toCallToolError } from "../../mcpPlugin-ByA2tf6D.mjs";
|
|
2
2
|
//#region src/integrations/mcp/defineTool.ts
|
|
3
3
|
/**
|
|
4
4
|
* Define a type-safe MCP tool.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as McpAuthResult, l as McpPluginOptions } from "../../types-
|
|
1
|
+
import { c as McpAuthResult, l as McpPluginOptions } from "../../types-Bc42CUyk.mjs";
|
|
2
2
|
//#region src/integrations/mcp/testing.d.ts
|
|
3
3
|
interface TestMcpClientOptions {
|
|
4
4
|
/** MCP plugin options (resources, overrides, etc.) — same as mcpPlugin config */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as createMcpServer, r as resourceToTools, t as filterResourcesForMcp } from "../../mcpPlugin-
|
|
1
|
+
import { m as createMcpServer, r as resourceToTools, t as filterResourcesForMcp } from "../../mcpPlugin-ByA2tf6D.mjs";
|
|
2
2
|
//#region src/integrations/mcp/testing.ts
|
|
3
3
|
/**
|
|
4
4
|
* @classytic/arc/mcp/testing — MCP Test Utilities
|
|
@@ -77,8 +77,9 @@ interface VerifySignatureOptions {
|
|
|
77
77
|
*
|
|
78
78
|
* ⚠ The `body` argument must be the exact bytes the sender signed. Fastify
|
|
79
79
|
* parses JSON bodies by default and the re-serialised object will NOT match
|
|
80
|
-
* the original signature. Register
|
|
81
|
-
*
|
|
80
|
+
* the original signature. Register `fastify-raw-body` (arc's createApp does
|
|
81
|
+
* this automatically with `global: false`) and opt the route in via
|
|
82
|
+
* `config: { rawBody: true }`, then pass `req.rawBody` here.
|
|
82
83
|
*
|
|
83
84
|
* @param body - Raw request body (string or Buffer — must be the exact bytes the sender signed)
|
|
84
85
|
* @param secret - Shared secret between sender and receiver
|
|
@@ -90,8 +91,11 @@ interface VerifySignatureOptions {
|
|
|
90
91
|
* ```typescript
|
|
91
92
|
* import { verifySignature } from '@classytic/arc/integrations/webhooks';
|
|
92
93
|
*
|
|
93
|
-
* // Arc-to-Arc (default headers + format)
|
|
94
|
-
* fastify
|
|
94
|
+
* // Arc-to-Arc (default headers + format). `config: { rawBody: true }` is
|
|
95
|
+
* // REQUIRED — arc registers fastify-raw-body with `global: false`, so
|
|
96
|
+
* // routes opt in per-route; without it `req.rawBody` is undefined and
|
|
97
|
+
* // verifySignature throws a TypeError.
|
|
98
|
+
* fastify.post('/webhooks/incoming', { config: { rawBody: true } }, async (req, reply) => {
|
|
95
99
|
* const sig = req.headers['x-webhook-signature'] as string;
|
|
96
100
|
* if (!verifySignature(req.rawBody, secret, sig)) {
|
|
97
101
|
* return reply.status(401).send({ error: 'Invalid signature' });
|
|
@@ -48,8 +48,9 @@ function signPayload(payload, secret) {
|
|
|
48
48
|
*
|
|
49
49
|
* ⚠ The `body` argument must be the exact bytes the sender signed. Fastify
|
|
50
50
|
* parses JSON bodies by default and the re-serialised object will NOT match
|
|
51
|
-
* the original signature. Register
|
|
52
|
-
*
|
|
51
|
+
* the original signature. Register `fastify-raw-body` (arc's createApp does
|
|
52
|
+
* this automatically with `global: false`) and opt the route in via
|
|
53
|
+
* `config: { rawBody: true }`, then pass `req.rawBody` here.
|
|
53
54
|
*
|
|
54
55
|
* @param body - Raw request body (string or Buffer — must be the exact bytes the sender signed)
|
|
55
56
|
* @param secret - Shared secret between sender and receiver
|
|
@@ -61,8 +62,11 @@ function signPayload(payload, secret) {
|
|
|
61
62
|
* ```typescript
|
|
62
63
|
* import { verifySignature } from '@classytic/arc/integrations/webhooks';
|
|
63
64
|
*
|
|
64
|
-
* // Arc-to-Arc (default headers + format)
|
|
65
|
-
* fastify
|
|
65
|
+
* // Arc-to-Arc (default headers + format). `config: { rawBody: true }` is
|
|
66
|
+
* // REQUIRED — arc registers fastify-raw-body with `global: false`, so
|
|
67
|
+
* // routes opt in per-route; without it `req.rawBody` is undefined and
|
|
68
|
+
* // verifySignature throws a TypeError.
|
|
69
|
+
* fastify.post('/webhooks/incoming', { config: { rawBody: true } }, async (req, reply) => {
|
|
66
70
|
* const sig = req.headers['x-webhook-signature'] as string;
|
|
67
71
|
* if (!verifySignature(req.rawBody, secret, sig)) {
|
|
68
72
|
* return reply.status(401).send({ error: 'Invalid signature' });
|
|
@@ -82,7 +86,7 @@ function signPayload(payload, secret) {
|
|
|
82
86
|
* ```
|
|
83
87
|
*/
|
|
84
88
|
function verifySignature(body, secret, signature, options) {
|
|
85
|
-
if (typeof body !== "string" && !Buffer.isBuffer(body)) throw new TypeError("verifySignature: body must be a string or Buffer (the exact bytes the sender signed).
|
|
89
|
+
if (typeof body !== "string" && !Buffer.isBuffer(body)) throw new TypeError("verifySignature: body must be a string or Buffer (the exact bytes the sender signed). Add `config: { rawBody: true }` to the route (arc registers fastify-raw-body with global: false) and pass req.rawBody — not req.body.");
|
|
86
90
|
if (!signature) return false;
|
|
87
91
|
const prefix = options?.prefix ?? "sha256=";
|
|
88
92
|
const algorithm = options?.algorithm ?? "sha256";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { t as ArcError } from "./errors-DkO8Nk6-.mjs";
|
|
2
|
+
import sjson from "secure-json-parse";
|
|
3
|
+
//#region src/utils/jsonBody.ts
|
|
4
|
+
/**
|
|
5
|
+
* Shared JSON request-body parsing for every arc content-type parser
|
|
6
|
+
* (`application/json`, `application/scim+json`, decrypted `application/jose`).
|
|
7
|
+
*
|
|
8
|
+
* One primitive, one contract:
|
|
9
|
+
* - empty body → `undefined` (DELETE/GET with `Content-Type: application/json`
|
|
10
|
+
* must not crash — the original reason arc replaces Fastify's parser)
|
|
11
|
+
* - prototype-poisoning payloads (`__proto__`, `constructor.prototype`)
|
|
12
|
+
* rejected via `secure-json-parse`, same protection Fastify's stock
|
|
13
|
+
* parser has
|
|
14
|
+
* - ANY parse failure → `ArcError` with `statusCode: 400` /
|
|
15
|
+
* `code: 'arc.bad_request'`. Client-sent bytes can never produce a 500:
|
|
16
|
+
* Fastify forwards parser errors to the error handler as-is, so an
|
|
17
|
+
* undecorated `SyntaxError` would fall through to the
|
|
18
|
+
* `arc.internal_error` fallback. The raw parser message stays on
|
|
19
|
+
* `cause` (logged, never on the wire).
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Parse a JSON request body with prototype-poisoning protection and the
|
|
23
|
+
* arc 400 error contract.
|
|
24
|
+
*
|
|
25
|
+
* @param raw - Body text (string or Buffer). Empty/absent → `undefined`.
|
|
26
|
+
* @param message - Wire-safe error message for parse failures
|
|
27
|
+
* (default: `"Invalid JSON payload"`).
|
|
28
|
+
*/
|
|
29
|
+
function parseJsonBody(raw, message = "Invalid JSON payload") {
|
|
30
|
+
const text = typeof raw === "string" ? raw : raw ? raw.toString("utf8") : "";
|
|
31
|
+
if (text.length === 0) return void 0;
|
|
32
|
+
try {
|
|
33
|
+
return sjson.parse(text);
|
|
34
|
+
} catch (cause) {
|
|
35
|
+
throw new ArcError(message, {
|
|
36
|
+
code: "arc.bad_request",
|
|
37
|
+
statusCode: 400,
|
|
38
|
+
cause
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { parseJsonBody as t };
|
package/dist/logger/index.d.mts
CHANGED
|
@@ -77,5 +77,30 @@ declare function configureArcLogger(options: ArcLoggerOptions): void;
|
|
|
77
77
|
* ```
|
|
78
78
|
*/
|
|
79
79
|
declare function arcLog(module: string): ArcLogger;
|
|
80
|
+
/**
|
|
81
|
+
* Minimal structural slice of a pino-style logger (`fastify.log`). Each
|
|
82
|
+
* level accepts `(msg)` or `(mergeObject, msg)` — the pino calling
|
|
83
|
+
* convention, which differs from console's variadic `(...args)`.
|
|
84
|
+
*/
|
|
85
|
+
interface PinoLike {
|
|
86
|
+
debug: (obj: unknown, msg?: string) => void;
|
|
87
|
+
info: (obj: unknown, msg?: string) => void;
|
|
88
|
+
warn: (obj: unknown, msg?: string) => void;
|
|
89
|
+
error: (obj: unknown, msg?: string) => void;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Bridge an `ArcLogWriter` onto a pino-style logger (`fastify.log`).
|
|
93
|
+
*
|
|
94
|
+
* arcLog call sites use the console convention — positional args like
|
|
95
|
+
* `log.warn("message", { userId })` — which pino would silently drop
|
|
96
|
+
* (extra args are printf interpolation values there). The bridge folds
|
|
97
|
+
* string args into the message, merges object args into the pino merge
|
|
98
|
+
* object, and maps `Error` instances to `{ err }` so pino's error
|
|
99
|
+
* serializer applies.
|
|
100
|
+
*
|
|
101
|
+
* `createApp` installs this automatically so arc-internal warnings flow
|
|
102
|
+
* through the host's transports, level, and redaction config.
|
|
103
|
+
*/
|
|
104
|
+
declare function createPinoWriter(logger: PinoLike): ArcLogWriter;
|
|
80
105
|
//#endregion
|
|
81
|
-
export { ArcLogWriter, ArcLogger, ArcLoggerOptions, arcLog, configureArcLogger };
|
|
106
|
+
export { ArcLogWriter, ArcLogger, ArcLoggerOptions, PinoLike, arcLog, configureArcLogger, createPinoWriter };
|
package/dist/logger/index.mjs
CHANGED
|
@@ -44,6 +44,44 @@ function arcLog(module) {
|
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Bridge an `ArcLogWriter` onto a pino-style logger (`fastify.log`).
|
|
49
|
+
*
|
|
50
|
+
* arcLog call sites use the console convention — positional args like
|
|
51
|
+
* `log.warn("message", { userId })` — which pino would silently drop
|
|
52
|
+
* (extra args are printf interpolation values there). The bridge folds
|
|
53
|
+
* string args into the message, merges object args into the pino merge
|
|
54
|
+
* object, and maps `Error` instances to `{ err }` so pino's error
|
|
55
|
+
* serializer applies.
|
|
56
|
+
*
|
|
57
|
+
* `createApp` installs this automatically so arc-internal warnings flow
|
|
58
|
+
* through the host's transports, level, and redaction config.
|
|
59
|
+
*/
|
|
60
|
+
function createPinoWriter(logger) {
|
|
61
|
+
const emit = (level) => (...args) => {
|
|
62
|
+
const parts = [];
|
|
63
|
+
let merge;
|
|
64
|
+
for (const arg of args) if (typeof arg === "string") parts.push(arg);
|
|
65
|
+
else if (arg instanceof Error) merge = {
|
|
66
|
+
...merge ?? {},
|
|
67
|
+
err: arg
|
|
68
|
+
};
|
|
69
|
+
else if (arg !== null && typeof arg === "object") merge = {
|
|
70
|
+
...merge ?? {},
|
|
71
|
+
...arg
|
|
72
|
+
};
|
|
73
|
+
else parts.push(String(arg));
|
|
74
|
+
const msg = parts.join(" ");
|
|
75
|
+
if (merge) logger[level](merge, msg);
|
|
76
|
+
else logger[level](msg);
|
|
77
|
+
};
|
|
78
|
+
return {
|
|
79
|
+
debug: emit("debug"),
|
|
80
|
+
info: emit("info"),
|
|
81
|
+
warn: emit("warn"),
|
|
82
|
+
error: emit("error")
|
|
83
|
+
};
|
|
84
|
+
}
|
|
47
85
|
function getWriter() {
|
|
48
86
|
return globalOptions.writer ?? console;
|
|
49
87
|
}
|
|
@@ -68,4 +106,4 @@ function isSuppressed() {
|
|
|
68
106
|
return env === "1" || env === "true";
|
|
69
107
|
}
|
|
70
108
|
//#endregion
|
|
71
|
-
export { arcLog, configureArcLogger };
|
|
109
|
+
export { arcLog, configureArcLogger, createPinoWriter };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { p as isArcError, t as ArcError } from "./errors-DkO8Nk6-.mjs";
|
|
2
2
|
import { c as getOrgId, g as getUserId } from "./types-bHblZ9YN.mjs";
|
|
3
|
-
import { t as BaseController } from "./BaseController-
|
|
3
|
+
import { t as BaseController } from "./BaseController-C6FlRWxF.mjs";
|
|
4
4
|
import { P as normalizePermissionResult } from "./permissions-BJMuKMl7.mjs";
|
|
5
5
|
import { t as executePipeline } from "./pipe-BOLmGIxa.mjs";
|
|
6
6
|
import { i as resolvePipelineSteps, t as resolveActionPermission } from "./actionPermissions-ze70xXJi.mjs";
|
|
7
7
|
import { n as validateAggregations } from "./validate-C2mGgSXg.mjs";
|
|
8
8
|
import { n as executeAggregation } from "./buildHandler-D_2ULWxZ.mjs";
|
|
9
9
|
import { t as pluralize } from "./pluralize-BhrgwZb9.mjs";
|
|
10
|
-
import { r as shouldRejectAdditionalProperties, t as normalizeSchemaIR } from "./schemaIR-
|
|
10
|
+
import { r as shouldRejectAdditionalProperties, t as normalizeSchemaIR } from "./schemaIR-B-6SPe7g.mjs";
|
|
11
11
|
import { createHash, randomUUID } from "node:crypto";
|
|
12
12
|
import { isHttpError, toErrorContract } from "@classytic/repo-core/errors";
|
|
13
13
|
import fp from "fastify-plugin";
|
|
@@ -630,6 +630,7 @@ function defaultCrudDescription(op, displayName, softDelete, queryMeta) {
|
|
|
630
630
|
if (queryMeta?.filterableFields?.length) parts.push(`Filterable fields: ${queryMeta.filterableFields.join(", ")}.`);
|
|
631
631
|
if (queryMeta?.allowedOperators?.length) parts.push(`Filter operators: ${queryMeta.allowedOperators.join(", ")} (use field[op]=value syntax).`);
|
|
632
632
|
if (queryMeta?.sortableFields?.length) parts.push(`Sortable fields: ${queryMeta.sortableFields.join(", ")}.`);
|
|
633
|
+
parts.push("Set _count: true for a count-only result, _exists: true for a boolean existence check, or _distinct: '<field>' for distinct values — all honor the same filters.");
|
|
633
634
|
return parts.join(" ");
|
|
634
635
|
}
|
|
635
636
|
case "get": return `Get a single ${singular} by ID`;
|
|
@@ -772,6 +773,9 @@ function buildListShape(fieldRules, options) {
|
|
|
772
773
|
const { filterableFields = [], hiddenFields = [], extraHideFields = [], allowedOperators } = options;
|
|
773
774
|
const allHidden = /* @__PURE__ */ new Set([...hiddenFields, ...extraHideFields]);
|
|
774
775
|
const shape = { ...PAGINATION_SHAPE };
|
|
776
|
+
shape._count = z.boolean().optional().describe("Return only { count } of records matching the filters — no documents fetched. Cheapest way to answer 'how many'.");
|
|
777
|
+
shape._exists = z.boolean().optional().describe("Return only whether ANY record matches the filters (boolean existence check).");
|
|
778
|
+
shape._distinct = z.string().optional().describe("Return the distinct values of this field across records matching the filters.");
|
|
775
779
|
if (!fieldRules) return shape;
|
|
776
780
|
for (const name of filterableFields) {
|
|
777
781
|
if (allHidden.has(name)) continue;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as MiddlewareHandler, L as RequestWithExtras, Q as MiddlewareConfig } from "../index-
|
|
1
|
+
import { I as MiddlewareHandler, L as RequestWithExtras, Q as MiddlewareConfig } from "../index-DbtgCOCj.mjs";
|
|
2
2
|
import { RouteHandlerMethod } from "fastify";
|
|
3
3
|
//#region src/middleware/middleware.d.ts
|
|
4
4
|
interface NamedMiddleware {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as ErrorMapper } from "./errorHandler-
|
|
1
|
+
import { n as ErrorMapper } from "./errorHandler-C6yv4ZTW.mjs";
|
|
2
2
|
import { FastifyInstance } from "fastify";
|
|
3
3
|
//#region src/factory/loadResources.d.ts
|
|
4
4
|
/**
|
|
@@ -306,6 +306,31 @@ interface ArcModule<TExports = unknown> {
|
|
|
306
306
|
* ```
|
|
307
307
|
*/
|
|
308
308
|
bootstrap?: (fastify: FastifyInstance) => TExports | Promise<TExports>;
|
|
309
|
+
/**
|
|
310
|
+
* App-level resource NAMES this module authoritatively SUPERSEDES. When the
|
|
311
|
+
* host also lists (or `resourceDir`-discovers) a resource of the same name,
|
|
312
|
+
* arc DROPS the app copy and registers THIS module's version instead — so the
|
|
313
|
+
* host keeps NO hand-maintained "which resources did modules take over" filter
|
|
314
|
+
* set. Ownership lives on the atom that provides it (colocated, drift-proof):
|
|
315
|
+
*
|
|
316
|
+
* ```ts
|
|
317
|
+
* defineModule({ name: "order", owns: ["order", "quotation", "rfq"], resources: () => [...] })
|
|
318
|
+
* ```
|
|
319
|
+
*
|
|
320
|
+
* Semantics:
|
|
321
|
+
* - Purely a supersede-the-app-fork switch — it filters the *app* resource
|
|
322
|
+
* list, never the module's own `resources` (those always register).
|
|
323
|
+
* - Static + declarative: read at compose time, so it works regardless of
|
|
324
|
+
* whether `resources` is an array or a post-bootstrap factory (no early
|
|
325
|
+
* factory resolution, no boot-order coupling).
|
|
326
|
+
* - Idempotent + tolerant: an `owns` entry with no matching app resource is
|
|
327
|
+
* a silent no-op — a module may pre-declare a name before any fork exists.
|
|
328
|
+
* - Collected across ALL modules; the app-side supersession is their union.
|
|
329
|
+
*
|
|
330
|
+
* Contract: if you `owns` a name, PROVIDE it (in this module's `resources`).
|
|
331
|
+
* Dropping the app fork without supplying a replacement removes the route.
|
|
332
|
+
*/
|
|
333
|
+
readonly owns?: readonly string[];
|
|
309
334
|
/**
|
|
310
335
|
* The module's resources. Array or factory — the factory form runs AFTER all
|
|
311
336
|
* bootstraps, so `defineResource(...)` receives fully-booted engines. Flows
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as getUserRoles } from "./types-XTApa8b6.mjs";
|
|
2
|
-
import { n as convertRouteSchema } from "./schemaConverter-
|
|
2
|
+
import { n as convertRouteSchema } from "./schemaConverter-Ds5reSGs.mjs";
|
|
3
3
|
import { t as resolveActionPermission } from "./actionPermissions-ze70xXJi.mjs";
|
|
4
4
|
import { t as pluralize } from "./pluralize-BhrgwZb9.mjs";
|
|
5
|
-
import { t as buildActionBodySchema } from "./createActionRouter-
|
|
5
|
+
import { t as buildActionBodySchema } from "./createActionRouter-h1cEEaEX.mjs";
|
|
6
6
|
import fp from "fastify-plugin";
|
|
7
7
|
//#region src/docs/openapi/canonical-schemas.ts
|
|
8
8
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import {
|
|
1
|
+
import { a as getUserRoles, i as UserBase, n as PermissionContext, o as normalizeRoles, r as PermissionResult, t as PermissionCheck } from "../types-Csxga7d3.mjs";
|
|
2
|
+
import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission } from "../fields-D3lhgzhD.mjs";
|
|
3
|
+
import { A as requireOwnership, B as requireMandate, C as createOrgPermissions, D as denyAll, E as anyOf, F as normalizePermissionResult, I as RequireAgentScopeOptions, L as RequireMandateOptions, M as roles, N as when, O as not, P as applyPermissionResult, R as requireAgentScope, S as createDynamicPermissionMatrix, T as allowPublic, _ as createRoleHierarchy, a as permissionMatrix, b as DynamicPermissionMatrixConfig, c as publicReadAdminWrite, d as requireOrgMembership, f as requireOrgRole, g as RoleHierarchy, h as requireTeamMembership, i as ownerWithAdminBypass, j as requireRoles, k as requireAuth, l as readOnly, m as requireServiceScope, n as authenticated, o as presets_d_exports, p as requireScopeContext, r as fullPublic, s as publicRead, t as adminOnly, u as requireOrgInScope, v as ConnectEventsOptions, w as allOf, x as PermissionEventBus, y as DynamicPermissionMatrix, z as requireDPoP } from "../index-ogIHvOjo.mjs";
|
|
3
4
|
export { type ConnectEventsOptions, type DynamicPermissionMatrix, type DynamicPermissionMatrixConfig, type FieldPermission, type FieldPermissionMap, type FieldPermissionType, type PermissionCheck, type PermissionContext, type PermissionEventBus, type PermissionResult, type RequireAgentScopeOptions, type RequireMandateOptions, type RoleHierarchy, type UserBase, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, permissionMatrix, presets_d_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAgentScope, requireAuth, requireDPoP, requireMandate, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ct as PipelineStep, Rt as IControllerResponse, St as PipelineContext, _t as Guard, bt as OperationFilter, vt as Interceptor, wt as Transform, xt as PipelineConfig, yt as NextFunction } from "../index-DbtgCOCj.mjs";
|
|
2
2
|
//#region src/pipeline/guard.d.ts
|
|
3
3
|
interface GuardOptions {
|
|
4
4
|
operations?: OperationFilter;
|