{"_id":"@akirilyuk/supabase-in-memory-server","_rev":"2-3f85332ede4b223944d2e71cba19b5d7","name":"@akirilyuk/supabase-in-memory-server","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@akirilyuk/supabase-in-memory-server","version":"1.0.0","keywords":["supabase","supabase-js","supabase-mock","supabase-local","supabase-client-js","postgrest","postgrest-mock","gotrue","gotrue-mock","in-memory","in-memory-database","http-server","mock-server","fake-server","integration-testing","e2e-testing","testing","typescript","node","nodejs","cli","rest-api","auth","anon-key","service-role","winston","local-development","dev-server"],"author":{"url":"https://github.com/akirilyuk","name":"akirilyuk"},"license":"MIT","_id":"@akirilyuk/supabase-in-memory-server@1.0.0","maintainers":[{"name":"akirilyuk","email":"alexander.kiri.aa@googlemail.com"}],"homepage":"https://github.com/akirilyuk/supabase-in-memory-server#readme","bugs":{"url":"https://github.com/akirilyuk/supabase-in-memory-server/issues"},"bin":{"supabase-in-memory-server":"dist/cli.js"},"dist":{"shasum":"ccad386530364fef3e5c8a41a230acbb3d5fa5e8","tarball":"https://registry.npmjs.org/@akirilyuk/supabase-in-memory-server/-/supabase-in-memory-server-1.0.0.tgz","fileCount":79,"integrity":"sha512-DVZS8OHMRRZX2UnlLZ+G32dJoXpSKajHzI2bhehthRmdhRa8ZkyHXv86MdO93jRBKgoJaSwmu51k+u6ynXPlCQ==","signatures":[{"sig":"MEUCIQD/mk+tnMN42lwZT5aFPohI/97gg+wUToevDVdvdY0rhgIgKXFxK8wDTAT28CvMhIe6/iwO5dYQ8PBhLxo7QeM5zRo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":146926},"main":"./dist/index.js","type":"commonjs","types":"./dist/index.d.ts","engines":{"node":"^20.9.0 || >=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"63ea35e64cdf54e7156c9aa8d81430ff4a52ea3c","scripts":{"lint":"eslint .","test":"tsx --test tests/integration.test.ts tests/e2e/supabase-client.e2e.test.ts","build":"tsc -p tsconfig.build.json","clean":"rimraf dist","format":"prettier --write .","prepack":"npm run build","lint:fix":"eslint . --fix","typecheck":"tsc --noEmit","format:check":"prettier --check ."},"_npmUser":{"name":"akirilyuk","email":"alexander.kiri.aa@googlemail.com"},"repository":{"url":"git+https://github.com/akirilyuk/supabase-in-memory-server.git","type":"git"},"_npmVersion":"11.6.1","description":"In-memory HTTP server mimicking Supabase REST (PostgREST) and Auth (GoTrue) for supabase-js: local testing, e2e, anon/service-role keys, optional CLI, Winston logs","directories":{},"_nodeVersion":"24.11.0","dependencies":{"winston":"^3.19.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","eslint":"^10.2.0","rimraf":"^6.1.3","prettier":"^3.8.2","@eslint/js":"^10.0.1","typescript":"^6.0.2","@types/node":"^25.6.0","typescript-eslint":"^8.58.1","@supabase/supabase-js":"^2.103.0","eslint-config-prettier":"^10.1.8","eslint-plugin-simple-import-sort":"^13.0.0"},"peerDependencies":{"@supabase/supabase-js":"^2.0.0"},"_npmOperationalInternal":{"tmp":"tmp/supabase-in-memory-server_1.0.0_1775918233316_0.32662763753901713","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@akirilyuk/supabase-in-memory-server","version":"1.0.1","description":"In-memory HTTP server mimicking Supabase REST (PostgREST) and Auth (GoTrue) for supabase-js: local testing, e2e, anon/service-role keys, optional CLI, Winston logs","type":"commonjs","main":"./dist/index.js","types":"./dist/index.d.ts","bin":{"supabase-in-memory-server":"dist/cli.js"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"rimraf dist","typecheck":"tsc --noEmit","lint":"eslint .","lint:fix":"eslint . --fix","format":"prettier --write .","format:check":"prettier --check .","prepack":"npm run build","test":"tsx --test tests/integration.test.ts tests/e2e/supabase-client.e2e.test.ts"},"repository":{"type":"git","url":"git+https://github.com/akirilyuk/supabase-in-memory-server.git"},"keywords":["supabase","supabase-js","supabase-mock","supabase-local","supabase-client-js","postgrest","postgrest-mock","gotrue","gotrue-mock","in-memory","in-memory-database","http-server","mock-server","fake-server","integration-testing","e2e-testing","testing","typescript","node","nodejs","cli","rest-api","auth","anon-key","service-role","winston","local-development","dev-server"],"author":{"name":"akirilyuk","url":"https://github.com/akirilyuk"},"license":"MIT","engines":{"node":"^20.9.0 || >=22"},"bugs":{"url":"https://github.com/akirilyuk/supabase-in-memory-server/issues"},"homepage":"https://github.com/akirilyuk/supabase-in-memory-server#readme","peerDependencies":{"@supabase/supabase-js":"^2.0.0"},"devDependencies":{"@eslint/js":"^10.0.1","@supabase/supabase-js":"^2.103.0","@types/node":"^25.6.0","eslint":"^10.2.0","eslint-config-prettier":"^10.1.8","eslint-plugin-simple-import-sort":"^13.0.0","prettier":"^3.8.2","rimraf":"^6.1.3","tsx":"^4.21.0","typescript":"^6.0.2","typescript-eslint":"^8.58.1"},"dependencies":{"winston":"^3.19.0"},"_id":"@akirilyuk/supabase-in-memory-server@1.0.1","gitHead":"ea9c019b5eb8e029e215a884673316ef84f398e8","_nodeVersion":"22.22.2","_npmVersion":"10.9.7","dist":{"integrity":"sha512-TFufoVxz8y2BTyA0Vu79Pv1jp5Bss7XbGwPL6LUKhbF90GCHdT1L4hrN3Q3SXzogs2kPPkdambIqS50jlv16Ng==","shasum":"3c42556cc53958f5547ce582fbea2f076334957d","tarball":"https://registry.npmjs.org/@akirilyuk/supabase-in-memory-server/-/supabase-in-memory-server-1.0.1.tgz","fileCount":79,"unpackedSize":147933,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDscufYFDiRmolemnewuwdAUAEPM6d4Hj4gJlOjeLEmTQIgfeussuVycyDVXO09DUjaqb6kKPw8PE+dp1tVA76Fkms="}]},"_npmUser":{"name":"akirilyuk","email":"alexander.kiri.aa@googlemail.com"},"directories":{},"maintainers":[{"name":"akirilyuk","email":"alexander.kiri.aa@googlemail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/supabase-in-memory-server_1.0.1_1775920662110_0.06703825147940679"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-11T14:37:13.222Z","modified":"2026-04-11T15:17:42.419Z","1.0.0":"2026-04-11T14:37:13.462Z","1.0.1":"2026-04-11T15:17:42.289Z"},"bugs":{"url":"https://github.com/akirilyuk/supabase-in-memory-server/issues"},"author":{"name":"akirilyuk","url":"https://github.com/akirilyuk"},"license":"MIT","homepage":"https://github.com/akirilyuk/supabase-in-memory-server#readme","keywords":["supabase","supabase-js","supabase-mock","supabase-local","supabase-client-js","postgrest","postgrest-mock","gotrue","gotrue-mock","in-memory","in-memory-database","http-server","mock-server","fake-server","integration-testing","e2e-testing","testing","typescript","node","nodejs","cli","rest-api","auth","anon-key","service-role","winston","local-development","dev-server"],"repository":{"type":"git","url":"git+https://github.com/akirilyuk/supabase-in-memory-server.git"},"description":"In-memory HTTP server mimicking Supabase REST (PostgREST) and Auth (GoTrue) for supabase-js: local testing, e2e, anon/service-role keys, optional CLI, Winston logs","maintainers":[{"name":"akirilyuk","email":"alexander.kiri.aa@googlemail.com"}],"readme":"# supabase-in-memory-server\n\nnpm package **`supabase-in-memory-server`** (formerly **`supabase-jest-mock`**).\n\nIn-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.\n\nThe 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()`.\n\n## Requirements\n\n- Node.js **20.9+** or **22+**\n- Peer dependency: **`@supabase/supabase-js` ^2**\n\n## Install\n\n```bash\nnpm install supabase-in-memory-server @supabase/supabase-js\n```\n\n## Quick start (programmatic)\n\n```ts\nimport { createClient } from '@supabase/supabase-js';\nimport {\n  createMemorySupabaseServer,\n  applyMemorySupabaseEnvToProcess,\n} from 'supabase-in-memory-server';\n\nconst srv = await createMemorySupabaseServer({ useEnv: false });\n\n// Optional: expose the same values Supabase apps expect in process.env\napplyMemorySupabaseEnvToProcess(srv);\n\nconst anon = createClient(srv.url, srv.anonKey, {\n  auth: { persistSession: false, autoRefreshToken: false },\n});\n\nconst { error } = await anon.from('todos').insert({ id: 1, title: 'Buy milk' }).select();\n// ...\n\nawait srv.close();\n```\n\n### Convenience: server + anon client\n\n```ts\nimport { createTestSupabaseClient } from 'supabase-in-memory-server';\n\nconst { client, url, anonKey, serviceRoleKey, store, logger, close } =\n  await createTestSupabaseClient();\n// `client` is already createClient(url, anonKey, { auth: { persistSession: false, ... } })\n\nawait close();\n```\n\n### Service role (admin) client\n\nUse the **service role** key for `auth.admin` (e.g. `listUsers`). Never expose this key in browser bundles.\n\n```ts\nimport { createClient } from '@supabase/supabase-js';\nimport { createMemorySupabaseServer } from 'supabase-in-memory-server';\n\nconst srv = await createMemorySupabaseServer({ useEnv: false });\nconst admin = createClient(srv.url, srv.serviceRoleKey, {\n  auth: { persistSession: false, autoRefreshToken: false },\n});\n\nconst { data, error } = await admin.auth.admin.listUsers({ perPage: 50 });\nawait srv.close();\n```\n\n## What you get back from the server\n\n`createMemorySupabaseServer` / `startInMemorySupabaseServer` resolve to an object with:\n\n| Field                | Description                                                                                            |\n| -------------------- | ------------------------------------------------------------------------------------------------------ |\n| **`url`**            | Base URL, e.g. `http://127.0.0.1:<port>`                                                               |\n| **`anonKey`**        | Anon API key (maps to `SUPABASE_ANON_KEY`)                                                             |\n| **`serviceRoleKey`** | Service role / admin key (maps to `SUPABASE_SERVICE_ROLE_KEY`)                                         |\n| **`supabaseKey`**    | Same as `anonKey` (legacy name)                                                                        |\n| **`store`**          | `MemoryStore` — in-memory tables for REST                                                              |\n| **`auth`**           | `AuthMemory` — in-memory users and sessions                                                            |\n| **`server`**         | Node `http.Server`                                                                                     |\n| **`logger`**         | Winston `Logger` — lifecycle + per-request logs (see **Logging** below)                                |\n| **`close()`**        | Stops the server and clears auth state (tables are **not** cleared unless you call `store.clearAll()`) |\n\n## Logging and debug mode\n\nLogging uses **Winston**. Each HTTP request gets a **10-character hex `requestId`**. In **debug** mode you will see:\n\n- **`Incoming request`** — `{ requestId, method, path, query }` when the request enters the pipeline (including **OPTIONS**).\n- **`Request finished`** — `{ requestId, method, path }` in a **`finally`** block when handling completes (success, early return, or error).\n- Handler-level **`debug`** lines for auth and REST (correlated via a **child logger** that carries `requestId` on every line).\n\n**Options**\n\n| Setting                             | Effect                                                                                                                      |\n| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |\n| **`debug: true`** in server options | Root log level `debug`: full request/handler detail.                                                                        |\n| **`debug: false`** (default)        | Level `info`: listen/close and **`error`** / **`warn`**; routine traffic stays at `debug` (hidden unless you enable debug). |\n| **`SUPABASE_JEST_MOCK_DEBUG`**      | If `1`, `true`, or `yes`, sets `debug` when `useEnv` is not `false`.                                                        |\n\n```ts\nawait createMemorySupabaseServer({ useEnv: false, debug: true });\n```\n\nTo silence logs in noisy tests: **`srv.logger.silent = true`**.\n\nYou can also build a matching logger with **`createMemorySupabaseLogger(debug)`** if you construct **`MemorySupabaseHttpServer`** yourself (advanced).\n\n## Environment variables\n\nBy default (**`useEnv` is not `false`**), options are merged with the environment: env first, then explicit options override.\n\n| Variable                        | Purpose                                                                                              |\n| ------------------------------- | ---------------------------------------------------------------------------------------------------- |\n| **`SUPABASE_URL`**              | If set, **host** and **port** for listening are taken from this URL (e.g. `http://127.0.0.1:54321`). |\n| **`SUPABASE_JEST_MOCK_HOST`**   | Overrides listen hostname after URL parsing.                                                         |\n| **`SUPABASE_JEST_MOCK_PORT`**   | Overrides listen port after URL parsing. Use `0` for an ephemeral port.                              |\n| **`SUPABASE_ANON_KEY`**         | Anon key used as the `apikey` header for the public client.                                          |\n| **`SUPABASE_SERVICE_ROLE_KEY`** | Service role key for admin operations.                                                               |\n| **`SUPABASE_JEST_MOCK_DEBUG`**  | Enables verbose **`debug`** logging (`1`, `true`, or `yes`).                                         |\n\nAfter the server is running, you can sync **`process.env`** to the **actual** URL and keys (recommended for apps that only read env):\n\n```ts\nimport {\n  createMemorySupabaseServer,\n  applyMemorySupabaseEnvToProcess,\n} from 'supabase-in-memory-server';\n\nconst srv = await createMemorySupabaseServer();\napplyMemorySupabaseEnvToProcess(srv);\n// process.env.SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY\n```\n\n## CLI\n\nFrom the package install:\n\n```bash\nnpx supabase-in-memory-server\n```\n\n- Starts the in-memory server (honors the same env vars as above).\n- Writes `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and `SUPABASE_SERVICE_ROLE_KEY` into **`process.env`**.\n- Prints a JSON object with those three keys to **stdout**.\n- Logs the listen URL to **stderr** (and Winston lifecycle lines unless silenced).\n- Exit with **Ctrl+C** (SIGINT) or SIGTERM.\n\n## Authentication and API keys\n\n- Every request must include header **`apikey`** equal to either **`anonKey`** or **`serviceRoleKey`**. Missing or wrong key → **401**.\n- **`GET /auth/v1/admin/users`** requires the **service role** key (or `Authorization: Bearer <serviceRoleKey>`).\n\nImplemented 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.\n\n## REST (PostgREST-shaped)\n\nSupported 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.\n\nWith **`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).\n\nThere is **no** RLS, **no** Realtime WebSocket, **no** Storage, **no** Edge Functions, **no** `/rest/v1/rpc/...`, and **no** full PostgREST operator set (see **TODO** below).\n\n## Publishing (maintainers)\n\nGitHub Actions **Release** workflow (`.github/workflows/release.yml`) runs when you **push a version tag**:\n\n1. Set **`version`** in `package.json` to the release you want (e.g. `1.2.3`).\n2. Commit that change on the default branch (e.g. `main`).\n3. Create and push a tag **`v`** + the same version: `git tag v1.2.3 && git push origin v1.2.3`.\n\nThe tag **must** be `vMAJOR.MINOR.PATCH` and match `package.json` exactly (e.g. tag `v1.2.3` ↔ `\"version\": \"1.2.3\"`). The workflow runs typecheck, lint, format check, build, and tests, then **`npm publish --access public`** (needed for **scoped** package names) and creates a **GitHub Release** with generated notes.\n\n**Repository secret:** add **`NPM_TOKEN`** in the repo’s **Settings → Secrets and variables → Actions**. Use an [npm access token](https://docs.npmjs.com/creating-and-viewing-access-tokens) with permission to publish this package (granular token for `@scope/package`, or a user token with publish rights).\n\n## API reference (exports)\n\nThe main entry is **`supabase-in-memory-server`** (`dist/index.js`). Notable exports:\n\n- **`createMemorySupabaseServer`**, **`startInMemorySupabaseServer`** — start the HTTP server.\n- **`createTestSupabaseClient`** — server + `SupabaseClient` with anon key.\n- **`applyMemorySupabaseEnvToProcess`** — set `SUPABASE_*` env from a running server.\n- **`MemorySupabaseHttpServer`** — HTTP app class (advanced: custom lifecycle, tests).\n- **`createMemorySupabaseLogger`** — Winston factory aligned with the server’s log format.\n- **`readMemorySupabaseServerEnv`**, **`resolveMemorySupabaseServerOptions`**, **`generateDefaultProjectKeys`**, **`MemorySupabaseServerInputOptions`** — configuration helpers.\n- **`MemorySupabaseServer`**, **`MemorySupabaseServerOptions`**, **`MemoryStore`**, **`AuthMemory`**, **`JsonRecord`**, etc.\n\nSee TSDoc on those symbols in the source for details.\n\n## TODO (toward a fuller in-memory Supabase mock)\n\nThis package intentionally covers a **small, test-friendly** slice of Supabase. A **full** in-memory mock would still need (non-exhaustive):\n\n### Auth (GoTrue)\n\n- [ ] OAuth / SSO providers, **magic links**, **OTP**, and phone SMS flows.\n- [ ] Additional **`auth.admin`** APIs: `deleteUser`, `updateUserById`, `inviteUserByEmail`, `generateLink`, etc.\n- [ ] **MFA** (TOTP, WebAuthn) and step-up semantics.\n- [ ] **Session management**: list/revoke sessions, refresh rotation edge cases matching production.\n- [ ] **Password recovery** / email change / user verification flows.\n- [ ] Stricter alignment with GoTrue error payloads, status codes, and headers.\n- [ ] Optional **JWT signing/verification** matching real projects (currently test-oriented tokens).\n\n### REST / PostgREST\n\n- [ ] **RPC**: `POST /rest/v1/rpc/:function` (and client `.rpc()`).\n- [ ] **Embedded resources** / foreign-table `select` shapes (`profiles(*)`).\n- [ ] More **filter operators** (`like`, `ilike`, `fts`, `cs`, `cd`, `@>`, `range`, `or`, `and`, `not`, etc.).\n- [ ] **`columns=`**, default values, generated columns behavior (as far as in-memory JSON allows).\n- [ ] **Schemas** / multiple schemas, views, and table exposure rules.\n- [ ] **Row Level Security** simulation (policies per role / JWT claims).\n- [ ] **Transactions** or batch semantics if clients rely on them.\n- [ ] Closer **error codes** and **Prefer** / **Content-Range** behavior vs real PostgREST.\n\n### Realtime\n\n- [ ] **WebSocket** server and **`postgres_changes`** (and channel/auth parity with Supabase Realtime).\n\n### Storage\n\n- [ ] **S3-compatible** or Supabase Storage REST: buckets, objects, signed URLs, MIME limits.\n\n### Edge Functions & platform\n\n- [ ] **Edge Functions** invoke path or local stub.\n- [ ] **Database webhooks**, **pg_cron**, and other backend-only features (usually out of scope for a pure HTTP mock).\n\n### Developer experience\n\n- [ ] Optional **OpenAPI** / schema endpoint mimicking PostgREST.\n- [ ] **Snapshot / fixture** helpers for common test scenarios.\n\nContributions that close items above are welcome; keep the default footprint small so Jest/CI stays fast.\n\n## Development\n\n```bash\nnpm install\nnpm run build      # emit dist/\nnpm run typecheck\nnpm run lint\nnpm run format:check\nnpm test           # integration + e2e tests\n```\n\n## License\n\n[MIT](LICENSE)\n","readmeFilename":"README.md"}