@classytic/arc 2.1.2 → 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{EventTransport-BD2U0BTc.d.mts → EventTransport-BkUDYZEb.d.mts} +1 -2
- package/dist/HookSystem-BsGV-j2l.mjs +1 -2
- package/dist/{ResourceRegistry-DsN4KJjV.mjs → ResourceRegistry-7Ic20ZMw.mjs} +1 -2
- package/dist/adapters/index.d.mts +4 -4
- package/dist/audit/index.d.mts +5 -6
- package/dist/audit/index.mjs +2 -3
- package/dist/audit/mongodb.d.mts +4 -4
- package/dist/audit/mongodb.mjs +1 -1
- package/dist/{audited-C3T5DTUx.mjs → audited-CGdLiSlE.mjs} +1 -2
- package/dist/auth/index.d.mts +6 -7
- package/dist/auth/index.mjs +10 -16
- package/dist/auth/redis-session.d.mts +2 -3
- package/dist/auth/redis-session.mjs +1 -2
- package/dist/{betterAuthOpenApi-BrHKeSAx.mjs → betterAuthOpenApi-DjWDddNc.mjs} +2 -3
- package/dist/cache/index.d.mts +3 -4
- package/dist/cache/index.mjs +4 -5
- package/dist/{caching-Bl28lYsR.mjs → caching-GSDJcA6-.mjs} +1 -2
- package/dist/{circuitBreaker-DeY4FCjs.mjs → circuitBreaker-DYhWBW_D.mjs} +1 -2
- package/dist/cli/commands/describe.d.mts +1 -2
- package/dist/cli/commands/describe.mjs +1 -2
- package/dist/cli/commands/docs.d.mts +1 -2
- package/dist/cli/commands/docs.mjs +3 -4
- package/dist/cli/commands/generate.d.mts +1 -2
- package/dist/cli/commands/generate.mjs +2 -3
- package/dist/cli/commands/init.d.mts +1 -2
- package/dist/cli/commands/init.mjs +6 -7
- package/dist/cli/commands/introspect.d.mts +1 -2
- package/dist/cli/commands/introspect.mjs +2 -3
- package/dist/cli/index.d.mts +1 -2
- package/dist/cli/index.mjs +1 -2
- package/dist/constants-DdXFXQtN.mjs +1 -2
- package/dist/core/index.d.mts +4 -4
- package/dist/core/index.mjs +1 -1
- package/dist/{createApp-CUgNqegw.mjs → createApp-D2D5XXaV.mjs} +9 -10
- package/dist/{defineResource-k0_BDn8v.mjs → defineResource-PXzSJ15_.mjs} +11 -11
- package/dist/discovery/index.d.mts +1 -2
- package/dist/discovery/index.mjs +1 -2
- package/dist/docs/index.d.mts +5 -6
- package/dist/docs/index.mjs +5 -4
- package/dist/{elevation-B_2dRLVP.d.mts → elevation-DGo5shaX.d.mts} +1 -2
- package/dist/{elevation-BRy3yFWT.mjs → elevation-DSTbVvYj.mjs} +4 -4
- package/dist/{errorHandler-C1okiriz.mjs → errorHandler-C3GY3_ow.mjs} +2 -3
- package/dist/{errorHandler-BbcgBmIH.d.mts → errorHandler-CW3OOeYq.d.mts} +2 -3
- package/dist/{errors-ChKiFz62.d.mts → errors-DAWRdiYP.d.mts} +1 -2
- package/dist/{errors-B9bZok84.mjs → errors-DBANPbGr.mjs} +1 -2
- package/dist/{eventPlugin-DGR_B2on.mjs → eventPlugin-BEOvaDqo.mjs} +2 -3
- package/dist/{eventPlugin-CTrLH3mt.d.mts → eventPlugin-H6wDDjGO.d.mts} +2 -3
- package/dist/events/index.d.mts +4 -5
- package/dist/events/index.mjs +2 -3
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +1 -2
- package/dist/events/transports/redis.d.mts +2 -3
- package/dist/events/transports/redis.mjs +1 -2
- package/dist/{externalPaths-DlINfKbP.d.mts → externalPaths-SyPF2tgK.d.mts} +1 -2
- package/dist/factory/index.d.mts +8 -9
- package/dist/factory/index.mjs +1 -1
- package/dist/{fastifyAdapter-BkrGrlFi.d.mts → fastifyAdapter-C8DlE0YH.d.mts} +4 -5
- package/dist/{fields-DyaDVX4J.d.mts → fields-Bi_AVKSo.d.mts} +2 -3
- package/dist/{fields-iagOozy0.mjs → fields-CTd_CrKr.mjs} +2 -3
- package/dist/hooks/index.d.mts +3 -3
- package/dist/idempotency/index.d.mts +4 -5
- package/dist/idempotency/index.mjs +1 -2
- package/dist/idempotency/mongodb.d.mts +1 -1
- package/dist/idempotency/mongodb.mjs +1 -2
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/idempotency/redis.mjs +1 -2
- package/dist/index.d.mts +9 -10
- package/dist/index.mjs +7 -8
- package/dist/integrations/event-gateway.d.mts +2 -3
- package/dist/integrations/event-gateway.mjs +2 -3
- package/dist/integrations/jobs.d.mts +1 -2
- package/dist/integrations/jobs.mjs +1 -2
- package/dist/integrations/streamline.d.mts +1 -2
- package/dist/integrations/streamline.mjs +1 -2
- package/dist/integrations/websocket.d.mts +1 -2
- package/dist/integrations/websocket.mjs +1 -2
- package/dist/{interface-B01JvPVc.d.mts → interface-CSNjltAc.d.mts} +1 -2
- package/dist/{interface-CZe8IkMf.d.mts → interface-DTbsvIWe.d.mts} +1 -2
- package/dist/{interface-Ch8HU9uM.d.mts → interface-e9XfSsUV.d.mts} +3 -4
- package/dist/{introspectionPlugin-rFdO8ZUa.mjs → introspectionPlugin-B3JkrjwU.mjs} +1 -2
- package/dist/{keys-BqNejWup.mjs → keys-DhqDRxv3.mjs} +1 -2
- package/dist/{logger-Df2O2WsW.mjs → logger-ByrvQWZO.mjs} +1 -2
- package/dist/{memory-cQgelFOj.mjs → memory-B2v7KrCB.mjs} +1 -2
- package/dist/migrations/index.d.mts +1 -2
- package/dist/migrations/index.mjs +1 -2
- package/dist/{mongodb-CGzRbfAK.d.mts → mongodb-ClykrfGo.d.mts} +2 -3
- package/dist/{mongodb-BfJVlUJH.mjs → mongodb-DNKEExbf.mjs} +1 -2
- package/dist/{mongodb-JN-9JA7K.d.mts → mongodb-Dg8O_gvd.d.mts} +2 -3
- package/dist/{openapi-G3Cw7XuM.mjs → openapi-9nB_kiuR.mjs} +5 -4
- package/dist/org/index.d.mts +4 -5
- package/dist/org/index.mjs +1 -2
- package/dist/org/types.d.mts +1 -2
- package/dist/permissions/index.d.mts +5 -6
- package/dist/permissions/index.mjs +7 -7
- package/dist/plugins/index.d.mts +7 -8
- package/dist/plugins/index.mjs +7 -8
- package/dist/plugins/response-cache.d.mts +1 -2
- package/dist/plugins/response-cache.mjs +2 -3
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -2
- package/dist/{pluralize-CEweyOEm.mjs → pluralize-CM-jZg7p.mjs} +1 -2
- package/dist/policies/index.d.mts +4 -5
- package/dist/policies/index.mjs +1 -2
- package/dist/presets/index.d.mts +4 -5
- package/dist/presets/index.mjs +2 -3
- package/dist/presets/multiTenant.d.mts +4 -5
- package/dist/presets/multiTenant.mjs +1 -2
- package/dist/{presets-DzSMwlKj.d.mts → presets-BTeYbw7h.d.mts} +2 -3
- package/dist/{presets-BITljm96.mjs → presets-CeFtfDR8.mjs} +1 -2
- package/dist/{prisma-Dg9GoVdj.d.mts → prisma-C3iornoK.d.mts} +2 -3
- package/dist/prisma-DJbMt3yf.mjs +1 -2
- package/dist/{queryCachePlugin-DMBnp2Q0.mjs → queryCachePlugin-B6R0d4av.mjs} +4 -5
- package/dist/{queryCachePlugin-7THaI5mt.d.mts → queryCachePlugin-Q6SYuHZ6.d.mts} +2 -3
- package/dist/{redis-D-JAeLtm.d.mts → redis-UwjEp8Ea.d.mts} +2 -3
- package/dist/{redis-stream-Bdh_vUU8.d.mts → redis-stream-CBg0upHI.d.mts} +2 -3
- package/dist/registry/index.d.mts +4 -5
- package/dist/registry/index.mjs +2 -2
- package/dist/{requestContext-QQD6ROJc.mjs → requestContext-xi6OKBL-.mjs} +1 -2
- package/dist/{schemaConverter-BwrmWroW.mjs → schemaConverter-Dtg0Kt9T.mjs} +1 -2
- package/dist/schemas/index.d.mts +1 -2
- package/dist/schemas/index.mjs +1 -2
- package/dist/scope/index.d.mts +2 -3
- package/dist/scope/index.mjs +2 -3
- package/dist/{sessionManager-jPKLbHE0.d.mts → sessionManager-D_iEHjQl.d.mts} +1 -2
- package/dist/{sse-B3c3_yZp.mjs → sse-DkqQ1uxb.mjs} +2 -3
- package/dist/testing/index.d.mts +8 -9
- package/dist/testing/index.mjs +3 -4
- package/dist/{tracing-Cc7vVQPp.d.mts → tracing-8CEbhF0w.d.mts} +1 -2
- package/dist/{typeGuards-DhMNLuvU.mjs → typeGuards-DwxA1t_L.mjs} +1 -2
- package/dist/types/index.d.mts +6 -7
- package/dist/types/index.mjs +1 -2
- package/dist/{types-CIgB7UUl.d.mts → types-B0dhNrnd.d.mts} +9 -10
- package/dist/types-Beqn1Un7.mjs +1 -2
- package/dist/types-DelU6kln.mjs +25 -0
- package/dist/{types-aYB4V7uN.d.mts → types-RLkFVgaw.d.mts} +18 -4
- package/dist/utils/index.d.mts +5 -6
- package/dist/utils/index.mjs +4 -4
- package/package.json +1 -1
- package/dist/EventTransport-BD2U0BTc.d.mts.map +0 -1
- package/dist/HookSystem-BsGV-j2l.mjs.map +0 -1
- package/dist/ResourceRegistry-DsN4KJjV.mjs.map +0 -1
- package/dist/audit/index.d.mts.map +0 -1
- package/dist/audit/index.mjs.map +0 -1
- package/dist/audited-C3T5DTUx.mjs.map +0 -1
- package/dist/auth/index.d.mts.map +0 -1
- package/dist/auth/index.mjs.map +0 -1
- package/dist/auth/redis-session.d.mts.map +0 -1
- package/dist/auth/redis-session.mjs.map +0 -1
- package/dist/betterAuthOpenApi-BrHKeSAx.mjs.map +0 -1
- package/dist/cache/index.d.mts.map +0 -1
- package/dist/cache/index.mjs.map +0 -1
- package/dist/caching-Bl28lYsR.mjs.map +0 -1
- package/dist/circuitBreaker-DeY4FCjs.mjs.map +0 -1
- package/dist/cli/commands/describe.d.mts.map +0 -1
- package/dist/cli/commands/describe.mjs.map +0 -1
- package/dist/cli/commands/docs.d.mts.map +0 -1
- package/dist/cli/commands/docs.mjs.map +0 -1
- package/dist/cli/commands/generate.d.mts.map +0 -1
- package/dist/cli/commands/generate.mjs.map +0 -1
- package/dist/cli/commands/init.d.mts.map +0 -1
- package/dist/cli/commands/init.mjs.map +0 -1
- package/dist/cli/commands/introspect.d.mts.map +0 -1
- package/dist/cli/commands/introspect.mjs.map +0 -1
- package/dist/cli/index.d.mts.map +0 -1
- package/dist/cli/index.mjs.map +0 -1
- package/dist/constants-DdXFXQtN.mjs.map +0 -1
- package/dist/createApp-CUgNqegw.mjs.map +0 -1
- package/dist/defineResource-k0_BDn8v.mjs.map +0 -1
- package/dist/discovery/index.d.mts.map +0 -1
- package/dist/discovery/index.mjs.map +0 -1
- package/dist/docs/index.d.mts.map +0 -1
- package/dist/docs/index.mjs.map +0 -1
- package/dist/elevation-BRy3yFWT.mjs.map +0 -1
- package/dist/elevation-B_2dRLVP.d.mts.map +0 -1
- package/dist/errorHandler-BbcgBmIH.d.mts.map +0 -1
- package/dist/errorHandler-C1okiriz.mjs.map +0 -1
- package/dist/errors-B9bZok84.mjs.map +0 -1
- package/dist/errors-ChKiFz62.d.mts.map +0 -1
- package/dist/eventPlugin-CTrLH3mt.d.mts.map +0 -1
- package/dist/eventPlugin-DGR_B2on.mjs.map +0 -1
- package/dist/events/index.d.mts.map +0 -1
- package/dist/events/index.mjs.map +0 -1
- package/dist/events/transports/redis-stream-entry.mjs.map +0 -1
- package/dist/events/transports/redis.d.mts.map +0 -1
- package/dist/events/transports/redis.mjs.map +0 -1
- package/dist/externalPaths-DlINfKbP.d.mts.map +0 -1
- package/dist/factory/index.d.mts.map +0 -1
- package/dist/fastifyAdapter-BkrGrlFi.d.mts.map +0 -1
- package/dist/fields-DyaDVX4J.d.mts.map +0 -1
- package/dist/fields-iagOozy0.mjs.map +0 -1
- package/dist/idempotency/index.d.mts.map +0 -1
- package/dist/idempotency/index.mjs.map +0 -1
- package/dist/idempotency/mongodb.mjs.map +0 -1
- package/dist/idempotency/redis.mjs.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/integrations/event-gateway.d.mts.map +0 -1
- package/dist/integrations/event-gateway.mjs.map +0 -1
- package/dist/integrations/jobs.d.mts.map +0 -1
- package/dist/integrations/jobs.mjs.map +0 -1
- package/dist/integrations/streamline.d.mts.map +0 -1
- package/dist/integrations/streamline.mjs.map +0 -1
- package/dist/integrations/websocket.d.mts.map +0 -1
- package/dist/integrations/websocket.mjs.map +0 -1
- package/dist/interface-B01JvPVc.d.mts.map +0 -1
- package/dist/interface-CZe8IkMf.d.mts.map +0 -1
- package/dist/interface-Ch8HU9uM.d.mts.map +0 -1
- package/dist/introspectionPlugin-rFdO8ZUa.mjs.map +0 -1
- package/dist/keys-BqNejWup.mjs.map +0 -1
- package/dist/logger-Df2O2WsW.mjs.map +0 -1
- package/dist/memory-cQgelFOj.mjs.map +0 -1
- package/dist/migrations/index.d.mts.map +0 -1
- package/dist/migrations/index.mjs.map +0 -1
- package/dist/mongodb-BfJVlUJH.mjs.map +0 -1
- package/dist/mongodb-CGzRbfAK.d.mts.map +0 -1
- package/dist/mongodb-JN-9JA7K.d.mts.map +0 -1
- package/dist/openapi-G3Cw7XuM.mjs.map +0 -1
- package/dist/org/index.d.mts.map +0 -1
- package/dist/org/index.mjs.map +0 -1
- package/dist/org/types.d.mts.map +0 -1
- package/dist/permissions/index.d.mts.map +0 -1
- package/dist/permissions/index.mjs.map +0 -1
- package/dist/plugins/index.d.mts.map +0 -1
- package/dist/plugins/index.mjs.map +0 -1
- package/dist/plugins/response-cache.d.mts.map +0 -1
- package/dist/plugins/response-cache.mjs.map +0 -1
- package/dist/plugins/tracing-entry.mjs.map +0 -1
- package/dist/pluralize-CEweyOEm.mjs.map +0 -1
- package/dist/policies/index.d.mts.map +0 -1
- package/dist/policies/index.mjs.map +0 -1
- package/dist/presets/index.d.mts.map +0 -1
- package/dist/presets/index.mjs.map +0 -1
- package/dist/presets/multiTenant.d.mts.map +0 -1
- package/dist/presets/multiTenant.mjs.map +0 -1
- package/dist/presets-BITljm96.mjs.map +0 -1
- package/dist/presets-DzSMwlKj.d.mts.map +0 -1
- package/dist/prisma-DJbMt3yf.mjs.map +0 -1
- package/dist/prisma-Dg9GoVdj.d.mts.map +0 -1
- package/dist/queryCachePlugin-7THaI5mt.d.mts.map +0 -1
- package/dist/queryCachePlugin-DMBnp2Q0.mjs.map +0 -1
- package/dist/redis-D-JAeLtm.d.mts.map +0 -1
- package/dist/redis-stream-Bdh_vUU8.d.mts.map +0 -1
- package/dist/registry/index.d.mts.map +0 -1
- package/dist/requestContext-QQD6ROJc.mjs.map +0 -1
- package/dist/schemaConverter-BwrmWroW.mjs.map +0 -1
- package/dist/schemas/index.d.mts.map +0 -1
- package/dist/schemas/index.mjs.map +0 -1
- package/dist/scope/index.d.mts.map +0 -1
- package/dist/scope/index.mjs.map +0 -1
- package/dist/sessionManager-jPKLbHE0.d.mts.map +0 -1
- package/dist/sse-B3c3_yZp.mjs.map +0 -1
- package/dist/testing/index.d.mts.map +0 -1
- package/dist/testing/index.mjs.map +0 -1
- package/dist/tracing-Cc7vVQPp.d.mts.map +0 -1
- package/dist/typeGuards-DhMNLuvU.mjs.map +0 -1
- package/dist/types/index.d.mts.map +0 -1
- package/dist/types/index.mjs.map +0 -1
- package/dist/types-Beqn1Un7.mjs.map +0 -1
- package/dist/types-CIgB7UUl.d.mts.map +0 -1
- package/dist/types-aYB4V7uN.d.mts.map +0 -1
- package/dist/utils/index.d.mts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schemaConverter-BwrmWroW.mjs","names":[],"sources":["../src/utils/schemaConverter.ts"],"sourcesContent":["/**\n * Schema Converter — Detect-First, Convert-Only-When-Needed\n *\n * Converts Zod v4 schemas to JSON Schema using Zod's native `z.toJSONSchema()`.\n * Plain JSON Schema objects pass through with zero overhead.\n *\n * Zod is an **optional** peer dependency — loaded lazily at module init.\n * If Zod is not installed, Zod schemas pass through unconverted with a warning.\n *\n * @example\n * ```typescript\n * import { toJsonSchema } from '@classytic/arc/utils';\n *\n * // Zod v4 schema → auto-converted via z.toJSONSchema()\n * const schema = toJsonSchema(z.object({ name: z.string() }));\n *\n * // Plain JSON Schema → passes through as-is\n * const same = toJsonSchema({ type: 'object', properties: { name: { type: 'string' } } });\n * ```\n */\n\nimport type { OpenApiSchemas } from '../types/index.js';\n\n// ============================================================================\n// Lazy Zod Import — loaded once at module init, only if installed\n// ============================================================================\n\ntype ToJSONSchemaFn = (schema: unknown, opts?: unknown) => Record<string, unknown>;\nlet _toJSONSchema: ToJSONSchemaFn | null = null;\n\n// Fire-and-forget: resolve Zod at module load (async but non-blocking).\n// By the time any route handler calls toJsonSchema(), the promise will have settled.\n// Safe for both ESM and CJS (no top-level await).\nimport('zod')\n .then(({ z }) => {\n if (typeof z?.toJSONSchema === 'function') {\n _toJSONSchema = (schema, opts) =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n z.toJSONSchema(schema as any, opts as any) as Record<string, unknown>;\n }\n })\n .catch(() => {\n // Zod not installed — schema conversion will pass through Zod objects as-is\n });\n\n// ============================================================================\n// Detection — O(1) checks\n// ============================================================================\n\n/**\n * Check if an object is already a plain JSON Schema.\n * Returns true if it has JSON Schema markers (`type`, `properties`, `$ref`,\n * `allOf`, `anyOf`, `oneOf`, `items`, `enum`) and does NOT have Zod markers.\n */\nexport function isJsonSchema(input: unknown): input is Record<string, unknown> {\n if (input === null || typeof input !== 'object') return false;\n const obj = input as Record<string, unknown>;\n\n // Zod markers — if present, this is a Zod schema, not JSON Schema\n if ('_def' in obj || '_zod' in obj) return false;\n\n // JSON Schema markers\n return (\n 'type' in obj ||\n 'properties' in obj ||\n '$ref' in obj ||\n 'allOf' in obj ||\n 'anyOf' in obj ||\n 'oneOf' in obj ||\n 'items' in obj ||\n 'enum' in obj\n );\n}\n\n/**\n * Check if an object is a Zod schema (has `_zod` marker from Zod v4).\n */\nexport function isZodSchema(input: unknown): boolean {\n return input !== null && typeof input === 'object' && '_zod' in (input as Record<string, unknown>);\n}\n\n// ============================================================================\n// Converter\n// ============================================================================\n\n/**\n * Convert any schema input to JSON Schema.\n *\n * Detection order:\n * 1. `null`/`undefined` → `undefined`\n * 2. Already JSON Schema → pass through as-is (zero overhead)\n * 3. Zod v4 schema → `z.toJSONSchema(schema, { target: 'openapi-3.0' })`\n * 4. Unrecognized object → return as-is (treat as opaque schema)\n */\nexport function toJsonSchema(input: unknown): Record<string, unknown> | undefined {\n if (input == null) return undefined;\n if (typeof input !== 'object') return undefined;\n\n // Fast path: already a plain JSON Schema → passthrough\n if (isJsonSchema(input)) return input as Record<string, unknown>;\n\n // Zod v4 schema → native conversion\n if (isZodSchema(input)) {\n if (!_toJSONSchema) {\n // Zod not installed but a Zod schema was passed — can't convert\n console.warn(\n '[Arc] Zod schema detected but zod is not installed. ' +\n 'Install zod v4: npm install zod'\n );\n return input as Record<string, unknown>;\n }\n try {\n return _toJSONSchema(input, { target: 'openapi-3.0' });\n } catch {\n return { type: 'object' };\n }\n }\n\n // Unrecognized — return as-is (don't break opaque schemas)\n return input as Record<string, unknown>;\n}\n\n// ============================================================================\n// Batch Converters\n// ============================================================================\n\n/**\n * Convert all schema fields in an OpenApiSchemas object.\n * JSON Schema values pass through unchanged. Only Zod schemas are converted.\n */\nexport function convertOpenApiSchemas(schemas: OpenApiSchemas): OpenApiSchemas {\n const result: OpenApiSchemas = {};\n const schemaFields = ['entity', 'createBody', 'updateBody', 'params', 'listQuery', 'response'] as const;\n\n for (const field of schemaFields) {\n const value = schemas[field];\n if (value !== undefined) {\n result[field] = toJsonSchema(value) ?? value;\n }\n }\n\n // Copy any extra fields as-is\n for (const [key, value] of Object.entries(schemas)) {\n if (!schemaFields.includes(key as typeof schemaFields[number])) {\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/**\n * Convert schema values in a Fastify route schema record.\n *\n * Handles `body`, `querystring`, `params`, `headers` (top-level conversion)\n * and `response` (iterates by status code — each value converted individually).\n *\n * JSON Schema values pass through unchanged. Only Zod schemas are converted.\n *\n * Used for both additionalRoutes and customSchemas (CRUD overrides).\n */\nexport function convertRouteSchema(schema: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = { ...schema };\n\n // Convert top-level schema fields (body, querystring, params, headers)\n for (const field of ['body', 'querystring', 'params', 'headers'] as const) {\n if (result[field] !== undefined) {\n result[field] = toJsonSchema(result[field]) ?? result[field];\n }\n }\n\n // Convert response schemas (keyed by status code, e.g. { 200: zodSchema, 201: zodSchema })\n if (result.response !== undefined && typeof result.response === 'object' && result.response !== null) {\n const responseObj = result.response as Record<string, unknown>;\n const convertedResponse: Record<string, unknown> = {};\n for (const [statusCode, responseSchema] of Object.entries(responseObj)) {\n convertedResponse[statusCode] = toJsonSchema(responseSchema) ?? responseSchema;\n }\n result.response = convertedResponse;\n }\n\n return result;\n}\n"],"mappings":";AA4BA,IAAI,gBAAuC;AAK3C,OAAO,OACJ,MAAM,EAAE,QAAQ;AACf,KAAI,OAAO,GAAG,iBAAiB,WAC7B,kBAAiB,QAAQ,SAEvB,EAAE,aAAa,QAAe,KAAY;EAE9C,CACD,YAAY,GAEX;;;;;;AAWJ,SAAgB,aAAa,OAAkD;AAC7E,KAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;CACxD,MAAM,MAAM;AAGZ,KAAI,UAAU,OAAO,UAAU,IAAK,QAAO;AAG3C,QACE,UAAU,OACV,gBAAgB,OAChB,UAAU,OACV,WAAW,OACX,WAAW,OACX,WAAW,OACX,WAAW,OACX,UAAU;;;;;AAOd,SAAgB,YAAY,OAAyB;AACnD,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,UAAW;;;;;;;;;;;AAgBnE,SAAgB,aAAa,OAAqD;AAChF,KAAI,SAAS,KAAM,QAAO;AAC1B,KAAI,OAAO,UAAU,SAAU,QAAO;AAGtC,KAAI,aAAa,MAAM,CAAE,QAAO;AAGhC,KAAI,YAAY,MAAM,EAAE;AACtB,MAAI,CAAC,eAAe;AAElB,WAAQ,KACN,sFAED;AACD,UAAO;;AAET,MAAI;AACF,UAAO,cAAc,OAAO,EAAE,QAAQ,eAAe,CAAC;UAChD;AACN,UAAO,EAAE,MAAM,UAAU;;;AAK7B,QAAO;;;;;;AAWT,SAAgB,sBAAsB,SAAyC;CAC7E,MAAM,SAAyB,EAAE;CACjC,MAAM,eAAe;EAAC;EAAU;EAAc;EAAc;EAAU;EAAa;EAAW;AAE9F,MAAK,MAAM,SAAS,cAAc;EAChC,MAAM,QAAQ,QAAQ;AACtB,MAAI,UAAU,OACZ,QAAO,SAAS,aAAa,MAAM,IAAI;;AAK3C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAChD,KAAI,CAAC,aAAa,SAAS,IAAmC,CAC5D,QAAO,OAAO;AAIlB,QAAO;;;;;;;;;;;;AAaT,SAAgB,mBAAmB,QAA0D;CAC3F,MAAM,SAAkC,EAAE,GAAG,QAAQ;AAGrD,MAAK,MAAM,SAAS;EAAC;EAAQ;EAAe;EAAU;EAAU,CAC9D,KAAI,OAAO,WAAW,OACpB,QAAO,SAAS,aAAa,OAAO,OAAO,IAAI,OAAO;AAK1D,KAAI,OAAO,aAAa,UAAa,OAAO,OAAO,aAAa,YAAY,OAAO,aAAa,MAAM;EACpG,MAAM,cAAc,OAAO;EAC3B,MAAM,oBAA6C,EAAE;AACrD,OAAK,MAAM,CAAC,YAAY,mBAAmB,OAAO,QAAQ,YAAY,CACpE,mBAAkB,cAAc,aAAa,eAAe,IAAI;AAElE,SAAO,WAAW;;AAGpB,QAAO"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/schemas/index.ts"],"mappings":";;;;;;;;;iBA+CgB,eAAA,WAA0B,SAAA,CAAA,CAAS,UAAA,EAAY,CAAA,sBAAC,OAAA;WAAA,kBAAA,CAAA,QAAA;;;;;;;;;AAgBhE;;;AAAA,iBAAgB,eAAA,WAA0B,SAAA,CAAA,CAAS,UAAA,EAAY,CAAA,sBAAC,OAAA;WAAA,kBAAA,CAAA,QAAA;;;;;;iBAUhD,mBAAA,WAA8B,SAAA,CAAA,CAAS,UAAA,EAAY,CAAA,sBAAC,OAAA;WAAA,kBAAA,CAAA,QAAA;;;;;;;iBAWpD,iBAAA,CAAA,sBAAiB,OAAA;WAAA,kBAAA,CAAA,QAAA;;;;;;iBAUjB,gBAAA,CAAA,sBAAgB,OAAA;WAAA,kBAAA,CAAA,QAAA;;;;;;;;;iBAiBhB,kBAAA,CAAA,sBAAkB,OAAA;qCAAA,kBAAA,CAAA,QAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["Type"],"sources":["../../src/schemas/index.ts"],"sourcesContent":["/**\n * Arc Schema Utilities — TypeBox Integration\n *\n * Provides type-safe schema definitions for Fastify routes using TypeBox.\n * Install `@sinclair/typebox` and `@fastify/type-provider-typebox` to use.\n *\n * @example\n * ```typescript\n * import { Type, ArcListResponse, ArcPaginationQuery } from '@classytic/arc/schemas';\n *\n * const ItemSchema = Type.Object({\n * _id: Type.String(),\n * name: Type.String(),\n * createdAt: Type.String({ format: 'date-time' }),\n * });\n *\n * // Use in route definitions\n * fastify.get('/items', {\n * schema: {\n * querystring: ArcPaginationQuery(),\n * response: { 200: ArcListResponse(ItemSchema) },\n * },\n * }, handler);\n * ```\n *\n * @module\n */\n\n// Re-export TypeBox core — users import Type from here instead of @sinclair/typebox directly\nexport { Type } from '@sinclair/typebox';\nexport type { Static, TSchema, TObject } from '@sinclair/typebox';\n\n// Re-export Fastify TypeBox type provider\nexport { TypeBoxValidatorCompiler } from '@fastify/type-provider-typebox';\nexport type { TypeBoxTypeProvider, FastifyPluginAsyncTypebox, FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';\n\nimport { Type } from '@sinclair/typebox';\nimport type { TSchema } from '@sinclair/typebox';\n\n// ============================================================================\n// Arc Response Schemas (TypeBox versions of responseSchemas.ts)\n// ============================================================================\n\n/**\n * Paginated list response — matches Arc's runtime format:\n * `{ success, docs: [...], page, limit, total, pages, hasNext, hasPrev }`\n */\nexport function ArcListResponse<T extends TSchema>(itemSchema: T) {\n return Type.Object({\n success: Type.Boolean(),\n docs: Type.Array(itemSchema),\n page: Type.Integer(),\n limit: Type.Integer(),\n total: Type.Integer(),\n pages: Type.Integer(),\n hasNext: Type.Boolean(),\n hasPrev: Type.Boolean(),\n });\n}\n\n/**\n * Single item response — `{ success, data: {...} }`\n */\nexport function ArcItemResponse<T extends TSchema>(itemSchema: T) {\n return Type.Object({\n success: Type.Boolean(),\n data: itemSchema,\n });\n}\n\n/**\n * Mutation (create/update) response — `{ success, data: {...}, message? }`\n */\nexport function ArcMutationResponse<T extends TSchema>(itemSchema: T) {\n return Type.Object({\n success: Type.Boolean(),\n data: itemSchema,\n message: Type.Optional(Type.String()),\n });\n}\n\n/**\n * Delete response — `{ success, message }`\n */\nexport function ArcDeleteResponse() {\n return Type.Object({\n success: Type.Boolean(),\n message: Type.Optional(Type.String()),\n });\n}\n\n/**\n * Error response schema\n */\nexport function ArcErrorResponse() {\n return Type.Object({\n success: Type.Literal(false),\n error: Type.String(),\n code: Type.Optional(Type.String()),\n message: Type.Optional(Type.String()),\n });\n}\n\n// ============================================================================\n// Arc Query Schemas\n// ============================================================================\n\n/**\n * Standard pagination + sorting + filtering query parameters.\n * Matches Arc's list endpoint conventions.\n */\nexport function ArcPaginationQuery() {\n return Type.Object({\n page: Type.Optional(Type.Integer({ minimum: 1, default: 1 })),\n limit: Type.Optional(Type.Integer({ minimum: 1, maximum: 100, default: 20 })),\n sort: Type.Optional(Type.String()),\n select: Type.Optional(Type.String()),\n populate: Type.Optional(Type.String()),\n });\n}\n"],"mappings":";;;;;;;;AA+CA,SAAgB,gBAAmC,YAAe;AAChE,QAAOA,OAAK,OAAO;EACjB,SAASA,OAAK,SAAS;EACvB,MAAMA,OAAK,MAAM,WAAW;EAC5B,MAAMA,OAAK,SAAS;EACpB,OAAOA,OAAK,SAAS;EACrB,OAAOA,OAAK,SAAS;EACrB,OAAOA,OAAK,SAAS;EACrB,SAASA,OAAK,SAAS;EACvB,SAASA,OAAK,SAAS;EACxB,CAAC;;;;;AAMJ,SAAgB,gBAAmC,YAAe;AAChE,QAAOA,OAAK,OAAO;EACjB,SAASA,OAAK,SAAS;EACvB,MAAM;EACP,CAAC;;;;;AAMJ,SAAgB,oBAAuC,YAAe;AACpE,QAAOA,OAAK,OAAO;EACjB,SAASA,OAAK,SAAS;EACvB,MAAM;EACN,SAASA,OAAK,SAASA,OAAK,QAAQ,CAAC;EACtC,CAAC;;;;;AAMJ,SAAgB,oBAAoB;AAClC,QAAOA,OAAK,OAAO;EACjB,SAASA,OAAK,SAAS;EACvB,SAASA,OAAK,SAASA,OAAK,QAAQ,CAAC;EACtC,CAAC;;;;;AAMJ,SAAgB,mBAAmB;AACjC,QAAOA,OAAK,OAAO;EACjB,SAASA,OAAK,QAAQ,MAAM;EAC5B,OAAOA,OAAK,QAAQ;EACpB,MAAMA,OAAK,SAASA,OAAK,QAAQ,CAAC;EAClC,SAASA,OAAK,SAASA,OAAK,QAAQ,CAAC;EACtC,CAAC;;;;;;AAWJ,SAAgB,qBAAqB;AACnC,QAAOA,OAAK,OAAO;EACjB,MAAMA,OAAK,SAASA,OAAK,QAAQ;GAAE,SAAS;GAAG,SAAS;GAAG,CAAC,CAAC;EAC7D,OAAOA,OAAK,SAASA,OAAK,QAAQ;GAAE,SAAS;GAAG,SAAS;GAAK,SAAS;GAAI,CAAC,CAAC;EAC7E,MAAMA,OAAK,SAASA,OAAK,QAAQ,CAAC;EAClC,QAAQA,OAAK,SAASA,OAAK,QAAQ,CAAC;EACpC,UAAUA,OAAK,SAASA,OAAK,QAAQ,CAAC;EACvC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/scope/resolveOrgFromHeader.ts"],"mappings":";;;;UA2BiB,2BAAA;EAcN;EAZT,MAAA;EAaW;EAXX,iBAAA,GAAoB,MAAA,UAAgB,KAAA,aAAkB,OAAA;IAAU,KAAA;EAAA;AAAA;;;;;;;iBASlD,oBAAA,CACd,OAAA,EAAS,2BAAA,IACP,OAAA,EAAS,cAAA,EAAgB,KAAA,EAAO,YAAA,KAAiB,OAAA"}
|
package/dist/scope/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/scope/resolveOrgFromHeader.ts"],"sourcesContent":["/**\n * Resolve Org Scope from Header\n *\n * Utility hook for JWT/custom auth apps that use `x-organization-id` header\n * to select an organization. Better Auth apps don't need this — org context\n * comes from the session automatically.\n *\n * **Important:** This hook reads `request.user` and `request.scope`, which\n * are populated by the auth `preHandler`. Register it as a `preHandler`\n * (not `onRequest`) so it runs after authentication:\n *\n * @example\n * ```typescript\n * import { resolveOrgFromHeader } from '@classytic/arc/scope';\n *\n * app.addHook('preHandler', resolveOrgFromHeader({\n * resolveMembership: async (userId, orgId) => {\n * const member = await MemberModel.findOne({ userId, orgId });\n * return member ? { roles: member.roles } : null;\n * },\n * }));\n * ```\n */\n\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport type { RequestScope } from './types.js';\n\nexport interface ResolveOrgFromHeaderOptions {\n /** Header name (default: 'x-organization-id') */\n header?: string;\n /** Resolve user's membership in the org. Return roles or null if not a member. */\n resolveMembership: (userId: string, orgId: string) => Promise<{ roles: string[] } | null>;\n}\n\n/**\n * Create a preHandler hook that resolves org scope from a header.\n * Must run AFTER authentication so `request.user` is populated.\n * If the header is present and user is a member, sets `request.scope` to `member`.\n * If the header is absent, scope stays as-is (typically `authenticated`).\n */\nexport function resolveOrgFromHeader(\n options: ResolveOrgFromHeaderOptions,\n): (request: FastifyRequest, reply: FastifyReply) => Promise<void> {\n const { header = 'x-organization-id', resolveMembership } = options;\n\n return async (request: FastifyRequest, reply: FastifyReply): Promise<void> => {\n const orgId = request.headers[header] as string | undefined;\n if (!orgId) return; // No org header — scope stays as auth adapter set it\n\n const scope = request.scope;\n if (!scope || scope.kind === 'public') {\n reply.code(401).send({\n success: false,\n error: 'Unauthorized',\n message: 'Authentication required for organization access',\n code: 'ORG_AUTH_REQUIRED',\n });\n return;\n }\n\n // Already elevated — don't downgrade\n if (scope.kind === 'elevated') return;\n\n const user = request.user;\n if (!user) {\n reply.code(401).send({\n success: false,\n error: 'Unauthorized',\n message: 'Authentication required for organization access',\n code: 'ORG_AUTH_REQUIRED',\n });\n return;\n }\n\n const userId = String(user.id ?? user._id ?? '');\n if (!userId) {\n reply.code(401).send({\n success: false,\n error: 'Unauthorized',\n message: 'User identity required for organization access',\n });\n return;\n }\n\n const membership = await resolveMembership(userId, orgId);\n if (!membership) {\n reply.code(403).send({\n success: false,\n error: 'Forbidden',\n message: 'Not a member of this organization',\n code: 'ORG_ACCESS_DENIED',\n });\n return;\n }\n\n request.scope = {\n kind: 'member',\n organizationId: orgId,\n orgRoles: membership.roles,\n } satisfies RequestScope;\n };\n}\n"],"mappings":";;;;;;;;;;AAwCA,SAAgB,qBACd,SACiE;CACjE,MAAM,EAAE,SAAS,qBAAqB,sBAAsB;AAE5D,QAAO,OAAO,SAAyB,UAAuC;EAC5E,MAAM,QAAQ,QAAQ,QAAQ;AAC9B,MAAI,CAAC,MAAO;EAEZ,MAAM,QAAQ,QAAQ;AACtB,MAAI,CAAC,SAAS,MAAM,SAAS,UAAU;AACrC,SAAM,KAAK,IAAI,CAAC,KAAK;IACnB,SAAS;IACT,OAAO;IACP,SAAS;IACT,MAAM;IACP,CAAC;AACF;;AAIF,MAAI,MAAM,SAAS,WAAY;EAE/B,MAAM,OAAO,QAAQ;AACrB,MAAI,CAAC,MAAM;AACT,SAAM,KAAK,IAAI,CAAC,KAAK;IACnB,SAAS;IACT,OAAO;IACP,SAAS;IACT,MAAM;IACP,CAAC;AACF;;EAGF,MAAM,SAAS,OAAO,KAAK,MAAM,KAAK,OAAO,GAAG;AAChD,MAAI,CAAC,QAAQ;AACX,SAAM,KAAK,IAAI,CAAC,KAAK;IACnB,SAAS;IACT,OAAO;IACP,SAAS;IACV,CAAC;AACF;;EAGF,MAAM,aAAa,MAAM,kBAAkB,QAAQ,MAAM;AACzD,MAAI,CAAC,YAAY;AACf,SAAM,KAAK,IAAI,CAAC,KAAK;IACnB,SAAS;IACT,OAAO;IACP,SAAS;IACT,MAAM;IACP,CAAC;AACF;;AAGF,UAAQ,QAAQ;GACd,MAAM;GACN,gBAAgB;GAChB,UAAU,WAAW;GACtB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sessionManager-jPKLbHE0.d.mts","names":[],"sources":["../src/auth/sessionManager.ts"],"mappings":";;;;;;UA+CiB,WAAA;EAyBL;EAvBV,MAAA;EAyBA;EAvBA,SAAA;EAuBgC;EArBhC,SAAA;EAqBkE;EAnBlE,SAAA;EAyBe;EAvBf,QAAA,GAAW,MAAA;AAAA;;;;;UAOI,YAAA;EA0Bf;EAxBA,GAAA,CAAI,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAwB1B;EAtBN,GAAA,CAAI,SAAA,UAAmB,IAAA,EAAM,WAAA,GAAc,OAAA;EA4BP;EA1BpC,MAAA,CAAO,SAAA,WAAoB,OAAA;EAwCE;EAtC7B,SAAA,CAAU,MAAA,WAAiB,OAAA;EA0BpB;EAxBP,eAAA,CAAgB,MAAA,UAAgB,gBAAA,WAA2B,OAAA;AAAA;;;;UAM5C,oBAAA;EA8BN;EA5BT,MAAA;EA4B6B;EA1B7B,QAAA;EAgCmC;EA9BnC,QAAA;EAgCQ;EA9BR,IAAA;EAgC+C;EA9B/C,MAAA;AAAA;;;;UAMe,qBAAA;EAwBS;EAtBxB,KAAA,EAAO,YAAA;EAsBwC;EApB/C,MAAA;EAoBgE;EAlBhE,MAAA;EAkBuE;EAhBvE,SAAA;EAiBD;EAfC,QAAA;EAwB0B;EAtB1B,UAAA;EAsBkE;EApBlE,MAAA,GAAS,oBAAA;AAAA;;;;UAMM,oBAAA;EA6B4B;EA3B3C,MAAA,EAAQ,kBAAA;EAiCe;EA/BvB,YAAA,GAAe,OAAA,EAAS,cAAA,EAAgB,KAAA,EAAO,YAAA,KAAiB,OAAA;AAAA;AAAA;EAAA,UAQtD,eAAA;IAEO;IAAf,YAAA,GAAe,OAAA,EAAS,cAAA,EAAgB,KAAA,EAAO,YAAA,KAAiB,OAAA;IAAxB;IAExC,cAAA;MAAA,sCAEE,aAAA,GACE,MAAA,UACA,QAAA,GAAW,MAAA,sBACR,OAAA;QAAU,SAAA;QAAmB,MAAA;MAAA,IAA7B;MAEL,aAAA,GAAgB,SAAA,aAAsB,OAAA,QAFJ;MAIlC,iBAAA,GAAoB,MAAA,aAAmB,OAAA,QAFvB;MAIhB,mBAAA,GAAsB,MAAA,UAAgB,gBAAA,aAA6B,OAAA,QAFnE;MAIA,cAAA,GAAiB,SAAA,aAAsB,OAAA,CAAQ,WAAA;IAAA;EAAA;EAAA,UAIzC,cAAA;IANgC;IAQxC,OAAA,GAAU,WAAA;MAAgB,EAAA;IAAA;EAAA;AAAA;AAAA,UAuHb,yBAAA;EAvHb;EAyHF,iBAAA;AAAA;;;;AAFF;cASa,kBAAA,YAA8B,YAAA;EAAA,QACjC,QAAA;EARR;EAAA,QAUQ,SAAA;EAAA,QACA,eAAA;cAEI,OAAA,GAAS,yBAAA;EAYf,GAAA,CAAI,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAahC,GAAA,CAAI,SAAA,UAAmB,IAAA,EAAM,WAAA,GAAc,OAAA;EAY3C,MAAA,CAAO,SAAA,WAAoB,OAAA;EAe3B,SAAA,CAAU,MAAA,WAAiB,OAAA;EAU3B,eAAA,CAAgB,MAAA,UAAgB,gBAAA,WAA2B,OAAA;EArChB;;;EA0DjD,KAAA,CAAA;EAzFyC;;;EAqGzC,QAAA,CAAA;IAAc,QAAA;IAAkB,KAAA;EAAA;;;;UAUxB,OAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;AAuEV;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,oBAAA,CAAqB,OAAA,EAAS,qBAAA,GAAwB,oBAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sse-B3c3_yZp.mjs","names":[],"sources":["../src/plugins/sse.ts"],"sourcesContent":["/**\n * SSE Plugin (Server-Sent Events)\n *\n * Streams domain events to clients over HTTP using Server-Sent Events.\n * Requires the events plugin (`arc-events`) to be registered first.\n *\n * @example\n * import { ssePlugin } from '@classytic/arc/plugins';\n *\n * // Basic — stream all events at /events/stream\n * await fastify.register(ssePlugin);\n *\n * // Filtered + org-scoped\n * await fastify.register(ssePlugin, {\n * path: '/api/events',\n * patterns: ['order.*', 'product.*'],\n * orgScoped: true,\n * });\n */\n\nimport fp from \"fastify-plugin\";\nimport type {\n FastifyInstance,\n FastifyPluginAsync,\n FastifyRequest,\n FastifyReply,\n} from \"fastify\";\nimport type { DomainEvent } from \"../events/EventTransport.js\";\nimport { getOrgId, PUBLIC_SCOPE } from \"../scope/types.js\";\nimport type { RequestScope } from \"../scope/types.js\";\nimport { arcLog } from \"../logger/index.js\";\n\nconst log = arcLog(\"sse\");\n\nexport interface SSEOptions {\n /** SSE endpoint path (default: '/events/stream') */\n path?: string;\n /** Require authentication (default: true) */\n requireAuth?: boolean;\n /** Event patterns to stream (default: ['*'] = all) */\n patterns?: string[];\n /** Heartbeat interval in ms (default: 30000) */\n heartbeat?: number;\n /** Filter events by organizationId from request.scope (default: false) */\n orgScoped?: boolean;\n /** Custom event filter function */\n filter?: (event: DomainEvent<unknown>, request: FastifyRequest) => boolean;\n}\n\n// ============================================================================\n// Plugin\n// ============================================================================\n\nconst ssePlugin: FastifyPluginAsync<SSEOptions> = async (\n fastify: FastifyInstance,\n opts: SSEOptions = {},\n) => {\n const {\n path = \"/events/stream\",\n requireAuth = true,\n patterns = [\"*\"],\n heartbeat = 30000,\n orgScoped = false,\n filter: customFilter,\n } = opts;\n\n // Check that events plugin is registered\n if (!fastify.hasDecorator(\"events\")) {\n log.warn(\n \"Events plugin (arc-events) not registered. SSE plugin will not function. \" +\n \"Register eventPlugin before ssePlugin.\",\n );\n return;\n }\n\n // Track active connections for cleanup\n const activeConnections = new Set<() => void>();\n\n // Build route options\n const routeOpts: {\n method: \"GET\";\n url: string;\n schema: Record<string, unknown>;\n preHandler?: (\n request: FastifyRequest,\n reply: FastifyReply,\n ) => Promise<void>;\n handler: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;\n } = {\n method: \"GET\",\n url: path,\n schema: {\n tags: [\"Events\"],\n summary: \"SSE event stream\",\n description: \"Server-Sent Events stream for real-time domain events\",\n response: {\n 200: {\n type: \"string\",\n description: \"text/event-stream\",\n },\n },\n },\n handler: async (\n request: FastifyRequest,\n reply: FastifyReply,\n ): Promise<void> => {\n // 1. Tell Fastify we are taking over the socket\n reply.hijack();\n\n // Set SSE headers and flush immediately so clients detect the connection\n reply.raw.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\", // Disable nginx buffering\n });\n reply.raw.flushHeaders();\n\n // Track unsubscribers for cleanup\n const unsubscribers: (() => void)[] = [];\n\n // Get org context from request.scope for filtering\n const scope: RequestScope = request.scope ?? PUBLIC_SCOPE;\n const requestOrgId = getOrgId(scope);\n\n // Subscribe to each pattern\n // If orgScoped is enabled but caller has no org context, drop all org events\n // to prevent leaking data across organizations\n const dropOrgEvents = orgScoped && !requestOrgId;\n\n for (const pattern of patterns) {\n const unsub = await fastify.events.subscribe(\n pattern,\n async (event: DomainEvent<unknown>) => {\n // Org-scoped filtering: only forward events for the user's org\n if (orgScoped) {\n const eventOrgId = (event.meta as Record<string, unknown>)\n ?.organizationId;\n // If caller has no org, drop any event that carries an orgId\n if (dropOrgEvents && eventOrgId) return;\n // If caller has an org, only forward events matching their org\n if (requestOrgId && eventOrgId && eventOrgId !== requestOrgId)\n return;\n }\n\n // Custom filter\n if (customFilter && !customFilter(event, request)) return;\n\n // Write SSE event\n const data = JSON.stringify({\n type: event.type,\n payload: event.payload,\n meta: { id: event.meta.id, timestamp: event.meta.timestamp },\n });\n const success = reply.raw.write(\n `event: ${event.type}\\ndata: ${data}\\n\\n`,\n );\n if (!success) {\n // TCP Backpressure / Slow Client Check:\n // Terminate connection if buffer is full to prevent unbounded memory leaks via L7 proxies\n request.raw.destroy(\n new Error(\n \"SSE connection terminated: slow client backpressure\",\n ),\n );\n cleanup();\n }\n },\n );\n unsubscribers.push(unsub);\n }\n\n // Heartbeat to keep connection alive\n const heartbeatTimer = setInterval(() => {\n const success = reply.raw.write(\": heartbeat\\n\\n\");\n if (!success) {\n request.raw.destroy(\n new Error(\"SSE connection terminated: heartbeat backpressure\"),\n );\n cleanup();\n }\n }, heartbeat);\n\n // Cleanup function\n const cleanup = () => {\n clearInterval(heartbeatTimer);\n for (const unsub of unsubscribers) {\n unsub();\n }\n // End the response to release the connection\n if (!reply.raw.writableEnded) {\n reply.raw.end();\n }\n activeConnections.delete(cleanup);\n };\n\n activeConnections.add(cleanup);\n\n // Cleanup on client disconnect\n request.raw.on(\"close\", cleanup);\n },\n };\n\n // Add auth preHandler if required — fail-closed: throw if decorator missing\n if (requireAuth) {\n if (!fastify.hasDecorator(\"authenticate\")) {\n throw new Error(\n \"[arc-sse] requireAuth is true but fastify.authenticate is not registered. \" +\n \"Register an auth plugin before SSE, or set requireAuth: false.\",\n );\n }\n routeOpts.preHandler = fastify.authenticate;\n }\n\n fastify.route(routeOpts);\n\n // Cleanup all connections on server close\n fastify.addHook(\"onClose\", async () => {\n for (const cleanup of activeConnections) {\n cleanup();\n }\n activeConnections.clear();\n });\n\n log.debug(\"Plugin registered\", { path, patterns, orgScoped });\n};\n\nexport default fp(ssePlugin, {\n name: \"arc-sse\",\n fastify: \"5.x\",\n dependencies: [\"arc-events\"],\n});\n\nexport { ssePlugin };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,MAAM,OAAO,MAAM;AAqBzB,MAAM,YAA4C,OAChD,SACA,OAAmB,EAAE,KAClB;CACH,MAAM,EACJ,OAAO,kBACP,cAAc,MACd,WAAW,CAAC,IAAI,EAChB,YAAY,KACZ,YAAY,OACZ,QAAQ,iBACN;AAGJ,KAAI,CAAC,QAAQ,aAAa,SAAS,EAAE;AACnC,MAAI,KACF,kHAED;AACD;;CAIF,MAAM,oCAAoB,IAAI,KAAiB;CAG/C,MAAM,YASF;EACF,QAAQ;EACR,KAAK;EACL,QAAQ;GACN,MAAM,CAAC,SAAS;GAChB,SAAS;GACT,aAAa;GACb,UAAU,EACR,KAAK;IACH,MAAM;IACN,aAAa;IACd,EACF;GACF;EACD,SAAS,OACP,SACA,UACkB;AAElB,SAAM,QAAQ;AAGd,SAAM,IAAI,UAAU,KAAK;IACvB,gBAAgB;IAChB,iBAAiB;IACjB,YAAY;IACZ,qBAAqB;IACtB,CAAC;AACF,SAAM,IAAI,cAAc;GAGxB,MAAM,gBAAgC,EAAE;GAIxC,MAAM,eAAe,SADO,QAAQ,SAAS,aACT;GAKpC,MAAM,gBAAgB,aAAa,CAAC;AAEpC,QAAK,MAAM,WAAW,UAAU;IAC9B,MAAM,QAAQ,MAAM,QAAQ,OAAO,UACjC,SACA,OAAO,UAAgC;AAErC,SAAI,WAAW;MACb,MAAM,aAAc,MAAM,MACtB;AAEJ,UAAI,iBAAiB,WAAY;AAEjC,UAAI,gBAAgB,cAAc,eAAe,aAC/C;;AAIJ,SAAI,gBAAgB,CAAC,aAAa,OAAO,QAAQ,CAAE;KAGnD,MAAM,OAAO,KAAK,UAAU;MAC1B,MAAM,MAAM;MACZ,SAAS,MAAM;MACf,MAAM;OAAE,IAAI,MAAM,KAAK;OAAI,WAAW,MAAM,KAAK;OAAW;MAC7D,CAAC;AAIF,SAAI,CAHY,MAAM,IAAI,MACxB,UAAU,MAAM,KAAK,UAAU,KAAK,MACrC,EACa;AAGZ,cAAQ,IAAI,wBACV,IAAI,MACF,sDACD,CACF;AACD,eAAS;;MAGd;AACD,kBAAc,KAAK,MAAM;;GAI3B,MAAM,iBAAiB,kBAAkB;AAEvC,QAAI,CADY,MAAM,IAAI,MAAM,kBAAkB,EACpC;AACZ,aAAQ,IAAI,wBACV,IAAI,MAAM,oDAAoD,CAC/D;AACD,cAAS;;MAEV,UAAU;GAGb,MAAM,gBAAgB;AACpB,kBAAc,eAAe;AAC7B,SAAK,MAAM,SAAS,cAClB,QAAO;AAGT,QAAI,CAAC,MAAM,IAAI,cACb,OAAM,IAAI,KAAK;AAEjB,sBAAkB,OAAO,QAAQ;;AAGnC,qBAAkB,IAAI,QAAQ;AAG9B,WAAQ,IAAI,GAAG,SAAS,QAAQ;;EAEnC;AAGD,KAAI,aAAa;AACf,MAAI,CAAC,QAAQ,aAAa,eAAe,CACvC,OAAM,IAAI,MACR,2IAED;AAEH,YAAU,aAAa,QAAQ;;AAGjC,SAAQ,MAAM,UAAU;AAGxB,SAAQ,QAAQ,WAAW,YAAY;AACrC,OAAK,MAAM,WAAW,kBACpB,UAAS;AAEX,oBAAkB,OAAO;GACzB;AAEF,KAAI,MAAM,qBAAqB;EAAE;EAAM;EAAU;EAAW,CAAC;;AAG/D,kBAAe,GAAG,WAAW;CAC3B,MAAM;CACN,SAAS;CACT,cAAc,CAAC,aAAa;CAC7B,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/testing/TestHarness.ts","../../src/testing/testFactory.ts","../../src/testing/mocks.ts","../../src/testing/authHelpers.ts","../../src/testing/HttpTestHarness.ts","../../src/testing/dbHelpers.ts"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/testing/TestHarness.ts","../../src/testing/dbHelpers.ts","../../src/testing/testFactory.ts","../../src/testing/mocks.ts","../../src/testing/authHelpers.ts","../../src/testing/HttpTestHarness.ts"],"sourcesContent":["/**\n * Resource Test Harness\n *\n * Generates baseline tests for Arc resources automatically.\n * Tests CRUD operations + preset routes with minimal configuration.\n *\n * @example\n * import { createTestHarness } from '@classytic/arc/testing';\n * import productResource from './product.resource.js';\n *\n * const harness = createTestHarness(productResource, {\n * fixtures: {\n * valid: { name: 'Test Product', price: 100 },\n * update: { name: 'Updated Product' },\n * },\n * });\n *\n * // Run all baseline tests (50+ auto-generated)\n * harness.runAll();\n *\n * // Or run specific test suites\n * harness.runCrud();\n * harness.runPresets();\n */\n\nimport { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';\nimport mongoose, { Model, Document } from 'mongoose';\nimport type { ResourceDefinition } from '../core/defineResource.js';\nimport { applyFieldReadPermissions, applyFieldWritePermissions } from '../permissions/fields.js';\nimport type { FieldPermissionMap } from '../permissions/fields.js';\nimport type { PipelineConfig, PipelineStep } from '../pipeline/types.js';\nimport { CRUD_OPERATIONS } from '../constants.js';\n\n/**\n * Test fixtures for a resource\n */\nexport interface TestFixtures<T = any> {\n /** Valid create payload */\n valid: Partial<T>;\n /** Update payload (optional, defaults to valid) */\n update?: Partial<T>;\n /** Invalid payload for validation tests (optional) */\n invalid?: Partial<T>;\n}\n\n/**\n * Test harness options\n */\nexport interface TestHarnessOptions<T = any> {\n /** Test data fixtures */\n fixtures: TestFixtures<T>;\n /** Custom setup function (runs before all tests) */\n setupFn?: () => Promise<void> | void;\n /** Custom teardown function (runs after all tests) */\n teardownFn?: () => Promise<void> | void;\n /** MongoDB connection URI (defaults to process.env.MONGO_URI) */\n mongoUri?: string;\n}\n\n/**\n * Test harness for Arc resources\n *\n * Provides automatic test generation for:\n * - CRUD operations (create, read, update, delete)\n * - Schema validation\n * - Preset-specific functionality (softDelete, slugLookup, tree, etc.)\n */\nexport class TestHarness<T = unknown> {\n private resource: ResourceDefinition<unknown>;\n private fixtures: TestFixtures<T>;\n private setupFn?: () => Promise<void> | void;\n private teardownFn?: () => Promise<void> | void;\n private mongoUri: string;\n private _createdIds: any[] = [];\n private Model: Model<any>;\n\n constructor(resource: ResourceDefinition<unknown>, options: TestHarnessOptions<T>) {\n this.resource = resource;\n this.fixtures = options.fixtures;\n this.setupFn = options.setupFn;\n this.teardownFn = options.teardownFn;\n this.mongoUri = options.mongoUri || process.env.MONGO_URI || 'mongodb://localhost:27017/test';\n\n // Extract model from adapter (Mongoose only)\n if (!resource.adapter) {\n throw new Error(`TestHarness requires a resource with a database adapter`);\n }\n\n if (resource.adapter.type !== 'mongoose') {\n throw new Error(`TestHarness currently only supports Mongoose adapters`);\n }\n\n const model = (resource.adapter as { model?: Model<unknown> }).model;\n if (!model) {\n throw new Error(`Mongoose adapter for ${resource.name} does not have a model`);\n }\n\n this.Model = model as Model<unknown>;\n }\n\n /**\n * Run all baseline tests\n *\n * Executes CRUD, validation, and preset tests\n */\n runAll(): void {\n this.runCrud();\n this.runValidation();\n this.runPresets();\n this.runFieldPermissions();\n this.runPipeline();\n this.runEvents();\n }\n\n /**\n * Run CRUD operation tests (model-level)\n *\n * Tests: create, read (list + getById), update, delete\n *\n * @deprecated Use `HttpTestHarness.runCrud()` for HTTP-level CRUD tests.\n * This method tests Mongoose models directly and does not exercise\n * HTTP routes, authentication, permissions, or the Arc pipeline.\n */\n runCrud(): void {\n const { resource, fixtures, Model } = this;\n\n describe(`${resource.displayName} CRUD Operations`, () => {\n beforeAll(async () => {\n await mongoose.connect(this.mongoUri);\n if (this.setupFn) await this.setupFn();\n });\n\n afterAll(async () => {\n // Cleanup created documents\n if (this._createdIds.length > 0) {\n await Model.deleteMany({ _id: { $in: this._createdIds } });\n }\n if (this.teardownFn) await this.teardownFn();\n await mongoose.disconnect();\n });\n\n describe('Create', () => {\n it('should create a new document with valid data', async () => {\n const doc = await Model.create(fixtures.valid);\n this._createdIds.push(doc._id);\n\n expect(doc).toBeDefined();\n expect(doc._id).toBeDefined();\n\n // Verify all provided fields\n for (const [key, value] of Object.entries(fixtures.valid)) {\n if (typeof value !== 'object') {\n expect(doc[key]).toEqual(value);\n }\n }\n });\n\n it('should have timestamps', async () => {\n const doc = await Model.findById(this._createdIds[0]);\n expect(doc).toBeDefined();\n expect(doc!.createdAt).toBeDefined();\n expect(doc!.updatedAt).toBeDefined();\n });\n });\n\n describe('Read', () => {\n it('should find document by ID', async () => {\n const doc = await Model.findById(this._createdIds[0]);\n expect(doc).toBeDefined();\n });\n\n it('should list documents', async () => {\n const docs = await Model.find({});\n expect(Array.isArray(docs)).toBe(true);\n expect(docs.length).toBeGreaterThan(0);\n });\n });\n\n describe('Update', () => {\n it('should update document', async () => {\n const updateData = fixtures.update || { updatedAt: new Date() };\n const doc = await Model.findByIdAndUpdate(this._createdIds[0], updateData, {\n new: true,\n });\n expect(doc).toBeDefined();\n });\n });\n\n describe('Delete', () => {\n it('should delete document', async () => {\n // Create a doc specifically for deletion\n const toDelete = await Model.create(fixtures.valid);\n await Model.findByIdAndDelete(toDelete._id);\n const deleted = await Model.findById(toDelete._id);\n expect(deleted).toBeNull();\n });\n });\n });\n }\n\n /**\n * Run validation tests\n *\n * Tests schema validation, required fields, etc.\n */\n runValidation(): void {\n const { resource, fixtures, Model } = this;\n\n describe(`${resource.displayName} Validation`, () => {\n beforeAll(async () => {\n await mongoose.connect(this.mongoUri);\n });\n\n afterAll(async () => {\n await mongoose.disconnect();\n });\n\n it('should reject empty document', async () => {\n await expect(Model.create({})).rejects.toThrow();\n });\n\n if (fixtures.invalid) {\n it('should reject invalid data', async () => {\n await expect(Model.create(fixtures.invalid!)).rejects.toThrow();\n });\n }\n });\n }\n\n /**\n * Run preset-specific tests\n *\n * Auto-detects applied presets and tests their functionality:\n * - softDelete: deletedAt field, soft delete/restore\n * - slugLookup: slug generation\n * - tree: parent references, displayOrder\n * - multiTenant: organizationId requirement\n * - ownedByUser: userId requirement\n */\n runPresets(): void {\n const { resource, fixtures, Model } = this;\n const presets = (resource as any)._appliedPresets || [];\n\n if (presets.length === 0) return;\n\n describe(`${resource.displayName} Preset Tests`, () => {\n beforeAll(async () => {\n await mongoose.connect(this.mongoUri);\n });\n\n afterAll(async () => {\n await mongoose.disconnect();\n });\n\n // Soft Delete preset tests\n if (presets.includes('softDelete')) {\n describe('Soft Delete', () => {\n let testDoc: any;\n\n beforeEach(async () => {\n testDoc = await Model.create(fixtures.valid);\n this._createdIds.push(testDoc._id);\n });\n\n it('should have deletedAt field', () => {\n expect(testDoc.deletedAt).toBeDefined();\n expect(testDoc.deletedAt).toBeNull();\n });\n\n it('should soft delete (set deletedAt)', async () => {\n await Model.findByIdAndUpdate(testDoc._id, { deletedAt: new Date() });\n const deleted = await Model.findById(testDoc._id);\n expect(deleted!.deletedAt).not.toBeNull();\n });\n\n it('should restore (clear deletedAt)', async () => {\n await Model.findByIdAndUpdate(testDoc._id, { deletedAt: new Date() });\n await Model.findByIdAndUpdate(testDoc._id, { deletedAt: null });\n const restored = await Model.findById(testDoc._id);\n expect(restored!.deletedAt).toBeNull();\n });\n });\n }\n\n // Slug preset tests\n if (presets.includes('slugLookup')) {\n describe('Slug Lookup', () => {\n it('should have slug field', async () => {\n const doc = await Model.create(fixtures.valid);\n this._createdIds.push(doc._id);\n expect(doc.slug).toBeDefined();\n });\n\n it('should generate slug from name', async () => {\n const doc = await Model.create({ ...fixtures.valid, name: 'Test Slug Name' });\n this._createdIds.push(doc._id);\n expect(doc.slug).toMatch(/test-slug-name/i);\n });\n });\n }\n\n // Tree preset tests\n if (presets.includes('tree')) {\n describe('Tree Structure', () => {\n it('should allow parent reference', async () => {\n const parent = await Model.create(fixtures.valid);\n this._createdIds.push(parent._id);\n\n const child = await Model.create({\n ...fixtures.valid,\n parent: parent._id,\n });\n this._createdIds.push(child._id);\n\n expect(child.parent.toString()).toEqual(parent._id.toString());\n });\n\n it('should support displayOrder', async () => {\n const doc = await Model.create({\n ...fixtures.valid,\n displayOrder: 5,\n });\n this._createdIds.push(doc._id);\n expect(doc.displayOrder).toEqual(5);\n });\n });\n }\n\n // Multi-tenant preset tests\n if (presets.includes('multiTenant')) {\n describe('Multi-Tenant', () => {\n it('should require organizationId', async () => {\n const docWithoutOrg = { ...fixtures.valid };\n delete (docWithoutOrg as any).organizationId;\n await expect(Model.create(docWithoutOrg)).rejects.toThrow();\n });\n });\n }\n\n // Owned by user preset tests\n if (presets.includes('ownedByUser')) {\n describe('Owned By User', () => {\n it('should require userId', async () => {\n const docWithoutUser = { ...fixtures.valid };\n delete (docWithoutUser as any).userId;\n await expect(Model.create(docWithoutUser)).rejects.toThrow();\n });\n });\n }\n });\n }\n\n /**\n * Run field-level permission tests\n *\n * Auto-generates tests for each field permission:\n * - hidden: field is stripped from responses\n * - visibleTo: field only shown to specified roles\n * - writableBy: field stripped from writes by non-privileged users\n * - redactFor: field shows redacted value for specified roles\n */\n runFieldPermissions(): void {\n const { resource } = this;\n const fieldPerms = resource.fields;\n\n if (!fieldPerms || Object.keys(fieldPerms).length === 0) return;\n\n describe(`${resource.displayName} Field Permissions`, () => {\n for (const [field, perm] of Object.entries(fieldPerms)) {\n switch (perm._type) {\n case 'hidden':\n it(`should always hide field '${field}'`, () => {\n const data = { [field]: 'secret', otherField: 'visible' } as Record<string, unknown>;\n const result = applyFieldReadPermissions(data, fieldPerms, []);\n expect(result[field]).toBeUndefined();\n expect(result.otherField).toBe('visible');\n });\n\n it(`should strip hidden field '${field}' from writes`, () => {\n const body = { [field]: 'attempt', name: 'test' } as Record<string, unknown>;\n const result = applyFieldWritePermissions(body, fieldPerms, []);\n expect(result[field]).toBeUndefined();\n expect(result.name).toBe('test');\n });\n break;\n\n case 'visibleTo':\n it(`should hide field '${field}' from non-privileged users`, () => {\n const data = { [field]: 'sensitive' } as Record<string, unknown>;\n const result = applyFieldReadPermissions(data, fieldPerms, ['viewer']);\n expect(result[field]).toBeUndefined();\n });\n\n if (perm.roles && perm.roles.length > 0) {\n const allowedRole = perm.roles[0]!;\n it(`should show field '${field}' to roles: ${[...perm.roles].join(', ')}`, () => {\n const data = { [field]: 'sensitive' } as Record<string, unknown>;\n const result = applyFieldReadPermissions(data, fieldPerms, [allowedRole]);\n expect(result[field]).toBe('sensitive');\n });\n }\n break;\n\n case 'writableBy':\n it(`should strip field '${field}' from writes by non-privileged users`, () => {\n const body = { [field]: 'new-value', name: 'test' } as Record<string, unknown>;\n const result = applyFieldWritePermissions(body, fieldPerms, ['viewer']);\n expect(result[field]).toBeUndefined();\n expect(result.name).toBe('test');\n });\n\n if (perm.roles && perm.roles.length > 0) {\n const writeRole = perm.roles[0]!;\n it(`should allow writing field '${field}' by roles: ${[...perm.roles].join(', ')}`, () => {\n const body = { [field]: 'new-value' } as Record<string, unknown>;\n const result = applyFieldWritePermissions(body, fieldPerms, [writeRole]);\n expect(result[field]).toBe('new-value');\n });\n }\n break;\n\n case 'redactFor':\n if (perm.roles && perm.roles.length > 0) {\n const redactRole = perm.roles[0]!;\n it(`should redact field '${field}' for roles: ${[...perm.roles].join(', ')}`, () => {\n const data = { [field]: 'real-value' } as Record<string, unknown>;\n const result = applyFieldReadPermissions(data, fieldPerms, [redactRole]);\n expect(result[field]).toBe(perm.redactValue ?? '***');\n });\n }\n\n it(`should show real value of field '${field}' to non-redacted roles`, () => {\n const data = { [field]: 'real-value' } as Record<string, unknown>;\n const result = applyFieldReadPermissions(data, fieldPerms, ['unrelated-role']);\n expect(result[field]).toBe('real-value');\n });\n break;\n }\n }\n });\n }\n\n /**\n * Run pipeline configuration tests\n *\n * Validates that pipeline steps are properly configured:\n * - All steps have names\n * - All steps have valid _type discriminants\n * - Operation filters (if set) use valid CRUD operation names\n */\n runPipeline(): void {\n const { resource } = this;\n const pipe = resource.pipe;\n\n if (!pipe) return;\n\n const validOps: Set<string> = new Set(CRUD_OPERATIONS);\n\n describe(`${resource.displayName} Pipeline`, () => {\n const steps = collectPipelineSteps(pipe);\n\n it('should have at least one pipeline step', () => {\n expect(steps.length).toBeGreaterThan(0);\n });\n\n for (const step of steps) {\n it(`${step._type} '${step.name}' should have a valid type`, () => {\n expect(['guard', 'transform', 'interceptor']).toContain(step._type);\n });\n\n it(`${step._type} '${step.name}' should have a name`, () => {\n expect(step.name).toBeTruthy();\n expect(typeof step.name).toBe('string');\n });\n\n it(`${step._type} '${step.name}' should have a handler function`, () => {\n expect(typeof step.handler).toBe('function');\n });\n\n if (step.operations?.length) {\n it(`${step._type} '${step.name}' should target valid operations`, () => {\n for (const op of step.operations!) {\n expect(validOps.has(op)).toBe(true);\n }\n });\n }\n }\n });\n }\n\n /**\n * Run event definition tests\n *\n * Validates that events are properly defined:\n * - All events have handler functions\n * - Event names follow resource:action convention\n * - Schema definitions (if present) are valid objects\n */\n runEvents(): void {\n const { resource } = this;\n const events = resource.events;\n\n if (!events || Object.keys(events).length === 0) return;\n\n describe(`${resource.displayName} Events`, () => {\n for (const [action, def] of Object.entries(events)) {\n it(`event '${resource.name}:${action}' should have a handler function`, () => {\n expect(typeof def.handler).toBe('function');\n });\n\n it(`event '${resource.name}:${action}' should have a name`, () => {\n expect(def.name).toBeTruthy();\n expect(typeof def.name).toBe('string');\n });\n\n if (def.schema) {\n it(`event '${resource.name}:${action}' schema should be an object`, () => {\n expect(typeof def.schema).toBe('object');\n expect(def.schema).not.toBeNull();\n });\n }\n }\n });\n }\n}\n\n/**\n * Collect all pipeline steps from a PipelineConfig (flat array or per-operation map)\n */\nfunction collectPipelineSteps(pipe: PipelineConfig): PipelineStep[] {\n if (Array.isArray(pipe)) return pipe;\n\n const seen = new Set<string>();\n const steps: PipelineStep[] = [];\n\n for (const opSteps of Object.values(pipe)) {\n if (Array.isArray(opSteps)) {\n for (const step of opSteps) {\n const key = `${step._type}:${step.name}`;\n if (!seen.has(key)) {\n seen.add(key);\n steps.push(step);\n }\n }\n }\n }\n\n return steps;\n}\n\n/**\n * Create a test harness for an Arc resource\n *\n * @param resource - The Arc resource definition to test\n * @param options - Test harness configuration\n * @returns Test harness instance\n *\n * @example\n * import { createTestHarness } from '@classytic/arc/testing';\n *\n * const harness = createTestHarness(productResource, {\n * fixtures: {\n * valid: { name: 'Product', price: 100 },\n * update: { name: 'Updated' },\n * },\n * });\n *\n * harness.runAll(); // Generates 50+ baseline tests\n */\nexport function createTestHarness<T = any>(\n resource: ResourceDefinition,\n options: TestHarnessOptions<T>\n): TestHarness<T> {\n return new TestHarness<T>(resource, options);\n}\n\n/**\n * Test file generation options\n */\nexport interface GenerateTestFileOptions {\n /** Applied presets (e.g., ['softDelete', 'slugLookup']) */\n presets?: string[];\n /** Module path for imports (default: '.') */\n modulePath?: string;\n}\n\n/**\n * Generate test file content for a resource\n *\n * Useful for scaffolding new resource tests via CLI\n *\n * @param resourceName - Resource name in kebab-case (e.g., 'product')\n * @param options - Generation options\n * @returns Complete test file content as string\n *\n * @example\n * const testContent = generateTestFile('product', {\n * presets: ['softDelete'],\n * modulePath: './modules/catalog',\n * });\n * fs.writeFileSync('product.test.js', testContent);\n */\nexport function generateTestFile(\n resourceName: string,\n options: GenerateTestFileOptions = {}\n): string {\n const { presets = [], modulePath = '.' } = options;\n const className = resourceName\n .split('-')\n .map((s) => s.charAt(0).toUpperCase() + s.slice(1))\n .join('');\n const varName = className.charAt(0).toLowerCase() + className.slice(1);\n\n return `/**\n * ${className} Resource Tests\n *\n * Auto-generated baseline tests. Customize as needed.\n */\n\nimport { describe, it, expect, beforeAll, afterAll } from 'vitest';\nimport mongoose from 'mongoose';\nimport { createTestHarness } from '@classytic/arc/testing';\nimport ${varName}Resource from '${modulePath}/${resourceName}.resource.js';\nimport ${className} from '${modulePath}/${resourceName}.model.js';\n\nconst MONGO_URI = process.env.MONGO_TEST_URI || 'mongodb://localhost:27017/${resourceName}-test';\n\n// Test fixtures\nconst fixtures = {\n valid: {\n name: 'Test ${className}',\n // Add required fields here\n },\n update: {\n name: 'Updated ${className}',\n },\n invalid: {\n // Empty or invalid data\n },\n};\n\n// Create test harness\nconst harness = createTestHarness(${varName}Resource, {\n fixtures,\n mongoUri: MONGO_URI,\n});\n\n// Run all baseline tests\nharness.runAll();\n\n// Custom tests\ndescribe('${className} Custom Tests', () => {\n let testId;\n\n beforeAll(async () => {\n await mongoose.connect(MONGO_URI);\n });\n\n afterAll(async () => {\n if (testId) {\n await ${className}.findByIdAndDelete(testId);\n }\n await mongoose.disconnect();\n });\n\n // Add your custom tests here\n it('should pass custom validation', async () => {\n // Example: const doc = await ${className}.create(fixtures.valid);\n // testId = doc._id;\n // expect(doc.someField).toBe('expectedValue');\n expect(true).toBe(true);\n });\n});\n`;\n}\n\n/**\n * Run config-level tests for a resource (no DB required)\n *\n * Tests field permissions, pipeline configuration, and event definitions.\n * Works with any adapter — no Mongoose dependency.\n *\n * @param resource - The Arc resource definition to test\n *\n * @example\n * ```typescript\n * import { createConfigTestSuite } from '@classytic/arc/testing';\n * import productResource from './product.resource.js';\n *\n * // Generates field permission, pipeline, and event tests\n * createConfigTestSuite(productResource);\n * ```\n */\nexport function createConfigTestSuite(resource: ResourceDefinition<unknown>): void {\n const fieldPerms = resource.fields;\n const pipe = resource.pipe;\n const events = resource.events;\n\n // Field permissions\n if (fieldPerms && Object.keys(fieldPerms).length > 0) {\n runFieldPermissionTests(resource.displayName, fieldPerms);\n }\n\n // Pipeline\n if (pipe) {\n runPipelineTests(resource.displayName, pipe);\n }\n\n // Events\n if (events && Object.keys(events).length > 0) {\n runEventTests(resource.name, resource.displayName, events);\n }\n\n // Permissions configuration\n if (resource.permissions && Object.keys(resource.permissions).length > 0) {\n describe(`${resource.displayName} Permission Config`, () => {\n for (const op of CRUD_OPERATIONS) {\n const check = resource.permissions[op];\n if (check) {\n it(`${op} permission should be a function`, () => {\n expect(typeof check).toBe('function');\n });\n }\n }\n });\n }\n}\n\nfunction runFieldPermissionTests(displayName: string, fieldPerms: FieldPermissionMap): void {\n describe(`${displayName} Field Permissions`, () => {\n for (const [field, perm] of Object.entries(fieldPerms)) {\n switch (perm._type) {\n case 'hidden':\n it(`should always hide field '${field}'`, () => {\n const data = { [field]: 'secret', other: 'visible' } as Record<string, unknown>;\n const result = applyFieldReadPermissions(data, fieldPerms, []);\n expect(result[field]).toBeUndefined();\n });\n\n it(`should strip hidden field '${field}' from writes`, () => {\n const body = { [field]: 'attempt', name: 'test' } as Record<string, unknown>;\n const result = applyFieldWritePermissions(body, fieldPerms, []);\n expect(result[field]).toBeUndefined();\n });\n break;\n\n case 'visibleTo':\n it(`should hide field '${field}' from non-privileged users`, () => {\n const data = { [field]: 'sensitive' } as Record<string, unknown>;\n const result = applyFieldReadPermissions(data, fieldPerms, ['_no_role_']);\n expect(result[field]).toBeUndefined();\n });\n\n if (perm.roles && perm.roles.length > 0) {\n const allowedRole = perm.roles[0]!;\n it(`should show field '${field}' to roles: ${[...perm.roles].join(', ')}`, () => {\n const data = { [field]: 'sensitive' } as Record<string, unknown>;\n const result = applyFieldReadPermissions(data, fieldPerms, [allowedRole]);\n expect(result[field]).toBe('sensitive');\n });\n }\n break;\n\n case 'writableBy':\n it(`should strip field '${field}' from writes by non-privileged users`, () => {\n const body = { [field]: 'v', name: 'test' } as Record<string, unknown>;\n const result = applyFieldWritePermissions(body, fieldPerms, ['_no_role_']);\n expect(result[field]).toBeUndefined();\n });\n\n if (perm.roles && perm.roles.length > 0) {\n const writeRole = perm.roles[0]!;\n it(`should allow writing field '${field}' by roles: ${[...perm.roles].join(', ')}`, () => {\n const body = { [field]: 'v' } as Record<string, unknown>;\n const result = applyFieldWritePermissions(body, fieldPerms, [writeRole]);\n expect(result[field]).toBe('v');\n });\n }\n break;\n\n case 'redactFor':\n if (perm.roles && perm.roles.length > 0) {\n const redactRole = perm.roles[0]!;\n it(`should redact field '${field}' for roles: ${[...perm.roles].join(', ')}`, () => {\n const data = { [field]: 'real' } as Record<string, unknown>;\n const result = applyFieldReadPermissions(data, fieldPerms, [redactRole]);\n expect(result[field]).toBe(perm.redactValue ?? '***');\n });\n }\n\n it(`should show real value of field '${field}' to non-redacted roles`, () => {\n const data = { [field]: 'real' } as Record<string, unknown>;\n const result = applyFieldReadPermissions(data, fieldPerms, ['_other_']);\n expect(result[field]).toBe('real');\n });\n break;\n }\n }\n });\n}\n\nfunction runPipelineTests(displayName: string, pipe: PipelineConfig): void {\n const steps = collectPipelineSteps(pipe);\n if (steps.length === 0) return;\n\n const validOps: Set<string> = new Set(CRUD_OPERATIONS);\n\n describe(`${displayName} Pipeline`, () => {\n it('should have at least one pipeline step', () => {\n expect(steps.length).toBeGreaterThan(0);\n });\n\n for (const step of steps) {\n it(`${step._type} '${step.name}' should have a valid type`, () => {\n expect(['guard', 'transform', 'interceptor']).toContain(step._type);\n });\n\n it(`${step._type} '${step.name}' should have a handler function`, () => {\n expect(typeof step.handler).toBe('function');\n });\n\n if (step.operations?.length) {\n it(`${step._type} '${step.name}' should target valid operations`, () => {\n for (const op of step.operations!) {\n expect(validOps.has(op)).toBe(true);\n }\n });\n }\n }\n });\n}\n\nfunction runEventTests(\n resourceName: string,\n displayName: string,\n events: Record<string, import('../types/index.js').EventDefinition>,\n): void {\n describe(`${displayName} Events`, () => {\n for (const [action, def] of Object.entries(events)) {\n it(`event '${resourceName}:${action}' should have a handler function`, () => {\n expect(typeof def.handler).toBe('function');\n });\n\n it(`event '${resourceName}:${action}' should have a name`, () => {\n expect(def.name).toBeTruthy();\n });\n\n if (def.schema) {\n it(`event '${resourceName}:${action}' schema should be an object`, () => {\n expect(typeof def.schema).toBe('object');\n expect(def.schema).not.toBeNull();\n });\n }\n }\n });\n}\n","/**\n * Testing Utilities - Database Helpers\n *\n * Utilities for managing test databases and fixtures\n */\n\nimport { beforeAll, afterAll, afterEach } from 'vitest';\nimport mongoose from 'mongoose';\nimport type { Connection } from 'mongoose';\n\n/**\n * Test database manager\n */\nexport class TestDatabase {\n private connection?: Connection;\n private dbName: string;\n\n constructor(dbName: string = `test_${Date.now()}`) {\n this.dbName = dbName;\n }\n\n /**\n * Connect to test database\n */\n async connect(uri?: string): Promise<Connection> {\n const mongoUri = uri || process.env.MONGO_TEST_URI || 'mongodb://localhost:27017';\n const fullUri = `${mongoUri}/${this.dbName}`;\n\n this.connection = await mongoose.createConnection(fullUri).asPromise();\n return this.connection;\n }\n\n /**\n * Disconnect and cleanup\n */\n async disconnect(): Promise<void> {\n if (this.connection) {\n await this.connection.dropDatabase();\n await this.connection.close();\n this.connection = undefined;\n }\n }\n\n /**\n * Clear all collections\n */\n async clear(): Promise<void> {\n if (!this.connection?.db) {\n throw new Error('Database not connected');\n }\n\n const collections = await this.connection.db.collections();\n await Promise.all(collections.map((collection) => collection.deleteMany({})));\n }\n\n /**\n * Get connection\n */\n getConnection(): Connection {\n if (!this.connection) {\n throw new Error('Database not connected');\n }\n return this.connection;\n }\n}\n\n/**\n * Higher-order function to wrap tests with database setup/teardown\n *\n * @example\n * describe('Product Tests', () => {\n * withTestDb(async (db) => {\n * test('create product', async () => {\n * const Product = db.getConnection().model('Product', schema);\n * const product = await Product.create({ name: 'Test' });\n * expect(product.name).toBe('Test');\n * });\n * });\n * });\n */\nexport function withTestDb(\n tests: (db: TestDatabase) => void | Promise<void>,\n options: { uri?: string; dbName?: string } = {}\n): void {\n const db = new TestDatabase(options.dbName);\n\n beforeAll(async () => {\n await db.connect(options.uri);\n });\n\n afterAll(async () => {\n await db.disconnect();\n });\n\n afterEach(async () => {\n await db.clear();\n });\n\n tests(db);\n}\n\n/**\n * Create test fixtures\n *\n * @example\n * const fixtures = new TestFixtures(connection);\n *\n * await fixtures.load('products', [\n * { name: 'Product 1', price: 100 },\n * { name: 'Product 2', price: 200 },\n * ]);\n *\n * const products = await fixtures.get('products');\n */\nexport class TestFixtures {\n private fixtures: Map<string, any[]> = new Map();\n private connection: Connection;\n\n constructor(connection: Connection) {\n this.connection = connection;\n }\n\n /**\n * Load fixtures into a collection\n */\n async load<T = any>(collectionName: string, data: Partial<T>[]): Promise<T[]> {\n const collection = this.connection.collection(collectionName);\n const result = await collection.insertMany(data as any[]);\n\n const insertedDocs = Object.values(result.insertedIds).map((id, index) => ({\n ...data[index],\n _id: id,\n })) as T[];\n\n this.fixtures.set(collectionName, insertedDocs);\n return insertedDocs;\n }\n\n /**\n * Get loaded fixtures\n */\n get<T = any>(collectionName: string): T[] {\n return (this.fixtures.get(collectionName) || []) as T[];\n }\n\n /**\n * Get first fixture\n */\n getFirst<T = any>(collectionName: string): T | null {\n const items = this.get<T>(collectionName);\n return items[0] || null;\n }\n\n /**\n * Clear all fixtures\n */\n async clear(): Promise<void> {\n for (const collectionName of this.fixtures.keys()) {\n const collection = this.connection.collection(collectionName);\n const ids = this.fixtures.get(collectionName)?.map((item) => item._id) || [];\n await collection.deleteMany({ _id: { $in: ids } });\n }\n this.fixtures.clear();\n }\n}\n\n/**\n * In-memory MongoDB for ultra-fast tests\n *\n * Requires: mongodb-memory-server\n *\n * @example\n * import { InMemoryDatabase } from '@classytic/arc/testing';\n *\n * describe('Fast Tests', () => {\n * const memoryDb = new InMemoryDatabase();\n *\n * beforeAll(async () => {\n * await memoryDb.start();\n * });\n *\n * afterAll(async () => {\n * await memoryDb.stop();\n * });\n *\n * test('create user', async () => {\n * const uri = memoryDb.getUri();\n * // Use uri for connection\n * });\n * });\n */\nexport class InMemoryDatabase {\n private mongod?: any;\n private uri?: string;\n\n /**\n * Start in-memory MongoDB\n */\n async start(): Promise<string> {\n try {\n const { MongoMemoryServer } = await import('mongodb-memory-server');\n this.mongod = await MongoMemoryServer.create();\n const uri = this.mongod.getUri() as string;\n this.uri = uri;\n return uri;\n } catch {\n throw new Error(\n 'mongodb-memory-server not installed. Install with: npm install -D mongodb-memory-server'\n );\n }\n }\n\n /**\n * Stop in-memory MongoDB\n */\n async stop(): Promise<void> {\n if (this.mongod) {\n await this.mongod.stop();\n this.mongod = undefined;\n this.uri = undefined;\n }\n }\n\n /**\n * Get connection URI\n */\n getUri(): string {\n if (!this.uri) {\n throw new Error('In-memory database not started');\n }\n return this.uri;\n }\n}\n\n/**\n * Database transaction helper for testing\n */\nexport class TestTransaction {\n private session?: any;\n private connection: Connection;\n\n constructor(connection: Connection) {\n this.connection = connection;\n }\n\n /**\n * Start transaction\n */\n async start(): Promise<void> {\n this.session = await this.connection.startSession();\n this.session.startTransaction();\n }\n\n /**\n * Commit transaction\n */\n async commit(): Promise<void> {\n if (!this.session) {\n throw new Error('Transaction not started');\n }\n await this.session.commitTransaction();\n await this.session.endSession();\n this.session = undefined;\n }\n\n /**\n * Rollback transaction\n */\n async rollback(): Promise<void> {\n if (!this.session) {\n throw new Error('Transaction not started');\n }\n await this.session.abortTransaction();\n await this.session.endSession();\n this.session = undefined;\n }\n\n /**\n * Get session\n */\n getSession(): any {\n if (!this.session) {\n throw new Error('Transaction not started');\n }\n return this.session;\n }\n}\n\n/**\n * Seed data helper\n */\nexport class TestSeeder {\n private connection: Connection;\n\n constructor(connection: Connection) {\n this.connection = connection;\n }\n\n /**\n * Seed collection with data\n */\n async seed<T>(collectionName: string, generator: () => T[], count: number = 10): Promise<T[]> {\n const data = Array.from({ length: count }, () => generator()).flat();\n const collection = this.connection.collection(collectionName);\n const result = await collection.insertMany(data as any[]);\n\n return Object.values(result.insertedIds).map((id, index) => ({\n ...data[index],\n _id: id,\n })) as T[];\n }\n\n /**\n * Clear collection\n */\n async clear(collectionName: string): Promise<void> {\n const collection = this.connection.collection(collectionName);\n await collection.deleteMany({});\n }\n\n /**\n * Clear all collections\n */\n async clearAll(): Promise<void> {\n if (!this.connection.db) {\n throw new Error('Database not connected');\n }\n const collections = await this.connection.db.collections();\n await Promise.all(collections.map((collection) => collection.deleteMany({})));\n }\n}\n\n/**\n * Database snapshot helper for rollback testing\n */\nexport class DatabaseSnapshot {\n private snapshots: Map<string, any[]> = new Map();\n private connection: Connection;\n\n constructor(connection: Connection) {\n this.connection = connection;\n }\n\n /**\n * Take snapshot of current database state\n */\n async take(): Promise<void> {\n if (!this.connection.db) {\n throw new Error('Database not connected');\n }\n const collections = await this.connection.db.collections();\n\n for (const collection of collections) {\n const data = await collection.find({}).toArray();\n this.snapshots.set(collection.collectionName, data);\n }\n }\n\n /**\n * Restore database to snapshot\n */\n async restore(): Promise<void> {\n if (!this.connection.db) {\n throw new Error('Database not connected');\n }\n // Clear current data\n const collections = await this.connection.db.collections();\n await Promise.all(collections.map((collection) => collection.deleteMany({})));\n\n // Restore snapshot\n for (const [collectionName, data] of this.snapshots.entries()) {\n if (data.length > 0) {\n const collection = this.connection.collection(collectionName);\n await collection.insertMany(data);\n }\n }\n }\n\n /**\n * Clear snapshot\n */\n clear(): void {\n this.snapshots.clear();\n }\n}\n","/**\n * Testing Utilities - Test App Factory\n *\n * Create Fastify test instances with Arc configuration\n */\n\nimport Fastify, { type FastifyInstance } from 'fastify';\nimport type { CreateAppOptions } from '../factory/types.js';\nimport { InMemoryDatabase } from './dbHelpers.js';\n\nexport interface CreateTestAppOptions extends Partial<CreateAppOptions> {\n /**\n * Use in-memory MongoDB for faster tests (default: true)\n * Requires: mongodb-memory-server\n *\n * Set to false to use a provided mongoUri instead\n */\n useInMemoryDb?: boolean;\n\n /**\n * MongoDB connection URI (only used if useInMemoryDb is false)\n */\n mongoUri?: string;\n}\n\nexport interface TestAppResult {\n /** Fastify app instance */\n app: FastifyInstance;\n\n /**\n * Cleanup function to close app and disconnect database\n * Call this in afterAll() or afterEach()\n */\n close: () => Promise<void>;\n\n /** MongoDB connection URI (useful for connecting models) */\n mongoUri?: string;\n}\n\n/**\n * Create a test application instance with optional in-memory MongoDB\n *\n * **Performance Boost**: Uses in-memory MongoDB by default for 10x faster tests.\n *\n * @example Basic usage with in-memory DB\n * ```typescript\n * import { createTestApp } from '@classytic/arc/testing';\n *\n * describe('API Tests', () => {\n * let testApp: TestAppResult;\n *\n * beforeAll(async () => {\n * testApp = await createTestApp({\n * auth: { type: 'jwt', jwt: { secret: 'test-secret' } },\n * });\n * });\n *\n * afterAll(async () => {\n * await testApp.close(); // Cleans up DB and disconnects\n * });\n *\n * test('GET /health', async () => {\n * const response = await testApp.app.inject({\n * method: 'GET',\n * url: '/health',\n * });\n * expect(response.statusCode).toBe(200);\n * });\n * });\n * ```\n *\n * @example Using external MongoDB\n * ```typescript\n * const testApp = await createTestApp({\n * auth: { type: 'jwt', jwt: { secret: 'test-secret' } },\n * useInMemoryDb: false,\n * mongoUri: 'mongodb://localhost:27017/test-db',\n * });\n * ```\n *\n * @example Accessing MongoDB URI for model connections\n * ```typescript\n * const testApp = await createTestApp({\n * auth: { type: 'jwt', jwt: { secret: 'test-secret' } },\n * });\n * await mongoose.connect(testApp.mongoUri); // Connect your models\n * ```\n */\nexport async function createTestApp(\n options: CreateTestAppOptions = {}\n): Promise<TestAppResult> {\n const { createApp } = await import('../factory/createApp.js');\n const { useInMemoryDb = true, mongoUri: providedMongoUri, ...appOptions } = options;\n\n // Default auth config for tests\n const defaultAuth = { type: 'jwt' as const, jwt: { secret: 'test-secret-32-chars-minimum-len' } };\n\n let inMemoryDb: InMemoryDatabase | null = null;\n let mongoUri: string | undefined = providedMongoUri;\n\n // Start in-memory MongoDB if enabled and no URI provided\n if (useInMemoryDb && !providedMongoUri) {\n try {\n inMemoryDb = new InMemoryDatabase();\n mongoUri = await inMemoryDb.start();\n } catch (err) {\n console.warn(\n '[createTestApp] Failed to start in-memory MongoDB:',\n (err as Error).message,\n '\\nFalling back to external MongoDB or no DB connection.'\n );\n }\n }\n\n const testDefaults: Partial<CreateAppOptions> = {\n preset: 'testing',\n logger: false, // Disable logging in tests\n helmet: false,\n cors: false,\n rateLimit: false,\n underPressure: false,\n auth: defaultAuth,\n };\n\n const app = await createApp({\n ...testDefaults,\n ...appOptions, // User options override defaults (including auth)\n });\n\n // Return app with cleanup function\n return {\n app,\n mongoUri,\n async close() {\n await app.close();\n if (inMemoryDb) {\n await inMemoryDb.stop();\n }\n },\n };\n}\n\n/**\n * Create a minimal Fastify instance for unit tests\n *\n * Use when you don't need Arc's full plugin stack\n *\n * @example\n * const app = createMinimalTestApp();\n * app.get('/test', async () => ({ success: true }));\n *\n * const response = await app.inject({ method: 'GET', url: '/test' });\n * expect(response.json()).toEqual({ success: true });\n */\nexport function createMinimalTestApp(options: Partial<any> = {}): FastifyInstance {\n return Fastify({\n logger: false,\n ...options,\n });\n}\n\n/**\n * Test request builder for cleaner tests\n *\n * @example\n * const request = new TestRequestBuilder(app)\n * .get('/products')\n * .withAuth(mockUser)\n * .withQuery({ page: 1, limit: 10 });\n *\n * const response = await request.send();\n * expect(response.statusCode).toBe(200);\n */\nexport class TestRequestBuilder {\n private method: string = 'GET';\n private url: string = '/';\n private body?: any;\n private query?: Record<string, any>;\n private headers: Record<string, string> = {};\n private app: FastifyInstance;\n\n constructor(app: FastifyInstance) {\n this.app = app;\n }\n\n get(url: string) {\n this.method = 'GET';\n this.url = url;\n return this;\n }\n\n post(url: string) {\n this.method = 'POST';\n this.url = url;\n return this;\n }\n\n put(url: string) {\n this.method = 'PUT';\n this.url = url;\n return this;\n }\n\n patch(url: string) {\n this.method = 'PATCH';\n this.url = url;\n return this;\n }\n\n delete(url: string) {\n this.method = 'DELETE';\n this.url = url;\n return this;\n }\n\n withBody(body: any) {\n this.body = body;\n return this;\n }\n\n withQuery(query: Record<string, any>) {\n this.query = query;\n return this;\n }\n\n withHeader(key: string, value: string) {\n this.headers[key] = value;\n return this;\n }\n\n withAuth(userOrHeaders: Record<string, unknown>) {\n if ('authorization' in userOrHeaders || 'Authorization' in userOrHeaders) {\n // Pre-built headers (Better Auth tokens, external auth)\n for (const [key, value] of Object.entries(userOrHeaders)) {\n if (typeof value === 'string') {\n this.headers[key] = value;\n }\n }\n } else {\n // JWT payload — sign with app's JWT plugin\n const token = this.app.jwt?.sign?.(userOrHeaders) || 'mock-token';\n this.headers['Authorization'] = `Bearer ${token}`;\n }\n return this;\n }\n\n withContentType(type: string) {\n this.headers['Content-Type'] = type;\n return this;\n }\n\n async send() {\n return this.app.inject({\n method: this.method as any,\n url: this.url,\n payload: this.body,\n query: this.query,\n headers: this.headers,\n });\n }\n}\n\n/**\n * Helper to create a test request builder\n */\nexport function request(app: FastifyInstance) {\n return new TestRequestBuilder(app);\n}\n\n/**\n * Test helper for authentication\n */\nexport function createTestAuth(app: FastifyInstance) {\n return {\n /**\n * Generate a JWT token for testing\n */\n generateToken(user: any): string {\n if (!app.jwt) {\n throw new Error('JWT plugin not registered');\n }\n return app.jwt.sign(user);\n },\n\n /**\n * Decode a JWT token\n */\n decodeToken(token: string): any {\n if (!app.jwt) {\n throw new Error('JWT plugin not registered');\n }\n return app.jwt.decode(token);\n },\n\n /**\n * Verify a JWT token\n */\n async verifyToken(token: string): Promise<any> {\n if (!app.jwt) {\n throw new Error('JWT plugin not registered');\n }\n return app.jwt.verify(token);\n },\n };\n}\n\n/**\n * Snapshot testing helper for API responses\n */\nexport function createSnapshotMatcher() {\n return {\n /**\n * Match response structure (ignores dynamic values like timestamps)\n */\n matchStructure(response: any, expected: any): boolean {\n if (typeof response !== typeof expected) {\n return false;\n }\n\n if (Array.isArray(response) && Array.isArray(expected)) {\n return response.length === expected.length;\n }\n\n if (typeof response === 'object' && response !== null) {\n const responseKeys = Object.keys(response).sort();\n const expectedKeys = Object.keys(expected).sort();\n\n if (JSON.stringify(responseKeys) !== JSON.stringify(expectedKeys)) {\n return false;\n }\n\n for (const key of responseKeys) {\n if (!this.matchStructure(response[key], expected[key])) {\n return false;\n }\n }\n\n return true;\n }\n\n return true; // Primitives - don't compare values\n },\n };\n}\n\n/**\n * Bulk test data loader\n */\nexport class TestDataLoader {\n private data: Map<string, any[]> = new Map();\n private app: FastifyInstance;\n\n constructor(app: FastifyInstance) {\n this.app = app;\n }\n\n /**\n * Load test data into database\n */\n async load(collection: string, items: any[]) {\n // Store for cleanup\n this.data.set(collection, items);\n\n // Load into database (assumes mongoose/mongodb)\n // This is a placeholder - implement based on your DB setup\n return items;\n }\n\n /**\n * Clear all loaded test data\n */\n async cleanup() {\n for (const [collection, items] of this.data.entries()) {\n // Cleanup logic here\n // e.g., await Model.deleteMany({ _id: { $in: items.map(i => i._id) } })\n }\n this.data.clear();\n }\n}\n","/**\n * Testing Utilities - Mock Factories\n *\n * Create mock repositories, controllers, and services for testing.\n * Uses Vitest for mocking (compatible with Jest API).\n */\n\nimport { vi, type Mock } from 'vitest';\nimport type { CrudRepository, AnyRecord, PaginatedResult } from '../types/index.js';\n\n/**\n * Extended repository interface for testing (includes optional preset methods)\n */\nexport interface MockRepository<T> extends CrudRepository<T> {\n // Optional preset methods for testing\n getBySlug?: Mock;\n getDeleted?: Mock;\n restore?: Mock;\n getTree?: Mock;\n getChildren?: Mock;\n [key: string]: unknown;\n}\n\n/**\n * Create a mock repository for testing\n *\n * @example\n * const mockRepo = createMockRepository<Product>({\n * getById: vi.fn().mockResolvedValue({ id: '1', name: 'Test' }),\n * create: vi.fn().mockImplementation(data => Promise.resolve({ id: '1', ...data })),\n * });\n *\n * await mockRepo.getById('1'); // Returns mocked product\n */\nexport function createMockRepository<T extends AnyRecord = AnyRecord>(\n overrides: Partial<MockRepository<T>> = {}\n): MockRepository<T> {\n const defaultMock: MockRepository<T> = {\n // MongoKit-compatible CRUD methods\n getAll: vi.fn().mockResolvedValue({\n docs: [],\n total: 0,\n page: 1,\n limit: 20,\n pages: 0,\n hasNext: false,\n hasPrev: false,\n } as PaginatedResult<T>),\n\n getById: vi.fn().mockResolvedValue(null),\n\n create: vi.fn().mockImplementation((data: Partial<T>) =>\n Promise.resolve({ _id: 'mock-id', ...data } as unknown as T)\n ),\n\n update: vi.fn().mockImplementation((_id: string, data: Partial<T>) =>\n Promise.resolve({ _id: 'mock-id', ...data } as unknown as T)\n ),\n\n delete: vi.fn().mockResolvedValue({ success: true, message: 'Deleted' }),\n\n // Optional preset methods\n getBySlug: vi.fn().mockResolvedValue(null),\n getDeleted: vi.fn().mockResolvedValue([]),\n restore: vi.fn().mockResolvedValue(null),\n getTree: vi.fn().mockResolvedValue([]),\n getChildren: vi.fn().mockResolvedValue([]),\n\n // Apply overrides\n ...overrides,\n };\n\n return defaultMock;\n}\n\n/**\n * Create a mock user for authentication testing\n */\nexport function createMockUser(overrides: Partial<AnyRecord> = {}) {\n return {\n _id: 'mock-user-id',\n id: 'mock-user-id',\n email: 'test@example.com',\n roles: ['user'],\n organizationId: null,\n ...overrides,\n };\n}\n\n/**\n * Create a mock Fastify request\n */\nexport function createMockRequest(overrides: Partial<AnyRecord> = {}) {\n return {\n body: {},\n params: {},\n query: {},\n headers: {},\n user: createMockUser(),\n context: {},\n log: {\n info: vi.fn(),\n warn: vi.fn(),\n error: vi.fn(),\n debug: vi.fn(),\n },\n ...overrides,\n } as unknown;\n}\n\n/**\n * Create a mock Fastify reply\n */\nexport function createMockReply() {\n const reply = {\n code: vi.fn().mockReturnThis(),\n send: vi.fn().mockReturnThis(),\n header: vi.fn().mockReturnThis(),\n headers: vi.fn().mockReturnThis(),\n status: vi.fn().mockReturnThis(),\n type: vi.fn().mockReturnThis(),\n redirect: vi.fn().mockReturnThis(),\n callNotFound: vi.fn().mockReturnThis(),\n sent: false,\n };\n\n return reply as unknown;\n}\n\n/**\n * Create a mock controller for testing\n */\nexport function createMockController(repository: CrudRepository<AnyRecord>) {\n return {\n repository,\n list: vi.fn(),\n get: vi.fn(),\n create: vi.fn(),\n update: vi.fn(),\n delete: vi.fn(),\n };\n}\n\n/**\n * Create mock data factory\n *\n * @example\n * const productFactory = createDataFactory<Product>({\n * name: () => faker.commerce.productName(),\n * price: () => faker.number.int({ min: 10, max: 1000 }),\n * sku: (i) => `SKU-${i}`,\n * });\n *\n * const product = productFactory.build();\n * const products = productFactory.buildMany(10);\n */\nexport function createDataFactory<T extends AnyRecord>(\n template: Record<keyof T, (index: number) => unknown>\n) {\n let counter = 0;\n\n return {\n build(overrides: Partial<T> = {}): T {\n const index = counter++;\n const data = {} as T;\n\n for (const [key, generator] of Object.entries(template)) {\n (data as AnyRecord)[key] = generator(index);\n }\n\n return { ...data, ...overrides };\n },\n\n buildMany(count: number, overrides: Partial<T> = {}): T[] {\n return Array.from({ length: count }, () => this.build(overrides));\n },\n\n reset() {\n counter = 0;\n },\n };\n}\n\n/**\n * Create a spy that tracks function calls\n *\n * Useful for testing side effects without full mocking\n */\nexport function createSpy<T extends (...args: unknown[]) => unknown>(\n _name = 'spy'\n): Mock<T> & { getCalls(): unknown[][]; getLastCall(): unknown[] } {\n const calls: unknown[][] = [];\n\n const spy = vi.fn((...args: unknown[]) => {\n calls.push(args);\n }) as Mock<T> & { getCalls(): unknown[][]; getLastCall(): unknown[] };\n\n spy.getCalls = () => calls;\n spy.getLastCall = () => calls[calls.length - 1] || [];\n\n return spy;\n}\n\n/**\n * Wait for a condition to be true\n *\n * Useful for async testing\n */\nexport async function waitFor(\n condition: () => boolean | Promise<boolean>,\n options: { timeout?: number; interval?: number } = {}\n): Promise<void> {\n const { timeout = 5000, interval = 100 } = options;\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n if (await condition()) {\n return;\n }\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n\n throw new Error(`Timeout waiting for condition after ${timeout}ms`);\n}\n\n/**\n * Create a test timer that can be controlled\n */\nexport function createTestTimer() {\n let time = Date.now();\n\n return {\n now: () => time,\n advance: (ms: number) => {\n time += ms;\n },\n set: (timestamp: number) => {\n time = timestamp;\n },\n reset: () => {\n time = Date.now();\n },\n };\n}\n","/**\r\n * Better Auth Test Helpers\r\n *\r\n * Reusable primitives for testing Arc apps that use Better Auth.\r\n * Extracted from common patterns in app-level test setups.\r\n *\r\n * @example Basic helpers\r\n * ```typescript\r\n * import { createBetterAuthTestHelpers } from '@classytic/arc/testing';\r\n *\r\n * const auth = createBetterAuthTestHelpers();\r\n * const signup = await auth.signUp(app, { email: 'test@example.com', password: 'pass', name: 'Test' });\r\n * const headers = auth.authHeaders(signup.token, orgId);\r\n * ```\r\n *\r\n * @example Full org setup\r\n * ```typescript\r\n * import { setupBetterAuthOrg } from '@classytic/arc/testing';\r\n *\r\n * const ctx = await setupBetterAuthOrg({\r\n * createApp: () => createAppInstance(),\r\n * org: { name: 'Test Corp', slug: 'test-corp' },\r\n * users: [\r\n * { key: 'admin', email: 'admin@test.com', password: 'pass', name: 'Admin', role: 'admin', isCreator: true },\r\n * { key: 'member', email: 'user@test.com', password: 'pass', name: 'User', role: 'member' },\r\n * ],\r\n * addMember: async (data) => { await auth.api.addMember({ body: data }); return { statusCode: 200 }; },\r\n * });\r\n *\r\n * // ctx.app, ctx.orgId, ctx.users.admin.token, ctx.teardown()\r\n * ```\r\n */\r\n\r\nimport type { FastifyInstance } from 'fastify';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport interface BetterAuthTestHelpersOptions {\r\n /** Base path for auth routes (default: '/api/auth') */\r\n basePath?: string;\r\n}\r\n\r\nexport interface AuthResponse {\r\n statusCode: number;\r\n token: string;\r\n user: any;\r\n body: any;\r\n}\r\n\r\nexport interface OrgResponse {\r\n statusCode: number;\r\n orgId: string;\r\n body: any;\r\n}\r\n\r\nexport interface BetterAuthTestHelpers {\r\n signUp(app: FastifyInstance, data: { email: string; password: string; name: string }): Promise<AuthResponse>;\r\n signIn(app: FastifyInstance, data: { email: string; password: string }): Promise<AuthResponse>;\r\n createOrg(app: FastifyInstance, token: string, data: { name: string; slug: string }): Promise<OrgResponse>;\r\n setActiveOrg(app: FastifyInstance, token: string, orgId: string): Promise<{ statusCode: number; body: any }>;\r\n authHeaders(token: string, orgId?: string): Record<string, string>;\r\n}\r\n\r\nexport interface TestUserContext {\r\n token: string;\r\n userId: string;\r\n email: string;\r\n}\r\n\r\nexport interface TestOrgContext<T = Record<string, TestUserContext>> {\r\n app: FastifyInstance;\r\n orgId: string;\r\n users: T;\r\n teardown: () => Promise<void>;\r\n}\r\n\r\nexport interface SetupUserConfig {\r\n /** Key used to reference this user in the context (e.g. 'admin', 'member') */\r\n key: string;\r\n email: string;\r\n password: string;\r\n name: string;\r\n /** Organization role assigned after joining */\r\n role: string;\r\n /** If true, this user creates the org (becomes org owner). Exactly one user should have this. */\r\n isCreator?: boolean;\r\n}\r\n\r\nexport interface SetupBetterAuthOrgOptions {\r\n /** Factory function to create the Fastify app instance */\r\n createApp: () => Promise<FastifyInstance>;\r\n /** Organization to create */\r\n org: { name: string; slug: string };\r\n /** Users to create and add to the organization */\r\n users: SetupUserConfig[];\r\n /**\r\n * Callback to add a member to the org.\r\n * Apps wire Better Auth differently — some use auth.api.addMember, others use HTTP.\r\n */\r\n addMember: (data: { organizationId: string; userId: string; role: string }) => Promise<{ statusCode: number }>;\r\n /**\r\n * Optional hook for app-specific initialization after all users are set up.\r\n * Use this for things like recruiter→account manager hierarchy.\r\n */\r\n afterSetup?: (ctx: TestOrgContext) => Promise<void>;\r\n /** Override auth helper options (e.g. custom basePath) */\r\n authHelpers?: BetterAuthTestHelpersOptions;\r\n}\r\n\r\n// ============================================================================\r\n// Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Safely parse a JSON response body.\r\n * Returns null if parsing fails.\r\n */\r\nexport function safeParseBody(body: string): any {\r\n try {\r\n return JSON.parse(body);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Better Auth Test Helpers Factory\r\n// ============================================================================\r\n\r\n/**\r\n * Create stateless Better Auth test helpers.\r\n *\r\n * All methods take the app instance as a parameter, making them\r\n * safe to use across multiple test suites.\r\n */\r\nexport function createBetterAuthTestHelpers(\r\n options: BetterAuthTestHelpersOptions = {},\r\n): BetterAuthTestHelpers {\r\n const basePath = options.basePath ?? '/api/auth';\r\n\r\n return {\r\n async signUp(app, data) {\r\n const res = await app.inject({\r\n method: 'POST',\r\n url: `${basePath}/sign-up/email`,\r\n payload: data,\r\n });\r\n const token = res.headers['set-auth-token'] as string | undefined;\r\n const body = safeParseBody(res.body);\r\n return {\r\n statusCode: res.statusCode,\r\n token: token || '',\r\n user: body?.user || body,\r\n body,\r\n };\r\n },\r\n\r\n async signIn(app, data) {\r\n const res = await app.inject({\r\n method: 'POST',\r\n url: `${basePath}/sign-in/email`,\r\n payload: data,\r\n });\r\n const token = res.headers['set-auth-token'] as string | undefined;\r\n const body = safeParseBody(res.body);\r\n return {\r\n statusCode: res.statusCode,\r\n token: token || '',\r\n user: body?.user || body,\r\n body,\r\n };\r\n },\r\n\r\n async createOrg(app, token, data) {\r\n const res = await app.inject({\r\n method: 'POST',\r\n url: `${basePath}/organization/create`,\r\n headers: { authorization: `Bearer ${token}` },\r\n payload: data,\r\n });\r\n const body = safeParseBody(res.body);\r\n return {\r\n statusCode: res.statusCode,\r\n orgId: body?.id,\r\n body,\r\n };\r\n },\r\n\r\n async setActiveOrg(app, token, orgId) {\r\n const res = await app.inject({\r\n method: 'POST',\r\n url: `${basePath}/organization/set-active`,\r\n headers: { authorization: `Bearer ${token}` },\r\n payload: { organizationId: orgId },\r\n });\r\n return {\r\n statusCode: res.statusCode,\r\n body: safeParseBody(res.body),\r\n };\r\n },\r\n\r\n authHeaders(token, orgId?) {\r\n const h: Record<string, string> = { authorization: `Bearer ${token}` };\r\n if (orgId) h['x-organization-id'] = orgId;\r\n return h;\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Composite Org Setup\r\n// ============================================================================\r\n\r\n/**\r\n * Set up a complete test organization with users.\r\n *\r\n * Creates the app, signs up users, creates an org, adds members,\r\n * and returns a context object with tokens and a teardown function.\r\n *\r\n * @example\r\n * ```typescript\r\n * const ctx = await setupBetterAuthOrg({\r\n * createApp: () => createAppInstance(),\r\n * org: { name: 'Test Corp', slug: 'test-corp' },\r\n * users: [\r\n * { key: 'admin', email: 'admin@test.com', password: 'pass', name: 'Admin', role: 'admin', isCreator: true },\r\n * { key: 'member', email: 'user@test.com', password: 'pass', name: 'User', role: 'member' },\r\n * ],\r\n * addMember: async (data) => {\r\n * await auth.api.addMember({ body: data });\r\n * return { statusCode: 200 };\r\n * },\r\n * });\r\n *\r\n * // Use in tests:\r\n * const res = await ctx.app.inject({\r\n * method: 'GET',\r\n * url: '/api/products',\r\n * headers: auth.authHeaders(ctx.users.admin.token, ctx.orgId),\r\n * });\r\n *\r\n * // Cleanup:\r\n * await ctx.teardown();\r\n * ```\r\n */\r\nexport async function setupBetterAuthOrg(\r\n options: SetupBetterAuthOrgOptions,\r\n): Promise<TestOrgContext> {\r\n const {\r\n createApp,\r\n org,\r\n users: userConfigs,\r\n addMember,\r\n afterSetup,\r\n authHelpers: helpersOptions,\r\n } = options;\r\n\r\n const helpers = createBetterAuthTestHelpers(helpersOptions);\r\n\r\n // Validate: exactly one creator\r\n const creators = userConfigs.filter((u) => u.isCreator);\r\n if (creators.length !== 1) {\r\n throw new Error(\r\n `setupBetterAuthOrg: Exactly one user must have isCreator: true (found ${creators.length})`,\r\n );\r\n }\r\n\r\n // 1. Create app\r\n const app = await createApp();\r\n await app.ready();\r\n\r\n // 2. Sign up all users\r\n const signups = new Map<string, AuthResponse>();\r\n for (const userConfig of userConfigs) {\r\n const signup = await helpers.signUp(app, {\r\n email: userConfig.email,\r\n password: userConfig.password,\r\n name: userConfig.name,\r\n });\r\n if (signup.statusCode !== 200) {\r\n throw new Error(\r\n `setupBetterAuthOrg: Failed to sign up ${userConfig.email} (status ${signup.statusCode})`,\r\n );\r\n }\r\n signups.set(userConfig.key, signup);\r\n }\r\n\r\n // 3. Create org (by the creator)\r\n const creatorConfig = creators[0]!;\r\n const creatorSignup = signups.get(creatorConfig.key)!;\r\n const orgResult = await helpers.createOrg(app, creatorSignup.token, org);\r\n if (orgResult.statusCode !== 200) {\r\n throw new Error(\r\n `setupBetterAuthOrg: Failed to create org (status ${orgResult.statusCode})`,\r\n );\r\n }\r\n const orgId = orgResult.orgId;\r\n\r\n // 4. Add non-creator members\r\n for (const userConfig of userConfigs) {\r\n if (userConfig.isCreator) continue;\r\n const signup = signups.get(userConfig.key)!;\r\n const result = await addMember({\r\n organizationId: orgId,\r\n userId: signup.user?.id,\r\n role: userConfig.role,\r\n });\r\n if (result.statusCode !== 200) {\r\n throw new Error(\r\n `setupBetterAuthOrg: Failed to add member ${userConfig.email} (status ${result.statusCode})`,\r\n );\r\n }\r\n }\r\n\r\n // 5. Set active org + re-login to get fresh tokens\r\n await helpers.setActiveOrg(app, creatorSignup.token, orgId);\r\n\r\n const users: Record<string, TestUserContext> = {};\r\n for (const userConfig of userConfigs) {\r\n if (userConfig.isCreator) {\r\n const signup = signups.get(userConfig.key)!;\r\n users[userConfig.key] = {\r\n token: signup.token,\r\n userId: signup.user?.id,\r\n email: userConfig.email,\r\n };\r\n } else {\r\n // Re-login to get token with org context\r\n const login = await helpers.signIn(app, {\r\n email: userConfig.email,\r\n password: userConfig.password,\r\n });\r\n await helpers.setActiveOrg(app, login.token, orgId);\r\n users[userConfig.key] = {\r\n token: login.token,\r\n userId: signups.get(userConfig.key)!.user?.id,\r\n email: userConfig.email,\r\n };\r\n }\r\n }\r\n\r\n const ctx: TestOrgContext = {\r\n app,\r\n orgId,\r\n users,\r\n async teardown() {\r\n await app.close();\r\n },\r\n };\r\n\r\n // 6. Run app-specific post-setup\r\n if (afterSetup) {\r\n await afterSetup(ctx);\r\n }\r\n\r\n return ctx;\r\n}\r\n","/**\r\n * HTTP Test Harness\r\n *\r\n * Generates HTTP-level CRUD tests for Arc resources using `app.inject()`.\r\n * Unlike TestHarness (which tests Mongoose models directly), this exercises\r\n * the full request lifecycle: HTTP routes, auth, permissions, pipeline,\r\n * field permissions, and the Arc response envelope.\r\n *\r\n * Supports both eager and deferred options:\r\n * - **Eager**: Pass options directly when app is available at construction time\r\n * - **Deferred**: Pass a getter function when app comes from async setup (beforeAll)\r\n *\r\n * @example Eager (app available at module level)\r\n * ```typescript\r\n * const harness = createHttpTestHarness(jobResource, {\r\n * app,\r\n * fixtures: { valid: { title: 'Test' } },\r\n * auth: createJwtAuthProvider({ app, users, adminRole: 'admin' }),\r\n * });\r\n * harness.runAll();\r\n * ```\r\n *\r\n * @example Deferred (app from beforeAll)\r\n * ```typescript\r\n * let ctx: TestContext;\r\n * beforeAll(async () => { ctx = await setupTestOrg(); });\r\n * afterAll(async () => { await teardownTestOrg(ctx); });\r\n *\r\n * const harness = createHttpTestHarness(jobResource, () => ({\r\n * app: ctx.app,\r\n * fixtures: { valid: { title: 'Test' } },\r\n * auth: createBetterAuthProvider({ tokens: { admin: ctx.users.admin.token }, orgId: ctx.orgId, adminRole: 'admin' }),\r\n * }));\r\n * harness.runAll();\r\n * ```\r\n */\r\n\r\nimport { describe, it, expect, afterAll } from 'vitest';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport type { ResourceDefinition } from '../core/defineResource.js';\r\nimport { CRUD_OPERATIONS } from '../constants.js';\r\n\r\n// ============================================================================\r\n// Auth Provider Interface\r\n// ============================================================================\r\n\r\n/**\r\n * Abstraction for generating auth headers in tests.\r\n * Supports JWT, Better Auth, or any custom auth mechanism.\r\n */\r\nexport interface AuthProvider {\r\n /** Get HTTP headers for a given role key */\r\n getHeaders(role: string): Record<string, string>;\r\n /** Available role keys (e.g. ['admin', 'member', 'viewer']) */\r\n availableRoles: string[];\r\n /** Role key that has full CRUD access */\r\n adminRole: string;\r\n}\r\n\r\n// ============================================================================\r\n// Auth Provider Factories\r\n// ============================================================================\r\n\r\n/**\r\n * Create an auth provider for JWT-based apps.\r\n *\r\n * Generates JWT tokens on the fly using the app's JWT plugin.\r\n *\r\n * @example\r\n * ```typescript\r\n * const auth = createJwtAuthProvider({\r\n * app,\r\n * users: {\r\n * admin: { payload: { id: '1', roles: ['admin'] }, organizationId: 'org1' },\r\n * viewer: { payload: { id: '2', roles: ['viewer'] } },\r\n * },\r\n * adminRole: 'admin',\r\n * });\r\n * ```\r\n */\r\nexport function createJwtAuthProvider(options: {\r\n app: FastifyInstance;\r\n users: Record<string, { payload: Record<string, unknown>; organizationId?: string }>;\r\n adminRole: string;\r\n}): AuthProvider {\r\n const { app, users, adminRole } = options;\r\n\r\n return {\r\n getHeaders(role: string): Record<string, string> {\r\n const user = users[role];\r\n if (!user) {\r\n throw new Error(`createJwtAuthProvider: Unknown role '${role}'. Available: ${Object.keys(users).join(', ')}`);\r\n }\r\n const token = (app as any).jwt?.sign?.(user.payload) || 'mock-token';\r\n const headers: Record<string, string> = {\r\n authorization: `Bearer ${token}`,\r\n };\r\n if (user.organizationId) {\r\n headers['x-organization-id'] = user.organizationId;\r\n }\r\n return headers;\r\n },\r\n availableRoles: Object.keys(users),\r\n adminRole,\r\n };\r\n}\r\n\r\n/**\r\n * Create an auth provider for Better Auth apps.\r\n *\r\n * Uses pre-existing tokens (from signUp/signIn) rather than generating them.\r\n *\r\n * @example\r\n * ```typescript\r\n * const auth = createBetterAuthProvider({\r\n * tokens: {\r\n * admin: ctx.users.admin.token,\r\n * member: ctx.users.member.token,\r\n * },\r\n * orgId: ctx.orgId,\r\n * adminRole: 'admin',\r\n * });\r\n * ```\r\n */\r\nexport function createBetterAuthProvider(options: {\r\n tokens: Record<string, string>;\r\n orgId: string;\r\n adminRole: string;\r\n}): AuthProvider {\r\n const { tokens, orgId, adminRole } = options;\r\n\r\n return {\r\n getHeaders(role: string): Record<string, string> {\r\n const token = tokens[role];\r\n if (!token) {\r\n throw new Error(`createBetterAuthProvider: No token for role '${role}'. Available: ${Object.keys(tokens).join(', ')}`);\r\n }\r\n return {\r\n authorization: `Bearer ${token}`,\r\n 'x-organization-id': orgId,\r\n };\r\n },\r\n availableRoles: Object.keys(tokens),\r\n adminRole,\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// HTTP Test Harness\r\n// ============================================================================\r\n\r\nexport interface HttpTestHarnessOptions<T = unknown> {\r\n /** Fastify app instance (must be ready) */\r\n app: FastifyInstance;\r\n /** Test data fixtures */\r\n fixtures: {\r\n /** Valid payload for creating a resource */\r\n valid: Partial<T>;\r\n /** Payload for updating a resource (defaults to valid) */\r\n update?: Partial<T>;\r\n /** Invalid payload that should fail validation */\r\n invalid?: Partial<T>;\r\n };\r\n /** Auth provider for generating request headers */\r\n auth: AuthProvider;\r\n /** API path prefix (default: '/api') */\r\n apiPrefix?: string;\r\n}\r\n\r\n/** Options can be passed directly or as a getter for deferred resolution */\r\ntype OptionsOrGetter<T> = HttpTestHarnessOptions<T> | (() => HttpTestHarnessOptions<T>);\r\n\r\n/**\r\n * HTTP-level test harness for Arc resources.\r\n *\r\n * Generates tests that exercise the full HTTP lifecycle:\r\n * routes, auth, permissions, pipeline, and response envelope.\r\n *\r\n * Supports deferred options via a getter function, which is essential\r\n * when the app instance comes from async `beforeAll()` setup.\r\n */\r\nexport class HttpTestHarness<T = unknown> {\r\n private resource: ResourceDefinition<unknown>;\r\n private optionsOrGetter: OptionsOrGetter<T>;\r\n private baseUrl: string;\r\n private enabledRoutes: Set<string>;\r\n private updateMethod: string;\r\n\r\n constructor(resource: ResourceDefinition<unknown>, optionsOrGetter: OptionsOrGetter<T>) {\r\n this.resource = resource;\r\n this.optionsOrGetter = optionsOrGetter;\r\n\r\n // These come from the resource definition (available at import time, no async needed)\r\n const apiPrefix = typeof optionsOrGetter === 'function'\r\n ? '/api'\r\n : (optionsOrGetter.apiPrefix ?? '/api');\r\n this.baseUrl = `${apiPrefix}${resource.prefix}`;\r\n\r\n // Determine which CRUD routes are enabled (from resource, not options)\r\n const disabled = new Set(resource.disabledRoutes ?? []);\r\n this.enabledRoutes = new Set(\r\n resource.disableDefaultRoutes\r\n ? []\r\n : CRUD_OPERATIONS.filter((op) => !disabled.has(op)),\r\n );\r\n\r\n this.updateMethod = resource.updateMethod === 'PUT' ? 'PUT' : 'PATCH';\r\n }\r\n\r\n /** Resolve options (supports both direct and deferred) */\r\n private getOptions(): HttpTestHarnessOptions<T> {\r\n return typeof this.optionsOrGetter === 'function'\r\n ? this.optionsOrGetter()\r\n : this.optionsOrGetter;\r\n }\r\n\r\n /**\r\n * Run all test suites: CRUD + permissions + validation\r\n */\r\n runAll(): void {\r\n this.runCrud();\r\n this.runPermissions();\r\n this.runValidation();\r\n }\r\n\r\n /**\r\n * Run HTTP-level CRUD tests.\r\n *\r\n * Tests each enabled CRUD operation through app.inject():\r\n * - POST (create) → 200/201 with { success: true, data }\r\n * - GET (list) → 200 with array or paginated response\r\n * - GET /:id → 200 with { success: true, data }\r\n * - PATCH/PUT /:id → 200 with { success: true, data }\r\n * - DELETE /:id → 200\r\n * - GET /:id with non-existent ID → 404\r\n */\r\n runCrud(): void {\r\n const { resource, baseUrl, enabledRoutes, updateMethod } = this;\r\n\r\n // Track created IDs for cleanup and cross-test references\r\n let createdId: string | null = null;\r\n\r\n describe(`${resource.displayName} HTTP CRUD`, () => {\r\n afterAll(async () => {\r\n // Cleanup: delete the created resource if still exists\r\n if (createdId && enabledRoutes.has('delete')) {\r\n const { app, auth } = this.getOptions();\r\n await app.inject({\r\n method: 'DELETE',\r\n url: `${baseUrl}/${createdId}`,\r\n headers: auth.getHeaders(auth.adminRole),\r\n });\r\n }\r\n });\r\n\r\n if (enabledRoutes.has('create')) {\r\n it('POST should create a resource', async () => {\r\n const { app, auth, fixtures } = this.getOptions();\r\n const adminHeaders = auth.getHeaders(auth.adminRole);\r\n\r\n const res = await app.inject({\r\n method: 'POST',\r\n url: baseUrl,\r\n headers: adminHeaders,\r\n payload: fixtures.valid,\r\n });\r\n\r\n expect(res.statusCode).toBeLessThan(300);\r\n const body = JSON.parse(res.body);\r\n expect(body.success).toBe(true);\r\n expect(body.data).toBeDefined();\r\n expect(body.data._id).toBeDefined();\r\n\r\n // Store for subsequent tests\r\n createdId = body.data._id;\r\n });\r\n }\r\n\r\n if (enabledRoutes.has('list')) {\r\n it('GET should list resources', async () => {\r\n const { app, auth } = this.getOptions();\r\n\r\n const res = await app.inject({\r\n method: 'GET',\r\n url: baseUrl,\r\n headers: auth.getHeaders(auth.adminRole),\r\n });\r\n\r\n expect(res.statusCode).toBe(200);\r\n const body = JSON.parse(res.body);\r\n expect(body.success).toBe(true);\r\n // Arc list responses use `data` or `docs` depending on the query parser\r\n const list = body.data ?? body.docs;\r\n expect(list).toBeDefined();\r\n expect(Array.isArray(list)).toBe(true);\r\n });\r\n }\r\n\r\n if (enabledRoutes.has('get')) {\r\n it('GET /:id should return the resource', async () => {\r\n if (!createdId) return;\r\n\r\n const { app, auth } = this.getOptions();\r\n const res = await app.inject({\r\n method: 'GET',\r\n url: `${baseUrl}/${createdId}`,\r\n headers: auth.getHeaders(auth.adminRole),\r\n });\r\n\r\n expect(res.statusCode).toBe(200);\r\n const body = JSON.parse(res.body);\r\n expect(body.success).toBe(true);\r\n expect(body.data).toBeDefined();\r\n expect(body.data._id).toBe(createdId);\r\n });\r\n\r\n it('GET /:id with non-existent ID should return 404', async () => {\r\n const { app, auth } = this.getOptions();\r\n const fakeId = '000000000000000000000000';\r\n const res = await app.inject({\r\n method: 'GET',\r\n url: `${baseUrl}/${fakeId}`,\r\n headers: auth.getHeaders(auth.adminRole),\r\n });\r\n\r\n expect(res.statusCode).toBe(404);\r\n const body = JSON.parse(res.body);\r\n expect(body.success).toBe(false);\r\n });\r\n }\r\n\r\n if (enabledRoutes.has('update')) {\r\n it(`${updateMethod} /:id should update the resource`, async () => {\r\n if (!createdId) return;\r\n\r\n const { app, auth, fixtures } = this.getOptions();\r\n const updatePayload = fixtures.update || fixtures.valid;\r\n const res = await app.inject({\r\n method: updateMethod as any,\r\n url: `${baseUrl}/${createdId}`,\r\n headers: auth.getHeaders(auth.adminRole),\r\n payload: updatePayload,\r\n });\r\n\r\n expect(res.statusCode).toBe(200);\r\n const body = JSON.parse(res.body);\r\n expect(body.success).toBe(true);\r\n expect(body.data).toBeDefined();\r\n });\r\n\r\n it(`${updateMethod} /:id with non-existent ID should return 404`, async () => {\r\n const { app, auth, fixtures } = this.getOptions();\r\n const fakeId = '000000000000000000000000';\r\n const res = await app.inject({\r\n method: updateMethod as any,\r\n url: `${baseUrl}/${fakeId}`,\r\n headers: auth.getHeaders(auth.adminRole),\r\n payload: fixtures.update || fixtures.valid,\r\n });\r\n\r\n expect(res.statusCode).toBe(404);\r\n });\r\n }\r\n\r\n if (enabledRoutes.has('delete')) {\r\n it('DELETE /:id should delete the resource', async () => {\r\n const { app, auth, fixtures } = this.getOptions();\r\n const adminHeaders = auth.getHeaders(auth.adminRole);\r\n\r\n // Create a separate resource for deletion to avoid affecting other tests\r\n let deleteId: string | undefined;\r\n\r\n if (enabledRoutes.has('create')) {\r\n const createRes = await app.inject({\r\n method: 'POST',\r\n url: baseUrl,\r\n headers: adminHeaders,\r\n payload: fixtures.valid,\r\n });\r\n deleteId = JSON.parse(createRes.body).data?._id;\r\n }\r\n\r\n if (!deleteId) return;\r\n\r\n const res = await app.inject({\r\n method: 'DELETE',\r\n url: `${baseUrl}/${deleteId}`,\r\n headers: adminHeaders,\r\n });\r\n\r\n expect(res.statusCode).toBe(200);\r\n\r\n // Verify it's gone\r\n if (enabledRoutes.has('get')) {\r\n const getRes = await app.inject({\r\n method: 'GET',\r\n url: `${baseUrl}/${deleteId}`,\r\n headers: adminHeaders,\r\n });\r\n expect(getRes.statusCode).toBe(404);\r\n }\r\n });\r\n\r\n it('DELETE /:id with non-existent ID should return 404', async () => {\r\n const { app, auth } = this.getOptions();\r\n const fakeId = '000000000000000000000000';\r\n const res = await app.inject({\r\n method: 'DELETE',\r\n url: `${baseUrl}/${fakeId}`,\r\n headers: auth.getHeaders(auth.adminRole),\r\n });\r\n\r\n expect(res.statusCode).toBe(404);\r\n });\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Run permission tests.\r\n *\r\n * Tests that:\r\n * - Unauthenticated requests return 401\r\n * - Admin role gets 2xx for all operations\r\n */\r\n runPermissions(): void {\r\n const { resource, baseUrl, enabledRoutes, updateMethod } = this;\r\n\r\n describe(`${resource.displayName} HTTP Permissions`, () => {\r\n if (enabledRoutes.has('list')) {\r\n it('GET list without auth should return 401', async () => {\r\n const { app } = this.getOptions();\r\n const res = await app.inject({ method: 'GET', url: baseUrl });\r\n expect(res.statusCode).toBe(401);\r\n });\r\n }\r\n\r\n if (enabledRoutes.has('get')) {\r\n it('GET get without auth should return 401', async () => {\r\n const { app } = this.getOptions();\r\n const res = await app.inject({ method: 'GET', url: `${baseUrl}/000000000000000000000000` });\r\n expect(res.statusCode).toBe(401);\r\n });\r\n }\r\n\r\n if (enabledRoutes.has('create')) {\r\n it('POST create without auth should return 401', async () => {\r\n const { app, fixtures } = this.getOptions();\r\n const res = await app.inject({ method: 'POST', url: baseUrl, payload: fixtures.valid });\r\n expect(res.statusCode).toBe(401);\r\n });\r\n }\r\n\r\n if (enabledRoutes.has('update')) {\r\n it(`${updateMethod} update without auth should return 401`, async () => {\r\n const { app, fixtures } = this.getOptions();\r\n const res = await app.inject({\r\n method: updateMethod as any,\r\n url: `${baseUrl}/000000000000000000000000`,\r\n payload: fixtures.update || fixtures.valid,\r\n });\r\n expect(res.statusCode).toBe(401);\r\n });\r\n }\r\n\r\n if (enabledRoutes.has('delete')) {\r\n it('DELETE delete without auth should return 401', async () => {\r\n const { app } = this.getOptions();\r\n const res = await app.inject({ method: 'DELETE', url: `${baseUrl}/000000000000000000000000` });\r\n expect(res.statusCode).toBe(401);\r\n });\r\n }\r\n\r\n // Admin access tests\r\n if (enabledRoutes.has('list')) {\r\n it('admin should access list endpoint', async () => {\r\n const { app, auth } = this.getOptions();\r\n const res = await app.inject({\r\n method: 'GET',\r\n url: baseUrl,\r\n headers: auth.getHeaders(auth.adminRole),\r\n });\r\n expect(res.statusCode).toBeLessThan(400);\r\n });\r\n }\r\n\r\n if (enabledRoutes.has('create')) {\r\n it('admin should access create endpoint', async () => {\r\n const { app, auth, fixtures } = this.getOptions();\r\n const res = await app.inject({\r\n method: 'POST',\r\n url: baseUrl,\r\n headers: auth.getHeaders(auth.adminRole),\r\n payload: fixtures.valid,\r\n });\r\n expect(res.statusCode).toBeLessThan(400);\r\n\r\n // Cleanup\r\n const body = JSON.parse(res.body);\r\n if (body.data?._id && enabledRoutes.has('delete')) {\r\n await app.inject({\r\n method: 'DELETE',\r\n url: `${baseUrl}/${body.data._id}`,\r\n headers: auth.getHeaders(auth.adminRole),\r\n });\r\n }\r\n });\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Run validation tests.\r\n *\r\n * Tests that invalid payloads return 400.\r\n */\r\n runValidation(): void {\r\n const { resource, baseUrl, enabledRoutes } = this;\r\n\r\n if (!enabledRoutes.has('create')) return;\r\n\r\n describe(`${resource.displayName} HTTP Validation`, () => {\r\n it('POST with invalid payload should not return 2xx', async () => {\r\n const { app, auth, fixtures } = this.getOptions();\r\n if (!fixtures.invalid) return;\r\n\r\n const res = await app.inject({\r\n method: 'POST',\r\n url: baseUrl,\r\n headers: auth.getHeaders(auth.adminRole),\r\n payload: fixtures.invalid,\r\n });\r\n\r\n // Invalid payload should be rejected — 400 (schema validation) or\r\n // 422/500 (model validation) depending on whether JSON Schema is configured\r\n expect(res.statusCode).toBeGreaterThanOrEqual(400);\r\n const body = JSON.parse(res.body);\r\n expect(body.success).toBe(false);\r\n });\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * Create an HTTP test harness for an Arc resource.\r\n *\r\n * Accepts options directly or as a getter function for deferred resolution.\r\n *\r\n * @example Deferred (recommended for async setup)\r\n * ```typescript\r\n * let ctx: TestContext;\r\n * beforeAll(async () => { ctx = await setupTestOrg(); });\r\n *\r\n * createHttpTestHarness(jobResource, () => ({\r\n * app: ctx.app,\r\n * fixtures: { valid: { title: 'Test' } },\r\n * auth: createBetterAuthProvider({ ... }),\r\n * })).runAll();\r\n * ```\r\n */\r\nexport function createHttpTestHarness<T = unknown>(\r\n resource: ResourceDefinition<unknown>,\r\n optionsOrGetter: HttpTestHarnessOptions<T> | (() => HttpTestHarnessOptions<T>),\r\n): HttpTestHarness<T> {\r\n return new HttpTestHarness<T>(resource, optionsOrGetter);\r\n}\r\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tracing-Cc7vVQPp.d.mts","names":[],"sources":["../src/plugins/tracing.ts"],"mappings":";;;UA6DiB,cAAA;EA0Bf;;AACW;EAvBX,WAAA;;;;;EAMA,WAAA;EAsBwB;;;AAAA;EAhBxB,mBAAA;;;;;EAMA,UAAA;AAAA;AAAA,UAGQ,aAAA;EACR,MAAA;EACA,WAAA;AAAA;AAAA;EAAA,UAIU,cAAA;IACR,MAAA,GAAS,aAAA;EAAA;AAAA;;;;iBAqCE,aAAA,CAAc,OAAA,EAAS,eAAA,EAAiB,OAAA,GAAS,cAAA,GAAmB,OAAA;;;;;;;;;;;;;;iBAiInE,UAAA,GAAA,CACd,OAAA,EAAS,cAAA,EACT,IAAA,UACA,EAAA,GAAK,IAAA,UAAc,OAAA,CAAQ,CAAA,GAC3B,UAAA,GAAa,MAAA,gBACZ,OAAA,CAAQ,CAAA;;;;;;AA8CX;;;;;;iBAAgB,MAAA,CAAO,QAAA,aACJ,MAAA,OAAa,WAAA,UAAqB,UAAA,EAAY,kBAAA,KAAkB,kBAAA;;;;iBA6BnE,kBAAA,CAAA;AAAA,cAEf,QAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"typeGuards-DhMNLuvU.mjs","names":[],"sources":["../src/utils/typeGuards.ts"],"sourcesContent":["/**\r\n * Shared Type Guards\r\n *\r\n * Reusable type narrowing for Fastify plugin decorators.\r\n * Eliminates inline `'events' in fastify && ...` checks across the codebase.\r\n */\r\n\r\nimport type { FastifyInstance } from 'fastify';\r\n\r\nexport interface EventsDecorator {\r\n publish: <T>(type: string, payload: T, meta?: Record<string, unknown>) => Promise<void>;\r\n subscribe: (pattern: string, handler: (event: { type: string; payload: unknown; meta: Record<string, unknown> }) => Promise<void>) => Promise<() => void>;\r\n transportName: string;\r\n}\r\n\r\n/** Check if fastify has the events plugin registered */\r\nexport function hasEvents(instance: FastifyInstance): instance is FastifyInstance & { events: EventsDecorator } {\r\n const inst = instance as unknown as Record<string, unknown>;\r\n return inst.events != null && typeof (inst.events as Record<string, unknown>).publish === 'function';\r\n}\r\n"],"mappings":";;AAgBA,SAAgB,UAAU,UAAsF;CAC9G,MAAM,OAAO;AACb,QAAO,KAAK,UAAU,QAAQ,OAAQ,KAAK,OAAmC,YAAY"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/types/index.ts"],"mappings":"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"}
|
package/dist/types/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":["/**\n * Arc Framework Types\n *\n * Clean, type-safe interfaces for the Arc framework.\n * Modern TypeScript patterns - no `any`, proper generics.\n */\n\nimport type { FastifyInstance, FastifyReply, FastifyRequest, RouteHandlerMethod } from 'fastify';\nimport type { Types } from 'mongoose';\nimport type { DataAdapter } from '../adapters/interface.js';\nimport type { PermissionCheck, UserBase } from '../permissions/types.js';\nimport type { RequestScope } from '../scope/types.js';\n\n// Re-export core types\nexport type { RouteHandlerMethod } from 'fastify';\n// Re-export scope types\nexport type { RequestScope } from '../scope/types.js';\nexport {\n isMember,\n isElevated,\n hasOrgAccess,\n isAuthenticated,\n getOrgId,\n getOrgRoles,\n getTeamId,\n PUBLIC_SCOPE,\n AUTHENTICATED_SCOPE,\n} from '../scope/types.js';\nexport type { ElevationOptions, ElevationEvent } from '../scope/elevation.js';\n\n// Fastify declaration merge — request.scope is always defined\ndeclare module 'fastify' {\n interface FastifyRequest {\n /** Request scope — set by auth adapter, read by permissions/presets/guards */\n scope: RequestScope;\n\n // ---- Auth / identity ----\n /** Current user — set by auth adapter (Better Auth, JWT, custom) */\n user: Record<string, unknown>;\n\n // ---- Policy middleware ----\n /** Policy-injected query filters (e.g. ownership, org-scoping) */\n _policyFilters?: Record<string, unknown>;\n /** Field mask — fields to include/exclude in responses */\n fieldMask?: { include?: string[]; exclude?: string[] };\n /** Arbitrary policy metadata for downstream consumers */\n policyMetadata?: Record<string, unknown>;\n /** Document loaded by policy middleware for ownership checks */\n document?: unknown;\n /** Ownership check context (field name + user field) */\n _ownershipCheck?: Record<string, unknown>;\n }\n}\n\n// Re-export from dedicated type modules\nexport type {\n CrudRepository,\n PaginatedResult,\n QueryOptions,\n PaginationParams,\n InferDoc,\n} from './repository.js';\n\nexport type {\n IRequestContext,\n IControllerResponse,\n ControllerHandler,\n FastifyHandler,\n RouteHandler,\n IController,\n ControllerLike,\n} from './handlers.js';\n\nexport type {\n PermissionCheck,\n PermissionContext,\n PermissionResult,\n UserBase,\n} from '../permissions/types.js';\n\n// ============================================================================\n// Base Types\n// ============================================================================\n\nexport type AnyRecord = Record<string, unknown>;\nexport type ObjectId = Types.ObjectId | string;\n\n/**\n * Flexible user type that accepts any object with id/ID properties.\n * Use this instead of `any` when dealing with user objects.\n * Re-exports UserBase from permissions module for convenience.\n * The actual user structure is defined by your app's auth system.\n */\nexport type UserLike = UserBase & {\n /** User email (optional) */\n email?: string;\n};\n\n/**\n * Extract user ID from a user object (supports both id and _id)\n */\nexport function getUserId(user: UserLike | null | undefined): string | undefined {\n if (!user) return undefined;\n const id = user.id ?? user._id;\n return id ? String(id) : undefined;\n}\n\n\n// ============================================================================\n// Controller Types\n// ============================================================================\n\n/** Standard controller type alias for CRUD operations */\nimport type { IController } from './handlers.js';\nexport type CrudController<TDoc> = IController<TDoc>;\n\nexport interface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n error?: string;\n message?: string;\n meta?: Record<string, unknown>;\n}\n\n// ============================================================================\n// User Types\n// ============================================================================\n\n// UserBase is re-exported from permissions/types.ts\n\nexport interface UserOrganization {\n userId: string;\n organizationId: string;\n [key: string]: unknown;\n}\n\nexport interface JWTPayload {\n sub: string;\n [key: string]: unknown;\n}\n\n// ============================================================================\n// Request Types - Flexible\n// ============================================================================\n\nexport interface RequestContext {\n operation?: string;\n user?: unknown; // YOUR user object\n filters?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Internal metadata shape injected by Arc's Fastify adapter.\n * Extends RequestContext with known internal fields so controllers\n * can access them without `as AnyRecord` casts.\n */\nexport interface ArcInternalMetadata extends RequestContext {\n /** Policy filters from permission middleware */\n _policyFilters?: Record<string, unknown>;\n /** Request scope from scope resolution */\n _scope?: import('../scope/types.js').RequestScope;\n /** Ownership check config from ownedByUser preset */\n _ownershipCheck?: { field: string; userId: string };\n /** Arc instance references (hooks, field permissions, etc.) */\n arc?: {\n hooks?: import('../hooks/HookSystem.js').HookSystem;\n fields?: import('../permissions/fields.js').FieldPermissionMap;\n [key: string]: unknown;\n };\n}\n\n/**\n * Controller-level query options - parsed from request query string\n * Includes pagination, filtering, and context data\n */\nexport interface ControllerQueryOptions {\n page?: number;\n limit?: number;\n sort?: string | Record<string, 1 | -1>;\n /** Simple populate (comma-separated string or array) */\n populate?: string | string[] | Record<string, unknown>;\n /**\n * Advanced populate options (Mongoose-compatible)\n * When set, takes precedence over simple `populate`\n */\n populateOptions?: PopulateOption[];\n select?: string | string[] | Record<string, 0 | 1>; // String, array, or MongoDB projection\n filters?: Record<string, unknown>;\n search?: string;\n lean?: boolean;\n after?: string; // Cursor-based pagination\n user?: unknown; // Current user context\n context?: Record<string, unknown>; // Additional context\n /** Allow additional options */\n [key: string]: unknown;\n}\n\n/**\n * Mongoose-compatible populate option for advanced field selection\n * Used when you need to select specific fields from populated documents\n *\n * @example\n * ```typescript\n * // URL: ?populate[author][select]=name,email\n * // Generates: { path: 'author', select: 'name email' }\n * ```\n */\nexport interface PopulateOption {\n /** Field path to populate */\n path: string;\n /** Fields to select (space-separated) */\n select?: string;\n /** Filter conditions for populated documents */\n match?: Record<string, unknown>;\n /** Query options (limit, sort, skip) */\n options?: {\n limit?: number;\n sort?: Record<string, 1 | -1>;\n skip?: number;\n };\n /** Nested populate configuration */\n populate?: PopulateOption;\n}\n\n/**\n * Parsed query result from QueryParser\n * Includes pagination, sorting, filtering, etc.\n *\n * The index signature allows custom query parsers (like MongoKit's QueryParser)\n * to add additional fields without breaking Arc's type system.\n */\nexport interface ParsedQuery {\n filters?: Record<string, unknown>;\n limit?: number;\n sort?: string | Record<string, 1 | -1>;\n /** Simple populate (comma-separated string or array) */\n populate?: string | string[] | Record<string, unknown>;\n /**\n * Advanced populate options (Mongoose-compatible)\n * When set, takes precedence over simple `populate`\n * @example [{ path: 'author', select: 'name email' }]\n */\n populateOptions?: PopulateOption[];\n search?: string;\n page?: number;\n after?: string; // Cursor for cursor-based pagination\n select?: string | string[] | Record<string, 0 | 1>; // MongoDB projection format\n /** Allow additional fields from custom query parsers */\n [key: string]: unknown;\n}\n\n/**\n * Query Parser Interface\n * Implement this to create custom query parsers\n *\n * @example MongoKit QueryParser\n * ```typescript\n * import { QueryParser } from '@classytic/mongokit';\n * const queryParser = new QueryParser();\n * ```\n */\nexport interface QueryParserInterface {\n parse(query: Record<string, unknown> | null | undefined): ParsedQuery;\n\n /**\n * Optional: Export OpenAPI schema for query parameters\n * Use this to document query parameters in OpenAPI/Swagger\n */\n getQuerySchema?(): {\n type: 'object';\n properties: Record<string, unknown>;\n required?: string[];\n };\n}\n\nexport interface FastifyRequestExtras {\n user?: Record<string, unknown>;\n}\n\nexport interface RequestWithExtras extends FastifyRequest {\n /**\n * Arc metadata - set by createCrudRouter\n * Contains resource configuration and schema options\n */\n arc?: {\n resourceName?: string;\n schemaOptions?: RouteSchemaOptions;\n permissions?: ResourcePermissions;\n };\n context?: Record<string, unknown>; // Additional context data\n _policyFilters?: Record<string, unknown>; // Policy filters from middleware\n fieldMask?: { include?: string[]; exclude?: string[] }; // Field projection for responses\n _ownershipCheck?: Record<string, unknown>; // Ownership validation context\n}\n\nexport type FastifyWithAuth = FastifyInstance & {\n authenticate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;\n};\n\n/**\n * Arc core decorator interface\n * Added by arcCorePlugin to provide instance-scoped hooks and registry\n */\nexport interface ArcDecorator {\n /** Instance-scoped hook system */\n hooks: import('../hooks/HookSystem.js').HookSystem;\n /** Instance-scoped resource registry */\n registry: import('../registry/ResourceRegistry.js').ResourceRegistry;\n /** Whether event emission is enabled */\n emitEvents: boolean;\n}\n\n/**\n * Events decorator interface\n * Added by eventPlugin to provide event pub/sub\n */\nexport interface EventsDecorator {\n /** Publish an event */\n publish: <T>(type: string, payload: T, meta?: Partial<{ id: string; timestamp: Date }>) => Promise<void>;\n /** Subscribe to events */\n subscribe: (pattern: string, handler: (event: unknown) => void | Promise<void>) => Promise<() => void>;\n /** Get transport name */\n transportName: string;\n}\n\n/**\n * Fastify instance with Arc decorators\n * Arc adds these decorators via plugins/presets\n */\nexport type FastifyWithDecorators = FastifyInstance & {\n // Arc core decorator (from arcCorePlugin)\n arc?: ArcDecorator;\n\n // Events decorator (from eventPlugin)\n events?: EventsDecorator;\n\n // Auth decorators (from auth plugin)\n authenticate?: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;\n optionalAuthenticate?: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;\n\n // Organization-scoped filtering (from multiTenant preset)\n organizationScoped?: (options?: { required?: boolean }) => RouteHandlerMethod;\n\n // Custom decorators from your app\n [key: string]: unknown;\n};\n\nexport interface OwnershipCheck {\n field: string;\n userField?: string;\n}\n\n// ============================================================================\n// Resource & Route Types\n// ============================================================================\n\nimport type { ControllerLike } from './handlers.js';\n\n/**\n * Per-resource rate limit configuration.\n *\n * Applied to all routes of the resource when `@fastify/rate-limit` is registered\n * on the Fastify instance. Set to `false` to explicitly disable rate limiting\n * for a resource even when a global rate limit is configured.\n *\n * @example\n * ```typescript\n * defineResource({\n * name: 'product',\n * rateLimit: { max: 100, timeWindow: '1 minute' },\n * });\n * ```\n */\n/**\n * Per-resource cache configuration for QueryCache.\n * Enables stale-while-revalidate, auto-invalidation on mutations,\n * and cross-resource tag-based invalidation.\n */\nexport interface ResourceCacheConfig {\n /** Seconds data is \"fresh\" (no revalidation). Default: 0 */\n staleTime?: number;\n /** Seconds stale data stays cached (SWR window). Default: 60 */\n gcTime?: number;\n /** Per-operation overrides */\n list?: { staleTime?: number; gcTime?: number };\n byId?: { staleTime?: number; gcTime?: number };\n /** Tags for cross-resource invalidation grouping */\n tags?: string[];\n /**\n * Cross-resource invalidation: event pattern → tag targets.\n * When matched event fires, all caches with those tags are invalidated.\n * @example { 'category.*': ['catalog'] }\n */\n invalidateOn?: Record<string, string[]>;\n /** Disable caching for this resource */\n disabled?: boolean;\n}\n\nexport interface RateLimitConfig {\n /** Maximum number of requests allowed within the time window */\n max: number;\n /** Time window for rate limiting (e.g., '1 minute', '15 seconds', '1 hour') */\n timeWindow: string;\n}\n\nexport interface ResourceConfig<TDoc = AnyRecord> {\n name: string;\n displayName?: string;\n tag?: string;\n prefix?: string; // Defaults to `/${name}s` if not provided\n adapter?: DataAdapter<TDoc>; // Optional for service-pattern resources\n /** Controller instance - accepts any object with CRUD methods */\n controller?: IController<TDoc> | ControllerLike;\n queryParser?: unknown;\n permissions?: ResourcePermissions;\n schemaOptions?: RouteSchemaOptions;\n openApiSchemas?: OpenApiSchemas;\n customSchemas?: Partial<CrudSchemas>; // Custom JSON schemas\n presets?: Array<string | PresetResult | { name: string; [key: string]: unknown }>; // Preset names, objects, or PresetResult\n hooks?: ResourceHooks;\n /**\n * Functional pipeline — guards, transforms, and interceptors.\n * Can be a flat array (all operations) or per-operation map.\n *\n * @example\n * ```typescript\n * import { pipe, guard, transform, intercept } from '@classytic/arc';\n *\n * resource('product', {\n * pipe: pipe(isActive, slugify, timing),\n * // OR per-operation:\n * pipe: { create: pipe(isActive, slugify), list: pipe(timing) },\n * });\n * ```\n */\n pipe?: import('../pipeline/types.js').PipelineConfig;\n /**\n * Field-level permissions — control visibility and writability per role.\n *\n * @example\n * ```typescript\n * import { fields } from '@classytic/arc';\n * fields: {\n * salary: fields.visibleTo(['admin', 'hr']),\n * password: fields.hidden(),\n * }\n * ```\n */\n fields?: import('../permissions/fields.js').FieldPermissionMap;\n middlewares?: MiddlewareConfig;\n additionalRoutes?: AdditionalRoute[];\n disableCrud?: boolean;\n disableDefaultRoutes?: boolean;\n disabledRoutes?: CrudRouteKey[]; // Specific routes to disable\n /**\n * Field name used for multi-tenant scoping (default: 'organizationId').\n * Override to match your schema: 'workspaceId', 'tenantId', 'teamId', etc.\n * Takes effect when org context is present (via multiTenant preset).\n */\n tenantField?: string;\n /**\n * Primary key field name (default: '_id').\n * Override for non-MongoDB adapters (e.g., 'id' for SQL databases).\n */\n idField?: string;\n module?: string; // For grouping in registry\n events?: Record<string, EventDefinition>; // Domain events\n skipValidation?: boolean; // Skip schema validation\n skipRegistry?: boolean; // Don't register in introspection\n _appliedPresets?: string[]; // Internal: track applied presets\n /** HTTP method for update routes. Default: 'PATCH' */\n updateMethod?: 'PUT' | 'PATCH' | 'both';\n /**\n * Per-resource rate limiting.\n * Requires `@fastify/rate-limit` to be registered on the Fastify instance.\n * Set to `false` to disable rate limiting for this resource.\n */\n rateLimit?: RateLimitConfig | false;\n /**\n * QueryCache configuration for this resource.\n * Enables stale-while-revalidate and auto-invalidation.\n * Requires `queryCachePlugin` to be registered.\n */\n cache?: ResourceCacheConfig;\n}\n\n/**\n * Resource-level permissions\n * ONLY PermissionCheck functions allowed - no string arrays\n */\nexport interface ResourcePermissions {\n list?: PermissionCheck;\n get?: PermissionCheck;\n create?: PermissionCheck;\n update?: PermissionCheck;\n delete?: PermissionCheck;\n}\n\nexport interface ResourceHooks {\n beforeCreate?: (data: AnyRecord) => Promise<AnyRecord> | AnyRecord;\n afterCreate?: (doc: AnyRecord) => Promise<void> | void;\n beforeUpdate?: (id: string, data: AnyRecord) => Promise<AnyRecord> | AnyRecord;\n afterUpdate?: (doc: AnyRecord) => Promise<void> | void;\n beforeDelete?: (id: string) => Promise<void> | void;\n afterDelete?: (id: string) => Promise<void> | void;\n}\n\n/**\n * Additional route definition for custom endpoints\n */\nexport interface AdditionalRoute {\n /** HTTP method */\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n /** Route path (relative to resource prefix) */\n path: string;\n /**\n * Handler - string (controller method name) or function\n * Function can be Fastify handler or (request, reply) => Promise<unknown>\n */\n handler: string | RouteHandlerMethod | ((request: FastifyRequest, reply: FastifyReply) => unknown);\n\n /** Permission check - REQUIRED */\n permissions: PermissionCheck;\n\n /**\n * Handler type - REQUIRED, no auto-detection\n * true = ControllerHandler (receives context object)\n * false = FastifyHandler (receives request, reply)\n */\n wrapHandler: boolean;\n\n /**\n * Logical operation name for pipeline keys and permission actions.\n * Defaults to handler name (string handlers) or method+path slug.\n * Prevents collisions when multiple routes share the same HTTP method.\n *\n * @example\n * operation: 'listDeleted' // Used as pipeline key and permission action\n * operation: 'restore'\n */\n operation?: string;\n\n /** OpenAPI summary */\n summary?: string;\n /** OpenAPI description */\n description?: string;\n /** OpenAPI tags */\n tags?: string[];\n\n /**\n * Custom route-level middleware\n * Can be an array of handlers or a function that receives fastify and returns handlers\n * @example\n * // Direct array\n * preHandler: [myMiddleware]\n * // Function that receives fastify (for accessing decorators)\n * preHandler: (fastify) => [fastify.customerContext({ required: true })]\n */\n preHandler?: RouteHandlerMethod[] | ((fastify: FastifyInstance) => RouteHandlerMethod[]);\n\n /** Fastify route schema */\n schema?: Record<string, unknown>;\n}\n\nexport interface RouteSchemaOptions {\n hiddenFields?: string[];\n readonlyFields?: string[];\n requiredFields?: string[];\n optionalFields?: string[];\n excludeFields?: string[];\n fieldRules?: Record<string, { systemManaged?: boolean; [key: string]: unknown }>;\n query?: Record<string, unknown>; // Query parameter schema for OpenAPI\n}\n\nexport interface FieldRule {\n field: string;\n required?: boolean;\n readonly?: boolean;\n hidden?: boolean;\n}\n\n/**\n * CRUD Route Schemas (Fastify Native Format)\n *\n * @example\n * {\n * list: {\n * querystring: { type: 'object', properties: { page: { type: 'number' } } },\n * response: { 200: { type: 'object', properties: { docs: { type: 'array' } } } }\n * },\n * create: {\n * body: { type: 'object', properties: { name: { type: 'string' } } },\n * response: { 201: { type: 'object' } }\n * }\n * }\n */\nexport interface CrudSchemas {\n /** GET / - List all resources */\n list?: {\n querystring?: Record<string, unknown>;\n response?: Record<number, unknown>;\n [key: string]: unknown;\n };\n\n /** GET /:id - Get single resource */\n get?: {\n params?: Record<string, unknown>;\n response?: Record<number, unknown>;\n [key: string]: unknown;\n };\n\n /** POST / - Create resource */\n create?: {\n body?: Record<string, unknown>;\n response?: Record<number, unknown>;\n [key: string]: unknown;\n };\n\n /** PATCH /:id - Update resource */\n update?: {\n params?: Record<string, unknown>;\n body?: Record<string, unknown>;\n response?: Record<number, unknown>;\n [key: string]: unknown;\n };\n\n /** DELETE /:id - Delete resource */\n delete?: {\n params?: Record<string, unknown>;\n response?: Record<number, unknown>;\n [key: string]: unknown;\n };\n\n // Allow custom operation schemas\n [key: string]: unknown;\n}\n\nexport interface OpenApiSchemas {\n entity?: unknown;\n createBody?: unknown;\n updateBody?: unknown;\n params?: unknown;\n listQuery?: unknown;\n /**\n * Explicit response schema for OpenAPI documentation.\n * If provided, this will be used as-is for the response schema.\n * If not provided, response schema is auto-generated from createBody.\n *\n * Note: This is for OpenAPI docs only - does NOT affect Fastify serialization.\n *\n * @example\n * response: {\n * type: 'object',\n * properties: {\n * _id: { type: 'string' },\n * name: { type: 'string' },\n * email: { type: 'string' },\n * // Exclude password, include virtuals\n * fullName: { type: 'string' },\n * }\n * }\n */\n response?: unknown;\n [key: string]: unknown;\n}\n\n/** Handler for middleware functions */\nexport type MiddlewareHandler = (request: RequestWithExtras, reply: FastifyReply) => Promise<unknown>;\nexport type CrudRouteKey = 'list' | 'get' | 'create' | 'update' | 'delete';\n\n// ============================================================================\n// Middleware & Config Types\n// ============================================================================\n\nexport interface MiddlewareConfig {\n list?: MiddlewareHandler[];\n get?: MiddlewareHandler[];\n create?: MiddlewareHandler[];\n update?: MiddlewareHandler[];\n delete?: MiddlewareHandler[];\n [key: string]: MiddlewareHandler[] | undefined;\n}\n\n// ============================================================================\n// Auth Types - Flexible, Database-Agnostic\n// ============================================================================\n\n/**\n * JWT utilities provided to authenticator\n * Arc provides these helpers, app uses them as needed\n */\nexport interface JwtContext {\n /** Verify a JWT token and return decoded payload */\n verify: <T = Record<string, unknown>>(token: string) => T;\n /** Sign a payload and return JWT token */\n sign: (payload: Record<string, unknown>, options?: { expiresIn?: string }) => string;\n /** Decode without verification (for inspection) */\n decode: <T = Record<string, unknown>>(token: string) => T | null;\n}\n\n/**\n * Context passed to app's authenticator function\n */\nexport interface AuthenticatorContext {\n /** JWT utilities (available if jwt.secret provided) */\n jwt: JwtContext | null;\n /** Fastify instance for advanced use cases */\n fastify: FastifyInstance;\n}\n\n/**\n * App-provided authenticator function\n *\n * Arc calls this for every non-public route.\n * App has FULL control over authentication logic.\n *\n * @example\n * ```typescript\n * // Simple JWT auth\n * authenticate: async (request, { jwt }) => {\n * const token = request.headers.authorization?.split(' ')[1];\n * if (!token || !jwt) return null;\n * const decoded = jwt.verify(token);\n * return userRepo.findById(decoded.id);\n * }\n *\n * // Multi-strategy (JWT + API Key)\n * authenticate: async (request, { jwt }) => {\n * const apiKey = request.headers['x-api-key'];\n * if (apiKey) {\n * const result = await apiKeyService.verify(apiKey);\n * if (result) return { _id: result.userId, isApiKey: true };\n * }\n * const token = request.headers.authorization?.split(' ')[1];\n * if (token && jwt) {\n * const decoded = jwt.verify(token);\n * return userRepo.findById(decoded.id);\n * }\n * return null;\n * }\n * ```\n */\nexport type Authenticator = (\n request: FastifyRequest,\n context: AuthenticatorContext\n) => Promise<unknown | null> | unknown | null;\n\n/**\n * Token pair returned by issueTokens helper\n */\nexport interface TokenPair {\n /** Access token (JWT) */\n accessToken: string;\n /** Refresh token (JWT with longer expiry) */\n refreshToken?: string;\n /** Access token expiry in seconds */\n expiresIn: number;\n /** Refresh token expiry in seconds */\n refreshExpiresIn?: number;\n /** Token type (always 'Bearer') */\n tokenType: 'Bearer';\n}\n\n/**\n * Auth helpers available on fastify.auth\n *\n * @example\n * ```typescript\n * // In login handler\n * const user = await userRepo.findByEmail(email);\n * if (!user || !await bcrypt.compare(password, user.password)) {\n * return reply.code(401).send({ error: 'Invalid credentials' });\n * }\n *\n * const tokens = fastify.auth.issueTokens({\n * id: user._id,\n * email: user.email,\n * roles: user.roles,\n * });\n *\n * return { success: true, ...tokens, user };\n * ```\n */\nexport interface AuthHelpers {\n /** JWT utilities (if configured) */\n jwt: JwtContext | null;\n\n /**\n * Issue access + refresh tokens for a user\n * App calls this after validating credentials\n */\n issueTokens: (\n payload: Record<string, unknown>,\n options?: { expiresIn?: string; refreshExpiresIn?: string }\n ) => TokenPair;\n\n /**\n * Verify a refresh token and return decoded payload\n */\n verifyRefreshToken: <T = Record<string, unknown>>(token: string) => T;\n}\n\nexport interface ServiceContext {\n user?: unknown;\n requestId?: string;\n select?: string[] | Record<string, 0 | 1>; // Field projection for responses\n populate?: string | string[]; // Relations to populate\n lean?: boolean; // Return plain objects\n}\n\n// ============================================================================\n// Preset Types\n// ============================================================================\n\nexport interface PresetHook {\n operation: 'create' | 'update' | 'delete' | 'read' | 'list';\n phase: 'before' | 'after';\n handler: (ctx: AnyRecord) => void | Promise<void> | AnyRecord | Promise<AnyRecord>;\n priority?: number;\n}\n\nexport interface PresetResult {\n name: string;\n additionalRoutes?: AdditionalRoute[] | ((permissions: ResourcePermissions) => AdditionalRoute[]);\n middlewares?: MiddlewareConfig;\n schemaOptions?: RouteSchemaOptions;\n controllerOptions?: Record<string, unknown>;\n hooks?: PresetHook[];\n}\n\nexport type PresetFunction = (config: ResourceConfig) => PresetResult;\n\n// ============================================================================\n// Plugin Types\n// ============================================================================\n\nexport interface GracefulShutdownOptions {\n timeout?: number;\n onShutdown?: () => Promise<void> | void;\n signals?: NodeJS.Signals[];\n logEvents?: boolean;\n}\n\nexport interface RequestIdOptions {\n headerName?: string;\n generator?: () => string;\n}\n\nexport interface HealthOptions {\n path?: string;\n check?: () => Promise<unknown>;\n}\n\nexport interface HealthCheck {\n healthy: boolean;\n timestamp: string;\n [key: string]: unknown;\n}\n\n/**\n * Auth Plugin Options - Clean, Minimal Configuration\n *\n * Arc provides JWT infrastructure and calls your authenticator.\n * You control ALL authentication logic.\n *\n * @example\n * ```typescript\n * // Minimal: just JWT (uses default jwtVerify)\n * auth: {\n * jwt: { secret: process.env.JWT_SECRET },\n * }\n *\n * // With custom authenticator (recommended)\n * auth: {\n * jwt: { secret: process.env.JWT_SECRET },\n * authenticate: async (request, { jwt }) => {\n * const token = request.headers.authorization?.split(' ')[1];\n * if (!token) return null;\n * const decoded = jwt.verify(token);\n * return userRepo.findById(decoded.id);\n * },\n * }\n *\n * // Multi-strategy (JWT + API Key)\n * auth: {\n * jwt: { secret: process.env.JWT_SECRET },\n * authenticate: async (request, { jwt }) => {\n * // Try API key first (faster)\n * const apiKey = request.headers['x-api-key'];\n * if (apiKey) {\n * const result = await apiKeyService.verify(apiKey);\n * if (result) return { _id: result.userId, isApiKey: true };\n * }\n * // Try JWT\n * const token = request.headers.authorization?.split(' ')[1];\n * if (token) {\n * const decoded = jwt.verify(token);\n * return userRepo.findById(decoded.id);\n * }\n * return null;\n * },\n * onFailure: (request, reply) => {\n * reply.code(401).send({\n * success: false,\n * error: 'Authentication required',\n * message: 'Use Bearer token or X-API-Key header',\n * });\n * },\n * }\n * ```\n */\nexport interface AuthPluginOptions {\n /**\n * JWT configuration (optional but recommended)\n * If provided, jwt utilities are available in authenticator context\n */\n jwt?: {\n /** JWT secret (required for JWT features) */\n secret: string;\n /** Access token expiry (default: '15m') */\n expiresIn?: string;\n /** Refresh token secret (defaults to main secret) */\n refreshSecret?: string;\n /** Refresh token expiry (default: '7d') */\n refreshExpiresIn?: string;\n /** Additional @fastify/jwt sign options */\n sign?: Record<string, unknown>;\n /** Additional @fastify/jwt verify options */\n verify?: Record<string, unknown>;\n };\n\n /**\n * Custom authenticator function (recommended)\n *\n * Arc calls this for non-public routes.\n * Return user object to authenticate, null/undefined to reject.\n *\n * If not provided and jwt.secret is set, uses default jwtVerify.\n */\n authenticate?: Authenticator;\n\n /**\n * Custom auth failure handler\n * Customize the 401 response when authentication fails\n */\n onFailure?: (\n request: FastifyRequest,\n reply: FastifyReply,\n error?: Error\n ) => void | Promise<void>;\n\n /**\n * Expose detailed auth error messages in 401 responses.\n * When false (default), returns generic \"Authentication required\".\n * When true, includes the actual error message for debugging.\n * Decoupled from log level — set explicitly per environment.\n */\n exposeAuthErrors?: boolean;\n\n /**\n * Property name to store user on request (default: 'user')\n */\n userProperty?: string;\n}\n\n\nexport interface IntrospectionPluginOptions {\n path?: string;\n prefix?: string;\n enabled?: boolean;\n authRoles?: string[];\n}\n\nexport interface CrudRouterOptions {\n /** Route prefix */\n prefix?: string;\n\n /** Permission checks for CRUD operations */\n permissions?: ResourcePermissions;\n\n /** OpenAPI tag for grouping routes */\n tag?: string;\n\n /** JSON schemas for CRUD operations */\n schemas?: Partial<CrudSchemas>;\n\n /** Middlewares for each CRUD operation */\n middlewares?: MiddlewareConfig;\n\n /** Additional custom routes (from presets or user-defined) */\n additionalRoutes?: AdditionalRoute[];\n\n /** Disable all default CRUD routes */\n disableDefaultRoutes?: boolean;\n\n /** Disable specific CRUD routes */\n disabledRoutes?: CrudRouteKey[];\n\n /** Functional pipeline (guard/transform/intercept) */\n pipe?: import('../pipeline/types.js').PipelineConfig;\n\n /** Resource name for lifecycle hooks */\n resourceName?: string;\n\n /** Schema generation options */\n schemaOptions?: RouteSchemaOptions;\n\n /** Field-level permissions (visibility, writability per role) */\n fields?: import('../permissions/fields.js').FieldPermissionMap;\n\n /** HTTP method for update routes. Default: 'PATCH' */\n updateMethod?: 'PUT' | 'PATCH' | 'both';\n\n /**\n * Per-resource rate limiting.\n * Requires `@fastify/rate-limit` to be registered on the Fastify instance.\n * Set to `false` to disable rate limiting for this resource.\n */\n rateLimit?: RateLimitConfig | false;\n}\n\n// ============================================================================\n// Registry & Metadata Types\n// ============================================================================\n\nexport interface ResourceMetadata {\n name: string;\n displayName?: string;\n tag?: string;\n prefix: string;\n module?: string;\n permissions?: ResourcePermissions;\n presets: string[];\n additionalRoutes?: AdditionalRoute[];\n routes: Array<{\n method: string;\n path: string;\n handler?: string;\n operation?: string;\n summary?: string;\n }>;\n events?: string[];\n}\n\nexport interface RegistryEntry extends ResourceMetadata {\n plugin: unknown;\n adapter?: { type: string; name: string } | null;\n events?: string[];\n disableDefaultRoutes?: boolean;\n openApiSchemas?: OpenApiSchemas;\n registeredAt?: string;\n /** Field-level permissions metadata (for OpenAPI docs) */\n fieldPermissions?: Record<string, { type: string; roles?: readonly string[]; redactValue?: unknown }>;\n /** Pipeline step names (for OpenAPI docs) */\n pipelineSteps?: Array<{ type: string; name: string; operations?: string[] }>;\n /** Update HTTP method(s) used for this resource */\n updateMethod?: 'PUT' | 'PATCH' | 'both';\n /** Routes disabled for this resource */\n disabledRoutes?: string[];\n /** Rate limit config */\n rateLimit?: RateLimitConfig | false;\n}\n\nexport interface RegistryStats {\n total?: number;\n totalResources: number;\n byTag?: Record<string, number>;\n byModule?: Record<string, number>;\n presetUsage?: Record<string, number>;\n totalRoutes?: number;\n totalEvents?: number;\n}\n\nexport interface IntrospectionData {\n resources: ResourceMetadata[];\n stats: RegistryStats;\n generatedAt?: string;\n}\n\nexport interface EventDefinition {\n name: string;\n handler: (data: unknown) => Promise<void> | void;\n schema?: Record<string, unknown>; // JSON schema for event payload\n description?: string; // Event documentation\n}\n\n// ============================================================================\n// Validation Types\n// ============================================================================\n\nexport interface ConfigError {\n field: string;\n message: string;\n code?: string;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: ConfigError[];\n}\n\nexport interface ValidateOptions {\n strict?: boolean;\n}\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/**\n * Infer document type from DataAdapter, Repository, or ResourceConfig.\n * Smart inference that works with multiple sources.\n *\n * @example\n * ```typescript\n * type Doc1 = InferDocType<typeof adapter>; // From DataAdapter\n * type Doc2 = InferDocType<typeof repository>; // From Repository\n * type Doc3 = InferDocType<typeof resource>; // From ResourceConfig\n * ```\n */\nimport type { CrudRepository } from './repository.js';\n\n/**\n * Infer document type from DataAdapter or ResourceConfig\n */\nexport type InferDocType<T> =\n T extends DataAdapter<infer D>\n ? D\n : T extends ResourceConfig<infer D>\n ? D\n : never;\n\n/**\n * Infer document type from a DataAdapter.\n * Falls back to `unknown` (not `never`) — safe for generic constraints.\n *\n * @example\n * ```typescript\n * const adapter = createMongooseAdapter({ model: ProductModel, repository: productRepo });\n * type ProductDoc = InferAdapterDoc<typeof adapter>;\n * // ProductDoc = the document type inferred from the adapter\n * ```\n */\nexport type InferAdapterDoc<A> = A extends DataAdapter<infer D> ? D : unknown;\n\nexport type InferResourceDoc<T> = T extends ResourceConfig<infer D> ? D : never;\nexport type TypedResourceConfig<TDoc> = ResourceConfig<TDoc>;\nexport type TypedController<TDoc> = IController<TDoc>;\nexport type TypedRepository<TDoc> = CrudRepository<TDoc>;\n\n// ============================================================================\n// Base Controller Options (canonical definition in core/BaseController.ts)\n// ============================================================================\n\nexport type { BaseControllerOptions } from '../core/BaseController.js';\n"],"mappings":";;;;;;AAqGA,SAAgB,UAAU,MAAuD;AAC/E,KAAI,CAAC,KAAM,QAAO;CAClB,MAAM,KAAK,KAAK,MAAM,KAAK;AAC3B,QAAO,KAAK,OAAO,GAAG,GAAG"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-Beqn1Un7.mjs","names":[],"sources":["../src/scope/types.ts"],"sourcesContent":["/**\n * Request Scope — The One Standard\n *\n * Discriminated union representing the access context of every request.\n * Replaces scattered orgScope/orgRoles/organizationId/bypassRoles.\n *\n * Set once by auth adapters, read everywhere by permissions/presets/guards.\n *\n * @example\n * ```typescript\n * // In a permission check\n * const scope = request.scope;\n * if (isElevated(scope)) return true;\n * if (isMember(scope) && scope.orgRoles.includes('admin')) return true;\n * ```\n */\n\n// ============================================================================\n// Core Type\n// ============================================================================\n\n/**\n * Request scope — 4 kinds, 4 states, no ambiguity.\n *\n * | Kind | Meaning |\n * |---------------|-----------------------------------|\n * | public | No authentication |\n * | authenticated | Logged in, no org context |\n * | member | In an org with specific roles |\n * | elevated | Platform admin, explicit elevation |\n */\nexport type RequestScope =\n | { kind: 'public' }\n | { kind: 'authenticated' }\n | { kind: 'member'; organizationId: string; orgRoles: string[]; teamId?: string }\n | { kind: 'elevated'; organizationId?: string; elevatedBy: string };\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/** Check if scope is `member` kind */\nexport function isMember(scope: RequestScope): scope is Extract<RequestScope, { kind: 'member' }> {\n return scope.kind === 'member';\n}\n\n/** Check if scope is `elevated` kind */\nexport function isElevated(scope: RequestScope): scope is Extract<RequestScope, { kind: 'elevated' }> {\n return scope.kind === 'elevated';\n}\n\n/** Check if scope has org access (member OR elevated) */\nexport function hasOrgAccess(scope: RequestScope): boolean {\n return scope.kind === 'member' || scope.kind === 'elevated';\n}\n\n/** Check if request is authenticated (any kind except public) */\nexport function isAuthenticated(scope: RequestScope): boolean {\n return scope.kind !== 'public';\n}\n\n// ============================================================================\n// Accessors\n// ============================================================================\n\n/** Get organizationId from scope (if present) */\nexport function getOrgId(scope: RequestScope): string | undefined {\n if (scope.kind === 'member') return scope.organizationId;\n if (scope.kind === 'elevated') return scope.organizationId;\n return undefined;\n}\n\n/** Get org roles from scope (empty array if not a member) */\nexport function getOrgRoles(scope: RequestScope): string[] {\n if (scope.kind === 'member') return scope.orgRoles;\n return [];\n}\n\n/** Get team ID from scope (only available on member kind) */\nexport function getTeamId(scope: RequestScope): string | undefined {\n if (scope.kind === 'member') return scope.teamId;\n return undefined;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Default public scope — used as initial decoration value */\nexport const PUBLIC_SCOPE: Readonly<RequestScope> = Object.freeze({ kind: 'public' as const });\n\n/** Default authenticated scope — used when user is logged in but no org */\nexport const AUTHENTICATED_SCOPE: Readonly<RequestScope> = Object.freeze({ kind: 'authenticated' as const });\n"],"mappings":";;AA0CA,SAAgB,SAAS,OAAyE;AAChG,QAAO,MAAM,SAAS;;;AAIxB,SAAgB,WAAW,OAA2E;AACpG,QAAO,MAAM,SAAS;;;AAIxB,SAAgB,aAAa,OAA8B;AACzD,QAAO,MAAM,SAAS,YAAY,MAAM,SAAS;;;AAInD,SAAgB,gBAAgB,OAA8B;AAC5D,QAAO,MAAM,SAAS;;;AAQxB,SAAgB,SAAS,OAAyC;AAChE,KAAI,MAAM,SAAS,SAAU,QAAO,MAAM;AAC1C,KAAI,MAAM,SAAS,WAAY,QAAO,MAAM;;;AAK9C,SAAgB,YAAY,OAA+B;AACzD,KAAI,MAAM,SAAS,SAAU,QAAO,MAAM;AAC1C,QAAO,EAAE;;;AAIX,SAAgB,UAAU,OAAyC;AACjE,KAAI,MAAM,SAAS,SAAU,QAAO,MAAM;;;AAS5C,MAAa,eAAuC,OAAO,OAAO,EAAE,MAAM,UAAmB,CAAC;;AAG9F,MAAa,sBAA8C,OAAO,OAAO,EAAE,MAAM,iBAA0B,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-CIgB7UUl.d.mts","names":[],"sources":["../src/factory/types.ts"],"mappings":";;;;;;;;;;;;;;;;;AAiDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAiB,aAAA;EACf,IAAA;EAsCE;;;;EAhCF,GAAA;IA8CY,6CA5CV,MAAA,UA+D6B;IA7D7B,SAAA,WAgEsE;IA9DtE,aAAA,WA8DF;IA5DE,gBAAA,WA4DoB;IA1DpB,IAAA,GAAO,MAAA,mBA0D2C;IAxDlD,MAAA,GAAS,MAAA;EAAA;EA6EI;;;;;;;;EAlEf,YAAA,GAAe,aAAA;EA4FA;;;;EAtFf,SAAA,IACE,OAAA,EAAS,cAAA,EACT,KAAA,EAAO,YAAA,EACP,KAAA,GAAQ,KAAA,YACE,OAAA;EAqFoD;;;;;;EA7EhE,gBAAA;EA6E+C;;;EAxE/C,YAAA;AAAA;AAoFF;;;;;;;;;;;;;;;AAgDA;AAhDA,UAjEiB,gBAAA;EACf,IAAA;EAuIW;EArIX,UAAA;IAAc,MAAA,EAAQ,kBAAA;IAAoB,OAAA,GAAU,oBAAA;EAAA;AAAA;;;;;;;;;;;;;;;;;;;UAqBrC,sBAAA;EACf,IAAA;EA0WsD;EAxWtD,MAAA,EAAQ,kBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;UAuBO,yBAAA;EACf,IAAA;EAuNY;EArNZ,YAAA,GAAe,OAAA,EAAS,cAAA,EAAgB,KAAA,EAAO,YAAA,KAAiB,OAAA;AAAA;;;;;;;;;;KAYtD,UAAA,WAER,aAAA,GACA,gBAAA,GACA,sBAAA,GACA,yBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkUJ;;;;;;;;;;AAOA;;;;;UA9RiB,gBAAA;EAiSb;EA3RF,MAAA;EA2RO;AAIT;;;;;EAvRE,OAAA;EA0RA;;;;;EAnRA,MAAA;sDAEE,MAAA,GAAS,cAAA;IAET,KAAA,GAAQ,UAAA;IAER,WAAA,GAAc,gBAAA;IAEd,UAAA,GAAa,UAAA;EAAA;;EAIf,MAAA,GAAS,oBAAA;;;;;;;;;;;;;;;;;;;EAoBT,KAAA;;EAGA,UAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyDA,IAAA,GAAO,UAAA;;;;;;;;;;;;;;;;;;;;;;EA2BP,SAAA,GAAY,gBAAA;;EAOZ,MAAA,GAAS,oBAAA;;EAGT,IAAA,GAAO,kBAAA;;EAGP,SAAA,GAAY,gBAAA;;EAUZ,aAAA,GAAgB,oBAAA;;EAOhB,QAAA;;EAGA,SAAA,GAAY,gBAAA;;EAGZ,OAAA,GAAU,cAAA;;EAOV,UAAA;8CAEE,SAAA;IAEA,MAAA;IAEA,gBAAA;IAEA,UAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4BA,MAAA,GAAS,IAAA,CA3Ca,kBAAA;;;;;IAgDtB,OAAA,GALa,cAAA;;;;;;IAWb,GAAA,GANwD,UAAA;;;;;;IAYxD,UAAA,GAN4C,uBAAA;EAAA;;;;;;;;;;;;;;;;;;;;EA4B9C,YAAA;;;;;;EAOA,YAAA,GA7B6E,mBAAA;;EAgC7E,OAAA,IAAW,OAAA,EAAS,eAAA,KAAoB,OAAA;;EAGxC,OAAA,IAAW,OAAA,EAAS,eAAA,YAA2B,OAAA;;EAG/C,OAAA,IAAW,OAAA,EAAS,eAAA,YAA2B,OAAA;AAAA;AAAA,UAKhC,oBAAA;EACf,iBAAA;EACA,iBAAA;EACA,gBAAA;EACA,WAAA;AAAA;AAAA,UAGe,gBAAA;EACf,MAAA;IACE,QAAA;IACA,KAAA;EAAA;AAAA;AAAA,UAIa,cAAA;EACf,KAAA;EACA,MAAA;EACA,QAAA;EACA,QAAA;AAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-aYB4V7uN.d.mts","names":[],"sources":["../src/permissions/types.ts"],"mappings":";;;;;;;UAaiB,QAAA;EACf,EAAA;EACA,GAAA;EACA,KAAA;EAAA,CACC,GAAA;AAAA;;;;UAMc,iBAAA;EAcQ;EAZvB,IAAA,EAAM,QAAA;EAYuB;EAV7B,OAAA,EAAS,cAAA;EAFT;EAIA,QAAA;EAFA;EAIA,MAAA;EAFA;EAIA,UAAA;EAAA;EAEA,MAAA,GAAS,MAAA;EAAA;EAET,IAAA,GAAO,OAAA,CAAQ,IAAA,IAAQ,MAAA;AAAA;;;;UAMR,gBAAA;EAAA;EAEf,OAAA;;EAEA,MAAA;EAFA;EAIA,OAAA,GAAU,MAAA;AAAA;;;;AA2BZ;;;;;;;;;;;;;;;;;;;;;KAAY,eAAA,iBACV,OAAA,EAAS,iBAAA,CAAkB,IAAA,gBACd,gBAAA,GAAmB,OAAA,WAAkB,gBAAA,KAClD,mBAAA;;;;;UAMe,mBAAA;EAMf;EAJA,SAAA;EAQA;EANA,MAAA;EAMe;EAJf,cAAA;;EAEA,SAAA;;EAEA,eAAA;AAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/utils/responseSchemas.ts","../../src/utils/stateMachine.ts","../../src/utils/circuitBreaker.ts","../../src/utils/queryParser.ts","../../src/utils/typeGuards.ts","../../src/utils/schemaConverter.ts"],"mappings":"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"}
|