@uptrademedia/site-kit 1.0.28 → 1.0.29

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 (53) hide show
  1. package/dist/{chunk-FRSN2JKU.js → chunk-6NTMCSHP.js} +15 -18
  2. package/dist/chunk-6NTMCSHP.js.map +1 -0
  3. package/dist/{chunk-WMOA3332.js → chunk-FOBATMSH.js} +70 -55
  4. package/dist/chunk-FOBATMSH.js.map +1 -0
  5. package/dist/{chunk-K2PERQLP.mjs → chunk-MLY7AWHG.mjs} +70 -55
  6. package/dist/chunk-MLY7AWHG.mjs.map +1 -0
  7. package/dist/{chunk-HHAJAANV.mjs → chunk-QY7CDW6P.mjs} +189 -34
  8. package/dist/chunk-QY7CDW6P.mjs.map +1 -0
  9. package/dist/{chunk-JOAULVQB.mjs → chunk-WG2SI2UN.mjs} +15 -18
  10. package/dist/chunk-WG2SI2UN.mjs.map +1 -0
  11. package/dist/{chunk-RM4XFDE6.js → chunk-ZGT5ZYQ5.js} +189 -34
  12. package/dist/chunk-ZGT5ZYQ5.js.map +1 -0
  13. package/dist/commerce/index.d.mts +1 -1
  14. package/dist/commerce/index.d.ts +1 -1
  15. package/dist/commerce/index.js +39 -39
  16. package/dist/commerce/index.mjs +1 -1
  17. package/dist/index.d.mts +1 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +39 -35
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +15 -11
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/{routing-D6bSzuw-.d.ts → routing-CHmSC8p0.d.ts} +1 -1
  24. package/dist/{routing-nObgWX16.d.mts → routing-Cy9vtQq8.d.mts} +1 -1
  25. package/dist/seo/index.d.mts +28 -28
  26. package/dist/seo/index.d.ts +28 -28
  27. package/dist/seo/index.js +96 -245
  28. package/dist/seo/index.js.map +1 -1
  29. package/dist/seo/index.mjs +25 -224
  30. package/dist/seo/index.mjs.map +1 -1
  31. package/dist/seo/register-sitemap-cli.js +3 -3
  32. package/dist/seo/register-sitemap-cli.mjs +2 -2
  33. package/dist/seo/server.d.mts +2 -2
  34. package/dist/seo/server.d.ts +2 -2
  35. package/dist/seo/server.js +185 -44
  36. package/dist/seo/server.js.map +1 -1
  37. package/dist/seo/server.mjs +183 -2
  38. package/dist/seo/server.mjs.map +1 -1
  39. package/dist/{api-EXKDAYGB.mjs → server-api-3HJLLZB7.mjs} +3 -3
  40. package/dist/server-api-3HJLLZB7.mjs.map +1 -0
  41. package/dist/{api-HBENRDUH.js → server-api-RM25RPFH.js} +20 -20
  42. package/dist/server-api-RM25RPFH.js.map +1 -0
  43. package/dist/{types-Cb9d3lkc.d.mts → types-CwyWiHtq.d.mts} +22 -11
  44. package/dist/{types-Cb9d3lkc.d.ts → types-CwyWiHtq.d.ts} +22 -11
  45. package/package.json +1 -1
  46. package/dist/api-EXKDAYGB.mjs.map +0 -1
  47. package/dist/api-HBENRDUH.js.map +0 -1
  48. package/dist/chunk-FRSN2JKU.js.map +0 -1
  49. package/dist/chunk-HHAJAANV.mjs.map +0 -1
  50. package/dist/chunk-JOAULVQB.mjs.map +0 -1
  51. package/dist/chunk-K2PERQLP.mjs.map +0 -1
  52. package/dist/chunk-RM4XFDE6.js.map +0 -1
  53. package/dist/chunk-WMOA3332.js.map +0 -1
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var chunkWMOA3332_js = require('./chunk-WMOA3332.js');
3
+ var chunkFOBATMSH_js = require('./chunk-FOBATMSH.js');
4
4
 
5
5
  // src/seo/routing.ts
