@geekmidas/constructs 0.0.17 → 0.0.19

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.
Files changed (147) hide show
  1. package/dist/{AWSLambdaFunction-H65WfXLt.mjs → AWSLambdaFunction-DBUENdP0.mjs} +2 -2
  2. package/dist/{AWSLambdaFunction-H65WfXLt.mjs.map → AWSLambdaFunction-DBUENdP0.mjs.map} +1 -1
  3. package/dist/{AWSLambdaFunction-C-fuCLA3.cjs → AWSLambdaFunction-vobYqQ0w.cjs} +2 -2
  4. package/dist/{AWSLambdaFunction-C-fuCLA3.cjs.map → AWSLambdaFunction-vobYqQ0w.cjs.map} +1 -1
  5. package/dist/{AWSLambdaSubscriberAdaptor-CyFh7MN8.mjs → AWSLambdaSubscriberAdaptor-BLHDyqzQ.mjs} +1 -1
  6. package/dist/{AWSLambdaSubscriberAdaptor-CyFh7MN8.mjs.map → AWSLambdaSubscriberAdaptor-BLHDyqzQ.mjs.map} +1 -1
  7. package/dist/{AWSLambdaSubscriberAdaptor-Dum5bkw3.cjs → AWSLambdaSubscriberAdaptor-DVC4VAQR.cjs} +1 -1
  8. package/dist/{AWSLambdaSubscriberAdaptor-Dum5bkw3.cjs.map → AWSLambdaSubscriberAdaptor-DVC4VAQR.cjs.map} +1 -1
  9. package/dist/{AmazonApiGatewayEndpointAdaptor-CI9L7Ucn.cjs → AmazonApiGatewayEndpointAdaptor-BLUW--OF.cjs} +4 -4
  10. package/dist/{AmazonApiGatewayEndpointAdaptor-CI9L7Ucn.cjs.map → AmazonApiGatewayEndpointAdaptor-BLUW--OF.cjs.map} +1 -1
  11. package/dist/{AmazonApiGatewayEndpointAdaptor-C6Jk5HSy.mjs → AmazonApiGatewayEndpointAdaptor-DBK53gB5.mjs} +4 -4
  12. package/dist/{AmazonApiGatewayEndpointAdaptor-C6Jk5HSy.mjs.map → AmazonApiGatewayEndpointAdaptor-DBK53gB5.mjs.map} +1 -1
  13. package/dist/{AmazonApiGatewayV1EndpointAdaptor-DYL1bCBS.cjs → AmazonApiGatewayV1EndpointAdaptor-B-i9_OtQ.cjs} +3 -3
  14. package/dist/{AmazonApiGatewayV1EndpointAdaptor-DYL1bCBS.cjs.map → AmazonApiGatewayV1EndpointAdaptor-B-i9_OtQ.cjs.map} +1 -1
  15. package/dist/{AmazonApiGatewayV1EndpointAdaptor-BMy8DdNJ.mjs → AmazonApiGatewayV1EndpointAdaptor-DfU3n5im.mjs} +3 -3
  16. package/dist/{AmazonApiGatewayV1EndpointAdaptor-BMy8DdNJ.mjs.map → AmazonApiGatewayV1EndpointAdaptor-DfU3n5im.mjs.map} +1 -1
  17. package/dist/{AmazonApiGatewayV2EndpointAdaptor-BU5wQMOe.mjs → AmazonApiGatewayV2EndpointAdaptor-D-AFyzaQ.mjs} +3 -3
  18. package/dist/{AmazonApiGatewayV2EndpointAdaptor-BU5wQMOe.mjs.map → AmazonApiGatewayV2EndpointAdaptor-D-AFyzaQ.mjs.map} +1 -1
  19. package/dist/{AmazonApiGatewayV2EndpointAdaptor-CPLCMeaN.cjs → AmazonApiGatewayV2EndpointAdaptor-D4k_Bg7Q.cjs} +3 -3
  20. package/dist/{AmazonApiGatewayV2EndpointAdaptor-CPLCMeaN.cjs.map → AmazonApiGatewayV2EndpointAdaptor-D4k_Bg7Q.cjs.map} +1 -1
  21. package/dist/{Cron-3bP5rwXs.cjs → Cron-CmtKQOmE.cjs} +1 -1
  22. package/dist/{Cron-3bP5rwXs.cjs.map → Cron-CmtKQOmE.cjs.map} +1 -1
  23. package/dist/{Cron-gISh3p1m.mjs → Cron-mWi3PQxt.mjs} +1 -1
  24. package/dist/{Cron-gISh3p1m.mjs.map → Cron-mWi3PQxt.mjs.map} +1 -1
  25. package/dist/{CronBuilder-BCYftl8v.mjs → CronBuilder-4DxT6wUa.mjs} +2 -2
  26. package/dist/{CronBuilder-BCYftl8v.mjs.map → CronBuilder-4DxT6wUa.mjs.map} +1 -1
  27. package/dist/{CronBuilder-2zUMc0WT.cjs → CronBuilder-CeffP9Rs.cjs} +2 -2
  28. package/dist/{CronBuilder-2zUMc0WT.cjs.map → CronBuilder-CeffP9Rs.cjs.map} +1 -1
  29. package/dist/{Endpoint-DDpF7NO1.cjs → Endpoint-BTvS2vwp.cjs} +1 -1
  30. package/dist/{Endpoint-DDpF7NO1.cjs.map → Endpoint-BTvS2vwp.cjs.map} +1 -1
  31. package/dist/{Endpoint-S6Yh2_PN.mjs → Endpoint-D2LVHBEO.mjs} +1 -1
  32. package/dist/{Endpoint-S6Yh2_PN.mjs.map → Endpoint-D2LVHBEO.mjs.map} +1 -1
  33. package/dist/{EndpointBuilder-bMiowRHY.cjs → EndpointBuilder-C4qahFeS.cjs} +2 -2
  34. package/dist/{EndpointBuilder-bMiowRHY.cjs.map → EndpointBuilder-C4qahFeS.cjs.map} +1 -1
  35. package/dist/{EndpointBuilder-DN0NQp1W.mjs → EndpointBuilder-O6B1zJ6v.mjs} +2 -2
  36. package/dist/{EndpointBuilder-DN0NQp1W.mjs.map → EndpointBuilder-O6B1zJ6v.mjs.map} +1 -1
  37. package/dist/{EndpointFactory-B0ldqkHz.mjs → EndpointFactory-BUYrnjau.mjs} +2 -2
  38. package/dist/EndpointFactory-BUYrnjau.mjs.map +1 -0
  39. package/dist/{EndpointFactory-DqvIVjOy.cjs → EndpointFactory-C_neYSiA.cjs} +2 -2
  40. package/dist/EndpointFactory-C_neYSiA.cjs.map +1 -0
  41. package/dist/{FunctionExecutionWrapper-DkNycmOh.cjs → FunctionExecutionWrapper-B8agyYHk.cjs} +1 -1
  42. package/dist/{FunctionExecutionWrapper-DkNycmOh.cjs.map → FunctionExecutionWrapper-B8agyYHk.cjs.map} +1 -1
  43. package/dist/{FunctionExecutionWrapper-Bubnr0zA.mjs → FunctionExecutionWrapper-BPIdmPe8.mjs} +1 -1
  44. package/dist/{FunctionExecutionWrapper-Bubnr0zA.mjs.map → FunctionExecutionWrapper-BPIdmPe8.mjs.map} +1 -1
  45. package/dist/{HonoEndpointAdaptor-Dc8XsOxw.d.cts → HonoEndpointAdaptor-C9wC10-w.d.cts} +3 -3
  46. package/dist/{HonoEndpointAdaptor-DuyE06nH.mjs → HonoEndpointAdaptor-DEFNrIv7.mjs} +5 -5
  47. package/dist/{HonoEndpointAdaptor-DuyE06nH.mjs.map → HonoEndpointAdaptor-DEFNrIv7.mjs.map} +1 -1
  48. package/dist/{HonoEndpointAdaptor-CfLRHHFw.cjs → HonoEndpointAdaptor-DbLeXkR6.cjs} +5 -5
  49. package/dist/{HonoEndpointAdaptor-CfLRHHFw.cjs.map → HonoEndpointAdaptor-DbLeXkR6.cjs.map} +1 -1
  50. package/dist/{TestEndpointAdaptor-BEyZa0Yg.mjs → TestEndpointAdaptor-BGrZsg5c.mjs} +38 -12
  51. package/dist/TestEndpointAdaptor-BGrZsg5c.mjs.map +1 -0
  52. package/dist/{TestEndpointAdaptor-jxn68ayg.d.mts → TestEndpointAdaptor-Bl2ic-yr.d.mts} +22 -8
  53. package/dist/{TestEndpointAdaptor-H5To8PH7.d.cts → TestEndpointAdaptor-ByXqQufk.d.cts} +22 -8
  54. package/dist/{TestEndpointAdaptor-C8425RJ0.cjs → TestEndpointAdaptor-JCvZ3VVi.cjs} +38 -12
  55. package/dist/TestEndpointAdaptor-JCvZ3VVi.cjs.map +1 -0
  56. package/dist/adaptors/aws.cjs +9 -9
  57. package/dist/adaptors/aws.d.cts +1 -1
  58. package/dist/adaptors/aws.mjs +9 -9
  59. package/dist/adaptors/hono.cjs +5 -5
  60. package/dist/adaptors/hono.d.cts +2 -2
  61. package/dist/adaptors/hono.mjs +5 -5
  62. package/dist/adaptors/testing.cjs +3 -3
  63. package/dist/adaptors/testing.d.cts +2 -2
  64. package/dist/adaptors/testing.d.mts +1 -1
  65. package/dist/adaptors/testing.mjs +3 -3
  66. package/dist/crons/Cron.cjs +1 -1
  67. package/dist/crons/Cron.d.cts +1 -1
  68. package/dist/crons/Cron.mjs +1 -1
  69. package/dist/crons/CronBuilder.cjs +2 -2
  70. package/dist/crons/CronBuilder.d.cts +1 -1
  71. package/dist/crons/CronBuilder.mjs +2 -2
  72. package/dist/crons/index.cjs +2 -2
  73. package/dist/crons/index.d.cts +5 -5
  74. package/dist/crons/index.mjs +2 -2
  75. package/dist/endpoints/AmazonApiGatewayEndpointAdaptor.cjs +3 -3
  76. package/dist/endpoints/AmazonApiGatewayEndpointAdaptor.d.cts +1 -1
  77. package/dist/endpoints/AmazonApiGatewayEndpointAdaptor.mjs +3 -3
  78. package/dist/endpoints/AmazonApiGatewayV1EndpointAdaptor.cjs +5 -5
  79. package/dist/endpoints/AmazonApiGatewayV1EndpointAdaptor.d.cts +1 -1
  80. package/dist/endpoints/AmazonApiGatewayV1EndpointAdaptor.mjs +5 -5
  81. package/dist/endpoints/AmazonApiGatewayV2EndpointAdaptor.cjs +5 -5
  82. package/dist/endpoints/AmazonApiGatewayV2EndpointAdaptor.d.cts +1 -1
  83. package/dist/endpoints/AmazonApiGatewayV2EndpointAdaptor.mjs +5 -5
  84. package/dist/endpoints/Endpoint.cjs +1 -1
  85. package/dist/endpoints/Endpoint.d.cts +1 -1
  86. package/dist/endpoints/Endpoint.mjs +1 -1
  87. package/dist/endpoints/EndpointBuilder.cjs +2 -2
  88. package/dist/endpoints/EndpointBuilder.d.cts +1 -1
  89. package/dist/endpoints/EndpointBuilder.mjs +2 -2
  90. package/dist/endpoints/EndpointFactory.cjs +3 -3
  91. package/dist/endpoints/EndpointFactory.d.cts +1 -1
  92. package/dist/endpoints/EndpointFactory.mjs +3 -3
  93. package/dist/endpoints/HonoEndpointAdaptor.cjs +5 -5
  94. package/dist/endpoints/HonoEndpointAdaptor.d.cts +2 -2
  95. package/dist/endpoints/HonoEndpointAdaptor.mjs +5 -5
  96. package/dist/endpoints/TestEndpointAdaptor.cjs +3 -3
  97. package/dist/endpoints/TestEndpointAdaptor.d.cts +2 -2
  98. package/dist/endpoints/TestEndpointAdaptor.d.mts +1 -1
  99. package/dist/endpoints/TestEndpointAdaptor.mjs +3 -3
  100. package/dist/endpoints/audit.d.cts +1 -1
  101. package/dist/endpoints/helpers.cjs +2 -2
  102. package/dist/endpoints/helpers.d.cts +1 -1
  103. package/dist/endpoints/helpers.mjs +2 -2
  104. package/dist/endpoints/index.cjs +3 -3
  105. package/dist/endpoints/index.d.cts +3 -3
  106. package/dist/endpoints/index.mjs +3 -3
  107. package/dist/endpoints/parseHonoQuery.cjs +1 -1
  108. package/dist/endpoints/parseHonoQuery.mjs +1 -1
  109. package/dist/endpoints/parseQueryParams.cjs +1 -1
  110. package/dist/endpoints/parseQueryParams.mjs +1 -1
  111. package/dist/endpoints/processAudits.cjs +1 -1
  112. package/dist/endpoints/processAudits.d.cts +1 -1
  113. package/dist/endpoints/processAudits.mjs +1 -1
  114. package/dist/functions/AWSLambdaFunction.cjs +2 -2
  115. package/dist/functions/AWSLambdaFunction.mjs +2 -2
  116. package/dist/functions/FunctionExecutionWrapper.cjs +1 -1
  117. package/dist/functions/FunctionExecutionWrapper.mjs +1 -1
  118. package/dist/functions/index.d.cts +1 -1
  119. package/dist/{helpers-Khuhi_Qx.cjs → helpers-CUYRcimZ.cjs} +2 -2
  120. package/dist/{helpers-Khuhi_Qx.cjs.map → helpers-CUYRcimZ.cjs.map} +1 -1
  121. package/dist/{helpers-2CLKTnRm.mjs → helpers-D-OW3LI_.mjs} +2 -2
  122. package/dist/{helpers-2CLKTnRm.mjs.map → helpers-D-OW3LI_.mjs.map} +1 -1
  123. package/dist/index-Doa8YPmH.d.cts +10 -0
  124. package/dist/{parseHonoQuery-CwFKw2ua.mjs → parseHonoQuery-BlwMModJ.mjs} +1 -1
  125. package/dist/{parseHonoQuery-CwFKw2ua.mjs.map → parseHonoQuery-BlwMModJ.mjs.map} +1 -1
  126. package/dist/{parseHonoQuery-CT8Cvin-.cjs → parseHonoQuery-D-fMmSbA.cjs} +1 -1
  127. package/dist/{parseHonoQuery-CT8Cvin-.cjs.map → parseHonoQuery-D-fMmSbA.cjs.map} +1 -1
  128. package/dist/{parseQueryParams-CwvXXwkW.cjs → parseQueryParams-CbY1zcCU.cjs} +1 -1
  129. package/dist/{parseQueryParams-CwvXXwkW.cjs.map → parseQueryParams-CbY1zcCU.cjs.map} +1 -1
  130. package/dist/{parseQueryParams-CHINupbZ.mjs → parseQueryParams-DlbV3_SB.mjs} +1 -1
  131. package/dist/{parseQueryParams-CHINupbZ.mjs.map → parseQueryParams-DlbV3_SB.mjs.map} +1 -1
  132. package/dist/{processAudits-DfcB-X-4.mjs → processAudits-CW7z5Kj9.mjs} +1 -1
  133. package/dist/{processAudits-DfcB-X-4.mjs.map → processAudits-CW7z5Kj9.mjs.map} +1 -1
  134. package/dist/{processAudits-BFokHhCO.cjs → processAudits-MHp5_fc7.cjs} +1 -1
  135. package/dist/{processAudits-BFokHhCO.cjs.map → processAudits-MHp5_fc7.cjs.map} +1 -1
  136. package/dist/subscribers/AWSLambdaSubscriberAdaptor.cjs +1 -1
  137. package/dist/subscribers/AWSLambdaSubscriberAdaptor.mjs +1 -1
  138. package/dist/subscribers/index.d.cts +2 -2
  139. package/package.json +5 -5
  140. package/src/endpoints/EndpointFactory.ts +17 -7
  141. package/src/endpoints/TestEndpointAdaptor.ts +92 -36
  142. package/src/endpoints/__tests__/TestEndpointAdaptor.audits.spec.ts +614 -0
  143. package/dist/EndpointFactory-B0ldqkHz.mjs.map +0 -1
  144. package/dist/EndpointFactory-DqvIVjOy.cjs.map +0 -1
  145. package/dist/TestEndpointAdaptor-BEyZa0Yg.mjs.map +0 -1
  146. package/dist/TestEndpointAdaptor-C8425RJ0.cjs.map +0 -1
  147. package/dist/index-C1dy81Sw.d.cts +0 -10
