@siglo/notifications 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +478 -2
  3. package/dist/approvals.d.ts +38 -0
  4. package/dist/approvals.d.ts.map +1 -0
  5. package/dist/approvals.js +111 -0
  6. package/dist/approvals.js.map +1 -0
  7. package/dist/callbacks.d.ts +14 -0
  8. package/dist/callbacks.d.ts.map +1 -0
  9. package/dist/callbacks.js +144 -0
  10. package/dist/callbacks.js.map +1 -0
  11. package/dist/dispatch.d.ts +26 -0
  12. package/dist/dispatch.d.ts.map +1 -0
  13. package/dist/dispatch.js +42 -0
  14. package/dist/dispatch.js.map +1 -0
  15. package/dist/egress.d.ts +8 -0
  16. package/dist/egress.d.ts.map +1 -0
  17. package/dist/egress.js +96 -0
  18. package/dist/egress.js.map +1 -0
  19. package/dist/index.d.ts +11 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +27 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/monitor.d.ts +10 -0
  24. package/dist/monitor.d.ts.map +1 -0
  25. package/dist/monitor.js +20 -0
  26. package/dist/monitor.js.map +1 -0
  27. package/dist/registry.d.ts +5 -0
  28. package/dist/registry.d.ts.map +1 -0
  29. package/dist/registry.js +15 -0
  30. package/dist/registry.js.map +1 -0
  31. package/dist/sms.d.ts +28 -0
  32. package/dist/sms.d.ts.map +1 -0
  33. package/dist/sms.js +43 -0
  34. package/dist/sms.js.map +1 -0
  35. package/dist/steps.d.ts +7 -0
  36. package/dist/steps.d.ts.map +1 -0
  37. package/dist/steps.js +131 -0
  38. package/dist/steps.js.map +1 -0
  39. package/dist/testing/index.d.ts +18 -0
  40. package/dist/testing/index.d.ts.map +1 -0
  41. package/dist/testing/index.js +19 -0
  42. package/dist/testing/index.js.map +1 -0
  43. package/dist/testing.d.ts +18 -0
  44. package/dist/testing.d.ts.map +1 -0
  45. package/dist/testing.js +19 -0
  46. package/dist/testing.js.map +1 -0
  47. package/dist/tokens.d.ts +24 -0
  48. package/dist/tokens.d.ts.map +1 -0
  49. package/dist/tokens.js +48 -0
  50. package/dist/tokens.js.map +1 -0
  51. package/dist/transports.d.ts +120 -0
  52. package/dist/transports.d.ts.map +1 -0
  53. package/dist/transports.js +172 -0
  54. package/dist/transports.js.map +1 -0
  55. package/dist/types.d.ts +106 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +3 -0
  58. package/dist/types.js.map +1 -0
  59. package/package.json +64 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callbacks.d.ts","sourceRoot":"","sources":["../src/callbacks.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAGjD,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AACD,wBAAsB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,4BAA4B,CAAC,CA+BtI;AACD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,4BAA4B,GAAG,MAAM,CAEvF;AAwBD,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,sBAAsB,SAC9D,GAAG,OAAO,GAAG,KAAG,OAAO,CAAC,IAAI,CAAC,CAUjD;AACD,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,sBAAsB,SAC3D,GAAG,SAAS,GAAG,KAAG,OAAO,CAAC,IAAI,CAAC,CAUnD;AACD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,sBAAsB,OAC1D,GAAG,KAAG,OAAO,CAAC,QAAQ,CAAC,CASzC"}
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleNotificationCallback = handleNotificationCallback;
4
+ exports.renderApprovalConfirmation = renderApprovalConfirmation;
5
+ exports.createNotificationExpressMiddleware = createNotificationExpressMiddleware;
6
+ exports.createNotificationFastifyHandler = createNotificationFastifyHandler;
7
+ exports.createNotificationHonoHandler = createNotificationHonoHandler;
8
+ const core_1 = require("@siglo/core");
9
+ const approvals_1 = require("./approvals");
10
+ const tokens_1 = require("./tokens");
11
+ const transports_1 = require("./transports");
12
+ async function handleNotificationCallback(token, options) {
13
+ let verified;
14
+ const report = (approvalState) => {
15
+ // Never attribute an unverified token to a workflow or accept caller ambient scope.
16
+ if (!verified?.inspection)
17
+ return;
18
+ core_1.stepInspectionStorage.run({ ...verified.inspection, stackId: verified.stackId, monitor: options.monitor }, () => (0, core_1.recordInspection)({ version: 1, kind: 'notification', approval: true,
19
+ outcome: approvalState === 'approved' || approvalState === 'rejected' ? 'success' : 'failure',
20
+ approvalState, approvalExpiresAt: verified.expiresAt }));
21
+ };
22
+ try {
23
+ const p = await (0, tokens_1.verifyActionToken)(token, options.signingSecret, { toleranceSeconds: options.toleranceSeconds });
24
+ verified = p;
25
+ if (!options.authorize && !options.allowBearerApproval) {
26
+ report('forbidden');
27
+ return { status: 403, body: { message: 'Authenticated approval required' } };
28
+ }
29
+ return await (0, approvals_1.getApprovalRevocationStore)().withApprovalLock(p.correlationKey, async () => {
30
+ if (options.authorize && !await options.authorize(p)) {
31
+ report('forbidden');
32
+ return { status: 403, body: { message: 'Approval forbidden' } };
33
+ }
34
+ if (await (0, approvals_1.getApprovalRevocationStore)().isRevoked(p.correlationKey)) {
35
+ report('cancelled');
36
+ return { status: 409, body: { message: 'Approval cancelled' } };
37
+ }
38
+ const adapter = (0, core_1.getStorageAdapter)();
39
+ const record = adapter?.getWaitRecord ? await adapter.getWaitRecord(p.correlationKey) : core_1.defaultDurableManager.getWaiting(p.correlationKey);
40
+ if (record && record.stackId !== p.stackId)
41
+ throw new core_1.ValidationException([{ field: 'token', message: 'Approval workflow mismatch' }]);
42
+ await (0, core_1.resumeWorkflow)(options.workflow, p.correlationKey, { approved: p.approved, event: { type: p.expectedEvent }, expectedEvent: p.expectedEvent });
43
+ report(p.approved ? 'approved' : 'rejected');
44
+ return { status: 200, body: { message: 'Approval recorded' }, redirect: options.onSuccessRedirect };
45
+ });
46
+ }
47
+ catch (e) {
48
+ const expired = e instanceof core_1.ExpiredWaitException || (e instanceof core_1.ValidationException && /expired/i.test(e.message));
49
+ const conflict = e instanceof core_1.WorkflowAlreadyResumedException || e instanceof core_1.DuplicateEventException;
50
+ const invalid = e instanceof core_1.ValidationException;
51
+ report(conflict ? 'conflict' : expired ? 'expired' : 'failed');
52
+ return { status: conflict ? 409 : expired ? 410 : invalid ? 400 : 500, body: { message: conflict ? 'Approval already resolved' : expired ? 'Approval expired' : invalid ? 'Invalid approval' : 'Unable to process approval' }, redirect: expired ? options.onExpiredRedirect : options.onErrorRedirect };
53
+ }
54
+ }
55
+ function renderApprovalConfirmation(result) {
56
+ return `<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${(0, transports_1.escapeHtml)(result.body.message)}</title><main><h1>${(0, transports_1.escapeHtml)(result.body.message)}</h1><p>You may close this window.</p></main></html>`;
57
+ }
58
+ function headers(origin, options) {
59
+ return { 'Cache-Control': 'no-store', 'Referrer-Policy': 'no-referrer', 'X-Content-Type-Options': 'nosniff', 'Content-Security-Policy': "default-src 'none'; frame-ancestors 'none'; form-action 'self'; base-uri 'none'", ...(origin && options.allowedOrigins?.includes(origin) ? { 'Access-Control-Allow-Origin': origin, 'Vary': 'Origin', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' } : {}) };
60
+ }
61
+ function tokenFrom(query, body) {
62
+ const token = query?.token ?? body?.token;
63
+ return typeof token === 'string' ? token : '';
64
+ }
65
+ /** GET is a preview only. Mutation tokens are accepted exclusively from POST bodies. */
66
+ async function route(method, query, body, options, request, origin) {
67
+ if (method === 'GET' || method === 'HEAD') {
68
+ try {
69
+ const token = tokenFrom(query, undefined);
70
+ const p = await (0, tokens_1.verifyActionToken)(token, options.signingSecret, { toleranceSeconds: options.toleranceSeconds });
71
+ const message = p.approved ? 'Confirm approval' : 'Confirm rejection';
72
+ return { status: 200, body: { message }, html: `<!doctype html><html lang="en"><meta charset="utf-8"><title>${message}</title><main><h1>${message}</h1><form method="post" action="?"><input type="hidden" name="token" value="${(0, transports_1.escapeHtml)(token)}"><button type="submit">${message}</button></form></main></html>` };
73
+ }
74
+ catch {
75
+ return { status: 400, body: { message: 'Invalid approval' } };
76
+ }
77
+ }
78
+ if (method !== 'POST')
79
+ return { status: 405, body: { message: 'Method not allowed' } };
80
+ if (origin && options.allowedOrigins && !options.allowedOrigins.includes(origin))
81
+ return { status: 403, body: { message: 'Origin forbidden' } };
82
+ // Authentication/CSRF middleware can inspect the original framework request.
83
+ const authorize = options.authorize ? (payload) => options.authorize(payload, request) : undefined;
84
+ return handleNotificationCallback(tokenFrom(undefined, body), { ...options, authorize });
85
+ }
86
+ function createNotificationExpressMiddleware(options) {
87
+ return async (req, res) => {
88
+ for (const [key, value] of Object.entries(headers(req.headers?.origin, options)))
89
+ res.setHeader(key, value);
90
+ res.setHeader('Allow', 'GET, HEAD, POST, OPTIONS');
91
+ if (req.method === 'OPTIONS') {
92
+ res.status(204).end();
93
+ return;
94
+ }
95
+ const r = await route(req.method, req.query, req.body, options, req, req.headers?.origin);
96
+ if (req.method === 'HEAD') {
97
+ res.status(r.status).end();
98
+ return;
99
+ }
100
+ if (r.redirect)
101
+ res.redirect(303, r.redirect);
102
+ else if (r.html || options.responseFormat === 'html')
103
+ res.status(r.status).type('html').send(r.html ?? renderApprovalConfirmation(r));
104
+ else
105
+ res.status(r.status).json(r.body);
106
+ };
107
+ }
108
+ function createNotificationFastifyHandler(options) {
109
+ return async (req, reply) => {
110
+ for (const [key, value] of Object.entries(headers(req.headers?.origin, options)))
111
+ reply.header(key, value);
112
+ reply.header('Allow', 'GET, HEAD, POST, OPTIONS');
113
+ if (req.method === 'OPTIONS') {
114
+ reply.code(204).send();
115
+ return;
116
+ }
117
+ const r = await route(req.method, req.query, req.body, options, req, req.headers?.origin);
118
+ if (req.method === 'HEAD') {
119
+ reply.code(r.status).send();
120
+ return;
121
+ }
122
+ if (r.redirect)
123
+ reply.code(303).redirect(r.redirect);
124
+ else if (r.html || options.responseFormat === 'html')
125
+ reply.code(r.status).type('text/html').send(r.html ?? renderApprovalConfirmation(r));
126
+ else
127
+ reply.code(r.status).send(r.body);
128
+ };
129
+ }
130
+ function createNotificationHonoHandler(options) {
131
+ return async (c) => {
132
+ for (const [key, value] of Object.entries(headers(c.req.header('origin'), options)))
133
+ c.header(key, value);
134
+ c.header('Allow', 'GET, HEAD, POST, OPTIONS');
135
+ if (c.req.method === 'OPTIONS')
136
+ return c.body(null, 204);
137
+ const body = c.req.method === 'POST' ? (c.req.header('content-type')?.includes('application/json') ? await c.req.json() : await c.req.parseBody()) : undefined;
138
+ const r = await route(c.req.method, { token: c.req.query('token') }, body, options, c, c.req.header('origin'));
139
+ if (c.req.method === 'HEAD')
140
+ return c.body(null, r.status);
141
+ return r.redirect ? c.redirect(r.redirect, 303) : r.html || options.responseFormat === 'html' ? c.html(r.html ?? renderApprovalConfirmation(r), r.status) : c.json(r.body, r.status);
142
+ };
143
+ }
144
+ //# sourceMappingURL=callbacks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callbacks.js","sourceRoot":"","sources":["../src/callbacks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { ResolvedNotificationMessage } from './types';
2
+ export interface DispatchIntent {
3
+ message: ResolvedNotificationMessage;
4
+ extra?: Record<string, unknown>;
5
+ }
6
+ /** Retain intents for at least the entire retry window. Never regenerate tokens on a retry. */
7
+ export interface NotificationDispatchStore {
8
+ prepare(key: string, create: () => Promise<DispatchIntent>): Promise<DispatchIntent>;
9
+ }
10
+ export declare class InMemoryNotificationDispatchStore implements NotificationDispatchStore {
11
+ private intents;
12
+ prepare(key: string, create: () => Promise<DispatchIntent>): Promise<DispatchIntent>;
13
+ }
14
+ export declare class PostgresNotificationDispatchStore implements NotificationDispatchStore {
15
+ private client;
16
+ constructor(client: {
17
+ query(sql: string, values?: any[]): Promise<{
18
+ rows: any[];
19
+ }>;
20
+ });
21
+ initialize(): Promise<void>;
22
+ prepare(key: string, create: () => Promise<DispatchIntent>): Promise<DispatchIntent>;
23
+ }
24
+ export declare function configureNotificationDispatchStore(value: NotificationDispatchStore): void;
25
+ export declare function getNotificationDispatchStore(): NotificationDispatchStore;
26
+ //# sourceMappingURL=dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,SAAS,CAAC;AAC3D,MAAM,WAAW,cAAc;IAAG,OAAO,EAAE,2BAA2B,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE;AACzG,+FAA+F;AAC/F,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACtF;AACD,qBAAa,iCAAkC,YAAW,yBAAyB;IACjF,OAAO,CAAC,OAAO,CAA8C;IACvD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC;CAQ3F;AACD,qBAAa,iCAAkC,YAAW,yBAAyB;IACrE,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE;QAAE,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;YAAE,IAAI,EAAE,GAAG,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE;IACtF,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAG3B,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC;CAQ3F;AAED,wBAAgB,kCAAkC,CAAC,KAAK,EAAE,yBAAyB,GAAG,IAAI,CAAmB;AAC7G,wBAAgB,4BAA4B,IAAI,yBAAyB,CAAkB"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostgresNotificationDispatchStore = exports.InMemoryNotificationDispatchStore = void 0;
4
+ exports.configureNotificationDispatchStore = configureNotificationDispatchStore;
5
+ exports.getNotificationDispatchStore = getNotificationDispatchStore;
6
+ class InMemoryNotificationDispatchStore {
7
+ intents = new Map();
8
+ async prepare(key, create) {
9
+ let intent = this.intents.get(key);
10
+ if (!intent) {
11
+ intent = create();
12
+ this.intents.set(key, intent);
13
+ intent.catch(() => { if (this.intents.get(key) === intent)
14
+ this.intents.delete(key); });
15
+ }
16
+ return intent;
17
+ }
18
+ }
19
+ exports.InMemoryNotificationDispatchStore = InMemoryNotificationDispatchStore;
20
+ class PostgresNotificationDispatchStore {
21
+ client;
22
+ constructor(client) {
23
+ this.client = client;
24
+ }
25
+ async initialize() {
26
+ await this.client.query('CREATE TABLE IF NOT EXISTS siglo_notification_dispatches (dispatch_key TEXT PRIMARY KEY, intent JSONB NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW())');
27
+ }
28
+ async prepare(key, create) {
29
+ const existing = await this.client.query('SELECT intent FROM siglo_notification_dispatches WHERE dispatch_key = $1', [key]);
30
+ if (existing.rows.length)
31
+ return existing.rows[0].intent;
32
+ const intent = await create();
33
+ const result = await this.client.query(`INSERT INTO siglo_notification_dispatches (dispatch_key, intent) VALUES ($1, $2::jsonb)
34
+ ON CONFLICT (dispatch_key) DO UPDATE SET dispatch_key = EXCLUDED.dispatch_key RETURNING intent`, [key, JSON.stringify(intent)]);
35
+ return result.rows[0].intent;
36
+ }
37
+ }
38
+ exports.PostgresNotificationDispatchStore = PostgresNotificationDispatchStore;
39
+ let store = new InMemoryNotificationDispatchStore();
40
+ function configureNotificationDispatchStore(value) { store = value; }
41
+ function getNotificationDispatchStore() { return store; }
42
+ //# sourceMappingURL=dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":";;;AAgCA,gFAA6G;AAC7G,oEAA2F;AA3B3F,MAAa,iCAAiC;IACpC,OAAO,GAAG,IAAI,GAAG,EAAmC,CAAC;IAC7D,KAAK,CAAC,OAAO,CAAC,GAAW,EAAE,MAAqC;QAC9D,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG,MAAM,EAAE,CAAC;YAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACjD,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,MAAM;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1F,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAVD,8EAUC;AACD,MAAa,iCAAiC;IACxB;IAApB,YAAoB,MAAwE;QAAxE,WAAM,GAAN,MAAM,CAAkE;IAAG,CAAC;IAChG,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gKAAgK,CAAC,CAAC;IAC5L,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,GAAW,EAAE,MAAqC;QAC9D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0EAA0E,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5H,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,MAAM,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;qGAC0D,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAClI,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/B,CAAC;CACF;AAbD,8EAaC;AACD,IAAI,KAAK,GAA8B,IAAI,iCAAiC,EAAE,CAAC;AAC/E,SAAgB,kCAAkC,CAAC,KAAgC,IAAU,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;AAC7G,SAAgB,4BAA4B,KAAgC,OAAO,KAAK,CAAC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { lookup } from 'node:dns';
2
+ /** Conservative public-address policy. Internal destinations require a trusted custom transport. */
3
+ export declare function isPublicNotificationAddress(address: string): boolean;
4
+ /** The lookup result returned here is the address used by the socket, not a preflight lookup. */
5
+ export declare const publicNotificationLookup: typeof lookup;
6
+ /** Native HTTPS preserves hostname certificate verification/SNI while pinning validated DNS results. */
7
+ export declare const publicNotificationFetch: typeof fetch;
8
+ //# sourceMappingURL=egress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"egress.d.ts","sourceRoot":"","sources":["../src/egress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,oGAAoG;AACpG,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAiBpE;AACD,iGAAiG;AACjG,eAAO,MAAM,wBAAwB,EAAE,OAAO,MAW3B,CAAC;AACpB,wGAAwG;AACxG,eAAO,MAAM,uBAAuB,EAkC9B,OAAO,KAAK,CAAC"}
package/dist/egress.js ADDED
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.publicNotificationFetch = exports.publicNotificationLookup = void 0;
4
+ exports.isPublicNotificationAddress = isPublicNotificationAddress;
5
+ const node_dns_1 = require("node:dns");
6
+ const node_net_1 = require("node:net");
7
+ const node_https_1 = require("node:https");
8
+ /** Conservative public-address policy. Internal destinations require a trusted custom transport. */
9
+ function isPublicNotificationAddress(address) {
10
+ const ip = address.replace(/^\[|\]$/g, '').toLowerCase();
11
+ if ((0, node_net_1.isIP)(ip) === 4) {
12
+ const [a, b, c] = ip.split('.').map(Number);
13
+ return !(a === 0 || a === 10 || a === 127 || a >= 224 ||
14
+ (a === 100 && b >= 64 && b <= 127) || (a === 169 && b === 254) ||
15
+ (a === 172 && b >= 16 && b <= 31) || (a === 192 && (b === 0 || b === 168 || (b === 88 && c === 99))) ||
16
+ (a === 198 && (b === 18 || b === 19 || (b === 51 && c === 100))) || (a === 203 && b === 0 && c === 113));
17
+ }
18
+ if ((0, node_net_1.isIP)(ip) === 6) {
19
+ // Accept global unicast only; reject mapped IPv4, loopback, ULA, link-local,
20
+ // multicast, transition/special-use space and documentation prefixes.
21
+ const normalized = new URL(`https://[${ip}]/`).hostname.slice(1, -1);
22
+ const [first, second] = normalized.split(':').map(value => parseInt(value || '0', 16));
23
+ return first >= 0x2000 && first < 0x3fff && first !== 0x2002 && !(first === 0x2001 && (second <= 0x1ff || second === 0xdb8));
24
+ }
25
+ return false;
26
+ }
27
+ /** The lookup result returned here is the address used by the socket, not a preflight lookup. */
28
+ exports.publicNotificationLookup = ((hostname, options, callback) => {
29
+ (0, node_dns_1.lookup)(hostname, { all: true, verbatim: true }, (error, addresses) => {
30
+ if (error) {
31
+ callback(error);
32
+ return;
33
+ }
34
+ if (!addresses.length || addresses.some(entry => !isPublicNotificationAddress(entry.address))) {
35
+ callback(new Error('Notification destination must resolve exclusively to public IP addresses'));
36
+ return;
37
+ }
38
+ const candidates = options?.family ? addresses.filter(entry => entry.family === options.family) : addresses;
39
+ if (!candidates.length) {
40
+ callback(new Error('No public address for requested family'));
41
+ return;
42
+ }
43
+ if (options?.all)
44
+ callback(null, candidates);
45
+ else
46
+ callback(null, candidates[0].address, candidates[0].family);
47
+ });
48
+ });
49
+ /** Native HTTPS preserves hostname certificate verification/SNI while pinning validated DNS results. */
50
+ exports.publicNotificationFetch = (async (input, init = {}) => {
51
+ const url = new URL(String(input));
52
+ if (url.protocol !== 'https:' || url.username || url.password)
53
+ throw new Error('Notification egress requires HTTPS without URL credentials');
54
+ const literal = url.hostname.replace(/^\[|\]$/g, '');
55
+ if ((0, node_net_1.isIP)(literal) && !isPublicNotificationAddress(literal))
56
+ throw new Error('Private notification destination forbidden');
57
+ return new Promise((resolve, reject) => {
58
+ const requestHeaders = {};
59
+ new Headers(init.headers).forEach((value, key) => { requestHeaders[key] = value; });
60
+ const req = (0, node_https_1.request)(url, {
61
+ method: init.method ?? 'POST', headers: requestHeaders,
62
+ lookup: exports.publicNotificationLookup, agent: false, signal: init.signal ?? undefined, timeout: 30000
63
+ }, response => {
64
+ if ((response.statusCode ?? 500) >= 300 && (response.statusCode ?? 500) < 400) {
65
+ response.destroy();
66
+ reject(new Error('Notification redirects are forbidden'));
67
+ return;
68
+ }
69
+ const chunks = [];
70
+ let bytes = 0;
71
+ response.on('data', chunk => {
72
+ bytes += chunk.length;
73
+ if (bytes > 1024 * 1024) {
74
+ response.destroy(new Error('Notification response too large'));
75
+ return;
76
+ }
77
+ chunks.push(Buffer.from(chunk));
78
+ });
79
+ response.on('error', reject);
80
+ response.on('end', () => {
81
+ const headers = new Headers();
82
+ for (const [key, value] of Object.entries(response.headers))
83
+ if (value !== undefined)
84
+ headers.set(key, Array.isArray(value) ? value.join(', ') : value);
85
+ const status = response.statusCode ?? 500;
86
+ resolve(new Response(status === 204 || status === 205 || status === 304 ? null : Buffer.concat(chunks), { status, headers }));
87
+ });
88
+ });
89
+ req.on('error', reject);
90
+ req.on('timeout', () => req.destroy(new Error('Notification request timed out')));
91
+ if (init.body)
92
+ req.write(init.body);
93
+ req.end();
94
+ });
95
+ });
96
+ //# sourceMappingURL=egress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"egress.js","sourceRoot":"","sources":["../src/egress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export * from './types';
2
+ export * from './registry';
3
+ export * from './tokens';
4
+ export * from './steps';
5
+ export * from './transports';
6
+ export * from './callbacks';
7
+ export * from './approvals';
8
+ export * from './sms';
9
+ export * from './monitor';
10
+ export * from './dispatch';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,OAAO,CAAC;AACtB,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types"), exports);
18
+ __exportStar(require("./registry"), exports);
19
+ __exportStar(require("./tokens"), exports);
20
+ __exportStar(require("./steps"), exports);
21
+ __exportStar(require("./transports"), exports);
22
+ __exportStar(require("./callbacks"), exports);
23
+ __exportStar(require("./approvals"), exports);
24
+ __exportStar(require("./sms"), exports);
25
+ __exportStar(require("./monitor"), exports);
26
+ __exportStar(require("./dispatch"), exports);
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,6CAA2B;AAC3B,2CAAyB;AACzB,0CAAwB;AACxB,+CAA6B;AAC7B,8CAA4B;AAC5B,8CAA4B;AAC5B,wCAAsB;AACtB,4CAA0B;AAC1B,6CAA2B"}
@@ -0,0 +1,10 @@
1
+ import { WorkflowEventEmitter, WorkflowExecutionEvent } from '@siglo/core';
2
+ /** A workflow monitor that masks configured event paths before any listener sees them.
3
+ * Patterns use event-relative paths, e.g. outputSummary.customers.*.contact.
4
+ */
5
+ export declare class NotificationMonitor extends WorkflowEventEmitter {
6
+ private readonly paths;
7
+ constructor(paths?: string[]);
8
+ emit(event: WorkflowExecutionEvent): void;
9
+ }
10
+ //# sourceMappingURL=monitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monitor.d.ts","sourceRoot":"","sources":["../src/monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAe,MAAM,aAAa,CAAC;AAGxF;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,oBAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,GAAE,MAAM,EAAO;IACxC,IAAI,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI;CAGnD"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotificationMonitor = void 0;
4
+ const core_1 = require("@siglo/core");
5
+ const crypto_1 = require("@siglo/crypto");
6
+ /** A workflow monitor that masks configured event paths before any listener sees them.
7
+ * Patterns use event-relative paths, e.g. outputSummary.customers.*.contact.
8
+ */
9
+ class NotificationMonitor extends core_1.WorkflowEventEmitter {
10
+ paths;
11
+ constructor(paths = []) {
12
+ super();
13
+ this.paths = paths;
14
+ }
15
+ emit(event) {
16
+ super.emit((0, core_1.redactEvent)((0, crypto_1.transformFields)(event, this.paths, () => '[REDACTED]')));
17
+ }
18
+ }
19
+ exports.NotificationMonitor = NotificationMonitor;
20
+ //# sourceMappingURL=monitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monitor.js","sourceRoot":"","sources":["../src/monitor.ts"],"names":[],"mappings":";;;AAAA,sCAAwF;AACxF,0CAAgD;AAEhD;;GAEG;AACH,MAAa,mBAAoB,SAAQ,2BAAoB;IAC9B;IAA7B,YAA6B,QAAkB,EAAE;QAAI,KAAK,EAAE,CAAC;QAAhC,UAAK,GAAL,KAAK,CAAe;IAAa,CAAC;IACtD,IAAI,CAAC,KAA6B;QACzC,KAAK,CAAC,IAAI,CAAC,IAAA,kBAAW,EAAC,IAAA,wBAAe,EAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC;CACF;AALD,kDAKC"}
@@ -0,0 +1,5 @@
1
+ import { NotificationChannel, NotificationTransport } from './types';
2
+ export declare function registerNotificationTransport(transport: NotificationTransport): void;
3
+ export declare function getNotificationTransport(channel: NotificationChannel): NotificationTransport;
4
+ export declare function clearNotificationTransports(): void;
5
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAErE,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,qBAAqB,GAAG,IAAI,CAAkD;AACvI,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,mBAAmB,GAAG,qBAAqB,CAI5F;AACD,wBAAgB,2BAA2B,IAAI,IAAI,CAAwB"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerNotificationTransport = registerNotificationTransport;
4
+ exports.getNotificationTransport = getNotificationTransport;
5
+ exports.clearNotificationTransports = clearNotificationTransports;
6
+ const transports = new Map();
7
+ function registerNotificationTransport(transport) { transports.set(transport.channel, transport); }
8
+ function getNotificationTransport(channel) {
9
+ const transport = transports.get(channel);
10
+ if (!transport)
11
+ throw new Error(`No notification transport registered for ${channel}`);
12
+ return transport;
13
+ }
14
+ function clearNotificationTransports() { transports.clear(); }
15
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":";;AAEA,sEAAuI;AACvI,4DAIC;AACD,kEAA2E;AAP3E,MAAM,UAAU,GAAG,IAAI,GAAG,EAA8C,CAAC;AACzE,SAAgB,6BAA6B,CAAC,SAAgC,IAAU,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;AACvI,SAAgB,wBAAwB,CAAC,OAA4B;IACnE,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,OAAO,EAAE,CAAC,CAAC;IACvF,OAAO,SAAS,CAAC;AACnB,CAAC;AACD,SAAgB,2BAA2B,KAAW,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC"}
package/dist/sms.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ export interface TwilioSmsReply {
2
+ messageId: string;
3
+ from: string;
4
+ to: string;
5
+ approved: boolean;
6
+ reference: string;
7
+ }
8
+ /** Verify form-encoded Twilio webhooks using the exact configured public URL.
9
+ * All original parameters must be supplied, including unknown future parameters.
10
+ * The caller must bind reference + sender to its pending request and atomically claim
11
+ * the wait before resumption. A signed SMS alone is not an approval authorization.
12
+ */
13
+ export declare function parseTwilioSmsReply(params: Record<string, string>, options: {
14
+ publicUrl: string;
15
+ authToken: string;
16
+ signature: string;
17
+ }): TwilioSmsReply;
18
+ /** Generate once and persist with the request, expected sender, destination and expiry. */
19
+ export declare function createSmsApprovalReference(prefix?: string): string;
20
+ export interface PendingSmsApproval {
21
+ reference: string;
22
+ from: string;
23
+ to: string;
24
+ expiresAt: number;
25
+ }
26
+ /** Validation only: the application must atomically consume its pending request before resuming. */
27
+ export declare function validateSmsApprovalReply(reply: TwilioSmsReply, pending: PendingSmsApproval, now?: number): void;
28
+ //# sourceMappingURL=sms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sms.d.ts","sourceRoot":"","sources":["../src/sms.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAUxJ;AAED,2FAA2F;AAC3F,wBAAgB,0BAA0B,CAAC,MAAM,SAAa,GAAG,MAAM,CAGtE;AACD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;CAChE;AACD,oGAAoG;AACpG,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,SAAa,GAAG,IAAI,CAKnH"}
package/dist/sms.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseTwilioSmsReply = parseTwilioSmsReply;
4
+ exports.createSmsApprovalReference = createSmsApprovalReference;
5
+ exports.validateSmsApprovalReply = validateSmsApprovalReply;
6
+ const node_crypto_1 = require("node:crypto");
7
+ const crypto_1 = require("@siglo/crypto");
8
+ const tokens_1 = require("./tokens");
9
+ /** Verify form-encoded Twilio webhooks using the exact configured public URL.
10
+ * All original parameters must be supplied, including unknown future parameters.
11
+ * The caller must bind reference + sender to its pending request and atomically claim
12
+ * the wait before resumption. A signed SMS alone is not an approval authorization.
13
+ */
14
+ function parseTwilioSmsReply(params, options) {
15
+ if (!options.authToken || !options.publicUrl.startsWith('https://'))
16
+ (0, tokens_1.invalidToken)('Invalid SMS webhook configuration');
17
+ if (Object.values(params).some(value => typeof value !== 'string'))
18
+ (0, tokens_1.invalidToken)('Invalid SMS form');
19
+ const signed = Object.keys(params).sort().reduce((value, key) => value + key + params[key], options.publicUrl);
20
+ const expected = (0, node_crypto_1.createHmac)('sha1', options.authToken).update(signed).digest('base64');
21
+ if (!(0, crypto_1.timingSafeCompare)(expected, options.signature, 'base64'))
22
+ (0, tokens_1.invalidToken)('Invalid SMS signature');
23
+ if (!/^SM[a-zA-Z0-9]+$/.test(params.MessageSid ?? '') || !/^\+[1-9]\d{6,14}$/.test(params.From ?? '') || !/^\+[1-9]\d{6,14}$/.test(params.To ?? ''))
24
+ (0, tokens_1.invalidToken)('Invalid SMS sender or message ID');
25
+ const match = /^(approve|reject)\s+([a-zA-Z0-9:_-]{1,256})$/i.exec((params.Body ?? '').trim());
26
+ if (!match)
27
+ (0, tokens_1.invalidToken)('Reply must contain APPROVE or REJECT and a request reference');
28
+ return { messageId: params.MessageSid, from: params.From, to: params.To, approved: match[1].toLowerCase() === 'approve', reference: match[2] };
29
+ }
30
+ /** Generate once and persist with the request, expected sender, destination and expiry. */
31
+ function createSmsApprovalReference(prefix = 'approval') {
32
+ if (!/^[a-zA-Z0-9:_-]{1,200}$/.test(prefix))
33
+ throw new Error('Invalid SMS approval reference prefix');
34
+ return `${prefix}:${(0, node_crypto_1.randomBytes)(16).toString('hex')}`;
35
+ }
36
+ /** Validation only: the application must atomically consume its pending request before resuming. */
37
+ function validateSmsApprovalReply(reply, pending, now = Date.now()) {
38
+ if (!Number.isFinite(pending.expiresAt) || pending.expiresAt <= now ||
39
+ !(0, crypto_1.timingSafeCompare)(reply.reference, pending.reference, 'utf8') || reply.from !== pending.from || reply.to !== pending.to) {
40
+ (0, tokens_1.invalidToken)('SMS reply does not match a pending approval');
41
+ }
42
+ }
43
+ //# sourceMappingURL=sms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sms.js","sourceRoot":"","sources":["../src/sms.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Step } from '@siglo/core';
2
+ import { SendNotificationOptions, InteractiveApprovalOptions, NotificationResult, ApprovalResult, NotificationTransport } from './types';
3
+ export declare function assertTransportPolicy(name: string, transport: NotificationTransport): void;
4
+ export declare function registerNotificationCompensationHandlers(): void;
5
+ export declare function sendNotificationStep<const N extends string, I = any>(name: N, options: SendNotificationOptions<I>): Step<I, NotificationResult, N>;
6
+ export declare function sendInteractiveApprovalStep<const N extends string, I = any>(name: N, options: InteractiveApprovalOptions<I>): Step<I, ApprovalResult, N>;
7
+ //# sourceMappingURL=steps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../src/steps.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAuP,MAAM,aAAa,CAAC;AAKxR,OAAO,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,kBAAkB,EAAwB,cAAc,EAAE,qBAAqB,EAA+B,MAAM,SAAS,CAAC;AAE5L,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,qBAAqB,GAAG,IAAI,CAE1F;AASD,wBAAgB,wCAAwC,IAAI,IAAI,CAI/D;AAGD,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAElJ;AAyED,wBAAgB,2BAA2B,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,0BAA0B,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAaxJ"}