@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.
- package/CHANGELOG.md +41 -0
- package/dist/{AWSScheduledFunction-Bn99MceY.d.cts → AWSScheduledFunction-BHHlWlfV.d.cts} +2 -2
- package/dist/{AWSScheduledFunction-ysaCsdWx.d.mts.map → AWSScheduledFunction-BHHlWlfV.d.cts.map} +1 -1
- package/dist/{AWSScheduledFunction-ysaCsdWx.d.mts → AWSScheduledFunction-BzGCUbkk.d.mts} +2 -2
- package/dist/{AWSScheduledFunction-Bn99MceY.d.cts.map → AWSScheduledFunction-BzGCUbkk.d.mts.map} +1 -1
- package/dist/{AWSScheduledFunction-DbkDr8CA.cjs → AWSScheduledFunction-C42adp8A.cjs} +16 -5
- package/dist/AWSScheduledFunction-C42adp8A.cjs.map +1 -0
- package/dist/{AWSScheduledFunction-CufMMhGB.mjs → AWSScheduledFunction-KP6lqbsW.mjs} +15 -4
- package/dist/AWSScheduledFunction-KP6lqbsW.mjs.map +1 -0
- package/dist/{Construct-r0U2zBwW.mjs → Construct-BWF5HxaM.mjs} +5 -2
- package/dist/Construct-BWF5HxaM.mjs.map +1 -0
- package/dist/{Construct-_1wX7p_Y.d.cts → Construct-JlyQkBkv.d.cts} +39 -4
- package/dist/Construct-JlyQkBkv.d.cts.map +1 -0
- package/dist/{Construct-vXMZJgRp.cjs → Construct-TGIM_E4o.cjs} +5 -2
- package/dist/Construct-TGIM_E4o.cjs.map +1 -0
- package/dist/{Construct-DCMuYOox.d.mts → Construct-pxwC6fDD.d.mts} +39 -4
- package/dist/Construct-pxwC6fDD.d.mts.map +1 -0
- package/dist/{Endpoint-CLPSIl6S.d.mts → Endpoint-B0P_pEMr.d.mts} +3 -3
- package/dist/{Endpoint-CLPSIl6S.d.mts.map → Endpoint-B0P_pEMr.d.mts.map} +1 -1
- package/dist/{Endpoint-DgfRslct.d.cts → Endpoint-Cwjhc1Hl.d.cts} +2 -2
- package/dist/Endpoint-Cwjhc1Hl.d.cts.map +1 -0
- package/dist/{HonoEndpointAdaptor-DJDT3PMx.mjs → HonoEndpointAdaptor-BMVwx2cz.mjs} +18 -11
- package/dist/HonoEndpointAdaptor-BMVwx2cz.mjs.map +1 -0
- package/dist/{HonoEndpointAdaptor-CkJENANP.cjs → HonoEndpointAdaptor-DPDsDi-D.cjs} +19 -12
- package/dist/HonoEndpointAdaptor-DPDsDi-D.cjs.map +1 -0
- package/dist/{Queue-HBDf0fqz.d.mts → Queue-BL68oDJ-.d.mts} +2 -2
- package/dist/{Queue-DaxjwmOQ.d.cts.map → Queue-BL68oDJ-.d.mts.map} +1 -1
- package/dist/{Queue-DaxjwmOQ.d.cts → Queue-DxJ6btRE.d.cts} +2 -2
- package/dist/{Queue-HBDf0fqz.d.mts.map → Queue-DxJ6btRE.d.cts.map} +1 -1
- package/dist/{Subscriber-B69ngPwl.d.cts → Subscriber-BpVhcGhX.d.cts} +2 -2
- package/dist/{Subscriber-B69ngPwl.d.cts.map → Subscriber-BpVhcGhX.d.cts.map} +1 -1
- package/dist/{Subscriber-D8Xm-86W.d.mts → Subscriber-DF6xsBAJ.d.mts} +2 -2
- package/dist/{Subscriber-D8Xm-86W.d.mts.map → Subscriber-DF6xsBAJ.d.mts.map} +1 -1
- package/dist/{Topic-DT10AqHk.d.mts → Topic-DJXoDeMP.d.cts} +3 -3
- package/dist/{Topic-C5ZMfveW.d.cts.map → Topic-DJXoDeMP.d.cts.map} +1 -1
- package/dist/{Topic-C5ZMfveW.d.cts → Topic-DxWQBgMN.d.mts} +3 -3
- package/dist/{Topic-DT10AqHk.d.mts.map → Topic-DxWQBgMN.d.mts.map} +1 -1
- package/dist/adaptors/aws.cjs +14 -7
- package/dist/adaptors/aws.cjs.map +1 -1
- package/dist/adaptors/aws.d.cts +6 -6
- package/dist/adaptors/aws.d.cts.map +1 -1
- package/dist/adaptors/aws.d.mts +8 -8
- package/dist/adaptors/aws.d.mts.map +1 -1
- package/dist/adaptors/aws.mjs +14 -7
- package/dist/adaptors/aws.mjs.map +1 -1
- package/dist/adaptors/hono.cjs +7 -6
- package/dist/adaptors/hono.d.cts +3 -3
- package/dist/adaptors/hono.d.cts.map +1 -1
- package/dist/adaptors/hono.d.mts +4 -4
- package/dist/adaptors/hono.d.mts.map +1 -1
- package/dist/adaptors/hono.mjs +7 -6
- package/dist/adaptors/testing.cjs +161 -126
- package/dist/adaptors/testing.cjs.map +1 -1
- package/dist/adaptors/testing.d.cts +7 -5
- package/dist/adaptors/testing.d.cts.map +1 -1
- package/dist/adaptors/testing.d.mts +8 -6
- package/dist/adaptors/testing.d.mts.map +1 -1
- package/dist/adaptors/testing.mjs +162 -127
- package/dist/adaptors/testing.mjs.map +1 -1
- package/dist/clone-I_WIpiFf.cjs +45 -0
- package/dist/clone-I_WIpiFf.cjs.map +1 -0
- package/dist/clone-pdXxc0t3.mjs +39 -0
- package/dist/clone-pdXxc0t3.mjs.map +1 -0
- package/dist/crons/index.cjs +14 -32
- package/dist/crons/index.cjs.map +1 -1
- package/dist/crons/index.d.cts +7 -7
- package/dist/crons/index.d.cts.map +1 -1
- package/dist/crons/index.d.mts +3 -3
- package/dist/crons/index.d.mts.map +1 -1
- package/dist/crons/index.mjs +14 -32
- package/dist/crons/index.mjs.map +1 -1
- package/dist/endpoints/index.cjs +74 -61
- package/dist/endpoints/index.cjs.map +1 -1
- package/dist/endpoints/index.d.cts +14 -6
- package/dist/endpoints/index.d.cts.map +1 -1
- package/dist/endpoints/index.d.mts +13 -5
- package/dist/endpoints/index.d.mts.map +1 -1
- package/dist/endpoints/index.mjs +74 -61
- package/dist/endpoints/index.mjs.map +1 -1
- package/dist/functions/index.cjs +3 -2
- package/dist/functions/index.d.cts +2 -2
- package/dist/functions/index.d.mts +2 -2
- package/dist/functions/index.mjs +3 -2
- package/dist/{functions-B-qt91O7.mjs → functions-EqTloHjo.mjs} +107 -46
- package/dist/functions-EqTloHjo.mjs.map +1 -0
- package/dist/{functions-C8i1kCMM.cjs → functions-SqtCDc9c.cjs} +118 -45
- package/dist/functions-SqtCDc9c.cjs.map +1 -0
- package/dist/{index-DP6fqv0I.d.mts → index-C7iynzLI.d.mts} +8 -2
- package/dist/index-C7iynzLI.d.mts.map +1 -0
- package/dist/{index-BVs9DvIj.d.cts → index-DdgJRm4q.d.cts} +12 -6
- package/dist/index-DdgJRm4q.d.cts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +1 -1
- package/dist/{lazyAccessors-DfqZR6C4.mjs → lazyAccessors-CCTK19xj.mjs} +3 -3
- package/dist/{lazyAccessors-DfqZR6C4.mjs.map → lazyAccessors-CCTK19xj.mjs.map} +1 -1
- package/dist/{lazyAccessors-DmTG8sQH.cjs → lazyAccessors-D04oftGw.cjs} +3 -3
- package/dist/{lazyAccessors-DmTG8sQH.cjs.map → lazyAccessors-D04oftGw.cjs.map} +1 -1
- package/dist/monitors/index.cjs +49 -0
- package/dist/monitors/index.cjs.map +1 -0
- package/dist/monitors/index.d.cts +45 -0
- package/dist/monitors/index.d.cts.map +1 -0
- package/dist/monitors/index.d.mts +45 -0
- package/dist/monitors/index.d.mts.map +1 -0
- package/dist/monitors/index.mjs +48 -0
- package/dist/monitors/index.mjs.map +1 -0
- package/dist/{processAudits-CKjjivyz.cjs → processAudits-BJZT5gmy.cjs} +2 -2
- package/dist/{processAudits-CKjjivyz.cjs.map → processAudits-BJZT5gmy.cjs.map} +1 -1
- package/dist/{processAudits-ySnizdMG.mjs → processAudits-CwyaaSQc.mjs} +1 -1
- package/dist/{processAudits-ySnizdMG.mjs.map → processAudits-CwyaaSQc.mjs.map} +1 -1
- package/dist/{publisher-lFQleddL.cjs → publisher-BZgcrVPy.cjs} +1 -1
- package/dist/{publisher-lFQleddL.cjs.map → publisher-BZgcrVPy.cjs.map} +1 -1
- package/dist/{publisher-BrFOF847.mjs → publisher-CnpeMv-r.mjs} +1 -1
- package/dist/{publisher-BrFOF847.mjs.map → publisher-CnpeMv-r.mjs.map} +1 -1
- package/dist/queue/index.cjs +9 -22
- package/dist/queue/index.cjs.map +1 -1
- package/dist/queue/index.d.cts +4 -4
- package/dist/queue/index.d.cts.map +1 -1
- package/dist/queue/index.d.mts +2 -2
- package/dist/queue/index.d.mts.map +1 -1
- package/dist/queue/index.mjs +9 -22
- package/dist/queue/index.mjs.map +1 -1
- package/dist/subscribers/index.cjs +9 -22
- package/dist/subscribers/index.cjs.map +1 -1
- package/dist/subscribers/index.d.cts +5 -5
- package/dist/subscribers/index.d.cts.map +1 -1
- package/dist/subscribers/index.d.mts +3 -3
- package/dist/subscribers/index.d.mts.map +1 -1
- package/dist/subscribers/index.mjs +9 -22
- package/dist/subscribers/index.mjs.map +1 -1
- package/dist/{telemetry-3vdxGn4q.d.mts → telemetry-C--EgYVr.d.mts} +1 -1
- package/dist/{telemetry-3vdxGn4q.d.mts.map → telemetry-C--EgYVr.d.mts.map} +1 -1
- package/dist/topic/index.cjs +4 -7
- package/dist/topic/index.cjs.map +1 -1
- package/dist/topic/index.d.cts +2 -2
- package/dist/topic/index.d.cts.map +1 -1
- package/dist/topic/index.d.mts +2 -2
- package/dist/topic/index.d.mts.map +1 -1
- package/dist/topic/index.mjs +4 -7
- package/dist/topic/index.mjs.map +1 -1
- package/dist/{types-BDNGr7pv.d.mts → types-DNngH0fX.d.mts} +1 -1
- package/dist/{types-BDNGr7pv.d.mts.map → types-DNngH0fX.d.mts.map} +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +32 -22
- package/src/Construct.ts +5 -0
- package/src/__tests__/builder-reuse.spec.ts +587 -0
- package/src/__tests__/monitor.spec.ts +636 -0
- package/src/clone.ts +38 -0
- package/src/crons/CronBuilder.ts +35 -45
- package/src/crons/__tests__/Cron.spec.ts +10 -2
- package/src/crons/__tests__/CronBuilder.state-isolation.spec.ts +64 -18
- package/src/endpoints/AmazonApiGatewayEndpointAdaptor.ts +23 -2
- package/src/endpoints/EndpointBuilder.ts +61 -70
- package/src/endpoints/EndpointFactory.ts +31 -0
- package/src/endpoints/HonoEndpointAdaptor.ts +16 -1
- package/src/endpoints/TestEndpointAdaptor.ts +194 -150
- package/src/endpoints/__tests__/EndpointBuilder.audit.spec.ts +6 -3
- package/src/endpoints/__tests__/EndpointBuilder.responseType.spec.ts +4 -1
- package/src/endpoints/__tests__/EndpointBuilder.spec.ts +16 -8
- package/src/functions/AWSLambdaFunction.ts +28 -2
- package/src/functions/BaseFunctionBuilder.ts +33 -22
- package/src/functions/FunctionBuilder.ts +41 -51
- package/src/functions/TestFunctionAdaptor.ts +66 -31
- package/src/functions/__tests__/FunctionBuilder.state-isolation.spec.ts +55 -12
- package/src/index.ts +6 -0
- package/src/monitor.ts +145 -0
- package/src/monitors/heartbeat.ts +86 -0
- package/src/monitors/index.ts +6 -0
- package/src/queue/QueueBuilder.ts +22 -22
- package/src/subscribers/SubscriberBuilder.ts +19 -22
- package/src/topic/TopicBuilder.ts +9 -7
- package/tsdown.config.ts +1 -0
- package/dist/AWSScheduledFunction-CufMMhGB.mjs.map +0 -1
- package/dist/AWSScheduledFunction-DbkDr8CA.cjs.map +0 -1
- package/dist/Construct-DCMuYOox.d.mts.map +0 -1
- package/dist/Construct-_1wX7p_Y.d.cts.map +0 -1
- package/dist/Construct-r0U2zBwW.mjs.map +0 -1
- package/dist/Construct-vXMZJgRp.cjs.map +0 -1
- package/dist/Endpoint-DgfRslct.d.cts.map +0 -1
- package/dist/HonoEndpointAdaptor-CkJENANP.cjs.map +0 -1
- package/dist/HonoEndpointAdaptor-DJDT3PMx.mjs.map +0 -1
- package/dist/functions-B-qt91O7.mjs.map +0 -1
- package/dist/functions-C8i1kCMM.cjs.map +0 -1
- package/dist/index-BVs9DvIj.d.cts.map +0 -1
- 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
|
+
});
|
|
@@ -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
|
|
32
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
56
|
-
|
|
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
|
|
68
|
-
|
|
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
|
|
76
|
-
|
|
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
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
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
|
|
54
|
-
|
|
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
|
|
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
|
|
80
|
-
|
|
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
|
-
|
|
94
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
145
|
-
|
|
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
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
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
|
|
20
|
-
|
|
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
|
|
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
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
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
|
@@ -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":"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"}
|
|
@@ -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"}
|