@geekmidas/cli 1.10.36 → 1.10.37

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 (82) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/{config-U-gojtxn.mjs → config-Bbu1JKvf.mjs} +2 -2
  3. package/dist/{config-U-gojtxn.mjs.map → config-Bbu1JKvf.mjs.map} +1 -1
  4. package/dist/{config-QnuOcYXp.cjs → config-DujV8DbR.cjs} +2 -2
  5. package/dist/{config-QnuOcYXp.cjs.map → config-DujV8DbR.cjs.map} +1 -1
  6. package/dist/config.cjs +2 -2
  7. package/dist/config.d.cts +1 -1
  8. package/dist/config.d.mts +1 -1
  9. package/dist/config.mjs +2 -2
  10. package/dist/{fullstack-secrets-Bchl2MDd.cjs → fullstack-secrets-BYzi6Hwl.cjs} +3 -2
  11. package/dist/{fullstack-secrets-Bchl2MDd.cjs.map → fullstack-secrets-BYzi6Hwl.cjs.map} +1 -1
  12. package/dist/{fullstack-secrets-P84v8zWn.mjs → fullstack-secrets-l8s3II_H.mjs} +3 -2
  13. package/dist/{fullstack-secrets-P84v8zWn.mjs.map → fullstack-secrets-l8s3II_H.mjs.map} +1 -1
  14. package/dist/{index-D7iT4dnv.d.mts → index-BBvGMG_A.d.mts} +124 -67
  15. package/dist/index-BBvGMG_A.d.mts.map +1 -0
  16. package/dist/{index-DRQq26DF.d.cts → index-Dz2a7xQU.d.cts} +124 -67
  17. package/dist/index-Dz2a7xQU.d.cts.map +1 -0
  18. package/dist/index.cjs +244 -91
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.mjs +244 -91
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/{openapi-Bb4UEyZN.cjs → openapi-0JUzU5Tv.cjs} +9 -2
  23. package/dist/{openapi-Bb4UEyZN.cjs.map → openapi-0JUzU5Tv.cjs.map} +1 -1
  24. package/dist/{openapi-BA0e3I_s.mjs → openapi-C5AycKTR.mjs} +10 -3
  25. package/dist/{openapi-BA0e3I_s.mjs.map → openapi-C5AycKTR.mjs.map} +1 -1
  26. package/dist/openapi.cjs +3 -3
  27. package/dist/openapi.mjs +3 -3
  28. package/dist/{reconcile-DAAKa0YR.mjs → reconcile-CYGmqXvq.mjs} +2 -2
  29. package/dist/{reconcile-DAAKa0YR.mjs.map → reconcile-CYGmqXvq.mjs.map} +1 -1
  30. package/dist/{reconcile-CZtzdrnc.cjs → reconcile-D93YG7G5.cjs} +2 -2
  31. package/dist/{reconcile-CZtzdrnc.cjs.map → reconcile-D93YG7G5.cjs.map} +1 -1
  32. package/dist/workspace/index.cjs +1 -1
  33. package/dist/workspace/index.d.cts +1 -1
  34. package/dist/workspace/index.d.mts +1 -1
  35. package/dist/workspace/index.mjs +1 -1
  36. package/dist/{workspace-BobDOIG9.cjs → workspace-CQTT7HJQ.cjs} +34 -25
  37. package/dist/workspace-CQTT7HJQ.cjs.map +1 -0
  38. package/dist/{workspace-Cgmvgwh8.mjs → workspace-D-37Ylqo.mjs} +34 -25
  39. package/dist/workspace-D-37Ylqo.mjs.map +1 -0
  40. package/docs/dev-server-resilience-design.md +189 -0
  41. package/package.json +5 -5
  42. package/src/build/__tests__/workspace-build.spec.ts +7 -7
  43. package/src/build/index.ts +25 -9
  44. package/src/credentials/__tests__/helpers.ts +1 -1
  45. package/src/credentials/__tests__/workspaceCredentials.spec.ts +1 -1
  46. package/src/deploy/__tests__/domain.spec.ts +12 -12
  47. package/src/deploy/__tests__/env-resolver.spec.ts +1 -1
  48. package/src/deploy/__tests__/index.spec.ts +14 -14
  49. package/src/deploy/__tests__/sniffer.spec.ts +9 -9
  50. package/src/deploy/domain.ts +19 -11
  51. package/src/deploy/index.ts +12 -1
  52. package/src/deploy/sniffer.ts +1 -1
  53. package/src/deploy/types.ts +1 -1
  54. package/src/dev/__tests__/index.spec.ts +11 -11
  55. package/src/dev/index.ts +14 -8
  56. package/src/docker/__tests__/compose.spec.ts +4 -4
  57. package/src/docker/compose.ts +5 -3
  58. package/src/docker/index.ts +34 -6
  59. package/src/docker/templates.ts +138 -0
  60. package/src/generators/OpenApiTsGenerator.ts +22 -0
  61. package/src/generators/__tests__/OpenApiTsGenerator.registry.spec.ts +77 -0
  62. package/src/init/__tests__/init.spec.ts +1 -1
  63. package/src/init/generators/monorepo.ts +3 -3
  64. package/src/secrets/__tests__/reconcile.spec.ts +1 -1
  65. package/src/setup/__tests__/reconcile-secrets.spec.ts +2 -2
  66. package/src/setup/fullstack-secrets.ts +7 -1
  67. package/src/setup/index.ts +2 -1
  68. package/src/test/__tests__/__fixtures__/workspace.ts +1 -1
  69. package/src/test/__tests__/web.spec.ts +2 -2
  70. package/src/workspace/__tests__/client-generator.spec.ts +6 -6
  71. package/src/workspace/__tests__/index.spec.ts +4 -4
  72. package/src/workspace/__tests__/schema.spec.ts +27 -30
  73. package/src/workspace/__tests__/type-inference.spec.ts +5 -5
  74. package/src/workspace/client-generator.ts +10 -7
  75. package/src/workspace/index.ts +1 -1
  76. package/src/workspace/publicEnv.ts +2 -4
  77. package/src/workspace/schema.ts +126 -27
  78. package/src/workspace/types.ts +40 -69
  79. package/dist/index-D7iT4dnv.d.mts.map +0 -1
  80. package/dist/index-DRQq26DF.d.cts.map +0 -1
  81. package/dist/workspace-BobDOIG9.cjs.map +0 -1
  82. package/dist/workspace-Cgmvgwh8.mjs.map +0 -1
