@geekmidas/constructs 9.0.2 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/{AWSScheduledFunction-Bn99MceY.d.cts → AWSScheduledFunction-BHHlWlfV.d.cts} +2 -2
  3. package/dist/{AWSScheduledFunction-ysaCsdWx.d.mts.map → AWSScheduledFunction-BHHlWlfV.d.cts.map} +1 -1
  4. package/dist/{AWSScheduledFunction-ysaCsdWx.d.mts → AWSScheduledFunction-BzGCUbkk.d.mts} +2 -2
  5. package/dist/{AWSScheduledFunction-Bn99MceY.d.cts.map → AWSScheduledFunction-BzGCUbkk.d.mts.map} +1 -1
  6. package/dist/{AWSScheduledFunction-DbkDr8CA.cjs → AWSScheduledFunction-C42adp8A.cjs} +16 -5
  7. package/dist/AWSScheduledFunction-C42adp8A.cjs.map +1 -0
  8. package/dist/{AWSScheduledFunction-CufMMhGB.mjs → AWSScheduledFunction-KP6lqbsW.mjs} +15 -4
  9. package/dist/AWSScheduledFunction-KP6lqbsW.mjs.map +1 -0
  10. package/dist/{Construct-r0U2zBwW.mjs → Construct-BWF5HxaM.mjs} +5 -2
  11. package/dist/Construct-BWF5HxaM.mjs.map +1 -0
  12. package/dist/{Construct-_1wX7p_Y.d.cts → Construct-JlyQkBkv.d.cts} +39 -4
  13. package/dist/Construct-JlyQkBkv.d.cts.map +1 -0
  14. package/dist/{Construct-vXMZJgRp.cjs → Construct-TGIM_E4o.cjs} +5 -2
  15. package/dist/Construct-TGIM_E4o.cjs.map +1 -0
  16. package/dist/{Construct-DCMuYOox.d.mts → Construct-pxwC6fDD.d.mts} +39 -4
  17. package/dist/Construct-pxwC6fDD.d.mts.map +1 -0
  18. package/dist/{Endpoint-CLPSIl6S.d.mts → Endpoint-B0P_pEMr.d.mts} +3 -3
  19. package/dist/{Endpoint-CLPSIl6S.d.mts.map → Endpoint-B0P_pEMr.d.mts.map} +1 -1
  20. package/dist/{Endpoint-DgfRslct.d.cts → Endpoint-Cwjhc1Hl.d.cts} +2 -2
  21. package/dist/Endpoint-Cwjhc1Hl.d.cts.map +1 -0
  22. package/dist/{HonoEndpointAdaptor-DJDT3PMx.mjs → HonoEndpointAdaptor-BMVwx2cz.mjs} +18 -11
  23. package/dist/HonoEndpointAdaptor-BMVwx2cz.mjs.map +1 -0
  24. package/dist/{HonoEndpointAdaptor-CkJENANP.cjs → HonoEndpointAdaptor-DPDsDi-D.cjs} +19 -12
  25. package/dist/HonoEndpointAdaptor-DPDsDi-D.cjs.map +1 -0
  26. package/dist/{Queue-HBDf0fqz.d.mts → Queue-BL68oDJ-.d.mts} +2 -2
  27. package/dist/{Queue-DaxjwmOQ.d.cts.map → Queue-BL68oDJ-.d.mts.map} +1 -1
  28. package/dist/{Queue-DaxjwmOQ.d.cts → Queue-DxJ6btRE.d.cts} +2 -2
  29. package/dist/{Queue-HBDf0fqz.d.mts.map → Queue-DxJ6btRE.d.cts.map} +1 -1
  30. package/dist/{Subscriber-B69ngPwl.d.cts → Subscriber-BpVhcGhX.d.cts} +2 -2
  31. package/dist/{Subscriber-B69ngPwl.d.cts.map → Subscriber-BpVhcGhX.d.cts.map} +1 -1
  32. package/dist/{Subscriber-D8Xm-86W.d.mts → Subscriber-DF6xsBAJ.d.mts} +2 -2
  33. package/dist/{Subscriber-D8Xm-86W.d.mts.map → Subscriber-DF6xsBAJ.d.mts.map} +1 -1
  34. package/dist/{Topic-DT10AqHk.d.mts → Topic-DJXoDeMP.d.cts} +3 -3
  35. package/dist/{Topic-C5ZMfveW.d.cts.map → Topic-DJXoDeMP.d.cts.map} +1 -1
  36. package/dist/{Topic-C5ZMfveW.d.cts → Topic-DxWQBgMN.d.mts} +3 -3
  37. package/dist/{Topic-DT10AqHk.d.mts.map → Topic-DxWQBgMN.d.mts.map} +1 -1
  38. package/dist/adaptors/aws.cjs +14 -7
  39. package/dist/adaptors/aws.cjs.map +1 -1
  40. package/dist/adaptors/aws.d.cts +6 -6
  41. package/dist/adaptors/aws.d.cts.map +1 -1
  42. package/dist/adaptors/aws.d.mts +8 -8
  43. package/dist/adaptors/aws.d.mts.map +1 -1
  44. package/dist/adaptors/aws.mjs +14 -7
  45. package/dist/adaptors/aws.mjs.map +1 -1
  46. package/dist/adaptors/hono.cjs +7 -6
  47. package/dist/adaptors/hono.d.cts +3 -3
  48. package/dist/adaptors/hono.d.cts.map +1 -1
  49. package/dist/adaptors/hono.d.mts +4 -4
  50. package/dist/adaptors/hono.d.mts.map +1 -1
  51. package/dist/adaptors/hono.mjs +7 -6
  52. package/dist/adaptors/testing.cjs +161 -126
  53. package/dist/adaptors/testing.cjs.map +1 -1
  54. package/dist/adaptors/testing.d.cts +7 -5
  55. package/dist/adaptors/testing.d.cts.map +1 -1
  56. package/dist/adaptors/testing.d.mts +8 -6
  57. package/dist/adaptors/testing.d.mts.map +1 -1
  58. package/dist/adaptors/testing.mjs +162 -127
  59. package/dist/adaptors/testing.mjs.map +1 -1
  60. package/dist/clone-I_WIpiFf.cjs +45 -0
  61. package/dist/clone-I_WIpiFf.cjs.map +1 -0
  62. package/dist/clone-pdXxc0t3.mjs +39 -0
  63. package/dist/clone-pdXxc0t3.mjs.map +1 -0
  64. package/dist/crons/index.cjs +14 -32
  65. package/dist/crons/index.cjs.map +1 -1
  66. package/dist/crons/index.d.cts +7 -7
  67. package/dist/crons/index.d.cts.map +1 -1
  68. package/dist/crons/index.d.mts +3 -3
  69. package/dist/crons/index.d.mts.map +1 -1
  70. package/dist/crons/index.mjs +14 -32
  71. package/dist/crons/index.mjs.map +1 -1
  72. package/dist/endpoints/index.cjs +74 -61
  73. package/dist/endpoints/index.cjs.map +1 -1
  74. package/dist/endpoints/index.d.cts +14 -6
  75. package/dist/endpoints/index.d.cts.map +1 -1
  76. package/dist/endpoints/index.d.mts +13 -5
  77. package/dist/endpoints/index.d.mts.map +1 -1
  78. package/dist/endpoints/index.mjs +74 -61
  79. package/dist/endpoints/index.mjs.map +1 -1
  80. package/dist/functions/index.cjs +3 -2
  81. package/dist/functions/index.d.cts +2 -2
  82. package/dist/functions/index.d.mts +2 -2
  83. package/dist/functions/index.mjs +3 -2
  84. package/dist/{functions-B-qt91O7.mjs → functions-EqTloHjo.mjs} +107 -46
  85. package/dist/functions-EqTloHjo.mjs.map +1 -0
  86. package/dist/{functions-C8i1kCMM.cjs → functions-SqtCDc9c.cjs} +118 -45
  87. package/dist/functions-SqtCDc9c.cjs.map +1 -0
  88. package/dist/{index-DP6fqv0I.d.mts → index-C7iynzLI.d.mts} +8 -2
  89. package/dist/index-C7iynzLI.d.mts.map +1 -0
  90. package/dist/{index-BVs9DvIj.d.cts → index-DdgJRm4q.d.cts} +12 -6
  91. package/dist/index-DdgJRm4q.d.cts.map +1 -0
  92. package/dist/index.cjs +1 -1
  93. package/dist/index.d.cts +2 -2
  94. package/dist/index.d.mts +4 -4
  95. package/dist/index.mjs +1 -1
  96. package/dist/{lazyAccessors-DfqZR6C4.mjs → lazyAccessors-CCTK19xj.mjs} +3 -3
  97. package/dist/{lazyAccessors-DfqZR6C4.mjs.map → lazyAccessors-CCTK19xj.mjs.map} +1 -1
  98. package/dist/{lazyAccessors-DmTG8sQH.cjs → lazyAccessors-D04oftGw.cjs} +3 -3
  99. package/dist/{lazyAccessors-DmTG8sQH.cjs.map → lazyAccessors-D04oftGw.cjs.map} +1 -1
  100. package/dist/monitors/index.cjs +49 -0
  101. package/dist/monitors/index.cjs.map +1 -0
  102. package/dist/monitors/index.d.cts +45 -0
  103. package/dist/monitors/index.d.cts.map +1 -0
  104. package/dist/monitors/index.d.mts +45 -0
  105. package/dist/monitors/index.d.mts.map +1 -0
  106. package/dist/monitors/index.mjs +48 -0
  107. package/dist/monitors/index.mjs.map +1 -0
  108. package/dist/{processAudits-CKjjivyz.cjs → processAudits-BJZT5gmy.cjs} +2 -2
  109. package/dist/{processAudits-CKjjivyz.cjs.map → processAudits-BJZT5gmy.cjs.map} +1 -1
  110. package/dist/{processAudits-ySnizdMG.mjs → processAudits-CwyaaSQc.mjs} +1 -1
  111. package/dist/{processAudits-ySnizdMG.mjs.map → processAudits-CwyaaSQc.mjs.map} +1 -1
  112. package/dist/{publisher-lFQleddL.cjs → publisher-BZgcrVPy.cjs} +1 -1
  113. package/dist/{publisher-lFQleddL.cjs.map → publisher-BZgcrVPy.cjs.map} +1 -1
  114. package/dist/{publisher-BrFOF847.mjs → publisher-CnpeMv-r.mjs} +1 -1
  115. package/dist/{publisher-BrFOF847.mjs.map → publisher-CnpeMv-r.mjs.map} +1 -1
  116. package/dist/queue/index.cjs +9 -22
  117. package/dist/queue/index.cjs.map +1 -1
  118. package/dist/queue/index.d.cts +4 -4
  119. package/dist/queue/index.d.cts.map +1 -1
  120. package/dist/queue/index.d.mts +2 -2
  121. package/dist/queue/index.d.mts.map +1 -1
  122. package/dist/queue/index.mjs +9 -22
  123. package/dist/queue/index.mjs.map +1 -1
  124. package/dist/subscribers/index.cjs +9 -22
  125. package/dist/subscribers/index.cjs.map +1 -1
  126. package/dist/subscribers/index.d.cts +5 -5
  127. package/dist/subscribers/index.d.cts.map +1 -1
  128. package/dist/subscribers/index.d.mts +3 -3
  129. package/dist/subscribers/index.d.mts.map +1 -1
  130. package/dist/subscribers/index.mjs +9 -22
  131. package/dist/subscribers/index.mjs.map +1 -1
  132. package/dist/{telemetry-3vdxGn4q.d.mts → telemetry-C--EgYVr.d.mts} +1 -1
  133. package/dist/{telemetry-3vdxGn4q.d.mts.map → telemetry-C--EgYVr.d.mts.map} +1 -1
  134. package/dist/topic/index.cjs +4 -7
  135. package/dist/topic/index.cjs.map +1 -1
  136. package/dist/topic/index.d.cts +2 -2
  137. package/dist/topic/index.d.cts.map +1 -1
  138. package/dist/topic/index.d.mts +2 -2
  139. package/dist/topic/index.d.mts.map +1 -1
  140. package/dist/topic/index.mjs +4 -7
  141. package/dist/topic/index.mjs.map +1 -1
  142. package/dist/{types-BDNGr7pv.d.mts → types-DNngH0fX.d.mts} +1 -1
  143. package/dist/{types-BDNGr7pv.d.mts.map → types-DNngH0fX.d.mts.map} +1 -1
  144. package/dist/types.d.mts +1 -1
  145. package/package.json +32 -22
  146. package/src/Construct.ts +5 -0
  147. package/src/__tests__/builder-reuse.spec.ts +587 -0
  148. package/src/__tests__/monitor.spec.ts +636 -0
  149. package/src/clone.ts +38 -0
  150. package/src/crons/CronBuilder.ts +35 -45
  151. package/src/crons/__tests__/Cron.spec.ts +10 -2
  152. package/src/crons/__tests__/CronBuilder.state-isolation.spec.ts +64 -18
  153. package/src/endpoints/AmazonApiGatewayEndpointAdaptor.ts +23 -2
  154. package/src/endpoints/EndpointBuilder.ts +61 -70
  155. package/src/endpoints/EndpointFactory.ts +31 -0
  156. package/src/endpoints/HonoEndpointAdaptor.ts +16 -1
  157. package/src/endpoints/TestEndpointAdaptor.ts +194 -150
  158. package/src/endpoints/__tests__/EndpointBuilder.audit.spec.ts +6 -3
  159. package/src/endpoints/__tests__/EndpointBuilder.responseType.spec.ts +4 -1
  160. package/src/endpoints/__tests__/EndpointBuilder.spec.ts +16 -8
  161. package/src/functions/AWSLambdaFunction.ts +28 -2
  162. package/src/functions/BaseFunctionBuilder.ts +33 -22
  163. package/src/functions/FunctionBuilder.ts +41 -51
  164. package/src/functions/TestFunctionAdaptor.ts +66 -31
  165. package/src/functions/__tests__/FunctionBuilder.state-isolation.spec.ts +55 -12
  166. package/src/index.ts +6 -0
  167. package/src/monitor.ts +145 -0
  168. package/src/monitors/heartbeat.ts +86 -0
  169. package/src/monitors/index.ts +6 -0
  170. package/src/queue/QueueBuilder.ts +22 -22
  171. package/src/subscribers/SubscriberBuilder.ts +19 -22
  172. package/src/topic/TopicBuilder.ts +9 -7
  173. package/tsdown.config.ts +1 -0
  174. package/dist/AWSScheduledFunction-CufMMhGB.mjs.map +0 -1
  175. package/dist/AWSScheduledFunction-DbkDr8CA.cjs.map +0 -1
  176. package/dist/Construct-DCMuYOox.d.mts.map +0 -1
  177. package/dist/Construct-_1wX7p_Y.d.cts.map +0 -1
  178. package/dist/Construct-r0U2zBwW.mjs.map +0 -1
  179. package/dist/Construct-vXMZJgRp.cjs.map +0 -1
  180. package/dist/Endpoint-DgfRslct.d.cts.map +0 -1
  181. package/dist/HonoEndpointAdaptor-CkJENANP.cjs.map +0 -1
  182. package/dist/HonoEndpointAdaptor-DJDT3PMx.mjs.map +0 -1
  183. package/dist/functions-B-qt91O7.mjs.map +0 -1
  184. package/dist/functions-C8i1kCMM.cjs.map +0 -1
  185. package/dist/index-BVs9DvIj.d.cts.map +0 -1
  186. package/dist/index-DP6fqv0I.d.mts.map +0 -1
