@tldraw/editor 3.16.0-canary.3be390323e1c → 3.16.0-canary.3e3b8b577bf1
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.
- package/dist-cjs/index.d.ts +15 -2
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/TldrawEditor.js +1 -1
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +9 -4
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +21 -4
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +17 -1
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +24 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +5 -1
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +15 -2
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/TldrawEditor.mjs +1 -1
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +9 -4
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +21 -4
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +16 -1
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +24 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +5 -1
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/lib/TldrawEditor.tsx +1 -2
- package/src/lib/editor/Editor.test.ts +90 -0
- package/src/lib/editor/Editor.ts +16 -4
- package/src/lib/license/LicenseManager.test.ts +78 -2
- package/src/lib/license/LicenseManager.ts +28 -5
- package/src/lib/license/LicenseProvider.tsx +40 -1
- package/src/lib/primitives/geometry/Geometry2d.test.ts +420 -0
- package/src/lib/primitives/geometry/Geometry2d.ts +29 -2
- package/src/lib/primitives/geometry/Group2d.ts +6 -1
- package/src/version.ts +3 -3
|
@@ -833,3 +833,93 @@ describe('selectAll', () => {
|
|
|
833
833
|
setSelectedShapesSpy.mockRestore()
|
|
834
834
|
})
|
|
835
835
|
})
|
|
836
|
+
|
|
837
|
+
describe('putExternalContent', () => {
|
|
838
|
+
let mockHandler: any
|
|
839
|
+
|
|
840
|
+
beforeEach(() => {
|
|
841
|
+
mockHandler = vi.fn()
|
|
842
|
+
editor.registerExternalContentHandler('text', mockHandler)
|
|
843
|
+
})
|
|
844
|
+
|
|
845
|
+
it('calls external content handler when not readonly', async () => {
|
|
846
|
+
vi.spyOn(editor, 'getIsReadonly').mockReturnValue(false)
|
|
847
|
+
|
|
848
|
+
const info = { type: 'text' as const, text: 'test-data' }
|
|
849
|
+
await editor.putExternalContent(info)
|
|
850
|
+
|
|
851
|
+
expect(mockHandler).toHaveBeenCalledWith(info)
|
|
852
|
+
})
|
|
853
|
+
|
|
854
|
+
it('does not call external content handler when readonly', async () => {
|
|
855
|
+
vi.spyOn(editor, 'getIsReadonly').mockReturnValue(true)
|
|
856
|
+
|
|
857
|
+
const info = { type: 'text' as const, text: 'test-data' }
|
|
858
|
+
await editor.putExternalContent(info)
|
|
859
|
+
|
|
860
|
+
expect(mockHandler).not.toHaveBeenCalled()
|
|
861
|
+
})
|
|
862
|
+
|
|
863
|
+
it('calls external content handler when readonly but force is true', async () => {
|
|
864
|
+
vi.spyOn(editor, 'getIsReadonly').mockReturnValue(true)
|
|
865
|
+
|
|
866
|
+
const info = { type: 'text' as const, text: 'test-data' }
|
|
867
|
+
await editor.putExternalContent(info, { force: true })
|
|
868
|
+
|
|
869
|
+
expect(mockHandler).toHaveBeenCalledWith(info)
|
|
870
|
+
})
|
|
871
|
+
|
|
872
|
+
it('calls external content handler when force is false and not readonly', async () => {
|
|
873
|
+
vi.spyOn(editor, 'getIsReadonly').mockReturnValue(false)
|
|
874
|
+
|
|
875
|
+
const info = { type: 'text' as const, text: 'test-data' }
|
|
876
|
+
await editor.putExternalContent(info, { force: false })
|
|
877
|
+
|
|
878
|
+
expect(mockHandler).toHaveBeenCalledWith(info)
|
|
879
|
+
})
|
|
880
|
+
})
|
|
881
|
+
|
|
882
|
+
describe('replaceExternalContent', () => {
|
|
883
|
+
let mockHandler: any
|
|
884
|
+
|
|
885
|
+
beforeEach(() => {
|
|
886
|
+
mockHandler = vi.fn()
|
|
887
|
+
editor.registerExternalContentHandler('text', mockHandler)
|
|
888
|
+
})
|
|
889
|
+
|
|
890
|
+
it('calls external content handler when not readonly', async () => {
|
|
891
|
+
vi.spyOn(editor, 'getIsReadonly').mockReturnValue(false)
|
|
892
|
+
|
|
893
|
+
const info = { type: 'text' as const, text: 'test-data' }
|
|
894
|
+
await editor.replaceExternalContent(info)
|
|
895
|
+
|
|
896
|
+
expect(mockHandler).toHaveBeenCalledWith(info)
|
|
897
|
+
})
|
|
898
|
+
|
|
899
|
+
it('does not call external content handler when readonly', async () => {
|
|
900
|
+
vi.spyOn(editor, 'getIsReadonly').mockReturnValue(true)
|
|
901
|
+
|
|
902
|
+
const info = { type: 'text' as const, text: 'test-data' }
|
|
903
|
+
await editor.replaceExternalContent(info)
|
|
904
|
+
|
|
905
|
+
expect(mockHandler).not.toHaveBeenCalled()
|
|
906
|
+
})
|
|
907
|
+
|
|
908
|
+
it('calls external content handler when readonly but force is true', async () => {
|
|
909
|
+
vi.spyOn(editor, 'getIsReadonly').mockReturnValue(true)
|
|
910
|
+
|
|
911
|
+
const info = { type: 'text' as const, text: 'test-data' }
|
|
912
|
+
await editor.replaceExternalContent(info, { force: true })
|
|
913
|
+
|
|
914
|
+
expect(mockHandler).toHaveBeenCalledWith(info)
|
|
915
|
+
})
|
|
916
|
+
|
|
917
|
+
it('calls external content handler when force is false and not readonly', async () => {
|
|
918
|
+
vi.spyOn(editor, 'getIsReadonly').mockReturnValue(false)
|
|
919
|
+
|
|
920
|
+
const info = { type: 'text' as const, text: 'test-data' }
|
|
921
|
+
await editor.replaceExternalContent(info, { force: false })
|
|
922
|
+
|
|
923
|
+
expect(mockHandler).toHaveBeenCalledWith(info)
|
|
924
|
+
})
|
|
925
|
+
})
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -4680,8 +4680,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4680
4680
|
return this.store.createComputedCache<Box, TLShape>('pageBoundsCache', (shape) => {
|
|
4681
4681
|
const pageTransform = this.getShapePageTransform(shape)
|
|
4682
4682
|
if (!pageTransform) return undefined
|
|
4683
|
-
|
|
4684
|
-
return Box.FromPoints(
|
|
4683
|
+
|
|
4684
|
+
return Box.FromPoints(
|
|
4685
|
+
pageTransform.applyToPoints(this.getShapeGeometry(shape).boundsVertices)
|
|
4686
|
+
)
|
|
4685
4687
|
})
|
|
4686
4688
|
}
|
|
4687
4689
|
|
|
@@ -8831,8 +8833,13 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8831
8833
|
* Handle external content, such as files, urls, embeds, or plain text which has been put into the app, for example by pasting external text or dropping external images onto canvas.
|
|
8832
8834
|
*
|
|
8833
8835
|
* @param info - Info about the external content.
|
|
8836
|
+
* @param opts - Options for handling external content, including force flag to bypass readonly checks.
|
|
8834
8837
|
*/
|
|
8835
|
-
async putExternalContent<E>(
|
|
8838
|
+
async putExternalContent<E>(
|
|
8839
|
+
info: TLExternalContent<E>,
|
|
8840
|
+
opts = {} as { force?: boolean }
|
|
8841
|
+
): Promise<void> {
|
|
8842
|
+
if (!opts.force && this.getIsReadonly()) return
|
|
8836
8843
|
return this.externalContentHandlers[info.type]?.(info as any)
|
|
8837
8844
|
}
|
|
8838
8845
|
|
|
@@ -8840,8 +8847,13 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8840
8847
|
* Handle replacing external content.
|
|
8841
8848
|
*
|
|
8842
8849
|
* @param info - Info about the external content.
|
|
8850
|
+
* @param opts - Options for handling external content, including force flag to bypass readonly checks.
|
|
8843
8851
|
*/
|
|
8844
|
-
async replaceExternalContent<E>(
|
|
8852
|
+
async replaceExternalContent<E>(
|
|
8853
|
+
info: TLExternalContent<E>,
|
|
8854
|
+
opts = {} as { force?: boolean }
|
|
8855
|
+
): Promise<void> {
|
|
8856
|
+
if (!opts.force && this.getIsReadonly()) return
|
|
8845
8857
|
return this.externalContentHandlers[info.type]?.(info as any)
|
|
8846
8858
|
}
|
|
8847
8859
|
|
|
@@ -266,7 +266,7 @@ describe('LicenseManager', () => {
|
|
|
266
266
|
delete window.location
|
|
267
267
|
// @ts-ignore
|
|
268
268
|
window.location = new URL(
|
|
269
|
-
'vscode-webview
|
|
269
|
+
'vscode-webview://1ipd8pun8ud7nd7hv9d112g7evi7m10vak9vviuvia66ou6aibp3/index.html?id=6ec2dc7a-afe9-45d9-bd71-1749f9568d28&origin=955b256f-37e1-4a72-a2f4-ad633e88239c&swVersion=4&extensionId=tldraw-org.tldraw-vscode&platform=electron&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=vscode-file%3A%2F%2Fvscode-app'
|
|
270
270
|
)
|
|
271
271
|
|
|
272
272
|
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
@@ -286,7 +286,7 @@ describe('LicenseManager', () => {
|
|
|
286
286
|
delete window.location
|
|
287
287
|
// @ts-ignore
|
|
288
288
|
window.location = new URL(
|
|
289
|
-
'vscode-webview
|
|
289
|
+
'vscode-webview://1ipd8pun8ud7nd7hv9d112g7evi7m10vak9vviuvia66ou6aibp3/index.html?id=6ec2dc7a-afe9-45d9-bd71-1749f9568d28&origin=955b256f-37e1-4a72-a2f4-ad633e88239c&swVersion=4&extensionId=tldraw-org.tldraw-vscode&platform=electron&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=vscode-file%3A%2F%2Fvscode-app'
|
|
290
290
|
)
|
|
291
291
|
|
|
292
292
|
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
@@ -300,6 +300,70 @@ describe('LicenseManager', () => {
|
|
|
300
300
|
)) as ValidLicenseKeyResult
|
|
301
301
|
expect(result.isDomainValid).toBe(false)
|
|
302
302
|
})
|
|
303
|
+
|
|
304
|
+
it('Succeeds if it is a native app', async () => {
|
|
305
|
+
// @ts-ignore
|
|
306
|
+
delete window.location
|
|
307
|
+
// @ts-ignore
|
|
308
|
+
window.location = new URL('app-bundle://app/index.html')
|
|
309
|
+
|
|
310
|
+
const nativeLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
311
|
+
nativeLicenseInfo[PROPERTIES.FLAGS] = FLAGS.NATIVE_LICENSE
|
|
312
|
+
nativeLicenseInfo[PROPERTIES.HOSTS] = ['app-bundle:']
|
|
313
|
+
const nativeLicenseKey = await generateLicenseKey(JSON.stringify(nativeLicenseInfo), keyPair)
|
|
314
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
315
|
+
nativeLicenseKey
|
|
316
|
+
)) as ValidLicenseKeyResult
|
|
317
|
+
expect(result.isDomainValid).toBe(true)
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
it('Succeeds if it is a native app with a wildcard', async () => {
|
|
321
|
+
// @ts-ignore
|
|
322
|
+
delete window.location
|
|
323
|
+
// @ts-ignore
|
|
324
|
+
window.location = new URL('app-bundle://unique-id-123/index.html')
|
|
325
|
+
|
|
326
|
+
const nativeLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
327
|
+
nativeLicenseInfo[PROPERTIES.FLAGS] = FLAGS.NATIVE_LICENSE
|
|
328
|
+
nativeLicenseInfo[PROPERTIES.HOSTS] = ['^app-bundle://unique-id-123.*']
|
|
329
|
+
const nativeLicenseKey = await generateLicenseKey(JSON.stringify(nativeLicenseInfo), keyPair)
|
|
330
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
331
|
+
nativeLicenseKey
|
|
332
|
+
)) as ValidLicenseKeyResult
|
|
333
|
+
expect(result.isDomainValid).toBe(true)
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
it('Succeeds if it is a native app with a wildcard and search param', async () => {
|
|
337
|
+
// @ts-ignore
|
|
338
|
+
delete window.location
|
|
339
|
+
// @ts-ignore
|
|
340
|
+
window.location = new URL('app-bundle://app/index.html?unique-id-123')
|
|
341
|
+
|
|
342
|
+
const nativeLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
343
|
+
nativeLicenseInfo[PROPERTIES.FLAGS] = FLAGS.NATIVE_LICENSE
|
|
344
|
+
nativeLicenseInfo[PROPERTIES.HOSTS] = ['^app-bundle://app.*unique-id-123.*']
|
|
345
|
+
const nativeLicenseKey = await generateLicenseKey(JSON.stringify(nativeLicenseInfo), keyPair)
|
|
346
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
347
|
+
nativeLicenseKey
|
|
348
|
+
)) as ValidLicenseKeyResult
|
|
349
|
+
expect(result.isDomainValid).toBe(true)
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
it('Fails if it is a native app with the wrong protocol', async () => {
|
|
353
|
+
// @ts-ignore
|
|
354
|
+
delete window.location
|
|
355
|
+
// @ts-ignore
|
|
356
|
+
window.location = new URL('blah-blundle://app/index.html')
|
|
357
|
+
|
|
358
|
+
const nativeLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
359
|
+
nativeLicenseInfo[PROPERTIES.FLAGS] = FLAGS.NATIVE_LICENSE
|
|
360
|
+
nativeLicenseInfo[PROPERTIES.HOSTS] = ['app-bundle:']
|
|
361
|
+
const nativeLicenseKey = await generateLicenseKey(JSON.stringify(nativeLicenseInfo), keyPair)
|
|
362
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
363
|
+
nativeLicenseKey
|
|
364
|
+
)) as ValidLicenseKeyResult
|
|
365
|
+
expect(result.isDomainValid).toBe(false)
|
|
366
|
+
})
|
|
303
367
|
})
|
|
304
368
|
|
|
305
369
|
describe('License types and flags', () => {
|
|
@@ -316,6 +380,17 @@ describe('LicenseManager', () => {
|
|
|
316
380
|
expect(result.isInternalLicense).toBe(true)
|
|
317
381
|
})
|
|
318
382
|
|
|
383
|
+
it('Checks for native license', async () => {
|
|
384
|
+
const nativeLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
385
|
+
nativeLicenseInfo[PROPERTIES.FLAGS] = FLAGS.NATIVE_LICENSE
|
|
386
|
+
const nativeLicenseKey = await generateLicenseKey(JSON.stringify(nativeLicenseInfo), keyPair)
|
|
387
|
+
|
|
388
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
389
|
+
nativeLicenseKey
|
|
390
|
+
)) as ValidLicenseKeyResult
|
|
391
|
+
expect(result.isNativeLicense).toBe(true)
|
|
392
|
+
})
|
|
393
|
+
|
|
319
394
|
it('Checks for license with watermark', async () => {
|
|
320
395
|
const withWatermarkLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
321
396
|
withWatermarkLicenseInfo[PROPERTIES.FLAGS] |= FLAGS.WITH_WATERMARK
|
|
@@ -553,6 +628,7 @@ function getDefaultLicenseResult(overrides: Partial<ValidLicenseKeyResult>): Val
|
|
|
553
628
|
isAnnualLicense: true,
|
|
554
629
|
isAnnualLicenseExpired: false,
|
|
555
630
|
isInternalLicense: false,
|
|
631
|
+
isNativeLicense: false,
|
|
556
632
|
isDevelopment: false,
|
|
557
633
|
isDomainValid: true,
|
|
558
634
|
isPerpetualLicense: false,
|
|
@@ -6,11 +6,22 @@ import { importPublicKey, str2ab } from '../utils/licensing'
|
|
|
6
6
|
const GRACE_PERIOD_DAYS = 30
|
|
7
7
|
|
|
8
8
|
export const FLAGS = {
|
|
9
|
+
// -- MUTUALLY EXCLUSIVE FLAGS --
|
|
10
|
+
// Annual means the license expires after a time period, usually 1 year.
|
|
9
11
|
ANNUAL_LICENSE: 1,
|
|
12
|
+
// Perpetual means the license never expires up to the max supported version.
|
|
10
13
|
PERPETUAL_LICENSE: 1 << 1,
|
|
14
|
+
|
|
15
|
+
// -- ADDITIVE FLAGS --
|
|
16
|
+
// Internal means the license is for internal use only.
|
|
11
17
|
INTERNAL_LICENSE: 1 << 2,
|
|
18
|
+
// Watermark means the product is watermarked.
|
|
12
19
|
WITH_WATERMARK: 1 << 3,
|
|
20
|
+
// Evaluation means the license is for evaluation purposes only.
|
|
13
21
|
EVALUATION_LICENSE: 1 << 4,
|
|
22
|
+
// Native means the license is for native apps which switches
|
|
23
|
+
// on special-case logic.
|
|
24
|
+
NATIVE_LICENSE: 1 << 5,
|
|
14
25
|
}
|
|
15
26
|
const HIGHEST_FLAG = Math.max(...Object.values(FLAGS))
|
|
16
27
|
|
|
@@ -69,6 +80,7 @@ export interface ValidLicenseKeyResult {
|
|
|
69
80
|
isPerpetualLicense: boolean
|
|
70
81
|
isPerpetualLicenseExpired: boolean
|
|
71
82
|
isInternalLicense: boolean
|
|
83
|
+
isNativeLicense: boolean
|
|
72
84
|
isLicensedWithWatermark: boolean
|
|
73
85
|
isEvaluationLicense: boolean
|
|
74
86
|
isEvaluationLicenseExpired: boolean
|
|
@@ -271,6 +283,7 @@ export class LicenseManager {
|
|
|
271
283
|
isPerpetualLicense,
|
|
272
284
|
isPerpetualLicenseExpired: isPerpetualLicense && this.isPerpetualLicenseExpired(expiryDate),
|
|
273
285
|
isInternalLicense: this.isFlagEnabled(licenseInfo.flags, FLAGS.INTERNAL_LICENSE),
|
|
286
|
+
isNativeLicense: this.isNativeLicense(licenseInfo),
|
|
274
287
|
isLicensedWithWatermark: this.isFlagEnabled(licenseInfo.flags, FLAGS.WITH_WATERMARK),
|
|
275
288
|
isEvaluationLicense,
|
|
276
289
|
isEvaluationLicenseExpired:
|
|
@@ -291,13 +304,13 @@ export class LicenseManager {
|
|
|
291
304
|
const currentHostname = window.location.hostname.toLowerCase()
|
|
292
305
|
|
|
293
306
|
return licenseInfo.hosts.some((host) => {
|
|
294
|
-
const
|
|
307
|
+
const normalizedHostOrUrlRegex = host.toLowerCase().trim()
|
|
295
308
|
|
|
296
309
|
// Allow the domain if listed and www variations, 'example.com' allows 'example.com' and 'www.example.com'
|
|
297
310
|
if (
|
|
298
|
-
|
|
299
|
-
`www.${
|
|
300
|
-
|
|
311
|
+
normalizedHostOrUrlRegex === currentHostname ||
|
|
312
|
+
`www.${normalizedHostOrUrlRegex}` === currentHostname ||
|
|
313
|
+
normalizedHostOrUrlRegex === `www.${currentHostname}`
|
|
301
314
|
) {
|
|
302
315
|
return true
|
|
303
316
|
}
|
|
@@ -308,6 +321,12 @@ export class LicenseManager {
|
|
|
308
321
|
return true
|
|
309
322
|
}
|
|
310
323
|
|
|
324
|
+
// Native license support
|
|
325
|
+
// In this case, `normalizedHost` is actually a protocol, e.g. `app-bundle:`
|
|
326
|
+
if (this.isNativeLicense(licenseInfo)) {
|
|
327
|
+
return new RegExp(normalizedHostOrUrlRegex).test(window.location.href)
|
|
328
|
+
}
|
|
329
|
+
|
|
311
330
|
// Glob testing, we only support '*.somedomain.com' right now.
|
|
312
331
|
if (host.includes('*')) {
|
|
313
332
|
const globToRegex = new RegExp(host.replace(/\*/g, '.*?'))
|
|
@@ -318,7 +337,7 @@ export class LicenseManager {
|
|
|
318
337
|
if (window.location.protocol === 'vscode-webview:') {
|
|
319
338
|
const currentUrl = new URL(window.location.href)
|
|
320
339
|
const extensionId = currentUrl.searchParams.get('extensionId')
|
|
321
|
-
if (
|
|
340
|
+
if (normalizedHostOrUrlRegex === extensionId) {
|
|
322
341
|
return true
|
|
323
342
|
}
|
|
324
343
|
}
|
|
@@ -327,6 +346,10 @@ export class LicenseManager {
|
|
|
327
346
|
})
|
|
328
347
|
}
|
|
329
348
|
|
|
349
|
+
private isNativeLicense(licenseInfo: LicenseInfo) {
|
|
350
|
+
return this.isFlagEnabled(licenseInfo.flags, FLAGS.NATIVE_LICENSE)
|
|
351
|
+
}
|
|
352
|
+
|
|
330
353
|
private getExpirationDateWithoutGracePeriod(expiryDate: Date) {
|
|
331
354
|
return new Date(expiryDate.getFullYear(), expiryDate.getMonth(), expiryDate.getDate())
|
|
332
355
|
}
|
|
@@ -17,7 +17,7 @@ export const LICENSE_TIMEOUT = 5000
|
|
|
17
17
|
|
|
18
18
|
/** @internal */
|
|
19
19
|
export function LicenseProvider({
|
|
20
|
-
licenseKey,
|
|
20
|
+
licenseKey = getLicenseKeyFromEnv() ?? undefined,
|
|
21
21
|
children,
|
|
22
22
|
}: {
|
|
23
23
|
licenseKey?: string
|
|
@@ -51,3 +51,42 @@ export function LicenseProvider({
|
|
|
51
51
|
function LicenseGate() {
|
|
52
52
|
return <div data-testid="tl-license-expired" style={{ display: 'none' }} />
|
|
53
53
|
}
|
|
54
|
+
|
|
55
|
+
let envLicenseKey: string | undefined | null = undefined
|
|
56
|
+
function getLicenseKeyFromEnv() {
|
|
57
|
+
if (envLicenseKey !== undefined) {
|
|
58
|
+
return envLicenseKey
|
|
59
|
+
}
|
|
60
|
+
// it's important here that we write out the full process.env.WHATEVER expression instead of
|
|
61
|
+
// doing something like process.env[someVariable]. This is because most bundlers do something
|
|
62
|
+
// like a find-replace inject environment variables, and so won't pick up on dynamic ones. It
|
|
63
|
+
// also means we can't do checks like `process.env && process.env.WHATEVER`, which is why we use
|
|
64
|
+
// the `getEnv` try/catch approach.
|
|
65
|
+
|
|
66
|
+
// framework-specific prefixes borrowed from the ones vercel uses, but trimmed down to just the
|
|
67
|
+
// react-y ones: https://vercel.com/docs/environment-variables/framework-environment-variables
|
|
68
|
+
envLicenseKey =
|
|
69
|
+
getEnv(() => process.env.TLDRAW_LICENSE_KEY) ||
|
|
70
|
+
getEnv(() => process.env.NEXT_PUBLIC_TLDRAW_LICENSE_KEY) ||
|
|
71
|
+
getEnv(() => process.env.REACT_APP_TLDRAW_LICENSE_KEY) ||
|
|
72
|
+
getEnv(() => process.env.GATSBY_TLDRAW_LICENSE_KEY) ||
|
|
73
|
+
getEnv(() => process.env.VITE_TLDRAW_LICENSE_KEY) ||
|
|
74
|
+
getEnv(() => process.env.PUBLIC_TLDRAW_LICENSE_KEY) ||
|
|
75
|
+
getEnv(() => (import.meta as any).env.TLDRAW_LICENSE_KEY) ||
|
|
76
|
+
getEnv(() => (import.meta as any).env.NEXT_PUBLIC_TLDRAW_LICENSE_KEY) ||
|
|
77
|
+
getEnv(() => (import.meta as any).env.REACT_APP_TLDRAW_LICENSE_KEY) ||
|
|
78
|
+
getEnv(() => (import.meta as any).env.GATSBY_TLDRAW_LICENSE_KEY) ||
|
|
79
|
+
getEnv(() => (import.meta as any).env.VITE_TLDRAW_LICENSE_KEY) ||
|
|
80
|
+
getEnv(() => (import.meta as any).env.PUBLIC_TLDRAW_LICENSE_KEY) ||
|
|
81
|
+
null
|
|
82
|
+
|
|
83
|
+
return envLicenseKey
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function getEnv(cb: () => string | undefined) {
|
|
87
|
+
try {
|
|
88
|
+
return cb()
|
|
89
|
+
} catch {
|
|
90
|
+
return undefined
|
|
91
|
+
}
|
|
92
|
+
}
|