@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,341 @@
1
+ import { NextResponse } from 'next/server';
2
+
3
+ // src/setup/api-handlers.ts
4
+ var PORTAL_URL = process.env.UPTRADE_PORTAL_URL || "https://portal.uptrademedia.com";
5
+ var API_URL = process.env.UPTRADE_API_URL || "https://api.uptrademedia.com";
6
+ var authSession = {};
7
+ async function handleStatus() {
8
+ const configured = !!(process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID && process.env.NEXT_PUBLIC_SUPABASE_URL);
9
+ return NextResponse.json({
10
+ configured,
11
+ authenticated: !!authSession.accessToken,
12
+ email: authSession.email
13
+ });
14
+ }
15
+ async function handleAuthStart() {
16
+ const state = Math.random().toString(36).substring(7);
17
+ const redirectUri = "http://localhost:3000/_uptrade/api/auth/callback";
18
+ const authUrl = `${PORTAL_URL}/auth/cli?` + new URLSearchParams({
19
+ redirect_uri: redirectUri,
20
+ state
21
+ });
22
+ return NextResponse.json({ authUrl, state });
23
+ }
24
+ async function handleAuthCallback(req) {
25
+ const { searchParams } = new URL(req.url);
26
+ const code = searchParams.get("code");
27
+ const error = searchParams.get("error");
28
+ if (error) {
29
+ return new NextResponse(errorHtml("Authentication Failed", error), {
30
+ headers: { "Content-Type": "text/html" }
31
+ });
32
+ }
33
+ if (!code) {
34
+ return new NextResponse(errorHtml("Missing Code", "No authorization code received"), {
35
+ headers: { "Content-Type": "text/html" }
36
+ });
37
+ }
38
+ try {
39
+ const tokenResponse = await fetch(`${API_URL}/auth/cli-token`, {
40
+ method: "POST",
41
+ headers: { "Content-Type": "application/json" },
42
+ body: JSON.stringify({
43
+ code,
44
+ redirect_uri: "http://localhost:3000/_uptrade/api/auth/callback"
45
+ })
46
+ });
47
+ if (!tokenResponse.ok) {
48
+ throw new Error("Failed to exchange code for token");
49
+ }
50
+ const { access_token, user_id, email } = await tokenResponse.json();
51
+ authSession = {
52
+ accessToken: access_token,
53
+ userId: user_id,
54
+ email
55
+ };
56
+ return new NextResponse(successHtml(), {
57
+ headers: { "Content-Type": "text/html" }
58
+ });
59
+ } catch (err) {
60
+ return new NextResponse(errorHtml("Token Exchange Failed", err.message), {
61
+ headers: { "Content-Type": "text/html" }
62
+ });
63
+ }
64
+ }
65
+ async function handleAuthStatus() {
66
+ return NextResponse.json({
67
+ authenticated: !!authSession.accessToken,
68
+ email: authSession.email
69
+ });
70
+ }
71
+ async function handleApiKeyAuth(req) {
72
+ const { apiKey } = await req.json();
73
+ try {
74
+ const response = await fetch(`${API_URL}/auth/verify-api-key`, {
75
+ headers: { "Authorization": `Bearer ${apiKey}` }
76
+ });
77
+ if (!response.ok) {
78
+ return NextResponse.json({ error: "Invalid API key" }, { status: 401 });
79
+ }
80
+ const { user_id, email } = await response.json();
81
+ authSession = {
82
+ accessToken: apiKey,
83
+ userId: user_id,
84
+ email
85
+ };
86
+ return NextResponse.json({ email });
87
+ } catch {
88
+ return NextResponse.json({ error: "Authentication failed" }, { status: 500 });
89
+ }
90
+ }
91
+ async function handleGetOrganizations() {
92
+ if (!authSession.accessToken) {
93
+ return NextResponse.json({ error: "Not authenticated" }, { status: 401 });
94
+ }
95
+ try {
96
+ const response = await fetch(`${API_URL}/organizations`, {
97
+ headers: { "Authorization": `Bearer ${authSession.accessToken}` }
98
+ });
99
+ if (!response.ok) {
100
+ throw new Error("Failed to fetch organizations");
101
+ }
102
+ const organizations = await response.json();
103
+ return NextResponse.json({ organizations });
104
+ } catch (err) {
105
+ return NextResponse.json({ error: err.message }, { status: 500 });
106
+ }
107
+ }
108
+ async function handleCreateProject(req) {
109
+ if (!authSession.accessToken) {
110
+ return NextResponse.json({ error: "Not authenticated" }, { status: 401 });
111
+ }
112
+ const { orgId, name, domain } = await req.json();
113
+ try {
114
+ const response = await fetch(`${API_URL}/organizations/${orgId}/projects`, {
115
+ method: "POST",
116
+ headers: {
117
+ "Authorization": `Bearer ${authSession.accessToken}`,
118
+ "Content-Type": "application/json"
119
+ },
120
+ body: JSON.stringify({ name, domain })
121
+ });
122
+ if (!response.ok) {
123
+ throw new Error("Failed to create project");
124
+ }
125
+ const project = await response.json();
126
+ return NextResponse.json(project);
127
+ } catch (err) {
128
+ return NextResponse.json({ error: err.message }, { status: 500 });
129
+ }
130
+ }
131
+ async function handleScan() {
132
+ const { scanCodebase } = await import('./scanner-LKJKW7IT.mjs');
133
+ try {
134
+ const results = await scanCodebase(process.cwd());
135
+ return NextResponse.json({
136
+ forms: results.forms.map((f) => ({
137
+ type: "form",
138
+ form_library: f.formLibrary,
139
+ file: f.filePath,
140
+ component_name: f.componentName,
141
+ line: f.startLine,
142
+ fields: f.fields,
143
+ complexity: f.complexity,
144
+ suggested_action: f.suggestedAction,
145
+ has_validation: f.hasValidation,
146
+ submits_to: f.submitsTo
147
+ })),
148
+ widgets: results.widgets.map((w) => ({
149
+ type: "widget",
150
+ widget_type: w.widgetType,
151
+ file: w.filePath,
152
+ line: w.startLine
153
+ })),
154
+ metadata: results.metadata.map((m) => ({
155
+ type: "metadata",
156
+ metadata_type: m.type,
157
+ file: m.filePath,
158
+ title: m.title,
159
+ description: m.description
160
+ })),
161
+ sitemaps: results.sitemaps.map((s) => ({
162
+ type: "sitemap",
163
+ sitemap_type: s.type,
164
+ file: s.filePath,
165
+ line: s.startLine,
166
+ generator: s.generator
167
+ }))
168
+ });
169
+ } catch (err) {
170
+ return NextResponse.json({ error: err.message }, { status: 500 });
171
+ }
172
+ }
173
+ async function handleMigrate(req) {
174
+ if (!authSession.accessToken) {
175
+ return NextResponse.json({ error: "Not authenticated" }, { status: 401 });
176
+ }
177
+ const { item, projectId } = await req.json();
178
+ const { migrateFiles } = await import('./migrator-2MQHOFDQ.mjs');
179
+ try {
180
+ const scanResults = {
181
+ forms: [item],
182
+ metadata: [],
183
+ widgets: [],
184
+ sitemaps: [],
185
+ schemas: [],
186
+ faqs: [],
187
+ analytics: [],
188
+ images: []
189
+ };
190
+ const options = { projectId, apiKey: authSession.accessToken || "" };
191
+ await migrateFiles(scanResults, options);
192
+ return NextResponse.json({ success: true });
193
+ } catch (err) {
194
+ return NextResponse.json({ error: err.message }, { status: 500 });
195
+ }
196
+ }
197
+ async function handleConfigure(req) {
198
+ if (!authSession.accessToken) {
199
+ return NextResponse.json({ error: "Not authenticated" }, { status: 401 });
200
+ }
201
+ const { projectId } = await req.json();
202
+ const { generateEnvFile, generateProvider } = await import('./generators-2XKQMPKH.mjs');
203
+ try {
204
+ const configResponse = await fetch(`${API_URL}/projects/${projectId}/config`, {
205
+ headers: { "Authorization": `Bearer ${authSession.accessToken}` }
206
+ });
207
+ if (!configResponse.ok) {
208
+ throw new Error("Failed to fetch project config");
209
+ }
210
+ const config = await configResponse.json();
211
+ const keyResponse = await fetch(`${API_URL}/projects/${projectId}/api-keys`, {
212
+ method: "POST",
213
+ headers: {
214
+ "Authorization": `Bearer ${authSession.accessToken}`,
215
+ "Content-Type": "application/json"
216
+ },
217
+ body: JSON.stringify({ name: "Site-Kit Setup" })
218
+ });
219
+ let apiKey = "ut_xxx";
220
+ if (keyResponse.ok) {
221
+ const keyData = await keyResponse.json();
222
+ apiKey = keyData.key;
223
+ }
224
+ await generateEnvFile({
225
+ projectId,
226
+ supabaseUrl: config.supabase_url,
227
+ supabaseAnonKey: config.supabase_anon_key,
228
+ apiKey
229
+ });
230
+ await generateProvider({ projectId });
231
+ return NextResponse.json({ success: true });
232
+ } catch (err) {
233
+ return NextResponse.json({ error: err.message }, { status: 500 });
234
+ }
235
+ }
236
+ async function handleSelfDestruct() {
237
+ const { selfDestruct } = await import('./generators-2XKQMPKH.mjs');
238
+ try {
239
+ await selfDestruct();
240
+ return NextResponse.json({ success: true });
241
+ } catch (err) {
242
+ return NextResponse.json({ error: err.message }, { status: 500 });
243
+ }
244
+ }
245
+ function successHtml() {
246
+ return `<!DOCTYPE html>
247
+ <html>
248
+ <head>
249
+ <title>Uptrade - Authenticated</title>
250
+ <style>
251
+ body {
252
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
253
+ display: flex; justify-content: center; align-items: center;
254
+ height: 100vh; margin: 0;
255
+ background: linear-gradient(135deg, #1a1a2e 0%, #0f0f1a 100%);
256
+ color: white;
257
+ }
258
+ .container {
259
+ text-align: center; padding: 3rem;
260
+ background: rgba(255, 255, 255, 0.05);
261
+ border-radius: 1rem; border: 1px solid rgba(255, 255, 255, 0.1);
262
+ }
263
+ .icon { font-size: 4rem; margin-bottom: 1rem; }
264
+ h1 { margin: 0 0 0.5rem; }
265
+ p { color: rgba(255, 255, 255, 0.7); margin: 0; }
266
+ </style>
267
+ <script>setTimeout(() => window.close(), 2000)</script>
268
+ </head>
269
+ <body>
270
+ <div class="container">
271
+ <div class="icon">\u2713</div>
272
+ <h1>Authenticated!</h1>
273
+ <p>This window will close automatically...</p>
274
+ </div>
275
+ </body>
276
+ </html>`;
277
+ }
278
+ function errorHtml(title, message) {
279
+ return `<!DOCTYPE html>
280
+ <html>
281
+ <head>
282
+ <title>Uptrade - Error</title>
283
+ <style>
284
+ body {
285
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
286
+ display: flex; justify-content: center; align-items: center;
287
+ height: 100vh; margin: 0;
288
+ background: linear-gradient(135deg, #2e1a1a 0%, #1a0f0f 100%);
289
+ color: white;
290
+ }
291
+ .container {
292
+ text-align: center; padding: 3rem;
293
+ background: rgba(255, 255, 255, 0.05);
294
+ border-radius: 1rem; border: 1px solid rgba(255, 100, 100, 0.2);
295
+ }
296
+ .icon { font-size: 4rem; margin-bottom: 1rem; }
297
+ h1 { margin: 0 0 0.5rem; color: #ff6b6b; }
298
+ p { color: rgba(255, 255, 255, 0.7); margin: 0; }
299
+ </style>
300
+ </head>
301
+ <body>
302
+ <div class="container">
303
+ <div class="icon">\u2717</div>
304
+ <h1>${title}</h1>
305
+ <p>${message}</p>
306
+ </div>
307
+ </body>
308
+ </html>`;
309
+ }
310
+ async function handleRequest(req, route) {
311
+ switch (route) {
312
+ case "status":
313
+ return handleStatus();
314
+ case "auth/start":
315
+ return handleAuthStart();
316
+ case "auth/callback":
317
+ return handleAuthCallback(req);
318
+ case "auth/status":
319
+ return handleAuthStatus();
320
+ case "auth/apikey":
321
+ return handleApiKeyAuth(req);
322
+ case "organizations":
323
+ return handleGetOrganizations();
324
+ case "projects":
325
+ return handleCreateProject(req);
326
+ case "scan":
327
+ return handleScan();
328
+ case "migrate":
329
+ return handleMigrate(req);
330
+ case "configure":
331
+ return handleConfigure(req);
332
+ case "self-destruct":
333
+ return handleSelfDestruct();
334
+ default:
335
+ return NextResponse.json({ error: "Not found" }, { status: 404 });
336
+ }
337
+ }
338
+
339
+ export { handleRequest };
340
+ //# sourceMappingURL=chunk-DQYMKR27.mjs.map
341
+ //# sourceMappingURL=chunk-DQYMKR27.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/setup/api-handlers.ts"],"names":[],"mappings":"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","file":"chunk-DQYMKR27.mjs","sourcesContent":["/**\n * Setup Wizard API Handlers\n * \n * These are Next.js API route handlers that the SetupWizard component calls.\n * They run on the server and have access to fs for code generation.\n * \n * Usage: Copy these to your app/_uptrade/api/ folder\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\n\n// ============================================\n// Configuration\n// ============================================\n\nconst PORTAL_URL = process.env.UPTRADE_PORTAL_URL || 'https://portal.uptrademedia.com'\nconst API_URL = process.env.UPTRADE_API_URL || 'https://api.uptrademedia.com'\n\n// In-memory session store (for dev server only)\nlet authSession: {\n accessToken?: string\n userId?: string\n email?: string\n pendingCode?: string\n} = {}\n\n// ============================================\n// Status Handler\n// ============================================\n\nexport async function handleStatus(): Promise<NextResponse> {\n const configured = !!(\n process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID &&\n process.env.NEXT_PUBLIC_SUPABASE_URL\n )\n\n return NextResponse.json({\n configured,\n authenticated: !!authSession.accessToken,\n email: authSession.email\n })\n}\n\n// ============================================\n// Auth Handlers\n// ============================================\n\nexport async function handleAuthStart(): Promise<NextResponse> {\n const state = Math.random().toString(36).substring(7)\n const redirectUri = 'http://localhost:3000/_uptrade/api/auth/callback'\n \n const authUrl = `${PORTAL_URL}/auth/cli?` + new URLSearchParams({\n redirect_uri: redirectUri,\n state\n })\n\n return NextResponse.json({ authUrl, state })\n}\n\nexport async function handleAuthCallback(req: NextRequest): Promise<NextResponse> {\n const { searchParams } = new URL(req.url)\n const code = searchParams.get('code')\n const error = searchParams.get('error')\n\n if (error) {\n return new NextResponse(errorHtml('Authentication Failed', error), {\n headers: { 'Content-Type': 'text/html' }\n })\n }\n\n if (!code) {\n return new NextResponse(errorHtml('Missing Code', 'No authorization code received'), {\n headers: { 'Content-Type': 'text/html' }\n })\n }\n\n try {\n // Exchange code for token\n const tokenResponse = await fetch(`${API_URL}/auth/cli-token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n code,\n redirect_uri: 'http://localhost:3000/_uptrade/api/auth/callback'\n })\n })\n\n if (!tokenResponse.ok) {\n throw new Error('Failed to exchange code for token')\n }\n\n const { access_token, user_id, email } = await tokenResponse.json()\n \n authSession = {\n accessToken: access_token,\n userId: user_id,\n email\n }\n\n return new NextResponse(successHtml(), {\n headers: { 'Content-Type': 'text/html' }\n })\n } catch (err) {\n return new NextResponse(errorHtml('Token Exchange Failed', (err as Error).message), {\n headers: { 'Content-Type': 'text/html' }\n })\n }\n}\n\nexport async function handleAuthStatus(): Promise<NextResponse> {\n return NextResponse.json({\n authenticated: !!authSession.accessToken,\n email: authSession.email\n })\n}\n\nexport async function handleApiKeyAuth(req: NextRequest): Promise<NextResponse> {\n const { apiKey } = await req.json()\n\n try {\n const response = await fetch(`${API_URL}/auth/verify-api-key`, {\n headers: { 'Authorization': `Bearer ${apiKey}` }\n })\n\n if (!response.ok) {\n return NextResponse.json({ error: 'Invalid API key' }, { status: 401 })\n }\n\n const { user_id, email } = await response.json()\n \n authSession = {\n accessToken: apiKey,\n userId: user_id,\n email\n }\n\n return NextResponse.json({ email })\n } catch {\n return NextResponse.json({ error: 'Authentication failed' }, { status: 500 })\n }\n}\n\n// ============================================\n// Organization & Project Handlers\n// ============================================\n\nexport async function handleGetOrganizations(): Promise<NextResponse> {\n if (!authSession.accessToken) {\n return NextResponse.json({ error: 'Not authenticated' }, { status: 401 })\n }\n\n try {\n const response = await fetch(`${API_URL}/organizations`, {\n headers: { 'Authorization': `Bearer ${authSession.accessToken}` }\n })\n\n if (!response.ok) {\n throw new Error('Failed to fetch organizations')\n }\n\n const organizations = await response.json()\n return NextResponse.json({ organizations })\n } catch (err) {\n return NextResponse.json({ error: (err as Error).message }, { status: 500 })\n }\n}\n\nexport async function handleCreateProject(req: NextRequest): Promise<NextResponse> {\n if (!authSession.accessToken) {\n return NextResponse.json({ error: 'Not authenticated' }, { status: 401 })\n }\n\n const { orgId, name, domain } = await req.json()\n\n try {\n const response = await fetch(`${API_URL}/organizations/${orgId}/projects`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${authSession.accessToken}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ name, domain })\n })\n\n if (!response.ok) {\n throw new Error('Failed to create project')\n }\n\n const project = await response.json()\n return NextResponse.json(project)\n } catch (err) {\n return NextResponse.json({ error: (err as Error).message }, { status: 500 })\n }\n}\n\n// ============================================\n// Scan Handler\n// ============================================\n\nexport async function handleScan(): Promise<NextResponse> {\n const { scanCodebase } = await import('../cli/scanner')\n \n try {\n const results = await scanCodebase(process.cwd())\n \n return NextResponse.json({\n forms: results.forms.map(f => ({\n type: 'form',\n form_library: f.formLibrary,\n file: f.filePath,\n component_name: f.componentName,\n line: f.startLine,\n fields: f.fields,\n complexity: f.complexity,\n suggested_action: f.suggestedAction,\n has_validation: f.hasValidation,\n submits_to: f.submitsTo,\n })),\n widgets: results.widgets.map(w => ({\n type: 'widget',\n widget_type: w.widgetType,\n file: w.filePath,\n line: w.startLine,\n })),\n metadata: results.metadata.map(m => ({\n type: 'metadata',\n metadata_type: m.type,\n file: m.filePath,\n title: m.title,\n description: m.description,\n })),\n sitemaps: results.sitemaps.map(s => ({\n type: 'sitemap',\n sitemap_type: s.type,\n file: s.filePath,\n line: s.startLine,\n generator: s.generator,\n })),\n })\n } catch (err) {\n return NextResponse.json({ error: (err as Error).message }, { status: 500 })\n }\n}\n\n// ============================================\n// Migrate Handler\n// ============================================\n\nexport async function handleMigrate(req: NextRequest): Promise<NextResponse> {\n if (!authSession.accessToken) {\n return NextResponse.json({ error: 'Not authenticated' }, { status: 401 })\n }\n\n const { item, projectId } = await req.json()\n const { migrateFiles } = await import('../cli/migrator')\n\n try {\n // Wrap item into ScanResults format\n const scanResults = { \n forms: [item], \n metadata: [], \n widgets: [], \n sitemaps: [],\n schemas: [],\n faqs: [],\n analytics: [],\n images: [],\n }\n const options = { projectId, apiKey: authSession.accessToken || '' }\n await migrateFiles(scanResults, options)\n return NextResponse.json({ success: true })\n } catch (err) {\n return NextResponse.json({ error: (err as Error).message }, { status: 500 })\n }\n}\n\n// ============================================\n// Configure Handler\n// ============================================\n\nexport async function handleConfigure(req: NextRequest): Promise<NextResponse> {\n if (!authSession.accessToken) {\n return NextResponse.json({ error: 'Not authenticated' }, { status: 401 })\n }\n\n const { projectId } = await req.json()\n const { generateEnvFile, generateProvider } = await import('../cli/generators')\n\n try {\n // Get Supabase config from API\n const configResponse = await fetch(`${API_URL}/projects/${projectId}/config`, {\n headers: { 'Authorization': `Bearer ${authSession.accessToken}` }\n })\n\n if (!configResponse.ok) {\n throw new Error('Failed to fetch project config')\n }\n\n const config = await configResponse.json()\n\n // Generate API key\n const keyResponse = await fetch(`${API_URL}/projects/${projectId}/api-keys`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${authSession.accessToken}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ name: 'Site-Kit Setup' })\n })\n\n let apiKey = 'ut_xxx'\n if (keyResponse.ok) {\n const keyData = await keyResponse.json()\n // Portal API returns { key: string, apiKey: {...} }\n apiKey = keyData.key\n }\n\n // Generate env file\n await generateEnvFile({\n projectId,\n supabaseUrl: config.supabase_url,\n supabaseAnonKey: config.supabase_anon_key,\n apiKey\n })\n\n // Generate provider in layout\n await generateProvider({ projectId })\n\n return NextResponse.json({ success: true })\n } catch (err) {\n return NextResponse.json({ error: (err as Error).message }, { status: 500 })\n }\n}\n\n// ============================================\n// Self-Destruct Handler\n// ============================================\n\nexport async function handleSelfDestruct(): Promise<NextResponse> {\n const { selfDestruct } = await import('../cli/generators')\n\n try {\n await selfDestruct()\n return NextResponse.json({ success: true })\n } catch (err) {\n return NextResponse.json({ error: (err as Error).message }, { status: 500 })\n }\n}\n\n// ============================================\n// HTML Templates\n// ============================================\n\nfunction successHtml(): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n <title>Uptrade - Authenticated</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex; justify-content: center; align-items: center;\n height: 100vh; margin: 0;\n background: linear-gradient(135deg, #1a1a2e 0%, #0f0f1a 100%);\n color: white;\n }\n .container {\n text-align: center; padding: 3rem;\n background: rgba(255, 255, 255, 0.05);\n border-radius: 1rem; border: 1px solid rgba(255, 255, 255, 0.1);\n }\n .icon { font-size: 4rem; margin-bottom: 1rem; }\n h1 { margin: 0 0 0.5rem; }\n p { color: rgba(255, 255, 255, 0.7); margin: 0; }\n </style>\n <script>setTimeout(() => window.close(), 2000)</script>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"icon\">✓</div>\n <h1>Authenticated!</h1>\n <p>This window will close automatically...</p>\n </div>\n</body>\n</html>`\n}\n\nfunction errorHtml(title: string, message: string): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n <title>Uptrade - Error</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex; justify-content: center; align-items: center;\n height: 100vh; margin: 0;\n background: linear-gradient(135deg, #2e1a1a 0%, #1a0f0f 100%);\n color: white;\n }\n .container {\n text-align: center; padding: 3rem;\n background: rgba(255, 255, 255, 0.05);\n border-radius: 1rem; border: 1px solid rgba(255, 100, 100, 0.2);\n }\n .icon { font-size: 4rem; margin-bottom: 1rem; }\n h1 { margin: 0 0 0.5rem; color: #ff6b6b; }\n p { color: rgba(255, 255, 255, 0.7); margin: 0; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"icon\">✗</div>\n <h1>${title}</h1>\n <p>${message}</p>\n </div>\n</body>\n</html>`\n}\n\n// ============================================\n// Unified Route Handler\n// ============================================\n\nexport async function handleRequest(\n req: NextRequest,\n route: string\n): Promise<NextResponse> {\n switch (route) {\n case 'status':\n return handleStatus()\n case 'auth/start':\n return handleAuthStart()\n case 'auth/callback':\n return handleAuthCallback(req)\n case 'auth/status':\n return handleAuthStatus()\n case 'auth/apikey':\n return handleApiKeyAuth(req)\n case 'organizations':\n return handleGetOrganizations()\n case 'projects':\n return handleCreateProject(req)\n case 'scan':\n return handleScan()\n case 'migrate':\n return handleMigrate(req)\n case 'configure':\n return handleConfigure(req)\n case 'self-destruct':\n return handleSelfDestruct()\n default:\n return NextResponse.json({ error: 'Not found' }, { status: 404 })\n }\n}\n"]}
@@ -0,0 +1,221 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ require('server-only');
5
+
6
+ // src/seo/server-api.ts
7
+ function getSecureApiConfig() {
8
+ const apiUrl = process.env.UPTRADE_API_URL || process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com";
9
+ const apiKey = process.env.UPTRADE_API_KEY || process.env.NEXT_PUBLIC_UPTRADE_API_KEY || "";
10
+ if (!apiKey) {
11
+ throw new Error("@sonordev/seo: UPTRADE_API_KEY or NEXT_PUBLIC_UPTRADE_API_KEY environment variable is required for server-side SEO functions");
12
+ }
13
+ return { apiUrl, apiKey };
14
+ }
15
+ function getProjectIdFromKey(apiKey) {
16
+ const match = apiKey.match(/^uptrade_([0-9a-f-]{36})_/);
17
+ return match ? match[1] : null;
18
+ }
19
+ async function secureApiPost(endpoint, body = {}) {
20
+ const { apiUrl, apiKey } = getSecureApiConfig();
21
+ try {
22
+ const response = await fetch(`${apiUrl}${endpoint}`, {
23
+ method: "POST",
24
+ headers: {
25
+ "Content-Type": "application/json",
26
+ "x-api-key": apiKey
27
+ },
28
+ body: JSON.stringify(body),
29
+ next: { revalidate: 60 }
30
+ // Cache for 60 seconds
31
+ });
32
+ if (!response.ok) {
33
+ let detail = response.statusText;
34
+ try {
35
+ const err = await response.json().catch(() => ({}));
36
+ if (err?.message) detail = err.message;
37
+ } catch {
38
+ }
39
+ console.error(`@sonordev/seo: API error ${response.status} ${endpoint}: ${detail}`);
40
+ return null;
41
+ }
42
+ return await response.json();
43
+ } catch (error) {
44
+ console.error("@sonordev/seo: Network error:", error);
45
+ return null;
46
+ }
47
+ }
48
+ var getSEOPageData = react.cache(async (path) => {
49
+ const result = await secureApiPost("/api/public/seo/page", { path });
50
+ return {
51
+ page: result?.page || null,
52
+ project: result?.project || null
53
+ };
54
+ });
55
+ var getSchemaMarkups = react.cache(async (path, options) => {
56
+ const result = await secureApiPost("/api/public/seo/schemas", {
57
+ path,
58
+ includeTypes: options?.includeTypes,
59
+ excludeTypes: options?.excludeTypes
60
+ });
61
+ return result?.schemas || [];
62
+ });
63
+ var getFAQData = react.cache(async (path) => {
64
+ const result = await secureApiPost("/api/public/seo/faq", { path });
65
+ return result?.faq || null;
66
+ });
67
+ var getInternalLinks = react.cache(async (sourcePath, options) => {
68
+ const result = await secureApiPost("/api/public/seo/internal-links", {
69
+ sourcePath,
70
+ position: options?.position,
71
+ limit: options?.limit
72
+ });
73
+ return result?.links || [];
74
+ });
75
+ var getContentBlock = react.cache(async (path, section) => {
76
+ const result = await secureApiPost("/api/public/seo/content", { path, section });
77
+ return result?.content || null;
78
+ });
79
+ var getABTest = react.cache(async (path, field) => {
80
+ const result = await secureApiPost("/api/public/seo/ab-test", { path, field });
81
+ return result?.test || null;
82
+ });
83
+ async function recordABImpression(testId, variant, sessionId) {
84
+ await secureApiPost("/api/public/seo/ab-impression", { testId, variant, sessionId });
85
+ }
86
+ var getRedirectData = react.cache(async (path) => {
87
+ const result = await secureApiPost("/api/public/seo/redirect", { path });
88
+ return result?.redirect || null;
89
+ });
90
+ var getManagedScripts = react.cache(async (position, currentPath) => {
91
+ const result = await secureApiPost("/api/public/seo/scripts", {
92
+ position,
93
+ currentPath
94
+ });
95
+ return result?.scripts || [];
96
+ });
97
+ var getRobotsData = react.cache(async (path) => {
98
+ const result = await secureApiPost("/api/public/seo/page", { path });
99
+ return result?.page?.managed_robots || null;
100
+ });
101
+ var getSitemapEntries = react.cache(async (options) => {
102
+ const result = await secureApiPost("/api/public/seo/sitemap", {
103
+ publishedOnly: options?.publishedOnly
104
+ });
105
+ return result?.entries || [];
106
+ });
107
+ async function registerSitemap(entries) {
108
+ const { apiUrl, apiKey } = getSecureApiConfig();
109
+ try {
110
+ const response = await fetch(`${apiUrl}/api/public/seo/register-sitemap`, {
111
+ method: "POST",
112
+ headers: {
113
+ "Content-Type": "application/json",
114
+ "x-api-key": apiKey
115
+ },
116
+ body: JSON.stringify({ entries })
117
+ });
118
+ if (!response.ok) {
119
+ console.error(`@sonordev/seo: Sitemap registration failed: ${response.statusText}`);
120
+ return { success: false, created: 0, updated: 0 };
121
+ }
122
+ return await response.json();
123
+ } catch (error) {
124
+ console.error("@sonordev/seo: Sitemap registration error:", error);
125
+ return { success: false, created: 0, updated: 0 };
126
+ }
127
+ }
128
+ var ensureMetadata = react.cache(async (path) => {
129
+ return secureApiPost("/api/public/seo/ensure-metadata", { path });
130
+ });
131
+ function getSignalApiConfig() {
132
+ const apiUrl = process.env.SIGNAL_API_URL || process.env.NEXT_PUBLIC_SIGNAL_API_URL || "https://signal.uptrademedia.com";
133
+ const apiKey = process.env.UPTRADE_API_KEY || "";
134
+ return { apiUrl, apiKey };
135
+ }
136
+ async function signalApiGet(endpoint) {
137
+ const { apiUrl, apiKey } = getSignalApiConfig();
138
+ if (!apiKey) {
139
+ return null;
140
+ }
141
+ try {
142
+ const response = await fetch(`${apiUrl}${endpoint}`, {
143
+ method: "GET",
144
+ headers: {
145
+ "Content-Type": "application/json",
146
+ "x-api-key": apiKey
147
+ },
148
+ next: { revalidate: 300 }
149
+ // Cache for 5 minutes
150
+ });
151
+ if (!response.ok) {
152
+ return null;
153
+ }
154
+ const result = await response.json();
155
+ return result?.data || result;
156
+ } catch (error) {
157
+ console.error("@sonordev/seo: Signal API error:", error);
158
+ return null;
159
+ }
160
+ }
161
+ var getEntities = react.cache(async (options) => {
162
+ const { apiKey } = getSecureApiConfig();
163
+ const projectId = getProjectIdFromKey(apiKey);
164
+ if (!projectId) return [];
165
+ let endpoint = `/skills/seo/entities/${projectId}`;
166
+ if (options?.type) {
167
+ endpoint += `?type=${options.type}`;
168
+ }
169
+ const result = await signalApiGet(endpoint);
170
+ return result || [];
171
+ });
172
+ var getPrimaryEntity = react.cache(async () => {
173
+ const { apiKey } = getSecureApiConfig();
174
+ const projectId = getProjectIdFromKey(apiKey);
175
+ if (!projectId) return null;
176
+ return signalApiGet(`/skills/seo/entities/${projectId}/primary`);
177
+ });
178
+ var getEntityEnhancedSchema = react.cache(async (pagePath) => {
179
+ const { apiKey } = getSecureApiConfig();
180
+ const projectId = getProjectIdFromKey(apiKey);
181
+ if (!projectId) return [];
182
+ const result = await signalApiGet(
183
+ `/skills/seo/schema/${projectId}/entity-enhanced?pagePath=${encodeURIComponent(pagePath)}`
184
+ );
185
+ return result?.schemas || [];
186
+ });
187
+ var getVisibilityScore = react.cache(async (pagePath) => {
188
+ const { apiKey } = getSecureApiConfig();
189
+ const projectId = getProjectIdFromKey(apiKey);
190
+ if (!projectId) return null;
191
+ const result = await signalApiGet(`/skills/seo/visibility/${projectId}`);
192
+ if (!result) return null;
193
+ return result.find((s) => s.page_path === pagePath) || null;
194
+ });
195
+ var getVisibilitySummary = react.cache(async () => {
196
+ const { apiKey } = getSecureApiConfig();
197
+ const projectId = getProjectIdFromKey(apiKey);
198
+ if (!projectId) return null;
199
+ return signalApiGet(`/skills/seo/visibility/${projectId}/summary`);
200
+ });
201
+
202
+ exports.ensureMetadata = ensureMetadata;
203
+ exports.getABTest = getABTest;
204
+ exports.getContentBlock = getContentBlock;
205
+ exports.getEntities = getEntities;
206
+ exports.getEntityEnhancedSchema = getEntityEnhancedSchema;
207
+ exports.getFAQData = getFAQData;
208
+ exports.getInternalLinks = getInternalLinks;
209
+ exports.getManagedScripts = getManagedScripts;
210
+ exports.getPrimaryEntity = getPrimaryEntity;
211
+ exports.getRedirectData = getRedirectData;
212
+ exports.getRobotsData = getRobotsData;
213
+ exports.getSEOPageData = getSEOPageData;
214
+ exports.getSchemaMarkups = getSchemaMarkups;
215
+ exports.getSitemapEntries = getSitemapEntries;
216
+ exports.getVisibilityScore = getVisibilityScore;
217
+ exports.getVisibilitySummary = getVisibilitySummary;
218
+ exports.recordABImpression = recordABImpression;
219
+ exports.registerSitemap = registerSitemap;
220
+ //# sourceMappingURL=chunk-DW5UJKHH.js.map
221
+ //# sourceMappingURL=chunk-DW5UJKHH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/seo/server-api.ts"],"names":["cache"],"mappings":"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","file":"chunk-DW5UJKHH.js","sourcesContent":["/**\n * @sonordev/site-kit/seo - Server-Only API Functions\n * \n * SECURITY: These functions use private environment variables\n * and should ONLY be imported in server-side code (RSC, API routes, server actions).\n * \n * DO NOT import this file in client components or it will expose API keys.\n */\n\nimport { cache } from 'react'\nimport 'server-only' // This ensures the module can only be imported server-side\n\n// ============================================\n// Server-Only API Config\n// ============================================\n\n/**\n * Config for portal API calls. Project is resolved by the portal from the API key;\n * sites never send or read project ID.\n */\nfunction getSecureApiConfig() {\n const apiUrl = process.env.UPTRADE_API_URL || process.env.NEXT_PUBLIC_UPTRADE_API_URL || 'https://api.uptrademedia.com'\n const apiKey = process.env.UPTRADE_API_KEY || process.env.NEXT_PUBLIC_UPTRADE_API_KEY || ''\n\n if (!apiKey) {\n throw new Error('@sonordev/seo: UPTRADE_API_KEY or NEXT_PUBLIC_UPTRADE_API_KEY environment variable is required for server-side SEO functions')\n }\n\n return { apiUrl, apiKey }\n}\n\n/** Derive project ID from API key for Signal API only (format: uptrade_{uuid}_{secret}). Not used for portal. */\nfunction getProjectIdFromKey(apiKey: string): string | null {\n const match = apiKey.match(/^uptrade_([0-9a-f-]{36})_/)\n return match ? match[1] : null\n}\n\nasync function secureApiPost<T>(endpoint: string, body: Record<string, any> = {}): Promise<T | null> {\n const { apiUrl, apiKey } = getSecureApiConfig()\n\n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify(body),\n next: { revalidate: 60 }, // Cache for 60 seconds\n })\n\n if (!response.ok) {\n let detail = response.statusText\n try {\n const err = await response.json().catch(() => ({}))\n if (err?.message) detail = err.message\n } catch {\n /* ignore */\n }\n console.error(`@sonordev/seo: API error ${response.status} ${endpoint}: ${detail}`)\n return null\n }\n\n return await response.json()\n } catch (error) {\n console.error('@sonordev/seo: Network error:', error)\n return null\n }\n}\n\nasync function secureApiGet<T>(endpoint: string): Promise<T | null> {\n const { apiUrl, apiKey } = getSecureApiConfig()\n \n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n next: { revalidate: 60 },\n })\n \n if (!response.ok) {\n console.error(`@sonordev/seo: API error ${response.status}: ${response.statusText}`)\n return null\n }\n \n return await response.json()\n } catch (error) {\n console.error('@sonordev/seo: Network error:', error)\n return null\n }\n}\n\n// ============================================\n// Secure Cached Data Fetchers\n// ============================================\n\n/**\n * Fetch SEO page data - cached per request\n * @server-only\n */\nexport const getSEOPageData = cache(async (path: string) => {\n const result = await secureApiPost<{ page: any; project: any }>('/api/public/seo/page', { path })\n return {\n page: result?.page || null,\n project: result?.project || null,\n }\n})\n\n/**\n * Fetch schema markups for a page - cached per request\n * @server-only\n */\nexport const getSchemaMarkups = cache(async (\n path: string,\n options?: { includeTypes?: string[]; excludeTypes?: string[] }\n) => {\n const result = await secureApiPost<{ schemas: any[] }>('/api/public/seo/schemas', {\n path,\n includeTypes: options?.includeTypes,\n excludeTypes: options?.excludeTypes,\n })\n return result?.schemas || []\n})\n\n/**\n * Fetch FAQ data for a page - cached per request\n * @server-only\n */\nexport const getFAQData = cache(async (path: string) => {\n const result = await secureApiPost<{ faq: any }>('/api/public/seo/faq', { path })\n return result?.faq || null\n})\n\n/**\n * Fetch internal links for a page - cached per request\n * @server-only\n */\nexport const getInternalLinks = cache(async (\n sourcePath: string,\n options?: { position?: string; limit?: number }\n) => {\n const result = await secureApiPost<{ links: any[] }>('/api/public/seo/internal-links', {\n sourcePath,\n position: options?.position,\n limit: options?.limit,\n })\n return result?.links || []\n})\n\n/**\n * Fetch content block - cached per request\n * @server-only\n */\nexport const getContentBlock = cache(async (path: string, section: string) => {\n const result = await secureApiPost<{ content: any }>('/api/public/seo/content', { path, section })\n return result?.content || null\n})\n\n/**\n * Fetch A/B test and determine variant - cached per request\n * @server-only\n */\nexport const getABTest = cache(async (path: string, field: string) => {\n const result = await secureApiPost<{ test: any }>('/api/public/seo/ab-test', { path, field })\n return result?.test || null\n})\n\n/**\n * Record A/B test impression\n * @server-only\n */\nexport async function recordABImpression(\n testId: string,\n variant: 'a' | 'b',\n sessionId?: string\n): Promise<void> {\n await secureApiPost('/api/public/seo/ab-impression', { testId, variant, sessionId })\n}\n\n/**\n * Fetch redirect for a path - cached per request\n * @server-only\n */\nexport const getRedirectData = cache(async (path: string) => {\n const result = await secureApiPost<{ redirect: any }>('/api/public/seo/redirect', { path })\n return result?.redirect || null\n})\n\n/**\n * Fetch managed scripts - cached per request\n * @server-only\n */\nexport const getManagedScripts = cache(async (position: string, currentPath?: string) => {\n const result = await secureApiPost<{ scripts: any[] }>('/api/public/seo/scripts', {\n position,\n currentPath,\n })\n return result?.scripts || []\n})\n\n/**\n * Fetch robots directive for a page - cached per request\n * @server-only\n */\nexport const getRobotsData = cache(async (path: string) => {\n const result = await secureApiPost<{ page: any }>('/api/public/seo/page', { path })\n return result?.page?.managed_robots || null\n})\n\n/**\n * Fetch sitemap entries - cached per request\n * @server-only\n */\nexport const getSitemapEntries = cache(async (options?: { publishedOnly?: boolean }) => {\n const result = await secureApiPost<{ entries: any[] }>('/api/public/seo/sitemap', {\n publishedOnly: options?.publishedOnly,\n })\n return result?.entries || []\n})\n\n/**\n * Register/sync sitemap entries from the client site\n * Call this at build time to populate seo_pages from your sitemap.xml\n * @server-only\n * \n * @example\n * ```ts\n * // scripts/register-sitemap.ts (run at build time)\n * import { registerSitemap } from '@sonordev/seo/server'\n * \n * await registerSitemap([\n * { path: '/', priority: 1.0, changefreq: 'daily' },\n * { path: '/about', priority: 0.8, changefreq: 'weekly' },\n * ])\n * ```\n */\nexport async function registerSitemap(\n entries: Array<{\n path: string\n title?: string\n priority?: number\n changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'\n }>\n): Promise<{ success: boolean; created: number; updated: number }> {\n const { apiUrl, apiKey } = getSecureApiConfig()\n\n try {\n const response = await fetch(`${apiUrl}/api/public/seo/register-sitemap`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify({ entries }),\n })\n \n if (!response.ok) {\n console.error(`@sonordev/seo: Sitemap registration failed: ${response.statusText}`)\n return { success: false, created: 0, updated: 0 }\n }\n \n return await response.json()\n } catch (error) {\n console.error('@sonordev/seo: Sitemap registration error:', error)\n return { success: false, created: 0, updated: 0 }\n }\n}\n\n// ============================================\n// Signal-Powered Metadata Fallback\n// ============================================\n\n/**\n * Ensure metadata exists for a page by triggering Signal AI optimization.\n * If the page has no managed_title or managed_meta_description, Signal will\n * generate them and save to the database via Portal proxy.\n *\n * Idempotent — returns existing metadata if already populated.\n * @server-only\n */\nexport const ensureMetadata = cache(async (path: string): Promise<{\n managed_title?: string\n managed_meta_description?: string\n managed_keywords?: string[]\n managed_schema?: Record<string, unknown>\n} | null> => {\n return secureApiPost('/api/public/seo/ensure-metadata', { path })\n})\n\n// ============================================\n// AI Visibility & Entity Graph API (Signal)\n// ============================================\n\nfunction getSignalApiConfig() {\n const apiUrl = process.env.SIGNAL_API_URL || process.env.NEXT_PUBLIC_SIGNAL_API_URL || 'https://signal.uptrademedia.com'\n const apiKey = process.env.UPTRADE_API_KEY || ''\n return { apiUrl, apiKey }\n}\n\nasync function signalApiGet<T>(endpoint: string): Promise<T | null> {\n const { apiUrl, apiKey } = getSignalApiConfig()\n \n if (!apiKey) {\n return null\n }\n \n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n next: { revalidate: 300 }, // Cache for 5 minutes\n })\n \n if (!response.ok) {\n return null\n }\n \n const result = await response.json()\n return result?.data || result\n } catch (error) {\n console.error('@sonordev/seo: Signal API error:', error)\n return null\n }\n}\n\n/**\n * Entity types for the knowledge graph\n */\nexport type EntityType = \n | 'organization'\n | 'person'\n | 'service'\n | 'product'\n | 'location'\n | 'concept'\n | 'credential'\n\n/**\n * Entity from the knowledge graph\n */\nexport interface SEOEntity {\n id: string\n project_id: string\n entity_type: EntityType\n name: string\n slug: string\n properties: Record<string, unknown>\n knows_about: string[]\n same_as: string[]\n schema_type?: string\n is_primary: boolean\n}\n\n/**\n * Fetch entities for a project - cached per request\n * Returns the entity graph for enhanced schema markup\n * @server-only\n */\nexport const getEntities = cache(async (\n options?: { type?: EntityType }\n): Promise<SEOEntity[]> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return []\n let endpoint = `/skills/seo/entities/${projectId}`\n if (options?.type) {\n endpoint += `?type=${options.type}`\n }\n const result = await signalApiGet<SEOEntity[]>(endpoint)\n return result || []\n})\n\n/**\n * Fetch primary entity (the business) - cached per request\n * @server-only\n */\nexport const getPrimaryEntity = cache(async (): Promise<SEOEntity | null> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return null\n return signalApiGet<SEOEntity>(`/skills/seo/entities/${projectId}/primary`)\n})\n\n/**\n * Fetch entity-enhanced schema for a page\n * Returns Organization schema with knowsAbout, areaServed, employee, etc.\n * @server-only\n */\nexport const getEntityEnhancedSchema = cache(async (pagePath: string): Promise<object[]> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return []\n const result = await signalApiGet<{ schemas: object[] }>(\n `/skills/seo/schema/${projectId}/entity-enhanced?pagePath=${encodeURIComponent(pagePath)}`\n )\n return result?.schemas || []\n})\n\n/**\n * Get AI visibility score for a page\n * @server-only\n */\nexport const getVisibilityScore = cache(async (\n pagePath: string\n): Promise<{\n overall_score: number\n entity_coverage: number\n answer_density: number\n chunk_readability: number\n authority_signals: number\n schema_completeness: number\n} | null> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return null\n const result = await signalApiGet<any[]>(`/skills/seo/visibility/${projectId}`)\n if (!result) return null\n return result.find(s => s.page_path === pagePath) || null\n})\n\n/**\n * Get AI visibility summary for project\n * @server-only\n */\nexport const getVisibilitySummary = cache(async (): Promise<{\n overall_score: number\n total_entities: number\n pages_analyzed: number\n top_recommendations: Array<{ priority: string; type: string; message: string }>\n} | null> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return null\n return signalApiGet(`/skills/seo/visibility/${projectId}/summary`)\n})\n"]}