@ezcoder.dev/sdk 1.4.0 → 1.6.0
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.
- package/dist/{DatabaseProvider-BtYMJRqh.d.ts → DatabaseProvider-DRnx_V_u.d.ts} +7 -0
- package/dist/analytics/index.js +4 -4
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +94 -4
- package/dist/auth/index.js.map +1 -1
- package/dist/{chunk-4WGGFJPE.js → chunk-FFMYVTI2.js} +2 -2
- package/dist/{chunk-KKTY5NCR.js → chunk-FPSSXTQG.js} +2 -2
- package/dist/{chunk-X4JP7DCK.js → chunk-KWR4PA5I.js} +13 -2
- package/dist/{chunk-X4JP7DCK.js.map → chunk-KWR4PA5I.js.map} +1 -1
- package/dist/{chunk-NTA3RMYR.js → chunk-L326T7UV.js} +48 -7
- package/dist/chunk-L326T7UV.js.map +1 -0
- package/dist/chunk-VHKTBOFU.js +124 -0
- package/dist/chunk-VHKTBOFU.js.map +1 -0
- package/dist/{chunk-5QYGP7G7.js → chunk-WFDQ4YUZ.js} +448 -125
- package/dist/chunk-WFDQ4YUZ.js.map +1 -0
- package/dist/cms/index.js +2 -2
- package/dist/{config-D5ajnLCe.d.ts → config-Cb4MMhGa.d.ts} +1 -0
- package/dist/cron/index.js +2 -2
- package/dist/database/index.d.ts +1 -1
- package/dist/database/index.js +11 -10
- package/dist/email/index.js +2 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +9 -9
- package/dist/notifications/index.js +5 -5
- package/dist/payments/index.d.ts +1 -1
- package/dist/payments/index.js +4 -4
- package/dist/roles/index.js +36 -13
- package/dist/roles/index.js.map +1 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.js +4 -4
- package/dist/{types-1uP3V_pe.d.ts → types-BET19sj2.d.ts} +1 -0
- package/package.json +1 -1
- package/dist/chunk-5QYGP7G7.js.map +0 -1
- package/dist/chunk-DU6N3HVQ.js +0 -389
- package/dist/chunk-DU6N3HVQ.js.map +0 -1
- package/dist/chunk-NTA3RMYR.js.map +0 -1
- /package/dist/{chunk-4WGGFJPE.js.map → chunk-FFMYVTI2.js.map} +0 -0
- /package/dist/{chunk-KKTY5NCR.js.map → chunk-FPSSXTQG.js.map} +0 -0
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ezcoder
|
|
3
|
-
} from "./chunk-DU6N3HVQ.js";
|
|
4
|
-
import {
|
|
5
|
-
isSupabaseConfigured,
|
|
6
|
-
supabase
|
|
7
|
-
} from "./chunk-KKTY5NCR.js";
|
|
8
1
|
import {
|
|
9
2
|
env,
|
|
10
|
-
features
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// src/database/DatabaseProvider.tsx
|
|
14
|
-
import { createContext, useContext, useEffect, useMemo, useState } from "react";
|
|
3
|
+
features,
|
|
4
|
+
isNeonAuthConfigured
|
|
5
|
+
} from "./chunk-KWR4PA5I.js";
|
|
15
6
|
|
|
16
7
|
// src/core/bootstrap.ts
|
|
17
8
|
var cached = null;
|
|
@@ -52,6 +43,386 @@ function configValue(key, bakedFallback) {
|
|
|
52
43
|
return typeof v === "string" && v ? v : bakedFallback;
|
|
53
44
|
}
|
|
54
45
|
|
|
46
|
+
// src/core/platform.ts
|
|
47
|
+
var isConfigured = () => Boolean(env.EZCODER_API_URL && env.EZC_PROJECT_ID);
|
|
48
|
+
function getSessionId() {
|
|
49
|
+
if (typeof sessionStorage === "undefined") return "server";
|
|
50
|
+
let sessionId = sessionStorage.getItem("ezcoder_session_id");
|
|
51
|
+
if (!sessionId) {
|
|
52
|
+
sessionId = `sess_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
53
|
+
sessionStorage.setItem("ezcoder_session_id", sessionId);
|
|
54
|
+
}
|
|
55
|
+
return sessionId;
|
|
56
|
+
}
|
|
57
|
+
function getVisitorId() {
|
|
58
|
+
if (typeof localStorage === "undefined") return "server";
|
|
59
|
+
let visitorId = localStorage.getItem("ezcoder_visitor_id");
|
|
60
|
+
if (!visitorId) {
|
|
61
|
+
visitorId = `vis_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
62
|
+
localStorage.setItem("ezcoder_visitor_id", visitorId);
|
|
63
|
+
}
|
|
64
|
+
return visitorId;
|
|
65
|
+
}
|
|
66
|
+
var pageEntryTime = typeof window !== "undefined" ? Date.now() : 0;
|
|
67
|
+
var currentPath = typeof window !== "undefined" ? window.location.pathname : "/";
|
|
68
|
+
var maxScrollDepth = 0;
|
|
69
|
+
var trackPageEntry = () => {
|
|
70
|
+
pageEntryTime = Date.now();
|
|
71
|
+
currentPath = window.location.pathname;
|
|
72
|
+
maxScrollDepth = 0;
|
|
73
|
+
};
|
|
74
|
+
var getTimeOnPage = () => Date.now() - pageEntryTime;
|
|
75
|
+
var throttle = (fn, wait) => {
|
|
76
|
+
let lastTime = 0;
|
|
77
|
+
return (...args) => {
|
|
78
|
+
const now = Date.now();
|
|
79
|
+
if (now - lastTime >= wait) {
|
|
80
|
+
lastTime = now;
|
|
81
|
+
fn(...args);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
var trackScrollDepth = () => {
|
|
86
|
+
if (typeof window === "undefined") return;
|
|
87
|
+
const scrollTop = window.scrollY;
|
|
88
|
+
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
|
|
89
|
+
if (docHeight > 0) {
|
|
90
|
+
const scrollPercent = Math.round(scrollTop / docHeight * 100);
|
|
91
|
+
if (scrollPercent > maxScrollDepth) {
|
|
92
|
+
maxScrollDepth = Math.min(scrollPercent, 100);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var analyticsPost = async (endpoint, body) => {
|
|
97
|
+
if (!isConfigured()) {
|
|
98
|
+
return { success: false, error: "Platform not configured" };
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const response = await fetch(`${env.EZCODER_API_URL}${endpoint}`, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
headers: { "Content-Type": "application/json" },
|
|
104
|
+
body: JSON.stringify(body)
|
|
105
|
+
});
|
|
106
|
+
if (!response.ok) {
|
|
107
|
+
const error = await response.text();
|
|
108
|
+
return { success: false, error };
|
|
109
|
+
}
|
|
110
|
+
return await response.json();
|
|
111
|
+
} catch (error) {
|
|
112
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
113
|
+
return { success: false, error: message };
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var stripePost = async (endpoint, body) => {
|
|
117
|
+
if (!env.EZCODER_API_URL) {
|
|
118
|
+
return { success: false, error: "Platform not configured" };
|
|
119
|
+
}
|
|
120
|
+
if (!env.EZC_SECRET_KEY) {
|
|
121
|
+
return {
|
|
122
|
+
success: false,
|
|
123
|
+
error: "Payment configuration incomplete. The site owner needs to redeploy from EzCoder to enable checkout."
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const headers = {
|
|
128
|
+
"Content-Type": "application/json",
|
|
129
|
+
"Authorization": `Bearer ${env.EZC_SECRET_KEY}`
|
|
130
|
+
};
|
|
131
|
+
const response = await fetch(`${env.EZCODER_API_URL}${endpoint}`, {
|
|
132
|
+
method: "POST",
|
|
133
|
+
headers,
|
|
134
|
+
body: JSON.stringify(body)
|
|
135
|
+
});
|
|
136
|
+
if (!response.ok) {
|
|
137
|
+
const error = await response.text();
|
|
138
|
+
return { success: false, error };
|
|
139
|
+
}
|
|
140
|
+
return await response.json();
|
|
141
|
+
} catch (error) {
|
|
142
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
143
|
+
return { success: false, error: message };
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
var stripeGet = async (endpoint) => {
|
|
147
|
+
if (!env.EZCODER_API_URL) {
|
|
148
|
+
return { success: false, error: "Platform not configured" };
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const headers = { "Content-Type": "application/json" };
|
|
152
|
+
if (env.EZC_SECRET_KEY) {
|
|
153
|
+
headers["Authorization"] = `Bearer ${env.EZC_SECRET_KEY}`;
|
|
154
|
+
}
|
|
155
|
+
const response = await fetch(`${env.EZCODER_API_URL}${endpoint}`, {
|
|
156
|
+
method: "GET",
|
|
157
|
+
headers
|
|
158
|
+
});
|
|
159
|
+
if (!response.ok) {
|
|
160
|
+
const error = await response.text();
|
|
161
|
+
return { success: false, error };
|
|
162
|
+
}
|
|
163
|
+
return await response.json();
|
|
164
|
+
} catch (error) {
|
|
165
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
166
|
+
return { success: false, error: message };
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
var sendPageExit = () => {
|
|
170
|
+
if (!isConfigured() || typeof navigator === "undefined") return;
|
|
171
|
+
const payload = JSON.stringify({
|
|
172
|
+
type: "page_exit",
|
|
173
|
+
projectId: env.EZC_PROJECT_ID,
|
|
174
|
+
sessionId: getSessionId(),
|
|
175
|
+
visitorId: getVisitorId(),
|
|
176
|
+
pathname: currentPath,
|
|
177
|
+
timeOnPage: getTimeOnPage(),
|
|
178
|
+
scrollDepth: maxScrollDepth,
|
|
179
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
180
|
+
});
|
|
181
|
+
if (navigator.sendBeacon) {
|
|
182
|
+
navigator.sendBeacon(`${env.EZCODER_API_URL}/api/analytics/collect`, payload);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
var ezcoder = {
|
|
186
|
+
isConfigured,
|
|
187
|
+
analytics: {
|
|
188
|
+
track: (eventType, properties = {}) => {
|
|
189
|
+
return analyticsPost("/api/analytics/collect", {
|
|
190
|
+
type: eventType,
|
|
191
|
+
projectId: env.EZC_PROJECT_ID,
|
|
192
|
+
sessionId: getSessionId(),
|
|
193
|
+
visitorId: getVisitorId(),
|
|
194
|
+
url: typeof window !== "undefined" ? window.location.href : "",
|
|
195
|
+
pathname: typeof window !== "undefined" ? window.location.pathname : "/",
|
|
196
|
+
referrer: typeof document !== "undefined" ? document.referrer : "",
|
|
197
|
+
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "",
|
|
198
|
+
screenResolution: typeof window !== "undefined" ? `${window.screen.width}x${window.screen.height}` : "",
|
|
199
|
+
viewport: typeof window !== "undefined" ? `${window.innerWidth}x${window.innerHeight}` : "",
|
|
200
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
201
|
+
metadata: properties
|
|
202
|
+
});
|
|
203
|
+
},
|
|
204
|
+
pageView: (path) => {
|
|
205
|
+
trackPageEntry();
|
|
206
|
+
return ezcoder.analytics.track("page_view", {
|
|
207
|
+
path: path || (typeof window !== "undefined" ? window.location.pathname : "/"),
|
|
208
|
+
title: typeof document !== "undefined" ? document.title : ""
|
|
209
|
+
});
|
|
210
|
+
},
|
|
211
|
+
identify: (userId, traits = {}) => {
|
|
212
|
+
return ezcoder.analytics.track("identify", { userId, ...traits });
|
|
213
|
+
},
|
|
214
|
+
error: (message, context = {}) => {
|
|
215
|
+
return ezcoder.analytics.track("error", {
|
|
216
|
+
message,
|
|
217
|
+
...context,
|
|
218
|
+
stack: context.stack || new Error().stack
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
stripe: {
|
|
223
|
+
createCheckout: async (priceId, options = {}) => {
|
|
224
|
+
const result = await stripePost("/api/stripe/create-checkout", {
|
|
225
|
+
priceId,
|
|
226
|
+
projectId: env.EZC_PROJECT_ID,
|
|
227
|
+
successUrl: options.successUrl || `${typeof window !== "undefined" ? window.location.origin : ""}/payment/success`,
|
|
228
|
+
cancelUrl: options.cancelUrl || `${typeof window !== "undefined" ? window.location.origin : ""}/payment/cancel`,
|
|
229
|
+
customerEmail: options.customerEmail,
|
|
230
|
+
quantity: options.quantity || 1
|
|
231
|
+
});
|
|
232
|
+
if (result.url && options.redirect !== false && typeof window !== "undefined") {
|
|
233
|
+
window.location.href = result.url;
|
|
234
|
+
}
|
|
235
|
+
return result;
|
|
236
|
+
},
|
|
237
|
+
getProducts: async () => {
|
|
238
|
+
return { products: [], message: "Products managed via EzCoder dashboard" };
|
|
239
|
+
},
|
|
240
|
+
verifySession: async (sessionId) => {
|
|
241
|
+
if (!sessionId) {
|
|
242
|
+
return { success: false, error: "Session ID is required" };
|
|
243
|
+
}
|
|
244
|
+
return stripeGet(`/api/stripe/verify-session?session_id=${encodeURIComponent(sessionId)}`);
|
|
245
|
+
},
|
|
246
|
+
getCustomerStatus: async (options = {}) => {
|
|
247
|
+
const params = new URLSearchParams();
|
|
248
|
+
if (options.customerId) params.set("customer_id", options.customerId);
|
|
249
|
+
if (options.email) params.set("email", options.email);
|
|
250
|
+
if (!options.customerId && !options.email) {
|
|
251
|
+
return { success: false, error: "Either customerId or email is required" };
|
|
252
|
+
}
|
|
253
|
+
return stripeGet(`/api/stripe/customer-status?${params.toString()}`);
|
|
254
|
+
},
|
|
255
|
+
createPortalSession: async (customerId, options = {}) => {
|
|
256
|
+
const result = await stripePost("/api/stripe/customer-portal", {
|
|
257
|
+
customerId,
|
|
258
|
+
returnUrl: options.returnUrl || window.location.href
|
|
259
|
+
});
|
|
260
|
+
if (result.url && options.redirect !== false && typeof window !== "undefined") {
|
|
261
|
+
window.location.href = result.url;
|
|
262
|
+
}
|
|
263
|
+
return result;
|
|
264
|
+
},
|
|
265
|
+
getInvoices: async (customerId, options = {}) => {
|
|
266
|
+
const params = new URLSearchParams();
|
|
267
|
+
params.set("customer_id", customerId);
|
|
268
|
+
if (options.limit) params.set("limit", String(options.limit));
|
|
269
|
+
return stripeGet(`/api/stripe/invoices?${params.toString()}`);
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
users: {
|
|
273
|
+
trackSignup: (userId, email, role = null) => {
|
|
274
|
+
return ezcoder.analytics.track("user_signup", { userId, email, role, signupMethod: "email" });
|
|
275
|
+
},
|
|
276
|
+
trackLogin: (userId) => {
|
|
277
|
+
return ezcoder.analytics.track("user_login", { userId });
|
|
278
|
+
},
|
|
279
|
+
trackLogout: (userId) => {
|
|
280
|
+
return ezcoder.analytics.track("user_logout", { userId });
|
|
281
|
+
},
|
|
282
|
+
trackRoleChange: (userId, oldRole, newRole) => {
|
|
283
|
+
return ezcoder.analytics.track("role_change", { userId, oldRole, newRole });
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
var ezcoderAuthIntegration = {
|
|
288
|
+
onLogin: (user) => {
|
|
289
|
+
if (user?.id) {
|
|
290
|
+
ezcoder.analytics.identify(user.id, {
|
|
291
|
+
email: user.email,
|
|
292
|
+
name: user.user_metadata?.full_name
|
|
293
|
+
});
|
|
294
|
+
ezcoder.users.trackLogin(user.id);
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
onSignup: (user) => {
|
|
298
|
+
if (user?.id) {
|
|
299
|
+
ezcoder.analytics.identify(user.id, { email: user.email });
|
|
300
|
+
ezcoder.users.trackSignup(user.id, user.email || "");
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
onLogout: (userId) => {
|
|
304
|
+
if (userId) {
|
|
305
|
+
ezcoder.users.trackLogout(userId);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
var trackWebVitals = () => {
|
|
310
|
+
if (typeof window === "undefined" || !("PerformanceObserver" in window)) return;
|
|
311
|
+
try {
|
|
312
|
+
new PerformanceObserver((list) => {
|
|
313
|
+
const entries = list.getEntries();
|
|
314
|
+
const lastEntry = entries[entries.length - 1];
|
|
315
|
+
if (lastEntry) {
|
|
316
|
+
ezcoder.analytics.track("web_vital", {
|
|
317
|
+
metric: "LCP",
|
|
318
|
+
value: Math.round(lastEntry.startTime),
|
|
319
|
+
pathname: window.location.pathname
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}).observe({ type: "largest-contentful-paint", buffered: true });
|
|
323
|
+
} catch {
|
|
324
|
+
}
|
|
325
|
+
try {
|
|
326
|
+
new PerformanceObserver((list) => {
|
|
327
|
+
const entry = list.getEntries()[0];
|
|
328
|
+
if (entry) {
|
|
329
|
+
ezcoder.analytics.track("web_vital", {
|
|
330
|
+
metric: "FID",
|
|
331
|
+
value: Math.round(entry.processingStart - entry.startTime),
|
|
332
|
+
pathname: window.location.pathname
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}).observe({ type: "first-input", buffered: true });
|
|
336
|
+
} catch {
|
|
337
|
+
}
|
|
338
|
+
try {
|
|
339
|
+
let clsValue = 0;
|
|
340
|
+
new PerformanceObserver((list) => {
|
|
341
|
+
for (const entry of list.getEntries()) {
|
|
342
|
+
if (!entry.hadRecentInput) {
|
|
343
|
+
clsValue += entry.value;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}).observe({ type: "layout-shift", buffered: true });
|
|
347
|
+
document.addEventListener("visibilitychange", () => {
|
|
348
|
+
if (document.hidden && clsValue > 0) {
|
|
349
|
+
ezcoder.analytics.track("web_vital", {
|
|
350
|
+
metric: "CLS",
|
|
351
|
+
value: Math.round(clsValue * 1e3) / 1e3,
|
|
352
|
+
pathname: window.location.pathname
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
} catch {
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
var setupErrorTracking = () => {
|
|
360
|
+
if (typeof window === "undefined") return;
|
|
361
|
+
window.onerror = (message, source, lineno, colno, error) => {
|
|
362
|
+
ezcoder.analytics.track("js_error", {
|
|
363
|
+
message: String(message),
|
|
364
|
+
source,
|
|
365
|
+
lineno,
|
|
366
|
+
colno,
|
|
367
|
+
stack: error?.stack,
|
|
368
|
+
pathname: window.location.pathname
|
|
369
|
+
});
|
|
370
|
+
return false;
|
|
371
|
+
};
|
|
372
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
373
|
+
ezcoder.analytics.track("promise_rejection", {
|
|
374
|
+
reason: event.reason?.message || String(event.reason),
|
|
375
|
+
stack: event.reason?.stack,
|
|
376
|
+
pathname: window.location.pathname
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
};
|
|
380
|
+
if (typeof window !== "undefined") {
|
|
381
|
+
window.addEventListener("scroll", throttle(trackScrollDepth, 500), { passive: true });
|
|
382
|
+
window.addEventListener("beforeunload", sendPageExit);
|
|
383
|
+
document.addEventListener("visibilitychange", () => {
|
|
384
|
+
if (!isConfigured()) return;
|
|
385
|
+
if (document.hidden) {
|
|
386
|
+
ezcoder.analytics.track("page_blur", {
|
|
387
|
+
timeOnPage: getTimeOnPage(),
|
|
388
|
+
scrollDepth: maxScrollDepth,
|
|
389
|
+
pathname: currentPath
|
|
390
|
+
});
|
|
391
|
+
} else {
|
|
392
|
+
ezcoder.analytics.track("page_focus", { pathname: window.location.pathname });
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
const originalPushState = history.pushState;
|
|
396
|
+
history.pushState = function(...args) {
|
|
397
|
+
sendPageExit();
|
|
398
|
+
originalPushState.apply(this, args);
|
|
399
|
+
trackPageEntry();
|
|
400
|
+
if (isConfigured()) ezcoder.analytics.pageView();
|
|
401
|
+
};
|
|
402
|
+
const originalReplaceState = history.replaceState;
|
|
403
|
+
history.replaceState = function(...args) {
|
|
404
|
+
originalReplaceState.apply(this, args);
|
|
405
|
+
trackPageEntry();
|
|
406
|
+
};
|
|
407
|
+
window.addEventListener("popstate", () => {
|
|
408
|
+
sendPageExit();
|
|
409
|
+
trackPageEntry();
|
|
410
|
+
if (isConfigured()) ezcoder.analytics.pageView();
|
|
411
|
+
});
|
|
412
|
+
if (isConfigured()) {
|
|
413
|
+
setTimeout(() => {
|
|
414
|
+
ezcoder.analytics.pageView();
|
|
415
|
+
trackWebVitals();
|
|
416
|
+
setupErrorTracking();
|
|
417
|
+
}, 100);
|
|
418
|
+
}
|
|
419
|
+
if (typeof window === "undefined" && env.EZCODER_API_URL && !env.EZC_SECRET_KEY) {
|
|
420
|
+
console.warn(
|
|
421
|
+
"[EzCoder SDK] EZCODER_SECRET_KEY is not set \u2014 Stripe checkout and authenticated API calls will fail. Redeploy your project from the EzCoder editor to auto-provision keys."
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
55
426
|
// src/database/errors.ts
|
|
56
427
|
var DatabaseError = class extends Error {
|
|
57
428
|
constructor(message, code = "DATABASE_ERROR", statusCode = 500) {
|
|
@@ -124,7 +495,7 @@ function assertSafeSelectColumns(columns) {
|
|
|
124
495
|
}
|
|
125
496
|
}
|
|
126
497
|
var QueryBuilder = class {
|
|
127
|
-
constructor(
|
|
498
|
+
constructor(supabase, projectId, table, serverProxy) {
|
|
128
499
|
this.operation = "select";
|
|
129
500
|
this.selectColumns = "*";
|
|
130
501
|
this.filters = [];
|
|
@@ -136,7 +507,7 @@ var QueryBuilder = class {
|
|
|
136
507
|
this.upsertConflict = null;
|
|
137
508
|
this.singleMode = false;
|
|
138
509
|
this.maybeSingleMode = false;
|
|
139
|
-
this.supabase =
|
|
510
|
+
this.supabase = supabase;
|
|
140
511
|
this.projectId = projectId;
|
|
141
512
|
this.table = table;
|
|
142
513
|
this.serverProxy = serverProxy;
|
|
@@ -374,12 +745,27 @@ function trackDbEvent(event, props) {
|
|
|
374
745
|
} catch {
|
|
375
746
|
}
|
|
376
747
|
}
|
|
748
|
+
var cachedNeonJwt = null;
|
|
749
|
+
var NEON_JWT_REFRESH_SKEW_MS = 3e4;
|
|
750
|
+
function decodeJwtExp(token) {
|
|
751
|
+
try {
|
|
752
|
+
const parts = token.split(".");
|
|
753
|
+
if (parts.length < 2) return 0;
|
|
754
|
+
let b64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
755
|
+
while (b64.length % 4) b64 += "=";
|
|
756
|
+
const json = typeof atob === "function" ? atob(b64) : Buffer.from(b64, "base64").toString("binary");
|
|
757
|
+
const payload = JSON.parse(json);
|
|
758
|
+
return typeof payload.exp === "number" ? payload.exp : 0;
|
|
759
|
+
} catch {
|
|
760
|
+
return 0;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
377
763
|
var MAX_RETRIES = 3;
|
|
378
764
|
var SERVER_TIMEOUT_MS = 8e3;
|
|
379
765
|
var DatabaseClient = class _DatabaseClient {
|
|
380
|
-
constructor(
|
|
766
|
+
constructor(supabase, projectId) {
|
|
381
767
|
this.serverMode = false;
|
|
382
|
-
this.supabase =
|
|
768
|
+
this.supabase = supabase;
|
|
383
769
|
this.projectId = projectId;
|
|
384
770
|
this.platformUrl = env.EZCODER_API_URL || "https://ezcoder.dev";
|
|
385
771
|
}
|
|
@@ -452,6 +838,10 @@ var DatabaseClient = class _DatabaseClient {
|
|
|
452
838
|
if (this.serverMode && this.apiKey) {
|
|
453
839
|
return { Authorization: `Bearer ${this.apiKey}` };
|
|
454
840
|
}
|
|
841
|
+
if (isNeonAuthConfigured && env.NEON_AUTH_URL) {
|
|
842
|
+
const token = await this._neonSessionJwt();
|
|
843
|
+
if (token) return { Authorization: `Bearer ${token}` };
|
|
844
|
+
}
|
|
455
845
|
if (this.supabase?.auth?.getSession) {
|
|
456
846
|
let sessionResult;
|
|
457
847
|
try {
|
|
@@ -466,6 +856,44 @@ var DatabaseClient = class _DatabaseClient {
|
|
|
466
856
|
if (pub) return { "X-EzCoder-Public-Token": pub };
|
|
467
857
|
return {};
|
|
468
858
|
}
|
|
859
|
+
/**
|
|
860
|
+
* Return a fresh Neon Better Auth session JWT (cached in-memory until ~30s
|
|
861
|
+
* before its exp), or '' when logged out / unavailable. NEVER throws — a
|
|
862
|
+
* failure falls through to the anonymous data path. Browser-only by nature
|
|
863
|
+
* (relies on the HttpOnly session cookie via credentials:'include').
|
|
864
|
+
*/
|
|
865
|
+
async _neonSessionJwt() {
|
|
866
|
+
if (typeof window === "undefined") return "";
|
|
867
|
+
const now = Date.now();
|
|
868
|
+
if (cachedNeonJwt && cachedNeonJwt.exp * 1e3 - NEON_JWT_REFRESH_SKEW_MS > now) {
|
|
869
|
+
return cachedNeonJwt.token;
|
|
870
|
+
}
|
|
871
|
+
const base = (env.NEON_AUTH_URL || "").replace(/\/$/, "");
|
|
872
|
+
if (!base) return "";
|
|
873
|
+
try {
|
|
874
|
+
const res = await fetch(`${base}/token`, {
|
|
875
|
+
method: "GET",
|
|
876
|
+
credentials: "include",
|
|
877
|
+
signal: AbortSignal.timeout(SERVER_TIMEOUT_MS)
|
|
878
|
+
});
|
|
879
|
+
if (!res.ok) {
|
|
880
|
+
cachedNeonJwt = null;
|
|
881
|
+
return "";
|
|
882
|
+
}
|
|
883
|
+
const body = await res.json().catch(() => null);
|
|
884
|
+
const token = body?.token;
|
|
885
|
+
if (!token) {
|
|
886
|
+
cachedNeonJwt = null;
|
|
887
|
+
return "";
|
|
888
|
+
}
|
|
889
|
+
const exp = decodeJwtExp(token);
|
|
890
|
+
cachedNeonJwt = { token, exp };
|
|
891
|
+
return token;
|
|
892
|
+
} catch {
|
|
893
|
+
cachedNeonJwt = null;
|
|
894
|
+
return "";
|
|
895
|
+
}
|
|
896
|
+
}
|
|
469
897
|
/** Platform API base — runtime bootstrap wins over the baked value so an
|
|
470
898
|
* env-less build still reaches the right host. */
|
|
471
899
|
baseUrl() {
|
|
@@ -504,123 +932,18 @@ var DatabaseClient = class _DatabaseClient {
|
|
|
504
932
|
}
|
|
505
933
|
};
|
|
506
934
|
|
|
507
|
-
// src/database/DatabaseProvider.tsx
|
|
508
|
-
import { jsx } from "react/jsx-runtime";
|
|
509
|
-
var DatabaseContext = createContext({
|
|
510
|
-
db: null,
|
|
511
|
-
isConfigured: false
|
|
512
|
-
});
|
|
513
|
-
function DatabaseProvider({ children, projectId }) {
|
|
514
|
-
const bakedProjectId = projectId || env.EZC_PROJECT_ID || "";
|
|
515
|
-
const [runtimeProjectId, setRuntimeProjectId] = useState(getRuntimeConfig()?.projectId || "");
|
|
516
|
-
const [bootstrapAttempted, setBootstrapAttempted] = useState(Boolean(getRuntimeConfig()));
|
|
517
|
-
useEffect(() => {
|
|
518
|
-
if (bakedProjectId) return;
|
|
519
|
-
let cancelled = false;
|
|
520
|
-
loadBootstrap().then((rc) => {
|
|
521
|
-
if (cancelled) return;
|
|
522
|
-
if (rc?.projectId) setRuntimeProjectId(rc.projectId);
|
|
523
|
-
setBootstrapAttempted(true);
|
|
524
|
-
});
|
|
525
|
-
return () => {
|
|
526
|
-
cancelled = true;
|
|
527
|
-
};
|
|
528
|
-
}, [bakedProjectId]);
|
|
529
|
-
const resolvedProjectId = bakedProjectId || runtimeProjectId;
|
|
530
|
-
const configured = Boolean(resolvedProjectId);
|
|
531
|
-
const db = useMemo(
|
|
532
|
-
() => configured ? new DatabaseClient(supabase, resolvedProjectId) : null,
|
|
533
|
-
[configured, resolvedProjectId]
|
|
534
|
-
);
|
|
535
|
-
const value = useMemo(() => ({ db, isConfigured: configured }), [db, configured]);
|
|
536
|
-
if (!bakedProjectId && !bootstrapAttempted && !runtimeProjectId) {
|
|
537
|
-
return null;
|
|
538
|
-
}
|
|
539
|
-
return /* @__PURE__ */ jsx(DatabaseContext.Provider, { value, children });
|
|
540
|
-
}
|
|
541
|
-
function useDatabase() {
|
|
542
|
-
const { db } = useContext(DatabaseContext);
|
|
543
|
-
if (!db) {
|
|
544
|
-
throw new Error(
|
|
545
|
-
"useDatabase() must be used within <DatabaseProvider>. Ensure the app is wrapped in <DatabaseProvider> and the project has a deployment origin or EZC_PROJECT_ID."
|
|
546
|
-
);
|
|
547
|
-
}
|
|
548
|
-
return db;
|
|
549
|
-
}
|
|
550
|
-
function useDatabaseOptional() {
|
|
551
|
-
const { db } = useContext(DatabaseContext);
|
|
552
|
-
return db;
|
|
553
|
-
}
|
|
554
|
-
function useIsDatabaseConfigured() {
|
|
555
|
-
const { isConfigured } = useContext(DatabaseContext);
|
|
556
|
-
return isConfigured;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// src/database/useRealtime.ts
|
|
560
|
-
import { useEffect as useEffect2, useState as useState2, useRef } from "react";
|
|
561
|
-
function useRealtime(table, options = {}) {
|
|
562
|
-
const [data, setData] = useState2([]);
|
|
563
|
-
const [status, setStatus] = useState2("connecting");
|
|
564
|
-
const optionsRef = useRef(options);
|
|
565
|
-
optionsRef.current = options;
|
|
566
|
-
const projectId = env.EZC_PROJECT_ID;
|
|
567
|
-
useEffect2(() => {
|
|
568
|
-
if (!isSupabaseConfigured || !projectId) {
|
|
569
|
-
setStatus("disabled");
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
const schemaName = `proj_${projectId.replace(/-/g, "_")}`;
|
|
573
|
-
const channelName = `${schemaName}_${table}_${optionsRef.current.event || "all"}`;
|
|
574
|
-
const channel = supabase.channel(channelName).on(
|
|
575
|
-
"postgres_changes",
|
|
576
|
-
{
|
|
577
|
-
event: optionsRef.current.event || "*",
|
|
578
|
-
schema: schemaName,
|
|
579
|
-
table,
|
|
580
|
-
filter: optionsRef.current.filter
|
|
581
|
-
},
|
|
582
|
-
(payload) => {
|
|
583
|
-
if (payload.eventType === "INSERT") {
|
|
584
|
-
setData((prev) => [...prev, payload.new]);
|
|
585
|
-
} else if (payload.eventType === "UPDATE") {
|
|
586
|
-
setData(
|
|
587
|
-
(prev) => prev.map(
|
|
588
|
-
(item) => item.id === payload.new.id ? payload.new : item
|
|
589
|
-
)
|
|
590
|
-
);
|
|
591
|
-
} else if (payload.eventType === "DELETE") {
|
|
592
|
-
setData(
|
|
593
|
-
(prev) => prev.filter(
|
|
594
|
-
(item) => item.id !== payload.old.id
|
|
595
|
-
)
|
|
596
|
-
);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
).subscribe((subStatus) => {
|
|
600
|
-
setStatus(subStatus === "SUBSCRIBED" ? "connected" : "connecting");
|
|
601
|
-
});
|
|
602
|
-
return () => {
|
|
603
|
-
supabase.removeChannel(channel);
|
|
604
|
-
};
|
|
605
|
-
}, [projectId, table]);
|
|
606
|
-
return { data, status, setData };
|
|
607
|
-
}
|
|
608
|
-
|
|
609
935
|
export {
|
|
610
936
|
loadBootstrap,
|
|
611
937
|
getRuntimeConfig,
|
|
612
938
|
configValue,
|
|
939
|
+
ezcoder,
|
|
940
|
+
ezcoderAuthIntegration,
|
|
613
941
|
DatabaseError,
|
|
614
942
|
QueryError,
|
|
615
943
|
ValidationError,
|
|
616
944
|
ConnectionError,
|
|
617
945
|
NotFoundError,
|
|
618
946
|
QueryBuilder,
|
|
619
|
-
DatabaseClient
|
|
620
|
-
DatabaseProvider,
|
|
621
|
-
useDatabase,
|
|
622
|
-
useDatabaseOptional,
|
|
623
|
-
useIsDatabaseConfigured,
|
|
624
|
-
useRealtime
|
|
947
|
+
DatabaseClient
|
|
625
948
|
};
|
|
626
|
-
//# sourceMappingURL=chunk-
|
|
949
|
+
//# sourceMappingURL=chunk-WFDQ4YUZ.js.map
|