@hexclave/js 1.0.20 → 1.0.22

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 (74) hide show
  1. package/README.md +187 -7
  2. package/dist/esm/lib/auth.d.ts.map +1 -1
  3. package/dist/esm/lib/auth.js +32 -11
  4. package/dist/esm/lib/auth.js.map +1 -1
  5. package/dist/esm/lib/auth.test.js +25 -10
  6. package/dist/esm/lib/auth.test.js.map +1 -1
  7. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -0
  8. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  9. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.js +1 -0
  10. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.js.map +1 -1
  11. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +54 -0
  12. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  13. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +4 -1
  14. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  15. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +28 -4
  16. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  17. package/dist/esm/lib/hexclave-app/apps/implementations/common.js +1 -1
  18. package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.d.ts +1 -0
  19. package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.d.ts.map +1 -1
  20. package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.js +17 -13
  21. package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.js.map +1 -1
  22. package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.test.js +4 -8
  23. package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.test.js.map +1 -1
  24. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.d.ts +3 -1
  25. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.d.ts.map +1 -1
  26. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.js +19 -13
  27. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.js.map +1 -1
  28. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.test.js +4 -9
  29. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.test.js.map +1 -1
  30. package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.d.ts +1 -0
  31. package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.d.ts.map +1 -1
  32. package/dist/esm/lib/hexclave-app/apps/interfaces/admin-app.js.map +1 -1
  33. package/dist/lib/auth.d.ts.map +1 -1
  34. package/dist/lib/auth.js +31 -10
  35. package/dist/lib/auth.js.map +1 -1
  36. package/dist/lib/auth.test.js +23 -8
  37. package/dist/lib/auth.test.js.map +1 -1
  38. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -0
  39. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  40. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.js +1 -0
  41. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.js.map +1 -1
  42. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +54 -0
  43. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  44. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +4 -1
  45. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  46. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +27 -3
  47. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  48. package/dist/lib/hexclave-app/apps/implementations/common.js +1 -1
  49. package/dist/lib/hexclave-app/apps/implementations/event-tracker.d.ts +1 -0
  50. package/dist/lib/hexclave-app/apps/implementations/event-tracker.d.ts.map +1 -1
  51. package/dist/lib/hexclave-app/apps/implementations/event-tracker.js +16 -12
  52. package/dist/lib/hexclave-app/apps/implementations/event-tracker.js.map +1 -1
  53. package/dist/lib/hexclave-app/apps/implementations/event-tracker.test.js +4 -8
  54. package/dist/lib/hexclave-app/apps/implementations/event-tracker.test.js.map +1 -1
  55. package/dist/lib/hexclave-app/apps/implementations/session-replay.d.ts +3 -1
  56. package/dist/lib/hexclave-app/apps/implementations/session-replay.d.ts.map +1 -1
  57. package/dist/lib/hexclave-app/apps/implementations/session-replay.js +19 -12
  58. package/dist/lib/hexclave-app/apps/implementations/session-replay.js.map +1 -1
  59. package/dist/lib/hexclave-app/apps/implementations/session-replay.test.js +4 -9
  60. package/dist/lib/hexclave-app/apps/implementations/session-replay.test.js.map +1 -1
  61. package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts +1 -0
  62. package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts.map +1 -1
  63. package/dist/lib/hexclave-app/apps/interfaces/admin-app.js.map +1 -1
  64. package/package.json +2 -2
  65. package/src/lib/auth.test.ts +32 -10
  66. package/src/lib/auth.ts +41 -7
  67. package/src/lib/hexclave-app/apps/implementations/admin-app-impl.ts +2 -1
  68. package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +66 -0
  69. package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +39 -3
  70. package/src/lib/hexclave-app/apps/implementations/event-tracker.test.ts +5 -13
  71. package/src/lib/hexclave-app/apps/implementations/event-tracker.ts +19 -14
  72. package/src/lib/hexclave-app/apps/implementations/session-replay.test.ts +4 -20
  73. package/src/lib/hexclave-app/apps/implementations/session-replay.ts +19 -12
  74. package/src/lib/hexclave-app/apps/interfaces/admin-app.ts +1 -0
package/README.md CHANGED
@@ -1,10 +1,190 @@
1
- # This package has been renamed.
1
+ # Hexclave
2
+ <div align="center">
2
3
 
3
- Stack Auth is now Hexclave! The new packages are:
4
+ <img src=".github/assets/hexclave-header.svg" alt="Hexclave" width="320"/>
4
5
 
5
- - @hexclave/next
6
- - @hexclave/react
7
- - @hexclave/js
8
- - @hexclave/cli
6
+ <br/>
9
7
 
