@c15t/cli 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/README.md +97 -74
  2. package/dist/commands/generate/index.d.ts +6 -0
  3. package/dist/commands/generate/index.d.ts.map +1 -0
  4. package/dist/{onboarding/storage-modes → commands/generate/options}/c15t-mode.d.ts +5 -10
  5. package/dist/commands/generate/options/c15t-mode.d.ts.map +1 -0
  6. package/dist/{onboarding/storage-modes → commands/generate/options}/custom-mode.d.ts +5 -7
  7. package/dist/commands/generate/options/custom-mode.d.ts.map +1 -0
  8. package/dist/{onboarding/storage-modes → commands/generate/options}/offline-mode.d.ts +5 -7
  9. package/dist/commands/generate/options/offline-mode.d.ts.map +1 -0
  10. package/dist/commands/generate/options/self-hosted-mode.d.ts +19 -0
  11. package/dist/commands/generate/options/self-hosted-mode.d.ts.map +1 -0
  12. package/dist/commands/generate/options/types.d.ts +12 -0
  13. package/dist/commands/generate/options/types.d.ts.map +1 -0
  14. package/dist/{onboarding → commands/generate/options/utils}/dependencies.d.ts +12 -0
  15. package/dist/commands/generate/options/utils/dependencies.d.ts.map +1 -0
  16. package/dist/{onboarding → commands/generate/options/utils}/generate-files.d.ts +4 -8
  17. package/dist/commands/generate/options/utils/generate-files.d.ts.map +1 -0
  18. package/dist/commands/generate/options/utils/shared-frontend.d.ts +13 -0
  19. package/dist/commands/generate/options/utils/shared-frontend.d.ts.map +1 -0
  20. package/dist/commands/generate/templates/backend.d.ts.map +1 -0
  21. package/dist/{onboarding → commands/generate}/templates/config.d.ts +1 -1
  22. package/dist/commands/generate/templates/config.d.ts.map +1 -0
  23. package/dist/{onboarding → commands/generate}/templates/env.d.ts +1 -1
  24. package/dist/commands/generate/templates/env.d.ts.map +1 -0
  25. package/dist/{onboarding → commands/generate}/templates/index.d.ts +1 -1
  26. package/dist/commands/generate/templates/index.d.ts.map +1 -0
  27. package/dist/{onboarding → commands/generate}/templates/layout.d.ts +1 -1
  28. package/dist/commands/generate/templates/layout.d.ts.map +1 -0
  29. package/dist/{onboarding → commands/generate}/templates/next/app/layout.d.ts +1 -1
  30. package/dist/commands/generate/templates/next/app/layout.d.ts.map +1 -0
  31. package/dist/{onboarding → commands/generate}/templates/next/index.d.ts +1 -1
  32. package/dist/commands/generate/templates/next/index.d.ts.map +1 -0
  33. package/dist/{onboarding → commands/generate}/templates/next/pages/layout.d.ts +1 -1
  34. package/dist/commands/generate/templates/next/pages/layout.d.ts.map +1 -0
  35. package/dist/commands/generate/templates/next-config.d.ts.map +1 -0
  36. package/dist/commands/generate/templates/shared/options.d.ts.map +1 -0
  37. package/dist/commands/self-host/index.d.ts +6 -0
  38. package/dist/commands/self-host/index.d.ts.map +1 -0
  39. package/dist/commands/self-host/migrate/ensure-backend-config.d.ts +7 -0
  40. package/dist/commands/self-host/migrate/ensure-backend-config.d.ts.map +1 -0
  41. package/dist/commands/self-host/migrate/ensure-backend-config.test.d.ts +2 -0
  42. package/dist/commands/self-host/migrate/ensure-backend-config.test.d.ts.map +1 -0
  43. package/dist/commands/self-host/migrate/index.d.ts +3 -0
  44. package/dist/commands/self-host/migrate/index.d.ts.map +1 -0
  45. package/dist/commands/self-host/migrate/index.test.d.ts +2 -0
  46. package/dist/commands/self-host/migrate/index.test.d.ts.map +1 -0
  47. package/dist/commands/self-host/migrate/migrator-result.d.ts +4 -0
  48. package/dist/commands/self-host/migrate/migrator-result.d.ts.map +1 -0
  49. package/dist/commands/self-host/migrate/migrator-result.test.d.ts +2 -0
  50. package/dist/commands/self-host/migrate/migrator-result.test.d.ts.map +1 -0
  51. package/dist/commands/self-host/migrate/orm-result.d.ts +4 -0
  52. package/dist/commands/self-host/migrate/orm-result.d.ts.map +1 -0
  53. package/dist/commands/self-host/migrate/orm-result.test.d.ts +2 -0
  54. package/dist/commands/self-host/migrate/orm-result.test.d.ts.map +1 -0
  55. package/dist/commands/self-host/migrate/read-config.d.ts +6 -0
  56. package/dist/commands/self-host/migrate/read-config.d.ts.map +1 -0
  57. package/dist/commands/self-host/migrate/read-config.test.d.ts +2 -0
  58. package/dist/commands/self-host/migrate/read-config.test.d.ts.map +1 -0
  59. package/dist/context/creator.d.ts.map +1 -1
  60. package/dist/context/framework-detection.d.ts +1 -1
  61. package/dist/context/framework-detection.d.ts.map +1 -1
  62. package/dist/context/types.d.ts +1 -0
  63. package/dist/context/types.d.ts.map +1 -1
  64. package/dist/index.d.ts +1 -1
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.mjs +760 -940
  67. package/dist/utils/logger.d.ts.map +1 -1
  68. package/dist/utils/telemetry.d.ts +3 -0
  69. package/dist/utils/telemetry.d.ts.map +1 -1
  70. package/package.json +12 -5
  71. package/readme.json +70 -0
  72. package/dist/actions/get-config/config-extraction.d.ts +0 -37
  73. package/dist/actions/get-config/config-extraction.d.ts.map +0 -1
  74. package/dist/actions/get-config/config-validation.d.ts +0 -7
  75. package/dist/actions/get-config/config-validation.d.ts.map +0 -1
  76. package/dist/actions/get-config/constants.d.ts +0 -13
  77. package/dist/actions/get-config/constants.d.ts.map +0 -1
  78. package/dist/actions/get-config/directory-search.d.ts +0 -6
  79. package/dist/actions/get-config/directory-search.d.ts.map +0 -1
  80. package/dist/actions/get-config/jiti-options.d.ts +0 -9
  81. package/dist/actions/get-config/jiti-options.d.ts.map +0 -1
  82. package/dist/actions/get-config.d.ts +0 -13
  83. package/dist/actions/get-config.d.ts.map +0 -1
  84. package/dist/actions/load-config-and-onboard.d.ts +0 -9
  85. package/dist/actions/load-config-and-onboard.d.ts.map +0 -1
  86. package/dist/commands/generate/actions/handle-existing-file.d.ts +0 -7
  87. package/dist/commands/generate/actions/handle-existing-file.d.ts.map +0 -1
  88. package/dist/commands/generate/actions/handle-new-file.d.ts +0 -7
  89. package/dist/commands/generate/actions/handle-new-file.d.ts.map +0 -1
  90. package/dist/commands/generate/actions/perform-write-action.d.ts +0 -6
  91. package/dist/commands/generate/actions/perform-write-action.d.ts.map +0 -1
  92. package/dist/commands/generate/generators/drizzle.d.ts +0 -4
  93. package/dist/commands/generate/generators/drizzle.d.ts.map +0 -1
  94. package/dist/commands/generate/generators/index.d.ts +0 -19
  95. package/dist/commands/generate/generators/index.d.ts.map +0 -1
  96. package/dist/commands/generate/generators/kysely.d.ts +0 -11
  97. package/dist/commands/generate/generators/kysely.d.ts.map +0 -1
  98. package/dist/commands/generate/generators/prisma.d.ts +0 -3
  99. package/dist/commands/generate/generators/prisma.d.ts.map +0 -1
  100. package/dist/commands/generate/generators/types.d.ts +0 -13
  101. package/dist/commands/generate/generators/types.d.ts.map +0 -1
  102. package/dist/commands/generate/schema.d.ts +0 -10
  103. package/dist/commands/generate/schema.d.ts.map +0 -1
  104. package/dist/commands/generate/setup.d.ts +0 -13
  105. package/dist/commands/generate/setup.d.ts.map +0 -1
  106. package/dist/commands/generate/write.d.ts +0 -8
  107. package/dist/commands/generate/write.d.ts.map +0 -1
  108. package/dist/commands/generate.d.ts +0 -6
  109. package/dist/commands/generate.d.ts.map +0 -1
  110. package/dist/commands/migrate/execute.d.ts +0 -7
  111. package/dist/commands/migrate/execute.d.ts.map +0 -1
  112. package/dist/commands/migrate/plan.d.ts +0 -12
  113. package/dist/commands/migrate/plan.d.ts.map +0 -1
  114. package/dist/commands/migrate/setup.d.ts +0 -12
  115. package/dist/commands/migrate/setup.d.ts.map +0 -1
  116. package/dist/commands/migrate.d.ts +0 -3
  117. package/dist/commands/migrate.d.ts.map +0 -1
  118. package/dist/context/config-management.d.ts +0 -20
  119. package/dist/context/config-management.d.ts.map +0 -1
  120. package/dist/onboarding/dependencies.d.ts.map +0 -1
  121. package/dist/onboarding/generate-files.d.ts.map +0 -1
  122. package/dist/onboarding/index.d.ts +0 -11
  123. package/dist/onboarding/index.d.ts.map +0 -1
  124. package/dist/onboarding/storage-modes/c15t-mode.d.ts.map +0 -1
  125. package/dist/onboarding/storage-modes/custom-mode.d.ts.map +0 -1
  126. package/dist/onboarding/storage-modes/index.d.ts +0 -5
  127. package/dist/onboarding/storage-modes/index.d.ts.map +0 -1
  128. package/dist/onboarding/storage-modes/offline-mode.d.ts.map +0 -1
  129. package/dist/onboarding/storage-modes/self-hosted-mode.d.ts +0 -22
  130. package/dist/onboarding/storage-modes/self-hosted-mode.d.ts.map +0 -1
  131. package/dist/onboarding/templates/backend.d.ts.map +0 -1
  132. package/dist/onboarding/templates/config.d.ts.map +0 -1
  133. package/dist/onboarding/templates/env.d.ts.map +0 -1
  134. package/dist/onboarding/templates/index.d.ts.map +0 -1
  135. package/dist/onboarding/templates/layout.d.ts.map +0 -1
  136. package/dist/onboarding/templates/next/app/layout.d.ts.map +0 -1
  137. package/dist/onboarding/templates/next/index.d.ts.map +0 -1
  138. package/dist/onboarding/templates/next/pages/layout.d.ts.map +0 -1
  139. package/dist/onboarding/templates/next-config.d.ts.map +0 -1
  140. package/dist/onboarding/templates/shared/options.d.ts.map +0 -1
  141. package/dist/onboarding.d.ts +0 -15
  142. package/dist/onboarding.d.ts.map +0 -1
  143. /package/dist/{onboarding → commands/generate}/templates/backend.d.ts +0 -0
  144. /package/dist/{onboarding → commands/generate}/templates/next-config.d.ts +0 -0
  145. /package/dist/{onboarding → commands/generate}/templates/shared/options.d.ts +0 -0
package/dist/index.mjs CHANGED
@@ -3,9 +3,8 @@ import * as __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__ from "@clack/pro
3
3
  import "dotenv/config";
4
4
  import * as __WEBPACK_EXTERNAL_MODULE_open__ from "open";
5
5
  import * as __WEBPACK_EXTERNAL_MODULE_picocolors__ from "picocolors";
6
- import * as __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__ from "node:fs/promises";
7
6
  import * as __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__ from "node:path";
8
- import * as __WEBPACK_EXTERNAL_MODULE_c12__ from "c12";
7
+ import * as __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__ from "node:fs/promises";
9
8
  import * as __WEBPACK_EXTERNAL_MODULE_node_crypto_9ba42079__ from "node:crypto";
10
9
  import * as __WEBPACK_EXTERNAL_MODULE_node_os_74b4b876__ from "node:os";
11
10
  import * as __WEBPACK_EXTERNAL_MODULE_posthog_node_1b07bdf4__ from "posthog-node";
@@ -13,213 +12,12 @@ import * as __WEBPACK_EXTERNAL_MODULE_node_child_process_27f17141__ from "node:c
13
12
  import * as __WEBPACK_EXTERNAL_MODULE_node_events_0a6aefe7__ from "node:events";
14
13
  import * as __WEBPACK_EXTERNAL_MODULE__doubletie_logger_91c58a8f__ from "@doubletie/logger";
15
14
  import * as __WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__ from "ts-morph";
