@selvajs/supabase-provider 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +271 -0
  3. package/dist/auth/SupabaseAuthProvider.d.ts +81 -0
  4. package/dist/auth/SupabaseAuthProvider.d.ts.map +1 -0
  5. package/dist/auth/SupabaseAuthProvider.js +383 -0
  6. package/dist/auth/SupabaseAuthProvider.js.map +1 -0
  7. package/dist/auth/__tests__/conformance.test.d.ts +2 -0
  8. package/dist/auth/__tests__/conformance.test.d.ts.map +1 -0
  9. package/dist/auth/__tests__/conformance.test.js +76 -0
  10. package/dist/auth/__tests__/conformance.test.js.map +1 -0
  11. package/dist/auth/index.d.ts +3 -0
  12. package/dist/auth/index.d.ts.map +1 -0
  13. package/dist/auth/index.js +2 -0
  14. package/dist/auth/index.js.map +1 -0
  15. package/dist/data/SupabaseAuditQuery.d.ts +16 -0
  16. package/dist/data/SupabaseAuditQuery.d.ts.map +1 -0
  17. package/dist/data/SupabaseAuditQuery.js +83 -0
  18. package/dist/data/SupabaseAuditQuery.js.map +1 -0
  19. package/dist/data/SupabaseComputeServerStore.d.ts +26 -0
  20. package/dist/data/SupabaseComputeServerStore.d.ts.map +1 -0
  21. package/dist/data/SupabaseComputeServerStore.js +227 -0
  22. package/dist/data/SupabaseComputeServerStore.js.map +1 -0
  23. package/dist/data/SupabaseDataProvider.d.ts +55 -0
  24. package/dist/data/SupabaseDataProvider.d.ts.map +1 -0
  25. package/dist/data/SupabaseDataProvider.js +114 -0
  26. package/dist/data/SupabaseDataProvider.js.map +1 -0
  27. package/dist/data/SupabaseDefinitionStore.d.ts +39 -0
  28. package/dist/data/SupabaseDefinitionStore.d.ts.map +1 -0
  29. package/dist/data/SupabaseDefinitionStore.js +419 -0
  30. package/dist/data/SupabaseDefinitionStore.js.map +1 -0
  31. package/dist/data/SupabaseEventSink.d.ts +17 -0
  32. package/dist/data/SupabaseEventSink.d.ts.map +1 -0
  33. package/dist/data/SupabaseEventSink.js +31 -0
  34. package/dist/data/SupabaseEventSink.js.map +1 -0
  35. package/dist/data/SupabaseInviteStore.d.ts +22 -0
  36. package/dist/data/SupabaseInviteStore.d.ts.map +1 -0
  37. package/dist/data/SupabaseInviteStore.js +159 -0
  38. package/dist/data/SupabaseInviteStore.js.map +1 -0
  39. package/dist/data/SupabaseOrgStore.d.ts +33 -0
  40. package/dist/data/SupabaseOrgStore.d.ts.map +1 -0
  41. package/dist/data/SupabaseOrgStore.js +455 -0
  42. package/dist/data/SupabaseOrgStore.js.map +1 -0
  43. package/dist/data/SupabaseProjectStore.d.ts +29 -0
  44. package/dist/data/SupabaseProjectStore.d.ts.map +1 -0
  45. package/dist/data/SupabaseProjectStore.js +328 -0
  46. package/dist/data/SupabaseProjectStore.js.map +1 -0
  47. package/dist/data/SupabaseShareLinkStore.d.ts +26 -0
  48. package/dist/data/SupabaseShareLinkStore.d.ts.map +1 -0
  49. package/dist/data/SupabaseShareLinkStore.js +150 -0
  50. package/dist/data/SupabaseShareLinkStore.js.map +1 -0
  51. package/dist/data/__tests__/compute-server-conformance.test.d.ts +2 -0
  52. package/dist/data/__tests__/compute-server-conformance.test.d.ts.map +1 -0
  53. package/dist/data/__tests__/compute-server-conformance.test.js +40 -0
  54. package/dist/data/__tests__/compute-server-conformance.test.js.map +1 -0
  55. package/dist/data/__tests__/definition-conformance.test.d.ts +2 -0
  56. package/dist/data/__tests__/definition-conformance.test.d.ts.map +1 -0
  57. package/dist/data/__tests__/definition-conformance.test.js +85 -0
  58. package/dist/data/__tests__/definition-conformance.test.js.map +1 -0
  59. package/dist/data/__tests__/event-sink-conformance.test.d.ts +2 -0
  60. package/dist/data/__tests__/event-sink-conformance.test.d.ts.map +1 -0
  61. package/dist/data/__tests__/event-sink-conformance.test.js +27 -0
  62. package/dist/data/__tests__/event-sink-conformance.test.js.map +1 -0
  63. package/dist/data/__tests__/invite-conformance.test.d.ts +2 -0
  64. package/dist/data/__tests__/invite-conformance.test.d.ts.map +1 -0
  65. package/dist/data/__tests__/invite-conformance.test.js +45 -0
  66. package/dist/data/__tests__/invite-conformance.test.js.map +1 -0
  67. package/dist/data/__tests__/org-conformance.test.d.ts +2 -0
  68. package/dist/data/__tests__/org-conformance.test.d.ts.map +1 -0
  69. package/dist/data/__tests__/org-conformance.test.js +29 -0
  70. package/dist/data/__tests__/org-conformance.test.js.map +1 -0
  71. package/dist/data/__tests__/project-conformance.test.d.ts +2 -0
  72. package/dist/data/__tests__/project-conformance.test.d.ts.map +1 -0
  73. package/dist/data/__tests__/project-conformance.test.js +57 -0
  74. package/dist/data/__tests__/project-conformance.test.js.map +1 -0
  75. package/dist/data/__tests__/share-link-conformance.test.d.ts +2 -0
  76. package/dist/data/__tests__/share-link-conformance.test.d.ts.map +1 -0
  77. package/dist/data/__tests__/share-link-conformance.test.js +88 -0
  78. package/dist/data/__tests__/share-link-conformance.test.js.map +1 -0
  79. package/dist/data/__tests__/test-helpers.d.ts +53 -0
  80. package/dist/data/__tests__/test-helpers.d.ts.map +1 -0
  81. package/dist/data/__tests__/test-helpers.js +175 -0
  82. package/dist/data/__tests__/test-helpers.js.map +1 -0
  83. package/dist/data/client.d.ts +44 -0
  84. package/dist/data/client.d.ts.map +1 -0
  85. package/dist/data/client.js +40 -0
  86. package/dist/data/client.js.map +1 -0
  87. package/dist/data/index.d.ts +12 -0
  88. package/dist/data/index.d.ts.map +1 -0
  89. package/dist/data/index.js +11 -0
  90. package/dist/data/index.js.map +1 -0
  91. package/dist/data/pagination.d.ts +30 -0
  92. package/dist/data/pagination.d.ts.map +1 -0
  93. package/dist/data/pagination.js +53 -0
  94. package/dist/data/pagination.js.map +1 -0
  95. package/dist/index.d.ts +9 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +6 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/permissions/SupabasePlatformPermissionStore.d.ts +25 -0
  100. package/dist/permissions/SupabasePlatformPermissionStore.d.ts.map +1 -0
  101. package/dist/permissions/SupabasePlatformPermissionStore.js +153 -0
  102. package/dist/permissions/SupabasePlatformPermissionStore.js.map +1 -0
  103. package/dist/permissions/__tests__/conformance.test.d.ts +2 -0
  104. package/dist/permissions/__tests__/conformance.test.d.ts.map +1 -0
  105. package/dist/permissions/__tests__/conformance.test.js +27 -0
  106. package/dist/permissions/__tests__/conformance.test.js.map +1 -0
  107. package/dist/permissions/index.d.ts +2 -0
  108. package/dist/permissions/index.d.ts.map +1 -0
  109. package/dist/permissions/index.js +2 -0
  110. package/dist/permissions/index.js.map +1 -0
  111. package/dist/storage/SupabaseStorageProvider.d.ts +67 -0
  112. package/dist/storage/SupabaseStorageProvider.d.ts.map +1 -0
  113. package/dist/storage/SupabaseStorageProvider.js +136 -0
  114. package/dist/storage/SupabaseStorageProvider.js.map +1 -0
  115. package/dist/storage/__tests__/conformance.test.d.ts +2 -0
  116. package/dist/storage/__tests__/conformance.test.d.ts.map +1 -0
  117. package/dist/storage/__tests__/conformance.test.js +149 -0
  118. package/dist/storage/__tests__/conformance.test.js.map +1 -0
  119. package/dist/storage/index.d.ts +3 -0
  120. package/dist/storage/index.d.ts.map +1 -0
  121. package/dist/storage/index.js +2 -0
  122. package/dist/storage/index.js.map +1 -0
  123. package/dist/userProfile/SupabaseUserProfileProvider.d.ts +16 -0
  124. package/dist/userProfile/SupabaseUserProfileProvider.d.ts.map +1 -0
  125. package/dist/userProfile/SupabaseUserProfileProvider.js +148 -0
  126. package/dist/userProfile/SupabaseUserProfileProvider.js.map +1 -0
  127. package/dist/userProfile/__tests__/conformance.test.d.ts +2 -0
  128. package/dist/userProfile/__tests__/conformance.test.d.ts.map +1 -0
  129. package/dist/userProfile/__tests__/conformance.test.js +38 -0
  130. package/dist/userProfile/__tests__/conformance.test.js.map +1 -0
  131. package/dist/userProfile/index.d.ts +2 -0
  132. package/dist/userProfile/index.d.ts.map +1 -0
  133. package/dist/userProfile/index.js +2 -0
  134. package/dist/userProfile/index.js.map +1 -0
  135. package/package.json +75 -0
  136. package/src/auth/SupabaseAuthProvider.ts +464 -0
  137. package/src/auth/__tests__/conformance.test.ts +78 -0
  138. package/src/auth/index.ts +2 -0
  139. package/src/data/SupabaseAuditQuery.ts +103 -0
  140. package/src/data/SupabaseComputeServerStore.ts +262 -0
  141. package/src/data/SupabaseDataProvider.ts +125 -0
  142. package/src/data/SupabaseDefinitionStore.ts +504 -0
  143. package/src/data/SupabaseEventSink.ts +30 -0
  144. package/src/data/SupabaseInviteStore.ts +183 -0
  145. package/src/data/SupabaseOrgStore.ts +547 -0
  146. package/src/data/SupabaseProjectStore.ts +414 -0
  147. package/src/data/SupabaseShareLinkStore.ts +191 -0
  148. package/src/data/__tests__/compute-server-conformance.test.ts +40 -0
  149. package/src/data/__tests__/definition-conformance.test.ts +89 -0
  150. package/src/data/__tests__/event-sink-conformance.test.ts +32 -0
  151. package/src/data/__tests__/invite-conformance.test.ts +46 -0
  152. package/src/data/__tests__/org-conformance.test.ts +30 -0
  153. package/src/data/__tests__/project-conformance.test.ts +57 -0
  154. package/src/data/__tests__/share-link-conformance.test.ts +87 -0
  155. package/src/data/__tests__/test-helpers.ts +186 -0
  156. package/src/data/client.ts +86 -0
  157. package/src/data/index.ts +11 -0
  158. package/src/data/pagination.ts +68 -0
  159. package/src/index.ts +23 -0
  160. package/src/permissions/SupabasePlatformPermissionStore.ts +161 -0
  161. package/src/permissions/__tests__/conformance.test.ts +28 -0
  162. package/src/permissions/index.ts +1 -0
  163. package/src/storage/SupabaseStorageProvider.ts +177 -0
  164. package/src/storage/__tests__/conformance.test.ts +152 -0
  165. package/src/storage/index.ts +2 -0
  166. package/src/userProfile/SupabaseUserProfileProvider.ts +177 -0
  167. package/src/userProfile/__tests__/conformance.test.ts +39 -0
  168. package/src/userProfile/index.ts +1 -0
  169. package/supabase/.branches/_current_branch +1 -0
  170. package/supabase/.temp/cli-latest +1 -0
  171. package/supabase/config.toml +68 -0
  172. package/supabase/migrations/0001_initial.sql +1084 -0
  173. package/supabase/seed.sql +13 -0
