@sonordev/site-kit 1.2.7

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 (300) hide show
  1. package/README.md +376 -0
  2. package/dist/SetupWizard-Cki06kB0.d.mts +12 -0
  3. package/dist/SetupWizard-Cki06kB0.d.ts +12 -0
  4. package/dist/analytics/index.d.mts +93 -0
  5. package/dist/analytics/index.d.ts +93 -0
  6. package/dist/analytics/index.js +89 -0
  7. package/dist/analytics/index.js.map +1 -0
  8. package/dist/analytics/index.mjs +71 -0
  9. package/dist/analytics/index.mjs.map +1 -0
  10. package/dist/api-CWtoFJCO.d.mts +137 -0
  11. package/dist/api-CWtoFJCO.d.ts +137 -0
  12. package/dist/blog/index.d.mts +305 -0
  13. package/dist/blog/index.d.ts +305 -0
  14. package/dist/blog/index.js +1578 -0
  15. package/dist/blog/index.js.map +1 -0
  16. package/dist/blog/index.mjs +1562 -0
  17. package/dist/blog/index.mjs.map +1 -0
  18. package/dist/blog/server.d.mts +229 -0
  19. package/dist/blog/server.d.ts +229 -0
  20. package/dist/blog/server.js +692 -0
  21. package/dist/blog/server.js.map +1 -0
  22. package/dist/blog/server.mjs +666 -0
  23. package/dist/blog/server.mjs.map +1 -0
  24. package/dist/chunk-24277A3Q.mjs +968 -0
  25. package/dist/chunk-24277A3Q.mjs.map +1 -0
  26. package/dist/chunk-373TK6TZ.js +321 -0
  27. package/dist/chunk-373TK6TZ.js.map +1 -0
  28. package/dist/chunk-3MYZS6PD.js +30 -0
  29. package/dist/chunk-3MYZS6PD.js.map +1 -0
  30. package/dist/chunk-43GBM4SX.js +283 -0
  31. package/dist/chunk-43GBM4SX.js.map +1 -0
  32. package/dist/chunk-4XPGGLVP.mjs +53 -0
  33. package/dist/chunk-4XPGGLVP.mjs.map +1 -0
  34. package/dist/chunk-622GAQP5.js +2008 -0
  35. package/dist/chunk-622GAQP5.js.map +1 -0
  36. package/dist/chunk-6BIPAKL4.mjs +28 -0
  37. package/dist/chunk-6BIPAKL4.mjs.map +1 -0
  38. package/dist/chunk-6ZCISNAB.mjs +343 -0
  39. package/dist/chunk-6ZCISNAB.mjs.map +1 -0
  40. package/dist/chunk-72MQFHYJ.js +1429 -0
  41. package/dist/chunk-72MQFHYJ.js.map +1 -0
  42. package/dist/chunk-7557OTHW.js +62 -0
  43. package/dist/chunk-7557OTHW.js.map +1 -0
  44. package/dist/chunk-7FUV73JZ.js +981 -0
  45. package/dist/chunk-7FUV73JZ.js.map +1 -0
  46. package/dist/chunk-7RF6PVHA.mjs +324 -0
  47. package/dist/chunk-7RF6PVHA.mjs.map +1 -0
  48. package/dist/chunk-7RYCHO6D.mjs +134 -0
  49. package/dist/chunk-7RYCHO6D.mjs.map +1 -0
  50. package/dist/chunk-7UKPRW25.mjs +1999 -0
  51. package/dist/chunk-7UKPRW25.mjs.map +1 -0
  52. package/dist/chunk-7URAOG2M.js +14864 -0
  53. package/dist/chunk-7URAOG2M.js.map +1 -0
  54. package/dist/chunk-AFAO3TGS.mjs +810 -0
  55. package/dist/chunk-AFAO3TGS.mjs.map +1 -0
  56. package/dist/chunk-BYLIU6XG.js +343 -0
  57. package/dist/chunk-BYLIU6XG.js.map +1 -0
  58. package/dist/chunk-D63MUKZ6.mjs +4423 -0
  59. package/dist/chunk-D63MUKZ6.mjs.map +1 -0
  60. package/dist/chunk-DDKW2FNA.js +390 -0
  61. package/dist/chunk-DDKW2FNA.js.map +1 -0
  62. package/dist/chunk-DQYMKR27.mjs +341 -0
  63. package/dist/chunk-DQYMKR27.mjs.map +1 -0
  64. package/dist/chunk-DW5UJKHH.js +221 -0
  65. package/dist/chunk-DW5UJKHH.js.map +1 -0
  66. package/dist/chunk-EEZCR6E6.js +50 -0
  67. package/dist/chunk-EEZCR6E6.js.map +1 -0
  68. package/dist/chunk-GCJXQ4AG.mjs +59 -0
  69. package/dist/chunk-GCJXQ4AG.mjs.map +1 -0
  70. package/dist/chunk-JGNQK2G6.mjs +14845 -0
  71. package/dist/chunk-JGNQK2G6.mjs.map +1 -0
  72. package/dist/chunk-JTLOJLWQ.mjs +563 -0
  73. package/dist/chunk-JTLOJLWQ.mjs.map +1 -0
  74. package/dist/chunk-K23A4G76.mjs +202 -0
  75. package/dist/chunk-K23A4G76.mjs.map +1 -0
  76. package/dist/chunk-KKU3K7RG.js +336 -0
  77. package/dist/chunk-KKU3K7RG.js.map +1 -0
  78. package/dist/chunk-KUGMH4ZF.js +571 -0
  79. package/dist/chunk-KUGMH4ZF.js.map +1 -0
  80. package/dist/chunk-LBVWVP72.js +110 -0
  81. package/dist/chunk-LBVWVP72.js.map +1 -0
  82. package/dist/chunk-LIVWLY2P.js +138 -0
  83. package/dist/chunk-LIVWLY2P.js.map +1 -0
  84. package/dist/chunk-M2T6R7BA.mjs +1003 -0
  85. package/dist/chunk-M2T6R7BA.mjs.map +1 -0
  86. package/dist/chunk-MV3QN7PW.mjs +47 -0
  87. package/dist/chunk-MV3QN7PW.mjs.map +1 -0
  88. package/dist/chunk-OB7E654K.js +72 -0
  89. package/dist/chunk-OB7E654K.js.map +1 -0
  90. package/dist/chunk-OIIKTGRL.mjs +380 -0
  91. package/dist/chunk-OIIKTGRL.mjs.map +1 -0
  92. package/dist/chunk-P3UWIUJS.mjs +1427 -0
  93. package/dist/chunk-P3UWIUJS.mjs.map +1 -0
  94. package/dist/chunk-PKN27UMH.mjs +136 -0
  95. package/dist/chunk-PKN27UMH.mjs.map +1 -0
  96. package/dist/chunk-QXV4667R.mjs +105 -0
  97. package/dist/chunk-QXV4667R.mjs.map +1 -0
  98. package/dist/chunk-S7FRYNSU.mjs +315 -0
  99. package/dist/chunk-S7FRYNSU.mjs.map +1 -0
  100. package/dist/chunk-TFLQX7K7.mjs +68 -0
  101. package/dist/chunk-TFLQX7K7.mjs.map +1 -0
  102. package/dist/chunk-UWE5PCYJ.mjs +279 -0
  103. package/dist/chunk-UWE5PCYJ.mjs.map +1 -0
  104. package/dist/chunk-UYFDNX2F.js +4469 -0
  105. package/dist/chunk-UYFDNX2F.js.map +1 -0
  106. package/dist/chunk-W4PALSGM.js +350 -0
  107. package/dist/chunk-W4PALSGM.js.map +1 -0
  108. package/dist/chunk-WECQ6KOB.js +1008 -0
  109. package/dist/chunk-WECQ6KOB.js.map +1 -0
  110. package/dist/chunk-XQQWI6WB.js +814 -0
  111. package/dist/chunk-XQQWI6WB.js.map +1 -0
  112. package/dist/chunk-XZJOZJB6.js +140 -0
  113. package/dist/chunk-XZJOZJB6.js.map +1 -0
  114. package/dist/chunk-ZSMWDLMK.js +63 -0
  115. package/dist/chunk-ZSMWDLMK.js.map +1 -0
  116. package/dist/cli/index.js +37243 -0
  117. package/dist/cli/index.js.map +1 -0
  118. package/dist/cli/index.mjs +37209 -0
  119. package/dist/cli/index.mjs.map +1 -0
  120. package/dist/commerce/index.d.mts +170 -0
  121. package/dist/commerce/index.d.ts +170 -0
  122. package/dist/commerce/index.js +174 -0
  123. package/dist/commerce/index.js.map +1 -0
  124. package/dist/commerce/index.mjs +5 -0
  125. package/dist/commerce/index.mjs.map +1 -0
  126. package/dist/commerce/server.d.mts +107 -0
  127. package/dist/commerce/server.d.ts +107 -0
  128. package/dist/commerce/server.js +187 -0
  129. package/dist/commerce/server.js.map +1 -0
  130. package/dist/commerce/server.mjs +177 -0
  131. package/dist/commerce/server.mjs.map +1 -0
  132. package/dist/config/index.d.mts +43 -0
  133. package/dist/config/index.d.ts +43 -0
  134. package/dist/config/index.js +66 -0
  135. package/dist/config/index.js.map +1 -0
  136. package/dist/config/index.mjs +64 -0
  137. package/dist/config/index.mjs.map +1 -0
  138. package/dist/engage/index.d.mts +33 -0
  139. package/dist/engage/index.d.ts +33 -0
  140. package/dist/engage/index.js +22 -0
  141. package/dist/engage/index.js.map +1 -0
  142. package/dist/engage/index.mjs +5 -0
  143. package/dist/engage/index.mjs.map +1 -0
  144. package/dist/forms/index.d.mts +437 -0
  145. package/dist/forms/index.d.ts +437 -0
  146. package/dist/forms/index.js +1168 -0
  147. package/dist/forms/index.js.map +1 -0
  148. package/dist/forms/index.mjs +1142 -0
  149. package/dist/forms/index.mjs.map +1 -0
  150. package/dist/generators-2XKQMPKH.mjs +4 -0
  151. package/dist/generators-2XKQMPKH.mjs.map +1 -0
  152. package/dist/generators-DTMO36DV.js +33 -0
  153. package/dist/generators-DTMO36DV.js.map +1 -0
  154. package/dist/images/index.d.mts +4 -0
  155. package/dist/images/index.d.ts +4 -0
  156. package/dist/images/index.js +46 -0
  157. package/dist/images/index.js.map +1 -0
  158. package/dist/images/index.mjs +5 -0
  159. package/dist/images/index.mjs.map +1 -0
  160. package/dist/images/server.d.mts +69 -0
  161. package/dist/images/server.d.ts +69 -0
  162. package/dist/images/server.js +21 -0
  163. package/dist/images/server.js.map +1 -0
  164. package/dist/images/server.mjs +4 -0
  165. package/dist/images/server.mjs.map +1 -0
  166. package/dist/index.d.mts +846 -0
  167. package/dist/index.d.ts +846 -0
  168. package/dist/index.js +2623 -0
  169. package/dist/index.js.map +1 -0
  170. package/dist/index.mjs +2416 -0
  171. package/dist/index.mjs.map +1 -0
  172. package/dist/layout/index.d.mts +53 -0
  173. package/dist/layout/index.d.ts +53 -0
  174. package/dist/layout/index.js +187 -0
  175. package/dist/layout/index.js.map +1 -0
  176. package/dist/layout/index.mjs +185 -0
  177. package/dist/layout/index.mjs.map +1 -0
  178. package/dist/llms/index.d.mts +448 -0
  179. package/dist/llms/index.d.ts +448 -0
  180. package/dist/llms/index.js +581 -0
  181. package/dist/llms/index.js.map +1 -0
  182. package/dist/llms/index.mjs +529 -0
  183. package/dist/llms/index.mjs.map +1 -0
  184. package/dist/manifest/index.d.mts +62 -0
  185. package/dist/manifest/index.d.ts +62 -0
  186. package/dist/manifest/index.js +85 -0
  187. package/dist/manifest/index.js.map +1 -0
  188. package/dist/manifest/index.mjs +83 -0
  189. package/dist/manifest/index.mjs.map +1 -0
  190. package/dist/middleware/index.d.mts +63 -0
  191. package/dist/middleware/index.d.ts +63 -0
  192. package/dist/middleware/index.js +54 -0
  193. package/dist/middleware/index.js.map +1 -0
  194. package/dist/middleware/index.mjs +51 -0
  195. package/dist/middleware/index.mjs.map +1 -0
  196. package/dist/migrator-2MQHOFDQ.mjs +4 -0
  197. package/dist/migrator-2MQHOFDQ.mjs.map +1 -0
  198. package/dist/migrator-THJCF6MZ.js +37 -0
  199. package/dist/migrator-THJCF6MZ.js.map +1 -0
  200. package/dist/redirects/index.d.mts +78 -0
  201. package/dist/redirects/index.d.ts +78 -0
  202. package/dist/redirects/index.js +26 -0
  203. package/dist/redirects/index.js.map +1 -0
  204. package/dist/redirects/index.mjs +5 -0
  205. package/dist/redirects/index.mjs.map +1 -0
  206. package/dist/reputation/index.d.mts +57 -0
  207. package/dist/reputation/index.d.ts +57 -0
  208. package/dist/reputation/index.js +21 -0
  209. package/dist/reputation/index.js.map +1 -0
  210. package/dist/reputation/index.mjs +4 -0
  211. package/dist/reputation/index.mjs.map +1 -0
  212. package/dist/robots/index.d.mts +38 -0
  213. package/dist/robots/index.d.ts +38 -0
  214. package/dist/robots/index.js +52 -0
  215. package/dist/robots/index.js.map +1 -0
  216. package/dist/robots/index.mjs +50 -0
  217. package/dist/robots/index.mjs.map +1 -0
  218. package/dist/routing-B5XS-6_W.d.mts +118 -0
  219. package/dist/routing-DZYzyDHw.d.ts +118 -0
  220. package/dist/scanner-GAF5PO5F.js +53 -0
  221. package/dist/scanner-GAF5PO5F.js.map +1 -0
  222. package/dist/scanner-LKJKW7IT.mjs +4 -0
  223. package/dist/scanner-LKJKW7IT.mjs.map +1 -0
  224. package/dist/securityHeaders-nwZ6nP4g.d.mts +24 -0
  225. package/dist/securityHeaders-nwZ6nP4g.d.ts +24 -0
  226. package/dist/seo/index.d.mts +600 -0
  227. package/dist/seo/index.d.ts +600 -0
  228. package/dist/seo/index.js +883 -0
  229. package/dist/seo/index.js.map +1 -0
  230. package/dist/seo/index.mjs +773 -0
  231. package/dist/seo/index.mjs.map +1 -0
  232. package/dist/seo/register-sitemap-cli.js +151 -0
  233. package/dist/seo/register-sitemap-cli.js.map +1 -0
  234. package/dist/seo/register-sitemap-cli.mjs +144 -0
  235. package/dist/seo/register-sitemap-cli.mjs.map +1 -0
  236. package/dist/seo/server.d.mts +107 -0
  237. package/dist/seo/server.d.ts +107 -0
  238. package/dist/seo/server.js +207 -0
  239. package/dist/seo/server.js.map +1 -0
  240. package/dist/seo/server.mjs +186 -0
  241. package/dist/seo/server.mjs.map +1 -0
  242. package/dist/server-api-EWXKOQZA.mjs +4 -0
  243. package/dist/server-api-EWXKOQZA.mjs.map +1 -0
  244. package/dist/server-api-GJPNRYUP.js +81 -0
  245. package/dist/server-api-GJPNRYUP.js.map +1 -0
  246. package/dist/setup/client.d.mts +60 -0
  247. package/dist/setup/client.d.ts +60 -0
  248. package/dist/setup/client.js +31 -0
  249. package/dist/setup/client.js.map +1 -0
  250. package/dist/setup/client.mjs +6 -0
  251. package/dist/setup/client.mjs.map +1 -0
  252. package/dist/setup/index.d.mts +5 -0
  253. package/dist/setup/index.d.ts +5 -0
  254. package/dist/setup/index.js +35 -0
  255. package/dist/setup/index.js.map +1 -0
  256. package/dist/setup/index.mjs +6 -0
  257. package/dist/setup/index.mjs.map +1 -0
  258. package/dist/setup/server.d.mts +14 -0
  259. package/dist/setup/server.d.ts +14 -0
  260. package/dist/setup/server.js +13 -0
  261. package/dist/setup/server.js.map +1 -0
  262. package/dist/setup/server.mjs +4 -0
  263. package/dist/setup/server.mjs.map +1 -0
  264. package/dist/site-config/index.d.mts +24 -0
  265. package/dist/site-config/index.d.ts +24 -0
  266. package/dist/site-config/index.js +17 -0
  267. package/dist/site-config/index.js.map +1 -0
  268. package/dist/site-config/index.mjs +4 -0
  269. package/dist/site-config/index.mjs.map +1 -0
  270. package/dist/sitemap/index.d.mts +96 -0
  271. package/dist/sitemap/index.d.ts +96 -0
  272. package/dist/sitemap/index.js +288 -0
  273. package/dist/sitemap/index.js.map +1 -0
  274. package/dist/sitemap/index.mjs +285 -0
  275. package/dist/sitemap/index.mjs.map +1 -0
  276. package/dist/socket-loader-J26QHHOB.js +16 -0
  277. package/dist/socket-loader-J26QHHOB.js.map +1 -0
  278. package/dist/socket-loader-R7S2YJ2J.mjs +14 -0
  279. package/dist/socket-loader-R7S2YJ2J.mjs.map +1 -0
  280. package/dist/types-0dmq3k20.d.mts +168 -0
  281. package/dist/types-0dmq3k20.d.ts +168 -0
  282. package/dist/types-Blb2QNkV.d.mts +263 -0
  283. package/dist/types-Blb2QNkV.d.ts +263 -0
  284. package/dist/types-BnCwwUX3.d.mts +250 -0
  285. package/dist/types-BnCwwUX3.d.ts +250 -0
  286. package/dist/types-CGlnp43R.d.mts +312 -0
  287. package/dist/types-CGlnp43R.d.ts +312 -0
  288. package/dist/types-D08004rU.d.mts +179 -0
  289. package/dist/types-D08004rU.d.ts +179 -0
  290. package/dist/types-DNSYU7qI.d.mts +127 -0
  291. package/dist/types-DNSYU7qI.d.ts +127 -0
  292. package/dist/types-KZP_VWZp.d.mts +266 -0
  293. package/dist/types-KZP_VWZp.d.ts +266 -0
  294. package/dist/useEventModal-BVTx69XE.d.mts +274 -0
  295. package/dist/useEventModal-Dx1dItTJ.d.ts +274 -0
  296. package/dist/web-vitals-444RLW3B.js +252 -0
  297. package/dist/web-vitals-444RLW3B.js.map +1 -0
  298. package/dist/web-vitals-KPICZIEF.mjs +241 -0
  299. package/dist/web-vitals-KPICZIEF.mjs.map +1 -0
  300. package/package.json +192 -0
