@kaiz11/stack-client 0.0.14

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 (263) hide show
  1. package/LICENSE +32 -0
  2. package/README.md +586 -0
  3. package/dist/accounts/accounts-client.d.ts +188 -0
  4. package/dist/accounts/accounts-client.d.ts.map +1 -0
  5. package/dist/accounts/accounts-client.js +264 -0
  6. package/dist/accounts/accounts-client.js.map +1 -0
  7. package/dist/accounts/index.d.ts +8 -0
  8. package/dist/accounts/index.d.ts.map +1 -0
  9. package/dist/accounts/index.js +8 -0
  10. package/dist/accounts/index.js.map +1 -0
  11. package/dist/accounts/mock-accounts.d.ts +90 -0
  12. package/dist/accounts/mock-accounts.d.ts.map +1 -0
  13. package/dist/accounts/mock-accounts.js +434 -0
  14. package/dist/accounts/mock-accounts.js.map +1 -0
  15. package/dist/accounts/types.d.ts +180 -0
  16. package/dist/accounts/types.d.ts.map +1 -0
  17. package/dist/accounts/types.js +59 -0
  18. package/dist/accounts/types.js.map +1 -0
  19. package/dist/auth/auth-client.d.ts +224 -0
  20. package/dist/auth/auth-client.d.ts.map +1 -0
  21. package/dist/auth/auth-client.js +230 -0
  22. package/dist/auth/auth-client.js.map +1 -0
  23. package/dist/auth/base-auth.d.ts +44 -0
  24. package/dist/auth/base-auth.d.ts.map +1 -0
  25. package/dist/auth/base-auth.js +55 -0
  26. package/dist/auth/base-auth.js.map +1 -0
  27. package/dist/auth/index.d.ts +11 -0
  28. package/dist/auth/index.d.ts.map +1 -0
  29. package/dist/auth/index.js +11 -0
  30. package/dist/auth/index.js.map +1 -0
  31. package/dist/auth/methods/admin.d.ts +59 -0
  32. package/dist/auth/methods/admin.d.ts.map +1 -0
  33. package/dist/auth/methods/admin.js +55 -0
  34. package/dist/auth/methods/admin.js.map +1 -0
  35. package/dist/auth/methods/index.d.ts +9 -0
  36. package/dist/auth/methods/index.d.ts.map +1 -0
  37. package/dist/auth/methods/index.js +8 -0
  38. package/dist/auth/methods/index.js.map +1 -0
  39. package/dist/auth/methods/magic-link.d.ts +27 -0
  40. package/dist/auth/methods/magic-link.d.ts.map +1 -0
  41. package/dist/auth/methods/magic-link.js +37 -0
  42. package/dist/auth/methods/magic-link.js.map +1 -0
  43. package/dist/auth/methods/mfa.d.ts +92 -0
  44. package/dist/auth/methods/mfa.d.ts.map +1 -0
  45. package/dist/auth/methods/mfa.js +153 -0
  46. package/dist/auth/methods/mfa.js.map +1 -0
  47. package/dist/auth/methods/oauth.d.ts +62 -0
  48. package/dist/auth/methods/oauth.d.ts.map +1 -0
  49. package/dist/auth/methods/oauth.js +165 -0
  50. package/dist/auth/methods/oauth.js.map +1 -0
  51. package/dist/auth/methods/otp.d.ts +43 -0
  52. package/dist/auth/methods/otp.d.ts.map +1 -0
  53. package/dist/auth/methods/otp.js +66 -0
  54. package/dist/auth/methods/otp.js.map +1 -0
  55. package/dist/auth/methods/password.d.ts +64 -0
  56. package/dist/auth/methods/password.d.ts.map +1 -0
  57. package/dist/auth/methods/password.js +116 -0
  58. package/dist/auth/methods/password.js.map +1 -0
  59. package/dist/auth/methods/recovery.d.ts +62 -0
  60. package/dist/auth/methods/recovery.d.ts.map +1 -0
  61. package/dist/auth/methods/recovery.js +100 -0
  62. package/dist/auth/methods/recovery.js.map +1 -0
  63. package/dist/auth/mock-auth.d.ts +135 -0
  64. package/dist/auth/mock-auth.d.ts.map +1 -0
  65. package/dist/auth/mock-auth.js +417 -0
  66. package/dist/auth/mock-auth.js.map +1 -0
  67. package/dist/auth/server/helpers.d.ts +215 -0
  68. package/dist/auth/server/helpers.d.ts.map +1 -0
  69. package/dist/auth/server/helpers.js +241 -0
  70. package/dist/auth/server/helpers.js.map +1 -0
  71. package/dist/auth/server/index.d.ts +24 -0
  72. package/dist/auth/server/index.d.ts.map +1 -0
  73. package/dist/auth/server/index.js +40 -0
  74. package/dist/auth/server/index.js.map +1 -0
  75. package/dist/auth/server/middleware.d.ts +305 -0
  76. package/dist/auth/server/middleware.d.ts.map +1 -0
  77. package/dist/auth/server/middleware.js +405 -0
  78. package/dist/auth/server/middleware.js.map +1 -0
  79. package/dist/auth/server/verify.d.ts +184 -0
  80. package/dist/auth/server/verify.d.ts.map +1 -0
  81. package/dist/auth/server/verify.js +222 -0
  82. package/dist/auth/server/verify.js.map +1 -0
  83. package/dist/auth/token-manager.d.ts +94 -0
  84. package/dist/auth/token-manager.d.ts.map +1 -0
  85. package/dist/auth/token-manager.js +231 -0
  86. package/dist/auth/token-manager.js.map +1 -0
  87. package/dist/auth/types.d.ts +412 -0
  88. package/dist/auth/types.d.ts.map +1 -0
  89. package/dist/auth/types.js +66 -0
  90. package/dist/auth/types.js.map +1 -0
  91. package/dist/auth/user/identities.d.ts +62 -0
  92. package/dist/auth/user/identities.d.ts.map +1 -0
  93. package/dist/auth/user/identities.js +88 -0
  94. package/dist/auth/user/identities.js.map +1 -0
  95. package/dist/auth/user/index.d.ts +4 -0
  96. package/dist/auth/user/index.d.ts.map +1 -0
  97. package/dist/auth/user/index.js +4 -0
  98. package/dist/auth/user/index.js.map +1 -0
  99. package/dist/auth/user/user.d.ts +64 -0
  100. package/dist/auth/user/user.d.ts.map +1 -0
  101. package/dist/auth/user/user.js +105 -0
  102. package/dist/auth/user/user.js.map +1 -0
  103. package/dist/auth/user/verification.d.ts +49 -0
  104. package/dist/auth/user/verification.d.ts.map +1 -0
  105. package/dist/auth/user/verification.js +71 -0
  106. package/dist/auth/user/verification.js.map +1 -0
  107. package/dist/cli/browser.d.ts +11 -0
  108. package/dist/cli/browser.d.ts.map +1 -0
  109. package/dist/cli/browser.js +35 -0
  110. package/dist/cli/browser.js.map +1 -0
  111. package/dist/cli/callback-server.d.ts +30 -0
  112. package/dist/cli/callback-server.d.ts.map +1 -0
  113. package/dist/cli/callback-server.js +100 -0
  114. package/dist/cli/callback-server.js.map +1 -0
  115. package/dist/cli/file-token-store.d.ts +79 -0
  116. package/dist/cli/file-token-store.d.ts.map +1 -0
  117. package/dist/cli/file-token-store.js +138 -0
  118. package/dist/cli/file-token-store.js.map +1 -0
  119. package/dist/cli/index.d.ts +33 -0
  120. package/dist/cli/index.d.ts.map +1 -0
  121. package/dist/cli/index.js +38 -0
  122. package/dist/cli/index.js.map +1 -0
  123. package/dist/cli/oauth.d.ts +67 -0
  124. package/dist/cli/oauth.d.ts.map +1 -0
  125. package/dist/cli/oauth.js +101 -0
  126. package/dist/cli/oauth.js.map +1 -0
  127. package/dist/cli/pkce.d.ts +35 -0
  128. package/dist/cli/pkce.d.ts.map +1 -0
  129. package/dist/cli/pkce.js +43 -0
  130. package/dist/cli/pkce.js.map +1 -0
  131. package/dist/client.d.ts +22 -0
  132. package/dist/client.d.ts.map +1 -0
  133. package/dist/client.js +99 -0
  134. package/dist/client.js.map +1 -0
  135. package/dist/db/client.d.ts +9 -0
  136. package/dist/db/client.d.ts.map +1 -0
  137. package/dist/db/client.js +19 -0
  138. package/dist/db/client.js.map +1 -0
  139. package/dist/db/errors.d.ts +19 -0
  140. package/dist/db/errors.d.ts.map +1 -0
  141. package/dist/db/errors.js +57 -0
  142. package/dist/db/errors.js.map +1 -0
  143. package/dist/db/index.d.ts +7 -0
  144. package/dist/db/index.d.ts.map +1 -0
  145. package/dist/db/index.js +5 -0
  146. package/dist/db/index.js.map +1 -0
  147. package/dist/db/mock.d.ts +28 -0
  148. package/dist/db/mock.d.ts.map +1 -0
  149. package/dist/db/mock.js +459 -0
  150. package/dist/db/mock.js.map +1 -0
  151. package/dist/db/types.d.ts +73 -0
  152. package/dist/db/types.d.ts.map +1 -0
  153. package/dist/db/types.js +2 -0
  154. package/dist/db/types.js.map +1 -0
  155. package/dist/index.d.ts +21 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +20 -0
  158. package/dist/index.js.map +1 -0
  159. package/dist/lib/errors.d.ts +33 -0
  160. package/dist/lib/errors.d.ts.map +1 -0
  161. package/dist/lib/errors.js +76 -0
  162. package/dist/lib/errors.js.map +1 -0
  163. package/dist/lib/http.d.ts +81 -0
  164. package/dist/lib/http.d.ts.map +1 -0
  165. package/dist/lib/http.js +163 -0
  166. package/dist/lib/http.js.map +1 -0
  167. package/dist/lib/keys.d.ts +87 -0
  168. package/dist/lib/keys.d.ts.map +1 -0
  169. package/dist/lib/keys.js +147 -0
  170. package/dist/lib/keys.js.map +1 -0
  171. package/dist/lib/paths.d.ts +37 -0
  172. package/dist/lib/paths.d.ts.map +1 -0
  173. package/dist/lib/paths.js +49 -0
  174. package/dist/lib/paths.js.map +1 -0
  175. package/dist/lib/token-store.d.ts +42 -0
  176. package/dist/lib/token-store.d.ts.map +1 -0
  177. package/dist/lib/token-store.js +75 -0
  178. package/dist/lib/token-store.js.map +1 -0
  179. package/dist/mocks/handlers.d.ts +29 -0
  180. package/dist/mocks/handlers.d.ts.map +1 -0
  181. package/dist/mocks/handlers.js +79 -0
  182. package/dist/mocks/handlers.js.map +1 -0
  183. package/dist/mocks/index.d.ts +5 -0
  184. package/dist/mocks/index.d.ts.map +1 -0
  185. package/dist/mocks/index.js +9 -0
  186. package/dist/mocks/index.js.map +1 -0
  187. package/dist/mocks/responses.d.ts +76 -0
  188. package/dist/mocks/responses.d.ts.map +1 -0
  189. package/dist/mocks/responses.js +91 -0
  190. package/dist/mocks/responses.js.map +1 -0
  191. package/dist/mocks/server.d.ts +7 -0
  192. package/dist/mocks/server.d.ts.map +1 -0
  193. package/dist/mocks/server.js +9 -0
  194. package/dist/mocks/server.js.map +1 -0
  195. package/dist/mocks/state.d.ts +86 -0
  196. package/dist/mocks/state.d.ts.map +1 -0
  197. package/dist/mocks/state.js +77 -0
  198. package/dist/mocks/state.js.map +1 -0
  199. package/dist/storage/bucket-ref.d.ts +183 -0
  200. package/dist/storage/bucket-ref.d.ts.map +1 -0
  201. package/dist/storage/bucket-ref.js +529 -0
  202. package/dist/storage/bucket-ref.js.map +1 -0
  203. package/dist/storage/errors.d.ts +27 -0
  204. package/dist/storage/errors.d.ts.map +1 -0
  205. package/dist/storage/errors.js +89 -0
  206. package/dist/storage/errors.js.map +1 -0
  207. package/dist/storage/index.d.ts +13 -0
  208. package/dist/storage/index.d.ts.map +1 -0
  209. package/dist/storage/index.js +11 -0
  210. package/dist/storage/index.js.map +1 -0
  211. package/dist/storage/interface.d.ts +245 -0
  212. package/dist/storage/interface.d.ts.map +1 -0
  213. package/dist/storage/interface.js +2 -0
  214. package/dist/storage/interface.js.map +1 -0
  215. package/dist/storage/mock-storage.d.ts +67 -0
  216. package/dist/storage/mock-storage.d.ts.map +1 -0
  217. package/dist/storage/mock-storage.js +478 -0
  218. package/dist/storage/mock-storage.js.map +1 -0
  219. package/dist/storage/policies-client.d.ts +77 -0
  220. package/dist/storage/policies-client.d.ts.map +1 -0
  221. package/dist/storage/policies-client.js +115 -0
  222. package/dist/storage/policies-client.js.map +1 -0
  223. package/dist/storage/policy-templates.d.ts +6 -0
  224. package/dist/storage/policy-templates.d.ts.map +1 -0
  225. package/dist/storage/policy-templates.js +290 -0
  226. package/dist/storage/policy-templates.js.map +1 -0
  227. package/dist/storage/policy-types.d.ts +98 -0
  228. package/dist/storage/policy-types.d.ts.map +1 -0
  229. package/dist/storage/policy-types.js +20 -0
  230. package/dist/storage/policy-types.js.map +1 -0
  231. package/dist/storage/storage-client.d.ts +32 -0
  232. package/dist/storage/storage-client.d.ts.map +1 -0
  233. package/dist/storage/storage-client.js +94 -0
  234. package/dist/storage/storage-client.js.map +1 -0
  235. package/dist/storage/tus-upload.d.ts +56 -0
  236. package/dist/storage/tus-upload.d.ts.map +1 -0
  237. package/dist/storage/tus-upload.js +236 -0
  238. package/dist/storage/tus-upload.js.map +1 -0
  239. package/dist/storage/types.d.ts +335 -0
  240. package/dist/storage/types.d.ts.map +1 -0
  241. package/dist/storage/types.js +39 -0
  242. package/dist/storage/types.js.map +1 -0
  243. package/dist/test/auth/helpers.d.ts +33 -0
  244. package/dist/test/auth/helpers.d.ts.map +1 -0
  245. package/dist/test/auth/helpers.js +80 -0
  246. package/dist/test/auth/helpers.js.map +1 -0
  247. package/dist/test/helpers/jwt.d.ts +61 -0
  248. package/dist/test/helpers/jwt.d.ts.map +1 -0
  249. package/dist/test/helpers/jwt.js +132 -0
  250. package/dist/test/helpers/jwt.js.map +1 -0
  251. package/dist/test/helpers/mailpit.d.ts +61 -0
  252. package/dist/test/helpers/mailpit.d.ts.map +1 -0
  253. package/dist/test/helpers/mailpit.js +107 -0
  254. package/dist/test/helpers/mailpit.js.map +1 -0
  255. package/dist/test/setup.d.ts +2 -0
  256. package/dist/test/setup.d.ts.map +1 -0
  257. package/dist/test/setup.js +17 -0
  258. package/dist/test/setup.js.map +1 -0
  259. package/dist/types.d.ts +96 -0
  260. package/dist/types.d.ts.map +1 -0
  261. package/dist/types.js +5 -0
  262. package/dist/types.js.map +1 -0
  263. package/package.json +78 -0
