@wasp.sh/wasp-cli-darwin-x64-unknown 0.25.0 → 0.26.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 (255) hide show
  1. package/data/Cli/starters/README.md +2 -0
  2. package/data/Cli/starters/basic/README.md +3 -3
  3. package/data/Cli/starters/basic/src/tags/components/CreateTagForm.tsx +2 -3
  4. package/data/Cli/starters/basic/vite.config.ts +0 -3
  5. package/data/Cli/starters/minimal/package.json +4 -1
  6. package/data/Cli/starters/minimal/vite.config.ts +0 -3
  7. package/data/Cli/starters/skeleton/AGENTS.md +6 -0
  8. package/data/Cli/starters/skeleton/CLAUDE.md +6 -0
  9. package/data/Cli/starters/skeleton/tsconfig.src.json +1 -11
  10. package/data/Generator/libs/auth/wasp.sh-lib-auth-0.26.0.tgz +0 -0
  11. package/data/Generator/libs/sdk-core/node_modules/@wasp.sh/lib-auth/wasp.sh-lib-auth-0.26.0.tgz +0 -0
  12. package/data/Generator/libs/sdk-core/wasp.sh-lib-sdk-core-0.26.0.tgz +0 -0
  13. package/data/Generator/libs/vite-ssr/{wasp.sh-lib-vite-ssr-0.25.0.tgz → wasp.sh-lib-vite-ssr-0.26.0.tgz} +0 -0
  14. package/data/Generator/templates/Dockerfile +1 -0
  15. package/data/Generator/templates/sdk/wasp/api/index.ts +5 -86
  16. package/data/Generator/templates/sdk/wasp/auth/email/actions/login.ts +2 -2
  17. package/data/Generator/templates/sdk/wasp/auth/email/actions/passwordReset.ts +1 -1
  18. package/data/Generator/templates/sdk/wasp/auth/email/actions/signup.ts +7 -6
  19. package/data/Generator/templates/sdk/wasp/auth/email/actions/verifyEmail.ts +1 -1
  20. package/data/Generator/templates/sdk/wasp/auth/forms/Auth.tsx +12 -6
  21. package/data/Generator/templates/sdk/wasp/auth/forms/ForgotPassword.tsx +2 -1
  22. package/data/Generator/templates/sdk/wasp/auth/forms/Login.tsx +2 -1
  23. package/data/Generator/templates/sdk/wasp/auth/forms/ResetPassword.tsx +2 -1
  24. package/data/Generator/templates/sdk/wasp/auth/forms/Signup.tsx +5 -5
  25. package/data/Generator/templates/sdk/wasp/auth/forms/VerifyEmail.tsx +2 -1
  26. package/data/Generator/templates/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx +34 -33
  27. package/data/Generator/templates/sdk/wasp/auth/forms/internal/email/DummyEmailSenderNotice.module.css +11 -0
  28. package/data/Generator/templates/sdk/wasp/auth/forms/internal/email/DummyEmailSenderNotice.tsx +17 -0
  29. package/data/Generator/templates/sdk/wasp/auth/forms/internal/email/ForgotPasswordForm.tsx +9 -13
  30. package/data/Generator/templates/sdk/wasp/auth/forms/internal/email/ResetPasswordForm.tsx +8 -9
  31. package/data/Generator/templates/sdk/wasp/auth/forms/internal/email/VerifyEmailForm.tsx +4 -8
  32. package/data/Generator/templates/sdk/wasp/auth/forms/internal/email/useEmail.ts +5 -5
  33. package/data/Generator/templates/sdk/wasp/auth/forms/internal/usernameAndPassword/useUsernameAndPassword.ts +6 -5
  34. package/data/Generator/templates/sdk/wasp/auth/forms/types.ts +0 -59
  35. package/data/Generator/templates/sdk/wasp/auth/helpers/_Provider.tsx +2 -2
  36. package/data/Generator/templates/sdk/wasp/auth/index.ts +1 -1
  37. package/data/Generator/templates/sdk/wasp/auth/logout.ts +1 -1
  38. package/data/Generator/templates/sdk/wasp/auth/providers/index.ts +4 -4
  39. package/data/Generator/templates/sdk/wasp/auth/providers/types.ts +20 -24
  40. package/data/Generator/templates/sdk/wasp/auth/useAuth.ts +5 -5
  41. package/data/Generator/templates/sdk/wasp/auth/user.ts +147 -14
  42. package/data/Generator/templates/sdk/wasp/auth/username/actions/login.ts +2 -2
  43. package/data/Generator/templates/sdk/wasp/auth/username/actions/signup.ts +6 -5
  44. package/data/Generator/templates/sdk/wasp/auth/validation.ts +1 -83
  45. package/data/Generator/templates/sdk/wasp/client/app/pages/OAuthCallback.tsx +8 -5
  46. package/data/Generator/templates/sdk/wasp/client/app/pages/createAuthRequiredPage.jsx +6 -4
  47. package/data/Generator/templates/sdk/wasp/client/app/router.tsx +2 -2
  48. package/data/Generator/templates/sdk/wasp/client/auth/ui.ts +2 -2
  49. package/data/Generator/templates/sdk/wasp/client/auth/username.ts +2 -2
  50. package/data/Generator/templates/sdk/wasp/client/config.ts +1 -6
  51. package/data/Generator/templates/sdk/wasp/client/crud/_crud.ts +129 -75
  52. package/data/Generator/templates/sdk/wasp/client/env/schema.ts +14 -7
  53. package/data/Generator/templates/sdk/wasp/client/env.ts +4 -3
  54. package/data/Generator/templates/sdk/wasp/client/index.ts +3 -12
  55. package/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts +14 -10
  56. package/data/Generator/templates/sdk/wasp/client/operations/actions/index.ts +7 -4
  57. package/data/Generator/templates/sdk/wasp/client/operations/index.ts +5 -5
  58. package/data/Generator/templates/sdk/wasp/client/operations/internal/index.ts +1 -8
  59. package/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +13 -55
  60. package/data/Generator/templates/sdk/wasp/client/operations/queries/index.ts +7 -7
  61. package/data/Generator/templates/sdk/wasp/client/router/Link.tsx +8 -8
  62. package/data/Generator/templates/sdk/wasp/client/router/NavLink.tsx +8 -8
  63. package/data/Generator/templates/sdk/wasp/client/router/index.ts +15 -15
  64. package/data/Generator/templates/sdk/wasp/client/test/index.ts +2 -1
  65. package/data/Generator/templates/sdk/wasp/client/test/vitest/helpers.tsx +5 -36
  66. package/data/Generator/templates/sdk/wasp/client/vite/index.ts +2 -1
  67. package/data/Generator/templates/sdk/wasp/client/vite/plugins/virtualUserModules.ts +43 -0
  68. package/data/Generator/templates/sdk/wasp/client/vite/plugins/{virtualModules.ts → virtualWaspModules.ts} +4 -4
  69. package/data/Generator/templates/sdk/wasp/client/vite/plugins/wasp.ts +17 -14
  70. package/data/Generator/templates/sdk/wasp/client/vite/plugins/waspConfig.ts +60 -18
  71. package/data/Generator/templates/sdk/wasp/client/vite/virtual-files/files/client-entry.tsx +1 -1
  72. package/data/Generator/templates/sdk/wasp/client/vite/virtual-files/files/routes.tsx +1 -1
  73. package/data/Generator/templates/sdk/wasp/client/vite/virtual-files/files/ssr-entry.tsx +1 -1
  74. package/data/Generator/templates/sdk/wasp/client/webSocket/WebSocketProvider.tsx +3 -3
  75. package/data/Generator/templates/sdk/wasp/client/webSocket/index.ts +1 -1
  76. package/data/Generator/templates/sdk/wasp/core/serialization/index.ts +2 -47
  77. package/data/Generator/templates/sdk/wasp/core/serialization/prisma.ts +0 -1
  78. package/data/Generator/templates/sdk/wasp/entities/index.ts +6 -6
  79. package/data/Generator/templates/sdk/wasp/env/index.ts +1 -9
  80. package/data/Generator/templates/sdk/wasp/package.json +150 -104
  81. package/data/Generator/templates/sdk/wasp/server/_types/index.ts +8 -10
  82. package/data/Generator/templates/sdk/wasp/server/_types/taggedEntities.ts +4 -4
  83. package/data/Generator/templates/sdk/wasp/server/api/index.ts +5 -5
  84. package/data/Generator/templates/sdk/wasp/server/auth/email/index.ts +2 -12
  85. package/data/Generator/templates/sdk/wasp/server/auth/email/utils.ts +8 -30
  86. package/data/Generator/templates/sdk/wasp/server/auth/hooks.ts +5 -2
  87. package/data/Generator/templates/sdk/wasp/server/auth/index.ts +3 -3
  88. package/data/Generator/templates/sdk/wasp/{auth → server/auth}/jwt.ts +1 -1
  89. package/data/Generator/templates/sdk/wasp/{auth → server/auth}/lucia.ts +4 -4
  90. package/data/Generator/templates/sdk/wasp/server/auth/oauth/oneTimeCode.ts +1 -1
  91. package/data/Generator/templates/sdk/wasp/server/auth/oauth/providers/discord.ts +1 -1
  92. package/data/Generator/templates/sdk/wasp/server/auth/oauth/providers/github.ts +1 -1
  93. package/data/Generator/templates/sdk/wasp/server/auth/oauth/providers/google.ts +1 -1
  94. package/data/Generator/templates/sdk/wasp/server/auth/oauth/providers/keycloak.ts +1 -1
  95. package/data/Generator/templates/sdk/wasp/server/auth/oauth/providers/microsoft.ts +1 -1
  96. package/data/Generator/templates/sdk/wasp/server/auth/oauth/providers/slack.ts +1 -1
  97. package/data/Generator/templates/sdk/wasp/{auth → server/auth}/session.ts +17 -6
  98. package/data/Generator/templates/sdk/wasp/{auth → server/auth}/utils.ts +40 -183
  99. package/data/Generator/templates/sdk/wasp/server/config.ts +1 -1
  100. package/data/Generator/templates/sdk/wasp/{core → server/core}/auth.ts +3 -3
  101. package/data/Generator/templates/sdk/wasp/server/crud/_operationTypes.ts +16 -63
  102. package/data/Generator/templates/sdk/wasp/server/dbClient.ts +15 -17
  103. package/data/Generator/templates/sdk/wasp/server/email/core/helpers.ts +3 -20
  104. package/data/Generator/templates/sdk/wasp/server/email/core/providers/dummy.ts +2 -2
  105. package/data/Generator/templates/sdk/wasp/server/email/core/providers/resend.ts +2 -1
  106. package/data/Generator/templates/sdk/wasp/server/email/core/providers/smtp.ts +2 -1
  107. package/data/Generator/templates/sdk/wasp/server/email/core/types.ts +2 -45
  108. package/data/Generator/templates/sdk/wasp/server/email/index.ts +1 -1
  109. package/data/Generator/templates/sdk/wasp/server/env.ts +20 -11
  110. package/data/Generator/templates/sdk/wasp/server/index.ts +3 -3
  111. package/data/Generator/templates/sdk/wasp/server/jobs/_job.ts +1 -1
  112. package/data/Generator/templates/sdk/wasp/server/jobs/core/pgBoss/index.ts +1 -1
  113. package/data/Generator/templates/sdk/wasp/server/jobs/core/pgBoss/pgBossJob.ts +4 -4
  114. package/data/Generator/templates/sdk/wasp/server/jobs/core/pgBoss/types.ts +1 -1
  115. package/data/Generator/templates/sdk/wasp/server/middleware/index.ts +1 -1
  116. package/data/Generator/templates/sdk/wasp/server/operations/actions/index.ts +14 -8
  117. package/data/Generator/templates/sdk/wasp/server/operations/actions/types.ts +5 -5
  118. package/data/Generator/templates/sdk/wasp/server/operations/queries/index.ts +14 -8
  119. package/data/Generator/templates/sdk/wasp/server/operations/queries/types.ts +5 -5
  120. package/data/Generator/templates/sdk/wasp/server/operations/wrappers.ts +40 -14
  121. package/data/Generator/templates/sdk/wasp/server/types/index.ts +1 -11
  122. package/data/Generator/templates/sdk/wasp/server/utils.ts +5 -20
  123. package/data/Generator/templates/sdk/wasp/server/webSocket/index.ts +7 -7
  124. package/data/Generator/templates/sdk/wasp/tsconfig.json +20 -46
  125. package/data/Generator/templates/sdk/wasp/types/index.ts +8 -0
  126. package/data/Generator/templates/sdk/wasp/types/register.ts +21 -0
  127. package/data/Generator/templates/sdk/wasp/vite-env.d.ts +0 -9
  128. package/data/Generator/templates/sdk/wasp/wasp-ssr.d.ts +8 -0
  129. package/data/Generator/templates/sdk/wasp/wasp-user-virtual-modules.d.ts +20 -0
  130. package/data/Generator/templates/server/package.json +2 -1
  131. package/data/Generator/templates/server/rollup.config.js +2 -43
  132. package/data/Generator/templates/server/rollup.dbSeed.config.js +3 -0
  133. package/data/Generator/templates/server/src/app.js +2 -2
  134. package/data/Generator/templates/server/src/auth/providers/config/email.ts +5 -5
  135. package/data/Generator/templates/server/src/auth/providers/email/login.ts +4 -4
  136. package/data/Generator/templates/server/src/auth/providers/email/requestPasswordReset.ts +4 -4
  137. package/data/Generator/templates/server/src/auth/providers/email/resetPassword.ts +13 -5
  138. package/data/Generator/templates/server/src/auth/providers/email/signup.ts +29 -18
  139. package/data/Generator/templates/server/src/auth/providers/email/verifyEmail.ts +7 -2
  140. package/data/Generator/templates/server/src/auth/providers/oauth/cookies.ts +5 -1
  141. package/data/Generator/templates/server/src/auth/providers/oauth/handler.ts +1 -1
  142. package/data/Generator/templates/server/src/auth/providers/oauth/oneTimeCode.ts +2 -2
  143. package/data/Generator/templates/server/src/auth/providers/oauth/state.ts +55 -13
  144. package/data/Generator/templates/server/src/auth/providers/oauth/user.ts +6 -3
  145. package/data/Generator/templates/server/src/auth/providers/username/login.ts +4 -4
  146. package/data/Generator/templates/server/src/auth/providers/username/signup.ts +12 -4
  147. package/data/Generator/templates/server/src/createRollupBundle.js +47 -0
  148. package/data/Generator/templates/server/src/crud/_operations.ts +16 -16
  149. package/data/Generator/templates/server/src/plugins/virtualUserModules.js +40 -0
  150. package/data/Generator/templates/server/src/routes/apis/index.ts +3 -3
  151. package/data/Generator/templates/server/src/routes/auth/index.js +1 -1
  152. package/data/Generator/templates/server/src/routes/auth/logout.ts +2 -2
  153. package/data/Generator/templates/server/src/routes/crud/_crud.ts +1 -1
  154. package/data/Generator/templates/server/src/routes/index.js +18 -18
  155. package/data/Generator/templates/server/src/routes/operations/index.js +1 -1
  156. package/data/Generator/templates/server/src/webSocket/initialization.ts +1 -1
  157. package/data/Generator/templates/server/tsconfig.json +7 -13
  158. package/data/Generator/templates/types/app/sdk/register.ts +57 -0
  159. package/data/packages/deploy/dist/common/cliVersion.js +17 -0
  160. package/data/packages/deploy/dist/common/waspProject.js +1 -1
  161. package/data/packages/deploy/dist/common/zx.js +24 -6
  162. package/data/packages/deploy/dist/providers/fly/commands/createDb/createDb.js +13 -5
  163. package/data/packages/deploy/dist/providers/fly/flyCli.js +29 -17
  164. package/data/packages/deploy/dist/providers/fly/index.js +16 -8
  165. package/data/packages/deploy/dist/providers/railway/commands/setup/setup.js +19 -31
  166. package/data/packages/deploy/dist/providers/railway/index.js +11 -2
  167. package/data/packages/deploy/dist/providers/railway/jsonOutputSchemas.js +19 -34
  168. package/data/packages/deploy/dist/providers/railway/railwayCli.js +11 -20
  169. package/data/packages/deploy/dist/providers/railway/railwayEnvironment/cli.js +20 -0
  170. package/data/packages/deploy/dist/providers/railway/railwayProject/RailwayProject.js +4 -1
  171. package/data/packages/deploy/dist/providers/railway/railwayProject/cli.js +6 -14
  172. package/data/packages/deploy/dist/providers/railway/railwayService/database.js +88 -0
  173. package/data/packages/deploy/dist/providers/railway/railwayService/deployment.js +12 -25
  174. package/data/packages/deploy/dist/providers/railway/railwayService/nameGenerator.js +5 -4
  175. package/data/packages/deploy/dist/providers/railway/railwayService/serviceInstance.js +48 -0
  176. package/data/packages/deploy/dist/providers/railway/railwayService/url.js +9 -30
  177. package/data/packages/deploy/package-lock.json +2 -2
  178. package/data/packages/deploy/package.json +1 -1
  179. package/data/packages/prisma/package-lock.json +2 -2
  180. package/data/packages/prisma/package.json +1 -1
  181. package/data/packages/spec/dist/__tests__/spec/mapApp.unit.test.js +19 -15
  182. package/data/packages/spec/dist/__tests__/spec/tsAppSpec.test-d.js +6 -0
  183. package/data/packages/spec/dist/src/appSpec.d.ts +15 -2
  184. package/data/packages/spec/dist/src/appSpec.d.ts.map +1 -1
  185. package/data/packages/spec/dist/src/spec/mapper/app.d.ts +1 -0
  186. package/data/packages/spec/dist/src/spec/mapper/app.d.ts.map +1 -1
  187. package/data/packages/spec/dist/src/spec/mapper/app.js +8 -2
  188. package/data/packages/spec/dist/src/spec/mapper/context.js +4 -4
  189. package/data/packages/spec/dist/src/spec/mapper/specElements.js +9 -9
  190. package/data/packages/spec/dist/src/spec/publicApi/constructors.d.ts +11 -11
  191. package/data/packages/spec/dist/src/spec/publicApi/constructors.js +11 -11
  192. package/data/packages/spec/dist/src/spec/publicApi/register.d.ts +1 -1
  193. package/data/packages/spec/dist/src/spec/publicApi/waspSpec.d.ts +58 -38
  194. package/data/packages/spec/dist/src/spec/publicApi/waspSpec.d.ts.map +1 -1
  195. package/data/packages/spec/package-lock.json +2 -2
  196. package/data/packages/spec/package.json +1 -1
  197. package/data/packages/studio/package-lock.json +15 -23
  198. package/data/packages/studio/package.json +2 -2
  199. package/package.json +1 -1
  200. package/wasp-bin +0 -0
  201. package/data/Generator/libs/auth/wasp.sh-lib-auth-0.25.0.tgz +0 -0
  202. package/data/Generator/templates/sdk/wasp/api/events.ts +0 -11
  203. package/data/Generator/templates/sdk/wasp/auth/email/index.ts +0 -5
  204. package/data/Generator/templates/sdk/wasp/auth/forms/internal/Form.module.css +0 -99
  205. package/data/Generator/templates/sdk/wasp/auth/forms/internal/Form.tsx +0 -74
  206. package/data/Generator/templates/sdk/wasp/auth/forms/internal/Message.module.css +0 -22
  207. package/data/Generator/templates/sdk/wasp/auth/forms/internal/Message.tsx +0 -34
  208. package/data/Generator/templates/sdk/wasp/auth/forms/internal/auth-styles.css +0 -30
  209. package/data/Generator/templates/sdk/wasp/auth/forms/internal/social/SocialButton.module.css +0 -33
  210. package/data/Generator/templates/sdk/wasp/auth/forms/internal/social/SocialButton.tsx +0 -14
  211. package/data/Generator/templates/sdk/wasp/auth/forms/internal/social/SocialIcons.module.css +0 -4
  212. package/data/Generator/templates/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx +0 -85
  213. package/data/Generator/templates/sdk/wasp/auth/forms/internal/util.ts +0 -16
  214. package/data/Generator/templates/sdk/wasp/auth/helpers/user.ts +0 -15
  215. package/data/Generator/templates/sdk/wasp/auth/responseSchemas.ts +0 -10
  216. package/data/Generator/templates/sdk/wasp/auth/types.ts +0 -2
  217. package/data/Generator/templates/sdk/wasp/auth/username/index.ts +0 -2
  218. package/data/Generator/templates/sdk/wasp/client/app/components/DefaultRootErrorBoundary.tsx +0 -16
  219. package/data/Generator/templates/sdk/wasp/client/app/components/FullPageWrapper.tsx +0 -21
  220. package/data/Generator/templates/sdk/wasp/client/app/components/Loader.module.css +0 -37
  221. package/data/Generator/templates/sdk/wasp/client/app/components/Loader.tsx +0 -12
  222. package/data/Generator/templates/sdk/wasp/client/app/components/Message.tsx +0 -86
  223. package/data/Generator/templates/sdk/wasp/client/crud/operationsHelpers.ts +0 -21
  224. package/data/Generator/templates/sdk/wasp/client/hooks.ts +0 -19
  225. package/data/Generator/templates/sdk/wasp/client/operations/hooks.ts +0 -347
  226. package/data/Generator/templates/sdk/wasp/client/operations/internal/resources.js +0 -85
  227. package/data/Generator/templates/sdk/wasp/client/operations/internal/updateHandlersMap.js +0 -37
  228. package/data/Generator/templates/sdk/wasp/client/operations/queryClient.ts +0 -34
  229. package/data/Generator/templates/sdk/wasp/client/operations/rpc.ts +0 -96
  230. package/data/Generator/templates/sdk/wasp/client/router/linkHelpers.ts +0 -48
  231. package/data/Generator/templates/sdk/wasp/client/router/types.ts +0 -98
  232. package/data/Generator/templates/sdk/wasp/client/vite/plugins/detectServerImports.ts +0 -50
  233. package/data/Generator/templates/sdk/wasp/client/vite/plugins/envFile.ts +0 -112
  234. package/data/Generator/templates/sdk/wasp/client/vite/plugins/typescriptCheck.ts +0 -36
  235. package/data/Generator/templates/sdk/wasp/client/vite/plugins/validateEnv.ts +0 -88
  236. package/data/Generator/templates/sdk/wasp/client/vite/virtual-files/resolver.ts +0 -35
  237. package/data/Generator/templates/sdk/wasp/core/serialization/custom-register.ts +0 -21
  238. package/data/Generator/templates/sdk/wasp/core/storage.ts +0 -73
  239. package/data/Generator/templates/sdk/wasp/env/validation.ts +0 -44
  240. package/data/Generator/templates/sdk/wasp/server/HttpError.ts +0 -30
  241. package/data/Generator/templates/sdk/wasp/server/auth/oauth/provider.ts +0 -20
  242. package/data/Generator/templates/sdk/wasp/server/auth/user.ts +0 -154
  243. package/data/Generator/templates/sdk/wasp/server/auth/username.ts +0 -1
  244. package/data/Generator/templates/sdk/wasp/server/jobs/core/job.ts +0 -28
  245. package/data/Generator/templates/sdk/wasp/server/middleware/globalMiddleware.ts +0 -8
  246. package/data/Generator/templates/sdk/wasp/universal/ansiColors.ts +0 -58
  247. package/data/Generator/templates/sdk/wasp/universal/predicates.ts +0 -3
  248. package/data/Generator/templates/sdk/wasp/universal/types.ts +0 -74
  249. package/data/Generator/templates/sdk/wasp/universal/url.ts +0 -9
  250. package/data/Generator/templates/sdk/wasp/universal/validators.ts +0 -21
  251. package/data/packages/ts-inspect/dist/exports.js +0 -82
  252. package/data/packages/ts-inspect/dist/index.js +0 -28
  253. package/data/packages/ts-inspect/package-lock.json +0 -4724
  254. package/data/packages/ts-inspect/package.json +0 -31
  255. /package/data/Generator/templates/sdk/wasp/{auth → server/auth}/password.ts +0 -0
