@waiaas/daemon 2.11.0-rc.21 → 2.11.0-rc.23

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 (90) hide show
  1. package/README.md +5 -5
  2. package/dist/api/routes/admin-notifications.d.ts.map +1 -1
  3. package/dist/api/routes/admin-notifications.js +2 -15
  4. package/dist/api/routes/admin-notifications.js.map +1 -1
  5. package/dist/api/routes/openapi-schemas.d.ts +29 -7
  6. package/dist/api/routes/openapi-schemas.d.ts.map +1 -1
  7. package/dist/api/routes/openapi-schemas.js +7 -5
  8. package/dist/api/routes/openapi-schemas.js.map +1 -1
  9. package/dist/api/routes/wallet-apps.d.ts.map +1 -1
  10. package/dist/api/routes/wallet-apps.js +20 -13
  11. package/dist/api/routes/wallet-apps.js.map +1 -1
  12. package/dist/constants.d.ts +1 -1
  13. package/dist/constants.d.ts.map +1 -1
  14. package/dist/constants.js +1 -1
  15. package/dist/constants.js.map +1 -1
  16. package/dist/infrastructure/config/loader.d.ts +0 -10
  17. package/dist/infrastructure/config/loader.d.ts.map +1 -1
  18. package/dist/infrastructure/config/loader.js +0 -2
  19. package/dist/infrastructure/config/loader.js.map +1 -1
  20. package/dist/infrastructure/database/migrations/v51-v59.d.ts +2 -1
  21. package/dist/infrastructure/database/migrations/v51-v59.d.ts.map +1 -1
  22. package/dist/infrastructure/database/migrations/v51-v59.js +88 -2
  23. package/dist/infrastructure/database/migrations/v51-v59.js.map +1 -1
  24. package/dist/infrastructure/database/schema-ddl.d.ts +1 -1
  25. package/dist/infrastructure/database/schema-ddl.d.ts.map +1 -1
  26. package/dist/infrastructure/database/schema-ddl.js +4 -3
  27. package/dist/infrastructure/database/schema-ddl.js.map +1 -1
  28. package/dist/infrastructure/database/schema.d.ts +19 -0
  29. package/dist/infrastructure/database/schema.d.ts.map +1 -1
  30. package/dist/infrastructure/database/schema.js +1 -0
  31. package/dist/infrastructure/database/schema.js.map +1 -1
  32. package/dist/infrastructure/settings/hot-reload.d.ts.map +1 -1
  33. package/dist/infrastructure/settings/hot-reload.js +0 -2
  34. package/dist/infrastructure/settings/hot-reload.js.map +1 -1
  35. package/dist/infrastructure/settings/setting-keys.d.ts.map +1 -1
  36. package/dist/infrastructure/settings/setting-keys.js +1 -5
  37. package/dist/infrastructure/settings/setting-keys.js.map +1 -1
  38. package/dist/infrastructure/telegram/telegram-bot-service.d.ts.map +1 -1
  39. package/dist/infrastructure/telegram/telegram-bot-service.js +3 -2
  40. package/dist/infrastructure/telegram/telegram-bot-service.js.map +1 -1
  41. package/dist/lifecycle/daemon-startup.js +3 -3
  42. package/dist/lifecycle/daemon-startup.js.map +1 -1
  43. package/dist/notifications/index.d.ts +0 -1
  44. package/dist/notifications/index.d.ts.map +1 -1
  45. package/dist/notifications/index.js +0 -1
  46. package/dist/notifications/index.js.map +1 -1
  47. package/dist/services/signing-sdk/approval-channel-router.d.ts +7 -7
  48. package/dist/services/signing-sdk/approval-channel-router.d.ts.map +1 -1
  49. package/dist/services/signing-sdk/approval-channel-router.js +13 -13
  50. package/dist/services/signing-sdk/approval-channel-router.js.map +1 -1
  51. package/dist/services/signing-sdk/channels/index.d.ts +2 -2
  52. package/dist/services/signing-sdk/channels/index.d.ts.map +1 -1
  53. package/dist/services/signing-sdk/channels/index.js +1 -1
  54. package/dist/services/signing-sdk/channels/index.js.map +1 -1
  55. package/dist/services/signing-sdk/channels/push-relay-signing-channel.d.ts +59 -0
  56. package/dist/services/signing-sdk/channels/push-relay-signing-channel.d.ts.map +1 -0
  57. package/dist/services/signing-sdk/channels/push-relay-signing-channel.js +190 -0
  58. package/dist/services/signing-sdk/channels/push-relay-signing-channel.js.map +1 -0
  59. package/dist/services/signing-sdk/channels/telegram-signing-channel.d.ts +1 -1
  60. package/dist/services/signing-sdk/channels/telegram-signing-channel.js +1 -1
  61. package/dist/services/signing-sdk/channels/wallet-notification-channel.d.ts +6 -7
  62. package/dist/services/signing-sdk/channels/wallet-notification-channel.d.ts.map +1 -1
  63. package/dist/services/signing-sdk/channels/wallet-notification-channel.js +38 -55
  64. package/dist/services/signing-sdk/channels/wallet-notification-channel.js.map +1 -1
  65. package/dist/services/signing-sdk/index.d.ts +3 -3
  66. package/dist/services/signing-sdk/index.d.ts.map +1 -1
  67. package/dist/services/signing-sdk/index.js +2 -2
  68. package/dist/services/signing-sdk/index.js.map +1 -1
  69. package/dist/services/signing-sdk/preset-auto-setup.js +2 -2
  70. package/dist/services/signing-sdk/preset-auto-setup.js.map +1 -1
  71. package/dist/services/signing-sdk/sign-request-builder.d.ts +2 -2
  72. package/dist/services/signing-sdk/sign-request-builder.d.ts.map +1 -1
  73. package/dist/services/signing-sdk/sign-request-builder.js +17 -25
  74. package/dist/services/signing-sdk/sign-request-builder.js.map +1 -1
  75. package/dist/services/signing-sdk/wallet-app-service.d.ts +4 -0
  76. package/dist/services/signing-sdk/wallet-app-service.d.ts.map +1 -1
  77. package/dist/services/signing-sdk/wallet-app-service.js +12 -5
  78. package/dist/services/signing-sdk/wallet-app-service.js.map +1 -1
  79. package/package.json +5 -5
  80. package/public/admin/assets/index-CpFF2lCo.js +3 -0
  81. package/public/admin/index.html +1 -1
  82. package/dist/notifications/channels/ntfy.d.ts +0 -13
  83. package/dist/notifications/channels/ntfy.d.ts.map +0 -1
  84. package/dist/notifications/channels/ntfy.js +0 -75
  85. package/dist/notifications/channels/ntfy.js.map +0 -1
  86. package/dist/services/signing-sdk/channels/ntfy-signing-channel.d.ts +0 -66
  87. package/dist/services/signing-sdk/channels/ntfy-signing-channel.d.ts.map +0 -1
  88. package/dist/services/signing-sdk/channels/ntfy-signing-channel.js +0 -270
  89. package/dist/services/signing-sdk/channels/ntfy-signing-channel.js.map +0 -1
  90. package/public/admin/assets/index-CdYTlzvu.js +0 -3
