add workers-shared package and source-maps for dotcom-worker sentry reports (#4052)
Share the new sentry stuff that plays nice with releases/sourcemaps with dotcom-worker using a new `worker-shared` package.
This commit is contained in:
parent
7ec30e56da
commit
031547749f
20 changed files with 150 additions and 54 deletions
|
@ -24,11 +24,11 @@
|
||||||
"@tldraw/tlschema": "workspace:*",
|
"@tldraw/tlschema": "workspace:*",
|
||||||
"@tldraw/tlsync": "workspace:*",
|
"@tldraw/tlsync": "workspace:*",
|
||||||
"@tldraw/utils": "workspace:*",
|
"@tldraw/utils": "workspace:*",
|
||||||
|
"@tldraw/worker-shared": "workspace:*",
|
||||||
"itty-router": "^4.0.13",
|
"itty-router": "^4.0.13",
|
||||||
"nanoid": "4.0.2",
|
"nanoid": "4.0.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0"
|
||||||
"toucan-js": "^3.4.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@cloudflare/workers-types": "^4.20240620.0",
|
"@cloudflare/workers-types": "^4.20240620.0",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { createSentry } from '@tldraw/worker-shared'
|
||||||
import { DurableObject } from 'cloudflare:workers'
|
import { DurableObject } from 'cloudflare:workers'
|
||||||
import { Router } from 'itty-router'
|
import { Router } from 'itty-router'
|
||||||
import { createSentry } from './sentry'
|
|
||||||
import { Environment } from './types'
|
import { Environment } from './types'
|
||||||
|
|
||||||
export class BemoDO extends DurableObject<Environment> {
|
export class BemoDO extends DurableObject<Environment> {
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { Toucan } from 'toucan-js'
|
|
||||||
import { Environment } from './types'
|
|
||||||
|
|
||||||
interface Context {
|
|
||||||
waitUntil: ExecutionContext['waitUntil']
|
|
||||||
request?: Request
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createSentry(ctx: Context, env: Environment, request?: Request) {
|
|
||||||
return new Toucan({
|
|
||||||
dsn: env.SENTRY_DSN,
|
|
||||||
release: `${env.WORKER_NAME}.${env.CF_VERSION_METADATA.id}`,
|
|
||||||
environment: env.WORKER_NAME,
|
|
||||||
context: ctx,
|
|
||||||
request,
|
|
||||||
requestDataOptions: {
|
|
||||||
allowedHeaders: ['user-agent'],
|
|
||||||
allowedSearchParams: /(.*)/,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
/// <reference no-default-lib="true"/>
|
/// <reference no-default-lib="true"/>
|
||||||
/// <reference types="@cloudflare/workers-types" />
|
/// <reference types="@cloudflare/workers-types" />
|
||||||
|
|
||||||
|
import { createSentry } from '@tldraw/worker-shared'
|
||||||
import { WorkerEntrypoint } from 'cloudflare:workers'
|
import { WorkerEntrypoint } from 'cloudflare:workers'
|
||||||
import { Router, createCors } from 'itty-router'
|
import { Router, createCors } from 'itty-router'
|
||||||
import { createSentry } from './sentry'
|
|
||||||
import { Environment } from './types'
|
import { Environment } from './types'
|
||||||
|
|
||||||
export { BemoDO } from './BemoDO'
|
export { BemoDO } from './BemoDO'
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
{
|
{
|
||||||
"path": "../../packages/dotcom-shared"
|
"path": "../../packages/dotcom-shared"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "../../packages/worker-shared"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "../../packages/store"
|
"path": "../../packages/store"
|
||||||
},
|
},
|
||||||
|
|
|
@ -40,7 +40,7 @@ bucket_name = 'uploads-preview'
|
||||||
|
|
||||||
# in production, we write to the main bucket
|
# in production, we write to the main bucket
|
||||||
[[env.production.r2_buckets]]
|
[[env.production.r2_buckets]]
|
||||||
binding = "ROOMS"
|
binding = "UPLOADS"
|
||||||
bucket_name = "uploads"
|
bucket_name = "uploads"
|
||||||
|
|
||||||
#################### Analytics engine ####################
|
#################### Analytics engine ####################
|
||||||
|
|
|
@ -27,11 +27,11 @@
|
||||||
"@tldraw/tlsync": "workspace:*",
|
"@tldraw/tlsync": "workspace:*",
|
||||||
"@tldraw/utils": "workspace:*",
|
"@tldraw/utils": "workspace:*",
|
||||||
"@tldraw/validate": "workspace:*",
|
"@tldraw/validate": "workspace:*",
|
||||||
|
"@tldraw/worker-shared": "workspace:*",
|
||||||
"itty-router": "^4.0.13",
|
"itty-router": "^4.0.13",
|
||||||
"nanoid": "4.0.2",
|
"nanoid": "4.0.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0"
|
||||||
"toucan-js": "^3.4.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@cloudflare/workers-types": "^4.20240620.0",
|
"@cloudflare/workers-types": "^4.20240620.0",
|
||||||
|
|
|
@ -17,8 +17,8 @@ import {
|
||||||
type PersistedRoomSnapshotForSupabase,
|
type PersistedRoomSnapshotForSupabase,
|
||||||
} from '@tldraw/tlsync'
|
} from '@tldraw/tlsync'
|
||||||
import { assert, assertExists, exhaustiveSwitchError } from '@tldraw/utils'
|
import { assert, assertExists, exhaustiveSwitchError } from '@tldraw/utils'
|
||||||
|
import { createSentry } from '@tldraw/worker-shared'
|
||||||
import { IRequest, Router } from 'itty-router'
|
import { IRequest, Router } from 'itty-router'
|
||||||
import { Toucan } from 'toucan-js'
|
|
||||||
import { AlarmScheduler } from './AlarmScheduler'
|
import { AlarmScheduler } from './AlarmScheduler'
|
||||||
import { PERSIST_INTERVAL_MS } from './config'
|
import { PERSIST_INTERVAL_MS } from './config'
|
||||||
import { getR2KeyForRoom } from './r2'
|
import { getR2KeyForRoom } from './r2'
|
||||||
|
@ -215,14 +215,7 @@ export class TLDrawDurableObject {
|
||||||
|
|
||||||
// Handle a request to the Durable Object.
|
// Handle a request to the Durable Object.
|
||||||
async fetch(req: IRequest) {
|
async fetch(req: IRequest) {
|
||||||
const sentry = new Toucan({
|
const sentry = createSentry(this.state, this.env, req)
|
||||||
dsn: this.sentryDSN,
|
|
||||||
request: req,
|
|
||||||
requestDataOptions: {
|
|
||||||
allowedHeaders: ['user-agent'],
|
|
||||||
allowedSearchParams: /(.*)/,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await this.router.handle(req)
|
return await this.router.handle(req)
|
||||||
|
|
|
@ -25,6 +25,8 @@ export interface Environment {
|
||||||
SLUG_TO_READONLY_SLUG: KVNamespace
|
SLUG_TO_READONLY_SLUG: KVNamespace
|
||||||
READONLY_SLUG_TO_SLUG: KVNamespace
|
READONLY_SLUG_TO_SLUG: KVNamespace
|
||||||
|
|
||||||
|
CF_VERSION_METADATA: WorkerVersionMetadata
|
||||||
|
|
||||||
// env vars
|
// env vars
|
||||||
SUPABASE_URL: string | undefined
|
SUPABASE_URL: string | undefined
|
||||||
SUPABASE_KEY: string | undefined
|
SUPABASE_KEY: string | undefined
|
||||||
|
|
|
@ -7,8 +7,8 @@ import {
|
||||||
ROOM_PREFIX,
|
ROOM_PREFIX,
|
||||||
} from '@tldraw/dotcom-shared'
|
} from '@tldraw/dotcom-shared'
|
||||||
import { T } from '@tldraw/validate'
|
import { T } from '@tldraw/validate'
|
||||||
|
import { createSentry } from '@tldraw/worker-shared'
|
||||||
import { Router, createCors, json } from 'itty-router'
|
import { Router, createCors, json } from 'itty-router'
|
||||||
import { Toucan } from 'toucan-js'
|
|
||||||
import { createRoom } from './routes/createRoom'
|
import { createRoom } from './routes/createRoom'
|
||||||
import { createRoomSnapshot } from './routes/createRoomSnapshot'
|
import { createRoomSnapshot } from './routes/createRoomSnapshot'
|
||||||
import { forwardRoomRequest } from './routes/forwardRoomRequest'
|
import { forwardRoomRequest } from './routes/forwardRoomRequest'
|
||||||
|
@ -55,15 +55,7 @@ const router = Router()
|
||||||
|
|
||||||
const Worker = {
|
const Worker = {
|
||||||
fetch(request: Request, env: Environment, context: ExecutionContext) {
|
fetch(request: Request, env: Environment, context: ExecutionContext) {
|
||||||
const sentry = new Toucan({
|
const sentry = createSentry(context, env, request)
|
||||||
dsn: env.SENTRY_DSN,
|
|
||||||
context, // Includes 'waitUntil', which is essential for Sentry logs to be delivered. Modules workers do not include 'request' in context -- you'll need to set it separately.
|
|
||||||
request, // request is not included in 'context', so we set it here.
|
|
||||||
requestDataOptions: {
|
|
||||||
allowedHeaders: ['user-agent'],
|
|
||||||
allowedSearchParams: /(.*)/,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return router
|
return router
|
||||||
.handle(request, env, context)
|
.handle(request, env, context)
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
{
|
{
|
||||||
"path": "../../packages/dotcom-shared"
|
"path": "../../packages/dotcom-shared"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "../../packages/worker-shared"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "../../packages/store"
|
"path": "../../packages/store"
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,11 +8,11 @@ ip = "0.0.0.0"
|
||||||
# these migrations are append-only. you can't change them. if you do need to change something, do so
|
# these migrations are append-only. you can't change them. if you do need to change something, do so
|
||||||
# by creating new migrations
|
# by creating new migrations
|
||||||
[[migrations]]
|
[[migrations]]
|
||||||
tag = "v1" # Should be unique for each entry
|
tag = "v1" # Should be unique for each entry
|
||||||
new_classes = ["TLDrawDurableObject"]
|
new_classes = ["TLDrawDurableObject"]
|
||||||
|
|
||||||
[[migrations]]
|
[[migrations]]
|
||||||
tag = "v2"
|
tag = "v2"
|
||||||
new_classes = ["TLProWorkspaceDurableObject"]
|
new_classes = ["TLProWorkspaceDurableObject"]
|
||||||
|
|
||||||
[[migrations]]
|
[[migrations]]
|
||||||
|
@ -44,9 +44,7 @@ name = "TLDR_DOC"
|
||||||
class_name = "TLDrawDurableObject"
|
class_name = "TLDrawDurableObject"
|
||||||
|
|
||||||
[durable_objects]
|
[durable_objects]
|
||||||
bindings = [
|
bindings = [{ name = "TLDR_DOC", class_name = "TLDrawDurableObject" }]
|
||||||
{ name = "TLDR_DOC", class_name = "TLDrawDurableObject" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[env.preview.durable_objects.bindings]]
|
[[env.preview.durable_objects.bindings]]
|
||||||
name = "TLDR_DOC"
|
name = "TLDR_DOC"
|
||||||
|
@ -186,3 +184,19 @@ id = "2fb5fc7f7ca54a5a9dfae1b07a30a778"
|
||||||
[[env.production.kv_namespaces]]
|
[[env.production.kv_namespaces]]
|
||||||
binding = "READONLY_SLUG_TO_SLUG"
|
binding = "READONLY_SLUG_TO_SLUG"
|
||||||
id = "96be6637b281412ab35b2544539d78e8"
|
id = "96be6637b281412ab35b2544539d78e8"
|
||||||
|
|
||||||
|
#################### Version metadata ####################
|
||||||
|
[version_metadata]
|
||||||
|
binding = "CF_VERSION_METADATA"
|
||||||
|
|
||||||
|
[env.dev.version_metadata]
|
||||||
|
binding = "CF_VERSION_METADATA"
|
||||||
|
|
||||||
|
[env.preview.version_metadata]
|
||||||
|
binding = "CF_VERSION_METADATA"
|
||||||
|
|
||||||
|
[env.staging.version_metadata]
|
||||||
|
binding = "CF_VERSION_METADATA"
|
||||||
|
|
||||||
|
[env.production.version_metadata]
|
||||||
|
binding = "CF_VERSION_METADATA"
|
||||||
|
|
26
packages/worker-shared/package.json
Normal file
26
packages/worker-shared/package.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"name": "@tldraw/worker-shared",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"private": true,
|
||||||
|
"/* NOTE */": "These `main` and `types` fields are rewritten by the build script. They are not the actual values we publish",
|
||||||
|
"main": "./src/index.ts",
|
||||||
|
"types": "./.tsbuild/index.d.ts",
|
||||||
|
"/* GOTCHA */": "files will include ./dist and index.d.ts by default, add any others you want to include in here",
|
||||||
|
"files": [],
|
||||||
|
"dependencies": {
|
||||||
|
"@cloudflare/workers-types": "^4.20240620.0",
|
||||||
|
"@tldraw/utils": "workspace:*",
|
||||||
|
"lazyrepo": "0.0.0-alpha.27",
|
||||||
|
"toucan-js": "^3.4.0",
|
||||||
|
"typescript": "^5.3.3"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test-ci": "lazy inherit",
|
||||||
|
"test": "yarn run -T jest",
|
||||||
|
"lint": "yarn run -T tsx ../../scripts/lint.ts"
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"preset": "config/jest/node",
|
||||||
|
"testEnvironment": "jsdom"
|
||||||
|
}
|
||||||
|
}
|
13
packages/worker-shared/src/env.ts
Normal file
13
packages/worker-shared/src/env.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { getOwnProperty } from '@tldraw/utils'
|
||||||
|
|
||||||
|
export function requiredEnv<T extends object>(
|
||||||
|
env: T,
|
||||||
|
keys: { [K in keyof T]: true }
|
||||||
|
): { [K in keyof T]-?: NonNullable<T[K]> } {
|
||||||
|
for (const key of Object.keys(keys)) {
|
||||||
|
if (getOwnProperty(env, key) === undefined) {
|
||||||
|
throw new Error(`Missing required env var: ${key}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return env as any
|
||||||
|
}
|
3
packages/worker-shared/src/index.test.ts
Normal file
3
packages/worker-shared/src/index.test.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
it('works', () => {
|
||||||
|
// we need a test for jest to pass.
|
||||||
|
})
|
4
packages/worker-shared/src/index.ts
Normal file
4
packages/worker-shared/src/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/// <reference no-default-lib="true"/>
|
||||||
|
/// <reference types="@cloudflare/workers-types" />
|
||||||
|
|
||||||
|
export { createSentry } from './sentry'
|
34
packages/worker-shared/src/sentry.ts
Normal file
34
packages/worker-shared/src/sentry.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { WorkerVersionMetadata } from '@cloudflare/workers-types'
|
||||||
|
import { Toucan } from 'toucan-js'
|
||||||
|
import { requiredEnv } from './env'
|
||||||
|
|
||||||
|
interface Context {
|
||||||
|
waitUntil: ExecutionContext['waitUntil']
|
||||||
|
request?: Request
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SentryEnvironment {
|
||||||
|
readonly SENTRY_DSN: string | undefined
|
||||||
|
readonly WORKER_NAME: string | undefined
|
||||||
|
readonly CF_VERSION_METADATA: WorkerVersionMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createSentry(ctx: Context, env: SentryEnvironment, request?: Request) {
|
||||||
|
const { SENTRY_DSN, WORKER_NAME, CF_VERSION_METADATA } = requiredEnv(env, {
|
||||||
|
SENTRY_DSN: true,
|
||||||
|
WORKER_NAME: true,
|
||||||
|
CF_VERSION_METADATA: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
return new Toucan({
|
||||||
|
dsn: SENTRY_DSN,
|
||||||
|
release: `${WORKER_NAME}.${CF_VERSION_METADATA.id}`,
|
||||||
|
environment: WORKER_NAME,
|
||||||
|
context: ctx,
|
||||||
|
request,
|
||||||
|
requestDataOptions: {
|
||||||
|
allowedHeaders: ['user-agent'],
|
||||||
|
allowedSearchParams: /(.*)/,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
14
packages/worker-shared/tsconfig.json
Normal file
14
packages/worker-shared/tsconfig.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"extends": "../../config/tsconfig.base.json",
|
||||||
|
"include": ["src"],
|
||||||
|
"exclude": ["node_modules", ".tsbuild*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./.tsbuild",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../utils"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -196,6 +196,10 @@ async function deployTlsyncWorker({ dryRun }: { dryRun: boolean }) {
|
||||||
APP_ORIGIN: env.APP_ORIGIN,
|
APP_ORIGIN: env.APP_ORIGIN,
|
||||||
WORKER_NAME: workerId,
|
WORKER_NAME: workerId,
|
||||||
},
|
},
|
||||||
|
sentry: {
|
||||||
|
project: 'tldraw-sync',
|
||||||
|
authToken: env.SENTRY_AUTH_TOKEN,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -6000,13 +6000,13 @@ __metadata:
|
||||||
"@tldraw/tlschema": "workspace:*"
|
"@tldraw/tlschema": "workspace:*"
|
||||||
"@tldraw/tlsync": "workspace:*"
|
"@tldraw/tlsync": "workspace:*"
|
||||||
"@tldraw/utils": "workspace:*"
|
"@tldraw/utils": "workspace:*"
|
||||||
|
"@tldraw/worker-shared": "workspace:*"
|
||||||
esbuild: "npm:^0.21.5"
|
esbuild: "npm:^0.21.5"
|
||||||
itty-router: "npm:^4.0.13"
|
itty-router: "npm:^4.0.13"
|
||||||
lazyrepo: "npm:0.0.0-alpha.27"
|
lazyrepo: "npm:0.0.0-alpha.27"
|
||||||
nanoid: "npm:4.0.2"
|
nanoid: "npm:4.0.2"
|
||||||
react: "npm:^18.2.0"
|
react: "npm:^18.2.0"
|
||||||
react-dom: "npm:^18.2.0"
|
react-dom: "npm:^18.2.0"
|
||||||
toucan-js: "npm:^3.4.0"
|
|
||||||
typescript: "npm:^5.3.3"
|
typescript: "npm:^5.3.3"
|
||||||
wrangler: "npm:3.62.0"
|
wrangler: "npm:3.62.0"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
|
@ -6089,13 +6089,13 @@ __metadata:
|
||||||
"@tldraw/tlsync": "workspace:*"
|
"@tldraw/tlsync": "workspace:*"
|
||||||
"@tldraw/utils": "workspace:*"
|
"@tldraw/utils": "workspace:*"
|
||||||
"@tldraw/validate": "workspace:*"
|
"@tldraw/validate": "workspace:*"
|
||||||
|
"@tldraw/worker-shared": "workspace:*"
|
||||||
esbuild: "npm:^0.21.5"
|
esbuild: "npm:^0.21.5"
|
||||||
itty-router: "npm:^4.0.13"
|
itty-router: "npm:^4.0.13"
|
||||||
lazyrepo: "npm:0.0.0-alpha.27"
|
lazyrepo: "npm:0.0.0-alpha.27"
|
||||||
nanoid: "npm:4.0.2"
|
nanoid: "npm:4.0.2"
|
||||||
react: "npm:^18.2.0"
|
react: "npm:^18.2.0"
|
||||||
react-dom: "npm:^18.2.0"
|
react-dom: "npm:^18.2.0"
|
||||||
toucan-js: "npm:^3.4.0"
|
|
||||||
typescript: "npm:^5.3.3"
|
typescript: "npm:^5.3.3"
|
||||||
wrangler: "npm:3.62.0"
|
wrangler: "npm:3.62.0"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
|
@ -6349,6 +6349,18 @@ __metadata:
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
"@tldraw/worker-shared@workspace:*, @tldraw/worker-shared@workspace:packages/worker-shared":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "@tldraw/worker-shared@workspace:packages/worker-shared"
|
||||||
|
dependencies:
|
||||||
|
"@cloudflare/workers-types": "npm:^4.20240620.0"
|
||||||
|
"@tldraw/utils": "workspace:*"
|
||||||
|
lazyrepo: "npm:0.0.0-alpha.27"
|
||||||
|
toucan-js: "npm:^3.4.0"
|
||||||
|
typescript: "npm:^5.3.3"
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"@tootallnate/once@npm:1":
|
"@tootallnate/once@npm:1":
|
||||||
version: 1.1.2
|
version: 1.1.2
|
||||||
resolution: "@tootallnate/once@npm:1.1.2"
|
resolution: "@tootallnate/once@npm:1.1.2"
|
||||||
|
|
Loading…
Reference in a new issue