@ifc-lite/viewer 1.27.0 → 1.28.1

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 (162) hide show
  1. package/.turbo/turbo-build.log +35 -42
  2. package/CHANGELOG.md +74 -0
  3. package/dist/assets/{basketViewActivator-B3CdrLsb.js → basketViewActivator-Ce38DhXd.js} +8 -8
  4. package/dist/assets/{bcf-QeHK_Aud.js → bcf-Cv_O3JfD.js} +56 -56
  5. package/dist/assets/{decode-worker-CgM1iNSK.js → decode-worker-Cjign7Zh.js} +1 -1
  6. package/dist/assets/{deflate-B-d0SYQM.js → deflate-HbyMq59o.js} +1 -1
  7. package/dist/assets/drawing-2d-DW98umlt.js +257 -0
  8. package/dist/assets/e57-source-2wI9jkCA.js +1 -0
  9. package/dist/assets/{exporters-B4LbZFeT.js → exporters-BuD3XRzB.js} +1309 -1153
  10. package/dist/assets/geometry.worker-TH3fCCoY.js +1 -0
  11. package/dist/assets/{geotiff-CrVtDRFq.js → geotiff-B2HA8Bwm.js} +10 -10
  12. package/dist/assets/{ids-DjsGFN10.js → ids-DYUFMd5f.js} +952 -945
  13. package/dist/assets/{ifc-lite_bg-DsYUIHm3.wasm → ifc-lite_bg-BEA5DLmg.wasm} +0 -0
  14. package/dist/assets/index-E9wB0zWt.css +1 -0
  15. package/dist/assets/{index-COYokSKc.js → index-n5O1QJMM.js} +37877 -38126
  16. package/dist/assets/{index.es-CY202jA3.js → index.es-BKVIpZgL.js} +9 -9
  17. package/dist/assets/{jpeg-D4wOkf5h.js → jpeg-C7hjKjPX.js} +1 -1
  18. package/dist/assets/{jspdf.es.min-DIGb9BHN.js → jspdf.es.min-oWlFc42Y.js} +4 -4
  19. package/dist/assets/lens-C4p1kQ0p.js +1 -0
  20. package/dist/assets/{lerc-DmW0_tgf.js → lerc-BfIOGhQz.js} +1 -1
  21. package/dist/assets/{lzw-oWetY-d6.js → lzw-B0jRuuW5.js} +1 -1
  22. package/dist/assets/{native-bridge-BX8_tHXE.js → native-bridge-DpB-dtEn.js} +6 -3
  23. package/dist/assets/{packbits-F8Nkp4NY.js → packbits-DVvBTC39.js} +1 -1
  24. package/dist/assets/parser.worker-BDsWQ6rc.js +182 -0
  25. package/dist/assets/{pdf-Dsh3HPZB.js → pdf-dVIqI5ac.js} +10 -10
  26. package/dist/assets/raw-C0ZJYGmN.js +1 -0
  27. package/dist/assets/{sandbox-BAC3a-eN.js → sandbox-qpJlrNN0.js} +2962 -2554
  28. package/dist/assets/server-client-DVZ2huNS.js +719 -0
  29. package/dist/assets/{webimage-BLV1dgmd.js → webimage-B394g0Tw.js} +1 -1
  30. package/dist/assets/{xlsx-Bc2HTrjC.js → xlsx-D-oHO76J.js} +8 -8
  31. package/dist/assets/{zstd-C_1HxVrA.js → zstd-Bf38MwV2.js} +1 -1
  32. package/dist/index.html +9 -9
  33. package/package.json +24 -23
  34. package/src/App.tsx +1 -3
  35. package/src/components/mcp/playground-dispatcher.ts +3 -0
  36. package/src/components/mcp/playground-files.ts +33 -1
  37. package/src/components/viewer/BCFPanel.tsx +1 -16
  38. package/src/components/viewer/ChatPanel.tsx +11 -46
  39. package/src/components/viewer/CommandPalette.tsx +6 -1
  40. package/src/components/viewer/ComparePanel.tsx +420 -0
  41. package/src/components/viewer/HierarchyPanel.tsx +48 -183
  42. package/src/components/viewer/IDSPanel.tsx +1 -26
  43. package/src/components/viewer/MainToolbar.tsx +94 -187
  44. package/src/components/viewer/MobileToolbar.tsx +1 -9
  45. package/src/components/viewer/PropertiesPanel.tsx +98 -127
  46. package/src/components/viewer/ScriptPanel.tsx +8 -34
  47. package/src/components/viewer/Section2DPanel.tsx +32 -1
  48. package/src/components/viewer/ViewerLayout.tsx +5 -2
  49. package/src/components/viewer/Viewport.tsx +3 -0
  50. package/src/components/viewer/ViewportContainer.tsx +24 -42
  51. package/src/components/viewer/ViewportOverlays.tsx +1 -4
  52. package/src/components/viewer/hierarchy/HierarchyNode.tsx +3 -3
  53. package/src/components/viewer/hierarchy/ifc-icons.ts +9 -0
  54. package/src/components/viewer/hierarchy/treeDataBuilder.ts +87 -0
  55. package/src/components/viewer/hierarchy/types.ts +1 -0
  56. package/src/components/viewer/hierarchy/useHierarchyTree.ts +6 -2
  57. package/src/components/viewer/properties/MaterialTotalsPanel.tsx +283 -0
  58. package/src/components/viewer/useGeometryStreaming.ts +0 -2
  59. package/src/hooks/federationLoadGate.test.ts +12 -2
  60. package/src/hooks/federationLoadGate.ts +9 -2
  61. package/src/hooks/ingest/federationAlign.ts +488 -0
  62. package/src/hooks/ingest/viewerModelIngest.ts +3 -212
  63. package/src/hooks/useCompare.ts +0 -0
  64. package/src/hooks/useCompareOverlay.ts +119 -0
  65. package/src/hooks/useDrawingGeneration.ts +234 -14
  66. package/src/hooks/useIfc.ts +1 -1
  67. package/src/hooks/useIfcCache.ts +100 -24
  68. package/src/hooks/useIfcFederation.ts +42 -811
  69. package/src/hooks/useIfcLoader.ts +349 -1517
  70. package/src/hooks/useIfcServer.ts +3 -0
  71. package/src/hooks/useLens.ts +5 -1
  72. package/src/hooks/useSymbolicAnnotations.ts +70 -38
  73. package/src/lib/compare/buildFingerprints.ts +173 -0
  74. package/src/lib/compare/describeChange.ts +0 -0
  75. package/src/lib/compare/geometricData.test.ts +54 -0
  76. package/src/lib/compare/geometricData.ts +37 -0
  77. package/src/lib/compare/overlay.test.ts +99 -0
  78. package/src/lib/compare/overlay.ts +91 -0
  79. package/src/lib/geo/cesium-placement.ts +1 -1
  80. package/src/lib/geo/reproject.ts +4 -1
  81. package/src/lib/llm/script-edit-ops.ts +23 -0
  82. package/src/lib/llm/stream-client.ts +8 -1
  83. package/src/lib/search/result-export.ts +7 -1
  84. package/src/sdk/adapters/export-adapter.ts +6 -1
  85. package/src/services/cacheService.ts +9 -25
  86. package/src/services/desktop-export.ts +2 -59
  87. package/src/services/file-dialog.ts +8 -142
  88. package/src/store/constants.ts +23 -0
  89. package/src/store/globalId.ts +15 -13
  90. package/src/store/index.ts +19 -6
  91. package/src/store/slices/cesiumSlice.ts +8 -1
  92. package/src/store/slices/compareSlice.ts +96 -0
  93. package/src/store/slices/drawing2DSlice.ts +8 -0
  94. package/src/store/slices/lensSlice.ts +8 -0
  95. package/src/store/slices/visibilitySlice.ts +22 -1
  96. package/src/store/types.ts +1 -71
  97. package/src/utils/acquireFileBuffer.test.ts +12 -4
  98. package/src/utils/ifcConfig.ts +0 -12
  99. package/src/utils/loadingUtils.ts +32 -0
  100. package/src/utils/spatialHierarchy.test.ts +53 -1
  101. package/src/utils/spatialHierarchy.ts +42 -2
  102. package/src/vite-env.d.ts +2 -0
  103. package/vite.config.ts +6 -3
  104. package/DESKTOP_CONTRACT_VERSION +0 -1
  105. package/dist/assets/drawing-2d-C71b8Ugx.js +0 -257
  106. package/dist/assets/e57-source-CQHxE8n3.js +0 -1
  107. package/dist/assets/event-B0kAzHa-.js +0 -1
  108. package/dist/assets/geometry.worker-BdH-E6NB.js +0 -1
  109. package/dist/assets/index-ajK6D32J.css +0 -1
  110. package/dist/assets/lens-PYsLu_MA.js +0 -1
  111. package/dist/assets/parser.worker-D591Zu_-.js +0 -182
  112. package/dist/assets/raw-D9iw0tmc.js +0 -1
  113. package/dist/assets/server-client-Cjwnm7il.js +0 -706
  114. package/dist/assets/tauri-core-stub-D8Fa-u43.js +0 -1
  115. package/dist/assets/tauri-dialog-stub-r7Wksg7o.js +0 -1
  116. package/dist/assets/tauri-fs-stub-BdeRC7aK.js +0 -1
  117. package/src/components/viewer/DesktopEntitlementBanner.tsx +0 -74
  118. package/src/components/viewer/SettingsPage.tsx +0 -581
  119. package/src/hooks/ingest/resolveDataStoreOrAbort.test.ts +0 -61
  120. package/src/hooks/ingest/resolveDataStoreOrAbort.ts +0 -28
  121. package/src/hooks/ingest/watchedGeometryStream.test.ts +0 -78
  122. package/src/hooks/ingest/watchedGeometryStream.ts +0 -76
  123. package/src/lib/desktop/desktopEntitlementEvents.ts +0 -39
  124. package/src/lib/desktop-entitlement.ts +0 -43
  125. package/src/lib/desktop-product.ts +0 -130
  126. package/src/lib/platform.ts +0 -23
  127. package/src/services/desktop-cache.ts +0 -186
  128. package/src/services/desktop-harness.ts +0 -196
  129. package/src/services/desktop-logger.ts +0 -20
  130. package/src/services/desktop-native-metadata.ts +0 -230
  131. package/src/services/desktop-panel-actions.ts +0 -43
  132. package/src/services/desktop-preferences.ts +0 -44
  133. package/src/services/fs-cache.ts +0 -212
  134. package/src/services/tauri-core-stub.ts +0 -7
  135. package/src/services/tauri-dialog-stub.ts +0 -7
  136. package/src/services/tauri-fs-stub.ts +0 -7
  137. package/src/services/tauri-modules.d.ts +0 -50
  138. package/src/store/slices/desktopEntitlementSlice.ts +0 -86
  139. package/src/utils/desktopModelSnapshot.ts +0 -358
  140. package/src/utils/nativeSpatialDataStore.ts +0 -277
  141. package/src-tauri/Cargo.toml +0 -29
  142. package/src-tauri/build.rs +0 -7
  143. package/src-tauri/capabilities/default.json +0 -18
  144. package/src-tauri/icons/128x128.png +0 -0
  145. package/src-tauri/icons/128x128@2x.png +0 -0
  146. package/src-tauri/icons/32x32.png +0 -0
  147. package/src-tauri/icons/Square107x107Logo.png +0 -0
  148. package/src-tauri/icons/Square142x142Logo.png +0 -0
  149. package/src-tauri/icons/Square150x150Logo.png +0 -0
  150. package/src-tauri/icons/Square284x284Logo.png +0 -0
  151. package/src-tauri/icons/Square30x30Logo.png +0 -0
  152. package/src-tauri/icons/Square310x310Logo.png +0 -0
  153. package/src-tauri/icons/Square44x44Logo.png +0 -0
  154. package/src-tauri/icons/Square71x71Logo.png +0 -0
  155. package/src-tauri/icons/Square89x89Logo.png +0 -0
  156. package/src-tauri/icons/StoreLogo.png +0 -0
  157. package/src-tauri/icons/icon.icns +0 -0
  158. package/src-tauri/icons/icon.ico +0 -0
  159. package/src-tauri/icons/icon.png +0 -0
  160. package/src-tauri/src/lib.rs +0 -21
  161. package/src-tauri/src/main.rs +0 -10
  162. package/src-tauri/tauri.conf.json +0 -39