@@ -6,7 +6,7 @@
6
6
  <meta name="theme-color" content="#0c0c0c" />
7
7
  <meta name="color-scheme" content="dark" />
8
8
  <title>WAIaaS Admin</title>
9
- <script type="module" crossorigin src="/admin/assets/index-CdYTlzvu.js"></script>
9
+ <script type="module" crossorigin src="/admin/assets/index-CpFF2lCo.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="/admin/assets/index-CTHU1J8K.css">
11
11
  </head>
12
12
  <body>
@@ -1,13 +0,0 @@
1
- import type { INotificationChannel, NotificationPayload } from '@waiaas/core';
2
- export declare class NtfyChannel implements INotificationChannel {
3
- readonly name = "ntfy";
4
- private server;
5
- private topic;
6
- initialize(config: Record<string, unknown>): Promise<void>;
7
- send(payload: NotificationPayload): Promise<void>;
8
- /** Map event type to ntfy priority (1-5, where 5=max). */
9
- private mapPriority;
10
- /** Map event type to ntfy tags (emoji shortcodes). */
11
- private mapTags;
12
- }
13
- //# sourceMappingURL=ntfy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ntfy.d.ts","sourceRoot":"","sources":["../../../src/notifications/channels/ntfy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAG9E,qBAAa,WAAY,YAAW,oBAAoB;IACtD,QAAQ,CAAC,IAAI,UAAU;IACvB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,KAAK,CAAM;IAEb,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ1D,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAuCvD,0DAA0D;IAC1D,OAAO,CAAC,WAAW;IAOnB,sDAAsD;IACtD,OAAO,CAAC,OAAO;CAShB"}
@@ -1,75 +0,0 @@
1
- import { abbreviateId, abbreviateAddress } from './format-utils.js';
2
- export class NtfyChannel {
3
- name = 'ntfy';
4
- server = 'https://ntfy.sh';
5
- topic = '';
6
- async initialize(config) {
7
- this.server = String(config.ntfy_server ?? 'https://ntfy.sh');
8
- this.topic = String(config.ntfy_topic ?? '');
9
- if (!this.topic) {
10
- throw new Error('NtfyChannel: ntfy_topic required');
11
- }
12
- }
13
- async send(payload) {
14
- // ntfy.sh: POST plain text with headers for title, priority, tags
15
- const priority = this.mapPriority(payload.eventType);
16
- const tags = this.mapTags(payload.eventType);
17
- const url = `${this.server}/${this.topic}`;
18
- const bodyParts = [payload.body];
19
- if (payload.explorerUrl) {
20
- bodyParts.push(`\nExplorer: ${payload.explorerUrl}`);
21
- }
22
- if (payload.walletId) {
23
- const name = payload.walletName || payload.walletId;
24
- const idAbbr = abbreviateId(payload.walletId);
25
- bodyParts.push(`\n${name} (${idAbbr})`);
26
- if (payload.walletAddress) {
27
- const addrAbbr = abbreviateAddress(payload.walletAddress);
28
- const net = payload.network ?? '';
29
- bodyParts.push(net ? `${addrAbbr} · ${net}` : addrAbbr);
30
- }
31
- bodyParts.push(`Time: ${new Date(payload.timestamp * 1000).toISOString()}`);
32
- }
33
- const response = await fetch(url, {
34
- method: 'POST',
35
- headers: {
36
- 'Title': `[WAIaaS] ${payload.title}`,
37
- 'Priority': String(priority),
38
- 'Tags': tags,
39
- },
40
- body: bodyParts.join(''),
41
- signal: AbortSignal.timeout(10_000),
42
- });
43
- if (!response.ok) {
44
- const body = await response.text();
45
- throw new Error(`NtfyChannel: ${response.status} ${body}`);
46
- }
47
- }
48
- /** Map event type to ntfy priority (1-5, where 5=max). */
49
- mapPriority(eventType) {
50
- if (eventType.includes('KILL_SWITCH') || eventType.includes('AUTO_STOP'))
51
- return 5; // urgent
52
- if (eventType.includes('SUSPENDED') || eventType.includes('FAILED') || eventType.includes('VIOLATION'))
53
- return 4; // high
54
- if (eventType.includes('APPROVAL') || eventType.includes('EXPIR'))
55
- return 3; // default
56
- return 2; // low for informational
57
- }
58
- /** Map event type to ntfy tags (emoji shortcodes). */
59
- mapTags(eventType) {
60
- if (eventType.includes('KILL_SWITCH') || eventType.includes('AUTO_STOP'))
61
- return 'rotating_light,warning';
62
- if (eventType.includes('FAILED') || eventType.includes('VIOLATION'))
63
- return 'x,warning';
64
- if (eventType.includes('CONFIRMED') || eventType.includes('RECOVERED'))
65
- return 'white_check_mark';
66
- if (eventType.includes('APPROVAL'))
67
- return 'bell';
68
- if (eventType.includes('SESSION'))
69
- return 'key';
70
- if (eventType.includes('OWNER'))
71
- return 'bust_in_silhouette';
72
- return 'speech_balloon';
73
- }
74
- }
75
- //# sourceMappingURL=ntfy.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ntfy.js","sourceRoot":"","sources":["../../../src/notifications/channels/ntfy.ts"],"names":[],"mappings":"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"}
@@ -1,66 +0,0 @@
1
- /**
2
- * NtfySigningChannel -- publishes SignRequests to ntfy and subscribes to responses via SSE.
3
- *
4
- * When a PENDING_APPROVAL transaction triggers a SignRequest:
5
- * 1. Publishes the request to the wallet's ntfy request topic (JSON format per doc 73 Section 7.2)
6
- * 2. Subscribes to the response topic via SSE
7
- * 3. Parses incoming SignResponse messages (base64url in ntfy message field)
8
- * 4. Delegates to SignResponseHandler for approval/rejection processing
9
- *
10
- * @see internal/design/73-signing-protocol-v1.md (Section 7.2, 7.3)
11
- * @see internal/design/74-wallet-sdk-daemon-components.md
12
- */
13
- import type { SignRequestBuilder, BuildRequestParams } from '../sign-request-builder.js';
14
- import type { SignResponseHandler } from '../sign-response-handler.js';
15
- import type { SettingsService } from '../../../infrastructure/settings/settings-service.js';
16
- export interface NtfySigningChannelOpts {
17
- signRequestBuilder: SignRequestBuilder;
18
- signResponseHandler: SignResponseHandler;
19
- settingsService: SettingsService;
20
- }
21
- export interface SendRequestParams extends BuildRequestParams {
22
- walletId: string;
23
- }
24
- export interface SendRequestResult {
25
- requestId: string;
26
- requestTopic: string;
27
- responseTopic: string;
28
- }
29
- export declare class NtfySigningChannel {
30
- private readonly signRequestBuilder;
31
- private readonly signResponseHandler;
32
- private readonly settings;
33
- /** Active SSE subscriptions: requestId -> AbortController */
34
- private readonly activeSubscriptions;
35
- constructor(opts: NtfySigningChannelOpts);
36
- /**
37
- * Publish a SignRequest to ntfy request topic and subscribe to response topic.
38
- *
39
- * @param params - Transaction metadata + walletId for topic routing
40
- * @returns requestId, requestTopic, responseTopic
41
- */
42
- sendRequest(params: SendRequestParams): Promise<SendRequestResult>;
43
- /**
44
- * Cancel a specific SSE subscription by requestId.
45
- */
46
- cancelSubscription(requestId: string): void;
47
- /**
48
- * Shutdown all active SSE subscriptions (daemon shutdown).
49
- */
50
- shutdown(): void;
51
- private getNtfyServer;
52
- private publishToNtfy;
53
- private subscribeToResponseTopic;
54
- private connectSse;
55
- /**
56
- * Parse an SSE stream into NtfyMessage objects.
57
- *
58
- * ntfy SSE format:
59
- * event: message
60
- * data: {"id":"...","time":...,"event":"message","topic":"...","message":"..."}
61
- *
62
- * We only care about `data:` lines containing JSON with a `message` field.
63
- */
64
- private parseSseStream;
65
- }
66
- //# sourceMappingURL=ntfy-signing-channel.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ntfy-signing-channel.d.ts","sourceRoot":"","sources":["../../../../src/services/signing-sdk/channels/ntfy-signing-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sDAAsD,CAAC;AAe5F,MAAM,WAAW,sBAAsB;IACrC,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,eAAe,EAAE,eAAe,CAAC;CAClC;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAcD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAE3C,6DAA6D;IAC7D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsC;gBAE9D,IAAI,EAAE,sBAAsB;IAUxC;;;;;OAKG;IACG,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAsCxE;;OAEG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAQ3C;;OAEG;IACH,QAAQ,IAAI,IAAI;IAWhB,OAAO,CAAC,aAAa;YAaP,aAAa;IA8C3B,OAAO,CAAC,wBAAwB;YAyBlB,UAAU;IAoFxB;;;;;;;;OAQG;YACY,cAAc;CAuC9B"}
@@ -1,270 +0,0 @@
1
- /**
2
- * NtfySigningChannel -- publishes SignRequests to ntfy and subscribes to responses via SSE.
3
- *
4
- * When a PENDING_APPROVAL transaction triggers a SignRequest:
5
- * 1. Publishes the request to the wallet's ntfy request topic (JSON format per doc 73 Section 7.2)
6
- * 2. Subscribes to the response topic via SSE
7
- * 3. Parses incoming SignResponse messages (base64url in ntfy message field)
8
- * 4. Delegates to SignResponseHandler for approval/rejection processing
9
- *
10
- * @see internal/design/73-signing-protocol-v1.md (Section 7.2, 7.3)
11
- * @see internal/design/74-wallet-sdk-daemon-components.md
12
- */
13
- import { SignResponseSchema, } from '@waiaas/core';
14
- import { SIGNING_CHANNEL_FETCH_TIMEOUT_MS } from '../../../constants.js';
15
- // ---------------------------------------------------------------------------
16
- // Constants
17
- // ---------------------------------------------------------------------------
18
- const MAX_RECONNECT_ATTEMPTS = 3;
19
- const RECONNECT_DELAY_MS = 5_000;
20
- const DEFAULT_NTFY_SERVER = 'https://ntfy.sh';
21
- // ---------------------------------------------------------------------------
22
- // NtfySigningChannel
23
- // ---------------------------------------------------------------------------
24
- export class NtfySigningChannel {
25
- signRequestBuilder;
26
- signResponseHandler;
27
- settings;
28
- /** Active SSE subscriptions: requestId -> AbortController */
29
- activeSubscriptions = new Map();
30
- constructor(opts) {
31
- this.signRequestBuilder = opts.signRequestBuilder;
32
- this.signResponseHandler = opts.signResponseHandler;
33
- this.settings = opts.settingsService;
34
- }
35
- // -------------------------------------------------------------------------
36
- // sendRequest -- publish to ntfy + subscribe for response
37
- // -------------------------------------------------------------------------
38
- /**
39
- * Publish a SignRequest to ntfy request topic and subscribe to response topic.
40
- *
41
- * @param params - Transaction metadata + walletId for topic routing
42
- * @returns requestId, requestTopic, responseTopic
43
- */
44
- async sendRequest(params) {
45
- // 1. Build SignRequest via SignRequestBuilder
46
- const { request, universalLinkUrl, requestTopic } = this.signRequestBuilder.buildRequest(params);
47
- // 2. Register request with SignResponseHandler for later matching
48
- this.signResponseHandler.registerRequest(request);
49
- // 3. Resolve ntfy server URL
50
- const ntfyServer = this.getNtfyServer();
51
- // 4. Publish to ntfy request topic (doc 73 Section 7.2)
52
- await this.publishToNtfy(ntfyServer, requestTopic, request, universalLinkUrl);
53
- // 5. Determine response topic
54
- let responseTopic;
55
- if (request.responseChannel.type === 'ntfy') {
56
- responseTopic = request.responseChannel.responseTopic;
57
- }
58
- else {
59
- // Fallback: construct response topic from request
60
- const prefix = this.settings.get('signing_sdk.ntfy_response_topic_prefix');
61
- responseTopic = `${prefix}-${request.requestId}`;
62
- }
63
- // 6. Subscribe to response topic via SSE (background, non-blocking)
64
- this.subscribeToResponseTopic(ntfyServer, responseTopic, request.requestId, request.expiresAt);
65
- return {
66
- requestId: request.requestId,
67
- requestTopic,
68
- responseTopic,
69
- };
70
- }
71
- // -------------------------------------------------------------------------
72
- // Subscription management
73
- // -------------------------------------------------------------------------
74
- /**
75
- * Cancel a specific SSE subscription by requestId.
76
- */
77
- cancelSubscription(requestId) {
78
- const controller = this.activeSubscriptions.get(requestId);
79
- if (controller) {
80
- controller.abort();
81
- this.activeSubscriptions.delete(requestId);
82
- }
83
- }
84
- /**
85
- * Shutdown all active SSE subscriptions (daemon shutdown).
86
- */
87
- shutdown() {
88
- for (const [requestId, controller] of this.activeSubscriptions) {
89
- controller.abort();
90
- this.activeSubscriptions.delete(requestId);
91
- }
92
- }
93
- // -------------------------------------------------------------------------
94
- // Private: ntfy server URL
95
- // -------------------------------------------------------------------------
96
- getNtfyServer() {
97
- try {
98
- const server = this.settings.get('notifications.ntfy_server');
99
- return server || DEFAULT_NTFY_SERVER;
100
- }
101
- catch {
102
- return DEFAULT_NTFY_SERVER;
103
- }
104
- }
105
- // -------------------------------------------------------------------------
106
- // Private: publish to ntfy (doc 73 Section 7.2)
107
- // -------------------------------------------------------------------------
108
- async publishToNtfy(ntfyServer, requestTopic, request, universalLinkUrl) {
109
- const url = `${ntfyServer}/${requestTopic}`;
110
- const encoded = Buffer.from(JSON.stringify(request), 'utf-8').toString('base64url');
111
- const body = JSON.stringify({
112
- topic: requestTopic,
113
- message: encoded,
114
- title: request.displayMessage,
115
- priority: 5,
116
- tags: ['waiaas', 'sign'],
117
- actions: [
118
- {
119
- action: 'view',
120
- label: 'Sign in wallet',
121
- url: universalLinkUrl,
122
- },
123
- ],
124
- click: universalLinkUrl,
125
- });
126
- const controller = new AbortController();
127
- const timeoutId = setTimeout(() => controller.abort(), SIGNING_CHANNEL_FETCH_TIMEOUT_MS);
128
- try {
129
- const res = await fetch(url, {
130
- method: 'POST',
131
- headers: { 'Content-Type': 'application/json' },
132
- body,
133
- signal: controller.signal,
134
- });
135
- if (!res.ok) {
136
- throw new Error(`Failed to publish sign request to ntfy: HTTP ${res.status}`);
137
- }
138
- }
139
- finally {
140
- clearTimeout(timeoutId);
141
- }
142
- }
143
- // -------------------------------------------------------------------------
144
- // Private: subscribe to response topic via SSE
145
- // -------------------------------------------------------------------------
146
- subscribeToResponseTopic(ntfyServer, responseTopic, requestId, expiresAt) {
147
- const abortController = new AbortController();
148
- this.activeSubscriptions.set(requestId, abortController);
149
- // Set timeout for request expiration
150
- const expiresAtMs = new Date(expiresAt).getTime();
151
- const timeoutMs = Math.max(0, expiresAtMs - Date.now());
152
- const timer = setTimeout(() => {
153
- this.cancelSubscription(requestId);
154
- }, timeoutMs);
155
- // Unref timer so it doesn't prevent process exit
156
- if (typeof timer === 'object' && 'unref' in timer) {
157
- timer.unref();
158
- }
159
- // Start SSE connection (non-blocking)
160
- void this.connectSse(ntfyServer, responseTopic, requestId, abortController, timer);
161
- }
162
- async connectSse(ntfyServer, responseTopic, requestId, abortController, expirationTimer, reconnectAttempt = 0) {
163
- if (abortController.signal.aborted) {
164
- clearTimeout(expirationTimer);
165
- return;
166
- }
167
- try {
168
- const url = `${ntfyServer}/${responseTopic}/sse`;
169
- const res = await fetch(url, {
170
- signal: abortController.signal,
171
- });
172
- if (!res.ok || !res.body) {
173
- throw new Error(`SSE connection failed: HTTP ${res.status}`);
174
- }
175
- const reader = res.body.getReader();
176
- for await (const ntfyMsg of this.parseSseStream(reader, abortController.signal)) {
177
- if (abortController.signal.aborted)
178
- break;
179
- if (!ntfyMsg.message)
180
- continue;
181
- // ntfy message field contains base64url-encoded SignResponse
182
- try {
183
- const json = Buffer.from(ntfyMsg.message, 'base64url').toString('utf-8');
184
- const parsed = JSON.parse(json);
185
- const signResponse = SignResponseSchema.parse(parsed);
186
- // Only process responses for this requestId
187
- if (signResponse.requestId !== requestId)
188
- continue;
189
- // Delegate to SignResponseHandler
190
- await this.signResponseHandler.handle(signResponse);
191
- // Response processed -- close subscription
192
- this.cancelSubscription(requestId);
193
- clearTimeout(expirationTimer);
194
- return;
195
- }
196
- catch {
197
- // Ignore malformed messages or handler errors
198
- }
199
- }
200
- // SSE stream ended normally -- clean up subscription (#194 Fix 3)
201
- this.activeSubscriptions.delete(requestId);
202
- clearTimeout(expirationTimer);
203
- }
204
- catch (_err) {
205
- // Don't reconnect if explicitly aborted
206
- if (abortController.signal.aborted) {
207
- clearTimeout(expirationTimer);
208
- return;
209
- }
210
- // Reconnect logic: max 3 attempts, 5s delay
211
- if (reconnectAttempt < MAX_RECONNECT_ATTEMPTS) {
212
- await new Promise((resolve) => setTimeout(resolve, RECONNECT_DELAY_MS));
213
- return this.connectSse(ntfyServer, responseTopic, requestId, abortController, expirationTimer, reconnectAttempt + 1);
214
- }
215
- // Max reconnects exceeded -- clean up
216
- this.activeSubscriptions.delete(requestId);
217
- clearTimeout(expirationTimer);
218
- }
219
- }
220
- // -------------------------------------------------------------------------
221
- // Private: SSE stream parser
222
- // -------------------------------------------------------------------------
223
- /**
224
- * Parse an SSE stream into NtfyMessage objects.
225
- *
226
- * ntfy SSE format:
227
- * event: message
228
- * data: {"id":"...","time":...,"event":"message","topic":"...","message":"..."}
229
- *
230
- * We only care about `data:` lines containing JSON with a `message` field.
231
- */
232
- async *parseSseStream(reader, signal) {
233
- const decoder = new TextDecoder();
234
- let buffer = '';
235
- try {
236
- while (!signal.aborted) {
237
- const { done, value } = await reader.read();
238
- if (done)
239
- break;
240
- buffer += decoder.decode(value, { stream: true });
241
- const lines = buffer.split('\n');
242
- // Keep the last incomplete line in buffer
243
- buffer = lines.pop() ?? '';
244
- for (const line of lines) {
245
- if (!line.startsWith('data: '))
246
- continue;
247
- const dataStr = line.slice(6).trim();
248
- if (!dataStr)
249
- continue;
250
- try {
251
- const msg = JSON.parse(dataStr);
252
- yield msg;
253
- }
254
- catch {
255
- // Ignore malformed JSON
256
- }
257
- }
258
- }
259
- }
260
- finally {
261
- try {
262
- reader.releaseLock();
263
- }
264
- catch {
265
- // Reader may already be released
266
- }
267
- }
268
- }
269
- }
270
- //# sourceMappingURL=ntfy-signing-channel.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ntfy-signing-channel.js","sourceRoot":"","sources":["../../../../src/services/signing-sdk/channels/ntfy-signing-channel.ts"],"names":[],"mappings":"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"}