diff --git a/bobbin/worker/src/index.ts b/bobbin/worker/src/index.ts index 5c1c8ba2..a46f47fd 100644 --- a/bobbin/worker/src/index.ts +++ b/bobbin/worker/src/index.ts @@ -5,10 +5,12 @@ export interface Env { RATE_LIMITER: RateLimit; BOBBIN_HYDRANT_URL: string; BOBBIN_SLINGSHOT_URL: string; + BOBBIN_MIRROR_V2_URL: string; + BOBBIN_SERVICE_DID: string; BOBBIN_LOG: string; } -export class BobbinContainer extends Container { +export class BobbinContainer extends Container { defaultPort = 8090; enableInternet = true; // Bobbin maintains an in-memory index rebuilt from Hydrant replay on every @@ -16,6 +18,19 @@ export class BobbinContainer extends Container { // onActivityExpired() to keep the container alive indefinitely. sleepAfter = "24h"; + constructor(ctx: DurableObjectState<{}>, env: Env) { + super(ctx, env, { + envVars: { + BOBBIN_HYDRANT_URL: env.BOBBIN_HYDRANT_URL, + BOBBIN_SLINGSHOT_URL: env.BOBBIN_SLINGSHOT_URL, + BOBBIN_MIRROR_V2_URL: env.BOBBIN_MIRROR_V2_URL, + BOBBIN_SERVICE_DID: env.BOBBIN_SERVICE_DID, + BOBBIN_LOG: env.BOBBIN_LOG, + BOBBIN_LOG_FORMAT: "json", + }, + }); + } + async onActivityExpired(): Promise { // Keep the container running; bobbin's in-memory index is expensive to // rebuild. Renew the timeout instead of stopping so we're pinged again later. @@ -31,8 +46,8 @@ const INDEX = `This is bobbin, Tangled's stateless XRPC API service: https://tan const CORS_HEADERS = { "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Methods": "GET, HEAD, OPTIONS", - "Access-Control-Allow-Headers": "Content-Type, Authorization", + "Access-Control-Allow-Methods": "GET, HEAD, POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization, atproto-proxy", "Access-Control-Max-Age": "86400", }; @@ -89,16 +104,6 @@ export default { } const container = env.BOBBIN.getByName("primary"); - await container.startAndWaitForPorts({ - startOptions: { - envVars: { - BOBBIN_HYDRANT_URL: env.BOBBIN_HYDRANT_URL, - BOBBIN_SLINGSHOT_URL: env.BOBBIN_SLINGSHOT_URL, - BOBBIN_LOG: env.BOBBIN_LOG, - BOBBIN_LOG_FORMAT: "json", - }, - }, - }); const response = await container.fetch(request); // A 101 is a protocol switch (e.g. WebSocket upgrade); return it untouched // so we don't strip the connection off the response. diff --git a/bobbin/worker/wrangler.dev.jsonc b/bobbin/worker/wrangler.dev.jsonc new file mode 100644 index 00000000..2386fda1 --- /dev/null +++ b/bobbin/worker/wrangler.dev.jsonc @@ -0,0 +1,54 @@ +{ + "$schema": "node_modules/wrangler/config-schema.json", + "name": "bobbin-svfe-dev", + "main": "src/index.ts", + "workers_dev": false, + "compatibility_date": "2026-03-07", + "observability": { + "enabled": true, + }, + "containers": [ + { + "class_name": "BobbinContainer", + "image": "../containerfiles/bobbin.Containerfile", + "image_build_context": "../../", + "instance_type": "standard-2", + "max_instances": 1, + "constraints": { + "regions": ["WEUR"], + "jurisdiction": "eu", + }, + }, + ], + "durable_objects": { + "bindings": [ + { + "name": "BOBBIN", + "class_name": "BobbinContainer", + }, + ], + }, + "migrations": [ + { + "tag": "v1", + "new_sqlite_classes": ["BobbinContainer"], + }, + ], + "ratelimits": [ + { + "name": "RATE_LIMITER", + "namespace_id": "1002", + "simple": { + "limit": 300, + "period": 60, + }, + }, + ], + "vars": { + "BOBBIN_HYDRANT_URL": "https://hyd.bob.oyster.cafe", + "BOBBIN_SLINGSHOT_URL": "https://slng.bob.oyster.cafe", + "BOBBIN_MIRROR_V2_URL": "https://mirror-fsn.tangled.network", + "BOBBIN_SERVICE_DID": "did:web:next.tangled.org", + "BOBBIN_LOG": "info", + }, +} diff --git a/bobbin/worker/wrangler.jsonc b/bobbin/worker/wrangler.jsonc index 01635df2..803bf81f 100644 --- a/bobbin/worker/wrangler.jsonc +++ b/bobbin/worker/wrangler.jsonc @@ -47,6 +47,8 @@ "vars": { "BOBBIN_HYDRANT_URL": "https://hyd.bob.oyster.cafe", "BOBBIN_SLINGSHOT_URL": "https://slng.bob.oyster.cafe", + "BOBBIN_MIRROR_V2_URL": "https://mirror-fsn.tangled.network", + "BOBBIN_SERVICE_DID": "did:web:api.tangled.org", "BOBBIN_LOG": "info", }, }