@tldraw/editor 5.3.0-internal.d205573d66cb → 5.3.0-next.299378752aaf

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.
@@ -1,4 +1,4 @@
1
- import { atom, transact } from '@tldraw/state'
1
+ import { atom } from '@tldraw/state'
2
2
  import { publishDates, version } from '../../version'
3
3
  import { getDefaultCdnBaseUrl } from '../utils/assets'
4
4
  import { importPublicKey, str2ab } from '../utils/licensing'
@@ -22,12 +22,6 @@ export const FLAGS = {
22
22
  // Native means the license is for native apps which switches
23
23
  // on special-case logic.
24
24
  NATIVE_LICENSE: 1 << 5,
25
-
26
- // -- FEATURE FLAGS --
27
- // Collaboration is the umbrella flag for collaboration features; it grants all sub-features.
28
- FEAT_COLLABORATION: 1 << 6,
29
- // Commenting is the first sub-feature of collaboration.
30
- FEAT_COMMENTING: 1 << 7,
31
25
  }
32
26
  const HIGHEST_FLAG = Math.max(...Object.values(FLAGS))
33
27
 
@@ -51,23 +45,6 @@ export interface LicenseInfo {
51
45
  expiryDate: string
52
46
  }
53
47
 
54
- /**
55
- * Names of the licensable product features gated by the license. `collaboration` is an umbrella
56
- * that also grants all of its sub-features (currently just `commenting`).
57
- *
58
- * @internal
59
- */
60
- export type LicenseFeatureName = 'collaboration' | 'commenting'
61
-
62
- const NO_FEATURES: Readonly<Record<LicenseFeatureName, boolean>> = {
63
- collaboration: false,
64
- commenting: false,
65
- }
66
- const ALL_FEATURES: Readonly<Record<LicenseFeatureName, boolean>> = {
67
- collaboration: true,
68
- commenting: true,
69
- }
70
-
71
48
  /** @internal */
72
49
  export type LicenseState =
73
50
  | 'pending' // License validation is in progress
@@ -107,8 +84,6 @@ export interface ValidLicenseKeyResult {
107
84
  isLicensedWithWatermark: boolean
108
85
  isEvaluationLicense: boolean
109
86
  isEvaluationLicenseExpired: boolean
110
- isCollaborationEnabled: boolean
111
- isCommentingEnabled: boolean
112
87
  daysSinceExpiry: number
113
88
  }
114
89
 
