@kelpie/server 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/dist/app.d.ts.map +1 -1
  2. package/dist/app.js +14 -0
  3. package/dist/app.js.map +1 -1
  4. package/dist/index.d.ts +2 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/lib/appUrl.d.ts +27 -0
  9. package/dist/lib/appUrl.d.ts.map +1 -0
  10. package/dist/lib/appUrl.js +53 -0
  11. package/dist/lib/appUrl.js.map +1 -0
  12. package/dist/lib/clientIp.d.ts +24 -0
  13. package/dist/lib/clientIp.d.ts.map +1 -0
  14. package/dist/lib/clientIp.js +34 -0
  15. package/dist/lib/clientIp.js.map +1 -0
  16. package/dist/lib/config.d.ts +11 -0
  17. package/dist/lib/config.d.ts.map +1 -1
  18. package/dist/lib/config.js +23 -12
  19. package/dist/lib/config.js.map +1 -1
  20. package/dist/lib/egress.d.ts +44 -0
  21. package/dist/lib/egress.d.ts.map +1 -0
  22. package/dist/lib/egress.js +111 -0
  23. package/dist/lib/egress.js.map +1 -0
  24. package/dist/lib/email.d.ts +53 -9
  25. package/dist/lib/email.d.ts.map +1 -1
  26. package/dist/lib/email.js +49 -4
  27. package/dist/lib/email.js.map +1 -1
  28. package/dist/lib/ids.d.ts +2 -0
  29. package/dist/lib/ids.d.ts.map +1 -1
  30. package/dist/lib/ids.js +2 -0
  31. package/dist/lib/ids.js.map +1 -1
  32. package/dist/lib/rateLimit.d.ts +12 -4
  33. package/dist/lib/rateLimit.d.ts.map +1 -1
  34. package/dist/lib/rateLimit.js +6 -0
  35. package/dist/lib/rateLimit.js.map +1 -1
  36. package/dist/modules/agent-tasks/dispatch.d.ts +4 -2
  37. package/dist/modules/agent-tasks/dispatch.d.ts.map +1 -1
  38. package/dist/modules/agent-tasks/dispatch.js +4 -2
  39. package/dist/modules/agent-tasks/dispatch.js.map +1 -1
  40. package/dist/modules/agent-tasks/index.d.ts.map +1 -1
  41. package/dist/modules/agent-tasks/index.js +3 -1
  42. package/dist/modules/agent-tasks/index.js.map +1 -1
  43. package/dist/modules/auth/index.d.ts.map +1 -1
  44. package/dist/modules/auth/index.js +10 -3
  45. package/dist/modules/auth/index.js.map +1 -1
  46. package/dist/modules/auth/repository.d.ts +13 -1
  47. package/dist/modules/auth/repository.d.ts.map +1 -1
  48. package/dist/modules/auth/repository.js +32 -1
  49. package/dist/modules/auth/repository.js.map +1 -1
  50. package/dist/modules/auth/routes.d.ts.map +1 -1
  51. package/dist/modules/auth/routes.js +29 -6
  52. package/dist/modules/auth/routes.js.map +1 -1
  53. package/dist/modules/auth/schema.d.ts +130 -0
  54. package/dist/modules/auth/schema.d.ts.map +1 -1
  55. package/dist/modules/auth/schema.js +16 -0
  56. package/dist/modules/auth/schema.js.map +1 -1
  57. package/dist/modules/auth/service.d.ts +7 -1
  58. package/dist/modules/auth/service.d.ts.map +1 -1
  59. package/dist/modules/auth/service.js +53 -4
  60. package/dist/modules/auth/service.js.map +1 -1
  61. package/dist/modules/deals/repository.d.ts.map +1 -1
  62. package/dist/modules/deals/repository.js +1 -0
  63. package/dist/modules/deals/repository.js.map +1 -1
  64. package/dist/modules/decisions/repository.d.ts.map +1 -1
  65. package/dist/modules/decisions/repository.js +8 -7
  66. package/dist/modules/decisions/repository.js.map +1 -1
  67. package/dist/modules/forms/index.d.ts.map +1 -1
  68. package/dist/modules/forms/index.js +6 -1
  69. package/dist/modules/forms/index.js.map +1 -1
  70. package/dist/modules/forms/publicRoutes.d.ts +3 -0
  71. package/dist/modules/forms/publicRoutes.d.ts.map +1 -1
  72. package/dist/modules/forms/publicRoutes.js +10 -4
  73. package/dist/modules/forms/publicRoutes.js.map +1 -1
  74. package/dist/modules/forms/submission.d.ts +3 -0
  75. package/dist/modules/forms/submission.d.ts.map +1 -1
  76. package/dist/modules/forms/submission.js +6 -0
  77. package/dist/modules/forms/submission.js.map +1 -1
  78. package/dist/modules/opportunities/repository.d.ts.map +1 -1
  79. package/dist/modules/opportunities/repository.js +1 -0
  80. package/dist/modules/opportunities/repository.js.map +1 -1
  81. package/dist/modules/partnerships/repository.d.ts.map +1 -1
  82. package/dist/modules/partnerships/repository.js +1 -0
  83. package/dist/modules/partnerships/repository.js.map +1 -1
  84. package/dist/modules/raises/repository.d.ts.map +1 -1
  85. package/dist/modules/raises/repository.js +1 -0
  86. package/dist/modules/raises/repository.js.map +1 -1
  87. package/dist/modules/rate-limit/middleware.d.ts +4 -4
  88. package/dist/modules/rate-limit/middleware.d.ts.map +1 -1
  89. package/dist/modules/rate-limit/middleware.js +57 -11
  90. package/dist/modules/rate-limit/middleware.js.map +1 -1
  91. package/dist/modules/webhooks/delivery.d.ts +5 -2
  92. package/dist/modules/webhooks/delivery.d.ts.map +1 -1
  93. package/dist/modules/webhooks/delivery.js +5 -2
  94. package/dist/modules/webhooks/delivery.js.map +1 -1
  95. package/dist/modules/webhooks/index.d.ts.map +1 -1
  96. package/dist/modules/webhooks/index.js +3 -1
  97. package/dist/modules/webhooks/index.js.map +1 -1
  98. package/dist/modules/workspace/idempotencyMiddleware.d.ts.map +1 -1
  99. package/dist/modules/workspace/idempotencyMiddleware.js +14 -1
  100. package/dist/modules/workspace/idempotencyMiddleware.js.map +1 -1
  101. package/dist/modules/workspace/index.d.ts.map +1 -1
  102. package/dist/modules/workspace/index.js +3 -0
  103. package/dist/modules/workspace/index.js.map +1 -1
  104. package/dist/modules/workspace/repository.d.ts +1 -1
  105. package/dist/modules/workspace/repository.d.ts.map +1 -1
  106. package/dist/modules/workspace/repository.js +15 -9
  107. package/dist/modules/workspace/repository.js.map +1 -1
  108. package/dist/modules/workspace/routes.d.ts +0 -4
  109. package/dist/modules/workspace/routes.d.ts.map +1 -1
  110. package/dist/modules/workspace/routes.js +2 -7
  111. package/dist/modules/workspace/routes.js.map +1 -1
  112. package/dist/modules/workspace/service.d.ts +4 -2
  113. package/dist/modules/workspace/service.d.ts.map +1 -1
  114. package/dist/modules/workspace/service.js +42 -17
  115. package/dist/modules/workspace/service.js.map +1 -1
  116. package/dist/modules/workspace/tools.d.ts.map +1 -1
  117. package/dist/modules/workspace/tools.js +6 -7
  118. package/dist/modules/workspace/tools.js.map +1 -1
  119. package/dist/operator.d.ts +40 -0
  120. package/dist/operator.d.ts.map +1 -0
  121. package/dist/operator.js +50 -0
  122. package/dist/operator.js.map +1 -0
  123. package/dist/runtime/module.d.ts +25 -1
  124. package/dist/runtime/module.d.ts.map +1 -1
  125. package/dist/runtime/registry.d.ts +16 -1
  126. package/dist/runtime/registry.d.ts.map +1 -1
  127. package/dist/runtime/registry.js +34 -0
  128. package/dist/runtime/registry.js.map +1 -1
  129. package/dist/testing/client.d.ts +3 -1
  130. package/dist/testing/client.d.ts.map +1 -1
  131. package/dist/testing/client.js +19 -2
  132. package/dist/testing/client.js.map +1 -1
  133. package/dist/testing/environment.d.ts +2 -0
  134. package/dist/testing/environment.d.ts.map +1 -1
  135. package/dist/testing/environment.js +3 -0
  136. package/dist/testing/environment.js.map +1 -1
  137. package/dist/webBundle.d.ts +8 -0
  138. package/dist/webBundle.d.ts.map +1 -1
  139. package/dist/webBundle.js +9 -7
  140. package/dist/webBundle.js.map +1 -1
  141. package/migrations/0018_hard_mystique.sql +12 -0
  142. package/migrations/meta/0018_snapshot.json +5113 -0
  143. package/migrations/meta/_journal.json +8 -1
  144. package/package.json +4 -2
  145. package/src/app.ts +16 -0
  146. package/src/index.ts +9 -1
  147. package/src/lib/appUrl.ts +64 -0
  148. package/src/lib/clientIp.ts +41 -0
  149. package/src/lib/config.ts +30 -12
  150. package/src/lib/egress.ts +149 -0
  151. package/src/lib/email.ts +75 -7
  152. package/src/lib/ids.ts +2 -0
  153. package/src/lib/rateLimit.ts +16 -4
  154. package/src/modules/agent-tasks/dispatch.ts +9 -2
  155. package/src/modules/agent-tasks/index.ts +3 -1
  156. package/src/modules/auth/index.ts +12 -5
  157. package/src/modules/auth/repository.ts +56 -1
  158. package/src/modules/auth/routes.ts +34 -6
  159. package/src/modules/auth/schema.ts +17 -0
  160. package/src/modules/auth/service.ts +78 -5
  161. package/src/modules/deals/repository.ts +1 -0
  162. package/src/modules/decisions/repository.ts +8 -7
  163. package/src/modules/forms/index.ts +6 -1
  164. package/src/modules/forms/publicRoutes.ts +14 -4
  165. package/src/modules/forms/submission.ts +10 -0
  166. package/src/modules/opportunities/repository.ts +1 -0
  167. package/src/modules/partnerships/repository.ts +1 -0
  168. package/src/modules/raises/repository.ts +1 -0
  169. package/src/modules/rate-limit/middleware.ts +74 -11
  170. package/src/modules/webhooks/delivery.ts +10 -2
  171. package/src/modules/webhooks/index.ts +3 -1
  172. package/src/modules/workspace/idempotencyMiddleware.ts +17 -1
  173. package/src/modules/workspace/index.ts +4 -0
  174. package/src/modules/workspace/repository.ts +15 -8
  175. package/src/modules/workspace/routes.ts +0 -8
  176. package/src/modules/workspace/service.ts +53 -20
  177. package/src/modules/workspace/tools.ts +7 -21
  178. package/src/runtime/module.ts +25 -1
  179. package/src/runtime/registry.ts +59 -1
  180. package/src/testing/client.ts +22 -2
  181. package/src/testing/environment.ts +4 -0
  182. package/src/webBundle.ts +21 -7
