@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,160 @@
1
+ // src/platform/runtime.ts
2
+ function cacheRequestForKey(key) {
3
+ return new Request(key, { method: "GET" });
4
+ }
5
+ function createCloudflarePublicCacheAdapter(cache) {
6
+ return {
7
+ kind: "cloudflare-cache",
8
+ async match(key) {
9
+ return await cache.match(cacheRequestForKey(key)) ?? null;
10
+ },
11
+ put(key, response) {
12
+ return cache.put(cacheRequestForKey(key), response);
13
+ },
14
+ delete(key) {
15
+ return cache.delete(cacheRequestForKey(key));
16
+ }
17
+ };
18
+ }
19
+ function createNoopPublicCacheAdapter(kind = "noop") {
20
+ return {
21
+ kind,
22
+ async match() {
23
+ return null;
24
+ },
25
+ async put() {
26
+ },
27
+ async delete() {
28
+ return false;
29
+ }
30
+ };
31
+ }
32
+ function createCloudflareKeyValueCacheAdapter(namespace) {
33
+ return {
34
+ kind: "workers-kv",
35
+ async get(key, options) {
36
+ return await namespace.get(key, {
37
+ type: "json",
38
+ cacheTtl: options?.cacheTtl
39
+ });
40
+ },
41
+ async put(key, value, options) {
42
+ await namespace.put(key, JSON.stringify(value), {
43
+ expirationTtl: options?.expirationTtl,
44
+ metadata: options?.metadata
45
+ });
46
+ },
47
+ delete(key) {
48
+ return namespace.delete(key);
49
+ },
50
+ async list(options) {
51
+ const result = await namespace.list({
52
+ prefix: options?.prefix,
53
+ limit: options?.limit,
54
+ cursor: options?.cursor
55
+ });
56
+ return {
57
+ keys: result.keys.map((key) => ({ name: key.name })),
58
+ cursor: result.list_complete ? void 0 : result.cursor,
59
+ listComplete: result.list_complete
60
+ };
61
+ }
62
+ };
63
+ }
64
+ function createNoopKeyValueCacheAdapter(kind = "noop") {
65
+ return {
66
+ kind,
67
+ async get() {
68
+ return null;
69
+ },
70
+ async put() {
71
+ },
72
+ async delete() {
73
+ },
74
+ async list() {
75
+ return { keys: [], listComplete: true };
76
+ }
77
+ };
78
+ }
79
+ function r2ObjectToStoredObject(object) {
80
+ return {
81
+ body: object.body,
82
+ size: object.size,
83
+ etag: object.etag,
84
+ contentType: object.httpMetadata?.contentType
85
+ };
86
+ }
87
+ function createCloudflareRuntimePlatform(env, options) {
88
+ const database = env.DB ? {
89
+ kind: "d1",
90
+ prepare(query) {
91
+ return env.DB.prepare(query);
92
+ },
93
+ async batch(statements) {
94
+ return await env.DB.batch(
95
+ statements
96
+ );
97
+ }
98
+ } : null;
99
+ const objectStorage = env.ASSETS_BUCKET ? {
100
+ kind: "r2",
101
+ async get(key) {
102
+ const object = await env.ASSETS_BUCKET?.get(key);
103
+ return object ? r2ObjectToStoredObject(object) : null;
104
+ },
105
+ async put(key, value, options2) {
106
+ await env.ASSETS_BUCKET?.put(key, value, {
107
+ httpMetadata: {
108
+ contentType: options2?.contentType,
109
+ cacheControl: options2?.cacheControl
110
+ },
111
+ customMetadata: options2?.metadata
112
+ });
113
+ },
114
+ async delete(key) {
115
+ await env.ASSETS_BUCKET?.delete(key);
116
+ },
117
+ async list(options2) {
118
+ const listed = await env.ASSETS_BUCKET?.list({
119
+ prefix: options2?.prefix,
120
+ limit: options2?.limit
121
+ });
122
+ return listed?.objects.map((object) => ({
123
+ key: object.key,
124
+ size: object.size,
125
+ uploaded: object.uploaded
126
+ })) ?? [];
127
+ }
128
+ } : null;
129
+ const imageTransformer = env.IMAGES ? {
130
+ kind: "cloudflare-images",
131
+ async transform(body, options2) {
132
+ const result = await env.IMAGES.input(body).transform(options2.width ? { width: options2.width } : {}).output({
133
+ format: options2.format,
134
+ quality: options2.quality
135
+ });
136
+ return {
137
+ body: result.image(),
138
+ contentType: result.contentType(),
139
+ response: () => result.response()
140
+ };
141
+ }
142
+ } : null;
143
+ const keyValueCache = env.CONTENT_CACHE ? createCloudflareKeyValueCacheAdapter(env.CONTENT_CACHE) : null;
144
+ return {
145
+ id: "cloudflare-workers",
146
+ database,
147
+ objectStorage,
148
+ imageTransformer,
149
+ keyValueCache,
150
+ publicCache: options?.publicCache ? createCloudflarePublicCacheAdapter(options.publicCache) : null
151
+ };
152
+ }
153
+ export {
154
+ createCloudflareKeyValueCacheAdapter,
155
+ createCloudflarePublicCacheAdapter,
156
+ createCloudflareRuntimePlatform,
157
+ createNoopKeyValueCacheAdapter,
158
+ createNoopPublicCacheAdapter
159
+ };
160
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/platform/runtime.ts"],"sourcesContent":["import type { AppEnv } from \"../util/env\";\n\nexport type PlatformBindingEnv = Pick<\n AppEnv,\n \"ASSETS_BUCKET\" | \"CONTENT_CACHE\" | \"DB\" | \"IMAGES\"\n>;\n\nexport type StoredObject = {\n body: ReadableStream;\n size: number;\n etag?: string;\n contentType?: string;\n};\n\nexport type ObjectStoragePutOptions = {\n contentType?: string;\n cacheControl?: string;\n metadata?: Record<string, string>;\n};\n\nexport type ObjectStorageListItem = {\n key: string;\n size: number;\n uploaded: Date;\n};\n\nexport type ObjectStorageAdapter = {\n kind: \"r2\";\n get(key: string): Promise<StoredObject | null>;\n put(\n key: string,\n value: ReadableStream | ArrayBuffer | ArrayBufferView | string | Blob,\n options?: ObjectStoragePutOptions\n ): Promise<void>;\n delete(key: string): Promise<void>;\n list(\n options?: { prefix?: string; limit?: number }\n ): Promise<ObjectStorageListItem[]>;\n};\n\nexport type ImageTransformOptions = {\n width?: number;\n format: \"image/avif\" | \"image/webp\";\n quality: number;\n};\n\nexport type ImageTransformResult = {\n body: ReadableStream;\n contentType: string;\n response(): Response;\n};\n\nexport type ImageTransformerAdapter = {\n kind: \"cloudflare-images\" | \"external\";\n transform(\n body: ReadableStream,\n options: ImageTransformOptions\n ): Promise<ImageTransformResult>;\n};\n\nexport type PublicCacheAdapter = {\n kind: \"cloudflare-cache\" | \"noop\" | \"external\";\n match(key: string): Promise<Response | null>;\n put(key: string, response: Response): Promise<void>;\n delete(key: string): Promise<boolean>;\n};\n\nexport type KeyValueCacheGetOptions = {\n cacheTtl?: number;\n};\n\nexport type KeyValueCachePutOptions = {\n expirationTtl?: number;\n metadata?: Record<string, string | number | boolean | null>;\n};\n\nexport type KeyValueCacheListOptions = {\n prefix?: string;\n limit?: number;\n cursor?: string;\n};\n\nexport type KeyValueCacheListResult = {\n keys: Array<{ name: string }>;\n cursor?: string;\n listComplete: boolean;\n};\n\nexport type KeyValueCacheAdapter = {\n kind: \"workers-kv\" | \"noop\" | \"external\";\n get<T = unknown>(\n key: string,\n options?: KeyValueCacheGetOptions\n ): Promise<T | null>;\n put<T = unknown>(\n key: string,\n value: T,\n options?: KeyValueCachePutOptions\n ): Promise<void>;\n delete(key: string): Promise<void>;\n list(options?: KeyValueCacheListOptions): Promise<KeyValueCacheListResult>;\n};\n\nexport type SqlValue = string | number | boolean | null;\n\nexport type SqlResult<T = Record<string, unknown>> = {\n results?: T[];\n success?: boolean;\n meta?: {\n changes?: number;\n duration?: number;\n last_row_id?: number;\n rows_read?: number;\n rows_written?: number;\n [key: string]: unknown;\n };\n};\n\nexport type SqlPreparedStatement = {\n bind(...values: SqlValue[]): SqlPreparedStatement;\n all<T = Record<string, unknown>>(): Promise<SqlResult<T>>;\n first<T = Record<string, unknown>>(columnName?: string): Promise<T | null>;\n run<T = Record<string, unknown>>(): Promise<SqlResult<T>>;\n};\n\nexport type SqlDatabaseAdapter = {\n kind: \"d1\";\n prepare(query: string): SqlPreparedStatement;\n batch<T = Record<string, unknown>>(\n statements: SqlPreparedStatement[]\n ): Promise<SqlResult<T>[]>;\n};\n\nexport type RuntimePlatform = {\n id: \"cloudflare-workers\";\n database: SqlDatabaseAdapter | null;\n objectStorage: ObjectStorageAdapter | null;\n imageTransformer: ImageTransformerAdapter | null;\n publicCache: PublicCacheAdapter | null;\n keyValueCache: KeyValueCacheAdapter | null;\n};\n\ntype CloudflareCacheLike = Pick<Cache, \"match\" | \"put\" | \"delete\">;\ntype CloudflareKvLike = Pick<KVNamespace, \"get\" | \"put\" | \"delete\" | \"list\">;\n\nfunction cacheRequestForKey(key: string) {\n return new Request(key, { method: \"GET\" });\n}\n\nexport function createCloudflarePublicCacheAdapter(\n cache: CloudflareCacheLike\n): PublicCacheAdapter {\n return {\n kind: \"cloudflare-cache\",\n async match(key) {\n return (await cache.match(cacheRequestForKey(key))) ?? null;\n },\n put(key, response) {\n return cache.put(cacheRequestForKey(key), response);\n },\n delete(key) {\n return cache.delete(cacheRequestForKey(key));\n },\n };\n}\n\nexport function createNoopPublicCacheAdapter(kind: \"noop\" = \"noop\"): PublicCacheAdapter {\n return {\n kind,\n async match() {\n return null;\n },\n async put() {},\n async delete() {\n return false;\n },\n };\n}\n\nexport function createCloudflareKeyValueCacheAdapter(\n namespace: CloudflareKvLike\n): KeyValueCacheAdapter {\n return {\n kind: \"workers-kv\",\n async get<T = unknown>(\n key: string,\n options?: KeyValueCacheGetOptions\n ): Promise<T | null> {\n return (await namespace.get(key, {\n type: \"json\",\n cacheTtl: options?.cacheTtl,\n })) as T | null;\n },\n async put(key, value, options) {\n await namespace.put(key, JSON.stringify(value), {\n expirationTtl: options?.expirationTtl,\n metadata: options?.metadata,\n });\n },\n delete(key) {\n return namespace.delete(key);\n },\n async list(options) {\n const result = await namespace.list({\n prefix: options?.prefix,\n limit: options?.limit,\n cursor: options?.cursor,\n });\n return {\n keys: result.keys.map((key) => ({ name: key.name })),\n cursor: result.list_complete ? undefined : result.cursor,\n listComplete: result.list_complete,\n };\n },\n };\n}\n\nexport function createNoopKeyValueCacheAdapter(\n kind: \"noop\" = \"noop\"\n): KeyValueCacheAdapter {\n return {\n kind,\n async get() {\n return null;\n },\n async put() {},\n async delete() {},\n async list() {\n return { keys: [], listComplete: true };\n },\n };\n}\n\nfunction r2ObjectToStoredObject(object: R2ObjectBody): StoredObject {\n return {\n body: object.body,\n size: object.size,\n etag: object.etag,\n contentType: object.httpMetadata?.contentType,\n };\n}\n\nexport function createCloudflareRuntimePlatform(\n env: PlatformBindingEnv,\n options?: { publicCache?: CloudflareCacheLike | null }\n): RuntimePlatform {\n const database: SqlDatabaseAdapter | null = env.DB\n ? ({\n kind: \"d1\",\n prepare(query: string) {\n return env.DB.prepare(query) as unknown as SqlPreparedStatement;\n },\n async batch(statements: SqlPreparedStatement[]) {\n return (await env.DB.batch(\n statements as unknown as D1PreparedStatement[]\n )) as unknown as SqlResult<Record<string, unknown>>[];\n },\n } as unknown as SqlDatabaseAdapter)\n : null;\n\n const objectStorage: ObjectStorageAdapter | null = env.ASSETS_BUCKET\n ? {\n kind: \"r2\",\n async get(key) {\n const object = await env.ASSETS_BUCKET?.get(key);\n return object ? r2ObjectToStoredObject(object) : null;\n },\n async put(key, value, options) {\n await env.ASSETS_BUCKET?.put(key, value, {\n httpMetadata: {\n contentType: options?.contentType,\n cacheControl: options?.cacheControl,\n },\n customMetadata: options?.metadata,\n });\n },\n async delete(key) {\n await env.ASSETS_BUCKET?.delete(key);\n },\n async list(options) {\n const listed = await env.ASSETS_BUCKET?.list({\n prefix: options?.prefix,\n limit: options?.limit,\n });\n return (\n listed?.objects.map((object) => ({\n key: object.key,\n size: object.size,\n uploaded: object.uploaded,\n })) ?? []\n );\n },\n }\n : null;\n\n const imageTransformer: ImageTransformerAdapter | null = env.IMAGES\n ? {\n kind: \"cloudflare-images\",\n async transform(body, options) {\n const result = await env.IMAGES.input(body)\n .transform(options.width ? { width: options.width } : {})\n .output({\n format: options.format,\n quality: options.quality,\n });\n return {\n body: result.image(),\n contentType: result.contentType(),\n response: () => result.response(),\n };\n },\n }\n : null;\n\n const keyValueCache: KeyValueCacheAdapter | null = env.CONTENT_CACHE\n ? createCloudflareKeyValueCacheAdapter(env.CONTENT_CACHE)\n : null;\n\n return {\n id: \"cloudflare-workers\",\n database,\n objectStorage,\n imageTransformer,\n keyValueCache,\n publicCache: options?.publicCache\n ? createCloudflarePublicCacheAdapter(options.publicCache)\n : null,\n };\n}\n"],"mappings":"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","names":["options"]}
@@ -0,0 +1,10 @@
1
+ type RuntimeId = "cloudflare-workers";
2
+ type RuntimeKind = "cloudflare";
3
+ interface RuntimeSelection {
4
+ kind: RuntimeKind;
5
+ runtimeId: RuntimeId;
6
+ }
7
+ declare function selectRuntime(env: unknown): RuntimeSelection;
8
+ declare function currentRuntimeId(): RuntimeId;
9
+
10
+ export { type RuntimeId, type RuntimeKind, type RuntimeSelection, currentRuntimeId, selectRuntime };
@@ -0,0 +1,22 @@
1
+ // src/platform/selection.ts
2
+ function hasCloudflareBindings(env) {
3
+ if (!env || typeof env !== "object") return false;
4
+ const record = env;
5
+ return "DB" in record || "ASSETS_BUCKET" in record || "R2" in record || "IMAGES" in record || "CONTENT_CACHE" in record;
6
+ }
7
+ function selectRuntime(env) {
8
+ if (hasCloudflareBindings(env)) {
9
+ return { kind: "cloudflare", runtimeId: "cloudflare-workers" };
10
+ }
11
+ throw new Error(
12
+ "No supported runtime detected. Expected Cloudflare Workers bindings (DB, ASSETS_BUCKET, R2, IMAGES, or CONTENT_CACHE)."
13
+ );
14
+ }
15
+ function currentRuntimeId() {
16
+ return "cloudflare-workers";
17
+ }
18
+ export {
19
+ currentRuntimeId,
20
+ selectRuntime
21
+ };
22
+ //# sourceMappingURL=selection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/platform/selection.ts"],"sourcesContent":["export type RuntimeId = \"cloudflare-workers\";\n\nexport type RuntimeKind = \"cloudflare\";\n\nexport interface RuntimeSelection {\n kind: RuntimeKind;\n runtimeId: RuntimeId;\n}\n\nfunction hasCloudflareBindings(env: unknown): boolean {\n if (!env || typeof env !== \"object\") return false;\n const record = env as Record<string, unknown>;\n return (\n \"DB\" in record ||\n \"ASSETS_BUCKET\" in record ||\n \"R2\" in record ||\n \"IMAGES\" in record ||\n \"CONTENT_CACHE\" in record\n );\n}\n\nexport function selectRuntime(env: unknown): RuntimeSelection {\n if (hasCloudflareBindings(env)) {\n return { kind: \"cloudflare\", runtimeId: \"cloudflare-workers\" };\n }\n throw new Error(\n \"No supported runtime detected. Expected Cloudflare Workers bindings \" +\n \"(DB, ASSETS_BUCKET, R2, IMAGES, or CONTENT_CACHE).\",\n );\n}\n\nexport function currentRuntimeId(): RuntimeId {\n return \"cloudflare-workers\";\n}\n"],"mappings":";AASA,SAAS,sBAAsB,KAAuB;AACpD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,SAAS;AACf,SACE,QAAQ,UACR,mBAAmB,UACnB,QAAQ,UACR,YAAY,UACZ,mBAAmB;AAEvB;AAEO,SAAS,cAAc,KAAgC;AAC5D,MAAI,sBAAsB,GAAG,GAAG;AAC9B,WAAO,EAAE,MAAM,cAAc,WAAW,qBAAqB;AAAA,EAC/D;AACA,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAEO,SAAS,mBAA8B;AAC5C,SAAO;AACT;","names":[]}
@@ -0,0 +1,17 @@
1
+ type UploadResult = {
2
+ key: string;
3
+ url: string;
4
+ size: number;
5
+ contentType: string;
6
+ };
7
+ declare function buildAssetUrl(kind: "cdn" | "files", key: string): string;
8
+ declare function uploadFile(file: File, prefix?: string): Promise<UploadResult>;
9
+ declare function deleteFile(key: string): Promise<void>;
10
+ declare function listFiles(prefix?: string, limit?: number): Promise<{
11
+ key: string;
12
+ size: number;
13
+ uploaded: string;
14
+ url: string;
15
+ }[]>;
16
+
17
+ export { type UploadResult, buildAssetUrl, deleteFile, listFiles, uploadFile };
@@ -0,0 +1,218 @@
1
+ // src/util/env.ts
2
+ import { env } from "cloudflare:workers";
3
+ var workerEnv = env;
4
+
5
+ // src/platform/runtime.ts
6
+ function cacheRequestForKey(key) {
7
+ return new Request(key, { method: "GET" });
8
+ }
9
+ function createCloudflarePublicCacheAdapter(cache) {
10
+ return {
11
+ kind: "cloudflare-cache",
12
+ async match(key) {
13
+ return await cache.match(cacheRequestForKey(key)) ?? null;
14
+ },
15
+ put(key, response) {
16
+ return cache.put(cacheRequestForKey(key), response);
17
+ },
18
+ delete(key) {
19
+ return cache.delete(cacheRequestForKey(key));
20
+ }
21
+ };
22
+ }
23
+ function createCloudflareKeyValueCacheAdapter(namespace) {
24
+ return {
25
+ kind: "workers-kv",
26
+ async get(key, options) {
27
+ return await namespace.get(key, {
28
+ type: "json",
29
+ cacheTtl: options?.cacheTtl
30
+ });
31
+ },
32
+ async put(key, value, options) {
33
+ await namespace.put(key, JSON.stringify(value), {
34
+ expirationTtl: options?.expirationTtl,
35
+ metadata: options?.metadata
36
+ });
37
+ },
38
+ delete(key) {
39
+ return namespace.delete(key);
40
+ },
41
+ async list(options) {
42
+ const result = await namespace.list({
43
+ prefix: options?.prefix,
44
+ limit: options?.limit,
45
+ cursor: options?.cursor
46
+ });
47
+ return {
48
+ keys: result.keys.map((key) => ({ name: key.name })),
49
+ cursor: result.list_complete ? void 0 : result.cursor,
50
+ listComplete: result.list_complete
51
+ };
52
+ }
53
+ };
54
+ }
55
+ function r2ObjectToStoredObject(object) {
56
+ return {
57
+ body: object.body,
58
+ size: object.size,
59
+ etag: object.etag,
60
+ contentType: object.httpMetadata?.contentType
61
+ };
62
+ }
63
+ function createCloudflareRuntimePlatform(env2, options) {
64
+ const database = env2.DB ? {
65
+ kind: "d1",
66
+ prepare(query) {
67
+ return env2.DB.prepare(query);
68
+ },
69
+ async batch(statements) {
70
+ return await env2.DB.batch(
71
+ statements
72
+ );
73
+ }
74
+ } : null;
75
+ const objectStorage = env2.ASSETS_BUCKET ? {
76
+ kind: "r2",
77
+ async get(key) {
78
+ const object = await env2.ASSETS_BUCKET?.get(key);
79
+ return object ? r2ObjectToStoredObject(object) : null;
80
+ },
81
+ async put(key, value, options2) {
82
+ await env2.ASSETS_BUCKET?.put(key, value, {
83
+ httpMetadata: {
84
+ contentType: options2?.contentType,
85
+ cacheControl: options2?.cacheControl
86
+ },
87
+ customMetadata: options2?.metadata
88
+ });
89
+ },
90
+ async delete(key) {
91
+ await env2.ASSETS_BUCKET?.delete(key);
92
+ },
93
+ async list(options2) {
94
+ const listed = await env2.ASSETS_BUCKET?.list({
95
+ prefix: options2?.prefix,
96
+ limit: options2?.limit
97
+ });
98
+ return listed?.objects.map((object) => ({
99
+ key: object.key,
100
+ size: object.size,
101
+ uploaded: object.uploaded
102
+ })) ?? [];
103
+ }
104
+ } : null;
105
+ const imageTransformer = env2.IMAGES ? {
106
+ kind: "cloudflare-images",
107
+ async transform(body, options2) {
108
+ const result = await env2.IMAGES.input(body).transform(options2.width ? { width: options2.width } : {}).output({
109
+ format: options2.format,
110
+ quality: options2.quality
111
+ });
112
+ return {
113
+ body: result.image(),
114
+ contentType: result.contentType(),
115
+ response: () => result.response()
116
+ };
117
+ }
118
+ } : null;
119
+ const keyValueCache = env2.CONTENT_CACHE ? createCloudflareKeyValueCacheAdapter(env2.CONTENT_CACHE) : null;
120
+ return {
121
+ id: "cloudflare-workers",
122
+ database,
123
+ objectStorage,
124
+ imageTransformer,
125
+ keyValueCache,
126
+ publicCache: options?.publicCache ? createCloudflarePublicCacheAdapter(options.publicCache) : null
127
+ };
128
+ }
129
+
130
+ // src/platform/cloudflare-runtime.ts
131
+ function getDefaultCloudflareCache() {
132
+ const globalWithCaches = globalThis;
133
+ return globalWithCaches.caches?.default ?? null;
134
+ }
135
+ function getRuntimePlatform() {
136
+ return createCloudflareRuntimePlatform(workerEnv, {
137
+ publicCache: getDefaultCloudflareCache()
138
+ });
139
+ }
140
+
141
+ // src/platform/current.ts
142
+ function getRuntimePlatform2() {
143
+ return getRuntimePlatform();
144
+ }
145
+
146
+ // src/storage/r2.ts
147
+ function buildAssetUrl(kind, key) {
148
+ const safeKey = key.split("/").filter(Boolean).map((segment) => encodeURIComponent(segment)).join("/");
149
+ return `/api/${kind}/${safeKey}`;
150
+ }
151
+ var ALLOWED = /* @__PURE__ */ new Set([
152
+ "image/jpeg",
153
+ "image/jpg",
154
+ "image/png",
155
+ "image/gif",
156
+ "image/webp",
157
+ "image/svg+xml",
158
+ "image/avif",
159
+ "application/pdf",
160
+ "text/plain"
161
+ ]);
162
+ var ALLOWED_IMAGE_EXT = /\.(jpe?g|png|gif|webp|avif|svg)$/i;
163
+ var MAX_SIZE = 100 * 1024 * 1024;
164
+ async function uploadFile(file, prefix = "uploads") {
165
+ const storage = getRuntimePlatform2().objectStorage;
166
+ if (!storage) {
167
+ throw new Error("Object storage binding not configured");
168
+ }
169
+ if (file.size > MAX_SIZE) {
170
+ throw new Error(`File too large: ${file.size} bytes (max ${MAX_SIZE})`);
171
+ }
172
+ if (!ALLOWED.has(file.type) && !ALLOWED_IMAGE_EXT.test(file.name)) {
173
+ throw new Error(`Unsupported file type: ${file.type || "(empty)"}`);
174
+ }
175
+ const ext = file.name.split(".").pop() || "bin";
176
+ const rand = crypto.randomUUID().replace(/-/g, "").slice(0, 16);
177
+ const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
178
+ const key = `${prefix}/${date}/${rand}.${ext}`;
179
+ await storage.put(key, file, {
180
+ contentType: file.type,
181
+ cacheControl: "public, max-age=31536000, immutable",
182
+ metadata: {
183
+ originalName: file.name.slice(0, 100),
184
+ uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
185
+ }
186
+ });
187
+ return {
188
+ key,
189
+ // Images go through the CDN (auto WebP/AVIF optimization); other
190
+ // files go through the raw /api/files proxy.
191
+ url: file.type.startsWith("image/") ? buildAssetUrl("cdn", key) : buildAssetUrl("files", key),
192
+ size: file.size,
193
+ contentType: file.type
194
+ };
195
+ }
196
+ async function deleteFile(key) {
197
+ const storage = getRuntimePlatform2().objectStorage;
198
+ if (!storage) return;
199
+ await storage.delete(key);
200
+ }
201
+ async function listFiles(prefix = "uploads", limit = 50) {
202
+ const storage = getRuntimePlatform2().objectStorage;
203
+ if (!storage) return [];
204
+ const listed = await storage.list({ prefix, limit });
205
+ return listed.map((object) => ({
206
+ key: object.key,
207
+ size: object.size,
208
+ uploaded: object.uploaded.toISOString(),
209
+ url: buildAssetUrl("files", object.key)
210
+ }));
211
+ }
212
+ export {
213
+ buildAssetUrl,
214
+ deleteFile,
215
+ listFiles,
216
+ uploadFile
217
+ };
218
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/env.ts","../../src/platform/runtime.ts","../../src/platform/cloudflare-runtime.ts","../../src/platform/current.ts","../../src/storage/r2.ts"],"sourcesContent":["// lib/env.ts - 集中获取 Cloudflare bindings\n// 用 cloudflare:workers 模块(workerd 内置),作为平台 adapter 的绑定入口\n\n/// <reference types=\"@cloudflare/workers-types\" />\nimport { env } from \"cloudflare:workers\";\n\nexport type AppEnv = {\n DB: D1Database;\n ASSETS: Fetcher;\n IMAGES: ImagesBinding;\n ASSETS_BUCKET?: R2Bucket;\n CONTENT_CACHE?: KVNamespace;\n ADMIN_PASSWORD: string;\n ADMIN_EMAIL?: string;\n SITE_URL?: string;\n RESEND_API_KEY?: string;\n RESEND_FROM?: string;\n // Google OAuth 仍然兼容 Cloudflare Secret 作为兜底。\n // 实际生效值以 app_settings.google_client_id / google_client_secret 为准。\n GOOGLE_CLIENT_ID?: string;\n GOOGLE_CLIENT_SECRET?: string;\n /** Turnstile site key fallback when not stored in app_settings */\n TURNSTILE_SITE_KEY?: string;\n /** Turnstile secret — set via `wrangler secret put TURNSTILE_SECRET_KEY` */\n TURNSTILE_SECRET_KEY?: string;\n /** Notion integration token for the blog data source */\n NOTION_TOKEN?: string;\n /** Notion data source ID used by dataSources.query */\n NOTION_DATA_SOURCE_ID?: string;\n /** Notion data source ID for the public movie catalog */\n NOTION_MOVIES_DATA_SOURCE_ID?: string;\n /** Notion data source ID for localized movie copy */\n NOTION_MOVIE_TRANSLATIONS_DATA_SOURCE_ID?: string;\n /** Optional Notion API base URL for tests or proxies */\n NOTION_API_BASE_URL?: string;\n /** Optional Notion edit URL for admin handoff screens */\n NOTION_EDIT_BASE_URL?: string;\n /** Optional webhook verification token for Notion invalidation */\n NOTION_WEBHOOK_VERIFICATION_TOKEN?: string;\n};\n\n// 强制类型:vinext 把 env 类型放在 env.d.ts(interface VinextEnv extends Env),\n// 但 TS server 经常解析不到。运行时一定有 DB,类型断言保证编译通过。\nexport const workerEnv = env as unknown as AppEnv;\n","import type { AppEnv } from \"../util/env\";\n\nexport type PlatformBindingEnv = Pick<\n AppEnv,\n \"ASSETS_BUCKET\" | \"CONTENT_CACHE\" | \"DB\" | \"IMAGES\"\n>;\n\nexport type StoredObject = {\n body: ReadableStream;\n size: number;\n etag?: string;\n contentType?: string;\n};\n\nexport type ObjectStoragePutOptions = {\n contentType?: string;\n cacheControl?: string;\n metadata?: Record<string, string>;\n};\n\nexport type ObjectStorageListItem = {\n key: string;\n size: number;\n uploaded: Date;\n};\n\nexport type ObjectStorageAdapter = {\n kind: \"r2\";\n get(key: string): Promise<StoredObject | null>;\n put(\n key: string,\n value: ReadableStream | ArrayBuffer | ArrayBufferView | string | Blob,\n options?: ObjectStoragePutOptions\n ): Promise<void>;\n delete(key: string): Promise<void>;\n list(\n options?: { prefix?: string; limit?: number }\n ): Promise<ObjectStorageListItem[]>;\n};\n\nexport type ImageTransformOptions = {\n width?: number;\n format: \"image/avif\" | \"image/webp\";\n quality: number;\n};\n\nexport type ImageTransformResult = {\n body: ReadableStream;\n contentType: string;\n response(): Response;\n};\n\nexport type ImageTransformerAdapter = {\n kind: \"cloudflare-images\" | \"external\";\n transform(\n body: ReadableStream,\n options: ImageTransformOptions\n ): Promise<ImageTransformResult>;\n};\n\nexport type PublicCacheAdapter = {\n kind: \"cloudflare-cache\" | \"noop\" | \"external\";\n match(key: string): Promise<Response | null>;\n put(key: string, response: Response): Promise<void>;\n delete(key: string): Promise<boolean>;\n};\n\nexport type KeyValueCacheGetOptions = {\n cacheTtl?: number;\n};\n\nexport type KeyValueCachePutOptions = {\n expirationTtl?: number;\n metadata?: Record<string, string | number | boolean | null>;\n};\n\nexport type KeyValueCacheListOptions = {\n prefix?: string;\n limit?: number;\n cursor?: string;\n};\n\nexport type KeyValueCacheListResult = {\n keys: Array<{ name: string }>;\n cursor?: string;\n listComplete: boolean;\n};\n\nexport type KeyValueCacheAdapter = {\n kind: \"workers-kv\" | \"noop\" | \"external\";\n get<T = unknown>(\n key: string,\n options?: KeyValueCacheGetOptions\n ): Promise<T | null>;\n put<T = unknown>(\n key: string,\n value: T,\n options?: KeyValueCachePutOptions\n ): Promise<void>;\n delete(key: string): Promise<void>;\n list(options?: KeyValueCacheListOptions): Promise<KeyValueCacheListResult>;\n};\n\nexport type SqlValue = string | number | boolean | null;\n\nexport type SqlResult<T = Record<string, unknown>> = {\n results?: T[];\n success?: boolean;\n meta?: {\n changes?: number;\n duration?: number;\n last_row_id?: number;\n rows_read?: number;\n rows_written?: number;\n [key: string]: unknown;\n };\n};\n\nexport type SqlPreparedStatement = {\n bind(...values: SqlValue[]): SqlPreparedStatement;\n all<T = Record<string, unknown>>(): Promise<SqlResult<T>>;\n first<T = Record<string, unknown>>(columnName?: string): Promise<T | null>;\n run<T = Record<string, unknown>>(): Promise<SqlResult<T>>;\n};\n\nexport type SqlDatabaseAdapter = {\n kind: \"d1\";\n prepare(query: string): SqlPreparedStatement;\n batch<T = Record<string, unknown>>(\n statements: SqlPreparedStatement[]\n ): Promise<SqlResult<T>[]>;\n};\n\nexport type RuntimePlatform = {\n id: \"cloudflare-workers\";\n database: SqlDatabaseAdapter | null;\n objectStorage: ObjectStorageAdapter | null;\n imageTransformer: ImageTransformerAdapter | null;\n publicCache: PublicCacheAdapter | null;\n keyValueCache: KeyValueCacheAdapter | null;\n};\n\ntype CloudflareCacheLike = Pick<Cache, \"match\" | \"put\" | \"delete\">;\ntype CloudflareKvLike = Pick<KVNamespace, \"get\" | \"put\" | \"delete\" | \"list\">;\n\nfunction cacheRequestForKey(key: string) {\n return new Request(key, { method: \"GET\" });\n}\n\nexport function createCloudflarePublicCacheAdapter(\n cache: CloudflareCacheLike\n): PublicCacheAdapter {\n return {\n kind: \"cloudflare-cache\",\n async match(key) {\n return (await cache.match(cacheRequestForKey(key))) ?? null;\n },\n put(key, response) {\n return cache.put(cacheRequestForKey(key), response);\n },\n delete(key) {\n return cache.delete(cacheRequestForKey(key));\n },\n };\n}\n\nexport function createNoopPublicCacheAdapter(kind: \"noop\" = \"noop\"): PublicCacheAdapter {\n return {\n kind,\n async match() {\n return null;\n },\n async put() {},\n async delete() {\n return false;\n },\n };\n}\n\nexport function createCloudflareKeyValueCacheAdapter(\n namespace: CloudflareKvLike\n): KeyValueCacheAdapter {\n return {\n kind: \"workers-kv\",\n async get<T = unknown>(\n key: string,\n options?: KeyValueCacheGetOptions\n ): Promise<T | null> {\n return (await namespace.get(key, {\n type: \"json\",\n cacheTtl: options?.cacheTtl,\n })) as T | null;\n },\n async put(key, value, options) {\n await namespace.put(key, JSON.stringify(value), {\n expirationTtl: options?.expirationTtl,\n metadata: options?.metadata,\n });\n },\n delete(key) {\n return namespace.delete(key);\n },\n async list(options) {\n const result = await namespace.list({\n prefix: options?.prefix,\n limit: options?.limit,\n cursor: options?.cursor,\n });\n return {\n keys: result.keys.map((key) => ({ name: key.name })),\n cursor: result.list_complete ? undefined : result.cursor,\n listComplete: result.list_complete,\n };\n },\n };\n}\n\nexport function createNoopKeyValueCacheAdapter(\n kind: \"noop\" = \"noop\"\n): KeyValueCacheAdapter {\n return {\n kind,\n async get() {\n return null;\n },\n async put() {},\n async delete() {},\n async list() {\n return { keys: [], listComplete: true };\n },\n };\n}\n\nfunction r2ObjectToStoredObject(object: R2ObjectBody): StoredObject {\n return {\n body: object.body,\n size: object.size,\n etag: object.etag,\n contentType: object.httpMetadata?.contentType,\n };\n}\n\nexport function createCloudflareRuntimePlatform(\n env: PlatformBindingEnv,\n options?: { publicCache?: CloudflareCacheLike | null }\n): RuntimePlatform {\n const database: SqlDatabaseAdapter | null = env.DB\n ? ({\n kind: \"d1\",\n prepare(query: string) {\n return env.DB.prepare(query) as unknown as SqlPreparedStatement;\n },\n async batch(statements: SqlPreparedStatement[]) {\n return (await env.DB.batch(\n statements as unknown as D1PreparedStatement[]\n )) as unknown as SqlResult<Record<string, unknown>>[];\n },\n } as unknown as SqlDatabaseAdapter)\n : null;\n\n const objectStorage: ObjectStorageAdapter | null = env.ASSETS_BUCKET\n ? {\n kind: \"r2\",\n async get(key) {\n const object = await env.ASSETS_BUCKET?.get(key);\n return object ? r2ObjectToStoredObject(object) : null;\n },\n async put(key, value, options) {\n await env.ASSETS_BUCKET?.put(key, value, {\n httpMetadata: {\n contentType: options?.contentType,\n cacheControl: options?.cacheControl,\n },\n customMetadata: options?.metadata,\n });\n },\n async delete(key) {\n await env.ASSETS_BUCKET?.delete(key);\n },\n async list(options) {\n const listed = await env.ASSETS_BUCKET?.list({\n prefix: options?.prefix,\n limit: options?.limit,\n });\n return (\n listed?.objects.map((object) => ({\n key: object.key,\n size: object.size,\n uploaded: object.uploaded,\n })) ?? []\n );\n },\n }\n : null;\n\n const imageTransformer: ImageTransformerAdapter | null = env.IMAGES\n ? {\n kind: \"cloudflare-images\",\n async transform(body, options) {\n const result = await env.IMAGES.input(body)\n .transform(options.width ? { width: options.width } : {})\n .output({\n format: options.format,\n quality: options.quality,\n });\n return {\n body: result.image(),\n contentType: result.contentType(),\n response: () => result.response(),\n };\n },\n }\n : null;\n\n const keyValueCache: KeyValueCacheAdapter | null = env.CONTENT_CACHE\n ? createCloudflareKeyValueCacheAdapter(env.CONTENT_CACHE)\n : null;\n\n return {\n id: \"cloudflare-workers\",\n database,\n objectStorage,\n imageTransformer,\n keyValueCache,\n publicCache: options?.publicCache\n ? createCloudflarePublicCacheAdapter(options.publicCache)\n : null,\n };\n}\n","import { workerEnv } from \"../util/env\";\nimport {\n createCloudflarePublicCacheAdapter,\n createCloudflareRuntimePlatform,\n} from \"./runtime\";\n\nfunction getDefaultCloudflareCache() {\n const globalWithCaches = globalThis as typeof globalThis & {\n caches?: CacheStorage & { default?: Cache };\n };\n return globalWithCaches.caches?.default ?? null;\n}\n\nexport function getRuntimePlatform() {\n return createCloudflareRuntimePlatform(workerEnv, {\n publicCache: getDefaultCloudflareCache(),\n });\n}\n\nexport function getDatabase() {\n const database = getRuntimePlatform().database;\n if (!database) {\n throw new Error(\"SQL database binding not configured\");\n }\n return database;\n}\n\nexport function getPublicCache() {\n const cache = getDefaultCloudflareCache();\n if (!cache) {\n throw new Error(\"Cloudflare cache binding not configured\");\n }\n return createCloudflarePublicCacheAdapter(cache);\n}\n","import {\n getPublicCache as getCloudflarePublicCache,\n getRuntimePlatform as getCloudflareRuntimePlatform,\n} from \"./cloudflare-runtime\";\nimport { currentRuntimeId } from \"./selection\";\n\nexport function getRuntimePlatform() {\n return getCloudflareRuntimePlatform();\n}\n\nexport function getDatabase() {\n const platform = getRuntimePlatform();\n const database = platform.database;\n if (!database) {\n throw new Error(`SQL database adapter not configured for ${platform.id}`);\n }\n return database;\n}\n\nexport function getPublicCache() {\n return getCloudflarePublicCache();\n}\n\nexport function getKeyValueCache() {\n return getRuntimePlatform().keyValueCache;\n}\n\nexport const runtimeSelection = {\n currentRuntimeId,\n};\n","// Object storage helpers for file upload, list, and delete.\n//\n// Cloudflare Workers uses R2 as the backing store; the abstraction in\n// platform/runtime.ts hides the concrete binding.\n//\n// File naming: <randomUUID>.<ext> — prevents collisions and makes keys\n// non-guessable.\n// Public access: today every read goes through the worker's\n// /api/files/[key] proxy (avoids the complexity of a public bucket).\n// To serve directly from R2: make the bucket public and attach a\n// custom domain.\n\nimport { getRuntimePlatform } from \"../platform/current\";\n\nexport type UploadResult = {\n key: string;\n url: string;\n size: number;\n contentType: string;\n};\n\nexport function buildAssetUrl(kind: \"cdn\" | \"files\", key: string): string {\n // Encode each path segment separately so nested R2 keys remain routable.\n const safeKey = key\n .split(\"/\")\n .filter(Boolean)\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n return `/api/${kind}/${safeKey}`;\n}\n\n// Whitelisted MIME types — keeps the bucket from becoming a dumping\n// ground. The browser can occasionally send an empty type, so the\n// extension is also checked.\nconst ALLOWED = new Set([\n \"image/jpeg\",\n \"image/jpg\",\n \"image/png\",\n \"image/gif\",\n \"image/webp\",\n \"image/svg+xml\",\n \"image/avif\",\n \"application/pdf\",\n \"text/plain\",\n]);\n\nconst ALLOWED_IMAGE_EXT = /\\.(jpe?g|png|gif|webp|avif|svg)$/i;\n\n// 100 MB cap (worker request body limit).\nconst MAX_SIZE = 100 * 1024 * 1024;\n\nexport async function uploadFile(\n file: File,\n prefix = \"uploads\"\n): Promise<UploadResult> {\n const storage = getRuntimePlatform().objectStorage;\n if (!storage) {\n throw new Error(\"Object storage binding not configured\");\n }\n if (file.size > MAX_SIZE) {\n throw new Error(`File too large: ${file.size} bytes (max ${MAX_SIZE})`);\n }\n // Belt and suspenders: pass the MIME whitelist OR a matching extension.\n if (!ALLOWED.has(file.type) && !ALLOWED_IMAGE_EXT.test(file.name)) {\n throw new Error(`Unsupported file type: ${file.type || \"(empty)\"}`);\n }\n\n // Random key (non-guessable).\n const ext = file.name.split(\".\").pop() || \"bin\";\n const rand = crypto.randomUUID().replace(/-/g, \"\").slice(0, 16);\n const date = new Date().toISOString().slice(0, 10);\n const key = `${prefix}/${date}/${rand}.${ext}`;\n\n // Write to object storage with content-type and immutable cache headers.\n await storage.put(key, file, {\n contentType: file.type,\n cacheControl: \"public, max-age=31536000, immutable\",\n metadata: {\n originalName: file.name.slice(0, 100),\n uploadedAt: new Date().toISOString(),\n },\n });\n\n return {\n key,\n // Images go through the CDN (auto WebP/AVIF optimization); other\n // files go through the raw /api/files proxy.\n url: file.type.startsWith(\"image/\")\n ? buildAssetUrl(\"cdn\", key)\n : buildAssetUrl(\"files\", key),\n size: file.size,\n contentType: file.type,\n };\n}\n\nexport async function deleteFile(key: string): Promise<void> {\n const storage = getRuntimePlatform().objectStorage;\n if (!storage) return;\n await storage.delete(key);\n}\n\nexport async function listFiles(prefix = \"uploads\", limit = 50) {\n const storage = getRuntimePlatform().objectStorage;\n if (!storage) return [];\n const listed = await storage.list({ prefix, limit });\n return listed.map((object) => ({\n key: object.key,\n size: object.size,\n uploaded: object.uploaded.toISOString(),\n url: buildAssetUrl(\"files\", object.key),\n }));\n}\n"],"mappings":"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","names":["env","options","getRuntimePlatform","getRuntimePlatform"]}
@@ -0,0 +1,19 @@
1
+ declare const dynamic = "force-dynamic";
2
+ type Props = {
3
+ params: Promise<{
4
+ key: string[];
5
+ }>;
6
+ };
7
+ declare const cdnRoute: {
8
+ GET(request: Request, props: Props): Promise<Response>;
9
+ handle(request: Request): Promise<Response>;
10
+ };
11
+ declare const GET: (request: Request, props: Props) => Promise<Response>;
12
+ /**
13
+ * Worker-friendly single-arg handler. Used by the Cloudflare Workers
14
+ * bootstrap in `@notionx/core/worker`. Equivalent to
15
+ * `cdnRoute.handle`.
16
+ */
17
+ declare function cdnRouteHandle(request: Request): Promise<Response>;
18
+
19
+ export { GET, cdnRoute, cdnRouteHandle, dynamic };