@@ -1 +1 @@
1
- {"version":3,"file":"processAudits-DfcB-X-4.mjs","names":["endpoint: Endpoint<\n any,\n any,\n any,\n OutSchema,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction\n >","response: InferStandardSchema<OutSchema>","serviceDiscovery: ServiceDiscovery<any, any>","logger: TLogger","ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n }","existingAuditor?: Auditor<TAuditAction>","auditor: Auditor<TAuditAction>","actor: AuditActor","endpoint: Endpoint<\n any,\n any,\n any,\n any,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction,\n TDatabase,\n TDatabaseServiceName\n >","auditContext: AuditExecutionContext<TAuditAction> | undefined","handler: (auditor?: Auditor<TAuditAction>) => Promise<T>","onComplete?: (response: T, auditor: Auditor<TAuditAction>) => Promise<void>","response"],"sources":["../src/endpoints/processAudits.ts"],"sourcesContent":["import type {\n AuditActor,\n AuditStorage,\n AuditableAction,\n Auditor,\n} from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { withAuditableTransaction } from '@geekmidas/audit/kysely';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { CookieFn, Endpoint, HeaderFn } from './Endpoint';\nimport type { ActorExtractor, MappedAudit } from './audit';\n\n/**\n * Process declarative audit definitions after successful endpoint execution.\n * Similar to publishConstructEvents for events.\n *\n * @param endpoint - The endpoint with audit configuration\n * @param response - The handler response to generate audit payloads from\n * @param serviceDiscovery - Service discovery for registering audit storage\n * @param logger - Logger for debug/error messages\n * @param ctx - Request context (session, headers, cookies, services)\n * @param existingAuditor - Optional existing auditor instance (e.g., from handler context).\n * If provided, uses this auditor (with its stored transaction).\n * If not provided, creates a new auditor.\n */\nexport async function processEndpointAudits<\n TServices extends Service[] = [],\n TSession = unknown,\n TLogger extends Logger = Logger,\n OutSchema extends StandardSchemaV1 | undefined = undefined,\n TAuditStorage extends AuditStorage | undefined = undefined,\n TAuditStorageServiceName extends string = string,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n>(\n endpoint: Endpoint<\n any,\n any,\n any,\n OutSchema,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction\n >,\n response: InferStandardSchema<OutSchema>,\n serviceDiscovery: ServiceDiscovery<any, any>,\n logger: TLogger,\n ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n },\n existingAuditor?: Auditor<TAuditAction>,\n): Promise<void> {\n try {\n const audits = endpoint.audits as MappedAudit<TAuditAction, OutSchema>[];\n\n // If we have an existing auditor (from handler context), we need to flush\n // any manual audits it collected, even if there are no declarative audits\n const hasExistingRecords =\n existingAuditor && existingAuditor.getRecords().length > 0;\n\n // Skip if no declarative audits and no existing records to flush\n if (!audits?.length && !hasExistingRecords) {\n logger.debug('No audits to process');\n return;\n }\n\n // If no auditor storage service and we have things to process, warn\n if (!endpoint.auditorStorageService) {\n if (hasExistingRecords || audits?.length) {\n logger.warn('No auditor storage service available');\n }\n return;\n }\n\n // Get or create auditor\n let auditor: Auditor<TAuditAction>;\n\n if (existingAuditor) {\n // Use existing auditor (preserves stored transaction and manual audits)\n auditor = existingAuditor;\n logger.debug('Using existing auditor from handler context');\n } else {\n // Create new auditor (backward compatibility)\n const services = await serviceDiscovery.register([\n endpoint.auditorStorageService,\n ]);\n const storage = services[\n endpoint.auditorStorageService.serviceName\n ] as AuditStorage;\n\n // Extract actor if configured\n let actor: AuditActor = { id: 'system', type: 'system' };\n if (endpoint.actorExtractor) {\n try {\n actor = await (\n endpoint.actorExtractor as ActorExtractor<\n TServices,\n TSession,\n TLogger\n >\n )({\n services: ctx.services as any,\n session: ctx.session,\n header: ctx.header,\n cookie: ctx.cookie,\n logger,\n });\n } catch (error) {\n logger.error(error as Error, 'Failed to extract actor for audits');\n // Continue with system actor\n }\n }\n\n auditor = new DefaultAuditor<TAuditAction>({\n actor,\n storage,\n metadata: {\n endpoint: endpoint.route,\n method: endpoint.method,\n },\n });\n }\n\n // Process each declarative audit\n if (audits?.length) {\n for (const audit of audits) {\n logger.debug({ audit: audit.type }, 'Processing declarative audit');\n\n // Check when condition\n if (audit.when && !audit.when(response as any)) {\n logger.debug(\n { audit: audit.type },\n 'Audit skipped due to when condition',\n );\n continue;\n }\n\n // Extract payload\n const payload = audit.payload(response as any);\n\n // Extract entityId if configured\n const entityId = audit.entityId?.(response as any);\n\n // Record the audit\n auditor.audit(audit.type as any, payload as any, {\n table: audit.table,\n entityId,\n });\n }\n }\n\n // Flush audits to storage\n // Note: If existingAuditor has a stored transaction (via setTransaction),\n // flush() will use it automatically\n const recordCount = auditor.getRecords().length;\n if (recordCount > 0) {\n // Check if auditor has a stored transaction (for logging purposes)\n const trx =\n 'getTransaction' in auditor\n ? (auditor as { getTransaction(): unknown }).getTransaction()\n : undefined;\n logger.debug(\n { auditCount: recordCount, hasTransaction: !!trx },\n 'Flushing audits',\n );\n await auditor.flush();\n }\n } catch (error) {\n logger.error(error as Error, 'Failed to process audits');\n // Don't rethrow - audit failures shouldn't fail the request\n }\n}\n\n/**\n * Context for audit-aware handler execution.\n */\nexport interface AuditExecutionContext<\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n> {\n /** The auditor instance for recording audits */\n auditor: Auditor<TAuditAction>;\n /** The audit storage instance */\n storage: AuditStorage;\n}\n\n/**\n * Create audit context for handler execution.\n * Returns the auditor and storage for use in the handler.\n *\n * @param endpoint - The endpoint with audit configuration\n * @param serviceDiscovery - Service discovery for getting audit storage\n * @param logger - Logger for debug/error messages\n * @param ctx - Request context for actor extraction\n * @returns Audit context with auditor and storage, or undefined if not configured\n */\nexport async function createAuditContext<\n TServices extends Service[] = [],\n TSession = unknown,\n TLogger extends Logger = Logger,\n TAuditStorage extends AuditStorage | undefined = undefined,\n TAuditStorageServiceName extends string = string,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n TDatabase = undefined,\n TDatabaseServiceName extends string = string,\n>(\n endpoint: Endpoint<\n any,\n any,\n any,\n any,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction,\n TDatabase,\n TDatabaseServiceName\n >,\n serviceDiscovery: ServiceDiscovery<any, any>,\n logger: TLogger,\n ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n },\n): Promise<AuditExecutionContext<TAuditAction> | undefined> {\n if (!endpoint.auditorStorageService) {\n return undefined;\n }\n\n const services = await serviceDiscovery.register([\n endpoint.auditorStorageService,\n ]);\n const storage = services[\n endpoint.auditorStorageService.serviceName\n ] as AuditStorage;\n\n // Extract actor if configured\n let actor: AuditActor = { id: 'system', type: 'system' };\n if (endpoint.actorExtractor) {\n try {\n actor = await (\n endpoint.actorExtractor as ActorExtractor<TServices, TSession, TLogger>\n )({\n services: ctx.services as any,\n session: ctx.session,\n header: ctx.header,\n cookie: ctx.cookie,\n logger,\n });\n } catch (error) {\n logger.error(error as Error, 'Failed to extract actor for audits');\n }\n }\n\n const auditor = new DefaultAuditor<TAuditAction>({\n actor,\n storage,\n metadata: {\n endpoint: endpoint.route,\n method: endpoint.method,\n },\n });\n\n return { auditor, storage };\n}\n\n/**\n * Execute a handler with automatic audit transaction support.\n * If the audit storage has a database (via getDatabase()), wraps execution\n * in a transaction so audits are atomic with handler's database operations.\n *\n * @param auditContext - The audit context from createAuditContext\n * @param handler - The handler function to execute (receives auditor)\n * @param onComplete - Called after handler with response, to process declarative audits\n * @returns The handler result\n */\nexport async function executeWithAuditTransaction<\n T,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n>(\n auditContext: AuditExecutionContext<TAuditAction> | undefined,\n handler: (auditor?: Auditor<TAuditAction>) => Promise<T>,\n onComplete?: (response: T, auditor: Auditor<TAuditAction>) => Promise<void>,\n): Promise<T> {\n // No audit context - just run handler\n if (!auditContext) {\n return handler(undefined);\n }\n\n const { auditor, storage } = auditContext;\n\n // Check if storage has a database for transactional execution\n const db = storage.getDatabase?.();\n\n if (db) {\n // Wrap in transaction - audits are atomic with handler operations\n return withAuditableTransaction(db as any, auditor as any, async () => {\n const response = await handler(auditor);\n\n // Process declarative audits within the transaction\n if (onComplete) {\n await onComplete(response, auditor);\n }\n\n // Audits are flushed by withAuditableTransaction before commit\n return response;\n });\n }\n\n // No database - run handler and flush audits after\n const response = await handler(auditor);\n\n if (onComplete) {\n await onComplete(response, auditor);\n }\n\n // Flush audits (no transaction)\n await auditor.flush();\n\n return response;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"processAudits-CW7z5Kj9.mjs","names":["endpoint: Endpoint<\n any,\n any,\n any,\n OutSchema,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction\n >","response: InferStandardSchema<OutSchema>","serviceDiscovery: ServiceDiscovery<any, any>","logger: TLogger","ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n }","existingAuditor?: Auditor<TAuditAction>","auditor: Auditor<TAuditAction>","actor: AuditActor","endpoint: Endpoint<\n any,\n any,\n any,\n any,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction,\n TDatabase,\n TDatabaseServiceName\n >","auditContext: AuditExecutionContext<TAuditAction> | undefined","handler: (auditor?: Auditor<TAuditAction>) => Promise<T>","onComplete?: (response: T, auditor: Auditor<TAuditAction>) => Promise<void>","response"],"sources":["../src/endpoints/processAudits.ts"],"sourcesContent":["import type {\n AuditActor,\n AuditStorage,\n AuditableAction,\n Auditor,\n} from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { withAuditableTransaction } from '@geekmidas/audit/kysely';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { CookieFn, Endpoint, HeaderFn } from './Endpoint';\nimport type { ActorExtractor, MappedAudit } from './audit';\n\n/**\n * Process declarative audit definitions after successful endpoint execution.\n * Similar to publishConstructEvents for events.\n *\n * @param endpoint - The endpoint with audit configuration\n * @param response - The handler response to generate audit payloads from\n * @param serviceDiscovery - Service discovery for registering audit storage\n * @param logger - Logger for debug/error messages\n * @param ctx - Request context (session, headers, cookies, services)\n * @param existingAuditor - Optional existing auditor instance (e.g., from handler context).\n * If provided, uses this auditor (with its stored transaction).\n * If not provided, creates a new auditor.\n */\nexport async function processEndpointAudits<\n TServices extends Service[] = [],\n TSession = unknown,\n TLogger extends Logger = Logger,\n OutSchema extends StandardSchemaV1 | undefined = undefined,\n TAuditStorage extends AuditStorage | undefined = undefined,\n TAuditStorageServiceName extends string = string,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n>(\n endpoint: Endpoint<\n any,\n any,\n any,\n OutSchema,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction\n >,\n response: InferStandardSchema<OutSchema>,\n serviceDiscovery: ServiceDiscovery<any, any>,\n logger: TLogger,\n ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n },\n existingAuditor?: Auditor<TAuditAction>,\n): Promise<void> {\n try {\n const audits = endpoint.audits as MappedAudit<TAuditAction, OutSchema>[];\n\n // If we have an existing auditor (from handler context), we need to flush\n // any manual audits it collected, even if there are no declarative audits\n const hasExistingRecords =\n existingAuditor && existingAuditor.getRecords().length > 0;\n\n // Skip if no declarative audits and no existing records to flush\n if (!audits?.length && !hasExistingRecords) {\n logger.debug('No audits to process');\n return;\n }\n\n // If no auditor storage service and we have things to process, warn\n if (!endpoint.auditorStorageService) {\n if (hasExistingRecords || audits?.length) {\n logger.warn('No auditor storage service available');\n }\n return;\n }\n\n // Get or create auditor\n let auditor: Auditor<TAuditAction>;\n\n if (existingAuditor) {\n // Use existing auditor (preserves stored transaction and manual audits)\n auditor = existingAuditor;\n logger.debug('Using existing auditor from handler context');\n } else {\n // Create new auditor (backward compatibility)\n const services = await serviceDiscovery.register([\n endpoint.auditorStorageService,\n ]);\n const storage = services[\n endpoint.auditorStorageService.serviceName\n ] as AuditStorage;\n\n // Extract actor if configured\n let actor: AuditActor = { id: 'system', type: 'system' };\n if (endpoint.actorExtractor) {\n try {\n actor = await (\n endpoint.actorExtractor as ActorExtractor<\n TServices,\n TSession,\n TLogger\n >\n )({\n services: ctx.services as any,\n session: ctx.session,\n header: ctx.header,\n cookie: ctx.cookie,\n logger,\n });\n } catch (error) {\n logger.error(error as Error, 'Failed to extract actor for audits');\n // Continue with system actor\n }\n }\n\n auditor = new DefaultAuditor<TAuditAction>({\n actor,\n storage,\n metadata: {\n endpoint: endpoint.route,\n method: endpoint.method,\n },\n });\n }\n\n // Process each declarative audit\n if (audits?.length) {\n for (const audit of audits) {\n logger.debug({ audit: audit.type }, 'Processing declarative audit');\n\n // Check when condition\n if (audit.when && !audit.when(response as any)) {\n logger.debug(\n { audit: audit.type },\n 'Audit skipped due to when condition',\n );\n continue;\n }\n\n // Extract payload\n const payload = audit.payload(response as any);\n\n // Extract entityId if configured\n const entityId = audit.entityId?.(response as any);\n\n // Record the audit\n auditor.audit(audit.type as any, payload as any, {\n table: audit.table,\n entityId,\n });\n }\n }\n\n // Flush audits to storage\n // Note: If existingAuditor has a stored transaction (via setTransaction),\n // flush() will use it automatically\n const recordCount = auditor.getRecords().length;\n if (recordCount > 0) {\n // Check if auditor has a stored transaction (for logging purposes)\n const trx =\n 'getTransaction' in auditor\n ? (auditor as { getTransaction(): unknown }).getTransaction()\n : undefined;\n logger.debug(\n { auditCount: recordCount, hasTransaction: !!trx },\n 'Flushing audits',\n );\n await auditor.flush();\n }\n } catch (error) {\n logger.error(error as Error, 'Failed to process audits');\n // Don't rethrow - audit failures shouldn't fail the request\n }\n}\n\n/**\n * Context for audit-aware handler execution.\n */\nexport interface AuditExecutionContext<\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n> {\n /** The auditor instance for recording audits */\n auditor: Auditor<TAuditAction>;\n /** The audit storage instance */\n storage: AuditStorage;\n}\n\n/**\n * Create audit context for handler execution.\n * Returns the auditor and storage for use in the handler.\n *\n * @param endpoint - The endpoint with audit configuration\n * @param serviceDiscovery - Service discovery for getting audit storage\n * @param logger - Logger for debug/error messages\n * @param ctx - Request context for actor extraction\n * @returns Audit context with auditor and storage, or undefined if not configured\n */\nexport async function createAuditContext<\n TServices extends Service[] = [],\n TSession = unknown,\n TLogger extends Logger = Logger,\n TAuditStorage extends AuditStorage | undefined = undefined,\n TAuditStorageServiceName extends string = string,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n TDatabase = undefined,\n TDatabaseServiceName extends string = string,\n>(\n endpoint: Endpoint<\n any,\n any,\n any,\n any,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction,\n TDatabase,\n TDatabaseServiceName\n >,\n serviceDiscovery: ServiceDiscovery<any, any>,\n logger: TLogger,\n ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n },\n): Promise<AuditExecutionContext<TAuditAction> | undefined> {\n if (!endpoint.auditorStorageService) {\n return undefined;\n }\n\n const services = await serviceDiscovery.register([\n endpoint.auditorStorageService,\n ]);\n const storage = services[\n endpoint.auditorStorageService.serviceName\n ] as AuditStorage;\n\n // Extract actor if configured\n let actor: AuditActor = { id: 'system', type: 'system' };\n if (endpoint.actorExtractor) {\n try {\n actor = await (\n endpoint.actorExtractor as ActorExtractor<TServices, TSession, TLogger>\n )({\n services: ctx.services as any,\n session: ctx.session,\n header: ctx.header,\n cookie: ctx.cookie,\n logger,\n });\n } catch (error) {\n logger.error(error as Error, 'Failed to extract actor for audits');\n }\n }\n\n const auditor = new DefaultAuditor<TAuditAction>({\n actor,\n storage,\n metadata: {\n endpoint: endpoint.route,\n method: endpoint.method,\n },\n });\n\n return { auditor, storage };\n}\n\n/**\n * Execute a handler with automatic audit transaction support.\n * If the audit storage has a database (via getDatabase()), wraps execution\n * in a transaction so audits are atomic with handler's database operations.\n *\n * @param auditContext - The audit context from createAuditContext\n * @param handler - The handler function to execute (receives auditor)\n * @param onComplete - Called after handler with response, to process declarative audits\n * @returns The handler result\n */\nexport async function executeWithAuditTransaction<\n T,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n>(\n auditContext: AuditExecutionContext<TAuditAction> | undefined,\n handler: (auditor?: Auditor<TAuditAction>) => Promise<T>,\n onComplete?: (response: T, auditor: Auditor<TAuditAction>) => Promise<void>,\n): Promise<T> {\n // No audit context - just run handler\n if (!auditContext) {\n return handler(undefined);\n }\n\n const { auditor, storage } = auditContext;\n\n // Check if storage has a database for transactional execution\n const db = storage.getDatabase?.();\n\n if (db) {\n // Wrap in transaction - audits are atomic with handler operations\n return withAuditableTransaction(db as any, auditor as any, async () => {\n const response = await handler(auditor);\n\n // Process declarative audits within the transaction\n if (onComplete) {\n await onComplete(response, auditor);\n }\n\n // Audits are flushed by withAuditableTransaction before commit\n return response;\n });\n }\n\n // No database - run handler and flush audits after\n const response = await handler(auditor);\n\n if (onComplete) {\n await onComplete(response, auditor);\n }\n\n // Flush audits (no transaction)\n await auditor.flush();\n\n return response;\n}\n"],"mappings":"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"}
@@ -171,4 +171,4 @@ Object.defineProperty(exports, 'processEndpointAudits', {
171
171
  return processEndpointAudits;
172
172
  }
173
173
  });
174
- //# sourceMappingURL=processAudits-BFokHhCO.cjs.map
174
+ //# sourceMappingURL=processAudits-MHp5_fc7.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"processAudits-BFokHhCO.cjs","names":["endpoint: Endpoint<\n any,\n any,\n any,\n OutSchema,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction\n >","response: InferStandardSchema<OutSchema>","serviceDiscovery: ServiceDiscovery<any, any>","logger: TLogger","ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n }","existingAuditor?: Auditor<TAuditAction>","auditor: Auditor<TAuditAction>","actor: AuditActor","DefaultAuditor","endpoint: Endpoint<\n any,\n any,\n any,\n any,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction,\n TDatabase,\n TDatabaseServiceName\n >","auditContext: AuditExecutionContext<TAuditAction> | undefined","handler: (auditor?: Auditor<TAuditAction>) => Promise<T>","onComplete?: (response: T, auditor: Auditor<TAuditAction>) => Promise<void>","response"],"sources":["../src/endpoints/processAudits.ts"],"sourcesContent":["import type {\n AuditActor,\n AuditStorage,\n AuditableAction,\n Auditor,\n} from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { withAuditableTransaction } from '@geekmidas/audit/kysely';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { CookieFn, Endpoint, HeaderFn } from './Endpoint';\nimport type { ActorExtractor, MappedAudit } from './audit';\n\n/**\n * Process declarative audit definitions after successful endpoint execution.\n * Similar to publishConstructEvents for events.\n *\n * @param endpoint - The endpoint with audit configuration\n * @param response - The handler response to generate audit payloads from\n * @param serviceDiscovery - Service discovery for registering audit storage\n * @param logger - Logger for debug/error messages\n * @param ctx - Request context (session, headers, cookies, services)\n * @param existingAuditor - Optional existing auditor instance (e.g., from handler context).\n * If provided, uses this auditor (with its stored transaction).\n * If not provided, creates a new auditor.\n */\nexport async function processEndpointAudits<\n TServices extends Service[] = [],\n TSession = unknown,\n TLogger extends Logger = Logger,\n OutSchema extends StandardSchemaV1 | undefined = undefined,\n TAuditStorage extends AuditStorage | undefined = undefined,\n TAuditStorageServiceName extends string = string,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n>(\n endpoint: Endpoint<\n any,\n any,\n any,\n OutSchema,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction\n >,\n response: InferStandardSchema<OutSchema>,\n serviceDiscovery: ServiceDiscovery<any, any>,\n logger: TLogger,\n ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n },\n existingAuditor?: Auditor<TAuditAction>,\n): Promise<void> {\n try {\n const audits = endpoint.audits as MappedAudit<TAuditAction, OutSchema>[];\n\n // If we have an existing auditor (from handler context), we need to flush\n // any manual audits it collected, even if there are no declarative audits\n const hasExistingRecords =\n existingAuditor && existingAuditor.getRecords().length > 0;\n\n // Skip if no declarative audits and no existing records to flush\n if (!audits?.length && !hasExistingRecords) {\n logger.debug('No audits to process');\n return;\n }\n\n // If no auditor storage service and we have things to process, warn\n if (!endpoint.auditorStorageService) {\n if (hasExistingRecords || audits?.length) {\n logger.warn('No auditor storage service available');\n }\n return;\n }\n\n // Get or create auditor\n let auditor: Auditor<TAuditAction>;\n\n if (existingAuditor) {\n // Use existing auditor (preserves stored transaction and manual audits)\n auditor = existingAuditor;\n logger.debug('Using existing auditor from handler context');\n } else {\n // Create new auditor (backward compatibility)\n const services = await serviceDiscovery.register([\n endpoint.auditorStorageService,\n ]);\n const storage = services[\n endpoint.auditorStorageService.serviceName\n ] as AuditStorage;\n\n // Extract actor if configured\n let actor: AuditActor = { id: 'system', type: 'system' };\n if (endpoint.actorExtractor) {\n try {\n actor = await (\n endpoint.actorExtractor as ActorExtractor<\n TServices,\n TSession,\n TLogger\n >\n )({\n services: ctx.services as any,\n session: ctx.session,\n header: ctx.header,\n cookie: ctx.cookie,\n logger,\n });\n } catch (error) {\n logger.error(error as Error, 'Failed to extract actor for audits');\n // Continue with system actor\n }\n }\n\n auditor = new DefaultAuditor<TAuditAction>({\n actor,\n storage,\n metadata: {\n endpoint: endpoint.route,\n method: endpoint.method,\n },\n });\n }\n\n // Process each declarative audit\n if (audits?.length) {\n for (const audit of audits) {\n logger.debug({ audit: audit.type }, 'Processing declarative audit');\n\n // Check when condition\n if (audit.when && !audit.when(response as any)) {\n logger.debug(\n { audit: audit.type },\n 'Audit skipped due to when condition',\n );\n continue;\n }\n\n // Extract payload\n const payload = audit.payload(response as any);\n\n // Extract entityId if configured\n const entityId = audit.entityId?.(response as any);\n\n // Record the audit\n auditor.audit(audit.type as any, payload as any, {\n table: audit.table,\n entityId,\n });\n }\n }\n\n // Flush audits to storage\n // Note: If existingAuditor has a stored transaction (via setTransaction),\n // flush() will use it automatically\n const recordCount = auditor.getRecords().length;\n if (recordCount > 0) {\n // Check if auditor has a stored transaction (for logging purposes)\n const trx =\n 'getTransaction' in auditor\n ? (auditor as { getTransaction(): unknown }).getTransaction()\n : undefined;\n logger.debug(\n { auditCount: recordCount, hasTransaction: !!trx },\n 'Flushing audits',\n );\n await auditor.flush();\n }\n } catch (error) {\n logger.error(error as Error, 'Failed to process audits');\n // Don't rethrow - audit failures shouldn't fail the request\n }\n}\n\n/**\n * Context for audit-aware handler execution.\n */\nexport interface AuditExecutionContext<\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n> {\n /** The auditor instance for recording audits */\n auditor: Auditor<TAuditAction>;\n /** The audit storage instance */\n storage: AuditStorage;\n}\n\n/**\n * Create audit context for handler execution.\n * Returns the auditor and storage for use in the handler.\n *\n * @param endpoint - The endpoint with audit configuration\n * @param serviceDiscovery - Service discovery for getting audit storage\n * @param logger - Logger for debug/error messages\n * @param ctx - Request context for actor extraction\n * @returns Audit context with auditor and storage, or undefined if not configured\n */\nexport async function createAuditContext<\n TServices extends Service[] = [],\n TSession = unknown,\n TLogger extends Logger = Logger,\n TAuditStorage extends AuditStorage | undefined = undefined,\n TAuditStorageServiceName extends string = string,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n TDatabase = undefined,\n TDatabaseServiceName extends string = string,\n>(\n endpoint: Endpoint<\n any,\n any,\n any,\n any,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction,\n TDatabase,\n TDatabaseServiceName\n >,\n serviceDiscovery: ServiceDiscovery<any, any>,\n logger: TLogger,\n ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n },\n): Promise<AuditExecutionContext<TAuditAction> | undefined> {\n if (!endpoint.auditorStorageService) {\n return undefined;\n }\n\n const services = await serviceDiscovery.register([\n endpoint.auditorStorageService,\n ]);\n const storage = services[\n endpoint.auditorStorageService.serviceName\n ] as AuditStorage;\n\n // Extract actor if configured\n let actor: AuditActor = { id: 'system', type: 'system' };\n if (endpoint.actorExtractor) {\n try {\n actor = await (\n endpoint.actorExtractor as ActorExtractor<TServices, TSession, TLogger>\n )({\n services: ctx.services as any,\n session: ctx.session,\n header: ctx.header,\n cookie: ctx.cookie,\n logger,\n });\n } catch (error) {\n logger.error(error as Error, 'Failed to extract actor for audits');\n }\n }\n\n const auditor = new DefaultAuditor<TAuditAction>({\n actor,\n storage,\n metadata: {\n endpoint: endpoint.route,\n method: endpoint.method,\n },\n });\n\n return { auditor, storage };\n}\n\n/**\n * Execute a handler with automatic audit transaction support.\n * If the audit storage has a database (via getDatabase()), wraps execution\n * in a transaction so audits are atomic with handler's database operations.\n *\n * @param auditContext - The audit context from createAuditContext\n * @param handler - The handler function to execute (receives auditor)\n * @param onComplete - Called after handler with response, to process declarative audits\n * @returns The handler result\n */\nexport async function executeWithAuditTransaction<\n T,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n>(\n auditContext: AuditExecutionContext<TAuditAction> | undefined,\n handler: (auditor?: Auditor<TAuditAction>) => Promise<T>,\n onComplete?: (response: T, auditor: Auditor<TAuditAction>) => Promise<void>,\n): Promise<T> {\n // No audit context - just run handler\n if (!auditContext) {\n return handler(undefined);\n }\n\n const { auditor, storage } = auditContext;\n\n // Check if storage has a database for transactional execution\n const db = storage.getDatabase?.();\n\n if (db) {\n // Wrap in transaction - audits are atomic with handler operations\n return withAuditableTransaction(db as any, auditor as any, async () => {\n const response = await handler(auditor);\n\n // Process declarative audits within the transaction\n if (onComplete) {\n await onComplete(response, auditor);\n }\n\n // Audits are flushed by withAuditableTransaction before commit\n return response;\n });\n }\n\n // No database - run handler and flush audits after\n const response = await handler(auditor);\n\n if (onComplete) {\n await onComplete(response, auditor);\n }\n\n // Flush audits (no transaction)\n await auditor.flush();\n\n return response;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"processAudits-MHp5_fc7.cjs","names":["endpoint: Endpoint<\n any,\n any,\n any,\n OutSchema,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction\n >","response: InferStandardSchema<OutSchema>","serviceDiscovery: ServiceDiscovery<any, any>","logger: TLogger","ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n }","existingAuditor?: Auditor<TAuditAction>","auditor: Auditor<TAuditAction>","actor: AuditActor","DefaultAuditor","endpoint: Endpoint<\n any,\n any,\n any,\n any,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction,\n TDatabase,\n TDatabaseServiceName\n >","auditContext: AuditExecutionContext<TAuditAction> | undefined","handler: (auditor?: Auditor<TAuditAction>) => Promise<T>","onComplete?: (response: T, auditor: Auditor<TAuditAction>) => Promise<void>","response"],"sources":["../src/endpoints/processAudits.ts"],"sourcesContent":["import type {\n AuditActor,\n AuditStorage,\n AuditableAction,\n Auditor,\n} from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { withAuditableTransaction } from '@geekmidas/audit/kysely';\nimport type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceDiscovery } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { CookieFn, Endpoint, HeaderFn } from './Endpoint';\nimport type { ActorExtractor, MappedAudit } from './audit';\n\n/**\n * Process declarative audit definitions after successful endpoint execution.\n * Similar to publishConstructEvents for events.\n *\n * @param endpoint - The endpoint with audit configuration\n * @param response - The handler response to generate audit payloads from\n * @param serviceDiscovery - Service discovery for registering audit storage\n * @param logger - Logger for debug/error messages\n * @param ctx - Request context (session, headers, cookies, services)\n * @param existingAuditor - Optional existing auditor instance (e.g., from handler context).\n * If provided, uses this auditor (with its stored transaction).\n * If not provided, creates a new auditor.\n */\nexport async function processEndpointAudits<\n TServices extends Service[] = [],\n TSession = unknown,\n TLogger extends Logger = Logger,\n OutSchema extends StandardSchemaV1 | undefined = undefined,\n TAuditStorage extends AuditStorage | undefined = undefined,\n TAuditStorageServiceName extends string = string,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n>(\n endpoint: Endpoint<\n any,\n any,\n any,\n OutSchema,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction\n >,\n response: InferStandardSchema<OutSchema>,\n serviceDiscovery: ServiceDiscovery<any, any>,\n logger: TLogger,\n ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n },\n existingAuditor?: Auditor<TAuditAction>,\n): Promise<void> {\n try {\n const audits = endpoint.audits as MappedAudit<TAuditAction, OutSchema>[];\n\n // If we have an existing auditor (from handler context), we need to flush\n // any manual audits it collected, even if there are no declarative audits\n const hasExistingRecords =\n existingAuditor && existingAuditor.getRecords().length > 0;\n\n // Skip if no declarative audits and no existing records to flush\n if (!audits?.length && !hasExistingRecords) {\n logger.debug('No audits to process');\n return;\n }\n\n // If no auditor storage service and we have things to process, warn\n if (!endpoint.auditorStorageService) {\n if (hasExistingRecords || audits?.length) {\n logger.warn('No auditor storage service available');\n }\n return;\n }\n\n // Get or create auditor\n let auditor: Auditor<TAuditAction>;\n\n if (existingAuditor) {\n // Use existing auditor (preserves stored transaction and manual audits)\n auditor = existingAuditor;\n logger.debug('Using existing auditor from handler context');\n } else {\n // Create new auditor (backward compatibility)\n const services = await serviceDiscovery.register([\n endpoint.auditorStorageService,\n ]);\n const storage = services[\n endpoint.auditorStorageService.serviceName\n ] as AuditStorage;\n\n // Extract actor if configured\n let actor: AuditActor = { id: 'system', type: 'system' };\n if (endpoint.actorExtractor) {\n try {\n actor = await (\n endpoint.actorExtractor as ActorExtractor<\n TServices,\n TSession,\n TLogger\n >\n )({\n services: ctx.services as any,\n session: ctx.session,\n header: ctx.header,\n cookie: ctx.cookie,\n logger,\n });\n } catch (error) {\n logger.error(error as Error, 'Failed to extract actor for audits');\n // Continue with system actor\n }\n }\n\n auditor = new DefaultAuditor<TAuditAction>({\n actor,\n storage,\n metadata: {\n endpoint: endpoint.route,\n method: endpoint.method,\n },\n });\n }\n\n // Process each declarative audit\n if (audits?.length) {\n for (const audit of audits) {\n logger.debug({ audit: audit.type }, 'Processing declarative audit');\n\n // Check when condition\n if (audit.when && !audit.when(response as any)) {\n logger.debug(\n { audit: audit.type },\n 'Audit skipped due to when condition',\n );\n continue;\n }\n\n // Extract payload\n const payload = audit.payload(response as any);\n\n // Extract entityId if configured\n const entityId = audit.entityId?.(response as any);\n\n // Record the audit\n auditor.audit(audit.type as any, payload as any, {\n table: audit.table,\n entityId,\n });\n }\n }\n\n // Flush audits to storage\n // Note: If existingAuditor has a stored transaction (via setTransaction),\n // flush() will use it automatically\n const recordCount = auditor.getRecords().length;\n if (recordCount > 0) {\n // Check if auditor has a stored transaction (for logging purposes)\n const trx =\n 'getTransaction' in auditor\n ? (auditor as { getTransaction(): unknown }).getTransaction()\n : undefined;\n logger.debug(\n { auditCount: recordCount, hasTransaction: !!trx },\n 'Flushing audits',\n );\n await auditor.flush();\n }\n } catch (error) {\n logger.error(error as Error, 'Failed to process audits');\n // Don't rethrow - audit failures shouldn't fail the request\n }\n}\n\n/**\n * Context for audit-aware handler execution.\n */\nexport interface AuditExecutionContext<\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n> {\n /** The auditor instance for recording audits */\n auditor: Auditor<TAuditAction>;\n /** The audit storage instance */\n storage: AuditStorage;\n}\n\n/**\n * Create audit context for handler execution.\n * Returns the auditor and storage for use in the handler.\n *\n * @param endpoint - The endpoint with audit configuration\n * @param serviceDiscovery - Service discovery for getting audit storage\n * @param logger - Logger for debug/error messages\n * @param ctx - Request context for actor extraction\n * @returns Audit context with auditor and storage, or undefined if not configured\n */\nexport async function createAuditContext<\n TServices extends Service[] = [],\n TSession = unknown,\n TLogger extends Logger = Logger,\n TAuditStorage extends AuditStorage | undefined = undefined,\n TAuditStorageServiceName extends string = string,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n TDatabase = undefined,\n TDatabaseServiceName extends string = string,\n>(\n endpoint: Endpoint<\n any,\n any,\n any,\n any,\n TServices,\n TLogger,\n TSession,\n any,\n any,\n TAuditStorage,\n TAuditStorageServiceName,\n TAuditAction,\n TDatabase,\n TDatabaseServiceName\n >,\n serviceDiscovery: ServiceDiscovery<any, any>,\n logger: TLogger,\n ctx: {\n session: TSession;\n header: HeaderFn;\n cookie: CookieFn;\n services: Record<string, unknown>;\n },\n): Promise<AuditExecutionContext<TAuditAction> | undefined> {\n if (!endpoint.auditorStorageService) {\n return undefined;\n }\n\n const services = await serviceDiscovery.register([\n endpoint.auditorStorageService,\n ]);\n const storage = services[\n endpoint.auditorStorageService.serviceName\n ] as AuditStorage;\n\n // Extract actor if configured\n let actor: AuditActor = { id: 'system', type: 'system' };\n if (endpoint.actorExtractor) {\n try {\n actor = await (\n endpoint.actorExtractor as ActorExtractor<TServices, TSession, TLogger>\n )({\n services: ctx.services as any,\n session: ctx.session,\n header: ctx.header,\n cookie: ctx.cookie,\n logger,\n });\n } catch (error) {\n logger.error(error as Error, 'Failed to extract actor for audits');\n }\n }\n\n const auditor = new DefaultAuditor<TAuditAction>({\n actor,\n storage,\n metadata: {\n endpoint: endpoint.route,\n method: endpoint.method,\n },\n });\n\n return { auditor, storage };\n}\n\n/**\n * Execute a handler with automatic audit transaction support.\n * If the audit storage has a database (via getDatabase()), wraps execution\n * in a transaction so audits are atomic with handler's database operations.\n *\n * @param auditContext - The audit context from createAuditContext\n * @param handler - The handler function to execute (receives auditor)\n * @param onComplete - Called after handler with response, to process declarative audits\n * @returns The handler result\n */\nexport async function executeWithAuditTransaction<\n T,\n TAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n string,\n unknown\n >,\n>(\n auditContext: AuditExecutionContext<TAuditAction> | undefined,\n handler: (auditor?: Auditor<TAuditAction>) => Promise<T>,\n onComplete?: (response: T, auditor: Auditor<TAuditAction>) => Promise<void>,\n): Promise<T> {\n // No audit context - just run handler\n if (!auditContext) {\n return handler(undefined);\n }\n\n const { auditor, storage } = auditContext;\n\n // Check if storage has a database for transactional execution\n const db = storage.getDatabase?.();\n\n if (db) {\n // Wrap in transaction - audits are atomic with handler operations\n return withAuditableTransaction(db as any, auditor as any, async () => {\n const response = await handler(auditor);\n\n // Process declarative audits within the transaction\n if (onComplete) {\n await onComplete(response, auditor);\n }\n\n // Audits are flushed by withAuditableTransaction before commit\n return response;\n });\n }\n\n // No database - run handler and flush audits after\n const response = await handler(auditor);\n\n if (onComplete) {\n await onComplete(response, auditor);\n }\n\n // Flush audits (no transaction)\n await auditor.flush();\n\n return response;\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- const require_AWSLambdaSubscriberAdaptor = require('../AWSLambdaSubscriberAdaptor-Dum5bkw3.cjs');
1
+ const require_AWSLambdaSubscriberAdaptor = require('../AWSLambdaSubscriberAdaptor-DVC4VAQR.cjs');
2
2
 
3
3
  exports.AWSLambdaSubscriber = require_AWSLambdaSubscriberAdaptor.AWSLambdaSubscriber;
@@ -1,3 +1,3 @@
1
- import { AWSLambdaSubscriber } from "../AWSLambdaSubscriberAdaptor-CyFh7MN8.mjs";
1
+ import { AWSLambdaSubscriber } from "../AWSLambdaSubscriberAdaptor-BLHDyqzQ.mjs";
2
2
 
3
3
  export { AWSLambdaSubscriber };
@@ -1,10 +1,10 @@
1
1
  import "../Construct-dI_rgdSp.cjs";
2
2
  import { Subscriber } from "../Subscriber-BhzqUzs-.cjs";
3
3
  import { SubscriberBuilder } from "../SubscriberBuilder-BCVkp-ga.cjs";
4
- import * as _geekmidas_logger3 from "@geekmidas/logger";
4
+ import * as _geekmidas_logger9 from "@geekmidas/logger";
5
5
 
6
6
  //#region src/subscribers/index.d.ts
7
- declare const s: SubscriberBuilder<[], _geekmidas_logger3.Logger, undefined, undefined, string, []>;
7
+ declare const s: SubscriberBuilder<[], _geekmidas_logger9.Logger, undefined, undefined, string, []>;
8
8
  //#endregion
9
9
  export { Subscriber, SubscriberBuilder, s };
10
10
  //# sourceMappingURL=index.d.cts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekmidas/constructs",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -66,14 +66,14 @@
66
66
  "lodash.set": "~4.3.2",
67
67
  "lodash.uniqby": "~4.7.0",
68
68
  "openapi-types": "~12.1.3",
69
- "@geekmidas/audit": "0.0.5",
69
+ "@geekmidas/audit": "0.0.6",
70
+ "@geekmidas/errors": "0.0.1",
70
71
  "@geekmidas/cache": "0.0.7",
71
72
  "@geekmidas/events": "0.0.2",
72
- "@geekmidas/logger": "0.0.1",
73
- "@geekmidas/services": "0.0.1",
74
73
  "@geekmidas/rate-limit": "0.1.0",
75
74
  "@geekmidas/schema": "0.0.2",
76
- "@geekmidas/errors": "0.0.1"
75
+ "@geekmidas/logger": "0.0.1",
76
+ "@geekmidas/services": "0.0.1"
77
77
  },
