@kamod-ch/otok-supabase 1.1.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.
- package/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +248 -0
- package/dist/admin/create-admin-client.d.ts +4 -0
- package/dist/admin/create-admin-client.d.ts.map +1 -0
- package/dist/admin/create-admin-client.js +20 -0
- package/dist/admin/create-admin-client.js.map +1 -0
- package/dist/admin/index.d.ts +2 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +2 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/auth/actions.d.ts +13 -0
- package/dist/auth/actions.d.ts.map +1 -0
- package/dist/auth/actions.js +98 -0
- package/dist/auth/actions.js.map +1 -0
- package/dist/auth/index.d.ts +4 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +4 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/middleware.d.ts +7 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +70 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/redirects.d.ts +9 -0
- package/dist/auth/redirects.d.ts.map +1 -0
- package/dist/auth/redirects.js +45 -0
- package/dist/auth/redirects.js.map +1 -0
- package/dist/auth/routes.d.ts +10 -0
- package/dist/auth/routes.d.ts.map +1 -0
- package/dist/auth/routes.js +111 -0
- package/dist/auth/routes.js.map +1 -0
- package/dist/browser/create-browser-client.d.ts +6 -0
- package/dist/browser/create-browser-client.d.ts.map +1 -0
- package/dist/browser/create-browser-client.js +27 -0
- package/dist/browser/create-browser-client.js.map +1 -0
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +2 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +77 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +6 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +15 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +27 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +77 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +23 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +27 -0
- package/dist/loader.js.map +1 -0
- package/dist/plugin.d.ts +6 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +65 -0
- package/dist/plugin.js.map +1 -0
- package/dist/realtime/index.d.ts +8 -0
- package/dist/realtime/index.d.ts.map +1 -0
- package/dist/realtime/index.js +8 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/registry.d.ts +7 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +18 -0
- package/dist/registry.js.map +1 -0
- package/dist/server/cookies.d.ts +20 -0
- package/dist/server/cookies.d.ts.map +1 -0
- package/dist/server/cookies.js +87 -0
- package/dist/server/cookies.js.map +1 -0
- package/dist/server/create-server-client.d.ts +6 -0
- package/dist/server/create-server-client.d.ts.map +1 -0
- package/dist/server/create-server-client.js +20 -0
- package/dist/server/create-server-client.js.map +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +3 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/middleware.d.ts +6 -0
- package/dist/server/middleware.d.ts.map +1 -0
- package/dist/server/middleware.js +14 -0
- package/dist/server/middleware.js.map +1 -0
- package/dist/storage/index.d.ts +8 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +8 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/test/fixtures.d.ts +141 -0
- package/dist/test/fixtures.d.ts.map +1 -0
- package/dist/test/fixtures.js +30 -0
- package/dist/test/fixtures.js.map +1 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +92 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Context, Hono } from "hono";
|
|
2
|
+
import type { SupabaseAuthRoutesOptions } from "../types.js";
|
|
3
|
+
export interface SupabaseAuthRoutes {
|
|
4
|
+
mount(app: Hono): void;
|
|
5
|
+
callback(c: Context): Promise<Response>;
|
|
6
|
+
confirm(c: Context): Promise<Response>;
|
|
7
|
+
signOut(c: Context): Promise<Response>;
|
|
8
|
+
}
|
|
9
|
+
export declare function createSupabaseAuthRoutes(options?: SupabaseAuthRoutesOptions): SupabaseAuthRoutes;
|
|
10
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/auth/routes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG1C,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAQ7D,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,OAAO,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,OAAO,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACxC;AAmCD,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,yBAA8B,GAAG,kBAAkB,CAwFpG"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { getCookie } from "hono/cookie";
|
|
2
|
+
import { isDataRequest, OTOK_CSRF_FIELD } from "@kamod-ch/otok/shared";
|
|
3
|
+
import { mapSupabaseError } from "../errors.js";
|
|
4
|
+
import { resolveAuthRedirect, safeRedirectPath } from "./redirects.js";
|
|
5
|
+
const DEFAULT_CALLBACK = "/auth/callback";
|
|
6
|
+
const DEFAULT_CONFIRM = "/auth/confirm";
|
|
7
|
+
const DEFAULT_SIGNOUT = "/auth/signout";
|
|
8
|
+
function timingSafeEqual(a, b) {
|
|
9
|
+
if (a.length !== b.length)
|
|
10
|
+
return false;
|
|
11
|
+
let mismatch = 0;
|
|
12
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
13
|
+
mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
14
|
+
}
|
|
15
|
+
return mismatch === 0;
|
|
16
|
+
}
|
|
17
|
+
function verifySignOutCsrf(c, formData) {
|
|
18
|
+
const cookie = getCookie(c, "otok_csrf") ?? getCookie(c, "sb-csrf");
|
|
19
|
+
const submitted = String(formData?.get(OTOK_CSRF_FIELD) ?? c.req.header("x-csrf-token") ?? "");
|
|
20
|
+
if (!cookie || !submitted || !timingSafeEqual(cookie, submitted)) {
|
|
21
|
+
return c.json({ status: 403, message: "Invalid CSRF token" }, 403);
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
function authFailureResponse(c, message, status = 400, errorRedirect) {
|
|
26
|
+
if (isDataRequest(c.req.raw)) {
|
|
27
|
+
return c.json({ status, message }, status);
|
|
28
|
+
}
|
|
29
|
+
const target = safeRedirectPath(errorRedirect ?? "/login", ["/"]) ?? "/login";
|
|
30
|
+
const url = new URL(target, c.req.url);
|
|
31
|
+
url.searchParams.set("error", "auth_failed");
|
|
32
|
+
return c.redirect(`${url.pathname}${url.search}`, 303);
|
|
33
|
+
}
|
|
34
|
+
export function createSupabaseAuthRoutes(options = {}) {
|
|
35
|
+
const successRedirect = options.successRedirect ?? "/dashboard";
|
|
36
|
+
const errorRedirect = options.errorRedirect ?? "/login";
|
|
37
|
+
const callbackPath = options.callbackPath ?? DEFAULT_CALLBACK;
|
|
38
|
+
const confirmPath = options.confirmPath ?? DEFAULT_CONFIRM;
|
|
39
|
+
const signOutPath = options.signOutPath ?? DEFAULT_SIGNOUT;
|
|
40
|
+
const allowlist = options.redirectAllowlist ?? ["/", successRedirect, errorRedirect];
|
|
41
|
+
async function callback(c) {
|
|
42
|
+
const supabase = c.var.supabase;
|
|
43
|
+
const code = c.req.query("code");
|
|
44
|
+
const next = resolveAuthRedirect(c.req.query("next") ?? c.req.query("returnTo"), successRedirect, allowlist);
|
|
45
|
+
if (!code) {
|
|
46
|
+
return authFailureResponse(c, "Missing authorization code.", 400, errorRedirect);
|
|
47
|
+
}
|
|
48
|
+
const { error } = await supabase.auth.exchangeCodeForSession(code);
|
|
49
|
+
if (error) {
|
|
50
|
+
const failure = mapSupabaseError(error, "Authentication failed.");
|
|
51
|
+
return authFailureResponse(c, failure.message ?? "Authentication failed.", failure.status, errorRedirect);
|
|
52
|
+
}
|
|
53
|
+
if (isDataRequest(c.req.raw)) {
|
|
54
|
+
return c.json({ redirect: next });
|
|
55
|
+
}
|
|
56
|
+
return c.redirect(next, 303);
|
|
57
|
+
}
|
|
58
|
+
async function confirm(c) {
|
|
59
|
+
const supabase = c.var.supabase;
|
|
60
|
+
const tokenHash = c.req.query("token_hash");
|
|
61
|
+
const type = c.req.query("type");
|
|
62
|
+
const next = resolveAuthRedirect(c.req.query("next"), successRedirect, allowlist);
|
|
63
|
+
if (!tokenHash || !type) {
|
|
64
|
+
return authFailureResponse(c, "Invalid confirmation link.", 400, errorRedirect);
|
|
65
|
+
}
|
|
66
|
+
const { error } = await supabase.auth.verifyOtp({ type, token_hash: tokenHash });
|
|
67
|
+
if (error) {
|
|
68
|
+
const failure = mapSupabaseError(error, "Email confirmation failed.");
|
|
69
|
+
return authFailureResponse(c, failure.message ?? "Email confirmation failed.", failure.status, errorRedirect);
|
|
70
|
+
}
|
|
71
|
+
if (isDataRequest(c.req.raw)) {
|
|
72
|
+
return c.json({ redirect: next });
|
|
73
|
+
}
|
|
74
|
+
return c.redirect(next, 303);
|
|
75
|
+
}
|
|
76
|
+
async function signOut(c) {
|
|
77
|
+
if (c.req.method !== "POST") {
|
|
78
|
+
return c.json({ status: 405, message: "Method not allowed" }, 405);
|
|
79
|
+
}
|
|
80
|
+
let formData;
|
|
81
|
+
const contentType = c.req.header("content-type") ?? "";
|
|
82
|
+
if (contentType.includes("multipart/form-data") || contentType.includes("application/x-www-form-urlencoded")) {
|
|
83
|
+
formData = await c.req.formData();
|
|
84
|
+
}
|
|
85
|
+
const csrfFailure = verifySignOutCsrf(c, formData);
|
|
86
|
+
if (csrfFailure)
|
|
87
|
+
return csrfFailure;
|
|
88
|
+
const supabase = c.var.supabase;
|
|
89
|
+
const { error } = await supabase.auth.signOut();
|
|
90
|
+
if (error) {
|
|
91
|
+
const failure = mapSupabaseError(error, "Sign out failed.");
|
|
92
|
+
return c.json(failure, failure.status);
|
|
93
|
+
}
|
|
94
|
+
const next = resolveAuthRedirect(c.req.query("next"), errorRedirect, allowlist);
|
|
95
|
+
if (isDataRequest(c.req.raw)) {
|
|
96
|
+
return c.json({ redirect: next });
|
|
97
|
+
}
|
|
98
|
+
return c.redirect(next, 303);
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
mount(app) {
|
|
102
|
+
app.get(callbackPath, callback);
|
|
103
|
+
app.get(confirmPath, confirm);
|
|
104
|
+
app.post(signOutPath, signOut);
|
|
105
|
+
},
|
|
106
|
+
callback,
|
|
107
|
+
confirm,
|
|
108
|
+
signOut,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/auth/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import { type SupabaseConfig } from "../config.js";
|
|
3
|
+
export declare function createOtokSupabaseBrowserClient<Database>(config: SupabaseConfig): SupabaseClient<Database>;
|
|
4
|
+
/** Reset the browser singleton — for tests only. */
|
|
5
|
+
export declare function resetOtokSupabaseBrowserClientForTests(): void;
|
|
6
|
+
//# sourceMappingURL=create-browser-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-browser-client.d.ts","sourceRoot":"","sources":["../../src/browser/create-browser-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAA0B,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAI3E,wBAAgB,+BAA+B,CAAC,QAAQ,EACtD,MAAM,EAAE,cAAc,GACrB,cAAc,CAAC,QAAQ,CAAC,CAuB1B;AAED,oDAAoD;AACpD,wBAAgB,sCAAsC,IAAI,IAAI,CAE7D"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createBrowserClient } from "@supabase/ssr";
|
|
2
|
+
import { validateSupabaseConfig } from "../config.js";
|
|
3
|
+
let browserClient;
|
|
4
|
+
export function createOtokSupabaseBrowserClient(config) {
|
|
5
|
+
const validated = validateSupabaseConfig(config);
|
|
6
|
+
if (typeof window === "undefined") {
|
|
7
|
+
throw new Error("otok-supabase: createOtokSupabaseBrowserClient() must only be called in the browser.");
|
|
8
|
+
}
|
|
9
|
+
if (!browserClient) {
|
|
10
|
+
browserClient = createBrowserClient(validated.url, validated.publishableKey, {
|
|
11
|
+
cookieOptions: validated.cookieOptions
|
|
12
|
+
? {
|
|
13
|
+
domain: validated.cookieOptions.domain,
|
|
14
|
+
path: validated.cookieOptions.path,
|
|
15
|
+
sameSite: validated.cookieOptions.sameSite,
|
|
16
|
+
secure: validated.cookieOptions.secure,
|
|
17
|
+
}
|
|
18
|
+
: undefined,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return browserClient;
|
|
22
|
+
}
|
|
23
|
+
/** Reset the browser singleton — for tests only. */
|
|
24
|
+
export function resetOtokSupabaseBrowserClientForTests() {
|
|
25
|
+
browserClient = undefined;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=create-browser-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-browser-client.js","sourceRoot":"","sources":["../../src/browser/create-browser-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAE,sBAAsB,EAAuB,MAAM,cAAc,CAAC;AAE3E,IAAI,aAA8C,CAAC;AAEnD,MAAM,UAAU,+BAA+B,CAC7C,MAAsB;IAEtB,MAAM,SAAS,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAEjD,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CACb,sFAAsF,CACvF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,aAAa,GAAG,mBAAmB,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,cAAc,EAAE;YAC3E,aAAa,EAAE,SAAS,CAAC,aAAa;gBACpC,CAAC,CAAC;oBACE,MAAM,EAAE,SAAS,CAAC,aAAa,CAAC,MAAM;oBACtC,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,IAAI;oBAClC,QAAQ,EAAE,SAAS,CAAC,aAAa,CAAC,QAAQ;oBAC1C,MAAM,EAAE,SAAS,CAAC,aAAa,CAAC,MAAM;iBACvC;gBACH,CAAC,CAAC,SAAS;SACd,CAAC,CAAC;IACL,CAAC;IAED,OAAO,aAAyC,CAAC;AACnD,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,sCAAsC;IACpD,aAAa,GAAG,SAAS,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,+BAA+B,EAC/B,sCAAsC,GACvC,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,+BAA+B,EAC/B,sCAAsC,GACvC,MAAM,4BAA4B,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface SupabaseCookieOptions {
|
|
2
|
+
domain?: string;
|
|
3
|
+
path?: string;
|
|
4
|
+
sameSite?: "lax" | "strict" | "none";
|
|
5
|
+
secure?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface SupabaseConfig {
|
|
8
|
+
url: string;
|
|
9
|
+
publishableKey: string;
|
|
10
|
+
cookieOptions?: SupabaseCookieOptions;
|
|
11
|
+
}
|
|
12
|
+
export interface SupabaseAdminConfig {
|
|
13
|
+
url: string;
|
|
14
|
+
serviceRoleKey: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function validateSupabaseConfig(config: SupabaseConfig): SupabaseConfig;
|
|
17
|
+
export declare function validateSupabaseAdminConfig(config: SupabaseAdminConfig): SupabaseAdminConfig;
|
|
18
|
+
export declare function mergeCookieOptions(supabaseOptions: Record<string, unknown> | undefined, defaults: SupabaseCookieOptions | undefined): Record<string, unknown>;
|
|
19
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,qBAAqB,CAAC;CACvC;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;CACxB;AA0BD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAwB7E;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB,CAmB5F;AAED,wBAAgB,kBAAkB,CAChC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACpD,QAAQ,EAAE,qBAAqB,GAAG,SAAS,GAC1C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { SupabaseConfigurationError } from "./errors.js";
|
|
2
|
+
const URL_PATTERN = /^https?:\/\/.+/;
|
|
3
|
+
function decodeJwtPayload(key) {
|
|
4
|
+
const parts = key.split(".");
|
|
5
|
+
if (parts.length < 2)
|
|
6
|
+
return null;
|
|
7
|
+
try {
|
|
8
|
+
const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
9
|
+
const padded = payload.padEnd(payload.length + ((4 - (payload.length % 4)) % 4), "=");
|
|
10
|
+
const json = atob(padded);
|
|
11
|
+
return JSON.parse(json);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function assertNotServiceRoleKey(key, label) {
|
|
18
|
+
const payload = decodeJwtPayload(key);
|
|
19
|
+
if (payload?.role === "service_role") {
|
|
20
|
+
throw new SupabaseConfigurationError(`${label} must not be a service role key. Use the publishable (anon) key for browser and SSR clients.`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function validateSupabaseConfig(config) {
|
|
24
|
+
if (!config || typeof config !== "object") {
|
|
25
|
+
throw new SupabaseConfigurationError("Supabase configuration must be an object.");
|
|
26
|
+
}
|
|
27
|
+
const url = String(config.url ?? "").trim();
|
|
28
|
+
if (!url) {
|
|
29
|
+
throw new SupabaseConfigurationError("Supabase url is required.");
|
|
30
|
+
}
|
|
31
|
+
if (!URL_PATTERN.test(url)) {
|
|
32
|
+
throw new SupabaseConfigurationError("Supabase url must be an absolute http(s) URL.");
|
|
33
|
+
}
|
|
34
|
+
const publishableKey = String(config.publishableKey ?? "").trim();
|
|
35
|
+
if (!publishableKey) {
|
|
36
|
+
throw new SupabaseConfigurationError("Supabase publishableKey is required.");
|
|
37
|
+
}
|
|
38
|
+
assertNotServiceRoleKey(publishableKey, "publishableKey");
|
|
39
|
+
return {
|
|
40
|
+
url,
|
|
41
|
+
publishableKey,
|
|
42
|
+
cookieOptions: config.cookieOptions,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function validateSupabaseAdminConfig(config) {
|
|
46
|
+
if (!config || typeof config !== "object") {
|
|
47
|
+
throw new SupabaseConfigurationError("Supabase admin configuration must be an object.");
|
|
48
|
+
}
|
|
49
|
+
const url = String(config.url ?? "").trim();
|
|
50
|
+
if (!url) {
|
|
51
|
+
throw new SupabaseConfigurationError("Supabase url is required.");
|
|
52
|
+
}
|
|
53
|
+
if (!URL_PATTERN.test(url)) {
|
|
54
|
+
throw new SupabaseConfigurationError("Supabase url must be an absolute http(s) URL.");
|
|
55
|
+
}
|
|
56
|
+
const serviceRoleKey = String(config.serviceRoleKey ?? "").trim();
|
|
57
|
+
if (!serviceRoleKey) {
|
|
58
|
+
throw new SupabaseConfigurationError("Supabase serviceRoleKey is required.");
|
|
59
|
+
}
|
|
60
|
+
return { url, serviceRoleKey };
|
|
61
|
+
}
|
|
62
|
+
export function mergeCookieOptions(supabaseOptions, defaults) {
|
|
63
|
+
const merged = { ...(supabaseOptions ?? {}) };
|
|
64
|
+
if (defaults?.domain !== undefined)
|
|
65
|
+
merged.domain = defaults.domain;
|
|
66
|
+
if (defaults?.path !== undefined)
|
|
67
|
+
merged.path = defaults.path;
|
|
68
|
+
if (defaults?.secure !== undefined)
|
|
69
|
+
merged.secure = defaults.secure;
|
|
70
|
+
if (defaults?.sameSite !== undefined) {
|
|
71
|
+
merged.sameSite = defaults.sameSite;
|
|
72
|
+
}
|
|
73
|
+
if (!merged.path)
|
|
74
|
+
merged.path = "/";
|
|
75
|
+
return merged;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
3
|
+
import type { OtokContext } from "@kamod-ch/otok/server";
|
|
4
|
+
export declare function supabaseFromHono<Database = unknown>(hono: Context | OtokContext["hono"], contextKey?: string): SupabaseClient<Database>;
|
|
5
|
+
export declare function getSupabaseConfig(): import("./config.js").SupabaseConfig;
|
|
6
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,wBAAgB,gBAAgB,CAAC,QAAQ,GAAG,OAAO,EACjD,IAAI,EAAE,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,EACnC,UAAU,SAAa,GACtB,cAAc,CAAC,QAAQ,CAAC,CAW1B;AAED,wBAAgB,iBAAiB,yCAEhC"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { getSupabaseRuntime, tryGetSupabaseRuntime } from "./registry.js";
|
|
2
|
+
export function supabaseFromHono(hono, contextKey = "supabase") {
|
|
3
|
+
const client = hono.get(contextKey);
|
|
4
|
+
if (!client) {
|
|
5
|
+
const runtime = tryGetSupabaseRuntime();
|
|
6
|
+
throw new Error(runtime
|
|
7
|
+
? `otok-supabase: Supabase client not found on Hono context key "${contextKey}". Mount supabase() middleware first.`
|
|
8
|
+
: "otok-supabase: no runtime registered. Add supabase() to otok.config.ts plugins.");
|
|
9
|
+
}
|
|
10
|
+
return client;
|
|
11
|
+
}
|
|
12
|
+
export function getSupabaseConfig() {
|
|
13
|
+
return getSupabaseRuntime().config;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE1E,MAAM,UAAU,gBAAgB,CAC9B,IAAmC,EACnC,UAAU,GAAG,UAAU;IAEvB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,UAAmB,CAAyC,CAAC;IACrF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,OAAO;YACL,CAAC,CAAC,iEAAiE,UAAU,uCAAuC;YACpH,CAAC,CAAC,iFAAiF,CACtF,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,kBAAkB,EAAE,CAAC,MAAM,CAAC;AACrC,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AuthError as SupabaseAuthApiError, PostgrestError } from "@supabase/supabase-js";
|
|
2
|
+
import type { OtokFailure } from "@kamod-ch/otok/server";
|
|
3
|
+
export type SupabaseIntegrationErrorCode = "configuration" | "auth" | "cookie" | "runtime" | "unsafe_redirect";
|
|
4
|
+
export declare class OtokSupabaseError extends Error {
|
|
5
|
+
readonly code: SupabaseIntegrationErrorCode;
|
|
6
|
+
constructor(code: SupabaseIntegrationErrorCode, message: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class SupabaseConfigurationError extends OtokSupabaseError {
|
|
9
|
+
constructor(message: string);
|
|
10
|
+
}
|
|
11
|
+
export declare class SupabaseAuthError extends OtokSupabaseError {
|
|
12
|
+
readonly status: number;
|
|
13
|
+
constructor(message: string, status?: number);
|
|
14
|
+
}
|
|
15
|
+
export declare class SupabaseCookieError extends OtokSupabaseError {
|
|
16
|
+
constructor(message: string);
|
|
17
|
+
}
|
|
18
|
+
type MappableError = PostgrestError | SupabaseAuthApiError | {
|
|
19
|
+
message?: string;
|
|
20
|
+
status?: number;
|
|
21
|
+
code?: string;
|
|
22
|
+
};
|
|
23
|
+
export declare function mapSupabaseError(error: MappableError, fallbackMessage?: string): OtokFailure;
|
|
24
|
+
export declare function throwSupabaseError(error: MappableError, fallbackMessage?: string): never;
|
|
25
|
+
export declare function isSupabaseIntegrationError(error: unknown): error is OtokSupabaseError;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,IAAI,oBAAoB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC/F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,MAAM,4BAA4B,GACpC,eAAe,GACf,MAAM,GACN,QAAQ,GACR,SAAS,GACT,iBAAiB,CAAC;AAEtB,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;gBAEhC,IAAI,EAAE,4BAA4B,EAAE,OAAO,EAAE,MAAM;CAKhE;AAED,qBAAa,0BAA2B,SAAQ,iBAAiB;gBACnD,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,iBAAkB,SAAQ,iBAAiB;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,OAAO,EAAE,MAAM,EAAE,MAAM,SAAM;CAK1C;AAED,qBAAa,mBAAoB,SAAQ,iBAAiB;gBAC5C,OAAO,EAAE,MAAM;CAI5B;AAED,KAAK,aAAa,GAAG,cAAc,GAAG,oBAAoB,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AA6BlH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,eAAe,SAAmB,GAAG,WAAW,CAkBtG;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,eAAe,SAAmB,GAAG,KAAK,CAGlG;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAErF"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export class OtokSupabaseError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
constructor(code, message) {
|
|
4
|
+
super(`[otok-supabase:${code}] ${message}`);
|
|
5
|
+
this.name = "OtokSupabaseError";
|
|
6
|
+
this.code = code;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class SupabaseConfigurationError extends OtokSupabaseError {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super("configuration", message);
|
|
12
|
+
this.name = "SupabaseConfigurationError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class SupabaseAuthError extends OtokSupabaseError {
|
|
16
|
+
status;
|
|
17
|
+
constructor(message, status = 401) {
|
|
18
|
+
super("auth", message);
|
|
19
|
+
this.name = "SupabaseAuthError";
|
|
20
|
+
this.status = status;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export class SupabaseCookieError extends OtokSupabaseError {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super("cookie", message);
|
|
26
|
+
this.name = "SupabaseCookieError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const PUBLIC_AUTH_MESSAGES = {
|
|
30
|
+
invalid_credentials: "Invalid email or password.",
|
|
31
|
+
email_not_confirmed: "Please confirm your email before signing in.",
|
|
32
|
+
user_already_exists: "An account with this email already exists.",
|
|
33
|
+
weak_password: "Password is too weak.",
|
|
34
|
+
over_request_rate_limit: "Too many requests. Please try again later.",
|
|
35
|
+
};
|
|
36
|
+
function sanitizeMessage(message, fallback) {
|
|
37
|
+
if (!message)
|
|
38
|
+
return fallback;
|
|
39
|
+
if (/key|secret|token|password|service_role/i.test(message))
|
|
40
|
+
return fallback;
|
|
41
|
+
return message;
|
|
42
|
+
}
|
|
43
|
+
function fieldErrorsFromAuthError(error) {
|
|
44
|
+
if (error.code === "invalid_credentials") {
|
|
45
|
+
return { password: ["Invalid email or password."] };
|
|
46
|
+
}
|
|
47
|
+
if (error.code === "weak_password") {
|
|
48
|
+
return { password: ["Password is too weak."] };
|
|
49
|
+
}
|
|
50
|
+
if (error.code === "user_already_exists") {
|
|
51
|
+
return { email: ["An account with this email already exists."] };
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
export function mapSupabaseError(error, fallbackMessage = "Request failed") {
|
|
56
|
+
const code = "code" in error ? error.code : undefined;
|
|
57
|
+
const status = "status" in error && typeof error.status === "number"
|
|
58
|
+
? error.status
|
|
59
|
+
: code === "PGRST116"
|
|
60
|
+
? 404
|
|
61
|
+
: 400;
|
|
62
|
+
const publicMessage = (code && PUBLIC_AUTH_MESSAGES[code]) ||
|
|
63
|
+
sanitizeMessage(error.message, fallbackMessage);
|
|
64
|
+
return {
|
|
65
|
+
status,
|
|
66
|
+
message: publicMessage,
|
|
67
|
+
fieldErrors: "name" in error && error.name === "AuthApiError" ? fieldErrorsFromAuthError(error) : undefined,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export function throwSupabaseError(error, fallbackMessage = "Request failed") {
|
|
71
|
+
const failure = mapSupabaseError(error, fallbackMessage);
|
|
72
|
+
throw Object.assign(new Error(failure.message), { failure, otokFailure: failure });
|
|
73
|
+
}
|
|
74
|
+
export function isSupabaseIntegrationError(error) {
|
|
75
|
+
return error instanceof OtokSupabaseError;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { default, configureSupabaseApp } from "./plugin.js";
|
|
2
|
+
export type { SupabaseConfig, SupabaseAdminConfig, SupabaseCookieOptions } from "./config.js";
|
|
3
|
+
export type { SupabasePluginOptions } from "./types.js";
|
|
4
|
+
export { validateSupabaseConfig, validateSupabaseAdminConfig } from "./config.js";
|
|
5
|
+
export { mapSupabaseError, throwSupabaseError, isSupabaseIntegrationError, OtokSupabaseError, SupabaseConfigurationError, SupabaseAuthError, SupabaseCookieError, } from "./errors.js";
|
|
6
|
+
export type { SupabaseClient, User, JwtPayload, SupabaseVariables, SupabaseClaimsVariables, SupabaseUserVariables, SupabaseEnv, SupabaseAuthClaimsEnv, SupabaseAuthUserEnv, SupabaseAuthFullEnv, SupabaseAuthRoutesOptions, RequireSupabaseAuthOptions, RequireSupabaseUserOptions, SupabaseActionResult, SupabaseRuntime, } from "./types.js";
|
|
7
|
+
export { registerSupabaseRuntime, getSupabaseRuntime, tryGetSupabaseRuntime, resetSupabaseRuntimeForTests, } from "./registry.js";
|
|
8
|
+
export { supabaseFromHono, getSupabaseConfig } from "./context.js";
|
|
9
|
+
export { createOtokSupabaseBrowserClient } from "./browser/index.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC9F,YAAY,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,0BAA0B,EAC1B,iBAAiB,EACjB,0BAA0B,EAC1B,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,cAAc,EACd,IAAI,EACJ,UAAU,EACV,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,WAAW,EACX,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,0BAA0B,EAC1B,0BAA0B,EAC1B,oBAAoB,EACpB,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default, configureSupabaseApp } from "./plugin.js";
|
|
2
|
+
export { validateSupabaseConfig, validateSupabaseAdminConfig } from "./config.js";
|
|
3
|
+
export { mapSupabaseError, throwSupabaseError, isSupabaseIntegrationError, OtokSupabaseError, SupabaseConfigurationError, SupabaseAuthError, SupabaseCookieError, } from "./errors.js";
|
|
4
|
+
export { registerSupabaseRuntime, getSupabaseRuntime, tryGetSupabaseRuntime, resetSupabaseRuntimeForTests, } from "./registry.js";
|
|
5
|
+
export { supabaseFromHono, getSupabaseConfig } from "./context.js";
|
|
6
|
+
export { createOtokSupabaseBrowserClient } from "./browser/index.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAG5D,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,0BAA0B,EAC1B,iBAAiB,EACjB,0BAA0B,EAC1B,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAkBrB,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { LoaderResult, OtokActionContext, OtokContext, OtokLoader } from "@kamod-ch/otok/server";
|
|
2
|
+
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
3
|
+
type LoaderSupabaseContext<Database> = {
|
|
4
|
+
supabase: SupabaseClient<Database>;
|
|
5
|
+
};
|
|
6
|
+
type ActionSupabaseContext<Database> = LoaderSupabaseContext<Database>;
|
|
7
|
+
/**
|
|
8
|
+
* Wrap a loader with typed `supabase` from the registered middleware.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* export const loader = defineLoader<Database>(async ({ supabase }) => {
|
|
12
|
+
* const { data } = await supabase.from("projects").select("*");
|
|
13
|
+
* return { projects: data ?? [] };
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function defineLoader<Data extends LoaderResult, Database = unknown>(handler: (ctx: OtokContext & LoaderSupabaseContext<Database>) => Data | Promise<Data>, contextKey?: string): OtokLoader<Data>;
|
|
18
|
+
/**
|
|
19
|
+
* Wrap an action with typed `supabase` from the registered middleware.
|
|
20
|
+
*/
|
|
21
|
+
export declare function defineAction<Result, Database = unknown>(handler: (ctx: OtokActionContext & ActionSupabaseContext<Database>) => Result | Promise<Result>, contextKey?: string): (context: OtokActionContext) => Result | Promise<Result>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACtG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,KAAK,qBAAqB,CAAC,QAAQ,IAAI;IACrC,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;CACpC,CAAC;AAEF,KAAK,qBAAqB,CAAC,QAAQ,IAAI,qBAAqB,CAAC,QAAQ,CAAC,CAAC;AAEvE;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,IAAI,SAAS,YAAY,EAAE,QAAQ,GAAG,OAAO,EACxE,OAAO,EAAE,CAAC,GAAG,EAAE,WAAW,GAAG,qBAAqB,CAAC,QAAQ,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EACrF,UAAU,SAAa,GACtB,UAAU,CAAC,IAAI,CAAC,CAMlB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,EACrD,OAAO,EAAE,CAAC,GAAG,EAAE,iBAAiB,GAAG,qBAAqB,CAAC,QAAQ,CAAC,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,EAC/F,UAAU,SAAa,GACtB,CAAC,OAAO,EAAE,iBAAiB,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM1D"}
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { supabaseFromHono } from "./context.js";
|
|
2
|
+
/**
|
|
3
|
+
* Wrap a loader with typed `supabase` from the registered middleware.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* export const loader = defineLoader<Database>(async ({ supabase }) => {
|
|
7
|
+
* const { data } = await supabase.from("projects").select("*");
|
|
8
|
+
* return { projects: data ?? [] };
|
|
9
|
+
* });
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export function defineLoader(handler, contextKey = "supabase") {
|
|
13
|
+
return (context) => handler({
|
|
14
|
+
...context,
|
|
15
|
+
supabase: supabaseFromHono(context.hono, contextKey),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Wrap an action with typed `supabase` from the registered middleware.
|
|
20
|
+
*/
|
|
21
|
+
export function defineAction(handler, contextKey = "supabase") {
|
|
22
|
+
return (context) => handler({
|
|
23
|
+
...context,
|
|
24
|
+
supabase: supabaseFromHono(context.hono, contextKey),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAQhD;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAqF,EACrF,UAAU,GAAG,UAAU;IAEvB,OAAO,CAAC,OAAO,EAAE,EAAE,CACjB,OAAO,CAAC;QACN,GAAG,OAAO;QACV,QAAQ,EAAE,gBAAgB,CAAW,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC;KAC/D,CAAC,CAAC;AACP,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,OAA+F,EAC/F,UAAU,GAAG,UAAU;IAEvB,OAAO,CAAC,OAAO,EAAE,EAAE,CACjB,OAAO,CAAC;QACN,GAAG,OAAO;QACV,QAAQ,EAAE,gBAAgB,CAAW,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC;KAC/D,CAAC,CAAC;AACP,CAAC"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Hono } from "hono";
|
|
2
|
+
import type { SupabasePluginOptions, SupabaseRuntime } from "./types.js";
|
|
3
|
+
export declare function configureSupabaseApp(app: Hono, options: SupabasePluginOptions): SupabaseRuntime;
|
|
4
|
+
/** Otok plugin factory — register in otok.config.ts plugins array. */
|
|
5
|
+
export default function supabasePlugin(options: SupabasePluginOptions): import("@kamod-ch/otok-config").OtokPlugin<unknown>;
|
|
6
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAMjC,OAAO,KAAK,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAQzE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,qBAAqB,GAAG,eAAe,CAuB/F;AA6BD,sEAAsE;AACtE,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,OAAO,EAAE,qBAAqB,uDAMpE"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { definePlugin } from "@kamod-ch/otok";
|
|
2
|
+
import { validateSupabaseConfig } from "./config.js";
|
|
3
|
+
import { SupabaseConfigurationError } from "./errors.js";
|
|
4
|
+
import { createSupabaseAuthRoutes } from "./auth/routes.js";
|
|
5
|
+
import { registerSupabaseRuntime } from "./registry.js";
|
|
6
|
+
import { supabase } from "./server/middleware.js";
|
|
7
|
+
const DEFAULT_AUTH_ROUTES = {
|
|
8
|
+
successRedirect: "/dashboard",
|
|
9
|
+
errorRedirect: "/login",
|
|
10
|
+
redirectAllowlist: ["/"],
|
|
11
|
+
};
|
|
12
|
+
export function configureSupabaseApp(app, options) {
|
|
13
|
+
const config = validateSupabaseConfig(options);
|
|
14
|
+
const mountAuthRoutes = options.mountAuthRoutes !== false;
|
|
15
|
+
const authRoutes = {
|
|
16
|
+
...DEFAULT_AUTH_ROUTES,
|
|
17
|
+
...options.authRoutes,
|
|
18
|
+
};
|
|
19
|
+
const runtime = {
|
|
20
|
+
config,
|
|
21
|
+
authRoutes,
|
|
22
|
+
mountAuthRoutes,
|
|
23
|
+
};
|
|
24
|
+
registerSupabaseRuntime(runtime);
|
|
25
|
+
app.use("*", supabase(config));
|
|
26
|
+
if (mountAuthRoutes) {
|
|
27
|
+
createSupabaseAuthRoutes(authRoutes).mount(app);
|
|
28
|
+
}
|
|
29
|
+
return runtime;
|
|
30
|
+
}
|
|
31
|
+
const supabasePluginFactory = definePlugin({
|
|
32
|
+
name: "@kamod-ch/otok-supabase",
|
|
33
|
+
version: "1.0.0",
|
|
34
|
+
schema: {
|
|
35
|
+
parse(input) {
|
|
36
|
+
if (!input || typeof input !== "object") {
|
|
37
|
+
throw new SupabaseConfigurationError("supabase() options must be an object.");
|
|
38
|
+
}
|
|
39
|
+
validateSupabaseConfig(input);
|
|
40
|
+
return input;
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
envSchema: {
|
|
44
|
+
parse(input) {
|
|
45
|
+
const url = input.SUPABASE_URL?.trim();
|
|
46
|
+
const publishableKey = input.SUPABASE_PUBLISHABLE_KEY?.trim();
|
|
47
|
+
if (url !== undefined && !url) {
|
|
48
|
+
throw new SupabaseConfigurationError("SUPABASE_URL must not be empty when set.");
|
|
49
|
+
}
|
|
50
|
+
if (publishableKey !== undefined && !publishableKey) {
|
|
51
|
+
throw new SupabaseConfigurationError("SUPABASE_PUBLISHABLE_KEY must not be empty when set.");
|
|
52
|
+
}
|
|
53
|
+
return { supabaseUrl: url, supabasePublishableKey: publishableKey };
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
/** Otok plugin factory — register in otok.config.ts plugins array. */
|
|
58
|
+
export default function supabasePlugin(options) {
|
|
59
|
+
const plugin = supabasePluginFactory(options);
|
|
60
|
+
plugin.configureApp = ({ app }) => {
|
|
61
|
+
configureSupabaseApp(app, options);
|
|
62
|
+
};
|
|
63
|
+
return plugin;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=plugin.js.map
|