cursedbelt 1.0.0 → 2.3.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/dist/client/index.js +1 -1
- package/dist/core/category/index.d.ts.map +1 -1
- package/dist/core/category/index.js +2 -1
- package/dist/core/category/index.js.map +1 -1
- package/dist/core/category/types.js +1 -1
- package/dist/core/category/types.js.map +1 -1
- package/dist/core/file-tree/fileTreeModel.d.ts +49 -0
- package/dist/core/file-tree/fileTreeModel.d.ts.map +1 -1
- package/dist/core/file-tree/fileTreeModel.js +84 -0
- package/dist/core/file-tree/fileTreeModel.js.map +1 -1
- package/dist/core/layout/index.js +1 -1
- package/dist/core/layout/index.js.map +1 -1
- package/dist/core/media/index.js +1 -1
- package/dist/core/media/index.js.map +1 -1
- package/dist/core/media/types.js +1 -1
- package/dist/core/media/types.js.map +1 -1
- package/dist/core/media/uploadLimits.js +1 -1
- package/dist/core/media/uploadLimits.js.map +1 -1
- package/dist/core/sharing/model.d.ts +1 -1
- package/dist/ctgr/index.js +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react/activity-bar/ActivityBar.d.ts +17 -0
- package/dist/react/activity-bar/ActivityBar.d.ts.map +1 -1
- package/dist/react/activity-bar/ActivityBar.js.map +1 -1
- package/dist/react/analytics/index.d.ts +1 -1
- package/dist/react/analytics/index.js +1 -1
- package/dist/react/chat/MessageComposer.d.ts.map +1 -1
- package/dist/react/chat/MessageComposer.js +5 -4
- package/dist/react/chat/MessageComposer.js.map +1 -1
- package/dist/react/components/Button.d.ts.map +1 -1
- package/dist/react/components/Button.js +3 -2
- package/dist/react/components/Button.js.map +1 -1
- package/dist/react/components/Checkbox.d.ts +19 -3
- package/dist/react/components/Checkbox.d.ts.map +1 -1
- package/dist/react/components/Checkbox.js +29 -12
- package/dist/react/components/Checkbox.js.map +1 -1
- package/dist/react/components/CodeArea.d.ts.map +1 -1
- package/dist/react/components/CodeArea.js +2 -1
- package/dist/react/components/CodeArea.js.map +1 -1
- package/dist/react/components/Collapsible.d.ts.map +1 -1
- package/dist/react/components/Collapsible.js +2 -1
- package/dist/react/components/Collapsible.js.map +1 -1
- package/dist/react/components/ComboboxField.d.ts.map +1 -1
- package/dist/react/components/ComboboxField.js +3 -2
- package/dist/react/components/ComboboxField.js.map +1 -1
- package/dist/react/components/CopyButton.d.ts.map +1 -1
- package/dist/react/components/CopyButton.js +2 -1
- package/dist/react/components/CopyButton.js.map +1 -1
- package/dist/react/components/DataTable/ColumnChecklist.d.ts.map +1 -1
- package/dist/react/components/DataTable/ColumnChecklist.js +2 -1
- package/dist/react/components/DataTable/ColumnChecklist.js.map +1 -1
- package/dist/react/components/DataTable/Pagination.d.ts.map +1 -1
- package/dist/react/components/DataTable/Pagination.js +2 -1
- package/dist/react/components/DataTable/Pagination.js.map +1 -1
- package/dist/react/components/DataTable/SortHeader.d.ts.map +1 -1
- package/dist/react/components/DataTable/SortHeader.js +2 -1
- package/dist/react/components/DataTable/SortHeader.js.map +1 -1
- package/dist/react/components/DataTable/TableFilterBuilder.d.ts +61 -0
- package/dist/react/components/DataTable/TableFilterBuilder.d.ts.map +1 -0
- package/dist/react/components/DataTable/{FilterBuilder.js → TableFilterBuilder.js} +26 -3
- package/dist/react/components/DataTable/TableFilterBuilder.js.map +1 -0
- package/dist/react/components/DataTable/Toolbar.d.ts +1 -1
- package/dist/react/components/DataTable/Toolbar.js +3 -3
- package/dist/react/components/DataTable/Toolbar.js.map +1 -1
- package/dist/react/components/DataTable/cells/LinkCell.d.ts.map +1 -1
- package/dist/react/components/DataTable/cells/LinkCell.js +2 -1
- package/dist/react/components/DataTable/cells/LinkCell.js.map +1 -1
- package/dist/react/components/DataTable/index.d.ts +1 -1
- package/dist/react/components/DataTable/index.d.ts.map +1 -1
- package/dist/react/components/DataTable/index.js +4 -1
- package/dist/react/components/DataTable/index.js.map +1 -1
- package/dist/react/components/DragHandle.d.ts.map +1 -1
- package/dist/react/components/DragHandle.js +2 -1
- package/dist/react/components/DragHandle.js.map +1 -1
- package/dist/react/components/EmojiField.d.ts.map +1 -1
- package/dist/react/components/EmojiField.js +2 -1
- package/dist/react/components/EmojiField.js.map +1 -1
- package/dist/react/components/EventTimeline.d.ts +3 -2
- package/dist/react/components/EventTimeline.d.ts.map +1 -1
- package/dist/react/components/EventTimeline.js +3 -2
- package/dist/react/components/EventTimeline.js.map +1 -1
- package/dist/react/components/IconButton.d.ts +1 -1
- package/dist/react/components/IconButton.js +1 -1
- package/dist/react/components/InfoHint.d.ts.map +1 -1
- package/dist/react/components/InfoHint.js +5 -4
- package/dist/react/components/InfoHint.js.map +1 -1
- package/dist/react/components/InheritBadge.js +1 -1
- package/dist/react/components/InheritBadge.js.map +1 -1
- package/dist/react/components/InlineEditableText.d.ts.map +1 -1
- package/dist/react/components/InlineEditableText.js +2 -1
- package/dist/react/components/InlineEditableText.js.map +1 -1
- package/dist/react/components/MeterList.d.ts.map +1 -1
- package/dist/react/components/MeterList.js +2 -1
- package/dist/react/components/MeterList.js.map +1 -1
- package/dist/react/components/PathText.d.ts +2 -2
- package/dist/react/components/PathText.d.ts.map +1 -1
- package/dist/react/components/PathText.js +2 -1
- package/dist/react/components/PathText.js.map +1 -1
- package/dist/react/components/RatingField.d.ts.map +1 -1
- package/dist/react/components/RatingField.js +2 -1
- package/dist/react/components/RatingField.js.map +1 -1
- package/dist/react/components/SecretInput.js +3 -2
- package/dist/react/components/SecretInput.js.map +1 -1
- package/dist/react/components/SegmentedControl.d.ts.map +1 -1
- package/dist/react/components/SegmentedControl.js +2 -1
- package/dist/react/components/SegmentedControl.js.map +1 -1
- package/dist/react/components/StarRating.d.ts.map +1 -1
- package/dist/react/components/StarRating.js +9 -5
- package/dist/react/components/StarRating.js.map +1 -1
- package/dist/react/components/StatStrip.d.ts.map +1 -1
- package/dist/react/components/StatStrip.js +2 -1
- package/dist/react/components/StatStrip.js.map +1 -1
- package/dist/react/components/StatTile.d.ts.map +1 -1
- package/dist/react/components/StatTile.js +3 -2
- package/dist/react/components/StatTile.js.map +1 -1
- package/dist/react/components/Tabs.d.ts.map +1 -1
- package/dist/react/components/Tabs.js +2 -1
- package/dist/react/components/Tabs.js.map +1 -1
- package/dist/react/components/TruncatedText.d.ts +2 -1
- package/dist/react/components/TruncatedText.d.ts.map +1 -1
- package/dist/react/components/TruncatedText.js +2 -1
- package/dist/react/components/TruncatedText.js.map +1 -1
- package/dist/react/components/calendar/MonthGrid.d.ts.map +1 -1
- package/dist/react/components/calendar/MonthGrid.js +2 -1
- package/dist/react/components/calendar/MonthGrid.js.map +1 -1
- package/dist/react/components/calendar/WeekView.d.ts.map +1 -1
- package/dist/react/components/calendar/WeekView.js +2 -1
- package/dist/react/components/calendar/WeekView.js.map +1 -1
- package/dist/react/components/revealOnHover.d.ts.map +1 -1
- package/dist/react/components/revealOnHover.js +2 -1
- package/dist/react/components/revealOnHover.js.map +1 -1
- package/dist/react/file-tree/FileTree.d.ts +50 -1
- package/dist/react/file-tree/FileTree.d.ts.map +1 -1
- package/dist/react/file-tree/FileTree.js +234 -6
- package/dist/react/file-tree/FileTree.js.map +1 -1
- package/dist/react/file-tree/fileTree.css +52 -0
- package/dist/react/filter-rail/FilterRail.d.ts.map +1 -1
- package/dist/react/filter-rail/FilterRail.js +5 -4
- package/dist/react/filter-rail/FilterRail.js.map +1 -1
- package/dist/react/folder-tree/FolderTreeRail.d.ts.map +1 -1
- package/dist/react/folder-tree/FolderTreeRail.js +2 -1
- package/dist/react/folder-tree/FolderTreeRail.js.map +1 -1
- package/dist/react/index.d.ts +5 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +5 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/layoutEngine/index.js +1 -1
- package/dist/react/layoutEngine/index.js.map +1 -1
- package/dist/react/lib/field.d.ts.map +1 -1
- package/dist/react/lib/field.js +3 -2
- package/dist/react/lib/field.js.map +1 -1
- package/dist/react/lib/floatingStyles.d.ts.map +1 -1
- package/dist/react/lib/floatingStyles.js +2 -1
- package/dist/react/lib/floatingStyles.js.map +1 -1
- package/dist/react/lib/tapTarget.d.ts +96 -0
- package/dist/react/lib/tapTarget.d.ts.map +1 -0
- package/dist/react/lib/tapTarget.js +96 -0
- package/dist/react/lib/tapTarget.js.map +1 -0
- package/dist/react/media/VideoTrimmer.d.ts +1 -1
- package/dist/react/media/VideoTrimmer.js +1 -1
- package/dist/react/media/denseGallery.css +3 -3
- package/dist/react/media/ffmpegWasm.js +2 -2
- package/dist/react/media/ffmpegWasm.js.map +1 -1
- package/dist/react/media/videoPlayer.css +42 -0
- package/dist/react/namespace/NamespaceTargetCapsule.d.ts +2 -2
- package/dist/react/namespace/NamespaceTargetCapsule.d.ts.map +1 -1
- package/dist/react/nav/BreadcrumbTrail.d.ts.map +1 -1
- package/dist/react/nav/BreadcrumbTrail.js +4 -3
- package/dist/react/nav/BreadcrumbTrail.js.map +1 -1
- package/dist/react/nav/HubTileGrid.d.ts.map +1 -1
- package/dist/react/nav/HubTileGrid.js +2 -1
- package/dist/react/nav/HubTileGrid.js.map +1 -1
- package/dist/react/nav/SideNav.d.ts.map +1 -1
- package/dist/react/nav/SideNav.js +4 -3
- package/dist/react/nav/SideNav.js.map +1 -1
- package/dist/react/nav/SideNavCustomize.d.ts.map +1 -1
- package/dist/react/nav/SideNavCustomize.js +2 -1
- package/dist/react/nav/SideNavCustomize.js.map +1 -1
- package/dist/react/palette/CommandPalette.d.ts.map +1 -1
- package/dist/react/palette/CommandPalette.js +3 -2
- package/dist/react/palette/CommandPalette.js.map +1 -1
- package/dist/server/drivers/pooledControlStores.pg.test.js +1 -0
- package/dist/server/drivers/pooledControlStores.pg.test.js.map +1 -1
- package/dist/server/drivers/pooledIdentityStore.pg.test.js +1 -0
- package/dist/server/drivers/pooledIdentityStore.pg.test.js.map +1 -1
- package/dist/server/drivers/retentionPolicy.pg.test.js +1 -0
- package/dist/server/drivers/retentionPolicy.pg.test.js.map +1 -1
- package/dist/server/guard/argon2Binding.d.ts +1 -1
- package/dist/server/guard/argon2Binding.js +1 -1
- package/dist/server/incidents/store.d.ts +3 -3
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/master-lock/masterLock.d.ts +1 -1
- package/dist/server/media-bun/index.js +1 -1
- package/dist/server/media-bun/index.js.map +1 -1
- package/dist/server/paths/appDataHome.d.ts +20 -0
- package/dist/server/paths/appDataHome.d.ts.map +1 -0
- package/dist/server/paths/appDataHome.js +69 -0
- package/dist/server/paths/appDataHome.js.map +1 -0
- package/dist/server/retention/archive.d.ts +3 -4
- package/dist/server/retention/archive.d.ts.map +1 -1
- package/dist/server/retention/archive.js +20 -15
- package/dist/server/retention/archive.js.map +1 -1
- package/dist/server/retention/index.d.ts +1 -1
- package/dist/server/retention/index.js +1 -1
- package/dist/server/retention/policy.d.ts +2 -2
- package/dist/server/retention/policy.d.ts.map +1 -1
- package/dist/server/retention/policy.js +1 -1
- package/dist/server/retention/store.d.ts.map +1 -1
- package/dist/server/retention/store.js +27 -20
- package/dist/server/retention/store.js.map +1 -1
- package/dist/server/runtime/localHost.d.ts +10 -5
- package/dist/server/runtime/localHost.d.ts.map +1 -1
- package/dist/server/runtime/localHost.js +12 -8
- package/dist/server/runtime/localHost.js.map +1 -1
- package/dist/server/runtime/meterRollup.pg.test.js +1 -0
- package/dist/server/runtime/meterRollup.pg.test.js.map +1 -1
- package/dist/server/runtime/recipe.d.ts +4 -4
- package/dist/server/runtime/retentionJob.pg.test.js +1 -0
- package/dist/server/runtime/retentionJob.pg.test.js.map +1 -1
- package/dist/server/search/pgSearchProvider.pg.test.js +1 -0
- package/dist/server/search/pgSearchProvider.pg.test.js.map +1 -1
- package/dist/shared/errors.d.ts +1 -1
- package/dist/shared/errors.js +1 -1
- package/dist/styles-static.css +391 -0
- package/dist/styles.css +27 -0
- package/package.json +19 -167
- package/scripts/generateStaticStyles.ts +122 -0
- package/scripts/publicSurface.ts +455 -0
- package/scripts/testTmpRoot.ts +34 -5
- package/src/client/index.ts +1 -1
- package/src/core/category/index.ts +2 -1
- package/src/core/category/types.ts +1 -1
- package/src/core/file-tree/fileTreeModel.spec.ts +134 -0
- package/src/core/file-tree/fileTreeModel.ts +104 -0
- package/src/core/layout/index.ts +1 -1
- package/src/core/media/index.ts +1 -1
- package/src/core/media/types.ts +1 -1
- package/src/core/media/uploadLimits.ts +1 -1
- package/src/core/sharing/model.ts +1 -1
- package/src/ctgr/index.ts +1 -1
- package/src/declaredDepsAreImported.spec.ts +87 -0
- package/src/demoFixture.spec.ts +133 -0
- package/src/index.ts +1 -1
- package/src/lockfileIsTracked.spec.ts +50 -0
- package/src/namedSubpathsResolve.spec.ts +119 -0
- package/src/publicSurface.spec.ts +72 -0
- package/src/react/activity-bar/ActivityBar.tsx +17 -0
- package/src/react/analytics/index.ts +1 -1
- package/src/react/chat/MessageComposer.tsx +5 -4
- package/src/react/components/Button.tsx +3 -2
- package/src/react/components/Checkbox.spec.tsx +51 -0
- package/src/react/components/Checkbox.tsx +68 -26
- package/src/react/components/CodeArea.tsx +2 -1
- package/src/react/components/CodeChip.spec.tsx +2 -2
- package/src/react/components/Collapsible.tsx +2 -1
- package/src/react/components/ComboboxField.tsx +3 -2
- package/src/react/components/CopyButton.tsx +2 -1
- package/src/react/components/CopyableText.spec.tsx +1 -1
- package/src/react/components/DataTable/ColumnChecklist.tsx +2 -1
- package/src/react/components/DataTable/Pagination.tsx +2 -1
- package/src/react/components/DataTable/SortHeader.tsx +2 -1
- package/src/react/components/DataTable/{FilterBuilder.tsx → TableFilterBuilder.tsx} +33 -5
- package/src/react/components/DataTable/Toolbar.tsx +3 -3
- package/src/react/components/DataTable/cells/LinkCell.tsx +2 -1
- package/src/react/components/DataTable/index.ts +8 -1
- package/src/react/components/DragHandle.tsx +2 -1
- package/src/react/components/EmojiField.tsx +2 -1
- package/src/react/components/EventTimeline.tsx +3 -2
- package/src/react/components/FileLocation.spec.tsx +1 -1
- package/src/react/components/IconButton.tsx +1 -1
- package/src/react/components/InfoHint.tsx +5 -4
- package/src/react/components/InheritBadge.tsx +1 -1
- package/src/react/components/InlineEditableText.tsx +2 -1
- package/src/react/components/MeterList.tsx +2 -1
- package/src/react/components/PathText.tsx +4 -3
- package/src/react/components/RatingField.tsx +2 -1
- package/src/react/components/SecretInput.tsx +3 -3
- package/src/react/components/SegmentedControl.tsx +2 -2
- package/src/react/components/StarRating.spec.tsx +2 -2
- package/src/react/components/StarRating.tsx +9 -5
- package/src/react/components/StatStrip.tsx +2 -1
- package/src/react/components/StatTile.tsx +3 -3
- package/src/react/components/Tabs.spec.tsx +3 -2
- package/src/react/components/Tabs.tsx +2 -1
- package/src/react/components/TruncatedText.tsx +2 -1
- package/src/react/components/calendar/MonthGrid.spec.tsx +2 -1
- package/src/react/components/calendar/MonthGrid.tsx +2 -1
- package/src/react/components/calendar/WeekView.tsx +2 -1
- package/src/react/components/revealOnHover.ts +3 -2
- package/src/react/file-tree/FileTree.spec.tsx +248 -0
- package/src/react/file-tree/FileTree.tsx +304 -4
- package/src/react/file-tree/fileTree.css +52 -0
- package/src/react/file-tree/fileTreeGeometry.fixture.json +151 -0
- package/src/react/file-tree/fileTreeGeometry.spec.ts +33 -52
- package/src/react/filter-rail/FilterRail.spec.tsx +2 -1
- package/src/react/filter-rail/FilterRail.tsx +5 -4
- package/src/react/folder-tree/FolderTreeRail.tsx +2 -1
- package/src/react/index.ts +13 -3
- package/src/react/layoutEngine/index.ts +1 -1
- package/src/react/layoutEngine/types.ts +1 -1
- package/src/react/lib/field.ts +4 -2
- package/src/react/lib/floatingStyles.spec.ts +2 -1
- package/src/react/lib/floatingStyles.ts +3 -1
- package/src/react/lib/tapTarget.ts +100 -0
- package/src/react/media/MaskPainter.tsx +2 -2
- package/src/react/media/VideoTrimmer.tsx +1 -1
- package/src/react/media/denseGallery.css +3 -3
- package/src/react/media/ffmpegWasm.ts +2 -2
- package/src/react/media/videoPlayer.css +42 -0
- package/src/react/namespace/NamespaceTargetCapsule.tsx +2 -2
- package/src/react/nav/BreadcrumbTrail.tsx +4 -3
- package/src/react/nav/HubTileGrid.tsx +2 -1
- package/src/react/nav/SideNav.tsx +4 -3
- package/src/react/nav/SideNavCustomize.tsx +2 -1
- package/src/react/palette/CommandPalette.tsx +3 -2
- package/src/server/ctgr.ts +1 -1
- package/src/server/drivers/pooledControlStores.pg.test.ts +1 -0
- package/src/server/drivers/pooledIdentityStore.pg.test.ts +1 -0
- package/src/server/drivers/retentionPolicy.pg.test.ts +1 -0
- package/src/server/guard/argon2Binding.ts +1 -1
- package/src/server/incidents/store.ts +3 -3
- package/src/server/index.ts +1 -1
- package/src/server/master-lock/masterLock.spec.ts +18 -2
- package/src/server/master-lock/masterLock.ts +1 -1
- package/src/server/media-bun/image.spec.ts +1 -0
- package/src/server/media-bun/index.ts +1 -1
- package/src/server/media-bun/video.spec.ts +1 -0
- package/src/server/paths/appDataHome.spec.ts +87 -0
- package/src/server/paths/appDataHome.ts +84 -0
- package/src/server/retention/archive.spec.ts +26 -4
- package/src/server/retention/archive.ts +20 -15
- package/src/server/retention/index.ts +1 -1
- package/src/server/retention/policy.ts +2 -2
- package/src/server/retention/store.spec.ts +38 -10
- package/src/server/retention/store.ts +26 -19
- package/src/server/runtime/localHost.spec.ts +22 -3
- package/src/server/runtime/localHost.ts +12 -9
- package/src/server/runtime/meterRollup.pg.test.ts +1 -0
- package/src/server/runtime/recipe.ts +4 -4
- package/src/server/runtime/retentionJob.pg.test.ts +1 -0
- package/src/server/search/pgSearchProvider.pg.test.ts +1 -0
- package/src/server/storage/binaryServerProcessing.integration.spec.ts +6 -2
- package/src/server/storage/chunked.integration.spec.ts +5 -2
- package/src/server/storage/fileUploadClient-chunked.integration.spec.ts +5 -2
- package/src/server/storage/files/adapter.photo.display.spec.ts +1 -0
- package/src/server/storage/imageThumbnail.spec.ts +1 -0
- package/src/server/storage/transcode.integration.spec.ts +5 -2
- package/src/server/storage/videoProcessor.posterOnly.spec.ts +1 -0
- package/src/shared/errors.ts +1 -1
- package/src/skippedTestsAreAnswered.spec.ts +215 -0
- package/src/styles-static.css +391 -0
- package/src/styles.css +27 -0
- package/src/stylesStaticMatches.spec.ts +134 -0
- package/src/tapTargetStylesheet.spec.ts +150 -0
- package/src/testTmpRoot.spec.ts +102 -0
- package/dist/core/duplicates/index.d.ts +0 -116
- package/dist/core/duplicates/index.d.ts.map +0 -1
- package/dist/core/duplicates/index.js +0 -178
- package/dist/core/duplicates/index.js.map +0 -1
- package/dist/core/namespace/helpers.d.ts +0 -14
- package/dist/core/namespace/helpers.d.ts.map +0 -1
- package/dist/core/namespace/helpers.js +0 -29
- package/dist/core/namespace/helpers.js.map +0 -1
- package/dist/core/namespace/index.d.ts +0 -4
- package/dist/core/namespace/index.d.ts.map +0 -1
- package/dist/core/namespace/index.js +0 -6
- package/dist/core/namespace/index.js.map +0 -1
- package/dist/core/namespace/memoryStore.d.ts +0 -19
- package/dist/core/namespace/memoryStore.d.ts.map +0 -1
- package/dist/core/namespace/memoryStore.js +0 -70
- package/dist/core/namespace/memoryStore.js.map +0 -1
- package/dist/core/namespace/types.d.ts +0 -44
- package/dist/core/namespace/types.d.ts.map +0 -1
- package/dist/core/namespace/types.js +0 -8
- package/dist/core/namespace/types.js.map +0 -1
- package/dist/game/core/DisposeRegistry.d.ts +0 -42
- package/dist/game/core/DisposeRegistry.d.ts.map +0 -1
- package/dist/game/core/DisposeRegistry.js +0 -67
- package/dist/game/core/DisposeRegistry.js.map +0 -1
- package/dist/game/core/drawBudget.d.ts +0 -26
- package/dist/game/core/drawBudget.d.ts.map +0 -1
- package/dist/game/core/drawBudget.js +0 -55
- package/dist/game/core/drawBudget.js.map +0 -1
- package/dist/game/core/fixedTimestep.d.ts +0 -38
- package/dist/game/core/fixedTimestep.d.ts.map +0 -1
- package/dist/game/core/fixedTimestep.js +0 -47
- package/dist/game/core/fixedTimestep.js.map +0 -1
- package/dist/game/core/index.d.ts +0 -9
- package/dist/game/core/index.d.ts.map +0 -1
- package/dist/game/core/index.js +0 -8
- package/dist/game/core/index.js.map +0 -1
- package/dist/game/core/inputCollector.d.ts +0 -82
- package/dist/game/core/inputCollector.d.ts.map +0 -1
- package/dist/game/core/inputCollector.js +0 -176
- package/dist/game/core/inputCollector.js.map +0 -1
- package/dist/game/core/resizeCanvas.d.ts +0 -19
- package/dist/game/core/resizeCanvas.d.ts.map +0 -1
- package/dist/game/core/resizeCanvas.js +0 -29
- package/dist/game/core/resizeCanvas.js.map +0 -1
- package/dist/game/react/index.d.ts +0 -3
- package/dist/game/react/index.d.ts.map +0 -1
- package/dist/game/react/index.js +0 -5
- package/dist/game/react/index.js.map +0 -1
- package/dist/game/react/useGameEngine.d.ts +0 -64
- package/dist/game/react/useGameEngine.d.ts.map +0 -1
- package/dist/game/react/useGameEngine.js +0 -78
- package/dist/game/react/useGameEngine.js.map +0 -1
- package/dist/react/canvas/CanvasNavHUD.d.ts +0 -64
- package/dist/react/canvas/CanvasNavHUD.d.ts.map +0 -1
- package/dist/react/canvas/CanvasNavHUD.js +0 -58
- package/dist/react/canvas/CanvasNavHUD.js.map +0 -1
- package/dist/react/canvas/fitLabel.d.ts +0 -53
- package/dist/react/canvas/fitLabel.d.ts.map +0 -1
- package/dist/react/canvas/fitLabel.js +0 -104
- package/dist/react/canvas/fitLabel.js.map +0 -1
- package/dist/react/canvas/index.d.ts +0 -4
- package/dist/react/canvas/index.d.ts.map +0 -1
- package/dist/react/canvas/index.js +0 -4
- package/dist/react/canvas/index.js.map +0 -1
- package/dist/react/canvas/lod.d.ts +0 -40
- package/dist/react/canvas/lod.d.ts.map +0 -1
- package/dist/react/canvas/lod.js +0 -37
- package/dist/react/canvas/lod.js.map +0 -1
- package/dist/react/components/DataTable/FilterBuilder.d.ts +0 -38
- package/dist/react/components/DataTable/FilterBuilder.d.ts.map +0 -1
- package/dist/react/components/DataTable/FilterBuilder.js.map +0 -1
- package/dist/react/seo/HeadProvider.d.ts +0 -14
- package/dist/react/seo/HeadProvider.d.ts.map +0 -1
- package/dist/react/seo/HeadProvider.js +0 -44
- package/dist/react/seo/HeadProvider.js.map +0 -1
- package/dist/react/seo/applyHeadToDocument.d.ts +0 -3
- package/dist/react/seo/applyHeadToDocument.d.ts.map +0 -1
- package/dist/react/seo/applyHeadToDocument.js +0 -66
- package/dist/react/seo/applyHeadToDocument.js.map +0 -1
- package/dist/react/seo/index.d.ts +0 -3
- package/dist/react/seo/index.d.ts.map +0 -1
- package/dist/react/seo/index.js +0 -7
- package/dist/react/seo/index.js.map +0 -1
- package/dist/react/timeline/ClipView.d.ts +0 -29
- package/dist/react/timeline/ClipView.d.ts.map +0 -1
- package/dist/react/timeline/ClipView.js +0 -53
- package/dist/react/timeline/ClipView.js.map +0 -1
- package/dist/react/timeline/Playhead.d.ts +0 -16
- package/dist/react/timeline/Playhead.d.ts.map +0 -1
- package/dist/react/timeline/Playhead.js +0 -26
- package/dist/react/timeline/Playhead.js.map +0 -1
- package/dist/react/timeline/TimeRuler.d.ts +0 -21
- package/dist/react/timeline/TimeRuler.d.ts.map +0 -1
- package/dist/react/timeline/TimeRuler.js +0 -31
- package/dist/react/timeline/TimeRuler.js.map +0 -1
- package/dist/react/timeline/TimelineSurface.d.ts +0 -29
- package/dist/react/timeline/TimelineSurface.d.ts.map +0 -1
- package/dist/react/timeline/TimelineSurface.js +0 -56
- package/dist/react/timeline/TimelineSurface.js.map +0 -1
- package/dist/react/timeline/TrackLane.d.ts +0 -31
- package/dist/react/timeline/TrackLane.d.ts.map +0 -1
- package/dist/react/timeline/TrackLane.js +0 -32
- package/dist/react/timeline/TrackLane.js.map +0 -1
- package/dist/react/timeline/index.d.ts +0 -6
- package/dist/react/timeline/index.d.ts.map +0 -1
- package/dist/react/timeline/index.js +0 -12
- package/dist/react/timeline/index.js.map +0 -1
- package/dist/server/private-media/index.d.ts +0 -7
- package/dist/server/private-media/index.d.ts.map +0 -1
- package/dist/server/private-media/index.js +0 -13
- package/dist/server/private-media/index.js.map +0 -1
- package/dist/server/seo/index.d.ts +0 -3
- package/dist/server/seo/index.d.ts.map +0 -1
- package/dist/server/seo/index.js +0 -6
- package/dist/server/seo/index.js.map +0 -1
- package/dist/server/seo/mountSeoRoutes.d.ts +0 -9
- package/dist/server/seo/mountSeoRoutes.d.ts.map +0 -1
- package/dist/server/seo/mountSeoRoutes.js +0 -19
- package/dist/server/seo/mountSeoRoutes.js.map +0 -1
- package/dist/server/seo/serveHeadInjectedIndex.d.ts +0 -9
- package/dist/server/seo/serveHeadInjectedIndex.d.ts.map +0 -1
- package/dist/server/seo/serveHeadInjectedIndex.js +0 -20
- package/dist/server/seo/serveHeadInjectedIndex.js.map +0 -1
- package/dist/upload.d.ts +0 -148
- package/dist/upload.d.ts.map +0 -1
- package/dist/upload.js +0 -159
- package/dist/upload.js.map +0 -1
- package/dist/verify/runtime/index.d.ts +0 -16
- package/dist/verify/runtime/index.d.ts.map +0 -1
- package/dist/verify/runtime/index.js +0 -16
- package/dist/verify/runtime/index.js.map +0 -1
- package/scripts/demoCheck.ts +0 -42
- package/src/core/duplicates/index.spec.ts +0 -116
- package/src/core/duplicates/index.ts +0 -203
- package/src/core/namespace/helpers.ts +0 -31
- package/src/core/namespace/index.ts +0 -12
- package/src/core/namespace/memoryStore.ts +0 -77
- package/src/core/namespace/namespace.spec.ts +0 -117
- package/src/core/namespace/types.ts +0 -53
- package/src/game/core/DisposeRegistry.spec.ts +0 -53
- package/src/game/core/DisposeRegistry.ts +0 -70
- package/src/game/core/drawBudget.spec.ts +0 -51
- package/src/game/core/drawBudget.ts +0 -75
- package/src/game/core/fixedTimestep.spec.ts +0 -91
- package/src/game/core/fixedTimestep.ts +0 -79
- package/src/game/core/index.ts +0 -16
- package/src/game/core/inputCollector.spec.ts +0 -29
- package/src/game/core/inputCollector.ts +0 -245
- package/src/game/core/resizeCanvas.ts +0 -31
- package/src/game/react/index.ts +0 -10
- package/src/game/react/useGameEngine.ts +0 -125
- package/src/react/canvas/CanvasNavHUD.spec.tsx +0 -62
- package/src/react/canvas/CanvasNavHUD.tsx +0 -210
- package/src/react/canvas/fitLabel.spec.ts +0 -82
- package/src/react/canvas/fitLabel.ts +0 -150
- package/src/react/canvas/index.ts +0 -15
- package/src/react/canvas/lod.ts +0 -53
- package/src/react/seo/HeadProvider.tsx +0 -67
- package/src/react/seo/applyHeadToDocument.ts +0 -73
- package/src/react/seo/index.ts +0 -12
- package/src/react/seo/seo.spec.tsx +0 -101
- package/src/react/timeline/ClipView.tsx +0 -146
- package/src/react/timeline/Playhead.tsx +0 -63
- package/src/react/timeline/TimeRuler.tsx +0 -85
- package/src/react/timeline/TimelineSurface.tsx +0 -157
- package/src/react/timeline/TrackLane.tsx +0 -87
- package/src/react/timeline/index.ts +0 -12
- package/src/react/timeline/timeline.spec.tsx +0 -175
- package/src/server/private-media/index.ts +0 -45
- package/src/server/seo/index.ts +0 -8
- package/src/server/seo/mountSeoRoutes.ts +0 -37
- package/src/server/seo/seo.spec.ts +0 -128
- package/src/server/seo/serveHeadInjectedIndex.ts +0 -36
- package/src/upload.spec.ts +0 -300
- package/src/upload.ts +0 -288
- package/src/verify/runtime/index.ts +0 -64
|
@@ -29,6 +29,7 @@ import { useDragReorder } from '../hooks/useDragReorder';
|
|
|
29
29
|
import { NavItemMenu } from './NavItemMenu';
|
|
30
30
|
import { type IconResolver, renderIcon } from './navShared';
|
|
31
31
|
import { Tooltip } from '../components/Tooltip';
|
|
32
|
+
import { TAP_TARGET } from '../lib/tapTarget';
|
|
32
33
|
|
|
33
34
|
export interface ReorderableRowsProps {
|
|
34
35
|
domains: NavDomain[];
|
|
@@ -98,7 +99,7 @@ export function RowCustomizeControls({
|
|
|
98
99
|
// pointer affordance only and must NOT be a Tab stop, so keyboard users tab
|
|
99
100
|
// cleanly through the nav links (a11y gotcha #NavItemMenu).
|
|
100
101
|
tabIndex={-1}
|
|
101
|
-
className={`inline-flex size-6 cursor-grab items-center justify-center rounded text-muted-foreground hover:text-foreground ${
|
|
102
|
+
className={`inline-flex size-6 cursor-grab items-center justify-center rounded text-muted-foreground hover:text-foreground ${TAP_TARGET}`}
|
|
102
103
|
>
|
|
103
104
|
<GripVertical className='size-4' />
|
|
104
105
|
</button>
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
CommandList,
|
|
43
43
|
} from './Command';
|
|
44
44
|
import { useShortcutRegistry } from './useShortcutRegistry';
|
|
45
|
+
import { TAP_TARGET_HEIGHT } from '../lib/tapTarget';
|
|
45
46
|
|
|
46
47
|
export interface CommandPaletteProps {
|
|
47
48
|
/** The single navigation registry (task 13) — the palette's page source of truth. */
|
|
@@ -540,7 +541,7 @@ function PinsQuickBar({
|
|
|
540
541
|
data-cb-pin-add=''
|
|
541
542
|
tooltip='Pin this page'
|
|
542
543
|
leftIcon={<Plus className='size-3.5' aria-hidden='true' />}
|
|
543
|
-
className=
|
|
544
|
+
className={`h-auto shrink-0 rounded-full border border-dashed border-border px-2.5 py-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground ${TAP_TARGET_HEIGHT}`}
|
|
544
545
|
>
|
|
545
546
|
Pin this page
|
|
546
547
|
</Button>
|
|
@@ -616,7 +617,7 @@ function PinChip({
|
|
|
616
617
|
}
|
|
617
618
|
: undefined
|
|
618
619
|
}
|
|
619
|
-
className=
|
|
620
|
+
className={`h-auto shrink-0 rounded-full border-border bg-surface px-2.5 py-1 text-xs font-medium text-foreground hover:bg-muted ${TAP_TARGET_HEIGHT}`}
|
|
620
621
|
>
|
|
621
622
|
{icon != null ? (
|
|
622
623
|
<span
|
package/src/server/ctgr.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ctgr Hono transport — the server half of the GET-tunnel: the `unGETify` middleware
|
|
3
3
|
* that decodes a `/ctgr<XX>` twin's query params back into the original request, and
|
|
4
4
|
* the `buildRoutes` registrar that wires the real verb route and its GET twin from one
|
|
5
|
-
* call. The codec
|
|
5
|
+
* call. The codec re-exports from `cursedbelt/server`; the browser side is `cursedbelt/client`.
|
|
6
6
|
*
|
|
7
7
|
* Protection is unchanged and lives elsewhere by design: the getOnly-claim 403 keys
|
|
8
8
|
* off the RAW request method (always GET on a twin) in the auth middleware, and the
|
|
@@ -31,6 +31,7 @@ const URL_ = process.env.CC_PG_URL;
|
|
|
31
31
|
let sql: SQL;
|
|
32
32
|
let pool: SaasPool;
|
|
33
33
|
|
|
34
|
+
// SKIPPED unless CC_PG_URL names a throwaway Postgres — this suite's subject IS the engine. `bun run test:pg` supplies one.
|
|
34
35
|
describe.skipIf(!URL_)('the shared control-plane stores against a real Postgres (04 §1)', () => {
|
|
35
36
|
// 120s, not Bun's default 5s. This hook drops and re-creates a role, a database
|
|
36
37
|
// and a whole migration chain against a REAL Postgres; on a shared 4-core CI
|
|
@@ -44,6 +44,7 @@ let store: RegistryIdentityStore;
|
|
|
44
44
|
|
|
45
45
|
const NOW = '2026-07-26T00:00:00.000Z';
|
|
46
46
|
|
|
47
|
+
// SKIPPED unless CC_PG_URL names a throwaway Postgres — this suite's subject IS the engine. `bun run test:pg` supplies one.
|
|
47
48
|
describe.skipIf(!URL_)('the saas identity tier against a real Postgres (04 §1a)', () => {
|
|
48
49
|
// 120s, not Bun's default 5s. This hook drops and re-creates a role, a database
|
|
49
50
|
// and a whole migration chain against a REAL Postgres; on a shared 4-core CI
|
|
@@ -35,6 +35,7 @@ const URL_ = process.env.CC_PG_URL;
|
|
|
35
35
|
let sql: SQL;
|
|
36
36
|
let executor: StatementExecutor;
|
|
37
37
|
|
|
38
|
+
// SKIPPED unless CC_PG_URL names a throwaway Postgres — this suite's subject IS the engine. `bun run test:pg` supplies one.
|
|
38
39
|
describe.skipIf(!URL_)('the retention policy table against a real Postgres (D30)', () => {
|
|
39
40
|
beforeAll(async () => {
|
|
40
41
|
sql = new SQL(URL_ as string);
|
|
@@ -167,7 +167,7 @@ export const registerArgon2idBinding = (binding: RawArgon2idBinding): void => {
|
|
|
167
167
|
* module exists to prevent.
|
|
168
168
|
*
|
|
169
169
|
* The same indirection that hides the specifier from a bundler hides it from
|
|
170
|
-
* every static import walker, so
|
|
170
|
+
* every static import walker, so the guard's peer map would report
|
|
171
171
|
* this edge as absent. The pragma is what puts it back.
|
|
172
172
|
*
|
|
173
173
|
* @peer @node-rs/argon2
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
* (`checks.ts`) does not call `reconcile` at all for a check that threw.
|
|
22
22
|
*
|
|
23
23
|
* ── Where the file lives ────────────────────────────────────────────────────
|
|
24
|
-
* Whatever `Database` the caller opens. The console keeps it
|
|
25
|
-
*
|
|
26
|
-
* database: metrics are capped, regenerable telemetry that trims on write, and
|
|
24
|
+
* Whatever `Database` the caller opens. The console keeps it in an incidents
|
|
25
|
+
* database of its own under the host's app-data root, deliberately NOT in the
|
|
26
|
+
* metrics database: metrics are capped, regenerable telemetry that trims on write, and
|
|
27
27
|
* an incident is a governed record whose whole value is that it survives — most
|
|
28
28
|
* of all across the restart a deploy of the console itself performs.
|
|
29
29
|
*/
|
package/src/server/index.ts
CHANGED
|
@@ -117,7 +117,7 @@ export {
|
|
|
117
117
|
} from './jobs';
|
|
118
118
|
// ── Media adapter (task 19): image rendering via sharp (lazy/optional peer) + ──
|
|
119
119
|
// video trim / probe / thumbnail via native ffmpeg. Also at the dedicated
|
|
120
|
-
//
|
|
120
|
+
// media-bun entry below; sharp is imported lazily inside renderImage,
|
|
121
121
|
// so importing this barrel never loads the native binary.
|
|
122
122
|
export {
|
|
123
123
|
buildProbeArgs,
|
|
@@ -209,6 +209,22 @@ describe("the idle clock", () => {
|
|
|
209
209
|
});
|
|
210
210
|
});
|
|
211
211
|
|
|
212
|
+
/**
|
|
213
|
+
* 🔴 The two tests below declare their own budget, and it is not padding.
|
|
214
|
+
*
|
|
215
|
+
* Every `unlock()` runs a real argon2id verification — that IS the thing under test — and
|
|
216
|
+
* these two are the only ones in the file that do it in bulk: 9 attempts and 17 attempts.
|
|
217
|
+
* Measured 2026-09-13 on this machine: 4.5s and 7.2s against bun's DEFAULT per-test budget
|
|
218
|
+
* of 5000ms, so the second failed on every run and the first was one hiccup behind it. The
|
|
219
|
+
* file's header says it "leans on the repo's per-test budget"; this repo's `bunfig.toml`
|
|
220
|
+
* declares none, so that budget is 5s and the claim was simply false.
|
|
221
|
+
*
|
|
222
|
+
* Stated per test rather than raised in `bunfig.toml`, deliberately: a repo-wide 20s would
|
|
223
|
+
* buy these two nothing the line below does not, and would cost all 5,200 other tests the
|
|
224
|
+
* fast failure that tells you something is HUNG rather than slow.
|
|
225
|
+
*/
|
|
226
|
+
const KDF_BULK_MS = 20_000;
|
|
227
|
+
|
|
212
228
|
describe("the guess throttle", () => {
|
|
213
229
|
test("five failures are free, the sixth costs a wait, and a success clears it", async () => {
|
|
214
230
|
let now = 1_000_000;
|
|
@@ -230,7 +246,7 @@ describe("the guess throttle", () => {
|
|
|
230
246
|
now += 30_001;
|
|
231
247
|
expect((await lock.unlock(VERIFIER)).ok).toBe(true);
|
|
232
248
|
expect(lock.status().retryAfterMs).toBe(0);
|
|
233
|
-
});
|
|
249
|
+
}, KDF_BULK_MS);
|
|
234
250
|
|
|
235
251
|
test("a windowed refusal does not advance the counter", async () => {
|
|
236
252
|
let now = 1_000_000;
|
|
@@ -242,7 +258,7 @@ describe("the guess throttle", () => {
|
|
|
242
258
|
// cost nothing.
|
|
243
259
|
const next = await lock.unlock("wrong");
|
|
244
260
|
expect(next.ok === false && next.retryAfterMs).toBe(60_000);
|
|
245
|
-
});
|
|
261
|
+
}, KDF_BULK_MS);
|
|
246
262
|
});
|
|
247
263
|
|
|
248
264
|
describe("rotation", () => {
|
|
@@ -83,7 +83,7 @@ export interface MasterLockOptions {
|
|
|
83
83
|
* The BOOTSTRAP record, as JSON, used only when the store is empty — the same shape as
|
|
84
84
|
* {@link MasterLockRecord} with `idleMs` optional.
|
|
85
85
|
*
|
|
86
|
-
* It arrives
|
|
86
|
+
* It arrives as `MASTER_LOCK_SEED` in the app's own 0600 deploy-secrets env file,
|
|
87
87
|
* copied from the vault's own `vault_keys` row, so the lock is armed from the first
|
|
88
88
|
* request rather than from whenever somebody remembers to set one. A lock that has to
|
|
89
89
|
* be configured before it protects anything protects nothing on the day it matters —
|
|
@@ -19,6 +19,7 @@ async function jpeg(w: number, h: number, color = { r: 200, g: 50, b: 50 }): Pro
|
|
|
19
19
|
.toBuffer();
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// SKIPPED when the OPTIONAL `sharp` peer is not installed — it is this suite's subject. Runs by default when it is.
|
|
22
23
|
describe.skipIf(!sharp)('renderImage (sharp)', () => {
|
|
23
24
|
test('resize + format-convert → webp with the right dimensions (acceptance #8)', async () => {
|
|
24
25
|
const src = await jpeg(400, 300);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// src/server/media-bun — the Bun server adapter, re-exported from `cursedbelt/server`, for the media-core
|
|
2
2
|
// specs: image rendering via sharp (lazy/optional), video trim + probe + thumbnail
|
|
3
3
|
// via native ffmpeg/ffprobe. App handlers keep auth, FsNode lookup, quota, and
|
|
4
4
|
// storeFile; this owns the actual pixel/codec work.
|
|
@@ -52,6 +52,7 @@ afterAll(() => {
|
|
|
52
52
|
if (dir) rmSync(dir, { recursive: true, force: true });
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
+
// SKIPPED on a host without ffmpeg/ffprobe — it synthesizes and decodes real media. Runs by default wherever ffmpeg is installed.
|
|
55
56
|
describe.skipIf(!haveFfmpeg)('media-bun video (ffmpeg)', () => {
|
|
56
57
|
test('probeMedia reads dimensions + duration', async () => {
|
|
57
58
|
const meta = await probeMedia(source);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { APP_DATA_HOME_ENV, resolveAppDataHome, XDG_DATA_HOME_ENV } from "./appDataHome";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The published-library defect this file is the gate for: a resolver that knows
|
|
8
|
+
* the name of a directory in one person's home. Every assertion below is either
|
|
9
|
+
* "the caller decides" or "the OS decides"; there is no third source.
|
|
10
|
+
*/
|
|
11
|
+
describe("the app-data home", () => {
|
|
12
|
+
it("takes an explicit argument over everything else", () => {
|
|
13
|
+
expect(
|
|
14
|
+
resolveAppDataHome({
|
|
15
|
+
override: "/srv/data",
|
|
16
|
+
env: { [APP_DATA_HOME_ENV]: "/env/data", [XDG_DATA_HOME_ENV]: "/xdg", HOME: "/home/x" },
|
|
17
|
+
}),
|
|
18
|
+
).toBe("/srv/data");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("reads APP_DATA_HOME — the one env var — before any convention", () => {
|
|
22
|
+
expect(
|
|
23
|
+
resolveAppDataHome({
|
|
24
|
+
env: { [APP_DATA_HOME_ENV]: "/env/data", [XDG_DATA_HOME_ENV]: "/xdg", HOME: "/home/x" },
|
|
25
|
+
}),
|
|
26
|
+
).toBe("/env/data");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("honors XDG_DATA_HOME on every platform, macOS included", () => {
|
|
30
|
+
for (const platform of ["darwin", "linux"]) {
|
|
31
|
+
expect(resolveAppDataHome({ env: { [XDG_DATA_HOME_ENV]: "/xdg", HOME: "/home/x" }, platform })).toBe("/xdg");
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("falls back to the macOS convention, not to anybody's dotfolder", () => {
|
|
36
|
+
const resolved = resolveAppDataHome({ env: { HOME: "/home/x" }, platform: "darwin" });
|
|
37
|
+
expect(resolved).toBe(join("/home/x", "Library", "Application Support"));
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("falls back to the XDG default path elsewhere", () => {
|
|
41
|
+
expect(resolveAppDataHome({ env: { HOME: "/home/x" }, platform: "linux" })).toBe(
|
|
42
|
+
join("/home/x", ".local", "share"),
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Whitespace is how an env var gets "set" by a shell script that meant to unset
|
|
47
|
+
// it; treating it as configuration points every app at the filesystem root.
|
|
48
|
+
it("treats a blank setting as no setting", () => {
|
|
49
|
+
expect(
|
|
50
|
+
resolveAppDataHome({
|
|
51
|
+
override: " ",
|
|
52
|
+
env: { [APP_DATA_HOME_ENV]: " ", [XDG_DATA_HOME_ENV]: "", HOME: "/home/x" },
|
|
53
|
+
platform: "linux",
|
|
54
|
+
}),
|
|
55
|
+
).toBe(join("/home/x", ".local", "share"));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("falls back to the process's own home when the env names none", () => {
|
|
59
|
+
expect(resolveAppDataHome({ env: {}, platform: "linux" })).toBe(join(homedir(), ".local", "share"));
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 🔴 The assertion this module exists for. It is deliberately a property of the
|
|
64
|
+
* OUTPUT rather than of the source text, so it still holds if somebody
|
|
65
|
+
* reintroduces the old folder through a variable, a `join`, or a constant.
|
|
66
|
+
*/
|
|
67
|
+
it("never resolves a previous generation's private directory", () => {
|
|
68
|
+
const envs: Array<Record<string, string | undefined>> = [
|
|
69
|
+
{},
|
|
70
|
+
{ HOME: "/home/x" },
|
|
71
|
+
{ HOME: "/home/x", [APP_DATA_HOME_ENV]: "/srv/data" },
|
|
72
|
+
{ HOME: "/home/x", [XDG_DATA_HOME_ENV]: "/xdg" },
|
|
73
|
+
// The previous generation's own env var must no longer steer anything: the
|
|
74
|
+
// value below is deliberately unlike any convention, so a resolver that
|
|
75
|
+
// still read this var could not produce a passing answer by accident.
|
|
76
|
+
{ HOME: "/home/x", APP_MANAGED_HOME: "/nowhere/inherited" },
|
|
77
|
+
];
|
|
78
|
+
for (const env of envs) {
|
|
79
|
+
for (const platform of ["darwin", "linux"]) {
|
|
80
|
+
const resolved = resolveAppDataHome({ env, platform });
|
|
81
|
+
expect(resolved).not.toContain("app-managed");
|
|
82
|
+
expect(resolved).not.toContain("code-retiring");
|
|
83
|
+
expect(resolved).not.toContain("Master-Docs");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a machine keeps an app's data — as CONFIGURATION, never as a convention
|
|
3
|
+
* baked into the library.
|
|
4
|
+
*
|
|
5
|
+
* ## What this replaces, and why it is a defect rather than untidiness
|
|
6
|
+
*
|
|
7
|
+
* Until 2026-09-13 three live modules in this package joined the ambient home
|
|
8
|
+
* directory to a hardcoded dotfolder belonging to the previous generation: the
|
|
9
|
+
* retention store, the archive, and `resolveAppDataRoot`. This package is
|
|
10
|
+
* PUBLISHED. Anybody who installed it got a library that went looking for a
|
|
11
|
+
* directory in their home that has nothing to do with them, and — worse — wrote
|
|
12
|
+
* into it if it happened to exist.
|
|
13
|
+
*
|
|
14
|
+
* A library may not know the name of a directory in somebody's home. It may know
|
|
15
|
+
* two things: what the caller told it, and what the operating system says the
|
|
16
|
+
* convention is. That is the whole ladder below.
|
|
17
|
+
*
|
|
18
|
+
* ## The ladder
|
|
19
|
+
*
|
|
20
|
+
* 1. an explicit `override` — a `--data-root` flag, a host's own resolution;
|
|
21
|
+
* 2. `$APP_DATA_HOME` — the ONE env var, for a machine that keeps every app's
|
|
22
|
+
* data under one root so a fleet-wide tool can see all of it at once;
|
|
23
|
+
* 3. `$XDG_DATA_HOME` — the user already told the OS where data goes;
|
|
24
|
+
* 4. the platform default: `~/Library/Application Support` on macOS,
|
|
25
|
+
* `~/.local/share` everywhere else.
|
|
26
|
+
*
|
|
27
|
+
* `$XDG_DATA_HOME` is honored on macOS too. It is not the platform's own
|
|
28
|
+
* convention there, but a user who sets it has stated a preference, and a
|
|
29
|
+
* preference outranks a default on any platform.
|
|
30
|
+
*
|
|
31
|
+
* Nothing here touches the filesystem: it is a pure mapping from environment to
|
|
32
|
+
* path, so a caller can reason about the answer before creating anything, and a
|
|
33
|
+
* test can assert both platforms on one machine.
|
|
34
|
+
*/
|
|
35
|
+
import { homedir } from "node:os";
|
|
36
|
+
import { join } from "node:path";
|
|
37
|
+
|
|
38
|
+
/** The one env var. A machine with a shared data root sets this and nothing else. */
|
|
39
|
+
export const APP_DATA_HOME_ENV = "APP_DATA_HOME";
|
|
40
|
+
|
|
41
|
+
/** The cross-desktop convention this honors ahead of the platform default. */
|
|
42
|
+
export const XDG_DATA_HOME_ENV = "XDG_DATA_HOME";
|
|
43
|
+
|
|
44
|
+
export interface ResolveAppDataHomeOptions {
|
|
45
|
+
/** An explicit answer from the caller. Wins outright — this is the "argument" half. */
|
|
46
|
+
readonly override?: string;
|
|
47
|
+
/** Environment to read. Injected by tests; defaults to the process's own. */
|
|
48
|
+
readonly env?: Record<string, string | undefined>;
|
|
49
|
+
/**
|
|
50
|
+
* Platform to resolve for. Injected by tests so both branches are proved on one
|
|
51
|
+
* machine; defaults to the running platform.
|
|
52
|
+
*/
|
|
53
|
+
readonly platform?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Trimmed, or undefined — an env var set to whitespace is not a configuration. */
|
|
57
|
+
function configured(value: string | undefined): string | undefined {
|
|
58
|
+
const trimmed = value?.trim();
|
|
59
|
+
return trimmed ? trimmed : undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The machine's app-data home. See the module note for the ordering rationale.
|
|
64
|
+
*/
|
|
65
|
+
export function resolveAppDataHome(options: ResolveAppDataHomeOptions = {}): string {
|
|
66
|
+
const env = options.env ?? process.env;
|
|
67
|
+
const override = configured(options.override);
|
|
68
|
+
if (override) return override;
|
|
69
|
+
|
|
70
|
+
const appDataHome = configured(env[APP_DATA_HOME_ENV]);
|
|
71
|
+
if (appDataHome) return appDataHome;
|
|
72
|
+
|
|
73
|
+
const xdg = configured(env[XDG_DATA_HOME_ENV]);
|
|
74
|
+
if (xdg) return xdg;
|
|
75
|
+
|
|
76
|
+
// `env.HOME` rather than `homedir()` alone, so a caller passing an env object
|
|
77
|
+
// gets a resolution it can actually control — every test below depends on it,
|
|
78
|
+
// and so does any host that boots an app under a different account.
|
|
79
|
+
const home = configured(env.HOME) ?? homedir();
|
|
80
|
+
const platform = options.platform ?? process.platform;
|
|
81
|
+
return platform === "darwin"
|
|
82
|
+
? join(home, "Library", "Application Support")
|
|
83
|
+
: join(home, ".local", "share");
|
|
84
|
+
}
|
|
@@ -9,6 +9,7 @@ import { afterEach, describe, expect, test } from "bun:test";
|
|
|
9
9
|
import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import { join } from "node:path";
|
|
12
|
+
import { resolveAppDataHome } from "../paths/appDataHome";
|
|
12
13
|
import {
|
|
13
14
|
archiveStamp,
|
|
14
15
|
createJsonlArchive,
|
|
@@ -133,18 +134,39 @@ describe("pendingBytes — the staleness signal a deployed box can actually obse
|
|
|
133
134
|
});
|
|
134
135
|
|
|
135
136
|
describe("resolveArchiveHome", () => {
|
|
136
|
-
test("the
|
|
137
|
+
test("the shared OS-convention home is TERMINAL — the archive simply grows there", () => {
|
|
137
138
|
const root = tmp();
|
|
138
|
-
|
|
139
|
+
const conventional = resolveAppDataHome({ env: { HOME: root } });
|
|
140
|
+
mkdirSync(conventional, { recursive: true });
|
|
139
141
|
const resolved = resolveArchiveHome("notes", { HOME: root });
|
|
140
142
|
expect(resolved).toEqual({
|
|
141
|
-
dir: join(
|
|
143
|
+
dir: join(conventional, "cursed-satellites", "archive", "notes"),
|
|
142
144
|
terminal: true,
|
|
143
145
|
});
|
|
144
146
|
});
|
|
145
147
|
|
|
148
|
+
test("APP_DATA_HOME is honored before the convention, and before it exists", () => {
|
|
149
|
+
const configured = join(tmp(), "managed");
|
|
150
|
+
expect(resolveArchiveHome("notes", { APP_DATA_HOME: configured })).toEqual({
|
|
151
|
+
dir: join(configured, "cursed-satellites", "archive", "notes"),
|
|
152
|
+
terminal: true,
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 🔴 Up to 2026-09-13 this resolved a hardcoded dotfolder in the owner's home —
|
|
158
|
+
* in a PUBLISHED package. Asserted on the output, so it still holds if the
|
|
159
|
+
* folder comes back through a variable.
|
|
160
|
+
*/
|
|
161
|
+
test("resolves nothing from a previous generation, whatever the env says", () => {
|
|
162
|
+
const root = tmp();
|
|
163
|
+
const resolved = resolveArchiveHome("notes", { HOME: root, APP_MANAGED_HOME: "/nowhere/inherited" });
|
|
164
|
+
expect(resolved.dir).not.toContain("app-managed");
|
|
165
|
+
expect(resolved.dir).not.toContain("/nowhere/inherited");
|
|
166
|
+
});
|
|
167
|
+
|
|
146
168
|
test("🔴 a deployed box falls back to the data dir and is STAGED — something must collect it", () => {
|
|
147
|
-
const root = tmp(); // no
|
|
169
|
+
const root = tmp(); // no shared data home, which is every deployed box
|
|
148
170
|
const dataDir = join(tmp(), "data");
|
|
149
171
|
mkdirSync(dataDir, { recursive: true });
|
|
150
172
|
expect(resolveArchiveHome("notes", { HOME: root, APP_DATA_DIR: dataDir })).toEqual({
|
|
@@ -28,10 +28,13 @@
|
|
|
28
28
|
* prefix and then delete the rest. A sealed file cannot be half a file.
|
|
29
29
|
*
|
|
30
30
|
* ── Terminal vs staged, and the staleness refusal ───────────────────────────
|
|
31
|
-
* On
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
31
|
+
* On a workstation the archive is home: `<app-data-home>/cursed-satellites/
|
|
32
|
+
* archive/<app>/`, it is `terminal`, and it simply grows. The home is
|
|
33
|
+
* CONFIGURATION ({@link resolveAppDataHome}) — `$APP_DATA_HOME`, else the OS's own
|
|
34
|
+
* convention — never a folder this library invented in somebody's home; that was
|
|
35
|
+
* the published defect fixed 2026-09-13. On a deployed box nothing outside the
|
|
36
|
+
* app's own data dir is writable, so it resolves to `$APP_DATA_DIR/archive` and
|
|
37
|
+
* is `staged` — something else has to come and get it. That distinction is what lets the
|
|
35
38
|
* sweeper honor "refuse to trim if the last successful pull is stale" using a
|
|
36
39
|
* fact the box can actually observe: how many bytes of sealed segments are still
|
|
37
40
|
* sitting there uncollected. If the collector stops, the archive fills to its
|
|
@@ -54,8 +57,8 @@ import {
|
|
|
54
57
|
writeFileSync,
|
|
55
58
|
writeSync,
|
|
56
59
|
} from "node:fs";
|
|
57
|
-
import { homedir } from "node:os";
|
|
58
60
|
import { join } from "node:path";
|
|
61
|
+
import { APP_DATA_HOME_ENV, resolveAppDataHome } from "../paths/appDataHome";
|
|
59
62
|
|
|
60
63
|
/** One sealed archive file. */
|
|
61
64
|
export interface ArchiveSegment {
|
|
@@ -127,10 +130,9 @@ function isUsable(dir: string): boolean {
|
|
|
127
130
|
* Where this app's archive lives on THIS machine, and whether the machine keeps
|
|
128
131
|
* it.
|
|
129
132
|
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* each land somewhere writable rather than somewhere assumed.
|
|
133
|
+
* `<app-data-home>/cursed-satellites/archive/<app>/`, reached through the same env
|
|
134
|
+
* ladder the retention home uses, so a test, a container and a deployed box each
|
|
135
|
+
* land somewhere writable rather than somewhere assumed.
|
|
134
136
|
*/
|
|
135
137
|
export function resolveArchiveHome(
|
|
136
138
|
app: string,
|
|
@@ -141,16 +143,19 @@ export function resolveArchiveHome(
|
|
|
141
143
|
if (env.RETENTION_ARCHIVE_HOME) {
|
|
142
144
|
candidates.push({ dir: join(env.RETENTION_ARCHIVE_HOME, app), terminal: true });
|
|
143
145
|
}
|
|
144
|
-
|
|
146
|
+
// An explicitly CONFIGURED home is used whether or not it exists yet — the
|
|
147
|
+
// operator naming it is the statement that it is the right place.
|
|
148
|
+
const configured = env[APP_DATA_HOME_ENV]?.trim();
|
|
149
|
+
if (configured) {
|
|
145
150
|
candidates.push({
|
|
146
|
-
dir: join(
|
|
151
|
+
dir: join(configured, "cursed-satellites", "archive", app),
|
|
147
152
|
terminal: true,
|
|
148
153
|
});
|
|
149
154
|
}
|
|
150
|
-
const conventional =
|
|
151
|
-
//
|
|
152
|
-
// deployed box would strand the archive where no collector looks.
|
|
153
|
-
if (existsSync(conventional)) {
|
|
155
|
+
const conventional = resolveAppDataHome({ env });
|
|
156
|
+
// The OS convention is only PREFERRED when it is already there: creating it on
|
|
157
|
+
// a deployed box would strand the archive where no collector looks.
|
|
158
|
+
if (!configured && existsSync(conventional)) {
|
|
154
159
|
candidates.push({
|
|
155
160
|
dir: join(conventional, "cursed-satellites", "archive", app),
|
|
156
161
|
terminal: true,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* ── Why this lives in cursedbelt ────────────────────────────────────────────
|
|
5
5
|
* Retention used to be spoken in three unrelated vocabularies: this
|
|
6
6
|
* category-based opt-in design (born in `cursed-satellites/satellite-kit`), the
|
|
7
|
-
* DB-backed audit|meter WINDOWS in `cursedbelt/server/drivers
|
|
7
|
+
* DB-backed audit|meter WINDOWS in `cursedbelt/server/drivers`' retentionPolicy
|
|
8
8
|
* (billing evidence — a genuinely different concern that keeps the name
|
|
9
9
|
* {@link RetentionWindows}), and `deploy-engine/backupRetention`'s artifact
|
|
10
10
|
* pruning. DEDUP-8(c) made THIS one canonical and moved it here, so a single
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* `ai_check_runs` keeps N per check, the proposal ledger caps at 200,
|
|
9
9
|
* orch's own `eventRetention` was a whole bespoke sweeper with its own timer, and `deploy-engine/backupRetention.ts` a second one with different
|
|
10
10
|
* rules. Meanwhile the things nobody had written a rule for grew without limit:
|
|
11
|
-
*
|
|
11
|
+
* orch's own state directory reached **1.0 GB** — 74 MB of attempt transcripts and a
|
|
12
12
|
* single 70 MB peer-link `dedupe.json` holding 118 entries — with no policy, no
|
|
13
13
|
* backup, and nothing that could report it.
|
|
14
14
|
*
|
|
@@ -178,7 +178,7 @@ export type RetentionUnit = "rows" | "files";
|
|
|
178
178
|
* why `retentionPolicies.test.ts` pins the ids too.
|
|
179
179
|
*/
|
|
180
180
|
export interface RetentionDeclaration {
|
|
181
|
-
/** App key, matching
|
|
181
|
+
/** App key, matching the fleet registry's app-tracking rows (`orch`, `notes`, …). */
|
|
182
182
|
app: string;
|
|
183
183
|
/** Stable, app-scoped id. The override key is `<app>:<id>`. */
|
|
184
184
|
id: string;
|
|
@@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
|
2
2
|
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
+
import { resolveAppDataHome } from "../paths/appDataHome";
|
|
5
6
|
import type { RetentionDeclaration } from "./policy";
|
|
6
7
|
import {
|
|
7
8
|
publishRetention,
|
|
@@ -169,23 +170,32 @@ describe("resolveRetentionHome", () => {
|
|
|
169
170
|
expect(resolveRetentionHome({ RETENTION_HOME: explicit })).toBe(explicit);
|
|
170
171
|
});
|
|
171
172
|
|
|
172
|
-
test("
|
|
173
|
+
test("APP_DATA_HOME — the one env var — is honored before any convention", () => {
|
|
173
174
|
setRetentionHomeForTests(null);
|
|
174
|
-
expect(resolveRetentionHome({
|
|
175
|
+
expect(resolveRetentionHome({ APP_DATA_HOME: home })).toBe(join(home, "retention"));
|
|
175
176
|
});
|
|
176
177
|
|
|
177
|
-
test("
|
|
178
|
-
// orch's APP_DATA_DIR is ~/.app-managed/orch; publishing there instead of
|
|
179
|
-
// the shared home would hide it from every other app's view of the fleet.
|
|
178
|
+
test("a configured home is used even before it exists — naming it is the statement", () => {
|
|
180
179
|
setRetentionHomeForTests(null);
|
|
181
|
-
|
|
180
|
+
const fresh = join(home, "not-yet");
|
|
181
|
+
expect(resolveRetentionHome({ APP_DATA_HOME: fresh, APP_DATA_DIR: join(home, "data") })).toBe(
|
|
182
|
+
join(fresh, "retention"),
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test("the shared OS-convention home wins over APP_DATA_DIR so the station sees ONE fleet", () => {
|
|
187
|
+
// An app's own APP_DATA_DIR is private to it; publishing there instead of the
|
|
188
|
+
// shared home would hide it from every other app's view of the fleet.
|
|
189
|
+
setRetentionHomeForTests(null);
|
|
190
|
+
const conventional = resolveAppDataHome({ env: { HOME: home } });
|
|
191
|
+
mkdirSync(conventional, { recursive: true });
|
|
182
192
|
expect(resolveRetentionHome({ HOME: home, APP_DATA_DIR: join(home, "data") })).toBe(
|
|
183
|
-
join(
|
|
193
|
+
join(conventional, "retention"),
|
|
184
194
|
);
|
|
185
195
|
});
|
|
186
196
|
|
|
187
|
-
test("a deployed box — no
|
|
188
|
-
// prod-ec2 has no
|
|
197
|
+
test("a deployed box — no shared data home — falls through to APP_DATA_DIR", () => {
|
|
198
|
+
// prod-ec2 has no shared data home, and under ProtectSystem=strict only the
|
|
189
199
|
// data dir is writable. The app still sweeps; its fleet is that box's.
|
|
190
200
|
setRetentionHomeForTests(null);
|
|
191
201
|
const dataDir = join(home, "data");
|
|
@@ -199,10 +209,28 @@ describe("resolveRetentionHome", () => {
|
|
|
199
209
|
const dataDir = join(home, "data2");
|
|
200
210
|
expect(
|
|
201
211
|
resolveRetentionHome({
|
|
202
|
-
|
|
212
|
+
APP_DATA_HOME: "/proc/definitely-not-writable",
|
|
203
213
|
HOME: join(home, "nonexistent-home"),
|
|
204
214
|
APP_DATA_DIR: dataDir,
|
|
205
215
|
}),
|
|
206
216
|
).toBe(join(dataDir, "retention"));
|
|
207
217
|
});
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* 🔴 The published defect, asserted on the OUTPUT rather than on the source: up
|
|
221
|
+
* to 2026-09-13 this resolved a hardcoded dotfolder in the owner's home, so
|
|
222
|
+
* every installer of `cursedbelt` got a library reaching into a directory that
|
|
223
|
+
* had nothing to do with them.
|
|
224
|
+
*/
|
|
225
|
+
test("resolves nothing from a previous generation, whatever the env says", () => {
|
|
226
|
+
for (const env of [
|
|
227
|
+
{ HOME: join(home, "nonexistent-home") },
|
|
228
|
+
{ HOME: join(home, "nonexistent-home"), APP_MANAGED_HOME: "/nowhere/inherited" },
|
|
229
|
+
]) {
|
|
230
|
+
setRetentionHomeForTests(null);
|
|
231
|
+
const resolved = resolveRetentionHome(env);
|
|
232
|
+
expect(resolved).not.toContain("app-managed");
|
|
233
|
+
expect(resolved).not.toContain("/nowhere/inherited");
|
|
234
|
+
}
|
|
235
|
+
});
|
|
208
236
|
});
|