78
78
  "devDependencies": {
79
79
  "@types/lodash.compact": "~3.0.9",
@@ -9,10 +9,10 @@ import { ConsoleLogger } from '@geekmidas/logger/console';
9
9
  import type { Service } from '@geekmidas/services';
10
10
  import uniqBy from 'lodash.uniqby';
11
11
  import type { HttpMethod } from '../types';
12
- import type { ActorExtractor } from './audit';
13
12
  import type { Authorizer } from './Authorizer';
14
13
  import type { AuthorizeFn, SessionFn } from './Endpoint';
15
14
  import { EndpointBuilder } from './EndpointBuilder';
15
+ import type { ActorExtractor } from './audit';
16
16
 
17
17
  const DEFAULT_LOGGER = new ConsoleLogger() as any;
18
18
 
@@ -26,9 +26,10 @@ export class EndpointFactory<
26
26
  TAuthorizers extends readonly string[] = readonly string[],
27
27
  TAuditStorage extends AuditStorage<any> | undefined = undefined,
28
28
  TAuditStorageServiceName extends string = string,
29
- TAuditAction extends AuditableAction<string, unknown> = ExtractStorageAuditAction<
30
- NonNullable<TAuditStorage>
31
- >,
29
+ TAuditAction extends AuditableAction<
30
+ string,
31
+ unknown
32
+ > = ExtractStorageAuditAction<NonNullable<TAuditStorage>>,
32
33
  TDatabase = undefined,
33
34
  TDatabaseServiceName extends string = string,
34
35
  > {
@@ -366,7 +367,11 @@ export class EndpointFactory<
366
367
  defaultAuditorStorage: this.defaultAuditorStorage,
367
368
  defaultDatabaseService: this.defaultDatabaseService,
368
369
  defaultActorExtractor: this
369
- .defaultActorExtractor as unknown as ActorExtractor<TServices, TSession, L>,
370
+ .defaultActorExtractor as unknown as ActorExtractor<
371
+ TServices,
372
+ TSession,
373
+ L
374
+ >,
370
375
  });
