@constructive-io/graphql-codegen 2.32.0 → 3.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 +429 -1691
- package/cli/index.d.ts +5 -2
- package/cli/index.js +98 -581
- package/cli/shared.d.ts +35 -0
- package/cli/shared.js +106 -0
- package/{esm/cli → core}/codegen/barrel.d.ts +1 -1
- package/{cli → core}/codegen/barrel.js +1 -4
- package/{esm/cli → core}/codegen/index.d.ts +15 -5
- package/{cli → core}/codegen/index.js +44 -24
- package/{cli → core}/codegen/invalidation.d.ts +2 -2
- package/{esm/cli → core}/codegen/mutation-keys.d.ts +2 -2
- package/{cli → core}/codegen/orm/client-generator.js +2 -3
- package/{esm/cli → core}/codegen/orm/index.d.ts +9 -2
- package/{cli → core}/codegen/orm/index.js +3 -2
- package/{cli → core}/codegen/query-keys.d.ts +2 -2
- package/core/codegen/shared/index.d.ts +39 -0
- package/core/codegen/shared/index.js +118 -0
- package/core/config/index.d.ts +5 -0
- package/core/config/index.js +13 -0
- package/core/config/loader.d.ts +18 -0
- package/{cli/commands/init.js → core/config/loader.js} +7 -94
- package/core/config/resolver.d.ts +46 -0
- package/core/config/resolver.js +104 -0
- package/core/database/index.d.ts +43 -0
- package/core/database/index.js +85 -0
- package/core/generate.d.ts +22 -0
- package/core/generate.js +192 -0
- package/core/index.d.ts +13 -1
- package/core/index.js +22 -2
- package/{cli → core}/introspect/fetch-schema.js +58 -9
- package/core/introspect/source/api-schemas.d.ts +44 -0
- package/core/introspect/source/api-schemas.js +122 -0
- package/core/introspect/source/database.d.ts +32 -0
- package/core/introspect/source/database.js +91 -0
- package/core/introspect/source/index.d.ts +112 -0
- package/core/introspect/source/index.js +173 -0
- package/core/introspect/source/pgpm-module.d.ts +83 -0
- package/core/introspect/source/pgpm-module.js +200 -0
- package/core/output/index.d.ts +4 -0
- package/core/output/index.js +9 -0
- package/core/output/writer.d.ts +38 -0
- package/core/output/writer.js +156 -0
- package/{cli/commands/shared.d.ts → core/pipeline/index.d.ts} +5 -3
- package/{cli/commands/shared.js → core/pipeline/index.js} +4 -0
- package/{cli → core}/watch/orchestrator.d.ts +25 -3
- package/{cli → core}/watch/orchestrator.js +35 -27
- package/{cli → core}/watch/types.d.ts +1 -1
- package/esm/cli/index.d.ts +5 -2
- package/esm/cli/index.js +97 -547
- package/esm/cli/shared.d.ts +35 -0
- package/esm/cli/shared.js +101 -0
- package/{cli → esm/core}/codegen/barrel.d.ts +1 -1
- package/esm/{cli → core}/codegen/barrel.js +1 -4
- package/{cli → esm/core}/codegen/index.d.ts +15 -5
- package/esm/{cli → core}/codegen/index.js +44 -24
- package/esm/{cli → core}/codegen/invalidation.d.ts +2 -2
- package/{cli → esm/core}/codegen/mutation-keys.d.ts +2 -2
- package/esm/{cli → core}/codegen/orm/client-generator.js +2 -3
- package/{cli → esm/core}/codegen/orm/index.d.ts +9 -2
- package/esm/{cli → core}/codegen/orm/index.js +3 -2
- package/esm/{cli → core}/codegen/query-keys.d.ts +2 -2
- package/esm/core/codegen/shared/index.d.ts +39 -0
- package/esm/core/codegen/shared/index.js +79 -0
- package/esm/core/config/index.d.ts +5 -0
- package/esm/core/config/index.js +5 -0
- package/esm/core/config/loader.d.ts +18 -0
- package/esm/core/config/loader.js +71 -0
- package/esm/core/config/resolver.d.ts +46 -0
- package/esm/core/config/resolver.js +100 -0
- package/esm/core/database/index.d.ts +43 -0
- package/esm/core/database/index.js +48 -0
- package/esm/core/generate.d.ts +22 -0
- package/esm/core/generate.js +186 -0
- package/esm/core/index.d.ts +13 -1
- package/esm/core/index.js +20 -1
- package/esm/{cli → core}/introspect/fetch-schema.js +55 -9
- package/esm/core/introspect/source/api-schemas.d.ts +44 -0
- package/esm/core/introspect/source/api-schemas.js +117 -0
- package/esm/core/introspect/source/database.d.ts +32 -0
- package/esm/core/introspect/source/database.js +87 -0
- package/esm/core/introspect/source/index.d.ts +112 -0
- package/esm/core/introspect/source/index.js +154 -0
- package/esm/core/introspect/source/pgpm-module.d.ts +83 -0
- package/esm/core/introspect/source/pgpm-module.js +194 -0
- package/esm/core/output/index.d.ts +4 -0
- package/esm/core/output/index.js +4 -0
- package/esm/core/output/writer.d.ts +38 -0
- package/esm/core/output/writer.js +119 -0
- package/esm/{cli/commands/shared.d.ts → core/pipeline/index.d.ts} +5 -3
- package/esm/{cli/commands/shared.js → core/pipeline/index.js} +1 -0
- package/esm/{cli → core}/watch/orchestrator.d.ts +25 -3
- package/esm/{cli → core}/watch/orchestrator.js +35 -27
- package/esm/{cli → core}/watch/types.d.ts +1 -1
- package/esm/index.d.ts +8 -3
- package/esm/index.js +9 -3
- package/esm/types/config.d.ts +101 -138
- package/esm/types/config.js +8 -35
- package/esm/types/index.d.ts +2 -2
- package/esm/types/index.js +1 -1
- package/index.d.ts +8 -3
- package/index.js +18 -8
- package/package.json +18 -11
- package/types/config.d.ts +101 -138
- package/types/config.js +9 -38
- package/types/index.d.ts +2 -2
- package/types/index.js +3 -3
- package/cli/commands/generate-orm.d.ts +0 -53
- package/cli/commands/generate-orm.js +0 -292
- package/cli/commands/generate.d.ts +0 -66
- package/cli/commands/generate.js +0 -431
- package/cli/commands/index.d.ts +0 -9
- package/cli/commands/index.js +0 -14
- package/cli/commands/init.d.ts +0 -35
- package/cli/introspect/source/index.d.ts +0 -48
- package/cli/introspect/source/index.js +0 -72
- package/esm/cli/commands/generate-orm.d.ts +0 -53
- package/esm/cli/commands/generate-orm.js +0 -289
- package/esm/cli/commands/generate.d.ts +0 -66
- package/esm/cli/commands/generate.js +0 -393
- package/esm/cli/commands/index.d.ts +0 -9
- package/esm/cli/commands/index.js +0 -6
- package/esm/cli/commands/init.d.ts +0 -35
- package/esm/cli/commands/init.js +0 -158
- package/esm/cli/introspect/source/index.d.ts +0 -48
- package/esm/cli/introspect/source/index.js +0 -54
- /package/{cli → core}/codegen/babel-ast.d.ts +0 -0
- /package/{cli → core}/codegen/babel-ast.js +0 -0
- /package/{cli → core}/codegen/client.d.ts +0 -0
- /package/{cli → core}/codegen/client.js +0 -0
- /package/{cli → core}/codegen/custom-mutations.d.ts +0 -0
- /package/{cli → core}/codegen/custom-mutations.js +0 -0
- /package/{cli → core}/codegen/custom-queries.d.ts +0 -0
- /package/{cli → core}/codegen/custom-queries.js +0 -0
- /package/{cli → core}/codegen/gql-ast.d.ts +0 -0
- /package/{cli → core}/codegen/gql-ast.js +0 -0
- /package/{cli → core}/codegen/invalidation.js +0 -0
- /package/{cli → core}/codegen/mutation-keys.js +0 -0
- /package/{cli → core}/codegen/mutations.d.ts +0 -0
- /package/{cli → core}/codegen/mutations.js +0 -0
- /package/{cli → core}/codegen/orm/barrel.d.ts +0 -0
- /package/{cli → core}/codegen/orm/barrel.js +0 -0
- /package/{cli → core}/codegen/orm/client-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/client.d.ts +0 -0
- /package/{cli → core}/codegen/orm/client.js +0 -0
- /package/{cli → core}/codegen/orm/custom-ops-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/custom-ops-generator.js +0 -0
- /package/{cli → core}/codegen/orm/input-types-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/input-types-generator.js +0 -0
- /package/{cli → core}/codegen/orm/model-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/model-generator.js +0 -0
- /package/{cli → core}/codegen/orm/query-builder.d.ts +0 -0
- /package/{cli → core}/codegen/orm/query-builder.js +0 -0
- /package/{cli → core}/codegen/orm/query-builder.ts +0 -0
- /package/{cli → core}/codegen/orm/select-types.d.ts +0 -0
- /package/{cli → core}/codegen/orm/select-types.js +0 -0
- /package/{cli → core}/codegen/queries.d.ts +0 -0
- /package/{cli → core}/codegen/queries.js +0 -0
- /package/{cli → core}/codegen/query-keys.js +0 -0
- /package/{cli → core}/codegen/scalars.d.ts +0 -0
- /package/{cli → core}/codegen/scalars.js +0 -0
- /package/{cli → core}/codegen/schema-gql-ast.d.ts +0 -0
- /package/{cli → core}/codegen/schema-gql-ast.js +0 -0
- /package/{cli → core}/codegen/schema-types-generator.d.ts +0 -0
- /package/{cli → core}/codegen/schema-types-generator.js +0 -0
- /package/{cli → core}/codegen/type-resolver.d.ts +0 -0
- /package/{cli → core}/codegen/type-resolver.js +0 -0
- /package/{cli → core}/codegen/types.d.ts +0 -0
- /package/{cli → core}/codegen/types.js +0 -0
- /package/{cli → core}/codegen/utils.d.ts +0 -0
- /package/{cli → core}/codegen/utils.js +0 -0
- /package/{cli → core}/introspect/fetch-schema.d.ts +0 -0
- /package/{cli → core}/introspect/index.d.ts +0 -0
- /package/{cli → core}/introspect/index.js +0 -0
- /package/{cli → core}/introspect/infer-tables.d.ts +0 -0
- /package/{cli → core}/introspect/infer-tables.js +0 -0
- /package/{cli → core}/introspect/schema-query.d.ts +0 -0
- /package/{cli → core}/introspect/schema-query.js +0 -0
- /package/{cli → core}/introspect/source/endpoint.d.ts +0 -0
- /package/{cli → core}/introspect/source/endpoint.js +0 -0
- /package/{cli → core}/introspect/source/file.d.ts +0 -0
- /package/{cli → core}/introspect/source/file.js +0 -0
- /package/{cli → core}/introspect/source/types.d.ts +0 -0
- /package/{cli → core}/introspect/source/types.js +0 -0
- /package/{cli → core}/introspect/transform-schema.d.ts +0 -0
- /package/{cli → core}/introspect/transform-schema.js +0 -0
- /package/{cli → core}/introspect/transform.d.ts +0 -0
- /package/{cli → core}/introspect/transform.js +0 -0
- /package/{cli → core}/watch/cache.d.ts +0 -0
- /package/{cli → core}/watch/cache.js +0 -0
- /package/{cli → core}/watch/debounce.d.ts +0 -0
- /package/{cli → core}/watch/debounce.js +0 -0
- /package/{cli → core}/watch/hash.d.ts +0 -0
- /package/{cli → core}/watch/hash.js +0 -0
- /package/{cli → core}/watch/index.d.ts +0 -0
- /package/{cli → core}/watch/index.js +0 -0
- /package/{cli → core}/watch/poller.d.ts +0 -0
- /package/{cli → core}/watch/poller.js +0 -0
- /package/{cli → core}/watch/types.js +0 -0
- /package/esm/{cli → core}/codegen/babel-ast.d.ts +0 -0
- /package/esm/{cli → core}/codegen/babel-ast.js +0 -0
- /package/esm/{cli → core}/codegen/client.d.ts +0 -0
- /package/esm/{cli → core}/codegen/client.js +0 -0
- /package/esm/{cli → core}/codegen/custom-mutations.d.ts +0 -0
- /package/esm/{cli → core}/codegen/custom-mutations.js +0 -0
- /package/esm/{cli → core}/codegen/custom-queries.d.ts +0 -0
- /package/esm/{cli → core}/codegen/custom-queries.js +0 -0
- /package/esm/{cli → core}/codegen/gql-ast.d.ts +0 -0
- /package/esm/{cli → core}/codegen/gql-ast.js +0 -0
- /package/esm/{cli → core}/codegen/invalidation.js +0 -0
- /package/esm/{cli → core}/codegen/mutation-keys.js +0 -0
- /package/esm/{cli → core}/codegen/mutations.d.ts +0 -0
- /package/esm/{cli → core}/codegen/mutations.js +0 -0
- /package/esm/{cli → core}/codegen/orm/barrel.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/barrel.js +0 -0
- /package/esm/{cli → core}/codegen/orm/client-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/client.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/client.js +0 -0
- /package/esm/{cli → core}/codegen/orm/custom-ops-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/custom-ops-generator.js +0 -0
- /package/esm/{cli → core}/codegen/orm/input-types-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/input-types-generator.js +0 -0
- /package/esm/{cli → core}/codegen/orm/model-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/model-generator.js +0 -0
- /package/esm/{cli → core}/codegen/orm/query-builder.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/query-builder.js +0 -0
- /package/esm/{cli → core}/codegen/orm/select-types.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/select-types.js +0 -0
- /package/esm/{cli → core}/codegen/queries.d.ts +0 -0
- /package/esm/{cli → core}/codegen/queries.js +0 -0
- /package/esm/{cli → core}/codegen/query-keys.js +0 -0
- /package/esm/{cli → core}/codegen/scalars.d.ts +0 -0
- /package/esm/{cli → core}/codegen/scalars.js +0 -0
- /package/esm/{cli → core}/codegen/schema-gql-ast.d.ts +0 -0
- /package/esm/{cli → core}/codegen/schema-gql-ast.js +0 -0
- /package/esm/{cli → core}/codegen/schema-types-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/schema-types-generator.js +0 -0
- /package/esm/{cli → core}/codegen/type-resolver.d.ts +0 -0
- /package/esm/{cli → core}/codegen/type-resolver.js +0 -0
- /package/esm/{cli → core}/codegen/types.d.ts +0 -0
- /package/esm/{cli → core}/codegen/types.js +0 -0
- /package/esm/{cli → core}/codegen/utils.d.ts +0 -0
- /package/esm/{cli → core}/codegen/utils.js +0 -0
- /package/esm/{cli → core}/introspect/fetch-schema.d.ts +0 -0
- /package/esm/{cli → core}/introspect/index.d.ts +0 -0
- /package/esm/{cli → core}/introspect/index.js +0 -0
- /package/esm/{cli → core}/introspect/infer-tables.d.ts +0 -0
- /package/esm/{cli → core}/introspect/infer-tables.js +0 -0
- /package/esm/{cli → core}/introspect/schema-query.d.ts +0 -0
- /package/esm/{cli → core}/introspect/schema-query.js +0 -0
- /package/esm/{cli → core}/introspect/source/endpoint.d.ts +0 -0
- /package/esm/{cli → core}/introspect/source/endpoint.js +0 -0
- /package/esm/{cli → core}/introspect/source/file.d.ts +0 -0
- /package/esm/{cli → core}/introspect/source/file.js +0 -0
- /package/esm/{cli → core}/introspect/source/types.d.ts +0 -0
- /package/esm/{cli → core}/introspect/source/types.js +0 -0
- /package/esm/{cli → core}/introspect/transform-schema.d.ts +0 -0
- /package/esm/{cli → core}/introspect/transform-schema.js +0 -0
- /package/esm/{cli → core}/introspect/transform.d.ts +0 -0
- /package/esm/{cli → core}/introspect/transform.js +0 -0
- /package/esm/{cli → core}/watch/cache.d.ts +0 -0
- /package/esm/{cli → core}/watch/cache.js +0 -0
- /package/esm/{cli → core}/watch/debounce.d.ts +0 -0
- /package/esm/{cli → core}/watch/debounce.js +0 -0
- /package/esm/{cli → core}/watch/hash.d.ts +0 -0
- /package/esm/{cli → core}/watch/hash.js +0 -0
- /package/esm/{cli → core}/watch/index.d.ts +0 -0
- /package/esm/{cli → core}/watch/index.js +0 -0
- /package/esm/{cli → core}/watch/poller.d.ts +0 -0
- /package/esm/{cli → core}/watch/poller.js +0 -0
- /package/esm/{cli → core}/watch/types.js +0 -0
|
@@ -1,37 +1,86 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.fetchSchema = fetchSchema;
|
|
4
7
|
/**
|
|
5
8
|
* Fetch GraphQL schema introspection from an endpoint
|
|
6
9
|
*/
|
|
10
|
+
const node_dns_1 = __importDefault(require("node:dns"));
|
|
11
|
+
const undici_1 = require("undici");
|
|
7
12
|
const schema_query_1 = require("./schema-query");
|
|
13
|
+
/**
|
|
14
|
+
* Check if a hostname is localhost or a localhost subdomain
|
|
15
|
+
*/
|
|
16
|
+
function isLocalhostHostname(hostname) {
|
|
17
|
+
return hostname === 'localhost' || hostname.endsWith('.localhost');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create an undici Agent that resolves *.localhost to 127.0.0.1
|
|
21
|
+
* This fixes DNS resolution issues on macOS where subdomains like api.localhost
|
|
22
|
+
* don't resolve automatically (unlike browsers which handle *.localhost).
|
|
23
|
+
*/
|
|
24
|
+
function createLocalhostAgent() {
|
|
25
|
+
return new undici_1.Agent({
|
|
26
|
+
connect: {
|
|
27
|
+
lookup(hostname, opts, cb) {
|
|
28
|
+
if (isLocalhostHostname(hostname)) {
|
|
29
|
+
cb(null, '127.0.0.1', 4);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
node_dns_1.default.lookup(hostname, opts, cb);
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
let localhostAgent = null;
|
|
38
|
+
function getLocalhostAgent() {
|
|
39
|
+
if (!localhostAgent) {
|
|
40
|
+
localhostAgent = createLocalhostAgent();
|
|
41
|
+
}
|
|
42
|
+
return localhostAgent;
|
|
43
|
+
}
|
|
8
44
|
/**
|
|
9
45
|
* Fetch the full schema introspection from a GraphQL endpoint
|
|
10
46
|
*/
|
|
11
47
|
async function fetchSchema(options) {
|
|
12
48
|
const { endpoint, authorization, headers = {}, timeout = 30000 } = options;
|
|
49
|
+
// Parse the endpoint URL to check for localhost
|
|
50
|
+
const url = new URL(endpoint);
|
|
51
|
+
const useLocalhostAgent = isLocalhostHostname(url.hostname);
|
|
13
52
|
// Build headers
|
|
14
53
|
const requestHeaders = {
|
|
15
54
|
'Content-Type': 'application/json',
|
|
16
55
|
Accept: 'application/json',
|
|
17
56
|
...headers,
|
|
18
57
|
};
|
|
58
|
+
// Set Host header for localhost subdomains to preserve routing
|
|
59
|
+
if (useLocalhostAgent && url.hostname !== 'localhost') {
|
|
60
|
+
requestHeaders['Host'] = url.hostname;
|
|
61
|
+
}
|
|
19
62
|
if (authorization) {
|
|
20
63
|
requestHeaders['Authorization'] = authorization;
|
|
21
64
|
}
|
|
22
65
|
// Create abort controller for timeout
|
|
23
66
|
const controller = new AbortController();
|
|
24
67
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
68
|
+
// Build fetch options
|
|
69
|
+
const fetchOptions = {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: requestHeaders,
|
|
72
|
+
body: JSON.stringify({
|
|
73
|
+
query: schema_query_1.SCHEMA_INTROSPECTION_QUERY,
|
|
74
|
+
variables: {},
|
|
75
|
+
}),
|
|
76
|
+
signal: controller.signal,
|
|
77
|
+
};
|
|
78
|
+
// Use custom agent for localhost to fix DNS resolution on macOS
|
|
79
|
+
if (useLocalhostAgent) {
|
|
80
|
+
fetchOptions.dispatcher = getLocalhostAgent();
|
|
81
|
+
}
|
|
25
82
|
try {
|
|
26
|
-
const response = await fetch(endpoint,
|
|
27
|
-
method: 'POST',
|
|
28
|
-
headers: requestHeaders,
|
|
29
|
-
body: JSON.stringify({
|
|
30
|
-
query: schema_query_1.SCHEMA_INTROSPECTION_QUERY,
|
|
31
|
-
variables: {},
|
|
32
|
-
}),
|
|
33
|
-
signal: controller.signal,
|
|
34
|
-
});
|
|
83
|
+
const response = await fetch(endpoint, fetchOptions);
|
|
35
84
|
clearTimeout(timeoutId);
|
|
36
85
|
if (!response.ok) {
|
|
37
86
|
return {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Schemas Resolution
|
|
3
|
+
*
|
|
4
|
+
* Utilities for resolving PostgreSQL schema names from API names
|
|
5
|
+
* by querying the services_public.api_schemas table.
|
|
6
|
+
*/
|
|
7
|
+
import { Pool } from 'pg';
|
|
8
|
+
/**
|
|
9
|
+
* Result of validating services schema requirements
|
|
10
|
+
*/
|
|
11
|
+
export interface ServicesSchemaValidation {
|
|
12
|
+
valid: boolean;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Validate that the required services schemas exist in the database
|
|
17
|
+
*
|
|
18
|
+
* Checks for:
|
|
19
|
+
* - services_public schema with apis and api_schemas tables
|
|
20
|
+
* - metaschema_public schema with schema table
|
|
21
|
+
*
|
|
22
|
+
* @param pool - Database connection pool
|
|
23
|
+
* @returns Validation result
|
|
24
|
+
*/
|
|
25
|
+
export declare function validateServicesSchemas(pool: Pool): Promise<ServicesSchemaValidation>;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve schema names from API names by querying services_public.api_schemas
|
|
28
|
+
*
|
|
29
|
+
* Joins services_public.apis, services_public.api_schemas, and metaschema_public.schema
|
|
30
|
+
* to get the actual PostgreSQL schema names for the given API names.
|
|
31
|
+
*
|
|
32
|
+
* @param pool - Database connection pool
|
|
33
|
+
* @param apiNames - Array of API names to resolve
|
|
34
|
+
* @returns Array of PostgreSQL schema names
|
|
35
|
+
* @throws Error if validation fails or no schemas found
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveApiSchemas(pool: Pool, apiNames: string[]): Promise<string[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Create a database pool for the given database name or connection string
|
|
40
|
+
*
|
|
41
|
+
* @param database - Database name or connection string
|
|
42
|
+
* @returns Database connection pool
|
|
43
|
+
*/
|
|
44
|
+
export declare function createDatabasePool(database: string): Pool;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateServicesSchemas = validateServicesSchemas;
|
|
4
|
+
exports.resolveApiSchemas = resolveApiSchemas;
|
|
5
|
+
exports.createDatabasePool = createDatabasePool;
|
|
6
|
+
const pg_cache_1 = require("pg-cache");
|
|
7
|
+
const pg_env_1 = require("pg-env");
|
|
8
|
+
/**
|
|
9
|
+
* Validate that the required services schemas exist in the database
|
|
10
|
+
*
|
|
11
|
+
* Checks for:
|
|
12
|
+
* - services_public schema with apis and api_schemas tables
|
|
13
|
+
* - metaschema_public schema with schema table
|
|
14
|
+
*
|
|
15
|
+
* @param pool - Database connection pool
|
|
16
|
+
* @returns Validation result
|
|
17
|
+
*/
|
|
18
|
+
async function validateServicesSchemas(pool) {
|
|
19
|
+
try {
|
|
20
|
+
// Check for services_public.apis table
|
|
21
|
+
const apisCheck = await pool.query(`
|
|
22
|
+
SELECT 1 FROM information_schema.tables
|
|
23
|
+
WHERE table_schema = 'services_public'
|
|
24
|
+
AND table_name = 'apis'
|
|
25
|
+
`);
|
|
26
|
+
if (apisCheck.rows.length === 0) {
|
|
27
|
+
return {
|
|
28
|
+
valid: false,
|
|
29
|
+
error: 'services_public.apis table not found. The database must have the services schema deployed.',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// Check for services_public.api_schemas table
|
|
33
|
+
const apiSchemasCheck = await pool.query(`
|
|
34
|
+
SELECT 1 FROM information_schema.tables
|
|
35
|
+
WHERE table_schema = 'services_public'
|
|
36
|
+
AND table_name = 'api_schemas'
|
|
37
|
+
`);
|
|
38
|
+
if (apiSchemasCheck.rows.length === 0) {
|
|
39
|
+
return {
|
|
40
|
+
valid: false,
|
|
41
|
+
error: 'services_public.api_schemas table not found. The database must have the services schema deployed.',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Check for metaschema_public.schema table
|
|
45
|
+
const metaschemaCheck = await pool.query(`
|
|
46
|
+
SELECT 1 FROM information_schema.tables
|
|
47
|
+
WHERE table_schema = 'metaschema_public'
|
|
48
|
+
AND table_name = 'schema'
|
|
49
|
+
`);
|
|
50
|
+
if (metaschemaCheck.rows.length === 0) {
|
|
51
|
+
return {
|
|
52
|
+
valid: false,
|
|
53
|
+
error: 'metaschema_public.schema table not found. The database must have the metaschema deployed.',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return { valid: true };
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
return {
|
|
60
|
+
valid: false,
|
|
61
|
+
error: `Failed to validate services schemas: ${err instanceof Error ? err.message : 'Unknown error'}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Resolve schema names from API names by querying services_public.api_schemas
|
|
67
|
+
*
|
|
68
|
+
* Joins services_public.apis, services_public.api_schemas, and metaschema_public.schema
|
|
69
|
+
* to get the actual PostgreSQL schema names for the given API names.
|
|
70
|
+
*
|
|
71
|
+
* @param pool - Database connection pool
|
|
72
|
+
* @param apiNames - Array of API names to resolve
|
|
73
|
+
* @returns Array of PostgreSQL schema names
|
|
74
|
+
* @throws Error if validation fails or no schemas found
|
|
75
|
+
*/
|
|
76
|
+
async function resolveApiSchemas(pool, apiNames) {
|
|
77
|
+
// First validate that the required schemas exist
|
|
78
|
+
const validation = await validateServicesSchemas(pool);
|
|
79
|
+
if (!validation.valid) {
|
|
80
|
+
throw new Error(validation.error);
|
|
81
|
+
}
|
|
82
|
+
// Query to get schema names for the given API names
|
|
83
|
+
const result = await pool.query(`
|
|
84
|
+
SELECT DISTINCT ms.schema_name
|
|
85
|
+
FROM services_public.api_schemas as_tbl
|
|
86
|
+
JOIN services_public.apis api ON api.id = as_tbl.api_id
|
|
87
|
+
JOIN metaschema_public.schema ms ON ms.id = as_tbl.schema_id
|
|
88
|
+
WHERE api.name = ANY($1)
|
|
89
|
+
ORDER BY ms.schema_name
|
|
90
|
+
`, [apiNames]);
|
|
91
|
+
if (result.rows.length === 0) {
|
|
92
|
+
throw new Error(`No schemas found for API names: ${apiNames.join(', ')}. ` +
|
|
93
|
+
'Ensure the APIs exist and have schemas assigned in services_public.api_schemas.');
|
|
94
|
+
}
|
|
95
|
+
return result.rows.map((row) => row.schema_name);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Create a database pool for the given database name or connection string
|
|
99
|
+
*
|
|
100
|
+
* @param database - Database name or connection string
|
|
101
|
+
* @returns Database connection pool
|
|
102
|
+
*/
|
|
103
|
+
function createDatabasePool(database) {
|
|
104
|
+
// Check if it's a connection string or just a database name
|
|
105
|
+
const isConnectionString = database.startsWith('postgres://') || database.startsWith('postgresql://');
|
|
106
|
+
if (isConnectionString) {
|
|
107
|
+
// Parse connection string and extract database name
|
|
108
|
+
// Format: postgres://user:password@host:port/database
|
|
109
|
+
const url = new URL(database);
|
|
110
|
+
const dbName = url.pathname.slice(1); // Remove leading slash
|
|
111
|
+
return (0, pg_cache_1.getPgPool)({
|
|
112
|
+
host: url.hostname,
|
|
113
|
+
port: parseInt(url.port || '5432', 10),
|
|
114
|
+
user: url.username,
|
|
115
|
+
password: url.password,
|
|
116
|
+
database: dbName,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
// Use environment variables for connection, just override database name
|
|
120
|
+
const config = (0, pg_env_1.getPgEnvOptions)({ database });
|
|
121
|
+
return (0, pg_cache_1.getPgPool)(config);
|
|
122
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { SchemaSource, SchemaSourceResult } from './types';
|
|
2
|
+
export interface DatabaseSchemaSourceOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Database name or connection string
|
|
5
|
+
* Can be a simple database name (uses PGHOST, PGPORT, PGUSER, PGPASSWORD env vars)
|
|
6
|
+
* or a full connection string (postgres://user:pass@host:port/dbname)
|
|
7
|
+
*/
|
|
8
|
+
database: string;
|
|
9
|
+
/**
|
|
10
|
+
* PostgreSQL schemas to include in introspection
|
|
11
|
+
* Mutually exclusive with apiNames
|
|
12
|
+
*/
|
|
13
|
+
schemas?: string[];
|
|
14
|
+
/**
|
|
15
|
+
* API names to resolve schemas from
|
|
16
|
+
* Queries services_public.api_schemas to get schema names
|
|
17
|
+
* Mutually exclusive with schemas
|
|
18
|
+
*/
|
|
19
|
+
apiNames?: string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Schema source that loads from a PostgreSQL database
|
|
23
|
+
*
|
|
24
|
+
* Uses PostGraphile to introspect the database and generate a GraphQL schema.
|
|
25
|
+
* The schema is built in-memory without writing to disk.
|
|
26
|
+
*/
|
|
27
|
+
export declare class DatabaseSchemaSource implements SchemaSource {
|
|
28
|
+
private readonly options;
|
|
29
|
+
constructor(options: DatabaseSchemaSourceOptions);
|
|
30
|
+
fetch(): Promise<SchemaSourceResult>;
|
|
31
|
+
describe(): string;
|
|
32
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DatabaseSchemaSource = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Database Schema Source
|
|
6
|
+
*
|
|
7
|
+
* Loads GraphQL schema directly from a PostgreSQL database using PostGraphile
|
|
8
|
+
* introspection and converts it to introspection format.
|
|
9
|
+
*/
|
|
10
|
+
const graphql_1 = require("graphql");
|
|
11
|
+
const types_1 = require("./types");
|
|
12
|
+
const database_1 = require("../../database");
|
|
13
|
+
const api_schemas_1 = require("./api-schemas");
|
|
14
|
+
/**
|
|
15
|
+
* Schema source that loads from a PostgreSQL database
|
|
16
|
+
*
|
|
17
|
+
* Uses PostGraphile to introspect the database and generate a GraphQL schema.
|
|
18
|
+
* The schema is built in-memory without writing to disk.
|
|
19
|
+
*/
|
|
20
|
+
class DatabaseSchemaSource {
|
|
21
|
+
options;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.options = options;
|
|
24
|
+
}
|
|
25
|
+
async fetch() {
|
|
26
|
+
const { database, apiNames } = this.options;
|
|
27
|
+
// Resolve schemas - either from explicit schemas option or from apiNames
|
|
28
|
+
let schemas;
|
|
29
|
+
if (apiNames && apiNames.length > 0) {
|
|
30
|
+
// Validate services schemas exist at the beginning for database mode
|
|
31
|
+
const pool = (0, api_schemas_1.createDatabasePool)(database);
|
|
32
|
+
try {
|
|
33
|
+
const validation = await (0, api_schemas_1.validateServicesSchemas)(pool);
|
|
34
|
+
if (!validation.valid) {
|
|
35
|
+
throw new types_1.SchemaSourceError(validation.error, this.describe());
|
|
36
|
+
}
|
|
37
|
+
schemas = await (0, api_schemas_1.resolveApiSchemas)(pool, apiNames);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
if (err instanceof types_1.SchemaSourceError)
|
|
41
|
+
throw err;
|
|
42
|
+
throw new types_1.SchemaSourceError(`Failed to resolve API schemas: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
schemas = this.options.schemas ?? ['public'];
|
|
47
|
+
}
|
|
48
|
+
// Build SDL from database
|
|
49
|
+
let sdl;
|
|
50
|
+
try {
|
|
51
|
+
sdl = await (0, database_1.buildSchemaSDLFromDatabase)({
|
|
52
|
+
database,
|
|
53
|
+
schemas,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
throw new types_1.SchemaSourceError(`Failed to introspect database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
|
|
58
|
+
}
|
|
59
|
+
// Validate non-empty
|
|
60
|
+
if (!sdl.trim()) {
|
|
61
|
+
throw new types_1.SchemaSourceError('Database introspection returned empty schema', this.describe());
|
|
62
|
+
}
|
|
63
|
+
// Parse SDL to GraphQL schema
|
|
64
|
+
let schema;
|
|
65
|
+
try {
|
|
66
|
+
schema = (0, graphql_1.buildSchema)(sdl);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
throw new types_1.SchemaSourceError(`Invalid GraphQL SDL from database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
|
|
70
|
+
}
|
|
71
|
+
// Convert to introspection format
|
|
72
|
+
let introspectionResult;
|
|
73
|
+
try {
|
|
74
|
+
introspectionResult = (0, graphql_1.introspectionFromSchema)(schema);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
throw new types_1.SchemaSourceError(`Failed to generate introspection: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
|
|
78
|
+
}
|
|
79
|
+
// Convert graphql-js introspection result to our mutable type
|
|
80
|
+
const introspection = JSON.parse(JSON.stringify(introspectionResult));
|
|
81
|
+
return { introspection };
|
|
82
|
+
}
|
|
83
|
+
describe() {
|
|
84
|
+
const { database, schemas, apiNames } = this.options;
|
|
85
|
+
if (apiNames && apiNames.length > 0) {
|
|
86
|
+
return `database: ${database} (apiNames: ${apiNames.join(', ')})`;
|
|
87
|
+
}
|
|
88
|
+
return `database: ${database} (schemas: ${(schemas ?? ['public']).join(', ')})`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.DatabaseSchemaSource = DatabaseSchemaSource;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema Source Module
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified interface for loading GraphQL schemas from different sources:
|
|
5
|
+
* - Live GraphQL endpoints (via introspection)
|
|
6
|
+
* - Static .graphql schema files
|
|
7
|
+
* - PostgreSQL databases (via PostGraphile introspection)
|
|
8
|
+
* - PGPM modules (via ephemeral database deployment)
|
|
9
|
+
*/
|
|
10
|
+
export * from './types';
|
|
11
|
+
export * from './endpoint';
|
|
12
|
+
export * from './file';
|
|
13
|
+
export * from './database';
|
|
14
|
+
export * from './pgpm-module';
|
|
15
|
+
export * from './api-schemas';
|
|
16
|
+
import type { SchemaSource } from './types';
|
|
17
|
+
import type { DbConfig } from '../../../types/config';
|
|
18
|
+
/**
|
|
19
|
+
* Options for endpoint-based schema source
|
|
20
|
+
*/
|
|
21
|
+
export interface EndpointSourceOptions {
|
|
22
|
+
endpoint: string;
|
|
23
|
+
authorization?: string;
|
|
24
|
+
headers?: Record<string, string>;
|
|
25
|
+
timeout?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Options for file-based schema source
|
|
29
|
+
*/
|
|
30
|
+
export interface FileSourceOptions {
|
|
31
|
+
schemaFile: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Options for database-based schema source
|
|
35
|
+
*/
|
|
36
|
+
export interface DatabaseSourceOptions {
|
|
37
|
+
database: string;
|
|
38
|
+
schemas?: string[];
|
|
39
|
+
apiNames?: string[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Options for PGPM module-based schema source (direct path)
|
|
43
|
+
*/
|
|
44
|
+
export interface PgpmModulePathSourceOptions {
|
|
45
|
+
pgpmModulePath: string;
|
|
46
|
+
schemas?: string[];
|
|
47
|
+
apiNames?: string[];
|
|
48
|
+
keepDb?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Options for PGPM module-based schema source (workspace + module name)
|
|
52
|
+
*/
|
|
53
|
+
export interface PgpmWorkspaceSourceOptions {
|
|
54
|
+
pgpmWorkspacePath: string;
|
|
55
|
+
pgpmModuleName: string;
|
|
56
|
+
schemas?: string[];
|
|
57
|
+
apiNames?: string[];
|
|
58
|
+
keepDb?: boolean;
|
|
59
|
+
}
|
|
60
|
+
export interface CreateSchemaSourceOptions {
|
|
61
|
+
/**
|
|
62
|
+
* GraphQL endpoint URL (for live introspection)
|
|
63
|
+
*/
|
|
64
|
+
endpoint?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Path to GraphQL schema file (.graphql)
|
|
67
|
+
*/
|
|
68
|
+
schemaFile?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Database configuration for direct database introspection or PGPM module
|
|
71
|
+
*/
|
|
72
|
+
db?: DbConfig;
|
|
73
|
+
/**
|
|
74
|
+
* Optional authorization header for endpoint requests
|
|
75
|
+
*/
|
|
76
|
+
authorization?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Optional additional headers for endpoint requests
|
|
79
|
+
*/
|
|
80
|
+
headers?: Record<string, string>;
|
|
81
|
+
/**
|
|
82
|
+
* Request timeout in milliseconds (for endpoint requests)
|
|
83
|
+
*/
|
|
84
|
+
timeout?: number;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Detect which source mode is being used based on options
|
|
88
|
+
*/
|
|
89
|
+
export type SourceMode = 'endpoint' | 'schemaFile' | 'database' | 'pgpm-module' | 'pgpm-workspace';
|
|
90
|
+
export declare function detectSourceMode(options: CreateSchemaSourceOptions): SourceMode | null;
|
|
91
|
+
/**
|
|
92
|
+
* Create a schema source based on configuration
|
|
93
|
+
*
|
|
94
|
+
* Supports five modes:
|
|
95
|
+
* - endpoint: Introspect from a live GraphQL endpoint
|
|
96
|
+
* - schemaFile: Load from a local .graphql file
|
|
97
|
+
* - database: Introspect directly from a PostgreSQL database
|
|
98
|
+
* - pgpm-module: Deploy a PGPM module to an ephemeral database and introspect
|
|
99
|
+
* - pgpm-workspace: Deploy a module from a PGPM workspace to an ephemeral database and introspect
|
|
100
|
+
*
|
|
101
|
+
* @param options - Source configuration
|
|
102
|
+
* @returns Appropriate SchemaSource implementation
|
|
103
|
+
* @throws Error if no valid source is provided
|
|
104
|
+
*/
|
|
105
|
+
export declare function createSchemaSource(options: CreateSchemaSourceOptions): SchemaSource;
|
|
106
|
+
/**
|
|
107
|
+
* Validate that source options are valid (exactly one source specified)
|
|
108
|
+
*/
|
|
109
|
+
export declare function validateSourceOptions(options: CreateSchemaSourceOptions): {
|
|
110
|
+
valid: boolean;
|
|
111
|
+
error?: string;
|
|
112
|
+
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.detectSourceMode = detectSourceMode;
|
|
18
|
+
exports.createSchemaSource = createSchemaSource;
|
|
19
|
+
exports.validateSourceOptions = validateSourceOptions;
|
|
20
|
+
/**
|
|
21
|
+
* Schema Source Module
|
|
22
|
+
*
|
|
23
|
+
* Provides a unified interface for loading GraphQL schemas from different sources:
|
|
24
|
+
* - Live GraphQL endpoints (via introspection)
|
|
25
|
+
* - Static .graphql schema files
|
|
26
|
+
* - PostgreSQL databases (via PostGraphile introspection)
|
|
27
|
+
* - PGPM modules (via ephemeral database deployment)
|
|
28
|
+
*/
|
|
29
|
+
__exportStar(require("./types"), exports);
|
|
30
|
+
__exportStar(require("./endpoint"), exports);
|
|
31
|
+
__exportStar(require("./file"), exports);
|
|
32
|
+
__exportStar(require("./database"), exports);
|
|
33
|
+
__exportStar(require("./pgpm-module"), exports);
|
|
34
|
+
__exportStar(require("./api-schemas"), exports);
|
|
35
|
+
const endpoint_1 = require("./endpoint");
|
|
36
|
+
const file_1 = require("./file");
|
|
37
|
+
const database_1 = require("./database");
|
|
38
|
+
const pgpm_module_1 = require("./pgpm-module");
|
|
39
|
+
function detectSourceMode(options) {
|
|
40
|
+
if (options.endpoint)
|
|
41
|
+
return 'endpoint';
|
|
42
|
+
if (options.schemaFile)
|
|
43
|
+
return 'schemaFile';
|
|
44
|
+
if (options.db) {
|
|
45
|
+
// Check for PGPM modes first
|
|
46
|
+
if (options.db.pgpm?.modulePath)
|
|
47
|
+
return 'pgpm-module';
|
|
48
|
+
if (options.db.pgpm?.workspacePath && options.db.pgpm?.moduleName)
|
|
49
|
+
return 'pgpm-workspace';
|
|
50
|
+
// Default to database mode if db is specified without pgpm
|
|
51
|
+
return 'database';
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Create a schema source based on configuration
|
|
57
|
+
*
|
|
58
|
+
* Supports five modes:
|
|
59
|
+
* - endpoint: Introspect from a live GraphQL endpoint
|
|
60
|
+
* - schemaFile: Load from a local .graphql file
|
|
61
|
+
* - database: Introspect directly from a PostgreSQL database
|
|
62
|
+
* - pgpm-module: Deploy a PGPM module to an ephemeral database and introspect
|
|
63
|
+
* - pgpm-workspace: Deploy a module from a PGPM workspace to an ephemeral database and introspect
|
|
64
|
+
*
|
|
65
|
+
* @param options - Source configuration
|
|
66
|
+
* @returns Appropriate SchemaSource implementation
|
|
67
|
+
* @throws Error if no valid source is provided
|
|
68
|
+
*/
|
|
69
|
+
function createSchemaSource(options) {
|
|
70
|
+
const mode = detectSourceMode(options);
|
|
71
|
+
switch (mode) {
|
|
72
|
+
case 'schemaFile':
|
|
73
|
+
return new file_1.FileSchemaSource({
|
|
74
|
+
schemaPath: options.schemaFile,
|
|
75
|
+
});
|
|
76
|
+
case 'endpoint':
|
|
77
|
+
return new endpoint_1.EndpointSchemaSource({
|
|
78
|
+
endpoint: options.endpoint,
|
|
79
|
+
authorization: options.authorization,
|
|
80
|
+
headers: options.headers,
|
|
81
|
+
timeout: options.timeout,
|
|
82
|
+
});
|
|
83
|
+
case 'database':
|
|
84
|
+
// Database mode uses db.config for connection (falls back to env vars)
|
|
85
|
+
// and db.schemas or db.apiNames for schema selection
|
|
86
|
+
return new database_1.DatabaseSchemaSource({
|
|
87
|
+
database: options.db?.config?.database ?? '',
|
|
88
|
+
schemas: options.db?.schemas,
|
|
89
|
+
apiNames: options.db?.apiNames,
|
|
90
|
+
});
|
|
91
|
+
case 'pgpm-module':
|
|
92
|
+
return new pgpm_module_1.PgpmModuleSchemaSource({
|
|
93
|
+
pgpmModulePath: options.db.pgpm.modulePath,
|
|
94
|
+
schemas: options.db?.schemas,
|
|
95
|
+
apiNames: options.db?.apiNames,
|
|
96
|
+
keepDb: options.db?.keepDb,
|
|
97
|
+
});
|
|
98
|
+
case 'pgpm-workspace':
|
|
99
|
+
return new pgpm_module_1.PgpmModuleSchemaSource({
|
|
100
|
+
pgpmWorkspacePath: options.db.pgpm.workspacePath,
|
|
101
|
+
pgpmModuleName: options.db.pgpm.moduleName,
|
|
102
|
+
schemas: options.db?.schemas,
|
|
103
|
+
apiNames: options.db?.apiNames,
|
|
104
|
+
keepDb: options.db?.keepDb,
|
|
105
|
+
});
|
|
106
|
+
default:
|
|
107
|
+
throw new Error('No source specified. Use one of: endpoint, schemaFile, or db (with optional pgpm for module deployment).');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Validate that source options are valid (exactly one source specified)
|
|
112
|
+
*/
|
|
113
|
+
function validateSourceOptions(options) {
|
|
114
|
+
// Count primary sources
|
|
115
|
+
const sources = [
|
|
116
|
+
options.endpoint,
|
|
117
|
+
options.schemaFile,
|
|
118
|
+
options.db,
|
|
119
|
+
].filter(Boolean);
|
|
120
|
+
if (sources.length === 0) {
|
|
121
|
+
return {
|
|
122
|
+
valid: false,
|
|
123
|
+
error: 'No source specified. Use one of: endpoint, schemaFile, or db.',
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (sources.length > 1) {
|
|
127
|
+
return {
|
|
128
|
+
valid: false,
|
|
129
|
+
error: 'Multiple sources specified. Use only one of: endpoint, schemaFile, or db.',
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
// Validate pgpm workspace mode has both required fields
|
|
133
|
+
if (options.db?.pgpm) {
|
|
134
|
+
const pgpm = options.db.pgpm;
|
|
135
|
+
if (pgpm.workspacePath && !pgpm.moduleName) {
|
|
136
|
+
return {
|
|
137
|
+
valid: false,
|
|
138
|
+
error: 'db.pgpm.workspacePath requires db.pgpm.moduleName to be specified.',
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
if (pgpm.moduleName && !pgpm.workspacePath) {
|
|
142
|
+
return {
|
|
143
|
+
valid: false,
|
|
144
|
+
error: 'db.pgpm.moduleName requires db.pgpm.workspacePath to be specified.',
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
// Must have either modulePath or workspacePath+moduleName
|
|
148
|
+
if (!pgpm.modulePath && !(pgpm.workspacePath && pgpm.moduleName)) {
|
|
149
|
+
return {
|
|
150
|
+
valid: false,
|
|
151
|
+
error: 'db.pgpm requires either modulePath or both workspacePath and moduleName.',
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// For database mode, validate schemas/apiNames mutual exclusivity
|
|
156
|
+
if (options.db) {
|
|
157
|
+
const hasSchemas = options.db.schemas && options.db.schemas.length > 0;
|
|
158
|
+
const hasApiNames = options.db.apiNames && options.db.apiNames.length > 0;
|
|
159
|
+
if (hasSchemas && hasApiNames) {
|
|
160
|
+
return {
|
|
161
|
+
valid: false,
|
|
162
|
+
error: 'Cannot specify both db.schemas and db.apiNames. Use one or the other.',
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
if (!hasSchemas && !hasApiNames) {
|
|
166
|
+
return {
|
|
167
|
+
valid: false,
|
|
168
|
+
error: 'Must specify either db.schemas or db.apiNames for database mode.',
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return { valid: true };
|
|
173
|
+
}
|