@brainfish-ai/devdoc 0.1.49 → 0.1.50

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.
@@ -1,12 +1,18 @@
1
1
  import { NextResponse } from 'next/server';
2
- import { validateApiKey, addCustomDomain, isCustomDomainRegistered } from '@/lib/storage/blob';
3
- import { isValidDomain, normalizeDomain, getDnsInstructions } from '@/lib/docs/config';
2
+ import { validateApiKey, addCustomDomain, isCustomDomainRegistered, updateCustomDomainStatus } from '@/lib/storage/blob';
3
+ import { isValidDomain, normalizeDomain } from '@/lib/docs/config';
4
+ import { addDomainToProject, isVercelIntegrationEnabled, formatVerificationInstructions, getDomainType } from '@/lib/vercel/domains';
4
5
  /**
5
6
  * POST /api/domains/add
6
7
  *
7
8
  * Add a custom domain to a project.
8
9
  * Each project can have ONE custom domain (free).
9
10
  *
11
+ * When Vercel integration is enabled (VERCEL_API_TOKEN + VERCEL_PROJECT_ID):
12
+ * - Domain is added to Vercel project
13
+ * - Real DNS verification instructions from Vercel are returned
14
+ * - SSL is provisioned automatically by Vercel after verification
15
+ *
10
16
  * Headers:
11
17
  * Authorization: Bearer <api_key>
12
18
  *
@@ -18,10 +24,9 @@ import { isValidDomain, normalizeDomain, getDnsInstructions } from '@/lib/docs/c
18
24
  * success: true,
19
25
  * domain: "docs.example.com",
20
26
  * status: "pending",
21
- * verification: {
22
- * cname: { name: "docs", value: "cname.devdoc-dns.com" },
23
- * txt: { name: "_devdoc-verify.docs.example.com", value: "devdoc-verify=xxx" }
24
- * }
27
+ * verification: [
28
+ * { type: "TXT", domain: "_vercel.docs.example.com", value: "vc-domain-verify=..." }
29
+ * ]
25
30
  * }
26
31
  */ export async function POST(request) {
27
32
  try {
@@ -63,7 +68,7 @@ import { isValidDomain, normalizeDomain, getDnsInstructions } from '@/lib/docs/c
63
68
  status: 400
64
69
  });
65
70
  }
66
- // Check if domain is already registered
71
+ // Check if domain is already registered in our registry
67
72
  const isRegistered = await isCustomDomainRegistered(customDomain);
68
73
  if (isRegistered) {
69
74
  return NextResponse.json({
@@ -72,42 +77,115 @@ import { isValidDomain, normalizeDomain, getDnsInstructions } from '@/lib/docs/c
72
77
  status: 409
73
78
  });
74
79
  }
75
- // Add the custom domain
76
- const result = await addCustomDomain(projectSlug, customDomain);
77
- if (!result.success) {
80
+ // Check if Vercel integration is enabled
81
+ if (isVercelIntegrationEnabled()) {
82
+ // Add domain to Vercel project
83
+ const vercelResult = await addDomainToProject(customDomain);
84
+ if (!vercelResult.success) {
85
+ return NextResponse.json({
86
+ error: vercelResult.error,
87
+ vercelError: vercelResult.vercelError
88
+ }, {
89
+ status: 400
90
+ });
91
+ }
92
+ const vercelDomain = vercelResult.domain;
93
+ // Add to our internal registry with Vercel data
94
+ const result = await addCustomDomain(projectSlug, customDomain);
95
+ if (!result.success) {
96
+ // Rollback: Try to remove from Vercel if we couldn't add to registry
97
+ console.error('[Domains API] Failed to add to registry, domain added to Vercel:', customDomain);
98
+ return NextResponse.json({
99
+ error: result.error
100
+ }, {
101
+ status: 400
102
+ });
103
+ }
104
+ // Update with Vercel domain ID
105
+ await updateCustomDomainStatus(customDomain, vercelDomain.verified ? 'active' : 'pending', {
106
+ vercelDomainId: vercelDomain.projectId
107
+ });
108
+ // If Vercel already verified the domain (e.g., previously configured DNS)
109
+ if (vercelDomain.verified) {
110
+ return NextResponse.json({
111
+ success: true,
112
+ domain: customDomain,
113
+ projectSlug,
114
+ status: 'active',
115
+ verified: true,
116
+ message: 'Domain is already verified and active!'
117
+ });
118
+ }
119
+ // Format Vercel's verification instructions
120
+ const verification = vercelDomain.verification || [];
121
+ const { records, instructions } = formatVerificationInstructions(verification);
122
+ // Add CNAME instruction for subdomains (Vercel may not always include it)
123
+ const domainType = getDomainType(customDomain);
124
+ const parts = customDomain.split('.');
125
+ const subdomain = parts.length > 2 ? parts[0] : '@';
126
+ const cnameInstruction = domainType === 'subdomain' ? `\nAlso add a CNAME record:\n Name: ${subdomain}\n Value: cname.vercel-dns.com` : `\nFor apex domains, add an A record:\n Name: @\n Value: 76.76.21.21`;
78
127
  return NextResponse.json({
79
- error: result.error
80
- }, {
81
- status: 400
128
+ success: true,
129
+ domain: customDomain,
130
+ projectSlug,
131
+ status: 'pending',
132
+ verified: false,
133
+ verification: records,
134
+ instructions: [
135
+ ...instructions,
136
+ cnameInstruction
137
+ ],
138
+ vercelVerification: verification
139
+ });
140
+ } else {
141
+ // Fallback: No Vercel integration, use legacy behavior
142
+ console.warn('[Domains API] Vercel integration not configured, using legacy mode');
143
+ const result = await addCustomDomain(projectSlug, customDomain);
144
+ if (!result.success) {
145
+ return NextResponse.json({
146
+ error: result.error
147
+ }, {
148
+ status: 400
149
+ });
150
+ }
151
+ // Legacy hardcoded DNS instructions
152
+ const parts = customDomain.split('.');
153
+ const subdomain = parts.length > 2 ? parts[0] : '@';
154
+ return NextResponse.json({
155
+ success: true,
156
+ domain: customDomain,
157
+ projectSlug,
158
+ status: result.entry.status,
159
+ verified: false,
160
+ verification: [
161
+ {
162
+ type: 'CNAME',
163
+ name: subdomain,
164
+ value: 'cname.vercel-dns.com'
165
+ },
166
+ {
167
+ type: 'TXT',
168
+ name: `_devdoc-verify.${customDomain}`,
169
+ value: result.entry.verificationToken || ''
170
+ }
171
+ ],
172
+ instructions: [
173
+ 'Add the following DNS records to your domain:',
174
+ '',
175
+ '1. CNAME Record:',
176
+ ` Name: ${subdomain}`,
177
+ ' Value: cname.vercel-dns.com',
178
+ '',
179
+ '2. TXT Record (for verification):',
180
+ ` Name: _devdoc-verify.${customDomain}`,
181
+ ` Value: ${result.entry.verificationToken || ''}`,
182
+ '',
183
+ 'After adding DNS records, run "devdoc domain verify" to verify.',
184
+ '',
185
+ 'Note: Vercel integration not configured. Set VERCEL_API_TOKEN and VERCEL_PROJECT_ID for automatic SSL.'
186
+ ]
82
187
  });
83
188
  }
84
- // Get DNS instructions
85
- const dnsInstructions = getDnsInstructions(customDomain);
86
- // Add verification token to TXT record
87
- dnsInstructions.txt.value = result.entry.verificationToken || '';
88
- return NextResponse.json({
89
- success: true,
90
- domain: customDomain,
91
- projectSlug,
92
- status: result.entry.status,
93
- verification: {
94
- cname: dnsInstructions.cname,
95
- txt: dnsInstructions.txt
96
- },
97
- instructions: [
98
- 'Add the following DNS records to your domain:',
99
- '',
100
- `1. CNAME Record:`,
101
- ` Name: ${dnsInstructions.cname.name}`,
102
- ` Value: ${dnsInstructions.cname.value}`,
103
- '',
104
- `2. TXT Record (for verification):`,
105
- ` Name: ${dnsInstructions.txt.name}`,
106
- ` Value: ${dnsInstructions.txt.value}`,
107
- '',
108
- 'After adding DNS records, run "devdoc domain verify" to verify.'
109
- ]
110
- });
111
189
  } catch (error) {
112
190
  console.error('[Domains API] Error adding domain:', error);
113
191
  const message = error instanceof Error ? error.message : String(error);
@@ -1,11 +1,16 @@
1
1
  import { NextResponse } from 'next/server';
2
2
  import { validateApiKey, getProjectCustomDomain, removeCustomDomain } from '@/lib/storage/blob';
3
3
  import { normalizeDomain } from '@/lib/docs/config';
4
+ import { removeDomain as vercelRemoveDomain, isVercelIntegrationEnabled } from '@/lib/vercel/domains';
4
5
  /**
5
6
  * DELETE /api/domains/remove
6
7
  *
7
8
  * Remove a custom domain from a project.
8
9
  *
10
+ * When Vercel integration is enabled:
11
+ * - Removes domain from Vercel project
12
+ * - Removes from internal registry
13
+ *
9
14
  * Headers:
10
15
  * Authorization: Bearer <api_key>
11
16
  *
@@ -52,7 +57,17 @@ import { normalizeDomain } from '@/lib/docs/config';
52
57
  }
53
58
  customDomain = projectDomain.customDomain;
54
59
  }
55
- // Remove the domain
60
+ // Remove from Vercel if integration is enabled
61
+ if (isVercelIntegrationEnabled()) {
62
+ const vercelResult = await vercelRemoveDomain(customDomain);
63
+ if (!vercelResult.success) {
64
+ // Log warning but continue - domain might not exist in Vercel
65
+ console.warn('[Domains API] Failed to remove from Vercel:', vercelResult.error);
66
+ } else {
67
+ console.log('[Domains API] Domain removed from Vercel:', customDomain);
68
+ }
69
+ }
70
+ // Remove from internal registry
56
71
  const result = await removeCustomDomain(customDomain, projectSlug);
57
72
  if (!result.success) {
58
73
  return NextResponse.json({
@@ -61,8 +76,6 @@ import { normalizeDomain } from '@/lib/docs/config';
61
76
  status: 400
62
77
  });
63
78
  }
64
- // TODO: In production, also remove from Vercel via API
65
- // await vercelApi.removeDomain(customDomain)
66
79
  return NextResponse.json({
67
80
  success: true,
68
81
  message: `Domain ${customDomain} removed successfully`,
@@ -1,6 +1,7 @@
1
1
  import { NextResponse } from 'next/server';
2
2
  import { validateApiKey, getProjectCustomDomain, getCustomDomainEntry, updateCustomDomainStatus } from '@/lib/storage/blob';
3
3
  import { normalizeDomain } from '@/lib/docs/config';
4
+ import { verifyDomain as vercelVerifyDomain, getDomainConfig, isVercelIntegrationEnabled, formatVerificationInstructions } from '@/lib/vercel/domains';
4
5
  import dns from 'dns';
5
6
  import { promisify } from 'util';
6
7
  const resolveCname = promisify(dns.resolveCname);
@@ -9,7 +10,13 @@ const resolveTxt = promisify(dns.resolveTxt);
9
10
  * POST /api/domains/verify
10
11
  *
11
12
  * Verify DNS configuration for a custom domain.
12
- * Checks CNAME and TXT records, then triggers SSL provisioning.
13
+ *
14
+ * When Vercel integration is enabled:
15
+ * - Calls Vercel's verify endpoint directly
16
+ * - Vercel handles DNS verification and SSL provisioning
17
+ *
18
+ * Legacy mode (no Vercel integration):
19
+ * - Checks CNAME and TXT records manually
13
20
  *
14
21
  * Headers:
15
22
  * Authorization: Bearer <api_key>
@@ -21,11 +28,9 @@ const resolveTxt = promisify(dns.resolveTxt);
21
28
  * {
22
29
  * success: true,
23
30
  * domain: "docs.example.com",
24
- * status: "dns_verified",
25
- * checks: {
26
- * cname: { found: true, value: "cname.devdoc-dns.com" },
27
- * txt: { found: true, verified: true }
28
- * }
31
+ * status: "active",
32
+ * verified: true,
33
+ * message: "Domain verified! SSL will be provisioned automatically."
29
34
  * }
30
35
  */ export async function POST(request) {
31
36
  try {
@@ -62,7 +67,7 @@ const resolveTxt = promisify(dns.resolveTxt);
62
67
  }
63
68
  customDomain = projectDomain.customDomain;
64
69
  }
65
- // Get domain entry
70
+ // Get domain entry from our registry
66
71
  const domainEntry = await getCustomDomainEntry(customDomain);
67
72
  if (!domainEntry) {
68
73
  return NextResponse.json({
@@ -79,12 +84,74 @@ const resolveTxt = promisify(dns.resolveTxt);
79
84
  status: 403
80
85
  });
81
86
  }
82
- // Check DNS records
87
+ // Use Vercel integration if available
88
+ if (isVercelIntegrationEnabled()) {
89
+ // Call Vercel's verify endpoint
90
+ const verifyResult = await vercelVerifyDomain(customDomain);
91
+ if (!verifyResult.success) {
92
+ // Get current domain config to show what's needed
93
+ const configResult = await getDomainConfig(customDomain);
94
+ const verification = configResult.domain?.verification || [];
95
+ let instructions = [];
96
+ if (verification.length > 0) {
97
+ const formatted = formatVerificationInstructions(verification);
98
+ instructions = formatted.instructions;
99
+ }
100
+ return NextResponse.json({
101
+ success: false,
102
+ domain: customDomain,
103
+ projectSlug,
104
+ status: domainEntry.status,
105
+ verified: false,
106
+ message: verifyResult.error || 'DNS verification failed. Please check your DNS records.',
107
+ verification: verification.map((v)=>({
108
+ type: v.type,
109
+ name: v.domain,
110
+ value: v.value
111
+ })),
112
+ instructions
113
+ });
114
+ }
115
+ // Domain verified successfully
116
+ if (verifyResult.verified) {
117
+ // Update our registry to mark as active
118
+ await updateCustomDomainStatus(customDomain, 'active');
119
+ return NextResponse.json({
120
+ success: true,
121
+ domain: customDomain,
122
+ projectSlug,
123
+ status: 'active',
124
+ verified: true,
125
+ message: 'Domain verified! SSL certificate will be provisioned automatically by Vercel.'
126
+ });
127
+ } else {
128
+ // Vercel didn't verify yet, return what's needed
129
+ const verification = verifyResult.domain?.verification || [];
130
+ const { instructions } = formatVerificationInstructions(verification);
131
+ return NextResponse.json({
132
+ success: false,
133
+ domain: customDomain,
134
+ projectSlug,
135
+ status: 'pending',
136
+ verified: false,
137
+ message: 'DNS records not yet propagated. This can take up to 48 hours.',
138
+ verification: verification.map((v)=>({
139
+ type: v.type,
140
+ name: v.domain,
141
+ value: v.value
142
+ })),
143
+ instructions
144
+ });
145
+ }
146
+ }
147
+ // Legacy verification (no Vercel integration)
148
+ console.warn('[Domains API] Vercel integration not configured, using legacy DNS verification');
149
+ // Check DNS records manually
83
150
  const checks = {
84
151
  cname: {
85
152
  found: false,
86
153
  value: null,
87
- expected: 'cname.devdoc-dns.com'
154
+ expected: 'cname.vercel-dns.com'
88
155
  },
89
156
  txt: {
90
157
  found: false,
@@ -116,18 +183,15 @@ const resolveTxt = promisify(dns.resolveTxt);
116
183
  // TXT not found or DNS error
117
184
  }
118
185
  // Determine overall status
119
- const cnameValid = checks.cname.found && checks.cname.value?.toLowerCase().includes('devdoc');
186
+ const cnameValid = checks.cname.found && checks.cname.value?.toLowerCase().includes('vercel');
120
187
  const txtValid = checks.txt.found && checks.txt.verified;
121
188
  let newStatus = domainEntry.status;
122
189
  let message = '';
123
190
  if (cnameValid && txtValid) {
124
- // DNS is verified, update status
125
- newStatus = 'dns_verified';
126
- message = 'DNS verified! SSL certificate will be provisioned automatically (1-24 hours).';
127
- await updateCustomDomainStatus(customDomain, 'dns_verified');
128
- // In production, this would trigger Vercel API to add domain
129
- // For now, we simulate SSL provisioning by updating status
130
- // TODO: Integrate with Vercel Domains API
191
+ // DNS is verified
192
+ newStatus = 'active';
193
+ message = 'DNS verified! Domain is now active.';
194
+ await updateCustomDomainStatus(customDomain, 'active');
131
195
  } else if (cnameValid && !txtValid) {
132
196
  message = 'CNAME record found, but TXT verification record is missing or incorrect.';
133
197
  } else if (!cnameValid && txtValid) {
@@ -140,6 +204,7 @@ const resolveTxt = promisify(dns.resolveTxt);
140
204
  domain: customDomain,
141
205
  projectSlug,
142
206
  status: newStatus,
207
+ verified: cnameValid && txtValid,
143
208
  message,
144
209
  checks: {
145
210
  cname: {
@@ -6,10 +6,6 @@ import { getProjectContent } from '@/lib/storage/blob';
6
6
  const STARTER_PATH = process.env.STARTER_PATH || 'devdoc-docs';
7
7
  // Get the docs directory - respects STARTER_PATH for local development
8
8
  function getDocsDir() {
9
- const projectSlug = process.env.BRAINFISH_PROJECT_SLUG;
10
- if (projectSlug) {
11
- return join(process.cwd(), '.devdoc', projectSlug);
12
- }
13
9
  // Use STARTER_PATH (can be absolute or relative)
14
10
  if (isAbsolute(STARTER_PATH)) {
15
11
  return STARTER_PATH;
@@ -43,22 +39,27 @@ export async function GET(request) {
43
39
  });
44
40
  }
45
41
  try {
46
- // Try blob storage first (for deployed projects)
47
- const projectSlug = process.env.BRAINFISH_PROJECT_SLUG;
42
+ // Get project slug from middleware header (multi-tenant) or env var (single-tenant)
43
+ const projectSlug = request.headers.get('x-devdoc-project') || process.env.BRAINFISH_PROJECT_SLUG;
44
+ // Try blob storage first (for deployed/multi-tenant projects)
48
45
  if (projectSlug) {
49
46
  const projectContent = await getProjectContent(projectSlug);
50
- if (projectContent?.files) {
51
- const file = projectContent.files.find((f)=>f.path === path || f.path === `/${path}`);
52
- if (file?.content) {
53
- return new NextResponse(file.content, {
47
+ // Check dedicated graphqlSchemas map first (like OpenAPI specs)
48
+ if (projectContent?.graphqlSchemas) {
49
+ const schemaContent = projectContent.graphqlSchemas[path] || projectContent.graphqlSchemas[path.replace(/^\//, '')] // Try without leading slash
50
+ ;
51
+ if (schemaContent) {
52
+ return new NextResponse(schemaContent, {
54
53
  headers: {
55
54
  'Content-Type': 'text/plain'
56
55
  }
57
56
  });
58
57
  }
58
+ // Log for debugging - schema not found
59
+ console.log('[Schema API] Schema not found in graphqlSchemas:', path, 'Available:', Object.keys(projectContent.graphqlSchemas));
59
60
  }
60
61
  }
61
- // Try local filesystem
62
+ // Try local filesystem (for local development)
62
63
  const docsDir = getDocsDir();
63
64
  const fullPath = join(docsDir, path);
64
65
  if (!existsSync(fullPath)) {
@@ -7,9 +7,8 @@ import { ThemeToggle } from "@/components/theme-toggle";
7
7
  import { useMobile } from "@/lib/api-docs/mobile-context";
8
8
  import { Button } from "@/components/ui/button";
9
9
  import { cn } from "@/lib/utils";
10
- // Default logo fallback
11
- const DEFAULT_LOGO = {
12
- url: 'https://cdn.prod.website-files.com/639181964f4fe88697a20a0a/67af64a5ba42bb659b8560c9_Logo%20(3).svg',
10
+ // Default logo dimensions (no default URL - show name only if no logo configured)
11
+ const DEFAULT_LOGO_DIMENSIONS = {
13
12
  alt: 'Logo',
14
13
  width: 80,
15
14
  height: 24
@@ -19,13 +18,14 @@ export function DocsHeader({ navigationTabs = [], activeTab, onTabChange, docsNa
19
18
  // Use config values with defaults
20
19
  // Support both single URL and separate light/dark logos
21
20
  const hasLightDarkLogos = docsLogo?.light && docsLogo?.dark;
21
+ const hasAnyLogo = docsLogo?.url || hasLightDarkLogos;
22
22
  const logo = {
23
- url: docsLogo?.url || DEFAULT_LOGO.url,
23
+ url: docsLogo?.url,
24
24
  light: docsLogo?.light,
25
25
  dark: docsLogo?.dark,
26
- alt: docsLogo?.alt || DEFAULT_LOGO.alt,
27
- width: docsLogo?.width || DEFAULT_LOGO.width,
28
- height: docsLogo?.height || DEFAULT_LOGO.height
26
+ alt: docsLogo?.alt || DEFAULT_LOGO_DIMENSIONS.alt,
27
+ width: docsLogo?.width || DEFAULT_LOGO_DIMENSIONS.width,
28
+ height: docsLogo?.height || DEFAULT_LOGO_DIMENSIONS.height
29
29
  };
30
30
  const showSearch = docsHeader?.showSearch !== false // Default true
31
31
  ;
@@ -87,7 +87,7 @@ export function DocsHeader({ navigationTabs = [], activeTab, onTabChange, docsNa
87
87
  priority: true
88
88
  })
89
89
  ]
90
- }) : /*#__PURE__*/ _jsx(Image, {
90
+ }) : logo.url ? /*#__PURE__*/ _jsx(Image, {
91
91
  src: logo.url,
92
92
  alt: logo.alt,
93
93
  width: logo.width,
@@ -97,14 +97,14 @@ export function DocsHeader({ navigationTabs = [], activeTab, onTabChange, docsNa
97
97
  height: logo.height
98
98
  },
99
99
  priority: true
100
- }),
100
+ }) : null,
101
101
  docsName && /*#__PURE__*/ _jsxs(_Fragment, {
102
102
  children: [
103
- /*#__PURE__*/ _jsx("div", {
103
+ hasAnyLogo && /*#__PURE__*/ _jsx("div", {
104
104
  className: "hidden sm:block h-5 w-px bg-border"
105
105
  }),
106
106
  /*#__PURE__*/ _jsx("span", {
107
- className: "docs-header-title hidden sm:inline text-sm font-medium text-muted-foreground pointer-events-none",
107
+ className: cn("docs-header-title text-sm font-medium pointer-events-none", hasAnyLogo ? "hidden sm:inline text-muted-foreground" : "text-foreground font-semibold"),
108
108
  children: docsName
109
109
  })
110
110
  ]
@@ -145,13 +145,26 @@ export const domainConfigSchema = z.object({
145
145
  }
146
146
  /**
147
147
  * Get DNS instructions for a custom domain
148
+ *
149
+ * NOTE: When Vercel integration is enabled (VERCEL_API_TOKEN + VERCEL_PROJECT_ID),
150
+ * the actual DNS instructions come from Vercel's API response.
151
+ * This function is used as a fallback for legacy/local development mode.
152
+ *
153
+ * For Vercel-hosted projects:
154
+ * - Subdomains: CNAME to cname.vercel-dns.com
155
+ * - Apex domains: A record to 76.76.21.21
156
+ *
157
+ * @param customDomain - The custom domain (e.g., "docs.example.com")
158
+ * @returns DNS instructions for CNAME and TXT records
148
159
  */ export function getDnsInstructions(customDomain) {
149
160
  const parts = customDomain.split('.');
150
161
  const subdomain = parts.length > 2 ? parts[0] : '@';
162
+ const isApexDomain = parts.length <= 2;
151
163
  return {
152
164
  cname: {
153
165
  name: subdomain === '@' ? customDomain : subdomain,
154
- value: 'cname.devdoc-dns.com'
166
+ // Use Vercel's actual DNS target
167
+ value: isApexDomain ? '76.76.21.21' : 'cname.vercel-dns.com'
155
168
  },
156
169
  txt: {
157
170
  name: `_devdoc-verify.${customDomain}`,
@@ -159,3 +172,12 @@ export const domainConfigSchema = z.object({
159
172
  }
160
173
  };
161
174
  }
175
+ /**
176
+ * Get human-readable DNS type based on domain
177
+ *
178
+ * @param customDomain - The custom domain
179
+ * @returns 'A' for apex domains, 'CNAME' for subdomains
180
+ */ export function getDnsRecordType(customDomain) {
181
+ const parts = customDomain.split('.');
182
+ return parts.length <= 2 ? 'A' : 'CNAME';
183
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Configuration Module Exports
3
3
  */ export { docsConfigSchema, parseDocsConfig, safeParseDocsConfig, getDefaultDocsConfig } from './schema';
4
- export { domainConfigSchema, parseDomainConfig, safeParseDomainConfig, isValidDomain, normalizeDomain, getDnsInstructions } from './domain-schema';
4
+ export { domainConfigSchema, parseDomainConfig, safeParseDomainConfig, isValidDomain, normalizeDomain, getDnsInstructions, getDnsRecordType } from './domain-schema';
5
5
  export { loadDocsConfig, safeLoadDocsConfig, clearConfigCache, hasDocsConfig, getContentDir, resolvePagePath, loadPageContent, listMdxFiles } from './loader';
6
6
  export { isDevMode, isProductionMode, shouldShowItem } from './environment';
@@ -30,7 +30,7 @@ function _getFileBlobPath(slug, filePath) {
30
30
  }
31
31
  /**
32
32
  * Store project content in Vercel Blob (or local filesystem in dev)
33
- */ export async function storeProjectContent(slug, name, docsJson, files, themeJson, openApiSpecs) {
33
+ */ export async function storeProjectContent(slug, name, docsJson, files, themeJson, openApiSpecs, graphqlSchemas) {
34
34
  const now = new Date().toISOString();
35
35
  const content = {
36
36
  slug,
@@ -41,6 +41,7 @@ function _getFileBlobPath(slug, filePath) {
41
41
  k,
42
42
  JSON.stringify(v)
43
43
  ])) : undefined,
44
+ graphqlSchemas,
44
45
  files,
45
46
  createdAt: now,
46
47
  updatedAt: now
@@ -92,7 +93,7 @@ function _getFileBlobPath(slug, filePath) {
92
93
  }
93
94
  /**
94
95
  * Update existing project content
95
- */ export async function updateProjectContent(slug, docsJson, files, themeJson, openApiSpecs) {
96
+ */ export async function updateProjectContent(slug, docsJson, files, themeJson, openApiSpecs, graphqlSchemas) {
96
97
  // Get existing content to preserve createdAt
97
98
  const existing = await getProjectContent(slug);
98
99
  const now = new Date().toISOString();
@@ -105,6 +106,7 @@ function _getFileBlobPath(slug, filePath) {
105
106
  k,
106
107
  JSON.stringify(v)
107
108
  ])) : undefined,
109
+ graphqlSchemas,
108
110
  files,
109
111
  createdAt: existing?.createdAt || now,
110
112
  updatedAt: now