@brokr/sdk 1.0.0 → 2.1.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 (298) hide show
  1. package/dist/account.js +34 -0
  2. package/dist/account.mjs +7 -0
  3. package/dist/auth.js +628 -114
  4. package/dist/auth.mjs +611 -111
  5. package/dist/chat.js +34 -0
  6. package/dist/chat.mjs +7 -0
  7. package/dist/events.js +64 -0
  8. package/dist/events.mjs +37 -0
  9. package/dist/feature.js +6304 -0
  10. package/dist/feature.mjs +6278 -0
  11. package/dist/files.js +428 -0
  12. package/dist/files.mjs +408 -0
  13. package/dist/index.d.ts +18 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +4069 -454
  16. package/dist/index.mjs +4040 -448
  17. package/dist/logs.js +148 -0
  18. package/dist/logs.mjs +124 -0
  19. package/dist/management.js +14 -13
  20. package/dist/management.mjs +14 -13
  21. package/dist/next.js +2725 -0
  22. package/dist/next.mjs +2710 -0
  23. package/dist/notifications.js +140 -0
  24. package/dist/notifications.mjs +110 -0
  25. package/dist/payments.js +32 -0
  26. package/dist/payments.mjs +7 -0
  27. package/dist/react-notifications.js +299 -0
  28. package/dist/react-notifications.mjs +267 -0
  29. package/dist/react-styles.js +2756 -0
  30. package/dist/react-styles.mjs +2720 -0
  31. package/dist/react-theme.js +4196 -0
  32. package/dist/react-theme.mjs +4172 -0
  33. package/dist/react.js +8591 -209
  34. package/dist/react.mjs +8571 -183
  35. package/dist/runtime.js +2113 -385
  36. package/dist/runtime.mjs +2085 -397
  37. package/dist/src/account/config.d.ts +42 -0
  38. package/dist/src/account/config.d.ts.map +1 -0
  39. package/dist/src/account/index.d.ts +3 -0
  40. package/dist/src/account/index.d.ts.map +1 -0
  41. package/dist/src/ai/client.d.ts +58 -0
  42. package/dist/src/ai/client.d.ts.map +1 -0
  43. package/dist/src/ai/conversation-title.d.ts +13 -0
  44. package/dist/src/ai/conversation-title.d.ts.map +1 -0
  45. package/dist/src/ai/types.d.ts +81 -0
  46. package/dist/src/ai/types.d.ts.map +1 -0
  47. package/dist/src/auth.d.ts +133 -20
  48. package/dist/src/auth.d.ts.map +1 -1
  49. package/dist/src/chat/config.d.ts +61 -0
  50. package/dist/src/chat/config.d.ts.map +1 -0
  51. package/dist/src/chat/index.d.ts +3 -0
  52. package/dist/src/chat/index.d.ts.map +1 -0
  53. package/dist/src/chat/sse-parser.d.ts +44 -0
  54. package/dist/src/chat/sse-parser.d.ts.map +1 -0
  55. package/dist/src/dev-console.d.ts +18 -0
  56. package/dist/src/dev-console.d.ts.map +1 -0
  57. package/dist/src/email/client.d.ts +33 -0
  58. package/dist/src/email/client.d.ts.map +1 -0
  59. package/dist/src/email/templates.d.ts +15 -0
  60. package/dist/src/email/templates.d.ts.map +1 -0
  61. package/dist/src/email/types.d.ts +35 -0
  62. package/dist/src/email/types.d.ts.map +1 -0
  63. package/dist/src/env-detect.d.ts +25 -0
  64. package/dist/src/env-detect.d.ts.map +1 -0
  65. package/dist/src/errors.d.ts +53 -0
  66. package/dist/src/errors.d.ts.map +1 -0
  67. package/dist/src/events/client.d.ts +25 -0
  68. package/dist/src/events/client.d.ts.map +1 -0
  69. package/dist/src/events/index.d.ts +9 -0
  70. package/dist/src/events/index.d.ts.map +1 -0
  71. package/dist/src/events/types.d.ts +10 -0
  72. package/dist/src/events/types.d.ts.map +1 -0
  73. package/dist/src/feature/canonical.d.ts +33 -0
  74. package/dist/src/feature/canonical.d.ts.map +1 -0
  75. package/dist/src/feature/create-feature.d.ts +33 -0
  76. package/dist/src/feature/create-feature.d.ts.map +1 -0
  77. package/dist/src/feature/db.d.ts +16 -0
  78. package/dist/src/feature/db.d.ts.map +1 -0
  79. package/dist/src/feature/handlers.d.ts +28 -0
  80. package/dist/src/feature/handlers.d.ts.map +1 -0
  81. package/dist/src/feature/index.d.ts +21 -0
  82. package/dist/src/feature/index.d.ts.map +1 -0
  83. package/dist/src/feature/manifest.d.ts +173 -0
  84. package/dist/src/feature/manifest.d.ts.map +1 -0
  85. package/dist/src/feature/mapping.d.ts +18 -0
  86. package/dist/src/feature/mapping.d.ts.map +1 -0
  87. package/dist/src/feature/runtime.d.ts +45 -0
  88. package/dist/src/feature/runtime.d.ts.map +1 -0
  89. package/dist/src/feature/types.d.ts +65 -0
  90. package/dist/src/feature/types.d.ts.map +1 -0
  91. package/dist/src/files/client.d.ts +28 -0
  92. package/dist/src/files/client.d.ts.map +1 -0
  93. package/dist/src/files/types.d.ts +28 -0
  94. package/dist/src/files/types.d.ts.map +1 -0
  95. package/dist/src/fix-registry.d.ts +8 -0
  96. package/dist/src/fix-registry.d.ts.map +1 -0
  97. package/dist/src/gateway.d.ts +32 -0
  98. package/dist/src/gateway.d.ts.map +1 -0
  99. package/dist/src/logs/capture.d.ts +56 -0
  100. package/dist/src/logs/capture.d.ts.map +1 -0
  101. package/dist/src/logs/index.d.ts +2 -0
  102. package/dist/src/logs/index.d.ts.map +1 -0
  103. package/dist/src/management.d.ts +1 -1
  104. package/dist/src/management.d.ts.map +1 -1
  105. package/dist/src/models.d.ts +32 -0
  106. package/dist/src/models.d.ts.map +1 -0
  107. package/dist/src/next/auth.d.ts +54 -0
  108. package/dist/src/next/auth.d.ts.map +1 -0
  109. package/dist/src/next/chat.d.ts +31 -0
  110. package/dist/src/next/chat.d.ts.map +1 -0
  111. package/dist/src/next/index.d.ts +14 -0
  112. package/dist/src/next/index.d.ts.map +1 -0
  113. package/dist/src/next/notifications.d.ts +67 -0
  114. package/dist/src/next/notifications.d.ts.map +1 -0
  115. package/dist/src/notifications/built-ins.d.ts +9 -0
  116. package/dist/src/notifications/built-ins.d.ts.map +1 -0
  117. package/dist/src/notifications/client.d.ts +38 -0
  118. package/dist/src/notifications/client.d.ts.map +1 -0
  119. package/dist/src/notifications/config.d.ts +71 -0
  120. package/dist/src/notifications/config.d.ts.map +1 -0
  121. package/dist/src/notifications/index.d.ts +6 -0
  122. package/dist/src/notifications/index.d.ts.map +1 -0
  123. package/dist/src/notifications/registry.d.ts +67 -0
  124. package/dist/src/notifications/registry.d.ts.map +1 -0
  125. package/dist/src/notifications/types.d.ts +48 -0
  126. package/dist/src/notifications/types.d.ts.map +1 -0
  127. package/dist/src/payments/client.d.ts +64 -0
  128. package/dist/src/payments/client.d.ts.map +1 -0
  129. package/dist/src/payments/config.d.ts +46 -0
  130. package/dist/src/payments/config.d.ts.map +1 -0
  131. package/dist/src/payments/entitlements.d.ts +48 -0
  132. package/dist/src/payments/entitlements.d.ts.map +1 -0
  133. package/dist/src/payments/types.d.ts +135 -0
  134. package/dist/src/payments/types.d.ts.map +1 -0
  135. package/dist/src/react/BrokrErrorBoundary.d.ts +23 -0
  136. package/dist/src/react/BrokrErrorBoundary.d.ts.map +1 -0
  137. package/dist/src/react/account/AccountPanel.d.ts +12 -0
  138. package/dist/src/react/account/AccountPanel.d.ts.map +1 -0
  139. package/dist/src/react/account/Avatar.d.ts +11 -0
  140. package/dist/src/react/account/Avatar.d.ts.map +1 -0
  141. package/dist/src/react/account/ProfilePhotoButton.d.ts +7 -0
  142. package/dist/src/react/account/ProfilePhotoButton.d.ts.map +1 -0
  143. package/dist/src/react/account/UserButton.d.ts +7 -0
  144. package/dist/src/react/account/UserButton.d.ts.map +1 -0
  145. package/dist/src/react/auth-pages/AuthPageShell.d.ts +9 -0
  146. package/dist/src/react/auth-pages/AuthPageShell.d.ts.map +1 -0
  147. package/dist/src/react/auth-pages/SignInPage.d.ts +9 -0
  148. package/dist/src/react/auth-pages/SignInPage.d.ts.map +1 -0
  149. package/dist/src/react/auth-pages/SignUpPage.d.ts +8 -0
  150. package/dist/src/react/auth-pages/SignUpPage.d.ts.map +1 -0
  151. package/dist/src/react/auth.d.ts +1 -49
  152. package/dist/src/react/auth.d.ts.map +1 -1
  153. package/dist/src/react/chat/AIChat.d.ts +4 -0
  154. package/dist/src/react/chat/AIChat.d.ts.map +1 -0
  155. package/dist/src/react/chat/ChatContext.d.ts +76 -0
  156. package/dist/src/react/chat/ChatContext.d.ts.map +1 -0
  157. package/dist/src/react/chat/ChatInput.d.ts +3 -0
  158. package/dist/src/react/chat/ChatInput.d.ts.map +1 -0
  159. package/dist/src/react/chat/MarkdownRenderer.d.ts +5 -0
  160. package/dist/src/react/chat/MarkdownRenderer.d.ts.map +1 -0
  161. package/dist/src/react/chat/MessageBubble.d.ts +14 -0
  162. package/dist/src/react/chat/MessageBubble.d.ts.map +1 -0
  163. package/dist/src/react/chat/MessagePane.d.ts +10 -0
  164. package/dist/src/react/chat/MessagePane.d.ts.map +1 -0
  165. package/dist/src/react/chat/ModelSelector.d.ts +13 -0
  166. package/dist/src/react/chat/ModelSelector.d.ts.map +1 -0
  167. package/dist/src/react/chat/ThreadSidebar.d.ts +3 -0
  168. package/dist/src/react/chat/ThreadSidebar.d.ts.map +1 -0
  169. package/dist/src/react/chat/index.d.ts +5 -0
  170. package/dist/src/react/chat/index.d.ts.map +1 -0
  171. package/dist/src/react/chat/token-limit.d.ts +14 -0
  172. package/dist/src/react/chat/token-limit.d.ts.map +1 -0
  173. package/dist/src/react/chat/types.d.ts +65 -0
  174. package/dist/src/react/chat/types.d.ts.map +1 -0
  175. package/dist/src/react/chat/useChat.d.ts +57 -0
  176. package/dist/src/react/chat/useChat.d.ts.map +1 -0
  177. package/dist/src/react/composites/FabAI.d.ts +15 -0
  178. package/dist/src/react/composites/FabAI.d.ts.map +1 -0
  179. package/dist/src/react/composites/FeedbackWidget.d.ts +10 -0
  180. package/dist/src/react/composites/FeedbackWidget.d.ts.map +1 -0
  181. package/dist/src/react/composites/SmartUpload.d.ts +12 -0
  182. package/dist/src/react/composites/SmartUpload.d.ts.map +1 -0
  183. package/dist/src/react/config.d.ts +23 -0
  184. package/dist/src/react/config.d.ts.map +1 -0
  185. package/dist/src/react/context.d.ts +4 -0
  186. package/dist/src/react/context.d.ts.map +1 -0
  187. package/dist/src/react/css/account.d.ts +2 -0
  188. package/dist/src/react/css/account.d.ts.map +1 -0
  189. package/dist/src/react/css/animations.d.ts +2 -0
  190. package/dist/src/react/css/animations.d.ts.map +1 -0
  191. package/dist/src/react/css/auth.d.ts +2 -0
  192. package/dist/src/react/css/auth.d.ts.map +1 -0
  193. package/dist/src/react/css/chat-extras.d.ts +2 -0
  194. package/dist/src/react/css/chat-extras.d.ts.map +1 -0
  195. package/dist/src/react/css/chat.d.ts +2 -0
  196. package/dist/src/react/css/chat.d.ts.map +1 -0
  197. package/dist/src/react/css/composites.d.ts +2 -0
  198. package/dist/src/react/css/composites.d.ts.map +1 -0
  199. package/dist/src/react/css/gates.d.ts +2 -0
  200. package/dist/src/react/css/gates.d.ts.map +1 -0
  201. package/dist/src/react/css/index.d.ts +3 -0
  202. package/dist/src/react/css/index.d.ts.map +1 -0
  203. package/dist/src/react/css/markdown.d.ts +2 -0
  204. package/dist/src/react/css/markdown.d.ts.map +1 -0
  205. package/dist/src/react/css/notifications.d.ts +2 -0
  206. package/dist/src/react/css/notifications.d.ts.map +1 -0
  207. package/dist/src/react/css/primitives.d.ts +2 -0
  208. package/dist/src/react/css/primitives.d.ts.map +1 -0
  209. package/dist/src/react/css/reset.d.ts +2 -0
  210. package/dist/src/react/css/reset.d.ts.map +1 -0
  211. package/dist/src/react/css/responsive.d.ts +2 -0
  212. package/dist/src/react/css/responsive.d.ts.map +1 -0
  213. package/dist/src/react/css/skeleton.d.ts +2 -0
  214. package/dist/src/react/css/skeleton.d.ts.map +1 -0
  215. package/dist/src/react/css/tokens.d.ts +2 -0
  216. package/dist/src/react/css/tokens.d.ts.map +1 -0
  217. package/dist/src/react/gates/AuthWall.d.ts +7 -0
  218. package/dist/src/react/gates/AuthWall.d.ts.map +1 -0
  219. package/dist/src/react/gates/BillingBoundary.d.ts +4 -0
  220. package/dist/src/react/gates/BillingBoundary.d.ts.map +1 -0
  221. package/dist/src/react/gates/Gate.d.ts +9 -0
  222. package/dist/src/react/gates/Gate.d.ts.map +1 -0
  223. package/dist/src/react/gates/RequirePlan.d.ts +4 -0
  224. package/dist/src/react/gates/RequirePlan.d.ts.map +1 -0
  225. package/dist/src/react/gates/RequireUser.d.ts +4 -0
  226. package/dist/src/react/gates/RequireUser.d.ts.map +1 -0
  227. package/dist/src/react/gates/UsageGate.d.ts +4 -0
  228. package/dist/src/react/gates/UsageGate.d.ts.map +1 -0
  229. package/dist/src/react/helpers.d.ts +7 -0
  230. package/dist/src/react/helpers.d.ts.map +1 -0
  231. package/dist/src/react/hooks/use-theme.d.ts +15 -0
  232. package/dist/src/react/hooks/use-theme.d.ts.map +1 -0
  233. package/dist/src/react/hooks/use-user.d.ts +12 -0
  234. package/dist/src/react/hooks/use-user.d.ts.map +1 -0
  235. package/dist/src/react/icons.d.ts +26 -0
  236. package/dist/src/react/icons.d.ts.map +1 -0
  237. package/dist/src/react/index.d.ts +48 -0
  238. package/dist/src/react/index.d.ts.map +1 -0
  239. package/dist/src/react/notifications/NotificationBell.d.ts +7 -0
  240. package/dist/src/react/notifications/NotificationBell.d.ts.map +1 -0
  241. package/dist/src/react/notifications/NotificationList.d.ts +7 -0
  242. package/dist/src/react/notifications/NotificationList.d.ts.map +1 -0
  243. package/dist/src/react/notifications/Toast.d.ts +13 -0
  244. package/dist/src/react/notifications/Toast.d.ts.map +1 -0
  245. package/dist/src/react/notifications/index.d.ts +8 -0
  246. package/dist/src/react/notifications/index.d.ts.map +1 -0
  247. package/dist/src/react/notifications/provider.d.ts +14 -0
  248. package/dist/src/react/notifications/provider.d.ts.map +1 -0
  249. package/dist/src/react/notifications/use-notifications.d.ts +24 -0
  250. package/dist/src/react/notifications/use-notifications.d.ts.map +1 -0
  251. package/dist/src/react/payments/AutoReloadToggle.d.ts +6 -0
  252. package/dist/src/react/payments/AutoReloadToggle.d.ts.map +1 -0
  253. package/dist/src/react/payments/Balance.d.ts +8 -0
  254. package/dist/src/react/payments/Balance.d.ts.map +1 -0
  255. package/dist/src/react/payments/CancelSubscription.d.ts +6 -0
  256. package/dist/src/react/payments/CancelSubscription.d.ts.map +1 -0
  257. package/dist/src/react/payments/CheckoutButton.d.ts +7 -0
  258. package/dist/src/react/payments/CheckoutButton.d.ts.map +1 -0
  259. package/dist/src/react/payments/CustomerPortalButton.d.ts +6 -0
  260. package/dist/src/react/payments/CustomerPortalButton.d.ts.map +1 -0
  261. package/dist/src/react/payments/FeatureMeter.d.ts +6 -0
  262. package/dist/src/react/payments/FeatureMeter.d.ts.map +1 -0
  263. package/dist/src/react/payments/Plans.d.ts +8 -0
  264. package/dist/src/react/payments/Plans.d.ts.map +1 -0
  265. package/dist/src/react/payments/TopUpButton.d.ts +8 -0
  266. package/dist/src/react/payments/TopUpButton.d.ts.map +1 -0
  267. package/dist/src/react/payments/UpdateBilling.d.ts +3 -0
  268. package/dist/src/react/payments/UpdateBilling.d.ts.map +1 -0
  269. package/dist/src/react/payments/UpgradePrompt.d.ts +8 -0
  270. package/dist/src/react/payments/UpgradePrompt.d.ts.map +1 -0
  271. package/dist/src/react/primitives/Skeleton.d.ts +15 -0
  272. package/dist/src/react/primitives/Skeleton.d.ts.map +1 -0
  273. package/dist/src/react/provider.d.ts +21 -0
  274. package/dist/src/react/provider.d.ts.map +1 -0
  275. package/dist/src/react/request.d.ts +2 -0
  276. package/dist/src/react/request.d.ts.map +1 -0
  277. package/dist/src/react/styles-entry.d.ts +4 -0
  278. package/dist/src/react/styles-entry.d.ts.map +1 -0
  279. package/dist/src/react/styles.d.ts +2 -0
  280. package/dist/src/react/styles.d.ts.map +1 -0
  281. package/dist/src/react/theme-entry.d.ts +3 -0
  282. package/dist/src/react/theme-entry.d.ts.map +1 -0
  283. package/dist/src/react/theme.d.ts +6 -0
  284. package/dist/src/react/theme.d.ts.map +1 -0
  285. package/dist/src/react/types.d.ts +191 -0
  286. package/dist/src/react/types.d.ts.map +1 -0
  287. package/dist/src/react/use-brokr-theme.d.ts +6 -0
  288. package/dist/src/react/use-brokr-theme.d.ts.map +1 -0
  289. package/dist/src/runtime.d.ts +69 -180
  290. package/dist/src/runtime.d.ts.map +1 -1
  291. package/dist/src/storage/client.d.ts +113 -0
  292. package/dist/src/storage/client.d.ts.map +1 -0
  293. package/dist/src/storage/types.d.ts +60 -0
  294. package/dist/src/storage/types.d.ts.map +1 -0
  295. package/dist/tsconfig.tsbuildinfo +1 -1
  296. package/dist/types.d.ts +2 -2
  297. package/dist/types.d.ts.map +1 -1
  298. package/package.json +70 -9
package/dist/index.mjs CHANGED
@@ -1,6 +1,8 @@
1
+ var __create = Object.create;
1
2
  var __defProp = Object.defineProperty;
2
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
4
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
7
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
8
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -8,29 +10,3164 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
8
10
  if (typeof require !== "undefined") return require.apply(this, arguments);
9
11
  throw Error('Dynamic require of "' + x + '" is not supported');
10
12
  });
