@constructive-io/graphql-codegen 2.32.0 → 3.0.1

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} +4 -0
  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} +1 -0
  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 +101 -138
  97. package/esm/types/config.js +8 -35
  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 +18 -11
  103. package/types/config.d.ts +101 -138
  104. package/types/config.js +9 -38
  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,194 @@
1
+ /**
2
+ * PGPM Module Schema Source
3
+ *
4
+ * Loads GraphQL schema from a PGPM module by:
5
+ * 1. Creating an ephemeral database
6
+ * 2. Deploying the module to the database
7
+ * 3. Introspecting the database with PostGraphile
8
+ * 4. Cleaning up the ephemeral database (unless keepDb is true)
9
+ */
10
+ import { buildSchema, introspectionFromSchema } from 'graphql';
11
+ import { PgpmPackage } from '@pgpmjs/core';
12
+ import { createEphemeralDb } from 'pgsql-client';
13
+ import { deployPgpm } from 'pgsql-seed';
14
+ import { getPgPool } from 'pg-cache';
15
+ import { SchemaSourceError } from './types';
16
+ import { buildSchemaSDLFromDatabase } from '../../database';
17
+ import { resolveApiSchemas, validateServicesSchemas } from './api-schemas';
18
+ /**
19
+ * Type guard to check if options use direct module path
20
+ */
21
+ export function isPgpmModulePathOptions(options) {
22
+ return 'pgpmModulePath' in options;
23
+ }
24
+ /**
25
+ * Type guard to check if options use workspace + module name
26
+ */
27
+ export function isPgpmWorkspaceOptions(options) {
28
+ return 'pgpmWorkspacePath' in options && 'pgpmModuleName' in options;
29
+ }
30
+ /**
31
+ * Schema source that loads from a PGPM module
32
+ *
33
+ * Creates an ephemeral database, deploys the module, introspects the schema,
34
+ * and cleans up. Supports both direct module path and workspace + module name modes.
35
+ */
36
+ export class PgpmModuleSchemaSource {
37
+ options;
38
+ ephemeralDb = null;
39
+ constructor(options) {
40
+ this.options = options;
41
+ }
42
+ async fetch() {
43
+ const keepDb = this.getKeepDb();
44
+ const apiNames = this.getApiNames();
45
+ // Resolve the module path
46
+ let modulePath;
47
+ try {
48
+ modulePath = this.resolveModulePath();
49
+ }
50
+ catch (err) {
51
+ throw new SchemaSourceError(`Failed to resolve module path: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
52
+ }
53
+ // Validate the module exists
54
+ const pkg = new PgpmPackage(modulePath);
55
+ if (!pkg.isInModule()) {
56
+ throw new SchemaSourceError(`Not a valid PGPM module: ${modulePath}. Directory must contain pgpm.plan and .control files.`, this.describe());
57
+ }
58
+ // Create ephemeral database
59
+ try {
60
+ this.ephemeralDb = createEphemeralDb({
61
+ prefix: 'codegen_pgpm_',
62
+ verbose: false,
63
+ });
64
+ }
65
+ catch (err) {
66
+ throw new SchemaSourceError(`Failed to create ephemeral database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
67
+ }
68
+ const { config: dbConfig, teardown } = this.ephemeralDb;
69
+ try {
70
+ // Deploy the module to the ephemeral database
71
+ try {
72
+ await deployPgpm(dbConfig, modulePath, false);
73
+ }
74
+ catch (err) {
75
+ throw new SchemaSourceError(`Failed to deploy PGPM module: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
76
+ }
77
+ // Resolve schemas - either from explicit schemas option or from apiNames (after deployment)
78
+ let schemas;
79
+ if (apiNames && apiNames.length > 0) {
80
+ // For PGPM mode, validate services schemas AFTER migration
81
+ const pool = getPgPool(dbConfig);
82
+ try {
83
+ const validation = await validateServicesSchemas(pool);
84
+ if (!validation.valid) {
85
+ throw new SchemaSourceError(validation.error, this.describe());
86
+ }
87
+ schemas = await resolveApiSchemas(pool, apiNames);
88
+ }
89
+ catch (err) {
90
+ if (err instanceof SchemaSourceError)
91
+ throw err;
92
+ throw new SchemaSourceError(`Failed to resolve API schemas: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
93
+ }
94
+ }
95
+ else {
96
+ schemas = this.getSchemas();
97
+ }
98
+ // Build SDL from the deployed database
99
+ let sdl;
100
+ try {
101
+ sdl = await buildSchemaSDLFromDatabase({
102
+ database: dbConfig.database,
103
+ schemas,
104
+ });
105
+ }
106
+ catch (err) {
107
+ throw new SchemaSourceError(`Failed to introspect database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
108
+ }
109
+ // Validate non-empty
110
+ if (!sdl.trim()) {
111
+ throw new SchemaSourceError('Database introspection returned empty schema', this.describe());
112
+ }
113
+ // Parse SDL to GraphQL schema
114
+ let schema;
115
+ try {
116
+ schema = buildSchema(sdl);
117
+ }
118
+ catch (err) {
119
+ throw new SchemaSourceError(`Invalid GraphQL SDL from database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
120
+ }
121
+ // Convert to introspection format
122
+ let introspectionResult;
123
+ try {
124
+ introspectionResult = introspectionFromSchema(schema);
125
+ }
126
+ catch (err) {
127
+ throw new SchemaSourceError(`Failed to generate introspection: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
128
+ }
129
+ // Convert graphql-js introspection result to our mutable type
130
+ const introspection = JSON.parse(JSON.stringify(introspectionResult));
131
+ return { introspection };
132
+ }
133
+ finally {
134
+ // Clean up the ephemeral database
135
+ teardown({ keepDb });
136
+ if (keepDb) {
137
+ console.log(`[pgpm-module] Kept ephemeral database: ${dbConfig.database}`);
138
+ }
139
+ }
140
+ }
141
+ describe() {
142
+ const apiNames = this.getApiNames();
143
+ if (isPgpmModulePathOptions(this.options)) {
144
+ if (apiNames && apiNames.length > 0) {
145
+ return `pgpm module: ${this.options.pgpmModulePath} (apiNames: ${apiNames.join(', ')})`;
146
+ }
147
+ const schemas = this.options.schemas ?? ['public'];
148
+ return `pgpm module: ${this.options.pgpmModulePath} (schemas: ${schemas.join(', ')})`;
149
+ }
150
+ else {
151
+ if (apiNames && apiNames.length > 0) {
152
+ return `pgpm workspace: ${this.options.pgpmWorkspacePath}, module: ${this.options.pgpmModuleName} (apiNames: ${apiNames.join(', ')})`;
153
+ }
154
+ const schemas = this.options.schemas ?? ['public'];
155
+ return `pgpm workspace: ${this.options.pgpmWorkspacePath}, module: ${this.options.pgpmModuleName} (schemas: ${schemas.join(', ')})`;
156
+ }
157
+ }
158
+ resolveModulePath() {
159
+ if (isPgpmModulePathOptions(this.options)) {
160
+ return this.options.pgpmModulePath;
161
+ }
162
+ // Workspace + module name mode
163
+ const { pgpmWorkspacePath, pgpmModuleName } = this.options;
164
+ const workspace = new PgpmPackage(pgpmWorkspacePath);
165
+ if (!workspace.workspacePath) {
166
+ throw new Error(`Not a valid PGPM workspace: ${pgpmWorkspacePath}`);
167
+ }
168
+ // Get the module from the workspace
169
+ const moduleProject = workspace.getModuleProject(pgpmModuleName);
170
+ const modulePath = moduleProject.getModulePath();
171
+ if (!modulePath) {
172
+ throw new Error(`Module "${pgpmModuleName}" not found in workspace`);
173
+ }
174
+ return modulePath;
175
+ }
176
+ getSchemas() {
177
+ if (isPgpmModulePathOptions(this.options)) {
178
+ return this.options.schemas ?? ['public'];
179
+ }
180
+ return this.options.schemas ?? ['public'];
181
+ }
182
+ getApiNames() {
183
+ if (isPgpmModulePathOptions(this.options)) {
184
+ return this.options.apiNames;
185
+ }
186
+ return this.options.apiNames;
187
+ }
188
+ getKeepDb() {
189
+ if (isPgpmModulePathOptions(this.options)) {
190
+ return this.options.keepDb ?? false;
191
+ }
192
+ return this.options.keepDb ?? false;
193
+ }
194
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Output module exports
3
+ */
4
+ export { writeGeneratedFiles, formatOutput, type GeneratedFile, type WriteResult, type WriteOptions, } from './writer';
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Output module exports
3
+ */
4
+ export { writeGeneratedFiles, formatOutput, } from './writer';
@@ -0,0 +1,38 @@
1
+ import type { GeneratedFile } from '../codegen';
2
+ export type { GeneratedFile };
3
+ /**
4
+ * Result of writing files
5
+ */
6
+ export interface WriteResult {
7
+ success: boolean;
8
+ filesWritten?: string[];
9
+ errors?: string[];
10
+ }
11
+ /**
12
+ * Options for writing files
13
+ */
14
+ export interface WriteOptions {
15
+ /** Show progress output (default: true) */
16
+ showProgress?: boolean;
17
+ /** Format files with oxfmt after writing (default: true) */
18
+ formatFiles?: boolean;
19
+ }
20
+ /**
21
+ * Write generated files to disk
22
+ *
23
+ * @param files - Array of files to write
24
+ * @param outputDir - Base output directory
25
+ * @param subdirs - Subdirectories to create
26
+ * @param options - Write options
27
+ */
28
+ export declare function writeGeneratedFiles(files: GeneratedFile[], outputDir: string, subdirs: string[], options?: WriteOptions): Promise<WriteResult>;
29
+ /**
30
+ * Format generated files using oxfmt
31
+ *
32
+ * Runs oxfmt on the output directory after all files are written.
33
+ * Uses the same formatting options as prettier: single quotes, trailing commas, 2-space tabs, semicolons.
34
+ */
35
+ export declare function formatOutput(outputDir: string): {
36
+ success: boolean;
37
+ error?: string;
38
+ };
@@ -0,0 +1,119 @@
1
+ /**
2
+ * File writing utilities
3
+ *
4
+ * Pure functions for writing generated files to disk and formatting them.
5
+ * These are core utilities that can be used programmatically or by the CLI.
6
+ */
7
+ import * as fs from 'node:fs';
8
+ import * as path from 'node:path';
9
+ import { execSync } from 'node:child_process';
10
+ /**
11
+ * Write generated files to disk
12
+ *
13
+ * @param files - Array of files to write
14
+ * @param outputDir - Base output directory
15
+ * @param subdirs - Subdirectories to create
16
+ * @param options - Write options
17
+ */
18
+ export async function writeGeneratedFiles(files, outputDir, subdirs, options = {}) {
19
+ const { showProgress = true, formatFiles = true } = options;
20
+ const errors = [];
21
+ const written = [];
22
+ const total = files.length;
23
+ const isTTY = process.stdout.isTTY;
24
+ // Ensure output directory exists
25
+ try {
26
+ fs.mkdirSync(outputDir, { recursive: true });
27
+ }
28
+ catch (err) {
29
+ const message = err instanceof Error ? err.message : 'Unknown error';
30
+ return {
31
+ success: false,
32
+ errors: [`Failed to create output directory: ${message}`],
33
+ };
34
+ }
35
+ // Create subdirectories
36
+ for (const subdir of subdirs) {
37
+ const subdirPath = path.join(outputDir, subdir);
38
+ try {
39
+ fs.mkdirSync(subdirPath, { recursive: true });
40
+ }
41
+ catch (err) {
42
+ const message = err instanceof Error ? err.message : 'Unknown error';
43
+ errors.push(`Failed to create directory ${subdirPath}: ${message}`);
44
+ }
45
+ }
46
+ if (errors.length > 0) {
47
+ return { success: false, errors };
48
+ }
49
+ for (let i = 0; i < files.length; i++) {
50
+ const file = files[i];
51
+ const filePath = path.join(outputDir, file.path);
52
+ // Show progress
53
+ if (showProgress) {
54
+ const progress = Math.round(((i + 1) / total) * 100);
55
+ if (isTTY) {
56
+ process.stdout.write(`\rWriting files: ${i + 1}/${total} (${progress}%)`);
57
+ }
58
+ else if (i % 100 === 0 || i === total - 1) {
59
+ // Non-TTY: periodic updates for CI/CD
60
+ console.log(`Writing files: ${i + 1}/${total}`);
61
+ }
62
+ }
63
+ // Ensure parent directory exists
64
+ const parentDir = path.dirname(filePath);
65
+ try {
66
+ fs.mkdirSync(parentDir, { recursive: true });
67
+ }
68
+ catch {
69
+ // Ignore if already exists
70
+ }
71
+ try {
72
+ fs.writeFileSync(filePath, file.content, 'utf-8');
73
+ written.push(filePath);
74
+ }
75
+ catch (err) {
76
+ const message = err instanceof Error ? err.message : 'Unknown error';
77
+ errors.push(`Failed to write ${filePath}: ${message}`);
78
+ }
79
+ }
80
+ // Clear progress line
81
+ if (showProgress && isTTY) {
82
+ process.stdout.write('\r' + ' '.repeat(40) + '\r');
83
+ }
84
+ // Format all generated files with oxfmt
85
+ if (formatFiles && errors.length === 0) {
86
+ if (showProgress) {
87
+ console.log('Formatting generated files...');
88
+ }
89
+ const formatResult = formatOutput(outputDir);
90
+ if (!formatResult.success && showProgress) {
91
+ console.warn('Warning: Failed to format generated files:', formatResult.error);
92
+ }
93
+ }
94
+ return {
95
+ success: errors.length === 0,
96
+ filesWritten: written,
97
+ errors: errors.length > 0 ? errors : undefined,
98
+ };
99
+ }
100
+ /**
101
+ * Format generated files using oxfmt
102
+ *
103
+ * Runs oxfmt on the output directory after all files are written.
104
+ * Uses the same formatting options as prettier: single quotes, trailing commas, 2-space tabs, semicolons.
105
+ */
106
+ export function formatOutput(outputDir) {
107
+ const absoluteOutputDir = path.resolve(outputDir);
108
+ try {
109
+ execSync(`npx oxfmt --write "${absoluteOutputDir}"`, {
110
+ stdio: 'pipe',
111
+ encoding: 'utf-8',
112
+ });
113
+ return { success: true };
114
+ }
115
+ catch (err) {
116
+ const message = err instanceof Error ? err.message : String(err);
117
+ return { success: false, error: message };
118
+ }
119
+ }
@@ -8,18 +8,20 @@
8
8
  * - Operation transformation
9
9
  * - Filtering
10
10
  */
11
- import type { ResolvedConfig } from '../../types/config';
11
+ import type { GraphQLSDKConfigTarget } from '../../types/config';
12
12
  import type { CleanTable, CleanOperation, TypeRegistry } from '../../types/schema';
13
13
  import type { SchemaSource } from '../introspect/source';
14
+ export type { SchemaSource } from '../introspect/source';
15
+ export { createSchemaSource, validateSourceOptions } from '../introspect/source';
14
16
  export interface CodegenPipelineOptions {
15
17
  /**
16
18
  * Schema source (endpoint or file)
17
19
  */
18
20
  source: SchemaSource;
19
21
  /**
20
- * Resolved configuration
22
+ * Configuration
21
23
  */
22
- config: ResolvedConfig;
24
+ config: GraphQLSDKConfigTarget;
23
25
  /**
24
26
  * Enable verbose logging
25
27
  */
@@ -1,6 +1,7 @@
1
1
  import { inferTablesFromIntrospection } from '../introspect/infer-tables';
2
2
  import { filterTables } from '../introspect/transform';
3
3
  import { transformSchemaToOperations, filterOperations, getTableOperationNames, getCustomOperations, } from '../introspect/transform-schema';
4
+ export { createSchemaSource, validateSourceOptions } from '../introspect/source';
4
5
  // ============================================================================
5
6
  // Main Pipeline
6
7
  // ============================================================================
@@ -3,10 +3,28 @@
3
3
  *
4
4
  * Coordinates schema polling, change detection, and code regeneration
5
5
  */
6
- import type { ResolvedConfig } from '../../types/config';
6
+ import type { GraphQLSDKConfigTarget } from '../../types/config';
7
7
  import type { GeneratorType } from './types';
8
+ export interface GenerateFunction {
9
+ (options: {
10
+ config?: string;
11
+ target?: string;
12
+ endpoint?: string;
13
+ output?: string;
14
+ authorization?: string;
15
+ verbose?: boolean;
16
+ skipCustomOperations?: boolean;
17
+ }): Promise<GenerateResult>;
18
+ }
19
+ export interface GenerateResult {
20
+ success: boolean;
21
+ message: string;
22
+ tables?: string[];
23
+ filesWritten?: string[];
24
+ errors?: string[];
25
+ }
8
26
  export interface WatchOrchestratorOptions {
9
- config: ResolvedConfig;
27
+ config: GraphQLSDKConfigTarget;
10
28
  generatorType: GeneratorType;
11
29
  verbose: boolean;
12
30
  authorization?: string;
@@ -14,10 +32,14 @@ export interface WatchOrchestratorOptions {
14
32
  configPath?: string;
15
33
  /** Target name for multi-target configs */
16
34
  target?: string;
17
- /** Override output directory (for ORM) */
35
+ /** Override output directory */
18
36
  outputDir?: string;
19
37
  /** Skip custom operations flag */
20
38
  skipCustomOperations?: boolean;
39
+ /** Generator function for React Query SDK */
40
+ generateReactQuery: GenerateFunction;
41
+ /** Generator function for ORM client */
42
+ generateOrm: GenerateFunction;
21
43
  }
22
44
  export interface WatchStatus {
23
45
  isRunning: boolean;
@@ -5,8 +5,6 @@
5
5
  */
6
6
  import { SchemaPoller } from './poller';
7
7
  import { debounce } from './debounce';
8
- import { generateReactQuery } from '../commands/generate';
9
- import { generateOrm, } from '../commands/generate-orm';
10
8
  /**
11
9
  * Main watch orchestrator class
12
10
  */
@@ -131,29 +129,31 @@ export class WatchOrchestrator {
131
129
  }
132
130
  this.log('Regenerating...');
133
131
  try {
134
- let result;
135
- if (this.options.generatorType === 'generate') {
136
- result = await generateReactQuery({
137
- config: this.options.configPath,
138
- target: this.options.target,
139
- endpoint: this.options.config.endpoint,
140
- output: this.options.outputDir ?? this.options.config.output,
141
- authorization: this.options.authorization,
142
- verbose: this.watchOptions.verbose,
143
- skipCustomOperations: this.options.skipCustomOperations,
144
- });
145
- }
146
- else {
147
- result = await generateOrm({
148
- config: this.options.configPath,
149
- target: this.options.target,
150
- endpoint: this.options.config.endpoint,
151
- output: this.options.outputDir ?? this.options.config.orm.output,
152
- authorization: this.options.authorization,
153
- verbose: this.watchOptions.verbose,
154
- skipCustomOperations: this.options.skipCustomOperations,
155
- });
132
+ let generateFn;
133
+ let outputDir;
134
+ switch (this.options.generatorType) {
135
+ case 'react-query':
136
+ generateFn = this.options.generateReactQuery;
137
+ // React Query hooks go to {output}/hooks
138
+ outputDir = this.options.outputDir ?? `${this.options.config.output}/hooks`;
139
+ break;
140
+ case 'orm':
141
+ generateFn = this.options.generateOrm;
142
+ // ORM client goes to {output}/orm
143
+ outputDir = this.options.outputDir ?? `${this.options.config.output}/orm`;
144
+ break;
145
+ default:
146
+ throw new Error(`Unknown generator type: ${this.options.generatorType}`);
156
147
  }
148
+ const result = await generateFn({
149
+ config: this.options.configPath,
150
+ target: this.options.target,
151
+ endpoint: this.options.config.endpoint,
152
+ output: outputDir,
153
+ authorization: this.options.authorization,
154
+ verbose: this.watchOptions.verbose,
155
+ skipCustomOperations: this.options.skipCustomOperations,
156
+ });
157
157
  const duration = Date.now() - startTime;
158
158
  if (result.success) {
159
159
  this.status.regenerateCount++;
@@ -193,9 +193,17 @@ export class WatchOrchestrator {
193
193
  process.stdout.write('\x1B[2J\x1B[0f');
194
194
  }
195
195
  logHeader() {
196
- const generatorName = this.options.generatorType === 'generate'
197
- ? 'React Query hooks'
198
- : 'ORM client';
196
+ let generatorName;
197
+ switch (this.options.generatorType) {
198
+ case 'react-query':
199
+ generatorName = 'React Query hooks';
200
+ break;
201
+ case 'orm':
202
+ generatorName = 'ORM client';
203
+ break;
204
+ default:
205
+ throw new Error(`Unknown generator type: ${this.options.generatorType}`);
206
+ }
199
207
  console.log(`\n${'─'.repeat(50)}`);
200
208
  console.log(`graphql-codegen watch mode (${generatorName})`);
201
209
  console.log(`Endpoint: ${this.options.config.endpoint}`);
@@ -61,4 +61,4 @@ export interface PollEvent {
61
61
  /**
62
62
  * Generator type for watch mode
63
63
  */
64
- export type GeneratorType = 'generate' | 'generate-orm';
64
+ export type GeneratorType = 'react-query' | 'orm';
package/esm/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @constructive-io/graphql-codegen
3
3
  *
4
- * CLI-based GraphQL SDK generator for PostGraphile endpoints.
4
+ * GraphQL SDK generator for Constructive databases.
5
5
  * Introspects via _meta query and generates typed queries, mutations,
6
6
  * and React Query v5 hooks.
7
7
  */
@@ -10,5 +10,10 @@ export * from './core';
10
10
  export * from './generators';
11
11
  export * from './client';
12
12
  export { defineConfig } from './types/config';
13
- export { generateReactQuery, generateOrm, findConfigFile, loadConfigFile, } from './cli/commands';
14
- export type { GenerateOptions, GenerateResult, GenerateTargetResult, GenerateOrmOptions, GenerateOrmResult, GenerateOrmTargetResult, InitOptions, InitResult, } from './cli/commands';
13
+ export { generate } from './core/generate';
14
+ export type { GenerateOptions, GenerateResult } from './core/generate';
15
+ export { findConfigFile, loadConfigFile } from './core/config';
16
+ export { codegenQuestions, splitCommas, printResult } from './cli/shared';
17
+ export type { CodegenAnswers } from './cli/shared';
18
+ export { buildSchemaFromDatabase, buildSchemaSDLFromDatabase, } from './core/database';
19
+ export type { BuildSchemaFromDatabaseOptions, BuildSchemaFromDatabaseResult, } from './core/database';
package/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @constructive-io/graphql-codegen
3
3
  *
4
- * CLI-based GraphQL SDK generator for PostGraphile endpoints.
4
+ * GraphQL SDK generator for Constructive databases.
5
5
  * Introspects via _meta query and generates typed queries, mutations,
6
6
  * and React Query v5 hooks.
7
7
  */
@@ -15,5 +15,11 @@ export * from './generators';
15
15
  export * from './client';
16
16
  // Config definition helper
17
17
  export { defineConfig } from './types/config';
18
- // CLI command exports (for packages/cli consumption)
19
- export { generateReactQuery, generateOrm, findConfigFile, loadConfigFile, } from './cli/commands';
18
+ // Main generate function (orchestrates the entire pipeline)
19
+ export { generate } from './core/generate';
20
+ // Config utilities
21
+ export { findConfigFile, loadConfigFile } from './core/config';
22
+ // CLI shared utilities (for packages/cli to import)
23
+ export { codegenQuestions, splitCommas, printResult } from './cli/shared';
24
+ // Database schema utilities (re-exported from core for convenience)
25
+ export { buildSchemaFromDatabase, buildSchemaSDLFromDatabase, } from './core/database';