@c15t/cli 1.2.0-beta.17 → 1.2.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +595 -0
- package/README.md +106 -0
- package/dist/actions/get-config/config-extraction.d.ts +37 -0
- package/dist/actions/get-config/config-extraction.d.ts.map +1 -0
- package/dist/actions/get-config/config-validation.d.ts +7 -0
- package/dist/actions/get-config/config-validation.d.ts.map +1 -0
- package/dist/actions/get-config/constants.d.ts +13 -0
- package/dist/actions/get-config/constants.d.ts.map +1 -0
- package/dist/actions/get-config/directory-search.d.ts +6 -0
- package/dist/actions/get-config/directory-search.d.ts.map +1 -0
- package/dist/actions/get-config/jiti-options.d.ts +9 -0
- package/dist/actions/get-config/jiti-options.d.ts.map +1 -0
- package/dist/actions/get-config.d.ts +13 -0
- package/dist/actions/get-config.d.ts.map +1 -0
- package/dist/actions/load-config-and-onboard.d.ts +9 -0
- package/dist/actions/load-config-and-onboard.d.ts.map +1 -0
- package/dist/actions/show-help-menu.d.ts +11 -0
- package/dist/actions/show-help-menu.d.ts.map +1 -0
- package/dist/commands/generate/actions/handle-existing-file.d.ts +7 -0
- package/dist/commands/generate/actions/handle-existing-file.d.ts.map +1 -0
- package/dist/commands/generate/actions/handle-new-file.d.ts +7 -0
- package/dist/commands/generate/actions/handle-new-file.d.ts.map +1 -0
- package/dist/commands/generate/actions/perform-write-action.d.ts +6 -0
- package/dist/commands/generate/actions/perform-write-action.d.ts.map +1 -0
- package/dist/commands/generate/generators/drizzle.d.ts +4 -0
- package/dist/commands/generate/generators/drizzle.d.ts.map +1 -0
- package/dist/commands/generate/generators/index.d.ts +19 -0
- package/dist/commands/generate/generators/index.d.ts.map +1 -0
- package/dist/commands/generate/generators/kysely.d.ts +11 -0
- package/dist/commands/generate/generators/kysely.d.ts.map +1 -0
- package/dist/commands/generate/generators/prisma.d.ts +3 -0
- package/dist/commands/generate/generators/prisma.d.ts.map +1 -0
- package/dist/commands/generate/generators/types.d.ts +13 -0
- package/dist/commands/generate/generators/types.d.ts.map +1 -0
- package/dist/commands/generate/schema.d.ts +10 -0
- package/dist/commands/generate/schema.d.ts.map +1 -0
- package/dist/commands/generate/setup.d.ts +13 -0
- package/dist/commands/generate/setup.d.ts.map +1 -0
- package/dist/commands/generate/write.d.ts +8 -0
- package/dist/commands/generate/write.d.ts.map +1 -0
- package/dist/commands/generate.d.ts +6 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/migrate/execute.d.ts +7 -0
- package/dist/commands/migrate/execute.d.ts.map +1 -0
- package/dist/commands/migrate/plan.d.ts +12 -0
- package/dist/commands/migrate/plan.d.ts.map +1 -0
- package/dist/commands/migrate/setup.d.ts +12 -0
- package/dist/commands/migrate/setup.d.ts.map +1 -0
- package/dist/commands/migrate.d.ts +3 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/components/intro.d.ts +9 -0
- package/dist/components/intro.d.ts.map +1 -0
- package/dist/context/config-management.d.ts +20 -0
- package/dist/context/config-management.d.ts.map +1 -0
- package/dist/context/creator.d.ts +11 -0
- package/dist/context/creator.d.ts.map +1 -0
- package/dist/context/error-handlers.d.ts +18 -0
- package/dist/context/error-handlers.d.ts.map +1 -0
- package/dist/context/file-system.d.ts +11 -0
- package/dist/context/file-system.d.ts.map +1 -0
- package/dist/context/parser.d.ts +11 -0
- package/dist/context/parser.d.ts.map +1 -0
- package/dist/context/types.d.ts +53 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/context/user-interaction.d.ts +14 -0
- package/dist/context/user-interaction.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +2002 -993
- package/dist/onboarding/dependencies.d.ts +20 -0
- package/dist/onboarding/dependencies.d.ts.map +1 -0
- package/dist/onboarding/detection.d.ts +33 -0
- package/dist/onboarding/detection.d.ts.map +1 -0
- package/dist/onboarding/index.d.ts +11 -0
- package/dist/onboarding/index.d.ts.map +1 -0
- package/dist/onboarding/storage-modes/c15t-mode.d.ts +22 -0
- package/dist/onboarding/storage-modes/c15t-mode.d.ts.map +1 -0
- package/dist/onboarding/storage-modes/custom-mode.d.ts +18 -0
- package/dist/onboarding/storage-modes/custom-mode.d.ts.map +1 -0
- package/dist/onboarding/storage-modes/index.d.ts +5 -0
- package/dist/onboarding/storage-modes/index.d.ts.map +1 -0
- package/dist/onboarding/storage-modes/offline-mode.d.ts +19 -0
- package/dist/onboarding/storage-modes/offline-mode.d.ts.map +1 -0
- package/dist/onboarding/storage-modes/self-hosted-mode.d.ts +22 -0
- package/dist/onboarding/storage-modes/self-hosted-mode.d.ts.map +1 -0
- package/dist/onboarding/templates.d.ts +30 -0
- package/dist/onboarding/templates.d.ts.map +1 -0
- package/dist/onboarding.d.ts +15 -0
- package/dist/onboarding.d.ts.map +1 -0
- package/dist/utils/capitalize-first-letter.d.ts +2 -0
- package/dist/utils/capitalize-first-letter.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +30 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/telemetry.d.ts +173 -0
- package/dist/utils/telemetry.d.ts.map +1 -0
- package/package.json +36 -31
package/dist/index.mjs
CHANGED
|
@@ -1,1058 +1,2067 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
function
|
|
22
|
-
|
|
23
|
-
return "";
|
|
24
|
-
}
|
|
25
|
-
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
2
|
+
import * as __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__ from "@clack/prompts";
|
|
3
|
+
import "dotenv/config";
|
|
4
|
+
import * as __WEBPACK_EXTERNAL_MODULE_open__ from "open";
|
|
5
|
+
import * as __WEBPACK_EXTERNAL_MODULE_picocolors__ from "picocolors";
|
|
6
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__ from "node:fs/promises";
|
|
7
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__ from "node:path";
|
|
8
|
+
import * as __WEBPACK_EXTERNAL_MODULE_c12__ from "c12";
|
|
9
|
+
import * as __WEBPACK_EXTERNAL_MODULE__doubletie_logger_91c58a8f__ from "@doubletie/logger";
|
|
10
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_crypto_9ba42079__ from "node:crypto";
|
|
11
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_os_74b4b876__ from "node:os";
|
|
12
|
+
import * as __WEBPACK_EXTERNAL_MODULE_posthog_node_1b07bdf4__ from "posthog-node";
|
|
13
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_child_process_27f17141__ from "node:child_process";
|
|
14
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_events_0a6aefe7__ from "node:events";
|
|
15
|
+
import * as __WEBPACK_EXTERNAL_MODULE_package_manager_detector_detect_94d6a9ae__ from "package-manager-detector/detect";
|
|
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";
|
|
19
|
+
import * as __WEBPACK_EXTERNAL_MODULE_figlet__ from "figlet";
|
|
20
|
+
import * as __WEBPACK_EXTERNAL_MODULE_fs_extra_ce68a66b__ from "fs-extra";
|
|
21
|
+
function isC15TOptions(obj) {
|
|
22
|
+
return 'object' == typeof obj && null !== obj && 'appName' in obj;
|
|
26
23
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
(
|
|
40
|
-
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
|
|
24
|
+
function isClientOptions(obj) {
|
|
25
|
+
return 'object' == typeof obj && null !== obj && ('mode' in obj || 'backendURL' in obj);
|
|
26
|
+
}
|
|
27
|
+
function tryGetFunctionResult(fn) {
|
|
28
|
+
if ('function' == typeof fn) try {
|
|
29
|
+
return fn();
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.warn('Error executing config function:', error);
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
function extractOptionsFromConfig(config) {
|
|
36
|
+
if (config.c15tConfig && isClientOptions(config.c15tConfig)) return config.c15tConfig;
|
|
37
|
+
if (config.c15tOptions && isClientOptions(config.c15tOptions)) return config.c15tOptions;
|
|
38
|
+
if (isClientOptions(config)) return config;
|
|
39
|
+
if (isC15TOptions(config.c15t)) return config.c15t;
|
|
40
|
+
if ('function' == typeof config.c15t) {
|
|
41
|
+
const result = tryGetFunctionResult(config.c15t);
|
|
42
|
+
if (isC15TOptions(result)) return result;
|
|
43
|
+
}
|
|
44
|
+
if (isC15TOptions(config.default)) return config.default;
|
|
45
|
+
if ('function' == typeof config.default) {
|
|
46
|
+
const result = tryGetFunctionResult(config.default);
|
|
47
|
+
if (isC15TOptions(result)) return result;
|
|
48
|
+
}
|
|
49
|
+
if (isC15TOptions(config.c15tInstance)) return config.c15tInstance;
|
|
50
|
+
if ('function' == typeof config.c15tInstance) {
|
|
51
|
+
const result = tryGetFunctionResult(config.c15tInstance);
|
|
52
|
+
if (isC15TOptions(result)) return result;
|
|
53
|
+
}
|
|
54
|
+
if (isC15TOptions(config.consent)) return config.consent;
|
|
55
|
+
if ('function' == typeof config.consent) {
|
|
56
|
+
const result = tryGetFunctionResult(config.consent);
|
|
57
|
+
if (isC15TOptions(result)) return result;
|
|
58
|
+
}
|
|
59
|
+
if ('object' == typeof config.c15t && null !== config.c15t && isC15TOptions(config.c15t.options)) return config.c15t.options;
|
|
60
|
+
if ('object' == typeof config.default && null !== config.default && isC15TOptions(config.default.options)) return config.default.options;
|
|
61
|
+
if ('object' == typeof config.c15tInstance && null !== config.c15tInstance && isC15TOptions(config.c15tInstance.options)) return config.c15tInstance.options;
|
|
62
|
+
if ('object' == typeof config.instance && null !== config.instance && isC15TOptions(config.instance.options)) return config.instance.options;
|
|
63
|
+
if ('object' == typeof config.consent && null !== config.consent && isC15TOptions(config.consent.options)) return config.consent.options;
|
|
64
|
+
if ('object' == typeof config.config && null !== config.config && isC15TOptions(config.config.options)) return config.config.options;
|
|
65
|
+
console.debug('No valid configuration found in any of the expected locations');
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const configFileNames = [
|
|
69
|
+
'c15t.config',
|
|
70
|
+
'c15t.backend',
|
|
71
|
+
'c15t',
|
|
72
|
+
'c15t.client',
|
|
73
|
+
'consent.config',
|
|
74
|
+
'consent.backend',
|
|
75
|
+
'consent',
|
|
76
|
+
'cmp.config',
|
|
77
|
+
'cmp.backend',
|
|
78
|
+
'cmp'
|
|
79
|
+
];
|
|
80
|
+
const constants_extensions = [
|
|
81
|
+
'.js',
|
|
82
|
+
'.jsx',
|
|
83
|
+
'.ts',
|
|
84
|
+
'.tsx',
|
|
85
|
+
'.cjs',
|
|
86
|
+
'.cts',
|
|
87
|
+
'.mjs',
|
|
88
|
+
'.mts',
|
|
89
|
+
'.server.cjs',
|
|
90
|
+
'.server.cts',
|
|
91
|
+
'.server.js',
|
|
92
|
+
'.server.jsx',
|
|
93
|
+
'.server.mjs',
|
|
94
|
+
'.server.mts',
|
|
95
|
+
'.server.ts',
|
|
96
|
+
'.server.tsx'
|
|
97
|
+
];
|
|
98
|
+
let possiblePaths = configFileNames.flatMap((name)=>constants_extensions.map((ext)=>`${name}${ext}`));
|
|
99
|
+
const directories = [
|
|
100
|
+
'',
|
|
101
|
+
'lib/server/',
|
|
102
|
+
'server/',
|
|
103
|
+
'lib/',
|
|
104
|
+
'utils/',
|
|
105
|
+
'config/',
|
|
106
|
+
'src/',
|
|
107
|
+
'app/'
|
|
108
|
+
];
|
|
109
|
+
possiblePaths = directories.flatMap((dir)=>possiblePaths.map((file)=>`${dir}${file}`));
|
|
110
|
+
const jitiOptions = (context, cwd)=>{
|
|
111
|
+
const alias = context.config.getPathAliases(cwd) || {};
|
|
112
|
+
return {
|
|
113
|
+
extensions: [
|
|
114
|
+
'.ts',
|
|
115
|
+
'.tsx',
|
|
116
|
+
'.js',
|
|
117
|
+
'.jsx',
|
|
118
|
+
'.mjs',
|
|
119
|
+
'.cjs',
|
|
120
|
+
'.mts',
|
|
121
|
+
'.cts'
|
|
122
|
+
],
|
|
123
|
+
alias
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
async function getConfig(contextOrOptions) {
|
|
127
|
+
const context = 'logger' in contextOrOptions ? contextOrOptions : {
|
|
128
|
+
...contextOrOptions,
|
|
129
|
+
logger: {
|
|
130
|
+
debug: console.debug,
|
|
131
|
+
info: console.info,
|
|
132
|
+
warn: console.warn,
|
|
133
|
+
error: console.error
|
|
134
|
+
},
|
|
135
|
+
flags: {
|
|
136
|
+
config: contextOrOptions.configPath
|
|
137
|
+
},
|
|
138
|
+
error: {
|
|
139
|
+
handleError: (error)=>{
|
|
140
|
+
console.error('Error loading configuration:', error);
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
57
143
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
if (!typeMap[type]) {
|
|
94
|
-
return `text('${snakeCaseName}')`;
|
|
144
|
+
};
|
|
145
|
+
const { cwd, logger, flags } = context;
|
|
146
|
+
const configPath = flags.config;
|
|
147
|
+
let foundConfigPath = null;
|
|
148
|
+
try {
|
|
149
|
+
let options = null;
|
|
150
|
+
const customJitiOptions = jitiOptions(context, cwd);
|
|
151
|
+
if (configPath) {
|
|
152
|
+
foundConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].resolve(cwd, configPath);
|
|
153
|
+
logger.debug(`Using explicitly provided config path: ${foundConfigPath}`);
|
|
154
|
+
} else {
|
|
155
|
+
const prioritizedDirs = [
|
|
156
|
+
cwd,
|
|
157
|
+
__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, 'packages/cli')
|
|
158
|
+
];
|
|
159
|
+
const primaryName = 'c15t.config';
|
|
160
|
+
const extensions = [
|
|
161
|
+
'.ts',
|
|
162
|
+
'.js',
|
|
163
|
+
'.mjs'
|
|
164
|
+
];
|
|
165
|
+
for (const dir of prioritizedDirs){
|
|
166
|
+
for (const ext of extensions){
|
|
167
|
+
const checkPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(dir, `${primaryName}${ext}`);
|
|
168
|
+
try {
|
|
169
|
+
await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].access(checkPath);
|
|
170
|
+
foundConfigPath = checkPath;
|
|
171
|
+
logger.debug(`Found config via manual check: ${foundConfigPath}`);
|
|
172
|
+
break;
|
|
173
|
+
} catch {}
|
|
174
|
+
}
|
|
175
|
+
if (foundConfigPath) break;
|
|
176
|
+
}
|
|
95
177
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
178
|
+
if (foundConfigPath) try {
|
|
179
|
+
logger.debug(`Loading configuration from resolved path: ${foundConfigPath}`);
|
|
180
|
+
const result = await (0, __WEBPACK_EXTERNAL_MODULE_c12__.loadConfig)({
|
|
181
|
+
configFile: foundConfigPath,
|
|
182
|
+
jitiOptions: customJitiOptions
|
|
183
|
+
});
|
|
184
|
+
logger.debug('Raw config loading result:', result);
|
|
185
|
+
if (result.config) {
|
|
186
|
+
logger.debug('Trying to extract config from result.config');
|
|
187
|
+
options = extractOptionsFromConfig(result.config);
|
|
188
|
+
}
|
|
189
|
+
if (options) {
|
|
190
|
+
logger.debug('Extracted config:', options);
|
|
191
|
+
if (isC15TOptions(options) || isClientOptions(options)) {
|
|
192
|
+
logger.debug('Configuration validated successfully.');
|
|
193
|
+
return options;
|
|
194
|
+
}
|
|
195
|
+
logger.debug('Loaded config does not match expected schema');
|
|
196
|
+
} else logger.debug('No configuration extracted from loaded file');
|
|
197
|
+
logger.debug('Raw loaded configuration:', result);
|
|
198
|
+
return null;
|
|
199
|
+
} catch (error) {
|
|
200
|
+
logger.debug('Error loading config from explicit path:', error);
|
|
201
|
+
try {
|
|
202
|
+
logger.debug(`Trying to require module directly: ${foundConfigPath}`);
|
|
203
|
+
const importedModule = await import(foundConfigPath);
|
|
204
|
+
logger.debug('Directly imported module:', importedModule);
|
|
205
|
+
const extracted = extractOptionsFromConfig(importedModule);
|
|
206
|
+
if (extracted && (isC15TOptions(extracted) || isClientOptions(extracted))) {
|
|
207
|
+
logger.debug('Found valid config through direct import');
|
|
208
|
+
return extracted;
|
|
209
|
+
}
|
|
210
|
+
} catch (importError) {
|
|
211
|
+
logger.debug('Error importing module directly:', importError);
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
118
214
|
}
|
|
119
|
-
return
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
215
|
+
return options;
|
|
216
|
+
} catch (error) {
|
|
217
|
+
if ('error' in context && context.error && 'function' == typeof context.error.handleError) return context.error.handleError(error, 'Error loading configuration');
|
|
218
|
+
console.error('Error loading configuration:', error);
|
|
219
|
+
return null;
|
|
123
220
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
const PRIMARY_KEY_REGEX = /\bprimary key\b/gi;
|
|
136
|
-
const REFERENCES_REGEX = /\breferences\b/gi;
|
|
137
|
-
const UNIQUE_REGEX = /\bunique\b/gi;
|
|
138
|
-
const CREATE_TABLE_KEYWORD_REGEX = /\bcreate\s+table\b/gi;
|
|
139
|
-
const CREATE_INDEX_KEYWORD_REGEX = /\bcreate\s+index\b/gi;
|
|
140
|
-
const ALTER_TABLE_REGEX = /\balter\s+table\b/gi;
|
|
141
|
-
const INSERT_INTO_REGEX = /\binsert\s+into\b/gi;
|
|
142
|
-
const UPDATE_REGEX = /\bupdate\b/gi;
|
|
143
|
-
const DELETE_FROM_REGEX = /\bdelete\s+from\b/gi;
|
|
144
|
-
const SELECT_REGEX = /\bselect\b/gi;
|
|
145
|
-
const FROM_REGEX = /\bfrom\b/gi;
|
|
146
|
-
const WHERE_REGEX = /\bwhere\b/gi;
|
|
147
|
-
const JOIN_REGEX = /\bjoin\b/gi;
|
|
148
|
-
const ON_REGEX = /\bon\b/gi;
|
|
149
|
-
const AND_REGEX = /\band\b/gi;
|
|
150
|
-
const OR_REGEX = /\bor\b/gi;
|
|
151
|
-
const BOOLEAN_FIELD_REGEX = /("is[A-Z][a-zA-Z0-9]*")\s+integer/g;
|
|
152
|
-
const DATE_FIELD_REGEX = /("(?:created|updated|expires)At")\s+date/gi;
|
|
153
|
-
const TEXT_FIELD_REGEX = /("(?:name|code|description|id)")\s+text/gi;
|
|
154
|
-
const JSON_FIELD_REGEX = /("(?:metadata|config|data|settings|options|preferences|attributes)")\s+text/gi;
|
|
155
|
-
function formatSQL(sql, databaseType = "sqlite", options) {
|
|
156
|
-
const dbType = databaseType === "pg" ? "postgresql" : databaseType;
|
|
157
|
-
const statements = sql.split(";").filter((stmt) => stmt.trim());
|
|
158
|
-
const rollbackStatements = [];
|
|
159
|
-
const formattedStatements = statements.map((statement) => {
|
|
160
|
-
const trimmedStmt = statement.trim().toLowerCase();
|
|
161
|
-
if (trimmedStmt.startsWith("create table")) {
|
|
162
|
-
const match = statement.match(CREATE_TABLE_REGEX);
|
|
163
|
-
if (match) {
|
|
164
|
-
const [_, tableName, columnsStr] = match;
|
|
165
|
-
rollbackStatements.unshift(`DROP TABLE IF EXISTS "${tableName}"`);
|
|
166
|
-
const columns = columnsStr.split(",").map((col) => col.trim());
|
|
167
|
-
const formattedColumns = columns.map((col) => {
|
|
168
|
-
let formattedCol = col.replace(NOT_NULL_REGEX, "NOT NULL").replace(PRIMARY_KEY_REGEX, "PRIMARY KEY").replace(REFERENCES_REGEX, "REFERENCES").replace(UNIQUE_REGEX, "UNIQUE");
|
|
169
|
-
if (dbType === "postgresql") {
|
|
170
|
-
formattedCol = formattedCol.replace(BOOLEAN_FIELD_REGEX, "$1 boolean").replace(DATE_FIELD_REGEX, "$1 timestamp with time zone").replace(TEXT_FIELD_REGEX, "$1 varchar(255)").replace(JSON_FIELD_REGEX, "$1 jsonb");
|
|
171
|
-
} else if (dbType === "mysql") {
|
|
172
|
-
formattedCol = formattedCol.replace(BOOLEAN_FIELD_REGEX, "$1 TINYINT(1)").replace(DATE_FIELD_REGEX, "$1 DATETIME").replace(TEXT_FIELD_REGEX, "$1 VARCHAR(255)").replace(JSON_FIELD_REGEX, "$1 JSON");
|
|
173
|
-
} else if (dbType === "sqlite") {
|
|
174
|
-
formattedCol = formattedCol.replace(
|
|
175
|
-
JSON_FIELD_REGEX,
|
|
176
|
-
"$1 text -- stored as JSON"
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
return formattedCol;
|
|
180
|
-
}).map((col) => ` ${col}`).join(",\n");
|
|
181
|
-
return `CREATE TABLE IF NOT EXISTS "${tableName}" (
|
|
182
|
-
${formattedColumns}
|
|
183
|
-
);`;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
if (trimmedStmt.startsWith("create index")) {
|
|
187
|
-
const indexMatch = statement.match(CREATE_INDEX_REGEX);
|
|
188
|
-
if (indexMatch) {
|
|
189
|
-
const [_, indexName] = indexMatch;
|
|
190
|
-
rollbackStatements.unshift(`DROP INDEX IF EXISTS "${indexName}"`);
|
|
191
|
-
return `CREATE INDEX IF NOT EXISTS "${indexName}" ${statement.substring(statement.toLowerCase().indexOf("on")).trim()};`;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return `${statement.trim().replace(CREATE_TABLE_KEYWORD_REGEX, "CREATE TABLE").replace(CREATE_INDEX_KEYWORD_REGEX, "CREATE INDEX").replace(ALTER_TABLE_REGEX, "ALTER TABLE").replace(INSERT_INTO_REGEX, "INSERT INTO").replace(UPDATE_REGEX, "UPDATE").replace(DELETE_FROM_REGEX, "DELETE FROM").replace(SELECT_REGEX, "SELECT").replace(FROM_REGEX, "FROM").replace(WHERE_REGEX, "WHERE").replace(JOIN_REGEX, "JOIN").replace(ON_REGEX, "ON").replace(AND_REGEX, "AND").replace(OR_REGEX, "OR")};`;
|
|
195
|
-
}).join("\n\n");
|
|
196
|
-
const useTransactions = dbType !== "d1";
|
|
197
|
-
const transactionStart = useTransactions ? dbType === "mysql" ? "START TRANSACTION;" : "BEGIN;" : "";
|
|
198
|
-
const transactionEnd = useTransactions ? "COMMIT;" : "";
|
|
199
|
-
const timestamp = options?.timestamp || (/* @__PURE__ */ new Date()).toISOString();
|
|
200
|
-
return `-- Migration generated by C15T (${timestamp})
|
|
201
|
-
-- Database type: ${dbType}
|
|
202
|
-
-- Description: Automatically generated schema migration
|
|
203
|
-
--
|
|
204
|
-
-- Wrapped in a transaction for atomicity
|
|
205
|
-
-- To roll back this migration, use the ROLLBACK section below
|
|
221
|
+
}
|
|
222
|
+
function showHelpMenu(context, version, commands, flags) {
|
|
223
|
+
const { logger } = context;
|
|
224
|
+
logger.debug('Displaying help menu using command and flag structures.');
|
|
225
|
+
const commandLines = commands.map((cmd)=>` ${cmd.name.padEnd(10)} ${cmd.description}`).join('\n');
|
|
226
|
+
const optionLines = flags.map((flag)=>{
|
|
227
|
+
const names = flag.names.join(', ');
|
|
228
|
+
const valuePlaceholder = flag.expectsValue ? ' <value>' : '';
|
|
229
|
+
return ` ${(names + valuePlaceholder).padEnd(20)} ${flag.description}`;
|
|
230
|
+
}).join('\n');
|
|
231
|
+
const helpContent = `c15t CLI version ${version}
|
|
206
232
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
${formattedStatements}
|
|
210
|
-
${transactionEnd}
|
|
233
|
+
Available Commands:
|
|
234
|
+
${commandLines}
|
|
211
235
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
/*
|
|
215
|
-
${transactionStart}
|
|
236
|
+
Options:
|
|
237
|
+
${optionLines}
|
|
216
238
|
|
|
217
|
-
${
|
|
239
|
+
Run a command directly (e.g., ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('c15t generate')}) or select one interactively when no command is provided.
|
|
218
240
|
|
|
219
|
-
|
|
220
|
-
|
|
241
|
+
For more help, visit: https://c15t.dev`;
|
|
242
|
+
logger.debug('Help menu content generated.');
|
|
243
|
+
logger.note(helpContent, 'Usage');
|
|
221
244
|
}
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
databaseType = adapter.options.provider;
|
|
232
|
-
} else if (options.database && "options" in options.database && options.database.options && typeof options.database.options === "object" && "provider" in options.database.options) {
|
|
233
|
-
databaseType = options.database.options.provider;
|
|
234
|
-
}
|
|
235
|
-
const isTest = process.env.NODE_ENV === "test" || file?.includes("test");
|
|
236
|
-
const testTimestamp = options?._testTimestamp;
|
|
237
|
-
const formatOptions = {
|
|
238
|
-
timestamp: testTimestamp || (isTest ? "2023-01-01T00:00:00.000Z" : void 0)
|
|
239
|
-
};
|
|
240
|
-
const formattedMigrations = formatSQL(
|
|
241
|
-
migrations,
|
|
242
|
-
databaseType,
|
|
243
|
-
formatOptions
|
|
244
|
-
);
|
|
245
|
-
const generatedFileName = file || `./c15t_migrations/${Date.now()}_create_tables.sql`;
|
|
246
|
-
return {
|
|
247
|
-
code: formattedMigrations,
|
|
248
|
-
fileName: generatedFileName
|
|
249
|
-
};
|
|
245
|
+
const validLogLevels = [
|
|
246
|
+
'error',
|
|
247
|
+
'warn',
|
|
248
|
+
'info',
|
|
249
|
+
'debug'
|
|
250
|
+
];
|
|
251
|
+
const formatArgs = (args)=>{
|
|
252
|
+
if (0 === args.length) return '';
|
|
253
|
+
return `\n${args.map((arg)=>` - ${JSON.stringify(arg, null, 2)}`).join('\n')}`;
|
|
250
254
|
};
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
} else {
|
|
272
|
-
schemaPrisma = getNewPrisma(provider);
|
|
273
|
-
}
|
|
274
|
-
const manyToManyRelations = /* @__PURE__ */ new Map();
|
|
275
|
-
for (const table in tables) {
|
|
276
|
-
if (Object.hasOwn(tables, table)) {
|
|
277
|
-
const fields = tables[table]?.fields;
|
|
278
|
-
for (const field in fields) {
|
|
279
|
-
if (Object.hasOwn(fields, field)) {
|
|
280
|
-
const attr = fields[field];
|
|
281
|
-
if (attr?.references) {
|
|
282
|
-
const referencedModel = capitalizeFirstLetter(
|
|
283
|
-
attr.references.model
|
|
284
|
-
);
|
|
285
|
-
if (!manyToManyRelations.has(referencedModel)) {
|
|
286
|
-
manyToManyRelations.set(referencedModel, /* @__PURE__ */ new Set());
|
|
255
|
+
const formatLogMessage = (logLevel, message, args = [])=>{
|
|
256
|
+
const messageStr = 'string' == typeof message ? message : String(message);
|
|
257
|
+
const formattedArgs = formatArgs(args);
|
|
258
|
+
switch(logLevel){
|
|
259
|
+
case 'error':
|
|
260
|
+
return `${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].bgRed(__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].black(' error '))} ${messageStr}${formattedArgs}`;
|
|
261
|
+
case 'warn':
|
|
262
|
+
return `${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].bgYellow(__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].black(' warning '))} ${messageStr}${formattedArgs}`;
|
|
263
|
+
case 'info':
|
|
264
|
+
return `${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].bgGreen(__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].black(' info '))} ${messageStr}${formattedArgs}`;
|
|
265
|
+
case 'debug':
|
|
266
|
+
return `${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].bgBlack(__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].white(' debug '))} ${messageStr}${formattedArgs}`;
|
|
267
|
+
case 'success':
|
|
268
|
+
return `${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].bgGreen(__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].white(' success '))} ${messageStr}${formattedArgs}`;
|
|
269
|
+
case 'failed':
|
|
270
|
+
return `${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].bgRed(__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].white(' failed '))} ${messageStr}${formattedArgs}`;
|
|
271
|
+
default:
|
|
272
|
+
{
|
|
273
|
+
const levelStr = logLevel;
|
|
274
|
+
return `[${levelStr.toUpperCase()}] ${messageStr}${formattedArgs}`;
|
|
287
275
|
}
|
|
288
|
-
manyToManyRelations.get(referencedModel).add(capitalizeFirstLetter(table));
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
276
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
277
|
+
};
|
|
278
|
+
const logMessage = (logLevel, message, ...args)=>{
|
|
279
|
+
const formattedMessage = formatLogMessage(logLevel, message, args);
|
|
280
|
+
switch(logLevel){
|
|
281
|
+
case 'error':
|
|
282
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.log.error(formattedMessage);
|
|
283
|
+
break;
|
|
284
|
+
case 'warn':
|
|
285
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.log.warn(formattedMessage);
|
|
286
|
+
break;
|
|
287
|
+
case 'info':
|
|
288
|
+
case 'debug':
|
|
289
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.log.info(formattedMessage);
|
|
290
|
+
break;
|
|
291
|
+
case 'success':
|
|
292
|
+
case 'failed':
|
|
293
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.outro(formattedMessage);
|
|
294
|
+
break;
|
|
295
|
+
default:
|
|
296
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.log.message(formattedMessage);
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
const createCliLogger = (level)=>{
|
|
300
|
+
const baseLogger = (0, __WEBPACK_EXTERNAL_MODULE__doubletie_logger_91c58a8f__.createLogger)({
|
|
301
|
+
level,
|
|
302
|
+
appName: 'c15t',
|
|
303
|
+
log: (logLevel, message, ...args)=>{
|
|
304
|
+
logMessage(logLevel, message, ...args);
|
|
300
305
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
306
|
+
});
|
|
307
|
+
const extendedLogger = baseLogger;
|
|
308
|
+
extendedLogger.message = (message)=>{
|
|
309
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.log.message(message);
|
|
310
|
+
};
|
|
311
|
+
extendedLogger.note = (message, ...args)=>{
|
|
312
|
+
const messageStr = 'string' == typeof message ? message : String(message);
|
|
313
|
+
const title = args.length > 0 && 'string' == typeof args[0] ? args[0] : void 0;
|
|
314
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.note(messageStr, title, {
|
|
315
|
+
format: (line)=>line
|
|
316
|
+
});
|
|
317
|
+
};
|
|
318
|
+
extendedLogger.success = (message, ...args)=>{
|
|
319
|
+
logMessage('success', message, ...args);
|
|
320
|
+
};
|
|
321
|
+
extendedLogger.failed = (message, ...args)=>{
|
|
322
|
+
logMessage('failed', message, ...args);
|
|
323
|
+
};
|
|
324
|
+
extendedLogger.outro = (message)=>{
|
|
325
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.outro(message);
|
|
326
|
+
};
|
|
327
|
+
return extendedLogger;
|
|
328
|
+
};
|
|
329
|
+
const TELEMETRY_DISABLED_ENV = 'C15T_TELEMETRY_DISABLED';
|
|
330
|
+
var telemetry_TelemetryEventName = /*#__PURE__*/ function(TelemetryEventName) {
|
|
331
|
+
TelemetryEventName["CLI_INVOKED"] = "cli.invoked";
|
|
332
|
+
TelemetryEventName["CLI_COMPLETED"] = "cli.completed";
|
|
333
|
+
TelemetryEventName["CLI_EXITED"] = "cli.exited";
|
|
334
|
+
TelemetryEventName["CLI_ENVIRONMENT_DETECTED"] = "cli.environment_detected";
|
|
335
|
+
TelemetryEventName["COMMAND_EXECUTED"] = "command.executed";
|
|
336
|
+
TelemetryEventName["COMMAND_SUCCEEDED"] = "command.succeeded";
|
|
337
|
+
TelemetryEventName["COMMAND_FAILED"] = "command.failed";
|
|
338
|
+
TelemetryEventName["COMMAND_UNKNOWN"] = "command.unknown";
|
|
339
|
+
TelemetryEventName["INTERACTIVE_MENU_OPENED"] = "ui.menu.opened";
|
|
340
|
+
TelemetryEventName["INTERACTIVE_MENU_EXITED"] = "ui.menu.exited";
|
|
341
|
+
TelemetryEventName["CONFIG_LOADED"] = "config.loaded";
|
|
342
|
+
TelemetryEventName["CONFIG_ERROR"] = "config.error";
|
|
343
|
+
TelemetryEventName["CONFIG_UPDATED"] = "config.updated";
|
|
344
|
+
TelemetryEventName["HELP_DISPLAYED"] = "help.displayed";
|
|
345
|
+
TelemetryEventName["VERSION_DISPLAYED"] = "version.displayed";
|
|
346
|
+
TelemetryEventName["ONBOARDING_STARTED"] = "onboarding.started";
|
|
347
|
+
TelemetryEventName["ONBOARDING_COMPLETED"] = "onboarding.completed";
|
|
348
|
+
TelemetryEventName["ONBOARDING_EXITED"] = "onboarding.exited";
|
|
349
|
+
TelemetryEventName["ONBOARDING_STORAGE_MODE_SELECTED"] = "onboarding.storage_mode_selected";
|
|
350
|
+
TelemetryEventName["ONBOARDING_C15T_MODE_CONFIGURED"] = "onboarding.c15t_mode_configured";
|
|
351
|
+
TelemetryEventName["ONBOARDING_OFFLINE_MODE_CONFIGURED"] = "onboarding.offline_mode_configured";
|
|
352
|
+
TelemetryEventName["ONBOARDING_SELF_HOSTED_CONFIGURED"] = "onboarding.self_hosted_configured";
|
|
353
|
+
TelemetryEventName["ONBOARDING_CUSTOM_MODE_CONFIGURED"] = "onboarding.custom_mode_configured";
|
|
354
|
+
TelemetryEventName["ONBOARDING_DEPENDENCIES_CHOICE"] = "onboarding.dependencies_choice";
|
|
355
|
+
TelemetryEventName["ONBOARDING_DEPENDENCIES_INSTALLED"] = "onboarding.dependencies_installed";
|
|
356
|
+
TelemetryEventName["ONBOARDING_GITHUB_STAR"] = "onboarding.github_star";
|
|
357
|
+
TelemetryEventName["ERROR_OCCURRED"] = "error.occurred";
|
|
358
|
+
TelemetryEventName["MIGRATION_STARTED"] = "migration.started";
|
|
359
|
+
TelemetryEventName["MIGRATION_PLANNED"] = "migration.planned";
|
|
360
|
+
TelemetryEventName["MIGRATION_EXECUTED"] = "migration.executed";
|
|
361
|
+
TelemetryEventName["MIGRATION_COMPLETED"] = "migration.completed";
|
|
362
|
+
TelemetryEventName["MIGRATION_FAILED"] = "migration.failed";
|
|
363
|
+
TelemetryEventName["GENERATE_STARTED"] = "generate.started";
|
|
364
|
+
TelemetryEventName["GENERATE_COMPLETED"] = "generate.completed";
|
|
365
|
+
TelemetryEventName["GENERATE_FAILED"] = "generate.failed";
|
|
366
|
+
return TelemetryEventName;
|
|
367
|
+
}({});
|
|
368
|
+
class Telemetry {
|
|
369
|
+
client = null;
|
|
370
|
+
disabled;
|
|
371
|
+
defaultProperties;
|
|
372
|
+
distinctId;
|
|
373
|
+
apiKey = 'phc_ViY5LtTmh4kqoumXZB2olPFoTz4AbbDfrogNgFi1MH3';
|
|
374
|
+
debug = false;
|
|
375
|
+
logger;
|
|
376
|
+
constructor(options){
|
|
377
|
+
const envDisabled = '1' === process.env[TELEMETRY_DISABLED_ENV] || process.env[TELEMETRY_DISABLED_ENV]?.toLowerCase() === 'true';
|
|
378
|
+
const hasValidApiKey = !!(this.apiKey && '' !== this.apiKey.trim());
|
|
379
|
+
this.disabled = options?.disabled ?? envDisabled ?? !hasValidApiKey;
|
|
380
|
+
this.defaultProperties = options?.defaultProperties ?? {};
|
|
381
|
+
this.logger = options?.logger;
|
|
382
|
+
this.distinctId = this.generateAnonymousId();
|
|
383
|
+
if (this.disabled) {
|
|
384
|
+
if (!hasValidApiKey) this.logDebug('Telemetry disabled: No API key provided');
|
|
385
|
+
} else this.initClient(options?.client);
|
|
386
|
+
}
|
|
387
|
+
trackEventSync(eventName, properties = {}) {
|
|
388
|
+
if (this.disabled || !this.client) {
|
|
389
|
+
if (this.debug) this.logDebug('Telemetry disabled or client not initialized');
|
|
390
|
+
return;
|
|
338
391
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
392
|
+
const safeProperties = {};
|
|
393
|
+
for (const [key, value] of Object.entries(properties))if ('config' !== key && void 0 !== value) safeProperties[key] = value;
|
|
394
|
+
if (this.debug) this.logDebug(`Sending telemetry event: ${eventName}`);
|
|
395
|
+
try {
|
|
396
|
+
this.client.capture({
|
|
397
|
+
distinctId: this.distinctId,
|
|
398
|
+
event: eventName,
|
|
399
|
+
properties: {
|
|
400
|
+
...this.defaultProperties,
|
|
401
|
+
...safeProperties,
|
|
402
|
+
timestamp: new Date().toISOString()
|
|
403
|
+
}
|
|
345
404
|
});
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
405
|
+
this.client.flush();
|
|
406
|
+
if (this.debug) this.logDebug(`Flushed telemetry event: ${eventName}`);
|
|
407
|
+
} catch (error) {
|
|
408
|
+
if (this.debug) this.logDebug(`Error sending telemetry: ${error}`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
trackEvent(eventName, properties = {}) {
|
|
412
|
+
this.trackEventSync(eventName, properties);
|
|
413
|
+
}
|
|
414
|
+
trackCommand(command, args = [], flags = {}) {
|
|
415
|
+
if (this.disabled || !this.client) return;
|
|
416
|
+
const safeFlags = {};
|
|
417
|
+
for (const [key, value] of Object.entries(flags))if ('config' !== key && void 0 !== value) safeFlags[key] = value;
|
|
418
|
+
this.trackEvent("command.executed", {
|
|
419
|
+
command,
|
|
420
|
+
args: args.join(' '),
|
|
421
|
+
flagsData: JSON.stringify(safeFlags)
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
trackError(error, command) {
|
|
425
|
+
if (this.disabled || !this.client) return;
|
|
426
|
+
this.trackEvent("error.occurred", {
|
|
427
|
+
command,
|
|
428
|
+
error: error.message,
|
|
429
|
+
errorName: error.name,
|
|
430
|
+
stack: 'development' === process.env.NODE_ENV ? error.stack : void 0
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
setLogLevel(level) {
|
|
434
|
+
if (this.client && 'debug' === level) {
|
|
435
|
+
this.debug = true;
|
|
436
|
+
this.client.debug(true);
|
|
437
|
+
this.logDebug('Telemetry debug mode enabled');
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
disable() {
|
|
441
|
+
this.disabled = true;
|
|
442
|
+
}
|
|
443
|
+
enable() {
|
|
444
|
+
this.disabled = false;
|
|
445
|
+
if (!this.client) this.initClient();
|
|
446
|
+
}
|
|
447
|
+
isDisabled() {
|
|
448
|
+
return this.disabled;
|
|
449
|
+
}
|
|
450
|
+
async shutdown() {
|
|
451
|
+
if (this.client) {
|
|
452
|
+
await this.client.shutdown();
|
|
453
|
+
this.client = null;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
setLogger(logger) {
|
|
457
|
+
this.logger = logger;
|
|
458
|
+
}
|
|
459
|
+
logDebug(message, ...args) {
|
|
460
|
+
if (this.logger) this.logger.debug(message, ...args);
|
|
461
|
+
else console.debug(message, ...args);
|
|
462
|
+
}
|
|
463
|
+
initClient(customClient) {
|
|
464
|
+
if (customClient) {
|
|
465
|
+
this.client = customClient;
|
|
466
|
+
if (this.debug) this.logDebug('Using custom PostHog client');
|
|
467
|
+
} else {
|
|
468
|
+
if (!this.apiKey || '' === this.apiKey.trim()) {
|
|
469
|
+
this.disabled = true;
|
|
470
|
+
this.logDebug('Telemetry disabled: No API key provided');
|
|
471
|
+
return;
|
|
363
472
|
}
|
|
364
|
-
|
|
365
|
-
|
|
473
|
+
const startTime = Date.now();
|
|
474
|
+
try {
|
|
475
|
+
const clientConfig = {
|
|
476
|
+
host: 'https://eu.i.posthog.com',
|
|
477
|
+
flushInterval: 0,
|
|
478
|
+
flushAt: 1,
|
|
479
|
+
requestTimeout: 3000
|
|
480
|
+
};
|
|
481
|
+
if (this.debug) this.logDebug('Initializing PostHog client with config:', JSON.stringify(clientConfig));
|
|
482
|
+
this.client = new __WEBPACK_EXTERNAL_MODULE_posthog_node_1b07bdf4__.PostHog(this.apiKey, clientConfig);
|
|
483
|
+
const initTime = Date.now() - startTime;
|
|
484
|
+
if (this.debug) this.logDebug('PostHog client initialized in', initTime, 'ms');
|
|
485
|
+
} catch (error) {
|
|
486
|
+
this.disabled = true;
|
|
487
|
+
const errorDetails = error instanceof Error ? {
|
|
488
|
+
message: error.message,
|
|
489
|
+
name: error.name,
|
|
490
|
+
stack: error.stack
|
|
491
|
+
} : {
|
|
492
|
+
rawError: String(error)
|
|
493
|
+
};
|
|
494
|
+
if (this.debug) this.logDebug('Telemetry disabled due to initialization error:', JSON.stringify(errorDetails, null, 2));
|
|
495
|
+
try {
|
|
496
|
+
if (this.debug) this.logDebug('Attempting fallback PostHog initialization');
|
|
497
|
+
this.client = new __WEBPACK_EXTERNAL_MODULE_posthog_node_1b07bdf4__.PostHog(this.apiKey);
|
|
498
|
+
this.disabled = false;
|
|
499
|
+
if (this.debug) this.logDebug('PostHog client initialized using fallback method');
|
|
500
|
+
} catch (fallbackError) {
|
|
501
|
+
this.logDebug('Fallback initialization also failed:', fallbackError instanceof Error ? fallbackError.message : String(fallbackError));
|
|
502
|
+
}
|
|
366
503
|
}
|
|
367
|
-
}
|
|
368
504
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
505
|
+
}
|
|
506
|
+
generateAnonymousId() {
|
|
507
|
+
const machineId = __WEBPACK_EXTERNAL_MODULE_node_crypto_9ba42079__["default"].createHash('sha256').update(__WEBPACK_EXTERNAL_MODULE_node_os_74b4b876__["default"].hostname() + __WEBPACK_EXTERNAL_MODULE_node_os_74b4b876__["default"].platform() + __WEBPACK_EXTERNAL_MODULE_node_os_74b4b876__["default"].arch() + __WEBPACK_EXTERNAL_MODULE_node_os_74b4b876__["default"].totalmem()).digest('hex');
|
|
508
|
+
return machineId;
|
|
509
|
+
}
|
|
510
|
+
flushSync() {
|
|
511
|
+
if (this.disabled || !this.client) return;
|
|
512
|
+
try {
|
|
513
|
+
this.client.flush();
|
|
514
|
+
if (this.debug) this.logDebug('Manually flushed telemetry events');
|
|
515
|
+
} catch (error) {
|
|
516
|
+
if (this.debug) this.logDebug(`Error flushing telemetry: ${error}`);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
function createTelemetry(options) {
|
|
521
|
+
return new Telemetry(options);
|
|
522
|
+
}
|
|
523
|
+
async function addAndInstallDependenciesViaPM(projectRoot, dependencies, packageManager) {
|
|
524
|
+
const depsToAdd = dependencies.map((dep)=>`${dep}`);
|
|
525
|
+
if (0 === depsToAdd.length) return;
|
|
526
|
+
let command = '';
|
|
527
|
+
let args = [];
|
|
528
|
+
switch(packageManager){
|
|
529
|
+
case 'npm':
|
|
530
|
+
command = 'npm';
|
|
531
|
+
args = [
|
|
532
|
+
'install',
|
|
533
|
+
...depsToAdd
|
|
534
|
+
];
|
|
535
|
+
break;
|
|
536
|
+
case 'yarn':
|
|
537
|
+
command = 'yarn';
|
|
538
|
+
args = [
|
|
539
|
+
'add',
|
|
540
|
+
...depsToAdd
|
|
541
|
+
];
|
|
542
|
+
break;
|
|
543
|
+
case 'pnpm':
|
|
544
|
+
command = 'pnpm';
|
|
545
|
+
args = [
|
|
546
|
+
'add',
|
|
547
|
+
...depsToAdd
|
|
548
|
+
];
|
|
549
|
+
break;
|
|
550
|
+
default:
|
|
551
|
+
throw new Error(`Unsupported package manager for dependency addition: ${packageManager}`);
|
|
552
|
+
}
|
|
553
|
+
const child = (0, __WEBPACK_EXTERNAL_MODULE_node_child_process_27f17141__.spawn)(command, args, {
|
|
554
|
+
cwd: projectRoot,
|
|
555
|
+
stdio: 'inherit'
|
|
556
|
+
});
|
|
557
|
+
await (0, __WEBPACK_EXTERNAL_MODULE_node_events_0a6aefe7__.once)(child, 'exit');
|
|
558
|
+
}
|
|
559
|
+
function getManualInstallCommand(dependencies, packageManager) {
|
|
560
|
+
const depsToAdd = dependencies.map((dep)=>`${dep}`);
|
|
561
|
+
switch(packageManager){
|
|
562
|
+
case 'npm':
|
|
563
|
+
return `npm install ${depsToAdd.join(' ')}`;
|
|
564
|
+
case 'yarn':
|
|
565
|
+
return `yarn add ${depsToAdd.join(' ')}`;
|
|
566
|
+
case 'pnpm':
|
|
567
|
+
return `pnpm add ${depsToAdd.join(' ')}`;
|
|
568
|
+
default:
|
|
569
|
+
return `npm install ${depsToAdd.join(' ')}`;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
async function detectFramework(projectRoot) {
|
|
573
|
+
try {
|
|
574
|
+
const packageJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'package.json');
|
|
575
|
+
const packageJson = JSON.parse(await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].readFile(packageJsonPath, 'utf-8'));
|
|
576
|
+
const deps = {
|
|
577
|
+
...packageJson.dependencies,
|
|
578
|
+
...packageJson.devDependencies
|
|
579
|
+
};
|
|
580
|
+
const hasReact = 'react' in deps;
|
|
581
|
+
let framework = null;
|
|
582
|
+
if ('next' in deps) framework = 'Next.js';
|
|
583
|
+
else if ('@remix-run/react' in deps) framework = 'Remix';
|
|
584
|
+
else if ('@vitejs/plugin-react' in deps || '@vitejs/plugin-react-swc' in deps) framework = 'Vite + React';
|
|
585
|
+
else if ('gatsby' in deps) framework = 'Gatsby';
|
|
586
|
+
else if (hasReact) framework = 'React';
|
|
587
|
+
return {
|
|
588
|
+
framework,
|
|
589
|
+
hasReact
|
|
590
|
+
};
|
|
591
|
+
} catch (error) {
|
|
592
|
+
return {
|
|
593
|
+
framework: null,
|
|
594
|
+
hasReact: false
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
async function detectProjectRoot(cwd) {
|
|
599
|
+
let projectRoot = cwd;
|
|
600
|
+
try {
|
|
601
|
+
let prevDir = '';
|
|
602
|
+
while(projectRoot !== prevDir)try {
|
|
603
|
+
await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].access(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'package.json'));
|
|
604
|
+
break;
|
|
605
|
+
} catch {
|
|
606
|
+
prevDir = projectRoot;
|
|
607
|
+
projectRoot = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].dirname(projectRoot);
|
|
608
|
+
}
|
|
609
|
+
if (projectRoot === prevDir) throw new Error('Could not find project root (no package.json found)');
|
|
610
|
+
return projectRoot;
|
|
611
|
+
} catch {
|
|
612
|
+
return cwd;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
async function detectPackageManager(projectRoot) {
|
|
616
|
+
try {
|
|
617
|
+
const result = await (0, __WEBPACK_EXTERNAL_MODULE_package_manager_detector_detect_94d6a9ae__.detect)({
|
|
618
|
+
cwd: projectRoot
|
|
619
|
+
});
|
|
620
|
+
let detectedPm = null;
|
|
621
|
+
if ('string' == typeof result) detectedPm = result;
|
|
622
|
+
else if (result && 'object' == typeof result) {
|
|
623
|
+
if ('name' in result && 'string' == typeof result.name) detectedPm = result.name;
|
|
624
|
+
else if ('pm' in result && 'string' == typeof result.pm) detectedPm = result.pm;
|
|
377
625
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
626
|
+
if (detectedPm && ('npm' === detectedPm || 'yarn' === detectedPm || 'pnpm' === detectedPm)) return detectedPm;
|
|
627
|
+
let detectedValueStr = String(result);
|
|
628
|
+
if (result && 'object' == typeof result) detectedValueStr = JSON.stringify(result);
|
|
629
|
+
throw new Error(`Could not reliably detect package manager (detected: ${detectedValueStr}).`);
|
|
630
|
+
} catch (error) {
|
|
631
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.log.warn(`Automatic package manager detection failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
632
|
+
const selectedPackageManager = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.select({
|
|
633
|
+
message: 'Please select your package manager:',
|
|
634
|
+
options: [
|
|
635
|
+
{
|
|
636
|
+
value: 'npm',
|
|
637
|
+
label: 'npm'
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
value: 'yarn',
|
|
641
|
+
label: 'yarn'
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
value: 'pnpm',
|
|
645
|
+
label: 'pnpm'
|
|
646
|
+
}
|
|
647
|
+
],
|
|
648
|
+
initialValue: 'npm'
|
|
649
|
+
});
|
|
650
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(selectedPackageManager)) {
|
|
651
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.log.warn('Package manager selection cancelled. Exiting.');
|
|
652
|
+
process.exit(0);
|
|
395
653
|
}
|
|
396
|
-
|
|
654
|
+
return selectedPackageManager;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
function generateClientConfigContent(mode, backendURL, useEnvFile) {
|
|
658
|
+
let configContent = '';
|
|
659
|
+
const validModes = [
|
|
660
|
+
'c15t',
|
|
661
|
+
'offline',
|
|
662
|
+
'custom'
|
|
663
|
+
];
|
|
664
|
+
if (!validModes.includes(mode)) throw new Error(`Invalid mode: ${mode}. Valid modes are: ${validModes.join(', ')}`);
|
|
665
|
+
switch(mode){
|
|
666
|
+
case 'c15t':
|
|
667
|
+
configContent = `// c15t Client Configuration
|
|
668
|
+
import type { ConsentManagerOptions } from '@c15t/react';
|
|
669
|
+
|
|
670
|
+
export const c15tConfig = {
|
|
671
|
+
// Using hosted c15t (consent.io) or self-hosted instance
|
|
672
|
+
mode: 'c15t',
|
|
673
|
+
backendURL: ${useEnvFile ? 'process.env.NEXT_PUBLIC_C15T_URL' : `'${backendURL || 'https://your-instance.c15t.dev'}'`},
|
|
674
|
+
|
|
675
|
+
// Optional: Add callback functions for various events
|
|
676
|
+
callbacks: {
|
|
677
|
+
onConsentSet: (response) => {
|
|
678
|
+
console.log('Consent has been saved');
|
|
397
679
|
}
|
|
398
|
-
});
|
|
399
|
-
return {
|
|
400
|
-
code: schema.trim() === schemaPrisma.trim() ? "" : schema,
|
|
401
|
-
fileName: filePath
|
|
402
|
-
};
|
|
403
|
-
};
|
|
404
|
-
const getNewPrisma = (provider) => `generator client {
|
|
405
|
-
provider = "prisma-client-js"
|
|
406
680
|
}
|
|
681
|
+
} satisfies ConsentManagerOptions;
|
|
682
|
+
|
|
683
|
+
// Use in your app layout:
|
|
684
|
+
// <ConsentManagerProvider options={c15tConfig}>
|
|
685
|
+
// {children}
|
|
686
|
+
// <CookieBanner />
|
|
687
|
+
// <ConsentManagerDialog />
|
|
688
|
+
// </ConsentManagerProvider>
|
|
689
|
+
`;
|
|
690
|
+
break;
|
|
691
|
+
case 'offline':
|
|
692
|
+
configContent = `// c15t Client Configuration
|
|
693
|
+
import type { ConsentManagerOptions } from '@c15t/react';
|
|
694
|
+
|
|
695
|
+
export const c15tConfig = {
|
|
696
|
+
// Using offline mode for browser-based storage
|
|
697
|
+
mode: 'offline',
|
|
407
698
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
699
|
+
// Optional: Add callback functions for various events
|
|
700
|
+
callbacks: {
|
|
701
|
+
onConsentSet: (response) => {
|
|
702
|
+
console.log('Consent has been saved locally');
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
} satisfies ConsentManagerOptions;
|
|
412
706
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
707
|
+
// Use in your app layout:
|
|
708
|
+
// <ConsentManagerProvider options={c15tConfig}>
|
|
709
|
+
// {children}
|
|
710
|
+
// <CookieBanner />
|
|
711
|
+
// <ConsentManagerDialog />
|
|
712
|
+
// </ConsentManagerProvider>
|
|
713
|
+
`;
|
|
714
|
+
break;
|
|
715
|
+
case 'custom':
|
|
716
|
+
configContent = `// c15t Client Configuration
|
|
717
|
+
import type { ConsentManagerOptions } from '@c15t/react';
|
|
718
|
+
import { createCustomHandlers } from './consent-handlers';
|
|
719
|
+
|
|
720
|
+
export const c15tConfig = {
|
|
721
|
+
// Using custom mode for complete control
|
|
722
|
+
mode: 'custom',
|
|
723
|
+
endpointHandlers: createCustomHandlers(),
|
|
724
|
+
|
|
725
|
+
// Optional: Add callback functions for various events
|
|
726
|
+
callbacks: {
|
|
727
|
+
onConsentSet: (response) => {
|
|
728
|
+
console.log('Consent has been saved');
|
|
729
|
+
}
|
|
424
730
|
}
|
|
425
|
-
|
|
426
|
-
};
|
|
731
|
+
} satisfies ConsentManagerOptions;
|
|
427
732
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
);
|
|
441
|
-
}
|
|
442
|
-
function createDataUriModule(module) {
|
|
443
|
-
return `data:text/javascript;charset=utf-8,${encodeURIComponent(module)}`;
|
|
444
|
-
}
|
|
445
|
-
function createStaticEnvModule(env) {
|
|
446
|
-
const declarations = Object.keys(env).filter((k) => validIdentifier.test(k) && !reserved.has(k)).map((k) => `export const ${k} = ${JSON.stringify(env[k])};`);
|
|
447
|
-
return `
|
|
448
|
-
${declarations.join("\n")}
|
|
449
|
-
// jiti dirty hack: .unknown
|
|
450
|
-
`;
|
|
451
|
-
}
|
|
452
|
-
function createDynamicEnvModule() {
|
|
453
|
-
return `
|
|
454
|
-
export const env = process.env;
|
|
455
|
-
// jiti dirty hack: .unknown
|
|
456
|
-
`;
|
|
733
|
+
// Use in your app layout:
|
|
734
|
+
// <ConsentManagerProvider options={c15tConfig}>
|
|
735
|
+
// {children}
|
|
736
|
+
// <CookieBanner />
|
|
737
|
+
// <ConsentManagerDialog />
|
|
738
|
+
// </ConsentManagerProvider>
|
|
739
|
+
|
|
740
|
+
// Don't forget to implement your custom handlers in consent-handlers.ts!
|
|
741
|
+
`;
|
|
742
|
+
break;
|
|
743
|
+
}
|
|
744
|
+
return configContent;
|
|
457
745
|
}
|
|
458
|
-
function
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
746
|
+
function generateBackendConfigContent(adapterChoice, connectionString, filePath) {
|
|
747
|
+
let adapterImport = '';
|
|
748
|
+
let adapterConfig = '';
|
|
749
|
+
switch(adapterChoice){
|
|
750
|
+
case 'kysely-postgres':
|
|
751
|
+
adapterImport = `import { kyselyAdapter } from '@c15t/backend/db/adapters/kysely';\nimport { PostgresDialect } from 'kysely';\nimport { Pool } from 'pg';`;
|
|
752
|
+
adapterConfig = `kyselyAdapter({
|
|
753
|
+
dialect: new PostgresDialect({
|
|
754
|
+
pool: new Pool({
|
|
755
|
+
connectionString: ${connectionString ? `"${connectionString}"` : 'process.env.DATABASE_URL || "postgresql://user:password@host:port/db"'}
|
|
756
|
+
})
|
|
757
|
+
})
|
|
758
|
+
})`;
|
|
759
|
+
break;
|
|
760
|
+
case 'kysely-sqlite':
|
|
761
|
+
adapterImport = `import { kyselyAdapter } from '@c15t/backend/db/adapters/kysely';\nimport { SqliteDialect } from 'kysely';\nimport Database from 'better-sqlite3';`;
|
|
762
|
+
adapterConfig = `kyselyAdapter({
|
|
763
|
+
dialect: new SqliteDialect({
|
|
764
|
+
database: new Database("${filePath || './db.sqlite'}")
|
|
765
|
+
})
|
|
766
|
+
})`;
|
|
767
|
+
break;
|
|
768
|
+
default:
|
|
769
|
+
adapterImport = "import { memoryAdapter } from '@c15t/backend/db/adapters/memory';";
|
|
770
|
+
adapterConfig = 'memoryAdapter({})';
|
|
771
|
+
break;
|
|
772
|
+
}
|
|
773
|
+
return `// c15t Backend Configuration
|
|
774
|
+
// Generated by c15t CLI onboarding
|
|
775
|
+
|
|
776
|
+
import { c15tInstance } from '@c15t/backend';
|
|
777
|
+
${adapterImport}
|
|
778
|
+
|
|
779
|
+
// WARNING: Database connection strings often contain sensitive credentials.
|
|
780
|
+
// Consider using environment variables instead of hardcoding these values.
|
|
781
|
+
|
|
782
|
+
// Define your c15t instance
|
|
783
|
+
const instance = c15tInstance({
|
|
784
|
+
appName: 'Your App Name',
|
|
785
|
+
basePath: '/api/c15t',
|
|
786
|
+
database: ${adapterConfig},
|
|
787
|
+
trustedOrigins: ['http://localhost:3000'],
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
export default instance;
|
|
791
|
+
`;
|
|
464
792
|
}
|
|
465
|
-
function
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
);
|
|
793
|
+
function generateEnvFileContent(backendURL) {
|
|
794
|
+
return `# c15t Configuration
|
|
795
|
+
# Note: This URL is public and can be safely committed to version control
|
|
796
|
+
NEXT_PUBLIC_C15T_URL=${backendURL}
|
|
797
|
+
`;
|
|
471
798
|
}
|
|
472
|
-
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
(name) => extensions.map((ext) => `${name}${ext}`)
|
|
545
|
-
);
|
|
546
|
-
const directories = [
|
|
547
|
-
"",
|
|
548
|
-
"lib/server/",
|
|
549
|
-
"server/",
|
|
550
|
-
"lib/",
|
|
551
|
-
"utils/",
|
|
552
|
-
"config/",
|
|
553
|
-
"src/",
|
|
554
|
-
"app/"
|
|
555
|
-
];
|
|
556
|
-
possiblePaths = directories.flatMap(
|
|
557
|
-
(dir) => possiblePaths.map((file) => `${dir}${file}`)
|
|
558
|
-
);
|
|
559
|
-
const monorepoSubdirs = ["packages/*", "apps/*"];
|
|
560
|
-
function stripJsonComments(jsonString) {
|
|
561
|
-
return jsonString.replace(
|
|
562
|
-
/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g,
|
|
563
|
-
(m, g) => g ? "" : m
|
|
564
|
-
).replace(/,(?=\s*[}\]])/g, "");
|
|
799
|
+
async function setupC15tMode(context, projectRoot, spinner, initialBackendURL, handleCancel) {
|
|
800
|
+
const { logger, cwd } = context;
|
|
801
|
+
const needsAccount = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
|
|
802
|
+
message: 'Do you need to create a consent.io account?',
|
|
803
|
+
initialValue: true
|
|
804
|
+
});
|
|
805
|
+
if (handleCancel?.(needsAccount)) throw new Error('Setup cancelled');
|
|
806
|
+
if (needsAccount) {
|
|
807
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.note(`We'll open your browser to create a consent.io account and set up your instance.\nFollow these steps:\n1. Sign up for a consent.io account\n2. Create a new instance in the dashboard\n3. Configure your trusted origins (domains that can connect)\n4. Copy the provided backendURL (e.g., https://your-instance.c15t.dev)`, 'consent.io Setup');
|
|
808
|
+
const shouldOpen = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
|
|
809
|
+
message: 'Open browser to sign up for consent.io?',
|
|
810
|
+
initialValue: true
|
|
811
|
+
});
|
|
812
|
+
if (handleCancel?.(shouldOpen)) throw new Error('Setup cancelled');
|
|
813
|
+
if (shouldOpen) try {
|
|
814
|
+
await (0, __WEBPACK_EXTERNAL_MODULE_open__["default"])('https://consent.io/dashboard/register?ref=cli');
|
|
815
|
+
const enterPressed = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.text({
|
|
816
|
+
message: 'Press Enter once you have created your instance and have the backendURL'
|
|
817
|
+
});
|
|
818
|
+
if (handleCancel?.(enterPressed)) throw new Error('Setup cancelled');
|
|
819
|
+
} catch (error) {
|
|
820
|
+
logger.warn('Failed to open browser automatically. Please visit https://consent.io/dashboard/register manually.');
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
const backendURLSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.text({
|
|
824
|
+
message: 'Enter your consent.io instance URL:',
|
|
825
|
+
placeholder: 'https://your-instance.c15t.dev',
|
|
826
|
+
initialValue: initialBackendURL,
|
|
827
|
+
validate: (value)=>{
|
|
828
|
+
if (!value || '' === value) return 'URL is required';
|
|
829
|
+
try {
|
|
830
|
+
const url = new URL(value);
|
|
831
|
+
if (!url.hostname.endsWith('.c15t.dev')) return 'Please enter a valid *.c15t.dev URL';
|
|
832
|
+
} catch {
|
|
833
|
+
return 'Please enter a valid URL';
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
if (handleCancel?.(backendURLSelection)) throw new Error('Setup cancelled');
|
|
838
|
+
if (!backendURLSelection || '' === backendURLSelection) {
|
|
839
|
+
logger.error('A valid consent.io URL is required');
|
|
840
|
+
throw new Error('A valid consent.io URL is required');
|
|
841
|
+
}
|
|
842
|
+
const backendURL = backendURLSelection;
|
|
843
|
+
const useEnvFileSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
|
|
844
|
+
message: 'Store the backendURL in a .env file? (Recommended, URL is public)',
|
|
845
|
+
initialValue: true
|
|
846
|
+
});
|
|
847
|
+
if (handleCancel?.(useEnvFileSelection)) throw new Error('Setup cancelled');
|
|
848
|
+
const useEnvFile = useEnvFileSelection;
|
|
849
|
+
const clientConfigContent = generateClientConfigContent('c15t', backendURL, useEnvFile);
|
|
850
|
+
const configPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'c15t.config.ts');
|
|
851
|
+
spinner.start('Creating client configuration file...');
|
|
852
|
+
await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(configPath, clientConfigContent);
|
|
853
|
+
spinner.stop(formatLogMessage('info', `Client configuration created: ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, configPath))}`));
|
|
854
|
+
if (useEnvFile) {
|
|
855
|
+
const envPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, '.env.local');
|
|
856
|
+
const envExamplePath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, '.env.example');
|
|
857
|
+
spinner.start('Creating environment files...');
|
|
858
|
+
const envContent = generateEnvFileContent(backendURL);
|
|
859
|
+
await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(envPath, envContent);
|
|
860
|
+
logger.info(` - Created environment file: ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, envPath))}`);
|
|
861
|
+
const envExampleContent = '# c15t Configuration\nNEXT_PUBLIC_C15T_URL=https://your-instance.c15t.dev\n';
|
|
862
|
+
await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(envExamplePath, envExampleContent);
|
|
863
|
+
logger.info(` - Created example env file: ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, envExamplePath))}`);
|
|
864
|
+
spinner.stop(formatLogMessage('info', 'Environment files created.'));
|
|
865
|
+
}
|
|
866
|
+
return {
|
|
867
|
+
clientConfigContent,
|
|
868
|
+
backendURL,
|
|
869
|
+
usingEnvFile: useEnvFile
|
|
870
|
+
};
|
|
565
871
|
}
|
|
566
|
-
function
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
872
|
+
async function setupCustomMode(context, projectRoot, spinner) {
|
|
873
|
+
const { logger, cwd } = context;
|
|
874
|
+
const clientConfigContent = generateClientConfigContent('custom');
|
|
875
|
+
const configPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'c15t.config.ts');
|
|
876
|
+
spinner.start('Creating client configuration file...');
|
|
877
|
+
await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(configPath, clientConfigContent);
|
|
878
|
+
spinner.stop(formatLogMessage('info', `Client configuration created: ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, configPath))}`));
|
|
879
|
+
logger.info(`Remember to implement custom endpoint handlers (see ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, configPath))}).`);
|
|
880
|
+
return {
|
|
881
|
+
clientConfigContent
|
|
882
|
+
};
|
|
576
883
|
}
|
|
577
|
-
function
|
|
578
|
-
|
|
579
|
-
const
|
|
580
|
-
const
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
}
|
|
593
|
-
addSvelteKitEnvModules(result);
|
|
594
|
-
return result;
|
|
595
|
-
} catch (error) {
|
|
596
|
-
logger.warn(`Error parsing config file ${configPath}`, error);
|
|
597
|
-
return null;
|
|
598
|
-
}
|
|
884
|
+
async function setupOfflineMode(context, projectRoot, spinner, handleCancel) {
|
|
885
|
+
const { logger, cwd } = context;
|
|
886
|
+
const clientConfigContent = generateClientConfigContent('offline', void 0, false);
|
|
887
|
+
const configPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'c15t.config.ts');
|
|
888
|
+
spinner.start('Creating client configuration file...');
|
|
889
|
+
try {
|
|
890
|
+
await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(configPath, clientConfigContent);
|
|
891
|
+
spinner.stop(formatLogMessage('info', `Client configuration created: ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, configPath))}`));
|
|
892
|
+
} catch (error) {
|
|
893
|
+
spinner.stop(formatLogMessage('error', `Failed to create configuration file: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
894
|
+
throw error;
|
|
895
|
+
} finally{}
|
|
896
|
+
return {
|
|
897
|
+
clientConfigContent
|
|
898
|
+
};
|
|
599
899
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
900
|
+
async function setupSelfHostedMode(context, projectRoot, spinner, handleCancel) {
|
|
901
|
+
const { logger, cwd } = context;
|
|
902
|
+
let backendConfigContent = null;
|
|
903
|
+
const dependencies = [
|
|
904
|
+
'@c15t/backend'
|
|
905
|
+
];
|
|
906
|
+
const setupBackendSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
|
|
907
|
+
message: 'Set up the backend configuration now?',
|
|
908
|
+
initialValue: true
|
|
909
|
+
});
|
|
910
|
+
if (handleCancel?.(setupBackendSelection)) throw new Error('Setup cancelled');
|
|
911
|
+
const setupBackend = setupBackendSelection;
|
|
912
|
+
let adapterChoice = 'memory';
|
|
913
|
+
if (setupBackend) {
|
|
914
|
+
const adapterSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.select({
|
|
915
|
+
message: 'Choose a database adapter:',
|
|
916
|
+
initialValue: 'kysely-sqlite',
|
|
917
|
+
options: [
|
|
918
|
+
{
|
|
919
|
+
value: 'kysely-sqlite',
|
|
920
|
+
label: 'Kysely (SQLite)',
|
|
921
|
+
hint: 'Simple setups/local dev'
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
value: 'kysely-postgres',
|
|
925
|
+
label: 'Kysely (PostgreSQL)',
|
|
926
|
+
hint: 'Production'
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
value: 'memory',
|
|
930
|
+
label: 'Memory',
|
|
931
|
+
hint: 'Testing/development only'
|
|
932
|
+
}
|
|
933
|
+
]
|
|
934
|
+
});
|
|
935
|
+
if (handleCancel?.(adapterSelection)) throw new Error('Setup cancelled');
|
|
936
|
+
adapterChoice = adapterSelection;
|
|
937
|
+
let connectionString;
|
|
938
|
+
let dbPath;
|
|
939
|
+
if ('kysely-postgres' === adapterChoice) {
|
|
940
|
+
const connectionStringSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.text({
|
|
941
|
+
message: 'Enter PostgreSQL connection string:',
|
|
942
|
+
placeholder: 'postgresql://user:pass@host:port/db'
|
|
943
|
+
});
|
|
944
|
+
if (handleCancel?.(connectionStringSelection)) throw new Error('Setup cancelled');
|
|
945
|
+
if (!connectionStringSelection || '' === connectionStringSelection) {
|
|
946
|
+
logger.error('A valid PostgreSQL connection string is required');
|
|
947
|
+
throw new Error('A valid PostgreSQL connection string is required');
|
|
611
948
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
return config.c15t();
|
|
624
|
-
}
|
|
625
|
-
if (config.default && typeof config.default === "function") {
|
|
626
|
-
return config.default();
|
|
627
|
-
}
|
|
628
|
-
if (config.c15tInstance && typeof config.c15tInstance === "function") {
|
|
629
|
-
return config.c15tInstance();
|
|
630
|
-
}
|
|
631
|
-
if (config.consent && typeof config.consent === "function") {
|
|
632
|
-
return config.consent();
|
|
633
|
-
}
|
|
634
|
-
return config.c15t?.options || config.default?.options || config.c15tInstance?.options || config.instance?.options || config.consent?.options || config.config?.options || // Also check for direct exports of options objects
|
|
635
|
-
(config.default && typeof config.default === "object" && "appName" in config.default ? config.default : null) || // Finally check for direct exports of the instance
|
|
636
|
-
(config.c15t && typeof config.c15t === "object" && "appName" in config.c15t ? config.c15t : null) || null;
|
|
637
|
-
}
|
|
638
|
-
function findDirectories(cwd, patterns) {
|
|
639
|
-
const results = [];
|
|
640
|
-
for (const pattern of patterns) {
|
|
641
|
-
if (pattern.includes("*")) {
|
|
642
|
-
const [prefix, _] = pattern.split("*");
|
|
643
|
-
const basePath = path.join(cwd, prefix);
|
|
644
|
-
try {
|
|
645
|
-
if (fs$1.existsSync(basePath)) {
|
|
646
|
-
const entries = fs$1.readdirSync(basePath, { withFileTypes: true });
|
|
647
|
-
for (const entry of entries) {
|
|
648
|
-
if (entry.isDirectory()) {
|
|
649
|
-
results.push(path.join(prefix, entry.name));
|
|
949
|
+
connectionString = connectionStringSelection;
|
|
950
|
+
} else if ('kysely-sqlite' === adapterChoice) {
|
|
951
|
+
const dbPathSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.text({
|
|
952
|
+
message: 'Enter path for SQLite database file:',
|
|
953
|
+
placeholder: './db.sqlite',
|
|
954
|
+
initialValue: './db.sqlite'
|
|
955
|
+
});
|
|
956
|
+
if (handleCancel?.(dbPathSelection)) throw new Error('Setup cancelled');
|
|
957
|
+
if (!dbPathSelection || '' === dbPathSelection) {
|
|
958
|
+
logger.error('A valid database path is required');
|
|
959
|
+
throw new Error('A valid database path is required');
|
|
650
960
|
}
|
|
651
|
-
|
|
961
|
+
dbPath = dbPathSelection;
|
|
652
962
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
963
|
+
backendConfigContent = generateBackendConfigContent(adapterChoice, connectionString, dbPath);
|
|
964
|
+
const backendConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'c15t.backend.ts');
|
|
965
|
+
spinner.start('Creating backend configuration file...');
|
|
966
|
+
await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(backendConfigPath, backendConfigContent);
|
|
967
|
+
spinner.stop(formatLogMessage('info', `Backend configuration created: ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, backendConfigPath))}`));
|
|
657
968
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
return
|
|
664
|
-
|
|
665
|
-
|
|
969
|
+
const clientConfigContent = generateClientConfigContent('c15t', '/api/c15t', false);
|
|
970
|
+
const configPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'c15t.config.ts');
|
|
971
|
+
spinner.start('Creating client configuration file...');
|
|
972
|
+
await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(configPath, clientConfigContent);
|
|
973
|
+
spinner.stop(formatLogMessage('info', `Client configuration created: ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, configPath))}`));
|
|
974
|
+
return {
|
|
975
|
+
clientConfigContent,
|
|
976
|
+
backendConfigContent,
|
|
977
|
+
dependencies,
|
|
978
|
+
adapterChoice
|
|
979
|
+
};
|
|
666
980
|
}
|
|
667
|
-
async function
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
try {
|
|
678
|
-
if (!fs$1.existsSync(resolvedPath)) {
|
|
679
|
-
throw new C15TError(
|
|
680
|
-
`Configuration file not found: ${resolvedPath}
|
|
681
|
-
Make sure the path is correct and the file exists.`
|
|
682
|
-
);
|
|
981
|
+
async function startOnboarding(context, existingConfig) {
|
|
982
|
+
const { logger, cwd, telemetry } = context;
|
|
983
|
+
const handleCancel = (value)=>{
|
|
984
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(value)) {
|
|
985
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_EXITED, {
|
|
986
|
+
reason: 'user_cancelled',
|
|
987
|
+
stage: 'setup'
|
|
988
|
+
});
|
|
989
|
+
context.error.handleCancel('Configuration cancelled.');
|
|
990
|
+
return true;
|
|
683
991
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
992
|
+
return false;
|
|
993
|
+
};
|
|
994
|
+
const isUpdate = !!existingConfig;
|
|
995
|
+
logger.info(isUpdate ? 'Starting configuration update...' : 'Starting onboarding process...');
|
|
996
|
+
telemetry.trackEvent(isUpdate ? telemetry_TelemetryEventName.CONFIG_UPDATED : telemetry_TelemetryEventName.ONBOARDING_STARTED, {
|
|
997
|
+
isUpdate
|
|
998
|
+
});
|
|
999
|
+
telemetry.flushSync();
|
|
1000
|
+
logger.note(isUpdate ? "Let's update your c15t configuration." : `Welcome to c15t! Let's set up your consent management configuration.\nFirst, we'll help you choose the best storage approach for your needs.`, isUpdate ? 'Update Configuration' : 'First time setup');
|
|
1001
|
+
const projectRoot = await detectProjectRoot(cwd);
|
|
1002
|
+
if (projectRoot !== cwd) logger.debug(`Project root identified: ${projectRoot}`);
|
|
1003
|
+
else logger.warn('Could not determine project root, using current directory');
|
|
1004
|
+
const s = __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner();
|
|
1005
|
+
let spinnerActive = false;
|
|
1006
|
+
try {
|
|
1007
|
+
const packageManager = await detectPackageManager(projectRoot);
|
|
1008
|
+
const { framework, hasReact } = await detectFramework(projectRoot);
|
|
1009
|
+
logger.debug(`Detected package manager: ${packageManager}`);
|
|
1010
|
+
if (framework) logger.debug(`Detected framework: ${framework}`);
|
|
1011
|
+
logger.debug(`React detected: ${hasReact}`);
|
|
1012
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.CLI_ENVIRONMENT_DETECTED, {
|
|
1013
|
+
packageManager,
|
|
1014
|
+
framework: framework || 'unknown',
|
|
1015
|
+
hasReact
|
|
689
1016
|
});
|
|
690
|
-
|
|
691
|
-
if (
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
`Found config file at ${resolvedPath} but couldn't extract c15t options.
|
|
695
|
-
Make sure you're exporting c15t with one of these patterns:
|
|
696
|
-
- export const c15t = c15tInstance({...})
|
|
697
|
-
- export const consent = c15tInstance({...})
|
|
698
|
-
- export const c15tInstance = c15tInstance({...})
|
|
699
|
-
- export default c15tInstance({...})`
|
|
700
|
-
);
|
|
1017
|
+
let initialStorageMode;
|
|
1018
|
+
if (isUpdate && existingConfig && 'mode' in existingConfig) {
|
|
1019
|
+
if (isClientOptions(existingConfig)) initialStorageMode = existingConfig.mode;
|
|
1020
|
+
else if (isC15TOptions(existingConfig)) initialStorageMode = 'c15t';
|
|
701
1021
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
1022
|
+
let storageModeSelection;
|
|
1023
|
+
try {
|
|
1024
|
+
storageModeSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.select({
|
|
1025
|
+
message: isUpdate ? `Select storage mode (current: ${initialStorageMode || 'unknown'}):` : 'How would you like to store consent decisions?',
|
|
1026
|
+
initialValue: initialStorageMode || 'c15t',
|
|
1027
|
+
options: [
|
|
1028
|
+
{
|
|
1029
|
+
value: 'c15t',
|
|
1030
|
+
label: 'Hosted c15t (consent.io)',
|
|
1031
|
+
hint: 'Recommended: Fully managed service'
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
value: 'offline',
|
|
1035
|
+
label: 'Offline Mode',
|
|
1036
|
+
hint: 'Store in browser, no backend needed'
|
|
1037
|
+
},
|
|
1038
|
+
{
|
|
1039
|
+
value: 'self-hosted',
|
|
1040
|
+
label: 'Self-Hosted',
|
|
1041
|
+
hint: 'Run your own c15t backend'
|
|
1042
|
+
},
|
|
1043
|
+
{
|
|
1044
|
+
value: 'custom',
|
|
1045
|
+
label: 'Custom Implementation',
|
|
1046
|
+
hint: 'Full control over storage logic'
|
|
1047
|
+
}
|
|
1048
|
+
]
|
|
1049
|
+
});
|
|
1050
|
+
} catch (error) {
|
|
1051
|
+
logger.error('Error selecting storage mode:', error);
|
|
1052
|
+
throw error;
|
|
718
1053
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
1054
|
+
if (handleCancel(storageModeSelection)) return;
|
|
1055
|
+
const storageMode = storageModeSelection;
|
|
1056
|
+
logger.debug(`Selected storage mode: ${storageMode}`);
|
|
1057
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_STORAGE_MODE_SELECTED, {
|
|
1058
|
+
storageMode,
|
|
1059
|
+
isUpdate
|
|
1060
|
+
});
|
|
1061
|
+
const dependenciesToAdd = [];
|
|
1062
|
+
let installDepsConfirmed = false;
|
|
1063
|
+
let ranInstall = false;
|
|
1064
|
+
if (hasReact) dependenciesToAdd.push('@c15t/react');
|
|
1065
|
+
else {
|
|
1066
|
+
dependenciesToAdd.push('c15t');
|
|
1067
|
+
if (null === framework) logger.note(`No React framework detected, installing base c15t package.\nIf you're using React, you might need to manually install @c15t/react instead.`, formatLogMessage('warn', 'Package Selection'));
|
|
1068
|
+
}
|
|
1069
|
+
if ('c15t' === storageMode) {
|
|
1070
|
+
let initialBackendURL;
|
|
1071
|
+
if (isUpdate && existingConfig && isClientOptions(existingConfig) && existingConfig.backendURL) initialBackendURL = existingConfig.backendURL;
|
|
1072
|
+
const c15tResult = await setupC15tMode(context, projectRoot, s, initialBackendURL, handleCancel);
|
|
1073
|
+
c15tResult.clientConfigContent;
|
|
1074
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_C15T_MODE_CONFIGURED, {
|
|
1075
|
+
usingEnvFile: c15tResult.usingEnvFile,
|
|
1076
|
+
hasInitialBackendURL: !!initialBackendURL
|
|
737
1077
|
});
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
1078
|
+
} else if ('offline' === storageMode) {
|
|
1079
|
+
const offlineResult = await setupOfflineMode(context, projectRoot, s, handleCancel);
|
|
1080
|
+
offlineResult.clientConfigContent;
|
|
1081
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_OFFLINE_MODE_CONFIGURED, {});
|
|
1082
|
+
} else if ('self-hosted' === storageMode) {
|
|
1083
|
+
const selfHostedResult = await setupSelfHostedMode(context, projectRoot, s, handleCancel);
|
|
1084
|
+
selfHostedResult.clientConfigContent;
|
|
1085
|
+
selfHostedResult.backendConfigContent;
|
|
1086
|
+
dependenciesToAdd.push(...selfHostedResult.dependencies);
|
|
1087
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_SELF_HOSTED_CONFIGURED, {
|
|
1088
|
+
databaseType: selfHostedResult.adapterChoice,
|
|
1089
|
+
dependencies: selfHostedResult.dependencies.join(',')
|
|
1090
|
+
});
|
|
1091
|
+
} else if ('custom' === storageMode) {
|
|
1092
|
+
const customResult = await setupCustomMode(context, projectRoot, s);
|
|
1093
|
+
customResult.clientConfigContent;
|
|
1094
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_CUSTOM_MODE_CONFIGURED, {});
|
|
1095
|
+
}
|
|
1096
|
+
let addDeps = false;
|
|
1097
|
+
if (dependenciesToAdd.length > 0) {
|
|
1098
|
+
const depsString = dependenciesToAdd.map((d)=>__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(d)).join(', ');
|
|
1099
|
+
const addDepsSelection = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
|
|
1100
|
+
message: `${isUpdate ? 'Update' : 'Add'} required dependencies using ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(packageManager)}? (${depsString})`,
|
|
1101
|
+
initialValue: true
|
|
1102
|
+
});
|
|
1103
|
+
if (handleCancel(addDepsSelection)) return;
|
|
1104
|
+
addDeps = addDepsSelection;
|
|
1105
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_DEPENDENCIES_CHOICE, {
|
|
1106
|
+
confirmed: addDeps,
|
|
1107
|
+
dependencies: dependenciesToAdd.join(','),
|
|
1108
|
+
packageManager
|
|
1109
|
+
});
|
|
1110
|
+
if (addDeps) {
|
|
1111
|
+
installDepsConfirmed = true;
|
|
1112
|
+
s.start(`Running ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(packageManager)} to add and install dependencies... (this might take a moment)`);
|
|
1113
|
+
spinnerActive = true;
|
|
1114
|
+
try {
|
|
1115
|
+
await addAndInstallDependenciesViaPM(projectRoot, dependenciesToAdd, packageManager);
|
|
1116
|
+
s.stop(`✅ Dependencies installed: ${dependenciesToAdd.map((d)=>__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(d)).join(', ')}`);
|
|
1117
|
+
spinnerActive = false;
|
|
1118
|
+
ranInstall = true;
|
|
1119
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
|
|
1120
|
+
success: true,
|
|
1121
|
+
dependencies: dependenciesToAdd.join(','),
|
|
1122
|
+
packageManager
|
|
1123
|
+
});
|
|
1124
|
+
} catch (installError) {
|
|
1125
|
+
s.stop(__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].yellow('⚠️ Dependency installation failed.'));
|
|
1126
|
+
spinnerActive = false;
|
|
1127
|
+
logger.error('Installation Error:', installError);
|
|
1128
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
|
|
1129
|
+
success: false,
|
|
1130
|
+
error: installError instanceof Error ? installError.message : String(installError),
|
|
1131
|
+
dependencies: dependenciesToAdd.join(','),
|
|
1132
|
+
packageManager
|
|
1133
|
+
});
|
|
1134
|
+
const pmCommand = getManualInstallCommand(dependenciesToAdd, packageManager);
|
|
1135
|
+
logger.info(`Please try running '${pmCommand}' manually in ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, projectRoot))}.`);
|
|
1136
|
+
}
|
|
755
1137
|
}
|
|
756
|
-
failedImports.push(fullPath);
|
|
757
|
-
}
|
|
758
1138
|
}
|
|
759
|
-
|
|
760
|
-
|
|
1139
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.log.step('Configuration Complete! Next Steps:');
|
|
1140
|
+
const configPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'c15t.config.ts');
|
|
1141
|
+
const backendConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, 'c15t.backend.ts');
|
|
1142
|
+
const relativeConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, configPath);
|
|
1143
|
+
const importPath = `./${relativeConfigPath.replace(/\\/g, '/').replace(/\.(ts|js|tsx|jsx)$/, '')}`;
|
|
1144
|
+
const importStatement = __WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(`import { c15tConfig } from '${importPath}';`);
|
|
1145
|
+
switch(storageMode){
|
|
1146
|
+
case 'c15t':
|
|
1147
|
+
{
|
|
1148
|
+
let steps = '1. Ensure your consent.io instance is configured (trusted origins etc).\n';
|
|
1149
|
+
try {
|
|
1150
|
+
await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].access(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, '.env.local'));
|
|
1151
|
+
steps += ` 2. Verify ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('NEXT_PUBLIC_C15T_URL')} in ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(projectRoot, '.env.local')))}.\n`;
|
|
1152
|
+
} catch {
|
|
1153
|
+
steps += ` 2. Verify ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('backendURL')} in ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(relativeConfigPath)}.\n`;
|
|
1154
|
+
}
|
|
1155
|
+
steps += ` 3. Import and use configuration in your app: ${importStatement}`;
|
|
1156
|
+
logger.info(steps);
|
|
1157
|
+
break;
|
|
1158
|
+
}
|
|
1159
|
+
case 'offline':
|
|
1160
|
+
logger.info(`1. Import and use configuration in your app: ${importStatement}`);
|
|
1161
|
+
break;
|
|
1162
|
+
case 'self-hosted':
|
|
1163
|
+
{
|
|
1164
|
+
let steps = '';
|
|
1165
|
+
try {
|
|
1166
|
+
await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].access(backendConfigPath);
|
|
1167
|
+
steps += `1. Configure database connection in ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].relative(cwd, backendConfigPath))}.\n`;
|
|
1168
|
+
steps += ' 2. Set up API routes using the exported backend instance.\n';
|
|
1169
|
+
} catch {
|
|
1170
|
+
steps += '1. Set up your c15t backend instance and API routes.\n';
|
|
1171
|
+
}
|
|
1172
|
+
steps += ` 3. Ensure ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('backendURL')} in ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(relativeConfigPath)} points to your API.\n`;
|
|
1173
|
+
steps += ` 4. Import and use client configuration: ${importStatement}`;
|
|
1174
|
+
logger.info(steps);
|
|
1175
|
+
break;
|
|
1176
|
+
}
|
|
1177
|
+
case 'custom':
|
|
1178
|
+
{
|
|
1179
|
+
const steps = `1. Implement your custom endpoint handlers (referenced in ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(relativeConfigPath)}).\n 2. Import and use configuration in your app: ${importStatement}`;
|
|
1180
|
+
logger.info(steps);
|
|
1181
|
+
break;
|
|
1182
|
+
}
|
|
761
1183
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
logger.error(
|
|
767
|
-
`\u274C Found ${foundPaths.length} potential config files, but couldn't load any of them:`
|
|
768
|
-
);
|
|
769
|
-
for (const filePath of foundPaths.slice(0, 3)) {
|
|
770
|
-
logger.error(` - ${filePath}`);
|
|
1184
|
+
if (installDepsConfirmed && !ranInstall) logger.info(` - ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].yellow('Dependency installation failed.')} Please check errors and install manually.`);
|
|
1185
|
+
else if (!addDeps && dependenciesToAdd.length > 0) {
|
|
1186
|
+
const pmCommand = getManualInstallCommand(dependenciesToAdd, packageManager);
|
|
1187
|
+
logger.warn(` - Run ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(pmCommand)} to install required dependencies.`);
|
|
771
1188
|
}
|
|
772
|
-
|
|
773
|
-
|
|
1189
|
+
logger.note(`${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].bold('✨ Setup complete!')} Your c15t configuration is ready to use. \n
|
|
1190
|
+
|
|
1191
|
+
We're building c15t as an ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].bold('open source')} project to make consent management more accessible.
|
|
1192
|
+
If you find this useful, we'd really appreciate a GitHub star - it helps others discover the project!`, '🎉 Thanks for using c15t');
|
|
1193
|
+
const shouldOpenGithub = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
|
|
1194
|
+
message: 'Would you like to star c15t on GitHub now?',
|
|
1195
|
+
initialValue: true
|
|
1196
|
+
});
|
|
1197
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(shouldOpenGithub)) {
|
|
1198
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_GITHUB_STAR, {
|
|
1199
|
+
action: 'cancelled'
|
|
1200
|
+
});
|
|
1201
|
+
return context.error.handleCancel('GitHub star prompt cancelled. Exiting onboarding.');
|
|
774
1202
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
1203
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_GITHUB_STAR, {
|
|
1204
|
+
action: shouldOpenGithub ? 'opened_browser' : 'declined'
|
|
1205
|
+
});
|
|
1206
|
+
if (shouldOpenGithub) try {
|
|
1207
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.note('Your support helps us continue improving c15t.\nThank you for being part of our community!', '⭐ Star Us on GitHub');
|
|
1208
|
+
await (0, __WEBPACK_EXTERNAL_MODULE_open__["default"])('https://github.com/c15t/c15t');
|
|
1209
|
+
logger.success('GitHub repository opened. Thank you for your support!');
|
|
1210
|
+
} catch (error) {
|
|
1211
|
+
logger.debug('Failed to open browser:', error);
|
|
1212
|
+
logger.info(`You can star us later by visiting: ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('https://github.com/c15t/c15t')}`);
|
|
1213
|
+
}
|
|
1214
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_COMPLETED, {
|
|
1215
|
+
success: true,
|
|
1216
|
+
storageMode,
|
|
1217
|
+
installDependencies: ranInstall
|
|
1218
|
+
});
|
|
1219
|
+
logger.success('🚀 Setup completed successfully!');
|
|
1220
|
+
} catch (error) {
|
|
1221
|
+
if (spinnerActive) s.stop(__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].red('Onboarding failed.'));
|
|
1222
|
+
if (!__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(error)) {
|
|
1223
|
+
logger.error('An unexpected error occurred during onboarding:', error);
|
|
1224
|
+
if (error instanceof Error && error.message) logger.error(`Error details: ${error.message}`);
|
|
1225
|
+
logger.failed('Onboarding process could not be completed.');
|
|
1226
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_COMPLETED, {
|
|
1227
|
+
success: false,
|
|
1228
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1229
|
+
});
|
|
787
1230
|
}
|
|
788
|
-
throw new C15TError("Unable to load any c15t configuration file");
|
|
789
|
-
}
|
|
790
|
-
logger.error(
|
|
791
|
-
"\u274C No c15t configuration files found in standard locations"
|
|
792
|
-
);
|
|
793
|
-
logger.info("\n\u{1F4DD} Create a c15t.ts file with your configuration:");
|
|
794
|
-
logger.info(`
|
|
795
|
-
import { c15tInstance } from '@c15t/backend';
|
|
796
|
-
|
|
797
|
-
export const c15t = c15tInstance({
|
|
798
|
-
appName: 'My App',
|
|
799
|
-
basePath: '/api/c15t',
|
|
800
|
-
// Add your configuration here
|
|
801
|
-
});
|
|
802
|
-
`);
|
|
803
|
-
throw new C15TError(
|
|
804
|
-
"No c15t config file found. Create a c15t.ts file or specify with --config"
|
|
805
|
-
);
|
|
806
|
-
}
|
|
807
|
-
return configFile;
|
|
808
|
-
} catch (e) {
|
|
809
|
-
if (typeof e === "object" && e && "message" in e && typeof e.message === "string" && e.message.includes(
|
|
810
|
-
"This module cannot be imported from a Client Component module"
|
|
811
|
-
)) {
|
|
812
|
-
logger.error(
|
|
813
|
-
"\u274C Server-only import detected in config file\nPlease temporarily remove the 'server-only' import while using the CLI,\nand you can add it back afterwards."
|
|
814
|
-
);
|
|
815
|
-
process.exit(1);
|
|
816
|
-
}
|
|
817
|
-
if (e instanceof C15TError) {
|
|
818
|
-
logger.error(`\u274C ${e.message}`);
|
|
819
|
-
} else {
|
|
820
|
-
logger.error(`\u274C Couldn't read your c15t configuration`);
|
|
821
|
-
logger.error(` Error: ${e instanceof Error ? e.message : String(e)}`);
|
|
822
1231
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
1232
|
+
}
|
|
1233
|
+
async function setupGenerateEnvironment(context) {
|
|
1234
|
+
const { logger, flags, cwd, error, telemetry } = context;
|
|
1235
|
+
logger.debug('Setting up generate environment...');
|
|
1236
|
+
logger.debug('Context flags:', flags);
|
|
1237
|
+
logger.debug(`Context CWD: ${cwd}`);
|
|
1238
|
+
if (!(0, __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__.existsSync)(cwd)) {
|
|
1239
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_FAILED, {
|
|
1240
|
+
error: `Directory ${cwd} does not exist`,
|
|
1241
|
+
stage: 'setup'
|
|
1242
|
+
});
|
|
1243
|
+
return error.handleError(new Error(`The directory "${cwd}" does not exist`), 'Generate setup failed');
|
|
828
1244
|
}
|
|
829
|
-
|
|
830
|
-
|
|
1245
|
+
logger.debug('Attempting to load configuration...');
|
|
1246
|
+
const config = await context.config.loadConfig();
|
|
1247
|
+
if (!config) {
|
|
1248
|
+
logger.debug('No config found during setup, generate command will handle onboarding.');
|
|
1249
|
+
try {
|
|
1250
|
+
const memAdapter = await (0, __WEBPACK_EXTERNAL_MODULE__c15t_backend_pkgs_db_adapters_cee37d0f__.getAdapter)({
|
|
1251
|
+
appName: 'temp-for-setup',
|
|
1252
|
+
database: {
|
|
1253
|
+
adapter: 'memory'
|
|
1254
|
+
}
|
|
1255
|
+
});
|
|
1256
|
+
return {
|
|
1257
|
+
config: null,
|
|
1258
|
+
adapter: memAdapter
|
|
1259
|
+
};
|
|
1260
|
+
} catch (adapterError) {
|
|
1261
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_FAILED, {
|
|
1262
|
+
error: adapterError instanceof Error ? adapterError.message : String(adapterError),
|
|
1263
|
+
stage: 'adapter_initialization'
|
|
1264
|
+
});
|
|
1265
|
+
return error.handleError(adapterError, 'Failed to initialize default memory adapter');
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
logger.debug('Config loaded, initializing adapter...');
|
|
1269
|
+
let adapter;
|
|
1270
|
+
try {
|
|
1271
|
+
adapter = await (0, __WEBPACK_EXTERNAL_MODULE__c15t_backend_pkgs_db_adapters_cee37d0f__.getAdapter)(config);
|
|
1272
|
+
logger.debug('Adapter initialized successfully');
|
|
1273
|
+
} catch (e) {
|
|
1274
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_FAILED, {
|
|
1275
|
+
error: e instanceof Error ? e.message : String(e),
|
|
1276
|
+
stage: 'adapter_initialization_with_config'
|
|
1277
|
+
});
|
|
1278
|
+
return error.handleError(e, 'Failed to initialize database adapter');
|
|
1279
|
+
}
|
|
1280
|
+
if (!adapter) {
|
|
1281
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_FAILED, {
|
|
1282
|
+
error: 'Adapter initialization returned undefined',
|
|
1283
|
+
stage: 'adapter_initialization_check'
|
|
1284
|
+
});
|
|
1285
|
+
return error.handleError(new Error('Adapter initialization returned undefined'), 'Database adapter could not be initialized');
|
|
1286
|
+
}
|
|
1287
|
+
logger.debug('Environment setup complete');
|
|
1288
|
+
return {
|
|
1289
|
+
config,
|
|
1290
|
+
adapter
|
|
1291
|
+
};
|
|
831
1292
|
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
logger.error(
|
|
851
|
-
"No configuration file found. Add a `c15t.ts` file to your project or pass the path to the configuration file using the `--config` flag."
|
|
852
|
-
);
|
|
853
|
-
return;
|
|
854
|
-
}
|
|
855
|
-
const adapter = await getAdapter(config).catch((e) => {
|
|
856
|
-
logger.error(e.message);
|
|
857
|
-
process.exit(1);
|
|
858
|
-
});
|
|
859
|
-
const spinner = yoctoSpinner({ text: "preparing schema..." }).start();
|
|
860
|
-
const schema = await getGenerator({
|
|
861
|
-
adapter,
|
|
862
|
-
file: options.output,
|
|
863
|
-
options: config
|
|
864
|
-
});
|
|
865
|
-
spinner.stop();
|
|
866
|
-
if (!schema.code) {
|
|
867
|
-
logger.info("Your schema is already up to date.");
|
|
868
|
-
process.exit(0);
|
|
869
|
-
}
|
|
870
|
-
if (schema.append || schema.overwrite) {
|
|
871
|
-
let confirm2 = options.y;
|
|
872
|
-
if (!confirm2) {
|
|
873
|
-
const response = await prompts({
|
|
874
|
-
type: "confirm",
|
|
875
|
-
name: "confirm",
|
|
876
|
-
message: `The file ${schema.fileName} already exists. Do you want to ${chalk.yellow(
|
|
877
|
-
`${schema.overwrite ? "overwrite" : "append"}`
|
|
878
|
-
)} the schema to the file?`
|
|
879
|
-
});
|
|
880
|
-
confirm2 = response.confirm;
|
|
881
|
-
}
|
|
882
|
-
if (confirm2) {
|
|
883
|
-
const exist = existsSync(path.join(cwd, schema.fileName));
|
|
884
|
-
if (!exist) {
|
|
885
|
-
await fs.mkdir(path.dirname(path.join(cwd, schema.fileName)), {
|
|
886
|
-
recursive: true
|
|
1293
|
+
async function generate(context) {
|
|
1294
|
+
const { logger, error, telemetry } = context;
|
|
1295
|
+
logger.debug('Starting generate command...');
|
|
1296
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_STARTED, {});
|
|
1297
|
+
const setupResult = await setupGenerateEnvironment(context);
|
|
1298
|
+
let { config, adapter } = setupResult;
|
|
1299
|
+
if (config) {
|
|
1300
|
+
let currentMode = 'unknown';
|
|
1301
|
+
if (isClientOptions(config)) {
|
|
1302
|
+
if (config.mode) currentMode = config.mode;
|
|
1303
|
+
} else if (isC15TOptions(config)) currentMode = 'backend';
|
|
1304
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.CONFIG_LOADED, {
|
|
1305
|
+
type: currentMode,
|
|
1306
|
+
exists: true
|
|
1307
|
+
});
|
|
1308
|
+
const shouldUpdate = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
|
|
1309
|
+
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}`)})`),
|
|
1310
|
+
initialValue: false
|
|
887
1311
|
});
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
1312
|
+
if (!shouldUpdate) {
|
|
1313
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_COMPLETED, {
|
|
1314
|
+
success: false,
|
|
1315
|
+
reason: 'user_cancelled'
|
|
1316
|
+
});
|
|
1317
|
+
return error.handleCancel('Operation cancelled.');
|
|
1318
|
+
}
|
|
1319
|
+
if (shouldUpdate) {
|
|
1320
|
+
await startOnboarding(context, config);
|
|
1321
|
+
logger.debug('Reloading configuration after update...');
|
|
1322
|
+
const postUpdateResult = await setupGenerateEnvironment(context);
|
|
1323
|
+
if (!postUpdateResult.config) {
|
|
1324
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_FAILED, {
|
|
1325
|
+
error: 'Failed to load configuration after update'
|
|
1326
|
+
});
|
|
1327
|
+
return error.handleError(new Error('Failed to load configuration after update.'), 'Configuration Error');
|
|
1328
|
+
}
|
|
1329
|
+
config = postUpdateResult.config;
|
|
1330
|
+
postUpdateResult.adapter;
|
|
1331
|
+
logger.info('Configuration updated successfully.');
|
|
1332
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_COMPLETED, {
|
|
1333
|
+
success: true,
|
|
1334
|
+
configUpdated: true
|
|
1335
|
+
});
|
|
1336
|
+
} else {
|
|
1337
|
+
logger.debug('Proceeding with existing configuration.');
|
|
1338
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_COMPLETED, {
|
|
1339
|
+
success: true,
|
|
1340
|
+
configUpdated: false
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
898
1343
|
} else {
|
|
899
|
-
|
|
900
|
-
|
|
1344
|
+
logger.info('No configuration found.');
|
|
1345
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.CONFIG_LOADED, {
|
|
1346
|
+
exists: false
|
|
1347
|
+
});
|
|
1348
|
+
const shouldOnboard = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
|
|
1349
|
+
message: 'No c15t configuration found. Would you like to create one now?',
|
|
1350
|
+
initialValue: true
|
|
1351
|
+
});
|
|
1352
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(shouldOnboard) || !shouldOnboard) {
|
|
1353
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_COMPLETED, {
|
|
1354
|
+
success: false,
|
|
1355
|
+
reason: 'onboarding_declined'
|
|
1356
|
+
});
|
|
1357
|
+
return error.handleCancel('Configuration setup cancelled.');
|
|
1358
|
+
}
|
|
1359
|
+
await startOnboarding(context);
|
|
1360
|
+
logger.debug('Reloading configuration after onboarding...');
|
|
1361
|
+
const postOnboardResult = await setupGenerateEnvironment(context);
|
|
1362
|
+
if (!postOnboardResult.config) {
|
|
1363
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_FAILED, {
|
|
1364
|
+
error: 'Failed to load configuration even after onboarding'
|
|
1365
|
+
});
|
|
1366
|
+
return error.handleError(new Error('Failed to load configuration even after onboarding.'), 'Configuration Error');
|
|
1367
|
+
}
|
|
1368
|
+
config = postOnboardResult.config;
|
|
1369
|
+
postOnboardResult.adapter;
|
|
1370
|
+
logger.info('New configuration loaded successfully.');
|
|
1371
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.GENERATE_COMPLETED, {
|
|
1372
|
+
success: true,
|
|
1373
|
+
newConfigCreated: true
|
|
1374
|
+
});
|
|
901
1375
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
)}?`
|
|
1376
|
+
}
|
|
1377
|
+
async function executeMigrations(context, runMigrationsFn) {
|
|
1378
|
+
const { logger, telemetry } = context;
|
|
1379
|
+
logger.info('Executing migrations...');
|
|
1380
|
+
const s = __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner();
|
|
1381
|
+
s.start('Running migrations...');
|
|
1382
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.MIGRATION_EXECUTED, {
|
|
1383
|
+
status: 'started'
|
|
911
1384
|
});
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1385
|
+
try {
|
|
1386
|
+
await runMigrationsFn();
|
|
1387
|
+
s.stop('Migrations completed successfully!');
|
|
1388
|
+
logger.success('🚀 Database migrated successfully');
|
|
1389
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.MIGRATION_EXECUTED, {
|
|
1390
|
+
status: 'completed'
|
|
1391
|
+
});
|
|
1392
|
+
} catch (error) {
|
|
1393
|
+
logger.error('Migration failed.');
|
|
1394
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.MIGRATION_EXECUTED, {
|
|
1395
|
+
status: 'failed',
|
|
1396
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1397
|
+
});
|
|
1398
|
+
context.error.handleError(error, 'Error running migrations');
|
|
924
1399
|
}
|
|
925
|
-
}
|
|
926
|
-
await fs.writeFile(
|
|
927
|
-
options.output || path.join(cwd, schema.fileName),
|
|
928
|
-
schema.code
|
|
929
|
-
);
|
|
930
|
-
logger.success("\u{1F680} Schema was generated successfully!");
|
|
931
|
-
process.exit(0);
|
|
932
1400
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1401
|
+
async function planMigrations(context, config, skipConfirmation) {
|
|
1402
|
+
const { logger } = context;
|
|
1403
|
+
logger.info('Planning migrations...');
|
|
1404
|
+
logger.debug('Config:', config);
|
|
1405
|
+
logger.debug(`Skip confirmation: ${skipConfirmation}`);
|
|
1406
|
+
const s = __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.spinner();
|
|
1407
|
+
s.start('Preparing migration plan...');
|
|
1408
|
+
let migrationData;
|
|
1409
|
+
try {
|
|
1410
|
+
migrationData = await (0, __WEBPACK_EXTERNAL_MODULE__c15t_backend_pkgs_migrations_80b6e3bd__.getMigrations)(config);
|
|
1411
|
+
logger.debug('Migration data:', migrationData);
|
|
1412
|
+
} catch (err) {
|
|
1413
|
+
s.stop('Migration preparation failed.');
|
|
1414
|
+
if (err instanceof Error) logger.error(err.message);
|
|
1415
|
+
else logger.error(String(err));
|
|
1416
|
+
logger.failed('Migration planning failed');
|
|
1417
|
+
return {
|
|
1418
|
+
shouldRun: false,
|
|
1419
|
+
runMigrationsFn: null
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
if (!migrationData) {
|
|
1423
|
+
s.stop('Could not retrieve migration data.');
|
|
1424
|
+
logger.failed('Migration planning failed');
|
|
1425
|
+
return {
|
|
1426
|
+
shouldRun: false,
|
|
1427
|
+
runMigrationsFn: null
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
const { toBeAdded, toBeCreated, runMigrations } = migrationData;
|
|
1431
|
+
logger.debug('Migrations to be added:', toBeAdded);
|
|
1432
|
+
logger.debug('Migrations to be created:', toBeCreated);
|
|
1433
|
+
if (!toBeAdded.length && !toBeCreated.length) {
|
|
1434
|
+
s.stop('No migrations needed.');
|
|
1435
|
+
logger.info('🚀 Database is up to date');
|
|
1436
|
+
return {
|
|
1437
|
+
shouldRun: false,
|
|
1438
|
+
runMigrationsFn: null
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
s.stop('Migration plan prepared.');
|
|
1442
|
+
logger.info('🔑 The following migrations will be applied:');
|
|
1443
|
+
for (const table of [
|
|
1444
|
+
...toBeCreated,
|
|
1445
|
+
...toBeAdded
|
|
1446
|
+
]){
|
|
1447
|
+
const fields = Object.keys(table.fields).join(', ');
|
|
1448
|
+
const tableName = table.table;
|
|
1449
|
+
logger.info(` + Table ${tableName}: Add fields [${fields}]`);
|
|
1450
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.log.message(` ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('+')} Table ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].yellow(tableName)}: Add fields [${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].green(fields)}]`);
|
|
1451
|
+
}
|
|
1452
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.log.message('');
|
|
1453
|
+
let shouldMigrate = skipConfirmation;
|
|
1454
|
+
if (!shouldMigrate) {
|
|
1455
|
+
shouldMigrate = await context.confirm('Apply these migrations to the database?', false);
|
|
1456
|
+
logger.debug(`User confirmation: ${shouldMigrate}`);
|
|
1457
|
+
}
|
|
1458
|
+
if (!shouldMigrate) {
|
|
1459
|
+
logger.failed('Migration cancelled');
|
|
1460
|
+
return {
|
|
1461
|
+
shouldRun: false,
|
|
1462
|
+
runMigrationsFn: null
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
logger.debug('Proceeding with migration execution');
|
|
1466
|
+
return {
|
|
1467
|
+
shouldRun: true,
|
|
1468
|
+
runMigrationsFn: runMigrations
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
async function loadConfigAndOnboard(context) {
|
|
1472
|
+
const { logger } = context;
|
|
1473
|
+
logger.debug('Checking for existing configuration...');
|
|
1474
|
+
let config;
|
|
1475
|
+
try {
|
|
1476
|
+
config = await context.config.loadConfig();
|
|
1477
|
+
} catch (error) {
|
|
1478
|
+
return context.error.handleError(error, 'Unexpected error during configuration loading');
|
|
1479
|
+
}
|
|
1480
|
+
if (!config) {
|
|
1481
|
+
logger.info('No config found, starting onboarding.');
|
|
1482
|
+
await startOnboarding(context);
|
|
1483
|
+
logger.debug('Exiting after triggering onboarding.');
|
|
1484
|
+
process.exit(0);
|
|
1485
|
+
}
|
|
1486
|
+
logger.debug('Configuration loaded successfully.');
|
|
1487
|
+
return config;
|
|
1488
|
+
}
|
|
1489
|
+
function validateAdapterIsKysely(context, adapter) {
|
|
1490
|
+
const { logger, error } = context;
|
|
1491
|
+
logger.debug('Validating adapter:', adapter);
|
|
1492
|
+
if (!adapter || 'kysely' !== adapter.id) {
|
|
1493
|
+
let message = 'Invalid or unsupported database configuration for migrate. Migrate command only works with built-in Kysely adapter.';
|
|
1494
|
+
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.";
|
|
1495
|
+
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.";
|
|
1496
|
+
error.handleError(new Error('Adapter validation failed: Not using Kysely'), message);
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
async function setupEnvironment(context) {
|
|
1500
|
+
const { logger, flags, cwd, error } = context;
|
|
1501
|
+
logger.info('Setting up migration environment...');
|
|
1502
|
+
logger.debug('Flags:', flags);
|
|
1503
|
+
logger.debug(`Working directory: ${cwd}`);
|
|
1504
|
+
if (!(0, __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__.existsSync)(cwd)) return error.handleError(new Error(`The directory "${cwd}" does not exist`), 'Migration setup failed');
|
|
1505
|
+
const config = await loadConfigAndOnboard(context);
|
|
1506
|
+
logger.debug('Config loaded:', config);
|
|
1507
|
+
let adapter;
|
|
1508
|
+
try {
|
|
1509
|
+
logger.debug('Initializing database adapter...');
|
|
1510
|
+
adapter = await (0, __WEBPACK_EXTERNAL_MODULE__c15t_backend_pkgs_db_adapters_cee37d0f__.getAdapter)(config);
|
|
1511
|
+
logger.debug('Adapter initialized:', adapter);
|
|
1512
|
+
} catch (e) {
|
|
1513
|
+
return error.handleError(e, 'Failed to initialize database adapter');
|
|
1514
|
+
}
|
|
1515
|
+
validateAdapterIsKysely(context, adapter);
|
|
1516
|
+
logger.info('✅ Environment setup complete');
|
|
1517
|
+
return {
|
|
1518
|
+
config,
|
|
1519
|
+
adapter: adapter
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
async function migrate(context) {
|
|
1523
|
+
const { logger, flags, telemetry } = context;
|
|
1524
|
+
logger.info('Starting migration process...');
|
|
1525
|
+
logger.debug('Context:', context);
|
|
1526
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.MIGRATION_STARTED, {
|
|
1527
|
+
skipConfirmation: true === flags.y
|
|
1011
1528
|
});
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1529
|
+
const skipConfirmation = flags.y;
|
|
1530
|
+
try {
|
|
1531
|
+
const { config } = await setupEnvironment(context);
|
|
1532
|
+
const planResult = await planMigrations(context, config, skipConfirmation);
|
|
1533
|
+
logger.debug('Plan result:', planResult);
|
|
1534
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.MIGRATION_PLANNED, {
|
|
1535
|
+
shouldRun: planResult.shouldRun,
|
|
1536
|
+
hasMigrations: !!planResult.runMigrationsFn
|
|
1537
|
+
});
|
|
1538
|
+
if (planResult.shouldRun && planResult.runMigrationsFn) {
|
|
1539
|
+
await executeMigrations(context, planResult.runMigrationsFn);
|
|
1540
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.MIGRATION_COMPLETED, {
|
|
1541
|
+
success: true
|
|
1542
|
+
});
|
|
1543
|
+
} else {
|
|
1544
|
+
logger.debug('Skipping migration execution based on plan result');
|
|
1545
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.MIGRATION_COMPLETED, {
|
|
1546
|
+
success: true,
|
|
1547
|
+
reason: planResult.shouldRun ? 'no_migrations_needed' : 'user_cancelled'
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
} catch (error) {
|
|
1551
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.MIGRATION_FAILED, {
|
|
1552
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1553
|
+
});
|
|
1554
|
+
context.error.handleError(error, 'An unexpected error occurred during the migration process');
|
|
1555
|
+
}
|
|
1023
1556
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
});
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1557
|
+
async function displayIntro(context, version) {
|
|
1558
|
+
const { logger } = context;
|
|
1559
|
+
logger.info(`${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].bold('Welcome!')} Let's get you set up.`);
|
|
1560
|
+
logger.message('');
|
|
1561
|
+
let figletText = 'c15t';
|
|
1562
|
+
try {
|
|
1563
|
+
figletText = await new Promise((resolve)=>{
|
|
1564
|
+
__WEBPACK_EXTERNAL_MODULE_figlet__["default"].text('c15t', {
|
|
1565
|
+
font: 'Nancyj-Improved',
|
|
1566
|
+
horizontalLayout: 'default',
|
|
1567
|
+
verticalLayout: 'default',
|
|
1568
|
+
width: 80,
|
|
1569
|
+
whitespaceBreak: true
|
|
1570
|
+
}, (err, data)=>{
|
|
1571
|
+
if (err) {
|
|
1572
|
+
logger.debug('Failed to generate figlet text');
|
|
1573
|
+
resolve('c15t');
|
|
1574
|
+
} else resolve(data || 'c15t');
|
|
1575
|
+
});
|
|
1576
|
+
});
|
|
1577
|
+
} catch (error) {
|
|
1578
|
+
logger.debug('Error generating figlet text', error);
|
|
1579
|
+
}
|
|
1580
|
+
const customColor = {
|
|
1581
|
+
teal10: (text)=>`\x1b[38;2;10;80;70m${text}\x1b[0m`,
|
|
1582
|
+
teal20: (text)=>`\x1b[38;2;15;100;90m${text}\x1b[0m`,
|
|
1583
|
+
teal30: (text)=>`\x1b[38;2;20;120;105m${text}\x1b[0m`,
|
|
1584
|
+
teal40: (text)=>`\x1b[38;2;25;150;130m${text}\x1b[0m`,
|
|
1585
|
+
teal50: (text)=>`\x1b[38;2;30;170;150m${text}\x1b[0m`,
|
|
1586
|
+
teal75: (text)=>`\x1b[38;2;34;211;187m${text}\x1b[0m`,
|
|
1587
|
+
teal90: (text)=>`\x1b[38;2;45;225;205m${text}\x1b[0m`,
|
|
1588
|
+
teal100: (text)=>`\x1b[38;2;65;235;220m${text}\x1b[0m`
|
|
1589
|
+
};
|
|
1590
|
+
const lines = figletText.split('\n');
|
|
1591
|
+
const coloredLines = lines.map((line, index)=>{
|
|
1592
|
+
const position = index / (lines.length - 1);
|
|
1593
|
+
if (position < 0.1) return customColor.teal10(line);
|
|
1594
|
+
if (position < 0.2) return customColor.teal20(line);
|
|
1595
|
+
if (position < 0.3) return customColor.teal30(line);
|
|
1596
|
+
if (position < 0.4) return customColor.teal40(line);
|
|
1597
|
+
if (position < 0.5) return customColor.teal50(line);
|
|
1598
|
+
if (position < 0.65) return customColor.teal75(line);
|
|
1599
|
+
if (position < 0.8) return customColor.teal90(line);
|
|
1600
|
+
return customColor.teal100(line);
|
|
1601
|
+
});
|
|
1602
|
+
logger.message(coloredLines.join('\n'));
|
|
1048
1603
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1604
|
+
function createConfigManagement(context) {
|
|
1605
|
+
const { logger, error } = context;
|
|
1606
|
+
return {
|
|
1607
|
+
loadConfig: async ()=>{
|
|
1608
|
+
logger.debug('Attempting to load configuration...');
|
|
1609
|
+
try {
|
|
1610
|
+
const configResult = await getConfig(context);
|
|
1611
|
+
const config = configResult ?? null;
|
|
1612
|
+
logger.debug('Config loading result:', config);
|
|
1613
|
+
if (config) logger.debug('Configuration loaded successfully.');
|
|
1614
|
+
else logger.debug('No configuration found.');
|
|
1615
|
+
return config;
|
|
1616
|
+
} catch (err) {
|
|
1617
|
+
return error.handleError(err, 'Error loading configuration');
|
|
1618
|
+
}
|
|
1619
|
+
},
|
|
1620
|
+
requireConfig: async ()=>{
|
|
1621
|
+
const config = await context.config.loadConfig();
|
|
1622
|
+
if (!config) return error.handleError(new Error('Configuration required but not found'), 'Missing required configuration');
|
|
1623
|
+
return config;
|
|
1624
|
+
},
|
|
1625
|
+
getPathAliases: (configDir)=>{
|
|
1626
|
+
const cwd = configDir || context.cwd;
|
|
1627
|
+
const tsConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, 'tsconfig.json');
|
|
1628
|
+
const jsConfigPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, 'jsconfig.json');
|
|
1629
|
+
const configPath = __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].existsSync(tsConfigPath) ? tsConfigPath : __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].existsSync(jsConfigPath) ? jsConfigPath : null;
|
|
1630
|
+
if (!configPath) return null;
|
|
1631
|
+
try {
|
|
1632
|
+
return extractAliasesFromConfigFile(context, configPath, cwd);
|
|
1633
|
+
} catch (extractError) {
|
|
1634
|
+
logger.warn(`Error extracting path aliases from ${configPath}:`, extractError);
|
|
1635
|
+
return null;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
function stripJsonComments(jsonString) {
|
|
1641
|
+
return jsonString.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g)=>g ? '' : m).replace(/,(?=\s*[}\]])/g, '');
|
|
1642
|
+
}
|
|
1643
|
+
function extractAliasesFromConfigFile(context, configPath, cwd) {
|
|
1644
|
+
try {
|
|
1645
|
+
const configContent = __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].readFileSync(configPath, 'utf8');
|
|
1646
|
+
const strippedConfigContent = stripJsonComments(configContent);
|
|
1647
|
+
const config = JSON.parse(strippedConfigContent);
|
|
1648
|
+
const { paths = {}, baseUrl = '.' } = config.compilerOptions || {};
|
|
1649
|
+
const result = {};
|
|
1650
|
+
const obj = Object.entries(paths);
|
|
1651
|
+
for (const [alias, aliasPaths] of obj)for (const aliasedPath of aliasPaths){
|
|
1652
|
+
const resolvedBaseUrl = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, baseUrl);
|
|
1653
|
+
const finalAlias = '*' === alias.slice(-1) ? alias.slice(0, -1) : alias;
|
|
1654
|
+
const finalAliasedPath = '*' === aliasedPath.slice(-1) ? aliasedPath.slice(0, -1) : aliasedPath;
|
|
1655
|
+
result[finalAlias || ''] = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(resolvedBaseUrl, finalAliasedPath);
|
|
1656
|
+
}
|
|
1657
|
+
if (hasSvelteKit(cwd)) addSvelteKitEnvModules(result);
|
|
1658
|
+
return result;
|
|
1659
|
+
} catch (error) {
|
|
1660
|
+
context.logger.warn(`Error parsing config file ${configPath}`, error);
|
|
1661
|
+
return null;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
function hasSvelteKit(cwd) {
|
|
1665
|
+
try {
|
|
1666
|
+
const packageJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, 'package.json');
|
|
1667
|
+
if (!__WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].existsSync(packageJsonPath)) return false;
|
|
1668
|
+
const packageJson = JSON.parse(__WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].readFileSync(packageJsonPath, 'utf8'));
|
|
1669
|
+
const deps = {
|
|
1670
|
+
...packageJson.dependencies,
|
|
1671
|
+
...packageJson.devDependencies
|
|
1672
|
+
};
|
|
1673
|
+
return '@sveltejs/kit' in deps;
|
|
1674
|
+
} catch (error) {
|
|
1675
|
+
return false;
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
function addSvelteKitEnvModules(aliases) {
|
|
1679
|
+
aliases['$app/'] = '$app/';
|
|
1680
|
+
aliases['$lib/'] = '$lib/';
|
|
1681
|
+
aliases['$env/'] = '$env/';
|
|
1682
|
+
aliases['$service-worker'] = '$service-worker';
|
|
1683
|
+
}
|
|
1684
|
+
function createErrorHandlers(context) {
|
|
1685
|
+
const { logger } = context;
|
|
1686
|
+
return {
|
|
1687
|
+
handleError: (error, message)=>{
|
|
1688
|
+
logger.error(message, error);
|
|
1689
|
+
if (error instanceof Error) logger.error(error.message);
|
|
1690
|
+
else logger.error(String(error));
|
|
1691
|
+
logger.failed(`${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].red('Operation failed unexpectedly.')}`);
|
|
1692
|
+
process.exit(1);
|
|
1693
|
+
},
|
|
1694
|
+
handleCancel: (message = 'Operation cancelled.')=>{
|
|
1695
|
+
logger.debug(`Handling cancellation: ${message}`);
|
|
1696
|
+
logger.failed(message);
|
|
1697
|
+
process.exit(0);
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1701
|
+
function createFileSystem(context) {
|
|
1702
|
+
const { logger, cwd } = context;
|
|
1703
|
+
return {
|
|
1704
|
+
getPackageInfo: ()=>{
|
|
1705
|
+
logger.debug('Reading package.json');
|
|
1706
|
+
const packageJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, 'package.json');
|
|
1707
|
+
logger.debug(`package.json path: ${packageJsonPath}`);
|
|
1708
|
+
try {
|
|
1709
|
+
const packageInfo = __WEBPACK_EXTERNAL_MODULE_fs_extra_ce68a66b__["default"].readJSONSync(packageJsonPath);
|
|
1710
|
+
logger.debug('Successfully read package.json');
|
|
1711
|
+
return {
|
|
1712
|
+
name: packageInfo?.name || 'unknown',
|
|
1713
|
+
version: packageInfo?.version || 'unknown',
|
|
1714
|
+
...packageInfo
|
|
1715
|
+
};
|
|
1716
|
+
} catch (error) {
|
|
1717
|
+
logger.error(`Error reading package.json at ${packageJsonPath}:`, error);
|
|
1718
|
+
return {
|
|
1719
|
+
name: 'unknown',
|
|
1720
|
+
version: 'unknown'
|
|
1721
|
+
};
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
const globalFlags = [
|
|
1727
|
+
{
|
|
1728
|
+
names: [
|
|
1729
|
+
'--help',
|
|
1730
|
+
'-h'
|
|
1731
|
+
],
|
|
1732
|
+
description: 'Show this help message.',
|
|
1733
|
+
type: 'special',
|
|
1734
|
+
expectsValue: false
|
|
1735
|
+
},
|
|
1736
|
+
{
|
|
1737
|
+
names: [
|
|
1738
|
+
'--version',
|
|
1739
|
+
'-v'
|
|
1740
|
+
],
|
|
1741
|
+
description: 'Show the CLI version.',
|
|
1742
|
+
type: 'special',
|
|
1743
|
+
expectsValue: false
|
|
1744
|
+
},
|
|
1745
|
+
{
|
|
1746
|
+
names: [
|
|
1747
|
+
'--logger'
|
|
1748
|
+
],
|
|
1749
|
+
description: 'Set log level (fatal, error, warn, info, debug).',
|
|
1750
|
+
type: 'string',
|
|
1751
|
+
expectsValue: true
|
|
1752
|
+
},
|
|
1753
|
+
{
|
|
1754
|
+
names: [
|
|
1755
|
+
'--config'
|
|
1756
|
+
],
|
|
1757
|
+
description: 'Specify path to configuration file.',
|
|
1758
|
+
type: 'string',
|
|
1759
|
+
expectsValue: true
|
|
1760
|
+
},
|
|
1761
|
+
{
|
|
1762
|
+
names: [
|
|
1763
|
+
'-y'
|
|
1764
|
+
],
|
|
1765
|
+
description: 'Skip confirmation prompts (use with caution).',
|
|
1766
|
+
type: 'boolean',
|
|
1767
|
+
expectsValue: false
|
|
1768
|
+
},
|
|
1769
|
+
{
|
|
1770
|
+
names: [
|
|
1771
|
+
'--no-telemetry'
|
|
1772
|
+
],
|
|
1773
|
+
description: 'Disable telemetry data collection.',
|
|
1774
|
+
type: 'boolean',
|
|
1775
|
+
expectsValue: false
|
|
1776
|
+
}
|
|
1777
|
+
];
|
|
1778
|
+
function parseCliArgs(rawArgs, commands) {
|
|
1779
|
+
const parsedFlags = {};
|
|
1780
|
+
const potentialCommandArgsAndUndefined = [];
|
|
1781
|
+
let commandName;
|
|
1782
|
+
const commandArgs = [];
|
|
1783
|
+
for (const flag of globalFlags){
|
|
1784
|
+
const primaryName = flag.names[0]?.replace(/^--/, '').replace(/^-/, '');
|
|
1785
|
+
if (primaryName) parsedFlags[primaryName] = 'boolean' === flag.type ? false : void 0;
|
|
1786
|
+
}
|
|
1787
|
+
for(let i = 0; i < rawArgs.length; i++){
|
|
1788
|
+
const arg = rawArgs[i];
|
|
1789
|
+
if ('string' != typeof arg) continue;
|
|
1790
|
+
let argIsFlagOrValue = false;
|
|
1791
|
+
for (const flag of globalFlags)if (flag.names.includes(arg)) {
|
|
1792
|
+
const primaryName = flag.names[0]?.replace(/^--/, '').replace(/^-/, '');
|
|
1793
|
+
if (primaryName) {
|
|
1794
|
+
argIsFlagOrValue = true;
|
|
1795
|
+
if ('boolean' === flag.type) parsedFlags[primaryName] = true;
|
|
1796
|
+
else if (flag.expectsValue) {
|
|
1797
|
+
const nextArg = rawArgs[i + 1];
|
|
1798
|
+
if (nextArg && !nextArg.startsWith('-')) {
|
|
1799
|
+
parsedFlags[primaryName] = nextArg;
|
|
1800
|
+
i++;
|
|
1801
|
+
} else __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.log.warn(formatLogMessage('warn', `Flag ${arg} expects a value, but none was found or the next item is a flag.`));
|
|
1802
|
+
} else parsedFlags[primaryName] = true;
|
|
1803
|
+
}
|
|
1804
|
+
break;
|
|
1805
|
+
}
|
|
1806
|
+
if (!argIsFlagOrValue) potentialCommandArgsAndUndefined.push(arg);
|
|
1807
|
+
}
|
|
1808
|
+
const potentialCommandArgs = potentialCommandArgsAndUndefined.filter((arg)=>'string' == typeof arg);
|
|
1809
|
+
commandName = potentialCommandArgs.find((arg)=>commands.some((cmd)=>cmd.name === arg));
|
|
1810
|
+
for (const arg of potentialCommandArgs)if (arg !== commandName) commandArgs.push(arg);
|
|
1811
|
+
return {
|
|
1812
|
+
commandName,
|
|
1813
|
+
commandArgs,
|
|
1814
|
+
parsedFlags
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1817
|
+
function createUserInteraction(context) {
|
|
1818
|
+
const { logger, error } = context;
|
|
1819
|
+
return {
|
|
1820
|
+
confirm: async (message, initialValue)=>{
|
|
1821
|
+
logger.debug(`Confirm action: "${message}", Initial: ${initialValue}`);
|
|
1822
|
+
const confirmed = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.confirm({
|
|
1823
|
+
message,
|
|
1824
|
+
initialValue
|
|
1825
|
+
});
|
|
1826
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(confirmed)) {
|
|
1827
|
+
error.handleCancel();
|
|
1828
|
+
return false;
|
|
1829
|
+
}
|
|
1830
|
+
logger.debug(`Confirmation result: ${confirmed}`);
|
|
1831
|
+
return confirmed;
|
|
1832
|
+
}
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
function createCliContext(rawArgs, cwd, commands) {
|
|
1836
|
+
const { commandName, commandArgs, parsedFlags } = parseCliArgs(rawArgs, commands);
|
|
1837
|
+
let desiredLogLevel = 'info';
|
|
1838
|
+
const levelArg = parsedFlags.logger;
|
|
1839
|
+
if ('string' == typeof levelArg) if (validLogLevels.includes(levelArg)) desiredLogLevel = levelArg;
|
|
1840
|
+
else console.warn(`[CLI Setup] Invalid log level '${levelArg}' provided via --logger. Using default 'info'.`);
|
|
1841
|
+
else if (true === levelArg) console.warn("[CLI Setup] --logger flag found but no level specified. Using default 'info'.");
|
|
1842
|
+
const logger = createCliLogger(desiredLogLevel);
|
|
1843
|
+
logger.debug(`Logger initialized with level: ${desiredLogLevel}`);
|
|
1844
|
+
const baseContext = {
|
|
1845
|
+
logger,
|
|
1846
|
+
flags: parsedFlags,
|
|
1847
|
+
commandName,
|
|
1848
|
+
commandArgs,
|
|
1849
|
+
cwd
|
|
1850
|
+
};
|
|
1851
|
+
const context = baseContext;
|
|
1852
|
+
context.error = createErrorHandlers(context);
|
|
1853
|
+
const userInteraction = createUserInteraction(context);
|
|
1854
|
+
context.confirm = userInteraction.confirm;
|
|
1855
|
+
context.config = createConfigManagement(context);
|
|
1856
|
+
context.fs = createFileSystem(context);
|
|
1857
|
+
const telemetryDisabled = true === parsedFlags['no-telemetry'];
|
|
1858
|
+
context.telemetry = createTelemetry({
|
|
1859
|
+
disabled: telemetryDisabled,
|
|
1860
|
+
defaultProperties: {
|
|
1861
|
+
cliVersion: context.fs.getPackageInfo().version
|
|
1862
|
+
},
|
|
1863
|
+
logger: context.logger
|
|
1864
|
+
});
|
|
1865
|
+
context.telemetry.setLogLevel(desiredLogLevel);
|
|
1866
|
+
if (telemetryDisabled) logger.debug('Telemetry is disabled by user preference');
|
|
1867
|
+
else logger.debug('Telemetry initialized');
|
|
1868
|
+
logger.debug('CLI context fully initialized with all utilities');
|
|
1869
|
+
return context;
|
|
1870
|
+
}
|
|
1871
|
+
const src_commands = [
|
|
1872
|
+
{
|
|
1873
|
+
name: 'generate',
|
|
1874
|
+
label: 'generate',
|
|
1875
|
+
hint: 'Generate schema/code',
|
|
1876
|
+
description: 'Generate schema/code based on your c15t config.',
|
|
1877
|
+
action: (context)=>generate(context)
|
|
1878
|
+
},
|
|
1879
|
+
{
|
|
1880
|
+
name: 'migrate',
|
|
1881
|
+
label: 'migrate',
|
|
1882
|
+
hint: 'Run database migrations',
|
|
1883
|
+
description: 'Run database migrations based on your c15t config.',
|
|
1884
|
+
action: (context)=>migrate(context)
|
|
1885
|
+
},
|
|
1886
|
+
{
|
|
1887
|
+
name: 'github',
|
|
1888
|
+
label: 'Github',
|
|
1889
|
+
hint: 'Star us on GitHub',
|
|
1890
|
+
description: 'Open our GitHub repository to give us a star.',
|
|
1891
|
+
action: async (context)=>{
|
|
1892
|
+
const { logger } = context;
|
|
1893
|
+
logger.note(`We're building c15t as an ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].bold('open source')} project to make consent management more accessible.\nIf you find this useful, we'd really appreciate a GitHub star - it helps others discover the project!`, '⭐ Star Us on GitHub');
|
|
1894
|
+
await (0, __WEBPACK_EXTERNAL_MODULE_open__["default"])('https://github.com/c15t/c15t');
|
|
1895
|
+
logger.success('Thank you for your support!');
|
|
1896
|
+
}
|
|
1897
|
+
},
|
|
1898
|
+
{
|
|
1899
|
+
name: 'docs',
|
|
1900
|
+
label: 'c15t docs',
|
|
1901
|
+
hint: 'Open documentation',
|
|
1902
|
+
description: 'Open the c15t documentation in your browser.',
|
|
1903
|
+
action: async (context)=>{
|
|
1904
|
+
const { logger } = context;
|
|
1905
|
+
await (0, __WEBPACK_EXTERNAL_MODULE_open__["default"])('https://c15t.com/docs?ref=cli');
|
|
1906
|
+
logger.success('Documentation opened in your browser.');
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
];
|
|
1052
1910
|
async function main() {
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1911
|
+
const rawArgs = process.argv.slice(2);
|
|
1912
|
+
const cwd = process.cwd();
|
|
1913
|
+
const context = createCliContext(rawArgs, cwd, src_commands);
|
|
1914
|
+
const { logger, flags, commandName, commandArgs, error, telemetry } = context;
|
|
1915
|
+
const packageInfo = context.fs.getPackageInfo();
|
|
1916
|
+
const version = packageInfo.version;
|
|
1917
|
+
if (!telemetry.isDisabled()) logger.note(`c15t collects anonymous usage data to help improve the CLI.
|
|
1918
|
+
This data is not personally identifiable and helps us prioritize features.
|
|
1919
|
+
To disable telemetry, use the ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('--no-telemetry')}
|
|
1920
|
+
flag or set ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan('C15T_TELEMETRY_DISABLED=1')} in your environment.`, `${formatLogMessage('info', 'Telemetry Notice')}`);
|
|
1921
|
+
try {
|
|
1922
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.CLI_INVOKED, {
|
|
1923
|
+
version,
|
|
1924
|
+
nodeVersion: process.version,
|
|
1925
|
+
platform: process.platform
|
|
1926
|
+
});
|
|
1927
|
+
telemetry.flushSync();
|
|
1928
|
+
} catch (error) {
|
|
1929
|
+
logger.debug('Failed to track CLI invocation:', error);
|
|
1930
|
+
}
|
|
1931
|
+
if (flags.version) {
|
|
1932
|
+
logger.debug('Version flag detected');
|
|
1933
|
+
logger.message(`c15t CLI version ${version}`);
|
|
1934
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.VERSION_DISPLAYED, {
|
|
1935
|
+
version
|
|
1936
|
+
});
|
|
1937
|
+
telemetry.flushSync();
|
|
1938
|
+
await telemetry.shutdown();
|
|
1939
|
+
process.exit(0);
|
|
1940
|
+
}
|
|
1941
|
+
if (flags.help) {
|
|
1942
|
+
logger.debug('Help flag detected. Displaying help and exiting.');
|
|
1943
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.HELP_DISPLAYED, {
|
|
1944
|
+
version
|
|
1945
|
+
});
|
|
1946
|
+
telemetry.flushSync();
|
|
1947
|
+
showHelpMenu(context, version, src_commands, globalFlags);
|
|
1948
|
+
await telemetry.shutdown();
|
|
1949
|
+
process.exit(0);
|
|
1950
|
+
}
|
|
1951
|
+
logger.debug('Raw process arguments:', process.argv);
|
|
1952
|
+
logger.debug('Parsed command name:', commandName);
|
|
1953
|
+
logger.debug('Parsed command args:', commandArgs);
|
|
1954
|
+
logger.debug('Parsed global flags:', flags);
|
|
1955
|
+
await displayIntro(context, version);
|
|
1956
|
+
logger.debug(`Current working directory: ${cwd}`);
|
|
1957
|
+
logger.debug(`Config path flag: ${flags.config}`);
|
|
1958
|
+
let clientConfig;
|
|
1959
|
+
let backendConfig;
|
|
1960
|
+
try {
|
|
1961
|
+
const loadedConfig = await getConfig(context);
|
|
1962
|
+
if (loadedConfig) if (isClientOptions(loadedConfig)) clientConfig = loadedConfig;
|
|
1963
|
+
else if (isC15TOptions(loadedConfig)) backendConfig = loadedConfig;
|
|
1964
|
+
else logger.warn('Loaded configuration is of an unknown type.');
|
|
1965
|
+
if (loadedConfig) telemetry.trackEvent(telemetry_TelemetryEventName.CONFIG_LOADED, {
|
|
1966
|
+
configType: clientConfig ? 'client' : backendConfig ? 'backend' : 'unknown',
|
|
1967
|
+
hasBackend: Boolean(backendConfig)
|
|
1968
|
+
});
|
|
1969
|
+
} catch (loadError) {
|
|
1970
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.CONFIG_ERROR, {
|
|
1971
|
+
error: loadError instanceof Error ? loadError.message : String(loadError)
|
|
1972
|
+
});
|
|
1973
|
+
return error.handleError(loadError, 'An unexpected error occurred during configuration loading');
|
|
1974
|
+
}
|
|
1975
|
+
if (!clientConfig) {
|
|
1976
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.ONBOARDING_STARTED, {});
|
|
1977
|
+
await startOnboarding(context);
|
|
1978
|
+
await telemetry.shutdown();
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
const coloredConsentIo = __WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyanBright('consent.io');
|
|
1982
|
+
const backendStatus = backendConfig ? 'Backend configuration loaded' : `Using ${coloredConsentIo} for your c15t deployment`;
|
|
1983
|
+
logger.info(`Client configuration successfully loaded and validated \n ${backendStatus}`);
|
|
1984
|
+
logger.debug('Client config details:', clientConfig);
|
|
1985
|
+
if (backendConfig) logger.debug('Backend config details:', backendConfig);
|
|
1986
|
+
try {
|
|
1987
|
+
if (commandName) {
|
|
1988
|
+
const command = src_commands.find((cmd)=>cmd.name === commandName);
|
|
1989
|
+
if (command) {
|
|
1990
|
+
logger.info(`Executing command: ${command.name}`);
|
|
1991
|
+
telemetry.trackCommand(command.name, commandArgs, flags);
|
|
1992
|
+
await command.action(context);
|
|
1993
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.COMMAND_SUCCEEDED, {
|
|
1994
|
+
command: command.name,
|
|
1995
|
+
executionTime: Date.now() - performance.now()
|
|
1996
|
+
});
|
|
1997
|
+
telemetry.flushSync();
|
|
1998
|
+
} else {
|
|
1999
|
+
logger.error(`Unknown command: ${commandName}`);
|
|
2000
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.COMMAND_UNKNOWN, {
|
|
2001
|
+
unknownCommand: commandName
|
|
2002
|
+
});
|
|
2003
|
+
telemetry.flushSync();
|
|
2004
|
+
logger.info('Run c15t --help to see available commands.');
|
|
2005
|
+
await telemetry.shutdown();
|
|
2006
|
+
process.exit(1);
|
|
2007
|
+
}
|
|
2008
|
+
} else {
|
|
2009
|
+
logger.debug('No command specified, entering interactive selection.');
|
|
2010
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.INTERACTIVE_MENU_OPENED, {});
|
|
2011
|
+
const promptOptions = src_commands.map((cmd)=>({
|
|
2012
|
+
value: cmd.name,
|
|
2013
|
+
label: cmd.label,
|
|
2014
|
+
hint: cmd.hint
|
|
2015
|
+
}));
|
|
2016
|
+
promptOptions.push({
|
|
2017
|
+
value: 'exit',
|
|
2018
|
+
label: 'exit',
|
|
2019
|
+
hint: 'Close the CLI'
|
|
2020
|
+
});
|
|
2021
|
+
const selectedCommandName = await __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.select({
|
|
2022
|
+
message: formatLogMessage('info', 'Which command would you like to run?'),
|
|
2023
|
+
options: promptOptions
|
|
2024
|
+
});
|
|
2025
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(selectedCommandName) || 'exit' === selectedCommandName) {
|
|
2026
|
+
logger.debug('Interactive selection cancelled or exit chosen.');
|
|
2027
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.INTERACTIVE_MENU_EXITED, {
|
|
2028
|
+
action: __WEBPACK_EXTERNAL_MODULE__clack_prompts_3cae1695__.isCancel(selectedCommandName) ? 'cancelled' : 'exit'
|
|
2029
|
+
});
|
|
2030
|
+
context.error.handleCancel('Operation cancelled.');
|
|
2031
|
+
} else {
|
|
2032
|
+
const selectedCommand = src_commands.find((cmd)=>cmd.name === selectedCommandName);
|
|
2033
|
+
if (selectedCommand) {
|
|
2034
|
+
logger.debug(`User selected command: ${selectedCommand.name}`);
|
|
2035
|
+
telemetry.trackCommand(selectedCommand.name, [], flags);
|
|
2036
|
+
await selectedCommand.action(context);
|
|
2037
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.COMMAND_SUCCEEDED, {
|
|
2038
|
+
command: selectedCommand.name,
|
|
2039
|
+
executionTime: Date.now() - performance.now()
|
|
2040
|
+
});
|
|
2041
|
+
telemetry.flushSync();
|
|
2042
|
+
} else {
|
|
2043
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.COMMAND_UNKNOWN, {
|
|
2044
|
+
unknownCommand: String(selectedCommandName)
|
|
2045
|
+
});
|
|
2046
|
+
telemetry.flushSync();
|
|
2047
|
+
error.handleError(new Error(`Command '${selectedCommandName}' not found`), 'An internal error occurred');
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
logger.debug('Command execution completed');
|
|
2052
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.CLI_COMPLETED, {
|
|
2053
|
+
success: true
|
|
2054
|
+
});
|
|
2055
|
+
telemetry.flushSync();
|
|
2056
|
+
} catch (executionError) {
|
|
2057
|
+
telemetry.trackEvent(telemetry_TelemetryEventName.COMMAND_FAILED, {
|
|
2058
|
+
command: commandName,
|
|
2059
|
+
error: executionError instanceof Error ? executionError.message : String(executionError)
|
|
2060
|
+
});
|
|
2061
|
+
telemetry.flushSync();
|
|
2062
|
+
error.handleError(executionError, 'An unexpected error occurred during command execution');
|
|
2063
|
+
}
|
|
2064
|
+
await telemetry.shutdown();
|
|
1057
2065
|
}
|
|
1058
2066
|
main();
|
|
2067
|
+
export { main };
|