@aethex.os/supabase 1.0.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/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # @aethex.os/supabase
2
+
3
+ Supabase client factories and Express auth middleware — stop copy-pasting the same Supabase boilerplate across every project.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @aethex.os/supabase @supabase/supabase-js
9
+ ```
10
+
11
+ ## Client factories
12
+
13
+ ```ts
14
+ import { createAdminClient, createUserClient, configFromEnv } from "@aethex.os/supabase";
15
+
16
+ const config = configFromEnv();
17
+ // reads SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE from process.env
18
+
19
+ const adminClient = createAdminClient(config); // service role — full access
20
+ const userClient = createUserClient(config, accessToken); // scoped to user's RLS
21
+ ```
22
+
23
+ Or pass config directly:
24
+
25
+ ```ts
26
+ const config = {
27
+ url: "https://xxxx.supabase.co",
28
+ anonKey: "...",
29
+ serviceRoleKey: "...",
30
+ };
31
+ ```
32
+
33
+ ## Express middleware
34
+
35
+ ```ts
36
+ import express from "express";
37
+ import { requireAuth, configFromEnv } from "@aethex.os/supabase";
38
+
39
+ const app = express();
40
+ const config = configFromEnv();
41
+
42
+ // Protects all routes below
43
+ app.use(requireAuth(config));
44
+
45
+ app.get("/me", (req, res) => {
46
+ // req.user → { id, email, role, metadata }
47
+ // req.supabase → user-scoped client (respects RLS)
48
+ // req.supabaseAdmin → service-role client
49
+ res.json(req.user);
50
+ });
51
+ ```
52
+
53
+ Optionally load profile columns alongside auth:
54
+
55
+ ```ts
56
+ app.use(requireAuth(config, "user_type, primary_arm, full_name"));
57
+ // req.user.role → profile.user_type
58
+ // req.user.metadata → full profile row
59
+ ```
60
+
61
+ ## Manual token verification
62
+
63
+ ```ts
64
+ import { authenticateToken, extractBearerToken } from "@aethex.os/supabase";
65
+
66
+ const token = extractBearerToken(req.headers.authorization);
67
+ if (!token) return res.status(401).json({ error: "No token" });
68
+
69
+ const { user, adminClient, userClient, error } = await authenticateToken(token, config);
70
+ if (!user) return res.status(401).json({ error });
71
+ ```
72
+
73
+ ## TypeScript augmentation
74
+
75
+ Extend `Express.Request` with the user type:
76
+
77
+ ```ts
78
+ declare global {
79
+ namespace Express {
80
+ interface Request {
81
+ user?: import("@aethex.os/supabase").AuthenticatedUser;
82
+ }
83
+ }
84
+ }
85
+ ```
86
+
87
+ ## API
88
+
89
+ | Export | Description |
90
+ |--------|-------------|
91
+ | `createAdminClient(config)` | Service-role Supabase client (bypasses RLS) |
92
+ | `createUserClient(config, token)` | User-scoped Supabase client (respects RLS) |
93
+ | `configFromEnv()` | Read config from environment variables |
94
+ | `authenticateToken(token, config, select?)` | Verify Bearer token, returns user + clients |
95
+ | `extractBearerToken(header)` | Parse `Authorization: Bearer <token>` |
96
+ | `requireAuth(config, select?)` | Express middleware — guards routes, attaches `req.user` |
97
+
98
+ ---
99
+
100
+ Part of the [`@aethex.os`](https://www.npmjs.com/search?q=%40aethex.os) toolkit.
package/lib/auth.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ import { type SupabaseConfig } from "./client";
3
+ export interface AuthenticatedUser {
4
+ id: string;
5
+ email?: string;
6
+ role?: string;
7
+ metadata?: Record<string, unknown>;
8
+ }
9
+ export interface AuthResult {
10
+ user: AuthenticatedUser | null;
11
+ error: string | null;
12
+ adminClient: SupabaseClient;
13
+ userClient: SupabaseClient | null;
14
+ }
15
+ export declare function authenticateToken(accessToken: string, config: SupabaseConfig, selectProfile?: string): Promise<AuthResult>;
16
+ export declare function extractBearerToken(authHeader: string | undefined): string | null;
17
+ export declare function requireAuth(config: SupabaseConfig, selectProfile?: string): (req: any, res: any, next: any) => Promise<void>;
18
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAuC,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAEpF,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,cAAc,CAAC;IAC5B,UAAU,EAAE,cAAc,GAAG,IAAI,CAAC;CACnC;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,UAAU,CAAC,CAgCrB;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAGhF;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,cAAc,EACtB,aAAa,CAAC,EAAE,MAAM,IAER,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,KAAG,OAAO,CAAC,IAAI,CAAC,CAkB5D"}
package/lib/auth.js ADDED
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authenticateToken = authenticateToken;
4
+ exports.extractBearerToken = extractBearerToken;
5
+ exports.requireAuth = requireAuth;
6
+ const client_1 = require("./client");
7
+ async function authenticateToken(accessToken, config, selectProfile) {
8
+ const adminClient = (0, client_1.createAdminClient)(config);
9
+ const { data: { user }, error: authError } = await adminClient.auth.getUser(accessToken);
10
+ if (authError || !user) {
11
+ return { user: null, error: "Invalid or expired token", adminClient, userClient: null };
12
+ }
13
+ let role;
14
+ let metadata;
15
+ if (selectProfile) {
16
+ const { data: profile } = await adminClient
17
+ .from("user_profiles")
18
+ .select(selectProfile)
19
+ .eq("id", user.id)
20
+ .single();
21
+ if (profile) {
22
+ role = profile.user_type ?? profile.role;
23
+ metadata = profile;
24
+ }
25
+ }
26
+ const userClient = (0, client_1.createUserClient)(config, accessToken);
27
+ return {
28
+ user: { id: user.id, email: user.email, role, metadata },
29
+ error: null,
30
+ adminClient,
31
+ userClient,
32
+ };
33
+ }
34
+ function extractBearerToken(authHeader) {
35
+ if (!authHeader?.startsWith("Bearer "))
36
+ return null;
37
+ return authHeader.slice(7);
38
+ }
39
+ function requireAuth(config, selectProfile) {
40
+ return async (req, res, next) => {
41
+ const token = extractBearerToken(req.headers.authorization);
42
+ if (!token) {
43
+ res.status(401).json({ error: "Unauthorized — Bearer token required" });
44
+ return;
45
+ }
46
+ const result = await authenticateToken(token, config, selectProfile);
47
+ if (!result.user) {
48
+ res.status(401).json({ error: result.error });
49
+ return;
50
+ }
51
+ req.user = result.user;
52
+ req.supabase = result.userClient;
53
+ req.supabaseAdmin = result.adminClient;
54
+ next();
55
+ };
56
+ }
57
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":";;AAiBA,8CAoCC;AAED,gDAGC;AAED,kCAsBC;AAjFD,qCAAoF;AAgB7E,KAAK,UAAU,iBAAiB,CACrC,WAAmB,EACnB,MAAsB,EACtB,aAAsB;IAEtB,MAAM,WAAW,GAAG,IAAA,0BAAiB,EAAC,MAAM,CAAC,CAAC;IAE9C,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAEzF,IAAI,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC;QACvB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,0BAA0B,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC1F,CAAC;IAED,IAAI,IAAwB,CAAC;IAC7B,IAAI,QAA6C,CAAC;IAElD,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,WAAW;aACxC,IAAI,CAAC,eAAe,CAAC;aACrB,MAAM,CAAC,aAAa,CAAC;aACrB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;aACjB,MAAM,EAAE,CAAC;QACZ,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;YACzC,QAAQ,GAAG,OAAO,CAAC;QACrB,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,IAAA,yBAAgB,EAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAEzD,OAAO;QACL,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxD,KAAK,EAAE,IAAI;QACX,WAAW;QACX,UAAU;KACX,CAAC;AACJ,CAAC;AAED,SAAgB,kBAAkB,CAAC,UAA8B;IAC/D,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACpD,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,SAAgB,WAAW,CACzB,MAAsB,EACtB,aAAsB;IAEtB,OAAO,KAAK,EAAE,GAAQ,EAAE,GAAQ,EAAE,IAAS,EAAiB,EAAE;QAC5D,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAC5D,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sCAAsC,EAAE,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;QACrE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACvB,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC;QACjC,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC,WAAW,CAAC;QACvC,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type SupabaseClient } from "@supabase/supabase-js";
2
+ export interface SupabaseConfig {
3
+ url: string;
4
+ anonKey: string;
5
+ serviceRoleKey?: string;
6
+ }
7
+ export declare function createAdminClient(config: SupabaseConfig): SupabaseClient;
8
+ export declare function createUserClient(config: SupabaseConfig, accessToken: string): SupabaseClient;
9
+ export declare function configFromEnv(): SupabaseConfig;
10
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE1E,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAKxE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,cAAc,CAK5F;AAED,wBAAgB,aAAa,IAAI,cAAc,CAO9C"}
package/lib/client.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAdminClient = createAdminClient;
4
+ exports.createUserClient = createUserClient;
5
+ exports.configFromEnv = configFromEnv;
6
+ const supabase_js_1 = require("@supabase/supabase-js");
7
+ function createAdminClient(config) {
8
+ if (!config.serviceRoleKey)
9
+ throw new Error("serviceRoleKey required for admin client");
10
+ return (0, supabase_js_1.createClient)(config.url, config.serviceRoleKey, {
11
+ auth: { autoRefreshToken: false, persistSession: false },
12
+ });
13
+ }
14
+ function createUserClient(config, accessToken) {
15
+ return (0, supabase_js_1.createClient)(config.url, config.anonKey, {
16
+ auth: { autoRefreshToken: false, persistSession: false },
17
+ global: { headers: { Authorization: `Bearer ${accessToken}` } },
18
+ });
19
+ }
20
+ function configFromEnv() {
21
+ const url = process.env.VITE_SUPABASE_URL ?? process.env.SUPABASE_URL ?? "";
22
+ const anonKey = process.env.VITE_SUPABASE_ANON_KEY ?? process.env.SUPABASE_ANON_KEY ?? "";
23
+ const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE ?? process.env.SUPABASE_SERVICE_ROLE_KEY;
24
+ if (!url || !anonKey)
25
+ throw new Error("SUPABASE_URL and SUPABASE_ANON_KEY must be set");
26
+ return { url, anonKey, serviceRoleKey };
27
+ }
28
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;AAQA,8CAKC;AAED,4CAKC;AAED,sCAOC;AA7BD,uDAA0E;AAQ1E,SAAgB,iBAAiB,CAAC,MAAsB;IACtD,IAAI,CAAC,MAAM,CAAC,cAAc;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACxF,OAAO,IAAA,0BAAY,EAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,cAAc,EAAE;QACrD,IAAI,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE;KACzD,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,gBAAgB,CAAC,MAAsB,EAAE,WAAmB;IAC1E,OAAO,IAAA,0BAAY,EAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE;QAC9C,IAAI,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE;QACxD,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,WAAW,EAAE,EAAE,EAAE;KAChE,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,aAAa;IAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;IAC5E,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;IAC1F,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;IAElG,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACxF,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1C,CAAC"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { createAdminClient, createUserClient, configFromEnv } from "./client";
2
+ export type { SupabaseConfig } from "./client";
3
+ export { authenticateToken, extractBearerToken, requireAuth } from "./auth";
4
+ export type { AuthenticatedUser, AuthResult } from "./auth";
5
+ //# 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,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9E,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC5E,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC"}
package/lib/index.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requireAuth = exports.extractBearerToken = exports.authenticateToken = exports.configFromEnv = exports.createUserClient = exports.createAdminClient = void 0;
4
+ var client_1 = require("./client");
5
+ Object.defineProperty(exports, "createAdminClient", { enumerable: true, get: function () { return client_1.createAdminClient; } });
6
+ Object.defineProperty(exports, "createUserClient", { enumerable: true, get: function () { return client_1.createUserClient; } });
7
+ Object.defineProperty(exports, "configFromEnv", { enumerable: true, get: function () { return client_1.configFromEnv; } });
8
+ var auth_1 = require("./auth");
9
+ Object.defineProperty(exports, "authenticateToken", { enumerable: true, get: function () { return auth_1.authenticateToken; } });
10
+ Object.defineProperty(exports, "extractBearerToken", { enumerable: true, get: function () { return auth_1.extractBearerToken; } });
11
+ Object.defineProperty(exports, "requireAuth", { enumerable: true, get: function () { return auth_1.requireAuth; } });
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAA8E;AAArE,2GAAA,iBAAiB,OAAA;AAAE,0GAAA,gBAAgB,OAAA;AAAE,uGAAA,aAAa,OAAA;AAG3D,+BAA4E;AAAnE,yGAAA,iBAAiB,OAAA;AAAE,0GAAA,kBAAkB,OAAA;AAAE,mGAAA,WAAW,OAAA"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@aethex.os/supabase",
3
+ "version": "1.0.0",
4
+ "description": "Supabase client factories and Express auth middleware — admin client, user client, and Bearer token authentication for Node.js servers",
5
+ "main": "lib/index.js",
6
+ "types": "lib/index.d.ts",
7
+ "files": [
8
+ "lib"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch"
13
+ },
14
+ "keywords": [
15
+ "supabase",
16
+ "auth",
17
+ "express",
18
+ "middleware",
19
+ "jwt",
20
+ "bearer",
21
+ "node",
22
+ "aethex"
23
+ ],
24
+ "author": "AeThex Corporation",
25
+ "license": "MIT",
26
+ "homepage": "https://aethex.dev",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/AeThex-Corporation/AeThex-OS.git",
30
+ "directory": "packages/aethex-supabase"
31
+ },
32
+ "peerDependencies": {
33
+ "@supabase/supabase-js": ">=2.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@supabase/supabase-js": "^2.0.0",
37
+ "@types/node": "^20.0.0",
38
+ "typescript": "^5.3.0"
39
+ },
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ }
43
+ }