Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
114 commits
Select commit Hold shift + click to select a range
bf27953
init rivet support
NathanFlurry Oct 22, 2025
572bb61
[automated] update i18n strings (#6966)
github-actions[bot] Oct 20, 2025
6ba33c2
analytics: fix regression on properties (#6967)
mimecuvalo Oct 20, 2025
054b7b9
workers: unify origin checks (#6951)
mimecuvalo Oct 20, 2025
fafd826
csp: allow analytics.google.com (#6969)
mimecuvalo Oct 20, 2025
9fd998e
worker-shared: move build dependencies to devDependencies (#6968)
steveruizok Oct 20, 2025
d1764fb
Improve hotfix pr checking (#6972)
MitjaBezensek Oct 21, 2025
5a683a5
Refactor analytics app to vanilla JS and modular architecture (#6964)
steveruizok Oct 21, 2025
250c3a6
Add analytics tracking to sidebar dotdev link actions (#6954)
steveruizok Oct 21, 2025
6cef0c5
Add bezier curve shape example (#6908)
kostyafarber Oct 21, 2025
7d4366a
Analytics: use consent worker on tldraw.com (#6973)
steveruizok Oct 21, 2025
cf11725
analytics: allow tldraw.dev without www (#6978)
mimecuvalo Oct 21, 2025
da57804
Groups backend minor fixes (#6976)
ds300 Oct 22, 2025
cd4a1e3
analytics: add opt_in/opt_out_capturing for posthog (#6979)
mimecuvalo Oct 22, 2025
bacda05
load timing analytics (#6983)
ds300 Oct 22, 2025
1f6e6d1
Revert "Bump up the target rate to 120fps. (#6868)" (#6985)
MitjaBezensek Oct 22, 2025
0487a33
Reduce frequency of file_state updates (#6989)
ds300 Oct 23, 2025
e26c9e4
Redeploy (#6991)
MitjaBezensek Oct 23, 2025
ad65304
watermark: add tracking to figure out use in the wild (#7001)
mimecuvalo Oct 24, 2025
e958892
Bump protocol version to v3 and enable new groups initialization (#6998)
MitjaBezensek Oct 24, 2025
4572777
Add allowReferrer option to window opening functions (#7004)
steveruizok Oct 24, 2025
8224b78
Support nested store queries with nested objects (#6981)
ds300 Oct 27, 2025
72d5b79
Add batch user migration to groups (#6999)
MitjaBezensek Oct 27, 2025
c2d0ba5
fix file deletion error toast (#7015)
ds300 Oct 27, 2025
b6fc69b
Improve the discord messsages (#7018)
MitjaBezensek Oct 27, 2025
1efa26c
Improve Discord deployment notifications (#6988)
MitjaBezensek Oct 27, 2025
34230d4
[automated] update i18n strings (#7013)
github-actions[bot] Oct 27, 2025
92e9014
Move InFrontOfTheCanvas back out (#7021)
ds300 Oct 28, 2025
46f091f
Bump versions to 4.1.2 [skip ci]
huppy-bot[bot] Oct 28, 2025
7172203
flush file state on beforeunload (#7023)
ds300 Oct 28, 2025
760aecf
Fix release tagging (#7025)
ds300 Oct 28, 2025
ce2e3f1
docs: podcast link (#7028)
mimecuvalo Oct 29, 2025
cb20384
Fix fairy position when sidebar is open (#7032)
TodePond Oct 29, 2025
656372b
Add accessibility rewrite (#7033)
MitjaBezensek Oct 29, 2025
4bab4db
Two fairies (#6982)
TodePond Oct 29, 2025
145a850
Add input element for local file picker to the DOM (#7037)
kostyafarber Oct 29, 2025
55d278b
a11y: dont navigate when doing alt+tab (#7005)
mimecuvalo Oct 29, 2025
4be8b3a
analytics: call reset on sign out (#7040)
mimecuvalo Oct 29, 2025
b564098
cross-realm: clipboard functionality broken in cross-realm app (#7026)
mimecuvalo Oct 29, 2025
d34987d
feat: allow custom relative snap points for handles (#6987)
nehaaprasad Oct 30, 2025
a2332c8
analytics: add cookieless mode (#7017)
mimecuvalo Oct 30, 2025
5688c43
bump min z protocol version (#7044)
ds300 Oct 30, 2025
7072513
analytics: add cookieless mode followup (#7046)
mimecuvalo Oct 30, 2025
0103361
Fix index crash in agent starter (#7048)
TodePond Oct 30, 2025
172e4e6
tiptap: fix focus issue when editor not mounted (#7043)
mimecuvalo Oct 30, 2025
f0a6e1d
fix admin_migrateToGroups (#7049)
ds300 Oct 31, 2025
9bd8179
incremental migration: use a single sql connection (#7052)
ds300 Oct 31, 2025
7bff12c
dotcom: fix slurping (#7056)
ds300 Oct 31, 2025
f5540f0
Add retries for persistence (#7050)
ds300 Nov 3, 2025
f326fe7
Add framer rewrites action (#7036)
MitjaBezensek Nov 3, 2025
b88b99c
[dotcom] init user data server-side (#7058)
ds300 Nov 3, 2025
07ceaea
Transfer API changes section to hotfix PRs (#7062)
MitjaBezensek Nov 3, 2025
089b915
dotcom: update license (#7054)
mimecuvalo Nov 3, 2025
9ea3736
[automated] update i18n strings (#7063)
github-actions[bot] Nov 3, 2025
e219405
server-side-init followup (#7066)
ds300 Nov 3, 2025
befe7e8
workers: followup to #6951 (#7000)
mimecuvalo Nov 4, 2025
1aafe8b
Fix persistence health reporting (#7067)
ds300 Nov 4, 2025
7451185
dedupe persistence_bad event (#7073)
ds300 Nov 5, 2025
f599f44
Support 3+ fairies (#7038)
TodePond Nov 5, 2025
1ab5203
Try out @pierre/storage for board history (#7022)
ds300 Nov 5, 2025
62ed670
Add stream operation for string append optimization (#7007)
quasor Nov 6, 2025
7a372d3
editor: be able to use TldrawEditor without needing `TldrawUiContextP…
mimecuvalo Nov 6, 2025
17b0061
docs: add another podcast link (#7075)
mimecuvalo Nov 6, 2025
283b10e
Incremental migration auto batching (#7076)
ds300 Nov 7, 2025
dde0eaa
stop incremental migration on errors (#7081)
ds300 Nov 7, 2025
d8e4192
feat: use window.prompt for mobile frame label input (#6838)
swdev33 Nov 7, 2025
ad972ed
incremental migration: add retry on per-user basis in case of flake (…
ds300 Nov 7, 2025
ec9bf51
docs: add another podcast link (#7084)
mimecuvalo Nov 7, 2025
d5f2a31
Fix pdf examples InFrontOfTheCanvas covering UI (#7089)
max-drake Nov 7, 2025
b8cd9d2
Add lined fill style (#7034)
TodePond Nov 10, 2025
5c9b607
Analytics improvements (#7041)
MitjaBezensek Nov 10, 2025
b4824eb
fix new user signup (#7093)
ds300 Nov 10, 2025
06d1f7e
docs: add another podcast link (#7096)
mimecuvalo Nov 10, 2025
e9810db
dotcom: rework login flow (#7031)
mimecuvalo Nov 11, 2025
31754c0
ci: fix i18n flow if no strings to download (#7099)
mimecuvalo Nov 11, 2025
d2e1b72
Improve watermark link (#7098)
MitjaBezensek Nov 11, 2025
842bc9b
login: make sure we have captcha (#7105)
mimecuvalo Nov 12, 2025
3a0a21d
fix the diffing (#7108)
ds300 Nov 12, 2025
315b206
handle large socket messages to TLUserDO (hotfix) (#7111)
mimecuvalo Nov 13, 2025
6511909
media: move mobile rotate handle to bottom (#6727)
mimecuvalo Nov 13, 2025
86744ac
fairies: pixie edition (#7102)
mimecuvalo Nov 13, 2025
332b7aa
docs: link to sitemap from robots.txt (#7115)
mimecuvalo Nov 13, 2025
24398d7
fix: prevent iOS zoom on feedback dialog (#7118)
steveruizok Nov 13, 2025
a65d2d0
Groups UI take 2 (#6974)
ds300 Nov 14, 2025
d76b9e3
login: add tos/privacy policy to sign in (#7121)
mimecuvalo Nov 14, 2025
930229e
login: handle redirect properly for Google OAuth (#7117)
mimecuvalo Nov 14, 2025
17c061c
Few groups fixes (#7120)
MitjaBezensek Nov 14, 2025
ebd0707
login: fix up scroll issue (#7126)
mimecuvalo Nov 14, 2025
40078b4
i18n: make sure we fallback to English for missing untranslated strin…
mimecuvalo Nov 14, 2025
0fe4fa2
cross-realm: canvas events (#7113)
mimecuvalo Nov 17, 2025
29f4949
schema: add missing export `DefaultLabelColorStyle` (#7114)
mimecuvalo Nov 17, 2025
c3ec3b4
examples: dynamic tools (#7136)
mimecuvalo Nov 17, 2025
5f08905
[automated] update i18n strings (#7132)
github-actions[bot] Nov 17, 2025
bff26d6
Fairy collaboration 2.0 improvements (#7140)
TodePond Nov 17, 2025
a5f2f86
Group e2e tests (#7129)
MitjaBezensek Nov 18, 2025
80bc07d
Remove cursor summary from generated changelog (#7142)
ds300 Nov 18, 2025
d817d98
Improve ux of accepting a group invite when logged out. (#7138)
MitjaBezensek Nov 19, 2025
7ef365f
example: add on interaction end example (#7143)
kostyafarber Nov 19, 2025
49e6eb0
example: add custom relative snap handle example (#7139)
kostyafarber Nov 19, 2025
2820b47
Improve copy in sign in dialog (#7148)
steveruizok Nov 19, 2025
13f3f3d
fairies: i18n (#7145)
mimecuvalo Nov 19, 2025
c7c3f70
fix push command (#7152)
ds300 Nov 19, 2025
a8e3256
Bump versions to 4.2.0 [skip ci]
huppy-bot[bot] Nov 19, 2025
167a132
hide inline pin icon from people without groups (#7150)
ds300 Nov 19, 2025
570ca28
fix push command again (#7154)
ds300 Nov 19, 2025
201af41
Easter egg example (#7137)
TodePond Nov 19, 2025
0f7f561
Update error messages for clarity and consistency (#7149)
steveruizok Nov 19, 2025
2c5bba9
perf: disable PostHog surveys module (#7119)
steveruizok Nov 19, 2025
2fe7534
Only track via trackCopyCode (#7158)
MitjaBezensek Nov 20, 2025
2439b8c
First send the update then disable the services. (#7160)
MitjaBezensek Nov 20, 2025
710eaab
Augmentation-based shape and binding types (#7091)
Andarist Nov 20, 2025
b7c3667
Fix claude imports. (#7161)
MitjaBezensek Nov 20, 2025
ecc859f
FaeOS (#7144)
TodePond Nov 20, 2025
8819dc0
init rivet support
NathanFlurry Oct 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 2 additions & 3 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
{
"hooks": {
"PostToolUse": [
"Stop": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | { read file_path; yarn run -T prettier --write \"$file_path\"; }"
"command": "git diff --name-only --diff-filter=ACMR | grep -E '\\.(ts|tsx|js|jsx|json|md)$' | xargs -r yarn run -T prettier --write"
}
]
}
Expand Down
70 changes: 70 additions & 0 deletions .github/workflows/add-framer-rewrites.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Add Framer Rewrites

on:
workflow_dispatch:

permissions:
contents: write
pull-requests: write

env:
CI: 1

defaults:
run:
shell: bash

jobs:
add-rewrites:
name: 'Add Framer Rewrites'
timeout-minutes: 10
runs-on: ubuntu-latest

steps:
- name: Check out code
uses: actions/checkout@v3

- name: Run our setup
uses: ./.github/actions/setup

- name: Check for changes before running script
id: before
run: |
echo "BEFORE_HASH=$(md5sum apps/docs/next.config.js | cut -d' ' -f1)" >> $GITHUB_OUTPUT

- name: Run add-framer-rewrites script
run: yarn add-framer-rewrites

- name: Check for changes after running script
id: after
run: |
echo "AFTER_HASH=$(md5sum apps/docs/next.config.js | cut -d' ' -f1)" >> $GITHUB_OUTPUT

- name: Create PR if changes detected
if: steps.before.outputs.BEFORE_HASH != steps.after.outputs.AFTER_HASH
env:
GH_TOKEN: ${{ github.token }}
run: |
BRANCH_NAME="framer-rewrites-$(date +%Y%m%d-%H%M%S)"

git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

git checkout -b "$BRANCH_NAME"
git add apps/docs/next.config.js
git commit -m "Add missing Framer rewrites to next.config.js"
git push origin "$BRANCH_NAME"

gh pr create \
--title "Add missing Framer rewrites" \
--body "Adds missing rewrites for new Framer marketing pages to \`apps/docs/next.config.js\`.

### Change type

- [x] \`improvement\`" \
--label "docs-hotfix-please"

- name: No changes detected
if: steps.before.outputs.BEFORE_HASH == steps.after.outputs.AFTER_HASH
run: |
echo "✔ No changes detected. All Framer paths already have rewrites configured."
49 changes: 49 additions & 0 deletions .github/workflows/deploy-analytics.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Deploy analytics worker
permissions:
contents: read
deployments: write

on:
pull_request:
push:
branches:
- main
- production

env:
CI: 1
PRINT_GITHUB_ANNOTATIONS: 1
TLDRAW_ENV: ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }}

defaults:
run:
shell: bash

jobs:
deploy:
name: Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }}
timeout-minutes: 10
runs-on: ubuntu-latest
environment: ${{ github.ref == 'refs/heads/production' && 'deploy-production' || 'deploy-staging' }}
concurrency: analytics-worker-${{ github.ref == 'refs/heads/production' && 'deploy-production' || github.ref }}

steps:
- name: Check out code
uses: actions/checkout@v3
with:
submodules: true

- uses: ./.github/actions/setup

- name: Build types
run: yarn build-types

- name: Deploy
run: yarn tsx internal/scripts/deploy-analytics.ts
env:
RELEASE_COMMIT_HASH: ${{ github.sha }}
GH_TOKEN: ${{ github.token }}

CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
DISCORD_DEPLOY_WEBHOOK_URL: ${{ secrets.DISCORD_DEPLOY_WEBHOOK_URL }}
3 changes: 2 additions & 1 deletion .github/workflows/deploy-dotcom.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
fi

- name: Delete Neon Branch
uses: neondatabase/delete-branch-action@v3.1.3
uses: neondatabase/delete-branch-action@v3.2.0
if: contains(github.event.pull_request.labels.*.name, 'reset-preview-db')
with:
project_id: ${{ vars.NEON_PROJECT_ID }}
Expand Down Expand Up @@ -158,3 +158,4 @@ jobs:
VITE_GA4_MEASUREMENT_ID: ${{ secrets.VITE_GA4_MEASUREMENT_ID }}
WORKER_SENTRY_DSN: ${{ secrets.WORKER_SENTRY_DSN }}
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
PIERRE_KEY: ${{ secrets.PIERRE_KEY }}
15 changes: 11 additions & 4 deletions .github/workflows/i18n-download-strings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,25 @@ jobs:
run: 'yarn i18n-check -f react-intl --locales ./apps/dotcom/client/public/tla/locales/ --source en'

- name: Commit and push changes
if: always()
env:
GH_TOKEN: ${{ github.token }}
run: |
git config --global user.name 'huppy-bot[bot]'
git config --global user.email '128400622+huppy-bot[bot]@users.noreply.github.com'
git checkout -b update-i18n-strings
git add "*.json"
if git diff-index --quiet HEAD --; then

# Check if there are any changes to JSON files
if ! git diff --quiet '*.json' || ! git diff --cached --quiet '*.json'; then
echo "Changes detected, creating PR..."
else
echo "No changes to commit"
exit 0
fi

# Delete the branch if it already exists
git push origin --delete update-i18n-strings 2>/dev/null || true

git checkout -b update-i18n-strings
git add "*.json"
git commit --no-verify -m '[automated] update i18n strings'
git push --set-upstream origin update-i18n-strings
gh pr create --title "[automated] update i18n strings" --body "This PR updates the i18n strings.
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ apps/docs/content/reference/**/*
**/.out/*
**/.temp/*
apps/dotcom/client/public/**/*.*
apps/analytics/public/**/*

**/.clasp.json

Expand Down
2 changes: 2 additions & 0 deletions apps/analytics-worker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build
.wrangler
127 changes: 127 additions & 0 deletions apps/analytics-worker/CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Analytics worker

A Cloudflare Worker that determines whether users require explicit cookie consent based on their geographic location.

## Purpose

This worker supports the tldraw analytics system by providing geographic consent checking. It helps ensure compliance with privacy regulations like GDPR, UK PECR, FADP, and LGPD by identifying users in regions that require explicit opt-in for tracking.

The worker is deployed to `tldraw-consent.workers.dev` and is called by the analytics app (`apps/analytics/`) during initialization.

## How it works

1. Receives GET request from analytics client
2. Reads user's country code from CloudFlare's `CF-IPCountry` header
3. Checks if country requires explicit consent
4. Returns JSON response indicating whether consent is required
5. Includes CORS headers for allowed tldraw origins

## API

**Endpoint**: `https://tldraw-consent.workers.dev` (or environment-specific variants)

**Method**: `GET`

**Response**:

```json
{
"requires_consent": boolean,
"country_code": string | null
}
```

**Caching**: Responses are cached for 1 hour (`Cache-Control: public, max-age=3600`)

## Geographic consent rules

Users in the following countries/regions require explicit consent:

**EU Member States (GDPR)**:

- Austria, Belgium, Bulgaria, Croatia, Cyprus, Czech Republic, Denmark, Estonia, Finland, France, Germany, Greece, Hungary, Ireland, Italy, Latvia, Lithuania, Luxembourg, Malta, Netherlands, Poland, Portugal, Romania, Slovakia, Slovenia, Spain, Sweden

**EEA/EFTA (GDPR)**:

- Iceland, Liechtenstein, Norway

**Other regions**:

- United Kingdom (UK PECR)
- Switzerland (FADP)
- Brazil (LGPD)

**Default behavior**: If country code cannot be determined, the worker defaults to requiring consent (conservative approach for privacy compliance).

## CORS configuration

The worker allows cross-origin requests from:

- `http://localhost:3000` - Local development
- `http://localhost:5420` - Local development
- `https://meet.google.com` - Google Meet integration
- `*.tldraw.com` - Production domains
- `*.tldraw.dev` - Development domains
- `*.tldraw.club` - Alternative domains
- `*.tldraw.xyz` - Alternative domains
- `*.tldraw.workers.dev` - Worker preview domains
- `*-tldraw.vercel.app` - Vercel preview deployments

## Development

### Running locally

```bash
yarn dev # Start local development server
```

### Testing

```bash
yarn test # Run tests
yarn test-ci # Run tests in CI mode
```

### Deployment

The worker is deployed via GitHub Actions (`.github/workflows/deploy-analytics.yml`) which runs `internal/scripts/deploy-analytics.ts`.

**Environments**:

- **dev**: `tldraw-consent-dev` (for testing)
- **staging**: `tldraw-consent-staging` (deployed on push to `main`)
- **production**: `tldraw-consent` (deployed on push to `production`)

## File structure

- `src/worker.ts` - Main worker code
- `wrangler.toml` - Cloudflare Worker configuration
- `package.json` - Package configuration and scripts
- `tsconfig.json` - TypeScript configuration
- `vitest.config.ts` - Test configuration

## Integration

This worker is called by the analytics app during initialization:

1. Analytics app loads in user's browser
2. If no existing consent preference is stored
3. App calls this worker to check if consent is required
4. Based on response, app either:
- Shows consent banner (requires_consent: true)
- Assumes implicit consent (requires_consent: false)

See `apps/analytics/src/utils/consent-check.ts` for the client-side integration.

## Dependencies

- `@cloudflare/workers-types` - TypeScript types for Cloudflare Workers
- `wrangler` - Cloudflare Workers CLI tool

## Notes

- This is a standalone worker (not part of the analytics app bundle)
- Uses CloudFlare's edge network for low-latency responses worldwide
- Conservative default (require consent) ensures compliance even if geo-detection fails
- CORS preflight requests are handled with 24-hour cache
- Responses are cached to reduce load and improve performance
28 changes: 28 additions & 0 deletions apps/analytics-worker/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@tldraw/analytics-worker",
"description": "tldraw infinite canvas SDK (analytics worker).",
"version": "0.0.0",
"private": true,
"author": {
"name": "tldraw GB Ltd.",
"email": "hello@tldraw.com"
},
"main": "./src/worker.ts",
"/* GOTCHA */": "files will include ./dist and index.d.ts by default, add any others you want to include in here",
"files": [],
"scripts": {
"dev": "yarn run -T tsx ../../internal/scripts/workers/dev.ts",
"test-ci": "yarn run -T vitest run --passWithNoTests",
"test": "yarn run -T vitest --passWithNoTests",
"test-coverage": "yarn run -T vitest run --coverage --passWithNoTests",
"check-bundle-size": "yarn run -T tsx ../../internal/scripts/check-worker-bundle.ts --entry src/worker.ts --size-limit-bytes 350000",
"lint": "yarn run -T tsx ../../internal/scripts/lint.ts"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20250913.0",
"esbuild": "^0.25.6",
"lazyrepo": "0.0.0-alpha.27",
"typescript": "^5.8.3",
"wrangler": "^4.37.1"
}
}
Loading