6
6
  async function getRedirect(options) {
7
- const { projectId, path } = options;
8
- const redirect = await chunkWMOA3332_js.getRedirectData(projectId, path);
7
+ const { path } = options;
8
+ const redirect = await chunkFOBATMSH_js.getRedirectData(path);
9
9
  if (!redirect) {
10
10
  return null;
11
11
  }
@@ -46,27 +46,27 @@ function parseRobotsString(robots) {
46
46
  return directive;
47
47
  }
48
48
  async function getRobotsDirective(options) {
49
- const { projectId, path } = options;
50
- const robotsString = await chunkWMOA3332_js.getRobotsData(projectId, path);
49
+ const { path } = options;
50
+ const robotsString = await chunkFOBATMSH_js.getRobotsData(path);
51
51
  if (!robotsString) {
52
52
  return { index: true, follow: true };
53
53
  }
54
54
  return parseRobotsString(robotsString);
55
55
  }
56
56
  async function generateSitemap(options) {
57
- const { projectId, baseUrl, publishedOnly = true } = options;
58
- const pages = await chunkWMOA3332_js.getSitemapEntries(projectId, { publishedOnly });
57
+ const { baseUrl, publishedOnly = true } = options;
58
+ const pages = await chunkFOBATMSH_js.getSitemapEntries({ publishedOnly });
59
59
  const normalizedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
60
60
  return pages.map((page) => ({
61
61
  path: page.path,
62
62
  url: `${normalizedBase}${page.path}`,
63
- lastmod: page.updated_at,
64
- changefreq: page.sitemap_changefreq || "weekly",
65
- priority: page.sitemap_priority || 0.5
63
+ lastmod: page.lastmod,
64
+ changefreq: page.changefreq || "weekly",
65
+ priority: page.priority ?? 0.5
66
66
  }));
67
67
  }
68
68
  async function registerLocalSitemap(options) {
69
- const { registerSitemap } = await import('./api-HBENRDUH.js');
69
+ const { registerSitemap } = await import('./server-api-RM25RPFH.js');
70
70
  let entries = options.entries || [];
71
71
  if (options.autoDiscover && entries.length === 0) {
72
72
  try {
@@ -86,10 +86,7 @@ async function registerLocalSitemap(options) {
86
86
  return { success: true, created: 0, updated: 0 };
87
87
  }
88
88
  console.log(`[Uptrade] Registering ${entries.length} sitemap entries...`);
89
- const result = await registerSitemap(entries, {
90
- optimize_meta: options.optimize_meta !== false
91
- // Default to true
92
- });
89
+ const result = await registerSitemap(entries);
93
90
  if (result.success) {
94
91
  console.log(`[Uptrade] Sitemap registered: ${result.created} new, ${result.updated} updated`);
95
92
  }
@@ -130,7 +127,7 @@ function discoverNextJsRoutes(appDir, fs, path, basePath = "") {
130
127
  return entries;
131
128
  }
132
129
  async function isIndexable(projectId, path) {
133
- const directive = await getRobotsDirective({ projectId, path });
130
+ const directive = await getRobotsDirective({ path });
134
131
  return directive.index;
135
132
  }
136
133
 
@@ -139,5 +136,5 @@ exports.getRedirect = getRedirect;
139
136
  exports.getRobotsDirective = getRobotsDirective;
140
137
  exports.isIndexable = isIndexable;
141
138
  exports.registerLocalSitemap = registerLocalSitemap;
142
- //# sourceMappingURL=chunk-FRSN2JKU.js.map
143
- //# sourceMappingURL=chunk-FRSN2JKU.js.map
139
+ //# sourceMappingURL=chunk-6NTMCSHP.js.map
140
+ //# sourceMappingURL=chunk-6NTMCSHP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/seo/routing.ts"],"names":["getRedirectData","getRobotsData","getSitemapEntries"],"mappings":"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","file":"chunk-6NTMCSHP.js","sourcesContent":["import { getRedirectData, getRobotsData, getSitemapEntries } from './server-api'\nimport type { \n GetRedirectOptions, \n RedirectResult, \n GetRobotsOptions, \n RobotsDirective,\n GetSitemapEntriesOptions,\n SitemapEntry \n} from './types'\n\n/**\n * Get redirect for a path if one exists\n * \n * Use in Next.js middleware to handle managed redirects\n * \n * @example\n * ```tsx\n * // middleware.ts\n * import { getRedirect } from '@uptrade/seo'\n * \n * export async function middleware(request) {\n * const redirect = await getRedirect({\n * projectId: process.env.UPTRADE_PROJECT_ID!,\n * path: request.nextUrl.pathname\n * })\n * \n * if (redirect) {\n * return NextResponse.redirect(redirect.destination, redirect.statusCode)\n * }\n * }\n * ```\n */\nexport async function getRedirect(\n options: GetRedirectOptions\n): Promise<RedirectResult | null> {\n const { path } = options\n\n const redirect = await getRedirectData(path)\n\n if (!redirect) {\n return null\n }\n\n // Check if expired\n if (redirect.expires_at && new Date(redirect.expires_at) < new Date()) {\n return null\n }\n\n // Determine destination\n const destination = redirect.destination_url || redirect.destination_path\n const isExternal = destination.startsWith('http://') || destination.startsWith('https://')\n\n return {\n destination,\n statusCode: redirect.status_code,\n isExternal,\n }\n}\n\n/**\n * Parse robots directive string into structured object\n */\nfunction parseRobotsString(robots: string): RobotsDirective {\n const directive: RobotsDirective = {\n index: true,\n follow: true,\n }\n\n const parts = robots.toLowerCase().split(',').map(p => p.trim())\n\n for (const part of parts) {\n if (part === 'noindex') directive.index = false\n if (part === 'nofollow') directive.follow = false\n if (part === 'noarchive') directive.noarchive = true\n if (part === 'nosnippet') directive.nosnippet = true\n if (part === 'noimageindex') directive.noimageindex = true\n if (part.startsWith('max-snippet:')) {\n directive.max_snippet = parseInt(part.split(':')[1], 10)\n }\n if (part.startsWith('max-image-preview:')) {\n const value = part.split(':')[1] as 'none' | 'standard' | 'large'\n directive.max_image_preview = value\n }\n if (part.startsWith('max-video-preview:')) {\n directive.max_video_preview = parseInt(part.split(':')[1], 10)\n }\n }\n\n return directive\n}\n\n/**\n * Get robots directive for a page\n * \n * @example\n * ```tsx\n * const robots = await getRobotsDirective({\n * projectId: process.env.UPTRADE_PROJECT_ID!,\n * path: '/private-page'\n * })\n * \n * if (!robots.index) {\n * // Page should not be indexed\n * }\n * ```\n */\nexport async function getRobotsDirective(\n options: GetRobotsOptions\n): Promise<RobotsDirective> {\n const { path } = options\n\n const robotsString = await getRobotsData(path)\n\n if (!robotsString) {\n // Default: index and follow\n return { index: true, follow: true }\n }\n\n return parseRobotsString(robotsString)\n}\n\n/**\n * Get sitemap entries for a project\n * \n * Use in sitemap.ts to generate dynamic sitemap\n * \n * @example\n * ```tsx\n * // app/sitemap.ts\n * import { generateSitemap } from '@uptrade/seo'\n * \n * export default async function sitemap() {\n * return generateSitemap({\n * projectId: process.env.UPTRADE_PROJECT_ID!,\n * baseUrl: 'https://example.com',\n * publishedOnly: true\n * })\n * }\n * ```\n */\nexport async function generateSitemap(\n options: GetSitemapEntriesOptions\n): Promise<SitemapEntry[]> {\n const { baseUrl, publishedOnly = true } = options\n\n const pages = await getSitemapEntries({ publishedOnly })\n\n const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n\n return pages.map((page: { path: string; lastmod?: string; changefreq?: string; priority?: number }) => ({\n path: page.path,\n url: `${normalizedBase}${page.path}`,\n lastmod: page.lastmod,\n changefreq: (page.changefreq || 'weekly') as SitemapEntry['changefreq'],\n priority: page.priority ?? 0.5,\n }))\n}\n\n/**\n * Register local sitemap entries with Uptrade Portal\n * \n * Call this at build time to sync your local routes to seo_pages.\n * This ensures analytics only tracks real pages.\n * \n * After registration, Signal AI will generate optimized meta titles\n * and descriptions for pages that don't have managed meta yet.\n * \n * @example\n * ```ts\n * // scripts/register-sitemap.ts\n * import { registerLocalSitemap } from '@uptrade/seo'\n * \n * // Option 1: Provide entries directly\n * await registerLocalSitemap({\n * entries: [\n * { path: '/', title: 'Home', priority: 1.0 },\n * { path: '/about', title: 'About Us', priority: 0.8 },\n * ]\n * })\n * \n * // Option 2: Auto-discover from Next.js app directory\n * await registerLocalSitemap({ autoDiscover: true })\n * \n * // Option 3: Skip Signal AI meta optimization\n * await registerLocalSitemap({ autoDiscover: true, optimize_meta: false })\n * ```\n */\nexport async function registerLocalSitemap(options: {\n entries?: Array<{\n path: string\n title?: string\n priority?: number\n changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'\n }>\n autoDiscover?: boolean\n /** Trigger Signal AI to generate optimized meta titles/descriptions (default: true) */\n optimize_meta?: boolean\n}): Promise<{ \n success: boolean\n created: number\n updated: number\n removed?: number\n meta_optimization?: {\n triggered: boolean\n pages_queued: number\n } | null\n}> {\n const { registerSitemap } = await import('./server-api')\n \n let entries = options.entries || []\n \n // Auto-discover from Next.js app directory if requested\n if (options.autoDiscover && entries.length === 0) {\n try {\n const fs = await import('fs')\n const path = await import('path')\n \n const appDir = path.join(process.cwd(), 'app')\n if (fs.existsSync(appDir)) {\n entries = discoverNextJsRoutes(appDir, fs, path)\n console.log(`[Uptrade] Auto-discovered ${entries.length} routes from app directory`)\n }\n } catch (error) {\n console.error('[Uptrade] Auto-discovery failed:', error)\n }\n }\n \n if (entries.length === 0) {\n console.warn('[Uptrade] No sitemap entries to register')\n return { success: true, created: 0, updated: 0 }\n }\n \n console.log(`[Uptrade] Registering ${entries.length} sitemap entries...`)\n const result = await registerSitemap(entries)\n \n if (result.success) {\n console.log(`[Uptrade] Sitemap registered: ${result.created} new, ${result.updated} updated`)\n }\n \n return result\n}\n\n/**\n * Discover routes from Next.js app directory\n */\nfunction discoverNextJsRoutes(\n appDir: string,\n fs: typeof import('fs'),\n path: typeof import('path'),\n basePath: string = ''\n): Array<{ path: string; priority: number }> {\n const entries: Array<{ path: string; priority: number }> = []\n \n const items = fs.readdirSync(appDir, { withFileTypes: true })\n \n for (const item of items) {\n // Skip private folders, api routes, and special files\n if (item.name.startsWith('_') || item.name.startsWith('.')) continue\n if (item.name === 'api') continue\n if (item.name === 'node_modules') continue\n \n const itemPath = path.join(appDir, item.name)\n \n if (item.isDirectory()) {\n // Check for page.tsx/page.js in this directory\n const hasPage = fs.existsSync(path.join(itemPath, 'page.tsx')) ||\n fs.existsSync(path.join(itemPath, 'page.js')) ||\n fs.existsSync(path.join(itemPath, 'page.jsx'))\n \n // Handle route groups (parentheses)\n const isRouteGroup = item.name.startsWith('(') && item.name.endsWith(')')\n \n // Handle dynamic segments [slug]\n const isDynamic = item.name.startsWith('[') && item.name.endsWith(']')\n \n let routePath = basePath\n if (!isRouteGroup && !isDynamic) {\n routePath = `${basePath}/${item.name}`\n }\n \n if (hasPage && !isDynamic) {\n const priority = routePath === '' ? 1.0 : 0.8\n entries.push({ path: routePath || '/', priority })\n }\n \n // Recurse into subdirectories (but not dynamic ones)\n if (!isDynamic) {\n const subEntries = discoverNextJsRoutes(itemPath, fs, path, isRouteGroup ? basePath : routePath)\n entries.push(...subEntries)\n }\n }\n }\n \n // Add root if app/page.tsx exists and we're at root\n if (basePath === '') {\n const hasRootPage = fs.existsSync(path.join(appDir, 'page.tsx')) ||\n fs.existsSync(path.join(appDir, 'page.js')) ||\n fs.existsSync(path.join(appDir, 'page.jsx'))\n if (hasRootPage) {\n entries.unshift({ path: '/', priority: 1.0 })\n }\n }\n \n return entries\n}\n\n/**\n * Check if a path should be indexed\n * \n * Quick helper to check indexability without full directive parsing\n */\nexport async function isIndexable(\n projectId: string,\n path: string\n): Promise<boolean> {\n const directive = await getRobotsDirective({ projectId, path })\n return directive.index\n}\n"]}
@@ -1,24 +1,23 @@
1
1
  'use strict';
2
2
 
3
3
  var react = require('react');
4
+ require('server-only');
4
5
 
5
- // src/seo/api.ts
6
- if (process.env.NODE_ENV === "development") {
7
- console.warn(
8
- "@uptrade/seo: WARNING - You are using the deprecated api.ts which exposes API keys. Please migrate to server-api.ts for better security. See: packages/site-kit/src/seo/README.md#migration"
9
- );
10
- }
11
- function getApiConfig() {
6
+ // src/seo/server-api.ts
7
+ function getSecureApiConfig() {
12
8
  const apiUrl = process.env.UPTRADE_API_URL || process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com";
13
9
  const apiKey = process.env.UPTRADE_API_KEY || process.env.NEXT_PUBLIC_UPTRADE_API_KEY || "";
14
- return { apiUrl, apiKey };
15
- }
16
- async function apiPost(endpoint, body = {}) {
17
- const { apiUrl, apiKey } = getApiConfig();
18
10
  if (!apiKey) {
19
- console.error("@uptrade/seo: No API key configured. Set UPTRADE_API_KEY.");
20
- return null;
11
+ throw new Error("@uptrade/seo: UPTRADE_API_KEY or NEXT_PUBLIC_UPTRADE_API_KEY environment variable is required for server-side SEO functions");
21
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();
22
21
  try {
23
22
  const response = await fetch(`${apiUrl}${endpoint}`, {
24
23
  method: "POST",
@@ -31,7 +30,13 @@ async function apiPost(endpoint, body = {}) {
31
30
  // Cache for 60 seconds
32
31
  });
33
32
  if (!response.ok) {
34
- console.error(`@uptrade/seo: API error: ${response.statusText}`);
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(`@uptrade/seo: API error ${response.status} ${endpoint}: ${detail}`);
35
40
  return null;
36
41
  }
37
42
  return await response.json();
@@ -40,68 +45,67 @@ async function apiPost(endpoint, body = {}) {
40
45
  return null;
41
46
  }
42
47
  }
43
- var getSEOPageData = react.cache(async (projectId, path) => {
44
- const result = await apiPost("/api/public/seo/page", { path });
45
- return result?.page || null;
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
+ };
46
54
  });
47
- var getSchemaMarkups = react.cache(async (projectId, path, options) => {
48
- const result = await apiPost("/api/public/seo/schemas", {
55
+ var getSchemaMarkups = react.cache(async (path, options) => {
56
+ const result = await secureApiPost("/api/public/seo/schemas", {
49
57
  path,
50
58
  includeTypes: options?.includeTypes,
51
59
  excludeTypes: options?.excludeTypes
52
60
  });
53
61
  return result?.schemas || [];
54
62
  });
55
- var getFAQData = react.cache(async (projectId, path) => {
56
- const result = await apiPost("/api/public/seo/faq", { path });
63
+ var getFAQData = react.cache(async (path) => {
64
+ const result = await secureApiPost("/api/public/seo/faq", { path });
57
65
  return result?.faq || null;
58
66
  });
59
- var getInternalLinks = react.cache(async (projectId, sourcePath, options) => {
60
- const result = await apiPost("/api/public/seo/internal-links", {
67
+ var getInternalLinks = react.cache(async (sourcePath, options) => {
68
+ const result = await secureApiPost("/api/public/seo/internal-links", {
61
69
  sourcePath,
62
70
  position: options?.position,
63
71
  limit: options?.limit
64
72
  });
65
73
  return result?.links || [];
66
74
  });
67
- var getContentBlock = react.cache(async (projectId, path, section) => {
68
- const result = await apiPost("/api/public/seo/content", { path, section });
75
+ var getContentBlock = react.cache(async (path, section) => {
76
+ const result = await secureApiPost("/api/public/seo/content", { path, section });
69
77
  return result?.content || null;
70
78
  });
71
- var getABTest = react.cache(async (projectId, path, field) => {
72
- const result = await apiPost("/api/public/seo/ab-test", { path, field });
79
+ var getABTest = react.cache(async (path, field) => {
80
+ const result = await secureApiPost("/api/public/seo/ab-test", { path, field });
73
81
  return result?.test || null;
74
82
  });
75
83
  async function recordABImpression(testId, variant, sessionId) {
76
- await apiPost("/api/public/seo/ab-impression", { testId, variant, sessionId });
84
+ await secureApiPost("/api/public/seo/ab-impression", { testId, variant, sessionId });
77
85
  }
78
- var getRedirectData = react.cache(async (projectId, path) => {
79
- const result = await apiPost("/api/public/seo/redirect", { path });
86
+ var getRedirectData = react.cache(async (path) => {
87
+ const result = await secureApiPost("/api/public/seo/redirect", { path });
80
88
  return result?.redirect || null;
81
89
  });
82
- var getManagedScripts = react.cache(async (projectId, position, currentPath) => {
83
- const result = await apiPost("/api/public/seo/scripts", {
90
+ var getManagedScripts = react.cache(async (position, currentPath) => {
91
+ const result = await secureApiPost("/api/public/seo/scripts", {
84
92
  position,
85
93
  currentPath
86
94
  });
87
95
  return result?.scripts || [];
88
96
  });
89
- var getRobotsData = react.cache(async (projectId, path) => {
90
- const result = await apiPost("/api/public/seo/page", { path });
97
+ var getRobotsData = react.cache(async (path) => {
98
+ const result = await secureApiPost("/api/public/seo/page", { path });
91
99
  return result?.page?.managed_robots || null;
92
100
  });
93
- var getSitemapEntries = react.cache(async (projectId, options) => {
94
- const result = await apiPost("/api/public/seo/sitemap", {
101
+ var getSitemapEntries = react.cache(async (options) => {
102
+ const result = await secureApiPost("/api/public/seo/sitemap", {
95
103
  publishedOnly: options?.publishedOnly
96
104
  });
97
105
  return result?.entries || [];
98
106
  });
99
- async function registerSitemap(entries, options) {
100
- const { apiUrl, apiKey } = getApiConfig();
101
- if (!apiKey) {
102
- console.error("@uptrade/seo: No API key configured. Set UPTRADE_API_KEY.");
103
- return { success: false, created: 0, updated: 0 };
104
- }
107
+ async function registerSitemap(entries) {
108
+ const { apiUrl, apiKey } = getSecureApiConfig();
105
109
  try {
106
110
  const response = await fetch(`${apiUrl}/api/public/seo/register-sitemap`, {
107
111
  method: "POST",
@@ -109,11 +113,7 @@ async function registerSitemap(entries, options) {
109
113
  "Content-Type": "application/json",
110
114
  "x-api-key": apiKey
111
115
  },
112
- body: JSON.stringify({
113
- entries,
114
- optimize_meta: options?.optimize_meta !== false
115
- // Default to true
116
- })
116
+ body: JSON.stringify({ entries })
117
117
  });
118
118
  if (!response.ok) {
119
119
  console.error(`@uptrade/seo: Sitemap registration failed: ${response.statusText}`);
@@ -127,7 +127,7 @@ async function registerSitemap(entries, options) {
127
127
  }
128
128
  function getSignalApiConfig() {
129
129
  const apiUrl = process.env.SIGNAL_API_URL || process.env.NEXT_PUBLIC_SIGNAL_API_URL || "https://signal.uptrademedia.com";
130
- const apiKey = process.env.UPTRADE_API_KEY || process.env.NEXT_PUBLIC_UPTRADE_API_KEY || "";
130
+ const apiKey = process.env.UPTRADE_API_KEY || "";
131
131
  return { apiUrl, apiKey };
132
132
  }
133
133
  async function signalApiGet(endpoint) {
@@ -155,7 +155,10 @@ async function signalApiGet(endpoint) {
155
155
  return null;
156
156
  }
157
157
  }
158
- var getEntities = react.cache(async (projectId, options) => {
158
+ var getEntities = react.cache(async (options) => {
159
+ const { apiKey } = getSecureApiConfig();
160
+ const projectId = getProjectIdFromKey(apiKey);
161
+ if (!projectId) return [];
159
162
  let endpoint = `/skills/seo/entities/${projectId}`;
160
163
  if (options?.type) {
161
164
  endpoint += `?type=${options.type}`;
@@ -163,21 +166,33 @@ var getEntities = react.cache(async (projectId, options) => {
163
166
  const result = await signalApiGet(endpoint);
164
167
  return result || [];
165
168
  });
166
- var getPrimaryEntity = react.cache(async (projectId) => {
169
+ var getPrimaryEntity = react.cache(async () => {
170
+ const { apiKey } = getSecureApiConfig();
171
+ const projectId = getProjectIdFromKey(apiKey);
172
+ if (!projectId) return null;
167
173
  return signalApiGet(`/skills/seo/entities/${projectId}/primary`);
168
174
  });
169
- var getEntityEnhancedSchema = react.cache(async (projectId, pagePath) => {
175
+ var getEntityEnhancedSchema = react.cache(async (pagePath) => {
176
+ const { apiKey } = getSecureApiConfig();
177
+ const projectId = getProjectIdFromKey(apiKey);
178
+ if (!projectId) return [];
170
179
  const result = await signalApiGet(
171
180
  `/skills/seo/schema/${projectId}/entity-enhanced?pagePath=${encodeURIComponent(pagePath)}`
172
181
  );
173
182
  return result?.schemas || [];
174
183
  });
175
- var getVisibilityScore = react.cache(async (projectId, pagePath) => {
184
+ var getVisibilityScore = react.cache(async (pagePath) => {
185
+ const { apiKey } = getSecureApiConfig();
186
+ const projectId = getProjectIdFromKey(apiKey);
187
+ if (!projectId) return null;
176
188
  const result = await signalApiGet(`/skills/seo/visibility/${projectId}`);
177
189
  if (!result) return null;
178
190
  return result.find((s) => s.page_path === pagePath) || null;
179
191
  });
180
- var getVisibilitySummary = react.cache(async (projectId) => {
192
+ var getVisibilitySummary = react.cache(async () => {
193
+ const { apiKey } = getSecureApiConfig();
194
+ const projectId = getProjectIdFromKey(apiKey);
195
+ if (!projectId) return null;
181
196
  return signalApiGet(`/skills/seo/visibility/${projectId}/summary`);
182
197
  });
183
198
 
@@ -198,5 +213,5 @@ exports.getVisibilityScore = getVisibilityScore;
198
213
  exports.getVisibilitySummary = getVisibilitySummary;
199
214
  exports.recordABImpression = recordABImpression;
200
215
  exports.registerSitemap = registerSitemap;
201
- //# sourceMappingURL=chunk-WMOA3332.js.map
202
- //# sourceMappingURL=chunk-WMOA3332.js.map
216
+ //# sourceMappingURL=chunk-FOBATMSH.js.map
217
+ //# sourceMappingURL=chunk-FOBATMSH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/seo/server-api.ts"],"names":["cache"],"mappings":"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","file":"chunk-FOBATMSH.js","sourcesContent":["/**\n * @uptrade/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('@uptrade/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(`@uptrade/seo: API error ${response.status} ${endpoint}: ${detail}`)\n return null\n }\n\n return await response.json()\n } catch (error) {\n console.error('@uptrade/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(`@uptrade/seo: API error ${response.status}: ${response.statusText}`)\n return null\n }\n \n return await response.json()\n } catch (error) {\n console.error('@uptrade/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 '@uptrade/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(`@uptrade/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('@uptrade/seo: Sitemap registration error:', error)\n return { success: false, created: 0, updated: 0 }\n }\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('@uptrade/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"]}
@@ -1,22 +1,21 @@
1
1
  import { cache } from 'react';
2
+ import 'server-only';
2
3
 
3
- // src/seo/api.ts
4
- if (process.env.NODE_ENV === "development") {
5
- console.warn(
6
- "@uptrade/seo: WARNING - You are using the deprecated api.ts which exposes API keys. Please migrate to server-api.ts for better security. See: packages/site-kit/src/seo/README.md#migration"
7
- );
8
- }
9
- function getApiConfig() {
4
+ // src/seo/server-api.ts
5
+ function getSecureApiConfig() {
10
6
  const apiUrl = process.env.UPTRADE_API_URL || process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com";
11
7
  const apiKey = process.env.UPTRADE_API_KEY || process.env.NEXT_PUBLIC_UPTRADE_API_KEY || "";
12
- return { apiUrl, apiKey };
13
- }
14
- async function apiPost(endpoint, body = {}) {
15
- const { apiUrl, apiKey } = getApiConfig();
16
8
  if (!apiKey) {
17
- console.error("@uptrade/seo: No API key configured. Set UPTRADE_API_KEY.");
18
- return null;
9
+ throw new Error("@uptrade/seo: UPTRADE_API_KEY or NEXT_PUBLIC_UPTRADE_API_KEY environment variable is required for server-side SEO functions");
19
10
  }
11
+ return { apiUrl, apiKey };
12
+ }
13
+ function getProjectIdFromKey(apiKey) {
14
+ const match = apiKey.match(/^uptrade_([0-9a-f-]{36})_/);
15
+ return match ? match[1] : null;
16
+ }
17
+ async function secureApiPost(endpoint, body = {}) {
18
+ const { apiUrl, apiKey } = getSecureApiConfig();
20
19
  try {
21
20
  const response = await fetch(`${apiUrl}${endpoint}`, {
22
21
  method: "POST",
@@ -29,7 +28,13 @@ async function apiPost(endpoint, body = {}) {
29
28
  // Cache for 60 seconds
30
29
  });
31
30
  if (!response.ok) {
32
- console.error(`@uptrade/seo: API error: ${response.statusText}`);
31
+ let detail = response.statusText;
32
+ try {
33
+ const err = await response.json().catch(() => ({}));
34
+ if (err?.message) detail = err.message;
35
+ } catch {
36
+ }
37
+ console.error(`@uptrade/seo: API error ${response.status} ${endpoint}: ${detail}`);
33
38
  return null;
34
39
  }
35
40
  return await response.json();
@@ -38,68 +43,67 @@ async function apiPost(endpoint, body = {}) {
38
43
  return null;
39
44
  }
40
45
  }
41
- var getSEOPageData = cache(async (projectId, path) => {
42
- const result = await apiPost("/api/public/seo/page", { path });
43
- return result?.page || null;
46
+ var getSEOPageData = cache(async (path) => {
47
+ const result = await secureApiPost("/api/public/seo/page", { path });
48
+ return {
49
+ page: result?.page || null,
50
+ project: result?.project || null
51
+ };
44
52
  });
45
- var getSchemaMarkups = cache(async (projectId, path, options) => {
46
- const result = await apiPost("/api/public/seo/schemas", {
53
+ var getSchemaMarkups = cache(async (path, options) => {
54
+ const result = await secureApiPost("/api/public/seo/schemas", {
47
55
  path,
48
56
  includeTypes: options?.includeTypes,
49
57
  excludeTypes: options?.excludeTypes
50
58
  });
51
59
  return result?.schemas || [];
52
60
  });
53
- var getFAQData = cache(async (projectId, path) => {
54
- const result = await apiPost("/api/public/seo/faq", { path });
61
+ var getFAQData = cache(async (path) => {
62
+ const result = await secureApiPost("/api/public/seo/faq", { path });
55
63
  return result?.faq || null;
56
64
  });
57
- var getInternalLinks = cache(async (projectId, sourcePath, options) => {
58
- const result = await apiPost("/api/public/seo/internal-links", {
65
+ var getInternalLinks = cache(async (sourcePath, options) => {
66
+ const result = await secureApiPost("/api/public/seo/internal-links", {
59
67
  sourcePath,
60
68
  position: options?.position,
61
69
  limit: options?.limit
62
70
  });
63
71
  return result?.links || [];
64
72
  });
65
- var getContentBlock = cache(async (projectId, path, section) => {
66
- const result = await apiPost("/api/public/seo/content", { path, section });
73
+ var getContentBlock = cache(async (path, section) => {
74
+ const result = await secureApiPost("/api/public/seo/content", { path, section });
67
75
  return result?.content || null;
68
76
  });
69
- var getABTest = cache(async (projectId, path, field) => {
70
- const result = await apiPost("/api/public/seo/ab-test", { path, field });
77
+ var getABTest = cache(async (path, field) => {
78
+ const result = await secureApiPost("/api/public/seo/ab-test", { path, field });
71
79
  return result?.test || null;
72
80
  });
73
81
  async function recordABImpression(testId, variant, sessionId) {
74
- await apiPost("/api/public/seo/ab-impression", { testId, variant, sessionId });
82
+ await secureApiPost("/api/public/seo/ab-impression", { testId, variant, sessionId });
75
83
  }
76
- var getRedirectData = cache(async (projectId, path) => {
77
- const result = await apiPost("/api/public/seo/redirect", { path });
84
+ var getRedirectData = cache(async (path) => {
85
+ const result = await secureApiPost("/api/public/seo/redirect", { path });
78
86
  return result?.redirect || null;
79
87
  });
80
- var getManagedScripts = cache(async (projectId, position, currentPath) => {
81
- const result = await apiPost("/api/public/seo/scripts", {
88
+ var getManagedScripts = cache(async (position, currentPath) => {
89
+ const result = await secureApiPost("/api/public/seo/scripts", {
82
90
  position,
83
91
  currentPath
84
92
  });
85
93
  return result?.scripts || [];
86
94
  });
87
- var getRobotsData = cache(async (projectId, path) => {
88
- const result = await apiPost("/api/public/seo/page", { path });
95
+ var getRobotsData = cache(async (path) => {
96
+ const result = await secureApiPost("/api/public/seo/page", { path });
89
97
  return result?.page?.managed_robots || null;
90
98
  });
91
- var getSitemapEntries = cache(async (projectId, options) => {
92
- const result = await apiPost("/api/public/seo/sitemap", {
99
+ var getSitemapEntries = cache(async (options) => {
100
+ const result = await secureApiPost("/api/public/seo/sitemap", {
93
101
  publishedOnly: options?.publishedOnly
94
102
  });
95
103
  return result?.entries || [];
96
104
  });
97
- async function registerSitemap(entries, options) {
98
- const { apiUrl, apiKey } = getApiConfig();
99
- if (!apiKey) {
100
- console.error("@uptrade/seo: No API key configured. Set UPTRADE_API_KEY.");
101
- return { success: false, created: 0, updated: 0 };
102
- }
105
+ async function registerSitemap(entries) {
106
+ const { apiUrl, apiKey } = getSecureApiConfig();
103
107
  try {
104
108
  const response = await fetch(`${apiUrl}/api/public/seo/register-sitemap`, {
105
109
  method: "POST",
@@ -107,11 +111,7 @@ async function registerSitemap(entries, options) {
107
111
  "Content-Type": "application/json",
108
112
  "x-api-key": apiKey
109
113
  },
110
- body: JSON.stringify({
111
- entries,
112
- optimize_meta: options?.optimize_meta !== false
113
- // Default to true
114
- })
114
+ body: JSON.stringify({ entries })
115
115
  });
116
116
  if (!response.ok) {
117
117
  console.error(`@uptrade/seo: Sitemap registration failed: ${response.statusText}`);
@@ -125,7 +125,7 @@ async function registerSitemap(entries, options) {
125
125
  }
126
126
  function getSignalApiConfig() {
127
127
  const apiUrl = process.env.SIGNAL_API_URL || process.env.NEXT_PUBLIC_SIGNAL_API_URL || "https://signal.uptrademedia.com";
128
- const apiKey = process.env.UPTRADE_API_KEY || process.env.NEXT_PUBLIC_UPTRADE_API_KEY || "";
128
+ const apiKey = process.env.UPTRADE_API_KEY || "";
129
129
  return { apiUrl, apiKey };
130
130
  }
131
131
  async function signalApiGet(endpoint) {
@@ -153,7 +153,10 @@ async function signalApiGet(endpoint) {
153
153
  return null;
154
154
  }
155
155
  }
156
- var getEntities = cache(async (projectId, options) => {
156
+ var getEntities = cache(async (options) => {
157
+ const { apiKey } = getSecureApiConfig();
158
+ const projectId = getProjectIdFromKey(apiKey);
159
+ if (!projectId) return [];
157
160
  let endpoint = `/skills/seo/entities/${projectId}`;
158
161
  if (options?.type) {
159
162
  endpoint += `?type=${options.type}`;
@@ -161,24 +164,36 @@ var getEntities = cache(async (projectId, options) => {
161
164
  const result = await signalApiGet(endpoint);
162
165
  return result || [];
163
166
  });
164
- var getPrimaryEntity = cache(async (projectId) => {
167
+ var getPrimaryEntity = cache(async () => {
168
+ const { apiKey } = getSecureApiConfig();
169
+ const projectId = getProjectIdFromKey(apiKey);
170
+ if (!projectId) return null;
165
171
  return signalApiGet(`/skills/seo/entities/${projectId}/primary`);
166
172
  });
167
- var getEntityEnhancedSchema = cache(async (projectId, pagePath) => {
173
+ var getEntityEnhancedSchema = cache(async (pagePath) => {
174
+ const { apiKey } = getSecureApiConfig();
175
+ const projectId = getProjectIdFromKey(apiKey);
176
+ if (!projectId) return [];
168
177
  const result = await signalApiGet(
169
178
  `/skills/seo/schema/${projectId}/entity-enhanced?pagePath=${encodeURIComponent(pagePath)}`
170
179
  );
171
180
  return result?.schemas || [];
172
181
  });
173
- var getVisibilityScore = cache(async (projectId, pagePath) => {
182
+ var getVisibilityScore = cache(async (pagePath) => {
183
+ const { apiKey } = getSecureApiConfig();
184
+ const projectId = getProjectIdFromKey(apiKey);
185
+ if (!projectId) return null;
174
186
  const result = await signalApiGet(`/skills/seo/visibility/${projectId}`);
175
187
  if (!result) return null;
176
188
  return result.find((s) => s.page_path === pagePath) || null;
177
189
  });
178
- var getVisibilitySummary = cache(async (projectId) => {
190
+ var getVisibilitySummary = cache(async () => {
191
+ const { apiKey } = getSecureApiConfig();
192
+ const projectId = getProjectIdFromKey(apiKey);
193
+ if (!projectId) return null;
179
194
  return signalApiGet(`/skills/seo/visibility/${projectId}/summary`);
180
195
  });
181
196
 
182
197
  export { getABTest, getContentBlock, getEntities, getEntityEnhancedSchema, getFAQData, getInternalLinks, getManagedScripts, getPrimaryEntity, getRedirectData, getRobotsData, getSEOPageData, getSchemaMarkups, getSitemapEntries, getVisibilityScore, getVisibilitySummary, recordABImpression, registerSitemap };
183
- //# sourceMappingURL=chunk-K2PERQLP.mjs.map
184
- //# sourceMappingURL=chunk-K2PERQLP.mjs.map
198
+ //# sourceMappingURL=chunk-MLY7AWHG.mjs.map
199
+ //# sourceMappingURL=chunk-MLY7AWHG.mjs.map