@@ -0,0 +1,968 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+
4
+ // src/cli/migrator/index.ts
5
+ function addImportSafely(content, importStatement) {
6
+ const importModule = importStatement.match(/from\s+['"]([^'"]+)['"]/)?.[1];
7
+ if (importModule && content.includes(importModule)) {
8
+ return content;
9
+ }
10
+ const directiveMatch = content.match(/^(['"]use (client|server)['"][\s;]*\n?)/);
11
+ if (directiveMatch) {
12
+ const directive = directiveMatch[0];
13
+ const restOfFile = content.slice(directive.length);
14
+ const firstImportMatch = restOfFile.match(/^(import\s+)/);
15
+ if (firstImportMatch) {
16
+ return directive + importStatement + "\n" + restOfFile;
17
+ } else {
18
+ return directive + importStatement + "\n" + restOfFile;
19
+ }
20
+ } else {
21
+ const firstImportMatch = content.match(/^(import\s+)/);
22
+ if (firstImportMatch) {
23
+ return importStatement + "\n" + content;
24
+ } else {
25
+ return importStatement + "\n\n" + content;
26
+ }
27
+ }
28
+ }
29
+ function isClientComponent(content) {
30
+ const firstLines = content.split("\n").slice(0, 5).join("\n");
31
+ return /['"]use client['"]/.test(firstLines);
32
+ }
33
+ function addToExistingImport(content, namedExport, modulePath) {
34
+ const importPattern = new RegExp(
35
+ `(import\\s*\\{[^}]*)\\}\\s*from\\s*['"]${modulePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}['"]`,
36
+ "g"
37
+ );
38
+ if (importPattern.test(content)) {
39
+ importPattern.lastIndex = 0;
40
+ return content.replace(importPattern, (match, imports) => {
41
+ if (imports.includes(namedExport)) {
42
+ return match;
43
+ }
44
+ return `${imports.trim()}, ${namedExport} } from '${modulePath}'`;
45
+ });
46
+ }
47
+ return content;
48
+ }
49
+ function insertManagedSchemaIntoJSX(content, pagePath, isTypeScript) {
50
+ if (content.includes("<ManagedSchema")) {
51
+ return content;
52
+ }
53
+ const projectIdSuffix = isTypeScript ? "!" : "";
54
+ const schemaComponent = `<ManagedSchema
55
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID${projectIdSuffix}}
56
+ path="${pagePath}"
57
+ />`;
58
+ const returnPatterns = [
59
+ // return (<> ... - fragment
60
+ /return\s*\(\s*<>/,
61
+ // return ( <Fragment> ...
62
+ /return\s*\(\s*<Fragment>/,
63
+ // return (<div ... or return (<main ... etc
64
+ /return\s*\(\s*<([a-zA-Z][a-zA-Z0-9]*)[^>]*>/
65
+ ];
66
+ for (const pattern of returnPatterns) {
67
+ const match = content.match(pattern);
68
+ if (match && match.index !== void 0) {
69
+ const insertPos = match.index + match[0].length;
70
+ content = content.slice(0, insertPos) + "\n " + schemaComponent + content.slice(insertPos);
71
+ return content;
72
+ }
73
+ }
74
+ const simpleReturnMatch = content.match(/return\s*\(/);
75
+ if (simpleReturnMatch && simpleReturnMatch.index !== void 0) {
76
+ const afterReturn = content.slice(simpleReturnMatch.index + simpleReturnMatch[0].length);
77
+ const firstTagMatch = afterReturn.match(/^\s*<([a-zA-Z>][^>]*)>?/);
78
+ if (firstTagMatch) {
79
+ const insertPos = simpleReturnMatch.index + simpleReturnMatch[0].length + firstTagMatch[0].length;
80
+ content = content.slice(0, insertPos) + "\n " + schemaComponent + content.slice(insertPos);
81
+ return content;
82
+ }
83
+ }
84
+ return content;
85
+ }
86
+ async function migrateFiles(scanResults, options) {
87
+ const results = [];
88
+ for (const form of scanResults.forms) {
89
+ if (form.suggestedAction === "manual") {
90
+ results.push({
91
+ filePath: form.filePath,
92
+ success: false,
93
+ changes: [],
94
+ error: "Form too complex for auto-migration"
95
+ });
96
+ continue;
97
+ }
98
+ try {
99
+ const result = await migrateForm(form, options);
100
+ results.push(result);
101
+ } catch (error) {
102
+ results.push({
103
+ filePath: form.filePath,
104
+ success: false,
105
+ changes: [],
106
+ error: error.message
107
+ });
108
+ }
109
+ }
110
+ for (const widget of scanResults.widgets) {
111
+ try {
112
+ const result = await migrateWidget(widget.filePath, widget, options);
113
+ results.push(result);
114
+ } catch (error) {
115
+ results.push({
116
+ filePath: widget.filePath,
117
+ success: false,
118
+ changes: [],
119
+ error: error.message
120
+ });
121
+ }
122
+ }
123
+ for (const meta of scanResults.metadata || []) {
124
+ try {
125
+ const result = await migrateMetadata(meta.filePath, meta, options);
126
+ results.push(result);
127
+ } catch (error) {
128
+ results.push({
129
+ filePath: meta.filePath,
130
+ success: false,
131
+ changes: [],
132
+ error: error.message
133
+ });
134
+ }
135
+ }
136
+ for (const schema of scanResults.schemas || []) {
137
+ try {
138
+ const result = await migrateSchema(schema.filePath, schema, options);
139
+ results.push(result);
140
+ } catch (error) {
141
+ results.push({
142
+ filePath: schema.filePath,
143
+ success: false,
144
+ changes: [],
145
+ error: error.message
146
+ });
147
+ }
148
+ }
149
+ for (const faq of scanResults.faqs || []) {
150
+ try {
151
+ const result = await migrateFAQ(faq.filePath, faq, options);
152
+ results.push(result);
153
+ } catch (error) {
154
+ results.push({
155
+ filePath: faq.filePath,
156
+ success: false,
157
+ changes: [],
158
+ error: error.message
159
+ });
160
+ }
161
+ }
162
+ for (const sitemap of scanResults.sitemaps || []) {
163
+ if (sitemap.generator === "site-kit") continue;
164
+ try {
165
+ const result = await migrateSitemap(sitemap.filePath, sitemap, options);
166
+ results.push(result);
167
+ } catch (error) {
168
+ results.push({
169
+ filePath: sitemap.filePath,
170
+ success: false,
171
+ changes: [],
172
+ error: error.message
173
+ });
174
+ }
175
+ }
176
+ for (const analytics of scanResults.analytics || []) {
177
+ try {
178
+ const result = await migrateAnalytics(analytics.filePath, analytics, options);
179
+ results.push(result);
180
+ } catch (error) {
181
+ results.push({
182
+ filePath: analytics.filePath,
183
+ success: false,
184
+ changes: [],
185
+ error: error.message
186
+ });
187
+ }
188
+ }
189
+ return results;
190
+ }
191
+ async function migrateForm(form, options) {
192
+ const changes = [];
193
+ const fullPath = path.resolve(process.cwd(), form.filePath);
194
+ const formSlug = generateSlug(form.componentName);
195
+ let formId;
196
+ if (!options.dryRun) {
197
+ try {
198
+ formId = await createFormInUptrade(form, formSlug, options);
199
+ changes.push(`Created managed form: ${formSlug}`);
200
+ } catch (error) {
201
+ changes.push(`Form may already exist: ${formSlug}`);
202
+ }
203
+ } else {
204
+ changes.push(`[DRY RUN] Would create managed form: ${formSlug}`);
205
+ }
206
+ if (options.dryRun) {
207
+ changes.push("[DRY RUN] Would create backup of original file");
208
+ changes.push("[DRY RUN] Would replace form with Site-Kit managed form");
209
+ return { filePath: form.filePath, success: true, changes, formId };
210
+ }
211
+ const content = await fs.readFile(fullPath, "utf-8");
212
+ const backupPath = fullPath + ".backup";
213
+ await fs.writeFile(backupPath, content, "utf-8");
214
+ changes.push(`Created backup: ${form.filePath}.backup`);
215
+ const isTypeScript = form.filePath.endsWith(".tsx") || form.filePath.endsWith(".ts");
216
+ const newCode = generateMigratedFormCode(form, formSlug, isTypeScript);
217
+ await fs.writeFile(fullPath, newCode, "utf-8");
218
+ changes.push("Replaced component with Site-Kit managed form");
219
+ changes.push("Original saved to .backup file - delete when satisfied");
220
+ return {
221
+ filePath: form.filePath,
222
+ success: true,
223
+ changes,
224
+ formId
225
+ };
226
+ }
227
+ function generateMigratedFormCode(form, formSlug, isTypeScript = true) {
228
+ const componentName = form.componentName || "MigratedForm";
229
+ const classNameType = isTypeScript ? "{ className?: string }" : "{ className }";
230
+ return `/**
231
+ * ${componentName}
232
+ *
233
+ * Migrated to @sonordev/site-kit
234
+ * Managed form: ${formSlug}
235
+ *
236
+ * Original file backed up to: ${form.filePath}.backup
237
+ */
238
+
239
+ 'use client'
240
+
241
+ import { useForm } from '@sonordev/site-kit/forms'
242
+
243
+ export function ${componentName}(${classNameType}) {
244
+ const {
245
+ form,
246
+ fields,
247
+ values,
248
+ errors,
249
+ setFieldValue,
250
+ submit,
251
+ isSubmitting,
252
+ isComplete
253
+ } = useForm('${formSlug}')
254
+
255
+ if (isComplete) {
256
+ return (
257
+ <div className={className}>
258
+ <p className="text-green-600">{form?.successMessage || 'Thanks for your submission!'}</p>
259
+ </div>
260
+ )
261
+ }
262
+
263
+ return (
264
+ <form
265
+ onSubmit={(e) => { e.preventDefault(); submit() }}
266
+ className={className}
267
+ >
268
+ {fields.map(field => (
269
+ <div key={field.slug} className="mb-4">
270
+ <label className="block text-sm font-medium mb-1">
271
+ {field.label}
272
+ {field.isRequired && <span className="text-red-500 ml-1">*</span>}
273
+ </label>
274
+
275
+ {field.fieldType === 'textarea' ? (
276
+ <textarea
277
+ name={field.slug}
278
+ placeholder={field.placeholder}
279
+ value={String(values[field.slug] || '')}
280
+ onChange={(e) => setFieldValue(field.slug, e.target.value)}
281
+ className="w-full p-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-transparent"
282
+ rows={4}
283
+ />
284
+ ) : field.fieldType === 'select' && field.options ? (
285
+ <select
286
+ name={field.slug}
287
+ value={String(values[field.slug] || '')}
288
+ onChange={(e) => setFieldValue(field.slug, e.target.value)}
289
+ className="w-full p-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-transparent"
290
+ >
291
+ <option value="">Select...</option>
292
+ {field.options.map(opt => (
293
+ <option key={opt.value} value={opt.value}>{opt.label}</option>
294
+ ))}
295
+ </select>
296
+ ) : (
297
+ <input
298
+ type={field.fieldType}
299
+ name={field.slug}
300
+ placeholder={field.placeholder}
301
+ value={String(values[field.slug] || '')}
302
+ onChange={(e) => setFieldValue(field.slug, e.target.value)}
303
+ className="w-full p-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-transparent"
304
+ />
305
+ )}
306
+
307
+ {errors[field.slug] && (
308
+ <p className="mt-1 text-sm text-red-500">{errors[field.slug]}</p>
309
+ )}
310
+
311
+ {field.helpText && (
312
+ <p className="mt-1 text-xs text-gray-500">{field.helpText}</p>
313
+ )}
314
+ </div>
315
+ ))}
316
+
317
+ <button
318
+ type="submit"
319
+ disabled={isSubmitting}
320
+ className="w-full py-2 px-4 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
321
+ >
322
+ {isSubmitting ? 'Submitting...' : (form?.submitButtonText || 'Submit')}
323
+ </button>
324
+ </form>
325
+ )
326
+ }
327
+
328
+ export default ${componentName}
329
+ `;
330
+ }
331
+ async function createFormInUptrade(form, slug, options) {
332
+ const response = await fetch("https://api.uptrademedia.com/forms", {
333
+ method: "POST",
334
+ headers: {
335
+ "Content-Type": "application/json",
336
+ "Authorization": `Bearer ${options.apiKey}`
337
+ },
338
+ body: JSON.stringify({
339
+ projectId: options.projectId,
340
+ slug,
341
+ name: formatName(form.componentName),
342
+ formType: detectFormType(form),
343
+ successMessage: "Thanks for your submission!",
344
+ submitButtonText: "Submit",
345
+ fields: form.fields.map((f, i) => ({
346
+ slug: f.name,
347
+ label: formatLabel(f.name),
348
+ fieldType: mapFieldType(f.type),
349
+ placeholder: f.placeholder,
350
+ isRequired: f.required,
351
+ sortOrder: i,
352
+ width: "full"
353
+ }))
354
+ })
355
+ });
356
+ if (!response.ok) {
357
+ const error = await response.json();
358
+ throw new Error(error.message || "Failed to create form");
359
+ }
360
+ const data = await response.json();
361
+ return data.id;
362
+ }
363
+ async function migrateWidget(filePath, widget, options) {
364
+ const changes = [];
365
+ if (options.dryRun) {
366
+ changes.push(`[DRY RUN] Would remove ${widget.widgetType} script`);
367
+ changes.push("[DRY RUN] Would enable Engage in SiteKitProvider");
368
+ return { filePath, success: true, changes };
369
+ }
370
+ const fullPath = path.resolve(process.cwd(), filePath);
371
+ let content = await fs.readFile(fullPath, "utf-8");
372
+ switch (widget.widgetType) {
373
+ case "intercom":
374
+ content = content.replace(/<Script[^>]*intercom[^>]*\/?>(?:<\/Script>)?/gi, "{/* Intercom replaced with Uptrade Engage */}");
375
+ content = content.replace(/window\.Intercom\s*=\s*[^;]+;/g, "");
376
+ break;
377
+ case "crisp":
378
+ content = content.replace(/<Script[^>]*crisp[^>]*\/?>(?:<\/Script>)?/gi, "{/* Crisp replaced with Uptrade Engage */}");
379
+ break;
380
+ case "drift":
381
+ content = content.replace(/<Script[^>]*drift[^>]*\/?>(?:<\/Script>)?/gi, "{/* Drift replaced with Uptrade Engage */}");
382
+ break;
383
+ }
384
+ await fs.writeFile(fullPath, content, "utf-8");
385
+ changes.push(`Removed ${widget.widgetType} script`);
386
+ changes.push("Enable Engage in SiteKitProvider to add chat widget");
387
+ return { filePath, success: true, changes };
388
+ }
389
+ function matchBalancedBraces(content, startIndex) {
390
+ if (content[startIndex] !== "{") return null;
391
+ let depth = 0;
392
+ let i = startIndex;
393
+ while (i < content.length) {
394
+ if (content[i] === "{") depth++;
395
+ else if (content[i] === "}") {
396
+ depth--;
397
+ if (depth === 0) {
398
+ return content.slice(startIndex, i + 1);
399
+ }
400
+ }
401
+ i++;
402
+ }
403
+ return null;
404
+ }
405
+ async function migrateMetadata(filePath, metadata, options) {
406
+ const changes = [];
407
+ const fullPath = path.resolve(process.cwd(), filePath);
408
+ let pagePath = filePath.replace(/^app\//, "/").replace(/^src\/app\//, "/").replace(/\/page\.(tsx?|jsx?)$/, "").replace(/\/layout\.(tsx?|jsx?)$/, "").replace(/\[([^\]]+)\]/g, ":$1");
409
+ if (pagePath === "") pagePath = "/";
410
+ let content = await fs.readFile(fullPath, "utf-8");
411
+ const isTypeScript = filePath.endsWith(".tsx") || filePath.endsWith(".ts");
412
+ const ext = isTypeScript ? ".tsx" : ".jsx";
413
+ if (isClientComponent(content)) {
414
+ const dir = path.dirname(fullPath);
415
+ const layoutPath = path.join(dir, `layout${ext}`);
416
+ try {
417
+ await fs.access(layoutPath);
418
+ const layoutContent = await fs.readFile(layoutPath, "utf-8");
419
+ if (layoutContent.includes("getManagedMetadata")) {
420
+ changes.push("Layout already has managed metadata");
421
+ return { filePath, success: true, changes };
422
+ }
423
+ changes.push("Layout exists but does not have managed metadata - add generateMetadata manually");
424
+ return { filePath, success: true, changes };
425
+ } catch {
426
+ }
427
+ if (options.dryRun) {
428
+ changes.push(`[DRY RUN] Client component detected - would create layout${ext} with managed metadata`);
429
+ changes.push(`[DRY RUN] Page path: ${pagePath}`);
430
+ return { filePath, success: true, changes };
431
+ }
432
+ try {
433
+ await createPageMetadata(pagePath, metadata, options);
434
+ changes.push(`Created managed metadata for page: ${pagePath}`);
435
+ } catch (error) {
436
+ changes.push(`Page metadata may already exist: ${pagePath}`);
437
+ }
438
+ const dirName = path.basename(dir).replace(/^\[\.\.\.([^\]]+)\]$/, "$1").replace(/^\[([^\]]+)\]$/, "$1");
439
+ const layoutName = dirName.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("") + "Layout";
440
+ const layoutCode = `import { getManagedMetadata, ManagedSchema } from '@sonordev/site-kit/seo'
441
+
442
+ export async function generateMetadata() {
443
+ return getManagedMetadata({
444
+ projectId: process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID${isTypeScript ? "!" : ""},
445
+ path: '${pagePath}',
446
+ fallback: {
447
+ title: '${(metadata.title || "Page Title").replace(/'/g, "\\'")}',
448
+ description: '${(metadata.description || "Page description").replace(/'/g, "\\'")}',
449
+ },
450
+ })
451
+ }
452
+
453
+ export default function ${layoutName}({ children }${isTypeScript ? ": { children: React.ReactNode }" : ""}) {
454
+ return (
455
+ <>
456
+ <ManagedSchema
457
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID${isTypeScript ? "!" : ""}}
458
+ path="${pagePath}"
459
+ />
460
+ {children}
461
+ </>
462
+ )
463
+ }
464
+ `;
465
+ await fs.writeFile(layoutPath, layoutCode, "utf-8");
466
+ changes.push(`Created layout${ext} with managed metadata and schema (client component page)`);
467
+ return { filePath, success: true, changes };
468
+ }
469
+ if (options.dryRun) {
470
+ changes.push(`[DRY RUN] Would create managed metadata for page: ${pagePath}`);
471
+ changes.push("[DRY RUN] Would add generateMetadata function (preserving rest of file)");
472
+ return { filePath, success: true, changes };
473
+ }
474
+ try {
475
+ await createPageMetadata(pagePath, metadata, options);
476
+ changes.push(`Created managed metadata for page: ${pagePath}`);
477
+ } catch (error) {
478
+ changes.push(`Page metadata may already exist: ${pagePath}`);
479
+ }
480
+ if (metadata.type === "no-metadata") {
481
+ if (!content.includes("'@sonordev/site-kit/seo") && !content.includes('"@sonordev/site-kit/seo')) {
482
+ content = addImportSafely(content, `import { getManagedMetadata, ManagedSchema } from '@sonordev/site-kit/seo'`);
483
+ } else if (!content.includes("ManagedSchema")) {
484
+ content = addToExistingImport(content, "ManagedSchema", "@sonordev/site-kit/seo");
485
+ }
486
+ const generateMetadataCode = `
487
+ export async function generateMetadata() {
488
+ return getManagedMetadata({
489
+ projectId: process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID${isTypeScript ? "!" : ""},
490
+ path: '${pagePath}',
491
+ fallback: {
492
+ title: '${(metadata.title || "Page Title").replace(/'/g, "\\'")}',
493
+ description: '${(metadata.description || "Page description").replace(/'/g, "\\'")}',
494
+ },
495
+ })
496
+ }
497
+ `;
498
+ const importEndMatch = content.match(/^(import\s+.*?['"][^'"]+['"];?\s*\n)+/m);
499
+ if (importEndMatch) {
500
+ const insertPos = importEndMatch.index + importEndMatch[0].length;
501
+ content = content.slice(0, insertPos) + generateMetadataCode + content.slice(insertPos);
502
+ } else {
503
+ const useClientMatch = content.match(/^['"]use client['"];?\s*\n/);
504
+ if (useClientMatch) {
505
+ const insertPos = useClientMatch[0].length;
506
+ content = content.slice(0, insertPos) + generateMetadataCode + content.slice(insertPos);
507
+ } else {
508
+ content = generateMetadataCode + content;
509
+ }
510
+ }
511
+ content = insertManagedSchemaIntoJSX(content, pagePath, isTypeScript);
512
+ changes.push("Added ManagedSchema component");
513
+ await fs.writeFile(fullPath, content, "utf-8");
514
+ changes.push("Added generateMetadata function");
515
+ return { filePath, success: true, changes };
516
+ }
517
+ if (metadata.type === "next-metadata") {
518
+ const metadataExportMatch = content.match(/export const metadata(?::\s*Metadata)?\s*=\s*/);
519
+ if (metadataExportMatch && metadataExportMatch.index !== void 0) {
520
+ const braceStart = metadataExportMatch.index + metadataExportMatch[0].length;
521
+ const braceContent = matchBalancedBraces(content, braceStart);
522
+ if (braceContent) {
523
+ const fullMatch = metadataExportMatch[0] + braceContent;
524
+ if (!content.includes("'@sonordev/site-kit/seo") && !content.includes('"@sonordev/site-kit/seo')) {
525
+ content = addImportSafely(content, `import { getManagedMetadata, ManagedSchema } from '@sonordev/site-kit/seo'`);
526
+ } else if (!content.includes("ManagedSchema")) {
527
+ content = addToExistingImport(content, "ManagedSchema", "@sonordev/site-kit/seo");
528
+ }
529
+ const generateMetadataCode = `export async function generateMetadata() {
530
+ return getManagedMetadata({
531
+ projectId: process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID${isTypeScript ? "!" : ""},
532
+ path: '${pagePath}',
533
+ fallback: {
534
+ title: '${(metadata.title || "Page Title").replace(/'/g, "\\'")}',
535
+ description: '${(metadata.description || "Page description").replace(/'/g, "\\'")}',
536
+ },
537
+ })
538
+ }`;
539
+ content = content.replace(fullMatch, generateMetadataCode);
540
+ changes.push("Replaced static metadata with getManagedMetadata");
541
+ content = insertManagedSchemaIntoJSX(content, pagePath, isTypeScript);
542
+ changes.push("Added ManagedSchema component");
543
+ }
544
+ }
545
+ if (content.includes("generateMetadata") && !content.includes("getManagedMetadata")) {
546
+ changes.push("generateMetadata function detected - add getManagedMetadata manually for full control");
547
+ }
548
+ }
549
+ await fs.writeFile(fullPath, content, "utf-8");
550
+ return { filePath, success: true, changes };
551
+ }
552
+ async function createPageMetadata(pagePath, metadata, options) {
553
+ const response = await fetch("https://api.uptrademedia.com/seo/pages", {
554
+ method: "POST",
555
+ headers: {
556
+ "Content-Type": "application/json",
557
+ "Authorization": `Bearer ${options.apiKey}`
558
+ },
559
+ body: JSON.stringify({
560
+ project_id: options.projectId,
561
+ path: pagePath,
562
+ managed_title: metadata.title,
563
+ managed_meta_description: metadata.description
564
+ })
565
+ });
566
+ if (!response.ok && response.status !== 409) {
567
+ throw new Error(`Failed to create page: ${response.statusText}`);
568
+ }
569
+ }
570
+ function extractSchemaJSON(content) {
571
+ const scriptPatterns = [
572
+ /<script\s+type=["']application\/ld\+json["'][^>]*>([\s\S]*?)<\/script>/i,
573
+ /<Script\s+[^>]*type=["']application\/ld\+json["'][^>]*>([\s\S]*?)<\/Script>/i
574
+ ];
575
+ for (const pattern of scriptPatterns) {
576
+ const match = content.match(pattern);
577
+ if (match && match[1]) {
578
+ try {
579
+ let jsonStr = match[1].trim();
580
+ if (jsonStr.startsWith("{") && (jsonStr.includes("`") || jsonStr.includes('"'))) {
581
+ const templateMatch = jsonStr.match(/\{[`"]([\s\S]*?)[`"]\}/);
582
+ if (templateMatch) {
583
+ jsonStr = templateMatch[1];
584
+ }
585
+ }
586
+ const innerHTMLMatch = jsonStr.match(/dangerouslySetInnerHTML=\{\{\s*__html:\s*['"`]([\s\S]*?)['"`]\s*\}\}/);
587
+ if (innerHTMLMatch) {
588
+ jsonStr = innerHTMLMatch[1];
589
+ }
590
+ const parsed = JSON.parse(jsonStr);
591
+ return {
592
+ schemaType: parsed["@type"] || "Unknown",
593
+ schemaJson: parsed
594
+ };
595
+ } catch {
596
+ return null;
597
+ }
598
+ }
599
+ }
600
+ const schemaObjectMatch = content.match(/const\s+\w*[sS]chema\w*\s*=\s*(\{[\s\S]*?@context[\s\S]*?\})\s*;?/);
601
+ if (schemaObjectMatch) {
602
+ try {
603
+ const typeMatch = schemaObjectMatch[1].match(/@type["']?\s*:\s*["']([^"']+)["']/);
604
+ if (typeMatch) {
605
+ return {
606
+ schemaType: typeMatch[1],
607
+ schemaJson: { "@type": typeMatch[1], "_note": "Schema extracted from JS object - review in Portal" }
608
+ };
609
+ }
610
+ } catch {
611
+ return null;
612
+ }
613
+ }
614
+ return null;
615
+ }
616
+ async function createSchemaRecord(pagePath, schemaType, schemaJson, options) {
617
+ const apiUrl = process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com";
618
+ const response = await fetch(`${apiUrl}/api/public/seo/register-schema`, {
619
+ method: "POST",
620
+ headers: {
621
+ "Content-Type": "application/json",
622
+ "x-api-key": options.apiKey
623
+ },
624
+ body: JSON.stringify({
625
+ page_path: pagePath,
626
+ schema_type: schemaType,
627
+ schema_json: schemaJson,
628
+ is_implemented: true
629
+ })
630
+ });
631
+ if (!response.ok) {
632
+ const errorText = await response.text();
633
+ throw new Error(`Failed to create schema: ${response.status} ${errorText}`);
634
+ }
635
+ }
636
+ async function migrateSchema(filePath, schema, options) {
637
+ const changes = [];
638
+ const fullPath = path.resolve(process.cwd(), filePath);
639
+ let pagePath = filePath.replace(/^app\//, "/").replace(/^src\/app\//, "/").replace(/\/page\.(tsx?|jsx?)$/, "").replace(/\[([^\]]+)\]/g, ":$1");
640
+ if (pagePath === "") pagePath = "/";
641
+ let content = await fs.readFile(fullPath, "utf-8");
642
+ if (isClientComponent(content)) {
643
+ changes.push("Skipped: Client component cannot use ManagedSchema (requires server rendering)");
644
+ changes.push("Consider moving schema to a parent server component or layout.tsx");
645
+ return { filePath, success: true, changes };
646
+ }
647
+ const extractedSchema = extractSchemaJSON(content);
648
+ if (options.dryRun) {
649
+ changes.push(`[DRY RUN] Would replace JSON-LD script with ManagedSchema component`);
650
+ changes.push(`[DRY RUN] Schema type: ${extractedSchema?.schemaType || schema.schemaType || "Unknown"}`);
651
+ if (extractedSchema) {
652
+ changes.push(`[DRY RUN] Would upload extracted schema to Portal`);
653
+ }
654
+ return { filePath, success: true, changes };
655
+ }
656
+ if (extractedSchema) {
657
+ try {
658
+ await createSchemaRecord(pagePath, extractedSchema.schemaType, extractedSchema.schemaJson, options);
659
+ changes.push(`Created managed schema (${extractedSchema.schemaType}) for: ${pagePath}`);
660
+ } catch (error) {
661
+ changes.push(`Schema record may already exist for: ${pagePath}`);
662
+ }
663
+ }
664
+ const alreadyHasManagedSchema = content.includes("<ManagedSchema");
665
+ const isTypeScript = filePath.endsWith(".tsx") || filePath.endsWith(".ts");
666
+ const projectIdSuffix = isTypeScript ? "!" : "";
667
+ const jsonLdPattern = /<script\s+type=["']application\/ld\+json["'][^>]*>[\s\S]*?<\/script>/gi;
668
+ const scriptPattern = /<Script\s+[^>]*type=["']application\/ld\+json["'][^>]*>[\s\S]*?<\/Script>/gi;
669
+ const hasJsonLd = jsonLdPattern.test(content) || scriptPattern.test(content);
670
+ if (hasJsonLd) {
671
+ jsonLdPattern.lastIndex = 0;
672
+ scriptPattern.lastIndex = 0;
673
+ if (alreadyHasManagedSchema) {
674
+ content = content.replace(jsonLdPattern, "{/* JSON-LD migrated to ManagedSchema */}");
675
+ content = content.replace(scriptPattern, "{/* JSON-LD migrated to ManagedSchema */}");
676
+ changes.push("Removed JSON-LD script (ManagedSchema already present)");
677
+ } else {
678
+ if (!content.includes("ManagedSchema")) {
679
+ if (content.includes("'@sonordev/site-kit/seo") || content.includes('"@sonordev/site-kit/seo')) {
680
+ content = addToExistingImport(content, "ManagedSchema", "@sonordev/site-kit/seo");
681
+ } else {
682
+ content = addImportSafely(content, `import { ManagedSchema } from '@sonordev/site-kit/seo'`);
683
+ }
684
+ changes.push("Added ManagedSchema import");
685
+ }
686
+ content = content.replace(jsonLdPattern, `<ManagedSchema
687
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID${projectIdSuffix}}
688
+ path="${pagePath}"
689
+ />`);
690
+ content = content.replace(scriptPattern, `<ManagedSchema
691
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID${projectIdSuffix}}
692
+ path="${pagePath}"
693
+ />`);
694
+ changes.push("Replaced JSON-LD script with ManagedSchema component");
695
+ }
696
+ }
697
+ await fs.writeFile(fullPath, content, "utf-8");
698
+ return { filePath, success: true, changes };
699
+ }
700
+ function extractFAQItems(content, faqType) {
701
+ const items = [];
702
+ if (faqType === "details-summary") {
703
+ const detailsPattern = /<details[^>]*>[\s\S]*?<summary[^>]*>([\s\S]*?)<\/summary>([\s\S]*?)<\/details>/gi;
704
+ let match2;
705
+ while ((match2 = detailsPattern.exec(content)) !== null) {
706
+ const question = match2[1].replace(/<[^>]+>/g, "").trim();
707
+ const answer = match2[2].replace(/<[^>]+>/g, "").trim();
708
+ if (question && answer) {
709
+ items.push({ question, answer });
710
+ }
711
+ }
712
+ }
713
+ const accordionItemPattern = /<(?:Accordion\.Item|AccordionItem|FAQItem)[^>]*(?:question|title)=["'`]([^"'`]+)["'`][^>]*>[\s\S]*?(?:answer|content)=["'`]([^"'`]+)["'`]/gi;
714
+ let match;
715
+ while ((match = accordionItemPattern.exec(content)) !== null) {
716
+ items.push({ question: match[1], answer: match[2] });
717
+ }
718
+ const faqArrayPattern = /\{\s*question:\s*["'`]([^"'`]+)["'`]\s*,\s*answer:\s*["'`]([^"'`]+)["'`]\s*\}/gi;
719
+ while ((match = faqArrayPattern.exec(content)) !== null) {
720
+ items.push({ question: match[1], answer: match[2] });
721
+ }
722
+ const shortFaqPattern = /\{\s*q:\s*["'`]([^"'`]+)["'`]\s*,\s*a:\s*["'`]([^"'`]+)["'`]\s*\}/gi;
723
+ while ((match = shortFaqPattern.exec(content)) !== null) {
724
+ items.push({ question: match[1], answer: match[2] });
725
+ }
726
+ return items;
727
+ }
728
+ async function createFAQRecord(pagePath, items, options) {
729
+ const apiUrl = process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com";
730
+ const response = await fetch(`${apiUrl}/api/public/seo/register-faq`, {
731
+ method: "POST",
732
+ headers: {
733
+ "Content-Type": "application/json",
734
+ "x-api-key": options.apiKey
735
+ },
736
+ body: JSON.stringify({
737
+ path: pagePath,
738
+ title: "Frequently Asked Questions",
739
+ items: items.map((item, index) => ({
740
+ id: `faq-${index + 1}`,
741
+ question: item.question,
742
+ answer: item.answer,
743
+ order: index,
744
+ is_visible: true
745
+ })),
746
+ include_schema: true,
747
+ is_published: items.length > 0
748
+ })
749
+ });
750
+ if (!response.ok) {
751
+ const errorText = await response.text();
752
+ throw new Error(`Failed to create FAQ: ${response.status} ${errorText}`);
753
+ }
754
+ }
755
+ async function migrateFAQ(filePath, faq, options) {
756
+ const changes = [];
757
+ const fullPath = path.resolve(process.cwd(), filePath);
758
+ let pagePath = filePath.replace(/^app\//, "/").replace(/^src\/app\//, "/").replace(/\/page\.(tsx?|jsx?)$/, "").replace(/\[([^\]]+)\]/g, ":$1");
759
+ if (pagePath === "") pagePath = "/";
760
+ let content = await fs.readFile(fullPath, "utf-8");
761
+ if (isClientComponent(content)) {
762
+ changes.push("Skipped: Client component cannot use ManagedFAQ (requires server rendering)");
763
+ changes.push("Consider using ManagedFAQ in a parent server component or layout.tsx");
764
+ return { filePath, success: true, changes };
765
+ }
766
+ const extractedItems = extractFAQItems(content, faq.type);
767
+ if (options.dryRun) {
768
+ changes.push(`[DRY RUN] Would extract ${extractedItems.length} FAQ items`);
769
+ changes.push(`[DRY RUN] Would create managed FAQ record for path: ${pagePath}`);
770
+ changes.push(`[DRY RUN] Would insert ManagedFAQ component`);
771
+ changes.push(`[DRY RUN] FAQ type: ${faq.type}${faq.componentName ? ` (${faq.componentName})` : ""}`);
772
+ return { filePath, success: true, changes };
773
+ }
774
+ if (extractedItems.length > 0) {
775
+ try {
776
+ await createFAQRecord(pagePath, extractedItems, options);
777
+ changes.push(`Created managed FAQ with ${extractedItems.length} items for: ${pagePath}`);
778
+ } catch (error) {
779
+ changes.push(`FAQ record may already exist for: ${pagePath}`);
780
+ }
781
+ } else {
782
+ try {
783
+ await createFAQRecord(pagePath, [], options);
784
+ changes.push(`Created empty managed FAQ for: ${pagePath} (add items in Portal)`);
785
+ } catch {
786
+ changes.push(`FAQ record may already exist for: ${pagePath}`);
787
+ }
788
+ }
789
+ if (!content.includes("ManagedFAQ")) {
790
+ if (content.includes("'@sonordev/site-kit/seo") || content.includes('"@sonordev/site-kit/seo')) {
791
+ content = addToExistingImport(content, "ManagedFAQ", "@sonordev/site-kit/seo");
792
+ } else {
793
+ content = addImportSafely(content, `import { ManagedFAQ } from '@sonordev/site-kit/seo'`);
794
+ }
795
+ changes.push("Added ManagedFAQ import");
796
+ }
797
+ const isTypeScript = filePath.endsWith(".tsx") || filePath.endsWith(".ts");
798
+ const projectIdSuffix = isTypeScript ? "!" : "";
799
+ const managedFAQComponent = `<ManagedFAQ
800
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID${projectIdSuffix}}
801
+ path="${pagePath}"
802
+ />`;
803
+ if (faq.componentName) {
804
+ const componentPattern = new RegExp(`(<${faq.componentName}[^>]*>)`, "i");
805
+ if (componentPattern.test(content)) {
806
+ content = content.replace(componentPattern, `{/* Managed FAQ - content controlled via Portal */}
807
+ ${managedFAQComponent}
808
+ {/* Original FAQ component (can be removed once migrated) */}
809
+ $1`);
810
+ changes.push("Inserted ManagedFAQ component before existing FAQ");
811
+ }
812
+ } else if (faq.type === "details-summary") {
813
+ const detailsMatch = content.match(/<details[^>]*>/);
814
+ if (detailsMatch && detailsMatch.index !== void 0) {
815
+ content = content.slice(0, detailsMatch.index) + `{/* Managed FAQ - content controlled via Portal */}
816
+ ${managedFAQComponent}
817
+ {/* Original FAQ (can be removed once migrated) */}
818
+ ` + content.slice(detailsMatch.index);
819
+ changes.push("Inserted ManagedFAQ component before details/summary FAQ");
820
+ }
821
+ }
822
+ if (!changes.some((c) => c.includes("Inserted ManagedFAQ"))) {
823
+ changes.push(`Add ManagedFAQ to your page JSX: ${managedFAQComponent}`);
824
+ }
825
+ await fs.writeFile(fullPath, content, "utf-8");
826
+ return { filePath, success: true, changes };
827
+ }
828
+ async function migrateSitemap(filePath, sitemap, options) {
829
+ const changes = [];
830
+ const fullPath = path.resolve(process.cwd(), filePath);
831
+ if (options.dryRun) {
832
+ changes.push(`[DRY RUN] Would migrate ${sitemap.type} to Site-Kit sitemap`);
833
+ if (sitemap.type === "next-sitemap-config") {
834
+ changes.push("[DRY RUN] Would update next-sitemap.config.js to use Site-Kit URLs");
835
+ }
836
+ return { filePath, success: true, changes };
837
+ }
838
+ if (sitemap.type === "next-sitemap-config") {
839
+ let content = await fs.readFile(fullPath, "utf-8");
840
+ if (!content.includes("Site-Kit")) {
841
+ content = `/**
842
+ * Site-Kit Integration
843
+ *
844
+ * Pages are automatically synced to Portal SEO module.
845
+ * Manage URLs, priorities, and change frequencies in the Portal.
846
+ */
847
+ ` + content;
848
+ }
849
+ await fs.writeFile(fullPath, content, "utf-8");
850
+ changes.push("Added Site-Kit integration comment to sitemap config");
851
+ changes.push("Configure sitemap settings in Portal SEO module for centralized management");
852
+ }
853
+ if (sitemap.type === "custom-sitemap" && filePath.includes("sitemap")) {
854
+ changes.push("Custom sitemap detected - consider using Site-Kit's createSitemap helper");
855
+ changes.push("Import: import { createSitemap } from '@sonordev/site-kit/seo'");
856
+ }
857
+ return { filePath, success: true, changes };
858
+ }
859
+ async function migrateAnalytics(filePath, analytics, options) {
860
+ const changes = [];
861
+ if (options.dryRun) {
862
+ changes.push(`[DRY RUN] Detected ${analytics.type}${analytics.trackingId ? ` (${analytics.trackingId})` : ""}`);
863
+ changes.push("[DRY RUN] Would recommend moving to SiteKitProvider analytics");
864
+ return { filePath, success: true, changes };
865
+ }
866
+ changes.push(`Detected ${analytics.type}${analytics.trackingId ? ` (${analytics.trackingId})` : ""}`);
867
+ changes.push("SiteKitProvider supports analytics integration");
868
+ changes.push("Configure analytics in project settings to consolidate tracking");
869
+ return { filePath, success: true, changes };
870
+ }
871
+ async function migrateFile(filePath, options) {
872
+ const fullPath = path.resolve(filePath);
873
+ const relPath = path.relative(process.cwd(), fullPath);
874
+ const content = await fs.readFile(fullPath, "utf-8");
875
+ const hasFormTag = content.includes("<form") || content.includes("onSubmit");
876
+ const hasWidget = /intercom|crisp|drift|hubspot|zendesk/i.test(content);
877
+ if (!hasFormTag && !hasWidget) {
878
+ return {
879
+ filePath: relPath,
880
+ success: false,
881
+ changes: [],
882
+ error: "No migratable components found in file"
883
+ };
884
+ }
885
+ if (hasWidget) {
886
+ const widgetType = content.toLowerCase().includes("intercom") ? "intercom" : content.toLowerCase().includes("crisp") ? "crisp" : content.toLowerCase().includes("drift") ? "drift" : content.toLowerCase().includes("hubspot") ? "hubspot" : content.toLowerCase().includes("zendesk") ? "zendesk" : "other";
887
+ return migrateWidget(relPath, {
888
+ widgetType}, options);
889
+ }
890
+ const { parse } = await import('@babel/parser');
891
+ const ast = parse(content, {
892
+ sourceType: "module",
893
+ plugins: ["jsx", "typescript"]
894
+ });
895
+ let componentName = "Form";
896
+ const traverse = (await import('@babel/traverse')).default;
897
+ traverse(ast, {
898
+ ExportNamedDeclaration(path2) {
899
+ const decl = path2.node.declaration;
900
+ if (decl && decl.type === "FunctionDeclaration" && decl.id) {
901
+ componentName = decl.id.name;
902
+ path2.stop();
903
+ }
904
+ },
905
+ ExportDefaultDeclaration(path2) {
906
+ const decl = path2.node.declaration;
907
+ if (decl && decl.type === "FunctionDeclaration" && decl.id) {
908
+ componentName = decl.id.name;
909
+ path2.stop();
910
+ }
911
+ }
912
+ });
913
+ const form = {
914
+ filePath: relPath,
915
+ componentName,
916
+ fields: [],
917
+ hasValidation: false,
918
+ formLibrary: "native",
919
+ submitsTo: null,
920
+ complexity: "simple",
921
+ suggestedAction: "auto-migrate",
922
+ startLine: 0,
923
+ endLine: 0
924
+ };
925
+ return migrateForm(form, options);
926
+ }
927
+ function generateSlug(name) {
928
+ return name.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "").replace(/form$/i, "").replace(/-+/g, "-").replace(/-$/, "") || "form";
929
+ }
930
+ function formatName(name) {
931
+ return name.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).trim();
932
+ }
933
+ function formatLabel(name) {
934
+ return name.replace(/([A-Z])/g, " $1").replace(/_/g, " ").replace(/^./, (str) => str.toUpperCase()).trim();
935
+ }
936
+ function mapFieldType(type) {
937
+ const mapping = {
938
+ "text": "text",
939
+ "email": "email",
940
+ "tel": "phone",
941
+ "phone": "phone",
942
+ "number": "number",
943
+ "textarea": "textarea",
944
+ "select": "select",
945
+ "checkbox": "checkbox",
946
+ "radio": "radio",
947
+ "date": "date",
948
+ "file": "file",
949
+ "url": "url",
950
+ "password": "text"
951
+ // Don't use password for managed forms
952
+ };
953
+ return mapping[type] || "text";
954
+ }
955
+ function detectFormType(form) {
956
+ const name = form.componentName.toLowerCase();
957
+ const fields = form.fields.map((f) => f.name.toLowerCase()).join(" ");
958
+ if (name.includes("contact") || fields.includes("message")) return "contact";
959
+ if (name.includes("newsletter") || name.includes("subscribe")) return "newsletter";
960
+ if (name.includes("quote") || name.includes("estimate")) return "prospect";
961
+ if (name.includes("support") || name.includes("help")) return "support";
962
+ if (name.includes("feedback")) return "feedback";
963
+ return "contact";
964
+ }
965
+
966
+ export { migrateAnalytics, migrateFAQ, migrateFile, migrateFiles, migrateMetadata, migrateSchema, migrateSitemap };
967
+ //# sourceMappingURL=chunk-24277A3Q.mjs.map
968
+ //# sourceMappingURL=chunk-24277A3Q.mjs.map