termcast 1.3.9
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/action-utils.d.ts +25 -0
- package/dist/action-utils.d.ts.map +1 -0
- package/dist/action-utils.js +209 -0
- package/dist/action-utils.js.map +1 -0
- package/dist/ai.d.ts +104 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +135 -0
- package/dist/ai.js.map +1 -0
- package/dist/apis/ai.d.ts +104 -0
- package/dist/apis/ai.d.ts.map +1 -0
- package/dist/apis/ai.js +135 -0
- package/dist/apis/ai.js.map +1 -0
- package/dist/apis/cache.d.ts +84 -0
- package/dist/apis/cache.d.ts.map +1 -0
- package/dist/apis/cache.js +307 -0
- package/dist/apis/cache.js.map +1 -0
- package/dist/apis/cache.test.d.ts +2 -0
- package/dist/apis/cache.test.d.ts.map +1 -0
- package/dist/apis/cache.test.js +246 -0
- package/dist/apis/cache.test.js.map +1 -0
- package/dist/apis/clipboard.d.ts +36 -0
- package/dist/apis/clipboard.d.ts.map +1 -0
- package/dist/apis/clipboard.js +154 -0
- package/dist/apis/clipboard.js.map +1 -0
- package/dist/apis/environment.d.ts +63 -0
- package/dist/apis/environment.d.ts.map +1 -0
- package/dist/apis/environment.js +189 -0
- package/dist/apis/environment.js.map +1 -0
- package/dist/apis/hud.d.ts +7 -0
- package/dist/apis/hud.d.ts.map +1 -0
- package/dist/apis/hud.js +45 -0
- package/dist/apis/hud.js.map +1 -0
- package/dist/apis/localstorage.d.ts +13 -0
- package/dist/apis/localstorage.d.ts.map +1 -0
- package/dist/apis/localstorage.js +190 -0
- package/dist/apis/localstorage.js.map +1 -0
- package/dist/apis/localstorage.test.d.ts +2 -0
- package/dist/apis/localstorage.test.d.ts.map +1 -0
- package/dist/apis/localstorage.test.js +131 -0
- package/dist/apis/localstorage.test.js.map +1 -0
- package/dist/apis/oauth.d.ts +142 -0
- package/dist/apis/oauth.d.ts.map +1 -0
- package/dist/apis/oauth.js +551 -0
- package/dist/apis/oauth.js.map +1 -0
- package/dist/apis/preferences.d.ts +23 -0
- package/dist/apis/preferences.d.ts.map +1 -0
- package/dist/apis/preferences.js +105 -0
- package/dist/apis/preferences.js.map +1 -0
- package/dist/apis/toast.d.ts +81 -0
- package/dist/apis/toast.d.ts.map +1 -0
- package/dist/apis/toast.js +275 -0
- package/dist/apis/toast.js.map +1 -0
- package/dist/apis/toast.test.d.ts +2 -0
- package/dist/apis/toast.test.d.ts.map +1 -0
- package/dist/apis/toast.test.js +67 -0
- package/dist/apis/toast.test.js.map +1 -0
- package/dist/apis/window.d.ts +12 -0
- package/dist/apis/window.d.ts.map +1 -0
- package/dist/apis/window.js +47 -0
- package/dist/apis/window.js.map +1 -0
- package/dist/build.d.ts +15 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +213 -0
- package/dist/build.js.map +1 -0
- package/dist/build.test.d.ts +2 -0
- package/dist/build.test.d.ts.map +1 -0
- package/dist/build.test.js +73 -0
- package/dist/build.test.js.map +1 -0
- package/dist/cache.d.ts +32 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +205 -0
- package/dist/cache.js.map +1 -0
- package/dist/cache.test.d.ts +2 -0
- package/dist/cache.test.d.ts.map +1 -0
- package/dist/cache.test.js +246 -0
- package/dist/cache.test.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +278 -0
- package/dist/cli.js.map +1 -0
- package/dist/clipboard.d.ts +36 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +154 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/colors.d.ts +15 -0
- package/dist/colors.d.ts.map +1 -0
- package/dist/colors.js +13 -0
- package/dist/colors.js.map +1 -0
- package/dist/components/actions.d.ts +120 -0
- package/dist/components/actions.d.ts.map +1 -0
- package/dist/components/actions.js +371 -0
- package/dist/components/actions.js.map +1 -0
- package/dist/components/alert.d.ts +25 -0
- package/dist/components/alert.d.ts.map +1 -0
- package/dist/components/alert.js +99 -0
- package/dist/components/alert.js.map +1 -0
- package/dist/components/detail.d.ts +65 -0
- package/dist/components/detail.d.ts.map +1 -0
- package/dist/components/detail.js +147 -0
- package/dist/components/detail.js.map +1 -0
- package/dist/components/dropdown.d.ts +40 -0
- package/dist/components/dropdown.d.ts.map +1 -0
- package/dist/components/dropdown.js +202 -0
- package/dist/components/dropdown.js.map +1 -0
- package/dist/components/extension-preferences.d.ts +8 -0
- package/dist/components/extension-preferences.d.ts.map +1 -0
- package/dist/components/extension-preferences.js +139 -0
- package/dist/components/extension-preferences.js.map +1 -0
- package/dist/components/form/assign-components.d.ts +2 -0
- package/dist/components/form/assign-components.d.ts.map +1 -0
- package/dist/components/form/assign-components.js +22 -0
- package/dist/components/form/assign-components.js.map +1 -0
- package/dist/components/form/checkbox.d.ts +7 -0
- package/dist/components/form/checkbox.d.ts.map +1 -0
- package/dist/components/form/checkbox.js +46 -0
- package/dist/components/form/checkbox.js.map +1 -0
- package/dist/components/form/date-picker.d.ts +18 -0
- package/dist/components/form/date-picker.d.ts.map +1 -0
- package/dist/components/form/date-picker.js +69 -0
- package/dist/components/form/date-picker.js.map +1 -0
- package/dist/components/form/description.d.ts +7 -0
- package/dist/components/form/description.d.ts.map +1 -0
- package/dist/components/form/description.js +8 -0
- package/dist/components/form/description.js.map +1 -0
- package/dist/components/form/dropdown.d.ts +25 -0
- package/dist/components/form/dropdown.d.ts.map +1 -0
- package/dist/components/form/dropdown.js +286 -0
- package/dist/components/form/dropdown.js.map +1 -0
- package/dist/components/form/file-autocomplete.d.ts +12 -0
- package/dist/components/form/file-autocomplete.d.ts.map +1 -0
- package/dist/components/form/file-autocomplete.js +84 -0
- package/dist/components/form/file-autocomplete.js.map +1 -0
- package/dist/components/form/file-picker.d.ts +31 -0
- package/dist/components/form/file-picker.d.ts.map +1 -0
- package/dist/components/form/file-picker.js +113 -0
- package/dist/components/form/file-picker.js.map +1 -0
- package/dist/components/form/form-end.d.ts +2 -0
- package/dist/components/form/form-end.d.ts.map +1 -0
- package/dist/components/form/form-end.js +6 -0
- package/dist/components/form/form-end.js.map +1 -0
- package/dist/components/form/form-type-only.d.ts +174 -0
- package/dist/components/form/form-type-only.d.ts.map +1 -0
- package/dist/components/form/form-type-only.js +2 -0
- package/dist/components/form/form-type-only.js.map +1 -0
- package/dist/components/form/index.d.ts +46 -0
- package/dist/components/form/index.d.ts.map +1 -0
- package/dist/components/form/index.js +106 -0
- package/dist/components/form/index.js.map +1 -0
- package/dist/components/form/password-field.d.ts +7 -0
- package/dist/components/form/password-field.d.ts.map +1 -0
- package/dist/components/form/password-field.js +34 -0
- package/dist/components/form/password-field.js.map +1 -0
- package/dist/components/form/separator.d.ts +2 -0
- package/dist/components/form/separator.d.ts.map +1 -0
- package/dist/components/form/separator.js +8 -0
- package/dist/components/form/separator.js.map +1 -0
- package/dist/components/form/tagpicker.d.ts +134 -0
- package/dist/components/form/tagpicker.d.ts.map +1 -0
- package/dist/components/form/tagpicker.js +79 -0
- package/dist/components/form/tagpicker.js.map +1 -0
- package/dist/components/form/text-area.d.ts +8 -0
- package/dist/components/form/text-area.d.ts.map +1 -0
- package/dist/components/form/text-area.js +26 -0
- package/dist/components/form/text-area.js.map +1 -0
- package/dist/components/form/text-field.d.ts +7 -0
- package/dist/components/form/text-field.d.ts.map +1 -0
- package/dist/components/form/text-field.js +28 -0
- package/dist/components/form/text-field.js.map +1 -0
- package/dist/components/form/types.d.ts +43 -0
- package/dist/components/form/types.d.ts.map +1 -0
- package/dist/components/form/types.js +2 -0
- package/dist/components/form/types.js.map +1 -0
- package/dist/components/form/use-form-handling.d.ts +4 -0
- package/dist/components/form/use-form-handling.d.ts.map +1 -0
- package/dist/components/form/use-form-handling.js +37 -0
- package/dist/components/form/use-form-handling.js.map +1 -0
- package/dist/components/form/use-form-navigation.d.ts +8 -0
- package/dist/components/form/use-form-navigation.d.ts.map +1 -0
- package/dist/components/form/use-form-navigation.js +58 -0
- package/dist/components/form/use-form-navigation.js.map +1 -0
- package/dist/components/form/with-left-border.d.ts +17 -0
- package/dist/components/form/with-left-border.d.ts.map +1 -0
- package/dist/components/form/with-left-border.js +10 -0
- package/dist/components/form/with-left-border.js.map +1 -0
- package/dist/components/icon.d.ts +9 -0
- package/dist/components/icon.d.ts.map +1 -0
- package/dist/components/icon.js +485 -0
- package/dist/components/icon.js.map +1 -0
- package/dist/components/image.d.ts +19 -0
- package/dist/components/image.d.ts.map +1 -0
- package/dist/components/image.js +32 -0
- package/dist/components/image.js.map +1 -0
- package/dist/components/list.d.ts +234 -0
- package/dist/components/list.d.ts.map +1 -0
- package/dist/components/list.js +667 -0
- package/dist/components/list.js.map +1 -0
- package/dist/components/loading-bar.d.ts +8 -0
- package/dist/components/loading-bar.d.ts.map +1 -0
- package/dist/components/loading-bar.js +107 -0
- package/dist/components/loading-bar.js.map +1 -0
- package/dist/components/menubar-extra.d.ts +68 -0
- package/dist/components/menubar-extra.d.ts.map +1 -0
- package/dist/components/menubar-extra.js +39 -0
- package/dist/components/menubar-extra.js.map +1 -0
- package/dist/descendants.d.ts +25 -0
- package/dist/descendants.d.ts.map +1 -0
- package/dist/descendants.js +81 -0
- package/dist/descendants.js.map +1 -0
- package/dist/dev-ui.d.ts +7 -0
- package/dist/dev-ui.d.ts.map +1 -0
- package/dist/dev-ui.js +118 -0
- package/dist/dev-ui.js.map +1 -0
- package/dist/e2e-node.d.ts +63 -0
- package/dist/e2e-node.d.ts.map +1 -0
- package/dist/e2e-node.js +255 -0
- package/dist/e2e-node.js.map +1 -0
- package/dist/e2e.d.ts +39 -0
- package/dist/e2e.d.ts.map +1 -0
- package/dist/e2e.js +127 -0
- package/dist/e2e.js.map +1 -0
- package/dist/environment.d.ts +63 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +189 -0
- package/dist/environment.js.map +1 -0
- package/dist/examples/action-show-in-finder.d.ts +2 -0
- package/dist/examples/action-show-in-finder.d.ts.map +1 -0
- package/dist/examples/action-show-in-finder.js +13 -0
- package/dist/examples/action-show-in-finder.js.map +1 -0
- package/dist/examples/datepicker.d.ts +2 -0
- package/dist/examples/datepicker.d.ts.map +1 -0
- package/dist/examples/datepicker.js +344 -0
- package/dist/examples/datepicker.js.map +1 -0
- package/dist/examples/environment-test.d.ts +2 -0
- package/dist/examples/environment-test.d.ts.map +1 -0
- package/dist/examples/environment-test.js +28 -0
- package/dist/examples/environment-test.js.map +1 -0
- package/dist/examples/error-boundary.d.ts +6 -0
- package/dist/examples/error-boundary.d.ts.map +1 -0
- package/dist/examples/error-boundary.js +67 -0
- package/dist/examples/error-boundary.js.map +1 -0
- package/dist/examples/form-basic-arrow-keys.vitest.d.ts +2 -0
- package/dist/examples/form-basic-arrow-keys.vitest.d.ts.map +1 -0
- package/dist/examples/form-basic-arrow-keys.vitest.js +46 -0
- package/dist/examples/form-basic-arrow-keys.vitest.js.map +1 -0
- package/dist/examples/form-basic.d.ts +2 -0
- package/dist/examples/form-basic.d.ts.map +1 -0
- package/dist/examples/form-basic.js +21 -0
- package/dist/examples/form-basic.js.map +1 -0
- package/dist/examples/form-basic.vitest.d.ts +2 -0
- package/dist/examples/form-basic.vitest.d.ts.map +1 -0
- package/dist/examples/form-basic.vitest.js +995 -0
- package/dist/examples/form-basic.vitest.js.map +1 -0
- package/dist/examples/form-dropdown-with-sections.d.ts +2 -0
- package/dist/examples/form-dropdown-with-sections.d.ts.map +1 -0
- package/dist/examples/form-dropdown-with-sections.js +13 -0
- package/dist/examples/form-dropdown-with-sections.js.map +1 -0
- package/dist/examples/form-dropdown-with-sections.vitest.d.ts +2 -0
- package/dist/examples/form-dropdown-with-sections.vitest.d.ts.map +1 -0
- package/dist/examples/form-dropdown-with-sections.vitest.js +75 -0
- package/dist/examples/form-dropdown-with-sections.vitest.js.map +1 -0
- package/dist/examples/form-dropdown.d.ts +2 -0
- package/dist/examples/form-dropdown.d.ts.map +1 -0
- package/dist/examples/form-dropdown.js +13 -0
- package/dist/examples/form-dropdown.js.map +1 -0
- package/dist/examples/form-dropdown.vitest.d.ts +2 -0
- package/dist/examples/form-dropdown.vitest.d.ts.map +1 -0
- package/dist/examples/form-dropdown.vitest.js +722 -0
- package/dist/examples/form-dropdown.vitest.js.map +1 -0
- package/dist/examples/form-multiselect-dropdown.d.ts +2 -0
- package/dist/examples/form-multiselect-dropdown.d.ts.map +1 -0
- package/dist/examples/form-multiselect-dropdown.js +13 -0
- package/dist/examples/form-multiselect-dropdown.js.map +1 -0
- package/dist/examples/form-tagpicker.d.ts +2 -0
- package/dist/examples/form-tagpicker.d.ts.map +1 -0
- package/dist/examples/form-tagpicker.js +13 -0
- package/dist/examples/form-tagpicker.js.map +1 -0
- package/dist/examples/form-tagpicker.vitest.d.ts +2 -0
- package/dist/examples/form-tagpicker.vitest.d.ts.map +1 -0
- package/dist/examples/form-tagpicker.vitest.js +491 -0
- package/dist/examples/form-tagpicker.vitest.js.map +1 -0
- package/dist/examples/internal/descendants-filtering.d.ts +2 -0
- package/dist/examples/internal/descendants-filtering.d.ts.map +1 -0
- package/dist/examples/internal/descendants-filtering.js +144 -0
- package/dist/examples/internal/descendants-filtering.js.map +1 -0
- package/dist/examples/internal/descendants.d.ts +2 -0
- package/dist/examples/internal/descendants.d.ts.map +1 -0
- package/dist/examples/internal/descendants.js +134 -0
- package/dist/examples/internal/descendants.js.map +1 -0
- package/dist/examples/internal/nested-boxes.d.ts +2 -0
- package/dist/examples/internal/nested-boxes.d.ts.map +1 -0
- package/dist/examples/internal/nested-boxes.js +7 -0
- package/dist/examples/internal/nested-boxes.js.map +1 -0
- package/dist/examples/internal/scrollbox-demo.d.ts +2 -0
- package/dist/examples/internal/scrollbox-demo.d.ts.map +1 -0
- package/dist/examples/internal/scrollbox-demo.js +104 -0
- package/dist/examples/internal/scrollbox-demo.js.map +1 -0
- package/dist/examples/internal/simple-dialog.d.ts +2 -0
- package/dist/examples/internal/simple-dialog.d.ts.map +1 -0
- package/dist/examples/internal/simple-dialog.js +43 -0
- package/dist/examples/internal/simple-dialog.js.map +1 -0
- package/dist/examples/internal/text-stacking.d.ts +2 -0
- package/dist/examples/internal/text-stacking.d.ts.map +1 -0
- package/dist/examples/internal/text-stacking.js +53 -0
- package/dist/examples/internal/text-stacking.js.map +1 -0
- package/dist/examples/internal/unicode-square-repro.d.ts +2 -0
- package/dist/examples/internal/unicode-square-repro.d.ts.map +1 -0
- package/dist/examples/internal/unicode-square-repro.js +7 -0
- package/dist/examples/internal/unicode-square-repro.js.map +1 -0
- package/dist/examples/list-dropdown-default.d.ts +2 -0
- package/dist/examples/list-dropdown-default.d.ts.map +1 -0
- package/dist/examples/list-dropdown-default.js +14 -0
- package/dist/examples/list-dropdown-default.js.map +1 -0
- package/dist/examples/list-dropdown-default.vitest.d.ts +2 -0
- package/dist/examples/list-dropdown-default.vitest.d.ts.map +1 -0
- package/dist/examples/list-dropdown-default.vitest.js +164 -0
- package/dist/examples/list-dropdown-default.vitest.js.map +1 -0
- package/dist/examples/list-fetch-data.d.ts +2 -0
- package/dist/examples/list-fetch-data.d.ts.map +1 -0
- package/dist/examples/list-fetch-data.js +87 -0
- package/dist/examples/list-fetch-data.js.map +1 -0
- package/dist/examples/list-fetch-data.vitest.d.ts +2 -0
- package/dist/examples/list-fetch-data.vitest.d.ts.map +1 -0
- package/dist/examples/list-fetch-data.vitest.js +103 -0
- package/dist/examples/list-fetch-data.vitest.js.map +1 -0
- package/dist/examples/list-filter-navigation.d.ts +2 -0
- package/dist/examples/list-filter-navigation.d.ts.map +1 -0
- package/dist/examples/list-filter-navigation.js +8 -0
- package/dist/examples/list-filter-navigation.js.map +1 -0
- package/dist/examples/list-with-detail.d.ts +2 -0
- package/dist/examples/list-with-detail.d.ts.map +1 -0
- package/dist/examples/list-with-detail.js +94 -0
- package/dist/examples/list-with-detail.js.map +1 -0
- package/dist/examples/list-with-detail.vitest.d.ts +2 -0
- package/dist/examples/list-with-detail.vitest.d.ts.map +1 -0
- package/dist/examples/list-with-detail.vitest.js +438 -0
- package/dist/examples/list-with-detail.vitest.js.map +1 -0
- package/dist/examples/list-with-dropdown.d.ts +2 -0
- package/dist/examples/list-with-dropdown.d.ts.map +1 -0
- package/dist/examples/list-with-dropdown.js +43 -0
- package/dist/examples/list-with-dropdown.js.map +1 -0
- package/dist/examples/list-with-dropdown.vitest.d.ts +2 -0
- package/dist/examples/list-with-dropdown.vitest.d.ts.map +1 -0
- package/dist/examples/list-with-dropdown.vitest.js +297 -0
- package/dist/examples/list-with-dropdown.vitest.js.map +1 -0
- package/dist/examples/list-with-sections.d.ts +2 -0
- package/dist/examples/list-with-sections.d.ts.map +1 -0
- package/dist/examples/list-with-sections.js +67 -0
- package/dist/examples/list-with-sections.js.map +1 -0
- package/dist/examples/list-with-sections.vitest.d.ts +2 -0
- package/dist/examples/list-with-sections.vitest.d.ts.map +1 -0
- package/dist/examples/list-with-sections.vitest.js +441 -0
- package/dist/examples/list-with-sections.vitest.js.map +1 -0
- package/dist/examples/miscellaneous.d.ts +2 -0
- package/dist/examples/miscellaneous.d.ts.map +1 -0
- package/dist/examples/miscellaneous.js +313 -0
- package/dist/examples/miscellaneous.js.map +1 -0
- package/dist/examples/nested-navigation.d.ts +2 -0
- package/dist/examples/nested-navigation.d.ts.map +1 -0
- package/dist/examples/nested-navigation.js +35 -0
- package/dist/examples/nested-navigation.js.map +1 -0
- package/dist/examples/preferences-test.d.ts +2 -0
- package/dist/examples/preferences-test.d.ts.map +1 -0
- package/dist/examples/preferences-test.js +43 -0
- package/dist/examples/preferences-test.js.map +1 -0
- package/dist/examples/simple-dropdown.d.ts +2 -0
- package/dist/examples/simple-dropdown.d.ts.map +1 -0
- package/dist/examples/simple-dropdown.js +15 -0
- package/dist/examples/simple-dropdown.js.map +1 -0
- package/dist/examples/simple-file-picker.d.ts +2 -0
- package/dist/examples/simple-file-picker.d.ts.map +1 -0
- package/dist/examples/simple-file-picker.js +21 -0
- package/dist/examples/simple-file-picker.js.map +1 -0
- package/dist/examples/simple-file-picker.vitest.d.ts +2 -0
- package/dist/examples/simple-file-picker.vitest.d.ts.map +1 -0
- package/dist/examples/simple-file-picker.vitest.js +277 -0
- package/dist/examples/simple-file-picker.vitest.js.map +1 -0
- package/dist/examples/simple-grid.d.ts +2 -0
- package/dist/examples/simple-grid.d.ts.map +1 -0
- package/dist/examples/simple-grid.js +51 -0
- package/dist/examples/simple-grid.js.map +1 -0
- package/dist/examples/simple-grid.vitest.d.ts +2 -0
- package/dist/examples/simple-grid.vitest.d.ts.map +1 -0
- package/dist/examples/simple-grid.vitest.js +498 -0
- package/dist/examples/simple-grid.vitest.js.map +1 -0
- package/dist/examples/simple-hud.d.ts +2 -0
- package/dist/examples/simple-hud.d.ts.map +1 -0
- package/dist/examples/simple-hud.js +18 -0
- package/dist/examples/simple-hud.js.map +1 -0
- package/dist/examples/simple-list-search.d.ts +2 -0
- package/dist/examples/simple-list-search.d.ts.map +1 -0
- package/dist/examples/simple-list-search.js +26 -0
- package/dist/examples/simple-list-search.js.map +1 -0
- package/dist/examples/simple-list.d.ts +2 -0
- package/dist/examples/simple-list.d.ts.map +1 -0
- package/dist/examples/simple-list.js +50 -0
- package/dist/examples/simple-list.js.map +1 -0
- package/dist/examples/simple-navigation.d.ts +2 -0
- package/dist/examples/simple-navigation.d.ts.map +1 -0
- package/dist/examples/simple-navigation.js +36 -0
- package/dist/examples/simple-navigation.js.map +1 -0
- package/dist/examples/simple-navigation.vitest.d.ts +2 -0
- package/dist/examples/simple-navigation.vitest.d.ts.map +1 -0
- package/dist/examples/simple-navigation.vitest.js +522 -0
- package/dist/examples/simple-navigation.vitest.js.map +1 -0
- package/dist/examples/store.d.ts +2 -0
- package/dist/examples/store.d.ts.map +1 -0
- package/dist/examples/store.js +5 -0
- package/dist/examples/store.js.map +1 -0
- package/dist/examples/store.vitest.d.ts +2 -0
- package/dist/examples/store.vitest.d.ts.map +1 -0
- package/dist/examples/store.vitest.js +52 -0
- package/dist/examples/store.vitest.js.map +1 -0
- package/dist/examples/tanstack-demo.d.ts +2 -0
- package/dist/examples/tanstack-demo.d.ts.map +1 -0
- package/dist/examples/tanstack-demo.js +51 -0
- package/dist/examples/tanstack-demo.js.map +1 -0
- package/dist/examples/use-promise-demo.d.ts +2 -0
- package/dist/examples/use-promise-demo.d.ts.map +1 -0
- package/dist/examples/use-promise-demo.js +45 -0
- package/dist/examples/use-promise-demo.js.map +1 -0
- package/dist/extensions/dev.d.ts +7 -0
- package/dist/extensions/dev.d.ts.map +1 -0
- package/dist/extensions/dev.js +124 -0
- package/dist/extensions/dev.js.map +1 -0
- package/dist/extensions/home.d.ts +8 -0
- package/dist/extensions/home.d.ts.map +1 -0
- package/dist/extensions/home.js +184 -0
- package/dist/extensions/home.js.map +1 -0
- package/dist/extensions/store.d.ts +6 -0
- package/dist/extensions/store.d.ts.map +1 -0
- package/dist/extensions/store.js +203 -0
- package/dist/extensions/store.js.map +1 -0
- package/dist/globals.d.ts +9 -0
- package/dist/globals.d.ts.map +1 -0
- package/dist/globals.js +21 -0
- package/dist/globals.js.map +1 -0
- package/dist/home-command.d.ts +8 -0
- package/dist/home-command.d.ts.map +1 -0
- package/dist/home-command.js +181 -0
- package/dist/home-command.js.map +1 -0
- package/dist/hooks/hooks.test.d.ts +2 -0
- package/dist/hooks/hooks.test.d.ts.map +1 -0
- package/dist/hooks/hooks.test.js +37 -0
- package/dist/hooks/hooks.test.js.map +1 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/use-action-panel.d.ts +16 -0
- package/dist/hooks/use-action-panel.d.ts.map +1 -0
- package/dist/hooks/use-action-panel.js +19 -0
- package/dist/hooks/use-action-panel.js.map +1 -0
- package/dist/hooks/use-id.d.ts +9 -0
- package/dist/hooks/use-id.d.ts.map +1 -0
- package/dist/hooks/use-id.js +17 -0
- package/dist/hooks/use-id.js.map +1 -0
- package/dist/hooks/use-unstable-ai.d.ts +9 -0
- package/dist/hooks/use-unstable-ai.d.ts.map +1 -0
- package/dist/hooks/use-unstable-ai.js +13 -0
- package/dist/hooks/use-unstable-ai.js.map +1 -0
- package/dist/hooks.d.ts +10 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +20 -0
- package/dist/hooks.js.map +1 -0
- package/dist/hover-repro.d.ts +2 -0
- package/dist/hover-repro.d.ts.map +1 -0
- package/dist/hover-repro.js +20 -0
- package/dist/hover-repro.js.map +1 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +71 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/date-picker-widget.d.ts +9 -0
- package/dist/internal/date-picker-widget.d.ts.map +1 -0
- package/dist/internal/date-picker-widget.js +380 -0
- package/dist/internal/date-picker-widget.js.map +1 -0
- package/dist/internal/dialog.d.ts +21 -0
- package/dist/internal/dialog.d.ts.map +1 -0
- package/dist/internal/dialog.js +122 -0
- package/dist/internal/dialog.js.map +1 -0
- package/dist/internal/error-handler.d.ts +2 -0
- package/dist/internal/error-handler.d.ts.map +1 -0
- package/dist/internal/error-handler.js +29 -0
- package/dist/internal/error-handler.js.map +1 -0
- package/dist/internal/focus-context.d.ts +10 -0
- package/dist/internal/focus-context.d.ts.map +1 -0
- package/dist/internal/focus-context.js +12 -0
- package/dist/internal/focus-context.js.map +1 -0
- package/dist/internal/navigation.d.ts +18 -0
- package/dist/internal/navigation.d.ts.map +1 -0
- package/dist/internal/navigation.js +83 -0
- package/dist/internal/navigation.js.map +1 -0
- package/dist/internal/providers.d.ts +8 -0
- package/dist/internal/providers.d.ts.map +1 -0
- package/dist/internal/providers.js +262 -0
- package/dist/internal/providers.js.map +1 -0
- package/dist/localstorage.d.ts +13 -0
- package/dist/localstorage.d.ts.map +1 -0
- package/dist/localstorage.js +190 -0
- package/dist/localstorage.js.map +1 -0
- package/dist/localstorage.test.d.ts +2 -0
- package/dist/localstorage.test.d.ts.map +1 -0
- package/dist/localstorage.test.js +131 -0
- package/dist/localstorage.test.js.map +1 -0
- package/dist/logger.d.ts +7 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +70 -0
- package/dist/logger.js.map +1 -0
- package/dist/oauth.d.ts +142 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +551 -0
- package/dist/oauth.js.map +1 -0
- package/dist/package-json.d.ts +84 -0
- package/dist/package-json.d.ts.map +1 -0
- package/dist/package-json.js +77 -0
- package/dist/package-json.js.map +1 -0
- package/dist/preferences.d.ts +23 -0
- package/dist/preferences.d.ts.map +1 -0
- package/dist/preferences.js +105 -0
- package/dist/preferences.js.map +1 -0
- package/dist/preload.d.ts +2 -0
- package/dist/preload.d.ts.map +1 -0
- package/dist/preload.js +28 -0
- package/dist/preload.js.map +1 -0
- package/dist/state.d.ts +26 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +18 -0
- package/dist/state.js.map +1 -0
- package/dist/store-api/download.d.ts +8 -0
- package/dist/store-api/download.d.ts.map +1 -0
- package/dist/store-api/download.js +37 -0
- package/dist/store-api/download.js.map +1 -0
- package/dist/store-api/download.test.d.ts +2 -0
- package/dist/store-api/download.test.d.ts.map +1 -0
- package/dist/store-api/download.test.js +36 -0
- package/dist/store-api/download.test.js.map +1 -0
- package/dist/store-api/extension.d.ts +87 -0
- package/dist/store-api/extension.d.ts.map +1 -0
- package/dist/store-api/extension.js +23 -0
- package/dist/store-api/extension.js.map +1 -0
- package/dist/store-api/extension.test.d.ts +2 -0
- package/dist/store-api/extension.test.d.ts.map +1 -0
- package/dist/store-api/extension.test.js +22 -0
- package/dist/store-api/extension.test.js.map +1 -0
- package/dist/store-api/search.d.ts +101 -0
- package/dist/store-api/search.d.ts.map +1 -0
- package/dist/store-api/search.js +29 -0
- package/dist/store-api/search.js.map +1 -0
- package/dist/store-api/search.test.d.ts +2 -0
- package/dist/store-api/search.test.d.ts.map +1 -0
- package/dist/store-api/search.test.js +45 -0
- package/dist/store-api/search.test.js.map +1 -0
- package/dist/store.d.ts +21 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +84 -0
- package/dist/store.js.map +1 -0
- package/dist/theme.d.ts +20 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +26 -0
- package/dist/theme.js.map +1 -0
- package/dist/toast.d.ts +44 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +221 -0
- package/dist/toast.js.map +1 -0
- package/dist/utils/file-system.d.ts +11 -0
- package/dist/utils/file-system.d.ts.map +1 -0
- package/dist/utils/file-system.js +66 -0
- package/dist/utils/file-system.js.map +1 -0
- package/dist/utils.d.ts +234 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +473 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.test.d.ts +2 -0
- package/dist/utils.test.d.ts.map +1 -0
- package/dist/utils.test.js +152 -0
- package/dist/utils.test.js.map +1 -0
- package/dist/window.d.ts +12 -0
- package/dist/window.d.ts.map +1 -0
- package/dist/window.js +48 -0
- package/dist/window.js.map +1 -0
- package/package.json +56 -0
- package/src/action-utils.tsx +207 -0
- package/src/apis/ai.tsx +177 -0
- package/src/apis/cache.test.ts +311 -0
- package/src/apis/cache.tsx +394 -0
- package/src/apis/clipboard.tsx +200 -0
- package/src/apis/environment.tsx +239 -0
- package/src/apis/hud.tsx +86 -0
- package/src/apis/localstorage.test.ts +164 -0
- package/src/apis/localstorage.tsx +215 -0
- package/src/apis/oauth.tsx +744 -0
- package/src/apis/preferences.tsx +140 -0
- package/src/apis/toast.tsx +388 -0
- package/src/apis/window.tsx +61 -0
- package/src/build.test.tsx +78 -0
- package/src/build.tsx +273 -0
- package/src/cli.tsx +328 -0
- package/src/colors.tsx +15 -0
- package/src/components/actions.tsx +718 -0
- package/src/components/alert.tsx +205 -0
- package/src/components/detail.tsx +359 -0
- package/src/components/dropdown.tsx +438 -0
- package/src/components/extension-preferences.tsx +269 -0
- package/src/components/form/assign-components.tsx +22 -0
- package/src/components/form/checkbox.tsx +96 -0
- package/src/components/form/date-picker.tsx +125 -0
- package/src/components/form/description.tsx +30 -0
- package/src/components/form/dropdown.tsx +512 -0
- package/src/components/form/file-autocomplete.tsx +141 -0
- package/src/components/form/file-picker.tsx +233 -0
- package/src/components/form/form-end.tsx +6 -0
- package/src/components/form/index.tsx +242 -0
- package/src/components/form/password-field.tsx +87 -0
- package/src/components/form/separator.tsx +15 -0
- package/src/components/form/tagpicker.tsx +245 -0
- package/src/components/form/text-area.tsx +82 -0
- package/src/components/form/text-field.tsx +82 -0
- package/src/components/form/types.tsx +49 -0
- package/src/components/form/use-form-navigation.tsx +65 -0
- package/src/components/form/with-left-border.tsx +53 -0
- package/src/components/icon.tsx +496 -0
- package/src/components/image.tsx +54 -0
- package/src/components/list.tsx +1564 -0
- package/src/components/loading-bar.tsx +141 -0
- package/src/components/menubar-extra.tsx +181 -0
- package/src/descendants.tsx +134 -0
- package/src/e2e-node.tsx +303 -0
- package/src/e2e.tsx +147 -0
- package/src/examples/action-show-in-finder.tsx +80 -0
- package/src/examples/environment-test.tsx +50 -0
- package/src/examples/error-boundary.tsx +217 -0
- package/src/examples/form-basic.tsx +122 -0
- package/src/examples/form-basic.vitest.tsx +1035 -0
- package/src/examples/form-dropdown.tsx +102 -0
- package/src/examples/form-dropdown.vitest.tsx +758 -0
- package/src/examples/form-tagpicker.tsx +66 -0
- package/src/examples/form-tagpicker.vitest.tsx +523 -0
- package/src/examples/internal/descendants-filtering.tsx +223 -0
- package/src/examples/internal/descendants.tsx +208 -0
- package/src/examples/internal/scrollbox-demo.tsx +149 -0
- package/src/examples/internal/simple-dialog.tsx +124 -0
- package/src/examples/internal/text-stacking.tsx +90 -0
- package/src/examples/list-dropdown-default.tsx +69 -0
- package/src/examples/list-dropdown-default.vitest.tsx +187 -0
- package/src/examples/list-fetch-data.tsx +123 -0
- package/src/examples/list-fetch-data.vitest.tsx +110 -0
- package/src/examples/list-with-detail.tsx +161 -0
- package/src/examples/list-with-detail.vitest.tsx +468 -0
- package/src/examples/list-with-dropdown.tsx +97 -0
- package/src/examples/list-with-dropdown.vitest.tsx +324 -0
- package/src/examples/list-with-sections.tsx +196 -0
- package/src/examples/list-with-sections.vitest.tsx +479 -0
- package/src/examples/miscellaneous.tsx +780 -0
- package/src/examples/nested-navigation.tsx +118 -0
- package/src/examples/preferences-test.tsx +82 -0
- package/src/examples/simple-dropdown.tsx +95 -0
- package/src/examples/simple-file-picker.tsx +75 -0
- package/src/examples/simple-file-picker.vitest.tsx +306 -0
- package/src/examples/simple-grid.tsx +149 -0
- package/src/examples/simple-grid.vitest.tsx +535 -0
- package/src/examples/simple-hud.tsx +60 -0
- package/src/examples/simple-list-search.tsx +93 -0
- package/src/examples/simple-list.tsx +149 -0
- package/src/examples/simple-navigation.tsx +89 -0
- package/src/examples/simple-navigation.vitest.tsx +571 -0
- package/src/examples/store.tsx +4 -0
- package/src/examples/store.vitest.tsx +59 -0
- package/src/examples/tanstack-demo.tsx +104 -0
- package/src/examples/use-promise-demo.tsx +96 -0
- package/src/extensions/dev.tsx +215 -0
- package/src/extensions/home.tsx +332 -0
- package/src/extensions/store.tsx +375 -0
- package/src/globals.ts +34 -0
- package/src/hooks/index.tsx +8 -0
- package/src/hooks/use-action-panel.tsx +28 -0
- package/src/hooks/use-id.tsx +19 -0
- package/src/hooks/use-unstable-ai.tsx +15 -0
- package/src/hooks.tsx +22 -0
- package/src/index.tsx +240 -0
- package/src/internal/date-picker-widget.tsx +500 -0
- package/src/internal/dialog.tsx +202 -0
- package/src/internal/error-handler.tsx +32 -0
- package/src/internal/focus-context.tsx +23 -0
- package/src/internal/navigation.tsx +149 -0
- package/src/internal/providers.tsx +430 -0
- package/src/logger.tsx +84 -0
- package/src/package-json.tsx +197 -0
- package/src/preload.tsx +32 -0
- package/src/state.tsx +49 -0
- package/src/store-api/download.test.tsx +38 -0
- package/src/store-api/download.tsx +52 -0
- package/src/store-api/extension.test.tsx +24 -0
- package/src/store-api/extension.tsx +123 -0
- package/src/store-api/search.test.tsx +50 -0
- package/src/store-api/search.tsx +146 -0
- package/src/theme.tsx +31 -0
- package/src/utils/file-system.ts +87 -0
- package/src/utils.test.tsx +204 -0
- package/src/utils.tsx +657 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, afterAll, jest } from 'bun:test'
|
|
2
|
+
import { Cache } from './cache'
|
|
3
|
+
import * as os from 'os'
|
|
4
|
+
import * as path from 'path'
|
|
5
|
+
import * as fs from 'fs'
|
|
6
|
+
|
|
7
|
+
describe('Cache', () => {
|
|
8
|
+
let cache: Cache
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
cache = new Cache({ namespace: `test-${Date.now()}-${Math.random()}` })
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
afterAll(() => {
|
|
15
|
+
// Optional: Clean up test databases after all tests
|
|
16
|
+
// const testDbPattern = path.join(os.homedir(), '.termcast-cache*.db')
|
|
17
|
+
// You could implement cleanup here if needed
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
describe('constructor', () => {
|
|
21
|
+
test('creates cache with default capacity', () => {
|
|
22
|
+
const cache = new Cache()
|
|
23
|
+
expect(Cache.DEFAULT_CAPACITY).toBe(10 * 1024 * 1024)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('creates cache with custom capacity', () => {
|
|
27
|
+
const cache = new Cache({ capacity: 1024 })
|
|
28
|
+
expect(cache).toBeDefined()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('creates cache with namespace', () => {
|
|
32
|
+
const cache = new Cache({ namespace: 'test-namespace' })
|
|
33
|
+
expect(cache.storageDirectory).toContain('test-namespace')
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
describe('get and set', () => {
|
|
38
|
+
test('stores and retrieves data', () => {
|
|
39
|
+
cache.set('key1', 'value1')
|
|
40
|
+
const result = cache.get('key1')
|
|
41
|
+
expect(result).toBe('value1')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('returns undefined for non-existent key', () => {
|
|
45
|
+
const result = cache.get('non-existent')
|
|
46
|
+
expect(result).toBeUndefined()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('overwrites existing values', () => {
|
|
50
|
+
cache.set('key', 'initial')
|
|
51
|
+
cache.set('key', 'updated')
|
|
52
|
+
const result = cache.get('key')
|
|
53
|
+
expect(result).toBe('updated')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('stores JSON stringified data', () => {
|
|
57
|
+
const data = { items: ['a', 'b', 'c'], count: 3 }
|
|
58
|
+
cache.set('json-data', JSON.stringify(data))
|
|
59
|
+
const result = cache.get('json-data')
|
|
60
|
+
expect(JSON.parse(result!)).toEqual(data)
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('has', () => {
|
|
65
|
+
test('returns true for existing key', () => {
|
|
66
|
+
cache.set('exists', 'value')
|
|
67
|
+
expect(cache.has('exists')).toBe(true)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('returns false for non-existent key', () => {
|
|
71
|
+
expect(cache.has('non-existent')).toBe(false)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('does not affect LRU order', () => {
|
|
75
|
+
cache.set('key1', 'value1')
|
|
76
|
+
cache.set('key2', 'value2')
|
|
77
|
+
|
|
78
|
+
// has() should not affect LRU, so key1 is still oldest
|
|
79
|
+
cache.has('key1')
|
|
80
|
+
cache.has('key1')
|
|
81
|
+
cache.has('key1')
|
|
82
|
+
|
|
83
|
+
// Add more data to potentially trigger eviction
|
|
84
|
+
// key1 should still be first to be evicted since has() doesn't update LRU
|
|
85
|
+
expect(cache.has('key1')).toBe(true)
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
describe('isEmpty', () => {
|
|
90
|
+
test('returns true for empty cache', () => {
|
|
91
|
+
expect(cache.isEmpty).toBe(true)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('returns false when cache has data', () => {
|
|
95
|
+
cache.set('key', 'value')
|
|
96
|
+
expect(cache.isEmpty).toBe(false)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test('returns true after clearing cache', () => {
|
|
100
|
+
cache.set('key', 'value')
|
|
101
|
+
cache.clear()
|
|
102
|
+
expect(cache.isEmpty).toBe(true)
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
describe('remove', () => {
|
|
107
|
+
test('removes existing key', () => {
|
|
108
|
+
cache.set('to-remove', 'value')
|
|
109
|
+
const removed = cache.remove('to-remove')
|
|
110
|
+
expect(removed).toBe(true)
|
|
111
|
+
expect(cache.get('to-remove')).toBeUndefined()
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
test('returns false when removing non-existent key', () => {
|
|
115
|
+
const removed = cache.remove('non-existent')
|
|
116
|
+
expect(removed).toBe(false)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
describe('clear', () => {
|
|
121
|
+
test('removes all cached data', () => {
|
|
122
|
+
cache.set('key1', 'value1')
|
|
123
|
+
cache.set('key2', 'value2')
|
|
124
|
+
cache.set('key3', 'value3')
|
|
125
|
+
|
|
126
|
+
cache.clear()
|
|
127
|
+
|
|
128
|
+
expect(cache.get('key1')).toBeUndefined()
|
|
129
|
+
expect(cache.get('key2')).toBeUndefined()
|
|
130
|
+
expect(cache.get('key3')).toBeUndefined()
|
|
131
|
+
expect(cache.isEmpty).toBe(true)
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
describe('subscribe', () => {
|
|
136
|
+
test('notifies subscriber on set', () => {
|
|
137
|
+
const subscriber = jest.fn()
|
|
138
|
+
cache.subscribe(subscriber)
|
|
139
|
+
|
|
140
|
+
cache.set('key', 'value')
|
|
141
|
+
|
|
142
|
+
expect(subscriber).toHaveBeenCalledWith('key', 'value')
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
test('notifies subscriber on remove', () => {
|
|
146
|
+
const subscriber = jest.fn()
|
|
147
|
+
cache.set('key', 'value')
|
|
148
|
+
cache.subscribe(subscriber)
|
|
149
|
+
|
|
150
|
+
cache.remove('key')
|
|
151
|
+
|
|
152
|
+
expect(subscriber).toHaveBeenCalledWith('key', undefined)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
test('notifies subscriber on clear', () => {
|
|
156
|
+
const subscriber = jest.fn()
|
|
157
|
+
cache.set('key', 'value')
|
|
158
|
+
cache.subscribe(subscriber)
|
|
159
|
+
|
|
160
|
+
cache.clear()
|
|
161
|
+
|
|
162
|
+
expect(subscriber).toHaveBeenCalledWith(undefined, undefined)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
test('does not notify when clear called with notifySubscribers: false', () => {
|
|
166
|
+
const subscriber = jest.fn()
|
|
167
|
+
cache.set('key', 'value')
|
|
168
|
+
cache.subscribe(subscriber)
|
|
169
|
+
|
|
170
|
+
cache.clear({ notifySubscribers: false })
|
|
171
|
+
|
|
172
|
+
expect(subscriber).not.toHaveBeenCalled()
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
test('unsubscribe stops notifications', () => {
|
|
176
|
+
const subscriber = jest.fn()
|
|
177
|
+
const unsubscribe = cache.subscribe(subscriber)
|
|
178
|
+
|
|
179
|
+
cache.set('key1', 'value1')
|
|
180
|
+
expect(subscriber).toHaveBeenCalledTimes(1)
|
|
181
|
+
|
|
182
|
+
unsubscribe()
|
|
183
|
+
|
|
184
|
+
cache.set('key2', 'value2')
|
|
185
|
+
expect(subscriber).toHaveBeenCalledTimes(1) // Still 1, not called again
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
test('handles multiple subscribers', () => {
|
|
189
|
+
const subscriber1 = jest.fn()
|
|
190
|
+
const subscriber2 = jest.fn()
|
|
191
|
+
|
|
192
|
+
cache.subscribe(subscriber1)
|
|
193
|
+
cache.subscribe(subscriber2)
|
|
194
|
+
|
|
195
|
+
cache.set('key', 'value')
|
|
196
|
+
|
|
197
|
+
expect(subscriber1).toHaveBeenCalledWith('key', 'value')
|
|
198
|
+
expect(subscriber2).toHaveBeenCalledWith('key', 'value')
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
test('handles subscriber errors gracefully', () => {
|
|
202
|
+
const errorSubscriber = jest.fn(() => {
|
|
203
|
+
throw new Error('Subscriber error')
|
|
204
|
+
})
|
|
205
|
+
const normalSubscriber = jest.fn()
|
|
206
|
+
|
|
207
|
+
cache.subscribe(errorSubscriber)
|
|
208
|
+
cache.subscribe(normalSubscriber)
|
|
209
|
+
|
|
210
|
+
// Should not throw, and normal subscriber should still be called
|
|
211
|
+
expect(() => cache.set('key', 'value')).not.toThrow()
|
|
212
|
+
expect(normalSubscriber).toHaveBeenCalledWith('key', 'value')
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
describe('capacity management', () => {
|
|
217
|
+
test('evicts least recently used items when capacity exceeded', () => {
|
|
218
|
+
const smallCache = new Cache({
|
|
219
|
+
capacity: 100,
|
|
220
|
+
namespace: `capacity-test-${Date.now()}`,
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
// Add items that together exceed capacity
|
|
224
|
+
smallCache.set('old', 'x'.repeat(40))
|
|
225
|
+
smallCache.set('medium', 'y'.repeat(40))
|
|
226
|
+
smallCache.set('new', 'z'.repeat(40)) // This should trigger eviction
|
|
227
|
+
|
|
228
|
+
// Old item should be evicted
|
|
229
|
+
expect(smallCache.get('old')).toBeUndefined()
|
|
230
|
+
expect(smallCache.get('medium')).toBe('y'.repeat(40))
|
|
231
|
+
expect(smallCache.get('new')).toBe('z'.repeat(40))
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
test('updates LRU order on get', () => {
|
|
235
|
+
const smallCache = new Cache({
|
|
236
|
+
capacity: 100,
|
|
237
|
+
namespace: `lru-test-${Date.now()}`,
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
smallCache.set('first', 'x'.repeat(30))
|
|
241
|
+
smallCache.set('second', 'y'.repeat(30))
|
|
242
|
+
|
|
243
|
+
// Access first item to make it more recent
|
|
244
|
+
smallCache.get('first')
|
|
245
|
+
|
|
246
|
+
// Add new item that triggers eviction
|
|
247
|
+
smallCache.set('third', 'z'.repeat(50))
|
|
248
|
+
|
|
249
|
+
// Second should be evicted, not first (because we accessed first after second)
|
|
250
|
+
expect(smallCache.get('first')).toBe('x'.repeat(30))
|
|
251
|
+
expect(smallCache.get('second')).toBeUndefined()
|
|
252
|
+
expect(smallCache.get('third')).toBe('z'.repeat(50))
|
|
253
|
+
})
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
describe('edge cases', () => {
|
|
257
|
+
test('handles empty string data', () => {
|
|
258
|
+
cache.set('empty', '')
|
|
259
|
+
expect(cache.get('empty')).toBe('')
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
test('handles large data', () => {
|
|
263
|
+
const largeData = 'x'.repeat(10000)
|
|
264
|
+
cache.set('large', largeData)
|
|
265
|
+
expect(cache.get('large')).toBe(largeData)
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
test('handles special characters in keys', () => {
|
|
269
|
+
const specialKey = 'key-!@#$%^&*()_+={}[]|\\:";\'<>?,./with spaces'
|
|
270
|
+
cache.set(specialKey, 'value')
|
|
271
|
+
expect(cache.get(specialKey)).toBe('value')
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
test('handles special characters in data', () => {
|
|
275
|
+
const specialData = 'data with !@#$%^&*()_+={}[]|\\:";\'<>?,./\n\t\r'
|
|
276
|
+
cache.set('key', specialData)
|
|
277
|
+
expect(cache.get('key')).toBe(specialData)
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
test('handles unicode data', () => {
|
|
281
|
+
const unicodeData = '测试数据 🎉 𝓗𝓮𝓵𝓵𝓸'
|
|
282
|
+
cache.set('unicode', unicodeData)
|
|
283
|
+
expect(cache.get('unicode')).toBe(unicodeData)
|
|
284
|
+
})
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
describe('storageDirectory', () => {
|
|
288
|
+
test('returns default directory without namespace', () => {
|
|
289
|
+
const cache = new Cache()
|
|
290
|
+
expect(cache.storageDirectory).toContain('.termcast-bundle')
|
|
291
|
+
expect(cache.storageDirectory).toContain('cache')
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
test('returns namespaced directory with namespace', () => {
|
|
295
|
+
const cache = new Cache({ namespace: 'my-command' })
|
|
296
|
+
expect(cache.storageDirectory).toContain('.termcast-bundle')
|
|
297
|
+
expect(cache.storageDirectory).toContain('cache')
|
|
298
|
+
expect(cache.storageDirectory).toContain('my-command')
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
describe('static properties', () => {
|
|
303
|
+
test('STORAGE_DIRECTORY_NAME is correct', () => {
|
|
304
|
+
expect(Cache.STORAGE_DIRECTORY_NAME).toBe('.termcast-cache')
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
test('DEFAULT_CAPACITY is 10MB', () => {
|
|
308
|
+
expect(Cache.DEFAULT_CAPACITY).toBe(10 * 1024 * 1024)
|
|
309
|
+
})
|
|
310
|
+
})
|
|
311
|
+
})
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import * as os from 'os'
|
|
4
|
+
import * as fs from 'fs'
|
|
5
|
+
import { logger } from '../logger'
|
|
6
|
+
import { useStore } from '../state'
|
|
7
|
+
|
|
8
|
+
function getCurrentDatabasePath(): string {
|
|
9
|
+
const extensionPath = useStore.getState().extensionPath
|
|
10
|
+
|
|
11
|
+
if (extensionPath) {
|
|
12
|
+
// Use same shared database as localstorage
|
|
13
|
+
return path.join(extensionPath, '.termcast-bundle', 'data.db')
|
|
14
|
+
} else {
|
|
15
|
+
return path.join(os.homedir(), '.termcast', '.termcast-bundle', 'data.db')
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getCurrentCacheDir(namespace?: string): string {
|
|
20
|
+
const extensionPath = useStore.getState().extensionPath
|
|
21
|
+
|
|
22
|
+
if (extensionPath) {
|
|
23
|
+
return namespace
|
|
24
|
+
? path.join(extensionPath, '.termcast-bundle', 'cache', namespace)
|
|
25
|
+
: path.join(extensionPath, '.termcast-bundle', 'cache')
|
|
26
|
+
} else {
|
|
27
|
+
return namespace
|
|
28
|
+
? path.join(
|
|
29
|
+
os.homedir(),
|
|
30
|
+
'.termcast',
|
|
31
|
+
'.termcast-bundle',
|
|
32
|
+
'cache',
|
|
33
|
+
namespace,
|
|
34
|
+
)
|
|
35
|
+
: path.join(os.homedir(), '.termcast', '.termcast-bundle', 'cache')
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class Cache {
|
|
40
|
+
static get STORAGE_DIRECTORY_NAME(): string {
|
|
41
|
+
const extensionPath = useStore.getState().extensionPath
|
|
42
|
+
return extensionPath ? 'cache' : '.termcast-cache'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static get DEFAULT_CAPACITY(): number {
|
|
46
|
+
return 10 * 1024 * 1024 // 10 MB
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private db: Database
|
|
50
|
+
private capacity: number
|
|
51
|
+
private namespace?: string
|
|
52
|
+
private tableName: string
|
|
53
|
+
private subscribers: Cache.Subscriber[] = []
|
|
54
|
+
private currentSize: number = 0
|
|
55
|
+
|
|
56
|
+
constructor(options?: Cache.Options) {
|
|
57
|
+
this.capacity = options?.capacity || Cache.DEFAULT_CAPACITY
|
|
58
|
+
this.namespace = options?.namespace
|
|
59
|
+
// Replace non-alphanumeric characters with underscores for valid SQL table names
|
|
60
|
+
const safeNamespace = this.namespace?.replace(/[^a-zA-Z0-9]/g, '_')
|
|
61
|
+
this.tableName = safeNamespace ? `cache_${safeNamespace}` : 'cache'
|
|
62
|
+
|
|
63
|
+
const dbPath = getCurrentDatabasePath()
|
|
64
|
+
|
|
65
|
+
// Ensure parent directory exists
|
|
66
|
+
const dbDir = path.dirname(dbPath)
|
|
67
|
+
if (!fs.existsSync(dbDir)) {
|
|
68
|
+
fs.mkdirSync(dbDir, { recursive: true })
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Open with options to reduce file usage
|
|
72
|
+
this.db = new Database(dbPath, {
|
|
73
|
+
create: true,
|
|
74
|
+
readwrite: true,
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
// Use WAL mode and optimize for single file usage
|
|
78
|
+
this.db.exec('PRAGMA journal_mode = WAL')
|
|
79
|
+
this.db.exec('PRAGMA wal_autocheckpoint = 1000')
|
|
80
|
+
this.db.exec('PRAGMA synchronous = NORMAL')
|
|
81
|
+
|
|
82
|
+
// Use rowid for ordering - it auto-increments and provides natural LRU order
|
|
83
|
+
this.db.exec(`
|
|
84
|
+
CREATE TABLE IF NOT EXISTS ${this.tableName} (
|
|
85
|
+
rowid INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
86
|
+
key TEXT UNIQUE NOT NULL,
|
|
87
|
+
data TEXT NOT NULL,
|
|
88
|
+
size INTEGER NOT NULL
|
|
89
|
+
)
|
|
90
|
+
`)
|
|
91
|
+
|
|
92
|
+
// Create index on key for fast lookups
|
|
93
|
+
this.db.exec(`
|
|
94
|
+
CREATE INDEX IF NOT EXISTS idx_${this.tableName}_key ON ${this.tableName}(key)
|
|
95
|
+
`)
|
|
96
|
+
|
|
97
|
+
// Calculate initial size
|
|
98
|
+
const row = this.db
|
|
99
|
+
.prepare(`SELECT SUM(size) as total FROM ${this.tableName}`)
|
|
100
|
+
.get() as { total: number | null } | undefined
|
|
101
|
+
this.currentSize = row?.total || 0
|
|
102
|
+
|
|
103
|
+
// Bind all methods to this instance
|
|
104
|
+
this.get = this.get.bind(this)
|
|
105
|
+
this.has = this.has.bind(this)
|
|
106
|
+
this.set = this.set.bind(this)
|
|
107
|
+
this.remove = this.remove.bind(this)
|
|
108
|
+
this.clear = this.clear.bind(this)
|
|
109
|
+
this.subscribe = this.subscribe.bind(this)
|
|
110
|
+
this.maintainCapacity = this.maintainCapacity.bind(this)
|
|
111
|
+
this.notifySubscribers = this.notifySubscribers.bind(this)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
get storageDirectory(): string {
|
|
115
|
+
return getCurrentCacheDir(this.namespace)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
get(key: string): string | undefined {
|
|
119
|
+
const row = this.db
|
|
120
|
+
.prepare(`SELECT rowid, data, size FROM ${this.tableName} WHERE key = ?`)
|
|
121
|
+
.get(key) as { rowid: number; data: string; size: number } | undefined
|
|
122
|
+
|
|
123
|
+
if (row) {
|
|
124
|
+
// Move to end of LRU by deleting and reinserting (gets new rowid)
|
|
125
|
+
const tx = this.db.transaction(() => {
|
|
126
|
+
this.db.prepare(`DELETE FROM ${this.tableName} WHERE key = ?`).run(key)
|
|
127
|
+
this.db
|
|
128
|
+
.prepare(
|
|
129
|
+
`INSERT INTO ${this.tableName} (key, data, size) VALUES (?, ?, ?)`,
|
|
130
|
+
)
|
|
131
|
+
.run(key, row.data, row.size)
|
|
132
|
+
})
|
|
133
|
+
tx()
|
|
134
|
+
|
|
135
|
+
return row.data
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return undefined
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
has(key: string): boolean {
|
|
142
|
+
const row = this.db
|
|
143
|
+
.prepare(`SELECT 1 FROM ${this.tableName} WHERE key = ?`)
|
|
144
|
+
.get(key)
|
|
145
|
+
return !!row
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
get isEmpty(): boolean {
|
|
149
|
+
const row = this.db
|
|
150
|
+
.prepare(`SELECT COUNT(*) as count FROM ${this.tableName}`)
|
|
151
|
+
.get() as { count: number }
|
|
152
|
+
return row.count === 0
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
set(key: string, data: string): void {
|
|
156
|
+
const dataSize = Buffer.byteLength(data, 'utf8')
|
|
157
|
+
|
|
158
|
+
// Get existing size if any
|
|
159
|
+
const existingRow = this.db
|
|
160
|
+
.prepare(`SELECT size FROM ${this.tableName} WHERE key = ?`)
|
|
161
|
+
.get(key) as { size: number } | undefined
|
|
162
|
+
const oldSize = existingRow?.size || 0
|
|
163
|
+
const newTotalSize = this.currentSize - oldSize + dataSize
|
|
164
|
+
|
|
165
|
+
if (newTotalSize > this.capacity) {
|
|
166
|
+
this.maintainCapacity(newTotalSize - this.capacity)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Insert or update the cache entry
|
|
170
|
+
this.db
|
|
171
|
+
.prepare(
|
|
172
|
+
`INSERT OR REPLACE INTO ${this.tableName} (key, data, size) VALUES (?, ?, ?)`,
|
|
173
|
+
)
|
|
174
|
+
.run(key, data, dataSize)
|
|
175
|
+
|
|
176
|
+
this.currentSize = this.currentSize - oldSize + dataSize
|
|
177
|
+
this.notifySubscribers(key, data)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
remove(key: string): boolean {
|
|
181
|
+
// Check if key exists and get its size
|
|
182
|
+
const row = this.db
|
|
183
|
+
.prepare(`SELECT size FROM ${this.tableName} WHERE key = ?`)
|
|
184
|
+
.get(key) as { size: number } | undefined
|
|
185
|
+
|
|
186
|
+
if (row) {
|
|
187
|
+
// Delete the key
|
|
188
|
+
this.db.prepare(`DELETE FROM ${this.tableName} WHERE key = ?`).run(key)
|
|
189
|
+
|
|
190
|
+
this.currentSize -= row.size
|
|
191
|
+
this.notifySubscribers(key, undefined)
|
|
192
|
+
return true
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return false
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
clear(options?: { notifySubscribers: boolean }): void {
|
|
199
|
+
this.db.exec(`DELETE FROM ${this.tableName}`)
|
|
200
|
+
this.currentSize = 0
|
|
201
|
+
|
|
202
|
+
if (options?.notifySubscribers !== false) {
|
|
203
|
+
this.notifySubscribers(undefined, undefined)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
subscribe(subscriber: Cache.Subscriber): Cache.Subscription {
|
|
208
|
+
this.subscribers.push(subscriber)
|
|
209
|
+
return () => {
|
|
210
|
+
const index = this.subscribers.indexOf(subscriber)
|
|
211
|
+
if (index > -1) {
|
|
212
|
+
this.subscribers.splice(index, 1)
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private maintainCapacity(bytesToFree: number): void {
|
|
218
|
+
// Order by rowid ASC to get oldest entries first
|
|
219
|
+
const rows = this.db
|
|
220
|
+
.prepare(`SELECT key, size FROM ${this.tableName} ORDER BY rowid ASC`)
|
|
221
|
+
.all() as Array<{ key: string; size: number }>
|
|
222
|
+
|
|
223
|
+
let freedBytes = 0
|
|
224
|
+
const keysToRemove: string[] = []
|
|
225
|
+
|
|
226
|
+
for (const row of rows) {
|
|
227
|
+
if (freedBytes >= bytesToFree) {
|
|
228
|
+
break
|
|
229
|
+
}
|
|
230
|
+
keysToRemove.push(row.key)
|
|
231
|
+
freedBytes += row.size
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (keysToRemove.length > 0) {
|
|
235
|
+
const placeholders = keysToRemove.map(() => '?').join(',')
|
|
236
|
+
const stmt = this.db.prepare(
|
|
237
|
+
`DELETE FROM ${this.tableName} WHERE key IN (${placeholders})`,
|
|
238
|
+
)
|
|
239
|
+
stmt.run(...(keysToRemove as [string, ...string[]]))
|
|
240
|
+
this.currentSize -= freedBytes
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private notifySubscribers(
|
|
245
|
+
key: string | undefined,
|
|
246
|
+
data: string | undefined,
|
|
247
|
+
): void {
|
|
248
|
+
for (const subscriber of this.subscribers) {
|
|
249
|
+
try {
|
|
250
|
+
subscriber(key, data)
|
|
251
|
+
} catch (error) {
|
|
252
|
+
logger.error('Cache subscriber error:', error)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export namespace Cache {
|
|
259
|
+
export interface Options {
|
|
260
|
+
namespace?: string
|
|
261
|
+
capacity?: number
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export type Subscriber = (
|
|
265
|
+
key: string | undefined,
|
|
266
|
+
data: string | undefined,
|
|
267
|
+
) => void
|
|
268
|
+
export type Subscription = () => void
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
interface CacheMetadata {
|
|
272
|
+
timestamp: number
|
|
273
|
+
value: any
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const functionCacheMap = new Map<string, Cache>()
|
|
277
|
+
const functionCacheData = new Map<string, Map<string, CacheMetadata>>()
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Wraps an async function with caching capabilities.
|
|
281
|
+
*
|
|
282
|
+
* This higher-order function adds automatic caching to any async function. Results are
|
|
283
|
+
* cached both in memory and persistently on disk, with support for cache expiration
|
|
284
|
+
* and validation. Each unique set of arguments creates a separate cache entry.
|
|
285
|
+
*
|
|
286
|
+
* @param fn - The async function to wrap with caching
|
|
287
|
+
* @param options - Caching options
|
|
288
|
+
* @param options.validate - Function to check if cached data is still valid (called before returning cached data)
|
|
289
|
+
* @param options.maxAge - Maximum age in milliseconds before cached data expires (default: Infinity)
|
|
290
|
+
* @returns The wrapped function with an additional `clearCache()` method
|
|
291
|
+
* @template Fn - Type of the async function being wrapped
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```typescript
|
|
295
|
+
* // Basic caching
|
|
296
|
+
* const fetchUser = async (userId: string) => {
|
|
297
|
+
* const response = await fetch(`/api/users/${userId}`)
|
|
298
|
+
* return response.json()
|
|
299
|
+
* }
|
|
300
|
+
* const cachedFetchUser = withCache(fetchUser)
|
|
301
|
+
*
|
|
302
|
+
* // First call fetches from API
|
|
303
|
+
* const user1 = await cachedFetchUser("123") // Makes API call
|
|
304
|
+
* // Subsequent calls return from cache
|
|
305
|
+
* const user2 = await cachedFetchUser("123") // Returns cached data
|
|
306
|
+
*
|
|
307
|
+
* // With expiration (5 minutes)
|
|
308
|
+
* const cachedSearch = withCache(searchAPI, {
|
|
309
|
+
* maxAge: 5 * 60 * 1000
|
|
310
|
+
* })
|
|
311
|
+
*
|
|
312
|
+
* // With validation
|
|
313
|
+
* const cachedGetConfig = withCache(getConfig, {
|
|
314
|
+
* validate: (config) => config.version === currentVersion
|
|
315
|
+
* })
|
|
316
|
+
*
|
|
317
|
+
* // Clear cache manually
|
|
318
|
+
* cachedFetchUser.clearCache()
|
|
319
|
+
*
|
|
320
|
+
* // Different arguments are cached separately
|
|
321
|
+
* await cachedFetchUser("123") // Cached
|
|
322
|
+
* await cachedFetchUser("456") // Different cache entry
|
|
323
|
+
* ```
|
|
324
|
+
*/
|
|
325
|
+
export function withCache<Fn extends (...args: any[]) => Promise<any>>(
|
|
326
|
+
fn: Fn,
|
|
327
|
+
options?: {
|
|
328
|
+
validate?: (data: Awaited<ReturnType<Fn>>) => boolean
|
|
329
|
+
maxAge?: number
|
|
330
|
+
},
|
|
331
|
+
): Fn & { clearCache: () => void } {
|
|
332
|
+
const fnKey = fn.toString()
|
|
333
|
+
const maxAge = options?.maxAge || Infinity
|
|
334
|
+
const validate = options?.validate || (() => true)
|
|
335
|
+
|
|
336
|
+
if (!functionCacheMap.has(fnKey)) {
|
|
337
|
+
functionCacheMap.set(fnKey, new Cache({ namespace: `fn-${Date.now()}` }))
|
|
338
|
+
functionCacheData.set(fnKey, new Map())
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const cache = functionCacheMap.get(fnKey)!
|
|
342
|
+
const cacheData = functionCacheData.get(fnKey)!
|
|
343
|
+
|
|
344
|
+
const cachedFn = (async (...args: Parameters<Fn>) => {
|
|
345
|
+
const cacheKey = JSON.stringify(args)
|
|
346
|
+
|
|
347
|
+
// Check memory cache first
|
|
348
|
+
const cached = cacheData.get(cacheKey)
|
|
349
|
+
if (cached) {
|
|
350
|
+
const age = Date.now() - cached.timestamp
|
|
351
|
+
if (age < maxAge && validate(cached.value)) {
|
|
352
|
+
return cached.value
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Check persistent cache
|
|
357
|
+
const persistentCached = cache.get(cacheKey)
|
|
358
|
+
if (persistentCached) {
|
|
359
|
+
try {
|
|
360
|
+
const metadata = JSON.parse(persistentCached) as CacheMetadata
|
|
361
|
+
const age = Date.now() - metadata.timestamp
|
|
362
|
+
if (age < maxAge && validate(metadata.value)) {
|
|
363
|
+
// Update memory cache
|
|
364
|
+
cacheData.set(cacheKey, metadata)
|
|
365
|
+
return metadata.value
|
|
366
|
+
}
|
|
367
|
+
} catch {
|
|
368
|
+
// Invalid cache entry, ignore
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Call the original function
|
|
373
|
+
const result = await fn(...args)
|
|
374
|
+
|
|
375
|
+
// Cache the result
|
|
376
|
+
const metadata: CacheMetadata = {
|
|
377
|
+
timestamp: Date.now(),
|
|
378
|
+
value: result,
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Update both caches
|
|
382
|
+
cacheData.set(cacheKey, metadata)
|
|
383
|
+
cache.set(cacheKey, JSON.stringify(metadata))
|
|
384
|
+
|
|
385
|
+
return result
|
|
386
|
+
}) as any
|
|
387
|
+
|
|
388
|
+
cachedFn.clearCache = () => {
|
|
389
|
+
cache.clear()
|
|
390
|
+
cacheData.clear()
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return cachedFn as Fn & { clearCache: () => void }
|
|
394
|
+
}
|