preact-missing-hooks 3.1.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.husky/pre-commit +1 -0
- package/.husky/pre-push +1 -0
- package/.prettierignore +3 -0
- package/.prettierrc +6 -0
- package/Readme.md +333 -137
- package/dist/entry.cjs +21 -0
- package/dist/entry.js +2 -0
- package/dist/entry.js.map +1 -0
- package/dist/entry.modern.mjs +2 -0
- package/dist/entry.modern.mjs.map +1 -0
- package/dist/entry.module.js +2 -0
- package/dist/entry.module.js.map +1 -0
- package/dist/entry.umd.js +2 -0
- package/dist/entry.umd.js.map +1 -0
- package/dist/index.d.ts +14 -13
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.modern.mjs +2 -0
- package/dist/index.modern.mjs.map +1 -0
- package/dist/index.module.js +1 -1
- package/dist/index.module.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/indexedDB/dbController.d.ts +2 -2
- package/dist/indexedDB/index.d.ts +6 -6
- package/dist/indexedDB/openDB.d.ts +1 -1
- package/dist/indexedDB/tableController.d.ts +1 -1
- package/dist/indexedDB/types.d.ts +1 -2
- package/dist/react.js +1 -0
- package/dist/react.modern.mjs +1 -0
- package/dist/react.module.js +1 -0
- package/dist/react.umd.js +1 -0
- package/dist/useEventBus.d.ts +1 -1
- package/dist/useIndexedDB.d.ts +3 -3
- package/dist/useLLMMetadata.d.ts +71 -0
- package/dist/useMutationObserver.d.ts +1 -1
- package/dist/useNetworkState.d.ts +3 -3
- package/dist/usePreferredTheme.d.ts +1 -1
- package/dist/useRageClick.d.ts +1 -1
- package/dist/useThreadedWorker.d.ts +1 -1
- package/dist/useTransition.d.ts +4 -1
- package/dist/useWorkerNotifications.d.ts +1 -1
- package/dist/useWrappedChildren.d.ts +3 -3
- package/docs/README.md +111 -0
- package/docs/index.html +58 -20
- package/docs/main.js +49 -0
- package/eslint.config.mjs +10 -0
- package/package.json +60 -6
- package/scripts/generate-entry.cjs +34 -0
- package/src/index.ts +14 -13
- package/src/indexedDB/dbController.ts +101 -92
- package/src/indexedDB/index.ts +16 -11
- package/src/indexedDB/openDB.ts +49 -49
- package/src/indexedDB/requestToPromise.ts +17 -16
- package/src/indexedDB/tableController.ts +331 -257
- package/src/indexedDB/types.ts +35 -35
- package/src/useClipboard.ts +99 -97
- package/src/useEventBus.ts +39 -36
- package/src/useIndexedDB.ts +111 -111
- package/src/useLLMMetadata.ts +418 -0
- package/src/useMutationObserver.ts +26 -26
- package/src/useNetworkState.ts +124 -122
- package/src/usePreferredTheme.ts +68 -68
- package/src/useRageClick.ts +103 -103
- package/src/useThreadedWorker.ts +165 -165
- package/src/useTransition.ts +22 -19
- package/src/useWasmCompute.ts +209 -204
- package/src/useWebRTCIP.ts +181 -176
- package/src/useWorkerNotifications.ts +28 -20
- package/src/useWrappedChildren.ts +72 -58
- package/tests/preact-as-react.ts +5 -0
- package/tests/react-adapter.tsx +12 -0
- package/tests/setup-react.ts +4 -0
- package/tests/useClipboard.test.tsx +4 -2
- package/tests/useLLMMetadata.test.tsx +149 -0
- package/tests/useThreadedWorker.test.tsx +3 -1
- package/tests/useWasmCompute.test.tsx +1 -1
- package/tests/useWebRTCIP.test.tsx +3 -1
- package/vite.config.ts +11 -4
- package/vitest.config.preact.ts +21 -0
- package/vitest.config.react.ts +36 -0
- package/vitest.workspace.ts +6 -0
package/docs/index.html
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
{
|
|
9
9
|
"imports": {
|
|
10
10
|
"preact": "https://esm.sh/preact@10",
|
|
11
|
-
"preact/hooks": "https://esm.sh/preact@10/hooks"
|
|
11
|
+
"preact/hooks": "https://esm.sh/preact@10/hooks",
|
|
12
|
+
"preact/compat": "https://esm.sh/preact@10/compat"
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
</script>
|
|
@@ -25,6 +26,7 @@
|
|
|
25
26
|
--surface2: #222228;
|
|
26
27
|
--border: #2e2e36;
|
|
27
28
|
--text: #e4e4e7;
|
|
29
|
+
--text2: #d4d4d8;
|
|
28
30
|
--textMuted: #a1a1aa;
|
|
29
31
|
--accent: #7c3aed;
|
|
30
32
|
--accentDim: rgba(124, 58, 237, 0.15);
|
|
@@ -38,24 +40,39 @@
|
|
|
38
40
|
* {
|
|
39
41
|
box-sizing: border-box;
|
|
40
42
|
}
|
|
43
|
+
html {
|
|
44
|
+
overflow-x: hidden;
|
|
45
|
+
}
|
|
41
46
|
body {
|
|
42
47
|
margin: 0;
|
|
43
|
-
font-family:
|
|
48
|
+
font-family: "DM Sans", system-ui, sans-serif;
|
|
44
49
|
background: var(--bg);
|
|
45
50
|
color: var(--text);
|
|
46
51
|
line-height: 1.5;
|
|
47
52
|
min-height: 100vh;
|
|
48
53
|
}
|
|
49
54
|
.page-header {
|
|
50
|
-
padding:
|
|
55
|
+
padding: 2.5rem 1.5rem;
|
|
51
56
|
text-align: center;
|
|
52
57
|
border-bottom: 1px solid var(--border);
|
|
58
|
+
background: linear-gradient(
|
|
59
|
+
180deg,
|
|
60
|
+
rgba(124, 58, 237, 0.04) 0%,
|
|
61
|
+
transparent 100%
|
|
62
|
+
);
|
|
53
63
|
}
|
|
54
64
|
.page-header h1 {
|
|
55
65
|
margin: 0;
|
|
56
|
-
font-size: 1.
|
|
66
|
+
font-size: 1.85rem;
|
|
57
67
|
font-weight: 700;
|
|
58
|
-
letter-spacing: -0.
|
|
68
|
+
letter-spacing: -0.03em;
|
|
69
|
+
color: var(--text2);
|
|
70
|
+
}
|
|
71
|
+
.page-header .subtitle {
|
|
72
|
+
margin: 0.5rem 0 0;
|
|
73
|
+
color: var(--textMuted);
|
|
74
|
+
font-size: 0.95rem;
|
|
75
|
+
font-weight: 400;
|
|
59
76
|
}
|
|
60
77
|
.page-header p {
|
|
61
78
|
margin: 0.5rem 0 0;
|
|
@@ -63,39 +80,50 @@
|
|
|
63
80
|
font-size: 0.95rem;
|
|
64
81
|
}
|
|
65
82
|
.container {
|
|
66
|
-
max-width:
|
|
83
|
+
max-width: min(1320px, 96vw);
|
|
67
84
|
margin: 0 auto;
|
|
68
|
-
padding: 1.5rem;
|
|
85
|
+
padding: 1.75rem 1.5rem;
|
|
69
86
|
}
|
|
70
87
|
.hook-section {
|
|
71
|
-
margin-bottom:
|
|
88
|
+
margin-bottom: 3.5rem;
|
|
89
|
+
padding-bottom: 2.5rem;
|
|
90
|
+
border-bottom: 1px solid var(--border);
|
|
91
|
+
}
|
|
92
|
+
.hook-section:last-child {
|
|
93
|
+
border-bottom: none;
|
|
72
94
|
}
|
|
73
95
|
.hook-section h2 {
|
|
74
96
|
margin: 0 0 0.5rem;
|
|
75
97
|
font-size: 1.35rem;
|
|
76
98
|
font-weight: 600;
|
|
77
99
|
color: var(--text);
|
|
100
|
+
letter-spacing: -0.02em;
|
|
78
101
|
}
|
|
79
102
|
.flow {
|
|
80
103
|
display: inline-block;
|
|
104
|
+
max-width: 100%;
|
|
81
105
|
margin-bottom: 0.5rem;
|
|
82
|
-
padding: 0.
|
|
106
|
+
padding: 0.35rem 0.7rem;
|
|
83
107
|
font-size: 0.75rem;
|
|
84
|
-
font-family:
|
|
108
|
+
font-family: "JetBrains Mono", monospace;
|
|
85
109
|
color: var(--accent);
|
|
86
110
|
background: var(--accentDim);
|
|
87
111
|
border-radius: var(--radiusSm);
|
|
112
|
+
white-space: pre-wrap;
|
|
113
|
+
word-break: break-word;
|
|
114
|
+
overflow-wrap: break-word;
|
|
88
115
|
}
|
|
89
116
|
.summary {
|
|
90
117
|
margin: 0 0 1rem;
|
|
91
118
|
font-size: 0.9rem;
|
|
92
119
|
color: var(--textMuted);
|
|
93
|
-
max-width:
|
|
120
|
+
max-width: 72ch;
|
|
121
|
+
line-height: 1.55;
|
|
94
122
|
}
|
|
95
123
|
.cards {
|
|
96
124
|
display: grid;
|
|
97
125
|
grid-template-columns: 1fr 1fr;
|
|
98
|
-
gap:
|
|
126
|
+
gap: 1.25rem;
|
|
99
127
|
}
|
|
100
128
|
@media (max-width: 800px) {
|
|
101
129
|
.cards {
|
|
@@ -107,6 +135,7 @@
|
|
|
107
135
|
border: 1px solid var(--border);
|
|
108
136
|
border-radius: var(--radius);
|
|
109
137
|
overflow: hidden;
|
|
138
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
110
139
|
}
|
|
111
140
|
.card-title {
|
|
112
141
|
padding: 0.5rem 0.75rem;
|
|
@@ -118,18 +147,24 @@
|
|
|
118
147
|
border-bottom: 1px solid var(--border);
|
|
119
148
|
}
|
|
120
149
|
.card-code {
|
|
121
|
-
padding: 0.75rem;
|
|
122
|
-
font-family:
|
|
150
|
+
padding: 0.75rem 1rem;
|
|
151
|
+
font-family: "JetBrains Mono", monospace;
|
|
123
152
|
font-size: 0.8rem;
|
|
124
|
-
line-height: 1.
|
|
153
|
+
line-height: 1.5;
|
|
125
154
|
color: var(--textMuted);
|
|
126
155
|
background: #0d0d0f;
|
|
127
|
-
|
|
128
|
-
|
|
156
|
+
white-space: pre-wrap;
|
|
157
|
+
word-break: break-word;
|
|
158
|
+
overflow-wrap: break-word;
|
|
159
|
+
overflow-x: hidden;
|
|
160
|
+
min-width: 0;
|
|
129
161
|
}
|
|
130
162
|
.card-live {
|
|
131
163
|
padding: 1rem;
|
|
132
164
|
min-height: 80px;
|
|
165
|
+
min-width: 0;
|
|
166
|
+
overflow-wrap: break-word;
|
|
167
|
+
word-break: break-word;
|
|
133
168
|
}
|
|
134
169
|
.card-live .status {
|
|
135
170
|
font-size: 0.85rem;
|
|
@@ -215,11 +250,13 @@
|
|
|
215
250
|
.wasm-flow-node {
|
|
216
251
|
padding: 0.3rem 0.5rem;
|
|
217
252
|
font-size: 0.7rem;
|
|
218
|
-
font-family:
|
|
253
|
+
font-family: "JetBrains Mono", monospace;
|
|
219
254
|
border-radius: 4px;
|
|
220
255
|
border: 1px solid var(--border);
|
|
221
256
|
color: var(--textMuted);
|
|
222
|
-
transition:
|
|
257
|
+
transition:
|
|
258
|
+
background 0.2s,
|
|
259
|
+
border-color 0.2s;
|
|
223
260
|
}
|
|
224
261
|
.wasm-flow-node.active {
|
|
225
262
|
border-color: var(--accent);
|
|
@@ -291,6 +328,7 @@
|
|
|
291
328
|
<body>
|
|
292
329
|
<header class="page-header">
|
|
293
330
|
<h1>Preact Missing Hooks</h1>
|
|
331
|
+
<p class="subtitle">React-like hooks for Preact — demo & usage</p>
|
|
294
332
|
</header>
|
|
295
333
|
<main class="container" id="root"></main>
|
|
296
334
|
<script type="module" src="./main.js"></script>
|
package/docs/main.js
CHANGED
|
@@ -18,6 +18,7 @@ const {
|
|
|
18
18
|
useWebRTCIP,
|
|
19
19
|
useWasmCompute,
|
|
20
20
|
useWorkerNotifications,
|
|
21
|
+
useLLMMetadata,
|
|
21
22
|
} = await import(
|
|
22
23
|
isLocal ? '../dist/index.module.js' : 'https://unpkg.com/preact-missing-hooks/dist/index.module.js'
|
|
23
24
|
);
|
|
@@ -316,6 +317,47 @@ function DemoWorkerNotifications() {
|
|
|
316
317
|
);
|
|
317
318
|
}
|
|
318
319
|
|
|
320
|
+
function DemoLLMMetadata() {
|
|
321
|
+
const [route, setRoute] = useState('/');
|
|
322
|
+
useLLMMetadata({
|
|
323
|
+
route,
|
|
324
|
+
mode: 'manual',
|
|
325
|
+
title: 'Preact Missing Hooks — Demo',
|
|
326
|
+
description: 'Live demo of useLLMMetadata and other hooks.',
|
|
327
|
+
tags: ['preact', 'hooks', 'demo'],
|
|
328
|
+
});
|
|
329
|
+
const scriptEl = typeof document !== 'undefined' ? document.querySelector('script[data-llm="true"]') : null;
|
|
330
|
+
const rawText = scriptEl?.textContent ?? '';
|
|
331
|
+
const payload = rawText ? (() => { try { return JSON.parse(rawText); } catch (_) { return null; } })() : null;
|
|
332
|
+
const llmFormatted = payload ? JSON.stringify(payload, null, 2) : rawText || '(no script yet)';
|
|
333
|
+
return h('div', {},
|
|
334
|
+
h('div', { style: { marginBottom: '0.5rem' } }, [
|
|
335
|
+
h('button', { onClick: () => setRoute('/') }, 'Route: /'),
|
|
336
|
+
h('button', { onClick: () => setRoute('/blog') }, 'Route: /blog'),
|
|
337
|
+
h('button', { onClick: () => setRoute('/docs') }, 'Route: /docs'),
|
|
338
|
+
]),
|
|
339
|
+
h('div', { class: 'status', style: { fontSize: '0.8rem', wordBreak: 'break-all', marginBottom: '0.5rem' } },
|
|
340
|
+
payload
|
|
341
|
+
? 'Injected: ' + (payload.title || payload.route) + (payload.generatedAt ? ' @ ' + payload.generatedAt : '')
|
|
342
|
+
: 'Check <head> for <script type="application/llm+json" data-llm="true">'
|
|
343
|
+
),
|
|
344
|
+
h('div', { style: { marginTop: '0.5rem' } }, [
|
|
345
|
+
h('div', { style: { fontSize: '0.75rem', fontWeight: '600', marginBottom: '0.25rem', color: 'var(--text2)' } }, 'llm.txt (full payload below):'),
|
|
346
|
+
h('pre', {
|
|
347
|
+
class: 'card-code',
|
|
348
|
+
style: {
|
|
349
|
+
maxHeight: '12rem',
|
|
350
|
+
overflow: 'auto',
|
|
351
|
+
margin: 0,
|
|
352
|
+
fontSize: '0.7rem',
|
|
353
|
+
whiteSpace: 'pre-wrap',
|
|
354
|
+
wordBreak: 'break-all',
|
|
355
|
+
},
|
|
356
|
+
}, llmFormatted),
|
|
357
|
+
])
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
|
|
319
361
|
// ——— Page data: heading, flow, summary, code, LiveComponent ———
|
|
320
362
|
|
|
321
363
|
const HOOKS = [
|
|
@@ -410,6 +452,13 @@ const HOOKS = [
|
|
|
410
452
|
code: `const stats = useWorkerNotifications(worker, { maxHistory: 100 });\n// stats.progress, stats.runningTasks, stats.throughputPerSecond, ...`,
|
|
411
453
|
Live: DemoWorkerNotifications,
|
|
412
454
|
},
|
|
455
|
+
{
|
|
456
|
+
name: 'useLLMMetadata',
|
|
457
|
+
flow: 'Component → useLLMMetadata({ route, mode, title?, ... } | null) → <script type="application/llm+json" data-llm="true"> in <head>',
|
|
458
|
+
summary: 'Injects AI-readable metadata into the document head on route change. Manual mode uses config; auto-extract uses document.title, visible h1/h2, first 3 <p>. Accepts null/undefined (minimal payload with route "/"). SSR-safe, cacheable.',
|
|
459
|
+
code: `useLLMMetadata({ route: pathname, mode: 'manual', title: 'My Page', tags: ['app'] });\n// useLLMMetadata(null) is safe → minimal payload with route "/"`,
|
|
460
|
+
Live: DemoLLMMetadata,
|
|
461
|
+
},
|
|
413
462
|
];
|
|
414
463
|
|
|
415
464
|
function App() {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import eslint from "@eslint/js";
|
|
2
|
+
import { defineConfig } from "eslint/config";
|
|
3
|
+
import tseslint from "typescript-eslint";
|
|
4
|
+
import prettier from "eslint-config-prettier";
|
|
5
|
+
|
|
6
|
+
export default defineConfig(
|
|
7
|
+
eslint.configs.recommended,
|
|
8
|
+
tseslint.configs.recommended,
|
|
9
|
+
prettier
|
|
10
|
+
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "preact-missing-hooks",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "A lightweight, extendable collection of missing React-like hooks for Preact — plus fresh, powerful new ones designed specifically for modern Preact apps.",
|
|
5
5
|
"author": "Prakhar Dubey",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,8 +11,11 @@
|
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
|
-
"import":
|
|
15
|
-
|
|
14
|
+
"import": {
|
|
15
|
+
"react": "./dist/react.module.js",
|
|
16
|
+
"default": "./dist/index.module.js"
|
|
17
|
+
},
|
|
18
|
+
"require": "./dist/entry.cjs"
|
|
16
19
|
},
|
|
17
20
|
"./useTransition": {
|
|
18
21
|
"types": "./dist/useTransition.d.ts",
|
|
@@ -78,16 +81,47 @@
|
|
|
78
81
|
"types": "./dist/useWorkerNotifications.d.ts",
|
|
79
82
|
"import": "./dist/useWorkerNotifications.module.js",
|
|
80
83
|
"require": "./dist/useWorkerNotifications.js"
|
|
84
|
+
},
|
|
85
|
+
"./react": {
|
|
86
|
+
"types": "./dist/index.d.ts",
|
|
87
|
+
"import": "./dist/react.module.js",
|
|
88
|
+
"require": "./dist/react.js"
|
|
81
89
|
}
|
|
82
90
|
},
|
|
83
91
|
"scripts": {
|
|
84
|
-
"build": "microbundle",
|
|
92
|
+
"build": "microbundle --alias react=preact/compat && npm run build:react && node scripts/generate-entry.cjs",
|
|
93
|
+
"build:react": "microbundle -i src/index.ts -o dist/react.js --alias preact=react,preact/hooks=react --no-sourcemap",
|
|
85
94
|
"dev": "microbundle watch",
|
|
86
95
|
"prepublishOnly": "npm run build",
|
|
87
96
|
"test": "vitest run",
|
|
97
|
+
"test:preact": "vitest run --project preact",
|
|
98
|
+
"test:react": "vitest run --project react",
|
|
88
99
|
"type-check": "tsc --noEmit",
|
|
89
|
-
"demo": "npx serve -l 5000"
|
|
100
|
+
"demo": "npx serve -l 5000",
|
|
101
|
+
"lint": "eslint src",
|
|
102
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
|
|
103
|
+
"format:check": "prettier --check \"src/**/*.{ts,tsx,json,md}\"",
|
|
104
|
+
"prepare": "husky",
|
|
105
|
+
"size": "npm run build && size-limit"
|
|
90
106
|
},
|
|
107
|
+
"size-limit": [
|
|
108
|
+
{
|
|
109
|
+
"path": "dist/index.module.js",
|
|
110
|
+
"limit": "20 KB"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"path": "dist/index.js",
|
|
114
|
+
"limit": "20 KB"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"path": "dist/react.module.js",
|
|
118
|
+
"limit": "20 KB"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"path": "dist/react.js",
|
|
122
|
+
"limit": "20 KB"
|
|
123
|
+
}
|
|
124
|
+
],
|
|
91
125
|
"keywords": [
|
|
92
126
|
"preact",
|
|
93
127
|
"hooks",
|
|
@@ -114,16 +148,36 @@
|
|
|
114
148
|
"preact": ">=10.0.0"
|
|
115
149
|
},
|
|
116
150
|
"devDependencies": {
|
|
151
|
+
"@eslint/js": "^9.15.0",
|
|
152
|
+
"@size-limit/file": "^11.2.0",
|
|
117
153
|
"@testing-library/jest-dom": "^6.6.3",
|
|
118
154
|
"@testing-library/preact": "^3.2.4",
|
|
155
|
+
"@testing-library/react": "^16.0.1",
|
|
119
156
|
"@types/jest": "^29.5.14",
|
|
157
|
+
"eslint": "^9.15.0",
|
|
158
|
+
"eslint-config-prettier": "^9.1.0",
|
|
120
159
|
"fake-indexeddb": "^6.0.2",
|
|
160
|
+
"husky": "^9.1.7",
|
|
121
161
|
"jsdom": "^26.1.0",
|
|
122
162
|
"microbundle": "^0.15.1",
|
|
163
|
+
"prettier": "^3.3.3",
|
|
164
|
+
"react": "^18.3.1",
|
|
165
|
+
"react-dom": "^18.3.1",
|
|
166
|
+
"size-limit": "^11.2.0",
|
|
123
167
|
"typescript": "^5.8.3",
|
|
168
|
+
"typescript-eslint": "^8.15.0",
|
|
124
169
|
"vitest": "^3.1.4"
|
|
125
170
|
},
|
|
126
171
|
"peerDependencies": {
|
|
127
|
-
"preact": ">=10.0.0"
|
|
172
|
+
"preact": ">=10.0.0",
|
|
173
|
+
"react": ">=17.0.0"
|
|
174
|
+
},
|
|
175
|
+
"peerDependenciesMeta": {
|
|
176
|
+
"preact": {
|
|
177
|
+
"optional": true
|
|
178
|
+
},
|
|
179
|
+
"react": {
|
|
180
|
+
"optional": true
|
|
181
|
+
}
|
|
128
182
|
}
|
|
129
183
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates dist/entry.cjs which auto-detects Preact vs React at runtime (CJS only).
|
|
3
|
+
* Run after build so dist/index.js and dist/react.js exist.
|
|
4
|
+
*/
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
|
|
8
|
+
const content = `"use strict";
|
|
9
|
+
/**
|
|
10
|
+
* Auto-detect Preact vs React and re-export the matching build.
|
|
11
|
+
* Used for require('preact-missing-hooks') in Node / CJS bundlers.
|
|
12
|
+
*/
|
|
13
|
+
function detect() {
|
|
14
|
+
try {
|
|
15
|
+
require.resolve("preact");
|
|
16
|
+
return require("./index.js");
|
|
17
|
+
} catch (_) {
|
|
18
|
+
try {
|
|
19
|
+
require.resolve("react");
|
|
20
|
+
return require("./react.js");
|
|
21
|
+
} catch (_) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
"preact-missing-hooks: Install either \\"preact\\" or \\"react\\" in your project."
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
module.exports = detect();
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const outPath = path.join(__dirname, "..", "dist", "entry.cjs");
|
|
32
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
33
|
+
fs.writeFileSync(outPath, content, "utf8");
|
|
34
|
+
console.log("Generated dist/entry.cjs");
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
11
|
-
export * from
|
|
12
|
-
export * from
|
|
13
|
-
export * from
|
|
1
|
+
export * from "./useTransition";
|
|
2
|
+
export * from "./useMutationObserver";
|
|
3
|
+
export * from "./useEventBus";
|
|
4
|
+
export * from "./useWrappedChildren";
|
|
5
|
+
export * from "./usePreferredTheme";
|
|
6
|
+
export * from "./useNetworkState";
|
|
7
|
+
export * from "./useClipboard";
|
|
8
|
+
export * from "./useRageClick";
|
|
9
|
+
export * from "./useThreadedWorker";
|
|
10
|
+
export * from "./useIndexedDB";
|
|
11
|
+
export * from "./useWebRTCIP";
|
|
12
|
+
export * from "./useWasmCompute";
|
|
13
|
+
export * from "./useWorkerNotifications";
|
|
14
|
+
export * from "./useLLMMetadata";
|
|
@@ -1,92 +1,101 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database controller: table(name), transaction(storeNames, mode, callback, options).
|
|
3
|
-
* @module indexedDB/dbController
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { IndexedDBConfig, TransactionOptions } from
|
|
7
|
-
import type { ITableController } from
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
*
|
|
32
|
-
* @param
|
|
33
|
-
* @
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Database controller: table(name), transaction(storeNames, mode, callback, options).
|
|
3
|
+
* @module indexedDB/dbController
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { IndexedDBConfig, TransactionOptions } from "./types";
|
|
7
|
+
import type { ITableController } from "./tableController";
|
|
8
|
+
import {
|
|
9
|
+
createTableController,
|
|
10
|
+
createTransactionTableController,
|
|
11
|
+
} from "./tableController";
|
|
12
|
+
|
|
13
|
+
/** Transaction context passed to the callback: provides table(name) bound to this transaction. */
|
|
14
|
+
export interface TransactionContext {
|
|
15
|
+
/** Returns a table controller bound to this transaction. Use for all ops inside the callback. */
|
|
16
|
+
table: (name: string) => ITableController;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Database controller built from an open IDBDatabase.
|
|
21
|
+
* Exposes table(name) and transaction(...).
|
|
22
|
+
*/
|
|
23
|
+
export interface IDBController {
|
|
24
|
+
/** Underlying IDBDatabase (read-only). */
|
|
25
|
+
readonly db: IDBDatabase;
|
|
26
|
+
/** Returns true if an object store with the given name exists. */
|
|
27
|
+
hasTable: (name: string) => boolean;
|
|
28
|
+
/** Returns a table controller for the given store (each op opens its own transaction). */
|
|
29
|
+
table: (name: string) => ITableController;
|
|
30
|
+
/**
|
|
31
|
+
* Runs a callback inside a single transaction. All operations in the callback use the same transaction.
|
|
32
|
+
* @param storeNames - Object store names to include in the transaction.
|
|
33
|
+
* @param mode - 'readonly' | 'readwrite'.
|
|
34
|
+
* @param callback - Async or sync function receiving { table(name) }. Return value is ignored; await all ops inside.
|
|
35
|
+
* @param options - Optional onSuccess/onError callbacks.
|
|
36
|
+
* @returns Promise that resolves when the transaction completes (after all requests and the callback).
|
|
37
|
+
*/
|
|
38
|
+
transaction: <T = void>(
|
|
39
|
+
storeNames: string[],
|
|
40
|
+
mode: IDBTransactionMode,
|
|
41
|
+
callback: (tx: TransactionContext) => T | Promise<T>,
|
|
42
|
+
options?: TransactionOptions
|
|
43
|
+
) => Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function withTransactionCallbacks(
|
|
47
|
+
promise: Promise<void>,
|
|
48
|
+
options?: TransactionOptions
|
|
49
|
+
): Promise<void> {
|
|
50
|
+
if (!options) return promise;
|
|
51
|
+
return promise
|
|
52
|
+
.then(() => options.onSuccess?.())
|
|
53
|
+
.catch((err: DOMException) => {
|
|
54
|
+
options.onError?.(err);
|
|
55
|
+
throw err;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Creates a database controller from an open IDBDatabase instance.
|
|
61
|
+
*/
|
|
62
|
+
export function createDBController(
|
|
63
|
+
db: IDBDatabase,
|
|
64
|
+
_config: IndexedDBConfig
|
|
65
|
+
): IDBController {
|
|
66
|
+
void _config; // Reserved for future config options
|
|
67
|
+
return {
|
|
68
|
+
get db(): IDBDatabase {
|
|
69
|
+
return db;
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
hasTable(name: string): boolean {
|
|
73
|
+
return db.objectStoreNames.contains(name);
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
table(name: string): ITableController {
|
|
77
|
+
return createTableController(db, name);
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
transaction<T = void>(
|
|
81
|
+
storeNames: string[],
|
|
82
|
+
mode: IDBTransactionMode,
|
|
83
|
+
callback: (tx: TransactionContext) => T | Promise<T>,
|
|
84
|
+
options?: TransactionOptions
|
|
85
|
+
): Promise<void> {
|
|
86
|
+
const tx = db.transaction(storeNames, mode);
|
|
87
|
+
const txContext: TransactionContext = {
|
|
88
|
+
table: (tableName: string) =>
|
|
89
|
+
createTransactionTableController(tx, tableName),
|
|
90
|
+
};
|
|
91
|
+
const txPromise = new Promise<void>((resolve, reject) => {
|
|
92
|
+
tx.oncomplete = () => resolve();
|
|
93
|
+
tx.onerror = () =>
|
|
94
|
+
reject(tx.error ?? new DOMException("Transaction failed"));
|
|
95
|
+
});
|
|
96
|
+
const callbackResult = callback(txContext);
|
|
97
|
+
const promise = Promise.resolve(callbackResult).then(() => txPromise);
|
|
98
|
+
return withTransactionCallbacks(promise, options);
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
package/src/indexedDB/index.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* IndexedDB hook system – public API.
|
|
3
|
-
* @module indexedDB
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export type {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
/**
|
|
2
|
+
* IndexedDB hook system – public API.
|
|
3
|
+
* @module indexedDB
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type {
|
|
7
|
+
IndexedDBConfig,
|
|
8
|
+
TableSchema,
|
|
9
|
+
OperationCallbacks,
|
|
10
|
+
TransactionOptions,
|
|
11
|
+
} from "./types";
|
|
12
|
+
export { requestToPromise } from "./requestToPromise";
|
|
13
|
+
export type { ITableController } from "./tableController";
|
|
14
|
+
export type { IDBController, TransactionContext } from "./dbController";
|
|
15
|
+
export { createDBController } from "./dbController";
|
|
16
|
+
export { openDB } from "./openDB";
|