@01.works/visual-review 0.9.2 → 0.9.3
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/README.md +29 -2
- package/dist/{bootstrap-error-X9PqxFnS.js → bootstrap-error-BwIf8fUE.js} +1 -0
- package/dist/{hosted-runtime-D1xY3Jtw.js → hosted-runtime-BpX-xGps.js} +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.js +1 -1
- package/dist/install-Ca3QT7YV.js +3 -0
- package/dist/react.js +1 -1
- package/package.json +1 -1
- package/dist/install-RHVUfLTU.js +0 -1
package/README.md
CHANGED
|
@@ -139,7 +139,32 @@ build adapter는 Vite mode와 알려진 hosting provider context로 provenance m
|
|
|
139
139
|
|
|
140
140
|
별도 enable 환경변수는 필요하지 않습니다. Launcher는 invitation fragment 또는 검증된
|
|
141
141
|
resume marker가 없으면 DOM, history listener, auth, network와 runtime import 전에
|
|
142
|
-
종료합니다.
|
|
142
|
+
종료합니다. development build에서는 설치 성공과 비활성 상태를 구분할 수 있도록 현재
|
|
143
|
+
Origin과 초대 링크로 다시 열라는 안내를 console에 한 번만 남깁니다. production의 일반
|
|
144
|
+
방문자에게는 이 안내나 UI를 노출하지 않습니다. 실제 활성화는 project의 exact origin
|
|
145
|
+
연결과 invitation 검증이 결정합니다.
|
|
146
|
+
|
|
147
|
+
초대가 있지만 bootstrap이 `ORIGIN_NOT_ALLOWED`를 반환하면 오류 surface에 현재 Origin과
|
|
148
|
+
프로젝트 설정에 그대로 추가할 값을 표시합니다. Origin은 protocol, hostname, port까지
|
|
149
|
+
정확히 일치해야 합니다. 이 검사는 invitation 기반 활성화나 서버의 exact-origin 검증을
|
|
150
|
+
우회하지 않습니다.
|
|
151
|
+
|
|
152
|
+
호스트가 자체 개발 안내나 telemetry를 연결하려면 `onInactive`를 사용할 수 있습니다.
|
|
153
|
+
초대가 없는 경우에는 어느 프로젝트에도 연결하지 않으므로 `missing-activation`만 알 수
|
|
154
|
+
있고, `origin-not-allowed`는 초대 bootstrap 응답으로 확인된 뒤에만 전달됩니다.
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
<VisualReview
|
|
158
|
+
onInactive={({ reason, origin }) => {
|
|
159
|
+
console.debug('Visual Review inactive', { reason, origin });
|
|
160
|
+
}}
|
|
161
|
+
/>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
현재 `reason`은 `missing-activation` 또는 `origin-not-allowed`입니다. 콜백은 opt-in
|
|
165
|
+
진단 신호일 뿐 DOM이나 network 요청을 추가하지 않으며, credential을 전달하지 않습니다.
|
|
166
|
+
콜백에서 발생한 예외는 기본 비활성 안내와 bootstrap 오류 UI를 중단시키지 않습니다.
|
|
167
|
+
React adapter는 StrictMode effect replay에서 동일한 상태를 중복 전달하지 않습니다.
|
|
143
168
|
|
|
144
169
|
```bash
|
|
145
170
|
npm run build -- --mode staging
|
|
@@ -186,7 +211,9 @@ safe-area inset은 모든 anchor에 적용됩니다. 너비 640px 이하에서
|
|
|
186
211
|
|
|
187
212
|
Invitation fragment, 검증된 resume marker 또는 명시적 local runtime이 없으면 한 번의
|
|
188
213
|
namespaced storage 확인 뒤 DOM, history listener, auth, dynamic runtime import와 network
|
|
189
|
-
bootstrap을 시작하지 않습니다.
|
|
214
|
+
bootstrap을 시작하지 않습니다. development build의 1회 console 안내와 명시적으로
|
|
215
|
+
등록한 `onInactive` callback만 이 dormant 경계에서 실행될 수 있습니다.
|
|
216
|
+
`enabled={false}`는 긴급 kill switch이며 진단도 실행하지 않습니다.
|
|
190
217
|
|
|
191
218
|
처음에는 `#visual-review=<invitation-id>` 초대 링크로 접근합니다. hosted service가
|
|
192
219
|
project에 연결된 exact Origin 목록과 현재 pathname을 읽기 전용 activation gate로
|
|
@@ -75,6 +75,7 @@ function e(e,r,i,a){let o=e.shadowRoot??e.attachShadow({mode:`open`}),s=o.ownerD
|
|
|
75
75
|
.bootstrap-error-copy > span {
|
|
76
76
|
display: block;
|
|
77
77
|
color: var(--vr-muted);
|
|
78
|
+
white-space: pre-line;
|
|
78
79
|
font: 500 11px/16px Geist, ui-sans-serif, system-ui, sans-serif;
|
|
79
80
|
}
|
|
80
81
|
.bootstrap-error button {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as e}from"./install-RHVUfLTU.js";import{t}from"./embedded-source-DSDHbbeU.js";import{i as n,init as r}from"@instantdb/core";const i=131072,a=32768,o=4096,s=1e3;var c=class extends Error{constructor(e,t){super(e,t),this.name=`InstantCaptureIntegrityError`}};function l(e){let t=_(e,`comment target`,!0),n={kind:t.kind,anchor:le(t.anchor),region:fe(t.region),elements:t.elements.map(e=>({selector:e.selector,tagName:e.tagName,textPreview:e.textPreview,rect:fe(e.rect),source:null,componentStack:[]})),pageUrl:t.pageUrl,pageTitle:t.pageTitle,capturedAt:t.capturedAt,...t.environment?{environment:ne(t.environment)}:{}},r={elements:t.elements.map(e=>({selector:e.selector,source:e.source?pe(e.source):null,componentStack:e.componentStack.map(pe)})),...t.sourceProvenance?{sourceProvenance:me(t.sourceProvenance)}:{}};T(n,i,`Public target`);let a=xe(r,65536,`Source context`);return{publicTarget:n,commentFields:f(n),targetElements:n.elements.map(p),sourceContextJson:a}}function u(e,t,n){let r=b(e,n),i={selector:x(r.anchorSelector,`${n} anchor selector`,o),offsetX:w(r.anchorOffsetX,`${n} anchor offsetX`),offsetY:w(r.anchorOffsetY,`${n} anchor offsetY`),viewportX:w(r.anchorViewportX,`${n} anchor viewportX`),viewportY:w(r.anchorViewportY,`${n} anchor viewportY`)},a=h({kind:r.targetKind,anchor:i,region:{pageX:r.targetPageX,pageY:r.targetPageY,width:r.targetWidth,height:r.targetHeight,viewportX:r.targetViewportX,viewportY:r.targetViewportY,viewportWidth:r.targetViewportWidth,viewportHeight:r.targetViewportHeight},elements:[],pageUrl:de({origin:S(r.targetPageOrigin,`${n} page origin`,1024),pathname:S(r.targetPagePathname,`${n} page pathname`,4096),search:x(r.targetPageSearch,`${n} page search`,1024),hash:x(r.targetPageHash,`${n} page hash`,1024)}),pageTitle:r.targetPageTitle,capturedAt:r.targetCapturedAt,...te(r,n)},n),s=m(t,`${n} elements`),c=a;for(let e of s)try{c=h({...a,elements:[...c.elements,e]},n)}catch{}return c}function d(e){if(!Array.isArray(e)||e.length===0)return;let t=[...e].map(e=>{try{let t=b(e,`Comment scope entry`);return{row:t,ordinal:_e(t.ordinal,`Comment scope entry ordinal`,0,19),id:typeof t.id==`string`?t.id:``}}catch{return null}}).filter(e=>e!==null).sort((e,t)=>e.ordinal-t.ordinal||e.id.localeCompare(t.id)),n={},r=new Set;for(let{row:e,ordinal:i}of t)if(!r.has(i)){r.add(i);try{let t=S(e.key,`Comment scope key`,256);if(Object.hasOwn(n,t))continue;switch(e.valueType){case`string`:n[t]=x(e.stringValue,`Comment scope ${t}`,s);break;case`number`:n[t]=C(e.numberValue,`Comment scope ${t}`);break;case`boolean`:if(typeof e.booleanValue!=`boolean`)throw E(`Comment scope ${t} is invalid`);n[t]=e.booleanValue;break;case`null`:n[t]=null;break;default:throw E(`Comment scope ${t} is invalid`)}}catch{}}if(Object.keys(n).length!==0)try{return T(n,a,`Comment scope`),n}catch{return}}function f(e){let t=new URL(e.pageUrl);return{anchorSelector:e.anchor.selector,anchorOffsetX:e.anchor.offsetX,anchorOffsetY:e.anchor.offsetY,anchorViewportX:e.anchor.viewportX,anchorViewportY:e.anchor.viewportY,targetKind:e.kind,targetPageX:e.region.pageX,targetPageY:e.region.pageY,targetWidth:e.region.width,targetHeight:e.region.height,targetViewportX:e.region.viewportX,targetViewportY:e.region.viewportY,targetViewportWidth:e.region.viewportWidth,targetViewportHeight:e.region.viewportHeight,targetPageOrigin:t.origin,targetPagePathname:ue(t.pathname),targetPageSearch:t.search.slice(1),targetPageHash:t.hash.slice(1),targetPageTitle:e.pageTitle,targetCapturedAt:e.capturedAt,...e.environment?{environmentBrowser:e.environment.browser,environmentOperatingSystem:e.environment.operatingSystem,environmentDeviceType:e.environment.deviceType,environmentScreenWidth:e.environment.screenWidth,environmentScreenHeight:e.environment.screenHeight,environmentDevicePixelRatio:e.environment.devicePixelRatio}:{}}}function p(e,t){return{ordinal:t,selector:e.selector,tagName:e.tagName,textPreview:e.textPreview,pageX:e.rect.pageX,pageY:e.rect.pageY,width:e.rect.width,height:e.rect.height,viewportX:e.rect.viewportX,viewportY:e.rect.viewportY,viewportWidth:e.rect.viewportWidth,viewportHeight:e.rect.viewportHeight}}function m(e,t){if(!Array.isArray(e)||e.length===0)return[];let n=[...e].map(e=>{try{let n=b(e,t);return{row:n,ordinal:_e(n.ordinal,`${t} ordinal`,0,7),id:typeof n.id==`string`?n.id:``}}catch{return null}}).filter(e=>e!==null).sort((e,t)=>e.ordinal-t.ordinal||e.id.localeCompare(t.id)),r=[],i=new Set;for(let{row:e,ordinal:a}of n)if(!i.has(a)){i.add(a);try{r.push(ie({selector:e.selector,tagName:e.tagName,textPreview:e.textPreview,rect:{pageX:e.pageX,pageY:e.pageY,width:e.width,height:e.height,viewportX:e.viewportX,viewportY:e.viewportY,viewportWidth:e.viewportWidth,viewportHeight:e.viewportHeight},source:null,componentStack:[]},`${t}[${a}]`,!1))}catch{}}return r}function h(e,t){return _(e,t,!1)}function g(e,t=`Comment body`){return S(e,t,2e4)}function ee(e){if(e==null)return;let t=b(e,`Comment scope`);if(Object.keys(t).length>20)throw E(`Comment scope has too many fields`);let n={};for(let[e,r]of Object.entries(t)){if(!e.trim()||e.length>256)throw E(`Comment scope has an invalid key`);if(typeof r==`string`){if(r.length>s)throw E(`Comment scope ${e} is too long`);n[e]=r}else if(typeof r==`number`)n[e]=C(r,`Comment scope ${e}`);else if(typeof r==`boolean`||r===null)n[e]=r;else throw E(`Comment scope ${e} is invalid`)}return T(n,a,`Comment scope`),n}function _(e,t,n){let r=y(e,t,[`kind`,`anchor`,`region`,`elements`,`pageUrl`,`pageTitle`,`capturedAt`,`environment`,`sourceProvenance`],[`environment`,`sourceProvenance`]),a=r.kind;if(a!==`element`&&a!==`region`&&a!==`viewport`)throw E(`${t} kind is invalid`);let o=he(r.elements,`${t} elements`);if(o.length>8)throw E(`${t} contains too many elements`);if(!n&&r.sourceProvenance!=null)throw E(`${t} exposes source provenance`);let c=S(r.pageUrl,`${t} pageUrl`,8192);be(c,`${t} pageUrl`);let l={kind:a,anchor:ae(r.anchor,`${t} anchor`),region:oe(r.region,`${t} region`),elements:o.map((e,r)=>ie(e,`${t} elements[${r}]`,n)),pageUrl:c,pageTitle:x(r.pageTitle,`${t} pageTitle`,s),capturedAt:ve(r.capturedAt,`${t} capturedAt`),...r.environment==null?{}:{environment:v(r.environment,`${t} environment`)},...n&&r.sourceProvenance!=null?{sourceProvenance:ce(r.sourceProvenance,`${t} provenance`)}:{}};return T(l,n?196608:i,t),l}function v(e,t){let n=y(e,t,[`browser`,`operatingSystem`,`deviceType`,`screenWidth`,`screenHeight`,`devicePixelRatio`]),r=n.deviceType;if(r!==`desktop`&&r!==`tablet`&&r!==`mobile`&&r!==`unknown`)throw E(`${t} deviceType is invalid`);return{browser:S(n.browser,`${t} browser`,120),operatingSystem:S(n.operatingSystem,`${t} operatingSystem`,120),deviceType:r,screenWidth:re(n.screenWidth,`${t} screenWidth`,1e5),screenHeight:re(n.screenHeight,`${t} screenHeight`,1e5),devicePixelRatio:re(n.devicePixelRatio,`${t} devicePixelRatio`,100)}}function te(e,t){if([e.environmentBrowser,e.environmentOperatingSystem,e.environmentDeviceType,e.environmentScreenWidth,e.environmentScreenHeight,e.environmentDevicePixelRatio].every(e=>e==null))return{};try{return{environment:v({browser:e.environmentBrowser,operatingSystem:e.environmentOperatingSystem,deviceType:e.environmentDeviceType,screenWidth:e.environmentScreenWidth,screenHeight:e.environmentScreenHeight,devicePixelRatio:e.environmentDevicePixelRatio},`${t} environment`)}}catch{return{}}}function ne(e){return{...e}}function re(e,t,n){let r=C(e,t);if(r<=0||r>n)throw E(`${t} is invalid`);return r}function ie(e,t,n){let r=y(e,t,[`selector`,`tagName`,`textPreview`,`rect`,`source`,`componentStack`]),i=he(r.componentStack,`${t} componentStack`);if(i.length>32)throw E(`${t} componentStack is too large`);if(!n&&(r.source!=null||i.length>0))throw E(`${t} exposes source metadata`);return{selector:S(r.selector,`${t} selector`,o),tagName:S(r.tagName,`${t} tagName`,128),textPreview:x(r.textPreview,`${t} textPreview`,s),rect:oe(r.rect,`${t} rect`),source:n&&r.source!=null?se(r.source,`${t} source`):null,componentStack:n?i.map((e,n)=>se(e,`${t} stack[${n}]`)):[]}}function ae(e,t){let n=y(e,t,[`selector`,`offsetX`,`offsetY`,`viewportX`,`viewportY`]);return{selector:x(n.selector,`${t} selector`,o),offsetX:w(n.offsetX,`${t} offsetX`),offsetY:w(n.offsetY,`${t} offsetY`),viewportX:w(n.viewportX,`${t} viewportX`),viewportY:w(n.viewportY,`${t} viewportY`)}}function oe(e,t){let n=y(e,t,[`pageX`,`pageY`,`width`,`height`,`viewportX`,`viewportY`,`viewportWidth`,`viewportHeight`]),r={pageX:C(n.pageX,`${t} pageX`),pageY:C(n.pageY,`${t} pageY`),width:C(n.width,`${t} width`),height:C(n.height,`${t} height`),viewportX:C(n.viewportX,`${t} viewportX`),viewportY:C(n.viewportY,`${t} viewportY`),viewportWidth:C(n.viewportWidth,`${t} viewportWidth`),viewportHeight:C(n.viewportHeight,`${t} viewportHeight`)};if(r.width<0||r.height<0||r.viewportWidth<0||r.viewportHeight<0)throw E(`${t} has a negative dimension`);return r}function se(e,n){let r=y(e,n,[`filePath`,`lineNumber`,`columnNumber`,`componentName`,`origin`,`generated`],[`generated`]),i=r.origin;if(i!==`app`&&i!==`shared-ui`&&i!==`dependency`&&i!==`generated`&&i!==`unknown`)throw E(`${n} origin is invalid`);let a=S(r.filePath,`${n} filePath`,o);return{filePath:a,lineNumber:ye(r.lineNumber,`${n} lineNumber`),columnNumber:ye(r.columnNumber,`${n} columnNumber`),componentName:r.componentName==null?null:S(r.componentName,`${n} componentName`,512),origin:t(a)}}function ce(e,t){let n=y(e,t,[`provider`,`build`,`resolvedAt`]),r=n.provider;if(r!==`react-grab`&&r!==`embedded`&&r!==`custom`)throw E(`${t} provider is invalid`);let i=y(n.build,`${t} build`,[`buildId`,`gitCommit`,`generatedAt`,`mode`],[`generatedAt`]),a=i.mode;if(a!==`development`&&a!==`preview`&&a!==`production`)throw E(`${t} build mode is invalid`);return{provider:r,build:{buildId:S(i.buildId,`${t} buildId`,512),gitCommit:i.gitCommit==null?null:S(i.gitCommit,`${t} gitCommit`,256),...i.generatedAt==null?{}:{generatedAt:ve(i.generatedAt,`${t} generatedAt`)},mode:a},resolvedAt:ve(n.resolvedAt,`${t} resolvedAt`)}}function le(e){return{...e}}function ue(e){return e.replace(/\/+$/,``)||`/`}function de(e){return`${e.origin}${e.pathname}${e.search?`?${e.search}`:``}${e.hash?`#${e.hash}`:``}`}function fe(e){return{...e}}function pe(e){return{...e}}function me(e){return{...e,build:{...e.build}}}function y(e,t,n,r=[]){let i=b(e,t);if(Object.keys(i).some(e=>!n.includes(e)))throw E(`${t} contains unknown fields`);for(let e of n)if(!r.includes(e)&&!Object.hasOwn(i,e))throw E(`${t} is missing ${e}`);return i}function b(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw E(`${t} is missing or invalid`);return e}function he(e,t){if(!Array.isArray(e))throw E(`${t} is missing or invalid`);return e}function x(e,t,n){if(typeof e!=`string`||ge(e,n)>n)throw E(`${t} is invalid or too long`);return e}function ge(e,t){let n=0;for(let r of e)if(n+=1,n>t)return n;return n}function S(e,t,n){let r=x(e,t,n);if(!r.trim())throw E(`${t} is empty`);return r}function C(e,t){if(typeof e!=`number`||!Number.isFinite(e))throw E(`${t} is invalid`);return e}function _e(e,t,n,r){if(typeof e!=`number`||!Number.isSafeInteger(e)||e<n||e>r)throw E(`${t} is invalid`);return e}function w(e,t){let n=C(e,t);if(n<0||n>1)throw E(`${t} is outside 0..1`);return n}function ve(e,t){if(typeof e!=`number`||!Number.isSafeInteger(e)||e<0||e>0xe677d21fdbff)throw E(`${t} is invalid`);return e}function ye(e,t){if(e===null)return null;if(typeof e!=`number`||!Number.isSafeInteger(e)||e<0)throw E(`${t} is invalid`);return e}function be(e,t){let n;try{n=new URL(e)}catch(e){throw E(`${t} is invalid`,e)}if(n.protocol!==`http:`&&n.protocol!==`https:`)throw E(`${t} must use HTTP or HTTPS`)}function T(e,t,n){xe(e,t,n)}function xe(e,t,n){let r;try{r=JSON.stringify(e)}catch(e){throw E(`${n} cannot be serialized`,e)}if(r.length>t)throw E(`${n} is too large`);return r}function E(e,t){return new c(e,{cause:t instanceof Error?t:void 0})}new Uint8Array([107,167,184,17,157,173,17,209,128,180,0,192,79,212,48,200]);const Se=n.schema({entities:{$files:n.entity({path:n.string().unique().indexed(),url:n.string()}),$users:n.entity({email:n.string().unique().indexed()}),projects:n.entity({name:n.string(),slug:n.string().unique().indexed(),allowedOrigin:n.string().optional(),originDisconnectedAt:n.number().optional(),originModelVersion:n.number().optional(),createdAt:n.number().indexed(),updatedAt:n.number()}),projectOrigins:n.entity({projectId:n.string().indexed(),originKey:n.string().unique().indexed(),origin:n.string().indexed(),label:n.string().optional(),createdAt:n.number().indexed(),updatedAt:n.number()}),reviewPages:n.entity({projectId:n.string().indexed(),autoRegistrationSlot:n.string().unique().indexed().optional(),name:n.string(),pathname:n.string(),stagingOrigin:n.string(),createdAt:n.number().indexed(),updatedAt:n.number()}),reviewPageBuilds:n.entity({projectId:n.string().indexed(),pageId:n.string().unique().indexed(),buildId:n.string(),gitCommit:n.string().optional(),generatedAt:n.number().optional(),mode:n.string(),updatedAt:n.number().indexed()}),reviewers:n.entity({authUserId:n.string().indexed(),projectId:n.string().indexed(),email:n.string().indexed(),displayName:n.string(),role:n.string(),createdAt:n.number()}),reviewerIdentityClaims:n.entity({reviewerId:n.string().unique().indexed(),projectId:n.string().indexed(),authUserId:n.string().indexed(),email:n.string(),displayName:n.string(),role:n.string(),createdAt:n.number()}),invitations:n.entity({projectId:n.string().indexed(),reviewerId:n.string().indexed().optional(),email:n.string().indexed(),status:n.string().indexed(),claimRevision:n.number(),claimedByAuthUserId:n.string().indexed().optional(),expiresAt:n.number().indexed(),createdAt:n.number(),acceptedAt:n.number().optional(),revokedAt:n.number().optional()}),comments:n.entity({pageId:n.string().indexed(),pageNumber:n.number().optional(),authorId:n.string().indexed(),authorAuthUserId:n.string().indexed(),authorName:n.string(),body:n.string(),bodyContentMarker:n.string().optional(),anchorSelector:n.string().optional(),anchorOffsetX:n.number().optional(),anchorOffsetY:n.number().optional(),anchorViewportX:n.number().optional(),anchorViewportY:n.number().optional(),targetKind:n.string().optional(),targetPageX:n.number().optional(),targetPageY:n.number().optional(),targetWidth:n.number().optional(),targetHeight:n.number().optional(),targetViewportX:n.number().optional(),targetViewportY:n.number().optional(),targetViewportWidth:n.number().optional(),targetViewportHeight:n.number().optional(),targetPageOrigin:n.string().optional(),targetPagePathname:n.string().optional(),targetPageSearch:n.string().optional(),targetPageHash:n.string().optional(),targetPageTitle:n.string().optional(),targetCapturedAt:n.number().optional(),environmentBrowser:n.string().optional(),environmentOperatingSystem:n.string().optional(),environmentDeviceType:n.string().optional(),environmentScreenWidth:n.number().optional(),environmentScreenHeight:n.number().optional(),environmentDevicePixelRatio:n.number().optional(),status:n.string().indexed(),workflowRevision:n.number(),createdAt:n.number().indexed(),updatedAt:n.number().indexed(),resolvedAt:n.number().optional(),resolvedById:n.string().optional(),deletingAt:n.number().optional()}),commentWorkflowClaims:n.entity({claimKey:n.string().unique().indexed(),commentId:n.string().indexed(),expectedWorkflowRevision:n.number(),createdAt:n.number().indexed()}),commentPageNumberClaims:n.entity({claimKey:n.string().unique().indexed(),pageId:n.string().indexed(),pageNumber:n.number(),commentId:n.string().indexed(),createdAt:n.number().indexed()}),commentTargetElements:n.entity({commentId:n.string().indexed(),slotKey:n.string().unique().indexed().optional(),ordinal:n.number(),selector:n.string(),tagName:n.string(),textPreview:n.string(),pageX:n.number(),pageY:n.number(),width:n.number(),height:n.number(),viewportX:n.number(),viewportY:n.number(),viewportWidth:n.number(),viewportHeight:n.number(),authorAuthUserId:n.string().indexed()}),commentScopeEntries:n.entity({commentId:n.string().indexed(),slotKey:n.string().unique().indexed().optional(),ordinal:n.number(),key:n.string(),valueType:n.string(),stringValue:n.string().optional(),numberValue:n.number().optional(),booleanValue:n.boolean().optional(),authorAuthUserId:n.string().indexed()}),commentSourceContexts:n.entity({commentId:n.string().unique().indexed(),pageId:n.string().indexed(),authorAuthUserId:n.string().indexed(),contextJson:n.string(),createdAt:n.number().indexed()}),replies:n.entity({pageId:n.string().indexed(),commentId:n.string().indexed(),authorId:n.string().indexed(),authorAuthUserId:n.string().indexed(),authorName:n.string(),body:n.string(),bodyContentMarker:n.string().optional(),createdAt:n.number().indexed(),updatedAt:n.number().indexed()}),reviewMessages:n.entity({pageId:n.string().indexed(),pathname:n.string().indexed(),authorId:n.string().indexed(),authorAuthUserId:n.string().indexed(),authorName:n.string(),body:n.string(),bodyContentMarker:n.string(),createdAt:n.number().indexed(),updatedAt:n.number().indexed()})},links:{projectOwners:{forward:{on:`projects`,has:`many`,label:`owners`},reverse:{on:`$users`,has:`many`,label:`ownedProjects`}},projectPages:{forward:{on:`projects`,has:`many`,label:`pages`},reverse:{on:`reviewPages`,has:`one`,label:`project`}},projectOriginProject:{forward:{on:`projects`,has:`many`,label:`origins`},reverse:{on:`projectOrigins`,has:`one`,label:`project`}},pageCurrentBuild:{forward:{on:`reviewPageBuilds`,has:`one`,label:`page`,required:!0,onDelete:`cascade`},reverse:{on:`reviewPages`,has:`one`,label:`currentBuild`}},projectReviewers:{forward:{on:`projects`,has:`many`,label:`reviewers`},reverse:{on:`reviewers`,has:`one`,label:`project`}},reviewerUser:{forward:{on:`reviewers`,has:`one`,label:`$user`},reverse:{on:`$users`,has:`many`,label:`reviewerMemberships`}},projectInvitations:{forward:{on:`projects`,has:`many`,label:`invitations`},reverse:{on:`invitations`,has:`one`,label:`project`}},invitationReviewer:{forward:{on:`invitations`,has:`one`,label:`reviewer`},reverse:{on:`reviewers`,has:`many`,label:`acceptedInvitations`}},invitationActiveUser:{forward:{on:`invitations`,has:`one`,label:`activeUser`},reverse:{on:`$users`,has:`many`,label:`activeReviewInvitations`}},pageComments:{forward:{on:`reviewPages`,has:`many`,label:`comments`},reverse:{on:`comments`,has:`one`,label:`page`}},pageReviewMessages:{forward:{on:`reviewPages`,has:`many`,label:`reviewMessages`},reverse:{on:`reviewMessages`,has:`one`,label:`page`}},commentReplies:{forward:{on:`comments`,has:`many`,label:`replies`},reverse:{on:`replies`,has:`one`,label:`comment`,required:!0,onDelete:`cascade`}},commentTargetElements:{forward:{on:`commentTargetElements`,has:`one`,label:`comment`,required:!0,onDelete:`cascade`},reverse:{on:`comments`,has:`many`,label:`targetElements`}},commentScopeEntries:{forward:{on:`commentScopeEntries`,has:`one`,label:`comment`,required:!0,onDelete:`cascade`},reverse:{on:`comments`,has:`many`,label:`scopeEntries`}},commentSourceContext:{forward:{on:`commentSourceContexts`,has:`one`,label:`comment`,required:!0,onDelete:`cascade`},reverse:{on:`comments`,has:`one`,label:`sourceContext`}},pageSourceContexts:{forward:{on:`commentSourceContexts`,has:`one`,label:`page`,required:!0},reverse:{on:`reviewPages`,has:`many`,label:`sourceContexts`}},sourceContextAuthor:{forward:{on:`commentSourceContexts`,has:`one`,label:`author`,required:!0},reverse:{on:`reviewers`,has:`many`,label:`sourceContexts`}},commentAuthor:{forward:{on:`comments`,has:`one`,label:`author`},reverse:{on:`reviewers`,has:`many`,label:`comments`}},replyAuthor:{forward:{on:`replies`,has:`one`,label:`author`},reverse:{on:`reviewers`,has:`many`,label:`replies`}},reviewMessageAuthor:{forward:{on:`reviewMessages`,has:`one`,label:`author`},reverse:{on:`reviewers`,has:`many`,label:`reviewMessages`}}},rooms:{visualReview:{presence:n.entity({reviewerId:n.string(),displayName:n.string(),color:n.string(),active:n.boolean(),pathname:n.string().optional(),cursorX:n.number().optional(),cursorY:n.number().optional(),viewportWidth:n.number().optional(),viewportHeight:n.number().optional(),cursorChat:n.string().optional()})}}}),D={$default:`false`},O={$default:`false`},k=`$user.activeReviewInvitations`,A=`${k}.project.id`;function j(e){return[`auth.id != null`,`size(auth.ref('${k}.id')) > 0`,`size(auth.ref('${A}')) == size(auth.ref('${k}.id'))`,`size(auth.ref('${k}.status')) == size(auth.ref('${k}.id'))`,`size(auth.ref('${k}.expiresAt')) == size(auth.ref('${k}.id'))`,`size(auth.ref('${k}.revokedAt')) == 0`,`auth.ref('${k}.status').all(status, status == 'accepted')`,`auth.ref('${k}.expiresAt').all(expiresAt, request.time < timestamp(expiresAt))`,e].join(` && `)}function M(...e){return e.map(e=>`(${e})`).join(` && `)}function N(...e){return e.map(e=>`(${e})`).join(` || `)}function P(e){let t=`data.ref('${e}project.origins.origin')`,n=`data.ref('${e}project.allowedOrigin')`,r=`data.ref('${e}project.originModelVersion')`;return N(`request.origin in ${t}`,M(`size(${r}) == 0`,`request.origin in ${n}`))}j(`data.ref('project.id')[0] in auth.ref('${A}')`),N(`request.origin in data.ref('project.origins.origin')`,M(`size(data.ref('project.originModelVersion')) == 0`,`request.origin in data.ref('project.allowedOrigin')`)),N(`request.origin in data.ref('origins.origin')`,M(`size(data.ref('originModelVersion')) == 0`,`request.origin in data.ref('allowedOrigin')`)),j(`data.ref('page.project.id')[0] in auth.ref('${A}')`),P(`page.`),N(`auth.id != null && auth.id in data.ref('comment.page.project.owners.id')`,M(j(`data.ref('comment.page.project.id')[0] in auth.ref('${A}')`),P(`comment.page.`))),j(`data.ref('comment.page.project.id')[0] in auth.ref('${A}')`),P(`comment.page.`),j(`data.ref('page.project.id')[0] in auth.ref('${A}')`),P(`page.`),P(``);const Ce=M(`data.reviewerId != null`,`data.projectId in data.ref('project.id')`,`data.reviewerId in data.ref('reviewer.id')`,`data.projectId in data.ref('reviewer.project.id')`,`auth.id in data.ref('reviewer.$user.id')`,`auth.email in data.ref('reviewer.email')`);M(`auth.id != null`,`data.revokedAt == null`,`data.status in ['pending', 'accepted']`,`data.status == 'pending' || data.claimedByAuthUserId == auth.id`,`request.time < timestamp(data.expiresAt)`,`request.modifiedFields.all(field, field in ['status', 'claimedByAuthUserId', 'acceptedAt', 'claimRevision', 'activeUser'])`,`'status' in request.modifiedFields`,`'claimedByAuthUserId' in request.modifiedFields`,`'acceptedAt' in request.modifiedFields`,`'claimRevision' in request.modifiedFields`,`'activeUser' in request.modifiedFields`,`newData.status == 'accepted'`,`newData.claimedByAuthUserId == auth.id`,`newData.claimRevision == data.claimRevision + 1`,`math.abs((request.time - timestamp(newData.acceptedAt)).getMinutes()) <= 1`,Ce),M(`actions.data == 'update'`,`actions.linkedData == 'update'`,`auth.id != null`,`auth.email != null`,`linkedData.id == auth.id`,`linkedData.email == auth.email`,`data.email == auth.email`,`data.revokedAt == null`,`data.status in ['pending', 'accepted']`,`data.status == 'pending' || data.claimedByAuthUserId == auth.id`,`request.time < timestamp(data.expiresAt)`,`newData.status == 'accepted'`,`newData.claimedByAuthUserId == auth.id`,`newData.claimRevision == data.claimRevision + 1`,`math.abs((request.time - timestamp(newData.acceptedAt)).getMinutes()) <= 1`,Ce),M(`actions.data == 'update'`,`actions.linkedData == 'update'`,`auth.id != null`,`auth.email != null`,`data.id == auth.id`,`data.email == auth.email`,`linkedData.email == auth.email`,`linkedData.revokedAt == null`,`linkedData.status == 'accepted'`,`linkedData.claimedByAuthUserId == auth.id`,`request.time < timestamp(linkedData.expiresAt)`,`math.abs((request.time - timestamp(linkedData.acceptedAt)).getMinutes()) <= 1`,`linkedData.projectId in linkedData.ref('project.id')`,`linkedData.reviewerId in linkedData.ref('reviewer.id')`,`linkedData.projectId in linkedData.ref('reviewer.project.id')`,`auth.id in linkedData.ref('reviewer.$user.id')`,`auth.email in linkedData.ref('reviewer.email')`),M(`auth.id != null`,`auth.email != null`,`linkedData.id == auth.id`,`linkedData.email == auth.email`,`data.email == auth.email`,`data.claimedByAuthUserId == auth.id`,`auth.id in data.ref('activeUser.id')`),M(`auth.id != null`,`auth.email != null`,`data.id == auth.id`,`data.email == auth.email`,`linkedData.email == auth.email`,`linkedData.claimedByAuthUserId == auth.id`,`auth.id in linkedData.ref('activeUser.id')`),{...D},{...D},{...O},{...O},j(`data.id in auth.ref('${A}')`),{...D},{...O},{...D},{...D},{...O},{...D},{...O},j(`data.ref('project.id')[0] in auth.ref('${A}')`),{...D},{...O},{...D},{...D},{...O},{...O},{...D},{...O},{...D},{...D},{...D},{...D},{...D},{...D},{...D};function we(e){if(!e.trim())throw Error(`InstantDB app ID is required`);return r({appId:e,schema:Se,devtool:!1})}var Te=class{db;session;#e;attachScreenshot;constructor(e,t,n={}){this.db=e,this.session=t,this.#e=n.commentTransport,this.#e&&(this.attachScreenshot=(e,t,n)=>this.#e.uploadScreenshot({pageId:e,commentId:t,screenshot:n}))}async getSnapshot(e){let{data:t}=await this.db.queryOnce(Ee(e,this.session.authUserId));return Oe(e,t.comments,t.replies)}async getProjectSnapshot(e){this.#t(e);let{data:t}=await this.db.queryOnce(De(e,this.session.authUserId));return ke(e,t.comments,t.replies)}subscribe(e,t,n){return this.db.subscribeQuery(Ee(e,this.session.authUserId),r=>{if(r.error){n?.(Ie(r.error));return}if(r.data)try{t(Oe(e,r.data.comments,r.data.replies))}catch{n?.({type:`error`,code:`data-integrity`,recovery:`retry`,clearSnapshot:!0})}})}subscribeProject(e,t,n){return this.#t(e),this.db.subscribeQuery(De(e,this.session.authUserId),r=>{if(r.error){n?.(Ie(r.error));return}if(r.data)try{t(ke(e,r.data.comments,r.data.replies))}catch{n?.({type:`error`,code:`data-integrity`,recovery:`retry`,clearSnapshot:!0})}})}async mutate(e,t){switch(t.type){case`comment.upsert`:{if(t.comment.pageId!==e)throw Error(`Comment page mismatch`);let n=t.comment;if(n.authorId!==this.session.reviewerId)throw Error(`Comment author mismatch`);let r=g(n.body).trim(),i=z(n.createdAt,`Comment createdAt`);if(z(n.updatedAt,`Comment updatedAt`)<i)throw new c(`Comment updatedAt precedes createdAt`);if(n.createdAt!==n.updatedAt)throw new c(`Comment edits must go through the review service`);if(n.status!==`open`||n.resolvedAt!==void 0||n.resolvedById!==void 0)throw new c(`New comments must start open`);let a=l(n.target);if(!Pe(n.anchor,a.publicTarget.anchor))throw new c(`Comment anchor does not match its target`);if(!this.#e)throw new c(`Comment creation requires the review service transport`);await this.#e.createComment({pageId:e,commentId:n.id,body:r,target:n.target,...n.scope===void 0?{}:{scope:n.scope}});return}case`comment.delete`:throw new c(`Comment deletion must go through the review service`);case`reply.upsert`:{let e=t.reply;if(e.authorId!==this.session.reviewerId)throw Error(`Reply author mismatch`);let n=g(e.body,`Reply body`).trim(),r=z(e.createdAt,`Reply createdAt`);if(z(e.updatedAt,`Reply updatedAt`)<r)throw new c(`Reply updatedAt precedes createdAt`);if(e.createdAt!==e.updatedAt)throw new c(`Reply edits must go through the review service`);if(!this.#e)throw new c(`Reply creation requires the review service transport`);await this.#e.createReply({commentId:e.commentId,replyId:e.id,body:n});return}case`reply.delete`:throw new c(`Reply deletion must go through the review service`)}}#t(e){if(!e.trim()||e!==this.session.projectId)throw Error(`Project does not belong to the reviewer session`)}};function Ee(e,t){return{comments:{$:{where:{pageId:e},order:{createdAt:`asc`}},targetElements:{},scopeEntries:{}},replies:{$:{where:{pageId:e},order:{createdAt:`asc`}}},$users:{$:{where:{id:t}},activeReviewInvitations:{project:{}}}}}function De(e,t){return{comments:{$:{where:{"page.project.id":e},order:{createdAt:`asc`}},page:{project:{}},targetElements:{},scopeEntries:{}},replies:{$:{where:{"comment.page.project.id":e},order:{createdAt:`asc`}},comment:{page:{project:{}}}},$users:{$:{where:{id:t}},activeReviewInvitations:{project:{}}}}}function Oe(e,t,n){let r=t.map(t=>je(t,e));F(r,`comment`);let i=new Set(r.map(({id:e})=>e)),a=n.map(t=>Me(t,e));F(a,`reply`);for(let e of a)if(!i.has(e.commentId))throw new c(`Reply ${e.id} references a comment outside the page snapshot`);return{pageId:e,comments:r,replies:a}}function ke(e,t,n){let r=new Map,i=t.map(t=>{let n=L(t.pageId,`comment pageId`);Ae(t.page,n,e,`comment ${String(t.id)}`);let i=I(t.page,`comment ${String(t.id)} page`),a=je(t,n),o=`/`;try{o=new URL(a.target.pageUrl).pathname||`/`}catch{}return r.set(n,{id:n,name:typeof i.name==`string`&&i.name.trim()?i.name.trim():a.target.pageTitle.trim()||o,pathname:typeof i.pathname==`string`&&i.pathname.trim()?i.pathname.trim():o}),a});F(i,`comment`);let a=new Map(i.map(e=>[e.id,e])),o=n.map(t=>{let n=L(t.pageId,`reply pageId`),r=I(t.comment,`reply ${String(t.id)} comment`),i=L(t.commentId,`reply ${String(t.id)} commentId`);if(L(r.id,`reply ${String(t.id)} comment relation id`)!==i)throw new c(`Reply ${String(t.id)} has an inconsistent comment relation`);Ae(r.page,n,e,`reply ${String(t.id)}`);let o=Me(t,n),s=a.get(o.commentId);if(!s||s.pageId!==n)throw new c(`Reply ${o.id} references a comment outside the project snapshot`);return o});return F(o,`reply`),{projectId:e,pages:[...r.values()].sort((e,t)=>e.pathname.localeCompare(t.pathname)||e.id.localeCompare(t.id)),comments:i,replies:o}}function Ae(e,t,n,r){let i=I(e,`${r} page`);if(L(i.id,`${r} page id`)!==t)throw new c(`${r} escaped its page relation`);if(L(I(i.project,`${r} project`).id,`${r} project id`)!==n)throw new c(`${r} escaped its project scope`)}function je(e,t){let n=I(e,`comment`),r=L(n.id,`comment id`);if(L(n.pageId,`comment ${r} pageId`)!==t)throw new c(`Comment ${r} escaped its page scope`);L(n.authorAuthUserId,`comment ${r} authorAuthUserId`);let i=!(Object.hasOwn(n,`anchor`)&&Object.hasOwn(n,`target`)),a=i?u(n,n.targetElements,`comment ${r} target`):h(n.target,`comment ${r} target`),o=i?{...a.anchor}:Ne(n.anchor,`comment ${r} anchor`);if(!Pe(o,a.anchor))throw new c(`Comment ${r} has inconsistent anchors`);let s=n.status;if(s!==`open`&&s!==`resolved`)throw new c(`Comment ${r} has an invalid status`);let l=z(n.createdAt,`comment ${r} createdAt`),f=z(n.updatedAt,`comment ${r} updatedAt`);if(f<l)throw new c(`Comment ${r} updatedAt precedes createdAt`);let p=Be(n.resolvedAt,`comment ${r} resolvedAt`),m=Ve(n.resolvedById,`comment ${r} resolvedById`);if(s===`open`&&(p!==void 0||m!==void 0))throw new c(`Open comment ${r} contains resolution metadata`);if(s===`resolved`&&(p===void 0||m===void 0||p!==f))throw new c(`Resolved comment ${r} has invalid workflow metadata`);return{id:r,pageId:t,...He(n.pageNumber,`comment ${r} pageNumber`),authorId:L(n.authorId,`comment ${r} authorId`),authorName:L(n.authorName,`comment ${r} authorName`),body:g(n.body,`comment ${r} body`),anchor:o,target:a,...i?Fe(d(n.scopeEntries)):n.scope==null?{}:{scope:ee(n.scope)},status:s,workflowRevision:ze(n.workflowRevision,`comment ${r} workflowRevision`),createdAt:l,updatedAt:f,...p===void 0?{}:{resolvedAt:p},...m===void 0?{}:{resolvedById:m}}}function Me(e,t){let n=I(e,`reply`),r=L(n.id,`reply id`);if(L(n.pageId,`reply ${r} pageId`)!==t)throw new c(`Reply ${r} escaped its page scope`);L(n.authorAuthUserId,`reply ${r} authorAuthUserId`);let i=z(n.createdAt,`reply ${r} createdAt`),a=z(n.updatedAt,`reply ${r} updatedAt`);if(a<i)throw new c(`Reply ${r} updatedAt precedes createdAt`);return{id:r,commentId:L(n.commentId,`reply ${r} commentId`),authorId:L(n.authorId,`reply ${r} authorId`),authorName:L(n.authorName,`reply ${r} authorName`),body:g(n.body,`reply ${r} body`),createdAt:i,updatedAt:a}}function Ne(e,t){let n=I(e,t);if(Object.keys(n).length!==5||!Object.hasOwn(n,`selector`)||!Object.hasOwn(n,`offsetX`)||!Object.hasOwn(n,`offsetY`)||!Object.hasOwn(n,`viewportX`)||!Object.hasOwn(n,`viewportY`))throw new c(`${t} has invalid fields`);return{selector:Re(n.selector,`${t} selector`),offsetX:R(n.offsetX,`${t} offsetX`),offsetY:R(n.offsetY,`${t} offsetY`),viewportX:R(n.viewportX,`${t} viewportX`),viewportY:R(n.viewportY,`${t} viewportY`)}}function Pe(e,t){return e.selector===t.selector&&e.offsetX===t.offsetX&&e.offsetY===t.offsetY&&e.viewportX===t.viewportX&&e.viewportY===t.viewportY}function Fe(e){return e===void 0?{}:{scope:e}}function F(e,t){let n=new Set;for(let r of e){if(n.has(r.id))throw new c(`Duplicate ${t} ${r.id}`);n.add(r.id)}}function Ie(e){let t=Le(e).toLowerCase();return t.includes(`expired`)||t.includes(`token`)?{type:`access-lost`,code:`session-expired`,recovery:`reauthenticate`,clearSnapshot:!0}:t.includes(`permission`)||t.includes(`forbidden`)||t.includes(`unauthorized`)?{type:`access-lost`,code:`permission-denied`,recovery:`reauthenticate`,clearSnapshot:!0}:{type:`error`,code:`transport`,recovery:`retry`,clearSnapshot:!0}}function Le(e){return e instanceof Error?e.message:e&&typeof e==`object`&&`message`in e?String(e.message):``}function I(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw new c(`${t} is missing or invalid`);return e}function Re(e,t){if(typeof e!=`string`)throw new c(`${t} is invalid`);return e}function L(e,t){let n=Re(e,t);if(!n.trim())throw new c(`${t} is empty`);return n}function R(e,t){if(typeof e!=`number`||!Number.isFinite(e)||e<0||e>1)throw new c(`${t} is invalid`);return e}function z(e,t){if(!Number.isSafeInteger(e)||e<0||e>0xe677d21fdbff)throw new c(`${t} is invalid`);return e}function ze(e,t){if(!Number.isSafeInteger(e)||e<0)throw new c(`${t} is invalid`);return e}function Be(e,t){return e==null?void 0:z(e,t)}function Ve(e,t){return e==null?void 0:L(e,t)}function He(e,t){if(e==null)return{};let n=ze(e,t);if(n<1)throw new c(`${t} is invalid`);return{pageNumber:n}}Object.freeze({field:`createdAt`,direction:`desc`,tieBreaker:`id`,tieDirection:`desc`}),Object.freeze({comments:200,replies:1e3,sourceContexts:200});var Ue=class{db;session;roomCredential;#e=new Map;constructor(e,t,n){this.db=e,this.session=t,this.roomCredential=n}subscribe(e,t,n,r){let i=[],a=[],o=!1,s=[],c=()=>{o||n({pageId:e,peers:structuredClone(i),messages:structuredClone(a)})};if(t.cursors){let n=tt(e,t.roomId),a,l,u=this.roomCredential?.id===t.roomId?this.roomCredential:void 0,d=u??{id:t.roomId,expiresAt:2**53-1,refresh:async()=>void 0},f=t=>{let o=this.db.joinRoom(`visualReview`,t),s=o.subscribePresence({},e=>{if(e.error){r?.(rt(e.error));return}i=Object.values(e.peers).map(e=>Ge(e)).filter(e=>e!==null).sort((e,t)=>e.displayName.localeCompare(t.displayName)||e.peerId.localeCompare(t.peerId)),c()}),l=a;a=()=>{s(),o.leaveRoom()},this.#e.set(n,{pageId:e,roomId:t,publishPresence:e=>o.publishPresence(e)}),l?.()},p=()=>{if(!u||o)return;let e=Math.max(1e3,d.expiresAt-Date.now()+250);l=setTimeout(()=>{m()},e)},m=async()=>{try{let e=await d.refresh();if(o||!e)return;d={...e,refresh:d.refresh},u&&(u.id=e.id,u.expiresAt=e.expiresAt),f(e.id),p()}catch(e){if(o)return;r?.(rt(e)),o||(l=setTimeout(()=>{m()},5e3))}};f(d.id),p(),s.push(()=>{l&&clearTimeout(l),this.#e.delete(n),a?.()})}return t.chat&&s.push(this.db.subscribeQuery(We(e,this.session.authUserId),t=>{if(t.error){r?.(rt(t.error));return}if(t.data)try{a=t.data.reviewMessages.map(t=>Je(t,e)).sort(nt),c()}catch{r?.({type:`error`,code:`data-integrity`,recovery:`retry`,clearSnapshot:!0})}})),queueMicrotask(c),()=>{if(!o){o=!0;for(let e of s.reverse())try{e()}catch{}}}}publishPresence(e,t,n){let r=this.#e.get(tt(e,t));r&&r.publishPresence({reviewerId:this.session.reviewerId,displayName:this.session.displayName,color:n.color,active:n.active,pathname:qe(n.pathname),...n.cursorX===void 0?{}:{cursorX:n.cursorX},...n.cursorY===void 0?{}:{cursorY:n.cursorY},...n.viewportWidth===void 0?{}:{viewportWidth:n.viewportWidth},...n.viewportHeight===void 0?{}:{viewportHeight:n.viewportHeight},cursorChat:Ke(n.cursorChat)})}async sendMessage(e,t){throw Error(`Persisted review messages are no longer supported`)}};function We(e,t){return{reviewMessages:{$:{where:{pageId:e},order:{createdAt:`desc`},limit:200}},$users:{$:{where:{id:t}},activeReviewInvitations:{project:{}}}}}function Ge(e){let t=Ze(e.reviewerId,128),n=Ze(e.displayName,512),r=typeof e.color==`string`&&/^#[0-9a-f]{6}$/iu.test(e.color)?e.color:null;if(!t||!n||!r||typeof e.active!=`boolean`)return null;let i=Qe(e.cursorX),a=Qe(e.cursorY),o=$e(e.viewportWidth),s=$e(e.viewportHeight),c=Ke(e.cursorChat),l=qe(e.pathname);return{peerId:e.peerId,reviewerId:t,displayName:n,color:r,active:e.active,pathname:l,...i===void 0?{}:{cursorX:i},...a===void 0?{}:{cursorY:a},...o===void 0?{}:{viewportWidth:o},...s===void 0?{}:{viewportHeight:s},...c?{cursorChat:c}:{}}}function Ke(e){return typeof e==`string`?e.trim().slice(0,280):``}function qe(e){if(typeof e!=`string`)return`/`;let t=e.trim();return t.startsWith(`/`)?t.slice(0,2e3):`/`}function Je(e,t){let n=B(e.id,`Review message id`,128);if(B(e.pageId,`Review message pageId`,128)!==t)throw Error(`Review message page mismatch`);return{id:n,pageId:t,pathname:Xe(e.pathname),authorId:B(e.authorId,`Review message authorId`,128),authorName:B(e.authorName,`Review message authorName`,512),body:Ye(e.body),createdAt:et(e.createdAt,`Review message createdAt`),updatedAt:et(e.updatedAt,`Review message updatedAt`)}}function Ye(e){return B(e,`Review message body`,4e3)}function Xe(e){let t=B(e,`Review message pathname`,2e3);if(!t.startsWith(`/`))throw Error(`Review message pathname is invalid`);return t}function B(e,t,n){if(typeof e!=`string`)throw Error(`${t} is invalid`);let r=e.trim();if(!r||r.length>n)throw Error(`${t} is invalid`);return r}function Ze(e,t){if(typeof e!=`string`)return null;let n=e.trim();return n&&n.length<=t?n:null}function Qe(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function $e(e){let t=Qe(e);return t!==void 0&&t>0?t:void 0}function et(e,t){if(!Number.isSafeInteger(e)||e<0)throw Error(`${t} is invalid`);return e}function tt(e,t){return JSON.stringify([e,t])}function nt(e,t){return e.createdAt-t.createdAt||e.id.localeCompare(t.id)}function rt(e){let t=e&&typeof e==`object`&&`code`in e?String(e.code):``;if(/^INVITATION_(?:EXPIRED|NOT_FOUND|REQUIRED|REVOKED)$/u.test(t))return{type:`access-lost`,code:t===`INVITATION_EXPIRED`?`session-expired`:`membership-revoked`,recovery:`reauthenticate`,clearSnapshot:!0};let n=String(e instanceof Error||e&&typeof e==`object`&&`message`in e?e.message:e).toLowerCase();return n.includes(`expired`)||n.includes(`token`)?{type:`access-lost`,code:`session-expired`,recovery:`reauthenticate`,clearSnapshot:!0}:n.includes(`permission`)||n.includes(`forbidden`)||n.includes(`unauthorized`)?{type:`access-lost`,code:`permission-denied`,recovery:`reauthenticate`,clearSnapshot:!0}:{type:`error`,code:`transport`,recovery:`retry`,clearSnapshot:!0}}Object.freeze({field:`createdAt`,direction:`desc`,tieBreaker:`id`,tieDirection:`desc`});var V=class extends Error{code;constructor(e,t){super(t),this.code=e,this.name=`ReviewerCommentSaveError`}};function it(e,t){let n=e.replace(/\/+$/,``),r=async(e,r)=>{let i=await t();if(!i)throw new V(`AUTH_REQUIRED`,`로그인 세션이 만료되었습니다. 새로고침 후 다시 시도해 주세요.`);let a;try{a=await fetch(`${n}${e}`,{method:`POST`,headers:{authorization:`Bearer ${i}`,"content-type":`application/json`},body:JSON.stringify(r)})}catch{throw new V(`NETWORK`,`리뷰 서버에 연결하지 못했습니다. 연결을 확인하고 다시 시도해 주세요.`)}if(!a.ok)throw new V(...await ot(a))};return{createComment:({target:e,...t})=>{let{environment:n,...i}=e;return r(`/v1/comments`,{...t,target:i,...n?{environment:n}:{}})},createReply:e=>r(`/v1/replies`,e),uploadScreenshot:async({pageId:e,commentId:r,screenshot:i})=>{let a=await t();if(!a)throw new V(`AUTH_REQUIRED`,`로그인 세션이 만료되어 위치 캡처를 저장하지 못했습니다.`);let o;try{o=await fetch(`${n}/v1/comments/${encodeURIComponent(r)}/screenshot`,{method:`PUT`,headers:{authorization:`Bearer ${a}`,"content-type":i.contentType,"x-review-page-id":e,"x-review-image-width":String(i.width),"x-review-image-height":String(i.height)},body:at(i.bytes)})}catch{throw new V(`NETWORK`,`리뷰 서버에 연결하지 못해 위치 캡처를 저장하지 못했습니다.`)}if(!o.ok)throw new V(...await ot(o))}}}function at(e){let t=new Uint8Array(e.byteLength);return t.set(e),t.buffer}async function ot(e){let t=e.status>=500?`리뷰 서버가 코멘트를 저장하지 못했습니다. 잠시 후 다시 시도해 주세요.`:`코멘트를 저장하지 못했습니다.`;try{let n=await e.json();if(!n||typeof n!=`object`)return[`UNKNOWN`,t];let r=n;return[typeof r.error==`string`?r.error:`UNKNOWN`,typeof r.message==`string`&&r.message.trim()?r.message:t]}catch{return[`UNKNOWN`,t]}}var H=class extends Error{code;constructor(e,t){super(t),this.code=e,this.name=`ReviewBootstrapError`}};const U=new Map;function st(e,t={}){let n=e.trim();if(!n)throw Error(`InstantDB app ID is required`);return{async resolve(e){let r=(t.databaseFactory??we)(n),i=await dt(n,r,e.authHost,e.signal,e.styleNonce);for(;;)try{await ct(t.acceptInvitation,{refreshToken:i.refresh_token,invitationId:e.invitationId,suggestedDisplayName:wt(i.email),authHost:e.authHost,signal:e.signal,styleNonce:e.styleNonce});break}catch(t){if(!q(t,`INVITATION_EMAIL_MISMATCH`))throw t;await _t(e.authHost,e.signal,e.styleNonce),i=await ft(n,r,i,e.authHost,e.signal,e.styleNonce)}t.resolveReviewPage&&await t.resolveReviewPage({refreshToken:i.refresh_token,invitationId:e.invitationId,origin:e.location.origin,pathname:e.location.pathname,signal:e.signal});let{data:a}=await r.queryOnce({reviewers:{$:{where:{authUserId:i.id}}},reviewPages:{},invitations:{}}),o=lt(a.invitations,a.reviewers,a.reviewPages,{invitationId:e.invitationId,authUserId:i.id,email:i.email??``,location:e.location,now:Date.now()});if(!o.ok)throw new H(o.code,X(o.code));let s={authUserId:i.id,reviewerId:o.reviewer.id,projectId:o.reviewer.projectId,invitationId:e.invitationId,email:o.reviewer.email||i.email||``,displayName:o.reviewer.displayName||i.email||`Reviewer`,role:o.reviewer.role===`agency`?`agency`:`reviewer`},c=o.page.id,l=e.collaboration?.scopeId,u=(e.collaboration?.cursors===!0||e.collaboration?.chat===!0)&&t.resolveCollaborationRoom?await t.resolveCollaborationRoom({refreshToken:i.refresh_token,invitationId:e.invitationId,pageId:o.page.id,scopeId:e.collaboration.scopeId,signal:e.signal}):void 0,d=u&&t.resolveCollaborationRoom?{...u,refresh:async()=>{let n=await r.getAuth();if(!(!n?.refresh_token||l===void 0))return t.resolveCollaborationRoom?.({refreshToken:n.refresh_token,invitationId:e.invitationId,pageId:c,scopeId:l,signal:new AbortController().signal})}}:void 0,f=0;return{pageId:o.page.id,resolvePage:async n=>{let i=++f,a=()=>i!==f||n.signal.aborted,o=(e,t,n)=>({pageId:e,...n&&d?{collaborationRoomId:n.id}:{},commit:()=>{a()||(c=e,t!==void 0&&(l=t),!(!n||!d)&&(d.id=n.id,d.expiresAt=n.expiresAt))}});if(n.location.origin!==e.location.origin)throw new H(`PAGE_NOT_FOUND`,X(`PAGE_NOT_FOUND`));let{data:u}=await r.queryOnce({reviewPages:{$:{where:{projectId:s.projectId}}}});if(a())throw J();let p=Et(n.location.pathname),m=ut(u.reviewPages,s.projectId,n.location.origin,p);if(!m&&t.resolveReviewPage){let i=await r.getAuth();if(a())throw J();if(!i?.refresh_token)throw Error(`리뷰 세션이 만료되어 페이지를 등록할 수 없습니다.`);if(await t.resolveReviewPage({refreshToken:i.refresh_token,invitationId:e.invitationId,origin:n.location.origin,pathname:p,signal:n.signal}),a()||({data:u}=await r.queryOnce({reviewPages:{$:{where:{projectId:s.projectId}}}}),a()))throw J();m=ut(u.reviewPages,s.projectId,n.location.origin,p)}if(!m)throw new H(`PAGE_NOT_FOUND`,X(`PAGE_NOT_FOUND`));if(n.collaboration?.cursors!==!0&&n.collaboration?.chat!==!0||d===void 0||t.resolveCollaborationRoom===void 0||!n.collaboration)return o(m.id,n.collaboration?.scopeId);let h=await r.getAuth();if(a())throw J();if(!h?.refresh_token)throw Error(`리뷰 세션이 만료되어 실시간 협업 연결을 갱신할 수 없습니다.`);let g=await t.resolveCollaborationRoom({refreshToken:h.refresh_token,invitationId:e.invitationId,pageId:m.id,scopeId:n.collaboration.scopeId,signal:n.signal});if(a())throw J();return o(m.id,n.collaboration.scopeId,g)},session:s,repository:new Te(r,s,{...t.serviceUrl===void 0?{}:{commentTransport:it(t.serviceUrl,async()=>(await r.getAuth())?.refresh_token??null)}}),...e.collaboration?.cursors===!0||e.collaboration?.chat===!0?{collaborationRepository:new Ue(r,s,d)}:{},...(e.collaboration?.cursors===!0||e.collaboration?.chat===!0)&&d?{collaborationRoomId:d.id}:{},allowedStagingHosts:[e.location.hostname]}}}}async function ct(e,t){if(!e)return;let n={refreshToken:t.refreshToken,invitationId:t.invitationId,signal:t.signal};try{await e(n);return}catch(e){if(!q(e,`DISPLAY_NAME_REQUIRED`))throw e}let r=await gt(t.authHost,t.signal,t.suggestedDisplayName,t.styleNonce);await e({...n,displayName:r})}function lt(e,t,n,r){let i=e.find(({id:e})=>e===r.invitationId);if(!i||Dt(i.email)!==Dt(r.email))return{ok:!1,code:`INVITATION_REQUIRED`};if(i.status===`revoked`)return{ok:!1,code:`INVITATION_REVOKED`};if(i.status===`expired`||i.expiresAt<=r.now)return{ok:!1,code:`INVITATION_EXPIRED`};if(i.status!==`accepted`)return{ok:!1,code:`INVITATION_NOT_ACCEPTED`};let a=t.find(e=>e.authUserId===r.authUserId&&e.projectId===i.projectId);if(!a)return{ok:!1,code:`MEMBERSHIP_REQUIRED`};let o=Et(r.location.pathname),s=ut(n,i.projectId,r.location.origin,o);return s?{ok:!0,invitation:i,reviewer:a,page:s}:{ok:!1,code:`PAGE_NOT_FOUND`}}function ut(e,t,n,r){let i=e.filter(e=>e.projectId===t&&Et(e.pathname)===r),a=i.filter(({stagingOrigin:e})=>e===n);return(a.length>0?a:i).sort((e,t)=>(e.createdAt??2**53-1)-(t.createdAt??2**53-1)||e.id.localeCompare(t.id))[0]}async function dt(e,t,n,r,i){let a=await W(r,()=>t.getAuth());if(a)return a;let o=await pt(e,r);try{return await W(r,()=>t.getAuth())||await ht(t,n,r,i)}finally{o()}}async function ft(e,t,n,r,i,a){G(i);let o=await pt(e,i);try{let e=await W(i,()=>t.getAuth());return e&&e.id!==n.id?e:(e&&await W(i,async()=>{await t.auth.signOut()}),G(i),await ht(t,r,i,a))}finally{o()}}async function pt(e,t){G(t);let n=U.get(e);return n||(n={held:!1,waiters:[]},U.set(e,n)),n.held?new Promise((e,r)=>{let i,a=()=>{let e=n.waiters.indexOf(i);e<0||(n.waiters.splice(e,1),t.removeEventListener(`abort`,a),r(Y()))};i={signal:t,resolve:e,reject:r,abort:a},n.waiters.push(i),t.addEventListener(`abort`,a,{once:!0}),t.aborted&&a()}):(n.held=!0,mt(e,n))}function mt(e,t){let n=!1;return()=>{if(!n){for(n=!0;t.waiters.length>0;){let n=t.waiters.shift();if(n.signal.removeEventListener(`abort`,n.abort),n.signal.aborted){n.reject(Y());continue}n.resolve(mt(e,t));return}t.held=!1,U.get(e)===t&&U.delete(e)}}}async function W(e,t){G(e);let n=await t();return G(e),n}function G(e){if(e.aborted)throw Y()}function ht(e,t,n,r){try{G(n)}catch(e){return Promise.reject(e)}let i=yt(t);i.replaceChildren(bt(i,r),xt(i));let a=i.querySelector(`form`),o=i.querySelector(`h2`),s=i.querySelector(`.description`),c=a.elements.namedItem(`email`),l=a.elements.namedItem(`code`),u=i.querySelector(`.code`),d=i.querySelector(`button`),f=i.querySelector(`.error`),p=!1;return new Promise((t,r)=>{let m=!1,h=!1,g=!1,ee=()=>{n.removeEventListener(`abort`,v),i.removeEventListener(`keydown`,te),a.removeEventListener(`submit`,ne)},_=e=>{m||(m=!0,ee(),e())},v=()=>{m||(g=!0,ee(),h||_(()=>r(Y())))},te=e=>{let t=e;t.key===`Escape`?(t.preventDefault(),v()):t.key===`Tab`&&Tt(i,t)},ne=async i=>{if(i.preventDefault(),!(m||h)){h=!0,f.textContent=``,d.disabled=!0,a.setAttribute(`aria-busy`,`true`);try{if(G(n),!p){let t=c.value.trim();await W(n,async()=>{await e.auth.sendMagicCode({email:t})}),p=!0,c.readOnly=!0,u.hidden=!1,l.required=!0,o.textContent=`인증 코드`,s.textContent=`${t}로 보낸 코드를 입력하세요.`,d.textContent=`확인`,l.focus();return}await W(n,async()=>{await e.auth.signInWithMagicCode({email:c.value.trim(),code:l.value.trim()})});let r=await W(n,()=>e.getAuth());if(!r)throw Error(`인증 세션을 확인할 수 없습니다.`);_(()=>t(r))}catch(e){if(m||n.aborted||q(e,`AUTH_CANCELLED`))return;f.textContent=vt(e)}finally{h=!1,!m&&(g||n.aborted)?_(()=>r(Y())):m||(d.disabled=!1,a.removeAttribute(`aria-busy`))}}};n.addEventListener(`abort`,v,{once:!0}),i.addEventListener(`keydown`,te),a.addEventListener(`submit`,ne)})}function gt(e,t,n=``,r){if(t.aborted)return Promise.reject(Y());let i=yt(e);i.replaceChildren(bt(i,r),St(i));let a=i.querySelector(`form`),o=a.elements.namedItem(`displayName`),s=i.querySelector(`button`),c=i.querySelector(`.error`);return o.value=n.trim().slice(0,120),o.focus(),o.select(),new Promise((e,n)=>{let r=!1,l=e=>{r||(r=!0,t.removeEventListener(`abort`,u),i.removeEventListener(`keydown`,p),a.removeEventListener(`submit`,f),e())},u=()=>l(()=>n(Y())),d=()=>{let t=o.value.trim();if(!t){c.textContent=`이름을 입력해 주세요.`,o.focus();return}if(t.length>120){c.textContent=`이름은 120자 이하여야 합니다.`,o.focus();return}c.textContent=``,s.disabled=!0,a.setAttribute(`aria-busy`,`true`),l(()=>e(t))},f=e=>{e.preventDefault(),d()},p=e=>{let t=e;if(t.key===`Escape`){t.preventDefault(),u();return}if(t.key===`Tab`){Tt(i,t);return}t.key===`Enter`&&!t.isComposing&&t.target===o&&(t.preventDefault(),d())};t.addEventListener(`abort`,u,{once:!0}),i.addEventListener(`keydown`,p),a.addEventListener(`submit`,f)})}function _t(e,t,n){if(t.aborted)return Promise.reject(Y());let r=yt(e);r.replaceChildren(bt(r,n),Ct(r));let i=r.querySelector(`form`),a=r.querySelector(`button`);return a.focus(),new Promise((e,n)=>{let o=!1,s=e=>{o||(o=!0,t.removeEventListener(`abort`,c),r.removeEventListener(`keydown`,u),i.removeEventListener(`submit`,l),e())},c=()=>s(()=>n(Y())),l=t=>{t.preventDefault(),a.disabled=!0,i.setAttribute(`aria-busy`,`true`),s(e)},u=e=>{let t=e;t.key===`Escape`?(t.preventDefault(),c()):t.key===`Tab`&&Tt(r,t)};t.addEventListener(`abort`,c,{once:!0}),r.addEventListener(`keydown`,u),i.addEventListener(`submit`,l)})}function vt(e){if(e&&typeof e==`object`&&`body`in e){let t=e.body;if(t?.message)return t.message}return e instanceof Error?e.message:`로그인에 실패했습니다. 다시 시도해 주세요.`}function yt(e){return e.shadowRoot??e.attachShadow({mode:`open`})}function bt(e,t){let n=e.ownerDocument.createElement(`style`);return t&&(n.nonce=t),n.textContent=Ot,n}function xt(e){let t=e.ownerDocument,n=t.createElement(`form`);n.setAttribute(`role`,`dialog`),n.setAttribute(`aria-modal`,`true`),n.setAttribute(`aria-labelledby`,`visual-review-login-title`),n.setAttribute(`aria-describedby`,`visual-review-login-description`);let r=K(t,`p`,`01.works`,`eyebrow`),i=K(t,`h2`,`Visual Review`);i.id=`visual-review-login-title`;let a=K(t,`p`,`초대받은 이메일로 계속하세요.`,`description`);a.id=`visual-review-login-description`;let o=t.createElement(`label`);o.append(`이메일`);let s=t.createElement(`input`);s.name=`email`,s.type=`email`,s.autocomplete=`email`,s.required=!0,o.append(s);let c=t.createElement(`label`);c.className=`code`,c.hidden=!0,c.append(`인증 코드`);let l=t.createElement(`input`);l.name=`code`,l.inputMode=`numeric`,l.autocomplete=`one-time-code`,c.append(l);let u=K(t,`p`,``,`error`);u.setAttribute(`role`,`alert`);let d=K(t,`button`,`코드 받기`);return d.type=`submit`,n.append(r,i,a,o,c,u,d),n}function St(e){let t=e.ownerDocument,n=t.createElement(`form`);n.setAttribute(`role`,`dialog`),n.setAttribute(`aria-modal`,`true`),n.setAttribute(`aria-labelledby`,`visual-review-name-title`),n.setAttribute(`aria-describedby`,`visual-review-name-description`);let r=K(t,`p`,`01.works`,`eyebrow`),i=K(t,`h2`,`표시 이름`);i.id=`visual-review-name-title`;let a=K(t,`p`,`피드백에 이 이름이 표시됩니다.`,`description`);a.id=`visual-review-name-description`;let o=K(t,`label`,`이름`);o.htmlFor=`visual-review-display-name`;let s=t.createElement(`input`);s.id=`visual-review-display-name`,s.name=`displayName`,s.autocomplete=`name`,s.maxLength=120,s.required=!0;let c=K(t,`p`,``,`error`);c.setAttribute(`role`,`alert`);let l=K(t,`button`,`리뷰 시작`);return l.type=`submit`,n.append(r,i,a,o,s,c,l),n}function Ct(e){let t=e.ownerDocument,n=t.createElement(`form`);n.setAttribute(`role`,`dialog`),n.setAttribute(`aria-modal`,`true`),n.setAttribute(`aria-labelledby`,`visual-review-account-title`),n.setAttribute(`aria-describedby`,`visual-review-account-description`);let r=K(t,`p`,`01.works`,`eyebrow`),i=K(t,`h2`,`계정 확인`);i.id=`visual-review-account-title`;let a=K(t,`p`,`이 초대는 현재 로그인한 계정과 일치하지 않습니다.`,`description`);a.id=`visual-review-account-description`;let o=K(t,`button`,`다른 계정으로 계속`);return o.type=`submit`,n.append(r,i,a,o),n}function K(e,t,n,r){let i=e.createElement(t);return i.textContent=n,r&&(i.className=r),i}function wt(e){return e?.split(`@`)[0]?.trim().slice(0,120)??``}function q(e,t){return!!(e&&typeof e==`object`&&`code`in e&&e.code===t)}function J(){return new DOMException(`Aborted`,`AbortError`)}function Y(){return new H(`AUTH_CANCELLED`,`리뷰 로그인이 취소되었습니다.`)}function Tt(e,t){let n=Array.from(e.querySelectorAll(`input:not([disabled]),button:not([disabled])`)).filter(e=>!e.closest(`[hidden]`));if(n.length===0)return;let r=n[0],i=n.at(-1);t.shiftKey&&e.activeElement===r?(t.preventDefault(),i.focus()):!t.shiftKey&&e.activeElement===i&&(t.preventDefault(),r.focus())}function Et(e){return e.replace(/\/+$/,``)||`/`}function Dt(e){return e.trim().toLowerCase()}function X(e){switch(e){case`INVITATION_REQUIRED`:return`현재 계정과 일치하는 리뷰 초대를 찾을 수 없습니다.`;case`INVITATION_NOT_ACCEPTED`:return`아직 수락되지 않은 리뷰 초대입니다.`;case`INVITATION_REVOKED`:return`취소된 리뷰 초대입니다. 계속 검토하려면 담당자에게 다시 요청하세요.`;case`INVITATION_EXPIRED`:return`만료된 리뷰 초대입니다. 담당자에게 새 링크를 요청하세요.`;case`MEMBERSHIP_REQUIRED`:return`이 프로젝트의 reviewer membership이 없습니다.`;case`PAGE_NOT_FOUND`:return`이 페이지는 아직 리뷰 대상이 아닙니다. 담당자에게 문의하세요.`}}const Ot=`
|
|
1
|
+
import{r as e}from"./install-Ca3QT7YV.js";import{t}from"./embedded-source-DSDHbbeU.js";import{i as n,init as r}from"@instantdb/core";const i=131072,a=32768,o=4096,s=1e3;var c=class extends Error{constructor(e,t){super(e,t),this.name=`InstantCaptureIntegrityError`}};function l(e){let t=_(e,`comment target`,!0),n={kind:t.kind,anchor:le(t.anchor),region:fe(t.region),elements:t.elements.map(e=>({selector:e.selector,tagName:e.tagName,textPreview:e.textPreview,rect:fe(e.rect),source:null,componentStack:[]})),pageUrl:t.pageUrl,pageTitle:t.pageTitle,capturedAt:t.capturedAt,...t.environment?{environment:ne(t.environment)}:{}},r={elements:t.elements.map(e=>({selector:e.selector,source:e.source?pe(e.source):null,componentStack:e.componentStack.map(pe)})),...t.sourceProvenance?{sourceProvenance:me(t.sourceProvenance)}:{}};T(n,i,`Public target`);let a=xe(r,65536,`Source context`);return{publicTarget:n,commentFields:f(n),targetElements:n.elements.map(p),sourceContextJson:a}}function u(e,t,n){let r=b(e,n),i={selector:x(r.anchorSelector,`${n} anchor selector`,o),offsetX:w(r.anchorOffsetX,`${n} anchor offsetX`),offsetY:w(r.anchorOffsetY,`${n} anchor offsetY`),viewportX:w(r.anchorViewportX,`${n} anchor viewportX`),viewportY:w(r.anchorViewportY,`${n} anchor viewportY`)},a=h({kind:r.targetKind,anchor:i,region:{pageX:r.targetPageX,pageY:r.targetPageY,width:r.targetWidth,height:r.targetHeight,viewportX:r.targetViewportX,viewportY:r.targetViewportY,viewportWidth:r.targetViewportWidth,viewportHeight:r.targetViewportHeight},elements:[],pageUrl:de({origin:S(r.targetPageOrigin,`${n} page origin`,1024),pathname:S(r.targetPagePathname,`${n} page pathname`,4096),search:x(r.targetPageSearch,`${n} page search`,1024),hash:x(r.targetPageHash,`${n} page hash`,1024)}),pageTitle:r.targetPageTitle,capturedAt:r.targetCapturedAt,...te(r,n)},n),s=m(t,`${n} elements`),c=a;for(let e of s)try{c=h({...a,elements:[...c.elements,e]},n)}catch{}return c}function d(e){if(!Array.isArray(e)||e.length===0)return;let t=[...e].map(e=>{try{let t=b(e,`Comment scope entry`);return{row:t,ordinal:_e(t.ordinal,`Comment scope entry ordinal`,0,19),id:typeof t.id==`string`?t.id:``}}catch{return null}}).filter(e=>e!==null).sort((e,t)=>e.ordinal-t.ordinal||e.id.localeCompare(t.id)),n={},r=new Set;for(let{row:e,ordinal:i}of t)if(!r.has(i)){r.add(i);try{let t=S(e.key,`Comment scope key`,256);if(Object.hasOwn(n,t))continue;switch(e.valueType){case`string`:n[t]=x(e.stringValue,`Comment scope ${t}`,s);break;case`number`:n[t]=C(e.numberValue,`Comment scope ${t}`);break;case`boolean`:if(typeof e.booleanValue!=`boolean`)throw E(`Comment scope ${t} is invalid`);n[t]=e.booleanValue;break;case`null`:n[t]=null;break;default:throw E(`Comment scope ${t} is invalid`)}}catch{}}if(Object.keys(n).length!==0)try{return T(n,a,`Comment scope`),n}catch{return}}function f(e){let t=new URL(e.pageUrl);return{anchorSelector:e.anchor.selector,anchorOffsetX:e.anchor.offsetX,anchorOffsetY:e.anchor.offsetY,anchorViewportX:e.anchor.viewportX,anchorViewportY:e.anchor.viewportY,targetKind:e.kind,targetPageX:e.region.pageX,targetPageY:e.region.pageY,targetWidth:e.region.width,targetHeight:e.region.height,targetViewportX:e.region.viewportX,targetViewportY:e.region.viewportY,targetViewportWidth:e.region.viewportWidth,targetViewportHeight:e.region.viewportHeight,targetPageOrigin:t.origin,targetPagePathname:ue(t.pathname),targetPageSearch:t.search.slice(1),targetPageHash:t.hash.slice(1),targetPageTitle:e.pageTitle,targetCapturedAt:e.capturedAt,...e.environment?{environmentBrowser:e.environment.browser,environmentOperatingSystem:e.environment.operatingSystem,environmentDeviceType:e.environment.deviceType,environmentScreenWidth:e.environment.screenWidth,environmentScreenHeight:e.environment.screenHeight,environmentDevicePixelRatio:e.environment.devicePixelRatio}:{}}}function p(e,t){return{ordinal:t,selector:e.selector,tagName:e.tagName,textPreview:e.textPreview,pageX:e.rect.pageX,pageY:e.rect.pageY,width:e.rect.width,height:e.rect.height,viewportX:e.rect.viewportX,viewportY:e.rect.viewportY,viewportWidth:e.rect.viewportWidth,viewportHeight:e.rect.viewportHeight}}function m(e,t){if(!Array.isArray(e)||e.length===0)return[];let n=[...e].map(e=>{try{let n=b(e,t);return{row:n,ordinal:_e(n.ordinal,`${t} ordinal`,0,7),id:typeof n.id==`string`?n.id:``}}catch{return null}}).filter(e=>e!==null).sort((e,t)=>e.ordinal-t.ordinal||e.id.localeCompare(t.id)),r=[],i=new Set;for(let{row:e,ordinal:a}of n)if(!i.has(a)){i.add(a);try{r.push(ie({selector:e.selector,tagName:e.tagName,textPreview:e.textPreview,rect:{pageX:e.pageX,pageY:e.pageY,width:e.width,height:e.height,viewportX:e.viewportX,viewportY:e.viewportY,viewportWidth:e.viewportWidth,viewportHeight:e.viewportHeight},source:null,componentStack:[]},`${t}[${a}]`,!1))}catch{}}return r}function h(e,t){return _(e,t,!1)}function g(e,t=`Comment body`){return S(e,t,2e4)}function ee(e){if(e==null)return;let t=b(e,`Comment scope`);if(Object.keys(t).length>20)throw E(`Comment scope has too many fields`);let n={};for(let[e,r]of Object.entries(t)){if(!e.trim()||e.length>256)throw E(`Comment scope has an invalid key`);if(typeof r==`string`){if(r.length>s)throw E(`Comment scope ${e} is too long`);n[e]=r}else if(typeof r==`number`)n[e]=C(r,`Comment scope ${e}`);else if(typeof r==`boolean`||r===null)n[e]=r;else throw E(`Comment scope ${e} is invalid`)}return T(n,a,`Comment scope`),n}function _(e,t,n){let r=y(e,t,[`kind`,`anchor`,`region`,`elements`,`pageUrl`,`pageTitle`,`capturedAt`,`environment`,`sourceProvenance`],[`environment`,`sourceProvenance`]),a=r.kind;if(a!==`element`&&a!==`region`&&a!==`viewport`)throw E(`${t} kind is invalid`);let o=he(r.elements,`${t} elements`);if(o.length>8)throw E(`${t} contains too many elements`);if(!n&&r.sourceProvenance!=null)throw E(`${t} exposes source provenance`);let c=S(r.pageUrl,`${t} pageUrl`,8192);be(c,`${t} pageUrl`);let l={kind:a,anchor:ae(r.anchor,`${t} anchor`),region:oe(r.region,`${t} region`),elements:o.map((e,r)=>ie(e,`${t} elements[${r}]`,n)),pageUrl:c,pageTitle:x(r.pageTitle,`${t} pageTitle`,s),capturedAt:ve(r.capturedAt,`${t} capturedAt`),...r.environment==null?{}:{environment:v(r.environment,`${t} environment`)},...n&&r.sourceProvenance!=null?{sourceProvenance:ce(r.sourceProvenance,`${t} provenance`)}:{}};return T(l,n?196608:i,t),l}function v(e,t){let n=y(e,t,[`browser`,`operatingSystem`,`deviceType`,`screenWidth`,`screenHeight`,`devicePixelRatio`]),r=n.deviceType;if(r!==`desktop`&&r!==`tablet`&&r!==`mobile`&&r!==`unknown`)throw E(`${t} deviceType is invalid`);return{browser:S(n.browser,`${t} browser`,120),operatingSystem:S(n.operatingSystem,`${t} operatingSystem`,120),deviceType:r,screenWidth:re(n.screenWidth,`${t} screenWidth`,1e5),screenHeight:re(n.screenHeight,`${t} screenHeight`,1e5),devicePixelRatio:re(n.devicePixelRatio,`${t} devicePixelRatio`,100)}}function te(e,t){if([e.environmentBrowser,e.environmentOperatingSystem,e.environmentDeviceType,e.environmentScreenWidth,e.environmentScreenHeight,e.environmentDevicePixelRatio].every(e=>e==null))return{};try{return{environment:v({browser:e.environmentBrowser,operatingSystem:e.environmentOperatingSystem,deviceType:e.environmentDeviceType,screenWidth:e.environmentScreenWidth,screenHeight:e.environmentScreenHeight,devicePixelRatio:e.environmentDevicePixelRatio},`${t} environment`)}}catch{return{}}}function ne(e){return{...e}}function re(e,t,n){let r=C(e,t);if(r<=0||r>n)throw E(`${t} is invalid`);return r}function ie(e,t,n){let r=y(e,t,[`selector`,`tagName`,`textPreview`,`rect`,`source`,`componentStack`]),i=he(r.componentStack,`${t} componentStack`);if(i.length>32)throw E(`${t} componentStack is too large`);if(!n&&(r.source!=null||i.length>0))throw E(`${t} exposes source metadata`);return{selector:S(r.selector,`${t} selector`,o),tagName:S(r.tagName,`${t} tagName`,128),textPreview:x(r.textPreview,`${t} textPreview`,s),rect:oe(r.rect,`${t} rect`),source:n&&r.source!=null?se(r.source,`${t} source`):null,componentStack:n?i.map((e,n)=>se(e,`${t} stack[${n}]`)):[]}}function ae(e,t){let n=y(e,t,[`selector`,`offsetX`,`offsetY`,`viewportX`,`viewportY`]);return{selector:x(n.selector,`${t} selector`,o),offsetX:w(n.offsetX,`${t} offsetX`),offsetY:w(n.offsetY,`${t} offsetY`),viewportX:w(n.viewportX,`${t} viewportX`),viewportY:w(n.viewportY,`${t} viewportY`)}}function oe(e,t){let n=y(e,t,[`pageX`,`pageY`,`width`,`height`,`viewportX`,`viewportY`,`viewportWidth`,`viewportHeight`]),r={pageX:C(n.pageX,`${t} pageX`),pageY:C(n.pageY,`${t} pageY`),width:C(n.width,`${t} width`),height:C(n.height,`${t} height`),viewportX:C(n.viewportX,`${t} viewportX`),viewportY:C(n.viewportY,`${t} viewportY`),viewportWidth:C(n.viewportWidth,`${t} viewportWidth`),viewportHeight:C(n.viewportHeight,`${t} viewportHeight`)};if(r.width<0||r.height<0||r.viewportWidth<0||r.viewportHeight<0)throw E(`${t} has a negative dimension`);return r}function se(e,n){let r=y(e,n,[`filePath`,`lineNumber`,`columnNumber`,`componentName`,`origin`,`generated`],[`generated`]),i=r.origin;if(i!==`app`&&i!==`shared-ui`&&i!==`dependency`&&i!==`generated`&&i!==`unknown`)throw E(`${n} origin is invalid`);let a=S(r.filePath,`${n} filePath`,o);return{filePath:a,lineNumber:ye(r.lineNumber,`${n} lineNumber`),columnNumber:ye(r.columnNumber,`${n} columnNumber`),componentName:r.componentName==null?null:S(r.componentName,`${n} componentName`,512),origin:t(a)}}function ce(e,t){let n=y(e,t,[`provider`,`build`,`resolvedAt`]),r=n.provider;if(r!==`react-grab`&&r!==`embedded`&&r!==`custom`)throw E(`${t} provider is invalid`);let i=y(n.build,`${t} build`,[`buildId`,`gitCommit`,`generatedAt`,`mode`],[`generatedAt`]),a=i.mode;if(a!==`development`&&a!==`preview`&&a!==`production`)throw E(`${t} build mode is invalid`);return{provider:r,build:{buildId:S(i.buildId,`${t} buildId`,512),gitCommit:i.gitCommit==null?null:S(i.gitCommit,`${t} gitCommit`,256),...i.generatedAt==null?{}:{generatedAt:ve(i.generatedAt,`${t} generatedAt`)},mode:a},resolvedAt:ve(n.resolvedAt,`${t} resolvedAt`)}}function le(e){return{...e}}function ue(e){return e.replace(/\/+$/,``)||`/`}function de(e){return`${e.origin}${e.pathname}${e.search?`?${e.search}`:``}${e.hash?`#${e.hash}`:``}`}function fe(e){return{...e}}function pe(e){return{...e}}function me(e){return{...e,build:{...e.build}}}function y(e,t,n,r=[]){let i=b(e,t);if(Object.keys(i).some(e=>!n.includes(e)))throw E(`${t} contains unknown fields`);for(let e of n)if(!r.includes(e)&&!Object.hasOwn(i,e))throw E(`${t} is missing ${e}`);return i}function b(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw E(`${t} is missing or invalid`);return e}function he(e,t){if(!Array.isArray(e))throw E(`${t} is missing or invalid`);return e}function x(e,t,n){if(typeof e!=`string`||ge(e,n)>n)throw E(`${t} is invalid or too long`);return e}function ge(e,t){let n=0;for(let r of e)if(n+=1,n>t)return n;return n}function S(e,t,n){let r=x(e,t,n);if(!r.trim())throw E(`${t} is empty`);return r}function C(e,t){if(typeof e!=`number`||!Number.isFinite(e))throw E(`${t} is invalid`);return e}function _e(e,t,n,r){if(typeof e!=`number`||!Number.isSafeInteger(e)||e<n||e>r)throw E(`${t} is invalid`);return e}function w(e,t){let n=C(e,t);if(n<0||n>1)throw E(`${t} is outside 0..1`);return n}function ve(e,t){if(typeof e!=`number`||!Number.isSafeInteger(e)||e<0||e>0xe677d21fdbff)throw E(`${t} is invalid`);return e}function ye(e,t){if(e===null)return null;if(typeof e!=`number`||!Number.isSafeInteger(e)||e<0)throw E(`${t} is invalid`);return e}function be(e,t){let n;try{n=new URL(e)}catch(e){throw E(`${t} is invalid`,e)}if(n.protocol!==`http:`&&n.protocol!==`https:`)throw E(`${t} must use HTTP or HTTPS`)}function T(e,t,n){xe(e,t,n)}function xe(e,t,n){let r;try{r=JSON.stringify(e)}catch(e){throw E(`${n} cannot be serialized`,e)}if(r.length>t)throw E(`${n} is too large`);return r}function E(e,t){return new c(e,{cause:t instanceof Error?t:void 0})}new Uint8Array([107,167,184,17,157,173,17,209,128,180,0,192,79,212,48,200]);const Se=n.schema({entities:{$files:n.entity({path:n.string().unique().indexed(),url:n.string()}),$users:n.entity({email:n.string().unique().indexed()}),projects:n.entity({name:n.string(),slug:n.string().unique().indexed(),allowedOrigin:n.string().optional(),originDisconnectedAt:n.number().optional(),originModelVersion:n.number().optional(),createdAt:n.number().indexed(),updatedAt:n.number()}),projectOrigins:n.entity({projectId:n.string().indexed(),originKey:n.string().unique().indexed(),origin:n.string().indexed(),label:n.string().optional(),createdAt:n.number().indexed(),updatedAt:n.number()}),reviewPages:n.entity({projectId:n.string().indexed(),autoRegistrationSlot:n.string().unique().indexed().optional(),name:n.string(),pathname:n.string(),stagingOrigin:n.string(),createdAt:n.number().indexed(),updatedAt:n.number()}),reviewPageBuilds:n.entity({projectId:n.string().indexed(),pageId:n.string().unique().indexed(),buildId:n.string(),gitCommit:n.string().optional(),generatedAt:n.number().optional(),mode:n.string(),updatedAt:n.number().indexed()}),reviewers:n.entity({authUserId:n.string().indexed(),projectId:n.string().indexed(),email:n.string().indexed(),displayName:n.string(),role:n.string(),createdAt:n.number()}),reviewerIdentityClaims:n.entity({reviewerId:n.string().unique().indexed(),projectId:n.string().indexed(),authUserId:n.string().indexed(),email:n.string(),displayName:n.string(),role:n.string(),createdAt:n.number()}),invitations:n.entity({projectId:n.string().indexed(),reviewerId:n.string().indexed().optional(),email:n.string().indexed(),status:n.string().indexed(),claimRevision:n.number(),claimedByAuthUserId:n.string().indexed().optional(),expiresAt:n.number().indexed(),createdAt:n.number(),acceptedAt:n.number().optional(),revokedAt:n.number().optional()}),comments:n.entity({pageId:n.string().indexed(),pageNumber:n.number().optional(),authorId:n.string().indexed(),authorAuthUserId:n.string().indexed(),authorName:n.string(),body:n.string(),bodyContentMarker:n.string().optional(),anchorSelector:n.string().optional(),anchorOffsetX:n.number().optional(),anchorOffsetY:n.number().optional(),anchorViewportX:n.number().optional(),anchorViewportY:n.number().optional(),targetKind:n.string().optional(),targetPageX:n.number().optional(),targetPageY:n.number().optional(),targetWidth:n.number().optional(),targetHeight:n.number().optional(),targetViewportX:n.number().optional(),targetViewportY:n.number().optional(),targetViewportWidth:n.number().optional(),targetViewportHeight:n.number().optional(),targetPageOrigin:n.string().optional(),targetPagePathname:n.string().optional(),targetPageSearch:n.string().optional(),targetPageHash:n.string().optional(),targetPageTitle:n.string().optional(),targetCapturedAt:n.number().optional(),environmentBrowser:n.string().optional(),environmentOperatingSystem:n.string().optional(),environmentDeviceType:n.string().optional(),environmentScreenWidth:n.number().optional(),environmentScreenHeight:n.number().optional(),environmentDevicePixelRatio:n.number().optional(),status:n.string().indexed(),workflowRevision:n.number(),createdAt:n.number().indexed(),updatedAt:n.number().indexed(),resolvedAt:n.number().optional(),resolvedById:n.string().optional(),deletingAt:n.number().optional()}),commentWorkflowClaims:n.entity({claimKey:n.string().unique().indexed(),commentId:n.string().indexed(),expectedWorkflowRevision:n.number(),createdAt:n.number().indexed()}),commentPageNumberClaims:n.entity({claimKey:n.string().unique().indexed(),pageId:n.string().indexed(),pageNumber:n.number(),commentId:n.string().indexed(),createdAt:n.number().indexed()}),commentTargetElements:n.entity({commentId:n.string().indexed(),slotKey:n.string().unique().indexed().optional(),ordinal:n.number(),selector:n.string(),tagName:n.string(),textPreview:n.string(),pageX:n.number(),pageY:n.number(),width:n.number(),height:n.number(),viewportX:n.number(),viewportY:n.number(),viewportWidth:n.number(),viewportHeight:n.number(),authorAuthUserId:n.string().indexed()}),commentScopeEntries:n.entity({commentId:n.string().indexed(),slotKey:n.string().unique().indexed().optional(),ordinal:n.number(),key:n.string(),valueType:n.string(),stringValue:n.string().optional(),numberValue:n.number().optional(),booleanValue:n.boolean().optional(),authorAuthUserId:n.string().indexed()}),commentSourceContexts:n.entity({commentId:n.string().unique().indexed(),pageId:n.string().indexed(),authorAuthUserId:n.string().indexed(),contextJson:n.string(),createdAt:n.number().indexed()}),replies:n.entity({pageId:n.string().indexed(),commentId:n.string().indexed(),authorId:n.string().indexed(),authorAuthUserId:n.string().indexed(),authorName:n.string(),body:n.string(),bodyContentMarker:n.string().optional(),createdAt:n.number().indexed(),updatedAt:n.number().indexed()}),reviewMessages:n.entity({pageId:n.string().indexed(),pathname:n.string().indexed(),authorId:n.string().indexed(),authorAuthUserId:n.string().indexed(),authorName:n.string(),body:n.string(),bodyContentMarker:n.string(),createdAt:n.number().indexed(),updatedAt:n.number().indexed()})},links:{projectOwners:{forward:{on:`projects`,has:`many`,label:`owners`},reverse:{on:`$users`,has:`many`,label:`ownedProjects`}},projectPages:{forward:{on:`projects`,has:`many`,label:`pages`},reverse:{on:`reviewPages`,has:`one`,label:`project`}},projectOriginProject:{forward:{on:`projects`,has:`many`,label:`origins`},reverse:{on:`projectOrigins`,has:`one`,label:`project`}},pageCurrentBuild:{forward:{on:`reviewPageBuilds`,has:`one`,label:`page`,required:!0,onDelete:`cascade`},reverse:{on:`reviewPages`,has:`one`,label:`currentBuild`}},projectReviewers:{forward:{on:`projects`,has:`many`,label:`reviewers`},reverse:{on:`reviewers`,has:`one`,label:`project`}},reviewerUser:{forward:{on:`reviewers`,has:`one`,label:`$user`},reverse:{on:`$users`,has:`many`,label:`reviewerMemberships`}},projectInvitations:{forward:{on:`projects`,has:`many`,label:`invitations`},reverse:{on:`invitations`,has:`one`,label:`project`}},invitationReviewer:{forward:{on:`invitations`,has:`one`,label:`reviewer`},reverse:{on:`reviewers`,has:`many`,label:`acceptedInvitations`}},invitationActiveUser:{forward:{on:`invitations`,has:`one`,label:`activeUser`},reverse:{on:`$users`,has:`many`,label:`activeReviewInvitations`}},pageComments:{forward:{on:`reviewPages`,has:`many`,label:`comments`},reverse:{on:`comments`,has:`one`,label:`page`}},pageReviewMessages:{forward:{on:`reviewPages`,has:`many`,label:`reviewMessages`},reverse:{on:`reviewMessages`,has:`one`,label:`page`}},commentReplies:{forward:{on:`comments`,has:`many`,label:`replies`},reverse:{on:`replies`,has:`one`,label:`comment`,required:!0,onDelete:`cascade`}},commentTargetElements:{forward:{on:`commentTargetElements`,has:`one`,label:`comment`,required:!0,onDelete:`cascade`},reverse:{on:`comments`,has:`many`,label:`targetElements`}},commentScopeEntries:{forward:{on:`commentScopeEntries`,has:`one`,label:`comment`,required:!0,onDelete:`cascade`},reverse:{on:`comments`,has:`many`,label:`scopeEntries`}},commentSourceContext:{forward:{on:`commentSourceContexts`,has:`one`,label:`comment`,required:!0,onDelete:`cascade`},reverse:{on:`comments`,has:`one`,label:`sourceContext`}},pageSourceContexts:{forward:{on:`commentSourceContexts`,has:`one`,label:`page`,required:!0},reverse:{on:`reviewPages`,has:`many`,label:`sourceContexts`}},sourceContextAuthor:{forward:{on:`commentSourceContexts`,has:`one`,label:`author`,required:!0},reverse:{on:`reviewers`,has:`many`,label:`sourceContexts`}},commentAuthor:{forward:{on:`comments`,has:`one`,label:`author`},reverse:{on:`reviewers`,has:`many`,label:`comments`}},replyAuthor:{forward:{on:`replies`,has:`one`,label:`author`},reverse:{on:`reviewers`,has:`many`,label:`replies`}},reviewMessageAuthor:{forward:{on:`reviewMessages`,has:`one`,label:`author`},reverse:{on:`reviewers`,has:`many`,label:`reviewMessages`}}},rooms:{visualReview:{presence:n.entity({reviewerId:n.string(),displayName:n.string(),color:n.string(),active:n.boolean(),pathname:n.string().optional(),cursorX:n.number().optional(),cursorY:n.number().optional(),viewportWidth:n.number().optional(),viewportHeight:n.number().optional(),cursorChat:n.string().optional()})}}}),D={$default:`false`},O={$default:`false`},k=`$user.activeReviewInvitations`,A=`${k}.project.id`;function j(e){return[`auth.id != null`,`size(auth.ref('${k}.id')) > 0`,`size(auth.ref('${A}')) == size(auth.ref('${k}.id'))`,`size(auth.ref('${k}.status')) == size(auth.ref('${k}.id'))`,`size(auth.ref('${k}.expiresAt')) == size(auth.ref('${k}.id'))`,`size(auth.ref('${k}.revokedAt')) == 0`,`auth.ref('${k}.status').all(status, status == 'accepted')`,`auth.ref('${k}.expiresAt').all(expiresAt, request.time < timestamp(expiresAt))`,e].join(` && `)}function M(...e){return e.map(e=>`(${e})`).join(` && `)}function N(...e){return e.map(e=>`(${e})`).join(` || `)}function P(e){let t=`data.ref('${e}project.origins.origin')`,n=`data.ref('${e}project.allowedOrigin')`,r=`data.ref('${e}project.originModelVersion')`;return N(`request.origin in ${t}`,M(`size(${r}) == 0`,`request.origin in ${n}`))}j(`data.ref('project.id')[0] in auth.ref('${A}')`),N(`request.origin in data.ref('project.origins.origin')`,M(`size(data.ref('project.originModelVersion')) == 0`,`request.origin in data.ref('project.allowedOrigin')`)),N(`request.origin in data.ref('origins.origin')`,M(`size(data.ref('originModelVersion')) == 0`,`request.origin in data.ref('allowedOrigin')`)),j(`data.ref('page.project.id')[0] in auth.ref('${A}')`),P(`page.`),N(`auth.id != null && auth.id in data.ref('comment.page.project.owners.id')`,M(j(`data.ref('comment.page.project.id')[0] in auth.ref('${A}')`),P(`comment.page.`))),j(`data.ref('comment.page.project.id')[0] in auth.ref('${A}')`),P(`comment.page.`),j(`data.ref('page.project.id')[0] in auth.ref('${A}')`),P(`page.`),P(``);const Ce=M(`data.reviewerId != null`,`data.projectId in data.ref('project.id')`,`data.reviewerId in data.ref('reviewer.id')`,`data.projectId in data.ref('reviewer.project.id')`,`auth.id in data.ref('reviewer.$user.id')`,`auth.email in data.ref('reviewer.email')`);M(`auth.id != null`,`data.revokedAt == null`,`data.status in ['pending', 'accepted']`,`data.status == 'pending' || data.claimedByAuthUserId == auth.id`,`request.time < timestamp(data.expiresAt)`,`request.modifiedFields.all(field, field in ['status', 'claimedByAuthUserId', 'acceptedAt', 'claimRevision', 'activeUser'])`,`'status' in request.modifiedFields`,`'claimedByAuthUserId' in request.modifiedFields`,`'acceptedAt' in request.modifiedFields`,`'claimRevision' in request.modifiedFields`,`'activeUser' in request.modifiedFields`,`newData.status == 'accepted'`,`newData.claimedByAuthUserId == auth.id`,`newData.claimRevision == data.claimRevision + 1`,`math.abs((request.time - timestamp(newData.acceptedAt)).getMinutes()) <= 1`,Ce),M(`actions.data == 'update'`,`actions.linkedData == 'update'`,`auth.id != null`,`auth.email != null`,`linkedData.id == auth.id`,`linkedData.email == auth.email`,`data.email == auth.email`,`data.revokedAt == null`,`data.status in ['pending', 'accepted']`,`data.status == 'pending' || data.claimedByAuthUserId == auth.id`,`request.time < timestamp(data.expiresAt)`,`newData.status == 'accepted'`,`newData.claimedByAuthUserId == auth.id`,`newData.claimRevision == data.claimRevision + 1`,`math.abs((request.time - timestamp(newData.acceptedAt)).getMinutes()) <= 1`,Ce),M(`actions.data == 'update'`,`actions.linkedData == 'update'`,`auth.id != null`,`auth.email != null`,`data.id == auth.id`,`data.email == auth.email`,`linkedData.email == auth.email`,`linkedData.revokedAt == null`,`linkedData.status == 'accepted'`,`linkedData.claimedByAuthUserId == auth.id`,`request.time < timestamp(linkedData.expiresAt)`,`math.abs((request.time - timestamp(linkedData.acceptedAt)).getMinutes()) <= 1`,`linkedData.projectId in linkedData.ref('project.id')`,`linkedData.reviewerId in linkedData.ref('reviewer.id')`,`linkedData.projectId in linkedData.ref('reviewer.project.id')`,`auth.id in linkedData.ref('reviewer.$user.id')`,`auth.email in linkedData.ref('reviewer.email')`),M(`auth.id != null`,`auth.email != null`,`linkedData.id == auth.id`,`linkedData.email == auth.email`,`data.email == auth.email`,`data.claimedByAuthUserId == auth.id`,`auth.id in data.ref('activeUser.id')`),M(`auth.id != null`,`auth.email != null`,`data.id == auth.id`,`data.email == auth.email`,`linkedData.email == auth.email`,`linkedData.claimedByAuthUserId == auth.id`,`auth.id in linkedData.ref('activeUser.id')`),{...D},{...D},{...O},{...O},j(`data.id in auth.ref('${A}')`),{...D},{...O},{...D},{...D},{...O},{...D},{...O},j(`data.ref('project.id')[0] in auth.ref('${A}')`),{...D},{...O},{...D},{...D},{...O},{...O},{...D},{...O},{...D},{...D},{...D},{...D},{...D},{...D},{...D};function we(e){if(!e.trim())throw Error(`InstantDB app ID is required`);return r({appId:e,schema:Se,devtool:!1})}var Te=class{db;session;#e;attachScreenshot;constructor(e,t,n={}){this.db=e,this.session=t,this.#e=n.commentTransport,this.#e&&(this.attachScreenshot=(e,t,n)=>this.#e.uploadScreenshot({pageId:e,commentId:t,screenshot:n}))}async getSnapshot(e){let{data:t}=await this.db.queryOnce(Ee(e,this.session.authUserId));return Oe(e,t.comments,t.replies)}async getProjectSnapshot(e){this.#t(e);let{data:t}=await this.db.queryOnce(De(e,this.session.authUserId));return ke(e,t.comments,t.replies)}subscribe(e,t,n){return this.db.subscribeQuery(Ee(e,this.session.authUserId),r=>{if(r.error){n?.(Ie(r.error));return}if(r.data)try{t(Oe(e,r.data.comments,r.data.replies))}catch{n?.({type:`error`,code:`data-integrity`,recovery:`retry`,clearSnapshot:!0})}})}subscribeProject(e,t,n){return this.#t(e),this.db.subscribeQuery(De(e,this.session.authUserId),r=>{if(r.error){n?.(Ie(r.error));return}if(r.data)try{t(ke(e,r.data.comments,r.data.replies))}catch{n?.({type:`error`,code:`data-integrity`,recovery:`retry`,clearSnapshot:!0})}})}async mutate(e,t){switch(t.type){case`comment.upsert`:{if(t.comment.pageId!==e)throw Error(`Comment page mismatch`);let n=t.comment;if(n.authorId!==this.session.reviewerId)throw Error(`Comment author mismatch`);let r=g(n.body).trim(),i=z(n.createdAt,`Comment createdAt`);if(z(n.updatedAt,`Comment updatedAt`)<i)throw new c(`Comment updatedAt precedes createdAt`);if(n.createdAt!==n.updatedAt)throw new c(`Comment edits must go through the review service`);if(n.status!==`open`||n.resolvedAt!==void 0||n.resolvedById!==void 0)throw new c(`New comments must start open`);let a=l(n.target);if(!Pe(n.anchor,a.publicTarget.anchor))throw new c(`Comment anchor does not match its target`);if(!this.#e)throw new c(`Comment creation requires the review service transport`);await this.#e.createComment({pageId:e,commentId:n.id,body:r,target:n.target,...n.scope===void 0?{}:{scope:n.scope}});return}case`comment.delete`:throw new c(`Comment deletion must go through the review service`);case`reply.upsert`:{let e=t.reply;if(e.authorId!==this.session.reviewerId)throw Error(`Reply author mismatch`);let n=g(e.body,`Reply body`).trim(),r=z(e.createdAt,`Reply createdAt`);if(z(e.updatedAt,`Reply updatedAt`)<r)throw new c(`Reply updatedAt precedes createdAt`);if(e.createdAt!==e.updatedAt)throw new c(`Reply edits must go through the review service`);if(!this.#e)throw new c(`Reply creation requires the review service transport`);await this.#e.createReply({commentId:e.commentId,replyId:e.id,body:n});return}case`reply.delete`:throw new c(`Reply deletion must go through the review service`)}}#t(e){if(!e.trim()||e!==this.session.projectId)throw Error(`Project does not belong to the reviewer session`)}};function Ee(e,t){return{comments:{$:{where:{pageId:e},order:{createdAt:`asc`}},targetElements:{},scopeEntries:{}},replies:{$:{where:{pageId:e},order:{createdAt:`asc`}}},$users:{$:{where:{id:t}},activeReviewInvitations:{project:{}}}}}function De(e,t){return{comments:{$:{where:{"page.project.id":e},order:{createdAt:`asc`}},page:{project:{}},targetElements:{},scopeEntries:{}},replies:{$:{where:{"comment.page.project.id":e},order:{createdAt:`asc`}},comment:{page:{project:{}}}},$users:{$:{where:{id:t}},activeReviewInvitations:{project:{}}}}}function Oe(e,t,n){let r=t.map(t=>je(t,e));F(r,`comment`);let i=new Set(r.map(({id:e})=>e)),a=n.map(t=>Me(t,e));F(a,`reply`);for(let e of a)if(!i.has(e.commentId))throw new c(`Reply ${e.id} references a comment outside the page snapshot`);return{pageId:e,comments:r,replies:a}}function ke(e,t,n){let r=new Map,i=t.map(t=>{let n=L(t.pageId,`comment pageId`);Ae(t.page,n,e,`comment ${String(t.id)}`);let i=I(t.page,`comment ${String(t.id)} page`),a=je(t,n),o=`/`;try{o=new URL(a.target.pageUrl).pathname||`/`}catch{}return r.set(n,{id:n,name:typeof i.name==`string`&&i.name.trim()?i.name.trim():a.target.pageTitle.trim()||o,pathname:typeof i.pathname==`string`&&i.pathname.trim()?i.pathname.trim():o}),a});F(i,`comment`);let a=new Map(i.map(e=>[e.id,e])),o=n.map(t=>{let n=L(t.pageId,`reply pageId`),r=I(t.comment,`reply ${String(t.id)} comment`),i=L(t.commentId,`reply ${String(t.id)} commentId`);if(L(r.id,`reply ${String(t.id)} comment relation id`)!==i)throw new c(`Reply ${String(t.id)} has an inconsistent comment relation`);Ae(r.page,n,e,`reply ${String(t.id)}`);let o=Me(t,n),s=a.get(o.commentId);if(!s||s.pageId!==n)throw new c(`Reply ${o.id} references a comment outside the project snapshot`);return o});return F(o,`reply`),{projectId:e,pages:[...r.values()].sort((e,t)=>e.pathname.localeCompare(t.pathname)||e.id.localeCompare(t.id)),comments:i,replies:o}}function Ae(e,t,n,r){let i=I(e,`${r} page`);if(L(i.id,`${r} page id`)!==t)throw new c(`${r} escaped its page relation`);if(L(I(i.project,`${r} project`).id,`${r} project id`)!==n)throw new c(`${r} escaped its project scope`)}function je(e,t){let n=I(e,`comment`),r=L(n.id,`comment id`);if(L(n.pageId,`comment ${r} pageId`)!==t)throw new c(`Comment ${r} escaped its page scope`);L(n.authorAuthUserId,`comment ${r} authorAuthUserId`);let i=!(Object.hasOwn(n,`anchor`)&&Object.hasOwn(n,`target`)),a=i?u(n,n.targetElements,`comment ${r} target`):h(n.target,`comment ${r} target`),o=i?{...a.anchor}:Ne(n.anchor,`comment ${r} anchor`);if(!Pe(o,a.anchor))throw new c(`Comment ${r} has inconsistent anchors`);let s=n.status;if(s!==`open`&&s!==`resolved`)throw new c(`Comment ${r} has an invalid status`);let l=z(n.createdAt,`comment ${r} createdAt`),f=z(n.updatedAt,`comment ${r} updatedAt`);if(f<l)throw new c(`Comment ${r} updatedAt precedes createdAt`);let p=Be(n.resolvedAt,`comment ${r} resolvedAt`),m=Ve(n.resolvedById,`comment ${r} resolvedById`);if(s===`open`&&(p!==void 0||m!==void 0))throw new c(`Open comment ${r} contains resolution metadata`);if(s===`resolved`&&(p===void 0||m===void 0||p!==f))throw new c(`Resolved comment ${r} has invalid workflow metadata`);return{id:r,pageId:t,...He(n.pageNumber,`comment ${r} pageNumber`),authorId:L(n.authorId,`comment ${r} authorId`),authorName:L(n.authorName,`comment ${r} authorName`),body:g(n.body,`comment ${r} body`),anchor:o,target:a,...i?Fe(d(n.scopeEntries)):n.scope==null?{}:{scope:ee(n.scope)},status:s,workflowRevision:ze(n.workflowRevision,`comment ${r} workflowRevision`),createdAt:l,updatedAt:f,...p===void 0?{}:{resolvedAt:p},...m===void 0?{}:{resolvedById:m}}}function Me(e,t){let n=I(e,`reply`),r=L(n.id,`reply id`);if(L(n.pageId,`reply ${r} pageId`)!==t)throw new c(`Reply ${r} escaped its page scope`);L(n.authorAuthUserId,`reply ${r} authorAuthUserId`);let i=z(n.createdAt,`reply ${r} createdAt`),a=z(n.updatedAt,`reply ${r} updatedAt`);if(a<i)throw new c(`Reply ${r} updatedAt precedes createdAt`);return{id:r,commentId:L(n.commentId,`reply ${r} commentId`),authorId:L(n.authorId,`reply ${r} authorId`),authorName:L(n.authorName,`reply ${r} authorName`),body:g(n.body,`reply ${r} body`),createdAt:i,updatedAt:a}}function Ne(e,t){let n=I(e,t);if(Object.keys(n).length!==5||!Object.hasOwn(n,`selector`)||!Object.hasOwn(n,`offsetX`)||!Object.hasOwn(n,`offsetY`)||!Object.hasOwn(n,`viewportX`)||!Object.hasOwn(n,`viewportY`))throw new c(`${t} has invalid fields`);return{selector:Re(n.selector,`${t} selector`),offsetX:R(n.offsetX,`${t} offsetX`),offsetY:R(n.offsetY,`${t} offsetY`),viewportX:R(n.viewportX,`${t} viewportX`),viewportY:R(n.viewportY,`${t} viewportY`)}}function Pe(e,t){return e.selector===t.selector&&e.offsetX===t.offsetX&&e.offsetY===t.offsetY&&e.viewportX===t.viewportX&&e.viewportY===t.viewportY}function Fe(e){return e===void 0?{}:{scope:e}}function F(e,t){let n=new Set;for(let r of e){if(n.has(r.id))throw new c(`Duplicate ${t} ${r.id}`);n.add(r.id)}}function Ie(e){let t=Le(e).toLowerCase();return t.includes(`expired`)||t.includes(`token`)?{type:`access-lost`,code:`session-expired`,recovery:`reauthenticate`,clearSnapshot:!0}:t.includes(`permission`)||t.includes(`forbidden`)||t.includes(`unauthorized`)?{type:`access-lost`,code:`permission-denied`,recovery:`reauthenticate`,clearSnapshot:!0}:{type:`error`,code:`transport`,recovery:`retry`,clearSnapshot:!0}}function Le(e){return e instanceof Error?e.message:e&&typeof e==`object`&&`message`in e?String(e.message):``}function I(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw new c(`${t} is missing or invalid`);return e}function Re(e,t){if(typeof e!=`string`)throw new c(`${t} is invalid`);return e}function L(e,t){let n=Re(e,t);if(!n.trim())throw new c(`${t} is empty`);return n}function R(e,t){if(typeof e!=`number`||!Number.isFinite(e)||e<0||e>1)throw new c(`${t} is invalid`);return e}function z(e,t){if(!Number.isSafeInteger(e)||e<0||e>0xe677d21fdbff)throw new c(`${t} is invalid`);return e}function ze(e,t){if(!Number.isSafeInteger(e)||e<0)throw new c(`${t} is invalid`);return e}function Be(e,t){return e==null?void 0:z(e,t)}function Ve(e,t){return e==null?void 0:L(e,t)}function He(e,t){if(e==null)return{};let n=ze(e,t);if(n<1)throw new c(`${t} is invalid`);return{pageNumber:n}}Object.freeze({field:`createdAt`,direction:`desc`,tieBreaker:`id`,tieDirection:`desc`}),Object.freeze({comments:200,replies:1e3,sourceContexts:200});var Ue=class{db;session;roomCredential;#e=new Map;constructor(e,t,n){this.db=e,this.session=t,this.roomCredential=n}subscribe(e,t,n,r){let i=[],a=[],o=!1,s=[],c=()=>{o||n({pageId:e,peers:structuredClone(i),messages:structuredClone(a)})};if(t.cursors){let n=tt(e,t.roomId),a,l,u=this.roomCredential?.id===t.roomId?this.roomCredential:void 0,d=u??{id:t.roomId,expiresAt:2**53-1,refresh:async()=>void 0},f=t=>{let o=this.db.joinRoom(`visualReview`,t),s=o.subscribePresence({},e=>{if(e.error){r?.(rt(e.error));return}i=Object.values(e.peers).map(e=>Ge(e)).filter(e=>e!==null).sort((e,t)=>e.displayName.localeCompare(t.displayName)||e.peerId.localeCompare(t.peerId)),c()}),l=a;a=()=>{s(),o.leaveRoom()},this.#e.set(n,{pageId:e,roomId:t,publishPresence:e=>o.publishPresence(e)}),l?.()},p=()=>{if(!u||o)return;let e=Math.max(1e3,d.expiresAt-Date.now()+250);l=setTimeout(()=>{m()},e)},m=async()=>{try{let e=await d.refresh();if(o||!e)return;d={...e,refresh:d.refresh},u&&(u.id=e.id,u.expiresAt=e.expiresAt),f(e.id),p()}catch(e){if(o)return;r?.(rt(e)),o||(l=setTimeout(()=>{m()},5e3))}};f(d.id),p(),s.push(()=>{l&&clearTimeout(l),this.#e.delete(n),a?.()})}return t.chat&&s.push(this.db.subscribeQuery(We(e,this.session.authUserId),t=>{if(t.error){r?.(rt(t.error));return}if(t.data)try{a=t.data.reviewMessages.map(t=>Je(t,e)).sort(nt),c()}catch{r?.({type:`error`,code:`data-integrity`,recovery:`retry`,clearSnapshot:!0})}})),queueMicrotask(c),()=>{if(!o){o=!0;for(let e of s.reverse())try{e()}catch{}}}}publishPresence(e,t,n){let r=this.#e.get(tt(e,t));r&&r.publishPresence({reviewerId:this.session.reviewerId,displayName:this.session.displayName,color:n.color,active:n.active,pathname:qe(n.pathname),...n.cursorX===void 0?{}:{cursorX:n.cursorX},...n.cursorY===void 0?{}:{cursorY:n.cursorY},...n.viewportWidth===void 0?{}:{viewportWidth:n.viewportWidth},...n.viewportHeight===void 0?{}:{viewportHeight:n.viewportHeight},cursorChat:Ke(n.cursorChat)})}async sendMessage(e,t){throw Error(`Persisted review messages are no longer supported`)}};function We(e,t){return{reviewMessages:{$:{where:{pageId:e},order:{createdAt:`desc`},limit:200}},$users:{$:{where:{id:t}},activeReviewInvitations:{project:{}}}}}function Ge(e){let t=Ze(e.reviewerId,128),n=Ze(e.displayName,512),r=typeof e.color==`string`&&/^#[0-9a-f]{6}$/iu.test(e.color)?e.color:null;if(!t||!n||!r||typeof e.active!=`boolean`)return null;let i=Qe(e.cursorX),a=Qe(e.cursorY),o=$e(e.viewportWidth),s=$e(e.viewportHeight),c=Ke(e.cursorChat),l=qe(e.pathname);return{peerId:e.peerId,reviewerId:t,displayName:n,color:r,active:e.active,pathname:l,...i===void 0?{}:{cursorX:i},...a===void 0?{}:{cursorY:a},...o===void 0?{}:{viewportWidth:o},...s===void 0?{}:{viewportHeight:s},...c?{cursorChat:c}:{}}}function Ke(e){return typeof e==`string`?e.trim().slice(0,280):``}function qe(e){if(typeof e!=`string`)return`/`;let t=e.trim();return t.startsWith(`/`)?t.slice(0,2e3):`/`}function Je(e,t){let n=B(e.id,`Review message id`,128);if(B(e.pageId,`Review message pageId`,128)!==t)throw Error(`Review message page mismatch`);return{id:n,pageId:t,pathname:Xe(e.pathname),authorId:B(e.authorId,`Review message authorId`,128),authorName:B(e.authorName,`Review message authorName`,512),body:Ye(e.body),createdAt:et(e.createdAt,`Review message createdAt`),updatedAt:et(e.updatedAt,`Review message updatedAt`)}}function Ye(e){return B(e,`Review message body`,4e3)}function Xe(e){let t=B(e,`Review message pathname`,2e3);if(!t.startsWith(`/`))throw Error(`Review message pathname is invalid`);return t}function B(e,t,n){if(typeof e!=`string`)throw Error(`${t} is invalid`);let r=e.trim();if(!r||r.length>n)throw Error(`${t} is invalid`);return r}function Ze(e,t){if(typeof e!=`string`)return null;let n=e.trim();return n&&n.length<=t?n:null}function Qe(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function $e(e){let t=Qe(e);return t!==void 0&&t>0?t:void 0}function et(e,t){if(!Number.isSafeInteger(e)||e<0)throw Error(`${t} is invalid`);return e}function tt(e,t){return JSON.stringify([e,t])}function nt(e,t){return e.createdAt-t.createdAt||e.id.localeCompare(t.id)}function rt(e){let t=e&&typeof e==`object`&&`code`in e?String(e.code):``;if(/^INVITATION_(?:EXPIRED|NOT_FOUND|REQUIRED|REVOKED)$/u.test(t))return{type:`access-lost`,code:t===`INVITATION_EXPIRED`?`session-expired`:`membership-revoked`,recovery:`reauthenticate`,clearSnapshot:!0};let n=String(e instanceof Error||e&&typeof e==`object`&&`message`in e?e.message:e).toLowerCase();return n.includes(`expired`)||n.includes(`token`)?{type:`access-lost`,code:`session-expired`,recovery:`reauthenticate`,clearSnapshot:!0}:n.includes(`permission`)||n.includes(`forbidden`)||n.includes(`unauthorized`)?{type:`access-lost`,code:`permission-denied`,recovery:`reauthenticate`,clearSnapshot:!0}:{type:`error`,code:`transport`,recovery:`retry`,clearSnapshot:!0}}Object.freeze({field:`createdAt`,direction:`desc`,tieBreaker:`id`,tieDirection:`desc`});var V=class extends Error{code;constructor(e,t){super(t),this.code=e,this.name=`ReviewerCommentSaveError`}};function it(e,t){let n=e.replace(/\/+$/,``),r=async(e,r)=>{let i=await t();if(!i)throw new V(`AUTH_REQUIRED`,`로그인 세션이 만료되었습니다. 새로고침 후 다시 시도해 주세요.`);let a;try{a=await fetch(`${n}${e}`,{method:`POST`,headers:{authorization:`Bearer ${i}`,"content-type":`application/json`},body:JSON.stringify(r)})}catch{throw new V(`NETWORK`,`리뷰 서버에 연결하지 못했습니다. 연결을 확인하고 다시 시도해 주세요.`)}if(!a.ok)throw new V(...await ot(a))};return{createComment:({target:e,...t})=>{let{environment:n,...i}=e;return r(`/v1/comments`,{...t,target:i,...n?{environment:n}:{}})},createReply:e=>r(`/v1/replies`,e),uploadScreenshot:async({pageId:e,commentId:r,screenshot:i})=>{let a=await t();if(!a)throw new V(`AUTH_REQUIRED`,`로그인 세션이 만료되어 위치 캡처를 저장하지 못했습니다.`);let o;try{o=await fetch(`${n}/v1/comments/${encodeURIComponent(r)}/screenshot`,{method:`PUT`,headers:{authorization:`Bearer ${a}`,"content-type":i.contentType,"x-review-page-id":e,"x-review-image-width":String(i.width),"x-review-image-height":String(i.height)},body:at(i.bytes)})}catch{throw new V(`NETWORK`,`리뷰 서버에 연결하지 못해 위치 캡처를 저장하지 못했습니다.`)}if(!o.ok)throw new V(...await ot(o))}}}function at(e){let t=new Uint8Array(e.byteLength);return t.set(e),t.buffer}async function ot(e){let t=e.status>=500?`리뷰 서버가 코멘트를 저장하지 못했습니다. 잠시 후 다시 시도해 주세요.`:`코멘트를 저장하지 못했습니다.`;try{let n=await e.json();if(!n||typeof n!=`object`)return[`UNKNOWN`,t];let r=n;return[typeof r.error==`string`?r.error:`UNKNOWN`,typeof r.message==`string`&&r.message.trim()?r.message:t]}catch{return[`UNKNOWN`,t]}}var H=class extends Error{code;constructor(e,t){super(t),this.code=e,this.name=`ReviewBootstrapError`}};const U=new Map;function st(e,t={}){let n=e.trim();if(!n)throw Error(`InstantDB app ID is required`);return{async resolve(e){let r=(t.databaseFactory??we)(n),i=await dt(n,r,e.authHost,e.signal,e.styleNonce);for(;;)try{await ct(t.acceptInvitation,{refreshToken:i.refresh_token,invitationId:e.invitationId,suggestedDisplayName:wt(i.email),authHost:e.authHost,signal:e.signal,styleNonce:e.styleNonce});break}catch(t){if(!q(t,`INVITATION_EMAIL_MISMATCH`))throw t;await _t(e.authHost,e.signal,e.styleNonce),i=await ft(n,r,i,e.authHost,e.signal,e.styleNonce)}t.resolveReviewPage&&await t.resolveReviewPage({refreshToken:i.refresh_token,invitationId:e.invitationId,origin:e.location.origin,pathname:e.location.pathname,signal:e.signal});let{data:a}=await r.queryOnce({reviewers:{$:{where:{authUserId:i.id}}},reviewPages:{},invitations:{}}),o=lt(a.invitations,a.reviewers,a.reviewPages,{invitationId:e.invitationId,authUserId:i.id,email:i.email??``,location:e.location,now:Date.now()});if(!o.ok)throw new H(o.code,X(o.code));let s={authUserId:i.id,reviewerId:o.reviewer.id,projectId:o.reviewer.projectId,invitationId:e.invitationId,email:o.reviewer.email||i.email||``,displayName:o.reviewer.displayName||i.email||`Reviewer`,role:o.reviewer.role===`agency`?`agency`:`reviewer`},c=o.page.id,l=e.collaboration?.scopeId,u=(e.collaboration?.cursors===!0||e.collaboration?.chat===!0)&&t.resolveCollaborationRoom?await t.resolveCollaborationRoom({refreshToken:i.refresh_token,invitationId:e.invitationId,pageId:o.page.id,scopeId:e.collaboration.scopeId,signal:e.signal}):void 0,d=u&&t.resolveCollaborationRoom?{...u,refresh:async()=>{let n=await r.getAuth();if(!(!n?.refresh_token||l===void 0))return t.resolveCollaborationRoom?.({refreshToken:n.refresh_token,invitationId:e.invitationId,pageId:c,scopeId:l,signal:new AbortController().signal})}}:void 0,f=0;return{pageId:o.page.id,resolvePage:async n=>{let i=++f,a=()=>i!==f||n.signal.aborted,o=(e,t,n)=>({pageId:e,...n&&d?{collaborationRoomId:n.id}:{},commit:()=>{a()||(c=e,t!==void 0&&(l=t),!(!n||!d)&&(d.id=n.id,d.expiresAt=n.expiresAt))}});if(n.location.origin!==e.location.origin)throw new H(`PAGE_NOT_FOUND`,X(`PAGE_NOT_FOUND`));let{data:u}=await r.queryOnce({reviewPages:{$:{where:{projectId:s.projectId}}}});if(a())throw J();let p=Et(n.location.pathname),m=ut(u.reviewPages,s.projectId,n.location.origin,p);if(!m&&t.resolveReviewPage){let i=await r.getAuth();if(a())throw J();if(!i?.refresh_token)throw Error(`리뷰 세션이 만료되어 페이지를 등록할 수 없습니다.`);if(await t.resolveReviewPage({refreshToken:i.refresh_token,invitationId:e.invitationId,origin:n.location.origin,pathname:p,signal:n.signal}),a()||({data:u}=await r.queryOnce({reviewPages:{$:{where:{projectId:s.projectId}}}}),a()))throw J();m=ut(u.reviewPages,s.projectId,n.location.origin,p)}if(!m)throw new H(`PAGE_NOT_FOUND`,X(`PAGE_NOT_FOUND`));if(n.collaboration?.cursors!==!0&&n.collaboration?.chat!==!0||d===void 0||t.resolveCollaborationRoom===void 0||!n.collaboration)return o(m.id,n.collaboration?.scopeId);let h=await r.getAuth();if(a())throw J();if(!h?.refresh_token)throw Error(`리뷰 세션이 만료되어 실시간 협업 연결을 갱신할 수 없습니다.`);let g=await t.resolveCollaborationRoom({refreshToken:h.refresh_token,invitationId:e.invitationId,pageId:m.id,scopeId:n.collaboration.scopeId,signal:n.signal});if(a())throw J();return o(m.id,n.collaboration.scopeId,g)},session:s,repository:new Te(r,s,{...t.serviceUrl===void 0?{}:{commentTransport:it(t.serviceUrl,async()=>(await r.getAuth())?.refresh_token??null)}}),...e.collaboration?.cursors===!0||e.collaboration?.chat===!0?{collaborationRepository:new Ue(r,s,d)}:{},...(e.collaboration?.cursors===!0||e.collaboration?.chat===!0)&&d?{collaborationRoomId:d.id}:{},allowedStagingHosts:[e.location.hostname]}}}}async function ct(e,t){if(!e)return;let n={refreshToken:t.refreshToken,invitationId:t.invitationId,signal:t.signal};try{await e(n);return}catch(e){if(!q(e,`DISPLAY_NAME_REQUIRED`))throw e}let r=await gt(t.authHost,t.signal,t.suggestedDisplayName,t.styleNonce);await e({...n,displayName:r})}function lt(e,t,n,r){let i=e.find(({id:e})=>e===r.invitationId);if(!i||Dt(i.email)!==Dt(r.email))return{ok:!1,code:`INVITATION_REQUIRED`};if(i.status===`revoked`)return{ok:!1,code:`INVITATION_REVOKED`};if(i.status===`expired`||i.expiresAt<=r.now)return{ok:!1,code:`INVITATION_EXPIRED`};if(i.status!==`accepted`)return{ok:!1,code:`INVITATION_NOT_ACCEPTED`};let a=t.find(e=>e.authUserId===r.authUserId&&e.projectId===i.projectId);if(!a)return{ok:!1,code:`MEMBERSHIP_REQUIRED`};let o=Et(r.location.pathname),s=ut(n,i.projectId,r.location.origin,o);return s?{ok:!0,invitation:i,reviewer:a,page:s}:{ok:!1,code:`PAGE_NOT_FOUND`}}function ut(e,t,n,r){let i=e.filter(e=>e.projectId===t&&Et(e.pathname)===r),a=i.filter(({stagingOrigin:e})=>e===n);return(a.length>0?a:i).sort((e,t)=>(e.createdAt??2**53-1)-(t.createdAt??2**53-1)||e.id.localeCompare(t.id))[0]}async function dt(e,t,n,r,i){let a=await W(r,()=>t.getAuth());if(a)return a;let o=await pt(e,r);try{return await W(r,()=>t.getAuth())||await ht(t,n,r,i)}finally{o()}}async function ft(e,t,n,r,i,a){G(i);let o=await pt(e,i);try{let e=await W(i,()=>t.getAuth());return e&&e.id!==n.id?e:(e&&await W(i,async()=>{await t.auth.signOut()}),G(i),await ht(t,r,i,a))}finally{o()}}async function pt(e,t){G(t);let n=U.get(e);return n||(n={held:!1,waiters:[]},U.set(e,n)),n.held?new Promise((e,r)=>{let i,a=()=>{let e=n.waiters.indexOf(i);e<0||(n.waiters.splice(e,1),t.removeEventListener(`abort`,a),r(Y()))};i={signal:t,resolve:e,reject:r,abort:a},n.waiters.push(i),t.addEventListener(`abort`,a,{once:!0}),t.aborted&&a()}):(n.held=!0,mt(e,n))}function mt(e,t){let n=!1;return()=>{if(!n){for(n=!0;t.waiters.length>0;){let n=t.waiters.shift();if(n.signal.removeEventListener(`abort`,n.abort),n.signal.aborted){n.reject(Y());continue}n.resolve(mt(e,t));return}t.held=!1,U.get(e)===t&&U.delete(e)}}}async function W(e,t){G(e);let n=await t();return G(e),n}function G(e){if(e.aborted)throw Y()}function ht(e,t,n,r){try{G(n)}catch(e){return Promise.reject(e)}let i=yt(t);i.replaceChildren(bt(i,r),xt(i));let a=i.querySelector(`form`),o=i.querySelector(`h2`),s=i.querySelector(`.description`),c=a.elements.namedItem(`email`),l=a.elements.namedItem(`code`),u=i.querySelector(`.code`),d=i.querySelector(`button`),f=i.querySelector(`.error`),p=!1;return new Promise((t,r)=>{let m=!1,h=!1,g=!1,ee=()=>{n.removeEventListener(`abort`,v),i.removeEventListener(`keydown`,te),a.removeEventListener(`submit`,ne)},_=e=>{m||(m=!0,ee(),e())},v=()=>{m||(g=!0,ee(),h||_(()=>r(Y())))},te=e=>{let t=e;t.key===`Escape`?(t.preventDefault(),v()):t.key===`Tab`&&Tt(i,t)},ne=async i=>{if(i.preventDefault(),!(m||h)){h=!0,f.textContent=``,d.disabled=!0,a.setAttribute(`aria-busy`,`true`);try{if(G(n),!p){let t=c.value.trim();await W(n,async()=>{await e.auth.sendMagicCode({email:t})}),p=!0,c.readOnly=!0,u.hidden=!1,l.required=!0,o.textContent=`인증 코드`,s.textContent=`${t}로 보낸 코드를 입력하세요.`,d.textContent=`확인`,l.focus();return}await W(n,async()=>{await e.auth.signInWithMagicCode({email:c.value.trim(),code:l.value.trim()})});let r=await W(n,()=>e.getAuth());if(!r)throw Error(`인증 세션을 확인할 수 없습니다.`);_(()=>t(r))}catch(e){if(m||n.aborted||q(e,`AUTH_CANCELLED`))return;f.textContent=vt(e)}finally{h=!1,!m&&(g||n.aborted)?_(()=>r(Y())):m||(d.disabled=!1,a.removeAttribute(`aria-busy`))}}};n.addEventListener(`abort`,v,{once:!0}),i.addEventListener(`keydown`,te),a.addEventListener(`submit`,ne)})}function gt(e,t,n=``,r){if(t.aborted)return Promise.reject(Y());let i=yt(e);i.replaceChildren(bt(i,r),St(i));let a=i.querySelector(`form`),o=a.elements.namedItem(`displayName`),s=i.querySelector(`button`),c=i.querySelector(`.error`);return o.value=n.trim().slice(0,120),o.focus(),o.select(),new Promise((e,n)=>{let r=!1,l=e=>{r||(r=!0,t.removeEventListener(`abort`,u),i.removeEventListener(`keydown`,p),a.removeEventListener(`submit`,f),e())},u=()=>l(()=>n(Y())),d=()=>{let t=o.value.trim();if(!t){c.textContent=`이름을 입력해 주세요.`,o.focus();return}if(t.length>120){c.textContent=`이름은 120자 이하여야 합니다.`,o.focus();return}c.textContent=``,s.disabled=!0,a.setAttribute(`aria-busy`,`true`),l(()=>e(t))},f=e=>{e.preventDefault(),d()},p=e=>{let t=e;if(t.key===`Escape`){t.preventDefault(),u();return}if(t.key===`Tab`){Tt(i,t);return}t.key===`Enter`&&!t.isComposing&&t.target===o&&(t.preventDefault(),d())};t.addEventListener(`abort`,u,{once:!0}),i.addEventListener(`keydown`,p),a.addEventListener(`submit`,f)})}function _t(e,t,n){if(t.aborted)return Promise.reject(Y());let r=yt(e);r.replaceChildren(bt(r,n),Ct(r));let i=r.querySelector(`form`),a=r.querySelector(`button`);return a.focus(),new Promise((e,n)=>{let o=!1,s=e=>{o||(o=!0,t.removeEventListener(`abort`,c),r.removeEventListener(`keydown`,u),i.removeEventListener(`submit`,l),e())},c=()=>s(()=>n(Y())),l=t=>{t.preventDefault(),a.disabled=!0,i.setAttribute(`aria-busy`,`true`),s(e)},u=e=>{let t=e;t.key===`Escape`?(t.preventDefault(),c()):t.key===`Tab`&&Tt(r,t)};t.addEventListener(`abort`,c,{once:!0}),r.addEventListener(`keydown`,u),i.addEventListener(`submit`,l)})}function vt(e){if(e&&typeof e==`object`&&`body`in e){let t=e.body;if(t?.message)return t.message}return e instanceof Error?e.message:`로그인에 실패했습니다. 다시 시도해 주세요.`}function yt(e){return e.shadowRoot??e.attachShadow({mode:`open`})}function bt(e,t){let n=e.ownerDocument.createElement(`style`);return t&&(n.nonce=t),n.textContent=Ot,n}function xt(e){let t=e.ownerDocument,n=t.createElement(`form`);n.setAttribute(`role`,`dialog`),n.setAttribute(`aria-modal`,`true`),n.setAttribute(`aria-labelledby`,`visual-review-login-title`),n.setAttribute(`aria-describedby`,`visual-review-login-description`);let r=K(t,`p`,`01.works`,`eyebrow`),i=K(t,`h2`,`Visual Review`);i.id=`visual-review-login-title`;let a=K(t,`p`,`초대받은 이메일로 계속하세요.`,`description`);a.id=`visual-review-login-description`;let o=t.createElement(`label`);o.append(`이메일`);let s=t.createElement(`input`);s.name=`email`,s.type=`email`,s.autocomplete=`email`,s.required=!0,o.append(s);let c=t.createElement(`label`);c.className=`code`,c.hidden=!0,c.append(`인증 코드`);let l=t.createElement(`input`);l.name=`code`,l.inputMode=`numeric`,l.autocomplete=`one-time-code`,c.append(l);let u=K(t,`p`,``,`error`);u.setAttribute(`role`,`alert`);let d=K(t,`button`,`코드 받기`);return d.type=`submit`,n.append(r,i,a,o,c,u,d),n}function St(e){let t=e.ownerDocument,n=t.createElement(`form`);n.setAttribute(`role`,`dialog`),n.setAttribute(`aria-modal`,`true`),n.setAttribute(`aria-labelledby`,`visual-review-name-title`),n.setAttribute(`aria-describedby`,`visual-review-name-description`);let r=K(t,`p`,`01.works`,`eyebrow`),i=K(t,`h2`,`표시 이름`);i.id=`visual-review-name-title`;let a=K(t,`p`,`피드백에 이 이름이 표시됩니다.`,`description`);a.id=`visual-review-name-description`;let o=K(t,`label`,`이름`);o.htmlFor=`visual-review-display-name`;let s=t.createElement(`input`);s.id=`visual-review-display-name`,s.name=`displayName`,s.autocomplete=`name`,s.maxLength=120,s.required=!0;let c=K(t,`p`,``,`error`);c.setAttribute(`role`,`alert`);let l=K(t,`button`,`리뷰 시작`);return l.type=`submit`,n.append(r,i,a,o,s,c,l),n}function Ct(e){let t=e.ownerDocument,n=t.createElement(`form`);n.setAttribute(`role`,`dialog`),n.setAttribute(`aria-modal`,`true`),n.setAttribute(`aria-labelledby`,`visual-review-account-title`),n.setAttribute(`aria-describedby`,`visual-review-account-description`);let r=K(t,`p`,`01.works`,`eyebrow`),i=K(t,`h2`,`계정 확인`);i.id=`visual-review-account-title`;let a=K(t,`p`,`이 초대는 현재 로그인한 계정과 일치하지 않습니다.`,`description`);a.id=`visual-review-account-description`;let o=K(t,`button`,`다른 계정으로 계속`);return o.type=`submit`,n.append(r,i,a,o),n}function K(e,t,n,r){let i=e.createElement(t);return i.textContent=n,r&&(i.className=r),i}function wt(e){return e?.split(`@`)[0]?.trim().slice(0,120)??``}function q(e,t){return!!(e&&typeof e==`object`&&`code`in e&&e.code===t)}function J(){return new DOMException(`Aborted`,`AbortError`)}function Y(){return new H(`AUTH_CANCELLED`,`리뷰 로그인이 취소되었습니다.`)}function Tt(e,t){let n=Array.from(e.querySelectorAll(`input:not([disabled]),button:not([disabled])`)).filter(e=>!e.closest(`[hidden]`));if(n.length===0)return;let r=n[0],i=n.at(-1);t.shiftKey&&e.activeElement===r?(t.preventDefault(),i.focus()):!t.shiftKey&&e.activeElement===i&&(t.preventDefault(),r.focus())}function Et(e){return e.replace(/\/+$/,``)||`/`}function Dt(e){return e.trim().toLowerCase()}function X(e){switch(e){case`INVITATION_REQUIRED`:return`현재 계정과 일치하는 리뷰 초대를 찾을 수 없습니다.`;case`INVITATION_NOT_ACCEPTED`:return`아직 수락되지 않은 리뷰 초대입니다.`;case`INVITATION_REVOKED`:return`취소된 리뷰 초대입니다. 계속 검토하려면 담당자에게 다시 요청하세요.`;case`INVITATION_EXPIRED`:return`만료된 리뷰 초대입니다. 담당자에게 새 링크를 요청하세요.`;case`MEMBERSHIP_REQUIRED`:return`이 프로젝트의 reviewer membership이 없습니다.`;case`PAGE_NOT_FOUND`:return`이 페이지는 아직 리뷰 대상이 아닙니다. 담당자에게 문의하세요.`}}const Ot=`
|
|
2
2
|
:host{all:initial;--vr-panel:#fff;--vr-text:#161616;--vr-muted:#707070;--vr-label:#3f3f3f;--vr-control:#fff;--vr-border:#d9d9d9;--vr-action:#161616;--vr-action-text:#fff;position:fixed;inset:0;z-index:2147483646;display:grid;place-items:center;overflow:auto;padding:8px;box-sizing:border-box;background:rgba(15,15,15,.34);font-family:Inter,ui-sans-serif,system-ui,sans-serif;color:var(--vr-text)}
|
|
3
3
|
form{box-sizing:border-box;width:min(320px,calc(100vw - 16px));padding:20px;border:0;border-radius:14px;background:var(--vr-panel);box-shadow:0 18px 56px rgba(0,0,0,.18)}
|
|
4
4
|
.eyebrow{margin:0 0 10px;color:var(--vr-muted);font-size:10px;font-weight:700;letter-spacing:.09em;text-transform:uppercase}
|
package/dist/index.d.ts
CHANGED
|
@@ -276,6 +276,16 @@ export interface VisualReviewOffset {
|
|
|
276
276
|
y?: number;
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
export type VisualReviewInactiveReason =
|
|
280
|
+
| 'missing-activation'
|
|
281
|
+
| 'origin-not-allowed';
|
|
282
|
+
|
|
283
|
+
export interface VisualReviewInactiveState {
|
|
284
|
+
reason: VisualReviewInactiveReason;
|
|
285
|
+
/** The exact browser origin, including the port when one is present. */
|
|
286
|
+
origin: string;
|
|
287
|
+
}
|
|
288
|
+
|
|
279
289
|
export interface InstallVisualReviewOptions {
|
|
280
290
|
/** Override only for local development or self-hosted integration tests. */
|
|
281
291
|
serviceUrl?: string;
|
|
@@ -303,6 +313,8 @@ export interface InstallVisualReviewOptions {
|
|
|
303
313
|
/** CSP nonce for review-owned styles. Defaults to a nonce found on the host document. */
|
|
304
314
|
styleNonce?: string;
|
|
305
315
|
onError?: (error: Error) => void;
|
|
316
|
+
/** Called when the launcher can safely identify why it stayed inactive. */
|
|
317
|
+
onInactive?: (state: VisualReviewInactiveState) => void;
|
|
306
318
|
/** Called once for each successful mount owned by this installation. */
|
|
307
319
|
onReady?: (widget: HTMLElement) => void;
|
|
308
320
|
/** Optional host-router adapter for opening feedback on another page. */
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./install-
|
|
1
|
+
import{t as e}from"./install-Ca3QT7YV.js";export{e as installVisualReview};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
const e=`https://review.01.works`;function t(e){let t=new URL(e),n=t.hostname===`localhost`||t.hostname===`127.0.0.1`||t.hostname.endsWith(`.test`)||t.hostname.endsWith(`.local`);if(t.protocol!==`https:`&&!(n&&t.protocol===`http:`))throw Error(`Visual Review serviceUrl must use HTTPS outside local development`);if(t.username||t.password||t.search||t.hash)throw Error(`Visual Review serviceUrl must be a plain origin or base path`);return t.toString().replace(/\/+$/,``)}const n=()=>{let e=Promise.resolve(null);return{ready:e,refresh:()=>e,dispose(){}}},r=new Map,i=6e4,a=1e4,o=new WeakMap;function s(e={}){if(e.enabled===!1||typeof window>`u`||typeof document>`u`)return n();let r=!1,i=0,a=null,o=null,s=null,g=null,_=!1,y=null,b=null,x=t(e.serviceUrl??`https://review.01.works`),T=e.activationParam??`visual-review`,k=ie(window),M=C(window.location);if(!(A(x,T,M,k,e.runtime!==void 0)??w(E(x,M.origin)))){let t={reason:`missing-activation`,origin:M.origin};return L(e.build).mode===`development`&&c(document,t.origin),l(e.onInactive,t),n()}let F=document.baseURI,R=new WeakMap,z=new Map,B=oe(e.styleNonce,document),V=S(window.location,T),H=v(window,e=>{let t=S(e,T);if(t===V)return;let n=j(T,e.href);n&&z.set(e.origin,n),V=t,W(e)}),U=e=>{if(!(r||!g||e.target!==g)){if((e instanceof CustomEvent&&e.detail&&typeof e.detail==`object`&&`code`in e.detail?e.detail.code:void 0)===`membership-revoked`){let e=C(window.location),t=z.get(e.origin);t&&(O(x,e.origin,t),z.delete(e.origin),J(x,e.origin,k,t));return}V=S(window.location,T),q()}};return window.addEventListener(`visual-review:reauthenticate-required`,U),{ready:q(),refresh(){return r?Promise.resolve(null):(V=S(window.location,T),W(C(window.location),!0))},dispose(){r||(r=!0,i+=1,K(),g?.remove(),g=null,b=null,y?.remove(),y=null,z.clear(),H.unsubscribe(),window.removeEventListener(`visual-review:reauthenticate-required`,U))}};function W(e,t=!1){return!g||!b||b.origin!==e.origin||j(T,e.href)?q():G(g,b,e,t)}function G(t,n,r,c){let l=++i;a!==o&&a?.abort();let u=new AbortController;a=u;let f=d(e.build,r),p=(async()=>{try{let i=await P(n.resolvePage({location:r,signal:u.signal,collaboration:{cursors:e.collaboration?.cursors===!0,chat:e.collaboration?.chat===!0,scopeId:f}}),u.signal);return Q(l,u)?(i.commit?.(),t.setPage({pageId:i.pageId,collaboration:{roomId:i.collaborationRoomId,scopeId:f}},{reload:c}),t.isConnected||document.body?.append(t),t):$(l)}catch{return Q(l,u)?q():$(l)}})();return s=p,p}function K(){a?.abort(),o?.abort(),a=null,o=null}function q(){let t=++i;K(),g?.remove(),g=null,b=null,y?.remove();let n=new AbortController,r=document.createElement(`div`);r.dataset.agencyReviewRoot=``,a=n,o=n,y=r;let c=Y(t,n,r);return s=c,c.then(r=>{r&&Q(t,n)&&g===r&&e.onReady?.(r)}),c}async function Y(t,n,i){try{let e=document.body??await I(document,n.signal);if(!Q(t,n))return $(t);e.append(i);let r=await X(t,n,i);return Q(t,n)?r:(i.remove(),$(t))}catch(a){if(!Q(t,n))return i.remove(),$(t);if(m(a,`AUTH_CANCELLED`))return i.remove(),y===i&&(y=null),null;let o=R.get(i),s=o?.[3];Z(a,i);let c=ae(a,o?.[2]),d=o?.[1]??C(window.location).origin,f=m(a,`ORIGIN_NOT_ALLOWED`);if(f&&l(e.onInactive,{reason:`origin-not-allowed`,origin:d}),s!==`storage`||_||!h(a)){let{renderBootstrapError:e}=await import(`./bootstrap-error-BwIf8fUE.js`);if(!Q(t,n))return i.remove(),$(t);let o=te(a)?void 0:()=>{r||y!==i||(V=S(window.location,T),q())};e(i,f?u(d):c.message,B,o)}else i.remove(),y===i&&(y=null);return e.onError?.(c),window.dispatchEvent(new CustomEvent(`visual-review:error`,{detail:c})),null}}async function X(t,n,r){let i=C(window.location),a=A(x,T,i,k,e.runtime!==void 0),o=ne(z.get(i.origin)),s=w(E(x,i.origin)),c=a?.source===`url`?a:o??s??a;if(!c)return R.delete(r),r.remove(),y===r&&(y=null),null;let l=c.invitationId;R.set(r,[x,i.origin,l,c.source]),c.source===`url`?(J(x,i.origin,k),z.set(i.origin,l),D(x,i.origin,l),H.suppress(()=>N(T))):c.source===`handoff`&&z.set(i.origin,l),V=S(window.location,T);let u=await P((e.runtime??await f(x)).resolve({invitationId:l,location:i,signal:n.signal,authHost:r,styleNonce:B,collaboration:{cursors:e.collaboration?.cursors===!0,chat:e.collaboration?.chat===!0,scopeId:d(e.build,i)}}),n.signal);if(!Q(t,n))return null;O(x,i.origin,l),re(x,l,i,k),z.set(i.origin,l);let m=e.sourceContextResolver??await ee(e.build,F,n.signal,B);if(!Q(t,n))return null;let{mountReviewWidget:h}=await p(n.signal);return Q(t,n)?(g=h({...u,collaboration:{cursors:e.collaboration?.cursors===!0&&!!(u.collaborationRepository&&u.collaborationRoomId),chat:e.collaboration?.chat===!0&&!!u.collaborationRepository,repository:u.collaborationRepository,roomId:u.collaborationRoomId,scopeId:d(e.build,i)},developerTools:e.developerTools?.codeContextCopy===!0||e.developerTools?.reactGrab===!0?{codeContextCopy:!0}:void 0,offset:e.offset,onNavigateToFeedback:async t=>{let n=new URL(t,window.location.href);if(n.origin!==window.location.origin)throw Error(`Visual Review route navigation must stay on the staging origin`);if(e.navigateToFeedback){await e.navigateToFeedback(n.href);return}window.location.assign(n.href)},sourceContextResolver:m,styleNonce:B,position:e.position}),b=u.resolvePage?{origin:i.origin,resolvePage:e=>u.resolvePage(e)}:null,r.remove(),y===r&&(y=null),_=!0,window.dispatchEvent(new CustomEvent(`visual-review:ready`,{detail:g})),g):null}function Z(e,t){if(!h(e))return;let n=R.get(t);if(!n)return;let[r,i,a]=n;O(r,i,a),z.get(i)===a&&z.delete(i),J(r,i,k,a)}function Q(e,t){return!r&&i===e&&a===t&&!t.signal.aborted}function $(e){return!r&&i!==e?s:null}}function c(e,t){let n=o.get(e);n||(n=new Set,o.set(e,n)),!n.has(t)&&(n.add(t),console.info([`[VisualReview] Inactive: no invitation or resume marker was found.`,`Open this page using a Visual Review invitation URL.`,`Current origin: ${t}`].join(`
|
|
2
|
+
`)))}function l(e,t){if(e)try{e(t)}catch(e){console.error(`[VisualReview] onInactive callback failed.`,e)}}function u(e){return[`현재 Origin이 Visual Review 프로젝트에 등록되어 있지 않아 시작할 수 없습니다.`,``,`현재 Origin:`,e,``,`프로젝트 설정에 위 값을 그대로 추가한 다음 초대 링크를 다시 여세요.`,`프로토콜, 호스트 이름, 포트까지 정확히 일치해야 합니다.`].join(`
|
|
3
|
+
`)}function d(e,t){return JSON.stringify([L(e).buildId,t.pathname,t.search])}async function f(e){let{createHostedReviewRuntime:t}=await import(`./hosted-runtime-BpX-xGps.js`);return t({serviceUrl:e})}async function p(e){return F(import(`./src-CtuDVE7s.js`),e,a,`리뷰 위젯을 불러오는 시간이 초과되었습니다. 다시 시도해 주세요.`)}async function ee(e,t,n,r){let i=L(e),{createGeneratedSourceContextResolver:o}=await F(import(`./generated-source-context-D59o5CKS.js`),n,a,`리뷰 소스 정보를 불러오는 시간이 초과되었습니다. 다시 시도해 주세요.`);return o({build:i})}function m(e,t){return e instanceof Error&&`code`in e&&e.code===t}function h(e){let t=g(e);return typeof t==`string`&&/^INVITATION_(?:EXPIRED|NOT_FOUND|REVOKED)$/.test(t)}function te(e){return h(e)||g(e)===`UNSUPPORTED_SERVICE_VERSION`}function g(e){return e instanceof Error&&`code`in e?e.code:void 0}const _=new WeakMap;function v(e,t){let n=_.get(e);if(!n){let t=e.history,r=t.pushState,i=t.replaceState,a=new Set;n={history:t,originalPushStateDescriptor:Object.getOwnPropertyDescriptor(t,`pushState`),originalReplaceStateDescriptor:Object.getOwnPropertyDescriptor(t,`replaceState`),patchedPushState:function(t,n,i){r.call(this,t,n,i),y(e)},patchedReplaceState:function(t,n,r){i.call(this,t,n,r),y(e)},popstateListener:()=>y(e),subscribers:a,suppressionDepth:0},_.set(e,n),b(t,`pushState`,n.patchedPushState),b(t,`replaceState`,n.patchedReplaceState),e.addEventListener(`popstate`,n.popstateListener)}n.subscribers.add(t);let r=!0;return{suppress(e){n.suppressionDepth+=1;try{return e()}finally{--n.suppressionDepth}},unsubscribe(){r&&(r=!1,n.subscribers.delete(t),!(n.subscribers.size>0)&&(e.removeEventListener(`popstate`,n.popstateListener),x(n.history,`pushState`,n.patchedPushState,n.originalPushStateDescriptor),x(n.history,`replaceState`,n.patchedReplaceState,n.originalReplaceStateDescriptor),_.delete(e)))}}}function y(e){let t=_.get(e);if(!t||t.suppressionDepth>0)return;let n=C(e.location);[...t.subscribers].forEach(e=>e(n))}function b(e,t,n){Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:!0,value:n})}function x(e,t,n,r){if(Object.getOwnPropertyDescriptor(e,t)?.value===n){if(r){Object.defineProperty(e,t,r);return}delete e[t]}}function S(e,t){return`${e.origin}\n${e.pathname}\n${j(t,e.href)??``}`}function C(e){return new URL(e.href)}function ne(e){return e?{invitationId:e,source:`memory`}:null}function w(e){return e?{invitationId:e,source:`handoff`}:null}function T(e,t){return JSON.stringify([e,t])}function E(e,t,n=Date.now()){let i=T(e,t),a=r.get(i);if(a){if(a.expiresAt>n)return a.invitationId;clearTimeout(a.timeout),r.delete(i)}}function D(e,t,n,a=Date.now()){k(a);let o=T(e,t),s=r.get(o);for(s&&(clearTimeout(s.timeout),r.delete(o));r.size>=32;){let e=r.keys().next().value;if(!e)break;let t=r.get(e);t&&clearTimeout(t.timeout),r.delete(e)}let c=a+i,l=setTimeout(()=>{r.get(o)?.expiresAt===c&&r.delete(o)},i);r.set(o,{invitationId:n,expiresAt:c,timeout:l})}function O(e,t,n){let i=T(e,t),a=r.get(i);a?.invitationId===n&&(clearTimeout(a.timeout),r.delete(i))}function k(e){for(let[t,n]of r)n.expiresAt>e||(clearTimeout(n.timeout),r.delete(t))}function A(e,t,n,r,i){let a=j(t,n.href);if(a)return{invitationId:a,source:`url`};let o=q(r,Y(e,n.origin));return o?{invitationId:o,source:`storage`}:i&&X(n.hostname)?{invitationId:`local-preview`,source:`local-preview`}:null}function j(e,t){let n=new URL(t),r=M(n.hash);return(r?.get(e)??r?.get(`visual-review`)??r?.get(`agency-review`)??r?.get(`agency-review-invite`)??n.searchParams.get(e)??n.searchParams.get(`agency-review`)??n.searchParams.get(`agency-review-invite`))?.trim()||null}function M(e){let t=e.startsWith(`#`)?e.slice(1):e,n=t.startsWith(`?`)?t.slice(1):t;return n.includes(`=`)?new URLSearchParams(n):null}function N(e){let t=new URL(window.location.href),n=new Set([e,`visual-review`,`agency-review`,`agency-review-invite`]),r=!1;n.forEach(e=>{t.searchParams.has(e)&&(t.searchParams.delete(e),r=!0)});let i=M(t.hash);if(i){n.forEach(e=>{i.has(e)&&(i.delete(e),r=!0)});let e=i.toString();t.hash=e?`#${e}`:``}r&&window.history.replaceState(window.history.state,``,`${t.pathname}${t.search}${t.hash}`)}function P(e,t){return new Promise((n,r)=>{let i=()=>r(new DOMException(`Aborted`,`AbortError`));if(t.aborted){i();return}t.addEventListener(`abort`,i,{once:!0}),e.then(e=>{t.removeEventListener(`abort`,i),n(e)},e=>{t.removeEventListener(`abort`,i),r(e)})})}function F(e,t,n,r){return new Promise((i,a)=>{let o=!1,s=e=>{o||(o=!0,clearTimeout(l),t.removeEventListener(`abort`,c),e())},c=()=>{s(()=>a(new DOMException(`Aborted`,`AbortError`)))},l=setTimeout(()=>{s(()=>a(Error(r)))},n);if(t.aborted){c();return}t.addEventListener(`abort`,c,{once:!0}),e.then(e=>s(()=>i(e)),e=>s(()=>a(e)))})}function I(e,t){return e.body?Promise.resolve(e.body):t.aborted?Promise.reject(new DOMException(`Aborted`,`AbortError`)):new Promise((n,r)=>{let i=!1,a=new MutationObserver(()=>c()),o=()=>{e.removeEventListener(`DOMContentLoaded`,c),t.removeEventListener(`abort`,l),a.disconnect()},s=e=>{i||(i=!0,o(),e())},c=()=>{let t=e.body;t&&s(()=>n(t))},l=()=>{s(()=>r(new DOMException(`Aborted`,`AbortError`)))};e.addEventListener(`DOMContentLoaded`,c),t.addEventListener(`abort`,l,{once:!0}),a.observe(e,{childList:!0,subtree:!0}),c()})}function L(e){let t=document.querySelector(`meta[name="visual-review-build"]`),n=document.querySelector(`meta[name="visual-review-commit"]`),r=K(B()),i=K(V());return{buildId:G(e?.buildId)??W(t)??r??`unversioned`,gitCommit:H(e,n,i),generatedAt:e?.generatedAt,mode:e?.mode??z(R())??(X(window.location.hostname)?`development`:`production`)}}function R(){try{return process.env.VISUAL_REVIEW_PUBLIC_BUILD_MODE}catch{return}}function z(e){return e===`development`||e===`preview`||e===`production`?e:void 0}function B(){try{return process.env.VISUAL_REVIEW_PUBLIC_BUILD_ID}catch{return}}function V(){try{return process.env.VISUAL_REVIEW_PUBLIC_GIT_COMMIT}catch{return}}function H(e,t,n){return e?.gitCommit===null?null:typeof e?.gitCommit==`string`?U(e.gitCommit):U(t?.content)??U(n)}function U(e){if(typeof e!=`string`)return null;let t=e.trim().toLowerCase();return/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(t)?t:null}function W(e){return K(e?.content)}function G(e){let t=typeof e==`string`?e.trim():``;return t.length>0?t:null}function K(e){return typeof e==`string`&&e.length>0?e:null}function re(e,t,n,r){try{r?.setItem(Y(e,n.origin),t)}catch{}}function q(e,t){try{return e?.getItem(t)??null}catch{return null}}function ie(e){try{return e.localStorage}catch{return null}}function J(e,t,n,r){try{if(!n)return;let i=Y(e,t),a=n.getItem(i);if(a===null||r!==void 0&&a!==r)return;n.removeItem(i)}catch{}}function Y(e,t){return`visual-review:${e}:${t}:invitation`}function X(e){return e===`localhost`||e===`127.0.0.1`||e.endsWith(`.test`)||e.endsWith(`.local`)}function ae(e,t){let n=e instanceof Error?e.message:String(e),r=Error(Z(n,t));if(e&&typeof e==`object`){let n=`code`in e?e.code:void 0,i=`status`in e?e.status:void 0;typeof n==`string`&&Object.defineProperty(r,"code",{configurable:!0,enumerable:!0,value:Z(n,t)}),typeof i==`number`&&Number.isFinite(i)&&Object.defineProperty(r,"status",{configurable:!0,enumerable:!0,value:i})}return r}function Z(e,t){if(!t)return e;let n=new Set([t,encodeURIComponent(t)]),r=e;for(let e of n)e&&(r=r.split(e).join(`[redacted]`));return r}function oe(e,t){if(e!==void 0)return $(e);let n=t.currentScript,r=n?Q(n):void 0;if(r)return r;try{for(let e of t.querySelectorAll(`script[nonce],style[nonce]`)){let t=Q(e);if(t)return t}}catch{}}function Q(e){let t=`nonce`in e?e.nonce:void 0;return typeof t==`string`?$(t):void 0}function $(e){return e.trim()||void 0}export{e as n,t as r,s as t};
|
package/dist/react.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./install-
|
|
1
|
+
import{t as e}from"./install-Ca3QT7YV.js";import{useEffect as t,useRef as n}from"react";function r({activationParam:r,build:i,collaboration:a,developerTools:o,enabled:s,navigateToFeedback:c,offset:l,onError:u,onInactive:d,onReady:f,position:p,runtime:m,serviceUrl:h,sourceContextResolver:g,styleNonce:_}){let v=n(u),y=n(d),b=n(f),x=n(null),S=i?.buildId,C=i?.gitCommit,w=i?.generatedAt,T=i?.mode,E=o?.codeContextCopy===!0||o?.reactGrab===!0,D=a?.cursors===!0,O=a?.chat===!0;return v.current=u,y.current=d,b.current=f,t(()=>{if(s===!1)return;let t=e({activationParam:r,build:S===void 0&&C===void 0&&w===void 0&&T===void 0?void 0:{buildId:S,gitCommit:C,generatedAt:w,mode:T},collaboration:D||O?{cursors:D,chat:O}:void 0,developerTools:E?{codeContextCopy:!0}:void 0,enabled:s,navigateToFeedback:c,offset:l,onError:e=>v.current?.(e),onInactive:e=>{let t=`${e.reason}\n${e.origin}`;x.current!==t&&(x.current=t,y.current?.(e))},onReady:e=>{x.current=null,b.current?.(e)},runtime:m,position:p,serviceUrl:h,sourceContextResolver:g,styleNonce:_});return()=>t.dispose()},[r,S,T,O,D,E,s,w,C,c,l?.x,l?.y,p,m,h,g,_]),null}r.displayName=`VisualReview`;export{r as VisualReview};
|
package/package.json
CHANGED
package/dist/install-RHVUfLTU.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const e=`https://review.01.works`;function t(e){let t=new URL(e),n=t.hostname===`localhost`||t.hostname===`127.0.0.1`||t.hostname.endsWith(`.test`)||t.hostname.endsWith(`.local`);if(t.protocol!==`https:`&&!(n&&t.protocol===`http:`))throw Error(`Visual Review serviceUrl must use HTTPS outside local development`);if(t.username||t.password||t.search||t.hash)throw Error(`Visual Review serviceUrl must be a plain origin or base path`);return t.toString().replace(/\/+$/,``)}const n=()=>{let e=Promise.resolve(null);return{ready:e,refresh:()=>e,dispose(){}}},r=new Map,i=6e4,a=1e4;function o(e={}){if(e.enabled===!1||typeof window>`u`||typeof document>`u`)return n();let r=!1,i=0,a=null,o=null,m=null,h=null,_=!1,v=null,y=null,C=t(e.serviceUrl??`https://review.01.works`),D=e.activationParam??`visual-review`,A=K(window),N=x(window.location);if(!(O(C,D,N,A,e.runtime!==void 0)??S(w(C,N.origin))))return n();let P=document.baseURI,F=new WeakMap,I=new Map,L=ne(e.styleNonce,document),R=b(window.location,D),z=g(window,e=>{let t=b(e,D);if(t===R)return;let n=k(D,e.href);n&&I.set(e.origin,n),R=t,V(e)}),B=e=>{if(!(r||!h||e.target!==h)){if((e instanceof CustomEvent&&e.detail&&typeof e.detail==`object`&&`code`in e.detail?e.detail.code:void 0)===`membership-revoked`){let e=x(window.location),t=I.get(e.origin);t&&(E(C,e.origin,t),I.delete(e.origin),q(C,e.origin,A,t));return}R=b(window.location,D),G()}};return window.addEventListener(`visual-review:reauthenticate-required`,B),{ready:G(),refresh(){return r?Promise.resolve(null):(R=b(window.location,D),V(x(window.location),!0))},dispose(){r||(r=!0,i+=1,U(),h?.remove(),h=null,y=null,v?.remove(),v=null,I.clear(),z.unsubscribe(),window.removeEventListener(`visual-review:reauthenticate-required`,B))}};function V(e,t=!1){return!h||!y||y.origin!==e.origin||k(D,e.href)?G():H(h,y,e,t)}function H(t,n,r,c){let l=++i;a!==o&&a?.abort();let u=new AbortController;a=u;let d=s(e.build,r),f=(async()=>{try{let i=await M(n.resolvePage({location:r,signal:u.signal,collaboration:{cursors:e.collaboration?.cursors===!0,chat:e.collaboration?.chat===!0,scopeId:d}}),u.signal);return Q(l,u)?(i.commit?.(),t.setPage({pageId:i.pageId,collaboration:{roomId:i.collaborationRoomId,scopeId:d}},{reload:c}),t.isConnected||document.body?.append(t),t):$(l)}catch{return Q(l,u)?G():$(l)}})();return m=f,f}function U(){a?.abort(),o?.abort(),a=null,o=null}function G(){let t=++i;U(),h?.remove(),h=null,y=null,v?.remove();let n=new AbortController,r=document.createElement(`div`);r.dataset.agencyReviewRoot=``,a=n,o=n,v=r;let s=J(t,n,r);return m=s,s.then(r=>{r&&Q(t,n)&&h===r&&e.onReady?.(r)}),s}async function J(t,n,i){try{let e=document.body??await te(document,n.signal);if(!Q(t,n))return $(t);e.append(i);let r=await Y(t,n,i);return Q(t,n)?r:(i.remove(),$(t))}catch(a){if(!Q(t,n))return i.remove(),$(t);if(d(a,`AUTH_CANCELLED`))return i.remove(),v===i&&(v=null),null;let o=F.get(i)?.[3];Z(a,i);let s=X(a,F.get(i)?.[2]);if(o!==`storage`||_||!f(a)){let{renderBootstrapError:e}=await import(`./bootstrap-error-X9PqxFnS.js`);if(!Q(t,n))return i.remove(),$(t);let o=p(a)?void 0:()=>{r||v!==i||(R=b(window.location,D),G())};e(i,s.message,L,o)}else i.remove(),v===i&&(v=null);return e.onError?.(s),window.dispatchEvent(new CustomEvent(`visual-review:error`,{detail:s})),null}}async function Y(t,n,r){let i=x(window.location),a=O(C,D,i,A,e.runtime!==void 0),o=ee(I.get(i.origin)),d=S(w(C,i.origin)),f=a?.source===`url`?a:o??d??a;if(!f)return F.delete(r),r.remove(),v===r&&(v=null),null;let p=f.invitationId;F.set(r,[C,i.origin,p,f.source]),f.source===`url`?(q(C,i.origin,A),I.set(i.origin,p),T(C,i.origin,p),z.suppress(()=>j(D))):f.source===`handoff`&&I.set(i.origin,p),R=b(window.location,D);let m=await M((e.runtime??await c(C)).resolve({invitationId:p,location:i,signal:n.signal,authHost:r,styleNonce:L,collaboration:{cursors:e.collaboration?.cursors===!0,chat:e.collaboration?.chat===!0,scopeId:s(e.build,i)}}),n.signal);if(!Q(t,n))return null;E(C,i.origin,p),W(C,p,i,A),I.set(i.origin,p);let g=e.sourceContextResolver??await u(e.build,P,n.signal,L);if(!Q(t,n))return null;let{mountReviewWidget:k}=await l(n.signal);return Q(t,n)?(h=k({...m,collaboration:{cursors:e.collaboration?.cursors===!0&&!!(m.collaborationRepository&&m.collaborationRoomId),chat:e.collaboration?.chat===!0&&!!m.collaborationRepository,repository:m.collaborationRepository,roomId:m.collaborationRoomId,scopeId:s(e.build,i)},developerTools:e.developerTools?.codeContextCopy===!0||e.developerTools?.reactGrab===!0?{codeContextCopy:!0}:void 0,offset:e.offset,onNavigateToFeedback:async t=>{let n=new URL(t,window.location.href);if(n.origin!==window.location.origin)throw Error(`Visual Review route navigation must stay on the staging origin`);if(e.navigateToFeedback){await e.navigateToFeedback(n.href);return}window.location.assign(n.href)},sourceContextResolver:g,styleNonce:L,position:e.position}),y=m.resolvePage?{origin:i.origin,resolvePage:e=>m.resolvePage(e)}:null,r.remove(),v===r&&(v=null),_=!0,window.dispatchEvent(new CustomEvent(`visual-review:ready`,{detail:h})),h):null}function Z(e,t){if(!f(e))return;let n=F.get(t);if(!n)return;let[r,i,a]=n;E(r,i,a),I.get(i)===a&&I.delete(i),q(r,i,A,a)}function Q(e,t){return!r&&i===e&&a===t&&!t.signal.aborted}function $(e){return!r&&i!==e?m:null}}function s(e,t){return JSON.stringify([P(e).buildId,t.pathname,t.search])}async function c(e){let{createHostedReviewRuntime:t}=await import(`./hosted-runtime-D1xY3Jtw.js`);return t({serviceUrl:e})}async function l(e){return N(import(`./src-CtuDVE7s.js`),e,a,`리뷰 위젯을 불러오는 시간이 초과되었습니다. 다시 시도해 주세요.`)}async function u(e,t,n,r){let i=P(e),{createGeneratedSourceContextResolver:o}=await N(import(`./generated-source-context-D59o5CKS.js`),n,a,`리뷰 소스 정보를 불러오는 시간이 초과되었습니다. 다시 시도해 주세요.`);return o({build:i})}function d(e,t){return e instanceof Error&&`code`in e&&e.code===t}function f(e){let t=m(e);return typeof t==`string`&&/^INVITATION_(?:EXPIRED|NOT_FOUND|REVOKED)$/.test(t)}function p(e){return f(e)||m(e)===`UNSUPPORTED_SERVICE_VERSION`}function m(e){return e instanceof Error&&`code`in e?e.code:void 0}const h=new WeakMap;function g(e,t){let n=h.get(e);if(!n){let t=e.history,r=t.pushState,i=t.replaceState,a=new Set;n={history:t,originalPushStateDescriptor:Object.getOwnPropertyDescriptor(t,`pushState`),originalReplaceStateDescriptor:Object.getOwnPropertyDescriptor(t,`replaceState`),patchedPushState:function(t,n,i){r.call(this,t,n,i),_(e)},patchedReplaceState:function(t,n,r){i.call(this,t,n,r),_(e)},popstateListener:()=>_(e),subscribers:a,suppressionDepth:0},h.set(e,n),v(t,`pushState`,n.patchedPushState),v(t,`replaceState`,n.patchedReplaceState),e.addEventListener(`popstate`,n.popstateListener)}n.subscribers.add(t);let r=!0;return{suppress(e){n.suppressionDepth+=1;try{return e()}finally{--n.suppressionDepth}},unsubscribe(){r&&(r=!1,n.subscribers.delete(t),!(n.subscribers.size>0)&&(e.removeEventListener(`popstate`,n.popstateListener),y(n.history,`pushState`,n.patchedPushState,n.originalPushStateDescriptor),y(n.history,`replaceState`,n.patchedReplaceState,n.originalReplaceStateDescriptor),h.delete(e)))}}}function _(e){let t=h.get(e);if(!t||t.suppressionDepth>0)return;let n=x(e.location);[...t.subscribers].forEach(e=>e(n))}function v(e,t,n){Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:!0,value:n})}function y(e,t,n,r){if(Object.getOwnPropertyDescriptor(e,t)?.value===n){if(r){Object.defineProperty(e,t,r);return}delete e[t]}}function b(e,t){return`${e.origin}\n${e.pathname}\n${k(t,e.href)??``}`}function x(e){return new URL(e.href)}function ee(e){return e?{invitationId:e,source:`memory`}:null}function S(e){return e?{invitationId:e,source:`handoff`}:null}function C(e,t){return JSON.stringify([e,t])}function w(e,t,n=Date.now()){let i=C(e,t),a=r.get(i);if(a){if(a.expiresAt>n)return a.invitationId;clearTimeout(a.timeout),r.delete(i)}}function T(e,t,n,a=Date.now()){D(a);let o=C(e,t),s=r.get(o);for(s&&(clearTimeout(s.timeout),r.delete(o));r.size>=32;){let e=r.keys().next().value;if(!e)break;let t=r.get(e);t&&clearTimeout(t.timeout),r.delete(e)}let c=a+i,l=setTimeout(()=>{r.get(o)?.expiresAt===c&&r.delete(o)},i);r.set(o,{invitationId:n,expiresAt:c,timeout:l})}function E(e,t,n){let i=C(e,t),a=r.get(i);a?.invitationId===n&&(clearTimeout(a.timeout),r.delete(i))}function D(e){for(let[t,n]of r)n.expiresAt>e||(clearTimeout(n.timeout),r.delete(t))}function O(e,t,n,r,i){let a=k(t,n.href);if(a)return{invitationId:a,source:`url`};let o=G(r,J(e,n.origin));return o?{invitationId:o,source:`storage`}:i&&Y(n.hostname)?{invitationId:`local-preview`,source:`local-preview`}:null}function k(e,t){let n=new URL(t),r=A(n.hash);return(r?.get(e)??r?.get(`visual-review`)??r?.get(`agency-review`)??r?.get(`agency-review-invite`)??n.searchParams.get(e)??n.searchParams.get(`agency-review`)??n.searchParams.get(`agency-review-invite`))?.trim()||null}function A(e){let t=e.startsWith(`#`)?e.slice(1):e,n=t.startsWith(`?`)?t.slice(1):t;return n.includes(`=`)?new URLSearchParams(n):null}function j(e){let t=new URL(window.location.href),n=new Set([e,`visual-review`,`agency-review`,`agency-review-invite`]),r=!1;n.forEach(e=>{t.searchParams.has(e)&&(t.searchParams.delete(e),r=!0)});let i=A(t.hash);if(i){n.forEach(e=>{i.has(e)&&(i.delete(e),r=!0)});let e=i.toString();t.hash=e?`#${e}`:``}r&&window.history.replaceState(window.history.state,``,`${t.pathname}${t.search}${t.hash}`)}function M(e,t){return new Promise((n,r)=>{let i=()=>r(new DOMException(`Aborted`,`AbortError`));if(t.aborted){i();return}t.addEventListener(`abort`,i,{once:!0}),e.then(e=>{t.removeEventListener(`abort`,i),n(e)},e=>{t.removeEventListener(`abort`,i),r(e)})})}function N(e,t,n,r){return new Promise((i,a)=>{let o=!1,s=e=>{o||(o=!0,clearTimeout(l),t.removeEventListener(`abort`,c),e())},c=()=>{s(()=>a(new DOMException(`Aborted`,`AbortError`)))},l=setTimeout(()=>{s(()=>a(Error(r)))},n);if(t.aborted){c();return}t.addEventListener(`abort`,c,{once:!0}),e.then(e=>s(()=>i(e)),e=>s(()=>a(e)))})}function te(e,t){return e.body?Promise.resolve(e.body):t.aborted?Promise.reject(new DOMException(`Aborted`,`AbortError`)):new Promise((n,r)=>{let i=!1,a=new MutationObserver(()=>c()),o=()=>{e.removeEventListener(`DOMContentLoaded`,c),t.removeEventListener(`abort`,l),a.disconnect()},s=e=>{i||(i=!0,o(),e())},c=()=>{let t=e.body;t&&s(()=>n(t))},l=()=>{s(()=>r(new DOMException(`Aborted`,`AbortError`)))};e.addEventListener(`DOMContentLoaded`,c),t.addEventListener(`abort`,l,{once:!0}),a.observe(e,{childList:!0,subtree:!0}),c()})}function P(e){let t=document.querySelector(`meta[name="visual-review-build"]`),n=document.querySelector(`meta[name="visual-review-commit"]`),r=U(L()),i=U(R());return{buildId:H(e?.buildId)??V(t)??r??`unversioned`,gitCommit:z(e,n,i),generatedAt:e?.generatedAt,mode:e?.mode??I(F())??(Y(window.location.hostname)?`development`:`production`)}}function F(){try{return process.env.VISUAL_REVIEW_PUBLIC_BUILD_MODE}catch{return}}function I(e){return e===`development`||e===`preview`||e===`production`?e:void 0}function L(){try{return process.env.VISUAL_REVIEW_PUBLIC_BUILD_ID}catch{return}}function R(){try{return process.env.VISUAL_REVIEW_PUBLIC_GIT_COMMIT}catch{return}}function z(e,t,n){return e?.gitCommit===null?null:typeof e?.gitCommit==`string`?B(e.gitCommit):B(t?.content)??B(n)}function B(e){if(typeof e!=`string`)return null;let t=e.trim().toLowerCase();return/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(t)?t:null}function V(e){return U(e?.content)}function H(e){let t=typeof e==`string`?e.trim():``;return t.length>0?t:null}function U(e){return typeof e==`string`&&e.length>0?e:null}function W(e,t,n,r){try{r?.setItem(J(e,n.origin),t)}catch{}}function G(e,t){try{return e?.getItem(t)??null}catch{return null}}function K(e){try{return e.localStorage}catch{return null}}function q(e,t,n,r){try{if(!n)return;let i=J(e,t),a=n.getItem(i);if(a===null||r!==void 0&&a!==r)return;n.removeItem(i)}catch{}}function J(e,t){return`visual-review:${e}:${t}:invitation`}function Y(e){return e===`localhost`||e===`127.0.0.1`||e.endsWith(`.test`)||e.endsWith(`.local`)}function X(e,t){let n=e instanceof Error?e.message:String(e),r=Error(Z(n,t));if(e&&typeof e==`object`){let n=`code`in e?e.code:void 0,i=`status`in e?e.status:void 0;typeof n==`string`&&Object.defineProperty(r,"code",{configurable:!0,enumerable:!0,value:Z(n,t)}),typeof i==`number`&&Number.isFinite(i)&&Object.defineProperty(r,"status",{configurable:!0,enumerable:!0,value:i})}return r}function Z(e,t){if(!t)return e;let n=new Set([t,encodeURIComponent(t)]),r=e;for(let e of n)e&&(r=r.split(e).join(`[redacted]`));return r}function ne(e,t){if(e!==void 0)return $(e);let n=t.currentScript,r=n?Q(n):void 0;if(r)return r;try{for(let e of t.querySelectorAll(`script[nonce],style[nonce]`)){let t=Q(e);if(t)return t}}catch{}}function Q(e){let t=`nonce`in e?e.nonce:void 0;return typeof t==`string`?$(t):void 0}function $(e){return e.trim()||void 0}export{e as n,t as r,o as t};
|