@hexclave/shared 1.0.3 → 1.0.5

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 (343) hide show
  1. package/dist/ai/unified-prompts/reminders.js +4 -3
  2. package/dist/ai/unified-prompts/reminders.js.map +1 -1
  3. package/dist/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.d.ts +3 -1
  4. package/dist/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.d.ts.map +1 -1
  5. package/dist/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js +216 -29
  6. package/dist/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js.map +1 -1
  7. package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-index.d.ts.map +1 -1
  8. package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-index.js +1 -0
  9. package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-index.js.map +1 -1
  10. package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.d.ts +18 -6
  11. package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.js +23 -8
  12. package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.js.map +1 -1
  13. package/dist/ai/unified-prompts/skill-site-prompt-parts/openapi-specs.js +1 -1
  14. package/dist/ai/unified-prompts/skill-site-prompt-parts/openapi-specs.js.map +1 -1
  15. package/dist/config/schema.d.ts +71 -71
  16. package/dist/config/schema.d.ts.map +1 -1
  17. package/dist/config/schema.js +5 -5
  18. package/dist/config/schema.js.map +1 -1
  19. package/dist/config-authoring.d.ts +4 -4
  20. package/dist/config-authoring.d.ts.map +1 -1
  21. package/dist/config-authoring.js +2 -2
  22. package/dist/config-authoring.js.map +1 -1
  23. package/dist/config-rendering.d.ts +4 -4
  24. package/dist/config-rendering.d.ts.map +1 -1
  25. package/dist/config-rendering.js +19 -18
  26. package/dist/config-rendering.js.map +1 -1
  27. package/dist/esm/ai/unified-prompts/reminders.js +4 -3
  28. package/dist/esm/ai/unified-prompts/reminders.js.map +1 -1
  29. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.d.ts +3 -1
  30. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.d.ts.map +1 -1
  31. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js +215 -30
  32. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js.map +1 -1
  33. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-index.d.ts.map +1 -1
  34. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-index.js +1 -0
  35. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-index.js.map +1 -1
  36. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.d.ts +18 -6
  37. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.js +23 -8
  38. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.js.map +1 -1
  39. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/openapi-specs.js +1 -1
  40. package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/openapi-specs.js.map +1 -1
  41. package/dist/esm/config/schema.d.ts +71 -71
  42. package/dist/esm/config/schema.d.ts.map +1 -1
  43. package/dist/esm/config/schema.js +5 -5
  44. package/dist/esm/config/schema.js.map +1 -1
  45. package/dist/esm/config-authoring.d.ts +4 -4
  46. package/dist/esm/config-authoring.d.ts.map +1 -1
  47. package/dist/esm/config-authoring.js +2 -2
  48. package/dist/esm/config-authoring.js.map +1 -1
  49. package/dist/esm/config-rendering.d.ts +4 -4
  50. package/dist/esm/config-rendering.d.ts.map +1 -1
  51. package/dist/esm/config-rendering.js +15 -14
  52. package/dist/esm/config-rendering.js.map +1 -1
  53. package/dist/esm/helpers/vault/client-side.d.ts.map +1 -1
  54. package/dist/esm/helpers/vault/client-side.js.map +1 -1
  55. package/dist/esm/helpers/vault/server-side.d.ts.map +1 -1
  56. package/dist/esm/helpers/vault/server-side.js.map +1 -1
  57. package/dist/esm/hexclave-config-file.d.ts +15 -0
  58. package/dist/esm/hexclave-config-file.d.ts.map +1 -0
  59. package/dist/esm/{stack-config-file.js → hexclave-config-file.js} +7 -7
  60. package/dist/esm/hexclave-config-file.js.map +1 -0
  61. package/dist/esm/hooks/use-async-callback.js +1 -1
  62. package/dist/esm/hooks/use-async-external-store.js +1 -1
  63. package/dist/esm/hooks/use-strict-memo.js +1 -1
  64. package/dist/esm/interface/admin-metrics.d.ts +4 -4
  65. package/dist/esm/interface/admin-metrics.js.map +1 -1
  66. package/dist/esm/interface/client-interface.js +2 -2
  67. package/dist/esm/interface/client-interface.js.map +1 -1
  68. package/dist/esm/interface/conversations.d.ts +13 -13
  69. package/dist/esm/interface/crud/current-user.d.ts +9 -9
  70. package/dist/esm/interface/crud/email-outbox.d.ts +112 -112
  71. package/dist/esm/interface/crud/products.d.ts +1 -1
  72. package/dist/esm/interface/crud/project-api-keys.d.ts +2 -2
  73. package/dist/esm/interface/crud/project-permissions.js +5 -5
  74. package/dist/esm/interface/crud/project-permissions.js.map +1 -1
  75. package/dist/esm/interface/crud/projects.d.ts +28 -28
  76. package/dist/esm/interface/crud/team-member-profiles.d.ts +22 -22
  77. package/dist/esm/interface/crud/team-permissions.js +5 -5
  78. package/dist/esm/interface/crud/team-permissions.js.map +1 -1
  79. package/dist/esm/interface/crud/users.d.ts +14 -14
  80. package/dist/esm/interface/page-component-versions.js +107 -107
  81. package/dist/esm/interface/page-component-versions.js.map +1 -1
  82. package/dist/esm/interface/webhooks.d.ts +4 -4
  83. package/dist/esm/known-errors.js +4 -4
  84. package/dist/esm/known-errors.js.map +1 -1
  85. package/dist/esm/schema-fields.d.ts +15 -5
  86. package/dist/esm/schema-fields.d.ts.map +1 -1
  87. package/dist/esm/schema-fields.js +26 -16
  88. package/dist/esm/schema-fields.js.map +1 -1
  89. package/dist/esm/utils/crypto.d.ts.map +1 -1
  90. package/dist/esm/utils/crypto.js.map +1 -1
  91. package/dist/esm/utils/currency-constants.d.ts +6 -0
  92. package/dist/esm/utils/currency-constants.d.ts.map +1 -1
  93. package/dist/esm/utils/currency-constants.js.map +1 -1
  94. package/dist/esm/utils/dev-env-state-path.d.ts +3 -3
  95. package/dist/esm/utils/dev-env-state-path.d.ts.map +1 -1
  96. package/dist/esm/utils/dev-env-state-path.js +4 -4
  97. package/dist/esm/utils/dev-env-state-path.js.map +1 -1
  98. package/dist/esm/utils/errors.js +2 -2
  99. package/dist/esm/utils/errors.js.map +1 -1
  100. package/dist/esm/utils/esbuild.d.ts.map +1 -1
  101. package/dist/esm/utils/esbuild.js +0 -1
  102. package/dist/esm/utils/esbuild.js.map +1 -1
  103. package/dist/esm/utils/featurebase.d.ts +3 -3
  104. package/dist/esm/utils/featurebase.d.ts.map +1 -1
  105. package/dist/esm/utils/featurebase.js +15 -15
  106. package/dist/esm/utils/featurebase.js.map +1 -1
  107. package/dist/esm/utils/fs.js +6 -6
  108. package/dist/esm/utils/fs.js.map +1 -1
  109. package/dist/esm/utils/globals.d.ts.map +1 -1
  110. package/dist/esm/utils/globals.js +10 -10
  111. package/dist/esm/utils/globals.js.map +1 -1
  112. package/dist/esm/utils/jwt.d.ts.map +1 -1
  113. package/dist/esm/utils/jwt.js +3 -3
  114. package/dist/esm/utils/jwt.js.map +1 -1
  115. package/dist/esm/utils/redirect-urls.d.ts +3 -3
  116. package/dist/esm/utils/redirect-urls.d.ts.map +1 -1
  117. package/dist/esm/utils/redirect-urls.js +5 -5
  118. package/dist/esm/utils/redirect-urls.js.map +1 -1
  119. package/dist/esm/utils/urls.js.map +1 -1
  120. package/dist/helpers/vault/client-side.d.ts.map +1 -1
  121. package/dist/helpers/vault/client-side.js.map +1 -1
  122. package/dist/helpers/vault/server-side.d.ts.map +1 -1
  123. package/dist/helpers/vault/server-side.js.map +1 -1
  124. package/dist/hexclave-config-file.d.ts +15 -0
  125. package/dist/hexclave-config-file.d.ts.map +1 -0
  126. package/dist/{stack-config-file.js → hexclave-config-file.js} +8 -8
  127. package/dist/hexclave-config-file.js.map +1 -0
  128. package/dist/hooks/use-async-callback.js +1 -1
  129. package/dist/hooks/use-async-external-store.js +1 -1
  130. package/dist/hooks/use-strict-memo.js +1 -1
  131. package/dist/interface/admin-metrics.d.ts +4 -4
  132. package/dist/interface/admin-metrics.js.map +1 -1
  133. package/dist/interface/client-interface.js +2 -2
  134. package/dist/interface/client-interface.js.map +1 -1
  135. package/dist/interface/conversations.d.ts +13 -13
  136. package/dist/interface/crud/current-user.d.ts +9 -9
  137. package/dist/interface/crud/email-outbox.d.ts +112 -112
  138. package/dist/interface/crud/products.d.ts +1 -1
  139. package/dist/interface/crud/project-api-keys.d.ts +2 -2
  140. package/dist/interface/crud/project-permissions.js +5 -5
  141. package/dist/interface/crud/project-permissions.js.map +1 -1
  142. package/dist/interface/crud/projects.d.ts +28 -28
  143. package/dist/interface/crud/team-member-profiles.d.ts +22 -22
  144. package/dist/interface/crud/team-permissions.js +5 -5
  145. package/dist/interface/crud/team-permissions.js.map +1 -1
  146. package/dist/interface/crud/users.d.ts +14 -14
  147. package/dist/interface/page-component-versions.js +107 -107
  148. package/dist/interface/page-component-versions.js.map +1 -1
  149. package/dist/interface/webhooks.d.ts +4 -4
  150. package/dist/known-errors.js +4 -4
  151. package/dist/known-errors.js.map +1 -1
  152. package/dist/schema-fields.d.ts +15 -5
  153. package/dist/schema-fields.d.ts.map +1 -1
  154. package/dist/schema-fields.js +26 -16
  155. package/dist/schema-fields.js.map +1 -1
  156. package/dist/utils/crypto.d.ts.map +1 -1
  157. package/dist/utils/crypto.js.map +1 -1
  158. package/dist/utils/currency-constants.d.ts +6 -0
  159. package/dist/utils/currency-constants.d.ts.map +1 -1
  160. package/dist/utils/currency-constants.js.map +1 -1
  161. package/dist/utils/dev-env-state-path.d.ts +3 -3
  162. package/dist/utils/dev-env-state-path.d.ts.map +1 -1
  163. package/dist/utils/dev-env-state-path.js +5 -5
  164. package/dist/utils/dev-env-state-path.js.map +1 -1
  165. package/dist/utils/errors.js +2 -2
  166. package/dist/utils/errors.js.map +1 -1
  167. package/dist/utils/esbuild.d.ts.map +1 -1
  168. package/dist/utils/esbuild.js +0 -1
  169. package/dist/utils/esbuild.js.map +1 -1
  170. package/dist/utils/featurebase.d.ts +3 -3
  171. package/dist/utils/featurebase.d.ts.map +1 -1
  172. package/dist/utils/featurebase.js +15 -15
  173. package/dist/utils/featurebase.js.map +1 -1
  174. package/dist/utils/fs.js.map +1 -1
  175. package/dist/utils/globals.d.ts.map +1 -1
  176. package/dist/utils/globals.js +10 -10
  177. package/dist/utils/globals.js.map +1 -1
  178. package/dist/utils/jwt.d.ts.map +1 -1
  179. package/dist/utils/jwt.js +3 -3
  180. package/dist/utils/jwt.js.map +1 -1
  181. package/dist/utils/redirect-urls.d.ts +3 -3
  182. package/dist/utils/redirect-urls.d.ts.map +1 -1
  183. package/dist/utils/redirect-urls.js +5 -5
  184. package/dist/utils/redirect-urls.js.map +1 -1
  185. package/dist/utils/urls.js.map +1 -1
  186. package/package.json +2 -1
  187. package/src/ai/image-limits.ts +62 -0
  188. package/src/ai/llms/llms.ts +36 -0
  189. package/src/ai/unified-prompts/reminders.ts +27 -0
  190. package/src/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.ts +1047 -0
  191. package/src/ai/unified-prompts/skill-site-prompt-parts/brain.ts +5 -0
  192. package/src/ai/unified-prompts/skill-site-prompt-parts/cli-help.ts +5 -0
  193. package/src/ai/unified-prompts/skill-site-prompt-parts/config-docs.ts +5 -0
  194. package/src/ai/unified-prompts/skill-site-prompt-parts/custom-components-instructions.ts +5 -0
  195. package/src/ai/unified-prompts/skill-site-prompt-parts/dashboard-instructions.ts +5 -0
  196. package/src/ai/unified-prompts/skill-site-prompt-parts/docs-index.ts +80 -0
  197. package/src/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.ts +322 -0
  198. package/src/ai/unified-prompts/skill-site-prompt-parts/openapi-specs.ts +5 -0
  199. package/src/ai/unified-prompts/skill-site-prompt-parts/sdk-interface-source.ts +5 -0
  200. package/src/ai/unified-prompts/skill-site-prompt.ts +72 -0
  201. package/src/apps/apps-config.ts +177 -0
  202. package/src/apps/apps-ui.tsx +112 -0
  203. package/src/config/README.md +154 -0
  204. package/src/config/db-sync-mappings.ts +2293 -0
  205. package/src/config/format.ts +388 -0
  206. package/src/config/migrate-catalogs-to-product-lines.ts +475 -0
  207. package/src/config/schema-fuzzer.test.ts +377 -0
  208. package/src/config/schema.ts +1507 -0
  209. package/src/config-authoring.test.ts +52 -0
  210. package/src/config-authoring.ts +37 -0
  211. package/src/config-rendering.ts +142 -0
  212. package/src/crud.tsx +275 -0
  213. package/src/global.d.ts +1 -0
  214. package/src/helpers/emails.ts +250 -0
  215. package/src/helpers/init-prompt.ts +39 -0
  216. package/src/helpers/password.ts +16 -0
  217. package/src/helpers/production-mode.ts +58 -0
  218. package/src/helpers/support-sla.test.ts +124 -0
  219. package/src/helpers/support-sla.ts +93 -0
  220. package/src/helpers/vault/client-side.ts +92 -0
  221. package/src/helpers/vault/server-side.ts +153 -0
  222. package/src/hexclave-config-file.ts +120 -0
  223. package/src/hooks/use-async-callback.tsx +43 -0
  224. package/src/hooks/use-async-external-store.tsx +24 -0
  225. package/src/hooks/use-hash.tsx +14 -0
  226. package/src/hooks/use-hover.tsx +88 -0
  227. package/src/hooks/use-strict-memo.tsx +157 -0
  228. package/src/index.ts +17 -0
  229. package/src/interface/admin-interface.ts +1043 -0
  230. package/src/interface/admin-metrics.ts +214 -0
  231. package/src/interface/client-interface.test.ts +765 -0
  232. package/src/interface/client-interface.ts +2586 -0
  233. package/src/interface/conversations.ts +109 -0
  234. package/src/interface/crud/analytics.ts +11 -0
  235. package/src/interface/crud/connected-accounts.ts +52 -0
  236. package/src/interface/crud/contact-channels.ts +74 -0
  237. package/src/interface/crud/current-user.ts +72 -0
  238. package/src/interface/crud/email-outbox.ts +263 -0
  239. package/src/interface/crud/email-templates.ts +50 -0
  240. package/src/interface/crud/emails.ts +22 -0
  241. package/src/interface/crud/internal-api-keys.ts +69 -0
  242. package/src/interface/crud/invoices.ts +36 -0
  243. package/src/interface/crud/items.ts +24 -0
  244. package/src/interface/crud/notification-preferences.ts +33 -0
  245. package/src/interface/crud/oauth-providers.ts +91 -0
  246. package/src/interface/crud/products.ts +42 -0
  247. package/src/interface/crud/project-api-keys.ts +100 -0
  248. package/src/interface/crud/project-permissions.ts +118 -0
  249. package/src/interface/crud/projects.ts +229 -0
  250. package/src/interface/crud/session-replays.ts +85 -0
  251. package/src/interface/crud/sessions.ts +66 -0
  252. package/src/interface/crud/sign-up-rules.ts +12 -0
  253. package/src/interface/crud/svix-token.ts +20 -0
  254. package/src/interface/crud/team-invitation-details.ts +22 -0
  255. package/src/interface/crud/team-invitation.ts +35 -0
  256. package/src/interface/crud/team-member-profiles.ts +61 -0
  257. package/src/interface/crud/team-memberships.ts +56 -0
  258. package/src/interface/crud/team-permissions.ts +119 -0
  259. package/src/interface/crud/teams.ts +142 -0
  260. package/src/interface/crud/transactions.ts +131 -0
  261. package/src/interface/crud/users.ts +185 -0
  262. package/src/interface/handler-urls.ts +74 -0
  263. package/src/interface/page-component-versions.ts +1702 -0
  264. package/src/interface/server-interface.ts +1146 -0
  265. package/src/interface/webhooks.ts +28 -0
  266. package/src/known-errors.tsx +2031 -0
  267. package/src/local-emulator.ts +5 -0
  268. package/src/payments/payment-methods.ts +167 -0
  269. package/src/payments/stripe-limits.ts +18 -0
  270. package/src/plans.ts +107 -0
  271. package/src/schema-fields.ts +944 -0
  272. package/src/sessions.ts +310 -0
  273. package/src/utils/api-keys.tsx +122 -0
  274. package/src/utils/arrays.tsx +248 -0
  275. package/src/utils/auth-methods.ts +8 -0
  276. package/src/utils/base64.tsx +24 -0
  277. package/src/utils/booleans.tsx +34 -0
  278. package/src/utils/browser-compat.tsx +17 -0
  279. package/src/utils/bytes.tsx +280 -0
  280. package/src/utils/caches.tsx +280 -0
  281. package/src/utils/cel-fields.ts +92 -0
  282. package/src/utils/cloud-hosts.tsx +92 -0
  283. package/src/utils/compile-time.tsx +11 -0
  284. package/src/utils/country-codes.ts +39 -0
  285. package/src/utils/crypto.tsx +174 -0
  286. package/src/utils/currencies.tsx +53 -0
  287. package/src/utils/currency-constants.tsx +51 -0
  288. package/src/utils/dates.tsx +246 -0
  289. package/src/utils/dev-env-state-path.ts +14 -0
  290. package/src/utils/dom.tsx +7 -0
  291. package/src/utils/env.tsx +117 -0
  292. package/src/utils/errors.tsx +284 -0
  293. package/src/utils/esbuild.tsx +235 -0
  294. package/src/utils/featurebase.tsx +247 -0
  295. package/src/utils/fs.tsx +33 -0
  296. package/src/utils/functions.tsx +22 -0
  297. package/src/utils/geo.tsx +16 -0
  298. package/src/utils/globals.tsx +48 -0
  299. package/src/utils/hashes.tsx +52 -0
  300. package/src/utils/html.tsx +60 -0
  301. package/src/utils/http.tsx +91 -0
  302. package/src/utils/ips.tsx +47 -0
  303. package/src/utils/json.tsx +200 -0
  304. package/src/utils/jsx-editable-transpiler.test.ts +156 -0
  305. package/src/utils/jsx-editable-transpiler.tsx +401 -0
  306. package/src/utils/jwt.tsx +170 -0
  307. package/src/utils/locks.tsx +71 -0
  308. package/src/utils/maps.tsx +407 -0
  309. package/src/utils/math.tsx +18 -0
  310. package/src/utils/monkey-patch.tsx +29 -0
  311. package/src/utils/node-http.tsx +47 -0
  312. package/src/utils/numbers.tsx +82 -0
  313. package/src/utils/oauth.tsx +9 -0
  314. package/src/utils/objects.tsx +581 -0
  315. package/src/utils/paginated-lists.test.ts +1039 -0
  316. package/src/utils/paginated-lists.tsx +479 -0
  317. package/src/utils/passkey.tsx +1 -0
  318. package/src/utils/promises.tsx +540 -0
  319. package/src/utils/proxies.tsx +212 -0
  320. package/src/utils/react.tsx +308 -0
  321. package/src/utils/redirect-urls.tsx +299 -0
  322. package/src/utils/regex.tsx +10 -0
  323. package/src/utils/results.tsx +411 -0
  324. package/src/utils/sentry.tsx +20 -0
  325. package/src/utils/stores.tsx +238 -0
  326. package/src/utils/strings.nicify.test.ts +253 -0
  327. package/src/utils/strings.tsx +723 -0
  328. package/src/utils/telemetry.tsx +37 -0
  329. package/src/utils/turnstile-browser.ts +106 -0
  330. package/src/utils/turnstile-flow.test.ts +101 -0
  331. package/src/utils/turnstile-flow.ts +266 -0
  332. package/src/utils/turnstile.ts +34 -0
  333. package/src/utils/typed-arrays.tsx +17 -0
  334. package/src/utils/types.tsx +208 -0
  335. package/src/utils/unicode.tsx +24 -0
  336. package/src/utils/urls.tsx +411 -0
  337. package/src/utils/uuids.tsx +47 -0
  338. package/dist/esm/stack-config-file.d.ts +0 -15
  339. package/dist/esm/stack-config-file.d.ts.map +0 -1
  340. package/dist/esm/stack-config-file.js.map +0 -1
  341. package/dist/stack-config-file.d.ts +0 -15
  342. package/dist/stack-config-file.d.ts.map +0 -1
  343. package/dist/stack-config-file.js.map +0 -1