@@ -0,0 +1,383 @@
1
+ import { createClient } from '@supabase/supabase-js';
2
+ export class SupabaseAuthProvider {
3
+ name = 'Supabase Auth';
4
+ passwordAuth;
5
+ oauth;
6
+ emailLink;
7
+ admin;
8
+ anon;
9
+ anonKey;
10
+ supabaseUrl;
11
+ constructor(config) {
12
+ this.supabaseUrl = config.supabaseUrl;
13
+ this.anonKey = config.anonKey;
14
+ this.admin = createClient(config.supabaseUrl, config.serviceRoleKey, {
15
+ auth: { persistSession: false, autoRefreshToken: false }
16
+ });
17
+ this.anon = createClient(config.supabaseUrl, config.anonKey, {
18
+ auth: { persistSession: false, autoRefreshToken: false }
19
+ });
20
+ this.passwordAuth = new SupabasePasswordAuth(this.admin, this.anon, (email, password) => this.signIn(email, password), config.enableSelfSignup ?? false, (user) => this.hydrate(user));
21
+ this.oauth = new SupabaseOAuthAuth(this.anon, (user) => this.hydrate(user), config.oauthProviders ?? []);
22
+ this.emailLink = new SupabaseEmailLinkAuth(this.anon, (user) => this.hydrate(user), config.allowEmailLinkSignup ?? true);
23
+ }
24
+ static fromEnv(env) {
25
+ const supabaseUrl = env.SUPABASE_URL;
26
+ const anonKey = env.SUPABASE_ANON_KEY;
27
+ const serviceRoleKey = env.SUPABASE_SERVICE_ROLE_KEY;
28
+ if (!supabaseUrl)
29
+ throw new Error('Missing required env var: SUPABASE_URL');
30
+ if (!anonKey)
31
+ throw new Error('Missing required env var: SUPABASE_ANON_KEY');
32
+ if (!serviceRoleKey)
33
+ throw new Error('Missing required env var: SUPABASE_SERVICE_ROLE_KEY');
34
+ const oauthProviders = (env.SUPABASE_OAUTH_PROVIDERS ?? '')
35
+ .split(',')
36
+ .map((p) => p.trim().toLowerCase())
37
+ .filter((p) => p.length > 0);
38
+ return new SupabaseAuthProvider({
39
+ supabaseUrl,
40
+ anonKey,
41
+ serviceRoleKey,
42
+ enableSelfSignup: env.SUPABASE_ENABLE_SELF_SIGNUP === 'true',
43
+ oauthProviders,
44
+ // Default true; set SUPABASE_ALLOW_EMAIL_LINK_SIGNUP=false to lock down
45
+ // to invite-only and reject magic-link signups for new addresses.
46
+ allowEmailLinkSignup: env.SUPABASE_ALLOW_EMAIL_LINK_SIGNUP !== 'false'
47
+ });
48
+ }
49
+ async verifyToken(token) {
50
+ if (!token)
51
+ return null;
52
+ // Per-request anon client with the JWT attached. `getUser(token)` also
53
+ // works, but routing through a scoped client keeps future sub-calls
54
+ // (profile fetch, etc.) RLS-aware if we ever move them here.
55
+ const { data, error } = await this.anon.auth.getUser(token);
56
+ if (error || !data.user)
57
+ return null;
58
+ if (data.user.user_metadata?.disabled === true)
59
+ return null;
60
+ return this.hydrate(data.user);
61
+ }
62
+ async getUser(id) {
63
+ const { data, error } = await this.admin.auth.admin.getUserById(id);
64
+ if (error || !data.user)
65
+ return null;
66
+ return this.hydrate(data.user);
67
+ }
68
+ async listUsers(opts) {
69
+ // GoTrue's admin.listUsers uses its own pagination (page/perPage).
70
+ // Translate our cursor (offset) into page number.
71
+ const perPage = opts?.limit ?? 50;
72
+ const page = opts?.cursor ? parseInt(opts.cursor, 10) : 1;
73
+ const { data, error } = await this.admin.auth.admin.listUsers({
74
+ page: Number.isFinite(page) && page >= 1 ? page : 1,
75
+ perPage
76
+ });
77
+ if (error)
78
+ throw error;
79
+ const users = data.users;
80
+ const hydrated = users.map((u) => this.hydrate(u));
81
+ // If the page was full, assume there may be more.
82
+ const nextCursor = users.length >= perPage ? String(page + 1) : undefined;
83
+ return { items: hydrated, nextCursor };
84
+ }
85
+ async createUser(email) {
86
+ // Allowlist variant: create without a password. The user receives a
87
+ // magic-link / OIDC handoff from the consuming app. Identity-only;
88
+ // platform permissions are granted via IPlatformPermissionStore.
89
+ const { data, error } = await this.admin.auth.admin.createUser({
90
+ email,
91
+ email_confirm: true
92
+ });
93
+ if (error)
94
+ throw error;
95
+ if (!data.user)
96
+ throw new Error('createUser returned no user');
97
+ return this.hydrate(data.user);
98
+ }
99
+ async deleteUser(id) {
100
+ // Identity-only delete. The §2 sole-`instance_admin` invariant lives
101
+ // on IPlatformPermissionStore; callers consult it before calling here.
102
+ const { error } = await this.admin.auth.admin.deleteUser(id);
103
+ if (error) {
104
+ // 404-shaped errors from GoTrue surface as { status: 404 } or a
105
+ // specific message. Normalize to 'not_found' rather than throwing.
106
+ const e = error;
107
+ if (e.status === 404 || /not.?found/i.test(e.message ?? ''))
108
+ return 'not_found';
109
+ throw error;
110
+ }
111
+ return 'ok';
112
+ }
113
+ async disableUser(id) {
114
+ const { data: existing, error: fetchError } = await this.admin.auth.admin.getUserById(id);
115
+ if (fetchError || !existing.user)
116
+ return 'not_found';
117
+ // GoTrue's user_metadata update merges shallowly — preserve existing
118
+ // fields by spreading them in.
119
+ const mergedMetadata = {
120
+ ...(existing.user.user_metadata ?? {}),
121
+ disabled: true
122
+ };
123
+ const { error } = await this.admin.auth.admin.updateUserById(id, {
124
+ user_metadata: mergedMetadata
125
+ });
126
+ if (error) {
127
+ const e = error;
128
+ if (e.status === 404 || /not.?found/i.test(e.message ?? ''))
129
+ return 'not_found';
130
+ throw error;
131
+ }
132
+ return 'ok';
133
+ }
134
+ async touchLastLogin(id) {
135
+ // 60-second debounce. Matches the local provider.
136
+ const { data, error } = await this.admin
137
+ .from('user_profiles')
138
+ .select('last_login_at')
139
+ .eq('user_id', id)
140
+ .maybeSingle();
141
+ if (error)
142
+ return;
143
+ if (data?.last_login_at) {
144
+ const prev = Date.parse(data.last_login_at);
145
+ if (Number.isFinite(prev) && Date.now() - prev < 60_000)
146
+ return;
147
+ }
148
+ await this.admin
149
+ .from('user_profiles')
150
+ .update({ last_login_at: new Date().toISOString() })
151
+ .eq('user_id', id);
152
+ }
153
+ // OAuth lives on `this.oauth` (typed `IOAuthAuth`); see `SupabaseOAuthAuth`
154
+ // below. Mirrors the `passwordAuth` capability split.
155
+ // ============================================================================
156
+ // Internals
157
+ // ============================================================================
158
+ /**
159
+ * Sign in via GoTrue. Returns the access token string and the hydrated
160
+ * user. Called by `SupabasePasswordAuth.verifyLogin` — kept on the
161
+ * provider class so it has access to the hydrate helper without plumbing.
162
+ */
163
+ async signIn(email, password) {
164
+ const { data, error } = await this.anon.auth.signInWithPassword({ email, password });
165
+ if (error || !data.user || !data.session)
166
+ return null;
167
+ if (data.user.user_metadata?.disabled === true)
168
+ return null;
169
+ return { user: this.hydrate(data.user), sessionToken: data.session.access_token };
170
+ }
171
+ /**
172
+ * Map a GoTrue `User` to our identity-only `AuthUser`. Platform permissions
173
+ * live on `IPlatformPermissionStore` and profile fields (displayName,
174
+ * starred, recentRuns) on `IUserProfileStore` — neither is in AuthUser.
175
+ */
176
+ hydrate(user) {
177
+ return {
178
+ id: user.id,
179
+ email: user.email ?? undefined,
180
+ createdAt: user.created_at ?? undefined,
181
+ lastLoginAt: user.last_sign_in_at ?? undefined,
182
+ disabled: user.user_metadata?.disabled === true,
183
+ metadata: user.user_metadata
184
+ };
185
+ }
186
+ /**
187
+ * Expose the anon URL + key so other code (e.g. the same process's
188
+ * storage provider or per-request client factories) can build user-scoped
189
+ * clients without requiring a second config read.
190
+ */
191
+ getAnonClientConfig() {
192
+ return { supabaseUrl: this.supabaseUrl, anonKey: this.anonKey };
193
+ }
194
+ }
195
+ class SupabasePasswordAuth {
196
+ admin;
197
+ anon;
198
+ signIn;
199
+ enableSelfSignup;
200
+ hydrate;
201
+ constructor(admin, anon, signIn, enableSelfSignup, hydrate) {
202
+ this.admin = admin;
203
+ this.anon = anon;
204
+ this.signIn = signIn;
205
+ this.enableSelfSignup = enableSelfSignup;
206
+ this.hydrate = hydrate;
207
+ }
208
+ async verifyLogin(email, password) {
209
+ const result = await this.signIn(email, password);
210
+ if (!result)
211
+ return { kind: 'failed', reason: 'invalid_credentials' };
212
+ return { kind: 'success', user: result.user, sessionToken: result.sessionToken };
213
+ }
214
+ async createUserWithPassword(email, password) {
215
+ // Identity-only — platform permissions are granted separately via
216
+ // IPlatformPermissionStore.set after creation.
217
+ const { data, error } = await this.admin.auth.admin.createUser({
218
+ email,
219
+ password,
220
+ email_confirm: true
221
+ });
222
+ if (error)
223
+ throw error;
224
+ if (!data.user)
225
+ throw new Error('createUserWithPassword returned no user');
226
+ return this.hydrate(data.user);
227
+ }
228
+ async registerUser(email, password) {
229
+ if (!this.enableSelfSignup)
230
+ return null;
231
+ const { data, error } = await this.anon.auth.signUp({ email, password });
232
+ if (error || !data.user)
233
+ return null;
234
+ return this.hydrate(data.user);
235
+ }
236
+ }
237
+ /**
238
+ * Supabase-backed `IOAuthAuth`. Thin wrappers over GoTrue's `signInWithOAuth`
239
+ * / `exchangeCodeForSession` / `refreshSession` — the failure-shape mapping
240
+ * (return null vs throw) is the only logic.
241
+ */
242
+ class SupabaseOAuthAuth {
243
+ anon;
244
+ hydrate;
245
+ providers;
246
+ constructor(anon, hydrate, providers) {
247
+ this.anon = anon;
248
+ this.hydrate = hydrate;
249
+ this.providers = providers;
250
+ }
251
+ listProviders() {
252
+ return this.providers;
253
+ }
254
+ async getOAuthAuthorizationUrl(provider, redirectTo) {
255
+ const { data, error } = await this.anon.auth.signInWithOAuth({
256
+ provider,
257
+ options: { redirectTo, skipBrowserRedirect: true }
258
+ });
259
+ if (error || !data.url)
260
+ throw error ?? new Error('signInWithOAuth returned no URL');
261
+ return data.url;
262
+ }
263
+ async exchangeOAuthCode(code) {
264
+ const { data, error } = await this.anon.auth.exchangeCodeForSession(code);
265
+ if (error || !data.user || !data.session)
266
+ return null;
267
+ if (data.user.user_metadata?.disabled === true)
268
+ return null;
269
+ return {
270
+ user: this.hydrate(data.user),
271
+ sessionToken: data.session.access_token,
272
+ refreshToken: data.session.refresh_token
273
+ };
274
+ }
275
+ async refreshSession(refreshToken) {
276
+ const { data, error } = await this.anon.auth.refreshSession({ refresh_token: refreshToken });
277
+ if (error || !data.session)
278
+ return null;
279
+ return {
280
+ sessionToken: data.session.access_token,
281
+ refreshToken: data.session.refresh_token
282
+ };
283
+ }
284
+ }
285
+ /**
286
+ * Supabase-backed `IEmailLinkAuth`. Wraps GoTrue's `signInWithOtp` (send the
287
+ * link) and `verifyOtp` with `type: 'magiclink' | 'email' | 'signup'`
288
+ * (verify on click).
289
+ *
290
+ * Token shape: Supabase emails the user `{callbackUrl}?token_hash=…&type=…`.
291
+ * `verifyMagicLink` accepts either the full URL or just the raw `token_hash`
292
+ * — adapters MAY support either to give the route layer flexibility. The
293
+ * `type` query param decides which OTP variant `verifyOtp` runs (signup vs
294
+ * magic-link returning user vs invite acceptance), so we pass it through.
295
+ */
296
+ class SupabaseEmailLinkAuth {
297
+ anon;
298
+ hydrate;
299
+ allowSignup;
300
+ constructor(anon, hydrate, allowSignup) {
301
+ this.anon = anon;
302
+ this.hydrate = hydrate;
303
+ this.allowSignup = allowSignup;
304
+ }
305
+ async sendMagicLink(email, callbackUrl) {
306
+ const { error } = await this.anon.auth.signInWithOtp({
307
+ email,
308
+ options: {
309
+ emailRedirectTo: callbackUrl,
310
+ shouldCreateUser: this.allowSignup
311
+ }
312
+ });
313
+ if (!error)
314
+ return { ok: true };
315
+ // Map GoTrue's classified errors to our coarse reasons. Anything we
316
+ // don't recognize we throw — the route returns 500 and we get a stack
317
+ // trace, instead of swallowing a real bug as "rate limited".
318
+ const status = error.status;
319
+ const code = error.code;
320
+ const message = error.message ?? '';
321
+ if (status === 429 || /rate.?limit/i.test(message))
322
+ return { ok: false, reason: 'rate_limited' };
323
+ if (code === 'otp_disabled' ||
324
+ code === 'signup_disabled' ||
325
+ /signup.*disabled/i.test(message)) {
326
+ return { ok: false, reason: 'signup_disabled' };
327
+ }
328
+ if (code === 'validation_failed' || /invalid.*email|email.*invalid/i.test(message)) {
329
+ return { ok: false, reason: 'invalid_email' };
330
+ }
331
+ throw error;
332
+ }
333
+ async verifyMagicLink(rawCallbackUrl) {
334
+ const params = parseCallbackParams(rawCallbackUrl);
335
+ if (!params)
336
+ return null;
337
+ const { tokenHash, type } = params;
338
+ const { data, error } = await this.anon.auth.verifyOtp({
339
+ token_hash: tokenHash,
340
+ type
341
+ });
342
+ if (error || !data.user || !data.session)
343
+ return null;
344
+ if (data.user.user_metadata?.disabled === true)
345
+ return null;
346
+ return {
347
+ user: this.hydrate(data.user),
348
+ sessionToken: data.session.access_token,
349
+ refreshToken: data.session.refresh_token
350
+ };
351
+ }
352
+ }
353
+ /**
354
+ * Pull `token_hash` + `type` from either a full callback URL or a bare
355
+ * `token_hash=…&type=…` query string. Tolerant of both shapes so the route
356
+ * layer can pass whichever form is convenient.
357
+ *
358
+ * Returns null when the inputs aren't recognizable — the caller treats null
359
+ * as "send the user back to /login".
360
+ */
361
+ function parseCallbackParams(raw) {
362
+ let search;
363
+ try {
364
+ // Full URL path
365
+ search = new URL(raw).searchParams;
366
+ }
367
+ catch {
368
+ // Query-string-only path — treat as bare params.
369
+ search = new URLSearchParams(raw.startsWith('?') ? raw.slice(1) : raw);
370
+ }
371
+ const tokenHash = search.get('token_hash');
372
+ const type = search.get('type');
373
+ if (!tokenHash)
374
+ return null;
375
+ const allowed = new Set(['magiclink', 'email', 'signup', 'invite', 'recovery']);
376
+ if (!type || !allowed.has(type))
377
+ return null;
378
+ return {
379
+ tokenHash,
380
+ type: type
381
+ };
382
+ }
383
+ //# sourceMappingURL=SupabaseAuthProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SupabaseAuthProvider.js","sourceRoot":"","sources":["../../src/auth/SupabaseAuthProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=conformance.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformance.test.d.ts","sourceRoot":"","sources":["../../../src/auth/__tests__/conformance.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,76 @@
1
+ import { describe, beforeEach, it } from 'vitest';
2
+ import { runAuthProviderConformance, runEmailLinkAuthConformance } from '@selvajs/platform/testing';
3
+ import { SupabaseAuthProvider } from '../SupabaseAuthProvider.js';
4
+ import { readEnv, resetAllData } from '../../data/__tests__/test-helpers.js';
5
+ const envCtx = readEnv();
6
+ if (!envCtx) {
7
+ describe.skip('SupabaseAuthProvider (skipped: no live stack)', () => {
8
+ it('populate packages/providers/supabase/.env.test with Supabase creds to run these tests', () => { });
9
+ });
10
+ }
11
+ else {
12
+ const ctx = envCtx; // non-null in this branch
13
+ // The auth conformance suite expects `verifyLogin('', adminPassword)` to
14
+ // succeed. Supabase requires a non-empty email, so we seed a deterministic
15
+ // admin email and have the suite use that via the `adminEmail` option.
16
+ const ADMIN_EMAIL = 'admin@conformance.test';
17
+ const ADMIN_PASSWORD = 'conformance-admin-password-1234';
18
+ async function ensureAdmin() {
19
+ const { data: existing } = await ctx.adminClient.auth.admin.listUsers({ perPage: 1000 });
20
+ const match = existing.users.find((u) => u.email === ADMIN_EMAIL);
21
+ if (match)
22
+ return match.id;
23
+ const { data, error } = await ctx.adminClient.auth.admin.createUser({
24
+ email: ADMIN_EMAIL,
25
+ password: ADMIN_PASSWORD,
26
+ email_confirm: true
27
+ });
28
+ if (error)
29
+ throw error;
30
+ return data.user.id;
31
+ }
32
+ async function makeProvider() {
33
+ const provider = new SupabaseAuthProvider({
34
+ supabaseUrl: ctx.url,
35
+ anonKey: ctx.anonKey,
36
+ serviceRoleKey: ctx.serviceRoleKey
37
+ });
38
+ // Ensure the admin account exists + has instance_admin.
39
+ const id = await ensureAdmin();
40
+ const { error: upError } = await ctx.adminClient
41
+ .from('user_profiles')
42
+ .update({ platform_permissions: ['instance_admin'] })
43
+ .eq('user_id', id);
44
+ if (upError)
45
+ throw upError;
46
+ return { provider, adminPassword: ADMIN_PASSWORD };
47
+ }
48
+ describe('SupabaseAuthProvider', () => {
49
+ beforeEach(async () => {
50
+ await resetAllData(ctx);
51
+ });
52
+ runAuthProviderConformance({
53
+ name: 'SupabaseAuthProvider',
54
+ createProvider: async () => {
55
+ const { provider, adminPassword } = await makeProvider();
56
+ return { provider, adminPassword, adminEmail: ADMIN_EMAIL };
57
+ },
58
+ userManagement: true
59
+ });
60
+ runEmailLinkAuthConformance({
61
+ name: 'SupabaseEmailLinkAuth',
62
+ createAdapter: async () => {
63
+ const { provider } = await makeProvider();
64
+ return {
65
+ adapter: provider.emailLink,
66
+ // `validEmail` isn't used by the suite for live mail delivery;
67
+ // it just needs to look like a real address. The malformed
68
+ // case is what we actually assert on.
69
+ validEmail: 'real-looking@conformance.test',
70
+ invalidEmail: 'not-an-email-address'
71
+ };
72
+ }
73
+ });
74
+ });
75
+ }
76
+ //# sourceMappingURL=conformance.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformance.test.js","sourceRoot":"","sources":["../../../src/auth/__tests__/conformance.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { SupabaseAuthProvider } from './SupabaseAuthProvider.js';
2
+ export type { SupabaseAuthProviderConfig } from './SupabaseAuthProvider.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,YAAY,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { SupabaseAuthProvider } from './SupabaseAuthProvider.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { AuditQueryFilters, AuditQueryResult, IAuditQuery, RequestContext } from '@selvajs/platform';
2
+ import type { ClientBundle } from './client.js';
3
+ /**
4
+ * Read-side for `audit_events`. Always uses the service-role client — RLS
5
+ * blocks all read access by design, so the route layer is the single trust
6
+ * boundary (callers must gate on `instance_admin`).
7
+ *
8
+ * Pagination is keyset on `(occurred_at desc, id desc)`. The `id` tie-breaker
9
+ * prevents skipped rows when multiple events land in the same millisecond.
10
+ */
11
+ export declare class SupabaseAuditQuery implements IAuditQuery {
12
+ private readonly clients;
13
+ constructor(clients: ClientBundle);
14
+ list(_ctx: RequestContext, filters: AuditQueryFilters): Promise<AuditQueryResult>;
15
+ }
16
+ //# sourceMappingURL=SupabaseAuditQuery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SupabaseAuditQuery.d.ts","sourceRoot":"","sources":["../../src/data/SupabaseAuditQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEX,iBAAiB,EACjB,gBAAgB,EAEhB,WAAW,EACX,cAAc,EACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAUhD;;;;;;;GAOG;AACH,qBAAa,kBAAmB,YAAW,WAAW;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY;IAE5C,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAmEvF"}
@@ -0,0 +1,83 @@
1
+ const MAX_LIMIT = 200;
2
+ const DEFAULT_LIMIT = 100;
3
+ // Cursor values are interpolated into PostgREST filter strings — both formats
4
+ // must be validated before any string concatenation reaches the query.
5
+ const ISO_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})$/;
6
+ const UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
7
+ /**
8
+ * Read-side for `audit_events`. Always uses the service-role client — RLS
9
+ * blocks all read access by design, so the route layer is the single trust
10
+ * boundary (callers must gate on `instance_admin`).
11
+ *
12
+ * Pagination is keyset on `(occurred_at desc, id desc)`. The `id` tie-breaker
13
+ * prevents skipped rows when multiple events land in the same millisecond.
14
+ */
15
+ export class SupabaseAuditQuery {
16
+ clients;
17
+ constructor(clients) {
18
+ this.clients = clients;
19
+ }
20
+ async list(_ctx, filters) {
21
+ const limit = clampLimit(filters.limit);
22
+ let q = this.clients.serviceClient
23
+ .from('audit_events')
24
+ .select('id, type, actor_id, occurred_at, data')
25
+ .order('occurred_at', { ascending: false })
26
+ .order('id', { ascending: false })
27
+ // Fetch one extra row to detect "has next page" without a count query.
28
+ .limit(limit + 1);
29
+ if (filters.types && filters.types.length > 0) {
30
+ q = q.in('type', [...filters.types]);
31
+ }
32
+ if (filters.actorId) {
33
+ q = q.eq('actor_id', filters.actorId);
34
+ }
35
+ if (filters.sinceIso) {
36
+ q = q.gte('occurred_at', filters.sinceIso);
37
+ }
38
+ if (filters.untilIso) {
39
+ q = q.lte('occurred_at', filters.untilIso);
40
+ }
41
+ if (filters.cursor) {
42
+ // `(occurred_at, id) < (cursorTs, cursorId)` expressed for PostgREST:
43
+ // strictly older OR same timestamp with a strictly smaller id.
44
+ //
45
+ // Both values are interpolated into a `.or()` filter string. Validate
46
+ // shape before interpolation — without these guards a malformed cursor
47
+ // (or a hand-crafted URL by a route caller) could break out of the
48
+ // filter and combine with arbitrary PostgREST operators.
49
+ const ts = filters.cursor.occurredAt;
50
+ const id = filters.cursor.id;
51
+ if (!ISO_RE.test(ts) || !UUID_RE.test(id)) {
52
+ throw new Error('audit_events query: malformed cursor');
53
+ }
54
+ q = q.or(`occurred_at.lt.${ts},and(occurred_at.eq.${ts},id.lt.${id})`);
55
+ }
56
+ const { data, error } = await q;
57
+ if (error) {
58
+ throw new Error(`audit_events query failed: ${error.message}`);
59
+ }
60
+ const fetched = (data ?? []);
61
+ const hasMore = fetched.length > limit;
62
+ const page = hasMore ? fetched.slice(0, limit) : fetched;
63
+ const last = page[page.length - 1];
64
+ return {
65
+ rows: page.map((r) => ({
66
+ id: r.id,
67
+ type: r.type,
68
+ actorId: r.actor_id,
69
+ occurredAt: r.occurred_at,
70
+ data: r.data
71
+ })),
72
+ nextCursor: hasMore && last ? { occurredAt: last.occurred_at, id: last.id } : null
73
+ };
74
+ }
75
+ }
76
+ function clampLimit(requested) {
77
+ if (!requested || requested <= 0)
78
+ return DEFAULT_LIMIT;
79
+ if (requested > MAX_LIMIT)
80
+ return MAX_LIMIT;
81
+ return Math.floor(requested);
82
+ }
83
+ //# sourceMappingURL=SupabaseAuditQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SupabaseAuditQuery.js","sourceRoot":"","sources":["../../src/data/SupabaseAuditQuery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { type IComputeServerStore, type ComputeConfig, type ComputeServerConfig, type RequestContext } from '@selvajs/platform';
2
+ import type { ClientBundle } from './client.js';
3
+ /**
4
+ * Compute-server config backed by three tables:
5
+ * - `compute_servers`: one row per server. `scope = 'platform' | 'org'`.
6
+ * Platform rows carry a `shared_with_all` flag + `compute_server_shares`
7
+ * allowlist; org rows carry `owner_org_id`.
8
+ * - `compute_server_shares`: many-to-many for platform servers shared
9
+ * with specific orgs (when `shared_with_all = false`).
10
+ * - `compute_server_org_defaults`: per-org `orgDefaults[orgId]` choice.
11
+ * - `compute_server_platform_default`: single-row sentinel for the global
12
+ * `defaultServerId`.
13
+ *
14
+ * `getConfig` returns the full doc; the visibility predicate is applied by
15
+ * callers (resolver, page loaders) using helpers in `@selvajs/platform`.
16
+ */
17
+ export declare class SupabaseComputeServerStore implements IComputeServerStore {
18
+ private readonly clients;
19
+ constructor(clients: ClientBundle);
20
+ getConfig(ctx: RequestContext): Promise<ComputeConfig>;
21
+ savePlatformServers(ctx: RequestContext, servers: ComputeServerConfig[], defaultServerId: string | undefined): Promise<void>;
22
+ saveOrgServers(ctx: RequestContext, orgId: string, servers: ComputeServerConfig[], defaultServerId?: string | null): Promise<void>;
23
+ setOrgDefault(ctx: RequestContext, orgId: string, serverId: string | null): Promise<void>;
24
+ deleteByOrg(ctx: RequestContext, orgId: string): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=SupabaseComputeServerStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SupabaseComputeServerStore.d.ts","sourceRoot":"","sources":["../../src/data/SupabaseComputeServerStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AACH,qBAAa,0BAA2B,YAAW,mBAAmB;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY;IAE5C,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAyCtD,mBAAmB,CACxB,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,mBAAmB,EAAE,EAC9B,eAAe,EAAE,MAAM,GAAG,SAAS,GACjC,OAAO,CAAC,IAAI,CAAC;IAiCV,cAAc,CACnB,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,mBAAmB,EAAE,EAC9B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,GAC7B,OAAO,CAAC,IAAI,CAAC;IAgCV,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBzF,WAAW,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA0BpE"}