@01.works/visual-review 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +10 -0
- package/LICENSES/Apache-2.0.txt +187 -0
- package/README.md +212 -0
- package/THIRD_PARTY_NOTICES.md +160 -0
- package/dist/build-identity-CgoY3-jy.js +114 -0
- package/dist/generated-frame-CkUKpj5U.js +1 -0
- package/dist/generated-source-context-9dbnOHdW.js +1 -0
- package/dist/hosted-runtime-CgyV50-M.js +13 -0
- package/dist/index.d.ts +200 -0
- package/dist/index.js +1 -0
- package/dist/install-BN5uBP-5.js +1 -0
- package/dist/next-config.d.ts +44 -0
- package/dist/next-config.js +406 -0
- package/dist/next.d.ts +1 -0
- package/dist/next.js +1 -0
- package/dist/primitives-lxsPH8SN.js +81 -0
- package/dist/react.d.ts +8 -0
- package/dist/react.js +1 -0
- package/dist/source-index-BdWeiNHZ.js +1398 -0
- package/dist/source-instrumentation-transform-BwKYKlp0.js +119 -0
- package/dist/source-loader.js +127 -0
- package/dist/src-1EIago0s.js +840 -0
- package/dist/vite.d.ts +29 -0
- package/dist/vite.js +141 -0
- package/package.json +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Copyright (c) 2026 01.works. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This package and the original 01.works Visual Review product code are
|
|
4
|
+
proprietary and are not offered under an open-source license. No permission is
|
|
5
|
+
granted to copy, modify, redistribute, sublicense, or create derivative works
|
|
6
|
+
except under a separate written agreement with 01.works.
|
|
7
|
+
|
|
8
|
+
Third-party components remain governed by their respective licenses. Their
|
|
9
|
+
copyright and license notices are provided in THIRD_PARTY_NOTICES.md and the
|
|
10
|
+
LICENSES directory.
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
|
|
5
|
+
http://www.apache.org/licenses/
|
|
6
|
+
|
|
7
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
8
|
+
|
|
9
|
+
1. Definitions.
|
|
10
|
+
|
|
11
|
+
"License" shall mean the terms and conditions for use, reproduction, and
|
|
12
|
+
distribution as defined by Sections 1 through 9 of this document.
|
|
13
|
+
|
|
14
|
+
"Licensor" shall mean the copyright owner or entity authorized by the
|
|
15
|
+
copyright owner that is granting the License.
|
|
16
|
+
|
|
17
|
+
"Legal Entity" shall mean the union of the acting entity and all other
|
|
18
|
+
entities that control, are controlled by, or are under common control with
|
|
19
|
+
that entity. For the purposes of this definition, "control" means (i) the
|
|
20
|
+
power, direct or indirect, to cause the direction or management of such
|
|
21
|
+
entity, whether by contract or otherwise, or (ii) ownership of fifty percent
|
|
22
|
+
(50%) or more of the outstanding shares, or (iii) beneficial ownership of
|
|
23
|
+
such entity.
|
|
24
|
+
|
|
25
|
+
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
|
26
|
+
permissions granted by this License.
|
|
27
|
+
|
|
28
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
29
|
+
including but not limited to software source code, documentation source, and
|
|
30
|
+
configuration files.
|
|
31
|
+
|
|
32
|
+
"Object" form shall mean any form resulting from mechanical transformation
|
|
33
|
+
or translation of a Source form, including but not limited to compiled object
|
|
34
|
+
code, generated documentation, and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or Object form,
|
|
37
|
+
made available under the License, as indicated by a copyright notice that is
|
|
38
|
+
included in or attached to the work.
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object form,
|
|
41
|
+
that is based on (or derived from) the Work and for which the editorial
|
|
42
|
+
revisions, annotations, elaborations, or other modifications represent, as a
|
|
43
|
+
whole, an original work of authorship. For the purposes of this License,
|
|
44
|
+
Derivative Works shall not include works that remain separable from, or
|
|
45
|
+
merely link (or bind by name) to the interfaces of, the Work and Derivative
|
|
46
|
+
Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including the original
|
|
49
|
+
version of the Work and any modifications or additions to that Work or
|
|
50
|
+
Derivative Works thereof, that is intentionally submitted to Licensor for
|
|
51
|
+
inclusion in the Work by the copyright owner or by an individual or Legal
|
|
52
|
+
Entity authorized to submit on behalf of the copyright owner. For the
|
|
53
|
+
purposes of this definition, "submitted" means any form of electronic,
|
|
54
|
+
verbal, or written communication sent to the Licensor or its representatives,
|
|
55
|
+
including but not limited to communication on electronic mailing lists,
|
|
56
|
+
source code control systems, and issue tracking systems that are managed by,
|
|
57
|
+
or on behalf of, the Licensor for the purpose of discussing and improving the
|
|
58
|
+
Work, but excluding communication that is conspicuously marked or otherwise
|
|
59
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
60
|
+
|
|
61
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity on
|
|
62
|
+
behalf of whom a Contribution has been received by Licensor and subsequently
|
|
63
|
+
incorporated within the Work.
|
|
64
|
+
|
|
65
|
+
2. Grant of Copyright License. Subject to the terms and conditions of this
|
|
66
|
+
License, each Contributor hereby grants to You a perpetual, worldwide,
|
|
67
|
+
non-exclusive, no-charge, royalty-free, irrevocable copyright license to
|
|
68
|
+
reproduce, prepare Derivative Works of, publicly display, publicly perform,
|
|
69
|
+
sublicense, and distribute the Work and such Derivative Works in Source or
|
|
70
|
+
Object form.
|
|
71
|
+
|
|
72
|
+
3. Grant of Patent License. Subject to the terms and conditions of this
|
|
73
|
+
License, each Contributor hereby grants to You a perpetual, worldwide,
|
|
74
|
+
non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this
|
|
75
|
+
section) patent license to make, have made, use, offer to sell, sell, import,
|
|
76
|
+
and otherwise transfer the Work, where such license applies only to those
|
|
77
|
+
patent claims licensable by such Contributor that are necessarily infringed
|
|
78
|
+
by their Contribution(s) alone or by combination of their Contribution(s)
|
|
79
|
+
with the Work to which such Contribution(s) was submitted. If You institute
|
|
80
|
+
patent litigation against any entity (including a cross-claim or counterclaim
|
|
81
|
+
in a lawsuit) alleging that the Work or a Contribution incorporated within
|
|
82
|
+
the Work constitutes direct or contributory patent infringement, then any
|
|
83
|
+
patent licenses granted to You under this License for that Work shall
|
|
84
|
+
terminate as of the date such litigation is filed.
|
|
85
|
+
|
|
86
|
+
4. Redistribution. You may reproduce and distribute copies of the Work or
|
|
87
|
+
Derivative Works thereof in any medium, with or without modifications, and in
|
|
88
|
+
Source or Object form, provided that You meet the following conditions:
|
|
89
|
+
|
|
90
|
+
(a) You must give any other recipients of the Work or Derivative Works a copy
|
|
91
|
+
of this License; and
|
|
92
|
+
|
|
93
|
+
(b) You must cause any modified files to carry prominent notices stating that
|
|
94
|
+
You changed the files; and
|
|
95
|
+
|
|
96
|
+
(c) You must retain, in the Source form of any Derivative Works that You
|
|
97
|
+
distribute, all copyright, patent, trademark, and attribution notices from
|
|
98
|
+
the Source form of the Work, excluding those notices that do not pertain
|
|
99
|
+
to any part of the Derivative Works; and
|
|
100
|
+
|
|
101
|
+
(d) If the Work includes a "NOTICE" text file as part of its distribution,
|
|
102
|
+
then any Derivative Works that You distribute must include a readable copy
|
|
103
|
+
of the attribution notices contained within such NOTICE file, excluding
|
|
104
|
+
those notices that do not pertain to any part of the Derivative Works, in
|
|
105
|
+
at least one of the following places: within a NOTICE text file distributed
|
|
106
|
+
as part of the Derivative Works; within the Source form or documentation,
|
|
107
|
+
if provided along with the Derivative Works; or, within a display generated
|
|
108
|
+
by the Derivative Works, if and wherever such third-party notices normally
|
|
109
|
+
appear. The contents of the NOTICE file are for informational purposes only
|
|
110
|
+
and do not modify the License. You may add Your own attribution notices
|
|
111
|
+
within Derivative Works that You distribute, alongside or as an addendum to
|
|
112
|
+
the NOTICE text from the Work, provided that such additional attribution
|
|
113
|
+
notices cannot be construed as modifying the License.
|
|
114
|
+
|
|
115
|
+
You may add Your own copyright statement to Your modifications and may
|
|
116
|
+
provide additional or different license terms and conditions for use,
|
|
117
|
+
reproduction, or distribution of Your modifications, or for any such
|
|
118
|
+
Derivative Works as a whole, provided Your use, reproduction, and distribution
|
|
119
|
+
of the Work otherwise complies with the conditions stated in this License.
|
|
120
|
+
|
|
121
|
+
5. Submission of Contributions. Unless You explicitly state otherwise, any
|
|
122
|
+
Contribution intentionally submitted for inclusion in the Work by You to the
|
|
123
|
+
Licensor shall be under the terms and conditions of this License, without any
|
|
124
|
+
additional terms or conditions. Notwithstanding the above, nothing herein
|
|
125
|
+
shall supersede or modify the terms of any separate license agreement you may
|
|
126
|
+
have executed with Licensor regarding such Contributions.
|
|
127
|
+
|
|
128
|
+
6. Trademarks. This License does not grant permission to use the trade names,
|
|
129
|
+
trademarks, service marks, or product names of the Licensor, except as required
|
|
130
|
+
for reasonable and customary use in describing the origin of the Work and
|
|
131
|
+
reproducing the content of the NOTICE file.
|
|
132
|
+
|
|
133
|
+
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in
|
|
134
|
+
writing, Licensor provides the Work (and each Contributor provides its
|
|
135
|
+
Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
136
|
+
KIND, either express or implied, including, without limitation, any warranties
|
|
137
|
+
or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
138
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
139
|
+
appropriateness of using or redistributing the Work and assume any risks
|
|
140
|
+
associated with Your exercise of permissions under this License.
|
|
141
|
+
|
|
142
|
+
8. Limitation of Liability. In no event and under no legal theory, whether in
|
|
143
|
+
tort (including negligence), contract, or otherwise, unless required by
|
|
144
|
+
applicable law (such as deliberate and grossly negligent acts) or agreed to in
|
|
145
|
+
writing, shall any Contributor be liable to You for damages, including any
|
|
146
|
+
direct, indirect, special, incidental, or consequential damages of any
|
|
147
|
+
character arising as a result of this License or out of the use or inability
|
|
148
|
+
to use the Work (including but not limited to damages for loss of goodwill,
|
|
149
|
+
work stoppage, computer failure or malfunction, or any and all other
|
|
150
|
+
commercial damages or losses), even if such Contributor has been advised of
|
|
151
|
+
the possibility of such damages.
|
|
152
|
+
|
|
153
|
+
9. Accepting Warranty or Additional Liability. While redistributing the Work
|
|
154
|
+
or Derivative Works thereof, You may choose to offer, and charge a fee for,
|
|
155
|
+
acceptance of support, warranty, indemnity, or other liability obligations
|
|
156
|
+
and/or rights consistent with this License. However, in accepting such
|
|
157
|
+
obligations, You may act only on Your own behalf and on Your sole
|
|
158
|
+
responsibility, not on behalf of any other Contributor, and only if You agree
|
|
159
|
+
to indemnify, defend, and hold each Contributor harmless for any liability
|
|
160
|
+
incurred by, or claims asserted against, such Contributor by reason of your
|
|
161
|
+
accepting any such warranty or additional liability.
|
|
162
|
+
|
|
163
|
+
END OF TERMS AND CONDITIONS
|
|
164
|
+
|
|
165
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
166
|
+
|
|
167
|
+
To apply the Apache License to your work, attach the following boilerplate
|
|
168
|
+
notice, with the fields enclosed by brackets "[]" replaced with your own
|
|
169
|
+
identifying information. (Don't include the brackets!) The text should be
|
|
170
|
+
enclosed in the appropriate comment syntax for the file format. We also
|
|
171
|
+
recommend that a file or class name and description of purpose be included on
|
|
172
|
+
the same "printed page" as the copyright notice for easier identification
|
|
173
|
+
within third-party archives.
|
|
174
|
+
|
|
175
|
+
Copyright [yyyy] [name of copyright owner]
|
|
176
|
+
|
|
177
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
178
|
+
this file except in compliance with the License. You may obtain a copy of the
|
|
179
|
+
License at
|
|
180
|
+
|
|
181
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
182
|
+
|
|
183
|
+
Unless required by applicable law or agreed to in writing, software
|
|
184
|
+
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
185
|
+
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
186
|
+
License for the specific language governing permissions and limitations under
|
|
187
|
+
the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# @01.works/visual-review
|
|
2
|
+
|
|
3
|
+
01.works가 호스팅하는 초대 전용 staging visual feedback widget입니다. 설치한
|
|
4
|
+
project는 InstantDB App ID나 admin credential을 설정하지 않습니다.
|
|
5
|
+
|
|
6
|
+
> Release status: package metadata와 React/Vite/Next 호환성 검증은 끝났지만
|
|
7
|
+
> `@01.works/visual-review`은 아직 npm에 publish하지 않았습니다.
|
|
8
|
+
> `visual-review.01.works`도 DNS/TLS 검증 전입니다. 아래 설치 예시는 최초 release
|
|
9
|
+
> 후의 public API입니다.
|
|
10
|
+
|
|
11
|
+
Package metadata의 consumer engine 선언은 Node `>=18.18`입니다. Release CI는
|
|
12
|
+
Node `24.18.0`에서 실행합니다.
|
|
13
|
+
|
|
14
|
+
### Build adapter 의존성
|
|
15
|
+
|
|
16
|
+
`@babel/core`, `@babel/parser`, JSX/TypeScript transform plugin과 `magic-string`은
|
|
17
|
+
Vite/Next production build에서 source marker와 private-map index를 만드는 Node 전용
|
|
18
|
+
build adapter 의존성입니다. 브라우저 entry는 이 패키지들을 import하지 않으며,
|
|
19
|
+
release verifier가 dormant root의 정적 import 경계와 6 KB gzip 상한을 별도로
|
|
20
|
+
검사합니다.
|
|
21
|
+
|
|
22
|
+
manifest의 caret 범위는 지원 가능한 adapter patch 범위를 의도적으로 표현합니다.
|
|
23
|
+
실제 설치 버전은 consumer lockfile이 고정하므로 애플리케이션의 lockfile을 함께
|
|
24
|
+
커밋해야 합니다. Release 검증은 빈 consumer 프로젝트에 tarball만 설치한 뒤 이
|
|
25
|
+
범위에 맞는 resolved dependency tree와 `npm audit --omit=dev
|
|
26
|
+
--audit-level=moderate`를 검사합니다. 이 의존성이나 source-map token, InstantDB
|
|
27
|
+
credential을 browser 설정으로 전달하지 않습니다.
|
|
28
|
+
|
|
29
|
+
`@instantdb/core`는 hosted realtime/auth 경계에 필요한 직접 runtime dependency이며
|
|
30
|
+
`npm install @01.works/visual-review` 때 자동 설치됩니다. Consumer가 App ID를 넣는
|
|
31
|
+
구조가 아니라, 활성 초대의 hosted bootstrap 응답으로 public App ID를 받습니다.
|
|
32
|
+
|
|
33
|
+
## 설치
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install @01.works/visual-review
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### React / Vite
|
|
40
|
+
|
|
41
|
+
Vite config에 build identity plugin을 한 번 추가하면 CI deployment metadata 또는
|
|
42
|
+
clean Git HEAD가 widget의 source provenance에 자동으로 기록됩니다. 브라우저에
|
|
43
|
+
주입하는 build identity는 공개 build ID와 full commit SHA 두 값뿐입니다. provider deployment ID가 없는
|
|
44
|
+
same-commit rebuild에는 `git:<sha>:deploy:<public-random-variant>` 형식의 서로 다른
|
|
45
|
+
build ID를 발급합니다. 이 public variant는 private marker salt와 upload token에서
|
|
46
|
+
독립적으로 생성되므로 token 회전 시에도 현재 build identity가 바뀌지 않습니다.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// vite.config.ts
|
|
50
|
+
import { defineConfig } from 'vite';
|
|
51
|
+
import react from '@vitejs/plugin-react';
|
|
52
|
+
import { visualReview } from '@01.works/visual-review/vite';
|
|
53
|
+
|
|
54
|
+
export default defineConfig({
|
|
55
|
+
plugins: [react(), visualReview()],
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Vite와 Next.js의 production build는 upload token이 없어도 per-build HMAC opaque
|
|
60
|
+
marker와 generated-asset locator index를 기본 생성합니다. 공개 산출물에는 raw
|
|
61
|
+
repository source path/line, marker salt, upload token을 넣지 않습니다.
|
|
62
|
+
`sourceMetadata: false`를 명시한 경우에만 marker/index adapter를 끄고 공개 build
|
|
63
|
+
identity만 남깁니다. 이 설정은 private source-map upload를 활성화하거나 비활성화하지
|
|
64
|
+
않으며 upload는 아래 `sourceMaps`/token gate를 그대로 따릅니다.
|
|
65
|
+
|
|
66
|
+
CI에 project-scoped `VISUAL_REVIEW_SOURCE_MAP_TOKEN`을 설정하면 같은 plugin이
|
|
67
|
+
browser build에 hidden source map을 만들고 기본 서비스
|
|
68
|
+
`https://visual-review.01.works`로 비공개 업로드합니다. 업로드가 완료되거나 실패한
|
|
69
|
+
뒤에는 배포 `outDir`의 `.map`을 모두 제거하며, 업로드 또는 정리에 실패하면 build도
|
|
70
|
+
실패합니다. token은 Vite config의 Node process에서만 읽고 browser `define`이나
|
|
71
|
+
runtime bundle에 넣지 않습니다. `inline` source map은 활성 상태에서 거부합니다.
|
|
72
|
+
|
|
73
|
+
Vite와 Next.js adapter, private upload API, 저장소, retention 경계는 package
|
|
74
|
+
verifier에서 함께 검증합니다. 다만 01.works production backend는 전용 PostgreSQL
|
|
75
|
+
runtime role, private Blob/OIDC gate가 provision되기 전까지
|
|
76
|
+
`VISUAL_REVIEW_SOURCE_MAP_BACKEND=disabled`로 명시적으로 닫아 둡니다. 해당 capability가
|
|
77
|
+
활성화되기 전에는 production consumer에 source-map token을 설정하지 마세요.
|
|
78
|
+
|
|
79
|
+
local/self-hosted upload API를 검증할 때만 Node config에서 service origin을 바꿉니다.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
visualReview({
|
|
83
|
+
sourceMaps: {
|
|
84
|
+
serviceUrl: 'http://localhost:8787',
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`sourceMaps: false`는 CI environment에 token이 있어도 이 build의 업로드를 명시적으로
|
|
90
|
+
끕니다. `sourceMaps: true`는 업로드를 명시적으로 요구하므로 token이 없으면 fail
|
|
91
|
+
closed합니다.
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
import { VisualReview } from '@01.works/visual-review/react';
|
|
95
|
+
|
|
96
|
+
export function App() {
|
|
97
|
+
return (
|
|
98
|
+
<VisualReview
|
|
99
|
+
enabled={import.meta.env.VITE_VISUAL_REVIEW_ENABLED === 'true'}
|
|
100
|
+
build={{ mode: 'preview' }}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Next.js App Router
|
|
107
|
+
|
|
108
|
+
지원 검증 범위는 Next.js 15.5와 16입니다. `/next` entry가 client boundary를
|
|
109
|
+
포함하므로 server layout에서 import할 수 있습니다. `next.config` wrapper는
|
|
110
|
+
object와 sync/async config factory를 보존합니다. 기존 webpack/Turbopack 설정을
|
|
111
|
+
유지하면서 실제 CLI가 선택한 bundler에 opaque source marker loader를 추가하고,
|
|
112
|
+
build identity로는 같은 공개 provenance 두 값만 추가합니다.
|
|
113
|
+
Next가 config를 다시 평가하는 compiler worker에는 main build가 확정한 공개
|
|
114
|
+
`buildId`/`gitCommit`만 process-local record로 전달합니다. 이 record는 엄격히
|
|
115
|
+
검증되며 source-map token과 private marker salt를 포함하거나 산출물에 내보내지
|
|
116
|
+
않습니다.
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
// next.config.mjs
|
|
120
|
+
import { withVisualReview } from '@01.works/visual-review/next-config';
|
|
121
|
+
|
|
122
|
+
export default withVisualReview({
|
|
123
|
+
reactStrictMode: true,
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
import { VisualReview } from '@01.works/visual-review/next';
|
|
129
|
+
|
|
130
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
131
|
+
return (
|
|
132
|
+
<html lang="ko">
|
|
133
|
+
<body>
|
|
134
|
+
{children}
|
|
135
|
+
<VisualReview
|
|
136
|
+
enabled={process.env.NEXT_PUBLIC_VISUAL_REVIEW_ENABLED === 'true'}
|
|
137
|
+
build={{ mode: 'preview' }}
|
|
138
|
+
/>
|
|
139
|
+
</body>
|
|
140
|
+
</html>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Vanilla TypeScript
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
import { installVisualReview } from '@01.works/visual-review';
|
|
149
|
+
|
|
150
|
+
const review = installVisualReview({
|
|
151
|
+
enabled: import.meta.env.VITE_VISUAL_REVIEW_ENABLED === 'true',
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// History API navigation is observed automatically.
|
|
155
|
+
// 필요한 경우 await review.refresh();
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
지원되는 deployment commit 환경변수가 없으면 clean consumer Git HEAD를 사용합니다.
|
|
159
|
+
dirty worktree, Git 미설치, 유효하지 않은 SHA에서는 commit을 추측하지 않고
|
|
160
|
+
`unversioned`/`null`로 남깁니다. 명시적 release identity가 필요하면 build config에서
|
|
161
|
+
`visualReview({ buildId, gitCommit })` 또는
|
|
162
|
+
`withVisualReview(config, { buildId, gitCommit })`을 사용합니다. `gitCommit: null`은
|
|
163
|
+
자동 탐색을 명시적으로 끕니다. 명시한 `buildId`는 서로 다른 deployment output에
|
|
164
|
+
재사용하면 immutable source-map release가 fail closed하므로 배포마다 고유해야 합니다.
|
|
165
|
+
commit은 full 40/64자리 SHA만 허용합니다.
|
|
166
|
+
build adapter는 staging/production mode를 추측하지 않으므로 review deployment의
|
|
167
|
+
component에는 `build={{ mode: 'preview' }}`를 명시합니다.
|
|
168
|
+
|
|
169
|
+
## Activation
|
|
170
|
+
|
|
171
|
+
`enabled`가 생략됐거나 정확히 `true`가 아니면 DOM, storage, auth, dynamic runtime
|
|
172
|
+
import와 network bootstrap을 시작하지 않습니다. production에는 flag를 설정하지
|
|
173
|
+
말고 Preview/Staging environment에만 설정합니다.
|
|
174
|
+
|
|
175
|
+
처음에는 `?visual-review=<invitation-id>` 초대 링크로 접근합니다. hosted service가
|
|
176
|
+
정확한 origin/path와 invitation을 activation gate로 확인하고, magic-code login 뒤
|
|
177
|
+
browser가 accept endpoint에 refresh token을 보냅니다. Server는
|
|
178
|
+
`db.asUser({ token })`으로 user-scoped claim을 실행하며 완료된 뒤에만 client가
|
|
179
|
+
정확한 page를 선택해 Instant subscription과 overlay를 mount합니다. `revokedAt`,
|
|
180
|
+
expiry와 claim 시 membership/project mismatch는 fail closed합니다.
|
|
181
|
+
|
|
182
|
+
public `enabled` flag는 load gate이고 registered origin/path는 hosted
|
|
183
|
+
activation/page-selection gate입니다. 지속 InstantDB data capability는 active,
|
|
184
|
+
accepted, unexpired, non-tombstoned invitation이 선택한 project 범위입니다.
|
|
185
|
+
reviewer membership은 claim 검증과 comment/reply author identity에 사용되며,
|
|
186
|
+
접근 철회는 invitation revoke로 수행합니다. admin token은 browser로 전달되지
|
|
187
|
+
않습니다.
|
|
188
|
+
|
|
189
|
+
정식 default service는 `https://visual-review.01.works`입니다. DNS 전 repository
|
|
190
|
+
검증에서는 local service를 사용할 수 있습니다. 현재 public Vercel alias는 exact
|
|
191
|
+
`DASHBOARD_ORIGIN`과 달라 실제 owner workflow의 대체 URL이 아닙니다.
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
<VisualReview
|
|
195
|
+
enabled
|
|
196
|
+
serviceUrl="http://localhost:8787"
|
|
197
|
+
/>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`serviceUrl`은 local/self-hosted integration test용입니다. DNS/TLS 전환 뒤의
|
|
201
|
+
normal consumer는 이 override를 제거합니다.
|
|
202
|
+
|
|
203
|
+
strict CSP host는 response의 style nonce를 `styleNonce`로 전달할 수 있습니다.
|
|
204
|
+
생략하면 document의 nonce가 있는 script/style에서 감지합니다. nonce는 Visual
|
|
205
|
+
Review auth/error surface와 widget stylesheet에만 적용됩니다.
|
|
206
|
+
|
|
207
|
+
## 라이선스
|
|
208
|
+
|
|
209
|
+
01.works 제품 코드는 `UNLICENSED`, All rights reserved입니다. public registry에
|
|
210
|
+
package가 노출되더라도 허가된 계약 범위 밖의 사용권을 부여하지 않습니다.
|
|
211
|
+
포함된 Pindrop.js, React Grab, InstantDB 등 제3자 코드는 package와 함께 배포되는
|
|
212
|
+
[`THIRD_PARTY_NOTICES.md`](./THIRD_PARTY_NOTICES.md)의 각 라이선스를 따릅니다.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
The notices below apply only to the identified third-party portions. They do
|
|
4
|
+
not change the proprietary license of the original 01.works product code.
|
|
5
|
+
|
|
6
|
+
## Pindrop.js
|
|
7
|
+
|
|
8
|
+
Portions of the bundled annotation core and review widget are derived from a
|
|
9
|
+
one-time source snapshot of Pindrop.js.
|
|
10
|
+
|
|
11
|
+
- Repository: https://github.com/huangdun/pindrop.js
|
|
12
|
+
- Snapshot commit: `23d7be3cc3fcfaf29a02931b3537382a0e0f6aeb`
|
|
13
|
+
- Snapshot version: `0.1.30`
|
|
14
|
+
- Author: Dun Huang
|
|
15
|
+
- License: MIT
|
|
16
|
+
|
|
17
|
+
This product is not an upstream-compatible fork.
|
|
18
|
+
|
|
19
|
+
### MIT License
|
|
20
|
+
|
|
21
|
+
Copyright (c) 2026 Dun Huang
|
|
22
|
+
|
|
23
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
24
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
25
|
+
in the Software without restriction, including without limitation the rights
|
|
26
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
27
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
28
|
+
furnished to do so, subject to the following conditions:
|
|
29
|
+
|
|
30
|
+
The above copyright notice and this permission notice shall be included in all
|
|
31
|
+
copies or substantial portions of the Software.
|
|
32
|
+
|
|
33
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
34
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
35
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
36
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
37
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
38
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
39
|
+
SOFTWARE.
|
|
40
|
+
|
|
41
|
+
## React Grab
|
|
42
|
+
|
|
43
|
+
The bundled selection engine uses `react-grab/primitives`, and the widget UI
|
|
44
|
+
adapts interface elements from the source snapshot below.
|
|
45
|
+
|
|
46
|
+
- Repository: https://github.com/aidenybai/react-grab
|
|
47
|
+
- Version first integrated: `0.1.50`
|
|
48
|
+
- Source snapshot commit: `2a39bc29e5f8bdbd69095cf1d33d91634576cd20`
|
|
49
|
+
- License: MIT
|
|
50
|
+
|
|
51
|
+
### MIT License
|
|
52
|
+
|
|
53
|
+
Copyright (c) 2025 Aiden Bai
|
|
54
|
+
|
|
55
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
56
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
57
|
+
in the Software without restriction, including without limitation the rights
|
|
58
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
59
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
60
|
+
furnished to do so, subject to the following conditions:
|
|
61
|
+
|
|
62
|
+
The above copyright notice and this permission notice shall be included in all
|
|
63
|
+
copies or substantial portions of the Software.
|
|
64
|
+
|
|
65
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
66
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
67
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
68
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
69
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
70
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
71
|
+
SOFTWARE.
|
|
72
|
+
|
|
73
|
+
## Bippy
|
|
74
|
+
|
|
75
|
+
React Grab includes portions of Bippy.
|
|
76
|
+
|
|
77
|
+
- Repository: https://github.com/aidenybai/bippy
|
|
78
|
+
- Version bundled: `0.6.1`
|
|
79
|
+
- License: MIT
|
|
80
|
+
|
|
81
|
+
Copyright 2024 Aiden Bai
|
|
82
|
+
|
|
83
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
84
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
85
|
+
in the Software without restriction, including without limitation the rights
|
|
86
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
87
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
88
|
+
furnished to do so, subject to the following conditions:
|
|
89
|
+
|
|
90
|
+
The above copyright notice and this permission notice shall be included in all
|
|
91
|
+
copies or substantial portions of the Software.
|
|
92
|
+
|
|
93
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
94
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
95
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
96
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
97
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
98
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
99
|
+
SOFTWARE.
|
|
100
|
+
|
|
101
|
+
## InstantDB JavaScript SDK
|
|
102
|
+
|
|
103
|
+
The browser runtime bundles `@instantdb/core` and `@instantdb/version`, first
|
|
104
|
+
integrated at version `1.0.52`.
|
|
105
|
+
|
|
106
|
+
- Repository: https://github.com/instantdb/instant
|
|
107
|
+
- License: Apache License 2.0
|
|
108
|
+
- License text: `LICENSES/Apache-2.0.txt`
|
|
109
|
+
|
|
110
|
+
## Mutative
|
|
111
|
+
|
|
112
|
+
- Repository: https://github.com/unadlib/mutative
|
|
113
|
+
- Version bundled: `1.3.0`
|
|
114
|
+
- License: MIT
|
|
115
|
+
|
|
116
|
+
Copyright (c) 2022 Michael Lin
|
|
117
|
+
|
|
118
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
119
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
120
|
+
in the Software without restriction, including without limitation the rights
|
|
121
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
122
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
123
|
+
furnished to do so, subject to the following conditions:
|
|
124
|
+
|
|
125
|
+
The above copyright notice and this permission notice shall be included in all
|
|
126
|
+
copies or substantial portions of the Software.
|
|
127
|
+
|
|
128
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
129
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
130
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
131
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
132
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
133
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
134
|
+
SOFTWARE.
|
|
135
|
+
|
|
136
|
+
## UUID
|
|
137
|
+
|
|
138
|
+
- Repository: https://github.com/uuidjs/uuid
|
|
139
|
+
- Version bundled: `11.1.1`
|
|
140
|
+
- License: MIT
|
|
141
|
+
|
|
142
|
+
Copyright (c) 2010-2020 Robert Kieffer and other contributors
|
|
143
|
+
|
|
144
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
145
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
146
|
+
in the Software without restriction, including without limitation the rights
|
|
147
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
148
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
149
|
+
furnished to do so, subject to the following conditions:
|
|
150
|
+
|
|
151
|
+
The above copyright notice and this permission notice shall be included in all
|
|
152
|
+
copies or substantial portions of the Software.
|
|
153
|
+
|
|
154
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
155
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
156
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
157
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
158
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
159
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
160
|
+
SOFTWARE.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
//#region src/build-identity.ts
|
|
4
|
+
const FULL_GIT_COMMIT = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;
|
|
5
|
+
const PUBLIC_BUILD_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
6
|
+
const DEPLOYMENT_VARIANT = /^[0-9a-f]{32}$/;
|
|
7
|
+
const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
8
|
+
function resolveVisualReviewBuildIdentity(options = {}, context = {
|
|
9
|
+
cwd: process.cwd(),
|
|
10
|
+
env: process.env
|
|
11
|
+
}) {
|
|
12
|
+
const explicitCommit = resolveExplicitCommit(options);
|
|
13
|
+
const gitCommit = explicitCommit.configured ? explicitCommit.value : resolveProviderCommit(context.env) ?? resolveCleanGitHead(context.cwd, context.runGit ?? runGit);
|
|
14
|
+
return {
|
|
15
|
+
buildId: resolveBuildId(options, context.env, gitCommit, context.createDeploymentVariant ?? createDeploymentVariant),
|
|
16
|
+
gitCommit
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function resolveExplicitCommit(options) {
|
|
20
|
+
if (!hasOwn(options, "gitCommit") || options.gitCommit === void 0) return {
|
|
21
|
+
configured: false,
|
|
22
|
+
value: null
|
|
23
|
+
};
|
|
24
|
+
if (options.gitCommit === null) return {
|
|
25
|
+
configured: true,
|
|
26
|
+
value: null
|
|
27
|
+
};
|
|
28
|
+
const commit = normalizeFullCommit(options.gitCommit);
|
|
29
|
+
if (!commit) throw new TypeError("visual-review gitCommit must be a full 40 or 64 character Git SHA");
|
|
30
|
+
return {
|
|
31
|
+
configured: true,
|
|
32
|
+
value: commit
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function resolveProviderCommit(env) {
|
|
36
|
+
const candidates = [
|
|
37
|
+
env.VERCEL_GIT_COMMIT_SHA,
|
|
38
|
+
env.CF_PAGES_COMMIT_SHA,
|
|
39
|
+
env.NETLIFY === "true" ? env.COMMIT_REF : void 0,
|
|
40
|
+
env.RENDER_GIT_COMMIT,
|
|
41
|
+
env.RAILWAY_GIT_COMMIT_SHA,
|
|
42
|
+
env.GITHUB_ACTIONS === "true" ? env.GITHUB_SHA : void 0
|
|
43
|
+
];
|
|
44
|
+
for (const candidate of candidates) {
|
|
45
|
+
const commit = normalizeFullCommit(candidate);
|
|
46
|
+
if (commit) return commit;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
function resolveBuildId(options, env, gitCommit, createVariant) {
|
|
51
|
+
if (hasOwn(options, "buildId") && options.buildId !== void 0) {
|
|
52
|
+
if (!isPublicBuildId(options.buildId)) throw new TypeError("visual-review buildId must be 1-128 characters using letters, numbers, dot, underscore, colon, or hyphen");
|
|
53
|
+
return options.buildId;
|
|
54
|
+
}
|
|
55
|
+
const providerBuildId = [
|
|
56
|
+
prefixedProviderBuildId("vercel", env.VERCEL_DEPLOYMENT_ID),
|
|
57
|
+
env.NETLIFY === "true" ? prefixedProviderBuildId("netlify", env.DEPLOY_ID) : null,
|
|
58
|
+
prefixedProviderBuildId("railway", env.RAILWAY_DEPLOYMENT_ID)
|
|
59
|
+
].find((value) => value !== null);
|
|
60
|
+
if (providerBuildId) return providerBuildId;
|
|
61
|
+
return gitCommit ? gitDeploymentBuildId(gitCommit, createVariant()) : "unversioned";
|
|
62
|
+
}
|
|
63
|
+
function gitDeploymentBuildId(gitCommit, variant) {
|
|
64
|
+
if (!DEPLOYMENT_VARIANT.test(variant)) throw new Error("visual-review generated an invalid deployment build variant");
|
|
65
|
+
return `git:${gitCommit}:deploy:${variant}`;
|
|
66
|
+
}
|
|
67
|
+
function createDeploymentVariant() {
|
|
68
|
+
return randomBytes(16).toString("hex");
|
|
69
|
+
}
|
|
70
|
+
function prefixedProviderBuildId(provider, value) {
|
|
71
|
+
if (!value) return null;
|
|
72
|
+
const buildId = `${provider}:${value}`;
|
|
73
|
+
return isPublicBuildId(buildId) ? buildId : null;
|
|
74
|
+
}
|
|
75
|
+
function normalizeFullCommit(value) {
|
|
76
|
+
if (typeof value !== "string") return null;
|
|
77
|
+
const normalized = value.trim().toLowerCase();
|
|
78
|
+
return FULL_GIT_COMMIT.test(normalized) ? normalized : null;
|
|
79
|
+
}
|
|
80
|
+
function isPublicBuildId(value) {
|
|
81
|
+
return typeof value === "string" && PUBLIC_BUILD_ID.test(value);
|
|
82
|
+
}
|
|
83
|
+
function resolveCleanGitHead(cwd, runner) {
|
|
84
|
+
try {
|
|
85
|
+
if (runner([
|
|
86
|
+
"status",
|
|
87
|
+
"--porcelain=v1",
|
|
88
|
+
"--untracked-files=all"
|
|
89
|
+
], cwd).trim().length > 0) return null;
|
|
90
|
+
return normalizeFullCommit(runner([
|
|
91
|
+
"rev-parse",
|
|
92
|
+
"--verify",
|
|
93
|
+
"HEAD"
|
|
94
|
+
], cwd));
|
|
95
|
+
} catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function runGit(arguments_, cwd) {
|
|
100
|
+
return execFileSync("git", arguments_, {
|
|
101
|
+
cwd,
|
|
102
|
+
encoding: "utf8",
|
|
103
|
+
maxBuffer: 64 * 1024,
|
|
104
|
+
stdio: [
|
|
105
|
+
"ignore",
|
|
106
|
+
"pipe",
|
|
107
|
+
"ignore"
|
|
108
|
+
],
|
|
109
|
+
timeout: 2e3,
|
|
110
|
+
windowsHide: true
|
|
111
|
+
}).trim();
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
export { resolveVisualReviewBuildIdentity as t };
|