package/src/monitor.ts ADDED
@@ -0,0 +1,145 @@
1
+ import type { Logger } from '@geekmidas/logger';
2
+ import type { Service, ServiceDiscovery } from '@geekmidas/services';
3
+ import type { ConstructType } from './Construct';
4
+
5
+ /**
6
+ * What a monitor is told about the construct whose run it is reporting.
7
+ */
8
+ export interface MonitorContext {
9
+ /** The kind of construct: function, cron or endpoint. */
10
+ type: ConstructType;
11
+ logger: Logger;
12
+ }
13
+
14
+ /**
15
+ * Reports a construct's runs to an outside service — a heartbeat, an uptime
16
+ * check, an error tracker.
17
+ *
18
+ * `start` runs before the handler and whatever it returns is handed back to
19
+ * `success` or `failure`, so a provider that pairs the two (a check-in id) can.
20
+ * A monitor that throws is logged and ignored: monitoring must never turn a
21
+ * successful run into a failed one.
22
+ */
23
+ export interface ConstructMonitor<TRun = unknown> {
24
+ start?(ctx: MonitorContext): Promise<TRun>;
25
+ success(
26
+ ctx: MonitorContext & { run: TRun; output: unknown; status?: number },
27
+ ): Promise<void>;
28
+ failure(
29
+ ctx: MonitorContext & { run: TRun; error: unknown; status?: number },
30
+ ): Promise<void>;
31
+ }
32
+
33
+ export type MonitorService = Service<string, ConstructMonitor<any>>;
34
+
35
+ /** A run in progress, closed by exactly one of its two methods. */
36
+ export interface MonitoredRun {
37
+ success(output: unknown, status?: number): Promise<void>;
38
+ failure(error: unknown, status?: number): Promise<void>;
39
+ /**
40
+ * Close an HTTP run from its response status: a 5xx is a failure, anything
41
+ * else is a success. A 4xx is the caller's mistake, not an outage.
42
+ */
43
+ settle(status: number, error?: unknown): Promise<void>;
44
+ }
45
+
46
+ /**
47
+ * Add a monitor to a construct's list, refusing one that is already there.
48
+ *
49
+ * Services are cached by name, so two monitors with one name would silently
50
+ * share an instance: two heartbeats reading `HEARTBEAT_URL` would both ping
51
+ * whichever was registered first, and the other provider would never hear
52
+ * from the construct.
53
+ */
54
+ export function addMonitor(
55
+ monitors: readonly MonitorService[],
56
+ monitor: MonitorService,
57
+ ): MonitorService[] {
58
+ if (monitors.some((m) => m.serviceName === monitor.serviceName)) {
59
+ throw new Error(
60
+ `Monitor "${monitor.serviceName}" is already set on this construct. ` +
61
+ 'Two heartbeats reading the same env var would share one URL; ' +
62
+ "give one its own, e.g. heartbeat.healthchecks('HEALTHCHECKS_HEARTBEAT_URL').",
63
+ );
64
+ }
65
+ return [...monitors, monitor];
66
+ }
67
+
68
+ const NOOP_RUN: MonitoredRun = {
69
+ async success() {},
70
+ async failure() {},
71
+ async settle() {},
72
+ };
73
+
74
+ /**
75
+ * Start a construct's monitors for one run.
76
+ *
77
+ * Never throws: a monitor that fails to register, start or report is logged,
78
+ * and the run goes on without it.
79
+ */
80
+ export async function startMonitors(
81
+ construct: { type: ConstructType; monitors: readonly MonitorService[] },
82
+ serviceDiscovery: ServiceDiscovery<any>,
83
+ logger: Logger,
84
+ ): Promise<MonitoredRun> {
85
+ if (!construct.monitors.length) {
86
+ return NOOP_RUN;
87
+ }
88
+
89
+ const ctx: MonitorContext = { type: construct.type, logger };
90
+
91
+ let started: { monitor: ConstructMonitor<any>; run: unknown }[];
92
+ try {
93
+ const registered: Record<string, unknown> = await serviceDiscovery.register(
94
+ [...construct.monitors],
95
+ );
96
+ started = await Promise.all(
97
+ construct.monitors.map(async ({ serviceName }) => {
98
+ const monitor = registered[serviceName] as ConstructMonitor<any>;
99
+ let run: unknown;
100
+ try {
101
+ run = await monitor.start?.(ctx);
102
+ } catch (error) {
103
+ logger.warn(
104
+ { error, monitor: serviceName },
105
+ 'Monitor failed to start',
106
+ );
107
+ }
108
+ return { monitor, run };
109
+ }),
110
+ );
111
+ } catch (error) {
112
+ logger.warn({ error }, 'Monitors could not be registered');
113
+ return NOOP_RUN;
114
+ }
115
+
116
+ const report = async (
117
+ call: (monitor: ConstructMonitor<any>, run: unknown) => Promise<void>,
118
+ ) => {
119
+ const results = await Promise.allSettled(
120
+ started.map(({ monitor, run }) => call(monitor, run)),
121
+ );
122
+ for (const result of results) {
123
+ if (result.status === 'rejected') {
124
+ logger.warn({ error: result.reason }, 'Monitor failed to report');
125
+ }
126
+ }
127
+ };
128
+
129
+ const run: MonitoredRun = {
130
+ success: (output, status) =>
131
+ report((monitor, r) =>
132
+ monitor.success({ ...ctx, run: r, output, status }),
133
+ ),
134
+ failure: (error, status) =>
135
+ report((monitor, r) =>
136
+ monitor.failure({ ...ctx, run: r, error, status }),
137
+ ),
138
+ settle: (status, error) =>
139
+ status >= 500
140
+ ? run.failure(error ?? new Error(`Responded with ${status}`), status)
141
+ : run.success(undefined, status),
142
+ };
143
+
144
+ return run;
145
+ }
@@ -0,0 +1,86 @@
1
+ import type { Service } from '@geekmidas/services';
2
+ import type { ConstructMonitor } from '../monitor';
3
+
4
+ export interface HeartbeatOptions {
5
+ /**
6
+ * The environment variable holding the heartbeat URL. When it is unset the
7
+ * monitor does nothing, so only the stages that set it are monitored.
8
+ * @default 'HEARTBEAT_URL'
9
+ */
10
+ env?: string;
11
+ /** The URL to request when a run starts. Omit for providers without one. */
12
+ start?: (url: string) => string;
13
+ /** The URL to request when a run succeeds. @default the URL itself */
14
+ success?: (url: string) => string;
15
+ /**
16
+ * The URL to request when a run fails. Omit to send nothing, and let the
17
+ * provider alert on the missed success ping instead.
18
+ */
19
+ failure?: (url: string) => string;
20
+ /** Milliseconds to wait for the provider. @default 3000 */
21
+ timeout?: number;
22
+ }
23
+
24
+ /**
25
+ * A monitor that pings a URL when a run succeeds, and optionally when it
26
+ * starts or fails — the shape most heartbeat and cron-monitoring services
27
+ * share.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * cron
32
+ * .schedule('rate(1 day)')
33
+ * .monitor(heartbeat.betterStack())
34
+ * .handle(async () => {});
35
+ * ```
36
+ */
37
+ export function heartbeat(
38
+ options: HeartbeatOptions = {},
39
+ ): Service<`heartbeat:${string}`, ConstructMonitor> {
40
+ const {
41
+ env = 'HEARTBEAT_URL',
42
+ start,
43
+ success = (url) => url,
44
+ failure,
45
+ timeout = 3000,
46
+ } = options;
47
+
48
+ return {
49
+ serviceName: `heartbeat:${env}`,
50
+ async register({ envParser }) {
51
+ const { url } = envParser
52
+ .create((get) => ({ url: get(env).string().optional() }))
53
+ .parse();
54
+
55
+ const ping = async (target?: (url: string) => string) => {
56
+ if (!url || !target) {
57
+ return;
58
+ }
59
+ const response = await fetch(target(url), {
60
+ signal: AbortSignal.timeout(timeout),
61
+ });
62
+ if (!response.ok) {
63
+ throw new Error(`Heartbeat responded with ${response.status}`);
64
+ }
65
+ };
66
+
67
+ return {
68
+ start: () => ping(start),
69
+ success: () => ping(success),
70
+ failure: () => ping(failure),
71
+ };
72
+ },
73
+ };
74
+ }
75
+
76
+ /** Better Stack heartbeats: `{url}` on success, `{url}/fail` on failure. */
77
+ heartbeat.betterStack = (env?: string) =>
78
+ heartbeat({ env, failure: (url) => `${url}/fail` });
79
+
80
+ /** Healthchecks.io: `{url}/start`, `{url}` and `{url}/fail`. */
81
+ heartbeat.healthchecks = (env?: string) =>
82
+ heartbeat({
83
+ env,
84
+ start: (url) => `${url}/start`,
85
+ failure: (url) => `${url}/fail`,
86
+ });
@@ -0,0 +1,6 @@
1
+ export type {
2
+ ConstructMonitor,
3
+ MonitorContext,
4
+ MonitorService,
5
+ } from '../monitor';
6
+ export { type HeartbeatOptions, heartbeat } from './heartbeat';
@@ -2,6 +2,7 @@ import type { Logger } from '@geekmidas/logger';
2
2
  import { DEFAULT_LOGGER } from '@geekmidas/logger/console';
3
3
  import type { Service } from '@geekmidas/services';
