@supabase/server 0.1.0-alpha.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.
@@ -0,0 +1,16 @@
1
+ import { a as JWTClaims, c as UserClaims, i as Credentials, l as WithSupabaseConfig, n as AllowWithKey, o as SupabaseContext, r as AuthResult, s as SupabaseEnv, t as Allow } from "./types-DNh3Z1O1.cjs";
2
+ import { a as extractCredentials, c as EnvError, i as verifyCredentials, n as createContextClient, o as resolveEnv, r as verifyAuth, s as AuthError, t as createAdminClient } from "./create-admin-client-BZ_3qcxI.cjs";
3
+
4
+ //#region src/with-supabase.d.ts
5
+ declare function withSupabase(config: WithSupabaseConfig, handler: (req: Request, ctx: SupabaseContext) => Promise<Response>): (req: Request) => Promise<Response>;
6
+ //#endregion
7
+ //#region src/create-supabase-context.d.ts
8
+ declare function createSupabaseContext(request: Request, options?: WithSupabaseConfig): Promise<{
9
+ data: SupabaseContext;
10
+ error: null;
11
+ } | {
12
+ data: null;
13
+ error: AuthError;
14
+ }>;
15
+ //#endregion
16
+ export { type Allow, type AllowWithKey, AuthError, type AuthResult, type Credentials, EnvError, type JWTClaims, type SupabaseContext, type SupabaseEnv, type UserClaims, type WithSupabaseConfig, createAdminClient, createContextClient, createSupabaseContext, extractCredentials, resolveEnv, verifyAuth, verifyCredentials, withSupabase };
@@ -0,0 +1,16 @@
1
+ import { a as JWTClaims, c as UserClaims, i as Credentials, l as WithSupabaseConfig, n as AllowWithKey, o as SupabaseContext, r as AuthResult, s as SupabaseEnv, t as Allow } from "./types-BLM5-qA8.mjs";
2
+ import { a as extractCredentials, c as EnvError, i as verifyCredentials, n as createContextClient, o as resolveEnv, r as verifyAuth, s as AuthError, t as createAdminClient } from "./create-admin-client-CSX-Q_Fv.mjs";
3
+
4
+ //#region src/with-supabase.d.ts
5
+ declare function withSupabase(config: WithSupabaseConfig, handler: (req: Request, ctx: SupabaseContext) => Promise<Response>): (req: Request) => Promise<Response>;
6
+ //#endregion
7
+ //#region src/create-supabase-context.d.ts
8
+ declare function createSupabaseContext(request: Request, options?: WithSupabaseConfig): Promise<{
9
+ data: SupabaseContext;
10
+ error: null;
11
+ } | {
12
+ data: null;
13
+ error: AuthError;
14
+ }>;
15
+ //#endregion
16
+ export { type Allow, type AllowWithKey, AuthError, type AuthResult, type Credentials, EnvError, type JWTClaims, type SupabaseContext, type SupabaseEnv, type UserClaims, type WithSupabaseConfig, createAdminClient, createContextClient, createSupabaseContext, extractCredentials, resolveEnv, verifyAuth, verifyCredentials, withSupabase };
package/dist/index.mjs ADDED
@@ -0,0 +1,42 @@
1
+ import { a as createAdminClient, c as EnvError, i as createContextClient, n as verifyCredentials, o as resolveEnv, r as extractCredentials, s as AuthError, t as verifyAuth } from "./verify-auth-DxUT0XoT.mjs";
2
+ import { t as createSupabaseContext } from "./create-supabase-context-BrSIe29v.mjs";
3
+ import { corsHeaders } from "@supabase/supabase-js/cors";
4
+
5
+ //#region src/cors.ts
6
+ function buildCorsHeaders(config) {
7
+ if (config === false) return {};
8
+ if (typeof config === "object") return config;
9
+ return corsHeaders;
10
+ }
11
+ function addCorsHeaders(response, config) {
12
+ if (config === false) return response;
13
+ const corsHeaders = buildCorsHeaders(config);
14
+ const newResponse = new Response(response.body, response);
15
+ for (const [key, value] of Object.entries(corsHeaders)) newResponse.headers.set(key, value);
16
+ return newResponse;
17
+ }
18
+
19
+ //#endregion
20
+ //#region src/with-supabase.ts
21
+ function withSupabase(config, handler) {
22
+ return async (req) => {
23
+ if (config.cors !== false && req.method === "OPTIONS") return new Response(null, {
24
+ status: 204,
25
+ headers: buildCorsHeaders(config.cors)
26
+ });
27
+ const { data: ctx, error } = await createSupabaseContext(req, config);
28
+ if (error) return Response.json({
29
+ error: error.message,
30
+ code: error.code
31
+ }, {
32
+ status: error.status,
33
+ headers: config.cors !== false ? buildCorsHeaders(config.cors) : {}
34
+ });
35
+ const response = await handler(req, ctx);
36
+ if (config.cors !== false) return addCorsHeaders(response, config.cors);
37
+ return response;
38
+ };
39
+ }
40
+
41
+ //#endregion
42
+ export { AuthError, EnvError, createAdminClient, createContextClient, createSupabaseContext, extractCredentials, resolveEnv, verifyAuth, verifyCredentials, withSupabase };
@@ -0,0 +1,59 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+
3
+ //#region src/types.d.ts
4
+ type Allow = 'always' | 'public' | 'secret' | 'user';
5
+ type AllowWithKey = Allow | `public:${string}` | `secret:${string}`;
6
+ interface SupabaseEnv {
7
+ url: string;
8
+ publishableKeys: Record<string, string>;
9
+ secretKeys: Record<string, string>;
10
+ jwks: JsonWebKeySet | null;
11
+ }
12
+ interface JsonWebKeySet {
13
+ keys: JsonWebKey[];
14
+ }
15
+ interface Credentials {
16
+ token: string | null;
17
+ apikey: string | null;
18
+ }
19
+ interface AuthResult {
20
+ authType: Allow;
21
+ token: string | null;
22
+ userClaims: UserClaims | null;
23
+ claims: JWTClaims | null;
24
+ keyName?: string | null;
25
+ }
26
+ interface JWTClaims {
27
+ sub: string;
28
+ iss?: string;
29
+ aud?: string | string[];
30
+ exp?: number;
31
+ iat?: number;
32
+ role?: string;
33
+ email?: string;
34
+ app_metadata?: Record<string, unknown>;
35
+ user_metadata?: Record<string, unknown>;
36
+ [key: string]: unknown;
37
+ }
38
+ interface UserClaims {
39
+ id: string;
40
+ role?: string;
41
+ email?: string;
42
+ appMetadata?: Record<string, unknown>;
43
+ userMetadata?: Record<string, unknown>;
44
+ }
45
+ interface WithSupabaseConfig {
46
+ allow?: AllowWithKey | AllowWithKey[];
47
+ env?: Partial<SupabaseEnv>;
48
+ cors?: boolean | Record<string, string>;
49
+ }
50
+ interface SupabaseContext {
51
+ supabase: SupabaseClient;
52
+ supabaseAdmin: SupabaseClient;
53
+ /** JWT-derived identity. For the full Supabase User object, call `supabase.auth.getUser()`. */
54
+ userClaims: UserClaims | null;
55
+ claims: JWTClaims | null;
56
+ authType: Allow;
57
+ }
58
+ //#endregion
59
+ export { JWTClaims as a, UserClaims as c, Credentials as i, WithSupabaseConfig as l, AllowWithKey as n, SupabaseContext as o, AuthResult as r, SupabaseEnv as s, Allow as t };
@@ -0,0 +1,59 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+
3
+ //#region src/types.d.ts
4
+ type Allow = 'always' | 'public' | 'secret' | 'user';
5
+ type AllowWithKey = Allow | `public:${string}` | `secret:${string}`;
6
+ interface SupabaseEnv {
7
+ url: string;
8
+ publishableKeys: Record<string, string>;
9
+ secretKeys: Record<string, string>;
10
+ jwks: JsonWebKeySet | null;
11
+ }
12
+ interface JsonWebKeySet {
13
+ keys: JsonWebKey[];
14
+ }
15
+ interface Credentials {
16
+ token: string | null;
17
+ apikey: string | null;
18
+ }
19
+ interface AuthResult {
20
+ authType: Allow;
21
+ token: string | null;
22
+ userClaims: UserClaims | null;
23
+ claims: JWTClaims | null;
24
+ keyName?: string | null;
25
+ }
26
+ interface JWTClaims {
27
+ sub: string;
28
+ iss?: string;
29
+ aud?: string | string[];
30
+ exp?: number;
31
+ iat?: number;
32
+ role?: string;
33
+ email?: string;
34
+ app_metadata?: Record<string, unknown>;
35
+ user_metadata?: Record<string, unknown>;
36
+ [key: string]: unknown;
37
+ }
38
+ interface UserClaims {
39
+ id: string;
40
+ role?: string;
41
+ email?: string;
42
+ appMetadata?: Record<string, unknown>;
43
+ userMetadata?: Record<string, unknown>;
44
+ }
45
+ interface WithSupabaseConfig {
46
+ allow?: AllowWithKey | AllowWithKey[];
47
+ env?: Partial<SupabaseEnv>;
48
+ cors?: boolean | Record<string, string>;
49
+ }
50
+ interface SupabaseContext {
51
+ supabase: SupabaseClient;
52
+ supabaseAdmin: SupabaseClient;
53
+ /** JWT-derived identity. For the full Supabase User object, call `supabase.auth.getUser()`. */
54
+ userClaims: UserClaims | null;
55
+ claims: JWTClaims | null;
56
+ authType: Allow;
57
+ }
58
+ //#endregion
59
+ export { JWTClaims as a, UserClaims as c, Credentials as i, WithSupabaseConfig as l, AllowWithKey as n, SupabaseContext as o, AuthResult as r, SupabaseEnv as s, Allow as t };
@@ -0,0 +1,317 @@
1
+ let _supabase_supabase_js = require("@supabase/supabase-js");
2
+ let jose = require("jose");
3
+
4
+ //#region src/errors.ts
5
+ var EnvError = class extends Error {
6
+ constructor(message, code = "ENV_ERROR") {
7
+ super(message);
8
+ this.status = 500;
9
+ this.name = "EnvError";
10
+ this.code = code;
11
+ }
12
+ };
13
+ var AuthError = class extends Error {
14
+ constructor(message, code = "AUTH_ERROR", status = 401) {
15
+ super(message);
16
+ this.name = "AuthError";
17
+ this.code = code;
18
+ this.status = status;
19
+ }
20
+ };
21
+
22
+ //#endregion
23
+ //#region src/core/resolve-env.ts
24
+ function getEnvVar(name) {
25
+ if (typeof Deno !== "undefined" && Deno.env?.get) return Deno.env.get(name);
26
+ if (typeof process !== "undefined" && process.env) return process.env[name];
27
+ }
28
+ function parseKeys(raw) {
29
+ if (!raw) return {};
30
+ try {
31
+ const parsed = JSON.parse(raw);
32
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
33
+ return parsed;
34
+ } catch {
35
+ return {};
36
+ }
37
+ }
38
+ function resolveKeys(singularVar, pluralVar) {
39
+ const plural = getEnvVar(pluralVar);
40
+ if (plural) return parseKeys(plural);
41
+ const singular = getEnvVar(singularVar);
42
+ if (singular) return { default: singular };
43
+ return {};
44
+ }
45
+ function parseJwks(raw) {
46
+ if (!raw) return null;
47
+ try {
48
+ const parsed = JSON.parse(raw);
49
+ if (Array.isArray(parsed)) return { keys: parsed };
50
+ if (parsed?.keys && Array.isArray(parsed.keys)) return parsed;
51
+ return null;
52
+ } catch {
53
+ return null;
54
+ }
55
+ }
56
+ function resolveEnv(overrides) {
57
+ const url = overrides?.url ?? getEnvVar("SUPABASE_URL");
58
+ if (!url) return {
59
+ data: null,
60
+ error: new EnvError("SUPABASE_URL is required but not set", "MISSING_SUPABASE_URL")
61
+ };
62
+ return {
63
+ data: {
64
+ url,
65
+ publishableKeys: overrides?.publishableKeys ?? resolveKeys("SUPABASE_PUBLISHABLE_KEY", "SUPABASE_PUBLISHABLE_KEYS"),
66
+ secretKeys: overrides?.secretKeys ?? resolveKeys("SUPABASE_SECRET_KEY", "SUPABASE_SECRET_KEYS"),
67
+ jwks: overrides?.jwks ?? parseJwks(getEnvVar("SUPABASE_JWKS"))
68
+ },
69
+ error: null
70
+ };
71
+ }
72
+
73
+ //#endregion
74
+ //#region src/core/create-admin-client.ts
75
+ function createAdminClient(env, keyName) {
76
+ const { data: resolved, error } = resolveEnv(env);
77
+ if (error) throw error;
78
+ const name = keyName ?? "default";
79
+ const keys = resolved.secretKeys;
80
+ const secretKey = keys[name] ?? (keyName == null ? Object.values(keys)[0] : void 0);
81
+ if (!secretKey) throw new EnvError(name === "default" ? "No default secret key found. Set SUPABASE_SECRET_KEY or include a \"default\" entry in SUPABASE_SECRET_KEYS." : `No "${name}" secret key found. Include a "${name}" entry in SUPABASE_SECRET_KEYS.`, "MISSING_SECRET_KEY");
82
+ return (0, _supabase_supabase_js.createClient)(resolved.url, secretKey, { auth: {
83
+ persistSession: false,
84
+ autoRefreshToken: false,
85
+ detectSessionInUrl: false
86
+ } });
87
+ }
88
+
89
+ //#endregion
90
+ //#region src/core/create-context-client.ts
91
+ function createContextClient(token, env, keyName) {
92
+ const { data: resolved, error } = resolveEnv(env);
93
+ if (error) throw error;
94
+ const name = keyName ?? "default";
95
+ const keys = resolved.publishableKeys;
96
+ const anonKey = keys[name] ?? (keyName == null ? Object.values(keys)[0] : void 0);
97
+ if (!anonKey) throw new EnvError(name === "default" ? "No default publishable key found. Set SUPABASE_PUBLISHABLE_KEY or include a \"default\" entry in SUPABASE_PUBLISHABLE_KEYS." : `No "${name}" publishable key found. Include a "${name}" entry in SUPABASE_PUBLISHABLE_KEYS.`, "MISSING_PUBLISHABLE_KEY");
98
+ return (0, _supabase_supabase_js.createClient)(resolved.url, anonKey, {
99
+ global: { headers: token ? { Authorization: `Bearer ${token}` } : {} },
100
+ auth: {
101
+ persistSession: false,
102
+ autoRefreshToken: false,
103
+ detectSessionInUrl: false
104
+ }
105
+ });
106
+ }
107
+
108
+ //#endregion
109
+ //#region src/core/extract-credentials.ts
110
+ function extractCredentials(request) {
111
+ const authHeader = request.headers.get("authorization");
112
+ return {
113
+ token: authHeader?.startsWith("Bearer ") ? authHeader.slice(7) || null : null,
114
+ apikey: request.headers.get("apikey")
115
+ };
116
+ }
117
+
118
+ //#endregion
119
+ //#region src/core/utils/timing-safe-equal.ts
120
+ const encoder = new TextEncoder();
121
+ async function timingSafeEqual(a, b) {
122
+ const key = crypto.getRandomValues(new Uint8Array(32));
123
+ const cryptoKey = await crypto.subtle.importKey("raw", key, {
124
+ name: "HMAC",
125
+ hash: "SHA-256"
126
+ }, false, ["sign"]);
127
+ const [sigA, sigB] = await Promise.all([crypto.subtle.sign("HMAC", cryptoKey, encoder.encode(a)), crypto.subtle.sign("HMAC", cryptoKey, encoder.encode(b))]);
128
+ if (sigA.byteLength !== sigB.byteLength) return false;
129
+ const viewA = new Uint8Array(sigA);
130
+ const viewB = new Uint8Array(sigB);
131
+ let result = 0;
132
+ for (let i = 0; i < viewA.length; i++) result |= viewA[i] ^ viewB[i];
133
+ return result === 0;
134
+ }
135
+
136
+ //#endregion
137
+ //#region src/core/verify-credentials.ts
138
+ function parseAllowMode(mode) {
139
+ if (mode === "always" || mode === "public" || mode === "secret" || mode === "user") return {
140
+ base: mode,
141
+ keyName: null
142
+ };
143
+ const colonIndex = mode.indexOf(":");
144
+ const base = mode.slice(0, colonIndex);
145
+ const keyName = mode.slice(colonIndex + 1);
146
+ if (!keyName) return {
147
+ base,
148
+ keyName: null
149
+ };
150
+ return {
151
+ base,
152
+ keyName
153
+ };
154
+ }
155
+ function claimsToUserClaims(claims) {
156
+ return {
157
+ id: claims.sub,
158
+ role: claims.role,
159
+ email: claims.email,
160
+ appMetadata: claims.app_metadata,
161
+ userMetadata: claims.user_metadata
162
+ };
163
+ }
164
+ async function tryMode(mode, credentials, env) {
165
+ const { base, keyName } = parseAllowMode(mode);
166
+ switch (base) {
167
+ case "always": return {
168
+ authType: "always",
169
+ token: null,
170
+ userClaims: null,
171
+ claims: null,
172
+ keyName: null
173
+ };
174
+ case "public": {
175
+ if (!credentials.apikey) return null;
176
+ const keys = env.publishableKeys;
177
+ if (keyName === "*") {
178
+ for (const [name, value] of Object.entries(keys)) if (await timingSafeEqual(credentials.apikey, value)) return {
179
+ authType: "public",
180
+ token: null,
181
+ userClaims: null,
182
+ claims: null,
183
+ keyName: name
184
+ };
185
+ } else {
186
+ const name = keyName ?? "default";
187
+ const value = keys[name];
188
+ if (value && await timingSafeEqual(credentials.apikey, value)) return {
189
+ authType: "public",
190
+ token: null,
191
+ userClaims: null,
192
+ claims: null,
193
+ keyName: name
194
+ };
195
+ }
196
+ return null;
197
+ }
198
+ case "secret": {
199
+ if (!credentials.apikey) return null;
200
+ const keys = env.secretKeys;
201
+ if (keyName === "*") {
202
+ for (const [name, value] of Object.entries(keys)) if (await timingSafeEqual(credentials.apikey, value)) return {
203
+ authType: "secret",
204
+ token: null,
205
+ userClaims: null,
206
+ claims: null,
207
+ keyName: name
208
+ };
209
+ } else {
210
+ const name = keyName ?? "default";
211
+ const value = keys[name];
212
+ if (value && await timingSafeEqual(credentials.apikey, value)) return {
213
+ authType: "secret",
214
+ token: null,
215
+ userClaims: null,
216
+ claims: null,
217
+ keyName: name
218
+ };
219
+ }
220
+ return null;
221
+ }
222
+ case "user":
223
+ if (!credentials.token) return null;
224
+ if (!env.jwks) return null;
225
+ try {
226
+ const jwkSet = (0, jose.createLocalJWKSet)(env.jwks);
227
+ const { payload } = await (0, jose.jwtVerify)(credentials.token, jwkSet);
228
+ if (typeof payload.sub !== "string") return null;
229
+ const claims = payload;
230
+ return {
231
+ authType: "user",
232
+ token: credentials.token,
233
+ userClaims: claimsToUserClaims(claims),
234
+ claims,
235
+ keyName: null
236
+ };
237
+ } catch {
238
+ return null;
239
+ }
240
+ default: return null;
241
+ }
242
+ }
243
+ async function verifyCredentials(credentials, options) {
244
+ const { data: env, error: envError } = resolveEnv(options.env);
245
+ if (envError) return {
246
+ data: null,
247
+ error: new AuthError(envError.message, envError.code, 500)
248
+ };
249
+ const modes = Array.isArray(options.allow) ? options.allow : [options.allow];
250
+ for (const mode of modes) {
251
+ const result = await tryMode(mode, credentials, env);
252
+ if (result) return {
253
+ data: result,
254
+ error: null
255
+ };
256
+ }
257
+ return {
258
+ data: null,
259
+ error: new AuthError("Invalid credentials", "INVALID_CREDENTIALS", 401)
260
+ };
261
+ }
262
+
263
+ //#endregion
264
+ //#region src/core/verify-auth.ts
265
+ async function verifyAuth(request, options) {
266
+ return verifyCredentials(extractCredentials(request), options);
267
+ }
268
+
269
+ //#endregion
270
+ Object.defineProperty(exports, 'AuthError', {
271
+ enumerable: true,
272
+ get: function () {
273
+ return AuthError;
274
+ }
275
+ });
276
+ Object.defineProperty(exports, 'EnvError', {
277
+ enumerable: true,
278
+ get: function () {
279
+ return EnvError;
280
+ }
281
+ });
282
+ Object.defineProperty(exports, 'createAdminClient', {
283
+ enumerable: true,
284
+ get: function () {
285
+ return createAdminClient;
286
+ }
287
+ });
288
+ Object.defineProperty(exports, 'createContextClient', {
289
+ enumerable: true,
290
+ get: function () {
291
+ return createContextClient;
292
+ }
293
+ });
294
+ Object.defineProperty(exports, 'extractCredentials', {
295
+ enumerable: true,
296
+ get: function () {
297
+ return extractCredentials;
298
+ }
299
+ });
300
+ Object.defineProperty(exports, 'resolveEnv', {
301
+ enumerable: true,
302
+ get: function () {
303
+ return resolveEnv;
304
+ }
305
+ });
306
+ Object.defineProperty(exports, 'verifyAuth', {
307
+ enumerable: true,
308
+ get: function () {
309
+ return verifyAuth;
310
+ }
311
+ });
312
+ Object.defineProperty(exports, 'verifyCredentials', {
313
+ enumerable: true,
314
+ get: function () {
315
+ return verifyCredentials;
316
+ }
317
+ });