16
- import * as __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__ from "node:fs";
17
- import * as __WEBPACK_EXTERNAL_MODULE__c15t_backend_pkgs_db_adapters_cee37d0f__ from "@c15t/backend/pkgs/db-adapters";
18
- import * as __WEBPACK_EXTERNAL_MODULE__c15t_backend_pkgs_migrations_80b6e3bd__ from "@c15t/backend/pkgs/migrations";
15
+ import * as __WEBPACK_EXTERNAL_MODULE__c15t_backend_v2_db_migrator_64e67b79__ from "@c15t/backend/v2/db/migrator";
16
+ import * as __WEBPACK_EXTERNAL_MODULE__c15t_backend_v2_db_schema_c18e255b__ from "@c15t/backend/v2/db/schema";
17
+ import * as __WEBPACK_EXTERNAL_MODULE_c12__ from "c12";
19
18
  import * as __WEBPACK_EXTERNAL_MODULE_figlet__ from "figlet";
20
19
  import * as __WEBPACK_EXTERNAL_MODULE_fs_extra_ce68a66b__ from "fs-extra";
21
20
  import * as __WEBPACK_EXTERNAL_MODULE_package_manager_detector_detect_94d6a9ae__ from "package-manager-detector/detect";
22
- function isC15TOptions(obj) {
23
- return 'object' == typeof obj && null !== obj && 'appName' in obj;
24
- }
25
- function isClientOptions(obj) {
26
- return 'object' == typeof obj && null !== obj && ('mode' in obj || 'backendURL' in obj);
27
- }
28
- function tryGetFunctionResult(fn) {
29
- if ('function' == typeof fn) try {
30
- return fn();
31
- } catch (error) {
32
- console.warn('Error executing config function:', error);
33
- }
34
- return null;
35
- }
36
- function extractOptionsFromConfig(config) {
37
- if (config.c15tConfig && isClientOptions(config.c15tConfig)) return config.c15tConfig;
38
- if (config.c15tOptions && isClientOptions(config.c15tOptions)) return config.c15tOptions;
39
- if (isClientOptions(config)) return config;
40
- if (isC15TOptions(config.c15t)) return config.c15t;
41
- if ('function' == typeof config.c15t) {
42
- const result = tryGetFunctionResult(config.c15t);
43
- if (isC15TOptions(result)) return result;
44
- }
45
- if (isC15TOptions(config.default)) return config.default;
46
- if ('function' == typeof config.default) {
47
- const result = tryGetFunctionResult(config.default);
48
- if (isC15TOptions(result)) return result;
49
- }
50
- if (isC15TOptions(config.c15tInstance)) return config.c15tInstance;
51
- if ('function' == typeof config.c15tInstance) {
52
- const result = tryGetFunctionResult(config.c15tInstance);
53
- if (isC15TOptions(result)) return result;
54
- }
55
- if (isC15TOptions(config.consent)) return config.consent;
56
- if ('function' == typeof config.consent) {
57
- const result = tryGetFunctionResult(config.consent);
58
- if (isC15TOptions(result)) return result;
59
- }
60
- if ('object' == typeof config.c15t && null !== config.c15t && isC15TOptions(config.c15t.options)) return config.c15t.options;
61
- if ('object' == typeof config.default && null !== config.default && isC15TOptions(config.default.options)) return config.default.options;
62
- if ('object' == typeof config.c15tInstance && null !== config.c15tInstance && isC15TOptions(config.c15tInstance.options)) return config.c15tInstance.options;
63
- if ('object' == typeof config.instance && null !== config.instance && isC15TOptions(config.instance.options)) return config.instance.options;
64
- if ('object' == typeof config.consent && null !== config.consent && isC15TOptions(config.consent.options)) return config.consent.options;
65
- if ('object' == typeof config.config && null !== config.config && isC15TOptions(config.config.options)) return config.config.options;
66
- console.debug('No valid configuration found in any of the expected locations');
67
- return null;
68
- }
69
- const configFileNames = [
70
- 'c15t.config',
71
- 'c15t.backend',
72
- 'c15t',
73
- 'c15t.client',
74
- 'consent.config',
75
- 'consent.backend',
76
- 'consent',
77
- 'cmp.config',
78
- 'cmp.backend',
79
- 'cmp'
80
- ];
81
- const constants_extensions = [
82
- '.js',
83
- '.jsx',
84
- '.ts',
85
- '.tsx',
86
- '.cjs',
87
- '.cts',
88
- '.mjs',
89
- '.mts',
90
- '.server.cjs',
91
- '.server.cts',
92
- '.server.js',
93
- '.server.jsx',
94
- '.server.mjs',
95
- '.server.mts',
96
- '.server.ts',
97
- '.server.tsx'
98
- ];
99
- let possiblePaths = configFileNames.flatMap((name)=>constants_extensions.map((ext)=>`${name}${ext}`));
100
- const directories = [
101
- '',
102
- 'lib/server/',
103
- 'server/',
104
- 'lib/',
105
- 'utils/',
106
- 'config/',
107
- 'src/',
108
- 'app/'
109
- ];
110
- possiblePaths = directories.flatMap((dir)=>possiblePaths.map((file)=>`${dir}${file}`));
111
- const jitiOptions = (context, cwd)=>{
112
- const alias = context.config.getPathAliases(cwd) || {};
113
- return {
114
- extensions: [
115
- '.ts',
116
- '.tsx',
117
- '.js',
118
- '.jsx',
119
- '.mjs',
120
- '.cjs',
121
- '.mts',
122
- '.cts'
123
- ],
124
- alias
125
- };
126
- };
127
- async function getConfig(contextOrOptions) {
128
- const context = 'logger' in contextOrOptions ? contextOrOptions : {
129
- ...contextOrOptions,
130
- logger: {
131
- debug: console.debug,
132
- info: console.info,
133
- warn: console.warn,
134
- error: console.error
135
- },
136
- flags: {
137
- config: contextOrOptions.configPath
138
- },
139
- error: {
140
- handleError: (error)=>{
141
- console.error('Error loading configuration:', error);
142
- return null;
143
- }
144
- }
145
- };
146
- const { cwd, logger, flags } = context;
147
- const configPath = flags.config;
148
- let foundConfigPath = null;
149
- try {
150
- let options = null;
151
- const customJitiOptions = jitiOptions(context, cwd);
152
- if (configPath) {
153
- foundConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].resolve(cwd, configPath);
154
- logger.debug(`Using explicitly provided config path: ${foundConfigPath}`);
155
- } else {
156
- const prioritizedDirs = [
157
- cwd,
158
- __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, 'packages/cli')
159
- ];
160
- const primaryName = 'c15t.config';
161
- const extensions = [
162
- '.ts',
163
- '.js',
164
- '.mjs'
165
- ];
166
- for (const dir of prioritizedDirs){
167
- for (const ext of extensions){
168
- const checkPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(dir, `${primaryName}${ext}`);
169
- try {
170
- await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].access(checkPath);
171
- foundConfigPath = checkPath;
172
- logger.debug(`Found config via manual check: ${foundConfigPath}`);
173
- break;
174
- } catch {}
175
- }
176
- if (foundConfigPath) break;
177
- }
178
- }
179
- if (foundConfigPath) try {
180
- logger.debug(`Loading configuration from resolved path: ${foundConfigPath}`);
181
- const result = await (0, __WEBPACK_EXTERNAL_MODULE_c12__.loadConfig)({
182
- configFile: foundConfigPath,
183
- jitiOptions: customJitiOptions
184
- });
185
- logger.debug('Raw config loading result:', result);
186
- if (result.config) {
187
- logger.debug('Trying to extract config from result.config');
188
- options = extractOptionsFromConfig(result.config);
189
- }
190
- if (options) {
191
- logger.debug('Extracted config:', options);
192
- if (isC15TOptions(options) || isClientOptions(options)) {
193
- logger.debug('Configuration validated successfully.');
194
- return options;
195
- }
196
- logger.debug('Loaded config does not match expected schema');
197
- } else logger.debug('No configuration extracted from loaded file');
198
- logger.debug('Raw loaded configuration:', result);
199
- return null;
200
- } catch (error) {
201
- logger.debug('Error loading config from explicit path:', error);
202
- try {
203
- logger.debug(`Trying to require module directly: ${foundConfigPath}`);
204
- const importedModule = await import(foundConfigPath);
205
- logger.debug('Directly imported module:', importedModule);
206
- const extracted = extractOptionsFromConfig(importedModule);
207
- if (extracted && (isC15TOptions(extracted) || isClientOptions(extracted))) {
208
- logger.debug('Found valid config through direct import');
209
- return extracted;
210
- }
211
- } catch (importError) {
212
- logger.debug('Error importing module directly:', importError);
213
- }
214
- return null;
215
- }
216
- return options;
217
- } catch (error) {
218
- if ('error' in context && context.error && 'function' == typeof context.error.handleError) return context.error.handleError(error, 'Error loading configuration');
219
- console.error('Error loading configuration:', error);
220
- return null;
221
- }
222
- }
223
21
  function showHelpMenu(context, version, commands, flags) {
224
22
  const { logger } = context;
225
23
  logger.debug('Displaying help menu using command and flag structures.');
@@ -288,7 +86,7 @@ async function detectFramework(projectRoot, logger) {
288
86
  return {
289
87
  framework: null,
290
88
  frameworkVersion: null,
291
- pkg: null,
89
+ pkg: 'c15t',
292
90
  hasReact: false,
293
91
  reactVersion: null
294
92
  };
@@ -368,7 +166,10 @@ const TelemetryEventName = {
368
166
  MIGRATION_FAILED: 'migration.failed',
369
167
  GENERATE_STARTED: 'generate.started',
370
168
  GENERATE_COMPLETED: 'generate.completed',
371
- GENERATE_FAILED: 'generate.failed'
169
+ GENERATE_FAILED: 'generate.failed',
170
+ SELF_HOST_STARTED: 'self-host.started',
171
+ SELF_HOST_COMPLETED: 'self-host.completed',
172
+ SELF_HOST_FAILED: 'self-host.failed'
372
173
  };
373
174
  class Telemetry {
374
175
  client = null;
@@ -591,6 +392,58 @@ function getManualInstallCommand(dependencies, packageManager) {
591
392
  return `npm install ${dependencies.join(' ')}`;
592
393
  }
593
394
  }
395
+ async function installDependencies({ context, dependenciesToAdd, handleCancel, autoInstall = false }) {
396
+ const { telemetry, logger } = context;
397
+ const s = __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner();
398
+ if (0 === dependenciesToAdd.length) return {
399
+ installDepsConfirmed: false,
400
+ ranInstall: false
401
+ };
402
+ const depsString = dependenciesToAdd.map((d)=>__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(d)).join(', ');
403
+ if (!autoInstall) {
404
+ const addDepsSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
405
+ message: `Add required dependencies using ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(context.packageManager.name)}? (${depsString})`,
406
+ initialValue: true
407
+ });
408
+ if (handleCancel?.(addDepsSelection)) return {
409
+ installDepsConfirmed: false,
410
+ ranInstall: false
411
+ };
412
+ if (!addDepsSelection) return {
413
+ installDepsConfirmed: false,
414
+ ranInstall: false
415
+ };
416
+ }
417
+ s.start(`Running ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(context.packageManager.name)} to add and install dependencies... (this might take a moment)`);
418
+ try {
419
+ await addAndInstallDependenciesViaPM(context.projectRoot, dependenciesToAdd, context.packageManager.name);
420
+ s.stop(`✅ Dependencies installed: ${dependenciesToAdd.map((d)=>__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(d)).join(', ')}`);
421
+ telemetry.trackEvent(TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
422
+ success: true,
423
+ dependencies: dependenciesToAdd.join(','),
424
+ packageManager: context.packageManager.name
425
+ });
426
+ return {
427
+ installDepsConfirmed: true,
428
+ ranInstall: true
429
+ };
430
+ } catch (installError) {
431
+ s.stop(__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].yellow('⚠️ Dependency installation failed.'));
432
+ logger.error('Installation Error:', installError);
433
+ telemetry.trackEvent(TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
434
+ success: false,
435
+ error: installError instanceof Error ? installError.message : String(installError),
436
+ dependencies: dependenciesToAdd.join(','),
437
+ packageManager: context.packageManager.name
438
+ });
439
+ const pmCommand = getManualInstallCommand(dependenciesToAdd, context.packageManager.name);
440
+ logger.info(`Please try running '${pmCommand}' manually in ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(context.cwd, context.projectRoot))}.`);
441
+ return {
442
+ installDepsConfirmed: true,
443
+ ranInstall: false
444
+ };
445
+ }
446
+ }
594
447
  const validLogLevels = [
595
448
  'error',
596
449
  'warn',
@@ -1471,10 +1324,11 @@ async function handleEnvFiles(options) {
1471
1324
  throw error;
1472
1325
  }
1473
1326
  }
