@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,251 @@
|
|
|
1
|
+
import type { Env } from '../types.js';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_CLOUDFLARE_REALTIME_BASE_URL = 'https://rtc.live.cloudflare.com/v1';
|
|
4
|
+
|
|
5
|
+
export interface CloudflareRealtimeSessionDescription {
|
|
6
|
+
sdp: string;
|
|
7
|
+
type: 'offer' | 'answer';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface CloudflareRealtimeTrackObject {
|
|
11
|
+
location: 'local' | 'remote';
|
|
12
|
+
mid?: string;
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
trackName?: string;
|
|
15
|
+
bidirectionalMediaStream?: boolean;
|
|
16
|
+
kind?: string;
|
|
17
|
+
simulcast?: {
|
|
18
|
+
preferredRid?: string;
|
|
19
|
+
priorityOrdering?: 'none' | 'asciibetical';
|
|
20
|
+
ridNotAvailable?: 'none' | 'asciibetical';
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CloudflareRealtimeNewSessionRequest {
|
|
25
|
+
sessionDescription?: CloudflareRealtimeSessionDescription;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface CloudflareRealtimeNewSessionResponse {
|
|
29
|
+
errorCode?: string;
|
|
30
|
+
errorDescription?: string;
|
|
31
|
+
sessionDescription?: CloudflareRealtimeSessionDescription;
|
|
32
|
+
sessionId: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface CloudflareRealtimeTracksRequest {
|
|
36
|
+
sessionDescription?: CloudflareRealtimeSessionDescription;
|
|
37
|
+
tracks: CloudflareRealtimeTrackObject[];
|
|
38
|
+
autoDiscover?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface CloudflareRealtimeTracksResponse {
|
|
42
|
+
errorCode?: string;
|
|
43
|
+
errorDescription?: string;
|
|
44
|
+
requiresImmediateRenegotiation?: boolean;
|
|
45
|
+
sessionDescription?: CloudflareRealtimeSessionDescription;
|
|
46
|
+
tracks?: Array<CloudflareRealtimeTrackObject & {
|
|
47
|
+
errorCode?: string;
|
|
48
|
+
errorDescription?: string;
|
|
49
|
+
}>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface CloudflareRealtimeRenegotiateRequest {
|
|
53
|
+
sessionDescription: CloudflareRealtimeSessionDescription;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface CloudflareRealtimeCloseTracksRequest {
|
|
57
|
+
sessionDescription?: CloudflareRealtimeSessionDescription;
|
|
58
|
+
tracks: Array<{ mid: string }>;
|
|
59
|
+
force?: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface CloudflareRealtimeIceServer {
|
|
63
|
+
urls: string[] | string;
|
|
64
|
+
username?: string;
|
|
65
|
+
credential?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface CloudflareRealtimeIceServersResponse {
|
|
69
|
+
iceServers: CloudflareRealtimeIceServer[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface CloudflareRealtimeEnv {
|
|
73
|
+
CF_REALTIME_APP_ID?: string;
|
|
74
|
+
CF_REALTIME_APP_SECRET?: string;
|
|
75
|
+
CF_REALTIME_BASE_URL?: string;
|
|
76
|
+
CF_REALTIME_TURN_KEY_ID?: string;
|
|
77
|
+
CF_REALTIME_TURN_API_TOKEN?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function trimString(value: unknown): string | undefined {
|
|
81
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function parseRealtimeResponse<T>(response: Response): Promise<T> {
|
|
85
|
+
const data = (await response.json().catch(() => ({}))) as Record<string, unknown>;
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
const message =
|
|
88
|
+
(typeof data.errorDescription === 'string' && data.errorDescription)
|
|
89
|
+
|| (typeof data.message === 'string' && data.message)
|
|
90
|
+
|| `Cloudflare Realtime request failed (${response.status})`;
|
|
91
|
+
throw new Error(message);
|
|
92
|
+
}
|
|
93
|
+
return data as T;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function hasCloudflareRealtimeConfig(env: CloudflareRealtimeEnv): boolean {
|
|
97
|
+
return !!trimString(env.CF_REALTIME_APP_ID) && !!trimString(env.CF_REALTIME_APP_SECRET);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function assertCloudflareRealtimeConfig(env: CloudflareRealtimeEnv): {
|
|
101
|
+
appId: string;
|
|
102
|
+
appSecret: string;
|
|
103
|
+
baseUrl: string;
|
|
104
|
+
turnKeyId?: string;
|
|
105
|
+
turnApiToken?: string;
|
|
106
|
+
} {
|
|
107
|
+
const appId = trimString(env.CF_REALTIME_APP_ID);
|
|
108
|
+
const appSecret = trimString(env.CF_REALTIME_APP_SECRET);
|
|
109
|
+
if (!appId || !appSecret) {
|
|
110
|
+
throw new Error('Cloudflare Realtime is not configured. Set CF_REALTIME_APP_ID and CF_REALTIME_APP_SECRET.');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
appId,
|
|
115
|
+
appSecret,
|
|
116
|
+
baseUrl: trimString(env.CF_REALTIME_BASE_URL) ?? DEFAULT_CLOUDFLARE_REALTIME_BASE_URL,
|
|
117
|
+
turnKeyId: trimString(env.CF_REALTIME_TURN_KEY_ID),
|
|
118
|
+
turnApiToken: trimString(env.CF_REALTIME_TURN_API_TOKEN),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export class CloudflareRealtimeClient {
|
|
123
|
+
private readonly appId: string;
|
|
124
|
+
private readonly appSecret: string;
|
|
125
|
+
private readonly baseUrl: string;
|
|
126
|
+
private readonly turnKeyId?: string;
|
|
127
|
+
private readonly turnApiToken?: string;
|
|
128
|
+
|
|
129
|
+
constructor(env: CloudflareRealtimeEnv) {
|
|
130
|
+
const config = assertCloudflareRealtimeConfig(env);
|
|
131
|
+
this.appId = config.appId;
|
|
132
|
+
this.appSecret = config.appSecret;
|
|
133
|
+
this.baseUrl = config.baseUrl;
|
|
134
|
+
this.turnKeyId = config.turnKeyId;
|
|
135
|
+
this.turnApiToken = config.turnApiToken;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async createSession(
|
|
139
|
+
body: CloudflareRealtimeNewSessionRequest = {},
|
|
140
|
+
query?: { thirdparty?: boolean; correlationId?: string },
|
|
141
|
+
): Promise<CloudflareRealtimeNewSessionResponse> {
|
|
142
|
+
const url = this.buildSessionUrl('/sessions/new', query);
|
|
143
|
+
const response = await fetch(url, {
|
|
144
|
+
method: 'POST',
|
|
145
|
+
headers: this.buildAuthHeaders(),
|
|
146
|
+
body: JSON.stringify(body),
|
|
147
|
+
});
|
|
148
|
+
return parseRealtimeResponse<CloudflareRealtimeNewSessionResponse>(response);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async addTracks(
|
|
152
|
+
sessionId: string,
|
|
153
|
+
body: CloudflareRealtimeTracksRequest,
|
|
154
|
+
): Promise<CloudflareRealtimeTracksResponse> {
|
|
155
|
+
const response = await fetch(
|
|
156
|
+
this.buildSessionUrl(`/sessions/${encodeURIComponent(sessionId)}/tracks/new`),
|
|
157
|
+
{
|
|
158
|
+
method: 'POST',
|
|
159
|
+
headers: this.buildAuthHeaders(),
|
|
160
|
+
body: JSON.stringify(body),
|
|
161
|
+
},
|
|
162
|
+
);
|
|
163
|
+
return parseRealtimeResponse<CloudflareRealtimeTracksResponse>(response);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async renegotiate(
|
|
167
|
+
sessionId: string,
|
|
168
|
+
body: CloudflareRealtimeRenegotiateRequest,
|
|
169
|
+
): Promise<CloudflareRealtimeTracksResponse> {
|
|
170
|
+
const response = await fetch(
|
|
171
|
+
this.buildSessionUrl(`/sessions/${encodeURIComponent(sessionId)}/renegotiate`),
|
|
172
|
+
{
|
|
173
|
+
method: 'PUT',
|
|
174
|
+
headers: this.buildAuthHeaders(),
|
|
175
|
+
body: JSON.stringify(body),
|
|
176
|
+
},
|
|
177
|
+
);
|
|
178
|
+
return parseRealtimeResponse<CloudflareRealtimeTracksResponse>(response);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async closeTracks(
|
|
182
|
+
sessionId: string,
|
|
183
|
+
body: CloudflareRealtimeCloseTracksRequest,
|
|
184
|
+
): Promise<CloudflareRealtimeTracksResponse> {
|
|
185
|
+
const response = await fetch(
|
|
186
|
+
this.buildSessionUrl(`/sessions/${encodeURIComponent(sessionId)}/tracks/close`),
|
|
187
|
+
{
|
|
188
|
+
method: 'PUT',
|
|
189
|
+
headers: this.buildAuthHeaders(),
|
|
190
|
+
body: JSON.stringify(body),
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
return parseRealtimeResponse<CloudflareRealtimeTracksResponse>(response);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async getSession(sessionId: string): Promise<{
|
|
197
|
+
tracks?: Array<CloudflareRealtimeTrackObject & { status?: string }>;
|
|
198
|
+
}> {
|
|
199
|
+
const response = await fetch(
|
|
200
|
+
this.buildSessionUrl(`/sessions/${encodeURIComponent(sessionId)}`),
|
|
201
|
+
{
|
|
202
|
+
method: 'GET',
|
|
203
|
+
headers: this.buildAuthHeaders(),
|
|
204
|
+
},
|
|
205
|
+
);
|
|
206
|
+
return parseRealtimeResponse<{ tracks?: Array<CloudflareRealtimeTrackObject & { status?: string }> }>(response);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async generateIceServers(ttl = 3600): Promise<CloudflareRealtimeIceServersResponse> {
|
|
210
|
+
if (!this.turnKeyId || !this.turnApiToken) {
|
|
211
|
+
throw new Error('Cloudflare TURN is not configured. Set CF_REALTIME_TURN_KEY_ID and CF_REALTIME_TURN_API_TOKEN.');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const response = await fetch(
|
|
215
|
+
`${this.baseUrl.replace(/\/$/, '')}/turn/keys/${encodeURIComponent(this.turnKeyId)}/credentials/generate-ice-servers`,
|
|
216
|
+
{
|
|
217
|
+
method: 'POST',
|
|
218
|
+
headers: {
|
|
219
|
+
Authorization: `Bearer ${this.turnApiToken}`,
|
|
220
|
+
'Content-Type': 'application/json',
|
|
221
|
+
},
|
|
222
|
+
body: JSON.stringify({ ttl }),
|
|
223
|
+
},
|
|
224
|
+
);
|
|
225
|
+
return parseRealtimeResponse<CloudflareRealtimeIceServersResponse>(response);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private buildSessionUrl(pathname: string, query?: { thirdparty?: boolean; correlationId?: string }): string {
|
|
229
|
+
const url = new URL(
|
|
230
|
+
`${this.baseUrl.replace(/\/$/, '')}/apps/${encodeURIComponent(this.appId)}${pathname}`,
|
|
231
|
+
);
|
|
232
|
+
if (query?.thirdparty !== undefined) {
|
|
233
|
+
url.searchParams.set('thirdparty', String(query.thirdparty));
|
|
234
|
+
}
|
|
235
|
+
if (query?.correlationId) {
|
|
236
|
+
url.searchParams.set('correlationId', query.correlationId);
|
|
237
|
+
}
|
|
238
|
+
return url.toString();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private buildAuthHeaders(): HeadersInit {
|
|
242
|
+
return {
|
|
243
|
+
Authorization: `Bearer ${this.appSecret}`,
|
|
244
|
+
'Content-Type': 'application/json',
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function createCloudflareRealtimeClient(env: Env): CloudflareRealtimeClient {
|
|
250
|
+
return new CloudflareRealtimeClient(env);
|
|
251
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AuthDb } from './auth-db-adapter.js';
|
|
2
|
+
import { D1AuthDb } from './auth-db-adapter.js';
|
|
3
|
+
|
|
4
|
+
export type ControlDb = AuthDb;
|
|
5
|
+
|
|
6
|
+
export const CONTROL_D1_SCHEMA = `
|
|
7
|
+
CREATE TABLE IF NOT EXISTS _meta (
|
|
8
|
+
key TEXT PRIMARY KEY,
|
|
9
|
+
value TEXT NOT NULL
|
|
10
|
+
);
|
|
11
|
+
`;
|
|
12
|
+
|
|
13
|
+
let controlSchemaInitialized = false;
|
|
14
|
+
|
|
15
|
+
export async function ensureControlSchema(db: ControlDb): Promise<void> {
|
|
16
|
+
if (controlSchemaInitialized) return;
|
|
17
|
+
|
|
18
|
+
const statements = CONTROL_D1_SCHEMA.split(/;\s*\n/)
|
|
19
|
+
.map((statement) => statement.trim())
|
|
20
|
+
.filter((statement) => statement.length > 0);
|
|
21
|
+
|
|
22
|
+
await db.batch(statements.map((sql) => ({ sql })));
|
|
23
|
+
controlSchemaInitialized = true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function resetControlSchemaInit(): void {
|
|
27
|
+
controlSchemaInitialized = false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function resolveControlDb(env: Record<string, unknown>): ControlDb {
|
|
31
|
+
const d1 = env.CONTROL_DB as D1Database | undefined;
|
|
32
|
+
if (!d1) {
|
|
33
|
+
throw new Error('CONTROL_DB D1 binding is not available in the environment.');
|
|
34
|
+
}
|
|
35
|
+
return new D1AuthDb(d1);
|
|
36
|
+
}
|
package/src/lib/cron.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron expression parser and next-fire-time calculator.
|
|
3
|
+
*
|
|
4
|
+
* Supports standard 5-field cron: minute hour dayOfMonth month dayOfWeek
|
|
5
|
+
* Examples:
|
|
6
|
+
* '0 9 * * *' - every day at 09:00
|
|
7
|
+
* '* /5 * * * *' - every 5 minutes
|
|
8
|
+
* '30 2 * * 1' - every Monday at 02:30
|
|
9
|
+
* '0 0 1 * *' - first day of every month at midnight
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// ─── Types ───
|
|
13
|
+
|
|
14
|
+
export interface CronSchedule {
|
|
15
|
+
minutes: Set<number>;
|
|
16
|
+
hours: Set<number>;
|
|
17
|
+
daysOfMonth: Set<number>;
|
|
18
|
+
months: Set<number>;
|
|
19
|
+
daysOfWeek: Set<number>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ParsedScheduleFunction {
|
|
23
|
+
name: string;
|
|
24
|
+
cron: string;
|
|
25
|
+
schedule: CronSchedule;
|
|
26
|
+
lastRunAt?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ─── Parser ───
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Parse a cron field into a Set of matching values.
|
|
33
|
+
* Supports: *, N, N-M, N/step, star/step, N-M/step, lists (comma-separated).
|
|
34
|
+
*/
|
|
35
|
+
export function parseCronField(field: string, min: number, max: number): Set<number> {
|
|
36
|
+
const values = new Set<number>();
|
|
37
|
+
|
|
38
|
+
for (const part of field.split(',')) {
|
|
39
|
+
const trimmed = part.trim();
|
|
40
|
+
|
|
41
|
+
if (trimmed === '*') {
|
|
42
|
+
for (let i = min; i <= max; i++) values.add(i);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// */step
|
|
47
|
+
const stepMatch = trimmed.match(/^(\*|(\d+)-(\d+))\/(\d+)$/);
|
|
48
|
+
if (stepMatch) {
|
|
49
|
+
const step = parseInt(stepMatch[4], 10);
|
|
50
|
+
if (step <= 0) throw new Error(`Invalid cron step: ${step}`);
|
|
51
|
+
let start = min;
|
|
52
|
+
let end = max;
|
|
53
|
+
if (stepMatch[2] !== undefined && stepMatch[3] !== undefined) {
|
|
54
|
+
start = parseInt(stepMatch[2], 10);
|
|
55
|
+
end = parseInt(stepMatch[3], 10);
|
|
56
|
+
}
|
|
57
|
+
for (let i = start; i <= end; i += step) values.add(i);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// N-M range
|
|
62
|
+
const rangeMatch = trimmed.match(/^(\d+)-(\d+)$/);
|
|
63
|
+
if (rangeMatch) {
|
|
64
|
+
const start = parseInt(rangeMatch[1], 10);
|
|
65
|
+
const end = parseInt(rangeMatch[2], 10);
|
|
66
|
+
for (let i = start; i <= end; i++) values.add(i);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Single value
|
|
71
|
+
const num = parseInt(trimmed, 10);
|
|
72
|
+
if (isNaN(num) || num < min || num > max) {
|
|
73
|
+
throw new Error(`Invalid cron value '${trimmed}' (${min}-${max})`);
|
|
74
|
+
}
|
|
75
|
+
values.add(num);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return values;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Parse a 5-field cron expression.
|
|
83
|
+
*/
|
|
84
|
+
export function parseCron(expression: string): CronSchedule {
|
|
85
|
+
const fields = expression.trim().split(/\s+/);
|
|
86
|
+
if (fields.length !== 5) {
|
|
87
|
+
throw new Error(`Invalid cron expression: expected 5 fields, got ${fields.length}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
minutes: parseCronField(fields[0], 0, 59),
|
|
92
|
+
hours: parseCronField(fields[1], 0, 23),
|
|
93
|
+
daysOfMonth: parseCronField(fields[2], 1, 31),
|
|
94
|
+
months: parseCronField(fields[3], 1, 12),
|
|
95
|
+
daysOfWeek: parseCronField(fields[4], 0, 6), // 0=Sunday
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Check if a Date matches a cron schedule.
|
|
101
|
+
*/
|
|
102
|
+
export function matchesCron(date: Date, schedule: CronSchedule): boolean {
|
|
103
|
+
return (
|
|
104
|
+
schedule.minutes.has(date.getUTCMinutes()) &&
|
|
105
|
+
schedule.hours.has(date.getUTCHours()) &&
|
|
106
|
+
schedule.daysOfMonth.has(date.getUTCDate()) &&
|
|
107
|
+
schedule.months.has(date.getUTCMonth() + 1) &&
|
|
108
|
+
schedule.daysOfWeek.has(date.getUTCDay())
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ─── Next Fire Time ───
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Calculate the next fire time from a given date for a cron schedule.
|
|
116
|
+
* Scans forward minute-by-minute up to 366 days.
|
|
117
|
+
* Returns timestamp in milliseconds.
|
|
118
|
+
*/
|
|
119
|
+
export function getNextFireTime(schedule: CronSchedule, from: Date): number {
|
|
120
|
+
// Start from the next minute
|
|
121
|
+
const next = new Date(from.getTime());
|
|
122
|
+
next.setUTCSeconds(0, 0);
|
|
123
|
+
next.setUTCMinutes(next.getUTCMinutes() + 1);
|
|
124
|
+
|
|
125
|
+
const maxIterations = 366 * 24 * 60; // 1 year of minutes
|
|
126
|
+
|
|
127
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
128
|
+
if (matchesCron(next, schedule)) {
|
|
129
|
+
return next.getTime();
|
|
130
|
+
}
|
|
131
|
+
next.setUTCMinutes(next.getUTCMinutes() + 1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
throw new Error('Could not find next fire time within 366 days');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ─── Alarm Multiplexer ───
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Given multiple schedule functions, find the earliest next fire time.
|
|
141
|
+
* Returns the timestamp and the list of functions that fire at that time.
|
|
142
|
+
*/
|
|
143
|
+
export function getNextAlarm(
|
|
144
|
+
schedules: ParsedScheduleFunction[],
|
|
145
|
+
from: Date,
|
|
146
|
+
): { time: number; functions: string[] } | null {
|
|
147
|
+
if (schedules.length === 0) return null;
|
|
148
|
+
|
|
149
|
+
let earliestTime = Infinity;
|
|
150
|
+
let functions: string[] = [];
|
|
151
|
+
|
|
152
|
+
for (const sched of schedules) {
|
|
153
|
+
const nextTime = getNextFireTime(sched.schedule, from);
|
|
154
|
+
if (nextTime < earliestTime) {
|
|
155
|
+
earliestTime = nextTime;
|
|
156
|
+
functions = [sched.name];
|
|
157
|
+
} else if (nextTime === earliestTime) {
|
|
158
|
+
functions.push(sched.name);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return earliestTime === Infinity ? null : { time: earliestTime, functions };
|
|
163
|
+
}
|