@tapflowio/relay 0.26.1 → 0.27.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 (161) hide show
  1. package/dist/RelayServer.d.ts +92 -0
  2. package/dist/RelayServer.d.ts.map +1 -1
  3. package/dist/RelayServer.js +352 -13
  4. package/dist/RelayServer.js.map +1 -1
  5. package/dist/SessionManager.d.ts +5 -3
  6. package/dist/SessionManager.d.ts.map +1 -1
  7. package/dist/SessionManager.js +3 -1
  8. package/dist/SessionManager.js.map +1 -1
  9. package/dist/api/builds.d.ts.map +1 -1
  10. package/dist/api/builds.js +13 -8
  11. package/dist/api/builds.js.map +1 -1
  12. package/dist/api/comments.d.ts.map +1 -1
  13. package/dist/api/comments.js +5 -7
  14. package/dist/api/comments.js.map +1 -1
  15. package/dist/api/invitations.d.ts.map +1 -1
  16. package/dist/api/invitations.js +3 -0
  17. package/dist/api/invitations.js.map +1 -1
  18. package/dist/api/profile.d.ts.map +1 -1
  19. package/dist/api/profile.js +28 -9
  20. package/dist/api/profile.js.map +1 -1
  21. package/dist/api/recordings.d.ts.map +1 -1
  22. package/dist/api/recordings.js +5 -6
  23. package/dist/api/recordings.js.map +1 -1
  24. package/dist/api/settings.d.ts.map +1 -1
  25. package/dist/api/settings.js +28 -9
  26. package/dist/api/settings.js.map +1 -1
  27. package/dist/lib/clientAddress.d.ts +12 -0
  28. package/dist/lib/clientAddress.d.ts.map +1 -1
  29. package/dist/lib/clientAddress.js +22 -0
  30. package/dist/lib/clientAddress.js.map +1 -1
  31. package/dist/lib/uploads.d.ts +13 -0
  32. package/dist/lib/uploads.d.ts.map +1 -1
  33. package/dist/lib/uploads.js +41 -0
  34. package/dist/lib/uploads.js.map +1 -1
  35. package/dist/lib/webhookTransport.d.ts +29 -0
  36. package/dist/lib/webhookTransport.d.ts.map +1 -0
  37. package/dist/lib/webhookTransport.js +86 -0
  38. package/dist/lib/webhookTransport.js.map +1 -0
  39. package/dist/lib/webhookUrl.d.ts +6 -0
  40. package/dist/lib/webhookUrl.d.ts.map +1 -1
  41. package/dist/lib/webhookUrl.js +50 -14
  42. package/dist/lib/webhookUrl.js.map +1 -1
  43. package/dist/lib/webhooks.d.ts +2 -10
  44. package/dist/lib/webhooks.d.ts.map +1 -1
  45. package/dist/lib/webhooks.js +8 -3
  46. package/dist/lib/webhooks.js.map +1 -1
  47. package/package.json +6 -6
  48. package/public/assets/{AppCenter-DZCsC2wa.js → AppCenter-CeLjUbnR.js} +7 -7
  49. package/public/assets/AppCenter-CeLjUbnR.js.br +0 -0
  50. package/public/assets/AppCenter-CeLjUbnR.js.gz +0 -0
  51. package/public/assets/Default-UB0Pa3lN.js +1 -0
  52. package/public/assets/Default-UB0Pa3lN.js.br +0 -0
  53. package/public/assets/Default-UB0Pa3lN.js.gz +0 -0
  54. package/public/assets/Invite-Dv3omu3x.js +1 -0
  55. package/public/assets/Invite-Dv3omu3x.js.br +0 -0
  56. package/public/assets/Invite-Dv3omu3x.js.gz +0 -0
  57. package/public/assets/{MacResources-B0DQ9ISE.js → MacResources-CY4-OdGt.js} +1 -1
  58. package/public/assets/MacResources-CY4-OdGt.js.br +0 -0
  59. package/public/assets/MacResources-CY4-OdGt.js.gz +0 -0
  60. package/public/assets/QASession-H5eRSwZv.js +150 -0
  61. package/public/assets/QASession-H5eRSwZv.js.br +0 -0
  62. package/public/assets/QASession-H5eRSwZv.js.gz +0 -0
  63. package/public/assets/ResetPassword-nFTigYt2.js +1 -0
  64. package/public/assets/ResetPassword-nFTigYt2.js.br +0 -0
  65. package/public/assets/ResetPassword-nFTigYt2.js.gz +0 -0
  66. package/public/assets/Setup-UmLtF2PF.js +1 -0
  67. package/public/assets/Setup-UmLtF2PF.js.br +0 -0
  68. package/public/assets/Setup-UmLtF2PF.js.gz +0 -0
  69. package/public/assets/Team-DW40kt3H.js +6 -0
  70. package/public/assets/Team-DW40kt3H.js.br +0 -0
  71. package/public/assets/Team-DW40kt3H.js.gz +0 -0
  72. package/public/assets/Tokens-B1a4ChJK.js +1 -0
  73. package/public/assets/Tokens-B1a4ChJK.js.br +0 -0
  74. package/public/assets/Tokens-B1a4ChJK.js.gz +0 -0
  75. package/public/assets/alert-dialog-aoqYdAwx.js +1 -0
  76. package/public/assets/alert-dialog-aoqYdAwx.js.br +0 -0
  77. package/public/assets/alert-dialog-aoqYdAwx.js.gz +0 -0
  78. package/public/assets/badge-DNaS0Mu3.js +1 -0
  79. package/public/assets/badge-DNaS0Mu3.js.br +0 -0
  80. package/public/assets/badge-DNaS0Mu3.js.gz +0 -0
  81. package/public/assets/{build-format-fzt-JrUX.js → build-format-DF5aFcag.js} +3 -3
  82. package/public/assets/build-format-DF5aFcag.js.br +0 -0
  83. package/public/assets/build-format-DF5aFcag.js.gz +0 -0
  84. package/public/assets/{dialog-DQkbaw8h.js → dialog-DE2WUMuX.js} +5 -5
  85. package/public/assets/dialog-DE2WUMuX.js.br +0 -0
  86. package/public/assets/dialog-DE2WUMuX.js.gz +0 -0
  87. package/public/assets/field-hint-Csb40Gzp.js +1 -0
  88. package/public/assets/field-hint-Csb40Gzp.js.br +2 -0
  89. package/public/assets/field-hint-Csb40Gzp.js.gz +0 -0
  90. package/public/assets/index-BbCkTtjO.css +1 -0
  91. package/public/assets/index-BbCkTtjO.css.br +0 -0
  92. package/public/assets/index-BbCkTtjO.css.gz +0 -0
  93. package/public/assets/index-DSW9h8XX.js +218 -0
  94. package/public/assets/index-DSW9h8XX.js.br +0 -0
  95. package/public/assets/index-DSW9h8XX.js.gz +0 -0
  96. package/public/assets/list-view-C0w97ltJ.js +1 -0
  97. package/public/assets/list-view-C0w97ltJ.js.br +0 -0
  98. package/public/assets/list-view-C0w97ltJ.js.gz +0 -0
  99. package/public/assets/{pencil-BJcOp3oN.js → pencil-BN18R4oa.js} +2 -2
  100. package/public/assets/pencil-BN18R4oa.js.br +0 -0
  101. package/public/assets/pencil-BN18R4oa.js.gz +0 -0
  102. package/public/assets/resource-health-Bi20EUDs.js +1 -0
  103. package/public/assets/resource-health-Bi20EUDs.js.br +0 -0
  104. package/public/assets/resource-health-Bi20EUDs.js.gz +0 -0
  105. package/public/assets/{trash-DhBxh6H7.js → trash-D1l1Fm-Z.js} +3 -3
  106. package/public/assets/trash-D1l1Fm-Z.js.br +0 -0
  107. package/public/assets/trash-D1l1Fm-Z.js.gz +0 -0
  108. package/public/index.html +2 -2
  109. package/public/index.html.br +0 -0
  110. package/public/index.html.gz +0 -0
  111. package/public/assets/AppCenter-DZCsC2wa.js.br +0 -0
  112. package/public/assets/AppCenter-DZCsC2wa.js.gz +0 -0
  113. package/public/assets/Default-xD9Fmd5X.js +0 -1
  114. package/public/assets/Default-xD9Fmd5X.js.br +0 -0
  115. package/public/assets/Default-xD9Fmd5X.js.gz +0 -0
  116. package/public/assets/Invite-29Erwv8j.js +0 -1
  117. package/public/assets/Invite-29Erwv8j.js.br +0 -0
  118. package/public/assets/Invite-29Erwv8j.js.gz +0 -0
  119. package/public/assets/MacResources-B0DQ9ISE.js.br +0 -0
  120. package/public/assets/MacResources-B0DQ9ISE.js.gz +0 -0
  121. package/public/assets/QASession-D-n6PXuD.js +0 -150
  122. package/public/assets/QASession-D-n6PXuD.js.br +0 -0
  123. package/public/assets/QASession-D-n6PXuD.js.gz +0 -0
  124. package/public/assets/ResetPassword-BnPIwTYH.js +0 -1
  125. package/public/assets/ResetPassword-BnPIwTYH.js.br +0 -0
  126. package/public/assets/ResetPassword-BnPIwTYH.js.gz +0 -0
  127. package/public/assets/Setup-DmUGFblg.js +0 -1
  128. package/public/assets/Setup-DmUGFblg.js.br +0 -0
  129. package/public/assets/Setup-DmUGFblg.js.gz +0 -0
  130. package/public/assets/Team-BpvRgFfZ.js +0 -6
  131. package/public/assets/Team-BpvRgFfZ.js.br +0 -0
  132. package/public/assets/Team-BpvRgFfZ.js.gz +0 -0
  133. package/public/assets/Tokens-x6BtCcL7.js +0 -1
  134. package/public/assets/Tokens-x6BtCcL7.js.br +0 -0
  135. package/public/assets/Tokens-x6BtCcL7.js.gz +0 -0
  136. package/public/assets/alert-dialog-C8wDimW-.js +0 -1
  137. package/public/assets/alert-dialog-C8wDimW-.js.br +0 -0
  138. package/public/assets/alert-dialog-C8wDimW-.js.gz +0 -0
  139. package/public/assets/badge-CWVbeuH3.js +0 -1
  140. package/public/assets/badge-CWVbeuH3.js.br +0 -0
  141. package/public/assets/badge-CWVbeuH3.js.gz +0 -0
  142. package/public/assets/build-format-fzt-JrUX.js.br +0 -0
  143. package/public/assets/build-format-fzt-JrUX.js.gz +0 -0
  144. package/public/assets/dialog-DQkbaw8h.js.br +0 -0
  145. package/public/assets/dialog-DQkbaw8h.js.gz +0 -0
  146. package/public/assets/index-C1Fo8g_c.js +0 -218
  147. package/public/assets/index-C1Fo8g_c.js.br +0 -0
  148. package/public/assets/index-C1Fo8g_c.js.gz +0 -0
  149. package/public/assets/index-C2F1AgwB.css +0 -1
  150. package/public/assets/index-C2F1AgwB.css.br +0 -0
  151. package/public/assets/index-C2F1AgwB.css.gz +0 -0
  152. package/public/assets/list-view-DxI397-H.js +0 -1
  153. package/public/assets/list-view-DxI397-H.js.br +0 -0
  154. package/public/assets/list-view-DxI397-H.js.gz +0 -0
  155. package/public/assets/pencil-BJcOp3oN.js.br +0 -0
  156. package/public/assets/pencil-BJcOp3oN.js.gz +0 -0
  157. package/public/assets/resource-health-Cq3gqqVd.js +0 -1
  158. package/public/assets/resource-health-Cq3gqqVd.js.br +0 -0
  159. package/public/assets/resource-health-Cq3gqqVd.js.gz +0 -0
  160. package/public/assets/trash-DhBxh6H7.js.br +0 -0
  161. package/public/assets/trash-DhBxh6H7.js.gz +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"clientAddress.js","sourceRoot":"","sources":["../../src/lib/clientAddress.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"clientAddress.js","sourceRoot":"","sources":["../../src/lib/clientAddress.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,15 @@
1
1
  export declare function unlinkSafe(filePath: string, label: string): void;
2
+ /**
3
+ * Writes an uploaded file to `dest`. Resolves once it is on disk; on a failed upload or write, closes the
4
+ * writer, removes what was written and rejects.
5
+ *
6
+ * `stream.pipe(writer)` does neither: when busboy destroys a file's stream — a body that ends inside the
7
+ * part — the writer stays open and the partial file stays on disk, once per failed upload.
8
+ *
9
+ * The rejection is marked handled here, for the case where nobody awaits it: a failed part also fails the
10
+ * parser, whose `'error'` handler answers the request, and the route's `'finish'` never runs. A failed
11
+ * *write* (a full disk) is different — the parser still finishes and the route awaits a rejection, so every
12
+ * caller catches it.
13
+ */
14
+ export declare function pipeUpload(stream: NodeJS.ReadableStream, dest: string, label: string): Promise<void>;
2
15
  //# sourceMappingURL=uploads.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAQhE"}
1
+ {"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAQhE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBpG"}
@@ -11,4 +11,45 @@ export function unlinkSafe(filePath, label) {
11
11
  }
12
12
  }