@@ -0,0 +1,540 @@
1
+ import { KnownError } from "..";
2
+ import { getProcessEnv } from "./env";
3
+ import { HexclaveAssertionError, captureError, concatStacktraces, errorToNiceString } from "./errors";
4
+ import { DependenciesMap } from "./maps";
5
+ import { Result } from "./results";
6
+ import { traceSpan } from "./telemetry";
7
+ import { generateUuid } from "./uuids";
8
+
9
+ export type ReactPromise<T> = Promise<T> & (
10
+ | { status: "rejected", reason: unknown }
11
+ | { status: "fulfilled", value: T }
12
+ | { status: "pending" }
13
+ );
14
+
15
+ type Resolve<T> = (value: T) => void;
16
+ type Reject = (reason: unknown) => void;
17
+ export function createPromise<T>(callback: (resolve: Resolve<T>, reject: Reject) => void): ReactPromise<T> {
18
+ let status = "pending" as "fulfilled" | "rejected" | "pending";
19
+ let valueOrReason: T | unknown | undefined = undefined;
20
+ let resolve: Resolve<T> | null = null;
21
+ let reject: Reject | null = null;
22
+ const promise = new Promise<T>((res, rej) => {
23
+ resolve = (value) => {
24
+ if (status !== "pending") return;
25
+ status = "fulfilled";
26
+ valueOrReason = value;
27
+ res(value);
28
+ };
29
+ reject = (reason) => {
30
+ if (status !== "pending") return;
31
+ status = "rejected";
32
+ valueOrReason = reason;
33
+ rej(reason);
34
+ };
35
+ });
36
+
37
+ callback(resolve!, reject!);
38
+ return Object.assign(promise, {
39
+ status: status,
40
+ ...status === "fulfilled" ? { value: valueOrReason as T } : {},
41
+ ...status === "rejected" ? { reason: valueOrReason } : {},
42
+ } as any);
43
+ }
44
+ import.meta.vitest?.test("createPromise", async ({ expect }) => {
45
+ // Test resolved promise
46
+ const resolvedPromise = createPromise<number>((resolve) => {
47
+ resolve(42);
48
+ });
49
+ expect(resolvedPromise.status).toBe("fulfilled");
50
+ expect((resolvedPromise as any).value).toBe(42);
51
+ expect(await resolvedPromise).toBe(42);
52
+
53
+ // Test rejected promise
54
+ const error = new Error("Test error");
55
+ const rejectedPromise = createPromise<number>((_, reject) => {
56
+ reject(error);
57
+ });
58
+ expect(rejectedPromise.status).toBe("rejected");
59
+ expect((rejectedPromise as any).reason).toBe(error);
60
+ await expect(rejectedPromise).rejects.toBe(error);
61
+
62
+ // Test pending promise
63
+ const pendingPromise = createPromise<number>(() => {
64
+ // Do nothing, leave it pending
65
+ });
66
+ expect(pendingPromise.status).toBe("pending");
67
+ expect((pendingPromise as any).value).toBeUndefined();
68
+ expect((pendingPromise as any).reason).toBeUndefined();
69
+
70
+ // Test that resolving after already resolved does nothing
71
+ let resolveCount = 0;
72
+ const multiResolvePromise = createPromise<number>((resolve) => {
73
+ resolve(1);
74
+ resolveCount++;
75
+ resolve(2);
76
+ resolveCount++;
77
+ });
78
+ expect(resolveCount).toBe(2); // Both resolve calls executed
79
+ expect(multiResolvePromise.status).toBe("fulfilled");
80
+ expect((multiResolvePromise as any).value).toBe(1); // Only first resolve took effect
81
+ expect(await multiResolvePromise).toBe(1);
82
+ });
83
+
84
+ let resolvedCache: DependenciesMap<[unknown], ReactPromise<unknown>> | null = null;
85
+ /**
86
+ * Like Promise.resolve(...), but also adds the status and value properties for use with React's `use` hook, and caches
87
+ * the value so that invoking `resolved` twice returns the same promise.
88
+ */
89
+ export function resolved<T>(value: T): ReactPromise<T> {
90
+ resolvedCache ??= new DependenciesMap<[unknown], ReactPromise<unknown>>();
91
+ if (resolvedCache.has([value])) {
92
+ return resolvedCache.get([value]) as ReactPromise<T>;
93
+ }
94
+
95
+ const res = Object.assign(Promise.resolve(value), {
96
+ status: "fulfilled",
97
+ value,
98
+ } as const);
99
+ resolvedCache.set([value], res);
100
+ return res;
101
+ }
102
+ import.meta.vitest?.test("resolved", async ({ expect }) => {
103
+ // Test with primitive value
104
+ const promise1 = resolved(42);
105
+ expect(promise1.status).toBe("fulfilled");
106
+ // Need to use type assertion since value is only available when status is "fulfilled"
107
+ expect((promise1 as { value: number }).value).toBe(42);
108
+ expect(await promise1).toBe(42);
109
+
110
+ // Test with object value
111
+ const obj = { test: true };
112
+ const promise2 = resolved(obj);
113
+ expect(promise2.status).toBe("fulfilled");
114
+ expect((promise2 as { value: typeof obj }).value).toBe(obj);
115
+ expect(await promise2).toBe(obj);
116
+
117
+ // Test caching (same reference for same value)
118
+ const promise3 = resolved(42);
119
+ expect(promise3).toBe(promise1); // Same reference due to caching
120
+
121
+ // Test with different value (different reference)
122
+ const promise4 = resolved(43);
123
+ expect(promise4).not.toBe(promise1);
124
+ });
125
+
126
+ let rejectedCache: DependenciesMap<[unknown], ReactPromise<unknown>> | null = null;
127
+ /**
128
+ * Like Promise.reject(...), but also adds the status and value properties for use with React's `use` hook, and caches
129
+ * the value so that invoking `rejected` twice returns the same promise.
130
+ */
131
+ export function rejected<T>(reason: unknown): ReactPromise<T> {
132
+ rejectedCache ??= new DependenciesMap<[unknown], ReactPromise<unknown>>();
133
+ if (rejectedCache.has([reason])) {
134
+ return rejectedCache.get([reason]) as ReactPromise<T>;
135
+ }
136
+
137
+ const promise = Promise.reject(reason);
138
+ ignoreUnhandledRejection(promise);
139
+ const res = Object.assign(promise, {
140
+ status: "rejected",
141
+ reason: reason,
142
+ } as const);
143
+ rejectedCache.set([reason], res);
144
+ return res;
145
+ }
146
+ import.meta.vitest?.test("rejected", ({ expect }) => {
147
+ // Test with error object
148
+ const error = new Error("Test error");
149
+ const promise1 = rejected<number>(error);
150
+ expect(promise1.status).toBe("rejected");
151
+ // Need to use type assertion since reason is only available when status is "rejected"
152
+ expect((promise1 as { reason: Error }).reason).toBe(error);
153
+
154
+ // Test with string reason
155
+ const promise2 = rejected<string>("error message");
156
+ expect(promise2.status).toBe("rejected");
157
+ expect((promise2 as { reason: string }).reason).toBe("error message");
158
+
159
+ // Test caching (same reference for same reason)
160
+ const promise3 = rejected<number>(error);
161
+ expect(promise3).toBe(promise1); // Same reference due to caching
162
+
163
+ // Test with different reason (different reference)
164
+ const differentError = new Error("Different error");
165
+ const promise4 = rejected<number>(differentError);
166
+ expect(promise4).not.toBe(promise1);
167
+
168
+ // Note: We're not using await expect(promise).rejects to avoid unhandled rejections
169
+ });
170
+
171
+ // We'll skip the rejection test for pending() since it's causing unhandled rejections
172
+ // The function is already well tested through other tests like rejected() and createPromise()
173
+
174
+
175
+ const neverResolvePromise = pending(new Promise<never>(() => {}));
176
+ export function neverResolve(): ReactPromise<never> {
177
+ return neverResolvePromise;
178
+ }
179
+ import.meta.vitest?.test("neverResolve", ({ expect }) => {
180
+ const promise = neverResolve();
181
+ expect(promise.status).toBe("pending");
182
+ expect((promise as any).value).toBeUndefined();
183
+ expect((promise as any).reason).toBeUndefined();
184
+
185
+ // Test that multiple calls return the same promise
186
+ const promise2 = neverResolve();
187
+ expect(promise2).toBe(promise);
188
+ });
189
+
190
+ export function pending<T>(promise: Promise<T>, options: { disableErrorWrapping?: boolean } = {}): ReactPromise<T> {
191
+ const res = promise.then(
192
+ value => {
193
+ res.status = "fulfilled";
194
+ (res as any).value = value;
195
+ return value;
196
+ },
197
+ actualReason => {
198
+ res.status = "rejected";
199
+ (res as any).reason = actualReason;
200
+ throw actualReason;
201
+ },
202
+ ) as ReactPromise<T>;
203
+ res.status = "pending";
204
+ return res;
205
+ }
206
+ import.meta.vitest?.test("pending", async ({ expect }) => {
207
+ // Test with a promise that resolves
208
+ const resolvePromise = Promise.resolve(42);
209
+ const pendingPromise = pending(resolvePromise);
210
+
211
+ // Initially it should be pending
212
+ expect(pendingPromise.status).toBe("pending");
213
+
214
+ // After resolution, it should be fulfilled
215
+ await resolvePromise;
216
+ // Need to wait a tick for the then handler to execute
217
+ await new Promise(resolve => setTimeout(resolve, 0));
218
+ expect(pendingPromise.status).toBe("fulfilled");
219
+ expect((pendingPromise as { value: number }).value).toBe(42);
220
+
221
+ // For the rejection test, we'll use a separate test to avoid unhandled rejections
222
+ });
223
+
224
+ /**
225
+ * Should be used to wrap Promises that are not immediately awaited, so they don't throw an unhandled promise rejection
226
+ * error.
227
+ *
228
+ * Vercel kills serverless functions on unhandled promise rejection errors, so this is important.
229
+ */
230
+ export function ignoreUnhandledRejection<T extends Promise<any>>(promise: T): void {
231
+ promise.catch(() => {});
232
+ }
233
+ import.meta.vitest?.test("ignoreUnhandledRejection", async ({ expect }) => {
234
+ // Test with a promise that resolves
235
+ const resolvePromise = Promise.resolve(42);
236
+ ignoreUnhandledRejection(resolvePromise);
237
+ expect(await resolvePromise).toBe(42); // Should still resolve to the same value
238
+
239
+ // Test with a promise that rejects
240
+ // The promise should still reject, but the rejection is caught internally
241
+ // so it doesn't cause an unhandled rejection error
242
+ const error = new Error("Test error");
243
+ const rejectPromise = Promise.reject(error);
244
+ ignoreUnhandledRejection(rejectPromise);
245
+ await expect(rejectPromise).rejects.toBe(error);
246
+ });
247
+
248
+ /**
249
+ * See concatStacktraces for more information.
250
+ */
251
+ export function concatStacktracesIfRejected<T>(promise: Promise<T>): void {
252
+ const currentError = new Error();
253
+ promise.catch(error => {
254
+ if (error instanceof Error) {
255
+ concatStacktraces(error, currentError);
256
+ } else {
257
+ // we can only concatenate errors, so we'll just ignore the non-error
258
+ }
259
+ });
260
+ }
261
+
262
+ export async function wait(ms: number) {
263
+ if (!Number.isFinite(ms) || ms < 0) {
264
+ throw new HexclaveAssertionError(`wait() requires a non-negative integer number of milliseconds to wait. (found: ${ms}ms)`);
265
+ }
266
+ if (ms >= 2**31) {
267
+ throw new HexclaveAssertionError("The maximum timeout for wait() is 2147483647ms (2**31 - 1). (found: ${ms}ms)");
268
+ }
269
+ return await traceSpan({ description: 'wait(...)', attributes: { 'stack.wait.ms': ms } }, async (span) => {
270
+ return await new Promise<void>(resolve => setTimeout(resolve, ms));
271
+ });
272
+ }
273
+ import.meta.vitest?.test("wait", async ({ expect }) => {
274
+ // Test with valid input
275
+ const start = Date.now();
276
+ await wait(10);
277
+ const elapsed = Date.now() - start;
278
+ expect(elapsed).toBeGreaterThanOrEqual(5); // Allow some flexibility in timing
279
+
280
+ // Test with zero
281
+ await expect(wait(0)).resolves.toBeUndefined();
282
+
283
+ // Test with negative number
284
+ await expect(wait(-10)).rejects.toThrow("wait() requires a non-negative integer");
285
+
286
+ // Test with non-finite number
287
+ await expect(wait(NaN)).rejects.toThrow("wait() requires a non-negative integer");
288
+ await expect(wait(Infinity)).rejects.toThrow("wait() requires a non-negative integer");
289
+
290
+ // Test with too large number
291
+ await expect(wait(2**31)).rejects.toThrow("The maximum timeout for wait()");
292
+ });
293
+
294
+ export async function waitUntil(date: Date) {
295
+ return await wait(date.getTime() - Date.now());
296
+ }
297
+ import.meta.vitest?.test("waitUntil", async ({ expect }) => {
298
+ // Test with future date
299
+ const futureDate = new Date(Date.now() + 10);
300
+ const start = Date.now();
301
+ await waitUntil(futureDate);
302
+ const elapsed = Date.now() - start;
303
+ expect(elapsed).toBeGreaterThanOrEqual(5); // Allow some flexibility in timing
304
+
305
+ // Test with past date - this will throw because wait() requires non-negative time
306
+ // We need to verify it throws the correct error
307
+ try {
308
+ await waitUntil(new Date(Date.now() - 1000));
309
+ expect.fail("Should have thrown an error");
310
+ } catch (error) {
311
+ expect(error).toBeInstanceOf(HexclaveAssertionError);
312
+ expect((error as Error).message).toContain("wait() requires a non-negative integer");
313
+ }
314
+ });
315
+
316
+ export function runAsynchronouslyWithAlert(...args: Parameters<typeof runAsynchronously>) {
317
+ return runAsynchronously(
318
+ args[0],
319
+ {
320
+ ...args[1],
321
+ onError: error => {
322
+ const nodeEnv = getProcessEnv("NODE_ENV");
323
+ if (KnownError.isKnownError(error) && nodeEnv?.includes("production")) {
324
+ alert(error.message);
325
+ } else {
326
+ alert(`An unhandled error occurred. Please ${nodeEnv === "development" ? `check the browser console for the full error.` : "report this to the developer."}\n\n${error}`);
327
+ }
328
+ args[1]?.onError?.(error);
329
+ },
330
+ },
331
+ ...args.slice(2) as [],
332
+ );
333
+ }
334
+ import.meta.vitest?.test("runAsynchronouslyWithAlert", ({ expect }) => {
335
+ // Simple test to verify the function calls runAsynchronously
336
+ // We can't easily test the alert functionality without mocking
337
+ const testFn = () => Promise.resolve("test");
338
+ const testOptions = { noErrorLogging: true };
339
+
340
+ // Just verify it doesn't throw
341
+ expect(() => runAsynchronouslyWithAlert(testFn, testOptions)).not.toThrow();
342
+
343
+ // We can't easily test the error handling without mocking, so we'll
344
+ // just verify the function exists and can be called
345
+ expect(typeof runAsynchronouslyWithAlert).toBe("function");
346
+ });
347
+
348
+ export function runAsynchronously(
349
+ promiseOrFunc: void | Promise<unknown> | (() => void | Promise<unknown>) | undefined,
350
+ options: {
351
+ noErrorLogging?: boolean,
352
+ onError?: (error: Error) => void,
353
+ } = {},
354
+ ): void {
355
+ if (typeof promiseOrFunc === "function") {
356
+ promiseOrFunc = promiseOrFunc();
357
+ }
358
+ if (promiseOrFunc) {
359
+ concatStacktracesIfRejected(promiseOrFunc);
360
+ promiseOrFunc.catch(error => {
361
+ options.onError?.(error);
362
+ const newError = new HexclaveAssertionError(
363
+ "Uncaught error in asynchronous function: " + errorToNiceString(error),
364
+ { cause: error },
365
+ );
366
+ if (!options.noErrorLogging) {
367
+ captureError("runAsynchronously", newError);
368
+ }
369
+ });
370
+ }
371
+ }
372
+ import.meta.vitest?.test("runAsynchronously", ({ expect }) => {
373
+ // Simple test to verify the function exists and can be called
374
+ const testFn = () => Promise.resolve("test");
375
+
376
+ // Just verify it doesn't throw
377
+ expect(() => runAsynchronously(testFn)).not.toThrow();
378
+ expect(() => runAsynchronously(Promise.resolve("test"))).not.toThrow();
379
+ expect(() => runAsynchronously(undefined)).not.toThrow();
380
+
381
+ // We can't easily test the error handling without mocking, so we'll
382
+ // just verify the function exists and can be called with options
383
+ expect(() => runAsynchronously(testFn, { noErrorLogging: true })).not.toThrow();
384
+ expect(() => runAsynchronously(testFn, { onError: () => {} })).not.toThrow();
385
+ });
386
+
387
+
388
+ class TimeoutError extends Error {
389
+ constructor(public readonly ms: number) {
390
+ super(`Timeout after ${ms}ms`);
391
+ this.name = "TimeoutError";
392
+ }
393
+ }
394
+
395
+ export async function timeout<T>(promiseOrFunc: Promise<T> | (() => Promise<T>), ms: number): Promise<Result<T, TimeoutError>> {
396
+ const promise = typeof promiseOrFunc === "function" ? promiseOrFunc() : promiseOrFunc;
397
+ return await Promise.race([
398
+ promise.then(value => Result.ok(value)),
399
+ wait(ms).then(() => Result.error(new TimeoutError(ms))),
400
+ ]);
401
+ }
402
+ import.meta.vitest?.test("timeout", async ({ expect }) => {
403
+ // Test with a promise that resolves quickly
404
+ const fastPromise = Promise.resolve(42);
405
+ const fastResult = await timeout(fastPromise, 100);
406
+ expect(fastResult.status).toBe("ok");
407
+ if (fastResult.status === "ok") {
408
+ expect(fastResult.data).toBe(42);
409
+ }
410
+
411
+ // Test with a promise that takes longer than the timeout
412
+ const slowPromise = new Promise(resolve => setTimeout(() => resolve("too late"), 50));
413
+ const slowResult = await timeout(slowPromise, 10);
414
+ expect(slowResult.status).toBe("error");
415
+ if (slowResult.status === "error") {
416
+ expect(slowResult.error).toBeInstanceOf(TimeoutError);
417
+ expect((slowResult.error as TimeoutError).ms).toBe(10);
418
+ }
419
+ });
420
+
421
+ export async function timeoutThrow<T>(promise: Promise<T>, ms: number): Promise<T> {
422
+ return Result.orThrow(await timeout(promise, ms));
423
+ }
424
+ import.meta.vitest?.test("timeoutThrow", async ({ expect }) => {
425
+ // Test with a promise that resolves quickly
426
+ const fastPromise = Promise.resolve(42);
427
+ const fastResult = await timeoutThrow(fastPromise, 100);
428
+ expect(fastResult).toBe(42);
429
+
430
+ // Test with a promise that takes longer than the timeout
431
+ const slowPromise = new Promise(resolve => setTimeout(() => resolve("too late"), 50));
432
+ await expect(timeoutThrow(slowPromise, 10)).rejects.toThrow("Timeout after 10ms");
433
+ await expect(timeoutThrow(slowPromise, 10)).rejects.toBeInstanceOf(TimeoutError);
434
+ });
435
+
436
+
437
+ export type RateLimitOptions = {
438
+ /**
439
+ * The number of requests to process in parallel. Currently only 1 is supported.
440
+ */
441
+ concurrency: 1,
442
+
443
+ /**
444
+ * If true, multiple requests waiting at the same time will be reduced to just one. Default is false.
445
+ */
446
+ batchCalls?: boolean,
447
+
448
+ /**
449
+ * Waits for throttleMs since the start of last request before starting the next request. Default is 0.
450
+ */
451
+ throttleMs?: number,
452
+
453
+ /**
454
+ * Waits for gapMs since the end of last request before starting the next request. Default is 0.
455
+ */
456
+ gapMs?: number,
457
+
458
+ /**
459
+ * Waits until there have been no new requests for debounceMs before starting a new request. Default is 0.
460
+ */
461
+ debounceMs?: number,
462
+ };
463
+
464
+ export function rateLimited<T>(
465
+ func: () => Promise<T>,
466
+ options: RateLimitOptions,
467
+ ): () => Promise<T> {
468
+ let waitUntil = performance.now();
469
+ let queue: [(t: T) => void, (e: unknown) => void][] = [];
470
+ let addedToQueueCallbacks = new Map<string, () => void>;
471
+
472
+ const next = async () => {
473
+ while (true) {
474
+ if (waitUntil > performance.now()) {
475
+ await wait(Math.max(1, waitUntil - performance.now() + 1));
476
+ } else if (queue.length === 0) {
477
+ const uuid = generateUuid();
478
+ await new Promise<void>(resolve => {
479
+ addedToQueueCallbacks.set(uuid, resolve);
480
+ });
481
+ addedToQueueCallbacks.delete(uuid);
482
+ } else {
483
+ break;
484
+ }
485
+ }
486
+ const nextFuncs = options.batchCalls ? queue.splice(0, queue.length) : [queue.shift()!];
487
+
488
+ const start = performance.now();
489
+ const value = await Result.fromPromise(func());
490
+ const end = performance.now();
491
+
492
+ waitUntil = Math.max(
493
+ waitUntil,
494
+ start + (options.throttleMs ?? 0),
495
+ end + (options.gapMs ?? 0),
496
+ );
497
+
498
+ for (const nextFunc of nextFuncs) {
499
+ if (value.status === "ok") {
500
+ nextFunc[0](value.data);
501
+ } else {
502
+ nextFunc[1](value.error);
503
+ }
504
+ }
505
+ };
506
+
507
+ runAsynchronously(async () => {
508
+ while (true) {
509
+ await next();
510
+ }
511
+ });
512
+
513
+ return () => {
514
+ return new Promise<T>((resolve, reject) => {
515
+ waitUntil = Math.max(
516
+ waitUntil,
517
+ performance.now() + (options.debounceMs ?? 0),
518
+ );
519
+ queue.push([resolve, reject]);
520
+ addedToQueueCallbacks.forEach(cb => cb());
521
+ });
522
+ };
523
+ }
524
+
525
+ export function throttled<T, A extends any[]>(func: (...args: A) => Promise<T>, delayMs: number): (...args: A) => Promise<T> {
526
+ let timeout: ReturnType<typeof setTimeout> | null = null;
527
+ let nextAvailable: Promise<T> | null = null;
528
+ return async (...args) => {
529
+ while (nextAvailable !== null) {
530
+ await nextAvailable;
531
+ }
532
+ nextAvailable = new Promise<T>(resolve => {
533
+ timeout = setTimeout(() => {
534
+ nextAvailable = null;
535
+ resolve(func(...args));
536
+ }, delayMs);
537
+ });
538
+ return await nextAvailable;
539
+ };
540
+ }