@c15t/cli 0.0.1-rc.24 → 1.0.0

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