@selvajs/supabase-provider 0.14.4-beta.0 → 0.15.0-beta.2

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 (158) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +2 -0
  3. package/dist/auth/SupabaseAuthProvider.d.ts.map +1 -1
  4. package/dist/auth/SupabaseAuthProvider.js +7 -14
  5. package/dist/auth/SupabaseAuthProvider.js.map +1 -1
  6. package/dist/data/SupabaseComputeServerStore.d.ts +14 -3
  7. package/dist/data/SupabaseComputeServerStore.d.ts.map +1 -1
  8. package/dist/data/SupabaseComputeServerStore.js +67 -16
  9. package/dist/data/SupabaseComputeServerStore.js.map +1 -1
  10. package/dist/data/SupabaseDataProvider.d.ts +36 -8
  11. package/dist/data/SupabaseDataProvider.d.ts.map +1 -1
  12. package/dist/data/SupabaseDataProvider.js +119 -15
  13. package/dist/data/SupabaseDataProvider.js.map +1 -1
  14. package/dist/data/SupabaseDefinitionStore.d.ts +1 -0
  15. package/dist/data/SupabaseDefinitionStore.d.ts.map +1 -1
  16. package/dist/data/SupabaseDefinitionStore.js +41 -4
  17. package/dist/data/SupabaseDefinitionStore.js.map +1 -1
  18. package/dist/data/SupabaseEventSink.d.ts +5 -2
  19. package/dist/data/SupabaseEventSink.d.ts.map +1 -1
  20. package/dist/data/SupabaseEventSink.js +20 -3
  21. package/dist/data/SupabaseEventSink.js.map +1 -1
  22. package/dist/data/SupabaseSolveMetricSink.d.ts +49 -4
  23. package/dist/data/SupabaseSolveMetricSink.d.ts.map +1 -1
  24. package/dist/data/SupabaseSolveMetricSink.js +109 -19
  25. package/dist/data/SupabaseSolveMetricSink.js.map +1 -1
  26. package/dist/data/index.d.ts +1 -0
  27. package/dist/data/index.d.ts.map +1 -1
  28. package/dist/data/index.js +1 -0
  29. package/dist/data/index.js.map +1 -1
  30. package/dist/data/migrationHead.d.ts +14 -0
  31. package/dist/data/migrationHead.d.ts.map +1 -0
  32. package/dist/data/migrationHead.js +14 -0
  33. package/dist/data/migrationHead.js.map +1 -0
  34. package/dist/index.d.ts +1 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +1 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/permissions/SupabasePlatformPermissionStore.d.ts +5 -3
  39. package/dist/permissions/SupabasePlatformPermissionStore.d.ts.map +1 -1
  40. package/dist/permissions/SupabasePlatformPermissionStore.js +17 -30
  41. package/dist/permissions/SupabasePlatformPermissionStore.js.map +1 -1
  42. package/dist/storage/SupabaseStorageProvider.d.ts.map +1 -1
  43. package/dist/storage/SupabaseStorageProvider.js +3 -0
  44. package/dist/storage/SupabaseStorageProvider.js.map +1 -1
  45. package/package.json +23 -14
  46. package/supabase/migrations/20260712120000_user_profiles_disabled_and_gin.sql +95 -0
  47. package/supabase/migrations/20260712123000_selva_migration_head_fn.sql +38 -0
  48. package/supabase/migrations/20260713120000_selva_next_version_number.sql +59 -0
  49. package/supabase/migrations/20260713140000_selva_solve_cache_limit.sql +15 -0
  50. package/supabase/migrations/20260716120000_definition_status_and_audit_version.sql +36 -0
  51. package/supabase/migrations/20260716130000_erase_user_audit_email.sql +36 -0
  52. package/supabase/migrations/20260717120000_compute_server_has_api_key.sql +20 -0
  53. package/dist/auth/__tests__/conformance.test.d.ts +0 -2
  54. package/dist/auth/__tests__/conformance.test.d.ts.map +0 -1
  55. package/dist/auth/__tests__/conformance.test.js +0 -76
  56. package/dist/auth/__tests__/conformance.test.js.map +0 -1
  57. package/dist/auth/__tests__/token-verification.test.d.ts +0 -13
  58. package/dist/auth/__tests__/token-verification.test.d.ts.map +0 -1
  59. package/dist/auth/__tests__/token-verification.test.js +0 -135
  60. package/dist/auth/__tests__/token-verification.test.js.map +0 -1
  61. package/dist/data/__tests__/compute-server-conformance.test.d.ts +0 -2
  62. package/dist/data/__tests__/compute-server-conformance.test.d.ts.map +0 -1
  63. package/dist/data/__tests__/compute-server-conformance.test.js +0 -45
  64. package/dist/data/__tests__/compute-server-conformance.test.js.map +0 -1
  65. package/dist/data/__tests__/compute-server-encryption.test.d.ts +0 -12
  66. package/dist/data/__tests__/compute-server-encryption.test.d.ts.map +0 -1
  67. package/dist/data/__tests__/compute-server-encryption.test.js +0 -143
  68. package/dist/data/__tests__/compute-server-encryption.test.js.map +0 -1
  69. package/dist/data/__tests__/definition-conformance.test.d.ts +0 -2
  70. package/dist/data/__tests__/definition-conformance.test.d.ts.map +0 -1
  71. package/dist/data/__tests__/definition-conformance.test.js +0 -85
  72. package/dist/data/__tests__/definition-conformance.test.js.map +0 -1
  73. package/dist/data/__tests__/event-sink-conformance.test.d.ts +0 -2
  74. package/dist/data/__tests__/event-sink-conformance.test.d.ts.map +0 -1
  75. package/dist/data/__tests__/event-sink-conformance.test.js +0 -27
  76. package/dist/data/__tests__/event-sink-conformance.test.js.map +0 -1
  77. package/dist/data/__tests__/invite-conformance.test.d.ts +0 -2
  78. package/dist/data/__tests__/invite-conformance.test.d.ts.map +0 -1
  79. package/dist/data/__tests__/invite-conformance.test.js +0 -45
  80. package/dist/data/__tests__/invite-conformance.test.js.map +0 -1
  81. package/dist/data/__tests__/org-conformance.test.d.ts +0 -2
  82. package/dist/data/__tests__/org-conformance.test.d.ts.map +0 -1
  83. package/dist/data/__tests__/org-conformance.test.js +0 -29
  84. package/dist/data/__tests__/org-conformance.test.js.map +0 -1
  85. package/dist/data/__tests__/project-conformance.test.d.ts +0 -2
  86. package/dist/data/__tests__/project-conformance.test.d.ts.map +0 -1
  87. package/dist/data/__tests__/project-conformance.test.js +0 -57
  88. package/dist/data/__tests__/project-conformance.test.js.map +0 -1
  89. package/dist/data/__tests__/share-link-concurrency.test.d.ts +0 -22
  90. package/dist/data/__tests__/share-link-concurrency.test.d.ts.map +0 -1
  91. package/dist/data/__tests__/share-link-concurrency.test.js +0 -115
  92. package/dist/data/__tests__/share-link-concurrency.test.js.map +0 -1
  93. package/dist/data/__tests__/share-link-conformance.test.d.ts +0 -2
  94. package/dist/data/__tests__/share-link-conformance.test.d.ts.map +0 -1
  95. package/dist/data/__tests__/share-link-conformance.test.js +0 -88
  96. package/dist/data/__tests__/share-link-conformance.test.js.map +0 -1
  97. package/dist/data/__tests__/solve-metric-sink-conformance.test.d.ts +0 -2
  98. package/dist/data/__tests__/solve-metric-sink-conformance.test.d.ts.map +0 -1
  99. package/dist/data/__tests__/solve-metric-sink-conformance.test.js +0 -52
  100. package/dist/data/__tests__/solve-metric-sink-conformance.test.js.map +0 -1
  101. package/dist/data/__tests__/test-helpers.d.ts +0 -52
  102. package/dist/data/__tests__/test-helpers.d.ts.map +0 -1
  103. package/dist/data/__tests__/test-helpers.js +0 -177
  104. package/dist/data/__tests__/test-helpers.js.map +0 -1
  105. package/dist/permissions/__tests__/conformance.test.d.ts +0 -2
  106. package/dist/permissions/__tests__/conformance.test.d.ts.map +0 -1
  107. package/dist/permissions/__tests__/conformance.test.js +0 -27
  108. package/dist/permissions/__tests__/conformance.test.js.map +0 -1
  109. package/dist/storage/__tests__/conformance.test.d.ts +0 -2
  110. package/dist/storage/__tests__/conformance.test.d.ts.map +0 -1
  111. package/dist/storage/__tests__/conformance.test.js +0 -149
  112. package/dist/storage/__tests__/conformance.test.js.map +0 -1
  113. package/dist/userProfile/__tests__/conformance.test.d.ts +0 -2
  114. package/dist/userProfile/__tests__/conformance.test.d.ts.map +0 -1
  115. package/dist/userProfile/__tests__/conformance.test.js +0 -38
  116. package/dist/userProfile/__tests__/conformance.test.js.map +0 -1
  117. package/src/auth/SupabaseAuthProvider.ts +0 -600
  118. package/src/auth/__tests__/conformance.test.ts +0 -78
  119. package/src/auth/__tests__/token-verification.test.ts +0 -158
  120. package/src/auth/index.ts +0 -2
  121. package/src/cli/sync-migrations.ts +0 -133
  122. package/src/data/SupabaseAuditQuery.ts +0 -103
  123. package/src/data/SupabaseComputeServerStore.ts +0 -382
  124. package/src/data/SupabaseDataProvider.ts +0 -153
  125. package/src/data/SupabaseDefinitionStore.ts +0 -527
  126. package/src/data/SupabaseEventSink.ts +0 -30
  127. package/src/data/SupabaseInviteStore.ts +0 -171
  128. package/src/data/SupabaseOrgStore.ts +0 -508
  129. package/src/data/SupabaseProjectStore.ts +0 -431
  130. package/src/data/SupabaseShareLinkStore.ts +0 -176
  131. package/src/data/SupabaseSolveMetricSink.ts +0 -38
  132. package/src/data/__tests__/compute-server-conformance.test.ts +0 -46
  133. package/src/data/__tests__/compute-server-encryption.test.ts +0 -173
  134. package/src/data/__tests__/definition-conformance.test.ts +0 -89
  135. package/src/data/__tests__/event-sink-conformance.test.ts +0 -32
  136. package/src/data/__tests__/invite-conformance.test.ts +0 -46
  137. package/src/data/__tests__/org-conformance.test.ts +0 -30
  138. package/src/data/__tests__/project-conformance.test.ts +0 -57
  139. package/src/data/__tests__/share-link-concurrency.test.ts +0 -124
  140. package/src/data/__tests__/share-link-conformance.test.ts +0 -87
  141. package/src/data/__tests__/solve-metric-sink-conformance.test.ts +0 -59
  142. package/src/data/__tests__/test-helpers.ts +0 -188
  143. package/src/data/client.ts +0 -173
  144. package/src/data/errors.ts +0 -45
  145. package/src/data/index.ts +0 -29
  146. package/src/data/pagination.ts +0 -68
  147. package/src/data/query.ts +0 -22
  148. package/src/data/rowStamp.ts +0 -48
  149. package/src/index.ts +0 -42
  150. package/src/permissions/SupabasePlatformPermissionStore.ts +0 -161
  151. package/src/permissions/__tests__/conformance.test.ts +0 -28
  152. package/src/permissions/index.ts +0 -1
  153. package/src/storage/SupabaseStorageProvider.ts +0 -182
  154. package/src/storage/__tests__/conformance.test.ts +0 -152
  155. package/src/storage/index.ts +0 -2
  156. package/src/userProfile/SupabaseUserProfileProvider.ts +0 -177
  157. package/src/userProfile/__tests__/conformance.test.ts +0 -39
  158. package/src/userProfile/index.ts +0 -1
