arcy.js 0.0.2 → 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.
Files changed (47) hide show
  1. package/README.md +94 -3
  2. package/dist/arcy.chat.ab181cf5a84b.js +1258 -0
  3. package/dist/arcy.flow.fef131718e42.js +3 -0
  4. package/dist/arcy.legacy.ab4e9266b657.js +567 -0
  5. package/dist/arcy.loader.js +2 -0
  6. package/dist/arcy.modern.60faeffc62a2.js +567 -0
  7. package/dist/arcy.picker.c598a581d964.js +59 -0
  8. package/dist/design-mode.cjs +135 -0
  9. package/dist/design-mode.d.cts +197 -0
  10. package/dist/design-mode.d.ts +197 -0
  11. package/dist/design-mode.js +127 -0
  12. package/dist/fonts/dm-sans-latin-ext.woff2 +0 -0
  13. package/dist/fonts/dm-sans-latin.woff2 +0 -0
  14. package/dist/fonts/ibm-plex-sans-latin-ext.woff2 +0 -0
  15. package/dist/fonts/ibm-plex-sans-latin.woff2 +0 -0
  16. package/dist/fonts/inter-latin-ext.woff2 +0 -0
  17. package/dist/fonts/inter-latin.woff2 +0 -0
  18. package/dist/fonts/lato-latin-ext.woff2 +0 -0
  19. package/dist/fonts/lato-latin.woff2 +0 -0
  20. package/dist/fonts/manrope-latin-ext.woff2 +0 -0
  21. package/dist/fonts/manrope-latin.woff2 +0 -0
  22. package/dist/fonts/montserrat-latin-ext.woff2 +0 -0
  23. package/dist/fonts/montserrat-latin.woff2 +0 -0
  24. package/dist/fonts/nunito-latin-ext.woff2 +0 -0
  25. package/dist/fonts/nunito-latin.woff2 +0 -0
  26. package/dist/fonts/open-sans-latin-ext.woff2 +0 -0
  27. package/dist/fonts/open-sans-latin.woff2 +0 -0
  28. package/dist/fonts/playfair-display-latin-ext.woff2 +0 -0
  29. package/dist/fonts/playfair-display-latin.woff2 +0 -0
  30. package/dist/fonts/poppins-latin-ext.woff2 +0 -0
  31. package/dist/fonts/poppins-latin.woff2 +0 -0
  32. package/dist/fonts/roboto-latin-ext.woff2 +0 -0
  33. package/dist/fonts/roboto-latin.woff2 +0 -0
  34. package/dist/fonts/source-sans-3-latin-ext.woff2 +0 -0
  35. package/dist/fonts/source-sans-3-latin.woff2 +0 -0
  36. package/dist/fonts/work-sans-latin-ext.woff2 +0 -0
  37. package/dist/fonts/work-sans-latin.woff2 +0 -0
  38. package/dist/index.cjs +5114 -0
  39. package/dist/index.d.cts +133 -0
  40. package/dist/index.d.ts +133 -0
  41. package/dist/index.js +5109 -0
  42. package/dist/snippet.cjs +46 -0
  43. package/dist/snippet.d.cts +39 -0
  44. package/dist/snippet.d.ts +39 -0
  45. package/dist/snippet.js +43 -0
  46. package/package.json +69 -5
  47. package/index.js +0 -5