10
- See the [migration guide](https://docs.hexclave.com/migration) for more information.
8
+ **The user infrastructure platform.**
9
+
10
+ Hexclave handles everything around your users: authentication, teams,
11
+ payments, emails, analytics, and much more. Start in minutes on the hosted
12
+ cloud. Your data is always yours to export and self-host.
13
+
14
+ [Website](https://hexclave.com) · [Docs](https://docs.hexclave.com) · [Dashboard](https://app.hexclave.com) · [Discord](https://discord.hexclave.com)
15
+
16
+ ![License](https://img.shields.io/badge/license-MIT%20%2F%20AGPLv3-blue)
17
+ ![SDKs](https://img.shields.io/badge/SDKs-Next.js%20%C2%B7%20React%20%C2%B7%20JS-black)
18
+ ![Deploy](https://img.shields.io/badge/deploy-Cloud%20or%20self--hosted-success)
19
+
20
+ </div>
21
+
22
+ ---
23
+
24
+ <div align="center">
25
+ <img src=".github/assets/comparison.png" alt="Where Hexclave fits in the infrastructure stack" width="900"/>
26
+ </div>
27
+
28
+ ## Get started
29
+
30
+ Setting up Hexclave is one prompt. Paste this into your coding agent of choice:
31
+
32
+ ```text
33
+ Read skill.hexclave.com and help me setup hexclave in this project
34
+ ```
35
+
36
+ ## For AI agents
37
+
38
+ If you're an AI coding agent, use your web fetch tool or curl the skill documentation for up-to-date integration instructions:
39
+
40
+ ```
41
+ curl -sSL "https://skill.hexclave.com?question=<your-question>&context=<your-context>"
42
+ ```
43
+
44
+ ## What's included
45
+
46
+ Hexclave ships as a catalog of apps you switch on as your product needs them.
47
+ Each one is built on the same user model, and new apps land regularly.
48
+
49
+ <table><tr>
50
+ <td width="50%" valign="middle">
51
+
52
+ ### <img src=".github/assets/logos/authentication.png" alt="" width="40" align="top"/> &nbsp; Authentication
53
+
54
+ Authentication that just works with passkeys, OAuth, and CLI auth. Drop in one component and ship the whole flow; auth methods toggle from the dashboard with no code changes needed.
55
+
56
+ </td>
57
+ <td width="50%" valign="middle" align="center">
58
+ <img src=".github/assets/app-shots/authentication.png" width="520" alt="Authentication"/>
59
+ </td>
60
+ </tr></table>
61
+
62
+ <table><tr>
63
+ <td width="50%" valign="middle">
64
+
65
+ ### <img src=".github/assets/logos/teams.png" alt="" width="40" align="top"/> &nbsp; Teams
66
+
67
+ Build for teams, not just users, with workspaces, email invites, and roles that actually gate the work. The workspace switcher remembers selection, invites auto sign up new users, and permissions hold up under audit.
68
+
69
+ </td>
70
+ <td width="50%" valign="middle" align="center">
71
+ <img src=".github/assets/app-shots/teams.png" width="520" alt="Teams"/>
72
+ </td>
73
+ </tr></table>
74
+
75
+ <table><tr>
76
+ <td width="50%" valign="middle">
77
+
78
+ ### <img src=".github/assets/logos/rbac.png" alt="" width="40" align="top"/> &nbsp; RBAC
79
+
80
+ Permissions, sorted: roles that nest and one permission check that works the same on server or client. Define them in the dashboard, check them anywhere in your code.
81
+
82
+ </td>
83
+ <td width="50%" valign="middle" align="center">
84
+ <img src=".github/assets/app-shots/rbac.png" width="520" alt="RBAC"/>
85
+ </td>
86
+ </tr></table>
87
+
88
+ <table><tr>
89
+ <td width="50%" valign="middle">
90
+
91
+ ### <img src=".github/assets/logos/api-keys.png" alt="" width="40" align="top"/> &nbsp; API Keys
92
+
93
+ API keys without the footguns: leaked keys get auto-revoked, work for users and teams, and show the full secret only once. We never keep the plaintext after creation.
94
+
95
+ </td>
96
+ <td width="50%" valign="middle" align="center">
97
+ <img src=".github/assets/app-shots/api-keys.png" width="520" alt="API Keys"/>
98
+ </td>
99
+ </tr></table>
100
+
101
+ <table><tr>
102
+ <td width="50%" valign="middle">
103
+
104
+ ### <img src=".github/assets/logos/payments.png" alt="" width="40" align="top"/> &nbsp; Payments
105
+
106
+ Payments without the plumbing for subscriptions, one-time charges, and usage metering with credits. Bill a person or a whole team with one model, no separate codepath.
107
+
108
+ </td>
109
+ <td width="50%" valign="middle" align="center">
110
+ <img src=".github/assets/app-shots/payments.png" width="520" alt="Payments"/>
111
+ </td>
112
+ </tr></table>
113
+
114
+ <table><tr>
115
+ <td width="50%" valign="middle">
116
+
117
+ ### <img src=".github/assets/logos/emails.png" alt="" width="40" align="top"/> &nbsp; Emails
118
+
119
+ Email that delivers and tells you so, handling transactional and marketing sends from one API. Edit templates with an AI editor, theme once, and track every open and click.
120
+
121
+ </td>
122
+ <td width="50%" valign="middle" align="center">
123
+ <img src=".github/assets/app-shots/emails.png" width="520" alt="Emails"/>
124
+ </td>
125
+ </tr></table>
126
+
127
+ <table><tr>
128
+ <td width="50%" valign="middle">
129
+
130
+ ### <img src=".github/assets/logos/analytics.png" alt="" width="40" align="top"/> &nbsp; Analytics
131
+
132
+ Know your users with no data stack required, with live active user counts and session replays out of the box. Ask in plain English to build dashboards or write SQL to save queries, all with one flag enabled.
133
+
134
+ </td>
135
+ <td width="50%" valign="middle" align="center">
136
+ <img src=".github/assets/app-shots/analytics.png" width="520" alt="Analytics"/>
137
+ </td>
138
+ </tr></table>
139
+
140
+ <table><tr>
141
+ <td width="50%" valign="middle">
142
+
143
+ ### <img src=".github/assets/logos/webhooks.png" alt="" width="40" align="top"/> &nbsp; Webhooks
144
+
145
+ React to every user event in real time with signed, tamper-proof webhooks. Retries and backoff are handled for you; verify in five lines and manage endpoints from the dashboard.
146
+
147
+ </td>
148
+ <td width="50%" valign="middle" align="center">
149
+ <img src=".github/assets/app-shots/webhooks.png" width="520" alt="Webhooks"/>
150
+ </td>
151
+ </tr></table>
152
+
153
+ <table><tr>
154
+ <td width="50%" valign="middle">
155
+
156
+ ### <img src=".github/assets/logos/data-vault.png" alt="" width="40" align="top"/> &nbsp; Data Vault
157
+
158
+ A safe for the secrets your users hand you, locked with your secret so we never see the plaintext. Store and retrieve tokens in two lines each, server-only by design.
159
+
160
+ </td>
161
+ <td width="50%" valign="middle" align="center">
162
+ <img src=".github/assets/app-shots/data-vault.png" width="520" alt="Data Vault"/>
163
+ </td>
164
+ </tr></table>
165
+
166
+ <table><tr>
167
+ <td width="50%" valign="middle">
168
+
169
+ ### <img src=".github/assets/logos/launch-checklist.png" alt="" width="40" align="top"/> &nbsp; Launch Checklist
170
+
171
+ Run through the must-do checks before flipping to production: domain setup, callbacks locked, secrets rotated. The progress tracker keeps your team aligned so nothing critical slips through on launch day.
172
+
173
+ </td>
174
+ <td width="50%" valign="middle" align="center">
175
+ <img src=".github/assets/app-shots/launch-checklist.png" width="520" alt="Launch Checklist"/>
176
+ </td>
177
+ </tr></table>
178
+
179
+ ## Contributing
180
+
181
+ Hexclave is open source, and contributions are welcome. Read
182
+ [`CONTRIBUTING.md`](./CONTRIBUTING.md) to get started, and say hello in
183
+ [Discord](https://discord.hexclave.com) before picking up anything large.
184
+ Found a security issue? Email security@hexclave.com.
185
+
186
+ ## ❤ Contributors
187
+
188
+ <a href="https://github.com/hexclave/hexclave/graphs/contributors">
189
+ <img src="https://contrib.rocks/image?repo=hexclave/hexclave&columns=9" alt="Contributors" width="100%" />
190
+ </a>
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","names":[],"sources":["../../../src/lib/auth.ts"],"mappings":";;;;iBAWsB,6BAAA,CACpB,KAAA,EAAO,uBAAA,EACP,OAAA;EACE,QAAA;EACA,WAAA;EACA,gBAAA;EACA,aAAA;AAAA,GAEF,OAAA,EAAS,eAAA,GACR,OAAA;AAAA,iBA0HmB,iBAAA,CACpB,KAAA,EAAO,uBAAA,EACP,WAAA,UACA,OAAA;EACE,+BAAA;AAAA,IACD,OAAA"}
1
+ {"version":3,"file":"auth.d.ts","names":[],"sources":["../../../src/lib/auth.ts"],"mappings":";;;;iBAWsB,6BAAA,CACpB,KAAA,EAAO,uBAAA,EACP,OAAA;EACE,QAAA;EACA,WAAA;EACA,gBAAA;EACA,aAAA;AAAA,GAEF,OAAA,EAAS,eAAA,GACR,OAAA;AAAA,iBA4JmB,iBAAA,CACpB,KAAA,EAAO,uBAAA,EACP,WAAA,UACA,OAAA;EACE,+BAAA;AAAA,IACD,OAAA"}
@@ -1,6 +1,6 @@
1
1
  import { deindent } from "@hexclave/shared/dist/utils/strings";
2
2
  import { HexclaveAssertionError, throwErr } from "@hexclave/shared/dist/utils/errors";
3
- import { KnownError } from "@hexclave/shared";
3
+ import { KnownError, KnownErrors } from "@hexclave/shared";
4
4
  import { Result } from "@hexclave/shared/dist/utils/results";
5
5
  import { constructRedirectUrl } from "../utils/url.js";
6
6
  import { consumeVerifierAndStateCookie, saveVerifierAndState } from "./cookie.js";
@@ -20,14 +20,29 @@ async function getNewOAuthProviderOrScopeUrl(iface, options, session) {
20
20
  providerScope: options.providerScope
21
21
  });
22
22
  }
23
+ const oauthErrorParams = [
24
+ "error",
25
+ "error_description",
26
+ "errorCode",
27
+ "message",
28
+ "details"
29
+ ];
30
+ function removeOAuthErrorParamsFromHistory(originalUrl) {
31
+ const newUrl = new URL(originalUrl);
32
+ for (const param of oauthErrorParams) newUrl.searchParams.delete(param);
33
+ window.history.replaceState({}, "", newUrl.toString());
34
+ }
35
+ function getProviderOAuthErrorFromUrl(originalUrl) {
36
+ const providerError = originalUrl.searchParams.get("error");
37
+ const providerErrorDescription = originalUrl.searchParams.get("error_description");
38
+ if (providerError == null && providerErrorDescription == null) return null;
39
+ switch (providerError) {
40
+ case "access_denied":
41
+ case "consent_required": return new KnownErrors.OAuthProviderAccessDenied();
42
+ default: return new KnownErrors.OAuthProviderTemporarilyUnavailable();
43
+ }
44
+ }
23
45
  function consumeOAuthCallbackQueryParams(options) {
24
- const oauthErrorParams = [
25
- "error",
26
- "error_description",
27
- "errorCode",
28
- "message",
29
- "details"
30
- ];
31
46
  const requiredParams = ["code", "state"];
32
47
  const originalUrl = new URL(window.location.href);
33
48
  const knownErrorCode = originalUrl.searchParams.get("errorCode");
@@ -43,9 +58,7 @@ function consumeOAuthCallbackQueryParams(options) {
43
58
  cause: error
44
59
  });
45
60
  }
46
- const newUrl = new URL(originalUrl);
47
- for (const param of oauthErrorParams) newUrl.searchParams.delete(param);
48
- window.history.replaceState({}, "", newUrl.toString());
61
+ removeOAuthErrorParamsFromHistory(originalUrl);
49
62
  return {
50
63
  type: "known-error",
51
64
  error: KnownError.fromJson({
@@ -55,6 +68,14 @@ function consumeOAuthCallbackQueryParams(options) {
55
68
  })
56
69
  };
57
70
  }
71
+ const providerOAuthError = getProviderOAuthErrorFromUrl(originalUrl);
72
+ if (providerOAuthError != null && !requiredParams.every((param) => originalUrl.searchParams.has(param))) {
73
+ removeOAuthErrorParamsFromHistory(originalUrl);
74
+ return {
75
+ type: "known-error",
76
+ error: providerOAuthError
77
+ };
78
+ }
58
79
  for (const param of requiredParams) if (!originalUrl.searchParams.has(param)) {
59
80
  if (!options?.dontWarnAboutMissingQueryParams) console.warn(/* @__PURE__ */ new Error(`Missing required query parameter on OAuth callback: ${param}. Maybe you opened or reloaded the oauth-callback page from your history?`));
60
81
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","names":[],"sources":["../../../src/lib/auth.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { KnownError, HexclaveClientInterface } from \"@hexclave/shared\";\nimport { InternalSession } from \"@hexclave/shared/dist/sessions\";\nimport { HexclaveAssertionError, throwErr } from \"@hexclave/shared/dist/utils/errors\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\nimport { deindent } from \"@hexclave/shared/dist/utils/strings\";\nimport { constructRedirectUrl } from \"../utils/url\";\nimport { consumeVerifierAndStateCookie, saveVerifierAndState } from \"./cookie\";\nexport async function getNewOAuthProviderOrScopeUrl(\n iface: HexclaveClientInterface,\n options: {\n provider: string,\n redirectUrl: string,\n errorRedirectUrl: string,\n providerScope?: string,\n },\n session: InternalSession,\n): Promise<string> {\n const { codeChallenge, state } = await saveVerifierAndState();\n return await iface.getOAuthUrl({\n provider: options.provider,\n redirectUrl: constructRedirectUrl(options.redirectUrl, \"redirectUrl\"),\n errorRedirectUrl: constructRedirectUrl(options.errorRedirectUrl, \"errorRedirectUrl\"),\n afterCallbackRedirectUrl: constructRedirectUrl(window.location.href, \"afterCallbackRedirectUrl\"),\n codeChallenge,\n state,\n type: \"link\",\n session,\n providerScope: options.providerScope,\n });\n}\n\n/**\n * Checks if the current URL has the query parameters for an OAuth callback, and if so, removes them.\n *\n * Must be synchronous for the logic in callOAuthCallback to work without race conditions.\n */\ntype OAuthCallbackConsumptionResult =\n | {\n type: \"oauth-response\",\n originalUrl: URL,\n codeVerifier: string,\n state: string,\n }\n | {\n type: \"known-error\",\n error: KnownError,\n };\n\nfunction consumeOAuthCallbackQueryParams(options?: {\n dontWarnAboutMissingQueryParams?: boolean,\n}): OAuthCallbackConsumptionResult | null {\n const oauthErrorParams = [\"error\", \"error_description\", \"errorCode\", \"message\", \"details\"] as const;\n const requiredParams = [\"code\", \"state\"];\n const originalUrl = new URL(window.location.href);\n const knownErrorCode = originalUrl.searchParams.get(\"errorCode\");\n const knownErrorMessage = originalUrl.searchParams.get(\"message\");\n if (knownErrorCode && knownErrorMessage) {\n const details = originalUrl.searchParams.get(\"details\");\n let detailsJson = {};\n if (details) {\n try {\n detailsJson = JSON.parse(details);\n } catch (error) {\n throw new HexclaveAssertionError(\"OAuth callback returned malformed known-error details\", {\n details,\n cause: error,\n });\n }\n }\n\n const newUrl = new URL(originalUrl);\n for (const param of oauthErrorParams) {\n newUrl.searchParams.delete(param);\n }\n window.history.replaceState({}, \"\", newUrl.toString());\n\n return {\n type: \"known-error\",\n error: KnownError.fromJson({\n code: knownErrorCode,\n message: knownErrorMessage,\n details: detailsJson,\n }),\n };\n }\n\n for (const param of requiredParams) {\n if (!originalUrl.searchParams.has(param)) {\n if (!options?.dontWarnAboutMissingQueryParams) {\n console.warn(new Error(`Missing required query parameter on OAuth callback: ${param}. Maybe you opened or reloaded the oauth-callback page from your history?`));\n }\n return null;\n }\n }\n\n const expectedState = originalUrl.searchParams.get(\"state\") ?? throwErr(\"This should never happen; isn't state required above?\");\n const cookieResult = consumeVerifierAndStateCookie(expectedState);\n\n if (!cookieResult) {\n // If the state can't be found in the cookies, then the callback wasn't meant for us.\n // Maybe the website uses another OAuth library?\n console.warn(deindent`\n Stack found an outer OAuth callback state in the query parameters, but not in cookies.\n\n This could have multiple reasons:\n - The cookie expired, because the OAuth flow took too long.\n - The user's browser deleted the cookie, either manually or because of a very strict cookie policy.\n - The cookie was already consumed by this page, and the user already logged in.\n - You are using another OAuth client library with the same callback URL as Stack.\n - The user opened the OAuth callback page from their history.\n\n Either way, it is probably safe to ignore this warning unless you are debugging an OAuth issue.\n `);\n return null;\n }\n\n\n const newUrl = new URL(originalUrl);\n for (const param of requiredParams) {\n newUrl.searchParams.delete(param);\n }\n\n // let's get rid of the authorization code in the history as we\n // don't redirect to `redirectUrl` if there's a validation error\n // (as the redirectUrl might be malicious!).\n //\n // We use history.replaceState instead of location.assign(...) to\n // prevent an unnecessary reload\n window.history.replaceState({}, \"\", newUrl.toString());\n\n return {\n type: \"oauth-response\",\n originalUrl,\n codeVerifier: cookieResult.codeVerifier,\n state: expectedState,\n };\n}\n\nexport async function callOAuthCallback(\n iface: HexclaveClientInterface,\n redirectUrl: string,\n options?: {\n dontWarnAboutMissingQueryParams?: boolean,\n },\n) {\n // note: this part of the function (until the return) needs\n // to be synchronous, to prevent race conditions when\n // callOAuthCallback is called multiple times in parallel\n const consumed = consumeOAuthCallbackQueryParams(options);\n if (!consumed) return Result.ok(undefined);\n if (consumed.type === \"known-error\") {\n throw consumed.error;\n }\n\n // the rest can be asynchronous (we now know that we are the\n // intended recipient of the callback, and the only instance\n // of callOAuthCallback that's running)\n try {\n return Result.ok(await iface.callOAuthCallback({\n oauthParams: consumed.originalUrl.searchParams,\n redirectUri: constructRedirectUrl(redirectUrl, \"redirectUri\"),\n codeVerifier: consumed.codeVerifier,\n state: consumed.state,\n }));\n } catch (e) {\n if (KnownError.isKnownError(e)) {\n throw e;\n }\n throw new HexclaveAssertionError(\"Error signing in during OAuth callback. Please try again.\", { cause: e });\n }\n}\n"],"mappings":";;;;;;;;AAWA,eAAsB,8BACpB,OACA,SAMA,SACiB;CACjB,MAAM,EAAE,eAAe,UAAU,MAAM,sBAAsB;AAC7D,QAAO,MAAM,MAAM,YAAY;EAC7B,UAAU,QAAQ;EAClB,aAAa,qBAAqB,QAAQ,aAAa,cAAc;EACrE,kBAAkB,qBAAqB,QAAQ,kBAAkB,mBAAmB;EACpF,0BAA0B,qBAAqB,OAAO,SAAS,MAAM,2BAA2B;EAChG;EACA;EACA,MAAM;EACN;EACA,eAAe,QAAQ;EACxB,CAAC;;AAoBJ,SAAS,gCAAgC,SAEC;CACxC,MAAM,mBAAmB;EAAC;EAAS;EAAqB;EAAa;EAAW;EAAU;CAC1F,MAAM,iBAAiB,CAAC,QAAQ,QAAQ;CACxC,MAAM,cAAc,IAAI,IAAI,OAAO,SAAS,KAAK;CACjD,MAAM,iBAAiB,YAAY,aAAa,IAAI,YAAY;CAChE,MAAM,oBAAoB,YAAY,aAAa,IAAI,UAAU;AACjE,KAAI,kBAAkB,mBAAmB;EACvC,MAAM,UAAU,YAAY,aAAa,IAAI,UAAU;EACvD,IAAI,cAAc,EAAE;AACpB,MAAI,QACF,KAAI;AACF,iBAAc,KAAK,MAAM,QAAQ;WAC1B,OAAO;AACd,SAAM,IAAI,uBAAuB,yDAAyD;IACxF;IACA,OAAO;IACR,CAAC;;EAIN,MAAM,SAAS,IAAI,IAAI,YAAY;AACnC,OAAK,MAAM,SAAS,iBAClB,QAAO,aAAa,OAAO,MAAM;AAEnC,SAAO,QAAQ,aAAa,EAAE,EAAE,IAAI,OAAO,UAAU,CAAC;AAEtD,SAAO;GACL,MAAM;GACN,OAAO,WAAW,SAAS;IACzB,MAAM;IACN,SAAS;IACT,SAAS;IACV,CAAC;GACH;;AAGH,MAAK,MAAM,SAAS,eAClB,KAAI,CAAC,YAAY,aAAa,IAAI,MAAM,EAAE;AACxC,MAAI,CAAC,SAAS,gCACZ,SAAQ,qBAAK,IAAI,MAAM,uDAAuD,MAAM,2EAA2E,CAAC;AAElK,SAAO;;CAIX,MAAM,gBAAgB,YAAY,aAAa,IAAI,QAAQ,IAAI,SAAS,wDAAwD;CAChI,MAAM,eAAe,8BAA8B,cAAc;AAEjE,KAAI,CAAC,cAAc;AAGjB,UAAQ,KAAK,QAAQ;;;;;;;;;;;MAWnB;AACF,SAAO;;CAIT,MAAM,SAAS,IAAI,IAAI,YAAY;AACnC,MAAK,MAAM,SAAS,eAClB,QAAO,aAAa,OAAO,MAAM;AASnC,QAAO,QAAQ,aAAa,EAAE,EAAE,IAAI,OAAO,UAAU,CAAC;AAEtD,QAAO;EACL,MAAM;EACN;EACA,cAAc,aAAa;EAC3B,OAAO;EACR;;AAGH,eAAsB,kBACpB,OACA,aACA,SAGA;CAIA,MAAM,WAAW,gCAAgC,QAAQ;AACzD,KAAI,CAAC,SAAU,QAAO,OAAO,GAAG,OAAU;AAC1C,KAAI,SAAS,SAAS,cACpB,OAAM,SAAS;AAMjB,KAAI;AACF,SAAO,OAAO,GAAG,MAAM,MAAM,kBAAkB;GAC7C,aAAa,SAAS,YAAY;GAClC,aAAa,qBAAqB,aAAa,cAAc;GAC7D,cAAc,SAAS;GACvB,OAAO,SAAS;GACjB,CAAC,CAAC;UACI,GAAG;AACV,MAAI,WAAW,aAAa,EAAE,CAC5B,OAAM;AAER,QAAM,IAAI,uBAAuB,6DAA6D,EAAE,OAAO,GAAG,CAAC"}
1
+ {"version":3,"file":"auth.js","names":[],"sources":["../../../src/lib/auth.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { KnownError, KnownErrors, HexclaveClientInterface } from \"@hexclave/shared\";\nimport { InternalSession } from \"@hexclave/shared/dist/sessions\";\nimport { HexclaveAssertionError, throwErr } from \"@hexclave/shared/dist/utils/errors\";\nimport { Result } from \"@hexclave/shared/dist/utils/results\";\nimport { deindent } from \"@hexclave/shared/dist/utils/strings\";\nimport { constructRedirectUrl } from \"../utils/url\";\nimport { consumeVerifierAndStateCookie, saveVerifierAndState } from \"./cookie\";\nexport async function getNewOAuthProviderOrScopeUrl(\n iface: HexclaveClientInterface,\n options: {\n provider: string,\n redirectUrl: string,\n errorRedirectUrl: string,\n providerScope?: string,\n },\n session: InternalSession,\n): Promise<string> {\n const { codeChallenge, state } = await saveVerifierAndState();\n return await iface.getOAuthUrl({\n provider: options.provider,\n redirectUrl: constructRedirectUrl(options.redirectUrl, \"redirectUrl\"),\n errorRedirectUrl: constructRedirectUrl(options.errorRedirectUrl, \"errorRedirectUrl\"),\n afterCallbackRedirectUrl: constructRedirectUrl(window.location.href, \"afterCallbackRedirectUrl\"),\n codeChallenge,\n state,\n type: \"link\",\n session,\n providerScope: options.providerScope,\n });\n}\n\n/**\n * Checks if the current URL has the query parameters for an OAuth callback, and if so, removes them.\n *\n * Must be synchronous for the logic in callOAuthCallback to work without race conditions.\n */\ntype OAuthCallbackConsumptionResult =\n | {\n type: \"oauth-response\",\n originalUrl: URL,\n codeVerifier: string,\n state: string,\n }\n | {\n type: \"known-error\",\n error: KnownError,\n };\n\nconst oauthErrorParams = [\"error\", \"error_description\", \"errorCode\", \"message\", \"details\"] as const;\n\nfunction removeOAuthErrorParamsFromHistory(originalUrl: URL): void {\n const newUrl = new URL(originalUrl);\n for (const param of oauthErrorParams) {\n newUrl.searchParams.delete(param);\n }\n window.history.replaceState({}, \"\", newUrl.toString());\n}\n\nfunction getProviderOAuthErrorFromUrl(originalUrl: URL): KnownError | null {\n const providerError = originalUrl.searchParams.get(\"error\");\n const providerErrorDescription = originalUrl.searchParams.get(\"error_description\");\n if (providerError == null && providerErrorDescription == null) {\n return null;\n }\n\n switch (providerError) {\n case \"access_denied\":\n case \"consent_required\": {\n return new KnownErrors.OAuthProviderAccessDenied();\n }\n case \"server_error\":\n case \"temporarily_unavailable\":\n default: {\n return new KnownErrors.OAuthProviderTemporarilyUnavailable();\n }\n }\n}\n\nfunction consumeOAuthCallbackQueryParams(options?: {\n dontWarnAboutMissingQueryParams?: boolean,\n}): OAuthCallbackConsumptionResult | null {\n const requiredParams = [\"code\", \"state\"];\n const originalUrl = new URL(window.location.href);\n const knownErrorCode = originalUrl.searchParams.get(\"errorCode\");\n const knownErrorMessage = originalUrl.searchParams.get(\"message\");\n if (knownErrorCode && knownErrorMessage) {\n const details = originalUrl.searchParams.get(\"details\");\n let detailsJson = {};\n if (details) {\n try {\n detailsJson = JSON.parse(details);\n } catch (error) {\n throw new HexclaveAssertionError(\"OAuth callback returned malformed known-error details\", {\n details,\n cause: error,\n });\n }\n }\n\n removeOAuthErrorParamsFromHistory(originalUrl);\n\n return {\n type: \"known-error\",\n error: KnownError.fromJson({\n code: knownErrorCode,\n message: knownErrorMessage,\n details: detailsJson,\n }),\n };\n }\n\n const providerOAuthError = getProviderOAuthErrorFromUrl(originalUrl);\n if (providerOAuthError != null && !requiredParams.every(param => originalUrl.searchParams.has(param))) {\n removeOAuthErrorParamsFromHistory(originalUrl);\n return {\n type: \"known-error\",\n error: providerOAuthError,\n };\n }\n\n for (const param of requiredParams) {\n if (!originalUrl.searchParams.has(param)) {\n if (!options?.dontWarnAboutMissingQueryParams) {\n console.warn(new Error(`Missing required query parameter on OAuth callback: ${param}. Maybe you opened or reloaded the oauth-callback page from your history?`));\n }\n return null;\n }\n }\n\n const expectedState = originalUrl.searchParams.get(\"state\") ?? throwErr(\"This should never happen; isn't state required above?\");\n const cookieResult = consumeVerifierAndStateCookie(expectedState);\n\n if (!cookieResult) {\n // If the state can't be found in the cookies, then the callback wasn't meant for us.\n // Maybe the website uses another OAuth library?\n console.warn(deindent`\n Stack found an outer OAuth callback state in the query parameters, but not in cookies.\n\n This could have multiple reasons:\n - The cookie expired, because the OAuth flow took too long.\n - The user's browser deleted the cookie, either manually or because of a very strict cookie policy.\n - The cookie was already consumed by this page, and the user already logged in.\n - You are using another OAuth client library with the same callback URL as Stack.\n - The user opened the OAuth callback page from their history.\n\n Either way, it is probably safe to ignore this warning unless you are debugging an OAuth issue.\n `);\n return null;\n }\n\n\n const newUrl = new URL(originalUrl);\n for (const param of requiredParams) {\n newUrl.searchParams.delete(param);\n }\n\n // let's get rid of the authorization code in the history as we\n // don't redirect to `redirectUrl` if there's a validation error\n // (as the redirectUrl might be malicious!).\n //\n // We use history.replaceState instead of location.assign(...) to\n // prevent an unnecessary reload\n window.history.replaceState({}, \"\", newUrl.toString());\n\n return {\n type: \"oauth-response\",\n originalUrl,\n codeVerifier: cookieResult.codeVerifier,\n state: expectedState,\n };\n}\n\nexport async function callOAuthCallback(\n iface: HexclaveClientInterface,\n redirectUrl: string,\n options?: {\n dontWarnAboutMissingQueryParams?: boolean,\n },\n) {\n // note: this part of the function (until the return) needs\n // to be synchronous, to prevent race conditions when\n // callOAuthCallback is called multiple times in parallel\n const consumed = consumeOAuthCallbackQueryParams(options);\n if (!consumed) return Result.ok(undefined);\n if (consumed.type === \"known-error\") {\n throw consumed.error;\n }\n\n // the rest can be asynchronous (we now know that we are the\n // intended recipient of the callback, and the only instance\n // of callOAuthCallback that's running)\n try {\n return Result.ok(await iface.callOAuthCallback({\n oauthParams: consumed.originalUrl.searchParams,\n redirectUri: constructRedirectUrl(redirectUrl, \"redirectUri\"),\n codeVerifier: consumed.codeVerifier,\n state: consumed.state,\n }));\n } catch (e) {\n if (KnownError.isKnownError(e)) {\n throw e;\n }\n throw new HexclaveAssertionError(\"Error signing in during OAuth callback. Please try again.\", { cause: e });\n }\n}\n"],"mappings":";;;;;;;;AAWA,eAAsB,8BACpB,OACA,SAMA,SACiB;CACjB,MAAM,EAAE,eAAe,UAAU,MAAM,sBAAsB;AAC7D,QAAO,MAAM,MAAM,YAAY;EAC7B,UAAU,QAAQ;EAClB,aAAa,qBAAqB,QAAQ,aAAa,cAAc;EACrE,kBAAkB,qBAAqB,QAAQ,kBAAkB,mBAAmB;EACpF,0BAA0B,qBAAqB,OAAO,SAAS,MAAM,2BAA2B;EAChG;EACA;EACA,MAAM;EACN;EACA,eAAe,QAAQ;EACxB,CAAC;;AAoBJ,MAAM,mBAAmB;CAAC;CAAS;CAAqB;CAAa;CAAW;CAAU;AAE1F,SAAS,kCAAkC,aAAwB;CACjE,MAAM,SAAS,IAAI,IAAI,YAAY;AACnC,MAAK,MAAM,SAAS,iBAClB,QAAO,aAAa,OAAO,MAAM;AAEnC,QAAO,QAAQ,aAAa,EAAE,EAAE,IAAI,OAAO,UAAU,CAAC;;AAGxD,SAAS,6BAA6B,aAAqC;CACzE,MAAM,gBAAgB,YAAY,aAAa,IAAI,QAAQ;CAC3D,MAAM,2BAA2B,YAAY,aAAa,IAAI,oBAAoB;AAClF,KAAI,iBAAiB,QAAQ,4BAA4B,KACvD,QAAO;AAGT,SAAQ,eAAR;EACE,KAAK;EACL,KAAK,mBACH,QAAO,IAAI,YAAY,2BAA2B;EAIpD,QACE,QAAO,IAAI,YAAY,qCAAqC;;;AAKlE,SAAS,gCAAgC,SAEC;CACxC,MAAM,iBAAiB,CAAC,QAAQ,QAAQ;CACxC,MAAM,cAAc,IAAI,IAAI,OAAO,SAAS,KAAK;CACjD,MAAM,iBAAiB,YAAY,aAAa,IAAI,YAAY;CAChE,MAAM,oBAAoB,YAAY,aAAa,IAAI,UAAU;AACjE,KAAI,kBAAkB,mBAAmB;EACvC,MAAM,UAAU,YAAY,aAAa,IAAI,UAAU;EACvD,IAAI,cAAc,EAAE;AACpB,MAAI,QACF,KAAI;AACF,iBAAc,KAAK,MAAM,QAAQ;WAC1B,OAAO;AACd,SAAM,IAAI,uBAAuB,yDAAyD;IACxF;IACA,OAAO;IACR,CAAC;;AAIN,oCAAkC,YAAY;AAE9C,SAAO;GACL,MAAM;GACN,OAAO,WAAW,SAAS;IACzB,MAAM;IACN,SAAS;IACT,SAAS;IACV,CAAC;GACH;;CAGH,MAAM,qBAAqB,6BAA6B,YAAY;AACpE,KAAI,sBAAsB,QAAQ,CAAC,eAAe,OAAM,UAAS,YAAY,aAAa,IAAI,MAAM,CAAC,EAAE;AACrG,oCAAkC,YAAY;AAC9C,SAAO;GACL,MAAM;GACN,OAAO;GACR;;AAGH,MAAK,MAAM,SAAS,eAClB,KAAI,CAAC,YAAY,aAAa,IAAI,MAAM,EAAE;AACxC,MAAI,CAAC,SAAS,gCACZ,SAAQ,qBAAK,IAAI,MAAM,uDAAuD,MAAM,2EAA2E,CAAC;AAElK,SAAO;;CAIX,MAAM,gBAAgB,YAAY,aAAa,IAAI,QAAQ,IAAI,SAAS,wDAAwD;CAChI,MAAM,eAAe,8BAA8B,cAAc;AAEjE,KAAI,CAAC,cAAc;AAGjB,UAAQ,KAAK,QAAQ;;;;;;;;;;;MAWnB;AACF,SAAO;;CAIT,MAAM,SAAS,IAAI,IAAI,YAAY;AACnC,MAAK,MAAM,SAAS,eAClB,QAAO,aAAa,OAAO,MAAM;AASnC,QAAO,QAAQ,aAAa,EAAE,EAAE,IAAI,OAAO,UAAU,CAAC;AAEtD,QAAO;EACL,MAAM;EACN;EACA,cAAc,aAAa;EAC3B,OAAO;EACR;;AAGH,eAAsB,kBACpB,OACA,aACA,SAGA;CAIA,MAAM,WAAW,gCAAgC,QAAQ;AACzD,KAAI,CAAC,SAAU,QAAO,OAAO,GAAG,OAAU;AAC1C,KAAI,SAAS,SAAS,cACpB,OAAM,SAAS;AAMjB,KAAI;AACF,SAAO,OAAO,GAAG,MAAM,MAAM,kBAAkB;GAC7C,aAAa,SAAS,YAAY;GAClC,aAAa,qBAAqB,aAAa,cAAc;GAC7D,cAAc,SAAS;GACvB,OAAO,SAAS;GACjB,CAAC,CAAC;UACI,GAAG;AACV,MAAI,WAAW,aAAa,EAAE,CAC5B,OAAM;AAER,QAAM,IAAI,uBAAuB,6DAA6D,EAAE,OAAO,GAAG,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it, vi } from "vitest";
2
- import { HexclaveClientInterface } from "@hexclave/shared";
3
- import { getNewOAuthProviderOrScopeUrl } from "./auth.js";
2
+ import { HexclaveClientInterface, KnownErrors } from "@hexclave/shared";
3
+ import { callOAuthCallback, getNewOAuthProviderOrScopeUrl } from "./auth.js";
4
4
 
5
5
  //#region src/lib/auth.test.ts
6
6
  // @vitest-environment jsdom
@@ -13,17 +13,20 @@ vi.mock("./cookie", async (importOriginal) => {
13
13
  })
14
14
  };
15
15
  });
