@access-dlsu/leapify 0.260507.1 → 0.260507.4
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/app.d.ts.map +1 -1
- package/dist/{chunk-QARF2YFF.cjs → chunk-BFMJDSDI.cjs} +3 -2
- package/dist/chunk-BFMJDSDI.cjs.map +1 -0
- package/dist/{chunk-ANNHE3PZ.js → chunk-LJ5BSSYE.js} +3 -2
- package/dist/{chunk-QARF2YFF.cjs.map → chunk-LJ5BSSYE.js.map} +1 -1
- package/dist/{chunk-63CUZGSZ.js → chunk-MCOLCTFX.js} +3 -2
- package/dist/chunk-MCOLCTFX.js.map +1 -0
- package/dist/{chunk-YFJBE3AU.cjs → chunk-MKWVLWVJ.cjs} +3 -2
- package/dist/chunk-MKWVLWVJ.cjs.map +1 -0
- package/dist/client/index.cjs +25 -25
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.ts +17 -17
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +25 -25
- package/dist/client/index.js.map +1 -1
- package/dist/client/types.d.ts +4 -2
- package/dist/client/types.d.ts.map +1 -1
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/schema/{events.d.ts → classes.d.ts} +3 -3
- package/dist/db/schema/classes.d.ts.map +1 -0
- package/dist/db/schema/index.d.ts +1 -1
- package/dist/db/schema/index.d.ts.map +1 -1
- package/dist/db/schema/site-config.d.ts +83 -0
- package/dist/db/schema/site-config.d.ts.map +1 -1
- package/dist/index.cjs +640 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +616 -33
- package/dist/index.js.map +1 -1
- package/dist/lib/middleware/pow-challenge.cjs +6 -6
- package/dist/lib/middleware/pow-challenge.d.ts.map +1 -1
- package/dist/lib/middleware/pow-challenge.js +1 -1
- package/dist/routes/classes.d.ts +4 -0
- package/dist/routes/classes.d.ts.map +1 -0
- package/dist/routes/contentful-sync.d.ts +4 -0
- package/dist/routes/contentful-sync.d.ts.map +1 -0
- package/dist/services/snapshot.d.ts +1 -1
- package/dist/services/snapshot.d.ts.map +1 -1
- package/dist/types.d.ts +19 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/worker-handler.d.ts.map +1 -1
- package/dist/worker.js +605 -29
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-63CUZGSZ.js.map +0 -1
- package/dist/chunk-ANNHE3PZ.js.map +0 -1
- package/dist/chunk-YFJBE3AU.cjs.map +0 -1
- package/dist/db/schema/events.d.ts.map +0 -1
- package/dist/routes/events.d.ts +0 -4
- package/dist/routes/events.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var chunkOK6RVPEH_cjs = require('./chunk-OK6RVPEH.cjs');
|
|
4
4
|
var chunkRFP2X2FA_cjs = require('./chunk-RFP2X2FA.cjs');
|
|
5
5
|
require('./chunk-JPVIXCF5.cjs');
|
|
6
|
-
var
|
|
6
|
+
var chunkBFMJDSDI_cjs = require('./chunk-BFMJDSDI.cjs');
|
|
7
7
|
var chunk5JKLV7IE_cjs = require('./chunk-5JKLV7IE.cjs');
|
|
8
8
|
require('./chunk-NKIQRCOM.cjs');
|
|
9
9
|
var chunk4DPT2KQR_cjs = require('./chunk-4DPT2KQR.cjs');
|
|
@@ -50,6 +50,18 @@ var errorHandler = (err, c) => {
|
|
|
50
50
|
);
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
+
// src/types.ts
|
|
54
|
+
function parseCmsMode(raw) {
|
|
55
|
+
if (raw === "cloudflare" || raw === "contentful") return raw;
|
|
56
|
+
return "hybrid";
|
|
57
|
+
}
|
|
58
|
+
function shouldPushToContentful(mode) {
|
|
59
|
+
return mode === "hybrid";
|
|
60
|
+
}
|
|
61
|
+
function shouldPullFromContentful(mode) {
|
|
62
|
+
return mode === "contentful" || mode === "hybrid";
|
|
63
|
+
}
|
|
64
|
+
|
|
53
65
|
// node_modules/hono/dist/middleware/cors/index.js
|
|
54
66
|
var cors = (options) => {
|
|
55
67
|
const opts = {
|
|
@@ -161,7 +173,7 @@ function createCorsMiddleware(allowedOrigins) {
|
|
|
161
173
|
function createRefererGuard(allowedOrigins) {
|
|
162
174
|
const MUTATION_METHODS = /* @__PURE__ */ new Set(["POST", "PATCH", "PUT", "DELETE"]);
|
|
163
175
|
const SKIP_PREFIXES = ["/health", "/internal", "/api/auth", "/.well-known"];
|
|
164
|
-
return
|
|
176
|
+
return chunkBFMJDSDI_cjs.createMiddleware(async (c, next) => {
|
|
165
177
|
if (!MUTATION_METHODS.has(c.req.method)) return next();
|
|
166
178
|
if (SKIP_PREFIXES.some((p) => c.req.path.startsWith(p))) return next();
|
|
167
179
|
if (allowedOrigins.includes("*")) return next();
|
|
@@ -36332,12 +36344,14 @@ function drizzle(client, config3 = {}) {
|
|
|
36332
36344
|
// src/db/schema/index.ts
|
|
36333
36345
|
var schema_exports = {};
|
|
36334
36346
|
chunkEMMSS5I5_cjs.__export(schema_exports, {
|
|
36347
|
+
CONTENTFUL_CONFIG_KEYS: () => CONTENTFUL_CONFIG_KEYS,
|
|
36335
36348
|
authAccount: () => authAccount,
|
|
36336
36349
|
authSession: () => authSession,
|
|
36337
36350
|
authUser: () => authUser,
|
|
36338
36351
|
authVerification: () => authVerification,
|
|
36339
36352
|
bookmarks: () => bookmarks,
|
|
36340
36353
|
bookmarksRelations: () => bookmarksRelations,
|
|
36354
|
+
contentfulConfig: () => contentfulConfig,
|
|
36341
36355
|
events: () => events,
|
|
36342
36356
|
eventsRelations: () => eventsRelations,
|
|
36343
36357
|
faqs: () => faqs,
|
|
@@ -36389,7 +36403,7 @@ var organizationsRelations = relations(organizations, ({ many }) => ({
|
|
|
36389
36403
|
events: many(events)
|
|
36390
36404
|
}));
|
|
36391
36405
|
|
|
36392
|
-
// src/db/schema/
|
|
36406
|
+
// src/db/schema/classes.ts
|
|
36393
36407
|
var events = sqliteTable(
|
|
36394
36408
|
"events",
|
|
36395
36409
|
{
|
|
@@ -36414,7 +36428,7 @@ var events = sqliteTable(
|
|
|
36414
36428
|
// start time string
|
|
36415
36429
|
endTime: text("end_time"),
|
|
36416
36430
|
// end time string
|
|
36417
|
-
|
|
36431
|
+
isSpotlight: integer2("is_spotlight", { mode: "boolean" }).notNull().default(false),
|
|
36418
36432
|
// Slot tracking (local counter — NOT polled from Google Forms)
|
|
36419
36433
|
maxSlots: integer2("max_slots").notNull().default(0),
|
|
36420
36434
|
registeredSlots: integer2("registered_slots").notNull().default(0),
|
|
@@ -36471,6 +36485,18 @@ var siteConfig = sqliteTable("site_config", {
|
|
|
36471
36485
|
// JSON-serializable string
|
|
36472
36486
|
updatedAt: integer2("updated_at").notNull().default(sql2`(unixepoch())`)
|
|
36473
36487
|
});
|
|
36488
|
+
var CONTENTFUL_CONFIG_KEYS = {
|
|
36489
|
+
ENABLED: "contentful.enabled",
|
|
36490
|
+
SPACE_ID: "contentful.spaceId",
|
|
36491
|
+
MANAGEMENT_TOKEN: "contentful.managementToken",
|
|
36492
|
+
DEFAULT_SPACE_ID: "dlsu-events"
|
|
36493
|
+
};
|
|
36494
|
+
var contentfulConfig = sqliteTable("contentful_config", {
|
|
36495
|
+
space_id: text("space_id"),
|
|
36496
|
+
contentful_enabled: integer2("contentful_enabled").notNull().default(0),
|
|
36497
|
+
last_sync_at: integer2("last_sync_at"),
|
|
36498
|
+
updated_at: integer2("updated_at").default(sql2`(unixepoch())`).notNull()
|
|
36499
|
+
});
|
|
36474
36500
|
|
|
36475
36501
|
// src/db/schema/faqs.ts
|
|
36476
36502
|
var faqs = sqliteTable("faqs", {
|
|
@@ -36686,7 +36712,7 @@ async function resolveUser(env2, betterAuthUserId, betterAuthUserEmail, betterAu
|
|
|
36686
36712
|
emailVerified: betterAuthEmailVerified
|
|
36687
36713
|
};
|
|
36688
36714
|
}
|
|
36689
|
-
var authMiddleware =
|
|
36715
|
+
var authMiddleware = chunkBFMJDSDI_cjs.createMiddleware(
|
|
36690
36716
|
async (c, next) => {
|
|
36691
36717
|
const rawToken = extractRawToken(c);
|
|
36692
36718
|
if (rawToken) {
|
|
@@ -36728,7 +36754,7 @@ var authMiddleware = chunkQARF2YFF_cjs.createMiddleware(
|
|
|
36728
36754
|
return next();
|
|
36729
36755
|
}
|
|
36730
36756
|
);
|
|
36731
|
-
var optionalAuthMiddleware =
|
|
36757
|
+
var optionalAuthMiddleware = chunkBFMJDSDI_cjs.createMiddleware(async (c, next) => {
|
|
36732
36758
|
const rawToken = extractRawToken(c);
|
|
36733
36759
|
if (!rawToken) {
|
|
36734
36760
|
c.set("user", null);
|
|
@@ -36736,7 +36762,7 @@ var optionalAuthMiddleware = chunkQARF2YFF_cjs.createMiddleware(async (c, next)
|
|
|
36736
36762
|
}
|
|
36737
36763
|
return authMiddleware(c, next);
|
|
36738
36764
|
});
|
|
36739
|
-
var adminMiddleware =
|
|
36765
|
+
var adminMiddleware = chunkBFMJDSDI_cjs.createMiddleware(
|
|
36740
36766
|
async (c, next) => {
|
|
36741
36767
|
const user = c.get("user");
|
|
36742
36768
|
if (!user || !["admin", "super_admin"].includes(user.role)) {
|
|
@@ -36745,7 +36771,7 @@ var adminMiddleware = chunkQARF2YFF_cjs.createMiddleware(
|
|
|
36745
36771
|
return next();
|
|
36746
36772
|
}
|
|
36747
36773
|
);
|
|
36748
|
-
var internalMiddleware =
|
|
36774
|
+
var internalMiddleware = chunkBFMJDSDI_cjs.createMiddleware(async (c, next) => {
|
|
36749
36775
|
const secret = c.req.header("X-Internal-Secret");
|
|
36750
36776
|
if (!secret || secret !== c.env.INTERNAL_API_SECRET) {
|
|
36751
36777
|
throw forbidden("Invalid internal secret");
|
|
@@ -36754,7 +36780,7 @@ var internalMiddleware = chunkQARF2YFF_cjs.createMiddleware(async (c, next) => {
|
|
|
36754
36780
|
});
|
|
36755
36781
|
|
|
36756
36782
|
// src/routes/health.ts
|
|
36757
|
-
var healthRoute = new
|
|
36783
|
+
var healthRoute = new chunkBFMJDSDI_cjs.Hono();
|
|
36758
36784
|
async function probeResend(apiKey) {
|
|
36759
36785
|
const start = Date.now();
|
|
36760
36786
|
try {
|
|
@@ -36983,7 +37009,7 @@ var parse4 = (cookie, name) => {
|
|
|
36983
37009
|
cookieValue = cookieValue.slice(1, -1);
|
|
36984
37010
|
}
|
|
36985
37011
|
if (validCookieValueRegEx.test(cookieValue)) {
|
|
36986
|
-
parsedCookie[cookieName] = cookieValue.indexOf("%") !== -1 ?
|
|
37012
|
+
parsedCookie[cookieName] = cookieValue.indexOf("%") !== -1 ? chunkBFMJDSDI_cjs.tryDecode(cookieValue, chunkBFMJDSDI_cjs.decodeURIComponent_) : cookieValue;
|
|
36987
37013
|
}
|
|
36988
37014
|
}
|
|
36989
37015
|
return parsedCookie;
|
|
@@ -37026,7 +37052,7 @@ var validator = (target, validationFunc) => {
|
|
|
37026
37052
|
value = await c.req.json();
|
|
37027
37053
|
} catch {
|
|
37028
37054
|
const message2 = "Malformed JSON in request body";
|
|
37029
|
-
throw new
|
|
37055
|
+
throw new chunkBFMJDSDI_cjs.HTTPException(400, { message: message2 });
|
|
37030
37056
|
}
|
|
37031
37057
|
break;
|
|
37032
37058
|
case "form": {
|
|
@@ -37044,7 +37070,7 @@ var validator = (target, validationFunc) => {
|
|
|
37044
37070
|
} catch (e) {
|
|
37045
37071
|
let message2 = "Malformed FormData request.";
|
|
37046
37072
|
message2 += e instanceof Error ? ` ${e.message}` : ` ${String(e)}`;
|
|
37047
|
-
throw new
|
|
37073
|
+
throw new chunkBFMJDSDI_cjs.HTTPException(400, { message: message2 });
|
|
37048
37074
|
}
|
|
37049
37075
|
}
|
|
37050
37076
|
const form = /* @__PURE__ */ Object.create(null);
|
|
@@ -37593,7 +37619,7 @@ var ContentfulManagement = class {
|
|
|
37593
37619
|
// src/lib/middleware/rate-limit.ts
|
|
37594
37620
|
function createRateLimitMiddleware(config3) {
|
|
37595
37621
|
const { endpoint, limit, windowSec, identifier } = config3;
|
|
37596
|
-
return
|
|
37622
|
+
return chunkBFMJDSDI_cjs.createMiddleware(async (c, next) => {
|
|
37597
37623
|
if (c.req.path === "/.well-known/leapify/pow/verify") return next();
|
|
37598
37624
|
const id = identifier === "uid" ? c.get("user")?.uid ?? c.req.header("CF-Connecting-IP") ?? "unknown" : c.req.header("CF-Connecting-IP") ?? "unknown";
|
|
37599
37625
|
const key = `rl:${endpoint}:${id}`;
|
|
@@ -37640,7 +37666,7 @@ var adminEventsRateLimit = createRateLimitMiddleware({
|
|
|
37640
37666
|
identifier: "uid"
|
|
37641
37667
|
});
|
|
37642
37668
|
|
|
37643
|
-
// src/routes/
|
|
37669
|
+
// src/routes/classes.ts
|
|
37644
37670
|
var EVENTS_LIST_KV_KEY = "events:list";
|
|
37645
37671
|
var EVENTS_ETAG_KV_KEY = "events:etag";
|
|
37646
37672
|
var EVENTS_LIST_TTL = 300;
|
|
@@ -37656,7 +37682,7 @@ async function pushEventToContentful(env2, event) {
|
|
|
37656
37682
|
const fields = {
|
|
37657
37683
|
title: ContentfulManagement.locale(event.title),
|
|
37658
37684
|
slug: ContentfulManagement.locale(event.slug),
|
|
37659
|
-
|
|
37685
|
+
isSpotlight: ContentfulManagement.locale(event.isSpotlight),
|
|
37660
37686
|
maxSlots: ContentfulManagement.locale(event.maxSlots)
|
|
37661
37687
|
};
|
|
37662
37688
|
if (event.themeId) fields.theme = ContentfulManagement.entryRef(event.themeId);
|
|
@@ -37719,7 +37745,7 @@ var createEventSchema = external_exports.object({
|
|
|
37719
37745
|
startTime: external_exports.string().optional(),
|
|
37720
37746
|
endTime: external_exports.string().optional(),
|
|
37721
37747
|
registrationClosesAt: external_exports.number().optional(),
|
|
37722
|
-
|
|
37748
|
+
isSpotlight: external_exports.boolean().default(false),
|
|
37723
37749
|
maxSlots: external_exports.number().int().min(0).default(0),
|
|
37724
37750
|
gformsId: external_exports.string().optional(),
|
|
37725
37751
|
gformsUrl: external_exports.string().url().optional(),
|
|
@@ -37728,11 +37754,11 @@ var createEventSchema = external_exports.object({
|
|
|
37728
37754
|
contentfulEntryId: external_exports.string().optional(),
|
|
37729
37755
|
status: external_exports.enum(["draft", "queued", "published"]).default("draft")
|
|
37730
37756
|
});
|
|
37731
|
-
var
|
|
37757
|
+
var classesRoute = new chunkBFMJDSDI_cjs.Hono();
|
|
37732
37758
|
function generateSlug(title) {
|
|
37733
37759
|
return title.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
37734
37760
|
}
|
|
37735
|
-
|
|
37761
|
+
classesRoute.get("/admin", authMiddleware, adminMiddleware, async (c) => {
|
|
37736
37762
|
const db = createDb(c.env.DB);
|
|
37737
37763
|
const data = await db.query.events.findMany({
|
|
37738
37764
|
with: { theme: true, organization: true },
|
|
@@ -37740,7 +37766,7 @@ eventsRoute.get("/admin", authMiddleware, adminMiddleware, async (c) => {
|
|
|
37740
37766
|
});
|
|
37741
37767
|
return c.json({ data });
|
|
37742
37768
|
});
|
|
37743
|
-
|
|
37769
|
+
classesRoute.post("/admin/publish", authMiddleware, adminMiddleware, async (c) => {
|
|
37744
37770
|
const body = await c.req.json();
|
|
37745
37771
|
const db = createDb(c.env.DB);
|
|
37746
37772
|
const cache3 = new CacheService(c.env.KV);
|
|
@@ -37768,7 +37794,7 @@ eventsRoute.post("/admin/publish", authMiddleware, adminMiddleware, async (c) =>
|
|
|
37768
37794
|
]);
|
|
37769
37795
|
return c.json({ data: { updated: body.ids.length } });
|
|
37770
37796
|
});
|
|
37771
|
-
|
|
37797
|
+
classesRoute.get("/", eventsListRateLimit, async (c) => {
|
|
37772
37798
|
const db = createDb(c.env.DB);
|
|
37773
37799
|
const cache3 = new CacheService(c.env.KV);
|
|
37774
37800
|
const [latest] = await db.select({ max: events.publishedAt }).from(events).where(eq(events.status, "published")).limit(1);
|
|
@@ -37779,7 +37805,7 @@ eventsRoute.get("/", eventsListRateLimit, async (c) => {
|
|
|
37779
37805
|
);
|
|
37780
37806
|
const ifNoneMatch = c.req.header("If-None-Match");
|
|
37781
37807
|
if (ifNoneMatch === etag) {
|
|
37782
|
-
return c.
|
|
37808
|
+
return c.body(null, 304);
|
|
37783
37809
|
}
|
|
37784
37810
|
const data = await cache3.getOrSet(
|
|
37785
37811
|
EVENTS_LIST_KV_KEY,
|
|
@@ -37803,7 +37829,7 @@ eventsRoute.get("/", eventsListRateLimit, async (c) => {
|
|
|
37803
37829
|
startTime: true,
|
|
37804
37830
|
endTime: true,
|
|
37805
37831
|
registrationClosesAt: true,
|
|
37806
|
-
|
|
37832
|
+
isSpotlight: true,
|
|
37807
37833
|
maxSlots: true,
|
|
37808
37834
|
registeredSlots: true,
|
|
37809
37835
|
gformsUrl: true,
|
|
@@ -37820,7 +37846,7 @@ eventsRoute.get("/", eventsListRateLimit, async (c) => {
|
|
|
37820
37846
|
);
|
|
37821
37847
|
return c.json({ data });
|
|
37822
37848
|
});
|
|
37823
|
-
|
|
37849
|
+
classesRoute.get("/:slug", async (c) => {
|
|
37824
37850
|
const { slug } = c.req.param();
|
|
37825
37851
|
const db = createDb(c.env.DB);
|
|
37826
37852
|
const event = await db.query.events.findFirst({
|
|
@@ -37832,7 +37858,7 @@ eventsRoute.get("/:slug", async (c) => {
|
|
|
37832
37858
|
if (!event) throw notFound("Event");
|
|
37833
37859
|
return c.json({ data: event });
|
|
37834
37860
|
});
|
|
37835
|
-
|
|
37861
|
+
classesRoute.get("/:slug/slots", eventsSlotsRateLimit, async (c) => {
|
|
37836
37862
|
const { slug } = c.req.param();
|
|
37837
37863
|
const db = createDb(c.env.DB);
|
|
37838
37864
|
const cache3 = new CacheService(c.env.KV);
|
|
@@ -37842,7 +37868,7 @@ eventsRoute.get("/:slug/slots", eventsSlotsRateLimit, async (c) => {
|
|
|
37842
37868
|
c.header("Cache-Control", "public, max-age=5, stale-while-revalidate=5");
|
|
37843
37869
|
return c.json({ data: info2 });
|
|
37844
37870
|
});
|
|
37845
|
-
|
|
37871
|
+
classesRoute.post(
|
|
37846
37872
|
"/",
|
|
37847
37873
|
authMiddleware,
|
|
37848
37874
|
adminMiddleware,
|
|
@@ -37877,11 +37903,13 @@ eventsRoute.post(
|
|
|
37877
37903
|
cache3.del(EVENTS_LIST_KV_KEY),
|
|
37878
37904
|
cache3.del(EVENTS_ETAG_KV_KEY)
|
|
37879
37905
|
]);
|
|
37880
|
-
c.
|
|
37906
|
+
if (c.get("cmsMode") === "hybrid") {
|
|
37907
|
+
c.executionCtx.waitUntil(pushEventToContentful(c.env, created));
|
|
37908
|
+
}
|
|
37881
37909
|
return c.json({ data: created }, 201);
|
|
37882
37910
|
}
|
|
37883
37911
|
);
|
|
37884
|
-
|
|
37912
|
+
classesRoute.patch("/:slug", authMiddleware, adminMiddleware, async (c) => {
|
|
37885
37913
|
const { slug } = c.req.param();
|
|
37886
37914
|
const body = await c.req.json();
|
|
37887
37915
|
const db = createDb(c.env.DB);
|
|
@@ -37896,10 +37924,12 @@ eventsRoute.patch("/:slug", authMiddleware, adminMiddleware, async (c) => {
|
|
|
37896
37924
|
cache3.del(EVENTS_LIST_KV_KEY),
|
|
37897
37925
|
cache3.del(EVENTS_ETAG_KV_KEY)
|
|
37898
37926
|
]);
|
|
37899
|
-
c.
|
|
37927
|
+
if (c.get("cmsMode") === "hybrid") {
|
|
37928
|
+
c.executionCtx.waitUntil(pushEventToContentful(c.env, updated));
|
|
37929
|
+
}
|
|
37900
37930
|
return c.json({ data: updated });
|
|
37901
37931
|
});
|
|
37902
|
-
|
|
37932
|
+
classesRoute.delete("/:slug", authMiddleware, adminMiddleware, async (c) => {
|
|
37903
37933
|
const { slug } = c.req.param();
|
|
37904
37934
|
const db = createDb(c.env.DB);
|
|
37905
37935
|
const cache3 = new CacheService(c.env.KV);
|
|
@@ -37914,7 +37944,7 @@ eventsRoute.delete("/:slug", authMiddleware, adminMiddleware, async (c) => {
|
|
|
37914
37944
|
|
|
37915
37945
|
// src/routes/users.ts
|
|
37916
37946
|
var VALID_ROLES = ["student", "admin", "super_admin"];
|
|
37917
|
-
var usersRoute = new
|
|
37947
|
+
var usersRoute = new chunkBFMJDSDI_cjs.Hono();
|
|
37918
37948
|
usersRoute.get("/", authMiddleware, adminMiddleware, async (c) => {
|
|
37919
37949
|
const db = createDb(c.env.DB);
|
|
37920
37950
|
const data = await db.select().from(users);
|
|
@@ -37998,7 +38028,447 @@ usersRoute.delete("/me/bookmarks/:eventId", authMiddleware, async (c) => {
|
|
|
37998
38028
|
return c.json({ data: { bookmarked: false } });
|
|
37999
38029
|
});
|
|
38000
38030
|
|
|
38031
|
+
// src/services/contentful.ts
|
|
38032
|
+
var CONTENTFUL_CDN = "https://cdn.contentful.com";
|
|
38033
|
+
var ContentfulService = class _ContentfulService {
|
|
38034
|
+
spaceId;
|
|
38035
|
+
accessToken;
|
|
38036
|
+
environment;
|
|
38037
|
+
constructor(spaceId, accessToken, environment = "master") {
|
|
38038
|
+
this.spaceId = spaceId;
|
|
38039
|
+
this.accessToken = accessToken;
|
|
38040
|
+
this.environment = environment;
|
|
38041
|
+
}
|
|
38042
|
+
/**
|
|
38043
|
+
* Returns true if the required Contentful credentials are configured.
|
|
38044
|
+
*/
|
|
38045
|
+
static isConfigured(spaceId, accessToken) {
|
|
38046
|
+
return !!(spaceId && accessToken);
|
|
38047
|
+
}
|
|
38048
|
+
// ─── Entries ─────────────────────────────────────────────────────────────
|
|
38049
|
+
/**
|
|
38050
|
+
* Fetch all entries of a given content type.
|
|
38051
|
+
* Handles pagination automatically (100 per page, Contentful max).
|
|
38052
|
+
*/
|
|
38053
|
+
async getEntries(contentTypeId) {
|
|
38054
|
+
const allItems = [];
|
|
38055
|
+
let skip = 0;
|
|
38056
|
+
const limit = 100;
|
|
38057
|
+
do {
|
|
38058
|
+
const url2 = this.buildUrl(`/entries`, {
|
|
38059
|
+
content_type: contentTypeId,
|
|
38060
|
+
skip: String(skip),
|
|
38061
|
+
limit: String(limit),
|
|
38062
|
+
include: "2"
|
|
38063
|
+
// resolve up to 2 levels of linked entries/assets
|
|
38064
|
+
});
|
|
38065
|
+
const res = await fetch(url2, { headers: this.headers() });
|
|
38066
|
+
if (!res.ok) {
|
|
38067
|
+
throw new Error(`Contentful entries error: ${res.status} ${await res.text()}`);
|
|
38068
|
+
}
|
|
38069
|
+
const data = await res.json();
|
|
38070
|
+
allItems.push(...data.items);
|
|
38071
|
+
skip += limit;
|
|
38072
|
+
if (allItems.length >= data.total) break;
|
|
38073
|
+
} while (true);
|
|
38074
|
+
return allItems;
|
|
38075
|
+
}
|
|
38076
|
+
/**
|
|
38077
|
+
* Fetch all assets. Handles pagination.
|
|
38078
|
+
*/
|
|
38079
|
+
async getAssets() {
|
|
38080
|
+
const allItems = [];
|
|
38081
|
+
let skip = 0;
|
|
38082
|
+
const limit = 100;
|
|
38083
|
+
do {
|
|
38084
|
+
const url2 = this.buildUrl(`/assets`, {
|
|
38085
|
+
skip: String(skip),
|
|
38086
|
+
limit: String(limit)
|
|
38087
|
+
});
|
|
38088
|
+
const res = await fetch(url2, { headers: this.headers() });
|
|
38089
|
+
if (!res.ok) {
|
|
38090
|
+
throw new Error(`Contentful assets error: ${res.status} ${await res.text()}`);
|
|
38091
|
+
}
|
|
38092
|
+
const data = await res.json();
|
|
38093
|
+
allItems.push(...data.items);
|
|
38094
|
+
skip += limit;
|
|
38095
|
+
if (allItems.length >= data.total) break;
|
|
38096
|
+
} while (true);
|
|
38097
|
+
return allItems;
|
|
38098
|
+
}
|
|
38099
|
+
// ─── Asset file download ─────────────────────────────────────────────────
|
|
38100
|
+
/**
|
|
38101
|
+
* Download an asset file from Contentful's CDN.
|
|
38102
|
+
* Returns the raw ArrayBuffer and content type.
|
|
38103
|
+
*/
|
|
38104
|
+
async downloadAsset(assetUrl) {
|
|
38105
|
+
const url2 = assetUrl.startsWith("//") ? `https:${assetUrl}` : assetUrl;
|
|
38106
|
+
const res = await fetch(url2);
|
|
38107
|
+
if (!res.ok) {
|
|
38108
|
+
throw new Error(`Failed to download asset: ${res.status}`);
|
|
38109
|
+
}
|
|
38110
|
+
const contentType = res.headers.get("Content-Type") ?? "application/octet-stream";
|
|
38111
|
+
const data = await res.arrayBuffer();
|
|
38112
|
+
return { data, contentType };
|
|
38113
|
+
}
|
|
38114
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
38115
|
+
/**
|
|
38116
|
+
* Extract a field value from a Contentful entry, handling locale wrapping.
|
|
38117
|
+
* Contentful fields are often `{ "en-US": value }` — this unwraps them.
|
|
38118
|
+
*/
|
|
38119
|
+
static getField(entry, fieldName) {
|
|
38120
|
+
const raw = entry.fields[fieldName];
|
|
38121
|
+
if (raw === void 0 || raw === null) return void 0;
|
|
38122
|
+
if (typeof raw === "object" && !Array.isArray(raw) && "en-US" in raw) {
|
|
38123
|
+
return raw["en-US"];
|
|
38124
|
+
}
|
|
38125
|
+
return raw;
|
|
38126
|
+
}
|
|
38127
|
+
/**
|
|
38128
|
+
* Extract a linked entry/sys reference ID from a reference field.
|
|
38129
|
+
*/
|
|
38130
|
+
static getRefId(entry, fieldName) {
|
|
38131
|
+
const ref = _ContentfulService.getField(entry, fieldName);
|
|
38132
|
+
return ref?.sys?.id;
|
|
38133
|
+
}
|
|
38134
|
+
/**
|
|
38135
|
+
* Extract an asset URL from a linked asset field.
|
|
38136
|
+
*/
|
|
38137
|
+
static getAssetUrl(entry, fieldName) {
|
|
38138
|
+
const asset = _ContentfulService.getField(entry, fieldName);
|
|
38139
|
+
return asset?.sys?.id;
|
|
38140
|
+
}
|
|
38141
|
+
/**
|
|
38142
|
+
* Resolve an asset URL by ID from a list of fetched assets.
|
|
38143
|
+
*/
|
|
38144
|
+
static resolveAssetUrl(assets, assetId) {
|
|
38145
|
+
const asset = assets.find((a) => a.sys.id === assetId);
|
|
38146
|
+
return asset?.fields?.file?.url;
|
|
38147
|
+
}
|
|
38148
|
+
// ─── Private ─────────────────────────────────────────────────────────────
|
|
38149
|
+
headers() {
|
|
38150
|
+
return {
|
|
38151
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
38152
|
+
"Content-Type": "application/json"
|
|
38153
|
+
};
|
|
38154
|
+
}
|
|
38155
|
+
buildUrl(path, params = {}) {
|
|
38156
|
+
const url2 = new URL(
|
|
38157
|
+
`/spaces/${this.spaceId}/environments/${this.environment}${path}`,
|
|
38158
|
+
CONTENTFUL_CDN
|
|
38159
|
+
);
|
|
38160
|
+
for (const [key, value] of Object.entries(params)) {
|
|
38161
|
+
url2.searchParams.set(key, value);
|
|
38162
|
+
}
|
|
38163
|
+
return url2.toString();
|
|
38164
|
+
}
|
|
38165
|
+
};
|
|
38166
|
+
|
|
38001
38167
|
// src/services/snapshot.ts
|
|
38168
|
+
var DEFAULT_FIELDS = {
|
|
38169
|
+
event: {
|
|
38170
|
+
title: "title",
|
|
38171
|
+
slug: "slug",
|
|
38172
|
+
theme: "theme",
|
|
38173
|
+
organization: "organization",
|
|
38174
|
+
venue: "venue",
|
|
38175
|
+
date: "date",
|
|
38176
|
+
startTime: "startTime",
|
|
38177
|
+
endTime: "endTime",
|
|
38178
|
+
price: "price",
|
|
38179
|
+
image: "image",
|
|
38180
|
+
isSpotlight: "isSpotlight",
|
|
38181
|
+
maxSlots: "maxSlots",
|
|
38182
|
+
gformsUrl: "gformsUrl",
|
|
38183
|
+
gformsEditorUrl: "gformsEditorUrl",
|
|
38184
|
+
registrationClosesAt: "registrationClosesAt",
|
|
38185
|
+
classCode: "classCode"
|
|
38186
|
+
},
|
|
38187
|
+
theme: {
|
|
38188
|
+
name: "name",
|
|
38189
|
+
path: "path"
|
|
38190
|
+
},
|
|
38191
|
+
faq: {
|
|
38192
|
+
question: "question",
|
|
38193
|
+
answer: "answer",
|
|
38194
|
+
category: "category",
|
|
38195
|
+
sortOrder: "sortOrder"
|
|
38196
|
+
},
|
|
38197
|
+
organization: {
|
|
38198
|
+
name: "name",
|
|
38199
|
+
acronym: "acronym",
|
|
38200
|
+
logoUrl: "logoUrl",
|
|
38201
|
+
link: "link"
|
|
38202
|
+
},
|
|
38203
|
+
siteConfig: {
|
|
38204
|
+
key: "key",
|
|
38205
|
+
value: "value"
|
|
38206
|
+
}
|
|
38207
|
+
};
|
|
38208
|
+
var CONTENTFUL_CACHE_PREFIX = "contentful:cache";
|
|
38209
|
+
var CONTENTFUL_CACHE_TTL = 300;
|
|
38210
|
+
async function snapshotAllContent(db, bucket, contentful, config3 = {}, kv) {
|
|
38211
|
+
const mergedConfig = {
|
|
38212
|
+
eventTypeId: config3.eventTypeId ?? "event",
|
|
38213
|
+
themeTypeId: config3.themeTypeId ?? "theme",
|
|
38214
|
+
faqTypeId: config3.faqTypeId ?? "faq",
|
|
38215
|
+
organizationTypeId: config3.organizationTypeId ?? "organization",
|
|
38216
|
+
fields: {
|
|
38217
|
+
event: { ...DEFAULT_FIELDS.event, ...config3.fields?.event },
|
|
38218
|
+
theme: { ...DEFAULT_FIELDS.theme, ...config3.fields?.theme },
|
|
38219
|
+
faq: { ...DEFAULT_FIELDS.faq, ...config3.fields?.faq },
|
|
38220
|
+
organization: { ...DEFAULT_FIELDS.organization, ...config3.fields?.organization },
|
|
38221
|
+
siteConfig: { ...DEFAULT_FIELDS.siteConfig, ...config3.fields?.siteConfig }
|
|
38222
|
+
}
|
|
38223
|
+
};
|
|
38224
|
+
const result = {
|
|
38225
|
+
themesSynced: 0,
|
|
38226
|
+
eventsSynced: 0,
|
|
38227
|
+
faqsSynced: 0,
|
|
38228
|
+
organizationsSynced: 0,
|
|
38229
|
+
imagesUploaded: 0,
|
|
38230
|
+
imagesSkipped: 0,
|
|
38231
|
+
errors: []
|
|
38232
|
+
};
|
|
38233
|
+
let allAssets = [];
|
|
38234
|
+
if (bucket) {
|
|
38235
|
+
try {
|
|
38236
|
+
allAssets = await contentful.getAssets();
|
|
38237
|
+
} catch (err) {
|
|
38238
|
+
result.errors.push(`Failed to fetch assets: ${err}`);
|
|
38239
|
+
}
|
|
38240
|
+
}
|
|
38241
|
+
try {
|
|
38242
|
+
const cacheKey = `${CONTENTFUL_CACHE_PREFIX}:themes`;
|
|
38243
|
+
let themeEntries;
|
|
38244
|
+
if (kv) {
|
|
38245
|
+
const cached2 = await kv.get(cacheKey, "json");
|
|
38246
|
+
if (cached2) {
|
|
38247
|
+
themeEntries = cached2;
|
|
38248
|
+
} else {
|
|
38249
|
+
themeEntries = await contentful.getEntries(mergedConfig.themeTypeId);
|
|
38250
|
+
await kv.put(cacheKey, JSON.stringify(themeEntries), { expirationTtl: CONTENTFUL_CACHE_TTL });
|
|
38251
|
+
}
|
|
38252
|
+
} else {
|
|
38253
|
+
themeEntries = await contentful.getEntries(mergedConfig.themeTypeId);
|
|
38254
|
+
}
|
|
38255
|
+
result.themesSynced = await syncThemes(db, themeEntries, mergedConfig);
|
|
38256
|
+
} catch (err) {
|
|
38257
|
+
result.errors.push(`Themes sync failed: ${err}`);
|
|
38258
|
+
}
|
|
38259
|
+
try {
|
|
38260
|
+
const cacheKey = `${CONTENTFUL_CACHE_PREFIX}:organizations`;
|
|
38261
|
+
let orgEntries;
|
|
38262
|
+
if (kv) {
|
|
38263
|
+
const cached2 = await kv.get(cacheKey, "json");
|
|
38264
|
+
if (cached2) {
|
|
38265
|
+
orgEntries = cached2;
|
|
38266
|
+
} else {
|
|
38267
|
+
orgEntries = await contentful.getEntries(mergedConfig.organizationTypeId);
|
|
38268
|
+
await kv.put(cacheKey, JSON.stringify(orgEntries), { expirationTtl: CONTENTFUL_CACHE_TTL });
|
|
38269
|
+
}
|
|
38270
|
+
} else {
|
|
38271
|
+
orgEntries = await contentful.getEntries(mergedConfig.organizationTypeId);
|
|
38272
|
+
}
|
|
38273
|
+
await syncOrganizations(db, orgEntries, mergedConfig);
|
|
38274
|
+
} catch (err) {
|
|
38275
|
+
result.errors.push(`Organizations sync failed: ${err}`);
|
|
38276
|
+
}
|
|
38277
|
+
try {
|
|
38278
|
+
const cacheKey = `${CONTENTFUL_CACHE_PREFIX}:events`;
|
|
38279
|
+
let eventEntries;
|
|
38280
|
+
if (kv) {
|
|
38281
|
+
const cached2 = await kv.get(cacheKey, "json");
|
|
38282
|
+
if (cached2) {
|
|
38283
|
+
eventEntries = cached2;
|
|
38284
|
+
} else {
|
|
38285
|
+
eventEntries = await contentful.getEntries(mergedConfig.eventTypeId);
|
|
38286
|
+
await kv.put(cacheKey, JSON.stringify(eventEntries), { expirationTtl: CONTENTFUL_CACHE_TTL });
|
|
38287
|
+
}
|
|
38288
|
+
} else {
|
|
38289
|
+
eventEntries = await contentful.getEntries(mergedConfig.eventTypeId);
|
|
38290
|
+
}
|
|
38291
|
+
result.eventsSynced = await syncEvents(db, bucket, contentful, allAssets, eventEntries, mergedConfig, result);
|
|
38292
|
+
} catch (err) {
|
|
38293
|
+
result.errors.push(`Events sync failed: ${err}`);
|
|
38294
|
+
}
|
|
38295
|
+
try {
|
|
38296
|
+
const cacheKey = `${CONTENTFUL_CACHE_PREFIX}:faqs`;
|
|
38297
|
+
let faqEntries;
|
|
38298
|
+
if (kv) {
|
|
38299
|
+
const cached2 = await kv.get(cacheKey, "json");
|
|
38300
|
+
if (cached2) {
|
|
38301
|
+
faqEntries = cached2;
|
|
38302
|
+
} else {
|
|
38303
|
+
faqEntries = await contentful.getEntries(mergedConfig.faqTypeId);
|
|
38304
|
+
await kv.put(cacheKey, JSON.stringify(faqEntries), { expirationTtl: CONTENTFUL_CACHE_TTL });
|
|
38305
|
+
}
|
|
38306
|
+
} else {
|
|
38307
|
+
faqEntries = await contentful.getEntries(mergedConfig.faqTypeId);
|
|
38308
|
+
}
|
|
38309
|
+
result.faqsSynced = await syncFaqs(db, faqEntries, mergedConfig);
|
|
38310
|
+
} catch (err) {
|
|
38311
|
+
result.errors.push(`FAQs sync failed: ${err}`);
|
|
38312
|
+
}
|
|
38313
|
+
console.log(
|
|
38314
|
+
`[Snapshot] Complete: ${result.themesSynced} themes, ${result.organizationsSynced} organizations, ${result.eventsSynced} events, ${result.faqsSynced} FAQs, ${result.imagesUploaded} images uploaded, ${result.imagesSkipped} images skipped, ${result.errors.length} errors`
|
|
38315
|
+
);
|
|
38316
|
+
return result;
|
|
38317
|
+
}
|
|
38318
|
+
async function syncThemes(db, entries, config3) {
|
|
38319
|
+
let count2 = 0;
|
|
38320
|
+
for (const entry of entries) {
|
|
38321
|
+
const cfId = entry.sys.id;
|
|
38322
|
+
const name = ContentfulService.getField(entry, config3.fields.theme.name);
|
|
38323
|
+
const path = ContentfulService.getField(entry, config3.fields.theme.path);
|
|
38324
|
+
if (!name || !path) continue;
|
|
38325
|
+
await db.insert(themes).values({ id: cfId, name, path }).onConflictDoUpdate({
|
|
38326
|
+
target: themes.id,
|
|
38327
|
+
set: { name, path }
|
|
38328
|
+
});
|
|
38329
|
+
count2++;
|
|
38330
|
+
}
|
|
38331
|
+
return count2;
|
|
38332
|
+
}
|
|
38333
|
+
async function syncOrganizations(db, entries, config3) {
|
|
38334
|
+
let count2 = 0;
|
|
38335
|
+
for (const entry of entries) {
|
|
38336
|
+
const cfId = entry.sys.id;
|
|
38337
|
+
const f = config3.fields.organization;
|
|
38338
|
+
const name = ContentfulService.getField(entry, f.name);
|
|
38339
|
+
const acronym = ContentfulService.getField(entry, f.acronym);
|
|
38340
|
+
if (!name || !acronym) continue;
|
|
38341
|
+
const logoUrl = ContentfulService.getField(entry, f.logoUrl) ?? null;
|
|
38342
|
+
const link = ContentfulService.getField(entry, f.link) ?? null;
|
|
38343
|
+
await db.insert(organizations).values({ id: cfId, name, acronym, logoUrl, link }).onConflictDoUpdate({
|
|
38344
|
+
target: organizations.id,
|
|
38345
|
+
set: { name, acronym, logoUrl, link }
|
|
38346
|
+
});
|
|
38347
|
+
count2++;
|
|
38348
|
+
}
|
|
38349
|
+
return count2;
|
|
38350
|
+
}
|
|
38351
|
+
async function syncEvents(db, bucket, contentful, allAssets, entries, config3, result) {
|
|
38352
|
+
let count2 = 0;
|
|
38353
|
+
for (const entry of entries) {
|
|
38354
|
+
try {
|
|
38355
|
+
const cfId = entry.sys.id;
|
|
38356
|
+
const f = config3.fields.event;
|
|
38357
|
+
const title = ContentfulService.getField(entry, f.title);
|
|
38358
|
+
if (!title) {
|
|
38359
|
+
result.errors.push(`Event ${cfId}: missing title, skipping`);
|
|
38360
|
+
continue;
|
|
38361
|
+
}
|
|
38362
|
+
const slug = ContentfulService.getField(entry, f.slug) ?? slugify2(title);
|
|
38363
|
+
const themeRef = ContentfulService.getField(entry, f.theme);
|
|
38364
|
+
const themeId = themeRef?.sys?.id ?? null;
|
|
38365
|
+
const orgRef = ContentfulService.getField(entry, f.organization);
|
|
38366
|
+
const organizationId = orgRef?.sys?.id ?? null;
|
|
38367
|
+
let backgroundImageUrl = null;
|
|
38368
|
+
if (bucket) {
|
|
38369
|
+
const imageRef = ContentfulService.getField(entry, f.image);
|
|
38370
|
+
const assetId = imageRef?.sys?.id;
|
|
38371
|
+
if (assetId) {
|
|
38372
|
+
const assetUrl = ContentfulService.resolveAssetUrl(allAssets, assetId);
|
|
38373
|
+
if (assetUrl) {
|
|
38374
|
+
const r2Key = `contentful/${assetId}`;
|
|
38375
|
+
const uploaded = await uploadAssetIfChanged(bucket, contentful, assetUrl, r2Key);
|
|
38376
|
+
if (uploaded.skipped) {
|
|
38377
|
+
result.imagesSkipped++;
|
|
38378
|
+
} else {
|
|
38379
|
+
result.imagesUploaded++;
|
|
38380
|
+
}
|
|
38381
|
+
backgroundImageUrl = `/uploads/images/${r2Key}`;
|
|
38382
|
+
}
|
|
38383
|
+
}
|
|
38384
|
+
}
|
|
38385
|
+
const values = {
|
|
38386
|
+
id: cfId,
|
|
38387
|
+
contentfulEntryId: cfId,
|
|
38388
|
+
title,
|
|
38389
|
+
slug,
|
|
38390
|
+
themeId,
|
|
38391
|
+
organizationId,
|
|
38392
|
+
updatedAt: entry.sys.updatedAt
|
|
38393
|
+
};
|
|
38394
|
+
const venue = ContentfulService.getField(entry, f.venue);
|
|
38395
|
+
if (venue !== void 0) values.venue = venue;
|
|
38396
|
+
const date5 = ContentfulService.getField(entry, f.date);
|
|
38397
|
+
if (date5 !== void 0) values.dateTime = date5;
|
|
38398
|
+
const price = ContentfulService.getField(entry, f.price);
|
|
38399
|
+
if (price !== void 0) values.price = price;
|
|
38400
|
+
if (backgroundImageUrl) values.backgroundImageUrl = backgroundImageUrl;
|
|
38401
|
+
const isSpotlight = ContentfulService.getField(entry, f.isSpotlight);
|
|
38402
|
+
if (isSpotlight !== void 0) values.isSpotlight = isSpotlight;
|
|
38403
|
+
const maxSlots = ContentfulService.getField(entry, f.maxSlots);
|
|
38404
|
+
if (maxSlots !== void 0) values.maxSlots = maxSlots;
|
|
38405
|
+
const gformsUrl = ContentfulService.getField(entry, f.gformsUrl);
|
|
38406
|
+
if (gformsUrl !== void 0) values.gformsUrl = gformsUrl;
|
|
38407
|
+
const gformsEditorUrl = ContentfulService.getField(entry, f.gformsEditorUrl);
|
|
38408
|
+
if (gformsEditorUrl !== void 0) values.gformsEditorUrl = gformsEditorUrl;
|
|
38409
|
+
const classCode = ContentfulService.getField(entry, f.classCode);
|
|
38410
|
+
if (classCode !== void 0) values.classCode = classCode;
|
|
38411
|
+
const startTime = ContentfulService.getField(entry, f.startTime);
|
|
38412
|
+
if (startTime !== void 0) values.startTime = startTime;
|
|
38413
|
+
const endTime = ContentfulService.getField(entry, f.endTime);
|
|
38414
|
+
if (endTime !== void 0) values.endTime = endTime;
|
|
38415
|
+
const regCloseRaw = ContentfulService.getField(entry, f.registrationClosesAt);
|
|
38416
|
+
if (regCloseRaw) {
|
|
38417
|
+
const ms = Date.parse(regCloseRaw);
|
|
38418
|
+
if (!Number.isNaN(ms)) values.registrationClosesAt = Math.floor(ms / 1e3);
|
|
38419
|
+
}
|
|
38420
|
+
await db.insert(events).values(values).onConflictDoUpdate({
|
|
38421
|
+
target: events.id,
|
|
38422
|
+
set: values
|
|
38423
|
+
});
|
|
38424
|
+
count2++;
|
|
38425
|
+
} catch (err) {
|
|
38426
|
+
result.errors.push(`Event ${entry.sys.id}: ${err}`);
|
|
38427
|
+
}
|
|
38428
|
+
}
|
|
38429
|
+
return count2;
|
|
38430
|
+
}
|
|
38431
|
+
async function syncFaqs(db, entries, config3) {
|
|
38432
|
+
let count2 = 0;
|
|
38433
|
+
for (const entry of entries) {
|
|
38434
|
+
const cfId = entry.sys.id;
|
|
38435
|
+
const f = config3.fields.faq;
|
|
38436
|
+
const question = ContentfulService.getField(entry, f.question);
|
|
38437
|
+
const answer = ContentfulService.getField(entry, f.answer);
|
|
38438
|
+
if (!question || !answer) continue;
|
|
38439
|
+
const category = ContentfulService.getField(entry, f.category) ?? null;
|
|
38440
|
+
const sortOrder = ContentfulService.getField(entry, f.sortOrder) ?? 0;
|
|
38441
|
+
await db.insert(faqs).values({
|
|
38442
|
+
id: cfId,
|
|
38443
|
+
question,
|
|
38444
|
+
answer,
|
|
38445
|
+
category,
|
|
38446
|
+
sortOrder
|
|
38447
|
+
}).onConflictDoUpdate({
|
|
38448
|
+
target: faqs.id,
|
|
38449
|
+
set: { question, answer, category, sortOrder }
|
|
38450
|
+
});
|
|
38451
|
+
count2++;
|
|
38452
|
+
}
|
|
38453
|
+
return count2;
|
|
38454
|
+
}
|
|
38455
|
+
async function uploadAssetIfChanged(bucket, contentful, assetUrl, r2Key) {
|
|
38456
|
+
const { data, contentType } = await contentful.downloadAsset(assetUrl);
|
|
38457
|
+
const sha = await computeSha256(data);
|
|
38458
|
+
const existing = await bucket.head(r2Key);
|
|
38459
|
+
if (existing?.customMetadata?.sha256 === sha) {
|
|
38460
|
+
return { skipped: true };
|
|
38461
|
+
}
|
|
38462
|
+
await bucket.put(r2Key, data, {
|
|
38463
|
+
httpMetadata: { contentType },
|
|
38464
|
+
customMetadata: {
|
|
38465
|
+
sha256: sha,
|
|
38466
|
+
source: "contentful",
|
|
38467
|
+
syncedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
38468
|
+
}
|
|
38469
|
+
});
|
|
38470
|
+
return { skipped: false };
|
|
38471
|
+
}
|
|
38002
38472
|
async function batchRun(items, fn, concurrency = 5) {
|
|
38003
38473
|
const results = [];
|
|
38004
38474
|
for (let i = 0; i < items.length; i += concurrency) {
|
|
@@ -38008,6 +38478,13 @@ async function batchRun(items, fn, concurrency = 5) {
|
|
|
38008
38478
|
}
|
|
38009
38479
|
return results;
|
|
38010
38480
|
}
|
|
38481
|
+
async function computeSha256(data) {
|
|
38482
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
38483
|
+
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
38484
|
+
}
|
|
38485
|
+
function slugify2(text2) {
|
|
38486
|
+
return text2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
38487
|
+
}
|
|
38011
38488
|
async function ensureContentTypes(mgmt, config3 = {}) {
|
|
38012
38489
|
const eventTypeId = config3.eventTypeId ?? "event";
|
|
38013
38490
|
const themeTypeId = config3.themeTypeId ?? "theme";
|
|
@@ -38028,7 +38505,7 @@ async function ensureContentTypes(mgmt, config3 = {}) {
|
|
|
38028
38505
|
{ id: "endTime", name: "End Time", type: "Symbol" },
|
|
38029
38506
|
{ id: "price", name: "Price", type: "Symbol" },
|
|
38030
38507
|
{ id: "image", name: "Image", type: "Link", linkType: "Asset" },
|
|
38031
|
-
{ id: "
|
|
38508
|
+
{ id: "isSpotlight", name: "Spotlight", type: "Boolean" },
|
|
38032
38509
|
{ id: "maxSlots", name: "Max Slots", type: "Integer" },
|
|
38033
38510
|
{ id: "gformsUrl", name: "Google Forms URL", type: "Symbol" },
|
|
38034
38511
|
{ id: "gformsEditorUrl", name: "Google Forms Editor URL", type: "Symbol" },
|
|
@@ -38113,7 +38590,7 @@ async function pushToContentful(db, mgmt, config3 = {}, kv, forceFull = false) {
|
|
|
38113
38590
|
const fields = {
|
|
38114
38591
|
title: ContentfulManagement.locale(event.title),
|
|
38115
38592
|
slug: ContentfulManagement.locale(event.slug),
|
|
38116
|
-
|
|
38593
|
+
isSpotlight: ContentfulManagement.locale(event.isSpotlight),
|
|
38117
38594
|
maxSlots: ContentfulManagement.locale(event.maxSlots)
|
|
38118
38595
|
};
|
|
38119
38596
|
if (event.themeId) fields.theme = ContentfulManagement.entryRef(event.themeId);
|
|
@@ -38170,7 +38647,7 @@ async function pushToContentful(db, mgmt, config3 = {}, kv, forceFull = false) {
|
|
|
38170
38647
|
}
|
|
38171
38648
|
|
|
38172
38649
|
// src/routes/site-config.ts
|
|
38173
|
-
var siteConfigRoute = new
|
|
38650
|
+
var siteConfigRoute = new chunkBFMJDSDI_cjs.Hono();
|
|
38174
38651
|
siteConfigRoute.get("/", async (c) => {
|
|
38175
38652
|
const db = createDb(c.env.DB);
|
|
38176
38653
|
const rows = await db.query.siteConfig.findMany();
|
|
@@ -38184,6 +38661,9 @@ siteConfigRoute.get("/", async (c) => {
|
|
|
38184
38661
|
siteName: config3.site_name ?? null,
|
|
38185
38662
|
registrationGloballyOpen: config3.registration_globally_open ?? true,
|
|
38186
38663
|
maintenanceMode: config3.maintenance_mode ?? false,
|
|
38664
|
+
// Prefer the D1-persisted value over the env-var default so that
|
|
38665
|
+
// PATCH /config/cms_mode changes are reflected immediately.
|
|
38666
|
+
cmsMode: config3.cms_mode ?? c.get("cmsMode"),
|
|
38187
38667
|
now: Math.floor(Date.now() / 1e3)
|
|
38188
38668
|
}
|
|
38189
38669
|
});
|
|
@@ -38205,6 +38685,10 @@ siteConfigRoute.patch("/:key", authMiddleware, adminMiddleware, async (c) => {
|
|
|
38205
38685
|
var SYNC_LOCK_KEY = "contentful:sync:lock";
|
|
38206
38686
|
var SYNC_LOCK_TTL = 60;
|
|
38207
38687
|
siteConfigRoute.post("/sync-content", authMiddleware, adminMiddleware, async (c) => {
|
|
38688
|
+
const cmsMode = c.get("cmsMode");
|
|
38689
|
+
if (cmsMode === "cloudflare") {
|
|
38690
|
+
throw serviceUnavailable("Contentful sync is not available in Cloudflare-only mode.");
|
|
38691
|
+
}
|
|
38208
38692
|
if (!ContentfulManagement.isConfigured(c.env.CONTENTFUL_SPACE_ID, c.env.CONTENTFUL_MANAGEMENT_TOKEN)) {
|
|
38209
38693
|
throw serviceUnavailable("Contentful Management API credentials not configured.");
|
|
38210
38694
|
}
|
|
@@ -38238,7 +38722,7 @@ var faqSchema = external_exports.object({
|
|
|
38238
38722
|
category: external_exports.string().optional(),
|
|
38239
38723
|
sortOrder: external_exports.number().int().default(0)
|
|
38240
38724
|
});
|
|
38241
|
-
var faqsRoute = new
|
|
38725
|
+
var faqsRoute = new chunkBFMJDSDI_cjs.Hono();
|
|
38242
38726
|
async function pushFaqToContentful(env2, faq) {
|
|
38243
38727
|
console.log("[Contentful] pushFaqToContentful called for FAQ:", faq.id);
|
|
38244
38728
|
if (!ContentfulManagement.isConfigured(env2.CONTENTFUL_SPACE_ID, env2.CONTENTFUL_MANAGEMENT_TOKEN)) {
|
|
@@ -38291,7 +38775,9 @@ faqsRoute.post(
|
|
|
38291
38775
|
const cache3 = new CacheService(c.env.KV);
|
|
38292
38776
|
const [created] = await db.insert(faqs).values(body).returning();
|
|
38293
38777
|
await cache3.del(FAQS_KV_KEY);
|
|
38294
|
-
c.
|
|
38778
|
+
if (c.get("cmsMode") === "hybrid") {
|
|
38779
|
+
c.executionCtx.waitUntil(pushFaqToContentful(c.env, created));
|
|
38780
|
+
}
|
|
38295
38781
|
return c.json({ data: created }, 201);
|
|
38296
38782
|
}
|
|
38297
38783
|
);
|
|
@@ -38304,7 +38790,9 @@ faqsRoute.patch("/:id", authMiddleware, adminMiddleware, async (c) => {
|
|
|
38304
38790
|
const [updated] = await db.update(faqs).set({ ...body, updatedAt: now2 }).where(eq(faqs.id, id)).returning();
|
|
38305
38791
|
if (!updated) throw notFound("FAQ");
|
|
38306
38792
|
await cache3.del(FAQS_KV_KEY);
|
|
38307
|
-
c.
|
|
38793
|
+
if (c.get("cmsMode") === "hybrid") {
|
|
38794
|
+
c.executionCtx.waitUntil(pushFaqToContentful(c.env, updated));
|
|
38795
|
+
}
|
|
38308
38796
|
return c.json({ data: updated });
|
|
38309
38797
|
});
|
|
38310
38798
|
faqsRoute.delete("/:id", authMiddleware, adminMiddleware, async (c) => {
|
|
@@ -38318,7 +38806,7 @@ faqsRoute.delete("/:id", authMiddleware, adminMiddleware, async (c) => {
|
|
|
38318
38806
|
});
|
|
38319
38807
|
|
|
38320
38808
|
// src/routes/internal/gforms-webhook.ts
|
|
38321
|
-
var gformsWebhookRoute = new
|
|
38809
|
+
var gformsWebhookRoute = new chunkBFMJDSDI_cjs.Hono();
|
|
38322
38810
|
gformsWebhookRoute.post("/", internalMiddleware, async (c) => {
|
|
38323
38811
|
const rawBody = await c.req.text();
|
|
38324
38812
|
const signature = c.req.header("X-Goog-Signature");
|
|
@@ -38390,7 +38878,7 @@ var ALLOWED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
|
38390
38878
|
"image/svg+xml"
|
|
38391
38879
|
]);
|
|
38392
38880
|
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
38393
|
-
var uploadsRoute = new
|
|
38881
|
+
var uploadsRoute = new chunkBFMJDSDI_cjs.Hono();
|
|
38394
38882
|
uploadsRoute.get("/images/*", async (c) => {
|
|
38395
38883
|
const bucket = c.env.FILES;
|
|
38396
38884
|
if (!bucket) {
|
|
@@ -38564,7 +39052,7 @@ var createThemeSchema = external_exports.object({
|
|
|
38564
39052
|
name: external_exports.string().min(1),
|
|
38565
39053
|
path: external_exports.string().min(1)
|
|
38566
39054
|
});
|
|
38567
|
-
var themesRoute = new
|
|
39055
|
+
var themesRoute = new chunkBFMJDSDI_cjs.Hono();
|
|
38568
39056
|
themesRoute.get("/", async (c) => {
|
|
38569
39057
|
const db = createDb(c.env.DB);
|
|
38570
39058
|
const data = await db.select().from(themes);
|
|
@@ -38580,7 +39068,9 @@ themesRoute.post(
|
|
|
38580
39068
|
const db = createDb(c.env.DB);
|
|
38581
39069
|
try {
|
|
38582
39070
|
const [created] = await db.insert(themes).values(body).returning();
|
|
38583
|
-
c.
|
|
39071
|
+
if (c.get("cmsMode") === "hybrid") {
|
|
39072
|
+
c.executionCtx.waitUntil(pushThemeToContentful(c.env, created));
|
|
39073
|
+
}
|
|
38584
39074
|
return c.json({ data: created }, 201);
|
|
38585
39075
|
} catch (err) {
|
|
38586
39076
|
if (err.message && err.message.includes("UNIQUE constraint failed")) {
|
|
@@ -38601,7 +39091,9 @@ themesRoute.patch(
|
|
|
38601
39091
|
try {
|
|
38602
39092
|
const [updated] = await db.update(themes).set(body).where(eq(themes.id, id)).returning();
|
|
38603
39093
|
if (!updated) throw notFound("Theme");
|
|
38604
|
-
c.
|
|
39094
|
+
if (c.get("cmsMode") === "hybrid") {
|
|
39095
|
+
c.executionCtx.waitUntil(pushThemeToContentful(c.env, updated));
|
|
39096
|
+
}
|
|
38605
39097
|
return c.json({ data: updated });
|
|
38606
39098
|
} catch (err) {
|
|
38607
39099
|
if (err.message && err.message.includes("UNIQUE constraint failed")) {
|
|
@@ -38616,7 +39108,9 @@ themesRoute.delete("/:id", authMiddleware, adminMiddleware, async (c) => {
|
|
|
38616
39108
|
const db = createDb(c.env.DB);
|
|
38617
39109
|
const [deleted] = await db.delete(themes).where(eq(themes.id, id)).returning();
|
|
38618
39110
|
if (!deleted) throw notFound("Theme");
|
|
38619
|
-
c.
|
|
39111
|
+
if (c.get("cmsMode") === "hybrid") {
|
|
39112
|
+
c.executionCtx.waitUntil(deleteThemeFromContentful(c.env, id));
|
|
39113
|
+
}
|
|
38620
39114
|
return c.body(null, 204);
|
|
38621
39115
|
});
|
|
38622
39116
|
|
|
@@ -38627,7 +39121,7 @@ var createOrganizationSchema = external_exports.object({
|
|
|
38627
39121
|
logoUrl: external_exports.string().url().nullable().optional(),
|
|
38628
39122
|
link: external_exports.string().url().nullable().optional()
|
|
38629
39123
|
});
|
|
38630
|
-
var organizationsRoute = new
|
|
39124
|
+
var organizationsRoute = new chunkBFMJDSDI_cjs.Hono();
|
|
38631
39125
|
organizationsRoute.get("/", async (c) => {
|
|
38632
39126
|
const db = createDb(c.env.DB);
|
|
38633
39127
|
const data = await db.select().from(organizations);
|
|
@@ -38680,9 +39174,86 @@ organizationsRoute.delete("/:id", authMiddleware, adminMiddleware, async (c) =>
|
|
|
38680
39174
|
return c.body(null, 204);
|
|
38681
39175
|
});
|
|
38682
39176
|
|
|
39177
|
+
// src/routes/contentful-sync.ts
|
|
39178
|
+
var contentfulSyncRoute = new chunkBFMJDSDI_cjs.Hono();
|
|
39179
|
+
contentfulSyncRoute.post(
|
|
39180
|
+
"/trigger",
|
|
39181
|
+
authMiddleware,
|
|
39182
|
+
adminMiddleware,
|
|
39183
|
+
async (c) => {
|
|
39184
|
+
const env2 = c.env;
|
|
39185
|
+
const { CONTENTFUL_SPACE_ID, CONTENTFUL_ACCESS_TOKEN, CONTENTFUL_MANAGEMENT_TOKEN, CONTENTFUL_ENVIRONMENT } = env2;
|
|
39186
|
+
if (!CONTENTFUL_SPACE_ID || !CONTENTFUL_ACCESS_TOKEN) {
|
|
39187
|
+
return c.json({ error: { code: "NOT_CONFIGURED", message: "Contentful credentials missing" } }, 400);
|
|
39188
|
+
}
|
|
39189
|
+
const db = createDb(env2.DB);
|
|
39190
|
+
const contentful = new ContentfulService(CONTENTFUL_SPACE_ID, CONTENTFUL_ACCESS_TOKEN, CONTENTFUL_ENVIRONMENT);
|
|
39191
|
+
try {
|
|
39192
|
+
if (CONTENTFUL_MANAGEMENT_TOKEN) {
|
|
39193
|
+
const mgmt = new ContentfulManagement(CONTENTFUL_SPACE_ID, CONTENTFUL_MANAGEMENT_TOKEN, CONTENTFUL_ENVIRONMENT);
|
|
39194
|
+
await ensureContentTypes(mgmt);
|
|
39195
|
+
}
|
|
39196
|
+
c.executionCtx.waitUntil(
|
|
39197
|
+
snapshotAllContent(db, env2.FILES, contentful, {}, env2.KV).then((r) => console.log("[Contentful] Snapshot complete:", JSON.stringify(r))).catch((err) => console.error("[Contentful] Snapshot failed:", err))
|
|
39198
|
+
);
|
|
39199
|
+
return c.json({ message: "Contentful sync triggered", triggeredAt: Math.floor(Date.now() / 1e3) });
|
|
39200
|
+
} catch (err) {
|
|
39201
|
+
console.error("[Contentful] Sync trigger failed:", err);
|
|
39202
|
+
return c.json({ error: { code: "SYNC_FAILED", message: err?.message ?? "Failed to trigger sync" } }, 500);
|
|
39203
|
+
}
|
|
39204
|
+
}
|
|
39205
|
+
);
|
|
39206
|
+
contentfulSyncRoute.post(
|
|
39207
|
+
"/push",
|
|
39208
|
+
authMiddleware,
|
|
39209
|
+
adminMiddleware,
|
|
39210
|
+
async (c) => {
|
|
39211
|
+
const env2 = c.env;
|
|
39212
|
+
const { CONTENTFUL_SPACE_ID, CONTENTFUL_MANAGEMENT_TOKEN, CONTENTFUL_ENVIRONMENT } = env2;
|
|
39213
|
+
if (!CONTENTFUL_SPACE_ID || !CONTENTFUL_MANAGEMENT_TOKEN) {
|
|
39214
|
+
return c.json({ error: { code: "NOT_CONFIGURED", message: "Contentful management credentials missing" } }, 400);
|
|
39215
|
+
}
|
|
39216
|
+
const db = createDb(env2.DB);
|
|
39217
|
+
const mgmt = new ContentfulManagement(CONTENTFUL_SPACE_ID, CONTENTFUL_MANAGEMENT_TOKEN, CONTENTFUL_ENVIRONMENT);
|
|
39218
|
+
try {
|
|
39219
|
+
c.executionCtx.waitUntil(
|
|
39220
|
+
pushToContentful(db, mgmt, {}, env2.KV).then((r) => console.log("[Contentful] Push complete:", JSON.stringify(r))).catch((err) => console.error("[Contentful] Push failed:", err))
|
|
39221
|
+
);
|
|
39222
|
+
return c.json({ message: "Contentful push triggered", triggeredAt: Math.floor(Date.now() / 1e3) });
|
|
39223
|
+
} catch (err) {
|
|
39224
|
+
console.error("[Contentful] Push trigger failed:", err);
|
|
39225
|
+
return c.json({ error: { code: "SYNC_FAILED", message: err?.message ?? "Failed to trigger push" } }, 500);
|
|
39226
|
+
}
|
|
39227
|
+
}
|
|
39228
|
+
);
|
|
39229
|
+
contentfulSyncRoute.get(
|
|
39230
|
+
"/status",
|
|
39231
|
+
authMiddleware,
|
|
39232
|
+
adminMiddleware,
|
|
39233
|
+
async (c) => {
|
|
39234
|
+
const env2 = c.env;
|
|
39235
|
+
const db = createDb(env2.DB);
|
|
39236
|
+
const [[{ themes: themes2 }], [{ events: events2 }], [{ faqs: faqs2 }], [{ orgs }]] = await Promise.all([
|
|
39237
|
+
db.all(sql2`SELECT count(*) as themes FROM themes`),
|
|
39238
|
+
db.all(sql2`SELECT count(*) as events FROM events`),
|
|
39239
|
+
db.all(sql2`SELECT count(*) as faqs FROM faqs`),
|
|
39240
|
+
db.all(sql2`SELECT count(*) as orgs FROM organizations`)
|
|
39241
|
+
]);
|
|
39242
|
+
const isConfigured = !!env2.CONTENTFUL_SPACE_ID && !!env2.CONTENTFUL_ACCESS_TOKEN;
|
|
39243
|
+
const canPush = !!env2.CONTENTFUL_SPACE_ID && !!env2.CONTENTFUL_MANAGEMENT_TOKEN;
|
|
39244
|
+
return c.json({
|
|
39245
|
+
isConfigured,
|
|
39246
|
+
canPush,
|
|
39247
|
+
cmsMode: c.get("cmsMode"),
|
|
39248
|
+
spaceId: env2.CONTENTFUL_SPACE_ID ?? null,
|
|
39249
|
+
totals: { themes: themes2, events: events2, faqs: faqs2, organizations: orgs }
|
|
39250
|
+
});
|
|
39251
|
+
}
|
|
39252
|
+
);
|
|
39253
|
+
|
|
38683
39254
|
// src/app.ts
|
|
38684
39255
|
function createApp(options = {}) {
|
|
38685
|
-
const app = new
|
|
39256
|
+
const app = new chunkBFMJDSDI_cjs.Hono();
|
|
38686
39257
|
if (options.gformsWebhookUrl) {
|
|
38687
39258
|
const webhookUrl = `${options.gformsWebhookUrl.replace(/\/$/, "")}/internal/gforms-webhook`;
|
|
38688
39259
|
app.use("*", async (c, next) => {
|
|
@@ -38691,8 +39262,14 @@ function createApp(options = {}) {
|
|
|
38691
39262
|
});
|
|
38692
39263
|
}
|
|
38693
39264
|
app.use("*", createCorsMiddleware(options.allowedOrigins ?? ["*"]));
|
|
38694
|
-
app.use("*",
|
|
39265
|
+
app.use("*", chunkBFMJDSDI_cjs.createPowChallengeMiddleware());
|
|
38695
39266
|
app.use("*", createRefererGuard(options.allowedOrigins ?? ["*"]));
|
|
39267
|
+
app.use("*", async (c, next) => {
|
|
39268
|
+
const overrideRaw = await c.env.KV.get("config:cms_mode").catch(() => null);
|
|
39269
|
+
const override = overrideRaw ? JSON.parse(overrideRaw) : null;
|
|
39270
|
+
c.set("cmsMode", parseCmsMode(override ?? c.env.CMS_MODE));
|
|
39271
|
+
return next();
|
|
39272
|
+
});
|
|
38696
39273
|
app.on(["POST", "GET"], "/api/auth/*", (c) => {
|
|
38697
39274
|
const auth = createAuth(c.env);
|
|
38698
39275
|
const req = c.req.raw;
|
|
@@ -38704,7 +39281,7 @@ function createApp(options = {}) {
|
|
|
38704
39281
|
return auth.handler(new Request(req.url, {
|
|
38705
39282
|
method: req.method,
|
|
38706
39283
|
headers: newHeaders,
|
|
38707
|
-
body: req.method === "GET" ? null : req.body,
|
|
39284
|
+
body: req.method === "GET" || req.method === "HEAD" || req.method === "OPTIONS" ? null : req.body,
|
|
38708
39285
|
redirect: req.redirect
|
|
38709
39286
|
}));
|
|
38710
39287
|
}
|
|
@@ -38722,15 +39299,16 @@ function createApp(options = {}) {
|
|
|
38722
39299
|
}
|
|
38723
39300
|
return next();
|
|
38724
39301
|
});
|
|
38725
|
-
app.post(
|
|
39302
|
+
app.post(chunkBFMJDSDI_cjs.POW_VERIFY_PATH, chunkBFMJDSDI_cjs.handlePowVerify);
|
|
38726
39303
|
app.route("/health", healthRoute);
|
|
38727
39304
|
app.route("/api/config", siteConfigRoute);
|
|
38728
|
-
app.route("/api/
|
|
39305
|
+
app.route("/api/classes", classesRoute);
|
|
38729
39306
|
app.route("/api/themes", themesRoute);
|
|
38730
39307
|
app.route("/api/users", usersRoute);
|
|
38731
39308
|
app.route("/api/organizations", organizationsRoute);
|
|
38732
39309
|
app.route("/api/faqs", faqsRoute);
|
|
38733
39310
|
app.route("/api/uploads", uploadsRoute);
|
|
39311
|
+
app.route("/api/contentful", contentfulSyncRoute);
|
|
38734
39312
|
app.route("/internal/gforms-webhook", gformsWebhookRoute);
|
|
38735
39313
|
app.onError(errorHandler);
|
|
38736
39314
|
app.notFound(
|
|
@@ -39364,6 +39942,7 @@ var PATCH_STATEMENTS = [
|
|
|
39364
39942
|
`ALTER TABLE "events" ADD COLUMN "class_code" text`,
|
|
39365
39943
|
`ALTER TABLE "events" ADD COLUMN "start_time" text`,
|
|
39366
39944
|
`ALTER TABLE "events" ADD COLUMN "end_time" text`,
|
|
39945
|
+
`ALTER TABLE "events" RENAME COLUMN "is_major" TO "is_spotlight"`,
|
|
39367
39946
|
`CREATE INDEX IF NOT EXISTS "idx_events_organization_id" ON "events" ("organization_id")`
|
|
39368
39947
|
];
|
|
39369
39948
|
var CREATE_STATEMENTS = [
|
|
@@ -39467,7 +40046,7 @@ var CREATE_STATEMENTS = [
|
|
|
39467
40046
|
"class_code" text,
|
|
39468
40047
|
"start_time" text,
|
|
39469
40048
|
"end_time" text,
|
|
39470
|
-
"
|
|
40049
|
+
"is_spotlight" integer DEFAULT false NOT NULL,
|
|
39471
40050
|
"max_slots" integer DEFAULT 0 NOT NULL,
|
|
39472
40051
|
"registered_slots" integer DEFAULT 0 NOT NULL,
|
|
39473
40052
|
"gforms_id" text,
|
|
@@ -39529,7 +40108,9 @@ async function ensureDatabase(d1) {
|
|
|
39529
40108
|
try {
|
|
39530
40109
|
await d1.prepare(sql3).run();
|
|
39531
40110
|
} catch (err) {
|
|
39532
|
-
if (err?.message?.includes("duplicate column"))
|
|
40111
|
+
if (err?.message?.includes("duplicate column") || err?.message?.includes("no such column: is_major")) {
|
|
40112
|
+
continue;
|
|
40113
|
+
}
|
|
39533
40114
|
throw err;
|
|
39534
40115
|
}
|
|
39535
40116
|
}
|
|
@@ -39538,12 +40119,14 @@ async function ensureDatabase(d1) {
|
|
|
39538
40119
|
// src/worker-handler.ts
|
|
39539
40120
|
var API_PREFIXES = [
|
|
39540
40121
|
"/api/auth/",
|
|
39541
|
-
"/api/
|
|
40122
|
+
"/api/classes",
|
|
39542
40123
|
"/api/users",
|
|
40124
|
+
"/api/organizations",
|
|
39543
40125
|
"/api/faqs",
|
|
39544
40126
|
"/api/themes",
|
|
39545
40127
|
"/api/config",
|
|
39546
40128
|
"/api/uploads",
|
|
40129
|
+
"/api/contentful",
|
|
39547
40130
|
"/health",
|
|
39548
40131
|
"/internal/",
|
|
39549
40132
|
"/.well-known/"
|
|
@@ -39582,7 +40165,7 @@ function createWorkerHandler(options) {
|
|
|
39582
40165
|
return getLeapify(env2).fetch(request, env2, ctx);
|
|
39583
40166
|
}
|
|
39584
40167
|
let response = await options.serveFrontend(request, env2, ctx);
|
|
39585
|
-
if ((!response || response.status === 404) && !pathname.includes(".")) {
|
|
40168
|
+
if ((!response || response.status === 404) && !pathname.includes(".") && request.method === "GET") {
|
|
39586
40169
|
const indexRequest = new Request(new URL("/", request.url), request);
|
|
39587
40170
|
response = await options.serveFrontend(indexRequest, env2, ctx);
|
|
39588
40171
|
}
|
|
@@ -39690,6 +40273,7 @@ function injectConfig2(html2, config3) {
|
|
|
39690
40273
|
(*! noble-ciphers - MIT License (c) 2023 Paul Miller (paulmillr.com) *)
|
|
39691
40274
|
*/
|
|
39692
40275
|
|
|
40276
|
+
exports.CONTENTFUL_CONFIG_KEYS = CONTENTFUL_CONFIG_KEYS;
|
|
39693
40277
|
exports.ContentfulManagement = ContentfulManagement;
|
|
39694
40278
|
exports.authAccount = authAccount;
|
|
39695
40279
|
exports.authSession = authSession;
|
|
@@ -39697,6 +40281,7 @@ exports.authUser = authUser;
|
|
|
39697
40281
|
exports.authVerification = authVerification;
|
|
39698
40282
|
exports.bookmarks = bookmarks;
|
|
39699
40283
|
exports.bookmarksRelations = bookmarksRelations;
|
|
40284
|
+
exports.contentfulConfig = contentfulConfig;
|
|
39700
40285
|
exports.createDb = createDb;
|
|
39701
40286
|
exports.createLeapify = createLeapify;
|
|
39702
40287
|
exports.createQueueHandler = createQueueHandler;
|
|
@@ -39710,6 +40295,9 @@ exports.getRuntimeConfig = getRuntimeConfig;
|
|
|
39710
40295
|
exports.injectConfig = injectConfig2;
|
|
39711
40296
|
exports.organizations = organizations;
|
|
39712
40297
|
exports.organizationsRelations = organizationsRelations;
|
|
40298
|
+
exports.parseCmsMode = parseCmsMode;
|
|
40299
|
+
exports.shouldPullFromContentful = shouldPullFromContentful;
|
|
40300
|
+
exports.shouldPushToContentful = shouldPushToContentful;
|
|
39713
40301
|
exports.siteConfig = siteConfig;
|
|
39714
40302
|
exports.themes = themes;
|
|
39715
40303
|
exports.themesRelations = themesRelations;
|