11
- var __esm = (fn, res) => function __init() {
12
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
13
+ var __commonJS = (cb, mod) => function __require2() {
14
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
13
15
  };
14
- var __export = (target, all) => {
15
- for (var name in all)
16
- __defProp(target, name, { get: all[name], enumerable: true });
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+
33
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/headers.js
34
+ var require_headers = __commonJS({
35
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/headers.js"(exports, module) {
36
+ "use strict";
37
+ var __defProp2 = Object.defineProperty;
38
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
39
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
40
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
41
+ var __export = (target, all) => {
42
+ for (var name in all)
43
+ __defProp2(target, name, { get: all[name], enumerable: true });
44
+ };
45
+ var __copyProps2 = (to, from, except, desc) => {
46
+ if (from && typeof from === "object" || typeof from === "function") {
47
+ for (let key of __getOwnPropNames2(from))
48
+ if (!__hasOwnProp2.call(to, key) && key !== except)
49
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
50
+ }
51
+ return to;
52
+ };
53
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
54
+ var headers_exports = {};
55
+ __export(headers_exports, {
56
+ CITY_HEADER_NAME: () => CITY_HEADER_NAME,
57
+ COUNTRY_HEADER_NAME: () => COUNTRY_HEADER_NAME,
58
+ EMOJI_FLAG_UNICODE_STARTING_POSITION: () => EMOJI_FLAG_UNICODE_STARTING_POSITION,
59
+ IP_HEADER_NAME: () => IP_HEADER_NAME,
60
+ LATITUDE_HEADER_NAME: () => LATITUDE_HEADER_NAME,
61
+ LONGITUDE_HEADER_NAME: () => LONGITUDE_HEADER_NAME,
62
+ POSTAL_CODE_HEADER_NAME: () => POSTAL_CODE_HEADER_NAME,
63
+ REGION_HEADER_NAME: () => REGION_HEADER_NAME,
64
+ REQUEST_ID_HEADER_NAME: () => REQUEST_ID_HEADER_NAME,
65
+ geolocation: () => geolocation2,
66
+ ipAddress: () => ipAddress2
67
+ });
68
+ module.exports = __toCommonJS(headers_exports);
69
+ var CITY_HEADER_NAME = "x-vercel-ip-city";
70
+ var COUNTRY_HEADER_NAME = "x-vercel-ip-country";
71
+ var IP_HEADER_NAME = "x-real-ip";
72
+ var LATITUDE_HEADER_NAME = "x-vercel-ip-latitude";
73
+ var LONGITUDE_HEADER_NAME = "x-vercel-ip-longitude";
74
+ var REGION_HEADER_NAME = "x-vercel-ip-country-region";
75
+ var POSTAL_CODE_HEADER_NAME = "x-vercel-ip-postal-code";
76
+ var REQUEST_ID_HEADER_NAME = "x-vercel-id";
77
+ var EMOJI_FLAG_UNICODE_STARTING_POSITION = 127397;
78
+ function getHeader(headers, key) {
79
+ return headers.get(key) ?? void 0;
80
+ }
81
+ function getHeaderWithDecode(request, key) {
82
+ const header = getHeader(request.headers, key);
83
+ return header ? decodeURIComponent(header) : void 0;
84
+ }
85
+ function getFlag(countryCode) {
86
+ const regex = new RegExp("^[A-Z]{2}$").test(countryCode);
87
+ if (!countryCode || !regex)
88
+ return void 0;
89
+ return String.fromCodePoint(
90
+ ...countryCode.split("").map((char) => EMOJI_FLAG_UNICODE_STARTING_POSITION + char.charCodeAt(0))
91
+ );
92
+ }
93
+ function ipAddress2(input) {
94
+ const headers = "headers" in input ? input.headers : input;
95
+ return getHeader(headers, IP_HEADER_NAME);
96
+ }
97
+ function getRegionFromRequestId(requestId) {
98
+ if (!requestId) {
99
+ return "dev1";
100
+ }
101
+ return requestId.split(":")[0];
102
+ }
103
+ function geolocation2(request) {
104
+ return {
105
+ // city name may be encoded to support multi-byte characters
106
+ city: getHeaderWithDecode(request, CITY_HEADER_NAME),
107
+ country: getHeader(request.headers, COUNTRY_HEADER_NAME),
108
+ flag: getFlag(getHeader(request.headers, COUNTRY_HEADER_NAME)),
109
+ countryRegion: getHeader(request.headers, REGION_HEADER_NAME),
110
+ region: getRegionFromRequestId(
111
+ getHeader(request.headers, REQUEST_ID_HEADER_NAME)
112
+ ),
113
+ latitude: getHeader(request.headers, LATITUDE_HEADER_NAME),
114
+ longitude: getHeader(request.headers, LONGITUDE_HEADER_NAME),
115
+ postalCode: getHeader(request.headers, POSTAL_CODE_HEADER_NAME)
116
+ };
117
+ }
118
+ }
119
+ });
120
+
121
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/get-env.js
122
+ var require_get_env = __commonJS({
123
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/get-env.js"(exports, module) {
124
+ "use strict";
125
+ var __defProp2 = Object.defineProperty;
126
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
127
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
128
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
129
+ var __export = (target, all) => {
130
+ for (var name in all)
131
+ __defProp2(target, name, { get: all[name], enumerable: true });
132
+ };
133
+ var __copyProps2 = (to, from, except, desc) => {
134
+ if (from && typeof from === "object" || typeof from === "function") {
135
+ for (let key of __getOwnPropNames2(from))
136
+ if (!__hasOwnProp2.call(to, key) && key !== except)
137
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
138
+ }
139
+ return to;
140
+ };
141
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
142
+ var get_env_exports = {};
143
+ __export(get_env_exports, {
144
+ getEnv: () => getEnv2
145
+ });
146
+ module.exports = __toCommonJS(get_env_exports);
147
+ var getEnv2 = (env = process.env) => ({
148
+ /**
149
+ * An indicator to show that System Environment Variables have been exposed to your project's Deployments.
150
+ * @example "1"
151
+ */
152
+ VERCEL: get(env, "VERCEL"),
153
+ /**
154
+ * An indicator that the code is running in a Continuous Integration environment.
155
+ * @example "1"
156
+ */
157
+ CI: get(env, "CI"),
158
+ /**
159
+ * The Environment that the app is deployed and running on.
160
+ * @example "production"
161
+ */
162
+ VERCEL_ENV: get(env, "VERCEL_ENV"),
163
+ /**
164
+ * The domain name of the generated deployment URL. The value does not include the protocol scheme https://.
165
+ * NOTE: This Variable cannot be used in conjunction with Standard Deployment Protection.
166
+ * @example "*.vercel.app"
167
+ */
168
+ VERCEL_URL: get(env, "VERCEL_URL"),
169
+ /**
170
+ * The domain name of the generated Git branch URL. The value does not include the protocol scheme https://.
171
+ * @example "*-git-*.vercel.app"
172
+ */
173
+ VERCEL_BRANCH_URL: get(env, "VERCEL_BRANCH_URL"),
174
+ /**
175
+ * A production domain name of the project. This is useful to reliably generate links that point to production such as OG-image URLs.
176
+ * The value does not include the protocol scheme https://.
177
+ * @example "myproject.vercel.app"
178
+ */
179
+ VERCEL_PROJECT_PRODUCTION_URL: get(env, "VERCEL_PROJECT_PRODUCTION_URL"),
180
+ /**
181
+ * The ID of the Region where the app is running.
182
+ *
183
+ * Possible values:
184
+ * - arn1 (Stockholm, Sweden)
185
+ * - bom1 (Mumbai, India)
186
+ * - cdg1 (Paris, France)
187
+ * - cle1 (Cleveland, USA)
188
+ * - cpt1 (Cape Town, South Africa)
189
+ * - dub1 (Dublin, Ireland)
190
+ * - fra1 (Frankfurt, Germany)
191
+ * - gru1 (São Paulo, Brazil)
192
+ * - hkg1 (Hong Kong)
193
+ * - hnd1 (Tokyo, Japan)
194
+ * - iad1 (Washington, D.C., USA)
195
+ * - icn1 (Seoul, South Korea)
196
+ * - kix1 (Osaka, Japan)
197
+ * - lhr1 (London, United Kingdom)
198
+ * - pdx1 (Portland, USA)
199
+ * - sfo1 (San Francisco, USA)
200
+ * - sin1 (Singapore)
201
+ * - syd1 (Sydney, Australia)
202
+ * - dev1 (Development Region)
203
+ *
204
+ * @example "iad1"
205
+ */
206
+ VERCEL_REGION: get(env, "VERCEL_REGION"),
207
+ /**
208
+ * The unique identifier for the deployment, which can be used to implement Skew Protection.
209
+ * @example "dpl_7Gw5ZMBpQA8h9GF832KGp7nwbuh3"
210
+ */
211
+ VERCEL_DEPLOYMENT_ID: get(env, "VERCEL_DEPLOYMENT_ID"),
212
+ /**
213
+ * When Skew Protection is enabled in Project Settings, this value is set to 1.
214
+ * @example "1"
215
+ */
216
+ VERCEL_SKEW_PROTECTION_ENABLED: get(env, "VERCEL_SKEW_PROTECTION_ENABLED"),
217
+ /**
218
+ * The Protection Bypass for Automation value, if the secret has been generated in the project's Deployment Protection settings.
219
+ */
220
+ VERCEL_AUTOMATION_BYPASS_SECRET: get(env, "VERCEL_AUTOMATION_BYPASS_SECRET"),
221
+ /**
222
+ * The Git Provider the deployment is triggered from.
223
+ * @example "github"
224
+ */
225
+ VERCEL_GIT_PROVIDER: get(env, "VERCEL_GIT_PROVIDER"),
226
+ /**
227
+ * The origin repository the deployment is triggered from.
228
+ * @example "my-site"
229
+ */
230
+ VERCEL_GIT_REPO_SLUG: get(env, "VERCEL_GIT_REPO_SLUG"),
231
+ /**
232
+ * The account that owns the repository the deployment is triggered from.
233
+ * @example "acme"
234
+ */
235
+ VERCEL_GIT_REPO_OWNER: get(env, "VERCEL_GIT_REPO_OWNER"),
236
+ /**
237
+ * The ID of the repository the deployment is triggered from.
238
+ * @example "117716146"
239
+ */
240
+ VERCEL_GIT_REPO_ID: get(env, "VERCEL_GIT_REPO_ID"),
241
+ /**
242
+ * The git branch of the commit the deployment was triggered by.
243
+ * @example "improve-about-page"
244
+ */
245
+ VERCEL_GIT_COMMIT_REF: get(env, "VERCEL_GIT_COMMIT_REF"),
246
+ /**
247
+ * The git SHA of the commit the deployment was triggered by.
248
+ * @example "fa1eade47b73733d6312d5abfad33ce9e4068081"
249
+ */
250
+ VERCEL_GIT_COMMIT_SHA: get(env, "VERCEL_GIT_COMMIT_SHA"),
251
+ /**
252
+ * The message attached to the commit the deployment was triggered by.
253
+ * @example "Update about page"
254
+ */
255
+ VERCEL_GIT_COMMIT_MESSAGE: get(env, "VERCEL_GIT_COMMIT_MESSAGE"),
256
+ /**
257
+ * The username attached to the author of the commit that the project was deployed by.
258
+ * @example "johndoe"
259
+ */
260
+ VERCEL_GIT_COMMIT_AUTHOR_LOGIN: get(env, "VERCEL_GIT_COMMIT_AUTHOR_LOGIN"),
261
+ /**
262
+ * The name attached to the author of the commit that the project was deployed by.
263
+ * @example "John Doe"
264
+ */
265
+ VERCEL_GIT_COMMIT_AUTHOR_NAME: get(env, "VERCEL_GIT_COMMIT_AUTHOR_NAME"),
266
+ /**
267
+ * The git SHA of the last successful deployment for the project and branch.
268
+ * NOTE: This Variable is only exposed when an Ignored Build Step is provided.
269
+ * @example "fa1eade47b73733d6312d5abfad33ce9e4068080"
270
+ */
271
+ VERCEL_GIT_PREVIOUS_SHA: get(env, "VERCEL_GIT_PREVIOUS_SHA"),
272
+ /**
273
+ * The pull request id the deployment was triggered by. If a deployment is created on a branch before a pull request is made, this value will be an empty string.
274
+ * @example "23"
275
+ */
276
+ VERCEL_GIT_PULL_REQUEST_ID: get(env, "VERCEL_GIT_PULL_REQUEST_ID")
277
+ });
278
+ var get = (env, key) => {
279
+ const value = env[key];
280
+ return value === "" ? void 0 : value;
281
+ };
282
+ }
283
+ });
284
+
285
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/get-context.js
286
+ var require_get_context = __commonJS({
287
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/get-context.js"(exports, module) {
288
+ "use strict";
289
+ var __defProp2 = Object.defineProperty;
290
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
291
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
292
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
293
+ var __export = (target, all) => {
294
+ for (var name in all)
295
+ __defProp2(target, name, { get: all[name], enumerable: true });
296
+ };
297
+ var __copyProps2 = (to, from, except, desc) => {
298
+ if (from && typeof from === "object" || typeof from === "function") {
299
+ for (let key of __getOwnPropNames2(from))
300
+ if (!__hasOwnProp2.call(to, key) && key !== except)
301
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
302
+ }
303
+ return to;
304
+ };
305
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
306
+ var get_context_exports = {};
307
+ __export(get_context_exports, {
308
+ SYMBOL_FOR_REQ_CONTEXT: () => SYMBOL_FOR_REQ_CONTEXT,
309
+ getContext: () => getContext
310
+ });
311
+ module.exports = __toCommonJS(get_context_exports);
312
+ var SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
313
+ function getContext() {
314
+ const fromSymbol = globalThis;
315
+ return fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};
316
+ }
317
+ }
318
+ });
319
+
320
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/wait-until.js
321
+ var require_wait_until = __commonJS({
322
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/wait-until.js"(exports, module) {
323
+ "use strict";
324
+ var __defProp2 = Object.defineProperty;
325
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
326
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
327
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
328
+ var __export = (target, all) => {
329
+ for (var name in all)
330
+ __defProp2(target, name, { get: all[name], enumerable: true });
331
+ };
332
+ var __copyProps2 = (to, from, except, desc) => {
333
+ if (from && typeof from === "object" || typeof from === "function") {
334
+ for (let key of __getOwnPropNames2(from))
335
+ if (!__hasOwnProp2.call(to, key) && key !== except)
336
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
337
+ }
338
+ return to;
339
+ };
340
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
341
+ var wait_until_exports = {};
342
+ __export(wait_until_exports, {
343
+ waitUntil: () => waitUntil2
344
+ });
345
+ module.exports = __toCommonJS(wait_until_exports);
346
+ var import_get_context = require_get_context();
347
+ var waitUntil2 = (promise) => {
348
+ if (promise === null || typeof promise !== "object" || typeof promise.then !== "function") {
349
+ throw new TypeError(
350
+ `waitUntil can only be called with a Promise, got ${typeof promise}`
351
+ );
352
+ }
353
+ return (0, import_get_context.getContext)().waitUntil?.(promise);
354
+ };
355
+ }
356
+ });
357
+
358
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/middleware.js
359
+ var require_middleware = __commonJS({
360
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/middleware.js"(exports, module) {
361
+ "use strict";
362
+ var __defProp2 = Object.defineProperty;
363
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
364
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
365
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
366
+ var __export = (target, all) => {
367
+ for (var name in all)
368
+ __defProp2(target, name, { get: all[name], enumerable: true });
369
+ };
370
+ var __copyProps2 = (to, from, except, desc) => {
371
+ if (from && typeof from === "object" || typeof from === "function") {
372
+ for (let key of __getOwnPropNames2(from))
373
+ if (!__hasOwnProp2.call(to, key) && key !== except)
374
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
375
+ }
376
+ return to;
377
+ };
378
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
379
+ var middleware_exports = {};
380
+ __export(middleware_exports, {
381
+ next: () => next2,
382
+ rewrite: () => rewrite2
383
+ });
384
+ module.exports = __toCommonJS(middleware_exports);
385
+ function handleMiddlewareField(init, headers) {
386
+ if (init?.request?.headers) {
387
+ if (!(init.request.headers instanceof Headers)) {
388
+ throw new Error("request.headers must be an instance of Headers");
389
+ }
390
+ const keys = [];
391
+ for (const [key, value] of init.request.headers) {
392
+ headers.set("x-middleware-request-" + key, value);
393
+ keys.push(key);
394
+ }
395
+ headers.set("x-middleware-override-headers", keys.join(","));
396
+ }
397
+ }
398
+ function rewrite2(destination, init) {
399
+ const headers = new Headers(init?.headers ?? {});
400
+ headers.set("x-middleware-rewrite", String(destination));
401
+ handleMiddlewareField(init, headers);
402
+ return new Response(null, {
403
+ ...init,
404
+ headers
405
+ });
406
+ }
407
+ function next2(init) {
408
+ const headers = new Headers(init?.headers ?? {});
409
+ headers.set("x-middleware-next", "1");
410
+ handleMiddlewareField(init, headers);
411
+ return new Response(null, {
412
+ ...init,
413
+ headers
414
+ });
415
+ }
416
+ }
417
+ });
418
+
419
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/cache/in-memory-cache.js
420
+ var require_in_memory_cache = __commonJS({
421
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/cache/in-memory-cache.js"(exports, module) {
422
+ "use strict";
423
+ var __defProp2 = Object.defineProperty;
424
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
425
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
426
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
427
+ var __export = (target, all) => {
428
+ for (var name in all)
429
+ __defProp2(target, name, { get: all[name], enumerable: true });
430
+ };
431
+ var __copyProps2 = (to, from, except, desc) => {
432
+ if (from && typeof from === "object" || typeof from === "function") {
433
+ for (let key of __getOwnPropNames2(from))
434
+ if (!__hasOwnProp2.call(to, key) && key !== except)
435
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
436
+ }
437
+ return to;
438
+ };
439
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
440
+ var in_memory_cache_exports = {};
441
+ __export(in_memory_cache_exports, {
442
+ InMemoryCache: () => InMemoryCache
443
+ });
444
+ module.exports = __toCommonJS(in_memory_cache_exports);
445
+ var InMemoryCache = class {
446
+ constructor() {
447
+ this.cache = {};
448
+ }
449
+ async get(key) {
450
+ const entry = this.cache[key];
451
+ if (entry) {
452
+ if (entry.ttl && entry.lastModified + entry.ttl * 1e3 < Date.now()) {
453
+ await this.delete(key);
454
+ return null;
455
+ }
456
+ return JSON.parse(entry.value);
457
+ }
458
+ return null;
459
+ }
460
+ async set(key, value, options) {
461
+ const serialized = JSON.stringify(value ?? null);
462
+ this.cache[key] = {
463
+ value: serialized,
464
+ lastModified: Date.now(),
465
+ ttl: options?.ttl,
466
+ tags: new Set(options?.tags || [])
467
+ };
468
+ }
469
+ async delete(key) {
470
+ delete this.cache[key];
471
+ }
472
+ async expireTag(tag) {
473
+ const tags = Array.isArray(tag) ? tag : [tag];
474
+ for (const key in this.cache) {
475
+ if (Object.prototype.hasOwnProperty.call(this.cache, key)) {
476
+ const entry = this.cache[key];
477
+ if (tags.some((t) => entry.tags.has(t))) {
478
+ delete this.cache[key];
479
+ }
480
+ }
481
+ }
482
+ }
483
+ };
484
+ }
485
+ });
486
+
487
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/cache/build-client.js
488
+ var require_build_client = __commonJS({
489
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/cache/build-client.js"(exports, module) {
490
+ "use strict";
491
+ var __defProp2 = Object.defineProperty;
492
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
493
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
494
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
495
+ var __export = (target, all) => {
496
+ for (var name in all)
497
+ __defProp2(target, name, { get: all[name], enumerable: true });
498
+ };
499
+ var __copyProps2 = (to, from, except, desc) => {
500
+ if (from && typeof from === "object" || typeof from === "function") {
501
+ for (let key of __getOwnPropNames2(from))
502
+ if (!__hasOwnProp2.call(to, key) && key !== except)
503
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
504
+ }
505
+ return to;
506
+ };
507
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
508
+ var build_client_exports = {};
509
+ __export(build_client_exports, {
510
+ BuildCache: () => BuildCache
511
+ });
512
+ module.exports = __toCommonJS(build_client_exports);
513
+ var import_index = require_cache();
514
+ var BuildCache = class {
515
+ constructor({
516
+ endpoint,
517
+ headers,
518
+ onError,
519
+ timeout = 500
520
+ }) {
521
+ this.get = async (key) => {
522
+ const controller = new AbortController();
523
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
524
+ try {
525
+ const res = await fetch(`${this.endpoint}${key}`, {
526
+ headers: this.headers,
527
+ method: "GET",
528
+ signal: controller.signal
529
+ });
530
+ if (res.status === 404) {
531
+ clearTimeout(timeoutId);
532
+ return null;
533
+ }
534
+ if (res.status === 200) {
535
+ const cacheState = res.headers.get(
536
+ import_index.HEADERS_VERCEL_CACHE_STATE
537
+ );
538
+ if (cacheState !== import_index.PkgCacheState.Fresh) {
539
+ res.body?.cancel?.();
540
+ clearTimeout(timeoutId);
541
+ return null;
542
+ }
543
+ const result = await res.json();
544
+ clearTimeout(timeoutId);
545
+ return result;
546
+ } else {
547
+ clearTimeout(timeoutId);
548
+ throw new Error(`Failed to get cache: ${res.statusText}`);
549
+ }
550
+ } catch (error) {
551
+ clearTimeout(timeoutId);
552
+ if (error.name === "AbortError") {
553
+ const timeoutError = new Error(
554
+ `Cache request timed out after ${this.timeout}ms`
555
+ );
556
+ timeoutError.stack = error.stack;
557
+ this.onError?.(timeoutError);
558
+ } else {
559
+ this.onError?.(error);
560
+ }
561
+ return null;
562
+ }
563
+ };
564
+ this.set = async (key, value, options) => {
565
+ const controller = new AbortController();
566
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
567
+ try {
568
+ const optionalHeaders = {};
569
+ if (options?.ttl) {
570
+ optionalHeaders[import_index.HEADERS_VERCEL_REVALIDATE] = options.ttl.toString();
571
+ }
572
+ if (options?.tags && options.tags.length > 0) {
573
+ optionalHeaders[import_index.HEADERS_VERCEL_CACHE_TAGS] = options.tags.join(",");
574
+ }
575
+ if (options?.name) {
576
+ optionalHeaders[import_index.HEADERS_VERCEL_CACHE_ITEM_NAME] = options.name;
577
+ }
578
+ const res = await fetch(`${this.endpoint}${key}`, {
579
+ method: "POST",
580
+ headers: {
581
+ ...this.headers,
582
+ ...optionalHeaders
583
+ },
584
+ body: JSON.stringify(value),
585
+ signal: controller.signal
586
+ });
587
+ clearTimeout(timeoutId);
588
+ if (res.status !== 200) {
589
+ throw new Error(`Failed to set cache: ${res.status} ${res.statusText}`);
590
+ }
591
+ } catch (error) {
592
+ clearTimeout(timeoutId);
593
+ if (error.name === "AbortError") {
594
+ const timeoutError = new Error(
595
+ `Cache request timed out after ${this.timeout}ms`
596
+ );
597
+ timeoutError.stack = error.stack;
598
+ this.onError?.(timeoutError);
599
+ } else {
600
+ this.onError?.(error);
601
+ }
602
+ }
603
+ };
604
+ this.delete = async (key) => {
605
+ const controller = new AbortController();
606
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
607
+ try {
608
+ const res = await fetch(`${this.endpoint}${key}`, {
609
+ method: "DELETE",
610
+ headers: this.headers,
611
+ signal: controller.signal
612
+ });
613
+ clearTimeout(timeoutId);
614
+ if (res.status !== 200) {
615
+ throw new Error(`Failed to delete cache: ${res.statusText}`);
616
+ }
617
+ } catch (error) {
618
+ clearTimeout(timeoutId);
619
+ if (error.name === "AbortError") {
620
+ const timeoutError = new Error(
621
+ `Cache request timed out after ${this.timeout}ms`
622
+ );
623
+ timeoutError.stack = error.stack;
624
+ this.onError?.(timeoutError);
625
+ } else {
626
+ this.onError?.(error);
627
+ }
628
+ }
629
+ };
630
+ this.expireTag = async (tag) => {
631
+ const controller = new AbortController();
632
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
633
+ try {
634
+ if (Array.isArray(tag)) {
635
+ tag = tag.join(",");
636
+ }
637
+ const res = await fetch(`${this.endpoint}revalidate?tags=${tag}`, {
638
+ method: "POST",
639
+ headers: this.headers,
640
+ signal: controller.signal
641
+ });
642
+ clearTimeout(timeoutId);
643
+ if (res.status !== 200) {
644
+ throw new Error(`Failed to revalidate tag: ${res.statusText}`);
645
+ }
646
+ } catch (error) {
647
+ clearTimeout(timeoutId);
648
+ if (error.name === "AbortError") {
649
+ const timeoutError = new Error(
650
+ `Cache request timed out after ${this.timeout}ms`
651
+ );
652
+ timeoutError.stack = error.stack;
653
+ this.onError?.(timeoutError);
654
+ } else {
655
+ this.onError?.(error);
656
+ }
657
+ }
658
+ };
659
+ this.endpoint = endpoint;
660
+ this.headers = headers;
661
+ this.onError = onError;
662
+ this.timeout = timeout;
663
+ }
664
+ };
665
+ }
666
+ });
667
+
668
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/cache/index.js
669
+ var require_cache = __commonJS({
670
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/cache/index.js"(exports, module) {
671
+ "use strict";
672
+ var __defProp2 = Object.defineProperty;
673
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
674
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
675
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
676
+ var __export = (target, all) => {
677
+ for (var name in all)
678
+ __defProp2(target, name, { get: all[name], enumerable: true });
679
+ };
680
+ var __copyProps2 = (to, from, except, desc) => {
681
+ if (from && typeof from === "object" || typeof from === "function") {
682
+ for (let key of __getOwnPropNames2(from))
683
+ if (!__hasOwnProp2.call(to, key) && key !== except)
684
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
685
+ }
686
+ return to;
687
+ };
688
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
689
+ var cache_exports = {};
690
+ __export(cache_exports, {
691
+ HEADERS_VERCEL_CACHE_ITEM_NAME: () => HEADERS_VERCEL_CACHE_ITEM_NAME,
692
+ HEADERS_VERCEL_CACHE_STATE: () => HEADERS_VERCEL_CACHE_STATE,
693
+ HEADERS_VERCEL_CACHE_TAGS: () => HEADERS_VERCEL_CACHE_TAGS,
694
+ HEADERS_VERCEL_REVALIDATE: () => HEADERS_VERCEL_REVALIDATE,
695
+ PkgCacheState: () => PkgCacheState,
696
+ getCache: () => getCache2
697
+ });
698
+ module.exports = __toCommonJS(cache_exports);
699
+ var import_get_context = require_get_context();
700
+ var import_in_memory_cache = require_in_memory_cache();
701
+ var import_build_client = require_build_client();
702
+ var defaultKeyHashFunction = (key) => {
703
+ let hash = 5381;
704
+ for (let i = 0; i < key.length; i++) {
705
+ hash = hash * 33 ^ key.charCodeAt(i);
706
+ }
707
+ return (hash >>> 0).toString(16);
708
+ };
709
+ var defaultNamespaceSeparator = "$";
710
+ var inMemoryCacheInstance = null;
711
+ var buildCacheInstance = null;
712
+ var getCache2 = (cacheOptions) => {
713
+ const resolveCache = () => {
714
+ let cache;
715
+ if ((0, import_get_context.getContext)().cache) {
716
+ cache = (0, import_get_context.getContext)().cache;
717
+ } else {
718
+ cache = getCacheImplementation(
719
+ process.env.SUSPENSE_CACHE_DEBUG === "true"
720
+ );
721
+ }
722
+ return cache;
723
+ };
724
+ return wrapWithKeyTransformation(
725
+ resolveCache,
726
+ createKeyTransformer(cacheOptions)
727
+ );
728
+ };
729
+ function createKeyTransformer(cacheOptions) {
730
+ const hashFunction = cacheOptions?.keyHashFunction || defaultKeyHashFunction;
731
+ return (key) => {
732
+ if (!cacheOptions?.namespace)
733
+ return hashFunction(key);
734
+ const separator = cacheOptions.namespaceSeparator || defaultNamespaceSeparator;
735
+ return `${cacheOptions.namespace}${separator}${hashFunction(key)}`;
736
+ };
737
+ }
738
+ function wrapWithKeyTransformation(resolveCache, makeKey) {
739
+ return {
740
+ get: (key) => {
741
+ return resolveCache().get(makeKey(key));
742
+ },
743
+ set: (key, value, options) => {
744
+ return resolveCache().set(makeKey(key), value, options);
745
+ },
746
+ delete: (key) => {
747
+ return resolveCache().delete(makeKey(key));
748
+ },
749
+ expireTag: (tag) => {
750
+ return resolveCache().expireTag(tag);
751
+ }
752
+ };
753
+ }
754
+ var warnedCacheUnavailable = false;
755
+ function getCacheImplementation(debug) {
756
+ if (!inMemoryCacheInstance) {
757
+ inMemoryCacheInstance = new import_in_memory_cache.InMemoryCache();
758
+ }
759
+ if (process.env.RUNTIME_CACHE_DISABLE_BUILD_CACHE === "true") {
760
+ debug && console.log("Using InMemoryCache as build cache is disabled");
761
+ return inMemoryCacheInstance;
762
+ }
763
+ const { RUNTIME_CACHE_ENDPOINT, RUNTIME_CACHE_HEADERS } = process.env;
764
+ if (debug) {
765
+ console.log("Runtime cache environment variables:", {
766
+ RUNTIME_CACHE_ENDPOINT,
767
+ RUNTIME_CACHE_HEADERS
768
+ });
769
+ }
770
+ if (!RUNTIME_CACHE_ENDPOINT || !RUNTIME_CACHE_HEADERS) {
771
+ if (!warnedCacheUnavailable) {
772
+ console.warn(
773
+ "Runtime Cache unavailable in this environment. Falling back to in-memory cache."
774
+ );
775
+ warnedCacheUnavailable = true;
776
+ }
777
+ return inMemoryCacheInstance;
778
+ }
779
+ if (!buildCacheInstance) {
780
+ let parsedHeaders = {};
781
+ try {
782
+ parsedHeaders = JSON.parse(RUNTIME_CACHE_HEADERS);
783
+ } catch (e) {
784
+ console.error("Failed to parse RUNTIME_CACHE_HEADERS:", e);
785
+ return inMemoryCacheInstance;
786
+ }
787
+ let timeout = 500;
788
+ if (process.env.RUNTIME_CACHE_TIMEOUT) {
789
+ const parsed = parseInt(process.env.RUNTIME_CACHE_TIMEOUT, 10);
790
+ if (!isNaN(parsed) && parsed > 0) {
791
+ timeout = parsed;
792
+ } else {
793
+ console.warn(
794
+ `Invalid RUNTIME_CACHE_TIMEOUT value: "${process.env.RUNTIME_CACHE_TIMEOUT}". Using default: ${timeout}ms`
795
+ );
796
+ }
797
+ }
798
+ buildCacheInstance = new import_build_client.BuildCache({
799
+ endpoint: RUNTIME_CACHE_ENDPOINT,
800
+ headers: parsedHeaders,
801
+ onError: (error) => console.error(error),
802
+ timeout
803
+ });
804
+ }
805
+ return buildCacheInstance;
806
+ }
807
+ var PkgCacheState = /* @__PURE__ */ ((PkgCacheState2) => {
808
+ PkgCacheState2["Fresh"] = "fresh";
809
+ PkgCacheState2["Stale"] = "stale";
810
+ PkgCacheState2["Expired"] = "expired";
811
+ PkgCacheState2["NotFound"] = "notFound";
812
+ PkgCacheState2["Error"] = "error";
813
+ return PkgCacheState2;
814
+ })(PkgCacheState || {});
815
+ var HEADERS_VERCEL_CACHE_STATE = "x-vercel-cache-state";
816
+ var HEADERS_VERCEL_REVALIDATE = "x-vercel-revalidate";
817
+ var HEADERS_VERCEL_CACHE_TAGS = "x-vercel-cache-tags";
818
+ var HEADERS_VERCEL_CACHE_ITEM_NAME = "x-vercel-cache-item-name";
819
+ }
820
+ });
821
+
822
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/db-connections/index.js
823
+ var require_db_connections = __commonJS({
824
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/db-connections/index.js"(exports, module) {
825
+ "use strict";
826
+ var __defProp2 = Object.defineProperty;
827
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
828
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
829
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
830
+ var __export = (target, all) => {
831
+ for (var name in all)
832
+ __defProp2(target, name, { get: all[name], enumerable: true });
833
+ };
834
+ var __copyProps2 = (to, from, except, desc) => {
835
+ if (from && typeof from === "object" || typeof from === "function") {
836
+ for (let key of __getOwnPropNames2(from))
837
+ if (!__hasOwnProp2.call(to, key) && key !== except)
838
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
839
+ }
840
+ return to;
841
+ };
842
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
843
+ var db_connections_exports = {};
844
+ __export(db_connections_exports, {
845
+ attachDatabasePool: () => attachDatabasePool2,
846
+ experimental_attachDatabasePool: () => experimental_attachDatabasePool2
847
+ });
848
+ module.exports = __toCommonJS(db_connections_exports);
849
+ var import_get_context = require_get_context();
850
+ var DEBUG = !!process.env.DEBUG;
851
+ function getIdleTimeout(dbPool) {
852
+ if ("options" in dbPool && dbPool.options) {
853
+ if ("idleTimeoutMillis" in dbPool.options) {
854
+ return typeof dbPool.options.idleTimeoutMillis === "number" ? dbPool.options.idleTimeoutMillis : 1e4;
855
+ }
856
+ if ("maxIdleTimeMS" in dbPool.options) {
857
+ return typeof dbPool.options.maxIdleTimeMS === "number" ? dbPool.options.maxIdleTimeMS : 0;
858
+ }
859
+ if ("status" in dbPool) {
860
+ return 5e3;
861
+ }
862
+ if ("connect" in dbPool && "execute" in dbPool) {
863
+ return 3e4;
864
+ }
865
+ }
866
+ if ("config" in dbPool && dbPool.config) {
867
+ if ("connectionConfig" in dbPool.config && dbPool.config.connectionConfig) {
868
+ return dbPool.config.connectionConfig.idleTimeout || 6e4;
869
+ }
870
+ if ("idleTimeout" in dbPool.config) {
871
+ return typeof dbPool.config.idleTimeout === "number" ? dbPool.config.idleTimeout : 6e4;
872
+ }
873
+ }
874
+ if ("poolTimeout" in dbPool) {
875
+ return typeof dbPool.poolTimeout === "number" ? dbPool.poolTimeout : 6e4;
876
+ }
877
+ if ("idleTimeout" in dbPool) {
878
+ return typeof dbPool.idleTimeout === "number" ? dbPool.idleTimeout : 0;
879
+ }
880
+ return 1e4;
881
+ }
882
+ var idleTimeout = null;
883
+ var idleTimeoutResolve = () => {
884
+ };
885
+ var bootTime = Date.now();
886
+ var maximumDuration = 15 * 60 * 1e3 - 1e3;
887
+ function waitUntilIdleTimeout(dbPool) {
888
+ if (!process.env.VERCEL_URL || // This is not set during builds where we don't need to wait for idle connections using the mechanism
889
+ !process.env.VERCEL_REGION) {
890
+ return;
891
+ }
892
+ if (idleTimeout) {
893
+ clearTimeout(idleTimeout);
894
+ idleTimeoutResolve();
895
+ }
896
+ const promise = new Promise((resolve) => {
897
+ idleTimeoutResolve = resolve;
898
+ });
899
+ const waitTime = Math.min(
900
+ getIdleTimeout(dbPool) + 100,
901
+ Math.max(100, maximumDuration - (Date.now() - bootTime))
902
+ );
903
+ idleTimeout = setTimeout(() => {
904
+ idleTimeoutResolve?.();
905
+ if (DEBUG) {
906
+ console.log("Database pool idle timeout reached. Releasing connections.");
907
+ }
908
+ }, waitTime);
909
+ const requestContext = (0, import_get_context.getContext)();
910
+ if (requestContext?.waitUntil) {
911
+ requestContext.waitUntil(promise);
912
+ } else {
913
+ console.warn("Pool release event triggered outside of request scope.");
914
+ }
915
+ }
916
+ function attachDatabasePool2(dbPool) {
917
+ if (idleTimeout) {
918
+ idleTimeoutResolve?.();
919
+ clearTimeout(idleTimeout);
920
+ }
921
+ if ("on" in dbPool && dbPool.on && "options" in dbPool && "idleTimeoutMillis" in dbPool.options) {
922
+ const pgPool = dbPool;
923
+ pgPool.on("release", () => {
924
+ if (DEBUG) {
925
+ console.log("Client released from pool");
926
+ }
927
+ waitUntilIdleTimeout(dbPool);
928
+ });
929
+ return;
930
+ } else if ("on" in dbPool && dbPool.on && "config" in dbPool && dbPool.config && "connectionConfig" in dbPool.config) {
931
+ const mysqlPool = dbPool;
932
+ mysqlPool.on("release", () => {
933
+ if (DEBUG) {
934
+ console.log("MySQL client released from pool");
935
+ }
936
+ waitUntilIdleTimeout(dbPool);
937
+ });
938
+ return;
939
+ } else if ("on" in dbPool && dbPool.on && "config" in dbPool && dbPool.config && "idleTimeout" in dbPool.config) {
940
+ const mysql2Pool = dbPool;
941
+ mysql2Pool.on("release", () => {
942
+ if (DEBUG) {
943
+ console.log("MySQL2/MariaDB client released from pool");
944
+ }
945
+ waitUntilIdleTimeout(dbPool);
946
+ });
947
+ return;
948
+ }
949
+ if ("on" in dbPool && dbPool.on && "options" in dbPool && dbPool.options && "maxIdleTimeMS" in dbPool.options) {
950
+ const mongoPool = dbPool;
951
+ mongoPool.on("connectionCheckedOut", () => {
952
+ if (DEBUG) {
953
+ console.log("MongoDB connection checked out");
954
+ }
955
+ waitUntilIdleTimeout(dbPool);
956
+ });
957
+ return;
958
+ }
959
+ if ("on" in dbPool && dbPool.on && "options" in dbPool && dbPool.options && "socket" in dbPool.options) {
960
+ const redisPool = dbPool;
961
+ redisPool.on("end", () => {
962
+ if (DEBUG) {
963
+ console.log("Redis connection ended");
964
+ }
965
+ waitUntilIdleTimeout(dbPool);
966
+ });
967
+ return;
968
+ }
969
+ throw new Error("Unsupported database pool type");
970
+ }
971
+ var experimental_attachDatabasePool2 = attachDatabasePool2;
972
+ }
973
+ });
974
+
975
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/purge/index.js
976
+ var require_purge = __commonJS({
977
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/purge/index.js"(exports, module) {
978
+ "use strict";
979
+ var __defProp2 = Object.defineProperty;
980
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
981
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
982
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
983
+ var __export = (target, all) => {
984
+ for (var name in all)
985
+ __defProp2(target, name, { get: all[name], enumerable: true });
986
+ };
987
+ var __copyProps2 = (to, from, except, desc) => {
988
+ if (from && typeof from === "object" || typeof from === "function") {
989
+ for (let key of __getOwnPropNames2(from))
990
+ if (!__hasOwnProp2.call(to, key) && key !== except)
991
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
992
+ }
993
+ return to;
994
+ };
995
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
996
+ var purge_exports = {};
997
+ __export(purge_exports, {
998
+ dangerouslyDeleteBySrcImage: () => dangerouslyDeleteBySrcImage2,
999
+ dangerouslyDeleteByTag: () => dangerouslyDeleteByTag2,
1000
+ invalidateBySrcImage: () => invalidateBySrcImage2,
1001
+ invalidateByTag: () => invalidateByTag2
1002
+ });
1003
+ module.exports = __toCommonJS(purge_exports);
1004
+ var import_get_context = require_get_context();
1005
+ var invalidateByTag2 = (tag) => {
1006
+ const api = (0, import_get_context.getContext)().purge;
1007
+ if (api) {
1008
+ return api.invalidateByTag(tag);
1009
+ }
1010
+ return Promise.resolve();
1011
+ };
1012
+ var dangerouslyDeleteByTag2 = (tag, options) => {
1013
+ const api = (0, import_get_context.getContext)().purge;
1014
+ if (api) {
1015
+ return api.dangerouslyDeleteByTag(tag, options);
1016
+ }
1017
+ return Promise.resolve();
1018
+ };
1019
+ var invalidateBySrcImage2 = (src) => {
1020
+ const api = (0, import_get_context.getContext)().purge;
1021
+ return api ? api.invalidateBySrcImage(src) : Promise.resolve();
1022
+ };
1023
+ var dangerouslyDeleteBySrcImage2 = (src, options) => {
1024
+ const api = (0, import_get_context.getContext)().purge;
1025
+ return api ? api.dangerouslyDeleteBySrcImage(src, options) : Promise.resolve();
1026
+ };
1027
+ }
1028
+ });
1029
+
1030
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/addcachetag/index.js
1031
+ var require_addcachetag = __commonJS({
1032
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/addcachetag/index.js"(exports, module) {
1033
+ "use strict";
1034
+ var __defProp2 = Object.defineProperty;
1035
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
1036
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
1037
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
1038
+ var __export = (target, all) => {
1039
+ for (var name in all)
1040
+ __defProp2(target, name, { get: all[name], enumerable: true });
1041
+ };
1042
+ var __copyProps2 = (to, from, except, desc) => {
1043
+ if (from && typeof from === "object" || typeof from === "function") {
1044
+ for (let key of __getOwnPropNames2(from))
1045
+ if (!__hasOwnProp2.call(to, key) && key !== except)
1046
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
1047
+ }
1048
+ return to;
1049
+ };
1050
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
1051
+ var addcachetag_exports = {};
1052
+ __export(addcachetag_exports, {
1053
+ addCacheTag: () => addCacheTag2
1054
+ });
1055
+ module.exports = __toCommonJS(addcachetag_exports);
1056
+ var import_get_context = require_get_context();
1057
+ var addCacheTag2 = (tag) => {
1058
+ const addCacheTag22 = (0, import_get_context.getContext)().addCacheTag;
1059
+ if (addCacheTag22) {
1060
+ return addCacheTag22(tag);
1061
+ }
1062
+ return Promise.resolve();
1063
+ };
1064
+ }
1065
+ });
1066
+
1067
+ // ../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/index.js
1068
+ var require_functions = __commonJS({
1069
+ "../../node_modules/.pnpm/@vercel+functions@3.4.3_@aws-sdk+credential-provider-web-identity@3.972.20/node_modules/@vercel/functions/index.js"(exports, module) {
1070
+ "use strict";
1071
+ var __defProp2 = Object.defineProperty;
1072
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
1073
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
1074
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
1075
+ var __export = (target, all) => {
1076
+ for (var name in all)
1077
+ __defProp2(target, name, { get: all[name], enumerable: true });
1078
+ };
1079
+ var __copyProps2 = (to, from, except, desc) => {
1080
+ if (from && typeof from === "object" || typeof from === "function") {
1081
+ for (let key of __getOwnPropNames2(from))
1082
+ if (!__hasOwnProp2.call(to, key) && key !== except)
1083
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
1084
+ }
1085
+ return to;
1086
+ };
1087
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
1088
+ var src_exports = {};
1089
+ __export(src_exports, {
1090
+ addCacheTag: () => import_addcachetag.addCacheTag,
1091
+ attachDatabasePool: () => import_db_connections.attachDatabasePool,
1092
+ dangerouslyDeleteBySrcImage: () => import_purge.dangerouslyDeleteBySrcImage,
1093
+ dangerouslyDeleteByTag: () => import_purge.dangerouslyDeleteByTag,
1094
+ experimental_attachDatabasePool: () => import_db_connections.experimental_attachDatabasePool,
1095
+ geolocation: () => import_headers.geolocation,
1096
+ getCache: () => import_cache.getCache,
1097
+ getEnv: () => import_get_env.getEnv,
1098
+ invalidateBySrcImage: () => import_purge.invalidateBySrcImage,
1099
+ invalidateByTag: () => import_purge.invalidateByTag,
1100
+ ipAddress: () => import_headers.ipAddress,
1101
+ next: () => import_middleware.next,
1102
+ rewrite: () => import_middleware.rewrite,
1103
+ waitUntil: () => import_wait_until.waitUntil
1104
+ });
1105
+ module.exports = __toCommonJS(src_exports);
1106
+ var import_headers = require_headers();
1107
+ var import_get_env = require_get_env();
1108
+ var import_wait_until = require_wait_until();
1109
+ var import_middleware = require_middleware();
1110
+ var import_cache = require_cache();
1111
+ var import_db_connections = require_db_connections();
1112
+ var import_purge = require_purge();
1113
+ var import_addcachetag = require_addcachetag();
1114
+ }
1115
+ });
1116
+
1117
+ // src/fix-registry.ts
1118
+ var FIX_REGISTRY = {
1119
+ AUTH_TOKEN_INVALID: [
1120
+ "\u2192 Run `brokr env pull --stack <name>` to refresh your token",
1121
+ "\u2192 Or run `brokr link account` to re-authenticate"
1122
+ ].join("\n"),
1123
+ AUTH_SESSION_EXPIRED: [
1124
+ "\u2192 Run `brokr link account` to re-authenticate"
1125
+ ].join("\n"),
1126
+ BROKR_TOKEN_MISSING: [
1127
+ "\u2192 Run `brokr env pull --stack <name>` to sync your environment",
1128
+ "\u2192 Or add BROKR_TOKEN to your .env.local manually"
1129
+ ].join("\n"),
1130
+ DATABASE_PROVISION_FAILED: [
1131
+ "\u2192 Run `brokr status <stack>` to check current state",
1132
+ "\u2192 Run `brokr retry <stack>` to re-trigger provisioning"
1133
+ ].join("\n"),
1134
+ DATABASE_QUOTA_REACHED: [
1135
+ "\u2192 Upgrade your plan or delete unused databases",
1136
+ "\u2192 Check usage at brokr.sh/billing"
1137
+ ].join("\n"),
1138
+ DATABASE_HEALTH_TIMEOUT: [
1139
+ "\u2192 Run `brokr status <stack>` to check database state",
1140
+ "\u2192 If persistent, check provider status page"
1141
+ ].join("\n"),
1142
+ DEPLOYMENT_FAILED: [
1143
+ "\u2192 Run `brokr logs --stack <name>` to see build logs",
1144
+ "\u2192 Fix the build error and run `brokr deploy`"
1145
+ ].join("\n"),
1146
+ DEPLOYMENT_RATE_LIMITED: [
1147
+ "\u2192 Wait a minute and retry",
1148
+ "\u2192 Vercel rate limits apply per project"
1149
+ ].join("\n"),
1150
+ REPO_ALREADY_EXISTS: [
1151
+ "\u2192 Use a different stack name",
1152
+ "\u2192 Or run `brokr status <stack>` to check the existing stack"
1153
+ ].join("\n"),
1154
+ REPO_CREATE_FAILED: [
1155
+ "\u2192 Check your GitHub connection: `brokr link account`",
1156
+ "\u2192 Ensure the Brokr GitHub App is installed"
1157
+ ].join("\n"),
1158
+ EMAIL_DOMAIN_FAILED: [
1159
+ "\u2192 Check DNS records are propagated",
1160
+ "\u2192 Run `brokr status <stack>` for details"
1161
+ ].join("\n"),
1162
+ DNS_RECORD_FAILED: [
1163
+ "\u2192 Check Cloudflare dashboard for zone status",
1164
+ "\u2192 Retry with `brokr retry <stack>`"
1165
+ ].join("\n"),
1166
+ INSUFFICIENT_CREDITS: [
1167
+ "\u2192 Top up credits at brokr.sh/billing",
1168
+ "\u2192 Or run `brokr billing topup`"
1169
+ ].join("\n"),
1170
+ AI_BUDGET_EXCEEDED: [
1171
+ "\u2192 Top up credits at brokr.sh/billing",
1172
+ "\u2192 Or run `brokr billing topup`"
1173
+ ].join("\n"),
1174
+ AI_PROVIDER_UNAVAILABLE: [
1175
+ "\u2192 The AI provider is temporarily down",
1176
+ "\u2192 Retry in a few seconds \u2014 this is usually transient"
1177
+ ].join("\n"),
1178
+ AI_MODEL_NOT_FOUND: [
1179
+ "\u2192 Check the model name in your configuration",
1180
+ "\u2192 See available models at brokr.sh/docs/ai-models"
1181
+ ].join("\n"),
1182
+ ENV_VAR_MISSING: [
1183
+ "\u2192 Run `brokr env pull --stack <name>` to sync environment",
1184
+ "\u2192 Check required vars in your template README"
1185
+ ].join("\n"),
1186
+ STACK_LIMIT_REACHED: [
1187
+ "\u2192 Delete unused stacks with `brokr delete <stack>`",
1188
+ "\u2192 Or upgrade your plan at brokr.sh/billing"
1189
+ ].join("\n"),
1190
+ STACK_NOT_FOUND: [
1191
+ "\u2192 Check the stack name: `brokr list`",
1192
+ "\u2192 Create a new stack: `brokr create --name <name>`"
1193
+ ].join("\n"),
1194
+ RATE_LIMITED: [
1195
+ "\u2192 Wait a moment and retry",
1196
+ "\u2192 If persistent, check brokr.sh/status"
1197
+ ].join("\n"),
1198
+ GATEWAY_AUTH_FAILED: [
1199
+ "\u2192 Your BROKR_TOKEN may be expired",
1200
+ "\u2192 Run `brokr env pull --stack <name>` to refresh"
1201
+ ].join("\n"),
1202
+ BROKR_TOKEN_INVALID: [
1203
+ "\u2192 Your BROKR_TOKEN has expired or been revoked",
1204
+ "\u2192 Run `brokr env pull --stack <name>` to get a fresh token"
1205
+ ].join("\n"),
1206
+ AI_STREAM_ERROR: [
1207
+ "\u2192 The AI stream was interrupted",
1208
+ "\u2192 Retry the request \u2014 this is usually transient"
1209
+ ].join("\n"),
1210
+ EMAIL_SEND_FAILED: [
1211
+ "\u2192 Email delivery failed",
1212
+ "\u2192 Check that your domain DNS is verified: `brokr status <stack>`"
1213
+ ].join("\n"),
1214
+ EMAIL_NOT_CONFIGURED: [
1215
+ "\u2192 Email is not set up for this stack",
1216
+ "\u2192 Add email capability: `brokr add email --stack <name>`"
1217
+ ].join("\n"),
1218
+ EMAIL_INVALID_FROM: [
1219
+ "\u2192 The from address must match your verified domain",
1220
+ "\u2192 Check your domain: `brokr status <stack>`"
1221
+ ].join("\n"),
1222
+ STORAGE_UPLOAD_FAILED: [
1223
+ "\u2192 File upload failed",
1224
+ "\u2192 Check file size limits and retry"
1225
+ ].join("\n"),
1226
+ STORAGE_NOT_FOUND: [
1227
+ "\u2192 The requested file does not exist",
1228
+ "\u2192 Check the key and try again"
1229
+ ].join("\n"),
1230
+ PAYMENTS_NOT_CONFIGURED: [
1231
+ "\u2192 Payments are not set up for this stack",
1232
+ "\u2192 Run `brokr payments sync` to configure Stripe"
1233
+ ].join("\n"),
1234
+ PAYMENTS_FAILED: [
1235
+ "\u2192 Payment processing failed",
1236
+ "\u2192 Check your Stripe dashboard for details"
1237
+ ].join("\n"),
1238
+ GATEWAY_INTERNAL: [
1239
+ "\u2192 The Brokr gateway encountered an internal error",
1240
+ "\u2192 Check brokr.sh/status for service health"
1241
+ ].join("\n"),
1242
+ UPSTREAM_ERROR: [
1243
+ "\u2192 An upstream service is temporarily unavailable",
1244
+ "\u2192 Retry in a few seconds \u2014 this is usually transient"
1245
+ ].join("\n"),
1246
+ NETWORK_ERROR: [
1247
+ "\u2192 Could not reach the Brokr gateway",
1248
+ "\u2192 Check your internet connection",
1249
+ "\u2192 Check brokr.sh/status for service health"
1250
+ ].join("\n"),
1251
+ TIMEOUT: [
1252
+ "\u2192 Request timed out",
1253
+ "\u2192 Retry \u2014 if persistent, check brokr.sh/status"
1254
+ ].join("\n")
1255
+ };
1256
+
1257
+ // src/errors.ts
1258
+ var BrokrError = class extends Error {
1259
+ constructor(message, code, capability, retryable = false, errorCode, requestId, hint) {
1260
+ super(message);
1261
+ this.code = code;
1262
+ this.capability = capability;
1263
+ this.retryable = retryable;
1264
+ this.errorCode = errorCode;
1265
+ this.requestId = requestId;
1266
+ this.hint = hint;
1267
+ this.name = "BrokrError";
1268
+ }
1269
+ /** Multi-line terminal fix block — looked up from error code. */
1270
+ get fix() {
1271
+ if (!this.errorCode) return void 0;
1272
+ return FIX_REGISTRY[this.errorCode];
1273
+ }
1274
+ /** Documentation URL for this error code. */
1275
+ get docsUrl() {
1276
+ if (!this.errorCode) return void 0;
1277
+ return `https://brokr.sh/errors/${this.errorCode.toLowerCase().replace(/_/g, "-")}`;
1278
+ }
1279
+ /** Safe message for end users — zero technical language. */
1280
+ toUserMessage() {
1281
+ switch (this.code) {
1282
+ case "RATE_LIMITED":
1283
+ return "Please wait a moment and try again.";
1284
+ case "TIMEOUT":
1285
+ return "The request took too long. Please try again.";
1286
+ case "NETWORK_ERROR":
1287
+ return "Connection issue. Check your internet and try again.";
1288
+ case "BROKR_TOKEN_MISSING":
1289
+ return "App is not connected to Brokr. Contact the developer.";
1290
+ case "BROKR_TOKEN_INVALID":
1291
+ return "Session expired. Please refresh.";
1292
+ case "AI_BUDGET_EXCEEDED":
1293
+ return "AI usage limit reached. The developer needs to add credits.";
1294
+ case "AI_PROVIDER_UNAVAILABLE":
1295
+ return "AI service is temporarily down. Please retry shortly.";
1296
+ case "AI_PROVIDER_RATE_LIMITED":
1297
+ return "Too many AI requests. Please wait a moment.";
1298
+ case "INSUFFICIENT_CREDITS":
1299
+ return "Not enough credits. Please top up your balance.";
1300
+ case "STORAGE_UPLOAD_FAILED":
1301
+ return "File upload failed. Please try again.";
1302
+ case "STORAGE_NOT_FOUND":
1303
+ return "File not found.";
1304
+ case "EMAIL_SEND_FAILED":
1305
+ return "Email could not be sent. Please try again.";
1306
+ case "EMAIL_NOT_CONFIGURED":
1307
+ return "Email is not set up for this app.";
1308
+ case "PAYMENTS_NOT_CONFIGURED":
1309
+ return "Payments are not configured. Contact the developer.";
1310
+ case "PAYMENTS_FAILED":
1311
+ return "Payment processing failed. Please try again.";
1312
+ case "NOT_FOUND":
1313
+ return "The requested resource was not found.";
1314
+ case "VALIDATION_ERROR":
1315
+ return "Invalid input. Please check your data and try again.";
1316
+ default:
1317
+ return "Something went wrong. We're looking into it.";
1318
+ }
1319
+ }
1320
+ toString() {
1321
+ return `${this.name} [${this.errorCode ?? this.code}]: ${this.message}`;
1322
+ }
1323
+ toJSON() {
1324
+ return {
1325
+ name: this.name,
1326
+ code: this.code,
1327
+ errorCode: this.errorCode,
1328
+ message: this.message,
1329
+ capability: this.capability,
1330
+ retryable: this.retryable,
1331
+ requestId: this.requestId,
1332
+ hint: this.hint,
1333
+ component: this.component
1334
+ };
1335
+ }
1336
+ };
1337
+ var BrokrAuthError = class extends BrokrError {
1338
+ constructor(message, code) {
1339
+ super(message, code, "auth", false);
1340
+ this.name = "BrokrAuthError";
1341
+ }
1342
+ };
1343
+ var BrokrRateLimitError = class extends BrokrError {
1344
+ constructor(message, retryAfter, capability) {
1345
+ super(message, "RATE_LIMITED", capability, true);
1346
+ this.retryAfter = retryAfter;
1347
+ this.name = "BrokrRateLimitError";
1348
+ }
1349
+ };
1350
+ var BrokrNetworkError = class extends BrokrError {
1351
+ constructor(message, capability) {
1352
+ super(message, "NETWORK_ERROR", capability, true);
1353
+ this.name = "BrokrNetworkError";
1354
+ }
1355
+ };
1356
+ var BrokrTimeoutError = class extends BrokrError {
1357
+ constructor(message, capability) {
1358
+ super(message, "TIMEOUT", capability, true);
1359
+ this.name = "BrokrTimeoutError";
1360
+ }
1361
+ };
1362
+ var BrokrNotFoundError = class extends BrokrError {
1363
+ constructor(message, capability) {
1364
+ super(message, "NOT_FOUND", capability, false);
1365
+ this.name = "BrokrNotFoundError";
1366
+ }
1367
+ };
1368
+ var BrokrValidationError = class extends BrokrError {
1369
+ constructor(message, capability) {
1370
+ super(message, "VALIDATION_ERROR", capability, false);
1371
+ this.name = "BrokrValidationError";
1372
+ }
1373
+ };
1374
+
1375
+ // src/gateway.ts
1376
+ var GATEWAY_URL = "https://api.brokr.sh";
1377
+ var FETCH_TIMEOUT_MS = 3e4;
1378
+ function resolveToken() {
1379
+ return typeof process !== "undefined" ? process.env.BROKR_TOKEN : void 0;
1380
+ }
1381
+ function requireToken(token, capability) {
1382
+ if (!token) {
1383
+ let hint = "brokr env pull --stack <name>";
1384
+ try {
1385
+ if (typeof process !== "undefined") {
1386
+ const fs = __require("fs");
1387
+ const path = __require("path");
1388
+ const brokrFile = path.join(process.cwd(), ".brokr");
1389
+ if (fs.existsSync(brokrFile)) {
1390
+ const data = JSON.parse(fs.readFileSync(brokrFile, "utf8"));
1391
+ if (data?.stackName) hint = `brokr env pull --stack ${data.stackName}`;
1392
+ }
1393
+ }
1394
+ } catch {
1395
+ }
1396
+ throw new BrokrAuthError(
1397
+ `BROKR_TOKEN is not set. Run: ${hint}`,
1398
+ "BROKR_TOKEN_MISSING"
1399
+ );
1400
+ }
1401
+ }
1402
+ async function gatewayFetch(gatewayUrl, token, path, body, capability) {
1403
+ const controller = new AbortController();
1404
+ const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
1405
+ let res;
1406
+ try {
1407
+ res = await fetch(`${gatewayUrl}${path}`, {
1408
+ method: "POST",
1409
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
1410
+ body: JSON.stringify(body),
1411
+ signal: controller.signal
1412
+ });
1413
+ } catch (err) {
1414
+ if (err instanceof Error && err.name === "AbortError") {
1415
+ throw new BrokrTimeoutError(
1416
+ `Request timed out after ${FETCH_TIMEOUT_MS / 1e3}s`,
1417
+ capability
1418
+ );
1419
+ }
1420
+ throw new BrokrNetworkError(
1421
+ "Could not reach Brokr gateway. Check your network.",
1422
+ capability
1423
+ );
1424
+ } finally {
1425
+ clearTimeout(timeout);
1426
+ }
1427
+ if (res.status === 429) {
1428
+ const rawRetryAfter = parseInt(res.headers.get("Retry-After") ?? "60", 10);
1429
+ const retryAfter = Number.isFinite(rawRetryAfter) ? rawRetryAfter : 60;
1430
+ const data = await res.json().catch(() => ({}));
1431
+ const errorMsg = typeof data.error === "string" ? data.error : `Rate limited (retry after ${retryAfter}s)`;
1432
+ throw new BrokrRateLimitError(
1433
+ errorMsg,
1434
+ retryAfter,
1435
+ capability
1436
+ );
1437
+ }
1438
+ if (res.status === 401) {
1439
+ throw new BrokrAuthError("Invalid or expired BROKR_TOKEN.", "BROKR_TOKEN_INVALID");
1440
+ }
1441
+ if (!res.ok) {
1442
+ const body2 = await res.json().catch(() => ({}));
1443
+ const errObj = typeof body2.error === "object" && body2.error !== null ? body2.error : void 0;
1444
+ const errorData = body2.data ?? errObj?.data ?? body2;
1445
+ const errorCode = errorData.errorCode ?? body2.code;
1446
+ const hint = errorData.hint;
1447
+ const requestId = errorData.requestId ?? res.headers.get("x-request-id");
1448
+ const retryable = errorData.retryable;
1449
+ const errorStr = typeof body2.error === "string" ? body2.error : void 0;
1450
+ const message = body2.message ?? errObj?.message ?? errorStr ?? `${capability} request failed (HTTP ${res.status})`;
1451
+ throw new BrokrError(
1452
+ message,
1453
+ errorCode ?? `${capability.toUpperCase()}_FAILED`,
1454
+ capability,
1455
+ retryable ?? false,
1456
+ errorCode ?? void 0,
1457
+ requestId ?? void 0,
1458
+ hint ?? void 0
1459
+ );
1460
+ }
1461
+ try {
1462
+ return await res.json();
1463
+ } catch {
1464
+ throw new BrokrError(
1465
+ `${capability} returned invalid response (expected JSON).`,
1466
+ `${capability.toUpperCase()}_INVALID_RESPONSE`,
1467
+ capability,
1468
+ true
1469
+ );
1470
+ }
1471
+ }
1472
+ async function gatewayStream(gatewayUrl, token, path, body, capability) {
1473
+ const controller = new AbortController();
1474
+ const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
1475
+ let res;
1476
+ try {
1477
+ res = await fetch(`${gatewayUrl}${path}`, {
1478
+ method: "POST",
1479
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
1480
+ body: JSON.stringify(body),
1481
+ signal: controller.signal
1482
+ });
1483
+ } catch (err) {
1484
+ clearTimeout(timeout);
1485
+ if (err instanceof Error && err.name === "AbortError") {
1486
+ throw new BrokrTimeoutError(
1487
+ `Stream request timed out after ${FETCH_TIMEOUT_MS / 1e3}s`,
1488
+ capability
1489
+ );
1490
+ }
1491
+ throw new BrokrNetworkError(
1492
+ "Could not reach Brokr gateway. Check your network.",
1493
+ capability
1494
+ );
1495
+ }
1496
+ clearTimeout(timeout);
1497
+ if (res.status === 429) {
1498
+ const retryAfter = parseInt(res.headers.get("Retry-After") ?? "60", 10);
1499
+ throw new BrokrRateLimitError("Rate limited.", retryAfter, capability);
1500
+ }
1501
+ if (res.status === 401) {
1502
+ throw new BrokrAuthError("Invalid or expired BROKR_TOKEN.", "BROKR_TOKEN_INVALID");
1503
+ }
1504
+ if (!res.ok || !res.body) {
1505
+ throw new BrokrError(
1506
+ `${capability} stream failed (HTTP ${res.status})`,
1507
+ `${capability.toUpperCase()}_STREAM_FAILED`,
1508
+ capability
1509
+ );
1510
+ }
1511
+ return res;
1512
+ }
1513
+
1514
+ // src/env-detect.ts
1515
+ var cached = null;
1516
+ function detectEnv() {
1517
+ if (cached) return cached;
1518
+ cached = _detect();
1519
+ return cached;
1520
+ }
1521
+ function _detect() {
1522
+ if (typeof process !== "undefined" && process.env) {
1523
+ const vercel = process.env.VERCEL;
1524
+ const vercelEnv = process.env.VERCEL_ENV;
1525
+ if (vercel === "1" || vercel === "true") {
1526
+ if (vercelEnv === "preview") return "staging";
1527
+ if (vercelEnv === "production") return "production";
1528
+ return "production";
1529
+ }
1530
+ return "development";
1531
+ }
1532
+ if (typeof window !== "undefined" && window.location) {
1533
+ const host = window.location.hostname;
1534
+ if (host === "localhost" || host === "127.0.0.1" || host === "::1") {
1535
+ return "development";
1536
+ }
1537
+ if (host.includes("-staging.brokr.sh") || host.includes(".preview.brokr.sh")) {
1538
+ return "staging";
1539
+ }
1540
+ if (host.endsWith(".brokr.sh") || host === "brokr.sh") {
1541
+ return "production";
1542
+ }
1543
+ return "production";
1544
+ }
1545
+ return "production";
1546
+ }
1547
+
1548
+ // src/dev-console.ts
1549
+ var BrokrDevConsole = class _BrokrDevConsole {
1550
+ static {
1551
+ this.installed = false;
1552
+ }
1553
+ static {
1554
+ this.env = "production";
1555
+ }
1556
+ static install() {
1557
+ if (_BrokrDevConsole.installed) return;
1558
+ const env = detectEnv();
1559
+ if (env === "production") return;
1560
+ _BrokrDevConsole.installed = true;
1561
+ _BrokrDevConsole.env = env;
1562
+ if (typeof process !== "undefined" && process.on) {
1563
+ process.on("unhandledRejection", (err) => {
1564
+ if (err instanceof BrokrError) {
1565
+ try {
1566
+ _BrokrDevConsole.print(err);
1567
+ } catch {
1568
+ }
1569
+ }
1570
+ });
1571
+ }
1572
+ }
1573
+ static print(err) {
1574
+ if (_BrokrDevConsole.env === "staging") {
1575
+ const hint = err.hint ?? err.message;
1576
+ console.error(`[brokr] ${err.errorCode ?? err.code}: ${hint}`);
1577
+ return;
1578
+ }
1579
+ const lines = [
1580
+ "",
1581
+ "\u2501".repeat(41),
1582
+ "",
1583
+ ` Brokr${err.component ? ` \u2014 ${err.component}` : ""}`,
1584
+ "",
1585
+ ` ${err.message}`
1586
+ ];
1587
+ if (err.fix) {
1588
+ lines.push("", " Fix it:");
1589
+ for (const line of err.fix.split("\n")) lines.push(` ${line}`);
1590
+ }
1591
+ if (err.docsUrl) {
1592
+ lines.push("", ` Still broken? \u2192 ${err.docsUrl}`);
1593
+ }
1594
+ lines.push("", "\u2501".repeat(41), "");
1595
+ console.error(lines.join("\n"));
1596
+ }
1597
+ };
1598
+
1599
+ // src/logs/capture.ts
1600
+ var DEFAULT_BATCH_SIZE = 20;
1601
+ var DEFAULT_FLUSH_INTERVAL_MS = 5e3;
1602
+ var buffer = [];
1603
+ var flushTimer = null;
1604
+ var config = null;
1605
+ var intercepted = false;
1606
+ function initCapture(opts = {}) {
1607
+ if (config) return;
1608
+ const token = opts.token ?? (typeof process !== "undefined" ? process.env.BROKR_TOKEN : void 0);
1609
+ const stackId = opts.stackId ?? resolveStackId();
1610
+ if (!token || !stackId) {
1611
+ if (typeof process !== "undefined") {
1612
+ console.log(`[brokr] Log capture skipped: token=${token ? "present" : "MISSING"} stackId=${stackId ?? "MISSING"}`);
1613
+ }
1614
+ return;
1615
+ }
1616
+ const apiUrl = opts.apiUrl ?? opts.gatewayUrl ?? (typeof process !== "undefined" ? process.env.BROKR_GATEWAY_URL : void 0) ?? "https://api.brokr.sh";
1617
+ config = {
1618
+ token,
1619
+ stackId,
1620
+ apiUrl: apiUrl.replace(/\/+$/, ""),
1621
+ batchSize: opts.batchSize ?? DEFAULT_BATCH_SIZE,
1622
+ flushIntervalMs: opts.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS
1623
+ };
1624
+ if (typeof process !== "undefined") {
1625
+ console.log(`[brokr] Log capture initialized \u2192 ${apiUrl}/v1/logs/ingest (stack: ${stackId.slice(0, 8)}...)`);
1626
+ }
1627
+ if (flushTimer) clearInterval(flushTimer);
1628
+ flushTimer = setInterval(() => flush(), config.flushIntervalMs);
1629
+ if (typeof process !== "undefined" && process.on) {
1630
+ process.on("beforeExit", () => flush());
1631
+ }
1632
+ if (typeof process !== "undefined" && !intercepted) {
1633
+ intercepted = true;
1634
+ const origError = console.error;
1635
+ const origWarn = console.warn;
1636
+ console.error = (...args) => {
1637
+ origError.apply(console, args);
1638
+ try {
1639
+ const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
1640
+ if (!msg.startsWith("[brokr]")) capture("error", msg, "console.error");
1641
+ } catch {
1642
+ }
1643
+ };
1644
+ console.warn = (...args) => {
1645
+ origWarn.apply(console, args);
1646
+ try {
1647
+ const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
1648
+ if (!msg.startsWith("[brokr]")) capture("warn", msg, "console.warn");
1649
+ } catch {
1650
+ }
1651
+ };
1652
+ }
1653
+ }
1654
+ function capture(level, message, source, stackTrace) {
1655
+ if (!config) return;
1656
+ buffer.push({
1657
+ level,
1658
+ message: message.slice(0, 1e4),
1659
+ source: source ?? "app",
1660
+ stackTrace: stackTrace?.slice(0, 5e4),
1661
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1662
+ });
1663
+ if (buffer.length >= (config.batchSize ?? DEFAULT_BATCH_SIZE)) {
1664
+ flush();
1665
+ }
1666
+ }
1667
+ function captureRequest(method, path, statusCode, durationMs) {
1668
+ const level = statusCode >= 500 ? "error" : statusCode >= 400 ? "warn" : "info";
1669
+ const dur = durationMs != null ? ` ${durationMs}ms` : "";
1670
+ capture(level, `${method} ${path} ${statusCode}${dur}`, path);
1671
+ }
1672
+ function flush() {
1673
+ if (!config || buffer.length === 0) return;
1674
+ const entries = buffer.splice(0);
1675
+ const { token, stackId, apiUrl } = config;
1676
+ fetch(`${apiUrl}/v1/logs/ingest`, {
1677
+ method: "POST",
1678
+ headers: {
1679
+ "Content-Type": "application/json",
1680
+ Authorization: `Bearer ${token}`
1681
+ },
1682
+ body: JSON.stringify({ stackId, entries })
1683
+ }).catch((err) => {
1684
+ if (typeof console !== "undefined") {
1685
+ console.warn("[brokr] Log flush failed:", err instanceof Error ? err.message : err);
1686
+ }
1687
+ });
1688
+ }
1689
+ function resolveStackId() {
1690
+ if (typeof process === "undefined") return void 0;
1691
+ if (process.env.BROKR_STACK_ID) return process.env.BROKR_STACK_ID;
1692
+ try {
1693
+ const fs = __require("fs");
1694
+ const path = __require("path");
1695
+ const brokrFile = path.join(process.cwd(), ".brokr");
1696
+ if (fs.existsSync(brokrFile)) {
1697
+ const content = fs.readFileSync(brokrFile, "utf8");
1698
+ const match = content.match(/BROKR_STACK_ID=(.+)/);
1699
+ if (match) return match[1].trim();
1700
+ }
1701
+ } catch {
1702
+ }
1703
+ return void 0;
1704
+ }
1705
+
1706
+ // src/ai/client.ts
1707
+ function normalizeInput(input) {
1708
+ if (typeof input === "string") {
1709
+ return [{ role: "user", content: input }];
1710
+ }
1711
+ return input;
1712
+ }
1713
+ var BrokrAIClient = class {
1714
+ constructor(_token, _gatewayUrl) {
1715
+ this._token = _token;
1716
+ this._gatewayUrl = _gatewayUrl;
1717
+ }
1718
+ // ---------------------------------------------------------------------------
1719
+ // Core chat
1720
+ // ---------------------------------------------------------------------------
1721
+ /**
1722
+ * Send a chat completion request.
1723
+ * Accepts a string (auto-wrapped as user message) or a message array.
1724
+ */
1725
+ async chat(input, options) {
1726
+ requireToken(this._token, "ai");
1727
+ const messages = normalizeInput(input);
1728
+ try {
1729
+ const data = await gatewayFetch(this._gatewayUrl, this._token, "/v1/chat/completions", {
1730
+ messages,
1731
+ model: options?.model,
1732
+ max_tokens: options?.maxTokens,
1733
+ temperature: options?.temperature
1734
+ }, "ai");
1735
+ return {
1736
+ content: data.choices?.[0]?.message?.content ?? "",
1737
+ model: data.model ?? "",
1738
+ usage: {
1739
+ promptTokens: data.usage?.prompt_tokens ?? 0,
1740
+ completionTokens: data.usage?.completion_tokens ?? 0
1741
+ }
1742
+ };
1743
+ } catch (err) {
1744
+ if (err instanceof BrokrError) err.component = "AIChat";
1745
+ const msg = err instanceof Error ? err.message : String(err);
1746
+ capture("error", `AI chat failed: ${msg}`, "brokr.ai.chat", err instanceof Error ? err.stack : void 0);
1747
+ throw err;
1748
+ }
1749
+ }
1750
+ /**
1751
+ * Stream a chat completion. Yields text strings directly.
1752
+ * Accepts a string (auto-wrapped as user message) or a message array.
1753
+ */
1754
+ /**
1755
+ * Stream a chat completion. Yields text strings directly.
1756
+ * Tries streaming first — if the gateway or provider doesn't support it,
1757
+ * falls back to a non-streaming call and yields the full response at once.
1758
+ */
1759
+ async *stream(input, options) {
1760
+ requireToken(this._token, "ai");
1761
+ const messages = normalizeInput(input);
1762
+ let res;
1763
+ try {
1764
+ res = await gatewayStream(
1765
+ this._gatewayUrl,
1766
+ this._token,
1767
+ "/v1/chat/completions",
1768
+ {
1769
+ messages,
1770
+ stream: true,
1771
+ model: options?.model,
1772
+ max_tokens: options?.maxTokens,
1773
+ temperature: options?.temperature
1774
+ },
1775
+ "ai"
1776
+ );
1777
+ } catch (err) {
1778
+ if (err instanceof BrokrError) err.component = "AIStream";
1779
+ const msg = err instanceof Error ? err.message : String(err);
1780
+ capture("error", `AI stream failed: ${msg}`, "brokr.ai.stream", err instanceof Error ? err.stack : void 0);
1781
+ try {
1782
+ const fallback = await this.chat(input, options);
1783
+ yield fallback.content;
1784
+ } catch (fallbackErr) {
1785
+ throw err;
1786
+ }
1787
+ return;
1788
+ }
1789
+ const ct = res.headers.get("content-type") ?? "";
1790
+ if (!ct.includes("text/event-stream")) {
1791
+ try {
1792
+ const data = await res.json();
1793
+ const content = data.choices?.[0]?.message?.content ?? "";
1794
+ if (content) yield content;
1795
+ } catch {
1796
+ const fallback = await this.chat(input, options);
1797
+ yield fallback.content;
1798
+ }
1799
+ return;
1800
+ }
1801
+ const reader = res.body.getReader();
1802
+ const decoder = new TextDecoder();
1803
+ let buffer2 = "";
1804
+ while (true) {
1805
+ const { done, value } = await reader.read();
1806
+ if (done) break;
1807
+ buffer2 += decoder.decode(value, { stream: true });
1808
+ const lines = buffer2.split("\n");
1809
+ buffer2 = lines.pop() ?? "";
1810
+ for (const line of lines) {
1811
+ if (!line.startsWith("data: ")) continue;
1812
+ const payload = line.slice(6).trim();
1813
+ if (payload === "[DONE]") return;
1814
+ try {
1815
+ const parsed = JSON.parse(payload);
1816
+ const delta = parsed.choices?.[0]?.delta?.content ?? "";
1817
+ if (delta) yield delta;
1818
+ } catch {
1819
+ }
1820
+ }
1821
+ }
1822
+ }
1823
+ // ---------------------------------------------------------------------------
1824
+ // Higher-level primitives
1825
+ // ---------------------------------------------------------------------------
1826
+ /**
1827
+ * Extract structured data from a prompt using JSON mode.
1828
+ * Returns a parsed object matching the provided schema shape.
1829
+ */
1830
+ async structured(params) {
1831
+ requireToken(this._token, "ai");
1832
+ const schemaStr = JSON.stringify(params.schema, null, 2);
1833
+ const messages = [
1834
+ {
1835
+ role: "system",
1836
+ content: `You are a structured data extraction assistant. Return ONLY valid JSON matching this schema:
1837
+ ${schemaStr}
1838
+ Do not include any other text, markdown, or explanation.`
1839
+ },
1840
+ { role: "user", content: params.prompt }
1841
+ ];
1842
+ try {
1843
+ const data = await gatewayFetch(this._gatewayUrl, this._token, "/v1/chat/completions", {
1844
+ messages,
1845
+ model: params.model,
1846
+ temperature: params.temperature ?? 0,
1847
+ response_format: { type: "json_object" }
1848
+ }, "ai");
1849
+ const raw = data.choices?.[0]?.message?.content ?? "{}";
1850
+ try {
1851
+ return JSON.parse(raw);
1852
+ } catch {
1853
+ throw new BrokrError(
1854
+ "[brokr] AI returned invalid JSON for structured extraction.",
1855
+ "AI_STRUCTURED_PARSE_ERROR",
1856
+ "ai"
1857
+ );
1858
+ }
1859
+ } catch (err) {
1860
+ if (err instanceof BrokrError) err.component = "AIStructured";
1861
+ throw err;
1862
+ }
1863
+ }
1864
+ /**
1865
+ * Extract fields from unstructured text.
1866
+ * Semantic alias for structured() — same behavior, clearer intent.
1867
+ */
1868
+ async extract(prompt, schema) {
1869
+ return this.structured({ prompt, schema });
1870
+ }
1871
+ /**
1872
+ * Summarize text using AI.
1873
+ */
1874
+ async summarize(text, options) {
1875
+ try {
1876
+ const lengthHint = options?.maxLength ? ` Keep it under ${options.maxLength}.` : "";
1877
+ const response = await this.chat(
1878
+ [
1879
+ {
1880
+ role: "system",
1881
+ content: `You are a summarization assistant. Provide a concise, accurate summary of the following text.${lengthHint} Return only the summary, no preamble.`
1882
+ },
1883
+ { role: "user", content: text }
1884
+ ],
1885
+ { model: options?.model }
1886
+ );
1887
+ return { summary: response.content };
1888
+ } catch (err) {
1889
+ if (err instanceof BrokrError) err.component = "AISummarize";
1890
+ throw err;
1891
+ }
1892
+ }
1893
+ /**
1894
+ * Classify text into one of the provided labels.
1895
+ */
1896
+ async classify(text, labels, options) {
1897
+ try {
1898
+ const labelsStr = labels.map((l) => `"${l}"`).join(", ");
1899
+ const result = await this.structured({
1900
+ prompt: `Classify the following text into exactly one of these labels: [${labelsStr}]
1901
+
1902
+ Text: ${text}`,
1903
+ schema: {
1904
+ type: "object",
1905
+ properties: {
1906
+ label: { type: "string", enum: labels },
1907
+ confidence: { type: "number", minimum: 0, maximum: 1 }
1908
+ },
1909
+ required: ["label", "confidence"]
1910
+ },
1911
+ model: options?.model,
1912
+ temperature: 0
1913
+ });
1914
+ return result;
1915
+ } catch (err) {
1916
+ if (err instanceof BrokrError) err.component = "AIClassify";
1917
+ throw err;
1918
+ }
1919
+ }
1920
+ /**
1921
+ * Generate an embedding vector for the given text.
1922
+ */
1923
+ async embed(text) {
1924
+ requireToken(this._token, "ai");
1925
+ try {
1926
+ const data = await gatewayFetch(this._gatewayUrl, this._token, "/v1/embeddings", {
1927
+ input: text,
1928
+ model: "text-embedding-3-small"
1929
+ }, "ai");
1930
+ return {
1931
+ vector: data.data?.[0]?.embedding ?? []
1932
+ };
1933
+ } catch (err) {
1934
+ if (err instanceof BrokrError) err.component = "AIEmbed";
1935
+ throw err;
1936
+ }
1937
+ }
1938
+ /**
1939
+ * Generate an image from a text prompt.
1940
+ */
1941
+ async image(prompt, options) {
1942
+ requireToken(this._token, "ai");
1943
+ try {
1944
+ const data = await gatewayFetch(this._gatewayUrl, this._token, "/v1/images/generate", {
1945
+ prompt,
1946
+ size: options?.size ?? "1024x1024",
1947
+ n: options?.n ?? 1,
1948
+ model: options?.model
1949
+ }, "ai");
1950
+ const url = data.data?.[0]?.url;
1951
+ if (!url) {
1952
+ throw new BrokrError("[brokr] Image generation returned no URL.", "AI_IMAGE_FAILED", "ai");
1953
+ }
1954
+ return { url };
1955
+ } catch (err) {
1956
+ if (err instanceof BrokrError) err.component = "AIImage";
1957
+ throw err;
1958
+ }
1959
+ }
1960
+ // ---------------------------------------------------------------------------
1961
+ // OpenAI-SDK compatibility
1962
+ // ---------------------------------------------------------------------------
1963
+ /** OpenAI-SDK compatible base URL. */
1964
+ get baseURL() {
1965
+ return `${this._gatewayUrl}/v1`;
1966
+ }
1967
+ /** Use as `apiKey` with the official OpenAI SDK to route through Brokr's gateway. */
1968
+ get apiKey() {
1969
+ requireToken(this._token, "ai");
1970
+ return this._token;
1971
+ }
1972
+ };
1973
+
1974
+ // src/storage/client.ts
1975
+ var MULTIPART_THRESHOLD = 100 * 1024 * 1024;
1976
+ var DEFAULT_PART_SIZE = 100 * 1024 * 1024;
1977
+ var PART_UPLOAD_RETRIES = 3;
1978
+ var BrokrStorageClient = class {
1979
+ constructor(_token, _gatewayUrl) {
1980
+ this._token = _token;
1981
+ this._gatewayUrl = _gatewayUrl;
1982
+ }
1983
+ async upload(paramsOrData, filename, contentTypeArg) {
1984
+ try {
1985
+ let data;
1986
+ let filePath;
1987
+ let contentType;
1988
+ if (typeof paramsOrData === "object" && paramsOrData !== null && "file" in paramsOrData) {
1989
+ data = paramsOrData.file;
1990
+ filePath = paramsOrData.path ?? `upload-${Date.now()}`;
1991
+ contentType = paramsOrData.contentType ?? "application/octet-stream";
1992
+ } else {
1993
+ data = paramsOrData;
1994
+ filePath = filename ?? `upload-${Date.now()}`;
1995
+ contentType = contentTypeArg ?? "application/octet-stream";
1996
+ }
1997
+ const size = getUploadSize(data);
1998
+ if (size !== void 0 && size > MULTIPART_THRESHOLD) {
1999
+ return await this._uploadMultipart(data, filePath, contentType, size);
2000
+ }
2001
+ const { url, key } = await this.signUpload({ fileName: filePath, contentType });
2002
+ const uploadHeaders = { "Content-Type": contentType };
2003
+ if (typeof window === "undefined") {
2004
+ const origin = process.env.BETTER_AUTH_URL ?? process.env.NEXT_PUBLIC_APP_URL ?? process.env.APP_URL ?? process.env.BROKR_AUTH_URL ?? (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : void 0) ?? "http://localhost:3000";
2005
+ uploadHeaders.Origin = origin;
2006
+ }
2007
+ const putRes = await fetch(url, {
2008
+ method: "PUT",
2009
+ headers: uploadHeaders,
2010
+ body: data
2011
+ });
2012
+ if (!putRes.ok) {
2013
+ throw new BrokrError(
2014
+ `[brokr] Upload failed (HTTP ${putRes.status})`,
2015
+ "STORAGE_UPLOAD_FAILED",
2016
+ "storage"
2017
+ );
2018
+ }
2019
+ const gatewayBase = this._gatewayUrl.replace(/\/+$/, "");
2020
+ const permanentUrl = `${gatewayBase}/v1/storage/file/${encodeURI(key)}`;
2021
+ return {
2022
+ key,
2023
+ url: permanentUrl,
2024
+ name: filePath,
2025
+ size,
2026
+ type: contentType
2027
+ };
2028
+ } catch (err) {
2029
+ if (err instanceof BrokrError) err.component = "Storage";
2030
+ throw err;
2031
+ }
2032
+ }
2033
+ /**
2034
+ * Get a presigned download URL for a stored object.
2035
+ */
2036
+ async signedUrl(key, options) {
2037
+ requireToken(this._token, "storage");
2038
+ try {
2039
+ return await gatewayFetch(
2040
+ this._gatewayUrl,
2041
+ this._token,
2042
+ "/v1/storage/sign-download",
2043
+ { key, expiresIn: options?.expiresIn },
2044
+ "storage"
2045
+ );
2046
+ } catch (err) {
2047
+ if (err instanceof BrokrError) err.component = "Storage";
2048
+ throw err;
2049
+ }
2050
+ }
2051
+ /** Low-level escape hatch. Most apps should call upload() instead. */
2052
+ async signUpload(params) {
2053
+ requireToken(this._token, "storage");
2054
+ try {
2055
+ return await gatewayFetch(
2056
+ this._gatewayUrl,
2057
+ this._token,
2058
+ "/v1/storage/sign-upload",
2059
+ { filename: params.fileName, contentType: params.contentType ?? "application/octet-stream" },
2060
+ "storage"
2061
+ );
2062
+ } catch (err) {
2063
+ if (err instanceof BrokrError) err.component = "Storage";
2064
+ throw err;
2065
+ }
2066
+ }
2067
+ // ---------------------------------------------------------------------------
2068
+ // Multipart upload — handles files > 100MB, up to 20GB
2069
+ // ---------------------------------------------------------------------------
2070
+ /**
2071
+ * Initiate a multipart upload via the gateway.
2072
+ */
2073
+ async _initiateMultipart(params) {
2074
+ requireToken(this._token, "storage");
2075
+ return gatewayFetch(
2076
+ this._gatewayUrl,
2077
+ this._token,
2078
+ "/v1/storage/multipart/initiate",
2079
+ {
2080
+ filename: params.fileName,
2081
+ contentType: params.contentType,
2082
+ totalSize: params.totalSize,
2083
+ partCount: params.partCount
2084
+ },
2085
+ "storage"
2086
+ );
2087
+ }
2088
+ /**
2089
+ * Get a presigned URL for uploading a single part.
2090
+ */
2091
+ async _signPartUpload(params) {
2092
+ requireToken(this._token, "storage");
2093
+ return gatewayFetch(
2094
+ this._gatewayUrl,
2095
+ this._token,
2096
+ "/v1/storage/multipart/sign-part",
2097
+ params,
2098
+ "storage"
2099
+ );
2100
+ }
2101
+ /**
2102
+ * Complete a multipart upload with part ETags.
2103
+ */
2104
+ async _completeMultipart(params) {
2105
+ requireToken(this._token, "storage");
2106
+ return gatewayFetch(
2107
+ this._gatewayUrl,
2108
+ this._token,
2109
+ "/v1/storage/multipart/complete",
2110
+ params,
2111
+ "storage"
2112
+ );
2113
+ }
2114
+ /**
2115
+ * Abort a multipart upload, cleaning up uploaded parts.
2116
+ */
2117
+ async _abortMultipart(params) {
2118
+ requireToken(this._token, "storage");
2119
+ await gatewayFetch(
2120
+ this._gatewayUrl,
2121
+ this._token,
2122
+ "/v1/storage/multipart/abort",
2123
+ params,
2124
+ "storage"
2125
+ );
2126
+ }
2127
+ /**
2128
+ * Upload a large file using multipart upload.
2129
+ * Splits the file into parts, uploads each with retry, then completes.
2130
+ */
2131
+ async _uploadMultipart(data, filePath, contentType, totalSize) {
2132
+ const bytes = await toUint8Array(data);
2133
+ const partSize = Math.max(DEFAULT_PART_SIZE, Math.ceil(totalSize / MAX_PARTS_PER_UPLOAD));
2134
+ const partCount = Math.ceil(totalSize / partSize);
2135
+ const { uploadId, key } = await this._initiateMultipart({
2136
+ fileName: filePath,
2137
+ contentType,
2138
+ totalSize,
2139
+ partCount
2140
+ });
2141
+ try {
2142
+ const completedParts = [];
2143
+ for (let i = 0; i < partCount; i++) {
2144
+ const partNumber = i + 1;
2145
+ const start = i * partSize;
2146
+ const end = Math.min(start + partSize, totalSize);
2147
+ const partData = bytes.slice(start, end);
2148
+ const { url } = await this._signPartUpload({ key, uploadId, partNumber });
2149
+ let lastError;
2150
+ for (let attempt = 0; attempt < PART_UPLOAD_RETRIES; attempt++) {
2151
+ try {
2152
+ const putRes = await fetch(url, {
2153
+ method: "PUT",
2154
+ body: partData
2155
+ });
2156
+ if (!putRes.ok) {
2157
+ throw new Error(`Part ${partNumber} upload failed (HTTP ${putRes.status})`);
2158
+ }
2159
+ const etag = putRes.headers.get("ETag");
2160
+ if (!etag) {
2161
+ throw new Error(`Part ${partNumber} upload returned no ETag`);
2162
+ }
2163
+ completedParts.push({ partNumber, etag });
2164
+ lastError = void 0;
2165
+ break;
2166
+ } catch (err) {
2167
+ lastError = err instanceof Error ? err : new Error(String(err));
2168
+ }
2169
+ }
2170
+ if (lastError) {
2171
+ throw new BrokrError(
2172
+ `[brokr] Multipart upload failed at part ${partNumber} after ${PART_UPLOAD_RETRIES} retries: ${lastError.message}`,
2173
+ "STORAGE_UPLOAD_FAILED",
2174
+ "storage"
2175
+ );
2176
+ }
2177
+ }
2178
+ completedParts.sort((a, b) => a.partNumber - b.partNumber);
2179
+ await this._completeMultipart({ key, uploadId, parts: completedParts });
2180
+ const gatewayBase = this._gatewayUrl.replace(/\/+$/, "");
2181
+ const permanentUrl = `${gatewayBase}/v1/storage/file/${encodeURI(key)}`;
2182
+ return {
2183
+ key,
2184
+ url: permanentUrl,
2185
+ name: filePath,
2186
+ size: totalSize,
2187
+ type: contentType
2188
+ };
2189
+ } catch (err) {
2190
+ try {
2191
+ await this._abortMultipart({ key, uploadId });
2192
+ } catch {
2193
+ }
2194
+ throw err;
2195
+ }
2196
+ }
2197
+ /**
2198
+ * List objects by prefix with pagination.
2199
+ */
2200
+ async list(params) {
2201
+ requireToken(this._token, "storage");
2202
+ try {
2203
+ return await gatewayFetch(
2204
+ this._gatewayUrl,
2205
+ this._token,
2206
+ "/v1/storage/list",
2207
+ {
2208
+ prefix: params?.prefix,
2209
+ maxKeys: params?.maxKeys,
2210
+ cursor: params?.cursor
2211
+ },
2212
+ "storage"
2213
+ );
2214
+ } catch (err) {
2215
+ if (err instanceof BrokrError) err.component = "Storage";
2216
+ throw err;
2217
+ }
2218
+ }
2219
+ /**
2220
+ * Delete an object by key.
2221
+ */
2222
+ async delete(key) {
2223
+ requireToken(this._token, "storage");
2224
+ try {
2225
+ await gatewayFetch(
2226
+ this._gatewayUrl,
2227
+ this._token,
2228
+ "/v1/storage/delete",
2229
+ { key },
2230
+ "storage"
2231
+ );
2232
+ } catch (err) {
2233
+ if (err instanceof BrokrError) err.component = "Storage";
2234
+ throw err;
2235
+ }
2236
+ }
2237
+ /**
2238
+ * Copy an object from one key to another.
2239
+ */
2240
+ async copy(from, to) {
2241
+ requireToken(this._token, "storage");
2242
+ try {
2243
+ return await gatewayFetch(
2244
+ this._gatewayUrl,
2245
+ this._token,
2246
+ "/v1/storage/copy",
2247
+ { from, to },
2248
+ "storage"
2249
+ );
2250
+ } catch (err) {
2251
+ if (err instanceof BrokrError) err.component = "Storage";
2252
+ throw err;
2253
+ }
2254
+ }
2255
+ /**
2256
+ * Move an object (copy then delete source).
2257
+ */
2258
+ async move(from, to) {
2259
+ try {
2260
+ const copied = await this.copy(from, to);
2261
+ await this.delete(from);
2262
+ return copied;
2263
+ } catch (err) {
2264
+ if (err instanceof BrokrError) err.component = "Storage";
2265
+ throw err;
2266
+ }
2267
+ }
2268
+ /**
2269
+ * Check if an object exists.
2270
+ */
2271
+ /**
2272
+ * Check if an object exists.
2273
+ *
2274
+ * Returns `false` on any error (not-found, rate-limit, network).
2275
+ * This preserves backwards compatibility — `if (await brokr.storage.exists(key))`
2276
+ * must never throw in user code that doesn't wrap it in try-catch.
2277
+ *
2278
+ * If you need to distinguish "doesn't exist" from "couldn't check",
2279
+ * use `metadata()` instead and catch the error.
2280
+ */
2281
+ async exists(key) {
2282
+ requireToken(this._token, "storage");
2283
+ try {
2284
+ const result = await gatewayFetch(
2285
+ this._gatewayUrl,
2286
+ this._token,
2287
+ "/v1/storage/exists",
2288
+ { key },
2289
+ "storage"
2290
+ );
2291
+ return result.exists;
2292
+ } catch (err) {
2293
+ if (err instanceof BrokrError) err.component = "Storage";
2294
+ return false;
2295
+ }
2296
+ }
2297
+ /**
2298
+ * Get file metadata without downloading the file.
2299
+ */
2300
+ async metadata(key) {
2301
+ requireToken(this._token, "storage");
2302
+ try {
2303
+ return await gatewayFetch(
2304
+ this._gatewayUrl,
2305
+ this._token,
2306
+ "/v1/storage/metadata",
2307
+ { key },
2308
+ "storage"
2309
+ );
2310
+ } catch (err) {
2311
+ if (err instanceof BrokrError) err.component = "Storage";
2312
+ throw err;
2313
+ }
2314
+ }
2315
+ // ---------------------------------------------------------------------------
2316
+ // Deprecated aliases (backward compat)
2317
+ // ---------------------------------------------------------------------------
2318
+ /** @deprecated Use signedUrl() instead. */
2319
+ async url(key, options) {
2320
+ return this.signedUrl(key, options);
2321
+ }
2322
+ /** @deprecated Use signedUrl() instead. */
2323
+ async getUrl(key, options) {
2324
+ return this.signedUrl(key, options);
2325
+ }
2326
+ /** @deprecated Use signUpload() instead. */
2327
+ async getUploadUrl(filename, contentType) {
2328
+ return this.signUpload({ fileName: filename, contentType });
2329
+ }
17
2330
  };
18
- var __copyProps = (to, from, except, desc) => {
19
- if (from && typeof from === "object" || typeof from === "function") {
20
- for (let key of __getOwnPropNames(from))
21
- if (!__hasOwnProp.call(to, key) && key !== except)
22
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
2331
+ var MAX_PARTS_PER_UPLOAD = 1e4;
2332
+ async function toUint8Array(data) {
2333
+ if (data instanceof Uint8Array) return data;
2334
+ if (typeof data === "string") return new TextEncoder().encode(data);
2335
+ if (typeof Blob !== "undefined" && data instanceof Blob) {
2336
+ return new Uint8Array(await data.arrayBuffer());
2337
+ }
2338
+ throw new Error("Unsupported data type for multipart upload");
2339
+ }
2340
+ function getUploadSize(data) {
2341
+ if (typeof data === "string") {
2342
+ return new TextEncoder().encode(data).length;
2343
+ }
2344
+ if (data instanceof Uint8Array) {
2345
+ return data.byteLength;
2346
+ }
2347
+ if (typeof Blob !== "undefined" && data instanceof Blob) {
2348
+ return data.size;
2349
+ }
2350
+ return void 0;
2351
+ }
2352
+
2353
+ // src/email/templates.ts
2354
+ function interpolate(template, vars) {
2355
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? "");
2356
+ }
2357
+ function wrapHtml(body) {
2358
+ return `<!DOCTYPE html>
2359
+ <html>
2360
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"></head>
2361
+ <body style="margin:0;padding:0;background:#f5f5f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
2362
+ <div style="max-width:560px;margin:40px auto;background:#ffffff;border-radius:8px;border:1px solid #e5e5e5;overflow:hidden;">
2363
+ ${body}
2364
+ </div>
2365
+ <div style="text-align:center;padding:20px;color:#999;font-size:12px;">
2366
+ Sent via Brokr
2367
+ </div>
2368
+ </body>
2369
+ </html>`;
2370
+ }
2371
+ function section(content) {
2372
+ return `<div style="padding:32px 40px;">${content}</div>`;
2373
+ }
2374
+ function button(text, urlVar) {
2375
+ return `<a href="{{${urlVar}}}" style="display:inline-block;padding:12px 24px;background:#000;color:#fff;text-decoration:none;border-radius:6px;font-weight:600;font-size:14px;">${text}</a>`;
2376
+ }
2377
+ var welcomeTemplate = {
2378
+ name: "welcome",
2379
+ subject: "Welcome to {{appName}}",
2380
+ html: (vars) => interpolate(wrapHtml(section(`
2381
+ <h1 style="margin:0 0 16px;font-size:24px;color:#111;">Welcome to {{appName}}</h1>
2382
+ <p style="margin:0 0 24px;color:#555;font-size:15px;line-height:1.6;">
2383
+ Your account is ready. You can start using {{appName}} right away.
2384
+ </p>
2385
+ ${button("Get Started", "actionUrl")}
2386
+ `)), vars)
2387
+ };
2388
+ var magicLinkTemplate = {
2389
+ name: "magicLink",
2390
+ subject: "Your sign-in link",
2391
+ html: (vars) => interpolate(wrapHtml(section(`
2392
+ <h1 style="margin:0 0 16px;font-size:24px;color:#111;">Sign in to {{appName}}</h1>
2393
+ <p style="margin:0 0 24px;color:#555;font-size:15px;line-height:1.6;">
2394
+ Click the button below to sign in. This link expires in 10 minutes.
2395
+ </p>
2396
+ ${button("Sign In", "magicLinkUrl")}
2397
+ <p style="margin:24px 0 0;color:#999;font-size:13px;">
2398
+ If you didn't request this, you can safely ignore this email.
2399
+ </p>
2400
+ `)), vars)
2401
+ };
2402
+ var passwordResetTemplate = {
2403
+ name: "passwordReset",
2404
+ subject: "Reset your password",
2405
+ html: (vars) => interpolate(wrapHtml(section(`
2406
+ <h1 style="margin:0 0 16px;font-size:24px;color:#111;">Reset your password</h1>
2407
+ <p style="margin:0 0 24px;color:#555;font-size:15px;line-height:1.6;">
2408
+ We received a request to reset your password for {{appName}}.
2409
+ Click the button below to choose a new password.
2410
+ </p>
2411
+ ${button("Reset Password", "resetUrl")}
2412
+ <p style="margin:24px 0 0;color:#999;font-size:13px;">
2413
+ This link expires in 1 hour. If you didn't request this, ignore this email.
2414
+ </p>
2415
+ `)), vars)
2416
+ };
2417
+ var invoiceTemplate = {
2418
+ name: "invoice",
2419
+ subject: "Invoice #{{invoiceNumber}}",
2420
+ html: (vars) => interpolate(wrapHtml(section(`
2421
+ <h1 style="margin:0 0 16px;font-size:24px;color:#111;">Invoice #{{invoiceNumber}}</h1>
2422
+ <p style="margin:0 0 8px;color:#555;font-size:15px;line-height:1.6;">
2423
+ Amount: <strong>{{amount}}</strong>
2424
+ </p>
2425
+ <p style="margin:0 0 24px;color:#555;font-size:15px;line-height:1.6;">
2426
+ {{description}}
2427
+ </p>
2428
+ ${button("View Invoice", "invoiceUrl")}
2429
+ `)), vars)
2430
+ };
2431
+ var notificationTemplate = {
2432
+ name: "notification",
2433
+ subject: "{{title}}",
2434
+ html: (vars) => interpolate(wrapHtml(section(`
2435
+ <h1 style="margin:0 0 16px;font-size:24px;color:#111;">{{title}}</h1>
2436
+ <p style="margin:0 0 24px;color:#555;font-size:15px;line-height:1.6;">
2437
+ {{body}}
2438
+ </p>
2439
+ `)), vars)
2440
+ };
2441
+ var builtinTemplates = {
2442
+ welcome: welcomeTemplate,
2443
+ magicLink: magicLinkTemplate,
2444
+ passwordReset: passwordResetTemplate,
2445
+ invoice: invoiceTemplate,
2446
+ notification: notificationTemplate
2447
+ };
2448
+
2449
+ // src/email/client.ts
2450
+ function interpolate2(template, vars) {
2451
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? "");
2452
+ }
2453
+ var BrokrEmailClient = class {
2454
+ constructor(_token, _gatewayUrl) {
2455
+ this._token = _token;
2456
+ this._gatewayUrl = _gatewayUrl;
2457
+ }
2458
+ /**
2459
+ * Send an email. The from address and API credentials are resolved server-side.
2460
+ */
2461
+ async send(params) {
2462
+ requireToken(this._token, "email");
2463
+ try {
2464
+ return await gatewayFetch(
2465
+ this._gatewayUrl,
2466
+ this._token,
2467
+ "/v1/email/send",
2468
+ params,
2469
+ "email"
2470
+ );
2471
+ } catch (err) {
2472
+ if (err instanceof BrokrError) err.component = "Email";
2473
+ throw err;
2474
+ }
2475
+ }
2476
+ /**
2477
+ * Send an email using a built-in template.
2478
+ *
2479
+ * @example
2480
+ * ```typescript
2481
+ * await brokr.email.sendTemplate({
2482
+ * template: 'welcome',
2483
+ * to: 'user@example.com',
2484
+ * variables: { appName: 'MyApp', actionUrl: 'https://myapp.com/dashboard' },
2485
+ * });
2486
+ * ```
2487
+ */
2488
+ async sendTemplate(params) {
2489
+ try {
2490
+ const template = builtinTemplates[params.template];
2491
+ if (!template) {
2492
+ throw new BrokrError(
2493
+ `[brokr] Unknown email template "${params.template}". Available: ${Object.keys(builtinTemplates).join(", ")}`,
2494
+ "EMAIL_TEMPLATE_NOT_FOUND",
2495
+ "email"
2496
+ );
2497
+ }
2498
+ const subject = interpolate2(template.subject, params.variables);
2499
+ const html = template.html(params.variables);
2500
+ return await this.send({
2501
+ to: params.to,
2502
+ subject,
2503
+ html,
2504
+ from: params.from
2505
+ });
2506
+ } catch (err) {
2507
+ if (err instanceof BrokrError) err.component = "Email";
2508
+ throw err;
2509
+ }
2510
+ }
2511
+ };
2512
+
2513
+ // src/files/client.ts
2514
+ var BrokrFilesClient = class {
2515
+ constructor(_token, _gatewayUrl, _storage) {
2516
+ this._token = _token;
2517
+ this._gatewayUrl = _gatewayUrl;
2518
+ this._storage = _storage;
2519
+ }
2520
+ /**
2521
+ * Upload a file and trigger server-side AI processing.
2522
+ * Returns the storage key plus any extracted description/text.
2523
+ */
2524
+ async process(params) {
2525
+ requireToken(this._token, "files");
2526
+ const uploaded = await this._storage.upload({
2527
+ file: params.file,
2528
+ path: params.fileName,
2529
+ contentType: params.purpose === "text-extraction" ? "application/pdf" : void 0
2530
+ });
2531
+ const result = await gatewayFetch(
2532
+ this._gatewayUrl,
2533
+ this._token,
2534
+ "/v1/files/process",
2535
+ { key: uploaded.key, purpose: params.purpose ?? "general" },
2536
+ "files"
2537
+ );
2538
+ return {
2539
+ key: uploaded.key,
2540
+ description: result.description,
2541
+ text: result.text
2542
+ };
2543
+ }
2544
+ /**
2545
+ * Get an AI-generated description of an already-uploaded file.
2546
+ */
2547
+ async describe(key) {
2548
+ requireToken(this._token, "files");
2549
+ return gatewayFetch(
2550
+ this._gatewayUrl,
2551
+ this._token,
2552
+ "/v1/files/describe",
2553
+ { key },
2554
+ "files"
2555
+ );
2556
+ }
2557
+ /**
2558
+ * Extract text from a PDF or image (OCR).
2559
+ */
2560
+ async getText(key) {
2561
+ requireToken(this._token, "files");
2562
+ return gatewayFetch(
2563
+ this._gatewayUrl,
2564
+ this._token,
2565
+ "/v1/files/text",
2566
+ { key },
2567
+ "files"
2568
+ );
2569
+ }
2570
+ };
2571
+
2572
+ // src/payments/client.ts
2573
+ var BrokrPaymentsClient = class {
2574
+ constructor(_token, _gatewayUrl) {
2575
+ this._token = _token;
2576
+ this._gatewayUrl = _gatewayUrl;
2577
+ }
2578
+ /**
2579
+ * Create a Stripe Checkout session for a plan.
2580
+ * Returns a URL to redirect the end user to.
2581
+ *
2582
+ * @example
2583
+ * ```ts
2584
+ * const user = await brokr.auth.requireUser(request.headers);
2585
+ * const { checkoutUrl } = await brokr.payments.checkout({
2586
+ * plan: 'pro',
2587
+ * userId: user.id,
2588
+ * });
2589
+ * // Redirect user to checkoutUrl
2590
+ * ```
2591
+ */
2592
+ /**
2593
+ * Create a Stripe Checkout session for a plan.
2594
+ *
2595
+ * @param params.plan - Plan slug (e.g. 'pro')
2596
+ * @param params.userId - End user's ID from your auth system
2597
+ * @param params.returnUrl - Where to redirect after checkout. Defaults to your stack's URL.
2598
+ * Pass explicitly for localhost or non-Brokr deployments.
2599
+ */
2600
+ async checkout(params) {
2601
+ requireToken(this._token, "payments");
2602
+ try {
2603
+ return await gatewayFetch(
2604
+ this._gatewayUrl,
2605
+ this._token,
2606
+ "/v1/payments/checkout",
2607
+ { planSlug: params.plan, appUserId: params.userId, returnUrl: params.returnUrl },
2608
+ "payments"
2609
+ );
2610
+ } catch (err) {
2611
+ if (err instanceof BrokrError) err.component = "Payments";
2612
+ throw err;
2613
+ }
2614
+ }
2615
+ /**
2616
+ * Create a Stripe Customer Portal session.
2617
+ * Returns a URL where the end user can manage their subscription.
2618
+ */
2619
+ /**
2620
+ * Create a Stripe Customer Portal session.
2621
+ *
2622
+ * @param params.userId - End user's ID
2623
+ * @param params.returnUrl - Where to redirect when they're done. Defaults to your stack's URL.
2624
+ */
2625
+ async portal(params) {
2626
+ requireToken(this._token, "payments");
2627
+ try {
2628
+ return await gatewayFetch(
2629
+ this._gatewayUrl,
2630
+ this._token,
2631
+ "/v1/payments/portal",
2632
+ { appUserId: params.userId, returnUrl: params.returnUrl },
2633
+ "payments"
2634
+ );
2635
+ } catch (err) {
2636
+ if (err instanceof BrokrError) err.component = "Payments";
2637
+ throw err;
2638
+ }
2639
+ }
2640
+ /**
2641
+ * Get the end user's current plan.
2642
+ * Returns null if the user has no subscription.
2643
+ */
2644
+ async currentPlan(params) {
2645
+ requireToken(this._token, "payments");
2646
+ try {
2647
+ return await gatewayFetch(
2648
+ this._gatewayUrl,
2649
+ this._token,
2650
+ "/v1/payments/plan",
2651
+ { appUserId: params.userId },
2652
+ "payments"
2653
+ );
2654
+ } catch (err) {
2655
+ if (err instanceof BrokrError) err.component = "Payments";
2656
+ throw err;
2657
+ }
2658
+ }
2659
+ };
2660
+
2661
+ // src/payments/entitlements.ts
2662
+ var BrokrEntitlementsClient = class {
2663
+ constructor(_token, _gatewayUrl) {
2664
+ this._token = _token;
2665
+ this._gatewayUrl = _gatewayUrl;
2666
+ }
2667
+ /**
2668
+ * Check if an end user is entitled to a feature.
2669
+ * Returns true/false without throwing.
2670
+ *
2671
+ * @example
2672
+ * ```ts
2673
+ * const user = await brokr.auth.requireUser(request.headers);
2674
+ * const canChat = await brokr.entitlements.check({ feature: 'ai.chat', userId: user.id });
2675
+ * ```
2676
+ */
2677
+ async check(params) {
2678
+ requireToken(this._token, "payments");
2679
+ const result = await gatewayFetch(
2680
+ this._gatewayUrl,
2681
+ this._token,
2682
+ "/v1/payments/entitlements/check",
2683
+ { feature: params.feature, appUserId: params.userId },
2684
+ "payments"
2685
+ );
2686
+ return result.allowed;
2687
+ }
2688
+ /**
2689
+ * Require that an end user is entitled to a feature.
2690
+ * Throws BrokrError if not entitled.
2691
+ */
2692
+ async require(params) {
2693
+ const allowed = await this.check(params);
2694
+ if (!allowed) {
2695
+ throw new BrokrError(
2696
+ `[brokr] Feature "${params.feature}" is not available on the user's current plan. Upgrade at the billing portal.`,
2697
+ "ENTITLEMENT_DENIED",
2698
+ "payments"
2699
+ );
2700
+ }
2701
+ }
2702
+ /**
2703
+ * Get usage stats for a metered feature.
2704
+ * This is a READ — does NOT increment the counter.
2705
+ * Use `increment()` to record usage.
2706
+ */
2707
+ async usage(params) {
2708
+ requireToken(this._token, "payments");
2709
+ return gatewayFetch(
2710
+ this._gatewayUrl,
2711
+ this._token,
2712
+ "/v1/payments/entitlements/usage",
2713
+ { feature: params.feature, appUserId: params.userId },
2714
+ "payments"
2715
+ );
2716
+ }
2717
+ /**
2718
+ * Record a usage event for a metered feature.
2719
+ * This is a WRITE — increments the counter.
2720
+ */
2721
+ async increment(params) {
2722
+ requireToken(this._token, "payments");
2723
+ await gatewayFetch(
2724
+ this._gatewayUrl,
2725
+ this._token,
2726
+ "/v1/payments/entitlements/increment",
2727
+ { feature: params.feature, appUserId: params.userId, amount: params.amount ?? 1 },
2728
+ "payments"
2729
+ );
2730
+ }
2731
+ };
2732
+
2733
+ // src/notifications/client.ts
2734
+ var BrokrNotificationsClient = class {
2735
+ constructor(token, gatewayUrl) {
2736
+ this.token = token;
2737
+ this.gatewayUrl = gatewayUrl;
2738
+ }
2739
+ /**
2740
+ * Send a notification to a user. Delivered via WebSocket in real-time
2741
+ * and persisted in the notification history.
2742
+ */
2743
+ async send(params) {
2744
+ requireToken(this.token, "notifications");
2745
+ try {
2746
+ return await gatewayFetch(
2747
+ this.gatewayUrl,
2748
+ this.token,
2749
+ "/v1/notifications/push",
2750
+ params,
2751
+ "notifications"
2752
+ );
2753
+ } catch (err) {
2754
+ if (err instanceof BrokrError) err.component = "Notifications";
2755
+ throw err;
2756
+ }
2757
+ }
2758
+ /**
2759
+ * Fetch notification history for a user. Reads from the DO's SQLite
2760
+ * storage via a gateway REST endpoint.
2761
+ */
2762
+ async list(params) {
2763
+ requireToken(this.token, "notifications");
2764
+ try {
2765
+ return await gatewayFetch(
2766
+ this.gatewayUrl,
2767
+ this.token,
2768
+ "/v1/notifications/list",
2769
+ params,
2770
+ "notifications"
2771
+ );
2772
+ } catch (err) {
2773
+ if (err instanceof BrokrError) err.component = "Notifications";
2774
+ throw err;
2775
+ }
23
2776
  }
24
- return to;
25
2777
  };