13
13
  }
14
+ /**
15
+ * Writes an uploaded file to `dest`. Resolves once it is on disk; on a failed upload or write, closes the
16
+ * writer, removes what was written and rejects.
17
+ *
18
+ * `stream.pipe(writer)` does neither: when busboy destroys a file's stream — a body that ends inside the
19
+ * part — the writer stays open and the partial file stays on disk, once per failed upload.
20
+ *
21
+ * The rejection is marked handled here, for the case where nobody awaits it: a failed part also fails the
22
+ * parser, whose `'error'` handler answers the request, and the route's `'finish'` never runs. A failed
23
+ * *write* (a full disk) is different — the parser still finishes and the route awaits a rejection, so every
24
+ * caller catches it.
25
+ */
26
+ export function pipeUpload(stream, dest, label) {
27
+ const writer = fs.createWriteStream(dest);
28
+ const written = new Promise((resolve, reject) => {
29
+ let failed = false;
30
+ const fail = (err) => {
31
+ if (failed)
32
+ return;
33
+ failed = true;
34
+ // Keep reading the upload: a writer error unpipes it, and a part nobody reads holds the parser short
35
+ // of `'finish'`, so the route would never answer.
36
+ stream.resume();
37
+ // Remove the file once the writer has closed it: Windows refuses to delete an open file, and an error
38
+ // before the open completes would otherwise delete nothing and leave the file it then creates.
39
+ const remove = () => { unlinkSafe(dest, label); reject(err); };
40
+ if (writer.closed)
41
+ remove();
42
+ else {
43
+ writer.once('close', remove);
44
+ writer.destroy();
45
+ }
46
+ };
47
+ writer.on('finish', resolve);
48
+ writer.on('error', fail);
49
+ stream.on('error', fail);
50
+ });
51
+ written.catch(() => { });
52
+ stream.pipe(writer);
53
+ return written;
54
+ }
14
55
  //# sourceMappingURL=uploads.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"uploads.js","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,yDAAyD;AACzD,kDAAkD;AAClD,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,KAAa;IACxD,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC,8BAA8B,KAAK,EAAE,EAAG,GAAa,CAAC,OAAO,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"uploads.js","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,yDAAyD;AACzD,kDAAkD;AAClD,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,KAAa;IACxD,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC,8BAA8B,KAAK,EAAE,EAAG,GAAa,CAAC,OAAO,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAC,MAA6B,EAAE,IAAY,EAAE,KAAa;IACnF,MAAM,MAAM,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAA;IACzC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACpD,IAAI,MAAM,GAAG,KAAK,CAAA;QAClB,MAAM,IAAI,GAAG,CAAC,GAAY,EAAE,EAAE;YAC5B,IAAI,MAAM;gBAAE,OAAM;YAClB,MAAM,GAAG,IAAI,CAAA;YACb,qGAAqG;YACrG,kDAAkD;YAClD,MAAM,CAAC,MAAM,EAAE,CAAA;YACf,sGAAsG;YACtG,+FAA+F;YAC/F,MAAM,MAAM,GAAG,GAAG,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA,CAAC,CAAC,CAAA;YAC7D,IAAI,MAAM,CAAC,MAAM;gBAAE,MAAM,EAAE,CAAA;iBACtB,CAAC;gBAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAAC,MAAM,CAAC,OAAO,EAAE,CAAA;YAAC,CAAC;QACzD,CAAC,CAAA;QACD,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QAC5B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QACxB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IAC1B,CAAC,CAAC,CAAA;IACF,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IACvB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACnB,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,29 @@