package/dist/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAGnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAItD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AAQ3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAEhE;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IACpD,oEAAoE;IACpE,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAA;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAA;IAC5C,4DAA4D;IAC5D,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAA;IACzC,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAA;CACvD;AAED,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE;QACT,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;CACF;AAqBD,wBAAgB,SAAS,CAAC,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,CAyH1E"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAGnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAItD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AAQ3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAEhE;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IACpD,oEAAoE;IACpE,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAA;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAA;IAC5C,4DAA4D;IAC5D,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAA;IACzC,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAA;CACvD;AAED,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE;QACT,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;CACF;AAqBD,wBAAgB,SAAS,CAAC,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,CAyI1E"}
package/dist/app.js CHANGED
@@ -99,6 +99,20 @@ export function createApp(dependencies) {
99
99
  app.use(MCP_ROUTE_PREFIX, createAuthAndApiRateLimitMiddleware(rateLimitDependencies));
100
100
  app.route(MCP_ROUTE_PREFIX, mcp.transport);
101
101
  app.route('/v1', mcp.catalog);
102
+ // Module declarations on the app itself, outside /v1 (`runtime/module.ts`).
103
+ // Middleware first, all of it, then routes: within one request Hono
104
+ // composes matching handlers in registration order, so this is what makes
105
+ // a declared pattern cover matching routes from every module, whichever
106
+ // registered first. Registered after core's own surfaces above, so nothing
107
+ // here can run ahead of them. Not rate limited: the `/v1` budgets are
108
+ // per-workspace-credential, and a declared surface owns its own access
109
+ // rules.
110
+ for (const middleware of dependencies.contributions.appMiddleware) {
111
+ app.use(middleware.pattern, middleware.handler);
112
+ }
113
+ for (const route of dependencies.contributions.appRoutes) {
114
+ app.on(route.method, route.path, route.handler);
115
+ }
102
116
  app.onError((error, context) => {
103
117
  if (error instanceof AppError) {
104
118
  return context.json(toErrorBody(error), error.status);
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGhC,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAI9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAA;AAEpE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC5F,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EACL,mCAAmC,EACnC,mCAAmC,GACpC,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAA;AA2C1F,MAAM,iBAAiB,GAAG,cAAc,CAAA;AAExC;;;;;;;;GAQG;AACH,MAAM,WAAW,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,GAAG;IACX,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC;IACxC,YAAY,EAAE,CAAC,cAAc,CAAC;IAC9B,WAAW,EAAE,KAAK;IAClB,MAAM,EAAE,MAAM;CACf,CAAC,CAAA;AAEF,MAAM,UAAU,SAAS,CAAC,YAA6B;IACrD,MAAM,iBAAiB,GAAG,YAAY,CAAC,iBAAiB,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAA;IACvF,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,IAAI,eAAe,EAAE,CAAA;IAC3D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAe,CAAA;IAEnC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QACnC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,iBAAiB,EAAE,CAAA;QAC9E,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,CAAA;QAEvD,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACnC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QAC7B,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAA;QAE5C,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QACnC,MAAM,IAAI,EAAE,CAAA;QAEZ,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE;YACrB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM;YAC1B,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI;YACtB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM;YAC1B,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;SACtD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAA;IAEvC,MAAM,qBAAqB,GAAG;QAC5B,EAAE,EAAE,YAAY,CAAC,WAAW,CAAC,EAAE;QAC/B,GAAG,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG;QACjC,QAAQ;QACR,WAAW,EAAE,YAAY,CAAC,WAAW;QACrC,eAAe,EAAE,YAAY,CAAC,eAAe;QAC7C,MAAM,EAAE,YAAY,CAAC,SAAS;KAC/B,CAAA;IAED,oEAAoE;IACpE,wEAAwE;IACxE,yEAAyE;IACzE,6CAA6C;IAC7C,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,mCAAmC,CAAC,qBAAqB,CAAC,CAAC,CAAA;IAE5E,8EAA8E;IAC9E,8EAA8E;IAC9E,2EAA2E;IAC3E,0CAA0C;IAC1C,GAAG,CAAC,GAAG,CACL,OAAO,EACP,2BAA2B,CAAC;QAC1B,EAAE,EAAE,YAAY,CAAC,WAAW,CAAC,EAAE;QAC/B,GAAG,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG;QACjC,QAAQ;QACR,WAAW,EAAE,YAAY,CAAC,WAAW;QACrC,GAAG,EAAE,YAAY,CAAC,MAAM;KACzB,CAAC,CACH,CAAA;IAED,4EAA4E;IAC5E,8EAA8E;IAC9E,sEAAsE;IACtE,GAAG,CAAC,GAAG,CAAC,GAAG,mBAAmB,IAAI,EAAE,WAAW,CAAC,CAAA;IAEhD,6EAA6E;IAC7E,wEAAwE;IACxE,yEAAyE;IACzE,GAAG,CAAC,GAAG,CAAC,GAAG,mBAAmB,IAAI,EAAE,mCAAmC,CAAC,qBAAqB,CAAC,CAAC,CAAA;IAE/F,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,YAAY,CAAC,aAAa,CAAC,aAAa,EAAE,CAAC;QAClE,GAAG,CAAC,KAAK,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAA;IACxC,CAAC;IAED,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,YAAY,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;QAC5D,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAC1B,CAAC;IAED,MAAM,GAAG,GAAG,iBAAiB,CAAC;QAC5B,GAAG,YAAY,CAAC,WAAW;QAC3B,KAAK,EAAE,YAAY,CAAC,aAAa,CAAC,QAAQ;QAC1C,UAAU,EAAE,eAAe;QAC3B,YAAY,EAAE,gBAAgB;QAC9B,MAAM,EAAE,YAAY,CAAC,MAAM;KAC5B,CAAC,CAAA;IAEF,sEAAsE;IACtE,qEAAqE;IACrE,yEAAyE;IACzE,yEAAyE;IACzE,2EAA2E;IAC3E,qEAAqE;IACrE,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,mCAAmC,CAAC,qBAAqB,CAAC,CAAC,CAAA;IAErF,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,GAAG,CAAC,SAAS,CAAC,CAAA;IAC1C,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IAE7B,4EAA4E;IAC5E,oEAAoE;IACpE,0EAA0E;IAC1E,wEAAwE;IACxE,2EAA2E;IAC3E,sEAAsE;IACtE,uEAAuE;IACvE,SAAS;IACT,KAAK,MAAM,UAAU,IAAI,YAAY,CAAC,aAAa,CAAC,aAAa,EAAE,CAAC;QAClE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;IACjD,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC;QACzD,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;IACjD,CAAC;IAED,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QAC7B,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;YAC9B,OAAO,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;QACvD,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,iBAAiB,EAAE;YAC7C,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM;YAC1B,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI;YACtB,KAAK,EAAE,KAAK,CAAC,OAAO;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC,CAAA;QACF,OAAO,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,GAAG,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;IAE9E,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACpC,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,aAAa,EAAE,CAAA;QAEhD,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,sBAAsB,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;YAC7E,OAAO,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,CAAA;QACpE,CAAC;QAED,OAAO,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,GAAG,CAAC,CAAA;IAC5D,CAAC,CAAC,CAAA;IAEF,OAAO,GAAG,CAAA;AACZ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export { WebBundleError, serveWebBundle } from './webBundle.ts';
4
4
  export type { WebBundleOptions } from './webBundle.ts';
5
5
  export { ConfigurationError, loadConfig } from './lib/config.ts';
6
6
  export type { Environment, KelpieConfig, LogLevel, RuntimeMode } from './lib/config.ts';
7
+ export { resolveClientIpFrom } from './lib/clientIp.ts';
7
8
  export { ModuleConfigFileError, readModuleConfigFile } from './lib/moduleConfig.ts';
8
9
  export { FOREIGN_KEY_VIOLATION, RESTRICT_VIOLATION, UNIQUE_VIOLATION, connectDatabase, isReferenceViolation, postgresErrorCode, } from './lib/database.ts';
9
10
  export type { Database, DatabaseConnection, DatabaseProbe } from './lib/database.ts';
@@ -37,7 +38,7 @@ export type { ResealColumnOutcome, ResealOutcome } from './modules/reseal.ts';
37
38
  export { KEY_KINDS, kindOfSecret, mintKey, parseKeyKind, readBearerToken } from './modules/api-keys/keys.ts';
38
39
  export type { KeyKind, MintedKey } from './modules/api-keys/keys.ts';
39
40
  export { registerModules } from './runtime/registry.ts';
40
- export type { ModuleContributions, ModuleRouter, ModuleRuntimeOptions } from './runtime/registry.ts';
41
+ export type { AppMiddlewareContribution, AppRouteContribution, ModuleContributions, ModuleRouter, ModuleRuntimeOptions, } from './runtime/registry.ts';
41
42
  export type { ModuleServices } from './runtime/module.ts';
42
43
  export type { Actor, ApiKeyActor, SessionActor } from './modules/auth/actor.ts';
43
44
  export { actorUserId, actorWorkspaceId, requireSessionActor } from './modules/auth/actor.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { createApp } from './app.js';
2
2
  export { WebBundleError, serveWebBundle } from './webBundle.js';
3
3
  export { ConfigurationError, loadConfig } from './lib/config.js';
4
+ export { resolveClientIpFrom } from './lib/clientIp.js';
4
5
  export { ModuleConfigFileError, readModuleConfigFile } from './lib/moduleConfig.js';
5
6
  export { FOREIGN_KEY_VIOLATION, RESTRICT_VIOLATION, UNIQUE_VIOLATION, connectDatabase, isReferenceViolation, postgresErrorCode, } from './lib/database.js';
6
7
  export * as schema from './schema/index.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGpC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAG/D,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAGhE,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAEnF,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAA;AAE3C,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAG3F,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAClH,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAE5E,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,uBAAuB,EACvB,iBAAiB,EACjB,WAAW,EACX,cAAc,GACf,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAa9C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAElE,OAAO,EAAE,yBAAyB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAUlG,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAEjE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAU7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AASjE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGpE,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAExE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAGzD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAG5G,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAKvD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAC5F,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAE9E,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGpC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAG/D,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAGhE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAEvD,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAEnF,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAA;AAE3C,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAG3F,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAClH,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAE5E,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,uBAAuB,EACvB,iBAAiB,EACjB,WAAW,EACX,cAAc,GACf,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAa9C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAElE,OAAO,EAAE,yBAAyB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAUlG,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAEjE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAU7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AASjE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGpE,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAExE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAGzD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAG5G,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAWvD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAC5F,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAE9E,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA"}
@@ -0,0 +1,27 @@
1
+ import { z } from 'zod';
2
+ /** The one variable the auth and workspace modules read to build their links. */
3
+ export declare const appUrlConfigSchema: z.ZodObject<{
4
+ APP_BASE_URL: z.ZodString;
5
+ }, z.core.$strip>;
6
+ export type AppUrlConfig = z.infer<typeof appUrlConfigSchema>;
7
+ /**
8
+ * The browser app's routes for each token-carrying link. They match the paths
9
+ * the single-page app serves (`packages/ui`), so a link built here reaches a
10
+ * real page once that bundle is deployed at `APP_BASE_URL`.
11
+ */
12
+ export declare const APP_LINK_PATHS: {
13
+ readonly passwordReset: '/reset-password';
14
+ readonly verifyEmail: '/verify-email';
15
+ readonly inviteAccept: '/join';
16
+ };
17
+ /**
18
+ * Builds a link at the deployment's base URL, carrying the token as a query
19
+ * parameter.
20
+ *
21
+ * `new URL(path, baseUrl)` resolves the path against the base, so a base with a
22
+ * trailing slash and one without give the same result. The token is base64url
23
+ * and needs no escaping. `searchParams` encodes it regardless, rather than trust
24
+ * that.
25
+ */
26
+ export declare function buildAppLink(baseUrl: string, path: string, token: string): string;
27
+ //# sourceMappingURL=appUrl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appUrl.d.ts","sourceRoot":"","sources":["../../src/lib/appUrl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA8BvB,iFAAiF;AACjF,eAAO,MAAM,kBAAkB;;iBAE7B,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAE7D;;;;GAIG;AACH,eAAO,MAAM,cAAc;aACzB,aAAa,EAAE,iBAAiB;aAChC,WAAW,EAAE,eAAe;aAC5B,YAAY,EAAE,OAAO;CACb,CAAA;AAEV;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjF"}
@@ -0,0 +1,53 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * The deployment's own base URL, and how token links in transactional mail are
4
+ * built from it.
5
+ *
6
+ * The service builds every reset, verification, and invite link itself, from a
7
+ * configured base URL. It does not build them from a URL the caller sends. A
8
+ * caller-supplied link lets anyone point a real Kelpie email at any address,
9
+ * which is an account-takeover path. The base URL is set once per deployment,
10
+ * beside the database URL and the mail provider.
11
+ */
12
+ const APP_BASE_URL_MESSAGE = 'must be an absolute http:// or https:// URL, e.g. https://crm.example.com';
13
+ /** True when the value is an absolute http(s) URL with no embedded credentials. */
14
+ function isValidBaseUrl(value) {
15
+ let url;
16
+ try {
17
+ url = new URL(value);
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ const protocolAllowed = url.protocol === 'http:' || url.protocol === 'https:';
23
+ return protocolAllowed && url.username.length === 0 && url.password.length === 0;
24
+ }
25
+ /** The one variable the auth and workspace modules read to build their links. */
26
+ export const appUrlConfigSchema = z.object({
27
+ APP_BASE_URL: z.string().refine(isValidBaseUrl, { message: APP_BASE_URL_MESSAGE }),
28
+ });
29
+ /**
30
+ * The browser app's routes for each token-carrying link. They match the paths
31
+ * the single-page app serves (`packages/ui`), so a link built here reaches a
32
+ * real page once that bundle is deployed at `APP_BASE_URL`.
33
+ */
34
+ export const APP_LINK_PATHS = {
35
+ passwordReset: '/reset-password',
36
+ verifyEmail: '/verify-email',
37
+ inviteAccept: '/join',
38
+ };
39
+ /**
40
+ * Builds a link at the deployment's base URL, carrying the token as a query
41
+ * parameter.
42
+ *
43
+ * `new URL(path, baseUrl)` resolves the path against the base, so a base with a
44
+ * trailing slash and one without give the same result. The token is base64url
45
+ * and needs no escaping. `searchParams` encodes it regardless, rather than trust
46
+ * that.
47
+ */
48
+ export function buildAppLink(baseUrl, path, token) {
49
+ const url = new URL(path, baseUrl);
50
+ url.searchParams.set('token', token);
51
+ return url.toString();
52
+ }
53
+ //# sourceMappingURL=appUrl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appUrl.js","sourceRoot":"","sources":["../../src/lib/appUrl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;;;GASG;AAEH,MAAM,oBAAoB,GAAG,2EAA2E,CAAA;AAExG,mFAAmF;AACnF,SAAS,cAAc,CAAC,KAAa;IACnC,IAAI,GAAQ,CAAA;IAEZ,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;IAED,MAAM,eAAe,GAAG,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAA;IAE7E,OAAO,eAAe,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAA;AAClF,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACnF,CAAC,CAAA;AAIF;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,aAAa,EAAE,iBAAiB;IAChC,WAAW,EAAE,eAAe;IAC5B,YAAY,EAAE,OAAO;CACb,CAAA;AAEV;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,IAAY,EAAE,KAAa;IACvE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAElC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAEpC,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAA;AACvB,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Resolving the caller's IP when the service sits behind trusted proxies.
3
+ *
4
+ * The rate limiter keys on this, so trusting it wrongly matters both ways: read a
5
+ * forgeable header and an attacker rotates it to dodge the limit; ignore a real
6
+ * proxy and every caller collapses into one bucket behind the load balancer.
7
+ *
8
+ * The deployment states how many proxies stand in front of it
9
+ * (`TRUSTED_PROXY_HOP_COUNT`). Zero, the default, means the service is reached
10
+ * directly and the socket address is the client. A positive count means the last
11
+ * N entries of `X-Forwarded-For` were written by infrastructure this deployment
12
+ * controls, so the entry just left of them is the client as the outermost trusted
13
+ * proxy saw it, which no earlier hop could forge.
14
+ */
15
+ /**
16
+ * @param socketAddress The address the TCP connection arrived from.
17
+ * @param forwardedFor The raw `X-Forwarded-For` header, or undefined.
18
+ * @param hopCount How many trusted proxies stand in front of the service.
19
+ * @returns The client's IP. Falls back to the socket address whenever the header
20
+ * is absent or holds fewer entries than the configured hop count, so a
21
+ * misconfiguration over-limits rather than trusts a forgeable position.
22
+ */
23
+ export declare function resolveClientIpFrom(socketAddress: string, forwardedFor: string | undefined, hopCount: number): string;
24
+ //# sourceMappingURL=clientIp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientIp.d.ts","sourceRoot":"","sources":["../../src/lib/clientIp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,QAAQ,EAAE,MAAM,GACf,MAAM,CAaR"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Resolving the caller's IP when the service sits behind trusted proxies.
3
+ *
4
+ * The rate limiter keys on this, so trusting it wrongly matters both ways: read a
5
+ * forgeable header and an attacker rotates it to dodge the limit; ignore a real
6
+ * proxy and every caller collapses into one bucket behind the load balancer.
7
+ *
8
+ * The deployment states how many proxies stand in front of it
9
+ * (`TRUSTED_PROXY_HOP_COUNT`). Zero, the default, means the service is reached
10
+ * directly and the socket address is the client. A positive count means the last
11
+ * N entries of `X-Forwarded-For` were written by infrastructure this deployment
12
+ * controls, so the entry just left of them is the client as the outermost trusted
13
+ * proxy saw it, which no earlier hop could forge.
14
+ */
15
+ /**
16
+ * @param socketAddress The address the TCP connection arrived from.
17
+ * @param forwardedFor The raw `X-Forwarded-For` header, or undefined.
18
+ * @param hopCount How many trusted proxies stand in front of the service.
19
+ * @returns The client's IP. Falls back to the socket address whenever the header
20
+ * is absent or holds fewer entries than the configured hop count, so a
21
+ * misconfiguration over-limits rather than trusts a forgeable position.
22
+ */
23
+ export function resolveClientIpFrom(socketAddress, forwardedFor, hopCount) {
24
+ if (hopCount <= 0 || forwardedFor === undefined) {
25
+ return socketAddress;
26
+ }
27
+ const entries = forwardedFor
28
+ .split(',')
29
+ .map((entry) => entry.trim())
30
+ .filter((entry) => entry.length > 0);
31
+ const index = entries.length - hopCount;
32
+ return index >= 0 ? (entries[index] ?? socketAddress) : socketAddress;
33
+ }
34
+ //# sourceMappingURL=clientIp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientIp.js","sourceRoot":"","sources":["../../src/lib/clientIp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,aAAqB,EACrB,YAAgC,EAChC,QAAgB;IAEhB,IAAI,QAAQ,IAAI,CAAC,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAChD,OAAO,aAAa,CAAA;IACtB,CAAC;IAED,MAAM,OAAO,GAAG,YAAY;SACzB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAEtC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAA;IAEvC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAA;AACvE,CAAC"}
@@ -28,6 +28,12 @@ export interface KelpieConfig {
28
28
  */
29
29
  readonly webBundleDirectory: string | undefined;
30
30
  readonly rateLimit: RateLimitConfig;
31
+ /**
32
+ * How many trusted proxies stand in front of the service. Zero means it is
33
+ * reached directly and the socket address is the client. Positive means the
34
+ * client IP is read from `X-Forwarded-For` (`lib/clientIp.ts`).
35
+ */
36
+ readonly trustedProxyHopCount: number;
31
37
  }
32
38
  /** Thrown at boot when the environment cannot produce a valid configuration. */
33
39
  export declare class ConfigurationError extends Error {
@@ -37,6 +43,11 @@ export declare class ConfigurationError extends Error {
37
43
  /**
38
44
  * Parses an environment into a validated config.
39
45
  *
46
+ * `emailConfigSchema` is a discriminated union, so it is parsed separately
47
+ * from the rest: a union has no flat `.shape` to spread into `environmentSchema`,
48
+ * only its own `EMAIL_PROVIDER`-keyed branches. Problems from both parses are
49
+ * combined into one error, preserving the "every missing variable at once" rule.
50
+ *
40
51
  * @param environment Raw variables, normally `process.env`.
41
52
  * @throws ConfigurationError listing every invalid or missing variable.
42
53
  */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD;;;;GAIG;AAEH,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;AAEtE,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,MAAM,GAAG,YAAY,CAAA;AAE/D,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAE1D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/C,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;CACpC;AAED,gFAAgF;AAChF,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IAEpC,YAAY,QAAQ,EAAE,SAAS,MAAM,EAAE,EAItC;CACF;AAwBD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,WAAW,GAAG,YAAY,CAiBjE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD;;;;GAIG;AAEH,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;AAEtE,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,MAAM,GAAG,YAAY,CAAA;AAE/D,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAE1D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/C,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;IACnC;;;;OAIG;IACH,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAA;CACtC;AAED,gFAAgF;AAChF,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IAEpC,YAAY,QAAQ,EAAE,SAAS,MAAM,EAAE,EAItC;CACF;AAwBD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,WAAW,GAAG,YAAY,CAwBjE"}
@@ -29,29 +29,40 @@ const environmentSchema = z.object({
29
29
  LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']),
30
30
  KELPIE_MODULE_CONFIG_PATH: z.string().min(1).optional(),
31
31
  WEB_BUNDLE_DIR: z.string().min(1).optional(),
32
- ...emailConfigSchema.shape,
32
+ TRUSTED_PROXY_HOP_COUNT: z.coerce.number().int().nonnegative().default(0),
33
33
  ...rateLimitConfigSchema.shape,
34
34
  });
35
35
  /**
36
36
  * Parses an environment into a validated config.
37
37
  *
38
+ * `emailConfigSchema` is a discriminated union, so it is parsed separately
39
+ * from the rest: a union has no flat `.shape` to spread into `environmentSchema`,
40
+ * only its own `EMAIL_PROVIDER`-keyed branches. Problems from both parses are
41
+ * combined into one error, preserving the "every missing variable at once" rule.
42
+ *
38
43
  * @param environment Raw variables, normally `process.env`.
39
44
  * @throws ConfigurationError listing every invalid or missing variable.
40
45
  */
41
46
  export function loadConfig(environment) {
42
- const result = environmentSchema.safeParse(environment);
43
- if (!result.success) {
44
- throw new ConfigurationError(result.error.issues.map(describeValidationIssue));
47
+ const environmentResult = environmentSchema.safeParse(environment);
48
+ const emailResult = emailConfigSchema.safeParse(environment);
49
+ if (!environmentResult.success || !emailResult.success) {
50
+ const problems = [
51
+ ...(environmentResult.success ? [] : environmentResult.error.issues.map(describeValidationIssue)),
52
+ ...(emailResult.success ? [] : emailResult.error.issues.map(describeValidationIssue)),
53
+ ];
54
+ throw new ConfigurationError(problems);
45
55
  }
46
56
  return {
47
- runtimeMode: result.data.NODE_ENV,
48
- port: result.data.PORT,
49
- databaseUrl: result.data.DATABASE_URL,
50
- logLevel: result.data.LOG_LEVEL,
51
- email: { EMAIL_PROVIDER: result.data.EMAIL_PROVIDER, EMAIL_FROM: result.data.EMAIL_FROM },
52
- moduleConfigPath: result.data.KELPIE_MODULE_CONFIG_PATH,
53
- webBundleDirectory: result.data.WEB_BUNDLE_DIR,
54
- rateLimit: rateLimitConfigFrom(result.data),
57
+ runtimeMode: environmentResult.data.NODE_ENV,
58
+ port: environmentResult.data.PORT,
59
+ databaseUrl: environmentResult.data.DATABASE_URL,
60
+ logLevel: environmentResult.data.LOG_LEVEL,
61
+ email: emailResult.data,
62
+ moduleConfigPath: environmentResult.data.KELPIE_MODULE_CONFIG_PATH,
63
+ webBundleDirectory: environmentResult.data.WEB_BUNDLE_DIR,
64
+ rateLimit: rateLimitConfigFrom(environmentResult.data),
65
+ trustedProxyHopCount: environmentResult.data.TRUSTED_PROXY_HOP_COUNT,
55
66
  };
56
67
  }
57
68
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAqC3E,gFAAgF;AAChF,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,QAAQ,CAAmB;IAEpC,YAAY,QAA2B;QACrC,KAAK,CAAC,uCAAuC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACtG,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAA;QAChC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,CAAC;CACF;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QACnC,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,aAAa,CAAA;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;IACvD,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;IACnD,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,MAAM,CAAC,aAAa,EAAE,EAAE,OAAO,EAAE,0DAA0D,EAAE,CAAC;IACjG,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACrD,yBAAyB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACvD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC5C,GAAG,iBAAiB,CAAC,KAAK;IAC1B,GAAG,qBAAqB,CAAC,KAAK;CAC/B,CAAC,CAAA;AAEF;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,WAAwB;IACjD,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;IAEvD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAA;IAChF,CAAC;IAED,OAAO;QACL,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ;QACjC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI;QACtB,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY;QACrC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS;QAC/B,KAAK,EAAE,EAAE,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE;QACzF,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,yBAAyB;QACvD,kBAAkB,EAAE,MAAM,CAAC,IAAI,CAAC,cAAc;QAC9C,SAAS,EAAE,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC;KAC5C,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * An optional guard against outbound POSTs to private or reserved addresses.
4
+ *
5
+ * Webhook and agent endpoints are customer-supplied, and a self-hosted Kelpie
6
+ * legitimately posts to an internal host such as `http://automation.internal`.
7
+ * So the guard is off by default (`lib/url.ts` says the same). A hosted
8
+ * deployment, where a customer must not be able to aim a delivery at the
9
+ * metadata service or a neighbour's database, sets `BLOCK_PRIVATE_EGRESS=true`.
10
+ *
11
+ * The check resolves the host and refuses the request when any resolved address
12
+ * is loopback, private, link-local, unique-local, or otherwise reserved. It runs
13
+ * just before the fetch. That leaves a narrow rebinding window between this
14
+ * lookup and the connection's own; the senders already pass `redirect: 'manual'`,
15
+ * which closes the redirect-based bypass, and a hosted deployment pairs this with
16
+ * network-level egress rules. It is defence in depth, not the only defence.
17
+ */
18
+ export declare const egressConfigSchema: z.ZodObject<{
19
+ BLOCK_PRIVATE_EGRESS: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
20
+ false: "false";
21
+ true: "true";
22
+ }>>, z.ZodTransform<boolean, "false" | "true">>;
23
+ }, z.core.$strip>;
24
+ export type EgressConfig = z.infer<typeof egressConfigSchema>;
25
+ /** Thrown when a target resolves to an address the guard refuses. */
26
+ export declare class BlockedEgressError extends Error {
27
+ constructor(host: string, address: string);
28
+ }
29
+ export interface EgressGuard {
30
+ /**
31
+ * @throws BlockedEgressError when the URL's host resolves to a private or
32
+ * reserved address. Resolves normally when the guard is off, or when every
33
+ * resolved address is public.
34
+ */
35
+ check(url: string): Promise<void>;
36
+ }
37
+ /**
38
+ * Builds the guard. When `BLOCK_PRIVATE_EGRESS` is false the guard is a no-op, so
39
+ * a self-hosted deployment keeps reaching its internal endpoints.
40
+ *
41
+ * @param resolveHost Injected so a test can classify a host without real DNS.
42
+ */
43
+ export declare function createEgressGuard(config: EgressConfig, resolveHost?: (host: string) => Promise<readonly string[]>): EgressGuard;
44
+ //# sourceMappingURL=egress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"egress.d.ts","sourceRoot":"","sources":["../../src/lib/egress.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,kBAAkB;;;;;iBAK7B,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAE7D,qEAAqE;AACrE,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAGxC;CACF;AAoED,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,YAAY,EACpB,WAAW,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,MAAM,EAAE,CAAsB,GAC7E,WAAW,CAoBb"}
@@ -0,0 +1,111 @@
1
+ import { lookup } from 'node:dns/promises';
2
+ import { isIP } from 'node:net';
3
+ import { z } from 'zod';
4
+ /**
5
+ * An optional guard against outbound POSTs to private or reserved addresses.
6
+ *
7
+ * Webhook and agent endpoints are customer-supplied, and a self-hosted Kelpie
8
+ * legitimately posts to an internal host such as `http://automation.internal`.
9
+ * So the guard is off by default (`lib/url.ts` says the same). A hosted
10
+ * deployment, where a customer must not be able to aim a delivery at the
11
+ * metadata service or a neighbour's database, sets `BLOCK_PRIVATE_EGRESS=true`.
12
+ *
13
+ * The check resolves the host and refuses the request when any resolved address
14
+ * is loopback, private, link-local, unique-local, or otherwise reserved. It runs
15
+ * just before the fetch. That leaves a narrow rebinding window between this
16
+ * lookup and the connection's own; the senders already pass `redirect: 'manual'`,
17
+ * which closes the redirect-based bypass, and a hosted deployment pairs this with
18
+ * network-level egress rules. It is defence in depth, not the only defence.
19
+ */
20
+ export const egressConfigSchema = z.object({
21
+ BLOCK_PRIVATE_EGRESS: z
22
+ .enum(['true', 'false'])
23
+ .default('false')
24
+ .transform((value) => value === 'true'),
25
+ });
26
+ /** Thrown when a target resolves to an address the guard refuses. */
27
+ export class BlockedEgressError extends Error {
28
+ constructor(host, address) {
29
+ super(`Refusing to connect to ${host}: ${address} is a private or reserved address`);
30
+ this.name = 'BlockedEgressError';
31
+ }
32
+ }
33
+ /** True for an IPv4 address in a loopback, private, link-local, or reserved range. */
34
+ function isPrivateIpv4(ip) {
35
+ const parts = ip.split('.').map((part) => Number(part));
36
+ if (parts.length !== 4 || parts.some((part) => Number.isNaN(part) || part < 0 || part > 255)) {
37
+ return false;
38
+ }
39
+ const [a, b] = parts;
40
+ if (a === 0 || a === 10 || a === 127) {
41
+ return true;
42
+ }
43
+ if (a === 169 && b === 254) {
44
+ // Link-local, which is where the cloud metadata service (169.254.169.254) lives.
45
+ return true;
46
+ }
47
+ if (a === 172 && b >= 16 && b <= 31) {
48
+ return true;
49
+ }
50
+ if (a === 192 && b === 168) {
51
+ return true;
52
+ }
53
+ if (a === 100 && b >= 64 && b <= 127) {
54
+ // Carrier-grade NAT.
55
+ return true;
56
+ }
57
+ // Multicast (224.0.0.0/4) and reserved (240.0.0.0/4), including broadcast.
58
+ return a >= 224;
59
+ }
60
+ /** True for an IPv6 address in a loopback, unspecified, link-local, or unique-local range. */
61
+ function isPrivateIpv6(ip) {
62
+ const lower = ip.toLowerCase();
63
+ if (lower === '::1' || lower === '::') {
64
+ return true;
65
+ }
66
+ const mapped = /^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/u.exec(lower);
67
+ if (mapped?.[1] !== undefined) {
68
+ // An IPv4 address written in IPv6 form resolves by its IPv4 rules.
69
+ return isPrivateIpv4(mapped[1]);
70
+ }
71
+ const firstHextet = Number.parseInt(lower.split(':')[0] || '0', 16);
72
+ // fe80::/10 link-local.
73
+ if ((firstHextet & 0xffc0) === 0xfe80) {
74
+ return true;
75
+ }
76
+ // fc00::/7 unique-local.
77
+ return (firstHextet & 0xfe00) === 0xfc00;
78
+ }
79
+ function isPrivateAddress(ip) {
80
+ return isIP(ip) === 6 ? isPrivateIpv6(ip) : isPrivateIpv4(ip);
81
+ }
82
+ /**
83
+ * Builds the guard. When `BLOCK_PRIVATE_EGRESS` is false the guard is a no-op, so
84
+ * a self-hosted deployment keeps reaching its internal endpoints.
85
+ *
86
+ * @param resolveHost Injected so a test can classify a host without real DNS.
87
+ */
88
+ export function createEgressGuard(config, resolveHost = defaultResolveHost) {
89
+ if (!config.BLOCK_PRIVATE_EGRESS) {
90
+ return { check: () => Promise.resolve() };
91
+ }
92
+ return {
93
+ async check(url) {
94
+ const host = new URL(url).hostname;
95
+ // A bracketed IPv6 literal arrives with its brackets; `URL.hostname` keeps
96
+ // them, and `isIP` wants them gone.
97
+ const bareHost = host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host;
98
+ const addresses = isIP(bareHost) !== 0 ? [bareHost] : await resolveHost(bareHost);
99
+ for (const address of addresses) {
100
+ if (isPrivateAddress(address)) {
101
+ throw new BlockedEgressError(host, address);
102
+ }
103
+ }
104
+ },
105
+ };
106
+ }
107
+ async function defaultResolveHost(host) {
108
+ const results = await lookup(host, { all: true });
109
+ return results.map((result) => result.address);
110
+ }
111
+ //# sourceMappingURL=egress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"egress.js","sourceRoot":"","sources":["../../src/lib/egress.ts"],"names":[],"mappings":"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"}