@geekmidas/constructs 10.0.0-alpha.52 → 10.0.0-alpha.53

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.
@@ -0,0 +1,109 @@
1
+ import { ServiceDiscovery } from "@geekmidas/services";
2
+ //#region src/subscribers/runSubscriber.ts
3
+ /** The subscriber's output did not match its `.output()` schema. */
4
+ var SubscriberOutputInvalid = class extends Error {
5
+ issues;
6
+ constructor(issues) {
7
+ super("Subscriber output validation failed: the handler's result does not match its .output() schema.");
8
+ this.issues = issues;
9
+ this.name = "SubscriberOutputInvalid";
10
+ }
11
+ };
12
+ /** The events in an SQS or SNS batch (a Lambda event's `Records`) that `subscriber` subscribed to. */
13
+ function subscribedEvents(subscriber, rawEvent, logger) {
14
+ const events = [];
15
+ const records = rawEvent.Records ?? [];
16
+ const first = records[0];
17
+ const parse = first?.eventSource === "aws:sqs" ? (record) => parseSQSRecord(record) : first?.EventSource === "aws:sns" ? (record) => parseSNSRecord(record) : void 0;
18
+ if (!parse) return events;
19
+ for (const record of records) try {
20
+ const event = parse(record);
21
+ if (isSubscribed(subscriber, event)) events.push(event);
22
+ } catch (error) {
23
+ logger.error({
24
+ error,
25
+ record
26
+ }, "Failed to parse record");
27
+ }
28
+ return events;
29
+ }
30
+ /** The subscriber's services and database, registered as functions do. */
31
+ async function subscriberContext(subscriber, envParser) {
32
+ const discovery = ServiceDiscovery.getInstance(envParser);
33
+ const services = subscriber.services.length > 0 ? await discovery.register(subscriber.services) : {};
34
+ const service = subscriber.databaseService;
35
+ return {
36
+ services,
37
+ db: service ? (await discovery.register([service]))[service.serviceName] : void 0
38
+ };
39
+ }
40
+ /** Runs the handler on `events`, and checks its output against its schema. */
41
+ async function runSubscriber(subscriber, context) {
42
+ if (context.events.length === 0) {
43
+ context.logger.info("No subscribed events to process");
44
+ return { batchItemFailures: [] };
45
+ }
46
+ const { events, services, db, logger } = context;
47
+ const result = await subscriber.handler({
48
+ events,
49
+ services,
50
+ logger,
51
+ db
52
+ });
53
+ if (subscriber.outputSchema && result) {
54
+ const validation = await subscriber.outputSchema["~standard"].validate(result);
55
+ if (validation.issues) {
56
+ context.logger.error({ issues: validation.issues }, "Subscriber output validation failed");
57
+ throw new SubscriberOutputInvalid(validation.issues);
58
+ }
59
+ return validation.value;
60
+ }
61
+ return result;
62
+ }
63
+ function isSubscribed(subscriber, event) {
64
+ if (typeof event !== "object" || !event?.type) return true;
65
+ if (!subscriber.subscribedEvents) return true;
66
+ return subscriber.subscribedEvents.includes(event.type);
67
+ }
68
+ function parseSNSRecord(record) {
69
+ const message = safeJsonParse(record.Sns.Message);
70
+ const messageType = record.Sns.MessageAttributes?.type?.Value;
71
+ if (message === null) return messageType ? {
72
+ type: messageType,
73
+ payload: record.Sns.Message
74
+ } : record.Sns.Message;
75
+ if (message.type) return message;
76
+ return messageType ? {
77
+ type: messageType,
78
+ payload: message
79
+ } : message;
80
+ }
81
+ function parseSQSRecord(record) {
82
+ const body = safeJsonParse(record.body);
83
+ if (body === null) return record.body;
84
+ if (body.Type === "Notification" && body.Message) {
85
+ const snsMessage = safeJsonParse(body.Message);
86
+ const messageType = body.MessageAttributes?.type?.Value;
87
+ if (snsMessage === null) return messageType ? {
88
+ type: messageType,
89
+ payload: body.Message
90
+ } : body.Message;
91
+ if (snsMessage.type) return snsMessage;
92
+ return messageType ? {
93
+ type: messageType,
94
+ payload: snsMessage
95
+ } : snsMessage;
96
+ }
97
+ return body;
98
+ }
99
+ function safeJsonParse(value) {
100
+ try {
101
+ return JSON.parse(value);
102
+ } catch {
103
+ return null;
104
+ }
105
+ }
106
+ //#endregion
107
+ export { subscribedEvents as n, subscriberContext as r, runSubscriber as t };
108
+
109
+ //# sourceMappingURL=runSubscriber-BYEY_bfA.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runSubscriber-BYEY_bfA.mjs","names":[],"sources":["../src/subscribers/runSubscriber.ts"],"sourcesContent":["/**\n * What a subscriber does with a batch of records, however they arrived: parse\n * them into events, keep the ones it subscribed to, and run its handler with\n * its services and database.\n *\n * Shared by the Lambda adaptor, which wraps it in middy, and the SNS push\n * adaptor, which a server runs and which must not need middy to load.\n */\n\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { ServiceDiscovery } from '@geekmidas/services';\nimport type { SNSEvent, SNSEventRecord, SQSEvent, SQSRecord } from 'aws-lambda';\nimport type { Subscriber } from './Subscriber';\n\ntype AnySubscriber = Subscriber<any, any, any, any, any, any, any>;\n\n/** The subscriber's output did not match its `.output()` schema. */\nexport class SubscriberOutputInvalid extends Error {\n\tconstructor(readonly issues: ReadonlyArray<unknown>) {\n\t\tsuper(\n\t\t\t\"Subscriber output validation failed: the handler's result does not match its .output() schema.\",\n\t\t);\n\t\tthis.name = 'SubscriberOutputInvalid';\n\t}\n}\n\n/** The events in an SQS or SNS batch (a Lambda event's `Records`) that `subscriber` subscribed to. */\nexport function subscribedEvents(\n\tsubscriber: AnySubscriber,\n\trawEvent: { Records?: readonly unknown[] },\n\tlogger: Logger,\n): any[] {\n\tconst events: any[] = [];\n\tconst records = rawEvent.Records ?? [];\n\tconst first = records[0] as any;\n\tconst parse =\n\t\tfirst?.eventSource === 'aws:sqs'\n\t\t\t? (record: any) => parseSQSRecord(record)\n\t\t\t: first?.EventSource === 'aws:sns'\n\t\t\t\t? (record: any) => parseSNSRecord(record)\n\t\t\t\t: undefined;\n\tif (!parse) return events;\n\n\tfor (const record of records) {\n\t\ttry {\n\t\t\tconst event = parse(record);\n\t\t\tif (isSubscribed(subscriber, event)) events.push(event);\n\t\t} catch (error) {\n\t\t\tlogger.error({ error, record }, 'Failed to parse record');\n\t\t}\n\t}\n\treturn events;\n}\n\n/** The subscriber's services and database, registered as functions do. */\nexport async function subscriberContext(\n\tsubscriber: AnySubscriber,\n\tenvParser: EnvironmentParser<{}>,\n): Promise<{ services: Record<string, unknown>; db: unknown }> {\n\tconst discovery = ServiceDiscovery.getInstance(envParser);\n\tconst services =\n\t\tsubscriber.services.length > 0\n\t\t\t? await discovery.register(subscriber.services)\n\t\t\t: {};\n\tconst service = subscriber.databaseService;\n\tconst db = service\n\t\t? (await discovery.register([service]))[service.serviceName]\n\t\t: undefined;\n\treturn { services, db };\n}\n\n/** Runs the handler on `events`, and checks its output against its schema. */\nexport async function runSubscriber(\n\tsubscriber: AnySubscriber,\n\tcontext: {\n\t\tevents: any[];\n\t\tservices: Record<string, unknown>;\n\t\tdb: unknown;\n\t\tlogger: Logger;\n\t},\n): Promise<unknown> {\n\tif (context.events.length === 0) {\n\t\tcontext.logger.info('No subscribed events to process');\n\t\treturn { batchItemFailures: [] };\n\t}\n\n\tconst { events, services, db, logger } = context;\n\tconst result = await subscriber.handler({\n\t\tevents,\n\t\tservices,\n\t\tlogger,\n\t\tdb,\n\t} as any);\n\n\tif (subscriber.outputSchema && result) {\n\t\tconst validation =\n\t\t\tawait subscriber.outputSchema['~standard'].validate(result);\n\t\tif (validation.issues) {\n\t\t\tcontext.logger.error(\n\t\t\t\t{ issues: validation.issues },\n\t\t\t\t'Subscriber output validation failed',\n\t\t\t);\n\t\t\tthrow new SubscriberOutputInvalid(validation.issues);\n\t\t}\n\t\treturn validation.value;\n\t}\n\n\treturn result;\n}\n\nfunction isSubscribed(subscriber: AnySubscriber, event: any): boolean {\n\t// No event type (raw string/non-object) — always include\n\tif (typeof event !== 'object' || !event?.type) return true;\n\t// No filter configured — accept all\n\tif (!subscriber.subscribedEvents) return true;\n\treturn subscriber.subscribedEvents.includes(event.type);\n}\n\nfunction parseSNSRecord(record: SNSEventRecord): any {\n\tconst message = safeJsonParse(record.Sns.Message);\n\tconst messageType = record.Sns.MessageAttributes?.type?.Value;\n\n\t// Not JSON — wrap raw string with type from MessageAttributes if available\n\tif (message === null) {\n\t\treturn messageType\n\t\t\t? { type: messageType, payload: record.Sns.Message }\n\t\t\t: record.Sns.Message;\n\t}\n\n\tif (message.type) {\n\t\treturn message; // Full event format: { type, payload }\n\t}\n\n\t// Payload-only format: type is in MessageAttributes\n\treturn messageType ? { type: messageType, payload: message } : message;\n}\n\nfunction parseSQSRecord(record: SQSRecord): any {\n\tconst body = safeJsonParse(record.body);\n\n\t// Not JSON — return raw body as-is\n\tif (body === null) {\n\t\treturn record.body;\n\t}\n\n\t// Check if this is an SNS message wrapped in SQS\n\tif (body.Type === 'Notification' && body.Message) {\n\t\tconst snsMessage = safeJsonParse(body.Message);\n\t\tconst messageType = body.MessageAttributes?.type?.Value;\n\n\t\t// SNS Message not JSON — wrap with type from MessageAttributes if available\n\t\tif (snsMessage === null) {\n\t\t\treturn messageType\n\t\t\t\t? { type: messageType, payload: body.Message }\n\t\t\t\t: body.Message;\n\t\t}\n\n\t\tif (snsMessage.type) {\n\t\t\treturn snsMessage; // Full event format: { type, payload }\n\t\t}\n\n\t\t// Payload-only format: type is in MessageAttributes\n\t\treturn messageType\n\t\t\t? { type: messageType, payload: snsMessage }\n\t\t\t: snsMessage;\n\t}\n\n\t// Direct SQS message\n\treturn body;\n}\n\nfunction safeJsonParse(value: string): any | null {\n\ttry {\n\t\treturn JSON.parse(value);\n\t} catch {\n\t\treturn null;\n\t}\n}\n"],"mappings":"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"}
@@ -1,4 +1,111 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_SubscriberBuilder = require("../SubscriberBuilder-C2PwqwIl.cjs");
3
+ const require_runSubscriber = require("../runSubscriber-BRp9a_qi.cjs");
4
+ let _geekmidas_errors = require("@geekmidas/errors");
5
+ let _geekmidas_services = require("@geekmidas/services");
6
+ let _geekmidas_events_sns = require("@geekmidas/events/sns");
7
+ //#region src/subscribers/SnsPushSubscriberAdaptor.ts
8
+ /**
9
+ * A topic subscriber run by SNS pushing to an HTTP endpoint, rather than by a
10
+ * poller.
11
+ *
12
+ * The notification is read as the Lambda event SNS would have invoked a
13
+ * function with, and run through the same parsing, services and handler as the
14
+ * Lambda adaptor — without its middy wrapper, which is Lambda's alone: a
15
+ * server serving this route has no reason to install `@middy/core`.
16
+ */
17
+ var SnsPushSubscriberAdaptor = class {
18
+ envParser;
19
+ subscriber;
20
+ options;
21
+ constructor(envParser, subscriber, options) {
22
+ this.envParser = envParser;
23
+ this.subscriber = subscriber;
24
+ this.options = options;
25
+ }
26
+ async handle(body) {
27
+ const message = body;
28
+ if (typeof message?.Type !== "string" || !message.TopicArn) return refuse(400, "not an SNS message");
29
+ if (message.TopicArn !== this.options.topicArn) return refuse(403, `not subscribed to ${message.TopicArn}`);
30
+ if (this.options.verify) try {
31
+ await (0, _geekmidas_events_sns.verifySnsMessage)(message);
32
+ } catch (error) {
33
+ this.subscriber.logger.warn({
34
+ error,
35
+ topicArn: message.TopicArn
36
+ }, "Refused an SNS message that did not verify");
37
+ return refuse(403, error.name);
38
+ }
39
+ switch (message.Type) {
40
+ case "SubscriptionConfirmation":
41
+ await (0, _geekmidas_events_sns.confirmSnsSubscription)(this.options.emulatorEndpoint && message.SubscribeURL ? {
42
+ ...message,
43
+ SubscribeURL: throughEndpoint(message.SubscribeURL, this.options.emulatorEndpoint)
44
+ } : message);
45
+ this.subscriber.logger.info({ topicArn: message.TopicArn }, "Confirmed SNS subscription");
46
+ return {
47
+ status: 200,
48
+ body: { status: "confirmed" }
49
+ };
50
+ case "Notification": try {
51
+ await this.notify(message);
52
+ return {
53
+ status: 200,
54
+ body: { status: "ok" }
55
+ };
56
+ } catch (error) {
57
+ return refuse(500, error.name);
58
+ }
59
+ default: return {
60
+ status: 200,
61
+ body: { status: "ignored" }
62
+ };
63
+ }
64
+ }
65
+ async notify(message) {
66
+ const requestId = message.MessageId;
67
+ const logger = this.subscriber.logger.child({ requestId });
68
+ await (0, _geekmidas_services.runWithRequestContext)({
69
+ logger,
70
+ requestId,
71
+ startTime: Date.now()
72
+ }, async () => {
73
+ try {
74
+ const { services, db } = await require_runSubscriber.subscriberContext(this.subscriber, this.envParser);
75
+ const events = require_runSubscriber.subscribedEvents(this.subscriber, (0, _geekmidas_events_sns.toSnsEvent)(message), logger);
76
+ await require_runSubscriber.runSubscriber(this.subscriber, {
77
+ events,
78
+ services,
79
+ logger,
80
+ db
81
+ });
82
+ } catch (error) {
83
+ logger.error(error, "Error processing subscriber");
84
+ throw (0, _geekmidas_errors.wrapError)(error);
85
+ }
86
+ });
87
+ }
88
+ };
89
+ /** `url`, sent to `endpoint`'s origin instead of its own. */
90
+ function throughEndpoint(url, endpoint) {
91
+ const target = new URL(url);
92
+ const origin = new URL(endpoint);
93
+ target.protocol = origin.protocol;
94
+ target.host = origin.host;
95
+ return target.toString();
96
+ }
97
+ function refuse(status, error) {
98
+ return {
99
+ status,
100
+ body: {
101
+ status: "refused",
102
+ error
103
+ }
104
+ };
105
+ }
106
+ //#endregion
107
+ exports.SnsPushSubscriberAdaptor = SnsPushSubscriberAdaptor;
3
108
  exports.Subscriber = require_SubscriberBuilder.Subscriber;