@@ -1,177 +0,0 @@
1
- import type {
2
- IUserProfileStore,
3
- RecentRun,
4
- RequestContext,
5
- UserManagementResult,
6
- UserProfile
7
- } from '@selvajs/platform';
8
- import { ProviderError, hasPermission } from '@selvajs/platform';
9
- import type { ClientBundle } from '../data/client.js';
10
-
11
- /**
12
- * User profile backed by `public.user_profiles` (one row per `auth.users.id`).
13
- * The row is auto-seeded by the `handle_new_auth_user` trigger on signup, so
14
- * the store never inserts — only reads/updates.
15
- *
16
- * Uses the service-role client throughout (RLS on `user_profiles` is
17
- * coarse-grained — server-side flows like the hooks.server.ts profile load
18
- * need access regardless of the caller's identity). The `assertCanAccess`
19
- * check enforces "you can only see/modify your own profile" at the app layer
20
- * to match the `IUserProfileStore` contract.
21
- */
22
- const MAX_RECENT_RUNS = 20;
23
-
24
- export class SupabaseUserProfileProvider implements IUserProfileStore {
25
- constructor(private readonly clients: ClientBundle) {}
26
-
27
- private client() {
28
- return this.clients.serviceClient;
29
- }
30
-
31
- async getProfile(ctx: RequestContext, userId: string): Promise<UserProfile | null> {
32
- assertCanAccess(ctx, userId);
33
- const { data, error } = await this.client()
34
- .from('user_profiles')
35
- .select('user_id, display_name, starred_definitions, recent_runs')
36
- .eq('user_id', userId)
37
- .maybeSingle();
38
- if (error) throw mapError(error);
39
- return data ? rowToProfile(data) : null;
40
- }
41
-
42
- async getProfiles(_ctx: RequestContext, userIds: readonly string[]): Promise<UserProfile[]> {
43
- // Batch read serves display-name lookups across the UI; scoping to one
44
- // user defeats the purpose. No assertCanAccess.
45
- if (userIds.length === 0) return [];
46
- const { data, error } = await this.client()
47
- .from('user_profiles')
48
- .select('user_id, display_name, starred_definitions, recent_runs')
49
- .in('user_id', [...userIds]);
50
- if (error) throw mapError(error);
51
- return (data ?? []).map(rowToProfile);
52
- }
53
-
54
- async updateProfile(
55
- ctx: RequestContext,
56
- userId: string,
57
- patch: { displayName?: string }
58
- ): Promise<UserManagementResult> {
59
- assertCanAccess(ctx, userId);
60
- const row: Record<string, unknown> = {};
61
- if (patch.displayName !== undefined) row.display_name = patch.displayName;
62
- if (Object.keys(row).length === 0) return 'ok';
63
-
64
- const { data, error } = await this.client()
65
- .from('user_profiles')
66
- .update(row)
67
- .eq('user_id', userId)
68
- .select('user_id');
69
- if (error) throw mapError(error);
70
- return data && data.length > 0 ? 'ok' : 'not_found';
71
- }
72
-
73
- async starDefinition(
74
- ctx: RequestContext,
75
- userId: string,
76
- definitionId: string
77
- ): Promise<UserManagementResult> {
78
- assertCanAccess(ctx, userId);
79
- // Read-modify-write is fine for the local scale here; if concurrent
80
- // starring ever becomes a hotspot, a SECURITY DEFINER RPC using
81
- // `array_append` + `array_distinct` closes the race.
82
- const existing = await this.getProfile(ctx, userId);
83
- if (!existing) return 'not_found';
84
- if (existing.starredDefinitions.includes(definitionId)) return 'ok';
85
-
86
- const next = [...existing.starredDefinitions, definitionId];
87
- const { data, error } = await this.client()
88
- .from('user_profiles')
89
- .update({ starred_definitions: next })
90
- .eq('user_id', userId)
91
- .select('user_id');
92
- if (error) throw mapError(error);
93
- return data && data.length > 0 ? 'ok' : 'not_found';
94
- }
95
-
96
- async unstarDefinition(
97
- ctx: RequestContext,
98
- userId: string,
99
- definitionId: string
100
- ): Promise<UserManagementResult> {
101
- assertCanAccess(ctx, userId);
102
- const existing = await this.getProfile(ctx, userId);
103
- if (!existing) return 'not_found';
104
- if (!existing.starredDefinitions.includes(definitionId)) return 'ok';
105
-
106
- const next = existing.starredDefinitions.filter((id) => id !== definitionId);
107
- const { data, error } = await this.client()
108
- .from('user_profiles')
109
- .update({ starred_definitions: next })
110
- .eq('user_id', userId)
111
- .select('user_id');
112
- if (error) throw mapError(error);
113
- return data && data.length > 0 ? 'ok' : 'not_found';
114
- }
115
-
116
- async recordRun(
117
- ctx: RequestContext,
118
- userId: string,
119
- run: RecentRun
120
- ): Promise<UserManagementResult> {
121
- assertCanAccess(ctx, userId);
122
- const existing = await this.getProfile(ctx, userId);
123
- if (!existing) return 'not_found';
124
-
125
- // Prepend newest, de-dupe by definitionId, cap at MAX_RECENT_RUNS.
126
- const filtered = existing.recentRuns.filter((r) => r.definitionId !== run.definitionId);
127
- const next = [run, ...filtered].slice(0, MAX_RECENT_RUNS);
128
-
129
- const { data, error } = await this.client()
130
- .from('user_profiles')
131
- .update({ recent_runs: next })
132
- .eq('user_id', userId)
133
- .select('user_id');
134
- if (error) throw mapError(error);
135
- return data && data.length > 0 ? 'ok' : 'not_found';
136
- }
137
- }
138
-
139
- function assertCanAccess(ctx: RequestContext, userId: string): void {
140
- if (ctx.system) return;
141
- if (ctx.userId === userId) return;
142
- if (hasPermission(ctx, 'instance_admin')) return;
143
- throw new ProviderError('Forbidden: cannot access another user’s profile', 403);
144
- }
145
-
146
- interface ProfileRow {
147
- user_id: string;
148
- display_name: string | null;
149
- starred_definitions: string[] | null;
150
- recent_runs: RecentRun[] | null;
151
- }
152
-
153
- function rowToProfile(row: ProfileRow): UserProfile {
154
- return {
155
- userId: row.user_id,
156
- displayName: row.display_name ?? undefined,
157
- starredDefinitions: row.starred_definitions ?? [],
158
- recentRuns: row.recent_runs ?? []
159
- };
160
- }
161
-
162
- interface PostgrestError {
163
- code?: string;
164
- message?: string;
165
- }
166
-
167
- function mapError(e: unknown): Error {
168
- const pg = e as PostgrestError;
169
- if (pg?.code === '23505') return new ProviderError(pg.message ?? 'Duplicate record', 409);
170
- if (pg?.code === '23503') return new ProviderError(pg.message ?? 'Foreign key violation', 409);
171
- if (e instanceof Error) return e;
172
- if (e && typeof e === 'object') {
173
- const obj = e as { message?: string; code?: string };
174
- return new Error(obj.code ? `[${obj.code}] ${obj.message ?? ''}` : (obj.message ?? String(e)));
175
- }
176
- return new Error(String(e));
177
- }
@@ -1,39 +0,0 @@
1
- import { describe, beforeEach, it } from 'vitest';
2
- import { runUserProfileStoreConformance } from '@selvajs/platform/testing';
3
- import type { AuthUser } from '@selvajs/platform';
4
- import { SupabaseUserProfileProvider } from '../SupabaseUserProfileProvider.js';
5
- import { readEnv, resetAllData } from '../../data/__tests__/test-helpers.js';
6
-
7
- const envCtx = readEnv();
8
-
9
- if (!envCtx) {
10
- describe.skip('SupabaseUserProfileProvider (skipped: no live stack)', () => {
11
- it('populate packages/providers/supabase/.env.test with Supabase creds to run these tests', () => {});
12
- });
13
- } else {
14
- describe('SupabaseUserProfileProvider', () => {
15
- beforeEach(async () => {
16
- await resetAllData(envCtx);
17
- });
18
-
19
- runUserProfileStoreConformance({
20
- name: 'SupabaseUserProfileProvider',
21
- createStore: async () => {
22
- const store = new SupabaseUserProfileProvider(envCtx.bundle);
23
- const seedUser = async (email: string): Promise<AuthUser> => {
24
- const { data, error } = await envCtx.adminClient.auth.admin.createUser({
25
- email,
26
- password: 'conformance-test-password-1234',
27
- email_confirm: true
28
- });
29
- if (error) throw error;
30
- return {
31
- id: data.user.id,
32
- email: data.user.email
33
- };
34
- };
35
- return { store, seedUser };
36
- }
37
- });
38
- });
39
- }
@@ -1 +0,0 @@
1
- export { SupabaseUserProfileProvider } from './SupabaseUserProfileProvider.js';