@lupinum/better-convex-nuxt 0.8.0-beta.40

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 (268) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSES/Apache-2.0.txt +201 -0
  3. package/README.md +151 -0
  4. package/THIRD_PARTY_NOTICES.md +38 -0
  5. package/dist/module.d.mts +55 -0
  6. package/dist/module.json +12 -0
  7. package/dist/module.mjs +309 -0
  8. package/dist/runtime/auth/auth-identity.d.ts +31 -0
  9. package/dist/runtime/auth/auth-identity.js +21 -0
  10. package/dist/runtime/auth/better-auth-browser-adapter.d.ts +33 -0
  11. package/dist/runtime/auth/better-auth-browser-adapter.js +215 -0
  12. package/dist/runtime/auth/client-engine-types.d.ts +4 -0
  13. package/dist/runtime/auth/client-engine-types.js +0 -0
  14. package/dist/runtime/auth/integrated-client.d.ts +25 -0
  15. package/dist/runtime/auth/integrated-client.js +132 -0
  16. package/dist/runtime/auth/operation-tracker.d.ts +7 -0
  17. package/dist/runtime/auth/operation-tracker.js +14 -0
  18. package/dist/runtime/auth/session-synchronization.d.ts +23 -0
  19. package/dist/runtime/auth/session-synchronization.js +156 -0
  20. package/dist/runtime/auth/token-fetcher.d.ts +66 -0
  21. package/dist/runtime/auth/token-fetcher.js +131 -0
  22. package/dist/runtime/auth/validate-auth-client-definition.d.ts +12 -0
  23. package/dist/runtime/auth/validate-auth-client-definition.js +47 -0
  24. package/dist/runtime/auth-client/convex-client-plugin.d.ts +31 -0
  25. package/dist/runtime/auth-client/convex-client-plugin.js +14 -0
  26. package/dist/runtime/auth-client/definition-types.d.ts +6 -0
  27. package/dist/runtime/auth-client/definition-types.js +0 -0
  28. package/dist/runtime/auth-client/empty-definition.d.ts +2 -0
  29. package/dist/runtime/auth-client/empty-definition.js +2 -0
  30. package/dist/runtime/auth-client/index.d.ts +71 -0
  31. package/dist/runtime/auth-client/index.js +3 -0
  32. package/dist/runtime/cli/auth-schema.d.ts +2 -0
  33. package/dist/runtime/cli/auth-schema.js +169 -0
  34. package/dist/runtime/cli/convex.d.ts +11 -0
  35. package/dist/runtime/cli/convex.js +274 -0
  36. package/dist/runtime/composables/useConvex.d.ts +4 -0
  37. package/dist/runtime/composables/useConvex.js +9 -0
  38. package/dist/runtime/composables/useConvexAction.d.ts +4 -0
  39. package/dist/runtime/composables/useConvexAction.js +18 -0
  40. package/dist/runtime/composables/useConvexAttachment.d.ts +9 -0
  41. package/dist/runtime/composables/useConvexAttachment.js +14 -0
  42. package/dist/runtime/composables/useConvexAuth.d.ts +10 -0
  43. package/dist/runtime/composables/useConvexAuth.js +37 -0
  44. package/dist/runtime/composables/useConvexConfig.d.ts +12 -0
  45. package/dist/runtime/composables/useConvexConfig.js +7 -0
  46. package/dist/runtime/composables/useConvexConnectionState.d.ts +33 -0
  47. package/dist/runtime/composables/useConvexConnectionState.js +24 -0
  48. package/dist/runtime/composables/useConvexFileUpload.d.ts +169 -0
  49. package/dist/runtime/composables/useConvexFileUpload.js +198 -0
  50. package/dist/runtime/composables/useConvexMutation.d.ts +13 -0
  51. package/dist/runtime/composables/useConvexMutation.js +24 -0
  52. package/dist/runtime/composables/useConvexPaginatedQuery.d.ts +13 -0
  53. package/dist/runtime/composables/useConvexPaginatedQuery.js +256 -0
  54. package/dist/runtime/composables/useConvexQuery.d.ts +19 -0
  55. package/dist/runtime/composables/useConvexQuery.js +308 -0
  56. package/dist/runtime/convex-auth/adapter/create-adapter.d.ts +33 -0
  57. package/dist/runtime/convex-auth/adapter/create-adapter.js +308 -0
  58. package/dist/runtime/convex-auth/adapter/define-functions.d.ts +160 -0
  59. package/dist/runtime/convex-auth/adapter/define-functions.js +497 -0
  60. package/dist/runtime/convex-auth/adapter/generate-schema.d.ts +16 -0
  61. package/dist/runtime/convex-auth/adapter/generate-schema.js +332 -0
  62. package/dist/runtime/convex-auth/adapter/metadata.d.ts +44 -0
  63. package/dist/runtime/convex-auth/adapter/metadata.js +91 -0
  64. package/dist/runtime/convex-auth/adapter/query.d.ts +32 -0
  65. package/dist/runtime/convex-auth/adapter/query.js +275 -0
  66. package/dist/runtime/convex-auth/adapter/relationships.d.ts +20 -0
  67. package/dist/runtime/convex-auth/adapter/relationships.js +128 -0
  68. package/dist/runtime/convex-auth/component/_generated/api.js +5 -0
  69. package/dist/runtime/convex-auth/component/_generated/component.d.ts +116 -0
  70. package/dist/runtime/convex-auth/component/_generated/component.js +0 -0
  71. package/dist/runtime/convex-auth/component/_generated/dataModel.js +0 -0
  72. package/dist/runtime/convex-auth/component/_generated/server.js +16 -0
  73. package/dist/runtime/convex-auth/component/adapter.d.ts +142 -0
  74. package/dist/runtime/convex-auth/component/adapter.js +16 -0
  75. package/dist/runtime/convex-auth/component/convex.config.d.ts +2 -0
  76. package/dist/runtime/convex-auth/component/convex.config.js +3 -0
  77. package/dist/runtime/convex-auth/component/schema.d.ts +799 -0
  78. package/dist/runtime/convex-auth/component/schema.js +180 -0
  79. package/dist/runtime/convex-auth/component/schemaMetadata.d.ts +2094 -0
  80. package/dist/runtime/convex-auth/component/schemaMetadata.js +2161 -0
  81. package/dist/runtime/convex-auth/context.d.ts +5 -0
  82. package/dist/runtime/convex-auth/context.js +8 -0
  83. package/dist/runtime/convex-auth/create-auth-component.d.ts +41 -0
  84. package/dist/runtime/convex-auth/create-auth-component.js +157 -0
  85. package/dist/runtime/convex-auth/index.d.ts +11 -0
  86. package/dist/runtime/convex-auth/index.js +7 -0
  87. package/dist/runtime/convex-auth/internal-session.d.ts +2 -0
  88. package/dist/runtime/convex-auth/internal-session.js +1 -0
  89. package/dist/runtime/convex-auth/jwks-rotation.d.ts +58 -0
  90. package/dist/runtime/convex-auth/jwks-rotation.js +163 -0
  91. package/dist/runtime/convex-auth/oauth-live-access.d.ts +17 -0
  92. package/dist/runtime/convex-auth/oauth-live-access.js +78 -0
  93. package/dist/runtime/convex-auth/oauth-provider-compat.d.ts +10 -0
  94. package/dist/runtime/convex-auth/oauth-provider-compat.js +170 -0
  95. package/dist/runtime/convex-auth/oauth-resource.d.ts +39 -0
  96. package/dist/runtime/convex-auth/oauth-resource.js +118 -0
  97. package/dist/runtime/convex-auth/oauth-security.d.ts +82 -0
  98. package/dist/runtime/convex-auth/oauth-security.js +454 -0
  99. package/dist/runtime/convex-auth/origin.d.ts +4 -0
  100. package/dist/runtime/convex-auth/origin.js +9 -0
  101. package/dist/runtime/convex-auth/plugin.d.ts +18 -0
  102. package/dist/runtime/convex-auth/plugin.js +605 -0
  103. package/dist/runtime/convex-auth/provider.d.ts +2 -0
  104. package/dist/runtime/convex-auth/provider.js +11 -0
  105. package/dist/runtime/convex-auth/test.d.ts +410 -0
  106. package/dist/runtime/convex-auth/test.js +9 -0
  107. package/dist/runtime/convex-auth/types.d.ts +18 -0
  108. package/dist/runtime/convex-auth/types.js +0 -0
  109. package/dist/runtime/convex-auth/user-projection.d.ts +106 -0
  110. package/dist/runtime/convex-auth/user-projection.js +128 -0
  111. package/dist/runtime/devtools/auth-proxy-registry.d.ts +4 -0
  112. package/dist/runtime/devtools/auth-proxy-registry.js +47 -0
  113. package/dist/runtime/devtools/bridge-setup.d.ts +21 -0
  114. package/dist/runtime/devtools/bridge-setup.js +165 -0
  115. package/dist/runtime/devtools/path-utils.d.ts +2 -0
  116. package/dist/runtime/devtools/path-utils.js +12 -0
  117. package/dist/runtime/devtools/server.d.ts +2 -0
  118. package/dist/runtime/devtools/server.js +108 -0
  119. package/dist/runtime/devtools/setup-client.d.ts +16 -0
  120. package/dist/runtime/devtools/setup-client.js +43 -0
  121. package/dist/runtime/devtools/sink.d.ts +18 -0
  122. package/dist/runtime/devtools/sink.js +110 -0
  123. package/dist/runtime/devtools/transport.d.ts +16 -0
  124. package/dist/runtime/devtools/transport.js +149 -0
  125. package/dist/runtime/devtools/types.d.ts +167 -0
  126. package/dist/runtime/devtools/types.js +1 -0
  127. package/dist/runtime/devtools/ui/dist/200.html +1 -0
  128. package/dist/runtime/devtools/ui/dist/404.html +1 -0
  129. package/dist/runtime/devtools/ui/dist/_nuxt/C4MASuCh.js +1 -0
  130. package/dist/runtime/devtools/ui/dist/_nuxt/DJHkqtZq.js +3 -0
  131. package/dist/runtime/devtools/ui/dist/_nuxt/DWwrCltl.js +2 -0
  132. package/dist/runtime/devtools/ui/dist/_nuxt/DZ_UiYoH.js +1 -0
  133. package/dist/runtime/devtools/ui/dist/_nuxt/_m9ujb-i.js +1 -0
  134. package/dist/runtime/devtools/ui/dist/_nuxt/builds/latest.json +1 -0
  135. package/dist/runtime/devtools/ui/dist/_nuxt/builds/meta/better-convex-nuxt-devtools.json +1 -0
  136. package/dist/runtime/devtools/ui/dist/_nuxt/entry.DpFDKYZ5.css +1 -0
  137. package/dist/runtime/devtools/ui/dist/_nuxt/error-404.DYUJo5xt.css +1 -0
  138. package/dist/runtime/devtools/ui/dist/_nuxt/error-500.DQdoJJXg.css +1 -0
  139. package/dist/runtime/devtools/ui/dist/convex-logo.svg +5 -0
  140. package/dist/runtime/devtools/ui/dist/index.html +1 -0
  141. package/dist/runtime/errors/index.d.ts +7 -0
  142. package/dist/runtime/errors/index.js +5 -0
  143. package/dist/runtime/middleware/convex-auth.global.d.ts +2 -0
  144. package/dist/runtime/middleware/convex-auth.global.js +31 -0
  145. package/dist/runtime/plugin.auth.client.d.ts +3 -0
  146. package/dist/runtime/plugin.auth.client.js +217 -0
  147. package/dist/runtime/plugin.client.d.ts +3 -0
  148. package/dist/runtime/plugin.client.js +43 -0
  149. package/dist/runtime/plugin.server.d.ts +12 -0
  150. package/dist/runtime/plugin.server.js +98 -0
  151. package/dist/runtime/plugins/convex-call-error-payload.d.ts +14 -0
  152. package/dist/runtime/plugins/convex-call-error-payload.js +12 -0
  153. package/dist/runtime/runtime-context.d.ts +26 -0
  154. package/dist/runtime/runtime-context.js +48 -0
  155. package/dist/runtime/server/api/auth/[...].d.ts +10 -0
  156. package/dist/runtime/server/api/auth/[...].js +509 -0
  157. package/dist/runtime/server/api/auth/authorization-server-metadata.d.ts +2 -0
  158. package/dist/runtime/server/api/auth/authorization-server-metadata.js +6 -0
  159. package/dist/runtime/server/api/auth/body-size.d.ts +15 -0
  160. package/dist/runtime/server/api/auth/body-size.js +179 -0
  161. package/dist/runtime/server/api/auth/headers.d.ts +6 -0
  162. package/dist/runtime/server/api/auth/headers.js +98 -0
  163. package/dist/runtime/server/api/auth/jwks.d.ts +2 -0
  164. package/dist/runtime/server/api/auth/jwks.js +6 -0
  165. package/dist/runtime/server/api/auth/security.d.ts +14 -0
  166. package/dist/runtime/server/api/auth/security.js +85 -0
  167. package/dist/runtime/server/api/release-fingerprint.d.ts +2 -0
  168. package/dist/runtime/server/api/release-fingerprint.js +36 -0
  169. package/dist/runtime/server/index.d.ts +1 -0
  170. package/dist/runtime/server/index.js +3 -0
  171. package/dist/runtime/server/plugins/runtime-config.d.ts +7 -0
  172. package/dist/runtime/server/plugins/runtime-config.js +7 -0
  173. package/dist/runtime/server/utils/auth-snapshot.d.ts +26 -0
  174. package/dist/runtime/server/utils/auth-snapshot.js +165 -0
  175. package/dist/runtime/server/utils/http.d.ts +16 -0
  176. package/dist/runtime/server/utils/http.js +133 -0
  177. package/dist/runtime/server/utils/server-convex-caller.d.ts +31 -0
  178. package/dist/runtime/server/utils/server-convex-caller.js +151 -0
  179. package/dist/runtime/server/utils/server-convex-options.d.ts +83 -0
  180. package/dist/runtime/server/utils/server-convex-options.js +69 -0
  181. package/dist/runtime/server/utils/signed-client-ip.d.ts +6 -0
  182. package/dist/runtime/server/utils/signed-client-ip.js +29 -0
  183. package/dist/runtime/server/utils/ssr-auth-headers.d.ts +26 -0
  184. package/dist/runtime/server/utils/ssr-auth-headers.js +49 -0
  185. package/dist/runtime/server/utils/token-exchange.d.ts +27 -0
  186. package/dist/runtime/server/utils/token-exchange.js +96 -0
  187. package/dist/runtime/shared/auth-cookie.d.ts +4 -0
  188. package/dist/runtime/shared/auth-cookie.js +25 -0
  189. package/dist/runtime/shared/auth-origin.d.ts +15 -0
  190. package/dist/runtime/shared/auth-origin.js +42 -0
  191. package/dist/runtime/shared/bounded-stream.d.ts +2 -0
  192. package/dist/runtime/shared/bounded-stream.js +50 -0
  193. package/dist/runtime/shared/client-ip.d.ts +21 -0
  194. package/dist/runtime/shared/client-ip.js +123 -0
  195. package/dist/runtime/shared/release-fingerprint.d.ts +5 -0
  196. package/dist/runtime/shared/release-fingerprint.js +17 -0
  197. package/dist/runtime/types.d.ts +19 -0
  198. package/dist/runtime/utils/auth-config.d.ts +24 -0
  199. package/dist/runtime/utils/auth-config.js +45 -0
  200. package/dist/runtime/utils/auth-contract.d.ts +22 -0
  201. package/dist/runtime/utils/auth-contract.js +0 -0
  202. package/dist/runtime/utils/auth-errors.d.ts +5 -0
  203. package/dist/runtime/utils/auth-errors.js +22 -0
  204. package/dist/runtime/utils/auth-identity-state.d.ts +4 -0
  205. package/dist/runtime/utils/auth-identity-state.js +8 -0
  206. package/dist/runtime/utils/auth-pending-state.d.ts +13 -0
  207. package/dist/runtime/utils/auth-pending-state.js +4 -0
  208. package/dist/runtime/utils/auth-pending.d.ts +10 -0
  209. package/dist/runtime/utils/auth-pending.js +30 -0
  210. package/dist/runtime/utils/auth-route-protection.d.ts +16 -0
  211. package/dist/runtime/utils/auth-route-protection.js +58 -0
  212. package/dist/runtime/utils/auth-status.d.ts +47 -0
  213. package/dist/runtime/utils/auth-status.js +8 -0
  214. package/dist/runtime/utils/bounded-convex-fetch.d.ts +18 -0
  215. package/dist/runtime/utils/bounded-convex-fetch.js +152 -0
  216. package/dist/runtime/utils/callable-devtools.d.ts +17 -0
  217. package/dist/runtime/utils/callable-devtools.js +49 -0
  218. package/dist/runtime/utils/callable-observer.d.ts +2 -0
  219. package/dist/runtime/utils/callable-observer.js +1 -0
  220. package/dist/runtime/utils/composable-scope.d.ts +2 -0
  221. package/dist/runtime/utils/composable-scope.js +8 -0
  222. package/dist/runtime/utils/config-defaults.d.ts +8 -0
  223. package/dist/runtime/utils/config-defaults.js +8 -0
  224. package/dist/runtime/utils/convex-cache.d.ts +68 -0
  225. package/dist/runtime/utils/convex-cache.js +47 -0
  226. package/dist/runtime/utils/convex-config.d.ts +16 -0
  227. package/dist/runtime/utils/convex-config.js +50 -0
  228. package/dist/runtime/utils/convex-shared.d.ts +67 -0
  229. package/dist/runtime/utils/convex-shared.js +134 -0
  230. package/dist/runtime/utils/identity-changed-error.d.ts +4 -0
  231. package/dist/runtime/utils/identity-changed-error.js +12 -0
  232. package/dist/runtime/utils/identity-key.d.ts +19 -0
  233. package/dist/runtime/utils/identity-key.js +10 -0
  234. package/dist/runtime/utils/integrated-auth-client.d.ts +5 -0
  235. package/dist/runtime/utils/integrated-auth-client.js +0 -0
  236. package/dist/runtime/utils/logger.d.ts +42 -0
  237. package/dist/runtime/utils/logger.js +190 -0
  238. package/dist/runtime/utils/mime-type.d.ts +33 -0
  239. package/dist/runtime/utils/mime-type.js +10 -0
  240. package/dist/runtime/utils/query-execution-gate.d.ts +47 -0
  241. package/dist/runtime/utils/query-execution-gate.js +63 -0
  242. package/dist/runtime/utils/query-execution.d.ts +8 -0
  243. package/dist/runtime/utils/query-execution.js +19 -0
  244. package/dist/runtime/utils/query-foundation.d.ts +20 -0
  245. package/dist/runtime/utils/query-foundation.js +39 -0
  246. package/dist/runtime/utils/query-state.d.ts +12 -0
  247. package/dist/runtime/utils/query-state.js +12 -0
  248. package/dist/runtime/utils/reactive-args.d.ts +5 -0
  249. package/dist/runtime/utils/reactive-args.js +42 -0
  250. package/dist/runtime/utils/runtime-config-normalize.d.ts +22 -0
  251. package/dist/runtime/utils/runtime-config-normalize.js +28 -0
  252. package/dist/runtime/utils/runtime-config.d.ts +4 -0
  253. package/dist/runtime/utils/runtime-config.js +8 -0
  254. package/dist/runtime/utils/sanitize-diagnostic.d.ts +6 -0
  255. package/dist/runtime/utils/sanitize-diagnostic.js +81 -0
  256. package/dist/runtime/utils/shared-helpers.d.ts +46 -0
  257. package/dist/runtime/utils/shared-helpers.js +139 -0
  258. package/dist/runtime/utils/site-url.d.ts +4 -0
  259. package/dist/runtime/utils/site-url.js +15 -0
  260. package/dist/runtime/utils/ssr-pagination-state.d.ts +3 -0
  261. package/dist/runtime/utils/ssr-pagination-state.js +3 -0
  262. package/dist/runtime/utils/types.d.ts +29 -0
  263. package/dist/runtime/utils/types.js +0 -0
  264. package/dist/runtime/utils/upload-core.d.ts +16 -0
  265. package/dist/runtime/utils/upload-core.js +116 -0
  266. package/dist/types.d.mts +21 -0
  267. package/package.json +253 -0
  268. package/security/upstream-convex-better-auth.json +477 -0