1
+ export type FetchLike = (url: string, init: {
2
+ method: string;
3
+ headers: Record<string, string>;
4
+ body: string;
5
+ signal: AbortSignal;
6
+ }) => Promise<{
7
+ ok: boolean;
8
+ status: number;
9
+ text: () => Promise<string>;
10
+ }>;
11
+ export type LookupFn = (hostname: string) => Promise<{
12
+ address: string;
13
+ family: number;
14
+ }[]>;
15
+ export declare class BlockedDestinationError extends Error {
16
+ constructor(host: string, address: string);
17
+ }
18
+ /**
19
+ * Webhook delivery transport. Unlike global fetch it judges the addresses a hostname resolves to, and
20
+ * the socket connects only to addresses that passed: the check runs inside the connection's own
21
+ * `lookup`, so there is no second resolution for DNS rebinding to answer differently. It never
22
+ * follows redirects — node's http client doesn't — so a 3xx comes back as a non-ok response instead of
23
+ * a hop to wherever the receiver points.
24
+ */
25
+ export declare function createSafeFetch(opts?: {
26
+ lookup?: LookupFn;
27
+ isBlocked?: (ip: string) => boolean;
28
+ }): FetchLike;
29
+ //# sourceMappingURL=webhookTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhookTransport.d.ts","sourceRoot":"","sources":["../../src/lib/webhookTransport.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,SAAS,GAAG,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,KACzF,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAAA;AAE1E,MAAM,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAAA;AAO3F,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAI1C;AAID;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,QAAQ,CAAC;IAAC,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAA;CAAO,GACpE,SAAS,CAmEX"}
@@ -0,0 +1,86 @@
1
+ import dns from 'dns';
2
+ import http from 'http';
3
+ import https from 'https';
4
+ import net from 'net';
5
+ import { isBlockedAddress } from './webhookUrl.js';
6
+ const systemLookup = (hostname) => dns.promises.lookup(hostname, { all: true });
7
+ // Only drained, never read for meaning, so a receiver can't make the relay buffer a large reply.
8
+ const MAX_RESPONSE_BYTES = 64 * 1024;
9
+ export class BlockedDestinationError extends Error {
10
+ constructor(host, address) {
11
+ super(`${host} resolves to ${address}, a loopback or metadata address`);
12
+ this.name = 'BlockedDestinationError';
13
+ }
14
+ }
15
+ /**
16
+ * Webhook delivery transport. Unlike global fetch it judges the addresses a hostname resolves to, and
17
+ * the socket connects only to addresses that passed: the check runs inside the connection's own
18
+ * `lookup`, so there is no second resolution for DNS rebinding to answer differently. It never
19
+ * follows redirects — node's http client doesn't — so a 3xx comes back as a non-ok response instead of
20
+ * a hop to wherever the receiver points.
21
+ */
22
+ export function createSafeFetch(opts = {}) {
23
+ const resolve = opts.lookup ?? systemLookup;
24
+ const isBlocked = opts.isBlocked ?? isBlockedAddress;
25
+ const gatedLookup = (hostname, options, callback) => {
26
+ resolve(hostname).then((answers) => {
27
+ if (answers.length === 0)
28
+ return callback(Object.assign(new Error(`getaddrinfo ENOTFOUND ${hostname}`), { code: 'ENOTFOUND' }), '');
29
+ // Blocked answers are dropped rather than failing the name: macOS answers a LAN host's `.local`
30
+ // name with its fe80:: address next to its 192.168.x one, and that host is a webhook receiver this
31
+ // feature exists for. Dropping is safe because only what survives is handed to the socket.
32
+ const permitted = answers.filter((a) => !isBlocked(a.address));
33
+ if (permitted.length === 0)
34
+ return callback(new BlockedDestinationError(hostname, answers[0].address), '');
35
+ const wanted = options.family === 4 || options.family === 6 ? permitted.filter((a) => a.family === options.family) : permitted;
36
+ if (wanted.length === 0)
37
+ return callback(Object.assign(new Error(`getaddrinfo ENOTFOUND ${hostname}`), { code: 'ENOTFOUND' }), '');
38
+ if (options.all)
39
+ return callback(null, wanted);
40
+ callback(null, wanted[0].address, wanted[0].family);
41
+ }, (err) => callback(err, ''));
42
+ };
43
+ return (url, init) => new Promise((resolvePromise, reject) => {
44
+ const u = new URL(url);
45
+ const host = u.hostname.replace(/^\[|\]$/g, '');
46
+ // net.connect skips `lookup` for an IP literal, so a literal is judged here.
47
+ if (net.isIP(host) && isBlocked(host))
48
+ return reject(new BlockedDestinationError(host, host));
49
+ // A row written before registration refused these must not leak them as an Authorization header.
50
+ if (u.username || u.password)
51
+ return reject(new Error('webhook URL must not contain credentials'));
52
+ const client = u.protocol === 'https:' ? https : http;
53
+ const req = client.request(u, {
54
+ method: init.method,
55
+ // fetch sent a User-Agent and Accept on its own, and edge WAFs commonly refuse a request with no
56
+ // User-Agent at all.
57
+ headers: {
58
+ 'User-Agent': 'tapflow-webhook',
59
+ Accept: '*/*',
60
+ ...init.headers,
61
+ 'Content-Length': String(Buffer.byteLength(init.body)),
62
+ },
63
+ lookup: gatedLookup,
64
+ signal: init.signal,
65
+ // A pooled socket would skip the lookup; every delivery resolves and is judged afresh.
66
+ agent: false,
67
+ }, (res) => {
68
+ const chunks = [];
69
+ let size = 0;
70
+ res.on('data', (c) => {
71
+ if (size < MAX_RESPONSE_BYTES)
72
+ chunks.push(c);
73
+ size += c.length;
74
+ });
75
+ res.on('error', reject);
76
+ res.on('end', () => {
77
+ const status = res.statusCode ?? 0;
78
+ const body = Buffer.concat(chunks).subarray(0, MAX_RESPONSE_BYTES).toString();
79
+ resolvePromise({ ok: status >= 200 && status < 300, status, text: async () => body });
80
+ });
81
+ });
82
+ req.on('error', reject);
83
+ req.end(init.body);
84
+ });
85
+ }
86
+ //# sourceMappingURL=webhookTransport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhookTransport.js","sourceRoot":"","sources":["../../src/lib/webhookTransport.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,14 @@
1
+ /** True when an IP address is one a webhook must never be delivered to. */
2
+ export declare function isBlockedAddress(ip: string): boolean;
1
3
  /**
2
4
  * Validate a webhook destination URL. Returns an error string, or null when allowed.
3
5
  * Blocks loopback and cloud-metadata addresses; private LAN ranges (10/172.16/192.168)
4
6
  * are intentionally allowed because self-hosted CI often lives there.
5
7
  *
8
+ * This is the registration-time check and sees only the URL, so a hostname is judged by its name.
9
+ * The address it resolves to is judged at delivery, by webhookTransport.ts — DNS can point a
10
+ * harmless-looking name at loopback, and can change after registration.
11
+ *
6
12
  * Lives in its own module so both webhooks.ts (delivery) and config.ts (config-file
7
13
  * endpoints) can validate without a circular import — webhooks.ts imports config.ts,
8
14
  * so config.ts can't import back into webhooks.ts.
@@ -1 +1 @@
1
- {"version":3,"file":"webhookUrl.d.ts","sourceRoot":"","sources":["../../src/lib/webhookUrl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA8B7D"}
1
+ {"version":3,"file":"webhookUrl.d.ts","sourceRoot":"","sources":["../../src/lib/webhookUrl.ts"],"names":[],"mappings":"AAgCA,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAIpD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAwB7D"}
@@ -1,8 +1,48 @@
1
+ import net from 'net';
2
+ // Loopback, unspecified, link-local (which holds the 169.254.169.254 metadata service) and AWS's IPv6
3
+ // metadata address. Private LAN ranges (10/172.16/192.168, fc00::/7) are intentionally absent:
4
+ // self-hosted CI usually lives there, and webhooks reaching it is the feature.
5
+ const blocked = new net.BlockList();
6
+ // BlockList matches the IPv4-mapped form (::ffff:127.0.0.1, ::ffff:7f00:1) of an IPv4 subnet by itself,
7
+ // but no other IPv6 spelling that carries an IPv4 address. Those are added as subnets of their own:
8
+ // IPv4-compatible ::a.b.c.d, IPv4-translated ::ffff:0:a.b.c.d (RFC 6052), the NAT64 well-known
9
+ // prefix 64:ff9b::/96, and 6to4 2002:aabb:ccdd::/48 — a NAT64 or 6to4 gateway on the relay's network
10
+ // hands such an address to the embedded IPv4 host. Not covered: the local-use NAT64 prefix
11
+ // 64:ff9b:1::/48 (RFC 8215) and any prefix an operator picks. Only a gateway that operator configured
12
+ // translates those, and an operator's own prefix cannot be known from here.
13
+ function blockIPv4Subnet(address, prefix) {
14
+ blocked.addSubnet(address, prefix, 'ipv4');
15
+ const [a, b, c, d] = address.split('.').map(Number);
16
+ const hi = ((a << 8) | b).toString(16);
17
+ const lo = ((c << 8) | d).toString(16);
18
+ blocked.addSubnet(`::${hi}:${lo}`, 96 + prefix, 'ipv6');
19
+ blocked.addSubnet(`::ffff:0:${hi}:${lo}`, 96 + prefix, 'ipv6');
20
+ blocked.addSubnet(`64:ff9b::${hi}:${lo}`, 96 + prefix, 'ipv6');
21
+ blocked.addSubnet(`2002:${hi}:${lo}::`, 16 + prefix, 'ipv6');
22
+ }
23
+ blockIPv4Subnet('127.0.0.0', 8);
24
+ blockIPv4Subnet('0.0.0.0', 8);
25
+ blockIPv4Subnet('169.254.0.0', 16);
26
+ blocked.addAddress('::1', 'ipv6');
27
+ blocked.addAddress('::', 'ipv6');
28
+ blocked.addSubnet('fe80::', 10, 'ipv6');
29
+ blocked.addAddress('fd00:ec2::254', 'ipv6');
30
+ /** True when an IP address is one a webhook must never be delivered to. */
31
+ export function isBlockedAddress(ip) {
32
+ const family = net.isIP(ip);
33
+ if (family === 0)
34
+ return false;
35
+ return blocked.check(ip, family === 4 ? 'ipv4' : 'ipv6');
36
+ }
1
37
  /**
2
38
  * Validate a webhook destination URL. Returns an error string, or null when allowed.
3
39
  * Blocks loopback and cloud-metadata addresses; private LAN ranges (10/172.16/192.168)
4
40
  * are intentionally allowed because self-hosted CI often lives there.
5
41
  *
42
+ * This is the registration-time check and sees only the URL, so a hostname is judged by its name.
43
+ * The address it resolves to is judged at delivery, by webhookTransport.ts — DNS can point a
44
+ * harmless-looking name at loopback, and can change after registration.
45
+ *
6
46
  * Lives in its own module so both webhooks.ts (delivery) and config.ts (config-file
7
47
  * endpoints) can validate without a circular import — webhooks.ts imports config.ts,
8
48
  * so config.ts can't import back into webhooks.ts.
@@ -18,21 +58,17 @@ export function validateWebhookUrl(raw) {
18
58
  if (u.protocol !== 'http:' && u.protocol !== 'https:') {
19
59
  return 'URL must use http or https';
20
60
  }
21
- let host = u.hostname.toLowerCase().replace(/^\[|\]$/g, ''); // strip IPv6 brackets
22
- // Node normalizes an IPv4-mapped IPv6 host (e.g. ::ffff:127.0.0.1) to a hex form
23
- // like ::ffff:7f00:1, which would slip past the IPv4 checks below yet still connect
24
- // to the embedded IPv4 — an SSRF bypass. Unwrap it back to dotted IPv4 first.
25
- const mapped = host.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
26
- if (mapped) {
27
- const hi = parseInt(mapped[1], 16);
28
- const lo = parseInt(mapped[2], 16);
29
- host = [hi >> 8, hi & 0xff, lo >> 8, lo & 0xff].join('.');
61
+ // fetch refused these outright; node's http client would turn them into an Authorization header.
62
+ if (u.username || u.password) {
63
+ return 'URL must not contain credentials';
30
64
  }
31
- if (host === 'localhost' ||
32
- host === '0.0.0.0' ||
33
- host === '::1' ||
34
- host.startsWith('127.') ||
35
- host.startsWith('169.254.')) {
65
+ // WHATWG URL has already canonicalized numeric IPv4 spellings (2130706433, 0x7f.1 → 127.0.0.1).
66
+ const host = u.hostname
67
+ .toLowerCase()
68
+ .replace(/^\[|\]$/g, '') // strip IPv6 brackets
69
+ .replace(/\.$/, ''); // a trailing dot names the same host
70
+ // RFC 6761 reserves localhost and every name under it for loopback, with no DNS involved.
71
+ if (host === 'localhost' || host.endsWith('.localhost') || isBlockedAddress(host)) {
36
72
  return 'URL host is not allowed (loopback or metadata address)';
37
73
  }
38
74
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"webhookUrl.js","sourceRoot":"","sources":["../../src/lib/webhookUrl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,CAAM,CAAA;IACV,IAAI,CAAC;QACH,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,aAAa,CAAA;IACtB,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACtD,OAAO,4BAA4B,CAAA;IACrC,CAAC;IACD,IAAI,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA,CAAC,sBAAsB;IAClF,iFAAiF;IACjF,oFAAoF;IACpF,8EAA8E;IAC9E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAA;IACrE,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QAClC,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QAClC,IAAI,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC3D,CAAC;IACD,IACE,IAAI,KAAK,WAAW;QACpB,IAAI,KAAK,SAAS;QAClB,IAAI,KAAK,KAAK;QACd,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QACvB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAC3B,CAAC;QACD,OAAO,wDAAwD,CAAA;IACjE,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
1
+ {"version":3,"file":"webhookUrl.js","sourceRoot":"","sources":["../../src/lib/webhookUrl.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAA;AAErB,sGAAsG;AACtG,+FAA+F;AAC/F,+EAA+E;AAC/E,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,SAAS,EAAE,CAAA;AAEnC,wGAAwG;AACxG,oGAAoG;AACpG,+FAA+F;AAC/F,qGAAqG;AACrG,2FAA2F;AAC3F,sGAAsG;AACtG,4EAA4E;AAC5E,SAAS,eAAe,CAAC,OAAe,EAAE,MAAc;IACtD,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1C,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACnD,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IACtC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IACtC,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,EAAE,MAAM,CAAC,CAAA;IACvD,OAAO,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9D,OAAO,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9D,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,MAAM,EAAE,MAAM,CAAC,CAAA;AAC9D,CAAC;AACD,eAAe,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;AAC/B,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;AAC7B,eAAe,CAAC,aAAa,EAAE,EAAE,CAAC,CAAA;AAClC,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;AACjC,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AAChC,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,CAAC,CAAA;AACvC,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,MAAM,CAAC,CAAA;AAE3C,2EAA2E;AAC3E,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC3B,IAAI,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAC9B,OAAO,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;AAC1D,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,CAAM,CAAA;IACV,IAAI,CAAC;QACH,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,aAAa,CAAA;IACtB,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACtD,OAAO,4BAA4B,CAAA;IACrC,CAAC;IACD,iGAAiG;IACjG,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC7B,OAAO,kCAAkC,CAAA;IAC3C,CAAC;IACD,gGAAgG;IAChG,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ;SACpB,WAAW,EAAE;SACb,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,sBAAsB;SAC9C,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA,CAAC,qCAAqC;IAC3D,0FAA0F;IAC1F,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;QAClF,OAAO,wDAAwD,CAAA;IACjE,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -1,4 +1,6 @@
1
+ import { type FetchLike } from './webhookTransport.js';
1
2
  export { validateWebhookUrl } from './webhookUrl.js';
3
+ export type { FetchLike } from './webhookTransport.js';
2
4
  export declare const WEBHOOK_TIMEOUT_MS = 5000;
3
5
  export interface WebhookPayload {
4
6
  event: string;
@@ -10,16 +12,6 @@ export interface WebhookPayload {
10
12
  };
11
13
  changedAt: string;
12
14
  }
13
- export type FetchLike = (url: string, init: {
14
- method: string;
15
- headers: Record<string, string>;
16
- body: string;
17
- signal: AbortSignal;
18
- }) => Promise<{
19
- ok: boolean;
20
- status: number;
21
- text: () => Promise<string>;
22
- }>;
23
15
  /** HMAC-SHA256 signature of the raw request body, formatted like EAS's expo-signature. */
