@sprinterai/supabase 0.2.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 (170) hide show
  1. package/LICENSE +21 -0
  2. package/dist/__test-utils__/mock-supabase.d.ts +18 -0
  3. package/dist/__test-utils__/mock-supabase.d.ts.map +1 -0
  4. package/dist/__test-utils__/mock-supabase.js +89 -0
  5. package/dist/__test-utils__/mock-supabase.js.map +1 -0
  6. package/dist/auth/adapter.d.ts +41 -0
  7. package/dist/auth/adapter.d.ts.map +1 -0
  8. package/dist/auth/adapter.js +73 -0
  9. package/dist/auth/adapter.js.map +1 -0
  10. package/dist/auth/claims.d.ts +31 -0
  11. package/dist/auth/claims.d.ts.map +1 -0
  12. package/dist/auth/claims.js +31 -0
  13. package/dist/auth/claims.js.map +1 -0
  14. package/dist/auth/claims.test.d.ts +2 -0
  15. package/dist/auth/claims.test.d.ts.map +1 -0
  16. package/dist/auth/claims.test.js +32 -0
  17. package/dist/auth/claims.test.js.map +1 -0
  18. package/dist/auth/index.d.ts +5 -0
  19. package/dist/auth/index.d.ts.map +1 -0
  20. package/dist/auth/index.js +4 -0
  21. package/dist/auth/index.js.map +1 -0
  22. package/dist/auth/permissions.d.ts +14 -0
  23. package/dist/auth/permissions.d.ts.map +1 -0
  24. package/dist/auth/permissions.js +25 -0
  25. package/dist/auth/permissions.js.map +1 -0
  26. package/dist/auth/permissions.test.d.ts +2 -0
  27. package/dist/auth/permissions.test.d.ts.map +1 -0
  28. package/dist/auth/permissions.test.js +40 -0
  29. package/dist/auth/permissions.test.js.map +1 -0
  30. package/dist/clients/admin.d.ts +9 -0
  31. package/dist/clients/admin.d.ts.map +1 -0
  32. package/dist/clients/admin.js +14 -0
  33. package/dist/clients/admin.js.map +1 -0
  34. package/dist/clients/admin.test.d.ts +2 -0
  35. package/dist/clients/admin.test.d.ts.map +1 -0
  36. package/dist/clients/admin.test.js +31 -0
  37. package/dist/clients/admin.test.js.map +1 -0
  38. package/dist/clients/browser.d.ts +9 -0
  39. package/dist/clients/browser.d.ts.map +1 -0
  40. package/dist/clients/browser.js +14 -0
  41. package/dist/clients/browser.js.map +1 -0
  42. package/dist/clients/browser.test.d.ts +2 -0
  43. package/dist/clients/browser.test.d.ts.map +1 -0
  44. package/dist/clients/browser.test.js +29 -0
  45. package/dist/clients/browser.test.js.map +1 -0
  46. package/dist/clients/index.d.ts +4 -0
  47. package/dist/clients/index.d.ts.map +1 -0
  48. package/dist/clients/index.js +4 -0
  49. package/dist/clients/index.js.map +1 -0
  50. package/dist/clients/server.d.ts +22 -0
  51. package/dist/clients/server.d.ts.map +1 -0
  52. package/dist/clients/server.js +25 -0
  53. package/dist/clients/server.js.map +1 -0
  54. package/dist/clients/server.test.d.ts +2 -0
  55. package/dist/clients/server.test.d.ts.map +1 -0
  56. package/dist/clients/server.test.js +26 -0
  57. package/dist/clients/server.test.js.map +1 -0
  58. package/dist/index.d.ts +11 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +11 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/realtime/channel.d.ts +24 -0
  63. package/dist/realtime/channel.d.ts.map +1 -0
  64. package/dist/realtime/channel.js +20 -0
  65. package/dist/realtime/channel.js.map +1 -0
  66. package/dist/realtime/index.d.ts +3 -0
  67. package/dist/realtime/index.d.ts.map +1 -0
  68. package/dist/realtime/index.js +2 -0
  69. package/dist/realtime/index.js.map +1 -0
  70. package/dist/stores/agent-store.d.ts +14 -0
  71. package/dist/stores/agent-store.d.ts.map +1 -0
  72. package/dist/stores/agent-store.js +47 -0
  73. package/dist/stores/agent-store.js.map +1 -0
  74. package/dist/stores/agent-store.test.d.ts +2 -0
  75. package/dist/stores/agent-store.test.d.ts.map +1 -0
  76. package/dist/stores/agent-store.test.js +64 -0
  77. package/dist/stores/agent-store.test.js.map +1 -0
  78. package/dist/stores/chat-store.d.ts +25 -0
  79. package/dist/stores/chat-store.d.ts.map +1 -0
  80. package/dist/stores/chat-store.js +148 -0
  81. package/dist/stores/chat-store.js.map +1 -0
  82. package/dist/stores/chat-store.test.d.ts +2 -0
  83. package/dist/stores/chat-store.test.d.ts.map +1 -0
  84. package/dist/stores/chat-store.test.js +83 -0
  85. package/dist/stores/chat-store.test.js.map +1 -0
  86. package/dist/stores/entity-store.d.ts +21 -0
  87. package/dist/stores/entity-store.d.ts.map +1 -0
  88. package/dist/stores/entity-store.js +169 -0
  89. package/dist/stores/entity-store.js.map +1 -0
  90. package/dist/stores/entity-store.test.d.ts +2 -0
  91. package/dist/stores/entity-store.test.d.ts.map +1 -0
  92. package/dist/stores/entity-store.test.js +125 -0
  93. package/dist/stores/entity-store.test.js.map +1 -0
  94. package/dist/stores/factory.d.ts +19 -0
  95. package/dist/stores/factory.d.ts.map +1 -0
  96. package/dist/stores/factory.js +25 -0
  97. package/dist/stores/factory.js.map +1 -0
  98. package/dist/stores/factory.test.d.ts +2 -0
  99. package/dist/stores/factory.test.d.ts.map +1 -0
  100. package/dist/stores/factory.test.js +41 -0
  101. package/dist/stores/factory.test.js.map +1 -0
  102. package/dist/stores/index.d.ts +11 -0
  103. package/dist/stores/index.d.ts.map +1 -0
  104. package/dist/stores/index.js +10 -0
  105. package/dist/stores/index.js.map +1 -0
  106. package/dist/stores/memory-store.d.ts +22 -0
  107. package/dist/stores/memory-store.d.ts.map +1 -0
  108. package/dist/stores/memory-store.js +59 -0
  109. package/dist/stores/memory-store.js.map +1 -0
  110. package/dist/stores/memory-store.test.d.ts +2 -0
  111. package/dist/stores/memory-store.test.d.ts.map +1 -0
  112. package/dist/stores/memory-store.test.js +70 -0
  113. package/dist/stores/memory-store.test.js.map +1 -0
  114. package/dist/stores/task-store.d.ts +17 -0
  115. package/dist/stores/task-store.d.ts.map +1 -0
  116. package/dist/stores/task-store.js +69 -0
  117. package/dist/stores/task-store.js.map +1 -0
  118. package/dist/stores/task-store.test.d.ts +2 -0
  119. package/dist/stores/task-store.test.d.ts.map +1 -0
  120. package/dist/stores/task-store.test.js +86 -0
  121. package/dist/stores/task-store.test.js.map +1 -0
  122. package/dist/stores/tenant-store.d.ts +11 -0
  123. package/dist/stores/tenant-store.d.ts.map +1 -0
  124. package/dist/stores/tenant-store.js +23 -0
  125. package/dist/stores/tenant-store.js.map +1 -0
  126. package/dist/stores/tool-store.d.ts +16 -0
  127. package/dist/stores/tool-store.d.ts.map +1 -0
  128. package/dist/stores/tool-store.js +50 -0
  129. package/dist/stores/tool-store.js.map +1 -0
  130. package/dist/stores/tool-store.test.d.ts +2 -0
  131. package/dist/stores/tool-store.test.d.ts.map +1 -0
  132. package/dist/stores/tool-store.test.js +56 -0
  133. package/dist/stores/tool-store.test.js.map +1 -0
  134. package/dist/stores/view-store.d.ts +14 -0
  135. package/dist/stores/view-store.d.ts.map +1 -0
  136. package/dist/stores/view-store.js +51 -0
  137. package/dist/stores/view-store.js.map +1 -0
  138. package/dist/stores/view-store.test.d.ts +2 -0
  139. package/dist/stores/view-store.test.d.ts.map +1 -0
  140. package/dist/stores/view-store.test.js +57 -0
  141. package/dist/stores/view-store.test.js.map +1 -0
  142. package/dist/tenant/actions.d.ts +44 -0
  143. package/dist/tenant/actions.d.ts.map +1 -0
  144. package/dist/tenant/actions.js +137 -0
  145. package/dist/tenant/actions.js.map +1 -0
  146. package/dist/tenant/constants.d.ts +9 -0
  147. package/dist/tenant/constants.d.ts.map +1 -0
  148. package/dist/tenant/constants.js +13 -0
  149. package/dist/tenant/constants.js.map +1 -0
  150. package/dist/tenant/constants.test.d.ts +2 -0
  151. package/dist/tenant/constants.test.d.ts.map +1 -0
  152. package/dist/tenant/constants.test.js +25 -0
  153. package/dist/tenant/constants.test.js.map +1 -0
  154. package/dist/tenant/context.d.ts +20 -0
  155. package/dist/tenant/context.d.ts.map +1 -0
  156. package/dist/tenant/context.js +99 -0
  157. package/dist/tenant/context.js.map +1 -0
  158. package/dist/tenant/index.d.ts +6 -0
  159. package/dist/tenant/index.d.ts.map +1 -0
  160. package/dist/tenant/index.js +5 -0
  161. package/dist/tenant/index.js.map +1 -0
  162. package/dist/tenant/roles.d.ts +7 -0
  163. package/dist/tenant/roles.d.ts.map +1 -0
  164. package/dist/tenant/roles.js +6 -0
  165. package/dist/tenant/roles.js.map +1 -0
  166. package/dist/types/index.d.ts +8 -0
  167. package/dist/types/index.d.ts.map +1 -0
  168. package/dist/types/index.js +6 -0
  169. package/dist/types/index.js.map +1 -0
  170. package/package.json +72 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sprinter AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,18 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ type MockQueryResult = {
3
+ data: unknown;
4
+ error: null | {
5
+ message: string;
6
+ code?: string;
7
+ };
8
+ };
9
+ /**
10
+ * Create a mock Supabase client for testing.
11
+ * Call `mockTable(name, result)` to configure per-table responses.
12
+ */
13
+ export declare function createMockClient(): SupabaseClient & {
14
+ mockTable: (name: string, result: MockQueryResult) => void;
15
+ mockAuth: (claims: Record<string, unknown> | null) => void;
16
+ };
17
+ export {};
18
+ //# sourceMappingURL=mock-supabase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-supabase.d.ts","sourceRoot":"","sources":["../../src/__test-utils__/mock-supabase.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,IAAI,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAClD,CAAC;AAuDF;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,GAAG;IACnD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAC3D,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;CAC5D,CA+CA"}
@@ -0,0 +1,89 @@
1
+ import { vi } from "vitest";
2
+ /**
3
+ * Creates a chainable mock Supabase query builder.
4
+ * Each method returns the builder, and the final await resolves the configured result.
5
+ */
6
+ function createMockQueryBuilder(result) {
7
+ const builder = {};
8
+ const methods = [
9
+ "select",
10
+ "insert",
11
+ "update",
12
+ "upsert",
13
+ "delete",
14
+ "eq",
15
+ "neq",
16
+ "gt",
17
+ "gte",
18
+ "lt",
19
+ "lte",
20
+ "like",
21
+ "ilike",
22
+ "in",
23
+ "contains",
24
+ "order",
25
+ "limit",
26
+ "single",
27
+ "maybeSingle",
28
+ "range",
29
+ "match",
30
+ "filter",
31
+ "not",
32
+ "or",
33
+ ];
34
+ for (const method of methods) {
35
+ builder[method] = vi.fn().mockReturnValue(builder);
36
+ }
37
+ // Override terminal methods to return the result
38
+ builder.single.mockResolvedValue(result);
39
+ builder.maybeSingle.mockResolvedValue(result);
40
+ // Make the builder itself thenable (for when you just await the chain)
41
+ builder.then = (resolve, reject) => {
42
+ return Promise.resolve(result).then(resolve, reject);
43
+ };
44
+ return builder;
45
+ }
46
+ /**
47
+ * Create a mock Supabase client for testing.
48
+ * Call `mockTable(name, result)` to configure per-table responses.
49
+ */
50
+ export function createMockClient() {
51
+ const tableResults = new Map();
52
+ let authClaims = null;
53
+ const client = {
54
+ from: vi.fn((table) => {
55
+ const result = tableResults.get(table) ?? {
56
+ data: null,
57
+ error: null,
58
+ };
59
+ return createMockQueryBuilder(result);
60
+ }),
61
+ auth: {
62
+ getClaims: vi.fn(() => Promise.resolve({
63
+ data: authClaims ? { claims: authClaims } : null,
64
+ error: null,
65
+ })),
66
+ getUser: vi.fn(() => Promise.resolve({
67
+ data: {
68
+ user: authClaims
69
+ ? { id: authClaims.sub, email: authClaims.email }
70
+ : null,
71
+ },
72
+ error: null,
73
+ })),
74
+ },
75
+ channel: vi.fn(() => ({
76
+ on: vi.fn().mockReturnThis(),
77
+ subscribe: vi.fn(),
78
+ unsubscribe: vi.fn(),
79
+ })),
80
+ mockTable(name, result) {
81
+ tableResults.set(name, result);
82
+ },
83
+ mockAuth(claims) {
84
+ authClaims = claims;
85
+ },
86
+ };
87
+ return client;
88
+ }
89
+ //# sourceMappingURL=mock-supabase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-supabase.js","sourceRoot":"","sources":["../../src/__test-utils__/mock-supabase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Auth adapter — centralized auth functions for the Sprinter platform.
3
+ *
4
+ * Architecture:
5
+ * - getClaims() for auth validation (local JWT, zero DB calls)
6
+ * - getUser() ONLY for login/provisioning (hits auth server)
7
+ * - getSession() NEVER for authorization (not server-verified)
8
+ *
9
+ * All functions take a SupabaseClient parameter — the caller (Next.js, etc.)
10
+ * is responsible for creating the client with proper cookie handling.
11
+ */
12
+ import type { TenantContext, AppPermission } from '@sprinterai/core';
13
+ import type { SupabaseClient } from '@supabase/supabase-js';
14
+ /**
15
+ * Require an authenticated user. Returns full tenant context.
16
+ * Throws 401 if not authenticated.
17
+ */
18
+ export declare function requireAuth(client: SupabaseClient, options?: {
19
+ tenantSlugOverride?: string;
20
+ }): Promise<TenantContext>;
21
+ /**
22
+ * Require an admin user (owner or admin role). Returns tenant context.
23
+ * Throws 401 if not authenticated, 403 if not admin.
24
+ */
25
+ export declare function requireAdmin(client: SupabaseClient, options?: {
26
+ tenantSlugOverride?: string;
27
+ }): Promise<TenantContext>;
28
+ /**
29
+ * Check if a user has a specific permission in their active tenant.
30
+ */
31
+ export declare function hasPermission(client: SupabaseClient, permission: AppPermission, options?: {
32
+ tenantSlugOverride?: string;
33
+ }): Promise<boolean>;
34
+ /**
35
+ * Require a specific permission. Returns tenant context if authorized.
36
+ * Throws 401 if not authenticated, 403 if missing the required permission.
37
+ */
38
+ export declare function requirePermission(client: SupabaseClient, permission: AppPermission, options?: {
39
+ tenantSlugOverride?: string;
40
+ }): Promise<TenantContext>;
41
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/auth/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAErE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAqB5D;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,OAAO,CAAC,aAAa,CAAC,CAMxB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,OAAO,CAAC,aAAa,CAAC,CAMxB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,aAAa,EACzB,OAAO,CAAC,EAAE;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,aAAa,EACzB,OAAO,CAAC,EAAE;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,OAAO,CAAC,aAAa,CAAC,CAOxB"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Auth adapter — centralized auth functions for the Sprinter platform.
3
+ *
4
+ * Architecture:
5
+ * - getClaims() for auth validation (local JWT, zero DB calls)
6
+ * - getUser() ONLY for login/provisioning (hits auth server)
7
+ * - getSession() NEVER for authorization (not server-verified)
8
+ *
9
+ * All functions take a SupabaseClient parameter — the caller (Next.js, etc.)
10
+ * is responsible for creating the client with proper cookie handling.
11
+ */
12
+ import { isAdminRole } from '@sprinterai/core';
13
+ import { getTenantContext } from '../tenant/context';
14
+ import { getUserId } from './claims';
15
+ import { getUserPermissions } from './permissions';
16
+ function createAuthenticationError(message) {
17
+ const error = new Error(message);
18
+ error.name = 'AuthenticationError';
19
+ error.status = 401;
20
+ return error;
21
+ }
22
+ function createAuthorizationError(message) {
23
+ const error = new Error(message);
24
+ error.name = 'AuthorizationError';
25
+ error.status = 403;
26
+ return error;
27
+ }
28
+ /**
29
+ * Require an authenticated user. Returns full tenant context.
30
+ * Throws 401 if not authenticated.
31
+ */
32
+ export async function requireAuth(client, options) {
33
+ const ctx = await getTenantContext(client, options);
34
+ if (!ctx.userId) {
35
+ throw createAuthenticationError('Not authenticated');
36
+ }
37
+ return ctx;
38
+ }
39
+ /**
40
+ * Require an admin user (owner or admin role). Returns tenant context.
41
+ * Throws 401 if not authenticated, 403 if not admin.
42
+ */
43
+ export async function requireAdmin(client, options) {
44
+ const ctx = await requireAuth(client, options);
45
+ if (!isAdminRole(ctx.role)) {
46
+ throw createAuthorizationError('Insufficient permissions: admin role required');
47
+ }
48
+ return ctx;
49
+ }
50
+ /**
51
+ * Check if a user has a specific permission in their active tenant.
52
+ */
53
+ export async function hasPermission(client, permission, options) {
54
+ const uid = await getUserId(client);
55
+ if (!uid)
56
+ return false;
57
+ const ctx = await getTenantContext(client, options);
58
+ const permissions = await getUserPermissions(client, ctx.userId, ctx.tenantId);
59
+ return permissions.includes(permission);
60
+ }
61
+ /**
62
+ * Require a specific permission. Returns tenant context if authorized.
63
+ * Throws 401 if not authenticated, 403 if missing the required permission.
64
+ */
65
+ export async function requirePermission(client, permission, options) {
66
+ const ctx = await requireAuth(client, options);
67
+ const permissions = await getUserPermissions(client, ctx.userId, ctx.tenantId);
68
+ if (!permissions.includes(permission)) {
69
+ throw createAuthorizationError(`Insufficient permissions: ${permission} required`);
70
+ }
71
+ return ctx;
72
+ }
73
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/auth/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,SAAS,yBAAyB,CAAC,OAAe;IAChD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,CAA4B,CAAC;IAC5D,KAAK,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACnC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC;IACnB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,wBAAwB,CAAC,OAAe;IAC/C,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,CAA4B,CAAC;IAC5D,KAAK,CAAC,IAAI,GAAG,oBAAoB,CAAC;IAClC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC;IACnB,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAsB,EACtB,OAAyC;IAEzC,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,yBAAyB,CAAC,mBAAmB,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAsB,EACtB,OAAyC;IAEzC,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,MAAM,wBAAwB,CAAC,+CAA+C,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAsB,EACtB,UAAyB,EACzB,OAAyC;IAEzC,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IAEvB,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/E,OAAO,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAsB,EACtB,UAAyB,EACzB,OAAyC;IAEzC,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/E,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACtC,MAAM,wBAAwB,CAAC,6BAA6B,UAAU,WAAW,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { SupabaseClient } from '@supabase/supabase-js';
2
+ /** JWT claims extracted from the Supabase session. */
3
+ export interface JwtClaims {
4
+ sub: string;
5
+ email?: string;
6
+ role?: string;
7
+ [key: string]: unknown;
8
+ }
9
+ /**
10
+ * Get JWT claims from the current Supabase session. Zero network calls —
11
+ * validates the JWT signature locally using cached JWKS keys.
12
+ * Returns null if no valid session exists.
13
+ *
14
+ * If the token is expired, the Supabase client refreshes it automatically
15
+ * (one network call), then validates the new token locally.
16
+ *
17
+ * Prefer this over `supabase.auth.getUser()` for auth checks. Only use
18
+ * `getUser()` for critical operations (login, provisioning) that need
19
+ * server-verified identity.
20
+ */
21
+ export declare function getClaims(client: SupabaseClient): Promise<JwtClaims | null>;
22
+ /**
23
+ * Get user ID from JWT claims. Zero network calls — validates JWT signature locally.
24
+ * Returns null if no valid session exists.
25
+ *
26
+ * Prefer this over `supabase.auth.getUser()` for auth checks. Only use
27
+ * `getUser()` for critical operations (login, provisioning) that need
28
+ * server-verified identity.
29
+ */
30
+ export declare function getUserId(client: SupabaseClient): Promise<string | null>;
31
+ //# sourceMappingURL=claims.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claims.d.ts","sourceRoot":"","sources":["../../src/auth/claims.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,sDAAsD;AACtD,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAIjF;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAG9E"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Get JWT claims from the current Supabase session. Zero network calls —
3
+ * validates the JWT signature locally using cached JWKS keys.
4
+ * Returns null if no valid session exists.
5
+ *
6
+ * If the token is expired, the Supabase client refreshes it automatically
7
+ * (one network call), then validates the new token locally.
8
+ *
9
+ * Prefer this over `supabase.auth.getUser()` for auth checks. Only use
10
+ * `getUser()` for critical operations (login, provisioning) that need
11
+ * server-verified identity.
12
+ */
13
+ export async function getClaims(client) {
14
+ const { data } = await client.auth.getClaims();
15
+ if (!data?.claims)
16
+ return null;
17
+ return data.claims;
18
+ }
19
+ /**
20
+ * Get user ID from JWT claims. Zero network calls — validates JWT signature locally.
21
+ * Returns null if no valid session exists.
22
+ *
23
+ * Prefer this over `supabase.auth.getUser()` for auth checks. Only use
24
+ * `getUser()` for critical operations (login, provisioning) that need
25
+ * server-verified identity.
26
+ */
27
+ export async function getUserId(client) {
28
+ const claims = await getClaims(client);
29
+ return claims?.sub ?? null;
30
+ }
31
+ //# sourceMappingURL=claims.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claims.js","sourceRoot":"","sources":["../../src/auth/claims.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAAsB;IACpD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;IAC/C,IAAI,CAAC,IAAI,EAAE,MAAM;QAAE,OAAO,IAAI,CAAC;IAC/B,OAAO,IAAI,CAAC,MAAmB,CAAC;AAClC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAAsB;IACpD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=claims.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claims.test.d.ts","sourceRoot":"","sources":["../../src/auth/claims.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,32 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { getClaims, getUserId } from "./claims";
3
+ import { createMockClient } from "../__test-utils__/mock-supabase";
4
+ describe("getClaims", () => {
5
+ it("returns claims from a valid session", async () => {
6
+ const client = createMockClient();
7
+ client.mockAuth({ sub: "user-123", email: "test@example.com" });
8
+ const claims = await getClaims(client);
9
+ expect(claims).toEqual({ sub: "user-123", email: "test@example.com" });
10
+ });
11
+ it("returns null when no session exists", async () => {
12
+ const client = createMockClient();
13
+ client.mockAuth(null);
14
+ const claims = await getClaims(client);
15
+ expect(claims).toBeNull();
16
+ });
17
+ });
18
+ describe("getUserId", () => {
19
+ it("returns user ID from claims", async () => {
20
+ const client = createMockClient();
21
+ client.mockAuth({ sub: "user-456" });
22
+ const id = await getUserId(client);
23
+ expect(id).toBe("user-456");
24
+ });
25
+ it("returns null when not authenticated", async () => {
26
+ const client = createMockClient();
27
+ client.mockAuth(null);
28
+ const id = await getUserId(client);
29
+ expect(id).toBeNull();
30
+ });
31
+ });
32
+ //# sourceMappingURL=claims.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claims.test.js","sourceRoot":"","sources":["../../src/auth/claims.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAClC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAEhE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAClC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEtB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAClC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAErC,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAClC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEtB,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { getClaims, getUserId } from "./claims";
2
+ export type { JwtClaims } from "./claims";
3
+ export { getUserPermissions, getPermissionsForRole } from "./permissions";
4
+ export { requireAuth, requireAdmin, hasPermission, requirePermission, } from "./adapter";
5
+ //# 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,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAChD,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EACL,WAAW,EACX,YAAY,EACZ,aAAa,EACb,iBAAiB,GAClB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { getClaims, getUserId } from "./claims";
2
+ export { getUserPermissions, getPermissionsForRole } from "./permissions";
3
+ export { requireAuth, requireAdmin, hasPermission, requirePermission, } from "./adapter";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEhD,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EACL,WAAW,EACX,YAAY,EACZ,aAAa,EACb,iBAAiB,GAClB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { AppPermission } from '@sprinterai/core';
2
+ import type { SupabaseClient } from '@supabase/supabase-js';
3
+ /**
4
+ * Get all permissions for a user in a specific tenant.
5
+ * Queries the denormalized user_permissions table.
6
+ */
7
+ export declare function getUserPermissions(client: SupabaseClient, userId: string, tenantId: string): Promise<AppPermission[]>;
8
+ /**
9
+ * Get permissions granted to a specific role.
10
+ * Used for agent autonomous execution — agents get their role's permissions.
11
+ * Requires admin client to bypass RLS.
12
+ */
13
+ export declare function getPermissionsForRole(adminClient: SupabaseClient, roleId: string): Promise<AppPermission[]>;
14
+ //# sourceMappingURL=permissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/auth/permissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,EAAE,CAAC,CAQ1B;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,cAAc,EAC3B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,EAAE,CAAC,CAO1B"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Get all permissions for a user in a specific tenant.
3
+ * Queries the denormalized user_permissions table.
4
+ */
5
+ export async function getUserPermissions(client, userId, tenantId) {
6
+ const { data } = await client
7
+ .from('user_permissions')
8
+ .select('permission')
9
+ .eq('user_id', userId)
10
+ .eq('tenant_id', tenantId);
11
+ return (data ?? []).map((row) => row.permission);
12
+ }
13
+ /**
14
+ * Get permissions granted to a specific role.
15
+ * Used for agent autonomous execution — agents get their role's permissions.
16
+ * Requires admin client to bypass RLS.
17
+ */
18
+ export async function getPermissionsForRole(adminClient, roleId) {
19
+ const { data } = await adminClient
20
+ .from('role_permissions')
21
+ .select('permission')
22
+ .eq('role_id', roleId);
23
+ return (data ?? []).map((row) => row.permission);
24
+ }
25
+ //# sourceMappingURL=permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/auth/permissions.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAsB,EACtB,MAAc,EACd,QAAgB;IAEhB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM;SAC1B,IAAI,CAAC,kBAAkB,CAAC;SACxB,MAAM,CAAC,YAAY,CAAC;SACpB,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC;SACrB,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAE7B,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAA2B,EAAE,EAAE,CAAC,GAAG,CAAC,UAA2B,CAAC,CAAC;AAC5F,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,WAA2B,EAC3B,MAAc;IAEd,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,WAAW;SAC/B,IAAI,CAAC,kBAAkB,CAAC;SACxB,MAAM,CAAC,YAAY,CAAC;SACpB,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAEzB,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAA2B,EAAE,EAAE,CAAC,GAAG,CAAC,UAA2B,CAAC,CAAC;AAC5F,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=permissions.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.test.d.ts","sourceRoot":"","sources":["../../src/auth/permissions.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,40 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { getUserPermissions, getPermissionsForRole } from "./permissions";
3
+ import { createMockClient } from "../__test-utils__/mock-supabase";
4
+ describe("getUserPermissions", () => {
5
+ it("returns permissions for a user in a tenant", async () => {
6
+ const client = createMockClient();
7
+ client.mockTable("user_permissions", {
8
+ data: [
9
+ { permission: "entities.own.create" },
10
+ { permission: "entities.own.read" },
11
+ ],
12
+ error: null,
13
+ });
14
+ const perms = await getUserPermissions(client, "user-1", "tenant-1");
15
+ expect(perms).toEqual(["entities.own.create", "entities.own.read"]);
16
+ });
17
+ it("returns empty array when no permissions found", async () => {
18
+ const client = createMockClient();
19
+ client.mockTable("user_permissions", { data: null, error: null });
20
+ const perms = await getUserPermissions(client, "user-1", "tenant-1");
21
+ expect(perms).toEqual([]);
22
+ });
23
+ });
24
+ describe("getPermissionsForRole", () => {
25
+ it("returns permissions for a role", async () => {
26
+ const client = createMockClient();
27
+ client.mockTable("role_permissions", {
28
+ data: [
29
+ { permission: "entities.all.create" },
30
+ { permission: "entities.all.read" },
31
+ { permission: "entities.all.update" },
32
+ ],
33
+ error: null,
34
+ });
35
+ const perms = await getPermissionsForRole(client, "role-admin");
36
+ expect(perms).toHaveLength(3);
37
+ expect(perms).toContain("entities.all.create");
38
+ });
39
+ });
40
+ //# sourceMappingURL=permissions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.test.js","sourceRoot":"","sources":["../../src/auth/permissions.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAClC,MAAM,CAAC,SAAS,CAAC,kBAAkB,EAAE;YACnC,IAAI,EAAE;gBACJ,EAAE,UAAU,EAAE,qBAAqB,EAAE;gBACrC,EAAE,UAAU,EAAE,mBAAmB,EAAE;aACpC;YACD,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;QACrE,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,qBAAqB,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAClC,MAAM,CAAC,SAAS,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAElE,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;QACrE,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAClC,MAAM,CAAC,SAAS,CAAC,kBAAkB,EAAE;YACnC,IAAI,EAAE;gBACJ,EAAE,UAAU,EAAE,qBAAqB,EAAE;gBACrC,EAAE,UAAU,EAAE,mBAAmB,EAAE;gBACnC,EAAE,UAAU,EAAE,qBAAqB,EAAE;aACtC;YACD,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAChE,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Create a Supabase admin client using the service role key.
3
+ * Bypasses RLS — use only for system operations.
4
+ */
5
+ export declare function createAdminClient(options?: {
6
+ supabaseUrl?: string;
7
+ supabaseServiceRoleKey?: string;
8
+ }): import("@supabase/supabase-js").SupabaseClient<any, "public", "public", any, any>;
9
+ //# sourceMappingURL=admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/clients/admin.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,qFAUA"}
@@ -0,0 +1,14 @@
1
+ import { createClient } from "@supabase/supabase-js";
2
+ /**
3
+ * Create a Supabase admin client using the service role key.
4
+ * Bypasses RLS — use only for system operations.
5
+ */
6
+ export function createAdminClient(options) {
7
+ const url = options?.supabaseUrl ?? process.env.NEXT_PUBLIC_SUPABASE_URL ?? "";
8
+ const key = options?.supabaseServiceRoleKey ??
9
+ process.env.SUPABASE_SECRET_KEY ??
10
+ process.env.SUPABASE_SERVICE_ROLE_KEY ??
11
+ "";
12
+ return createClient(url, key);
13
+ }
14
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/clients/admin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAGjC;IACC,MAAM,GAAG,GACP,OAAO,EAAE,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,EAAE,CAAC;IACrE,MAAM,GAAG,GACP,OAAO,EAAE,sBAAsB;QAC/B,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAC/B,OAAO,CAAC,GAAG,CAAC,yBAAyB;QACrC,EAAE,CAAC;IAEL,OAAO,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=admin.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.test.d.ts","sourceRoot":"","sources":["../../src/clients/admin.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,31 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { createAdminClient } from "./admin";
3
+ vi.mock("@supabase/supabase-js", () => ({
4
+ createClient: vi.fn((url, key) => ({
5
+ url,
6
+ key,
7
+ mock: true,
8
+ })),
9
+ }));
10
+ describe("createAdminClient", () => {
11
+ it("creates an admin client with explicit options", () => {
12
+ const client = createAdminClient({
13
+ supabaseUrl: "https://test.supabase.co",
14
+ supabaseServiceRoleKey: "service-role-key",
15
+ });
16
+ expect(client).toBeDefined();
17
+ expect(client.url).toBe("https://test.supabase.co");
18
+ expect(client.key).toBe("service-role-key");
19
+ });
20
+ it("falls back to env vars when no options provided", () => {
21
+ process.env.NEXT_PUBLIC_SUPABASE_URL = "https://env.supabase.co";
22
+ process.env.SUPABASE_SECRET_KEY = "env-secret";
23
+ const client = createAdminClient();
24
+ expect(client).toBeDefined();
25
+ expect(client.url).toBe("https://env.supabase.co");
26
+ expect(client.key).toBe("env-secret");
27
+ delete process.env.NEXT_PUBLIC_SUPABASE_URL;
28
+ delete process.env.SUPABASE_SECRET_KEY;
29
+ });
30
+ });
31
+ //# sourceMappingURL=admin.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.test.js","sourceRoot":"","sources":["../../src/clients/admin.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5C,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,CAAC;IACtC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,GAAW,EAAE,GAAW,EAAE,EAAE,CAAC,CAAC;QACjD,GAAG;QACH,GAAG;QACH,IAAI,EAAE,IAAI;KACX,CAAC,CAAC;CACJ,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,MAAM,GAAG,iBAAiB,CAAC;YAC/B,WAAW,EAAE,0BAA0B;YACvC,sBAAsB,EAAE,kBAAkB;SAC3C,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAC7B,MAAM,CAAE,MAAkC,CAAC,GAAG,CAAC,CAAC,IAAI,CAClD,0BAA0B,CAC3B,CAAC;QACF,MAAM,CAAE,MAAkC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,OAAO,CAAC,GAAG,CAAC,wBAAwB,GAAG,yBAAyB,CAAC;QACjE,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,YAAY,CAAC;QAE/C,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;QAEnC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAC7B,MAAM,CAAE,MAAkC,CAAC,GAAG,CAAC,CAAC,IAAI,CAClD,yBAAyB,CAC1B,CAAC;QACF,MAAM,CAAE,MAAkC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAEnE,OAAO,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;QAC5C,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Create a Supabase browser client for use in client components.
3
+ * Reads env vars or accepts explicit URL/key.
4
+ */
5
+ export declare function createBrowserClient(options?: {
6
+ supabaseUrl?: string;
7
+ supabaseAnonKey?: string;
8
+ }): import("@supabase/supabase-js").SupabaseClient<any, "public", "public", any, any>;
9
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/clients/browser.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,qFAUA"}
@@ -0,0 +1,14 @@
1
+ import { createBrowserClient as createSSRBrowserClient } from "@supabase/ssr";
2
+ /**
3
+ * Create a Supabase browser client for use in client components.
4
+ * Reads env vars or accepts explicit URL/key.
5
+ */
6
+ export function createBrowserClient(options) {
7
+ const url = options?.supabaseUrl ?? process.env.NEXT_PUBLIC_SUPABASE_URL ?? "";
8
+ const key = options?.supabaseAnonKey ??
9
+ process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY ??
10
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ??
11
+ "";
12
+ return createSSRBrowserClient(url, key);
13
+ }
14
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/clients/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,IAAI,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAE9E;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAGnC;IACC,MAAM,GAAG,GACP,OAAO,EAAE,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,EAAE,CAAC;IACrE,MAAM,GAAG,GACP,OAAO,EAAE,eAAe;QACxB,OAAO,CAAC,GAAG,CAAC,oCAAoC;QAChD,OAAO,CAAC,GAAG,CAAC,6BAA6B;QACzC,EAAE,CAAC;IAEL,OAAO,sBAAsB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=browser.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.test.d.ts","sourceRoot":"","sources":["../../src/clients/browser.test.ts"],"names":[],"mappings":""}