@geekmidas/cli 0.54.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +26 -5
- package/dist/CachedStateProvider-D73dCqfH.cjs +60 -0
- package/dist/CachedStateProvider-D73dCqfH.cjs.map +1 -0
- package/dist/CachedStateProvider-DVyKfaMm.mjs +54 -0
- package/dist/CachedStateProvider-DVyKfaMm.mjs.map +1 -0
- package/dist/CachedStateProvider-D_uISMmJ.cjs +3 -0
- package/dist/CachedStateProvider-OiFUGr7p.mjs +3 -0
- package/dist/HostingerProvider-DUV9-Tzg.cjs +210 -0
- package/dist/HostingerProvider-DUV9-Tzg.cjs.map +1 -0
- package/dist/HostingerProvider-DqUq6e9i.mjs +210 -0
- package/dist/HostingerProvider-DqUq6e9i.mjs.map +1 -0
- package/dist/LocalStateProvider-CdspeSVL.cjs +43 -0
- package/dist/LocalStateProvider-CdspeSVL.cjs.map +1 -0
- package/dist/LocalStateProvider-DxoSaWUV.mjs +42 -0
- package/dist/LocalStateProvider-DxoSaWUV.mjs.map +1 -0
- package/dist/Route53Provider-CpRIqu69.cjs +157 -0
- package/dist/Route53Provider-CpRIqu69.cjs.map +1 -0
- package/dist/Route53Provider-KUAX3vz9.mjs +156 -0
- package/dist/Route53Provider-KUAX3vz9.mjs.map +1 -0
- package/dist/SSMStateProvider-BxAPU99a.cjs +53 -0
- package/dist/SSMStateProvider-BxAPU99a.cjs.map +1 -0
- package/dist/SSMStateProvider-C4wp4AZe.mjs +52 -0
- package/dist/SSMStateProvider-C4wp4AZe.mjs.map +1 -0
- package/dist/{bundler-DGry2vaR.mjs → bundler-BqTN5Dj5.mjs} +3 -3
- package/dist/{bundler-DGry2vaR.mjs.map → bundler-BqTN5Dj5.mjs.map} +1 -1
- package/dist/{bundler-BB-kETMd.cjs → bundler-tHLLwYuU.cjs} +3 -3
- package/dist/{bundler-BB-kETMd.cjs.map → bundler-tHLLwYuU.cjs.map} +1 -1
- package/dist/{config-HYiM3iQJ.cjs → config-BGeJsW1r.cjs} +2 -2
- package/dist/{config-HYiM3iQJ.cjs.map → config-BGeJsW1r.cjs.map} +1 -1
- package/dist/{config-C3LSBNSl.mjs → config-C6awcFBx.mjs} +2 -2
- package/dist/{config-C3LSBNSl.mjs.map → config-C6awcFBx.mjs.map} +1 -1
- package/dist/config.cjs +2 -2
- package/dist/config.d.cts +1 -1
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs +2 -2
- package/dist/credentials-C8DWtnMY.cjs +174 -0
- package/dist/credentials-C8DWtnMY.cjs.map +1 -0
- package/dist/credentials-DT1dSxIx.mjs +126 -0
- package/dist/credentials-DT1dSxIx.mjs.map +1 -0
- package/dist/deploy/sniffer-envkit-patch.cjs.map +1 -1
- package/dist/deploy/sniffer-envkit-patch.mjs.map +1 -1
- package/dist/deploy/sniffer-loader.cjs +1 -1
- package/dist/{dokploy-api-94KzmTVf.mjs → dokploy-api-7k3t7_zd.mjs} +1 -1
- package/dist/{dokploy-api-94KzmTVf.mjs.map → dokploy-api-7k3t7_zd.mjs.map} +1 -1
- package/dist/dokploy-api-CHa8G51l.mjs +3 -0
- package/dist/{dokploy-api-YD8WCQfW.cjs → dokploy-api-CQvhV6Hd.cjs} +1 -1
- package/dist/{dokploy-api-YD8WCQfW.cjs.map → dokploy-api-CQvhV6Hd.cjs.map} +1 -1
- package/dist/dokploy-api-CWc02yyg.cjs +3 -0
- package/dist/{encryption-DaCB_NmS.cjs → encryption-BE0UOb8j.cjs} +1 -1
- package/dist/{encryption-DaCB_NmS.cjs.map → encryption-BE0UOb8j.cjs.map} +1 -1
- package/dist/{encryption-Biq0EZ4m.cjs → encryption-Cv3zips0.cjs} +1 -1
- package/dist/{encryption-BC4MAODn.mjs → encryption-JtMsiGNp.mjs} +1 -1
- package/dist/{encryption-BC4MAODn.mjs.map → encryption-JtMsiGNp.mjs.map} +1 -1
- package/dist/encryption-UUmaWAmz.mjs +3 -0
- package/dist/{index-pOA56MWT.d.cts → index-B5rGIc4g.d.cts} +553 -196
- package/dist/index-B5rGIc4g.d.cts.map +1 -0
- package/dist/{index-A70abJ1m.d.mts → index-KFEbMIRa.d.mts} +554 -197
- package/dist/index-KFEbMIRa.d.mts.map +1 -0
- package/dist/index.cjs +2223 -606
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +2200 -583
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-C3C-BzIZ.mjs → openapi-BMFmLnX6.mjs} +51 -7
- package/dist/openapi-BMFmLnX6.mjs.map +1 -0
- package/dist/{openapi-D7WwlpPF.cjs → openapi-D1KXv2Ml.cjs} +51 -7
- package/dist/openapi-D1KXv2Ml.cjs.map +1 -0
- package/dist/{openapi-react-query-C_MxpBgF.cjs → openapi-react-query-BeXvk-wa.cjs} +1 -1
- package/dist/{openapi-react-query-C_MxpBgF.cjs.map → openapi-react-query-BeXvk-wa.cjs.map} +1 -1
- package/dist/{openapi-react-query-ZoP9DPbY.mjs → openapi-react-query-DGEkD39r.mjs} +1 -1
- package/dist/{openapi-react-query-ZoP9DPbY.mjs.map → openapi-react-query-DGEkD39r.mjs.map} +1 -1
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.cjs +3 -3
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +2 -2
- package/dist/openapi.mjs +3 -3
- package/dist/{storage-Dhst7BhI.mjs → storage-BMW6yLu3.mjs} +1 -1
- package/dist/{storage-Dhst7BhI.mjs.map → storage-BMW6yLu3.mjs.map} +1 -1
- package/dist/{storage-fOR8dMu5.cjs → storage-C7pmBq1u.cjs} +1 -1
- package/dist/{storage-BPRgh3DU.cjs → storage-CoCNe0Pt.cjs} +1 -1
- package/dist/{storage-BPRgh3DU.cjs.map → storage-CoCNe0Pt.cjs.map} +1 -1
- package/dist/{storage-DNj_I11J.mjs → storage-D8XzjVaO.mjs} +1 -1
- package/dist/{types-BtGL-8QS.d.mts → types-BldpmqQX.d.mts} +1 -1
- package/dist/{types-BtGL-8QS.d.mts.map → types-BldpmqQX.d.mts.map} +1 -1
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +1 -1
- package/dist/workspace/index.d.mts +2 -2
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-CaVW6j2q.cjs → workspace-BFRUOOrh.cjs} +309 -25
- package/dist/workspace-BFRUOOrh.cjs.map +1 -0
- package/dist/{workspace-DLFRaDc-.mjs → workspace-DAxG3_H2.mjs} +309 -25
- package/dist/workspace-DAxG3_H2.mjs.map +1 -0
- package/package.json +12 -8
- package/src/build/__tests__/handler-templates.spec.ts +115 -47
- package/src/deploy/CachedStateProvider.ts +86 -0
- package/src/deploy/LocalStateProvider.ts +57 -0
- package/src/deploy/SSMStateProvider.ts +93 -0
- package/src/deploy/StateProvider.ts +171 -0
- package/src/deploy/__tests__/CachedStateProvider.spec.ts +228 -0
- package/src/deploy/__tests__/HostingerProvider.spec.ts +347 -0
- package/src/deploy/__tests__/LocalStateProvider.spec.ts +126 -0
- package/src/deploy/__tests__/Route53Provider.spec.ts +402 -0
- package/src/deploy/__tests__/SSMStateProvider.spec.ts +177 -0
- package/src/deploy/__tests__/__fixtures__/env-parsers/throwing-env-parser.ts +1 -3
- package/src/deploy/__tests__/__fixtures__/route-apps/services.ts +28 -19
- package/src/deploy/__tests__/createDnsProvider.spec.ts +172 -0
- package/src/deploy/__tests__/createStateProvider.spec.ts +116 -0
- package/src/deploy/__tests__/dns-orchestration.spec.ts +192 -0
- package/src/deploy/__tests__/dns-verification.spec.ts +2 -2
- package/src/deploy/__tests__/env-resolver.spec.ts +37 -15
- package/src/deploy/__tests__/sniffer.spec.ts +4 -20
- package/src/deploy/__tests__/state.spec.ts +13 -5
- package/src/deploy/dns/DnsProvider.ts +163 -0
- package/src/deploy/dns/HostingerProvider.ts +100 -0
- package/src/deploy/dns/Route53Provider.ts +256 -0
- package/src/deploy/dns/index.ts +257 -165
- package/src/deploy/env-resolver.ts +12 -5
- package/src/deploy/index.ts +16 -13
- package/src/deploy/sniffer-envkit-patch.ts +3 -1
- package/src/deploy/sniffer-routes-worker.ts +104 -0
- package/src/deploy/sniffer.ts +77 -55
- package/src/deploy/state-commands.ts +274 -0
- package/src/dev/__tests__/entry.spec.ts +8 -2
- package/src/dev/__tests__/index.spec.ts +1 -3
- package/src/dev/index.ts +9 -3
- package/src/docker/__tests__/templates.spec.ts +3 -1
- package/src/index.ts +88 -0
- package/src/init/__tests__/generators.spec.ts +273 -0
- package/src/init/__tests__/init.spec.ts +3 -3
- package/src/init/generators/auth.ts +1 -0
- package/src/init/generators/config.ts +2 -0
- package/src/init/generators/models.ts +6 -1
- package/src/init/generators/monorepo.ts +3 -0
- package/src/init/generators/ui.ts +1472 -0
- package/src/init/generators/web.ts +134 -87
- package/src/init/index.ts +22 -3
- package/src/init/templates/api.ts +109 -3
- package/src/openapi.ts +99 -13
- package/src/workspace/__tests__/schema.spec.ts +107 -0
- package/src/workspace/schema.ts +314 -4
- package/src/workspace/types.ts +22 -36
- package/dist/dokploy-api-CItuaWTq.mjs +0 -3
- package/dist/dokploy-api-DBNE8MDt.cjs +0 -3
- package/dist/encryption-CQXBZGkt.mjs +0 -3
- package/dist/index-A70abJ1m.d.mts.map +0 -1
- package/dist/index-pOA56MWT.d.cts.map +0 -1
- package/dist/openapi-C3C-BzIZ.mjs.map +0 -1
- package/dist/openapi-D7WwlpPF.cjs.map +0 -1
- package/dist/workspace-CaVW6j2q.cjs.map +0 -1
- package/dist/workspace-DLFRaDc-.mjs.map +0 -1
- package/tsconfig.tsbuildinfo +0 -1
package/src/index.ts
CHANGED
|
@@ -6,6 +6,12 @@ import { loginCommand, logoutCommand, whoamiCommand } from './auth';
|
|
|
6
6
|
import { buildCommand } from './build/index';
|
|
7
7
|
import { type DeployProvider, deployCommand } from './deploy/index';
|
|
8
8
|
import { deployInitCommand, deployListCommand } from './deploy/init';
|
|
9
|
+
import {
|
|
10
|
+
stateDiffCommand,
|
|
11
|
+
statePullCommand,
|
|
12
|
+
statePushCommand,
|
|
13
|
+
stateShowCommand,
|
|
14
|
+
} from './deploy/state-commands';
|
|
9
15
|
import { devCommand, execCommand } from './dev/index';
|
|
10
16
|
import { type DockerOptions, dockerCommand } from './docker/index';
|
|
11
17
|
import { type InitOptions, initCommand } from './init/index';
|
|
@@ -710,4 +716,86 @@ program
|
|
|
710
716
|
}
|
|
711
717
|
});
|
|
712
718
|
|
|
719
|
+
// State management commands
|
|
720
|
+
program
|
|
721
|
+
.command('state:pull')
|
|
722
|
+
.description('Pull deployment state from remote to local')
|
|
723
|
+
.requiredOption(
|
|
724
|
+
'--stage <stage>',
|
|
725
|
+
'Deployment stage (e.g., production, staging)',
|
|
726
|
+
)
|
|
727
|
+
.action(async (options: { stage: string }) => {
|
|
728
|
+
try {
|
|
729
|
+
const globalOptions = program.opts();
|
|
730
|
+
if (globalOptions.cwd) {
|
|
731
|
+
process.chdir(globalOptions.cwd);
|
|
732
|
+
}
|
|
733
|
+
await statePullCommand(options);
|
|
734
|
+
} catch (error) {
|
|
735
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
736
|
+
process.exit(1);
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
program
|
|
741
|
+
.command('state:push')
|
|
742
|
+
.description('Push deployment state from local to remote')
|
|
743
|
+
.requiredOption(
|
|
744
|
+
'--stage <stage>',
|
|
745
|
+
'Deployment stage (e.g., production, staging)',
|
|
746
|
+
)
|
|
747
|
+
.action(async (options: { stage: string }) => {
|
|
748
|
+
try {
|
|
749
|
+
const globalOptions = program.opts();
|
|
750
|
+
if (globalOptions.cwd) {
|
|
751
|
+
process.chdir(globalOptions.cwd);
|
|
752
|
+
}
|
|
753
|
+
await statePushCommand(options);
|
|
754
|
+
} catch (error) {
|
|
755
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
756
|
+
process.exit(1);
|
|
757
|
+
}
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
program
|
|
761
|
+
.command('state:show')
|
|
762
|
+
.description('Show deployment state for a stage')
|
|
763
|
+
.requiredOption(
|
|
764
|
+
'--stage <stage>',
|
|
765
|
+
'Deployment stage (e.g., production, staging)',
|
|
766
|
+
)
|
|
767
|
+
.option('--json', 'Output as JSON')
|
|
768
|
+
.action(async (options: { stage: string; json?: boolean }) => {
|
|
769
|
+
try {
|
|
770
|
+
const globalOptions = program.opts();
|
|
771
|
+
if (globalOptions.cwd) {
|
|
772
|
+
process.chdir(globalOptions.cwd);
|
|
773
|
+
}
|
|
774
|
+
await stateShowCommand(options);
|
|
775
|
+
} catch (error) {
|
|
776
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
777
|
+
process.exit(1);
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
program
|
|
782
|
+
.command('state:diff')
|
|
783
|
+
.description('Compare local and remote deployment state')
|
|
784
|
+
.requiredOption(
|
|
785
|
+
'--stage <stage>',
|
|
786
|
+
'Deployment stage (e.g., production, staging)',
|
|
787
|
+
)
|
|
788
|
+
.action(async (options: { stage: string }) => {
|
|
789
|
+
try {
|
|
790
|
+
const globalOptions = program.opts();
|
|
791
|
+
if (globalOptions.cwd) {
|
|
792
|
+
process.chdir(globalOptions.cwd);
|
|
793
|
+
}
|
|
794
|
+
await stateDiffCommand(options);
|
|
795
|
+
} catch (error) {
|
|
796
|
+
console.error(error instanceof Error ? error.message : 'Command failed');
|
|
797
|
+
process.exit(1);
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
|
|
713
801
|
program.parse();
|
|
@@ -5,6 +5,7 @@ import { generateEnvFiles } from '../generators/env.js';
|
|
|
5
5
|
import { generateModelsPackage } from '../generators/models.js';
|
|
6
6
|
import { generateMonorepoFiles } from '../generators/monorepo.js';
|
|
7
7
|
import { generatePackageJson } from '../generators/package.js';
|
|
8
|
+
import { generateUiPackageFiles } from '../generators/ui.js';
|
|
8
9
|
import type { TemplateOptions } from '../templates/index.js';
|
|
9
10
|
import { minimalTemplate } from '../templates/minimal.js';
|
|
10
11
|
import { serverlessTemplate } from '../templates/serverless.js';
|
|
@@ -372,3 +373,275 @@ describe('generateModelsPackage', () => {
|
|
|
372
373
|
expect(config.extends).toBe('../../tsconfig.json');
|
|
373
374
|
});
|
|
374
375
|
});
|
|
376
|
+
|
|
377
|
+
describe('generateUiPackageFiles', () => {
|
|
378
|
+
const fullstackOptions: TemplateOptions = {
|
|
379
|
+
...baseOptions,
|
|
380
|
+
template: 'fullstack',
|
|
381
|
+
monorepo: true,
|
|
382
|
+
apiPath: 'apps/api',
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
it('should return empty array for non-monorepo', () => {
|
|
386
|
+
const files = generateUiPackageFiles(baseOptions);
|
|
387
|
+
expect(files).toHaveLength(0);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it('should return empty array for non-fullstack template', () => {
|
|
391
|
+
const options: TemplateOptions = {
|
|
392
|
+
...baseOptions,
|
|
393
|
+
template: 'minimal',
|
|
394
|
+
monorepo: true,
|
|
395
|
+
apiPath: 'apps/api',
|
|
396
|
+
};
|
|
397
|
+
const files = generateUiPackageFiles(options);
|
|
398
|
+
expect(files).toHaveLength(0);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it('should generate UI package files for fullstack template', () => {
|
|
402
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
403
|
+
const paths = files.map((f) => f.path);
|
|
404
|
+
expect(paths).toContain('packages/ui/package.json');
|
|
405
|
+
expect(paths).toContain('packages/ui/tsconfig.json');
|
|
406
|
+
expect(paths).toContain('packages/ui/components.json');
|
|
407
|
+
expect(paths).toContain('packages/ui/.storybook/main.ts');
|
|
408
|
+
expect(paths).toContain('packages/ui/.storybook/preview.ts');
|
|
409
|
+
expect(paths).toContain('packages/ui/src/styles/globals.css');
|
|
410
|
+
expect(paths).toContain('packages/ui/src/lib/utils.ts');
|
|
411
|
+
expect(paths).toContain('packages/ui/src/index.ts');
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
it('should use correct package name', () => {
|
|
415
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
416
|
+
const pkgJson = files.find((f) => f.path === 'packages/ui/package.json');
|
|
417
|
+
expect(pkgJson).toBeDefined();
|
|
418
|
+
const pkg = JSON.parse(pkgJson!.content);
|
|
419
|
+
expect(pkg.name).toBe('@test-project/ui');
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it('should have typescript source exports (not dist)', () => {
|
|
423
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
424
|
+
const pkgJson = files.find((f) => f.path === 'packages/ui/package.json');
|
|
425
|
+
expect(pkgJson).toBeDefined();
|
|
426
|
+
const pkg = JSON.parse(pkgJson!.content);
|
|
427
|
+
expect(pkg.exports['.']).toBe('./src/index.ts');
|
|
428
|
+
expect(pkg.exports['./components']).toBe('./src/components/index.ts');
|
|
429
|
+
expect(pkg.exports['./lib/utils']).toBe('./src/lib/utils.ts');
|
|
430
|
+
expect(pkg.exports['./styles']).toBe('./src/styles/globals.css');
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it('should not have build script (private packages are not built)', () => {
|
|
434
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
435
|
+
const pkgJson = files.find((f) => f.path === 'packages/ui/package.json');
|
|
436
|
+
expect(pkgJson).toBeDefined();
|
|
437
|
+
const pkg = JSON.parse(pkgJson!.content);
|
|
438
|
+
expect(pkg.scripts.build).toBeUndefined();
|
|
439
|
+
expect(pkg.scripts.storybook).toBeDefined();
|
|
440
|
+
expect(pkg.scripts['build:storybook']).toBeDefined();
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
it('should include Radix UI dependencies', () => {
|
|
444
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
445
|
+
const pkgJson = files.find((f) => f.path === 'packages/ui/package.json');
|
|
446
|
+
expect(pkgJson).toBeDefined();
|
|
447
|
+
const pkg = JSON.parse(pkgJson!.content);
|
|
448
|
+
expect(pkg.dependencies['@radix-ui/react-slot']).toBeDefined();
|
|
449
|
+
expect(pkg.dependencies['@radix-ui/react-dialog']).toBeDefined();
|
|
450
|
+
expect(pkg.dependencies['@radix-ui/react-label']).toBeDefined();
|
|
451
|
+
expect(pkg.dependencies['@radix-ui/react-separator']).toBeDefined();
|
|
452
|
+
expect(pkg.dependencies['@radix-ui/react-tabs']).toBeDefined();
|
|
453
|
+
expect(pkg.dependencies['@radix-ui/react-tooltip']).toBeDefined();
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it('should include Storybook dependencies', () => {
|
|
457
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
458
|
+
const pkgJson = files.find((f) => f.path === 'packages/ui/package.json');
|
|
459
|
+
expect(pkgJson).toBeDefined();
|
|
460
|
+
const pkg = JSON.parse(pkgJson!.content);
|
|
461
|
+
expect(pkg.devDependencies['@storybook/react']).toBeDefined();
|
|
462
|
+
expect(pkg.devDependencies['@storybook/react-vite']).toBeDefined();
|
|
463
|
+
expect(pkg.devDependencies['@storybook/addon-essentials']).toBeDefined();
|
|
464
|
+
expect(pkg.devDependencies.storybook).toBeDefined();
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it('should include Tailwind CSS dependencies', () => {
|
|
468
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
469
|
+
const pkgJson = files.find((f) => f.path === 'packages/ui/package.json');
|
|
470
|
+
expect(pkgJson).toBeDefined();
|
|
471
|
+
const pkg = JSON.parse(pkgJson!.content);
|
|
472
|
+
expect(pkg.devDependencies.tailwindcss).toBeDefined();
|
|
473
|
+
expect(pkg.devDependencies['@tailwindcss/vite']).toBeDefined();
|
|
474
|
+
expect(pkg.peerDependencies.tailwindcss).toBeDefined();
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
it('should extend root tsconfig with noEmit', () => {
|
|
478
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
479
|
+
const tsConfig = files.find((f) => f.path === 'packages/ui/tsconfig.json');
|
|
480
|
+
expect(tsConfig).toBeDefined();
|
|
481
|
+
const config = JSON.parse(tsConfig!.content);
|
|
482
|
+
expect(config.extends).toBe('../../tsconfig.json');
|
|
483
|
+
expect(config.compilerOptions.noEmit).toBe(true);
|
|
484
|
+
expect(config.compilerOptions.jsx).toBe('react-jsx');
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
it('should not include tsdown.config.ts', () => {
|
|
488
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
489
|
+
const paths = files.map((f) => f.path);
|
|
490
|
+
expect(paths).not.toContain('packages/ui/tsdown.config.ts');
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
it('should generate all component files in folder structure', () => {
|
|
494
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
495
|
+
const paths = files.map((f) => f.path);
|
|
496
|
+
|
|
497
|
+
// Button
|
|
498
|
+
expect(paths).toContain('packages/ui/src/components/ui/button/index.tsx');
|
|
499
|
+
expect(paths).toContain(
|
|
500
|
+
'packages/ui/src/components/ui/button/button.stories.tsx',
|
|
501
|
+
);
|
|
502
|
+
|
|
503
|
+
// Input
|
|
504
|
+
expect(paths).toContain('packages/ui/src/components/ui/input/index.tsx');
|
|
505
|
+
expect(paths).toContain(
|
|
506
|
+
'packages/ui/src/components/ui/input/input.stories.tsx',
|
|
507
|
+
);
|
|
508
|
+
|
|
509
|
+
// Card
|
|
510
|
+
expect(paths).toContain('packages/ui/src/components/ui/card/index.tsx');
|
|
511
|
+
expect(paths).toContain(
|
|
512
|
+
'packages/ui/src/components/ui/card/card.stories.tsx',
|
|
513
|
+
);
|
|
514
|
+
|
|
515
|
+
// Label
|
|
516
|
+
expect(paths).toContain('packages/ui/src/components/ui/label/index.tsx');
|
|
517
|
+
expect(paths).toContain(
|
|
518
|
+
'packages/ui/src/components/ui/label/label.stories.tsx',
|
|
519
|
+
);
|
|
520
|
+
|
|
521
|
+
// Badge
|
|
522
|
+
expect(paths).toContain('packages/ui/src/components/ui/badge/index.tsx');
|
|
523
|
+
expect(paths).toContain(
|
|
524
|
+
'packages/ui/src/components/ui/badge/badge.stories.tsx',
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
// Separator
|
|
528
|
+
expect(paths).toContain(
|
|
529
|
+
'packages/ui/src/components/ui/separator/index.tsx',
|
|
530
|
+
);
|
|
531
|
+
expect(paths).toContain(
|
|
532
|
+
'packages/ui/src/components/ui/separator/separator.stories.tsx',
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
// Tabs
|
|
536
|
+
expect(paths).toContain('packages/ui/src/components/ui/tabs/index.tsx');
|
|
537
|
+
expect(paths).toContain(
|
|
538
|
+
'packages/ui/src/components/ui/tabs/tabs.stories.tsx',
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
// Tooltip
|
|
542
|
+
expect(paths).toContain('packages/ui/src/components/ui/tooltip/index.tsx');
|
|
543
|
+
expect(paths).toContain(
|
|
544
|
+
'packages/ui/src/components/ui/tooltip/tooltip.stories.tsx',
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
// Dialog
|
|
548
|
+
expect(paths).toContain('packages/ui/src/components/ui/dialog/index.tsx');
|
|
549
|
+
expect(paths).toContain(
|
|
550
|
+
'packages/ui/src/components/ui/dialog/dialog.stories.tsx',
|
|
551
|
+
);
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
it('should export all components from index', () => {
|
|
555
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
556
|
+
const indexFile = files.find(
|
|
557
|
+
(f) => f.path === 'packages/ui/src/components/ui/index.ts',
|
|
558
|
+
);
|
|
559
|
+
expect(indexFile).toBeDefined();
|
|
560
|
+
expect(indexFile!.content).toContain("from './button'");
|
|
561
|
+
expect(indexFile!.content).toContain("from './input'");
|
|
562
|
+
expect(indexFile!.content).toContain("from './card'");
|
|
563
|
+
expect(indexFile!.content).toContain("from './label'");
|
|
564
|
+
expect(indexFile!.content).toContain("from './badge'");
|
|
565
|
+
expect(indexFile!.content).toContain("from './separator'");
|
|
566
|
+
expect(indexFile!.content).toContain("from './tabs'");
|
|
567
|
+
expect(indexFile!.content).toContain("from './tooltip'");
|
|
568
|
+
expect(indexFile!.content).toContain("from './dialog'");
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
it('should include cn utility function', () => {
|
|
572
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
573
|
+
const utilsFile = files.find(
|
|
574
|
+
(f) => f.path === 'packages/ui/src/lib/utils.ts',
|
|
575
|
+
);
|
|
576
|
+
expect(utilsFile).toBeDefined();
|
|
577
|
+
expect(utilsFile!.content).toContain('export function cn');
|
|
578
|
+
expect(utilsFile!.content).toContain('clsx');
|
|
579
|
+
expect(utilsFile!.content).toContain('twMerge');
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
it('should include Tailwind v4 CSS with theme variables', () => {
|
|
583
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
584
|
+
const globalsCss = files.find(
|
|
585
|
+
(f) => f.path === 'packages/ui/src/styles/globals.css',
|
|
586
|
+
);
|
|
587
|
+
expect(globalsCss).toBeDefined();
|
|
588
|
+
expect(globalsCss!.content).toContain('@import "tailwindcss"');
|
|
589
|
+
expect(globalsCss!.content).toContain('@theme');
|
|
590
|
+
expect(globalsCss!.content).toContain('--color-background');
|
|
591
|
+
expect(globalsCss!.content).toContain('--color-primary');
|
|
592
|
+
expect(globalsCss!.content).toContain('.dark');
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
it('should configure Storybook with Tailwind v4 plugin', () => {
|
|
596
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
597
|
+
const storybookMain = files.find(
|
|
598
|
+
(f) => f.path === 'packages/ui/.storybook/main.ts',
|
|
599
|
+
);
|
|
600
|
+
expect(storybookMain).toBeDefined();
|
|
601
|
+
expect(storybookMain!.content).toContain('@storybook/react-vite');
|
|
602
|
+
expect(storybookMain!.content).toContain('@tailwindcss/vite');
|
|
603
|
+
expect(storybookMain!.content).toContain('viteFinal');
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
it('should import globals.css in Storybook preview', () => {
|
|
607
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
608
|
+
const storybookPreview = files.find(
|
|
609
|
+
(f) => f.path === 'packages/ui/.storybook/preview.ts',
|
|
610
|
+
);
|
|
611
|
+
expect(storybookPreview).toBeDefined();
|
|
612
|
+
expect(storybookPreview!.content).toContain(
|
|
613
|
+
"import '../src/styles/globals.css'",
|
|
614
|
+
);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
it('should include shadcn components.json config', () => {
|
|
618
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
619
|
+
const componentsJson = files.find(
|
|
620
|
+
(f) => f.path === 'packages/ui/components.json',
|
|
621
|
+
);
|
|
622
|
+
expect(componentsJson).toBeDefined();
|
|
623
|
+
const config = JSON.parse(componentsJson!.content);
|
|
624
|
+
expect(config.$schema).toContain('ui.shadcn.com');
|
|
625
|
+
expect(config.style).toBe('new-york');
|
|
626
|
+
expect(config.tailwind.cssVariables).toBe(true);
|
|
627
|
+
expect(config.aliases.components).toBe('~/components');
|
|
628
|
+
expect(config.aliases.utils).toBe('~/lib/utils');
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
it('should use ~/* path alias in components', () => {
|
|
632
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
633
|
+
const buttonFile = files.find(
|
|
634
|
+
(f) => f.path === 'packages/ui/src/components/ui/button/index.tsx',
|
|
635
|
+
);
|
|
636
|
+
expect(buttonFile).toBeDefined();
|
|
637
|
+
expect(buttonFile!.content).toContain("from '~/lib/utils'");
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
it('should configure ~/* path in tsconfig', () => {
|
|
641
|
+
const files = generateUiPackageFiles(fullstackOptions);
|
|
642
|
+
const tsConfig = files.find((f) => f.path === 'packages/ui/tsconfig.json');
|
|
643
|
+
expect(tsConfig).toBeDefined();
|
|
644
|
+
const config = JSON.parse(tsConfig!.content);
|
|
645
|
+
expect(config.compilerOptions.paths['~/*']).toEqual(['./src/*']);
|
|
646
|
+
});
|
|
647
|
+
});
|
|
@@ -176,9 +176,9 @@ describe('initCommand', () => {
|
|
|
176
176
|
expect(
|
|
177
177
|
existsSync(join(projectDir, 'packages/models/tsconfig.json')),
|
|
178
178
|
).toBe(true);
|
|
179
|
-
expect(
|
|
180
|
-
|
|
181
|
-
);
|
|
179
|
+
expect(
|
|
180
|
+
existsSync(join(projectDir, 'packages/models/src/common.ts')),
|
|
181
|
+
).toBe(true);
|
|
182
182
|
expect(existsSync(join(projectDir, 'packages/models/src/user.ts'))).toBe(
|
|
183
183
|
true,
|
|
184
184
|
);
|
|
@@ -93,6 +93,7 @@ export default defineConfig({
|
|
|
93
93
|
noEmit: true,
|
|
94
94
|
baseUrl: '.',
|
|
95
95
|
paths: {
|
|
96
|
+
'~/*': ['./src/*'],
|
|
96
97
|
[`@${options.name}/*`]: ['../../packages/*/src'],
|
|
97
98
|
},
|
|
98
99
|
},
|
|
@@ -256,6 +257,7 @@ function generateSingleAppConfigFiles(
|
|
|
256
257
|
noEmit: true,
|
|
257
258
|
baseUrl: '.',
|
|
258
259
|
paths: {
|
|
260
|
+
'~/*': ['./src/*'],
|
|
259
261
|
[`@${options.name}/*`]: ['../../packages/*/src'],
|
|
260
262
|
},
|
|
261
263
|
},
|
|
@@ -51,7 +51,11 @@ export function generateModelsPackage(
|
|
|
51
51
|
// Common Schemas
|
|
52
52
|
// ============================================
|
|
53
53
|
|
|
54
|
-
export const IdSchema = z.
|
|
54
|
+
export const IdSchema = z.uuid();
|
|
55
|
+
|
|
56
|
+
export const IdParamsSchema = z.object({
|
|
57
|
+
id: IdSchema,
|
|
58
|
+
});
|
|
55
59
|
|
|
56
60
|
export const TimestampsSchema = z.object({
|
|
57
61
|
createdAt: z.coerce.date(),
|
|
@@ -77,6 +81,7 @@ export const PaginatedResponseSchema = <T extends z.ZodTypeAny>(itemSchema: T) =
|
|
|
77
81
|
// ============================================
|
|
78
82
|
|
|
79
83
|
export type Id = z.infer<typeof IdSchema>;
|
|
84
|
+
export type IdParams = z.infer<typeof IdParamsSchema>;
|
|
80
85
|
export type Timestamps = z.infer<typeof TimestampsSchema>;
|
|
81
86
|
export type Pagination = z.infer<typeof PaginationSchema>;
|
|
82
87
|
`;
|
|
@@ -34,6 +34,9 @@ export function generateMonorepoFiles(
|
|
|
34
34
|
lint: 'biome lint .',
|
|
35
35
|
fmt: 'biome format . --write',
|
|
36
36
|
'fmt:check': 'biome format .',
|
|
37
|
+
...(isFullstack
|
|
38
|
+
? { storybook: 'pnpm --filter ./packages/ui storybook' }
|
|
39
|
+
: {}),
|
|
37
40
|
...(options.deployTarget === 'dokploy'
|
|
38
41
|
? { deploy: 'gkm deploy --provider dokploy --stage production' }
|
|
39
42
|
: {}),
|