@@ -1,347 +0,0 @@
1
- import {
2
- QueryClient,
3
- QueryKey,
4
- useMutation,
5
- UseMutationOptions,
6
- useQueryClient,
7
- useQuery as rqUseQuery,
8
- UseQueryResult,
9
- } from "@tanstack/react-query";
10
- import { Action, Query } from "./rpc";
11
- import { makeQueryCacheKey } from "./queries/core";
12
- export { configureQueryClient } from "./queryClient";
13
-
14
- // PUBLIC API
15
- export function useQuery<Input, Output>(
16
- query: Query<Input, Output>,
17
- queryFnArgs?: Input,
18
- options?: any
19
- ): UseQueryResult<Output, Error> {
20
- if (typeof query !== 'function') {
21
- throw new TypeError('useQuery requires queryFn to be a function.')
22
- }
23
-
24
- if (!query.queryCacheKey) {
25
- throw new TypeError('queryFn needs to have queryCacheKey property defined.')
26
- }
27
-
28
- return rqUseQuery({
29
- // todo: The full queryCacheKey is constructed in two places, both here and
30
- // inside the Query. See https://github.com/wasp-lang/wasp/issues/2017
31
- // FIXME: query fns don't handle the `undefined` case correctly
32
- // https://github.com/wasp-lang/wasp/issues/2017
33
- queryKey: makeQueryCacheKey(query, (queryFnArgs as Input)),
34
- // FIXME: query fns don't handle the `undefined` case correctly
35
- // https://github.com/wasp-lang/wasp/issues/2017
36
- queryFn: () => query(queryFnArgs as Input),
37
- ...options,
38
- })
39
- }
40
-
41
- // PUBLIC API
42
- /**
43
- * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates).
44
- *
45
- * @param actionFn The Wasp Action you wish to enhance/decorate.
46
- * @param actionOptions An options object for enhancing/decorating the given Action.
47
- * @returns A decorated Action with added behavior but an unchanged API.
48
- */
49
- export function useAction<Input = unknown, Output = unknown>(
50
- actionFn: Action<Input, Output>,
51
- actionOptions?: ActionOptions<Input>
52
- ): typeof actionFn {
53
- const queryClient = useQueryClient();
54
-
55
- let mutationFn = actionFn;
56
- let options = {};
57
- if (actionOptions?.optimisticUpdates) {
58
- const optimisticUpdatesDefinitions = actionOptions.optimisticUpdates.map(
59
- translateToInternalDefinition
60
- );
61
- mutationFn = makeOptimisticUpdateMutationFn(
62
- actionFn,
63
- optimisticUpdatesDefinitions
64
- );
65
- options = makeRqOptimisticUpdateOptions(
66
- queryClient,
67
- optimisticUpdatesDefinitions
68
- );
69
- }
70
-
71
- // NOTE: We decided to hide React Query's extra mutation features (e.g.,
72
- // isLoading, onSuccess and onError callbacks, synchronous mutate) and only
73
- // expose a simple async function whose API matches the original Action.
74
- // We did this to avoid cluttering the API with stuff we're not sure we need
75
- // yet (e.g., isLoading), to postpone the action vs mutation dilemma, and to
76
- // clearly separate our opinionated API from React Query's lower-level
77
- // advanced API (which users can also use)
78
- const mutation = useMutation(mutationFn, options);
79
-
80
- // This assertion is necessary because, when the Input is void, we want to
81
- // present the function as not accepting a payload (which isn't consistent
82
- // with how it's defined).
83
- return ((args: Input) => mutation.mutateAsync(args)) as typeof actionFn;
84
- }
85
-
86
- // PUBLIC API
87
- // todo: Improve this type. Details here:
88
- // https://github.com/wasp-lang/wasp/issues/2017
89
- /**
90
- * A documented (public) way to define optimistic updates.
91
- */
92
- export type OptimisticUpdateDefinition<ActionInput, CachedData> = {
93
- getQuerySpecifier: GetQuerySpecifier<ActionInput, CachedData>;
94
- updateQuery: UpdateQuery<ActionInput, CachedData>;
95
- };
96
-
97
- /**
98
- * An options object passed into the `useAction` hook and used to enhance the
99
- * action with extra options.
100
- *
101
- */
102
- type ActionOptions<ActionInput> = {
103
- optimisticUpdates: OptimisticUpdateDefinition<ActionInput, any>[];
104
- };
105
-
106
- /**
107
- * A function that takes an item and returns a Wasp Query specifier.
108
- */
109
- type GetQuerySpecifier<ActionInput, CachedData> = (
110
- item: ActionInput
111
- ) => QuerySpecifier<unknown, CachedData>;
112
-
113
- // todo: Improve the type's signature for when the cache is empty. Details here:
114
- // https://github.com/wasp-lang/wasp/issues/2017
115
- /**
116
- * A function that takes an item and the previous state of the cache, and returns
117
- * the desired (new) state of the cache.
118
- */
119
- type UpdateQuery<ActionInput, CachedData> = (
120
- item: ActionInput,
121
- oldData: CachedData | undefined
122
- ) => CachedData;
123
-
124
- // todo: Improve this type signature. Details here:
125
- // https://github.com/wasp-lang/wasp/issues/2017
126
- /**
127
- * A public query specifier used for addressing Wasp queries. See our docs for details:
128
- * https://wasp.sh/docs/language/features#the-useaction-hook.
129
- */
130
- type QuerySpecifier<Input, Output> = [Query<Input, Output>, ...any[]];
131
-
132
- /**
133
- * An internal (undocumented, private, desugared) way of defining optimistic updates.
134
- */
135
- type InternalOptimisticUpdateDefinition<ActionInput, CachedData> = {
136
- getQueryKey: (item: ActionInput) => QueryKey;
137
- updateQuery: UpdateQuery<ActionInput, CachedData>;
138
- };
139
-
140
- /**
141
- * An UpdateQuery function "instantiated" with a specific item. It only takes
142
- * the current state of the cache and returns the desired (new) state of the
143
- * cache.
144
- */
145
- type SpecificUpdateQuery<CachedData> = (oldData: CachedData | undefined) => CachedData;
146
-
147
- /**
148
- * A specific, "instantiated" optimistic update definition which contains a
149
- * fully-constructed query key and a specific update function.
150
- */
151
- type SpecificOptimisticUpdateDefinition<Item> = {
152
- queryKey: QueryKey;
153
- updateQuery: SpecificUpdateQuery<Item>;
154
- };
155
-
156
- type InternalAction<Input, Output> = Action<Input, Output> & {
157
- internal<CachedData extends unknown>(
158
- item: Input,
159
- optimisticUpdateDefinitions: SpecificOptimisticUpdateDefinition<CachedData>[]
160
- ): Promise<Output>;
161
- };
162
-
163
- /**
164
- * Translates/Desugars a public optimistic update definition object into a
165
- * definition object our system uses internally.
166
- *
167
- * @param publicOptimisticUpdateDefinition An optimistic update definition
168
- * object that's a part of the public API:
169
- * https://wasp.sh/docs/language/features#the-useaction-hook.
170
- * @returns An internally-used optimistic update definition object.
171
- */
172
- function translateToInternalDefinition<Item, CachedData>(
173
- publicOptimisticUpdateDefinition: OptimisticUpdateDefinition<Item, CachedData>
174
- ): InternalOptimisticUpdateDefinition<Item, CachedData> {
175
- const { getQuerySpecifier, updateQuery } = publicOptimisticUpdateDefinition;
176
-
177
- const definitionErrors: string[] = [];
178
- if (typeof getQuerySpecifier !== "function") {
179
- definitionErrors.push("`getQuerySpecifier` is not a function.");
180
- }
181
- if (typeof updateQuery !== "function") {
182
- definitionErrors.push("`updateQuery` is not a function.");
183
- }
184
- if (definitionErrors.length) {
185
- throw new TypeError(
186
- `Invalid optimistic update definition: ${definitionErrors.join(", ")}.`
187
- );
188
- }
189
-
190
- return {
191
- getQueryKey: (item) => getRqQueryKeyFromSpecifier(getQuerySpecifier(item)),
192
- updateQuery,
193
- };
194
- }
195
-
196
- /**
197
- * Creates a function that performs an action while telling it about the
198
- * optimistic updates it caused.
199
- *
200
- * @param actionFn The Wasp Action.
201
- * @param optimisticUpdateDefinitions The optimisitc updates the action causes.
202
- * @returns An decorated action which performs optimistic updates.
203
- */
204
- function makeOptimisticUpdateMutationFn<Input, Output, CachedData>(
205
- actionFn: Action<Input, Output>,
206
- optimisticUpdateDefinitions: InternalOptimisticUpdateDefinition<
207
- Input,
208
- CachedData
209
- >[]
210
- ): typeof actionFn {
211
- return (function performActionWithOptimisticUpdates(item: Input) {
212
- const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map(
213
- (generalDefinition) =>
214
- getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item)
215
- );
216
- return (actionFn as InternalAction<Input, Output>).internal(
217
- item,
218
- specificOptimisticUpdateDefinitions
219
- );
220
- // This assertion is necessary because, when the Input is void, we want to
221
- // present the function as not accepting a payload (which isn't consistent
222
- // with how it's defined).
223
- }) as typeof actionFn;
224
- }
225
-
226
- /**
227
- * Given a ReactQuery query client and our internal definition of optimistic
228
- * updates, this function constructs an object describing those same optimistic
229
- * updates in a format we can pass into React Query's useMutation hook. In other
230
- * words, it translates our optimistic updates definition into React Query's
231
- * optimistic updates definition. Check their docs for details:
232
- * https://tanstack.com/query/v4/docs/guides/optimistic-updates?from=reactQueryV3&original=https://react-query-v3.tanstack.com/guides/optimistic-updates
233
- *
234
- * @param queryClient The QueryClient instance used by React Query.
235
- * @param optimisticUpdateDefinitions A list containing internal optimistic
236
- * updates definition objects (i.e., a list where each object carries the
237
- * instructions for performing particular optimistic update).
238
- * @returns An object containing 'onMutate' and 'onError' functions
239
- * corresponding to the given optimistic update definitions (check the docs
240
- * linked above for details).
241
- */
242
- function makeRqOptimisticUpdateOptions<ActionInput, CachedData>(
243
- queryClient: QueryClient,
244
- optimisticUpdateDefinitions: InternalOptimisticUpdateDefinition<
245
- ActionInput,
246
- CachedData
247
- >[]
248
- ): Pick<UseMutationOptions, "onMutate" | "onError"> {
249
- async function onMutate(item) {
250
- const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map(
251
- (generalDefinition) =>
252
- getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item)
253
- );
254
-
255
- // Cancel any outgoing refetches (so they don't overwrite our optimistic update).
256
- // Theoretically, we can be a bit faster. Instead of awaiting the
257
- // cancellation of all queries, we could cancel and update them in parallel.
258
- // However, awaiting cancellation hasn't yet proven to be a performance bottleneck.
259
- await Promise.all(
260
- specificOptimisticUpdateDefinitions.map(({ queryKey }) =>
261
- queryClient.cancelQueries(queryKey)
262
- )
263
- );
264
-
265
- // We're using a Map to correctly serialize query keys that contain objects.
266
- const previousData: Map<QueryKey, CachedData | undefined> = new Map();
267
- specificOptimisticUpdateDefinitions.forEach(({ queryKey, updateQuery }) => {
268
- // Snapshot the currently cached value.
269
- const previousDataForQuery: CachedData | undefined =
270
- queryClient.getQueryData(queryKey);
271
-
272
- // Attempt to optimistically update the cache using the new value.
273
- try {
274
- queryClient.setQueryData(queryKey, updateQuery);
275
- } catch (e) {
276
- console.error(
277
- "The `updateQuery` function threw an exception, skipping optimistic update:"
278
- );
279
- console.error(e);
280
- }
281
-
282
- // Remember the snapshotted value to restore in case of an error.
283
- previousData.set(queryKey, previousDataForQuery);
284
- });
285
-
286
- return { previousData };
287
- }
288
-
289
- function onError(_err, _item, context) {
290
- // All we do in case of an error is roll back all optimistic updates. We ensure
291
- // not to do anything else because React Query rethrows the error. This allows
292
- // the programmer to handle the error as they usually would (i.e., we want the
293
- // error handling to work as it would if the programmer wasn't using optimistic
294
- // updates).
295
- context.previousData.forEach(async (data, queryKey) => {
296
- await queryClient.cancelQueries(queryKey);
297
- queryClient.setQueryData(queryKey, data);
298
- });
299
- }
300
-
301
- return {
302
- onMutate,
303
- onError,
304
- };
305
- }
306
-
307
- /**
308
- * Constructs the definition for optimistically updating a specific item. It
309
- * uses a closure over the updated item to construct an item-specific query key
310
- * (e.g., useful when the query key depends on an ID).
311
- *
312
- * @param optimisticUpdateDefinition The general, "uninstantiated" optimistic
313
- * update definition with a function for constructing the query key.
314
- * @param item The item triggering the Action/optimistic update (i.e., the
315
- * argument passed to the Action).
316
- * @returns A specific optimistic update definition which corresponds to the
317
- * provided definition and closes over the provided item.
318
- */
319
- function getOptimisticUpdateDefinitionForSpecificItem<ActionInput, CachedData>(
320
- optimisticUpdateDefinition: InternalOptimisticUpdateDefinition<
321
- ActionInput,
322
- CachedData
323
- >,
324
- item: ActionInput
325
- ): SpecificOptimisticUpdateDefinition<CachedData> {
326
- const { getQueryKey, updateQuery } = optimisticUpdateDefinition;
327
- return {
328
- queryKey: getQueryKey(item),
329
- updateQuery: (old) => updateQuery(item, old),
330
- };
331
- }
332
-
333
- // todo: Address the duplication between this function and the one in
334
- // queries/core.ts. Details here: https://github.com/wasp-lang/wasp/issues/2017
335
- /**
336
- * Translates a Wasp query specifier to a query cache key used by React Query.
337
- *
338
- * @param querySpecifier A query specifier that's a part of the public API:
339
- * https://wasp.sh/docs/language/features#the-useaction-hook.
340
- * @returns A cache key React Query internally uses for addressing queries.
341
- */
342
- function getRqQueryKeyFromSpecifier(
343
- querySpecifier: QuerySpecifier<unknown, unknown>
344
- ): QueryKey {
345
- const [queryFn, ...otherKeys] = querySpecifier;
346
- return [...(queryFn as any).queryCacheKey, ...otherKeys];
347
- }
@@ -1,85 +0,0 @@
1
- import { queryClientInitialized } from '../queryClient.js'
2
- import { makeUpdateHandlersMap } from './updateHandlersMap'
3
- import { hashQueryKey } from '@tanstack/react-query'
4
-
5
- // Map where key is resource name and value is Set
6
- // containing query ids of all the queries that use
7
- // that resource.
8
- const resourceToQueryCacheKeys = new Map()
9
-
10
- const updateHandlers = makeUpdateHandlersMap(hashQueryKey)
11
-
12
- // PRIVATE API
13
- /**
14
- * Remembers that specified query is using specified resources.
15
- * If called multiple times for same query, resources are added, not reset.
16
- * @param {string[]} queryCacheKey - Unique key under used to identify query in the cache.
17
- * @param {string[]} resources - Names of resources that query is using.
18
- */
19
- export function addResourcesUsedByQuery(queryCacheKey, resources) {
20
- for (const resource of resources) {
21
- let cacheKeys = resourceToQueryCacheKeys.get(resource)
22
- if (!cacheKeys) {
23
- cacheKeys = new Set()
24
- resourceToQueryCacheKeys.set(resource, cacheKeys)
25
- }
26
- cacheKeys.add(queryCacheKey)
27
- }
28
- }
29
-
30
- export function registerActionInProgress(optimisticUpdateTuples) {
31
- optimisticUpdateTuples.forEach(
32
- ({ queryKey, updateQuery }) => updateHandlers.add(queryKey, updateQuery)
33
- )
34
- }
35
-
36
- export async function registerActionDone(resources, optimisticUpdateTuples) {
37
- optimisticUpdateTuples.forEach(({ queryKey }) => updateHandlers.remove(queryKey))
38
- await invalidateQueriesUsing(resources)
39
- }
40
-
41
- export function getActiveOptimisticUpdates(queryKey) {
42
- return updateHandlers.getUpdateHandlers(queryKey)
43
- }
44
-
45
- export async function invalidateAndRemoveQueries() {
46
- const queryClient = await queryClientInitialized
47
- // If we don't reset the queries before removing them, Wasp will stay on
48
- // the same page. The user would have to manually refresh the page to "finish"
49
- // logging out.
50
- // When a query is removed, the `Observer` is removed as well, and the components
51
- // that are using the query are not re-rendered. This is why we need to reset
52
- // the queries, so that the `Observer` is re-created and the components are re-rendered.
53
- // For more details: https://github.com/wasp-lang/wasp/pull/1014/files#r1111862125
54
- queryClient.resetQueries()
55
- // If we don't remove the queries after invalidating them, the old query data
56
- // remains in the cache, casuing a potential privacy issue.
57
- queryClient.removeQueries()
58
- }
59
-
60
- /**
61
- * Invalidates all queries that are using specified resources.
62
- * @param {string[]} resources - Names of resources.
63
- */
64
- async function invalidateQueriesUsing(resources) {
65
- const queryClient = await queryClientInitialized
66
-
67
- const queryCacheKeysToInvalidate = getQueriesUsingResources(resources)
68
- await Promise.all(
69
- queryCacheKeysToInvalidate.map(
70
- queryCacheKey => queryClient.invalidateQueries(queryCacheKey)
71
- )
72
- )
73
- }
74
-
75
- /**
76
- * @param {string} resource - Resource name.
77
- * @returns {string[]} Array of "query cache keys" of queries that use specified resource.
78
- */
79
- function getQueriesUsingResource(resource) {
80
- return Array.from(resourceToQueryCacheKeys.get(resource) || [])
81
- }
82
-
83
- function getQueriesUsingResources(resources) {
84
- return Array.from(new Set(resources.flatMap(getQueriesUsingResource)))
85
- }
@@ -1,37 +0,0 @@
1
- export function makeUpdateHandlersMap(calculateHash) {
2
- const updateHandlers = new Map()
3
-
4
- function getHandlerTuples(queryKeyHash) {
5
- return updateHandlers.get(queryKeyHash) || [];
6
- }
7
-
8
- function add(queryKey, updateQuery) {
9
- const queryKeyHash = calculateHash(queryKey)
10
- const handlers = getHandlerTuples(queryKeyHash);
11
- updateHandlers.set(queryKeyHash, [...handlers, { queryKey, updateQuery }])
12
- }
13
-
14
- function getUpdateHandlers(queryKey) {
15
- const queryKeyHash = calculateHash(queryKey)
16
- return getHandlerTuples(queryKeyHash).map(({ updateQuery }) => updateQuery)
17
- }
18
-
19
- function remove(queryKeyToRemove) {
20
- const queryKeyHash = calculateHash(queryKeyToRemove)
21
- const filteredHandlers = getHandlerTuples(queryKeyHash).filter(
22
- ({ queryKey }) => queryKey !== queryKeyToRemove
23
- )
24
-
25
- if (filteredHandlers.length > 0) {
26
- updateHandlers.set(queryKeyHash, filteredHandlers)
27
- } else {
28
- updateHandlers.delete(queryKeyHash)
29
- }
30
- }
31
-
32
- return {
33
- add,
34
- remove,
35
- getUpdateHandlers,
36
- }
37
- }
@@ -1,34 +0,0 @@
1
- import { QueryClient, QueryClientConfig } from '@tanstack/react-query'
2
-
3
- const defaultQueryClientConfig = {};
4
-
5
- let queryClientConfig: QueryClientConfig,
6
- resolveQueryClientInitialized: (...args: any[]) => any,
7
- isQueryClientInitialized: boolean;
8
-
9
- // PRIVATE API (framework code)
10
- export const queryClientInitialized: Promise<QueryClient> = new Promise(
11
- (resolve) => {
12
- resolveQueryClientInitialized = resolve;
13
- }
14
- );
15
-
16
- // PUBLIC API
17
- export function configureQueryClient(config: QueryClientConfig): void {
18
- if (isQueryClientInitialized) {
19
- throw new Error(
20
- "Attempted to configure the QueryClient after initialization"
21
- );
22
- }
23
-
24
- queryClientConfig = config;
25
- }
26
-
27
- // PRIVATE API (framework code)
28
- export function initializeQueryClient(): void {
29
- const queryClient = new QueryClient(
30
- queryClientConfig ?? defaultQueryClientConfig
31
- );
32
- isQueryClientInitialized = true;
33
- resolveQueryClientInitialized(queryClient);
34
- }
@@ -1,96 +0,0 @@
1
- import { type Route } from "../index.js";
2
- import type {
3
- IfAny,
4
- _Awaited,
5
- _ReturnType,
6
- } from "../../universal/types.js"
7
-
8
- // PRIVATE API (for SDK, should maybe be public, users define values of this
9
- // type).
10
- //
11
- // Frontend queries are functions with some extra properties (metadata).
12
- //
13
- // To simplify working with the type (i.e., referencing the type's two different
14
- // components), we've defined it as an intersection of two distinct types:
15
- // one representing the function (QueryFunction), and the other representing the
16
- // metadata (QueryMetadata) .
17
- /**
18
- * The client Query object type. It's a callable Query function with some extra
19
- * properties (metadata).
20
- */
21
- export type Query<Input, Output> = QueryFunction<Input, Output> & QueryMetadata
22
-
23
- // PRIVATE API (for SDK, should maybe be public, users define values of this
24
- // type)
25
- /**
26
- * The client Action object type (unlike a Query, it's just a normal function).
27
- */
28
- export type Action<Input, Output> = ClientOperation<Input, Output>
29
-
30
- // PRIVATE API (for SDK)
31
- /**
32
- * The client Query function type.
33
- */
34
- export type QueryFunction<Input, Output> = ClientOperation<Input, Output>
35
-
36
- // PRIVATE API (for SDK)
37
- // todo: revisit what we expose. Also, queryCacheKey is confusing and
38
- // incorrect.Details here: https://github.com/wasp-lang/wasp/issues/2017
39
- /**
40
- * All extra properties (metadata) found on a Query object type.
41
- */
42
- export type QueryMetadata = {
43
- queryCacheKey: string[]
44
- route: Route
45
- }
46
-
47
- // PRIVATE API (needed in SDK)
48
- // Explanation:
49
- // - Custom `_Awaited` and `_ReturnType` - Read the comments above their
50
- // definitions.
51
- // - `Parameters<BackendOperation> extends []` - See here:
52
- // https://github.com/wasp-lang/wasp/pull/1992/files#r1583040080
53
- /**
54
- * Constructs the client RPC function type from the type of the operation's
55
- * definition on the backend.
56
- */
57
- export type OperationRpcFor<BackendOperation extends GenericBackendOperation> =
58
- Parameters<BackendOperation> extends []
59
- ? ClientOperation<void, _Awaited<_ReturnType<BackendOperation>>>
60
- : ClientOperation<
61
- Parameters<BackendOperation>[0],
62
- _Awaited<_ReturnType<BackendOperation>>
63
- >
64
-
65
- // PRIVATE API (needed in SDK)
66
- /**
67
- * A supertype of all possible backend operation definitions (i.e., Queries and
68
- * Actions)
69
- */
70
- export type GenericBackendOperation = (args: never, context: any) => unknown
71
-
72
- // PRIVATE API (needed in SDK)
73
- /**
74
- * A supertype of all possible frontend RPC function types.
75
- */
76
- export type GenericOperationRpc = (args: never) => Promise<unknown>
77
-
78
- // NOTE: There's some duplication in the below types.
79
- // Read the discussion here to understand why before trying to remove it:
80
- // https://github.com/wasp-lang/wasp/pull/2170#discussion_r1671285049
81
- //
82
- // Read this to understand the type: https://github.com/wasp-lang/wasp/pull/2170#issue-2398830273
83
- type ClientOperation<Input, Output> =
84
- IfAny<
85
- Input,
86
- (args?: any) => Promise<Output>,
87
- ClientOperationWithNonAnyInput<Input, Output>
88
- >
89
-
90
- // Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471
91
- type ClientOperationWithNonAnyInput<Input, Output> =
92
- [Input] extends [never]
93
- ? (args?: unknown) => Promise<Output>
94
- : [Input] extends [void]
95
- ? () => Promise<Output>
96
- : (args: Input) => Promise<Output>
@@ -1,48 +0,0 @@
1
- import type { Params, Search } from "./types";
2
-
3
- // PRIVATE API
4
- export function interpolatePath(
5
- path: string,
6
- params?: Params,
7
- search?: Search,
8
- hash?: string
9
- ) {
10
- const interpolatedPath = params ? interpolatePathParams(path, params) : path
11
- const interpolatedSearch = search
12
- ? `?${new URLSearchParams(search).toString()}`
13
- : ''
14
- const interpolatedHash = hash ? `#${hash}` : ''
15
- return interpolatedPath + interpolatedSearch + interpolatedHash
16
- }
17
-
18
- function interpolatePathParams(path: string, params: Params) {
19
- function mapPathPart(part: string) {
20
- if (part === '*') {
21
- return params['*'];
22
- }
23
- if (part.startsWith(":")) {
24
- const paramName = extractParamNameFromPathPart(part);
25
- return params[paramName];
26
- }
27
- return part;
28
- }
29
-
30
- const interpolatedPath = path
31
- .split("/")
32
- .map(mapPathPart)
33
- .filter(isValidPathPart)
34
- .join("/");
35
-
36
- return path.startsWith("/") ? `/${interpolatedPath}` : interpolatedPath;
37
- }
38
-
39
- function isValidPathPart(part: any): boolean {
40
- return !!part;
41
- }
42
-
43
- function extractParamNameFromPathPart(paramString: string) {
44
- if (paramString.endsWith("?")) {
45
- return paramString.slice(1, -1);
46
- }
47
- return paramString.slice(1);
48
- }