@notionx/core 0.1.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.
Files changed (208) hide show
  1. package/dist/admin/index.d.ts +137 -0
  2. package/dist/admin/index.js +206 -0
  3. package/dist/admin/index.js.map +1 -0
  4. package/dist/admin/pages/index.d.ts +324 -0
  5. package/dist/admin/pages/index.js +827 -0
  6. package/dist/admin/pages/index.js.map +1 -0
  7. package/dist/auth/auth-pages/forgot-password.d.ts +20 -0
  8. package/dist/auth/auth-pages/forgot-password.js +70 -0
  9. package/dist/auth/auth-pages/forgot-password.js.map +1 -0
  10. package/dist/auth/auth-pages/index.d.ts +6 -0
  11. package/dist/auth/auth-pages/index.js +342 -0
  12. package/dist/auth/auth-pages/index.js.map +1 -0
  13. package/dist/auth/auth-pages/login.d.ts +30 -0
  14. package/dist/auth/auth-pages/login.js +125 -0
  15. package/dist/auth/auth-pages/login.js.map +1 -0
  16. package/dist/auth/auth-pages/register.d.ts +17 -0
  17. package/dist/auth/auth-pages/register.js +81 -0
  18. package/dist/auth/auth-pages/register.js.map +1 -0
  19. package/dist/auth/auth-pages/reset-password.d.ts +18 -0
  20. package/dist/auth/auth-pages/reset-password.js +72 -0
  21. package/dist/auth/auth-pages/reset-password.js.map +1 -0
  22. package/dist/auth/index.d.ts +72 -0
  23. package/dist/auth/index.js +1011 -0
  24. package/dist/auth/index.js.map +1 -0
  25. package/dist/auth/passwords.d.ts +6 -0
  26. package/dist/auth/passwords.js +79 -0
  27. package/dist/auth/passwords.js.map +1 -0
  28. package/dist/auth/rate-limit.d.ts +28 -0
  29. package/dist/auth/rate-limit.js +245 -0
  30. package/dist/auth/rate-limit.js.map +1 -0
  31. package/dist/auth/routes/google-callback.d.ts +6 -0
  32. package/dist/auth/routes/google-callback.js +404 -0
  33. package/dist/auth/routes/google-callback.js.map +1 -0
  34. package/dist/auth/routes/google.d.ts +6 -0
  35. package/dist/auth/routes/google.js +250 -0
  36. package/dist/auth/routes/google.js.map +1 -0
  37. package/dist/auth/routes/index.d.ts +22 -0
  38. package/dist/auth/routes/index.js +619 -0
  39. package/dist/auth/routes/index.js.map +1 -0
  40. package/dist/auth/routes/verify-email.d.ts +6 -0
  41. package/dist/auth/routes/verify-email.js +317 -0
  42. package/dist/auth/routes/verify-email.js.map +1 -0
  43. package/dist/auth/routes/viewer.d.ts +6 -0
  44. package/dist/auth/routes/viewer.js +372 -0
  45. package/dist/auth/routes/viewer.js.map +1 -0
  46. package/dist/auth/session.d.ts +9 -0
  47. package/dist/auth/session.js +1 -0
  48. package/dist/auth/session.js.map +1 -0
  49. package/dist/auth/turnstile.d.ts +20 -0
  50. package/dist/auth/turnstile.js +301 -0
  51. package/dist/auth/turnstile.js.map +1 -0
  52. package/dist/auth/user-session.d.ts +42 -0
  53. package/dist/auth/user-session.js +419 -0
  54. package/dist/auth/user-session.js.map +1 -0
  55. package/dist/auth/users.d.ts +112 -0
  56. package/dist/auth/users.js +558 -0
  57. package/dist/auth/users.js.map +1 -0
  58. package/dist/bootstrap-CN2g76M6.d.ts +67 -0
  59. package/dist/cache/index.d.ts +6 -0
  60. package/dist/cache/index.js +47 -0
  61. package/dist/cache/index.js.map +1 -0
  62. package/dist/content/admin-summary.d.ts +24 -0
  63. package/dist/content/admin-summary.js +36 -0
  64. package/dist/content/admin-summary.js.map +1 -0
  65. package/dist/content/index.d.ts +9 -0
  66. package/dist/content/index.js +473 -0
  67. package/dist/content/index.js.map +1 -0
  68. package/dist/content/models.d.ts +69 -0
  69. package/dist/content/models.js +24 -0
  70. package/dist/content/models.js.map +1 -0
  71. package/dist/content/prewarm.d.ts +28 -0
  72. package/dist/content/prewarm.js +56 -0
  73. package/dist/content/prewarm.js.map +1 -0
  74. package/dist/content/revalidate.d.ts +37 -0
  75. package/dist/content/revalidate.js +170 -0
  76. package/dist/content/revalidate.js.map +1 -0
  77. package/dist/content/search-index.d.ts +54 -0
  78. package/dist/content/search-index.js +172 -0
  79. package/dist/content/search-index.js.map +1 -0
  80. package/dist/content/search.d.ts +8 -0
  81. package/dist/content/search.js +57 -0
  82. package/dist/content/search.js.map +1 -0
  83. package/dist/doctor/cli.d.ts +1 -0
  84. package/dist/doctor/cli.js +360 -0
  85. package/dist/doctor/cli.js.map +1 -0
  86. package/dist/doctor/index.d.ts +139 -0
  87. package/dist/doctor/index.js +289 -0
  88. package/dist/doctor/index.js.map +1 -0
  89. package/dist/email/index.d.ts +38 -0
  90. package/dist/email/index.js +126 -0
  91. package/dist/email/index.js.map +1 -0
  92. package/dist/env-C5qu-0R-.d.ts +35 -0
  93. package/dist/hooks/index.d.ts +2 -0
  94. package/dist/hooks/index.js +1 -0
  95. package/dist/hooks/index.js.map +1 -0
  96. package/dist/i18n/index.d.ts +26 -0
  97. package/dist/i18n/index.js +73 -0
  98. package/dist/i18n/index.js.map +1 -0
  99. package/dist/index.d.ts +8 -0
  100. package/dist/index.js +1281 -0
  101. package/dist/index.js.map +1 -0
  102. package/dist/internal/admin/index.d.ts +75 -0
  103. package/dist/internal/admin/index.js +365 -0
  104. package/dist/internal/admin/index.js.map +1 -0
  105. package/dist/media/index.d.ts +24 -0
  106. package/dist/media/index.js +86 -0
  107. package/dist/media/index.js.map +1 -0
  108. package/dist/media/routes/index.d.ts +1 -0
  109. package/dist/media/routes/index.js +585 -0
  110. package/dist/media/routes/index.js.map +1 -0
  111. package/dist/media/routes/notion-media.d.ts +19 -0
  112. package/dist/media/routes/notion-media.js +588 -0
  113. package/dist/media/routes/notion-media.js.map +1 -0
  114. package/dist/middleware.d.ts +95 -0
  115. package/dist/middleware.js +79 -0
  116. package/dist/middleware.js.map +1 -0
  117. package/dist/notion/block-text.d.ts +5 -0
  118. package/dist/notion/block-text.js +37 -0
  119. package/dist/notion/block-text.js.map +1 -0
  120. package/dist/notion/blocks.d.ts +24 -0
  121. package/dist/notion/blocks.js +46 -0
  122. package/dist/notion/blocks.js.map +1 -0
  123. package/dist/notion/client.d.ts +7 -0
  124. package/dist/notion/client.js +13 -0
  125. package/dist/notion/client.js.map +1 -0
  126. package/dist/notion/config.d.ts +25 -0
  127. package/dist/notion/config.js +147 -0
  128. package/dist/notion/config.js.map +1 -0
  129. package/dist/notion/content-cache.d.ts +45 -0
  130. package/dist/notion/content-cache.js +166 -0
  131. package/dist/notion/content-cache.js.map +1 -0
  132. package/dist/notion/generic-source.d.ts +61 -0
  133. package/dist/notion/generic-source.js +408 -0
  134. package/dist/notion/generic-source.js.map +1 -0
  135. package/dist/notion/index.d.ts +13 -0
  136. package/dist/notion/index.js +1278 -0
  137. package/dist/notion/index.js.map +1 -0
  138. package/dist/notion/mappers.d.ts +1 -0
  139. package/dist/notion/mappers.js +152 -0
  140. package/dist/notion/mappers.js.map +1 -0
  141. package/dist/notion/media.d.ts +22 -0
  142. package/dist/notion/media.js +209 -0
  143. package/dist/notion/media.js.map +1 -0
  144. package/dist/notion/property-mappers.d.ts +24 -0
  145. package/dist/notion/property-mappers.js +152 -0
  146. package/dist/notion/property-mappers.js.map +1 -0
  147. package/dist/notion/routes/index.d.ts +8 -0
  148. package/dist/notion/routes/index.js +428 -0
  149. package/dist/notion/routes/index.js.map +1 -0
  150. package/dist/notion/routes/webhook.d.ts +98 -0
  151. package/dist/notion/routes/webhook.js +428 -0
  152. package/dist/notion/routes/webhook.js.map +1 -0
  153. package/dist/notion/types.d.ts +152 -0
  154. package/dist/notion/types.js +1 -0
  155. package/dist/notion/types.js.map +1 -0
  156. package/dist/notion/webhook.d.ts +83 -0
  157. package/dist/notion/webhook.js +490 -0
  158. package/dist/notion/webhook.js.map +1 -0
  159. package/dist/platform/capabilities.d.ts +34 -0
  160. package/dist/platform/capabilities.js +42 -0
  161. package/dist/platform/capabilities.js.map +1 -0
  162. package/dist/platform/current.d.ts +13 -0
  163. package/dist/platform/current.js +181 -0
  164. package/dist/platform/current.js.map +1 -0
  165. package/dist/platform/index.d.ts +5 -0
  166. package/dist/platform/index.js +269 -0
  167. package/dist/platform/index.js.map +1 -0
  168. package/dist/platform/runtime.d.ts +118 -0
  169. package/dist/platform/runtime.js +160 -0
  170. package/dist/platform/runtime.js.map +1 -0
  171. package/dist/platform/selection.d.ts +10 -0
  172. package/dist/platform/selection.js +22 -0
  173. package/dist/platform/selection.js.map +1 -0
  174. package/dist/storage/index.d.ts +17 -0
  175. package/dist/storage/index.js +218 -0
  176. package/dist/storage/index.js.map +1 -0
  177. package/dist/storage/routes/cdn.d.ts +19 -0
  178. package/dist/storage/routes/cdn.js +289 -0
  179. package/dist/storage/routes/cdn.js.map +1 -0
  180. package/dist/storage/routes/files.d.ts +27 -0
  181. package/dist/storage/routes/files.js +216 -0
  182. package/dist/storage/routes/files.js.map +1 -0
  183. package/dist/storage/routes/index.d.ts +2 -0
  184. package/dist/storage/routes/index.js +352 -0
  185. package/dist/storage/routes/index.js.map +1 -0
  186. package/dist/types-BsAcZSNX.d.ts +94 -0
  187. package/dist/types.d.ts +78 -0
  188. package/dist/types.js +1 -0
  189. package/dist/types.js.map +1 -0
  190. package/dist/util/index.d.ts +18 -0
  191. package/dist/util/index.js +48 -0
  192. package/dist/util/index.js.map +1 -0
  193. package/dist/worker/index.d.ts +6 -0
  194. package/dist/worker/index.js +1026 -0
  195. package/dist/worker/index.js.map +1 -0
  196. package/dist/worker/routes/content-prewarm.d.ts +34 -0
  197. package/dist/worker/routes/content-prewarm.js +38 -0
  198. package/dist/worker/routes/content-prewarm.js.map +1 -0
  199. package/dist/worker/routes/content-revalidate.d.ts +81 -0
  200. package/dist/worker/routes/content-revalidate.js +64 -0
  201. package/dist/worker/routes/content-revalidate.js.map +1 -0
  202. package/dist/worker/routes/health.d.ts +14 -0
  203. package/dist/worker/routes/health.js +278 -0
  204. package/dist/worker/routes/health.js.map +1 -0
  205. package/dist/worker/routes/index.d.ts +6 -0
  206. package/dist/worker/routes/index.js +373 -0
  207. package/dist/worker/routes/index.js.map +1 -0
  208. package/package.json +124 -0