1474
- async function generateFiles({ context, projectRoot, mode, pkg, backendURL, spinner, useEnvFile, proxyNextjs }) {
1327
+ async function generateFiles({ context, mode, spinner, useEnvFile, proxyNextjs, backendURL }) {
1475
1328
  const result = {
1476
1329
  layoutUpdated: false
1477
1330
  };
1331
+ const { projectRoot, framework: { pkg } } = context;
1478
1332
  if ('@c15t/nextjs' === pkg || '@c15t/react' === pkg) {
1479
1333
  const layoutResult = await handleReactLayout({
1480
1334
  projectRoot,
@@ -1514,6 +1368,39 @@ async function generateFiles({ context, projectRoot, mode, pkg, backendURL, spin
1514
1368
  });
1515
1369
  return result;
1516
1370
  }
1371
+ async function getSharedFrontendOptions({ backendURL, context, handleCancel }) {
1372
+ let useEnvFile = false;
1373
+ let proxyNextjs;
1374
+ if (!backendURL) return {
1375
+ proxyNextjs: void 0,
1376
+ useEnvFile: void 0
1377
+ };
1378
+ const useEnvFileSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
1379
+ message: 'Store the backendURL in a .env file? (Recommended, URL is public)',
1380
+ initialValue: true
1381
+ });
1382
+ if (handleCancel?.(useEnvFileSelection)) context.error.handleCancel('Setup cancelled.', {
1383
+ command: 'onboarding',
1384
+ stage: 'self_hosted_env_file_setup'
1385
+ });
1386
+ useEnvFile = useEnvFileSelection;
1387
+ if ('@c15t/nextjs' === context.framework.pkg) {
1388
+ context.logger.info('Learn more about Next.js Rewrites: https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites');
1389
+ const proxyNextjsSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
1390
+ message: 'Proxy requests to your instance with Next.js Rewrites? (Recommended)',
1391
+ initialValue: true
1392
+ });
1393
+ if (handleCancel?.(proxyNextjsSelection)) context.error.handleCancel('Setup cancelled.', {
1394
+ command: 'onboarding',
1395
+ stage: 'self_hosted_proxy_nextjs_setup'
1396
+ });
1397
+ proxyNextjs = proxyNextjsSelection;
1398
+ }
1399
+ return {
1400
+ proxyNextjs,
1401
+ useEnvFile
1402
+ };
1403
+ }
1517
1404
  async function handleAccountCreation(context, handleCancel) {
1518
1405
  const { logger } = context;
1519
1406
  const needsAccount = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
@@ -1572,218 +1459,567 @@ async function getBackendURL(context, initialBackendURL, handleCancel) {
1572
1459
  });
1573
1460
  return backendURLSelection;
1574
1461
  }
1575
- async function setupC15tMode({ context, projectRoot, spinner, packageName, initialBackendURL, handleCancel }) {
1462
+ async function setupC15tMode({ context, spinner, initialBackendURL, handleCancel }) {
1576
1463
  await handleAccountCreation(context, handleCancel);
1577
1464
  const backendURL = await getBackendURL(context, initialBackendURL, handleCancel);
1578
- const useEnvFileSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
1579
- message: 'Store the backendURL in a .env file? (Recommended, URL is public)',
1580
- initialValue: true
1581
- });
1582
- if (handleCancel?.(useEnvFileSelection)) context.error.handleCancel('Setup cancelled.', {
1583
- command: 'onboarding',
1584
- stage: 'c15t_env_file_setup'
1465
+ const { useEnvFile, proxyNextjs } = await getSharedFrontendOptions({
1466
+ backendURL: backendURL,
1467
+ context,
1468
+ handleCancel
1585
1469
  });
1586
- const useEnvFile = useEnvFileSelection;
1587
- let proxyNextjs;
1588
- if ('@c15t/nextjs' === packageName) {
1589
- context.logger.info('Learn more about Next.js Rewrites: https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites');
1590
- const proxyNextjsSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
1591
- message: 'Proxy requests to your instance with Next.js Rewrites? (Recommended)',
1592
- initialValue: true
1593
- });
1594
- if (handleCancel?.(proxyNextjsSelection)) context.error.handleCancel('Setup cancelled.', {
1595
- command: 'onboarding',
1596
- stage: 'c15t_proxy_nextjs_setup'
1597
- });
1598
- proxyNextjs = proxyNextjsSelection;
1599
- }
1600
1470
  await generateFiles({
1601
1471
  context,
1602
- projectRoot,
1603
1472
  mode: 'c15t',
1604
- pkg: packageName,
1605
1473
  backendURL,
1606
1474
  spinner,
1607
1475
  useEnvFile,
1608
1476
  proxyNextjs
1609
1477
  });
1478
+ const { ranInstall, installDepsConfirmed } = await installDependencies({
1479
+ context,
1480
+ dependenciesToAdd: [
1481
+ context.framework.pkg
1482
+ ],
1483
+ handleCancel
1484
+ });
1610
1485
  return {
1611
1486
  backendURL,
1612
- usingEnvFile: useEnvFile,
1613
- proxyNextjs
1487
+ usingEnvFile: useEnvFile ?? false,
1488
+ proxyNextjs,
1489
+ installDepsConfirmed,
1490
+ ranInstall
1614
1491
  };
1615
1492
  }
1616
- async function setupCustomMode({ context, projectRoot, spinner, pkg }) {
1617
- const { logger, cwd } = context;
1493
+ async function setupCustomMode({ context, spinner }) {
1494
+ const { logger, cwd, framework: { pkg } } = context;
1495
+ if (!pkg) throw new Error('Error detecting framework');
1618
1496
  const result = await generateFiles({
1619
1497
  context,
1620
- projectRoot,
1621
1498
  mode: 'custom',
1622
- pkg,
1623
1499
  spinner
1624
1500
  });
1625
1501
  logger.info(`Remember to implement custom endpoint handlers ${result.configPath ? `(see ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, result.configPath))})` : ''}`);
1502
+ const { ranInstall, installDepsConfirmed } = await installDependencies({
1503
+ context,
1504
+ dependenciesToAdd: [
1505
+ context.framework.pkg
1506
+ ]
1507
+ });
1626
1508
  return {
1627
- clientConfigContent: result.configContent ?? ''
1509
+ clientConfigContent: result.configContent ?? '',
1510
+ installDepsConfirmed,
1511
+ ranInstall
1628
1512
  };
1629
1513
  }