371
376
  }
372
377
 
@@ -462,7 +467,11 @@ export class EndpointFactory<
462
467
  defaultAuditorStorage: this.defaultAuditorStorage,
463
468
  defaultDatabaseService: this.defaultDatabaseService,
464
469
  defaultActorExtractor: this
465
- .defaultActorExtractor as unknown as ActorExtractor<TServices, T, TLogger>,
470
+ .defaultActorExtractor as unknown as ActorExtractor<
471
+ TServices,
472
+ T,
473
+ TLogger
474
+ >,
466
475
  });
467
476
  }
468
477
 
@@ -558,7 +567,8 @@ export class EndpointFactory<
558
567
  defaultAuthorizerName: this.defaultAuthorizerName,
559
568
  defaultAuditorStorage: storage,
560
569
  defaultDatabaseService: this.defaultDatabaseService,
561
- defaultActorExtractor: this.defaultActorExtractor as unknown as ActorExtractor<
570
+ defaultActorExtractor: this
571
+ .defaultActorExtractor as unknown as ActorExtractor<
562
572
  TServices,
563
573
  TSession,
564
574
  TLogger
@@ -1,4 +1,5 @@
1
- import type { AuditStorage, AuditableAction } from '@geekmidas/audit';
1
+ import type { AuditActor, AuditStorage, AuditableAction } from '@geekmidas/audit';
2
+ import { DefaultAuditor } from '@geekmidas/audit';
2
3
  import { EnvironmentParser } from '@geekmidas/envkit';