@@ -0,0 +1,96 @@
1
+ import { ConvexCallError } from "../../errors/index.js";
2
+ import { filterBetterAuthCookies, getBetterAuthSessionToken } from "../../utils/shared-helpers.js";
3
+ import { normalizeConvexSiteUrl } from "../../utils/site-url.js";
4
+ import { fetchWithTimeout, MAX_SERVER_AUTH_RESPONSE_BODY_BYTES, readBoundedJson } from "./http.js";
5
+ import {
6
+ assertConvexCredentialShape,
7
+ assertCredentialValueSafe,
8
+ ServerConvexValidationError
9
+ } from "./server-convex-options.js";
10
+ import { buildSignedClientIpHeaders } from "./signed-client-ip.js";
11
+ const TOKEN_EXCHANGE_PATH = "/api/auth/convex/token";
12
+ const DEFAULT_TOKEN_EXCHANGE_TIMEOUT_MS = 5e3;
13
+ function readToken(body) {
14
+ if (body && typeof body === "object") {
15
+ const token = body.token;
16
+ if (typeof token === "string" && token.length > 0) return token;
17
+ }
18
+ return null;
19
+ }
20
+ function validateTokenExchangeCredential(credential) {
21
+ assertConvexCredentialShape(credential);
22
+ assertCredentialValueSafe(credential.value, "credential value");
23
+ const cookieHeader = filterBetterAuthCookies(credential.value);
24
+ const sessionToken = getBetterAuthSessionToken(cookieHeader);
25
+ if (!cookieHeader || !sessionToken) {
26
+ throw new ServerConvexValidationError(
27
+ "credential must contain a non-empty supported Better Auth session cookie"
28
+ );
29
+ }
30
+ return cookieHeader;
31
+ }
32
+ export function exchangeConvexToken(input) {
33
+ const cookieHeader = validateTokenExchangeCredential(input.credential);
34
+ return (async () => {
35
+ try {
36
+ const clientIpHeaders = await buildSignedClientIpHeaders(input.event, {
37
+ trustedClientIpHeader: input.trustedClientIpHeader
38
+ });
39
+ return await runTokenExchange(input, { ...clientIpHeaders, Cookie: cookieHeader });
40
+ } catch {
41
+ return tokenExchangeTransportFailure();
42
+ }
43
+ })();
44
+ }
45
+ function tokenExchangeTransportFailure() {
46
+ return {
47
+ token: null,
48
+ status: void 0,
49
+ error: new ConvexCallError({
50
+ kind: "transport",
51
+ message: "Convex token exchange could not complete"
52
+ })
53
+ };
54
+ }
55
+ async function runTokenExchange(input, headers) {
56
+ try {
57
+ const response = await fetchWithTimeout(
58
+ `${normalizeConvexSiteUrl(input.siteUrl)}${TOKEN_EXCHANGE_PATH}`,
59
+ {
60
+ method: "GET",
61
+ headers,
62
+ redirect: "error",
63
+ timeoutMs: input.timeoutMs ?? DEFAULT_TOKEN_EXCHANGE_TIMEOUT_MS
64
+ }
65
+ );
66
+ if (!response.ok) {
67
+ await response.body?.cancel().catch(() => {
68
+ });
69
+ return {
70
+ token: null,
71
+ status: response.status,
72
+ error: new ConvexCallError({
73
+ kind: response.status === 401 || response.status === 403 ? "authentication" : "transport",
74
+ message: `Convex token exchange failed with HTTP ${response.status}`,
75
+ status: response.status
76
+ })
77
+ };
78
+ }
79
+ const parsed = await readBoundedJson(response, MAX_SERVER_AUTH_RESPONSE_BODY_BYTES);
80
+ const token = readToken(parsed);
81
+ if (!token) {
82
+ return {
83
+ token: null,
84
+ status: response.status,
85
+ error: new ConvexCallError({
86
+ kind: "transport",
87
+ message: "Convex token exchange response did not include a token",
88
+ status: response.status
89
+ })
90
+ };
91
+ }
92
+ return { token, status: response.status, error: null };
93
+ } catch {
94
+ return tokenExchangeTransportFailure();
95
+ }
96
+ }
@@ -0,0 +1,4 @@
1
+ /** The only cookie namespace supported by the Nuxt auth boundary. */
2
+ export declare function isBetterAuthCookieName(name: string): boolean;
3
+ /** Whether a request presents any supported Better Auth cookie name, even malformed. */
4
+ export declare function hasBetterAuthCookie(cookieHeader: string | null | undefined): boolean;
@@ -0,0 +1,25 @@
1
+ const COOKIE_NAME_PATTERN = /^[!#$%&'*+\-.^`|~\w]+$/;
2
+ function trimOptionalWhitespace(value) {
3
+ let start = 0;
4
+ let end = value.length;
5
+ while (start < end && (value.charCodeAt(start) === 32 || value.charCodeAt(start) === 9)) {
6
+ start += 1;
7
+ }
8
+ while (end > start && (value.charCodeAt(end - 1) === 32 || value.charCodeAt(end - 1) === 9)) {
9
+ end -= 1;
10
+ }
11
+ return start === 0 && end === value.length ? value : value.slice(start, end);
12
+ }
13
+ export function isBetterAuthCookieName(name) {
14
+ if (!COOKIE_NAME_PATTERN.test(name)) return false;
15
+ const unprefixed = name.startsWith("__Secure-") ? name.slice("__Secure-".length) : name;
16
+ return unprefixed.startsWith("better-auth.") && unprefixed.length > "better-auth.".length;
17
+ }
18
+ export function hasBetterAuthCookie(cookieHeader) {
19
+ if (!cookieHeader) return false;
20
+ return cookieHeader.split(";").some((chunk) => {
21
+ const separator = chunk.indexOf("=");
22
+ const name = trimOptionalWhitespace(separator === -1 ? chunk : chunk.slice(0, separator));
23
+ return isBetterAuthCookieName(name);
24
+ });
25
+ }
@@ -0,0 +1,15 @@
1
+ export type AuthOriginName = 'SITE_URL' | 'CONVEX_SITE_URL' | 'auth.origin' | 'convex.url' | 'convex.siteUrl';
2
+ /**
3
+ * Return whether a URL parser hostname is one of the three exact development
4
+ * loopback forms supported by the auth boundary.
5
+ *
6
+ * This intentionally does not accept `*.localhost`, the rest of 127/8, IPv4
7
+ * aliases, or expanded/mapped IPv6 forms. Callers must first prove that the
8
+ * complete URL already uses its canonical serialization so the URL parser
9
+ * cannot turn an ambiguous spelling into one of these values.
10
+ */
11
+ export declare function isExactLoopbackHost(hostname: string): boolean;
12
+ /** Return one canonical, credential-free HTTP(S) origin or throw. */
13
+ export declare function normalizeAuthOrigin(input: string, name: AuthOriginName): string;
14
+ /** Read and validate a required auth origin from an environment-like object. */
15
+ export declare function requireAuthOrigin(name: 'SITE_URL' | 'CONVEX_SITE_URL', env: Readonly<Record<string, string | undefined>>): string;
@@ -0,0 +1,42 @@
1
+ export function isExactLoopbackHost(hostname) {
2
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
3
+ }
4
+ export function normalizeAuthOrigin(input, name) {
5
+ if (typeof input !== "string" || input.length === 0) {
6
+ throw new TypeError(`${name} must be a non-empty string URL origin`);
7
+ }
8
+ let url;
9
+ try {
10
+ url = new URL(input);
11
+ } catch {
12
+ throw new TypeError(`${name} must be a valid URL origin`);
13
+ }
14
+ if (url.username || url.password) {
15
+ throw new TypeError(`${name} must not contain credentials`);
16
+ }
17
+ if (url.search || url.hash) {
18
+ throw new TypeError(`${name} must not contain a query string or fragment`);
19
+ }
20
+ if (url.pathname !== "/") {
21
+ throw new TypeError(`${name} must not contain a path`);
22
+ }
23
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
24
+ throw new TypeError(`${name} must use http or https`);
25
+ }
26
+ if (url.hostname.endsWith(".")) {
27
+ throw new TypeError(`${name} must not use a trailing-dot hostname`);
28
+ }
29
+ const inputWithoutOneTrailingSlash = input.endsWith("/") ? input.slice(0, -1) : input;
30
+ if (inputWithoutOneTrailingSlash !== url.origin) {
31
+ throw new TypeError(`${name} must use its canonical URL serialization`);
32
+ }
33
+ if (url.protocol === "http:" && !isExactLoopbackHost(url.hostname)) {
34
+ throw new TypeError(`${name} must use https outside exact loopback development hosts`);
35
+ }
36
+ return url.origin;
37
+ }
38
+ export function requireAuthOrigin(name, env) {
39
+ const value = env[name];
40
+ if (!value) throw new TypeError(`${name} is required`);
41
+ return normalizeAuthOrigin(value, name);
42
+ }
@@ -0,0 +1,2 @@
1
+ export declare function bodyChunkBytes(chunk: unknown): Uint8Array;
2
+ export declare function readStreamWithByteLimit(stream: ReadableStream<unknown> | null | undefined, maxBytes: number, createSizeError: (observedBytes: number, maxBytes: number) => unknown, signal?: AbortSignal): Promise<Uint8Array | undefined>;
@@ -0,0 +1,50 @@
1
+ export function bodyChunkBytes(chunk) {
2
+ if (chunk instanceof Uint8Array) return chunk;
3
+ if (chunk instanceof ArrayBuffer) return new Uint8Array(chunk);
4
+ if (typeof chunk === "string") return new TextEncoder().encode(chunk);
5
+ throw new TypeError("[better-convex-nuxt] Body stream yielded an unsupported chunk.");
6
+ }
7
+ async function readNextChunk(reader, signal) {
8
+ if (!signal) return await reader.read();
9
+ if (signal.aborted) throw signal.reason;
10
+ return await new Promise((resolve, reject) => {
11
+ const abort = () => reject(signal.reason ?? new Error("Body read was aborted"));
12
+ signal.addEventListener("abort", abort, { once: true });
13
+ reader.read().then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
14
+ });
15
+ }
16
+ function cancelReader(reader, reason) {
17
+ try {
18
+ void reader.cancel(reason).catch(() => {
19
+ });
20
+ } catch {
21
+ }
22
+ }
23
+ export async function readStreamWithByteLimit(stream, maxBytes, createSizeError, signal) {
24
+ if (!stream) return void 0;
25
+ const reader = stream.getReader();
26
+ const chunks = [];
27
+ let totalBytes = 0;
28
+ try {
29
+ while (true) {
30
+ const { done, value } = await readNextChunk(reader, signal);
31
+ if (done) break;
32
+ const chunk = bodyChunkBytes(value);
33
+ totalBytes += chunk.byteLength;
34
+ if (totalBytes > maxBytes) throw createSizeError(totalBytes, maxBytes);
35
+ chunks.push(chunk);
36
+ }
37
+ } catch (error) {
38
+ cancelReader(reader, error);
39
+ throw error;
40
+ } finally {
41
+ reader.releaseLock();
42
+ }
43
+ const body = new Uint8Array(totalBytes);
44
+ let offset = 0;
45
+ for (const chunk of chunks) {
46
+ body.set(chunk, offset);
47
+ offset += chunk.byteLength;
48
+ }
49
+ return body;
50
+ }
@@ -0,0 +1,21 @@
1
+ /** Reserved request headers used only between the Nuxt proxy and Convex. */
2
+ export declare const CLIENT_IP_HEADER = "x-bcn-client-ip";
3
+ export declare const CLIENT_IP_SIGNATURE_HEADER = "x-bcn-client-ip-signature";
4
+ export declare const VERIFIED_CLIENT_IP_HEADER = "x-bcn-verified-client-ip";
5
+ /**
6
+ * Parse one unambiguous IP literal and return its canonical text form.
7
+ * Forwarding chains, ports, zone identifiers, whitespace, and control bytes
8
+ * are deliberately outside this protocol.
9
+ */
10
+ export declare function normalizeClientIp(value: string | null | undefined): string | null;
11
+ /** Throw when the proxy IP secret cannot safely key HMAC-SHA-256. */
12
+ export declare function requireProxyIpSecret(secret: string | null | undefined): string;
13
+ /** Sign one canonical client IP for the private Nuxt-to-Convex hop. */
14
+ export declare function signClientIp(clientIp: string, secret: string): Promise<string>;
15
+ /**
16
+ * Verify a complete signed pair and return only a canonical authenticated IP.
17
+ * Invalid configuration and malformed attacker input are indistinguishable to
18
+ * callers. An absent pair permits direct Convex request metadata; once either
19
+ * reserved header is present, the component rejects an invalid pair.
20
+ */
21
+ export declare function verifySignedClientIp(clientIp: string | null, signature: string | null, secret: string | null | undefined): Promise<string | null>;
@@ -0,0 +1,123 @@
1
+ const HMAC_ALGORITHM = "HMAC";
2
+ const HMAC_HASH = "SHA-256";
3
+ const SIGNATURE_PREFIX = "v1\n";
4
+ const MAX_CLIENT_IP_INPUT_LENGTH = 45;
5
+ const HMAC_SHA256_BYTE_LENGTH = 32;
6
+ const HMAC_SHA256_BASE64URL_LENGTH = 43;
7
+ const MIN_PROXY_IP_SECRET_BYTE_LENGTH = 32;
8
+ const MAX_PROXY_IP_SECRET_BYTE_LENGTH = 1024;
9
+ export const CLIENT_IP_HEADER = "x-bcn-client-ip";
10
+ export const CLIENT_IP_SIGNATURE_HEADER = "x-bcn-client-ip-signature";
11
+ export const VERIFIED_CLIENT_IP_HEADER = "x-bcn-verified-client-ip";
12
+ function hasUnsafeHeaderCharacter(value) {
13
+ for (let index = 0; index < value.length; index += 1) {
14
+ const code = value.charCodeAt(index);
15
+ if (code <= 32 || code === 127) return true;
16
+ }
17
+ return false;
18
+ }
19
+ function normalizeIpv4(value) {
20
+ const parts = value.split(".");
21
+ if (parts.length !== 4) return null;
22
+ for (const part of parts) {
23
+ if (!/^(?:0|[1-9]\d{0,2})$/.test(part)) return null;
24
+ if (Number(part) > 255) return null;
25
+ }
26
+ return parts.join(".");
27
+ }
28
+ function normalizeIpv6(value) {
29
+ if (!value.includes(":") || value.includes("%") || value.includes("[") || value.includes("]")) {
30
+ return null;
31
+ }
32
+ try {
33
+ const hostname = new URL(`http://[${value}]/`).hostname;
34
+ if (!hostname.startsWith("[") || !hostname.endsWith("]")) return null;
35
+ return hostname.slice(1, -1).toLowerCase();
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+ export function normalizeClientIp(value) {
41
+ if (typeof value !== "string" || value.length === 0 || value.length > MAX_CLIENT_IP_INPUT_LENGTH || hasUnsafeHeaderCharacter(value) || value.includes(",")) {
42
+ return null;
43
+ }
44
+ return value.includes(":") ? normalizeIpv6(value) : normalizeIpv4(value);
45
+ }
46
+ function secretBytes(secret) {
47
+ if (typeof secret !== "string") return null;
48
+ const bytes = new TextEncoder().encode(secret);
49
+ if (bytes.byteLength < MIN_PROXY_IP_SECRET_BYTE_LENGTH || bytes.byteLength > MAX_PROXY_IP_SECRET_BYTE_LENGTH) {
50
+ return null;
51
+ }
52
+ return bytes;
53
+ }
54
+ function ownedArrayBuffer(bytes) {
55
+ const owned = new Uint8Array(bytes.byteLength);
56
+ owned.set(bytes);
57
+ return owned.buffer;
58
+ }
59
+ export function requireProxyIpSecret(secret) {
60
+ if (!secretBytes(secret)) {
61
+ throw new TypeError("BCN_AUTH_PROXY_IP_SECRET must contain 32 to 1024 UTF-8 bytes");
62
+ }
63
+ return secret;
64
+ }
65
+ function bytesToBase64Url(bytes) {
66
+ let binary = "";
67
+ for (const byte of bytes) binary += String.fromCharCode(byte);
68
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
69
+ }
70
+ function strictBase64UrlSignature(value) {
71
+ if (typeof value !== "string" || value.length !== HMAC_SHA256_BASE64URL_LENGTH || !/^[\w-]{43}$/.test(value)) {
72
+ return null;
73
+ }
74
+ try {
75
+ const base64 = `${value.replaceAll("-", "+").replaceAll("_", "/")}=`;
76
+ const binary = atob(base64);
77
+ const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
78
+ if (bytes.byteLength !== HMAC_SHA256_BYTE_LENGTH) return null;
79
+ return bytesToBase64Url(bytes) === value ? bytes : null;
80
+ } catch {
81
+ return null;
82
+ }
83
+ }
84
+ async function importHmacKey(secret) {
85
+ return crypto.subtle.importKey(
86
+ "raw",
87
+ ownedArrayBuffer(secretBytes(secret)),
88
+ { name: HMAC_ALGORITHM, hash: HMAC_HASH },
89
+ false,
90
+ ["sign", "verify"]
91
+ );
92
+ }
93
+ function signatureInput(clientIp) {
94
+ return ownedArrayBuffer(new TextEncoder().encode(`${SIGNATURE_PREFIX}${clientIp}`));
95
+ }
96
+ export async function signClientIp(clientIp, secret) {
97
+ const normalized = normalizeClientIp(clientIp);
98
+ if (!normalized) throw new TypeError("Client IP must be one valid IP literal");
99
+ requireProxyIpSecret(secret);
100
+ const signature = await crypto.subtle.sign(
101
+ HMAC_ALGORITHM,
102
+ await importHmacKey(secret),
103
+ signatureInput(normalized)
104
+ );
105
+ return bytesToBase64Url(new Uint8Array(signature));
106
+ }
107
+ export async function verifySignedClientIp(clientIp, signature, secret) {
108
+ const normalized = normalizeClientIp(clientIp);
109
+ const signatureBytes = strictBase64UrlSignature(signature);
110
+ const keyBytes = secretBytes(secret);
111
+ if (!normalized || normalized !== clientIp || !signatureBytes || !keyBytes) return null;
112
+ try {
113
+ const verified = await crypto.subtle.verify(
114
+ HMAC_ALGORITHM,
115
+ await importHmacKey(secret),
116
+ ownedArrayBuffer(signatureBytes),
117
+ signatureInput(normalized)
118
+ );
119
+ return verified ? normalized : null;
120
+ } catch {
121
+ return null;
122
+ }
123
+ }
@@ -0,0 +1,5 @@
1
+ export declare const PACKED_RUNTIME_FINGERPRINT_HEADER = "x-bcn-runtime-fingerprint";
2
+ /** Undefined in ordinary source/dev builds; populated only in immutable release bytes. */
3
+ export declare function getPackedRuntimeFingerprint(): string | undefined;
4
+ /** Bind a package-owned Web Response to the immutable candidate that produced it. */
5
+ export declare function bindPackedRuntimeFingerprint(response: Response): Response;
@@ -0,0 +1,17 @@
1
+ const packedRuntimeFingerprint = "bcn-release-v1-9ddfb9636940ef0e3412c414c75947f5cbf3406fa22175219d58923c455bfd07";
2
+ const packedRuntimeFingerprintPattern = /^bcn-release-v1-[0-9a-f]{64}$/u;
3
+ export const PACKED_RUNTIME_FINGERPRINT_HEADER = "x-bcn-runtime-fingerprint";
4
+ export function getPackedRuntimeFingerprint() {
5
+ return packedRuntimeFingerprintPattern.test(packedRuntimeFingerprint) ? packedRuntimeFingerprint : void 0;
6
+ }
7
+ export function bindPackedRuntimeFingerprint(response) {
8
+ const fingerprint = getPackedRuntimeFingerprint();
9
+ if (!fingerprint) return response;
10
+ const headers = new Headers(response.headers);
11
+ headers.set(PACKED_RUNTIME_FINGERPRINT_HEADER, fingerprint);
12
+ return new Response(response.body, {
13
+ headers,
14
+ status: response.status,
15
+ statusText: response.statusText
16
+ });
17
+ }
@@ -0,0 +1,19 @@
1
+ import type { ConvexRuntimeContext } from './runtime-context'
2
+
3
+ // The public `$convex` and `$auth` Nuxt-app property augmentations are deleted
4
+ // : consumers use the stable `useConvex()` handle and the auth
5
+ // composables, never a raw replaceable client or generic Nuxt injection. The
6
+ // augmentations below are INTERNAL inter-plugin seams (browser-only).
7
+ declare module '#app' {
8
+ interface NuxtApp {
9
+ /**
10
+ * The per-Nuxt-app client owner (architecture invariant). Sole source of
11
+ * truth for the replaceable primary and lazy anonymous clients; `useConvex()`
12
+ * returns its stable handle and `useConvexConnectionState()` observes its
13
+ * connection store. Provided by the core client plugin (browser only).
14
+ */
15
+ $convexRuntime?: ConvexRuntimeContext
16
+ }
17
+ }
18
+
19
+ export {}
@@ -0,0 +1,24 @@
1
+ /** Build-time authentication options. An object opts the application into auth. */
2
+ export interface ConvexAuthOptions {
3
+ /** Exact public Nuxt application origin used by the same-origin auth proxy. */
4
+ origin: string;
5
+ /** Optional build-time Better Auth client definition. Never copied to runtime config. */
6
+ client?: string;
7
+ /** Trusted ingress-owned header containing exactly one client IP address. */
8
+ trustedClientIpHeader?: string;
9
+ /** Local route used when protected navigation needs authentication. */
10
+ redirectTo?: string;
11
+ }
12
+ /** Internal materialized auth policy. `false` exists only for a no-auth build. */
13
+ export type NormalizedConvexAuthConfig = false | Readonly<{
14
+ origin: string;
15
+ trustedClientIpHeader: string;
16
+ redirectTo: string;
17
+ }>;
18
+ /**
19
+ * Normalize the build grammar. Omission is a genuine Convex-only build; an
20
+ * object opts into auth and must name its one exact public application origin.
21
+ * `false` remains a Nuxt-layer tombstone for removing inherited auth options.
22
+ */
23
+ export declare function normalizeConvexAuthConfig(input: false | ConvexAuthOptions | undefined | unknown): NormalizedConvexAuthConfig;
24
+ export declare function isConvexAuthEnabled(config: NormalizedConvexAuthConfig): config is Exclude<NormalizedConvexAuthConfig, false>;
@@ -0,0 +1,45 @@
1
+ import { isExactLoopbackHost, normalizeAuthOrigin } from "../shared/auth-origin.js";
2
+ import { normalizeLocalRedirectPath } from "./auth-route-protection.js";
3
+ const DEFAULT_AUTH_REDIRECT = "/auth/signin";
4
+ function normalizeTrustedClientIpHeader(input) {
5
+ if (input === void 0) return "";
6
+ if (typeof input !== "string") {
7
+ throw new TypeError("auth.trustedClientIpHeader must be a valid HTTP header name");
8
+ }
9
+ const header = input.trim().toLowerCase();
10
+ if (!header) return "";
11
+ try {
12
+ new Headers().set(header, "validation");
13
+ } catch {
14
+ throw new TypeError("auth.trustedClientIpHeader must be a valid HTTP header name");
15
+ }
16
+ if (header.startsWith("x-bcn-")) {
17
+ throw new TypeError("auth.trustedClientIpHeader must not use the reserved x-bcn-* namespace");
18
+ }
19
+ return header;
20
+ }
21
+ export function normalizeConvexAuthConfig(input) {
22
+ if (input === void 0 || input === false) return false;
23
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
24
+ throw new TypeError("auth must be false or an object with an origin");
25
+ }
26
+ const options = input;
27
+ if (typeof options.origin !== "string") {
28
+ throw new TypeError("auth.origin must be a non-empty string URL origin");
29
+ }
30
+ const origin = normalizeAuthOrigin(options.origin, "auth.origin");
31
+ const trustedClientIpHeader = normalizeTrustedClientIpHeader(options.trustedClientIpHeader);
32
+ if (!trustedClientIpHeader && !isExactLoopbackHost(new URL(origin).hostname)) {
33
+ throw new TypeError(
34
+ "auth.trustedClientIpHeader is required outside exact loopback development origins"
35
+ );
36
+ }
37
+ const redirectTo = normalizeLocalRedirectPath(options.redirectTo ?? DEFAULT_AUTH_REDIRECT);
38
+ if (!redirectTo) {
39
+ throw new TypeError("auth.redirectTo must be a safe local application path");
40
+ }
41
+ return Object.freeze({ origin, trustedClientIpHeader, redirectTo });
42
+ }
43
+ export function isConvexAuthEnabled(config) {
44
+ return config !== false;
45
+ }
@@ -0,0 +1,22 @@
1
+ import type { ComputedRef, Ref } from 'vue';
2
+ import type { ConvexCallError } from '../errors/index.js';
3
+ import type { ConvexAuthStatus } from './auth-status.js';
4
+ import type { IntegratedAuthClient } from './integrated-auth-client.js';
5
+ import type { ConvexUser } from './types.js';
6
+ /**
7
+ * Convex authentication state plus the provider client accepted by the Nuxt
8
+ * runtime. The neutral default keeps the root declaration graph independent
9
+ * from any particular authentication package; `useConvexAuth()` specializes
10
+ * this with the registered Better Auth client inside auth-enabled builds.
11
+ */
12
+ export interface UseConvexAuthReturn<Client extends object = object> {
13
+ readonly status: ComputedRef<ConvexAuthStatus>;
14
+ readonly isPending: ComputedRef<boolean>;
15
+ readonly user: Readonly<Ref<ConvexUser | null>>;
16
+ readonly error: Readonly<Ref<ConvexCallError | undefined>>;
17
+ /** Every PromiseLike client operation crosses canonical session reconciliation. */
18
+ readonly client: IntegratedAuthClient<Client> | null;
19
+ ready(options?: {
20
+ timeoutMs?: number;
21
+ }): Promise<ConvexAuthStatus>;
22
+ }
File without changes
@@ -0,0 +1,5 @@
1
+ export declare function buildMissingSiteUrlMessage(): string;
2
+ export declare function buildMissingPublicOriginMessage(): string;
3
+ export declare function buildBlockedOriginMessage(): string;
4
+ export declare function buildAuthProxyUnreachableMessage(): string;
5
+ export declare function buildAuthProxyUpstreamStatusMessage(status: number): string;
@@ -0,0 +1,22 @@
1
+ const PREFIX = "NuxtConvexError";
2
+ function prefix(message) {
3
+ return `${PREFIX}: ${message}`;
4
+ }
5
+ export function buildMissingSiteUrlMessage() {
6
+ return prefix("Auth proxy requires a configured Convex HTTP Actions host (`convex.siteUrl`).");
7
+ }
8
+ export function buildMissingPublicOriginMessage() {
9
+ return prefix("Auth proxy requires one canonical public Nuxt origin. Set `convex.auth.origin`.");
10
+ }
11
+ export function buildBlockedOriginMessage() {
12
+ return prefix("Cross-origin auth request blocked. Use the same-origin Nuxt auth proxy.");
13
+ }
14
+ export function buildAuthProxyUnreachableMessage() {
15
+ return prefix(
16
+ "Auth proxy could not reach the configured Convex auth server. Check `convex.siteUrl` and the deployed Convex HTTP routes."
17
+ );
18
+ }
19
+ export function buildAuthProxyUpstreamStatusMessage(status) {
20
+ const hint = status === 404 ? "This usually means Better Auth routes are not registered in `convex/http.ts` or `convex.siteUrl` points to the wrong host." : "Check your Convex deployment health and Better Auth setup.";
21
+ return prefix(`Auth proxy upstream returned HTTP ${status}. ${hint}`);
22
+ }
@@ -0,0 +1,4 @@
1
+ import type { Ref } from 'vue';
2
+ import { type AuthIdentity } from '../auth/auth-identity.js';
3
+ /** The single SSR-hydrated identity value used by every runtime auth reader. */
4
+ export declare function useConvexIdentityState(): Ref<AuthIdentity>;
@@ -0,0 +1,8 @@
1
+ import { useState } from "#imports";
2
+ import { ANONYMOUS_IDENTITY, LOADING_IDENTITY } from "../auth/auth-identity.js";
3
+ export function useConvexIdentityState() {
4
+ return useState(
5
+ "convex:identity",
6
+ () => import.meta.client ? LOADING_IDENTITY : ANONYMOUS_IDENTITY
7
+ );
8
+ }
@@ -0,0 +1,13 @@
1
+ import type { Ref } from 'vue';
2
+ /**
3
+ * Single source for the `convex:pending` auth-readiness state.
4
+ *
5
+ * The client starts pending — auth is unknown until the client engine settles —
6
+ * while the server starts settled, because `plugin.server` writes the resolved
7
+ * auth state into the SSR payload before render. Every reader/writer of
8
+ * `convex:pending` must go through this helper so the initial value can never
9
+ * diverge by first-touch order.
10
+ *
11
+ * Internal only — not part of the public auto-import surface.
12
+ */
13
+ export declare function useConvexAuthPendingState(): Ref<boolean>;
@@ -0,0 +1,4 @@
1
+ import { useState } from "#imports";
2
+ export function useConvexAuthPendingState() {
3
+ return useState("convex:pending", () => import.meta.client);
4
+ }
@@ -0,0 +1,10 @@
1
+ import { type Ref } from 'vue';
2
+ export interface WaitForPendingClearOptions {
3
+ timeoutMs?: number;
4
+ onTimeout?: () => void;
5
+ }
6
+ /**
7
+ * Wait for an auth pending ref to settle to false.
8
+ * Returns false on timeout, true when settled.
9
+ */
10
+ export declare function waitForPendingClear(pending: Ref<boolean>, options?: WaitForPendingClearOptions): Promise<boolean>;
@@ -0,0 +1,30 @@
1
+ import { watch } from "vue";
2
+ export async function waitForPendingClear(pending, options = {}) {
3
+ if (!pending.value) {
4
+ return true;
5
+ }
6
+ const timeoutMs = options.timeoutMs ?? 5e3;
7
+ return await new Promise((resolve) => {
8
+ let settled = false;
9
+ let stopWatch = null;
10
+ let timeoutId = null;
11
+ const finish = (value) => {
12
+ if (settled) return;
13
+ settled = true;
14
+ stopWatch?.();
15
+ if (timeoutId) {
16
+ clearTimeout(timeoutId);
17
+ }
18
+ resolve(value);
19
+ };
20
+ stopWatch = watch(pending, (isPending) => {
21
+ if (!isPending) {
22
+ finish(true);
23
+ }
24
+ });
25
+ timeoutId = setTimeout(() => {
26
+ options.onTimeout?.();
27
+ finish(false);
28
+ }, timeoutMs);
29
+ });
30
+ }
@@ -0,0 +1,16 @@
1
+ import type { RouteLocationRaw } from 'vue-router';
2
+ export type ConvexAuthPageMeta = boolean | {
3
+ redirectTo?: RouteLocationRaw;
4
+ };
5
+ export interface RouteProtectionDecisionInput {
6
+ meta: ConvexAuthPageMeta | undefined;
7
+ defaultRedirectTo: string;
8
+ preserveReturnTo: boolean;
9
+ currentPath: string;
10
+ currentFullPath?: string;
11
+ }
12
+ export interface RouteProtectionDecision {
13
+ redirectTo: RouteLocationRaw;
14
+ }
15
+ export declare function normalizeLocalRedirectPath(value: string): string | null;
16
+ export declare function resolveRouteProtectionDecision(input: RouteProtectionDecisionInput): RouteProtectionDecision | null;