@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.
- package/README.md +356 -0
- package/dist/auth/credentials.d.ts +58 -0
- package/dist/auth/credentials.d.ts.map +1 -0
- package/dist/auth/credentials.js +107 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +563 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +113 -0
- package/dist/commands/login.d.ts +9 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +158 -0
- package/dist/commands/logout.d.ts +5 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +13 -0
- package/dist/commands/push.d.ts +13 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +328 -0
- package/dist/commands/scaffold.d.ts +19 -0
- package/dist/commands/scaffold.d.ts.map +1 -0
- package/dist/commands/scaffold.js +366 -0
- package/dist/commands/seed.d.ts +20 -0
- package/dist/commands/seed.d.ts.map +1 -0
- package/dist/commands/seed.js +380 -0
- package/dist/commands/select-project.d.ts +10 -0
- package/dist/commands/select-project.d.ts.map +1 -0
- package/dist/commands/select-project.js +277 -0
- package/dist/commands/setup.d.ts +5 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +51 -0
- package/dist/commands/sync.d.ts +13 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +318 -0
- package/dist/commands/whoami.d.ts +5 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +31 -0
- package/dist/config/load-config.d.ts +6 -0
- package/dist/config/load-config.d.ts.map +1 -0
- package/dist/config/load-config.js +103 -0
- package/dist/config/settings.d.ts +20 -0
- package/dist/config/settings.d.ts.map +1 -0
- package/dist/config/settings.js +64 -0
- package/dist/config/types.d.ts +152 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +94 -0
- package/dist/fetcher/fetch-schemas.d.ts +140 -0
- package/dist/fetcher/fetch-schemas.d.ts.map +1 -0
- package/dist/fetcher/fetch-schemas.js +223 -0
- package/dist/fetcher/fetch-workflows.d.ts +53 -0
- package/dist/fetcher/fetch-workflows.d.ts.map +1 -0
- package/dist/fetcher/fetch-workflows.js +164 -0
- package/dist/generated/hooks/customer-detail.d.ts +74 -0
- package/dist/generated/hooks/customer-detail.d.ts.map +1 -0
- package/dist/generated/hooks/customer-detail.js +113 -0
- package/dist/generated/hooks/design-system.d.ts +74 -0
- package/dist/generated/hooks/design-system.d.ts.map +1 -0
- package/dist/generated/hooks/design-system.js +109 -0
- package/dist/generated/hooks/index.d.ts +16 -0
- package/dist/generated/hooks/index.d.ts.map +1 -0
- package/dist/generated/hooks/index.js +14 -0
- package/dist/generated/hooks/shopify-collection.d.ts +74 -0
- package/dist/generated/hooks/shopify-collection.d.ts.map +1 -0
- package/dist/generated/hooks/shopify-collection.js +113 -0
- package/dist/generated/hooks/shopify-market.d.ts +74 -0
- package/dist/generated/hooks/shopify-market.d.ts.map +1 -0
- package/dist/generated/hooks/shopify-market.js +109 -0
- package/dist/generated/hooks/shopify-product.d.ts +74 -0
- package/dist/generated/hooks/shopify-product.d.ts.map +1 -0
- package/dist/generated/hooks/shopify-product.js +113 -0
- package/dist/generated/hooks/shopify-variant.d.ts +74 -0
- package/dist/generated/hooks/shopify-variant.d.ts.map +1 -0
- package/dist/generated/hooks/shopify-variant.js +113 -0
- package/dist/generated/hooks/template.d.ts +74 -0
- package/dist/generated/hooks/template.d.ts.map +1 -0
- package/dist/generated/hooks/template.js +107 -0
- package/dist/generated/types/config.d.ts +88 -0
- package/dist/generated/types/config.d.ts.map +1 -0
- package/dist/generated/types/config.js +14 -0
- package/dist/generated/types/data-models/index.d.ts +7 -0
- package/dist/generated/types/data-models/index.d.ts.map +1 -0
- package/dist/generated/types/data-models/index.js +6 -0
- package/dist/generated/types/data-models/test.d.ts +29 -0
- package/dist/generated/types/data-models/test.d.ts.map +1 -0
- package/dist/generated/types/data-models/test.js +1 -0
- package/dist/generated/types/data-models/watch.d.ts +26 -0
- package/dist/generated/types/data-models/watch.d.ts.map +1 -0
- package/dist/generated/types/data-models/watch.js +1 -0
- package/dist/generated/types/field-types.d.ts +255 -0
- package/dist/generated/types/field-types.d.ts.map +1 -0
- package/dist/generated/types/field-types.js +35 -0
- package/dist/generated/types/hooks.d.ts +106 -0
- package/dist/generated/types/hooks.d.ts.map +1 -0
- package/dist/generated/types/hooks.js +9 -0
- package/dist/generated/types/index.d.ts +10 -0
- package/dist/generated/types/index.d.ts.map +1 -0
- package/dist/generated/types/index.js +9 -0
- package/dist/generated/types/models/button-variant.d.ts +16 -0
- package/dist/generated/types/models/button-variant.d.ts.map +1 -0
- package/dist/generated/types/models/button-variant.js +1 -0
- package/dist/generated/types/models/color-palette.d.ts +27 -0
- package/dist/generated/types/models/color-palette.d.ts.map +1 -0
- package/dist/generated/types/models/color-palette.js +1 -0
- package/dist/generated/types/models/color-with-scale.d.ts +15 -0
- package/dist/generated/types/models/color-with-scale.d.ts.map +1 -0
- package/dist/generated/types/models/color-with-scale.js +1 -0
- package/dist/generated/types/models/context.d.ts +53 -0
- package/dist/generated/types/models/context.d.ts.map +1 -0
- package/dist/generated/types/models/context.js +51 -0
- package/dist/generated/types/models/customer-detail.d.ts +32 -0
- package/dist/generated/types/models/customer-detail.d.ts.map +1 -0
- package/dist/generated/types/models/customer-detail.js +26 -0
- package/dist/generated/types/models/design-system-badges.d.ts +16 -0
- package/dist/generated/types/models/design-system-badges.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-badges.js +1 -0
- package/dist/generated/types/models/design-system-buttons.d.ts +17 -0
- package/dist/generated/types/models/design-system-buttons.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-buttons.js +1 -0
- package/dist/generated/types/models/design-system-cards.d.ts +16 -0
- package/dist/generated/types/models/design-system-cards.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-cards.js +1 -0
- package/dist/generated/types/models/design-system-colors.d.ts +12 -0
- package/dist/generated/types/models/design-system-colors.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-colors.js +1 -0
- package/dist/generated/types/models/design-system-dark-mode.d.ts +13 -0
- package/dist/generated/types/models/design-system-dark-mode.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-dark-mode.js +1 -0
- package/dist/generated/types/models/design-system-focus-ring.d.ts +14 -0
- package/dist/generated/types/models/design-system-focus-ring.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-focus-ring.js +1 -0
- package/dist/generated/types/models/design-system-grid.d.ts +18 -0
- package/dist/generated/types/models/design-system-grid.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-grid.js +1 -0
- package/dist/generated/types/models/design-system-inputs.d.ts +26 -0
- package/dist/generated/types/models/design-system-inputs.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-inputs.js +1 -0
- package/dist/generated/types/models/design-system-links.d.ts +16 -0
- package/dist/generated/types/models/design-system-links.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-links.js +1 -0
- package/dist/generated/types/models/design-system-shadows.d.ts +20 -0
- package/dist/generated/types/models/design-system-shadows.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-shadows.js +1 -0
- package/dist/generated/types/models/design-system-spacing.d.ts +13 -0
- package/dist/generated/types/models/design-system-spacing.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-spacing.js +1 -0
- package/dist/generated/types/models/design-system-transitions.d.ts +15 -0
- package/dist/generated/types/models/design-system-transitions.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-transitions.js +1 -0
- package/dist/generated/types/models/design-system-typography.d.ts +21 -0
- package/dist/generated/types/models/design-system-typography.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-typography.js +1 -0
- package/dist/generated/types/models/design-system.d.ts +138 -0
- package/dist/generated/types/models/design-system.d.ts.map +1 -0
- package/dist/generated/types/models/design-system.js +64 -0
- package/dist/generated/types/models/experiment.d.ts +57 -0
- package/dist/generated/types/models/experiment.d.ts.map +1 -0
- package/dist/generated/types/models/experiment.js +55 -0
- package/dist/generated/types/models/font-file.d.ts +16 -0
- package/dist/generated/types/models/font-file.d.ts.map +1 -0
- package/dist/generated/types/models/font-file.js +1 -0
- package/dist/generated/types/models/index.d.ts +38 -0
- package/dist/generated/types/models/index.d.ts.map +1 -0
- package/dist/generated/types/models/index.js +12 -0
- package/dist/generated/types/models/integration.d.ts +32 -0
- package/dist/generated/types/models/integration.d.ts.map +1 -0
- package/dist/generated/types/models/integration.js +26 -0
- package/dist/generated/types/models/route-tree.d.ts +43 -0
- package/dist/generated/types/models/route-tree.d.ts.map +1 -0
- package/dist/generated/types/models/route-tree.js +39 -0
- package/dist/generated/types/models/segment.d.ts +57 -0
- package/dist/generated/types/models/segment.d.ts.map +1 -0
- package/dist/generated/types/models/segment.js +55 -0
- package/dist/generated/types/models/shopify-collection.d.ts +32 -0
- package/dist/generated/types/models/shopify-collection.d.ts.map +1 -0
- package/dist/generated/types/models/shopify-collection.js +26 -0
- package/dist/generated/types/models/shopify-market.d.ts +32 -0
- package/dist/generated/types/models/shopify-market.d.ts.map +1 -0
- package/dist/generated/types/models/shopify-market.js +26 -0
- package/dist/generated/types/models/shopify-product.d.ts +32 -0
- package/dist/generated/types/models/shopify-product.d.ts.map +1 -0
- package/dist/generated/types/models/shopify-product.js +26 -0
- package/dist/generated/types/models/shopify-variant.d.ts +32 -0
- package/dist/generated/types/models/shopify-variant.d.ts.map +1 -0
- package/dist/generated/types/models/shopify-variant.js +26 -0
- package/dist/generated/types/models/template.d.ts +53 -0
- package/dist/generated/types/models/template.d.ts.map +1 -0
- package/dist/generated/types/models/template.js +40 -0
- package/dist/generated/types/models/typography-variant.d.ts +15 -0
- package/dist/generated/types/models/typography-variant.d.ts.map +1 -0
- package/dist/generated/types/models/typography-variant.js +1 -0
- package/dist/generated/types/scalars.d.ts +56 -0
- package/dist/generated/types/scalars.d.ts.map +1 -0
- package/dist/generated/types/scalars.js +6 -0
- package/dist/generators/admin/index.d.ts +32 -0
- package/dist/generators/admin/index.d.ts.map +1 -0
- package/dist/generators/admin/index.js +219 -0
- package/dist/generators/admin/mutations.d.ts +23 -0
- package/dist/generators/admin/mutations.d.ts.map +1 -0
- package/dist/generators/admin/mutations.js +424 -0
- package/dist/generators/admin/queries.d.ts +20 -0
- package/dist/generators/admin/queries.d.ts.map +1 -0
- package/dist/generators/admin/queries.js +476 -0
- package/dist/generators/admin/types.d.ts +28 -0
- package/dist/generators/admin/types.d.ts.map +1 -0
- package/dist/generators/admin/types.js +254 -0
- package/dist/generators/cms/index.d.ts +29 -0
- package/dist/generators/cms/index.d.ts.map +1 -0
- package/dist/generators/cms/index.js +126 -0
- package/dist/generators/cms/route.d.ts +27 -0
- package/dist/generators/cms/route.d.ts.map +1 -0
- package/dist/generators/cms/route.js +409 -0
- package/dist/generators/cms/types.d.ts +15 -0
- package/dist/generators/cms/types.d.ts.map +1 -0
- package/dist/generators/cms/types.js +137 -0
- package/dist/generators/contexts/index.d.ts +25 -0
- package/dist/generators/contexts/index.d.ts.map +1 -0
- package/dist/generators/contexts/index.js +591 -0
- package/dist/generators/documents/data-models.d.ts +6 -0
- package/dist/generators/documents/data-models.d.ts.map +1 -0
- package/dist/generators/documents/data-models.js +61 -0
- package/dist/generators/documents/entity-models.d.ts +7 -0
- package/dist/generators/documents/entity-models.d.ts.map +1 -0
- package/dist/generators/documents/entity-models.js +87 -0
- package/dist/generators/documents/workflows.d.ts +11 -0
- package/dist/generators/documents/workflows.d.ts.map +1 -0
- package/dist/generators/documents/workflows.js +101 -0
- package/dist/generators/filters/index.d.ts +16 -0
- package/dist/generators/filters/index.d.ts.map +1 -0
- package/dist/generators/filters/index.js +384 -0
- package/dist/generators/hooks/agnostic.d.ts +16 -0
- package/dist/generators/hooks/agnostic.d.ts.map +1 -0
- package/dist/generators/hooks/agnostic.js +248 -0
- package/dist/generators/hooks/index.d.ts +9 -0
- package/dist/generators/hooks/index.d.ts.map +1 -0
- package/dist/generators/hooks/index.js +8 -0
- package/dist/generators/hooks/react.d.ts +16 -0
- package/dist/generators/hooks/react.d.ts.map +1 -0
- package/dist/generators/hooks/react.js +394 -0
- package/dist/generators/hooks/remix.d.ts +16 -0
- package/dist/generators/hooks/remix.d.ts.map +1 -0
- package/dist/generators/hooks/remix.js +349 -0
- package/dist/generators/hooks/workflows.d.ts +23 -0
- package/dist/generators/hooks/workflows.d.ts.map +1 -0
- package/dist/generators/hooks/workflows.js +312 -0
- package/dist/generators/resolve/index.d.ts +13 -0
- package/dist/generators/resolve/index.d.ts.map +1 -0
- package/dist/generators/resolve/index.js +13 -0
- package/dist/generators/resolve/platform.d.ts +29 -0
- package/dist/generators/resolve/platform.d.ts.map +1 -0
- package/dist/generators/resolve/platform.js +479 -0
- package/dist/generators/types/config.d.ts +7 -0
- package/dist/generators/types/config.d.ts.map +1 -0
- package/dist/generators/types/config.js +113 -0
- package/dist/generators/types/data-models.d.ts +10 -0
- package/dist/generators/types/data-models.d.ts.map +1 -0
- package/dist/generators/types/data-models.js +100 -0
- package/dist/generators/types/entity-models.d.ts +13 -0
- package/dist/generators/types/entity-models.d.ts.map +1 -0
- package/dist/generators/types/entity-models.js +241 -0
- package/dist/generators/types/field-types.d.ts +9 -0
- package/dist/generators/types/field-types.d.ts.map +1 -0
- package/dist/generators/types/field-types.js +651 -0
- package/dist/generators/types/hooks.d.ts +7 -0
- package/dist/generators/types/hooks.d.ts.map +1 -0
- package/dist/generators/types/hooks.js +132 -0
- package/dist/generators/types/scalars.d.ts +6 -0
- package/dist/generators/types/scalars.d.ts.map +1 -0
- package/dist/generators/types/scalars.js +68 -0
- package/dist/generators/types/user-details.d.ts +6 -0
- package/dist/generators/types/user-details.d.ts.map +1 -0
- package/dist/generators/types/user-details.js +60 -0
- package/dist/generators/types/workflows.d.ts +15 -0
- package/dist/generators/types/workflows.d.ts.map +1 -0
- package/dist/generators/types/workflows.js +163 -0
- package/dist/graphql/generated/gql.d.ts +47 -0
- package/dist/graphql/generated/gql.d.ts.map +1 -0
- package/dist/graphql/generated/gql.js +10 -0
- package/dist/graphql/generated/graphql.d.ts +8455 -0
- package/dist/graphql/generated/graphql.d.ts.map +1 -0
- package/dist/graphql/generated/graphql.js +573 -0
- package/dist/graphql/generated/index.d.ts +2 -0
- package/dist/graphql/generated/index.d.ts.map +1 -0
- package/dist/graphql/generated/index.js +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/schema/define-entity-model.d.ts +122 -0
- package/dist/schema/define-entity-model.d.ts.map +1 -0
- package/dist/schema/define-entity-model.js +59 -0
- package/dist/schema/schema-loader.d.ts +10 -0
- package/dist/schema/schema-loader.d.ts.map +1 -0
- package/dist/schema/schema-loader.js +91 -0
- package/dist/utils/field-mapping.d.ts +83 -0
- package/dist/utils/field-mapping.d.ts.map +1 -0
- package/dist/utils/field-mapping.js +334 -0
- package/dist/writer/write-files.d.ts +12 -0
- package/dist/writer/write-files.d.ts.map +1 -0
- package/dist/writer/write-files.js +35 -0
- package/package.json +70 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { join, resolve } from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getCredentials } from '../auth/credentials.js';
|
|
5
|
+
import { generateSchemaFile } from '../schema/schema-loader.js';
|
|
6
|
+
/**
|
|
7
|
+
* Fetch entity models from the API
|
|
8
|
+
*/
|
|
9
|
+
async function fetchRemoteSchemas(apiUrl, accessToken) {
|
|
10
|
+
const response = await fetch(`${apiUrl}/graphql`, {
|
|
11
|
+
method: 'POST',
|
|
12
|
+
headers: {
|
|
13
|
+
'Content-Type': 'application/json',
|
|
14
|
+
Authorization: `Bearer ${accessToken}`,
|
|
15
|
+
},
|
|
16
|
+
body: JSON.stringify({
|
|
17
|
+
query: `
|
|
18
|
+
query GetEntityModels {
|
|
19
|
+
entityModels {
|
|
20
|
+
key
|
|
21
|
+
name
|
|
22
|
+
pluralName
|
|
23
|
+
description
|
|
24
|
+
tier
|
|
25
|
+
editorMode
|
|
26
|
+
fields {
|
|
27
|
+
key
|
|
28
|
+
type
|
|
29
|
+
label
|
|
30
|
+
required
|
|
31
|
+
helpText
|
|
32
|
+
placeholder
|
|
33
|
+
defaultValue
|
|
34
|
+
options
|
|
35
|
+
validation {
|
|
36
|
+
type
|
|
37
|
+
value
|
|
38
|
+
message
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
modes {
|
|
42
|
+
records
|
|
43
|
+
inline
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
`,
|
|
48
|
+
}),
|
|
49
|
+
});
|
|
50
|
+
if (!response.ok) {
|
|
51
|
+
throw new Error(`Failed to fetch schemas: ${response.statusText}`);
|
|
52
|
+
}
|
|
53
|
+
const result = (await response.json());
|
|
54
|
+
if (result.errors && result.errors.length > 0) {
|
|
55
|
+
throw new Error(`GraphQL error: ${result.errors[0]?.message ?? 'Unknown error'}`);
|
|
56
|
+
}
|
|
57
|
+
return result.data?.entityModels ?? [];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Init command - generate local schema files from platform schemas
|
|
61
|
+
*/
|
|
62
|
+
export async function init(options) {
|
|
63
|
+
const credentials = await getCredentials();
|
|
64
|
+
if (!credentials) {
|
|
65
|
+
console.log('Not logged in. Run `uniformgen login` first.');
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
if (!credentials.selectedProject) {
|
|
69
|
+
console.log('No project selected. Run `uniformgen select-project` first.');
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
console.log(`Initializing schemas from project: ${credentials.selectedProject.name}\n`);
|
|
73
|
+
// Fetch remote schemas
|
|
74
|
+
console.log('Fetching schemas from platform...');
|
|
75
|
+
const schemas = await fetchRemoteSchemas(options.apiUrl, credentials.accessToken);
|
|
76
|
+
if (schemas.length === 0) {
|
|
77
|
+
console.log(chalk.yellow('No schemas found in project.'));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
console.log(`Found ${schemas.length} schema(s)\n`);
|
|
81
|
+
// Ensure schemas directory exists
|
|
82
|
+
const schemasDir = resolve(process.cwd(), options.schemasDir);
|
|
83
|
+
await fs.mkdir(schemasDir, { recursive: true });
|
|
84
|
+
let created = 0;
|
|
85
|
+
let skipped = 0;
|
|
86
|
+
for (const schema of schemas) {
|
|
87
|
+
const filePath = join(schemasDir, `${schema.key}.schema.ts`);
|
|
88
|
+
// Check if file exists
|
|
89
|
+
try {
|
|
90
|
+
await fs.access(filePath);
|
|
91
|
+
if (!options.overwrite) {
|
|
92
|
+
console.log(chalk.gray(`- ${schema.key}.schema.ts`) + chalk.gray(' (exists, skipped)'));
|
|
93
|
+
skipped++;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// File doesn't exist, continue
|
|
99
|
+
}
|
|
100
|
+
// Generate schema file
|
|
101
|
+
const content = generateSchemaFile(schema);
|
|
102
|
+
await fs.writeFile(filePath, content, 'utf-8');
|
|
103
|
+
console.log(chalk.green(`+ ${schema.key}.schema.ts`));
|
|
104
|
+
created++;
|
|
105
|
+
}
|
|
106
|
+
// Summary
|
|
107
|
+
console.log('\n' + '─'.repeat(40));
|
|
108
|
+
console.log('Summary');
|
|
109
|
+
console.log('─'.repeat(40));
|
|
110
|
+
console.log(` Created: ${created}`);
|
|
111
|
+
console.log(` Skipped: ${skipped}`);
|
|
112
|
+
console.log(` Output: ${schemasDir}`);
|
|
113
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAQA,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AA4ED;;GAEG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAmIhE"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import open from 'open';
|
|
2
|
+
import http from 'http';
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
import { writeCredentials, } from '../auth/credentials.js';
|
|
5
|
+
/**
|
|
6
|
+
* Find an available port in a range
|
|
7
|
+
*/
|
|
8
|
+
async function findAvailablePort(start, end) {
|
|
9
|
+
for (let port = start; port <= end; port++) {
|
|
10
|
+
const available = await new Promise((resolve) => {
|
|
11
|
+
const server = http.createServer();
|
|
12
|
+
server.listen(port, () => {
|
|
13
|
+
server.close();
|
|
14
|
+
resolve(true);
|
|
15
|
+
});
|
|
16
|
+
server.on('error', () => resolve(false));
|
|
17
|
+
});
|
|
18
|
+
if (available) {
|
|
19
|
+
return port;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
throw new Error(`No available ports in range ${start}-${end}`);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Exchange authorization code for tokens
|
|
26
|
+
*/
|
|
27
|
+
async function exchangeCodeForTokens(apiUrl, code, codeVerifier, redirectUri) {
|
|
28
|
+
const tokenUrl = new URL('/auth/cli/token', apiUrl);
|
|
29
|
+
const response = await fetch(tokenUrl.toString(), {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
32
|
+
body: JSON.stringify({
|
|
33
|
+
grant_type: 'authorization_code',
|
|
34
|
+
code,
|
|
35
|
+
code_verifier: codeVerifier,
|
|
36
|
+
redirect_uri: redirectUri,
|
|
37
|
+
}),
|
|
38
|
+
});
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
const error = await response.text();
|
|
41
|
+
throw new Error(`Token exchange failed: ${error}`);
|
|
42
|
+
}
|
|
43
|
+
const data = (await response.json());
|
|
44
|
+
// Map snake_case API response to camelCase
|
|
45
|
+
return {
|
|
46
|
+
accessToken: data.access_token,
|
|
47
|
+
refreshToken: data.refresh_token,
|
|
48
|
+
expiresIn: data.expires_in,
|
|
49
|
+
user: data.user,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Login command - authenticate via browser OAuth
|
|
54
|
+
*/
|
|
55
|
+
export async function login(options) {
|
|
56
|
+
console.log('Starting authentication...\n');
|
|
57
|
+
// Generate PKCE values
|
|
58
|
+
const codeVerifier = crypto.randomBytes(32).toString('base64url');
|
|
59
|
+
const codeChallenge = crypto
|
|
60
|
+
.createHash('sha256')
|
|
61
|
+
.update(codeVerifier)
|
|
62
|
+
.digest('base64url');
|
|
63
|
+
const state = crypto.randomBytes(16).toString('hex');
|
|
64
|
+
const port = await findAvailablePort(9876, 9900);
|
|
65
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
66
|
+
// Start local server to receive callback
|
|
67
|
+
const authCode = await new Promise((resolve, reject) => {
|
|
68
|
+
const server = http.createServer((req, res) => {
|
|
69
|
+
const url = new URL(req.url, `http://localhost:${port}`);
|
|
70
|
+
if (url.pathname === '/callback') {
|
|
71
|
+
const code = url.searchParams.get('code');
|
|
72
|
+
const returnedState = url.searchParams.get('state');
|
|
73
|
+
const error = url.searchParams.get('error');
|
|
74
|
+
if (error) {
|
|
75
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
76
|
+
res.end(`
|
|
77
|
+
<html>
|
|
78
|
+
<body style="font-family: system-ui; text-align: center; padding: 50px;">
|
|
79
|
+
<h1>✗ Authentication failed</h1>
|
|
80
|
+
<p>${error}</p>
|
|
81
|
+
<p>You can close this window.</p>
|
|
82
|
+
</body>
|
|
83
|
+
</html>
|
|
84
|
+
`);
|
|
85
|
+
server.close();
|
|
86
|
+
reject(new Error(`Authentication failed: ${error}`));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (returnedState !== state) {
|
|
90
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
91
|
+
res.end(`
|
|
92
|
+
<html>
|
|
93
|
+
<body style="font-family: system-ui; text-align: center; padding: 50px;">
|
|
94
|
+
<h1>✗ Security error</h1>
|
|
95
|
+
<p>Invalid state parameter. Please try again.</p>
|
|
96
|
+
</body>
|
|
97
|
+
</html>
|
|
98
|
+
`);
|
|
99
|
+
server.close();
|
|
100
|
+
reject(new Error('Invalid state parameter'));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Derive admin URL from API URL (api-dev.eide.app -> admin-dev.eide.app)
|
|
104
|
+
const apiHost = new URL(options.apiUrl).host;
|
|
105
|
+
const adminHost = apiHost.replace(/^api/, 'admin');
|
|
106
|
+
const adminUrl = `https://${adminHost}`;
|
|
107
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
108
|
+
res.end(`
|
|
109
|
+
<html>
|
|
110
|
+
<head>
|
|
111
|
+
<meta http-equiv="refresh" content="2;url=${adminUrl}">
|
|
112
|
+
</head>
|
|
113
|
+
<body style="font-family: system-ui; text-align: center; padding: 50px;">
|
|
114
|
+
<h1>Authentication successful!</h1>
|
|
115
|
+
<p>Redirecting to admin panel...</p>
|
|
116
|
+
<p style="color: #666; font-size: 14px;">If not redirected, <a href="${adminUrl}">click here</a>.</p>
|
|
117
|
+
</body>
|
|
118
|
+
</html>
|
|
119
|
+
`);
|
|
120
|
+
server.close();
|
|
121
|
+
resolve(code);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
server.listen(port);
|
|
125
|
+
// Timeout after 5 minutes
|
|
126
|
+
setTimeout(() => {
|
|
127
|
+
server.close();
|
|
128
|
+
reject(new Error('Authentication timed out after 5 minutes'));
|
|
129
|
+
}, 5 * 60 * 1000);
|
|
130
|
+
// Build auth URL and open browser
|
|
131
|
+
const authUrl = new URL('/auth/cli', options.apiUrl);
|
|
132
|
+
authUrl.searchParams.set('response_type', 'code');
|
|
133
|
+
authUrl.searchParams.set('code_challenge', codeChallenge);
|
|
134
|
+
authUrl.searchParams.set('code_challenge_method', 'S256');
|
|
135
|
+
authUrl.searchParams.set('redirect_uri', redirectUri);
|
|
136
|
+
authUrl.searchParams.set('state', state);
|
|
137
|
+
console.log('Opening browser for authentication...');
|
|
138
|
+
console.log(`If the browser doesn't open, visit: ${authUrl.toString()}\n`);
|
|
139
|
+
open(authUrl.toString()).catch(() => {
|
|
140
|
+
console.log('Could not open browser automatically.');
|
|
141
|
+
console.log(`Please visit: ${authUrl.toString()}\n`);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
console.log('Exchanging code for tokens...');
|
|
145
|
+
// Exchange code for tokens
|
|
146
|
+
const tokens = await exchangeCodeForTokens(options.apiUrl, authCode, codeVerifier, redirectUri);
|
|
147
|
+
// Store credentials
|
|
148
|
+
const credentials = {
|
|
149
|
+
accessToken: tokens.accessToken,
|
|
150
|
+
refreshToken: tokens.refreshToken,
|
|
151
|
+
expiresAt: new Date(Date.now() + tokens.expiresIn * 1000).toISOString(),
|
|
152
|
+
user: tokens.user,
|
|
153
|
+
};
|
|
154
|
+
await writeCredentials(credentials);
|
|
155
|
+
console.log(`\n✓ Logged in as ${tokens.user.email}`);
|
|
156
|
+
console.log('\nRun `uniformgen select-project` to choose a project.');
|
|
157
|
+
process.exit(0);
|
|
158
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAU5C"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { deleteCredentials, getCredentials } from '../auth/credentials.js';
|
|
2
|
+
/**
|
|
3
|
+
* Logout command - clear stored credentials
|
|
4
|
+
*/
|
|
5
|
+
export async function logout() {
|
|
6
|
+
const credentials = await getCredentials();
|
|
7
|
+
if (!credentials) {
|
|
8
|
+
console.log('Not logged in.');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
await deleteCredentials();
|
|
12
|
+
console.log(`✓ Logged out (was ${credentials.user.email})`);
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface PushOptions {
|
|
2
|
+
apiUrl: string;
|
|
3
|
+
schemasDir: string;
|
|
4
|
+
pattern?: string;
|
|
5
|
+
dryRun?: boolean;
|
|
6
|
+
publish?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Push command - sync local schemas to platform
|
|
10
|
+
*/
|
|
11
|
+
export declare function push(options: PushOptions): Promise<void>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=push.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/commands/push.ts"],"names":[],"mappings":"AAaA,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAmVD;;GAEG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAkJ9D"}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { getCredentials } from '../auth/credentials.js';
|
|
3
|
+
import { loadSchemas } from '../schema/schema-loader.js';
|
|
4
|
+
/**
|
|
5
|
+
* Get the internal GraphQL endpoint URL from the base API URL
|
|
6
|
+
*/
|
|
7
|
+
function getGraphQLEndpoint(apiUrl) {
|
|
8
|
+
const base = apiUrl.replace(/\/$/, '').replace(/\/graphql$/, '');
|
|
9
|
+
return `${base}/graphql`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Fetch existing entity models from the API
|
|
13
|
+
*/
|
|
14
|
+
async function fetchRemoteSchemas(apiUrl, accessToken, tenantId, projectId) {
|
|
15
|
+
const response = await fetch(getGraphQLEndpoint(apiUrl), {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
Authorization: `Bearer ${accessToken}`,
|
|
20
|
+
'x-tenant-id': tenantId,
|
|
21
|
+
'x-project-id': projectId,
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
query: `
|
|
25
|
+
query GetEntityModels {
|
|
26
|
+
entityModels(limit: 500) {
|
|
27
|
+
items {
|
|
28
|
+
id
|
|
29
|
+
key
|
|
30
|
+
metadata {
|
|
31
|
+
name
|
|
32
|
+
description
|
|
33
|
+
pluralName
|
|
34
|
+
}
|
|
35
|
+
schema
|
|
36
|
+
currentVersionId
|
|
37
|
+
}
|
|
38
|
+
total
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
`,
|
|
42
|
+
}),
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const errorText = await response.text().catch(() => 'No response body');
|
|
46
|
+
console.error(`[Debug] API URL: ${apiUrl}`);
|
|
47
|
+
console.error(`[Debug] Response status: ${response.status}`);
|
|
48
|
+
console.error(`[Debug] Response body: ${errorText.substring(0, 500)}`);
|
|
49
|
+
throw new Error(`Failed to fetch schemas: ${response.statusText}`);
|
|
50
|
+
}
|
|
51
|
+
const result = (await response.json());
|
|
52
|
+
if (result.errors && result.errors.length > 0) {
|
|
53
|
+
console.error(`[Debug] GraphQL errors:`, JSON.stringify(result.errors, null, 2));
|
|
54
|
+
throw new Error(`GraphQL error: ${result.errors[0]?.message ?? 'Unknown error'}`);
|
|
55
|
+
}
|
|
56
|
+
const models = new Map();
|
|
57
|
+
for (const model of result.data?.entityModels?.items ?? []) {
|
|
58
|
+
models.set(model.key, model);
|
|
59
|
+
}
|
|
60
|
+
return models;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Create a new entity model
|
|
64
|
+
*/
|
|
65
|
+
async function createEntityModel(apiUrl, accessToken, tenantId, projectId, model) {
|
|
66
|
+
const response = await fetch(`${apiUrl}/graphql`, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: {
|
|
69
|
+
'Content-Type': 'application/json',
|
|
70
|
+
Authorization: `Bearer ${accessToken}`,
|
|
71
|
+
'x-tenant-id': tenantId,
|
|
72
|
+
'x-project-id': projectId,
|
|
73
|
+
},
|
|
74
|
+
body: JSON.stringify({
|
|
75
|
+
query: `
|
|
76
|
+
mutation CreateEntityModel($input: CreateEntityModelInput!) {
|
|
77
|
+
createEntityModel(input: $input) {
|
|
78
|
+
id
|
|
79
|
+
key
|
|
80
|
+
currentVersionId
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
`,
|
|
84
|
+
variables: {
|
|
85
|
+
input: {
|
|
86
|
+
key: model.key,
|
|
87
|
+
metadata: {
|
|
88
|
+
name: model.name,
|
|
89
|
+
description: model.description,
|
|
90
|
+
pluralName: model.pluralName,
|
|
91
|
+
},
|
|
92
|
+
schema: {
|
|
93
|
+
fields: model.fields,
|
|
94
|
+
},
|
|
95
|
+
modes: model.modes,
|
|
96
|
+
editorMode: model.editorMode,
|
|
97
|
+
pages: model.pages,
|
|
98
|
+
hooks: model.hooks,
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
}),
|
|
102
|
+
});
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
throw new Error(`Failed to create schema: ${response.statusText}`);
|
|
105
|
+
}
|
|
106
|
+
const result = (await response.json());
|
|
107
|
+
if (result.errors && result.errors.length > 0) {
|
|
108
|
+
throw new Error(result.errors[0]?.message ?? 'Unknown error');
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
id: result.data.createEntityModel.id,
|
|
112
|
+
currentVersionId: result.data.createEntityModel.currentVersionId,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Update an entity model schema
|
|
117
|
+
*/
|
|
118
|
+
async function updateEntityModelSchema(apiUrl, accessToken, tenantId, projectId, modelId, model) {
|
|
119
|
+
const response = await fetch(`${apiUrl}/graphql`, {
|
|
120
|
+
method: 'POST',
|
|
121
|
+
headers: {
|
|
122
|
+
'Content-Type': 'application/json',
|
|
123
|
+
Authorization: `Bearer ${accessToken}`,
|
|
124
|
+
'x-tenant-id': tenantId,
|
|
125
|
+
'x-project-id': projectId,
|
|
126
|
+
},
|
|
127
|
+
body: JSON.stringify({
|
|
128
|
+
query: `
|
|
129
|
+
mutation UpdateEntityModel($id: ID!, $input: UpdateEntityModelInput!) {
|
|
130
|
+
updateEntityModel(id: $id, input: $input) {
|
|
131
|
+
id
|
|
132
|
+
key
|
|
133
|
+
currentVersionId
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
`,
|
|
137
|
+
variables: {
|
|
138
|
+
id: modelId,
|
|
139
|
+
input: {
|
|
140
|
+
metadata: {
|
|
141
|
+
name: model.name,
|
|
142
|
+
description: model.description,
|
|
143
|
+
pluralName: model.pluralName,
|
|
144
|
+
},
|
|
145
|
+
schema: {
|
|
146
|
+
fields: model.fields,
|
|
147
|
+
},
|
|
148
|
+
modes: model.modes,
|
|
149
|
+
editorMode: model.editorMode,
|
|
150
|
+
pages: model.pages,
|
|
151
|
+
hooks: model.hooks,
|
|
152
|
+
changeDescription: `Updated via uniformgen push`,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
}),
|
|
156
|
+
});
|
|
157
|
+
if (!response.ok) {
|
|
158
|
+
throw new Error(`Failed to update schema: ${response.statusText}`);
|
|
159
|
+
}
|
|
160
|
+
const result = (await response.json());
|
|
161
|
+
if (result.errors && result.errors.length > 0) {
|
|
162
|
+
throw new Error(result.errors[0]?.message ?? 'Unknown error');
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
id: result.data.updateEntityModel.id,
|
|
166
|
+
currentVersionId: result.data.updateEntityModel.currentVersionId,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Publish an entity model schema
|
|
171
|
+
*/
|
|
172
|
+
async function publishEntityModelSchema(apiUrl, accessToken, tenantId, projectId, modelId, versionId) {
|
|
173
|
+
const response = await fetch(`${apiUrl}/graphql`, {
|
|
174
|
+
method: 'POST',
|
|
175
|
+
headers: {
|
|
176
|
+
'Content-Type': 'application/json',
|
|
177
|
+
Authorization: `Bearer ${accessToken}`,
|
|
178
|
+
'x-tenant-id': tenantId,
|
|
179
|
+
'x-project-id': projectId,
|
|
180
|
+
},
|
|
181
|
+
body: JSON.stringify({
|
|
182
|
+
query: `
|
|
183
|
+
mutation PublishEntityModel($id: ID!, $versionId: ID!) {
|
|
184
|
+
publishEntityModel(id: $id, versionId: $versionId) {
|
|
185
|
+
id
|
|
186
|
+
key
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
`,
|
|
190
|
+
variables: { id: modelId, versionId },
|
|
191
|
+
}),
|
|
192
|
+
});
|
|
193
|
+
if (!response.ok) {
|
|
194
|
+
throw new Error(`Failed to publish schema: ${response.statusText}`);
|
|
195
|
+
}
|
|
196
|
+
const result = (await response.json());
|
|
197
|
+
if (result.errors && result.errors.length > 0) {
|
|
198
|
+
throw new Error(result.errors[0]?.message ?? 'Unknown error');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Compare two schemas and determine if they differ
|
|
203
|
+
*/
|
|
204
|
+
function schemasAreDifferent(local, remote) {
|
|
205
|
+
// Compare basic properties via metadata
|
|
206
|
+
if (local.name !== remote.metadata.name ||
|
|
207
|
+
local.pluralName !== remote.metadata.pluralName ||
|
|
208
|
+
local.description !== remote.metadata.description) {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
// Compare fields
|
|
212
|
+
const localFields = local.fields ?? [];
|
|
213
|
+
const remoteFields = remote.schema?.fields ?? [];
|
|
214
|
+
if (localFields.length !== remoteFields.length) {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
for (let i = 0; i < localFields.length; i++) {
|
|
218
|
+
const localField = localFields[i];
|
|
219
|
+
const remoteField = remoteFields[i];
|
|
220
|
+
if (localField.key !== remoteField.key ||
|
|
221
|
+
localField.type !== remoteField.type ||
|
|
222
|
+
localField.label !== remoteField.label ||
|
|
223
|
+
localField.required !== remoteField.required ||
|
|
224
|
+
localField.helpText !== remoteField.helpText ||
|
|
225
|
+
JSON.stringify(localField.options) !== JSON.stringify(remoteField.options)) {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Push command - sync local schemas to platform
|
|
233
|
+
*/
|
|
234
|
+
export async function push(options) {
|
|
235
|
+
const credentials = await getCredentials();
|
|
236
|
+
if (!credentials) {
|
|
237
|
+
console.log('Not logged in. Run `uniformgen login` first.');
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
if (!credentials.selectedProject) {
|
|
241
|
+
console.log('No project selected. Run `uniformgen select-project` first.');
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
console.log(`Syncing schemas to project: ${credentials.selectedProject.name}\n`);
|
|
245
|
+
// Load local schemas
|
|
246
|
+
console.log(`Loading schemas from ${options.schemasDir}...`);
|
|
247
|
+
const localSchemas = await loadSchemas(options.schemasDir, options.pattern);
|
|
248
|
+
if (localSchemas.length === 0) {
|
|
249
|
+
console.log(chalk.yellow('No schema files found.'));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
console.log(`Found ${localSchemas.length} local schema(s)\n`);
|
|
253
|
+
// Fetch remote schemas
|
|
254
|
+
console.log('Fetching remote schemas...');
|
|
255
|
+
const remoteSchemas = await fetchRemoteSchemas(options.apiUrl, credentials.accessToken, credentials.selectedProject.tenantId, credentials.selectedProject.id);
|
|
256
|
+
console.log(`Found ${remoteSchemas.size} remote schema(s)\n`);
|
|
257
|
+
// Compare and sync
|
|
258
|
+
const result = {
|
|
259
|
+
created: [],
|
|
260
|
+
updated: [],
|
|
261
|
+
unchanged: [],
|
|
262
|
+
errors: [],
|
|
263
|
+
};
|
|
264
|
+
for (const local of localSchemas) {
|
|
265
|
+
const remote = remoteSchemas.get(local.key);
|
|
266
|
+
if (!remote) {
|
|
267
|
+
// Create new schema
|
|
268
|
+
if (options.dryRun) {
|
|
269
|
+
console.log(chalk.green(`+ ${local.key}`) + chalk.gray(' (would create)'));
|
|
270
|
+
result.created.push(local.key);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
try {
|
|
274
|
+
const created = await createEntityModel(options.apiUrl, credentials.accessToken, credentials.selectedProject.tenantId, credentials.selectedProject.id, local);
|
|
275
|
+
if (options.publish && created.currentVersionId) {
|
|
276
|
+
await publishEntityModelSchema(options.apiUrl, credentials.accessToken, credentials.selectedProject.tenantId, credentials.selectedProject.id, created.id, created.currentVersionId);
|
|
277
|
+
}
|
|
278
|
+
console.log(chalk.green(`+ ${local.key}`) + chalk.gray(' (created)'));
|
|
279
|
+
result.created.push(local.key);
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
283
|
+
console.log(chalk.red(`✗ ${local.key}`) + chalk.gray(` (error: ${message})`));
|
|
284
|
+
result.errors.push({ key: local.key, error: message });
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
else if (schemasAreDifferent(local, remote)) {
|
|
289
|
+
// Update existing schema
|
|
290
|
+
if (options.dryRun) {
|
|
291
|
+
console.log(chalk.yellow(`~ ${local.key}`) + chalk.gray(' (would update)'));
|
|
292
|
+
result.updated.push(local.key);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
try {
|
|
296
|
+
const updated = await updateEntityModelSchema(options.apiUrl, credentials.accessToken, credentials.selectedProject.tenantId, credentials.selectedProject.id, remote.id, local);
|
|
297
|
+
if (options.publish && updated.currentVersionId) {
|
|
298
|
+
await publishEntityModelSchema(options.apiUrl, credentials.accessToken, credentials.selectedProject.tenantId, credentials.selectedProject.id, updated.id, updated.currentVersionId);
|
|
299
|
+
}
|
|
300
|
+
console.log(chalk.yellow(`~ ${local.key}`) + chalk.gray(' (updated)'));
|
|
301
|
+
result.updated.push(local.key);
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
305
|
+
console.log(chalk.red(`✗ ${local.key}`) + chalk.gray(` (error: ${message})`));
|
|
306
|
+
result.errors.push({ key: local.key, error: message });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
console.log(chalk.gray(`= ${local.key}`) + chalk.gray(' (unchanged)'));
|
|
312
|
+
result.unchanged.push(local.key);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Summary
|
|
316
|
+
console.log('\n' + '─'.repeat(40));
|
|
317
|
+
console.log('Summary');
|
|
318
|
+
console.log('─'.repeat(40));
|
|
319
|
+
console.log(` Created: ${result.created.length}`);
|
|
320
|
+
console.log(` Updated: ${result.updated.length}`);
|
|
321
|
+
console.log(` Unchanged: ${result.unchanged.length}`);
|
|
322
|
+
if (result.errors.length > 0) {
|
|
323
|
+
console.log(` Errors: ${result.errors.length}`);
|
|
324
|
+
}
|
|
325
|
+
if (options.dryRun) {
|
|
326
|
+
console.log(chalk.cyan('\n(Dry run - no changes made)'));
|
|
327
|
+
}
|
|
328
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scaffold Command
|
|
3
|
+
*
|
|
4
|
+
* Generates component stubs for EIDE entity models using @eide/foir-renderer.
|
|
5
|
+
* Creates type-safe components that integrate with the EntityRenderer.
|
|
6
|
+
*/
|
|
7
|
+
export interface ScaffoldOptions {
|
|
8
|
+
apiUrl: string;
|
|
9
|
+
componentsDir: string;
|
|
10
|
+
models?: string;
|
|
11
|
+
overwrite?: boolean;
|
|
12
|
+
framework?: 'react' | 'remix' | 'next';
|
|
13
|
+
config?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Main scaffold function
|
|
17
|
+
*/
|
|
18
|
+
export declare function scaffold(options: ScaffoldOptions): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=scaffold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/commands/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAmSD;;GAEG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAsGtE"}
|