4
4
  import type { StandardSchemaV1 } from '@standard-schema/spec';
5
+ import { cloneWith } from '../clone';
5
6
  import { Queue, type QueueHandler } from './Queue';
6
7
 
7
8
  /**
@@ -28,32 +29,34 @@ export class QueueBuilder<
28
29
  queue<T extends string>(
29
30
  name: T,
30
31
  ): QueueBuilder<T, TMessage, TServices, TLogger> {
31
- this._name = name;
32
- return this as unknown as QueueBuilder<T, TMessage, TServices, TLogger>;
32
+ return cloneWith(this, { _name: name }) as unknown as QueueBuilder<
33
+ T,
34
+ TMessage,
35
+ TServices,
36
+ TLogger
37
+ >;
33
38
  }
34
39
 
35
40
  timeout(timeout: number): this {
36
- this._timeout = timeout;
37
- return this;
41
+ return cloneWith(this, { _timeout: timeout });
38
42
  }
39
43
 
40
44
  /** SQS event-source batch size (deployed). */
41
45
  batchSize(batchSize: number): this {
42
- this._batchSize = batchSize;
43
- return this;
46
+ return cloneWith(this, { _batchSize: batchSize });
44
47
  }
45
48
 
46
49
  /** Mark the queue as FIFO (deployed). */
47
50
  fifo(fifo = true): this {
48
- this._fifo = fifo;
49
- return this;
51
+ return cloneWith(this, { _fifo: fifo });
50
52
  }
51
53
 
52
54
  services<T extends Service[]>(
53
55
  services: T,
54
56
  ): QueueBuilder<TName, TMessage, [...TServices, ...T], TLogger> {
55
- this._services = [...this._services, ...services] as unknown as TServices;
56
- return this as unknown as QueueBuilder<
57
+ return cloneWith(this, {
58
+ _services: [...this._services, ...services] as unknown as TServices,
59
+ }) as unknown as QueueBuilder<
57
60
  TName,
58
61
  TMessage,
59
62
  [...TServices, ...T],
@@ -64,16 +67,18 @@ export class QueueBuilder<
64
67
  logger<T extends Logger>(
65
68
  logger: T,
66
69
  ): QueueBuilder<TName, TMessage, TServices, T> {
67
- this._logger = logger as unknown as TLogger;
68
- return this as unknown as QueueBuilder<TName, TMessage, TServices, T>;
70
+ return cloneWith(this, {
71
+ _logger: logger as unknown as TLogger,
72
+ }) as unknown as QueueBuilder<TName, TMessage, TServices, T>;
69
73
  }
70
74
 
71
75
  /** The typed message (job) payload the queue carries. */
72
76
  message<T extends StandardSchemaV1>(
73
77
  schema: T,
74
78
  ): QueueBuilder<TName, T, TServices, TLogger> {
75
- this._messageSchema = schema as unknown as TMessage;
76
- return this as unknown as QueueBuilder<TName, T, TServices, TLogger>;
79
+ return cloneWith(this, {
80
+ _messageSchema: schema as unknown as TMessage,
81
+ }) as unknown as QueueBuilder<TName, T, TServices, TLogger>;
77
82
  }
78
83
 
79
84
  handle(
@@ -101,14 +106,9 @@ export class QueueBuilder<
101
106
  this._fifo,
102
107
  );
103
108
 
104
- // Reset builder state to prevent pollution across reuse.
105
- this._name = undefined;
106
- this._messageSchema = undefined;
107
- this._timeout = 30000;
108
- this._batchSize = undefined;
109
- this._fifo = undefined;
110
- this._services = [] as Service[] as TServices;
111
- this._logger = DEFAULT_LOGGER as TLogger;
109
+ // No reset. `.handle()` reads this builder and leaves it alone, so a
110
+ // configured base keeps its configuration for every construct built
111
+ // from it. The reset that used to be here wiped the base on first use.
112
112
 
113
113
  return queue;
114
114
  }
@@ -6,6 +6,7 @@ import type { Logger } from '@geekmidas/logger';
6
6
  import { DEFAULT_LOGGER } from '@geekmidas/logger/console';
7
7
  import type { Service } from '@geekmidas/services';
8
8
  import type { StandardSchemaV1 } from '@standard-schema/spec';
9
+ import { cloneWith } from '../clone';
9
10
  import type { Topic, TopicEvents, TopicMessage } from '../topic/Topic';
10
11
  import { Subscriber, type SubscriberHandler } from './Subscriber';
11
12
 
@@ -50,8 +51,9 @@ export class SubscriberBuilder<
50
51
  TEventPublisherServiceName,
51
52
  TSubscribedEvents
52
53
  > {
53
- this._topicName = topic.name;
54
- return this as unknown as SubscriberBuilder<
54
+ return cloneWith(this, {
55
+ _topicName: topic.name,
56
+ }) as unknown as SubscriberBuilder<
55
57
  TServices,
56
58
  TLogger,
57
59
  OutSchema,
@@ -62,8 +64,7 @@ export class SubscriberBuilder<
62
64
  }
63
65
 
64
66
  timeout(timeout: number): this {
65
- this._timeout = timeout;
66
- return this;
67
+ return cloneWith(this, { _timeout: timeout });
67
68
  }
68
69
 
