@edge-base/server 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin-build/.gitkeep +0 -0
- package/admin-build/_app/env.js +1 -0
- package/admin-build/_app/immutable/assets/0.Bm6cF078.css +1 -0
- package/admin-build/_app/immutable/assets/1.BfW3pUNa.css +1 -0
- package/admin-build/_app/immutable/assets/11.CVmQOewb.css +1 -0
- package/admin-build/_app/immutable/assets/12.B1EhbRZT.css +1 -0
- package/admin-build/_app/immutable/assets/13.BvwYeuwE.css +1 -0
- package/admin-build/_app/immutable/assets/14.CdVfcO0R.css +1 -0
- package/admin-build/_app/immutable/assets/15.2yeZ66b-.css +1 -0
- package/admin-build/_app/immutable/assets/17.BVg0JEVu.css +1 -0
- package/admin-build/_app/immutable/assets/18.Rwnl3x_i.css +1 -0
- package/admin-build/_app/immutable/assets/20.DsPWA9AV.css +1 -0
- package/admin-build/_app/immutable/assets/21.Dz2RJ56c.css +1 -0
- package/admin-build/_app/immutable/assets/22.DwNLk5Ai.css +1 -0
- package/admin-build/_app/immutable/assets/23.CFpu0gOO.css +1 -0
- package/admin-build/_app/immutable/assets/24.Cy5LBeoJ.css +1 -0
- package/admin-build/_app/immutable/assets/25.pUyLVf-h.css +1 -0
- package/admin-build/_app/immutable/assets/26.DBcGrlXa.css +1 -0
- package/admin-build/_app/immutable/assets/27.BswYyAJD.css +1 -0
- package/admin-build/_app/immutable/assets/28.B4ueB1Kf.css +1 -0
- package/admin-build/_app/immutable/assets/29.B-qU6PdF.css +1 -0
- package/admin-build/_app/immutable/assets/3.Dg81Pgmd.css +1 -0
- package/admin-build/_app/immutable/assets/30.CsdWum94.css +1 -0
- package/admin-build/_app/immutable/assets/31.U6OwIp50.css +1 -0
- package/admin-build/_app/immutable/assets/4.CyawCCux.css +1 -0
- package/admin-build/_app/immutable/assets/5.C0YO2HTk.css +1 -0
- package/admin-build/_app/immutable/assets/8.Br5jd6kD.css +1 -0
- package/admin-build/_app/immutable/assets/Badge.EMYLHBxE.css +1 -0
- package/admin-build/_app/immutable/assets/Button.DpzMRTjK.css +1 -0
- package/admin-build/_app/immutable/assets/ConfirmDialog.DAnaWRRk.css +1 -0
- package/admin-build/_app/immutable/assets/EmptyState.CwKsu57Y.css +1 -0
- package/admin-build/_app/immutable/assets/Input.BDUSenmU.css +1 -0
- package/admin-build/_app/immutable/assets/Modal.Dm5B0Xie.css +1 -0
- package/admin-build/_app/immutable/assets/PageShell.CmU-Xh-b.css +1 -0
- package/admin-build/_app/immutable/assets/SchemaFieldEditor.g4NsCdno.css +1 -0
- package/admin-build/_app/immutable/assets/Select.BW4Keufm.css +1 -0
- package/admin-build/_app/immutable/assets/Skeleton.KWUulTKJ.css +1 -0
- package/admin-build/_app/immutable/assets/Tabs.CniGYb67.css +1 -0
- package/admin-build/_app/immutable/assets/TimeChart.BTCDAvmT.css +1 -0
- package/admin-build/_app/immutable/assets/Toggle.Cy_K12OM.css +1 -0
- package/admin-build/_app/immutable/assets/TopList.ClFzmPlA.css +1 -0
- package/admin-build/_app/immutable/chunks/7B47DvSx.js +1 -0
- package/admin-build/_app/immutable/chunks/7f08Id8e.js +1 -0
- package/admin-build/_app/immutable/chunks/8wJeQ7LN.js +1 -0
- package/admin-build/_app/immutable/chunks/B-h2afW5.js +1 -0
- package/admin-build/_app/immutable/chunks/B8vJP3wz.js +1 -0
- package/admin-build/_app/immutable/chunks/BR_fL5Yv.js +1 -0
- package/admin-build/_app/immutable/chunks/BY92tFS2.js +1 -0
- package/admin-build/_app/immutable/chunks/BcR-Rdj9.js +1 -0
- package/admin-build/_app/immutable/chunks/BdrwyZv8.js +1 -0
- package/admin-build/_app/immutable/chunks/Bh56EfQ_.js +1 -0
- package/admin-build/_app/immutable/chunks/BkrCkgYp.js +1 -0
- package/admin-build/_app/immutable/chunks/BmRjiP5k.js +1 -0
- package/admin-build/_app/immutable/chunks/BsokvhWC.js +1 -0
- package/admin-build/_app/immutable/chunks/C4D51vTW.js +1 -0
- package/admin-build/_app/immutable/chunks/C6puvcoR.js +2 -0
- package/admin-build/_app/immutable/chunks/CCKNu7m7.js +1 -0
- package/admin-build/_app/immutable/chunks/CWj6FrbW.js +1 -0
- package/admin-build/_app/immutable/chunks/Ce-ngf4p.js +5 -0
- package/admin-build/_app/immutable/chunks/Cs0GwzJA.js +1 -0
- package/admin-build/_app/immutable/chunks/CwROoZK0.js +1 -0
- package/admin-build/_app/immutable/chunks/CxCPv_Ut.js +1 -0
- package/admin-build/_app/immutable/chunks/CxbRue-5.js +1 -0
- package/admin-build/_app/immutable/chunks/CyqB6g-D.js +1 -0
- package/admin-build/_app/immutable/chunks/D5h5A1cc.js +2 -0
- package/admin-build/_app/immutable/chunks/DnyL7Zq-.js +1 -0
- package/admin-build/_app/immutable/chunks/DoPXzH7F.js +1 -0
- package/admin-build/_app/immutable/chunks/DrQSgw-f.js +1 -0
- package/admin-build/_app/immutable/chunks/DttM2zNO.js +1 -0
- package/admin-build/_app/immutable/chunks/DuXuUBWN.js +1 -0
- package/admin-build/_app/immutable/chunks/MdeqaOQx.js +10 -0
- package/admin-build/_app/immutable/chunks/NuUjtcO2.js +1 -0
- package/admin-build/_app/immutable/chunks/Q2nPFxS6.js +1 -0
- package/admin-build/_app/immutable/chunks/R6arueIl.js +1 -0
- package/admin-build/_app/immutable/chunks/UUazaC_N.js +1 -0
- package/admin-build/_app/immutable/chunks/cOYbrQxx.js +1 -0
- package/admin-build/_app/immutable/chunks/eFQHTGwA.js +1 -0
- package/admin-build/_app/immutable/chunks/ehbppgYb.js +1 -0
- package/admin-build/_app/immutable/chunks/glwixJlP.js +1 -0
- package/admin-build/_app/immutable/chunks/vApWTCBs.js +1 -0
- package/admin-build/_app/immutable/chunks/w89G9Xpi.js +1 -0
- package/admin-build/_app/immutable/chunks/wJsUhbfZ.js +1 -0
- package/admin-build/_app/immutable/chunks/zfauFM8P.js +1 -0
- package/admin-build/_app/immutable/entry/app.CcO-Uos3.js +2 -0
- package/admin-build/_app/immutable/entry/start.COebYq3I.js +1 -0
- package/admin-build/_app/immutable/nodes/0.CjtHKU-6.js +1 -0
- package/admin-build/_app/immutable/nodes/1.DEisjlM0.js +1 -0
- package/admin-build/_app/immutable/nodes/10.CvhdyWVB.js +1 -0
- package/admin-build/_app/immutable/nodes/11.DjHqcOvy.js +1 -0
- package/admin-build/_app/immutable/nodes/12.mQLz4Mj_.js +1 -0
- package/admin-build/_app/immutable/nodes/13.CBonZZyP.js +110 -0
- package/admin-build/_app/immutable/nodes/14.d-oiZL0j.js +3 -0
- package/admin-build/_app/immutable/nodes/15.CKPQsUYF.js +1 -0
- package/admin-build/_app/immutable/nodes/16.wPzAPQGx.js +1 -0
- package/admin-build/_app/immutable/nodes/17.DayhKyEZ.js +1 -0
- package/admin-build/_app/immutable/nodes/18.DKwS0Ir0.js +1 -0
- package/admin-build/_app/immutable/nodes/19.wPzAPQGx.js +1 -0
- package/admin-build/_app/immutable/nodes/2.BKoKrw1i.js +1 -0
- package/admin-build/_app/immutable/nodes/20.BvIkkkrW.js +1 -0
- package/admin-build/_app/immutable/nodes/21.DMaFhdHk.js +128 -0
- package/admin-build/_app/immutable/nodes/22.3xdgwuK1.js +1 -0
- package/admin-build/_app/immutable/nodes/23.8Bvgjbsl.js +112 -0
- package/admin-build/_app/immutable/nodes/24.DzSSzRhG.js +2 -0
- package/admin-build/_app/immutable/nodes/25.9KKYBnAE.js +2 -0
- package/admin-build/_app/immutable/nodes/26.Bhn9dfhY.js +1 -0
- package/admin-build/_app/immutable/nodes/27.kRLiC24G.js +1 -0
- package/admin-build/_app/immutable/nodes/28.BVIN1-7N.js +1 -0
- package/admin-build/_app/immutable/nodes/29.3yabZWj4.js +1 -0
- package/admin-build/_app/immutable/nodes/3.BFtSOkX7.js +2 -0
- package/admin-build/_app/immutable/nodes/30.CyCQlwaP.js +1 -0
- package/admin-build/_app/immutable/nodes/31.C4LDXjES.js +1 -0
- package/admin-build/_app/immutable/nodes/4.CvbiMlCa.js +1 -0
- package/admin-build/_app/immutable/nodes/5.C6BLv2eM.js +1 -0
- package/admin-build/_app/immutable/nodes/6.BcXvfl2P.js +1 -0
- package/admin-build/_app/immutable/nodes/7.CIuqhPiK.js +1 -0
- package/admin-build/_app/immutable/nodes/8.BQOR_JfO.js +1 -0
- package/admin-build/_app/immutable/nodes/9.NZqXQxPy.js +1 -0
- package/admin-build/_app/version.json +1 -0
- package/admin-build/favicon.svg +26 -0
- package/admin-build/index.html +45 -0
- package/openapi.json +19543 -0
- package/package.json +66 -0
- package/src/__tests__/admin-assets.test.ts +55 -0
- package/src/__tests__/admin-data-routes.test.ts +488 -0
- package/src/__tests__/admin-db-target.test.ts +103 -0
- package/src/__tests__/admin-routing.test.ts +31 -0
- package/src/__tests__/admin-user-management.test.ts +311 -0
- package/src/__tests__/analytics-query.test.ts +75 -0
- package/src/__tests__/auth-d1.test.ts +749 -0
- package/src/__tests__/auth-db-adapter.test.ts +73 -0
- package/src/__tests__/auth-jwt.test.ts +440 -0
- package/src/__tests__/auth-oauth.test.ts +389 -0
- package/src/__tests__/auth-password.test.ts +367 -0
- package/src/__tests__/auth-redirect.test.ts +87 -0
- package/src/__tests__/backup-restore.test.ts +711 -0
- package/src/__tests__/broadcast.test.ts +128 -0
- package/src/__tests__/cli.test.ts +178 -0
- package/src/__tests__/cloudflare-realtime.test.ts +113 -0
- package/src/__tests__/config.test.ts +469 -0
- package/src/__tests__/cors.test.ts +154 -0
- package/src/__tests__/cron.test.ts +302 -0
- package/src/__tests__/d1-handler.test.ts +402 -0
- package/src/__tests__/d1-sql.test.ts +120 -0
- package/src/__tests__/database-live-config.test.ts +42 -0
- package/src/__tests__/database-live-emitter.test.ts +56 -0
- package/src/__tests__/database-live-filters.test.ts +63 -0
- package/src/__tests__/database-live-route.test.ts +113 -0
- package/src/__tests__/db-sql.test.ts +163 -0
- package/src/__tests__/do-lifecycle.test.ts +263 -0
- package/src/__tests__/do-router.test.ts +729 -0
- package/src/__tests__/email-provider.test.ts +128 -0
- package/src/__tests__/email-templates.test.ts +528 -0
- package/src/__tests__/error-format.test.ts +250 -0
- package/src/__tests__/field-ops.test.ts +242 -0
- package/src/__tests__/functions-context.test.ts +334 -0
- package/src/__tests__/functions-d1-proxy.test.ts +229 -0
- package/src/__tests__/functions-registry-runtime-config.test.ts +17 -0
- package/src/__tests__/functions-route.test.ts +139 -0
- package/src/__tests__/internal-request.test.ts +77 -0
- package/src/__tests__/log-writer.test.ts +44 -0
- package/src/__tests__/logger.test.ts +58 -0
- package/src/__tests__/meta-admin-proxy.test.ts +48 -0
- package/src/__tests__/meta-export-coverage.test.ts +191 -0
- package/src/__tests__/meta-route-registration.test.ts +47 -0
- package/src/__tests__/namespace-dump.test.ts +28 -0
- package/src/__tests__/oauth-providers.test.ts +337 -0
- package/src/__tests__/openapi-coverage.test.ts +144 -0
- package/src/__tests__/pagination.test.ts +59 -0
- package/src/__tests__/password-policy.test.ts +191 -0
- package/src/__tests__/plugin-migrations.test.ts +379 -0
- package/src/__tests__/postgres-batch-compat.test.ts +133 -0
- package/src/__tests__/postgres-dialect.test.ts +328 -0
- package/src/__tests__/postgres-executor.test.ts +79 -0
- package/src/__tests__/postgres-field-ops-compat.test.ts +222 -0
- package/src/__tests__/postgres-schema-init.test.ts +105 -0
- package/src/__tests__/postgres-table-utils.test.ts +107 -0
- package/src/__tests__/presence.test.ts +199 -0
- package/src/__tests__/provider.test.ts +550 -0
- package/src/__tests__/public-user-profile.test.ts +339 -0
- package/src/__tests__/push-handlers.test.ts +179 -0
- package/src/__tests__/push-provider.test.ts +80 -0
- package/src/__tests__/push-token.test.ts +418 -0
- package/src/__tests__/query.test.ts +771 -0
- package/src/__tests__/rate-limit.test.ts +260 -0
- package/src/__tests__/room-access-policy.test.ts +101 -0
- package/src/__tests__/room-handler-context.test.ts +130 -0
- package/src/__tests__/room-monitoring.test.ts +138 -0
- package/src/__tests__/room-runtime-routing.test.ts +222 -0
- package/src/__tests__/room.test.ts +254 -0
- package/src/__tests__/route-parser.test.ts +490 -0
- package/src/__tests__/rules.test.ts +234 -0
- package/src/__tests__/runtime-surface-accounting.test.ts +120 -0
- package/src/__tests__/scheduled.test.ts +80 -0
- package/src/__tests__/schema.test.ts +1273 -0
- package/src/__tests__/security-hardening.test.ts +312 -0
- package/src/__tests__/server.unit.test.ts +333 -0
- package/src/__tests__/service-key-db-proxy.test.ts +650 -0
- package/src/__tests__/service-key-provider-bypass.test.ts +138 -0
- package/src/__tests__/service-key.test.ts +757 -0
- package/src/__tests__/smoke-skip-report.test.ts +72 -0
- package/src/__tests__/sms-provider.test.ts +39 -0
- package/src/__tests__/sql-route.test.ts +218 -0
- package/src/__tests__/storage-hook-context.test.ts +115 -0
- package/src/__tests__/totp.test.ts +200 -0
- package/src/__tests__/uuid.test.ts +144 -0
- package/src/__tests__/validation.test.ts +773 -0
- package/src/__tests__/websocket-pending.test.ts +163 -0
- package/src/_functions-registry.ts +51 -0
- package/src/bench-entry.ts +9 -0
- package/src/cloudflare-test.d.ts +1 -0
- package/src/durable-objects/auth-do.ts +49 -0
- package/src/durable-objects/database-do.ts +2240 -0
- package/src/durable-objects/database-live-do.ts +949 -0
- package/src/durable-objects/logs-do.ts +1200 -0
- package/src/durable-objects/room-runtime-base.ts +1604 -0
- package/src/durable-objects/rooms-do.ts +2191 -0
- package/src/generated-config.ts +6 -0
- package/src/index.ts +382 -0
- package/src/lib/admin-assets.ts +54 -0
- package/src/lib/admin-db-target.ts +301 -0
- package/src/lib/admin-routing.ts +35 -0
- package/src/lib/admin-user-management.ts +464 -0
- package/src/lib/analytics-adapter.ts +103 -0
- package/src/lib/analytics-query.ts +579 -0
- package/src/lib/auth-d1-service.ts +1193 -0
- package/src/lib/auth-d1.ts +1056 -0
- package/src/lib/auth-db-adapter.ts +289 -0
- package/src/lib/auth-redirect.ts +116 -0
- package/src/lib/cidr.ts +115 -0
- package/src/lib/client-ip.ts +51 -0
- package/src/lib/cloudflare-realtime.ts +251 -0
- package/src/lib/control-db.ts +36 -0
- package/src/lib/cron.ts +163 -0
- package/src/lib/d1-handler.ts +1425 -0
- package/src/lib/d1-schema-init.ts +255 -0
- package/src/lib/d1-sql.ts +33 -0
- package/src/lib/database-live-config.ts +24 -0
- package/src/lib/database-live-emitter.ts +111 -0
- package/src/lib/db-sql.ts +66 -0
- package/src/lib/do-retry.ts +36 -0
- package/src/lib/do-router.ts +270 -0
- package/src/lib/do-sql.ts +73 -0
- package/src/lib/email-provider.ts +379 -0
- package/src/lib/email-templates.ts +285 -0
- package/src/lib/email-translations.ts +422 -0
- package/src/lib/errors.ts +151 -0
- package/src/lib/functions.ts +2091 -0
- package/src/lib/hono.ts +56 -0
- package/src/lib/internal-request.ts +56 -0
- package/src/lib/jwt.ts +354 -0
- package/src/lib/log-writer.ts +272 -0
- package/src/lib/namespace-dump.ts +125 -0
- package/src/lib/oauth-providers.ts +1225 -0
- package/src/lib/op-parser.ts +99 -0
- package/src/lib/openapi.ts +146 -0
- package/src/lib/pagination.ts +19 -0
- package/src/lib/password-policy.ts +102 -0
- package/src/lib/password.ts +145 -0
- package/src/lib/plugin-migrations.ts +612 -0
- package/src/lib/postgres-executor.ts +203 -0
- package/src/lib/postgres-handler.ts +1102 -0
- package/src/lib/postgres-schema-init.ts +341 -0
- package/src/lib/postgres-table-utils.ts +87 -0
- package/src/lib/public-user-profile.ts +187 -0
- package/src/lib/push-provider.ts +409 -0
- package/src/lib/push-token.ts +294 -0
- package/src/lib/query-engine.ts +768 -0
- package/src/lib/room-monitoring.ts +97 -0
- package/src/lib/room-runtime.ts +14 -0
- package/src/lib/route-parser.ts +434 -0
- package/src/lib/schema.ts +538 -0
- package/src/lib/schemas.ts +152 -0
- package/src/lib/service-key.ts +419 -0
- package/src/lib/sms-provider.ts +230 -0
- package/src/lib/startup-config.ts +99 -0
- package/src/lib/totp.ts +242 -0
- package/src/lib/uuid.ts +87 -0
- package/src/lib/validation.ts +205 -0
- package/src/lib/version.ts +2 -0
- package/src/lib/websocket-pending.ts +40 -0
- package/src/middleware/auth.ts +169 -0
- package/src/middleware/captcha-verify.ts +217 -0
- package/src/middleware/cors.ts +159 -0
- package/src/middleware/error-handler.ts +54 -0
- package/src/middleware/internal-guard.ts +26 -0
- package/src/middleware/logger.ts +126 -0
- package/src/middleware/rate-limit.ts +283 -0
- package/src/middleware/rules.ts +475 -0
- package/src/routes/admin-auth.ts +447 -0
- package/src/routes/admin.ts +3501 -0
- package/src/routes/analytics-api.ts +290 -0
- package/src/routes/auth.ts +4222 -0
- package/src/routes/backup.ts +1466 -0
- package/src/routes/config.ts +53 -0
- package/src/routes/d1.ts +109 -0
- package/src/routes/database-live.ts +281 -0
- package/src/routes/functions.ts +155 -0
- package/src/routes/health.ts +32 -0
- package/src/routes/kv.ts +167 -0
- package/src/routes/oauth.ts +1055 -0
- package/src/routes/push.ts +1465 -0
- package/src/routes/room.ts +639 -0
- package/src/routes/schema-endpoint.ts +76 -0
- package/src/routes/sql.ts +176 -0
- package/src/routes/storage.ts +1674 -0
- package/src/routes/tables.ts +699 -0
- package/src/routes/users.ts +21 -0
- package/src/routes/vectorize.ts +372 -0
- package/src/types.ts +99 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LogWriter adapter pattern.
|
|
3
|
+
*
|
|
4
|
+
* Provides environment-aware log storage with extended analytics fields:
|
|
5
|
+
* - Cloud: AnalyticsEngineWriter — 10 blobs, 6 doubles
|
|
6
|
+
* - Docker/Self-hosted: SQLiteLogWriter — LogsDO with 3-tier pre-aggregation
|
|
7
|
+
* - Dev fallback: ConsoleLogWriter — structured console output
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* const logger = createLogWriter(env, executionCtx);
|
|
11
|
+
* logger.write({ method, path, status, duration, userId, category, ... });
|
|
12
|
+
*
|
|
13
|
+
* Data Point Layout (Analytics Engine):
|
|
14
|
+
* index1: userId (or 'anonymous')
|
|
15
|
+
* blob1: method blob6: subcategory
|
|
16
|
+
* blob2: path blob7: target1
|
|
17
|
+
* blob3: status (str) blob8: target2
|
|
18
|
+
* blob4: error blob9: operation
|
|
19
|
+
* blob5: category blob10: region
|
|
20
|
+
* double1: status double4: requestSize
|
|
21
|
+
* double2: duration double5: responseSize
|
|
22
|
+
* double3: timestamp double6: resultCount
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// ─── Types ───
|
|
26
|
+
|
|
27
|
+
export interface LogEntry {
|
|
28
|
+
// Core fields (original)
|
|
29
|
+
method: string;
|
|
30
|
+
path: string;
|
|
31
|
+
status: number;
|
|
32
|
+
duration: number;
|
|
33
|
+
userId?: string;
|
|
34
|
+
error?: string;
|
|
35
|
+
timestamp?: number;
|
|
36
|
+
// Route classification (from route-parser)
|
|
37
|
+
category?: string;
|
|
38
|
+
subcategory?: string;
|
|
39
|
+
target1?: string;
|
|
40
|
+
target2?: string;
|
|
41
|
+
operation?: string;
|
|
42
|
+
// Request context
|
|
43
|
+
region?: string;
|
|
44
|
+
requestSize?: number;
|
|
45
|
+
responseSize?: number;
|
|
46
|
+
resultCount?: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface QueryResult {
|
|
50
|
+
data: Record<string, unknown>[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface LogWriter {
|
|
54
|
+
write(entry: LogEntry): void;
|
|
55
|
+
query(sql: string): Promise<QueryResult>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isDurableObjectResetError(err: unknown): boolean {
|
|
59
|
+
return (
|
|
60
|
+
typeof err === 'object'
|
|
61
|
+
&& err !== null
|
|
62
|
+
&& 'durableObjectReset' in err
|
|
63
|
+
&& (err as { durableObjectReset?: unknown }).durableObjectReset === true
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ─── AnalyticsEngineWriter (Cloud) ───
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Log writer using Cloudflare Analytics Engine.
|
|
71
|
+
* Non-blocking fire-and-forget write. 10 blobs + 6 doubles per data point.
|
|
72
|
+
* SQL API queries are proxied via admin endpoint (requires CF account credentials).
|
|
73
|
+
*/
|
|
74
|
+
export class AnalyticsEngineWriter implements LogWriter {
|
|
75
|
+
constructor(private analytics: AnalyticsEngineDataset) {}
|
|
76
|
+
|
|
77
|
+
write(entry: LogEntry): void {
|
|
78
|
+
this.analytics.writeDataPoint({
|
|
79
|
+
indexes: [entry.userId || 'anonymous'],
|
|
80
|
+
blobs: [
|
|
81
|
+
entry.method, // blob1
|
|
82
|
+
entry.path, // blob2
|
|
83
|
+
String(entry.status), // blob3
|
|
84
|
+
entry.error || '', // blob4
|
|
85
|
+
entry.category || '', // blob5
|
|
86
|
+
entry.subcategory || '', // blob6
|
|
87
|
+
entry.target1 || '', // blob7
|
|
88
|
+
entry.target2 || '', // blob8
|
|
89
|
+
entry.operation || '', // blob9
|
|
90
|
+
entry.region || '', // blob10
|
|
91
|
+
],
|
|
92
|
+
doubles: [
|
|
93
|
+
entry.status, // double1
|
|
94
|
+
entry.duration, // double2
|
|
95
|
+
entry.timestamp || Date.now(), // double3
|
|
96
|
+
entry.requestSize || 0, // double4
|
|
97
|
+
entry.responseSize || 0, // double5
|
|
98
|
+
entry.resultCount || 0, // double6
|
|
99
|
+
],
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async query(_sql: string): Promise<QueryResult> {
|
|
104
|
+
// Analytics Engine SQL API requires account-level credentials
|
|
105
|
+
// and is called via the Cloudflare REST API, not from Workers.
|
|
106
|
+
// Admin endpoint /admin/api/data/analytics proxies these queries.
|
|
107
|
+
return { data: [] };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ─── SQLiteLogWriter (Docker / Self-hosted) ───
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Log writer that buffers entries and flushes to LogsDO in batches.
|
|
115
|
+
* LogsDO stores logs in SQLite with 3-tier pre-aggregation:
|
|
116
|
+
* _logs_raw (24h) → _logs_hourly (90d) → _logs_daily (permanent)
|
|
117
|
+
*
|
|
118
|
+
* Buffering: flushes at 50 entries or after 100ms, whichever comes first.
|
|
119
|
+
* Uses ExecutionContext.waitUntil() for non-blocking writes.
|
|
120
|
+
*
|
|
121
|
+
* Retry policy: failed batches are re-queued once (retried = true).
|
|
122
|
+
* If a retried batch fails again, entries fall back to console.
|
|
123
|
+
* Buffer is capped at 1000 entries to prevent memory exhaustion.
|
|
124
|
+
*/
|
|
125
|
+
export class SQLiteLogWriter implements LogWriter {
|
|
126
|
+
private static readonly MAX_BUFFER = 1000;
|
|
127
|
+
private buffer: (LogEntry & { _retried?: boolean })[] = [];
|
|
128
|
+
private flushScheduled = false;
|
|
129
|
+
|
|
130
|
+
constructor(
|
|
131
|
+
private logsDO: { fetch: (input: RequestInfo) => Promise<Response> },
|
|
132
|
+
private ctx?: { waitUntil: (promise: Promise<unknown>) => void },
|
|
133
|
+
) {}
|
|
134
|
+
|
|
135
|
+
write(entry: LogEntry): void {
|
|
136
|
+
if (this.buffer.length >= SQLiteLogWriter.MAX_BUFFER) {
|
|
137
|
+
// Drop oldest to prevent memory exhaustion
|
|
138
|
+
this.buffer.shift();
|
|
139
|
+
}
|
|
140
|
+
this.buffer.push(entry);
|
|
141
|
+
|
|
142
|
+
if (this.buffer.length >= 50) {
|
|
143
|
+
// Immediate flush when buffer is full
|
|
144
|
+
const promise = this.flush();
|
|
145
|
+
if (this.ctx) {
|
|
146
|
+
this.ctx.waitUntil(promise);
|
|
147
|
+
}
|
|
148
|
+
} else if (!this.flushScheduled) {
|
|
149
|
+
// Schedule delayed flush for batching
|
|
150
|
+
this.flushScheduled = true;
|
|
151
|
+
const promise = this.scheduledFlush();
|
|
152
|
+
if (this.ctx) {
|
|
153
|
+
this.ctx.waitUntil(promise);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private async scheduledFlush(): Promise<void> {
|
|
159
|
+
await new Promise(r => setTimeout(r, 100));
|
|
160
|
+
this.flushScheduled = false;
|
|
161
|
+
await this.flush();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private async flush(): Promise<void> {
|
|
165
|
+
if (!this.buffer.length) return;
|
|
166
|
+
const batch = [...this.buffer];
|
|
167
|
+
this.buffer = [];
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
await this.logsDO.fetch(
|
|
171
|
+
new Request('http://internal/internal/logs/write', {
|
|
172
|
+
method: 'POST',
|
|
173
|
+
headers: { 'Content-Type': 'application/json' },
|
|
174
|
+
body: JSON.stringify({ entries: batch }),
|
|
175
|
+
}),
|
|
176
|
+
);
|
|
177
|
+
} catch (err) {
|
|
178
|
+
// Split batch: re-queue entries that haven't been retried yet
|
|
179
|
+
const retryable = batch.filter(e => !e._retried);
|
|
180
|
+
const dropped = batch.filter(e => e._retried);
|
|
181
|
+
|
|
182
|
+
if (retryable.length) {
|
|
183
|
+
for (const e of retryable) e._retried = true;
|
|
184
|
+
// Re-queue at front, respecting buffer cap
|
|
185
|
+
const space = SQLiteLogWriter.MAX_BUFFER - this.buffer.length;
|
|
186
|
+
this.buffer.unshift(...retryable.slice(0, space));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (isDurableObjectResetError(err)) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (dropped.length) {
|
|
194
|
+
console.error(`[EdgeBase] Failed to write ${dropped.length} logs to LogsDO (retry exhausted):`, err);
|
|
195
|
+
for (const entry of dropped) {
|
|
196
|
+
console.log(`[LOG] ${entry.method} ${entry.path} ${entry.status} ${entry.duration}ms`);
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
console.warn(`[EdgeBase] LogsDO write failed, ${retryable.length} entries queued for retry:`, err);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async query(sql: string): Promise<QueryResult> {
|
|
205
|
+
try {
|
|
206
|
+
const params = new URLSearchParams({ sql });
|
|
207
|
+
const resp = await this.logsDO.fetch(
|
|
208
|
+
new Request(`http://internal/internal/logs/query?${params}`),
|
|
209
|
+
);
|
|
210
|
+
return (await resp.json()) as QueryResult;
|
|
211
|
+
} catch {
|
|
212
|
+
return { data: [] };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ─── ConsoleLogWriter (Dev fallback) ───
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Fallback log writer for local development.
|
|
221
|
+
* Outputs structured log lines to console. No persistence.
|
|
222
|
+
*/
|
|
223
|
+
export class ConsoleLogWriter implements LogWriter {
|
|
224
|
+
write(entry: LogEntry): void {
|
|
225
|
+
const ts = new Date(entry.timestamp || Date.now()).toISOString();
|
|
226
|
+
const cat = entry.category ? ` [${entry.category}]` : '';
|
|
227
|
+
const line = `[${ts}]${cat} ${entry.method} ${entry.path} ${entry.status} ${entry.duration}ms${entry.userId ? ` user=${entry.userId}` : ''}${entry.error ? ` error=${entry.error}` : ''}`;
|
|
228
|
+
if (entry.status >= 500) {
|
|
229
|
+
console.error(line);
|
|
230
|
+
} else if (entry.status >= 400) {
|
|
231
|
+
console.warn(line);
|
|
232
|
+
} else {
|
|
233
|
+
console.log(line);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async query(_sql: string): Promise<QueryResult> {
|
|
238
|
+
return { data: [] };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ─── Factory ───
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Create the appropriate LogWriter based on environment bindings.
|
|
246
|
+
*
|
|
247
|
+
* Priority:
|
|
248
|
+
* 1. env.ANALYTICS exists → AnalyticsEngineWriter (Cloud)
|
|
249
|
+
* 2. env.LOGS exists → SQLiteLogWriter (Docker / Self-hosted)
|
|
250
|
+
* 3. Otherwise → ConsoleLogWriter (dev fallback)
|
|
251
|
+
*/
|
|
252
|
+
export function createLogWriter(
|
|
253
|
+
env: Record<string, unknown>,
|
|
254
|
+
executionCtx?: { waitUntil: (promise: Promise<unknown>) => void },
|
|
255
|
+
): LogWriter {
|
|
256
|
+
// Cloud: Analytics Engine
|
|
257
|
+
const analytics = env.ANALYTICS as AnalyticsEngineDataset | undefined;
|
|
258
|
+
if (analytics) {
|
|
259
|
+
return new AnalyticsEngineWriter(analytics);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Docker / Self-hosted: LogsDO SQLite
|
|
263
|
+
const logsNs = env.LOGS as { idFromName: (name: string) => { toString: () => string }; get: (id: unknown) => { fetch: (input: RequestInfo) => Promise<Response> } } | undefined;
|
|
264
|
+
if (logsNs) {
|
|
265
|
+
const logsId = logsNs.idFromName('logs:main');
|
|
266
|
+
const logsDO = logsNs.get(logsId);
|
|
267
|
+
return new SQLiteLogWriter(logsDO, executionCtx);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Dev fallback
|
|
271
|
+
return new ConsoleLogWriter();
|
|
272
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { EdgeBaseError, type EdgeBaseConfig } from '@edge-base/shared';
|
|
2
|
+
import type { Env } from '../types.js';
|
|
3
|
+
import { callDO, getDbDoName, getD1BindingName, shouldRouteToD1 } from './do-router.js';
|
|
4
|
+
import { ensureD1Schema } from './d1-schema-init.js';
|
|
5
|
+
import { ensurePgSchema } from './postgres-schema-init.js';
|
|
6
|
+
import {
|
|
7
|
+
ensureLocalDevPostgresSchema,
|
|
8
|
+
getLocalDevPostgresExecOptions,
|
|
9
|
+
getProviderBindingName,
|
|
10
|
+
withPostgresConnection,
|
|
11
|
+
} from './postgres-executor.js';
|
|
12
|
+
|
|
13
|
+
interface DumpNamespaceTablesOptions {
|
|
14
|
+
includeMeta?: boolean;
|
|
15
|
+
tableNames?: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function dumpNamespaceTables(
|
|
19
|
+
env: Env,
|
|
20
|
+
config: EdgeBaseConfig,
|
|
21
|
+
namespace: string,
|
|
22
|
+
options: DumpNamespaceTablesOptions = {},
|
|
23
|
+
): Promise<Record<string, unknown[]>> {
|
|
24
|
+
const dbBlock = config.databases?.[namespace];
|
|
25
|
+
if (!dbBlock) {
|
|
26
|
+
throw new EdgeBaseError(404, `Namespace '${namespace}' not found in config.`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const tableNames = options.tableNames?.length
|
|
30
|
+
? options.tableNames
|
|
31
|
+
: Object.keys(dbBlock.tables ?? {});
|
|
32
|
+
const tables: Record<string, unknown[]> = {};
|
|
33
|
+
const includeMeta = options.includeMeta !== false;
|
|
34
|
+
|
|
35
|
+
if (dbBlock.provider === 'neon' || dbBlock.provider === 'postgres') {
|
|
36
|
+
const bindingName = getProviderBindingName(namespace);
|
|
37
|
+
const envRecord = env as unknown as Record<string, unknown>;
|
|
38
|
+
const hyperdrive = envRecord[bindingName] as { connectionString?: string } | undefined;
|
|
39
|
+
const envKey = dbBlock.connectionString ?? `${bindingName}_URL`;
|
|
40
|
+
const connStr = hyperdrive?.connectionString ?? (envRecord[envKey] as string | undefined);
|
|
41
|
+
if (!connStr) {
|
|
42
|
+
throw new EdgeBaseError(500, `PostgreSQL connection not available for '${namespace}'.`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const localDevOptions = getLocalDevPostgresExecOptions(env as unknown as Record<string, unknown>, namespace);
|
|
46
|
+
if (localDevOptions) {
|
|
47
|
+
await ensureLocalDevPostgresSchema(localDevOptions);
|
|
48
|
+
}
|
|
49
|
+
await withPostgresConnection(connStr, async (query) => {
|
|
50
|
+
if (!localDevOptions) {
|
|
51
|
+
await ensurePgSchema(connStr, namespace, dbBlock.tables ?? {}, query);
|
|
52
|
+
}
|
|
53
|
+
for (const tableName of tableNames) {
|
|
54
|
+
try {
|
|
55
|
+
const result = await query(`SELECT * FROM "${tableName}"`, []);
|
|
56
|
+
tables[tableName] = result.rows;
|
|
57
|
+
} catch {
|
|
58
|
+
tables[tableName] = [];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (includeMeta) {
|
|
63
|
+
try {
|
|
64
|
+
const meta = await query('SELECT * FROM "_meta"', []);
|
|
65
|
+
tables['_meta'] = meta.rows;
|
|
66
|
+
} catch {
|
|
67
|
+
tables['_meta'] = [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}, localDevOptions);
|
|
71
|
+
|
|
72
|
+
return tables;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (shouldRouteToD1(namespace, config)) {
|
|
76
|
+
const bindingName = getD1BindingName(namespace);
|
|
77
|
+
const db = (env as unknown as Record<string, unknown>)[bindingName] as D1Database | undefined;
|
|
78
|
+
if (!db) {
|
|
79
|
+
throw new EdgeBaseError(500, `D1 binding '${bindingName}' not available for '${namespace}'.`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
await ensureD1Schema(db, namespace, dbBlock.tables ?? {});
|
|
83
|
+
for (const tableName of tableNames) {
|
|
84
|
+
try {
|
|
85
|
+
const result = await db.prepare(`SELECT * FROM "${tableName}"`).all();
|
|
86
|
+
tables[tableName] = result.results ?? [];
|
|
87
|
+
} catch {
|
|
88
|
+
tables[tableName] = [];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (includeMeta) {
|
|
93
|
+
try {
|
|
94
|
+
const meta = await db.prepare('SELECT * FROM "_meta"').all();
|
|
95
|
+
tables['_meta'] = meta.results ?? [];
|
|
96
|
+
} catch {
|
|
97
|
+
tables['_meta'] = [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return tables;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const doName = getDbDoName(namespace);
|
|
105
|
+
const response = await callDO(env.DATABASE, doName, '/internal/backup/dump', {
|
|
106
|
+
headers: { 'X-DO-Name': doName },
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
throw new EdgeBaseError(response.status as 500, `Namespace dump failed: ${await response.text()}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const payload = (await response.json()) as {
|
|
114
|
+
tables?: Record<string, Array<Record<string, unknown>>>;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
for (const tableName of tableNames) {
|
|
118
|
+
tables[tableName] = payload.tables?.[tableName] ?? [];
|
|
119
|
+
}
|
|
120
|
+
if (includeMeta) {
|
|
121
|
+
tables['_meta'] = payload.tables?._meta ?? [];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return tables;
|
|
125
|
+
}
|