3
4
  import type { EventPublisher } from '@geekmidas/events';
4
5
  import type { Logger } from '@geekmidas/logger';
@@ -22,7 +23,7 @@ import {
22
23
  } from './Endpoint';
23
24
  import type { MappedAudit } from './audit';
24
25
  import {
25
- createAuditContext,
26
+ type AuditExecutionContext,
26
27
  executeWithAuditTransaction,
27
28
  } from './processAudits';
28
29
 
@@ -85,6 +86,8 @@ export class TestEndpointAdaptor<
85
86
  string,
86
87
  unknown
87
88
  >,
89
+ TDatabase = undefined,
90
+ TDatabaseServiceName extends string = string,
88
91
  > {
89
92
  static getDefaultServiceDiscover<
90
93
  TRoute extends string,
@@ -102,6 +105,8 @@ export class TestEndpointAdaptor<
102
105
  string,
103
106
  unknown
104
107
  >,
108
+ TDatabase = undefined,
109
+ TDatabaseServiceName extends string = string,
105
110
  >(
106
111
  endpoint: Endpoint<
107
112
  TRoute,
@@ -115,7 +120,9 @@ export class TestEndpointAdaptor<
115
120
  TEventPublisherServiceName,
116
121
  TAuditStorage,
117
122
  TAuditStorageServiceName,
118
- TAuditAction
123
+ TAuditAction,
124
+ TDatabase,
125
+ TDatabaseServiceName
119
126
  >,
120
127
  ) {
121
128
  return ServiceDiscovery.getInstance(
@@ -136,7 +143,9 @@ export class TestEndpointAdaptor<
136
143
  TEventPublisherServiceName,
137
144
  TAuditStorage,
138
145
  TAuditStorageServiceName,
139
- TAuditAction
146
+ TAuditAction,
147
+ TDatabase,
148
+ TDatabaseServiceName
140
149
  >,
141
150
  private serviceDiscovery: ServiceDiscovery<
142
151
  any,
@@ -149,7 +158,11 @@ export class TestEndpointAdaptor<
149
158
  TInput,
150
159
  TServices,
151
160
  TEventPublisher,
152
- TEventPublisherServiceName
161
+ TEventPublisherServiceName,
162
+ TAuditStorage,
163
+ TAuditStorageServiceName,
164
+ TDatabase,
165
+ TDatabaseServiceName
153
166
  >,
154
167
  ): Promise<TestHttpResponse<InferStandardSchema<TOutSchema>>> {
155
168
  const body = await this.endpoint.parseInput((ctx as any).body, 'body');
@@ -173,18 +186,39 @@ export class TestEndpointAdaptor<
173
186
  cookie,
174
187
  });
175
188
 
176
- // Create audit context if audit storage is configured
177
- const auditContext = await createAuditContext(
178
- this.endpoint,
179
- this.serviceDiscovery,
180
- logger,
181
- {
182
- session,
183
- header,
184
- cookie,
185
- services: ctx.services as Record<string, unknown>,
186
- },
187
- );
189
+ // Create audit context if audit storage is provided
190
+ // The auditorStorage instance is required when endpoint uses .auditor()
191
+ const auditorStorage = (ctx as any).auditorStorage as TAuditStorage;
192
+ let auditContext: AuditExecutionContext<TAuditAction> | undefined;
193
+
194
+ if (auditorStorage) {
195
+ // Extract actor if configured
196
+ let actor: AuditActor = { id: 'system', type: 'system' };
197
+ if (this.endpoint.actorExtractor) {
198
+ try {
199
+ actor = await this.endpoint.actorExtractor({
200
+ services: ctx.services as any,
201
+ session,
202
+ header,
203
+ cookie,
204
+ logger,
205
+ });
206
+ } catch (error) {
207
+ logger.error(error as Error, 'Failed to extract actor for audits');
208
+ }
209
+ }
210
+
211
+ const auditor = new DefaultAuditor<TAuditAction>({
212
+ actor,
213
+ storage: auditorStorage as AuditStorage,
214
+ metadata: {
215
+ endpoint: this.endpoint.route,
216
+ method: this.endpoint.method,
217
+ },
218
+ });
219
+
220
+ auditContext = { auditor, storage: auditorStorage as AuditStorage };
221
+ }
188
222
 
189
223
  // Warn if declarative audits are configured but no audit storage
190
224
  const audits = this.endpoint.audits as MappedAudit<
@@ -195,28 +229,18 @@ export class TestEndpointAdaptor<
195
229
  logger.warn('No auditor storage service available');
196
230
  }