1630
- async function setupOfflineMode({ context, projectRoot, spinner, pkg }) {
1514
+ async function setupOfflineMode({ context, spinner }) {
1631
1515
  const result = await generateFiles({
1632
1516
  context,
1633
- projectRoot,
1634
1517
  mode: 'offline',
1635
- pkg,
1636
1518
  spinner
1637
1519
  });
1520
+ const { ranInstall, installDepsConfirmed } = await installDependencies({
1521
+ context,
1522
+ dependenciesToAdd: [
1523
+ context.framework.pkg
1524
+ ]
1525
+ });
1638
1526
  return {
1639
- clientConfigContent: result.configContent ?? ''
1527
+ clientConfigContent: result.configContent ?? '',
1528
+ installDepsConfirmed,
1529
+ ranInstall
1640
1530
  };
1641
1531
  }
1642
- function generateBackendConfigContent(adapterChoice, connectionString, filePath) {
1643
- let adapterImport = '';
1644
- let adapterConfig = '';
1645
- switch(adapterChoice){
1646
- case 'kysely-postgres':
1647
- adapterImport = `import { kyselyAdapter } from '@c15t/backend/db/adapters/kysely';\nimport { PostgresDialect } from 'kysely';\nimport { Pool } from 'pg';`;
1648
- adapterConfig = `kyselyAdapter({
1649
- dialect: new PostgresDialect({
1650
- pool: new Pool({
1651
- connectionString: ${connectionString ? `"${connectionString}"` : 'process.env.DATABASE_URL || "postgresql://user:password@host:port/db"'}
1652
- })
1653
- })
1654
- })`;
1655
- break;
1656
- case 'kysely-sqlite':
1657
- adapterImport = `import { kyselyAdapter } from '@c15t/backend/db/adapters/kysely';\nimport { SqliteDialect } from 'kysely';\nimport Database from 'better-sqlite3';`;
1658
- adapterConfig = `kyselyAdapter({
1659
- dialect: new SqliteDialect({
1660
- database: new Database("${filePath || './db.sqlite'}")
1661
- })
1662
- })`;
1663
- break;
1664
- default:
1665
- adapterImport = "import { memoryAdapter } from '@c15t/backend/db/adapters/memory';";
1666
- adapterConfig = 'memoryAdapter({})';
1667
- break;
1532
+ const ADAPTER_LABELS = {
1533
+ kyselyAdapter: 'kysely',
1534
+ drizzleAdapter: 'drizzle',
1535
+ prismaAdapter: 'prisma',
1536
+ typeormAdapter: 'typeorm',
1537
+ mongoAdapter: 'mongo'
1538
+ };
1539
+ const PROVIDERS_BY_ADAPTER = {
1540
+ kyselyAdapter: [
1541
+ {
1542
+ label: 'PostgreSQL',
1543
+ value: 'postgresql'
1544
+ },
1545
+ {
1546
+ label: 'MySQL',
1547
+ value: 'mysql'
1548
+ },
1549
+ {
1550
+ label: 'SQLite',
1551
+ value: 'sqlite'
1552
+ },
1553
+ {
1554
+ label: 'CockroachDB',
1555
+ value: 'cockroachdb'
1556
+ },
1557
+ {
1558
+ label: 'Microsoft SQL Server',
1559
+ value: 'mssql'
1560
+ }
1561
+ ],
1562
+ drizzleAdapter: [
1563
+ {
1564
+ label: 'PostgreSQL',
1565
+ value: 'postgresql'
1566
+ },
1567
+ {
1568
+ label: 'MySQL',
1569
+ value: 'mysql'
1570
+ },
1571
+ {
1572
+ label: 'SQLite',
1573
+ value: 'sqlite'
1574
+ }
1575
+ ],
1576
+ prismaAdapter: [
1577
+ {
1578
+ label: 'PostgreSQL',
1579
+ value: 'postgresql'
1580
+ },
1581
+ {
1582
+ label: 'MySQL',
1583
+ value: 'mysql'
1584
+ },
1585
+ {
1586
+ label: 'SQLite',
1587
+ value: 'sqlite'
1588
+ },
1589
+ {
1590
+ label: 'MongoDB',
1591
+ value: 'mongodb'
1592
+ }
1593
+ ],
1594
+ typeormAdapter: [
1595
+ {
1596
+ label: 'PostgreSQL',
1597
+ value: 'postgresql'
1598
+ },
1599
+ {
1600
+ label: 'MySQL',
1601
+ value: 'mysql'
1602
+ },
1603
+ {
1604
+ label: 'SQLite',
1605
+ value: 'sqlite'
1606
+ },
1607
+ {
1608
+ label: 'SQL Server',
1609
+ value: 'mssql'
1610
+ }
1611
+ ],
1612
+ mongoAdapter: [
1613
+ {
1614
+ label: 'MongoDB',
1615
+ value: 'mongodb'
1616
+ }
1617
+ ]
1618
+ };
1619
+ class Cancelled extends Error {
1620
+ stage;
1621
+ constructor(stage){
1622
+ super('Operation cancelled.');
1623
+ this.stage = stage;
1624
+ }
1625
+ }
1626
+ const CONFIG_BUILDERS = {
1627
+ kyselyAdapter: (provider)=>`kyselyAdapter({ provider: '${provider}', db })`,
1628
+ drizzleAdapter: (provider)=>`drizzleAdapter({ provider: '${provider}', db })`,
1629
+ prismaAdapter: (provider)=>`prismaAdapter({ provider: '${provider}', prisma })`,
1630
+ typeormAdapter: (provider)=>`typeormAdapter({ provider: '${provider}', source })`,
1631
+ mongoAdapter: ()=>'mongoAdapter({ client })'
1632
+ };
1633
+ async function pathExists(filePath) {
1634
+ try {
1635
+ await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].access(filePath);
1636
+ return true;
1637
+ } catch {
1638
+ return false;
1668
1639
  }
1669
- return `// c15t Backend Configuration
1670
- // Generated by c15t CLI onboarding
1671
-
1672
- import { c15tInstance } from '@c15t/backend';
1673
- ${adapterImport}
1674
-
1675
- // WARNING: Database connection strings often contain sensitive credentials.
1676
- // Consider using environment variables instead of hardcoding these values.
1677
-
1678
- // Define your c15t instance
1679
- const instance = c15tInstance({
1680
- appName: 'Your App Name',
1681
- basePath: '/api/c15t',
1682
- database: ${adapterConfig},
1683
- trustedOrigins: ['http://localhost:3000'],
1640
+ }
1641
+ function buildDatabaseConfig(adapter, provider, connection) {
1642
+ const builder = CONFIG_BUILDERS[adapter];
1643
+ return builder(provider, connection);
1644
+ }
1645
+ function buildKyselyPrelude(provider, connection) {
1646
+ const connExpr = connection.useEnv ? `process.env.${connection.envVar || 'DATABASE_URL'}!` : `"${connection.value || ''}"`;
1647
+ if ('postgresql' === provider || 'cockroachdb' === provider) return {
1648
+ imports: "import { Kysely, PostgresDialect } from 'kysely';\nimport { Pool } from 'pg';",
1649
+ prelude: `const db = new Kysely({\n\tdialect: new PostgresDialect({\n\t\tpool: new Pool({ connectionString: ${connExpr} }),\n\t}),\n});`
1650
+ };
1651
+ if ('mysql' === provider) return {
1652
+ imports: "import { Kysely, MysqlDialect } from 'kysely';\nimport mysql from 'mysql2/promise';",
1653
+ prelude: `const db = new Kysely({\n\tdialect: new MysqlDialect({\n\t\tpool: mysql.createPool(${connExpr}),\n\t}),\n});`
1654
+ };
1655
+ if ('mssql' === provider) return {
1656
+ imports: "import { Kysely, MssqlDialect } from 'kysely';\nimport mssql from 'mssql';",
1657
+ prelude: `const db = new Kysely({\n\tdialect: new MssqlDialect({\n\t\tpool: new mssql.ConnectionPool(${connExpr}),\n\t}),\n});`
1658
+ };
1659
+ return {
1660
+ imports: '',
1661
+ prelude: ''
1662
+ };
1663
+ }
1664
+ function buildSqliteKyselyPrelude(file) {
1665
+ return {
1666
+ imports: "import { Kysely, SqliteDialect } from 'kysely';\nimport Database from 'better-sqlite3';",
1667
+ prelude: `const db = new Kysely({\n\tdialect: new SqliteDialect({\n\t\tdatabase: new Database("${file}"),\n\t}),\n});`
1668
+ };
1669
+ }
1670
+ function buildDrizzlePrelude(provider, connection) {
1671
+ const connExpr = connection.useEnv ? `process.env.${connection.envVar || 'DATABASE_URL'}!` : `"${connection.value || ''}"`;
1672
+ if ('postgresql' === provider) return {
1673
+ imports: "import { drizzle } from 'drizzle-orm/node-postgres';\nimport { Pool } from 'pg';",
1674
+ prelude: `const db = drizzle(new Pool({ connectionString: ${connExpr} }));`
1675
+ };
1676
+ if ('mysql' === provider) return {
1677
+ imports: "import { drizzle } from 'drizzle-orm/mysql2';\nimport mysql from 'mysql2/promise';",
1678
+ prelude: `const db = drizzle(await mysql.createConnection(${connExpr}));`
1679
+ };
1680
+ if ('sqlite' === provider) {
1681
+ const file = connection.sqliteFile || './db.sqlite';
1682
+ return {
1683
+ imports: "import { drizzle } from 'drizzle-orm/better-sqlite3';\nimport Database from 'better-sqlite3';",
1684
+ prelude: `const db = drizzle(new Database("${file}"));`
1685
+ };
1686
+ }
1687
+ return {
1688
+ imports: '',
1689
+ prelude: ''
1690
+ };
1691
+ }
1692
+ function buildPrismaPrelude(_provider, _connection) {
1693
+ return {
1694
+ imports: "import { PrismaClient } from '@prisma/client';",
1695
+ prelude: 'const prisma = new PrismaClient();'
1696
+ };
1697
+ }
1698
+ function buildTypeormPrelude(provider, connection) {
1699
+ const connExpr = connection.useEnv ? `process.env.${connection.envVar || 'DATABASE_URL'}!` : `"${connection.value || ''}"`;
1700
+ if ('sqlite' === provider) {
1701
+ const file = connection.sqliteFile || './db.sqlite';
1702
+ return {
1703
+ imports: "import { DataSource } from 'typeorm';",
1704
+ prelude: `const source = new DataSource({ type: 'sqlite', database: "${file}" });`
1705
+ };
1706
+ }
1707
+ const typeMap = {
1708
+ postgresql: 'postgres',
1709
+ mysql: 'mysql',
1710
+ mssql: 'mssql'
1711
+ };
1712
+ return {
1713
+ imports: "import { DataSource } from 'typeorm';",
1714
+ prelude: `const source = new DataSource({ type: '${typeMap[String(provider)]}', url: ${connExpr} });`
1715
+ };
1716
+ }
1717
+ function buildMongoPrelude(connection) {
1718
+ const urlExpr = connection.useEnv ? `process.env.${connection.envVar || 'MONGODB_URI'}!` : `"${connection.value || ''}"`;
1719
+ return {
1720
+ imports: "import { MongoClient } from 'mongodb';",
1721
+ prelude: `const client = new MongoClient(${urlExpr});`
1722
+ };
1723
+ }
1724
+ function buildFileContent(adapter, provider, dbConfig, connection) {
1725
+ const adapterPath = 'mongoAdapter' === adapter ? 'mongo' : adapter.replace('Adapter', '');
1726
+ const importAdapter = `import { ${adapter} } from '@c15t/backend/v2/db/adapters/${adapterPath}';`;
1727
+ let extras = {
1728
+ imports: '',
1729
+ prelude: ''
1730
+ };
1731
+ if ('kyselyAdapter' === adapter) if ('sqlite' === provider) {
1732
+ const file = connection.sqliteFile || './db.sqlite';
1733
+ extras = buildSqliteKyselyPrelude(file);
1734
+ } else extras = buildKyselyPrelude(provider, connection);
1735
+ else if ('drizzleAdapter' === adapter) extras = buildDrizzlePrelude(provider, connection);
1736
+ else if ('prismaAdapter' === adapter) extras = buildPrismaPrelude(provider, connection);
1737
+ else if ('typeormAdapter' === adapter) extras = buildTypeormPrelude(provider, connection);
1738
+ else if ('mongoAdapter' === adapter) extras = buildMongoPrelude(connection);
1739
+ return `import { defineConfig } from '@c15t/backend/v2';
1740
+ ${importAdapter}
1741
+ ${extras.imports ? `${extras.imports}\n` : ''}
1742
+ ${extras.prelude ? `${extras.prelude}\n` : ''}
1743
+ export default defineConfig({
1744
+ adapter: ${dbConfig},
1684
1745
  });
1685
-
1686
- export default instance;
1687
1746
  `;
1688
1747
  }
1689
- async function setupSelfHostedMode(context, projectRoot, spinner, handleCancel) {
1690
- const { cwd } = context;
1691
- let backendConfigContent = null;
1692
- const dependencies = [
1693
- '@c15t/backend'
1694
- ];
1695
- const setupBackendSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
1696
- message: 'Set up the backend configuration now?',
1697
- initialValue: true
1748
+ async function promptSelectAdapter() {
1749
+ const selection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.select({
1750
+ message: 'Select database adapter:',
1751
+ options: Object.keys(ADAPTER_LABELS).map((key)=>({
1752
+ value: key,
1753
+ label: ADAPTER_LABELS[key]
1754
+ }))
1698
1755
  });
1699
- if (handleCancel?.(setupBackendSelection)) context.error.handleCancel('Setup cancelled.', {
1700
- command: 'onboarding',
1701
- stage: 'self_hosted_backend_setup'
1756
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(selection)) throw new Cancelled('adapter_select');
1757
+ return selection;
1758
+ }
1759
+ async function promptSelectProvider(adapter) {
1760
+ const providers = PROVIDERS_BY_ADAPTER[adapter];
1761
+ if (0 === providers.length) throw new Error('No providers available for selected adapter');
1762
+ if (1 === providers.length) {
1763
+ const [first] = providers;
1764
+ return first.value;
1765
+ }
1766
+ const selection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.select({
1767
+ message: 'Select database provider:',
1768
+ options: providers.map((opt)=>({
1769
+ value: opt.value,
1770
+ label: opt.label
1771
+ }))
1702
1772
  });
1703
- const setupBackend = setupBackendSelection;
1704
- let adapterChoice = 'memory';
1705
- if (setupBackend) {
1706
- const adapterSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.select({
1707
- message: 'Choose a database adapter:',
1708
- initialValue: 'kysely-sqlite',
1709
- options: [
1710
- {
1711
- value: 'kysely-sqlite',
1712
- label: 'Kysely (SQLite)',
1713
- hint: 'Simple setups/local dev'
1714
- },
1715
- {
1716
- value: 'kysely-postgres',
1717
- label: 'Kysely (PostgreSQL)',
1718
- hint: 'Production'
1719
- },
1720
- {
1721
- value: 'memory',
1722
- label: 'Memory',
1723
- hint: 'Testing/development only'
1724
- }
1725
- ]
1773
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(selection)) throw new Cancelled('provider_select');
1774
+ return selection;
1775
+ }
1776
+ async function promptConnection(adapter, provider) {
1777
+ const connection = {
1778
+ useEnv: true
1779
+ };
1780
+ if ('sqlite' === provider) {
1781
+ const sqliteFile = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.text({
1782
+ message: 'SQLite file path:',
1783
+ initialValue: './db.sqlite'
1726
1784
  });
1727
- if (handleCancel?.(adapterSelection)) context.error.handleCancel('Setup cancelled.', {
1728
- command: 'onboarding',
1729
- stage: 'self_hosted_adapter_selection'
1785
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(sqliteFile)) throw new Cancelled('sqlite_path');
1786
+ connection.sqliteFile = String(sqliteFile);
1787
+ return connection;
1788
+ }
1789
+ const useEnv = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
1790
+ message: 'Store connection string in an environment variable?',
1791
+ initialValue: true
1792
+ });
1793
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(useEnv)) throw new Cancelled('use_env_confirm');
1794
+ connection.useEnv = Boolean(useEnv);
1795
+ if (connection.useEnv) {
1796
+ const defaultVar = 'mongoAdapter' === adapter ? 'MONGODB_URI' : 'DATABASE_URL';
1797
+ const envVarName = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.text({
1798
+ message: 'Env var name for connection string:',
1799
+ initialValue: defaultVar
1730
1800
  });
1731
- adapterChoice = adapterSelection;
1732
- let connectionString;
1733
- let dbPath;
1734
- if ('kysely-postgres' === adapterChoice) {
1735
- const connectionStringSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.text({
1736
- message: 'Enter PostgreSQL connection string:',
1737
- placeholder: 'postgresql://user:pass@host:port/db'
1738
- });
1739
- if (handleCancel?.(connectionStringSelection)) context.error.handleCancel('Setup cancelled.', {
1740
- command: 'onboarding',
1741
- stage: 'self_hosted_postgres_setup'
1742
- });
1743
- if (!connectionStringSelection || '' === connectionStringSelection) context.error.handleCancel('A valid PostgreSQL connection string is required', {
1744
- command: 'onboarding',
1745
- stage: 'self_hosted_postgres_validation'
1746
- });
1747
- connectionString = connectionStringSelection;
1748
- } else if ('kysely-sqlite' === adapterChoice) {
1749
- const dbPathSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.text({
1750
- message: 'Enter path for SQLite database file:',
1751
- placeholder: './db.sqlite',
1752
- initialValue: './db.sqlite'
1753
- });
1754
- if (handleCancel?.(dbPathSelection)) context.error.handleCancel('Setup cancelled.', {
1755
- command: 'onboarding',
1756
- stage: 'self_hosted_sqlite_setup'
1757
- });
1758
- if (!dbPathSelection || '' === dbPathSelection) context.error.handleCancel('A valid database path is required', {
1759
- command: 'onboarding',
1760
- stage: 'self_hosted_sqlite_validation'
1761
- });
1762
- dbPath = dbPathSelection;
1763
- }
1764
- backendConfigContent = generateBackendConfigContent(adapterChoice, connectionString, dbPath);
1765
- const backendConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'c15t.backend.ts');
1766
- spinner.start('Creating backend configuration file...');
1767
- await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(backendConfigPath, backendConfigContent);
1768
- spinner.stop(formatLogMessage('info', `Backend configuration created: ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, backendConfigPath))}`));
1801
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(envVarName)) throw new Cancelled('env_var_name');
1802
+ connection.envVar = String(envVarName);
1803
+ return connection;
1804
+ }
1805
+ const placeholder = 'mongoAdapter' === adapter ? 'mongodb+srv://user:pass@host/db' : 'postgresql://user:pass@host:5432/db';
1806
+ const connectionString = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.text({
1807
+ message: 'Connection string:',
1808
+ placeholder
1809
+ });
1810
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(connectionString)) throw new Cancelled('connection_string');
1811
+ connection.value = String(connectionString);
1812
+ return connection;
1813
+ }
1814
+ async function ensureBackendConfig(context) {
1815
+ const { cwd, logger } = context;
1816
+ const targetPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, 'c15t-backend.config.ts');
1817
+ if (await pathExists(targetPath)) {
1818
+ logger.debug(`Backend config already exists at ${targetPath}`);
1819
+ return {
1820
+ path: targetPath,
1821
+ dependencies: []
1822
+ };
1769
1823
  }
1770
- const clientConfigContent = generateClientConfigContent('c15t', '/api/c15t', false);
1771
- const configPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'c15t.config.ts');
1772
- spinner.start('Creating client configuration file...');
1773
- await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(configPath, clientConfigContent);
1774
- spinner.stop(formatLogMessage('info', `Client configuration created: ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, configPath))}`));
1775
- return {
1776
- clientConfigContent,
1777
- backendConfigContent,
1778
- dependencies,
1779
- adapterChoice
1780
- };
1781
- }
1782
- const WINDOWS_PATH_SEPARATOR_REGEX = /\\/g;
1824
+ try {
1825
+ const adapter = await promptSelectAdapter();
1826
+ const provider = await promptSelectProvider(adapter);
1827
+ const connection = await promptConnection(adapter, provider);
1828
+ const dependencies = [];
1829
+ if ('kyselyAdapter' === adapter) {
1830
+ dependencies.push('kysely');
1831
+ if ('postgresql' === provider || 'cockroachdb' === provider) dependencies.push('pg');
1832
+ else if ('mysql' === provider) dependencies.push('mysql2');
1833
+ else if ('mssql' === provider) dependencies.push('mssql');
1834
+ else if ('sqlite' === provider) dependencies.push('better-sqlite3');
1835
+ } else if ('drizzleAdapter' === adapter) {
1836
+ dependencies.push('drizzle-orm');
1837
+ if ('postgresql' === provider) dependencies.push('pg');
1838
+ else if ('mysql' === provider) dependencies.push('mysql2');
1839
+ else if ('sqlite' === provider) dependencies.push('better-sqlite3');
1840
+ } else if ('prismaAdapter' === adapter) dependencies.push('@prisma/client');
1841
+ else if ('typeormAdapter' === adapter) dependencies.push('typeorm');
1842
+ else if ('mongoAdapter' === adapter) dependencies.push('mongodb');
1843
+ const dbConfig = buildDatabaseConfig(adapter, provider, connection);
1844
+ const fileContent = buildFileContent(adapter, String(provider), dbConfig, connection);
1845
+ await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(targetPath, fileContent, 'utf8');
1846
+ context.logger.success(`Created ${__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, targetPath)}`);
1847
+ if ('sqlite' !== provider && connection.useEnv && connection.envVar) context.logger.note(`Remember to set ${connection.envVar} in your environment or .env file.`, 'Environment');
1848
+ return {
1849
+ path: targetPath,
1850
+ dependencies
1851
+ };
1852
+ } catch (err) {
1853
+ if (err instanceof Cancelled) return context.error.handleCancel('Operation cancelled.', {
1854
+ command: 'ensure-backend-config',
1855
+ stage: err.stage
1856
+ });
1857
+ throw err;
1858
+ }
1859
+ }
1860
+ async function handleMigrationResult(context, result) {
1861
+ const { logger, telemetry } = context;
1862
+ telemetry.trackEvent(TelemetryEventName.MIGRATION_PLANNED, {
1863
+ success: true
1864
+ });
1865
+ const viewSQL = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
1866
+ message: 'View SQL for this migration?',
1867
+ initialValue: true
1868
+ });
1869
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(viewSQL)) return void telemetry.trackEvent(TelemetryEventName.MIGRATION_FAILED, {
1870
+ viewSQL: false
1871
+ });
1872
+ if (viewSQL) {
1873
+ const sql = result.getSQL?.() ?? '';
1874
+ logger.info(sql);
1875
+ }
1876
+ const execute = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
1877
+ message: 'Execute this migration?',
1878
+ initialValue: false
1879
+ });
1880
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(execute)) return void telemetry.trackEvent(TelemetryEventName.MIGRATION_FAILED, {
1881
+ execute: false
1882
+ });
1883
+ await result.execute();
1884
+ logger.success('Migration completed.');
1885
+ telemetry.trackEvent(TelemetryEventName.MIGRATION_COMPLETED, {
1886
+ success: true
1887
+ });
1888
+ }
1889
+ async function handleORMResult(context, result) {
1890
+ const { logger, telemetry, cwd } = context;
1891
+ const filePath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, result.path);
1892
+ await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].mkdir(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].dirname(filePath), {
1893
+ recursive: true
1894
+ });
1895
+ await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(filePath, result.code);
1896
+ logger.info(`Migration file created at ${filePath}`);
1897
+ telemetry.trackEvent(TelemetryEventName.MIGRATION_COMPLETED, {
1898
+ success: true,
1899
+ migrationFileCreated: true
1900
+ });
1901
+ }
1902
+ async function readConfigAndGetDb(context, absoluteConfigPath) {
1903
+ const { logger } = context;
1904
+ logger.info(`Loading backend config from ${absoluteConfigPath}`);
1905
+ const resolvedPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].resolve(absoluteConfigPath);
1906
+ try {
1907
+ await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].access(resolvedPath);
1908
+ } catch {
1909
+ throw new Error(`Backend config not found at: ${resolvedPath}`);
1910
+ }
1911
+ try {
1912
+ const { config } = await (0, __WEBPACK_EXTERNAL_MODULE_c12__.loadConfig)({
1913
+ configFile: absoluteConfigPath,
1914
+ jitiOptions: {
1915
+ extensions: [
1916
+ '.ts',
1917
+ '.tsx',
1918
+ '.js',
1919
+ '.jsx',
1920
+ '.mjs',
1921
+ '.cjs',
1922
+ '.mts',
1923
+ '.cts',
1924
+ '.cjs'
1925
+ ]
1926
+ }
1927
+ });
1928
+ logger.debug('Imported Config');
1929
+ return {
1930
+ db: __WEBPACK_EXTERNAL_MODULE__c15t_backend_v2_db_schema_c18e255b__.DB.client(config.adapter)
1931
+ };
1932
+ } catch (error) {
1933
+ logger.error('Failed to load backend config', error);
1934
+ if (error instanceof Error) throw error;
1935
+ throw new Error(`Unknown error loading backend config: ${String(error)}`);
1936
+ }
1937
+ }
1938
+ async function migrate(context) {
1939
+ const { logger } = context;
1940
+ logger.info('Starting migration process...');
1941
+ const configResult = await ensureBackendConfig(context);
1942
+ if (!configResult || !configResult.path) return void logger.error('No backend config found.');
1943
+ const { path, dependencies } = configResult;
1944
+ if (dependencies.length > 0) await installDependencies({
1945
+ context,
1946
+ dependenciesToAdd: dependencies,
1947
+ autoInstall: true
1948
+ });
1949
+ const { db } = await readConfigAndGetDb(context, path);
1950
+ logger.info('Loaded c15t-backend.config.ts');
1951
+ const result = await (0, __WEBPACK_EXTERNAL_MODULE__c15t_backend_v2_db_migrator_64e67b79__.migrator)({
1952
+ db,
1953
+ schema: 'latest'
1954
+ });
1955
+ if ('path' in result) await handleORMResult(context, result);
1956
+ else await handleMigrationResult(context, result);
1957
+ }
1958
+ async function setupSelfHostedMode({ context, spinner, handleCancel }) {
1959
+ const dependenciesToAdd = [
1960
+ context.framework.pkg,
1961
+ '@c15t/backend'
1962
+ ];
1963
+ const targetPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(context.cwd, 'c15t-backend.config.ts');
1964
+ let createBackendConfig = false;
1965
+ if (!await pathExists(targetPath)) {
1966
+ if (createBackendConfig) {
1967
+ const config = await ensureBackendConfig(context);
1968
+ createBackendConfig = true;
1969
+ dependenciesToAdd.push(...config?.dependencies ?? []);
1970
+ }
1971
+ }
1972
+ const backendURL = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.text({
1973
+ message: 'Enter the backend URL:',
1974
+ initialValue: 'http://localhost:3000'
1975
+ });
1976
+ if (handleCancel?.(backendURL)) context.error.handleCancel('Setup cancelled.', {
1977
+ command: 'onboarding',
1978
+ stage: 'self_hosted_backend_url_setup'
1979
+ });
1980
+ const { useEnvFile, proxyNextjs } = await getSharedFrontendOptions({
1981
+ backendURL: backendURL,
1982
+ context,
1983
+ handleCancel
1984
+ });
1985
+ await generateFiles({
1986
+ context,
1987
+ mode: 'c15t',
1988
+ backendURL: backendURL,
1989
+ spinner,
1990
+ useEnvFile,
1991
+ proxyNextjs
1992
+ });
1993
+ const { ranInstall, installDepsConfirmed } = await installDependencies({
1994
+ context,
1995
+ dependenciesToAdd,
1996
+ handleCancel
1997
+ });
1998
+ const runMigrations = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
1999
+ message: 'Would you like to run migrations?',
2000
+ initialValue: true
2001
+ });
2002
+ if (handleCancel?.(runMigrations)) context.error.handleCancel('Setup cancelled.', {
2003
+ command: 'onboarding',
2004
+ stage: 'self_hosted_run_migrations_setup'
2005
+ });
2006
+ if (runMigrations) await migrate(context);
2007
+ return {
2008
+ backendURL: backendURL,
2009
+ usingEnvFile: useEnvFile ?? false,
2010
+ proxyNextjs,
2011
+ createBackendConfig: createBackendConfig,
2012
+ installDepsConfirmed,
2013
+ ranInstall,
2014
+ runMigrations: runMigrations
2015
+ };
2016
+ }
2017
+ const WINDOWS_PATH_SEPARATOR_REGEX = /\\/g;
1783
2018
  const FILE_EXTENSION_REGEX = /\.(ts|js|tsx|jsx)$/;
1784
- async function startOnboarding(context, existingConfig) {
2019
+ async function generate(context, mode) {
1785
2020
  const { logger, telemetry } = context;
1786
- const isUpdate = !!existingConfig;
2021
+ logger.debug('Starting generate command...');
2022
+ logger.debug(`Mode: ${mode}`);
1787
2023
  const handleCancel = (value)=>{
1788
2024
  if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(value)) {
1789
2025
  telemetry.trackEvent(TelemetryEventName.ONBOARDING_EXITED, {
@@ -1799,12 +2035,10 @@ async function startOnboarding(context, existingConfig) {
1799
2035
  return false;
1800
2036
  };
1801
2037
  try {
1802
- logger.info(isUpdate ? 'Starting configuration update...' : 'Starting onboarding process...');
1803
- telemetry.trackEvent(isUpdate ? TelemetryEventName.CONFIG_UPDATED : TelemetryEventName.ONBOARDING_STARTED, {
1804
- isUpdate
1805
- });
2038
+ logger.info('Starting onboarding process...');
2039
+ telemetry.trackEvent(TelemetryEventName.ONBOARDING_STARTED, {});
1806
2040
  telemetry.flushSync();
1807
- await performOnboarding(context, existingConfig, handleCancel);
2041
+ await performOnboarding(context, handleCancel, mode);
1808
2042
  logger.success('🚀 Setup completed successfully!');
1809
2043
  } catch (error) {
1810
2044
  if (!__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(error)) telemetry.trackEvent(TelemetryEventName.ONBOARDING_COMPLETED, {
@@ -1813,70 +2047,78 @@ async function startOnboarding(context, existingConfig) {
1813
2047
  });
1814
2048
  }
1815
2049
  }
1816
- async function performOnboarding(context, existingConfig, handleCancel) {
2050
+ async function performOnboarding(context, handleCancel, mode) {
1817
2051
  const { telemetry, logger, packageManager } = context;
1818
- const isUpdate = !!existingConfig;
1819
2052
  const projectRoot = await detectProjectRoot(context.cwd, logger);
1820
2053
  const { pkg } = await detectFramework(projectRoot, logger);
1821
2054
  if (!pkg) throw new Error('Error detecting framework');
1822
- const storageMode = await handleStorageModeSelection(context, handleCancel, existingConfig);
1823
- if (!storageMode) return;
1824
- const dependenciesToAdd = [
1825
- pkg
1826
- ];
1827
- switch(storageMode){
2055
+ let selectedMode = mode ?? null;
2056
+ logger.debug(`Selected mode: ${selectedMode}`);
2057
+ if (!selectedMode) selectedMode = await handleStorageModeSelection(context, handleCancel);
2058
+ if (!selectedMode) return;
2059
+ const sharedOptions = {
2060
+ context,
2061
+ spinner: __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner(),
2062
+ handleCancel
2063
+ };
2064
+ let installDepsConfirmed = false;
2065
+ let ranInstall = false;
2066
+ const dependenciesToAdd = [];
2067
+ switch(selectedMode){
1828
2068
  case 'c15t':
1829
2069
  {
1830
- const initialBackendURL = isUpdate && existingConfig && isClientOptions(existingConfig) ? existingConfig.backendURL : void 0;
1831
- const c15tResult = await setupC15tMode({
1832
- context,
1833
- projectRoot,
1834
- spinner: __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner(),
1835
- packageName: pkg,
1836
- initialBackendURL,
1837
- handleCancel
1838
- });
2070
+ const c15tResult = await setupC15tMode(sharedOptions);
2071
+ installDepsConfirmed = c15tResult.installDepsConfirmed;
2072
+ ranInstall = c15tResult.ranInstall;
2073
+ dependenciesToAdd.push(context.framework.pkg);
1839
2074
  telemetry.trackEvent(TelemetryEventName.ONBOARDING_C15T_MODE_CONFIGURED, {
1840
2075
  usingEnvFile: c15tResult.usingEnvFile,
1841
- hasInitialBackendURL: !!initialBackendURL,
1842
2076
  proxyNextjs: c15tResult.proxyNextjs
1843
2077
  });
1844
2078
  break;
1845
2079
  }
1846
2080
  case 'offline':
1847
- await setupOfflineMode({
1848
- context,
1849
- projectRoot,
1850
- spinner: __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner(),
1851
- pkg
1852
- });
1853
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_OFFLINE_MODE_CONFIGURED, {});
1854
- break;
2081
+ {
2082
+ const offlineResult = await setupOfflineMode({
2083
+ context,
2084
+ spinner: __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner()
2085
+ });
2086
+ installDepsConfirmed = offlineResult.installDepsConfirmed;
2087
+ ranInstall = offlineResult.ranInstall;
2088
+ dependenciesToAdd.push(context.framework.pkg);
2089
+ telemetry.trackEvent(TelemetryEventName.ONBOARDING_OFFLINE_MODE_CONFIGURED, {});
2090
+ break;
2091
+ }
1855
2092
  case 'self-hosted':
1856
2093
  {
1857
- const selfHostedResult = await setupSelfHostedMode(context, projectRoot, __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner(), handleCancel);
1858
- dependenciesToAdd.push(...selfHostedResult.dependencies);
1859
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_SELF_HOSTED_CONFIGURED, {
1860
- databaseType: selfHostedResult.adapterChoice,
1861
- dependencies: selfHostedResult.dependencies.join(',')
2094
+ const selfHostedResult = await setupSelfHostedMode({
2095
+ context,
2096
+ spinner: __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner(),
2097
+ handleCancel
1862
2098
  });
2099
+ installDepsConfirmed = selfHostedResult.installDepsConfirmed;
2100
+ ranInstall = selfHostedResult.ranInstall;
2101
+ dependenciesToAdd.push(context.framework.pkg);
2102
+ telemetry.trackEvent(TelemetryEventName.ONBOARDING_SELF_HOSTED_CONFIGURED, {});
1863
2103
  break;
1864
2104
  }
1865
2105
  default:
1866
- await setupCustomMode({
1867
- context,
1868
- projectRoot,
1869
- spinner: __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner(),
1870
- pkg
1871
- });
1872
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_CUSTOM_MODE_CONFIGURED, {});
1873
- break;
2106
+ {
2107
+ const customResult = await setupCustomMode({
2108
+ context,
2109
+ spinner: __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner()
2110
+ });
2111
+ installDepsConfirmed = customResult.installDepsConfirmed;
2112
+ ranInstall = customResult.ranInstall;
2113
+ dependenciesToAdd.push(context.framework.pkg);
2114
+ telemetry.trackEvent(TelemetryEventName.ONBOARDING_CUSTOM_MODE_CONFIGURED, {});
2115
+ break;
2116
+ }
1874
2117
  }
1875
- const { installDepsConfirmed, ranInstall } = await handleDependencyInstallation(context, projectRoot, dependenciesToAdd, packageManager, handleCancel, isUpdate);
1876
2118
  await displayNextSteps({
1877
2119
  context,
1878
2120
  projectRoot,
1879
- storageMode,
2121
+ storageMode: selectedMode,
1880
2122
  installDepsConfirmed,
1881
2123
  ranInstall,
1882
2124
  dependenciesToAdd,
@@ -1885,16 +2127,15 @@ async function performOnboarding(context, existingConfig, handleCancel) {
1885
2127
  await handleGitHubStar(context);
1886
2128
  telemetry.trackEvent(TelemetryEventName.ONBOARDING_COMPLETED, {
1887
2129
  success: true,
1888
- storageMode,
2130
+ selectedMode,
1889
2131
  installDependencies: ranInstall
1890
2132
  });
1891
2133
  }
1892
- async function handleStorageModeSelection(context, handleCancel, existingConfig) {
2134
+ async function handleStorageModeSelection(context, handleCancel) {
1893
2135
  const { telemetry } = context;
1894
- const initialStorageMode = getInitialStorageMode(existingConfig);
1895
2136
  const storageModeSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.select({
1896
- message: existingConfig ? `Select storage mode (current: ${initialStorageMode || 'unknown'}):` : 'How would you like to store consent decisions?',
1897
- initialValue: initialStorageMode || 'c15t',
2137
+ message: 'How would you like to store consent decisions?',
2138
+ initialValue: 'c15t',
1898
2139
  options: [
1899
2140
  {
1900
2141
  value: 'c15t',
@@ -1921,71 +2162,15 @@ async function handleStorageModeSelection(context, handleCancel, existingConfig)
1921
2162
  if (handleCancel(storageModeSelection)) return null;
1922
2163
  const storageMode = storageModeSelection;
1923
2164
  telemetry.trackEvent(TelemetryEventName.ONBOARDING_STORAGE_MODE_SELECTED, {
1924
- storageMode,
1925
- isUpdate: !!existingConfig
2165
+ storageMode
1926
2166
  });
1927
2167
  return storageMode;
1928
2168
  }
1929
- async function handleDependencyInstallation(context, projectRoot, dependenciesToAdd, packageManager, handleCancel, isUpdate) {
1930
- const { telemetry, logger } = context;
1931
- const s = __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner();
1932
- if (0 === dependenciesToAdd.length) return {
1933
- installDepsConfirmed: false,
1934
- ranInstall: false
1935
- };
1936
- const depsString = dependenciesToAdd.map((d)=>__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(d)).join(', ');
1937
- const addDepsSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
1938
- message: `${isUpdate ? 'Update' : 'Add'} required dependencies using ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(packageManager.name)}? (${depsString})`,
1939
- initialValue: true
1940
- });
1941
- if (handleCancel(addDepsSelection)) return {
1942
- installDepsConfirmed: false,
1943
- ranInstall: false
1944
- };
1945
- if (!addDepsSelection) return {
1946
- installDepsConfirmed: false,
1947
- ranInstall: false
1948
- };
1949
- s.start(`Running ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(packageManager.name)} to add and install dependencies... (this might take a moment)`);
1950
- try {
1951
- await addAndInstallDependenciesViaPM(projectRoot, dependenciesToAdd, packageManager.name);
1952
- s.stop(`✅ Dependencies installed: ${dependenciesToAdd.map((d)=>__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(d)).join(', ')}`);
1953
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
1954
- success: true,
1955
- dependencies: dependenciesToAdd.join(','),
1956
- packageManager: packageManager.name
1957
- });
1958
- return {
1959
- installDepsConfirmed: true,
1960
- ranInstall: true
1961
- };
1962
- } catch (installError) {
1963
- s.stop(__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].yellow('⚠️ Dependency installation failed.'));
1964
- logger.error('Installation Error:', installError);
1965
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
1966
- success: false,
1967
- error: installError instanceof Error ? installError.message : String(installError),
1968
- dependencies: dependenciesToAdd.join(','),
1969
- packageManager: packageManager.name
1970
- });
1971
- const pmCommand = getManualInstallCommand(dependenciesToAdd, packageManager.name);
1972
- logger.info(`Please try running '${pmCommand}' manually in ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(context.cwd, projectRoot))}.`);
1973
- return {
1974
- installDepsConfirmed: true,
1975
- ranInstall: false
1976
- };
1977
- }
1978
- }
1979
- function getInitialStorageMode(config) {
1980
- if (!config) return;
1981
- if ('mode' in config) return isClientOptions(config) ? config.mode : 'c15t';
1982
- }
1983
2169
  async function displayNextSteps(options) {
1984
2170
  const { context, projectRoot, storageMode, installDepsConfirmed, ranInstall, dependenciesToAdd, packageManager } = options;
1985
2171
  const { logger, cwd } = context;
1986
2172
  const { log } = __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__;
1987
2173
  const configPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'c15t.config.ts');
1988
- const backendConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'c15t.backend.ts');
1989
2174
  const relativeConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, configPath);
1990
2175
  const importPath = `./${relativeConfigPath.replace(WINDOWS_PATH_SEPARATOR_REGEX, '/').replace(FILE_EXTENSION_REGEX, '')}`;
1991
2176
  const importStatement = __WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(`import { c15tConfig } from '${importPath}';`);
@@ -1995,20 +2180,9 @@ async function displayNextSteps(options) {
1995
2180
  case 'offline':
1996
2181
  break;
1997
2182
  case 'self-hosted':
1998
- {
1999
- log.step('Configuration Complete! Next Steps:');
2000
- let steps = '';
2001
- try {
2002
- await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].access(backendConfigPath);
2003
- steps += `1. Configure database connection in ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, backendConfigPath))}.\n`;
2004
- steps += ' 2. Set up API routes using the exported backend instance.\n';
2005
- } catch {
2006
- steps += '1. Set up your c15t backend instance and API routes.\n';
2007
- }
2008
- steps += `3. Ensure ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('backendURL')} in ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(relativeConfigPath)} points to your API.\n`;
2009
- logger.info(steps);
2010
- break;
2011
- }
2183
+ log.step('Setup your backend with the c15t docs:');
2184
+ logger.info('https://c15t.com/docs/self-host/v2');
2185
+ break;
2012
2186
  case 'custom':
2013
2187
  {
2014
2188
  log.step('Configuration Complete! Next Steps:');
@@ -2054,335 +2228,90 @@ If you find this useful, we'd really appreciate a GitHub star - it helps others
2054
2228
  logger.info(`You can star us later by visiting: ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('https://github.com/c15t/c15t')}`);
2055
2229
  }
2056
2230
  }
2057
- async function setupGenerateEnvironment(context) {
2058
- const { logger, flags, cwd, error, telemetry } = context;
2059
- logger.debug('Setting up generate environment...');
2060
- logger.debug('Context flags:', flags);
2061
- logger.debug(`Context CWD: ${cwd}`);
2062
- if (!(0, __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__.existsSync)(cwd)) {
2063
- telemetry.trackEvent(TelemetryEventName.GENERATE_FAILED, {
2064
- error: `Directory ${cwd} does not exist`,
2065
- stage: 'setup'
2066
- });
2067
- return error.handleError(new Error(`The directory "${cwd}" does not exist`), 'Generate setup failed');
2068
- }
2069
- logger.debug('Attempting to load configuration...');
2070
- const config = await context.config.loadConfig();
2071
- if (!config) {
2072
- logger.debug('No config found during setup, generate command will handle onboarding.');
2073
- try {
2074
- const memAdapter = await (0, __WEBPACK_EXTERNAL_MODULE__c15t_backend_pkgs_db_adapters_cee37d0f__.getAdapter)({
2075
- appName: 'temp-for-setup',
2076
- database: {
2077
- adapter: 'memory'
2078
- }
2079
- });
2080
- return {
2081
- config: null,
2082
- adapter: memAdapter
2083
- };
2084
- } catch (adapterError) {
2085
- telemetry.trackEvent(TelemetryEventName.GENERATE_FAILED, {
2086
- error: adapterError instanceof Error ? adapterError.message : String(adapterError),
2087
- stage: 'adapter_initialization'
2088
- });
2089
- return error.handleError(adapterError, 'Failed to initialize default memory adapter');
2090
- }
2091
- }
2092
- logger.debug('Config loaded, initializing adapter...');
2093
- let adapter;
2094
- try {
2095
- adapter = await (0, __WEBPACK_EXTERNAL_MODULE__c15t_backend_pkgs_db_adapters_cee37d0f__.getAdapter)(config);
2096
- logger.debug('Adapter initialized successfully');
2097
- } catch (e) {
2098
- telemetry.trackEvent(TelemetryEventName.GENERATE_FAILED, {
2099
- error: e instanceof Error ? e.message : String(e),
2100
- stage: 'adapter_initialization_with_config'
2101
- });
2102
- return error.handleError(e, 'Failed to initialize database adapter');
2103
- }
2104
- if (!adapter) {
2105
- telemetry.trackEvent(TelemetryEventName.GENERATE_FAILED, {
2106
- error: 'Adapter initialization returned undefined',
2107
- stage: 'adapter_initialization_check'
2108
- });
2109
- return error.handleError(new Error('Adapter initialization returned undefined'), 'Database adapter could not be initialized');
2231
+ const subcommands = [
2232
+ {
2233
+ name: 'generate',
2234
+ label: 'Generate',
2235
+ hint: 'Generate code for your c15t project',
2236
+ action: generate
2237
+ },
2238
+ {
2239
+ name: 'migrate',
2240
+ label: 'Migrate',
2241
+ hint: 'Run database migrations',
2242
+ action: migrate
2110
2243
  }
2111
- logger.debug('Environment setup complete');
2112
- return {
2113
- config,
2114
- adapter
2115
- };
2116
- }
2117
- async function generate(context) {
2118
- const { logger, error, telemetry } = context;
2119
- logger.debug('Starting generate command...');
2120
- telemetry.trackEvent(TelemetryEventName.GENERATE_STARTED, {});
2121
- const setupResult = await setupGenerateEnvironment(context);
2122
- let { config, adapter } = setupResult;
2123
- if (config) {
2124
- let currentMode = 'unknown';
2125
- if (isClientOptions(config)) {
2126
- if (config.mode) currentMode = config.mode;
2127
- } else if (isC15TOptions(config)) currentMode = 'backend';
2128
- telemetry.trackEvent(TelemetryEventName.CONFIG_LOADED, {
2129
- type: currentMode,
2130
- exists: true
2131
- });
2132
- const shouldUpdate = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
2133
- message: formatLogMessage('warn', `A c15t configuration already exists. Would you like to update it before generating? (${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].dim(`Current mode: ${currentMode}`)})`),
2134
- initialValue: false
2135
- });
2136
- if (!shouldUpdate) {
2137
- telemetry.trackEvent(TelemetryEventName.GENERATE_COMPLETED, {
2138
- success: false,
2139
- reason: 'user_cancelled'
2140
- });
2141
- return error.handleCancel('Operation cancelled.', {
2142
- command: 'generate',
2143
- stage: 'config_update_prompt'
2144
- });
2145
- }
2146
- if (shouldUpdate) {
2147
- await startOnboarding(context, config);
2148
- logger.debug('Reloading configuration after update...');
2149
- const postUpdateResult = await setupGenerateEnvironment(context);
2150
- if (!postUpdateResult.config) {
2151
- telemetry.trackEvent(TelemetryEventName.GENERATE_FAILED, {
2152
- error: 'Failed to load configuration after update'
2244
+ ];
2245
+ async function selfHost(context) {
2246
+ const { logger, telemetry, commandArgs, error } = context;
2247
+ logger.debug('Starting self-host command...');
2248
+ telemetry.trackEvent(TelemetryEventName.SELF_HOST_STARTED, {});
2249
+ const [subcommand] = commandArgs;
2250
+ if (subcommand) {
2251
+ switch(subcommand){
2252
+ case 'generate':
2253
+ await generate(context, 'self-hosted');
2254
+ break;
2255
+ case 'migrate':
2256
+ await migrate(context);
2257
+ break;
2258
+ default:
2259
+ logger.error(`Unknown self-host subcommand: ${subcommand}`);
2260
+ logger.info('Available subcommands: generate, migrate');
2261
+ telemetry.trackEvent(TelemetryEventName.SELF_HOST_COMPLETED, {
2262
+ success: false,
2263
+ reason: 'unknown_subcommand'
2153
2264
  });
2154
- return error.handleError(new Error('Failed to load configuration after update.'), 'Configuration Error');
2155
- }
2156
- config = postUpdateResult.config;
2157
- postUpdateResult.adapter;
2158
- logger.info('Configuration updated successfully.');
2159
- telemetry.trackEvent(TelemetryEventName.GENERATE_COMPLETED, {
2160
- success: true,
2161
- configUpdated: true
2162
- });
2163
- } else {
2164
- logger.debug('Proceeding with existing configuration.');
2165
- telemetry.trackEvent(TelemetryEventName.GENERATE_COMPLETED, {
2166
- success: true,
2167
- configUpdated: false
2168
- });
2169
- }
2170
- } else {
2171
- logger.info('No configuration found.');
2172
- telemetry.trackEvent(TelemetryEventName.CONFIG_LOADED, {
2173
- exists: false
2174
- });
2175
- const shouldOnboard = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
2176
- message: 'No c15t configuration found. Would you like to create one now?',
2177
- initialValue: true
2178
- });
2179
- if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(shouldOnboard) || !shouldOnboard) {
2180
- telemetry.trackEvent(TelemetryEventName.GENERATE_COMPLETED, {
2181
- success: false,
2182
- reason: 'onboarding_declined'
2183
- });
2184
- return error.handleCancel('Configuration setup cancelled.', {
2185
- command: 'generate',
2186
- stage: 'onboarding_prompt'
2187
- });
2188
- }
2189
- await startOnboarding(context);
2190
- logger.debug('Reloading configuration after onboarding...');
2191
- const postOnboardResult = await setupGenerateEnvironment(context);
2192
- if (!postOnboardResult.config) {
2193
- telemetry.trackEvent(TelemetryEventName.GENERATE_FAILED, {
2194
- error: 'Failed to load configuration even after onboarding'
2195
- });
2196
- return error.handleError(new Error('Failed to load configuration even after onboarding.'), 'Configuration Error');
2265
+ break;
2197
2266
  }
2198
- config = postOnboardResult.config;
2199
- postOnboardResult.adapter;
2200
- logger.info('New configuration loaded successfully.');
2201
- telemetry.trackEvent(TelemetryEventName.GENERATE_COMPLETED, {
2202
- success: true,
2203
- newConfigCreated: true
2204
- });
2267
+ return;
2205
2268
  }
2206
- }
2207
- async function executeMigrations(context, runMigrationsFn) {
2208
- const { logger, telemetry } = context;
2209
- logger.info('Executing migrations...');
2210
- const s = __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner();
2211
- s.start('Running migrations...');
2212
- telemetry.trackEvent(TelemetryEventName.MIGRATION_EXECUTED, {
2213
- status: 'started'
2269
+ logger.debug('No subcommand specified, entering interactive selection.');
2270
+ telemetry.trackEvent(TelemetryEventName.INTERACTIVE_MENU_OPENED, {
2271
+ context: 'self-host'
2214
2272
  });
2215
- try {
2216
- await runMigrationsFn();
2217
- s.stop('Migrations completed successfully!');
2218
- logger.success('🚀 Database migrated successfully');
2219
- telemetry.trackEvent(TelemetryEventName.MIGRATION_EXECUTED, {
2220
- status: 'completed'
2273
+ const promptOptions = subcommands.map((cmd)=>({
2274
+ value: cmd.name,
2275
+ label: cmd.label,
2276
+ hint: cmd.hint
2277
+ }));
2278
+ promptOptions.push({
2279
+ value: 'exit',
2280
+ label: 'Exit',
2281
+ hint: 'Return to main menu'
2282
+ });
2283
+ const selectedSubcommandName = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.select({
2284
+ message: formatLogMessage('info', 'Which self-host command would you like to run?'),
2285
+ options: promptOptions
2286
+ });
2287
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(selectedSubcommandName) || 'exit' === selectedSubcommandName) {
2288
+ logger.debug('Interactive selection cancelled or exit chosen.');
2289
+ telemetry.trackEvent(TelemetryEventName.INTERACTIVE_MENU_EXITED, {
2290
+ action: __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(selectedSubcommandName) ? 'cancelled' : 'exit',
2291
+ context: 'self-host'
2221
2292
  });
2222
- } catch (error) {
2223
- logger.error('Migration failed.');
2224
- telemetry.trackEvent(TelemetryEventName.MIGRATION_EXECUTED, {
2225
- status: 'failed',
2226
- error: error instanceof Error ? error.message : String(error)
2293
+ error.handleCancel('Operation cancelled.', {
2294
+ command: 'self-host',
2295
+ stage: 'menu_selection'
2227
2296
  });
2228
- context.error.handleError(error, 'Error running migrations');
2229
- }
2230
- }
2231
- async function planMigrations(context, config, skipConfirmation) {
2232
- const { logger } = context;
2233
- logger.info('Planning migrations...');
2234
- logger.debug('Config:', config);
2235
- logger.debug(`Skip confirmation: ${skipConfirmation}`);
2236
- const s = __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner();
2237
- s.start('Preparing migration plan...');
2238
- let migrationData;
2239
- try {
2240
- migrationData = await (0, __WEBPACK_EXTERNAL_MODULE__c15t_backend_pkgs_migrations_80b6e3bd__.getMigrations)(config);
2241
- logger.debug('Migration data:', migrationData);
2242
- } catch (err) {
2243
- s.stop('Migration preparation failed.');
2244
- if (err instanceof Error) logger.error(err.message);
2245
- else logger.error(String(err));
2246
- logger.failed('Migration planning failed');
2247
- return {
2248
- shouldRun: false,
2249
- runMigrationsFn: null
2250
- };
2251
- }
2252
- if (!migrationData) {
2253
- s.stop('Could not retrieve migration data.');
2254
- logger.failed('Migration planning failed');
2255
- return {
2256
- shouldRun: false,
2257
- runMigrationsFn: null
2258
- };
2259
- }
2260
- const { toBeAdded, toBeCreated, runMigrations } = migrationData;
2261
- logger.debug('Migrations to be added:', toBeAdded);
2262
- logger.debug('Migrations to be created:', toBeCreated);
2263
- if (!toBeAdded.length && !toBeCreated.length) {
2264
- s.stop('No migrations needed.');
2265
- logger.info('🚀 Database is up to date');
2266
- return {
2267
- shouldRun: false,
2268
- runMigrationsFn: null
2269
- };
2270
- }
2271
- s.stop('Migration plan prepared.');
2272
- logger.info('🔑 The following migrations will be applied:');
2273
- for (const table of [
2274
- ...toBeCreated,
2275
- ...toBeAdded
2276
- ]){
2277
- const fields = Object.keys(table.fields).join(', ');
2278
- const tableName = table.table;
2279
- logger.info(` + Table ${tableName}: Add fields [${fields}]`);
2280
- logger.message(` ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('+')} Table ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].yellow(tableName)}: Add fields [${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].green(fields)}]`);
2281
- }
2282
- logger.message('');
2283
- let shouldMigrate = skipConfirmation;
2284
- if (!shouldMigrate) {
2285
- shouldMigrate = await context.confirm('Apply these migrations to the database?', false);
2286
- logger.debug(`User confirmation: ${shouldMigrate}`);
2287
- }
2288
- if (!shouldMigrate) {
2289
- logger.failed('Migration cancelled');
2290
- return {
2291
- shouldRun: false,
2292
- runMigrationsFn: null
2293
- };
2294
- }
2295
- logger.debug('Proceeding with migration execution');
2296
- return {
2297
- shouldRun: true,
2298
- runMigrationsFn: runMigrations
2299
- };
2300
- }
2301
- async function loadConfigAndOnboard(context) {
2302
- const { logger } = context;
2303
- logger.debug('Checking for existing configuration...');
2304
- let config;
2305
- try {
2306
- config = await context.config.loadConfig();
2307
- } catch (error) {
2308
- return context.error.handleError(error, 'Unexpected error during configuration loading');
2309
- }
2310
- if (!config) {
2311
- logger.info('No config found, starting onboarding.');
2312
- await startOnboarding(context);
2313
- logger.debug('Exiting after triggering onboarding.');
2314
- process.exit(0);
2297
+ return;
2315
2298
  }
2316
- logger.debug('Configuration loaded successfully.');
2317
- return config;
2318
- }
2319
- function validateAdapterIsKysely(context, adapter) {
2320
- const { logger, error } = context;
2321
- logger.debug('Validating adapter:', adapter);
2322
- if (!adapter || 'kysely' !== adapter.id) {
2323
- let message = 'Invalid or unsupported database configuration for migrate. Migrate command only works with built-in Kysely adapter.';
2324
- if (adapter?.id === 'prisma') message = "The migrate command only works with the built-in Kysely adapter. For Prisma, run `npx @c15t/cli generate` to create the schema, then use Prisma's migrate or push to apply it.";
2325
- else if (adapter?.id === 'drizzle') message = "The migrate command only works with the built-in Kysely adapter. For Drizzle, run `npx @c15t/cli generate` to create the schema, then use Drizzle's migrate or push to apply it.";
2326
- error.handleError(new Error('Adapter validation failed: Not using Kysely'), message);
2327
- }
2328
- }
2329
- async function setupEnvironment(context) {
2330
- const { logger, flags, cwd, error } = context;
2331
- logger.info('Setting up migration environment...');
2332
- logger.debug('Flags:', flags);
2333
- logger.debug(`Working directory: ${cwd}`);
2334
- if (!(0, __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__.existsSync)(cwd)) return error.handleError(new Error(`The directory "${cwd}" does not exist`), 'Migration setup failed');
2335
- const config = await loadConfigAndOnboard(context);
2336
- logger.debug('Config loaded:', config);
2337
- let adapter;
2338
- try {
2339
- logger.debug('Initializing database adapter...');
2340
- adapter = await (0, __WEBPACK_EXTERNAL_MODULE__c15t_backend_pkgs_db_adapters_cee37d0f__.getAdapter)(config);
2341
- logger.debug('Adapter initialized:', adapter);
2342
- } catch (e) {
2343
- return error.handleError(e, 'Failed to initialize database adapter');
2344
- }
2345
- validateAdapterIsKysely(context, adapter);
2346
- logger.info('✅ Environment setup complete');
2347
- return {
2348
- config,
2349
- adapter: adapter
2350
- };
2351
- }
2352
- async function migrate(context) {
2353
- const { logger, flags, telemetry } = context;
2354
- logger.info('Starting migration process...');
2355
- logger.debug('Context:', context);
2356
- telemetry.trackEvent(TelemetryEventName.MIGRATION_STARTED, {
2357
- skipConfirmation: true === flags.y
2358
- });
2359
- const skipConfirmation = flags.y;
2360
- try {
2361
- const { config } = await setupEnvironment(context);
2362
- const planResult = await planMigrations(context, config, skipConfirmation);
2363
- logger.debug('Plan result:', planResult);
2364
- telemetry.trackEvent(TelemetryEventName.MIGRATION_PLANNED, {
2365
- shouldRun: planResult.shouldRun,
2366
- hasMigrations: !!planResult.runMigrationsFn
2367
- });
2368
- if (planResult.shouldRun && planResult.runMigrationsFn) {
2369
- await executeMigrations(context, planResult.runMigrationsFn);
2370
- telemetry.trackEvent(TelemetryEventName.MIGRATION_COMPLETED, {
2371
- success: true
2372
- });
2373
- } else {
2374
- logger.debug('Skipping migration execution based on plan result');
2375
- telemetry.trackEvent(TelemetryEventName.MIGRATION_COMPLETED, {
2376
- success: true,
2377
- reason: planResult.shouldRun ? 'no_migrations_needed' : 'user_cancelled'
2378
- });
2379
- }
2380
- } catch (error) {
2381
- telemetry.trackEvent(TelemetryEventName.MIGRATION_FAILED, {
2382
- error: error instanceof Error ? error.message : String(error)
2299
+ const selectedSubcommand = subcommands.find((cmd)=>cmd.name === selectedSubcommandName);
2300
+ if (selectedSubcommand) {
2301
+ logger.debug(`User selected subcommand: ${selectedSubcommand.name}`);
2302
+ if ('generate' === selectedSubcommand.name) await generate(context, 'self-hosted');
2303
+ else await selectedSubcommand.action(context);
2304
+ } else {
2305
+ logger.error(`Unknown subcommand: ${selectedSubcommandName}`);
2306
+ telemetry.trackEvent(TelemetryEventName.SELF_HOST_COMPLETED, {
2307
+ success: false,
2308
+ reason: 'invalid_selection'
2383
2309
  });
2384
- context.error.handleError(error, 'An unexpected error occurred during the migration process');
2310
+ return;
2385
2311
  }
2312
+ telemetry.trackEvent(TelemetryEventName.SELF_HOST_COMPLETED, {
2313
+ success: true
2314
+ });
2386
2315
  }
2387
2316
  async function displayIntro(context, version) {
2388
2317
  const { logger } = context;
@@ -2431,86 +2360,6 @@ async function displayIntro(context, version) {
2431
2360
  });
2432
2361
  logger.message(coloredLines.join('\n'));
2433
2362
  }
2434
- function createConfigManagement(context) {
2435
- const { logger, error } = context;
2436
- return {
2437
- loadConfig: async ()=>{
2438
- logger.debug('Attempting to load configuration...');
2439
- try {
2440
- const configResult = await getConfig(context);
2441
- const config = configResult ?? null;
2442
- logger.debug('Config loading result:', config);
2443
- if (config) logger.debug('Configuration loaded successfully.');
2444
- else logger.debug('No configuration found.');
2445
- return config;
2446
- } catch (err) {
2447
- return error.handleError(err, 'Error loading configuration');
2448
- }
2449
- },
2450
- requireConfig: async ()=>{
2451
- const config = await context.config.loadConfig();
2452
- if (!config) return error.handleError(new Error('Configuration required but not found'), 'Missing required configuration');
2453
- return config;
2454
- },
2455
- getPathAliases: (configDir)=>{
2456
- const cwd = configDir || context.cwd;
2457
- const tsConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, 'tsconfig.json');
2458
- const jsConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, 'jsconfig.json');
2459
- const configPath = __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].existsSync(tsConfigPath) ? tsConfigPath : __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].existsSync(jsConfigPath) ? jsConfigPath : null;
2460
- if (!configPath) return null;
2461
- try {
2462
- return extractAliasesFromConfigFile(context, configPath, cwd);
2463
- } catch (extractError) {
2464
- logger.warn(`Error extracting path aliases from ${configPath}:`, extractError);
2465
- return null;
2466
- }
2467
- }
2468
- };
2469
- }
2470
- function stripJsonComments(jsonString) {
2471
- return jsonString.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g)=>g ? '' : m).replace(/,(?=\s*[}\]])/g, '');
2472
- }
2473
- function extractAliasesFromConfigFile(context, configPath, cwd) {
2474
- try {
2475
- const configContent = __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].readFileSync(configPath, 'utf8');
2476
- const strippedConfigContent = stripJsonComments(configContent);
2477
- const config = JSON.parse(strippedConfigContent);
2478
- const { paths = {}, baseUrl = '.' } = config.compilerOptions || {};
2479
- const result = {};
2480
- const obj = Object.entries(paths);
2481
- for (const [alias, aliasPaths] of obj)for (const aliasedPath of aliasPaths){
2482
- const resolvedBaseUrl = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, baseUrl);
2483
- const finalAlias = '*' === alias.slice(-1) ? alias.slice(0, -1) : alias;
2484
- const finalAliasedPath = '*' === aliasedPath.slice(-1) ? aliasedPath.slice(0, -1) : aliasedPath;
2485
- result[finalAlias || ''] = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(resolvedBaseUrl, finalAliasedPath);
2486
- }
2487
- if (hasSvelteKit(cwd)) addSvelteKitEnvModules(result);
2488
- return result;
2489
- } catch (error) {
2490
- context.logger.warn(`Error parsing config file ${configPath}`, error);
2491
- return null;
2492
- }
2493
- }
2494
- function hasSvelteKit(cwd) {
2495
- try {
2496
- const packageJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, 'package.json');
2497
- if (!__WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].existsSync(packageJsonPath)) return false;
2498
- const packageJson = JSON.parse(__WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].readFileSync(packageJsonPath, 'utf8'));
2499
- const deps = {
2500
- ...packageJson.dependencies,
2501
- ...packageJson.devDependencies
2502
- };
2503
- return '@sveltejs/kit' in deps;
2504
- } catch (error) {
2505
- return false;
2506
- }
2507
- }
2508
- function addSvelteKitEnvModules(aliases) {
2509
- aliases['$app/'] = '$app/';
2510
- aliases['$lib/'] = '$lib/';
2511
- aliases['$env/'] = '$env/';
2512
- aliases['$service-worker'] = '$service-worker';
2513
- }
2514
2363
  function createErrorHandlers(context) {
2515
2364
  const { logger, telemetry } = context;
2516
2365
  return {
@@ -2737,7 +2586,7 @@ function createUserInteraction(context) {
2737
2586
  }
2738
2587
  async function createCliContext(rawArgs, cwd, commands) {
2739
2588
  const { commandName, commandArgs, parsedFlags } = parseCliArgs(rawArgs, commands);
2740
- let desiredLogLevel = 'info';
2589
+ let desiredLogLevel = 'debug';
2741
2590
  const levelArg = parsedFlags.logger;
2742
2591
  if ('string' == typeof levelArg) if (validLogLevels.includes(levelArg)) desiredLogLevel = levelArg;
2743
2592
  else console.warn(`[CLI Setup] Invalid log level '${levelArg}' provided via --logger. Using default 'info'.`);
@@ -2755,11 +2604,10 @@ async function createCliContext(rawArgs, cwd, commands) {
2755
2604
  context.error = createErrorHandlers(context);
2756
2605
  const userInteraction = createUserInteraction(context);
2757
2606
  context.confirm = userInteraction.confirm;
2758
- context.config = createConfigManagement(context);
2759
2607
  context.fs = createFileSystem(context);
2760
- const projectRoot = await detectProjectRoot(cwd, logger);
2761
- context.framework = await detectFramework(projectRoot, logger);
2762
- context.packageManager = await detectPackageManager(projectRoot, logger);
2608
+ context.projectRoot = await detectProjectRoot(cwd, logger);
2609
+ context.framework = await detectFramework(context.projectRoot, logger);
2610
+ context.packageManager = await detectPackageManager(context.projectRoot, logger);
2763
2611
  const telemetryDisabled = true === parsedFlags['no-telemetry'];
2764
2612
  const telemetryDebug = true === parsedFlags['telemetry-debug'];
2765
2613
  try {
@@ -2794,17 +2642,17 @@ async function createCliContext(rawArgs, cwd, commands) {
2794
2642
  const src_commands = [
2795
2643
  {
2796
2644
  name: 'generate',
2797
- label: 'generate',
2798
- hint: 'Generate schema/code',
2799
- description: 'Generate schema/code based on your c15t config.',
2645
+ label: 'Generate (Recommended)',
2646
+ hint: 'Add c15t to your project',
2647
+ description: 'Setup your c15t project',
2800
2648
  action: (context)=>generate(context)
2801
2649
  },
2802
2650
  {
2803
- name: 'migrate',
2804
- label: 'migrate',
2805
- hint: 'Run database migrations',
2806
- description: 'Run database migrations based on your c15t config.',
2807
- action: (context)=>migrate(context)
2651
+ name: 'self-host',
2652
+ label: 'Self Host',
2653
+ hint: 'Host c15t backend on your own infra',
2654
+ description: 'Commands for self-hosting c15t (generate, migrate).',
2655
+ action: (context)=>selfHost(context)
2808
2656
  },
2809
2657
  {
2810
2658
  name: 'github',
@@ -2878,34 +2726,6 @@ flag or set ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('C15T_TELEM
2878
2726
  await displayIntro(context, version);
2879
2727
  logger.debug(`Current working directory: ${cwd}`);
2880
2728
  logger.debug(`Config path flag: ${flags.config}`);
2881
- let clientConfig;
2882
- let backendConfig;
2883
- try {
2884
- const loadedConfig = await getConfig(context);
2885
- if (loadedConfig) if (isClientOptions(loadedConfig)) clientConfig = loadedConfig;
2886
- else if (isC15TOptions(loadedConfig)) backendConfig = loadedConfig;
2887
- else logger.warn('Loaded configuration is of an unknown type.');
2888
- if (loadedConfig) telemetry.trackEvent(TelemetryEventName.CONFIG_LOADED, {
2889
- configType: clientConfig ? 'client' : backendConfig ? 'backend' : 'unknown',
2890
- hasBackend: Boolean(backendConfig)
2891
- });
2892
- } catch (loadError) {
2893
- telemetry.trackEvent(TelemetryEventName.CONFIG_ERROR, {
2894
- error: loadError instanceof Error ? loadError.message : String(loadError)
2895
- });
2896
- return error.handleError(loadError, 'An unexpected error occurred during configuration loading');
2897
- }
2898
- if (!clientConfig) {
2899
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_STARTED, {});
2900
- await startOnboarding(context);
2901
- await telemetry.shutdown();
2902
- return;
2903
- }
2904
- const coloredConsentIo = __WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyanBright('consent.io');
2905
- const backendStatus = backendConfig ? 'Backend configuration loaded' : `Using ${coloredConsentIo} for your c15t deployment`;
2906
- logger.info(`Client configuration successfully loaded and validated \n ${backendStatus}`);
2907
- logger.debug('Client config details:', clientConfig);
2908
- if (backendConfig) logger.debug('Backend config details:', backendConfig);
2909
2729
  try {
2910
2730
  if (commandName) {
2911
2731
  const command = src_commands.find((cmd)=>cmd.name === commandName);