efficient-shell 4.127.0 → 4.132.0
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/README.md +938 -5
- package/dist/{Browser-F5TKMP4K.js → Browser-XPVJ2K7B.js} +13 -10
- package/dist/Browser-XPVJ2K7B.js.map +1 -0
- package/dist/{Calculator-T3XG7S73.js → Calculator-ZXJPXG7F.js} +12 -9
- package/dist/Calculator-ZXJPXG7F.js.map +1 -0
- package/dist/ConfirmDialog-MTC7QMUJ.js +4 -0
- package/dist/{ConfirmDialog-LJXMB45A.js.map → ConfirmDialog-MTC7QMUJ.js.map} +1 -1
- package/dist/{CurrencyConverter-CASQMKLO.js → CurrencyConverter-WSJ2BBSX.js} +12 -9
- package/dist/CurrencyConverter-WSJ2BBSX.js.map +1 -0
- package/dist/{Documents-YX67YTZS.js → Documents-ONGSXUJI.js} +14 -11
- package/dist/Documents-ONGSXUJI.js.map +1 -0
- package/dist/{Files-QB63GO6J.js → Files-GQZMFWXQ.js} +17 -14
- package/dist/Files-GQZMFWXQ.js.map +1 -0
- package/dist/{Notepad-3SUD5XUE.js → Notepad-HM73XAM4.js} +15 -12
- package/dist/Notepad-HM73XAM4.js.map +1 -0
- package/dist/PdfViewer-M2YGZIYX.js +5 -0
- package/dist/{PdfViewer-LSP3YNFC.js.map → PdfViewer-M2YGZIYX.js.map} +1 -1
- package/dist/{PomodoroTimer-4EHD2QC4.js → PomodoroTimer-DG3LI5CX.js} +14 -11
- package/dist/PomodoroTimer-DG3LI5CX.js.map +1 -0
- package/dist/{Preview-4ZHR4SKP.js → Preview-TUSV4UMO.js} +16 -13
- package/dist/Preview-TUSV4UMO.js.map +1 -0
- package/dist/{Sidebar-J76PV4QF.js → Sidebar-BPU7RCZP.js} +5 -4
- package/dist/Sidebar-BPU7RCZP.js.map +1 -0
- package/dist/{Spreadsheet-G3SC7XJ5.js → Spreadsheet-3WTXCHYQ.js} +14 -11
- package/dist/Spreadsheet-3WTXCHYQ.js.map +1 -0
- package/dist/{Stock-TLT4VN2R.js → Stock-YMPOMUAW.js} +12 -9
- package/dist/Stock-YMPOMUAW.js.map +1 -0
- package/dist/{Weather-FRKX3DAK.js → Weather-NZO3CWLH.js} +12 -9
- package/dist/Weather-NZO3CWLH.js.map +1 -0
- package/dist/{WorldClock-GKCITO3M.js → WorldClock-HUC6D3AD.js} +12 -9
- package/dist/WorldClock-HUC6D3AD.js.map +1 -0
- package/dist/apps/index.js +26 -22
- package/dist/apps/index.js.map +1 -1
- package/dist/brand.css +1 -1
- package/dist/chunk-7IN7YZAL.js +547 -0
- package/dist/chunk-7IN7YZAL.js.map +1 -0
- package/dist/{chunk-YNGPTOL6.js → chunk-7MA5XBWD.js} +3 -3
- package/dist/{chunk-YNGPTOL6.js.map → chunk-7MA5XBWD.js.map} +1 -1
- package/dist/{chunk-WK7FV7VV.js → chunk-BJ34QOR3.js} +827 -625
- package/dist/chunk-BJ34QOR3.js.map +1 -0
- package/dist/{chunk-HNH7FOYB.js → chunk-CGXMWHQW.js} +7 -6
- package/dist/chunk-CGXMWHQW.js.map +1 -0
- package/dist/{chunk-XUCIYMN7.js → chunk-CJYO4RVV.js} +4 -4
- package/dist/{chunk-XUCIYMN7.js.map → chunk-CJYO4RVV.js.map} +1 -1
- package/dist/{chunk-N3CG5HG5.js → chunk-CLGNTGC5.js} +12 -11
- package/dist/chunk-CLGNTGC5.js.map +1 -0
- package/dist/chunk-D276EMXS.js +57 -0
- package/dist/chunk-D276EMXS.js.map +1 -0
- package/dist/{chunk-7KIOEKHS.js → chunk-E3TWIN7Z.js} +21 -135
- package/dist/chunk-E3TWIN7Z.js.map +1 -0
- package/dist/{chunk-2VM2FRZJ.js → chunk-EENVXIVU.js} +47 -67
- package/dist/chunk-EENVXIVU.js.map +1 -0
- package/dist/{chunk-YG45DAUT.js → chunk-FONEQRBH.js} +17 -11
- package/dist/chunk-FONEQRBH.js.map +1 -0
- package/dist/chunk-IPXN646P.js +14 -0
- package/dist/chunk-IPXN646P.js.map +1 -0
- package/dist/chunk-IRWSRJ4K.js +48 -0
- package/dist/chunk-IRWSRJ4K.js.map +1 -0
- package/dist/chunk-JMKYYPOF.js +7 -0
- package/dist/{chunk-CJZXR7MG.js.map → chunk-JMKYYPOF.js.map} +1 -1
- package/dist/{chunk-JFQGPY7W.js → chunk-KWEX4ZAF.js} +20 -17
- package/dist/chunk-KWEX4ZAF.js.map +1 -0
- package/dist/{chunk-OKEFO6TI.js → chunk-LQTVTOSY.js} +10 -10
- package/dist/chunk-LQTVTOSY.js.map +1 -0
- package/dist/{chunk-G4KA3SAX.js → chunk-MQPX6ERJ.js} +4 -4
- package/dist/{chunk-G4KA3SAX.js.map → chunk-MQPX6ERJ.js.map} +1 -1
- package/dist/{chunk-FQB24B42.js → chunk-SEWF4O3H.js} +3 -3
- package/dist/{chunk-FQB24B42.js.map → chunk-SEWF4O3H.js.map} +1 -1
- package/dist/{chunk-AXWC3332.js → chunk-TFXJRHJV.js} +3 -3
- package/dist/{chunk-AXWC3332.js.map → chunk-TFXJRHJV.js.map} +1 -1
- package/dist/{chunk-G3HQLQYZ.js → chunk-TQURTLK2.js} +59 -34
- package/dist/chunk-TQURTLK2.js.map +1 -0
- package/dist/{chunk-6XQHH7D2.js → chunk-TRCWINHF.js} +5 -5
- package/dist/{chunk-6XQHH7D2.js.map → chunk-TRCWINHF.js.map} +1 -1
- package/dist/{chunk-NPJCMM6V.js → chunk-VWZIGZFF.js} +4 -4
- package/dist/{chunk-NPJCMM6V.js.map → chunk-VWZIGZFF.js.map} +1 -1
- package/dist/{chunk-HYZ5QMVO.js → chunk-XH3ELPQZ.js} +22 -19
- package/dist/chunk-XH3ELPQZ.js.map +1 -0
- package/dist/{chunk-PPUZJFCI.js → chunk-ZKHD4J73.js} +8 -7
- package/dist/chunk-ZKHD4J73.js.map +1 -0
- package/dist/file-intake/index.js +3 -1
- package/dist/file-intake/index.js.map +1 -1
- package/dist/{index-dQia6NpB.d.ts → index-COwksV6G.d.ts} +699 -199
- package/dist/index.d.ts +2 -2
- package/dist/index.js +37 -32
- package/dist/index.js.map +1 -1
- package/dist/map/index.js +5 -3
- package/dist/map/index.js.map +1 -1
- package/dist/markdown/index.js +4 -3
- package/dist/markdown/index.js.map +1 -1
- package/dist/page-tabs/index.js +12 -8
- package/dist/page-tabs/index.js.map +1 -1
- package/dist/shell.css +17 -17
- package/dist/themes.css +15 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +17 -13
- package/dist/ui/index.js.map +1 -1
- package/dist/ui.css +691 -283
- package/package.json +1 -1
- package/dist/Browser-F5TKMP4K.js.map +0 -1
- package/dist/Calculator-T3XG7S73.js.map +0 -1
- package/dist/ConfirmDialog-LJXMB45A.js +0 -3
- package/dist/CurrencyConverter-CASQMKLO.js.map +0 -1
- package/dist/Documents-YX67YTZS.js.map +0 -1
- package/dist/Files-QB63GO6J.js.map +0 -1
- package/dist/Notepad-3SUD5XUE.js.map +0 -1
- package/dist/PdfViewer-LSP3YNFC.js +0 -4
- package/dist/PomodoroTimer-4EHD2QC4.js.map +0 -1
- package/dist/Preview-4ZHR4SKP.js.map +0 -1
- package/dist/Sidebar-J76PV4QF.js.map +0 -1
- package/dist/Spreadsheet-G3SC7XJ5.js.map +0 -1
- package/dist/Stock-TLT4VN2R.js.map +0 -1
- package/dist/Weather-FRKX3DAK.js.map +0 -1
- package/dist/WorldClock-GKCITO3M.js.map +0 -1
- package/dist/chunk-2VM2FRZJ.js.map +0 -1
- package/dist/chunk-3CUSBZWG.js +0 -59
- package/dist/chunk-3CUSBZWG.js.map +0 -1
- package/dist/chunk-7KIOEKHS.js.map +0 -1
- package/dist/chunk-CJZXR7MG.js +0 -7
- package/dist/chunk-G3HQLQYZ.js.map +0 -1
- package/dist/chunk-HNH7FOYB.js.map +0 -1
- package/dist/chunk-HYZ5QMVO.js.map +0 -1
- package/dist/chunk-JFQGPY7W.js.map +0 -1
- package/dist/chunk-N3CG5HG5.js.map +0 -1
- package/dist/chunk-OKEFO6TI.js.map +0 -1
- package/dist/chunk-PPUZJFCI.js.map +0 -1
- package/dist/chunk-WK7FV7VV.js.map +0 -1
- package/dist/chunk-YG45DAUT.js.map +0 -1
package/dist/apps/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/apps/openAttachment.ts","../../src/apps/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Route a stored file into the app that can read it — Preview for PDFs,\n * images, drawings and 3D models, Spreadsheet for CSV/TSV — instead of handing\n * it to a browser tab (harness UI-18).\n *\n * Lifted from the admin portal, where it had routed email and CRM-note\n * attachments since 2026-09; the customer, supplier and dealer portals needed\n * the same decision table for their own attachments, and a fourth copy of a\n * classification this specific is exactly what drifts.\n *\n * Two transports, because stored-file URLs differ by deployment:\n *\n * - By default the viewer is given the URL and fetches it itself. Fine where\n * the file is same-origin with the page.\n * - Pass `fetchBlob` where it is not. A presigned/CDN URL is cross-origin to\n * the portal, so the viewer's own fetch fails (\"Failed to fetch\") even\n * though the URL opens perfectly in a tab; the caller's API client pulls\n * the bytes instead, and the window shows a placeholder until they land.\n *\n * Binary workbooks (xlsx, ods) stay downloads on purpose: previewing one means\n * parsing untrusted bytes in the host's own origin.\n */\nimport toast from '../shell/toast';\nimport { setPdfPreview } from './_previewStage';\nimport { setSpreadsheetPreview } from './_spreadsheetStage';\n\n/** Minimal attachment shape — a filename and where the bytes are. */\nexport interface OpenableAttachment {\n filename?: string | null;\n /** `null` where the serializer could not address the stored file; treated\n * exactly like a missing one, so a caller need not narrow before calling. */\n url?: string | null;\n}\n\n/** `useWindowManager().openPage`. */\nexport type OpenPage = (path: string) => void;\n\nexport interface OpenAttachmentOptions {\n /**\n * Fetch the bytes yourself — for a URL the page cannot fetch (presigned/CDN)\n * or one that needs an Authorization header. Called only for a file a viewer\n * can render; the window opens on `loadingMessage` and swaps in the result.\n * Reject with an Error whose message the reader should see.\n */\n fetchBlob?: (att: OpenableAttachment) => Promise<Blob>;\n /** Placeholder headline while `fetchBlob` runs. Default: \"LOADING FILE\". */\n loadingMessage?: string;\n}\n\n/** Lower-case file extension (no dot) from a name or URL, '' if none. */\nfunction extOf(name: string): string {\n const m = /\\.([a-z0-9]+)(?:[?#].*)?$/i.exec((name || '').trim());\n return m ? m[1].toLowerCase() : '';\n}\n\nconst DELIMITED_TEXT_EXT = new Set(['csv', 'tsv']);\nconst BINARY_WORKBOOK_EXT = new Set(['xlsx', 'xls', 'xlsm', 'ods']);\nconst IMAGE_EXT = new Set(['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'svg', 'avif']);\nconst THREED_EXT = new Set(['step', 'stp', 'stl', 'obj', 'gltf', 'glb', '3mf', 'iges', 'igs']);\n\n/** Which viewer renders this file, or `null` for one neither app can show. */\nexport function attachmentKind(nameOrUrl: string): 'pdf' | 'image' | '3d' | 'dxf' | 'csv' | null {\n const ext = extOf(nameOrUrl);\n if (ext === 'pdf') return 'pdf';\n if (ext === 'dxf') return 'dxf';\n if (DELIMITED_TEXT_EXT.has(ext)) return 'csv';\n if (IMAGE_EXT.has(ext)) return 'image';\n if (THREED_EXT.has(ext)) return '3d';\n return null;\n}\n\nfunction openInNewTab(url: string) {\n window.open(url, '_blank', 'noopener,noreferrer');\n}\n\nasync function readText(url: string, opts: OpenAttachmentOptions, att: OpenableAttachment): Promise<string> {\n if (opts.fetchBlob) return (await opts.fetchBlob(att)).text();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`fetch failed: ${res.status}`);\n return res.text();\n}\n\nfunction errorText(err: unknown, fallback: string): string {\n const message = err instanceof Error ? err.message : '';\n return message || fallback;\n}\n\n/**\n * Open `att` in the shell app that can read it. `openPage` comes from\n * `useWindowManager()`.\n *\n * Resolves once the file has been handed to a window (or opened in a tab); it\n * never throws — a failure is shown to the reader, in the viewer when one is\n * already open for the file and as a toast when there is nothing to show it in.\n */\nexport async function openAttachment(\n att: OpenableAttachment,\n openPage: OpenPage,\n opts: OpenAttachmentOptions = {},\n): Promise<void> {\n const url = att?.url || '';\n const filename = att?.filename || 'attachment';\n if (!url && !opts.fetchBlob) {\n toast.error('This attachment has no download link.');\n return;\n }\n const kind = attachmentKind(filename) ?? attachmentKind(url);\n\n if (kind === 'csv') {\n try {\n setSpreadsheetPreview({ csv: await readText(url, opts, att), filename });\n openPage('/spreadsheet');\n } catch {\n toast.error('Could not open the spreadsheet — opening the file instead.');\n if (url) openInNewTab(url);\n }\n return;\n }\n\n if (BINARY_WORKBOOK_EXT.has(extOf(filename) || extOf(url))) {\n // Parsing an untrusted workbook in the host's own origin is not worth a\n // preview; the reader gets the file itself.\n toast.error('Spreadsheet preview is unavailable for this file type. Opening the file instead.');\n if (url) openInNewTab(url);\n return;\n }\n\n if (!kind) {\n // No viewer renders docx / txt / zip — say so rather than appear to fail.\n if (!url) {\n toast.error('This attachment has no download link.');\n return;\n }\n toast.info('Opening this file outside the app — no viewer can show it here.');\n openInNewTab(url);\n return;\n }\n\n if (!opts.fetchBlob) {\n setPdfPreview({ url, filename, kind });\n openPage('/preview');\n return;\n }\n\n // The viewer cannot fetch this URL itself: open it on a placeholder and swap\n // the bytes in, so a slow file is visibly loading and a failed one says why\n // in the window the reader is already looking at.\n const handle = setPdfPreview({\n filename, kind, converting: true,\n convertingMessage: opts.loadingMessage || 'LOADING FILE',\n });\n openPage('/preview');\n try {\n const blob = await opts.fetchBlob(att);\n handle.update({ url: URL.createObjectURL(blob), filename, kind });\n } catch (err) {\n handle.update({\n filename, kind, converting: false,\n convertingMessage: errorText(err, 'Failed to load this file.'),\n });\n }\n}\n","/**\n * Bundled apps — pre-built window registry entries for the 12 apps that ship\n * with `react-os-shell`. Consumers compose them into their own registry via\n * `createWindowRegistry`:\n *\n * import { createWindowRegistry } from 'react-os-shell';\n * import { bundledApps } from 'react-os-shell/apps';\n * import { erpEntities } from './shell-config';\n *\n * const windows = createWindowRegistry(bundledApps, erpEntities);\n *\n * Subsets are also exported (`utilityApps`, `documentApps`, `webApps`) so a\n * consumer can pick-and-choose without importing every component.\n *\n * NOTE: Notepad requires consumer-supplied persistence for stored content.\n * WorldClock uses `useShellPrefs()` so it lives in `bundledApps`; without a\n * consumer-supplied prefs adapter the city list won't survive a reload.\n */\nimport { lazy } from 'react';\nimport type { WindowRegistry } from '../windowRegistry/types';\n\n// ── Utility apps ──\nconst Calculator = lazy(() => import('./Calculator'));\nconst Spreadsheet = lazy(() => import('./Spreadsheet'));\nconst Weather = lazy(() => import('./Weather'));\nconst CurrencyConverter = lazy(() => import('./CurrencyConverter'));\nconst PomodoroTimer = lazy(() => import('./PomodoroTimer'));\nconst Notepad = lazy(() => import('./Notepad'));\nconst WorldClock = lazy(() => import('./WorldClock'));\nconst Stock = lazy(() => import('./Stock'));\n\n// ── Document apps ──\nconst Preview = lazy(() => import('./Preview'));\n/** The PDF reader out of the Preview window, for embedding in a pane of your\n * own (a preview beside a form, a document tab). Lazy for the same reason\n * every app here is: its static `pdfjs-dist` import must not land in a host's\n * startup bundle — so render it inside a `<Suspense>`, and give it a parent\n * with a resolved height. See `PdfViewerProps` for `fit`. */\nconst PdfViewer = lazy(() => import('./PdfViewer'));\nconst Documents = lazy(() => import('./Documents'));\nconst Files = lazy(() => import('./Files'));\n\n// ── Web ──\nconst Browser = lazy(() => import('./Browser'));\n\nexport const utilityApps: WindowRegistry = {\n '/calculator': { component: Calculator, label: 'Calculator', size: 'sm', allowPinOnTop: true, utility: true, widget: true, dimensions: [280, 420] },\n '/spreadsheet': { component: Spreadsheet, label: 'Spreadsheets', size: '2xl', appStyle: true, multiInstance: true },\n '/notepad': { component: Notepad, label: 'Notepad', size: 'lg', allowPinOnTop: true, flushBody: true },\n '/weather': { component: Weather, label: 'Weather', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 400] },\n '/currency': { component: CurrencyConverter, label: 'Currency Converter', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/pomodoro': { component: PomodoroTimer, label: 'Pomodoro Timer', size: 'sm', utility: true, widget: true, dimensions: [320, 600] },\n '/world-clock': { component: WorldClock, label: 'World Clock', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/stock': { component: Stock, label: 'Stocks', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 360] },\n};\n\nexport const documentApps: WindowRegistry = {\n '/preview': { component: Preview, label: 'Preview', size: '2xl', appStyle: true, multiInstance: true },\n '/documents': { component: Documents, label: 'Documents', size: 'xl', appStyle: true, multiInstance: true },\n '/files': { component: Files, label: 'Files', size: 'xl', appStyle: true },\n};\n\nexport const webApps: WindowRegistry = {\n '/browser': { component: Browser, label: 'Browser', size: '2xl', appStyle: true, multiInstance: true },\n};\n\nexport const bundledApps: WindowRegistry = {\n ...utilityApps,\n ...documentApps,\n ...webApps,\n};\n\nexport {\n Calculator,\n Spreadsheet,\n Notepad,\n Weather,\n CurrencyConverter,\n PomodoroTimer,\n WorldClock,\n Stock,\n Preview,\n PdfViewer,\n Documents,\n Files,\n Browser,\n};\n\nexport { BUILTIN_APP_INFO } from './_about';\nexport type { BuiltinAppId, BuiltinAppInfo } from './_about';\n// Setters/config live in small standalone modules (not the app-implementation\n// files) so importing them here never drags an app chunk — most notably\n// Preview's static pdfjs-dist import — into a host's startup bundle.\nexport { setPdfPreview } from './_previewStage';\nexport { setSpreadsheetPreview } from './_spreadsheetStage';\n// Routes a stored file to whichever of the two can read it (UI-18). Same\n// module family for the same reason: it imports the stages, not the apps.\nexport { openAttachment, attachmentKind } from './openAttachment';\nexport type { OpenableAttachment, OpenAttachmentOptions, OpenPage } from './openAttachment';\nexport { setBrowserStartUrl } from './_browserStage';\nexport { openFilesInTrashMode, setFilesDemoTree } from './_filesShared';\nexport type { FilesDemoNode } from './_filesShared';\nexport type { PdfPreviewData, PdfPreviewHandle } from './_previewStage';\n// Type-only, so this re-export is erased at build and never pulls the module.\nexport type { PdfViewerProps } from './PdfViewer';\nexport type { SpreadsheetPreviewData, SpreadsheetPreviewHandle } from './_spreadsheetStage';\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/apps/openAttachment.ts","../../src/apps/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Route a stored file into the app that can read it — Preview for PDFs,\n * images, drawings and 3D models, Spreadsheet for CSV/TSV — instead of handing\n * it to a browser tab (harness UI-18).\n *\n * Lifted from the admin portal, where it had routed email and CRM-note\n * attachments since 2026-09; the customer, supplier and dealer portals needed\n * the same decision table for their own attachments, and a fourth copy of a\n * classification this specific is exactly what drifts.\n *\n * Two transports, because stored-file URLs differ by deployment:\n *\n * - By default the viewer is given the URL and fetches it itself. Fine where\n * the file is same-origin with the page.\n * - Pass `fetchBlob` where it is not. A presigned/CDN URL is cross-origin to\n * the portal, so the viewer's own fetch fails (\"Failed to fetch\") even\n * though the URL opens perfectly in a tab; the caller's API client pulls\n * the bytes instead, and the window shows a placeholder until they land.\n *\n * Binary workbooks (xlsx, ods) stay downloads on purpose: previewing one means\n * parsing untrusted bytes in the host's own origin.\n */\nimport toast from '../shell/toast';\nimport { setPdfPreview } from './_previewStage';\nimport { setSpreadsheetPreview } from './_spreadsheetStage';\n\n/** Minimal attachment shape — a filename and where the bytes are. */\nexport interface OpenableAttachment {\n filename?: string | null;\n /** `null` where the serializer could not address the stored file; treated\n * exactly like a missing one, so a caller need not narrow before calling. */\n url?: string | null;\n}\n\n/** `useWindowManager().openPage`. */\nexport type OpenPage = (path: string) => void;\n\nexport interface OpenAttachmentOptions {\n /**\n * Fetch the bytes yourself — for a URL the page cannot fetch (presigned/CDN)\n * or one that needs an Authorization header. Called only for a file a viewer\n * can render; the window opens on `loadingMessage` and swaps in the result.\n * Reject with an Error whose message the reader should see.\n */\n fetchBlob?: (att: OpenableAttachment) => Promise<Blob>;\n /** Placeholder headline while `fetchBlob` runs. Default: \"LOADING FILE\". */\n loadingMessage?: string;\n}\n\n/** Lower-case file extension (no dot) from a name or URL, '' if none. */\nfunction extOf(name: string): string {\n const m = /\\.([a-z0-9]+)(?:[?#].*)?$/i.exec((name || '').trim());\n return m ? m[1].toLowerCase() : '';\n}\n\nconst DELIMITED_TEXT_EXT = new Set(['csv', 'tsv']);\nconst BINARY_WORKBOOK_EXT = new Set(['xlsx', 'xls', 'xlsm', 'ods']);\nconst IMAGE_EXT = new Set(['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'svg', 'avif']);\nconst THREED_EXT = new Set(['step', 'stp', 'stl', 'obj', 'gltf', 'glb', '3mf', 'iges', 'igs']);\n\n/** Which viewer renders this file, or `null` for one neither app can show. */\nexport function attachmentKind(nameOrUrl: string): 'pdf' | 'image' | '3d' | 'dxf' | 'csv' | null {\n const ext = extOf(nameOrUrl);\n if (ext === 'pdf') return 'pdf';\n if (ext === 'dxf') return 'dxf';\n if (DELIMITED_TEXT_EXT.has(ext)) return 'csv';\n if (IMAGE_EXT.has(ext)) return 'image';\n if (THREED_EXT.has(ext)) return '3d';\n return null;\n}\n\nfunction openInNewTab(url: string) {\n window.open(url, '_blank', 'noopener,noreferrer');\n}\n\nasync function readText(url: string, opts: OpenAttachmentOptions, att: OpenableAttachment): Promise<string> {\n if (opts.fetchBlob) return (await opts.fetchBlob(att)).text();\n const res = await fetch(url);\n if (!res.ok) throw new Error(`fetch failed: ${res.status}`);\n return res.text();\n}\n\nfunction errorText(err: unknown, fallback: string): string {\n const message = err instanceof Error ? err.message : '';\n return message || fallback;\n}\n\n/**\n * Open `att` in the shell app that can read it. `openPage` comes from\n * `useWindowManager()`.\n *\n * Resolves once the file has been handed to a window (or opened in a tab); it\n * never throws — a failure is shown to the reader, in the viewer when one is\n * already open for the file and as a toast when there is nothing to show it in.\n */\nexport async function openAttachment(\n att: OpenableAttachment,\n openPage: OpenPage,\n opts: OpenAttachmentOptions = {},\n): Promise<void> {\n const url = att?.url || '';\n const filename = att?.filename || 'attachment';\n if (!url && !opts.fetchBlob) {\n toast.error('This attachment has no download link.');\n return;\n }\n const kind = attachmentKind(filename) ?? attachmentKind(url);\n\n if (kind === 'csv') {\n try {\n setSpreadsheetPreview({ csv: await readText(url, opts, att), filename });\n openPage('/spreadsheet');\n } catch {\n toast.error('Could not open the spreadsheet — opening the file instead.');\n if (url) openInNewTab(url);\n }\n return;\n }\n\n if (BINARY_WORKBOOK_EXT.has(extOf(filename) || extOf(url))) {\n // Parsing an untrusted workbook in the host's own origin is not worth a\n // preview; the reader gets the file itself.\n toast.error('Spreadsheet preview is unavailable for this file type. Opening the file instead.');\n if (url) openInNewTab(url);\n return;\n }\n\n if (!kind) {\n // No viewer renders docx / txt / zip — say so rather than appear to fail.\n if (!url) {\n toast.error('This attachment has no download link.');\n return;\n }\n toast.info('Opening this file outside the app — no viewer can show it here.');\n openInNewTab(url);\n return;\n }\n\n if (!opts.fetchBlob) {\n setPdfPreview({ url, filename, kind });\n openPage('/preview');\n return;\n }\n\n // The viewer cannot fetch this URL itself: open it on a placeholder and swap\n // the bytes in, so a slow file is visibly loading and a failed one says why\n // in the window the reader is already looking at.\n const handle = setPdfPreview({\n filename, kind, converting: true,\n convertingMessage: opts.loadingMessage || 'LOADING FILE',\n });\n openPage('/preview');\n try {\n const blob = await opts.fetchBlob(att);\n handle.update({ url: URL.createObjectURL(blob), filename, kind });\n } catch (err) {\n handle.update({\n filename, kind, converting: false,\n convertingMessage: errorText(err, 'Failed to load this file.'),\n });\n }\n}\n","/**\n * Bundled apps — pre-built window registry entries for the 12 apps that ship\n * with `react-os-shell`. Consumers compose them into their own registry via\n * `createWindowRegistry`:\n *\n * import { createWindowRegistry } from 'react-os-shell';\n * import { bundledApps } from 'react-os-shell/apps';\n * import { erpEntities } from './shell-config';\n *\n * const windows = createWindowRegistry(bundledApps, erpEntities);\n *\n * Subsets are also exported (`utilityApps`, `documentApps`, `webApps`) so a\n * consumer can pick-and-choose without importing every component.\n *\n * NOTE: Notepad requires consumer-supplied persistence for stored content.\n * WorldClock uses `useShellPrefs()` so it lives in `bundledApps`; without a\n * consumer-supplied prefs adapter the city list won't survive a reload.\n */\nimport { lazy } from 'react';\nimport type { WindowRegistry } from '../windowRegistry/types';\n\n// ── Utility apps ──\nconst Calculator = lazy(() => import('./Calculator'));\nconst Spreadsheet = lazy(() => import('./Spreadsheet'));\nconst Weather = lazy(() => import('./Weather'));\nconst CurrencyConverter = lazy(() => import('./CurrencyConverter'));\nconst PomodoroTimer = lazy(() => import('./PomodoroTimer'));\nconst Notepad = lazy(() => import('./Notepad'));\nconst WorldClock = lazy(() => import('./WorldClock'));\nconst Stock = lazy(() => import('./Stock'));\n\n// ── Document apps ──\nconst Preview = lazy(() => import('./Preview'));\n/** The PDF reader out of the Preview window, for embedding in a pane of your\n * own (a preview beside a form, a document tab). Lazy for the same reason\n * every app here is: its static `pdfjs-dist` import must not land in a host's\n * startup bundle — so render it inside a `<Suspense>`, and give it a parent\n * with a resolved height. See `PdfViewerProps` for `fit`. */\nconst PdfViewer = lazy(() => import('./PdfViewer'));\nconst Documents = lazy(() => import('./Documents'));\nconst Files = lazy(() => import('./Files'));\n\n// ── Web ──\nconst Browser = lazy(() => import('./Browser'));\n\nexport const utilityApps: WindowRegistry = {\n '/calculator': { component: Calculator, label: 'Calculator', size: 'sm', allowPinOnTop: true, utility: true, widget: true, dimensions: [280, 420] },\n '/spreadsheet': { component: Spreadsheet, label: 'Spreadsheets', size: '2xl', appStyle: true, multiInstance: true },\n '/notepad': { component: Notepad, label: 'Notepad', size: 'lg', allowPinOnTop: true, flushBody: true },\n '/weather': { component: Weather, label: 'Weather', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 400] },\n '/currency': { component: CurrencyConverter, label: 'Currency Converter', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/pomodoro': { component: PomodoroTimer, label: 'Pomodoro Timer', size: 'sm', utility: true, widget: true, dimensions: [320, 600] },\n '/world-clock': { component: WorldClock, label: 'World Clock', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/stock': { component: Stock, label: 'Stocks', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 360] },\n};\n\nexport const documentApps: WindowRegistry = {\n '/preview': { component: Preview, label: 'Preview', size: '2xl', appStyle: true, multiInstance: true },\n '/documents': { component: Documents, label: 'Documents', size: 'xl', appStyle: true, multiInstance: true },\n '/files': { component: Files, label: 'Files', size: 'xl', appStyle: true },\n};\n\nexport const webApps: WindowRegistry = {\n '/browser': { component: Browser, label: 'Browser', size: '2xl', appStyle: true, multiInstance: true },\n};\n\nexport const bundledApps: WindowRegistry = {\n ...utilityApps,\n ...documentApps,\n ...webApps,\n};\n\nexport {\n Calculator,\n Spreadsheet,\n Notepad,\n Weather,\n CurrencyConverter,\n PomodoroTimer,\n WorldClock,\n Stock,\n Preview,\n PdfViewer,\n Documents,\n Files,\n Browser,\n};\n\nexport { BUILTIN_APP_INFO } from './_about';\nexport type { BuiltinAppId, BuiltinAppInfo } from './_about';\n// Setters/config live in small standalone modules (not the app-implementation\n// files) so importing them here never drags an app chunk — most notably\n// Preview's static pdfjs-dist import — into a host's startup bundle.\nexport { setPdfPreview } from './_previewStage';\nexport { setSpreadsheetPreview } from './_spreadsheetStage';\n// Routes a stored file to whichever of the two can read it (UI-18). Same\n// module family for the same reason: it imports the stages, not the apps.\nexport { openAttachment, attachmentKind } from './openAttachment';\nexport type { OpenableAttachment, OpenAttachmentOptions, OpenPage } from './openAttachment';\nexport { setBrowserStartUrl } from './_browserStage';\nexport { openFilesInTrashMode, setFilesDemoTree } from './_filesShared';\nexport type { FilesDemoNode } from './_filesShared';\nexport type { PdfPreviewData, PdfPreviewHandle } from './_previewStage';\n// Type-only, so this re-export is erased at build and never pulls the module.\nexport type { PdfViewerProps } from './PdfViewer';\nexport type { SpreadsheetPreviewData, SpreadsheetPreviewHandle } from './_spreadsheetStage';\n"]}
|