@chat-de-hp/site 0.2.4 → 0.2.5

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.
Files changed (35) hide show
  1. package/dist/annotation-middleware.d.ts +4 -0
  2. package/dist/annotation-middleware.d.ts.map +1 -0
  3. package/dist/annotation-middleware.js +20 -0
  4. package/dist/astro.d.ts.map +1 -1
  5. package/dist/astro.js +2 -0
  6. package/dist/check.d.ts +21 -0
  7. package/dist/check.d.ts.map +1 -0
  8. package/dist/check.js +576 -0
  9. package/dist/cli.js +51 -11
  10. package/dist/contracts/forms.d.ts +6 -6
  11. package/dist/emdash-annotation.d.ts +7 -0
  12. package/dist/emdash-annotation.d.ts.map +1 -0
  13. package/dist/emdash-annotation.js +37 -0
  14. package/dist/internal/annotation-context.d.ts +3 -0
  15. package/dist/internal/annotation-context.d.ts.map +1 -0
  16. package/dist/internal/annotation-context.js +14 -0
  17. package/dist/internal/annotation-integration.d.ts +3 -0
  18. package/dist/internal/annotation-integration.d.ts.map +1 -0
  19. package/dist/internal/annotation-integration.js +43 -0
  20. package/dist/runtime/annotation-capture.d.ts +2 -0
  21. package/dist/runtime/annotation-capture.d.ts.map +1 -0
  22. package/dist/runtime/annotation-capture.js +204 -0
  23. package/dist/runtime/capture-contract.d.ts +58 -0
  24. package/dist/runtime/capture-contract.d.ts.map +1 -0
  25. package/dist/runtime/capture-contract.js +105 -0
  26. package/dist/runtime/contracts.d.ts +2 -0
  27. package/dist/runtime/contracts.d.ts.map +1 -1
  28. package/dist/runtime/contracts.js +2 -1
  29. package/dist/runtime/element-extractor.d.ts +21 -0
  30. package/dist/runtime/element-extractor.d.ts.map +1 -0
  31. package/dist/runtime/element-extractor.js +258 -0
  32. package/dist/runtime/index.d.ts +1 -0
  33. package/dist/runtime/index.d.ts.map +1 -1
  34. package/dist/runtime/index.js +1 -0
  35. package/package.json +26 -1
package/dist/cli.js CHANGED
@@ -1,26 +1,40 @@
1
1
  #!/usr/bin/env bun
2
2
  import { resolve } from "node:path";
3
+ import { checkSiteConformance } from "./check.js";
3
4
  import { generateSiteFiles } from "./generator.js";
5
+ const USAGE = [
6
+ "Usage:",
7
+ " chat-de-hp generate [--check] [--root <directory>]",
8
+ " chat-de-hp check [--root <directory>]",
9
+ ].join("\n");
4
10
  const args = process.argv.slice(2);
5
11
  const command = args.shift();
