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