@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,21 @@
|
|
|
1
|
+
import type { Env } from '../types.js';
|
|
2
|
+
import { ensureAuthSchema } from '../lib/auth-d1.js';
|
|
3
|
+
import { resolveAuthDb, type AuthDb } from '../lib/auth-db-adapter.js';
|
|
4
|
+
import { getPublicProfileWithCache as getCachedPublicProfile } from '../lib/public-user-profile.js';
|
|
5
|
+
|
|
6
|
+
function getAuthDbFromEnv(env: unknown): AuthDb {
|
|
7
|
+
return resolveAuthDb(env as Record<string, unknown>);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function getPublicProfileWithCache(
|
|
11
|
+
userId: string,
|
|
12
|
+
env: Env,
|
|
13
|
+
executionCtx: ExecutionContext,
|
|
14
|
+
): Promise<Record<string, unknown> | null> {
|
|
15
|
+
const authDb = getAuthDbFromEnv(env as unknown as Record<string, unknown>);
|
|
16
|
+
await ensureAuthSchema(authDb);
|
|
17
|
+
return getCachedPublicProfile(authDb, userId, {
|
|
18
|
+
executionCtx,
|
|
19
|
+
kv: env.KV,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vectorize route — POST /api/vectorize/:index
|
|
3
|
+
*
|
|
4
|
+
* Allows server SDK (with Service Key) to access user-defined Vectorize indexes.
|
|
5
|
+
* NOT available to client SDK (server-only,).
|
|
6
|
+
*
|
|
7
|
+
* Supported actions:
|
|
8
|
+
* upsert — Insert or replace vectors (write)
|
|
9
|
+
* insert — Insert vectors, error on duplicate ID (write)
|
|
10
|
+
* search — Similarity search by vector values (query)
|
|
11
|
+
* queryById — Similarity search using an existing vector's ID (query, Vectorize v2 only)
|
|
12
|
+
* getByIds — Retrieve vectors by ID (query)
|
|
13
|
+
* delete — Remove vectors by ID (write)
|
|
14
|
+
* describe — Get index info: vectorCount, dimensions, metric (query)
|
|
15
|
+
*
|
|
16
|
+
* Security:
|
|
17
|
+
* - Config Allowlist: index must be declared in config.vectorize
|
|
18
|
+
* - Service Key required with scoped validation
|
|
19
|
+
*
|
|
20
|
+
* Note: Vectorize is Cloudflare Edge-only. In local/Docker (Miniflare), the binding
|
|
21
|
+
* will not exist — the route returns a stub response with a warning.
|
|
22
|
+
*
|
|
23
|
+
* Flow: Server SDK → POST /api/vectorize/:index → Worker → Vectorize binding → JSON
|
|
24
|
+
*/
|
|
25
|
+
import { OpenAPIHono, createRoute, z, type HonoEnv } from '../lib/hono.js';
|
|
26
|
+
import { parseConfig } from '../lib/do-router.js';
|
|
27
|
+
import { validateKey, buildConstraintCtx } from '../lib/service-key.js';
|
|
28
|
+
import { zodDefaultHook, vectorizeBodySchema, jsonResponseSchema, errorResponseSchema } from '../lib/schemas.js';
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const VALID_ACTIONS = ['upsert', 'insert', 'search', 'queryById', 'getByIds', 'delete', 'describe'] as const;
|
|
32
|
+
type Action = typeof VALID_ACTIONS[number];
|
|
33
|
+
|
|
34
|
+
const READ_ACTIONS: Action[] = ['search', 'getByIds', 'queryById', 'describe'];
|
|
35
|
+
|
|
36
|
+
const STUB_WARNING = 'Vectorize not available in this environment';
|
|
37
|
+
const VECTOR_BATCH_LIMIT = 20;
|
|
38
|
+
|
|
39
|
+
export const vectorizeRoute = new OpenAPIHono<HonoEnv>({ defaultHook: zodDefaultHook });
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* POST /api/vectorize/:index
|
|
43
|
+
* Body: { action, vectors?, vector?, vectorId?, topK?, filter?, ids?, namespace?, returnValues?, returnMetadata? }
|
|
44
|
+
*/
|
|
45
|
+
const vectorizeOperation = createRoute({
|
|
46
|
+
operationId: 'vectorizeOperation',
|
|
47
|
+
method: 'post',
|
|
48
|
+
path: '/{index}',
|
|
49
|
+
tags: ['admin'],
|
|
50
|
+
summary: 'Execute Vectorize operation',
|
|
51
|
+
request: {
|
|
52
|
+
params: z.object({ index: z.string() }),
|
|
53
|
+
body: { content: { 'application/json': { schema: vectorizeBodySchema } }, required: true },
|
|
54
|
+
},
|
|
55
|
+
responses: {
|
|
56
|
+
200: { description: 'Operation result', content: { 'application/json': { schema: jsonResponseSchema } } },
|
|
57
|
+
400: { description: 'Bad request', content: { 'application/json': { schema: errorResponseSchema } } },
|
|
58
|
+
401: { description: 'Unauthorized', content: { 'application/json': { schema: errorResponseSchema } } },
|
|
59
|
+
403: { description: 'Forbidden', content: { 'application/json': { schema: errorResponseSchema } } },
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
vectorizeRoute.openapi(vectorizeOperation, async (c) => {
|
|
64
|
+
const nameParam = c.req.param('index')!;
|
|
65
|
+
|
|
66
|
+
let body: {
|
|
67
|
+
action?: string;
|
|
68
|
+
vectors?: Array<{ id: string; values: number[]; metadata?: Record<string, unknown>; namespace?: string }>;
|
|
69
|
+
vector?: number[];
|
|
70
|
+
vectorId?: string;
|
|
71
|
+
topK?: number;
|
|
72
|
+
filter?: Record<string, unknown>;
|
|
73
|
+
ids?: string[];
|
|
74
|
+
namespace?: string;
|
|
75
|
+
returnValues?: boolean;
|
|
76
|
+
returnMetadata?: boolean | 'all' | 'indexed' | 'none';
|
|
77
|
+
};
|
|
78
|
+
try {
|
|
79
|
+
body = await c.req.json();
|
|
80
|
+
} catch {
|
|
81
|
+
return c.json({ code: 400, message: 'Invalid JSON body' }, 400);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const { action } = body;
|
|
85
|
+
if (!action || !(VALID_ACTIONS as readonly string[]).includes(action)) {
|
|
86
|
+
return c.json({ code: 400, message: `action must be one of: ${VALID_ACTIONS.join(', ')}` }, 400);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// §2 Allowlist: validate index is declared in config
|
|
90
|
+
const config = parseConfig(c.env);
|
|
91
|
+
const vectorConfig = config.vectorize?.[nameParam];
|
|
92
|
+
if (!vectorConfig) {
|
|
93
|
+
return c.json({ code: 404, message: `Vectorize index '${nameParam}' not found in config.` }, 404);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// §4 Scope mapping: read vs write
|
|
97
|
+
const scope = READ_ACTIONS.includes(action as Action)
|
|
98
|
+
? `vectorize:index:${nameParam}:query`
|
|
99
|
+
: `vectorize:index:${nameParam}:write`;
|
|
100
|
+
|
|
101
|
+
// Service Key validation
|
|
102
|
+
const { result: skResult } = validateKey(
|
|
103
|
+
c.req.header('X-EdgeBase-Service-Key'),
|
|
104
|
+
scope,
|
|
105
|
+
config,
|
|
106
|
+
c.env,
|
|
107
|
+
undefined,
|
|
108
|
+
buildConstraintCtx(c.env, c.req),
|
|
109
|
+
);
|
|
110
|
+
if (skResult === 'missing') {
|
|
111
|
+
return c.json({ code: 403, message: 'Service Key required to access Vectorize' }, 403);
|
|
112
|
+
}
|
|
113
|
+
if (skResult === 'invalid') {
|
|
114
|
+
return c.json({ code: 401, message: 'Unauthorized. Invalid Service Key.' }, 401);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ─── Input validation ─────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
if (action === 'upsert' || action === 'insert') {
|
|
120
|
+
if (!body.vectors || !Array.isArray(body.vectors) || body.vectors.length === 0) {
|
|
121
|
+
return c.json({ code: 400, message: 'vectors array is required and must not be empty for ' + action }, 400);
|
|
122
|
+
}
|
|
123
|
+
const invalidVector = body.vectors.find((vector) => !Array.isArray(vector.values) || vector.values.length !== vectorConfig.dimensions);
|
|
124
|
+
if (invalidVector) {
|
|
125
|
+
const actual = Array.isArray(invalidVector.values) ? invalidVector.values.length : 0;
|
|
126
|
+
return c.json({
|
|
127
|
+
code: 400,
|
|
128
|
+
message: `vector dimension mismatch: expected ${vectorConfig.dimensions}, got ${actual}`,
|
|
129
|
+
}, 400);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (action === 'delete' || action === 'getByIds') {
|
|
134
|
+
if (!body.ids || !Array.isArray(body.ids) || body.ids.length === 0) {
|
|
135
|
+
return c.json({ code: 400, message: 'ids array is required and must not be empty for ' + action }, 400);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (action === 'search' || action === 'queryById') {
|
|
140
|
+
const topK = body.topK ?? 10;
|
|
141
|
+
if (topK < 1 || topK > 100) {
|
|
142
|
+
return c.json({ code: 400, message: 'topK must be between 1 and 100' }, 400);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (action === 'search') {
|
|
147
|
+
if (!body.vector || !Array.isArray(body.vector)) {
|
|
148
|
+
return c.json({ code: 400, message: 'vector array is required for search' }, 400);
|
|
149
|
+
}
|
|
150
|
+
if (body.vector.length !== vectorConfig.dimensions) {
|
|
151
|
+
return c.json({ code: 400, message: `vector dimension mismatch: expected ${vectorConfig.dimensions}, got ${body.vector.length}` }, 400);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (action === 'queryById') {
|
|
156
|
+
if (!body.vectorId || typeof body.vectorId !== 'string') {
|
|
157
|
+
return c.json({ code: 400, message: 'vectorId string is required for queryById' }, 400);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ─── Binding access ───────────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
// §1 Env type — dynamic binding access via type assertion
|
|
164
|
+
// §7: Vectorize is Edge-only, Miniflare doesn't support it
|
|
165
|
+
const bindingName = vectorConfig.binding ?? `VECTORIZE_${nameParam.toUpperCase()}`;
|
|
166
|
+
const binding = (c.env as unknown as Record<string, unknown>)[bindingName] as VectorizeIndex | undefined;
|
|
167
|
+
if (!binding) {
|
|
168
|
+
console.warn(`⚠️ Vectorize binding '${bindingName}' for '${nameParam}' not available. Running locally or binding not configured.`);
|
|
169
|
+
// Return stub responses for local development
|
|
170
|
+
// Include both v1 (count) and v2 (mutationId) fields so code for either version works.
|
|
171
|
+
switch (action) {
|
|
172
|
+
case 'search':
|
|
173
|
+
return c.json({ matches: [], count: 0, _stub: true, _warning: STUB_WARNING });
|
|
174
|
+
case 'upsert':
|
|
175
|
+
return c.json({ ok: true, count: 0, mutationId: null, _stub: true, _warning: STUB_WARNING });
|
|
176
|
+
case 'insert':
|
|
177
|
+
return c.json({ ok: true, count: 0, mutationId: null, _stub: true, _warning: STUB_WARNING });
|
|
178
|
+
case 'delete':
|
|
179
|
+
return c.json({ ok: true, count: 0, mutationId: null, _stub: true, _warning: STUB_WARNING });
|
|
180
|
+
case 'getByIds':
|
|
181
|
+
return c.json({ vectors: [], _stub: true, _warning: STUB_WARNING });
|
|
182
|
+
case 'queryById':
|
|
183
|
+
return c.json({ matches: [], count: 0, _stub: true, _warning: STUB_WARNING });
|
|
184
|
+
case 'describe':
|
|
185
|
+
return c.json({
|
|
186
|
+
vectorCount: 0,
|
|
187
|
+
dimensions: vectorConfig.dimensions,
|
|
188
|
+
metric: vectorConfig.metric,
|
|
189
|
+
processedUpToDatetime: null,
|
|
190
|
+
processedUpToMutation: null,
|
|
191
|
+
_stub: true,
|
|
192
|
+
_warning: STUB_WARNING,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ─── Execute Vectorize operation ──────────────────────────────────────
|
|
198
|
+
|
|
199
|
+
switch (action) {
|
|
200
|
+
case 'upsert': {
|
|
201
|
+
const vectors = applyNamespace(body.vectors!, body.namespace) as VectorizeVector[];
|
|
202
|
+
let count = 0;
|
|
203
|
+
let mutationId: string | undefined;
|
|
204
|
+
for (const chunk of chunkArray(vectors, VECTOR_BATCH_LIMIT)) {
|
|
205
|
+
const result = await binding!.upsert(chunk);
|
|
206
|
+
count += 'count' in result ? result.count : chunk.length;
|
|
207
|
+
if ('mutationId' in result) {
|
|
208
|
+
mutationId = (result as { mutationId: string }).mutationId;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return c.json({
|
|
212
|
+
ok: true,
|
|
213
|
+
count,
|
|
214
|
+
...(mutationId ? { mutationId } : {}),
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
case 'insert': {
|
|
219
|
+
const vectors = applyNamespace(body.vectors!, body.namespace) as VectorizeVector[];
|
|
220
|
+
try {
|
|
221
|
+
let count = 0;
|
|
222
|
+
let mutationId: string | undefined;
|
|
223
|
+
for (const chunk of chunkArray(vectors, VECTOR_BATCH_LIMIT)) {
|
|
224
|
+
const result = await binding!.insert(chunk);
|
|
225
|
+
count += 'count' in result ? result.count : chunk.length;
|
|
226
|
+
if ('mutationId' in result) {
|
|
227
|
+
mutationId = (result as { mutationId: string }).mutationId;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return c.json({
|
|
231
|
+
ok: true,
|
|
232
|
+
count,
|
|
233
|
+
...(mutationId ? { mutationId } : {}),
|
|
234
|
+
});
|
|
235
|
+
} catch (err: unknown) {
|
|
236
|
+
// insert() throws on duplicate ID — surface as 409 Conflict
|
|
237
|
+
const message = err instanceof Error ? err.message : 'Insert failed — duplicate ID';
|
|
238
|
+
return c.json({ code: 409, message }, 409);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
case 'search': {
|
|
243
|
+
const queryOpts: VectorizeQueryOptions = {
|
|
244
|
+
topK: body.topK ?? 10,
|
|
245
|
+
filter: body.filter as VectorizeVectorMetadataFilter | undefined,
|
|
246
|
+
};
|
|
247
|
+
if (body.returnValues !== undefined) queryOpts.returnValues = body.returnValues;
|
|
248
|
+
if (body.returnMetadata !== undefined) queryOpts.returnMetadata = body.returnMetadata;
|
|
249
|
+
if (body.namespace) queryOpts.namespace = body.namespace;
|
|
250
|
+
|
|
251
|
+
const results = await binding!.query(body.vector!, queryOpts);
|
|
252
|
+
return c.json({
|
|
253
|
+
matches: mapMatches(results.matches),
|
|
254
|
+
count: results.count,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
case 'queryById': {
|
|
259
|
+
// queryById only exists on the new Vectorize class, not legacy VectorizeIndex
|
|
260
|
+
const asVectorize = binding as unknown as {
|
|
261
|
+
queryById?: (id: string, opts?: VectorizeQueryOptions) => Promise<VectorizeMatches>;
|
|
262
|
+
};
|
|
263
|
+
if (typeof asVectorize.queryById !== 'function') {
|
|
264
|
+
return c.json({
|
|
265
|
+
code: 501,
|
|
266
|
+
message: 'queryById is not available on this Vectorize binding (requires Vectorize v2)',
|
|
267
|
+
}, 501);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const queryOpts: VectorizeQueryOptions = {
|
|
271
|
+
topK: body.topK ?? 10,
|
|
272
|
+
filter: body.filter as VectorizeVectorMetadataFilter | undefined,
|
|
273
|
+
};
|
|
274
|
+
if (body.returnValues !== undefined) queryOpts.returnValues = body.returnValues;
|
|
275
|
+
if (body.returnMetadata !== undefined) queryOpts.returnMetadata = body.returnMetadata;
|
|
276
|
+
if (body.namespace) queryOpts.namespace = body.namespace;
|
|
277
|
+
|
|
278
|
+
const results = await asVectorize.queryById(body.vectorId!, queryOpts);
|
|
279
|
+
return c.json({
|
|
280
|
+
matches: mapMatches(results.matches),
|
|
281
|
+
count: results.count,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
case 'getByIds': {
|
|
286
|
+
const vectors = (
|
|
287
|
+
await Promise.all(chunkArray(body.ids!, VECTOR_BATCH_LIMIT).map((chunk) => binding!.getByIds(chunk)))
|
|
288
|
+
).flat();
|
|
289
|
+
return c.json({
|
|
290
|
+
vectors: vectors.map((v) => ({
|
|
291
|
+
id: v.id,
|
|
292
|
+
values: v.values instanceof Float32Array || v.values instanceof Float64Array
|
|
293
|
+
? Array.from(v.values)
|
|
294
|
+
: v.values,
|
|
295
|
+
...(v.metadata !== undefined && { metadata: v.metadata }),
|
|
296
|
+
...(v.namespace && { namespace: v.namespace }),
|
|
297
|
+
})),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
case 'delete': {
|
|
302
|
+
let count = 0;
|
|
303
|
+
let mutationId: string | undefined;
|
|
304
|
+
for (const chunk of chunkArray(body.ids!, VECTOR_BATCH_LIMIT)) {
|
|
305
|
+
const result = await binding!.deleteByIds(chunk);
|
|
306
|
+
count += 'count' in result ? result.count : chunk.length;
|
|
307
|
+
if ('mutationId' in result) {
|
|
308
|
+
mutationId = (result as { mutationId: string }).mutationId;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return c.json({
|
|
312
|
+
ok: true,
|
|
313
|
+
count,
|
|
314
|
+
...(mutationId ? { mutationId } : {}),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
case 'describe': {
|
|
319
|
+
const info = await binding!.describe();
|
|
320
|
+
// Handle both VectorizeIndexDetails (beta) and VectorizeIndexInfo (new)
|
|
321
|
+
const details = info as unknown as Record<string, unknown>;
|
|
322
|
+
return c.json({
|
|
323
|
+
vectorCount: details.vectorCount ?? details.vectorsCount ?? 0,
|
|
324
|
+
dimensions: details.dimensions ?? (details.config as Record<string, unknown>)?.dimensions ?? vectorConfig.dimensions,
|
|
325
|
+
metric: details.metric ?? (details.config as Record<string, unknown>)?.metric ?? vectorConfig.metric,
|
|
326
|
+
...('id' in details && { id: details.id }),
|
|
327
|
+
...('name' in details && { name: details.name }),
|
|
328
|
+
// v2 Vectorize: processedUpTo fields for mutation tracking
|
|
329
|
+
...('processedUpToDatetime' in details && { processedUpToDatetime: details.processedUpToDatetime }),
|
|
330
|
+
...('processedUpToMutation' in details && { processedUpToMutation: details.processedUpToMutation }),
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
default:
|
|
335
|
+
return c.json({ code: 400, message: 'Unknown action' }, 400);
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
340
|
+
|
|
341
|
+
/** Apply a default namespace to vectors that don't have one set. */
|
|
342
|
+
function applyNamespace(
|
|
343
|
+
vectors: Array<{ id: string; values: number[]; metadata?: Record<string, unknown>; namespace?: string }>,
|
|
344
|
+
defaultNs?: string,
|
|
345
|
+
): Array<{ id: string; values: number[]; metadata?: Record<string, unknown>; namespace?: string }> {
|
|
346
|
+
if (!defaultNs) return vectors;
|
|
347
|
+
return vectors.map((v) => (v.namespace ? v : { ...v, namespace: defaultNs }));
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function chunkArray<T>(items: T[], size: number): T[][] {
|
|
351
|
+
if (items.length === 0) return [];
|
|
352
|
+
const chunks: T[][] = [];
|
|
353
|
+
for (let index = 0; index < items.length; index += size) {
|
|
354
|
+
chunks.push(items.slice(index, index + size));
|
|
355
|
+
}
|
|
356
|
+
return chunks;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** Map VectorizeMatch to a clean JSON-safe response object. */
|
|
360
|
+
function mapMatches(matches: VectorizeMatch[]): Array<Record<string, unknown>> {
|
|
361
|
+
return matches.map((m) => ({
|
|
362
|
+
id: m.id,
|
|
363
|
+
score: m.score,
|
|
364
|
+
...(m.values !== undefined && {
|
|
365
|
+
values: m.values instanceof Float32Array || m.values instanceof Float64Array
|
|
366
|
+
? Array.from(m.values)
|
|
367
|
+
: m.values,
|
|
368
|
+
}),
|
|
369
|
+
...(m.metadata !== undefined && { metadata: m.metadata }),
|
|
370
|
+
...(m.namespace && { namespace: m.namespace }),
|
|
371
|
+
}));
|
|
372
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare Worker environment bindings.
|
|
3
|
+
* Each binding corresponds to a wrangler.toml entry.
|
|
4
|
+
*/
|
|
5
|
+
export interface Env {
|
|
6
|
+
// ─── Durable Objects ───
|
|
7
|
+
DATABASE: DurableObjectNamespace;
|
|
8
|
+
AUTH: DurableObjectNamespace;
|
|
9
|
+
DATABASE_LIVE: DurableObjectNamespace;
|
|
10
|
+
/** Room DO — per-room state synchronization, members, signals, media */
|
|
11
|
+
ROOMS: DurableObjectNamespace;
|
|
12
|
+
|
|
13
|
+
// ─── R2 Storage ───
|
|
14
|
+
STORAGE: R2Bucket;
|
|
15
|
+
|
|
16
|
+
// ─── KV (OAuth state, WebSocket pending) ───
|
|
17
|
+
KV: KVNamespace;
|
|
18
|
+
|
|
19
|
+
// ─── Rate Limiting Bindings ───
|
|
20
|
+
GLOBAL_RATE_LIMITER?: RateLimit;
|
|
21
|
+
DB_RATE_LIMITER?: RateLimit;
|
|
22
|
+
STORAGE_RATE_LIMITER?: RateLimit;
|
|
23
|
+
FUNCTIONS_RATE_LIMITER?: RateLimit;
|
|
24
|
+
AUTH_RATE_LIMITER?: RateLimit;
|
|
25
|
+
AUTH_SIGNIN_RATE_LIMITER?: RateLimit;
|
|
26
|
+
AUTH_SIGNUP_RATE_LIMITER?: RateLimit;
|
|
27
|
+
EVENTS_RATE_LIMITER?: RateLimit;
|
|
28
|
+
|
|
29
|
+
// ─── D1 (Internal Control Plane + Auth,) ───
|
|
30
|
+
AUTH_DB: D1Database;
|
|
31
|
+
CONTROL_DB: D1Database;
|
|
32
|
+
|
|
33
|
+
// ─── Analytics Engine ───
|
|
34
|
+
ANALYTICS?: AnalyticsEngineDataset;
|
|
35
|
+
|
|
36
|
+
// ─── Analytics Engine for App Functions ───
|
|
37
|
+
ANALYTICS_APP?: AnalyticsEngineDataset;
|
|
38
|
+
|
|
39
|
+
// ─── LogsDO (Analytics log storage for Docker/self-hosted,) ───
|
|
40
|
+
LOGS?: DurableObjectNamespace;
|
|
41
|
+
|
|
42
|
+
// ─── Cloudflare API (Analytics Engine SQL API proxy,) ───
|
|
43
|
+
CF_ACCOUNT_ID?: string;
|
|
44
|
+
CF_API_TOKEN?: string;
|
|
45
|
+
|
|
46
|
+
// ─── Static Assets ───
|
|
47
|
+
ASSETS?: { fetch(request: Request): Promise<Response> };
|
|
48
|
+
/** External admin dashboard origin when the dashboard is deployed separately. */
|
|
49
|
+
ADMIN_ORIGIN?: string;
|
|
50
|
+
|
|
51
|
+
// ─── Secrets ───
|
|
52
|
+
JWT_USER_SECRET?: string;
|
|
53
|
+
/** Old JWT user secret — valid during 28d grace period after rotate-jwt */
|
|
54
|
+
JWT_USER_SECRET_OLD?: string;
|
|
55
|
+
/** ISO 8601 timestamp of last JWT user key rotation */
|
|
56
|
+
JWT_USER_SECRET_OLD_AT?: string;
|
|
57
|
+
JWT_ADMIN_SECRET?: string;
|
|
58
|
+
/** Old JWT admin secret — valid during 28d grace period after rotate-jwt */
|
|
59
|
+
JWT_ADMIN_SECRET_OLD?: string;
|
|
60
|
+
/** ISO 8601 timestamp of last JWT admin key rotation */
|
|
61
|
+
JWT_ADMIN_SECRET_OLD_AT?: string;
|
|
62
|
+
SERVICE_KEY?: string;
|
|
63
|
+
|
|
64
|
+
// ─── Captcha ───
|
|
65
|
+
/** Turnstile secret key — auto-provisioned via deploy or manually set */
|
|
66
|
+
TURNSTILE_SECRET?: string;
|
|
67
|
+
/** Turnstile site key — public, returned to clients via GET /api/config (§34) */
|
|
68
|
+
CAPTCHA_SITE_KEY?: string;
|
|
69
|
+
/** Cloudflare Realtime app ID for SFU session control. */
|
|
70
|
+
CF_REALTIME_APP_ID?: string;
|
|
71
|
+
/** Cloudflare Realtime app secret for SFU session control. */
|
|
72
|
+
CF_REALTIME_APP_SECRET?: string;
|
|
73
|
+
/** Optional override for the Cloudflare Realtime API base URL. */
|
|
74
|
+
CF_REALTIME_BASE_URL?: string;
|
|
75
|
+
/** Cloudflare TURN key ID used to mint short-lived ICE credentials. */
|
|
76
|
+
CF_REALTIME_TURN_KEY_ID?: string;
|
|
77
|
+
/** Cloudflare TURN API token returned when the TURN key is created. */
|
|
78
|
+
CF_REALTIME_TURN_API_TOKEN?: string;
|
|
79
|
+
|
|
80
|
+
// ─── Environment Identification ───
|
|
81
|
+
/** Server environment name for Service Key constraints.env evaluation */
|
|
82
|
+
ENVIRONMENT?: string;
|
|
83
|
+
|
|
84
|
+
// ─── Push Secrets ───
|
|
85
|
+
/** FCM Service Account JSON string */
|
|
86
|
+
PUSH_FCM_SERVICE_ACCOUNT?: string;
|
|
87
|
+
/** Optional override base URL for mock FCM endpoints in local/Docker test runs. */
|
|
88
|
+
MOCK_FCM_BASE_URL?: string;
|
|
89
|
+
/** Optional internal base URL used for Worker self-calls behind Docker/proxy port mapping. */
|
|
90
|
+
EDGEBASE_INTERNAL_WORKER_URL?: string;
|
|
91
|
+
/** Optional override for email delivery in deployed/local mock environments. */
|
|
92
|
+
EDGEBASE_EMAIL_API_URL?: string;
|
|
93
|
+
/** Optional override for SMS delivery in deployed/local mock environments. */
|
|
94
|
+
EDGEBASE_SMS_API_URL?: string;
|
|
95
|
+
|
|
96
|
+
// ─── Dev Mode ───
|
|
97
|
+
/** Schema Editor sidecar port — set by CLI dev command via --var */
|
|
98
|
+
EDGEBASE_DEV_SIDECAR_PORT?: string;
|
|
99
|
+
}
|