197
231
 
198
- // Resolve database service if configured
199
- const rawDb = this.endpoint.databaseService
200
- ? await this.serviceDiscovery
201
- .register([this.endpoint.databaseService])
202
- .then(
203
- (s) =>
204
- s[this.endpoint.databaseService!.serviceName as keyof typeof s],
205
- )
206
- : undefined;
232
+ // Use database instance directly from context
233
+ // The database instance is required when endpoint uses .database()
234
+ const rawDb = (ctx as any).database as TDatabase;
207
235
 
208
236
  // Execute handler with automatic audit transaction support
209
237
  const result = await executeWithAuditTransaction(
210
238
  auditContext,
211
239
  async (auditor) => {
212
- // Use audit transaction as db only if the storage uses the same database service
213
- const sameDatabase =
214
- auditContext?.storage?.databaseServiceName &&
215
- auditContext.storage.databaseServiceName ===
216
- this.endpoint.databaseService?.serviceName;
217
- const db = sameDatabase
218
- ? (auditor?.getTransaction?.() ?? rawDb)
219
- : rawDb;
240
+ // Use audit transaction as db if available (when storage has same database)
241
+ // For testing, the tester controls whether to use transactional auditing
242
+ const trx = auditor?.getTransaction?.();
243
+ const db = trx ?? rawDb;
220
244
 
221
245
  const responseBuilder = new ResponseBuilder();
222
246
  const response = await this.endpoint.handler(
@@ -299,7 +323,11 @@ export class TestEndpointAdaptor<
299
323
  TInput,
300
324
  TServices,
301
325
  TEventPublisher,
302
- TEventPublisherServiceName
326
+ TEventPublisherServiceName,
327
+ TAuditStorage,
328
+ TAuditStorageServiceName,
329
+ TDatabase,
330
+ TDatabaseServiceName
303
331
  >,
304
332
  ): Promise<InferStandardSchema<TOutSchema>> {
305
333
  const response = await this.fullRequest(ctx);
@@ -307,13 +335,41 @@ export class TestEndpointAdaptor<
307
335
  }
308
336
  }
309
337
 
338
+ /**
339
+ * Conditional audit storage requirement - required when TAuditStorage is configured
340
+ */
341
+ type AuditStorageRequirement<
342
+ TAuditStorage extends AuditStorage | undefined = undefined,
343
+ > = TAuditStorage extends undefined
344
+ ? {}
345
+ : {
346
+ /** Audit storage instance - required when endpoint uses .auditor() */
347
+ auditorStorage: TAuditStorage;
348
+ };
349
+
350
+ /**
351
+ * Conditional database requirement - required when TDatabase is configured
352
+ */
353
+ type DatabaseRequirement<TDatabase = undefined> = TDatabase extends undefined
354
+ ? {}
355
+ : {
356
+ /** Database instance - required when endpoint uses .database() */
357
+ database: TDatabase;
358
+ };
359
+
310
360
  export type TestRequestAdaptor<
311
361
  TInput extends EndpointSchemas = {},
312
362
  TServices extends Service[] = [],
313
363
  TEventPublisher extends EventPublisher<any> | undefined = undefined,
314
364
  TEventPublisherServiceName extends string = string,
365
+ TAuditStorage extends AuditStorage | undefined = undefined,
366
+ _TAuditStorageServiceName extends string = string,
367
+ TDatabase = undefined,
368
+ _TDatabaseServiceName extends string = string,
315
369
  > = {
316
370
  services: ServiceRecord<TServices>;
317
371
  headers: Record<string, string>;
318
372
  publisher?: Service<TEventPublisherServiceName, TEventPublisher>;
319
- } & InferComposableStandardSchema<TInput>;
373
+ } & InferComposableStandardSchema<TInput> &
374
+ AuditStorageRequirement<TAuditStorage> &
375
+ DatabaseRequirement<TDatabase>;