@@ -322,7 +322,7 @@ function generateFrontendAppEntry(options: TemplateOptions): string {
322
322
  switch (options.frontendFramework) {
323
323
  case 'tanstack-start':
324
324
  return `web: {
325
- type: 'frontend',
325
+ type: 'web',
326
326
  framework: 'tanstack-start',
327
327
  path: 'apps/web',
328
328
  port: 3001,
@@ -334,7 +334,7 @@ function generateFrontendAppEntry(options: TemplateOptions): string {
334
334
  },`;
335
335
  case 'expo':
336
336
  return `app: {
337
- type: 'frontend',
337
+ type: 'mobile',
338
338
  framework: 'expo',
339
339
  path: 'apps/app',
340
340
  port: 8081,
@@ -342,7 +342,7 @@ function generateFrontendAppEntry(options: TemplateOptions): string {
342
342
  },`;
343
343
  default:
344
344
  return `web: {
345
- type: 'frontend',
345
+ type: 'web',
346
346
  framework: 'nextjs',
347
347
  path: 'apps/web',
348
348
  port: 3001,
@@ -19,7 +19,7 @@ function createMultiAppWorkspace(
19
19
  resolvedDeployTarget: 'dokploy',
20
20
  },
21
21
  web: {
22
- type: 'frontend',
22
+ type: 'web',
23
23
  path: 'apps/web',
24
24
  port: 3001,
25
25
  dependencies: ['api'],
@@ -29,7 +29,7 @@ function createWorkspace(
29
29
  dependencies: [],
30
30
  },
31
31
  web: {
32
- type: 'frontend',
32
+ type: 'web',
33
33
  port: 3002,
34
34
  root: '/tmp/test-project/apps/web',
35
35
  packageName: '@test/web',
@@ -333,7 +333,7 @@ describe('generateFullstackCustomSecrets', () => {
333
333
  dependencies: [],
334
334
  },
335
335
  web: {
336
- type: 'frontend',
336
+ type: 'web',
337
337
  port: 3001,
338
338
  root: '/tmp/test-project/apps/web',
339
339
  path: 'apps/web',
@@ -55,13 +55,19 @@ export function generateFullstackCustomSecrets(
55
55
  const frontendPorts: number[] = [];
56
56
 
57
57
  for (const [appName, appConfig] of Object.entries(workspace.apps)) {
58
- if (appConfig.type === 'frontend') {
58
+ if (appConfig.type === 'web') {
59
59
  frontendPorts.push(appConfig.port);
60
60
  const upperName = appName.toUpperCase();
61
61
  customs[`${upperName}_URL`] = `http://localhost:${appConfig.port}`;
62
62
  continue;
63
63
  }
64
64
 
65
+ // Mobile apps (Expo, etc.) don't run on a host port the backend
66
+ // cares about for CORS, and don't need DB credentials.
67
+ if (appConfig.type === 'mobile') {
68
+ continue;
69
+ }
70
+
65
71
  // Backend apps with database: generate per-app DB passwords and URLs
66
72
  const password = generateDbPassword();
67
73
  const upperName = appName.toUpperCase();
@@ -359,7 +359,8 @@ function printSummary(workspace: NormalizedWorkspace, stage: string): void {
359
359
 
360
360
  logger.log('📋 Apps:');
361
361
  for (const [name, app] of Object.entries(workspace.apps)) {
362
- const icon = app.type === 'frontend' ? '🌐' : '🔧';
362
+ const icon =
363
+ app.type === 'web' ? '🌐' : app.type === 'mobile' ? '📱' : '🔧';
363
364
  logger.log(` ${icon} ${name} → http://localhost:${app.port}`);
364
365
  }
365
366
 
@@ -57,7 +57,7 @@ export function createFullstackWorkspace(): ReturnType<
57
57
  dependencies: [],
58
58
  },
59
59
  web: {
60
- type: 'frontend',
60
+ type: 'web',
61
61
  path: 'apps/web',
62
62
  port: 3001,
63
63
  framework: 'nextjs',
@@ -104,7 +104,7 @@ describe('web (frontend) app context', () => {
104
104
  dependencies: [],
105
105
  },
106
106
  web: {
107
- type: 'frontend',
107
+ type: 'web',
108
108
  path: 'apps/web',
109
109
  port: 3001,
110
110
  framework: 'nextjs',
@@ -149,7 +149,7 @@ describe('web (frontend) app context', () => {
149
149
  dependencies: [],
150
150
  },
151
151
  web: {
152
- type: 'frontend',
152
+ type: 'web',
153
153
  path: 'apps/web',
154
154
  port: 3001,
155
155
  framework: 'nextjs',
@@ -108,7 +108,7 @@ describe('Client Generator', () => {
108
108
  resolvedDeployTarget: 'dokploy',
109
109
  },
110
110
  web: {
111
- type: 'frontend',
111
+ type: 'web',
112
112
  path: 'apps/web',
113
113
  port: 3002,
114
114
  dependencies: ['api', 'auth'],
@@ -147,7 +147,7 @@ describe('Client Generator', () => {
147
147
  // No routes - not an HTTP backend
148
148
  },
149
149
  web: {
150
- type: 'frontend',
150
+ type: 'web',
151
151
  path: 'apps/web',
152
152
  port: 3002,
153
153
  dependencies: ['api', 'worker'],
@@ -204,21 +204,21 @@ describe('Client Generator', () => {
204
204
  resolvedDeployTarget: 'dokploy',
205
205
  },
206
206
  web: {
207
- type: 'frontend',
207
+ type: 'web',
208
208
  path: 'apps/web',
209
209
  port: 3001,
210
210
  dependencies: ['api'],
211
211
  resolvedDeployTarget: 'dokploy',
212
212
  },
213
213
  admin: {
214
- type: 'frontend',
214
+ type: 'web',
215
215
  path: 'apps/admin',
216
216
  port: 3002,
217
217
  dependencies: ['api'],
218
218
  resolvedDeployTarget: 'dokploy',
219
219
  },
220
220
  docs: {
221
- type: 'frontend',
221
+ type: 'web',
222
222
  path: 'apps/docs',
223
223
  port: 3003,
224
224
  dependencies: [], // No API dependency
@@ -291,7 +291,7 @@ describe('Client Generator', () => {
291
291
  root: '/project',
292
292
  apps: {
293
293
  web: {
294
- type: 'frontend',
294
+ type: 'web',
295
295
  path: 'apps/web',
296
296
  port: 3000,
297
297
  dependencies: [],
@@ -406,7 +406,7 @@ describe('getAppGkmConfig', () => {
406
406
  const config: WorkspaceConfig = {
407
407
  apps: {
408
408
  web: {
409
- type: 'frontend',
409
+ type: 'web',
410
410
  path: 'apps/web',
411
411
  port: 3001,
412
412
  framework: 'nextjs',
@@ -444,7 +444,7 @@ describe('getAppBuildOrder', () => {
444
444
  const config: WorkspaceConfig = {
445
445
  apps: {
446
446
  web: {
447
- type: 'frontend',
447
+ type: 'web',
448
448
  path: 'apps/web',
449
449
  port: 3001,
450
450
  framework: 'nextjs',
@@ -509,7 +509,7 @@ describe('getDependencyEnvVars', () => {
509
509
  const config: WorkspaceConfig = {
510
510
  apps: {
511
511
  web: {
512
- type: 'frontend',
512
+ type: 'web',
513
513
  path: 'apps/web',
514
514
  port: 3001,
515
515
  framework: 'nextjs',
@@ -545,7 +545,7 @@ describe('getDependencyEnvVars', () => {
545
545
  const config: WorkspaceConfig = {
546
546
  apps: {
547
547
  web: {
548
- type: 'frontend',
548
+ type: 'web',
549
549
  path: 'apps/web',
550
550
  port: 3001,
551
551
  framework: 'nextjs',
@@ -47,7 +47,7 @@ describe('WorkspaceConfigSchema', () => {
47
47
  openapi: { enabled: true, title: 'My API' },
48
48
  },
49
49
  web: {
50
- type: 'frontend' as const,
50
+ type: 'web' as const,
51
51
  path: 'apps/web',
52
52
  port: 3001,
53
53
  framework: 'nextjs' as const,
@@ -82,7 +82,7 @@ describe('WorkspaceConfigSchema', () => {
82
82
 
83
83
  expect(result.name).toBe('my-saas');
84
84
  expect(result.apps.api.type).toBe('backend');
85
- expect(result.apps.web.type).toBe('frontend');
85
+ expect(result.apps.web.type).toBe('web');
86
86
  expect(result.apps.web.dependencies).toEqual(['api']);
87
87
  expect(result.shared?.packages).toEqual(['packages/*']);
88
88
  expect(result.deploy?.default).toBe('dokploy');
@@ -163,7 +163,7 @@ describe('WorkspaceConfigSchema', () => {
163
163
  const config = {
164
164
  apps: {
165
165
  web: {
166
- type: 'frontend' as const,
166
+ type: 'web' as const,
167
167
  path: 'apps/web',
168
168
  port: 3001,
169
169
  // Missing framework
@@ -197,7 +197,7 @@ describe('WorkspaceConfigSchema', () => {
197
197
  const config = {
198
198
  apps: {
199
199
  web: {
200
- type: 'frontend' as const,
200
+ type: 'web' as const,
201
201
  path: 'apps/web',
202
202
  port: 3001,
203
203
  framework: 'nextjs' as const,
@@ -479,53 +479,50 @@ describe('WorkspaceConfigSchema', () => {
479
479
  });
480
480
 
481
481
  describe('auth app configuration', () => {
482
- it('should accept auth app with provider', () => {
482
+ it('should accept auth app as backend with better-auth framework', () => {
483
483
  const config = {
484
484
  apps: {
485
485
  auth: {
486
- type: 'auth' as const,
486
+ type: 'backend' as const,
487
487
  path: 'apps/auth',
488
488
  port: 3002,
489
- provider: 'better-auth' as const,
489
+ framework: 'better-auth' as const,
490
490
  },
491
491
  },
492
492
  };
493
493
 
494
494
  const result = validateWorkspaceConfig(config);
495
495
 
496
- expect(result.apps.auth.type).toBe('auth');
497
- expect(result.apps.auth.provider).toBe('better-auth');
496
+ expect(result.apps.auth.type).toBe('backend');
497
+ expect(result.apps.auth.framework).toBe('better-auth');
498
498
  });
499
499
 
500
- it('should reject auth app without provider', () => {
500
+ it('should accept auth backend without explicit framework', () => {
501
+ // Backend type defaults are permissive — framework is optional.
501
502
  const config = {
502
503
  apps: {
503
504
  auth: {
504
- type: 'auth' as const,
505
+ type: 'backend' as const,
505
506
  path: 'apps/auth',
506
507
  port: 3002,
507
- // Missing provider
508
508
  },
509
509
  },
510
510
  };
511
511
 
512
- const result = safeValidateWorkspaceConfig(config);
512
+ const result = validateWorkspaceConfig(config);
513
513
 
514
- expect(result.success).toBe(false);
515
- if (result.error) {
516
- const formatted = formatValidationErrors(result.error);
517
- expect(formatted).toContain('Auth apps must have provider defined');
518
- }
514
+ expect(result.apps.auth.type).toBe('backend');
515
+ expect(result.apps.auth.framework).toBeUndefined();
519
516
  });
520
517
 
521
- it('should allow auth app with backend properties', () => {
518
+ it('should allow auth backend with additional backend properties', () => {
522
519
  const config = {
523
520
  apps: {
524
521
  auth: {
525
- type: 'auth' as const,
522
+ type: 'backend' as const,
526
523
  path: 'apps/auth',
527
524
  port: 3002,
528
- provider: 'better-auth' as const,
525
+ framework: 'better-auth' as const,
529
526
  envParser: './src/config/env',
530
527
  logger: './src/logger',
531
528
  telescope: true,
@@ -535,12 +532,12 @@ describe('WorkspaceConfigSchema', () => {
535
532
 
536
533
  const result = validateWorkspaceConfig(config);
537
534
 
538
- expect(result.apps.auth.type).toBe('auth');
535
+ expect(result.apps.auth.framework).toBe('better-auth');
539
536
  expect(result.apps.auth.envParser).toBe('./src/config/env');
540
537
  expect(result.apps.auth.telescope).toBe(true);
541
538
  });
542
539
 
543
- it('should validate fullstack workspace with auth app', () => {
540
+ it('should validate fullstack workspace with auth backend', () => {
544
541
  const config = {
545
542
  name: 'fullstack-app',
546
543
  apps: {
@@ -552,13 +549,13 @@ describe('WorkspaceConfigSchema', () => {
552
549
  dependencies: ['auth'],
553
550
  },
554
551
  auth: {
555
- type: 'auth' as const,
552
+ type: 'backend' as const,
556
553
  path: 'apps/auth',
557
554
  port: 3002,
558
- provider: 'better-auth' as const,
555
+ framework: 'better-auth' as const,
559
556
  },
560
557
  web: {
561
- type: 'frontend' as const,
558
+ type: 'web' as const,
562
559
  path: 'apps/web',
563
560
  port: 3001,
564
561
  framework: 'nextjs' as const,
@@ -570,18 +567,18 @@ describe('WorkspaceConfigSchema', () => {
570
567
  const result = validateWorkspaceConfig(config);
571
568
 
572
569
  expect(result.apps.api.dependencies).toEqual(['auth']);
573
- expect(result.apps.auth.type).toBe('auth');
570
+ expect(result.apps.auth.framework).toBe('better-auth');
574
571
  expect(result.apps.web.dependencies).toEqual(['api', 'auth']);
575
572
  });
576
573
 
577
- it('should reject invalid auth provider', () => {
574
+ it('should reject auth backend with invalid framework value', () => {
578
575
  const config = {
579
576
  apps: {
580
577
  auth: {
581
- type: 'auth' as const,
578
+ type: 'backend' as const,
582
579
  path: 'apps/auth',
583
580
  port: 3002,
584
- provider: 'invalid-provider',
581
+ framework: 'invalid-framework',
585
582
  },
586
583
  },
587
584
  };
@@ -14,7 +14,7 @@ describe('Type Inference', () => {
14
14
  routes: './src/**/*.ts',
15
15
  },
16
16
  web: {
17
- type: 'frontend',
17
+ type: 'web',
18
18
  path: 'apps/web',
19
19
  port: 3001,
20
20
  framework: 'nextjs',
@@ -46,7 +46,7 @@ describe('Type Inference', () => {
46
46
  routes: './src/**/*.ts',
47
47
  },
48
48
  web: {
49
- type: 'frontend',
49
+ type: 'web',
50
50
  path: 'apps/web',
51
51
  port: 3002,
52
52
  framework: 'nextjs',
@@ -69,7 +69,7 @@ describe('Type Inference', () => {
69
69
  routes: './src/**/*.ts',
70
70
  },
71
71
  web: {
72
- type: 'frontend',
72
+ type: 'web',
73
73
  path: 'apps/web',
74
74
  port: 3001,
75
75
  framework: 'nextjs',
@@ -186,14 +186,14 @@ describe('Type Inference', () => {
186
186
  dependencies: ['user-service'],
187
187
  },
188
188
  'web-app': {
189
- type: 'frontend',
189
+ type: 'web',
190
190
  path: 'apps/web',
191
191
  port: 3003,
192
192
  framework: 'nextjs',
193
193
  dependencies: ['api-gateway'],
194
194
  },
195
195
  'admin-dashboard': {
196
- type: 'frontend',
196
+ type: 'web',
197
197
  path: 'apps/admin',
198
198
  port: 3004,
199
199
  framework: 'nextjs',
@@ -55,25 +55,25 @@ export function shouldRegenerateClient(
55
55
  }
56
56
 
57
57
  /**
58
- * Get backend apps that a frontend depends on.
58
+ * Get backend apps that a web/mobile client depends on.
59
59
  */
60
60
  export function getBackendDependencies(
61
61
  workspace: NormalizedWorkspace,
62
- frontendAppName: string,
62
+ clientAppName: string,
63
63
  ): string[] {
64
- const frontendApp = workspace.apps[frontendAppName];
65
- if (!frontendApp || frontendApp.type !== 'frontend') {
64
+ const clientApp = workspace.apps[clientAppName];
65
+ if (!clientApp || (clientApp.type !== 'web' && clientApp.type !== 'mobile')) {
66
66
  return [];
67
67
  }
68
68
 
69
- return frontendApp.dependencies.filter((dep) => {
69
+ return clientApp.dependencies.filter((dep) => {
70
70
  const depApp = workspace.apps[dep];
71
71
  return depApp?.type === 'backend' && depApp.routes;
72
72
  });
73
73
  }
74
74
 
75
75
  /**
76
- * Get frontend apps that depend on a backend app.
76
+ * Get web/mobile apps that depend on a backend app.
77
77
  */
78
78
  export function getDependentFrontends(
79
79
  workspace: NormalizedWorkspace,
@@ -82,7 +82,10 @@ export function getDependentFrontends(
82
82
  const dependentApps: string[] = [];
83
83
 
84
84
  for (const [appName, app] of Object.entries(workspace.apps)) {
85
- if (app.type === 'frontend' && app.dependencies.includes(backendAppName)) {
85
+ if (
86
+ (app.type === 'web' || app.type === 'mobile') &&
87
+ app.dependencies.includes(backendAppName)
88
+ ) {
86
89
  dependentApps.push(appName);
87
90
  }
88
91
  }
@@ -111,7 +111,7 @@ function validateDependencies<TApps extends AppsRecord>(apps: TApps): void {
111
111
  * logger: './src/logger',
112
112
  * },
113
113
  * web: {
114
- * type: 'frontend',
114
+ * type: 'web',
115
115
  * framework: 'nextjs',
116
116
  * path: 'apps/web',
117
117
  * port: 3001,
@@ -1,4 +1,4 @@
1
- import type { BackendFramework, FrontendFramework } from './types.js';
1
+ import type { Framework } from './types.js';
2
2
 
3
3
  /**
4
4
  * All public env-var prefixes the toolbox understands.
@@ -27,9 +27,7 @@ export const PUBLIC_ENV_PREFIXES = [
27
27
  * preserve the historical default. Backend apps never read these vars
28
28
  * from a bundle, so the prefix only affects scaffolding/symmetry.
29
29
  */
30
- export function getPublicEnvPrefix(
31
- framework?: FrontendFramework | BackendFramework,
32
- ): string {
30
+ export function getPublicEnvPrefix(framework?: Framework): string {
33
31
  switch (framework) {
34
32
  case 'vite':
35
33
  case 'tanstack-start':