69
70
  output<T extends StandardSchemaV1>(
@@ -76,8 +77,9 @@ export class SubscriberBuilder<
76
77
  TEventPublisherServiceName,
77
78
  TSubscribedEvents
78
79
  > {
79
- this.outputSchema = schema as unknown as OutSchema;
80
- return this as any;
80
+ return cloneWith(this, {
81
+ outputSchema: schema as unknown as OutSchema,
82
+ }) as any;
81
83
  }
82
84
 
83
85
  services<T extends Service[]>(
@@ -90,8 +92,9 @@ export class SubscriberBuilder<
90
92
  TEventPublisherServiceName,
91
93
  TSubscribedEvents
92
94
  > {
93
- this._services = [...this._services, ...services] as any;
94
- return this as any;
95
+ return cloneWith(this, {
96
+ _services: [...this._services, ...services] as any,
97
+ }) as any;
95
98
  }
96
99
 
97
100
  logger<T extends Logger>(
@@ -104,8 +107,7 @@ export class SubscriberBuilder<
104
107
  TEventPublisherServiceName,
105
108
  TSubscribedEvents
106
109
  > {
107
- this._logger = logger as unknown as TLogger;
108
- return this as any;
110
+ return cloneWith(this, { _logger: logger as unknown as TLogger }) as any;
109
111
  }
110
112
 
111
113
  publisher<T extends EventPublisher<any>, TName extends string>(
@@ -118,8 +120,7 @@ export class SubscriberBuilder<
118
120
  TName,
119
121
  TSubscribedEvents
120
122
  > {
121
- this._publisher = publisher as any;
122
- return this as any;
123
+ return cloneWith(this, { _publisher: publisher as any }) as any;
123
124
  }
124
125
 
125
126
  subscribe<
@@ -141,8 +142,9 @@ export class SubscriberBuilder<
141
142
  : [...TSubscribedEvents, TEvent]
142
143
  > {
143
144
  const eventsToAdd = Array.isArray(event) ? event : [event];
144
- this._subscribedEvents = [...this._subscribedEvents, ...eventsToAdd] as any;
145
- return this as any;
145
+ return cloneWith(this, {
146
+ _subscribedEvents: [...this._subscribedEvents, ...eventsToAdd] as any,
147
+ }) as any;
146
148
  }
147
149
 
148
150
  handle(
@@ -172,14 +174,9 @@ export class SubscriberBuilder<
172
174
  this._topicName,
173
175
  );
174
176
 
175
- // Reset builder state after creating the subscriber to prevent pollution
176
- this._services = [] as Service[] as TServices;
177
- this._logger = DEFAULT_LOGGER;
178
- this._publisher = undefined;
179
- this._topicName = undefined;
180
- this._subscribedEvents = [] as any;
181
- this._timeout = 30000; // Reset to default
182
- this.outputSchema = undefined;
177
+ // No reset. `.handle()` reads this builder and leaves it alone, so a
178
+ // configured base keeps its configuration for every construct built
179
+ // from it. The reset that used to be here wiped the base on first use.
183
180
 
184
181
  return subscriber;
185
182
  }
@@ -1,5 +1,6 @@
1
1
  import type { Logger } from '@geekmidas/logger';
2
2
  import { DEFAULT_LOGGER } from '@geekmidas/logger/console';
3
+ import { cloneWith } from '../clone';
3
4
  import { Topic, type TopicEvents } from './Topic';
4
5
 
5
6
  /**
@@ -16,13 +17,14 @@ export class TopicBuilder<
16
17
 
17
18
  /** The topic name — drives the infra topic and its `<NAME>_*` env vars. */
18
19
  topic<T extends string>(name: T): TopicBuilder<T, TEvents> {
19
- this._name = name;
20
- return this as unknown as TopicBuilder<T, TEvents>;
20
+ return cloneWith(this, { _name: name }) as unknown as TopicBuilder<
21
+ T,
22
+ TEvents
23
+ >;
21
24
  }
22
25
 
23
26
  logger(logger: Logger): this {
24
- this._logger = logger;
25
- return this;
27
+ return cloneWith(this, { _logger: logger });
26
28
  }
27
29
 
28
30
  /**
@@ -42,9 +44,9 @@ export class TopicBuilder<
42
44
  this._logger,
43
45
  );
44
46
 
45
- // Reset builder state to prevent pollution across reuse.
46
- this._name = undefined;
47
- this._logger = DEFAULT_LOGGER;
47
+ // No reset. `.events()` reads this builder and leaves it alone, so a
48
+ // configured base keeps its configuration for every construct built
49
+ // from it. The reset that used to be here wiped the base on first use.
48
50
 
49
51
  return topic;
50
52
  }
package/tsdown.config.ts CHANGED
@@ -7,6 +7,7 @@ export default defineConfig({
7
7
  'src/endpoints/index.ts',
8
8
  'src/functions/index.ts',
9
9
  'src/crons/index.ts',
10
+ 'src/monitors/index.ts',
10
11
  'src/subscribers/index.ts',
11
12
  'src/queue/index.ts',
12
13
  'src/topic/index.ts',
@@ -1 +0,0 @@
1
- {"version":3,"file":"AWSScheduledFunction-CufMMhGB.mjs","names":["envParser: EnvironmentParser<{}>","fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tFunctionHandler<\n\t\t\t\tTInput,\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tTOutSchema,\n\t\t\t\tTDatabase,\n\t\t\t\tTAuditStorage,\n\t\t\t\tTAuditAction\n\t\t\t>\n\t\t>","handler: (ctx: {\n\t\t\tauditor?: Auditor<TAuditAction>;\n\t\t\tdb?: TDatabase;\n\t\t}) => Promise<T>","db","response","event: TEvent","response: InferStandardSchema<TOutSchema>","data: unknown","schema: T","envParser: EnvironmentParser<{}>","fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tFunctionHandler<\n\t\t\t\tTInput,\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tTOutSchema,\n\t\t\t\tTDatabase,\n\t\t\t\tTAuditStorage,\n\t\t\t\tTAuditAction\n\t\t\t>\n\t\t>","event: FunctionEvent<\n\t\t\tTEvent,\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTDatabase,\n\t\t\tTAuditAction\n\t\t>","event: unknown","context: Context","envParser: EnvironmentParser<{}>","cron: Cron<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>"],"sources":["../src/functions/FunctionExecutionWrapper.ts","../src/functions/AWSLambdaFunction.ts","../src/crons/AWSScheduledFunction.ts"],"sourcesContent":["import type { AuditableAction, Auditor, AuditStorage } from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { withAuditableTransaction } from '@geekmidas/audit/kysely';\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tComposableStandardSchema,\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport {\n\ttype Service,\n\tServiceDiscovery,\n\ttype ServiceRecord,\n} from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishEvents } from '../publisher';\nimport type { Function, FunctionHandler } from './Function';\nimport { FunctionBuilder } from './FunctionBuilder';\n\nexport abstract class FunctionExecutionWrapper<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> {\n\tconstructor(\n\t\tprotected envParser: EnvironmentParser<{}>,\n\t\tprotected readonly fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tFunctionHandler<\n\t\t\t\tTInput,\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tTOutSchema,\n\t\t\t\tTDatabase,\n\t\t\t\tTAuditStorage,\n\t\t\t\tTAuditAction\n\t\t\t>\n\t\t>,\n\t) {}\n\n\tprotected _logger?: TLogger;\n\n\tget logger(): TLogger {\n\t\treturn this._logger || this.fn.logger;\n\t}\n\n\tget serviceDiscovery(): ServiceDiscovery<ServiceRecord<TServices>> {\n\t\tconst serviceDiscovery = ServiceDiscovery.getInstance<\n\t\t\tServiceRecord<TServices>\n\t\t>(this.envParser);\n\n\t\treturn serviceDiscovery;\n\t}\n\n\tgetServices(): Promise<ServiceRecord<TServices>> {\n\t\treturn this.serviceDiscovery.register(this.fn.services);\n\t}\n\n\tasync getDatabase(): Promise<TDatabase | undefined> {\n\t\tif (!this.fn.databaseService) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst services = await this.serviceDiscovery.register([\n\t\t\tthis.fn.databaseService,\n\t\t]);\n\n\t\treturn services[\n\t\t\tthis.fn.databaseService.serviceName as keyof typeof services\n\t\t] as TDatabase;\n\t}\n\n\t/**\n\t * Get the audit storage service if configured.\n\t * Returns undefined if no auditor storage is configured.\n\t */\n\tasync getAuditStorage(): Promise<TAuditStorage | undefined> {\n\t\tif (!this.fn.auditorStorageService) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst services = await this.serviceDiscovery.register([\n\t\t\tthis.fn.auditorStorageService,\n\t\t]);\n\n\t\treturn services[\n\t\t\tthis.fn.auditorStorageService.serviceName as keyof typeof services\n\t\t] as TAuditStorage;\n\t}\n\n\t/**\n\t * Create an auditor instance for the function.\n\t * Returns undefined if no auditor storage is configured.\n\t */\n\tasync createAuditor(): Promise<Auditor<TAuditAction> | undefined> {\n\t\tconst storage = await this.getAuditStorage();\n\t\tif (!storage) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn new DefaultAuditor<TAuditAction>({\n\t\t\tactor: { id: 'system', type: 'system' },\n\t\t\tstorage: storage as AuditStorage,\n\t\t\tmetadata: {\n\t\t\t\tfunction: this.fn.type,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Execute handler with audit transaction support.\n\t * If the audit storage has a database (via getDatabase()), wraps execution\n\t * in a transaction so audits are atomic with handler's database operations.\n\t *\n\t * @param handler - The handler function to execute (receives auditor and db)\n\t * @returns The handler result\n\t */\n\tasync executeWithAudit<T>(\n\t\thandler: (ctx: {\n\t\t\tauditor?: Auditor<TAuditAction>;\n\t\t\tdb?: TDatabase;\n\t\t}) => Promise<T>,\n\t): Promise<T> {\n\t\tconst auditor = await this.createAuditor();\n\t\tconst storage = await this.getAuditStorage();\n\n\t\t// No audit context - just run handler with regular db\n\t\tif (!auditor || !storage) {\n\t\t\tconst db = await this.getDatabase();\n\t\t\treturn handler({ db });\n\t\t}\n\n\t\t// Check if storage has a database and db service names match\n\t\tconst storageDb = (storage as AuditStorage).getDatabase?.();\n\t\tconst databaseServiceName = this.fn.databaseService?.serviceName;\n\t\tconst auditDbServiceName = this.fn.auditorStorageService?.serviceName;\n\n\t\t// If the audit storage has a database and we're using the same database service\n\t\t// (or the audit storage provides the database), use transactional execution\n\t\tif (storageDb && databaseServiceName && auditDbServiceName) {\n\t\t\treturn withAuditableTransaction(\n\t\t\t\tstorageDb as any,\n\t\t\t\tauditor as any,\n\t\t\t\tasync (trx) => {\n\t\t\t\t\t// Use transaction as db\n\t\t\t\t\tconst response = await handler({\n\t\t\t\t\t\tauditor,\n\t\t\t\t\t\tdb: trx as TDatabase,\n\t\t\t\t\t});\n\t\t\t\t\t// Audits are flushed by withAuditableTransaction before commit\n\t\t\t\t\treturn response;\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// No database on storage or service names don't match - run handler and flush audits after\n\t\tconst db = await this.getDatabase();\n\t\tconst response = await handler({ auditor, db });\n\n\t\t// Flush audits (no transaction)\n\t\tawait auditor.flush();\n\n\t\treturn response;\n\t}\n\n\tasync getFunctionInput<TEvent>(\n\t\tevent: TEvent,\n\t): Promise<InferComposableStandardSchema<TInput>> {\n\t\tconst parsedInput = await FunctionBuilder.parseComposableStandardSchema(\n\t\t\tevent,\n\t\t\tthis.fn.input,\n\t\t);\n\n\t\treturn parsedInput as InferComposableStandardSchema<TInput>;\n\t}\n\n\tasync publishEvents(response: InferStandardSchema<TOutSchema>) {\n\t\tawait publishEvents(\n\t\t\tthis.logger,\n\t\t\tthis.serviceDiscovery,\n\t\t\tthis.fn.events,\n\t\t\tresponse,\n\t\t\tthis.fn.publisherService,\n\t\t);\n\t}\n\n\tasync parseComposableStandardSchema<T extends ComposableStandardSchema>(\n\t\tdata: unknown,\n\t\tschema: T,\n\t): Promise<InferComposableStandardSchema<T>> {\n\t\treturn FunctionBuilder.parseComposableStandardSchema(data, schema);\n\t}\n}\n","import type { AuditableAction, Auditor, AuditStorage } from '@geekmidas/audit';\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport { wrapError } from '@geekmidas/errors';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tComposableStandardSchema,\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport type { Service, ServiceRecord } from '@geekmidas/services';\nimport { runWithRequestContext } from '@geekmidas/services';\nimport middy, { type MiddlewareObj } from '@middy/core';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Context, Handler } from 'aws-lambda';\nimport type { Function, FunctionHandler } from './Function';\nimport { FunctionBuilder } from './FunctionBuilder';\nimport { FunctionExecutionWrapper } from './FunctionExecutionWrapper';\n\nexport type AWSLambdaHandler<TEvent = any, TResult = any> = Handler<\n\tTEvent,\n\tTResult\n>;\n\ntype FunctionEvent<\n\tTEvent,\n\tTInput extends ComposableStandardSchema | undefined,\n\tTServices extends Service[],\n\tTLogger extends Logger,\n\tTDatabase = undefined,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> = TEvent & {\n\tparsedInput: InferComposableStandardSchema<TInput>;\n\tservices: ServiceRecord<TServices>;\n\tlogger: TLogger;\n\tdb: TDatabase | undefined;\n\tauditor: Auditor<TAuditAction> | undefined;\n};\n\ntype Middleware<\n\tTEvent,\n\tTInput extends ComposableStandardSchema | undefined,\n\tTServices extends Service[],\n\tTLogger extends Logger,\n\tTOutSchema extends StandardSchemaV1 | undefined,\n\tTDatabase = undefined,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> = MiddlewareObj<\n\tFunctionEvent<TEvent, TInput, TServices, TLogger, TDatabase, TAuditAction>,\n\tInferComposableStandardSchema<TOutSchema>,\n\tError,\n\tContext\n>;\n\nexport class AWSLambdaFunction<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> extends FunctionExecutionWrapper<\n\tTInput,\n\tTOutSchema,\n\tTServices,\n\tTLogger,\n\tTEventPublisher,\n\tTEventPublisherServiceName,\n\tTAuditStorage,\n\tTAuditStorageServiceName,\n\tTDatabase,\n\tTDatabaseServiceName,\n\tTAuditAction\n> {\n\tconstructor(\n\t\tenvParser: EnvironmentParser<{}>,\n\t\toverride readonly fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tFunctionHandler<\n\t\t\t\tTInput,\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tTOutSchema,\n\t\t\t\tTDatabase,\n\t\t\t\tTAuditStorage,\n\t\t\t\tTAuditAction\n\t\t\t>\n\t\t>,\n\t) {\n\t\tsuper(envParser, fn);\n\t}\n\n\tprivate error<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tonError: (req) => {\n\t\t\t\tconst logger = req.event?.logger || this.fn.logger;\n\t\t\t\tlogger.error(req.error || {}, 'Error processing function');\n\n\t\t\t\t// Re-throw the wrapped error to let Lambda handle it\n\t\t\t\tthrow wrapError(req.error);\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate baseInput<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: (_req) => {},\n\t\t};\n\t}\n\n\tprivate input<\n\t\tTEvent extends { input: InferComposableStandardSchema<TInput> },\n\t>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: async (req) => {\n\t\t\t\ttry {\n\t\t\t\t\t// Parse input if schema is provided\n\t\t\t\t\tif (this.fn.input) {\n\t\t\t\t\t\tconst parsedInput =\n\t\t\t\t\t\t\tawait FunctionBuilder.parseComposableStandardSchema(\n\t\t\t\t\t\t\t\treq.event,\n\t\t\t\t\t\t\t\tthis.fn.input,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\treq.event.parsedInput =\n\t\t\t\t\t\t\tparsedInput as InferComposableStandardSchema<TInput>;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If no schema, pass the event as-is\n\t\t\t\t\t\treq.event.parsedInput = req.event as any;\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.logger.error(\n\t\t\t\t\t\t{ error, event: req.event },\n\t\t\t\t\t\t'Failed to parse input',\n\t\t\t\t\t);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate loggerMiddleware<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: (req) => {\n\t\t\t\tthis._logger = this.fn.logger.child({\n\t\t\t\t\tfn: {\n\t\t\t\t\t\tname: req.context.functionName,\n\t\t\t\t\t\tversion: req.context.functionVersion,\n\t\t\t\t\t\tmemory: req.context.memoryLimitInMB,\n\t\t\t\t\t},\n\t\t\t\t\treq: {\n\t\t\t\t\t\tid: req.context.awsRequestId,\n\t\t\t\t\t},\n\t\t\t\t}) as TLogger;\n\n\t\t\t\treq.event.logger = this._logger;\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate services<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: async (req) => {\n\t\t\t\treq.event.services = await this.getServices();\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate database<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: async (req) => {\n\t\t\t\treq.event.db = await this.getDatabase();\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate auditor<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: async (req) => {\n\t\t\t\treq.event.auditor = await this.createAuditor();\n\t\t\t},\n\t\t\tafter: async (req) => {\n\t\t\t\t// Flush any pending audits after successful execution\n\t\t\t\tif (req.event.auditor) {\n\t\t\t\t\tconst records = req.event.auditor.getRecords();\n\t\t\t\t\tif (records.length > 0) {\n\t\t\t\t\t\tthis.logger.debug(\n\t\t\t\t\t\t\t{ auditCount: records.length },\n\t\t\t\t\t\t\t'Flushing function audits',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait req.event.auditor.flush();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate events<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tafter: async (req) => {\n\t\t\t\tconst response = (req.response ||\n\t\t\t\t\tundefined) as InferStandardSchema<TOutSchema>;\n\t\t\t\tawait this.publishEvents(response);\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate async _handler<TEvent>(\n\t\tevent: FunctionEvent<\n\t\t\tTEvent,\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTDatabase,\n\t\t\tTAuditAction\n\t\t>,\n\t) {\n\t\t// Execute the function with the parsed context\n\t\tconst result = await this.fn.fn({\n\t\t\tinput: event.parsedInput,\n\t\t\tservices: event.services,\n\t\t\tlogger: event.logger,\n\t\t\tdb: event.db,\n\t\t\tauditor: event.auditor,\n\t\t} as any);\n\n\t\t// Parse output if schema is provided\n\t\tconst output = await this.fn.parseOutput(result);\n\n\t\treturn output;\n\t}\n\n\tget handler(): AWSLambdaHandler {\n\t\tconst handler = this._handler.bind(this);\n\n\t\t// Apply middleware in order\n\t\tconst chain = middy(handler)\n\t\t\t.use(this.loggerMiddleware())\n\t\t\t.use(this.baseInput())\n\t\t\t.use(this.error())\n\t\t\t.use(this.services())\n\t\t\t.use(this.database())\n\t\t\t.use(this.auditor())\n\t\t\t.use(this.input())\n\t\t\t.use(this.events());\n\n\t\t// Wrap entire Middy chain in request context for service access\n\t\tconst wrappedHandler = async (event: unknown, context: Context) => {\n\t\t\tconst startTime = Date.now();\n\t\t\tconst requestId = context.awsRequestId;\n\t\t\tconst logger = this.fn.logger.child({ requestId }) as TLogger;\n\n\t\t\treturn runWithRequestContext({ logger, requestId, startTime }, () =>\n\t\t\t\tchain(event as Parameters<typeof chain>[0], context),\n\t\t\t);\n\t\t};\n\n\t\treturn wrappedHandler as unknown as AWSLambdaHandler;\n\t}\n}\n","import type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type { ComposableStandardSchema } from '@geekmidas/schema';\nimport type { Service } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { AWSLambdaFunction } from '../functions/AWSLambdaFunction';\nimport type { Cron } from './Cron';\n\n/**\n * AWS Lambda adaptor for {@link Cron} constructs.\n *\n * A `Cron` is a {@link import('../functions').Function} that is invoked on a\n * schedule (an EventBridge rule) rather than by an API request. Because of\n * that, the runtime execution pipeline is identical to a regular Lambda\n * function: input parsing, service/database/auditor wiring, event publishing,\n * error handling, and the `runWithRequestContext` wrapper that powers\n * request-scoped logging via `serviceContext.getLogger()`.\n *\n * This adaptor therefore reuses {@link AWSLambdaFunction} wholesale and only\n * narrows the constructor to accept a `Cron`. The schedule expression itself\n * (`cron.schedule`) is **deploy-time** infrastructure consumed by the CLI to\n * provision the EventBridge rule — it is not needed at runtime.\n *\n * @example\n * ```typescript\n * import { AWSScheduledFunction } from '@geekmidas/constructs/crons';\n * import { cancelPastBookings } from '../../../src/crons/cancelPastBookings.js';\n * import { envParser } from '../../../src/env';\n *\n * const adapter = new AWSScheduledFunction(envParser, cancelPastBookings);\n *\n * export const handler = adapter.handler;\n * ```\n */\nexport class AWSScheduledFunction<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n> extends AWSLambdaFunction<\n\tTInput,\n\tTOutSchema,\n\tTServices,\n\tTLogger,\n\tTEventPublisher,\n\tTEventPublisherServiceName,\n\tundefined,\n\tstring,\n\tTDatabase,\n\tTDatabaseServiceName\n> {\n\t// biome-ignore lint/complexity/noUselessConstructor: narrows the inherited `Function` parameter to `Cron` for a clearer public API\n\tconstructor(\n\t\tenvParser: EnvironmentParser<{}>,\n\t\tcron: Cron<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t) {\n\t\tsuper(envParser, cron);\n\t}\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"AWSScheduledFunction-DbkDr8CA.cjs","names":["envParser: EnvironmentParser<{}>","fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tFunctionHandler<\n\t\t\t\tTInput,\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tTOutSchema,\n\t\t\t\tTDatabase,\n\t\t\t\tTAuditStorage,\n\t\t\t\tTAuditAction\n\t\t\t>\n\t\t>","DefaultAuditor","handler: (ctx: {\n\t\t\tauditor?: Auditor<TAuditAction>;\n\t\t\tdb?: TDatabase;\n\t\t}) => Promise<T>","db","response","event: TEvent","response: InferStandardSchema<TOutSchema>","data: unknown","schema: T","envParser: EnvironmentParser<{}>","fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tFunctionHandler<\n\t\t\t\tTInput,\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tTOutSchema,\n\t\t\t\tTDatabase,\n\t\t\t\tTAuditStorage,\n\t\t\t\tTAuditAction\n\t\t\t>\n\t\t>","event: FunctionEvent<\n\t\t\tTEvent,\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTDatabase,\n\t\t\tTAuditAction\n\t\t>","event: unknown","context: Context","envParser: EnvironmentParser<{}>","cron: Cron<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>"],"sources":["../src/functions/FunctionExecutionWrapper.ts","../src/functions/AWSLambdaFunction.ts","../src/crons/AWSScheduledFunction.ts"],"sourcesContent":["import type { AuditableAction, Auditor, AuditStorage } from '@geekmidas/audit';\nimport { DefaultAuditor } from '@geekmidas/audit';\nimport { withAuditableTransaction } from '@geekmidas/audit/kysely';\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tComposableStandardSchema,\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport {\n\ttype Service,\n\tServiceDiscovery,\n\ttype ServiceRecord,\n} from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { publishEvents } from '../publisher';\nimport type { Function, FunctionHandler } from './Function';\nimport { FunctionBuilder } from './FunctionBuilder';\n\nexport abstract class FunctionExecutionWrapper<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> {\n\tconstructor(\n\t\tprotected envParser: EnvironmentParser<{}>,\n\t\tprotected readonly fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tFunctionHandler<\n\t\t\t\tTInput,\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tTOutSchema,\n\t\t\t\tTDatabase,\n\t\t\t\tTAuditStorage,\n\t\t\t\tTAuditAction\n\t\t\t>\n\t\t>,\n\t) {}\n\n\tprotected _logger?: TLogger;\n\n\tget logger(): TLogger {\n\t\treturn this._logger || this.fn.logger;\n\t}\n\n\tget serviceDiscovery(): ServiceDiscovery<ServiceRecord<TServices>> {\n\t\tconst serviceDiscovery = ServiceDiscovery.getInstance<\n\t\t\tServiceRecord<TServices>\n\t\t>(this.envParser);\n\n\t\treturn serviceDiscovery;\n\t}\n\n\tgetServices(): Promise<ServiceRecord<TServices>> {\n\t\treturn this.serviceDiscovery.register(this.fn.services);\n\t}\n\n\tasync getDatabase(): Promise<TDatabase | undefined> {\n\t\tif (!this.fn.databaseService) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst services = await this.serviceDiscovery.register([\n\t\t\tthis.fn.databaseService,\n\t\t]);\n\n\t\treturn services[\n\t\t\tthis.fn.databaseService.serviceName as keyof typeof services\n\t\t] as TDatabase;\n\t}\n\n\t/**\n\t * Get the audit storage service if configured.\n\t * Returns undefined if no auditor storage is configured.\n\t */\n\tasync getAuditStorage(): Promise<TAuditStorage | undefined> {\n\t\tif (!this.fn.auditorStorageService) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst services = await this.serviceDiscovery.register([\n\t\t\tthis.fn.auditorStorageService,\n\t\t]);\n\n\t\treturn services[\n\t\t\tthis.fn.auditorStorageService.serviceName as keyof typeof services\n\t\t] as TAuditStorage;\n\t}\n\n\t/**\n\t * Create an auditor instance for the function.\n\t * Returns undefined if no auditor storage is configured.\n\t */\n\tasync createAuditor(): Promise<Auditor<TAuditAction> | undefined> {\n\t\tconst storage = await this.getAuditStorage();\n\t\tif (!storage) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn new DefaultAuditor<TAuditAction>({\n\t\t\tactor: { id: 'system', type: 'system' },\n\t\t\tstorage: storage as AuditStorage,\n\t\t\tmetadata: {\n\t\t\t\tfunction: this.fn.type,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Execute handler with audit transaction support.\n\t * If the audit storage has a database (via getDatabase()), wraps execution\n\t * in a transaction so audits are atomic with handler's database operations.\n\t *\n\t * @param handler - The handler function to execute (receives auditor and db)\n\t * @returns The handler result\n\t */\n\tasync executeWithAudit<T>(\n\t\thandler: (ctx: {\n\t\t\tauditor?: Auditor<TAuditAction>;\n\t\t\tdb?: TDatabase;\n\t\t}) => Promise<T>,\n\t): Promise<T> {\n\t\tconst auditor = await this.createAuditor();\n\t\tconst storage = await this.getAuditStorage();\n\n\t\t// No audit context - just run handler with regular db\n\t\tif (!auditor || !storage) {\n\t\t\tconst db = await this.getDatabase();\n\t\t\treturn handler({ db });\n\t\t}\n\n\t\t// Check if storage has a database and db service names match\n\t\tconst storageDb = (storage as AuditStorage).getDatabase?.();\n\t\tconst databaseServiceName = this.fn.databaseService?.serviceName;\n\t\tconst auditDbServiceName = this.fn.auditorStorageService?.serviceName;\n\n\t\t// If the audit storage has a database and we're using the same database service\n\t\t// (or the audit storage provides the database), use transactional execution\n\t\tif (storageDb && databaseServiceName && auditDbServiceName) {\n\t\t\treturn withAuditableTransaction(\n\t\t\t\tstorageDb as any,\n\t\t\t\tauditor as any,\n\t\t\t\tasync (trx) => {\n\t\t\t\t\t// Use transaction as db\n\t\t\t\t\tconst response = await handler({\n\t\t\t\t\t\tauditor,\n\t\t\t\t\t\tdb: trx as TDatabase,\n\t\t\t\t\t});\n\t\t\t\t\t// Audits are flushed by withAuditableTransaction before commit\n\t\t\t\t\treturn response;\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// No database on storage or service names don't match - run handler and flush audits after\n\t\tconst db = await this.getDatabase();\n\t\tconst response = await handler({ auditor, db });\n\n\t\t// Flush audits (no transaction)\n\t\tawait auditor.flush();\n\n\t\treturn response;\n\t}\n\n\tasync getFunctionInput<TEvent>(\n\t\tevent: TEvent,\n\t): Promise<InferComposableStandardSchema<TInput>> {\n\t\tconst parsedInput = await FunctionBuilder.parseComposableStandardSchema(\n\t\t\tevent,\n\t\t\tthis.fn.input,\n\t\t);\n\n\t\treturn parsedInput as InferComposableStandardSchema<TInput>;\n\t}\n\n\tasync publishEvents(response: InferStandardSchema<TOutSchema>) {\n\t\tawait publishEvents(\n\t\t\tthis.logger,\n\t\t\tthis.serviceDiscovery,\n\t\t\tthis.fn.events,\n\t\t\tresponse,\n\t\t\tthis.fn.publisherService,\n\t\t);\n\t}\n\n\tasync parseComposableStandardSchema<T extends ComposableStandardSchema>(\n\t\tdata: unknown,\n\t\tschema: T,\n\t): Promise<InferComposableStandardSchema<T>> {\n\t\treturn FunctionBuilder.parseComposableStandardSchema(data, schema);\n\t}\n}\n","import type { AuditableAction, Auditor, AuditStorage } from '@geekmidas/audit';\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport { wrapError } from '@geekmidas/errors';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tComposableStandardSchema,\n\tInferComposableStandardSchema,\n\tInferStandardSchema,\n} from '@geekmidas/schema';\nimport type { Service, ServiceRecord } from '@geekmidas/services';\nimport { runWithRequestContext } from '@geekmidas/services';\nimport middy, { type MiddlewareObj } from '@middy/core';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Context, Handler } from 'aws-lambda';\nimport type { Function, FunctionHandler } from './Function';\nimport { FunctionBuilder } from './FunctionBuilder';\nimport { FunctionExecutionWrapper } from './FunctionExecutionWrapper';\n\nexport type AWSLambdaHandler<TEvent = any, TResult = any> = Handler<\n\tTEvent,\n\tTResult\n>;\n\ntype FunctionEvent<\n\tTEvent,\n\tTInput extends ComposableStandardSchema | undefined,\n\tTServices extends Service[],\n\tTLogger extends Logger,\n\tTDatabase = undefined,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> = TEvent & {\n\tparsedInput: InferComposableStandardSchema<TInput>;\n\tservices: ServiceRecord<TServices>;\n\tlogger: TLogger;\n\tdb: TDatabase | undefined;\n\tauditor: Auditor<TAuditAction> | undefined;\n};\n\ntype Middleware<\n\tTEvent,\n\tTInput extends ComposableStandardSchema | undefined,\n\tTServices extends Service[],\n\tTLogger extends Logger,\n\tTOutSchema extends StandardSchemaV1 | undefined,\n\tTDatabase = undefined,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> = MiddlewareObj<\n\tFunctionEvent<TEvent, TInput, TServices, TLogger, TDatabase, TAuditAction>,\n\tInferComposableStandardSchema<TOutSchema>,\n\tError,\n\tContext\n>;\n\nexport class AWSLambdaFunction<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTAuditStorageServiceName extends string = string,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> extends FunctionExecutionWrapper<\n\tTInput,\n\tTOutSchema,\n\tTServices,\n\tTLogger,\n\tTEventPublisher,\n\tTEventPublisherServiceName,\n\tTAuditStorage,\n\tTAuditStorageServiceName,\n\tTDatabase,\n\tTDatabaseServiceName,\n\tTAuditAction\n> {\n\tconstructor(\n\t\tenvParser: EnvironmentParser<{}>,\n\t\toverride readonly fn: Function<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTAuditStorage,\n\t\t\tTAuditStorageServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName,\n\t\t\tTAuditAction,\n\t\t\tFunctionHandler<\n\t\t\t\tTInput,\n\t\t\t\tTServices,\n\t\t\t\tTLogger,\n\t\t\t\tTOutSchema,\n\t\t\t\tTDatabase,\n\t\t\t\tTAuditStorage,\n\t\t\t\tTAuditAction\n\t\t\t>\n\t\t>,\n\t) {\n\t\tsuper(envParser, fn);\n\t}\n\n\tprivate error<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tonError: (req) => {\n\t\t\t\tconst logger = req.event?.logger || this.fn.logger;\n\t\t\t\tlogger.error(req.error || {}, 'Error processing function');\n\n\t\t\t\t// Re-throw the wrapped error to let Lambda handle it\n\t\t\t\tthrow wrapError(req.error);\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate baseInput<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: (_req) => {},\n\t\t};\n\t}\n\n\tprivate input<\n\t\tTEvent extends { input: InferComposableStandardSchema<TInput> },\n\t>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: async (req) => {\n\t\t\t\ttry {\n\t\t\t\t\t// Parse input if schema is provided\n\t\t\t\t\tif (this.fn.input) {\n\t\t\t\t\t\tconst parsedInput =\n\t\t\t\t\t\t\tawait FunctionBuilder.parseComposableStandardSchema(\n\t\t\t\t\t\t\t\treq.event,\n\t\t\t\t\t\t\t\tthis.fn.input,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\treq.event.parsedInput =\n\t\t\t\t\t\t\tparsedInput as InferComposableStandardSchema<TInput>;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If no schema, pass the event as-is\n\t\t\t\t\t\treq.event.parsedInput = req.event as any;\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.logger.error(\n\t\t\t\t\t\t{ error, event: req.event },\n\t\t\t\t\t\t'Failed to parse input',\n\t\t\t\t\t);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate loggerMiddleware<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: (req) => {\n\t\t\t\tthis._logger = this.fn.logger.child({\n\t\t\t\t\tfn: {\n\t\t\t\t\t\tname: req.context.functionName,\n\t\t\t\t\t\tversion: req.context.functionVersion,\n\t\t\t\t\t\tmemory: req.context.memoryLimitInMB,\n\t\t\t\t\t},\n\t\t\t\t\treq: {\n\t\t\t\t\t\tid: req.context.awsRequestId,\n\t\t\t\t\t},\n\t\t\t\t}) as TLogger;\n\n\t\t\t\treq.event.logger = this._logger;\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate services<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: async (req) => {\n\t\t\t\treq.event.services = await this.getServices();\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate database<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: async (req) => {\n\t\t\t\treq.event.db = await this.getDatabase();\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate auditor<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tbefore: async (req) => {\n\t\t\t\treq.event.auditor = await this.createAuditor();\n\t\t\t},\n\t\t\tafter: async (req) => {\n\t\t\t\t// Flush any pending audits after successful execution\n\t\t\t\tif (req.event.auditor) {\n\t\t\t\t\tconst records = req.event.auditor.getRecords();\n\t\t\t\t\tif (records.length > 0) {\n\t\t\t\t\t\tthis.logger.debug(\n\t\t\t\t\t\t\t{ auditCount: records.length },\n\t\t\t\t\t\t\t'Flushing function audits',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait req.event.auditor.flush();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate events<TEvent>(): Middleware<\n\t\tTEvent,\n\t\tTInput,\n\t\tTServices,\n\t\tTLogger,\n\t\tTOutSchema,\n\t\tTDatabase,\n\t\tTAuditAction\n\t> {\n\t\treturn {\n\t\t\tafter: async (req) => {\n\t\t\t\tconst response = (req.response ||\n\t\t\t\t\tundefined) as InferStandardSchema<TOutSchema>;\n\t\t\t\tawait this.publishEvents(response);\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate async _handler<TEvent>(\n\t\tevent: FunctionEvent<\n\t\t\tTEvent,\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTDatabase,\n\t\t\tTAuditAction\n\t\t>,\n\t) {\n\t\t// Execute the function with the parsed context\n\t\tconst result = await this.fn.fn({\n\t\t\tinput: event.parsedInput,\n\t\t\tservices: event.services,\n\t\t\tlogger: event.logger,\n\t\t\tdb: event.db,\n\t\t\tauditor: event.auditor,\n\t\t} as any);\n\n\t\t// Parse output if schema is provided\n\t\tconst output = await this.fn.parseOutput(result);\n\n\t\treturn output;\n\t}\n\n\tget handler(): AWSLambdaHandler {\n\t\tconst handler = this._handler.bind(this);\n\n\t\t// Apply middleware in order\n\t\tconst chain = middy(handler)\n\t\t\t.use(this.loggerMiddleware())\n\t\t\t.use(this.baseInput())\n\t\t\t.use(this.error())\n\t\t\t.use(this.services())\n\t\t\t.use(this.database())\n\t\t\t.use(this.auditor())\n\t\t\t.use(this.input())\n\t\t\t.use(this.events());\n\n\t\t// Wrap entire Middy chain in request context for service access\n\t\tconst wrappedHandler = async (event: unknown, context: Context) => {\n\t\t\tconst startTime = Date.now();\n\t\t\tconst requestId = context.awsRequestId;\n\t\t\tconst logger = this.fn.logger.child({ requestId }) as TLogger;\n\n\t\t\treturn runWithRequestContext({ logger, requestId, startTime }, () =>\n\t\t\t\tchain(event as Parameters<typeof chain>[0], context),\n\t\t\t);\n\t\t};\n\n\t\treturn wrappedHandler as unknown as AWSLambdaHandler;\n\t}\n}\n","import type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { EventPublisher } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type { ComposableStandardSchema } from '@geekmidas/schema';\nimport type { Service } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { AWSLambdaFunction } from '../functions/AWSLambdaFunction';\nimport type { Cron } from './Cron';\n\n/**\n * AWS Lambda adaptor for {@link Cron} constructs.\n *\n * A `Cron` is a {@link import('../functions').Function} that is invoked on a\n * schedule (an EventBridge rule) rather than by an API request. Because of\n * that, the runtime execution pipeline is identical to a regular Lambda\n * function: input parsing, service/database/auditor wiring, event publishing,\n * error handling, and the `runWithRequestContext` wrapper that powers\n * request-scoped logging via `serviceContext.getLogger()`.\n *\n * This adaptor therefore reuses {@link AWSLambdaFunction} wholesale and only\n * narrows the constructor to accept a `Cron`. The schedule expression itself\n * (`cron.schedule`) is **deploy-time** infrastructure consumed by the CLI to\n * provision the EventBridge rule — it is not needed at runtime.\n *\n * @example\n * ```typescript\n * import { AWSScheduledFunction } from '@geekmidas/constructs/crons';\n * import { cancelPastBookings } from '../../../src/crons/cancelPastBookings.js';\n * import { envParser } from '../../../src/env';\n *\n * const adapter = new AWSScheduledFunction(envParser, cancelPastBookings);\n *\n * export const handler = adapter.handler;\n * ```\n */\nexport class AWSScheduledFunction<\n\tTInput extends ComposableStandardSchema | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n\tTOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTEventPublisher extends EventPublisher<any> | undefined = undefined,\n\tTEventPublisherServiceName extends string = string,\n\tTDatabase = undefined,\n\tTDatabaseServiceName extends string = string,\n> extends AWSLambdaFunction<\n\tTInput,\n\tTOutSchema,\n\tTServices,\n\tTLogger,\n\tTEventPublisher,\n\tTEventPublisherServiceName,\n\tundefined,\n\tstring,\n\tTDatabase,\n\tTDatabaseServiceName\n> {\n\t// biome-ignore lint/complexity/noUselessConstructor: narrows the inherited `Function` parameter to `Cron` for a clearer public API\n\tconstructor(\n\t\tenvParser: EnvironmentParser<{}>,\n\t\tcron: Cron<\n\t\t\tTInput,\n\t\t\tTServices,\n\t\t\tTLogger,\n\t\t\tTOutSchema,\n\t\t\tTEventPublisher,\n\t\t\tTEventPublisherServiceName,\n\t\t\tTDatabase,\n\t\t\tTDatabaseServiceName\n\t\t>,\n\t) {\n\t\tsuper(envParser, cron);\n\t}\n}\n"],"mappings":";;;;;;;;;;AAqBA,IAAsB,2BAAtB,MAeE;CACD,YACWA,WACSC,IAsBlB;EAvBS;EACS;CAsBhB;CAEJ,AAAU;CAEV,IAAI,SAAkB;AACrB,SAAO,KAAK,WAAW,KAAK,GAAG;CAC/B;CAED,IAAI,mBAA+D;EAClE,MAAM,mBAAmB,sCAAiB,YAExC,KAAK,UAAU;AAEjB,SAAO;CACP;CAED,cAAiD;AAChD,SAAO,KAAK,iBAAiB,SAAS,KAAK,GAAG,SAAS;CACvD;CAED,MAAM,cAA8C;AACnD,OAAK,KAAK,GAAG,gBACZ;EAGD,MAAM,WAAW,MAAM,KAAK,iBAAiB,SAAS,CACrD,KAAK,GAAG,eACR,EAAC;AAEF,SAAO,SACN,KAAK,GAAG,gBAAgB;CAEzB;;;;;CAMD,MAAM,kBAAsD;AAC3D,OAAK,KAAK,GAAG,sBACZ;EAGD,MAAM,WAAW,MAAM,KAAK,iBAAiB,SAAS,CACrD,KAAK,GAAG,qBACR,EAAC;AAEF,SAAO,SACN,KAAK,GAAG,sBAAsB;CAE/B;;;;;CAMD,MAAM,gBAA4D;EACjE,MAAM,UAAU,MAAM,KAAK,iBAAiB;AAC5C,OAAK,QACJ;AAGD,SAAO,IAAIC,iCAA6B;GACvC,OAAO;IAAE,IAAI;IAAU,MAAM;GAAU;GAC9B;GACT,UAAU,EACT,UAAU,KAAK,GAAG,KAClB;EACD;CACD;;;;;;;;;CAUD,MAAM,iBACLC,SAIa;EACb,MAAM,UAAU,MAAM,KAAK,eAAe;EAC1C,MAAM,UAAU,MAAM,KAAK,iBAAiB;AAG5C,OAAK,YAAY,SAAS;GACzB,MAAMC,OAAK,MAAM,KAAK,aAAa;AACnC,UAAO,QAAQ,EAAE,SAAI,EAAC;EACtB;EAGD,MAAM,YAAY,AAAC,QAAyB,eAAe;EAC3D,MAAM,sBAAsB,KAAK,GAAG,iBAAiB;EACrD,MAAM,qBAAqB,KAAK,GAAG,uBAAuB;AAI1D,MAAI,aAAa,uBAAuB,mBACvC,QAAO,uDACN,WACA,SACA,OAAO,QAAQ;GAEd,MAAMC,aAAW,MAAM,QAAQ;IAC9B;IACA,IAAI;GACJ,EAAC;AAEF,UAAOA;EACP,EACD;EAIF,MAAM,KAAK,MAAM,KAAK,aAAa;EACnC,MAAM,WAAW,MAAM,QAAQ;GAAE;GAAS;EAAI,EAAC;AAG/C,QAAM,QAAQ,OAAO;AAErB,SAAO;CACP;CAED,MAAM,iBACLC,OACiD;EACjD,MAAM,cAAc,MAAM,kCAAgB,8BACzC,OACA,KAAK,GAAG,MACR;AAED,SAAO;CACP;CAED,MAAM,cAAcC,UAA2C;AAC9D,QAAM,gCACL,KAAK,QACL,KAAK,kBACL,KAAK,GAAG,QACR,UACA,KAAK,GAAG,iBACR;CACD;CAED,MAAM,8BACLC,MACAC,QAC4C;AAC5C,SAAO,kCAAgB,8BAA8B,MAAM,OAAO;CAClE;AACD;;;;AC3JD,IAAa,oBAAb,cAeU,yBAYR;CACD,YACCC,WACkBC,IAsBjB;AACD,QAAM,WAAW,GAAG;EAvBF;CAwBlB;CAED,AAAQ,QAQN;AACD,SAAO,EACN,SAAS,CAAC,QAAQ;GACjB,MAAM,SAAS,IAAI,OAAO,UAAU,KAAK,GAAG;AAC5C,UAAO,MAAM,IAAI,SAAS,CAAE,GAAE,4BAA4B;AAG1D,SAAM,kCAAU,IAAI,MAAM;EAC1B,EACD;CACD;CAED,AAAQ,YAQN;AACD,SAAO,EACN,QAAQ,CAAC,SAAS,CAAE,EACpB;CACD;CAED,AAAQ,QAUN;AACD,SAAO,EACN,QAAQ,OAAO,QAAQ;AACtB,OAAI;AAEH,QAAI,KAAK,GAAG,OAAO;KAClB,MAAM,cACL,MAAM,kCAAgB,8BACrB,IAAI,OACJ,KAAK,GAAG,MACR;AAEF,SAAI,MAAM,cACT;IACD,MAEA,KAAI,MAAM,cAAc,IAAI;GAE7B,SAAQ,OAAO;AACf,SAAK,OAAO,MACX;KAAE;KAAO,OAAO,IAAI;IAAO,GAC3B,wBACA;AACD,UAAM;GACN;EACD,EACD;CACD;CAED,AAAQ,mBAQN;AACD,SAAO,EACN,QAAQ,CAAC,QAAQ;AAChB,QAAK,UAAU,KAAK,GAAG,OAAO,MAAM;IACnC,IAAI;KACH,MAAM,IAAI,QAAQ;KAClB,SAAS,IAAI,QAAQ;KACrB,QAAQ,IAAI,QAAQ;IACpB;IACD,KAAK,EACJ,IAAI,IAAI,QAAQ,aAChB;GACD,EAAC;AAEF,OAAI,MAAM,SAAS,KAAK;EACxB,EACD;CACD;CAED,AAAQ,WAQN;AACD,SAAO,EACN,QAAQ,OAAO,QAAQ;AACtB,OAAI,MAAM,WAAW,MAAM,KAAK,aAAa;EAC7C,EACD;CACD;CAED,AAAQ,WAQN;AACD,SAAO,EACN,QAAQ,OAAO,QAAQ;AACtB,OAAI,MAAM,KAAK,MAAM,KAAK,aAAa;EACvC,EACD;CACD;CAED,AAAQ,UAQN;AACD,SAAO;GACN,QAAQ,OAAO,QAAQ;AACtB,QAAI,MAAM,UAAU,MAAM,KAAK,eAAe;GAC9C;GACD,OAAO,OAAO,QAAQ;AAErB,QAAI,IAAI,MAAM,SAAS;KACtB,MAAM,UAAU,IAAI,MAAM,QAAQ,YAAY;AAC9C,SAAI,QAAQ,SAAS,GAAG;AACvB,WAAK,OAAO,MACX,EAAE,YAAY,QAAQ,OAAQ,GAC9B,2BACA;AACD,YAAM,IAAI,MAAM,QAAQ,OAAO;KAC/B;IACD;GACD;EACD;CACD;CAED,AAAQ,SAQN;AACD,SAAO,EACN,OAAO,OAAO,QAAQ;GACrB,MAAM,WAAY,IAAI;AAEtB,SAAM,KAAK,cAAc,SAAS;EAClC,EACD;CACD;CAED,MAAc,SACbC,OAQC;EAED,MAAM,SAAS,MAAM,KAAK,GAAG,GAAG;GAC/B,OAAO,MAAM;GACb,UAAU,MAAM;GAChB,QAAQ,MAAM;GACd,IAAI,MAAM;GACV,SAAS,MAAM;EACf,EAAQ;EAGT,MAAM,SAAS,MAAM,KAAK,GAAG,YAAY,OAAO;AAEhD,SAAO;CACP;CAED,IAAI,UAA4B;EAC/B,MAAM,UAAU,KAAK,SAAS,KAAK,KAAK;EAGxC,MAAM,QAAQ,0BAAM,QAAQ,CAC1B,IAAI,KAAK,kBAAkB,CAAC,CAC5B,IAAI,KAAK,WAAW,CAAC,CACrB,IAAI,KAAK,OAAO,CAAC,CACjB,IAAI,KAAK,UAAU,CAAC,CACpB,IAAI,KAAK,UAAU,CAAC,CACpB,IAAI,KAAK,SAAS,CAAC,CACnB,IAAI,KAAK,OAAO,CAAC,CACjB,IAAI,KAAK,QAAQ,CAAC;EAGpB,MAAM,iBAAiB,OAAOC,OAAgBC,YAAqB;GAClE,MAAM,YAAY,KAAK,KAAK;GAC5B,MAAM,YAAY,QAAQ;GAC1B,MAAM,SAAS,KAAK,GAAG,OAAO,MAAM,EAAE,UAAW,EAAC;AAElD,UAAO,gDAAsB;IAAE;IAAQ;IAAW;GAAW,GAAE,MAC9D,MAAM,OAAsC,QAAQ,CACpD;EACD;AAED,SAAO;CACP;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxTD,IAAa,uBAAb,cASU,kBAWR;CAED,YACCC,WACAC,MAUC;AACD,QAAM,WAAW,KAAK;CACtB;AACD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"Construct-DCMuYOox.d.mts","names":[],"sources":["../src/Construct.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAS8D;AAuC9D;;;cAtBM,cAuBoB,EAvBJ,cAuBI;AAEf,uBAHW,SAGX,CAAA,gBAFM,MAEN,GAFe,MAEf,EAAA,qBAAA,MAAA,GAAA,MAAA,EAAA,UAAA,cAAA,CAAA,GAAA,CAAA,GAAA,SAAA,GAAA,SAAA,EAAA,kBACQ,gBADR,GAAA,SAAA,GAAA,SAAA,EAAA,kBAEQ,OAFR,EAAA,GAAA,EAAA,EAAA,iCAAA,MAAA,GAAA,MAAA,EAAA,sBAIY,YAJZ,GAAA,SAAA,GAAA,SAAA,EAAA,6BAAA,MAAA,GAAA,MAAA,EAAA,YAAA,OAAA,CAAA,CAAA;EAAc,SACN,IAAA,EAWK,aAXL;EAAgB,SAChB,MAAA,EAWO,OAXP;EAAO,SAEH,QAAA,EAUK,SAVL;EAAY,SAQX,MAAA,EAGE,WAHF,CAGc,CAHd,EAAA,GAAA,CAAA,EAAA;EAAa,SACX,gBAAA,CAAA,EAIW,OAJX,CAImB,YAJnB,EAIiC,CAJjC,CAAA;EAAO,YACL,CAAA,EAIJ,SAJI,GAAA,SAAA;EAAS,SACC,OAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAC,SAAb,UAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAW,SAEQ,qBAAA,CAAA,EAIH,OAJG,CAK1C,wBAL0C,EAM1C,aAN0C,CAAA;EAAY;EAAG,eAAvB,CAAA,EARX,OAQW,CARH,oBAQG,EARmB,SAQnB,CAAA;EAAO,WACpB,CAAA,IAAA,EANA,aAMA,EAAA,MAAA,EALE,OAKF,EAAA,QAAA,EAJI,SAIJ,EAAA,MAAA,CAAA,EAHE,WAGF,CAHc,CAGd,EAAA,GAAA,CAAA,EAAA,EAAA,gBAAA,CAAA,EADa,OACb,CADqB,YACrB,EADmC,CACnC,CAAA,EAAA,YAAA,CAAA,EAAA,SAAA,GAAA,SAAA,EAAA,OAAA,CAAA,EAAA,MAAA,GAAA,SAAA,EAAA,UAAA,CAAA,EAAA,MAAA,GAAA,SAAA,EAAA,qBAAA,CAAA,EAGkB,OAHlB,CAIrB,wBAJqB,EAKrB,aALqB,CAAA;EAAS;;;;;;;;;;;;;;;;;;;AAkCtB;AAiEX;AAuBA;;EAAkC,cAAU,CAAA,IAA6B,CAA7B,EAAA;IAAkB,YAAA,CAAA,EAAA,OAAA;EAAW,CAAA,CAAA,EAxFrE,OAwFkD,CAAA,MAAA,EAAA,CAAA;AAAO;aAvBjD,aAAA;;;;;;;;;;;;;;;;;;;;;;iBAuBU,YAAA,UAAsB,UAAU,QAAQ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"Construct-_1wX7p_Y.d.cts","names":[],"sources":["../src/Construct.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAS8D;AAuC9D;;;cAtBM,cAuBoB,EAvBJ,cAuBI;AAEf,uBAHW,SAGX,CAAA,gBAFM,MAEN,GAFe,MAEf,EAAA,qBAAA,MAAA,GAAA,MAAA,EAAA,UAAA,cAAA,CAAA,GAAA,CAAA,GAAA,SAAA,GAAA,SAAA,EAAA,kBACQ,gBADR,GAAA,SAAA,GAAA,SAAA,EAAA,kBAEQ,OAFR,EAAA,GAAA,EAAA,EAAA,iCAAA,MAAA,GAAA,MAAA,EAAA,sBAIY,YAJZ,GAAA,SAAA,GAAA,SAAA,EAAA,6BAAA,MAAA,GAAA,MAAA,EAAA,YAAA,OAAA,CAAA,CAAA;EAAc,SACN,IAAA,EAWK,aAXL;EAAgB,SAChB,MAAA,EAWO,OAXP;EAAO,SAEH,QAAA,EAUK,SAVL;EAAY,SAQX,MAAA,EAGE,WAHF,CAGc,CAHd,EAAA,GAAA,CAAA,EAAA;EAAa,SACX,gBAAA,CAAA,EAIW,OAJX,CAImB,YAJnB,EAIiC,CAJjC,CAAA,GAAA,SAAA;EAAO,YACL,CAAA,EAIJ,SAJI,GAAA,SAAA;EAAS,SACC,OAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAC,SAAb,UAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAW,SAEQ,qBAAA,CAAA,EAIH,OAJG,CAK1C,wBAL0C,EAM1C,aAN0C,CAAA,GAAA,SAAA;EAAY;EAAG,eAAvB,CAAA,EARX,OAQW,CARH,oBAQG,EARmB,SAQnB,CAAA;EAAO,WACpB,CAAA,IAAA,EANA,aAMA,EAAA,MAAA,EALE,OAKF,EAAA,QAAA,EAJI,SAIJ,EAAA,MAAA,CAAA,EAHE,WAGF,CAHc,CAGd,EAAA,GAAA,CAAA,EAAA,EAAA,gBAAA,CAAA,EADa,OACb,CADqB,YACrB,EADmC,CACnC,CAAA,GAAA,SAAA,EAAA,YAAA,CAAA,EAAA,SAAA,GAAA,SAAA,EAAA,OAAA,CAAA,EAAA,MAAA,GAAA,SAAA,EAAA,UAAA,CAAA,EAAA,MAAA,GAAA,SAAA,EAAA,qBAAA,CAAA,EAGkB,OAHlB,CAIrB,wBAJqB,EAKrB,aALqB,CAAA,GAAA,SAAA;EAAS;;;;;;;;;;;;;;;;;;;AAkCtB;AAiEX;AAuBA;;EAAkC,cAAU,CAAA,IAA6B,CAA7B,EAAA;IAAkB,YAAA,CAAA,EAAA,OAAA;EAAW,CAAA,CAAA,EAxFrE,OAwFkD,CAAA,MAAA,EAAA,CAAA;AAAO;aAvBjD,aAAA;;;;;;;;;;;;;;;;;;;;;;iBAuBU,YAAA,UAAsB,UAAU,QAAQ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"Construct-r0U2zBwW.mjs","names":["compact","snifferContext: ServiceContext","type: ConstructType","logger: TLogger","services: TServices","events: MappedEvent<T, any>[]","publisherService?: Service<TServiceName, T>","outputSchema?: OutSchema","timeout?: number","memorySize?: number","auditorStorageService?: Service<\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditStorage\n\t\t>","opts: { markOptional?: boolean }","services: Service[]","service: Service"],"sources":["../../../node_modules/.pnpm/lodash.compact@3.0.1/node_modules/lodash.compact/index.js","../src/Construct.ts"],"sourcesContent":["/**\n * lodash 3.0.1 (Custom Build) <https://lodash.com/>\n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright 2012-2016 The Dojo Foundation <http://dojofoundation.org/>\n * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n * Copyright 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n * Available under MIT license <https://lodash.com/license>\n */\n\n/**\n * Creates an array with all falsey values removed. The values `false`, `null`,\n * `0`, `\"\"`, `undefined`, and `NaN` are falsey.\n *\n * @static\n * @memberOf _\n * @category Array\n * @param {Array} array The array to compact.\n * @returns {Array} Returns the new array of filtered values.\n * @example\n *\n * _.compact([0, 1, false, 2, '', 3]);\n * // => [1, 2, 3]\n */\nfunction compact(array) {\n var index = -1,\n length = array ? array.length : 0,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (value) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nmodule.exports = compact;\n","import type { AuditStorage } from '@geekmidas/audit';\nimport {\n\tSnifferEnvironmentParser,\n\ttype SniffResult,\n\tsniffWithFireAndForget,\n} from '@geekmidas/envkit/sniffer';\nimport type { EventPublisher, MappedEvent } from '@geekmidas/events';\nimport type { Logger } from '@geekmidas/logger';\nimport type { Service, ServiceContext } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport compact from 'lodash.compact';\n\n// Cache for service environment variables to handle singleton services\n// Stores both the full list and the optional subset so the same sniff result\n// can satisfy both getEnvironment() and getEnvironment({ markOptional: true }).\nconst serviceEnvCache = new Map<\n\tService,\n\t{ envVars: string[]; optionalEnvVars: string[] }\n>();\n\n/**\n * Noop context for environment sniffing.\n * Used when calling service.register() to detect env vars without a real request.\n * Returns dummy values since services should only use context in instance methods,\n * not during registration.\n */\nconst snifferContext: ServiceContext = {\n\tgetLogger() {\n\t\t// Return a noop logger for sniffing - services shouldn't log during registration\n\t\treturn {\n\t\t\tdebug: () => {},\n\t\t\tinfo: () => {},\n\t\t\twarn: () => {},\n\t\t\terror: () => {},\n\t\t\tchild: () => snifferContext.getLogger(),\n\t\t} as unknown as Logger;\n\t},\n\tgetRequestId() {\n\t\treturn 'sniffer-context';\n\t},\n\tgetRequestStartTime() {\n\t\treturn Date.now();\n\t},\n\thasContext() {\n\t\treturn false;\n\t},\n};\n\nexport abstract class Construct<\n\tTLogger extends Logger = Logger,\n\tTServiceName extends string = string,\n\tT extends EventPublisher<any> | undefined = undefined,\n\tOutSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTAuditStorageServiceName extends string = string,\n\tTAuditStorage extends AuditStorage | undefined = undefined,\n\tTDatabaseServiceName extends string = string,\n\tTDatabase = unknown,\n> {\n\t/** Database service for this construct (used by Endpoint for RLS/audit context) */\n\tpublic databaseService?: Service<TDatabaseServiceName, TDatabase>;\n\n\tconstructor(\n\t\tpublic readonly type: ConstructType,\n\t\tpublic readonly logger: TLogger,\n\t\tpublic readonly services: TServices,\n\t\tpublic readonly events: MappedEvent<T, any>[] = [],\n\n\t\tpublic readonly publisherService?: Service<TServiceName, T>,\n\t\tpublic outputSchema?: OutSchema,\n\t\tpublic readonly timeout?: number,\n\t\tpublic readonly memorySize?: number,\n\t\tpublic readonly auditorStorageService?: Service<\n\t\t\tTAuditStorageServiceName,\n\t\t\tTAuditStorage\n\t\t>,\n\t) {}\n\n\t/**\n\t * Returns an array of environment variable names required by this construct's services.\n\t * This is determined by running a \"sniffer\" EnvironmentParser through each service's\n\t * register method to track which environment variables are accessed.\n\t *\n\t * Results are cached per service class to handle singleton patterns where\n\t * subsequent register() calls may short-circuit and not access env vars.\n\t *\n\t * @param markOptional - When true, optional vars (those accessed via `.optional()` or\n\t * `.default()`) are suffixed with `?` in the returned array (e.g. `'PORT?'`).\n\t * @returns Promise that resolves to array of environment variable names, sorted alphabetically\n\t *\n\t * @example\n\t * ```typescript\n\t * const endpoint = e\n\t * .services([databaseService, authService])\n\t * .get('/users')\n\t * .handle(async () => []);\n\t *\n\t * await endpoint.getEnvironment(); // ['AUTH_SECRET', 'DATABASE_URL']\n\t * await endpoint.getEnvironment({ markOptional: true }); // ['AUTH_SECRET', 'DATABASE_URL', 'PORT?']\n\t * ```\n\t */\n\tasync getEnvironment(\n\t\topts: { markOptional?: boolean } = {},\n\t): Promise<string[]> {\n\t\tconst { markOptional = false } = opts;\n\t\tconst envVars = new Set<string>();\n\t\tconst optionalVars = new Set<string>();\n\t\tconst services: Service[] = compact([\n\t\t\t...this.services,\n\t\t\tthis.publisherService,\n\t\t\tthis.publisherService,\n\t\t\tthis.auditorStorageService,\n\t\t\tthis.databaseService,\n\t\t]);\n\n\t\ttry {\n\t\t\tfor (const service of services) {\n\t\t\t\t// Check cache first - handles singleton services that short-circuit\n\t\t\t\tif (serviceEnvCache.has(service)) {\n\t\t\t\t\tconst cached = serviceEnvCache.get(service)!;\n\t\t\t\t\tcached.envVars.forEach((v) => envVars.add(v));\n\t\t\t\t\tcached.optionalEnvVars.forEach((v) => optionalVars.add(v));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Use sniffService to properly handle all error scenarios\n\t\t\t\tconst result = await sniffService(service);\n\n\t\t\t\t// Log any issues for debugging\n\t\t\t\tif (result.error) {\n\t\t\t\t\tthis.logger.warn(\n\t\t\t\t\t\t{ error: result.error.message, service: service.serviceName },\n\t\t\t\t\t\t'Service threw error during env sniffing (env vars still captured)',\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (result.unhandledRejections.length > 0) {\n\t\t\t\t\tthis.logger.warn(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terrors: result.unhandledRejections.map((e) => e.message),\n\t\t\t\t\t\t\tservice: service.serviceName,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'Fire-and-forget rejections during env sniffing (suppressed)',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Cache and collect env vars (both required and optional)\n\t\t\t\tserviceEnvCache.set(service, {\n\t\t\t\t\tenvVars: result.envVars,\n\t\t\t\t\toptionalEnvVars: result.optionalEnvVars,\n\t\t\t\t});\n\t\t\t\tresult.envVars.forEach((v) => envVars.add(v));\n\t\t\t\tresult.optionalEnvVars.forEach((v) => optionalVars.add(v));\n\t\t\t}\n\n\t\t\tconst sorted = Array.from(envVars).sort();\n\t\t\tif (!markOptional || optionalVars.size === 0) return sorted;\n\t\t\treturn sorted.map((v) => (optionalVars.has(v) ? `${v}?` : v));\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\n\t\t\t\t{ error },\n\t\t\t\t'Error determining environment variables for construct',\n\t\t\t);\n\n\t\t\treturn [];\n\t\t}\n\t}\n}\n\nexport enum ConstructType {\n\tCron = 'dev.geekmidas.function.cron',\n\tEndpoint = 'dev.geekmidas.function.endpoint',\n\tFunction = 'dev.geekmidas.function.function',\n\tSubscriber = 'dev.geekmidas.function.subscriber',\n\tQueue = 'dev.geekmidas.function.queue',\n\tTopic = 'dev.geekmidas.resource.topic',\n}\n\n/**\n * Utility to test sniffing a service for environment variables.\n * Useful for debugging services that throw errors during sniffing.\n *\n * @example\n * ```typescript\n * import { sniffService } from '@geekmidas/constructs';\n * import { authService } from './services/AuthService';\n *\n * const result = await sniffService(authService);\n * console.log('Env vars:', result.envVars);\n * console.log('Error:', result.error);\n * ```\n */\nexport async function sniffService(service: Service): Promise<SniffResult> {\n\tconst sniffer = new SnifferEnvironmentParser();\n\n\treturn sniffWithFireAndForget(sniffer, () =>\n\t\tservice.register({\n\t\t\tenvParser: sniffer as any,\n\t\t\tcontext: snifferContext,\n\t\t}),\n\t);\n}\n\n// Export for testing\nexport { snifferContext };\n"],"x_google_ignoreList":[0],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBA,SAASA,UAAQ,OAAO;EACtB,IAAI,QAAQ,IACR,SAAS,QAAQ,MAAM,SAAS,GAChC,WAAW,GACX,SAAS,CAAE;AAEf,SAAO,EAAE,QAAQ,QAAQ;GACvB,IAAI,QAAQ,MAAM;AAClB,OAAI,MACF,QAAO,cAAc;EAExB;AACD,SAAO;CACR;AAED,QAAO,UAAUA;;;;;;ACvBjB,MAAM,kCAAkB,IAAI;;;;;;;AAW5B,MAAMC,iBAAiC;CACtC,YAAY;AAEX,SAAO;GACN,OAAO,MAAM,CAAE;GACf,MAAM,MAAM,CAAE;GACd,MAAM,MAAM,CAAE;GACd,OAAO,MAAM,CAAE;GACf,OAAO,MAAM,eAAe,WAAW;EACvC;CACD;CACD,eAAe;AACd,SAAO;CACP;CACD,sBAAsB;AACrB,SAAO,KAAK,KAAK;CACjB;CACD,aAAa;AACZ,SAAO;CACP;AACD;AAED,IAAsB,YAAtB,MAUE;;CAED,AAAO;CAEP,YACiBC,MACAC,QACAC,UACAC,SAAgC,CAAE,GAElCC,kBACTC,cACSC,SACAC,YACAC,uBAIf;EAbe;EACA;EACA;EACA;EAEA;EACT;EACS;EACA;EACA;CAIb;;;;;;;;;;;;;;;;;;;;;;;;CAyBJ,MAAM,eACLC,OAAmC,CAAE,GACjB;EACpB,MAAM,EAAE,eAAe,OAAO,GAAG;EACjC,MAAM,0BAAU,IAAI;EACpB,MAAM,+BAAe,IAAI;EACzB,MAAMC,WAAsB,2BAAQ;GACnC,GAAG,KAAK;GACR,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;EACL,EAAC;AAEF,MAAI;AACH,QAAK,MAAM,WAAW,UAAU;AAE/B,QAAI,gBAAgB,IAAI,QAAQ,EAAE;KACjC,MAAM,SAAS,gBAAgB,IAAI,QAAQ;AAC3C,YAAO,QAAQ,QAAQ,CAAC,MAAM,QAAQ,IAAI,EAAE,CAAC;AAC7C,YAAO,gBAAgB,QAAQ,CAAC,MAAM,aAAa,IAAI,EAAE,CAAC;AAC1D;IACA;IAGD,MAAM,SAAS,MAAM,aAAa,QAAQ;AAG1C,QAAI,OAAO,MACV,MAAK,OAAO,KACX;KAAE,OAAO,OAAO,MAAM;KAAS,SAAS,QAAQ;IAAa,GAC7D,oEACA;AAEF,QAAI,OAAO,oBAAoB,SAAS,EACvC,MAAK,OAAO,KACX;KACC,QAAQ,OAAO,oBAAoB,IAAI,CAAC,MAAM,EAAE,QAAQ;KACxD,SAAS,QAAQ;IACjB,GACD,8DACA;AAIF,oBAAgB,IAAI,SAAS;KAC5B,SAAS,OAAO;KAChB,iBAAiB,OAAO;IACxB,EAAC;AACF,WAAO,QAAQ,QAAQ,CAAC,MAAM,QAAQ,IAAI,EAAE,CAAC;AAC7C,WAAO,gBAAgB,QAAQ,CAAC,MAAM,aAAa,IAAI,EAAE,CAAC;GAC1D;GAED,MAAM,SAAS,MAAM,KAAK,QAAQ,CAAC,MAAM;AACzC,QAAK,gBAAgB,aAAa,SAAS,EAAG,QAAO;AACrD,UAAO,OAAO,IAAI,CAAC,MAAO,aAAa,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAG;EAC7D,SAAQ,OAAO;AACf,QAAK,OAAO,MACX,EAAE,MAAO,GACT,wDACA;AAED,UAAO,CAAE;EACT;CACD;AACD;AAED,IAAY,0DAAL;AACN;AACA;AACA;AACA;AACA;AACA;;AACA;;;;;;;;;;;;;;;AAgBD,eAAsB,aAAaC,SAAwC;CAC1E,MAAM,UAAU,IAAI;AAEpB,QAAO,uBAAuB,SAAS,MACtC,QAAQ,SAAS;EAChB,WAAW;EACX,SAAS;CACT,EAAC,CACF;AACD"}