4
109
  exports.SubscriberBuilder = require_SubscriberBuilder.SubscriberBuilder;
110
+
111
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["verifySnsMessage","confirmSnsSubscription","runWithRequestContext","subscriberContext","subscribedEvents","toSnsEvent","runSubscriber","wrapError"],"sources":["../../src/subscribers/SnsPushSubscriberAdaptor.ts"],"sourcesContent":["import type { EnvironmentParser } from '@geekmidas/envkit';\nimport { wrapError } from '@geekmidas/errors';\nimport {\n\tconfirmSnsSubscription,\n\ttype SnsHttpMessage,\n\ttoSnsEvent,\n\tverifySnsMessage,\n} from '@geekmidas/events/sns';\nimport { runWithRequestContext } from '@geekmidas/services';\nimport {\n\trunSubscriber,\n\tsubscribedEvents,\n\tsubscriberContext,\n} from './runSubscriber';\nimport type { Subscriber } from './Subscriber';\n\nexport interface SnsPushOptions {\n\t/** The topic this subscriber is subscribed to. Anything else is refused. */\n\ttopicArn: string;\n\t/**\n\t * Verify each message's signature. Off only against an emulator, which\n\t * signs nothing — decided by the connection string's endpoint, never by\n\t * anything the request says about itself.\n\t */\n\tverify: boolean;\n\t/**\n\t * The emulator's address, as this server was configured with it. An\n\t * emulator names itself in `SubscribeURL` by the port it listens on inside\n\t * its container, which is not the port published to the host — so against\n\t * one, the confirmation is sent here instead. From configuration, never\n\t * from the request.\n\t */\n\temulatorEndpoint?: string;\n}\n\n/** What to answer SNS with. A non-2xx tells SNS to retry. */\nexport interface SnsPushResponse {\n\tstatus: 200 | 400 | 403 | 500;\n\tbody: { status: string; error?: string };\n}\n\n/**\n * A topic subscriber run by SNS pushing to an HTTP endpoint, rather than by a\n * poller.\n *\n * The notification is read as the Lambda event SNS would have invoked a\n * function with, and run through the same parsing, services and handler as the\n * Lambda adaptor — without its middy wrapper, which is Lambda's alone: a\n * server serving this route has no reason to install `@middy/core`.\n */\nexport class SnsPushSubscriberAdaptor {\n\tconstructor(\n\t\tprivate readonly envParser: EnvironmentParser<{}>,\n\t\treadonly subscriber: Subscriber<any, any, any, any, any, any, any>,\n\t\tprivate readonly options: SnsPushOptions,\n\t) {}\n\n\tasync handle(body: unknown): Promise<SnsPushResponse> {\n\t\tconst message = body as SnsHttpMessage;\n\t\tif (typeof message?.Type !== 'string' || !message.TopicArn) {\n\t\t\treturn refuse(400, 'not an SNS message');\n\t\t}\n\t\t// Checked before the signature: a genuine message for another topic is\n\t\t// still not this subscriber's to confirm or to handle.\n\t\tif (message.TopicArn !== this.options.topicArn) {\n\t\t\treturn refuse(403, `not subscribed to ${message.TopicArn}`);\n\t\t}\n\n\t\tif (this.options.verify) {\n\t\t\ttry {\n\t\t\t\tawait verifySnsMessage(message);\n\t\t\t} catch (error) {\n\t\t\t\tthis.subscriber.logger.warn(\n\t\t\t\t\t{ error, topicArn: message.TopicArn },\n\t\t\t\t\t'Refused an SNS message that did not verify',\n\t\t\t\t);\n\t\t\t\treturn refuse(403, (error as Error).name);\n\t\t\t}\n\t\t}\n\n\t\tswitch (message.Type) {\n\t\t\tcase 'SubscriptionConfirmation':\n\t\t\t\tawait confirmSnsSubscription(\n\t\t\t\t\tthis.options.emulatorEndpoint && message.SubscribeURL\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t...message,\n\t\t\t\t\t\t\t\tSubscribeURL: throughEndpoint(\n\t\t\t\t\t\t\t\t\tmessage.SubscribeURL,\n\t\t\t\t\t\t\t\t\tthis.options.emulatorEndpoint,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: message,\n\t\t\t\t);\n\t\t\t\tthis.subscriber.logger.info(\n\t\t\t\t\t{ topicArn: message.TopicArn },\n\t\t\t\t\t'Confirmed SNS subscription',\n\t\t\t\t);\n\t\t\t\treturn { status: 200, body: { status: 'confirmed' } };\n\t\t\tcase 'Notification':\n\t\t\t\ttry {\n\t\t\t\t\tawait this.notify(message);\n\t\t\t\t\treturn { status: 200, body: { status: 'ok' } };\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Already logged. A 500 makes SNS retry, which is the point of\n\t\t\t\t\t// answering at all.\n\t\t\t\t\treturn refuse(500, (error as Error).name);\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn { status: 200, body: { status: 'ignored' } };\n\t\t}\n\t}\n\n\tprivate async notify(message: SnsHttpMessage): Promise<void> {\n\t\tconst requestId = message.MessageId;\n\t\tconst logger = this.subscriber.logger.child({ requestId });\n\n\t\tawait runWithRequestContext(\n\t\t\t{ logger, requestId, startTime: Date.now() },\n\t\t\tasync () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst { services, db } = await subscriberContext(\n\t\t\t\t\t\tthis.subscriber,\n\t\t\t\t\t\tthis.envParser,\n\t\t\t\t\t);\n\t\t\t\t\tconst events = subscribedEvents(\n\t\t\t\t\t\tthis.subscriber,\n\t\t\t\t\t\ttoSnsEvent(message),\n\t\t\t\t\t\tlogger,\n\t\t\t\t\t);\n\t\t\t\t\tawait runSubscriber(this.subscriber, {\n\t\t\t\t\t\tevents,\n\t\t\t\t\t\tservices,\n\t\t\t\t\t\tlogger,\n\t\t\t\t\t\tdb,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(error as object, 'Error processing subscriber');\n\t\t\t\t\tthrow wrapError(error);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\t}\n}\n\n/** `url`, sent to `endpoint`'s origin instead of its own. */\nfunction throughEndpoint(url: string, endpoint: string): string {\n\tconst target = new URL(url);\n\tconst origin = new URL(endpoint);\n\ttarget.protocol = origin.protocol;\n\ttarget.host = origin.host;\n\treturn target.toString();\n}\n\nfunction refuse(\n\tstatus: SnsPushResponse['status'],\n\terror: string,\n): SnsPushResponse {\n\treturn { status, body: { status: 'refused', error } };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkDA,IAAa,2BAAb,MAAsC;CAEnB;CACR;CACQ;CAHlB,YACC,WACA,YACA,SACC;EAHgB,KAAA,YAAA;EACR,KAAA,aAAA;EACQ,KAAA,UAAA;CACf;CAEH,MAAM,OAAO,MAAyC;EACrD,MAAM,UAAU;EAChB,IAAI,OAAO,SAAS,SAAS,YAAY,CAAC,QAAQ,UACjD,OAAO,OAAO,KAAK,oBAAoB;EAIxC,IAAI,QAAQ,aAAa,KAAK,QAAQ,UACrC,OAAO,OAAO,KAAK,qBAAqB,QAAQ,UAAU;EAG3D,IAAI,KAAK,QAAQ,QAChB,IAAI;GACH,OAAA,GAAMA,sBAAAA,iBAAAA,CAAiB,OAAO;EAC/B,SAAS,OAAO;GACf,KAAK,WAAW,OAAO,KACtB;IAAE;IAAO,UAAU,QAAQ;GAAS,GACpC,4CACD;GACA,OAAO,OAAO,KAAM,MAAgB,IAAI;EACzC;EAGD,QAAQ,QAAQ,MAAhB;GACC,KAAK;IACJ,OAAA,GAAMC,sBAAAA,uBAAAA,CACL,KAAK,QAAQ,oBAAoB,QAAQ,eACtC;KACA,GAAG;KACH,cAAc,gBACb,QAAQ,cACR,KAAK,QAAQ,gBACd;IACD,IACC,OACJ;IACA,KAAK,WAAW,OAAO,KACtB,EAAE,UAAU,QAAQ,SAAS,GAC7B,4BACD;IACA,OAAO;KAAE,QAAQ;KAAK,MAAM,EAAE,QAAQ,YAAY;IAAE;GACrD,KAAK,gBACJ,IAAI;IACH,MAAM,KAAK,OAAO,OAAO;IACzB,OAAO;KAAE,QAAQ;KAAK,MAAM,EAAE,QAAQ,KAAK;IAAE;GAC9C,SAAS,OAAO;IAGf,OAAO,OAAO,KAAM,MAAgB,IAAI;GACzC;GACD,SACC,OAAO;IAAE,QAAQ;IAAK,MAAM,EAAE,QAAQ,UAAU;GAAE;EACpD;CACD;CAEA,MAAc,OAAO,SAAwC;EAC5D,MAAM,YAAY,QAAQ;EAC1B,MAAM,SAAS,KAAK,WAAW,OAAO,MAAM,EAAE,UAAU,CAAC;EAEzD,OAAA,GAAMC,oBAAAA,sBAAAA,CACL;GAAE;GAAQ;GAAW,WAAW,KAAK,IAAI;EAAE,GAC3C,YAAY;GACX,IAAI;IACH,MAAM,EAAE,UAAU,OAAO,MAAMC,sBAAAA,kBAC9B,KAAK,YACL,KAAK,SACN;IACA,MAAM,SAASC,sBAAAA,iBACd,KAAK,aAAA,GACLC,sBAAAA,WAAAA,CAAW,OAAO,GAClB,MACD;IACA,MAAMC,sBAAAA,cAAc,KAAK,YAAY;KACpC;KACA;KACA;KACA;IACD,CAAC;GACF,SAAS,OAAO;IACf,OAAO,MAAM,OAAiB,6BAA6B;IAC3D,OAAA,GAAMC,kBAAAA,UAAAA,CAAU,KAAK;GACtB;EACD,CACD;CACD;AACD;;AAGA,SAAS,gBAAgB,KAAa,UAA0B;CAC/D,MAAM,SAAS,IAAI,IAAI,GAAG;CAC1B,MAAM,SAAS,IAAI,IAAI,QAAQ;CAC/B,OAAO,WAAW,OAAO;CACzB,OAAO,OAAO,OAAO;CACrB,OAAO,OAAO,SAAS;AACxB;AAEA,SAAS,OACR,QACA,OACkB;CAClB,OAAO;EAAE;EAAQ,MAAM;GAAE,QAAQ;GAAW;EAAM;CAAE;AACrD"}
@@ -1,3 +1,50 @@
1
1
  import { t as Subscriber } from "../Subscriber-Bpp02cGr.cjs";
