@akirilyuk/supabase-in-memory-server 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/LICENSE +21 -0
- package/README.md +240 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +28 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/auth-memory.d.ts +40 -0
- package/dist/lib/auth-memory.d.ts.map +1 -0
- package/dist/lib/auth-memory.js +167 -0
- package/dist/lib/auth-memory.js.map +1 -0
- package/dist/lib/http-headers.d.ts +6 -0
- package/dist/lib/http-headers.d.ts.map +1 -0
- package/dist/lib/http-headers.js +14 -0
- package/dist/lib/http-headers.js.map +1 -0
- package/dist/lib/jwt.d.ts +14 -0
- package/dist/lib/jwt.d.ts.map +1 -0
- package/dist/lib/jwt.js +41 -0
- package/dist/lib/jwt.js.map +1 -0
- package/dist/lib/memory-store.d.ts +18 -0
- package/dist/lib/memory-store.d.ts.map +1 -0
- package/dist/lib/memory-store.js +34 -0
- package/dist/lib/memory-store.js.map +1 -0
- package/dist/lib/postgrest.d.ts +9 -0
- package/dist/lib/postgrest.d.ts.map +1 -0
- package/dist/lib/postgrest.js +169 -0
- package/dist/lib/postgrest.js.map +1 -0
- package/dist/lib/server-logger.d.ts +10 -0
- package/dist/lib/server-logger.d.ts.map +1 -0
- package/dist/lib/server-logger.js +36 -0
- package/dist/lib/server-logger.js.map +1 -0
- package/dist/lib/server-options.d.ts +52 -0
- package/dist/lib/server-options.d.ts.map +1 -0
- package/dist/lib/server-options.js +82 -0
- package/dist/lib/server-options.js.map +1 -0
- package/dist/lib/types.d.ts +3 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +3 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/memory-server/MemorySupabaseHttpServer.d.ts +24 -0
- package/dist/memory-server/MemorySupabaseHttpServer.d.ts.map +1 -0
- package/dist/memory-server/MemorySupabaseHttpServer.js +91 -0
- package/dist/memory-server/MemorySupabaseHttpServer.js.map +1 -0
- package/dist/memory-server/auth-routes.d.ts +3 -0
- package/dist/memory-server/auth-routes.d.ts.map +1 -0
- package/dist/memory-server/auth-routes.js +217 -0
- package/dist/memory-server/auth-routes.js.map +1 -0
- package/dist/memory-server/handler-context.d.ts +19 -0
- package/dist/memory-server/handler-context.d.ts.map +1 -0
- package/dist/memory-server/handler-context.js +3 -0
- package/dist/memory-server/handler-context.js.map +1 -0
- package/dist/memory-server/http-utils.d.ts +19 -0
- package/dist/memory-server/http-utils.d.ts.map +1 -0
- package/dist/memory-server/http-utils.js +109 -0
- package/dist/memory-server/http-utils.js.map +1 -0
- package/dist/memory-server/index.d.ts +4 -0
- package/dist/memory-server/index.d.ts.map +1 -0
- package/dist/memory-server/index.js +8 -0
- package/dist/memory-server/index.js.map +1 -0
- package/dist/memory-server/log-meta.d.ts +12 -0
- package/dist/memory-server/log-meta.d.ts.map +1 -0
- package/dist/memory-server/log-meta.js +58 -0
- package/dist/memory-server/log-meta.js.map +1 -0
- package/dist/memory-server/rest-routes.d.ts +3 -0
- package/dist/memory-server/rest-routes.d.ts.map +1 -0
- package/dist/memory-server/rest-routes.js +235 -0
- package/dist/memory-server/rest-routes.js.map +1 -0
- package/dist/memory-server/server-lifecycle.d.ts +19 -0
- package/dist/memory-server/server-lifecycle.d.ts.map +1 -0
- package/dist/memory-server/server-lifecycle.js +75 -0
- package/dist/memory-server/server-lifecycle.js.map +1 -0
- package/dist/memory-server/types.d.ts +33 -0
- package/dist/memory-server/types.d.ts.map +1 -0
- package/dist/memory-server/types.js +3 -0
- package/dist/memory-server/types.js.map +1 -0
- package/package.json +97 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 supabase-in-memory-server contributors
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# supabase-in-memory-server
|
|
2
|
+
|
|
3
|
+
npm package **`supabase-in-memory-server`** (formerly **`supabase-jest-mock`**).
|
|
4
|
+
|
|
5
|
+
In-memory HTTP server that mimics the parts of [Supabase](https://supabase.com/) that `@supabase/supabase-js` talks to: **PostgREST-style REST** (`/rest/v1/...`) and **GoTrue-style auth** (`/auth/v1/...`). Use it in tests or local tooling without a real Supabase project—similar in spirit to an embedded mock, not a separate binary.
|
|
6
|
+
|
|
7
|
+
The server is implemented as **`MemorySupabaseHttpServer`** (request pipeline, shared `MemoryStore` + `AuthMemory`). **`createMemorySupabaseServer`** starts Node’s `http.Server`, resolves listen address and keys, wires **Winston** logging, and returns a handle you can `close()`.
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- Node.js **20.9+** or **22+**
|
|
12
|
+
- Peer dependency: **`@supabase/supabase-js` ^2**
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install supabase-in-memory-server @supabase/supabase-js
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick start (programmatic)
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { createClient } from '@supabase/supabase-js';
|
|
24
|
+
import {
|
|
25
|
+
createMemorySupabaseServer,
|
|
26
|
+
applyMemorySupabaseEnvToProcess,
|
|
27
|
+
} from 'supabase-in-memory-server';
|
|
28
|
+
|
|
29
|
+
const srv = await createMemorySupabaseServer({ useEnv: false });
|
|
30
|
+
|
|
31
|
+
// Optional: expose the same values Supabase apps expect in process.env
|
|
32
|
+
applyMemorySupabaseEnvToProcess(srv);
|
|
33
|
+
|
|
34
|
+
const anon = createClient(srv.url, srv.anonKey, {
|
|
35
|
+
auth: { persistSession: false, autoRefreshToken: false },
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const { error } = await anon.from('todos').insert({ id: 1, title: 'Buy milk' }).select();
|
|
39
|
+
// ...
|
|
40
|
+
|
|
41
|
+
await srv.close();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Convenience: server + anon client
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { createTestSupabaseClient } from 'supabase-in-memory-server';
|
|
48
|
+
|
|
49
|
+
const { client, url, anonKey, serviceRoleKey, store, logger, close } =
|
|
50
|
+
await createTestSupabaseClient();
|
|
51
|
+
// `client` is already createClient(url, anonKey, { auth: { persistSession: false, ... } })
|
|
52
|
+
|
|
53
|
+
await close();
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Service role (admin) client
|
|
57
|
+
|
|
58
|
+
Use the **service role** key for `auth.admin` (e.g. `listUsers`). Never expose this key in browser bundles.
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { createClient } from '@supabase/supabase-js';
|
|
62
|
+
import { createMemorySupabaseServer } from 'supabase-in-memory-server';
|
|
63
|
+
|
|
64
|
+
const srv = await createMemorySupabaseServer({ useEnv: false });
|
|
65
|
+
const admin = createClient(srv.url, srv.serviceRoleKey, {
|
|
66
|
+
auth: { persistSession: false, autoRefreshToken: false },
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const { data, error } = await admin.auth.admin.listUsers({ perPage: 50 });
|
|
70
|
+
await srv.close();
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## What you get back from the server
|
|
74
|
+
|
|
75
|
+
`createMemorySupabaseServer` / `startInMemorySupabaseServer` resolve to an object with:
|
|
76
|
+
|
|
77
|
+
| Field | Description |
|
|
78
|
+
| -------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
79
|
+
| **`url`** | Base URL, e.g. `http://127.0.0.1:<port>` |
|
|
80
|
+
| **`anonKey`** | Anon API key (maps to `SUPABASE_ANON_KEY`) |
|
|
81
|
+
| **`serviceRoleKey`** | Service role / admin key (maps to `SUPABASE_SERVICE_ROLE_KEY`) |
|
|
82
|
+
| **`supabaseKey`** | Same as `anonKey` (legacy name) |
|
|
83
|
+
| **`store`** | `MemoryStore` — in-memory tables for REST |
|
|
84
|
+
| **`auth`** | `AuthMemory` — in-memory users and sessions |
|
|
85
|
+
| **`server`** | Node `http.Server` |
|
|
86
|
+
| **`logger`** | Winston `Logger` — lifecycle + per-request logs (see **Logging** below) |
|
|
87
|
+
| **`close()`** | Stops the server and clears auth state (tables are **not** cleared unless you call `store.clearAll()`) |
|
|
88
|
+
|
|
89
|
+
## Logging and debug mode
|
|
90
|
+
|
|
91
|
+
Logging uses **Winston**. Each HTTP request gets a **10-character hex `requestId`**. In **debug** mode you will see:
|
|
92
|
+
|
|
93
|
+
- **`Incoming request`** — `{ requestId, method, path, query }` when the request enters the pipeline (including **OPTIONS**).
|
|
94
|
+
- **`Request finished`** — `{ requestId, method, path }` in a **`finally`** block when handling completes (success, early return, or error).
|
|
95
|
+
- Handler-level **`debug`** lines for auth and REST (correlated via a **child logger** that carries `requestId` on every line).
|
|
96
|
+
|
|
97
|
+
**Options**
|
|
98
|
+
|
|
99
|
+
| Setting | Effect |
|
|
100
|
+
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
101
|
+
| **`debug: true`** in server options | Root log level `debug`: full request/handler detail. |
|
|
102
|
+
| **`debug: false`** (default) | Level `info`: listen/close and **`error`** / **`warn`**; routine traffic stays at `debug` (hidden unless you enable debug). |
|
|
103
|
+
| **`SUPABASE_JEST_MOCK_DEBUG`** | If `1`, `true`, or `yes`, sets `debug` when `useEnv` is not `false`. |
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
await createMemorySupabaseServer({ useEnv: false, debug: true });
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
To silence logs in noisy tests: **`srv.logger.silent = true`**.
|
|
110
|
+
|
|
111
|
+
You can also build a matching logger with **`createMemorySupabaseLogger(debug)`** if you construct **`MemorySupabaseHttpServer`** yourself (advanced).
|
|
112
|
+
|
|
113
|
+
## Environment variables
|
|
114
|
+
|
|
115
|
+
By default (**`useEnv` is not `false`**), options are merged with the environment: env first, then explicit options override.
|
|
116
|
+
|
|
117
|
+
| Variable | Purpose |
|
|
118
|
+
| ------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
119
|
+
| **`SUPABASE_URL`** | If set, **host** and **port** for listening are taken from this URL (e.g. `http://127.0.0.1:54321`). |
|
|
120
|
+
| **`SUPABASE_JEST_MOCK_HOST`** | Overrides listen hostname after URL parsing. |
|
|
121
|
+
| **`SUPABASE_JEST_MOCK_PORT`** | Overrides listen port after URL parsing. Use `0` for an ephemeral port. |
|
|
122
|
+
| **`SUPABASE_ANON_KEY`** | Anon key used as the `apikey` header for the public client. |
|
|
123
|
+
| **`SUPABASE_SERVICE_ROLE_KEY`** | Service role key for admin operations. |
|
|
124
|
+
| **`SUPABASE_JEST_MOCK_DEBUG`** | Enables verbose **`debug`** logging (`1`, `true`, or `yes`). |
|
|
125
|
+
|
|
126
|
+
After the server is running, you can sync **`process.env`** to the **actual** URL and keys (recommended for apps that only read env):
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import {
|
|
130
|
+
createMemorySupabaseServer,
|
|
131
|
+
applyMemorySupabaseEnvToProcess,
|
|
132
|
+
} from 'supabase-in-memory-server';
|
|
133
|
+
|
|
134
|
+
const srv = await createMemorySupabaseServer();
|
|
135
|
+
applyMemorySupabaseEnvToProcess(srv);
|
|
136
|
+
// process.env.SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## CLI
|
|
140
|
+
|
|
141
|
+
From the package install:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npx supabase-in-memory-server
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- Starts the in-memory server (honors the same env vars as above).
|
|
148
|
+
- Writes `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_SERVICE_ROLE_KEY` into **`process.env`**.
|
|
149
|
+
- Prints a JSON object with those three keys to **stdout**.
|
|
150
|
+
- Logs the listen URL to **stderr** (and Winston lifecycle lines unless silenced).
|
|
151
|
+
- Exit with **Ctrl+C** (SIGINT) or SIGTERM.
|
|
152
|
+
|
|
153
|
+
## Authentication and API keys
|
|
154
|
+
|
|
155
|
+
- Every request must include header **`apikey`** equal to either **`anonKey`** or **`serviceRoleKey`**. Missing or wrong key → **401**.
|
|
156
|
+
- **`GET /auth/v1/admin/users`** requires the **service role** key (or `Authorization: Bearer <serviceRoleKey>`).
|
|
157
|
+
|
|
158
|
+
Implemented auth routes include: **signup** (email or phone), **token** (`grant_type=password` and `refresh_token`), **logout**, **get user** (`GET /auth/v1/user`), and **admin list users** (paginated). JWTs used by the mock are **unsigned** test tokens—do not use for real security.
|
|
159
|
+
|
|
160
|
+
## REST (PostgREST-shaped)
|
|
161
|
+
|
|
162
|
+
Supported on **`/rest/v1/:table`**: insert, upsert (via `Prefer: resolution=merge-duplicates` / `ignore-duplicates`), select with common filters (`eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `is`, `in`), `order`, `limit` / `offset`, update, delete, `Prefer: return=representation`, `Prefer: count=…`, and `Accept: application/vnd.pgrst.object+json` for `.single()` / `.maybeSingle()`-style behavior.
|
|
163
|
+
|
|
164
|
+
With **`Prefer: return=representation`**, **PATCH** returns the updated rows in the body: one row as a single JSON **object**, multiple rows as a JSON **array** (same convention as **POST** insert).
|
|
165
|
+
|
|
166
|
+
There is **no** RLS, **no** Realtime WebSocket, **no** Storage, **no** Edge Functions, **no** `/rest/v1/rpc/...`, and **no** full PostgREST operator set (see **TODO** below).
|
|
167
|
+
|
|
168
|
+
## API reference (exports)
|
|
169
|
+
|
|
170
|
+
The main entry is **`supabase-in-memory-server`** (`dist/index.js`). Notable exports:
|
|
171
|
+
|
|
172
|
+
- **`createMemorySupabaseServer`**, **`startInMemorySupabaseServer`** — start the HTTP server.
|
|
173
|
+
- **`createTestSupabaseClient`** — server + `SupabaseClient` with anon key.
|
|
174
|
+
- **`applyMemorySupabaseEnvToProcess`** — set `SUPABASE_*` env from a running server.
|
|
175
|
+
- **`MemorySupabaseHttpServer`** — HTTP app class (advanced: custom lifecycle, tests).
|
|
176
|
+
- **`createMemorySupabaseLogger`** — Winston factory aligned with the server’s log format.
|
|
177
|
+
- **`readMemorySupabaseServerEnv`**, **`resolveMemorySupabaseServerOptions`**, **`generateDefaultProjectKeys`**, **`MemorySupabaseServerInputOptions`** — configuration helpers.
|
|
178
|
+
- **`MemorySupabaseServer`**, **`MemorySupabaseServerOptions`**, **`MemoryStore`**, **`AuthMemory`**, **`JsonRecord`**, etc.
|
|
179
|
+
|
|
180
|
+
See TSDoc on those symbols in the source for details.
|
|
181
|
+
|
|
182
|
+
## TODO (toward a fuller in-memory Supabase mock)
|
|
183
|
+
|
|
184
|
+
This package intentionally covers a **small, test-friendly** slice of Supabase. A **full** in-memory mock would still need (non-exhaustive):
|
|
185
|
+
|
|
186
|
+
### Auth (GoTrue)
|
|
187
|
+
|
|
188
|
+
- [ ] OAuth / SSO providers, **magic links**, **OTP**, and phone SMS flows.
|
|
189
|
+
- [ ] Additional **`auth.admin`** APIs: `deleteUser`, `updateUserById`, `inviteUserByEmail`, `generateLink`, etc.
|
|
190
|
+
- [ ] **MFA** (TOTP, WebAuthn) and step-up semantics.
|
|
191
|
+
- [ ] **Session management**: list/revoke sessions, refresh rotation edge cases matching production.
|
|
192
|
+
- [ ] **Password recovery** / email change / user verification flows.
|
|
193
|
+
- [ ] Stricter alignment with GoTrue error payloads, status codes, and headers.
|
|
194
|
+
- [ ] Optional **JWT signing/verification** matching real projects (currently test-oriented tokens).
|
|
195
|
+
|
|
196
|
+
### REST / PostgREST
|
|
197
|
+
|
|
198
|
+
- [ ] **RPC**: `POST /rest/v1/rpc/:function` (and client `.rpc()`).
|
|
199
|
+
- [ ] **Embedded resources** / foreign-table `select` shapes (`profiles(*)`).
|
|
200
|
+
- [ ] More **filter operators** (`like`, `ilike`, `fts`, `cs`, `cd`, `@>`, `range`, `or`, `and`, `not`, etc.).
|
|
201
|
+
- [ ] **`columns=`**, default values, generated columns behavior (as far as in-memory JSON allows).
|
|
202
|
+
- [ ] **Schemas** / multiple schemas, views, and table exposure rules.
|
|
203
|
+
- [ ] **Row Level Security** simulation (policies per role / JWT claims).
|
|
204
|
+
- [ ] **Transactions** or batch semantics if clients rely on them.
|
|
205
|
+
- [ ] Closer **error codes** and **Prefer** / **Content-Range** behavior vs real PostgREST.
|
|
206
|
+
|
|
207
|
+
### Realtime
|
|
208
|
+
|
|
209
|
+
- [ ] **WebSocket** server and **`postgres_changes`** (and channel/auth parity with Supabase Realtime).
|
|
210
|
+
|
|
211
|
+
### Storage
|
|
212
|
+
|
|
213
|
+
- [ ] **S3-compatible** or Supabase Storage REST: buckets, objects, signed URLs, MIME limits.
|
|
214
|
+
|
|
215
|
+
### Edge Functions & platform
|
|
216
|
+
|
|
217
|
+
- [ ] **Edge Functions** invoke path or local stub.
|
|
218
|
+
- [ ] **Database webhooks**, **pg_cron**, and other backend-only features (usually out of scope for a pure HTTP mock).
|
|
219
|
+
|
|
220
|
+
### Developer experience
|
|
221
|
+
|
|
222
|
+
- [ ] Optional **OpenAPI** / schema endpoint mimicking PostgREST.
|
|
223
|
+
- [ ] **Snapshot / fixture** helpers for common test scenarios.
|
|
224
|
+
|
|
225
|
+
Contributions that close items above are welcome; keep the default footprint small so Jest/CI stays fast.
|
|
226
|
+
|
|
227
|
+
## Development
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
npm install
|
|
231
|
+
npm run build # emit dist/
|
|
232
|
+
npm run typecheck
|
|
233
|
+
npm run lint
|
|
234
|
+
npm run format:check
|
|
235
|
+
npm test # integration + e2e tests
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
[MIT](LICENSE)
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
/**
|
|
5
|
+
* CLI entry (`supabase-in-memory-server` bin): starts the in-memory server, applies `SUPABASE_*` to `process.env`,
|
|
6
|
+
* prints JSON keys to stdout, and keeps the process alive until SIGINT/SIGTERM.
|
|
7
|
+
*/
|
|
8
|
+
const index_js_1 = require("./index.js");
|
|
9
|
+
async function main() {
|
|
10
|
+
const srv = await (0, index_js_1.startInMemorySupabaseServer)();
|
|
11
|
+
(0, index_js_1.applyMemorySupabaseEnvToProcess)(srv);
|
|
12
|
+
console.log(JSON.stringify({
|
|
13
|
+
SUPABASE_URL: srv.url,
|
|
14
|
+
SUPABASE_ANON_KEY: srv.anonKey,
|
|
15
|
+
SUPABASE_SERVICE_ROLE_KEY: srv.serviceRoleKey,
|
|
16
|
+
}, null, 2));
|
|
17
|
+
console.error(`In-memory Supabase listening on ${srv.url} (Ctrl+C to stop)`);
|
|
18
|
+
const shutdown = () => {
|
|
19
|
+
void srv.close().then(() => process.exit(0), () => process.exit(1));
|
|
20
|
+
};
|
|
21
|
+
process.on('SIGINT', shutdown);
|
|
22
|
+
process.on('SIGTERM', shutdown);
|
|
23
|
+
}
|
|
24
|
+
void main().catch((e) => {
|
|
25
|
+
console.error(e);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
});
|
|
28
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AACA;;;GAGG;AACH,yCAA0F;AAE1F,KAAK,UAAU,IAAI;IACjB,MAAM,GAAG,GAAG,MAAM,IAAA,sCAA2B,GAAE,CAAC;IAChD,IAAA,0CAA+B,EAAC,GAAG,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ;QACE,YAAY,EAAE,GAAG,CAAC,GAAG;QACrB,iBAAiB,EAAE,GAAG,CAAC,OAAO;QAC9B,yBAAyB,EAAE,GAAG,CAAC,cAAc;KAC9C,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;IACF,OAAO,CAAC,KAAK,CAAC,mCAAmC,GAAG,CAAC,GAAG,mBAAmB,CAAC,CAAC;IAE7E,MAAM,QAAQ,GAAG,GAAS,EAAE;QAC1B,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,CACnB,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EACrB,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CACtB,CAAC;IACJ,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE;IAC/B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry for **supabase-in-memory-server**: in-memory Supabase-shaped HTTP server and test helpers.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import { type SupabaseClient } from '@supabase/supabase-js';
|
|
7
|
+
import { createMemorySupabaseServer, MemorySupabaseHttpServer, type MemorySupabaseServer, type MemorySupabaseServerOptions } from './memory-server/index.js';
|
|
8
|
+
export { AuthMemory, type MemorySession, type MemoryUser } from './lib/auth-memory.js';
|
|
9
|
+
export { getIncomingHeader } from './lib/http-headers.js';
|
|
10
|
+
export { MemoryStore } from './lib/memory-store.js';
|
|
11
|
+
export { createMemorySupabaseLogger } from './lib/server-logger.js';
|
|
12
|
+
export { generateDefaultProjectKeys, type MemorySupabaseServerInputOptions, readMemorySupabaseServerEnv, resolveMemorySupabaseServerOptions, } from './lib/server-options.js';
|
|
13
|
+
export type { JsonRecord } from './lib/types.js';
|
|
14
|
+
export { createMemorySupabaseServer, MemorySupabaseHttpServer, type MemorySupabaseServer, type MemorySupabaseServerOptions, };
|
|
15
|
+
/** Running server handle plus a {@link SupabaseClient} configured with the anon key. */
|
|
16
|
+
export type TestSupabaseBundle = MemorySupabaseServer & {
|
|
17
|
+
client: SupabaseClient;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Writes the running server URL and keys into `process.env` so tools that read
|
|
21
|
+
* `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_SERVICE_ROLE_KEY` pick them up.
|
|
22
|
+
*
|
|
23
|
+
* @param srv - A server returned from {@link createMemorySupabaseServer} or {@link startInMemorySupabaseServer}.
|
|
24
|
+
*/
|
|
25
|
+
export declare function applyMemorySupabaseEnvToProcess(srv: MemorySupabaseServer): void;
|
|
26
|
+
/**
|
|
27
|
+
* Starts the in-memory HTTP server (merging env via `readMemorySupabaseServerEnv` unless `useEnv: false`).
|
|
28
|
+
* Alias for {@link createMemorySupabaseServer}.
|
|
29
|
+
*/
|
|
30
|
+
export declare function startInMemorySupabaseServer(options?: MemorySupabaseServerOptions): Promise<MemorySupabaseServer>;
|
|
31
|
+
/**
|
|
32
|
+
* Starts the in-memory HTTP server and returns a real `SupabaseClient` using the **anon** key.
|
|
33
|
+
* Disables auth persistence and token auto-refresh (typical for tests).
|
|
34
|
+
*
|
|
35
|
+
* @param options - Same as {@link createMemorySupabaseServer}.
|
|
36
|
+
* @returns Server fields plus `client`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createTestSupabaseClient(options?: MemorySupabaseServerOptions): Promise<TestSupabaseBundle>;
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EACjC,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,UAAU,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EACL,0BAA0B,EAC1B,KAAK,gCAAgC,EACrC,2BAA2B,EAC3B,kCAAkC,GACnC,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,GACjC,CAAC;AAEF,wFAAwF;AACxF,MAAM,MAAM,kBAAkB,GAAG,oBAAoB,GAAG;IACtD,MAAM,EAAE,cAAc,CAAC;CACxB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,oBAAoB,GAAG,IAAI,CAI/E;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,CAAC,EAAE,2BAA2B,GACpC,OAAO,CAAC,oBAAoB,CAAC,CAE/B;AAED;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,CAAC,EAAE,2BAA2B,GACpC,OAAO,CAAC,kBAAkB,CAAC,CAS7B"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MemorySupabaseHttpServer = exports.createMemorySupabaseServer = exports.resolveMemorySupabaseServerOptions = exports.readMemorySupabaseServerEnv = exports.generateDefaultProjectKeys = exports.createMemorySupabaseLogger = exports.MemoryStore = exports.getIncomingHeader = exports.AuthMemory = void 0;
|
|
4
|
+
exports.applyMemorySupabaseEnvToProcess = applyMemorySupabaseEnvToProcess;
|
|
5
|
+
exports.startInMemorySupabaseServer = startInMemorySupabaseServer;
|
|
6
|
+
exports.createTestSupabaseClient = createTestSupabaseClient;
|
|
7
|
+
/**
|
|
8
|
+
* Public entry for **supabase-in-memory-server**: in-memory Supabase-shaped HTTP server and test helpers.
|
|
9
|
+
*
|
|
10
|
+
* @packageDocumentation
|
|
11
|
+
*/
|
|
12
|
+
const supabase_js_1 = require("@supabase/supabase-js");
|
|
13
|
+
const index_js_1 = require("./memory-server/index.js");
|
|
14
|
+
Object.defineProperty(exports, "createMemorySupabaseServer", { enumerable: true, get: function () { return index_js_1.createMemorySupabaseServer; } });
|
|
15
|
+
Object.defineProperty(exports, "MemorySupabaseHttpServer", { enumerable: true, get: function () { return index_js_1.MemorySupabaseHttpServer; } });
|
|
16
|
+
var auth_memory_js_1 = require("./lib/auth-memory.js");
|
|
17
|
+
Object.defineProperty(exports, "AuthMemory", { enumerable: true, get: function () { return auth_memory_js_1.AuthMemory; } });
|
|
18
|
+
var http_headers_js_1 = require("./lib/http-headers.js");
|
|
19
|
+
Object.defineProperty(exports, "getIncomingHeader", { enumerable: true, get: function () { return http_headers_js_1.getIncomingHeader; } });
|
|
20
|
+
var memory_store_js_1 = require("./lib/memory-store.js");
|
|
21
|
+
Object.defineProperty(exports, "MemoryStore", { enumerable: true, get: function () { return memory_store_js_1.MemoryStore; } });
|
|
22
|
+
var server_logger_js_1 = require("./lib/server-logger.js");
|
|
23
|
+
Object.defineProperty(exports, "createMemorySupabaseLogger", { enumerable: true, get: function () { return server_logger_js_1.createMemorySupabaseLogger; } });
|
|
24
|
+
var server_options_js_1 = require("./lib/server-options.js");
|
|
25
|
+
Object.defineProperty(exports, "generateDefaultProjectKeys", { enumerable: true, get: function () { return server_options_js_1.generateDefaultProjectKeys; } });
|
|
26
|
+
Object.defineProperty(exports, "readMemorySupabaseServerEnv", { enumerable: true, get: function () { return server_options_js_1.readMemorySupabaseServerEnv; } });
|
|
27
|
+
Object.defineProperty(exports, "resolveMemorySupabaseServerOptions", { enumerable: true, get: function () { return server_options_js_1.resolveMemorySupabaseServerOptions; } });
|
|
28
|
+
/**
|
|
29
|
+
* Writes the running server URL and keys into `process.env` so tools that read
|
|
30
|
+
* `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_SERVICE_ROLE_KEY` pick them up.
|
|
31
|
+
*
|
|
32
|
+
* @param srv - A server returned from {@link createMemorySupabaseServer} or {@link startInMemorySupabaseServer}.
|
|
33
|
+
*/
|
|
34
|
+
function applyMemorySupabaseEnvToProcess(srv) {
|
|
35
|
+
process.env.SUPABASE_URL = srv.url;
|
|
36
|
+
process.env.SUPABASE_ANON_KEY = srv.anonKey;
|
|
37
|
+
process.env.SUPABASE_SERVICE_ROLE_KEY = srv.serviceRoleKey;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Starts the in-memory HTTP server (merging env via `readMemorySupabaseServerEnv` unless `useEnv: false`).
|
|
41
|
+
* Alias for {@link createMemorySupabaseServer}.
|
|
42
|
+
*/
|
|
43
|
+
async function startInMemorySupabaseServer(options) {
|
|
44
|
+
return (0, index_js_1.createMemorySupabaseServer)(options);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Starts the in-memory HTTP server and returns a real `SupabaseClient` using the **anon** key.
|
|
48
|
+
* Disables auth persistence and token auto-refresh (typical for tests).
|
|
49
|
+
*
|
|
50
|
+
* @param options - Same as {@link createMemorySupabaseServer}.
|
|
51
|
+
* @returns Server fields plus `client`.
|
|
52
|
+
*/
|
|
53
|
+
async function createTestSupabaseClient(options) {
|
|
54
|
+
const srv = await (0, index_js_1.createMemorySupabaseServer)(options);
|
|
55
|
+
const client = (0, supabase_js_1.createClient)(srv.url, srv.anonKey, {
|
|
56
|
+
auth: {
|
|
57
|
+
persistSession: false,
|
|
58
|
+
autoRefreshToken: false,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
return { ...srv, client };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AA2CA,0EAIC;AAMD,kEAIC;AASD,4DAWC;AA7ED;;;;GAIG;AACH,uDAA0E;AAE1E,uDAKkC;AAchC,2GAlBA,qCAA0B,OAkBA;AAC1B,yGAlBA,mCAAwB,OAkBA;AAb1B,uDAAuF;AAA9E,4GAAA,UAAU,OAAA;AACnB,yDAA0D;AAAjD,oHAAA,iBAAiB,OAAA;AAC1B,yDAAoD;AAA3C,8GAAA,WAAW,OAAA;AACpB,2DAAoE;AAA3D,8HAAA,0BAA0B,OAAA;AACnC,6DAKiC;AAJ/B,+HAAA,0BAA0B,OAAA;AAE1B,gIAAA,2BAA2B,OAAA;AAC3B,uIAAA,kCAAkC,OAAA;AAepC;;;;;GAKG;AACH,SAAgB,+BAA+B,CAAC,GAAyB;IACvE,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,GAAG,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,GAAG,CAAC,OAAO,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,yBAAyB,GAAG,GAAG,CAAC,cAAc,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,2BAA2B,CAC/C,OAAqC;IAErC,OAAO,IAAA,qCAA0B,EAAC,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,wBAAwB,CAC5C,OAAqC;IAErC,MAAM,GAAG,GAAG,MAAM,IAAA,qCAA0B,EAAC,OAAO,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,IAAA,0BAAY,EAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE;QAChD,IAAI,EAAE;YACJ,cAAc,EAAE,KAAK;YACrB,gBAAgB,EAAE,KAAK;SACxB;KACF,CAAC,CAAC;IACH,OAAO,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface MemoryUser {
|
|
2
|
+
id: string;
|
|
3
|
+
aud: string;
|
|
4
|
+
role: string;
|
|
5
|
+
email?: string;
|
|
6
|
+
phone?: string;
|
|
7
|
+
email_confirmed_at?: string;
|
|
8
|
+
phone_confirmed_at?: string;
|
|
9
|
+
app_metadata?: Record<string, unknown>;
|
|
10
|
+
user_metadata?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export interface MemorySession {
|
|
13
|
+
access_token: string;
|
|
14
|
+
refresh_token: string;
|
|
15
|
+
token_type: string;
|
|
16
|
+
expires_in: number;
|
|
17
|
+
expires_at: number;
|
|
18
|
+
user: MemoryUser;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* In-memory auth backing store: email/phone sign-up and sign-in, refresh tokens, JWT-shaped access tokens,
|
|
22
|
+
* and a user list for admin APIs. Not persisted; cleared when the HTTP server closes.
|
|
23
|
+
*/
|
|
24
|
+
export declare class AuthMemory {
|
|
25
|
+
private readonly byEmail;
|
|
26
|
+
private readonly byPhone;
|
|
27
|
+
private readonly refreshToUserId;
|
|
28
|
+
private sessionTokens;
|
|
29
|
+
signUpEmail(email: string, password: string, metadata: Record<string, unknown>): MemorySession;
|
|
30
|
+
signInEmail(email: string, password: string): MemorySession;
|
|
31
|
+
signUpPhone(phone: string, password: string, metadata: Record<string, unknown>): MemorySession;
|
|
32
|
+
signInPhone(phone: string, password: string): MemorySession;
|
|
33
|
+
refreshSession(refreshToken: string): MemorySession;
|
|
34
|
+
getUserFromAccessToken(accessToken: string): MemoryUser;
|
|
35
|
+
private findUserById;
|
|
36
|
+
/** All registered users (for admin list). */
|
|
37
|
+
listUsers(): MemoryUser[];
|
|
38
|
+
clear(): void;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=auth-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-memory.d.ts","sourceRoot":"","sources":["../../src/lib/auth-memory.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,UAAU,CAAC;CAClB;AAOD;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA6B;IAE7D,OAAO,CAAC,aAAa;IAsBrB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa;IAqB9F,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa;IAa3D,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa;IAoB9F,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa;IAY3D,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa;IAmBnD,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU;IAiBvD,OAAO,CAAC,YAAY;IAUpB,6CAA6C;IAC7C,SAAS,IAAI,UAAU,EAAE;IAgBzB,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthMemory = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const jwt_js_1 = require("./jwt.js");
|
|
6
|
+
/**
|
|
7
|
+
* In-memory auth backing store: email/phone sign-up and sign-in, refresh tokens, JWT-shaped access tokens,
|
|
8
|
+
* and a user list for admin APIs. Not persisted; cleared when the HTTP server closes.
|
|
9
|
+
*/
|
|
10
|
+
class AuthMemory {
|
|
11
|
+
byEmail = new Map();
|
|
12
|
+
byPhone = new Map();
|
|
13
|
+
refreshToUserId = new Map();
|
|
14
|
+
sessionTokens(user, refreshToken) {
|
|
15
|
+
const now = Math.floor(Date.now() / 1000);
|
|
16
|
+
const expiresIn = 3600;
|
|
17
|
+
const access_token = (0, jwt_js_1.encodeMemoryJwt)({
|
|
18
|
+
sub: user.id,
|
|
19
|
+
email: user.email,
|
|
20
|
+
phone: user.phone,
|
|
21
|
+
role: user.role,
|
|
22
|
+
aud: user.aud,
|
|
23
|
+
exp: now + expiresIn,
|
|
24
|
+
iat: now,
|
|
25
|
+
});
|
|
26
|
+
return {
|
|
27
|
+
access_token,
|
|
28
|
+
refresh_token: refreshToken,
|
|
29
|
+
token_type: 'bearer',
|
|
30
|
+
expires_in: expiresIn,
|
|
31
|
+
expires_at: now + expiresIn,
|
|
32
|
+
user,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
signUpEmail(email, password, metadata) {
|
|
36
|
+
const key = email.toLowerCase();
|
|
37
|
+
if (this.byEmail.has(key)) {
|
|
38
|
+
const err = new Error('User already registered');
|
|
39
|
+
err.status = 422;
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
const user = {
|
|
43
|
+
id: (0, node_crypto_1.randomUUID)(),
|
|
44
|
+
aud: 'authenticated',
|
|
45
|
+
role: 'authenticated',
|
|
46
|
+
email,
|
|
47
|
+
email_confirmed_at: new Date().toISOString(),
|
|
48
|
+
user_metadata: metadata,
|
|
49
|
+
};
|
|
50
|
+
this.byEmail.set(key, { user, password });
|
|
51
|
+
const refresh = (0, jwt_js_1.randomToken)();
|
|
52
|
+
this.refreshToUserId.set(refresh, user.id);
|
|
53
|
+
return this.sessionTokens({ ...user }, refresh);
|
|
54
|
+
}
|
|
55
|
+
signInEmail(email, password) {
|
|
56
|
+
const key = email.toLowerCase();
|
|
57
|
+
const rec = this.byEmail.get(key);
|
|
58
|
+
if (rec?.password !== password) {
|
|
59
|
+
const err = new Error('Invalid login credentials');
|
|
60
|
+
err.status = 400;
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
63
|
+
const refresh = (0, jwt_js_1.randomToken)();
|
|
64
|
+
this.refreshToUserId.set(refresh, rec.user.id);
|
|
65
|
+
return this.sessionTokens({ ...rec.user }, refresh);
|
|
66
|
+
}
|
|
67
|
+
signUpPhone(phone, password, metadata) {
|
|
68
|
+
if (this.byPhone.has(phone)) {
|
|
69
|
+
const err = new Error('User already registered');
|
|
70
|
+
err.status = 422;
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
const user = {
|
|
74
|
+
id: (0, node_crypto_1.randomUUID)(),
|
|
75
|
+
aud: 'authenticated',
|
|
76
|
+
role: 'authenticated',
|
|
77
|
+
phone,
|
|
78
|
+
phone_confirmed_at: new Date().toISOString(),
|
|
79
|
+
user_metadata: metadata,
|
|
80
|
+
};
|
|
81
|
+
this.byPhone.set(phone, { user, password });
|
|
82
|
+
const refresh = (0, jwt_js_1.randomToken)();
|
|
83
|
+
this.refreshToUserId.set(refresh, user.id);
|
|
84
|
+
return this.sessionTokens({ ...user }, refresh);
|
|
85
|
+
}
|
|
86
|
+
signInPhone(phone, password) {
|
|
87
|
+
const rec = this.byPhone.get(phone);
|
|
88
|
+
if (rec?.password !== password) {
|
|
89
|
+
const err = new Error('Invalid login credentials');
|
|
90
|
+
err.status = 400;
|
|
91
|
+
throw err;
|
|
92
|
+
}
|
|
93
|
+
const refresh = (0, jwt_js_1.randomToken)();
|
|
94
|
+
this.refreshToUserId.set(refresh, rec.user.id);
|
|
95
|
+
return this.sessionTokens({ ...rec.user }, refresh);
|
|
96
|
+
}
|
|
97
|
+
refreshSession(refreshToken) {
|
|
98
|
+
const userId = this.refreshToUserId.get(refreshToken);
|
|
99
|
+
if (!userId) {
|
|
100
|
+
const err = new Error('Invalid refresh token');
|
|
101
|
+
err.status = 400;
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
this.refreshToUserId.delete(refreshToken);
|
|
105
|
+
const user = this.findUserById(userId);
|
|
106
|
+
if (!user) {
|
|
107
|
+
const err = new Error('User not found');
|
|
108
|
+
err.status = 400;
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
const refresh = (0, jwt_js_1.randomToken)();
|
|
112
|
+
this.refreshToUserId.set(refresh, user.id);
|
|
113
|
+
return this.sessionTokens({ ...user }, refresh);
|
|
114
|
+
}
|
|
115
|
+
getUserFromAccessToken(accessToken) {
|
|
116
|
+
const payload = (0, jwt_js_1.decodeJwtPayload)(accessToken);
|
|
117
|
+
const sub = payload?.sub;
|
|
118
|
+
if (typeof sub !== 'string') {
|
|
119
|
+
const err = new Error('Invalid JWT');
|
|
120
|
+
err.status = 403;
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
const user = this.findUserById(sub);
|
|
124
|
+
if (!user) {
|
|
125
|
+
const err = new Error('User not found');
|
|
126
|
+
err.status = 403;
|
|
127
|
+
throw err;
|
|
128
|
+
}
|
|
129
|
+
return { ...user };
|
|
130
|
+
}
|
|
131
|
+
findUserById(id) {
|
|
132
|
+
for (const { user } of this.byEmail.values()) {
|
|
133
|
+
if (user.id === id)
|
|
134
|
+
return user;
|
|
135
|
+
}
|
|
136
|
+
for (const { user } of this.byPhone.values()) {
|
|
137
|
+
if (user.id === id)
|
|
138
|
+
return user;
|
|
139
|
+
}
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
/** All registered users (for admin list). */
|
|
143
|
+
listUsers() {
|
|
144
|
+
const seen = new Set();
|
|
145
|
+
const out = [];
|
|
146
|
+
for (const { user } of this.byEmail.values()) {
|
|
147
|
+
if (seen.has(user.id))
|
|
148
|
+
continue;
|
|
149
|
+
seen.add(user.id);
|
|
150
|
+
out.push({ ...user });
|
|
151
|
+
}
|
|
152
|
+
for (const { user } of this.byPhone.values()) {
|
|
153
|
+
if (seen.has(user.id))
|
|
154
|
+
continue;
|
|
155
|
+
seen.add(user.id);
|
|
156
|
+
out.push({ ...user });
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
clear() {
|
|
161
|
+
this.byEmail.clear();
|
|
162
|
+
this.byPhone.clear();
|
|
163
|
+
this.refreshToUserId.clear();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.AuthMemory = AuthMemory;
|
|
167
|
+
//# sourceMappingURL=auth-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-memory.js","sourceRoot":"","sources":["../../src/lib/auth-memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { IncomingMessage } from 'node:http';
|
|
2
|
+
/**
|
|
3
|
+
* Reads a request header case-insensitively; if multiple values exist, returns the first.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getIncomingHeader(req: IncomingMessage, name: string): string | undefined;
|
|
6
|
+
//# sourceMappingURL=http-headers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-headers.d.ts","sourceRoot":"","sources":["../../src/lib/http-headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKxF"}
|