@constructive-io/graphql-codegen 2.31.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.
Files changed (270) hide show
  1. package/README.md +429 -1691
  2. package/cli/index.d.ts +5 -2
  3. package/cli/index.js +98 -581
  4. package/cli/shared.d.ts +35 -0
  5. package/cli/shared.js +106 -0
  6. package/{esm/cli → core}/codegen/barrel.d.ts +1 -1
  7. package/{cli → core}/codegen/barrel.js +1 -4
  8. package/{esm/cli → core}/codegen/index.d.ts +15 -5
  9. package/{cli → core}/codegen/index.js +44 -24
  10. package/{cli → core}/codegen/invalidation.d.ts +2 -2
  11. package/{esm/cli → core}/codegen/mutation-keys.d.ts +2 -2
  12. package/{cli → core}/codegen/orm/client-generator.js +2 -3
  13. package/{esm/cli → core}/codegen/orm/index.d.ts +9 -2
  14. package/{cli → core}/codegen/orm/index.js +3 -2
  15. package/{cli → core}/codegen/query-keys.d.ts +2 -2
  16. package/core/codegen/shared/index.d.ts +39 -0
  17. package/core/codegen/shared/index.js +118 -0
  18. package/core/config/index.d.ts +5 -0
  19. package/core/config/index.js +13 -0
  20. package/core/config/loader.d.ts +18 -0
  21. package/{cli/commands/init.js → core/config/loader.js} +7 -94
  22. package/core/config/resolver.d.ts +46 -0
  23. package/core/config/resolver.js +104 -0
  24. package/core/database/index.d.ts +43 -0
  25. package/core/database/index.js +85 -0
  26. package/core/generate.d.ts +22 -0
  27. package/core/generate.js +192 -0
  28. package/core/index.d.ts +13 -1
  29. package/core/index.js +22 -2
  30. package/{cli → core}/introspect/fetch-schema.js +58 -9
  31. package/core/introspect/source/api-schemas.d.ts +44 -0
  32. package/core/introspect/source/api-schemas.js +122 -0
  33. package/core/introspect/source/database.d.ts +32 -0
  34. package/core/introspect/source/database.js +91 -0
  35. package/core/introspect/source/index.d.ts +112 -0
  36. package/core/introspect/source/index.js +173 -0
  37. package/core/introspect/source/pgpm-module.d.ts +83 -0
  38. package/core/introspect/source/pgpm-module.js +200 -0
  39. package/core/output/index.d.ts +4 -0
  40. package/core/output/index.js +9 -0
  41. package/core/output/writer.d.ts +38 -0
  42. package/core/output/writer.js +156 -0
  43. package/{cli/commands/shared.d.ts → core/pipeline/index.d.ts} +5 -3
  44. package/{cli/commands/shared.js → core/pipeline/index.js} +12 -5
  45. package/{cli → core}/watch/orchestrator.d.ts +25 -3
  46. package/{cli → core}/watch/orchestrator.js +35 -27
  47. package/{cli → core}/watch/types.d.ts +1 -1
  48. package/esm/cli/index.d.ts +5 -2
  49. package/esm/cli/index.js +97 -547
  50. package/esm/cli/shared.d.ts +35 -0
  51. package/esm/cli/shared.js +101 -0
  52. package/{cli → esm/core}/codegen/barrel.d.ts +1 -1
  53. package/esm/{cli → core}/codegen/barrel.js +1 -4
  54. package/{cli → esm/core}/codegen/index.d.ts +15 -5
  55. package/esm/{cli → core}/codegen/index.js +44 -24
  56. package/esm/{cli → core}/codegen/invalidation.d.ts +2 -2
  57. package/{cli → esm/core}/codegen/mutation-keys.d.ts +2 -2
  58. package/esm/{cli → core}/codegen/orm/client-generator.js +2 -3
  59. package/{cli → esm/core}/codegen/orm/index.d.ts +9 -2
  60. package/esm/{cli → core}/codegen/orm/index.js +3 -2
  61. package/esm/{cli → core}/codegen/query-keys.d.ts +2 -2
  62. package/esm/core/codegen/shared/index.d.ts +39 -0
  63. package/esm/core/codegen/shared/index.js +79 -0
  64. package/esm/core/config/index.d.ts +5 -0
  65. package/esm/core/config/index.js +5 -0
  66. package/esm/core/config/loader.d.ts +18 -0
  67. package/esm/core/config/loader.js +71 -0
  68. package/esm/core/config/resolver.d.ts +46 -0
  69. package/esm/core/config/resolver.js +100 -0
  70. package/esm/core/database/index.d.ts +43 -0
  71. package/esm/core/database/index.js +48 -0
  72. package/esm/core/generate.d.ts +22 -0
  73. package/esm/core/generate.js +186 -0
  74. package/esm/core/index.d.ts +13 -1
  75. package/esm/core/index.js +20 -1
  76. package/esm/{cli → core}/introspect/fetch-schema.js +55 -9
  77. package/esm/core/introspect/source/api-schemas.d.ts +44 -0
  78. package/esm/core/introspect/source/api-schemas.js +117 -0
  79. package/esm/core/introspect/source/database.d.ts +32 -0
  80. package/esm/core/introspect/source/database.js +87 -0
  81. package/esm/core/introspect/source/index.d.ts +112 -0
  82. package/esm/core/introspect/source/index.js +154 -0
  83. package/esm/core/introspect/source/pgpm-module.d.ts +83 -0
  84. package/esm/core/introspect/source/pgpm-module.js +194 -0
  85. package/esm/core/output/index.d.ts +4 -0
  86. package/esm/core/output/index.js +4 -0
  87. package/esm/core/output/writer.d.ts +38 -0
  88. package/esm/core/output/writer.js +119 -0
  89. package/esm/{cli/commands/shared.d.ts → core/pipeline/index.d.ts} +5 -3
  90. package/esm/{cli/commands/shared.js → core/pipeline/index.js} +9 -5
  91. package/esm/{cli → core}/watch/orchestrator.d.ts +25 -3
  92. package/esm/{cli → core}/watch/orchestrator.js +35 -27
  93. package/esm/{cli → core}/watch/types.d.ts +1 -1
  94. package/esm/index.d.ts +8 -3
  95. package/esm/index.js +9 -3
  96. package/esm/types/config.d.ts +110 -136
  97. package/esm/types/config.js +23 -148
  98. package/esm/types/index.d.ts +2 -2
  99. package/esm/types/index.js +1 -1
  100. package/index.d.ts +8 -3
  101. package/index.js +18 -8
  102. package/package.json +19 -11
  103. package/types/config.d.ts +110 -136
  104. package/types/config.js +28 -152
  105. package/types/index.d.ts +2 -2
  106. package/types/index.js +3 -3
  107. package/cli/commands/generate-orm.d.ts +0 -53
  108. package/cli/commands/generate-orm.js +0 -292
  109. package/cli/commands/generate.d.ts +0 -66
  110. package/cli/commands/generate.js +0 -431
  111. package/cli/commands/index.d.ts +0 -9
  112. package/cli/commands/index.js +0 -14
  113. package/cli/commands/init.d.ts +0 -35
  114. package/cli/introspect/source/index.d.ts +0 -48
  115. package/cli/introspect/source/index.js +0 -72
  116. package/esm/cli/commands/generate-orm.d.ts +0 -53
  117. package/esm/cli/commands/generate-orm.js +0 -289
  118. package/esm/cli/commands/generate.d.ts +0 -66
  119. package/esm/cli/commands/generate.js +0 -393
  120. package/esm/cli/commands/index.d.ts +0 -9
  121. package/esm/cli/commands/index.js +0 -6
  122. package/esm/cli/commands/init.d.ts +0 -35
  123. package/esm/cli/commands/init.js +0 -158
  124. package/esm/cli/introspect/source/index.d.ts +0 -48
  125. package/esm/cli/introspect/source/index.js +0 -54
  126. /package/{cli → core}/codegen/babel-ast.d.ts +0 -0
  127. /package/{cli → core}/codegen/babel-ast.js +0 -0
  128. /package/{cli → core}/codegen/client.d.ts +0 -0
  129. /package/{cli → core}/codegen/client.js +0 -0
  130. /package/{cli → core}/codegen/custom-mutations.d.ts +0 -0
  131. /package/{cli → core}/codegen/custom-mutations.js +0 -0
  132. /package/{cli → core}/codegen/custom-queries.d.ts +0 -0
  133. /package/{cli → core}/codegen/custom-queries.js +0 -0
  134. /package/{cli → core}/codegen/gql-ast.d.ts +0 -0
  135. /package/{cli → core}/codegen/gql-ast.js +0 -0
  136. /package/{cli → core}/codegen/invalidation.js +0 -0
  137. /package/{cli → core}/codegen/mutation-keys.js +0 -0
  138. /package/{cli → core}/codegen/mutations.d.ts +0 -0
  139. /package/{cli → core}/codegen/mutations.js +0 -0
  140. /package/{cli → core}/codegen/orm/barrel.d.ts +0 -0
  141. /package/{cli → core}/codegen/orm/barrel.js +0 -0
  142. /package/{cli → core}/codegen/orm/client-generator.d.ts +0 -0
  143. /package/{cli → core}/codegen/orm/client.d.ts +0 -0
  144. /package/{cli → core}/codegen/orm/client.js +0 -0
  145. /package/{cli → core}/codegen/orm/custom-ops-generator.d.ts +0 -0
  146. /package/{cli → core}/codegen/orm/custom-ops-generator.js +0 -0
  147. /package/{cli → core}/codegen/orm/input-types-generator.d.ts +0 -0
  148. /package/{cli → core}/codegen/orm/input-types-generator.js +0 -0
  149. /package/{cli → core}/codegen/orm/model-generator.d.ts +0 -0
  150. /package/{cli → core}/codegen/orm/model-generator.js +0 -0
  151. /package/{cli → core}/codegen/orm/query-builder.d.ts +0 -0
  152. /package/{cli → core}/codegen/orm/query-builder.js +0 -0
  153. /package/{cli → core}/codegen/orm/query-builder.ts +0 -0
  154. /package/{cli → core}/codegen/orm/select-types.d.ts +0 -0
  155. /package/{cli → core}/codegen/orm/select-types.js +0 -0
  156. /package/{cli → core}/codegen/queries.d.ts +0 -0
  157. /package/{cli → core}/codegen/queries.js +0 -0
  158. /package/{cli → core}/codegen/query-keys.js +0 -0
  159. /package/{cli → core}/codegen/scalars.d.ts +0 -0
  160. /package/{cli → core}/codegen/scalars.js +0 -0
  161. /package/{cli → core}/codegen/schema-gql-ast.d.ts +0 -0
  162. /package/{cli → core}/codegen/schema-gql-ast.js +0 -0
  163. /package/{cli → core}/codegen/schema-types-generator.d.ts +0 -0
  164. /package/{cli → core}/codegen/schema-types-generator.js +0 -0
  165. /package/{cli → core}/codegen/type-resolver.d.ts +0 -0
  166. /package/{cli → core}/codegen/type-resolver.js +0 -0
  167. /package/{cli → core}/codegen/types.d.ts +0 -0
  168. /package/{cli → core}/codegen/types.js +0 -0
  169. /package/{cli → core}/codegen/utils.d.ts +0 -0
  170. /package/{cli → core}/codegen/utils.js +0 -0
  171. /package/{cli → core}/introspect/fetch-schema.d.ts +0 -0
  172. /package/{cli → core}/introspect/index.d.ts +0 -0
  173. /package/{cli → core}/introspect/index.js +0 -0
  174. /package/{cli → core}/introspect/infer-tables.d.ts +0 -0
  175. /package/{cli → core}/introspect/infer-tables.js +0 -0
  176. /package/{cli → core}/introspect/schema-query.d.ts +0 -0
  177. /package/{cli → core}/introspect/schema-query.js +0 -0
  178. /package/{cli → core}/introspect/source/endpoint.d.ts +0 -0
  179. /package/{cli → core}/introspect/source/endpoint.js +0 -0
  180. /package/{cli → core}/introspect/source/file.d.ts +0 -0
  181. /package/{cli → core}/introspect/source/file.js +0 -0
  182. /package/{cli → core}/introspect/source/types.d.ts +0 -0
  183. /package/{cli → core}/introspect/source/types.js +0 -0
  184. /package/{cli → core}/introspect/transform-schema.d.ts +0 -0
  185. /package/{cli → core}/introspect/transform-schema.js +0 -0
  186. /package/{cli → core}/introspect/transform.d.ts +0 -0
  187. /package/{cli → core}/introspect/transform.js +0 -0
  188. /package/{cli → core}/watch/cache.d.ts +0 -0
  189. /package/{cli → core}/watch/cache.js +0 -0
  190. /package/{cli → core}/watch/debounce.d.ts +0 -0
  191. /package/{cli → core}/watch/debounce.js +0 -0
  192. /package/{cli → core}/watch/hash.d.ts +0 -0
  193. /package/{cli → core}/watch/hash.js +0 -0
  194. /package/{cli → core}/watch/index.d.ts +0 -0
  195. /package/{cli → core}/watch/index.js +0 -0
  196. /package/{cli → core}/watch/poller.d.ts +0 -0
  197. /package/{cli → core}/watch/poller.js +0 -0
  198. /package/{cli → core}/watch/types.js +0 -0
  199. /package/esm/{cli → core}/codegen/babel-ast.d.ts +0 -0
  200. /package/esm/{cli → core}/codegen/babel-ast.js +0 -0
  201. /package/esm/{cli → core}/codegen/client.d.ts +0 -0
  202. /package/esm/{cli → core}/codegen/client.js +0 -0
  203. /package/esm/{cli → core}/codegen/custom-mutations.d.ts +0 -0
  204. /package/esm/{cli → core}/codegen/custom-mutations.js +0 -0
  205. /package/esm/{cli → core}/codegen/custom-queries.d.ts +0 -0
  206. /package/esm/{cli → core}/codegen/custom-queries.js +0 -0
  207. /package/esm/{cli → core}/codegen/gql-ast.d.ts +0 -0
  208. /package/esm/{cli → core}/codegen/gql-ast.js +0 -0
  209. /package/esm/{cli → core}/codegen/invalidation.js +0 -0
  210. /package/esm/{cli → core}/codegen/mutation-keys.js +0 -0
  211. /package/esm/{cli → core}/codegen/mutations.d.ts +0 -0
  212. /package/esm/{cli → core}/codegen/mutations.js +0 -0
  213. /package/esm/{cli → core}/codegen/orm/barrel.d.ts +0 -0
  214. /package/esm/{cli → core}/codegen/orm/barrel.js +0 -0
  215. /package/esm/{cli → core}/codegen/orm/client-generator.d.ts +0 -0
  216. /package/esm/{cli → core}/codegen/orm/client.d.ts +0 -0
  217. /package/esm/{cli → core}/codegen/orm/client.js +0 -0
  218. /package/esm/{cli → core}/codegen/orm/custom-ops-generator.d.ts +0 -0
  219. /package/esm/{cli → core}/codegen/orm/custom-ops-generator.js +0 -0
  220. /package/esm/{cli → core}/codegen/orm/input-types-generator.d.ts +0 -0
  221. /package/esm/{cli → core}/codegen/orm/input-types-generator.js +0 -0
  222. /package/esm/{cli → core}/codegen/orm/model-generator.d.ts +0 -0
  223. /package/esm/{cli → core}/codegen/orm/model-generator.js +0 -0
  224. /package/esm/{cli → core}/codegen/orm/query-builder.d.ts +0 -0
  225. /package/esm/{cli → core}/codegen/orm/query-builder.js +0 -0
  226. /package/esm/{cli → core}/codegen/orm/select-types.d.ts +0 -0
  227. /package/esm/{cli → core}/codegen/orm/select-types.js +0 -0
  228. /package/esm/{cli → core}/codegen/queries.d.ts +0 -0
  229. /package/esm/{cli → core}/codegen/queries.js +0 -0
  230. /package/esm/{cli → core}/codegen/query-keys.js +0 -0
  231. /package/esm/{cli → core}/codegen/scalars.d.ts +0 -0
  232. /package/esm/{cli → core}/codegen/scalars.js +0 -0
  233. /package/esm/{cli → core}/codegen/schema-gql-ast.d.ts +0 -0
  234. /package/esm/{cli → core}/codegen/schema-gql-ast.js +0 -0
  235. /package/esm/{cli → core}/codegen/schema-types-generator.d.ts +0 -0
  236. /package/esm/{cli → core}/codegen/schema-types-generator.js +0 -0
  237. /package/esm/{cli → core}/codegen/type-resolver.d.ts +0 -0
  238. /package/esm/{cli → core}/codegen/type-resolver.js +0 -0
  239. /package/esm/{cli → core}/codegen/types.d.ts +0 -0
  240. /package/esm/{cli → core}/codegen/types.js +0 -0
  241. /package/esm/{cli → core}/codegen/utils.d.ts +0 -0
  242. /package/esm/{cli → core}/codegen/utils.js +0 -0
  243. /package/esm/{cli → core}/introspect/fetch-schema.d.ts +0 -0
  244. /package/esm/{cli → core}/introspect/index.d.ts +0 -0
  245. /package/esm/{cli → core}/introspect/index.js +0 -0
  246. /package/esm/{cli → core}/introspect/infer-tables.d.ts +0 -0
  247. /package/esm/{cli → core}/introspect/infer-tables.js +0 -0
  248. /package/esm/{cli → core}/introspect/schema-query.d.ts +0 -0
  249. /package/esm/{cli → core}/introspect/schema-query.js +0 -0
  250. /package/esm/{cli → core}/introspect/source/endpoint.d.ts +0 -0
  251. /package/esm/{cli → core}/introspect/source/endpoint.js +0 -0
  252. /package/esm/{cli → core}/introspect/source/file.d.ts +0 -0
  253. /package/esm/{cli → core}/introspect/source/file.js +0 -0
  254. /package/esm/{cli → core}/introspect/source/types.d.ts +0 -0
  255. /package/esm/{cli → core}/introspect/source/types.js +0 -0
  256. /package/esm/{cli → core}/introspect/transform-schema.d.ts +0 -0
  257. /package/esm/{cli → core}/introspect/transform-schema.js +0 -0
  258. /package/esm/{cli → core}/introspect/transform.d.ts +0 -0
  259. /package/esm/{cli → core}/introspect/transform.js +0 -0
  260. /package/esm/{cli → core}/watch/cache.d.ts +0 -0
  261. /package/esm/{cli → core}/watch/cache.js +0 -0
  262. /package/esm/{cli → core}/watch/debounce.d.ts +0 -0
  263. /package/esm/{cli → core}/watch/debounce.js +0 -0
  264. /package/esm/{cli → core}/watch/hash.d.ts +0 -0
  265. /package/esm/{cli → core}/watch/hash.js +0 -0
  266. /package/esm/{cli → core}/watch/index.d.ts +0 -0
  267. /package/esm/{cli → core}/watch/index.js +0 -0
  268. /package/esm/{cli → core}/watch/poller.d.ts +0 -0
  269. /package/esm/{cli → core}/watch/poller.js +0 -0
  270. /package/esm/{cli → core}/watch/types.js +0 -0