6
12
  try {
7
- if (command !== "generate") {
8
- throw new Error("Usage: chat-de-hp generate [--check] [--root <directory>]");
13
+ if (command === "generate") {
14
+ await runGenerate(args);
9
15
  }
16
+ else if (command === "check") {
17
+ await runCheck(args);
18
+ }
19
+ else {
20
+ throw new Error(USAGE);
21
+ }
22
+ }
23
+ catch (error) {
24
+ console.error(error instanceof Error ? error.message : String(error));
25
+ process.exitCode = 1;
26
+ }
27
+ async function runGenerate(argv) {
10
28
  let check = false;
11
29
  let root = process.cwd();
12
- while (args.length > 0) {
13
- const argument = args.shift();
30
+ while (argv.length > 0) {
31
+ const argument = argv.shift();
14
32
  if (argument === "--check") {
15
33
  check = true;
16
34
  continue;
17
35
  }
18
36
  if (argument === "--root") {
19
- const value = args.shift();
20
- if (!value) {
21
- throw new Error("--root requires a directory.");
22
- }
23
- root = resolve(value);
37
+ root = resolve(requireValue(argv, "--root"));
24
38
  continue;
25
39
  }
26
40
  throw new Error(`Unknown argument: ${argument}`);
@@ -30,7 +44,33 @@ try {
30
44
  ? "Chat de HP generated files are current."
31
45
  : "Generated Chat de HP runtime files.");
32
46
  }
33
- catch (error) {
34
- console.error(error instanceof Error ? error.message : String(error));
47
+ async function runCheck(argv) {
48
+ let root = process.cwd();
49
+ while (argv.length > 0) {
50
+ const argument = argv.shift();
51
+ if (argument === "--root") {
52
+ root = resolve(requireValue(argv, "--root"));
53
+ continue;
54
+ }
55
+ throw new Error(`Unknown argument: ${argument}`);
56
+ }
57
+ const violations = await checkSiteConformance({ root });
58
+ if (violations.length === 0) {
59
+ return;
60
+ }
61
+ for (const violation of violations) {
62
+ console.error(formatViolation(violation));
63
+ }
64
+ console.error(`\n${violations.length} problem${violations.length === 1 ? "" : "s"}`);
35
65
  process.exitCode = 1;
36
66
  }
67
+ function formatViolation(violation) {
68
+ return `✗ ${violation.rule}: ${violation.file}:${violation.line}\n ${violation.message}`;
69
+ }
70
+ function requireValue(argv, flag) {
71
+ const value = argv.shift();
72
+ if (!value) {
73
+ throw new Error(`${flag} requires a directory.`);
74
+ }
75
+ return value;
76
+ }
@@ -4,9 +4,9 @@ export declare const siteFormFieldSchema: z.ZodObject<{
4
4
  field: z.ZodString;
5
5
  op: z.ZodEnum<{
6
6
  eq: "eq";
7
+ empty: "empty";
7
8
  neq: "neq";
8
9
  filled: "filled";
9
- empty: "empty";
10
10
  }>;
11
11
  value: z.ZodOptional<z.ZodString>;
12
12
  }, z.core.$strip>>;
@@ -28,13 +28,13 @@ export declare const siteFormFieldSchema: z.ZodObject<{
28
28
  file: "file";
29
29
  url: "url";
30
30
  date: "date";
31
+ hidden: "hidden";
31
32
  textarea: "textarea";
32
33
  tel: "tel";
33
34
  select: "select";
34
35
  radio: "radio";
35
36
  checkbox: "checkbox";
36
37
  "checkbox-group": "checkbox-group";
37
- hidden: "hidden";
38
38
  }>;
39
39
  validation: z.ZodOptional<z.ZodObject<{
40
40
  accept: z.ZodOptional<z.ZodString>;
@@ -47,8 +47,8 @@ export declare const siteFormFieldSchema: z.ZodObject<{
47
47
  patternMessage: z.ZodOptional<z.ZodString>;
48
48
  }, z.core.$strip>>;
49
49
  width: z.ZodDefault<z.ZodEnum<{
50
- half: "half";
51
50
  full: "full";
51
+ half: "half";
52
52
  }>>;
53
53
  }, z.core.$strip>;
54
54
  export declare const siteFormInputSchema: z.ZodObject<{
@@ -59,9 +59,9 @@ export declare const siteFormInputSchema: z.ZodObject<{
59
59
  field: z.ZodString;
60
60
  op: z.ZodEnum<{
61
61
  eq: "eq";
62
+ empty: "empty";
62
63
  neq: "neq";
63
64
  filled: "filled";
64
- empty: "empty";
65
65
  }>;
66
66
  value: z.ZodOptional<z.ZodString>;
67
67
  }, z.core.$strip>>;
@@ -83,13 +83,13 @@ export declare const siteFormInputSchema: z.ZodObject<{
83
83
  file: "file";
84
84
  url: "url";
85
85
  date: "date";
86
+ hidden: "hidden";
86
87
  textarea: "textarea";
87
88
  tel: "tel";
88
89
  select: "select";
89
90
  radio: "radio";
90
91
  checkbox: "checkbox";
91
92
  "checkbox-group": "checkbox-group";
92
- hidden: "hidden";
93
93
  }>;
94
94
  validation: z.ZodOptional<z.ZodObject<{
95
95
  accept: z.ZodOptional<z.ZodString>;
@@ -102,8 +102,8 @@ export declare const siteFormInputSchema: z.ZodObject<{
102
102
  patternMessage: z.ZodOptional<z.ZodString>;
103
103
  }, z.core.$strip>>;
104
104
  width: z.ZodDefault<z.ZodEnum<{
105
- half: "half";
106
105
  full: "full";
106
+ half: "half";
107
107
  }>>;
108
108
  }, z.core.$strip>>;
109
109
  title: z.ZodOptional<z.ZodString>;
@@ -0,0 +1,7 @@
1
+ import type { CollectionFilter, CollectionResult, EntryResult, InferCollectionData } from "emdash";
2
+ export * from "emdash";
3
+ export declare function getEmDashCollection<T extends string, D = InferCollectionData<T>>(type: T, filter?: CollectionFilter): Promise<CollectionResult<D>>;
4
+ export declare function getEmDashEntry<T extends string, D = InferCollectionData<T>>(type: T, id: string, options?: {
5
+ locale?: string;
6
+ }): Promise<EntryResult<D>>;
7
+ //# sourceMappingURL=emdash-annotation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emdash-annotation.d.ts","sourceRoot":"","sources":["../src/emdash-annotation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAEhB,WAAW,EACX,mBAAmB,EACpB,MAAM,QAAQ,CAAC;AAKhB,cAAc,QAAQ,CAAC;AAEvB,wBAAsB,mBAAmB,CACvC,CAAC,SAAS,MAAM,EAChB,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,EAC1B,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAUlE;AAED,wBAAsB,cAAc,CAClC,CAAC,SAAS,MAAM,EAChB,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,EAC1B,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAU7E"}
@@ -0,0 +1,37 @@
1
+ import { createEditable, getEmDashCollection as getPublishedEmDashCollection, getEmDashEntry as getPublishedEmDashEntry, } from "emdash";
2
+ import { isAnnotationMode } from "./internal/annotation-context.js";
3
+ // oxlint-disable-next-line no-barrel-file -- this compatibility module preserves the existing EmDash API while overriding only its two content queries
4
+ export * from "emdash";
5
+ export async function getEmDashCollection(type, filter) {
6
+ const result = await getPublishedEmDashCollection(type, filter);
7
+ if (!isAnnotationMode()) {
8
+ return result;
9
+ }
10
+ return {
11
+ ...result,
12
+ entries: result.entries.map((entry) => annotateEntry(type, entry)),
13
+ };
14
+ }
15
+ export async function getEmDashEntry(type, id, options) {
16
+ const result = await getPublishedEmDashEntry(type, id, options);
17
+ if (!(isAnnotationMode() && result.entry)) {
18
+ return result;
19
+ }
20
+ return {
21
+ ...result,
22
+ entry: annotateEntry(type, result.entry),
23
+ };
24
+ }
25
+ function annotateEntry(collection, entry) {
26
+ const data = entry.data && typeof entry.data === "object"
27
+ ? entry.data
28
+ : {};
29
+ const databaseId = typeof data.id === "string" && data.id ? data.id : undefined;
30
+ if (!databaseId) {
31
+ return entry;
32
+ }
33
+ return {
34
+ ...entry,
35
+ edit: createEditable(collection, databaseId),
36
+ };
37
+ }
@@ -0,0 +1,3 @@
1
+ export declare function isAnnotationMode(): boolean;
2
+ export declare function runWithAnnotationMode<T>(callback: () => T): T;
3
+ //# sourceMappingURL=annotation-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotation-context.d.ts","sourceRoot":"","sources":["../../src/internal/annotation-context.ts"],"names":[],"mappings":"AAcA,wBAAgB,gBAAgB,YAE/B;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CAE7D"}
@@ -0,0 +1,14 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ const ANNOTATION_CONTEXT_KEY = Symbol.for("chat-de-hp:annotation-only-context");
3
+ const storage = globalThis[ANNOTATION_CONTEXT_KEY] ??
4
+ (() => {
5
+ const context = new AsyncLocalStorage();
6
+ globalThis[ANNOTATION_CONTEXT_KEY] = context;
7
+ return context;
8
+ })();
9
+ export function isAnnotationMode() {
10
+ return storage.getStore() === true;
11
+ }
12
+ export function runWithAnnotationMode(callback) {
13
+ return storage.run(true, callback);
14
+ }
@@ -0,0 +1,3 @@
1
+ import type { AstroIntegration } from "astro";
2
+ export declare function createAnnotationOnlyIntegration(): AstroIntegration;
3
+ //# sourceMappingURL=annotation-integration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotation-integration.d.ts","sourceRoot":"","sources":["../../src/internal/annotation-integration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAK9C,wBAAgB,+BAA+B,IAAI,gBAAgB,CAqBlE"}
@@ -0,0 +1,43 @@
1
+ const ANNOTATION_INTEGRATION_NAME = "@chat-de-hp/site/annotation-only";
2
+ export function createAnnotationOnlyIntegration() {
3
+ return {
4
+ hooks: {
5
+ "astro:config:setup": ({ addMiddleware, injectScript, updateConfig }) => {
6
+ addMiddleware({
7
+ entrypoint: "@chat-de-hp/site/annotation-middleware",
8
+ order: "pre",
9
+ });
10
+ injectScript("page", 'import "@chat-de-hp/site/runtime/annotation-capture";');
11
+ updateConfig({
12
+ vite: {
13
+ plugins: [createEmDashAnnotationResolver()],
14
+ },
15
+ });
16
+ },
17
+ },
18
+ name: ANNOTATION_INTEGRATION_NAME,
19
+ };
20
+ }
21
+ function createEmDashAnnotationResolver() {
22
+ return {
23
+ enforce: "pre",
24
+ name: `${ANNOTATION_INTEGRATION_NAME}/emdash-resolver`,
25
+ async resolveId(source, importer) {
26
+ if (source !== "emdash" ||
27
+ !importer ||
28
+ isPlatformPackageImporter(importer)) {
29
+ return null;
30
+ }
31
+ const resolved = await this.resolve("@chat-de-hp/site/emdash", importer, {
32
+ skipSelf: true,
33
+ });
34
+ return resolved?.id ?? null;
35
+ },
36
+ };
37
+ }
38
+ function isPlatformPackageImporter(importer) {
39
+ const normalized = importer.replaceAll("\\", "/");
40
+ return (normalized.includes("/node_modules/") ||
41
+ normalized.includes("/packages/site/src/") ||
42
+ normalized.includes("/packages/site/dist/"));
43
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=annotation-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotation-capture.d.ts","sourceRoot":"","sources":["../../src/runtime/annotation-capture.ts"],"names":[],"mappings":""}
@@ -0,0 +1,204 @@
1
+ import { isExpectedSiteCaptureParentMessage, SITE_CAPTURE_BOOT_NONCE_PARAM, SITE_CAPTURE_BOOT_PAGE_HASH_PARAM, SITE_CAPTURE_BOOT_PARENT_ORIGIN_PARAM, SITE_CAPTURE_MESSAGE_TYPE, SITE_CAPTURE_PARENT_ORIGIN_COOKIE, SITE_CAPTURE_SESSION_STORAGE_KEY, } from "./capture-contract.js";
2
+ import { SITE_ANNOTATION_END_PARAM } from "./contracts.js";
3
+ import { extractElements } from "./element-extractor.js";
4
+ let captureFrozen = false;
5
+ let endSessionPromise = null;
6
+ function startAnnotationCapture() {
7
+ if (window.parent === window) {
8
+ return;
9
+ }
10
+ const session = readCaptureSession();
11
+ if (!session) {
12
+ return;
13
+ }
14
+ window.addEventListener("message", (event) => {
15
+ if (!isExpectedSiteCaptureParentMessage(event, {
16
+ nonce: session.nonce,
17
+ origin: session.parentOrigin,
18
+ source: window.parent,
19
+ })) {
20
+ return;
21
+ }
22
+ if (event.data.type === SITE_CAPTURE_MESSAGE_TYPE.end) {
23
+ void endAnnotationSession(session, true);
24
+ return;
25
+ }
26
+ if (captureFrozen) {
27
+ return;
28
+ }
29
+ try {
30
+ const root = document.body ?? document.documentElement;
31
+ const elements = extractElements(root);
32
+ freezeViewport();
33
+ captureFrozen = true;
34
+ postToParent(session, {
35
+ elements,
36
+ nonce: session.nonce,
37
+ pagePath: currentPagePath(),
38
+ type: SITE_CAPTURE_MESSAGE_TYPE.captured,
39
+ });
40
+ void endAnnotationSession(session, false);
41
+ }
42
+ catch {
43
+ postToParent(session, {
44
+ message: "画面を読み取れませんでした。",
45
+ nonce: session.nonce,
46
+ type: SITE_CAPTURE_MESSAGE_TYPE.error,
47
+ });
48
+ }
49
+ });
50
+ postToParent(session, {
51
+ nonce: session.nonce,
52
+ pagePath: currentPagePath(),
53
+ type: SITE_CAPTURE_MESSAGE_TYPE.ready,
54
+ });
55
+ }
56
+ function readCaptureSession() {
57
+ const bootstrap = readCaptureBootstrap();
58
+ if (bootstrap) {
59
+ try {
60
+ window.sessionStorage.setItem(SITE_CAPTURE_SESSION_STORAGE_KEY, JSON.stringify(bootstrap));
61
+ }
62
+ catch {
63
+ // The active page can still capture even if browser storage is blocked.
64
+ }
65
+ return bootstrap;
66
+ }
67
+ try {
68
+ return parseStoredSession(window.sessionStorage.getItem(SITE_CAPTURE_SESSION_STORAGE_KEY));
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ function readCaptureBootstrap() {
75
+ const hash = new URLSearchParams(window.location.hash.slice(1));
76
+ const nonce = hash.get(SITE_CAPTURE_BOOT_NONCE_PARAM);
77
+ const parentOrigin = normalizeOrigin(hash.get(SITE_CAPTURE_BOOT_PARENT_ORIGIN_PARAM));
78
+ if (!(nonce?.trim() &&
79
+ nonce.length <= 256 &&
80
+ parentOrigin &&
81
+ parentOrigin === readAllowedParentOrigin())) {
82
+ return null;
83
+ }
84
+ const pageHash = hash.get(SITE_CAPTURE_BOOT_PAGE_HASH_PARAM);
85
+ const nextUrl = `${window.location.pathname}${window.location.search}${pageHash ? `#${pageHash}` : ""}`;
86
+ window.history.replaceState(window.history.state, "", nextUrl);
87
+ return { nonce, parentOrigin };
88
+ }
89
+ function parseStoredSession(value) {
90
+ if (!value) {
91
+ return null;
92
+ }
93
+ try {
94
+ const parsed = JSON.parse(value);
95
+ if (!parsed || typeof parsed !== "object") {
96
+ return null;
97
+ }
98
+ const nonce = Reflect.get(parsed, "nonce");
99
+ const parentOrigin = normalizeOrigin(Reflect.get(parsed, "parentOrigin"));
100
+ return typeof nonce === "string" &&
101
+ nonce.trim() &&
102
+ nonce.length <= 256 &&
103
+ parentOrigin &&
104
+ parentOrigin === readAllowedParentOrigin()
105
+ ? { nonce, parentOrigin }
106
+ : null;
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ }
112
+ function normalizeOrigin(value) {
113
+ if (typeof value !== "string") {
114
+ return null;
115
+ }
116
+ try {
117
+ const url = new URL(value);
118
+ if ((url.protocol !== "https:" && url.protocol !== "http:") ||
119
+ url.origin !== value) {
120
+ return null;
121
+ }
122
+ return url.origin;
123
+ }
124
+ catch {
125
+ return null;
126
+ }
127
+ }
128
+ function readAllowedParentOrigin() {
129
+ for (const item of document.cookie.split(";")) {
130
+ const separator = item.indexOf("=");
131
+ if (separator < 1) {
132
+ continue;
133
+ }
134
+ if (item.slice(0, separator).trim() === SITE_CAPTURE_PARENT_ORIGIN_COOKIE) {
135
+ try {
136
+ return normalizeOrigin(decodeURIComponent(item.slice(separator + 1).trim()));
137
+ }
138
+ catch {
139
+ return null;
140
+ }
141
+ }
142
+ }
143
+ return null;
144
+ }
145
+ function currentPagePath() {
146
+ return `${window.location.pathname}${window.location.search}${window.location.hash}`;
147
+ }
148
+ function freezeViewport() {
149
+ const { body, documentElement } = document;
150
+ const scrollX = window.scrollX;
151
+ const scrollY = window.scrollY;
152
+ documentElement.style.overflow = "hidden";
153
+ documentElement.style.touchAction = "none";
154
+ body.style.position = "fixed";
155
+ body.style.top = `-${scrollY}px`;
156
+ body.style.left = `-${scrollX}px`;
157
+ body.style.width = "100%";
158
+ body.style.overflow = "hidden";
159
+ body.style.pointerEvents = "none";
160
+ body.style.touchAction = "none";
161
+ }
162
+ function endAnnotationSession(session, notifyParent) {
163
+ if (endSessionPromise) {
164
+ return endSessionPromise;
165
+ }
166
+ endSessionPromise = (async () => {
167
+ try {
168
+ window.sessionStorage.removeItem(SITE_CAPTURE_SESSION_STORAGE_KEY);
169
+ }
170
+ catch {
171
+ // The server-side cookie expiration remains authoritative.
172
+ }
173
+ const endUrl = new URL(window.location.href);
174
+ endUrl.hash = "";
175
+ endUrl.search = "";
176
+ endUrl.searchParams.set(SITE_ANNOTATION_END_PARAM, "1");
177
+ try {
178
+ await window.fetch(endUrl, {
179
+ cache: "no-store",
180
+ credentials: "same-origin",
181
+ });
182
+ }
183
+ finally {
184
+ if (notifyParent) {
185
+ postToParent(session, {
186
+ nonce: session.nonce,
187
+ type: SITE_CAPTURE_MESSAGE_TYPE.ended,
188
+ });
189
+ }
190
+ }
191
+ })();
192
+ return endSessionPromise;
193
+ }
194
+ function postToParent(session, message) {
195
+ window.parent.postMessage(message, session.parentOrigin);
196
+ }
197
+ if (document.readyState === "loading") {
198
+ document.addEventListener("DOMContentLoaded", startAnnotationCapture, {
199
+ once: true,
200
+ });
201
+ }
202
+ else {
203
+ startAnnotationCapture();
204
+ }
@@ -0,0 +1,58 @@
1
+ import type { ExtractedElement } from "./element-extractor.js";
2
+ export declare const SITE_CAPTURE_BOOT_NONCE_PARAM = "__chat_de_hp_capture";
3
+ export declare const SITE_CAPTURE_BOOT_PARENT_ORIGIN_PARAM = "__chat_de_hp_capture_parent";
4
+ export declare const SITE_CAPTURE_BOOT_PAGE_HASH_PARAM = "__chat_de_hp_capture_page_hash";
5
+ export declare const SITE_CAPTURE_PARENT_ORIGIN_COOKIE = "__Host-chat-de-hp-annotation-parent";
6
+ export declare const SITE_CAPTURE_SESSION_STORAGE_KEY = "chat-de-hp:capture-session";
7
+ export declare const SITE_CAPTURE_MESSAGE_TYPE: {
8
+ readonly capture: "chat-de-hp:capture";
9
+ readonly captured: "chat-de-hp:captured";
10
+ readonly end: "chat-de-hp:end-capture";
11
+ readonly ended: "chat-de-hp:capture-ended";
12
+ readonly error: "chat-de-hp:capture-error";
13
+ readonly ready: "chat-de-hp:capture-ready";
14
+ };
15
+ export type SiteCaptureParentMessage = {
16
+ nonce: string;
17
+ type: typeof SITE_CAPTURE_MESSAGE_TYPE.capture;
18
+ } | {
19
+ nonce: string;
20
+ type: typeof SITE_CAPTURE_MESSAGE_TYPE.end;
21
+ };
22
+ export type SiteCaptureFrameMessage = {
23
+ nonce: string;
24
+ pagePath: string;
25
+ type: typeof SITE_CAPTURE_MESSAGE_TYPE.ready;
26
+ } | {
27
+ elements: ExtractedElement[];
28
+ nonce: string;
29
+ pagePath: string;
30
+ type: typeof SITE_CAPTURE_MESSAGE_TYPE.captured;
31
+ } | {
32
+ message: string;
33
+ nonce: string;
34
+ type: typeof SITE_CAPTURE_MESSAGE_TYPE.error;
35
+ } | {
36
+ nonce: string;
37
+ type: typeof SITE_CAPTURE_MESSAGE_TYPE.ended;
38
+ };
39
+ type CaptureMessageEvent = {
40
+ data: unknown;
41
+ origin: string;
42
+ source: unknown;
43
+ };
44
+ type CaptureMessageExpectation = {
45
+ nonce: string;
46
+ origin: string;
47
+ source: unknown;
48
+ };
49
+ export declare function isExpectedSiteCaptureParentMessage(event: CaptureMessageEvent, expected: CaptureMessageExpectation): event is CaptureMessageEvent & {
50
+ data: SiteCaptureParentMessage;
51
+ };
52
+ export declare function isExpectedSiteCaptureFrameMessage(event: CaptureMessageEvent, expected: CaptureMessageExpectation): event is CaptureMessageEvent & {
53
+ data: SiteCaptureFrameMessage;
54
+ };
55
+ export declare function isSiteCaptureParentMessage(value: unknown): value is SiteCaptureParentMessage;
56
+ export declare function isSiteCaptureFrameMessage(value: unknown): value is SiteCaptureFrameMessage;
57
+ export {};
58
+ //# sourceMappingURL=capture-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-contract.d.ts","sourceRoot":"","sources":["../../src/runtime/capture-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,eAAO,MAAM,6BAA6B,yBAAyB,CAAC;AACpE,eAAO,MAAM,qCAAqC,gCACnB,CAAC;AAChC,eAAO,MAAM,iCAAiC,mCACZ,CAAC;AACnC,eAAO,MAAM,iCAAiC,wCACP,CAAC;AACxC,eAAO,MAAM,gCAAgC,+BAA+B,CAAC;AAE7E,eAAO,MAAM,yBAAyB;;;;;;;CAO5B,CAAC;AAEX,MAAM,MAAM,wBAAwB,GAChC;IACE,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,yBAAyB,CAAC,OAAO,CAAC;CAChD,GACD;IACE,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,yBAAyB,CAAC,GAAG,CAAC;CAC5C,CAAC;AAEN,MAAM,MAAM,uBAAuB,GAC/B;IACE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,yBAAyB,CAAC,KAAK,CAAC;CAC9C,GACD;IACE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,yBAAyB,CAAC,QAAQ,CAAC;CACjD,GACD;IACE,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,yBAAyB,CAAC,KAAK,CAAC;CAC9C,GACD;IACE,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,yBAAyB,CAAC,KAAK,CAAC;CAC9C,CAAC;AAEN,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,EAAE,yBAAyB,GAClC,KAAK,IAAI,mBAAmB,GAAG;IAAE,IAAI,EAAE,wBAAwB,CAAA;CAAE,CAOnE;AAED,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,EAAE,yBAAyB,GAClC,KAAK,IAAI,mBAAmB,GAAG;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,CAOlE;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,wBAAwB,CAQnC;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,uBAAuB,CAmBlC"}
@@ -0,0 +1,105 @@
1
+ export const SITE_CAPTURE_BOOT_NONCE_PARAM = "__chat_de_hp_capture";
2
+ export const SITE_CAPTURE_BOOT_PARENT_ORIGIN_PARAM = "__chat_de_hp_capture_parent";
3
+ export const SITE_CAPTURE_BOOT_PAGE_HASH_PARAM = "__chat_de_hp_capture_page_hash";
4
+ export const SITE_CAPTURE_PARENT_ORIGIN_COOKIE = "__Host-chat-de-hp-annotation-parent";
5
+ export const SITE_CAPTURE_SESSION_STORAGE_KEY = "chat-de-hp:capture-session";
6
+ export const SITE_CAPTURE_MESSAGE_TYPE = {
7
+ capture: "chat-de-hp:capture",
8
+ captured: "chat-de-hp:captured",
9
+ end: "chat-de-hp:end-capture",
10
+ ended: "chat-de-hp:capture-ended",
11
+ error: "chat-de-hp:capture-error",
12
+ ready: "chat-de-hp:capture-ready",
13
+ };
14
+ export function isExpectedSiteCaptureParentMessage(event, expected) {
15
+ return (event.origin === expected.origin &&
16
+ event.source === expected.source &&
17
+ isSiteCaptureParentMessage(event.data) &&
18
+ event.data.nonce === expected.nonce);
19
+ }
20
+ export function isExpectedSiteCaptureFrameMessage(event, expected) {
21
+ return (event.origin === expected.origin &&
22
+ event.source === expected.source &&
23
+ isSiteCaptureFrameMessage(event.data) &&
24
+ event.data.nonce === expected.nonce);
25
+ }
26
+ export function isSiteCaptureParentMessage(value) {
27
+ if (!isRecord(value) || !isNonce(value.nonce)) {
28
+ return false;
29
+ }
30
+ return (value.type === SITE_CAPTURE_MESSAGE_TYPE.capture ||
31
+ value.type === SITE_CAPTURE_MESSAGE_TYPE.end);
32
+ }
33
+ export function isSiteCaptureFrameMessage(value) {
34
+ if (!isRecord(value) || !isNonce(value.nonce)) {
35
+ return false;
36
+ }
37
+ if (value.type === SITE_CAPTURE_MESSAGE_TYPE.ready) {
38
+ return isPagePath(value.pagePath);
39
+ }
40
+ if (value.type === SITE_CAPTURE_MESSAGE_TYPE.captured) {
41
+ return (isPagePath(value.pagePath) &&
42
+ Array.isArray(value.elements) &&
43
+ value.elements.every(isExtractedElement));
44
+ }
45
+ if (value.type === SITE_CAPTURE_MESSAGE_TYPE.error) {
46
+ return isNonEmptyString(value.message);
47
+ }
48
+ return value.type === SITE_CAPTURE_MESSAGE_TYPE.ended;
49
+ }
50
+ function isExtractedElement(value) {
51
+ if (!isRecord(value) ||
52
+ !isNonEmptyString(value.elementId) ||
53
+ !isNonEmptyString(value.role) ||
54
+ !isNormalizedRect(value.bounds)) {
55
+ return false;
56
+ }
57
+ if (value.text !== undefined && typeof value.text !== "string") {
58
+ return false;
59
+ }
60
+ if (value.section !== undefined && typeof value.section !== "string") {
61
+ return false;
62
+ }
63
+ if (value.cmsRef === undefined) {
64
+ return true;
65
+ }
66
+ return (isRecord(value.cmsRef) &&
67
+ isNonEmptyString(value.cmsRef.collection) &&
68
+ isNonEmptyString(value.cmsRef.id) &&
69
+ (value.cmsRef.field === undefined || isNonEmptyString(value.cmsRef.field)));
70
+ }
71
+ function isNormalizedRect(value) {
72
+ if (!isRecord(value)) {
73
+ return false;
74
+ }
75
+ const { height, width, x, y } = value;
76
+ if (!isUnitNumber(height) ||
77
+ !isUnitNumber(width) ||
78
+ !isUnitNumber(x) ||
79
+ !isUnitNumber(y)) {
80
+ return false;
81
+ }
82
+ const tolerance = Number.EPSILON * 4;
83
+ return x + width <= 1 + tolerance && y + height <= 1 + tolerance;
84
+ }
85
+ function isUnitNumber(value) {
86
+ return (typeof value === "number" &&
87
+ Number.isFinite(value) &&
88
+ value >= 0 &&
89
+ value <= 1);
90
+ }
91
+ function isPagePath(value) {
92
+ return (typeof value === "string" &&
93
+ value.startsWith("/") &&
94
+ !value.startsWith("//") &&
95
+ !value.includes("\\"));
96
+ }
97
+ function isNonce(value) {
98
+ return isNonEmptyString(value) && value.length <= 256;
99
+ }
100
+ function isNonEmptyString(value) {
101
+ return typeof value === "string" && value.trim().length > 0;
102
+ }
103
+ function isRecord(value) {
104
+ return typeof value === "object" && value !== null;
105
+ }
@@ -1,3 +1,5 @@
1
+ export declare const CHAT_DE_HP_ANNOTATION_MODE_HEADER = "x-chat-de-hp-annotation-mode";
2
+ export declare const SITE_ANNOTATION_END_PARAM = "__chat_de_hp_annotation_end";
1
3
  export type ChatDeHpExecutionContext = {
2
4
  passThroughOnException?(): void;
3
5
  waitUntil(promise: Promise<unknown>): void;