@c15t/cli 1.8.3 → 2.0.0-rc.1

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 (187) hide show
  1. package/dist/760.mjs +1720 -0
  2. package/dist/__tests__/auth/config-store.test.d.ts +2 -0
  3. package/dist/__tests__/auth/config-store.test.d.ts.map +1 -0
  4. package/dist/__tests__/constants.test.d.ts +2 -0
  5. package/dist/__tests__/constants.test.d.ts.map +1 -0
  6. package/dist/__tests__/detection/layout.test.d.ts +2 -0
  7. package/dist/__tests__/detection/layout.test.d.ts.map +1 -0
  8. package/dist/__tests__/mocks/prompts.d.ts +25 -0
  9. package/dist/__tests__/mocks/prompts.d.ts.map +1 -0
  10. package/dist/__tests__/utils/validation.test.d.ts +2 -0
  11. package/dist/__tests__/utils/validation.test.d.ts.map +1 -0
  12. package/dist/auth/config-store.d.ts +63 -0
  13. package/dist/auth/config-store.d.ts.map +1 -0
  14. package/dist/auth/device-flow.d.ts +41 -0
  15. package/dist/auth/device-flow.d.ts.map +1 -0
  16. package/dist/auth/index.d.ts +7 -0
  17. package/dist/auth/index.d.ts.map +1 -0
  18. package/dist/auth/types.d.ts +90 -0
  19. package/dist/auth/types.d.ts.map +1 -0
  20. package/dist/commands/auth/index.d.ts +21 -0
  21. package/dist/commands/auth/index.d.ts.map +1 -0
  22. package/dist/commands/generate/index.d.ts +23 -2
  23. package/dist/commands/generate/index.d.ts.map +1 -1
  24. package/dist/commands/generate/options/c15t-mode.d.ts.map +1 -1
  25. package/dist/commands/generate/options/custom-mode.d.ts +3 -1
  26. package/dist/commands/generate/options/custom-mode.d.ts.map +1 -1
  27. package/dist/commands/generate/options/offline-mode.d.ts.map +1 -1
  28. package/dist/commands/generate/options/self-hosted-mode.d.ts.map +1 -1
  29. package/dist/commands/generate/options/shared/backend-options.d.ts +26 -0
  30. package/dist/commands/generate/options/shared/backend-options.d.ts.map +1 -0
  31. package/dist/commands/generate/options/shared/dev-tools.d.ts +9 -0
  32. package/dist/commands/generate/options/shared/dev-tools.d.ts.map +1 -0
  33. package/dist/commands/generate/options/shared/frontend-ui-options.d.ts +44 -0
  34. package/dist/commands/generate/options/shared/frontend-ui-options.d.ts.map +1 -0
  35. package/dist/commands/generate/options/shared/index.d.ts +9 -0
  36. package/dist/commands/generate/options/shared/index.d.ts.map +1 -0
  37. package/dist/commands/generate/options/shared/ssr.d.ts +21 -0
  38. package/dist/commands/generate/options/shared/ssr.d.ts.map +1 -0
  39. package/dist/commands/generate/options/utils/generate-files.d.ts +10 -2
  40. package/dist/commands/generate/options/utils/generate-files.d.ts.map +1 -1
  41. package/dist/commands/generate/preflight.d.ts +31 -0
  42. package/dist/commands/generate/preflight.d.ts.map +1 -0
  43. package/dist/commands/generate/prompts/expanded-theme.d.ts +46 -0
  44. package/dist/commands/generate/prompts/expanded-theme.d.ts.map +1 -0
  45. package/dist/commands/generate/prompts/index.d.ts +10 -0
  46. package/dist/commands/generate/prompts/index.d.ts.map +1 -0
  47. package/dist/commands/generate/prompts/instance.d.ts +33 -0
  48. package/dist/commands/generate/prompts/instance.d.ts.map +1 -0
  49. package/dist/commands/generate/prompts/mode-select.d.ts +42 -0
  50. package/dist/commands/generate/prompts/mode-select.d.ts.map +1 -0
  51. package/dist/commands/generate/prompts/scripts.d.ts +66 -0
  52. package/dist/commands/generate/prompts/scripts.d.ts.map +1 -0
  53. package/dist/commands/generate/prompts/theme.d.ts +46 -0
  54. package/dist/commands/generate/prompts/theme.d.ts.map +1 -0
  55. package/dist/commands/generate/prompts/ui-style.d.ts +36 -0
  56. package/dist/commands/generate/prompts/ui-style.d.ts.map +1 -0
  57. package/dist/commands/generate/summary.d.ts +37 -0
  58. package/dist/commands/generate/summary.d.ts.map +1 -0
  59. package/dist/commands/generate/templates/config.d.ts +7 -6
  60. package/dist/commands/generate/templates/config.d.ts.map +1 -1
  61. package/dist/commands/generate/templates/css.d.ts +12 -0
  62. package/dist/commands/generate/templates/css.d.ts.map +1 -0
  63. package/dist/commands/generate/templates/index.d.ts +1 -1
  64. package/dist/commands/generate/templates/index.d.ts.map +1 -1
  65. package/dist/commands/generate/templates/layout.d.ts +7 -0
  66. package/dist/commands/generate/templates/layout.d.ts.map +1 -1
  67. package/dist/commands/generate/templates/next/app/layout.d.ts +9 -2
  68. package/dist/commands/generate/templates/next/app/layout.d.ts.map +1 -1
  69. package/dist/commands/generate/templates/next/index.d.ts +7 -0
  70. package/dist/commands/generate/templates/next/index.d.ts.map +1 -1
  71. package/dist/commands/generate/templates/next/pages/layout.d.ts +3 -1
  72. package/dist/commands/generate/templates/next/pages/layout.d.ts.map +1 -1
  73. package/dist/commands/generate/templates/shared/components.d.ts +69 -0
  74. package/dist/commands/generate/templates/shared/components.d.ts.map +1 -0
  75. package/dist/commands/generate/templates/shared/directory.d.ts +71 -0
  76. package/dist/commands/generate/templates/shared/directory.d.ts.map +1 -0
  77. package/dist/commands/generate/templates/shared/expanded-components.d.ts +50 -0
  78. package/dist/commands/generate/templates/shared/expanded-components.d.ts.map +1 -0
  79. package/dist/commands/generate/templates/shared/framework-config.d.ts +18 -0
  80. package/dist/commands/generate/templates/shared/framework-config.d.ts.map +1 -0
  81. package/dist/commands/generate/templates/shared/layout-pipeline.d.ts +47 -0
  82. package/dist/commands/generate/templates/shared/layout-pipeline.d.ts.map +1 -0
  83. package/dist/commands/generate/templates/shared/module-specifier.d.ts +68 -0
  84. package/dist/commands/generate/templates/shared/module-specifier.d.ts.map +1 -0
  85. package/dist/commands/generate/templates/shared/options.d.ts +37 -20
  86. package/dist/commands/generate/templates/shared/options.d.ts.map +1 -1
  87. package/dist/commands/generate/templates/shared/scripts.d.ts +62 -0
  88. package/dist/commands/generate/templates/shared/scripts.d.ts.map +1 -0
  89. package/dist/commands/generate/templates/shared/server-components.d.ts +38 -0
  90. package/dist/commands/generate/templates/shared/server-components.d.ts.map +1 -0
  91. package/dist/commands/index.d.ts +8 -0
  92. package/dist/commands/index.d.ts.map +1 -0
  93. package/dist/commands/instances/index.d.ts +22 -0
  94. package/dist/commands/instances/index.d.ts.map +1 -0
  95. package/dist/commands/self-host/migrate/migrator-result.d.ts +1 -1
  96. package/dist/commands/self-host/migrate/migrator-result.d.ts.map +1 -1
  97. package/dist/commands/self-host/migrate/orm-result.d.ts +1 -1
  98. package/dist/commands/self-host/migrate/orm-result.d.ts.map +1 -1
  99. package/dist/commands/self-host/migrate/read-config.d.ts +1 -1
  100. package/dist/commands/self-host/migrate/read-config.d.ts.map +1 -1
  101. package/dist/constants.d.ts +101 -0
  102. package/dist/constants.d.ts.map +1 -0
  103. package/dist/context/framework-detection.d.ts +1 -0
  104. package/dist/context/framework-detection.d.ts.map +1 -1
  105. package/dist/context/types.d.ts +3 -3
  106. package/dist/context/types.d.ts.map +1 -1
  107. package/dist/core/context.d.ts +24 -0
  108. package/dist/core/context.d.ts.map +1 -0
  109. package/dist/core/errors.d.ts +214 -0
  110. package/dist/core/errors.d.ts.map +1 -0
  111. package/dist/core/index.d.ts +9 -0
  112. package/dist/core/index.d.ts.map +1 -0
  113. package/dist/core/logger.d.ts +50 -0
  114. package/dist/core/logger.d.ts.map +1 -0
  115. package/dist/core/parser.d.ts +35 -0
  116. package/dist/core/parser.d.ts.map +1 -0
  117. package/dist/core/telemetry.d.ts +78 -0
  118. package/dist/core/telemetry.d.ts.map +1 -0
  119. package/dist/detection/framework.d.ts +31 -0
  120. package/dist/detection/framework.d.ts.map +1 -0
  121. package/dist/detection/index.d.ts +7 -0
  122. package/dist/detection/index.d.ts.map +1 -0
  123. package/dist/detection/layout.d.ts +36 -0
  124. package/dist/detection/layout.d.ts.map +1 -0
  125. package/dist/detection/package-manager.d.ts +31 -0
  126. package/dist/detection/package-manager.d.ts.map +1 -0
  127. package/dist/index.d.ts +9 -0
  128. package/dist/index.d.ts.map +1 -1
  129. package/dist/index.mjs +2066 -1836
  130. package/dist/machines/generate/actions.d.ts +116 -0
  131. package/dist/machines/generate/actions.d.ts.map +1 -0
  132. package/dist/machines/generate/actors/dependencies.d.ts +43 -0
  133. package/dist/machines/generate/actors/dependencies.d.ts.map +1 -0
  134. package/dist/machines/generate/actors/file-generation.d.ts +54 -0
  135. package/dist/machines/generate/actors/file-generation.d.ts.map +1 -0
  136. package/dist/machines/generate/actors/preflight.d.ts +46 -0
  137. package/dist/machines/generate/actors/preflight.d.ts.map +1 -0
  138. package/dist/machines/generate/actors/prompts.d.ts +122 -0
  139. package/dist/machines/generate/actors/prompts.d.ts.map +1 -0
  140. package/dist/machines/generate/guards.d.ts +180 -0
  141. package/dist/machines/generate/guards.d.ts.map +1 -0
  142. package/dist/machines/generate/machine.d.ts +250 -0
  143. package/dist/machines/generate/machine.d.ts.map +1 -0
  144. package/dist/machines/generate/runner.d.ts +40 -0
  145. package/dist/machines/generate/runner.d.ts.map +1 -0
  146. package/dist/machines/generate/types.d.ts +189 -0
  147. package/dist/machines/generate/types.d.ts.map +1 -0
  148. package/dist/machines/index.d.ts +20 -0
  149. package/dist/machines/index.d.ts.map +1 -0
  150. package/dist/machines/persistence.d.ts +65 -0
  151. package/dist/machines/persistence.d.ts.map +1 -0
  152. package/dist/machines/telemetry-plugin.d.ts +54 -0
  153. package/dist/machines/telemetry-plugin.d.ts.map +1 -0
  154. package/dist/machines/types.d.ts +104 -0
  155. package/dist/machines/types.d.ts.map +1 -0
  156. package/dist/mcp/client.d.ts +61 -0
  157. package/dist/mcp/client.d.ts.map +1 -0
  158. package/dist/mcp/index.d.ts +6 -0
  159. package/dist/mcp/index.d.ts.map +1 -0
  160. package/dist/mcp/types.d.ts +84 -0
  161. package/dist/mcp/types.d.ts.map +1 -0
  162. package/dist/types.d.ts +238 -0
  163. package/dist/types.d.ts.map +1 -0
  164. package/dist/utils/formatter.d.ts +71 -0
  165. package/dist/utils/formatter.d.ts.map +1 -0
  166. package/dist/utils/fs.d.ts +80 -0
  167. package/dist/utils/fs.d.ts.map +1 -0
  168. package/dist/utils/index.d.ts +8 -0
  169. package/dist/utils/index.d.ts.map +1 -0
  170. package/dist/utils/spinner.d.ts +60 -0
  171. package/dist/utils/spinner.d.ts.map +1 -0
  172. package/dist/utils/telemetry.d.ts +4 -0
  173. package/dist/utils/telemetry.d.ts.map +1 -1
  174. package/dist/utils/validation.d.ts +68 -0
  175. package/dist/utils/validation.d.ts.map +1 -0
  176. package/package.json +63 -64
  177. package/LICENSE.md +0 -595
  178. package/dist/commands/generate/options/utils/shared-frontend.d.ts +0 -14
  179. package/dist/commands/generate/options/utils/shared-frontend.d.ts.map +0 -1
  180. package/dist/commands/generate/templates/backend.d.ts +0 -10
  181. package/dist/commands/generate/templates/backend.d.ts.map +0 -1
  182. package/dist/commands/generate/templates/next/app/components.d.ts +0 -44
  183. package/dist/commands/generate/templates/next/app/components.d.ts.map +0 -1
  184. package/dist/commands/generate/templates/next/pages/components.d.ts +0 -22
  185. package/dist/commands/generate/templates/next/pages/components.d.ts.map +0 -1
  186. package/dist/commands/generate/templates/react/components.d.ts +0 -21
  187. package/dist/commands/generate/templates/react/components.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,24 +1,162 @@
1
1
  #!/usr/bin/env node
2
- import { confirm as prompts_confirm, isCancel, log as prompts_log, note, outro, select as prompts_select, spinner as prompts_spinner, text as prompts_text } from "@clack/prompts";
2
+ import * as __rspack_external__clack_prompts_3cae1695 from "@clack/prompts";
3
+ import * as __rspack_external_node_fs_promises_153e37e0 from "node:fs/promises";
4
+ import * as __rspack_external_node_path_c5b9b54f from "node:path";
5
+ import * as __rspack_external_picocolors from "picocolors";
3
6
  import "dotenv/config";
4
- import open_0 from "open";
5
- import picocolors from "picocolors";
6
- import node_path, { join } from "node:path";
7
- import promises, { writeFile } from "node:fs/promises";
8
- import node_crypto from "node:crypto";
9
- import node_os from "node:os";
10
- import { PostHog } from "posthog-node";
11
- import { spawn } from "node:child_process";
12
- import { once } from "node:events";
13
- import { createLogger } from "@c15t/logger";
14
- import { Node, Project, SyntaxKind } from "ts-morph";
15
- import { migrator } from "@c15t/backend/v2/db/migrator";
16
- import { DB } from "@c15t/backend/v2/db/schema";
17
- import { loadConfig } from "c12";
18
- import figlet from "figlet";
19
- import fs_extra from "fs-extra";
20
- import { detect } from "package-manager-detector/detect";
21
- var __webpack_require__ = {};
7
+ import * as __rspack_external_open from "open";
8
+ import * as __rspack_external_xstate from "xstate";
9
+ import * as __rspack_external_node_crypto_9ba42079 from "node:crypto";
10
+ import * as __rspack_external_node_os_74b4b876 from "node:os";
11
+ import * as __rspack_external_posthog_node_1b07bdf4 from "posthog-node";
12
+ import * as __rspack_external_node_child_process_27f17141 from "node:child_process";
13
+ import * as __rspack_external_node_events_0a6aefe7 from "node:events";
14
+ import * as __rspack_external__c15t_logger_04a510d4 from "@c15t/logger";
15
+ import * as __rspack_external__c15t_backend_db_migrator_ebe6d5c7 from "@c15t/backend/db/migrator";
16
+ import * as __rspack_external__c15t_backend_db_schema_e7c5e6a0 from "@c15t/backend/db/schema";
17
+ import * as __rspack_external_c12 from "c12";
18
+ import * as __rspack_external_figlet from "figlet";
19
+ import * as __rspack_external_fs_extra_ce68a66b from "fs-extra";
20
+ import * as __rspack_external_package_manager_detector_detect_94d6a9ae from "package-manager-detector/detect";
21
+ var __webpack_modules__ = {
22
+ "./src/constants.ts" (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
23
+ __webpack_require__.d(__webpack_exports__, {
24
+ $V: ()=>STORAGE_MODES,
25
+ tl: ()=>URLS
26
+ });
27
+ const URLS = {
28
+ CONSENT_IO: 'https://consent.io',
29
+ DOCS: 'https://c15t.dev/docs',
30
+ GITHUB: 'https://github.com/c15t/c15t',
31
+ DISCORD: 'https://c15t.dev/discord',
32
+ API_DOCS: 'https://c15t.dev/docs/api',
33
+ CLI_DOCS: 'https://c15t.dev/docs/cli'
34
+ };
35
+ const STORAGE_MODES = {
36
+ C15T: 'c15t',
37
+ OFFLINE: 'offline',
38
+ SELF_HOSTED: 'self-hosted',
39
+ CUSTOM: 'custom'
40
+ };
41
+ },
42
+ "./src/utils/logger.ts" (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
43
+ __webpack_require__.d(__webpack_exports__, {
44
+ U0: ()=>validLogLevels,
45
+ $e: ()=>formatLogMessage,
46
+ xw: ()=>createCliLogger
47
+ });
48
+ var prompts_ = __webpack_require__("@clack/prompts");
49
+ var external_picocolors_ = __webpack_require__("picocolors");
50
+ const validLogLevels = [
51
+ 'error',
52
+ 'warn',
53
+ 'info',
54
+ 'debug'
55
+ ];
56
+ const formatArgs = (args)=>{
57
+ if (0 === args.length) return '';
58
+ return `\n${args.map((arg)=>` - ${JSON.stringify(arg, null, 2)}`).join('\n')}`;
59
+ };
60
+ const formatLogMessage = (logLevel, message, args = [])=>{
61
+ const messageStr = 'string' == typeof message ? message : String(message);
62
+ const formattedArgs = formatArgs(args);
63
+ switch(logLevel){
64
+ case 'error':
65
+ return `${external_picocolors_["default"].bgRed(external_picocolors_["default"].black(' error '))} ${messageStr}${formattedArgs}`;
66
+ case 'warn':
67
+ return `${external_picocolors_["default"].bgYellow(external_picocolors_["default"].black(' warning '))} ${messageStr}${formattedArgs}`;
68
+ case 'info':
69
+ return `${external_picocolors_["default"].bgGreen(external_picocolors_["default"].black(' info '))} ${messageStr}${formattedArgs}`;
70
+ case 'debug':
71
+ return `${external_picocolors_["default"].bgBlack(external_picocolors_["default"].white(' debug '))} ${messageStr}${formattedArgs}`;
72
+ case 'success':
73
+ return `${external_picocolors_["default"].bgGreen(external_picocolors_["default"].white(' success '))} ${messageStr}${formattedArgs}`;
74
+ case 'failed':
75
+ return `${external_picocolors_["default"].bgRed(external_picocolors_["default"].white(' failed '))} ${messageStr}${formattedArgs}`;
76
+ default:
77
+ {
78
+ const levelStr = logLevel;
79
+ return `[${levelStr.toUpperCase()}] ${messageStr}${formattedArgs}`;
80
+ }
81
+ }
82
+ };
83
+ const logMessage = (logLevel, message, ...args)=>{
84
+ const formattedMessage = formatLogMessage(logLevel, message, args);
85
+ switch(logLevel){
86
+ case 'error':
87
+ prompts_.log.error(formattedMessage);
88
+ break;
89
+ case 'warn':
90
+ prompts_.log.warn(formattedMessage);
91
+ break;
92
+ case 'info':
93
+ case 'debug':
94
+ prompts_.log.info(formattedMessage);
95
+ break;
96
+ case 'success':
97
+ case 'failed':
98
+ prompts_.outro(formattedMessage);
99
+ break;
100
+ default:
101
+ prompts_.log.message(formattedMessage);
102
+ }
103
+ };
104
+ const createCliLogger = (level)=>{
105
+ const baseLogger = (0, __rspack_external__c15t_logger_04a510d4.createLogger)({
106
+ level,
107
+ appName: 'c15t',
108
+ log: (logLevel, message, ...args)=>{
109
+ logMessage(logLevel, message, ...args);
110
+ }
111
+ });
112
+ const extendedLogger = baseLogger;
113
+ extendedLogger.message = (message)=>{
114
+ prompts_.log.message(message);
115
+ };
116
+ extendedLogger.note = (message, ...args)=>{
117
+ const messageStr = 'string' == typeof message ? message : String(message);
118
+ const title = args.length > 0 && 'string' == typeof args[0] ? args[0] : void 0;
119
+ prompts_.note(messageStr, title, {
120
+ format: (line)=>line
121
+ });
122
+ };
123
+ extendedLogger.success = (message, ...args)=>{
124
+ logMessage('success', message, ...args);
125
+ };
126
+ extendedLogger.failed = (message, ...args)=>{
127
+ logMessage('failed', message, ...args);
128
+ process.exit(0);
129
+ };
130
+ extendedLogger.outro = (message)=>{
131
+ prompts_.outro(message);
132
+ };
133
+ return extendedLogger;
134
+ };
135
+ },
136
+ "@clack/prompts" (module) {
137
+ module.exports = __rspack_external__clack_prompts_3cae1695;
138
+ },
139
+ "node:fs/promises" (module) {
140
+ module.exports = __rspack_external_node_fs_promises_153e37e0;
141
+ },
142
+ "node:path" (module) {
143
+ module.exports = __rspack_external_node_path_c5b9b54f;
144
+ },
145
+ picocolors (module) {
146
+ module.exports = __rspack_external_picocolors;
147
+ }
148
+ };
149
+ var __webpack_module_cache__ = {};
150
+ function __webpack_require__(moduleId) {
151
+ var cachedModule = __webpack_module_cache__[moduleId];
152
+ if (void 0 !== cachedModule) return cachedModule.exports;
153
+ var module = __webpack_module_cache__[moduleId] = {
154
+ exports: {}
155
+ };
156
+ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
157
+ return module.exports;
158
+ }
159
+ __webpack_require__.m = __webpack_modules__;
22
160
  (()=>{
23
161
  __webpack_require__.d = (exports, definition)=>{
24
162
  for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {
@@ -27,31 +165,58 @@ var __webpack_require__ = {};
27
165
  });
28
166
  };
29
167
  })();
168
+ (()=>{
169
+ __webpack_require__.f = {};
170
+ __webpack_require__.e = (chunkId)=>Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key)=>{
171
+ __webpack_require__.f[key](chunkId, promises);
172
+ return promises;
173
+ }, []));
174
+ })();
175
+ (()=>{
176
+ __webpack_require__.u = (chunkId)=>"" + chunkId + ".mjs";
177
+ })();
30
178
  (()=>{
31
179
  __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
32
180
  })();
33
181
  (()=>{
34
- __webpack_require__.r = (exports)=>{
35
- if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports, Symbol.toStringTag, {
36
- value: 'Module'
37
- });
38
- Object.defineProperty(exports, '__esModule', {
39
- value: true
40
- });
182
+ var installedChunks = {
183
+ 410: 0
184
+ };
185
+ var installChunk = (data)=>{
186
+ var __rspack_esm_ids = data.__rspack_esm_ids;
187
+ var __webpack_modules__ = data.__webpack_modules__;
188
+ var __rspack_esm_runtime = data.__rspack_esm_runtime;
189
+ var moduleId, chunkId, i = 0;
190
+ for(moduleId in __webpack_modules__)if (__webpack_require__.o(__webpack_modules__, moduleId)) __webpack_require__.m[moduleId] = __webpack_modules__[moduleId];
191
+ if (__rspack_esm_runtime) __rspack_esm_runtime(__webpack_require__);
192
+ for(; i < __rspack_esm_ids.length; i++){
193
+ chunkId = __rspack_esm_ids[i];
194
+ if (__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) installedChunks[chunkId][0]();
195
+ installedChunks[__rspack_esm_ids[i]] = 0;
196
+ }
197
+ };
198
+ __webpack_require__.f.j = function(chunkId, promises) {
199
+ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : void 0;
200
+ if (0 !== installedChunkData) if (installedChunkData) promises.push(installedChunkData[1]);
201
+ else {
202
+ var promise = import("./" + __webpack_require__.u(chunkId)).then(installChunk, (e)=>{
203
+ if (0 !== installedChunks[chunkId]) installedChunks[chunkId] = void 0;
204
+ throw e;
205
+ });
206
+ var promise = Promise.race([
207
+ promise,
208
+ new Promise((resolve)=>{
209
+ installedChunkData = installedChunks[chunkId] = [
210
+ resolve
211
+ ];
212
+ })
213
+ ]);
214
+ promises.push(installedChunkData[1] = promise);
215
+ }
41
216
  };
42
217
  })();
43
- var prompts_namespaceObject = {};
44
- __webpack_require__.r(prompts_namespaceObject);
45
- __webpack_require__.d(prompts_namespaceObject, {
46
- confirm: ()=>prompts_confirm,
47
- isCancel: ()=>isCancel,
48
- log: ()=>prompts_log,
49
- note: ()=>note,
50
- outro: ()=>outro,
51
- select: ()=>prompts_select,
52
- spinner: ()=>prompts_spinner,
53
- text: ()=>prompts_text
54
- });
218
+ var prompts_ = __webpack_require__("@clack/prompts");
219
+ var external_picocolors_ = __webpack_require__("picocolors");
55
220
  function showHelpMenu(context, version, commands, flags) {
56
221
  const { logger } = context;
57
222
  logger.debug('Displaying help menu using command and flag structures.');
@@ -69,101 +234,12 @@ ${commandLines}
69
234
  Options:
70
235
  ${optionLines}
71
236
 
72
- Run a command directly (e.g., ${picocolors.cyan('c15t generate')}) or select one interactively when no command is provided.
237
+ Run a command directly (e.g., ${external_picocolors_["default"].cyan('c15t generate')}) or select one interactively when no command is provided.
73
238
 
74
239
  For more help, visit: https://c15t.dev`;
75
240
  logger.debug('Help menu content generated.');
76
241
  logger.note(helpContent, 'Usage');
77
242
  }