@@ -0,0 +1,117 @@
1
+ import { getPgPool } from 'pg-cache';
2
+ import { getPgEnvOptions } from 'pg-env';
3
+ /**
4
+ * Validate that the required services schemas exist in the database
5
+ *
6
+ * Checks for:
7
+ * - services_public schema with apis and api_schemas tables
8
+ * - metaschema_public schema with schema table
9
+ *
10
+ * @param pool - Database connection pool
11
+ * @returns Validation result
12
+ */
13
+ export async function validateServicesSchemas(pool) {
14
+ try {
15
+ // Check for services_public.apis table
16
+ const apisCheck = await pool.query(`
17
+ SELECT 1 FROM information_schema.tables
18
+ WHERE table_schema = 'services_public'
19
+ AND table_name = 'apis'
20
+ `);
21
+ if (apisCheck.rows.length === 0) {
22
+ return {
23
+ valid: false,
24
+ error: 'services_public.apis table not found. The database must have the services schema deployed.',
25
+ };
26
+ }
27
+ // Check for services_public.api_schemas table
28
+ const apiSchemasCheck = await pool.query(`
29
+ SELECT 1 FROM information_schema.tables
30
+ WHERE table_schema = 'services_public'
31
+ AND table_name = 'api_schemas'
32
+ `);
33
+ if (apiSchemasCheck.rows.length === 0) {
34
+ return {
35
+ valid: false,
36
+ error: 'services_public.api_schemas table not found. The database must have the services schema deployed.',
37
+ };
38
+ }
39
+ // Check for metaschema_public.schema table
40
+ const metaschemaCheck = await pool.query(`
41
+ SELECT 1 FROM information_schema.tables
42
+ WHERE table_schema = 'metaschema_public'
43
+ AND table_name = 'schema'
44
+ `);
45
+ if (metaschemaCheck.rows.length === 0) {
46
+ return {
47
+ valid: false,
48
+ error: 'metaschema_public.schema table not found. The database must have the metaschema deployed.',
49
+ };
50
+ }
51
+ return { valid: true };
52
+ }
53
+ catch (err) {
54
+ return {
55
+ valid: false,
56
+ error: `Failed to validate services schemas: ${err instanceof Error ? err.message : 'Unknown error'}`,
57
+ };
58
+ }
59
+ }
60
+ /**
61
+ * Resolve schema names from API names by querying services_public.api_schemas
62
+ *
63
+ * Joins services_public.apis, services_public.api_schemas, and metaschema_public.schema
64
+ * to get the actual PostgreSQL schema names for the given API names.
65
+ *
66
+ * @param pool - Database connection pool
67
+ * @param apiNames - Array of API names to resolve
68
+ * @returns Array of PostgreSQL schema names
69
+ * @throws Error if validation fails or no schemas found
70
+ */
71
+ export async function resolveApiSchemas(pool, apiNames) {
72
+ // First validate that the required schemas exist
73
+ const validation = await validateServicesSchemas(pool);
74
+ if (!validation.valid) {
75
+ throw new Error(validation.error);
76
+ }
77
+ // Query to get schema names for the given API names
78
+ const result = await pool.query(`
79
+ SELECT DISTINCT ms.schema_name
80
+ FROM services_public.api_schemas as_tbl
81
+ JOIN services_public.apis api ON api.id = as_tbl.api_id
82
+ JOIN metaschema_public.schema ms ON ms.id = as_tbl.schema_id
83
+ WHERE api.name = ANY($1)
84
+ ORDER BY ms.schema_name
85
+ `, [apiNames]);
86
+ if (result.rows.length === 0) {
87
+ throw new Error(`No schemas found for API names: ${apiNames.join(', ')}. ` +
88
+ 'Ensure the APIs exist and have schemas assigned in services_public.api_schemas.');
89
+ }
90
+ return result.rows.map((row) => row.schema_name);
91
+ }
92
+ /**
93
+ * Create a database pool for the given database name or connection string
94
+ *
95
+ * @param database - Database name or connection string
96
+ * @returns Database connection pool
97
+ */
98
+ export function createDatabasePool(database) {
99
+ // Check if it's a connection string or just a database name
100
+ const isConnectionString = database.startsWith('postgres://') || database.startsWith('postgresql://');
101
+ if (isConnectionString) {
102
+ // Parse connection string and extract database name
103
+ // Format: postgres://user:password@host:port/database
104
+ const url = new URL(database);
105
+ const dbName = url.pathname.slice(1); // Remove leading slash
106
+ return getPgPool({
107
+ host: url.hostname,
108
+ port: parseInt(url.port || '5432', 10),
109
+ user: url.username,
110
+ password: url.password,
111
+ database: dbName,
112
+ });
113
+ }
114
+ // Use environment variables for connection, just override database name
115
+ const config = getPgEnvOptions({ database });
116
+ return getPgPool(config);
117
+ }
@@ -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,87 @@
1
+ /**
2
+ * Database Schema Source
3
+ *
4
+ * Loads GraphQL schema directly from a PostgreSQL database using PostGraphile
5
+ * introspection and converts it to introspection format.
6
+ */
7
+ import { buildSchema, introspectionFromSchema } from 'graphql';
8
+ import { SchemaSourceError } from './types';
9
+ import { buildSchemaSDLFromDatabase } from '../../database';
10
+ import { createDatabasePool, resolveApiSchemas, validateServicesSchemas } from './api-schemas';
11
+ /**
12
+ * Schema source that loads from a PostgreSQL database
13
+ *
14
+ * Uses PostGraphile to introspect the database and generate a GraphQL schema.
15
+ * The schema is built in-memory without writing to disk.
16
+ */
17
+ export class DatabaseSchemaSource {
18
+ options;
19
+ constructor(options) {
20
+ this.options = options;
21
+ }
22
+ async fetch() {
23
+ const { database, apiNames } = this.options;
24
+ // Resolve schemas - either from explicit schemas option or from apiNames
25
+ let schemas;
26
+ if (apiNames && apiNames.length > 0) {
27
+ // Validate services schemas exist at the beginning for database mode
28
+ const pool = createDatabasePool(database);
29
+ try {
30
+ const validation = await validateServicesSchemas(pool);
31
+ if (!validation.valid) {
32
+ throw new SchemaSourceError(validation.error, this.describe());
33
+ }
34
+ schemas = await resolveApiSchemas(pool, apiNames);
35
+ }
36
+ catch (err) {
37
+ if (err instanceof SchemaSourceError)
38
+ throw err;
39
+ throw new SchemaSourceError(`Failed to resolve API schemas: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
40
+ }
41
+ }
42
+ else {
43
+ schemas = this.options.schemas ?? ['public'];
44
+ }
45
+ // Build SDL from database
46
+ let sdl;
47
+ try {
48
+ sdl = await buildSchemaSDLFromDatabase({
49
+ database,
50
+ schemas,
51
+ });
52
+ }
53
+ catch (err) {
54
+ throw new SchemaSourceError(`Failed to introspect database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
55
+ }
56
+ // Validate non-empty
57
+ if (!sdl.trim()) {
58
+ throw new SchemaSourceError('Database introspection returned empty schema', this.describe());
59
+ }
60
+ // Parse SDL to GraphQL schema
61
+ let schema;
62
+ try {
63
+ schema = buildSchema(sdl);
64
+ }
65
+ catch (err) {
66
+ throw new SchemaSourceError(`Invalid GraphQL SDL from database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
67
+ }
68
+ // Convert to introspection format
69
+ let introspectionResult;
70
+ try {
71
+ introspectionResult = introspectionFromSchema(schema);
72
+ }
73
+ catch (err) {
74
+ throw new SchemaSourceError(`Failed to generate introspection: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
75
+ }
76
+ // Convert graphql-js introspection result to our mutable type
77
+ const introspection = JSON.parse(JSON.stringify(introspectionResult));
78
+ return { introspection };
79
+ }
80
+ describe() {
81
+ const { database, schemas, apiNames } = this.options;
82
+ if (apiNames && apiNames.length > 0) {
83
+ return `database: ${database} (apiNames: ${apiNames.join(', ')})`;
84
+ }
85
+ return `database: ${database} (schemas: ${(schemas ?? ['public']).join(', ')})`;
86
+ }
87
+ }
@@ -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,154 @@
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 { EndpointSchemaSource } from './endpoint';
17
+ import { FileSchemaSource } from './file';
18
+ import { DatabaseSchemaSource } from './database';
19
+ import { PgpmModuleSchemaSource, } from './pgpm-module';
20
+ export function detectSourceMode(options) {
21
+ if (options.endpoint)
22
+ return 'endpoint';
23
+ if (options.schemaFile)
24
+ return 'schemaFile';
25
+ if (options.db) {
26
+ // Check for PGPM modes first
27
+ if (options.db.pgpm?.modulePath)
28
+ return 'pgpm-module';
29
+ if (options.db.pgpm?.workspacePath && options.db.pgpm?.moduleName)
30
+ return 'pgpm-workspace';
31
+ // Default to database mode if db is specified without pgpm
32
+ return 'database';
33
+ }
34
+ return null;
35
+ }
36
+ /**
37
+ * Create a schema source based on configuration
38
+ *
39
+ * Supports five modes:
40
+ * - endpoint: Introspect from a live GraphQL endpoint
41
+ * - schemaFile: Load from a local .graphql file
42
+ * - database: Introspect directly from a PostgreSQL database
43
+ * - pgpm-module: Deploy a PGPM module to an ephemeral database and introspect
44
+ * - pgpm-workspace: Deploy a module from a PGPM workspace to an ephemeral database and introspect
45
+ *
46
+ * @param options - Source configuration
47
+ * @returns Appropriate SchemaSource implementation
48
+ * @throws Error if no valid source is provided
49
+ */
50
+ export function createSchemaSource(options) {
51
+ const mode = detectSourceMode(options);
52
+ switch (mode) {
53
+ case 'schemaFile':
54
+ return new FileSchemaSource({
55
+ schemaPath: options.schemaFile,
56
+ });
57
+ case 'endpoint':
58
+ return new EndpointSchemaSource({
59
+ endpoint: options.endpoint,
60
+ authorization: options.authorization,
61
+ headers: options.headers,
62
+ timeout: options.timeout,
63
+ });
64
+ case 'database':
65
+ // Database mode uses db.config for connection (falls back to env vars)
66
+ // and db.schemas or db.apiNames for schema selection
67
+ return new DatabaseSchemaSource({
68
+ database: options.db?.config?.database ?? '',
69
+ schemas: options.db?.schemas,
70
+ apiNames: options.db?.apiNames,
71
+ });
72
+ case 'pgpm-module':
73
+ return new PgpmModuleSchemaSource({
74
+ pgpmModulePath: options.db.pgpm.modulePath,
75
+ schemas: options.db?.schemas,
76
+ apiNames: options.db?.apiNames,
77
+ keepDb: options.db?.keepDb,
78
+ });
79
+ case 'pgpm-workspace':
80
+ return new PgpmModuleSchemaSource({
81
+ pgpmWorkspacePath: options.db.pgpm.workspacePath,
82
+ pgpmModuleName: options.db.pgpm.moduleName,
83
+ schemas: options.db?.schemas,
84
+ apiNames: options.db?.apiNames,
85
+ keepDb: options.db?.keepDb,
86
+ });
87
+ default:
88
+ throw new Error('No source specified. Use one of: endpoint, schemaFile, or db (with optional pgpm for module deployment).');
89
+ }
90
+ }
91
+ /**
92
+ * Validate that source options are valid (exactly one source specified)
93
+ */
94
+ export function validateSourceOptions(options) {
95
+ // Count primary sources
96
+ const sources = [
97
+ options.endpoint,
98
+ options.schemaFile,
99
+ options.db,
100
+ ].filter(Boolean);
101
+ if (sources.length === 0) {
102
+ return {
103
+ valid: false,
104
+ error: 'No source specified. Use one of: endpoint, schemaFile, or db.',
105
+ };
106
+ }
107
+ if (sources.length > 1) {
108
+ return {
109
+ valid: false,
110
+ error: 'Multiple sources specified. Use only one of: endpoint, schemaFile, or db.',
111
+ };
112
+ }
113
+ // Validate pgpm workspace mode has both required fields
114
+ if (options.db?.pgpm) {
115
+ const pgpm = options.db.pgpm;
116
+ if (pgpm.workspacePath && !pgpm.moduleName) {
117
+ return {
118
+ valid: false,
119
+ error: 'db.pgpm.workspacePath requires db.pgpm.moduleName to be specified.',
120
+ };
121
+ }
122
+ if (pgpm.moduleName && !pgpm.workspacePath) {
123
+ return {
124
+ valid: false,
125
+ error: 'db.pgpm.moduleName requires db.pgpm.workspacePath to be specified.',
126
+ };
127
+ }
128
+ // Must have either modulePath or workspacePath+moduleName
129
+ if (!pgpm.modulePath && !(pgpm.workspacePath && pgpm.moduleName)) {
130
+ return {
131
+ valid: false,
132
+ error: 'db.pgpm requires either modulePath or both workspacePath and moduleName.',
133
+ };
134
+ }
135
+ }
136
+ // For database mode, validate schemas/apiNames mutual exclusivity
137
+ if (options.db) {
138
+ const hasSchemas = options.db.schemas && options.db.schemas.length > 0;
139
+ const hasApiNames = options.db.apiNames && options.db.apiNames.length > 0;
140
+ if (hasSchemas && hasApiNames) {
141
+ return {
142
+ valid: false,
143
+ error: 'Cannot specify both db.schemas and db.apiNames. Use one or the other.',
144
+ };
145
+ }
146
+ if (!hasSchemas && !hasApiNames) {
147
+ return {
148
+ valid: false,
149
+ error: 'Must specify either db.schemas or db.apiNames for database mode.',
150
+ };
151
+ }
152
+ }
153
+ return { valid: true };
154
+ }
@@ -0,0 +1,83 @@
1
+ import type { SchemaSource, SchemaSourceResult } from './types';
2
+ /**
3
+ * Options for PGPM module schema source using direct module path
4
+ */
5
+ export interface PgpmModulePathOptions {
6
+ /**
7
+ * Path to the PGPM module directory
8
+ * The directory should contain a pgpm.plan file and .control file
9
+ */
10
+ pgpmModulePath: string;
11
+ /**
12
+ * PostgreSQL schemas to include in introspection
13
+ * Mutually exclusive with apiNames
14
+ */
15
+ schemas?: string[];
16
+ /**
17
+ * API names to resolve schemas from
18
+ * Queries services_public.api_schemas to get schema names
19
+ * Mutually exclusive with schemas
20
+ */
21
+ apiNames?: string[];
22
+ /**
23
+ * If true, keeps the ephemeral database after introspection (useful for debugging)
24
+ * @default false
25
+ */
26
+ keepDb?: boolean;
27
+ }
28
+ /**
29
+ * Options for PGPM module schema source using workspace + module name
30
+ */
31
+ export interface PgpmWorkspaceOptions {
32
+ /**
33
+ * Path to the PGPM workspace directory
34
+ * The directory should contain a pgpm.config.yaml or similar workspace config
35
+ */
36
+ pgpmWorkspacePath: string;
37
+ /**
38
+ * Name of the module within the workspace
39
+ */
40
+ pgpmModuleName: string;
41
+ /**
42
+ * PostgreSQL schemas to include in introspection
43
+ * Mutually exclusive with apiNames
44
+ */
45
+ schemas?: string[];
46
+ /**
47
+ * API names to resolve schemas from
48
+ * Queries services_public.api_schemas to get schema names
49
+ * Mutually exclusive with schemas
50
+ */
51
+ apiNames?: string[];
52
+ /**
53
+ * If true, keeps the ephemeral database after introspection (useful for debugging)
54
+ * @default false
55
+ */
56
+ keepDb?: boolean;
57
+ }
58
+ export type PgpmModuleSchemaSourceOptions = PgpmModulePathOptions | PgpmWorkspaceOptions;
59
+ /**
60
+ * Type guard to check if options use direct module path
61
+ */
62
+ export declare function isPgpmModulePathOptions(options: PgpmModuleSchemaSourceOptions): options is PgpmModulePathOptions;
63
+ /**
64
+ * Type guard to check if options use workspace + module name
65
+ */
66
+ export declare function isPgpmWorkspaceOptions(options: PgpmModuleSchemaSourceOptions): options is PgpmWorkspaceOptions;
67
+ /**
68
+ * Schema source that loads from a PGPM module
69
+ *
70
+ * Creates an ephemeral database, deploys the module, introspects the schema,
71
+ * and cleans up. Supports both direct module path and workspace + module name modes.
72
+ */
73
+ export declare class PgpmModuleSchemaSource implements SchemaSource {
74
+ private readonly options;
75
+ private ephemeralDb;
76
+ constructor(options: PgpmModuleSchemaSourceOptions);
77
+ fetch(): Promise<SchemaSourceResult>;
78
+ describe(): string;
79
+ private resolveModulePath;
80
+ private getSchemas;
81
+ private getApiNames;
82
+ private getKeepDb;
83
+ }