@eide/uniformgen 0.1.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 (299) hide show
  1. package/README.md +356 -0
  2. package/dist/auth/credentials.d.ts +58 -0
  3. package/dist/auth/credentials.d.ts.map +1 -0
  4. package/dist/auth/credentials.js +107 -0
  5. package/dist/cli.d.ts +3 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +563 -0
  8. package/dist/commands/init.d.ts +11 -0
  9. package/dist/commands/init.d.ts.map +1 -0
  10. package/dist/commands/init.js +113 -0
  11. package/dist/commands/login.d.ts +9 -0
  12. package/dist/commands/login.d.ts.map +1 -0
  13. package/dist/commands/login.js +158 -0
  14. package/dist/commands/logout.d.ts +5 -0
  15. package/dist/commands/logout.d.ts.map +1 -0
  16. package/dist/commands/logout.js +13 -0
  17. package/dist/commands/push.d.ts +13 -0
  18. package/dist/commands/push.d.ts.map +1 -0
  19. package/dist/commands/push.js +328 -0
  20. package/dist/commands/scaffold.d.ts +19 -0
  21. package/dist/commands/scaffold.d.ts.map +1 -0
  22. package/dist/commands/scaffold.js +366 -0
  23. package/dist/commands/seed.d.ts +20 -0
  24. package/dist/commands/seed.d.ts.map +1 -0
  25. package/dist/commands/seed.js +380 -0
  26. package/dist/commands/select-project.d.ts +10 -0
  27. package/dist/commands/select-project.d.ts.map +1 -0
  28. package/dist/commands/select-project.js +277 -0
  29. package/dist/commands/setup.d.ts +5 -0
  30. package/dist/commands/setup.d.ts.map +1 -0
  31. package/dist/commands/setup.js +51 -0
  32. package/dist/commands/sync.d.ts +13 -0
  33. package/dist/commands/sync.d.ts.map +1 -0
  34. package/dist/commands/sync.js +318 -0
  35. package/dist/commands/whoami.d.ts +5 -0
  36. package/dist/commands/whoami.d.ts.map +1 -0
  37. package/dist/commands/whoami.js +31 -0
  38. package/dist/config/load-config.d.ts +6 -0
  39. package/dist/config/load-config.d.ts.map +1 -0
  40. package/dist/config/load-config.js +103 -0
  41. package/dist/config/settings.d.ts +20 -0
  42. package/dist/config/settings.d.ts.map +1 -0
  43. package/dist/config/settings.js +64 -0
  44. package/dist/config/types.d.ts +152 -0
  45. package/dist/config/types.d.ts.map +1 -0
  46. package/dist/config/types.js +94 -0
  47. package/dist/fetcher/fetch-schemas.d.ts +140 -0
  48. package/dist/fetcher/fetch-schemas.d.ts.map +1 -0
  49. package/dist/fetcher/fetch-schemas.js +223 -0
  50. package/dist/fetcher/fetch-workflows.d.ts +53 -0
  51. package/dist/fetcher/fetch-workflows.d.ts.map +1 -0
  52. package/dist/fetcher/fetch-workflows.js +164 -0
  53. package/dist/generated/hooks/customer-detail.d.ts +74 -0
  54. package/dist/generated/hooks/customer-detail.d.ts.map +1 -0
  55. package/dist/generated/hooks/customer-detail.js +113 -0
  56. package/dist/generated/hooks/design-system.d.ts +74 -0
  57. package/dist/generated/hooks/design-system.d.ts.map +1 -0
  58. package/dist/generated/hooks/design-system.js +109 -0
  59. package/dist/generated/hooks/index.d.ts +16 -0
  60. package/dist/generated/hooks/index.d.ts.map +1 -0
  61. package/dist/generated/hooks/index.js +14 -0
  62. package/dist/generated/hooks/shopify-collection.d.ts +74 -0
  63. package/dist/generated/hooks/shopify-collection.d.ts.map +1 -0
  64. package/dist/generated/hooks/shopify-collection.js +113 -0
  65. package/dist/generated/hooks/shopify-market.d.ts +74 -0
  66. package/dist/generated/hooks/shopify-market.d.ts.map +1 -0
  67. package/dist/generated/hooks/shopify-market.js +109 -0
  68. package/dist/generated/hooks/shopify-product.d.ts +74 -0
  69. package/dist/generated/hooks/shopify-product.d.ts.map +1 -0
  70. package/dist/generated/hooks/shopify-product.js +113 -0
  71. package/dist/generated/hooks/shopify-variant.d.ts +74 -0
  72. package/dist/generated/hooks/shopify-variant.d.ts.map +1 -0
  73. package/dist/generated/hooks/shopify-variant.js +113 -0
  74. package/dist/generated/hooks/template.d.ts +74 -0
  75. package/dist/generated/hooks/template.d.ts.map +1 -0
  76. package/dist/generated/hooks/template.js +107 -0
  77. package/dist/generated/types/config.d.ts +88 -0
  78. package/dist/generated/types/config.d.ts.map +1 -0
  79. package/dist/generated/types/config.js +14 -0
  80. package/dist/generated/types/data-models/index.d.ts +7 -0
  81. package/dist/generated/types/data-models/index.d.ts.map +1 -0
  82. package/dist/generated/types/data-models/index.js +6 -0
  83. package/dist/generated/types/data-models/test.d.ts +29 -0
  84. package/dist/generated/types/data-models/test.d.ts.map +1 -0
  85. package/dist/generated/types/data-models/test.js +1 -0
  86. package/dist/generated/types/data-models/watch.d.ts +26 -0
  87. package/dist/generated/types/data-models/watch.d.ts.map +1 -0
  88. package/dist/generated/types/data-models/watch.js +1 -0
  89. package/dist/generated/types/field-types.d.ts +255 -0
  90. package/dist/generated/types/field-types.d.ts.map +1 -0
  91. package/dist/generated/types/field-types.js +35 -0
  92. package/dist/generated/types/hooks.d.ts +106 -0
  93. package/dist/generated/types/hooks.d.ts.map +1 -0
  94. package/dist/generated/types/hooks.js +9 -0
  95. package/dist/generated/types/index.d.ts +10 -0
  96. package/dist/generated/types/index.d.ts.map +1 -0
  97. package/dist/generated/types/index.js +9 -0
  98. package/dist/generated/types/models/button-variant.d.ts +16 -0
  99. package/dist/generated/types/models/button-variant.d.ts.map +1 -0
  100. package/dist/generated/types/models/button-variant.js +1 -0
  101. package/dist/generated/types/models/color-palette.d.ts +27 -0
  102. package/dist/generated/types/models/color-palette.d.ts.map +1 -0
  103. package/dist/generated/types/models/color-palette.js +1 -0
  104. package/dist/generated/types/models/color-with-scale.d.ts +15 -0
  105. package/dist/generated/types/models/color-with-scale.d.ts.map +1 -0
  106. package/dist/generated/types/models/color-with-scale.js +1 -0
  107. package/dist/generated/types/models/context.d.ts +53 -0
  108. package/dist/generated/types/models/context.d.ts.map +1 -0
  109. package/dist/generated/types/models/context.js +51 -0
  110. package/dist/generated/types/models/customer-detail.d.ts +32 -0
  111. package/dist/generated/types/models/customer-detail.d.ts.map +1 -0
  112. package/dist/generated/types/models/customer-detail.js +26 -0
  113. package/dist/generated/types/models/design-system-badges.d.ts +16 -0
  114. package/dist/generated/types/models/design-system-badges.d.ts.map +1 -0
  115. package/dist/generated/types/models/design-system-badges.js +1 -0
  116. package/dist/generated/types/models/design-system-buttons.d.ts +17 -0
  117. package/dist/generated/types/models/design-system-buttons.d.ts.map +1 -0
  118. package/dist/generated/types/models/design-system-buttons.js +1 -0
  119. package/dist/generated/types/models/design-system-cards.d.ts +16 -0
  120. package/dist/generated/types/models/design-system-cards.d.ts.map +1 -0
  121. package/dist/generated/types/models/design-system-cards.js +1 -0
  122. package/dist/generated/types/models/design-system-colors.d.ts +12 -0
  123. package/dist/generated/types/models/design-system-colors.d.ts.map +1 -0
  124. package/dist/generated/types/models/design-system-colors.js +1 -0
  125. package/dist/generated/types/models/design-system-dark-mode.d.ts +13 -0
  126. package/dist/generated/types/models/design-system-dark-mode.d.ts.map +1 -0
  127. package/dist/generated/types/models/design-system-dark-mode.js +1 -0
  128. package/dist/generated/types/models/design-system-focus-ring.d.ts +14 -0
  129. package/dist/generated/types/models/design-system-focus-ring.d.ts.map +1 -0
  130. package/dist/generated/types/models/design-system-focus-ring.js +1 -0
  131. package/dist/generated/types/models/design-system-grid.d.ts +18 -0
  132. package/dist/generated/types/models/design-system-grid.d.ts.map +1 -0
  133. package/dist/generated/types/models/design-system-grid.js +1 -0
  134. package/dist/generated/types/models/design-system-inputs.d.ts +26 -0
  135. package/dist/generated/types/models/design-system-inputs.d.ts.map +1 -0
  136. package/dist/generated/types/models/design-system-inputs.js +1 -0
  137. package/dist/generated/types/models/design-system-links.d.ts +16 -0
  138. package/dist/generated/types/models/design-system-links.d.ts.map +1 -0
  139. package/dist/generated/types/models/design-system-links.js +1 -0
  140. package/dist/generated/types/models/design-system-shadows.d.ts +20 -0
  141. package/dist/generated/types/models/design-system-shadows.d.ts.map +1 -0
  142. package/dist/generated/types/models/design-system-shadows.js +1 -0
  143. package/dist/generated/types/models/design-system-spacing.d.ts +13 -0
  144. package/dist/generated/types/models/design-system-spacing.d.ts.map +1 -0
  145. package/dist/generated/types/models/design-system-spacing.js +1 -0
  146. package/dist/generated/types/models/design-system-transitions.d.ts +15 -0
  147. package/dist/generated/types/models/design-system-transitions.d.ts.map +1 -0
  148. package/dist/generated/types/models/design-system-transitions.js +1 -0
  149. package/dist/generated/types/models/design-system-typography.d.ts +21 -0
  150. package/dist/generated/types/models/design-system-typography.d.ts.map +1 -0
  151. package/dist/generated/types/models/design-system-typography.js +1 -0
  152. package/dist/generated/types/models/design-system.d.ts +138 -0
  153. package/dist/generated/types/models/design-system.d.ts.map +1 -0
  154. package/dist/generated/types/models/design-system.js +64 -0
  155. package/dist/generated/types/models/experiment.d.ts +57 -0
  156. package/dist/generated/types/models/experiment.d.ts.map +1 -0
  157. package/dist/generated/types/models/experiment.js +55 -0
  158. package/dist/generated/types/models/font-file.d.ts +16 -0
  159. package/dist/generated/types/models/font-file.d.ts.map +1 -0
  160. package/dist/generated/types/models/font-file.js +1 -0
  161. package/dist/generated/types/models/index.d.ts +38 -0
  162. package/dist/generated/types/models/index.d.ts.map +1 -0
  163. package/dist/generated/types/models/index.js +12 -0
  164. package/dist/generated/types/models/integration.d.ts +32 -0
  165. package/dist/generated/types/models/integration.d.ts.map +1 -0
  166. package/dist/generated/types/models/integration.js +26 -0
  167. package/dist/generated/types/models/route-tree.d.ts +43 -0
  168. package/dist/generated/types/models/route-tree.d.ts.map +1 -0
  169. package/dist/generated/types/models/route-tree.js +39 -0
  170. package/dist/generated/types/models/segment.d.ts +57 -0
  171. package/dist/generated/types/models/segment.d.ts.map +1 -0
  172. package/dist/generated/types/models/segment.js +55 -0
  173. package/dist/generated/types/models/shopify-collection.d.ts +32 -0
  174. package/dist/generated/types/models/shopify-collection.d.ts.map +1 -0
  175. package/dist/generated/types/models/shopify-collection.js +26 -0
  176. package/dist/generated/types/models/shopify-market.d.ts +32 -0
  177. package/dist/generated/types/models/shopify-market.d.ts.map +1 -0
  178. package/dist/generated/types/models/shopify-market.js +26 -0
  179. package/dist/generated/types/models/shopify-product.d.ts +32 -0
  180. package/dist/generated/types/models/shopify-product.d.ts.map +1 -0
  181. package/dist/generated/types/models/shopify-product.js +26 -0
  182. package/dist/generated/types/models/shopify-variant.d.ts +32 -0
  183. package/dist/generated/types/models/shopify-variant.d.ts.map +1 -0
  184. package/dist/generated/types/models/shopify-variant.js +26 -0
  185. package/dist/generated/types/models/template.d.ts +53 -0
  186. package/dist/generated/types/models/template.d.ts.map +1 -0
  187. package/dist/generated/types/models/template.js +40 -0
  188. package/dist/generated/types/models/typography-variant.d.ts +15 -0
  189. package/dist/generated/types/models/typography-variant.d.ts.map +1 -0
  190. package/dist/generated/types/models/typography-variant.js +1 -0
  191. package/dist/generated/types/scalars.d.ts +56 -0
  192. package/dist/generated/types/scalars.d.ts.map +1 -0
  193. package/dist/generated/types/scalars.js +6 -0
  194. package/dist/generators/admin/index.d.ts +32 -0
  195. package/dist/generators/admin/index.d.ts.map +1 -0
  196. package/dist/generators/admin/index.js +219 -0
  197. package/dist/generators/admin/mutations.d.ts +23 -0
  198. package/dist/generators/admin/mutations.d.ts.map +1 -0
  199. package/dist/generators/admin/mutations.js +424 -0
  200. package/dist/generators/admin/queries.d.ts +20 -0
  201. package/dist/generators/admin/queries.d.ts.map +1 -0
  202. package/dist/generators/admin/queries.js +476 -0
  203. package/dist/generators/admin/types.d.ts +28 -0
  204. package/dist/generators/admin/types.d.ts.map +1 -0
  205. package/dist/generators/admin/types.js +254 -0
  206. package/dist/generators/cms/index.d.ts +29 -0
  207. package/dist/generators/cms/index.d.ts.map +1 -0
  208. package/dist/generators/cms/index.js +126 -0
  209. package/dist/generators/cms/route.d.ts +27 -0
  210. package/dist/generators/cms/route.d.ts.map +1 -0
  211. package/dist/generators/cms/route.js +409 -0
  212. package/dist/generators/cms/types.d.ts +15 -0
  213. package/dist/generators/cms/types.d.ts.map +1 -0
  214. package/dist/generators/cms/types.js +137 -0
  215. package/dist/generators/contexts/index.d.ts +25 -0
  216. package/dist/generators/contexts/index.d.ts.map +1 -0
  217. package/dist/generators/contexts/index.js +591 -0
  218. package/dist/generators/documents/data-models.d.ts +6 -0
  219. package/dist/generators/documents/data-models.d.ts.map +1 -0
  220. package/dist/generators/documents/data-models.js +61 -0
  221. package/dist/generators/documents/entity-models.d.ts +7 -0
  222. package/dist/generators/documents/entity-models.d.ts.map +1 -0
  223. package/dist/generators/documents/entity-models.js +87 -0
  224. package/dist/generators/documents/workflows.d.ts +11 -0
  225. package/dist/generators/documents/workflows.d.ts.map +1 -0
  226. package/dist/generators/documents/workflows.js +101 -0
  227. package/dist/generators/filters/index.d.ts +16 -0
  228. package/dist/generators/filters/index.d.ts.map +1 -0
  229. package/dist/generators/filters/index.js +384 -0
  230. package/dist/generators/hooks/agnostic.d.ts +16 -0
  231. package/dist/generators/hooks/agnostic.d.ts.map +1 -0
  232. package/dist/generators/hooks/agnostic.js +248 -0
  233. package/dist/generators/hooks/index.d.ts +9 -0
  234. package/dist/generators/hooks/index.d.ts.map +1 -0
  235. package/dist/generators/hooks/index.js +8 -0
  236. package/dist/generators/hooks/react.d.ts +16 -0
  237. package/dist/generators/hooks/react.d.ts.map +1 -0
  238. package/dist/generators/hooks/react.js +394 -0
  239. package/dist/generators/hooks/remix.d.ts +16 -0
  240. package/dist/generators/hooks/remix.d.ts.map +1 -0
  241. package/dist/generators/hooks/remix.js +349 -0
  242. package/dist/generators/hooks/workflows.d.ts +23 -0
  243. package/dist/generators/hooks/workflows.d.ts.map +1 -0
  244. package/dist/generators/hooks/workflows.js +312 -0
  245. package/dist/generators/resolve/index.d.ts +13 -0
  246. package/dist/generators/resolve/index.d.ts.map +1 -0
  247. package/dist/generators/resolve/index.js +13 -0
  248. package/dist/generators/resolve/platform.d.ts +29 -0
  249. package/dist/generators/resolve/platform.d.ts.map +1 -0
  250. package/dist/generators/resolve/platform.js +479 -0
  251. package/dist/generators/types/config.d.ts +7 -0
  252. package/dist/generators/types/config.d.ts.map +1 -0
  253. package/dist/generators/types/config.js +113 -0
  254. package/dist/generators/types/data-models.d.ts +10 -0
  255. package/dist/generators/types/data-models.d.ts.map +1 -0
  256. package/dist/generators/types/data-models.js +100 -0
  257. package/dist/generators/types/entity-models.d.ts +13 -0
  258. package/dist/generators/types/entity-models.d.ts.map +1 -0
  259. package/dist/generators/types/entity-models.js +241 -0
  260. package/dist/generators/types/field-types.d.ts +9 -0
  261. package/dist/generators/types/field-types.d.ts.map +1 -0
  262. package/dist/generators/types/field-types.js +651 -0
  263. package/dist/generators/types/hooks.d.ts +7 -0
  264. package/dist/generators/types/hooks.d.ts.map +1 -0
  265. package/dist/generators/types/hooks.js +132 -0
  266. package/dist/generators/types/scalars.d.ts +6 -0
  267. package/dist/generators/types/scalars.d.ts.map +1 -0
  268. package/dist/generators/types/scalars.js +68 -0
  269. package/dist/generators/types/user-details.d.ts +6 -0
  270. package/dist/generators/types/user-details.d.ts.map +1 -0
  271. package/dist/generators/types/user-details.js +60 -0
  272. package/dist/generators/types/workflows.d.ts +15 -0
  273. package/dist/generators/types/workflows.d.ts.map +1 -0
  274. package/dist/generators/types/workflows.js +163 -0
  275. package/dist/graphql/generated/gql.d.ts +47 -0
  276. package/dist/graphql/generated/gql.d.ts.map +1 -0
  277. package/dist/graphql/generated/gql.js +10 -0
  278. package/dist/graphql/generated/graphql.d.ts +8455 -0
  279. package/dist/graphql/generated/graphql.d.ts.map +1 -0
  280. package/dist/graphql/generated/graphql.js +573 -0
  281. package/dist/graphql/generated/index.d.ts +2 -0
  282. package/dist/graphql/generated/index.d.ts.map +1 -0
  283. package/dist/graphql/generated/index.js +1 -0
  284. package/dist/index.d.ts +13 -0
  285. package/dist/index.d.ts.map +1 -0
  286. package/dist/index.js +9 -0
  287. package/dist/schema/define-entity-model.d.ts +122 -0
  288. package/dist/schema/define-entity-model.d.ts.map +1 -0
  289. package/dist/schema/define-entity-model.js +59 -0
  290. package/dist/schema/schema-loader.d.ts +10 -0
  291. package/dist/schema/schema-loader.d.ts.map +1 -0
  292. package/dist/schema/schema-loader.js +91 -0
  293. package/dist/utils/field-mapping.d.ts +83 -0
  294. package/dist/utils/field-mapping.d.ts.map +1 -0
  295. package/dist/utils/field-mapping.js +334 -0
  296. package/dist/writer/write-files.d.ts +12 -0
  297. package/dist/writer/write-files.d.ts.map +1 -0
  298. package/dist/writer/write-files.js +35 -0
  299. package/package.json +70 -0
