failproofai 0.0.11-beta.8 → 0.0.11
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
- package/.next/standalone/.next/build-manifest.json +6 -6
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/routes-manifest.json +6 -0
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/audit/invite/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/audit/invite/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +7 -0
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/audit/invite/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/audit/run/route.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +2 -2
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +2 -2
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js +2 -2
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +2 -2
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +2 -2
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/policies/page.js +2 -2
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +3 -3
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +3 -3
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +3 -3
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
- package/.next/standalone/.next/server/chunks/[externals]__1_g_b3t._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0dwpg-h._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lnenda._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13i_sva._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1_mqemn._.js +1 -1
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_audit_invite_route_actions_0-2n5sy.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_0-tu4ot._.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_0ttxbz7._.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_1bnh1y0._.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_1epycqa._.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_1wpdcgo._.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +3 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1d4gx_t._.js → [root-of-the-server]__00uwqi6._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0808sha._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1cd25c7._.js → [root-of-the-server]__0e4-6d8._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ehe24g._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1-scthx._.js → [root-of-the-server]__0f62vu9._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g253ve._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0l13qf2._.js → [root-of-the-server]__0k65l27._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__15i0juc._.js → [root-of-the-server]__0kjb_s4._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0vxf0_g._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12mcauo._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0989_dx._.js → [root-of-the-server]__1e-x7j4._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mt35_w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pcxxwg._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1uvfwgr._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/_05whahf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0il3fl1._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +49 -21
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_0ihmbv4.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1ao30b1.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +10 -10
- package/.next/standalone/.next/static/chunks/{0d49wc5zca0u1.js → 02fywjt0by40a.js} +1 -1
- package/.next/standalone/.next/static/chunks/0f7d7hnbh4djs.js +1 -0
- package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +1 -0
- package/.next/standalone/.next/static/chunks/0xdx2ehtbdoeg.js +1 -0
- package/.next/standalone/.next/static/chunks/{1nd1e30h8s_mc.js → 1-a5rvq67k7ed.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1m2yj97j7f_km.js → 15csyj1_rf0-w.js} +1 -1
- package/.next/standalone/.next/static/chunks/1o0xa47736gi9.css +2 -0
- package/.next/standalone/.next/static/chunks/24cv31x607n7k.js +1 -0
- package/.next/standalone/.next/static/chunks/{3w8d8k_dca5rp.js → 2h0dkzyy0vocp.js} +1 -1
- package/.next/standalone/.next/static/chunks/2n_s8v1ae38_a.js +69 -0
- package/.next/standalone/.next/static/chunks/2y-jmvrjxz60x.js +6 -0
- package/.next/standalone/.next/static/chunks/{24z-bgbisv379.js → 3eik_d9qrvoft.js} +1 -1
- package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +1 -0
- package/.next/standalone/.next/static/chunks/{0j969hb6nujdf.js → 3v61675vr6jav.js} +1 -1
- package/.next/standalone/.next/static/chunks/3zkg2s2vzxc3d.js +1 -0
- package/.next/standalone/.next/static/chunks/{turbopack-00qy7zfa7m--m.js → turbopack-3lrm4f20fz89b.js} +1 -1
- package/.next/standalone/app/api/audit/invite/route.ts +192 -0
- package/.next/standalone/app/api/audit/run/route.ts +35 -0
- package/.next/standalone/app/api/auth/login-request/route.ts +2 -2
- package/.next/standalone/app/api/auth/login-verify/route.ts +10 -2
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +39 -63
- package/.next/standalone/app/audit/_components/audit-poster.tsx +326 -0
- package/.next/standalone/app/audit/_components/auth-dialog.tsx +23 -49
- package/.next/standalone/app/audit/_components/come-back-better-section.tsx +336 -0
- package/.next/standalone/app/audit/_components/how-to-improve-section.tsx +187 -0
- package/.next/standalone/app/audit/_components/invite-dialog.tsx +230 -0
- package/.next/standalone/app/audit/_components/quirks-section.tsx +75 -0
- package/.next/standalone/app/audit/_components/share-templates.ts +63 -32
- package/.next/standalone/app/audit/_components/sigil.tsx +9 -66
- package/.next/standalone/app/audit/_components/strengths-section.tsx +20 -32
- package/.next/standalone/app/audit/audit-styles.css +778 -1786
- package/.next/standalone/app/components/sessions-list.tsx +77 -80
- package/.next/standalone/app/globals.css +241 -34
- package/.next/standalone/app/layout.tsx +1 -10
- package/.next/standalone/app/policies/hooks-client.tsx +45 -28
- package/.next/standalone/app/project/[name]/page.tsx +23 -79
- package/.next/standalone/app/projects/page.tsx +14 -23
- package/.next/standalone/assets/audit/poster-styles.css +1 -1
- package/.next/standalone/assets/audit/styles.css +11 -11
- package/.next/standalone/components/navbar.tsx +2 -37
- package/.next/standalone/components/reach-developers.tsx +10 -25
- package/.next/standalone/lib/auth/api-server-client.ts +28 -0
- package/.next/standalone/lib/client-telemetry.ts +4 -0
- package/.next/standalone/node_modules/@next/env/package.json +2 -2
- package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
- package/.next/standalone/node_modules/next/package.json +15 -15
- package/.next/standalone/package.json +19 -14
- package/.next/standalone/server.js +1 -1
- package/README.md +2 -2
- package/bin/failproofai.mjs +24 -5
- package/dist/cli.mjs +2328 -381
- package/lib/auth/api-server-client.ts +28 -0
- package/lib/client-telemetry.ts +4 -0
- package/package.json +19 -14
- package/scripts/launch.ts +30 -4
- package/scripts/postinstall.mjs +10 -1
- package/scripts/skew-log-filter.ts +46 -0
- package/scripts/validate-mdx.ts +139 -0
- package/src/audit/cli.ts +330 -0
- package/src/audit/open-browser.ts +69 -0
- package/src/audit/social-proof.ts +34 -0
- package/src/auth/cli.ts +16 -13
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07tgnzi._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oeun7z._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__12pit4m._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13ra2jq._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1b9z5-i._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ixjiy8._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1-1804f._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00jkjmt._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013du6r._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e85wxv._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0gfxvb1._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1hlrq6y._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ihxdo5._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1vvfde2._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html2canvas_dist_html2canvas_esm_1k58rb_.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html2canvas_dist_html2canvas_esm_1n-0xws.js +0 -3
- package/.next/standalone/.next/static/chunks/09ueq8s1as8xs.css +0 -2
- package/.next/standalone/.next/static/chunks/0qassxjx1ef04.js +0 -1
- package/.next/standalone/.next/static/chunks/0qxb5czqxe-vu.js +0 -1
- package/.next/standalone/.next/static/chunks/1dh06515j265n.js +0 -41
- package/.next/standalone/.next/static/chunks/29gs4efgi3hme.js +0 -6
- package/.next/standalone/.next/static/chunks/2mni177pnjx6u.js +0 -1
- package/.next/standalone/.next/static/chunks/2so39wg7mjbi7.js +0 -1
- package/.next/standalone/.next/static/chunks/3gti1qdk5epqn.js +0 -1
- package/.next/standalone/.next/static/chunks/3wycox197ouus.css +0 -1
- package/.next/standalone/app/audit/_components/findings-section.tsx +0 -135
- package/.next/standalone/app/audit/_components/identity-section.tsx +0 -126
- package/.next/standalone/app/audit/_components/policies-section.tsx +0 -194
- package/.next/standalone/app/audit/_components/return-section.tsx +0 -416
- package/.next/standalone/app/audit/_components/score-section.tsx +0 -179
- package/.next/standalone/app/audit/_components/share-dock.tsx +0 -265
- package/.next/standalone/app/audit/_components/show-off-cta.tsx +0 -135
- /package/.next/standalone/.next/static/{CVv2A0hMd24t0c0x3V-W_ → P_MIRSeoE296wkbE-Icin}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{CVv2A0hMd24t0c0x3V-W_ → P_MIRSeoE296wkbE-Icin}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{CVv2A0hMd24t0c0x3V-W_ → P_MIRSeoE296wkbE-Icin}/_ssgManifest.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,66459,e=>{"use strict";let t;var r=e.i(47167);let n=(t=0,()=>(t+=1,`u${`0000${(1679616*Math.random()|0).toString(36)}`.slice(-4)}${t}`));function l(e){let t=[];for(let r=0,n=e.length;r<n;r++)t.push(e[r]);return t}let i=null;function a(e={}){return i||(i=e.includeStyleProperties?e.includeStyleProperties:l(window.getComputedStyle(document.documentElement)))}function o(e,t){let r=(e.ownerDocument.defaultView||window).getComputedStyle(e).getPropertyValue(t);return r?parseFloat(r.replace("px","")):0}function c(e,t={}){let r,n,l,i;return{width:t.width||(r=o(e,"border-left-width"),n=o(e,"border-right-width"),e.clientWidth+r+n),height:t.height||(l=o(e,"border-top-width"),i=o(e,"border-bottom-width"),e.clientHeight+l+i)}}function s(e){return new Promise((t,r)=>{let n=new Image;n.onload=()=>{n.decode().then(()=>{requestAnimationFrame(()=>t(n))})},n.onerror=r,n.crossOrigin="anonymous",n.decoding="async",n.src=e})}async function u(e){return Promise.resolve().then(()=>new XMLSerializer().serializeToString(e)).then(encodeURIComponent).then(e=>`data:image/svg+xml;charset=utf-8,${e}`)}async function h(e,t,r){let n="http://www.w3.org/2000/svg",l=document.createElementNS(n,"svg"),i=document.createElementNS(n,"foreignObject");return l.setAttribute("width",`${t}`),l.setAttribute("height",`${r}`),l.setAttribute("viewBox",`0 0 ${t} ${r}`),i.setAttribute("width","100%"),i.setAttribute("height","100%"),i.setAttribute("x","0"),i.setAttribute("y","0"),i.setAttribute("externalResourcesRequired","true"),l.appendChild(i),i.appendChild(e),u(l)}let d=(e,t)=>{if(e instanceof t)return!0;let r=Object.getPrototypeOf(e);return null!==r&&(r.constructor.name===t.name||d(r,t))};function f(e,t,r,l){let i,o,c,s=window.getComputedStyle(e,r),u=s.getPropertyValue("content");if(""===u||"none"===u)return;let h=n();try{t.className=`${t.className} ${h}`}catch(e){return}let d=document.createElement("style");d.appendChild((i=`.${h}:${r}`,c=s.cssText?(o=s.getPropertyValue("content"),`${s.cssText} content: '${o.replace(/'|"/g,"")}';`):a(l).map(e=>{let t=s.getPropertyValue(e),r=s.getPropertyPriority(e);return`${e}: ${t}${r?" !important":""};`}).join(" "),document.createTextNode(`${i}{${c}}`))),t.appendChild(d)}let m="application/font-woff",g="image/jpeg",p={woff:m,woff2:m,ttf:"application/font-truetype",eot:"application/vnd.ms-fontobject",png:"image/png",jpg:g,jpeg:g,gif:"image/gif",tiff:"image/tiff",svg:"image/svg+xml",webp:"image/webp"};function y(e){let t;return p[((t=/\.([^./]*?)$/g.exec(e))?t[1]:"").toLowerCase()]||""}function w(e){return -1!==e.search(/^(data:)/)}function b(e,t){return`data:${t};base64,${e}`}async function S(e,t,r){let n=await fetch(e,t);if(404===n.status)throw Error(`Resource "${n.url}" not found`);let l=await n.blob();return new Promise((e,t)=>{let i=new FileReader;i.onerror=t,i.onloadend=()=>{try{e(r({res:n,result:i.result}))}catch(e){t(e)}},i.readAsDataURL(l)})}let E={};async function x(e,t,r){var n,l,i;let a,o,c=(n=e,l=t,i=r.includeQueryParams,o=n.replace(/\?.*/,""),i&&(o=n),/ttf|otf|eot|woff2?/i.test(o)&&(o=o.replace(/.*\//,"")),l?`[${l}]${o}`:o);if(null!=E[c])return E[c];r.cacheBust&&(e+=(/\?/.test(e)?"&":"?")+new Date().getTime());try{let n=await S(e,r.fetchRequestInit,({res:e,result:r})=>(t||(t=e.headers.get("Content-Type")||""),r.split(/,/)[1]));a=b(n,t)}catch(n){a=r.imagePlaceholder||"";let t=`Failed to fetch resource: ${e}`;n&&(t="string"==typeof n?n:n.message),t&&console.warn(t)}return E[c]=a,a}async function $(e){let t=e.toDataURL();return"data:,"===t?e.cloneNode(!1):s(t)}async function v(e,t){if(e.currentSrc){let t=document.createElement("canvas"),r=t.getContext("2d");return t.width=e.clientWidth,t.height=e.clientHeight,null==r||r.drawImage(e,0,0,t.width,t.height),s(t.toDataURL())}let r=e.poster,n=y(r);return s(await x(r,n,t))}async function C(e,t){var r;try{if(null==(r=null==e?void 0:e.contentDocument)?void 0:r.body)return await N(e.contentDocument.body,t,!0)}catch(e){}return e.cloneNode(!1)}async function P(e,t){return d(e,HTMLCanvasElement)?$(e):d(e,HTMLVideoElement)?v(e,t):d(e,HTMLIFrameElement)?C(e,t):e.cloneNode(R(e))}let R=e=>null!=e.tagName&&"SVG"===e.tagName.toUpperCase();async function T(e,t,r){var n,i;if(R(t))return t;let a=[];return 0===(a=null!=e.tagName&&"SLOT"===e.tagName.toUpperCase()&&e.assignedNodes?l(e.assignedNodes()):d(e,HTMLIFrameElement)&&(null==(n=e.contentDocument)?void 0:n.body)?l(e.contentDocument.body.childNodes):l((null!=(i=e.shadowRoot)?i:e).childNodes)).length||d(e,HTMLVideoElement)||await a.reduce((e,n)=>e.then(()=>N(n,r)).then(e=>{e&&t.appendChild(e)}),Promise.resolve()),t}async function A(e,t){let r=e.querySelectorAll?e.querySelectorAll("use"):[];if(0===r.length)return e;let n={};for(let l=0;l<r.length;l++){let i=r[l].getAttribute("xlink:href");if(i){let r=e.querySelector(i),l=document.querySelector(i);r||!l||n[i]||(n[i]=await N(l,t,!0))}}let l=Object.values(n);if(l.length){let t="http://www.w3.org/1999/xhtml",r=document.createElementNS(t,"svg");r.setAttribute("xmlns",t),r.style.position="absolute",r.style.width="0",r.style.height="0",r.style.overflow="hidden",r.style.display="none";let n=document.createElementNS(t,"defs");r.appendChild(n);for(let e=0;e<l.length;e++)n.appendChild(l[e]);e.appendChild(r)}return e}async function N(e,t,r){return r||!t.filter||t.filter(e)?Promise.resolve(e).then(e=>P(e,t)).then(r=>T(e,r,t)).then(r=>(function(e,t,r){if(d(t,Element)&&(!function(e,t,r){let n=t.style;if(!n)return;let l=window.getComputedStyle(e);l.cssText?(n.cssText=l.cssText,n.transformOrigin=l.transformOrigin):a(r).forEach(r=>{let i=l.getPropertyValue(r);if("font-size"===r&&i.endsWith("px")){let e=Math.floor(parseFloat(i.substring(0,i.length-2)))-.1;i=`${e}px`}d(e,HTMLIFrameElement)&&"display"===r&&"inline"===i&&(i="block"),"d"===r&&t.getAttribute("d")&&(i=`path(${t.getAttribute("d")})`),n.setProperty(r,i,l.getPropertyPriority(r))})}(e,t,r),f(e,t,":before",r),f(e,t,":after",r),d(e,HTMLTextAreaElement)&&(t.innerHTML=e.value),d(e,HTMLInputElement)&&t.setAttribute("value",e.value),d(e,HTMLSelectElement))){let r=Array.from(t.children).find(t=>e.value===t.getAttribute("value"));r&&r.setAttribute("selected","")}return t})(e,r,t)).then(e=>A(e,t)):null}let L=/url\((['"]?)([^'"]+?)\1\)/g,k=/url\([^)]+\)\s*format\((["']?)([^"']+)\1\)/g,I=/src:\s*(?:url\([^)]+\)\s*format\([^)]+\)[,;]\s*)+/g;async function H(e,t,r,n,l){try{let i,a,o=r?function(e,t){if(e.match(/^[a-z]+:\/\//i))return e;if(e.match(/^\/\//))return window.location.protocol+e;if(e.match(/^[a-z]+:/i))return e;let r=document.implementation.createHTMLDocument(),n=r.createElement("base"),l=r.createElement("a");return r.head.appendChild(n),r.body.appendChild(l),t&&(n.href=t),l.href=e,l.href}(t,r):t,c=y(t);if(l){let e=await l(o);i=b(e,c)}else i=await x(o,c,n);return e.replace((a=t.replace(/([.*+?^${}()|\[\]\/\\])/g,"\\$1"),RegExp(`(url\\(['"]?)(${a})(['"]?\\))`,"g")),`$1${i}$3`)}catch(e){}return e}function M(e){return -1!==e.search(L)}async function V(e,t,r){let n;if(!M(e))return e;let l=function(e,{preferredFontFormat:t}){return t?e.replace(I,e=>{for(;;){let[r,,n]=k.exec(e)||[];if(!n)return"";if(n===t)return`src: ${r};`}}):e}(e,r);return(n=[],l.replace(L,(e,t,r)=>(n.push(r),e)),n.filter(e=>!w(e))).reduce((e,n)=>e.then(e=>H(e,n,t,r)),Promise.resolve(l))}async function D(e,t,r){var n;let l=null==(n=t.style)?void 0:n.getPropertyValue(e);if(l){let n=await V(l,null,r);return t.style.setProperty(e,n,t.style.getPropertyPriority(e)),!0}return!1}async function F(e,t){await D("background",e,t)||await D("background-image",e,t),await D("mask",e,t)||await D("-webkit-mask",e,t)||await D("mask-image",e,t)||await D("-webkit-mask-image",e,t)}async function O(e,t){let r=d(e,HTMLImageElement);if(!(r&&!w(e.src))&&!(d(e,SVGImageElement)&&!w(e.href.baseVal)))return;let n=r?e.src:e.href.baseVal,l=await x(n,y(n),t);await new Promise((n,i)=>{e.onload=n,e.onerror=t.onImageErrorHandler?(...e)=>{try{n(t.onImageErrorHandler(...e))}catch(e){i(e)}}:i,e.decode&&(e.decode=n),"lazy"===e.loading&&(e.loading="eager"),r?(e.srcset="",e.src=l):e.href.baseVal=l})}async function U(e,t){let r=l(e.childNodes).map(e=>q(e,t));await Promise.all(r).then(()=>e)}async function q(e,t){d(e,Element)&&(await F(e,t),await O(e,t),await U(e,t))}let j={};async function B(e){let t=j[e];if(null!=t)return t;let r=await fetch(e);return t={url:e,cssText:await r.text()},j[e]=t,t}async function z(e,t){let r=e.cssText,n=/url\(["']?([^"')]+)["']?\)/g;return Promise.all((r.match(/url\([^)]+\)/g)||[]).map(async l=>{let i=l.replace(n,"$1");return i.startsWith("https://")||(i=new URL(i,e.url).href),S(i,t.fetchRequestInit,({result:e})=>(r=r.replace(l,`url(${e})`),[l,e]))})).then(()=>r)}function W(e){if(null==e)return[];let t=[],r=e.replace(/(\/\*[\s\S]*?\*\/)/gi,""),n=RegExp("((@.*?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})","gi");for(;;){let e=n.exec(r);if(null===e)break;t.push(e[0])}r=r.replace(n,"");let l=/@import[\s\S]*?url\([^)]*\)[\s\S]*?;/gi,i=RegExp("((\\s*?(?:\\/\\*[\\s\\S]*?\\*\\/)?\\s*?@media[\\s\\S]*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})","gi");for(;;){let e=l.exec(r);if(null===e){if(null===(e=i.exec(r)))break;l.lastIndex=i.lastIndex}else i.lastIndex=l.lastIndex;t.push(e[0])}return t}async function _(e,t){let r=[],n=[];return e.forEach(r=>{if("cssRules"in r)try{l(r.cssRules||[]).forEach((e,l)=>{if(e.type===CSSRule.IMPORT_RULE){let i=l+1,a=e.href,o=B(a).then(e=>z(e,t)).then(e=>W(e).forEach(e=>{try{r.insertRule(e,e.startsWith("@import")?i+=1:r.cssRules.length)}catch(t){console.error("Error inserting rule from remote css",{rule:e,error:t})}})).catch(e=>{console.error("Error loading remote css",e.toString())});n.push(o)}})}catch(i){let l=e.find(e=>null==e.href)||document.styleSheets[0];null!=r.href&&n.push(B(r.href).then(e=>z(e,t)).then(e=>W(e).forEach(e=>{l.insertRule(e,l.cssRules.length)})).catch(e=>{console.error("Error loading remote stylesheet",e)})),console.error("Error inlining remote css file",i)}}),Promise.all(n).then(()=>(e.forEach(e=>{if("cssRules"in e)try{l(e.cssRules||[]).forEach(e=>{r.push(e)})}catch(t){console.error(`Error while reading CSS rules from ${e.href}`,t)}}),r))}async function G(e,t){if(null==e.ownerDocument)throw Error("Provided element is not within a Document");let r=l(e.ownerDocument.styleSheets);return(await _(r,t)).filter(e=>e.type===CSSRule.FONT_FACE_RULE).filter(e=>M(e.style.getPropertyValue("src")))}function K(e){return e.trim().replace(/["']/g,"")}async function Q(e,t){let r,n=await G(e,t),l=(r=new Set,!function e(t){(t.style.fontFamily||getComputedStyle(t).fontFamily).split(",").forEach(e=>{r.add(K(e))}),Array.from(t.children).forEach(t=>{t instanceof HTMLElement&&e(t)})}(e),r);return(await Promise.all(n.filter(e=>l.has(K(e.style.fontFamily))).map(e=>{let r=e.parentStyleSheet?e.parentStyleSheet.href:null;return V(e.cssText,r,t)}))).join("\n")}async function X(e,t){let r=null!=t.fontEmbedCSS?t.fontEmbedCSS:t.skipFonts?null:await Q(e,t);if(r){let t=document.createElement("style"),n=document.createTextNode(r);t.appendChild(n),e.firstChild?e.insertBefore(t,e.firstChild):e.appendChild(t)}}async function J(e,t={}){let{width:r,height:n}=c(e,t),l=await N(e,t,!0);return await X(l,t),await q(l,t),!function(e,t){let{style:r}=e;t.backgroundColor&&(r.backgroundColor=t.backgroundColor),t.width&&(r.width=`${t.width}px`),t.height&&(r.height=`${t.height}px`);let n=t.style;null!=n&&Object.keys(n).forEach(e=>{r[e]=n[e]})}(l,t),await h(l,r,n)}async function Y(e,t={}){let{width:n,height:l}=c(e,t),i=await J(e,t),a=await s(i),o=document.createElement("canvas"),u=o.getContext("2d"),h=t.pixelRatio||function(){let e,t;try{t=r.default}catch(e){}let n=t&&t.env?t.env.devicePixelRatio:null;return n&&Number.isNaN(e=parseInt(n,10))&&(e=1),e||window.devicePixelRatio||1}(),d=t.canvasWidth||n,f=t.canvasHeight||l;return o.width=d*h,o.height=f*h,!t.skipAutoScale&&(o.width>16384||o.height>16384)&&(o.width>16384&&o.height>16384?o.width>o.height?(o.height*=16384/o.width,o.width=16384):(o.width*=16384/o.height,o.height=16384):o.width>16384?(o.height*=16384/o.width,o.width=16384):(o.width*=16384/o.height,o.height=16384)),o.style.width=`${d}`,o.style.height=`${f}`,t.backgroundColor&&(u.fillStyle=t.backgroundColor,u.fillRect(0,0,o.width,o.height)),u.drawImage(a,0,0,o.width,o.height),o}async function Z(e,t={}){let r=await Y(e,t);return await function(e,t={}){return new Promise(e.toBlob?r=>{e.toBlob(r,t.type?t.type:"image/png",t.quality?t.quality:1)}:r=>{let n=window.atob(e.toDataURL(t.type?t.type:void 0,t.quality?t.quality:void 0).split(",")[1]),l=n.length,i=new Uint8Array(l);for(let e=0;e<l;e+=1)i[e]=n.charCodeAt(e);r(new Blob([i],{type:t.type?t.type:"image/png"}))})}(r)}e.s(["toBlob",0,Z],66459)}]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,{otherChunks:["static/chunks/0zbxssxh53n-3.js","static/chunks/1__i9af9g78vd.js","static/chunks/03fmihek9n986.js","static/chunks/3w8d8k_dca5rp.js","static/chunks/13f1kmjea-0md.js"],runtimeModuleIds:[94553]}]),(()=>{let e;if(!Array.isArray(globalThis.TURBOPACK))return;let t="/_next/",r=function(){if(null!=self.TURBOPACK_ASSET_SUFFIX)return self.TURBOPACK_ASSET_SUFFIX;let e=document?.currentScript?.getAttribute?.("src")??"",t=e.indexOf("?");return t>=0?e.slice(t):""}(),n=["NEXT_DEPLOYMENT_ID","NEXT_CLIENT_ASSET_SUFFIX"];var o,i=((o=i||{})[o.Runtime=0]="Runtime",o[o.Parent=1]="Parent",o[o.Update=2]="Update",o);let l=new WeakMap;function s(e,t){this.m=e,this.e=t}let u=s.prototype,a=Object.prototype.hasOwnProperty,c="u">typeof Symbol&&Symbol.toStringTag;function f(e,t,r){a.call(e,t)||Object.defineProperty(e,t,r)}function p(e,t){let r=e[t];return r||(r=h(t),e[t]=r),r}function h(e){return{exports:{},error:void 0,id:e,namespaceObject:void 0}}function d(e,t){f(e,"__esModule",{value:!0}),c&&f(e,c,{value:"Module"});let r=0;for(;r<t.length;){let n=t[r++],o=t[r++];if("number"==typeof o)if(0===o)f(e,n,{value:t[r++],enumerable:!0,writable:!1});else throw Error(`unexpected tag: ${o}`);else"function"==typeof t[r]?f(e,n,{get:o,set:t[r++],enumerable:!0}):f(e,n,{get:o,enumerable:!0})}Object.seal(e)}function m(e,t){(null!=t?p(this.c,t):this.m).exports=e}u.s=function(e,t){let r,n;null!=t?n=(r=p(this.c,t)).exports:(r=this.m,n=this.e),r.namespaceObject=n,d(n,e)},u.j=function(e,t){var r,n;let o,i,s;null!=t?i=(o=p(this.c,t)).exports:(o=this.m,i=this.e);let u=(r=o,n=i,(s=l.get(r))||(l.set(r,s=[]),r.exports=r.namespaceObject=new Proxy(n,{get(e,t){if(a.call(e,t)||"default"===t||"__esModule"===t)return Reflect.get(e,t);for(let e of s){let r=Reflect.get(e,t);if(void 0!==r)return r}},ownKeys(e){let t=Reflect.ownKeys(e);for(let e of s)for(let r of Reflect.ownKeys(e))"default"===r||t.includes(r)||t.push(r);return t}})),s);"object"==typeof e&&null!==e&&u.push(e)},u.v=m,u.n=function(e,t){let r;(r=null!=t?p(this.c,t):this.m).exports=r.namespaceObject=e};let b=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,y=[null,b({}),b([]),b(b)];function g(e,t,r){let n=[],o=-1;for(let t=e;("object"==typeof t||"function"==typeof t)&&!y.includes(t);t=b(t))for(let r of Object.getOwnPropertyNames(t))n.push(r,function(e,t){return()=>e[t]}(e,r)),-1===o&&"default"===r&&(o=n.length-1);return r&&o>=0||(o>=0?n.splice(o,1,0,e):n.push("default",0,e)),d(t,n),t}function O(e){let t=B(e,this.m);if(t.namespaceObject)return t.namespaceObject;let r=t.exports;return t.namespaceObject=g(r,"function"==typeof r?function(...e){return r.apply(this,e)}:Object.create(null),r&&r.__esModule)}function w(e){let t=e.indexOf("#");-1!==t&&(e=e.substring(0,t));let r=e.indexOf("?");return -1!==r&&(e=e.substring(0,r)),e}function k(){let e,t;return{promise:new Promise((r,n)=>{t=n,e=r}),resolve:e,reject:t}}u.i=O,u.A=function(e){return this.r(e)(O.bind(this))},u.t="function"==typeof require?require:function(){throw Error("Unexpected use of runtime require")},u.r=function(e){return B(e,this.m).exports},u.f=function(e){function t(t){if(t=w(t),a.call(e,t))return e[t].module();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r}return t.keys=()=>Object.keys(e),t.resolve=t=>{if(t=w(t),a.call(e,t))return e[t].id();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r},t.import=async e=>await t(e),t};let j=Symbol("turbopack queues"),U=Symbol("turbopack exports"),v=Symbol("turbopack error");function C(e){e&&1!==e.status&&(e.status=1,e.forEach(e=>e.queueCount--),e.forEach(e=>e.queueCount--?e.queueCount++:e()))}u.a=function(e,t){let r=this.m,n=t?Object.assign([],{status:-1}):void 0,o=new Set,{resolve:i,reject:l,promise:s}=k(),u=Object.assign(s,{[U]:r.exports,[j]:e=>{n&&e(n),o.forEach(e),u.catch(()=>{})}}),a={get:()=>u,set(e){e!==u&&(u[U]=e)}};Object.defineProperty(r,"exports",a),Object.defineProperty(r,"namespaceObject",a),e(function(e){let t=e.map(e=>{if(null!==e&&"object"==typeof e){if(j in e)return e;if(null!=e&&"object"==typeof e&&"then"in e&&"function"==typeof e.then){let t=Object.assign([],{status:0}),r={[U]:{},[j]:e=>e(t)};return e.then(e=>{r[U]=e,C(t)},e=>{r[v]=e,C(t)}),r}}return{[U]:e,[j]:()=>{}}}),r=()=>t.map(e=>{if(e[v])throw e[v];return e[U]}),{promise:i,resolve:l}=k(),s=Object.assign(()=>l(r),{queueCount:0});function u(e){e!==n&&!o.has(e)&&(o.add(e),e&&0===e.status&&(s.queueCount++,e.push(s)))}return t.map(e=>e[j](u)),s.queueCount?i:r()},function(e){e?l(u[v]=e):i(u[U]),C(n)}),n&&-1===n.status&&(n.status=0)};let P=function(e){let t=new URL(e,"x:/"),r={};for(let e in t)r[e]=t[e];for(let t in r.href=e,r.pathname=e.replace(/[?#].*/,""),r.origin=r.protocol="",r.toString=r.toJSON=(...t)=>e,r)Object.defineProperty(this,t,{enumerable:!0,configurable:!0,value:r[t]})};function R(e,t){throw Error(`Invariant: ${t(e)}`)}P.prototype=URL.prototype,u.U=P,u.z=function(e){throw Error("dynamic usage of require is not supported")},u.g=globalThis;let S=s.prototype,_=new Map;u.M=_;let $=new Map,E=new Map;async function T(e,t,r){let n;if("string"==typeof r)return M(e,t,N(r));let o=r.included||[],i=o.map(e=>!!_.has(e)||$.get(e));if(i.length>0&&i.every(e=>e))return void await Promise.all(i);let l=r.moduleChunks||[],s=l.map(e=>E.get(e)).filter(e=>e);if(s.length>0){if(s.length===l.length)return void await Promise.all(s);let r=new Set;for(let e of l)E.has(e)||r.add(e);for(let n of r){let r=M(e,t,N(n));E.set(n,r),s.push(r)}n=Promise.all(s)}else{for(let o of(n=M(e,t,N(r.path)),l))E.has(o)||E.set(o,n)}for(let e of o)$.has(e)||$.set(e,n);await n}S.l=function(e){return T(i.Parent,this.m.id,e)};let A=Promise.resolve(void 0),x=new WeakMap;function M(t,r,n){let o=e.loadChunkCached(t,n),l=x.get(o);if(void 0===l){let e=x.set.bind(x,o,A);l=o.then(e).catch(e=>{let o;switch(t){case i.Runtime:o=`as a runtime dependency of chunk ${r}`;break;case i.Parent:o=`from module ${r}`;break;case i.Update:o="from an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}let l=Error(`Failed to load chunk ${n} ${o}${e?`: ${e}`:""}`,e?{cause:e}:void 0);throw l.name="ChunkLoadError",l}),x.set(o,l)}return l}function N(e){return`${t}${e.split("/").map(e=>encodeURIComponent(e)).join("/")}${r}`}S.L=function(e){return M(i.Parent,this.m.id,e)},S.R=function(e){let t=this.r(e);return t?.default??t},S.P=function(e){return`/ROOT/${e??""}`},S.q=function(e,t){m.call(this,`${e}${r}`,t)},S.b=function(e,t,o,i){let l="SharedWorker"===e.name,s=[o.map(e=>N(e)).reverse(),r];for(let e of n)s.push(globalThis[e]);let u=new URL(N(t),location.origin),a=JSON.stringify(s);return l?u.searchParams.set("params",a):u.hash="#params="+encodeURIComponent(a),new e(u,i?{...i,type:void 0}:void 0)};let K=/\.js(?:\?[^#]*)?(?:#.*)?$/,q=/\.css(?:\?[^#]*)?(?:#.*)?$/;function L(e){return q.test(e)}u.w=function(t,r,n){return e.loadWebAssembly(i.Parent,this.m.id,t,r,n)},u.u=function(t,r){return e.loadWebAssemblyModule(i.Parent,this.m.id,t,r)};let I={};u.c=I;let B=(e,t)=>{let r=I[e];if(r){if(r.error)throw r.error;return r}return W(e,i.Parent,t.id)};function W(e,t,r){let n=_.get(e);if("function"!=typeof n)throw Error(function(e,t,r){let n;switch(t){case 0:n=`as a runtime entry of chunk ${r}`;break;case 1:n=`because it was required from module ${r}`;break;case 2:n="because of an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}return`Module ${e} was instantiated ${n}, but the module factory is not available.`}(e,t,r));let o=h(e),i=o.exports;I[e]=o;let l=new s(o,i);try{n(l,o,i)}catch(e){throw o.error=e,e}return o.namespaceObject&&o.exports!==o.namespaceObject&&g(o.exports,o.namespaceObject),o}function F(t){let r,n=function(e){if("string"==typeof e)return e;if(e)return{src:e.getAttribute("src")};if("u">typeof TURBOPACK_NEXT_CHUNK_URLS)return{src:TURBOPACK_NEXT_CHUNK_URLS.pop()};throw Error("chunk path empty but not in a worker")}(t[0]);return 2===t.length?r=t[1]:(r=void 0,!function(e,t){let r=1;for(;r<e.length;){let n,o=r+1;for(;o<e.length&&"function"!=typeof e[o];)o++;if(o===e.length)throw Error("malformed chunk format, expected a factory function");let i=e[o];for(let i=r;i<o;i++){let r=e[i],o=t.get(r);if(o){n=o;break}}let l=n??i,s=!1;for(let n=r;n<o;n++){let r=e[n];t.has(r)||(s||(l===i&&Object.defineProperty(i,"name",{value:"module evaluation"}),s=!0),t.set(r,l))}r=o+1}}(t,_)),e.registerChunk(n,r)}let X=new Map;function D(e){let t=X.get(e);if(!t){let r,n;t={resolved:!1,loadingStarted:!1,promise:new Promise((e,t)=>{r=e,n=t}),resolve:()=>{t.resolved=!0,r()},reject:n},X.set(e,t)}return t}e={async registerChunk(e,r){let n=function(e){if("string"==typeof e)return e;let r=decodeURIComponent(e.src.replace(/[?#].*$/,""));return r.startsWith(t)?r.slice(t.length):r}(e);if(D("string"==typeof e?N(e):e.src).resolve(),null!=r){for(let e of r.otherChunks)D(N("string"==typeof e?e:e.path));if(await Promise.all(r.otherChunks.map(e=>T(i.Runtime,n,e))),r.runtimeModuleIds.length>0)for(let e of r.runtimeModuleIds)!function(e,t){let r=I[t];if(r){if(r.error)throw r.error;return}W(t,i.Runtime,e)}(n,e)}},loadChunkCached:(e,t)=>(function(e,t){let r=D(t);if(r.loadingStarted)return r.promise;if(e===i.Runtime)return r.loadingStarted=!0,L(t)&&r.resolve(),r.promise;if("function"==typeof importScripts)if(L(t));else if(K.test(t))self.TURBOPACK_NEXT_CHUNK_URLS.push(t),importScripts(t);else throw Error(`can't infer type of chunk from URL ${t} in worker`);else{let e=decodeURI(t);if(L(t))if(document.querySelectorAll(`link[rel=stylesheet][href="${t}"],link[rel=stylesheet][href^="${t}?"],link[rel=stylesheet][href="${e}"],link[rel=stylesheet][href^="${e}?"]`).length>0)r.resolve();else{let e=document.createElement("link");e.rel="stylesheet",e.href=t,e.onerror=()=>{r.reject()},e.onload=()=>{r.resolve()},document.head.appendChild(e)}else if(K.test(t)){let n=document.querySelectorAll(`script[src="${t}"],script[src^="${t}?"],script[src="${e}"],script[src^="${e}?"]`);if(n.length>0)for(let e of Array.from(n))e.addEventListener("error",()=>{r.reject()});else{let e=document.createElement("script");e.src=t,e.onerror=()=>{r.reject()},document.head.appendChild(e)}}else throw Error(`can't infer type of chunk from URL ${t}`)}return r.loadingStarted=!0,r.promise})(e,t),async loadWebAssembly(e,t,r,n,o){let i=fetch(N(r)),{instance:l}=await WebAssembly.instantiateStreaming(i,o);return l.exports},async loadWebAssemblyModule(e,t,r,n){let o=fetch(N(r));return await WebAssembly.compileStreaming(o)}};let H=globalThis.TURBOPACK;globalThis.TURBOPACK={push:F},H.forEach(F)})();
|
|
1
|
+
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,{otherChunks:["static/chunks/0zbxssxh53n-3.js","static/chunks/1__i9af9g78vd.js","static/chunks/13f1kmjea-0md.js","static/chunks/2h0dkzyy0vocp.js","static/chunks/03fmihek9n986.js"],runtimeModuleIds:[94553]}]),(()=>{let e;if(!Array.isArray(globalThis.TURBOPACK))return;let t="/_next/",r=function(){if(null!=self.TURBOPACK_ASSET_SUFFIX)return self.TURBOPACK_ASSET_SUFFIX;let e=document?.currentScript?.getAttribute?.("src")??"",t=e.indexOf("?");return t>=0?e.slice(t):""}(),n=["NEXT_DEPLOYMENT_ID","NEXT_CLIENT_ASSET_SUFFIX"];var o,i=((o=i||{})[o.Runtime=0]="Runtime",o[o.Parent=1]="Parent",o[o.Update=2]="Update",o);let l=new WeakMap;function s(e,t){this.m=e,this.e=t}let u=s.prototype,a=Object.prototype.hasOwnProperty,c="u">typeof Symbol&&Symbol.toStringTag;function f(e,t,r){a.call(e,t)||Object.defineProperty(e,t,r)}function p(e,t){let r=e[t];return r||(r=h(t),e[t]=r),r}function h(e){return{exports:{},error:void 0,id:e,namespaceObject:void 0}}function d(e,t){f(e,"__esModule",{value:!0}),c&&f(e,c,{value:"Module"});let r=0;for(;r<t.length;){let n=t[r++],o=t[r++];if("number"==typeof o)if(0===o)f(e,n,{value:t[r++],enumerable:!0,writable:!1});else throw Error(`unexpected tag: ${o}`);else"function"==typeof t[r]?f(e,n,{get:o,set:t[r++],enumerable:!0}):f(e,n,{get:o,enumerable:!0})}Object.seal(e)}function m(e,t){(null!=t?p(this.c,t):this.m).exports=e}u.s=function(e,t){let r,n;null!=t?n=(r=p(this.c,t)).exports:(r=this.m,n=this.e),r.namespaceObject=n,d(n,e)},u.j=function(e,t){var r,n;let o,i,s;null!=t?i=(o=p(this.c,t)).exports:(o=this.m,i=this.e);let u=(r=o,n=i,(s=l.get(r))||(l.set(r,s=[]),r.exports=r.namespaceObject=new Proxy(n,{get(e,t){if(a.call(e,t)||"default"===t||"__esModule"===t)return Reflect.get(e,t);for(let e of s){let r=Reflect.get(e,t);if(void 0!==r)return r}},ownKeys(e){let t=Reflect.ownKeys(e);for(let e of s)for(let r of Reflect.ownKeys(e))"default"===r||t.includes(r)||t.push(r);return t}})),s);"object"==typeof e&&null!==e&&u.push(e)},u.v=m,u.n=function(e,t){let r;(r=null!=t?p(this.c,t):this.m).exports=r.namespaceObject=e};let b=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,y=[null,b({}),b([]),b(b)];function g(e,t,r){let n=[],o=-1;for(let t=e;("object"==typeof t||"function"==typeof t)&&!y.includes(t);t=b(t))for(let r of Object.getOwnPropertyNames(t))n.push(r,function(e,t){return()=>e[t]}(e,r)),-1===o&&"default"===r&&(o=n.length-1);return r&&o>=0||(o>=0?n.splice(o,1,0,e):n.push("default",0,e)),d(t,n),t}function O(e){let t=B(e,this.m);if(t.namespaceObject)return t.namespaceObject;let r=t.exports;return t.namespaceObject=g(r,"function"==typeof r?function(...e){return r.apply(this,e)}:Object.create(null),r&&r.__esModule)}function w(e){let t=e.indexOf("#");-1!==t&&(e=e.substring(0,t));let r=e.indexOf("?");return -1!==r&&(e=e.substring(0,r)),e}function k(){let e,t;return{promise:new Promise((r,n)=>{t=n,e=r}),resolve:e,reject:t}}u.i=O,u.A=function(e){return this.r(e)(O.bind(this))},u.t="function"==typeof require?require:function(){throw Error("Unexpected use of runtime require")},u.r=function(e){return B(e,this.m).exports},u.f=function(e){function t(t){if(t=w(t),a.call(e,t))return e[t].module();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r}return t.keys=()=>Object.keys(e),t.resolve=t=>{if(t=w(t),a.call(e,t))return e[t].id();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r},t.import=async e=>await t(e),t};let j=Symbol("turbopack queues"),v=Symbol("turbopack exports"),U=Symbol("turbopack error");function C(e){e&&1!==e.status&&(e.status=1,e.forEach(e=>e.queueCount--),e.forEach(e=>e.queueCount--?e.queueCount++:e()))}u.a=function(e,t){let r=this.m,n=t?Object.assign([],{status:-1}):void 0,o=new Set,{resolve:i,reject:l,promise:s}=k(),u=Object.assign(s,{[v]:r.exports,[j]:e=>{n&&e(n),o.forEach(e),u.catch(()=>{})}}),a={get:()=>u,set(e){e!==u&&(u[v]=e)}};Object.defineProperty(r,"exports",a),Object.defineProperty(r,"namespaceObject",a),e(function(e){let t=e.map(e=>{if(null!==e&&"object"==typeof e){if(j in e)return e;if(null!=e&&"object"==typeof e&&"then"in e&&"function"==typeof e.then){let t=Object.assign([],{status:0}),r={[v]:{},[j]:e=>e(t)};return e.then(e=>{r[v]=e,C(t)},e=>{r[U]=e,C(t)}),r}}return{[v]:e,[j]:()=>{}}}),r=()=>t.map(e=>{if(e[U])throw e[U];return e[v]}),{promise:i,resolve:l}=k(),s=Object.assign(()=>l(r),{queueCount:0});function u(e){e!==n&&!o.has(e)&&(o.add(e),e&&0===e.status&&(s.queueCount++,e.push(s)))}return t.map(e=>e[j](u)),s.queueCount?i:r()},function(e){e?l(u[U]=e):i(u[v]),C(n)}),n&&-1===n.status&&(n.status=0)};let P=function(e){let t=new URL(e,"x:/"),r={};for(let e in t)r[e]=t[e];for(let t in r.href=e,r.pathname=e.replace(/[?#].*/,""),r.origin=r.protocol="",r.toString=r.toJSON=(...t)=>e,r)Object.defineProperty(this,t,{enumerable:!0,configurable:!0,value:r[t]})};function R(e,t){throw Error(`Invariant: ${t(e)}`)}P.prototype=URL.prototype,u.U=P,u.z=function(e){throw Error("dynamic usage of require is not supported")},u.g=globalThis;let S=s.prototype,$=new Map;u.M=$;let _=new Map,E=new Map;async function T(e,t,r){let n;if("string"==typeof r)return M(e,t,N(r));let o=r.included||[],i=o.map(e=>!!$.has(e)||_.get(e));if(i.length>0&&i.every(e=>e))return void await Promise.all(i);let l=r.moduleChunks||[],s=l.map(e=>E.get(e)).filter(e=>e);if(s.length>0){if(s.length===l.length)return void await Promise.all(s);let r=new Set;for(let e of l)E.has(e)||r.add(e);for(let n of r){let r=M(e,t,N(n));E.set(n,r),s.push(r)}n=Promise.all(s)}else{for(let o of(n=M(e,t,N(r.path)),l))E.has(o)||E.set(o,n)}for(let e of o)_.has(e)||_.set(e,n);await n}S.l=function(e){return T(i.Parent,this.m.id,e)};let A=Promise.resolve(void 0),x=new WeakMap;function M(t,r,n){let o=e.loadChunkCached(t,n),l=x.get(o);if(void 0===l){let e=x.set.bind(x,o,A);l=o.then(e).catch(e=>{let o;switch(t){case i.Runtime:o=`as a runtime dependency of chunk ${r}`;break;case i.Parent:o=`from module ${r}`;break;case i.Update:o="from an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}let l=Error(`Failed to load chunk ${n} ${o}${e?`: ${e}`:""}`,e?{cause:e}:void 0);throw l.name="ChunkLoadError",l}),x.set(o,l)}return l}function N(e){return`${t}${e.split("/").map(e=>encodeURIComponent(e)).join("/")}${r}`}S.L=function(e){return M(i.Parent,this.m.id,e)},S.R=function(e){let t=this.r(e);return t?.default??t},S.P=function(e){return`/ROOT/${e??""}`},S.q=function(e,t){m.call(this,`${e}${r}`,t)},S.b=function(e,t,o,i){let l="SharedWorker"===e.name,s=[o.map(e=>N(e)).reverse(),r];for(let e of n)s.push(globalThis[e]);let u=new URL(N(t),location.origin),a=JSON.stringify(s);return l?u.searchParams.set("params",a):u.hash="#params="+encodeURIComponent(a),new e(u,i?{...i,type:void 0}:void 0)};let K=/\.js(?:\?[^#]*)?(?:#.*)?$/,q=/\.css(?:\?[^#]*)?(?:#.*)?$/;function L(e){return q.test(e)}u.w=function(t,r,n){return e.loadWebAssembly(i.Parent,this.m.id,t,r,n)},u.u=function(t,r){return e.loadWebAssemblyModule(i.Parent,this.m.id,t,r)};let I={};u.c=I;let B=(e,t)=>{let r=I[e];if(r){if(r.error)throw r.error;return r}return W(e,i.Parent,t.id)};function W(e,t,r){let n=$.get(e);if("function"!=typeof n)throw Error(function(e,t,r){let n;switch(t){case 0:n=`as a runtime entry of chunk ${r}`;break;case 1:n=`because it was required from module ${r}`;break;case 2:n="because of an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}return`Module ${e} was instantiated ${n}, but the module factory is not available.`}(e,t,r));let o=h(e),i=o.exports;I[e]=o;let l=new s(o,i);try{n(l,o,i)}catch(e){throw o.error=e,e}return o.namespaceObject&&o.exports!==o.namespaceObject&&g(o.exports,o.namespaceObject),o}function F(t){let r,n=function(e){if("string"==typeof e)return e;if(e)return{src:e.getAttribute("src")};if("u">typeof TURBOPACK_NEXT_CHUNK_URLS)return{src:TURBOPACK_NEXT_CHUNK_URLS.pop()};throw Error("chunk path empty but not in a worker")}(t[0]);return 2===t.length?r=t[1]:(r=void 0,!function(e,t){let r=1;for(;r<e.length;){let n,o=r+1;for(;o<e.length&&"function"!=typeof e[o];)o++;if(o===e.length)throw Error("malformed chunk format, expected a factory function");let i=e[o];for(let i=r;i<o;i++){let r=e[i],o=t.get(r);if(o){n=o;break}}let l=n??i,s=!1;for(let n=r;n<o;n++){let r=e[n];t.has(r)||(s||(l===i&&Object.defineProperty(i,"name",{value:"module evaluation"}),s=!0),t.set(r,l))}r=o+1}}(t,$)),e.registerChunk(n,r)}let X=new Map;function D(e){let t=X.get(e);if(!t){let r,n;t={resolved:!1,loadingStarted:!1,promise:new Promise((e,t)=>{r=e,n=t}),resolve:()=>{t.resolved=!0,r()},reject:n},X.set(e,t)}return t}e={async registerChunk(e,r){let n=function(e){if("string"==typeof e)return e;let r=decodeURIComponent(e.src.replace(/[?#].*$/,""));return r.startsWith(t)?r.slice(t.length):r}(e);if(D("string"==typeof e?N(e):e.src).resolve(),null!=r){for(let e of r.otherChunks)D(N("string"==typeof e?e:e.path));if(await Promise.all(r.otherChunks.map(e=>T(i.Runtime,n,e))),r.runtimeModuleIds.length>0)for(let e of r.runtimeModuleIds)!function(e,t){let r=I[t];if(r){if(r.error)throw r.error;return}W(t,i.Runtime,e)}(n,e)}},loadChunkCached:(e,t)=>(function(e,t){let r=D(t);if(r.loadingStarted)return r.promise;if(e===i.Runtime)return r.loadingStarted=!0,L(t)&&r.resolve(),r.promise;if("function"==typeof importScripts)if(L(t));else if(K.test(t))self.TURBOPACK_NEXT_CHUNK_URLS.push(t),importScripts(t);else throw Error(`can't infer type of chunk from URL ${t} in worker`);else{let e=decodeURI(t);if(L(t))if(document.querySelectorAll(`link[rel=stylesheet][href="${t}"],link[rel=stylesheet][href^="${t}?"],link[rel=stylesheet][href="${e}"],link[rel=stylesheet][href^="${e}?"]`).length>0)r.resolve();else{let e=document.createElement("link");e.rel="stylesheet",e.href=t,e.onerror=()=>{r.reject()},e.onload=()=>{r.resolve()},document.head.appendChild(e)}else if(K.test(t)){let n=document.querySelectorAll(`script[src="${t}"],script[src^="${t}?"],script[src="${e}"],script[src^="${e}?"]`);if(n.length>0)for(let e of Array.from(n))e.addEventListener("error",()=>{r.reject()});else{let e=document.createElement("script");e.src=t,e.onerror=()=>{r.reject()},document.head.appendChild(e)}}else throw Error(`can't infer type of chunk from URL ${t}`)}return r.loadingStarted=!0,r.promise})(e,t),async loadWebAssembly(e,t,r,n,o){let i=fetch(N(r)),{instance:l}=await WebAssembly.instantiateStreaming(i,o);return l.exports},async loadWebAssemblyModule(e,t,r,n){let o=fetch(N(r));return await WebAssembly.compileStreaming(o)}};let H=globalThis.TURBOPACK;globalThis.TURBOPACK={push:F},H.forEach(F)})();
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/audit/invite
|
|
3
|
+
*
|
|
4
|
+
* Browser-facing proxy for the api-server's POST /v0/invite — the user
|
|
5
|
+
* supplies a list of friend emails, the api-server composes invite emails
|
|
6
|
+
* (Cc'ing the sender so the recipient sees who invited them), and dispatches
|
|
7
|
+
* them through the same email infrastructure that backs the OTP flow.
|
|
8
|
+
*
|
|
9
|
+
* Auth: requires an active session — same cookie/refresh-token contract as
|
|
10
|
+
* /api/auth/reminder. Anonymous calls get 401 so the front-end can route to
|
|
11
|
+
* the AuthDialog before retrying.
|
|
12
|
+
*
|
|
13
|
+
* Validation: max 10 recipients per call, each must look like an email.
|
|
14
|
+
* Anything beyond that gets a 400 and never reaches upstream.
|
|
15
|
+
*
|
|
16
|
+
* Contract for the upstream endpoint is handed over to the platform team
|
|
17
|
+
* separately.
|
|
18
|
+
*/
|
|
19
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
20
|
+
import { whoAmI } from "@/lib/auth/auth-store";
|
|
21
|
+
import { AuthApiError, sendInvites } from "@/lib/auth/api-server-client";
|
|
22
|
+
import { initTelemetry, trackEvent } from "@/lib/telemetry";
|
|
23
|
+
|
|
24
|
+
export const dynamic = "force-dynamic";
|
|
25
|
+
|
|
26
|
+
const MAX_RECIPIENTS = 10;
|
|
27
|
+
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
28
|
+
|
|
29
|
+
interface InviteBody {
|
|
30
|
+
to?: unknown;
|
|
31
|
+
score?: unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function POST(req: NextRequest): Promise<NextResponse> {
|
|
35
|
+
await initTelemetry();
|
|
36
|
+
const who = await whoAmI();
|
|
37
|
+
if (!who) {
|
|
38
|
+
trackEvent("audit_invite_sent", { status: "unauthorized", source: "dashboard" });
|
|
39
|
+
return NextResponse.json(
|
|
40
|
+
{ code: "unauthorized", message: "Sign in before sending invites." },
|
|
41
|
+
{ status: 401 },
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let body: InviteBody = {};
|
|
46
|
+
const raw = await req.text();
|
|
47
|
+
if (raw.trim().length > 0) {
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(raw);
|
|
50
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
51
|
+
trackEvent("audit_invite_sent", {
|
|
52
|
+
status: "validation_error",
|
|
53
|
+
source: "dashboard",
|
|
54
|
+
reason: "not_an_object",
|
|
55
|
+
user_id: who.me.id,
|
|
56
|
+
});
|
|
57
|
+
return NextResponse.json(
|
|
58
|
+
{ code: "validation_error", message: "Request body must be a JSON object." },
|
|
59
|
+
{ status: 400 },
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
body = parsed as InviteBody;
|
|
63
|
+
} catch {
|
|
64
|
+
trackEvent("audit_invite_sent", {
|
|
65
|
+
status: "validation_error",
|
|
66
|
+
source: "dashboard",
|
|
67
|
+
reason: "malformed_json",
|
|
68
|
+
user_id: who.me.id,
|
|
69
|
+
});
|
|
70
|
+
return NextResponse.json(
|
|
71
|
+
{ code: "validation_error", message: "Request body is not valid JSON." },
|
|
72
|
+
{ status: 400 },
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!Array.isArray(body.to)) {
|
|
78
|
+
trackEvent("audit_invite_sent", {
|
|
79
|
+
status: "validation_error",
|
|
80
|
+
source: "dashboard",
|
|
81
|
+
reason: "missing_to",
|
|
82
|
+
user_id: who.me.id,
|
|
83
|
+
});
|
|
84
|
+
return NextResponse.json(
|
|
85
|
+
{ code: "validation_error", message: "`to` must be a list of email addresses." },
|
|
86
|
+
{ status: 400 },
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const normalised: string[] = [];
|
|
91
|
+
const seen = new Set<string>();
|
|
92
|
+
for (const entry of body.to) {
|
|
93
|
+
if (typeof entry !== "string") continue;
|
|
94
|
+
const e = entry.trim().toLowerCase();
|
|
95
|
+
if (!e || !EMAIL_RE.test(e)) continue;
|
|
96
|
+
if (e === who.me.email.toLowerCase()) continue; // can't invite yourself
|
|
97
|
+
if (seen.has(e)) continue;
|
|
98
|
+
seen.add(e);
|
|
99
|
+
normalised.push(e);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (normalised.length === 0) {
|
|
103
|
+
trackEvent("audit_invite_sent", {
|
|
104
|
+
status: "validation_error",
|
|
105
|
+
source: "dashboard",
|
|
106
|
+
reason: "no_valid_recipients",
|
|
107
|
+
user_id: who.me.id,
|
|
108
|
+
input_count: Array.isArray(body.to) ? body.to.length : 0,
|
|
109
|
+
});
|
|
110
|
+
return NextResponse.json(
|
|
111
|
+
{
|
|
112
|
+
code: "validation_error",
|
|
113
|
+
message: "Provide at least one valid email address (other than your own).",
|
|
114
|
+
},
|
|
115
|
+
{ status: 400 },
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (normalised.length > MAX_RECIPIENTS) {
|
|
120
|
+
trackEvent("audit_invite_sent", {
|
|
121
|
+
status: "validation_error",
|
|
122
|
+
source: "dashboard",
|
|
123
|
+
reason: "too_many_recipients",
|
|
124
|
+
user_id: who.me.id,
|
|
125
|
+
input_count: normalised.length,
|
|
126
|
+
});
|
|
127
|
+
return NextResponse.json(
|
|
128
|
+
{
|
|
129
|
+
code: "validation_error",
|
|
130
|
+
message: `Up to ${MAX_RECIPIENTS} recipients per invite batch. Please send the rest in a follow-up.`,
|
|
131
|
+
},
|
|
132
|
+
{ status: 400 },
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Optional sender audit score (0–100), surfaced in the invite body. Coerce
|
|
137
|
+
// defensively — the value is client-supplied: ignore non-finite garbage,
|
|
138
|
+
// round, then clamp into range before forwarding upstream.
|
|
139
|
+
let score: number | undefined;
|
|
140
|
+
if (typeof body.score === "number" && Number.isFinite(body.score)) {
|
|
141
|
+
score = Math.max(0, Math.min(100, Math.round(body.score)));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
const result = await sendInvites(who.auth.access_token, normalised, score);
|
|
146
|
+
trackEvent("audit_invite_sent", {
|
|
147
|
+
status: "success",
|
|
148
|
+
source: "dashboard",
|
|
149
|
+
user_id: who.me.id,
|
|
150
|
+
sent_count: result.sent.length,
|
|
151
|
+
failed_count: result.failed.length,
|
|
152
|
+
});
|
|
153
|
+
return NextResponse.json(result, { status: 200 });
|
|
154
|
+
} catch (err) {
|
|
155
|
+
if (err instanceof AuthApiError) {
|
|
156
|
+
trackEvent("audit_invite_sent", {
|
|
157
|
+
status: "failed",
|
|
158
|
+
source: "dashboard",
|
|
159
|
+
user_id: who.me.id,
|
|
160
|
+
error_code: err.code,
|
|
161
|
+
http_status: err.status,
|
|
162
|
+
recipient_count: normalised.length,
|
|
163
|
+
});
|
|
164
|
+
const httpStatus = err.status >= 200 && err.status < 600 ? err.status : 504;
|
|
165
|
+
return NextResponse.json(
|
|
166
|
+
{
|
|
167
|
+
code: err.code,
|
|
168
|
+
message: err.message,
|
|
169
|
+
...(err.retryAfterSecs !== undefined ? { retry_after_secs: err.retryAfterSecs } : {}),
|
|
170
|
+
},
|
|
171
|
+
{ status: httpStatus },
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
// Don't surface the raw upstream message to either telemetry or the
|
|
175
|
+
// client. Network/DNS errors can carry internal hostnames, IPs, or
|
|
176
|
+
// fragment payload bytes that have no business leaving the proxy.
|
|
177
|
+
// Log the error name only (bounded) and return a stable generic.
|
|
178
|
+
const errorName = err instanceof Error ? err.name : "unknown";
|
|
179
|
+
trackEvent("audit_invite_sent", {
|
|
180
|
+
status: "failed",
|
|
181
|
+
source: "dashboard",
|
|
182
|
+
user_id: who.me.id,
|
|
183
|
+
error_code: "upstream_unreachable",
|
|
184
|
+
error_name: errorName.slice(0, 50),
|
|
185
|
+
recipient_count: normalised.length,
|
|
186
|
+
});
|
|
187
|
+
return NextResponse.json(
|
|
188
|
+
{ code: "upstream_unreachable", message: "Invite service is unreachable. Please try again in a moment." },
|
|
189
|
+
{ status: 502 },
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -17,6 +17,7 @@ import { writeDashboardCache } from "@/src/audit/dashboard-cache";
|
|
|
17
17
|
import { INTEGRATION_TYPES, type IntegrationType } from "@/src/hooks/types";
|
|
18
18
|
import type { RunAuditOptions } from "@/src/audit/types";
|
|
19
19
|
import { finishRun, tryAcquireRun } from "../_state";
|
|
20
|
+
import { initTelemetry, trackEvent } from "@/lib/telemetry";
|
|
20
21
|
|
|
21
22
|
export const dynamic = "force-dynamic";
|
|
22
23
|
|
|
@@ -52,6 +53,11 @@ function sanitize(body: RunBody): RunAuditOptions {
|
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
56
|
+
// initTelemetry never throws; init up front so every exit path (incl. the
|
|
57
|
+
// 400/409 rejections and the detached run task below) can report. The
|
|
58
|
+
// dashboard is a long-lived process, so trackEvent's background flush
|
|
59
|
+
// delivers even after this handler returns 202.
|
|
60
|
+
await initTelemetry();
|
|
55
61
|
let body: RunBody = {};
|
|
56
62
|
try {
|
|
57
63
|
const raw = await request.text();
|
|
@@ -60,6 +66,7 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
|
60
66
|
// JSON.parse("null") returns null and JSON.parse("[]") returns an
|
|
61
67
|
// array — both pass the catch but break sanitize()'s field access.
|
|
62
68
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
69
|
+
trackEvent("audit_run_rejected", { source: "dashboard", reason: "non_object_body" });
|
|
63
70
|
return NextResponse.json(
|
|
64
71
|
{ error: "Request body must be a JSON object" },
|
|
65
72
|
{ status: 400 },
|
|
@@ -68,18 +75,31 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
|
68
75
|
body = parsed as RunBody;
|
|
69
76
|
}
|
|
70
77
|
} catch {
|
|
78
|
+
trackEvent("audit_run_rejected", { source: "dashboard", reason: "invalid_json" });
|
|
71
79
|
return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
const opts = sanitize(body);
|
|
75
83
|
|
|
76
84
|
if (!tryAcquireRun()) {
|
|
85
|
+
trackEvent("audit_run_rejected", { source: "dashboard", reason: "already_running" });
|
|
77
86
|
return NextResponse.json(
|
|
78
87
|
{ error: "Audit already running", status: "already-running" },
|
|
79
88
|
{ status: 409 },
|
|
80
89
|
);
|
|
81
90
|
}
|
|
82
91
|
|
|
92
|
+
// Mirror the CLI's cli_audit_* funnel for the dashboard path (which shares the
|
|
93
|
+
// same runAudit() core but previously emitted no server telemetry at all).
|
|
94
|
+
trackEvent("audit_run_started", {
|
|
95
|
+
source: "dashboard",
|
|
96
|
+
since: opts.since ?? null,
|
|
97
|
+
no_cache: opts.noCache === true,
|
|
98
|
+
cli_count: opts.clis?.length ?? 0,
|
|
99
|
+
project_count: opts.projects?.length ?? 0,
|
|
100
|
+
});
|
|
101
|
+
const startedAt = Date.now();
|
|
102
|
+
|
|
83
103
|
// Fire-and-forget: a cold, all-history scan can run far longer than any HTTP
|
|
84
104
|
// request should stay open — and longer than Node's `server.requestTimeout`
|
|
85
105
|
// on the standalone production server. Start runAudit() as a detached task in
|
|
@@ -93,8 +113,23 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
|
93
113
|
// the client (the POST already returned 202), so a failed persist is a
|
|
94
114
|
// failed run from the user's view — surface it instead of reporting OK.
|
|
95
115
|
const persisted = writeDashboardCache(opts, result);
|
|
116
|
+
trackEvent("audit_run_completed", {
|
|
117
|
+
source: "dashboard",
|
|
118
|
+
duration_ms: Date.now() - startedAt,
|
|
119
|
+
events_scanned: result.eventsScanned,
|
|
120
|
+
sessions_scanned: result.transcripts.scanned,
|
|
121
|
+
projects_scanned: result.projectsScanned.length,
|
|
122
|
+
findings: result.results.length,
|
|
123
|
+
total_hits: result.totals.hits,
|
|
124
|
+
persisted,
|
|
125
|
+
});
|
|
96
126
|
finishRun(persisted ? null : "audit finished but its result could not be saved");
|
|
97
127
|
} catch (err) {
|
|
128
|
+
trackEvent("audit_run_failed", {
|
|
129
|
+
source: "dashboard",
|
|
130
|
+
duration_ms: Date.now() - startedAt,
|
|
131
|
+
error_type: err instanceof Error ? err.name : "unknown",
|
|
132
|
+
});
|
|
98
133
|
finishRun(err instanceof Error ? err.message : String(err));
|
|
99
134
|
}
|
|
100
135
|
})();
|
|
@@ -21,11 +21,11 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
|
|
21
21
|
try {
|
|
22
22
|
body = (await req.json()) as RequestBody;
|
|
23
23
|
} catch {
|
|
24
|
-
trackEvent("audit_otp_requested", { status: "validation_error", reason: "invalid_json" });
|
|
24
|
+
trackEvent("audit_otp_requested", { status: "validation_error", source: "dashboard", reason: "invalid_json" });
|
|
25
25
|
return NextResponse.json({ code: "validation_error", message: "Invalid JSON body" }, { status: 400 });
|
|
26
26
|
}
|
|
27
27
|
if (typeof body.email !== "string" || !body.email.trim()) {
|
|
28
|
-
trackEvent("audit_otp_requested", { status: "validation_error", reason: "missing_email" });
|
|
28
|
+
trackEvent("audit_otp_requested", { status: "validation_error", source: "dashboard", reason: "missing_email" });
|
|
29
29
|
return NextResponse.json(
|
|
30
30
|
{ code: "validation_error", message: "email is required" },
|
|
31
31
|
{ status: 400 },
|
|
@@ -20,26 +20,32 @@ interface VerifyBody {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export async function POST(req: NextRequest): Promise<NextResponse> {
|
|
23
|
+
// `initTelemetry` never throws — its internal try/catch is total. Init up
|
|
24
|
+
// front so the validation-400 paths below are tracked too, mirroring
|
|
25
|
+
// /api/auth/login-request.
|
|
26
|
+
await initTelemetry();
|
|
23
27
|
let body: VerifyBody = {};
|
|
24
28
|
try {
|
|
25
29
|
body = (await req.json()) as VerifyBody;
|
|
26
30
|
} catch {
|
|
31
|
+
trackEvent("audit_otp_verified", { status: "validation_error", source: "dashboard", reason: "invalid_json" });
|
|
27
32
|
return NextResponse.json({ code: "validation_error", message: "Invalid JSON body" }, { status: 400 });
|
|
28
33
|
}
|
|
29
34
|
if (typeof body.email !== "string" || !body.email.trim()) {
|
|
35
|
+
trackEvent("audit_otp_verified", { status: "validation_error", source: "dashboard", reason: "missing_email" });
|
|
30
36
|
return NextResponse.json(
|
|
31
37
|
{ code: "validation_error", message: "email is required" },
|
|
32
38
|
{ status: 400 },
|
|
33
39
|
);
|
|
34
40
|
}
|
|
35
41
|
if (typeof body.code !== "string" || !body.code.trim()) {
|
|
42
|
+
trackEvent("audit_otp_verified", { status: "validation_error", source: "dashboard", reason: "missing_code", email: body.email.trim().toLowerCase() });
|
|
36
43
|
return NextResponse.json(
|
|
37
44
|
{ code: "validation_error", message: "code is required" },
|
|
38
45
|
{ status: 400 },
|
|
39
46
|
);
|
|
40
47
|
}
|
|
41
|
-
|
|
42
|
-
await initTelemetry();
|
|
48
|
+
const email = body.email.trim().toLowerCase();
|
|
43
49
|
try {
|
|
44
50
|
const tokens = await verifyLoginCode(body.email, body.code);
|
|
45
51
|
writeAuth(authFromTokenResponse(tokens));
|
|
@@ -72,6 +78,7 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
|
|
72
78
|
trackEvent("audit_otp_verified", {
|
|
73
79
|
status: "failed",
|
|
74
80
|
source: "dashboard",
|
|
81
|
+
email,
|
|
75
82
|
error_code: err.code,
|
|
76
83
|
http_status: err.status,
|
|
77
84
|
});
|
|
@@ -87,6 +94,7 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
|
|
87
94
|
trackEvent("audit_otp_verified", {
|
|
88
95
|
status: "failed",
|
|
89
96
|
source: "dashboard",
|
|
97
|
+
email,
|
|
90
98
|
error_code: "upstream_unreachable",
|
|
91
99
|
error_message: message.slice(0, 200),
|
|
92
100
|
});
|
|
@@ -3,30 +3,31 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Top-level client wrapper for /audit.
|
|
5
5
|
*
|
|
6
|
-
* Composes the personality report: classify the agent into one of
|
|
7
|
-
* archetypes, derive a score
|
|
8
|
-
* ShowOff + Strengths + Score (with leaderboard) + Findings + Policies
|
|
9
|
-
* + Return-loop CTA.
|
|
6
|
+
* Composes the calm personality report: classify the agent into one of
|
|
7
|
+
* 8 archetypes, derive a score, and render the 5-section flow:
|
|
10
8
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* 01 AuditPoster — single-screen shareable poster
|
|
10
|
+
* 02 StrengthsSection — what it's great at
|
|
11
|
+
* 03 QuirksSection — what slipped through
|
|
12
|
+
* 04 HowToImproveSection — install / configure
|
|
13
|
+
* 05 ComeBackBetterSection — reminder + perks
|
|
14
|
+
*
|
|
15
|
+
* Empty / running states fall back to EmptyState and RunProgress.
|
|
13
16
|
*/
|
|
14
17
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
15
18
|
import { getAuditResultAction } from "@/app/actions/get-audit-result";
|
|
16
19
|
import type { AuditResult, RunAuditOptions } from "@/src/audit/types";
|
|
17
20
|
import { classifyAgent } from "@/src/audit/archetypes";
|
|
18
|
-
import {
|
|
21
|
+
import { deriveScore, gradeFor, projectedScore } from "@/src/audit/scoring";
|
|
19
22
|
import { deriveStrengths } from "@/src/audit/strengths";
|
|
20
23
|
import { deriveFindings } from "@/src/audit/findings";
|
|
21
24
|
import { usePostHog } from "@/contexts/PostHogContext";
|
|
22
25
|
|
|
23
|
-
import {
|
|
24
|
-
import { ShareDock } from "./share-dock";
|
|
26
|
+
import { AuditPoster } from "./audit-poster";
|
|
25
27
|
import { StrengthsSection } from "./strengths-section";
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import { ReturnSection } from "./return-section";
|
|
28
|
+
import { QuirksSection } from "./quirks-section";
|
|
29
|
+
import { HowToImproveSection } from "./how-to-improve-section";
|
|
30
|
+
import { ComeBackBetterSection } from "./come-back-better-section";
|
|
30
31
|
import { ReportFooter } from "./report-footer";
|
|
31
32
|
import { EmptyState } from "./empty-state";
|
|
32
33
|
import { RunProgress } from "./run-progress";
|
|
@@ -58,11 +59,6 @@ interface Props {
|
|
|
58
59
|
totalCatalogSize: number;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
function inferWindow(params: RunAuditOptions | undefined): string {
|
|
62
|
-
if (!params?.since) return "all time";
|
|
63
|
-
return params.since;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
62
|
function inferProjectName(result: AuditResult, override?: string): string {
|
|
67
63
|
if (override && override.trim()) return override;
|
|
68
64
|
// Pick the cwd that appears in the most examples — proxy for "your
|
|
@@ -108,7 +104,8 @@ export function AuditDashboard({ initial, projectFromUrl, totalCatalogSize }: Pr
|
|
|
108
104
|
if (running) return;
|
|
109
105
|
capture("audit_rerun_clicked", { source, since: "all" });
|
|
110
106
|
setRunning(true);
|
|
111
|
-
|
|
107
|
+
const startedAt = Date.now();
|
|
108
|
+
setRerunStatus({ kind: "running", startedAt });
|
|
112
109
|
try {
|
|
113
110
|
// noCache: an explicit re-audit bypasses the per-transcript cache and
|
|
114
111
|
// re-scans from scratch — never a silent no-op that returns the identical
|
|
@@ -118,6 +115,11 @@ export function AuditDashboard({ initial, projectFromUrl, totalCatalogSize }: Pr
|
|
|
118
115
|
// fast cached path — it's a first scan, not a re-audit.
|
|
119
116
|
await triggerRun({ cli: [], since: "all", noCache: true });
|
|
120
117
|
await refreshFromCache();
|
|
118
|
+
capture("audit_rerun_succeeded", {
|
|
119
|
+
source,
|
|
120
|
+
since: "all",
|
|
121
|
+
duration_ms: Date.now() - startedAt,
|
|
122
|
+
});
|
|
121
123
|
setRerunStatus({ kind: "idle" });
|
|
122
124
|
} catch (err) {
|
|
123
125
|
const kind = err instanceof RerunError ? err.kind : "network";
|
|
@@ -126,6 +128,7 @@ export function AuditDashboard({ initial, projectFromUrl, totalCatalogSize }: Pr
|
|
|
126
128
|
source,
|
|
127
129
|
since: "all",
|
|
128
130
|
cli_filter: "all",
|
|
131
|
+
duration_ms: Date.now() - startedAt,
|
|
129
132
|
});
|
|
130
133
|
setRerunStatus({ kind: "failed", reason: kind, failedAt: Date.now() });
|
|
131
134
|
} finally {
|
|
@@ -249,9 +252,7 @@ export function AuditDashboard({ initial, projectFromUrl, totalCatalogSize }: Pr
|
|
|
249
252
|
<MainReport
|
|
250
253
|
result={result}
|
|
251
254
|
cachedAt={cachedAt}
|
|
252
|
-
params={params}
|
|
253
255
|
projectFromUrl={projectFromUrl}
|
|
254
|
-
totalCatalogSize={totalCatalogSize}
|
|
255
256
|
isRunning={running}
|
|
256
257
|
rerunStatus={rerunStatus}
|
|
257
258
|
onRerun={(source) => startRerun(source)}
|
|
@@ -263,9 +264,7 @@ export function AuditDashboard({ initial, projectFromUrl, totalCatalogSize }: Pr
|
|
|
263
264
|
interface MainReportProps {
|
|
264
265
|
result: AuditResult;
|
|
265
266
|
cachedAt: string | null;
|
|
266
|
-
params: RunAuditOptions | undefined;
|
|
267
267
|
projectFromUrl?: string;
|
|
268
|
-
totalCatalogSize: number;
|
|
269
268
|
isRunning: boolean;
|
|
270
269
|
rerunStatus: RerunStatus;
|
|
271
270
|
onRerun: (source: RerunSource) => void;
|
|
@@ -275,9 +274,7 @@ interface MainReportProps {
|
|
|
275
274
|
function MainReport({
|
|
276
275
|
result,
|
|
277
276
|
cachedAt,
|
|
278
|
-
params,
|
|
279
277
|
projectFromUrl,
|
|
280
|
-
totalCatalogSize,
|
|
281
278
|
isRunning,
|
|
282
279
|
rerunStatus,
|
|
283
280
|
onRerun,
|
|
@@ -294,14 +291,10 @@ function MainReport({
|
|
|
294
291
|
const projectedGrade = gradeFor(projected);
|
|
295
292
|
const strengths = useMemo(() => deriveStrengths(result), [result]);
|
|
296
293
|
const findings = useMemo(() => deriveFindings(result), [result]);
|
|
297
|
-
// Renamed from `window` to avoid shadowing the browser global — any
|
|
298
|
-
// future `window.*` reference added inside MainReport would silently
|
|
299
|
-
// bind to a string and crash at runtime.
|
|
300
|
-
const scopeWindow = inferWindow(params);
|
|
301
294
|
|
|
302
|
-
// One pass over result.results
|
|
303
|
-
//
|
|
304
|
-
//
|
|
295
|
+
// One pass over result.results: detectors triggered + missing prescribed
|
|
296
|
+
// policies. Both feed PostHog instrumentation; `missing` also feeds the
|
|
297
|
+
// poster's share-text template.
|
|
305
298
|
const { detectorsTriggered, missing } = useMemo(() => {
|
|
306
299
|
let detectorsTriggered = 0;
|
|
307
300
|
let missing = 0;
|
|
@@ -340,54 +333,38 @@ function MainReport({
|
|
|
340
333
|
detectorsTriggered,
|
|
341
334
|
]);
|
|
342
335
|
|
|
343
|
-
/**
|
|
344
|
-
const
|
|
336
|
+
/** Poster ref — captured to PNG by the poster's share buttons. */
|
|
337
|
+
const posterRef = useRef<HTMLDivElement>(null);
|
|
345
338
|
|
|
346
339
|
return (
|
|
347
340
|
<div className="app">
|
|
348
341
|
<AuditProgressStrip status={rerunStatus} onDismiss={onDismissRerun} />
|
|
349
|
-
<div className="scanline-overlay" />
|
|
350
342
|
<div className="app-shell">
|
|
351
343
|
<div className="report">
|
|
352
|
-
<
|
|
353
|
-
ref={
|
|
344
|
+
<AuditPoster
|
|
345
|
+
ref={posterRef}
|
|
354
346
|
archetypeKey={classification.archetype}
|
|
355
|
-
secondaryKey={classification.secondary}
|
|
356
|
-
toolCalls={result.eventsScanned ?? 0}
|
|
357
|
-
sessions={result.transcripts.scanned}
|
|
358
|
-
window={scopeWindow}
|
|
359
347
|
seed={classification.variantSeed}
|
|
360
|
-
/>
|
|
361
|
-
<StrengthsSection
|
|
362
|
-
strengths={strengths}
|
|
363
|
-
totalDetectorsTriggered={detectorsTriggered}
|
|
364
|
-
totalDetectorsAvailable={totalCatalogSize}
|
|
365
|
-
/>
|
|
366
|
-
<ScoreSection
|
|
367
|
-
result={result}
|
|
368
348
|
score={score}
|
|
369
349
|
grade={grade}
|
|
370
|
-
|
|
371
|
-
|
|
350
|
+
missing={missing}
|
|
351
|
+
auditedAt={cachedAt ?? new Date().toISOString()}
|
|
372
352
|
/>
|
|
373
|
-
<
|
|
353
|
+
<StrengthsSection strengths={strengths} />
|
|
354
|
+
<QuirksSection findings={findings} />
|
|
355
|
+
<HowToImproveSection
|
|
374
356
|
result={result}
|
|
357
|
+
projected={projected}
|
|
358
|
+
projectedGrade={projectedGrade}
|
|
359
|
+
/>
|
|
360
|
+
<ComeBackBetterSection
|
|
375
361
|
isRunning={isRunning}
|
|
376
362
|
onRerun={() => onRerun("return_section")}
|
|
363
|
+
score={score}
|
|
377
364
|
/>
|
|
378
|
-
<FindingsSection findings={findings} />
|
|
379
|
-
<PoliciesSection result={result} projected={projected} projectedGrade={projectedGrade} />
|
|
380
365
|
</div>
|
|
381
366
|
<ReportFooter cachedAt={cachedAt} />
|
|
382
367
|
</div>
|
|
383
|
-
<ShareDock
|
|
384
|
-
frameRef={identityFrameRef}
|
|
385
|
-
archetypeKey={classification.archetype}
|
|
386
|
-
seed={classification.variantSeed}
|
|
387
|
-
score={score}
|
|
388
|
-
grade={grade}
|
|
389
|
-
missing={missing}
|
|
390
|
-
/>
|
|
391
368
|
</div>
|
|
392
369
|
);
|
|
393
370
|
}
|
|
@@ -408,7 +385,6 @@ function ShellEmpty({ running, mode = "no-cache", rerunStatus, onDismissRerun, o
|
|
|
408
385
|
return (
|
|
409
386
|
<div className="app">
|
|
410
387
|
<AuditProgressStrip status={rerunStatus} onDismiss={onDismissRerun} />
|
|
411
|
-
<div className="scanline-overlay" />
|
|
412
388
|
<div className="app-shell">
|
|
413
389
|
<div className="report">
|
|
414
390
|
{running ? (
|