24
16
  export declare function signPayload(secret: string, body: string): string;
25
17
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/lib/webhooks.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAKpD,eAAO,MAAM,kBAAkB,OAAO,CAAA;AAEtC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAA;QACV,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;QACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;QACzB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD,SAAS,EAAE,MAAM,CAAA;CAClB;AAGD,MAAM,MAAM,SAAS,GAAG,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,KACzF,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAAA;AAE1E,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhE;AAOD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,SAAS,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CAiCf"}
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/lib/webhooks.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAIvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACpD,YAAY,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAKtD,eAAO,MAAM,kBAAkB,OAAO,CAAA;AAEtC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAA;QACV,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;QACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;QACzB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhE;AAOD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,SAAS,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CAqCf"}
@@ -2,6 +2,7 @@ import crypto from 'crypto';
2
2
  import { createLogger } from '@tapflowio/agent-core';
3
3
  import { getDb } from '../db.js';
4
4
  import { config } from './config.js';
5
+ import { createSafeFetch } from './webhookTransport.js';
5
6
  // Re-exported so existing importers keep using webhooks.ts; the implementation lives
6
7
  // in webhookUrl.ts to avoid a circular import with config.ts (which also validates).
7
8
  export { validateWebhookUrl } from './webhookUrl.js';