@@ -0,0 +1,380 @@
1
+ /**
2
+ * Seed Command
3
+ *
4
+ * Seeds content data to a Foir project from local JSON/YAML files.
5
+ * Useful for bootstrapping starter content in templates.
6
+ */
7
+ import chalk from 'chalk';
8
+ import ora from 'ora';
9
+ import { readFile, readdir, stat } from 'fs/promises';
10
+ import { join, extname, basename } from 'path';
11
+ import { loadConfig } from '../config/load-config.js';
12
+ /**
13
+ * Get the GraphQL endpoint URL
14
+ */
15
+ function getGraphQLEndpoint(apiUrl) {
16
+ const base = apiUrl.replace(/\/$/, '').replace(/\/graphql$/, '');
17
+ return `${base}/graphql`;
18
+ }
19
+ /**
20
+ * Create a simple GraphQL client
21
+ */
22
+ function createClient(apiUrl, accessToken, tenantId, projectId) {
23
+ const endpoint = getGraphQLEndpoint(apiUrl);
24
+ return {
25
+ async request(query, variables) {
26
+ const headers = {
27
+ 'Content-Type': 'application/json',
28
+ };
29
+ if (accessToken) {
30
+ headers['Authorization'] = `Bearer ${accessToken}`;
31
+ }
32
+ // Add tenant/project context headers for internal API
33
+ if (tenantId) {
34
+ headers['x-tenant-id'] = tenantId;
35
+ }
36
+ if (projectId) {
37
+ headers['x-project-id'] = projectId;
38
+ }
39
+ const response = await fetch(endpoint, {
40
+ method: 'POST',
41
+ headers,
42
+ body: JSON.stringify({ query, variables }),
43
+ });
44
+ if (!response.ok) {
45
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
46
+ }
47
+ const result = await response.json();
48
+ if (result.errors && result.errors.length > 0) {
49
+ throw new Error(result.errors.map((e) => e.message).join(', '));
50
+ }
51
+ return result.data;
52
+ },
53
+ };
54
+ }
55
+ // GraphQL mutations (Internal API)
56
+ const CREATE_ENTITY_RECORD_MUTATION = `
57
+ mutation CreateEntityRecord($input: CreateEntityRecordInput!) {
58
+ createEntityRecord(input: $input) {
59
+ id
60
+ modelKey
61
+ naturalKey
62
+ currentVersionId
63
+ variants(limit: 1) {
64
+ items {
65
+ id
66
+ currentVersionId
67
+ }
68
+ }
69
+ }
70
+ }
71
+ `;
72
+ const PUBLISH_VERSION_MUTATION = `
73
+ mutation PublishEntityRecordVersion($versionId: ID!) {
74
+ publishEntityRecordVersion(versionId: $versionId) {
75
+ id
76
+ publishedVersionId
77
+ }
78
+ }
79
+ `;
80
+ const CREATE_ROUTE_MUTATION = `
81
+ mutation CreateRoute($input: CreateRouteInput!) {
82
+ createRoute(input: $input) {
83
+ id
84
+ path
85
+ }
86
+ }
87
+ `;
88
+ // Query to find existing record by natural key
89
+ const GET_ENTITY_RECORD_QUERY = `
90
+ query GetEntityRecord($modelKey: String!, $naturalKey: String!) {
91
+ entityRecord(modelKey: $modelKey, naturalKey: $naturalKey) {
92
+ id
93
+ naturalKey
94
+ currentVersionId
95
+ variants(limit: 1) {
96
+ items {
97
+ id
98
+ currentVersionId
99
+ isDefault
100
+ }
101
+ }
102
+ }
103
+ }
104
+ `;
105
+ // Mutation to create a new version (for upsert)
106
+ const CREATE_VERSION_MUTATION = `
107
+ mutation CreateEntityRecordVersion($input: CreateEntityRecordVersionInput!) {
108
+ createEntityRecordVersion(input: $input) {
109
+ id
110
+ versionNumber
111
+ }
112
+ }
113
+ `;
114
+ // Mutation to update record metadata
115
+ const UPDATE_ENTITY_RECORD_MUTATION = `
116
+ mutation UpdateEntityRecord($id: ID!, $input: UpdateEntityRecordInput!) {
117
+ updateEntityRecord(id: $id, input: $input) {
118
+ id
119
+ naturalKey
120
+ }
121
+ }
122
+ `;
123
+ /**
124
+ * Parse a seed file (JSON or YAML)
125
+ */
126
+ async function parseSeedFile(filePath) {
127
+ const ext = extname(filePath).toLowerCase();
128
+ const content = await readFile(filePath, 'utf-8');
129
+ if (ext === '.json') {
130
+ return JSON.parse(content);
131
+ }
132
+ if (ext === '.yaml' || ext === '.yml') {
133
+ // Simple YAML parsing for common cases
134
+ // For full YAML support, users can install js-yaml
135
+ try {
136
+ // Dynamic import for optional js-yaml dependency
137
+ // @ts-expect-error - js-yaml is an optional peer dependency
138
+ const jsYaml = await import('js-yaml');
139
+ const loadFn = jsYaml.load || jsYaml.default?.load;
140
+ if (!loadFn)
141
+ throw new Error('js-yaml load function not found');
142
+ return loadFn(content);
143
+ }
144
+ catch {
145
+ console.warn(chalk.yellow(` Warning: js-yaml not installed, skipping ${filePath}`));
146
+ return null;
147
+ }
148
+ }
149
+ return null;
150
+ }
151
+ /**
152
+ * Get all seed files from a directory
153
+ */
154
+ async function getSeedFiles(seedDir, pattern) {
155
+ const files = [];
156
+ async function scanDir(dir) {
157
+ const entries = await readdir(dir);
158
+ for (const entry of entries) {
159
+ const fullPath = join(dir, entry);
160
+ const stats = await stat(fullPath);
161
+ if (stats.isDirectory()) {
162
+ await scanDir(fullPath);
163
+ }
164
+ else if (stats.isFile()) {
165
+ const ext = extname(entry).toLowerCase();
166
+ if (['.json', '.yaml', '.yml'].includes(ext)) {
167
+ // Apply pattern filter if provided
168
+ if (!pattern || entry.includes(pattern) || basename(entry, ext).includes(pattern)) {
169
+ files.push(fullPath);
170
+ }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ await scanDir(seedDir);
176
+ return files.sort();
177
+ }
178
+ /**
179
+ * Main seed function
180
+ */
181
+ export async function seed(options) {
182
+ const spinner = ora();
183
+ try {
184
+ // Load configuration
185
+ spinner.start('Loading configuration...');
186
+ const config = await loadConfig(options.config, process.cwd());
187
+ // Override config with CLI options
188
+ if (options.apiUrl)
189
+ config.apiUrl = options.apiUrl;
190
+ if (!config.apiUrl) {
191
+ throw new Error('API URL not configured. Run `uniformgen setup` or provide --api-url');
192
+ }
193
+ spinner.succeed('Configuration loaded');
194
+ // Create GraphQL client with tenant/project context
195
+ const client = createClient(config.apiUrl, config.accessToken, config.tenantId, config.projectId);
196
+ // Find seed files
197
+ spinner.start(`Scanning ${options.seedDir} for seed files...`);
198
+ const seedFiles = await getSeedFiles(options.seedDir, options.pattern);
199
+ spinner.succeed(`Found ${seedFiles.length} seed files`);
200
+ if (seedFiles.length === 0) {
201
+ console.log(chalk.yellow('\nNo seed files found.'));
202
+ console.log(chalk.gray('Create .json or .yaml files in the seed directory.'));
203
+ return;
204
+ }
205
+ // Process each seed file
206
+ let totalCreated = 0;
207
+ let totalUpdated = 0;
208
+ let totalPublished = 0;
209
+ let totalRoutes = 0;
210
+ let totalSkipped = 0;
211
+ let totalErrors = 0;
212
+ for (const filePath of seedFiles) {
213
+ const relativePath = filePath.replace(options.seedDir, '').replace(/^\//, '');
214
+ spinner.start(`Processing ${relativePath}...`);
215
+ const seedData = await parseSeedFile(filePath);
216
+ if (!seedData) {
217
+ spinner.warn(`Skipped ${relativePath} (unsupported format)`);
218
+ totalSkipped++;
219
+ continue;
220
+ }
221
+ const { modelKey, records } = seedData;
222
+ if (!modelKey || !records || !Array.isArray(records)) {
223
+ spinner.warn(`Skipped ${relativePath} (invalid format - needs modelKey and records)`);
224
+ totalSkipped++;
225
+ continue;
226
+ }
227
+ spinner.text = `Processing ${relativePath} (${records.length} records)...`;
228
+ for (const record of records) {
229
+ if (!record.naturalKey || !record.data) {
230
+ console.log(chalk.yellow(` Skipping record without naturalKey or data`));
231
+ totalSkipped++;
232
+ continue;
233
+ }
234
+ try {
235
+ if (options.dryRun) {
236
+ console.log(chalk.gray(` [dry-run] Would ${options.upsert ? 'upsert' : 'create'} ${modelKey}/${record.naturalKey}`));
237
+ totalCreated++;
238
+ continue;
239
+ }
240
+ let existingRecord = null;
241
+ if (options.upsert) {
242
+ try {
243
+ const result = await client.request(GET_ENTITY_RECORD_QUERY, {
244
+ modelKey,
245
+ naturalKey: record.naturalKey,
246
+ });
247
+ existingRecord = result.entityRecord;
248
+ }
249
+ catch {
250
+ // Record doesn't exist, will create new
251
+ existingRecord = null;
252
+ }
253
+ }
254
+ let entityId;
255
+ let versionId = null;
256
+ if (existingRecord !== null && options.upsert) {
257
+ // UPDATE existing record
258
+ const existing = existingRecord;
259
+ entityId = existing.id;
260
+ // Update metadata if provided
261
+ if (record.metadata) {
262
+ await client.request(UPDATE_ENTITY_RECORD_MUTATION, {
263
+ id: entityId,
264
+ input: { metadata: record.metadata },
265
+ });
266
+ }
267
+ // Get the default variant ID
268
+ const defaultVariant = existing.variants.items.find((v) => v.isDefault) || existing.variants.items[0];
269
+ if (defaultVariant) {
270
+ // Create a new version with the seed content
271
+ const versionResult = await client.request(CREATE_VERSION_MUTATION, {
272
+ input: {
273
+ variantId: defaultVariant.id,
274
+ content: record.data,
275
+ changeDescription: 'Updated via seed --upsert',
276
+ },
277
+ });
278
+ versionId = versionResult.createEntityRecordVersion.id;
279
+ }
280
+ totalUpdated++;
281
+ console.log(chalk.blue(` ↻ ${modelKey}/${record.naturalKey} (updated)`));
282
+ }
283
+ else {
284
+ // CREATE new record
285
+ const createResult = await client.request(CREATE_ENTITY_RECORD_MUTATION, {
286
+ input: {
287
+ modelKey,
288
+ naturalKey: record.naturalKey,
289
+ metadata: record.metadata,
290
+ content: record.data,
291
+ },
292
+ });
293
+ entityId = createResult.createEntityRecord.id;
294
+ versionId =
295
+ createResult.createEntityRecord.currentVersionId ??
296
+ createResult.createEntityRecord.variants.items[0]?.currentVersionId ?? null;
297
+ totalCreated++;
298
+ console.log(chalk.green(` ✓ ${modelKey}/${record.naturalKey}`));
299
+ }
300
+ // Create route if routing config provided
301
+ if (record.routing?.path) {
302
+ try {
303
+ await client.request(CREATE_ROUTE_MUTATION, {
304
+ input: {
305
+ path: record.routing.path,
306
+ entityRecordId: entityId,
307
+ priority: record.routing.priority ?? 0,
308
+ },
309
+ });
310
+ totalRoutes++;
311
+ }
312
+ catch (_routeError) {
313
+ // Route creation is optional, log but don't fail
314
+ console.log(chalk.yellow(` Warning: Could not create route for ${record.naturalKey}`));
315
+ }
316
+ }
317
+ // Publish if requested
318
+ if (options.publish && versionId) {
319
+ try {
320
+ await client.request(PUBLISH_VERSION_MUTATION, {
321
+ versionId,
322
+ });
323
+ totalPublished++;
324
+ }
325
+ catch (_publishError) {
326
+ console.log(chalk.yellow(` Warning: Could not publish ${record.naturalKey}`));
327
+ }
328
+ }
329
+ }
330
+ catch (error) {
331
+ const message = error instanceof Error ? error.message : 'Unknown error';
332
+ if (message.includes('already exists') || message.includes('duplicate')) {
333
+ if (options.upsert) {
334
+ console.log(chalk.red(` ✗ ${modelKey}/${record.naturalKey}: Failed to upsert - ${message}`));
335
+ totalErrors++;
336
+ }
337
+ else {
338
+ console.log(chalk.gray(` ○ ${modelKey}/${record.naturalKey} (already exists, use --upsert to update)`));
339
+ totalSkipped++;
340
+ }
341
+ }
342
+ else {
343
+ console.log(chalk.red(` ✗ ${modelKey}/${record.naturalKey}: ${message}`));
344
+ totalErrors++;
345
+ }
346
+ }
347
+ }
348
+ spinner.succeed(`Processed ${relativePath}`);
349
+ }
350
+ // Summary
351
+ console.log('');
352
+ console.log(chalk.bold('Seed Summary'));
353
+ console.log('─'.repeat(40));
354
+ console.log(chalk.green(` Created: ${totalCreated} records`));
355
+ if (totalUpdated > 0) {
356
+ console.log(chalk.blue(` Updated: ${totalUpdated} records`));
357
+ }
358
+ if (options.publish) {
359
+ console.log(chalk.green(` Published: ${totalPublished} records`));
360
+ }
361
+ if (totalRoutes > 0) {
362
+ console.log(chalk.green(` Routes: ${totalRoutes} created`));
363
+ }
364
+ if (totalSkipped > 0) {
365
+ console.log(chalk.yellow(` Skipped: ${totalSkipped} records`));
366
+ }
367
+ if (totalErrors > 0) {
368
+ console.log(chalk.red(` Errors: ${totalErrors} records`));
369
+ }
370
+ if (options.dryRun) {
371
+ console.log('');
372
+ console.log(chalk.cyan('This was a dry run. No changes were made.'));
373
+ console.log(chalk.gray('Remove --dry-run to actually seed data.'));
374
+ }
375
+ }
376
+ catch (error) {
377
+ spinner.fail('Seeding failed');
378
+ throw error;
379
+ }
380
+ }
@@ -0,0 +1,10 @@
1
+ interface SelectProjectOptions {
2
+ apiUrl: string;
3
+ projectId?: string;
4
+ }
5
+ /**
6
+ * Select project command - choose which project to work with
7
+ */
8
+ export declare function selectProject(options: SelectProjectOptions): Promise<void>;
9
+ export {};
10
+ //# sourceMappingURL=select-project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-project.d.ts","sourceRoot":"","sources":["../../src/commands/select-project.ts"],"names":[],"mappings":"AA2BA,UAAU,oBAAoB;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+QD;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CA2Ff"}
@@ -0,0 +1,277 @@
1
+ import inquirer from 'inquirer';
2
+ import { getCredentials, updateCredentials } from '../auth/credentials.js';
3
+ const CLI_API_KEY_NAME = 'UniformGen CLI';
4
+ /**
5
+ * Get the internal GraphQL endpoint URL from the base API URL
6
+ */
7
+ function getInternalGraphQLEndpoint(apiUrl) {
8
+ const base = apiUrl.replace(/\/$/, '').replace(/\/graphql$/, '');
9
+ return `${base}/graphql`;
10
+ }
11
+ /**
12
+ * Fetch session context with available tenants and projects
13
+ * Uses the same pattern as the admin app - no tenant context required
14
+ */
15
+ async function fetchSessionContext(apiUrl, accessToken) {
16
+ const response = await fetch(getInternalGraphQLEndpoint(apiUrl), {
17
+ method: 'POST',
18
+ headers: {
19
+ 'Content-Type': 'application/json',
20
+ Authorization: `Bearer ${accessToken}`,
21
+ },
22
+ body: JSON.stringify({
23
+ query: `
24
+ query GetSessionContext {
25
+ sessionContext {
26
+ tenantId
27
+ projectId
28
+ availableTenants {
29
+ id
30
+ name
31
+ }
32
+ availableProjects {
33
+ id
34
+ name
35
+ tenantId
36
+ }
37
+ }
38
+ }
39
+ `,
40
+ }),
41
+ });
42
+ if (!response.ok) {
43
+ throw new Error(`Failed to fetch session context: ${response.statusText}`);
44
+ }
45
+ const result = (await response.json());
46
+ if (result.errors && result.errors.length > 0) {
47
+ throw new Error(`GraphQL error: ${result.errors[0]?.message ?? 'Unknown error'}`);
48
+ }
49
+ if (!result.data?.sessionContext) {
50
+ throw new Error('No session context returned');
51
+ }
52
+ return result.data.sessionContext;
53
+ }
54
+ /**
55
+ * Fetch API keys for a project
56
+ */
57
+ async function fetchApiKeys(apiUrl, accessToken, projectId, tenantId) {
58
+ const response = await fetch(getInternalGraphQLEndpoint(apiUrl), {
59
+ method: 'POST',
60
+ headers: {
61
+ 'Content-Type': 'application/json',
62
+ Authorization: `Bearer ${accessToken}`,
63
+ 'x-tenant-id': tenantId,
64
+ 'x-project-id': projectId,
65
+ },
66
+ body: JSON.stringify({
67
+ query: `
68
+ query ListApiKeys {
69
+ listApiKeys(includeInactive: false, limit: 100) {
70
+ apiKeys {
71
+ id
72
+ name
73
+ isActive
74
+ }
75
+ }
76
+ }
77
+ `,
78
+ }),
79
+ });
80
+ if (!response.ok) {
81
+ throw new Error(`Failed to fetch API keys: ${response.statusText}`);
82
+ }
83
+ const result = (await response.json());
84
+ if (result.errors && result.errors.length > 0) {
85
+ throw new Error(`GraphQL error: ${result.errors[0]?.message ?? 'Unknown error'}`);
86
+ }
87
+ return result.data?.listApiKeys?.apiKeys ?? [];
88
+ }
89
+ /**
90
+ * Create a new API key
91
+ */
92
+ async function createApiKey(apiUrl, accessToken, projectId, tenantId, name) {
93
+ const response = await fetch(getInternalGraphQLEndpoint(apiUrl), {
94
+ method: 'POST',
95
+ headers: {
96
+ 'Content-Type': 'application/json',
97
+ Authorization: `Bearer ${accessToken}`,
98
+ 'x-tenant-id': tenantId,
99
+ 'x-project-id': projectId,
100
+ },
101
+ body: JSON.stringify({
102
+ query: `
103
+ mutation CreateApiKey($input: CreateApiKeyInput!) {
104
+ createApiKey(input: $input) {
105
+ apiKey {
106
+ id
107
+ name
108
+ isActive
109
+ }
110
+ plainKey
111
+ }
112
+ }
113
+ `,
114
+ variables: {
115
+ input: {
116
+ name,
117
+ projectId,
118
+ scopes: ['entities:read', 'files:read'],
119
+ },
120
+ },
121
+ }),
122
+ });
123
+ if (!response.ok) {
124
+ throw new Error(`Failed to create API key: ${response.statusText}`);
125
+ }
126
+ const result = (await response.json());
127
+ if (result.errors && result.errors.length > 0) {
128
+ throw new Error(`GraphQL error: ${result.errors[0]?.message ?? 'Unknown error'}`);
129
+ }
130
+ if (!result.data?.createApiKey) {
131
+ throw new Error('Failed to create API key: No data returned');
132
+ }
133
+ return result.data.createApiKey;
134
+ }
135
+ /**
136
+ * Rotate an existing API key to get a new plain key
137
+ */
138
+ async function rotateApiKey(apiUrl, accessToken, projectId, tenantId, keyId) {
139
+ const response = await fetch(getInternalGraphQLEndpoint(apiUrl), {
140
+ method: 'POST',
141
+ headers: {
142
+ 'Content-Type': 'application/json',
143
+ Authorization: `Bearer ${accessToken}`,
144
+ 'x-tenant-id': tenantId,
145
+ 'x-project-id': projectId,
146
+ },
147
+ body: JSON.stringify({
148
+ query: `
149
+ mutation RotateApiKey($id: ID!) {
150
+ rotateApiKey(id: $id) {
151
+ apiKey {
152
+ id
153
+ name
154
+ isActive
155
+ }
156
+ plainKey
157
+ }
158
+ }
159
+ `,
160
+ variables: { id: keyId },
161
+ }),
162
+ });
163
+ if (!response.ok) {
164
+ throw new Error(`Failed to rotate API key: ${response.statusText}`);
165
+ }
166
+ const result = (await response.json());
167
+ if (result.errors && result.errors.length > 0) {
168
+ throw new Error(`GraphQL error: ${result.errors[0]?.message ?? 'Unknown error'}`);
169
+ }
170
+ if (!result.data?.rotateApiKey) {
171
+ throw new Error('Failed to rotate API key: No data returned');
172
+ }
173
+ return result.data.rotateApiKey;
174
+ }
175
+ /**
176
+ * Provision an API key for CLI usage
177
+ * - If CLI key exists and we have it stored, verify it's still active
178
+ * - If CLI key exists but we don't have it, rotate to get new plain key
179
+ * - If CLI key doesn't exist, create one
180
+ */
181
+ async function provisionApiKey(apiUrl, accessToken, projectId, tenantId) {
182
+ const apiKeys = await fetchApiKeys(apiUrl, accessToken, projectId, tenantId);
183
+ const existingCliKey = apiKeys.find((k) => k.name === CLI_API_KEY_NAME && k.isActive);
184
+ if (existingCliKey) {
185
+ // Key exists - rotate it to get a new plain key
186
+ // (We can't retrieve the plain key after creation, only on create/rotate)
187
+ console.log(' Rotating existing CLI API key...');
188
+ const rotated = await rotateApiKey(apiUrl, accessToken, projectId, tenantId, existingCliKey.id);
189
+ return {
190
+ apiKey: rotated.plainKey,
191
+ apiKeyId: rotated.apiKey.id,
192
+ };
193
+ }
194
+ else {
195
+ // No CLI key exists - create one
196
+ console.log(' Creating CLI API key...');
197
+ const created = await createApiKey(apiUrl, accessToken, projectId, tenantId, CLI_API_KEY_NAME);
198
+ return {
199
+ apiKey: created.plainKey,
200
+ apiKeyId: created.apiKey.id,
201
+ };
202
+ }
203
+ }
204
+ /**
205
+ * Select project command - choose which project to work with
206
+ */
207
+ export async function selectProject(options) {
208
+ const credentials = await getCredentials();
209
+ if (!credentials) {
210
+ console.log('Not logged in. Run `uniformgen login` first.');
211
+ process.exit(1);
212
+ }
213
+ console.log('Fetching your projects...\n');
214
+ // Fetch session context - same pattern as admin app
215
+ const sessionContext = await fetchSessionContext(options.apiUrl, credentials.accessToken);
216
+ const { availableTenants: tenants, availableProjects: projects } = sessionContext;
217
+ if (projects.length === 0) {
218
+ console.log('No projects found. Create one in the platform first.');
219
+ process.exit(1);
220
+ }
221
+ // Create tenant name lookup map
222
+ const tenantNameMap = new Map(tenants.map((t) => [t.id, t.name]));
223
+ let selectedProject;
224
+ // If project ID provided directly, use it
225
+ if (options.projectId) {
226
+ const found = projects.find((p) => p.id === options.projectId);
227
+ if (!found) {
228
+ console.log(`Project with ID "${options.projectId}" not found.`);
229
+ console.log('Available projects:');
230
+ projects.forEach((p) => console.log(` - ${p.name} (${p.id})`));
231
+ process.exit(1);
232
+ }
233
+ selectedProject = found;
234
+ }
235
+ else {
236
+ // Interactive selection
237
+ // Group projects by tenant
238
+ const byTenant = projects.reduce((acc, p) => {
239
+ const key = tenantNameMap.get(p.tenantId) ?? 'Unknown';
240
+ if (!acc[key])
241
+ acc[key] = [];
242
+ acc[key].push(p);
243
+ return acc;
244
+ }, {});
245
+ const choices = Object.entries(byTenant).flatMap(([tenantName, tenantProjects]) => [
246
+ new inquirer.Separator(`── ${tenantName} ──`),
247
+ ...tenantProjects.map((p) => ({
248
+ name: ` ${p.name}`,
249
+ value: p.id,
250
+ short: p.name,
251
+ })),
252
+ ]);
253
+ const { projectId } = await inquirer.prompt([
254
+ {
255
+ type: 'list',
256
+ name: 'projectId',
257
+ message: 'Select a project:',
258
+ choices,
259
+ },
260
+ ]);
261
+ selectedProject = projects.find((p) => p.id === projectId);
262
+ }
263
+ // Provision API key for CLI access
264
+ console.log('\nProvisioning API key for CLI access...');
265
+ const { apiKey, apiKeyId } = await provisionApiKey(options.apiUrl, credentials.accessToken, selectedProject.id, selectedProject.tenantId);
266
+ await updateCredentials({
267
+ selectedProject: {
268
+ id: selectedProject.id,
269
+ name: selectedProject.name,
270
+ tenantId: selectedProject.tenantId,
271
+ apiKey,
272
+ apiKeyId,
273
+ },
274
+ });
275
+ console.log(`\n✓ Selected project: ${selectedProject.name}`);
276
+ console.log('✓ API key provisioned for CLI access');
277
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Setup command - configure UniformGen preferences
3
+ */
4
+ export declare function setup(): Promise<void>;
5
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AA4BA;;GAEG;AACH,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAiC3C"}