78
- async function detectFramework(projectRoot, logger) {
79
- try {
80
- logger?.debug(`Detecting framework in ${projectRoot}`);
81
- const packageJsonPath = node_path.join(projectRoot, 'package.json');
82
- const packageJson = JSON.parse(await promises.readFile(packageJsonPath, 'utf-8'));
83
- const deps = {
84
- ...packageJson.dependencies,
85
- ...packageJson.devDependencies
86
- };
87
- const hasReact = 'react' in deps;
88
- const reactVersion = hasReact ? deps.react : null;
89
- logger?.debug(`React detected: ${hasReact}${reactVersion ? ` (version: ${reactVersion})` : ''}`);
90
- let framework = null;
91
- let frameworkVersion = null;
92
- let pkg = hasReact ? '@c15t/react' : 'c15t';
93
- if ('next' in deps) {
94
- framework = 'Next.js';
95
- frameworkVersion = deps.next;
96
- pkg = '@c15t/nextjs';
97
- } else if ('@remix-run/react' in deps) {
98
- framework = 'Remix';
99
- frameworkVersion = deps['@remix-run/react'];
100
- } else if ('@vitejs/plugin-react' in deps || '@vitejs/plugin-react-swc' in deps) {
101
- framework = 'Vite + React';
102
- frameworkVersion = deps['@vitejs/plugin-react'] || deps['@vitejs/plugin-react-swc'];
103
- } else if ('gatsby' in deps) {
104
- framework = 'Gatsby';
105
- frameworkVersion = deps.gatsby;
106
- } else if (hasReact) {
107
- framework = 'React';
108
- frameworkVersion = reactVersion;
109
- }
110
- logger?.debug(`Detected framework: ${framework}${frameworkVersion ? ` (version: ${frameworkVersion})` : ''}, package: ${pkg}`);
111
- return {
112
- framework,
113
- frameworkVersion,
114
- pkg,
115
- hasReact,
116
- reactVersion
117
- };
118
- } catch (error) {
119
- logger?.debug(`Framework detection failed: ${error instanceof Error ? error.message : String(error)}`);
120
- return {
121
- framework: null,
122
- frameworkVersion: null,
123
- pkg: 'c15t',
124
- hasReact: false,
125
- reactVersion: null
126
- };
127
- }
128
- }
129
- async function detectProjectRoot(cwd, logger) {
130
- let projectRoot = cwd;
131
- logger?.debug(`Starting project root detection from: ${cwd}`);
132
- try {
133
- let prevDir = '';
134
- let depth = 0;
135
- const maxDepth = 10;
136
- while(projectRoot !== prevDir && depth < maxDepth){
137
- logger?.debug(`Checking directory (depth ${depth}): ${projectRoot}`);
138
- try {
139
- const packageJsonPath = node_path.join(projectRoot, 'package.json');
140
- logger?.debug(`Looking for package.json at: ${packageJsonPath}`);
141
- await promises.access(packageJsonPath);
142
- logger?.debug(`Found package.json at: ${projectRoot}`);
143
- break;
144
- } catch (error) {
145
- logger?.debug(`No package.json found in ${projectRoot}: ${error instanceof Error ? error.message : String(error)}`);
146
- prevDir = projectRoot;
147
- projectRoot = node_path.dirname(projectRoot);
148
- depth++;
149
- }
150
- }
151
- if (projectRoot === prevDir) {
152
- logger?.debug('Reached root directory without finding package.json');
153
- logger?.failed('Could not find project root (no package.json found)');
154
- }
155
- if (depth >= maxDepth) {
156
- logger?.debug('Reached maximum directory depth without finding package.json');
157
- logger?.failed('Could not find project root (reached maximum directory depth)');
158
- }
159
- logger?.debug(`Project root detection complete. Found at: ${projectRoot}`);
160
- return projectRoot;
161
- } catch (error) {
162
- logger?.debug(`Project root detection failed: ${error instanceof Error ? error.message : String(error)}`);
163
- logger?.debug(`Falling back to current directory: ${cwd}`);
164
- return cwd;
165
- }
166
- }
167
243
  const TELEMETRY_DISABLED_ENV = 'C15T_TELEMETRY_DISABLED';
