@tldraw/editor 5.3.0-next.4123e97459a9 → 5.3.0-next.5cb71bb7e8fe

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.
Files changed (99) hide show
  1. package/dist-cjs/index.d.ts +115 -3
  2. package/dist-cjs/index.js +13 -3
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +24 -19
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/EditorPortal.js +44 -0
  7. package/dist-cjs/lib/components/EditorPortal.js.map +7 -0
  8. package/dist-cjs/lib/components/LiveCollaborators.js +102 -0
  9. package/dist-cjs/lib/components/LiveCollaborators.js.map +7 -0
  10. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +4 -10
  11. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +3 -3
  12. package/dist-cjs/lib/components/default-components/DefaultCursor.js +59 -0
  13. package/dist-cjs/lib/components/default-components/DefaultCursor.js.map +7 -0
  14. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +4 -4
  15. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
  16. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  17. package/dist-cjs/lib/hooks/EditorComponentsContext.js.map +2 -2
  18. package/dist-cjs/lib/hooks/useCursor.js +1 -0
  19. package/dist-cjs/lib/hooks/useCursor.js.map +2 -2
  20. package/dist-cjs/lib/hooks/useEditorComponents.js +2 -0
  21. package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
  22. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +49 -18
  23. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +3 -3
  24. package/dist-cjs/lib/hooks/useTransform.js +45 -0
  25. package/dist-cjs/lib/hooks/useTransform.js.map +7 -0
  26. package/dist-cjs/lib/license/LicenseManager.js +51 -2
  27. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  28. package/dist-cjs/lib/license/useLicenseManagerState.js +7 -0
  29. package/dist-cjs/lib/license/useLicenseManagerState.js.map +2 -2
  30. package/dist-cjs/lib/utils/collaborators.js +27 -0
  31. package/dist-cjs/lib/utils/collaborators.js.map +7 -0
  32. package/dist-cjs/lib/utils/getHtmlLayerTransform.js +33 -0
  33. package/dist-cjs/lib/utils/getHtmlLayerTransform.js.map +7 -0
  34. package/dist-cjs/version.js +3 -3
  35. package/dist-cjs/version.js.map +1 -1
  36. package/dist-esm/index.d.mts +115 -3
  37. package/dist-esm/index.mjs +19 -4
  38. package/dist-esm/index.mjs.map +2 -2
  39. package/dist-esm/lib/TldrawEditor.mjs +23 -18
  40. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  41. package/dist-esm/lib/components/EditorPortal.mjs +24 -0
  42. package/dist-esm/lib/components/EditorPortal.mjs.map +7 -0
  43. package/dist-esm/lib/components/LiveCollaborators.mjs +82 -0
  44. package/dist-esm/lib/components/LiveCollaborators.mjs.map +7 -0
  45. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +5 -11
  46. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  47. package/dist-esm/lib/components/default-components/DefaultCursor.mjs +29 -0
  48. package/dist-esm/lib/components/default-components/DefaultCursor.mjs.map +7 -0
  49. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +5 -5
  50. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
  51. package/dist-esm/lib/hooks/EditorComponentsContext.mjs.map +2 -2
  52. package/dist-esm/lib/hooks/useCursor.mjs +1 -0
  53. package/dist-esm/lib/hooks/useCursor.mjs.map +2 -2
  54. package/dist-esm/lib/hooks/useEditorComponents.mjs +2 -0
  55. package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
  56. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +50 -19
  57. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +3 -3
  58. package/dist-esm/lib/hooks/useTransform.mjs +25 -0
  59. package/dist-esm/lib/hooks/useTransform.mjs.map +7 -0
  60. package/dist-esm/lib/license/LicenseManager.mjs +52 -3
  61. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  62. package/dist-esm/lib/license/useLicenseManagerState.mjs +7 -0
  63. package/dist-esm/lib/license/useLicenseManagerState.mjs.map +2 -2
  64. package/dist-esm/lib/utils/collaborators.mjs +7 -0
  65. package/dist-esm/lib/utils/collaborators.mjs.map +7 -0
  66. package/dist-esm/lib/utils/getHtmlLayerTransform.mjs +13 -0
  67. package/dist-esm/lib/utils/getHtmlLayerTransform.mjs.map +7 -0
  68. package/dist-esm/version.mjs +3 -3
  69. package/dist-esm/version.mjs.map +1 -1
  70. package/editor.css +43 -4
  71. package/package.json +7 -7
  72. package/src/index.ts +14 -2
  73. package/src/lib/TldrawEditor.tsx +21 -13
  74. package/src/lib/components/EditorPortal.tsx +77 -0
  75. package/src/lib/components/LiveCollaborators.tsx +133 -0
  76. package/src/lib/components/default-components/DefaultCanvas.tsx +5 -17
  77. package/src/lib/components/default-components/DefaultCursor.tsx +65 -0
  78. package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.test.ts +46 -1
  79. package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +10 -5
  80. package/src/lib/editor/types/external-content.ts +5 -0
  81. package/src/lib/hooks/EditorComponentsContext.tsx +2 -0
  82. package/src/lib/hooks/useCursor.ts +1 -0
  83. package/src/lib/hooks/useEditorComponents.tsx +2 -0
  84. package/src/lib/hooks/usePassThroughWheelEvents.ts +83 -24
  85. package/src/lib/hooks/useTransform.ts +38 -0
  86. package/src/lib/license/LicenseManager.test.ts +146 -0
  87. package/src/lib/license/LicenseManager.ts +98 -2
  88. package/src/lib/license/useLicenseManagerState.ts +17 -1
  89. package/src/lib/test/EditorPortal.test.tsx +48 -0
  90. package/src/lib/test/usePassThroughWheelEvents.test.tsx +77 -0
  91. package/src/lib/utils/collaborators.test.ts +34 -0
  92. package/src/lib/utils/collaborators.ts +25 -0
  93. package/src/lib/utils/getHtmlLayerTransform.ts +22 -0
  94. package/src/version.ts +3 -3
  95. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +0 -51
  96. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +0 -7
  97. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +0 -31
  98. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +0 -7
  99. package/src/lib/hooks/usePassThroughMouseOverEvents.ts +0 -32
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/license/LicenseManager.ts"],
4
- "sourcesContent": ["import { atom } from '@tldraw/state'\nimport { publishDates, version } from '../../version'\nimport { getDefaultCdnBaseUrl } from '../utils/assets'\nimport { importPublicKey, str2ab } from '../utils/licensing'\n\nconst GRACE_PERIOD_DAYS = 30\n\nexport const FLAGS = {\n\t// -- MUTUALLY EXCLUSIVE FLAGS\n\t// Annual means the license expires after a time period, usually 1 year.\n\tANNUAL_LICENSE: 1,\n\t// Perpetual means the license never expires up to the max supported version.\n\tPERPETUAL_LICENSE: 1 << 1,\n\n\t// -- ADDITIVE FLAGS --\n\t// Internal means the license is for internal use only.\n\tINTERNAL_LICENSE: 1 << 2,\n\t// Watermark means the product is watermarked.\n\tWITH_WATERMARK: 1 << 3,\n\t// Evaluation means the license is for evaluation purposes only.\n\tEVALUATION_LICENSE: 1 << 4,\n\t// Native means the license is for native apps which switches\n\t// on special-case logic.\n\tNATIVE_LICENSE: 1 << 5,\n}\nconst HIGHEST_FLAG = Math.max(...Object.values(FLAGS))\n\nexport const PROPERTIES = {\n\tID: 0,\n\tHOSTS: 1,\n\tFLAGS: 2,\n\tEXPIRY_DATE: 3,\n}\nconst NUMBER_OF_KNOWN_PROPERTIES = Object.keys(PROPERTIES).length\n\nconst LICENSE_EMAIL = 'sales@tldraw.com'\n\nconst WATERMARK_TRACK_SRC = `${getDefaultCdnBaseUrl()}/watermarks/watermark-track.svg`\n\n/** @internal */\nexport interface LicenseInfo {\n\tid: string\n\thosts: string[]\n\tflags: number\n\texpiryDate: string\n}\n\n/** @internal */\nexport type LicenseState =\n\t| 'pending' // License validation is in progress\n\t| 'licensed' // License is valid and active (no restrictions)\n\t| 'licensed-with-watermark' // License is valid but shows watermark (evaluation licenses, WITH_WATERMARK licenses)\n\t| 'unlicensed' // No valid license found or license is invalid (development)\n\t| 'unlicensed-production' // No valid license in production deployment (missing, invalid, or wrong domain)\n\t| 'expired' // License has been expired (30 days past expiration for regular licenses, immediately for evaluation licenses)\n/** @internal */\nexport type InvalidLicenseReason =\n\t| 'invalid-license-key'\n\t| 'no-key-provided'\n\t| 'has-key-development-mode'\n\n/** @internal */\nexport type LicenseFromKeyResult = InvalidLicenseKeyResult | ValidLicenseKeyResult\n\n/** @internal */\nexport interface InvalidLicenseKeyResult {\n\tisLicenseParseable: false\n\treason: InvalidLicenseReason\n}\n\n/** @internal */\nexport interface ValidLicenseKeyResult {\n\tisLicenseParseable: true\n\tlicense: LicenseInfo\n\tisDevelopment: boolean\n\tisDomainValid: boolean\n\texpiryDate: Date\n\tisAnnualLicense: boolean\n\tisAnnualLicenseExpired: boolean\n\tisPerpetualLicense: boolean\n\tisPerpetualLicenseExpired: boolean\n\tisInternalLicense: boolean\n\tisNativeLicense: boolean\n\tisLicensedWithWatermark: boolean\n\tisEvaluationLicense: boolean\n\tisEvaluationLicenseExpired: boolean\n\tdaysSinceExpiry: number\n}\n\n/** @internal */\nexport type TrackType = 'unlicensed' | 'with_watermark' | 'evaluation' | null\n\n/** @internal */\nexport class LicenseManager {\n\tprivate publicKey =\n\t\t'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHJh0uUfxHtCGyerXmmatE368Hd9rI6LH9oPDQihnaCryRFWEVeOvf9U/SPbyxX74LFyJs5tYeAHq5Nc0Ax25LQ'\n\tpublic isDevelopment: boolean\n\tpublic isTest: boolean\n\tpublic isCryptoAvailable: boolean\n\tstate = atom<LicenseState>('license state', 'pending')\n\tpublic verbose = true\n\n\tconstructor(licenseKey: string | undefined, testPublicKey?: string) {\n\t\tthis.isTest = process.env.NODE_ENV === 'test'\n\t\tthis.isDevelopment = this.getIsDevelopment()\n\t\tthis.publicKey = testPublicKey || this.publicKey\n\t\tthis.isCryptoAvailable = !!crypto.subtle\n\n\t\tthis.getLicenseFromKey(licenseKey)\n\t\t\t.then((result) => {\n\t\t\t\tconst licenseState = getLicenseState(\n\t\t\t\t\tresult,\n\t\t\t\t\t(messages: string[]) => this.outputMessages(messages),\n\t\t\t\t\tthis.isDevelopment\n\t\t\t\t)\n\n\t\t\t\tthis.maybeTrack(result, licenseState)\n\n\t\t\t\tthis.state.set(licenseState)\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tconsole.error('License validation failed:', error)\n\t\t\t\tthis.state.set('unlicensed')\n\t\t\t})\n\t}\n\n\tprivate getIsDevelopment() {\n\t\t// If we are using https on a non-loopback domain we assume it's a production env and a development one otherwise\n\t\treturn (\n\t\t\t!['https:', 'vscode-webview:'].includes(window.location.protocol) ||\n\t\t\tthis.isLoopbackHost(window.location.hostname) ||\n\t\t\tprocess.env.NODE_ENV !== 'production'\n\t\t)\n\t}\n\n\tprivate isLoopbackHost(hostname: string) {\n\t\t// localhost, IPv4 loopback (127.0.0.0/8) and IPv6 loopback (::1) are all local development hosts\n\t\tconst host = hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n\t\treturn host === 'localhost' || host === '::1' || /^127(?:\\.\\d{1,3}){3}$/.test(host)\n\t}\n\n\tprivate getTrackType(result: LicenseFromKeyResult, licenseState: LicenseState): TrackType {\n\t\t// Track watermark for unlicensed production deployments\n\t\tif (licenseState === 'unlicensed-production') {\n\t\t\treturn 'unlicensed'\n\t\t}\n\n\t\tif (this.isDevelopment) {\n\t\t\treturn null\n\t\t}\n\n\t\tif (!result.isLicenseParseable) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Track evaluation licenses (for analytics, even though no watermark is shown)\n\t\tif (result.isEvaluationLicense) {\n\t\t\treturn 'evaluation'\n\t\t}\n\n\t\t// Track licenses that show watermarks\n\t\tif (licenseState === 'licensed-with-watermark') {\n\t\t\treturn 'with_watermark'\n\t\t}\n\n\t\treturn null\n\t}\n\n\tprivate maybeTrack(result: LicenseFromKeyResult, licenseState: LicenseState): void {\n\t\tconst trackType = this.getTrackType(result, licenseState)\n\t\tif (!trackType) {\n\t\t\treturn\n\t\t}\n\n\t\tconst url = new URL(WATERMARK_TRACK_SRC)\n\t\turl.searchParams.set('version', version)\n\t\turl.searchParams.set('license_type', trackType)\n\t\tif ('license' in result) {\n\t\t\turl.searchParams.set('license_id', result.license.id)\n\t\t\tconst sku = this.isFlagEnabled(result.license.flags, FLAGS.EVALUATION_LICENSE)\n\t\t\t\t? 'evaluation'\n\t\t\t\t: this.isFlagEnabled(result.license.flags, FLAGS.ANNUAL_LICENSE)\n\t\t\t\t\t? 'annual'\n\t\t\t\t\t: this.isFlagEnabled(result.license.flags, FLAGS.PERPETUAL_LICENSE)\n\t\t\t\t\t\t? 'perpetual'\n\t\t\t\t\t\t: 'unknown'\n\t\t\turl.searchParams.set('sku', sku)\n\t\t}\n\t\turl.searchParams.set('url', window.location.href)\n\t\tif (process.env.NODE_ENV) {\n\t\t\turl.searchParams.set('environment', process.env.NODE_ENV)\n\t\t}\n\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tfetch(url.toString())\n\t}\n\n\tprivate async extractLicenseKey(licenseKey: string): Promise<LicenseInfo> {\n\t\tconst [data, signature] = licenseKey.split('.')\n\t\tconst [prefix, encodedData] = data.split('/')\n\n\t\tif (!prefix.startsWith('tldraw-')) {\n\t\t\tthrow new Error(`Unsupported prefix '${prefix}'`)\n\t\t}\n\n\t\tconst publicCryptoKey = await importPublicKey(this.publicKey)\n\n\t\tlet isVerified\n\t\ttry {\n\t\t\tisVerified = await crypto.subtle.verify(\n\t\t\t\t{\n\t\t\t\t\tname: 'ECDSA',\n\t\t\t\t\thash: { name: 'SHA-256' },\n\t\t\t\t},\n\t\t\t\tpublicCryptoKey,\n\t\t\t\tnew Uint8Array(str2ab(atob(signature))),\n\t\t\t\tnew Uint8Array(str2ab(atob(encodedData)))\n\t\t\t)\n\t\t} catch (e) {\n\t\t\tconsole.error(e)\n\t\t\tthrow new Error('Could not perform signature validation')\n\t\t}\n\n\t\tif (!isVerified) {\n\t\t\tthrow new Error('Invalid signature')\n\t\t}\n\n\t\tlet decodedData: any\n\t\ttry {\n\t\t\tdecodedData = JSON.parse(atob(encodedData))\n\t\t} catch {\n\t\t\tthrow new Error('Could not parse object')\n\t\t}\n\t\tif (decodedData.length > NUMBER_OF_KNOWN_PROPERTIES) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'License key contains some unknown properties.',\n\t\t\t\t'You may want to update tldraw packages to a newer version to get access to new functionality.',\n\t\t\t])\n\t\t}\n\n\t\treturn {\n\t\t\tid: decodedData[PROPERTIES.ID],\n\t\t\thosts: decodedData[PROPERTIES.HOSTS],\n\t\t\tflags: decodedData[PROPERTIES.FLAGS],\n\t\t\texpiryDate: decodedData[PROPERTIES.EXPIRY_DATE],\n\t\t}\n\t}\n\n\tasync getLicenseFromKey(licenseKey?: string): Promise<LicenseFromKeyResult> {\n\t\tif (!licenseKey) {\n\t\t\tif (!this.isDevelopment) {\n\t\t\t\tthis.outputNoLicenseKeyProvided()\n\t\t\t}\n\n\t\t\treturn { isLicenseParseable: false, reason: 'no-key-provided' }\n\t\t}\n\n\t\tif (this.isDevelopment && !this.isCryptoAvailable) {\n\t\t\tif (this.verbose) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(\n\t\t\t\t\t'tldraw: you seem to be in a development environment that does not support crypto. License not verified.'\n\t\t\t\t)\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log('You should check that this works in production separately.')\n\t\t\t}\n\t\t\t// We can't parse the license if we are in development mode since crypto\n\t\t\t// is not available on http\n\t\t\treturn { isLicenseParseable: false, reason: 'has-key-development-mode' }\n\t\t}\n\n\t\t// Borrowed idea from AG Grid:\n\t\t// Copying from various sources (like PDFs) can include zero-width characters.\n\t\t// This helps makes sure the key validation doesn't fail.\n\t\tlet cleanedLicenseKey = licenseKey.replace(/[\\u200B-\\u200D\\uFEFF]/g, '')\n\t\tcleanedLicenseKey = cleanedLicenseKey.replace(/\\r?\\n|\\r/g, '')\n\n\t\ttry {\n\t\t\tconst licenseInfo = await this.extractLicenseKey(cleanedLicenseKey)\n\t\t\tconst expiryDate = new Date(licenseInfo.expiryDate)\n\t\t\tconst isAnnualLicense = this.isFlagEnabled(licenseInfo.flags, FLAGS.ANNUAL_LICENSE)\n\t\t\tconst isPerpetualLicense = this.isFlagEnabled(licenseInfo.flags, FLAGS.PERPETUAL_LICENSE)\n\t\t\tconst isEvaluationLicense = this.isFlagEnabled(licenseInfo.flags, FLAGS.EVALUATION_LICENSE)\n\n\t\t\tconst isAnnualLicenseExpired = isAnnualLicense && this.isAnnualLicenseExpired(expiryDate)\n\t\t\tconst isPerpetualLicenseExpired =\n\t\t\t\tisPerpetualLicense && this.isPerpetualLicenseExpired(expiryDate)\n\n\t\t\t// For perpetual licenses, the calendar expiry date only gates access to future\n\t\t\t// major/minor releases; it does not \"expire\" the license itself. While the user\n\t\t\t// is still on a covered version we report `daysSinceExpiry` as 0 so consumers\n\t\t\t// (and the grace-period warning) don't treat them as past expiry.\n\t\t\tconst daysSinceExpiry =\n\t\t\t\tisPerpetualLicense && !isPerpetualLicenseExpired ? 0 : this.getDaysSinceExpiry(expiryDate)\n\n\t\t\tconst result: ValidLicenseKeyResult = {\n\t\t\t\tlicense: licenseInfo,\n\t\t\t\tisLicenseParseable: true,\n\t\t\t\tisDevelopment: this.isDevelopment,\n\t\t\t\tisDomainValid: this.isDomainValid(licenseInfo),\n\t\t\t\texpiryDate,\n\t\t\t\tisAnnualLicense,\n\t\t\t\tisAnnualLicenseExpired,\n\t\t\t\tisPerpetualLicense,\n\t\t\t\tisPerpetualLicenseExpired,\n\t\t\t\tisInternalLicense: this.isFlagEnabled(licenseInfo.flags, FLAGS.INTERNAL_LICENSE),\n\t\t\t\tisNativeLicense: this.isNativeLicense(licenseInfo),\n\t\t\t\tisLicensedWithWatermark: this.isFlagEnabled(licenseInfo.flags, FLAGS.WITH_WATERMARK),\n\t\t\t\tisEvaluationLicense,\n\t\t\t\tisEvaluationLicenseExpired:\n\t\t\t\t\tisEvaluationLicense && this.isEvaluationLicenseExpired(expiryDate),\n\t\t\t\tdaysSinceExpiry,\n\t\t\t}\n\t\t\tthis.outputLicenseInfoIfNeeded(result)\n\n\t\t\treturn result\n\t\t} catch (e: any) {\n\t\t\tthis.outputInvalidLicenseKey(e.message)\n\t\t\t// If the license can't be parsed, it's invalid\n\t\t\treturn { isLicenseParseable: false, reason: 'invalid-license-key' }\n\t\t}\n\t}\n\n\tprivate isDomainValid(licenseInfo: LicenseInfo) {\n\t\tconst currentHostname = window.location.hostname.toLowerCase()\n\n\t\treturn licenseInfo.hosts.some((host) => {\n\t\t\tconst normalizedHostOrUrlRegex = host.toLowerCase().trim()\n\n\t\t\t// Allow the domain if listed and www variations, 'example.com' allows 'example.com' and 'www.example.com'\n\t\t\tif (\n\t\t\t\tnormalizedHostOrUrlRegex === currentHostname ||\n\t\t\t\t`www.${normalizedHostOrUrlRegex}` === currentHostname ||\n\t\t\t\tnormalizedHostOrUrlRegex === `www.${currentHostname}`\n\t\t\t) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// If host is '*', we allow all domains.\n\t\t\tif (host === '*') {\n\t\t\t\t// All domains allowed.\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// Native license support\n\t\t\t// In this case, `normalizedHost` is actually a protocol, e.g. `app-bundle:`\n\t\t\tif (this.isNativeLicense(licenseInfo)) {\n\t\t\t\treturn new RegExp(normalizedHostOrUrlRegex).test(window.location.href)\n\t\t\t}\n\n\t\t\t// Glob testing, we only support '*.somedomain.com' right now.\n\t\t\tif (host.includes('*')) {\n\t\t\t\tconst globToRegex = new RegExp(host.replace(/\\*/g, '.*?'))\n\t\t\t\treturn globToRegex.test(currentHostname) || globToRegex.test(`www.${currentHostname}`)\n\t\t\t}\n\n\t\t\t// VSCode support\n\t\t\tif (window.location.protocol === 'vscode-webview:') {\n\t\t\t\tconst currentUrl = new URL(window.location.href)\n\t\t\t\tconst extensionId = currentUrl.searchParams.get('extensionId')\n\t\t\t\tif (normalizedHostOrUrlRegex === extensionId) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false\n\t\t})\n\t}\n\n\tprivate isNativeLicense(licenseInfo: LicenseInfo) {\n\t\treturn this.isFlagEnabled(licenseInfo.flags, FLAGS.NATIVE_LICENSE)\n\t}\n\n\tprivate getExpirationDateWithoutGracePeriod(expiryDate: Date) {\n\t\t// The named expiry date is the last day the license is fully usable, so the license\n\t\t// expires at the end of that day, i.e. the start of the following day. We work in UTC\n\t\t// (the expiry date is minted and parsed as a UTC date-only string) so the cutoff is a\n\t\t// single predictable instant for every user regardless of their local timezone.\n\t\treturn new Date(\n\t\t\tDate.UTC(\n\t\t\t\texpiryDate.getUTCFullYear(),\n\t\t\t\texpiryDate.getUTCMonth(),\n\t\t\t\texpiryDate.getUTCDate() + 1 // Add 1 day so the named date is fully usable\n\t\t\t)\n\t\t)\n\t}\n\n\tprivate getExpirationDateWithGracePeriod(expiryDate: Date) {\n\t\treturn new Date(\n\t\t\tDate.UTC(\n\t\t\t\texpiryDate.getUTCFullYear(),\n\t\t\t\texpiryDate.getUTCMonth(),\n\t\t\t\texpiryDate.getUTCDate() + GRACE_PERIOD_DAYS + 1 // Add 1 day to include the expiration day\n\t\t\t)\n\t\t)\n\t}\n\n\tprivate isAnnualLicenseExpired(expiryDate: Date) {\n\t\tconst expiration = this.getExpirationDateWithGracePeriod(expiryDate)\n\t\treturn new Date() >= expiration\n\t}\n\n\tprivate isPerpetualLicenseExpired(expiryDate: Date) {\n\t\tconst expiration = this.getExpirationDateWithGracePeriod(expiryDate)\n\t\tconst dates = {\n\t\t\tmajor: new Date(publishDates.major),\n\t\t\tminor: new Date(publishDates.minor),\n\t\t}\n\t\t// We allow patch releases, but the major and minor releases should be within the expiration date\n\t\treturn dates.major >= expiration || dates.minor >= expiration\n\t}\n\n\tprivate getDaysSinceExpiry(expiryDate: Date): number {\n\t\tconst now = new Date()\n\t\tconst expiration = this.getExpirationDateWithoutGracePeriod(expiryDate)\n\t\tconst diffTime = now.getTime() - expiration.getTime()\n\t\tconst diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24))\n\t\treturn Math.max(0, diffDays)\n\t}\n\n\tprivate isEvaluationLicenseExpired(expiryDate: Date): boolean {\n\t\t// Evaluation licenses have no grace period - they expire immediately\n\t\tconst now = new Date()\n\t\tconst expiration = this.getExpirationDateWithoutGracePeriod(expiryDate)\n\t\treturn now >= expiration\n\t}\n\n\tprivate isFlagEnabled(flags: number, flag: number) {\n\t\treturn (flags & flag) === flag\n\t}\n\n\tprivate outputNoLicenseKeyProvided() {\n\t\t// Noop, we don't need to show this message.\n\t\t// this.outputMessages([\n\t\t// \t'No tldraw license key provided!',\n\t\t// \t`Please reach out to ${LICENSE_EMAIL} if you would like to license tldraw or if you'd like a trial.`,\n\t\t// ])\n\t}\n\n\tprivate outputInvalidLicenseKey(msg: string) {\n\t\tthis.outputMessages(['Invalid tldraw license key', `Reason: ${msg}`])\n\t}\n\n\tprivate outputLicenseInfoIfNeeded(result: ValidLicenseKeyResult) {\n\t\t// If we added a new flag it will be twice the value of the currently highest flag.\n\t\t// And if all the current flags are on we would get the `HIGHEST_FLAG * 2 - 1`, so anything higher than that means there are new flags.\n\t\tif (result.license.flags >= HIGHEST_FLAG * 2) {\n\t\t\tthis.outputMessages(\n\t\t\t\t[\n\t\t\t\t\t'Warning: This tldraw license contains some unknown flags.',\n\t\t\t\t\t'This will still work, however, you may want to update tldraw packages to a newer version to get access to new functionality.',\n\t\t\t\t],\n\t\t\t\t'warning'\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate outputMessages(messages: string[], type: 'warning' | 'error' = 'error') {\n\t\tif (this.isTest) return\n\t\tif (this.verbose) {\n\t\t\tthis.outputDelimiter(type)\n\t\t\tfor (const message of messages) {\n\t\t\t\tconst bgColor = type === 'warning' ? 'orange' : 'crimson'\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(\n\t\t\t\t\t`%c${message}`,\n\t\t\t\t\t`color: white; background: ${bgColor}; padding: 2px; border-radius: 3px;`\n\t\t\t\t)\n\t\t\t}\n\t\t\tthis.outputDelimiter(type)\n\t\t}\n\t}\n\n\tprivate outputDelimiter(type: 'warning' | 'error' = 'error') {\n\t\tconst bgColor = type === 'warning' ? 'orange' : 'crimson'\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(\n\t\t\t'%c-------------------------------------------------------------------',\n\t\t\t`color: white; background: ${bgColor}; padding: 2px; border-radius: 3px;`\n\t\t)\n\t}\n\n\tstatic className = 'tl-watermark_SEE-LICENSE'\n}\n\nexport function getLicenseState(\n\tresult: LicenseFromKeyResult,\n\toutputMessages: (messages: string[]) => void,\n\tisDevelopment: boolean\n): LicenseState {\n\tif (!result.isLicenseParseable) {\n\t\tif (isDevelopment) {\n\t\t\treturn 'unlicensed'\n\t\t}\n\n\t\t// All unlicensed scenarios should not work in production\n\t\tif (result.reason === 'no-key-provided') {\n\t\t\toutputMessages([\n\t\t\t\t'No tldraw license key provided!',\n\t\t\t\t'A license is required for production deployments.',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} to purchase a license.`,\n\t\t\t])\n\t\t} else {\n\t\t\toutputMessages([\n\t\t\t\t'Invalid license key. tldraw requires a valid license for production use.',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} to purchase a license.`,\n\t\t\t])\n\t\t}\n\t\treturn 'unlicensed-production'\n\t}\n\n\tif (!result.isDomainValid && !result.isDevelopment) {\n\t\toutputMessages([\n\t\t\t'License key is not valid for this domain.',\n\t\t\t'A license is required for production deployments.',\n\t\t\t`Please reach out to ${LICENSE_EMAIL} to purchase a license.`,\n\t\t])\n\t\treturn 'unlicensed-production'\n\t}\n\n\t// Handle evaluation licenses - they expire immediately with no grace period\n\tif (result.isEvaluationLicense) {\n\t\tif (result.isEvaluationLicenseExpired) {\n\t\t\toutputMessages([\n\t\t\t\t'Your tldraw evaluation license has expired!',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} to purchase a full license.`,\n\t\t\t])\n\t\t\treturn 'expired'\n\t\t} else {\n\t\t\t// Valid evaluation license - tracked but no watermark shown\n\t\t\treturn 'licensed'\n\t\t}\n\t}\n\n\t// Handle expired regular licenses (both annual and perpetual)\n\tif (result.isPerpetualLicenseExpired || result.isAnnualLicenseExpired) {\n\t\toutputMessages([\n\t\t\t'Your tldraw license has been expired for more than 30 days!',\n\t\t\t`Please reach out to ${LICENSE_EMAIL} to renew your license.`,\n\t\t])\n\t\treturn 'expired'\n\t}\n\n\t// Check if license is past expiry date but within grace period\n\tconst daysSinceExpiry = result.daysSinceExpiry\n\tif (daysSinceExpiry > 0 && !result.isEvaluationLicense) {\n\t\toutputMessages([\n\t\t\t'Your tldraw license has expired.',\n\t\t\t`License expired ${daysSinceExpiry} days ago.`,\n\t\t\t`Please reach out to ${LICENSE_EMAIL} to renew your license.`,\n\t\t])\n\t\t// Within 30-day grace period: still licensed (no watermark)\n\t\treturn 'licensed'\n\t}\n\n\t// License is valid, determine if it has watermark\n\tif (result.isLicensedWithWatermark) {\n\t\treturn 'licensed-with-watermark'\n\t}\n\n\treturn 'licensed'\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { atom, transact } from '@tldraw/state'\nimport { publishDates, version } from '../../version'\nimport { getDefaultCdnBaseUrl } from '../utils/assets'\nimport { importPublicKey, str2ab } from '../utils/licensing'\n\nconst GRACE_PERIOD_DAYS = 30\n\nexport const FLAGS = {\n\t// -- MUTUALLY EXCLUSIVE FLAGS\n\t// Annual means the license expires after a time period, usually 1 year.\n\tANNUAL_LICENSE: 1,\n\t// Perpetual means the license never expires up to the max supported version.\n\tPERPETUAL_LICENSE: 1 << 1,\n\n\t// -- ADDITIVE FLAGS --\n\t// Internal means the license is for internal use only.\n\tINTERNAL_LICENSE: 1 << 2,\n\t// Watermark means the product is watermarked.\n\tWITH_WATERMARK: 1 << 3,\n\t// Evaluation means the license is for evaluation purposes only.\n\tEVALUATION_LICENSE: 1 << 4,\n\t// Native means the license is for native apps which switches\n\t// on special-case logic.\n\tNATIVE_LICENSE: 1 << 5,\n\n\t// -- FEATURE FLAGS --\n\t// Collaboration is the umbrella flag for collaboration features; it grants all sub-features.\n\tFEAT_COLLABORATION: 1 << 6,\n\t// Commenting is the first sub-feature of collaboration.\n\tFEAT_COMMENTING: 1 << 7,\n}\nconst HIGHEST_FLAG = Math.max(...Object.values(FLAGS))\n\nexport const PROPERTIES = {\n\tID: 0,\n\tHOSTS: 1,\n\tFLAGS: 2,\n\tEXPIRY_DATE: 3,\n}\nconst NUMBER_OF_KNOWN_PROPERTIES = Object.keys(PROPERTIES).length\n\nconst LICENSE_EMAIL = 'sales@tldraw.com'\n\nconst WATERMARK_TRACK_SRC = `${getDefaultCdnBaseUrl()}/watermarks/watermark-track.svg`\n\n/** @internal */\nexport interface LicenseInfo {\n\tid: string\n\thosts: string[]\n\tflags: number\n\texpiryDate: string\n}\n\n/**\n * Names of the licensable product features gated by the license. `collaboration` is an umbrella\n * that also grants all of its sub-features (currently just `commenting`).\n *\n * @internal\n */\nexport type LicenseFeatureName = 'collaboration' | 'commenting'\n\nconst NO_FEATURES: Readonly<Record<LicenseFeatureName, boolean>> = {\n\tcollaboration: false,\n\tcommenting: false,\n}\nconst ALL_FEATURES: Readonly<Record<LicenseFeatureName, boolean>> = {\n\tcollaboration: true,\n\tcommenting: true,\n}\n\n/** @internal */\nexport type LicenseState =\n\t| 'pending' // License validation is in progress\n\t| 'licensed' // License is valid and active (no restrictions)\n\t| 'licensed-with-watermark' // License is valid but shows watermark (evaluation licenses, WITH_WATERMARK licenses)\n\t| 'unlicensed' // No valid license found or license is invalid (development)\n\t| 'unlicensed-production' // No valid license in production deployment (missing, invalid, or wrong domain)\n\t| 'expired' // License has been expired (30 days past expiration for regular licenses, immediately for evaluation licenses)\n/** @internal */\nexport type InvalidLicenseReason =\n\t| 'invalid-license-key'\n\t| 'no-key-provided'\n\t| 'has-key-development-mode'\n\n/** @internal */\nexport type LicenseFromKeyResult = InvalidLicenseKeyResult | ValidLicenseKeyResult\n\n/** @internal */\nexport interface InvalidLicenseKeyResult {\n\tisLicenseParseable: false\n\treason: InvalidLicenseReason\n}\n\n/** @internal */\nexport interface ValidLicenseKeyResult {\n\tisLicenseParseable: true\n\tlicense: LicenseInfo\n\tisDevelopment: boolean\n\tisDomainValid: boolean\n\texpiryDate: Date\n\tisAnnualLicense: boolean\n\tisAnnualLicenseExpired: boolean\n\tisPerpetualLicense: boolean\n\tisPerpetualLicenseExpired: boolean\n\tisInternalLicense: boolean\n\tisNativeLicense: boolean\n\tisLicensedWithWatermark: boolean\n\tisEvaluationLicense: boolean\n\tisEvaluationLicenseExpired: boolean\n\tisCollaborationEnabled: boolean\n\tisCommentingEnabled: boolean\n\tdaysSinceExpiry: number\n}\n\n/** @internal */\nexport type TrackType = 'unlicensed' | 'with_watermark' | 'evaluation' | null\n\n/** @internal */\nexport class LicenseManager {\n\tprivate publicKey =\n\t\t'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHJh0uUfxHtCGyerXmmatE368Hd9rI6LH9oPDQihnaCryRFWEVeOvf9U/SPbyxX74LFyJs5tYeAHq5Nc0Ax25LQ'\n\tpublic isDevelopment: boolean\n\tpublic isTest: boolean\n\tpublic isCryptoAvailable: boolean\n\tstate = atom<LicenseState>('license state', 'pending')\n\tfeatureFlags = atom<Record<LicenseFeatureName, boolean>>('license feature flags', {\n\t\t...NO_FEATURES,\n\t})\n\tpublic verbose = true\n\n\tconstructor(licenseKey: string | undefined, testPublicKey?: string) {\n\t\tthis.isTest = process.env.NODE_ENV === 'test'\n\t\tthis.isDevelopment = this.getIsDevelopment()\n\t\tthis.publicKey = testPublicKey || this.publicKey\n\t\tthis.isCryptoAvailable = !!crypto.subtle\n\n\t\t// In development every feature is enabled (see `getEnabledFeatures`), and that doesn't depend\n\t\t// on the async validation result. Reflect it eagerly so features aren't reported as disabled\n\t\t// during the validation window \u2014 or left disabled if validation rejects (the `.catch` below\n\t\t// never sets `featureFlags`). In production the fail-closed default stands until validation.\n\t\tif (this.isDevelopment) {\n\t\t\tthis.featureFlags.set({ ...ALL_FEATURES })\n\t\t}\n\n\t\tthis.getLicenseFromKey(licenseKey)\n\t\t\t.then((result) => {\n\t\t\t\tconst licenseState = getLicenseState(\n\t\t\t\t\tresult,\n\t\t\t\t\t(messages: string[]) => this.outputMessages(messages),\n\t\t\t\t\tthis.isDevelopment\n\t\t\t\t)\n\n\t\t\t\tthis.maybeTrack(result, licenseState)\n\n\t\t\t\t// Update both atoms atomically so dependents never observe the license state and the\n\t\t\t\t// feature flags out of sync mid-update.\n\t\t\t\ttransact(() => {\n\t\t\t\t\tthis.state.set(licenseState)\n\t\t\t\t\tthis.featureFlags.set(getEnabledFeatures(result, licenseState, this.isDevelopment))\n\t\t\t\t})\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tconsole.error('License validation failed:', error)\n\t\t\t\tthis.state.set('unlicensed')\n\t\t\t})\n\t}\n\n\t/**\n\t * Returns whether a given licensable feature is enabled. Reactive: reading this inside a signal\n\t * recomputes when license validation resolves.\n\t */\n\tisFeatureEnabled(feature: LicenseFeatureName): boolean {\n\t\treturn this.featureFlags.get()[feature]\n\t}\n\n\tprivate getIsDevelopment() {\n\t\t// If we are using https on a non-loopback domain we assume it's a production env and a development one otherwise\n\t\treturn (\n\t\t\t!['https:', 'vscode-webview:'].includes(window.location.protocol) ||\n\t\t\tthis.isLoopbackHost(window.location.hostname) ||\n\t\t\tprocess.env.NODE_ENV !== 'production'\n\t\t)\n\t}\n\n\tprivate isLoopbackHost(hostname: string) {\n\t\t// localhost, IPv4 loopback (127.0.0.0/8) and IPv6 loopback (::1) are all local development hosts\n\t\tconst host = hostname.toLowerCase().replace(/^\\[|\\]$/g, '')\n\t\treturn host === 'localhost' || host === '::1' || /^127(?:\\.\\d{1,3}){3}$/.test(host)\n\t}\n\n\tprivate getTrackType(result: LicenseFromKeyResult, licenseState: LicenseState): TrackType {\n\t\t// Track watermark for unlicensed production deployments\n\t\tif (licenseState === 'unlicensed-production') {\n\t\t\treturn 'unlicensed'\n\t\t}\n\n\t\tif (this.isDevelopment) {\n\t\t\treturn null\n\t\t}\n\n\t\tif (!result.isLicenseParseable) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Track evaluation licenses (for analytics, even though no watermark is shown)\n\t\tif (result.isEvaluationLicense) {\n\t\t\treturn 'evaluation'\n\t\t}\n\n\t\t// Track licenses that show watermarks\n\t\tif (licenseState === 'licensed-with-watermark') {\n\t\t\treturn 'with_watermark'\n\t\t}\n\n\t\treturn null\n\t}\n\n\tprivate maybeTrack(result: LicenseFromKeyResult, licenseState: LicenseState): void {\n\t\tconst trackType = this.getTrackType(result, licenseState)\n\t\tif (!trackType) {\n\t\t\treturn\n\t\t}\n\n\t\tconst url = new URL(WATERMARK_TRACK_SRC)\n\t\turl.searchParams.set('version', version)\n\t\turl.searchParams.set('license_type', trackType)\n\t\tif ('license' in result) {\n\t\t\turl.searchParams.set('license_id', result.license.id)\n\t\t\tconst sku = this.isFlagEnabled(result.license.flags, FLAGS.EVALUATION_LICENSE)\n\t\t\t\t? 'evaluation'\n\t\t\t\t: this.isFlagEnabled(result.license.flags, FLAGS.ANNUAL_LICENSE)\n\t\t\t\t\t? 'annual'\n\t\t\t\t\t: this.isFlagEnabled(result.license.flags, FLAGS.PERPETUAL_LICENSE)\n\t\t\t\t\t\t? 'perpetual'\n\t\t\t\t\t\t: 'unknown'\n\t\t\turl.searchParams.set('sku', sku)\n\t\t}\n\t\turl.searchParams.set('url', window.location.href)\n\t\tif (process.env.NODE_ENV) {\n\t\t\turl.searchParams.set('environment', process.env.NODE_ENV)\n\t\t}\n\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tfetch(url.toString())\n\t}\n\n\tprivate async extractLicenseKey(licenseKey: string): Promise<LicenseInfo> {\n\t\tconst [data, signature] = licenseKey.split('.')\n\t\tconst [prefix, encodedData] = data.split('/')\n\n\t\tif (!prefix.startsWith('tldraw-')) {\n\t\t\tthrow new Error(`Unsupported prefix '${prefix}'`)\n\t\t}\n\n\t\tconst publicCryptoKey = await importPublicKey(this.publicKey)\n\n\t\tlet isVerified\n\t\ttry {\n\t\t\tisVerified = await crypto.subtle.verify(\n\t\t\t\t{\n\t\t\t\t\tname: 'ECDSA',\n\t\t\t\t\thash: { name: 'SHA-256' },\n\t\t\t\t},\n\t\t\t\tpublicCryptoKey,\n\t\t\t\tnew Uint8Array(str2ab(atob(signature))),\n\t\t\t\tnew Uint8Array(str2ab(atob(encodedData)))\n\t\t\t)\n\t\t} catch (e) {\n\t\t\tconsole.error(e)\n\t\t\tthrow new Error('Could not perform signature validation')\n\t\t}\n\n\t\tif (!isVerified) {\n\t\t\tthrow new Error('Invalid signature')\n\t\t}\n\n\t\tlet decodedData: any\n\t\ttry {\n\t\t\tdecodedData = JSON.parse(atob(encodedData))\n\t\t} catch {\n\t\t\tthrow new Error('Could not parse object')\n\t\t}\n\t\tif (decodedData.length > NUMBER_OF_KNOWN_PROPERTIES) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'License key contains some unknown properties.',\n\t\t\t\t'You may want to update tldraw packages to a newer version to get access to new functionality.',\n\t\t\t])\n\t\t}\n\n\t\treturn {\n\t\t\tid: decodedData[PROPERTIES.ID],\n\t\t\thosts: decodedData[PROPERTIES.HOSTS],\n\t\t\tflags: decodedData[PROPERTIES.FLAGS],\n\t\t\texpiryDate: decodedData[PROPERTIES.EXPIRY_DATE],\n\t\t}\n\t}\n\n\tasync getLicenseFromKey(licenseKey?: string): Promise<LicenseFromKeyResult> {\n\t\tif (!licenseKey) {\n\t\t\tif (!this.isDevelopment) {\n\t\t\t\tthis.outputNoLicenseKeyProvided()\n\t\t\t}\n\n\t\t\treturn { isLicenseParseable: false, reason: 'no-key-provided' }\n\t\t}\n\n\t\tif (this.isDevelopment && !this.isCryptoAvailable) {\n\t\t\tif (this.verbose) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(\n\t\t\t\t\t'tldraw: you seem to be in a development environment that does not support crypto. License not verified.'\n\t\t\t\t)\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log('You should check that this works in production separately.')\n\t\t\t}\n\t\t\t// We can't parse the license if we are in development mode since crypto\n\t\t\t// is not available on http\n\t\t\treturn { isLicenseParseable: false, reason: 'has-key-development-mode' }\n\t\t}\n\n\t\t// Borrowed idea from AG Grid:\n\t\t// Copying from various sources (like PDFs) can include zero-width characters.\n\t\t// This helps makes sure the key validation doesn't fail.\n\t\tlet cleanedLicenseKey = licenseKey.replace(/[\\u200B-\\u200D\\uFEFF]/g, '')\n\t\tcleanedLicenseKey = cleanedLicenseKey.replace(/\\r?\\n|\\r/g, '')\n\n\t\ttry {\n\t\t\tconst licenseInfo = await this.extractLicenseKey(cleanedLicenseKey)\n\t\t\tconst expiryDate = new Date(licenseInfo.expiryDate)\n\t\t\tconst isAnnualLicense = this.isFlagEnabled(licenseInfo.flags, FLAGS.ANNUAL_LICENSE)\n\t\t\tconst isPerpetualLicense = this.isFlagEnabled(licenseInfo.flags, FLAGS.PERPETUAL_LICENSE)\n\t\t\tconst isEvaluationLicense = this.isFlagEnabled(licenseInfo.flags, FLAGS.EVALUATION_LICENSE)\n\n\t\t\tconst isAnnualLicenseExpired = isAnnualLicense && this.isAnnualLicenseExpired(expiryDate)\n\t\t\tconst isPerpetualLicenseExpired =\n\t\t\t\tisPerpetualLicense && this.isPerpetualLicenseExpired(expiryDate)\n\n\t\t\t// The collaboration umbrella grants all of its sub-features, so commenting is enabled\n\t\t\t// by either the commenting flag or the collaboration flag.\n\t\t\tconst isCollaborationEnabled = this.isFlagEnabled(licenseInfo.flags, FLAGS.FEAT_COLLABORATION)\n\t\t\tconst isCommentingEnabled =\n\t\t\t\tisCollaborationEnabled || this.isFlagEnabled(licenseInfo.flags, FLAGS.FEAT_COMMENTING)\n\n\t\t\t// For perpetual licenses, the calendar expiry date only gates access to future\n\t\t\t// major/minor releases; it does not \"expire\" the license itself. While the user\n\t\t\t// is still on a covered version we report `daysSinceExpiry` as 0 so consumers\n\t\t\t// (and the grace-period warning) don't treat them as past expiry.\n\t\t\tconst daysSinceExpiry =\n\t\t\t\tisPerpetualLicense && !isPerpetualLicenseExpired ? 0 : this.getDaysSinceExpiry(expiryDate)\n\n\t\t\tconst result: ValidLicenseKeyResult = {\n\t\t\t\tlicense: licenseInfo,\n\t\t\t\tisLicenseParseable: true,\n\t\t\t\tisDevelopment: this.isDevelopment,\n\t\t\t\tisDomainValid: this.isDomainValid(licenseInfo),\n\t\t\t\texpiryDate,\n\t\t\t\tisAnnualLicense,\n\t\t\t\tisAnnualLicenseExpired,\n\t\t\t\tisPerpetualLicense,\n\t\t\t\tisPerpetualLicenseExpired,\n\t\t\t\tisInternalLicense: this.isFlagEnabled(licenseInfo.flags, FLAGS.INTERNAL_LICENSE),\n\t\t\t\tisNativeLicense: this.isNativeLicense(licenseInfo),\n\t\t\t\tisLicensedWithWatermark: this.isFlagEnabled(licenseInfo.flags, FLAGS.WITH_WATERMARK),\n\t\t\t\tisEvaluationLicense,\n\t\t\t\tisEvaluationLicenseExpired:\n\t\t\t\t\tisEvaluationLicense && this.isEvaluationLicenseExpired(expiryDate),\n\t\t\t\tisCollaborationEnabled,\n\t\t\t\tisCommentingEnabled,\n\t\t\t\tdaysSinceExpiry,\n\t\t\t}\n\t\t\tthis.outputLicenseInfoIfNeeded(result)\n\n\t\t\treturn result\n\t\t} catch (e: any) {\n\t\t\tthis.outputInvalidLicenseKey(e.message)\n\t\t\t// If the license can't be parsed, it's invalid\n\t\t\treturn { isLicenseParseable: false, reason: 'invalid-license-key' }\n\t\t}\n\t}\n\n\tprivate isDomainValid(licenseInfo: LicenseInfo) {\n\t\tconst currentHostname = window.location.hostname.toLowerCase()\n\n\t\treturn licenseInfo.hosts.some((host) => {\n\t\t\tconst normalizedHostOrUrlRegex = host.toLowerCase().trim()\n\n\t\t\t// Allow the domain if listed and www variations, 'example.com' allows 'example.com' and 'www.example.com'\n\t\t\tif (\n\t\t\t\tnormalizedHostOrUrlRegex === currentHostname ||\n\t\t\t\t`www.${normalizedHostOrUrlRegex}` === currentHostname ||\n\t\t\t\tnormalizedHostOrUrlRegex === `www.${currentHostname}`\n\t\t\t) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// If host is '*', we allow all domains.\n\t\t\tif (host === '*') {\n\t\t\t\t// All domains allowed.\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// Native license support\n\t\t\t// In this case, `normalizedHost` is actually a protocol, e.g. `app-bundle:`\n\t\t\tif (this.isNativeLicense(licenseInfo)) {\n\t\t\t\treturn new RegExp(normalizedHostOrUrlRegex).test(window.location.href)\n\t\t\t}\n\n\t\t\t// Glob testing, we only support '*.somedomain.com' right now.\n\t\t\tif (host.includes('*')) {\n\t\t\t\tconst globToRegex = new RegExp(host.replace(/\\*/g, '.*?'))\n\t\t\t\treturn globToRegex.test(currentHostname) || globToRegex.test(`www.${currentHostname}`)\n\t\t\t}\n\n\t\t\t// VSCode support\n\t\t\tif (window.location.protocol === 'vscode-webview:') {\n\t\t\t\tconst currentUrl = new URL(window.location.href)\n\t\t\t\tconst extensionId = currentUrl.searchParams.get('extensionId')\n\t\t\t\tif (normalizedHostOrUrlRegex === extensionId) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false\n\t\t})\n\t}\n\n\tprivate isNativeLicense(licenseInfo: LicenseInfo) {\n\t\treturn this.isFlagEnabled(licenseInfo.flags, FLAGS.NATIVE_LICENSE)\n\t}\n\n\tprivate getExpirationDateWithoutGracePeriod(expiryDate: Date) {\n\t\t// The named expiry date is the last day the license is fully usable, so the license\n\t\t// expires at the end of that day, i.e. the start of the following day. We work in UTC\n\t\t// (the expiry date is minted and parsed as a UTC date-only string) so the cutoff is a\n\t\t// single predictable instant for every user regardless of their local timezone.\n\t\treturn new Date(\n\t\t\tDate.UTC(\n\t\t\t\texpiryDate.getUTCFullYear(),\n\t\t\t\texpiryDate.getUTCMonth(),\n\t\t\t\texpiryDate.getUTCDate() + 1 // Add 1 day so the named date is fully usable\n\t\t\t)\n\t\t)\n\t}\n\n\tprivate getExpirationDateWithGracePeriod(expiryDate: Date) {\n\t\treturn new Date(\n\t\t\tDate.UTC(\n\t\t\t\texpiryDate.getUTCFullYear(),\n\t\t\t\texpiryDate.getUTCMonth(),\n\t\t\t\texpiryDate.getUTCDate() + GRACE_PERIOD_DAYS + 1 // Add 1 day to include the expiration day\n\t\t\t)\n\t\t)\n\t}\n\n\tprivate isAnnualLicenseExpired(expiryDate: Date) {\n\t\tconst expiration = this.getExpirationDateWithGracePeriod(expiryDate)\n\t\treturn new Date() >= expiration\n\t}\n\n\tprivate isPerpetualLicenseExpired(expiryDate: Date) {\n\t\tconst expiration = this.getExpirationDateWithGracePeriod(expiryDate)\n\t\tconst dates = {\n\t\t\tmajor: new Date(publishDates.major),\n\t\t\tminor: new Date(publishDates.minor),\n\t\t}\n\t\t// We allow patch releases, but the major and minor releases should be within the expiration date\n\t\treturn dates.major >= expiration || dates.minor >= expiration\n\t}\n\n\tprivate getDaysSinceExpiry(expiryDate: Date): number {\n\t\tconst now = new Date()\n\t\tconst expiration = this.getExpirationDateWithoutGracePeriod(expiryDate)\n\t\tconst diffTime = now.getTime() - expiration.getTime()\n\t\tconst diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24))\n\t\treturn Math.max(0, diffDays)\n\t}\n\n\tprivate isEvaluationLicenseExpired(expiryDate: Date): boolean {\n\t\t// Evaluation licenses have no grace period - they expire immediately\n\t\tconst now = new Date()\n\t\tconst expiration = this.getExpirationDateWithoutGracePeriod(expiryDate)\n\t\treturn now >= expiration\n\t}\n\n\tprivate isFlagEnabled(flags: number, flag: number) {\n\t\treturn (flags & flag) === flag\n\t}\n\n\tprivate outputNoLicenseKeyProvided() {\n\t\t// Noop, we don't need to show this message.\n\t\t// this.outputMessages([\n\t\t// \t'No tldraw license key provided!',\n\t\t// \t`Please reach out to ${LICENSE_EMAIL} if you would like to license tldraw or if you'd like a trial.`,\n\t\t// ])\n\t}\n\n\tprivate outputInvalidLicenseKey(msg: string) {\n\t\tthis.outputMessages(['Invalid tldraw license key', `Reason: ${msg}`])\n\t}\n\n\tprivate outputLicenseInfoIfNeeded(result: ValidLicenseKeyResult) {\n\t\t// If we added a new flag it will be twice the value of the currently highest flag.\n\t\t// And if all the current flags are on we would get the `HIGHEST_FLAG * 2 - 1`, so anything higher than that means there are new flags.\n\t\tif (result.license.flags >= HIGHEST_FLAG * 2) {\n\t\t\tthis.outputMessages(\n\t\t\t\t[\n\t\t\t\t\t'Warning: This tldraw license contains some unknown flags.',\n\t\t\t\t\t'This will still work, however, you may want to update tldraw packages to a newer version to get access to new functionality.',\n\t\t\t\t],\n\t\t\t\t'warning'\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate outputMessages(messages: string[], type: 'warning' | 'error' = 'error') {\n\t\tif (this.isTest) return\n\t\tif (this.verbose) {\n\t\t\tthis.outputDelimiter(type)\n\t\t\tfor (const message of messages) {\n\t\t\t\tconst bgColor = type === 'warning' ? 'orange' : 'crimson'\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(\n\t\t\t\t\t`%c${message}`,\n\t\t\t\t\t`color: white; background: ${bgColor}; padding: 2px; border-radius: 3px;`\n\t\t\t\t)\n\t\t\t}\n\t\t\tthis.outputDelimiter(type)\n\t\t}\n\t}\n\n\tprivate outputDelimiter(type: 'warning' | 'error' = 'error') {\n\t\tconst bgColor = type === 'warning' ? 'orange' : 'crimson'\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(\n\t\t\t'%c-------------------------------------------------------------------',\n\t\t\t`color: white; background: ${bgColor}; padding: 2px; border-radius: 3px;`\n\t\t)\n\t}\n\n\tstatic className = 'tl-watermark_SEE-LICENSE'\n}\n\n/**\n * Derives which licensable features are enabled from the parse result and the derived license\n * state. In development every feature is enabled so SDK developers can build against them; in\n * production a feature requires both an active, valid license and the corresponding flag.\n *\n * @internal\n */\nexport function getEnabledFeatures(\n\tresult: LicenseFromKeyResult,\n\tlicenseState: LicenseState,\n\tisDevelopment: boolean\n): Record<LicenseFeatureName, boolean> {\n\t// Development gets all features so SDK developers can build against them.\n\tif (isDevelopment) {\n\t\treturn { ...ALL_FEATURES }\n\t}\n\n\t// Features require an active, valid license. Both the 30-day grace-period 'licensed' state and\n\t// the watermark state count as valid; unlicensed/expired/pending do not.\n\tif (\n\t\t!result.isLicenseParseable ||\n\t\t(licenseState !== 'licensed' && licenseState !== 'licensed-with-watermark')\n\t) {\n\t\treturn { ...NO_FEATURES }\n\t}\n\n\t// Evaluation licenses get every feature so prospects can trial the whole product without us\n\t// having to mint per-feature evaluation keys. Expired evaluation licenses are already excluded\n\t// above: they resolve to the 'expired' state.\n\tif (result.isEvaluationLicense) {\n\t\treturn { ...ALL_FEATURES }\n\t}\n\n\treturn {\n\t\tcollaboration: result.isCollaborationEnabled,\n\t\tcommenting: result.isCommentingEnabled,\n\t}\n}\n\nexport function getLicenseState(\n\tresult: LicenseFromKeyResult,\n\toutputMessages: (messages: string[]) => void,\n\tisDevelopment: boolean\n): LicenseState {\n\tif (!result.isLicenseParseable) {\n\t\tif (isDevelopment) {\n\t\t\treturn 'unlicensed'\n\t\t}\n\n\t\t// All unlicensed scenarios should not work in production\n\t\tif (result.reason === 'no-key-provided') {\n\t\t\toutputMessages([\n\t\t\t\t'No tldraw license key provided!',\n\t\t\t\t'A license is required for production deployments.',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} to purchase a license.`,\n\t\t\t])\n\t\t} else {\n\t\t\toutputMessages([\n\t\t\t\t'Invalid license key. tldraw requires a valid license for production use.',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} to purchase a license.`,\n\t\t\t])\n\t\t}\n\t\treturn 'unlicensed-production'\n\t}\n\n\tif (!result.isDomainValid && !result.isDevelopment) {\n\t\toutputMessages([\n\t\t\t'License key is not valid for this domain.',\n\t\t\t'A license is required for production deployments.',\n\t\t\t`Please reach out to ${LICENSE_EMAIL} to purchase a license.`,\n\t\t])\n\t\treturn 'unlicensed-production'\n\t}\n\n\t// Handle evaluation licenses - they expire immediately with no grace period\n\tif (result.isEvaluationLicense) {\n\t\tif (result.isEvaluationLicenseExpired) {\n\t\t\toutputMessages([\n\t\t\t\t'Your tldraw evaluation license has expired!',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} to purchase a full license.`,\n\t\t\t])\n\t\t\treturn 'expired'\n\t\t} else {\n\t\t\t// Valid evaluation license - tracked but no watermark shown\n\t\t\treturn 'licensed'\n\t\t}\n\t}\n\n\t// Handle expired regular licenses (both annual and perpetual)\n\tif (result.isPerpetualLicenseExpired || result.isAnnualLicenseExpired) {\n\t\toutputMessages([\n\t\t\t'Your tldraw license has been expired for more than 30 days!',\n\t\t\t`Please reach out to ${LICENSE_EMAIL} to renew your license.`,\n\t\t])\n\t\treturn 'expired'\n\t}\n\n\t// Check if license is past expiry date but within grace period\n\tconst daysSinceExpiry = result.daysSinceExpiry\n\tif (daysSinceExpiry > 0 && !result.isEvaluationLicense) {\n\t\toutputMessages([\n\t\t\t'Your tldraw license has expired.',\n\t\t\t`License expired ${daysSinceExpiry} days ago.`,\n\t\t\t`Please reach out to ${LICENSE_EMAIL} to renew your license.`,\n\t\t])\n\t\t// Within 30-day grace period: still licensed (no watermark)\n\t\treturn 'licensed'\n\t}\n\n\t// License is valid, determine if it has watermark\n\tif (result.isLicensedWithWatermark) {\n\t\treturn 'licensed-with-watermark'\n\t}\n\n\treturn 'licensed'\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var useLicenseManagerState_exports = {};
20
20
  __export(useLicenseManagerState_exports, {
21
+ useLicenseFeatureFlag: () => useLicenseFeatureFlag,
21
22
  useLicenseManagerState: () => useLicenseManagerState
22
23
  });
23
24
  module.exports = __toCommonJS(useLicenseManagerState_exports);
@@ -25,4 +26,10 @@ var import_state_react = require("@tldraw/state-react");
25
26
  function useLicenseManagerState(licenseManager) {
26
27
  return (0, import_state_react.useValue)("watermarkState", () => licenseManager.state.get(), [licenseManager]);
27
28
  }
29
+ function useLicenseFeatureFlag(licenseManager, feature) {
30
+ return (0, import_state_react.useValue)("licenseFeature", () => licenseManager.isFeatureEnabled(feature), [
31
+ licenseManager,
32
+ feature
33
+ ]);
34
+ }
28
35
  //# sourceMappingURL=useLicenseManagerState.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/license/useLicenseManagerState.ts"],
4
- "sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { LicenseManager, LicenseState } from './LicenseManager'\n\n/** @internal */\nexport function useLicenseManagerState(licenseManager: LicenseManager): LicenseState {\n\treturn useValue('watermarkState', () => licenseManager.state.get(), [licenseManager])\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAyB;AAIlB,SAAS,uBAAuB,gBAA8C;AACpF,aAAO,6BAAS,kBAAkB,MAAM,eAAe,MAAM,IAAI,GAAG,CAAC,cAAc,CAAC;AACrF;",
4
+ "sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { LicenseFeatureName, LicenseManager, LicenseState } from './LicenseManager'\n\n/** @internal */\nexport function useLicenseManagerState(licenseManager: LicenseManager): LicenseState {\n\treturn useValue('watermarkState', () => licenseManager.state.get(), [licenseManager])\n}\n\n/**\n * Reactively reads whether a licensable feature is enabled for the current license. Re-renders when\n * license validation resolves.\n *\n * @internal\n */\nexport function useLicenseFeatureFlag(\n\tlicenseManager: LicenseManager,\n\tfeature: LicenseFeatureName\n): boolean {\n\treturn useValue('licenseFeature', () => licenseManager.isFeatureEnabled(feature), [\n\t\tlicenseManager,\n\t\tfeature,\n\t])\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAyB;AAIlB,SAAS,uBAAuB,gBAA8C;AACpF,aAAO,6BAAS,kBAAkB,MAAM,eAAe,MAAM,IAAI,GAAG,CAAC,cAAc,CAAC;AACrF;AAQO,SAAS,sBACf,gBACA,SACU;AACV,aAAO,6BAAS,kBAAkB,MAAM,eAAe,iBAAiB,OAAO,GAAG;AAAA,IACjF;AAAA,IACA;AAAA,EACD,CAAC;AACF;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var collaborators_exports = {};
20
+ __export(collaborators_exports, {
21
+ isCursorInViewport: () => isCursorInViewport
22
+ });
23
+ module.exports = __toCommonJS(collaborators_exports);
24
+ function isCursorInViewport(cursor, viewport, zoom) {
25
+ return !(cursor.x < viewport.minX - 12 / zoom || cursor.y < viewport.minY - 16 / zoom || cursor.x > viewport.maxX - 12 / zoom || cursor.y > viewport.maxY - 16 / zoom);
26
+ }
27
+ //# sourceMappingURL=collaborators.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/utils/collaborators.ts"],
4
+ "sourcesContent": ["import { VecLike } from '../primitives/Vec'\n\n/**\n * Whether a collaborator's cursor (page coords) is inside the viewport, with a small margin for the\n * cursor glyph so it isn't culled the instant its hotspot crosses the edge.\n *\n * Single source of truth for the cursor/hint split: the DOM cursor layer renders a collaborator\n * when this is true, and `CollaboratorHintOverlayUtil` draws the viewport-edge hint when it's\n * false. Sharing the predicate keeps those two exhaustive and mutually exclusive \u2014 a margin change\n * can't open a dead zone (neither renders) or a double-render (both).\n *\n * @public\n */\nexport function isCursorInViewport(\n\tcursor: VecLike,\n\tviewport: { minX: number; minY: number; maxX: number; maxY: number },\n\tzoom: number\n): boolean {\n\treturn !(\n\t\tcursor.x < viewport.minX - 12 / zoom ||\n\t\tcursor.y < viewport.minY - 16 / zoom ||\n\t\tcursor.x > viewport.maxX - 12 / zoom ||\n\t\tcursor.y > viewport.maxY - 16 / zoom\n\t)\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAaO,SAAS,mBACf,QACA,UACA,MACU;AACV,SAAO,EACN,OAAO,IAAI,SAAS,OAAO,KAAK,QAChC,OAAO,IAAI,SAAS,OAAO,KAAK,QAChC,OAAO,IAAI,SAAS,OAAO,KAAK,QAChC,OAAO,IAAI,SAAS,OAAO,KAAK;AAElC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var getHtmlLayerTransform_exports = {};
20
+ __export(getHtmlLayerTransform_exports, {
21
+ getHtmlLayerTransform: () => getHtmlLayerTransform
22
+ });
23
+ module.exports = __toCommonJS(getHtmlLayerTransform_exports);
24
+ var import_utils = require("@tldraw/utils");
25
+ var import_utils2 = require("../primitives/utils");
26
+ function getHtmlLayerTransform(editor) {
27
+ const { x, y, z } = editor.getCamera();
28
+ const offset = z >= 1 ? (0, import_utils.modulate)(z, [1, 8], [0.125, 0.5], true) : (0, import_utils.modulate)(z, [0.1, 1], [-2, 0.125], true);
29
+ return `scale(${(0, import_utils2.toDomPrecision)(z)}) translate(${(0, import_utils2.toDomPrecision)(x + offset)}px,${(0, import_utils2.toDomPrecision)(
30
+ y + offset
31
+ )}px)`;
32
+ }
33
+ //# sourceMappingURL=getHtmlLayerTransform.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/utils/getHtmlLayerTransform.ts"],
4
+ "sourcesContent": ["import { modulate } from '@tldraw/utils'\nimport type { Editor } from '../editor/Editor'\nimport { toDomPrecision } from '../primitives/utils'\n\n/**\n * The CSS `transform` that puts a 1px-sized html layer into page space under the current camera.\n * Shared by every camera-tracked DOM layer (the canvas's shape layer, the collaborator cursor\n * layer) so they line up exactly and can't drift apart.\n *\n * The offset compensates for the layer's 1px width/height when zoomed, so it registers precisely\n * with the other layers.\n *\n * @internal\n */\nexport function getHtmlLayerTransform(editor: Editor): string {\n\tconst { x, y, z } = editor.getCamera()\n\tconst offset =\n\t\tz >= 1 ? modulate(z, [1, 8], [0.125, 0.5], true) : modulate(z, [0.1, 1], [-2, 0.125], true)\n\treturn `scale(${toDomPrecision(z)}) translate(${toDomPrecision(x + offset)}px,${toDomPrecision(\n\t\ty + offset\n\t)}px)`\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAyB;AAEzB,IAAAA,gBAA+B;AAYxB,SAAS,sBAAsB,QAAwB;AAC7D,QAAM,EAAE,GAAG,GAAG,EAAE,IAAI,OAAO,UAAU;AACrC,QAAM,SACL,KAAK,QAAI,uBAAS,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,GAAG,GAAG,IAAI,QAAI,uBAAS,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,GAAG,IAAI;AAC3F,SAAO,aAAS,8BAAe,CAAC,CAAC,mBAAe,8BAAe,IAAI,MAAM,CAAC,UAAM;AAAA,IAC/E,IAAI;AAAA,EACL,CAAC;AACF;",
6
+ "names": ["import_utils"]
7
+ }
@@ -22,10 +22,10 @@ __export(version_exports, {
22
22
  version: () => version
23
23
  });
24
24
  module.exports = __toCommonJS(version_exports);
25
- const version = "5.3.0-next.4123e97459a9";
25
+ const version = "5.3.0-next.5cb71bb7e8fe";
26
26
  const publishDates = {
27
27
  major: "2026-05-06T16:28:18.473Z",
28
- minor: "2026-07-23T10:43:39.737Z",
29
- patch: "2026-07-23T10:43:39.737Z"
28
+ minor: "2026-08-05T11:22:14.621Z",
29
+ patch: "2026-08-05T11:22:14.621Z"
30
30
  };
31
31
  //# sourceMappingURL=version.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/version.ts"],
4
- "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.3.0-next.4123e97459a9'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-07-23T10:43:39.737Z',\n\tpatch: '2026-07-23T10:43:39.737Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.3.0-next.5cb71bb7e8fe'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-08-05T11:22:14.621Z',\n\tpatch: '2026-08-05T11:22:14.621Z',\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
@@ -19,12 +19,14 @@ import { JsonObject } from '@tldraw/utils';
19
19
  import { JSX } from 'react/jsx-runtime';
20
20
  import { LegacyMigrations } from '@tldraw/store';
21
21
  import { MigrationSequence } from '@tldraw/store';
22
+ import { NamedExoticComponent } from 'react';
22
23
  import { Node as Node_2 } from '@tiptap/pm/model';
23
24
  import { PerformanceTracker } from '@tldraw/utils';
24
25
  import * as React_2 from 'react';
25
26
  import { default as React_3 } from 'react';
26
27
  import { ReactElement } from 'react';
27
28
  import { ReactNode } from 'react';
29
+ import { ReactPortal } from 'react';
28
30
  import { RecordProps } from '@tldraw/tlschema';
29
31
  import { RecordsDiff } from '@tldraw/store';
30
32
  import { RefAttributes } from 'react';
@@ -982,6 +984,15 @@ export declare function DefaultBackground(): JSX.Element;
982
984
  /** @public @react */
983
985
  export declare function DefaultCanvas({ className }: TLCanvasComponentProps): JSX.Element;
984
986
 
987
+ /**
988
+ * The default collaborator cursor: the arrow glyph plus a name tag or chat bubble. The arrow is a
989
+ * `<use>` of a shared `<defs>` symbol that `LiveCollaborators` renders, so a `DefaultCursor`
990
+ * used outside that layer draws no arrow.
991
+ *
992
+ * @public @react
993
+ */
994
+ export declare const DefaultCursor: NamedExoticComponent<TLCursorProps>;
995
+
985
996
  /** @public @react */
986
997
  export declare const DefaultErrorFallback: TLErrorFallbackComponent;
987
998
 
@@ -4586,6 +4597,52 @@ export declare abstract class EditorManager {
4586
4597
  /* Excluded from this release type: dispose */
4587
4598
  }
4588
4599
 
4600
+ /**
4601
+ * Renders its children into the end of the editor's container, escaping the canvas layer.
4602
+ *
4603
+ * Use this for anything anchored to canvas coordinates that also has to draw over the UI — a
4604
+ * popover on a shape, a comment thread, an annotation panel. The `OnTheCanvas` and
4605
+ * `InFrontOfTheCanvas` slots are fixed layers, each its own stacking context, so content mounted
4606
+ * there can't paint above whatever outranks its layer whatever z-index it asks for. Mount in
4607
+ * whichever slot suits your data flow, wrap the part that needs its own layer in this, and give
4608
+ * that part a z-index.
4609
+ *
4610
+ * This package's own layers stop at 250 (`--tl-layer-canvas-in-front`); above that belongs to
4611
+ * whatever renders the UI. In `tldraw` that's `--tl-layer-panels` (300) and `--tl-layer-menus`
4612
+ * (400), defined by `tldraw`'s stylesheet rather than this one.
4613
+ *
4614
+ * Positioning still resolves against the editor's container, so a `position: absolute` child uses
4615
+ * ordinary container coordinates.
4616
+ *
4617
+ * Prefer this over `createPortal(children, useContainer())`, which picks its DOM position from the
4618
+ * commit that mounts it — landing the node ahead of the UI and of the "skip to main content" link
4619
+ * that only works while nothing precedes it. This host is a real element placed last, so ordering
4620
+ * is fixed rather than dependent on mount timing.
4621
+ *
4622
+ * @example
4623
+ * ```tsx
4624
+ * // 400 clears tldraw's menus layer; the bare editor's own layers stop at 250.
4625
+ * function ShapeAnnotation({ point }: { point: VecLike }) {
4626
+ * return (
4627
+ * <EditorPortal>
4628
+ * <div style={{ position: 'absolute', left: point.x, top: point.y, zIndex: 400 }}>
4629
+ * Above the UI
4630
+ * </div>
4631
+ * </EditorPortal>
4632
+ * )
4633
+ * }
4634
+ * ```
4635
+ *
4636
+ * @public
4637
+ * @react
4638
+ */
4639
+ export declare function EditorPortal({ children }: EditorPortalProps): ReactPortal | null;
4640
+
4641
+ /** @public */
4642
+ export declare interface EditorPortalProps {
4643
+ children: ReactNode;
4644
+ }
4645
+
4589
4646
  /** @public @react */
4590
4647
  export declare function EditorProvider({ editor, children }: EditorProviderProps): JSX.Element;
4591
4648
 
@@ -5449,6 +5506,24 @@ export declare function intersectPolygonPolygon(polygonA: VecLike[], polygonB: V
5449
5506
 
5450
5507
  /* Excluded from this release type: isAccelKey */
5451
5508
 
5509
+ /**
5510
+ * Whether a collaborator's cursor (page coords) is inside the viewport, with a small margin for the
5511
+ * cursor glyph so it isn't culled the instant its hotspot crosses the edge.
5512
+ *
5513
+ * Single source of truth for the cursor/hint split: the DOM cursor layer renders a collaborator
5514
+ * when this is true, and `CollaboratorHintOverlayUtil` draws the viewport-edge hint when it's
5515
+ * false. Sharing the predicate keeps those two exhaustive and mutually exclusive — a margin change
5516
+ * can't open a dead zone (neither renders) or a double-render (both).
5517
+ *
5518
+ * @public
5519
+ */
5520
+ export declare function isCursorInViewport(cursor: VecLike, viewport: {
5521
+ maxX: number;
5522
+ maxY: number;
5523
+ minX: number;
5524
+ minY: number;
5525
+ }, zoom: number): boolean;
5526
+
5452
5527
  /**
5453
5528
  * Check if a float is safe to use. ie: Not too big or small.
5454
5529
  * @public
@@ -5470,6 +5545,8 @@ export declare function kickoutOccludedShapes(editor: Editor, shapeIds: TLShapeI
5470
5545
 
5471
5546
  /* Excluded from this release type: LICENSE_TIMEOUT */
5472
5547
 
5548
+ /* Excluded from this release type: LicenseFeatureName */
5549
+
5473
5550
  /* Excluded from this release type: LicenseFromKeyResult */
5474
5551
 
5475
5552
  /* Excluded from this release type: LicenseInfo */
@@ -7548,6 +7625,11 @@ export declare interface TLBaseEventInfo {
7548
7625
 
7549
7626
  /** @public */
7550
7627
  export declare interface TLBaseExternalContent {
7628
+ /**
7629
+ * The other content sources found on the clipboard alongside this content. For example, when
7630
+ * pasting an image copied together with HTML and plain text, the `files` content will have
7631
+ * text sources for the HTML and plain text parts.
7632
+ */
7551
7633
  sources?: TLExternalContentSource[];
7552
7634
  point?: VecLike;
7553
7635
  }
@@ -7794,6 +7876,17 @@ export declare interface TLCurrentUser {
7794
7876
  readonly setUserPreferences: (userPreferences: TLUserPreferences) => void;
7795
7877
  }
7796
7878
 
7879
+ /** @public */
7880
+ export declare interface TLCursorProps {
7881
+ userId: string;
7882
+ className?: string;
7883
+ point: null | VecModel;
7884
+ zoom: number;
7885
+ color?: string;
7886
+ name: null | string;
7887
+ chatMessage: string;
7888
+ }
7889
+
7797
7890
  /** @public */
7798
7891
  export declare type TLDeepLink = {
7799
7892
  bounds: BoxModel;
@@ -8296,6 +8389,7 @@ export declare interface TLDropShapesOverInfo {
8296
8389
  export declare interface TLEditorComponents {
8297
8390
  Background?: ComponentType | null;
8298
8391
  Canvas?: ComponentType<TLCanvasComponentProps> | null;
8392
+ CollaboratorCursor?: ComponentType<TLCursorProps> | null;
8299
8393
  Grid?: ComponentType<TLGridProps> | null;
8300
8394
  InFrontOfTheCanvas?: ComponentType | null;
8301
8395
  LoadingScreen?: ComponentType | null;
@@ -9751,6 +9845,16 @@ export declare function useEditor(): Editor;
9751
9845
  /** @public */
9752
9846
  export declare function useEditorComponents(): Required<TLEditorComponents>;
9753
9847
 
9848
+ /**
9849
+ * The DOM node that {@link EditorPortal} renders into: an empty `display: contents` element the
9850
+ * editor renders last among its container's children, after the canvas and after the UI.
9851
+ *
9852
+ * Null until the container has mounted, so prefer {@link EditorPortal}, which handles that for you.
9853
+ *
9854
+ * @public
9855
+ */
9856
+ export declare function useEditorPortalHost(): HTMLElement | null;
9857
+
9754
9858
  /* Excluded from this release type: useEvent */
9755
9859
 
9756
9860
  /** @public */
@@ -9762,6 +9866,10 @@ export declare function useIsCropping(shapeId: TLShapeId): boolean;
9762
9866
  /** @public */
9763
9867
  export declare function useIsEditing(shapeId: TLShapeId): boolean;
9764
9868
 
9869
+ /* Excluded from this release type: useLicenseContext */
9870
+
9871
+ /* Excluded from this release type: useLicenseFeatureFlag */
9872
+
9765
9873
  /* Excluded from this release type: useLocalStore */
9766
9874
 
9767
9875
  /** @public */
@@ -9769,9 +9877,6 @@ export declare function useMaybeEditor(): Editor | null;
9769
9877
 
9770
9878
  /* Excluded from this release type: useOnMount */
9771
9879
 
9772
- /** @public */
9773
- export declare function usePassThroughMouseOverEvents(ref: RefObject<HTMLElement | null>): void;
9774
-
9775
9880
  /** @public */
9776
9881
  export declare function usePassThroughWheelEvents(ref: RefObject<HTMLElement | null>): void;
9777
9882
 
@@ -9898,6 +10003,13 @@ export declare function useTLSchemaFromUtils(opts: TLStoreSchemaOptions): StoreS
9898
10003
  /** @public */
9899
10004
  export declare function useTLStore(opts: TLStoreOptions): TLStore;
9900
10005
 
10006
+ /**
10007
+ * Position an element by writing its `transform` directly, outside React's render output — the
10008
+ * cheap path for elements that move at pointer/presence frequency.
10009
+ * @public
10010
+ */
10011
+ export declare function useTransform(ref: React.RefObject<HTMLElement | null | SVGElement>, x?: number, y?: number, scale?: number, rotate?: number, additionalOffset?: VecLike): void;
10012
+
9901
10013
  /**
9902
10014
  * React's useId hook returns a unique id for the component. However, it uses a colon in the id,
9903
10015
  * which is not valid for CSS selectors. This hook replaces the colon with an underscore.
@@ -9,6 +9,9 @@ import { DefaultBackground } from "./lib/components/default-components/DefaultBa
9
9
  import {
10
10
  DefaultCanvas
11
11
  } from "./lib/components/default-components/DefaultCanvas.mjs";
12
+ import {
13
+ DefaultCursor
14
+ } from "./lib/components/default-components/DefaultCursor.mjs";
12
15
  import {
13
16
  DefaultErrorFallback
14
17
  } from "./lib/components/default-components/DefaultErrorFallback.mjs";
@@ -18,6 +21,10 @@ import {
18
21
  } from "./lib/components/default-components/DefaultShapeWrapper.mjs";
19
22
  import { DefaultSpinner } from "./lib/components/default-components/DefaultSpinner.mjs";
20
23
  import { DefaultSvgDefs } from "./lib/components/default-components/DefaultSvgDefs.mjs";
24
+ import {
25
+ EditorPortal,
26
+ useEditorPortalHost
27
+ } from "./lib/components/EditorPortal.mjs";
21
28
  import {
22
29
  ErrorBoundary,
23
30
  OptionalErrorBoundary
@@ -144,7 +151,6 @@ import { useShallowArrayIdentity, useShallowObjectIdentity } from "./lib/hooks/u
144
151
  import { useIsCropping } from "./lib/hooks/useIsCropping.mjs";
145
152
  import { useIsEditing } from "./lib/hooks/useIsEditing.mjs";
146
153
  import { useLocalStore } from "./lib/hooks/useLocalStore.mjs";
147
- import { usePassThroughMouseOverEvents } from "./lib/hooks/usePassThroughMouseOverEvents.mjs";
148
154
  import { usePassThroughWheelEvents } from "./lib/hooks/usePassThroughWheelEvents.mjs";
149
155
  import { usePeerIds } from "./lib/hooks/usePeerIds.mjs";
150
156
  import { usePresence } from "./lib/hooks/usePresence.mjs";
@@ -155,12 +161,15 @@ import {
155
161
  useSharedSafeId,
156
162
  useUniqueSafeId
157
163
  } from "./lib/hooks/useSafeId.mjs";
164
+ import { useTransform } from "./lib/hooks/useTransform.mjs";
165
+ import { isCursorInViewport } from "./lib/utils/collaborators.mjs";
158
166
  import { useTLSchemaFromUtils, useTLStore } from "./lib/hooks/useTLStore.mjs";
159
167
  import { useViewportHeight } from "./lib/hooks/useViewportHeight.mjs";
160
168
  import {
161
169
  LicenseManager
162
170
  } from "./lib/license/LicenseManager.mjs";
163
- import { LICENSE_TIMEOUT } from "./lib/license/LicenseProvider.mjs";
171
+ import { LICENSE_TIMEOUT, useLicenseContext } from "./lib/license/LicenseProvider.mjs";
172
+ import { useLicenseFeatureFlag } from "./lib/license/useLicenseManagerState.mjs";
164
173
  import {
165
174
  defaultTldrawOptions
166
175
  } from "./lib/options.mjs";
@@ -296,7 +305,7 @@ import { LocalIndexedDb, Table } from "./lib/utils/sync/LocalIndexedDb.mjs";
296
305
  import { uniq } from "./lib/utils/uniq.mjs";
297
306
  registerTldrawLibraryVersion(
298
307
  "@tldraw/editor",
299
- "5.3.0-next.4123e97459a9",
308
+ "5.3.0-next.5cb71bb7e8fe",
300
309
  "esm"
301
310
  );
302
311
  import { getColorValue } from "./lib/editor/managers/ThemeManager/defaultThemes.mjs";
@@ -320,6 +329,7 @@ export {
320
329
  DEFAULT_THEME,
321
330
  DefaultBackground,
322
331
  DefaultCanvas,
332
+ DefaultCursor,
323
333
  DefaultErrorFallback,
324
334
  DefaultGrid,
325
335
  DefaultShapeWrapper,
@@ -333,6 +343,7 @@ export {
333
343
  EditorAtom,
334
344
  EditorContext,
335
345
  EditorManager,
346
+ EditorPortal,
336
347
  EditorProvider,
337
348
  Ellipse2d,
338
349
  ErrorBoundary,
@@ -453,6 +464,7 @@ export {
453
464
  intersectPolygonBounds,
454
465
  intersectPolygonPolygon,
455
466
  isAccelKey,
467
+ isCursorInViewport,
456
468
  isSafeFloat,
457
469
  kickoutOccludedShapes,
458
470
  linesIntersect,
@@ -503,14 +515,16 @@ export {
503
515
  useDelaySvgExport,
504
516
  useEditor,
505
517
  useEditorComponents,
518
+ useEditorPortalHost,
506
519
  useEvent,
507
520
  useGlobalMenuIsOpen,
508
521
  useIsCropping,
509
522
  useIsEditing,
523
+ useLicenseContext,
524
+ useLicenseFeatureFlag,
510
525
  useLocalStore,
511
526
  useMaybeEditor,
512
527
  useOnMount,
513
- usePassThroughMouseOverEvents,
514
528
  usePassThroughWheelEvents,
515
529
  usePeerIds,
516
530
  usePresence,
@@ -523,6 +537,7 @@ export {
523
537
  useTLSchemaFromUtils,
524
538
  useTLStore,
525
539
  useTldrawCurrentUser,
540
+ useTransform,
526
541
  useUniqueSafeId,
527
542
  useViewportHeight,
528
543
  userTypeValidator