26
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
2778
 
28
2779
  // src/auth.ts
29
- var auth_exports = {};
30
- __export(auth_exports, {
31
- BrokrAuthClient: () => BrokrAuthClient,
32
- authMiddleware: () => authMiddleware
33
- });
2780
+ function resolveAppUrl(appUrl) {
2781
+ if (appUrl) return appUrl;
2782
+ throw new BrokrError(
2783
+ "[brokr] BROKR_AUTH_URL is not set. Auth may not be provisioned.",
2784
+ "AUTH_NOT_CONFIGURED",
2785
+ "auth"
2786
+ );
2787
+ }
2788
+ function mapSessionUser(raw) {
2789
+ return {
2790
+ id: raw.id,
2791
+ email: raw.email,
2792
+ name: raw.name ?? null,
2793
+ image: raw.image ?? null,
2794
+ emailVerified: raw.emailVerified ? /* @__PURE__ */ new Date() : null
2795
+ };
2796
+ }
2797
+ function pluralizeResource(resource) {
2798
+ if (resource.endsWith("s")) return resource;
2799
+ if (resource.endsWith("y") && !/[aeiou]y$/i.test(resource)) return resource.slice(0, -1) + "ies";
2800
+ return resource + "s";
2801
+ }
2802
+ function validateSqlIdentifier(name, label) {
2803
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
2804
+ throw new BrokrError(
2805
+ `[brokr] Invalid ${label}: "${name}". Must be alphanumeric with underscores only.`,
2806
+ "INVALID_IDENTIFIER",
2807
+ "auth"
2808
+ );
2809
+ }
2810
+ }
2811
+ var _ownershipPool = null;
2812
+ async function getOwnershipPool(dbUrl) {
2813
+ let Pool;
2814
+ try {
2815
+ const mod = await import("@neondatabase/serverless");
2816
+ Pool = mod.Pool;
2817
+ } catch {
2818
+ throw new BrokrError(
2819
+ "[brokr] @neondatabase/serverless is required for ownership checks. Run: npm install @neondatabase/serverless",
2820
+ "MISSING_DEPENDENCY",
2821
+ "auth"
2822
+ );
2823
+ }
2824
+ if (_ownershipPool && _ownershipPool.dbUrl === dbUrl) {
2825
+ return _ownershipPool.pool;
2826
+ }
2827
+ const pool = new Pool({ connectionString: dbUrl, max: 3 });
2828
+ _ownershipPool = { pool, dbUrl };
2829
+ return pool;
2830
+ }
2831
+ async function authApiFetch(appUrl, path, options) {
2832
+ const headers = { "Content-Type": "application/json" };
2833
+ if (options?.cookies) headers.cookie = options.cookies;
2834
+ if (typeof window === "undefined") {
2835
+ headers.Origin = process.env.BETTER_AUTH_URL ?? process.env.NEXT_PUBLIC_APP_URL ?? process.env.APP_URL ?? process.env.BROKR_AUTH_URL ?? (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : void 0) ?? appUrl;
2836
+ }
2837
+ const res = await fetch(`${appUrl}${path}`, {
2838
+ method: options?.method ?? "GET",
2839
+ headers,
2840
+ body: options?.body ? JSON.stringify(options.body) : void 0
2841
+ });
2842
+ if (!res.ok) {
2843
+ const data = await res.json().catch(() => ({}));
2844
+ throw new BrokrError(
2845
+ data.message ?? `[brokr] Auth API call failed (HTTP ${res.status})`,
2846
+ "AUTH_API_FAILED",
2847
+ "auth"
2848
+ );
2849
+ }
2850
+ return res.json();
2851
+ }
2852
+ var BrokrAuthClient = class {
2853
+ constructor(_token, _gatewayUrl, appUrl) {
2854
+ this._appUrl = appUrl ?? (typeof process !== "undefined" ? process.env.BROKR_AUTH_URL : void 0);
2855
+ }
2856
+ // -------------------------------------------------------------------------
2857
+ // Identity — read user/session from incoming request
2858
+ // -------------------------------------------------------------------------
2859
+ /**
2860
+ * Get user from request headers. Returns null if not authenticated.
2861
+ * Calls the app's own Better Auth API.
2862
+ */
2863
+ async user(headers) {
2864
+ const session = await this.session(headers);
2865
+ return session?.user ?? null;
2866
+ }
2867
+ /**
2868
+ * Get user from request headers. Throws 401 if not authenticated.
2869
+ */
2870
+ async requireUser(headers) {
2871
+ const u = await this.user(headers);
2872
+ if (!u) {
2873
+ throw new BrokrError("[brokr] Authentication required. The request has no valid session. Check that cookies are being forwarded.", "UNAUTHORIZED", "auth");
2874
+ }
2875
+ return u;
2876
+ }
2877
+ /**
2878
+ * Get full session from request headers. Returns null if not authenticated.
2879
+ */
2880
+ async session(headers) {
2881
+ const appUrl = resolveAppUrl(this._appUrl);
2882
+ const cookieHeader = headers.get("cookie") ?? "";
2883
+ if (!cookieHeader) return null;
2884
+ const res = await fetch(`${appUrl}/api/auth/get-session`, {
2885
+ method: "GET",
2886
+ headers: { cookie: cookieHeader }
2887
+ });
2888
+ if (!res.ok) return null;
2889
+ const data = await res.json();
2890
+ if (!data?.user || !data?.session) return null;
2891
+ return {
2892
+ user: mapSessionUser(data.user),
2893
+ sessionId: data.session.id,
2894
+ expiresAt: new Date(data.session.expiresAt)
2895
+ };
2896
+ }
2897
+ /**
2898
+ * Get full session. Throws 401 if not authenticated.
2899
+ */
2900
+ async requireSession(headers) {
2901
+ const s = await this.session(headers);
2902
+ if (!s) {
2903
+ throw new BrokrError("[brokr] Authentication required. The request has no valid session. Check that cookies are being forwarded.", "UNAUTHORIZED", "auth");
2904
+ }
2905
+ return s;
2906
+ }
2907
+ // -------------------------------------------------------------------------
2908
+ // Legacy aliases (backward compat)
2909
+ // -------------------------------------------------------------------------
2910
+ /** @deprecated Use user(request.headers) instead. */
2911
+ async currentUser(request) {
2912
+ return this.user(request.headers);
2913
+ }
2914
+ /** @deprecated Use session(request.headers) instead. */
2915
+ async getSession(request) {
2916
+ return this.session(request.headers);
2917
+ }
2918
+ // -------------------------------------------------------------------------
2919
+ // Auth actions — call Better Auth endpoints on the stack's app
2920
+ // -------------------------------------------------------------------------
2921
+ /**
2922
+ * Sign in with email and password.
2923
+ */
2924
+ async signIn(params) {
2925
+ const appUrl = resolveAppUrl(this._appUrl);
2926
+ const data = await authApiFetch(appUrl, "/api/auth/sign-in/email", {
2927
+ method: "POST",
2928
+ body: params
2929
+ });
2930
+ return {
2931
+ user: mapSessionUser(data.user),
2932
+ sessionId: data.session.id,
2933
+ expiresAt: new Date(data.session.expiresAt)
2934
+ };
2935
+ }
2936
+ /**
2937
+ * Sign in with OAuth provider. Returns redirect URL.
2938
+ */
2939
+ async signInWithProvider(provider, options) {
2940
+ const appUrl = resolveAppUrl(this._appUrl);
2941
+ const redirectTo = options?.redirectTo ?? "/";
2942
+ if (!redirectTo.startsWith("/") || redirectTo.startsWith("//")) {
2943
+ throw new BrokrError("[brokr] redirectTo must be a relative path (start with /)", "INVALID_REDIRECT", "auth");
2944
+ }
2945
+ if (!/^[a-z][a-z0-9_-]*$/.test(provider)) {
2946
+ throw new BrokrError(`[brokr] Invalid provider name: "${provider}". Must be lowercase alphanumeric.`, "INVALID_PROVIDER", "auth");
2947
+ }
2948
+ const params = new URLSearchParams({ provider, callbackURL: redirectTo });
2949
+ return { redirectUrl: `${appUrl}/api/auth/sign-in/social?${params}` };
2950
+ }
2951
+ /**
2952
+ * Sign up with email and password.
2953
+ */
2954
+ async signUp(params) {
2955
+ const appUrl = resolveAppUrl(this._appUrl);
2956
+ const data = await authApiFetch(appUrl, "/api/auth/sign-up/email", {
2957
+ method: "POST",
2958
+ body: params
2959
+ });
2960
+ return {
2961
+ user: mapSessionUser(data.user),
2962
+ sessionId: data.session.id,
2963
+ expiresAt: new Date(data.session.expiresAt)
2964
+ };
2965
+ }
2966
+ /**
2967
+ * Sign out the current user.
2968
+ */
2969
+ async signOut(headers) {
2970
+ const appUrl = resolveAppUrl(this._appUrl);
2971
+ const cookies = headers?.get("cookie") ?? "";
2972
+ await authApiFetch(appUrl, "/api/auth/sign-out", {
2973
+ method: "POST",
2974
+ cookies
2975
+ });
2976
+ }
2977
+ /**
2978
+ * Send a magic link email.
2979
+ */
2980
+ async sendMagicLink(email, options) {
2981
+ const appUrl = resolveAppUrl(this._appUrl);
2982
+ await authApiFetch(appUrl, "/api/auth/magic-link/send", {
2983
+ method: "POST",
2984
+ body: { email, callbackURL: options?.redirectTo ?? "/" }
2985
+ });
2986
+ }
2987
+ /**
2988
+ * Send a password reset email.
2989
+ */
2990
+ async sendPasswordReset(params) {
2991
+ const appUrl = resolveAppUrl(this._appUrl);
2992
+ await authApiFetch(appUrl, "/api/auth/forget-password", {
2993
+ method: "POST",
2994
+ body: params
2995
+ });
2996
+ }
2997
+ /**
2998
+ * Reset password with token from email.
2999
+ */
3000
+ async resetPassword(params) {
3001
+ const appUrl = resolveAppUrl(this._appUrl);
3002
+ await authApiFetch(appUrl, "/api/auth/reset-password", {
3003
+ method: "POST",
3004
+ body: { token: params.token, newPassword: params.password }
3005
+ });
3006
+ }
3007
+ /**
3008
+ * Verify email with token from email.
3009
+ */
3010
+ async verifyEmail(params) {
3011
+ const appUrl = resolveAppUrl(this._appUrl);
3012
+ await authApiFetch(appUrl, "/api/auth/verify-email", {
3013
+ method: "POST",
3014
+ body: params
3015
+ });
3016
+ }
3017
+ /**
3018
+ * Update the current user's profile.
3019
+ */
3020
+ async updateUser(params, headers) {
3021
+ const appUrl = resolveAppUrl(this._appUrl);
3022
+ const cookies = headers?.get("cookie") ?? "";
3023
+ await authApiFetch(appUrl, "/api/auth/update-user", {
3024
+ method: "POST",
3025
+ body: params,
3026
+ cookies
3027
+ });
3028
+ }
3029
+ // -------------------------------------------------------------------------
3030
+ // Session management
3031
+ // -------------------------------------------------------------------------
3032
+ /** Session management sub-client. */
3033
+ get sessions() {
3034
+ if (!this._sessions) {
3035
+ this._sessions = new BrokrSessionsClient(this._appUrl);
3036
+ }
3037
+ return this._sessions;
3038
+ }
3039
+ // -------------------------------------------------------------------------
3040
+ // Ownership — queries the stack's own DB via gateway → server
3041
+ // -------------------------------------------------------------------------
3042
+ /**
3043
+ * Check if the current user owns a resource. Throws 403 if not.
3044
+ *
3045
+ * Queries the developer's own database directly via DATABASE_URL.
3046
+ * Convention: pluralizes resource name → table, assumes `id` PK + `user_id` owner column.
3047
+ * Override with `opts.table` and `opts.ownerColumn` for non-standard schemas.
3048
+ *
3049
+ * @example
3050
+ * ```ts
3051
+ * await brokr.auth.requireOwner('conversation', conversationId, request.headers);
3052
+ * // Under the hood: SELECT 1 FROM conversations WHERE id = $1 AND user_id = $2
3053
+ * ```
3054
+ */
3055
+ async requireOwner(resource, id, headers, opts) {
3056
+ const isOwner = await this.isOwner(resource, id, headers, opts);
3057
+ if (!isOwner) {
3058
+ throw new BrokrError(
3059
+ `[brokr] Access denied \u2014 current user does not own this ${resource}. Verify the resource ID and that the user is the owner.`,
3060
+ "FORBIDDEN",
3061
+ "auth"
3062
+ );
3063
+ }
3064
+ }
3065
+ /**
3066
+ * Check if the current user owns a resource. Returns boolean.
3067
+ *
3068
+ * Runs a direct query against the developer's database (DATABASE_URL).
3069
+ * No gateway round-trip — this is a local DB operation.
3070
+ */
3071
+ async isOwner(resource, id, headers, opts) {
3072
+ const user = await this.requireUser(headers);
3073
+ const dbUrl = typeof process !== "undefined" ? process.env.DATABASE_URL : void 0;
3074
+ if (!dbUrl) {
3075
+ throw new BrokrError(
3076
+ "[brokr] DATABASE_URL is not set. Cannot check ownership without a database.",
3077
+ "DB_NOT_CONFIGURED",
3078
+ "auth"
3079
+ );
3080
+ }
3081
+ const tableName = opts?.table ?? pluralizeResource(resource);
3082
+ const ownerCol = opts?.ownerColumn ?? "user_id";
3083
+ validateSqlIdentifier(tableName, "table name");
3084
+ validateSqlIdentifier(ownerCol, "owner column");
3085
+ const pool = await getOwnershipPool(dbUrl);
3086
+ try {
3087
+ const result = await pool.query(
3088
+ `SELECT 1 FROM "${tableName}" WHERE id = $1 AND "${ownerCol}" = $2 LIMIT 1`,
3089
+ [id, user.id]
3090
+ );
3091
+ return (result.rowCount ?? 0) > 0;
3092
+ } catch (err) {
3093
+ const msg = err instanceof Error ? err.message : String(err);
3094
+ console.error("[brokr] Ownership check error:", msg);
3095
+ if (msg.includes("does not exist")) {
3096
+ throw new BrokrError(
3097
+ `[brokr] Table "${tableName}" does not exist. Check your resource name or provide { table: '...' }.`,
3098
+ "TABLE_NOT_FOUND",
3099
+ "auth"
3100
+ );
3101
+ }
3102
+ throw new BrokrError(
3103
+ "[brokr] Ownership check failed. Check your DATABASE_URL and that the database is accessible.",
3104
+ "DB_QUERY_FAILED",
3105
+ "auth"
3106
+ );
3107
+ }
3108
+ }
3109
+ /**
3110
+ * Check if the current user matches a specific userId. Throws 403 if not.
3111
+ */
3112
+ async requireCurrentUser(userId, headers) {
3113
+ const user = await this.requireUser(headers);
3114
+ if (user.id !== userId) {
3115
+ throw new BrokrError("[brokr] Access denied.", "FORBIDDEN", "auth");
3116
+ }
3117
+ }
3118
+ // -------------------------------------------------------------------------
3119
+ // Legacy alias
3120
+ // -------------------------------------------------------------------------
3121
+ /** @deprecated Use signInWithProvider() instead. */
3122
+ async getOAuthUrl(provider, options) {
3123
+ return this.signInWithProvider(provider, options);
3124
+ }
3125
+ };
3126
+ var BrokrSessionsClient = class {
3127
+ constructor(appUrl) {
3128
+ this._appUrl = appUrl;
3129
+ }
3130
+ /**
3131
+ * List all active sessions for the current user.
3132
+ */
3133
+ async list(headers) {
3134
+ const appUrl = resolveAppUrl(this._appUrl);
3135
+ const cookies = headers.get("cookie") ?? "";
3136
+ const data = await authApiFetch(appUrl, "/api/auth/list-sessions", { cookies });
3137
+ const sessionToken = parseCookieValue(cookies, "better-auth.session_token") ?? parseCookieValue(cookies, "__Secure-better-auth.session_token");
3138
+ return data.map((s) => ({
3139
+ id: s.id,
3140
+ createdAt: new Date(s.createdAt),
3141
+ expiresAt: new Date(s.expiresAt),
3142
+ userAgent: s.userAgent,
3143
+ ipAddress: s.ipAddress,
3144
+ isCurrent: s.token === sessionToken
3145
+ }));
3146
+ }
3147
+ /**
3148
+ * Revoke a specific session by ID.
3149
+ */
3150
+ async revoke(sessionId, headers) {
3151
+ const appUrl = resolveAppUrl(this._appUrl);
3152
+ const cookies = headers.get("cookie") ?? "";
3153
+ await authApiFetch(appUrl, "/api/auth/revoke-session", {
3154
+ method: "POST",
3155
+ body: { id: sessionId },
3156
+ cookies
3157
+ });
3158
+ }
3159
+ /**
3160
+ * Revoke all sessions except the current one.
3161
+ */
3162
+ async revokeOthers(headers) {
3163
+ const appUrl = resolveAppUrl(this._appUrl);
3164
+ const cookies = headers.get("cookie") ?? "";
3165
+ await authApiFetch(appUrl, "/api/auth/revoke-other-sessions", {
3166
+ method: "POST",
3167
+ cookies
3168
+ });
3169
+ }
3170
+ };
34
3171
  function parseCookies(cookieHeader) {
35
3172
  const cookies = /* @__PURE__ */ new Map();
36
3173
  for (const pair of cookieHeader.split(";")) {
@@ -42,6 +3179,9 @@ function parseCookies(cookieHeader) {
42
3179
  }
43
3180
  return cookies;
44
3181
  }
3182
+ function parseCookieValue(cookieHeader, name) {
3183
+ return parseCookies(cookieHeader).get(name);
3184
+ }
45
3185
  function authMiddleware(options) {
46
3186
  const { protectedRoutes = [], publicOnlyRoutes = [] } = options;
47
3187
  return async function middleware(request) {
@@ -52,7 +3192,7 @@ function authMiddleware(options) {
52
3192
  if (!isProtected && !isPublicOnly) return void 0;
53
3193
  const cookieHeader = request.headers.get("cookie") ?? "";
54
3194
  const cookies = parseCookies(cookieHeader);
55
- const hasSession = cookies.has("better-auth.session_token");
3195
+ const hasSession = cookies.has("better-auth.session_token") || cookies.has("__Secure-better-auth.session_token");
56
3196
  if (isProtected && !hasSession) {
57
3197
  return Response.redirect(new URL("/sign-in", request.url).toString(), 302);
58
3198
  }
@@ -61,498 +3201,950 @@ function authMiddleware(options) {
61
3201
  }
62
3202
  return void 0;
63
3203
  };
64
- }
65
- var BrokrAuthClient;
66
- var init_auth = __esm({
67
- "src/auth.ts"() {
68
- "use strict";
69
- init_runtime();
70
- BrokrAuthClient = class {
71
- constructor(token, gatewayUrl, appUrl) {
72
- this._token = token;
73
- this._gatewayUrl = gatewayUrl;
74
- this._appUrl = appUrl ?? (typeof process !== "undefined" ? process.env.BETTER_AUTH_URL : void 0);
75
- }
76
- /**
77
- * Get current user from an incoming request's cookies.
78
- * Calls the local Better Auth API (runs inside your app).
79
- */
80
- async currentUser(request) {
81
- const session = await this.getSession(request);
82
- return session?.user ?? null;
83
- }
84
- /**
85
- * Get the full session (user + metadata) from an incoming request.
86
- * Calls the local Better Auth API.
87
- */
88
- async getSession(request) {
89
- const appUrl = this._appUrl;
90
- if (!appUrl) {
91
- throw new BrokrError(
92
- "[brokr] BETTER_AUTH_URL is not set. Auth may not be provisioned.",
93
- "AUTH_NOT_CONFIGURED",
94
- "auth"
95
- );
96
- }
97
- const cookieHeader = request.headers.get("cookie") ?? "";
98
- if (!cookieHeader) return null;
99
- const res = await fetch(`${appUrl}/api/auth/get-session`, {
100
- method: "GET",
101
- headers: { cookie: cookieHeader }
102
- });
103
- if (!res.ok) return null;
104
- const data = await res.json();
105
- if (!data?.user || !data?.session) return null;
106
- return {
107
- user: {
108
- id: data.user.id,
109
- email: data.user.email,
110
- name: data.user.name ?? null,
111
- avatarUrl: data.user.image ?? null,
112
- emailVerified: data.user.emailVerified ? /* @__PURE__ */ new Date() : null
113
- },
114
- sessionId: data.session.id,
115
- expiresAt: new Date(data.session.expiresAt)
116
- };
117
- }
118
- /**
119
- * Generate an OAuth authorization URL.
120
- */
121
- async getOAuthUrl(provider, options) {
122
- const appUrl = this._appUrl;
123
- if (!appUrl) {
124
- throw new BrokrError("[brokr] BETTER_AUTH_URL is not set.", "AUTH_NOT_CONFIGURED", "auth");
125
- }
126
- const redirectTo = options?.redirectTo ?? "/";
127
- if (!redirectTo.startsWith("/") || redirectTo.startsWith("//")) {
128
- throw new BrokrError("[brokr] redirectTo must be a relative path (start with /)", "INVALID_REDIRECT", "auth");
129
- }
130
- const params = new URLSearchParams({ callbackURL: redirectTo });
131
- return { redirectUrl: `${appUrl}/api/auth/sign-in/social?provider=${provider}&${params}` };
132
- }
133
- /**
134
- * Send a magic link email (requires email capability).
135
- */
136
- async sendMagicLink(email, options) {
137
- const appUrl = this._appUrl;
138
- if (!appUrl) {
139
- throw new BrokrError("[brokr] BETTER_AUTH_URL is not set.", "AUTH_NOT_CONFIGURED", "auth");
140
- }
141
- const res = await fetch(`${appUrl}/api/auth/magic-link/send`, {
142
- method: "POST",
143
- headers: { "Content-Type": "application/json" },
144
- body: JSON.stringify({ email, callbackURL: options?.redirectTo ?? "/" })
145
- });
146
- if (!res.ok) {
147
- const data = await res.json().catch(() => ({}));
148
- throw new BrokrError(
149
- data.message ?? `[brokr] Failed to send magic link (HTTP ${res.status})`,
150
- "AUTH_MAGIC_LINK_FAILED",
151
- "auth"
152
- );
153
- }
154
- }
155
- };
156
- }
157
- });
3204
+ }
158
3205
 
159
- // src/runtime.ts
160
- function resolveToken() {
161
- return typeof process !== "undefined" ? process.env.BROKR_TOKEN : void 0;
3206
+ // src/models.ts
3207
+ var models = {
3208
+ /** Cheapest and fastest model (Deepseek Chat). */
3209
+ FAST: "deepseek-chat",
3210
+ /** Most capable model. */
3211
+ SMART: "claude-sonnet-4-6",
3212
+ /** Default balanced model (Deepseek Chat). */
3213
+ BALANCED: "deepseek-chat"
3214
+ };
3215
+ var providers = [
3216
+ { id: "deepseek", label: "Deepseek", model: "deepseek-chat", color: "#0EA5E9", free: true, logo: "https://assets.brokr.sh/sdk/deepseek_logo.png" },
3217
+ { id: "openai", label: "ChatGPT", model: "gpt-5.4-mini", color: "#10B981", free: false, logo: "https://assets.brokr.sh/sdk/gpt_logo.png" },
3218
+ { id: "anthropic", label: "Claude", model: "claude-sonnet-4-6", color: "#F59E0B", free: false, logo: "https://assets.brokr.sh/sdk/claude_logo.png" },
3219
+ { id: "kimi", label: "Kimi", model: "fireworks/kimi-k2p5", color: "#8B5CF6", free: false, logo: "https://assets.brokr.sh/sdk/kimi_logo.png" },
3220
+ { id: "minimax", label: "Minimax", model: "MiniMaxAI/MiniMax-M2.5", color: "#EC4899", free: false, logo: "https://assets.brokr.sh/sdk/minimax_logo.png" }
3221
+ ];
3222
+ function resolveProviderByModel(model) {
3223
+ return providers.find((p) => p.model === model) ?? providers.find((p) => model.toLowerCase().includes(p.id));
162
3224
  }
163
- function assertToken(token, capability) {
164
- if (!token) {
165
- let hint = "brokr env pull --stack <name>";
166
- try {
167
- if (typeof process !== "undefined") {
168
- const fs = __require("fs");
169
- const path = __require("path");
170
- const brokrFile = path.join(process.cwd(), ".brokr");
171
- if (fs.existsSync(brokrFile)) {
172
- const data = JSON.parse(fs.readFileSync(brokrFile, "utf8"));
173
- if (data?.stackName) hint = `brokr env pull --stack ${data.stackName}`;
174
- }
175
- }
176
- } catch {
3225
+
3226
+ // src/runtime.ts
3227
+ var BrokrRuntime = class {
3228
+ constructor(options) {
3229
+ this._token = options?.token ?? resolveToken();
3230
+ this._gatewayUrl = options?.gatewayUrl ?? GATEWAY_URL;
3231
+ this.ai = new BrokrAIClient(this._token, this._gatewayUrl);
3232
+ this.storage = new BrokrStorageClient(this._token, this._gatewayUrl);
3233
+ this.email = new BrokrEmailClient(this._token, this._gatewayUrl);
3234
+ }
3235
+ // -------------------------------------------------------------------------
3236
+ // Lazy namespace getters
3237
+ // -------------------------------------------------------------------------
3238
+ /** Files client (upload + AI processing). */
3239
+ get files() {
3240
+ if (!this._files) {
3241
+ this._files = new BrokrFilesClient(this._token, this._gatewayUrl, this.storage);
177
3242
  }
178
- throw new BrokrAuthError(
179
- `[brokr] BROKR_TOKEN is not set.
180
- Run: ${hint}`,
181
- "BROKR_TOKEN_MISSING"
182
- );
3243
+ return this._files;
183
3244
  }
184
- }
185
- async function gatewayFetch(gatewayUrl, token, path, body, capability) {
186
- let res;
187
- try {
188
- res = await fetch(`${gatewayUrl}${path}`, {
189
- method: "POST",
190
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
191
- body: JSON.stringify(body)
192
- });
193
- } catch (err) {
194
- throw new BrokrNetworkError(
195
- `[brokr] Could not reach Brokr gateway. Check your network.
196
- ${err instanceof Error ? err.message : String(err)}`,
197
- capability
198
- );
3245
+ /** Payments client (checkout, portal, plan queries). */
3246
+ get payments() {
3247
+ if (!this._payments) {
3248
+ this._payments = new BrokrPaymentsClient(this._token, this._gatewayUrl);
3249
+ }
3250
+ return this._payments;
199
3251
  }
200
- if (res.status === 429) {
201
- const retryAfter = parseInt(res.headers.get("Retry-After") ?? "60", 10);
202
- const data = await res.json().catch(() => ({}));
203
- throw new BrokrRateLimitError(
204
- data.error ?? `[brokr] Rate limited (retry after ${retryAfter}s)`,
205
- retryAfter,
206
- capability
207
- );
3252
+ /** Notifications client (send + list notifications). */
3253
+ get notifications() {
3254
+ if (!this._notifications) {
3255
+ this._notifications = new BrokrNotificationsClient(this._token, this._gatewayUrl);
3256
+ }
3257
+ return this._notifications;
208
3258
  }
209
- if (res.status === 401) {
210
- throw new BrokrAuthError("[brokr] Invalid or expired BROKR_TOKEN.", "BROKR_TOKEN_INVALID");
3259
+ /** Entitlements client (feature checks, usage queries). */
3260
+ get entitlements() {
3261
+ if (!this._entitlements) {
3262
+ this._entitlements = new BrokrEntitlementsClient(this._token, this._gatewayUrl);
3263
+ }
3264
+ return this._entitlements;
211
3265
  }
212
- if (!res.ok) {
213
- const data = await res.json().catch(() => ({}));
214
- throw new BrokrError(
215
- data.error ?? `[brokr] ${capability} request failed (HTTP ${res.status})`,
216
- data.code ?? `${capability.toUpperCase()}_FAILED`,
217
- capability
218
- );
3266
+ /** Auth client — lazily initialized. */
3267
+ get auth() {
3268
+ if (!this._auth) {
3269
+ this._auth = new BrokrAuthClient(this._token, this._gatewayUrl);
3270
+ }
3271
+ return this._auth;
219
3272
  }
220
- return res.json();
221
- }
3273
+ // -------------------------------------------------------------------------
3274
+ // Root aliases — one-liner DX for the most common operations
3275
+ // -------------------------------------------------------------------------
3276
+ /** Send a chat message. Alias for `brokr.ai.chat()`. */
3277
+ chat(input, options) {
3278
+ return this.ai.chat(input, options);
3279
+ }
3280
+ /** Upload a file. Alias for `brokr.storage.upload()`. */
3281
+ upload(params) {
3282
+ return this.storage.upload(params);
3283
+ }
3284
+ /** Start a checkout flow. Alias for `brokr.payments.checkout()`. */
3285
+ checkout(params) {
3286
+ return this.payments.checkout(params);
3287
+ }
3288
+ /** Start a checkout flow. Alias for `brokr.checkout()` — north star one-liner. */
3289
+ purchase(params) {
3290
+ return this.payments.checkout(params);
3291
+ }
3292
+ };
222
3293
  function createBrokr(options) {
3294
+ BrokrDevConsole.install();
3295
+ initCapture({
3296
+ token: options?.token,
3297
+ gatewayUrl: options?.gatewayUrl
3298
+ });
223
3299
  return new BrokrRuntime(options);
224
3300
  }
225
- var GATEWAY_URL, BrokrError, BrokrAuthError, BrokrRateLimitError, BrokrNetworkError, BrokrAIClient, BrokrStorageClient, BrokrEmailClient, BrokrRuntime;
226
- var init_runtime = __esm({
227
- "src/runtime.ts"() {
228
- "use strict";
229
- GATEWAY_URL = "https://api.brokr.sh";
230
- BrokrError = class extends Error {
231
- constructor(message, code, capability, retryable = false) {
232
- super(message);
233
- this.code = code;
234
- this.capability = capability;
235
- this.retryable = retryable;
236
- this.name = "BrokrError";
237
- }
238
- };
239
- BrokrAuthError = class extends BrokrError {
240
- constructor(message, code) {
241
- super(message, code, "auth", false);
242
- this.name = "BrokrAuthError";
243
- }
244
- };
245
- BrokrRateLimitError = class extends BrokrError {
246
- constructor(message, retryAfter, capability) {
247
- super(message, "RATE_LIMITED", capability, true);
248
- this.retryAfter = retryAfter;
249
- this.name = "BrokrRateLimitError";
250
- }
251
- };
252
- BrokrNetworkError = class extends BrokrError {
253
- constructor(message, capability) {
254
- super(message, "NETWORK_ERROR", capability, true);
255
- this.name = "BrokrNetworkError";
256
- }
257
- };
258
- BrokrAIClient = class {
259
- constructor(_token, _gatewayUrl) {
260
- this._token = _token;
261
- this._gatewayUrl = _gatewayUrl;
262
- }
263
- /**
264
- * Send a chat completion request.
265
- *
266
- * @example
267
- * ```typescript
268
- * const reply = await brokr.ai.chat([
269
- * { role: 'user', content: 'Explain quantum computing in one sentence.' }
270
- * ]);
271
- * console.log(reply.content);
272
- * ```
273
- */
274
- async chat(messages, options) {
275
- assertToken(this._token, "ai");
276
- const data = await gatewayFetch(this._gatewayUrl, this._token, "/v1/chat/completions", {
277
- messages,
278
- model: options?.model,
279
- max_tokens: options?.maxTokens,
280
- temperature: options?.temperature
281
- }, "ai");
282
- return {
283
- content: data.choices?.[0]?.message?.content ?? "",
284
- model: data.model ?? "",
285
- usage: {
286
- promptTokens: data.usage?.prompt_tokens ?? 0,
287
- completionTokens: data.usage?.completion_tokens ?? 0
288
- }
289
- };
290
- }
291
- /**
292
- * Stream a chat completion. Yields text strings directly.
293
- *
294
- * @example
295
- * ```typescript
296
- * for await (const text of brokr.ai.stream(messages)) {
297
- * process.stdout.write(text);
298
- * }
299
- * ```
300
- */
301
- async *stream(messages, options) {
302
- assertToken(this._token, "ai");
303
- let res;
304
- try {
305
- res = await fetch(`${this._gatewayUrl}/v1/chat/completions`, {
306
- method: "POST",
307
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${this._token}` },
308
- body: JSON.stringify({ messages, stream: true, model: options?.model, max_tokens: options?.maxTokens })
309
- });
310
- } catch (err) {
311
- throw new BrokrNetworkError(
312
- `[brokr] Could not reach Brokr gateway.
313
- ${err instanceof Error ? err.message : String(err)}`,
314
- "ai"
315
- );
316
- }
317
- if (res.status === 429) {
318
- const retryAfter = parseInt(res.headers.get("Retry-After") ?? "60", 10);
319
- throw new BrokrRateLimitError("[brokr] AI rate limited.", retryAfter, "ai");
320
- }
321
- if (res.status === 401) {
322
- throw new BrokrAuthError("[brokr] Invalid or expired BROKR_TOKEN.", "BROKR_TOKEN_INVALID");
323
- }
324
- if (!res.ok || !res.body) {
325
- throw new BrokrError(`[brokr] AI stream failed (HTTP ${res.status})`, "AI_STREAM_FAILED", "ai");
326
- }
327
- const reader = res.body.getReader();
328
- const decoder = new TextDecoder();
329
- let buffer = "";
330
- while (true) {
331
- const { done, value } = await reader.read();
332
- if (done) break;
333
- buffer += decoder.decode(value, { stream: true });
334
- const lines = buffer.split("\n");
335
- buffer = lines.pop() ?? "";
336
- for (const line of lines) {
337
- if (!line.startsWith("data: ")) continue;
338
- const payload = line.slice(6).trim();
339
- if (payload === "[DONE]") return;
340
- try {
341
- const parsed = JSON.parse(payload);
342
- const delta = parsed.choices?.[0]?.delta?.content ?? "";
343
- if (delta) yield delta;
344
- } catch {
345
- }
346
- }
347
- }
348
- }
349
- /**
350
- * OpenAI-SDK compatible base URL.
351
- *
352
- * @example
353
- * ```typescript
354
- * const openai = new OpenAI({ baseURL: brokr.ai.baseURL, apiKey: brokr.ai.apiKey });
355
- * ```
356
- */
357
- get baseURL() {
358
- return `${this._gatewayUrl}/v1`;
359
- }
360
- /** Use as `apiKey` with the official OpenAI SDK to route through Brokr's gateway. */
361
- get apiKey() {
362
- assertToken(this._token, "ai");
363
- return this._token;
364
- }
365
- };
366
- BrokrStorageClient = class {
367
- constructor(_token, _gatewayUrl) {
368
- this._token = _token;
369
- this._gatewayUrl = _gatewayUrl;
370
- }
371
- /**
372
- * Get a presigned upload URL for browser-direct or streaming uploads.
373
- *
374
- * @example
375
- * ```typescript
376
- * const { url, key } = await brokr.storage.getUploadUrl('avatar.png', 'image/png');
377
- * await fetch(url, { method: 'PUT', body: file });
378
- * ```
379
- */
380
- async getUploadUrl(filename, contentType = "application/octet-stream") {
381
- assertToken(this._token, "storage");
382
- return gatewayFetch(
383
- this._gatewayUrl,
384
- this._token,
385
- "/v1/storage/sign-upload",
386
- { filename, contentType },
387
- "storage"
388
- );
389
- }
390
- /**
391
- * Upload data to R2. Returns the stable object key.
392
- *
393
- * @example
394
- * ```typescript
395
- * const { key } = await brokr.storage.upload(fileBuffer, 'photo.jpg', 'image/jpeg');
396
- * ```
397
- */
398
- async upload(data, filename, contentType = "application/octet-stream") {
399
- const { url, key } = await this.getUploadUrl(filename, contentType);
400
- const putRes = await fetch(url, {
401
- method: "PUT",
402
- headers: { "Content-Type": contentType },
403
- body: data
404
- });
405
- if (!putRes.ok) {
406
- throw new BrokrError(`[brokr] Upload failed (HTTP ${putRes.status})`, "STORAGE_UPLOAD_FAILED", "storage");
407
- }
408
- return { key };
409
- }
410
- /**
411
- * Get a presigned download URL for a stored object.
412
- *
413
- * @example
414
- * ```typescript
415
- * const { url } = await brokr.storage.url('photos/avatar.jpg');
416
- * // use url in <img src={url} /> or redirect
417
- * ```
418
- */
419
- async url(key, options) {
420
- assertToken(this._token, "storage");
421
- return gatewayFetch(
422
- this._gatewayUrl,
423
- this._token,
424
- "/v1/storage/sign-download",
425
- { key, expiresIn: options?.expiresIn },
426
- "storage"
427
- );
428
- }
429
- /** @deprecated Use `url()` instead. */
430
- async getUrl(key, options) {
431
- return this.url(key, options);
432
- }
433
- };
434
- BrokrEmailClient = class {
435
- constructor(_token, _gatewayUrl) {
436
- this._token = _token;
437
- this._gatewayUrl = _gatewayUrl;
438
- }
439
- /**
440
- * Send an email. The from address and API credentials are resolved server-side.
441
- *
442
- * @example
443
- * ```typescript
444
- * await brokr.email.send({
445
- * to: 'user@example.com',
446
- * subject: 'Welcome!',
447
- * html: '<h1>Welcome to the app</h1>',
448
- * });
449
- * ```
450
- */
451
- async send(params) {
452
- assertToken(this._token, "email");
453
- return gatewayFetch(
454
- this._gatewayUrl,
455
- this._token,
456
- "/v1/email/send",
457
- params,
458
- "email"
459
- );
460
- }
461
- };
462
- BrokrRuntime = class {
463
- constructor(options) {
464
- this._token = options?.token ?? resolveToken();
465
- this._gatewayUrl = options?.gatewayUrl ?? GATEWAY_URL;
466
- this.ai = new BrokrAIClient(this._token, this._gatewayUrl);
467
- this.storage = new BrokrStorageClient(this._token, this._gatewayUrl);
468
- this.email = new BrokrEmailClient(this._token, this._gatewayUrl);
469
- }
470
- /** Auth client — lazily initialized to avoid pulling in auth deps when not needed. */
471
- get auth() {
472
- if (!this._auth) {
473
- const { BrokrAuthClient: BrokrAuthClient2 } = (init_auth(), __toCommonJS(auth_exports));
474
- this._auth = new BrokrAuthClient2(this._token, this._gatewayUrl);
475
- }
476
- return this._auth;
477
- }
478
- };
479
- }
480
- });
481
3301
 
482
- // index.ts
483
- init_runtime();
484
- init_auth();
3302
+ // src/ai/conversation-title.ts
3303
+ function titleCaseWord(word) {
3304
+ if (!word) return word;
3305
+ if (/[A-Z]{2,}/.test(word) || /\d/.test(word)) return word;
3306
+ return `${word.charAt(0).toUpperCase()}${word.slice(1).toLowerCase()}`;
3307
+ }
3308
+ function buildFallbackConversationTitle(message) {
3309
+ const words = message.replace(/\s+/g, " ").trim().split(" ").filter(Boolean).slice(0, 5).map((word) => word.replace(/^[^\w]+|[^\w]+$/g, "")).filter(Boolean).map(titleCaseWord);
3310
+ return words.length > 0 ? words.join(" ") : "New Chat";
3311
+ }
3312
+ function sanitizeConversationTitle(input, fallback = "New Chat") {
3313
+ const cleaned = input.replace(/^['"`]+|['"`]+$/g, "").replace(/[.!?]+$/g, "").replace(/[:/\\]+/g, " ").replace(/\s+/g, " ").trim();
3314
+ if (!cleaned) return fallback;
3315
+ const words = cleaned.split(" ").filter(Boolean).slice(0, 5).map(titleCaseWord);
3316
+ if (words.length === 0) return fallback;
3317
+ const title = words.join(" ").slice(0, 80).trim();
3318
+ return title || fallback;
3319
+ }
3320
+ async function generateConversationTitle(ai, firstUserMessage, options = {}) {
3321
+ const fallback = sanitizeConversationTitle(
3322
+ options.fallback ?? buildFallbackConversationTitle(firstUserMessage),
3323
+ "New Chat"
3324
+ );
3325
+ const prompt = [
3326
+ "Generate a short conversation title for an AI chat thread.",
3327
+ "The title must describe the user intent from the first user message, not the assistant response.",
3328
+ 'Return JSON with one field: "title".',
3329
+ "Rules:",
3330
+ "- 2 to 5 words.",
3331
+ "- Plain Title Case.",
3332
+ "- Specific and concrete.",
3333
+ "- No quotes, emojis, colons, slashes, or trailing punctuation.",
3334
+ "- Do not use filler like New Chat, Help, Question, Support, General, or Conversation unless there is truly no better option.",
3335
+ "- Preserve product names, framework names, and acronyms when they matter.",
3336
+ "",
3337
+ "First user message:",
3338
+ firstUserMessage.trim()
3339
+ ].join("\n");
3340
+ try {
3341
+ const result = await ai.structured({
3342
+ prompt,
3343
+ schema: {
3344
+ type: "object",
3345
+ additionalProperties: false,
3346
+ properties: {
3347
+ title: { type: "string" }
3348
+ },
3349
+ required: ["title"]
3350
+ },
3351
+ model: options.model,
3352
+ temperature: 0.15
3353
+ });
3354
+ return sanitizeConversationTitle(result.title ?? "", fallback);
3355
+ } catch {
3356
+ return fallback;
3357
+ }
3358
+ }
485
3359
 
486
3360
  // src/management.ts
487
- async function trpcRequest(config, procedure, input) {
488
- const url = new URL(`${config.apiUrl}/api/trpc/${procedure}`);
3361
+ async function orpcRequest(config2, procedure, input) {
3362
+ const path = procedure.replace(/^v1\./, "").replace(/\./g, "/");
3363
+ const url = new URL(`${config2.apiUrl}/api/orpc/${path}`);
489
3364
  const response = await fetch(url.toString(), {
490
3365
  method: "POST",
491
3366
  headers: {
492
3367
  "Content-Type": "application/json",
493
- "Authorization": `Bearer ${config.accessToken}`,
494
- ...config.headers
3368
+ "Authorization": `Bearer ${config2.accessToken}`,
3369
+ ...config2.headers
495
3370
  },
496
- body: JSON.stringify(input),
497
- signal: config.timeout ? AbortSignal.timeout(config.timeout) : void 0
3371
+ body: JSON.stringify({ json: input }),
3372
+ signal: config2.timeout ? AbortSignal.timeout(config2.timeout) : void 0
498
3373
  });
499
3374
  if (!response.ok) {
500
3375
  const error = await response.json().catch(() => ({ message: "Request failed" }));
501
- throw new Error(error.message || `HTTP ${response.status}`);
3376
+ throw new Error(error?.json?.message || error?.message || `HTTP ${response.status}`);
502
3377
  }
503
- const result = await response.json();
504
- return result.data;
3378
+ const envelope = await response.json();
3379
+ return envelope.json;
505
3380
  }
506
3381
  var BrokrClient = class {
507
- constructor(config) {
508
- this.config = config;
3382
+ constructor(config2) {
3383
+ this.config = config2;
509
3384
  }
510
3385
  /** Create a new stack with default providers. */
511
3386
  async create(input) {
512
- return trpcRequest(this.config, "v1.stack.create", input);
3387
+ return orpcRequest(this.config, "v1.stack.create", input);
513
3388
  }
514
3389
  /** List all stacks for the current user. */
515
3390
  async listStacks() {
516
- return trpcRequest(this.config, "v1.stack.list", {});
3391
+ return orpcRequest(this.config, "v1.stack.list", {});
517
3392
  }
518
3393
  /** Get a specific stack by ID. */
519
3394
  async getStack(id) {
520
- return trpcRequest(this.config, "v1.stack.get", { id });
3395
+ return orpcRequest(this.config, "v1.stack.get", { id });
521
3396
  }
522
3397
  /** Update a stack. */
523
3398
  async updateStack(id, input) {
524
- return trpcRequest(this.config, "v1.stack.update", { id, ...input });
3399
+ return orpcRequest(this.config, "v1.stack.update", { id, ...input });
525
3400
  }
526
3401
  /** Delete a stack. */
527
3402
  async deleteStack(id) {
528
- return trpcRequest(this.config, "v1.stack.delete", { id });
3403
+ return orpcRequest(this.config, "v1.stack.delete", { id });
529
3404
  }
530
3405
  /** Add a provider to a stack. */
531
3406
  async add(provider, input) {
532
- return trpcRequest(this.config, "v1.provider.add", { provider, ...input });
3407
+ return orpcRequest(this.config, "v1.provider.add", { provider, ...input });
533
3408
  }
534
3409
  /** Refresh the access token. */
535
3410
  async refreshToken(refreshToken) {
536
- return trpcRequest(this.config, "v1.auth.refresh", { refreshToken });
3411
+ return orpcRequest(this.config, "v1.auth.refresh", { refreshToken });
537
3412
  }
538
3413
  /** Update the access token. */
539
3414
  setAccessToken(accessToken) {
540
3415
  this.config.accessToken = accessToken;
541
3416
  }
542
3417
  };
543
- function createBrokrClient(config) {
544
- return new BrokrClient(config);
3418
+ function createBrokrClient(config2) {
3419
+ return new BrokrClient(config2);
545
3420
  }
546
3421
  var create = createBrokrClient;
3422
+
3423
+ // src/next/notifications.ts
3424
+ var DEFAULT_TABLE = "brokr_notifications";
3425
+ async function getNeonSql() {
3426
+ const url = process.env.DATABASE_URL;
3427
+ if (!url) {
3428
+ throw new Error(
3429
+ "[brokr] DATABASE_URL is not set. Notification persistence requires a Postgres database.\nRun: brokr add database"
3430
+ );
3431
+ }
3432
+ try {
3433
+ const { neon } = await import("@neondatabase/serverless");
3434
+ return neon(url);
3435
+ } catch {
3436
+ throw new Error(
3437
+ "[brokr] @neondatabase/serverless is not installed.\nRun: npm install @neondatabase/serverless"
3438
+ );
3439
+ }
3440
+ }
3441
+ var _sql = null;
3442
+ var _ensuredTables = /* @__PURE__ */ new Set();
3443
+ async function getDb() {
3444
+ if (!_sql) _sql = await getNeonSql();
3445
+ return _sql;
3446
+ }
3447
+ function validateTableName(name) {
3448
+ if (!/^[a-z_][a-z0-9_]{0,62}$/.test(name)) {
3449
+ throw new Error(`[brokr] Invalid table name: "${name}". Use lowercase letters, digits, and underscores only.`);
3450
+ }
3451
+ return name;
3452
+ }
3453
+ async function ensureNotificationTable(tableName = DEFAULT_TABLE) {
3454
+ const table = validateTableName(tableName);
3455
+ if (_ensuredTables.has(table)) return;
3456
+ const sql = await getDb();
3457
+ await sql`
3458
+ CREATE TABLE IF NOT EXISTS brokr_notifications (
3459
+ id TEXT PRIMARY KEY,
3460
+ user_id TEXT NOT NULL,
3461
+ type TEXT NOT NULL DEFAULT 'default',
3462
+ title TEXT NOT NULL,
3463
+ message TEXT NOT NULL,
3464
+ variant TEXT NOT NULL DEFAULT 'default',
3465
+ href TEXT,
3466
+ image_url TEXT,
3467
+ image_alt TEXT,
3468
+ read BOOLEAN NOT NULL DEFAULT false,
3469
+ read_at TIMESTAMPTZ,
3470
+ data JSONB,
3471
+ expires_at TIMESTAMPTZ,
3472
+ created_at TIMESTAMPTZ DEFAULT NOW()
3473
+ )
3474
+ `;
3475
+ await sql`ALTER TABLE brokr_notifications ADD COLUMN IF NOT EXISTS type TEXT NOT NULL DEFAULT 'default'`.catch(() => {
3476
+ });
3477
+ await sql`ALTER TABLE brokr_notifications ADD COLUMN IF NOT EXISTS href TEXT`.catch(() => {
3478
+ });
3479
+ await sql`ALTER TABLE brokr_notifications ADD COLUMN IF NOT EXISTS image_url TEXT`.catch(() => {
3480
+ });
3481
+ await sql`ALTER TABLE brokr_notifications ADD COLUMN IF NOT EXISTS image_alt TEXT`.catch(() => {
3482
+ });
3483
+ await sql`ALTER TABLE brokr_notifications ADD COLUMN IF NOT EXISTS read_at TIMESTAMPTZ`.catch(() => {
3484
+ });
3485
+ await sql`ALTER TABLE brokr_notifications ADD COLUMN IF NOT EXISTS expires_at TIMESTAMPTZ`.catch(() => {
3486
+ });
3487
+ await sql`
3488
+ CREATE INDEX IF NOT EXISTS idx_brokr_notifications_user
3489
+ ON brokr_notifications(user_id, created_at DESC)
3490
+ `;
3491
+ await sql`
3492
+ CREATE INDEX IF NOT EXISTS idx_brokr_notifications_type
3493
+ ON brokr_notifications(user_id, type, created_at DESC)
3494
+ `;
3495
+ if (table !== DEFAULT_TABLE) {
3496
+ const exists = await sql`
3497
+ SELECT 1 FROM information_schema.tables
3498
+ WHERE table_schema = 'public' AND table_name = ${table}
3499
+ `;
3500
+ if (exists.length === 0) {
3501
+ throw new Error(
3502
+ `[brokr] Custom notification table "${table}" does not exist.
3503
+ Create it with the same schema as brokr_notifications, or remove the tableName config.`
3504
+ );
3505
+ }
3506
+ }
3507
+ _ensuredTables.add(table);
3508
+ }
3509
+ async function persistNotification(params, opts) {
3510
+ await ensureNotificationTable(opts?.tableName);
3511
+ const sql = await getDb();
3512
+ await sql`
3513
+ INSERT INTO brokr_notifications (id, user_id, type, title, message, variant, href, image_url, image_alt, data, expires_at, created_at)
3514
+ VALUES (
3515
+ ${params.id},
3516
+ ${params.userId},
3517
+ ${params.type ?? "default"},
3518
+ ${params.title},
3519
+ ${params.message},
3520
+ ${params.variant},
3521
+ ${params.href ?? null},
3522
+ ${params.imageUrl ?? null},
3523
+ ${params.imageAlt ?? null},
3524
+ ${params.data ? JSON.stringify(params.data) : null}::jsonb,
3525
+ ${params.expiresAt?.toISOString() ?? null},
3526
+ NOW()
3527
+ )
3528
+ ON CONFLICT (id) DO NOTHING
3529
+ `;
3530
+ }
3531
+ async function listPersistedNotifications(userId, params, opts) {
3532
+ await ensureNotificationTable(opts?.tableName);
3533
+ const sql = await getDb();
3534
+ const limit = Math.min(params?.limit ?? 50, 100);
3535
+ const typeFilter = params?.type ?? null;
3536
+ const skipUnreadFilter = !(params?.unreadOnly ?? false);
3537
+ const rows = await sql`
3538
+ SELECT id, user_id, type, title, message, variant, href, image_url, image_alt, read, read_at, data, expires_at, created_at
3539
+ FROM brokr_notifications
3540
+ WHERE user_id = ${userId}
3541
+ AND (expires_at IS NULL OR expires_at > NOW())
3542
+ AND (${typeFilter}::text IS NULL OR type = ${typeFilter})
3543
+ AND (${skipUnreadFilter}::boolean OR read = false)
3544
+ ORDER BY created_at DESC
3545
+ LIMIT ${limit}
3546
+ `;
3547
+ return rows.map((r) => ({
3548
+ id: r.id,
3549
+ userId: r.user_id,
3550
+ type: r.type ?? "default",
3551
+ title: r.title,
3552
+ message: r.message,
3553
+ variant: r.variant,
3554
+ href: r.href ?? null,
3555
+ imageUrl: r.image_url ?? null,
3556
+ imageAlt: r.image_alt ?? null,
3557
+ read: r.read,
3558
+ readAt: r.read_at ? r.read_at.toISOString() : null,
3559
+ data: r.data,
3560
+ expiresAt: r.expires_at ? r.expires_at.toISOString() : null,
3561
+ createdAt: r.created_at.toISOString()
3562
+ }));
3563
+ }
3564
+ async function markNotificationRead(notificationId, userId, opts) {
3565
+ await ensureNotificationTable(opts?.tableName);
3566
+ const sql = await getDb();
3567
+ await sql`
3568
+ UPDATE brokr_notifications SET read = true, read_at = NOW()
3569
+ WHERE id = ${notificationId} AND user_id = ${userId}
3570
+ `;
3571
+ }
3572
+
3573
+ // src/ai/types.ts
3574
+ function contentToText(content) {
3575
+ if (typeof content === "string") return content;
3576
+ return content.filter((p) => p.type === "text").map((p) => p.text).join("");
3577
+ }
3578
+
3579
+ // src/next/chat.ts
3580
+ initCapture();
3581
+ var CHARS_PER_TOKEN = 4;
3582
+ var DEFAULT_TOKEN_BUDGET = 2e4;
3583
+ function estimateTokens(text) {
3584
+ return Math.ceil(text.length / CHARS_PER_TOKEN);
3585
+ }
3586
+ function trimToTokenBudget(msgs, budget = DEFAULT_TOKEN_BUDGET) {
3587
+ if (msgs.length === 0) return msgs;
3588
+ const system = msgs.filter((m) => m.role === "system");
3589
+ const rest = msgs.filter((m) => m.role !== "system");
3590
+ if (rest.length === 0) return system;
3591
+ const systemCost = system.reduce((s, m) => s + estimateTokens(contentToText(m.content)), 0);
3592
+ const latest = rest[rest.length - 1];
3593
+ const latestCost = estimateTokens(contentToText(latest.content));
3594
+ const remaining = budget - systemCost - latestCost;
3595
+ if (remaining <= 0) return [...system, latest];
3596
+ const kept = [];
3597
+ let used = 0;
3598
+ for (let i = rest.length - 2; i >= 0; i--) {
3599
+ const cost = estimateTokens(contentToText(rest[i].content));
3600
+ if (used + cost > remaining) break;
3601
+ used += cost;
3602
+ kept.unshift(rest[i]);
3603
+ }
3604
+ return [...system, ...kept, latest];
3605
+ }
3606
+ async function getNeonSql2() {
3607
+ const url = process.env.DATABASE_URL;
3608
+ if (!url) {
3609
+ throw new Error(
3610
+ "[brokr] DATABASE_URL is not set. Thread persistence requires a Postgres database.\nSet DATABASE_URL in your environment variables."
3611
+ );
3612
+ }
3613
+ try {
3614
+ const { neon } = await import("@neondatabase/serverless");
3615
+ return neon(url);
3616
+ } catch {
3617
+ throw new Error(
3618
+ "[brokr] @neondatabase/serverless is not installed.\nRun: npm install @neondatabase/serverless"
3619
+ );
3620
+ }
3621
+ }
3622
+ var _sql2 = null;
3623
+ var _tablesEnsured = false;
3624
+ async function getDb2() {
3625
+ if (!_sql2) _sql2 = await getNeonSql2();
3626
+ return _sql2;
3627
+ }
3628
+ async function ensureTables(sql) {
3629
+ if (_tablesEnsured) return;
3630
+ await sql`CREATE SCHEMA IF NOT EXISTS brokr_ai`;
3631
+ const oldTablesExist = await sql`
3632
+ SELECT EXISTS (
3633
+ SELECT 1 FROM information_schema.tables
3634
+ WHERE table_schema = 'public' AND table_name = 'brokr_ai_threads'
3635
+ ) AS exists
3636
+ `;
3637
+ if (oldTablesExist[0]?.exists) {
3638
+ await sql`ALTER TABLE public.brokr_ai_threads SET SCHEMA brokr_ai`.catch(() => {
3639
+ });
3640
+ await sql`ALTER TABLE public.brokr_ai_messages SET SCHEMA brokr_ai`.catch(() => {
3641
+ });
3642
+ await sql`ALTER TABLE brokr_ai.brokr_ai_threads RENAME TO threads`.catch(() => {
3643
+ });
3644
+ await sql`ALTER TABLE brokr_ai.brokr_ai_messages RENAME TO messages`.catch(() => {
3645
+ });
3646
+ }
3647
+ await sql`
3648
+ CREATE TABLE IF NOT EXISTS brokr_ai.threads (
3649
+ id TEXT PRIMARY KEY,
3650
+ surface TEXT NOT NULL DEFAULT 'default',
3651
+ subject TEXT,
3652
+ title TEXT NOT NULL DEFAULT 'New chat',
3653
+ created_at TIMESTAMPTZ DEFAULT NOW(),
3654
+ updated_at TIMESTAMPTZ DEFAULT NOW()
3655
+ )
3656
+ `;
3657
+ await sql`
3658
+ CREATE TABLE IF NOT EXISTS brokr_ai.messages (
3659
+ id TEXT PRIMARY KEY,
3660
+ thread_id TEXT NOT NULL REFERENCES brokr_ai.threads(id) ON DELETE CASCADE,
3661
+ role TEXT NOT NULL CHECK (role IN ('user', 'assistant')),
3662
+ content TEXT NOT NULL,
3663
+ model TEXT,
3664
+ created_at TIMESTAMPTZ DEFAULT NOW()
3665
+ )
3666
+ `;
3667
+ await sql`
3668
+ ALTER TABLE brokr_ai.messages ADD COLUMN IF NOT EXISTS model TEXT
3669
+ `.catch(() => {
3670
+ });
3671
+ await sql`
3672
+ ALTER TABLE brokr_ai.messages ADD COLUMN IF NOT EXISTS status TEXT NOT NULL DEFAULT 'complete'
3673
+ `.catch(() => {
3674
+ });
3675
+ await sql`
3676
+ ALTER TABLE brokr_ai.messages ADD COLUMN IF NOT EXISTS provider TEXT
3677
+ `.catch(() => {
3678
+ });
3679
+ await sql`
3680
+ CREATE INDEX IF NOT EXISTS brokr_ai_threads_surface_subject
3681
+ ON brokr_ai.threads(surface, subject, updated_at DESC)
3682
+ `;
3683
+ await sql`
3684
+ CREATE INDEX IF NOT EXISTS brokr_ai_messages_thread_id
3685
+ ON brokr_ai.messages(thread_id, created_at ASC)
3686
+ `;
3687
+ _tablesEnsured = true;
3688
+ }
3689
+ function parsePath(url) {
3690
+ const segments = new URL(url).pathname.split("/").filter(Boolean);
3691
+ const last = segments[segments.length - 1];
3692
+ const secondLast = segments[segments.length - 2];
3693
+ if (last === "chat") return { action: "chat" };
3694
+ if (last === "threads") return { action: "threads" };
3695
+ if (last === "ws-token") return { action: "ws-token" };
3696
+ if (last === "notifications") return { action: "notifications" };
3697
+ if (last === "read" && secondLast === "notifications") return { action: "notifications-read" };
3698
+ if (last === "messages" && secondLast) return { action: "messages", id: secondLast };
3699
+ if (last === "rename" && secondLast) return { action: "rename", id: secondLast };
3700
+ if (secondLast === "threads" && last) return { action: "thread", id: last };
3701
+ return { action: "unknown" };
3702
+ }
3703
+ function makeThreadTitle(content) {
3704
+ const cleaned = content.trim().replace(/\s+/g, " ");
3705
+ return cleaned.length > 48 ? `${cleaned.slice(0, 48).trimEnd()}\u2026` : cleaned || "New chat";
3706
+ }
3707
+ async function handleListThreads(request, opts) {
3708
+ if (!opts.persist) {
3709
+ return Response.json({ threads: [] });
3710
+ }
3711
+ const url = new URL(request.url);
3712
+ const surface = url.searchParams.get("surface") ?? "default";
3713
+ const subject = url.searchParams.get("subject");
3714
+ const sql = await getDb2();
3715
+ await ensureTables(sql);
3716
+ const rows = subject ? await sql`
3717
+ SELECT t.id, t.surface, t.subject, t.title, t.created_at, t.updated_at,
3718
+ (SELECT COUNT(*) FROM brokr_ai.messages WHERE thread_id = t.id) AS message_count
3719
+ FROM brokr_ai.threads t
3720
+ WHERE t.surface = ${surface} AND t.subject = ${subject}
3721
+ ORDER BY t.updated_at DESC
3722
+ LIMIT 50
3723
+ ` : await sql`
3724
+ SELECT t.id, t.surface, t.subject, t.title, t.created_at, t.updated_at,
3725
+ (SELECT COUNT(*) FROM brokr_ai.messages WHERE thread_id = t.id) AS message_count
3726
+ FROM brokr_ai.threads t
3727
+ WHERE t.surface = ${surface}
3728
+ ORDER BY t.updated_at DESC
3729
+ LIMIT 50
3730
+ `;
3731
+ return Response.json({
3732
+ threads: rows.map((r) => ({
3733
+ id: r.id,
3734
+ surface: r.surface,
3735
+ subject: r.subject,
3736
+ title: r.title,
3737
+ createdAt: r.created_at,
3738
+ updatedAt: r.updated_at,
3739
+ messageCount: Number(r.message_count)
3740
+ }))
3741
+ });
3742
+ }
3743
+ async function handleGetMessages(request, threadId, opts) {
3744
+ if (!opts.persist) {
3745
+ return Response.json({ messages: [], hasMore: false });
3746
+ }
3747
+ const url = new URL(request.url);
3748
+ const limit = Math.min(Number(url.searchParams.get("limit")) || 30, 100);
3749
+ const offset = Math.max(Number(url.searchParams.get("offset")) || 0, 0);
3750
+ const sql = await getDb2();
3751
+ const countResult = await sql`
3752
+ SELECT COUNT(*) AS total FROM brokr_ai.messages WHERE thread_id = ${threadId}
3753
+ `;
3754
+ const total = Number(countResult[0]?.total ?? 0);
3755
+ const rows = await sql`
3756
+ SELECT id, role, content, model, status, provider FROM (
3757
+ SELECT id, role, content, model, status, provider, created_at
3758
+ FROM brokr_ai.messages
3759
+ WHERE thread_id = ${threadId}
3760
+ ORDER BY created_at DESC, id DESC
3761
+ LIMIT ${limit} OFFSET ${offset}
3762
+ ) sub ORDER BY created_at ASC, id ASC
3763
+ `;
3764
+ return Response.json({
3765
+ messages: rows.map((r) => ({
3766
+ id: r.id,
3767
+ role: r.role,
3768
+ content: r.content,
3769
+ model: r.model ?? void 0,
3770
+ status: r.status ?? "complete",
3771
+ provider: r.provider ?? void 0
3772
+ })),
3773
+ hasMore: offset + limit < total
3774
+ });
3775
+ }
3776
+ async function handleRenameThread(request, threadId, opts) {
3777
+ if (!opts.persist) {
3778
+ return Response.json({ success: false }, { status: 400 });
3779
+ }
3780
+ const body = await request.json();
3781
+ const title = (body.title ?? "").trim();
3782
+ if (!title) {
3783
+ return Response.json({ error: "Title is required" }, { status: 400 });
3784
+ }
3785
+ const safeTitle = title.length > 100 ? `${title.slice(0, 100).trimEnd()}\u2026` : title;
3786
+ const sql = await getDb2();
3787
+ await ensureTables(sql);
3788
+ await sql`UPDATE brokr_ai.threads SET title = ${safeTitle}, updated_at = NOW() WHERE id = ${threadId}`;
3789
+ return Response.json({ success: true, title: safeTitle });
3790
+ }
3791
+ async function handleDeleteThread(_request, threadId, opts) {
3792
+ if (!opts.persist) {
3793
+ return Response.json({ success: true });
3794
+ }
3795
+ const sql = await getDb2();
3796
+ await sql`DELETE FROM brokr_ai.threads WHERE id = ${threadId}`;
3797
+ return Response.json({ success: true });
3798
+ }
3799
+ async function backgroundTask(promise) {
3800
+ try {
3801
+ const mod = await Promise.resolve().then(() => __toESM(require_functions()));
3802
+ if (typeof mod.waitUntil === "function") {
3803
+ mod.waitUntil(promise);
3804
+ return;
3805
+ }
3806
+ } catch {
3807
+ }
3808
+ promise.catch((err) => console.error("[brokr] Background task failed:", err));
3809
+ }
3810
+ async function handleChat(request, opts) {
3811
+ const body = await request.json();
3812
+ const gatewayUrl = process.env.BROKR_GATEWAY_URL ?? GATEWAY_URL;
3813
+ const token = process.env.BROKR_TOKEN;
3814
+ if (!token) {
3815
+ return Response.json(
3816
+ { error: "BROKR_TOKEN is not configured. Run: brokr env pull --stack <name>" },
3817
+ { status: 500 }
3818
+ );
3819
+ }
3820
+ const ai = new BrokrAIClient(token, gatewayUrl);
3821
+ const model = body.model;
3822
+ const systemPrompt = opts.systemPrompt ?? body.systemPrompt;
3823
+ const resolvedProvider = model ? resolveProviderByModel(model) : void 0;
3824
+ let messages;
3825
+ let threadId;
3826
+ let isNewThread = false;
3827
+ let userMsgId;
3828
+ let assistantMsgId;
3829
+ let threadTitle;
3830
+ if (opts.persist && body.content !== void 0) {
3831
+ threadId = body.thread_id ?? void 0;
3832
+ const sql = await getDb2();
3833
+ await ensureTables(sql);
3834
+ let history = [];
3835
+ if (threadId) {
3836
+ const [historyRows, titleRows] = await Promise.all([
3837
+ sql`
3838
+ SELECT role, content FROM brokr_ai.messages
3839
+ WHERE thread_id = ${threadId} AND status = 'complete'
3840
+ ORDER BY created_at ASC
3841
+ `,
3842
+ sql`SELECT title FROM brokr_ai.threads WHERE id = ${threadId} LIMIT 1`
3843
+ ]);
3844
+ history = historyRows;
3845
+ threadTitle = titleRows[0]?.title || void 0;
3846
+ } else {
3847
+ threadId = crypto.randomUUID();
3848
+ isNewThread = true;
3849
+ }
3850
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3851
+ const assistantNow = new Date(Date.parse(now) + 1).toISOString();
3852
+ if (!threadTitle) {
3853
+ threadTitle = makeThreadTitle(body.content ?? "");
3854
+ }
3855
+ userMsgId = crypto.randomUUID();
3856
+ assistantMsgId = crypto.randomUUID();
3857
+ if (isNewThread) {
3858
+ await sql`
3859
+ INSERT INTO brokr_ai.threads (id, surface, subject, title, created_at, updated_at)
3860
+ VALUES (
3861
+ ${threadId},
3862
+ ${body.surface ?? "default"},
3863
+ ${body.subject ?? null},
3864
+ ${threadTitle},
3865
+ ${now},
3866
+ ${now}
3867
+ )
3868
+ `;
3869
+ } else {
3870
+ await sql`
3871
+ UPDATE brokr_ai.threads SET updated_at = ${now} WHERE id = ${threadId}
3872
+ `;
3873
+ }
3874
+ await sql`
3875
+ INSERT INTO brokr_ai.messages (id, thread_id, role, content, status, created_at)
3876
+ VALUES (${userMsgId}, ${threadId}, 'user', ${body.content ?? ""}, 'complete', ${now})
3877
+ `;
3878
+ await sql`
3879
+ INSERT INTO brokr_ai.messages (id, thread_id, role, content, model, provider, status, created_at)
3880
+ VALUES (${assistantMsgId}, ${threadId}, 'assistant', '', ${model ?? null}, ${resolvedProvider?.id ?? null}, 'pending', ${assistantNow})
3881
+ `;
3882
+ messages = trimToTokenBudget([
3883
+ ...systemPrompt ? [{ role: "system", content: systemPrompt }] : [],
3884
+ ...history.map((h) => ({ role: h.role, content: h.content })),
3885
+ { role: "user", content: body.content }
3886
+ ]);
3887
+ } else {
3888
+ const clientMessages = body.messages ?? [];
3889
+ messages = systemPrompt ? [{ role: "system", content: systemPrompt }, ...clientMessages] : clientMessages;
3890
+ }
3891
+ const chunks = [];
3892
+ let chunkIndex = 0;
3893
+ let generationDone = false;
3894
+ let generationError = null;
3895
+ let fullResponse = "";
3896
+ let metadataSent = false;
3897
+ let resolveChunk = null;
3898
+ function notifyChunk() {
3899
+ if (resolveChunk) {
3900
+ const fn = resolveChunk;
3901
+ resolveChunk = null;
3902
+ fn();
3903
+ }
3904
+ }
3905
+ function waitForChunk() {
3906
+ if (generationDone || generationError || chunkIndex < chunks.length) {
3907
+ return Promise.resolve();
3908
+ }
3909
+ return new Promise((resolve) => {
3910
+ resolveChunk = resolve;
3911
+ });
3912
+ }
3913
+ const generationTask = (async () => {
3914
+ try {
3915
+ const aiStream = ai.stream(messages, { model });
3916
+ for await (const delta of aiStream) {
3917
+ fullResponse += delta;
3918
+ chunks.push(delta);
3919
+ notifyChunk();
3920
+ }
3921
+ if (opts.persist && threadId && assistantMsgId) {
3922
+ const sql = await getDb2();
3923
+ await sql`
3924
+ UPDATE brokr_ai.messages
3925
+ SET content = ${fullResponse}, status = 'complete'
3926
+ WHERE id = ${assistantMsgId}
3927
+ `;
3928
+ }
3929
+ if (opts.persist && body.userId && threadId && assistantMsgId) {
3930
+ const notifId = crypto.randomUUID();
3931
+ const preview = fullResponse.length > 120 ? `${fullResponse.slice(0, 120)}...` : fullResponse;
3932
+ const notifData = {
3933
+ type: "ai_response",
3934
+ threadId,
3935
+ assistantMessageId: assistantMsgId,
3936
+ model: model ?? null,
3937
+ provider: resolvedProvider?.id ?? null,
3938
+ providerLogo: resolvedProvider?.logo ?? null,
3939
+ surface: body.surface ?? "default",
3940
+ href: `/chat?thread=${threadId}`
3941
+ };
3942
+ await Promise.allSettled([
3943
+ persistNotification({
3944
+ id: notifId,
3945
+ userId: body.userId,
3946
+ type: "ai_response",
3947
+ title: threadTitle ?? "AI Response",
3948
+ message: preview,
3949
+ variant: "default",
3950
+ href: `/chat?thread=${threadId}`,
3951
+ imageUrl: resolvedProvider?.logo ?? void 0,
3952
+ imageAlt: resolvedProvider?.label ?? void 0,
3953
+ data: notifData
3954
+ }, { tableName: opts.notifications?.tableName }).catch((err) => {
3955
+ console.error("[brokr] Notification DB persist failed:", err);
3956
+ }),
3957
+ new BrokrNotificationsClient(token, gatewayUrl).send({
3958
+ userId: body.userId,
3959
+ title: threadTitle ?? "AI Response",
3960
+ message: preview,
3961
+ variant: "default",
3962
+ data: notifData,
3963
+ dedup: `ai_response:${assistantMsgId}`
3964
+ }).catch((err) => {
3965
+ console.error("[brokr] Notification push failed:", err);
3966
+ })
3967
+ ]);
3968
+ }
3969
+ } catch (err) {
3970
+ console.error("[brokr] AI generation error:", err);
3971
+ generationError = "Something went wrong generating a reply.";
3972
+ if (opts.persist && threadId && assistantMsgId) {
3973
+ try {
3974
+ const sql = await getDb2();
3975
+ await sql`
3976
+ UPDATE brokr_ai.messages
3977
+ SET status = 'error', content = ''
3978
+ WHERE id = ${assistantMsgId}
3979
+ `;
3980
+ } catch (dbErr) {
3981
+ console.error("[brokr] Failed to mark message as error:", dbErr);
3982
+ }
3983
+ }
3984
+ } finally {
3985
+ generationDone = true;
3986
+ notifyChunk();
3987
+ }
3988
+ })();
3989
+ void backgroundTask(generationTask);
3990
+ const encoder = new TextEncoder();
3991
+ const stream = new ReadableStream({
3992
+ async pull(controller) {
3993
+ const enqueue = (event) => {
3994
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}
3995
+
3996
+ `));
3997
+ };
3998
+ await waitForChunk();
3999
+ if (!metadataSent && opts.persist && threadId) {
4000
+ metadataSent = true;
4001
+ enqueue({
4002
+ type: "conversation",
4003
+ id: threadId,
4004
+ assistantMessageId: assistantMsgId,
4005
+ isNewThread
4006
+ });
4007
+ }
4008
+ while (chunkIndex < chunks.length) {
4009
+ enqueue({ type: "delta", delta: chunks[chunkIndex] });
4010
+ chunkIndex++;
4011
+ }
4012
+ if (generationDone || generationError) {
4013
+ if (generationError) {
4014
+ enqueue({ type: "error", message: generationError });
4015
+ } else {
4016
+ enqueue({ type: "done" });
4017
+ }
4018
+ controller.close();
4019
+ }
4020
+ }
4021
+ });
4022
+ return new Response(stream, {
4023
+ headers: {
4024
+ "Content-Type": "text/event-stream",
4025
+ "Cache-Control": "no-cache",
4026
+ Connection: "keep-alive"
4027
+ }
4028
+ });
4029
+ }
4030
+ async function handleListNotifications(request, opts) {
4031
+ const url = new URL(request.url);
4032
+ const userId = url.searchParams.get("userId");
4033
+ if (!userId) {
4034
+ return Response.json({ error: "userId is required" }, { status: 400 });
4035
+ }
4036
+ const tableName = opts.notifications?.tableName;
4037
+ try {
4038
+ const notifications = await listPersistedNotifications(
4039
+ userId,
4040
+ {
4041
+ limit: Math.min(Number(url.searchParams.get("limit")) || 50, 100),
4042
+ unreadOnly: url.searchParams.get("unreadOnly") === "true",
4043
+ type: url.searchParams.get("type") ?? void 0
4044
+ },
4045
+ { tableName }
4046
+ );
4047
+ return Response.json({ notifications });
4048
+ } catch (err) {
4049
+ console.error("[brokr] List notifications failed:", err);
4050
+ return Response.json({ notifications: [] });
4051
+ }
4052
+ }
4053
+ async function handleMarkNotificationRead(request, opts) {
4054
+ const body = await request.json();
4055
+ if (!body.notificationId || !body.userId) {
4056
+ return Response.json({ error: "notificationId and userId are required" }, { status: 400 });
4057
+ }
4058
+ const tableName = opts.notifications?.tableName;
4059
+ try {
4060
+ await markNotificationRead(body.notificationId, body.userId, { tableName });
4061
+ return Response.json({ success: true });
4062
+ } catch (err) {
4063
+ console.error("[brokr] Mark notification read failed:", err);
4064
+ return Response.json({ error: "Failed to mark as read" }, { status: 500 });
4065
+ }
4066
+ }
4067
+ function handleWsToken() {
4068
+ const token = process.env.BROKR_TOKEN;
4069
+ if (!token) {
4070
+ return Response.json(
4071
+ { error: "BROKR_TOKEN not configured" },
4072
+ { status: 500 }
4073
+ );
4074
+ }
4075
+ return Response.json({ token });
4076
+ }
4077
+ function createBrokrHandlers(options) {
4078
+ const opts = { persist: false, ...options };
4079
+ function withLogging(method, handler) {
4080
+ return async (request) => {
4081
+ const start = Date.now();
4082
+ const urlPath = new URL(request.url).pathname;
4083
+ try {
4084
+ const response = await handler(request);
4085
+ const dur = Date.now() - start;
4086
+ captureRequest(method, urlPath, response.status, dur);
4087
+ return response;
4088
+ } catch (err) {
4089
+ const dur = Date.now() - start;
4090
+ capture("error", `${method} ${urlPath} FAILED ${dur}ms \u2014 ${err instanceof Error ? err.message : "unknown"}`, urlPath);
4091
+ throw err;
4092
+ }
4093
+ };
4094
+ }
4095
+ return {
4096
+ GET: withLogging("GET", async (request) => {
4097
+ const path = parsePath(request.url);
4098
+ if (path.action === "threads") return handleListThreads(request, opts);
4099
+ if (path.action === "messages" && path.id) return handleGetMessages(request, path.id, opts);
4100
+ if (path.action === "ws-token") return handleWsToken();
4101
+ if (path.action === "notifications") return handleListNotifications(request, opts);
4102
+ return new Response("Not found", { status: 404 });
4103
+ }),
4104
+ POST: withLogging("POST", async (request) => {
4105
+ const path = parsePath(request.url);
4106
+ if (path.action === "chat") return handleChat(request, opts);
4107
+ if (path.action === "notifications-read") return handleMarkNotificationRead(request, opts);
4108
+ return new Response("Not found", { status: 404 });
4109
+ }),
4110
+ PATCH: withLogging("PATCH", async (request) => {
4111
+ const path = parsePath(request.url);
4112
+ if (path.action === "rename" && path.id) return handleRenameThread(request, path.id, opts);
4113
+ if (path.action === "thread" && path.id) return handleRenameThread(request, path.id, opts);
4114
+ return new Response("Not found", { status: 404 });
4115
+ }),
4116
+ DELETE: withLogging("DELETE", async (request) => {
4117
+ const path = parsePath(request.url);
4118
+ if (path.action === "thread" && path.id) return handleDeleteThread(request, path.id, opts);
4119
+ return new Response("Not found", { status: 404 });
4120
+ })
4121
+ };
4122
+ }
547
4123
  export {
548
4124
  BrokrAIClient,
4125
+ BrokrAuthError,
549
4126
  BrokrClient,
550
4127
  BrokrEmailClient,
4128
+ BrokrEntitlementsClient,
551
4129
  BrokrError,
4130
+ BrokrFilesClient,
4131
+ BrokrNetworkError,
4132
+ BrokrNotFoundError,
4133
+ BrokrPaymentsClient,
4134
+ BrokrRateLimitError,
552
4135
  BrokrRuntime,
553
4136
  BrokrStorageClient,
4137
+ BrokrTimeoutError,
4138
+ BrokrValidationError,
554
4139
  authMiddleware,
4140
+ buildFallbackConversationTitle,
555
4141
  create,
556
4142
  createBrokr,
557
- createBrokrClient
4143
+ createBrokrClient,
4144
+ createBrokrHandlers,
4145
+ generateConversationTitle,
4146
+ models,
4147
+ providers,
4148
+ resolveProviderByModel,
4149
+ sanitizeConversationTitle
558
4150
  };