termcast 1.3.32 → 1.3.34
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.map +1 -1
- package/dist/action-utils.js +8 -0
- package/dist/action-utils.js.map +1 -1
- package/dist/apis/cache.d.ts +1 -2
- package/dist/apis/cache.d.ts.map +1 -1
- package/dist/apis/cache.js +138 -54
- package/dist/apis/cache.js.map +1 -1
- package/dist/apis/clipboard.d.ts.map +1 -1
- package/dist/apis/clipboard.js +4 -0
- package/dist/apis/clipboard.js.map +1 -1
- package/dist/apis/oauth.d.ts.map +1 -1
- package/dist/apis/oauth.js +31 -4
- package/dist/apis/oauth.js.map +1 -1
- package/dist/build.d.ts +0 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +30 -51
- package/dist/build.js.map +1 -1
- package/dist/cli.js +31 -14
- package/dist/cli.js.map +1 -1
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +5 -1
- package/dist/compile.js.map +1 -1
- package/dist/components/actions.d.ts +14 -0
- package/dist/components/actions.d.ts.map +1 -1
- package/dist/components/actions.js +151 -59
- package/dist/components/actions.js.map +1 -1
- package/dist/components/alert.d.ts.map +1 -1
- package/dist/components/alert.js +6 -5
- package/dist/components/alert.js.map +1 -1
- package/dist/components/animation-tick.d.ts +1 -1
- package/dist/components/animation-tick.js +1 -1
- package/dist/components/animation-tick.js.map +1 -1
- package/dist/components/detail.d.ts +5 -31
- package/dist/components/detail.d.ts.map +1 -1
- package/dist/components/detail.js +36 -52
- package/dist/components/detail.js.map +1 -1
- package/dist/components/dropdown.d.ts +1 -1
- package/dist/components/dropdown.d.ts.map +1 -1
- package/dist/components/dropdown.js +50 -22
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/footer.d.ts.map +1 -1
- package/dist/components/footer.js +19 -18
- package/dist/components/footer.js.map +1 -1
- package/dist/components/form/checkbox.d.ts.map +1 -1
- package/dist/components/form/checkbox.js +12 -11
- package/dist/components/form/checkbox.js.map +1 -1
- package/dist/components/form/date-picker.d.ts.map +1 -1
- package/dist/components/form/date-picker.js +7 -22
- package/dist/components/form/date-picker.js.map +1 -1
- package/dist/components/form/description.d.ts +1 -1
- package/dist/components/form/description.d.ts.map +1 -1
- package/dist/components/form/description.js +6 -5
- package/dist/components/form/description.js.map +1 -1
- package/dist/components/form/dropdown.d.ts.map +1 -1
- package/dist/components/form/dropdown.js +53 -50
- package/dist/components/form/dropdown.js.map +1 -1
- package/dist/components/form/file-autocomplete.d.ts.map +1 -1
- package/dist/components/form/file-autocomplete.js +5 -4
- package/dist/components/form/file-autocomplete.js.map +1 -1
- package/dist/components/form/file-picker.d.ts.map +1 -1
- package/dist/components/form/file-picker.js +23 -22
- package/dist/components/form/file-picker.js.map +1 -1
- package/dist/components/form/form-end.d.ts.map +1 -1
- package/dist/components/form/form-end.js +6 -4
- package/dist/components/form/form-end.js.map +1 -1
- package/dist/components/form/form-field-wrapper.d.ts +15 -0
- package/dist/components/form/form-field-wrapper.d.ts.map +1 -0
- package/dist/components/form/form-field-wrapper.js +29 -0
- package/dist/components/form/form-field-wrapper.js.map +1 -0
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +31 -30
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/form/password-field.d.ts.map +1 -1
- package/dist/components/form/password-field.js +7 -6
- package/dist/components/form/password-field.js.map +1 -1
- package/dist/components/form/separator.d.ts.map +1 -1
- package/dist/components/form/separator.js +3 -2
- package/dist/components/form/separator.js.map +1 -1
- package/dist/components/form/tagpicker.d.ts.map +1 -1
- package/dist/components/form/tagpicker.js +2 -1
- package/dist/components/form/tagpicker.js.map +1 -1
- package/dist/components/form/text-area.d.ts.map +1 -1
- package/dist/components/form/text-area.js +7 -6
- package/dist/components/form/text-area.js.map +1 -1
- package/dist/components/form/text-field.d.ts.map +1 -1
- package/dist/components/form/text-field.js +7 -6
- package/dist/components/form/text-field.js.map +1 -1
- package/dist/components/form/use-form-navigation.d.ts.map +1 -1
- package/dist/components/form/use-form-navigation.js +4 -4
- package/dist/components/form/use-form-navigation.js.map +1 -1
- package/dist/components/form/with-left-border.d.ts +15 -0
- package/dist/components/form/with-left-border.d.ts.map +1 -1
- package/dist/components/form/with-left-border.js +21 -9
- package/dist/components/form/with-left-border.js.map +1 -1
- package/dist/components/icon.d.ts +14 -0
- package/dist/components/icon.d.ts.map +1 -1
- package/dist/components/icon.js +60 -0
- package/dist/components/icon.js.map +1 -1
- package/dist/components/image.d.ts +47 -2
- package/dist/components/image.d.ts.map +1 -1
- package/dist/components/image.js +46 -7
- package/dist/components/image.js.map +1 -1
- package/dist/components/list.d.ts +5 -0
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +188 -132
- package/dist/components/list.js.map +1 -1
- package/dist/components/loading-bar.d.ts.map +1 -1
- package/dist/components/loading-bar.js +4 -3
- package/dist/components/loading-bar.js.map +1 -1
- package/dist/components/metadata.d.ts +70 -0
- package/dist/components/metadata.d.ts.map +1 -0
- package/dist/components/metadata.js +82 -0
- package/dist/components/metadata.js.map +1 -0
- package/dist/components/theme-picker.d.ts.map +1 -1
- package/dist/components/theme-picker.js +3 -2
- package/dist/components/theme-picker.js.map +1 -1
- package/dist/descendants-v2.d.ts +60 -0
- package/dist/descendants-v2.d.ts.map +1 -0
- package/dist/descendants-v2.js +144 -0
- package/dist/descendants-v2.js.map +1 -0
- package/dist/examples/actions-context.d.ts +2 -0
- package/dist/examples/actions-context.d.ts.map +1 -0
- package/dist/examples/actions-context.js +33 -0
- package/dist/examples/actions-context.js.map +1 -0
- package/dist/examples/form-basic.d.ts.map +1 -1
- package/dist/examples/form-basic.js +1 -1
- package/dist/examples/form-basic.js.map +1 -1
- package/dist/examples/form-dropdown.js +1 -1
- package/dist/examples/form-dropdown.js.map +1 -1
- package/dist/examples/internal/custom-action-renderables.d.ts +70 -0
- package/dist/examples/internal/custom-action-renderables.d.ts.map +1 -0
- package/dist/examples/internal/custom-action-renderables.js +163 -0
- package/dist/examples/internal/custom-action-renderables.js.map +1 -0
- package/dist/examples/internal/custom-dropdown.d.ts +99 -0
- package/dist/examples/internal/custom-dropdown.d.ts.map +1 -0
- package/dist/examples/internal/custom-dropdown.js +270 -0
- package/dist/examples/internal/custom-dropdown.js.map +1 -0
- package/dist/examples/internal/custom-renderable-form.d.ts +43 -0
- package/dist/examples/internal/custom-renderable-form.d.ts.map +1 -0
- package/dist/examples/internal/custom-renderable-form.js +284 -0
- package/dist/examples/internal/custom-renderable-form.js.map +1 -0
- package/dist/examples/internal/custom-renderable-list-default-search.d.ts +2 -0
- package/dist/examples/internal/custom-renderable-list-default-search.d.ts.map +1 -0
- package/dist/examples/internal/custom-renderable-list-default-search.js +16 -0
- package/dist/examples/internal/custom-renderable-list-default-search.js.map +1 -0
- package/dist/examples/internal/custom-renderable-list-v2-default-search.d.ts +2 -0
- package/dist/examples/internal/custom-renderable-list-v2-default-search.d.ts.map +1 -0
- package/dist/examples/internal/custom-renderable-list-v2-default-search.js +24 -0
- package/dist/examples/internal/custom-renderable-list-v2-default-search.js.map +1 -0
- package/dist/examples/internal/custom-renderable-list-v2.d.ts +189 -0
- package/dist/examples/internal/custom-renderable-list-v2.d.ts.map +1 -0
- package/dist/examples/internal/custom-renderable-list-v2.js +708 -0
- package/dist/examples/internal/custom-renderable-list-v2.js.map +1 -0
- package/dist/examples/internal/custom-renderable-list.d.ts +72 -0
- package/dist/examples/internal/custom-renderable-list.d.ts.map +1 -0
- package/dist/examples/internal/custom-renderable-list.js +544 -0
- package/dist/examples/internal/custom-renderable-list.js.map +1 -0
- package/dist/examples/internal/rhf-custom-ref.js +5 -4
- package/dist/examples/internal/rhf-custom-ref.js.map +1 -1
- package/dist/examples/internal/scrollbox-with-descendants.js +4 -2
- package/dist/examples/internal/scrollbox-with-descendants.js.map +1 -1
- package/dist/examples/list-controlled-search.d.ts +2 -0
- package/dist/examples/list-controlled-search.d.ts.map +1 -0
- package/dist/examples/list-controlled-search.js +12 -0
- package/dist/examples/list-controlled-search.js.map +1 -0
- package/dist/examples/list-detail-metadata.js +1 -1
- package/dist/examples/list-detail-metadata.js.map +1 -1
- package/dist/examples/simple-image-mask.d.ts +8 -0
- package/dist/examples/simple-image-mask.d.ts.map +1 -0
- package/dist/examples/simple-image-mask.js +12 -0
- package/dist/examples/simple-image-mask.js.map +1 -0
- package/dist/examples/toast-variations.js +1 -1
- package/dist/examples/toast-variations.js.map +1 -1
- package/dist/extensions/dev.d.ts.map +1 -1
- package/dist/extensions/dev.js +3 -2
- package/dist/extensions/dev.js.map +1 -1
- package/dist/extensions/react-refresh-init.d.ts.map +1 -1
- package/dist/extensions/react-refresh-init.js +4 -3
- package/dist/extensions/react-refresh-init.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/date-picker-widget.d.ts.map +1 -1
- package/dist/internal/date-picker-widget.js +2 -1
- package/dist/internal/date-picker-widget.js.map +1 -1
- package/dist/internal/dialog.d.ts +6 -0
- package/dist/internal/dialog.d.ts.map +1 -1
- package/dist/internal/dialog.js +59 -18
- package/dist/internal/dialog.js.map +1 -1
- package/dist/internal/navigation.d.ts.map +1 -1
- package/dist/internal/navigation.js +8 -1
- package/dist/internal/navigation.js.map +1 -1
- package/dist/internal/offscreen.d.ts +3 -0
- package/dist/internal/offscreen.d.ts.map +1 -1
- package/dist/internal/offscreen.js +5 -0
- package/dist/internal/offscreen.js.map +1 -1
- package/dist/internal/providers.d.ts.map +1 -1
- package/dist/internal/providers.js +20 -3
- package/dist/internal/providers.js.map +1 -1
- package/dist/internal/scrollbox.d.ts.map +1 -1
- package/dist/internal/scrollbox.js +3 -2
- package/dist/internal/scrollbox.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +4 -0
- package/dist/logger.js.map +1 -1
- package/dist/preload.js +5 -17
- package/dist/preload.js.map +1 -1
- package/dist/state.d.ts +4 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +4 -0
- package/dist/state.js.map +1 -1
- package/dist/test-border-overlay.d.ts +2 -0
- package/dist/test-border-overlay.d.ts.map +1 -0
- package/dist/test-border-overlay.js +7 -0
- package/dist/test-border-overlay.js.map +1 -0
- package/dist/test-layout-2.d.ts +2 -0
- package/dist/test-layout-2.d.ts.map +1 -0
- package/dist/test-layout-2.js +5 -0
- package/dist/test-layout-2.js.map +1 -0
- package/dist/test-layout.d.ts +2 -0
- package/dist/test-layout.d.ts.map +1 -0
- package/dist/test-layout.js +7 -0
- package/dist/test-layout.js.map +1 -0
- package/dist/theme.d.ts +1 -2
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +5 -9
- package/dist/theme.js.map +1 -1
- package/dist/utils/run-command.d.ts +1 -1
- package/dist/utils/run-command.d.ts.map +1 -1
- package/dist/utils/run-command.js +27 -7
- package/dist/utils/run-command.js.map +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +44 -23
- package/dist/utils.js.map +1 -1
- package/dist/watcher.d.ts.map +1 -1
- package/dist/watcher.js +24 -4
- package/dist/watcher.js.map +1 -1
- package/package.json +14 -12
- package/src/action-utils.tsx +10 -0
- package/src/apis/cache.test.ts +35 -3
- package/src/apis/cache.tsx +184 -59
- package/src/apis/clipboard.tsx +5 -0
- package/src/apis/oauth.tsx +33 -4
- package/src/build.tsx +35 -58
- package/src/cli.tsx +156 -134
- package/src/compile.tsx +6 -3
- package/src/compile.vitest.tsx +33 -15
- package/src/components/actions.tsx +230 -99
- package/src/components/alert.tsx +11 -10
- package/src/components/animation-tick.tsx +1 -1
- package/src/components/detail.tsx +56 -151
- package/src/components/dropdown.tsx +70 -36
- package/src/components/footer.tsx +58 -33
- package/src/components/form/checkbox.tsx +30 -32
- package/src/components/form/date-picker.tsx +27 -47
- package/src/components/form/description.tsx +19 -18
- package/src/components/form/dropdown.tsx +95 -103
- package/src/components/form/file-autocomplete.tsx +9 -8
- package/src/components/form/file-picker.tsx +46 -46
- package/src/components/form/form-end.tsx +6 -4
- package/src/components/form/index.tsx +38 -48
- package/src/components/form/password-field.tsx +25 -27
- package/src/components/form/separator.tsx +3 -2
- package/src/components/form/tagpicker.tsx +2 -1
- package/src/components/form/text-area.tsx +25 -30
- package/src/components/form/text-field.tsx +25 -27
- package/src/components/form/use-form-navigation.tsx +4 -5
- package/src/components/form/with-left-border.tsx +48 -10
- package/src/components/icon.tsx +69 -0
- package/src/components/image.tsx +60 -7
- package/src/components/list.tsx +270 -202
- package/src/components/loading-bar.tsx +4 -3
- package/src/components/metadata.tsx +217 -0
- package/src/components/theme-picker.tsx +3 -2
- package/src/examples/actions-context.tsx +63 -0
- package/src/examples/actions-context.vitest.tsx +110 -0
- package/src/examples/actions-dialog-layout.vitest.tsx +2 -1
- package/src/examples/file-autocomplete.vitest.tsx +15 -15
- package/src/examples/form-basic.tsx +12 -0
- package/src/examples/form-basic.vitest.tsx +74 -74
- package/src/examples/form-dropdown.tsx +8 -0
- package/src/examples/form-dropdown.vitest.tsx +364 -421
- package/src/examples/form-tagpicker.vitest.tsx +56 -54
- package/src/examples/github.vitest.tsx +252 -0
- package/src/examples/internal/rhf-custom-ref.tsx +16 -15
- package/src/examples/internal/scrollbox-with-descendants.tsx +4 -2
- package/src/examples/internal/simple-dialog.tsx +1 -1
- package/src/examples/internal/simple-scrollbox.vitest.tsx +14 -9
- package/src/examples/list-controlled-search.tsx +28 -0
- package/src/examples/list-controlled-search.vitest.tsx +49 -0
- package/src/examples/list-detail-metadata.tsx +8 -5
- package/src/examples/list-detail-metadata.vitest.tsx +22 -22
- package/src/examples/list-dropdown-default.vitest.tsx +12 -12
- package/src/examples/list-scrollbox.vitest.tsx +52 -38
- package/src/examples/list-with-detail.vitest.tsx +45 -41
- package/src/examples/list-with-dropdown.vitest.tsx +5 -5
- package/src/examples/list-with-sections.vitest.tsx +65 -12
- package/src/examples/list-with-toast.vitest.tsx +4 -4
- package/src/examples/simple-file-picker.vitest.tsx +12 -12
- package/src/examples/simple-grid.vitest.tsx +53 -53
- package/src/examples/simple-image-mask.tsx +58 -0
- package/src/examples/simple-navigation.vitest.tsx +19 -19
- package/src/examples/store.vitest.tsx +1 -1
- package/src/examples/swift-extension.vitest.tsx +4 -2
- package/src/examples/synonyms.vitest.tsx +31 -9
- package/src/examples/toast-action.vitest.tsx +8 -8
- package/src/examples/toast-variations.tsx +1 -1
- package/src/examples/toast-variations.vitest.tsx +69 -134
- package/src/extensions/dev.tsx +3 -2
- package/src/extensions/dev.vitest.tsx +65 -28
- package/src/extensions/react-refresh-init.tsx +4 -3
- package/src/index.tsx +3 -1
- package/src/internal/date-picker-widget.tsx +2 -1
- package/src/internal/dialog.tsx +100 -28
- package/src/internal/navigation.tsx +8 -1
- package/src/internal/offscreen.tsx +10 -0
- package/src/internal/providers.tsx +34 -8
- package/src/internal/scrollbox.tsx +4 -2
- package/src/logger.tsx +4 -0
- package/src/preload.tsx +5 -17
- package/src/state.tsx +12 -0
- package/src/theme.tsx +6 -9
- package/src/utils/run-command.tsx +32 -8
- package/src/utils.tsx +58 -23
- package/src/watcher.tsx +26 -6
package/src/apis/cache.tsx
CHANGED
|
@@ -5,15 +5,27 @@ import * as fs from 'fs'
|
|
|
5
5
|
import { logger } from '../logger'
|
|
6
6
|
import { useStore } from '../state'
|
|
7
7
|
|
|
8
|
+
const CACHE_TABLE_NAME = 'cache_entries'
|
|
9
|
+
const DEFAULT_NAMESPACE = '__default__'
|
|
10
|
+
const initializedDatabasePaths = new Set<string>()
|
|
11
|
+
let logicalTimestamp = Date.now()
|
|
12
|
+
|
|
13
|
+
function nextTimestamp(): number {
|
|
14
|
+
logicalTimestamp += 1
|
|
15
|
+
return logicalTimestamp
|
|
16
|
+
}
|
|
17
|
+
|
|
8
18
|
function getCurrentDatabasePath(): string {
|
|
9
19
|
const { extensionPath } = useStore.getState()
|
|
20
|
+
const dbSuffix = process.env.TERMCAST_DB_SUFFIX?.replace(/[^a-zA-Z0-9_-]/g, '_')
|
|
21
|
+
const dbFileName = dbSuffix ? `data-${dbSuffix}.db` : 'data.db'
|
|
10
22
|
|
|
11
23
|
if (extensionPath) {
|
|
12
|
-
return path.join(extensionPath, '.termcast-bundle',
|
|
24
|
+
return path.join(extensionPath, '.termcast-bundle', dbFileName)
|
|
13
25
|
}
|
|
14
26
|
|
|
15
27
|
// Fallback for examples/tests that don't set extensionPath
|
|
16
|
-
return path.join(os.homedir(), '.termcast', '.termcast-bundle',
|
|
28
|
+
return path.join(os.homedir(), '.termcast', '.termcast-bundle', dbFileName)
|
|
17
29
|
}
|
|
18
30
|
|
|
19
31
|
function getCurrentCacheDir(namespace?: string): string {
|
|
@@ -26,6 +38,109 @@ function getCurrentCacheDir(namespace?: string): string {
|
|
|
26
38
|
return namespace ? path.join(baseDir, namespace) : baseDir
|
|
27
39
|
}
|
|
28
40
|
|
|
41
|
+
function getNamespace(namespace?: string): string {
|
|
42
|
+
return namespace || DEFAULT_NAMESPACE
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function initializeDatabaseOnce({ db, dbPath }: { db: Database; dbPath: string }): void {
|
|
46
|
+
if (initializedDatabasePaths.has(dbPath)) {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
db.exec('PRAGMA journal_mode = WAL')
|
|
51
|
+
db.exec('PRAGMA wal_autocheckpoint = 1000')
|
|
52
|
+
db.exec('PRAGMA synchronous = NORMAL')
|
|
53
|
+
|
|
54
|
+
db.exec(`
|
|
55
|
+
CREATE TABLE IF NOT EXISTS ${CACHE_TABLE_NAME} (
|
|
56
|
+
namespace TEXT NOT NULL,
|
|
57
|
+
key TEXT NOT NULL,
|
|
58
|
+
data TEXT NOT NULL,
|
|
59
|
+
size INTEGER NOT NULL,
|
|
60
|
+
last_accessed_at INTEGER NOT NULL,
|
|
61
|
+
updated_at INTEGER NOT NULL,
|
|
62
|
+
PRIMARY KEY(namespace, key)
|
|
63
|
+
)
|
|
64
|
+
`)
|
|
65
|
+
|
|
66
|
+
db.exec(`
|
|
67
|
+
CREATE INDEX IF NOT EXISTS idx_${CACHE_TABLE_NAME}_namespace_lru
|
|
68
|
+
ON ${CACHE_TABLE_NAME}(namespace, last_accessed_at)
|
|
69
|
+
`)
|
|
70
|
+
|
|
71
|
+
cleanupLegacyCacheTables(db)
|
|
72
|
+
initializedDatabasePaths.add(dbPath)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function cleanupLegacyCacheTables(db: Database): void {
|
|
76
|
+
const rows = db
|
|
77
|
+
.prepare(
|
|
78
|
+
`SELECT name FROM sqlite_master
|
|
79
|
+
WHERE type = 'table'
|
|
80
|
+
AND (name = 'cache' OR name LIKE 'cache_%')
|
|
81
|
+
AND name != ?`,
|
|
82
|
+
)
|
|
83
|
+
.all(CACHE_TABLE_NAME) as Array<{ name: string }>
|
|
84
|
+
|
|
85
|
+
if (rows.length === 0) {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const tx = db.transaction(() => {
|
|
90
|
+
const upsert = db.prepare(
|
|
91
|
+
`INSERT INTO ${CACHE_TABLE_NAME} (namespace, key, data, size, last_accessed_at, updated_at)
|
|
92
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
93
|
+
ON CONFLICT(namespace, key)
|
|
94
|
+
DO UPDATE SET
|
|
95
|
+
data = excluded.data,
|
|
96
|
+
size = excluded.size,
|
|
97
|
+
last_accessed_at = excluded.last_accessed_at,
|
|
98
|
+
updated_at = excluded.updated_at`,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
for (const { name } of rows) {
|
|
102
|
+
const namespace =
|
|
103
|
+
name === 'cache'
|
|
104
|
+
? DEFAULT_NAMESPACE
|
|
105
|
+
: name === 'cache_tanstack_query'
|
|
106
|
+
? 'tanstack-query'
|
|
107
|
+
: `legacy:${name.slice('cache_'.length)}`
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const values = db
|
|
111
|
+
.prepare(`SELECT key, data, size, rowid FROM ${name}`)
|
|
112
|
+
.all() as Array<{ key: string; data: string; size: number; rowid: number }>
|
|
113
|
+
|
|
114
|
+
values.forEach((entry) => {
|
|
115
|
+
const timestamp = entry.rowid
|
|
116
|
+
upsert.run(
|
|
117
|
+
namespace,
|
|
118
|
+
entry.key,
|
|
119
|
+
entry.data,
|
|
120
|
+
entry.size,
|
|
121
|
+
timestamp,
|
|
122
|
+
timestamp,
|
|
123
|
+
)
|
|
124
|
+
})
|
|
125
|
+
} catch {
|
|
126
|
+
// Ignore invalid legacy tables and continue cleanup.
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
db.exec(`DROP TABLE IF EXISTS ${name}`)
|
|
130
|
+
}
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
tx()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function hashString(value: string): string {
|
|
137
|
+
let hash = 0
|
|
138
|
+
for (let i = 0; i < value.length; i++) {
|
|
139
|
+
hash = (hash * 31 + value.charCodeAt(i)) | 0
|
|
140
|
+
}
|
|
141
|
+
return Math.abs(hash).toString(36)
|
|
142
|
+
}
|
|
143
|
+
|
|
29
144
|
export class Cache {
|
|
30
145
|
static get STORAGE_DIRECTORY_NAME(): string {
|
|
31
146
|
const extensionPath = useStore.getState().extensionPath
|
|
@@ -38,17 +153,14 @@ export class Cache {
|
|
|
38
153
|
|
|
39
154
|
private db: Database
|
|
40
155
|
private capacity: number
|
|
41
|
-
private namespace
|
|
42
|
-
private tableName: string
|
|
156
|
+
private namespace: string
|
|
43
157
|
private subscribers: Cache.Subscriber[] = []
|
|
44
158
|
private currentSize: number = 0
|
|
45
159
|
|
|
46
160
|
constructor(options?: Cache.Options) {
|
|
161
|
+
const sqliteLoadStart = Date.now()
|
|
47
162
|
this.capacity = options?.capacity || Cache.DEFAULT_CAPACITY
|
|
48
|
-
this.namespace = options?.namespace
|
|
49
|
-
// Replace non-alphanumeric characters with underscores for valid SQL table names
|
|
50
|
-
const safeNamespace = this.namespace?.replace(/[^a-zA-Z0-9]/g, '_')
|
|
51
|
-
this.tableName = safeNamespace ? `cache_${safeNamespace}` : 'cache'
|
|
163
|
+
this.namespace = getNamespace(options?.namespace)
|
|
52
164
|
|
|
53
165
|
const dbPath = getCurrentDatabasePath()
|
|
54
166
|
|
|
@@ -64,32 +176,23 @@ export class Cache {
|
|
|
64
176
|
readwrite: true,
|
|
65
177
|
})
|
|
66
178
|
|
|
67
|
-
|
|
68
|
-
this.db.exec('PRAGMA journal_mode = WAL')
|
|
69
|
-
this.db.exec('PRAGMA wal_autocheckpoint = 1000')
|
|
70
|
-
this.db.exec('PRAGMA synchronous = NORMAL')
|
|
71
|
-
|
|
72
|
-
// Use rowid for ordering - it auto-increments and provides natural LRU order
|
|
73
|
-
this.db.exec(`
|
|
74
|
-
CREATE TABLE IF NOT EXISTS ${this.tableName} (
|
|
75
|
-
rowid INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
76
|
-
key TEXT UNIQUE NOT NULL,
|
|
77
|
-
data TEXT NOT NULL,
|
|
78
|
-
size INTEGER NOT NULL
|
|
79
|
-
)
|
|
80
|
-
`)
|
|
81
|
-
|
|
82
|
-
// Create index on key for fast lookups
|
|
83
|
-
this.db.exec(`
|
|
84
|
-
CREATE INDEX IF NOT EXISTS idx_${this.tableName}_key ON ${this.tableName}(key)
|
|
85
|
-
`)
|
|
179
|
+
initializeDatabaseOnce({ db: this.db, dbPath })
|
|
86
180
|
|
|
87
181
|
// Calculate initial size
|
|
88
182
|
const row = this.db
|
|
89
|
-
.prepare(
|
|
90
|
-
|
|
183
|
+
.prepare(
|
|
184
|
+
`SELECT COALESCE(SUM(size), 0) as total FROM ${CACHE_TABLE_NAME} WHERE namespace = ?`,
|
|
185
|
+
)
|
|
186
|
+
.get(this.namespace) as { total: number | null } | undefined
|
|
91
187
|
this.currentSize = row?.total || 0
|
|
92
188
|
|
|
189
|
+
const sqliteLoadMs = Date.now() - sqliteLoadStart
|
|
190
|
+
if (sqliteLoadMs > 500) {
|
|
191
|
+
logger.log(
|
|
192
|
+
`[perf] sqlite cache init took ${sqliteLoadMs}ms (namespace=${this.namespace})`,
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
|
|
93
196
|
// Bind all methods to this instance
|
|
94
197
|
this.get = this.get.bind(this)
|
|
95
198
|
this.has = this.has.bind(this)
|
|
@@ -106,21 +209,19 @@ export class Cache {
|
|
|
106
209
|
}
|
|
107
210
|
|
|
108
211
|
get(key: string): string | undefined {
|
|
212
|
+
const now = nextTimestamp()
|
|
109
213
|
const row = this.db
|
|
110
|
-
.prepare(
|
|
111
|
-
|
|
214
|
+
.prepare(
|
|
215
|
+
`SELECT data, size FROM ${CACHE_TABLE_NAME} WHERE namespace = ? AND key = ?`,
|
|
216
|
+
)
|
|
217
|
+
.get(this.namespace, key) as { data: string; size: number } | undefined
|
|
112
218
|
|
|
113
219
|
if (row) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
`INSERT INTO ${this.tableName} (key, data, size) VALUES (?, ?, ?)`,
|
|
120
|
-
)
|
|
121
|
-
.run(key, row.data, row.size)
|
|
122
|
-
})
|
|
123
|
-
tx()
|
|
220
|
+
this.db
|
|
221
|
+
.prepare(
|
|
222
|
+
`UPDATE ${CACHE_TABLE_NAME} SET last_accessed_at = ? WHERE namespace = ? AND key = ?`,
|
|
223
|
+
)
|
|
224
|
+
.run(now, this.namespace, key)
|
|
124
225
|
|
|
125
226
|
return row.data
|
|
126
227
|
}
|
|
@@ -130,25 +231,30 @@ export class Cache {
|
|
|
130
231
|
|
|
131
232
|
has(key: string): boolean {
|
|
132
233
|
const row = this.db
|
|
133
|
-
.prepare(`SELECT 1 FROM ${
|
|
134
|
-
.get(key)
|
|
234
|
+
.prepare(`SELECT 1 FROM ${CACHE_TABLE_NAME} WHERE namespace = ? AND key = ?`)
|
|
235
|
+
.get(this.namespace, key)
|
|
135
236
|
return !!row
|
|
136
237
|
}
|
|
137
238
|
|
|
138
239
|
get isEmpty(): boolean {
|
|
139
240
|
const row = this.db
|
|
140
|
-
.prepare(
|
|
141
|
-
|
|
241
|
+
.prepare(
|
|
242
|
+
`SELECT COUNT(*) as count FROM ${CACHE_TABLE_NAME} WHERE namespace = ?`,
|
|
243
|
+
)
|
|
244
|
+
.get(this.namespace) as { count: number }
|
|
142
245
|
return row.count === 0
|
|
143
246
|
}
|
|
144
247
|
|
|
145
248
|
set(key: string, data: string): void {
|
|
249
|
+
const now = nextTimestamp()
|
|
146
250
|
const dataSize = Buffer.byteLength(data, 'utf8')
|
|
147
251
|
|
|
148
252
|
// Get existing size if any
|
|
149
253
|
const existingRow = this.db
|
|
150
|
-
.prepare(
|
|
151
|
-
|
|
254
|
+
.prepare(
|
|
255
|
+
`SELECT size FROM ${CACHE_TABLE_NAME} WHERE namespace = ? AND key = ?`,
|
|
256
|
+
)
|
|
257
|
+
.get(this.namespace, key) as { size: number } | undefined
|
|
152
258
|
const oldSize = existingRow?.size || 0
|
|
153
259
|
const newTotalSize = this.currentSize - oldSize + dataSize
|
|
154
260
|
|
|
@@ -159,9 +265,16 @@ export class Cache {
|
|
|
159
265
|
// Insert or update the cache entry
|
|
160
266
|
this.db
|
|
161
267
|
.prepare(
|
|
162
|
-
`INSERT
|
|
268
|
+
`INSERT INTO ${CACHE_TABLE_NAME} (namespace, key, data, size, last_accessed_at, updated_at)
|
|
269
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
270
|
+
ON CONFLICT(namespace, key)
|
|
271
|
+
DO UPDATE SET
|
|
272
|
+
data = excluded.data,
|
|
273
|
+
size = excluded.size,
|
|
274
|
+
last_accessed_at = excluded.last_accessed_at,
|
|
275
|
+
updated_at = excluded.updated_at`,
|
|
163
276
|
)
|
|
164
|
-
.run(key, data, dataSize)
|
|
277
|
+
.run(this.namespace, key, data, dataSize, now, now)
|
|
165
278
|
|
|
166
279
|
this.currentSize = this.currentSize - oldSize + dataSize
|
|
167
280
|
this.notifySubscribers(key, data)
|
|
@@ -170,12 +283,16 @@ export class Cache {
|
|
|
170
283
|
remove(key: string): boolean {
|
|
171
284
|
// Check if key exists and get its size
|
|
172
285
|
const row = this.db
|
|
173
|
-
.prepare(
|
|
174
|
-
|
|
286
|
+
.prepare(
|
|
287
|
+
`SELECT size FROM ${CACHE_TABLE_NAME} WHERE namespace = ? AND key = ?`,
|
|
288
|
+
)
|
|
289
|
+
.get(this.namespace, key) as { size: number } | undefined
|
|
175
290
|
|
|
176
291
|
if (row) {
|
|
177
292
|
// Delete the key
|
|
178
|
-
this.db
|
|
293
|
+
this.db
|
|
294
|
+
.prepare(`DELETE FROM ${CACHE_TABLE_NAME} WHERE namespace = ? AND key = ?`)
|
|
295
|
+
.run(this.namespace, key)
|
|
179
296
|
|
|
180
297
|
this.currentSize -= row.size
|
|
181
298
|
this.notifySubscribers(key, undefined)
|
|
@@ -186,7 +303,9 @@ export class Cache {
|
|
|
186
303
|
}
|
|
187
304
|
|
|
188
305
|
clear(options?: { notifySubscribers: boolean }): void {
|
|
189
|
-
this.db
|
|
306
|
+
this.db
|
|
307
|
+
.prepare(`DELETE FROM ${CACHE_TABLE_NAME} WHERE namespace = ?`)
|
|
308
|
+
.run(this.namespace)
|
|
190
309
|
this.currentSize = 0
|
|
191
310
|
|
|
192
311
|
if (options?.notifySubscribers !== false) {
|
|
@@ -205,10 +324,14 @@ export class Cache {
|
|
|
205
324
|
}
|
|
206
325
|
|
|
207
326
|
private maintainCapacity(bytesToFree: number): void {
|
|
208
|
-
// Order by
|
|
327
|
+
// Order by oldest last-access time first to evict least-recently-used rows.
|
|
209
328
|
const rows = this.db
|
|
210
|
-
.prepare(
|
|
211
|
-
|
|
329
|
+
.prepare(
|
|
330
|
+
`SELECT key, size FROM ${CACHE_TABLE_NAME}
|
|
331
|
+
WHERE namespace = ?
|
|
332
|
+
ORDER BY last_accessed_at ASC`,
|
|
333
|
+
)
|
|
334
|
+
.all(this.namespace) as Array<{ key: string; size: number }>
|
|
212
335
|
|
|
213
336
|
let freedBytes = 0
|
|
214
337
|
const keysToRemove: string[] = []
|
|
@@ -224,9 +347,10 @@ export class Cache {
|
|
|
224
347
|
if (keysToRemove.length > 0) {
|
|
225
348
|
const placeholders = keysToRemove.map(() => '?').join(',')
|
|
226
349
|
const stmt = this.db.prepare(
|
|
227
|
-
`DELETE FROM ${
|
|
350
|
+
`DELETE FROM ${CACHE_TABLE_NAME}
|
|
351
|
+
WHERE namespace = ? AND key IN (${placeholders})`,
|
|
228
352
|
)
|
|
229
|
-
stmt.run(...(keysToRemove as [string, ...string[]]))
|
|
353
|
+
stmt.run(this.namespace, ...(keysToRemove as [string, ...string[]]))
|
|
230
354
|
this.currentSize -= freedBytes
|
|
231
355
|
}
|
|
232
356
|
}
|
|
@@ -324,7 +448,8 @@ export function withCache<Fn extends (...args: any[]) => Promise<any>>(
|
|
|
324
448
|
const validate = options?.validate || (() => true)
|
|
325
449
|
|
|
326
450
|
if (!functionCacheMap.has(fnKey)) {
|
|
327
|
-
|
|
451
|
+
const functionNamespace = `fn-${hashString(fnKey)}`
|
|
452
|
+
functionCacheMap.set(fnKey, new Cache({ namespace: functionNamespace }))
|
|
328
453
|
functionCacheData.set(fnKey, new Map())
|
|
329
454
|
}
|
|
330
455
|
|
package/src/apis/clipboard.tsx
CHANGED
|
@@ -12,6 +12,11 @@ const platform = process.platform
|
|
|
12
12
|
async function copyFileToClipboard(filePath: string): Promise<void> {
|
|
13
13
|
const absolutePath = path.resolve(filePath)
|
|
14
14
|
|
|
15
|
+
if (process.env.VITEST) {
|
|
16
|
+
logger.log(`📋 [VITEST] Skipping copy file to clipboard: ${filePath}`)
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
if (!fs.existsSync(absolutePath)) {
|
|
16
21
|
throw new Error(`File not found: ${absolutePath}`)
|
|
17
22
|
}
|
package/src/apis/oauth.tsx
CHANGED
|
@@ -444,11 +444,16 @@ export namespace OAuth {
|
|
|
444
444
|
<h1 id="status">Processing...</h1>
|
|
445
445
|
<div id="message"></div>
|
|
446
446
|
<script>
|
|
447
|
-
// Extract tokens from URL fragment
|
|
447
|
+
// Extract tokens from URL fragment (implicit flow) or query params (auth code flow)
|
|
448
448
|
const hash = window.location.hash.substring(1);
|
|
449
|
-
const
|
|
449
|
+
const hashParams = new URLSearchParams(hash);
|
|
450
|
+
const queryParams = new URLSearchParams(window.location.search);
|
|
451
|
+
|
|
452
|
+
// Use query params if we have a code (auth code flow), otherwise use hash (implicit flow)
|
|
453
|
+
const params = queryParams.get('code') ? queryParams : hashParams;
|
|
450
454
|
|
|
451
455
|
const data = {
|
|
456
|
+
code: params.get('code'),
|
|
452
457
|
access_token: params.get('access_token'),
|
|
453
458
|
id_token: params.get('id_token'),
|
|
454
459
|
expires_in: params.get('expires_in'),
|
|
@@ -458,6 +463,8 @@ export namespace OAuth {
|
|
|
458
463
|
error: params.get('error'),
|
|
459
464
|
error_description: params.get('error_description')
|
|
460
465
|
};
|
|
466
|
+
|
|
467
|
+
console.log('OAuth callback data:', data);
|
|
461
468
|
|
|
462
469
|
// Send tokens back to our server
|
|
463
470
|
fetch('/oauth/implicit-callback', {
|
|
@@ -499,6 +506,14 @@ export namespace OAuth {
|
|
|
499
506
|
req.on('end', () => {
|
|
500
507
|
try {
|
|
501
508
|
const data = JSON.parse(body)
|
|
509
|
+
|
|
510
|
+
logger.log('OAuth callback received data:', {
|
|
511
|
+
hasCode: !!data.code,
|
|
512
|
+
hasAccessToken: !!data.access_token,
|
|
513
|
+
receivedState: data.state,
|
|
514
|
+
expectedState: expectedState,
|
|
515
|
+
error: data.error,
|
|
516
|
+
})
|
|
502
517
|
|
|
503
518
|
if (data.error) {
|
|
504
519
|
res.writeHead(400, {
|
|
@@ -516,6 +531,10 @@ export namespace OAuth {
|
|
|
516
531
|
|
|
517
532
|
// Validate state
|
|
518
533
|
if (data.state !== expectedState) {
|
|
534
|
+
logger.error('OAuth state mismatch:', {
|
|
535
|
+
received: data.state,
|
|
536
|
+
expected: expectedState,
|
|
537
|
+
})
|
|
519
538
|
res.writeHead(400, {
|
|
520
539
|
'Content-Type': 'application/json',
|
|
521
540
|
})
|
|
@@ -546,6 +565,17 @@ export namespace OAuth {
|
|
|
546
565
|
scope: data.scope,
|
|
547
566
|
}
|
|
548
567
|
|
|
568
|
+
// For authorization code flow, return the code for token exchange
|
|
569
|
+
if (data.code) {
|
|
570
|
+
logger.log('Authorization code flow - returning code for token exchange')
|
|
571
|
+
resolve({
|
|
572
|
+
authorizationCode: data.code,
|
|
573
|
+
state: data.state,
|
|
574
|
+
})
|
|
575
|
+
return
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// For implicit flow, tokens come directly
|
|
549
579
|
// Store tokens in memory for later retrieval
|
|
550
580
|
this.implicitFlowTokens = tokens
|
|
551
581
|
|
|
@@ -554,9 +584,8 @@ export namespace OAuth {
|
|
|
554
584
|
.then(() => {
|
|
555
585
|
logger.log('Implicit flow tokens saved directly')
|
|
556
586
|
|
|
557
|
-
// Return the tokens (authorizationCode is a dummy value for compatibility)
|
|
558
587
|
resolve({
|
|
559
|
-
authorizationCode: '
|
|
588
|
+
authorizationCode: 'implicit_flow_complete',
|
|
560
589
|
accessToken: data.access_token,
|
|
561
590
|
idToken: data.id_token,
|
|
562
591
|
state: data.state,
|
package/src/build.tsx
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
|
-
import { execSync } from 'node:child_process'
|
|
4
3
|
import type { BunPlugin } from 'bun'
|
|
5
|
-
import * as swc from '@swc/core'
|
|
6
4
|
import { logger } from './logger'
|
|
7
5
|
import { getCommandsWithFiles, CommandWithFile } from './package-json'
|
|
8
6
|
import * as termcastApi from './index'
|
|
@@ -43,13 +41,23 @@ export const aliasPlugin: BunPlugin = {
|
|
|
43
41
|
|
|
44
42
|
// Alias @raycast/api to termcast using namespace
|
|
45
43
|
build.onResolve({ filter: /@raycast\/api/ }, () => {
|
|
46
|
-
logger.log('Resolving @raycast/api to termcast')
|
|
44
|
+
// logger.log('Resolving @raycast/api to termcast')
|
|
47
45
|
return {
|
|
48
46
|
path: 'termcast',
|
|
49
47
|
namespace: GLOBALS_NAMESPACE,
|
|
50
48
|
}
|
|
51
49
|
})
|
|
52
50
|
|
|
51
|
+
// Alias @raycast/utils to our fork with termcast OAuth proxy URLs
|
|
52
|
+
build.onResolve({ filter: /@raycast\/utils/ }, () => {
|
|
53
|
+
// logger.log('Resolving @raycast/utils to termcast fork')
|
|
54
|
+
return {
|
|
55
|
+
path: require.resolve('@termcast/utils'),
|
|
56
|
+
|
|
57
|
+
// external: true,
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
|
|
53
61
|
// Resolve external packages to globals namespace
|
|
54
62
|
build.onResolve({ filter: /^termcast/ }, (args) => {
|
|
55
63
|
return {
|
|
@@ -180,62 +188,19 @@ export const aliasPlugin: BunPlugin = {
|
|
|
180
188
|
},
|
|
181
189
|
}
|
|
182
190
|
|
|
183
|
-
// React Refresh transform plugin for hot reloading using SWC (Rust-based, ~20x faster than Babel)
|
|
184
|
-
// Transforms extension source files to inject $RefreshReg$ and $RefreshSig$ calls
|
|
185
|
-
export const reactRefreshPlugin: BunPlugin = {
|
|
186
|
-
name: 'react-refresh-transform',
|
|
187
|
-
async setup(build) {
|
|
188
|
-
build.onLoad({ filter: /\.[tj]sx?$/ }, async (args) => {
|
|
189
|
-
// Skip node_modules
|
|
190
|
-
if (args.path.includes('node_modules')) {
|
|
191
|
-
return undefined
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const code = await Bun.file(args.path).text()
|
|
195
|
-
|
|
196
|
-
const isTypeScript =
|
|
197
|
-
args.path.endsWith('.ts') || args.path.endsWith('.tsx')
|
|
198
|
-
const hasJsx = args.path.endsWith('.tsx') || args.path.endsWith('.jsx')
|
|
199
|
-
|
|
200
|
-
const result = await swc.transform(code, {
|
|
201
|
-
filename: args.path,
|
|
202
|
-
jsc: {
|
|
203
|
-
parser: isTypeScript
|
|
204
|
-
? {
|
|
205
|
-
syntax: 'typescript',
|
|
206
|
-
tsx: hasJsx,
|
|
207
|
-
}
|
|
208
|
-
: {
|
|
209
|
-
syntax: 'ecmascript',
|
|
210
|
-
jsx: hasJsx,
|
|
211
|
-
},
|
|
212
|
-
transform: {
|
|
213
|
-
react: {
|
|
214
|
-
development: true,
|
|
215
|
-
refresh: true, // Built-in React Refresh support in SWC
|
|
216
|
-
runtime: 'automatic',
|
|
217
|
-
},
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
sourceMaps: 'inline',
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
if (!result?.code) {
|
|
224
|
-
return undefined
|
|
225
|
-
}
|
|
226
191
|
|
|
227
|
-
return {
|
|
228
|
-
contents: result.code,
|
|
229
|
-
loader: 'js', // SWC transforms JSX to JS
|
|
230
|
-
}
|
|
231
|
-
})
|
|
232
|
-
},
|
|
233
|
-
}
|
|
234
192
|
|
|
235
193
|
interface BundledCommand extends CommandWithFile {
|
|
236
194
|
bundledPath: string
|
|
237
195
|
}
|
|
238
196
|
|
|
197
|
+
function sanitizeHotReloadBundle({ code }: { code: string }): string {
|
|
198
|
+
// Bun reactFastRefresh can emit invalid self-redeclarations like:
|
|
199
|
+
// `var Component = Component;`
|
|
200
|
+
// which throws in ESM during import. Strip those lines in hot-reload bundles.
|
|
201
|
+
return code.replace(/^var\s+([A-Za-z_$][\w$]*)\s*=\s*\1;\s*$/gm, '')
|
|
202
|
+
}
|
|
203
|
+
|
|
239
204
|
export interface BuildResult {
|
|
240
205
|
commands: BundledCommand[]
|
|
241
206
|
bundleDir: string
|
|
@@ -276,20 +241,17 @@ export async function buildExtensionCommands({
|
|
|
276
241
|
|
|
277
242
|
logger.log(`Building ${entrypoints.length} commands...`)
|
|
278
243
|
|
|
279
|
-
const plugins = [aliasPlugin, swiftLoaderPlugin]
|
|
280
|
-
if (hotReload) {
|
|
281
|
-
plugins.push(reactRefreshPlugin)
|
|
282
|
-
}
|
|
244
|
+
const plugins: BunPlugin[] = [aliasPlugin, swiftLoaderPlugin]
|
|
283
245
|
|
|
284
246
|
const result = await Bun.build({
|
|
285
247
|
entrypoints,
|
|
286
248
|
outdir: bundleDir,
|
|
287
249
|
target: target || (format === 'cjs' ? 'node' : 'bun'),
|
|
288
250
|
format,
|
|
289
|
-
// external: [],
|
|
290
251
|
plugins,
|
|
291
252
|
naming: '[name].js',
|
|
292
253
|
throw: false,
|
|
254
|
+
reactFastRefresh: hotReload,
|
|
293
255
|
})
|
|
294
256
|
|
|
295
257
|
if (!result.success) {
|
|
@@ -299,6 +261,21 @@ export async function buildExtensionCommands({
|
|
|
299
261
|
throw new Error(`Build failed: ${errorMessage}`)
|
|
300
262
|
}
|
|
301
263
|
|
|
264
|
+
if (hotReload) {
|
|
265
|
+
for (const output of result.outputs) {
|
|
266
|
+
const outputPath = output.path
|
|
267
|
+
if (!outputPath.endsWith('.js')) {
|
|
268
|
+
continue
|
|
269
|
+
}
|
|
270
|
+
const code = fs.readFileSync(outputPath, 'utf-8')
|
|
271
|
+
const sanitizedCode = sanitizeHotReloadBundle({ code })
|
|
272
|
+
if (sanitizedCode === code) {
|
|
273
|
+
continue
|
|
274
|
+
}
|
|
275
|
+
fs.writeFileSync(outputPath, sanitizedCode)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
302
279
|
// Map outputs back to commands
|
|
303
280
|
const bundledCommands: BundledCommand[] = commandsData.commands.map(
|
|
304
281
|
(command) => {
|