@@ -123,9 +98,6 @@ export class LicenseManager {
123
98
  public isTest: boolean
124
99
  public isCryptoAvailable: boolean
125
100
  state = atom<LicenseState>('license state', 'pending')
126
- featureFlags = atom<Record<LicenseFeatureName, boolean>>('license feature flags', {
127
- ...NO_FEATURES,
128
- })
129
101
  public verbose = true
130
102
 
131
103
  constructor(licenseKey: string | undefined, testPublicKey?: string) {
@@ -134,14 +106,6 @@ export class LicenseManager {
134
106
  this.publicKey = testPublicKey || this.publicKey
135
107
  this.isCryptoAvailable = !!crypto.subtle
136
108
 
137
- // In development every feature is enabled (see `getEnabledFeatures`), and that doesn't depend
138
- // on the async validation result. Reflect it eagerly so features aren't reported as disabled
139
- // during the validation window — or left disabled if validation rejects (the `.catch` below
140
- // never sets `featureFlags`). In production the fail-closed default stands until validation.
141
- if (this.isDevelopment) {
142
- this.featureFlags.set({ ...ALL_FEATURES })
143
- }
144
-
145
109
  this.getLicenseFromKey(licenseKey)
146
110
  .then((result) => {
147
111
  const licenseState = getLicenseState(
@@ -152,12 +116,7 @@ export class LicenseManager {
152
116
 
153
117
  this.maybeTrack(result, licenseState)
154
118
 
155
- // Update both atoms atomically so dependents never observe the license state and the
156
- // feature flags out of sync mid-update.
157
- transact(() => {
158
- this.state.set(licenseState)
159
- this.featureFlags.set(getEnabledFeatures(result, licenseState, this.isDevelopment))
160
- })
119
+ this.state.set(licenseState)
161
120
  })
162
121
  .catch((error) => {
163
122
  console.error('License validation failed:', error)
@@ -165,14 +124,6 @@ export class LicenseManager {
165
124
  })
166
125
  }
167
126
 
168
- /**
169
- * Returns whether a given licensable feature is enabled. Reactive: reading this inside a signal
170
- * recomputes when license validation resolves.
171
- */
172
- isFeatureEnabled(feature: LicenseFeatureName): boolean {
173
- return this.featureFlags.get()[feature]
174
- }
175
-
176
127
  private getIsDevelopment() {
177
128
  // If we are using https on a non-loopback domain we assume it's a production env and a development one otherwise
178
129
  return (
@@ -335,12 +286,6 @@ export class LicenseManager {
335
286
  const isPerpetualLicenseExpired =
336
287
  isPerpetualLicense && this.isPerpetualLicenseExpired(expiryDate)
337
288
 
338
- // The collaboration umbrella grants all of its sub-features, so commenting is enabled
339
- // by either the commenting flag or the collaboration flag.
340
- const isCollaborationEnabled = this.isFlagEnabled(licenseInfo.flags, FLAGS.FEAT_COLLABORATION)
341
- const isCommentingEnabled =
342
- isCollaborationEnabled || this.isFlagEnabled(licenseInfo.flags, FLAGS.FEAT_COMMENTING)
343
-
344
289
  // For perpetual licenses, the calendar expiry date only gates access to future
345
290
  // major/minor releases; it does not "expire" the license itself. While the user
346
291
  // is still on a covered version we report `daysSinceExpiry` as 0 so consumers
@@ -364,8 +309,6 @@ export class LicenseManager {
364
309
  isEvaluationLicense,
365
310
  isEvaluationLicenseExpired:
366
311
  isEvaluationLicense && this.isEvaluationLicenseExpired(expiryDate),
367
- isCollaborationEnabled,
368
- isCommentingEnabled,
369
312
  daysSinceExpiry,
370
313
  }
371
314
  this.outputLicenseInfoIfNeeded(result)
@@ -429,26 +372,14 @@ export class LicenseManager {
429
372
  }
430
373
 
431
374
  private getExpirationDateWithoutGracePeriod(expiryDate: Date) {
432
- // The named expiry date is the last day the license is fully usable, so the license
433
- // expires at the end of that day, i.e. the start of the following day. We work in UTC
434
- // (the expiry date is minted and parsed as a UTC date-only string) so the cutoff is a
435
- // single predictable instant for every user regardless of their local timezone.
436
- return new Date(
437
- Date.UTC(
438
- expiryDate.getUTCFullYear(),
439
- expiryDate.getUTCMonth(),
440
- expiryDate.getUTCDate() + 1 // Add 1 day so the named date is fully usable
441
- )
442
- )
375
+ return new Date(expiryDate.getFullYear(), expiryDate.getMonth(), expiryDate.getDate())
443
376
  }
444
377
 
445
378
  private getExpirationDateWithGracePeriod(expiryDate: Date) {
446
379
  return new Date(
447
- Date.UTC(
448
- expiryDate.getUTCFullYear(),
449
- expiryDate.getUTCMonth(),
450
- expiryDate.getUTCDate() + GRACE_PERIOD_DAYS + 1 // Add 1 day to include the expiration day
451
- )
380
+ expiryDate.getFullYear(),
381
+ expiryDate.getMonth(),
382
+ expiryDate.getDate() + GRACE_PERIOD_DAYS + 1 // Add 1 day to include the expiration day
452
383
  )
453
384
  }
454
385
 
@@ -540,38 +471,6 @@ export class LicenseManager {
540
471
  static className = 'tl-watermark_SEE-LICENSE'
541
472
  }
542
473
 
543
- /**
544
- * Derives which licensable features are enabled from the parse result and the derived license
545
- * state. In development every feature is enabled so SDK developers can build against them; in
546
- * production a feature requires both an active, valid license and the corresponding flag.
547
- *
548
- * @internal
549
- */
550
- export function getEnabledFeatures(
551
- result: LicenseFromKeyResult,
552
- licenseState: LicenseState,
553
- isDevelopment: boolean
554
- ): Record<LicenseFeatureName, boolean> {
555
- // Development gets all features so SDK developers can build against them.
556
- if (isDevelopment) {
557
- return { ...ALL_FEATURES }
558
- }
559
-
560
- // Features require an active, valid license. Both the 30-day grace-period 'licensed' state and
561
- // the watermark state count as valid; unlicensed/expired/pending do not.
562
- if (
563
- !result.isLicenseParseable ||
564
- (licenseState !== 'licensed' && licenseState !== 'licensed-with-watermark')
565
- ) {
566
- return { ...NO_FEATURES }
567
- }
568
-
569
- return {
570
- collaboration: result.isCollaborationEnabled,
571
- commenting: result.isCommentingEnabled,
572
- }
573
- }
574
-
575
474
  export function getLicenseState(
576
475
  result: LicenseFromKeyResult,
577
476
  outputMessages: (messages: string[]) => void,
@@ -1,23 +1,7 @@
1
1
  import { useValue } from '@tldraw/state-react'
2
- import { LicenseFeatureName, LicenseManager, LicenseState } from './LicenseManager'
2
+ import { LicenseManager, LicenseState } from './LicenseManager'
3
3
 
4
4
  /** @internal */
5
5
  export function useLicenseManagerState(licenseManager: LicenseManager): LicenseState {
6
6
  return useValue('watermarkState', () => licenseManager.state.get(), [licenseManager])
7
7
  }
8
-
9
- /**
10
- * Reactively reads whether a licensable feature is enabled for the current license. Re-renders when
11
- * license validation resolves.
12
- *
13
- * @internal
14
- */
15
- export function useLicenseFeatureFlag(
16
- licenseManager: LicenseManager,
17
- feature: LicenseFeatureName
18
- ): boolean {
19
- return useValue('licenseFeature', () => licenseManager.isFeatureEnabled(feature), [
20
- licenseManager,
21
- feature,
22
- ])
23
- }
package/src/version.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  // This file is automatically generated by internal/scripts/refresh-assets.ts.
2
2
  // Do not edit manually. Or do, I'm a comment, not a cop.
3
3
 
4
- export const version = '5.3.0-internal.d205573d66cb'
4
+ export const version = '5.3.0-next.299378752aaf'
5
5
  export const publishDates = {
6
6
  major: '2026-05-06T16:28:18.473Z',
7
- minor: '2026-07-13T14:47:11.349Z',
8
- patch: '2026-07-13T14:47:11.349Z',
7
+ minor: '2026-07-13T13:51:04.172Z',
8
+ patch: '2026-07-13T13:51:04.172Z',
9
9
  }