168
244
  const TelemetryEventName = {
169
245
  CLI_INVOKED: 'cli.invoked',
@@ -203,7 +279,11 @@ const TelemetryEventName = {
203
279
  GENERATE_FAILED: 'generate.failed',
204
280
  SELF_HOST_STARTED: 'self-host.started',
205
281
  SELF_HOST_COMPLETED: 'self-host.completed',
206
- SELF_HOST_FAILED: 'self-host.failed'
282
+ SELF_HOST_FAILED: 'self-host.failed',
283
+ CLI_STATE_TRANSITION: 'cli.state.transition',
284
+ CLI_STATE_ERROR: 'cli.state.error',
285
+ CLI_STATE_CANCELLED: 'cli.state.cancelled',
286
+ CLI_STATE_COMPLETE: 'cli.state.complete'
207
287
  };
208
288
  class Telemetry {
209
289
  client = null;
@@ -338,7 +418,7 @@ class Telemetry {
338
418
  requestTimeout: 3000
339
419
  };
340
420
  if (this.debug) this.logDebug('Initializing PostHog client with config:', JSON.stringify(clientConfig));
341
- this.client = new PostHog(this.apiKey, clientConfig);
421
+ this.client = new __rspack_external_posthog_node_1b07bdf4.PostHog(this.apiKey, clientConfig);
342
422
  const initTime = Date.now() - startTime;
343
423
  if (this.debug) this.logDebug('PostHog client initialized in', initTime, 'ms');
344
424
  } catch (error) {
@@ -353,7 +433,7 @@ class Telemetry {
353
433
  if (this.debug) this.logDebug('Telemetry disabled due to initialization error:', JSON.stringify(errorDetails, null, 2));
354
434
  try {
355
435
  if (this.debug) this.logDebug('Attempting fallback PostHog initialization');
356
- this.client = new PostHog(this.apiKey);
436
+ this.client = new __rspack_external_posthog_node_1b07bdf4.PostHog(this.apiKey);
357
437
  this.disabled = false;
358
438
  if (this.debug) this.logDebug('PostHog client initialized using fallback method');
359
439
  } catch (fallbackError) {
@@ -363,7 +443,7 @@ class Telemetry {
363
443
  }
364
444
  }
365
445
  generateAnonymousId() {
366
- const machineId = node_crypto.createHash('sha256').update(node_os.hostname() + node_os.platform() + node_os.arch() + node_os.totalmem()).digest('hex');
446
+ const machineId = __rspack_external_node_crypto_9ba42079["default"].createHash('sha256').update(__rspack_external_node_os_74b4b876["default"].hostname() + __rspack_external_node_os_74b4b876["default"].platform() + __rspack_external_node_os_74b4b876["default"].arch() + __rspack_external_node_os_74b4b876["default"].totalmem()).digest('hex');
367
447
  return machineId;
368
448
  }
369
449
  flushSync() {
@@ -379,10 +459,175 @@ class Telemetry {
379
459
  function createTelemetry(options) {
380
460
  return new Telemetry(options);
381
461
  }
382
- async function addAndInstallDependenciesViaPM(projectRoot, dependencies, packageManager) {
462
+ var external_node_path_ = __webpack_require__("node:path");
463
+ const DEFAULT_PERSIST_FILENAME = '.c15t-state.json';
464
+ function getPersistPath(projectRoot) {
465
+ return external_node_path_["default"].join(projectRoot, DEFAULT_PERSIST_FILENAME);
466
+ }
467
+ const NON_SERIALIZABLE_FIELDS = new Set([
468
+ 'cliContext',
469
+ 'spinner',
470
+ '_parent',
471
+ '_actorScope',
472
+ '_processingStatus',
473
+ '_systemId',
474
+ 'logic',
475
+ 'src',
476
+ 'system',
477
+ 'self',
478
+ '_snapshot'
479
+ ]);
480
+ function makeSerializable(obj, seen = new WeakSet()) {
481
+ if (null == obj) return obj;
482
+ if ('object' != typeof obj) return obj;
483
+ if (seen.has(obj)) return '[Circular]';
484
+ seen.add(obj);
485
+ if (Array.isArray(obj)) return obj.map((item)=>makeSerializable(item, seen));
486
+ if (obj instanceof Date) return obj.toISOString();
487
+ if (obj instanceof Map) return Object.fromEntries(Array.from(obj.entries()).map(([k, v])=>[
488
+ k,
489
+ makeSerializable(v, seen)
490
+ ]));
491
+ if (obj instanceof Set) return Array.from(obj).map((v)=>makeSerializable(v, seen));
492
+ const result = {};
493
+ for (const [key, value] of Object.entries(obj))if (!NON_SERIALIZABLE_FIELDS.has(key)) {
494
+ if ('function' != typeof value && 'symbol' != typeof value) result[key] = makeSerializable(value, seen);
495
+ }
496
+ return result;
497
+ }
498
+ async function saveSnapshot(snapshot, machineId, persistPath) {
499
+ const fs = await import("node:fs/promises");
500
+ const serializableSnapshot = makeSerializable(snapshot);
501
+ const persisted = {
502
+ machineId,
503
+ version: 1,
504
+ savedAt: Date.now(),
505
+ snapshot: serializableSnapshot
506
+ };
507
+ await fs.writeFile(persistPath, JSON.stringify(persisted, null, 2), 'utf-8');
508
+ }
509
+ async function loadSnapshot(persistPath, machineId) {
510
+ const fs = await import("node:fs/promises");
511
+ try {
512
+ const content = await fs.readFile(persistPath, 'utf-8');
513
+ const persisted = JSON.parse(content);
514
+ if (persisted.machineId !== machineId) return null;
515
+ const maxAge = 86400000;
516
+ if (Date.now() - persisted.savedAt > maxAge) {
517
+ await clearSnapshot(persistPath);
518
+ return null;
519
+ }
520
+ return persisted.snapshot;
521
+ } catch {
522
+ return null;
523
+ }
524
+ }
525
+ async function clearSnapshot(persistPath) {
526
+ const fs = await import("node:fs/promises");
527
+ try {
528
+ await fs.unlink(persistPath);
529
+ } catch {}
530
+ }
531
+ async function hasPersistedState(persistPath) {
532
+ const fs = await import("node:fs/promises");
533
+ try {
534
+ await fs.access(persistPath);
535
+ return true;
536
+ } catch {
537
+ return false;
538
+ }
539
+ }
540
+ function createPersistenceSubscriber(machineId, persistPath, options = {}) {
541
+ const { persistStates, skipStates = [
542
+ 'exited',
543
+ 'complete',
544
+ 'error'
545
+ ] } = options;
546
+ return (snapshot)=>{
547
+ const stateValue = String(snapshot.value);
548
+ if (skipStates.includes(stateValue)) return void clearSnapshot(persistPath).catch(()=>{});
549
+ if (persistStates && !persistStates.includes(stateValue)) return;
550
+ saveSnapshot(snapshot, machineId, persistPath).catch((error)=>{
551
+ console.error('Failed to persist state:', error);
552
+ });
553
+ };
554
+ }
555
+ function createTelemetrySubscriber(config) {
556
+ const { telemetry, machineId, skipStates = [] } = config;
557
+ let lastState = null;
558
+ let lastStateTime = Date.now();
559
+ const stateHistory = [];
560
+ return (snapshot)=>{
561
+ const currentState = String(snapshot.value);
562
+ const now = Date.now();
563
+ if (currentState === lastState) return;
564
+ if (skipStates.includes(currentState)) return;
565
+ if (null !== lastState) {
566
+ const duration = now - lastStateTime;
567
+ telemetry.trackEvent(TelemetryEventName.CLI_STATE_TRANSITION, {
568
+ machineId,
569
+ fromState: lastState,
570
+ toState: currentState,
571
+ duration
572
+ });
573
+ }
574
+ stateHistory.push({
575
+ state: currentState,
576
+ timestamp: now
577
+ });
578
+ if ('error' === currentState || 'preflightError' === currentState) {
579
+ const ctx = snapshot.context;
580
+ const errors = ctx?.errors;
581
+ const lastError = errors?.[errors.length - 1];
582
+ telemetry.trackEvent(TelemetryEventName.CLI_STATE_ERROR, {
583
+ machineId,
584
+ state: currentState,
585
+ error: lastError?.error?.message ?? 'Unknown error',
586
+ stateHistory: stateHistory.map((e)=>e.state).join(',')
587
+ });
588
+ }
589
+ if ('exited' === currentState || 'cancelled' === currentState) telemetry.trackEvent(TelemetryEventName.CLI_STATE_CANCELLED, {
590
+ machineId,
591
+ lastState: lastState ?? 'unknown',
592
+ stateHistory: stateHistory.map((e)=>e.state).join(',')
593
+ });
594
+ if ('complete' === currentState || 'success' === currentState) {
595
+ const totalDuration = now - (stateHistory[0]?.timestamp ?? now);
596
+ telemetry.trackEvent(TelemetryEventName.CLI_STATE_COMPLETE, {
597
+ machineId,
598
+ totalDuration,
599
+ statesVisited: stateHistory.length,
600
+ stateHistory: stateHistory.map((e)=>e.state).join(',')
601
+ });
602
+ }
603
+ lastState = currentState;
604
+ lastStateTime = now;
605
+ };
606
+ }
607
+ function combineSubscribers(...subscribers) {
608
+ return (snapshot)=>{
609
+ for (const subscriber of subscribers)try {
610
+ subscriber(snapshot);
611
+ } catch (error) {
612
+ console.error('Subscriber error:', error);
613
+ }
614
+ };
615
+ }
616
+ function createDebugSubscriber(machineId, logger) {
617
+ let lastState = null;
618
+ return (snapshot)=>{
619
+ const currentState = String(snapshot.value);
620
+ if (currentState !== lastState) {
621
+ const log = logger?.debug ?? console.debug;
622
+ log(`[${machineId}] State: ${lastState ?? 'initial'} -> ${currentState}`);
623
+ lastState = currentState;
624
+ }
625
+ };
626
+ }
627
+ async function runPackageManagerInstall(projectRoot, dependencies, packageManager) {
383
628
  if (0 === dependencies.length) return;
384
- let command = '';
385
- let args = [];
629
+ let command;
630
+ let args;
386
631
  switch(packageManager){
387
632
  case 'npm':
388
633
  command = 'npm';
@@ -413,14 +658,40 @@ async function addAndInstallDependenciesViaPM(projectRoot, dependencies, package
413
658
  ];
414
659
  break;
415
660
  default:
416
- throw new Error(`Unsupported package manager for dependency addition: ${packageManager}`);
661
+ throw new Error(`Unsupported package manager: ${packageManager}`);
417
662
  }
418
- const child = spawn(command, args, {
663
+ const child = (0, __rspack_external_node_child_process_27f17141.spawn)(command, args, {
419
664
  cwd: projectRoot,
420
665
  stdio: 'inherit'
421
666
  });
422
- await once(child, 'exit');
667
+ const [exitCode] = await (0, __rspack_external_node_events_0a6aefe7.once)(child, 'exit');
668
+ if (0 !== exitCode) throw new Error(`Package manager exited with code ${exitCode}`);
423
669
  }
670
+ const dependencyInstallActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
671
+ const { cliContext, dependencies } = input;
672
+ const { projectRoot, packageManager, logger } = cliContext;
673
+ if (0 === dependencies.length) return {
674
+ success: true,
675
+ installedDependencies: []
676
+ };
677
+ logger.debug(`Installing dependencies: ${dependencies.join(', ')}`);
678
+ logger.debug(`Using package manager: ${packageManager.name}`);
679
+ try {
680
+ await runPackageManagerInstall(projectRoot, dependencies, packageManager.name);
681
+ return {
682
+ success: true,
683
+ installedDependencies: dependencies
684
+ };
685
+ } catch (error) {
686
+ const errorMessage = error instanceof Error ? error.message : String(error);
687
+ logger.error(`Dependency installation failed: ${errorMessage}`);
688
+ return {
689
+ success: false,
690
+ installedDependencies: [],
691
+ error: errorMessage
692
+ };
693
+ }
694
+ });
424
695
  function getManualInstallCommand(dependencies, packageManager) {
425
696
  switch(packageManager){
426
697
  case 'npm':
@@ -435,1449 +706,1585 @@ function getManualInstallCommand(dependencies, packageManager) {
435
706
  return `npm install ${dependencies.join(' ')}`;
436
707
  }
437
708
  }
438
- async function installDependencies({ context, dependenciesToAdd, handleCancel, autoInstall = false }) {
439
- const { telemetry, logger } = context;
440
- const s = prompts_spinner();
441
- if (0 === dependenciesToAdd.length) return {
442
- installDepsConfirmed: false,
443
- ranInstall: false
444
- };
445
- const depsString = dependenciesToAdd.map((d)=>picocolors.cyan(d)).join(', ');
446
- if (!autoInstall) {
447
- const addDepsSelection = await prompts_confirm({
448
- message: `Add required dependencies using ${picocolors.cyan(context.packageManager.name)}? (${depsString})`,
449
- initialValue: true
450
- });
451
- if (handleCancel?.(addDepsSelection)) return {
452
- installDepsConfirmed: false,
453
- ranInstall: false
454
- };
455
- if (!addDepsSelection) return {
456
- installDepsConfirmed: false,
457
- ranInstall: false
709
+ const checkDependenciesActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
710
+ const { projectRoot, dependencies } = input;
711
+ const fs = await import("node:fs/promises");
712
+ const path = await import("node:path");
713
+ const installed = [];
714
+ const missing = [];
715
+ try {
716
+ const packageJsonPath = path.join(projectRoot, 'package.json');
717
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
718
+ const allDeps = {
719
+ ...packageJson.dependencies,
720
+ ...packageJson.devDependencies
458
721
  };
722
+ for (const dep of dependencies){
723
+ const depName = dep.startsWith('@') ? dep : dep.split('@')[0];
724
+ if (depName && depName in allDeps) installed.push(dep);
725
+ else missing.push(dep);
726
+ }
727
+ } catch {
728
+ missing.push(...dependencies);
459
729
  }
460
- s.start(`Running ${picocolors.cyan(context.packageManager.name)} to add and install dependencies... (this might take a moment)`);
730
+ return {
731
+ installed,
732
+ missing
733
+ };
734
+ });
735
+ async function readFileForBackup(filePath) {
736
+ const fs = await import("node:fs/promises");
461
737
  try {
462
- await addAndInstallDependenciesViaPM(context.projectRoot, dependenciesToAdd, context.packageManager.name);
463
- s.stop(`✅ Dependencies installed: ${dependenciesToAdd.map((d)=>picocolors.cyan(d)).join(', ')}`);
464
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
465
- success: true,
466
- dependencies: dependenciesToAdd.join(','),
467
- packageManager: context.packageManager.name
468
- });
469
- return {
470
- installDepsConfirmed: true,
471
- ranInstall: true
472
- };
473
- } catch (installError) {
474
- s.stop(picocolors.yellow('⚠️ Dependency installation failed.'));
475
- logger.error('Installation Error:', installError);
476
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
477
- success: false,
478
- error: installError instanceof Error ? installError.message : String(installError),
479
- dependencies: dependenciesToAdd.join(','),
480
- packageManager: context.packageManager.name
481
- });
482
- const pmCommand = getManualInstallCommand(dependenciesToAdd, context.packageManager.name);
483
- logger.info(`Please try running '${pmCommand}' manually in ${picocolors.cyan(node_path.relative(context.cwd, context.projectRoot))}.`);
484
- return {
485
- installDepsConfirmed: true,
486
- ranInstall: false
487
- };
738
+ return await fs.readFile(filePath, 'utf-8');
739
+ } catch {
740
+ return null;
488
741
  }
489
742
  }
490
- const validLogLevels = [
491
- 'error',
492
- 'warn',
493
- 'info',
494
- 'debug'
495
- ];
496
- const formatArgs = (args)=>{
497
- if (0 === args.length) return '';
498
- return `\n${args.map((arg)=>` - ${JSON.stringify(arg, null, 2)}`).join('\n')}`;
499
- };
500
- const formatLogMessage = (logLevel, message, args = [])=>{
501
- const messageStr = 'string' == typeof message ? message : String(message);
502
- const formattedArgs = formatArgs(args);
503
- switch(logLevel){
504
- case 'error':
505
- return `${picocolors.bgRed(picocolors.black(' error '))} ${messageStr}${formattedArgs}`;
506
- case 'warn':
507
- return `${picocolors.bgYellow(picocolors.black(' warning '))} ${messageStr}${formattedArgs}`;
508
- case 'info':
509
- return `${picocolors.bgGreen(picocolors.black(' info '))} ${messageStr}${formattedArgs}`;
510
- case 'debug':
511
- return `${picocolors.bgBlack(picocolors.white(' debug '))} ${messageStr}${formattedArgs}`;
512
- case 'success':
513
- return `${picocolors.bgGreen(picocolors.white(' success '))} ${messageStr}${formattedArgs}`;
514
- case 'failed':
515
- return `${picocolors.bgRed(picocolors.white(' failed '))} ${messageStr}${formattedArgs}`;
516
- default:
517
- {
518
- const levelStr = logLevel;
519
- return `[${levelStr.toUpperCase()}] ${messageStr}${formattedArgs}`;
520
- }
521
- }
522
- };
523
- const logMessage = (logLevel, message, ...args)=>{
524
- const formattedMessage = formatLogMessage(logLevel, message, args);
525
- switch(logLevel){
526
- case 'error':
527
- prompts_log.error(formattedMessage);
528
- break;
529
- case 'warn':
530
- prompts_log.warn(formattedMessage);
531
- break;
532
- case 'info':
533
- case 'debug':
534
- prompts_log.info(formattedMessage);
535
- break;
536
- case 'success':
537
- case 'failed':
538
- outro(formattedMessage);
539
- break;
540
- default:
541
- prompts_log.message(formattedMessage);
743
+ async function fileExists(filePath) {
744
+ const fs = await import("node:fs/promises");
745
+ try {
746
+ await fs.access(filePath);
747
+ return true;
748
+ } catch {
749
+ return false;
542
750
  }
543
- };
544
- const createCliLogger = (level)=>{
545
- const baseLogger = createLogger({
546
- level,
547
- appName: 'c15t',
548
- log: (logLevel, message, ...args)=>{
549
- logMessage(logLevel, message, ...args);
751
+ }
752
+ async function formatGeneratedFiles(projectRoot, files, logger) {
753
+ const fs = await import("node:fs/promises");
754
+ const { execFile } = await import("node:child_process");
755
+ const { promisify } = await import("node:util");
756
+ const execFileAsync = promisify(execFile);
757
+ const codeFiles = files.filter((f)=>f.endsWith('.ts') || f.endsWith('.tsx') || f.endsWith('.js') || f.endsWith('.jsx'));
758
+ if (0 === codeFiles.length) return;
759
+ const formatters = [
760
+ {
761
+ bin: external_node_path_["default"].join(projectRoot, 'node_modules', '.bin', 'prettier'),
762
+ args: [
763
+ '--write'
764
+ ]
765
+ },
766
+ {
767
+ bin: external_node_path_["default"].join(projectRoot, 'node_modules', '.bin', 'biome'),
768
+ args: [
769
+ 'format',
770
+ '--write'
771
+ ]
550
772
  }
551
- });
552
- const extendedLogger = baseLogger;
553
- extendedLogger.message = (message)=>{
554
- prompts_log.message(message);
555
- };
556
- extendedLogger.note = (message, ...args)=>{
557
- const messageStr = 'string' == typeof message ? message : String(message);
558
- const title = args.length > 0 && 'string' == typeof args[0] ? args[0] : void 0;
559
- note(messageStr, title, {
560
- format: (line)=>line
773
+ ];
774
+ for (const { bin, args } of formatters)try {
775
+ await fs.access(bin);
776
+ await execFileAsync(bin, [
777
+ ...args,
778
+ ...codeFiles
779
+ ], {
780
+ cwd: projectRoot
561
781
  });
782
+ logger.debug(`Formatted ${codeFiles.length} files with ${external_node_path_["default"].basename(bin)}`);
783
+ return;
784
+ } catch {}
785
+ logger.debug('No formatter found, skipping formatting');
786
+ }
787
+ const fileGenerationActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
788
+ const { cliContext, mode, backendURL, useEnvFile, proxyNextjs, enableSSR, enableDevTools, uiStyle, expandedTheme, selectedScripts } = input;
789
+ const filesCreated = [];
790
+ const filesModified = [];
791
+ const result = {
792
+ filesCreated: [],
793
+ filesModified: [],
794
+ configPath: null,
795
+ layoutPath: null,
796
+ nextConfigPath: null,
797
+ envPath: null
562
798
  };
563
- extendedLogger.success = (message, ...args)=>{
564
- logMessage('success', message, ...args);
799
+ const { projectRoot, framework, cwd, logger } = cliContext;
800
+ framework.pkg;
801
+ const { generateFiles } = await __webpack_require__.e("760").then(__webpack_require__.bind(__webpack_require__, "./src/commands/generate/options/utils/generate-files.ts"));
802
+ const spinnerMock = {
803
+ start: (msg)=>logger.debug(`[spinner] ${msg}`),
804
+ stop: (msg)=>logger.debug(`[spinner] ${msg}`),
805
+ message: (msg)=>logger.debug(`[spinner] ${msg}`)
565
806
  };
566
- extendedLogger.failed = (message, ...args)=>{
567
- logMessage('failed', message, ...args);
568
- process.exit(0);
569
- };
570
- extendedLogger.outro = (message)=>{
571
- outro(message);
572
- };
573
- return extendedLogger;
574
- };
575
- function generateClientConfigContent(mode, backendURL, useEnvFile, logger) {
576
- let configContent = '';
577
- const validModes = [
578
- 'c15t',
579
- 'offline',
580
- 'custom'
581
- ];
582
- switch(mode){
583
- case 'c15t':
584
- configContent = `
585
- import {
586
- type ConsentManagerOptions,
587
- configureConsentManager,
588
- createConsentManagerStore
589
- } from "c15t";
590
-
591
- export const consentManager = configureConsentManager({ mode: "c15t", backendURL: ${useEnvFile ? 'process.env.NEXT_PUBLIC_C15T_URL' : `'${backendURL || 'https://your-instance.c15t.dev'}'`}, });
592
- export const store = createConsentManagerStore(consentManager, {
593
- initialGdprTypes: ["necessary", "marketing"], // Optional: Specify which consent categories to show in the banner.
594
- ignoreGeoLocation: true // Useful for development to always view the banner.
595
- });
596
-
597
- store.getState().setConsent("marketing", true); // set consent to marketing
598
- store.getState().showPopup;
599
- `;
600
- break;
601
- case 'offline':
602
- configContent = `
603
- import {
604
- type ConsentManagerOptions,
605
- configureConsentManager,
606
- createConsentManagerStore
607
- } from "c15t";
608
-
609
- export const consentManager = configureConsentManager({ mode: "offline" });
610
- export const store = createConsentManagerStore(consentManager, {
611
- initialGdprTypes: ["necessary", "marketing"], // Optional: Specify which consent categories to show in the banner.
612
- });
613
-
614
- store.getState().setConsent("marketing", true); // set consent to marketing
615
- store.getState().showPopup; // should show popup?
616
-
617
- `;
618
- break;
619
- case 'custom':
620
- configContent = `import {
621
- type ConsentManagerOptions,
622
- configureConsentManager,
623
- createConsentManagerStore
624
- } from "c15t";
625
-
626
- export const consentManager = configureConsentManager({ mode: "custom", endpointHandlers: createCustomHandlers(), });
627
- export const store = createConsentManagerStore(consentManager, {
628
- initialGdprTypes: ["necessary", "marketing"], // Optional: Specify which consent categories to show in the banner.
629
- ignoreGeoLocation: true // Useful for development to always view the banner.
630
- });
631
-
632
- store.getState().setConsent("marketing", true); // set consent to marketing
633
- store.getState().showPopup; // should show popup?
634
- `;
635
- break;
636
- default:
637
- logger?.failed(`Invalid mode: ${mode}. Valid modes are: ${validModes.join(', ')}`);
638
- }
639
- return configContent;
640
- }
641
- function getEnvVarName(pkg) {
642
- return '@c15t/nextjs' === pkg ? 'NEXT_PUBLIC_C15T_URL' : 'PUBLIC_C15T_URL';
643
- }
644
- function generateEnvFileContent(backendURL, pkg) {
645
- const envVarName = getEnvVarName(pkg);
646
- return `\n${envVarName}=${backendURL}\n`;
647
- }
648
- function generateEnvExampleContent(pkg) {
649
- const envVarName = getEnvVarName(pkg);
650
- return `\n# c15t Configuration\n${envVarName}=https://your-instance.c15t.dev\n`;
651
- }
652
- function generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs) {
653
- switch(mode){
654
- case 'c15t':
655
- if (proxyNextjs) return `{
656
- mode: 'c15t',
657
- backendURL: '/api/c15t',
658
- consentCategories: ['necessary', 'marketing'], // Optional: Specify which consent categories to show in the banner.
659
- ignoreGeoLocation: true, // Useful for development to always view the banner.
660
- }`;
661
- if (useEnvFile) return `{
662
- mode: 'c15t',
663
- backendURL: process.env.NEXT_PUBLIC_C15T_URL!,
664
- consentCategories: ['necessary', 'marketing'], // Optional: Specify which consent categories to show in the banner.
665
- ignoreGeoLocation: true, // Useful for development to always view the banner.
666
- }`;
667
- return `{
668
- mode: 'c15t',
669
- backendURL: '${backendURL || 'https://your-instance.c15t.dev'}',
670
- consentCategories: ['necessary', 'marketing'], // Optional: Specify which consent categories to show in the banner.
671
- ignoreGeoLocation: true, // Useful for development to always view the banner.
672
- }`;
673
- case 'custom':
674
- return `{
675
- mode: 'custom',
676
- endpointHandlers: createCustomHandlers(),
677
- }`;
678
- default:
679
- return `{
680
- mode: 'offline',
681
- consentCategories: ['necessary', 'marketing'], // Optional: Specify which consent categories to show in the banner.
682
- }`;
683
- }
684
- }
685
- function generateConsentManagerTemplate(optionsText) {
686
- return `import type { ReactNode } from 'react';
687
- import {
688
- ConsentManagerDialog,
689
- ConsentManagerProvider,
690
- CookieBanner,
691
- } from '@c15t/nextjs';
692
- // For client-only apps (non-SSR), you can use:
693
- // import { ConsentManagerProvider } from '@c15t/nextjs/client';
694
- import { ConsentManagerClient } from './consent-manager.client';
695
-
696
- /**
697
- * Server-side rendered consent management wrapper for Next.js App Router
698
- *
699
- * This component provides SSR-compatible consent management by separating
700
- * server-side configuration from client-side functionality. The server handles
701
- * initial setup and configuration, while client-side features (callbacks,
702
- * scripts) are delegated to the ConsentManagerClient component.
703
- *
704
- * @param props - Component properties
705
- * @param props.children - Child components to render within the consent manager context
706
- *
707
- * @returns The consent manager provider with banner, dialog, and client wrapper
708
- *
709
- * @remarks
710
- * This split architecture is necessary because certain options like callbacks
711
- * and scripts cannot be serialized during server-side rendering. For
712
- * client-only implementations, use \`<ConsentManagerProvider />\` from
713
- * \`@c15t/nextjs/client\`.
714
- *
715
- * @example
716
- * \`\`\`tsx
717
- * // In your root layout.tsx
718
- * import { ConsentManager } from './consent-manager';
719
- *
720
- * export default function RootLayout({ children }) {
721
- * return (
722
- * <html>
723
- * <body>
724
- * <ConsentManager>
725
- * {children}
726
- * </ConsentManager>
727
- * </body>
728
- * </html>
729
- * );
730
- * }
731
- * \`\`\`
732
- */
733
- export function ConsentManager({ children }: { children: ReactNode }) {
734
- return (
735
- <ConsentManagerProvider
736
- options={${optionsText}}
737
- >
738
- <CookieBanner />
739
- <ConsentManagerDialog />
740
- <ConsentManagerClient>{children}</ConsentManagerClient>
741
- </ConsentManagerProvider>
742
- );
743
- }
744
- `;
745
- }
746
- function generateConsentManagerClientTemplate() {
747
- return `'use client';
748
-
749
- import type { ReactNode } from 'react';
750
- import { ClientSideOptionsProvider } from '@c15t/nextjs/client';
751
-
752
- /**
753
- * Client-side consent manager wrapper for handling scripts and callbacks
754
- *
755
- * This component is rendered on the client and provides the ability to:
756
- * - Load integration scripts (Google Tag Manager, Meta Pixel, TikTok Pixel, etc.)
757
- * - Handle client-side callbacks (onConsentSet, onError, onBannerFetched)
758
- * - Manage script lifecycle (onLoad, onDelete)
759
- *
760
- * @param props - Component properties
761
- * @param props.children - Child components to render within the client-side context
762
- *
763
- * @returns The client-side options provider with children
764
- *
765
- * @see https://c15t.com/docs/frameworks/next/callbacks
766
- * @see https://c15t.com/docs/frameworks/next/script-loader
767
- */
768
- export function ConsentManagerClient({
769
- children,
770
- }: {
771
- children: ReactNode;
772
- }) {
773
- return (
774
- <ClientSideOptionsProvider
775
- // 📝 Add your integration scripts here
776
- // Scripts are loaded when consent is given and removed when consent is revoked
777
- scripts={[
778
- // Example:
779
- // googleTagManager({
780
- // id: 'GTM-XXXXXX',
781
- // script: {
782
- // onLoad: () => console.log('GTM loaded'),
783
- // },
784
- // }),
785
- ]}
786
- // 📝 Add your callbacks here
787
- // Callbacks allow you to react to consent events
788
- callbacks={{
789
- // Example:
790
- // onConsentSet(response) {
791
- // console.log('Consent updated:', response);
792
- // },
793
- // onError(error) {
794
- // console.error('Consent error:', error);
795
- // },
796
- }}
797
- >
798
- {children}
799
- </ClientSideOptionsProvider>
800
- );
801
- }
802
- `;
803
- }
804
- const HTML_TAG_REGEX = /<html[^>]*>([\s\S]*)<\/html>/;
805
- const BODY_TAG_REGEX = /<body[^>]*>([\s\S]*)<\/body>/;
806
- const BODY_OPENING_TAG_REGEX = /<body[^>]*>/;
807
- const HTML_CONTENT_REGEX = /([\s\S]*<\/html>)/;
808
- function findAppLayoutFile(project, projectRoot) {
809
- const layoutPatterns = [
810
- 'app/layout.tsx',
811
- 'src/app/layout.tsx',
812
- 'app/layout.ts',
813
- 'src/app/layout.ts'
814
- ];
815
- for (const pattern of layoutPatterns){
816
- const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
817
- if (files.length > 0) return files[0];
818
- }
819
- }
820
- function getAppDirectory(layoutFilePath) {
821
- const normalizedPath = node_path.normalize(layoutFilePath);
822
- const srcAppSegment = node_path.join('src', 'app');
823
- if (normalizedPath.includes(srcAppSegment)) return node_path.join('src', 'app');
824
- return 'app';
825
- }
826
- function computeRelativeModuleSpecifier(fromFilePath, toFilePath) {
827
- const fromDir = node_path.dirname(fromFilePath);
828
- let relativePath = node_path.relative(fromDir, toFilePath);
829
- relativePath = relativePath.split(node_path.sep).join('/');
830
- relativePath = relativePath.replace(/\.(tsx?|jsx?)$/, '');
831
- if (!relativePath.startsWith('.')) relativePath = `./${relativePath}`;
832
- return relativePath;
833
- }
834
- function addConsentManagerImport(layoutFile, consentManagerFilePath) {
835
- const layoutFilePath = layoutFile.getFilePath();
836
- const moduleSpecifier = computeRelativeModuleSpecifier(layoutFilePath, consentManagerFilePath);
837
- const existingImports = layoutFile.getImportDeclarations();
838
- const hasConsentManagerImport = existingImports.some((importDecl)=>{
839
- const existingSpec = importDecl.getModuleSpecifierValue();
840
- return existingSpec === moduleSpecifier || existingSpec.endsWith('consent-manager') || existingSpec.endsWith('consent-manager.tsx');
841
- });
842
- if (!hasConsentManagerImport) layoutFile.addImportDeclaration({
843
- namedImports: [
844
- 'ConsentManager'
845
- ],
846
- moduleSpecifier
847
- });
848
- }
849
- function wrapAppJsxContent(originalJsx) {
850
- const hasHtmlTag = originalJsx.includes('<html') || originalJsx.includes('</html>');
851
- const hasBodyTag = originalJsx.includes('<body') || originalJsx.includes('</body>');
852
- const consentWrapper = (content)=>`
853
- <ConsentManager>
854
- ${content}
855
- </ConsentManager>
856
- `;
857
- if (hasHtmlTag) {
858
- const htmlMatch = originalJsx.match(HTML_TAG_REGEX);
859
- const htmlContent = htmlMatch?.[1] || '';
860
- if (!htmlContent) return consentWrapper(originalJsx);
861
- const bodyMatch = htmlContent.match(BODY_TAG_REGEX);
862
- if (!bodyMatch) return originalJsx.replace(HTML_CONTENT_REGEX, `<html>${consentWrapper('$1')}</html>`);
863
- const bodyContent = bodyMatch[1] || '';
864
- const bodyOpeningTag = originalJsx.match(BODY_OPENING_TAG_REGEX)?.[0] || '<body>';
865
- return originalJsx.replace(BODY_TAG_REGEX, `${bodyOpeningTag}${consentWrapper(bodyContent)}</body>`);
866
- }
867
- if (hasBodyTag) {
868
- const bodyMatch = originalJsx.match(BODY_TAG_REGEX);
869
- const bodyContent = bodyMatch?.[1] || '';
870
- if (!bodyContent) return consentWrapper(originalJsx);
871
- const bodyOpeningTag = originalJsx.match(BODY_OPENING_TAG_REGEX)?.[0] || '<body>';
872
- return originalJsx.replace(BODY_TAG_REGEX, `${bodyOpeningTag}${consentWrapper(bodyContent)}</body>`);
873
- }
874
- return consentWrapper(originalJsx);
875
- }
876
- async function createConsentManagerComponents(projectRoot, appDir, optionsText) {
877
- const appDirPath = node_path.join(projectRoot, appDir);
878
- const consentManagerContent = generateConsentManagerTemplate(optionsText);
879
- const consentManagerClientContent = generateConsentManagerClientTemplate();
880
- const consentManagerPath = node_path.join(appDirPath, 'consent-manager.tsx');
881
- const consentManagerClientPath = node_path.join(appDirPath, 'consent-manager.client.tsx');
882
- await Promise.all([
883
- promises.writeFile(consentManagerPath, consentManagerContent, 'utf-8'),
884
- promises.writeFile(consentManagerClientPath, consentManagerClientContent, 'utf-8')
885
- ]);
886
- return {
887
- consentManager: consentManagerPath,
888
- consentManagerClient: consentManagerClientPath
889
- };
890
- }
891
- async function updateAppLayout({ projectRoot, mode, backendURL, useEnvFile, proxyNextjs }) {
892
- const project = new Project();
893
- const layoutFile = findAppLayoutFile(project, projectRoot);
894
- if (!layoutFile) return {
895
- updated: false,
896
- filePath: null,
897
- alreadyModified: false
898
- };
899
- const layoutFilePath = layoutFile.getFilePath();
900
- const appDir = getAppDirectory(layoutFilePath);
901
- const existingImports = layoutFile.getImportDeclarations();
902
- const hasConsentManagerImport = existingImports.some((importDecl)=>'./consent-manager' === importDecl.getModuleSpecifierValue() || './consent-manager.tsx' === importDecl.getModuleSpecifierValue());
903
- if (hasConsentManagerImport) return {
904
- updated: false,
905
- filePath: layoutFilePath,
906
- alreadyModified: true
907
- };
908
- const optionsText = generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs);
909
- const componentFiles = await createConsentManagerComponents(projectRoot, appDir, optionsText);
910
- addConsentManagerImport(layoutFile, componentFiles.consentManager);
911
- const returnStatement = layoutFile.getDescendantsOfKind(SyntaxKind.ReturnStatement)[0];
912
- if (!returnStatement) return {
913
- updated: false,
914
- filePath: layoutFilePath,
915
- alreadyModified: false
916
- };
917
- const expression = returnStatement.getExpression();
918
- if (!expression) return {
919
- updated: false,
920
- filePath: layoutFilePath,
921
- alreadyModified: false
922
- };
923
- const originalJsx = expression.getText();
924
- const newJsx = wrapAppJsxContent(originalJsx);
925
- returnStatement.replaceWithText(`return ${newJsx}`);
926
- await layoutFile.save();
927
- return {
928
- updated: true,
929
- filePath: layoutFilePath,
930
- alreadyModified: false,
931
- componentFiles
932
- };
933
- }
934
- function components_generateConsentManagerTemplate(optionsText) {
935
- return `import type { ReactNode } from 'react';
936
- import {
937
- ConsentManagerDialog,
938
- ConsentManagerProvider,
939
- CookieBanner,
940
- type InitialDataPromise
941
- } from '@c15t/nextjs/pages';
942
- // For client-only apps (non-SSR), you can use:
943
- // import { ConsentManagerProvider } from '@c15t/nextjs/client';
944
-
945
- /**
946
- * Consent management wrapper for Next.js Pages Router
947
- *
948
- * This component wraps your app with consent management functionality,
949
- * including the cookie banner, consent dialog, and provider.
950
- *
951
- * @param props - Component properties
952
- * @param props.children - Child components to render within the consent manager context
953
- * @param props.initialData - Initial consent data from server-side props (optional)
954
- *
955
- * @returns The consent manager provider with banner and dialog
956
- *
957
- * @remarks
958
- * To get initial server-side data on other pages, use:
959
- * \`\`\`tsx
960
- * import { withInitialC15TData } from '@c15t/nextjs/pages';
961
- *
962
- * export const getServerSideProps = withInitialC15TData('/api/c15t');
963
- * \`\`\`
964
- *
965
- * @example
966
- * \`\`\`tsx
967
- * // In your pages/_app.tsx
968
- * import { ConsentManager } from '../components/consent-manager';
969
- *
970
- * export default function MyApp({ Component, pageProps }) {
971
- * return (
972
- * <ConsentManager initialData={pageProps.initialC15TData}>
973
- * <Component {...pageProps} />
974
- * </ConsentManager>
975
- * );
976
- * }
977
- * \`\`\`
978
- */
979
- export function ConsentManager({
980
- children,
981
- initialData,
982
- }: {
983
- children: ReactNode;
984
- initialData?: InitialDataPromise;
985
- }) {
986
- return (
987
- <ConsentManagerProvider
988
- initialData={initialData}
989
- options={${optionsText}}
990
- >
991
- <CookieBanner />
992
- <ConsentManagerDialog />
993
- {children}
994
- </ConsentManagerProvider>
995
- );
996
- }
997
- `;
998
- }
999
- function findPagesAppFile(project, projectRoot) {
1000
- const appPatterns = [
1001
- 'pages/_app.tsx',
1002
- 'pages/_app.ts',
1003
- 'src/pages/_app.tsx',
1004
- 'src/pages/_app.ts'
1005
- ];
1006
- for (const pattern of appPatterns){
1007
- const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
1008
- if (files.length > 0) return files[0];
1009
- }
1010
- }
1011
- function getPagesDirectory(appFilePath) {
1012
- const normalizedPath = node_path.normalize(appFilePath);
1013
- const srcPagesSegment = node_path.join('src', 'pages');
1014
- if (normalizedPath.includes(srcPagesSegment)) return node_path.join('src', 'pages');
1015
- return 'pages';
1016
- }
1017
- function layout_computeRelativeModuleSpecifier(fromFilePath, toFilePath) {
1018
- const fromDir = node_path.dirname(fromFilePath);
1019
- let relativePath = node_path.relative(fromDir, toFilePath);
1020
- relativePath = relativePath.split(node_path.sep).join('/');
1021
- relativePath = relativePath.replace(/\.(tsx?|jsx?)$/, '');
1022
- if (!relativePath.startsWith('.')) relativePath = `./${relativePath}`;
1023
- return relativePath;
1024
- }
1025
- function layout_addConsentManagerImport(appFile, consentManagerFilePath) {
1026
- const appFilePath = appFile.getFilePath();
1027
- const moduleSpecifier = layout_computeRelativeModuleSpecifier(appFilePath, consentManagerFilePath);
1028
- const existingImports = appFile.getImportDeclarations();
1029
- const hasConsentManagerImport = existingImports.some((importDecl)=>{
1030
- const existingSpec = importDecl.getModuleSpecifierValue();
1031
- return existingSpec === moduleSpecifier || existingSpec.endsWith('consent-manager') || existingSpec.endsWith('consent-manager.tsx');
1032
- });
1033
- if (!hasConsentManagerImport) appFile.addImportDeclaration({
1034
- namedImports: [
1035
- 'ConsentManager'
1036
- ],
1037
- moduleSpecifier
1038
- });
1039
- }
1040
- function wrapPagesJsxContent(originalJsx) {
1041
- const trimmedJsx = originalJsx.trim();
1042
- const hasParentheses = trimmedJsx.startsWith('(') && trimmedJsx.endsWith(')');
1043
- const cleanJsx = hasParentheses ? trimmedJsx.slice(1, -1).trim() : originalJsx;
1044
- const wrappedContent = `
1045
- <ConsentManager initialData={pageProps.initialC15TData}>
1046
- ${cleanJsx}
1047
- </ConsentManager>
1048
- `;
1049
- return `(${wrappedContent})`;
1050
- }
1051
- async function createConsentManagerComponent(projectRoot, pagesDir, optionsText) {
1052
- let componentsDir;
1053
- componentsDir = pagesDir.includes('src') ? node_path.join('src', 'components') : 'components';
1054
- const componentsDirPath = node_path.join(projectRoot, componentsDir);
1055
- await promises.mkdir(componentsDirPath, {
1056
- recursive: true
1057
- });
1058
- const consentManagerContent = components_generateConsentManagerTemplate(optionsText);
1059
- const consentManagerPath = node_path.join(componentsDirPath, 'consent-manager.tsx');
1060
- await promises.writeFile(consentManagerPath, consentManagerContent, 'utf-8');
1061
- return {
1062
- consentManager: consentManagerPath
1063
- };
1064
- }
1065
- function addServerSideDataComment(appFile, backendURL, useEnvFile, proxyNextjs) {
1066
- const existingComments = appFile.getLeadingCommentRanges();
1067
- let urlExample;
1068
- urlExample = proxyNextjs ? "'/api/c15t'" : useEnvFile ? 'process.env.NEXT_PUBLIC_C15T_URL!' : `'${backendURL || 'https://your-instance.c15t.dev'}'`;
1069
- const serverSideComment = `/**
1070
- * Note: To get the initial server-side data on other pages, add this to each page:
1071
- *
1072
- * import { withInitialC15TData } from '@c15t/nextjs/pages';
1073
- *
1074
- * export const getServerSideProps = withInitialC15TData(${urlExample});
1075
- *
1076
- * This will automatically pass initialC15TData to pageProps.initialC15TData
1077
- */`;
1078
- const hasServerSideComment = existingComments.some((comment)=>comment.getText().includes('withInitialC15TData'));
1079
- if (!hasServerSideComment) appFile.insertText(0, `${serverSideComment}\n\n`);
1080
- }
1081
- function updateAppComponentTyping(appFile) {
1082
- const exportAssignment = appFile.getExportAssignment(()=>true);
1083
- if (!exportAssignment) return;
1084
- const declaration = exportAssignment.getExpression();
1085
- if (!declaration) return;
1086
- const text = declaration.getText();
1087
- if (text.includes('pageProps') && !text.includes('AppProps')) {
1088
- const hasAppPropsImport = appFile.getImportDeclarations().some((importDecl)=>'next/app' === importDecl.getModuleSpecifierValue() && importDecl.getNamedImports().some((namedImport)=>'AppProps' === namedImport.getName()));
1089
- if (!hasAppPropsImport) appFile.addImportDeclaration({
1090
- namedImports: [
1091
- 'AppProps'
1092
- ],
1093
- moduleSpecifier: 'next/app'
807
+ try {
808
+ const potentialFiles = [
809
+ external_node_path_["default"].join(projectRoot, 'c15t.config.ts'),
810
+ external_node_path_["default"].join(projectRoot, '.env.local'),
811
+ external_node_path_["default"].join(projectRoot, '.env.example'),
812
+ external_node_path_["default"].join(projectRoot, 'next.config.ts'),
813
+ external_node_path_["default"].join(projectRoot, 'next.config.js'),
814
+ external_node_path_["default"].join(projectRoot, 'next.config.mjs')
815
+ ];
816
+ for (const filePath of potentialFiles){
817
+ const exists = await fileExists(filePath);
818
+ if (exists) {
819
+ const backup = await readFileForBackup(filePath);
820
+ if (null !== backup) filesModified.push({
821
+ path: filePath,
822
+ backup,
823
+ type: 'modified'
824
+ });
825
+ }
826
+ }
827
+ const generateResult = await generateFiles({
828
+ context: cliContext,
829
+ mode: mode,
830
+ spinner: spinnerMock,
831
+ backendURL: backendURL ?? void 0,
832
+ useEnvFile,
833
+ proxyNextjs,
834
+ enableSSR,
835
+ enableDevTools,
836
+ uiStyle,
837
+ expandedTheme: expandedTheme ?? void 0,
838
+ selectedScripts
1094
839
  });
1095
- }
1096
- }
1097
- async function updatePagesLayout({ projectRoot, mode, backendURL, useEnvFile, proxyNextjs }) {
1098
- const project = new Project();
1099
- const appFile = findPagesAppFile(project, projectRoot);
1100
- if (!appFile) return {
1101
- updated: false,
1102
- filePath: null,
1103
- alreadyModified: false
1104
- };
1105
- const appFilePath = appFile.getFilePath();
1106
- const pagesDir = getPagesDirectory(appFilePath);
1107
- const existingImports = appFile.getImportDeclarations();
1108
- const hasConsentManagerImport = existingImports.some((importDecl)=>{
1109
- const specifier = importDecl.getModuleSpecifierValue();
1110
- return specifier.endsWith('/consent-manager') || specifier.endsWith('/consent-manager.tsx') || './consent-manager' === specifier || './consent-manager.tsx' === specifier;
1111
- });
1112
- if (hasConsentManagerImport) return {
1113
- updated: false,
1114
- filePath: appFilePath,
1115
- alreadyModified: true
1116
- };
1117
- const optionsText = generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs);
1118
- const componentFiles = await createConsentManagerComponent(projectRoot, pagesDir, optionsText);
1119
- layout_addConsentManagerImport(appFile, componentFiles.consentManager);
1120
- updateAppComponentTyping(appFile);
1121
- addServerSideDataComment(appFile, backendURL, useEnvFile, proxyNextjs);
1122
- const returnStatement = appFile.getDescendantsOfKind(SyntaxKind.ReturnStatement)[0];
1123
- if (!returnStatement) return {
1124
- updated: false,
1125
- filePath: appFilePath,
1126
- alreadyModified: false
1127
- };
1128
- const expression = returnStatement.getExpression();
1129
- if (!expression) return {
1130
- updated: false,
1131
- filePath: appFilePath,
1132
- alreadyModified: false
1133
- };
1134
- const originalJsx = expression.getText();
1135
- const newJsx = wrapPagesJsxContent(originalJsx);
1136
- returnStatement.replaceWithText(`return ${newJsx}`);
1137
- await appFile.save();
1138
- return {
1139
- updated: true,
1140
- filePath: appFilePath,
1141
- alreadyModified: false,
1142
- componentFiles
1143
- };
1144
- }
1145
- function detectNextJsStructure(projectRoot) {
1146
- const project = new Project();
1147
- const appLayoutPatterns = [
1148
- 'app/layout.tsx',
1149
- 'src/app/layout.tsx',
1150
- 'app/layout.ts',
1151
- 'src/app/layout.ts'
1152
- ];
1153
- for (const pattern of appLayoutPatterns){
1154
- const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
1155
- if (files.length > 0) return 'app';
1156
- }
1157
- const pagesAppPatterns = [
1158
- 'pages/_app.tsx',
1159
- 'pages/_app.ts',
1160
- 'src/pages/_app.tsx',
1161
- 'src/pages/_app.ts'
1162
- ];
1163
- for (const pattern of pagesAppPatterns){
1164
- const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
1165
- if (files.length > 0) return 'pages';
1166
- }
1167
- return null;
1168
- }
1169
- async function updateNextLayout(options) {
1170
- const structureType = detectNextJsStructure(options.projectRoot);
1171
- if (!structureType) return {
1172
- updated: false,
1173
- filePath: null,
1174
- alreadyModified: false,
1175
- structureType: null
1176
- };
1177
- let result;
1178
- result = 'app' === structureType ? await updateAppLayout(options) : await updatePagesLayout(options);
1179
- return {
1180
- ...result,
1181
- structureType
1182
- };
1183
- }
1184
- function react_components_generateConsentManagerTemplate(optionsText) {
1185
- return `import type { ReactNode } from 'react';
1186
- import {
1187
- ConsentManagerDialog,
1188
- ConsentManagerProvider,
1189
- CookieBanner,
1190
- } from '@c15t/react';
1191
-
1192
- /**
1193
- * Consent management wrapper for React
1194
- *
1195
- * This component wraps your app with consent management functionality,
1196
- * including the cookie banner, consent dialog, and provider.
1197
- *
1198
- * @param props - Component properties
1199
- * @param props.children - Child components to render within the consent manager context
1200
- *
1201
- * @returns The consent manager provider with banner and dialog
1202
- *
1203
- * @example
1204
- * \`\`\`tsx
1205
- * // In your App.tsx
1206
- * import { ConsentManager } from './consent-manager';
1207
- *
1208
- * export default function App() {
1209
- * return (
1210
- * <ConsentManager>
1211
- * <YourApp />
1212
- * </ConsentManager>
1213
- * );
1214
- * }
1215
- * \`\`\`
1216
- */
1217
- export function ConsentManager({ children }: { children: ReactNode }) {
1218
- return (
1219
- <ConsentManagerProvider
1220
- options={${optionsText}}
1221
- >
1222
- <CookieBanner />
1223
- <ConsentManagerDialog />
1224
- {children}
1225
- </ConsentManagerProvider>
1226
- );
1227
- }
1228
- `;
1229
- }
1230
- function templates_layout_computeRelativeModuleSpecifier(fromFilePath, toFilePath) {
1231
- const fromDir = node_path.dirname(fromFilePath);
1232
- let relativePath = node_path.relative(fromDir, toFilePath);
1233
- relativePath = relativePath.split(node_path.sep).join('/');
1234
- relativePath = relativePath.replace(/\.(tsx?|jsx?)$/, '');
1235
- if (!relativePath.startsWith('.')) relativePath = `./${relativePath}`;
1236
- return relativePath;
1237
- }
1238
- function templates_layout_addConsentManagerImport(layoutFile, consentManagerFilePath) {
1239
- const layoutFilePath = layoutFile.getFilePath();
1240
- const moduleSpecifier = templates_layout_computeRelativeModuleSpecifier(layoutFilePath, consentManagerFilePath);
1241
- const existingImports = layoutFile.getImportDeclarations();
1242
- const hasConsentManagerImport = existingImports.some((importDecl)=>{
1243
- const existingSpec = importDecl.getModuleSpecifierValue();
1244
- return existingSpec === moduleSpecifier || existingSpec.endsWith('consent-manager') || existingSpec.endsWith('consent-manager.tsx');
1245
- });
1246
- if (!hasConsentManagerImport) layoutFile.addImportDeclaration({
1247
- namedImports: [
1248
- 'ConsentManager'
1249
- ],
1250
- moduleSpecifier
1251
- });
1252
- }
1253
- function getSourceDirectory(layoutFilePath) {
1254
- const normalizedPath = node_path.normalize(layoutFilePath);
1255
- const segments = normalizedPath.split(node_path.sep);
1256
- if (segments.includes('src')) return 'src';
1257
- return '';
1258
- }
1259
- function updateGenericReactJsx(layoutFile) {
1260
- const functionDeclarations = layoutFile.getFunctions();
1261
- const variableDeclarations = layoutFile.getVariableDeclarations();
1262
- for (const func of functionDeclarations){
1263
- const returnStatement = func.getDescendantsOfKind(SyntaxKind.ReturnStatement)[0];
1264
- if (returnStatement) return wrapReturnStatementWithConsentManager(returnStatement);
1265
- }
1266
- for (const varDecl of variableDeclarations){
1267
- const initializer = varDecl.getInitializer();
1268
- if (initializer) {
1269
- const returnStatement = initializer.getDescendantsOfKind(SyntaxKind.ReturnStatement)[0];
1270
- if (returnStatement) return wrapReturnStatementWithConsentManager(returnStatement);
840
+ if (generateResult.configPath) {
841
+ result.configPath = generateResult.configPath;
842
+ if (!filesModified.some((f)=>f.path === generateResult.configPath)) filesCreated.push(generateResult.configPath);
1271
843
  }
1272
- }
1273
- return false;
1274
- }
1275
- function wrapReturnStatementWithConsentManager(returnStatement) {
1276
- const expression = returnStatement.getExpression();
1277
- if (!expression) return false;
1278
- const originalJsx = expression.getText();
1279
- const newJsx = `(
1280
- <ConsentManager>
1281
- ${originalJsx}
1282
- </ConsentManager>
1283
- )`;
1284
- returnStatement.replaceWithText(`return ${newJsx}`);
1285
- return true;
1286
- }
1287
- async function layout_createConsentManagerComponent(projectRoot, sourceDir, optionsText) {
1288
- const targetDir = sourceDir ? node_path.join(projectRoot, sourceDir) : projectRoot;
1289
- const consentManagerContent = react_components_generateConsentManagerTemplate(optionsText);
1290
- const consentManagerPath = node_path.join(targetDir, 'consent-manager.tsx');
1291
- await promises.writeFile(consentManagerPath, consentManagerContent, 'utf-8');
1292
- return {
1293
- consentManager: consentManagerPath
1294
- };
1295
- }
1296
- async function updateGenericReactLayout({ projectRoot, mode, backendURL, useEnvFile, proxyNextjs }) {
1297
- const layoutPatterns = [
1298
- 'app.tsx',
1299
- 'App.tsx',
1300
- 'app.jsx',
1301
- 'App.jsx',
1302
- 'src/app.tsx',
1303
- 'src/App.tsx',
1304
- 'src/app.jsx',
1305
- 'src/App.jsx',
1306
- 'src/app/app.tsx',
1307
- 'src/app/App.tsx',
1308
- 'src/app/app.jsx',
1309
- 'src/app/App.jsx'
1310
- ];
1311
- const project = new Project();
1312
- let layoutFile;
1313
- for (const pattern of layoutPatterns)try {
1314
- const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
1315
- if (files.length > 0) {
1316
- layoutFile = files[0];
1317
- break;
844
+ if (generateResult.layoutPath) result.layoutPath = generateResult.layoutPath;
845
+ if (generateResult.nextConfigPath) {
846
+ result.nextConfigPath = generateResult.nextConfigPath;
847
+ if (generateResult.nextConfigCreated) filesCreated.push(generateResult.nextConfigPath);
1318
848
  }
1319
- } catch {}
1320
- if (!layoutFile) return {
1321
- updated: false,
1322
- filePath: null,
1323
- alreadyModified: false
1324
- };
1325
- const layoutFilePath = layoutFile.getFilePath();
1326
- const sourceDir = getSourceDirectory(layoutFilePath);
1327
- const existingImports = layoutFile.getImportDeclarations();
1328
- const hasConsentManagerImport = existingImports.some((importDecl)=>'./consent-manager' === importDecl.getModuleSpecifierValue() || './consent-manager.tsx' === importDecl.getModuleSpecifierValue());
1329
- if (hasConsentManagerImport) return {
1330
- updated: false,
1331
- filePath: layoutFilePath,
1332
- alreadyModified: true
1333
- };
1334
- try {
1335
- const optionsText = generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs);
1336
- const componentFiles = await layout_createConsentManagerComponent(projectRoot, sourceDir, optionsText);
1337
- templates_layout_addConsentManagerImport(layoutFile, componentFiles.consentManager);
1338
- const updated = updateGenericReactJsx(layoutFile);
1339
- if (updated) {
1340
- await layoutFile.save();
1341
- return {
1342
- updated: true,
1343
- filePath: layoutFilePath,
1344
- alreadyModified: false,
1345
- componentFiles
1346
- };
849
+ if (useEnvFile && backendURL) {
850
+ const envPath = external_node_path_["default"].join(projectRoot, '.env.local');
851
+ const envExamplePath = external_node_path_["default"].join(projectRoot, '.env.example');
852
+ if (!filesModified.some((f)=>f.path === envPath) && await fileExists(envPath)) filesCreated.push(envPath);
853
+ result.envPath = envPath;
854
+ if (!filesModified.some((f)=>f.path === envExamplePath) && await fileExists(envExamplePath)) filesCreated.push(envExamplePath);
1347
855
  }
1348
- return {
1349
- updated: false,
1350
- filePath: layoutFilePath,
1351
- alreadyModified: false
1352
- };
856
+ result.filesCreated = filesCreated;
857
+ result.filesModified = filesModified;
858
+ const allFiles = [
859
+ ...filesCreated,
860
+ ...filesModified.map((f)=>f.path),
861
+ generateResult.layoutPath
862
+ ].filter((f)=>!!f);
863
+ await formatGeneratedFiles(projectRoot, allFiles, logger);
864
+ return result;
1353
865
  } catch (error) {
1354
- throw new Error(`Failed to update generic React layout: ${error instanceof Error ? error.message : String(error)}`);
866
+ result.filesCreated = filesCreated;
867
+ result.filesModified = filesModified;
868
+ throw error;
1355
869
  }
1356
- }
1357
- async function updateReactLayout(options) {
1358
- if ('@c15t/nextjs' === options.pkg) {
1359
- const nextResult = await updateNextLayout(options);
1360
- if (nextResult.structureType) return {
1361
- updated: nextResult.updated,
1362
- filePath: nextResult.filePath,
1363
- alreadyModified: nextResult.alreadyModified,
1364
- componentFiles: nextResult.componentFiles
1365
- };
870
+ });
871
+ const rollbackActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
872
+ const { filesCreated, filesModified } = input;
873
+ const fs = await import("node:fs/promises");
874
+ const errors = [];
875
+ for (const filePath of filesCreated)try {
876
+ await fs.unlink(filePath);
877
+ } catch (error) {
878
+ errors.push(`Failed to delete ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
1366
879
  }
1367
- return updateGenericReactLayout(options);
1368
- }
1369
- async function updateNextConfig({ projectRoot, backendURL, useEnvFile }) {
1370
- const project = new Project();
1371
- const configFile = findNextConfigFile(project, projectRoot);
1372
- if (!configFile) {
1373
- const newConfigPath = `${projectRoot}/next.config.ts`;
1374
- const newConfig = createNewNextConfig(backendURL, useEnvFile);
1375
- const newConfigFile = project.createSourceFile(newConfigPath, newConfig);
1376
- await newConfigFile.save();
1377
- return {
1378
- updated: true,
1379
- filePath: newConfigPath,
1380
- alreadyModified: false,
1381
- created: true
1382
- };
880
+ for (const mod of filesModified)try {
881
+ await fs.writeFile(mod.path, mod.backup, 'utf-8');
882
+ } catch (error) {
883
+ errors.push(`Failed to restore ${mod.path}: ${error instanceof Error ? error.message : String(error)}`);
1383
884
  }
1384
- if (hasC15tRewriteRule(configFile)) return {
1385
- updated: false,
1386
- filePath: configFile.getFilePath(),
1387
- alreadyModified: true,
1388
- created: false
1389
- };
1390
- const updated = await updateExistingConfig(configFile, backendURL, useEnvFile);
1391
- if (updated) await configFile.save();
1392
885
  return {
1393
- updated,
1394
- filePath: configFile.getFilePath(),
1395
- alreadyModified: false,
1396
- created: false
886
+ success: 0 === errors.length,
887
+ errors
1397
888
  };
1398
- }
1399
- function findNextConfigFile(project, projectRoot) {
1400
- const configPatterns = [
1401
- 'next.config.ts',
1402
- 'next.config.js',
1403
- 'next.config.mjs'
1404
- ];
1405
- for (const pattern of configPatterns){
1406
- const configPath = `${projectRoot}/${pattern}`;
1407
- try {
1408
- const files = project.addSourceFilesAtPaths(configPath);
1409
- if (files.length > 0) return files[0];
1410
- } catch {}
1411
- }
1412
- }
1413
- function hasC15tRewriteRule(configFile) {
1414
- const text = configFile.getFullText();
1415
- return text.includes('/api/c15t/') || text.includes("'/api/c15t/:path*'");
1416
- }
1417
- function generateRewriteDestination(backendURL, useEnvFile) {
1418
- if (useEnvFile) return {
1419
- destination: '${process.env.NEXT_PUBLIC_C15T_URL}/:path*',
1420
- isTemplateLiteral: true
1421
- };
1422
- return {
1423
- destination: `${backendURL || 'https://your-instance.c15t.dev'}/:path*`,
1424
- isTemplateLiteral: false
1425
- };
1426
- }
1427
- function createNewNextConfig(backendURL, useEnvFile) {
1428
- const { destination, isTemplateLiteral } = generateRewriteDestination(backendURL, useEnvFile);
1429
- const destinationValue = isTemplateLiteral ? `\`${destination}\`` : `'${destination}'`;
1430
- return `import type { NextConfig } from 'next';
1431
-
1432
- const config: NextConfig = {
1433
- async rewrites() {
1434
- return [
1435
- {
1436
- source: '/api/c15t/:path*',
1437
- destination: ${destinationValue},
1438
- },
1439
- ];
1440
- },
1441
- };
1442
-
1443
- export default config;
1444
- `;
1445
- }
1446
- function createRewriteRule(destination, isTemplateLiteral) {
1447
- const destinationValue = isTemplateLiteral ? `\`${destination}\`` : `'${destination}'`;
1448
- return `{
1449
- source: '/api/c15t/:path*',
1450
- destination: ${destinationValue},
1451
- }`;
1452
- }
1453
- function updateExistingConfig(configFile, backendURL, useEnvFile) {
1454
- const { destination, isTemplateLiteral } = generateRewriteDestination(backendURL, useEnvFile);
1455
- const configObject = findConfigObject(configFile);
1456
- if (!configObject) return false;
1457
- const rewritesProperty = configObject.getProperty('rewrites');
1458
- if (rewritesProperty && Node.isMethodDeclaration(rewritesProperty)) return updateExistingRewrites(rewritesProperty, destination, isTemplateLiteral);
1459
- if (rewritesProperty && Node.isPropertyAssignment(rewritesProperty)) return updatePropertyAssignmentRewrites(rewritesProperty, destination, isTemplateLiteral);
1460
- return addNewRewritesMethod(configObject, destination, isTemplateLiteral);
1461
- }
1462
- function findConfigObject(configFile) {
1463
- return findConfigFromExportDefault(configFile) || findConfigFromVariableDeclarations(configFile);
1464
- }
1465
- function findConfigFromExportDefault(configFile) {
1466
- const exportDefault = configFile.getDefaultExportSymbol();
1467
- if (!exportDefault) return;
1468
- const declarations = exportDefault.getDeclarations();
1469
- for (const declaration of declarations)if (Node.isExportAssignment(declaration)) {
1470
- const result = findConfigFromExpression(declaration.getExpression(), configFile);
1471
- if (result) return result;
1472
- }
1473
- }
1474
- function findConfigFromExpression(expression, configFile) {
1475
- if (Node.isCallExpression(expression)) return findConfigFromCallExpression(expression, configFile);
1476
- if (Node.isObjectLiteralExpression(expression)) return expression;
1477
- if (Node.isIdentifier(expression)) return findConfigFromIdentifier(expression.getText(), configFile);
1478
- }
1479
- function findConfigFromCallExpression(expression, configFile) {
1480
- const args = expression.getArguments();
1481
- if (0 === args.length) return;
1482
- const firstArg = args[0];
1483
- if (Node.isCallExpression(firstArg)) {
1484
- const innerArgs = firstArg.getArguments();
1485
- if (innerArgs.length > 0 && Node.isIdentifier(innerArgs[0])) return findConfigFromIdentifier(innerArgs[0].getText(), configFile);
1486
- }
1487
- }
1488
- function findConfigFromIdentifier(identifierText, configFile) {
1489
- const configVar = configFile.getVariableDeclaration(identifierText);
1490
- const initializer = configVar?.getInitializer();
1491
- return initializer && Node.isObjectLiteralExpression(initializer) ? initializer : void 0;
1492
- }
1493
- function findConfigFromVariableDeclarations(configFile) {
1494
- const variableDeclarations = configFile.getVariableDeclarations();
1495
- for (const varDecl of variableDeclarations){
1496
- const typeNode = varDecl.getTypeNode();
1497
- if (typeNode?.getText().includes('NextConfig')) {
1498
- const initializer = varDecl.getInitializer();
1499
- if (Node.isObjectLiteralExpression(initializer)) return initializer;
1500
- }
1501
- }
1502
- }
1503
- function updateExistingRewrites(rewritesMethod, destination, isTemplateLiteral) {
1504
- const body = rewritesMethod.getBody();
1505
- if (!Node.isBlock(body)) return false;
1506
- const returnStatement = body.getStatements().find((stmt)=>Node.isReturnStatement(stmt));
1507
- if (!returnStatement || !Node.isReturnStatement(returnStatement)) return false;
1508
- const expression = returnStatement.getExpression();
1509
- if (!expression || !Node.isArrayLiteralExpression(expression)) return false;
1510
- const newRewrite = createRewriteRule(destination, isTemplateLiteral);
1511
- const elements = expression.getElements();
1512
- if (elements.length > 0) expression.insertElement(0, newRewrite);
1513
- else expression.addElement(newRewrite);
1514
- return true;
1515
- }
1516
- function updatePropertyAssignmentRewrites(rewritesProperty, destination, isTemplateLiteral) {
1517
- const initializer = rewritesProperty.getInitializer();
1518
- if (Node.isArrayLiteralExpression(initializer)) {
1519
- const newRewrite = createRewriteRule(destination, isTemplateLiteral);
1520
- initializer.insertElement(0, newRewrite);
889
+ });
890
+ async function preflight_fileExists(filePath) {
891
+ try {
892
+ const fs = await import("node:fs/promises");
893
+ await fs.access(filePath);
1521
894
  return true;
895
+ } catch {
896
+ return false;
1522
897
  }
1523
- return false;
1524
- }
1525
- function addNewRewritesMethod(configObject, destination, isTemplateLiteral) {
1526
- const destinationValue = isTemplateLiteral ? `\`${destination}\`` : `'${destination}'`;
1527
- const rewritesMethod = `async rewrites() {
1528
- return [
1529
- {
1530
- source: '/api/c15t/:path*',
1531
- destination: ${destinationValue},
1532
- },
1533
- ];
1534
- }`;
1535
- configObject.addProperty(rewritesMethod);
1536
- return true;
1537
- }
1538
- async function handleReactLayout(options) {
1539
- const { projectRoot, mode, backendURL, useEnvFile, proxyNextjs, pkg, spinner, cwd } = options;
1540
- spinner.start('Updating layout file...');
1541
- const layoutResult = await updateReactLayout({
1542
- projectRoot,
1543
- mode,
1544
- backendURL,
1545
- useEnvFile,
1546
- proxyNextjs,
1547
- pkg
1548
- });
1549
- const spinnerMessage = ()=>{
1550
- if (layoutResult.alreadyModified) return {
1551
- message: 'ConsentManager is already imported. Skipped layout file update.',
1552
- type: 'info'
1553
- };
1554
- if (layoutResult.updated) {
1555
- const typedResult = layoutResult;
1556
- if (typedResult.componentFiles) {
1557
- const relativeConsentManager = node_path.relative(cwd, typedResult.componentFiles.consentManager);
1558
- const relativeLayout = node_path.relative(cwd, layoutResult.filePath || '');
1559
- if (typedResult.componentFiles.consentManagerClient) {
1560
- const relativeConsentManagerClient = node_path.relative(cwd, typedResult.componentFiles.consentManagerClient);
1561
- return {
1562
- message: `Layout setup complete!\n ${picocolors.green('✓')} Created: ${picocolors.cyan(relativeConsentManager)}\n ${picocolors.green('✓')} Created: ${picocolors.cyan(relativeConsentManagerClient)}\n ${picocolors.green('✓')} Updated: ${picocolors.cyan(relativeLayout)}`,
1563
- type: 'info'
1564
- };
1565
- }
1566
- return {
1567
- message: `Layout setup complete!\n ${picocolors.green('✓')} Created: ${picocolors.cyan(relativeConsentManager)}\n ${picocolors.green('✓')} Updated: ${picocolors.cyan(relativeLayout)}`,
1568
- type: 'info'
1569
- };
1570
- }
1571
- return {
1572
- message: `Layout file updated: ${layoutResult.filePath}`,
1573
- type: 'info'
1574
- };
1575
- }
1576
- return {
1577
- message: 'Layout file not updated.',
1578
- type: 'error'
1579
- };
1580
- };
1581
- const { message, type } = spinnerMessage();
1582
- spinner.stop(formatLogMessage(type, message));
1583
- return {
1584
- layoutUpdated: layoutResult.updated,
1585
- layoutPath: layoutResult.filePath
1586
- };
1587
898
  }
1588
- async function handleNextConfig(options) {
1589
- const { projectRoot, backendURL, useEnvFile, spinner } = options;
1590
- spinner.start('Updating Next.js config...');
1591
- const configResult = await updateNextConfig({
1592
- projectRoot,
1593
- backendURL,
1594
- useEnvFile
1595
- });
1596
- const spinnerMessage = ()=>{
1597
- if (configResult.alreadyModified) return {
1598
- message: 'Next.js config already has c15t rewrite rule. Skipped config update.',
1599
- type: 'info'
1600
- };
1601
- if (configResult.updated && configResult.created) return {
1602
- message: `Next.js config created: ${configResult.filePath}`,
1603
- type: 'info'
899
+ async function checkGitStatus(projectRoot) {
900
+ try {
901
+ const gitDir = external_node_path_["default"].join(projectRoot, '.git');
902
+ const isGitRepo = await preflight_fileExists(gitDir);
903
+ if (!isGitRepo) return {
904
+ name: 'Git',
905
+ status: 'warn',
906
+ message: 'Not a git repository',
907
+ hint: 'Consider initializing git to track changes'
1604
908
  };
1605
- if (configResult.updated) return {
1606
- message: `Next.js config updated: ${configResult.filePath}`,
1607
- type: 'info'
909
+ return {
910
+ name: 'Git',
911
+ status: 'pass',
912
+ message: 'Git repository detected'
1608
913
  };
914
+ } catch {
1609
915
  return {
1610
- message: 'Next.js config not updated.',
1611
- type: 'error'
916
+ name: 'Git',
917
+ status: 'warn',
918
+ message: 'Could not check git status'
1612
919
  };
1613
- };
1614
- const { message, type } = spinnerMessage();
1615
- spinner.stop(formatLogMessage(type, message));
920
+ }
921
+ }
922
+ async function runPreflightChecks(context) {
923
+ const { projectRoot, framework, packageManager, logger } = context;
924
+ const checks = [];
925
+ logger.debug('Running preflight checks...');
926
+ const packageJsonPath = external_node_path_["default"].join(projectRoot, 'package.json');
927
+ const hasPackageJson = await preflight_fileExists(packageJsonPath);
928
+ checks.push({
929
+ name: 'package.json',
930
+ status: hasPackageJson ? 'pass' : 'fail',
931
+ message: hasPackageJson ? 'Found package.json' : 'No package.json found',
932
+ hint: hasPackageJson ? void 0 : 'Make sure you are in a JavaScript/TypeScript project'
933
+ });
934
+ checks.push({
935
+ name: 'Framework',
936
+ status: framework.framework ? 'pass' : 'warn',
937
+ message: framework.framework ? `Detected ${framework.framework}` : 'No framework detected',
938
+ hint: framework.framework ? void 0 : 'Will use vanilla JavaScript setup'
939
+ });
940
+ if ('c15t' !== framework.pkg) checks.push({
941
+ name: 'React',
942
+ status: framework.hasReact ? 'pass' : 'warn',
943
+ message: framework.hasReact ? `Found React ${framework.reactVersion || ''}` : 'React not detected',
944
+ hint: framework.hasReact ? void 0 : 'c15t works best with React'
945
+ });
946
+ checks.push({
947
+ name: 'Package Manager',
948
+ status: packageManager.name ? 'pass' : 'warn',
949
+ message: packageManager.name ? `Using ${packageManager.name}` : 'No package manager detected',
950
+ hint: packageManager.name ? void 0 : 'Will default to npm'
951
+ });
952
+ const gitCheck = await checkGitStatus(projectRoot);
953
+ checks.push(gitCheck);
954
+ const configPath = external_node_path_["default"].join(projectRoot, 'c15t.config.ts');
955
+ const hasExistingConfig = await preflight_fileExists(configPath);
956
+ checks.push({
957
+ name: 'Existing config',
958
+ status: hasExistingConfig ? 'warn' : 'pass',
959
+ message: hasExistingConfig ? 'c15t.config.ts already exists' : 'No existing configuration',
960
+ hint: hasExistingConfig ? 'Existing config will be overwritten' : void 0
961
+ });
962
+ const hasFailures = checks.some((c)=>'fail' === c.status);
1616
963
  return {
1617
- nextConfigUpdated: configResult.updated,
1618
- nextConfigPath: configResult.filePath,
1619
- nextConfigCreated: configResult.created
964
+ passed: !hasFailures,
965
+ checks,
966
+ projectRoot,
967
+ framework: {
968
+ name: framework.framework,
969
+ version: framework.frameworkVersion,
970
+ pkg: framework.pkg,
971
+ hasReact: framework.hasReact,
972
+ reactVersion: framework.reactVersion,
973
+ tailwindVersion: framework.tailwindVersion
974
+ },
975
+ packageManager
1620
976
  };
1621
977
  }
1622
- async function handleEnvFiles(options) {
1623
- const { projectRoot, backendURL, pkg, spinner, cwd } = options;
1624
- const envPath = node_path.join(projectRoot, '.env.local');
1625
- const envExamplePath = node_path.join(projectRoot, '.env.example');
1626
- spinner.start('Creating/updating environment files...');
1627
- const envContent = generateEnvFileContent(backendURL, pkg);
1628
- const envExampleContent = generateEnvExampleContent(pkg);
1629
- const envVarName = getEnvVarName(pkg);
1630
- try {
1631
- const [envExists, envExampleExists] = await Promise.all([
1632
- promises.access(envPath).then(()=>true).catch(()=>false),
1633
- promises.access(envExamplePath).then(()=>true).catch(()=>false)
1634
- ]);
1635
- if (envExists) {
1636
- const currentEnvContent = await promises.readFile(envPath, 'utf-8');
1637
- if (!currentEnvContent.includes(envVarName)) await promises.appendFile(envPath, envContent);
1638
- } else await promises.writeFile(envPath, envContent);
1639
- if (envExampleExists) {
1640
- const currentExampleContent = await promises.readFile(envExamplePath, 'utf-8');
1641
- if (!currentExampleContent.includes(envVarName)) await promises.appendFile(envExamplePath, envExampleContent);
1642
- } else await promises.writeFile(envExamplePath, envExampleContent);
1643
- spinner.stop(formatLogMessage('info', `Environment files added/updated successfully: ${picocolors.cyan(node_path.relative(cwd, envPath))} and ${picocolors.cyan(node_path.relative(cwd, envExamplePath))}`));
1644
- } catch (error) {
1645
- spinner.stop(formatLogMessage('error', `Error processing environment files: ${error instanceof Error ? error.message : String(error)}`));
1646
- throw error;
978
+ const preflightActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
979
+ const { cliContext } = input;
980
+ if (!cliContext) throw new Error('CLI context is required for preflight checks');
981
+ return runPreflightChecks(cliContext);
982
+ });
983
+ function getStatusIcon(status) {
984
+ switch(status){
985
+ case 'pass':
986
+ return external_picocolors_["default"].green('✓');
987
+ case 'warn':
988
+ return external_picocolors_["default"].yellow('⚠');
989
+ case 'fail':
990
+ return external_picocolors_["default"].red('✗');
991
+ default:
992
+ return ' ';
1647
993
  }
1648
994
  }
1649
- async function generateFiles({ context, mode, spinner, useEnvFile, proxyNextjs, backendURL }) {
1650
- const result = {
1651
- layoutUpdated: false
1652
- };
1653
- const { projectRoot, framework: { pkg } } = context;
1654
- if ('@c15t/nextjs' === pkg || '@c15t/react' === pkg) {
1655
- const layoutResult = await handleReactLayout({
1656
- projectRoot,
1657
- mode,
1658
- backendURL,
1659
- useEnvFile,
1660
- proxyNextjs,
1661
- pkg,
1662
- spinner,
1663
- cwd: context.cwd
1664
- });
1665
- result.layoutUpdated = layoutResult.layoutUpdated;
1666
- result.layoutPath = layoutResult.layoutPath;
1667
- }
1668
- if ('@c15t/nextjs' === pkg && proxyNextjs && 'c15t' === mode) {
1669
- const configResult = await handleNextConfig({
1670
- projectRoot,
1671
- backendURL,
1672
- useEnvFile,
1673
- spinner
995
+ function displayPreflightResults(context, checks) {
996
+ const { logger } = context;
997
+ const lines = [];
998
+ lines.push('');
999
+ lines.push(external_picocolors_["default"].bold('Pre-flight checks:'));
1000
+ for (const check of checks){
1001
+ const icon = getStatusIcon(check.status);
1002
+ lines.push(` ${icon} ${check.message}`);
1003
+ if (check.hint && 'pass' !== check.status) lines.push(` ${external_picocolors_["default"].dim(check.hint)}`);
1004
+ }
1005
+ lines.push('');
1006
+ logger.message(lines.join('\n'));
1007
+ }
1008
+ function displayPreflightFailure(context, checks) {
1009
+ const { logger } = context;
1010
+ const lines = [];
1011
+ lines.push(external_picocolors_["default"].red('Pre-flight checks failed'));
1012
+ lines.push('');
1013
+ const failures = checks.filter((c)=>'fail' === c.status);
1014
+ for (const check of failures){
1015
+ lines.push(` ${external_picocolors_["default"].red('•')} ${check.message}`);
1016
+ if (check.hint) lines.push(` ${check.hint}`);
1017
+ }
1018
+ lines.push('');
1019
+ lines.push('Please fix the issues above and try again.');
1020
+ logger.message(lines.join('\n'));
1021
+ }
1022
+ async function getDevToolsOption({ context, handleCancel, onCancel }) {
1023
+ const isReactProject = '@c15t/react' === context.framework.pkg || '@c15t/nextjs' === context.framework.pkg;
1024
+ context.logger.info("c15t DevTools helps you inspect consent state, scripts, and location overrides during development.");
1025
+ context.logger.info('Learn more: https://c15t.com/docs/dev-tools/overview');
1026
+ const enableDevTools = await prompts_.select({
1027
+ message: 'Install and enable c15t DevTools?',
1028
+ options: [
1029
+ {
1030
+ value: true,
1031
+ label: 'Yes (Recommended)',
1032
+ hint: isReactProject ? 'Adds <C15TDevTools /> to generated consent components' : 'Adds createDevTools() setup to c15t.config.ts'
1033
+ },
1034
+ {
1035
+ value: false,
1036
+ label: 'No',
1037
+ hint: 'Skip DevTools installation and setup'
1038
+ }
1039
+ ],
1040
+ initialValue: true
1041
+ });
1042
+ const cancelled = handleCancel?.(enableDevTools) ?? prompts_.isCancel(enableDevTools);
1043
+ if (cancelled) {
1044
+ if (onCancel) onCancel();
1045
+ context.error.handleCancel('Setup cancelled.', {
1046
+ command: 'onboarding',
1047
+ stage: 'dev_tools_option'
1674
1048
  });
1675
- result.nextConfigUpdated = configResult.nextConfigUpdated;
1676
- result.nextConfigPath = configResult.nextConfigPath;
1677
- result.nextConfigCreated = configResult.nextConfigCreated;
1678
- }
1679
- if ('c15t' === pkg) {
1680
- spinner.start('Generating client configuration file...');
1681
- result.configContent = generateClientConfigContent(mode, backendURL, useEnvFile);
1682
- result.configPath = node_path.join(projectRoot, 'c15t.config.ts');
1683
- spinner.stop(formatLogMessage('info', `Client configuration file generated: ${result.configContent}`));
1684
1049
  }
1685
- if (useEnvFile && backendURL) await handleEnvFiles({
1686
- projectRoot,
1687
- backendURL,
1688
- pkg,
1689
- spinner,
1690
- cwd: context.cwd
1691
- });
1692
- return result;
1050
+ return enableDevTools;
1693
1051
  }
1694
- async function getScriptsToAdd({ context, handleCancel }) {
1695
- context.logger.info("@c15t/scripts has various prebuilt scripts for you to use. Learn more: https://c15t.com/docs/integrations");
1696
- const addScriptsSelection = await prompts_confirm({
1697
- message: "Do you want to add @c15t/scripts to your project?",
1698
- initialValue: true
1699
- });
1700
- if (handleCancel?.(addScriptsSelection)) context.error.handleCancel('Setup cancelled.', {
1701
- command: 'onboarding',
1702
- stage: "scripts_addition"
1703
- });
1704
- return addScriptsSelection;
1705
- }
1706
- async function getSharedFrontendOptions({ backendURL, context, handleCancel }) {
1707
- let useEnvFile = false;
1708
- let proxyNextjs;
1709
- if (!backendURL) return {
1710
- proxyNextjs: void 0,
1711
- useEnvFile: void 0,
1712
- dependenciesToAdd: []
1713
- };
1714
- const useEnvFileSelection = await prompts_confirm({
1715
- message: 'Store the backendURL in a .env file? (Recommended, URL is public)',
1052
+ async function getSSROption({ context, handleCancel, onCancel }) {
1053
+ context.logger.info('SSR consent prefetch starts data loading on the server for faster banner visibility.');
1054
+ context.logger.info('Tradeoff: this uses Next.js headers() and makes the route dynamic (not fully static).');
1055
+ context.logger.info('On slow backends or cross-region setups, SSR can increase TTFB. Measure both TTFB and banner visibility.');
1056
+ context.logger.info('Learn more: https://c15t.com/docs/frameworks/nextjs/ssr');
1057
+ const enableSSR = await prompts_.select({
1058
+ message: 'Enable SSR consent prefetch? (faster first banner visibility, dynamic route)',
1059
+ options: [
1060
+ {
1061
+ value: true,
1062
+ label: 'Yes (Recommended)',
1063
+ hint: 'Fetch consent data on server and stream to client'
1064
+ },
1065
+ {
1066
+ value: false,
1067
+ label: 'No',
1068
+ hint: 'Client-only fetch after hydration (better for fully static pages)'
1069
+ }
1070
+ ],
1716
1071
  initialValue: true
1717
1072
  });
1718
- if (handleCancel?.(useEnvFileSelection)) context.error.handleCancel('Setup cancelled.', {
1719
- command: 'onboarding',
1720
- stage: 'self_hosted_env_file_setup'
1721
- });
1722
- useEnvFile = useEnvFileSelection;
1723
- if ('@c15t/nextjs' === context.framework.pkg) {
1724
- context.logger.info('Learn more about Next.js Rewrites: https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites');
1725
- const proxyNextjsSelection = await prompts_confirm({
1726
- message: 'Proxy requests to your instance with Next.js Rewrites? (Recommended)',
1727
- initialValue: true
1728
- });
1729
- if (handleCancel?.(proxyNextjsSelection)) context.error.handleCancel('Setup cancelled.', {
1073
+ const cancelled = handleCancel?.(enableSSR) ?? prompts_.isCancel(enableSSR);
1074
+ if (cancelled) {
1075
+ if (onCancel) onCancel();
1076
+ context.error.handleCancel('Setup cancelled.', {
1730
1077
  command: 'onboarding',
1731
- stage: 'self_hosted_proxy_nextjs_setup'
1078
+ stage: 'ssr_option'
1732
1079
  });
1733
- proxyNextjs = proxyNextjsSelection;
1734
1080
  }
1735
- const addScriptsSelection = await getScriptsToAdd({
1736
- context,
1737
- handleCancel
1081
+ return enableSSR;
1082
+ }
1083
+ function isCancel(value) {
1084
+ return prompts_.isCancel(value);
1085
+ }
1086
+ class PromptCancelledError extends Error {
1087
+ constructor(stage){
1088
+ super(`Prompt cancelled at stage: ${stage}`);
1089
+ this.name = 'PromptCancelledError';
1090
+ }
1091
+ }
1092
+ const modeSelectionActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
1093
+ const result = await prompts_.select({
1094
+ message: 'How would you like to store consent decisions?',
1095
+ initialValue: input.initialMode ?? 'c15t',
1096
+ options: [
1097
+ {
1098
+ value: 'c15t',
1099
+ label: 'Hosted c15t (consent.io)',
1100
+ hint: 'Recommended: Fully managed service'
1101
+ },
1102
+ {
1103
+ value: 'offline',
1104
+ label: 'Offline Mode',
1105
+ hint: 'Store in browser, no backend needed'
1106
+ },
1107
+ {
1108
+ value: 'self-hosted',
1109
+ label: 'Self-Hosted',
1110
+ hint: 'Run your own c15t backend'
1111
+ },
1112
+ {
1113
+ value: 'custom',
1114
+ label: 'Custom Implementation',
1115
+ hint: 'Full control over storage logic'
1116
+ }
1117
+ ]
1738
1118
  });
1739
- const dependenciesToAdd = [
1740
- context.framework.pkg
1741
- ];
1742
- if (addScriptsSelection) dependenciesToAdd.push("@c15t/scripts");
1119
+ if (isCancel(result)) throw new PromptCancelledError('mode_selection');
1743
1120
  return {
1744
- proxyNextjs,
1745
- useEnvFile,
1746
- dependenciesToAdd
1121
+ mode: result
1747
1122
  };
1748
- }
1749
- async function handleAccountCreation(context, handleCancel) {
1750
- const { logger } = context;
1751
- const needsAccount = await prompts_confirm({
1123
+ });
1124
+ const accountCreationActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
1125
+ const { cliContext } = input;
1126
+ const needsAccount = await prompts_.confirm({
1752
1127
  message: 'Do you need to create a consent.io account?',
1753
1128
  initialValue: true
1754
1129
  });
1755
- if (handleCancel?.(needsAccount)) context.error.handleCancel('Setup cancelled.', {
1756
- command: 'onboarding',
1757
- stage: 'c15t_account_creation'
1758
- });
1759
- if (!needsAccount) return;
1760
- 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');
1761
- const shouldOpen = await prompts_confirm({
1130
+ if (isCancel(needsAccount)) throw new PromptCancelledError('account_creation');
1131
+ if (!needsAccount) return {
1132
+ needsAccount: false,
1133
+ browserOpened: false
1134
+ };
1135
+ prompts_.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');
1136
+ const shouldOpen = await prompts_.confirm({
1762
1137
  message: 'Open browser to sign up for consent.io?',
1763
1138
  initialValue: true
1764
1139
  });
1765
- if (handleCancel?.(shouldOpen)) context.error.handleCancel('Setup cancelled.', {
1766
- command: 'onboarding',
1767
- stage: 'c15t_browser_open'
1768
- });
1140
+ if (isCancel(shouldOpen)) throw new PromptCancelledError('browser_open');
1141
+ let browserOpened = false;
1769
1142
  if (shouldOpen) try {
1770
- await open_0('https://consent.io/dashboard/register?ref=cli');
1771
- const enterPressed = await prompts_text({
1143
+ const open = (await import("open")).default;
1144
+ await open('https://consent.io/dashboard/register?ref=cli');
1145
+ browserOpened = true;
1146
+ const enterPressed = await prompts_.text({
1772
1147
  message: 'Press Enter once you have created your instance and have the backendURL'
1773
1148
  });
1774
- if (handleCancel?.(enterPressed)) context.error.handleCancel('Setup cancelled.', {
1775
- command: 'onboarding',
1776
- stage: 'c15t_url_input'
1777
- });
1778
- } catch {
1779
- logger.warn('Failed to open browser automatically. Please visit https://consent.io/dashboard/register manually.');
1149
+ if (isCancel(enterPressed)) throw new PromptCancelledError('url_input_wait');
1150
+ } catch (error) {
1151
+ if (error instanceof PromptCancelledError) throw error;
1152
+ cliContext.logger.warn('Failed to open browser automatically. Please visit https://consent.io/dashboard/register manually.');
1780
1153
  }
1781
- }
1782
- async function getBackendURL(context, initialBackendURL, handleCancel) {
1783
- const backendURLSelection = await prompts_text({
1784
- message: 'Enter your consent.io instance URL:',
1785
- placeholder: 'https://your-instance.c15t.dev',
1786
- initialValue: initialBackendURL,
1154
+ return {
1155
+ needsAccount: true,
1156
+ browserOpened
1157
+ };
1158
+ });
1159
+ const backendURLActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
1160
+ const { initialURL, isC15tMode } = input;
1161
+ const placeholder = isC15tMode ? 'https://your-instance.c15t.dev' : 'https://your-backend.example.com/api/c15t';
1162
+ const result = await prompts_.text({
1163
+ message: isC15tMode ? 'Enter your consent.io instance URL:' : 'Enter your self-hosted backend URL:',
1164
+ placeholder,
1165
+ initialValue: initialURL,
1787
1166
  validate: (value)=>{
1788
1167
  if (!value || '' === value) return 'URL is required';
1789
1168
  try {
1790
1169
  const url = new URL(value);
1791
- if (!url.hostname.endsWith('.c15t.dev')) return 'Please enter a valid *.c15t.dev URL';
1170
+ if (isC15tMode && !url.hostname.endsWith('.c15t.dev')) return 'Please enter a valid *.c15t.dev URL';
1792
1171
  } catch {
1793
1172
  return 'Please enter a valid URL';
1794
1173
  }
1795
1174
  }
1796
1175
  });
1797
- if (handleCancel?.(backendURLSelection)) context.error.handleCancel('Setup cancelled.', {
1798
- command: 'onboarding',
1799
- stage: 'c15t_url_validation'
1176
+ if (isCancel(result)) throw new PromptCancelledError('backend_url');
1177
+ return {
1178
+ url: result
1179
+ };
1180
+ });
1181
+ const backendOptionsActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
1182
+ const { cliContext } = input;
1183
+ const useEnvFile = await prompts_.confirm({
1184
+ message: 'Store the backendURL in a .env file? (Recommended, URL is public)',
1185
+ initialValue: true
1800
1186
  });
1801
- if (!backendURLSelection || '' === backendURLSelection) context.error.handleCancel('A valid consent.io URL is required', {
1802
- command: 'onboarding',
1803
- stage: 'c15t_url_validation'
1187
+ if (isCancel(useEnvFile)) throw new PromptCancelledError('env_file');
1188
+ let proxyNextjs = false;
1189
+ if ('@c15t/nextjs' === cliContext.framework.pkg) {
1190
+ cliContext.logger.info('Learn more about Next.js Rewrites: https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites');
1191
+ const proxyResult = await prompts_.confirm({
1192
+ message: 'Proxy requests to your instance with Next.js Rewrites? (Recommended)',
1193
+ initialValue: true
1194
+ });
1195
+ if (isCancel(proxyResult)) throw new PromptCancelledError('proxy_nextjs');
1196
+ proxyNextjs = proxyResult;
1197
+ }
1198
+ return {
1199
+ useEnvFile: useEnvFile,
1200
+ proxyNextjs
1201
+ };
1202
+ });
1203
+ const frontendOptionsActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
1204
+ const { cliContext, hasBackend } = input;
1205
+ const pkg = cliContext.framework.pkg;
1206
+ let enableSSR;
1207
+ let enableDevTools = false;
1208
+ let uiStyle = 'prebuilt';
1209
+ let expandedTheme;
1210
+ if ('@c15t/nextjs' === pkg) {
1211
+ if (hasBackend) {
1212
+ const { existsSync } = await import("node:fs");
1213
+ const { join } = await import("node:path");
1214
+ const projectRoot = cliContext.projectRoot;
1215
+ const isAppRouter = [
1216
+ 'app/layout.tsx',
1217
+ 'src/app/layout.tsx',
1218
+ 'app/layout.ts',
1219
+ 'src/app/layout.ts'
1220
+ ].some((p)=>existsSync(join(projectRoot, p)));
1221
+ if (isAppRouter) enableSSR = await getSSROption({
1222
+ context: cliContext,
1223
+ onCancel: ()=>{
1224
+ throw new PromptCancelledError('ssr_option');
1225
+ }
1226
+ });
1227
+ }
1228
+ cliContext.logger.info('Choose how you want your consent UI components generated.');
1229
+ cliContext.logger.info('Learn more: https://c15t.com/docs/frameworks/nextjs/customization');
1230
+ const styleResult = await prompts_.select({
1231
+ message: 'UI component style:',
1232
+ options: [
1233
+ {
1234
+ value: 'prebuilt',
1235
+ label: 'Prebuilt (Recommended)',
1236
+ hint: 'Ready-to-use components'
1237
+ },
1238
+ {
1239
+ value: 'expanded',
1240
+ label: 'Compound components',
1241
+ hint: 'Full customization control'
1242
+ }
1243
+ ],
1244
+ initialValue: 'prebuilt'
1245
+ });
1246
+ if (isCancel(styleResult)) throw new PromptCancelledError('ui_style');
1247
+ uiStyle = styleResult;
1248
+ const themeResult = await prompts_.select({
1249
+ message: 'Theme preset:',
1250
+ options: [
1251
+ {
1252
+ value: 'none',
1253
+ label: 'None',
1254
+ hint: 'No preset styling'
1255
+ },
1256
+ {
1257
+ value: 'minimal',
1258
+ label: 'Minimal',
1259
+ hint: 'Clean light theme'
1260
+ },
1261
+ {
1262
+ value: 'dark',
1263
+ label: 'Dark',
1264
+ hint: 'High contrast dark mode'
1265
+ },
1266
+ {
1267
+ value: 'tailwind',
1268
+ label: 'Tailwind',
1269
+ hint: 'Uses Tailwind utility classes'
1270
+ }
1271
+ ],
1272
+ initialValue: 'none'
1273
+ });
1274
+ if (isCancel(themeResult)) throw new PromptCancelledError('expanded_theme');
1275
+ expandedTheme = themeResult;
1276
+ }
1277
+ if ('@c15t/react' === pkg) {
1278
+ cliContext.logger.info('Choose how you want your consent UI components generated.');
1279
+ const styleResult = await prompts_.select({
1280
+ message: 'UI component style:',
1281
+ options: [
1282
+ {
1283
+ value: 'prebuilt',
1284
+ label: 'Prebuilt (Recommended)',
1285
+ hint: 'Ready-to-use components'
1286
+ },
1287
+ {
1288
+ value: 'expanded',
1289
+ label: 'Compound components',
1290
+ hint: 'Full customization control'
1291
+ }
1292
+ ],
1293
+ initialValue: 'prebuilt'
1294
+ });
1295
+ if (isCancel(styleResult)) throw new PromptCancelledError('ui_style');
1296
+ uiStyle = styleResult;
1297
+ const reactThemeResult = await prompts_.select({
1298
+ message: 'Theme preset:',
1299
+ options: [
1300
+ {
1301
+ value: 'none',
1302
+ label: 'None',
1303
+ hint: 'No preset styling'
1304
+ },
1305
+ {
1306
+ value: 'minimal',
1307
+ label: 'Minimal',
1308
+ hint: 'Clean light theme'
1309
+ },
1310
+ {
1311
+ value: 'dark',
1312
+ label: 'Dark',
1313
+ hint: 'High contrast dark mode'
1314
+ },
1315
+ {
1316
+ value: 'tailwind',
1317
+ label: 'Tailwind',
1318
+ hint: 'Uses Tailwind utility classes'
1319
+ }
1320
+ ],
1321
+ initialValue: 'none'
1322
+ });
1323
+ if (isCancel(reactThemeResult)) throw new PromptCancelledError('expanded_theme');
1324
+ expandedTheme = reactThemeResult;
1325
+ }
1326
+ if ('c15t' === pkg || '@c15t/react' === pkg || '@c15t/nextjs' === pkg) enableDevTools = await getDevToolsOption({
1327
+ context: cliContext,
1328
+ onCancel: ()=>{
1329
+ throw new PromptCancelledError('dev_tools_option');
1330
+ }
1804
1331
  });
1805
- return backendURLSelection;
1806
- }
1807
- async function setupC15tMode({ context, spinner, initialBackendURL, handleCancel }) {
1808
- await handleAccountCreation(context, handleCancel);
1809
- const backendURL = await getBackendURL(context, initialBackendURL, handleCancel);
1810
- const { useEnvFile, proxyNextjs, dependenciesToAdd } = await getSharedFrontendOptions({
1811
- backendURL: backendURL,
1812
- context,
1813
- handleCancel
1332
+ return {
1333
+ enableSSR,
1334
+ enableDevTools,
1335
+ uiStyle,
1336
+ expandedTheme
1337
+ };
1338
+ });
1339
+ const AVAILABLE_SCRIPTS = [
1340
+ {
1341
+ value: 'google-tag-manager',
1342
+ label: 'Google Tag Manager',
1343
+ hint: "GTM container script"
1344
+ },
1345
+ {
1346
+ value: 'google-tag',
1347
+ label: 'Google Tag (gtag.js)',
1348
+ hint: 'Google Analytics 4'
1349
+ },
1350
+ {
1351
+ value: 'meta-pixel',
1352
+ label: 'Meta Pixel',
1353
+ hint: 'Facebook/Instagram tracking'
1354
+ },
1355
+ {
1356
+ value: 'posthog',
1357
+ label: 'PostHog',
1358
+ hint: 'Product analytics'
1359
+ },
1360
+ {
1361
+ value: 'linkedin-insights',
1362
+ label: 'LinkedIn Insight Tag',
1363
+ hint: 'LinkedIn conversion tracking'
1364
+ },
1365
+ {
1366
+ value: 'tiktok-pixel',
1367
+ label: 'TikTok Pixel',
1368
+ hint: 'TikTok ads tracking'
1369
+ },
1370
+ {
1371
+ value: 'x-pixel',
1372
+ label: 'X (Twitter) Pixel',
1373
+ hint: 'X/Twitter conversion tracking'
1374
+ },
1375
+ {
1376
+ value: 'microsoft-uet',
1377
+ label: 'Microsoft UET',
1378
+ hint: 'Bing Ads tracking'
1379
+ },
1380
+ {
1381
+ value: 'databuddy',
1382
+ label: 'Databuddy',
1383
+ hint: 'Data collection'
1384
+ }
1385
+ ];
1386
+ const scriptsOptionActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
1387
+ const { cliContext } = input;
1388
+ cliContext.logger.info("The @c15t/scripts package provides pre-configured third-party scripts with consent management.");
1389
+ const addScripts = await prompts_.confirm({
1390
+ message: "Add @c15t/scripts for third-party script management?",
1391
+ initialValue: true
1814
1392
  });
1815
- await generateFiles({
1816
- context,
1817
- mode: 'c15t',
1818
- backendURL,
1819
- spinner,
1820
- useEnvFile,
1821
- proxyNextjs
1393
+ if (isCancel(addScripts)) throw new PromptCancelledError("scripts_option");
1394
+ if (!addScripts) return {
1395
+ addScripts: false,
1396
+ selectedScripts: []
1397
+ };
1398
+ const selected = await prompts_.multiselect({
1399
+ message: "Which scripts do you want to add?",
1400
+ options: AVAILABLE_SCRIPTS.map((s)=>({
1401
+ value: s.value,
1402
+ label: s.label,
1403
+ hint: s.hint
1404
+ })),
1405
+ required: false
1406
+ });
1407
+ if (isCancel(selected)) throw new PromptCancelledError("scripts_selection");
1408
+ return {
1409
+ addScripts: true,
1410
+ selectedScripts: selected
1411
+ };
1412
+ });
1413
+ const installConfirmActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
1414
+ const { dependencies, packageManager } = input;
1415
+ const depList = dependencies.join(', ');
1416
+ const result = await prompts_.confirm({
1417
+ message: `Install dependencies (${depList}) with ${packageManager}?`,
1418
+ initialValue: true
1822
1419
  });
1823
- const { ranInstall, installDepsConfirmed } = await installDependencies({
1824
- context,
1825
- dependenciesToAdd,
1826
- handleCancel
1420
+ if (isCancel(result)) throw new PromptCancelledError('install_confirm');
1421
+ return {
1422
+ confirmed: result
1423
+ };
1424
+ });
1425
+ const githubStarActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
1426
+ const { cliContext } = input;
1427
+ const result = await prompts_.confirm({
1428
+ message: 'Would you like to star c15t on GitHub now?',
1429
+ initialValue: true
1827
1430
  });
1431
+ if (isCancel(result)) return {
1432
+ opened: false
1433
+ };
1434
+ if (result) try {
1435
+ const open = (await import("open")).default;
1436
+ await open('https://github.com/c15t/c15t');
1437
+ cliContext.logger.success('GitHub repository opened. Thank you for your support!');
1438
+ return {
1439
+ opened: true
1440
+ };
1441
+ } catch {
1442
+ cliContext.logger.info('You can star us later by visiting: https://github.com/c15t/c15t');
1443
+ }
1828
1444
  return {
1829
- backendURL,
1830
- usingEnvFile: useEnvFile ?? false,
1831
- proxyNextjs,
1832
- installDepsConfirmed,
1833
- ranInstall
1445
+ opened: false
1834
1446
  };
1447
+ });
1448
+ function preflightPassed({ context }) {
1449
+ return context.preflightPassed;
1835
1450
  }
1836
- async function setupCustomMode({ context, spinner }) {
1837
- const { logger, cwd, framework: { pkg } } = context;
1838
- if (!pkg) throw new Error('Error detecting framework');
1839
- const result = await generateFiles({
1840
- context,
1841
- mode: 'custom',
1842
- spinner
1843
- });
1844
- logger.info(`Remember to implement custom endpoint handlers ${result.configPath ? `(see ${picocolors.cyan(node_path.relative(cwd, result.configPath))})` : ''}`);
1845
- const { ranInstall, installDepsConfirmed } = await installDependencies({
1846
- context,
1847
- dependenciesToAdd: [
1848
- context.framework.pkg
1451
+ function preflightFailed({ context }) {
1452
+ return !context.preflightPassed;
1453
+ }
1454
+ function hasModeArg({ context }) {
1455
+ return null !== context.modeArg;
1456
+ }
1457
+ function guards_isC15tMode({ context }) {
1458
+ return 'c15t' === context.selectedMode;
1459
+ }
1460
+ function isOfflineMode({ context }) {
1461
+ return 'offline' === context.selectedMode;
1462
+ }
1463
+ function isSelfHostedMode({ context }) {
1464
+ return 'self-hosted' === context.selectedMode;
1465
+ }
1466
+ function isCustomMode({ context }) {
1467
+ return 'custom' === context.selectedMode;
1468
+ }
1469
+ function modeRequiresBackend({ context }) {
1470
+ return 'c15t' === context.selectedMode || 'self-hosted' === context.selectedMode;
1471
+ }
1472
+ function modeNoBackend({ context }) {
1473
+ return 'offline' === context.selectedMode || 'custom' === context.selectedMode;
1474
+ }
1475
+ function isNextjs({ context }) {
1476
+ return context.framework?.pkg === '@c15t/nextjs';
1477
+ }
1478
+ function isReact({ context }) {
1479
+ return context.framework?.pkg === '@c15t/react';
1480
+ }
1481
+ function isCore({ context }) {
1482
+ return context.framework?.pkg === 'c15t';
1483
+ }
1484
+ function guards_hasReact({ context }) {
1485
+ return context.framework?.hasReact ?? false;
1486
+ }
1487
+ function hasTailwind({ context }) {
1488
+ return context.framework?.tailwindVersion !== null;
1489
+ }
1490
+ function hasBackendURL({ context }) {
1491
+ return null !== context.backendURL && '' !== context.backendURL;
1492
+ }
1493
+ function isExpandedUIStyle({ context }) {
1494
+ return 'expanded' === context.uiStyle;
1495
+ }
1496
+ function installConfirmed({ context }) {
1497
+ return context.installConfirmed;
1498
+ }
1499
+ function installSucceeded({ context }) {
1500
+ return context.installSucceeded;
1501
+ }
1502
+ function hasFilesToRollback({ context }) {
1503
+ return context.filesCreated.length > 0 || context.filesModified.length > 0;
1504
+ }
1505
+ function hasDependencies({ context }) {
1506
+ return context.dependenciesToAdd.length > 0;
1507
+ }
1508
+ function hasErrors({ context }) {
1509
+ return context.errors.length > 0;
1510
+ }
1511
+ function needsCleanup({ context }) {
1512
+ return !context.cleanupDone && (context.filesCreated.length > 0 || context.filesModified.length > 0);
1513
+ }
1514
+ function shouldPromptSSR({ context }) {
1515
+ return context.framework?.pkg === '@c15t/nextjs' && ('c15t' === context.selectedMode || 'self-hosted' === context.selectedMode);
1516
+ }
1517
+ function shouldPromptUIStyle({ context }) {
1518
+ return context.framework?.pkg === '@c15t/nextjs' || context.framework?.pkg === '@c15t/react';
1519
+ }
1520
+ const guards = {
1521
+ preflightPassed,
1522
+ preflightFailed,
1523
+ hasModeArg,
1524
+ isC15tMode: guards_isC15tMode,
1525
+ isOfflineMode,
1526
+ isSelfHostedMode,
1527
+ isCustomMode,
1528
+ modeRequiresBackend,
1529
+ modeNoBackend,
1530
+ isNextjs,
1531
+ isReact,
1532
+ isCore,
1533
+ hasReact: guards_hasReact,
1534
+ hasTailwind,
1535
+ hasBackendURL,
1536
+ isExpandedUIStyle,
1537
+ installConfirmed,
1538
+ installSucceeded,
1539
+ hasFilesToRollback,
1540
+ hasDependencies,
1541
+ hasErrors,
1542
+ needsCleanup,
1543
+ shouldPromptSSR,
1544
+ shouldPromptUIStyle
1545
+ };
1546
+ function createInitialContext(cliContext, modeArg) {
1547
+ return {
1548
+ cliContext: cliContext ?? null,
1549
+ projectRoot: cliContext?.projectRoot ?? '',
1550
+ framework: null,
1551
+ packageManager: null,
1552
+ preflightPassed: false,
1553
+ preflightChecks: [],
1554
+ selectedMode: null,
1555
+ modeArg: modeArg ?? null,
1556
+ backendURL: null,
1557
+ useEnvFile: true,
1558
+ proxyNextjs: true,
1559
+ enableSSR: false,
1560
+ enableDevTools: false,
1561
+ uiStyle: 'prebuilt',
1562
+ expandedTheme: null,
1563
+ addScripts: false,
1564
+ selectedScripts: [],
1565
+ filesCreated: [],
1566
+ filesModified: [],
1567
+ dependenciesToAdd: [],
1568
+ installConfirmed: false,
1569
+ installAttempted: false,
1570
+ installSucceeded: false,
1571
+ runMigrations: false,
1572
+ cancelReason: null,
1573
+ cleanupDone: false,
1574
+ errors: [],
1575
+ stateHistory: []
1576
+ };
1577
+ }
1578
+ const generateMachine = (0, __rspack_external_xstate.setup)({
1579
+ types: {
1580
+ context: {},
1581
+ events: {},
1582
+ input: {}
1583
+ },
1584
+ guards: guards,
1585
+ actors: {
1586
+ preflight: preflightActor,
1587
+ modeSelection: modeSelectionActor,
1588
+ accountCreation: accountCreationActor,
1589
+ backendURL: backendURLActor,
1590
+ backendOptions: backendOptionsActor,
1591
+ frontendOptions: frontendOptionsActor,
1592
+ scriptsOption: scriptsOptionActor,
1593
+ fileGeneration: fileGenerationActor,
1594
+ checkDependencies: checkDependenciesActor,
1595
+ installConfirm: installConfirmActor,
1596
+ dependencyInstall: dependencyInstallActor,
1597
+ rollback: rollbackActor,
1598
+ githubStar: githubStarActor
1599
+ }
1600
+ }).createMachine({
1601
+ id: 'generate',
1602
+ initial: 'idle',
1603
+ context: ({ input })=>createInitialContext(input.cliContext, input.modeArg),
1604
+ on: {
1605
+ CANCEL: {
1606
+ target: '.cancelling',
1607
+ actions: (0, __rspack_external_xstate.assign)({
1608
+ cancelReason: ({ event })=>event.reason ?? 'User cancelled'
1609
+ })
1610
+ }
1611
+ },
1612
+ states: {
1613
+ idle: {
1614
+ on: {
1615
+ START: 'preflight'
1616
+ }
1617
+ },
1618
+ preflight: {
1619
+ invoke: {
1620
+ src: 'preflight',
1621
+ input: ({ context })=>({
1622
+ cliContext: context.cliContext
1623
+ }),
1624
+ onDone: [
1625
+ {
1626
+ guard: ({ event })=>event.output.passed,
1627
+ target: 'modeSelection',
1628
+ actions: [
1629
+ (0, __rspack_external_xstate.assign)({
1630
+ preflightPassed: ({ event })=>event.output.passed,
1631
+ preflightChecks: ({ event })=>event.output.checks,
1632
+ projectRoot: ({ event })=>event.output.projectRoot,
1633
+ framework: ({ event })=>event.output.framework,
1634
+ packageManager: ({ event })=>event.output.packageManager
1635
+ }),
1636
+ ({ context, event })=>{
1637
+ if (context.cliContext) displayPreflightResults(context.cliContext, event.output.checks);
1638
+ }
1639
+ ]
1640
+ },
1641
+ {
1642
+ target: 'preflightError',
1643
+ actions: (0, __rspack_external_xstate.assign)({
1644
+ preflightPassed: false,
1645
+ preflightChecks: ({ event })=>event.output.checks
1646
+ })
1647
+ }
1648
+ ],
1649
+ onError: {
1650
+ target: 'error',
1651
+ actions: (0, __rspack_external_xstate.assign)({
1652
+ errors: ({ context, event })=>[
1653
+ ...context.errors,
1654
+ {
1655
+ state: 'preflight',
1656
+ error: event.error,
1657
+ timestamp: Date.now()
1658
+ }
1659
+ ]
1660
+ })
1661
+ }
1662
+ }
1663
+ },
1664
+ preflightError: {
1665
+ entry: ({ context })=>{
1666
+ if (context.cliContext) displayPreflightFailure(context.cliContext, context.preflightChecks);
1667
+ },
1668
+ on: {
1669
+ RETRY: {
1670
+ target: 'preflight',
1671
+ actions: (0, __rspack_external_xstate.assign)({
1672
+ preflightPassed: false,
1673
+ preflightChecks: [],
1674
+ errors: []
1675
+ })
1676
+ }
1677
+ },
1678
+ after: {
1679
+ 100: 'exited'
1680
+ }
1681
+ },
1682
+ modeSelection: {
1683
+ always: [
1684
+ {
1685
+ guard: 'hasModeArg',
1686
+ target: 'routeToMode',
1687
+ actions: (0, __rspack_external_xstate.assign)({
1688
+ selectedMode: ({ context })=>context.modeArg
1689
+ })
1690
+ }
1691
+ ],
1692
+ invoke: {
1693
+ src: 'modeSelection',
1694
+ input: ()=>({}),
1695
+ onDone: {
1696
+ target: 'routeToMode',
1697
+ actions: (0, __rspack_external_xstate.assign)({
1698
+ selectedMode: ({ event })=>event.output.mode
1699
+ })
1700
+ },
1701
+ onError: {
1702
+ target: 'cancelling',
1703
+ actions: (0, __rspack_external_xstate.assign)({
1704
+ cancelReason: 'Mode selection cancelled'
1705
+ })
1706
+ }
1707
+ }
1708
+ },
1709
+ routeToMode: {
1710
+ always: [
1711
+ {
1712
+ guard: 'isC15tMode',
1713
+ target: 'c15tMode'
1714
+ },
1715
+ {
1716
+ guard: 'isOfflineMode',
1717
+ target: 'offlineMode'
1718
+ },
1719
+ {
1720
+ guard: 'isSelfHostedMode',
1721
+ target: 'selfHostedMode'
1722
+ },
1723
+ {
1724
+ guard: 'isCustomMode',
1725
+ target: 'customMode'
1726
+ },
1727
+ {
1728
+ target: 'customMode'
1729
+ }
1730
+ ]
1731
+ },
1732
+ c15tMode: {
1733
+ initial: 'accountCreation',
1734
+ states: {
1735
+ accountCreation: {
1736
+ invoke: {
1737
+ src: 'accountCreation',
1738
+ input: ({ context })=>({
1739
+ cliContext: context.cliContext
1740
+ }),
1741
+ onDone: 'backendURL',
1742
+ onError: {
1743
+ target: '#generate.cancelling',
1744
+ actions: (0, __rspack_external_xstate.assign)({
1745
+ cancelReason: 'Account creation cancelled'
1746
+ })
1747
+ }
1748
+ }
1749
+ },
1750
+ backendURL: {
1751
+ invoke: {
1752
+ src: 'backendURL',
1753
+ input: ()=>({
1754
+ isC15tMode: true
1755
+ }),
1756
+ onDone: {
1757
+ target: '#generate.backendOptions',
1758
+ actions: (0, __rspack_external_xstate.assign)({
1759
+ backendURL: ({ event })=>event.output.url
1760
+ })
1761
+ },
1762
+ onError: {
1763
+ target: '#generate.cancelling',
1764
+ actions: (0, __rspack_external_xstate.assign)({
1765
+ cancelReason: 'Backend URL entry cancelled'
1766
+ })
1767
+ }
1768
+ }
1769
+ }
1770
+ }
1771
+ },
1772
+ offlineMode: {
1773
+ always: 'frontendOptions'
1774
+ },
1775
+ selfHostedMode: {
1776
+ invoke: {
1777
+ src: 'backendURL',
1778
+ input: ()=>({
1779
+ isC15tMode: false
1780
+ }),
1781
+ onDone: {
1782
+ target: 'backendOptions',
1783
+ actions: (0, __rspack_external_xstate.assign)({
1784
+ backendURL: ({ event })=>event.output.url
1785
+ })
1786
+ },
1787
+ onError: {
1788
+ target: 'cancelling',
1789
+ actions: (0, __rspack_external_xstate.assign)({
1790
+ cancelReason: 'Backend URL entry cancelled'
1791
+ })
1792
+ }
1793
+ }
1794
+ },
1795
+ customMode: {
1796
+ always: 'frontendOptions'
1797
+ },
1798
+ backendOptions: {
1799
+ invoke: {
1800
+ src: 'backendOptions',
1801
+ input: ({ context })=>({
1802
+ cliContext: context.cliContext,
1803
+ backendURL: context.backendURL
1804
+ }),
1805
+ onDone: {
1806
+ target: 'frontendOptions',
1807
+ actions: (0, __rspack_external_xstate.assign)({
1808
+ useEnvFile: ({ event })=>event.output.useEnvFile,
1809
+ proxyNextjs: ({ event })=>event.output.proxyNextjs
1810
+ })
1811
+ },
1812
+ onError: {
1813
+ target: 'cancelling',
1814
+ actions: (0, __rspack_external_xstate.assign)({
1815
+ cancelReason: 'Backend options cancelled'
1816
+ })
1817
+ }
1818
+ }
1819
+ },
1820
+ frontendOptions: {
1821
+ invoke: {
1822
+ src: 'frontendOptions',
1823
+ input: ({ context })=>({
1824
+ cliContext: context.cliContext,
1825
+ hasBackend: 'c15t' === context.selectedMode || 'self-hosted' === context.selectedMode
1826
+ }),
1827
+ onDone: {
1828
+ target: "scriptsOptions",
1829
+ actions: (0, __rspack_external_xstate.assign)({
1830
+ enableSSR: ({ event, context })=>event.output.enableSSR ?? context.enableSSR,
1831
+ enableDevTools: ({ event, context })=>event.output.enableDevTools ?? context.enableDevTools,
1832
+ uiStyle: ({ event })=>event.output.uiStyle,
1833
+ expandedTheme: ({ event })=>event.output.expandedTheme ?? null
1834
+ })
1835
+ },
1836
+ onError: {
1837
+ target: 'cancelling',
1838
+ actions: (0, __rspack_external_xstate.assign)({
1839
+ cancelReason: 'Frontend options cancelled'
1840
+ })
1841
+ }
1842
+ }
1843
+ },
1844
+ scriptsOptions: {
1845
+ invoke: {
1846
+ src: "scriptsOption",
1847
+ input: ({ context })=>({
1848
+ cliContext: context.cliContext
1849
+ }),
1850
+ onDone: {
1851
+ target: 'fileGeneration',
1852
+ actions: (0, __rspack_external_xstate.assign)({
1853
+ addScripts: ({ event })=>event.output.addScripts,
1854
+ selectedScripts: ({ event })=>event.output.selectedScripts ?? [],
1855
+ dependenciesToAdd: ({ context, event })=>{
1856
+ const deps = [
1857
+ context.framework?.pkg ?? 'c15t'
1858
+ ];
1859
+ if (event.output.addScripts) deps.push("@c15t/scripts");
1860
+ if (context.enableDevTools) deps.push('@c15t/dev-tools');
1861
+ return deps;
1862
+ }
1863
+ })
1864
+ },
1865
+ onError: {
1866
+ target: 'cancelling',
1867
+ actions: (0, __rspack_external_xstate.assign)({
1868
+ cancelReason: 'Scripts option cancelled'
1869
+ })
1870
+ }
1871
+ }
1872
+ },
1873
+ fileGeneration: {
1874
+ invoke: {
1875
+ src: 'fileGeneration',
1876
+ input: ({ context })=>({
1877
+ cliContext: context.cliContext,
1878
+ mode: context.selectedMode,
1879
+ backendURL: context.backendURL,
1880
+ useEnvFile: context.useEnvFile,
1881
+ proxyNextjs: context.proxyNextjs,
1882
+ enableSSR: context.enableSSR,
1883
+ enableDevTools: context.enableDevTools,
1884
+ uiStyle: context.uiStyle,
1885
+ expandedTheme: context.expandedTheme,
1886
+ selectedScripts: context.selectedScripts
1887
+ }),
1888
+ onDone: {
1889
+ target: 'dependencyCheck',
1890
+ actions: (0, __rspack_external_xstate.assign)({
1891
+ filesCreated: ({ event })=>event.output.filesCreated,
1892
+ filesModified: ({ event })=>event.output.filesModified
1893
+ })
1894
+ },
1895
+ onError: {
1896
+ target: 'error',
1897
+ actions: (0, __rspack_external_xstate.assign)({
1898
+ errors: ({ context, event })=>[
1899
+ ...context.errors,
1900
+ {
1901
+ state: 'fileGeneration',
1902
+ error: event.error,
1903
+ timestamp: Date.now()
1904
+ }
1905
+ ]
1906
+ })
1907
+ }
1908
+ }
1909
+ },
1910
+ dependencyCheck: {
1911
+ invoke: {
1912
+ src: 'checkDependencies',
1913
+ input: ({ context })=>({
1914
+ projectRoot: context.cliContext.projectRoot,
1915
+ dependencies: context.dependenciesToAdd
1916
+ }),
1917
+ onDone: {
1918
+ target: 'dependencyConfirm',
1919
+ actions: (0, __rspack_external_xstate.assign)({
1920
+ dependenciesToAdd: ({ event })=>event.output.missing
1921
+ })
1922
+ },
1923
+ onError: {
1924
+ target: 'dependencyConfirm'
1925
+ }
1926
+ }
1927
+ },
1928
+ dependencyConfirm: {
1929
+ always: [
1930
+ {
1931
+ guard: ({ context })=>0 === context.dependenciesToAdd.length,
1932
+ target: 'summary'
1933
+ }
1934
+ ],
1935
+ invoke: {
1936
+ src: 'installConfirm',
1937
+ input: ({ context })=>({
1938
+ dependencies: context.dependenciesToAdd,
1939
+ packageManager: context.packageManager?.name ?? 'npm'
1940
+ }),
1941
+ onDone: [
1942
+ {
1943
+ guard: ({ event })=>event.output.confirmed,
1944
+ target: 'dependencyInstall',
1945
+ actions: (0, __rspack_external_xstate.assign)({
1946
+ installConfirmed: true
1947
+ })
1948
+ },
1949
+ {
1950
+ target: 'summary',
1951
+ actions: (0, __rspack_external_xstate.assign)({
1952
+ installConfirmed: false
1953
+ })
1954
+ }
1955
+ ],
1956
+ onError: {
1957
+ target: 'summary',
1958
+ actions: (0, __rspack_external_xstate.assign)({
1959
+ installConfirmed: false
1960
+ })
1961
+ }
1962
+ }
1963
+ },
1964
+ dependencyInstall: {
1965
+ invoke: {
1966
+ src: 'dependencyInstall',
1967
+ input: ({ context })=>({
1968
+ cliContext: context.cliContext,
1969
+ dependencies: context.dependenciesToAdd
1970
+ }),
1971
+ onDone: {
1972
+ target: 'summary',
1973
+ actions: (0, __rspack_external_xstate.assign)({
1974
+ installAttempted: true,
1975
+ installSucceeded: ({ event })=>event.output.success
1976
+ })
1977
+ },
1978
+ onError: {
1979
+ target: 'summary',
1980
+ actions: (0, __rspack_external_xstate.assign)({
1981
+ installAttempted: true,
1982
+ installSucceeded: false
1983
+ })
1984
+ }
1985
+ }
1986
+ },
1987
+ summary: {
1988
+ entry: ({ context })=>{
1989
+ if (!context.cliContext) return;
1990
+ const { logger, packageManager } = context.cliContext;
1991
+ if ('self-hosted' === context.selectedMode) {
1992
+ logger.info('Setup your backend with the c15t docs:');
1993
+ logger.info('https://c15t.com/docs/self-host/v2');
1994
+ } else if ('custom' === context.selectedMode) logger.info('Configuration Complete! Implement your custom endpoint handlers.');
1995
+ if (context.installConfirmed && !context.installSucceeded) logger.warn('Dependency installation failed. Please check errors and install manually.');
1996
+ else if (!context.installConfirmed && context.dependenciesToAdd.length > 0) {
1997
+ const pmCommand = getManualInstallCommand(context.dependenciesToAdd, packageManager.name);
1998
+ logger.warn(`Run ${pmCommand} to install required dependencies.`);
1999
+ }
2000
+ },
2001
+ after: {
2002
+ 100: 'githubStar'
2003
+ }
2004
+ },
2005
+ githubStar: {
2006
+ invoke: {
2007
+ src: 'githubStar',
2008
+ input: ({ context })=>({
2009
+ cliContext: context.cliContext
2010
+ }),
2011
+ onDone: 'complete',
2012
+ onError: 'complete'
2013
+ }
2014
+ },
2015
+ complete: {
2016
+ entry: ({ context })=>{
2017
+ context.cliContext?.logger.success('Setup completed successfully!');
2018
+ },
2019
+ type: 'final'
2020
+ },
2021
+ error: {
2022
+ entry: ({ context })=>{
2023
+ const lastError = context.errors[context.errors.length - 1];
2024
+ context.cliContext?.logger.error(`Error: ${lastError?.error?.message ?? 'Unknown error'}`);
2025
+ },
2026
+ always: [
2027
+ {
2028
+ guard: 'hasFilesToRollback',
2029
+ target: 'rollback'
2030
+ },
2031
+ {
2032
+ target: 'exited'
2033
+ }
2034
+ ]
2035
+ },
2036
+ cancelling: {
2037
+ entry: ({ context })=>{
2038
+ context.cliContext?.logger.info(context.cancelReason ?? 'Configuration cancelled.');
2039
+ },
2040
+ always: [
2041
+ {
2042
+ guard: 'hasFilesToRollback',
2043
+ target: 'rollback'
2044
+ },
2045
+ {
2046
+ target: 'exited'
2047
+ }
2048
+ ]
2049
+ },
2050
+ rollback: {
2051
+ invoke: {
2052
+ src: 'rollback',
2053
+ input: ({ context })=>({
2054
+ filesCreated: context.filesCreated,
2055
+ filesModified: context.filesModified
2056
+ }),
2057
+ onDone: {
2058
+ target: 'exited',
2059
+ actions: (0, __rspack_external_xstate.assign)({
2060
+ filesCreated: [],
2061
+ filesModified: [],
2062
+ cleanupDone: true
2063
+ })
2064
+ },
2065
+ onError: {
2066
+ target: 'exited',
2067
+ actions: (0, __rspack_external_xstate.assign)({
2068
+ cleanupDone: true
2069
+ })
2070
+ }
2071
+ }
2072
+ },
2073
+ exited: {
2074
+ type: 'final'
2075
+ }
2076
+ }
2077
+ });
2078
+ async function runGenerateMachine(options) {
2079
+ const { context: cliContext, modeArg, resume = false, debug = false, persist = true } = options;
2080
+ const { logger, telemetry } = cliContext;
2081
+ const startTime = Date.now();
2082
+ const persistPath = getPersistPath(cliContext.projectRoot);
2083
+ const machineId = 'generate';
2084
+ let snapshot;
2085
+ if (resume) {
2086
+ const hasPersisted = await hasPersistedState(persistPath);
2087
+ if (hasPersisted) {
2088
+ snapshot = await loadSnapshot(persistPath, machineId);
2089
+ if (snapshot) logger.info('Resuming from previous state...');
2090
+ }
2091
+ }
2092
+ const actor = (0, __rspack_external_xstate.createActor)(generateMachine, {
2093
+ input: {
2094
+ cliContext,
2095
+ modeArg
2096
+ },
2097
+ ...snapshot ? {
2098
+ snapshot: snapshot
2099
+ } : {}
2100
+ });
2101
+ const subscribers = [];
2102
+ subscribers.push(createTelemetrySubscriber({
2103
+ telemetry,
2104
+ machineId,
2105
+ skipStates: [
2106
+ 'routeToMode'
1849
2107
  ]
2108
+ }));
2109
+ if (debug) subscribers.push(createDebugSubscriber(machineId, logger));
2110
+ if (persist) subscribers.push(createPersistenceSubscriber(machineId, persistPath));
2111
+ const combinedSubscriber = combineSubscribers(...subscribers);
2112
+ actor.subscribe((snapshot)=>combinedSubscriber(snapshot));
2113
+ telemetry.trackEvent(TelemetryEventName.ONBOARDING_STARTED, {
2114
+ resumed: resume && void 0 !== snapshot
2115
+ });
2116
+ telemetry.flushSync();
2117
+ actor.start();
2118
+ if (!snapshot) actor.send({
2119
+ type: 'START'
2120
+ });
2121
+ return new Promise((resolve)=>{
2122
+ actor.subscribe({
2123
+ complete: ()=>{
2124
+ const finalSnapshot = actor.getSnapshot();
2125
+ const finalContext = finalSnapshot.context;
2126
+ const finalState = String(finalSnapshot.value);
2127
+ const duration = Date.now() - startTime;
2128
+ clearSnapshot(persistPath).catch(()=>{});
2129
+ const success = 'complete' === finalState || 'done' === finalSnapshot.status;
2130
+ telemetry.trackEvent(TelemetryEventName.ONBOARDING_COMPLETED, {
2131
+ success,
2132
+ selectedMode: finalContext.selectedMode ?? void 0,
2133
+ installDependencies: finalContext.installSucceeded,
2134
+ duration,
2135
+ finalState
2136
+ });
2137
+ resolve({
2138
+ success,
2139
+ context: finalContext,
2140
+ finalState,
2141
+ duration,
2142
+ errors: finalContext.errors
2143
+ });
2144
+ }
2145
+ });
2146
+ });
2147
+ }
2148
+ async function generateAction(context) {
2149
+ const { logger, commandArgs, flags } = context;
2150
+ const modeArg = commandArgs[0];
2151
+ const resume = true === flags.resume;
2152
+ const debug = true === flags.debug || 'debug' === flags.logger;
2153
+ logger.debug('Starting generate command with state machine...');
2154
+ logger.debug(`Mode arg: ${modeArg}`);
2155
+ logger.debug(`Resume: ${resume}`);
2156
+ try {
2157
+ const result = await runGenerateMachine({
2158
+ context,
2159
+ modeArg,
2160
+ resume,
2161
+ debug,
2162
+ persist: true
2163
+ });
2164
+ if (!result.success) {
2165
+ if (result.errors.length > 0) process.exitCode = 1;
2166
+ }
2167
+ } catch (error) {
2168
+ logger.error(`Generate command failed: ${error instanceof Error ? error.message : String(error)}`);
2169
+ process.exitCode = 1;
2170
+ }
2171
+ }
2172
+ async function generate(context, mode) {
2173
+ if (mode) context.commandArgs = [
2174
+ mode
2175
+ ];
2176
+ return generateAction(context);
2177
+ }
2178
+ var utils_logger = __webpack_require__("./src/utils/logger.ts");
2179
+ async function addAndInstallDependenciesViaPM(projectRoot, dependencies, packageManager) {
2180
+ if (0 === dependencies.length) return;
2181
+ let command = '';
2182
+ let args = [];
2183
+ switch(packageManager){
2184
+ case 'npm':
2185
+ command = 'npm';
2186
+ args = [
2187
+ 'install',
2188
+ ...dependencies
2189
+ ];
2190
+ break;
2191
+ case 'yarn':
2192
+ command = 'yarn';
2193
+ args = [
2194
+ 'add',
2195
+ ...dependencies
2196
+ ];
2197
+ break;
2198
+ case 'pnpm':
2199
+ command = 'pnpm';
2200
+ args = [
2201
+ 'add',
2202
+ ...dependencies
2203
+ ];
2204
+ break;
2205
+ case 'bun':
2206
+ command = 'bun';
2207
+ args = [
2208
+ 'add',
2209
+ ...dependencies
2210
+ ];
2211
+ break;
2212
+ default:
2213
+ throw new Error(`Unsupported package manager for dependency addition: ${packageManager}`);
2214
+ }
2215
+ const child = (0, __rspack_external_node_child_process_27f17141.spawn)(command, args, {
2216
+ cwd: projectRoot,
2217
+ stdio: 'inherit'
1850
2218
  });
1851
- return {
1852
- clientConfigContent: result.configContent ?? '',
1853
- installDepsConfirmed,
1854
- ranInstall
1855
- };
2219
+ await (0, __rspack_external_node_events_0a6aefe7.once)(child, 'exit');
1856
2220
  }
1857
- async function setupOfflineMode({ context, spinner, handleCancel }) {
1858
- const addScriptsSelection = await getScriptsToAdd({
1859
- context,
1860
- handleCancel
1861
- });
1862
- const result = await generateFiles({
1863
- context,
1864
- mode: 'offline',
1865
- spinner
1866
- });
1867
- const dependenciesToAdd = [
1868
- context.framework.pkg
1869
- ];
1870
- if (addScriptsSelection) dependenciesToAdd.push("@c15t/scripts");
1871
- const { ranInstall, installDepsConfirmed } = await installDependencies({
1872
- context,
1873
- dependenciesToAdd
1874
- });
1875
- return {
1876
- clientConfigContent: result.configContent ?? '',
1877
- installDepsConfirmed,
1878
- ranInstall
2221
+ function dependencies_getManualInstallCommand(dependencies, packageManager) {
2222
+ switch(packageManager){
2223
+ case 'npm':
2224
+ return `npm install ${dependencies.join(' ')}`;
2225
+ case 'yarn':
2226
+ return `yarn add ${dependencies.join(' ')}`;
2227
+ case 'pnpm':
2228
+ return `pnpm add ${dependencies.join(' ')}`;
2229
+ case 'bun':
2230
+ return `bun add ${dependencies.join(' ')}`;
2231
+ default:
2232
+ return `npm install ${dependencies.join(' ')}`;
2233
+ }
2234
+ }
2235
+ async function installDependencies({ context, dependenciesToAdd, handleCancel, autoInstall = false }) {
2236
+ const { telemetry, logger } = context;
2237
+ const s = prompts_.spinner();
2238
+ if (0 === dependenciesToAdd.length) return {
2239
+ installDepsConfirmed: false,
2240
+ ranInstall: false
1879
2241
  };
2242
+ const depsString = dependenciesToAdd.map((d)=>external_picocolors_["default"].cyan(d)).join(', ');
2243
+ if (!autoInstall) {
2244
+ const addDepsSelection = await prompts_.confirm({
2245
+ message: `Add required dependencies using ${external_picocolors_["default"].cyan(context.packageManager.name)}? (${depsString})`,
2246
+ initialValue: true
2247
+ });
2248
+ if (handleCancel?.(addDepsSelection)) return {
2249
+ installDepsConfirmed: false,
2250
+ ranInstall: false
2251
+ };
2252
+ if (!addDepsSelection) return {
2253
+ installDepsConfirmed: false,
2254
+ ranInstall: false
2255
+ };
2256
+ }
2257
+ s.start(`Running ${external_picocolors_["default"].cyan(context.packageManager.name)} to add and install dependencies... (this might take a moment)`);
2258
+ try {
2259
+ await addAndInstallDependenciesViaPM(context.projectRoot, dependenciesToAdd, context.packageManager.name);
2260
+ s.stop(`✅ Dependencies installed: ${dependenciesToAdd.map((d)=>external_picocolors_["default"].cyan(d)).join(', ')}`);
2261
+ telemetry.trackEvent(TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
2262
+ success: true,
2263
+ dependencies: dependenciesToAdd.join(','),
2264
+ packageManager: context.packageManager.name
2265
+ });
2266
+ return {
2267
+ installDepsConfirmed: true,
2268
+ ranInstall: true
2269
+ };
2270
+ } catch (installError) {
2271
+ s.stop(external_picocolors_["default"].yellow('⚠️ Dependency installation failed.'));
2272
+ logger.error('Installation Error:', installError);
2273
+ telemetry.trackEvent(TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
2274
+ success: false,
2275
+ error: installError instanceof Error ? installError.message : String(installError),
2276
+ dependencies: dependenciesToAdd.join(','),
2277
+ packageManager: context.packageManager.name
2278
+ });
2279
+ const pmCommand = dependencies_getManualInstallCommand(dependenciesToAdd, context.packageManager.name);
2280
+ logger.info(`Please try running '${pmCommand}' manually in ${external_picocolors_["default"].cyan(external_node_path_["default"].relative(context.cwd, context.projectRoot))}.`);
2281
+ return {
2282
+ installDepsConfirmed: true,
2283
+ ranInstall: false
2284
+ };
2285
+ }
1880
2286
  }
2287
+ var promises_ = __webpack_require__("node:fs/promises");
1881
2288
  const ADAPTER_LABELS = {
1882
2289
  kyselyAdapter: 'kysely',
1883
2290
  drizzleAdapter: 'drizzle',
@@ -1981,7 +2388,7 @@ const CONFIG_BUILDERS = {
1981
2388
  };
1982
2389
  async function pathExists(filePath) {
1983
2390
  try {
1984
- await promises.access(filePath);
2391
+ await promises_["default"].access(filePath);
1985
2392
  return true;
1986
2393
  } catch {
1987
2394
  return false;
@@ -2072,7 +2479,7 @@ function buildMongoPrelude(connection) {
2072
2479
  }
2073
2480
  function buildFileContent(adapter, provider, dbConfig, connection) {
2074
2481
  const adapterPath = 'mongoAdapter' === adapter ? 'mongo' : adapter.replace('Adapter', '');
2075
- const importAdapter = `import { ${adapter} } from '@c15t/backend/v2/db/adapters/${adapterPath}';`;
2482
+ const importAdapter = `import { ${adapter} } from '@c15t/backend/db/adapters/${adapterPath}';`;
2076
2483
  let extras = {
2077
2484
  imports: '',
2078
2485
  prelude: ''
@@ -2085,7 +2492,7 @@ function buildFileContent(adapter, provider, dbConfig, connection) {
2085
2492
  else if ('prismaAdapter' === adapter) extras = buildPrismaPrelude(provider, connection);
2086
2493
  else if ('typeormAdapter' === adapter) extras = buildTypeormPrelude(provider, connection);
2087
2494
  else if ('mongoAdapter' === adapter) extras = buildMongoPrelude(connection);
2088
- return `import { defineConfig } from '@c15t/backend/v2';
2495
+ return `import { defineConfig } from '@c15t/backend';
2089
2496
  ${importAdapter}
2090
2497
  ${extras.imports ? `${extras.imports}\n` : ''}
2091
2498
  ${extras.prelude ? `${extras.prelude}\n` : ''}
@@ -2095,14 +2502,14 @@ export default defineConfig({
2095
2502
  `;
2096
2503
  }
2097
2504
  async function promptSelectAdapter() {
2098
- const selection = await prompts_select({
2505
+ const selection = await prompts_.select({
2099
2506
  message: 'Select database adapter:',
2100
2507
  options: Object.keys(ADAPTER_LABELS).map((key)=>({
2101
2508
  value: key,
2102
2509
  label: ADAPTER_LABELS[key]
2103
2510
  }))
2104
2511
  });
2105
- if (isCancel(selection)) throw new Cancelled('adapter_select');
2512
+ if (prompts_.isCancel(selection)) throw new Cancelled('adapter_select');
2106
2513
  return selection;
2107
2514
  }
2108
2515
  async function promptSelectProvider(adapter) {
@@ -2112,14 +2519,14 @@ async function promptSelectProvider(adapter) {
2112
2519
  const [first] = providers;
2113
2520
  return first.value;
2114
2521
  }
2115
- const selection = await prompts_select({
2522
+ const selection = await prompts_.select({
2116
2523
  message: 'Select database provider:',
2117
2524
  options: providers.map((opt)=>({
2118
2525
  value: opt.value,
2119
2526
  label: opt.label
2120
2527
  }))
2121
2528
  });
2122
- if (isCancel(selection)) throw new Cancelled('provider_select');
2529
+ if (prompts_.isCancel(selection)) throw new Cancelled('provider_select');
2123
2530
  return selection;
2124
2531
  }
2125
2532
  async function promptConnection(adapter, provider) {
@@ -2127,42 +2534,42 @@ async function promptConnection(adapter, provider) {
2127
2534
  useEnv: true
2128
2535
  };
2129
2536
  if ('sqlite' === provider) {
2130
- const sqliteFile = await prompts_text({
2537
+ const sqliteFile = await prompts_.text({
2131
2538
  message: 'SQLite file path:',
2132
2539
  initialValue: './db.sqlite'
2133
2540
  });
2134
- if (isCancel(sqliteFile)) throw new Cancelled('sqlite_path');
2541
+ if (prompts_.isCancel(sqliteFile)) throw new Cancelled('sqlite_path');
2135
2542
  connection.sqliteFile = String(sqliteFile);
2136
2543
  return connection;
2137
2544
  }
2138
- const useEnv = await prompts_confirm({
2545
+ const useEnv = await prompts_.confirm({
2139
2546
  message: 'Store connection string in an environment variable?',
2140
2547
  initialValue: true
2141
2548
  });
2142
- if (isCancel(useEnv)) throw new Cancelled('use_env_confirm');
2549
+ if (prompts_.isCancel(useEnv)) throw new Cancelled('use_env_confirm');
2143
2550
  connection.useEnv = Boolean(useEnv);
2144
2551
  if (connection.useEnv) {
2145
2552
  const defaultVar = 'mongoAdapter' === adapter ? 'MONGODB_URI' : 'DATABASE_URL';
2146
- const envVarName = await prompts_text({
2553
+ const envVarName = await prompts_.text({
2147
2554
  message: 'Env var name for connection string:',
2148
2555
  initialValue: defaultVar
2149
2556
  });
2150
- if (isCancel(envVarName)) throw new Cancelled('env_var_name');
2557
+ if (prompts_.isCancel(envVarName)) throw new Cancelled('env_var_name');
2151
2558
  connection.envVar = String(envVarName);
2152
2559
  return connection;
2153
2560
  }
2154
2561
  const placeholder = 'mongoAdapter' === adapter ? 'mongodb+srv://user:pass@host/db' : 'postgresql://user:pass@host:5432/db';
2155
- const connectionString = await prompts_text({
2562
+ const connectionString = await prompts_.text({
2156
2563
  message: 'Connection string:',
2157
2564
  placeholder
2158
2565
  });
2159
- if (isCancel(connectionString)) throw new Cancelled('connection_string');
2566
+ if (prompts_.isCancel(connectionString)) throw new Cancelled('connection_string');
2160
2567
  connection.value = String(connectionString);
2161
2568
  return connection;
2162
2569
  }
2163
2570
  async function ensureBackendConfig(context) {
2164
2571
  const { cwd, logger } = context;
2165
- const targetPath = node_path.join(cwd, 'c15t-backend.config.ts');
2572
+ const targetPath = external_node_path_["default"].join(cwd, 'c15t-backend.config.ts');
2166
2573
  if (await pathExists(targetPath)) {
2167
2574
  logger.debug(`Backend config already exists at ${targetPath}`);
2168
2575
  return {
@@ -2191,8 +2598,8 @@ async function ensureBackendConfig(context) {
2191
2598
  else if ('mongoAdapter' === adapter) dependencies.push('mongodb');
2192
2599
  const dbConfig = buildDatabaseConfig(adapter, provider, connection);
2193
2600
  const fileContent = buildFileContent(adapter, String(provider), dbConfig, connection);
2194
- await promises.writeFile(targetPath, fileContent, 'utf8');
2195
- context.logger.success(`Created ${node_path.relative(cwd, targetPath)}`);
2601
+ await promises_["default"].writeFile(targetPath, fileContent, 'utf8');
2602
+ context.logger.success(`Created ${external_node_path_["default"].relative(cwd, targetPath)}`);
2196
2603
  if ('sqlite' !== provider && connection.useEnv && connection.envVar) context.logger.note(`Remember to set ${connection.envVar} in your environment or .env file.`, 'Environment');
2197
2604
  return {
2198
2605
  path: targetPath,
@@ -2211,26 +2618,26 @@ async function handleMigrationResult(context, result) {
2211
2618
  telemetry.trackEvent(TelemetryEventName.MIGRATION_PLANNED, {
2212
2619
  success: true
2213
2620
  });
2214
- const saveSQL = await prompts_confirm({
2621
+ const saveSQL = await prompts_.confirm({
2215
2622
  message: 'Save SQL to file?',
2216
2623
  initialValue: true
2217
2624
  });
2218
- if (isCancel(saveSQL)) return void telemetry.trackEvent(TelemetryEventName.MIGRATION_FAILED, {
2625
+ if (prompts_.isCancel(saveSQL)) return void telemetry.trackEvent(TelemetryEventName.MIGRATION_FAILED, {
2219
2626
  saveSql: false
2220
2627
  });
2221
2628
  if (saveSQL) {
2222
2629
  const sql = result.getSQL?.() ?? '';
2223
2630
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
2224
2631
  const filename = `migration-${timestamp}.sql`;
2225
- const filepath = join(process.cwd(), filename);
2226
- await writeFile(filepath, sql, 'utf-8');
2632
+ const filepath = (0, external_node_path_.join)(process.cwd(), filename);
2633
+ await (0, promises_.writeFile)(filepath, sql, 'utf-8');
2227
2634
  logger.success(`SQL saved to: ${filename}`);
2228
2635
  }
2229
- const execute = await prompts_confirm({
2636
+ const execute = await prompts_.confirm({
2230
2637
  message: 'Execute this migration?',
2231
2638
  initialValue: false
2232
2639
  });
2233
- if (isCancel(execute)) return void telemetry.trackEvent(TelemetryEventName.MIGRATION_FAILED, {
2640
+ if (prompts_.isCancel(execute)) return void telemetry.trackEvent(TelemetryEventName.MIGRATION_FAILED, {
2234
2641
  execute: false
2235
2642
  });
2236
2643
  await result.execute();
@@ -2241,11 +2648,11 @@ async function handleMigrationResult(context, result) {
2241
2648
  }
2242
2649
  async function handleORMResult(context, result) {
2243
2650
  const { logger, telemetry, cwd } = context;
2244
- const filePath = node_path.join(cwd, result.path);
2245
- await promises.mkdir(node_path.dirname(filePath), {
2651
+ const filePath = external_node_path_["default"].join(cwd, result.path);
2652
+ await promises_["default"].mkdir(external_node_path_["default"].dirname(filePath), {
2246
2653
  recursive: true
2247
2654
  });
2248
- await promises.writeFile(filePath, result.code);
2655
+ await promises_["default"].writeFile(filePath, result.code);
2249
2656
  logger.info(`Migration file created at ${filePath}`);
2250
2657
  telemetry.trackEvent(TelemetryEventName.MIGRATION_COMPLETED, {
2251
2658
  success: true,
@@ -2255,14 +2662,14 @@ async function handleORMResult(context, result) {
2255
2662
  async function readConfigAndGetDb(context, absoluteConfigPath) {
2256
2663
  const { logger } = context;
2257
2664
  logger.info(`Loading backend config from ${absoluteConfigPath}`);
2258
- const resolvedPath = node_path.resolve(absoluteConfigPath);
2665
+ const resolvedPath = external_node_path_["default"].resolve(absoluteConfigPath);
2259
2666
  try {
2260
- await promises.access(resolvedPath);
2667
+ await promises_["default"].access(resolvedPath);
2261
2668
  } catch {
2262
2669
  throw new Error(`Backend config not found at: ${resolvedPath}`);
2263
2670
  }
2264
2671
  try {
2265
- const { config } = await loadConfig({
2672
+ const { config } = await (0, __rspack_external_c12.loadConfig)({
2266
2673
  configFile: absoluteConfigPath,
2267
2674
  jitiOptions: {
2268
2675
  extensions: [
@@ -2279,8 +2686,9 @@ async function readConfigAndGetDb(context, absoluteConfigPath) {
2279
2686
  }
2280
2687
  });
2281
2688
  logger.debug('Imported Config');
2689
+ if (!config || 'object' != typeof config || !('adapter' in config)) throw new Error('Invalid backend config: missing required "adapter" property');
2282
2690
  return {
2283
- db: DB.client(config.adapter)
2691
+ db: __rspack_external__c15t_backend_db_schema_e7c5e6a0.DB.client(config.adapter)
2284
2692
  };
2285
2693
  } catch (error) {
2286
2694
  logger.error('Failed to load backend config', error);
@@ -2301,285 +2709,13 @@ async function migrate(context) {
2301
2709
  });
2302
2710
  const { db } = await readConfigAndGetDb(context, path);
2303
2711
  logger.info('Loaded c15t-backend.config.ts');
2304
- const result = await migrator({
2712
+ const result = await (0, __rspack_external__c15t_backend_db_migrator_ebe6d5c7.migrator)({
2305
2713
  db,
2306
2714
  schema: 'latest'
2307
2715
  });
2308
2716
  if ('path' in result) await handleORMResult(context, result);
2309
2717
  else await handleMigrationResult(context, result);
2310
2718
  }
2311
- async function setupSelfHostedMode({ context, spinner, handleCancel }) {
2312
- const dependenciesToAdd = new Set([
2313
- context.framework.pkg,
2314
- '@c15t/backend'
2315
- ]);
2316
- const targetPath = node_path.join(context.cwd, 'c15t-backend.config.ts');
2317
- let createBackendConfig = false;
2318
- if (!await pathExists(targetPath)) {
2319
- const config = await ensureBackendConfig(context);
2320
- createBackendConfig = true;
2321
- for (const dep of config?.dependencies ?? [])dependenciesToAdd.add(dep);
2322
- }
2323
- const backendURL = await prompts_text({
2324
- message: 'Enter the backend URL:',
2325
- initialValue: 'http://localhost:3000'
2326
- });
2327
- if (handleCancel?.(backendURL)) context.error.handleCancel('Setup cancelled.', {
2328
- command: 'onboarding',
2329
- stage: 'self_hosted_backend_url_setup'
2330
- });
2331
- const { useEnvFile, proxyNextjs, dependenciesToAdd: sharedDependenciesToAdd } = await getSharedFrontendOptions({
2332
- backendURL: backendURL,
2333
- context,
2334
- handleCancel
2335
- });
2336
- for (const dep of sharedDependenciesToAdd)dependenciesToAdd.add(dep);
2337
- await generateFiles({
2338
- context,
2339
- mode: 'c15t',
2340
- backendURL: backendURL,
2341
- spinner,
2342
- useEnvFile,
2343
- proxyNextjs
2344
- });
2345
- const { ranInstall, installDepsConfirmed } = await installDependencies({
2346
- context,
2347
- dependenciesToAdd: Array.from(dependenciesToAdd),
2348
- handleCancel
2349
- });
2350
- const runMigrations = await prompts_confirm({
2351
- message: 'Would you like to run migrations?',
2352
- initialValue: true
2353
- });
2354
- if (handleCancel?.(runMigrations)) context.error.handleCancel('Setup cancelled.', {
2355
- command: 'onboarding',
2356
- stage: 'self_hosted_run_migrations_setup'
2357
- });
2358
- if (runMigrations) await migrate(context);
2359
- return {
2360
- backendURL: backendURL,
2361
- usingEnvFile: useEnvFile ?? false,
2362
- proxyNextjs,
2363
- createBackendConfig: createBackendConfig,
2364
- installDepsConfirmed,
2365
- ranInstall,
2366
- runMigrations: runMigrations
2367
- };
2368
- }
2369
- const WINDOWS_PATH_SEPARATOR_REGEX = /\\/g;
2370
- const FILE_EXTENSION_REGEX = /\.(ts|js|tsx|jsx)$/;
2371
- async function generate(context, mode) {
2372
- const { logger, telemetry } = context;
2373
- logger.debug('Starting generate command...');
2374
- logger.debug(`Mode: ${mode}`);
2375
- const handleCancel = (value)=>{
2376
- if (isCancel(value)) {
2377
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_EXITED, {
2378
- reason: 'user_cancelled',
2379
- command: 'onboarding',
2380
- stage: 'setup'
2381
- });
2382
- context.error.handleCancel('Configuration cancelled.', {
2383
- command: 'onboarding',
2384
- stage: 'setup'
2385
- });
2386
- }
2387
- return false;
2388
- };
2389
- try {
2390
- logger.info('Starting onboarding process...');
2391
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_STARTED, {});
2392
- telemetry.flushSync();
2393
- await performOnboarding(context, handleCancel, mode);
2394
- logger.success('🚀 Setup completed successfully!');
2395
- } catch (error) {
2396
- if (!isCancel(error)) telemetry.trackEvent(TelemetryEventName.ONBOARDING_COMPLETED, {
2397
- success: false,
2398
- error: error instanceof Error ? error.message : String(error)
2399
- });
2400
- }
2401
- }
2402
- async function performOnboarding(context, handleCancel, mode) {
2403
- const { telemetry, logger, packageManager } = context;
2404
- const projectRoot = await detectProjectRoot(context.cwd, logger);
2405
- const { pkg } = await detectFramework(projectRoot, logger);
2406
- if (!pkg) throw new Error('Error detecting framework');
2407
- let selectedMode = mode ?? null;
2408
- logger.debug(`Selected mode: ${selectedMode}`);
2409
- if (!selectedMode) selectedMode = await handleStorageModeSelection(context, handleCancel);
2410
- if (!selectedMode) return;
2411
- const sharedOptions = {
2412
- context,
2413
- spinner: prompts_spinner(),
2414
- handleCancel
2415
- };
2416
- let installDepsConfirmed = false;
2417
- let ranInstall = false;
2418
- const dependenciesToAdd = [];
2419
- switch(selectedMode){
2420
- case 'c15t':
2421
- {
2422
- const c15tResult = await setupC15tMode(sharedOptions);
2423
- installDepsConfirmed = c15tResult.installDepsConfirmed;
2424
- ranInstall = c15tResult.ranInstall;
2425
- dependenciesToAdd.push(context.framework.pkg);
2426
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_C15T_MODE_CONFIGURED, {
2427
- usingEnvFile: c15tResult.usingEnvFile,
2428
- proxyNextjs: c15tResult.proxyNextjs
2429
- });
2430
- break;
2431
- }
2432
- case 'offline':
2433
- {
2434
- const offlineResult = await setupOfflineMode({
2435
- context,
2436
- spinner: prompts_spinner()
2437
- });
2438
- installDepsConfirmed = offlineResult.installDepsConfirmed;
2439
- ranInstall = offlineResult.ranInstall;
2440
- dependenciesToAdd.push(context.framework.pkg);
2441
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_OFFLINE_MODE_CONFIGURED, {});
2442
- break;
2443
- }
2444
- case 'self-hosted':
2445
- {
2446
- const selfHostedResult = await setupSelfHostedMode({
2447
- context,
2448
- spinner: prompts_spinner(),
2449
- handleCancel
2450
- });
2451
- installDepsConfirmed = selfHostedResult.installDepsConfirmed;
2452
- ranInstall = selfHostedResult.ranInstall;
2453
- dependenciesToAdd.push(context.framework.pkg);
2454
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_SELF_HOSTED_CONFIGURED, {});
2455
- break;
2456
- }
2457
- default:
2458
- {
2459
- const customResult = await setupCustomMode({
2460
- context,
2461
- spinner: prompts_spinner()
2462
- });
2463
- installDepsConfirmed = customResult.installDepsConfirmed;
2464
- ranInstall = customResult.ranInstall;
2465
- dependenciesToAdd.push(context.framework.pkg);
2466
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_CUSTOM_MODE_CONFIGURED, {});
2467
- break;
2468
- }
2469
- }
2470
- await displayNextSteps({
2471
- context,
2472
- projectRoot,
2473
- storageMode: selectedMode,
2474
- installDepsConfirmed,
2475
- ranInstall,
2476
- dependenciesToAdd,
2477
- packageManager
2478
- });
2479
- await handleGitHubStar(context);
2480
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_COMPLETED, {
2481
- success: true,
2482
- selectedMode,
2483
- installDependencies: ranInstall
2484
- });
2485
- }
2486
- async function handleStorageModeSelection(context, handleCancel) {
2487
- const { telemetry } = context;
2488
- const storageModeSelection = await prompts_select({
2489
- message: 'How would you like to store consent decisions?',
2490
- initialValue: 'c15t',
2491
- options: [
2492
- {
2493
- value: 'c15t',
2494
- label: 'Hosted c15t (consent.io)',
2495
- hint: 'Recommended: Fully managed service'
2496
- },
2497
- {
2498
- value: 'offline',
2499
- label: 'Offline Mode',
2500
- hint: 'Store in browser, no backend needed'
2501
- },
2502
- {
2503
- value: 'self-hosted',
2504
- label: 'Self-Hosted',
2505
- hint: 'Run your own c15t backend'
2506
- },
2507
- {
2508
- value: 'custom',
2509
- label: 'Custom Implementation',
2510
- hint: 'Full control over storage logic'
2511
- }
2512
- ]
2513
- });
2514
- if (handleCancel(storageModeSelection)) return null;
2515
- const storageMode = storageModeSelection;
2516
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_STORAGE_MODE_SELECTED, {
2517
- storageMode
2518
- });
2519
- return storageMode;
2520
- }
2521
- async function displayNextSteps(options) {
2522
- const { context, projectRoot, storageMode, installDepsConfirmed, ranInstall, dependenciesToAdd, packageManager } = options;
2523
- const { logger, cwd } = context;
2524
- const { log } = prompts_namespaceObject;
2525
- const configPath = node_path.join(projectRoot, 'c15t.config.ts');
2526
- const relativeConfigPath = node_path.relative(cwd, configPath);
2527
- const importPath = `./${relativeConfigPath.replace(WINDOWS_PATH_SEPARATOR_REGEX, '/').replace(FILE_EXTENSION_REGEX, '')}`;
2528
- const importStatement = picocolors.cyan(`import { c15tConfig } from '${importPath}';`);
2529
- switch(storageMode){
2530
- case 'c15t':
2531
- break;
2532
- case 'offline':
2533
- break;
2534
- case 'self-hosted':
2535
- log.step('Setup your backend with the c15t docs:');
2536
- logger.info('https://c15t.com/docs/self-host/v2');
2537
- break;
2538
- case 'custom':
2539
- {
2540
- log.step('Configuration Complete! Next Steps:');
2541
- const steps = `1. Implement your custom endpoint handlers (referenced in ${picocolors.cyan(relativeConfigPath)}).\n 2. Import and use configuration in your app: ${importStatement}`;
2542
- logger.info(steps);
2543
- break;
2544
- }
2545
- }
2546
- if (installDepsConfirmed && !ranInstall) logger.info(` - ${picocolors.yellow('Dependency installation failed.')} Please check errors and install manually.`);
2547
- else if (!ranInstall && dependenciesToAdd.length > 0) {
2548
- const pmCommand = getManualInstallCommand(dependenciesToAdd, packageManager.name);
2549
- logger.warn(` - Run ${picocolors.cyan(pmCommand)} to install required dependencies.`);
2550
- }
2551
- }
2552
- async function handleGitHubStar(context) {
2553
- const { logger, telemetry } = context;
2554
- logger.note(`${picocolors.bold('✨ Setup complete!')} Your c15t configuration is ready to use. \n
2555
-
2556
- We're building c15t as an ${picocolors.bold('open source')} project to make consent management more accessible.
2557
- If you find this useful, we'd really appreciate a GitHub star - it helps others discover the project!`, '🎉 Thanks for using c15t');
2558
- const shouldOpenGitHub = await prompts_confirm({
2559
- message: 'Would you like to star c15t on GitHub now?',
2560
- initialValue: true
2561
- });
2562
- if (isCancel(shouldOpenGitHub)) {
2563
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_GITHUB_STAR, {
2564
- action: 'cancelled'
2565
- });
2566
- return context.error.handleCancel('GitHub star prompt cancelled. Exiting onboarding.', {
2567
- command: 'onboarding',
2568
- stage: 'github_star'
2569
- });
2570
- }
2571
- telemetry.trackEvent(TelemetryEventName.ONBOARDING_GITHUB_STAR, {
2572
- action: shouldOpenGitHub ? 'opened_browser' : 'declined'
2573
- });
2574
- if (shouldOpenGitHub) try {
2575
- note('Your support helps us continue improving c15t.\nThank you for being part of our community!', '⭐ Star Us on GitHub');
2576
- await open_0('https://github.com/c15t/c15t');
2577
- logger.success('GitHub repository opened. Thank you for your support!');
2578
- } catch (error) {
2579
- logger.debug('Failed to open browser:', error);
2580
- logger.info(`You can star us later by visiting: ${picocolors.cyan('https://github.com/c15t/c15t')}`);
2581
- }
2582
- }
2583
2719
  const subcommands = [
2584
2720
  {
2585
2721
  name: 'generate',
@@ -2632,14 +2768,14 @@ async function selfHost(context) {
2632
2768
  label: 'Exit',
2633
2769
  hint: 'Return to main menu'
2634
2770
  });
2635
- const selectedSubcommandName = await prompts_select({
2636
- message: formatLogMessage('info', 'Which self-host command would you like to run?'),
2771
+ const selectedSubcommandName = await prompts_.select({
2772
+ message: (0, utils_logger.$e)('info', 'Which self-host command would you like to run?'),
2637
2773
  options: promptOptions
2638
2774
  });
2639
- if (isCancel(selectedSubcommandName) || 'exit' === selectedSubcommandName) {
2775
+ if (prompts_.isCancel(selectedSubcommandName) || 'exit' === selectedSubcommandName) {
2640
2776
  logger.debug('Interactive selection cancelled or exit chosen.');
2641
2777
  telemetry.trackEvent(TelemetryEventName.INTERACTIVE_MENU_EXITED, {
2642
- action: isCancel(selectedSubcommandName) ? 'cancelled' : 'exit',
2778
+ action: prompts_.isCancel(selectedSubcommandName) ? 'cancelled' : 'exit',
2643
2779
  context: 'self-host'
2644
2780
  });
2645
2781
  error.handleCancel('Operation cancelled.', {
@@ -2667,12 +2803,12 @@ async function selfHost(context) {
2667
2803
  }
2668
2804
  async function displayIntro(context, version) {
2669
2805
  const { logger } = context;
2670
- logger.info(`${picocolors.bold('Welcome!')} Let's get you set up.`);
2806
+ logger.info(`${external_picocolors_["default"].bold('Welcome!')} Let's get you set up.`);
2671
2807
  logger.message('');
2672
2808
  let figletText = 'c15t';
2673
2809
  try {
2674
2810
  figletText = await new Promise((resolve)=>{
2675
- figlet.text('c15t', {
2811
+ __rspack_external_figlet["default"].text('c15t', {
2676
2812
  font: 'Nancyj-Improved',
2677
2813
  horizontalLayout: 'default',
2678
2814
  verticalLayout: 'default',
@@ -2712,6 +2848,7 @@ async function displayIntro(context, version) {
2712
2848
  });
2713
2849
  logger.message(coloredLines.join('\n'));
2714
2850
  }
2851
+ var constants = __webpack_require__("./src/constants.ts");
2715
2852
  function createErrorHandlers(context) {
2716
2853
  const { logger, telemetry } = context;
2717
2854
  return {
@@ -2719,7 +2856,7 @@ function createErrorHandlers(context) {
2719
2856
  logger.error(message, error);
2720
2857
  if (error instanceof Error) logger.error(error.message);
2721
2858
  else logger.error(String(error));
2722
- logger.failed(`${picocolors.red('Operation failed unexpectedly.')}`);
2859
+ logger.failed(`${external_picocolors_["default"].red('Operation failed unexpectedly.')}`);
2723
2860
  process.exit(1);
2724
2861
  },
2725
2862
  handleCancel: (message = 'Operation cancelled.', context)=>{
@@ -2739,10 +2876,10 @@ function createFileSystem(context) {
2739
2876
  return {
2740
2877
  getPackageInfo: ()=>{
2741
2878
  logger.debug('Reading package.json');
2742
- const packageJsonPath = node_path.join(cwd, 'package.json');
2879
+ const packageJsonPath = external_node_path_["default"].join(cwd, 'package.json');
2743
2880
  logger.debug(`package.json path: ${packageJsonPath}`);
2744
2881
  try {
2745
- const packageInfo = fs_extra.readJSONSync(packageJsonPath);
2882
+ const packageInfo = __rspack_external_fs_extra_ce68a66b["default"].readJSONSync(packageJsonPath);
2746
2883
  logger.debug('Successfully read package.json');
2747
2884
  return {
2748
2885
  name: packageInfo?.name || 'unknown',
@@ -2759,6 +2896,99 @@ function createFileSystem(context) {
2759
2896
  }
2760
2897
  };
2761
2898
  }
2899
+ async function detectFramework(projectRoot, logger) {
2900
+ try {
2901
+ logger?.debug(`Detecting framework in ${projectRoot}`);
2902
+ const packageJsonPath = external_node_path_["default"].join(projectRoot, 'package.json');
2903
+ const packageJson = JSON.parse(await promises_["default"].readFile(packageJsonPath, 'utf-8'));
2904
+ const deps = {
2905
+ ...packageJson.dependencies,
2906
+ ...packageJson.devDependencies
2907
+ };
2908
+ const hasReact = 'react' in deps;
2909
+ const reactVersion = hasReact ? deps.react : null;
2910
+ logger?.debug(`React detected: ${hasReact}${reactVersion ? ` (version: ${reactVersion})` : ''}`);
2911
+ const tailwindVersion = deps.tailwindcss || null;
2912
+ logger?.debug(`Tailwind detected: ${!!tailwindVersion}${tailwindVersion ? ` (version: ${tailwindVersion})` : ''}`);
2913
+ let framework = null;
2914
+ let frameworkVersion = null;
2915
+ let pkg = hasReact ? '@c15t/react' : 'c15t';
2916
+ if ('next' in deps) {
2917
+ framework = 'Next.js';
2918
+ frameworkVersion = deps.next;
2919
+ pkg = '@c15t/nextjs';
2920
+ } else if ('@remix-run/react' in deps) {
2921
+ framework = 'Remix';
2922
+ frameworkVersion = deps['@remix-run/react'];
2923
+ } else if ('@vitejs/plugin-react' in deps || '@vitejs/plugin-react-swc' in deps) {
2924
+ framework = 'Vite + React';
2925
+ frameworkVersion = deps['@vitejs/plugin-react'] || deps['@vitejs/plugin-react-swc'];
2926
+ } else if ('gatsby' in deps) {
2927
+ framework = 'Gatsby';
2928
+ frameworkVersion = deps.gatsby;
2929
+ } else if (hasReact) {
2930
+ framework = 'React';
2931
+ frameworkVersion = reactVersion;
2932
+ }
2933
+ logger?.debug(`Detected framework: ${framework}${frameworkVersion ? ` (version: ${frameworkVersion})` : ''}, package: ${pkg}`);
2934
+ return {
2935
+ framework,
2936
+ frameworkVersion,
2937
+ pkg,
2938
+ hasReact,
2939
+ reactVersion,
2940
+ tailwindVersion
2941
+ };
2942
+ } catch (error) {
2943
+ logger?.debug(`Framework detection failed: ${error instanceof Error ? error.message : String(error)}`);
2944
+ return {
2945
+ framework: null,
2946
+ frameworkVersion: null,
2947
+ pkg: 'c15t',
2948
+ hasReact: false,
2949
+ reactVersion: null,
2950
+ tailwindVersion: null
2951
+ };
2952
+ }
2953
+ }
2954
+ async function detectProjectRoot(cwd, logger) {
2955
+ let projectRoot = cwd;
2956
+ logger?.debug(`Starting project root detection from: ${cwd}`);
2957
+ try {
2958
+ let prevDir = '';
2959
+ let depth = 0;
2960
+ const maxDepth = 10;
2961
+ while(projectRoot !== prevDir && depth < maxDepth){
2962
+ logger?.debug(`Checking directory (depth ${depth}): ${projectRoot}`);
2963
+ try {
2964
+ const packageJsonPath = external_node_path_["default"].join(projectRoot, 'package.json');
2965
+ logger?.debug(`Looking for package.json at: ${packageJsonPath}`);
2966
+ await promises_["default"].access(packageJsonPath);
2967
+ logger?.debug(`Found package.json at: ${projectRoot}`);
2968
+ break;
2969
+ } catch (error) {
2970
+ logger?.debug(`No package.json found in ${projectRoot}: ${error instanceof Error ? error.message : String(error)}`);
2971
+ prevDir = projectRoot;
2972
+ projectRoot = external_node_path_["default"].dirname(projectRoot);
2973
+ depth++;
2974
+ }
2975
+ }
2976
+ if (projectRoot === prevDir) {
2977
+ logger?.debug('Reached root directory without finding package.json');
2978
+ logger?.failed('Could not find project root (no package.json found)');
2979
+ }
2980
+ if (depth >= maxDepth) {
2981
+ logger?.debug('Reached maximum directory depth without finding package.json');
2982
+ logger?.failed('Could not find project root (reached maximum directory depth)');
2983
+ }
2984
+ logger?.debug(`Project root detection complete. Found at: ${projectRoot}`);
2985
+ return projectRoot;
2986
+ } catch (error) {
2987
+ logger?.debug(`Project root detection failed: ${error instanceof Error ? error.message : String(error)}`);
2988
+ logger?.debug(`Falling back to current directory: ${cwd}`);
2989
+ return cwd;
2990
+ }
2991
+ }
2762
2992
  const SUPPORTED_PACKAGE_MANAGERS = [
2763
2993
  'npm',
2764
2994
  'yarn',
@@ -2777,7 +3007,7 @@ async function getPackageManagerVersion(pm) {
2777
3007
  async function detectPackageManager(projectRoot, logger) {
2778
3008
  try {
2779
3009
  logger?.debug('Detecting package manager');
2780
- const pm = await detect({
3010
+ const pm = await (0, __rspack_external_package_manager_detector_detect_94d6a9ae.detect)({
2781
3011
  cwd: projectRoot
2782
3012
  });
2783
3013
  if (!pm) throw new Error('No package manager detected');
@@ -2790,7 +3020,7 @@ async function detectPackageManager(projectRoot, logger) {
2790
3020
  } catch (error) {
2791
3021
  logger?.error(`Error detecting package manager: ${error instanceof Error ? error.message : String(error)}`);
2792
3022
  }
2793
- const selectedPackageManager = await prompts_select({
3023
+ const selectedPackageManager = await prompts_.select({
2794
3024
  message: 'Please select your package manager:',
2795
3025
  options: [
2796
3026
  {
@@ -2812,7 +3042,7 @@ async function detectPackageManager(projectRoot, logger) {
2812
3042
  ],
2813
3043
  initialValue: 'npm'
2814
3044
  });
2815
- if (isCancel(selectedPackageManager)) {
3045
+ if (prompts_.isCancel(selectedPackageManager)) {
2816
3046
  logger?.debug('Package manager selection cancelled by user');
2817
3047
  logger?.failed('Package manager selection cancelled. Exiting.');
2818
3048
  process.exit(0);
@@ -2907,7 +3137,7 @@ function parseCliArgs(rawArgs, commands) {
2907
3137
  if (nextArg && !nextArg.startsWith('-')) {
2908
3138
  parsedFlags[primaryName] = nextArg;
2909
3139
  i++;
2910
- } else prompts_log.warn(formatLogMessage('warn', `Flag ${arg} expects a value, but none was found or the next item is a flag.`));
3140
+ } else prompts_.log.warn((0, utils_logger.$e)('warn', `Flag ${arg} expects a value, but none was found or the next item is a flag.`));
2911
3141
  } else parsedFlags[primaryName] = true;
2912
3142
  }
2913
3143
  break;
@@ -2928,11 +3158,11 @@ function createUserInteraction(context) {
2928
3158
  return {
2929
3159
  confirm: async (message, initialValue)=>{
2930
3160
  logger.debug(`Confirm action: "${message}", Initial: ${initialValue}`);
2931
- const confirmed = await prompts_confirm({
3161
+ const confirmed = await prompts_.confirm({
2932
3162
  message,
2933
3163
  initialValue
2934
3164
  });
2935
- if (isCancel(confirmed)) {
3165
+ if (prompts_.isCancel(confirmed)) {
2936
3166
  error.handleCancel();
2937
3167
  return false;
2938
3168
  }
@@ -2945,10 +3175,10 @@ async function createCliContext(rawArgs, cwd, commands) {
2945
3175
  const { commandName, commandArgs, parsedFlags } = parseCliArgs(rawArgs, commands);
2946
3176
  let desiredLogLevel = 'info';
2947
3177
  const levelArg = parsedFlags.logger;
2948
- if ('string' == typeof levelArg) if (validLogLevels.includes(levelArg)) desiredLogLevel = levelArg;
3178
+ if ('string' == typeof levelArg) if (utils_logger.U0.includes(levelArg)) desiredLogLevel = levelArg;
2949
3179
  else console.warn(`[CLI Setup] Invalid log level '${levelArg}' provided via --logger. Using default 'info'.`);
2950
3180
  else if (true === levelArg) console.warn("[CLI Setup] --logger flag found but no level specified. Using default 'info'.");
2951
- const logger = createCliLogger(desiredLogLevel);
3181
+ const logger = (0, utils_logger.xw)(desiredLogLevel);
2952
3182
  logger.debug(`Logger initialized with level: ${desiredLogLevel}`);
2953
3183
  const baseContext = {
2954
3184
  logger,
@@ -3018,8 +3248,8 @@ const src_commands = [
3018
3248
  description: 'Open our GitHub repository to give us a star.',
3019
3249
  action: async (context)=>{
3020
3250
  const { logger } = context;
3021
- logger.note(`We're building c15t as an ${picocolors.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');
3022
- await open_0('https://github.com/c15t/c15t');
3251
+ logger.note(`We're building c15t as an ${external_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');
3252
+ await (0, __rspack_external_open["default"])(constants.tl.GITHUB);
3023
3253
  logger.success('Thank you for your support!');
3024
3254
  }
3025
3255
  },
@@ -3030,7 +3260,7 @@ const src_commands = [
3030
3260
  description: 'Open the c15t documentation in your browser.',
3031
3261
  action: async (context)=>{
3032
3262
  const { logger } = context;
3033
- await open_0('https://c15t.com/docs?ref=cli');
3263
+ await (0, __rspack_external_open["default"])(`${constants.tl.DOCS}?ref=cli`);
3034
3264
  logger.success('Documentation opened in your browser.');
3035
3265
  }
3036
3266
  }
@@ -3044,8 +3274,8 @@ async function main() {
3044
3274
  const version = packageInfo.version;
3045
3275
  if (!telemetry.isDisabled()) logger.note(`c15t collects anonymous usage data to help improve the CLI.
3046
3276
  This data is not personally identifiable and helps us prioritize features.
3047
- To disable telemetry, use the ${picocolors.cyan('--no-telemetry')}
3048
- flag or set ${picocolors.cyan('C15T_TELEMETRY_DISABLED=1')} in your environment.`, `${formatLogMessage('info', 'Telemetry Notice')}`);
3277
+ To disable telemetry, use the ${external_picocolors_["default"].cyan('--no-telemetry')}
3278
+ flag or set ${external_picocolors_["default"].cyan('C15T_TELEMETRY_DISABLED=1')} in your environment.`, `${(0, utils_logger.$e)('info', 'Telemetry Notice')}`);
3049
3279
  try {
3050
3280
  telemetry.trackEvent(TelemetryEventName.CLI_INVOKED, {
3051
3281
  version,
@@ -3118,14 +3348,14 @@ flag or set ${picocolors.cyan('C15T_TELEMETRY_DISABLED=1')} in your environment.
3118
3348
  label: 'exit',
3119
3349
  hint: 'Close the CLI'
3120
3350
  });
3121
- const selectedCommandName = await prompts_select({
3122
- message: formatLogMessage('info', 'Which command would you like to run?'),
3351
+ const selectedCommandName = await prompts_.select({
3352
+ message: (0, utils_logger.$e)('info', 'Which command would you like to run?'),
3123
3353
  options: promptOptions
3124
3354
  });
3125
- if (isCancel(selectedCommandName) || 'exit' === selectedCommandName) {
3355
+ if (prompts_.isCancel(selectedCommandName) || 'exit' === selectedCommandName) {
3126
3356
  logger.debug('Interactive selection cancelled or exit chosen.');
3127
3357
  telemetry.trackEvent(TelemetryEventName.INTERACTIVE_MENU_EXITED, {
3128
- action: isCancel(selectedCommandName) ? 'cancelled' : 'exit'
3358
+ action: prompts_.isCancel(selectedCommandName) ? 'cancelled' : 'exit'
3129
3359
  });
3130
3360
  context.error.handleCancel('Operation cancelled.', {
3131
3361
  command: 'interactive_menu',