2
2
  import { t as SubscriberBuilder } from "../SubscriberBuilder-g3fAVWgs.cjs";
3
- export { Subscriber, SubscriberBuilder };
3
+ import { EnvironmentParser } from "@geekmidas/envkit";
4
+ //#region src/subscribers/SnsPushSubscriberAdaptor.d.ts
5
+ interface SnsPushOptions {
6
+ /** The topic this subscriber is subscribed to. Anything else is refused. */
7
+ topicArn: string;
8
+ /**
9
+ * Verify each message's signature. Off only against an emulator, which
10
+ * signs nothing — decided by the connection string's endpoint, never by
11
+ * anything the request says about itself.
12
+ */
13
+ verify: boolean;
14
+ /**
15
+ * The emulator's address, as this server was configured with it. An
16
+ * emulator names itself in `SubscribeURL` by the port it listens on inside
17
+ * its container, which is not the port published to the host — so against
18
+ * one, the confirmation is sent here instead. From configuration, never
19
+ * from the request.
20
+ */
21
+ emulatorEndpoint?: string;
22
+ }
23
+ /** What to answer SNS with. A non-2xx tells SNS to retry. */
24
+ interface SnsPushResponse {
25
+ status: 200 | 400 | 403 | 500;
26
+ body: {
27
+ status: string;
28
+ error?: string;
29
+ };
30
+ }
31
+ /**
32
+ * A topic subscriber run by SNS pushing to an HTTP endpoint, rather than by a
33
+ * poller.
34
+ *
35
+ * The notification is read as the Lambda event SNS would have invoked a
36
+ * function with, and run through the same parsing, services and handler as the
37
+ * Lambda adaptor — without its middy wrapper, which is Lambda's alone: a
38
+ * server serving this route has no reason to install `@middy/core`.
39
+ */
40
+ export declare class SnsPushSubscriberAdaptor {
41
+ private readonly envParser;
42
+ readonly subscriber: Subscriber<any, any, any, any, any, any, any>;
43
+ private readonly options;
44
+ constructor(envParser: EnvironmentParser<{}>, subscriber: Subscriber<any, any, any, any, any, any, any>, options: SnsPushOptions);
45
+ handle(body: unknown): Promise<SnsPushResponse>;
46
+ private notify;
47
+ }
48
+ //#endregion
49
+ export { type SnsPushOptions, type SnsPushResponse, Subscriber, SubscriberBuilder };
50
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/subscribers/SnsPushSubscriberAdaptor.ts"],"mappings":";;;;UAgBiB;;EAEhB;;;;;;EAMA;;;;;;;;EAQA;;;UAIgB;EAChB;EACA;IAAQ;IAAgB;;;;;;;;;;;;qBAYZ;mBAEM;WACR,YAAY;mBACJ;EAHlB,YACkB,WAAW,uBACnB,YAAY,+CACJ,SAAS;EAGrB,OAAO,gBAAgB,QAAQ;UAuDvB"}
@@ -1,3 +1,50 @@
1
1
  import { t as Subscriber } from "../Subscriber-CtN9R48-.mjs";
