@constructive-io/graphql-dev-server 3.3.2

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 ADDED
@@ -0,0 +1,23 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Dan Lynch <pyramation@gmail.com>
4
+ Copyright (c) 2025 Constructive <developers@constructive.io>
5
+ Copyright (c) 2020-present, Interweb, Inc.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # @constructive-io/graphql-dev-server
2
+
3
+ <p align="center" width="100%">
4
+ <img height="250" src="https://raw.githubusercontent.com/constructive-io/constructive/refs/heads/main/assets/outline-logo.svg" />
5
+ </p>
6
+
7
+ <p align="center" width="100%">
8
+ <a href="https://github.com/constructive-io/constructive/actions/workflows/run-tests.yaml">
9
+ <img height="20" src="https://github.com/constructive-io/constructive/actions/workflows/run-tests.yaml/badge.svg" />
10
+ </a>
11
+ <a href="https://github.com/constructive-io/constructive/blob/main/LICENSE"><img height="20" src="https://img.shields.io/badge/license-MIT-blue.svg"/></a>
12
+ </p>
13
+
14
+ **Constructive GraphQL Dev Server** is a pure-PostGraphile, single-tenant GraphQL server for local development and test harnesses. It points at one database, exposes the configured schemas, and runs every request as a single fixed Postgres role.
15
+
16
+ It is deliberately **not** the production server: there is no scoped-routing plane and no tenant `database_id`. Because of that, it only enables the Constructive plugins that do **not** require a `database_id`; plugins that resolve per-tenant config from a `database_id` are excluded.
17
+
18
+ > For production, use `@constructive-io/graphql-server`, which always resolves each request through the scoped routing plane (`resolve_route()`).
19
+
20
+ ## Quick Start
21
+
22
+ ```ts
23
+ import { getEnvOptions } from '@constructive-io/graphql-env';
24
+ import { createDevServer } from '@constructive-io/graphql-dev-server';
25
+
26
+ const server = await createDevServer(
27
+ getEnvOptions({
28
+ pg: { database: 'my_db' },
29
+ api: { exposedSchemas: ['app_public'], roleName: 'administrator' }
30
+ }),
31
+ { port: 5555 }
32
+ );
33
+
34
+ console.log(server.graphqlUrl); // http://127.0.0.1:5555/graphql
35
+
36
+ // later
37
+ await server.stop();
38
+ ```
39
+
40
+ ## What it does
41
+
42
+ - Builds a Constructive-style PostGraphile v5 preset via `createConstructivePreset()`, so all the standard presets (connection filters, search, PostGIS, ltree, direct uploads, meta-schema, inflection, type mappings, etc.) are baked in automatically.
43
+ - Serves the schemas in `api.exposedSchemas` from a single database.
44
+ - Runs every request as one fixed role (`api.roleName` → `api.anonRole` → `pg.user`). There is no per-request auth and no routing.
45
+ - Exposes `/healthz`, `/graphql`, and `/graphiql`.
46
+
47
+ ## Plugins that are excluded
48
+
49
+ The following plugin groups resolve per-tenant configuration from a `database_id` and are therefore **disabled** in the dev server:
50
+
51
+ - **Presigned uploads / bucket provisioner** (`enablePresignedUploads: false`) — resolve per-tenant storage config keyed by `database_id`.
52
+ - **LLM** (`enableLlm: false`) — resolves per-tenant billing / inference-log config keyed by `database_id`.
53
+
54
+ Direct uploads stay enabled: they stream to a fixed, env-configured bucket and need no `database_id`.
55
+
56
+ ## Configuration
57
+
58
+ Configuration is merged from defaults, config files, and env vars via `@constructive-io/graphql-env`. See `graphql/env/README.md` for the full list.
59
+
60
+ | Option | Source env var | Purpose |
61
+ | --------------------- | --------------------- | ------------------------------------------ |
62
+ | `pg.database` | `PGDATABASE` | Database to serve |
63
+ | `api.exposedSchemas` | `API_EXPOSED_SCHEMAS` | Schemas to expose |
64
+ | `api.roleName` | `API_ROLE_NAME` | Fixed Postgres role for every request |
65
+ | `api.anonRole` | `API_ANON_ROLE` | Fallback role if `roleName` is unset |
66
+
67
+ ## API
68
+
69
+ - `createDevServer(opts?, serverOpts?)` → `Promise<DevServerInfo>` — starts an Express + PostGraphile server. `DevServerInfo` includes `url`, `graphqlUrl`, `port`, `host`, `httpServer`, `app`, and `stop()`.
70
+ - `buildDevPreset({ pool, schemas, role })` → `GraphileConfig.Preset` — the dev preset, if you want to embed it in your own server.
71
+
72
+ ## Related Packages
73
+
74
+ - `@constructive-io/graphql-server` — production scoped-routing server
75
+ - `@constructive-io/graphql-env` — env parsing + defaults
76
+ - `graphile-settings` — PostGraphile configuration presets
77
+
78
+ ---
79
+
80
+ ## Education and Tutorials
81
+
82
+ 1. 🚀 [Quickstart: Getting Up and Running](https://constructive.io/learn/quickstart)
83
+ Get started with modular databases in minutes. Install prerequisites and deploy your first module.
84
+
85
+ 2. 📦 [Modular PostgreSQL Development with Database Packages](https://constructive.io/learn/modular-postgres)
86
+ Learn to organize PostgreSQL projects with pgpm workspaces and reusable database modules.
87
+
88
+ 3. ✏️ [Authoring Database Changes](https://constructive.io/learn/authoring-database-changes)
89
+ Master the workflow for adding, organizing, and managing database changes with pgpm.
90
+
91
+ 4. 🧪 [End-to-End PostgreSQL Testing with TypeScript](https://constructive.io/learn/e2e-postgres-testing)
92
+ Master end-to-end PostgreSQL testing with ephemeral databases, RLS testing, and CI/CD automation.
93
+
94
+ 5. ⚡ [Supabase Testing](https://constructive.io/learn/supabase)
95
+ Use TypeScript-first tools to test Supabase projects with realistic RLS, policies, and auth contexts.
96
+
97
+ 6. 💧 [Drizzle ORM Testing](https://constructive.io/learn/drizzle-testing)
98
+ Run full-stack tests with Drizzle ORM, including database setup, teardown, and RLS enforcement.
99
+
100
+ 7. 🔧 [Troubleshooting](https://constructive.io/learn/troubleshooting)
101
+ Common issues and solutions for pgpm, PostgreSQL, and testing.
102
+
103
+ ## Related Constructive Tooling
104
+
105
+ ### 📦 Package Management
106
+
107
+ * [pgpm](https://github.com/constructive-io/constructive/tree/main/pgpm/pgpm): **🖥️ PostgreSQL Package Manager** for modular Postgres development. Works with database workspaces, scaffolding, migrations, seeding, and installing database packages.
108
+
109
+ ### 🧪 Testing
110
+
111
+ * [pgsql-test](https://github.com/constructive-io/constructive/tree/main/postgres/pgsql-test): **📊 Isolated testing environments** with per-test transaction rollbacks—ideal for integration tests, complex migrations, and RLS simulation.
112
+ * [pgsql-seed](https://github.com/constructive-io/constructive/tree/main/postgres/pgsql-seed): **🌱 PostgreSQL seeding utilities** for CSV, JSON, SQL data loading, and pgpm deployment.
113
+ * [supabase-test](https://github.com/constructive-io/constructive/tree/main/postgres/supabase-test): **🧪 Supabase-native test harness** preconfigured for the local Supabase stack—per-test rollbacks, JWT/role context helpers, and CI/GitHub Actions ready.
114
+ * [graphile-test](https://github.com/constructive-io/constructive/tree/main/graphile/graphile-test): **🔐 Authentication mocking** for Graphile-focused test helpers and emulating row-level security contexts.
115
+ * [pg-query-context](https://github.com/constructive-io/constructive/tree/main/postgres/pg-query-context): **🔒 Session context injection** to add session-local context (e.g., `SET LOCAL`) into queries—ideal for setting `role`, `jwt.claims`, and other session settings.
116
+
117
+ ### 🧠 Parsing & AST
118
+
119
+ * [pgsql-parser](https://www.npmjs.com/package/pgsql-parser): **🔄 SQL conversion engine** that interprets and converts PostgreSQL syntax.
120
+ * [libpg-query-node](https://www.npmjs.com/package/libpg-query): **🌉 Node.js bindings** for `libpg_query`, converting SQL into parse trees.
121
+ * [pg-proto-parser](https://www.npmjs.com/package/pg-proto-parser): **📦 Protobuf parser** for parsing PostgreSQL Protocol Buffers definitions to generate TypeScript interfaces, utility functions, and JSON mappings for enums.
122
+ * [@pgsql/enums](https://www.npmjs.com/package/@pgsql/enums): **🏷️ TypeScript enums** for PostgreSQL AST for safe and ergonomic parsing logic.
123
+ * [@pgsql/types](https://www.npmjs.com/package/@pgsql/types): **📝 Type definitions** for PostgreSQL AST nodes in TypeScript.
124
+ * [@pgsql/utils](https://www.npmjs.com/package/@pgsql/utils): **🛠️ AST utilities** for constructing and transforming PostgreSQL syntax trees.
125
+
126
+ ### 📚 Documentation & Skills
127
+
128
+ * [constructive-skills](https://github.com/constructive-io/constructive-skills): **📖 Platform documentation and AI agent skills** — feature catalog, blueprint reference, SDK guides (i18n, billing, limits, events, uploads, security, entities, search, AI), and deployment guides.
129
+
130
+ Install skills for AI coding agents:
131
+
132
+ ```bash
133
+ # All platform skills (security, blueprints, codegen, billing, etc.)
134
+ npx skills add constructive-io/constructive-skills
135
+
136
+ # Individual repo skills (pgpm, testing, CLI, search, etc.)
137
+ npx skills add https://github.com/constructive-io/constructive --skill pgpm
138
+ npx skills add https://github.com/constructive-io/constructive --skill constructive-testing
139
+ ```
140
+
141
+ ## Credits
142
+
143
+ **🛠 Built by the [Constructive](https://constructive.io) team — creators of modular Postgres tooling for secure, composable backends. If you like our work, contribute on [GitHub](https://github.com/constructive-io).**
144
+
145
+ ## Disclaimer
146
+
147
+ AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.
148
+
149
+ No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.
package/esm/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { createDevServer } from './server';
2
+ export { buildDevPreset } from './preset';
package/esm/preset.js ADDED
@@ -0,0 +1,32 @@
1
+ import { createConstructivePreset, makePgService } from 'graphile-settings';
2
+ /**
3
+ * Build the dev-server PostGraphile v5 preset.
4
+ *
5
+ * This is a pure-PostGraphile surface over a single database: it exposes the
6
+ * configured schemas with a fixed role and no scoped-routing plane. Only
7
+ * plugins that do NOT depend on a tenant database id are enabled. The presigned
8
+ * upload / bucket-provisioner plugins resolve per-tenant storage config from a
9
+ * `database_id`, and the LLM plugin resolves per-tenant billing / inference-log
10
+ * config from a `database_id`, so all three are excluded here. Direct uploads
11
+ * stream to a fixed env-configured bucket and need no database id, so they stay.
12
+ * Nothing enabled here reads `jwt.claims.database_id`.
13
+ */
14
+ export const buildDevPreset = ({ pool, schemas, role }) => ({
15
+ extends: [
16
+ createConstructivePreset({
17
+ enablePresignedUploads: false,
18
+ enableLlm: false
19
+ })
20
+ ],
21
+ pgServices: [makePgService({ pool, schemas })],
22
+ grafserv: {
23
+ graphqlPath: '/graphql',
24
+ graphiqlPath: '/graphiql',
25
+ graphiql: true,
26
+ graphiqlOnGraphQLGET: false
27
+ },
28
+ grafast: {
29
+ explain: process.env.NODE_ENV === 'development',
30
+ context: () => ({ pgSettings: { role } })
31
+ }
32
+ });
package/esm/server.js ADDED
@@ -0,0 +1,61 @@
1
+ import { getEnvOptions } from '@constructive-io/graphql-env';
2
+ import { Logger } from '@pgpmjs/logger';
3
+ import { cors, healthz, poweredBy } from '@pgpmjs/server-utils';
4
+ import express from 'express';
5
+ import { createGraphileInstance } from 'graphile-cache';
6
+ import { getPgPool } from 'pg-cache';
7
+ import { getPgEnvOptions } from 'pg-env';
8
+ import { buildDevPreset } from './preset';
9
+ const log = new Logger('dev-server');
10
+ /**
11
+ * Create a pure-PostGraphile single-tenant dev server.
12
+ *
13
+ * Unlike the production `@constructive-io/graphql-server`, this server has no
14
+ * scoped-routing plane and no database id: it points at one database, exposes
15
+ * the configured schemas, and runs every request as a single fixed role. It is
16
+ * intended for local development and test harnesses only — never production.
17
+ */
18
+ export const createDevServer = async (rawOpts = {}, serverOpts = {}) => {
19
+ const opts = getEnvOptions(rawOpts);
20
+ // Bind to 127.0.0.1 by default to avoid IPv6/IPv4 mismatches with supertest.
21
+ const host = serverOpts.host ?? '127.0.0.1';
22
+ const port = serverOpts.port ?? 0;
23
+ const schemas = opts.api?.exposedSchemas ?? [];
24
+ const role = opts.api?.roleName ?? opts.api?.anonRole ?? opts.pg?.user ?? 'postgres';
25
+ log.info(`[dev-server] starting db=${opts.pg?.database} schemas=[${schemas.join(', ')}] role=${role}`);
26
+ const pool = getPgPool(getPgEnvOptions({ ...opts.pg }));
27
+ const preset = buildDevPreset({ pool, schemas, role });
28
+ const cacheKey = `dev:${opts.pg?.database ?? ''}:${schemas.join(',')}:${role}`;
29
+ const instance = await createGraphileInstance({
30
+ preset,
31
+ cacheKey
32
+ });
33
+ const app = express();
34
+ healthz(app);
35
+ cors(app, serverOpts.origin ?? opts.server?.origin);
36
+ app.use(poweredBy('constructive'));
37
+ app.use((req, res, next) => instance.handler(req, res, next));
38
+ const httpServer = await new Promise((resolve, reject) => {
39
+ const server = app.listen(port, host, () => resolve(server));
40
+ server.on('error', reject);
41
+ });
42
+ const actualPort = httpServer.address().port;
43
+ const stop = async () => {
44
+ await new Promise((resolve, reject) => {
45
+ httpServer.close((err) => (err ? reject(err) : resolve()));
46
+ });
47
+ if (instance.httpServer?.listening) {
48
+ await new Promise((resolve) => instance.httpServer.close(() => resolve()));
49
+ }
50
+ await instance.pgl?.release?.();
51
+ };
52
+ return {
53
+ httpServer,
54
+ app,
55
+ url: `http://${host}:${actualPort}`,
56
+ graphqlUrl: `http://${host}:${actualPort}/graphql`,
57
+ port: actualPort,
58
+ host,
59
+ stop
60
+ };
61
+ };
package/esm/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/index.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { createDevServer } from './server';
2
+ export { buildDevPreset } from './preset';
3
+ export type { DevPresetInput } from './preset';
4
+ export type { DevServerInfo, DevServerOptions } from './types';
package/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildDevPreset = exports.createDevServer = void 0;
4
+ var server_1 = require("./server");
5
+ Object.defineProperty(exports, "createDevServer", { enumerable: true, get: function () { return server_1.createDevServer; } });
6
+ var preset_1 = require("./preset");
7
+ Object.defineProperty(exports, "buildDevPreset", { enumerable: true, get: function () { return preset_1.buildDevPreset; } });
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@constructive-io/graphql-dev-server",
3
+ "version": "3.3.2",
4
+ "author": "Constructive <developers@constructive.io>",
5
+ "description": "Pure-PostGraphile single-tenant dev server (no scoped routing, no database-id plugins)",
6
+ "main": "index.js",
7
+ "module": "esm/index.js",
8
+ "types": "index.d.ts",
9
+ "homepage": "https://github.com/constructive-io/constructive",
10
+ "license": "MIT",
11
+ "publishConfig": {
12
+ "access": "public",
13
+ "directory": "dist"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/constructive-io/constructive"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/constructive-io/constructive/issues"
21
+ },
22
+ "scripts": {
23
+ "clean": "makage clean",
24
+ "prepack": "npm run build",
25
+ "build": "makage build",
26
+ "build:dev": "makage build --dev",
27
+ "lint": "eslint . --fix",
28
+ "test": "jest --passWithNoTests",
29
+ "test:watch": "jest --watch"
30
+ },
31
+ "devDependencies": {
32
+ "@types/express": "^5.0.6",
33
+ "@types/pg": "^8.20.0",
34
+ "makage": "^0.3.0"
35
+ },
36
+ "dependencies": {
37
+ "@constructive-io/graphql-env": "^3.19.2",
38
+ "@constructive-io/graphql-types": "^3.18.2",
39
+ "@pgpmjs/logger": "^2.15.2",
40
+ "@pgpmjs/server-utils": "^3.16.2",
41
+ "express": "^5.2.1",
42
+ "grafast": "1.0.2",
43
+ "grafserv": "1.0.0",
44
+ "graphile-build": "5.0.2",
45
+ "graphile-build-pg": "5.0.2",
46
+ "graphile-cache": "^4.1.2",
47
+ "graphile-config": "1.0.1",
48
+ "graphile-settings": "^6.1.2",
49
+ "graphile-utils": "5.0.1",
50
+ "graphql": "16.13.0",
51
+ "pg": "^8.21.0",
52
+ "pg-cache": "^3.16.2",
53
+ "pg-env": "^1.19.2",
54
+ "pg-sql2": "5.0.1",
55
+ "postgraphile": "5.0.3"
56
+ },
57
+ "keywords": [
58
+ "graphql",
59
+ "graphile",
60
+ "postgraphile",
61
+ "constructive",
62
+ "dev-server",
63
+ "single-tenant"
64
+ ],
65
+ "gitHead": "08741ce3a6897192c2dbc7d1da48b9f456ffb59f"
66
+ }
package/preset.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import type { GraphileConfig } from 'graphile-config';
2
+ import type { Pool } from 'pg';
3
+ export interface DevPresetInput {
4
+ pool: Pool;
5
+ schemas: string[];
6
+ /** Postgres role every request runs as (there is no per-request auth here). */
7
+ role: string;
8
+ }
9
+ /**
10
+ * Build the dev-server PostGraphile v5 preset.
11
+ *
12
+ * This is a pure-PostGraphile surface over a single database: it exposes the
13
+ * configured schemas with a fixed role and no scoped-routing plane. Only
14
+ * plugins that do NOT depend on a tenant database id are enabled. The presigned
15
+ * upload / bucket-provisioner plugins resolve per-tenant storage config from a
16
+ * `database_id`, and the LLM plugin resolves per-tenant billing / inference-log
17
+ * config from a `database_id`, so all three are excluded here. Direct uploads
18
+ * stream to a fixed env-configured bucket and need no database id, so they stay.
19
+ * Nothing enabled here reads `jwt.claims.database_id`.
20
+ */
21
+ export declare const buildDevPreset: ({ pool, schemas, role }: DevPresetInput) => GraphileConfig.Preset;
package/preset.js ADDED
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildDevPreset = void 0;
4
+ const graphile_settings_1 = require("graphile-settings");
5
+ /**
6
+ * Build the dev-server PostGraphile v5 preset.
7
+ *
8
+ * This is a pure-PostGraphile surface over a single database: it exposes the
9
+ * configured schemas with a fixed role and no scoped-routing plane. Only
10
+ * plugins that do NOT depend on a tenant database id are enabled. The presigned
11
+ * upload / bucket-provisioner plugins resolve per-tenant storage config from a
12
+ * `database_id`, and the LLM plugin resolves per-tenant billing / inference-log
13
+ * config from a `database_id`, so all three are excluded here. Direct uploads
14
+ * stream to a fixed env-configured bucket and need no database id, so they stay.
15
+ * Nothing enabled here reads `jwt.claims.database_id`.
16
+ */
17
+ const buildDevPreset = ({ pool, schemas, role }) => ({
18
+ extends: [
19
+ (0, graphile_settings_1.createConstructivePreset)({
20
+ enablePresignedUploads: false,
21
+ enableLlm: false
22
+ })
23
+ ],
24
+ pgServices: [(0, graphile_settings_1.makePgService)({ pool, schemas })],
25
+ grafserv: {
26
+ graphqlPath: '/graphql',
27
+ graphiqlPath: '/graphiql',
28
+ graphiql: true,
29
+ graphiqlOnGraphQLGET: false
30
+ },
31
+ grafast: {
32
+ explain: process.env.NODE_ENV === 'development',
33
+ context: () => ({ pgSettings: { role } })
34
+ }
35
+ });
36
+ exports.buildDevPreset = buildDevPreset;
package/server.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { ConstructiveOptions } from '@constructive-io/graphql-types';
2
+ import type { DevServerInfo, DevServerOptions } from './types';
3
+ /**
4
+ * Create a pure-PostGraphile single-tenant dev server.
5
+ *
6
+ * Unlike the production `@constructive-io/graphql-server`, this server has no
7
+ * scoped-routing plane and no database id: it points at one database, exposes
8
+ * the configured schemas, and runs every request as a single fixed role. It is
9
+ * intended for local development and test harnesses only — never production.
10
+ */
11
+ export declare const createDevServer: (rawOpts?: ConstructiveOptions, serverOpts?: DevServerOptions) => Promise<DevServerInfo>;
package/server.js ADDED
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createDevServer = void 0;
7
+ const graphql_env_1 = require("@constructive-io/graphql-env");
8
+ const logger_1 = require("@pgpmjs/logger");
9
+ const server_utils_1 = require("@pgpmjs/server-utils");
10
+ const express_1 = __importDefault(require("express"));
11
+ const graphile_cache_1 = require("graphile-cache");
12
+ const pg_cache_1 = require("pg-cache");
13
+ const pg_env_1 = require("pg-env");
14
+ const preset_1 = require("./preset");
15
+ const log = new logger_1.Logger('dev-server');
16
+ /**
17
+ * Create a pure-PostGraphile single-tenant dev server.
18
+ *
19
+ * Unlike the production `@constructive-io/graphql-server`, this server has no
20
+ * scoped-routing plane and no database id: it points at one database, exposes
21
+ * the configured schemas, and runs every request as a single fixed role. It is
22
+ * intended for local development and test harnesses only — never production.
23
+ */
24
+ const createDevServer = async (rawOpts = {}, serverOpts = {}) => {
25
+ const opts = (0, graphql_env_1.getEnvOptions)(rawOpts);
26
+ // Bind to 127.0.0.1 by default to avoid IPv6/IPv4 mismatches with supertest.
27
+ const host = serverOpts.host ?? '127.0.0.1';
28
+ const port = serverOpts.port ?? 0;
29
+ const schemas = opts.api?.exposedSchemas ?? [];
30
+ const role = opts.api?.roleName ?? opts.api?.anonRole ?? opts.pg?.user ?? 'postgres';
31
+ log.info(`[dev-server] starting db=${opts.pg?.database} schemas=[${schemas.join(', ')}] role=${role}`);
32
+ const pool = (0, pg_cache_1.getPgPool)((0, pg_env_1.getPgEnvOptions)({ ...opts.pg }));
33
+ const preset = (0, preset_1.buildDevPreset)({ pool, schemas, role });
34
+ const cacheKey = `dev:${opts.pg?.database ?? ''}:${schemas.join(',')}:${role}`;
35
+ const instance = await (0, graphile_cache_1.createGraphileInstance)({
36
+ preset,
37
+ cacheKey
38
+ });
39
+ const app = (0, express_1.default)();
40
+ (0, server_utils_1.healthz)(app);
41
+ (0, server_utils_1.cors)(app, serverOpts.origin ?? opts.server?.origin);
42
+ app.use((0, server_utils_1.poweredBy)('constructive'));
43
+ app.use((req, res, next) => instance.handler(req, res, next));
44
+ const httpServer = await new Promise((resolve, reject) => {
45
+ const server = app.listen(port, host, () => resolve(server));
46
+ server.on('error', reject);
47
+ });
48
+ const actualPort = httpServer.address().port;
49
+ const stop = async () => {
50
+ await new Promise((resolve, reject) => {
51
+ httpServer.close((err) => (err ? reject(err) : resolve()));
52
+ });
53
+ if (instance.httpServer?.listening) {
54
+ await new Promise((resolve) => instance.httpServer.close(() => resolve()));
55
+ }
56
+ await instance.pgl?.release?.();
57
+ };
58
+ return {
59
+ httpServer,
60
+ app,
61
+ url: `http://${host}:${actualPort}`,
62
+ graphqlUrl: `http://${host}:${actualPort}/graphql`,
63
+ port: actualPort,
64
+ host,
65
+ stop
66
+ };
67
+ };
68
+ exports.createDevServer = createDevServer;
package/types.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import type { Express } from 'express';
2
+ import type { Server as HttpServer } from 'http';
3
+ /** Options controlling how the dev server binds its HTTP listener. */
4
+ export interface DevServerOptions {
5
+ /** Host to bind. Defaults to 127.0.0.1. */
6
+ host?: string;
7
+ /** Port to bind. Defaults to 0 (OS-assigned). */
8
+ port?: number;
9
+ /** CORS origin. Defaults to permissive (reflect request origin). */
10
+ origin?: string;
11
+ }
12
+ /** Handle returned by {@link createDevServer}. */
13
+ export interface DevServerInfo {
14
+ httpServer: HttpServer;
15
+ app: Express;
16
+ url: string;
17
+ graphqlUrl: string;
18
+ port: number;
19
+ host: string;
20
+ stop: () => Promise<void>;
21
+ }
package/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });