@uptrademedia/site-kit 1.0.1 → 1.0.3

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 (111) hide show
  1. package/dist/blog/index.js.map +1 -1
  2. package/dist/blog/index.mjs.map +1 -1
  3. package/dist/chunk-5R4R3WDP.js +1451 -0
  4. package/dist/chunk-5R4R3WDP.js.map +1 -0
  5. package/dist/{chunk-COI6GOX2.mjs → chunk-63JNO4QN.mjs} +3 -3
  6. package/dist/chunk-63JNO4QN.mjs.map +1 -0
  7. package/dist/chunk-6EXHT7PS.mjs +330 -0
  8. package/dist/chunk-6EXHT7PS.mjs.map +1 -0
  9. package/dist/{chunk-RV7H3I6J.js → chunk-ADHVEFWD.js} +68 -2
  10. package/dist/chunk-ADHVEFWD.js.map +1 -0
  11. package/dist/chunk-BGJLOJ7T.mjs +605 -0
  12. package/dist/chunk-BGJLOJ7T.mjs.map +1 -0
  13. package/dist/chunk-BZBJVG5Y.js +88 -0
  14. package/dist/chunk-BZBJVG5Y.js.map +1 -0
  15. package/dist/chunk-DRFTRTKV.js +809 -0
  16. package/dist/chunk-DRFTRTKV.js.map +1 -0
  17. package/dist/chunk-EL5QTAA3.mjs +805 -0
  18. package/dist/chunk-EL5QTAA3.mjs.map +1 -0
  19. package/dist/chunk-JG2K4S2I.js +997 -0
  20. package/dist/chunk-JG2K4S2I.js.map +1 -0
  21. package/dist/chunk-P7LGOKGI.mjs +981 -0
  22. package/dist/chunk-P7LGOKGI.mjs.map +1 -0
  23. package/dist/{chunk-3MUOUXHV.js → chunk-PYYEPAHL.js} +3 -3
  24. package/dist/chunk-PYYEPAHL.js.map +1 -0
  25. package/dist/chunk-QAYJV4KK.js +608 -0
  26. package/dist/chunk-QAYJV4KK.js.map +1 -0
  27. package/dist/{chunk-FEBYQGY4 2.mjs → chunk-SMUFNQLM.mjs} +67 -3
  28. package/dist/chunk-SMUFNQLM.mjs.map +1 -0
  29. package/dist/chunk-VDMZZL2O.mjs +83 -0
  30. package/dist/chunk-VDMZZL2O.mjs.map +1 -0
  31. package/dist/chunk-XFRPT5ZX.mjs +1449 -0
  32. package/dist/chunk-XFRPT5ZX.mjs.map +1 -0
  33. package/dist/chunk-YKMCG3DS.js +332 -0
  34. package/dist/chunk-YKMCG3DS.js.map +1 -0
  35. package/dist/commerce/index.js +38 -38
  36. package/dist/commerce/index.mjs +1 -1
  37. package/dist/engage/index.js +7 -40
  38. package/dist/engage/index.js.map +1 -1
  39. package/dist/engage/index.mjs +1 -41
  40. package/dist/engage/index.mjs.map +1 -1
  41. package/dist/forms/index.js +13 -5
  42. package/dist/forms/index.js.map +1 -1
  43. package/dist/forms/index.mjs +2 -2
  44. package/dist/forms/index.mjs.map +1 -1
  45. package/dist/{generators-7Y5ABRYV 2.mjs → generators-TO2FKJR6.mjs} +134 -3
  46. package/dist/generators-TO2FKJR6.mjs.map +1 -0
  47. package/dist/{generators-GWIYCA5M.js → generators-YZWIGHCO.js} +135 -2
  48. package/dist/generators-YZWIGHCO.js.map +1 -0
  49. package/dist/images/index.js +41 -0
  50. package/dist/images/index.js.map +1 -0
  51. package/dist/images/index.mjs +8 -0
  52. package/dist/images/index.mjs.map +1 -0
  53. package/dist/index.js +1355 -104
  54. package/dist/index.js.map +1 -1
  55. package/dist/index.mjs +1242 -76
  56. package/dist/index.mjs.map +1 -1
  57. package/dist/redirects/index.js +25 -0
  58. package/dist/redirects/index.js.map +1 -0
  59. package/dist/redirects/index.mjs +4 -0
  60. package/dist/redirects/index.mjs.map +1 -0
  61. package/dist/{scanner-MF7P3CDE 2.mjs → scanner-AZV5I6US.mjs} +123 -4
  62. package/dist/scanner-AZV5I6US.mjs.map +1 -0
  63. package/dist/{scanner-NT6YG4TD 2.js → scanner-ETJAMIT7.js} +124 -3
  64. package/dist/scanner-ETJAMIT7.js.map +1 -0
  65. package/dist/setup/client.js +30 -0
  66. package/dist/setup/client.js.map +1 -0
  67. package/dist/setup/client.mjs +5 -0
  68. package/dist/setup/client.mjs.map +1 -0
  69. package/dist/setup/index.js +28 -1043
  70. package/dist/setup/index.js.map +1 -1
  71. package/dist/setup/index.mjs +3 -1043
  72. package/dist/setup/index.mjs.map +1 -1
  73. package/dist/setup/server.js +13 -0
  74. package/dist/setup/server.js.map +1 -0
  75. package/dist/setup/server.mjs +4 -0
  76. package/dist/setup/server.mjs.map +1 -0
  77. package/package.json +21 -1
  78. package/dist/chunk-3MUOUXHV.js.map +0 -1
  79. package/dist/chunk-4HVYXYQL 2.mjs +0 -255
  80. package/dist/chunk-4HVYXYQL.mjs +0 -255
  81. package/dist/chunk-4HVYXYQL.mjs.map +0 -1
  82. package/dist/chunk-COI6GOX2.mjs.map +0 -1
  83. package/dist/chunk-EQCVQC35.js 2.map +0 -1
  84. package/dist/chunk-FEBYQGY4.mjs +0 -251
  85. package/dist/chunk-FEBYQGY4.mjs.map +0 -1
  86. package/dist/chunk-NYKRE2FL 2.mjs +0 -31
  87. package/dist/chunk-NYKRE2FL.mjs 2.map +0 -1
  88. package/dist/chunk-RV7H3I6J.js 2.map +0 -1
  89. package/dist/chunk-RV7H3I6J.js.map +0 -1
  90. package/dist/chunk-TUKGA3UK.js +0 -257
  91. package/dist/chunk-TUKGA3UK.js 2.map +0 -1
  92. package/dist/chunk-TUKGA3UK.js.map +0 -1
  93. package/dist/generators-7Y5ABRYV.mjs +0 -161
  94. package/dist/generators-7Y5ABRYV.mjs 2.map +0 -1
  95. package/dist/generators-7Y5ABRYV.mjs.map +0 -1
  96. package/dist/generators-GWIYCA5M.js 2.map +0 -1
  97. package/dist/generators-GWIYCA5M.js.map +0 -1
  98. package/dist/index 2.mjs +0 -74
  99. package/dist/index.js 2.map +0 -1
  100. package/dist/migrator-V6KS75EA 2.mjs +0 -265
  101. package/dist/migrator-V6KS75EA.mjs 2.map +0 -1
  102. package/dist/migrator-XKM7YQCY.js 2.map +0 -1
  103. package/dist/scanner-MF7P3CDE.mjs +0 -14386
  104. package/dist/scanner-MF7P3CDE.mjs 2.map +0 -1
  105. package/dist/scanner-MF7P3CDE.mjs.map +0 -1
  106. package/dist/scanner-NT6YG4TD.js +0 -14397
  107. package/dist/scanner-NT6YG4TD.js 2.map +0 -1
  108. package/dist/scanner-NT6YG4TD.js.map +0 -1
  109. package/dist/web-vitals-BH55V7EJ.js 2.map +0 -1
  110. package/dist/web-vitals-RJYPWAR3 2.mjs +0 -241
  111. package/dist/web-vitals-RJYPWAR3.mjs 2.map +0 -1
@@ -0,0 +1,330 @@
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-AZV5I6US.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-V6KS75EA.mjs');
179
+ try {
180
+ await migrateFiles([item], projectId, authSession.accessToken);
181
+ return NextResponse.json({ success: true });
182
+ } catch (err) {
183
+ return NextResponse.json({ error: err.message }, { status: 500 });
184
+ }
185
+ }
186
+ async function handleConfigure(req) {
187
+ if (!authSession.accessToken) {
188
+ return NextResponse.json({ error: "Not authenticated" }, { status: 401 });
189
+ }
190
+ const { projectId } = await req.json();
191
+ const { generateEnvFile, generateProvider } = await import('./generators-TO2FKJR6.mjs');
192
+ try {
193
+ const configResponse = await fetch(`${API_URL}/projects/${projectId}/config`, {
194
+ headers: { "Authorization": `Bearer ${authSession.accessToken}` }
195
+ });
196
+ if (!configResponse.ok) {
197
+ throw new Error("Failed to fetch project config");
198
+ }
199
+ const config = await configResponse.json();
200
+ const keyResponse = await fetch(`${API_URL}/projects/${projectId}/api-keys`, {
201
+ method: "POST",
202
+ headers: {
203
+ "Authorization": `Bearer ${authSession.accessToken}`,
204
+ "Content-Type": "application/json"
205
+ },
206
+ body: JSON.stringify({ name: "Site-Kit Setup" })
207
+ });
208
+ let apiKey = "ut_xxx";
209
+ if (keyResponse.ok) {
210
+ const keyData = await keyResponse.json();
211
+ apiKey = keyData.key;
212
+ }
213
+ await generateEnvFile({
214
+ projectId,
215
+ supabaseUrl: config.supabase_url,
216
+ supabaseAnonKey: config.supabase_anon_key,
217
+ apiKey
218
+ });
219
+ await generateProvider({ projectId });
220
+ return NextResponse.json({ success: true });
221
+ } catch (err) {
222
+ return NextResponse.json({ error: err.message }, { status: 500 });
223
+ }
224
+ }
225
+ async function handleSelfDestruct() {
226
+ const { selfDestruct } = await import('./generators-TO2FKJR6.mjs');
227
+ try {
228
+ await selfDestruct();
229
+ return NextResponse.json({ success: true });
230
+ } catch (err) {
231
+ return NextResponse.json({ error: err.message }, { status: 500 });
232
+ }
233
+ }
234
+ function successHtml() {
235
+ return `<!DOCTYPE html>
236
+ <html>
237
+ <head>
238
+ <title>Uptrade - Authenticated</title>
239
+ <style>
240
+ body {
241
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
242
+ display: flex; justify-content: center; align-items: center;
243
+ height: 100vh; margin: 0;
244
+ background: linear-gradient(135deg, #1a1a2e 0%, #0f0f1a 100%);
245
+ color: white;
246
+ }
247
+ .container {
248
+ text-align: center; padding: 3rem;
249
+ background: rgba(255, 255, 255, 0.05);
250
+ border-radius: 1rem; border: 1px solid rgba(255, 255, 255, 0.1);
251
+ }
252
+ .icon { font-size: 4rem; margin-bottom: 1rem; }
253
+ h1 { margin: 0 0 0.5rem; }
254
+ p { color: rgba(255, 255, 255, 0.7); margin: 0; }
255
+ </style>
256
+ <script>setTimeout(() => window.close(), 2000)</script>
257
+ </head>
258
+ <body>
259
+ <div class="container">
260
+ <div class="icon">\u2713</div>
261
+ <h1>Authenticated!</h1>
262
+ <p>This window will close automatically...</p>
263
+ </div>
264
+ </body>
265
+ </html>`;
266
+ }
267
+ function errorHtml(title, message) {
268
+ return `<!DOCTYPE html>
269
+ <html>
270
+ <head>
271
+ <title>Uptrade - Error</title>
272
+ <style>
273
+ body {
274
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
275
+ display: flex; justify-content: center; align-items: center;
276
+ height: 100vh; margin: 0;
277
+ background: linear-gradient(135deg, #2e1a1a 0%, #1a0f0f 100%);
278
+ color: white;
279
+ }
280
+ .container {
281
+ text-align: center; padding: 3rem;
282
+ background: rgba(255, 255, 255, 0.05);
283
+ border-radius: 1rem; border: 1px solid rgba(255, 100, 100, 0.2);
284
+ }
285
+ .icon { font-size: 4rem; margin-bottom: 1rem; }
286
+ h1 { margin: 0 0 0.5rem; color: #ff6b6b; }
287
+ p { color: rgba(255, 255, 255, 0.7); margin: 0; }
288
+ </style>
289
+ </head>
290
+ <body>
291
+ <div class="container">
292
+ <div class="icon">\u2717</div>
293
+ <h1>${title}</h1>
294
+ <p>${message}</p>
295
+ </div>
296
+ </body>
297
+ </html>`;
298
+ }
299
+ async function handleRequest(req, route) {
300
+ switch (route) {
301
+ case "status":
302
+ return handleStatus();
303
+ case "auth/start":
304
+ return handleAuthStart();
305
+ case "auth/callback":
306
+ return handleAuthCallback(req);
307
+ case "auth/status":
308
+ return handleAuthStatus();
309
+ case "auth/apikey":
310
+ return handleApiKeyAuth(req);
311
+ case "organizations":
312
+ return handleGetOrganizations();
313
+ case "projects":
314
+ return handleCreateProject(req);
315
+ case "scan":
316
+ return handleScan();
317
+ case "migrate":
318
+ return handleMigrate(req);
319
+ case "configure":
320
+ return handleConfigure(req);
321
+ case "self-destruct":
322
+ return handleSelfDestruct();
323
+ default:
324
+ return NextResponse.json({ error: "Not found" }, { status: 404 });
325
+ }
326
+ }
327
+
328
+ export { handleRequest };
329
+ //# sourceMappingURL=chunk-6EXHT7PS.mjs.map
330
+ //# sourceMappingURL=chunk-6EXHT7PS.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/setup/api-handlers.ts"],"names":[],"mappings":"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","file":"chunk-6EXHT7PS.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 await migrateFiles([item], projectId, authSession.accessToken)\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"]}
@@ -158,6 +158,41 @@ var formsApi = {
158
158
  */
159
159
  async setActive(formId, isActive) {
160
160
  return formsApi.update(formId, { isActive });
161
+ },
162
+ /**
163
+ * Sync a form definition to the backend
164
+ * Creates the form if it doesn't exist, updates if it does
165
+ * Perfect for defining forms in code during development
166
+ *
167
+ * @example
168
+ * ```tsx
169
+ * // In your app initialization or form component
170
+ * await formsApi.sync({
171
+ * slug: 'contact',
172
+ * name: 'Contact Form',
173
+ * formType: 'prospect',
174
+ * fields: [
175
+ * field.text('name', 'Your Name', { isRequired: true }),
176
+ * field.email('email', 'Email Address'),
177
+ * field.phone('phone', 'Phone Number'),
178
+ * field.textarea('message', 'Message'),
179
+ * ]
180
+ * })
181
+ * ```
182
+ */
183
+ async sync(input) {
184
+ return apiRequest(
185
+ "POST",
186
+ "/api/public/forms/sync",
187
+ input
188
+ );
189
+ },
190
+ /**
191
+ * Sync multiple forms at once
192
+ * Useful for initializing all forms in your app
193
+ */
194
+ async syncAll(forms) {
195
+ return Promise.all(forms.map((form) => formsApi.sync(form)));
161
196
  }
162
197
  };
163
198
  var field = {
@@ -247,9 +282,40 @@ var field = {
247
282
  fieldType: "paragraph"
248
283
  })
249
284
  };
285
+ function defineForm(definition) {
286
+ const fieldsWithOrder = definition.fields.map((f, index) => ({
287
+ ...f,
288
+ sortOrder: f.sortOrder ?? index
289
+ }));
290
+ return {
291
+ ...definition,
292
+ fields: fieldsWithOrder,
293
+ formType: definition.formType || "contact",
294
+ successMessage: definition.successMessage || "Thank you for your submission!",
295
+ submitButtonText: definition.submitButtonText || "Submit",
296
+ layout: definition.layout || "stacked",
297
+ isActive: definition.isActive ?? true
298
+ };
299
+ }
300
+ async function initializeForms(forms) {
301
+ if (typeof window === "undefined") {
302
+ console.log(`[Site-Kit] ${forms.length} form(s) ready to sync: ${forms.map((f) => f.slug).join(", ")}`);
303
+ return;
304
+ }
305
+ try {
306
+ const results = await formsApi.syncAll(forms);
307
+ const created = results.filter((r) => r.created).length;
308
+ const updated = results.filter((r) => r.updated).length;
309
+ console.log(`[Site-Kit] Forms synced: ${created} created, ${updated} updated`);
310
+ } catch (error) {
311
+ console.error("[Site-Kit] Failed to sync forms:", error);
312
+ }
313
+ }
250
314
 
251
315
  exports.configureFormsApi = configureFormsApi;
316
+ exports.defineForm = defineForm;
252
317
  exports.field = field;
253
318
  exports.formsApi = formsApi;
254
- //# sourceMappingURL=chunk-RV7H3I6J.js.map
255
- //# sourceMappingURL=chunk-RV7H3I6J.js.map
319
+ exports.initializeForms = initializeForms;
320
+ //# sourceMappingURL=chunk-ADHVEFWD.js.map
321
+ //# sourceMappingURL=chunk-ADHVEFWD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/forms/formsApi.ts"],"names":["field"],"mappings":"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","file":"chunk-ADHVEFWD.js","sourcesContent":["/**\n * @uptrade/site-kit/forms - Forms API Client\n * \n * Full API client for form management. Allows developers to create, update,\n * and delete forms programmatically. Changes sync to Portal automatically.\n * \n * @example\n * ```tsx\n * import { formsApi } from '@uptrade/site-kit/forms'\n * \n * // Create a new form\n * const form = await formsApi.create({\n * projectId: 'xxx',\n * slug: 'contact-us',\n * name: 'Contact Form',\n * formType: 'prospect',\n * fields: [\n * { slug: 'name', label: 'Name', fieldType: 'text', isRequired: true },\n * { slug: 'email', label: 'Email', fieldType: 'email', isRequired: true },\n * { slug: 'message', label: 'Message', fieldType: 'textarea' },\n * ]\n * })\n * \n * // Update fields\n * await formsApi.update(form.id, {\n * fields: [...form.fields, { slug: 'phone', label: 'Phone', fieldType: 'phone' }]\n * })\n * ```\n */\n\n// ============================================\n// Types\n// ============================================\n\nexport type FormType = \n | 'prospect' // → CRM leads\n | 'contact' // → Contact form\n | 'support' // → Support tickets\n | 'feedback' // → Feedback entries\n | 'newsletter' // → Email subscribers\n | 'custom' // → Custom webhook\n\nexport type FieldType =\n | 'text'\n | 'email'\n | 'phone'\n | 'number'\n | 'textarea'\n | 'select'\n | 'multi_select'\n | 'radio'\n | 'checkbox'\n | 'date'\n | 'time'\n | 'datetime'\n | 'url'\n | 'file'\n | 'rating'\n | 'slider'\n | 'hidden'\n | 'heading'\n | 'paragraph'\n\nexport type FieldWidth = 'full' | 'half' | 'third' | 'quarter'\n\nexport interface FieldOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface FieldValidation {\n min?: number\n max?: number\n minLength?: number\n maxLength?: number\n pattern?: string\n patternMessage?: string\n}\n\nexport interface FieldConditional {\n field: string\n operator: 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_empty' | 'not_empty' | 'greater_than' | 'less_than'\n value?: string | number | boolean\n}\n\nexport interface FormField {\n id?: string\n slug: string\n label: string\n fieldType: FieldType\n placeholder?: string\n helpText?: string\n defaultValue?: string\n isRequired?: boolean\n validation?: FieldValidation\n options?: FieldOption[]\n conditional?: FieldConditional\n width?: FieldWidth\n sortOrder?: number\n destinationField?: string\n stepId?: string\n}\n\nexport interface FormStep {\n id?: string\n stepNumber: number\n title?: string\n description?: string\n condition?: FieldConditional\n}\n\nexport interface Form {\n id: string\n projectId: string\n slug: string\n name: string\n description?: string\n formType: FormType\n successMessage: string\n redirectUrl?: string\n notificationEmails?: string[]\n submitButtonText: string\n layout: 'stacked' | 'inline' | 'grid'\n showProgress: boolean\n enableSaveDraft: boolean\n isActive: boolean\n createdAt: string\n updatedAt: string\n fields?: FormField[]\n steps?: FormStep[]\n}\n\nexport interface CreateFormInput {\n projectId: string\n slug: string\n name: string\n description?: string\n formType?: FormType\n successMessage?: string\n redirectUrl?: string\n notificationEmails?: string[]\n submitButtonText?: string\n layout?: 'stacked' | 'inline' | 'grid'\n showProgress?: boolean\n enableSaveDraft?: boolean\n isActive?: boolean\n fields?: FormField[]\n steps?: FormStep[]\n}\n\nexport interface UpdateFormInput {\n slug?: string\n name?: string\n description?: string\n formType?: FormType\n successMessage?: string\n redirectUrl?: string\n notificationEmails?: string[]\n submitButtonText?: string\n layout?: 'stacked' | 'inline' | 'grid'\n showProgress?: boolean\n enableSaveDraft?: boolean\n isActive?: boolean\n fields?: FormField[]\n steps?: FormStep[]\n}\n\nexport interface FormsListOptions {\n projectId?: string\n formType?: FormType\n isActive?: boolean\n search?: string\n}\n\n// ============================================\n// API Client Configuration\n// ============================================\n\ninterface FormsApiConfig {\n baseUrl: string\n apiKey?: string\n getAuthToken?: () => Promise<string> | string\n}\n\nlet config: FormsApiConfig | null = null\n\n/**\n * Configure the forms API client\n */\nexport function configureFormsApi(options: FormsApiConfig) {\n config = options\n}\n\n/**\n * Get API config, falling back to SiteKitProvider globals\n */\nfunction getConfig(): FormsApiConfig {\n if (config) return config\n \n // Try to get from window globals (set by SiteKitProvider)\n if (typeof window !== 'undefined') {\n const apiUrl = (window as any).__SITE_KIT_API_URL__\n const apiKey = (window as any).__SITE_KIT_API_KEY__\n \n if (apiUrl && apiKey) {\n return { baseUrl: apiUrl, apiKey }\n }\n }\n \n throw new Error(\n 'Forms API not configured. Either wrap your app in SiteKitProvider or call configureFormsApi() first.'\n )\n}\n\n// ============================================\n// HTTP Helpers\n// ============================================\n\nasync function apiRequest<T>(\n method: 'GET' | 'POST' | 'PUT' | 'DELETE',\n path: string,\n body?: any\n): Promise<T> {\n const { baseUrl, apiKey, getAuthToken } = getConfig()\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n }\n \n // Use API key for public endpoints, auth token for admin endpoints\n if (apiKey) {\n headers['x-api-key'] = apiKey\n } else if (getAuthToken) {\n const token = await getAuthToken()\n headers['Authorization'] = `Bearer ${token}`\n }\n \n const response = await fetch(`${baseUrl}${path}`, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n })\n \n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: response.statusText }))\n throw new Error(error.message || `API error: ${response.status}`)\n }\n \n if (response.status === 204) {\n return undefined as T\n }\n \n return response.json()\n}\n\n// ============================================\n// Forms API\n// ============================================\n\nexport const formsApi = {\n /**\n * List all forms for a project\n */\n async list(options: FormsListOptions = {}): Promise<Form[]> {\n const params = new URLSearchParams()\n if (options.projectId) params.set('projectId', options.projectId)\n if (options.formType) params.set('formType', options.formType)\n if (options.isActive !== undefined) params.set('isActive', String(options.isActive))\n if (options.search) params.set('search', options.search)\n \n const query = params.toString()\n const result = await apiRequest<{ data: Form[] }>('GET', `/forms${query ? `?${query}` : ''}`)\n return result.data\n },\n \n /**\n * Get a single form by ID or slug\n */\n async get(idOrSlug: string): Promise<Form> {\n return apiRequest<Form>('GET', `/forms/${idOrSlug}`)\n },\n \n /**\n * Create a new form\n */\n async create(input: CreateFormInput): Promise<Form> {\n return apiRequest<Form>('POST', '/forms', input)\n },\n \n /**\n * Update an existing form\n */\n async update(id: string, input: UpdateFormInput): Promise<Form> {\n return apiRequest<Form>('PUT', `/forms/${id}`, input)\n },\n \n /**\n * Delete a form\n */\n async delete(id: string): Promise<void> {\n return apiRequest<void>('DELETE', `/forms/${id}`)\n },\n \n /**\n * Add a field to an existing form\n */\n async addField(formId: string, field: FormField): Promise<Form> {\n const form = await formsApi.get(formId)\n const maxSortOrder = Math.max(0, ...(form.fields || []).map(f => f.sortOrder || 0))\n \n return formsApi.update(formId, {\n fields: [\n ...(form.fields || []),\n { ...field, sortOrder: field.sortOrder ?? maxSortOrder + 1 }\n ]\n })\n },\n \n /**\n * Update a field in an existing form\n */\n async updateField(formId: string, fieldSlug: string, updates: Partial<FormField>): Promise<Form> {\n const form = await formsApi.get(formId)\n \n return formsApi.update(formId, {\n fields: (form.fields || []).map(f => \n f.slug === fieldSlug ? { ...f, ...updates } : f\n )\n })\n },\n \n /**\n * Remove a field from a form\n */\n async removeField(formId: string, fieldSlug: string): Promise<Form> {\n const form = await formsApi.get(formId)\n \n return formsApi.update(formId, {\n fields: (form.fields || []).filter(f => f.slug !== fieldSlug)\n })\n },\n \n /**\n * Reorder fields in a form\n */\n async reorderFields(formId: string, fieldSlugs: string[]): Promise<Form> {\n const form = await formsApi.get(formId)\n const fieldsMap = new Map((form.fields || []).map(f => [f.slug, f]))\n \n const orderedFields = fieldSlugs.map((slug, index) => {\n const field = fieldsMap.get(slug)\n if (!field) throw new Error(`Field not found: ${slug}`)\n return { ...field, sortOrder: index }\n })\n \n return formsApi.update(formId, { fields: orderedFields })\n },\n \n /**\n * Clone a form\n */\n async clone(formId: string, newSlug: string, newName?: string): Promise<Form> {\n const form = await formsApi.get(formId)\n \n return formsApi.create({\n projectId: form.projectId,\n slug: newSlug,\n name: newName || `${form.name} (Copy)`,\n description: form.description,\n formType: form.formType,\n successMessage: form.successMessage,\n redirectUrl: form.redirectUrl,\n notificationEmails: form.notificationEmails,\n submitButtonText: form.submitButtonText,\n layout: form.layout,\n showProgress: form.showProgress,\n enableSaveDraft: form.enableSaveDraft,\n isActive: false, // Clone as inactive\n fields: (form.fields || []).map(({ id, ...field }) => field), // Remove IDs\n steps: (form.steps || []).map(({ id, ...step }) => step), // Remove IDs\n })\n },\n \n /**\n * Activate or deactivate a form\n */\n async setActive(formId: string, isActive: boolean): Promise<Form> {\n return formsApi.update(formId, { isActive })\n },\n\n /**\n * Sync a form definition to the backend\n * Creates the form if it doesn't exist, updates if it does\n * Perfect for defining forms in code during development\n * \n * @example\n * ```tsx\n * // In your app initialization or form component\n * await formsApi.sync({\n * slug: 'contact',\n * name: 'Contact Form',\n * formType: 'prospect',\n * fields: [\n * field.text('name', 'Your Name', { isRequired: true }),\n * field.email('email', 'Email Address'),\n * field.phone('phone', 'Phone Number'),\n * field.textarea('message', 'Message'),\n * ]\n * })\n * ```\n */\n async sync(input: Omit<CreateFormInput, 'projectId'>): Promise<Form & { synced: boolean; created: boolean; updated: boolean }> {\n return apiRequest<Form & { synced: boolean; created: boolean; updated: boolean }>(\n 'POST',\n '/api/public/forms/sync',\n input\n )\n },\n\n /**\n * Sync multiple forms at once\n * Useful for initializing all forms in your app\n */\n async syncAll(forms: Array<Omit<CreateFormInput, 'projectId'>>): Promise<Array<Form & { synced: boolean; created: boolean; updated: boolean }>> {\n return Promise.all(forms.map(form => formsApi.sync(form)))\n },\n}\n\n// ============================================\n// Field Builder Helpers\n// ============================================\n\n/**\n * Helper functions to build field definitions\n */\nexport const field = {\n text: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'text',\n ...options,\n }),\n \n email: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'email',\n isRequired: true,\n ...options,\n }),\n \n phone: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'phone',\n ...options,\n }),\n \n textarea: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'textarea',\n ...options,\n }),\n \n select: (slug: string, label: string, choices: Array<{ value: string; label: string }>, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'select',\n options: choices,\n ...options,\n }),\n \n radio: (slug: string, label: string, choices: Array<{ value: string; label: string }>, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'radio',\n options: choices,\n ...options,\n }),\n \n checkbox: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'checkbox',\n ...options,\n }),\n \n date: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'date',\n ...options,\n }),\n \n number: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'number',\n ...options,\n }),\n \n rating: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'rating',\n ...options,\n }),\n \n file: (slug: string, label: string, options?: Partial<FormField>): FormField => ({\n slug,\n label,\n fieldType: 'file',\n ...options,\n }),\n \n hidden: (slug: string, defaultValue: string): FormField => ({\n slug,\n label: '',\n fieldType: 'hidden',\n defaultValue,\n }),\n \n heading: (slug: string, label: string): FormField => ({\n slug,\n label,\n fieldType: 'heading',\n }),\n \n paragraph: (slug: string, label: string): FormField => ({\n slug,\n label,\n fieldType: 'paragraph',\n }),\n}\n\n// ============================================\n// Form Definition Helper\n// ============================================\n\nexport interface FormDefinition extends Omit<CreateFormInput, 'projectId'> {\n slug: string\n name: string\n fields: FormField[]\n}\n\n/**\n * Define a form declaratively\n * Returns a form definition that can be synced to the backend\n * \n * @example\n * ```tsx\n * // forms/contact.ts\n * import { defineForm, field } from '@uptrade/site-kit/forms'\n * \n * export const contactForm = defineForm({\n * slug: 'contact',\n * name: 'Contact Us',\n * formType: 'prospect',\n * successMessage: 'Thanks! We\\'ll be in touch soon.',\n * fields: [\n * field.text('name', 'Your Name', { isRequired: true }),\n * field.email('email', 'Email Address'),\n * field.phone('phone', 'Phone Number'),\n * field.select('service', 'Service Needed', [\n * { value: 'consultation', label: 'Free Consultation' },\n * { value: 'representation', label: 'Legal Representation' },\n * ]),\n * field.textarea('message', 'Tell us about your case'),\n * ]\n * })\n * \n * // Then in your app:\n * await formsApi.sync(contactForm)\n * ```\n */\nexport function defineForm(definition: FormDefinition): FormDefinition {\n // Ensure fields have sort order\n const fieldsWithOrder = definition.fields.map((f, index) => ({\n ...f,\n sortOrder: f.sortOrder ?? index,\n }))\n \n return {\n ...definition,\n fields: fieldsWithOrder,\n formType: definition.formType || 'contact',\n successMessage: definition.successMessage || 'Thank you for your submission!',\n submitButtonText: definition.submitButtonText || 'Submit',\n layout: definition.layout || 'stacked',\n isActive: definition.isActive ?? true,\n }\n}\n\n/**\n * Initialize multiple forms and sync them to the backend\n * Call this once during app initialization (e.g., in layout.tsx or _app.tsx)\n * \n * @example\n * ```tsx\n * // app/layout.tsx\n * import { initializeForms } from '@uptrade/site-kit/forms'\n * import { contactForm } from './forms/contact'\n * import { consultationForm } from './forms/consultation'\n * \n * // Initialize forms (runs once per build/server start in dev)\n * if (process.env.NODE_ENV === 'development') {\n * initializeForms([contactForm, consultationForm])\n * }\n * ```\n */\nexport async function initializeForms(forms: FormDefinition[]): Promise<void> {\n if (typeof window === 'undefined') {\n // Server-side: log that forms need to be synced\n console.log(`[Site-Kit] ${forms.length} form(s) ready to sync: ${forms.map(f => f.slug).join(', ')}`)\n return\n }\n \n try {\n const results = await formsApi.syncAll(forms)\n const created = results.filter(r => r.created).length\n const updated = results.filter(r => r.updated).length\n console.log(`[Site-Kit] Forms synced: ${created} created, ${updated} updated`)\n } catch (error) {\n console.error('[Site-Kit] Failed to sync forms:', error)\n }\n}\n"]}