2
2
  import { t as SubscriberBuilder } from "../SubscriberBuilder-CuCMFpYW.mjs";
3
- export { Subscriber, SubscriberBuilder };
3
+ import { EnvironmentParser } from "@geekmidas/envkit";
4
+ //#region src/subscribers/SnsPushSubscriberAdaptor.d.ts
5
+ interface SnsPushOptions {
6
+ /** The topic this subscriber is subscribed to. Anything else is refused. */
7
+ topicArn: string;
8
+ /**
9
+ * Verify each message's signature. Off only against an emulator, which
10
+ * signs nothing — decided by the connection string's endpoint, never by
11
+ * anything the request says about itself.
12
+ */
13
+ verify: boolean;
14
+ /**
15
+ * The emulator's address, as this server was configured with it. An
16
+ * emulator names itself in `SubscribeURL` by the port it listens on inside
17
+ * its container, which is not the port published to the host — so against
18
+ * one, the confirmation is sent here instead. From configuration, never
19
+ * from the request.
20
+ */
21
+ emulatorEndpoint?: string;
22
+ }
23
+ /** What to answer SNS with. A non-2xx tells SNS to retry. */
24
+ interface SnsPushResponse {
25
+ status: 200 | 400 | 403 | 500;
26
+ body: {
27
+ status: string;
28
+ error?: string;
29
+ };
30
+ }
31
+ /**
32
+ * A topic subscriber run by SNS pushing to an HTTP endpoint, rather than by a
33
+ * poller.
34
+ *
35
+ * The notification is read as the Lambda event SNS would have invoked a
36
+ * function with, and run through the same parsing, services and handler as the
37
+ * Lambda adaptor — without its middy wrapper, which is Lambda's alone: a
38
+ * server serving this route has no reason to install `@middy/core`.
39
+ */
40
+ export declare class SnsPushSubscriberAdaptor {
41
+ private readonly envParser;
42
+ readonly subscriber: Subscriber<any, any, any, any, any, any, any>;
43
+ private readonly options;
44
+ constructor(envParser: EnvironmentParser<{}>, subscriber: Subscriber<any, any, any, any, any, any, any>, options: SnsPushOptions);
45
+ handle(body: unknown): Promise<SnsPushResponse>;
46
+ private notify;
47
+ }
48
+ //#endregion
49
+ export { type SnsPushOptions, type SnsPushResponse, Subscriber, SubscriberBuilder };
50
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/subscribers/SnsPushSubscriberAdaptor.ts"],"mappings":";;;;UAgBiB;;EAEhB;;;;;;EAMA;;;;;;;;EAQA;;;UAIgB;EAChB;EACA;IAAQ;IAAgB;;;;;;;;;;;;qBAYZ;mBAEM;WACR,YAAY;mBACJ;EAHlB,YACkB,WAAW,uBACnB,YAAY,+CACJ,SAAS;EAGrB,OAAO,gBAAgB,QAAQ;UAuDvB"}
@@ -1,2 +1,108 @@
1
1
  import { n as Subscriber, t as SubscriberBuilder } from "../SubscriberBuilder-DMFk_Ap1.mjs";