@@ -29,7 +30,7 @@ export async function deliverWebhooks(payload, opts = {}) {
29
30
  if (rows.length === 0)
30
31
  return;
31
32
  const body = JSON.stringify(payload);
32
- const fetchFn = opts.fetchFn ?? globalThis.fetch;
33
+ const fetchFn = opts.fetchFn ?? createSafeFetch();
33
34
  await Promise.allSettled(rows.map(async (ep) => {
34
35
  const headers = { 'Content-Type': 'application/json' };
35
36
  if (ep.secret)
@@ -41,10 +42,14 @@ export async function deliverWebhooks(payload, opts = {}) {
41
42
  body,
42
43
  signal: AbortSignal.timeout(WEBHOOK_TIMEOUT_MS),
43
44
  });
44
- // Drain the body so undici releases the connection back to the pool.
45
+ // Drain the body so the connection is released.
45
46
  await res.text();
46
- if (!res.ok)
47
+ if (res.status >= 300 && res.status < 400) {
48
+ logger.warn(`webhook POST ${ep.url} returned ${res.status} (redirects are not followed; register the final URL)`);
49
+ }
50
+ else if (!res.ok) {
47
51
  logger.warn(`webhook POST ${ep.url} returned ${res.status}`);
52
+ }
48
53
  }
49
54
  catch (err) {
50
55
  logger.warn(`webhook POST ${ep.url} failed: ${String(err)}`);
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/lib/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAA;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,qFAAqF;AACrF,qFAAqF;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEpD,MAAM,MAAM,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAAA;AAE7C,6EAA6E;AAC7E,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAA;AAmBtC,0FAA0F;AAC1F,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,IAAY;IACtD,OAAO,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACnF,CAAC;AAOD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAuB,EACvB,OAAgC,EAAE;IAElC,MAAM,MAAM,GAAG,KAAK,EAAE;SACnB,OAAO,CAAC,6DAA6D,CAAC;SACtE,GAAG,EAAmB,CAAA;IACzB,oFAAoF;IACpF,MAAM,UAAU,GAAkB,MAAM,CAAC,QAAQ;SAC9C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;SACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,CAAA;IACzD,MAAM,IAAI,GAAG,CAAC,GAAG,UAAU,EAAE,GAAG,MAAM,CAAC,CAAA;IACvC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAM;IAE7B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAK,UAAU,CAAC,KAA8B,CAAA;IAE1E,MAAM,OAAO,CAAC,UAAU,CACtB,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACpB,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAA;QAC9E,IAAI,EAAE,CAAC,MAAM;YAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QAC5E,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE;gBAChC,MAAM,EAAE,MAAM;gBACd,OAAO;gBACP,IAAI;gBACJ,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC;aAChD,CAAC,CAAA;YACF,qEAAqE;YACrE,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;YAChB,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,GAAG,aAAa,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;QAC3E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,GAAG,YAAY,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC9D,CAAC;IACH,CAAC,CAAC,CACH,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/lib/webhooks.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapflowio/relay",
3
- "version": "0.26.1",
3
+ "version": "0.27.1",
4
4
  "description": "WebSocket relay server for tapflow — NAT traversal, session routing, JWT auth, bundled dashboard",
5
5
  "keywords": [
6
6
  "tapflow",
@@ -49,18 +49,18 @@
49
49
  "better-sqlite3": "^12.11.1",
50
50
  "busboy": "^1.6.0",
51
51
  "jsonwebtoken": "^9.0.3",
52
- "nodemailer": "^9.1.1",
53
- "ws": "^8.21.3",
52
+ "nodemailer": "^10.0.11",
53
+ "ws": "^8.22.0",
54
54
  "zod": "^4.6.5",
55
- "@tapflowio/agent-core": "0.26.1",
56
- "@tapflowio/protocol": "0.26.1"
55
+ "@tapflowio/agent-core": "0.27.1",
56
+ "@tapflowio/protocol": "0.27.1"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/better-sqlite3": "^7.6.13",
60
60
  "@types/busboy": "^1.5.4",
61
61
  "@types/jsonwebtoken": "^9.0.10",
62
62
  "@types/node": "^22.20.4",
63
- "@types/nodemailer": "^8.0.1",
63
+ "@types/nodemailer": "^8.0.2",
64
64
  "@types/ws": "^8.0.0",
65
65
  "typescript": "^5.0.0",
66
66
  "vitest": "^4.1.11",