@maiyunnet/kebab 9.14.2 → 9.15.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/doc/kebab-rag.md +381 -559
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/core.d.ts +2 -0
- package/lib/core.js +21 -6
- package/lib/crypto.js +1 -1
- package/lib/fs.js +1 -2
- package/lib/kv.d.ts +5 -0
- package/lib/kv.js +21 -1
- package/lib/net/formdata.d.ts +2 -81
- package/lib/net/formdata.js +2 -164
- package/lib/net.js +16 -2
- package/lib/ratelimit.js +6 -6
- package/lib/scan.js +18 -5
- package/lib/session.js +2 -0
- package/lib/text.d.ts +6 -0
- package/lib/text.js +39 -6
- package/lib/undici/response.js +0 -2
- package/lib/undici.js +17 -2
- package/package.json +1 -1
- package/sys/child.js +0 -8
- package/sys/ctr.d.ts +6 -0
- package/sys/master.js +158 -48
- package/sys/route.d.ts +6 -0
- package/sys/route.js +87 -25
- package/www/example/ctr/test.js +5 -3
- package/www/example/stc/view/hello.page.js +1 -1
- package/www/example/stc/view/hello.page.tsx +2 -2
- package/www/example/stc/view/react-router.page.js +4 -4
- package/www/example/stc/view/react-router.page.tsx +15 -16
- package/www/example/stc/view/react.page.js +7 -7
- package/www/example/stc/view/react.page.tsx +27 -22
|
@@ -59,7 +59,7 @@ interface IProps {
|
|
|
59
59
|
// ─── 页面内部组件(仅本页演示使用,无需提取到 lib/)────────────────────────────
|
|
60
60
|
|
|
61
61
|
/** --- 卡片容器 --- */
|
|
62
|
-
function Card({ children, className = '' }: { 'children': ReactNode; 'className'?: string }) {
|
|
62
|
+
function Card({ children, className = '' }: { 'children': ReactNode; 'className'?: string; }) {
|
|
63
63
|
return (
|
|
64
64
|
<div className={`bg-white rounded-xl shadow-sm border border-slate-200 p-6 ${className}`}>
|
|
65
65
|
{children}
|
|
@@ -75,7 +75,7 @@ function Badge({ children, variant = 'default' }: {
|
|
|
75
75
|
const styles = {
|
|
76
76
|
'default': 'bg-blue-100 text-blue-700',
|
|
77
77
|
'success': 'bg-green-100 text-green-700',
|
|
78
|
-
'warn':
|
|
78
|
+
'warn': 'bg-amber-100 text-amber-700',
|
|
79
79
|
};
|
|
80
80
|
return (
|
|
81
81
|
<span className={`inline-flex px-2.5 py-0.5 rounded-md text-xs font-semibold ${styles[variant]}`}>
|
|
@@ -137,13 +137,13 @@ function RouterAbout() {
|
|
|
137
137
|
<p className="text-slate-500 text-xs mb-3">useNavigate() programmatic navigation (without Link component):</p>
|
|
138
138
|
<div className="flex gap-2">
|
|
139
139
|
<button
|
|
140
|
-
onClick={() => navigate('/')}
|
|
140
|
+
onClick={() => { Promise.resolve(navigate('/')).catch(() => {}); }}
|
|
141
141
|
className="inline-flex items-center px-3 py-1.5 rounded-lg border border-slate-300 hover:bg-slate-50 text-slate-700 text-xs font-medium cursor-pointer"
|
|
142
142
|
>
|
|
143
143
|
← Back to /
|
|
144
144
|
</button>
|
|
145
145
|
<button
|
|
146
|
-
onClick={() => navigate('/user/99')}
|
|
146
|
+
onClick={() => { Promise.resolve(navigate('/user/99')).catch(() => {}); }}
|
|
147
147
|
className="inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-500 hover:bg-blue-600 text-white text-xs font-medium cursor-pointer"
|
|
148
148
|
>
|
|
149
149
|
→ /user/99
|
|
@@ -155,7 +155,7 @@ function RouterAbout() {
|
|
|
155
155
|
|
|
156
156
|
/** --- 路由 User 动态参数页 --- */
|
|
157
157
|
function RouterUser() {
|
|
158
|
-
const { id } = useParams<{ 'id': string }>();
|
|
158
|
+
const { id } = useParams<{ 'id': string; }>();
|
|
159
159
|
const navigate = useNavigate();
|
|
160
160
|
return (
|
|
161
161
|
<div>
|
|
@@ -166,7 +166,7 @@ function RouterUser() {
|
|
|
166
166
|
useParams() dynamic segment: <code className="bg-slate-100 px-1 rounded">id = "{id}"</code>
|
|
167
167
|
</p>
|
|
168
168
|
<button
|
|
169
|
-
onClick={() => navigate('/')}
|
|
169
|
+
onClick={() => { Promise.resolve(navigate('/')).catch(() => {}); }}
|
|
170
170
|
className="inline-flex items-center px-3 py-1.5 rounded-lg border border-slate-300 hover:bg-slate-50 text-slate-700 text-xs font-medium cursor-pointer"
|
|
171
171
|
>
|
|
172
172
|
← Back to /
|
|
@@ -195,7 +195,7 @@ function ShadcnDemo() {
|
|
|
195
195
|
const agreeId = useId();
|
|
196
196
|
const newsletterId = useId();
|
|
197
197
|
|
|
198
|
-
function handleSubmit(e: React.
|
|
198
|
+
function handleSubmit(e: React.SyntheticEvent<HTMLFormElement>): void {
|
|
199
199
|
e.preventDefault();
|
|
200
200
|
setSubmitted(true);
|
|
201
201
|
}
|
|
@@ -226,7 +226,7 @@ function ShadcnDemo() {
|
|
|
226
226
|
type="text"
|
|
227
227
|
placeholder="Enter your username"
|
|
228
228
|
value={name}
|
|
229
|
-
onChange={e => setName(e.target.value)}
|
|
229
|
+
onChange={e => { setName(e.target.value); }}
|
|
230
230
|
/>
|
|
231
231
|
</div>
|
|
232
232
|
<div className="grid gap-1.5">
|
|
@@ -236,7 +236,7 @@ function ShadcnDemo() {
|
|
|
236
236
|
type="email"
|
|
237
237
|
placeholder="you@example.com"
|
|
238
238
|
value={email}
|
|
239
|
-
onChange={e => setEmail(e.target.value)}
|
|
239
|
+
onChange={e => { setEmail(e.target.value); }}
|
|
240
240
|
/>
|
|
241
241
|
</div>
|
|
242
242
|
</div>
|
|
@@ -290,7 +290,7 @@ function ShadcnDemo() {
|
|
|
290
290
|
2
|
|
291
291
|
)}</pre>
|
|
292
292
|
<button
|
|
293
|
-
onClick={() => setSubmitted(false)}
|
|
293
|
+
onClick={() => { setSubmitted(false); }}
|
|
294
294
|
className="text-xs text-blue-500 hover:underline cursor-pointer"
|
|
295
295
|
>Reset</button>
|
|
296
296
|
</div>
|
|
@@ -303,7 +303,7 @@ function ShadcnDemo() {
|
|
|
303
303
|
required
|
|
304
304
|
placeholder="At least 2 characters"
|
|
305
305
|
value={name}
|
|
306
|
-
onChange={e => setName(e.target.value)}
|
|
306
|
+
onChange={e => { setName(e.target.value); }}
|
|
307
307
|
/>
|
|
308
308
|
</div>
|
|
309
309
|
<div className="grid gap-1.5">
|
|
@@ -314,7 +314,7 @@ function ShadcnDemo() {
|
|
|
314
314
|
required
|
|
315
315
|
placeholder="you@example.com"
|
|
316
316
|
value={email}
|
|
317
|
-
onChange={e => setEmail(e.target.value)}
|
|
317
|
+
onChange={e => { setEmail(e.target.value); }}
|
|
318
318
|
/>
|
|
319
319
|
</div>
|
|
320
320
|
<div className="flex items-center gap-2">
|
|
@@ -417,7 +417,7 @@ export default function ReactPage({ title, serverTime, node, _urlBase, _urlStc,
|
|
|
417
417
|
{(['overview', 'routing', 'fetch', 'shadcn'] as const).map(t => (
|
|
418
418
|
<button
|
|
419
419
|
key={t}
|
|
420
|
-
onClick={() => setTab(t)}
|
|
420
|
+
onClick={() => { setTab(t); }}
|
|
421
421
|
className={[
|
|
422
422
|
'px-4 py-2 rounded-md text-sm font-medium transition-colors cursor-pointer',
|
|
423
423
|
tab === t ? 'bg-white shadow text-slate-900' : 'text-slate-500 hover:text-slate-900',
|
|
@@ -441,12 +441,12 @@ export default function ReactPage({ title, serverTime, node, _urlBase, _urlStc,
|
|
|
441
441
|
</p>
|
|
442
442
|
<div className="flex items-center gap-4">
|
|
443
443
|
<button
|
|
444
|
-
onClick={() => setCount(c => c - 1)}
|
|
444
|
+
onClick={() => { setCount(c => c - 1); }}
|
|
445
445
|
className="w-10 h-10 rounded-lg border border-slate-300 hover:bg-slate-50 font-bold text-slate-700 text-xl cursor-pointer"
|
|
446
446
|
>−</button>
|
|
447
447
|
<span className="text-3xl font-bold text-slate-900 w-10 text-center tabular-nums">{count}</span>
|
|
448
448
|
<button
|
|
449
|
-
onClick={() => setCount(c => c + 1)}
|
|
449
|
+
onClick={() => { setCount(c => c + 1); }}
|
|
450
450
|
className="w-10 h-10 rounded-lg bg-blue-500 hover:bg-blue-600 text-white font-bold text-xl cursor-pointer"
|
|
451
451
|
>+</button>
|
|
452
452
|
</div>
|
|
@@ -459,7 +459,8 @@ export default function ReactPage({ title, serverTime, node, _urlBase, _urlStc,
|
|
|
459
459
|
Passed via{' '}
|
|
460
460
|
<code className="bg-slate-100 px-1 rounded">_loadReactPage(path, props)</code>.
|
|
461
461
|
The framework auto-injects constants like _urlBase and serializes
|
|
462
|
-
all props as inline JSON, reused directly during client hydration —
|
|
462
|
+
all props as inline JSON, reused directly during client hydration —
|
|
463
|
+
no extra request needed.
|
|
463
464
|
</p>
|
|
464
465
|
<div className="space-y-2">
|
|
465
466
|
{([
|
|
@@ -491,8 +492,10 @@ export default function ReactPage({ title, serverTime, node, _urlBase, _urlStc,
|
|
|
491
492
|
react-page.tsx # Page component (import + compose)`}
|
|
492
493
|
</pre>
|
|
493
494
|
<p className="text-slate-500 text-xs mt-3">
|
|
494
|
-
Mirrors the shadcn/ui
|
|
495
|
-
|
|
495
|
+
Mirrors the shadcn/ui{' '}
|
|
496
|
+
<code className="bg-slate-100 px-1 rounded">components/ui/</code> convention.
|
|
497
|
+
In dev mode, the framework auto-scans imports —
|
|
498
|
+
no manual import map configuration needed.
|
|
496
499
|
</p>
|
|
497
500
|
</Card>
|
|
498
501
|
|
|
@@ -527,7 +530,8 @@ export default function ReactPage({ title, serverTime, node, _urlBase, _urlStc,
|
|
|
527
530
|
<h2 className="font-semibold text-slate-900 mb-2">Full-Page BrowserRouter Setup</h2>
|
|
528
531
|
<p className="text-slate-500 text-xs mb-3">
|
|
529
532
|
To let React Router manage the real URL (e.g. /app, /app/about),
|
|
530
|
-
replace MemoryRouter with BrowserRouter and route all sub-paths
|
|
533
|
+
replace MemoryRouter with BrowserRouter and route all sub-paths
|
|
534
|
+
to the same Ctr method on the server:
|
|
531
535
|
</p>
|
|
532
536
|
<pre className="bg-slate-50 border border-slate-200 rounded-lg p-4 text-xs overflow-auto leading-relaxed text-slate-700">{`// 1. route.json: 将所有子路径路由到同一 Ctr 方法
|
|
533
537
|
{
|
|
@@ -561,18 +565,19 @@ await this._loadReactPage('view/my', { ...props }, {
|
|
|
561
565
|
<Card>
|
|
562
566
|
<h2 className="font-semibold text-slate-900 mb-3">Client Fetch Demo</h2>
|
|
563
567
|
<p className="text-slate-500 text-xs mb-4">
|
|
564
|
-
After hydration, click a button to send a GET request.
|
|
568
|
+
After hydration, click a button to send a GET request.
|
|
569
|
+
setState triggers a partial re-render — no page refresh.
|
|
565
570
|
</p>
|
|
566
571
|
<div className="flex gap-3 flex-wrap">
|
|
567
572
|
<Btn
|
|
568
|
-
onClick={() => doFetch(`${_urlBase}test/json?type=4`)}
|
|
573
|
+
onClick={() => { doFetch(`${_urlBase}test/json?type=4`); }}
|
|
569
574
|
disabled={isFetching}
|
|
570
575
|
>
|
|
571
576
|
{isFetching ? 'Fetching...' : 'GET /test/json?type=4'}
|
|
572
577
|
</Btn>
|
|
573
578
|
<Btn
|
|
574
579
|
outline
|
|
575
|
-
onClick={() => doFetch(`${_urlBase}test/json?type=2`)}
|
|
580
|
+
onClick={() => { doFetch(`${_urlBase}test/json?type=2`); }}
|
|
576
581
|
disabled={isFetching}
|
|
577
582
|
>
|
|
578
583
|
GET type=2 (error resp)
|