2
- export { Subscriber, SubscriberBuilder };
2
+ import { n as subscribedEvents, r as subscriberContext, t as runSubscriber } from "../runSubscriber-BYEY_bfA.mjs";
3
+ import { wrapError } from "@geekmidas/errors";
4
+ import { runWithRequestContext } from "@geekmidas/services";
5
+ import { confirmSnsSubscription, toSnsEvent, verifySnsMessage } from "@geekmidas/events/sns";
6
+ //#region src/subscribers/SnsPushSubscriberAdaptor.ts
7
+ /**
8
+ * A topic subscriber run by SNS pushing to an HTTP endpoint, rather than by a
9
+ * poller.
10
+ *
11
+ * The notification is read as the Lambda event SNS would have invoked a
12
+ * function with, and run through the same parsing, services and handler as the
13
+ * Lambda adaptor — without its middy wrapper, which is Lambda's alone: a
14
+ * server serving this route has no reason to install `@middy/core`.
15
+ */
16
+ var SnsPushSubscriberAdaptor = class {
17
+ envParser;
18
+ subscriber;
19
+ options;
20
+ constructor(envParser, subscriber, options) {
21
+ this.envParser = envParser;
22
+ this.subscriber = subscriber;
23
+ this.options = options;
24
+ }
25
+ async handle(body) {
26
+ const message = body;
27
+ if (typeof message?.Type !== "string" || !message.TopicArn) return refuse(400, "not an SNS message");
28
+ if (message.TopicArn !== this.options.topicArn) return refuse(403, `not subscribed to ${message.TopicArn}`);
29
+ if (this.options.verify) try {
30
+ await verifySnsMessage(message);
31
+ } catch (error) {
32
+ this.subscriber.logger.warn({
33
+ error,
34
+ topicArn: message.TopicArn
35
+ }, "Refused an SNS message that did not verify");
36
+ return refuse(403, error.name);
37
+ }
38
+ switch (message.Type) {
39
+ case "SubscriptionConfirmation":
40
+ await confirmSnsSubscription(this.options.emulatorEndpoint && message.SubscribeURL ? {
41
+ ...message,
42
+ SubscribeURL: throughEndpoint(message.SubscribeURL, this.options.emulatorEndpoint)
43
+ } : message);
44
+ this.subscriber.logger.info({ topicArn: message.TopicArn }, "Confirmed SNS subscription");
45
+ return {
46
+ status: 200,
47
+ body: { status: "confirmed" }
48
+ };
49
+ case "Notification": try {
50
+ await this.notify(message);
51
+ return {
52
+ status: 200,
53
+ body: { status: "ok" }
54
+ };
55
+ } catch (error) {
56
+ return refuse(500, error.name);
57
+ }
58
+ default: return {
59
+ status: 200,
60
+ body: { status: "ignored" }
61
+ };
62
+ }
63
+ }
64
+ async notify(message) {
65
+ const requestId = message.MessageId;
66
+ const logger = this.subscriber.logger.child({ requestId });
67
+ await runWithRequestContext({
68
+ logger,
69
+ requestId,
70
+ startTime: Date.now()
71
+ }, async () => {
72
+ try {
73
+ const { services, db } = await subscriberContext(this.subscriber, this.envParser);
74
+ const events = subscribedEvents(this.subscriber, toSnsEvent(message), logger);
75
+ await runSubscriber(this.subscriber, {
76
+ events,
77
+ services,
78
+ logger,
79
+ db
80
+ });
81
+ } catch (error) {
82
+ logger.error(error, "Error processing subscriber");
83
+ throw wrapError(error);
84
+ }
85
+ });
86
+ }
87
+ };
88
+ /** `url`, sent to `endpoint`'s origin instead of its own. */
89
+ function throughEndpoint(url, endpoint) {
90
+ const target = new URL(url);
91
+ const origin = new URL(endpoint);
92
+ target.protocol = origin.protocol;
93
+ target.host = origin.host;
94
+ return target.toString();
95
+ }
96
+ function refuse(status, error) {
97
+ return {
98
+ status,
99
+ body: {
100
+ status: "refused",
101
+ error
102
+ }
103
+ };
104
+ }
105
+ //#endregion
106
+ export { SnsPushSubscriberAdaptor, Subscriber, SubscriberBuilder };
107
+
108
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/subscribers/SnsPushSubscriberAdaptor.ts"],"sourcesContent":["import type { EnvironmentParser } from '@geekmidas/envkit';\nimport { wrapError } from '@geekmidas/errors';\nimport {\n\tconfirmSnsSubscription,\n\ttype SnsHttpMessage,\n\ttoSnsEvent,\n\tverifySnsMessage,\n} from '@geekmidas/events/sns';\nimport { runWithRequestContext } from '@geekmidas/services';\nimport {\n\trunSubscriber,\n\tsubscribedEvents,\n\tsubscriberContext,\n} from './runSubscriber';\nimport type { Subscriber } from './Subscriber';\n\nexport interface SnsPushOptions {\n\t/** The topic this subscriber is subscribed to. Anything else is refused. */\n\ttopicArn: string;\n\t/**\n\t * Verify each message's signature. Off only against an emulator, which\n\t * signs nothing — decided by the connection string's endpoint, never by\n\t * anything the request says about itself.\n\t */\n\tverify: boolean;\n\t/**\n\t * The emulator's address, as this server was configured with it. An\n\t * emulator names itself in `SubscribeURL` by the port it listens on inside\n\t * its container, which is not the port published to the host — so against\n\t * one, the confirmation is sent here instead. From configuration, never\n\t * from the request.\n\t */\n\temulatorEndpoint?: string;\n}\n\n/** What to answer SNS with. A non-2xx tells SNS to retry. */\nexport interface SnsPushResponse {\n\tstatus: 200 | 400 | 403 | 500;\n\tbody: { status: string; error?: string };\n}\n\n/**\n * A topic subscriber run by SNS pushing to an HTTP endpoint, rather than by a\n * poller.\n *\n * The notification is read as the Lambda event SNS would have invoked a\n * function with, and run through the same parsing, services and handler as the\n * Lambda adaptor — without its middy wrapper, which is Lambda's alone: a\n * server serving this route has no reason to install `@middy/core`.\n */\nexport class SnsPushSubscriberAdaptor {\n\tconstructor(\n\t\tprivate readonly envParser: EnvironmentParser<{}>,\n\t\treadonly subscriber: Subscriber<any, any, any, any, any, any, any>,\n\t\tprivate readonly options: SnsPushOptions,\n\t) {}\n\n\tasync handle(body: unknown): Promise<SnsPushResponse> {\n\t\tconst message = body as SnsHttpMessage;\n\t\tif (typeof message?.Type !== 'string' || !message.TopicArn) {\n\t\t\treturn refuse(400, 'not an SNS message');\n\t\t}\n\t\t// Checked before the signature: a genuine message for another topic is\n\t\t// still not this subscriber's to confirm or to handle.\n\t\tif (message.TopicArn !== this.options.topicArn) {\n\t\t\treturn refuse(403, `not subscribed to ${message.TopicArn}`);\n\t\t}\n\n\t\tif (this.options.verify) {\n\t\t\ttry {\n\t\t\t\tawait verifySnsMessage(message);\n\t\t\t} catch (error) {\n\t\t\t\tthis.subscriber.logger.warn(\n\t\t\t\t\t{ error, topicArn: message.TopicArn },\n\t\t\t\t\t'Refused an SNS message that did not verify',\n\t\t\t\t);\n\t\t\t\treturn refuse(403, (error as Error).name);\n\t\t\t}\n\t\t}\n\n\t\tswitch (message.Type) {\n\t\t\tcase 'SubscriptionConfirmation':\n\t\t\t\tawait confirmSnsSubscription(\n\t\t\t\t\tthis.options.emulatorEndpoint && message.SubscribeURL\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t...message,\n\t\t\t\t\t\t\t\tSubscribeURL: throughEndpoint(\n\t\t\t\t\t\t\t\t\tmessage.SubscribeURL,\n\t\t\t\t\t\t\t\t\tthis.options.emulatorEndpoint,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: message,\n\t\t\t\t);\n\t\t\t\tthis.subscriber.logger.info(\n\t\t\t\t\t{ topicArn: message.TopicArn },\n\t\t\t\t\t'Confirmed SNS subscription',\n\t\t\t\t);\n\t\t\t\treturn { status: 200, body: { status: 'confirmed' } };\n\t\t\tcase 'Notification':\n\t\t\t\ttry {\n\t\t\t\t\tawait this.notify(message);\n\t\t\t\t\treturn { status: 200, body: { status: 'ok' } };\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Already logged. A 500 makes SNS retry, which is the point of\n\t\t\t\t\t// answering at all.\n\t\t\t\t\treturn refuse(500, (error as Error).name);\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn { status: 200, body: { status: 'ignored' } };\n\t\t}\n\t}\n\n\tprivate async notify(message: SnsHttpMessage): Promise<void> {\n\t\tconst requestId = message.MessageId;\n\t\tconst logger = this.subscriber.logger.child({ requestId });\n\n\t\tawait runWithRequestContext(\n\t\t\t{ logger, requestId, startTime: Date.now() },\n\t\t\tasync () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst { services, db } = await subscriberContext(\n\t\t\t\t\t\tthis.subscriber,\n\t\t\t\t\t\tthis.envParser,\n\t\t\t\t\t);\n\t\t\t\t\tconst events = subscribedEvents(\n\t\t\t\t\t\tthis.subscriber,\n\t\t\t\t\t\ttoSnsEvent(message),\n\t\t\t\t\t\tlogger,\n\t\t\t\t\t);\n\t\t\t\t\tawait runSubscriber(this.subscriber, {\n\t\t\t\t\t\tevents,\n\t\t\t\t\t\tservices,\n\t\t\t\t\t\tlogger,\n\t\t\t\t\t\tdb,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(error as object, 'Error processing subscriber');\n\t\t\t\t\tthrow wrapError(error);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\t}\n}\n\n/** `url`, sent to `endpoint`'s origin instead of its own. */\nfunction throughEndpoint(url: string, endpoint: string): string {\n\tconst target = new URL(url);\n\tconst origin = new URL(endpoint);\n\ttarget.protocol = origin.protocol;\n\ttarget.host = origin.host;\n\treturn target.toString();\n}\n\nfunction refuse(\n\tstatus: SnsPushResponse['status'],\n\terror: string,\n): SnsPushResponse {\n\treturn { status, body: { status: 'refused', error } };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAkDA,IAAa,2BAAb,MAAsC;CAEnB;CACR;CACQ;CAHlB,YACC,WACA,YACA,SACC;EAHgB,KAAA,YAAA;EACR,KAAA,aAAA;EACQ,KAAA,UAAA;CACf;CAEH,MAAM,OAAO,MAAyC;EACrD,MAAM,UAAU;EAChB,IAAI,OAAO,SAAS,SAAS,YAAY,CAAC,QAAQ,UACjD,OAAO,OAAO,KAAK,oBAAoB;EAIxC,IAAI,QAAQ,aAAa,KAAK,QAAQ,UACrC,OAAO,OAAO,KAAK,qBAAqB,QAAQ,UAAU;EAG3D,IAAI,KAAK,QAAQ,QAChB,IAAI;GACH,MAAM,iBAAiB,OAAO;EAC/B,SAAS,OAAO;GACf,KAAK,WAAW,OAAO,KACtB;IAAE;IAAO,UAAU,QAAQ;GAAS,GACpC,4CACD;GACA,OAAO,OAAO,KAAM,MAAgB,IAAI;EACzC;EAGD,QAAQ,QAAQ,MAAhB;GACC,KAAK;IACJ,MAAM,uBACL,KAAK,QAAQ,oBAAoB,QAAQ,eACtC;KACA,GAAG;KACH,cAAc,gBACb,QAAQ,cACR,KAAK,QAAQ,gBACd;IACD,IACC,OACJ;IACA,KAAK,WAAW,OAAO,KACtB,EAAE,UAAU,QAAQ,SAAS,GAC7B,4BACD;IACA,OAAO;KAAE,QAAQ;KAAK,MAAM,EAAE,QAAQ,YAAY;IAAE;GACrD,KAAK,gBACJ,IAAI;IACH,MAAM,KAAK,OAAO,OAAO;IACzB,OAAO;KAAE,QAAQ;KAAK,MAAM,EAAE,QAAQ,KAAK;IAAE;GAC9C,SAAS,OAAO;IAGf,OAAO,OAAO,KAAM,MAAgB,IAAI;GACzC;GACD,SACC,OAAO;IAAE,QAAQ;IAAK,MAAM,EAAE,QAAQ,UAAU;GAAE;EACpD;CACD;CAEA,MAAc,OAAO,SAAwC;EAC5D,MAAM,YAAY,QAAQ;EAC1B,MAAM,SAAS,KAAK,WAAW,OAAO,MAAM,EAAE,UAAU,CAAC;EAEzD,MAAM,sBACL;GAAE;GAAQ;GAAW,WAAW,KAAK,IAAI;EAAE,GAC3C,YAAY;GACX,IAAI;IACH,MAAM,EAAE,UAAU,OAAO,MAAM,kBAC9B,KAAK,YACL,KAAK,SACN;IACA,MAAM,SAAS,iBACd,KAAK,YACL,WAAW,OAAO,GAClB,MACD;IACA,MAAM,cAAc,KAAK,YAAY;KACpC;KACA;KACA;KACA;IACD,CAAC;GACF,SAAS,OAAO;IACf,OAAO,MAAM,OAAiB,6BAA6B;IAC3D,MAAM,UAAU,KAAK;GACtB;EACD,CACD;CACD;AACD;;AAGA,SAAS,gBAAgB,KAAa,UAA0B;CAC/D,MAAM,SAAS,IAAI,IAAI,GAAG;CAC1B,MAAM,SAAS,IAAI,IAAI,QAAQ;CAC/B,OAAO,WAAW,OAAO;CACzB,OAAO,OAAO,OAAO;CACrB,OAAO,OAAO,SAAS;AACxB;AAEA,SAAS,OACR,QACA,OACkB;CAClB,OAAO;EAAE;EAAQ,MAAM;GAAE,QAAQ;GAAW;EAAM;CAAE;AACrD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekmidas/constructs",
3
- "version": "10.0.0-alpha.52",
3
+ "version": "10.0.0-alpha.53",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -276,13 +276,13 @@
276
276
  "lodash.uniqby": "~4.7.0",
277
277
  "openapi-types": "~12.1.3",
278
278
  "qs": "~6.16.0",
279
- "@geekmidas/envkit": "^10.0.0-alpha.52",
280
- "@geekmidas/errors": "^10.0.0-alpha.52",
281
- "@geekmidas/events": "^10.0.0-alpha.52",
282
- "@geekmidas/logger": "^10.0.0-alpha.52",
283
- "@geekmidas/manifest": "^10.0.0-alpha.52",
284
- "@geekmidas/schema": "^10.0.0-alpha.52",
285
- "@geekmidas/services": "^10.0.0-alpha.52"
279
+ "@geekmidas/envkit": "^10.0.0-alpha.53",
280
+ "@geekmidas/errors": "^10.0.0-alpha.53",
281
+ "@geekmidas/events": "^10.0.0-alpha.53",
282
+ "@geekmidas/logger": "^10.0.0-alpha.53",
283
+ "@geekmidas/manifest": "^10.0.0-alpha.53",
284
+ "@geekmidas/schema": "^10.0.0-alpha.53",
285
+ "@geekmidas/services": "^10.0.0-alpha.53"
286
286
  },
287
287
  "devDependencies": {
288
288
  "@aws-sdk/client-kms": "~3.1136.0",
@@ -299,20 +299,20 @@
299
299
  "msw": "~2.15.0",
300
300
  "pg": "~8.23.0",
301
301
  "zod": "~4.6.5",
302
- "@geekmidas/audit": "^10.0.0-alpha.52",
303
- "@geekmidas/auth": "10.0.0-alpha.52",
304
- "@geekmidas/cache": "^10.0.0-alpha.52",
305
- "@geekmidas/db": "^10.0.0-alpha.52",
306
- "@geekmidas/emailkit": "^10.0.0-alpha.52",
307
- "@geekmidas/envkit": "^10.0.0-alpha.52",
308
- "@geekmidas/errors": "^10.0.0-alpha.52",
309
- "@geekmidas/events": "^10.0.0-alpha.52",
310
- "@geekmidas/logger": "^10.0.0-alpha.52",
311
- "@geekmidas/rate-limit": "^10.0.0-alpha.52",
312
- "@geekmidas/schema": "^10.0.0-alpha.52",
313
- "@geekmidas/services": "^10.0.0-alpha.52",
314
- "@geekmidas/telescope": "10.0.0-alpha.52",
315
- "@geekmidas/testkit": "^10.0.0-alpha.52"
302
+ "@geekmidas/audit": "^10.0.0-alpha.53",
303
+ "@geekmidas/auth": "10.0.0-alpha.53",
304
+ "@geekmidas/cache": "^10.0.0-alpha.53",
305
+ "@geekmidas/db": "^10.0.0-alpha.53",
306
+ "@geekmidas/emailkit": "^10.0.0-alpha.53",
307
+ "@geekmidas/envkit": "^10.0.0-alpha.53",
308
+ "@geekmidas/errors": "^10.0.0-alpha.53",
309
+ "@geekmidas/events": "^10.0.0-alpha.53",
310
+ "@geekmidas/logger": "^10.0.0-alpha.53",
311
+ "@geekmidas/rate-limit": "^10.0.0-alpha.53",
312
+ "@geekmidas/schema": "^10.0.0-alpha.53",
313
+ "@geekmidas/services": "^10.0.0-alpha.53",
314
+ "@geekmidas/telescope": "10.0.0-alpha.53",
315
+ "@geekmidas/testkit": "^10.0.0-alpha.53"
316
316
  },
317
317
  "peerDependencies": {
318
318
  "@aws-sdk/client-kms": ">=3.1136.0",
@@ -323,15 +323,15 @@
323
323
  "kysely": "~0.29.6",
324
324
  "msw": ">=2.15.0",
325
325
  "pg": ">=8.23.0",
326
- "@geekmidas/audit": "^10.0.0-alpha.52",
327
- "@geekmidas/auth": "10.0.0-alpha.52",
328
- "@geekmidas/cache": "^10.0.0-alpha.52",
329
- "@geekmidas/db": "^10.0.0-alpha.52",
330
- "@geekmidas/emailkit": "^10.0.0-alpha.52",
331
- "@geekmidas/rate-limit": "^10.0.0-alpha.52",
332
- "@geekmidas/storage": "^10.0.0-alpha.52",
333
- "@geekmidas/telescope": "10.0.0-alpha.52",
334
- "@geekmidas/testkit": "^10.0.0-alpha.52"
326
+ "@geekmidas/audit": "^10.0.0-alpha.53",
327
+ "@geekmidas/auth": "10.0.0-alpha.53",
328
+ "@geekmidas/cache": "^10.0.0-alpha.53",
329
+ "@geekmidas/db": "^10.0.0-alpha.53",
330
+ "@geekmidas/emailkit": "^10.0.0-alpha.53",
331
+ "@geekmidas/rate-limit": "^10.0.0-alpha.53",
332
+ "@geekmidas/storage": "^10.0.0-alpha.53",
333
+ "@geekmidas/telescope": "10.0.0-alpha.53",
334
+ "@geekmidas/testkit": "^10.0.0-alpha.53"
335
335
  },
336
336
  "peerDependenciesMeta": {
337
337
  "@aws-sdk/client-kms": {