@@ -0,0 +1,197 @@
1
+ /**
2
+ * The thin identity core: the fields an interaction event carries in
3
+ * `payload.fingerprint`, and the fields the backend hashes into
4
+ * `fingerprint_key` (sorted keys, canonical JSON, SHA-256; slice 19.0).
5
+ *
6
+ * This shape is a cross-repo contract, not a convenience type. The same
7
+ * object is captured in two places, by 7.3's collector on every interactive
8
+ * click and by the design-mode picker (15.4) when an operator selects an
9
+ * element, and the two must produce byte-identical JSON for the same element
10
+ * or match counts (15.9), the observed-element list (D180), and the
11
+ * fingerprint-confidence stats silently read zero. Three rules keep the hash
12
+ * stable, enforced by the golden-vector parity tests:
13
+ *
14
+ * 1. **Flat.** `computeFingerprintKey` sorts only top-level keys, so a nested
15
+ * object would hash in whatever insertion order the client used. The
16
+ * semantic ancestor is three flat fields for exactly this reason.
17
+ * 2. **Absent keys are omitted, never `null` or `undefined`.**
18
+ * `JSON.stringify` drops `undefined` properties but keeps `null` ones, so
19
+ * the two spellings of "no value" would hash differently. There is one
20
+ * spelling: the key does not appear.
21
+ * 3. **No raw class string, anywhere.** G5 (PRODUCT_SCOPE §6.2.5.1.1): on a
22
+ * Tailwind app a class string is a presentational sentence that changes
23
+ * when a designer touches padding. Classes enter the system only through
24
+ * the ranked selector generator (15.2), after utility suppression.
25
+ *
26
+ * Changing this field set orphans every stored `fingerprint_key`. It is a
27
+ * migration, not an edit (see ADR 0059).
28
+ */
29
+ interface EventFingerprint {
30
+ /** Lowercase tag name. The one field that is always present. */
31
+ tag: string;
32
+ /** Subtree text, whitespace-collapsed, PII-masked, capped. Primary matcher. */
33
+ text?: string;
34
+ /** The icon-only control's signal; masked and capped like text. */
35
+ ariaLabel?: string;
36
+ /** Form controls have no textContent; their placeholder stands in. */
37
+ placeholder?: string;
38
+ /**
39
+ * The element's own id, only when it looks author-written. Generated ids
40
+ * (React useId's `:r3:`, Radix) change per render and would fragment the
41
+ * key, turning one button into a new "element" every session.
42
+ */
43
+ id?: string;
44
+ /** The explicit `role` attribute. No implicit-role table: not worth its bytes. */
45
+ role?: string;
46
+ /**
47
+ * The element's own `data-testid`, `data-test`, or `data-cy`, first one
48
+ * present (ADR 0134). The strongest evidence a page can offer that two
49
+ * elements are the same element: it is written by a developer to be stable
50
+ * and survives a redesign, a copy edit, and a locale switch at once.
51
+ *
52
+ * Read from the element itself, unlike `ancestorAttr`/`ancestorValue`,
53
+ * which report the same attributes found on an ancestor. Absent on most
54
+ * elements, and absence is spelled the way every optional field here is
55
+ * spelled: the key does not appear.
56
+ */
57
+ testId?: string;
58
+ /** 0-based index among same-tag element siblings. The structural tiebreak. */
59
+ siblingIndex: number;
60
+ /** Nearest ancestor carrying a semantic identifier, as three flat fields. */
61
+ ancestorTag?: string;
62
+ /** Which attribute won the ancestor walk (e.g. "data-testid", "id"). */
63
+ ancestorAttr?: string;
64
+ /** That attribute's value, masked and capped like text. */
65
+ ancestorValue?: string;
66
+ }
67
+ /**
68
+ * How strictly the runtime matcher (15.3) scores candidates. A discrete step,
69
+ * not a float: the mapping from step to score threshold lives in the matcher,
70
+ * so tuning the scoring function never migrates stored targets. 1 is loosest,
71
+ * 5 is strictest. The slider help text is the workflow: loosen when the
72
+ * element is not found, tighten when the wrong element is found.
73
+ */
74
+ type Precision = 1 | 2 | 3 | 4 | 5;
75
+ /**
76
+ * The full element target: the identity core plus the authoring layer an
77
+ * operator sets in the picker (15.4) and edits in manual adjustment (15.9).
78
+ * Stored on a flow step, so this object outlives any single arcy.js version.
79
+ */
80
+ interface TargetFingerprint {
81
+ /**
82
+ * Schema version. Durable data stored in customers' flows needs a
83
+ * discriminant before a v2 exists, or the v2 migration has nothing to
84
+ * dispatch on. Bump only with a migration plan for stored targets.
85
+ */
86
+ v: 1;
87
+ /**
88
+ * The identity core, embedded as-is and never spread flat. Everything that
89
+ * hashes or matches reads `target.core`, structurally the same object shape
90
+ * an event carries, so a field can never be forgotten in translation.
91
+ */
92
+ core: EventFingerprint;
93
+ /**
94
+ * The active selector refinement. Default null (§6.2.5.1: the reference
95
+ * leads with text, not a selector, and that default is preserved). Never
96
+ * hand-authored; 15.2's generator is the only writer, and it writes only
97
+ * when the top-ranked candidate is top-two-tier and matches exactly one
98
+ * element at pick time (D318).
99
+ */
100
+ selector: string | null;
101
+ /**
102
+ * Ranked stable-selector candidates captured at pick time by 15.2, shown
103
+ * read-only in manual adjustment as a diagnostic. Capped so a pathological
104
+ * page cannot bloat a stored target.
105
+ */
106
+ selectorCandidates: string[];
107
+ /**
108
+ * 1-based position among document-ordered candidates that survive the
109
+ * precision threshold: "if multiple matches, select 1st element". Always
110
+ * present. This is the G5 policy reversal (D013): a human pointed at the
111
+ * element and set this, so ties take the ordinal, never refuse-to-guess.
112
+ */
113
+ ordinal: number;
114
+ precision: Precision;
115
+ /**
116
+ * Marks text as changing at runtime ("3 items in cart"), so the matcher
117
+ * down-weights text rather than treating its mismatch as disqualifying.
118
+ */
119
+ dynamicText: boolean;
120
+ }
121
+
122
+ /** The one masking token. Exported because the matcher (15.3) must treat it
123
+ * as an absent signal rather than a value: every masked email collapses to
124
+ * this same string, so scoring it as text would make any PII match any
125
+ * other PII exactly. */
126
+ declare const MASK = "[masked]";
127
+
128
+ /**
129
+ * Bumped whenever a message shape changes incompatibly. A receiver that reads
130
+ * a number it does not speak refuses and says so, rather than guessing at a
131
+ * payload it half understands (the same posture ADR 0069 took for loading).
132
+ */
133
+ declare const DESIGN_MODE_PROTOCOL = 2;
134
+ /** Posted once, when the overlay has mounted and the operator can click. */
135
+ declare const DESIGN_MODE_READY = "arcy:design-mode:ready";
136
+ /** Posted for every pick. The last one wins; there is no confirm (D502). */
137
+ declare const DESIGN_MODE_PICK = "arcy:design-mode:pick";
138
+ /** Posted when the operator leaves design mode. */
139
+ declare const DESIGN_MODE_EXIT = "arcy:design-mode:exit";
140
+ /**
141
+ * Posted once per pick, asynchronously, after rasterization finishes
142
+ * (15.7). Never gates `DESIGN_MODE_PICK`'s own delivery (D502): a receiver
143
+ * that has not built `DESIGN_MODE_SCREENSHOT` into its `switch` simply drops
144
+ * it via the same unknown-`type` path every other unrecognized message takes,
145
+ * so this needed no `DESIGN_MODE_PROTOCOL` bump to add.
146
+ */
147
+ declare const DESIGN_MODE_SCREENSHOT = "arcy:design-mode:screenshot";
148
+ interface DesignModeReady {
149
+ type: typeof DESIGN_MODE_READY;
150
+ protocol: number;
151
+ }
152
+ interface DesignModePick {
153
+ type: typeof DESIGN_MODE_PICK;
154
+ protocol: number;
155
+ target: TargetFingerprint;
156
+ /**
157
+ * The path the element was picked on, read at pick time (D504). A target
158
+ * and the page it lives on are stored as two separate fields on a step, and
159
+ * browse mode means the operator can be somewhere else by the time they
160
+ * pick. Without this the step would keep whichever page was chosen in the
161
+ * dropdown, and a target filed under the wrong page reports zero forever.
162
+ */
163
+ route: string;
164
+ /**
165
+ * How many elements on this page matched the target at the moment it was
166
+ * picked (ADR 0132). Scored here, where the live document and the matcher
167
+ * both already are, rather than asked for afterwards over a channel to a tab
168
+ * the pick is about to close.
169
+ *
170
+ * Information for the operator, never a gate: zero and forty are both real
171
+ * answers worth showing, and neither is a reason to refuse a save.
172
+ */
173
+ matchCount: number;
174
+ }
175
+ interface DesignModeExit {
176
+ type: typeof DESIGN_MODE_EXIT;
177
+ protocol: number;
178
+ }
179
+ interface DesignModeScreenshot {
180
+ type: typeof DESIGN_MODE_SCREENSHOT;
181
+ protocol: number;
182
+ /** A `data:image/png;base64,...` artifact of the most recently picked
183
+ * element. Last one wins, same as the pick it decorates: a receiver simply
184
+ * overwrites whatever it is holding. */
185
+ screenshot: string;
186
+ }
187
+ type DesignModeMessage = DesignModeReady | DesignModePick | DesignModeExit | DesignModeScreenshot;
188
+ /**
189
+ * The receiver's only entry point: turns `event.data` into a message it can
190
+ * act on, or null. Says nothing about *who* sent it. The other two checks
191
+ * D501 requires, the source window and the origin, belong to the receiver,
192
+ * because only it knows which window it opened and which environment it is
193
+ * authoring in.
194
+ */
195
+ declare function readDesignModeMessage(data: unknown): DesignModeMessage | null;
196
+
197
+ export { DESIGN_MODE_EXIT, DESIGN_MODE_PICK, DESIGN_MODE_PROTOCOL, DESIGN_MODE_READY, DESIGN_MODE_SCREENSHOT, type DesignModeExit, type DesignModeMessage, type DesignModePick, type DesignModeReady, type DesignModeScreenshot, MASK, readDesignModeMessage };
@@ -0,0 +1,127 @@
1
+ /* arcy.js — https://arcyai.com */
2
+
3
+ // src/fingerprint/model.ts
4
+ var FINGERPRINT_TEXT_MAX = 80;
5
+ var SELECTOR_CANDIDATES_MAX = 5;
6
+
7
+ // src/fingerprint/capture.ts
8
+ var MASK = "[masked]";
9
+
10
+ // src/picker/message.ts
11
+ var DESIGN_MODE_PROTOCOL = 2;
12
+ var DESIGN_MODE_READY = "arcy:design-mode:ready";
13
+ var DESIGN_MODE_PICK = "arcy:design-mode:pick";
14
+ var DESIGN_MODE_EXIT = "arcy:design-mode:exit";
15
+ var DESIGN_MODE_SCREENSHOT = "arcy:design-mode:screenshot";
16
+ var TAG_MAX = 64;
17
+ var ROUTE_MAX = 2048;
18
+ var SELECTOR_MAX = 512;
19
+ var ORDINAL_MAX = 1e4;
20
+ var SIBLING_INDEX_MAX = 1e5;
21
+ var SCREENSHOT_DATA_URL_MAX = 4e6;
22
+ var SCREENSHOT_PREFIX = "data:image/png;base64,";
23
+ var MATCH_COUNT_MAX = 1e6;
24
+ function isRecord(value) {
25
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26
+ }
27
+ function isBoundedString(value, max) {
28
+ return typeof value === "string" && value.length > 0 && value.length <= max;
29
+ }
30
+ function isOptionalBoundedString(value, max) {
31
+ return value === void 0 || isBoundedString(value, max);
32
+ }
33
+ function isBoundedInteger(value, min, max) {
34
+ return typeof value === "number" && Number.isInteger(value) && value >= min && value <= max;
35
+ }
36
+ function readCore(value) {
37
+ if (!isRecord(value)) return null;
38
+ if (!isBoundedString(value.tag, TAG_MAX)) return null;
39
+ if (!isBoundedInteger(value.siblingIndex, 0, SIBLING_INDEX_MAX)) return null;
40
+ const optional = [
41
+ "text",
42
+ "ariaLabel",
43
+ "placeholder",
44
+ "id",
45
+ "role",
46
+ "testId",
47
+ "ancestorTag",
48
+ "ancestorAttr",
49
+ "ancestorValue"
50
+ ];
51
+ for (const key of optional) {
52
+ if (!isOptionalBoundedString(value[key], FINGERPRINT_TEXT_MAX)) return null;
53
+ }
54
+ const core = {
55
+ tag: value.tag,
56
+ siblingIndex: value.siblingIndex
57
+ };
58
+ for (const key of optional) {
59
+ const field = value[key];
60
+ if (typeof field === "string") core[key] = field;
61
+ }
62
+ return core;
63
+ }
64
+ function readTarget(value) {
65
+ if (!isRecord(value)) return null;
66
+ if (value.v !== 1) return null;
67
+ const core = readCore(value.core);
68
+ if (!core) return null;
69
+ const { selector, selectorCandidates, ordinal, precision, dynamicText } = value;
70
+ if (selector !== null && !isBoundedString(selector, SELECTOR_MAX)) return null;
71
+ if (!Array.isArray(selectorCandidates)) return null;
72
+ if (selectorCandidates.length > SELECTOR_CANDIDATES_MAX) return null;
73
+ if (!selectorCandidates.every((c) => isBoundedString(c, SELECTOR_MAX)))
74
+ return null;
75
+ if (!isBoundedInteger(ordinal, 1, ORDINAL_MAX)) return null;
76
+ if (!isBoundedInteger(precision, 1, 5)) return null;
77
+ if (typeof dynamicText !== "boolean") return null;
78
+ return {
79
+ v: 1,
80
+ core,
81
+ selector,
82
+ selectorCandidates,
83
+ ordinal,
84
+ precision,
85
+ dynamicText
86
+ };
87
+ }
88
+ function readDesignModeMessage(data) {
89
+ if (!isRecord(data)) return null;
90
+ if (data.protocol !== DESIGN_MODE_PROTOCOL) return null;
91
+ switch (data.type) {
92
+ case DESIGN_MODE_READY:
93
+ return { type: DESIGN_MODE_READY, protocol: DESIGN_MODE_PROTOCOL };
94
+ case DESIGN_MODE_EXIT:
95
+ return { type: DESIGN_MODE_EXIT, protocol: DESIGN_MODE_PROTOCOL };
96
+ case DESIGN_MODE_PICK: {
97
+ const target = readTarget(data.target);
98
+ if (!target) return null;
99
+ const { route, matchCount } = data;
100
+ if (!isBoundedString(route, ROUTE_MAX)) return null;
101
+ if (!route.startsWith("/")) return null;
102
+ if (route.startsWith("//")) return null;
103
+ if (!isBoundedInteger(matchCount, 0, MATCH_COUNT_MAX)) return null;
104
+ return {
105
+ type: DESIGN_MODE_PICK,
106
+ protocol: DESIGN_MODE_PROTOCOL,
107
+ target,
108
+ route,
109
+ matchCount
110
+ };
111
+ }
112
+ case DESIGN_MODE_SCREENSHOT: {
113
+ const { screenshot } = data;
114
+ if (!isBoundedString(screenshot, SCREENSHOT_DATA_URL_MAX)) return null;
115
+ if (!screenshot.startsWith(SCREENSHOT_PREFIX)) return null;
116
+ return {
117
+ type: DESIGN_MODE_SCREENSHOT,
118
+ protocol: DESIGN_MODE_PROTOCOL,
119
+ screenshot
120
+ };
121
+ }
122
+ default:
123
+ return null;
124
+ }
125
+ }
126
+
127
+ export { DESIGN_MODE_EXIT, DESIGN_MODE_PICK, DESIGN_MODE_PROTOCOL, DESIGN_MODE_READY, DESIGN_MODE_SCREENSHOT, MASK, readDesignModeMessage };
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file