package/LICENSE ADDED
@@ -0,0 +1,32 @@
1
+ Copyright (c) 2026 Kai Zhao. All rights reserved.
2
+
3
+ PROPRIETARY SOFTWARE LICENSE
4
+
5
+ This software and associated documentation files (the "Software") are the
6
+ proprietary and confidential property of Kai Zhao.
7
+
8
+ RESTRICTIONS
9
+
10
+ You may NOT, without prior written permission from the copyright holder:
11
+
12
+ 1. Copy, reproduce, or duplicate the Software or any portion thereof
13
+ 2. Modify, adapt, translate, or create derivative works based on the Software
14
+ 3. Distribute, sublicense, lease, rent, loan, or otherwise transfer the Software
15
+ 4. Reverse engineer, disassemble, decompile, or attempt to derive the source
16
+ code of the Software
17
+ 5. Remove or alter any proprietary notices, labels, or marks on the Software
18
+ 6. Use the Software for any commercial purpose
19
+ 7. Make the Software available to any third party
20
+
21
+ DISCLAIMER
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
27
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+
30
+ CONTACT
31
+
32
+ For licensing inquiries, please contact the copyright holder.
package/README.md ADDED
@@ -0,0 +1,586 @@
1
+ # @kaiz11/stack-client
2
+
3
+ A standalone TypeScript client for Supabase stack services. Supports both platform-level and tenant-level operations with automatic token management.
4
+
5
+ ## Installation
6
+
7
+ This package is published to GitHub Packages. Configure your `.npmrc` to use the GitHub registry for the `@kaiz11` scope:
8
+
9
+ ```bash
10
+ # .npmrc (project root or ~/.npmrc)
11
+ @kaiz11:registry=https://npm.pkg.github.com
12
+ //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
13
+ ```
14
+
15
+ Then install:
16
+
17
+ ```bash
18
+ pnpm add @kaiz11/stack-client
19
+ ```
20
+
21
+ ### Authentication
22
+
23
+ GitHub Packages requires authentication even for public packages. Create a [Personal Access Token](https://github.com/settings/tokens) with the `read:packages` scope and set it as `GITHUB_TOKEN`:
24
+
25
+ ```bash
26
+ # Option 1: Environment variable
27
+ export GITHUB_TOKEN=ghp_xxxxxxxxxxxx
28
+
29
+ # Option 2: npm login
30
+ npm login --registry=https://npm.pkg.github.com
31
+ ```
32
+
33
+ For CI/CD, use the built-in `GITHUB_TOKEN` secret or a PAT with `read:packages` scope.
34
+
35
+ ## Quick Start
36
+
37
+ ```typescript
38
+ import { createTenantClient } from "@kaiz11/stack-client";
39
+
40
+ const client = createTenantClient({
41
+ baseUrl: "https://stack.example.com",
42
+ tenantId: "my-tenant",
43
+ });
44
+
45
+ // Sign in
46
+ await client.auth.signInWithPassword({
47
+ email: "user@example.com",
48
+ password: "password123",
49
+ });
50
+
51
+ // Access the user
52
+ const user = client.auth.getUser();
53
+ ```
54
+
55
+ ## Client Modes
56
+
57
+ ### Tenant Mode
58
+
59
+ For applications serving a single tenant. Endpoints use `/auth/{tenantId}/*`.
60
+
61
+ ```typescript
62
+ import { createTenantClient } from "@kaiz11/stack-client";
63
+
64
+ const client = createTenantClient({
65
+ baseUrl: "https://stack.example.com",
66
+ tenantId: "acme-corp",
67
+ });
68
+ ```
69
+
70
+ ### Platform Mode
71
+
72
+ For platform-level operations (admin dashboards, multi-tenant management). Endpoints use `/auth/_platform/*`.
73
+
74
+ ```typescript
75
+ import { createPlatformClient } from "@kaiz11/stack-client";
76
+
77
+ const client = createPlatformClient({
78
+ baseUrl: "https://stack.example.com",
79
+ });
80
+ ```
81
+
82
+ ### Generic Mode
83
+
84
+ When you need to specify the mode dynamically, use `createClient()` with `tenantId` for tenant mode, or without it for platform mode:
85
+
86
+ ```typescript
87
+ import { createClient } from "@kaiz11/stack-client";
88
+
89
+ // Tenant mode (tenantId present)
90
+ const tenantClient = createClient({
91
+ baseUrl: "https://stack.example.com",
92
+ tenantId: "acme-corp",
93
+ });
94
+
95
+ // Platform mode (no tenantId)
96
+ const platformClient = createClient({
97
+ baseUrl: "https://stack.example.com",
98
+ });
99
+ ```
100
+
101
+ ## Configuration
102
+
103
+ ```typescript
104
+ interface ClientConfig {
105
+ /** Base URL of the stack server */
106
+ baseUrl: string;
107
+
108
+ /** Token storage type: "memory" | "localStorage" | custom TokenStore */
109
+ tokenStore?: TokenStoreType;
110
+
111
+ /** Storage key prefix (default: "stack") */
112
+ storagePrefix?: string;
113
+
114
+ /** Request timeout in milliseconds (default: 30000) */
115
+ timeout?: number;
116
+
117
+ /** Enable mock mode for testing (no HTTP requests) */
118
+ mock?: boolean;
119
+
120
+ /** Mock options (latency simulation, etc.) */
121
+ mockOptions?: MockOptions;
122
+ }
123
+
124
+ interface TenantClientConfig extends ClientConfig {
125
+ /** Tenant identifier */
126
+ tenantId: string;
127
+ }
128
+ ```
129
+
130
+ ## Token Storage
131
+
132
+ Tokens need to be stored somewhere. The client supports pluggable storage backends:
133
+
134
+ ### Memory Store (Default)
135
+
136
+ Tokens are stored in memory. Lost on page refresh. Good for server-side usage.
137
+
138
+ ```typescript
139
+ import { createTenantClient, MemoryTokenStore } from "@kaiz11/stack-client";
140
+
141
+ const client = createTenantClient({
142
+ baseUrl: "https://stack.example.com",
143
+ tenantId: "my-tenant",
144
+ tokenStore: new MemoryTokenStore(), // This is the default
145
+ });
146
+ ```
147
+
148
+ ### LocalStorage Store
149
+
150
+ Tokens persist in browser localStorage. Survives page refreshes.
151
+
152
+ ```typescript
153
+ import {
154
+ createTenantClient,
155
+ LocalStorageTokenStore,
156
+ } from "@kaiz11/stack-client";
157
+
158
+ const client = createTenantClient({
159
+ baseUrl: "https://stack.example.com",
160
+ tenantId: "my-tenant",
161
+ tokenStore: new LocalStorageTokenStore("my-app-auth"),
162
+ });
163
+ ```
164
+
165
+ ### Custom Store
166
+
167
+ Implement the `TokenStore` interface for custom backends (cookies, IndexedDB, etc.):
168
+
169
+ ```typescript
170
+ import { TokenStore } from "@kaiz11/stack-client";
171
+
172
+ class CookieTokenStore implements TokenStore {
173
+ getAccessToken(): string | null {
174
+ return getCookie("access_token");
175
+ }
176
+
177
+ getRefreshToken(): string | null {
178
+ return getCookie("refresh_token");
179
+ }
180
+
181
+ setTokens(accessToken: string, refreshToken: string): void {
182
+ setCookie("access_token", accessToken, { httpOnly: true, secure: true });
183
+ setCookie("refresh_token", refreshToken, { httpOnly: true, secure: true });
184
+ }
185
+
186
+ clearTokens(): void {
187
+ deleteCookie("access_token");
188
+ deleteCookie("refresh_token");
189
+ }
190
+ }
191
+ ```
192
+
193
+ ## Cleanup
194
+
195
+ When done with the client, call `destroy()` to clear auto-refresh timers:
196
+
197
+ ```typescript
198
+ const client = createTenantClient({ ... });
199
+
200
+ // When cleaning up (e.g., component unmount)
201
+ client.destroy();
202
+ ```
203
+
204
+ ## Server-Side Usage
205
+
206
+ The same client works on both frontend and backend. For server-side usage, use `tokenStore: "memory"` and pass `accessToken` directly.
207
+
208
+ > **Note:** The client does not verify tokens passed via `accessToken`. It assumes the token is valid and uses it for outgoing API calls. Verification happens server-side when the request reaches PostgREST, Storage, or other backend services. If you need to verify incoming requests, use the [Auth Middleware](#auth-middleware-verifying-incoming-requests).
209
+
210
+ ### Service Role (Admin Access)
211
+
212
+ Use a service role token for admin operations that bypass RLS:
213
+
214
+ ```typescript
215
+ import { createTenantClient } from "@kaiz11/stack-client";
216
+
217
+ const adminClient = createTenantClient({
218
+ baseUrl: "https://stack.example.com",
219
+ tenantId: "acme-corp",
220
+ tokenStore: "memory",
221
+ accessToken: process.env.SERVICE_ROLE_TOKEN,
222
+ });
223
+
224
+ // Admin operations - bypasses RLS
225
+ await adminClient.storage.from("uploads").upload("file.pdf", data);
226
+ await adminClient.storage.from("private").list(); // Can access all files
227
+ ```
228
+
229
+ ### User Context (Respects RLS)
230
+
231
+ Pass the user's access token (from a verified request) to make calls scoped to that user:
232
+
233
+ ```typescript
234
+ import { createTenantClient } from "@kaiz11/stack-client";
235
+
236
+ // In your API handler, after verifying the request
237
+ const userClient = createTenantClient({
238
+ baseUrl: "https://stack.example.com",
239
+ tenantId: "acme-corp",
240
+ tokenStore: "memory",
241
+ accessToken: userAccessToken, // From verified JWT
242
+ });
243
+
244
+ // User-scoped operations - respects RLS
245
+ await userClient.storage.from("user-files").list(); // Only sees their files
246
+ await userClient.accounts.list(); // Only sees their accounts
247
+ ```
248
+
249
+ ### Auth Middleware (Verifying Incoming Requests)
250
+
251
+ Use the auth middleware to verify JWTs on incoming requests. The middleware automatically fetches the JWKS from GoTrue for ES256 verification.
252
+
253
+ ```typescript
254
+ import { Hono } from "hono";
255
+ import { createStackAuthMiddleware } from "@kaiz11/stack-client/auth/server";
256
+
257
+ const app = new Hono();
258
+
259
+ // For tenant APIs
260
+ app.use(
261
+ "*",
262
+ createStackAuthMiddleware({
263
+ baseUrl: "https://stack.example.com",
264
+ tenantId: "acme-corp",
265
+ excludePaths: [/^\/health$/], // Optional: skip auth for these paths
266
+ }),
267
+ );
268
+
269
+ // For platform APIs
270
+ app.use(
271
+ "*",
272
+ createStackAuthMiddleware({
273
+ baseUrl: "https://stack.example.com",
274
+ // No tenantId = platform mode
275
+ }),
276
+ );
277
+
278
+ // Access verified user in handlers
279
+ app.get("/api/me", (c) => {
280
+ const user = c.get("user"); // { id, email, role, aal, ... }
281
+ const token = c.get("accessToken"); // Raw JWT for downstream calls
282
+ return c.json({ user });
283
+ });
284
+ ```
285
+
286
+ ### Optional Auth Middleware
287
+
288
+ For routes that work with or without authentication:
289
+
290
+ ```typescript
291
+ import { optionalStackAuthMiddleware } from "@kaiz11/stack-client/auth/server";
292
+
293
+ app.use(
294
+ "*",
295
+ optionalStackAuthMiddleware({
296
+ baseUrl: "https://stack.example.com",
297
+ tenantId: "acme-corp",
298
+ }),
299
+ );
300
+
301
+ app.get("/api/feed", (c) => {
302
+ const user = c.get("user"); // undefined if not authenticated
303
+ if (user) {
304
+ return c.json({ feed: getPersonalizedFeed(user.id) });
305
+ }
306
+ return c.json({ feed: getPublicFeed() });
307
+ });
308
+ ```
309
+
310
+ ### Role & MFA Guards
311
+
312
+ Add additional guards after the auth middleware:
313
+
314
+ ```typescript
315
+ import {
316
+ createStackAuthMiddleware,
317
+ requireRoleMiddleware,
318
+ requireMfaMiddleware,
319
+ } from "@kaiz11/stack-client/auth/server";
320
+
321
+ // All routes require authentication
322
+ app.use("*", createStackAuthMiddleware({ baseUrl, tenantId }));
323
+
324
+ // Admin routes require service_role
325
+ app.use("/admin/*", requireRoleMiddleware("service_role"));
326
+
327
+ // Sensitive routes require MFA (AAL2)
328
+ app.use("/settings/security/*", requireMfaMiddleware());
329
+ ```
330
+
331
+ ### Complete Server Example
332
+
333
+ ```typescript
334
+ import { Hono } from "hono";
335
+ import { createTenantClient } from "@kaiz11/stack-client";
336
+ import { createStackAuthMiddleware } from "@kaiz11/stack-client/auth/server";
337
+
338
+ const app = new Hono();
339
+
340
+ const baseUrl = "https://stack.example.com";
341
+ const tenantId = "acme-corp";
342
+
343
+ // Verify incoming requests
344
+ app.use("/api/*", createStackAuthMiddleware({ baseUrl, tenantId }));
345
+
346
+ // User uploads a file (respects RLS)
347
+ app.post("/api/upload", async (c) => {
348
+ const userClient = createTenantClient({
349
+ baseUrl,
350
+ tenantId,
351
+ tokenStore: "memory",
352
+ accessToken: c.get("accessToken"),
353
+ });
354
+
355
+ const file = await c.req.blob();
356
+ const { data, error } = await userClient.storage
357
+ .from("uploads")
358
+ .upload(`${c.get("user").id}/file.pdf`, file);
359
+
360
+ return c.json({ data, error });
361
+ });
362
+
363
+ // Admin generates a report (bypasses RLS)
364
+ app.post("/api/admin/report", async (c) => {
365
+ const adminClient = createTenantClient({
366
+ baseUrl,
367
+ tenantId,
368
+ tokenStore: "memory",
369
+ accessToken: process.env.SERVICE_ROLE_TOKEN,
370
+ });
371
+
372
+ // Can access all users' files
373
+ const { data } = await adminClient.storage.from("uploads").list();
374
+ return c.json({ files: data });
375
+ });
376
+
377
+ export default app;
378
+ ```
379
+
380
+ ## Testing
381
+
382
+ The client includes built-in mock mode for testing without HTTP requests.
383
+
384
+ ### Mock Mode
385
+
386
+ Enable mock mode for unit tests or local development:
387
+
388
+ ```typescript
389
+ const client = createTenantClient({
390
+ baseUrl: "https://stack.example.com",
391
+ tenantId: "test-tenant",
392
+ mock: true,
393
+ });
394
+
395
+ // All auth methods work without network requests
396
+ await client.auth.signIn({ email: "test@example.com", password: "password" });
397
+ const user = client.auth.getUser(); // Returns mock user
398
+ ```
399
+
400
+ ### Simulating Latency
401
+
402
+ Add artificial delay to simulate network conditions:
403
+
404
+ ```typescript
405
+ const client = createTenantClient({
406
+ baseUrl: "https://stack.example.com",
407
+ tenantId: "test-tenant",
408
+ mock: true,
409
+ mockOptions: {
410
+ latency: 100, // 100ms delay on all operations
411
+ },
412
+ });
413
+ ```
414
+
415
+ ### Controlling Mock Behavior
416
+
417
+ Use `mockState` to simulate errors and edge cases:
418
+
419
+ ```typescript
420
+ import { createTenantClient, mockState } from "@kaiz11/stack-client";
421
+
422
+ const client = createTenantClient({ ..., mock: true });
423
+
424
+ // Simulate sign-in failure
425
+ mockState.shouldFailSignIn = true;
426
+ await client.auth.signIn({ email, password }); // Throws AuthError
427
+
428
+ // Simulate sign-up failure (user exists)
429
+ mockState.shouldFailSignUp = true;
430
+ await client.auth.signUp({ email, password }); // Throws AuthError
431
+
432
+ // Simulate token refresh failure
433
+ mockState.shouldFailRefresh = true;
434
+ await client.auth.refreshSession(); // Throws AuthError
435
+
436
+ // Reset to default behavior
437
+ mockState.reset();
438
+ ```
439
+
440
+ ### Tracking Request Counts
441
+
442
+ Use `requestCounts` to verify operations were called:
443
+
444
+ ```typescript
445
+ import { createTenantClient, requestCounts } from "@kaiz11/stack-client";
446
+
447
+ const client = createTenantClient({ ..., mock: true });
448
+
449
+ await client.auth.signIn({ email, password });
450
+ console.log(requestCounts.signIn); // 1
451
+
452
+ await client.auth.signOut();
453
+ console.log(requestCounts.signOut); // 1
454
+
455
+ // Reset counts between tests
456
+ requestCounts.reset();
457
+ ```
458
+
459
+ ### Vitest Example
460
+
461
+ ```typescript
462
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
463
+ import {
464
+ createTenantClient,
465
+ mockState,
466
+ requestCounts,
467
+ } from "@kaiz11/stack-client";
468
+
469
+ describe("auth", () => {
470
+ let client: ReturnType<typeof createTenantClient>;
471
+
472
+ beforeEach(() => {
473
+ client = createTenantClient({
474
+ baseUrl: "https://stack.example.com",
475
+ tenantId: "test",
476
+ mock: true,
477
+ });
478
+ });
479
+
480
+ afterEach(() => {
481
+ client.destroy();
482
+ mockState.reset();
483
+ requestCounts.reset();
484
+ });
485
+
486
+ it("signs in user", async () => {
487
+ await client.auth.signIn({ email: "test@example.com", password: "pass" });
488
+
489
+ expect(client.auth.isAuthenticated()).toBe(true);
490
+ expect(requestCounts.signIn).toBe(1);
491
+ });
492
+
493
+ it("handles sign-in error", async () => {
494
+ mockState.shouldFailSignIn = true;
495
+
496
+ await expect(
497
+ client.auth.signIn({ email: "test@example.com", password: "wrong" }),
498
+ ).rejects.toThrow();
499
+ });
500
+ });
501
+ ```
502
+
503
+ ## Known Limitations
504
+
505
+ Some client features require backend configuration or are not yet supported by the self-hosted Stack platform.
506
+
507
+ ### Features Requiring Backend Configuration
508
+
509
+ | Feature | Requirement | Status |
510
+ | --------------------------- | --------------------------------------------- | ---------------------------- |
511
+ | **Phone/SMS Auth** | Twilio configuration in GoTrue | Not configured |
512
+ | **Manual Identity Linking** | `GOTRUE_SECURITY_MANUAL_LINKING_ENABLED=true` | Disabled by default |
513
+ | **TUS Resumable Uploads** | Storage service TUS endpoint | Returns 500 (platform issue) |
514
+
515
+ ### Features Requiring Browser Interaction
516
+
517
+ These features work correctly but cannot be fully automated in tests:
518
+
519
+ | Feature | Reason |
520
+ | -------------------------- | ------------------------------------- |
521
+ | **OAuth Sign-In** | Requires browser redirect to provider |
522
+ | **OAuth Identity Linking** | Requires browser OAuth flow |
523
+ | **PKCE OAuth Flow** | Requires browser for code exchange |
524
+
525
+ ### API Differences from Official Supabase
526
+
527
+ | Method | Difference |
528
+ | ------------------------ | ------------------------------------------------- |
529
+ | `auth.mfa.listFactors()` | Returns 405 (endpoint not available in GoTrue) |
530
+ | `auth.reauthenticate()` | Sends OTP email, returns `void` (not `{ nonce }`) |
531
+
532
+ ### Workarounds
533
+
534
+ **For `reauthenticate()`**: The OTP sent to email should be used as the `nonce` parameter in `updatePassword()`:
535
+
536
+ ```typescript
537
+ // Request reauthentication (sends OTP to email)
538
+ await client.auth.reauthenticate();
539
+
540
+ // User receives OTP via email, enters it
541
+ const otp = "123456"; // from email
542
+
543
+ // Use OTP as nonce for password update
544
+ await client.auth.updatePassword({
545
+ password: "new-password",
546
+ nonce: otp,
547
+ });
548
+ ```
549
+
550
+ ## Modules
551
+
552
+ | Module | Description | Documentation |
553
+ | ----------- | --------------------------------------------------- | ------------------------------------------- |
554
+ | `auth` | Authentication (sign in, sign up, sign out, tokens) | [Auth README](./src/auth/README.md) |
555
+ | `accounts` | Multi-tenant accounts (teams, roles, members) | [Accounts README](./src/accounts/README.md) |
556
+ | `storage` | File storage (buckets, uploads, signed URLs, TUS) | [Storage README](./src/storage/README.md) |
557
+ | `functions` | Edge functions | Coming soon |
558
+ | `realtime` | Realtime subscriptions | Coming soon |
559
+
560
+ ## TypeScript Types
561
+
562
+ ```typescript
563
+ import type {
564
+ // Client
565
+ StackClient,
566
+ ClientConfig,
567
+ TenantClientConfig,
568
+ PlatformClientConfig,
569
+ ClientMode,
570
+
571
+ // Token storage
572
+ TokenStore,
573
+ TokenStoreType,
574
+
575
+ // Mock mode
576
+ MockOptions,
577
+ MockState,
578
+ RequestCounts,
579
+ } from "@kaiz11/stack-client";
580
+ ```
581
+
582
+ ## License
583
+
584
+ Copyright © 2026 Kai Zhao. All rights reserved.
585
+
586
+ This software is proprietary and confidential. Unauthorized copying, distribution, modification, or use of this software, via any medium, is strictly prohibited without prior written permission from the copyright holder.