@@ -0,0 +1,1026 @@
1
+ // src/middleware.ts
2
+ var requestContext = /* @__PURE__ */ new WeakMap();
3
+ function defaultIsProtectedPath(request) {
4
+ const url = new URL(request.url);
5
+ if (url.pathname.startsWith("/api/admin/")) return true;
6
+ if (url.pathname.startsWith("/admin")) {
7
+ return request.method !== "GET" && request.method !== "HEAD";
8
+ }
9
+ return false;
10
+ }
11
+ function readSessionCookie(request, name) {
12
+ const header = request.headers.get("cookie");
13
+ if (!header) return null;
14
+ for (const part of header.split(";")) {
15
+ const [rawKey, ...rest] = part.split("=");
16
+ if (!rawKey) continue;
17
+ if (rawKey.trim() !== name) continue;
18
+ return rest.join("=").trim() || null;
19
+ }
20
+ return null;
21
+ }
22
+ async function resolveFoundationViewer(request, options) {
23
+ const sessionId = readSessionCookie(
24
+ request,
25
+ options.authConfig.sessionCookie.name
26
+ );
27
+ if (!sessionId || !options.sessionLookup) {
28
+ return { viewer: null, sessionId: sessionId ?? null };
29
+ }
30
+ const env2 = request.env ?? null;
31
+ const lookup = await options.sessionLookup(sessionId, env2);
32
+ if (!lookup) {
33
+ return { viewer: null, sessionId };
34
+ }
35
+ return {
36
+ viewer: {
37
+ userId: lookup.userId,
38
+ role: lookup.role,
39
+ email: lookup.email ?? null
40
+ },
41
+ sessionId
42
+ };
43
+ }
44
+ async function nextionMiddleware(request, env2, options) {
45
+ const context = await resolveFoundationViewer(request, options);
46
+ requestContext.set(request, context);
47
+ const isProtected = options.isProtectedPath ?? defaultIsProtectedPath;
48
+ if (!isProtected(request)) return null;
49
+ if (context.viewer) return null;
50
+ return new Response(
51
+ JSON.stringify({ ok: false, error: "Unauthorized" }),
52
+ {
53
+ status: 401,
54
+ headers: {
55
+ "Content-Type": "application/json",
56
+ "Cache-Control": "no-store",
57
+ "X-Foundation-Gate": "admin"
58
+ }
59
+ }
60
+ );
61
+ }
62
+
63
+ // src/storage/routes/files.ts
64
+ import { NextResponse } from "next/server";
65
+
66
+ // src/util/env.ts
67
+ import { env } from "cloudflare:workers";
68
+ var workerEnv = env;
69
+
70
+ // src/platform/runtime.ts
71
+ function cacheRequestForKey(key) {
72
+ return new Request(key, { method: "GET" });
73
+ }
74
+ function createCloudflarePublicCacheAdapter(cache) {
75
+ return {
76
+ kind: "cloudflare-cache",
77
+ async match(key) {
78
+ return await cache.match(cacheRequestForKey(key)) ?? null;
79
+ },
80
+ put(key, response) {
81
+ return cache.put(cacheRequestForKey(key), response);
82
+ },
83
+ delete(key) {
84
+ return cache.delete(cacheRequestForKey(key));
85
+ }
86
+ };
87
+ }
88
+ function createCloudflareKeyValueCacheAdapter(namespace) {
89
+ return {
90
+ kind: "workers-kv",
91
+ async get(key, options) {
92
+ return await namespace.get(key, {
93
+ type: "json",
94
+ cacheTtl: options?.cacheTtl
95
+ });
96
+ },
97
+ async put(key, value, options) {
98
+ await namespace.put(key, JSON.stringify(value), {
99
+ expirationTtl: options?.expirationTtl,
100
+ metadata: options?.metadata
101
+ });
102
+ },
103
+ delete(key) {
104
+ return namespace.delete(key);
105
+ },
106
+ async list(options) {
107
+ const result = await namespace.list({
108
+ prefix: options?.prefix,
109
+ limit: options?.limit,
110
+ cursor: options?.cursor
111
+ });
112
+ return {
113
+ keys: result.keys.map((key) => ({ name: key.name })),
114
+ cursor: result.list_complete ? void 0 : result.cursor,
115
+ listComplete: result.list_complete
116
+ };
117
+ }
118
+ };
119
+ }
120
+ function r2ObjectToStoredObject(object) {
121
+ return {
122
+ body: object.body,
123
+ size: object.size,
124
+ etag: object.etag,
125
+ contentType: object.httpMetadata?.contentType
126
+ };
127
+ }
128
+ function createCloudflareRuntimePlatform(env2, options) {
129
+ const database = env2.DB ? {
130
+ kind: "d1",
131
+ prepare(query) {
132
+ return env2.DB.prepare(query);
133
+ },
134
+ async batch(statements) {
135
+ return await env2.DB.batch(
136
+ statements
137
+ );
138
+ }
139
+ } : null;
140
+ const objectStorage = env2.ASSETS_BUCKET ? {
141
+ kind: "r2",
142
+ async get(key) {
143
+ const object = await env2.ASSETS_BUCKET?.get(key);
144
+ return object ? r2ObjectToStoredObject(object) : null;
145
+ },
146
+ async put(key, value, options2) {
147
+ await env2.ASSETS_BUCKET?.put(key, value, {
148
+ httpMetadata: {
149
+ contentType: options2?.contentType,
150
+ cacheControl: options2?.cacheControl
151
+ },
152
+ customMetadata: options2?.metadata
153
+ });
154
+ },
155
+ async delete(key) {
156
+ await env2.ASSETS_BUCKET?.delete(key);
157
+ },
158
+ async list(options2) {
159
+ const listed = await env2.ASSETS_BUCKET?.list({
160
+ prefix: options2?.prefix,
161
+ limit: options2?.limit
162
+ });
163
+ return listed?.objects.map((object) => ({
164
+ key: object.key,
165
+ size: object.size,
166
+ uploaded: object.uploaded
167
+ })) ?? [];
168
+ }
169
+ } : null;
170
+ const imageTransformer = env2.IMAGES ? {
171
+ kind: "cloudflare-images",
172
+ async transform(body, options2) {
173
+ const result = await env2.IMAGES.input(body).transform(options2.width ? { width: options2.width } : {}).output({
174
+ format: options2.format,
175
+ quality: options2.quality
176
+ });
177
+ return {
178
+ body: result.image(),
179
+ contentType: result.contentType(),
180
+ response: () => result.response()
181
+ };
182
+ }
183
+ } : null;
184
+ const keyValueCache = env2.CONTENT_CACHE ? createCloudflareKeyValueCacheAdapter(env2.CONTENT_CACHE) : null;
185
+ return {
186
+ id: "cloudflare-workers",
187
+ database,
188
+ objectStorage,
189
+ imageTransformer,
190
+ keyValueCache,
191
+ publicCache: options?.publicCache ? createCloudflarePublicCacheAdapter(options.publicCache) : null
192
+ };
193
+ }
194
+
195
+ // src/platform/cloudflare-runtime.ts
196
+ function getDefaultCloudflareCache() {
197
+ const globalWithCaches = globalThis;
198
+ return globalWithCaches.caches?.default ?? null;
199
+ }
200
+ function getRuntimePlatform() {
201
+ return createCloudflareRuntimePlatform(workerEnv, {
202
+ publicCache: getDefaultCloudflareCache()
203
+ });
204
+ }
205
+ function getPublicCache() {
206
+ const cache = getDefaultCloudflareCache();
207
+ if (!cache) {
208
+ throw new Error("Cloudflare cache binding not configured");
209
+ }
210
+ return createCloudflarePublicCacheAdapter(cache);
211
+ }
212
+
213
+ // src/platform/current.ts
214
+ function getRuntimePlatform2() {
215
+ return getRuntimePlatform();
216
+ }
217
+ function getDatabase() {
218
+ const platform = getRuntimePlatform2();
219
+ const database = platform.database;
220
+ if (!database) {
221
+ throw new Error(`SQL database adapter not configured for ${platform.id}`);
222
+ }
223
+ return database;
224
+ }
225
+ function getPublicCache2() {
226
+ return getPublicCache();
227
+ }
228
+
229
+ // src/storage/routes/files.ts
230
+ var filesRoute = {
231
+ /**
232
+ * Next.js handler for `app/api/files/[...key]/route.ts`. Receives the
233
+ * catch-all key from the route params.
234
+ */
235
+ async GET(_request, props) {
236
+ const { key } = await props.params;
237
+ return filesRoute.handle(new Request(buildInternalUrl(_request, key)));
238
+ },
239
+ /**
240
+ * Worker-friendly handler. Extracts the catch-all key from the URL
241
+ * pathname (`/api/files/<key>`).
242
+ */
243
+ async handle(request) {
244
+ const key = readKeyFromUrl(request.url);
245
+ if (!key) {
246
+ return NextResponse.json({ error: "Invalid key" }, { status: 400 });
247
+ }
248
+ if (key.includes("..") || key.startsWith("/")) {
249
+ return NextResponse.json({ error: "Invalid key" }, { status: 400 });
250
+ }
251
+ const storage = getRuntimePlatform2().objectStorage;
252
+ if (!storage) {
253
+ return NextResponse.json(
254
+ { error: "Object storage not configured" },
255
+ { status: 503 }
256
+ );
257
+ }
258
+ const object = await storage.get(key);
259
+ if (!object) {
260
+ return NextResponse.json({ error: "Not found" }, { status: 404 });
261
+ }
262
+ const headers = new Headers();
263
+ if (object.contentType) {
264
+ headers.set("Content-Type", object.contentType);
265
+ }
266
+ headers.set("Cache-Control", "public, max-age=31536000, immutable");
267
+ if (object.etag) headers.set("ETag", object.etag);
268
+ headers.set("Content-Length", String(object.size));
269
+ return new Response(object.body, { headers });
270
+ }
271
+ };
272
+ function buildInternalUrl(request, keyParts) {
273
+ const url = new URL(request.url);
274
+ url.pathname = `/api/files/${keyParts.map(encodeURIComponent).join("/")}`;
275
+ return url.toString();
276
+ }
277
+ function readKeyFromUrl(rawUrl) {
278
+ const url = new URL(rawUrl);
279
+ const prefix = "/api/files/";
280
+ if (!url.pathname.startsWith(prefix)) return null;
281
+ const encoded = url.pathname.slice(prefix.length);
282
+ if (!encoded) return null;
283
+ return decodeURIComponent(encoded);
284
+ }
285
+ var GET = filesRoute.GET;
286
+
287
+ // src/storage/routes/cdn.ts
288
+ import { NextResponse as NextResponse2 } from "next/server";
289
+ var DEFAULT_WIDTH = 1200;
290
+ var MAX_WIDTH = 2400;
291
+ var DEFAULT_QUALITY = 75;
292
+ var MIN_QUALITY = 40;
293
+ var MAX_QUALITY = 85;
294
+ var cdnRoute = {
295
+ async GET(request, props) {
296
+ const { key } = await props.params;
297
+ return cdnRoute.handle(new Request(buildInternalUrl2(request, key)));
298
+ },
299
+ async handle(request) {
300
+ const url = new URL(request.url);
301
+ const key = readKeyFromPathname(url.pathname);
302
+ if (!key) {
303
+ return NextResponse2.json({ error: "Invalid key" }, { status: 400 });
304
+ }
305
+ if (key.includes("..") || key.startsWith("/")) {
306
+ return NextResponse2.json({ error: "Invalid key" }, { status: 400 });
307
+ }
308
+ const platform = getRuntimePlatform2();
309
+ const storage = platform.objectStorage;
310
+ if (!storage) {
311
+ return NextResponse2.json(
312
+ { error: "Object storage not configured" },
313
+ { status: 503 }
314
+ );
315
+ }
316
+ const object = await storage.get(key);
317
+ if (!object) {
318
+ return NextResponse2.json({ error: "Not found" }, { status: 404 });
319
+ }
320
+ const accept = request.headers.get("accept") ?? "";
321
+ const isImage = object.contentType?.startsWith("image/") ?? false;
322
+ if (!isImage) {
323
+ return streamObject(object, {
324
+ "X-Debug-Cdn-Branch": "non-image",
325
+ "X-Debug-Cdn-Key": key
326
+ });
327
+ }
328
+ let outputFormat = null;
329
+ let outputQuality = void 0;
330
+ if (accept.includes("image/avif")) {
331
+ outputFormat = "image/avif";
332
+ outputQuality = 60;
333
+ } else if (accept.includes("image/webp")) {
334
+ outputFormat = "image/webp";
335
+ outputQuality = 75;
336
+ }
337
+ const isSvg = object.contentType === "image/svg+xml";
338
+ if (!outputFormat || isSvg || !platform.imageTransformer) {
339
+ return streamObject(object, {
340
+ "X-Debug-Cdn-Branch": isSvg ? "svg-bypass" : !platform.imageTransformer ? "transformer-bypass" : "format-bypass",
341
+ "X-Debug-Cdn-Accept": accept.includes("image/avif") ? "avif" : accept.includes("image/webp") ? "webp" : "other",
342
+ "X-Debug-Cdn-Key": key
343
+ });
344
+ }
345
+ try {
346
+ const width = clampInt(
347
+ url.searchParams.get("w"),
348
+ 64,
349
+ MAX_WIDTH,
350
+ DEFAULT_WIDTH
351
+ );
352
+ const quality = clampInt(
353
+ url.searchParams.get("q"),
354
+ MIN_QUALITY,
355
+ MAX_QUALITY,
356
+ outputQuality ?? DEFAULT_QUALITY
357
+ );
358
+ const result = await platform.imageTransformer.transform(object.body, {
359
+ width,
360
+ format: outputFormat,
361
+ quality
362
+ });
363
+ return new Response(result.body, {
364
+ headers: {
365
+ "Content-Type": result.contentType,
366
+ "Cache-Control": "public, max-age=31536000, immutable",
367
+ Vary: "Accept",
368
+ "X-Debug-Cdn-Branch": "transformed",
369
+ "X-Debug-Cdn-Key": key,
370
+ "X-Optimized-Width": String(width),
371
+ "X-Optimized-Quality": String(quality),
372
+ "X-Original-Format": object.contentType ?? "unknown",
373
+ "X-Optimized-Format": outputFormat
374
+ }
375
+ });
376
+ } catch (e) {
377
+ return streamObject(object, {
378
+ "X-Debug-Cdn-Branch": "transform-error-fallback",
379
+ "X-Debug-Cdn-Key": key,
380
+ "X-Debug-Cdn-Error": e instanceof Error ? e.name : "unknown"
381
+ });
382
+ }
383
+ }
384
+ };
385
+ function buildInternalUrl2(request, keyParts) {
386
+ const url = new URL(request.url);
387
+ url.pathname = `/api/cdn/${keyParts.map(encodeURIComponent).join("/")}`;
388
+ return url.toString();
389
+ }
390
+ function readKeyFromPathname(pathname) {
391
+ const prefix = "/api/cdn/";
392
+ if (!pathname.startsWith(prefix)) return null;
393
+ const encoded = pathname.slice(prefix.length);
394
+ if (!encoded) return null;
395
+ return decodeURIComponent(encoded);
396
+ }
397
+ function clampInt(value, min, max, fallback) {
398
+ const parsed = Number.parseInt(value ?? "", 10);
399
+ if (!Number.isFinite(parsed)) {
400
+ return fallback;
401
+ }
402
+ return Math.max(min, Math.min(max, parsed));
403
+ }
404
+ function streamObject(object, extraHeaders) {
405
+ const headers = new Headers();
406
+ if (object.contentType) {
407
+ headers.set("Content-Type", object.contentType);
408
+ }
409
+ headers.set("Cache-Control", "public, max-age=31536000, immutable");
410
+ headers.set("Content-Length", String(object.size));
411
+ if (object.etag) headers.set("ETag", object.etag);
412
+ for (const [key, value] of Object.entries(extraHeaders ?? {})) {
413
+ headers.set(key, value);
414
+ }
415
+ return new Response(object.body, { headers });
416
+ }
417
+ var GET2 = cdnRoute.GET;
418
+
419
+ // src/media/routes/notion-media.ts
420
+ import { NextResponse as NextResponse3 } from "next/server";
421
+ import { getRequestExecutionContext } from "vinext/shims/request-context";
422
+
423
+ // src/cache/cache-keys.ts
424
+ var CACHE_ORIGIN = "https://cache.local";
425
+ var CACHE_NAMESPACE = "/__public-cache/v20260609a";
426
+ var NOTION_MEDIA_R2_PREFIX = "notion-media/v1";
427
+ function normalizePath(pathname) {
428
+ if (pathname === "/") return "/";
429
+ return pathname.endsWith("/") ? pathname.slice(0, -1) : pathname;
430
+ }
431
+ function publicMediaVariantForAccept(accept) {
432
+ if (accept.includes("image/avif")) return "avif";
433
+ if (accept.includes("image/webp")) return "webp";
434
+ return "source";
435
+ }
436
+ function publicMediaCacheKeyForUrl(input, variant) {
437
+ const url = new URL(
438
+ `${CACHE_NAMESPACE}${normalizePath(input.pathname)}${input.search}`,
439
+ CACHE_ORIGIN
440
+ );
441
+ url.searchParams.set("__variant", variant);
442
+ url.searchParams.sort();
443
+ return url.toString();
444
+ }
445
+ function keySegment(value) {
446
+ return encodeURIComponent(value || "none");
447
+ }
448
+ function notionMediaR2KeyForUrl(input, variant) {
449
+ if (variant === "source") return null;
450
+ const version = input.searchParams.get("v");
451
+ if (!version) return null;
452
+ const path = normalizePath(input.pathname).split("/").filter(Boolean).map(keySegment).join("/");
453
+ const width = input.searchParams.get("w") ?? "source";
454
+ const quality = input.searchParams.get("q") ?? "source";
455
+ return [
456
+ NOTION_MEDIA_R2_PREFIX,
457
+ variant,
458
+ path,
459
+ `v-${keySegment(version)}`,
460
+ `w-${keySegment(width)}`,
461
+ `q-${keySegment(quality)}.${variant}`
462
+ ].join("/");
463
+ }
464
+
465
+ // src/notion/client.ts
466
+ import { Client } from "@notionhq/client";
467
+ function createNotionClient(config) {
468
+ return new Client({
469
+ auth: config.token,
470
+ baseUrl: config.apiBaseUrl,
471
+ notionVersion: "2026-03-11"
472
+ });
473
+ }
474
+
475
+ // src/notion/config.ts
476
+ function readProcessEnv() {
477
+ const env2 = {
478
+ NOTION_TOKEN: process.env.NOTION_TOKEN,
479
+ NOTION_DATA_SOURCE_ID: process.env.NOTION_DATA_SOURCE_ID,
480
+ NOTION_MOVIES_DATA_SOURCE_ID: process.env.NOTION_MOVIES_DATA_SOURCE_ID,
481
+ NOTION_API_BASE_URL: process.env.NOTION_API_BASE_URL,
482
+ NOTION_EDIT_BASE_URL: process.env.NOTION_EDIT_BASE_URL,
483
+ NOTION_WEBHOOK_VERIFICATION_TOKEN: process.env.NOTION_WEBHOOK_VERIFICATION_TOKEN
484
+ };
485
+ for (const [key, value] of Object.entries(process.env)) {
486
+ if (key.startsWith("NOTION_") && typeof value === "string") {
487
+ env2[key] = value;
488
+ }
489
+ }
490
+ return env2;
491
+ }
492
+ async function readWorkerEnv() {
493
+ try {
494
+ const mod = await import(
495
+ /* webpackIgnore: true */
496
+ "cloudflare:workers"
497
+ );
498
+ const env2 = {};
499
+ for (const [key, value] of Object.entries(mod.env ?? {})) {
500
+ if (key.startsWith("NOTION_") && typeof value === "string") {
501
+ env2[key] = value;
502
+ }
503
+ }
504
+ return env2;
505
+ } catch {
506
+ return {};
507
+ }
508
+ }
509
+ function readString(source, name) {
510
+ const value = String(source[name] ?? "").trim();
511
+ return value || void 0;
512
+ }
513
+ function mergeEnv(...sources) {
514
+ const merged = {};
515
+ for (const source of sources) {
516
+ for (const name of Object.keys(source)) {
517
+ if (!name.startsWith("NOTION_")) continue;
518
+ const value = readString(source, name);
519
+ if (value) merged[name] = value;
520
+ }
521
+ }
522
+ return merged;
523
+ }
524
+ async function readEnv() {
525
+ const processEnv = readProcessEnv();
526
+ return mergeEnv(await readWorkerEnv(), processEnv);
527
+ }
528
+ function readRequired(source, name) {
529
+ const value = readString(source, name);
530
+ if (!value) {
531
+ throw new Error(`Missing required Notion env: ${name}`);
532
+ }
533
+ return value;
534
+ }
535
+ async function getNotionClientConfig() {
536
+ const env2 = await readEnv();
537
+ return {
538
+ token: readRequired(env2, "NOTION_TOKEN"),
539
+ apiBaseUrl: readString(env2, "NOTION_API_BASE_URL")
540
+ };
541
+ }
542
+
543
+ // src/notion/media.ts
544
+ function normalizeNotionFileSource(input) {
545
+ const file = input;
546
+ if (!file || typeof file !== "object") return null;
547
+ if (file.type === "external") {
548
+ const url = String(file.external?.url ?? "").trim();
549
+ return url ? { type: "external", url } : null;
550
+ }
551
+ if (file.type === "file") {
552
+ const url = String(file.file?.url ?? "").trim();
553
+ if (!url) return null;
554
+ return {
555
+ type: "file",
556
+ url,
557
+ expiryTime: String(file.file?.expiry_time ?? "").trim() || null
558
+ };
559
+ }
560
+ return null;
561
+ }
562
+ function pickFirstFilesPropertyValue(property) {
563
+ const value = property;
564
+ if (!value || value.type !== "files" || !Array.isArray(value.files)) {
565
+ return null;
566
+ }
567
+ return value.files[0] ?? null;
568
+ }
569
+ function fileObjectForMediaBlock(block) {
570
+ const typed = block[block.type];
571
+ if (!typed || typeof typed !== "object") return null;
572
+ if (block.type === "image" || block.type === "video" || block.type === "file" || block.type === "pdf" || block.type === "audio") {
573
+ return typed;
574
+ }
575
+ return null;
576
+ }
577
+
578
+ // src/media/routes/notion-media.ts
579
+ var DEFAULT_WIDTH2 = 1200;
580
+ var MAX_WIDTH2 = 2400;
581
+ var DEFAULT_QUALITY2 = 75;
582
+ var MIN_QUALITY2 = 40;
583
+ var MAX_QUALITY2 = 85;
584
+ var CACHEABLE_STATUS = /* @__PURE__ */ new Set([200]);
585
+ var notionMediaRoute = {
586
+ async GET(_request, props) {
587
+ const { ref } = await props.params;
588
+ if (ref.some((part) => part === ".." || part.includes("/"))) {
589
+ return badRequest();
590
+ }
591
+ const url = new URL(_request.url);
592
+ url.pathname = buildNotionMediaPath(ref);
593
+ return notionMediaRoute.handle(new Request(url.toString(), _request));
594
+ },
595
+ async handle(request) {
596
+ const variant = publicMediaVariantForAccept(
597
+ request.headers.get("accept") ?? ""
598
+ );
599
+ return withEdgeMediaCache(request, variant, () => loadMedia(request));
600
+ }
601
+ };
602
+ function buildNotionMediaPath(ref) {
603
+ return `/api/notion/media/${ref.map(encodeURIComponent).join("/")}`;
604
+ }
605
+ function clampInt2(value, min, max, fallback) {
606
+ const parsed = Number.parseInt(value ?? "", 10);
607
+ if (!Number.isFinite(parsed)) return fallback;
608
+ return Math.max(min, Math.min(max, parsed));
609
+ }
610
+ function cacheControl(request) {
611
+ const url = new URL(request.url);
612
+ if (url.searchParams.has("v")) {
613
+ return "public, max-age=31536000, immutable";
614
+ }
615
+ return "public, max-age=3600, s-maxage=3600, stale-while-revalidate=86400";
616
+ }
617
+ function canUseMediaCache(request) {
618
+ if (request.method !== "GET") return false;
619
+ return !request.headers.has("range");
620
+ }
621
+ function mediaCacheHeaders(response, request, state, r2State) {
622
+ const headers = new Headers(response.headers);
623
+ headers.set("Cache-Control", cacheControl(request));
624
+ headers.set("X-Notion-Media-Cache", state);
625
+ if (r2State) headers.set("X-Notion-Media-R2", r2State);
626
+ return headers;
627
+ }
628
+ async function responseFromR2Cache(request, variant) {
629
+ const url = new URL(request.url);
630
+ const r2Key = notionMediaR2KeyForUrl(url, variant);
631
+ const storage = getRuntimePlatform2().objectStorage;
632
+ if (!r2Key || !storage) return null;
633
+ const object = await storage.get(r2Key);
634
+ if (!object?.body) return null;
635
+ const contentType = object.contentType ?? (variant === "avif" ? "image/avif" : "image/webp");
636
+ const headers = new Headers();
637
+ headers.set("Content-Type", contentType);
638
+ headers.set("Cache-Control", cacheControl(request));
639
+ headers.set("Vary", "Accept");
640
+ headers.set("X-Notion-Media-Branch", "r2");
641
+ headers.set("X-Notion-Media-R2", "HIT");
642
+ if (object.etag) headers.set("ETag", object.etag);
643
+ return new Response(object.body, { headers });
644
+ }
645
+ async function withEdgeMediaCache(request, variant, load) {
646
+ if (!canUseMediaCache(request)) {
647
+ const response2 = await load();
648
+ return new Response(response2.body, {
649
+ status: response2.status,
650
+ headers: mediaCacheHeaders(response2, request, "BYPASS")
651
+ });
652
+ }
653
+ const url = new URL(request.url);
654
+ const cache = getPublicCache2();
655
+ const cacheKey = publicMediaCacheKeyForUrl(url, variant);
656
+ const cached = await cache.match(cacheKey);
657
+ if (cached) {
658
+ return new Response(cached.body, {
659
+ status: cached.status,
660
+ headers: mediaCacheHeaders(cached, request, "HIT")
661
+ });
662
+ }
663
+ const r2Response = await responseFromR2Cache(request, variant);
664
+ const response = r2Response ?? await load();
665
+ const headers = mediaCacheHeaders(response, request, "MISS");
666
+ const output = new Response(response.body, {
667
+ status: response.status,
668
+ headers
669
+ });
670
+ if (CACHEABLE_STATUS.has(response.status)) {
671
+ const toCache = output.clone();
672
+ getRequestExecutionContext()?.waitUntil(cache.put(cacheKey, toCache));
673
+ }
674
+ return output;
675
+ }
676
+ function mediaRedirect(url) {
677
+ const response = NextResponse3.redirect(url, 302);
678
+ response.headers.set(
679
+ "Cache-Control",
680
+ "public, max-age=300, s-maxage=300, stale-while-revalidate=300"
681
+ );
682
+ return response;
683
+ }
684
+ function notFound() {
685
+ return NextResponse3.json({ error: "Not found" }, { status: 404 });
686
+ }
687
+ function badRequest() {
688
+ return NextResponse3.json({ error: "Invalid media ref" }, { status: 400 });
689
+ }
690
+ function forbidden() {
691
+ return NextResponse3.json({ error: "Forbidden" }, { status: 403 });
692
+ }
693
+ async function serveFileObject(input, request, options) {
694
+ const source = normalizeNotionFileSource(input);
695
+ if (!source) return notFound();
696
+ if (options?.redirectNotionHosted) return mediaRedirect(source.url);
697
+ return proxyNotionHostedFile(source.url, request);
698
+ }
699
+ async function proxyNotionHostedFile(url, request) {
700
+ const range = request.headers.get("range");
701
+ const ifRange = request.headers.get("if-range");
702
+ const upstreamHeaders = new Headers({
703
+ Accept: request.headers.get("accept") ?? "*/*"
704
+ });
705
+ if (range) upstreamHeaders.set("Range", range);
706
+ if (ifRange) upstreamHeaders.set("If-Range", ifRange);
707
+ const upstream = await fetch(url, {
708
+ headers: upstreamHeaders
709
+ });
710
+ if (!upstream.ok && upstream.status !== 416 || !upstream.body) {
711
+ return NextResponse3.json(
712
+ { error: "Unable to fetch Notion media" },
713
+ { status: upstream.status || 502 }
714
+ );
715
+ }
716
+ const contentType = upstream.headers.get("content-type") ?? "";
717
+ const isImage = contentType.startsWith("image/");
718
+ const accept = request.headers.get("accept") ?? "";
719
+ const variant = publicMediaVariantForAccept(accept);
720
+ const urlObj = new URL(request.url);
721
+ const width = clampInt2(
722
+ urlObj.searchParams.get("w"),
723
+ 64,
724
+ MAX_WIDTH2,
725
+ DEFAULT_WIDTH2
726
+ );
727
+ const quality = clampInt2(
728
+ urlObj.searchParams.get("q"),
729
+ MIN_QUALITY2,
730
+ MAX_QUALITY2,
731
+ DEFAULT_QUALITY2
732
+ );
733
+ let outputFormat = null;
734
+ if (variant === "avif") {
735
+ outputFormat = "image/avif";
736
+ } else if (variant === "webp") {
737
+ outputFormat = "image/webp";
738
+ }
739
+ const platform = getRuntimePlatform2();
740
+ const imageTransformer = platform.imageTransformer;
741
+ if (isImage && !range && outputFormat && imageTransformer) {
742
+ const r2Key = notionMediaR2KeyForUrl(urlObj, variant);
743
+ try {
744
+ const result = await imageTransformer.transform(upstream.body, {
745
+ width,
746
+ format: outputFormat,
747
+ quality
748
+ });
749
+ const transformed = result.response();
750
+ const headers2 = new Headers(transformed.headers);
751
+ headers2.set("Content-Type", result.contentType);
752
+ headers2.set("Cache-Control", cacheControl(request));
753
+ headers2.set("Vary", "Accept");
754
+ headers2.set("X-Notion-Media-Branch", "transformed");
755
+ headers2.set("X-Notion-Media-R2", r2Key ? "MISS" : "BYPASS");
756
+ headers2.set("X-Optimized-Width", String(width));
757
+ headers2.set("X-Optimized-Quality", String(quality));
758
+ if (transformed.body && r2Key && platform.objectStorage) {
759
+ const [clientBody, r2Body] = transformed.body.tee();
760
+ getRequestExecutionContext()?.waitUntil(
761
+ platform.objectStorage.put(r2Key, r2Body, {
762
+ contentType: result.contentType,
763
+ cacheControl: "public, max-age=31536000, immutable",
764
+ metadata: {
765
+ source: "notion",
766
+ cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
767
+ width: String(width),
768
+ quality: String(quality)
769
+ }
770
+ })
771
+ );
772
+ return new Response(clientBody, { headers: headers2 });
773
+ }
774
+ return new Response(transformed.body, { headers: headers2 });
775
+ } catch {
776
+ }
777
+ }
778
+ const headers = new Headers();
779
+ for (const header of [
780
+ "accept-ranges",
781
+ "content-disposition",
782
+ "content-encoding",
783
+ "content-length",
784
+ "content-range",
785
+ "content-type",
786
+ "etag",
787
+ "last-modified"
788
+ ]) {
789
+ const value = upstream.headers.get(header);
790
+ if (value) headers.set(header, value);
791
+ }
792
+ if (contentType && !headers.has("Content-Type")) {
793
+ headers.set("Content-Type", contentType);
794
+ }
795
+ headers.set("Cache-Control", cacheControl(request));
796
+ headers.set("X-Notion-Media-Branch", "proxied");
797
+ return new Response(upstream.body, { status: upstream.status, headers });
798
+ }
799
+ async function loadMedia(request) {
800
+ const url = new URL(request.url);
801
+ const ref = readRefFromPathname(url.pathname);
802
+ if (!ref) return badRequest();
803
+ const client = createNotionClient(await getNotionClientConfig());
804
+ if (ref[0] === "page" && ref[1] && ref[2] === "cover") {
805
+ const page = await client.pages.retrieve({
806
+ page_id: ref[1]
807
+ });
808
+ return serveFileObject(page.cover, request);
809
+ }
810
+ if (ref[0] === "page" && ref[1] && ref[2] === "property" && ref[3]) {
811
+ const page = await client.pages.retrieve({
812
+ page_id: ref[1]
813
+ });
814
+ const propertyName = decodeURIComponent(ref.slice(3).join("/"));
815
+ return serveFileObject(
816
+ pickFirstFilesPropertyValue(page.properties?.[propertyName]),
817
+ request
818
+ );
819
+ }
820
+ if (ref[0] === "block" && ref[1]) {
821
+ const block = await client.blocks.retrieve({
822
+ block_id: ref[1]
823
+ });
824
+ if (block.type === "video") {
825
+ return forbidden();
826
+ }
827
+ return serveFileObject(fileObjectForMediaBlock(block), request, {
828
+ redirectNotionHosted: block.type === "audio" || block.type === "pdf" || block.type === "file"
829
+ });
830
+ }
831
+ return badRequest();
832
+ }
833
+ function readRefFromPathname(pathname) {
834
+ const prefix = "/api/notion/media/";
835
+ if (!pathname.startsWith(prefix)) return null;
836
+ const encoded = pathname.slice(prefix.length);
837
+ if (!encoded) return null;
838
+ return encoded.split("/").map((part) => decodeURIComponent(part));
839
+ }
840
+ var GET3 = notionMediaRoute.GET;
841
+
842
+ // src/worker/routes/health.ts
843
+ import { NextResponse as NextResponse4 } from "next/server";
844
+
845
+ // src/internal/admin/schema-guard.ts
846
+ var REQUIRED_SCHEMA_CHECKS = [
847
+ {
848
+ key: "app_settings.turnstile_enabled",
849
+ sql: "SELECT turnstile_enabled FROM app_settings LIMIT 1"
850
+ },
851
+ {
852
+ key: "users.session_rev",
853
+ sql: "SELECT session_rev FROM users LIMIT 1"
854
+ },
855
+ {
856
+ key: "auth_rate_limits",
857
+ sql: "SELECT 1 FROM auth_rate_limits LIMIT 1"
858
+ }
859
+ ];
860
+ function isSchemaDriftError(error) {
861
+ const message = error instanceof Error ? error.message : String(error ?? "");
862
+ return message.includes("no such column") || message.includes("no such table");
863
+ }
864
+ async function runSchemaHealthChecks(db) {
865
+ const missing = [];
866
+ const errors = [];
867
+ for (const check of REQUIRED_SCHEMA_CHECKS) {
868
+ try {
869
+ await db.prepare(check.sql).first();
870
+ } catch (error) {
871
+ if (isSchemaDriftError(error)) {
872
+ missing.push(check.key);
873
+ } else {
874
+ const message = error instanceof Error ? error.message : String(error);
875
+ errors.push(`${check.key}: ${message}`);
876
+ }
877
+ }
878
+ }
879
+ return {
880
+ ok: missing.length === 0 && errors.length === 0,
881
+ missing,
882
+ errors
883
+ };
884
+ }
885
+
886
+ // src/worker/routes/health.ts
887
+ async function probeDatabase() {
888
+ const database = getDatabase();
889
+ try {
890
+ const result = await database.prepare(
891
+ "SELECT name FROM sqlite_master WHERE type='table' AND name='posts' LIMIT 1"
892
+ ).first();
893
+ return {
894
+ ok: true,
895
+ error: null,
896
+ postsTableExists: Boolean(result?.name)
897
+ };
898
+ } catch (e) {
899
+ return {
900
+ ok: false,
901
+ error: e instanceof Error ? e.message : String(e),
902
+ postsTableExists: false
903
+ };
904
+ }
905
+ }
906
+ var healthRoute = {
907
+ async GET() {
908
+ return healthRoute.handle(new Request("https://health.local/api/health"));
909
+ },
910
+ async handle(_request) {
911
+ const start = Date.now();
912
+ const probe = await probeDatabase();
913
+ const d1Ok = probe.ok;
914
+ const d1Error = probe.error;
915
+ let schemaOk = false;
916
+ let schemaError = null;
917
+ let schemaMissing = [];
918
+ try {
919
+ const schema = await runSchemaHealthChecks(getDatabase());
920
+ schemaOk = schema.ok;
921
+ schemaMissing = schema.missing;
922
+ if (schema.errors.length > 0) {
923
+ schemaError = schema.errors.join("; ");
924
+ } else if (schema.missing.length > 0) {
925
+ schemaError = `missing required schema: ${schema.missing.join(", ")}`;
926
+ }
927
+ } catch (e) {
928
+ schemaError = e instanceof Error ? e.message : String(e);
929
+ }
930
+ const allHealthy = d1Ok && schemaOk;
931
+ return NextResponse4.json(
932
+ {
933
+ status: allHealthy ? "ok" : "degraded",
934
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
935
+ uptime_ms: Date.now() - start,
936
+ checks: {
937
+ d1: d1Ok ? "ok" : "error",
938
+ d1_error: d1Error,
939
+ schema: schemaOk ? "ok" : "error",
940
+ schema_error: schemaError,
941
+ schema_missing: schemaMissing
942
+ },
943
+ version: "1.0.0"
944
+ },
945
+ {
946
+ status: allHealthy ? 200 : 503,
947
+ headers: {
948
+ "Cache-Control": "no-store",
949
+ "Access-Control-Allow-Origin": "*"
950
+ }
951
+ }
952
+ );
953
+ }
954
+ };
955
+ var GET4 = healthRoute.GET;
956
+ async function healthRouteHandle(request) {
957
+ return healthRoute.handle(request);
958
+ }
959
+
960
+ // src/worker/bootstrap.ts
961
+ function pathMatches(pathname, match) {
962
+ if (match.endsWith("/")) return pathname.startsWith(match);
963
+ return pathname === match || pathname.startsWith(`${match}/`);
964
+ }
965
+ function buildStaticRoutes() {
966
+ return [
967
+ {
968
+ match: (req) => new URL(req.url).pathname === "/api/health",
969
+ handle: healthRouteHandle
970
+ },
971
+ {
972
+ match: (req) => pathMatches(new URL(req.url).pathname, "/api/notion/media/"),
973
+ handle: notionMediaRoute.handle
974
+ },
975
+ {
976
+ match: (req) => pathMatches(new URL(req.url).pathname, "/api/files/"),
977
+ handle: filesRoute.handle
978
+ },
979
+ {
980
+ match: (req) => pathMatches(new URL(req.url).pathname, "/api/cdn/"),
981
+ handle: cdnRoute.handle
982
+ }
983
+ ];
984
+ }
985
+ function createNextionWorker(options) {
986
+ const sources = options.sources;
987
+ const auth = { databaseBinding: options.authConfig.databaseBinding };
988
+ const routes = buildStaticRoutes();
989
+ if (options.extraRoutes) {
990
+ for (const [path, load] of Object.entries(options.extraRoutes)) {
991
+ const modPromise = load();
992
+ routes.push({
993
+ match: (req) => new URL(req.url).pathname === path,
994
+ handle: async (req) => {
995
+ const mod = await modPromise;
996
+ return mod.default(req, options, sources, auth);
997
+ }
998
+ });
999
+ }
1000
+ }
1001
+ const middlewareOptions = {
1002
+ authConfig: options.authConfig,
1003
+ sessionLookup: options.sessionLookup
1004
+ };
1005
+ return {
1006
+ async fetch(request, env2, ctx) {
1007
+ void ctx;
1008
+ const gateResponse = await nextionMiddleware(
1009
+ request,
1010
+ env2,
1011
+ middlewareOptions
1012
+ );
1013
+ if (gateResponse) return gateResponse;
1014
+ for (const route of routes) {
1015
+ if (route.match(request)) return route.handle(request);
1016
+ }
1017
+ return null;
1018
+ }
1019
+ };
1020
+ }
1021
+ export {
1022
+ createNextionWorker,
1023
+ healthRoute,
1024
+ healthRouteHandle
1025
+ };
1026
+ //# sourceMappingURL=index.js.map