@@ -1,212 +0,0 @@
1
- /* This Source Code Form is subject to the terms of the Mozilla Public
2
- * License, v. 2.0. If a copy of the MPL was not distributed with this
3
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
-
5
- /**
6
- * File system cache service for IFC files (Tauri desktop)
7
- *
8
- * Stores parsed IFC data and geometry in app data directory for fast subsequent loads.
9
- * Uses xxhash64 of the source file as the cache key.
10
- */
11
-
12
- import * as fs from '@tauri-apps/plugin-fs';
13
- import { appDataDir, join } from '@tauri-apps/api/path';
14
-
15
- const CACHE_DIR_NAME = 'ifc-lite-cache';
16
-
17
- let cacheDirPath: string | null = null;
18
-
19
- /**
20
- * Get the cache directory path, creating it if necessary
21
- */
22
- async function getCacheDir(): Promise<string> {
23
- if (cacheDirPath) return cacheDirPath;
24
-
25
- const appDir = await appDataDir();
26
- cacheDirPath = await join(appDir, CACHE_DIR_NAME);
27
-
28
- // Ensure cache directory exists (writeFile does NOT auto-create parent directories)
29
- await fs.mkdir(cacheDirPath, { recursive: true });
30
-
31
- return cacheDirPath;
32
- }
33
-
34
- /**
35
- * Get cache file path for a given key
36
- */
37
- async function getCachePath(key: string): Promise<string> {
38
- const dir = await getCacheDir();
39
- return `${dir}/${key}.cache`;
40
- }
41
-
42
- /**
43
- * Get metadata file path for a given key
44
- */
45
- async function getMetadataPath(key: string): Promise<string> {
46
- const dir = await getCacheDir();
47
- return `${dir}/${key}.meta.json`;
48
- }
49
-
50
- interface CacheMetadata {
51
- fileName: string;
52
- fileSize: number;
53
- createdAt: number;
54
- }
55
-
56
- /**
57
- * Get a cached model by hash key
58
- */
59
- export async function getCached(key: string): Promise<ArrayBuffer | null> {
60
- try {
61
- const cachePath = await getCachePath(key);
62
-
63
- if (!(await fs.exists(cachePath))) {
64
- return null;
65
- }
66
-
67
- const data = await fs.readFile(cachePath);
68
- // Slice to actual data range - Uint8Array.buffer may contain extra bytes
69
- const buffer = (data.buffer as ArrayBuffer).slice(data.byteOffset, data.byteOffset + data.byteLength);
70
-
71
- console.log(`[FS Cache] Cache hit for key ${key} (${(buffer.byteLength / 1024 / 1024).toFixed(2)}MB)`);
72
- return buffer;
73
- } catch (err) {
74
- console.warn('[FS Cache] Cache read failed:', err);
75
- return null;
76
- }
77
- }
78
-
79
- /**
80
- * Store a model in the cache
81
- */
82
- export async function setCached(
83
- key: string,
84
- buffer: ArrayBuffer,
85
- fileName: string,
86
- fileSize: number
87
- ): Promise<void> {
88
- try {
89
- const cachePath = await getCachePath(key);
90
- const metadataPath = await getMetadataPath(key);
91
-
92
- const metadata: CacheMetadata = {
93
- fileName,
94
- fileSize,
95
- createdAt: Date.now(),
96
- };
97
-
98
- await fs.writeFile(cachePath, new Uint8Array(buffer));
99
- await fs.writeTextFile(metadataPath, JSON.stringify(metadata, null, 2));
100
-
101
- console.log(`[FS Cache] Cached ${fileName} (${(fileSize / 1024 / 1024).toFixed(2)}MB)`);
102
- } catch (err) {
103
- console.warn('[FS Cache] Cache write failed:', err);
104
- }
105
- }
106
-
107
- /**
108
- * Check if a cache entry exists
109
- */
110
- export async function hasCached(key: string): Promise<boolean> {
111
- try {
112
- const cachePath = await getCachePath(key);
113
- return await fs.exists(cachePath);
114
- } catch {
115
- return false;
116
- }
117
- }
118
-
119
- /**
120
- * Delete a cache entry
121
- */
122
- export async function deleteCached(key: string): Promise<void> {
123
- try {
124
- const cachePath = await getCachePath(key);
125
- const metadataPath = await getMetadataPath(key);
126
-
127
- if (await fs.exists(cachePath)) {
128
- await fs.remove(cachePath);
129
- }
130
- if (await fs.exists(metadataPath)) {
131
- await fs.remove(metadataPath);
132
- }
133
- } catch (err) {
134
- console.warn('[FS Cache] Failed to delete cache entry:', err);
135
- }
136
- }
137
-
138
- /**
139
- * Clear all cached models
140
- */
141
- export async function clearCache(): Promise<void> {
142
- try {
143
- const dir = await getCacheDir();
144
- if (!(await fs.exists(dir))) {
145
- return;
146
- }
147
-
148
- const entries = await fs.readDir(dir);
149
- for (const entry of entries) {
150
- if (entry.name) {
151
- await fs.remove(`${dir}/${entry.name}`);
152
- }
153
- }
154
-
155
- console.log('[FS Cache] Cache cleared');
156
- } catch (err) {
157
- console.warn('[FS Cache] Failed to clear cache:', err);
158
- }
159
- }
160
-
161
- /**
162
- * Get cache statistics
163
- */
164
- export async function getCacheStats(): Promise<{
165
- entryCount: number;
166
- totalSize: number;
167
- entries: Array<{ fileName: string; fileSize: number; createdAt: Date }>;
168
- }> {
169
- try {
170
- const dir = await getCacheDir();
171
- if (!(await fs.exists(dir))) {
172
- return { entryCount: 0, totalSize: 0, entries: [] };
173
- }
174
-
175
- const entries = await fs.readDir(dir);
176
- const metadataFiles = entries.filter((e) => e.name?.endsWith('.meta.json'));
177
-
178
- const stats = {
179
- entryCount: 0,
180
- totalSize: 0,
181
- entries: [] as Array<{ fileName: string; fileSize: number; createdAt: Date }>,
182
- };
183
-
184
- for (const metaFile of metadataFiles) {
185
- try {
186
- const metaPath = `${dir}/${metaFile.name}`;
187
- const metaContent = await fs.readTextFile(metaPath);
188
- const metadata: CacheMetadata = JSON.parse(metaContent);
189
-
190
- const cacheKey = metaFile.name!.replace('.meta.json', '');
191
- const cachePath = await getCachePath(cacheKey);
192
-
193
- if (await fs.exists(cachePath)) {
194
- const cacheData = await fs.readFile(cachePath);
195
- stats.entryCount++;
196
- stats.totalSize += cacheData.byteLength;
197
- stats.entries.push({
198
- fileName: metadata.fileName,
199
- fileSize: metadata.fileSize,
200
- createdAt: new Date(metadata.createdAt),
201
- });
202
- }
203
- } catch (err) {
204
- console.warn(`[FS Cache] Failed to read metadata for ${metaFile.name}:`, err);
205
- }
206
- }
207
-
208
- return stats;
209
- } catch {
210
- return { entryCount: 0, totalSize: 0, entries: [] };
211
- }
212
- }
@@ -1,7 +0,0 @@
1
- /* This Source Code Form is subject to the terms of the Mozilla Public
2
- * License, v. 2.0. If a copy of the MPL was not distributed with this
3
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
-
5
- export async function invoke(): Promise<never> {
6
- throw new Error('Tauri core API is unavailable in the browser build');
7
- }
@@ -1,7 +0,0 @@
1
- /* This Source Code Form is subject to the terms of the Mozilla Public
2
- * License, v. 2.0. If a copy of the MPL was not distributed with this
3
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
-
5
- export async function open(): Promise<null> {
6
- return null;
7
- }
@@ -1,7 +0,0 @@
1
- /* This Source Code Form is subject to the terms of the Mozilla Public
2
- * License, v. 2.0. If a copy of the MPL was not distributed with this
3
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
-
5
- export async function readFile(_path: string): Promise<Uint8Array> {
6
- throw new Error('Tauri file system API is unavailable in the browser benchmark build');
7
- }
@@ -1,50 +0,0 @@
1
- /* This Source Code Form is subject to the terms of the Mozilla Public
2
- * License, v. 2.0. If a copy of the MPL was not distributed with this
3
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
-
5
- /**
6
- * Ambient type declarations for Tauri-only modules.
7
- * These packages are only available at runtime in desktop (Tauri) builds
8
- * and are not installed in the web viewer's node_modules.
9
- */
10
-
11
- declare module '@tauri-apps/plugin-fs' {
12
- export function mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;
13
- export function writeFile(path: string, data: Uint8Array): Promise<void>;
14
- export function writeTextFile(path: string, data: string): Promise<void>;
15
- export function readFile(path: string): Promise<Uint8Array>;
16
- export function readTextFile(path: string): Promise<string>;
17
- export function exists(path: string): Promise<boolean>;
18
- export function remove(path: string): Promise<void>;
19
- export function readDir(path: string): Promise<Array<{ name: string | null }>>;
20
- export function stat(path: string): Promise<{ size: number; mtime?: number | null }>;
21
- }
22
-
23
- declare module '@tauri-apps/api/path' {
24
- export function appDataDir(): Promise<string>;
25
- export function join(...paths: string[]): Promise<string>;
26
- }
27
-
28
- declare module '@tauri-apps/api/core' {
29
- /**
30
- * Tauri's IPC entry point. Generic by command name.
31
- */
32
- export function invoke<T = unknown>(cmd: string, args?: Record<string, unknown>): Promise<T>;
33
- }
34
-
35
- declare module '@tauri-apps/plugin-dialog' {
36
- export interface OpenDialogOptions {
37
- title?: string;
38
- multiple?: boolean;
39
- directory?: boolean;
40
- defaultPath?: string;
41
- filters?: Array<{ name: string; extensions: string[] }>;
42
- }
43
- export interface SaveDialogOptions {
44
- title?: string;
45
- defaultPath?: string;
46
- filters?: Array<{ name: string; extensions: string[] }>;
47
- }
48
- export function open(options?: OpenDialogOptions): Promise<string | string[] | null>;
49
- export function save(options?: SaveDialogOptions): Promise<string | null>;
50
- }
@@ -1,86 +0,0 @@
1
- /* This Source Code Form is subject to the terms of the Mozilla Public
2
- * License, v. 2.0. If a copy of the MPL was not distributed with this
3
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
-
5
- import type { StateCreator } from 'zustand';
6
- import {
7
- getDefaultDesktopEntitlement,
8
- type DesktopEntitlement,
9
- type DesktopEntitlementSource,
10
- type DesktopEntitlementStatus,
11
- } from '@/lib/desktop-product';
12
-
13
- const STORAGE_KEY = 'ifc-lite:desktop-entitlement:v1';
14
-
15
- function sanitizeTimestamp(value: unknown): number | null {
16
- return typeof value === 'number' && Number.isFinite(value) ? value : null;
17
- }
18
-
19
- function parseStoredEntitlement(raw: string | null): DesktopEntitlement {
20
- if (!raw) {
21
- return getDefaultDesktopEntitlement();
22
- }
23
-
24
- try {
25
- const parsed = JSON.parse(raw) as Partial<DesktopEntitlement> | null;
26
- const fallback = getDefaultDesktopEntitlement();
27
- return {
28
- tier: parsed?.tier === 'pro' ? 'pro' : 'free',
29
- status: isEntitlementStatus(parsed?.status) ? parsed.status : fallback.status,
30
- source: isEntitlementSource(parsed?.source) ? parsed.source : fallback.source,
31
- userId: typeof parsed?.userId === 'string' ? parsed.userId : null,
32
- validatedAt: sanitizeTimestamp(parsed?.validatedAt),
33
- graceUntil: sanitizeTimestamp(parsed?.graceUntil),
34
- trialEndsAt: sanitizeTimestamp(parsed?.trialEndsAt),
35
- };
36
- } catch {
37
- return getDefaultDesktopEntitlement();
38
- }
39
- }
40
-
41
- function isEntitlementStatus(value: unknown): value is DesktopEntitlementStatus {
42
- return value === 'anonymous'
43
- || value === 'signed_out'
44
- || value === 'active'
45
- || value === 'trial'
46
- || value === 'expired'
47
- || value === 'grace_offline';
48
- }
49
-
50
- function isEntitlementSource(value: unknown): value is DesktopEntitlementSource {
51
- return value === 'anonymous' || value === 'clerk_claims' || value === 'cached';
52
- }
53
-
54
- function persistEntitlement(entitlement: DesktopEntitlement): void {
55
- try {
56
- localStorage.setItem(STORAGE_KEY, JSON.stringify(entitlement));
57
- } catch {
58
- // ignore storage failures
59
- }
60
- }
61
-
62
- export interface DesktopEntitlementSlice {
63
- desktopEntitlement: DesktopEntitlement;
64
- setDesktopEntitlement: (entitlement: DesktopEntitlement) => void;
65
- clearDesktopEntitlement: () => void;
66
- }
67
-
68
- export const createDesktopEntitlementSlice: StateCreator<
69
- DesktopEntitlementSlice,
70
- [],
71
- [],
72
- DesktopEntitlementSlice
73
- > = (set) => ({
74
- desktopEntitlement: parseStoredEntitlement(typeof localStorage === 'undefined' ? null : localStorage.getItem(STORAGE_KEY)),
75
-
76
- setDesktopEntitlement: (desktopEntitlement) => {
77
- persistEntitlement(desktopEntitlement);
78
- set({ desktopEntitlement });
79
- },
80
-
81
- clearDesktopEntitlement: () => {
82
- const next = getDefaultDesktopEntitlement();
83
- persistEntitlement(next);
84
- set({ desktopEntitlement: next });
85
- },
86
- });