16
+ function createTestInterface() {
17
+ return new HexclaveClientInterface({
18
+ clientVersion: "test",
19
+ getBaseUrl: () => "https://api.example.com",
20
+ getApiUrls: () => ["https://api.example.com"],
21
+ extraRequestHeaders: {},
22
+ projectId: "00000000-0000-4000-8000-000000000000",
23
+ publishableClientKey: "pck_test"
24
+ });
25
+ }
16
26
  describe("getNewOAuthProviderOrScopeUrl", () => {
17
27
  it("returns the OAuth URL without performing navigation", async () => {
18
28
  window.history.replaceState({}, "", "/account?after_auth_return_to=%2Fsettings");
19
- const iface = new HexclaveClientInterface({
20
- clientVersion: "test",
21
- getBaseUrl: () => "https://api.example.com",
22
- getApiUrls: () => ["https://api.example.com"],
23
- extraRequestHeaders: {},
24
- projectId: "00000000-0000-4000-8000-000000000000",
25
- publishableClientKey: "pck_test"
26
- });
29
+ const iface = createTestInterface();
27
30
  const location = await getNewOAuthProviderOrScopeUrl(iface, {
28
31
  provider: "github",
29
32
  redirectUrl: "/handler/oauth-callback",
@@ -54,6 +57,18 @@ describe("getNewOAuthProviderOrScopeUrl", () => {
54
57
  `);
55
58
  });
56
59
  });
60
+ describe("callOAuthCallback", () => {
61
+ it("turns provider access denial callback params into a known error", async () => {
62
+ window.history.replaceState({}, "", "/handler/oauth-callback?error=access_denied&error_description=User+cancelled");
63
+ await expect(callOAuthCallback(createTestInterface(), "/handler/oauth-callback")).rejects.toSatisfy((error) => KnownErrors.OAuthProviderAccessDenied.isInstance(error));
64
+ expect(window.location.href).toBe("http://localhost:3000/handler/oauth-callback");
65
+ });
66
+ it("turns generic provider error callback params into a known error", async () => {
67
+ window.history.replaceState({}, "", "/handler/oauth-callback?error=server_error&error_description=Provider+failed");
68
+ await expect(callOAuthCallback(createTestInterface(), "/handler/oauth-callback")).rejects.toSatisfy((error) => KnownErrors.OAuthProviderTemporarilyUnavailable.isInstance(error));
69
+ expect(window.location.href).toBe("http://localhost:3000/handler/oauth-callback");
70
+ });
71
+ });
57
72
 
58
73
  //#endregion
59
74
  export { };
@@ -1 +1 @@
1
- {"version":3,"file":"auth.test.js","names":[],"sources":["../../../src/lib/auth.test.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n// @vitest-environment jsdom\n\nimport { HexclaveClientInterface } from \"@hexclave/shared\";\nimport { describe, expect, it, vi } from \"vitest\";\nimport { getNewOAuthProviderOrScopeUrl } from \"./auth\";\n\nvi.mock(\"./cookie\", async (importOriginal) => {\n const actual = await importOriginal<typeof import(\"./cookie\")>();\n return {\n ...actual,\n saveVerifierAndState: async () => ({\n codeChallenge: \"<stripped code challenge>\",\n state: \"<stripped state>\",\n }),\n };\n});\n\ndescribe(\"getNewOAuthProviderOrScopeUrl\", () => {\n it(\"returns the OAuth URL without performing navigation\", async () => {\n window.history.replaceState({}, \"\", \"/account?after_auth_return_to=%2Fsettings\");\n\n const iface = new HexclaveClientInterface({\n clientVersion: \"test\",\n getBaseUrl: () => \"https://api.example.com\",\n getApiUrls: () => [\"https://api.example.com\"],\n extraRequestHeaders: {},\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"pck_test\",\n });\n const session = iface.createSession({ refreshToken: null, accessToken: null });\n\n const location = await getNewOAuthProviderOrScopeUrl(\n iface,\n {\n provider: \"github\",\n redirectUrl: \"/handler/oauth-callback\",\n errorRedirectUrl: \"/handler/error\",\n providerScope: \"repo user\",\n },\n session,\n );\n\n const url = new URL(location);\n expect(`${url.origin}${url.pathname}`).toBe(\"https://api.example.com/api/v1/auth/oauth/authorize/github\");\n expect(Object.fromEntries(url.searchParams.entries())).toMatchInlineSnapshot(`\n {\n \"after_callback_redirect_url\": \"http://localhost:3000/account?after_auth_return_to=%2Fsettings\",\n \"client_id\": \"00000000-0000-4000-8000-000000000000\",\n \"client_secret\": \"pck_test\",\n \"code_challenge\": \"<stripped code challenge>\",\n \"code_challenge_method\": \"S256\",\n \"error_redirect_url\": \"http://localhost:3000/handler/error?after_auth_return_to=%2Fsettings\",\n \"grant_type\": \"authorization_code\",\n \"provider_scope\": \"repo user\",\n \"redirect_uri\": \"http://localhost:3000/handler/oauth-callback?after_auth_return_to=%2Fsettings\",\n \"response_type\": \"code\",\n \"scope\": \"legacy\",\n \"state\": \"<stripped state>\",\n \"type\": \"link\",\n }\n `);\n });\n});\n"],"mappings":";;;;;;AAUA,GAAG,KAAK,YAAY,OAAO,mBAAmB;AAE5C,QAAO;EACL,GAFa,MAAM,gBAA2C;EAG9D,sBAAsB,aAAa;GACjC,eAAe;GACf,OAAO;GACR;EACF;EACD;AAEF,SAAS,uCAAuC;AAC9C,IAAG,uDAAuD,YAAY;AACpE,SAAO,QAAQ,aAAa,EAAE,EAAE,IAAI,4CAA4C;EAEhF,MAAM,QAAQ,IAAI,wBAAwB;GACxC,eAAe;GACf,kBAAkB;GAClB,kBAAkB,CAAC,0BAA0B;GAC7C,qBAAqB,EAAE;GACvB,WAAW;GACX,sBAAsB;GACvB,CAAC;EAGF,MAAM,WAAW,MAAM,8BACrB,OACA;GACE,UAAU;GACV,aAAa;GACb,kBAAkB;GAClB,eAAe;GAChB,EATa,MAAM,cAAc;GAAE,cAAc;GAAM,aAAa;GAAM,CAAC,CAW7E;EAED,MAAM,MAAM,IAAI,IAAI,SAAS;AAC7B,SAAO,GAAG,IAAI,SAAS,IAAI,WAAW,CAAC,KAAK,6DAA6D;AACzG,SAAO,OAAO,YAAY,IAAI,aAAa,SAAS,CAAC,CAAC,CAAC,sBAAsB;;;;;;;;;;;;;;;;MAgB3E;GACF;EACF"}
1
+ {"version":3,"file":"auth.test.js","names":[],"sources":["../../../src/lib/auth.test.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n// @vitest-environment jsdom\n\nimport { HexclaveClientInterface, KnownErrors } from \"@hexclave/shared\";\nimport { describe, expect, it, vi } from \"vitest\";\nimport { callOAuthCallback, getNewOAuthProviderOrScopeUrl } from \"./auth\";\n\nvi.mock(\"./cookie\", async (importOriginal) => {\n const actual = await importOriginal<typeof import(\"./cookie\")>();\n return {\n ...actual,\n saveVerifierAndState: async () => ({\n codeChallenge: \"<stripped code challenge>\",\n state: \"<stripped state>\",\n }),\n };\n});\n\nfunction createTestInterface() {\n return new HexclaveClientInterface({\n clientVersion: \"test\",\n getBaseUrl: () => \"https://api.example.com\",\n getApiUrls: () => [\"https://api.example.com\"],\n extraRequestHeaders: {},\n projectId: \"00000000-0000-4000-8000-000000000000\",\n publishableClientKey: \"pck_test\",\n });\n}\n\ndescribe(\"getNewOAuthProviderOrScopeUrl\", () => {\n it(\"returns the OAuth URL without performing navigation\", async () => {\n window.history.replaceState({}, \"\", \"/account?after_auth_return_to=%2Fsettings\");\n\n const iface = createTestInterface();\n const session = iface.createSession({ refreshToken: null, accessToken: null });\n\n const location = await getNewOAuthProviderOrScopeUrl(\n iface,\n {\n provider: \"github\",\n redirectUrl: \"/handler/oauth-callback\",\n errorRedirectUrl: \"/handler/error\",\n providerScope: \"repo user\",\n },\n session,\n );\n\n const url = new URL(location);\n expect(`${url.origin}${url.pathname}`).toBe(\"https://api.example.com/api/v1/auth/oauth/authorize/github\");\n expect(Object.fromEntries(url.searchParams.entries())).toMatchInlineSnapshot(`\n {\n \"after_callback_redirect_url\": \"http://localhost:3000/account?after_auth_return_to=%2Fsettings\",\n \"client_id\": \"00000000-0000-4000-8000-000000000000\",\n \"client_secret\": \"pck_test\",\n \"code_challenge\": \"<stripped code challenge>\",\n \"code_challenge_method\": \"S256\",\n \"error_redirect_url\": \"http://localhost:3000/handler/error?after_auth_return_to=%2Fsettings\",\n \"grant_type\": \"authorization_code\",\n \"provider_scope\": \"repo user\",\n \"redirect_uri\": \"http://localhost:3000/handler/oauth-callback?after_auth_return_to=%2Fsettings\",\n \"response_type\": \"code\",\n \"scope\": \"legacy\",\n \"state\": \"<stripped state>\",\n \"type\": \"link\",\n }\n `);\n });\n});\n\ndescribe(\"callOAuthCallback\", () => {\n it(\"turns provider access denial callback params into a known error\", async () => {\n window.history.replaceState({}, \"\", \"/handler/oauth-callback?error=access_denied&error_description=User+cancelled\");\n\n await expect(callOAuthCallback(createTestInterface(), \"/handler/oauth-callback\"))\n .rejects.toSatisfy((error: unknown) => KnownErrors.OAuthProviderAccessDenied.isInstance(error));\n expect(window.location.href).toBe(\"http://localhost:3000/handler/oauth-callback\");\n });\n\n it(\"turns generic provider error callback params into a known error\", async () => {\n window.history.replaceState({}, \"\", \"/handler/oauth-callback?error=server_error&error_description=Provider+failed\");\n\n await expect(callOAuthCallback(createTestInterface(), \"/handler/oauth-callback\"))\n .rejects.toSatisfy((error: unknown) => KnownErrors.OAuthProviderTemporarilyUnavailable.isInstance(error));\n expect(window.location.href).toBe(\"http://localhost:3000/handler/oauth-callback\");\n });\n});\n"],"mappings":";;;;;;AAUA,GAAG,KAAK,YAAY,OAAO,mBAAmB;AAE5C,QAAO;EACL,GAFa,MAAM,gBAA2C;EAG9D,sBAAsB,aAAa;GACjC,eAAe;GACf,OAAO;GACR;EACF;EACD;AAEF,SAAS,sBAAsB;AAC7B,QAAO,IAAI,wBAAwB;EACjC,eAAe;EACf,kBAAkB;EAClB,kBAAkB,CAAC,0BAA0B;EAC7C,qBAAqB,EAAE;EACvB,WAAW;EACX,sBAAsB;EACvB,CAAC;;AAGJ,SAAS,uCAAuC;AAC9C,IAAG,uDAAuD,YAAY;AACpE,SAAO,QAAQ,aAAa,EAAE,EAAE,IAAI,4CAA4C;EAEhF,MAAM,QAAQ,qBAAqB;EAGnC,MAAM,WAAW,MAAM,8BACrB,OACA;GACE,UAAU;GACV,aAAa;GACb,kBAAkB;GAClB,eAAe;GAChB,EATa,MAAM,cAAc;GAAE,cAAc;GAAM,aAAa;GAAM,CAAC,CAW7E;EAED,MAAM,MAAM,IAAI,IAAI,SAAS;AAC7B,SAAO,GAAG,IAAI,SAAS,IAAI,WAAW,CAAC,KAAK,6DAA6D;AACzG,SAAO,OAAO,YAAY,IAAI,aAAa,SAAS,CAAC,CAAC,CAAC,sBAAsB;;;;;;;;;;;;;;;;MAgB3E;GACF;EACF;AAEF,SAAS,2BAA2B;AAClC,IAAG,mEAAmE,YAAY;AAChF,SAAO,QAAQ,aAAa,EAAE,EAAE,IAAI,+EAA+E;AAEnH,QAAM,OAAO,kBAAkB,qBAAqB,EAAE,0BAA0B,CAAC,CAC9E,QAAQ,WAAW,UAAmB,YAAY,0BAA0B,WAAW,MAAM,CAAC;AACjG,SAAO,OAAO,SAAS,KAAK,CAAC,KAAK,+CAA+C;GACjF;AAEF,IAAG,mEAAmE,YAAY;AAChF,SAAO,QAAQ,aAAa,EAAE,EAAE,IAAI,+EAA+E;AAEnH,QAAM,OAAO,kBAAkB,qBAAqB,EAAE,0BAA0B,CAAC,CAC9E,QAAQ,WAAW,UAAmB,YAAY,oCAAoC,WAAW,MAAM,CAAC;AAC3G,SAAO,OAAO,SAAS,KAAK,CAAC,KAAK,+CAA+C;GACjF;EACF"}
@@ -322,6 +322,7 @@ declare class _HexclaveAdminAppImplIncomplete<HasTokenStore extends boolean, Pro
322
322
  listOutboxEmails(options?: {
323
323
  status?: string;
324
324
  simpleStatus?: string;
325
+ userId?: string;
325
326
  limit?: number;
326
327
  cursor?: string;
327
328
  }): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"admin-app-impl.d.ts","names":[],"sources":["../../../../../../src/lib/hexclave-app/apps/implementations/admin-app-impl.ts"],"mappings":"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"}
1
+ {"version":3,"file":"admin-app-impl.d.ts","names":[],"sources":["../../../../../../src/lib/hexclave-app/apps/implementations/admin-app-impl.ts"],"mappings":"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"}
@@ -785,6 +785,7 @@ var _HexclaveAdminAppImplIncomplete = class extends _HexclaveServerAppImplIncomp
785
785
  const response = await this._interface.listOutboxEmails({
786
786
  status: options?.status,
787
787
  simple_status: options?.simpleStatus,
788
+ user_id: options?.userId,
788
789
  limit: options?.limit,
789
790
  cursor: options?.cursor
790
791
  });