weifuwu 0.95.0 → 0.95.2
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/level5/client/layout/weifuwu-layout.css +37 -1
- package/dist/level6/apps/agent-platform/app-root.ts +15 -0
- package/dist/level6/apps/agent-platform/scripts/seed.mjs +18 -9
- package/dist/level6/apps/agent-platform/server.js +125 -125
- package/dist/level6/apps/agent-platform/src/bootstrap/routes-protected.ts +7 -17
- package/dist/level6/apps/agent-platform/src/bootstrap/routes-public.ts +4 -8
- package/dist/level6/apps/agent-platform/src/routes/role-templates.ts +3 -4
- package/dist/level6/apps/agent-platform/src/sandbox/docker.ts +3 -5
- package/dist/level6/apps/agent-platform/ui/ssr.ts +9 -5
- package/dist/level6/apps/showcase/server.js +22 -22
- package/dist/level6/apps/showcase/server.ts +1 -1
- package/dist/level6/client/layout/weifuwu-layout.css +1 -0
- package/dist/level6/index.js +9 -0
- package/dist/level6/server/user/index.js +1 -1
- package/dist/level6/server/user/index.ts +12 -0
- package/dist/server/index.js +9 -0
- package/dist/server/user/index.js +1 -1
- package/docs/client.md +2 -2
- package/docs/level.md +1 -1
- package/docs/migration.md +6 -1
- package/package.json +1 -1
|
@@ -218,7 +218,7 @@ async function loadSsrApp(): Promise<any> {
|
|
|
218
218
|
format: 'esm',
|
|
219
219
|
write: false,
|
|
220
220
|
jsx: 'automatic',
|
|
221
|
-
jsxImportSource: '
|
|
221
|
+
jsxImportSource: resolve(fwRoot, 'level6', 'client', 'vdom'),
|
|
222
222
|
})
|
|
223
223
|
const tmp = resolve(osTmpdir(), `wf-ssr-${process.pid}-${Date.now()}.mjs`)
|
|
224
224
|
await writeFile(tmp, result.outputFiles[0].text)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer tokens,base,layout,components,utilities;@layer layout{.wf-stack{display:flex;flex-direction:column}:where(.wf-stack){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, stretch)}.wf-row{display:flex;flex-wrap:wrap}:where(.wf-row){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, center)}.wf-row-reverse{display:flex;flex-wrap:wrap;flex-direction:row-reverse}:where(.wf-row-reverse){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, center)}.wf-items-start{--wf-align: flex-start}.wf-items-center{--wf-align: center}.wf-items-end{--wf-align: flex-end}.wf-items-stretch{--wf-align: stretch}.wf-grid{display:grid;grid-template-columns:var(--wf-cols, repeat(auto-fill, minmax(280px, 1fr)))}:where(.wf-grid){gap:var(--wf-gap, var(--wf-gap-lg))}.wf-center{display:flex;flex-direction:column;align-items:center;justify-content:center}.wf-justify-between{display:flex;justify-content:space-between}:where(.wf-justify-between){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-justify-end{display:flex;justify-content:flex-end}:where(.wf-justify-end){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-justify-center{display:flex;justify-content:center}:where(.wf-justify-center){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-fill{flex:1;min-width:0;min-height:0}.wf-fill-hover{border-radius:var(--wf-radius-sm);padding:2px 4px;margin:-2px -4px;transition:background .15s ease}.wf-cover{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;z-index:var(--wf-z, var(--wf-cover-z))}}:root{--wf-brand-seed: #4f6ef7;--wf-brand-500: var(--wf-brand-seed);--wf-brand-600: color-mix(in srgb, var(--wf-brand-seed) 85%, #000);--wf-brand-700: color-mix(in srgb, var(--wf-brand-seed) 70%, #000);--wf-brand-50: color-mix(in srgb, var(--wf-brand-seed) 12%, #fff);--wf-green-500: #22c55e;--wf-green-50: #f0fdf4;--wf-green-700: #15803d;--wf-amber-500: #f59e0b;--wf-amber-50: #fffbeb;--wf-amber-700: #b45309;--wf-red-500: #ef4444;--wf-red-50: #fef2f2;--wf-red-700: #b91c1c;--wf-sky-500: #1677ff;--wf-sky-50: #e6f4ff;--wf-sky-700: #0369a1;--wf-slate-900: #0f172a;--wf-slate-500: #64748b;--wf-slate-400: #94a3b8;--wf-slate-300: #cbd5e1;--wf-slate-200: #e2e8f0;--wf-slate-100: #f1f5f9;--wf-slate-50: #f8fafc;--wf-white: #ffffff;--wf-dark-brand-seed: #6b8aff;--wf-dark-brand-500: var(--wf-dark-brand-seed);--wf-dark-brand-600: color-mix(in srgb, var(--wf-dark-brand-seed) 78%, #fff);--wf-dark-brand-50: color-mix(in srgb, var(--wf-dark-brand-seed) 12%, #0f172a);--wf-dark-green-500: #4ade80;--wf-dark-green-50: #14532d;--wf-dark-amber-500: #fbbf24;--wf-dark-amber-50: #451a03;--wf-dark-red-500: #f87171;--wf-dark-red-50: #451a1a;--wf-dark-sky-500: #60a5fa;--wf-dark-sky-50: #172554;--wf-dark-slate-900: #f1f5f9;--wf-dark-slate-500: #94a3b8;--wf-dark-slate-400: #64748b;--wf-dark-slate-300: #475569;--wf-dark-slate-200: #334155;--wf-dark-slate-100: #1e293b;--wf-dark-bg: #0f172a;--wf-dark-overlay: rgba(0, 0, 0, .6);--wf-dark-fill: var(--wf-dark-slate-200);--wf-dark-bg-hover: var(--wf-dark-state-hover);--wf-dark-state-hover: rgba(255, 255, 255, .06);--wf-dark-state-pressed: rgba(255, 255, 255, .1);--wf-dark-surface-shadow: var(--wf-dark-shadow);--wf-dark-shadow-sm: 0 1px 2px rgba(0, 0, 0, .2);--wf-dark-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, .3);--wf-dark-shadow: 0 1px 3px rgba(0, 0, 0, .3);--wf-dark-shadow-md: 0 4px 12px rgba(0, 0, 0, .4);--wf-dark-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .4)}:root{--wf-space-xs: 4px;--wf-space-sm: 8px;--wf-space: 12px;--wf-space-md: 16px;--wf-space-lg: 24px;--wf-space-xl: 32px;--wf-space-2xl: 40px;--wf-gap-xs: var(--wf-space-xs);--wf-gap-sm: var(--wf-space-sm);--wf-gap-md: var(--wf-space);--wf-gap-lg: var(--wf-space-md);--wf-gap-xl: var(--wf-space-lg);--wf-gap-2xl: var(--wf-space-xl);--wf-radius-xs: 2px;--wf-radius-sm: 4px;--wf-radius: 6px;--wf-radius-md: 8px;--wf-radius-lg: 12px;--wf-radius-xl: 20px;--wf-surface-radius: var(--wf-radius-md);--wf-surface-shadow: var(--wf-shadow);--wf-shadow-sm: 0 1px 2px rgba(0,0,0,.05);--wf-shadow-inset: inset 0 1px 2px rgba(0,0,0,.04);--wf-shadow: 0 1px 3px rgba(0,0,0,.08);--wf-shadow-md: 0 4px 12px rgba(0,0,0,.1);--wf-shadow-lg: 0 10px 15px -3px rgba(0,0,0,.1);--wf-z-sticky: 40;--wf-z-overlay: 80;--wf-z-modal: 100;--wf-tour-min-width: 240px;--wf-kanban-col-min-width: 200px;--wf-layout-sider-width: 240px;--wf-layout-sider-collapsed-width: 64px;--wf-layout-header-height: 56px;--wf-kanban-col-max-width: 300px;--wf-treeselect-min-width: 200px;--wf-navmenu-min-width: 160px;--wf-select-menu-min-width: 200px;--wf-treeselect-max-width: 320px;--wf-treeselect-dropdown-max-height: 260px;--wf-z-popover: 120;--wf-z-toast: 140;--wf-z-tooltip: 160;--wf-z-dropdown: var(--wf-z-popover);--wf-pop-z: var(--wf-z-popover);--wf-cover-z: var(--wf-z-modal);--wf-color-primary: var(--wf-brand-500);--wf-color-primary-hover: var(--wf-brand-600);--wf-color-primary-bg: var(--wf-brand-50);--wf-color-success: var(--wf-green-500);--wf-color-success-bg: var(--wf-green-50);--wf-color-warning: var(--wf-amber-500);--wf-color-warning-bg: var(--wf-amber-50);--wf-color-error: var(--wf-red-500);--wf-color-error-bg: var(--wf-red-50);--wf-color-text: var(--wf-slate-900);--wf-color-text-secondary: var(--wf-slate-500);--wf-color-text-tertiary: var(--wf-slate-400);--wf-color-text-disabled: var(--wf-slate-300);--wf-color-bg: var(--wf-white);--wf-color-bg-secondary: var(--wf-slate-50);--wf-color-bg-tertiary: var(--wf-slate-100);--wf-color-border: var(--wf-slate-200);--wf-color-border-light: var(--wf-slate-100);--wf-color-border-dark: var(--wf-slate-300);--wf-surface-bg: var(--wf-color-bg);--wf-color-bg-elevated: var(--wf-color-bg);--wf-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;--wf-font-mono: "SF Mono", "Fira Code", "JetBrains Mono", "PingFang SC", "Microsoft YaHei", monospace;--wf-font-size-xs: 12px;--wf-font-size-sm: 13px;--wf-font-size-base: 14px;--wf-font-size-lg: 15px;--wf-font-size-xl: 16px;--wf-font-size-2xl: 21px;--wf-font-size-3xl: 24px;--wf-font-size-4xl: 30px;--wf-font-size-5xl: 36px;--wf-font-size-display: 30px;--wf-heading-case: none;--wf-heading-tracking: 0;--wf-font-weight-normal: 400;--wf-font-weight-medium: 500;--wf-font-weight-semibold: 600;--wf-font-weight-bold: 700;--wf-line-height-tight: 1.25;--wf-line-height: 1.5;--wf-line-height-relaxed: 1.75;--wf-border-width: 1px;--wf-focus-ring: 0 0 0 2px var(--wf-color-primary-bg), 0 0 0 1px var(--wf-color-primary);--wf-transition-duration: var(--wf-dur-fast);--wf-transition-timing: var(--wf-ease-out);--wf-transition: var(--wf-transition-duration) var(--wf-transition-timing);--wf-dur-fast: .12s;--wf-dur-base: .2s;--wf-dur-slow: .3s;--wf-ease-out: cubic-bezier(.16, 1, .3, 1);--wf-ease-in: cubic-bezier(.4, 0, 1, 1);--wf-ease-in-out: cubic-bezier(.4, 0, .2, 1);--wf-ease-snap: cubic-bezier(.34, 1.56, .64, 1);--wf-ease-standard: ease;--wf-dur-md: var(--wf-dur-base);--wf-motion-sm: 4px;--wf-dur-spin: .6s;--wf-dur-pulse: 1.2s;--wf-dur-blink: 1.1s;--wf-dur-progress: 1.4s;--wf-color-info: var(--wf-sky-500);--wf-color-info-bg: var(--wf-sky-50);--wf-color-primary-text: var(--wf-brand-700);--wf-color-success-text: var(--wf-green-700);--wf-color-warning-text: var(--wf-amber-700);--wf-color-error-text: var(--wf-red-700);--wf-color-info-text: var(--wf-sky-700);--wf-color-fill: var(--wf-slate-100);--wf-color-bg-subtle: var(--wf-color-fill);--wf-state-hover: rgba(0, 0, 0, .04);--wf-state-pressed: rgba(0, 0, 0, .08);--wf-color-bg-hover: var(--wf-state-hover);--wf-color-on-brand: #fff;--wf-color-on-warning: #451a03;--wf-overlay: rgba(0, 0, 0, .4);--wf-overlay-blur: 4px;--wf-accent-color: var(--wf-color-primary);--wf-caret-color: var(--wf-color-primary);--wf-control-pad-y: 10px;--wf-control-height: 36px;--wf-field-height: var(--wf-control-height);--wf-field-radius: var(--wf-radius);--wf-bp-sm: 640px;--wf-bp-md: 768px;--wf-bp-lg: 1024px;--wf-bp-xl: 1280px;--wf-sidebar-width: 240px;--wf-opacity-disabled: .5;--wf-letter-spacing-wide: .5px;--wf-heading-display-tracking: -.5px;--wf-nums: "tabular-nums"}@supports not (color: color-mix(in srgb,red 50%,blue)){:root{--wf-brand-600: #3b5ae0;--wf-brand-700: #4338ca;--wf-brand-50: #eef1ff;--wf-dark-brand-600: #8ba3ff;--wf-dark-brand-50: #1e293b}}:root[data-theme=dark]{color-scheme:dark;--wf-color-primary: var(--wf-dark-brand-500);--wf-color-primary-hover: var(--wf-dark-brand-600);--wf-color-primary-bg: var(--wf-dark-brand-50);--wf-color-success: var(--wf-dark-green-500);--wf-color-success-bg: var(--wf-dark-green-50);--wf-color-warning: var(--wf-dark-amber-500);--wf-color-warning-bg: var(--wf-dark-amber-50);--wf-color-error: var(--wf-dark-red-500);--wf-color-error-bg: var(--wf-dark-red-50);--wf-color-info: var(--wf-dark-sky-500);--wf-color-info-bg: var(--wf-dark-sky-50);--wf-color-text: var(--wf-dark-slate-900);--wf-color-text-secondary: var(--wf-dark-slate-500);--wf-color-text-tertiary: var(--wf-dark-slate-400);--wf-color-text-disabled: var(--wf-dark-slate-300);--wf-color-bg: var(--wf-dark-bg);--wf-color-bg-secondary: var(--wf-dark-slate-100);--wf-color-bg-tertiary: var(--wf-dark-slate-200);--wf-color-fill: var(--wf-dark-fill);--wf-color-bg-subtle: var(--wf-dark-fill);--wf-color-bg-hover: var(--wf-dark-bg-hover);--wf-state-hover: var(--wf-dark-state-hover);--wf-state-pressed: var(--wf-dark-state-pressed);--wf-color-bg-elevated: var(--wf-dark-slate-100);--wf-color-border: var(--wf-dark-slate-200);--wf-color-border-light: var(--wf-dark-slate-100);--wf-color-border-dark: var(--wf-dark-slate-300);--wf-surface-bg: var(--wf-color-bg);--wf-surface-shadow: var(--wf-dark-surface-shadow);--wf-shadow-sm: var(--wf-dark-shadow-sm);--wf-shadow: var(--wf-dark-shadow);--wf-shadow-md: var(--wf-dark-shadow-md);--wf-shadow-lg: var(--wf-dark-shadow-lg);--wf-shadow-inset: var(--wf-dark-shadow-inset);--wf-color-primary-text: var(--wf-dark-brand-500);--wf-color-success-text: var(--wf-dark-green-500);--wf-color-warning-text: var(--wf-dark-amber-500);--wf-color-error-text: var(--wf-dark-red-500);--wf-color-info-text: var(--wf-dark-sky-500);--wf-overlay: var(--wf-dark-overlay)}@media(prefers-color-scheme:dark){:root:not([data-theme=light]){color-scheme:dark;--wf-color-primary: var(--wf-dark-brand-500);--wf-color-primary-hover: var(--wf-dark-brand-600);--wf-color-primary-bg: var(--wf-dark-brand-50);--wf-color-success: var(--wf-dark-green-500);--wf-color-success-bg: var(--wf-dark-green-50);--wf-color-warning: var(--wf-dark-amber-500);--wf-color-warning-bg: var(--wf-dark-amber-50);--wf-color-error: var(--wf-dark-red-500);--wf-color-error-bg: var(--wf-dark-red-50);--wf-color-info: var(--wf-dark-sky-500);--wf-color-info-bg: var(--wf-dark-sky-50);--wf-color-text: var(--wf-dark-slate-900);--wf-color-text-secondary: var(--wf-dark-slate-500);--wf-color-text-tertiary: var(--wf-dark-slate-400);--wf-color-text-disabled: var(--wf-dark-slate-300);--wf-color-bg: var(--wf-dark-bg);--wf-color-bg-secondary: var(--wf-dark-slate-100);--wf-color-bg-tertiary: var(--wf-dark-slate-200);--wf-color-fill: var(--wf-dark-fill);--wf-color-bg-subtle: var(--wf-dark-fill);--wf-color-bg-hover: var(--wf-dark-bg-hover);--wf-state-hover: var(--wf-dark-state-hover);--wf-state-pressed: var(--wf-dark-state-pressed);--wf-color-bg-elevated: var(--wf-dark-slate-100);--wf-color-border: var(--wf-dark-slate-200);--wf-color-border-light: var(--wf-dark-slate-100);--wf-color-border-dark: var(--wf-dark-slate-300);--wf-surface-bg: var(--wf-color-bg);--wf-surface-shadow: var(--wf-dark-surface-shadow);--wf-shadow-sm: var(--wf-dark-shadow-sm);--wf-shadow: var(--wf-dark-shadow);--wf-shadow-md: var(--wf-dark-shadow-md);--wf-shadow-lg: var(--wf-dark-shadow-lg);--wf-shadow-inset: var(--wf-dark-shadow-inset);--wf-color-primary-text: var(--wf-dark-brand-500);--wf-color-success-text: var(--wf-dark-green-500);--wf-color-warning-text: var(--wf-dark-amber-500);--wf-color-error-text: var(--wf-dark-red-500);--wf-color-info-text: var(--wf-dark-sky-500);--wf-overlay: var(--wf-dark-overlay)}}:root[data-preset=minimal]{--wf-brand-seed: #64748b;--wf-dark-brand-seed: #94a3b8}:root[data-preset=compact]{--wf-control-height: 32px;--wf-control-pad-y: 6px;--wf-space-xs: 3px;--wf-space-sm: 6px;--wf-space: 9px;--wf-space-md: 12px;--wf-space-lg: 18px;--wf-space-xl: 24px;--wf-space-2xl: 30px;--wf-font-size-sm: 12px;--wf-font-size-base: 13px}:root[data-preset=rounded]{--wf-radius-sm: 8px;--wf-radius: 12px;--wf-radius-md: 16px;--wf-radius-lg: 20px;--wf-radius-xl: 28px;--wf-surface-radius: var(--wf-radius-md);--wf-btn-radius: 999px;--wf-field-radius: var(--wf-radius-md)}@property --wf-gap{syntax: "*"; inherits: false;}@property --wf-align{syntax: "*"; inherits: false;}@property --wf-justify{syntax: "*"; inherits: false;}@property --wf-cols{syntax: "*"; inherits: false;}@property --wf-max{syntax: "*"; inherits: false;}@property --wf-w-sm{syntax: "*"; inherits: false;}@property --wf-z{syntax: "*"; inherits: false;}@property --wf-offset{syntax: "*"; inherits: false;}@property --wf-popup-max{syntax: "*"; inherits: false;}@layer base{*,*:before,*:after{box-sizing:border-box}::selection{background:var(--wf-color-primary-bg);color:var(--wf-color-primary-text)}*{scrollbar-width:thin;scrollbar-color:var(--wf-color-border-dark) transparent}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--wf-color-border-dark);border-radius:var(--wf-radius-sm);border:2px solid transparent;background-clip:padding-box}::-webkit-scrollbar-thumb:hover{background:var(--wf-color-text-secondary);background-clip:padding-box;border:2px solid transparent}:root{color-scheme:light}body{margin:0;background:var(--wf-color-bg);color:var(--wf-color-text);font-family:var(--wf-font-sans);font-size:var(--wf-font-size-base);line-height:var(--wf-line-height);-webkit-font-smoothing:antialiased}a{color:var(--wf-color-primary-text);text-decoration:none}a:hover{color:var(--wf-color-primary-hover);text-decoration:underline}input,textarea,select,button{font-family:inherit;font-size:inherit;line-height:inherit}input,textarea,select{accent-color:var(--wf-accent-color);caret-color:var(--wf-caret-color);background:var(--wf-color-bg);color:var(--wf-color-text);border:var(--wf-border-width) solid var(--wf-color-border);border-radius:var(--wf-radius);padding:var(--wf-control-pad-y) var(--wf-space)}input:focus,textarea:focus,select:focus{outline:none;box-shadow:var(--wf-focus-ring);border-color:var(--wf-color-primary)}input:disabled,textarea:disabled,select:disabled,button:disabled{opacity:var(--wf-opacity-disabled);cursor:not-allowed}button{accent-color:var(--wf-accent-color);background:var(--wf-color-bg);color:var(--wf-color-text);border:var(--wf-border-width) solid var(--wf-color-border);border-radius:var(--wf-radius);padding:var(--wf-control-pad-y) var(--wf-space-md);min-height:var(--wf-control-height);cursor:pointer;transition:border-color var(--wf-dur-fast) var(--wf-ease-out),color var(--wf-dur-fast) var(--wf-ease-out),box-shadow var(--wf-dur-fast) var(--wf-ease-out),background-color var(--wf-dur-fast) var(--wf-ease-out),filter var(--wf-dur-fast) var(--wf-ease-out)}button:hover{border-color:var(--wf-color-primary);color:var(--wf-color-primary-text)}button:active:not(:disabled),[role=button]:active{filter:brightness(.95)}button:focus-visible,[tabindex]:focus-visible{outline:none;box-shadow:var(--wf-focus-ring)}[role=button]{cursor:pointer;transition:background-color var(--wf-dur-fast) var(--wf-ease-out),border-color var(--wf-dur-fast) var(--wf-ease-out),box-shadow var(--wf-dur-fast) var(--wf-ease-out),color var(--wf-dur-fast) var(--wf-ease-out),filter var(--wf-dur-fast) var(--wf-ease-out)}@media(pointer:coarse){button,[role=button],input,textarea,select,.wf-card--clickable,.wf-table-th--sortable,.wf-accordion-summary,.wf-tag-close,.wf-checkbox,.wf-switch,.wf-radio,.wf-datepicker-cell{min-height:44px;min-width:44px}}h1,h2,h3,h4,h5,h6{font-weight:var(--wf-font-weight-semibold);line-height:var(--wf-line-height-tight);color:var(--wf-color-text)}p{line-height:var(--wf-line-height-relaxed)}small{font-size:var(--wf-font-size-sm);color:var(--wf-color-text-tertiary)}label{font-size:var(--wf-font-size-base);font-weight:var(--wf-font-weight-medium);color:var(--wf-color-text)}table{width:100%;border-collapse:collapse}th{text-align:left;font-weight:var(--wf-font-weight-medium);font-size:var(--wf-font-size-xs);color:var(--wf-color-text-tertiary);text-transform:var(--wf-heading-case);letter-spacing:var(--wf-heading-tracking);padding:var(--wf-space) var(--wf-space-sm);border-bottom:var(--wf-border-width) solid var(--wf-color-border);background:var(--wf-color-bg-secondary)}td{padding:var(--wf-space) var(--wf-space-sm);border-bottom:var(--wf-border-width) solid var(--wf-color-border);color:var(--wf-color-text);font-size:var(--wf-font-size-base)}hr{border:none;border-top:var(--wf-border-width) solid var(--wf-color-border);margin:var(--wf-space-md) 0}pre,code{font-family:var(--wf-font-mono);font-size:var(--wf-font-size-sm)}pre{background:var(--wf-color-bg-secondary);border:var(--wf-border-width) solid var(--wf-color-border);border-radius:var(--wf-radius);padding:var(--wf-space) var(--wf-space-md);overflow-x:auto;white-space:pre}code{background:var(--wf-color-bg-secondary);padding:2px 6px;border-radius:var(--wf-radius-sm)}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}body.wf-dragging{user-select:none;-webkit-user-select:none}@keyframes wf-stream-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.wf-stream-in{animation:wf-stream-in var(--wf-dur-base) var(--wf-ease-out) both}@media(prefers-reduced-motion:reduce){.wf-stream-in{animation-duration:.01ms}}.wf-hero-cursor{animation:wf-hero-blink 1s step-end infinite;color:var(--wf-color-primary)}@keyframes wf-hero-blink{0%,to{opacity:1}50%{opacity:0}}}@layer layout{.wf-stack{display:flex;flex-direction:column}:where(.wf-stack){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, stretch)}.wf-row{display:flex;flex-wrap:wrap}:where(.wf-row){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, center)}.wf-row-reverse{display:flex;flex-wrap:wrap;flex-direction:row-reverse}:where(.wf-row-reverse){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, center)}.wf-items-start{--wf-align: flex-start}.wf-items-center{--wf-align: center}.wf-items-end{--wf-align: flex-end}.wf-items-stretch{--wf-align: stretch}.wf-grid{display:grid;grid-template-columns:var(--wf-cols, repeat(auto-fill, minmax(280px, 1fr)))}:where(.wf-grid){gap:var(--wf-gap, var(--wf-gap-lg))}.wf-center{display:flex;flex-direction:column;align-items:center;justify-content:center}.wf-justify-between{display:flex;justify-content:space-between}:where(.wf-justify-between){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-justify-end{display:flex;justify-content:flex-end}:where(.wf-justify-end){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-justify-center{display:flex;justify-content:center}:where(.wf-justify-center){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-fill{flex:1;min-width:0;min-height:0}.wf-fill-hover{border-radius:var(--wf-radius-sm);padding:2px 4px;margin:-2px -4px;transition:background .15s ease}.wf-cover{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;z-index:var(--wf-z, var(--wf-cover-z))}}@layer layout{.wf-split{display:flex;justify-content:space-between}:where(.wf-split){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-split>:last-child{flex-shrink:0}}@layer layout{.wf-cluster{display:flex;flex-wrap:wrap}:where(.wf-cluster){gap:var(--wf-gap, var(--wf-gap-sm));justify-content:var(--wf-justify, center);align-items:var(--wf-align, center)}}@layer layout{.wf-relative{position:relative}.wf-absolute{position:absolute}}@layer layout{.wf-sticky{position:sticky;top:var(--wf-offset, 0)}}@layer layout{.wf-overflow-auto{overflow:auto}.wf-overflow-hidden{overflow:hidden}.wf-overflow-x{overflow-x:auto}}@layer layout{.wf-safe-bottom{padding-bottom:env(safe-area-inset-bottom)}.wf-safe-top{padding-top:env(safe-area-inset-top)}}@layer layout{.wf-layer{position:relative;z-index:var(--wf-z, 1)}}@layer layout{.wf-self-start{align-self:flex-start}.wf-self-center{align-self:center}.wf-self-end{align-self:flex-end}.wf-self-stretch{align-self:stretch}}@layer layout{.wf-nowrap{display:flex;flex-wrap:nowrap}:where(.wf-nowrap){gap:var(--wf-gap, var(--wf-gap-md))}}@layer layout{.wf-shrink{min-width:0;min-height:0}.wf-min-width-0{min-width:0}}@layer layout{.wf-container{width:100%;max-width:var(--wf-max, 1200px);margin:0 auto;padding:0 var(--wf-gap, var(--wf-gap-lg))}}@layer layout{.wf-app-shell{display:grid;grid-template-columns:var(--wf-sidebar-width, 240px) minmax(0,1fr);height:100vh;overflow:hidden}.wf-sidebar{display:flex;flex-direction:column;position:sticky;top:0;height:100vh;overflow-y:auto;background:var(--wf-color-bg-secondary);border-right:var(--wf-border-width) solid var(--wf-color-border)}.wf-sidebar-header{display:flex;align-items:center;gap:var(--wf-gap-sm);padding:var(--wf-space-md);border-bottom:var(--wf-border-width) solid var(--wf-color-border-light);flex-shrink:0}.wf-sidebar-body{flex:1;padding:var(--wf-space-sm);overflow-y:auto}.wf-sidebar-footer{padding:var(--wf-space-sm);border-top:var(--wf-border-width) solid var(--wf-color-border-light);flex-shrink:0}.wf-nav{display:flex;flex-direction:column;gap:2px}.wf-nav-group{font-size:var(--wf-font-size-xs);font-weight:var(--wf-font-weight-medium);color:var(--wf-color-text-tertiary);text-transform:var(--wf-heading-case);letter-spacing:var(--wf-heading-tracking);padding:var(--wf-space-md) var(--wf-space-sm) var(--wf-space-xs)}.wf-nav-item{display:flex;align-items:center;gap:var(--wf-gap-sm);padding:var(--wf-space-sm) var(--wf-space);border-radius:var(--wf-radius);color:var(--wf-color-text-secondary);font-size:var(--wf-font-size-base);text-decoration:none;cursor:pointer;border:none;background:none;width:100%;text-align:left;font-family:inherit;transition:background var(--wf-transition),color var(--wf-transition)}.wf-nav-item:hover{background:var(--wf-color-bg-tertiary);color:var(--wf-color-text);text-decoration:none}.wf-nav-item:focus-visible{outline:none;box-shadow:var(--wf-focus-ring)}.wf-nav-item--active{background:var(--wf-color-primary-bg);color:var(--wf-color-primary-text);font-weight:var(--wf-font-weight-medium)}.wf-nav-item--active:hover{background:var(--wf-color-primary-bg);color:var(--wf-color-primary-text)}.wf-nav--collapsed .wf-nav-item{justify-content:center;gap:0;padding:var(--wf-space-sm)}.wf-nav--collapsed .wf-nav-label{display:none}.wf-nav--collapsed .wf-nav-group{text-align:center;padding-left:0;padding-right:0;overflow:hidden;white-space:nowrap}.wf-main{padding:var(--wf-space-lg);min-width:0;min-height:0;overflow-y:auto;background:var(--wf-color-bg);--wf-main-max: none}.wf-main>*{max-width:var(--wf-main-max);margin-inline:auto}@media(pointer:coarse){.wf-nav-item{min-height:44px}}@media(max-width:767.98px){.wf-app-shell{grid-template-columns:1fr;height:auto;overflow:visible}.wf-sidebar{position:static;height:auto;border-right:none;border-bottom:var(--wf-border-width) solid var(--wf-color-border)}.wf-main{padding:var(--wf-space-md);overflow:visible}}}@layer utilities{.wf-surface{border-radius:var(--wf-surface-radius);box-shadow:var(--wf-surface-shadow);background:var(--wf-surface-bg)}.wf-surface--flat{box-shadow:none}.wf-bg-secondary{background:var(--wf-color-bg-secondary)}.wf-bg-tertiary{background:var(--wf-color-bg-tertiary)}.wf-bg-primary{background:var(--wf-color-primary-bg)}.wf-bg-warning{background:var(--wf-color-warning-bg)}.wf-bg-error{background:var(--wf-color-error-bg)}.wf-bg-none{background:transparent}.wf-pill{border-radius:999px}.wf-radius-sm{border-radius:var(--wf-radius-sm)}.wf-radius{border-radius:var(--wf-radius)}.wf-radius-md{border-radius:var(--wf-radius-md)}.wf-radius-lg{border-radius:var(--wf-radius-lg)}.wf-shadow{box-shadow:var(--wf-shadow)}.wf-elevate{transition:box-shadow var(--wf-dur-fast) var(--wf-ease-out),transform var(--wf-dur-fast) var(--wf-ease-out)}.wf-elevate:hover{box-shadow:var(--wf-shadow-md);transform:translateY(-2px)}.wf-elevate:focus-visible{outline:none;box-shadow:var(--wf-shadow-md),var(--wf-focus-ring)}.wf-panel-in{animation:wf-panel-in var(--wf-dur-fast) var(--wf-ease-out);transform-origin:top center}@keyframes wf-panel-in{0%{opacity:0;transform:translateY(calc(var(--wf-motion-sm) * -1)) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}.wf-bubble{display:inline-block;max-width:70%;padding:var(--wf-space-sm) var(--wf-space-md);border-radius:var(--wf-radius-md);background:var(--wf-color-bg-secondary);color:var(--wf-color-text);font-size:var(--wf-font-size-base);line-height:var(--wf-line-height);white-space:pre-wrap;word-break:break-word}.wf-bubble--own{background:var(--wf-color-primary);color:var(--wf-color-on-brand);border-bottom-right-radius:var(--wf-radius-sm)}.wf-bubble--ai{background:var(--wf-color-primary-bg);border:var(--wf-border-width) solid var(--wf-color-border-light);border-bottom-left-radius:var(--wf-radius-sm)}.wf-rounded-sm{border-radius:var(--wf-radius-sm)}.wf-rounded-md{border-radius:var(--wf-radius-md)}.wf-card-outline{border:var(--wf-border-width) solid var(--wf-color-border)}}@layer utilities{.wf-border{border:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-top{border-top:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-bottom{border-bottom:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-left{border-left:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-right{border-right:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-none{border:none}}@layer utilities{.wf-text-left{text-align:left}.wf-text-center{text-align:center}.wf-text-right{text-align:right}.wf-font-xs{font-size:var(--wf-font-size-xs)}.wf-font-sm{font-size:var(--wf-font-size-sm)}.wf-font-base{font-size:var(--wf-font-size-base)}.wf-font-lg{font-size:var(--wf-font-size-lg)}.wf-font-2xl{font-size:var(--wf-font-size-2xl)}.wf-font-3xl{font-size:var(--wf-font-size-3xl)}.wf-font-4xl{font-size:var(--wf-font-size-4xl)}.wf-nums{font-variant-numeric:var(--wf-nums)}.wf-text-secondary{color:var(--wf-color-text-secondary)}.wf-text-tertiary{color:var(--wf-color-text-tertiary)}.wf-text-danger{color:var(--wf-color-error-text)}.wf-text-primary{color:var(--wf-color-primary-text)}.wf-text-success{color:var(--wf-color-success-text)}.wf-text-warning{color:var(--wf-color-warning-text)}.wf-font-mono{font-family:var(--wf-font-mono)}.wf-text-error{color:var(--wf-color-error-text)}.wf-text-on-brand{color:var(--wf-color-on-brand)}.wf-text-on-warning{color:var(--wf-color-on-warning)}.wf-medium{font-weight:var(--wf-font-weight-medium)}.wf-semibold{font-weight:var(--wf-font-weight-semibold)}.wf-bold{font-weight:var(--wf-font-weight-bold)}.wf-tracking-wide{letter-spacing:var(--wf-letter-spacing-wide)}.wf-uppercase{text-transform:uppercase}.wf-pre-wrap{white-space:pre-wrap;word-break:break-word}.wf-break-word{overflow-wrap:break-word;word-break:break-word}.wf-text-nowrap{white-space:nowrap}.wf-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}@layer utilities{.wf-padding-none{padding:0}.wf-padding-xs{padding:var(--wf-space-xs)}.wf-padding-sm{padding:var(--wf-space-sm)}.wf-padding-md{padding:var(--wf-space-md)}.wf-padding-lg{padding:var(--wf-space-lg)}.wf-padding-xl{padding:var(--wf-space-xl)}.wf-padding-x-xs{padding-left:var(--wf-space-xs);padding-right:var(--wf-space-xs)}.wf-padding-x-sm{padding-left:var(--wf-space-sm);padding-right:var(--wf-space-sm)}.wf-padding-x-md{padding-left:var(--wf-space-md);padding-right:var(--wf-space-md)}.wf-padding-y-xs{padding-top:var(--wf-space-xs);padding-bottom:var(--wf-space-xs)}.wf-padding-y-sm{padding-top:var(--wf-space-sm);padding-bottom:var(--wf-space-sm)}.wf-padding-y-md{padding-top:var(--wf-space-md);padding-bottom:var(--wf-space-md)}.wf-padding-y-lg{padding-top:var(--wf-space-lg);padding-bottom:var(--wf-space-lg)}.wf-padding-top-sm{padding-top:var(--wf-space-sm)}.wf-padding-left-sm{padding-left:var(--wf-space-sm)}.wf-padding-bottom-xs{padding-bottom:var(--wf-space-xs)}.wf-padding-bottom-sm{padding-bottom:var(--wf-space-sm)}.wf-padding-bottom-md{padding-bottom:var(--wf-space-md)}.wf-margin-none{margin:0}.wf-margin-top-none{margin-top:0}.wf-margin-top-xs{margin-top:var(--wf-space-xs)}.wf-margin-top-sm{margin-top:var(--wf-space-sm)}.wf-margin-top-md{margin-top:var(--wf-space-md)}.wf-margin-bottom-xs{margin-bottom:var(--wf-space-xs)}.wf-margin-bottom-sm{margin-bottom:var(--wf-space-sm)}.wf-margin-bottom-md{margin-bottom:var(--wf-space-md)}.wf-margin-bottom-lg{margin-bottom:var(--wf-space-lg)}.wf-margin-left-xs{margin-left:var(--wf-space-xs)}.wf-margin-left-sm{margin-left:var(--wf-space-sm)}.wf-margin-x-auto{margin-left:auto;margin-right:auto}.wf-margin-y-xs{margin-top:var(--wf-space-xs);margin-bottom:var(--wf-space-xs)}.wf-gap-none{gap:0}.wf-gap-xs{gap:var(--wf-gap-xs)}.wf-gap-sm{gap:var(--wf-gap-sm)}.wf-gap-md{gap:var(--wf-gap-md)}.wf-gap-lg{gap:var(--wf-gap-lg)}.wf-gap-xl{gap:var(--wf-gap-xl)}.wf-width-full{width:100%}.wf-width-sm{width:var(--wf-w-sm, 480px)}.wf-height-full{height:100%}}@layer utilities{:where(.wf-block){display:block}}@layer utilities{:where(.wf-flex){display:flex}@media(min-width:640px){.wf-flex\@sm{display:flex}}@media(min-width:1024px){.wf-flex\@lg{display:flex}}}@layer utilities{:where(.wf-hidden){display:none}@media(min-width:1024px){.wf-hidden\@lg{display:none}}.wf-dim{opacity:.7}.wf-pointer{cursor:pointer}}@layer layout{.wf-popup{max-width:min(var(--wf-popup-max, 480px),calc(100vw - 32px));box-sizing:border-box}.wf-popup-mask{position:fixed;inset:0;z-index:var(--wf-z-overlay);background:var(--wf-overlay)}}
|
package/dist/level6/index.js
CHANGED
|
@@ -3214,6 +3214,15 @@ function userSystem(options) {
|
|
|
3214
3214
|
open_registration: false
|
|
3215
3215
|
}).run();
|
|
3216
3216
|
}
|
|
3217
|
+
const defAppId = await findAppIdBySlug("_default");
|
|
3218
|
+
if (defAppId) {
|
|
3219
|
+
const owners = await M.select("user_id").where({ app_id: { eq: BUILTIN_APP_ID }, role: { eq: "owner" } }).run();
|
|
3220
|
+
for (const o of owners) {
|
|
3221
|
+
const uid = String(o.user_id);
|
|
3222
|
+
if (await findMemberRole(defAppId, uid)) continue;
|
|
3223
|
+
await M.insert({ app_id: defAppId, user_id: uid, role: "owner", invited_by: null, source: "migrate" }).onConflict().run();
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3217
3226
|
const leftover = await U.select("id").run();
|
|
3218
3227
|
for (const u of leftover) {
|
|
3219
3228
|
await ensureBuiltinMember(String(u.id), "migrate");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var l=class extends Error{status;constructor(e,t){super(e),this.name="HttpError",this.status=t}};var Y=class extends Error{issues;constructor(e){super(e.map(t=>`${t.path}: ${t.message}`).join("; ")),this.name="ZodError",this.issues=e}},v=class{_meta={};get metaInfo(){return this._meta}meta(e){return this._meta={...this._meta,...e},this}parse(e){let t=this._parse(e);if(!t.ok)throw new Y([{path:t.path??"",message:t.message??"invalid"}]);return t.value}safeParse(e){let t=this._parse(e);return t.ok?{success:!0,data:t.value}:{success:!1,error:new Y([{path:t.path??"",message:t.message??"invalid"}])}}optional(){return new ye(this)}nullable(){return new ke(this)}default(e){return new _e(this,e)}refine(e,t){return new be(this,e,t)}transform(e){return new xe(this,e)}},Q=class extends v{_typeName(){return"string"}_parse(e){if(typeof e!="string")return{ok:!1,path:"",message:"expected string"};let t=e;return this._min!==void 0&&t.length<this._min?{ok:!1,path:"",message:`too small (min ${this._min})`}:this._max!==void 0&&t.length>this._max?{ok:!1,path:"",message:`too big (max ${this._max})`}:this._pattern&&!this._pattern.test(t)?{ok:!1,path:"",message:"invalid pattern"}:this._email&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)?{ok:!1,path:"",message:"invalid email"}:this._uuid&&!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t)?{ok:!1,path:"",message:"invalid uuid"}:{ok:!0,value:t}}_min;_max;_pattern;_email=!1;_uuid=!1;min(e){return this._min=e,this}max(e){return this._max=e,this}regex(e,t){return this._pattern=e,this}email(){return this._email=!0,this}uuid(){return this._uuid=!0,this}},le=class extends v{_typeName(){return"number"}_parse(e){if(typeof e!="number"||Number.isNaN(e))return{ok:!1,path:"",message:"expected number"};let t=e;return this._int&&!Number.isInteger(t)?{ok:!1,path:"",message:"expected integer"}:this._min!==void 0&&t<this._min?{ok:!1,path:"",message:`too small (min ${this._min})`}:this._max!==void 0&&t>this._max?{ok:!1,path:"",message:`too big (max ${this._max})`}:{ok:!0,value:t}}_int=!1;_min;_max;int(){return this._int=!0,this}min(e){return this._min=e,this}max(e){return this._max=e,this}positive(){return this._min=0,this}},de=class extends v{_typeName(){return"boolean"}_parse(e){return typeof e!="boolean"?{ok:!1,path:"",message:"expected boolean"}:{ok:!0,value:e}}},ee=class extends v{lit;constructor(e){super(),this.lit=e}get value(){return this.lit}_typeName(){return"literal"}_parse(e){return e!==this.lit?{ok:!1,path:"",message:`expected literal ${JSON.stringify(this.lit)}`}:{ok:!0,value:e}}},te=class extends v{raw;constructor(e){super(),this.raw=e}get values(){return this.raw}_typeName(){return"enum"}_parse(e){return typeof e!="string"||!this.raw.includes(e)?{ok:!1,path:"",message:`expected one of ${this.raw.join(" | ")}`}:{ok:!0,value:e}}},pe=class extends v{_typeName(){return"datetime"}_parse(e){return typeof e!="string"||Number.isNaN(Date.parse(e))?{ok:!1,path:"",message:"expected datetime string (ISO)"}:{ok:!0,value:e}}},ce=class extends v{dims;constructor(e){super(),this.dims=e}_typeName(){return"vector"}_parse(e){return typeof e!="object"||e===null||!Array.isArray(e)||!e.every(t=>typeof t=="number")?{ok:!1,path:"",message:"expected number[] vector"}:this.dims>0&&e.length!==this.dims?{ok:!1,path:"",message:`expected vector(${this.dims})\u2014\u2014got ${e.length} dims`}:{ok:!0,value:e}}},ge=class extends v{_typeName(){return"json"}_parse(e){return{ok:!0,value:e}}},me=class n extends v{shape;constructor(e){super(),this.shape=e}_typeName(){return"object"}_parse(e){if(typeof e!="object"||e===null||Array.isArray(e))return{ok:!1,path:"",message:"expected object"};let t={},y=[];for(let[w,S]of Object.entries(this.shape)){let A=S._parse(e[w]);if(!A.ok){y.push({path:w,message:A.message??""});continue}t[w]=A.value}return y.length?{ok:!1,path:y[0].path,message:y[0].message}:{ok:!0,value:t}}pick(e){let t={};for(let y of e)t[y]=this.shape[y];return new n(t)}omit(e){let t={};for(let[y,w]of Object.entries(this.shape))e.includes(y)||(t[y]=w);return new n(t)}extend(e){return new n({...this.shape,...e})}},fe=class extends v{inner;constructor(e){super(),this.inner=e}get itemSchema(){return this.inner}_typeName(){return"array"}_parse(e){if(!Array.isArray(e))return{ok:!1,path:"",message:"expected array"};if(this._min!==void 0&&e.length<this._min)return{ok:!1,path:"",message:`too small (min ${this._min})`};if(this._max!==void 0&&e.length>this._max)return{ok:!1,path:"",message:`too big (max ${this._max})`};let t=[];for(let y=0;y<e.length;y++){let w=this.inner._parse(e[y]);if(!w.ok)return{ok:!1,path:`${y}`,message:w.message};t.push(w.value)}return{ok:!0,value:t}}_min;_max;min(e){return this._min=e,this}max(e){return this._max=e,this}},we=class extends v{options;constructor(e){super(),this.options=e}_typeName(){return"union"}_parse(e){let t=null;for(let y of this.options){let w=y._parse(e);if(w.ok)return{ok:!0,value:w.value};t||(t={path:w.path??"",message:w.message??""})}return{ok:!1,path:"",message:`expected union (${t?.message})`}}},he=class extends v{disc;options;discValueOf;constructor(e,t,y){super(),this.disc=e,this.options=t,this.discValueOf=y}_typeName(){return"disUnion"}_parse(e){if(typeof e!="object"||e===null)return{ok:!1,path:"",message:"expected object"};let t=e[this.disc];for(let y of this.options)if(this.discValueOf(y.shape)===t){let w=y._parse(e);return w.ok?{ok:!0,value:w.value}:{ok:!1,path:`(${String(t)})`,message:w.message??""}}return{ok:!1,path:this.disc,message:`invalid discriminator value ${JSON.stringify(t)}`}}};function Ke(n,e){let t=n[e];if(t instanceof ee)return t.lit;if(t instanceof te)return t.values;throw new Error(`z.discriminatedUnion: \u5224\u522B\u5B57\u6BB5\u9700\u4E3A literal/enum\u2014\u2014\u5F97\u5230 ${t?._typeName?.()}`)}var ye=class extends v{inner;constructor(e){super(),this.inner=e}_typeName(){return"optional"}_parse(e){return e===void 0?{ok:!0,value:void 0}:this.inner._parse(e)}},ke=class extends v{inner;constructor(e){super(),this.inner=e}_typeName(){return"nullable"}_parse(e){return e===null?{ok:!0,value:null}:this.inner._parse(e)}},_e=class extends v{inner;d;constructor(e,t){super(),this.inner=e,this.d=t}_typeName(){return"default"}_parse(e){if(e===void 0){let t=typeof this.d=="function"?this.d():this.d;return this.inner._parse(t)}return this.inner._parse(e)}},be=class extends v{inner;fn;msg;constructor(e,t,y){super(),this.inner=e,this.fn=t,this.msg=y}_typeName(){return"effects"}_parse(e){let t=this.inner._parse(e);return t.ok?this.fn(t.value)?{ok:!0,value:t.value}:{ok:!1,path:"",message:this.msg??"refine failed"}:{ok:!1,path:t.path??"",message:t.message??""}}},xe=class extends v{inner;fn;constructor(e,t){super(),this.inner=e,this.fn=t}_typeName(){return"transform"}_parse(e){let t=this.inner._parse(e);return t.ok?{ok:!0,value:this.fn(t.value)}:{ok:!1,path:t.path??"",message:t.message??""}}},i={string:()=>new Q,number:()=>new le,boolean:()=>new de,literal:n=>new ee(n),enum:n=>new te(n),date:()=>new pe,uuid:()=>new Q().uuid(),json:()=>new ge,vector:n=>new ce(n),object:n=>new me(n),array:n=>new fe(n),union:n=>new we(n),discriminatedUnion:(n,e)=>new he(n,e,t=>Ke(t,n))};function z(n,e){return n.meta(e)}var x={pk:n=>z(n,{pk:!0,default:"random"}),req:n=>z(n,{notNull:!0}),col:(n,e)=>z(n,{column:e}),now:n=>z(n,{default:"now"}),unique:n=>z(n,{unique:!0}),dflt:(n,e)=>z(n,{default:e})};import{randomBytes as We,scrypt as ze,timingSafeEqual as He}from"node:crypto";import{promisify as Fe}from"node:util";var Ae=Fe(ze),Ve=64,ne={N:16384,r:8,p:1};async function J(n){let e=We(16),t=await Ae(n,e,Ve,ne);return`scrypt$${ne.N}$${ne.r}$${ne.p}$${e.toString("hex")}$${t.toString("hex")}`}async function re(n,e){let t=e.split("$");if(t.length!==6||t[0]!=="scrypt")return!1;let[,y,w,S,A,q]=t,$=Buffer.from(q,"hex"),U=await Ae(n,Buffer.from(A,"hex"),$.length,{N:Number(y),r:Number(w),p:Number(S)});return U.length===$.length&&He(U,$)}import{createHash as Je,createHmac as je,randomBytes as Ge,timingSafeEqual as Xe}from"node:crypto";var Oe=n=>Buffer.from(JSON.stringify(n)).toString("base64url");function se(n,e,t){let y=Math.floor(Date.now()/1e3),w=`${Oe({alg:"HS256",typ:"JWT"})}.${Oe({...n,iat:y,exp:y+t})}`,S=je("sha256",e).update(w).digest("base64url");return`${w}.${S}`}function ae(n,e){let t=n.split(".");if(t.length!==3)return null;let[y,w,S]=t,A=`${y}.${w}`,q=je("sha256",e).update(A).digest("base64url"),$=Buffer.from(S),U=Buffer.from(q);if($.length!==U.length||!Xe($,U))return null;try{let T=JSON.parse(Buffer.from(w,"base64url").toString("utf8"));return typeof T.exp=="number"&&T.exp<Date.now()/1e3?null:T}catch{return null}}function qe(){return Ge(32).toString("hex")}function ie(n){return Je("sha256").update(n).digest("hex")}function Z(n,e){return Response.json(n,{status:200,...e})}function B(n,e){return Response.json(n,{status:201,...e})}function $e(n){return new Response(null,{status:204,...n})}function H(n){return Response.json({error:n??"Bad Request"},{status:400})}import{randomBytes as Pe}from"node:crypto";var oe={users:{id:x.pk(i.uuid()),email:x.req(i.string()).meta({unique:!0}),password_hash:i.string().nullable(),name:i.string().nullable(),role:i.string().nullable(),tenant:i.string().nullable(),email_verified:i.boolean().meta({notNull:!0,default:!1}),created_at:x.now(i.date())},sessions:{token_hash:x.req(i.string()),user_id:x.req(i.uuid()),app_id:i.string().nullable(),expires_at:x.req(i.date()),revoked_at:i.date().nullable(),created_at:x.now(i.date())},apps:{id:x.pk(i.uuid()),slug:x.req(i.string()).meta({unique:!0}),name:x.req(i.string()),owner_user_id:i.uuid().nullable(),open_registration:i.boolean().meta({notNull:!0,default:!1}),app_key:i.string().nullable(),created_at:x.now(i.date())},members:{app_id:x.req(i.uuid()),user_id:x.req(i.uuid()),role:i.string().meta({notNull:!0,default:"member"}),invited_by:i.uuid().nullable(),joined_at:x.now(i.date()),source:i.string().nullable(),last_login_at:i.date().nullable()}},Ye="_weifuwu_users",Qe="_weifuwu_sessions",Se="_weifuwu_apps",N="00000000-0000-4000-8000-0000000000b1",Ze="_weifuwu_app_members",Ne=8,et=1024;function Te(n){if(n.length<Ne)throw new l(`password must be at least ${Ne} characters`,400);if(n.length>et)throw new l("password is too long",400)}function D(n){return n.trim().toLowerCase()}var Ue=null;async function Me(n){Ue??=await J("dummy-timing-equalize-password"),await re(n,Ue)}function Rt(n){let e=n.orm,t=e.table(Ye,oe.users),y=e.table(Qe,oe.sessions),w=e.table(Se,oe.apps),S=e.table(Ze,oe.members),A=n.secret??process.env.AUTH_SECRET;if(!A)throw new Error("userSystem: secret is required \u2014 pass options.secret or set AUTH_SECRET (at least 32 chars)");if(A.length<16)throw new Error("userSystem: secret must be at least 16 characters");let q=A,$=n.hooks,U=n.allowedRoles??["owner","admin","member","viewer"],T=n.sso??null,ve=n.inviteRoles??U;function Re(a){if(a!==void 0&&!U.includes(a))throw new l(`invalid role: ${a}\uFF08allowed: ${U.join("/")}\uFF09`,403)}let De=n.accessTtlSeconds??3600,Ce=n.refreshTtlDays??30,Ee=n.prefix??"/api/auth",G=a=>({id:String(a.id),email:a.email,name:a.name,role:a.role,tenant:a.tenant}),Be=168*3600;async function ue(a){let g=await t.select("id","email","name","role","tenant").where({id:{eq:a}}).run();return g.length?g[0]:null}async function F(a,g){(await S.select("role").where({app_id:{eq:N},user_id:{eq:a}}).run()).length||await S.insert({app_id:N,user_id:a,role:"member",invited_by:null,source:g}).onConflict().run()}async function P(a,g){let h=await S.select("role").where({app_id:{eq:a},user_id:{eq:g}}).run();return h.length?String(h[0].role):null}async function L(a){let g=await w.select("id").where({slug:{eq:a}}).run();return g.length?String(g[0].id):null}async function K(a){let g=await t.select("id","email","name","role","tenant").where({email:{eq:a}}).run();return g.length?g[0]:null}async function Ie(a){return(await e.query.from(`${Ze} m`).select("m.app_id","m.role","a.id","a.slug","a.name").join(`${Se} a`,{"a.id":{col:"m.app_id"}}).where({"m.user_id":{eq:a}}).run()).filter(h=>!String(h.slug).startsWith("_")).map(h=>({id:String(h.id),slug:String(h.slug),name:String(h.name),role:String(h.role)}))}async function C(a,g){let h=se({sub:a.id,...a.email?{email:a.email}:{},...a.name?{name:a.name}:{},...g?.appId?{appId:g.appId,role:g.role}:{},...!g?.appId&&a.tenant?{tenantId:a.tenant}:{}},q,De),d=qe(),s=new Date(Date.now()+Ce*24*3600*1e3);return await y.insert({token_hash:ie(d),user_id:a.id,expires_at:s.toISOString(),...g?.appId?{app_id:g.appId}:{}}).run(),{token:h,refreshToken:d}}async function Le(a){let g=await y.update({revoked_at:new Date().toISOString()}).where({token_hash:{eq:ie(a)},revoked_at:{isNull:!0}}).returning("user_id","expires_at","app_id").run();if(!g.length)throw new l("Invalid refresh token",401);let h=g[0];if(new Date(String(h.expires_at))<new Date)throw new l("Refresh token expired",401);let d=await ue(h.user_id);if(!d)throw new l("User not found",401);return{user:d,appId:h.app_id?String(h.app_id):void 0}}let E=(async(a,g,h)=>{let d=null,s=null,p={},u,f,R,O=a.headers.get("authorization"),M=null;if(O?.startsWith("Bearer "))M=O.slice(7);else if(a.method==="GET"){let r=new URL(a.url??"","http://localhost"),o=r.searchParams.get("ticket");if(o){let m=ae(o,q);m?.type==="download"&&m?.sub&&(s=await ue(String(m.sub)),d=s,p.userId=String(m.sub),m.appId!=null&&(f=m.appId,p.appId=String(m.appId)))}else M=r.searchParams.get("token")}if(M&&!s){let r=ae(M,q);if(r?.sub){s=await ue(String(r.sub)),d=s;for(let[o,m]of Object.entries(r))o==="sub"||o==="iat"||o==="exp"||o==="type"||(p[o]=m);p.userId=String(r.sub),u=r.tenantId,f=r.appId,R=r.role}}g.user=s,f!=null&&(g.appId=String(f)),g.session=f!=null?{userId:String(s.id),appId:String(f),role:String(R??"")}:null,u!=null&&(g.tenantId=String(u));let W={...p,async register(r){if(!r.email||!r.password)throw new l("email and password are required",400);Te(r.password);let o=D(r.email),m=await J(r.password),c=await t.insert({email:o,password_hash:m,name:r.name??null,role:null,tenant:r.tenant??null}).run(),_=G(c[0]),b=await C(_);return await F(_.id,"register"),d=_,{...b,user:_}},async registerWithApp(r){let o=await this.register({email:r.email,password:r.password,name:r.name});await F(o.user.id,"register");let m=(r.appSlug??r.email.split("@")[1]??"default").trim().toLowerCase(),c=m;for(let k=1;k<=200&&await L(c);k++)c=`${m}-${k}`;let _=await this.createApp({slug:c,name:r.appName??`${r.name??"\u7528\u6237"} \u7684\u5E94\u7528`,openRegistration:!1}),b=await C(o.user,{appId:_.id,role:"owner"});return await $?.onRegisterApp?.(o.user.id,_),{...b,user:o.user,app:{..._,role:"owner"}}},async login(r,o){let c=(await t.select("id","email","password_hash","name","role","tenant").where({email:{eq:D(r)}}).run())[0];if(!c||c.password_hash==null)throw await Me(o),new l("Invalid email or password",401);if(!await re(o,String(c.password_hash)))throw new l("Invalid email or password",401);let b={id:String(c.id),email:String(c.email),name:c.name,role:c.role,tenant:c.tenant},k=await C(b),j=await Ie(b.id);return d=b,{...k,user:b,apps:j}},async logout(r){await y.update({revoked_at:new Date().toISOString()}).where({token_hash:{eq:ie(r)}}).run()},requireAuth(){if(!s)throw new l("Unauthorized",401);return s},async setPassword(r,o){Te(o);let m=await J(o);await t.update({password_hash:m}).where({id:{eq:r}}).run()},createToken(r,o,m){return se({type:r,...o},q,m.ttlSeconds)},async createApp(r){if(!d)throw new l("Unauthorized",401);if(!r.slug||!r.name)throw new l("slug and name are required",400);let o=r.slug.trim().toLowerCase();if(o.startsWith("_"))throw new l("slug \u4EE5 _ \u5F00\u5934\u4E3A\u7CFB\u7EDF\u4FDD\u7559\u540D",400);if(!await P(N,d.id))throw new l("\u4EC5\u5E94\u7528\u7BA1\u7406\u9762\uFF08_builtin\uFF09\u6210\u5458\u53EF\u521B\u5EFA\u5E94\u7528",403);let c=Pe(32).toString("hex"),b=(await w.insert({slug:o,name:r.name,owner_user_id:d.id,open_registration:r.openRegistration??!1,app_key:c}).run())[0];return await S.insert({app_id:b.id,user_id:d.id,role:"owner",invited_by:d.id}).run(),b},async registerInApp(r){if(!r.email||!r.password)throw new l("email and password are required",400);Te(r.password);let o=await w.select("id","open_registration").where({slug:{eq:r.appSlug}}).run();if(!o.length)throw new l("Application not found",404);let m=o[0],c=String(m.id),_=D(r.email),b="member";if(!m.open_registration){if(!r.inviteToken)throw new l("Registration closed for this application",403);let I=ae(r.inviteToken,q);if(!I||I.type!=="app-invite"||I.appId!==c)throw new l("Invalid invite",403);if(I.email&&String(I.email)!==_)throw new l("Invite email mismatch",403);typeof I.role=="string"&&I.role!=="owner"&&(Re(I.role),b=I.role)}let k=await K(_);if(!k){let I=await J(r.password),X=await t.insert({email:_,password_hash:I,name:r.name??null,role:null,tenant:null}).onConflict("email").run();if(k=X.length?G(X[0]):await K(_),!k)throw new l("User creation failed",500)}await F(k.id,"register"),await P(c,k.id)||await S.insert({app_id:c,user_id:k.id,role:b,invited_by:d?.id??null,source:"invite"}).onConflict().run();let V=await C(k,{appId:c,role:b});return await S.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:c},user_id:{eq:k.id}}).run(),d=k,await $?.onJoinApp?.(k.id,c,b),{...V,user:k}},async loginApp(r,o,m){let c=await w.select("id").where({slug:{eq:r}}).run();if(!c.length)throw new l("Application not found",404);let _=String(c[0].id),k=(await t.select("id","email","password_hash","name","role","tenant").where({email:{eq:D(o)}}).run())[0];if(!k||k.password_hash==null)throw await Me(m),new l("Invalid email or password",401);if(!await re(m,String(k.password_hash)))throw new l("Invalid email or password",401);let V=await P(_,String(k.id));if(!V)throw new l("Not a member of this application",401);let I={id:String(k.id),email:String(k.email),name:k.name,role:k.role,tenant:k.tenant},X=await C(I,{appId:_,role:V});return await S.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:_},user_id:{eq:I.id}}).run(),d=I,{...X,user:I,role:V}},async ssoLogin(r,o){let m=D(r),c=await K(m);if(!c){let k=await t.insert({email:m,password_hash:null,name:o?.name??null,role:null,tenant:null}).onConflict("email").run();if(c=k.length?G(k[0]):await K(m),!c)throw new l("User creation failed",500)}await F(c.id,"sso");let _;o?.appId&&(await P(o.appId,c.id)||await S.insert({app_id:o.appId,user_id:c.id,role:"member",invited_by:null,source:"sso"}).onConflict().run(),_=o.appId,await S.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:o.appId},user_id:{eq:c.id}}).run());let b=await C(c,_?{appId:_,role:"member"}:void 0);return d=c,{...b,user:c}},async createInvite(r,o){if(r===N)throw new l("_builtin \u4E0D\u8D70\u9080\u8BF7\u6D41\uFF08\u4EFB\u547D\u5236\uFF09",403);if(o.role!==void 0&&!ve.includes(o.role))throw new l(`invite role not allowed: ${o.role}\uFF08allowed: ${ve.join("/")}\uFF09`,403);if(!d)throw new l("Unauthorized",401);if(await P(r,d.id)!=="owner")throw new l("Owner only",403);let c=o.role&&o.role!=="owner"?o.role:"member";return{inviteToken:se({type:"app-invite",appId:r,...o.email?{email:D(o.email)}:{},role:c},q,Be)}},async addMember(r,o,m){if(Re(m),r===N&&m!==void 0&&m==="viewer")throw new l("_builtin \u65E0\u53EA\u8BFB\uFF08viewer \u7981\u2014\u2014\u7BA1\u7406\u9762\u8EAB\u4EFD\uFF09",403);if(!d)throw new l("Unauthorized",401);if(await P(r,d.id)!=="owner")throw new l("Owner only",403);let _=await t.select("id").where({email:{eq:D(o)}}).run();if(!_.length)throw new l("User not found \u2014 invite them to register first",400);let b=m&&m!=="owner"?m:"member";await S.insert({app_id:r,user_id:String(_[0].id),role:b,invited_by:d.id}).run()},async setOpenRegistration(r,o){if(!d)throw new l("Unauthorized",401);if(r===N)throw new l("_builtin \u6CE8\u518C\u5F00\u5173\u6052 false",403);if(await P(r,d.id)!=="owner")throw new l("Owner only",403);await w.update({open_registration:o}).where({id:{eq:r}}).run()},async listMyApps(){if(!d)throw new l("Unauthorized",401);return Ie(d.id)},async requireApp(r){if(!d)throw new l("Unauthorized",401);let o=await P(r,d.id);if(!o)throw new l("Not a member of this application",403);return{userId:d.id,appId:r,role:o}}};return g.auth=W,h(a,g)});return E.__meta={injects:["user","auth"],depends:[]},E.seedBuiltinOwners=async a=>{let g={owner:null,admins:[]};for(let h of a){let d=D(h);if(!d)continue;let s=await K(d);if(!s){let u=await t.insert({email:d,password_hash:null,name:null,role:null,tenant:null}).onConflict("email").run();s=u.length?G(u[0]):await K(d)}if(!s)continue;let p=await S.select("role").where({app_id:{eq:N},user_id:{eq:s.id}}).run();if(p.length){String(p[0].role??"")==="owner"?g.owner=String(s.id):g.admins.push(String(s.id));continue}if(g.owner)await S.insert({app_id:N,user_id:String(s.id),role:"admin",invited_by:g.owner,source:"seed"}).run(),g.admins.push(String(s.id));else{await S.insert({app_id:N,user_id:String(s.id),role:"owner",invited_by:null,source:"seed"}).run(),g.owner=String(s.id);let u=await L("_default");u&&(await P(u,String(s.id))||await S.insert({app_id:u,user_id:String(s.id),role:"owner",invited_by:null,source:"seed"}).run())}}return g},E.migrate=async()=>{(await w.select("id").where({slug:{eq:"_builtin"}}).run()).length||await e.query.insert(Se).values({id:N,slug:"_builtin",name:"System",owner_user_id:null,open_registration:!1}).returning("id").run();let g=await w.select("id").where({app_key:{isNull:!0}}).run();for(let s of g)await w.update({app_key:Pe(32).toString("hex")}).where({id:{eq:String(s.id)}}).run();(await w.select("id").where({slug:{eq:"_default"}}).run()).length||await w.insert({slug:"_default",name:"Default",owner_user_id:null,open_registration:!1}).run();let d=await t.select("id").run();for(let s of d)await F(String(s.id),"migrate")},E.routes=(a,g)=>{let h=g?.prefix??Ee,d=new Set(g?.exclude??[]);if(d.has("register")||a.post(`${h}/register`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await p.auth.register(u);return B(f)}),d.has("register")||a.post(`${h}/register-app`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await p.auth.registerWithApp(u);return B(f)}),d.has("login")||a.post(`${h}/login`,async(s,p)=>{let u=await s.json().catch(()=>({}));if(!u.email||!u.password)return H("email and password are required");let f=await p.auth.login(u.email,u.password);return Z(f)}),d.has("logout")||a.post(`${h}/logout`,async(s,p)=>{let u=await s.json().catch(()=>({}));return u.refreshToken?(await p.auth.logout(u.refreshToken),$e()):H("refreshToken is required")}),d.has("refresh")||a.post(`${h}/refresh`,async(s,p)=>{let u=await s.json().catch(()=>({}));if(!u.refreshToken)throw new l("refreshToken is required",400);let{user:f,appId:R}=await Le(u.refreshToken),O;if(R){let W=await P(R,f.id);W&&(O={appId:R,role:W})}let M=await C(f,O);return Z({...M,user:f})}),d.has("me")||a.get(`${h}/me`,async(s,p)=>{if(!p.user)throw new l("Unauthorized",401);return Z({user:p.user,session:p.session??null})}),T){let s=`${h}/apps/_builtin/auth/sso`;a.get(`${s}/enabled`,async()=>Z({enabled:!0,appSlug:T.defaultAppSlug??null})),a.get(`${s}/login`,async p=>{let f=new URL(p.url??"","http://localhost").searchParams.get("app")??T.defaultAppSlug,R=new URLSearchParams({response_type:"code",client_id:T.clientId,redirect_uri:T.redirectBase?`${T.redirectBase.replace(/\/$/,"")}${s}/callback`:`${new URL(p.url,"http://localhost").origin}${s}/callback`,scope:T.scope??"openid email profile",state:f??"sso"});return new Response(null,{status:302,headers:{Location:`${T.issuer.replace(/\/$/,"")}/authorize?${R}`}})}),a.get(`${s}/callback`,async(p,u)=>{let f=new URL(p.url??"","http://localhost"),R=f.searchParams.get("code");if(!R)throw new l("SSO \u56DE\u8C03\u7F3A\u5C11 code",400);let O=T.redirectBase?`${T.redirectBase.replace(/\/$/,"")}${s}/callback`:`${f.origin}${s}/callback`,M=await fetch(`${T.issuer.replace(/\/$/,"")}/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:R,redirect_uri:O,client_id:T.clientId,client_secret:T.clientSecret})});if(!M.ok)throw new l("SSO token \u4EA4\u6362\u5931\u8D25",401);let W=await M.json(),r=await fetch(`${T.issuer.replace(/\/$/,"")}/userinfo`,{headers:{Authorization:`Bearer ${W.access_token}`}});if(!r.ok)throw new l("SSO \u7528\u6237\u4FE1\u606F\u83B7\u53D6\u5931\u8D25",401);let o=await r.json(),m=(o.email??"").trim().toLowerCase();if(!m)throw new l("SSO \u672A\u8FD4\u56DE\u90AE\u7BB1\uFF08\u9700\u8981 email scope\uFF09",401);let c=f.searchParams.get("state"),_;if(c&&c!=="sso"){let j=await L(c);j&&(_=j)}let b=await u.auth.ssoLogin(m,{appId:_,name:o.name});await $?.onSsoLogin?.(b.user.id,_);let k={token:b.token,refreshToken:b.refreshToken,user:b.user};if(T.renderCallback){let j=T.renderCallback(k);return typeof j=="string"?new Response(j,{headers:{"Content-Type":"text/html; charset=utf-8"}}):j}return Z(k)})}d.has("apps")||(a.post(`${h}/apps`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await p.auth.createApp(u);return B({app:f})}),a.get(`${h}/apps`,async(s,p)=>{let u=await p.auth.listMyApps();return Z({apps:u})}),a.post(`${h}/apps/:appSlug/auth/members`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await L(p.params.appSlug);if(!f)throw new l("Application not found",404);return await p.auth.addMember(f,u.email??"",u.role),B({ok:!0})}),a.post(`${h}/apps/:appSlug/auth/invites`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await L(p.params.appSlug);if(!f)throw new l("Application not found",404);let R=await p.auth.createInvite(f,{email:u.email,role:u.role});return B(R)}),a.post(`${h}/apps/:appSlug/auth/login`,async(s,p)=>{let u=await s.json().catch(()=>({}));if(!u.email||!u.password)return H("email and password are required");let f=await p.auth.loginApp(p.params.appSlug,u.email,u.password);return Z(f)}),a.patch(`${h}/apps/:appSlug/auth/registration`,async(s,p)=>{let u=await s.json().catch(()=>({}));if(typeof u.open!="boolean")return H("open is required (boolean)");let f=await L(p.params.appSlug);if(!f)throw new l("Application not found",404);return await p.auth.setOpenRegistration(f,u.open),Z({open:u.open})}),a.post(`${h}/apps/:appSlug/auth/verify`,async(s,p)=>{let u=s.headers.get("x-wf-app-id"),f=s.headers.get("x-wf-app-key");if(!u||!f)return H("X-Wf-App-Id / X-Wf-App-Key required");let R=await w.select("id","slug","name").where({id:{eq:u},app_key:{eq:f}}).run();if(!R.length)throw new l("Invalid app credentials",403);let O=R[0];return Z({app:{id:String(O.id),slug:String(O.slug),name:String(O.name)}})}),a.post(`${h}/apps/:appSlug/auth/register`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await p.auth.registerInApp({appSlug:p.params.appSlug,email:u.email??"",password:u.password??"",name:u.name,inviteToken:u.inviteToken});return B(f)}))},E.asAppAuth=()=>E,E}var It={tables:[{name:"_weifuwu_users",columns:{id:x.pk(i.uuid()),email:x.req(i.string()).meta({unique:!0}),password_hash:i.string(),name:i.string(),role:i.string(),tenant:i.string(),email_verified:i.boolean().meta({default:!1}),created_at:i.date().meta({default:"now"})},dropNotNull:["password_hash"]},{name:"_weifuwu_sessions",columns:{token_hash:i.string().meta({pk:!0}),user_id:x.req(i.uuid()).meta({references:"_weifuwu_users",onDelete:"cascade"}),app_id:i.string(),expires_at:i.date().meta({notNull:!0}),revoked_at:i.date(),created_at:i.date().meta({default:"now"})}},{name:"_weifuwu_apps",columns:{id:x.pk(i.uuid()),slug:x.req(i.string()).meta({unique:!0}),name:x.req(i.string()),owner_user_id:i.uuid().meta({references:"_weifuwu_users",onDelete:"cascade"}),open_registration:i.boolean().meta({default:!1}),created_at:i.date().meta({default:"now"}),app_key:i.string()}},{name:"_weifuwu_app_members",columns:{app_id:x.req(i.uuid()).meta({references:"_weifuwu_apps",onDelete:"cascade"}),user_id:x.req(i.uuid()).meta({references:"_weifuwu_users",onDelete:"cascade"}),role:i.string().meta({default:"member"}),invited_by:i.uuid(),joined_at:i.date().meta({default:"now"}),source:i.string(),last_login_at:i.date()},uniques:[["app_id","user_id"]]}]};export{N as BUILTIN_APP_ID,oe as USER_TABLES,It as WEIFUWU_USER_SCHEMA,Rt as userSystem};
|
|
1
|
+
var l=class extends Error{status;constructor(e,t){super(e),this.name="HttpError",this.status=t}};var Y=class extends Error{issues;constructor(e){super(e.map(t=>`${t.path}: ${t.message}`).join("; ")),this.name="ZodError",this.issues=e}},v=class{_meta={};get metaInfo(){return this._meta}meta(e){return this._meta={...this._meta,...e},this}parse(e){let t=this._parse(e);if(!t.ok)throw new Y([{path:t.path??"",message:t.message??"invalid"}]);return t.value}safeParse(e){let t=this._parse(e);return t.ok?{success:!0,data:t.value}:{success:!1,error:new Y([{path:t.path??"",message:t.message??"invalid"}])}}optional(){return new ye(this)}nullable(){return new _e(this)}default(e){return new ke(this,e)}refine(e,t){return new be(this,e,t)}transform(e){return new xe(this,e)}},Q=class extends v{_typeName(){return"string"}_parse(e){if(typeof e!="string")return{ok:!1,path:"",message:"expected string"};let t=e;return this._min!==void 0&&t.length<this._min?{ok:!1,path:"",message:`too small (min ${this._min})`}:this._max!==void 0&&t.length>this._max?{ok:!1,path:"",message:`too big (max ${this._max})`}:this._pattern&&!this._pattern.test(t)?{ok:!1,path:"",message:"invalid pattern"}:this._email&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)?{ok:!1,path:"",message:"invalid email"}:this._uuid&&!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t)?{ok:!1,path:"",message:"invalid uuid"}:{ok:!0,value:t}}_min;_max;_pattern;_email=!1;_uuid=!1;min(e){return this._min=e,this}max(e){return this._max=e,this}regex(e,t){return this._pattern=e,this}email(){return this._email=!0,this}uuid(){return this._uuid=!0,this}},le=class extends v{_typeName(){return"number"}_parse(e){if(typeof e!="number"||Number.isNaN(e))return{ok:!1,path:"",message:"expected number"};let t=e;return this._int&&!Number.isInteger(t)?{ok:!1,path:"",message:"expected integer"}:this._min!==void 0&&t<this._min?{ok:!1,path:"",message:`too small (min ${this._min})`}:this._max!==void 0&&t>this._max?{ok:!1,path:"",message:`too big (max ${this._max})`}:{ok:!0,value:t}}_int=!1;_min;_max;int(){return this._int=!0,this}min(e){return this._min=e,this}max(e){return this._max=e,this}positive(){return this._min=0,this}},de=class extends v{_typeName(){return"boolean"}_parse(e){return typeof e!="boolean"?{ok:!1,path:"",message:"expected boolean"}:{ok:!0,value:e}}},ee=class extends v{lit;constructor(e){super(),this.lit=e}get value(){return this.lit}_typeName(){return"literal"}_parse(e){return e!==this.lit?{ok:!1,path:"",message:`expected literal ${JSON.stringify(this.lit)}`}:{ok:!0,value:e}}},te=class extends v{raw;constructor(e){super(),this.raw=e}get values(){return this.raw}_typeName(){return"enum"}_parse(e){return typeof e!="string"||!this.raw.includes(e)?{ok:!1,path:"",message:`expected one of ${this.raw.join(" | ")}`}:{ok:!0,value:e}}},pe=class extends v{_typeName(){return"datetime"}_parse(e){return typeof e!="string"||Number.isNaN(Date.parse(e))?{ok:!1,path:"",message:"expected datetime string (ISO)"}:{ok:!0,value:e}}},ce=class extends v{dims;constructor(e){super(),this.dims=e}_typeName(){return"vector"}_parse(e){return typeof e!="object"||e===null||!Array.isArray(e)||!e.every(t=>typeof t=="number")?{ok:!1,path:"",message:"expected number[] vector"}:this.dims>0&&e.length!==this.dims?{ok:!1,path:"",message:`expected vector(${this.dims})\u2014\u2014got ${e.length} dims`}:{ok:!0,value:e}}},ge=class extends v{_typeName(){return"json"}_parse(e){return{ok:!0,value:e}}},me=class n extends v{shape;constructor(e){super(),this.shape=e}_typeName(){return"object"}_parse(e){if(typeof e!="object"||e===null||Array.isArray(e))return{ok:!1,path:"",message:"expected object"};let t={},y=[];for(let[w,x]of Object.entries(this.shape)){let A=x._parse(e[w]);if(!A.ok){y.push({path:w,message:A.message??""});continue}t[w]=A.value}return y.length?{ok:!1,path:y[0].path,message:y[0].message}:{ok:!0,value:t}}pick(e){let t={};for(let y of e)t[y]=this.shape[y];return new n(t)}omit(e){let t={};for(let[y,w]of Object.entries(this.shape))e.includes(y)||(t[y]=w);return new n(t)}extend(e){return new n({...this.shape,...e})}},fe=class extends v{inner;constructor(e){super(),this.inner=e}get itemSchema(){return this.inner}_typeName(){return"array"}_parse(e){if(!Array.isArray(e))return{ok:!1,path:"",message:"expected array"};if(this._min!==void 0&&e.length<this._min)return{ok:!1,path:"",message:`too small (min ${this._min})`};if(this._max!==void 0&&e.length>this._max)return{ok:!1,path:"",message:`too big (max ${this._max})`};let t=[];for(let y=0;y<e.length;y++){let w=this.inner._parse(e[y]);if(!w.ok)return{ok:!1,path:`${y}`,message:w.message};t.push(w.value)}return{ok:!0,value:t}}_min;_max;min(e){return this._min=e,this}max(e){return this._max=e,this}},we=class extends v{options;constructor(e){super(),this.options=e}_typeName(){return"union"}_parse(e){let t=null;for(let y of this.options){let w=y._parse(e);if(w.ok)return{ok:!0,value:w.value};t||(t={path:w.path??"",message:w.message??""})}return{ok:!1,path:"",message:`expected union (${t?.message})`}}},he=class extends v{disc;options;discValueOf;constructor(e,t,y){super(),this.disc=e,this.options=t,this.discValueOf=y}_typeName(){return"disUnion"}_parse(e){if(typeof e!="object"||e===null)return{ok:!1,path:"",message:"expected object"};let t=e[this.disc];for(let y of this.options)if(this.discValueOf(y.shape)===t){let w=y._parse(e);return w.ok?{ok:!0,value:w.value}:{ok:!1,path:`(${String(t)})`,message:w.message??""}}return{ok:!1,path:this.disc,message:`invalid discriminator value ${JSON.stringify(t)}`}}};function Ke(n,e){let t=n[e];if(t instanceof ee)return t.lit;if(t instanceof te)return t.values;throw new Error(`z.discriminatedUnion: \u5224\u522B\u5B57\u6BB5\u9700\u4E3A literal/enum\u2014\u2014\u5F97\u5230 ${t?._typeName?.()}`)}var ye=class extends v{inner;constructor(e){super(),this.inner=e}_typeName(){return"optional"}_parse(e){return e===void 0?{ok:!0,value:void 0}:this.inner._parse(e)}},_e=class extends v{inner;constructor(e){super(),this.inner=e}_typeName(){return"nullable"}_parse(e){return e===null?{ok:!0,value:null}:this.inner._parse(e)}},ke=class extends v{inner;d;constructor(e,t){super(),this.inner=e,this.d=t}_typeName(){return"default"}_parse(e){if(e===void 0){let t=typeof this.d=="function"?this.d():this.d;return this.inner._parse(t)}return this.inner._parse(e)}},be=class extends v{inner;fn;msg;constructor(e,t,y){super(),this.inner=e,this.fn=t,this.msg=y}_typeName(){return"effects"}_parse(e){let t=this.inner._parse(e);return t.ok?this.fn(t.value)?{ok:!0,value:t.value}:{ok:!1,path:"",message:this.msg??"refine failed"}:{ok:!1,path:t.path??"",message:t.message??""}}},xe=class extends v{inner;fn;constructor(e,t){super(),this.inner=e,this.fn=t}_typeName(){return"transform"}_parse(e){let t=this.inner._parse(e);return t.ok?{ok:!0,value:this.fn(t.value)}:{ok:!1,path:t.path??"",message:t.message??""}}},o={string:()=>new Q,number:()=>new le,boolean:()=>new de,literal:n=>new ee(n),enum:n=>new te(n),date:()=>new pe,uuid:()=>new Q().uuid(),json:()=>new ge,vector:n=>new ce(n),object:n=>new me(n),array:n=>new fe(n),union:n=>new we(n),discriminatedUnion:(n,e)=>new he(n,e,t=>Ke(t,n))};function z(n,e){return n.meta(e)}var S={pk:n=>z(n,{pk:!0,default:"random"}),req:n=>z(n,{notNull:!0}),col:(n,e)=>z(n,{column:e}),now:n=>z(n,{default:"now"}),unique:n=>z(n,{unique:!0}),dflt:(n,e)=>z(n,{default:e})};import{randomBytes as We,scrypt as ze,timingSafeEqual as He}from"node:crypto";import{promisify as Fe}from"node:util";var Ae=Fe(ze),Ve=64,ne={N:16384,r:8,p:1};async function J(n){let e=We(16),t=await Ae(n,e,Ve,ne);return`scrypt$${ne.N}$${ne.r}$${ne.p}$${e.toString("hex")}$${t.toString("hex")}`}async function re(n,e){let t=e.split("$");if(t.length!==6||t[0]!=="scrypt")return!1;let[,y,w,x,A,P]=t,Z=Buffer.from(P,"hex"),U=await Ae(n,Buffer.from(A,"hex"),Z.length,{N:Number(y),r:Number(w),p:Number(x)});return U.length===Z.length&&He(U,Z)}import{createHash as Je,createHmac as qe,randomBytes as Ge,timingSafeEqual as Xe}from"node:crypto";var Oe=n=>Buffer.from(JSON.stringify(n)).toString("base64url");function se(n,e,t){let y=Math.floor(Date.now()/1e3),w=`${Oe({alg:"HS256",typ:"JWT"})}.${Oe({...n,iat:y,exp:y+t})}`,x=qe("sha256",e).update(w).digest("base64url");return`${w}.${x}`}function ae(n,e){let t=n.split(".");if(t.length!==3)return null;let[y,w,x]=t,A=`${y}.${w}`,P=qe("sha256",e).update(A).digest("base64url"),Z=Buffer.from(x),U=Buffer.from(P);if(Z.length!==U.length||!Xe(Z,U))return null;try{let T=JSON.parse(Buffer.from(w,"base64url").toString("utf8"));return typeof T.exp=="number"&&T.exp<Date.now()/1e3?null:T}catch{return null}}function je(){return Ge(32).toString("hex")}function ie(n){return Je("sha256").update(n).digest("hex")}function N(n,e){return Response.json(n,{status:200,...e})}function L(n,e){return Response.json(n,{status:201,...e})}function $e(n){return new Response(null,{status:204,...n})}function H(n){return Response.json({error:n??"Bad Request"},{status:400})}import{randomBytes as Pe}from"node:crypto";var oe={users:{id:S.pk(o.uuid()),email:S.req(o.string()).meta({unique:!0}),password_hash:o.string().nullable(),name:o.string().nullable(),role:o.string().nullable(),tenant:o.string().nullable(),email_verified:o.boolean().meta({notNull:!0,default:!1}),created_at:S.now(o.date())},sessions:{token_hash:S.req(o.string()),user_id:S.req(o.uuid()),app_id:o.string().nullable(),expires_at:S.req(o.date()),revoked_at:o.date().nullable(),created_at:S.now(o.date())},apps:{id:S.pk(o.uuid()),slug:S.req(o.string()).meta({unique:!0}),name:S.req(o.string()),owner_user_id:o.uuid().nullable(),open_registration:o.boolean().meta({notNull:!0,default:!1}),app_key:o.string().nullable(),created_at:S.now(o.date())},members:{app_id:S.req(o.uuid()),user_id:S.req(o.uuid()),role:o.string().meta({notNull:!0,default:"member"}),invited_by:o.uuid().nullable(),joined_at:S.now(o.date()),source:o.string().nullable(),last_login_at:o.date().nullable()}},Ye="_weifuwu_users",Qe="_weifuwu_sessions",Se="_weifuwu_apps",$="00000000-0000-4000-8000-0000000000b1",Ze="_weifuwu_app_members",Ne=8,et=1024;function Te(n){if(n.length<Ne)throw new l(`password must be at least ${Ne} characters`,400);if(n.length>et)throw new l("password is too long",400)}function D(n){return n.trim().toLowerCase()}var Ue=null;async function Me(n){Ue??=await J("dummy-timing-equalize-password"),await re(n,Ue)}function Rt(n){let e=n.orm,t=e.table(Ye,oe.users),y=e.table(Qe,oe.sessions),w=e.table(Se,oe.apps),x=e.table(Ze,oe.members),A=n.secret??process.env.AUTH_SECRET;if(!A)throw new Error("userSystem: secret is required \u2014 pass options.secret or set AUTH_SECRET (at least 32 chars)");if(A.length<16)throw new Error("userSystem: secret must be at least 16 characters");let P=A,Z=n.hooks,U=n.allowedRoles??["owner","admin","member","viewer"],T=n.sso??null,ve=n.inviteRoles??U;function Re(a){if(a!==void 0&&!U.includes(a))throw new l(`invalid role: ${a}\uFF08allowed: ${U.join("/")}\uFF09`,403)}let De=n.accessTtlSeconds??3600,Ce=n.refreshTtlDays??30,Ee=n.prefix??"/api/auth",G=a=>({id:String(a.id),email:a.email,name:a.name,role:a.role,tenant:a.tenant}),Be=168*3600;async function ue(a){let m=await t.select("id","email","name","role","tenant").where({id:{eq:a}}).run();return m.length?m[0]:null}async function F(a,m){(await x.select("role").where({app_id:{eq:$},user_id:{eq:a}}).run()).length||await x.insert({app_id:$,user_id:a,role:"member",invited_by:null,source:m}).onConflict().run()}async function O(a,m){let h=await x.select("role").where({app_id:{eq:a},user_id:{eq:m}}).run();return h.length?String(h[0].role):null}async function C(a){let m=await w.select("id").where({slug:{eq:a}}).run();return m.length?String(m[0].id):null}async function K(a){let m=await t.select("id","email","name","role","tenant").where({email:{eq:a}}).run();return m.length?m[0]:null}async function Ie(a){return(await e.query.from(`${Ze} m`).select("m.app_id","m.role","a.id","a.slug","a.name").join(`${Se} a`,{"a.id":{col:"m.app_id"}}).where({"m.user_id":{eq:a}}).run()).filter(h=>!String(h.slug).startsWith("_")).map(h=>({id:String(h.id),slug:String(h.slug),name:String(h.name),role:String(h.role)}))}async function E(a,m){let h=se({sub:a.id,...a.email?{email:a.email}:{},...a.name?{name:a.name}:{},...m?.appId?{appId:m.appId,role:m.role}:{},...!m?.appId&&a.tenant?{tenantId:a.tenant}:{}},P,De),p=je(),s=new Date(Date.now()+Ce*24*3600*1e3);return await y.insert({token_hash:ie(p),user_id:a.id,expires_at:s.toISOString(),...m?.appId?{app_id:m.appId}:{}}).run(),{token:h,refreshToken:p}}async function Le(a){let m=await y.update({revoked_at:new Date().toISOString()}).where({token_hash:{eq:ie(a)},revoked_at:{isNull:!0}}).returning("user_id","expires_at","app_id").run();if(!m.length)throw new l("Invalid refresh token",401);let h=m[0];if(new Date(String(h.expires_at))<new Date)throw new l("Refresh token expired",401);let p=await ue(h.user_id);if(!p)throw new l("User not found",401);return{user:p,appId:h.app_id?String(h.app_id):void 0}}let B=(async(a,m,h)=>{let p=null,s=null,d={},i,c,R,q=a.headers.get("authorization"),M=null;if(q?.startsWith("Bearer "))M=q.slice(7);else if(a.method==="GET"){let r=new URL(a.url??"","http://localhost"),u=r.searchParams.get("ticket");if(u){let f=ae(u,P);f?.type==="download"&&f?.sub&&(s=await ue(String(f.sub)),p=s,d.userId=String(f.sub),f.appId!=null&&(c=f.appId,d.appId=String(f.appId)))}else M=r.searchParams.get("token")}if(M&&!s){let r=ae(M,P);if(r?.sub){s=await ue(String(r.sub)),p=s;for(let[u,f]of Object.entries(r))u==="sub"||u==="iat"||u==="exp"||u==="type"||(d[u]=f);d.userId=String(r.sub),i=r.tenantId,c=r.appId,R=r.role}}m.user=s,c!=null&&(m.appId=String(c)),m.session=c!=null?{userId:String(s.id),appId:String(c),role:String(R??"")}:null,i!=null&&(m.tenantId=String(i));let W={...d,async register(r){if(!r.email||!r.password)throw new l("email and password are required",400);Te(r.password);let u=D(r.email),f=await J(r.password),g=await t.insert({email:u,password_hash:f,name:r.name??null,role:null,tenant:r.tenant??null}).run(),k=G(g[0]),b=await E(k);return await F(k.id,"register"),p=k,{...b,user:k}},async registerWithApp(r){let u=await this.register({email:r.email,password:r.password,name:r.name});await F(u.user.id,"register");let f=(r.appSlug??r.email.split("@")[1]??"default").trim().toLowerCase(),g=f;for(let _=1;_<=200&&await C(g);_++)g=`${f}-${_}`;let k=await this.createApp({slug:g,name:r.appName??`${r.name??"\u7528\u6237"} \u7684\u5E94\u7528`,openRegistration:!1}),b=await E(u.user,{appId:k.id,role:"owner"});return await Z?.onRegisterApp?.(u.user.id,k),{...b,user:u.user,app:{...k,role:"owner"}}},async login(r,u){let g=(await t.select("id","email","password_hash","name","role","tenant").where({email:{eq:D(r)}}).run())[0];if(!g||g.password_hash==null)throw await Me(u),new l("Invalid email or password",401);if(!await re(u,String(g.password_hash)))throw new l("Invalid email or password",401);let b={id:String(g.id),email:String(g.email),name:g.name,role:g.role,tenant:g.tenant},_=await E(b),j=await Ie(b.id);return p=b,{..._,user:b,apps:j}},async logout(r){await y.update({revoked_at:new Date().toISOString()}).where({token_hash:{eq:ie(r)}}).run()},requireAuth(){if(!s)throw new l("Unauthorized",401);return s},async setPassword(r,u){Te(u);let f=await J(u);await t.update({password_hash:f}).where({id:{eq:r}}).run()},createToken(r,u,f){return se({type:r,...u},P,f.ttlSeconds)},async createApp(r){if(!p)throw new l("Unauthorized",401);if(!r.slug||!r.name)throw new l("slug and name are required",400);let u=r.slug.trim().toLowerCase();if(u.startsWith("_"))throw new l("slug \u4EE5 _ \u5F00\u5934\u4E3A\u7CFB\u7EDF\u4FDD\u7559\u540D",400);if(!await O($,p.id))throw new l("\u4EC5\u5E94\u7528\u7BA1\u7406\u9762\uFF08_builtin\uFF09\u6210\u5458\u53EF\u521B\u5EFA\u5E94\u7528",403);let g=Pe(32).toString("hex"),b=(await w.insert({slug:u,name:r.name,owner_user_id:p.id,open_registration:r.openRegistration??!1,app_key:g}).run())[0];return await x.insert({app_id:b.id,user_id:p.id,role:"owner",invited_by:p.id}).run(),b},async registerInApp(r){if(!r.email||!r.password)throw new l("email and password are required",400);Te(r.password);let u=await w.select("id","open_registration").where({slug:{eq:r.appSlug}}).run();if(!u.length)throw new l("Application not found",404);let f=u[0],g=String(f.id),k=D(r.email),b="member";if(!f.open_registration){if(!r.inviteToken)throw new l("Registration closed for this application",403);let I=ae(r.inviteToken,P);if(!I||I.type!=="app-invite"||I.appId!==g)throw new l("Invalid invite",403);if(I.email&&String(I.email)!==k)throw new l("Invite email mismatch",403);typeof I.role=="string"&&I.role!=="owner"&&(Re(I.role),b=I.role)}let _=await K(k);if(!_){let I=await J(r.password),X=await t.insert({email:k,password_hash:I,name:r.name??null,role:null,tenant:null}).onConflict("email").run();if(_=X.length?G(X[0]):await K(k),!_)throw new l("User creation failed",500)}await F(_.id,"register"),await O(g,_.id)||await x.insert({app_id:g,user_id:_.id,role:b,invited_by:p?.id??null,source:"invite"}).onConflict().run();let V=await E(_,{appId:g,role:b});return await x.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:g},user_id:{eq:_.id}}).run(),p=_,await Z?.onJoinApp?.(_.id,g,b),{...V,user:_}},async loginApp(r,u,f){let g=await w.select("id").where({slug:{eq:r}}).run();if(!g.length)throw new l("Application not found",404);let k=String(g[0].id),_=(await t.select("id","email","password_hash","name","role","tenant").where({email:{eq:D(u)}}).run())[0];if(!_||_.password_hash==null)throw await Me(f),new l("Invalid email or password",401);if(!await re(f,String(_.password_hash)))throw new l("Invalid email or password",401);let V=await O(k,String(_.id));if(!V)throw new l("Not a member of this application",401);let I={id:String(_.id),email:String(_.email),name:_.name,role:_.role,tenant:_.tenant},X=await E(I,{appId:k,role:V});return await x.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:k},user_id:{eq:I.id}}).run(),p=I,{...X,user:I,role:V}},async ssoLogin(r,u){let f=D(r),g=await K(f);if(!g){let _=await t.insert({email:f,password_hash:null,name:u?.name??null,role:null,tenant:null}).onConflict("email").run();if(g=_.length?G(_[0]):await K(f),!g)throw new l("User creation failed",500)}await F(g.id,"sso");let k;u?.appId&&(await O(u.appId,g.id)||await x.insert({app_id:u.appId,user_id:g.id,role:"member",invited_by:null,source:"sso"}).onConflict().run(),k=u.appId,await x.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:u.appId},user_id:{eq:g.id}}).run());let b=await E(g,k?{appId:k,role:"member"}:void 0);return p=g,{...b,user:g}},async createInvite(r,u){if(r===$)throw new l("_builtin \u4E0D\u8D70\u9080\u8BF7\u6D41\uFF08\u4EFB\u547D\u5236\uFF09",403);if(u.role!==void 0&&!ve.includes(u.role))throw new l(`invite role not allowed: ${u.role}\uFF08allowed: ${ve.join("/")}\uFF09`,403);if(!p)throw new l("Unauthorized",401);if(await O(r,p.id)!=="owner")throw new l("Owner only",403);let g=u.role&&u.role!=="owner"?u.role:"member";return{inviteToken:se({type:"app-invite",appId:r,...u.email?{email:D(u.email)}:{},role:g},P,Be)}},async addMember(r,u,f){if(Re(f),r===$&&f!==void 0&&f==="viewer")throw new l("_builtin \u65E0\u53EA\u8BFB\uFF08viewer \u7981\u2014\u2014\u7BA1\u7406\u9762\u8EAB\u4EFD\uFF09",403);if(!p)throw new l("Unauthorized",401);if(await O(r,p.id)!=="owner")throw new l("Owner only",403);let k=await t.select("id").where({email:{eq:D(u)}}).run();if(!k.length)throw new l("User not found \u2014 invite them to register first",400);let b=f&&f!=="owner"?f:"member";await x.insert({app_id:r,user_id:String(k[0].id),role:b,invited_by:p.id}).run()},async setOpenRegistration(r,u){if(!p)throw new l("Unauthorized",401);if(r===$)throw new l("_builtin \u6CE8\u518C\u5F00\u5173\u6052 false",403);if(await O(r,p.id)!=="owner")throw new l("Owner only",403);await w.update({open_registration:u}).where({id:{eq:r}}).run()},async listMyApps(){if(!p)throw new l("Unauthorized",401);return Ie(p.id)},async requireApp(r){if(!p)throw new l("Unauthorized",401);let u=await O(r,p.id);if(!u)throw new l("Not a member of this application",403);return{userId:p.id,appId:r,role:u}}};return m.auth=W,h(a,m)});return B.__meta={injects:["user","auth"],depends:[]},B.seedBuiltinOwners=async a=>{let m={owner:null,admins:[]};for(let h of a){let p=D(h);if(!p)continue;let s=await K(p);if(!s){let i=await t.insert({email:p,password_hash:null,name:null,role:null,tenant:null}).onConflict("email").run();s=i.length?G(i[0]):await K(p)}if(!s)continue;let d=await x.select("role").where({app_id:{eq:$},user_id:{eq:s.id}}).run();if(d.length){String(d[0].role??"")==="owner"?m.owner=String(s.id):m.admins.push(String(s.id));continue}if(m.owner)await x.insert({app_id:$,user_id:String(s.id),role:"admin",invited_by:m.owner,source:"seed"}).run(),m.admins.push(String(s.id));else{await x.insert({app_id:$,user_id:String(s.id),role:"owner",invited_by:null,source:"seed"}).run(),m.owner=String(s.id);let i=await C("_default");i&&(await O(i,String(s.id))||await x.insert({app_id:i,user_id:String(s.id),role:"owner",invited_by:null,source:"seed"}).run())}}return m},B.migrate=async()=>{(await w.select("id").where({slug:{eq:"_builtin"}}).run()).length||await e.query.insert(Se).values({id:$,slug:"_builtin",name:"System",owner_user_id:null,open_registration:!1}).returning("id").run();let m=await w.select("id").where({app_key:{isNull:!0}}).run();for(let d of m)await w.update({app_key:Pe(32).toString("hex")}).where({id:{eq:String(d.id)}}).run();(await w.select("id").where({slug:{eq:"_default"}}).run()).length||await w.insert({slug:"_default",name:"Default",owner_user_id:null,open_registration:!1}).run();let p=await C("_default");if(p){let d=await x.select("user_id").where({app_id:{eq:$},role:{eq:"owner"}}).run();for(let i of d){let c=String(i.user_id);await O(p,c)||await x.insert({app_id:p,user_id:c,role:"owner",invited_by:null,source:"migrate"}).onConflict().run()}}let s=await t.select("id").run();for(let d of s)await F(String(d.id),"migrate")},B.routes=(a,m)=>{let h=m?.prefix??Ee,p=new Set(m?.exclude??[]);if(p.has("register")||a.post(`${h}/register`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await d.auth.register(i);return L(c)}),p.has("register")||a.post(`${h}/register-app`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await d.auth.registerWithApp(i);return L(c)}),p.has("login")||a.post(`${h}/login`,async(s,d)=>{let i=await s.json().catch(()=>({}));if(!i.email||!i.password)return H("email and password are required");let c=await d.auth.login(i.email,i.password);return N(c)}),p.has("logout")||a.post(`${h}/logout`,async(s,d)=>{let i=await s.json().catch(()=>({}));return i.refreshToken?(await d.auth.logout(i.refreshToken),$e()):H("refreshToken is required")}),p.has("refresh")||a.post(`${h}/refresh`,async(s,d)=>{let i=await s.json().catch(()=>({}));if(!i.refreshToken)throw new l("refreshToken is required",400);let{user:c,appId:R}=await Le(i.refreshToken),q;if(R){let W=await O(R,c.id);W&&(q={appId:R,role:W})}let M=await E(c,q);return N({...M,user:c})}),p.has("me")||a.get(`${h}/me`,async(s,d)=>{if(!d.user)throw new l("Unauthorized",401);return N({user:d.user,session:d.session??null})}),T){let s=`${h}/apps/_builtin/auth/sso`;a.get(`${s}/enabled`,async()=>N({enabled:!0,appSlug:T.defaultAppSlug??null})),a.get(`${s}/login`,async d=>{let c=new URL(d.url??"","http://localhost").searchParams.get("app")??T.defaultAppSlug,R=new URLSearchParams({response_type:"code",client_id:T.clientId,redirect_uri:T.redirectBase?`${T.redirectBase.replace(/\/$/,"")}${s}/callback`:`${new URL(d.url,"http://localhost").origin}${s}/callback`,scope:T.scope??"openid email profile",state:c??"sso"});return new Response(null,{status:302,headers:{Location:`${T.issuer.replace(/\/$/,"")}/authorize?${R}`}})}),a.get(`${s}/callback`,async(d,i)=>{let c=new URL(d.url??"","http://localhost"),R=c.searchParams.get("code");if(!R)throw new l("SSO \u56DE\u8C03\u7F3A\u5C11 code",400);let q=T.redirectBase?`${T.redirectBase.replace(/\/$/,"")}${s}/callback`:`${c.origin}${s}/callback`,M=await fetch(`${T.issuer.replace(/\/$/,"")}/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:R,redirect_uri:q,client_id:T.clientId,client_secret:T.clientSecret})});if(!M.ok)throw new l("SSO token \u4EA4\u6362\u5931\u8D25",401);let W=await M.json(),r=await fetch(`${T.issuer.replace(/\/$/,"")}/userinfo`,{headers:{Authorization:`Bearer ${W.access_token}`}});if(!r.ok)throw new l("SSO \u7528\u6237\u4FE1\u606F\u83B7\u53D6\u5931\u8D25",401);let u=await r.json(),f=(u.email??"").trim().toLowerCase();if(!f)throw new l("SSO \u672A\u8FD4\u56DE\u90AE\u7BB1\uFF08\u9700\u8981 email scope\uFF09",401);let g=c.searchParams.get("state"),k;if(g&&g!=="sso"){let j=await C(g);j&&(k=j)}let b=await i.auth.ssoLogin(f,{appId:k,name:u.name});await Z?.onSsoLogin?.(b.user.id,k);let _={token:b.token,refreshToken:b.refreshToken,user:b.user};if(T.renderCallback){let j=T.renderCallback(_);return typeof j=="string"?new Response(j,{headers:{"Content-Type":"text/html; charset=utf-8"}}):j}return N(_)})}p.has("apps")||(a.post(`${h}/apps`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await d.auth.createApp(i);return L({app:c})}),a.get(`${h}/apps`,async(s,d)=>{let i=await d.auth.listMyApps();return N({apps:i})}),a.post(`${h}/apps/:appSlug/auth/members`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await C(d.params.appSlug);if(!c)throw new l("Application not found",404);return await d.auth.addMember(c,i.email??"",i.role),L({ok:!0})}),a.post(`${h}/apps/:appSlug/auth/invites`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await C(d.params.appSlug);if(!c)throw new l("Application not found",404);let R=await d.auth.createInvite(c,{email:i.email,role:i.role});return L(R)}),a.post(`${h}/apps/:appSlug/auth/login`,async(s,d)=>{let i=await s.json().catch(()=>({}));if(!i.email||!i.password)return H("email and password are required");let c=await d.auth.loginApp(d.params.appSlug,i.email,i.password);return N(c)}),a.patch(`${h}/apps/:appSlug/auth/registration`,async(s,d)=>{let i=await s.json().catch(()=>({}));if(typeof i.open!="boolean")return H("open is required (boolean)");let c=await C(d.params.appSlug);if(!c)throw new l("Application not found",404);return await d.auth.setOpenRegistration(c,i.open),N({open:i.open})}),a.post(`${h}/apps/:appSlug/auth/verify`,async(s,d)=>{let i=s.headers.get("x-wf-app-id"),c=s.headers.get("x-wf-app-key");if(!i||!c)return H("X-Wf-App-Id / X-Wf-App-Key required");let R=await w.select("id","slug","name").where({id:{eq:i},app_key:{eq:c}}).run();if(!R.length)throw new l("Invalid app credentials",403);let q=R[0];return N({app:{id:String(q.id),slug:String(q.slug),name:String(q.name)}})}),a.post(`${h}/apps/:appSlug/auth/register`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await d.auth.registerInApp({appSlug:d.params.appSlug,email:i.email??"",password:i.password??"",name:i.name,inviteToken:i.inviteToken});return L(c)}))},B.asAppAuth=()=>B,B}var It={tables:[{name:"_weifuwu_users",columns:{id:S.pk(o.uuid()),email:S.req(o.string()).meta({unique:!0}),password_hash:o.string(),name:o.string(),role:o.string(),tenant:o.string(),email_verified:o.boolean().meta({default:!1}),created_at:o.date().meta({default:"now"})},dropNotNull:["password_hash"]},{name:"_weifuwu_sessions",columns:{token_hash:o.string().meta({pk:!0}),user_id:S.req(o.uuid()).meta({references:"_weifuwu_users",onDelete:"cascade"}),app_id:o.string(),expires_at:o.date().meta({notNull:!0}),revoked_at:o.date(),created_at:o.date().meta({default:"now"})}},{name:"_weifuwu_apps",columns:{id:S.pk(o.uuid()),slug:S.req(o.string()).meta({unique:!0}),name:S.req(o.string()),owner_user_id:o.uuid().meta({references:"_weifuwu_users",onDelete:"cascade"}),open_registration:o.boolean().meta({default:!1}),created_at:o.date().meta({default:"now"}),app_key:o.string()}},{name:"_weifuwu_app_members",columns:{app_id:S.req(o.uuid()).meta({references:"_weifuwu_apps",onDelete:"cascade"}),user_id:S.req(o.uuid()).meta({references:"_weifuwu_users",onDelete:"cascade"}),role:o.string().meta({default:"member"}),invited_by:o.uuid(),joined_at:o.date().meta({default:"now"}),source:o.string(),last_login_at:o.date()},uniques:[["app_id","user_id"]]}]};export{$ as BUILTIN_APP_ID,oe as USER_TABLES,It as WEIFUWU_USER_SCHEMA,Rt as userSystem};
|
|
@@ -939,6 +939,18 @@ export function userSystem(options: UserSystemOptions): UserSystemClient {
|
|
|
939
939
|
open_registration: false,
|
|
940
940
|
}).run()
|
|
941
941
|
}
|
|
942
|
+
// _default 存量补挂(0.95.1 实证:_default 建于 _builtin owner 之后——首 owner 关联分支
|
|
943
|
+
// 永远错过 → UI 单应用模式(agent-platform = _default)登录 401 "Not a member")
|
|
944
|
+
// 定案:_builtin owner(超级管理员)→ _default owner 成员——幂等循环补足(存量库修复面)
|
|
945
|
+
const defAppId = await findAppIdBySlug('_default')
|
|
946
|
+
if (defAppId) {
|
|
947
|
+
const owners = await M.select('user_id').where({ app_id: { eq: BUILTIN_APP_ID }, role: { eq: 'owner' } }).run()
|
|
948
|
+
for (const o of owners) {
|
|
949
|
+
const uid = String(o.user_id)
|
|
950
|
+
if (await findMemberRole(defAppId, uid)) continue
|
|
951
|
+
await M.insert({ app_id: defAppId, user_id: uid, role: 'owner', invited_by: null, source: 'migrate' }).onConflict().run()
|
|
952
|
+
}
|
|
953
|
+
}
|
|
942
954
|
// 存量补挂(定案:全员应用管理面入册——旧库 users 无 _builtin 成员行着补——
|
|
943
955
|
// query builder 循环——memory/真库双后端一致——迁移期一次性 O(N) 可接受)
|
|
944
956
|
const leftover = await U.select('id').run()
|
package/dist/server/index.js
CHANGED
|
@@ -3214,6 +3214,15 @@ function userSystem(options) {
|
|
|
3214
3214
|
open_registration: false
|
|
3215
3215
|
}).run();
|
|
3216
3216
|
}
|
|
3217
|
+
const defAppId = await findAppIdBySlug("_default");
|
|
3218
|
+
if (defAppId) {
|
|
3219
|
+
const owners = await M.select("user_id").where({ app_id: { eq: BUILTIN_APP_ID }, role: { eq: "owner" } }).run();
|
|
3220
|
+
for (const o of owners) {
|
|
3221
|
+
const uid = String(o.user_id);
|
|
3222
|
+
if (await findMemberRole(defAppId, uid)) continue;
|
|
3223
|
+
await M.insert({ app_id: defAppId, user_id: uid, role: "owner", invited_by: null, source: "migrate" }).onConflict().run();
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3217
3226
|
const leftover = await U.select("id").run();
|
|
3218
3227
|
for (const u of leftover) {
|
|
3219
3228
|
await ensureBuiltinMember(String(u.id), "migrate");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var l=class extends Error{status;constructor(e,t){super(e),this.name="HttpError",this.status=t}};var Y=class extends Error{issues;constructor(e){super(e.map(t=>`${t.path}: ${t.message}`).join("; ")),this.name="ZodError",this.issues=e}},v=class{_meta={};get metaInfo(){return this._meta}meta(e){return this._meta={...this._meta,...e},this}parse(e){let t=this._parse(e);if(!t.ok)throw new Y([{path:t.path??"",message:t.message??"invalid"}]);return t.value}safeParse(e){let t=this._parse(e);return t.ok?{success:!0,data:t.value}:{success:!1,error:new Y([{path:t.path??"",message:t.message??"invalid"}])}}optional(){return new ye(this)}nullable(){return new ke(this)}default(e){return new _e(this,e)}refine(e,t){return new be(this,e,t)}transform(e){return new xe(this,e)}},Q=class extends v{_typeName(){return"string"}_parse(e){if(typeof e!="string")return{ok:!1,path:"",message:"expected string"};let t=e;return this._min!==void 0&&t.length<this._min?{ok:!1,path:"",message:`too small (min ${this._min})`}:this._max!==void 0&&t.length>this._max?{ok:!1,path:"",message:`too big (max ${this._max})`}:this._pattern&&!this._pattern.test(t)?{ok:!1,path:"",message:"invalid pattern"}:this._email&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)?{ok:!1,path:"",message:"invalid email"}:this._uuid&&!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t)?{ok:!1,path:"",message:"invalid uuid"}:{ok:!0,value:t}}_min;_max;_pattern;_email=!1;_uuid=!1;min(e){return this._min=e,this}max(e){return this._max=e,this}regex(e,t){return this._pattern=e,this}email(){return this._email=!0,this}uuid(){return this._uuid=!0,this}},le=class extends v{_typeName(){return"number"}_parse(e){if(typeof e!="number"||Number.isNaN(e))return{ok:!1,path:"",message:"expected number"};let t=e;return this._int&&!Number.isInteger(t)?{ok:!1,path:"",message:"expected integer"}:this._min!==void 0&&t<this._min?{ok:!1,path:"",message:`too small (min ${this._min})`}:this._max!==void 0&&t>this._max?{ok:!1,path:"",message:`too big (max ${this._max})`}:{ok:!0,value:t}}_int=!1;_min;_max;int(){return this._int=!0,this}min(e){return this._min=e,this}max(e){return this._max=e,this}positive(){return this._min=0,this}},de=class extends v{_typeName(){return"boolean"}_parse(e){return typeof e!="boolean"?{ok:!1,path:"",message:"expected boolean"}:{ok:!0,value:e}}},ee=class extends v{lit;constructor(e){super(),this.lit=e}get value(){return this.lit}_typeName(){return"literal"}_parse(e){return e!==this.lit?{ok:!1,path:"",message:`expected literal ${JSON.stringify(this.lit)}`}:{ok:!0,value:e}}},te=class extends v{raw;constructor(e){super(),this.raw=e}get values(){return this.raw}_typeName(){return"enum"}_parse(e){return typeof e!="string"||!this.raw.includes(e)?{ok:!1,path:"",message:`expected one of ${this.raw.join(" | ")}`}:{ok:!0,value:e}}},pe=class extends v{_typeName(){return"datetime"}_parse(e){return typeof e!="string"||Number.isNaN(Date.parse(e))?{ok:!1,path:"",message:"expected datetime string (ISO)"}:{ok:!0,value:e}}},ce=class extends v{dims;constructor(e){super(),this.dims=e}_typeName(){return"vector"}_parse(e){return typeof e!="object"||e===null||!Array.isArray(e)||!e.every(t=>typeof t=="number")?{ok:!1,path:"",message:"expected number[] vector"}:this.dims>0&&e.length!==this.dims?{ok:!1,path:"",message:`expected vector(${this.dims})\u2014\u2014got ${e.length} dims`}:{ok:!0,value:e}}},ge=class extends v{_typeName(){return"json"}_parse(e){return{ok:!0,value:e}}},me=class n extends v{shape;constructor(e){super(),this.shape=e}_typeName(){return"object"}_parse(e){if(typeof e!="object"||e===null||Array.isArray(e))return{ok:!1,path:"",message:"expected object"};let t={},y=[];for(let[w,S]of Object.entries(this.shape)){let A=S._parse(e[w]);if(!A.ok){y.push({path:w,message:A.message??""});continue}t[w]=A.value}return y.length?{ok:!1,path:y[0].path,message:y[0].message}:{ok:!0,value:t}}pick(e){let t={};for(let y of e)t[y]=this.shape[y];return new n(t)}omit(e){let t={};for(let[y,w]of Object.entries(this.shape))e.includes(y)||(t[y]=w);return new n(t)}extend(e){return new n({...this.shape,...e})}},fe=class extends v{inner;constructor(e){super(),this.inner=e}get itemSchema(){return this.inner}_typeName(){return"array"}_parse(e){if(!Array.isArray(e))return{ok:!1,path:"",message:"expected array"};if(this._min!==void 0&&e.length<this._min)return{ok:!1,path:"",message:`too small (min ${this._min})`};if(this._max!==void 0&&e.length>this._max)return{ok:!1,path:"",message:`too big (max ${this._max})`};let t=[];for(let y=0;y<e.length;y++){let w=this.inner._parse(e[y]);if(!w.ok)return{ok:!1,path:`${y}`,message:w.message};t.push(w.value)}return{ok:!0,value:t}}_min;_max;min(e){return this._min=e,this}max(e){return this._max=e,this}},we=class extends v{options;constructor(e){super(),this.options=e}_typeName(){return"union"}_parse(e){let t=null;for(let y of this.options){let w=y._parse(e);if(w.ok)return{ok:!0,value:w.value};t||(t={path:w.path??"",message:w.message??""})}return{ok:!1,path:"",message:`expected union (${t?.message})`}}},he=class extends v{disc;options;discValueOf;constructor(e,t,y){super(),this.disc=e,this.options=t,this.discValueOf=y}_typeName(){return"disUnion"}_parse(e){if(typeof e!="object"||e===null)return{ok:!1,path:"",message:"expected object"};let t=e[this.disc];for(let y of this.options)if(this.discValueOf(y.shape)===t){let w=y._parse(e);return w.ok?{ok:!0,value:w.value}:{ok:!1,path:`(${String(t)})`,message:w.message??""}}return{ok:!1,path:this.disc,message:`invalid discriminator value ${JSON.stringify(t)}`}}};function Ke(n,e){let t=n[e];if(t instanceof ee)return t.lit;if(t instanceof te)return t.values;throw new Error(`z.discriminatedUnion: \u5224\u522B\u5B57\u6BB5\u9700\u4E3A literal/enum\u2014\u2014\u5F97\u5230 ${t?._typeName?.()}`)}var ye=class extends v{inner;constructor(e){super(),this.inner=e}_typeName(){return"optional"}_parse(e){return e===void 0?{ok:!0,value:void 0}:this.inner._parse(e)}},ke=class extends v{inner;constructor(e){super(),this.inner=e}_typeName(){return"nullable"}_parse(e){return e===null?{ok:!0,value:null}:this.inner._parse(e)}},_e=class extends v{inner;d;constructor(e,t){super(),this.inner=e,this.d=t}_typeName(){return"default"}_parse(e){if(e===void 0){let t=typeof this.d=="function"?this.d():this.d;return this.inner._parse(t)}return this.inner._parse(e)}},be=class extends v{inner;fn;msg;constructor(e,t,y){super(),this.inner=e,this.fn=t,this.msg=y}_typeName(){return"effects"}_parse(e){let t=this.inner._parse(e);return t.ok?this.fn(t.value)?{ok:!0,value:t.value}:{ok:!1,path:"",message:this.msg??"refine failed"}:{ok:!1,path:t.path??"",message:t.message??""}}},xe=class extends v{inner;fn;constructor(e,t){super(),this.inner=e,this.fn=t}_typeName(){return"transform"}_parse(e){let t=this.inner._parse(e);return t.ok?{ok:!0,value:this.fn(t.value)}:{ok:!1,path:t.path??"",message:t.message??""}}},i={string:()=>new Q,number:()=>new le,boolean:()=>new de,literal:n=>new ee(n),enum:n=>new te(n),date:()=>new pe,uuid:()=>new Q().uuid(),json:()=>new ge,vector:n=>new ce(n),object:n=>new me(n),array:n=>new fe(n),union:n=>new we(n),discriminatedUnion:(n,e)=>new he(n,e,t=>Ke(t,n))};function z(n,e){return n.meta(e)}var x={pk:n=>z(n,{pk:!0,default:"random"}),req:n=>z(n,{notNull:!0}),col:(n,e)=>z(n,{column:e}),now:n=>z(n,{default:"now"}),unique:n=>z(n,{unique:!0}),dflt:(n,e)=>z(n,{default:e})};import{randomBytes as We,scrypt as ze,timingSafeEqual as He}from"node:crypto";import{promisify as Fe}from"node:util";var Ae=Fe(ze),Ve=64,ne={N:16384,r:8,p:1};async function J(n){let e=We(16),t=await Ae(n,e,Ve,ne);return`scrypt$${ne.N}$${ne.r}$${ne.p}$${e.toString("hex")}$${t.toString("hex")}`}async function re(n,e){let t=e.split("$");if(t.length!==6||t[0]!=="scrypt")return!1;let[,y,w,S,A,q]=t,$=Buffer.from(q,"hex"),U=await Ae(n,Buffer.from(A,"hex"),$.length,{N:Number(y),r:Number(w),p:Number(S)});return U.length===$.length&&He(U,$)}import{createHash as Je,createHmac as je,randomBytes as Ge,timingSafeEqual as Xe}from"node:crypto";var Oe=n=>Buffer.from(JSON.stringify(n)).toString("base64url");function se(n,e,t){let y=Math.floor(Date.now()/1e3),w=`${Oe({alg:"HS256",typ:"JWT"})}.${Oe({...n,iat:y,exp:y+t})}`,S=je("sha256",e).update(w).digest("base64url");return`${w}.${S}`}function ae(n,e){let t=n.split(".");if(t.length!==3)return null;let[y,w,S]=t,A=`${y}.${w}`,q=je("sha256",e).update(A).digest("base64url"),$=Buffer.from(S),U=Buffer.from(q);if($.length!==U.length||!Xe($,U))return null;try{let T=JSON.parse(Buffer.from(w,"base64url").toString("utf8"));return typeof T.exp=="number"&&T.exp<Date.now()/1e3?null:T}catch{return null}}function qe(){return Ge(32).toString("hex")}function ie(n){return Je("sha256").update(n).digest("hex")}function Z(n,e){return Response.json(n,{status:200,...e})}function B(n,e){return Response.json(n,{status:201,...e})}function $e(n){return new Response(null,{status:204,...n})}function H(n){return Response.json({error:n??"Bad Request"},{status:400})}import{randomBytes as Pe}from"node:crypto";var oe={users:{id:x.pk(i.uuid()),email:x.req(i.string()).meta({unique:!0}),password_hash:i.string().nullable(),name:i.string().nullable(),role:i.string().nullable(),tenant:i.string().nullable(),email_verified:i.boolean().meta({notNull:!0,default:!1}),created_at:x.now(i.date())},sessions:{token_hash:x.req(i.string()),user_id:x.req(i.uuid()),app_id:i.string().nullable(),expires_at:x.req(i.date()),revoked_at:i.date().nullable(),created_at:x.now(i.date())},apps:{id:x.pk(i.uuid()),slug:x.req(i.string()).meta({unique:!0}),name:x.req(i.string()),owner_user_id:i.uuid().nullable(),open_registration:i.boolean().meta({notNull:!0,default:!1}),app_key:i.string().nullable(),created_at:x.now(i.date())},members:{app_id:x.req(i.uuid()),user_id:x.req(i.uuid()),role:i.string().meta({notNull:!0,default:"member"}),invited_by:i.uuid().nullable(),joined_at:x.now(i.date()),source:i.string().nullable(),last_login_at:i.date().nullable()}},Ye="_weifuwu_users",Qe="_weifuwu_sessions",Se="_weifuwu_apps",N="00000000-0000-4000-8000-0000000000b1",Ze="_weifuwu_app_members",Ne=8,et=1024;function Te(n){if(n.length<Ne)throw new l(`password must be at least ${Ne} characters`,400);if(n.length>et)throw new l("password is too long",400)}function D(n){return n.trim().toLowerCase()}var Ue=null;async function Me(n){Ue??=await J("dummy-timing-equalize-password"),await re(n,Ue)}function Rt(n){let e=n.orm,t=e.table(Ye,oe.users),y=e.table(Qe,oe.sessions),w=e.table(Se,oe.apps),S=e.table(Ze,oe.members),A=n.secret??process.env.AUTH_SECRET;if(!A)throw new Error("userSystem: secret is required \u2014 pass options.secret or set AUTH_SECRET (at least 32 chars)");if(A.length<16)throw new Error("userSystem: secret must be at least 16 characters");let q=A,$=n.hooks,U=n.allowedRoles??["owner","admin","member","viewer"],T=n.sso??null,ve=n.inviteRoles??U;function Re(a){if(a!==void 0&&!U.includes(a))throw new l(`invalid role: ${a}\uFF08allowed: ${U.join("/")}\uFF09`,403)}let De=n.accessTtlSeconds??3600,Ce=n.refreshTtlDays??30,Ee=n.prefix??"/api/auth",G=a=>({id:String(a.id),email:a.email,name:a.name,role:a.role,tenant:a.tenant}),Be=168*3600;async function ue(a){let g=await t.select("id","email","name","role","tenant").where({id:{eq:a}}).run();return g.length?g[0]:null}async function F(a,g){(await S.select("role").where({app_id:{eq:N},user_id:{eq:a}}).run()).length||await S.insert({app_id:N,user_id:a,role:"member",invited_by:null,source:g}).onConflict().run()}async function P(a,g){let h=await S.select("role").where({app_id:{eq:a},user_id:{eq:g}}).run();return h.length?String(h[0].role):null}async function L(a){let g=await w.select("id").where({slug:{eq:a}}).run();return g.length?String(g[0].id):null}async function K(a){let g=await t.select("id","email","name","role","tenant").where({email:{eq:a}}).run();return g.length?g[0]:null}async function Ie(a){return(await e.query.from(`${Ze} m`).select("m.app_id","m.role","a.id","a.slug","a.name").join(`${Se} a`,{"a.id":{col:"m.app_id"}}).where({"m.user_id":{eq:a}}).run()).filter(h=>!String(h.slug).startsWith("_")).map(h=>({id:String(h.id),slug:String(h.slug),name:String(h.name),role:String(h.role)}))}async function C(a,g){let h=se({sub:a.id,...a.email?{email:a.email}:{},...a.name?{name:a.name}:{},...g?.appId?{appId:g.appId,role:g.role}:{},...!g?.appId&&a.tenant?{tenantId:a.tenant}:{}},q,De),d=qe(),s=new Date(Date.now()+Ce*24*3600*1e3);return await y.insert({token_hash:ie(d),user_id:a.id,expires_at:s.toISOString(),...g?.appId?{app_id:g.appId}:{}}).run(),{token:h,refreshToken:d}}async function Le(a){let g=await y.update({revoked_at:new Date().toISOString()}).where({token_hash:{eq:ie(a)},revoked_at:{isNull:!0}}).returning("user_id","expires_at","app_id").run();if(!g.length)throw new l("Invalid refresh token",401);let h=g[0];if(new Date(String(h.expires_at))<new Date)throw new l("Refresh token expired",401);let d=await ue(h.user_id);if(!d)throw new l("User not found",401);return{user:d,appId:h.app_id?String(h.app_id):void 0}}let E=(async(a,g,h)=>{let d=null,s=null,p={},u,f,R,O=a.headers.get("authorization"),M=null;if(O?.startsWith("Bearer "))M=O.slice(7);else if(a.method==="GET"){let r=new URL(a.url??"","http://localhost"),o=r.searchParams.get("ticket");if(o){let m=ae(o,q);m?.type==="download"&&m?.sub&&(s=await ue(String(m.sub)),d=s,p.userId=String(m.sub),m.appId!=null&&(f=m.appId,p.appId=String(m.appId)))}else M=r.searchParams.get("token")}if(M&&!s){let r=ae(M,q);if(r?.sub){s=await ue(String(r.sub)),d=s;for(let[o,m]of Object.entries(r))o==="sub"||o==="iat"||o==="exp"||o==="type"||(p[o]=m);p.userId=String(r.sub),u=r.tenantId,f=r.appId,R=r.role}}g.user=s,f!=null&&(g.appId=String(f)),g.session=f!=null?{userId:String(s.id),appId:String(f),role:String(R??"")}:null,u!=null&&(g.tenantId=String(u));let W={...p,async register(r){if(!r.email||!r.password)throw new l("email and password are required",400);Te(r.password);let o=D(r.email),m=await J(r.password),c=await t.insert({email:o,password_hash:m,name:r.name??null,role:null,tenant:r.tenant??null}).run(),_=G(c[0]),b=await C(_);return await F(_.id,"register"),d=_,{...b,user:_}},async registerWithApp(r){let o=await this.register({email:r.email,password:r.password,name:r.name});await F(o.user.id,"register");let m=(r.appSlug??r.email.split("@")[1]??"default").trim().toLowerCase(),c=m;for(let k=1;k<=200&&await L(c);k++)c=`${m}-${k}`;let _=await this.createApp({slug:c,name:r.appName??`${r.name??"\u7528\u6237"} \u7684\u5E94\u7528`,openRegistration:!1}),b=await C(o.user,{appId:_.id,role:"owner"});return await $?.onRegisterApp?.(o.user.id,_),{...b,user:o.user,app:{..._,role:"owner"}}},async login(r,o){let c=(await t.select("id","email","password_hash","name","role","tenant").where({email:{eq:D(r)}}).run())[0];if(!c||c.password_hash==null)throw await Me(o),new l("Invalid email or password",401);if(!await re(o,String(c.password_hash)))throw new l("Invalid email or password",401);let b={id:String(c.id),email:String(c.email),name:c.name,role:c.role,tenant:c.tenant},k=await C(b),j=await Ie(b.id);return d=b,{...k,user:b,apps:j}},async logout(r){await y.update({revoked_at:new Date().toISOString()}).where({token_hash:{eq:ie(r)}}).run()},requireAuth(){if(!s)throw new l("Unauthorized",401);return s},async setPassword(r,o){Te(o);let m=await J(o);await t.update({password_hash:m}).where({id:{eq:r}}).run()},createToken(r,o,m){return se({type:r,...o},q,m.ttlSeconds)},async createApp(r){if(!d)throw new l("Unauthorized",401);if(!r.slug||!r.name)throw new l("slug and name are required",400);let o=r.slug.trim().toLowerCase();if(o.startsWith("_"))throw new l("slug \u4EE5 _ \u5F00\u5934\u4E3A\u7CFB\u7EDF\u4FDD\u7559\u540D",400);if(!await P(N,d.id))throw new l("\u4EC5\u5E94\u7528\u7BA1\u7406\u9762\uFF08_builtin\uFF09\u6210\u5458\u53EF\u521B\u5EFA\u5E94\u7528",403);let c=Pe(32).toString("hex"),b=(await w.insert({slug:o,name:r.name,owner_user_id:d.id,open_registration:r.openRegistration??!1,app_key:c}).run())[0];return await S.insert({app_id:b.id,user_id:d.id,role:"owner",invited_by:d.id}).run(),b},async registerInApp(r){if(!r.email||!r.password)throw new l("email and password are required",400);Te(r.password);let o=await w.select("id","open_registration").where({slug:{eq:r.appSlug}}).run();if(!o.length)throw new l("Application not found",404);let m=o[0],c=String(m.id),_=D(r.email),b="member";if(!m.open_registration){if(!r.inviteToken)throw new l("Registration closed for this application",403);let I=ae(r.inviteToken,q);if(!I||I.type!=="app-invite"||I.appId!==c)throw new l("Invalid invite",403);if(I.email&&String(I.email)!==_)throw new l("Invite email mismatch",403);typeof I.role=="string"&&I.role!=="owner"&&(Re(I.role),b=I.role)}let k=await K(_);if(!k){let I=await J(r.password),X=await t.insert({email:_,password_hash:I,name:r.name??null,role:null,tenant:null}).onConflict("email").run();if(k=X.length?G(X[0]):await K(_),!k)throw new l("User creation failed",500)}await F(k.id,"register"),await P(c,k.id)||await S.insert({app_id:c,user_id:k.id,role:b,invited_by:d?.id??null,source:"invite"}).onConflict().run();let V=await C(k,{appId:c,role:b});return await S.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:c},user_id:{eq:k.id}}).run(),d=k,await $?.onJoinApp?.(k.id,c,b),{...V,user:k}},async loginApp(r,o,m){let c=await w.select("id").where({slug:{eq:r}}).run();if(!c.length)throw new l("Application not found",404);let _=String(c[0].id),k=(await t.select("id","email","password_hash","name","role","tenant").where({email:{eq:D(o)}}).run())[0];if(!k||k.password_hash==null)throw await Me(m),new l("Invalid email or password",401);if(!await re(m,String(k.password_hash)))throw new l("Invalid email or password",401);let V=await P(_,String(k.id));if(!V)throw new l("Not a member of this application",401);let I={id:String(k.id),email:String(k.email),name:k.name,role:k.role,tenant:k.tenant},X=await C(I,{appId:_,role:V});return await S.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:_},user_id:{eq:I.id}}).run(),d=I,{...X,user:I,role:V}},async ssoLogin(r,o){let m=D(r),c=await K(m);if(!c){let k=await t.insert({email:m,password_hash:null,name:o?.name??null,role:null,tenant:null}).onConflict("email").run();if(c=k.length?G(k[0]):await K(m),!c)throw new l("User creation failed",500)}await F(c.id,"sso");let _;o?.appId&&(await P(o.appId,c.id)||await S.insert({app_id:o.appId,user_id:c.id,role:"member",invited_by:null,source:"sso"}).onConflict().run(),_=o.appId,await S.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:o.appId},user_id:{eq:c.id}}).run());let b=await C(c,_?{appId:_,role:"member"}:void 0);return d=c,{...b,user:c}},async createInvite(r,o){if(r===N)throw new l("_builtin \u4E0D\u8D70\u9080\u8BF7\u6D41\uFF08\u4EFB\u547D\u5236\uFF09",403);if(o.role!==void 0&&!ve.includes(o.role))throw new l(`invite role not allowed: ${o.role}\uFF08allowed: ${ve.join("/")}\uFF09`,403);if(!d)throw new l("Unauthorized",401);if(await P(r,d.id)!=="owner")throw new l("Owner only",403);let c=o.role&&o.role!=="owner"?o.role:"member";return{inviteToken:se({type:"app-invite",appId:r,...o.email?{email:D(o.email)}:{},role:c},q,Be)}},async addMember(r,o,m){if(Re(m),r===N&&m!==void 0&&m==="viewer")throw new l("_builtin \u65E0\u53EA\u8BFB\uFF08viewer \u7981\u2014\u2014\u7BA1\u7406\u9762\u8EAB\u4EFD\uFF09",403);if(!d)throw new l("Unauthorized",401);if(await P(r,d.id)!=="owner")throw new l("Owner only",403);let _=await t.select("id").where({email:{eq:D(o)}}).run();if(!_.length)throw new l("User not found \u2014 invite them to register first",400);let b=m&&m!=="owner"?m:"member";await S.insert({app_id:r,user_id:String(_[0].id),role:b,invited_by:d.id}).run()},async setOpenRegistration(r,o){if(!d)throw new l("Unauthorized",401);if(r===N)throw new l("_builtin \u6CE8\u518C\u5F00\u5173\u6052 false",403);if(await P(r,d.id)!=="owner")throw new l("Owner only",403);await w.update({open_registration:o}).where({id:{eq:r}}).run()},async listMyApps(){if(!d)throw new l("Unauthorized",401);return Ie(d.id)},async requireApp(r){if(!d)throw new l("Unauthorized",401);let o=await P(r,d.id);if(!o)throw new l("Not a member of this application",403);return{userId:d.id,appId:r,role:o}}};return g.auth=W,h(a,g)});return E.__meta={injects:["user","auth"],depends:[]},E.seedBuiltinOwners=async a=>{let g={owner:null,admins:[]};for(let h of a){let d=D(h);if(!d)continue;let s=await K(d);if(!s){let u=await t.insert({email:d,password_hash:null,name:null,role:null,tenant:null}).onConflict("email").run();s=u.length?G(u[0]):await K(d)}if(!s)continue;let p=await S.select("role").where({app_id:{eq:N},user_id:{eq:s.id}}).run();if(p.length){String(p[0].role??"")==="owner"?g.owner=String(s.id):g.admins.push(String(s.id));continue}if(g.owner)await S.insert({app_id:N,user_id:String(s.id),role:"admin",invited_by:g.owner,source:"seed"}).run(),g.admins.push(String(s.id));else{await S.insert({app_id:N,user_id:String(s.id),role:"owner",invited_by:null,source:"seed"}).run(),g.owner=String(s.id);let u=await L("_default");u&&(await P(u,String(s.id))||await S.insert({app_id:u,user_id:String(s.id),role:"owner",invited_by:null,source:"seed"}).run())}}return g},E.migrate=async()=>{(await w.select("id").where({slug:{eq:"_builtin"}}).run()).length||await e.query.insert(Se).values({id:N,slug:"_builtin",name:"System",owner_user_id:null,open_registration:!1}).returning("id").run();let g=await w.select("id").where({app_key:{isNull:!0}}).run();for(let s of g)await w.update({app_key:Pe(32).toString("hex")}).where({id:{eq:String(s.id)}}).run();(await w.select("id").where({slug:{eq:"_default"}}).run()).length||await w.insert({slug:"_default",name:"Default",owner_user_id:null,open_registration:!1}).run();let d=await t.select("id").run();for(let s of d)await F(String(s.id),"migrate")},E.routes=(a,g)=>{let h=g?.prefix??Ee,d=new Set(g?.exclude??[]);if(d.has("register")||a.post(`${h}/register`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await p.auth.register(u);return B(f)}),d.has("register")||a.post(`${h}/register-app`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await p.auth.registerWithApp(u);return B(f)}),d.has("login")||a.post(`${h}/login`,async(s,p)=>{let u=await s.json().catch(()=>({}));if(!u.email||!u.password)return H("email and password are required");let f=await p.auth.login(u.email,u.password);return Z(f)}),d.has("logout")||a.post(`${h}/logout`,async(s,p)=>{let u=await s.json().catch(()=>({}));return u.refreshToken?(await p.auth.logout(u.refreshToken),$e()):H("refreshToken is required")}),d.has("refresh")||a.post(`${h}/refresh`,async(s,p)=>{let u=await s.json().catch(()=>({}));if(!u.refreshToken)throw new l("refreshToken is required",400);let{user:f,appId:R}=await Le(u.refreshToken),O;if(R){let W=await P(R,f.id);W&&(O={appId:R,role:W})}let M=await C(f,O);return Z({...M,user:f})}),d.has("me")||a.get(`${h}/me`,async(s,p)=>{if(!p.user)throw new l("Unauthorized",401);return Z({user:p.user,session:p.session??null})}),T){let s=`${h}/apps/_builtin/auth/sso`;a.get(`${s}/enabled`,async()=>Z({enabled:!0,appSlug:T.defaultAppSlug??null})),a.get(`${s}/login`,async p=>{let f=new URL(p.url??"","http://localhost").searchParams.get("app")??T.defaultAppSlug,R=new URLSearchParams({response_type:"code",client_id:T.clientId,redirect_uri:T.redirectBase?`${T.redirectBase.replace(/\/$/,"")}${s}/callback`:`${new URL(p.url,"http://localhost").origin}${s}/callback`,scope:T.scope??"openid email profile",state:f??"sso"});return new Response(null,{status:302,headers:{Location:`${T.issuer.replace(/\/$/,"")}/authorize?${R}`}})}),a.get(`${s}/callback`,async(p,u)=>{let f=new URL(p.url??"","http://localhost"),R=f.searchParams.get("code");if(!R)throw new l("SSO \u56DE\u8C03\u7F3A\u5C11 code",400);let O=T.redirectBase?`${T.redirectBase.replace(/\/$/,"")}${s}/callback`:`${f.origin}${s}/callback`,M=await fetch(`${T.issuer.replace(/\/$/,"")}/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:R,redirect_uri:O,client_id:T.clientId,client_secret:T.clientSecret})});if(!M.ok)throw new l("SSO token \u4EA4\u6362\u5931\u8D25",401);let W=await M.json(),r=await fetch(`${T.issuer.replace(/\/$/,"")}/userinfo`,{headers:{Authorization:`Bearer ${W.access_token}`}});if(!r.ok)throw new l("SSO \u7528\u6237\u4FE1\u606F\u83B7\u53D6\u5931\u8D25",401);let o=await r.json(),m=(o.email??"").trim().toLowerCase();if(!m)throw new l("SSO \u672A\u8FD4\u56DE\u90AE\u7BB1\uFF08\u9700\u8981 email scope\uFF09",401);let c=f.searchParams.get("state"),_;if(c&&c!=="sso"){let j=await L(c);j&&(_=j)}let b=await u.auth.ssoLogin(m,{appId:_,name:o.name});await $?.onSsoLogin?.(b.user.id,_);let k={token:b.token,refreshToken:b.refreshToken,user:b.user};if(T.renderCallback){let j=T.renderCallback(k);return typeof j=="string"?new Response(j,{headers:{"Content-Type":"text/html; charset=utf-8"}}):j}return Z(k)})}d.has("apps")||(a.post(`${h}/apps`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await p.auth.createApp(u);return B({app:f})}),a.get(`${h}/apps`,async(s,p)=>{let u=await p.auth.listMyApps();return Z({apps:u})}),a.post(`${h}/apps/:appSlug/auth/members`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await L(p.params.appSlug);if(!f)throw new l("Application not found",404);return await p.auth.addMember(f,u.email??"",u.role),B({ok:!0})}),a.post(`${h}/apps/:appSlug/auth/invites`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await L(p.params.appSlug);if(!f)throw new l("Application not found",404);let R=await p.auth.createInvite(f,{email:u.email,role:u.role});return B(R)}),a.post(`${h}/apps/:appSlug/auth/login`,async(s,p)=>{let u=await s.json().catch(()=>({}));if(!u.email||!u.password)return H("email and password are required");let f=await p.auth.loginApp(p.params.appSlug,u.email,u.password);return Z(f)}),a.patch(`${h}/apps/:appSlug/auth/registration`,async(s,p)=>{let u=await s.json().catch(()=>({}));if(typeof u.open!="boolean")return H("open is required (boolean)");let f=await L(p.params.appSlug);if(!f)throw new l("Application not found",404);return await p.auth.setOpenRegistration(f,u.open),Z({open:u.open})}),a.post(`${h}/apps/:appSlug/auth/verify`,async(s,p)=>{let u=s.headers.get("x-wf-app-id"),f=s.headers.get("x-wf-app-key");if(!u||!f)return H("X-Wf-App-Id / X-Wf-App-Key required");let R=await w.select("id","slug","name").where({id:{eq:u},app_key:{eq:f}}).run();if(!R.length)throw new l("Invalid app credentials",403);let O=R[0];return Z({app:{id:String(O.id),slug:String(O.slug),name:String(O.name)}})}),a.post(`${h}/apps/:appSlug/auth/register`,async(s,p)=>{let u=await s.json().catch(()=>({})),f=await p.auth.registerInApp({appSlug:p.params.appSlug,email:u.email??"",password:u.password??"",name:u.name,inviteToken:u.inviteToken});return B(f)}))},E.asAppAuth=()=>E,E}var It={tables:[{name:"_weifuwu_users",columns:{id:x.pk(i.uuid()),email:x.req(i.string()).meta({unique:!0}),password_hash:i.string(),name:i.string(),role:i.string(),tenant:i.string(),email_verified:i.boolean().meta({default:!1}),created_at:i.date().meta({default:"now"})},dropNotNull:["password_hash"]},{name:"_weifuwu_sessions",columns:{token_hash:i.string().meta({pk:!0}),user_id:x.req(i.uuid()).meta({references:"_weifuwu_users",onDelete:"cascade"}),app_id:i.string(),expires_at:i.date().meta({notNull:!0}),revoked_at:i.date(),created_at:i.date().meta({default:"now"})}},{name:"_weifuwu_apps",columns:{id:x.pk(i.uuid()),slug:x.req(i.string()).meta({unique:!0}),name:x.req(i.string()),owner_user_id:i.uuid().meta({references:"_weifuwu_users",onDelete:"cascade"}),open_registration:i.boolean().meta({default:!1}),created_at:i.date().meta({default:"now"}),app_key:i.string()}},{name:"_weifuwu_app_members",columns:{app_id:x.req(i.uuid()).meta({references:"_weifuwu_apps",onDelete:"cascade"}),user_id:x.req(i.uuid()).meta({references:"_weifuwu_users",onDelete:"cascade"}),role:i.string().meta({default:"member"}),invited_by:i.uuid(),joined_at:i.date().meta({default:"now"}),source:i.string(),last_login_at:i.date()},uniques:[["app_id","user_id"]]}]};export{N as BUILTIN_APP_ID,oe as USER_TABLES,It as WEIFUWU_USER_SCHEMA,Rt as userSystem};
|
|
1
|
+
var l=class extends Error{status;constructor(e,t){super(e),this.name="HttpError",this.status=t}};var Y=class extends Error{issues;constructor(e){super(e.map(t=>`${t.path}: ${t.message}`).join("; ")),this.name="ZodError",this.issues=e}},v=class{_meta={};get metaInfo(){return this._meta}meta(e){return this._meta={...this._meta,...e},this}parse(e){let t=this._parse(e);if(!t.ok)throw new Y([{path:t.path??"",message:t.message??"invalid"}]);return t.value}safeParse(e){let t=this._parse(e);return t.ok?{success:!0,data:t.value}:{success:!1,error:new Y([{path:t.path??"",message:t.message??"invalid"}])}}optional(){return new ye(this)}nullable(){return new _e(this)}default(e){return new ke(this,e)}refine(e,t){return new be(this,e,t)}transform(e){return new xe(this,e)}},Q=class extends v{_typeName(){return"string"}_parse(e){if(typeof e!="string")return{ok:!1,path:"",message:"expected string"};let t=e;return this._min!==void 0&&t.length<this._min?{ok:!1,path:"",message:`too small (min ${this._min})`}:this._max!==void 0&&t.length>this._max?{ok:!1,path:"",message:`too big (max ${this._max})`}:this._pattern&&!this._pattern.test(t)?{ok:!1,path:"",message:"invalid pattern"}:this._email&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)?{ok:!1,path:"",message:"invalid email"}:this._uuid&&!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t)?{ok:!1,path:"",message:"invalid uuid"}:{ok:!0,value:t}}_min;_max;_pattern;_email=!1;_uuid=!1;min(e){return this._min=e,this}max(e){return this._max=e,this}regex(e,t){return this._pattern=e,this}email(){return this._email=!0,this}uuid(){return this._uuid=!0,this}},le=class extends v{_typeName(){return"number"}_parse(e){if(typeof e!="number"||Number.isNaN(e))return{ok:!1,path:"",message:"expected number"};let t=e;return this._int&&!Number.isInteger(t)?{ok:!1,path:"",message:"expected integer"}:this._min!==void 0&&t<this._min?{ok:!1,path:"",message:`too small (min ${this._min})`}:this._max!==void 0&&t>this._max?{ok:!1,path:"",message:`too big (max ${this._max})`}:{ok:!0,value:t}}_int=!1;_min;_max;int(){return this._int=!0,this}min(e){return this._min=e,this}max(e){return this._max=e,this}positive(){return this._min=0,this}},de=class extends v{_typeName(){return"boolean"}_parse(e){return typeof e!="boolean"?{ok:!1,path:"",message:"expected boolean"}:{ok:!0,value:e}}},ee=class extends v{lit;constructor(e){super(),this.lit=e}get value(){return this.lit}_typeName(){return"literal"}_parse(e){return e!==this.lit?{ok:!1,path:"",message:`expected literal ${JSON.stringify(this.lit)}`}:{ok:!0,value:e}}},te=class extends v{raw;constructor(e){super(),this.raw=e}get values(){return this.raw}_typeName(){return"enum"}_parse(e){return typeof e!="string"||!this.raw.includes(e)?{ok:!1,path:"",message:`expected one of ${this.raw.join(" | ")}`}:{ok:!0,value:e}}},pe=class extends v{_typeName(){return"datetime"}_parse(e){return typeof e!="string"||Number.isNaN(Date.parse(e))?{ok:!1,path:"",message:"expected datetime string (ISO)"}:{ok:!0,value:e}}},ce=class extends v{dims;constructor(e){super(),this.dims=e}_typeName(){return"vector"}_parse(e){return typeof e!="object"||e===null||!Array.isArray(e)||!e.every(t=>typeof t=="number")?{ok:!1,path:"",message:"expected number[] vector"}:this.dims>0&&e.length!==this.dims?{ok:!1,path:"",message:`expected vector(${this.dims})\u2014\u2014got ${e.length} dims`}:{ok:!0,value:e}}},ge=class extends v{_typeName(){return"json"}_parse(e){return{ok:!0,value:e}}},me=class n extends v{shape;constructor(e){super(),this.shape=e}_typeName(){return"object"}_parse(e){if(typeof e!="object"||e===null||Array.isArray(e))return{ok:!1,path:"",message:"expected object"};let t={},y=[];for(let[w,x]of Object.entries(this.shape)){let A=x._parse(e[w]);if(!A.ok){y.push({path:w,message:A.message??""});continue}t[w]=A.value}return y.length?{ok:!1,path:y[0].path,message:y[0].message}:{ok:!0,value:t}}pick(e){let t={};for(let y of e)t[y]=this.shape[y];return new n(t)}omit(e){let t={};for(let[y,w]of Object.entries(this.shape))e.includes(y)||(t[y]=w);return new n(t)}extend(e){return new n({...this.shape,...e})}},fe=class extends v{inner;constructor(e){super(),this.inner=e}get itemSchema(){return this.inner}_typeName(){return"array"}_parse(e){if(!Array.isArray(e))return{ok:!1,path:"",message:"expected array"};if(this._min!==void 0&&e.length<this._min)return{ok:!1,path:"",message:`too small (min ${this._min})`};if(this._max!==void 0&&e.length>this._max)return{ok:!1,path:"",message:`too big (max ${this._max})`};let t=[];for(let y=0;y<e.length;y++){let w=this.inner._parse(e[y]);if(!w.ok)return{ok:!1,path:`${y}`,message:w.message};t.push(w.value)}return{ok:!0,value:t}}_min;_max;min(e){return this._min=e,this}max(e){return this._max=e,this}},we=class extends v{options;constructor(e){super(),this.options=e}_typeName(){return"union"}_parse(e){let t=null;for(let y of this.options){let w=y._parse(e);if(w.ok)return{ok:!0,value:w.value};t||(t={path:w.path??"",message:w.message??""})}return{ok:!1,path:"",message:`expected union (${t?.message})`}}},he=class extends v{disc;options;discValueOf;constructor(e,t,y){super(),this.disc=e,this.options=t,this.discValueOf=y}_typeName(){return"disUnion"}_parse(e){if(typeof e!="object"||e===null)return{ok:!1,path:"",message:"expected object"};let t=e[this.disc];for(let y of this.options)if(this.discValueOf(y.shape)===t){let w=y._parse(e);return w.ok?{ok:!0,value:w.value}:{ok:!1,path:`(${String(t)})`,message:w.message??""}}return{ok:!1,path:this.disc,message:`invalid discriminator value ${JSON.stringify(t)}`}}};function Ke(n,e){let t=n[e];if(t instanceof ee)return t.lit;if(t instanceof te)return t.values;throw new Error(`z.discriminatedUnion: \u5224\u522B\u5B57\u6BB5\u9700\u4E3A literal/enum\u2014\u2014\u5F97\u5230 ${t?._typeName?.()}`)}var ye=class extends v{inner;constructor(e){super(),this.inner=e}_typeName(){return"optional"}_parse(e){return e===void 0?{ok:!0,value:void 0}:this.inner._parse(e)}},_e=class extends v{inner;constructor(e){super(),this.inner=e}_typeName(){return"nullable"}_parse(e){return e===null?{ok:!0,value:null}:this.inner._parse(e)}},ke=class extends v{inner;d;constructor(e,t){super(),this.inner=e,this.d=t}_typeName(){return"default"}_parse(e){if(e===void 0){let t=typeof this.d=="function"?this.d():this.d;return this.inner._parse(t)}return this.inner._parse(e)}},be=class extends v{inner;fn;msg;constructor(e,t,y){super(),this.inner=e,this.fn=t,this.msg=y}_typeName(){return"effects"}_parse(e){let t=this.inner._parse(e);return t.ok?this.fn(t.value)?{ok:!0,value:t.value}:{ok:!1,path:"",message:this.msg??"refine failed"}:{ok:!1,path:t.path??"",message:t.message??""}}},xe=class extends v{inner;fn;constructor(e,t){super(),this.inner=e,this.fn=t}_typeName(){return"transform"}_parse(e){let t=this.inner._parse(e);return t.ok?{ok:!0,value:this.fn(t.value)}:{ok:!1,path:t.path??"",message:t.message??""}}},o={string:()=>new Q,number:()=>new le,boolean:()=>new de,literal:n=>new ee(n),enum:n=>new te(n),date:()=>new pe,uuid:()=>new Q().uuid(),json:()=>new ge,vector:n=>new ce(n),object:n=>new me(n),array:n=>new fe(n),union:n=>new we(n),discriminatedUnion:(n,e)=>new he(n,e,t=>Ke(t,n))};function z(n,e){return n.meta(e)}var S={pk:n=>z(n,{pk:!0,default:"random"}),req:n=>z(n,{notNull:!0}),col:(n,e)=>z(n,{column:e}),now:n=>z(n,{default:"now"}),unique:n=>z(n,{unique:!0}),dflt:(n,e)=>z(n,{default:e})};import{randomBytes as We,scrypt as ze,timingSafeEqual as He}from"node:crypto";import{promisify as Fe}from"node:util";var Ae=Fe(ze),Ve=64,ne={N:16384,r:8,p:1};async function J(n){let e=We(16),t=await Ae(n,e,Ve,ne);return`scrypt$${ne.N}$${ne.r}$${ne.p}$${e.toString("hex")}$${t.toString("hex")}`}async function re(n,e){let t=e.split("$");if(t.length!==6||t[0]!=="scrypt")return!1;let[,y,w,x,A,P]=t,Z=Buffer.from(P,"hex"),U=await Ae(n,Buffer.from(A,"hex"),Z.length,{N:Number(y),r:Number(w),p:Number(x)});return U.length===Z.length&&He(U,Z)}import{createHash as Je,createHmac as qe,randomBytes as Ge,timingSafeEqual as Xe}from"node:crypto";var Oe=n=>Buffer.from(JSON.stringify(n)).toString("base64url");function se(n,e,t){let y=Math.floor(Date.now()/1e3),w=`${Oe({alg:"HS256",typ:"JWT"})}.${Oe({...n,iat:y,exp:y+t})}`,x=qe("sha256",e).update(w).digest("base64url");return`${w}.${x}`}function ae(n,e){let t=n.split(".");if(t.length!==3)return null;let[y,w,x]=t,A=`${y}.${w}`,P=qe("sha256",e).update(A).digest("base64url"),Z=Buffer.from(x),U=Buffer.from(P);if(Z.length!==U.length||!Xe(Z,U))return null;try{let T=JSON.parse(Buffer.from(w,"base64url").toString("utf8"));return typeof T.exp=="number"&&T.exp<Date.now()/1e3?null:T}catch{return null}}function je(){return Ge(32).toString("hex")}function ie(n){return Je("sha256").update(n).digest("hex")}function N(n,e){return Response.json(n,{status:200,...e})}function L(n,e){return Response.json(n,{status:201,...e})}function $e(n){return new Response(null,{status:204,...n})}function H(n){return Response.json({error:n??"Bad Request"},{status:400})}import{randomBytes as Pe}from"node:crypto";var oe={users:{id:S.pk(o.uuid()),email:S.req(o.string()).meta({unique:!0}),password_hash:o.string().nullable(),name:o.string().nullable(),role:o.string().nullable(),tenant:o.string().nullable(),email_verified:o.boolean().meta({notNull:!0,default:!1}),created_at:S.now(o.date())},sessions:{token_hash:S.req(o.string()),user_id:S.req(o.uuid()),app_id:o.string().nullable(),expires_at:S.req(o.date()),revoked_at:o.date().nullable(),created_at:S.now(o.date())},apps:{id:S.pk(o.uuid()),slug:S.req(o.string()).meta({unique:!0}),name:S.req(o.string()),owner_user_id:o.uuid().nullable(),open_registration:o.boolean().meta({notNull:!0,default:!1}),app_key:o.string().nullable(),created_at:S.now(o.date())},members:{app_id:S.req(o.uuid()),user_id:S.req(o.uuid()),role:o.string().meta({notNull:!0,default:"member"}),invited_by:o.uuid().nullable(),joined_at:S.now(o.date()),source:o.string().nullable(),last_login_at:o.date().nullable()}},Ye="_weifuwu_users",Qe="_weifuwu_sessions",Se="_weifuwu_apps",$="00000000-0000-4000-8000-0000000000b1",Ze="_weifuwu_app_members",Ne=8,et=1024;function Te(n){if(n.length<Ne)throw new l(`password must be at least ${Ne} characters`,400);if(n.length>et)throw new l("password is too long",400)}function D(n){return n.trim().toLowerCase()}var Ue=null;async function Me(n){Ue??=await J("dummy-timing-equalize-password"),await re(n,Ue)}function Rt(n){let e=n.orm,t=e.table(Ye,oe.users),y=e.table(Qe,oe.sessions),w=e.table(Se,oe.apps),x=e.table(Ze,oe.members),A=n.secret??process.env.AUTH_SECRET;if(!A)throw new Error("userSystem: secret is required \u2014 pass options.secret or set AUTH_SECRET (at least 32 chars)");if(A.length<16)throw new Error("userSystem: secret must be at least 16 characters");let P=A,Z=n.hooks,U=n.allowedRoles??["owner","admin","member","viewer"],T=n.sso??null,ve=n.inviteRoles??U;function Re(a){if(a!==void 0&&!U.includes(a))throw new l(`invalid role: ${a}\uFF08allowed: ${U.join("/")}\uFF09`,403)}let De=n.accessTtlSeconds??3600,Ce=n.refreshTtlDays??30,Ee=n.prefix??"/api/auth",G=a=>({id:String(a.id),email:a.email,name:a.name,role:a.role,tenant:a.tenant}),Be=168*3600;async function ue(a){let m=await t.select("id","email","name","role","tenant").where({id:{eq:a}}).run();return m.length?m[0]:null}async function F(a,m){(await x.select("role").where({app_id:{eq:$},user_id:{eq:a}}).run()).length||await x.insert({app_id:$,user_id:a,role:"member",invited_by:null,source:m}).onConflict().run()}async function O(a,m){let h=await x.select("role").where({app_id:{eq:a},user_id:{eq:m}}).run();return h.length?String(h[0].role):null}async function C(a){let m=await w.select("id").where({slug:{eq:a}}).run();return m.length?String(m[0].id):null}async function K(a){let m=await t.select("id","email","name","role","tenant").where({email:{eq:a}}).run();return m.length?m[0]:null}async function Ie(a){return(await e.query.from(`${Ze} m`).select("m.app_id","m.role","a.id","a.slug","a.name").join(`${Se} a`,{"a.id":{col:"m.app_id"}}).where({"m.user_id":{eq:a}}).run()).filter(h=>!String(h.slug).startsWith("_")).map(h=>({id:String(h.id),slug:String(h.slug),name:String(h.name),role:String(h.role)}))}async function E(a,m){let h=se({sub:a.id,...a.email?{email:a.email}:{},...a.name?{name:a.name}:{},...m?.appId?{appId:m.appId,role:m.role}:{},...!m?.appId&&a.tenant?{tenantId:a.tenant}:{}},P,De),p=je(),s=new Date(Date.now()+Ce*24*3600*1e3);return await y.insert({token_hash:ie(p),user_id:a.id,expires_at:s.toISOString(),...m?.appId?{app_id:m.appId}:{}}).run(),{token:h,refreshToken:p}}async function Le(a){let m=await y.update({revoked_at:new Date().toISOString()}).where({token_hash:{eq:ie(a)},revoked_at:{isNull:!0}}).returning("user_id","expires_at","app_id").run();if(!m.length)throw new l("Invalid refresh token",401);let h=m[0];if(new Date(String(h.expires_at))<new Date)throw new l("Refresh token expired",401);let p=await ue(h.user_id);if(!p)throw new l("User not found",401);return{user:p,appId:h.app_id?String(h.app_id):void 0}}let B=(async(a,m,h)=>{let p=null,s=null,d={},i,c,R,q=a.headers.get("authorization"),M=null;if(q?.startsWith("Bearer "))M=q.slice(7);else if(a.method==="GET"){let r=new URL(a.url??"","http://localhost"),u=r.searchParams.get("ticket");if(u){let f=ae(u,P);f?.type==="download"&&f?.sub&&(s=await ue(String(f.sub)),p=s,d.userId=String(f.sub),f.appId!=null&&(c=f.appId,d.appId=String(f.appId)))}else M=r.searchParams.get("token")}if(M&&!s){let r=ae(M,P);if(r?.sub){s=await ue(String(r.sub)),p=s;for(let[u,f]of Object.entries(r))u==="sub"||u==="iat"||u==="exp"||u==="type"||(d[u]=f);d.userId=String(r.sub),i=r.tenantId,c=r.appId,R=r.role}}m.user=s,c!=null&&(m.appId=String(c)),m.session=c!=null?{userId:String(s.id),appId:String(c),role:String(R??"")}:null,i!=null&&(m.tenantId=String(i));let W={...d,async register(r){if(!r.email||!r.password)throw new l("email and password are required",400);Te(r.password);let u=D(r.email),f=await J(r.password),g=await t.insert({email:u,password_hash:f,name:r.name??null,role:null,tenant:r.tenant??null}).run(),k=G(g[0]),b=await E(k);return await F(k.id,"register"),p=k,{...b,user:k}},async registerWithApp(r){let u=await this.register({email:r.email,password:r.password,name:r.name});await F(u.user.id,"register");let f=(r.appSlug??r.email.split("@")[1]??"default").trim().toLowerCase(),g=f;for(let _=1;_<=200&&await C(g);_++)g=`${f}-${_}`;let k=await this.createApp({slug:g,name:r.appName??`${r.name??"\u7528\u6237"} \u7684\u5E94\u7528`,openRegistration:!1}),b=await E(u.user,{appId:k.id,role:"owner"});return await Z?.onRegisterApp?.(u.user.id,k),{...b,user:u.user,app:{...k,role:"owner"}}},async login(r,u){let g=(await t.select("id","email","password_hash","name","role","tenant").where({email:{eq:D(r)}}).run())[0];if(!g||g.password_hash==null)throw await Me(u),new l("Invalid email or password",401);if(!await re(u,String(g.password_hash)))throw new l("Invalid email or password",401);let b={id:String(g.id),email:String(g.email),name:g.name,role:g.role,tenant:g.tenant},_=await E(b),j=await Ie(b.id);return p=b,{..._,user:b,apps:j}},async logout(r){await y.update({revoked_at:new Date().toISOString()}).where({token_hash:{eq:ie(r)}}).run()},requireAuth(){if(!s)throw new l("Unauthorized",401);return s},async setPassword(r,u){Te(u);let f=await J(u);await t.update({password_hash:f}).where({id:{eq:r}}).run()},createToken(r,u,f){return se({type:r,...u},P,f.ttlSeconds)},async createApp(r){if(!p)throw new l("Unauthorized",401);if(!r.slug||!r.name)throw new l("slug and name are required",400);let u=r.slug.trim().toLowerCase();if(u.startsWith("_"))throw new l("slug \u4EE5 _ \u5F00\u5934\u4E3A\u7CFB\u7EDF\u4FDD\u7559\u540D",400);if(!await O($,p.id))throw new l("\u4EC5\u5E94\u7528\u7BA1\u7406\u9762\uFF08_builtin\uFF09\u6210\u5458\u53EF\u521B\u5EFA\u5E94\u7528",403);let g=Pe(32).toString("hex"),b=(await w.insert({slug:u,name:r.name,owner_user_id:p.id,open_registration:r.openRegistration??!1,app_key:g}).run())[0];return await x.insert({app_id:b.id,user_id:p.id,role:"owner",invited_by:p.id}).run(),b},async registerInApp(r){if(!r.email||!r.password)throw new l("email and password are required",400);Te(r.password);let u=await w.select("id","open_registration").where({slug:{eq:r.appSlug}}).run();if(!u.length)throw new l("Application not found",404);let f=u[0],g=String(f.id),k=D(r.email),b="member";if(!f.open_registration){if(!r.inviteToken)throw new l("Registration closed for this application",403);let I=ae(r.inviteToken,P);if(!I||I.type!=="app-invite"||I.appId!==g)throw new l("Invalid invite",403);if(I.email&&String(I.email)!==k)throw new l("Invite email mismatch",403);typeof I.role=="string"&&I.role!=="owner"&&(Re(I.role),b=I.role)}let _=await K(k);if(!_){let I=await J(r.password),X=await t.insert({email:k,password_hash:I,name:r.name??null,role:null,tenant:null}).onConflict("email").run();if(_=X.length?G(X[0]):await K(k),!_)throw new l("User creation failed",500)}await F(_.id,"register"),await O(g,_.id)||await x.insert({app_id:g,user_id:_.id,role:b,invited_by:p?.id??null,source:"invite"}).onConflict().run();let V=await E(_,{appId:g,role:b});return await x.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:g},user_id:{eq:_.id}}).run(),p=_,await Z?.onJoinApp?.(_.id,g,b),{...V,user:_}},async loginApp(r,u,f){let g=await w.select("id").where({slug:{eq:r}}).run();if(!g.length)throw new l("Application not found",404);let k=String(g[0].id),_=(await t.select("id","email","password_hash","name","role","tenant").where({email:{eq:D(u)}}).run())[0];if(!_||_.password_hash==null)throw await Me(f),new l("Invalid email or password",401);if(!await re(f,String(_.password_hash)))throw new l("Invalid email or password",401);let V=await O(k,String(_.id));if(!V)throw new l("Not a member of this application",401);let I={id:String(_.id),email:String(_.email),name:_.name,role:_.role,tenant:_.tenant},X=await E(I,{appId:k,role:V});return await x.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:k},user_id:{eq:I.id}}).run(),p=I,{...X,user:I,role:V}},async ssoLogin(r,u){let f=D(r),g=await K(f);if(!g){let _=await t.insert({email:f,password_hash:null,name:u?.name??null,role:null,tenant:null}).onConflict("email").run();if(g=_.length?G(_[0]):await K(f),!g)throw new l("User creation failed",500)}await F(g.id,"sso");let k;u?.appId&&(await O(u.appId,g.id)||await x.insert({app_id:u.appId,user_id:g.id,role:"member",invited_by:null,source:"sso"}).onConflict().run(),k=u.appId,await x.update({last_login_at:new Date().toISOString()}).where({app_id:{eq:u.appId},user_id:{eq:g.id}}).run());let b=await E(g,k?{appId:k,role:"member"}:void 0);return p=g,{...b,user:g}},async createInvite(r,u){if(r===$)throw new l("_builtin \u4E0D\u8D70\u9080\u8BF7\u6D41\uFF08\u4EFB\u547D\u5236\uFF09",403);if(u.role!==void 0&&!ve.includes(u.role))throw new l(`invite role not allowed: ${u.role}\uFF08allowed: ${ve.join("/")}\uFF09`,403);if(!p)throw new l("Unauthorized",401);if(await O(r,p.id)!=="owner")throw new l("Owner only",403);let g=u.role&&u.role!=="owner"?u.role:"member";return{inviteToken:se({type:"app-invite",appId:r,...u.email?{email:D(u.email)}:{},role:g},P,Be)}},async addMember(r,u,f){if(Re(f),r===$&&f!==void 0&&f==="viewer")throw new l("_builtin \u65E0\u53EA\u8BFB\uFF08viewer \u7981\u2014\u2014\u7BA1\u7406\u9762\u8EAB\u4EFD\uFF09",403);if(!p)throw new l("Unauthorized",401);if(await O(r,p.id)!=="owner")throw new l("Owner only",403);let k=await t.select("id").where({email:{eq:D(u)}}).run();if(!k.length)throw new l("User not found \u2014 invite them to register first",400);let b=f&&f!=="owner"?f:"member";await x.insert({app_id:r,user_id:String(k[0].id),role:b,invited_by:p.id}).run()},async setOpenRegistration(r,u){if(!p)throw new l("Unauthorized",401);if(r===$)throw new l("_builtin \u6CE8\u518C\u5F00\u5173\u6052 false",403);if(await O(r,p.id)!=="owner")throw new l("Owner only",403);await w.update({open_registration:u}).where({id:{eq:r}}).run()},async listMyApps(){if(!p)throw new l("Unauthorized",401);return Ie(p.id)},async requireApp(r){if(!p)throw new l("Unauthorized",401);let u=await O(r,p.id);if(!u)throw new l("Not a member of this application",403);return{userId:p.id,appId:r,role:u}}};return m.auth=W,h(a,m)});return B.__meta={injects:["user","auth"],depends:[]},B.seedBuiltinOwners=async a=>{let m={owner:null,admins:[]};for(let h of a){let p=D(h);if(!p)continue;let s=await K(p);if(!s){let i=await t.insert({email:p,password_hash:null,name:null,role:null,tenant:null}).onConflict("email").run();s=i.length?G(i[0]):await K(p)}if(!s)continue;let d=await x.select("role").where({app_id:{eq:$},user_id:{eq:s.id}}).run();if(d.length){String(d[0].role??"")==="owner"?m.owner=String(s.id):m.admins.push(String(s.id));continue}if(m.owner)await x.insert({app_id:$,user_id:String(s.id),role:"admin",invited_by:m.owner,source:"seed"}).run(),m.admins.push(String(s.id));else{await x.insert({app_id:$,user_id:String(s.id),role:"owner",invited_by:null,source:"seed"}).run(),m.owner=String(s.id);let i=await C("_default");i&&(await O(i,String(s.id))||await x.insert({app_id:i,user_id:String(s.id),role:"owner",invited_by:null,source:"seed"}).run())}}return m},B.migrate=async()=>{(await w.select("id").where({slug:{eq:"_builtin"}}).run()).length||await e.query.insert(Se).values({id:$,slug:"_builtin",name:"System",owner_user_id:null,open_registration:!1}).returning("id").run();let m=await w.select("id").where({app_key:{isNull:!0}}).run();for(let d of m)await w.update({app_key:Pe(32).toString("hex")}).where({id:{eq:String(d.id)}}).run();(await w.select("id").where({slug:{eq:"_default"}}).run()).length||await w.insert({slug:"_default",name:"Default",owner_user_id:null,open_registration:!1}).run();let p=await C("_default");if(p){let d=await x.select("user_id").where({app_id:{eq:$},role:{eq:"owner"}}).run();for(let i of d){let c=String(i.user_id);await O(p,c)||await x.insert({app_id:p,user_id:c,role:"owner",invited_by:null,source:"migrate"}).onConflict().run()}}let s=await t.select("id").run();for(let d of s)await F(String(d.id),"migrate")},B.routes=(a,m)=>{let h=m?.prefix??Ee,p=new Set(m?.exclude??[]);if(p.has("register")||a.post(`${h}/register`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await d.auth.register(i);return L(c)}),p.has("register")||a.post(`${h}/register-app`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await d.auth.registerWithApp(i);return L(c)}),p.has("login")||a.post(`${h}/login`,async(s,d)=>{let i=await s.json().catch(()=>({}));if(!i.email||!i.password)return H("email and password are required");let c=await d.auth.login(i.email,i.password);return N(c)}),p.has("logout")||a.post(`${h}/logout`,async(s,d)=>{let i=await s.json().catch(()=>({}));return i.refreshToken?(await d.auth.logout(i.refreshToken),$e()):H("refreshToken is required")}),p.has("refresh")||a.post(`${h}/refresh`,async(s,d)=>{let i=await s.json().catch(()=>({}));if(!i.refreshToken)throw new l("refreshToken is required",400);let{user:c,appId:R}=await Le(i.refreshToken),q;if(R){let W=await O(R,c.id);W&&(q={appId:R,role:W})}let M=await E(c,q);return N({...M,user:c})}),p.has("me")||a.get(`${h}/me`,async(s,d)=>{if(!d.user)throw new l("Unauthorized",401);return N({user:d.user,session:d.session??null})}),T){let s=`${h}/apps/_builtin/auth/sso`;a.get(`${s}/enabled`,async()=>N({enabled:!0,appSlug:T.defaultAppSlug??null})),a.get(`${s}/login`,async d=>{let c=new URL(d.url??"","http://localhost").searchParams.get("app")??T.defaultAppSlug,R=new URLSearchParams({response_type:"code",client_id:T.clientId,redirect_uri:T.redirectBase?`${T.redirectBase.replace(/\/$/,"")}${s}/callback`:`${new URL(d.url,"http://localhost").origin}${s}/callback`,scope:T.scope??"openid email profile",state:c??"sso"});return new Response(null,{status:302,headers:{Location:`${T.issuer.replace(/\/$/,"")}/authorize?${R}`}})}),a.get(`${s}/callback`,async(d,i)=>{let c=new URL(d.url??"","http://localhost"),R=c.searchParams.get("code");if(!R)throw new l("SSO \u56DE\u8C03\u7F3A\u5C11 code",400);let q=T.redirectBase?`${T.redirectBase.replace(/\/$/,"")}${s}/callback`:`${c.origin}${s}/callback`,M=await fetch(`${T.issuer.replace(/\/$/,"")}/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:R,redirect_uri:q,client_id:T.clientId,client_secret:T.clientSecret})});if(!M.ok)throw new l("SSO token \u4EA4\u6362\u5931\u8D25",401);let W=await M.json(),r=await fetch(`${T.issuer.replace(/\/$/,"")}/userinfo`,{headers:{Authorization:`Bearer ${W.access_token}`}});if(!r.ok)throw new l("SSO \u7528\u6237\u4FE1\u606F\u83B7\u53D6\u5931\u8D25",401);let u=await r.json(),f=(u.email??"").trim().toLowerCase();if(!f)throw new l("SSO \u672A\u8FD4\u56DE\u90AE\u7BB1\uFF08\u9700\u8981 email scope\uFF09",401);let g=c.searchParams.get("state"),k;if(g&&g!=="sso"){let j=await C(g);j&&(k=j)}let b=await i.auth.ssoLogin(f,{appId:k,name:u.name});await Z?.onSsoLogin?.(b.user.id,k);let _={token:b.token,refreshToken:b.refreshToken,user:b.user};if(T.renderCallback){let j=T.renderCallback(_);return typeof j=="string"?new Response(j,{headers:{"Content-Type":"text/html; charset=utf-8"}}):j}return N(_)})}p.has("apps")||(a.post(`${h}/apps`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await d.auth.createApp(i);return L({app:c})}),a.get(`${h}/apps`,async(s,d)=>{let i=await d.auth.listMyApps();return N({apps:i})}),a.post(`${h}/apps/:appSlug/auth/members`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await C(d.params.appSlug);if(!c)throw new l("Application not found",404);return await d.auth.addMember(c,i.email??"",i.role),L({ok:!0})}),a.post(`${h}/apps/:appSlug/auth/invites`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await C(d.params.appSlug);if(!c)throw new l("Application not found",404);let R=await d.auth.createInvite(c,{email:i.email,role:i.role});return L(R)}),a.post(`${h}/apps/:appSlug/auth/login`,async(s,d)=>{let i=await s.json().catch(()=>({}));if(!i.email||!i.password)return H("email and password are required");let c=await d.auth.loginApp(d.params.appSlug,i.email,i.password);return N(c)}),a.patch(`${h}/apps/:appSlug/auth/registration`,async(s,d)=>{let i=await s.json().catch(()=>({}));if(typeof i.open!="boolean")return H("open is required (boolean)");let c=await C(d.params.appSlug);if(!c)throw new l("Application not found",404);return await d.auth.setOpenRegistration(c,i.open),N({open:i.open})}),a.post(`${h}/apps/:appSlug/auth/verify`,async(s,d)=>{let i=s.headers.get("x-wf-app-id"),c=s.headers.get("x-wf-app-key");if(!i||!c)return H("X-Wf-App-Id / X-Wf-App-Key required");let R=await w.select("id","slug","name").where({id:{eq:i},app_key:{eq:c}}).run();if(!R.length)throw new l("Invalid app credentials",403);let q=R[0];return N({app:{id:String(q.id),slug:String(q.slug),name:String(q.name)}})}),a.post(`${h}/apps/:appSlug/auth/register`,async(s,d)=>{let i=await s.json().catch(()=>({})),c=await d.auth.registerInApp({appSlug:d.params.appSlug,email:i.email??"",password:i.password??"",name:i.name,inviteToken:i.inviteToken});return L(c)}))},B.asAppAuth=()=>B,B}var It={tables:[{name:"_weifuwu_users",columns:{id:S.pk(o.uuid()),email:S.req(o.string()).meta({unique:!0}),password_hash:o.string(),name:o.string(),role:o.string(),tenant:o.string(),email_verified:o.boolean().meta({default:!1}),created_at:o.date().meta({default:"now"})},dropNotNull:["password_hash"]},{name:"_weifuwu_sessions",columns:{token_hash:o.string().meta({pk:!0}),user_id:S.req(o.uuid()).meta({references:"_weifuwu_users",onDelete:"cascade"}),app_id:o.string(),expires_at:o.date().meta({notNull:!0}),revoked_at:o.date(),created_at:o.date().meta({default:"now"})}},{name:"_weifuwu_apps",columns:{id:S.pk(o.uuid()),slug:S.req(o.string()).meta({unique:!0}),name:S.req(o.string()),owner_user_id:o.uuid().meta({references:"_weifuwu_users",onDelete:"cascade"}),open_registration:o.boolean().meta({default:!1}),created_at:o.date().meta({default:"now"}),app_key:o.string()}},{name:"_weifuwu_app_members",columns:{app_id:S.req(o.uuid()).meta({references:"_weifuwu_apps",onDelete:"cascade"}),user_id:S.req(o.uuid()).meta({references:"_weifuwu_users",onDelete:"cascade"}),role:o.string().meta({default:"member"}),invited_by:o.uuid(),joined_at:o.date().meta({default:"now"}),source:o.string(),last_login_at:o.date()},uniques:[["app_id","user_id"]]}]};export{$ as BUILTIN_APP_ID,oe as USER_TABLES,It as WEIFUWU_USER_SCHEMA,Rt as userSystem};
|
package/docs/client.md
CHANGED
|
@@ -41,7 +41,7 @@ TS/TSX 源码树,仅供 `ctx.ui` 浏览器编译,Node 在 `node_modules` 下
|
|
|
41
41
|
| `weifuwu/dist/level6/client/components/index.js` | `src/level6/client/components/index.ts`(138 组件) |
|
|
42
42
|
| `weifuwu/dist/level6/client/components/style.css` | dist 聚合样式(layout + 组件全量) |
|
|
43
43
|
| `weifuwu/dist/level6/client/layout/index.js` | `src/level6/client/layout/index.ts`(defineLayout + 装配) |
|
|
44
|
-
| `weifuwu/dist/
|
|
44
|
+
| `weifuwu/dist/level6/client/layout/weifuwu-layout.css` | 布局原语 CSS(独立面——聚合产物;`level5/.../weifuwu-layout.css` 为 @import 装配入口) |
|
|
45
45
|
| `weifuwu/dist/level0/router/index.js` | `src/level0/router/index.ts`(trie/pipeline/context/chain 五件) |
|
|
46
46
|
| `weifuwu/dist/level6/dev/index.js` | `src/level6/dev/index.ts`(`node --import weifuwu/dist/level6/dev/index.js server.ts`) |
|
|
47
47
|
|
|
@@ -156,7 +156,7 @@ TS/TSX 源码树,仅供 `ctx.ui` 浏览器编译,Node 在 `node_modules` 下
|
|
|
156
156
|
**载荷面(W6 minify)**:dist 发布产物 `weifuwu-layout.css` **29.4K**(gzip 5.7K · brotli 5.0K)·
|
|
157
157
|
`weifuwu/dist/level6/client/components/style.css` **221.4K**(gzip 29.1K · brotli 23.4K)——esbuild minify(
|
|
158
158
|
`build.mjs` 实装:`@layer`/`@property`/`@supports`/转义类名全保留,注释全剥离);
|
|
159
|
-
**无组件应用只引 `weifuwu/dist/
|
|
159
|
+
**无组件应用只引 `weifuwu/dist/level6/client/layout/weifuwu-layout.css`**(29.4K / br 5.0K——独立面,零组件 CSS 成本)。
|
|
160
160
|
按需子集(per-component 子路径 / purge)**判负**:动态类名漏删风险 + 构建期改造成本
|
|
161
161
|
+ br 后 24.3K 非瓶颈——推翻条件:真实应用首屏 CSS 成为 LCP 阻塞的实测数据。
|
|
162
162
|
|
package/docs/level.md
CHANGED
|
@@ -102,7 +102,7 @@ npm run test:levels # 内核回归(level0–4——无 docker/无浏览
|
|
|
102
102
|
| L3 客户端运行时 | 51 | 7707 | 203 | 0 | 0 |
|
|
103
103
|
| L4 生成器 | 7 | 693 | 22 | 0 | 0 |
|
|
104
104
|
| L5 装备 | 235 | 35992 | 895 | 167 | 347 |
|
|
105
|
-
| L6 装配+应用 |
|
|
105
|
+
| L6 装配+应用 | 173 | 35629 | 999 | 17 | 0 |
|
|
106
106
|
|
|
107
107
|
闭包读数:(迁移后)由目录定级——level1 通用 19 · level3 客户端 51(剥注释口径——分类规则见 git log)
|
|
108
108
|
|
package/docs/migration.md
CHANGED
|
@@ -22,7 +22,7 @@ Node 在 `node_modules` 下拒绝 TS 类型剥离(`ERR_UNSUPPORTED_NODE_MODULE
|
|
|
22
22
|
| `weifuwu/client/components` | `weifuwu/dist/level6/client/components/index.js` | 同上 |
|
|
23
23
|
| `weifuwu/client/components/style.css` | `weifuwu/dist/level6/client/components/style.css` | — |
|
|
24
24
|
| `weifuwu/client/layout` · `weifuwu/layout` | `weifuwu/dist/level6/client/layout/index.js` | 同上 |
|
|
25
|
-
| `weifuwu/client/layout/weifuwu-layout.css` | `weifuwu/dist/
|
|
25
|
+
| `weifuwu/client/layout/weifuwu-layout.css` | `weifuwu/dist/level6/client/layout/weifuwu-layout.css` | — |
|
|
26
26
|
| `weifuwu/dev` | `weifuwu/dist/level6/dev/index.js` | — |
|
|
27
27
|
| `weifuwu/shared/router` | `weifuwu/dist/level0/router/index.js` | 同上 |
|
|
28
28
|
|
|
@@ -73,6 +73,11 @@ showcase 无必需 env(`PORT` 可选)。
|
|
|
73
73
|
|
|
74
74
|
## 4. 框架开发者(源码级)
|
|
75
75
|
|
|
76
|
+
- **应用 bundle 路径锚点**:esbuild 把 app server 打成单文件后,`import.meta.url` = bundle 位置——
|
|
77
|
+
源码目录相对的 `__dirname` 推导全部失真。应用相对路径(skills/public/sandbox-agent/框架 dist)
|
|
78
|
+
必须经 `app-root.ts` 的 `APP_ROOT` 推导(dev 与 dist 同语义——0.95.0 安装包实证);
|
|
79
|
+
JSX 编译器 `jsxImportSource` 必须绝对路径(`weifuwu/client/vdom` 裸系已不可解析)。
|
|
80
|
+
|
|
76
81
|
- 源码路径 `src/{core,client,server,shared}` → `src/level0`–`src/level6`(目录即层级);
|
|
77
82
|
- 分类清单 `src/levels.json`;守卫 `npm run audit:levels`(方向/环境/三方/规模/docs/L0 快照);
|
|
78
83
|
- 旧 116 个兼容 shim 已全量删除(无过渡层)——包内导入已全量重写;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weifuwu",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.95.
|
|
4
|
+
"version": "0.95.2",
|
|
5
5
|
"description": "AI SaaS full-stack framework — backend HTTP + frontend VDOM + 138 components + CSS design system + SaaS foundation (auth/queue/AI). Zero-build, zero-dependency.",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist/",
|