@hexclave/shared 1.0.14 → 1.0.16
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/dist/apps/apps-config.d.ts +6 -0
- package/dist/apps/apps-config.js +6 -0
- package/dist/apps/apps-config.js.map +1 -1
- package/dist/config/schema.d.ts +107 -107
- package/dist/config-authoring.d.ts.map +1 -1
- package/dist/config-authoring.js.map +1 -1
- package/dist/config-authoring.test.js +1 -1
- package/dist/config-authoring.test.js.map +1 -1
- package/dist/config-rendering.d.ts +2 -2
- package/dist/config-rendering.js +16 -0
- package/dist/config-rendering.js.map +1 -1
- package/dist/esm/apps/apps-config.d.ts +6 -0
- package/dist/esm/apps/apps-config.js +6 -0
- package/dist/esm/apps/apps-config.js.map +1 -1
- package/dist/esm/config/schema.d.ts +107 -107
- package/dist/esm/config-authoring.d.ts.map +1 -1
- package/dist/esm/config-authoring.js.map +1 -1
- package/dist/esm/config-authoring.test.js +1 -1
- package/dist/esm/config-authoring.test.js.map +1 -1
- package/dist/esm/config-rendering.d.ts +2 -2
- package/dist/esm/config-rendering.js +16 -2
- package/dist/esm/config-rendering.js.map +1 -1
- package/dist/esm/hexclave-config-file.d.ts +24 -1
- package/dist/esm/hexclave-config-file.d.ts.map +1 -1
- package/dist/esm/hexclave-config-file.js +69 -2
- package/dist/esm/hexclave-config-file.js.map +1 -1
- package/dist/esm/interface/admin-interface.d.ts +19 -1
- package/dist/esm/interface/admin-interface.d.ts.map +1 -1
- package/dist/esm/interface/admin-interface.js +14 -0
- package/dist/esm/interface/admin-interface.js.map +1 -1
- package/dist/esm/interface/admin-metrics.d.ts +115 -21
- package/dist/esm/interface/admin-metrics.d.ts.map +1 -1
- package/dist/esm/interface/admin-metrics.js +61 -1
- package/dist/esm/interface/admin-metrics.js.map +1 -1
- package/dist/esm/interface/conversations.d.ts +42 -42
- package/dist/esm/interface/crud/current-user.d.ts +15 -15
- package/dist/esm/interface/crud/email-outbox.d.ts +220 -220
- package/dist/esm/interface/crud/invoices.d.ts +2 -2
- package/dist/esm/interface/crud/products.d.ts +17 -17
- package/dist/esm/interface/crud/products.d.ts.map +1 -1
- package/dist/esm/interface/crud/project-api-keys.d.ts +4 -4
- package/dist/esm/interface/crud/projects.d.ts +59 -59
- package/dist/esm/interface/crud/team-member-profiles.d.ts +26 -26
- package/dist/esm/interface/crud/transactions.d.ts +15 -15
- package/dist/esm/interface/crud/transactions.d.ts.map +1 -1
- package/dist/esm/interface/crud/users.d.ts +18 -18
- package/dist/esm/interface/webhooks.d.ts +4 -4
- package/dist/esm/known-errors.d.ts +5 -5
- package/dist/esm/schema-fields.d.ts +8 -8
- package/dist/esm/sessions.d.ts +7 -7
- package/dist/esm/utils/analytics-clickmap-overlay.d.ts +18 -0
- package/dist/esm/utils/analytics-clickmap-overlay.d.ts.map +1 -0
- package/dist/esm/utils/analytics-clickmap-overlay.js +19 -0
- package/dist/esm/utils/analytics-clickmap-overlay.js.map +1 -0
- package/dist/esm/utils/dev-tool.d.ts +31 -0
- package/dist/esm/utils/dev-tool.d.ts.map +1 -0
- package/dist/esm/utils/dev-tool.js +32 -0
- package/dist/esm/utils/dev-tool.js.map +1 -0
- package/dist/esm/utils/dom.d.ts +7 -1
- package/dist/esm/utils/dom.d.ts.map +1 -1
- package/dist/esm/utils/dom.js +20 -1
- package/dist/esm/utils/dom.js.map +1 -1
- package/dist/esm/utils/elements-chain.d.ts +38 -0
- package/dist/esm/utils/elements-chain.d.ts.map +1 -0
- package/dist/esm/utils/elements-chain.js +297 -0
- package/dist/esm/utils/elements-chain.js.map +1 -0
- package/dist/hexclave-config-file.d.ts +24 -1
- package/dist/hexclave-config-file.d.ts.map +1 -1
- package/dist/hexclave-config-file.js +71 -1
- package/dist/hexclave-config-file.js.map +1 -1
- package/dist/interface/admin-interface.d.ts +19 -1
- package/dist/interface/admin-interface.d.ts.map +1 -1
- package/dist/interface/admin-interface.js +14 -0
- package/dist/interface/admin-interface.js.map +1 -1
- package/dist/interface/admin-metrics.d.ts +115 -21
- package/dist/interface/admin-metrics.d.ts.map +1 -1
- package/dist/interface/admin-metrics.js +65 -0
- package/dist/interface/admin-metrics.js.map +1 -1
- package/dist/interface/conversations.d.ts +42 -42
- package/dist/interface/crud/current-user.d.ts +15 -15
- package/dist/interface/crud/email-outbox.d.ts +220 -220
- package/dist/interface/crud/invoices.d.ts +2 -2
- package/dist/interface/crud/products.d.ts +17 -17
- package/dist/interface/crud/products.d.ts.map +1 -1
- package/dist/interface/crud/project-api-keys.d.ts +4 -4
- package/dist/interface/crud/projects.d.ts +59 -59
- package/dist/interface/crud/team-member-profiles.d.ts +26 -26
- package/dist/interface/crud/transactions.d.ts +15 -15
- package/dist/interface/crud/transactions.d.ts.map +1 -1
- package/dist/interface/crud/users.d.ts +18 -18
- package/dist/interface/webhooks.d.ts +4 -4
- package/dist/known-errors.d.ts +5 -5
- package/dist/schema-fields.d.ts +8 -8
- package/dist/sessions.d.ts +7 -7
- package/dist/utils/analytics-clickmap-overlay.d.ts +18 -0
- package/dist/utils/analytics-clickmap-overlay.d.ts.map +1 -0
- package/dist/utils/analytics-clickmap-overlay.js +23 -0
- package/dist/utils/analytics-clickmap-overlay.js.map +1 -0
- package/dist/utils/dev-tool.d.ts +31 -0
- package/dist/utils/dev-tool.d.ts.map +1 -0
- package/dist/utils/dev-tool.js +37 -0
- package/dist/utils/dev-tool.js.map +1 -0
- package/dist/utils/dom.d.ts +7 -1
- package/dist/utils/dom.d.ts.map +1 -1
- package/dist/utils/dom.js +20 -0
- package/dist/utils/dom.js.map +1 -1
- package/dist/utils/elements-chain.d.ts +38 -0
- package/dist/utils/elements-chain.d.ts.map +1 -0
- package/dist/utils/elements-chain.js +304 -0
- package/dist/utils/elements-chain.js.map +1 -0
- package/package.json +1 -1
- package/src/apps/apps-config.ts +6 -0
- package/src/config-authoring.test.ts +1 -1
- package/src/config-authoring.ts +6 -6
- package/src/config-rendering.ts +24 -2
- package/src/hexclave-config-file.ts +90 -1
- package/src/interface/admin-interface.ts +43 -1
- package/src/interface/admin-metrics.ts +92 -4
- package/src/utils/analytics-clickmap-overlay.tsx +15 -0
- package/src/utils/dev-tool.tsx +30 -0
- package/src/utils/dom.tsx +42 -0
- package/src/utils/elements-chain.tsx +349 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
//#region src/utils/elements-chain.tsx
|
|
2
|
+
const ELEMENTS_CHAIN_MAX_DEPTH = 8;
|
|
3
|
+
const ELEMENTS_CHAIN_TEXT_MAX = 80;
|
|
4
|
+
const ELEMENTS_CHAIN_ATTR_MAX = 200;
|
|
5
|
+
const ELEMENTS_CHAIN_ATTRS = [
|
|
6
|
+
"id",
|
|
7
|
+
"data-testid",
|
|
8
|
+
"data-test-id",
|
|
9
|
+
"data-hexclave-id",
|
|
10
|
+
"name",
|
|
11
|
+
"type",
|
|
12
|
+
"role",
|
|
13
|
+
"aria-label",
|
|
14
|
+
"placeholder",
|
|
15
|
+
"title"
|
|
16
|
+
];
|
|
17
|
+
function escapeElementsChainValue(value) {
|
|
18
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
19
|
+
}
|
|
20
|
+
function escapeElementsChainClass(value) {
|
|
21
|
+
return value.replace(/\\/g, "\\\\").replace(/\./g, "\\.").replace(/:/g, "\\:");
|
|
22
|
+
}
|
|
23
|
+
function getElementClasses(element) {
|
|
24
|
+
const className = element.className;
|
|
25
|
+
if (typeof className !== "string" || className.trim() === "") return [];
|
|
26
|
+
return className.trim().split(/\s+/).filter(Boolean).slice(0, 4);
|
|
27
|
+
}
|
|
28
|
+
function getNthChildIndex(element) {
|
|
29
|
+
const parent = element.parentElement;
|
|
30
|
+
if (parent == null) return null;
|
|
31
|
+
const index = Array.prototype.indexOf.call(parent.children, element);
|
|
32
|
+
return index >= 0 ? index + 1 : null;
|
|
33
|
+
}
|
|
34
|
+
function getNthOfTypeIndex(element) {
|
|
35
|
+
const parent = element.parentElement;
|
|
36
|
+
if (parent == null) return null;
|
|
37
|
+
const tagName = element.tagName;
|
|
38
|
+
const siblings = Array.from(parent.children).filter((child) => child.tagName === tagName);
|
|
39
|
+
if (siblings.length <= 1) return null;
|
|
40
|
+
const index = siblings.indexOf(element);
|
|
41
|
+
return index >= 0 ? index + 1 : null;
|
|
42
|
+
}
|
|
43
|
+
function serializeElementsChainSegment(element) {
|
|
44
|
+
const parts = [];
|
|
45
|
+
parts.push(element.tagName.toLowerCase());
|
|
46
|
+
const classes = getElementClasses(element);
|
|
47
|
+
if (classes.length > 0) parts.push(`.${classes.map(escapeElementsChainClass).join(".")}`);
|
|
48
|
+
const text = element.textContent.trim().replace(/\s+/g, " ").slice(0, ELEMENTS_CHAIN_TEXT_MAX);
|
|
49
|
+
const nthChild = getNthChildIndex(element);
|
|
50
|
+
const nthOfType = getNthOfTypeIndex(element);
|
|
51
|
+
const attrPairs = [];
|
|
52
|
+
if (nthChild != null) attrPairs.push(`nth-child="${nthChild}"`);
|
|
53
|
+
if (nthOfType != null) attrPairs.push(`nth-of-type="${nthOfType}"`);
|
|
54
|
+
if (text !== "") attrPairs.push(`text="${escapeElementsChainValue(text)}"`);
|
|
55
|
+
for (const attrName of ELEMENTS_CHAIN_ATTRS) {
|
|
56
|
+
const value = element.getAttribute(attrName);
|
|
57
|
+
if (value == null || value === "") continue;
|
|
58
|
+
attrPairs.push(`attr__${attrName}="${escapeElementsChainValue(value.slice(0, ELEMENTS_CHAIN_ATTR_MAX))}"`);
|
|
59
|
+
}
|
|
60
|
+
if (element.tagName === "A") {
|
|
61
|
+
const href = element.getAttribute("href");
|
|
62
|
+
if (href != null && href !== "") attrPairs.push(`href="${escapeElementsChainValue(href.slice(0, ELEMENTS_CHAIN_ATTR_MAX))}"`);
|
|
63
|
+
}
|
|
64
|
+
if (attrPairs.length > 0) parts.push(`:${attrPairs.join(":")}`);
|
|
65
|
+
return parts.join("");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Serialise a clicked element and up to {@link ELEMENTS_CHAIN_MAX_DEPTH}
|
|
69
|
+
* ancestors (leaf-first) into an `elements_chain` string.
|
|
70
|
+
*/
|
|
71
|
+
function buildElementsChain(element) {
|
|
72
|
+
const segments = [];
|
|
73
|
+
let current = element;
|
|
74
|
+
let depth = 0;
|
|
75
|
+
while (current != null && depth < ELEMENTS_CHAIN_MAX_DEPTH && current !== document.documentElement) {
|
|
76
|
+
segments.push(serializeElementsChainSegment(current));
|
|
77
|
+
current = current.parentElement;
|
|
78
|
+
depth += 1;
|
|
79
|
+
}
|
|
80
|
+
return segments.join(";");
|
|
81
|
+
}
|
|
82
|
+
function splitEscapedDots(input) {
|
|
83
|
+
const out = [];
|
|
84
|
+
let cur = "";
|
|
85
|
+
for (let i = 0; i < input.length; i++) {
|
|
86
|
+
const ch = input[i];
|
|
87
|
+
if (ch === "\\" && i + 1 < input.length) {
|
|
88
|
+
cur += input[i + 1];
|
|
89
|
+
i += 1;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (ch === ".") {
|
|
93
|
+
out.push(cur);
|
|
94
|
+
cur = "";
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
cur += ch;
|
|
98
|
+
}
|
|
99
|
+
out.push(cur);
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
function applyElementsChainAttr(key, value) {
|
|
103
|
+
if (key === "nth-child") {
|
|
104
|
+
const n = Number.parseInt(value, 10);
|
|
105
|
+
return Number.isFinite(n) ? { nthChild: n } : {};
|
|
106
|
+
}
|
|
107
|
+
if (key === "nth-of-type") {
|
|
108
|
+
const n = Number.parseInt(value, 10);
|
|
109
|
+
return Number.isFinite(n) ? { nthOfType: n } : {};
|
|
110
|
+
}
|
|
111
|
+
if (key === "text") return { text: value };
|
|
112
|
+
if (key === "href") return {
|
|
113
|
+
href: value,
|
|
114
|
+
attrKey: key,
|
|
115
|
+
attrValue: value
|
|
116
|
+
};
|
|
117
|
+
if (key.startsWith("attr__")) return {
|
|
118
|
+
attrKey: key.slice(6),
|
|
119
|
+
attrValue: value
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
attrKey: key,
|
|
123
|
+
attrValue: value
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function parseElementsChainSegment(segment) {
|
|
127
|
+
const trimmed = segment.trim();
|
|
128
|
+
if (trimmed === "") return null;
|
|
129
|
+
let prefixEnd = trimmed.length;
|
|
130
|
+
let inQuotes = false;
|
|
131
|
+
for (let i = 0; i < trimmed.length; i++) {
|
|
132
|
+
const ch = trimmed[i];
|
|
133
|
+
if (ch === "\\" && i + 1 < trimmed.length) {
|
|
134
|
+
i += 1;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (ch === "\"") {
|
|
138
|
+
inQuotes = !inQuotes;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (ch === ":" && !inQuotes) {
|
|
142
|
+
prefixEnd = i;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const prefix = trimmed.slice(0, prefixEnd);
|
|
147
|
+
const rest = trimmed.slice(prefixEnd);
|
|
148
|
+
const prefixParts = splitEscapedDots(prefix);
|
|
149
|
+
const tag = prefixParts[0].trim().toLowerCase();
|
|
150
|
+
if (tag === "") return null;
|
|
151
|
+
const classes = prefixParts.slice(1).map((c) => c.trim()).filter((c) => c !== "");
|
|
152
|
+
const attrs = {};
|
|
153
|
+
let nthChild = null;
|
|
154
|
+
let nthOfType = null;
|
|
155
|
+
let text = null;
|
|
156
|
+
let href = null;
|
|
157
|
+
let i = 0;
|
|
158
|
+
while (i < rest.length) {
|
|
159
|
+
if (rest[i] !== ":") {
|
|
160
|
+
i += 1;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
i += 1;
|
|
164
|
+
let keyEnd = i;
|
|
165
|
+
while (keyEnd < rest.length && rest[keyEnd] !== "=" && rest[keyEnd] !== ":") keyEnd += 1;
|
|
166
|
+
const key = rest.slice(i, keyEnd).trim();
|
|
167
|
+
if (keyEnd >= rest.length || rest[keyEnd] !== "=") {
|
|
168
|
+
i = keyEnd;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
let valStart = keyEnd + 1;
|
|
172
|
+
if (rest[valStart] !== "\"") {
|
|
173
|
+
let end = valStart;
|
|
174
|
+
while (end < rest.length && rest[end] !== ":") end += 1;
|
|
175
|
+
const result = applyElementsChainAttr(key, rest.slice(valStart, end));
|
|
176
|
+
if (result.nthChild != null) nthChild = result.nthChild;
|
|
177
|
+
if (result.nthOfType != null) nthOfType = result.nthOfType;
|
|
178
|
+
if (result.text != null) text = result.text;
|
|
179
|
+
if (result.href != null) href = result.href;
|
|
180
|
+
if (result.attrKey != null) attrs[result.attrKey] = result.attrValue ?? "";
|
|
181
|
+
i = end;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
valStart += 1;
|
|
185
|
+
let end = valStart;
|
|
186
|
+
let value = "";
|
|
187
|
+
while (end < rest.length) {
|
|
188
|
+
const ch = rest[end];
|
|
189
|
+
if (ch === "\\" && end + 1 < rest.length) {
|
|
190
|
+
const next = rest[end + 1];
|
|
191
|
+
if (next === "\"" || next === "\\") {
|
|
192
|
+
value += next;
|
|
193
|
+
end += 2;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
value += ch;
|
|
197
|
+
end += 1;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (ch === "\"") break;
|
|
201
|
+
value += ch;
|
|
202
|
+
end += 1;
|
|
203
|
+
}
|
|
204
|
+
const result = applyElementsChainAttr(key, value);
|
|
205
|
+
if (result.nthChild != null) nthChild = result.nthChild;
|
|
206
|
+
if (result.nthOfType != null) nthOfType = result.nthOfType;
|
|
207
|
+
if (result.text != null) text = result.text;
|
|
208
|
+
if (result.href != null) href = result.href;
|
|
209
|
+
if (result.attrKey != null) attrs[result.attrKey] = result.attrValue ?? "";
|
|
210
|
+
i = end + 1;
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
tag,
|
|
214
|
+
classes,
|
|
215
|
+
attrs,
|
|
216
|
+
text,
|
|
217
|
+
nthChild,
|
|
218
|
+
nthOfType,
|
|
219
|
+
href
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
/** Parse an `elements_chain` string into structured, leaf-first segments. */
|
|
223
|
+
function parseElementsChain(chain) {
|
|
224
|
+
const segments = [];
|
|
225
|
+
let current = "";
|
|
226
|
+
let inQuotes = false;
|
|
227
|
+
for (let i = 0; i < chain.length; i++) {
|
|
228
|
+
const ch = chain[i];
|
|
229
|
+
if (ch === "\\" && i + 1 < chain.length) {
|
|
230
|
+
current += ch + chain[i + 1];
|
|
231
|
+
i += 1;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (ch === "\"") {
|
|
235
|
+
inQuotes = !inQuotes;
|
|
236
|
+
current += ch;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (ch === ";" && !inQuotes) {
|
|
240
|
+
segments.push(current);
|
|
241
|
+
current = "";
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
current += ch;
|
|
245
|
+
}
|
|
246
|
+
if (current.length > 0) segments.push(current);
|
|
247
|
+
return segments.map(parseElementsChainSegment).filter((segment) => segment != null);
|
|
248
|
+
}
|
|
249
|
+
(void 0)?.test("parseElementsChain parses a simple leaf+ancestor chain", ({ expect }) => {
|
|
250
|
+
expect(parseElementsChain("button.btn.btn-primary:nth-of-type=\"1\":text=\"Save\":attr__id=\"save-btn\";div.container")).toEqual([{
|
|
251
|
+
tag: "button",
|
|
252
|
+
classes: ["btn", "btn-primary"],
|
|
253
|
+
attrs: { id: "save-btn" },
|
|
254
|
+
text: "Save",
|
|
255
|
+
nthChild: null,
|
|
256
|
+
nthOfType: 1,
|
|
257
|
+
href: null
|
|
258
|
+
}, {
|
|
259
|
+
tag: "div",
|
|
260
|
+
classes: ["container"],
|
|
261
|
+
attrs: {},
|
|
262
|
+
text: null,
|
|
263
|
+
nthChild: null,
|
|
264
|
+
nthOfType: null,
|
|
265
|
+
href: null
|
|
266
|
+
}]);
|
|
267
|
+
});
|
|
268
|
+
(void 0)?.test("parseElementsChain reverses class escaping for Tailwind-style tokens", ({ expect }) => {
|
|
269
|
+
expect(parseElementsChain("a.md\\:hover\\:bg-blue-500.w-\\[1\\.5rem\\]:href=\"/p?a=1\"")).toEqual([{
|
|
270
|
+
tag: "a",
|
|
271
|
+
classes: ["md:hover:bg-blue-500", "w-[1.5rem]"],
|
|
272
|
+
attrs: { href: "/p?a=1" },
|
|
273
|
+
text: null,
|
|
274
|
+
nthChild: null,
|
|
275
|
+
nthOfType: null,
|
|
276
|
+
href: "/p?a=1"
|
|
277
|
+
}]);
|
|
278
|
+
});
|
|
279
|
+
(void 0)?.test("parseElementsChain unescapes quotes/backslashes and ignores ';' inside quoted values", ({ expect }) => {
|
|
280
|
+
expect(parseElementsChain("span:text=\"a \\\"b\\\"; c \\\\ d\"")).toEqual([{
|
|
281
|
+
tag: "span",
|
|
282
|
+
classes: [],
|
|
283
|
+
attrs: {},
|
|
284
|
+
text: "a \"b\"; c \\ d",
|
|
285
|
+
nthChild: null,
|
|
286
|
+
nthOfType: null,
|
|
287
|
+
href: null
|
|
288
|
+
}]);
|
|
289
|
+
});
|
|
290
|
+
(void 0)?.test("parseElementsChain drops empty/tagless segments", ({ expect }) => {
|
|
291
|
+
expect(parseElementsChain("")).toEqual([]);
|
|
292
|
+
expect(parseElementsChain(";;")).toEqual([]);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
//#endregion
|
|
296
|
+
export { ELEMENTS_CHAIN_ATTRS, ELEMENTS_CHAIN_ATTR_MAX, ELEMENTS_CHAIN_MAX_DEPTH, ELEMENTS_CHAIN_TEXT_MAX, buildElementsChain, parseElementsChain };
|
|
297
|
+
//# sourceMappingURL=elements-chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements-chain.js","names":[],"sources":["../../../src/utils/elements-chain.tsx"],"sourcesContent":["/**\n * PostHog-style `elements_chain` format — the single owner of both halves of the\n * contract. The event tracker {@link buildElementsChain serializes} a clicked\n * element (and its ancestors) into a string; the clickmap overlay\n * {@link parseElementsChain parses} that string back into structured segments so\n * it can re-locate the element in a live DOM.\n *\n * Encode and decode MUST round-trip exactly, which is why they live together:\n * the escaping applied here on the write side is reversed by the parser below,\n * and a single round-trip test in `elements-chain.test.tsx` guards the pair.\n *\n * Segment shape (leaf-first, joined by `;`):\n * tag.class1.class2:nth-child=\"2\":nth-of-type=\"1\":text=\"Save\":attr__id=\"x\":href=\"...\"\n */\n\nexport type ElementsChainSegment = {\n tag: string,\n classes: string[],\n attrs: Record<string, string>,\n text: string | null,\n nthChild: number | null,\n nthOfType: number | null,\n href: string | null,\n};\n\nexport const ELEMENTS_CHAIN_MAX_DEPTH = 8;\nexport const ELEMENTS_CHAIN_TEXT_MAX = 80;\nexport const ELEMENTS_CHAIN_ATTR_MAX = 200;\n\n// Attributes we serialise into elements_chain. Mirrors the set PostHog persists:\n// stable identifiers (id, data-testid), semantics (role, type, name, aria-label),\n// and a few we expect downstream tooling to want to match against.\nexport const ELEMENTS_CHAIN_ATTRS = [\n \"id\",\n \"data-testid\",\n \"data-test-id\",\n \"data-hexclave-id\",\n \"name\",\n \"type\",\n \"role\",\n \"aria-label\",\n \"placeholder\",\n \"title\",\n] as const;\n\n// ---------------------------------------------------------------------------\n// Serialization (DOM element -> elements_chain string)\n// ---------------------------------------------------------------------------\n\nfunction escapeElementsChainValue(value: string): string {\n return value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n}\n\n// Class tokens are written into the unquoted, dot-joined prefix of a segment, so\n// any \".\" or \":\" inside a class (e.g. Tailwind variants like `md:hover:bg-blue-500`\n// or arbitrary values like `w-[1.5rem]`) must be escaped to round-trip through the\n// parser, which splits the prefix on unescaped \".\" and the segment on unescaped \":\".\nfunction escapeElementsChainClass(value: string): string {\n return value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\./g, \"\\\\.\").replace(/:/g, \"\\\\:\");\n}\n\nfunction getElementClasses(element: Element): string[] {\n const className = (element as HTMLElement).className;\n if (typeof className !== \"string\" || className.trim() === \"\") {\n return [];\n }\n return className.trim().split(/\\s+/).filter(Boolean).slice(0, 4);\n}\n\nfunction getNthChildIndex(element: Element): number | null {\n const parent = element.parentElement;\n if (parent == null) return null;\n const index = Array.prototype.indexOf.call(parent.children, element);\n return index >= 0 ? index + 1 : null;\n}\n\nfunction getNthOfTypeIndex(element: Element): number | null {\n const parent = element.parentElement;\n if (parent == null) return null;\n const tagName = element.tagName;\n const siblings = Array.from(parent.children).filter((child) => child.tagName === tagName);\n if (siblings.length <= 1) return null;\n const index = siblings.indexOf(element);\n return index >= 0 ? index + 1 : null;\n}\n\nfunction serializeElementsChainSegment(element: Element): string {\n const parts: string[] = [];\n parts.push(element.tagName.toLowerCase());\n const classes = getElementClasses(element);\n if (classes.length > 0) {\n parts.push(`.${classes.map(escapeElementsChainClass).join(\".\")}`);\n }\n const text = element.textContent.trim().replace(/\\s+/g, \" \").slice(0, ELEMENTS_CHAIN_TEXT_MAX);\n const nthChild = getNthChildIndex(element);\n const nthOfType = getNthOfTypeIndex(element);\n const attrPairs: string[] = [];\n if (nthChild != null) attrPairs.push(`nth-child=\"${nthChild}\"`);\n if (nthOfType != null) attrPairs.push(`nth-of-type=\"${nthOfType}\"`);\n if (text !== \"\") attrPairs.push(`text=\"${escapeElementsChainValue(text)}\"`);\n for (const attrName of ELEMENTS_CHAIN_ATTRS) {\n const value = element.getAttribute(attrName);\n if (value == null || value === \"\") continue;\n attrPairs.push(`attr__${attrName}=\"${escapeElementsChainValue(value.slice(0, ELEMENTS_CHAIN_ATTR_MAX))}\"`);\n }\n if (element.tagName === \"A\") {\n const href = element.getAttribute(\"href\");\n if (href != null && href !== \"\") {\n attrPairs.push(`href=\"${escapeElementsChainValue(href.slice(0, ELEMENTS_CHAIN_ATTR_MAX))}\"`);\n }\n }\n if (attrPairs.length > 0) {\n parts.push(`:${attrPairs.join(\":\")}`);\n }\n return parts.join(\"\");\n}\n\n/**\n * Serialise a clicked element and up to {@link ELEMENTS_CHAIN_MAX_DEPTH}\n * ancestors (leaf-first) into an `elements_chain` string.\n */\nexport function buildElementsChain(element: Element): string {\n const segments: string[] = [];\n let current: Element | null = element;\n let depth = 0;\n while (current != null && depth < ELEMENTS_CHAIN_MAX_DEPTH && current !== document.documentElement) {\n segments.push(serializeElementsChainSegment(current));\n current = current.parentElement;\n depth += 1;\n }\n return segments.join(\";\");\n}\n\n// ---------------------------------------------------------------------------\n// Parsing (elements_chain string -> structured segments)\n// ---------------------------------------------------------------------------\n\n// Split a string on unescaped occurrences of `.`, unescaping `\\.`, `\\:` and `\\\\`\n// back to their literal characters. Reverses `escapeElementsChainClass`.\nfunction splitEscapedDots(input: string): string[] {\n const out: string[] = [];\n let cur = '';\n for (let i = 0; i < input.length; i++) {\n const ch = input[i];\n if (ch === '\\\\' && i + 1 < input.length) {\n cur += input[i + 1];\n i += 1;\n continue;\n }\n if (ch === '.') {\n out.push(cur);\n cur = '';\n continue;\n }\n cur += ch;\n }\n out.push(cur);\n return out;\n}\n\ntype ElementsChainAttrResult = {\n nthChild?: number,\n nthOfType?: number,\n text?: string,\n href?: string,\n attrKey?: string,\n attrValue?: string,\n};\n\nfunction applyElementsChainAttr(key: string, value: string): ElementsChainAttrResult {\n if (key === 'nth-child') {\n const n = Number.parseInt(value, 10);\n return Number.isFinite(n) ? { nthChild: n } : {};\n }\n if (key === 'nth-of-type') {\n const n = Number.parseInt(value, 10);\n return Number.isFinite(n) ? { nthOfType: n } : {};\n }\n if (key === 'text') {\n return { text: value };\n }\n if (key === 'href') {\n return { href: value, attrKey: key, attrValue: value };\n }\n if (key.startsWith('attr__')) {\n return { attrKey: key.slice('attr__'.length), attrValue: value };\n }\n return { attrKey: key, attrValue: value };\n}\n\nfunction parseElementsChainSegment(segment: string): ElementsChainSegment | null {\n const trimmed = segment.trim();\n if (trimmed === '') return null;\n\n // Find first ':' at top level — separates tag/classes prefix from attribute pairs.\n let prefixEnd = trimmed.length;\n let inQuotes = false;\n for (let i = 0; i < trimmed.length; i++) {\n const ch = trimmed[i];\n if (ch === '\\\\' && i + 1 < trimmed.length) {\n i += 1;\n continue;\n }\n if (ch === '\"') {\n inQuotes = !inQuotes;\n continue;\n }\n if (ch === ':' && !inQuotes) {\n prefixEnd = i;\n break;\n }\n }\n\n const prefix = trimmed.slice(0, prefixEnd);\n const rest = trimmed.slice(prefixEnd);\n const prefixParts = splitEscapedDots(prefix);\n const tag = prefixParts[0].trim().toLowerCase();\n if (tag === '') return null;\n const classes = prefixParts.slice(1).map((c) => c.trim()).filter((c) => c !== '');\n\n const attrs: Record<string, string> = {};\n let nthChild: number | null = null;\n let nthOfType: number | null = null;\n let text: string | null = null;\n let href: string | null = null;\n\n // Parse :key=\"value\" pairs from rest.\n let i = 0;\n while (i < rest.length) {\n if (rest[i] !== ':') {\n i += 1;\n continue;\n }\n i += 1; // skip ':'\n // read key up to '='\n let keyEnd = i;\n while (keyEnd < rest.length && rest[keyEnd] !== '=' && rest[keyEnd] !== ':') keyEnd += 1;\n const key = rest.slice(i, keyEnd).trim();\n if (keyEnd >= rest.length || rest[keyEnd] !== '=') {\n i = keyEnd;\n continue;\n }\n let valStart = keyEnd + 1;\n if (rest[valStart] !== '\"') {\n // unquoted — read until next ':' at top level\n let end = valStart;\n while (end < rest.length && rest[end] !== ':') end += 1;\n const value = rest.slice(valStart, end);\n const result = applyElementsChainAttr(key, value);\n if (result.nthChild != null) nthChild = result.nthChild;\n if (result.nthOfType != null) nthOfType = result.nthOfType;\n if (result.text != null) text = result.text;\n if (result.href != null) href = result.href;\n if (result.attrKey != null) attrs[result.attrKey] = result.attrValue ?? '';\n i = end;\n continue;\n }\n // quoted value — find unescaped closing quote\n valStart += 1;\n let end = valStart;\n let value = '';\n while (end < rest.length) {\n const ch = rest[end];\n if (ch === '\\\\' && end + 1 < rest.length) {\n const next = rest[end + 1];\n if (next === '\"' || next === '\\\\') {\n value += next;\n end += 2;\n continue;\n }\n value += ch;\n end += 1;\n continue;\n }\n if (ch === '\"') break;\n value += ch;\n end += 1;\n }\n const result = applyElementsChainAttr(key, value);\n if (result.nthChild != null) nthChild = result.nthChild;\n if (result.nthOfType != null) nthOfType = result.nthOfType;\n if (result.text != null) text = result.text;\n if (result.href != null) href = result.href;\n if (result.attrKey != null) attrs[result.attrKey] = result.attrValue ?? '';\n i = end + 1; // skip closing quote\n }\n\n return { tag, classes, attrs, text, nthChild, nthOfType, href };\n}\n\n/** Parse an `elements_chain` string into structured, leaf-first segments. */\nexport function parseElementsChain(chain: string): ElementsChainSegment[] {\n // Split top-level by ';' respecting quoted strings.\n const segments: string[] = [];\n let current = '';\n let inQuotes = false;\n for (let i = 0; i < chain.length; i++) {\n const ch = chain[i];\n if (ch === '\\\\' && i + 1 < chain.length) {\n current += ch + chain[i + 1];\n i += 1;\n continue;\n }\n if (ch === '\"') {\n inQuotes = !inQuotes;\n current += ch;\n continue;\n }\n if (ch === ';' && !inQuotes) {\n segments.push(current);\n current = '';\n continue;\n }\n current += ch;\n }\n if (current.length > 0) {\n segments.push(current);\n }\n return segments.map(parseElementsChainSegment).filter((segment): segment is ElementsChainSegment => segment != null);\n}\n\nimport.meta.vitest?.test(\"parseElementsChain parses a simple leaf+ancestor chain\", ({ expect }) => {\n const parsed = parseElementsChain('button.btn.btn-primary:nth-of-type=\"1\":text=\"Save\":attr__id=\"save-btn\";div.container');\n expect(parsed).toEqual([\n { tag: \"button\", classes: [\"btn\", \"btn-primary\"], attrs: { id: \"save-btn\" }, text: \"Save\", nthChild: null, nthOfType: 1, href: null },\n { tag: \"div\", classes: [\"container\"], attrs: {}, text: null, nthChild: null, nthOfType: null, href: null },\n ]);\n});\n\nimport.meta.vitest?.test(\"parseElementsChain reverses class escaping for Tailwind-style tokens\", ({ expect }) => {\n // `md:hover:bg-blue-500` and `w-[1.5rem]` contain the prefix delimiters `:`/`.`,\n // so the serializer escapes them; the parser must recover the literal classes.\n const parsed = parseElementsChain('a.md\\\\:hover\\\\:bg-blue-500.w-\\\\[1\\\\.5rem\\\\]:href=\"/p?a=1\"');\n expect(parsed).toEqual([\n { tag: \"a\", classes: [\"md:hover:bg-blue-500\", \"w-[1.5rem]\"], attrs: { href: \"/p?a=1\" }, text: null, nthChild: null, nthOfType: null, href: \"/p?a=1\" },\n ]);\n});\n\nimport.meta.vitest?.test(\"parseElementsChain unescapes quotes/backslashes and ignores ';' inside quoted values\", ({ expect }) => {\n const parsed = parseElementsChain('span:text=\"a \\\\\"b\\\\\"; c \\\\\\\\ d\"');\n expect(parsed).toEqual([\n { tag: \"span\", classes: [], attrs: {}, text: 'a \"b\"; c \\\\ d', nthChild: null, nthOfType: null, href: null },\n ]);\n});\n\nimport.meta.vitest?.test(\"parseElementsChain drops empty/tagless segments\", ({ expect }) => {\n expect(parseElementsChain(\"\")).toEqual([]);\n expect(parseElementsChain(\";;\")).toEqual([]);\n});\n"],"mappings":"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"}
|
|
@@ -9,7 +9,30 @@ declare const showOnboardingHexclaveConfigValue = "show-onboarding";
|
|
|
9
9
|
*/
|
|
10
10
|
declare function renderConfigFileContent(config: unknown, importPackage?: string): string;
|
|
11
11
|
type ParsedStackConfig = Record<string, unknown> | typeof showOnboardingHexclaveConfigValue;
|
|
12
|
+
/**
|
|
13
|
+
* Like {@link parseHexclaveConfigFileContent}, but returns `null` instead of
|
|
14
|
+
* throwing when the file is not a plain static config (e.g. it wraps the config
|
|
15
|
+
* in a helper call, references imported values, or has a syntax error). Useful
|
|
16
|
+
* for deciding whether a config file can be safely regenerated deterministically
|
|
17
|
+
* or whether it has custom structure that must be preserved.
|
|
18
|
+
*/
|
|
19
|
+
declare function tryParseHexclaveConfigFileContent(content: string, filePath: string): ParsedStackConfig | null;
|
|
20
|
+
/**
|
|
21
|
+
* Returns whether `content` parses as a module that exports a `config` binding.
|
|
22
|
+
* Used as a lightweight structural sanity check after editing config files whose
|
|
23
|
+
* values can't be evaluated by our loader (e.g. they import external text
|
|
24
|
+
* files), where a full semantic comparison isn't possible.
|
|
25
|
+
*/
|
|
26
|
+
declare function hexclaveConfigFileExportsConfig(content: string, filePath: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Returns the relative import sources (those starting with `./` or `../`)
|
|
29
|
+
* declared in `content`. Used to discover the external files a config update may
|
|
30
|
+
* touch — e.g. `import x from "./welcome-email.tsx" with { type: "text" }` — so
|
|
31
|
+
* they can be snapshotted and rolled back if an in-place update fails. Returns
|
|
32
|
+
* an empty array if the file can't be parsed.
|
|
33
|
+
*/
|
|
34
|
+
declare function getRelativeImportSpecifiers(content: string): string[];
|
|
12
35
|
declare function parseHexclaveConfigFileContent(content: string, filePath: string): ParsedStackConfig;
|
|
13
36
|
//#endregion
|
|
14
|
-
export { parseHexclaveConfigFileContent, renderConfigFileContent, showOnboardingHexclaveConfigValue };
|
|
37
|
+
export { getRelativeImportSpecifiers, hexclaveConfigFileExportsConfig, parseHexclaveConfigFileContent, renderConfigFileContent, showOnboardingHexclaveConfigValue, tryParseHexclaveConfigFileContent };
|
|
15
38
|
//# sourceMappingURL=hexclave-config-file.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hexclave-config-file.d.ts","names":[],"sources":["../src/hexclave-config-file.ts"],"mappings":";cAIa,iCAAA;AAAb;;;;;AAWA;;AAXA,iBAWgB,uBAAA,CAAwB,MAAA,WAAiB,aAAA;AAAA,KAyBpD,iBAAA,GAAoB,MAAA,2BAAiC,iCAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"hexclave-config-file.d.ts","names":[],"sources":["../src/hexclave-config-file.ts"],"mappings":";cAIa,iCAAA;AAAb;;;;;AAWA;;AAXA,iBAWgB,uBAAA,CAAwB,MAAA,WAAiB,aAAA;AAAA,KAyBpD,iBAAA,GAAoB,MAAA,2BAAiC,iCAAA;;AAFzD;;;;;AAuED;iBAAgB,iCAAA,CAAkC,OAAA,UAAiB,QAAA,WAAmB,iBAAA;;;;;;;iBActE,+BAAA,CAAgC,OAAA,UAAiB,QAAA;AAAjE;;;;;AA8CA;;AA9CA,iBA8CgB,2BAAA,CAA4B,OAAA;AAAA,iBAsB5B,8BAAA,CAA+B,OAAA,UAAiB,QAAA,WAAmB,iBAAA"}
|
|
@@ -59,11 +59,78 @@ function evaluateStaticConfigExpression(expression) {
|
|
|
59
59
|
}
|
|
60
60
|
throw new Error(`Unsupported config expression: ${unwrapped.type}`);
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Like {@link parseHexclaveConfigFileContent}, but returns `null` instead of
|
|
64
|
+
* throwing when the file is not a plain static config (e.g. it wraps the config
|
|
65
|
+
* in a helper call, references imported values, or has a syntax error). Useful
|
|
66
|
+
* for deciding whether a config file can be safely regenerated deterministically
|
|
67
|
+
* or whether it has custom structure that must be preserved.
|
|
68
|
+
*/
|
|
69
|
+
function tryParseHexclaveConfigFileContent(content, filePath) {
|
|
70
|
+
try {
|
|
71
|
+
return parseHexclaveConfigFileContent(content, filePath);
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Returns whether `content` parses as a module that exports a `config` binding.
|
|
78
|
+
* Used as a lightweight structural sanity check after editing config files whose
|
|
79
|
+
* values can't be evaluated by our loader (e.g. they import external text
|
|
80
|
+
* files), where a full semantic comparison isn't possible.
|
|
81
|
+
*/
|
|
82
|
+
function hexclaveConfigFileExportsConfig(content, filePath) {
|
|
83
|
+
let ast;
|
|
84
|
+
try {
|
|
85
|
+
ast = _babel_parser.parse(content, {
|
|
86
|
+
sourceType: "module",
|
|
87
|
+
sourceFilename: filePath,
|
|
88
|
+
plugins: ["typescript", "importAttributes"]
|
|
89
|
+
});
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
for (const statement of ast.program.body) {
|
|
94
|
+
if (!_babel_types.isExportNamedDeclaration(statement)) continue;
|
|
95
|
+
if (statement.exportKind === "type") continue;
|
|
96
|
+
if (_babel_types.isVariableDeclaration(statement.declaration)) {
|
|
97
|
+
for (const declaration of statement.declaration.declarations) if (_babel_types.isIdentifier(declaration.id) && declaration.id.name === "config" && declaration.init != null) return true;
|
|
98
|
+
}
|
|
99
|
+
for (const specifier of statement.specifiers) if (_babel_types.isExportSpecifier(specifier) && specifier.exportKind !== "type") {
|
|
100
|
+
if ((_babel_types.isIdentifier(specifier.exported) ? specifier.exported.name : specifier.exported.value) === "config") return true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Returns the relative import sources (those starting with `./` or `../`)
|
|
107
|
+
* declared in `content`. Used to discover the external files a config update may
|
|
108
|
+
* touch — e.g. `import x from "./welcome-email.tsx" with { type: "text" }` — so
|
|
109
|
+
* they can be snapshotted and rolled back if an in-place update fails. Returns
|
|
110
|
+
* an empty array if the file can't be parsed.
|
|
111
|
+
*/
|
|
112
|
+
function getRelativeImportSpecifiers(content) {
|
|
113
|
+
let ast;
|
|
114
|
+
try {
|
|
115
|
+
ast = _babel_parser.parse(content, {
|
|
116
|
+
sourceType: "module",
|
|
117
|
+
plugins: ["typescript", "importAttributes"]
|
|
118
|
+
});
|
|
119
|
+
} catch {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
const sources = [];
|
|
123
|
+
for (const statement of ast.program.body) if (_babel_types.isImportDeclaration(statement)) {
|
|
124
|
+
const source = statement.source.value;
|
|
125
|
+
if (source.startsWith("./") || source.startsWith("../")) sources.push(source);
|
|
126
|
+
}
|
|
127
|
+
return sources;
|
|
128
|
+
}
|
|
62
129
|
function parseHexclaveConfigFileContent(content, filePath) {
|
|
63
130
|
if (content.trim() === "") return {};
|
|
64
131
|
const ast = _babel_parser.parse(content, {
|
|
65
132
|
sourceType: "module",
|
|
66
|
-
plugins: ["typescript"]
|
|
133
|
+
plugins: ["typescript", "importAttributes"]
|
|
67
134
|
});
|
|
68
135
|
for (const statement of ast.program.body) {
|
|
69
136
|
if (!_babel_types.isExportNamedDeclaration(statement) || !_babel_types.isVariableDeclaration(statement.declaration)) continue;
|
|
@@ -77,7 +144,10 @@ function parseHexclaveConfigFileContent(content, filePath) {
|
|
|
77
144
|
}
|
|
78
145
|
|
|
79
146
|
//#endregion
|
|
147
|
+
exports.getRelativeImportSpecifiers = getRelativeImportSpecifiers;
|
|
148
|
+
exports.hexclaveConfigFileExportsConfig = hexclaveConfigFileExportsConfig;
|
|
80
149
|
exports.parseHexclaveConfigFileContent = parseHexclaveConfigFileContent;
|
|
81
150
|
exports.renderConfigFileContent = renderConfigFileContent;
|
|
82
151
|
exports.showOnboardingHexclaveConfigValue = showOnboardingHexclaveConfigValue;
|
|
152
|
+
exports.tryParseHexclaveConfigFileContent = tryParseHexclaveConfigFileContent;
|
|
83
153
|
//# sourceMappingURL=hexclave-config-file.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hexclave-config-file.js","names":["t","parser"],"sources":["../src/hexclave-config-file.ts"],"sourcesContent":["import * as parser from \"@babel/parser\";\nimport * as t from \"@babel/types\";\nimport { isValidConfig, normalize } from \"./config/format\";\n\nexport const showOnboardingHexclaveConfigValue = \"show-onboarding\";\n\nconst DEFAULT_CONFIG_IMPORT_PACKAGE = \"@hexclave/js\";\n\n/**\n * Renders a config object into the source text of a `stack.config.ts` file.\n *\n * Browser-safe: kept here (next to `parseHexclaveConfigFileContent`) instead of in\n * `config-rendering.ts` so dashboard client code can render config files\n * without pulling in `fs` / `path`.\n */\nexport function renderConfigFileContent(config: unknown, importPackage?: string): string {\n if (!isValidConfig(config)) {\n throw new Error(\"Invalid config: expected a plain object.\");\n }\n\n const droppedKeys: string[] = [];\n const normalizedConfig = normalize(config, {\n onDotIntoNonObject: \"ignore\",\n onDotIntoNull: \"empty-object\",\n droppedKeys,\n });\n if (droppedKeys.length > 0) {\n throw new Error(`Config has conflicting keys that would be dropped during normalization: ${droppedKeys.map(k => JSON.stringify(k)).join(\", \")}`);\n }\n const pkg = importPackage ?? DEFAULT_CONFIG_IMPORT_PACKAGE;\n // Import the `HexclaveConfig` type from the package's lightweight `/config`\n // entrypoint, which is free of framework runtime code and therefore safe for\n // tooling (e.g. the local dashboard) to load in a plain Node context. Only the\n // Hexclave-branded packages expose this subpath; legacy `@stackframe/*`\n // releases predate it, so fall back to their package root.\n const importSpecifier = pkg.startsWith(\"@hexclave/\") ? `${pkg}/config` : pkg;\n const importLine = `import type { HexclaveConfig } from \"${importSpecifier}\";`;\n return `${importLine}\\n\\nexport const config: HexclaveConfig = ${JSON.stringify(normalizedConfig, null, 2)};\\n`;\n}\n\ntype ParsedStackConfig = Record<string, unknown> | typeof showOnboardingHexclaveConfigValue;\n\nfunction unwrapStaticConfigExpression(expression: t.Expression): t.Expression {\n if (\n t.isTSAsExpression(expression)\n || t.isTSSatisfiesExpression(expression)\n || t.isTSTypeAssertion(expression)\n || t.isTSNonNullExpression(expression)\n ) {\n return unwrapStaticConfigExpression(expression.expression);\n }\n return expression;\n}\n\nfunction evaluateStaticConfigExpression(expression: t.Expression): unknown {\n const unwrapped = unwrapStaticConfigExpression(expression);\n if (t.isStringLiteral(unwrapped)) return unwrapped.value;\n if (t.isBooleanLiteral(unwrapped)) return unwrapped.value;\n if (t.isNumericLiteral(unwrapped)) return unwrapped.value;\n if (t.isNullLiteral(unwrapped)) return null;\n if (t.isIdentifier(unwrapped) && unwrapped.name === \"undefined\") return undefined;\n if (t.isUnaryExpression(unwrapped) && unwrapped.operator === \"-\" && t.isNumericLiteral(unwrapped.argument)) {\n return -unwrapped.argument.value;\n }\n if (t.isArrayExpression(unwrapped)) {\n return unwrapped.elements.map((element) => {\n if (element == null || t.isSpreadElement(element)) {\n throw new Error(\"Config arrays cannot contain holes or spreads.\");\n }\n return evaluateStaticConfigExpression(element);\n });\n }\n if (t.isObjectExpression(unwrapped)) {\n const result: Record<string, unknown> = {};\n for (const property of unwrapped.properties) {\n if (t.isSpreadElement(property)) {\n throw new Error(\"Config objects cannot contain spreads.\");\n }\n if (property.computed) {\n throw new Error(\"Config object keys cannot be computed.\");\n }\n const key = t.isIdentifier(property.key)\n ? property.key.name\n : t.isStringLiteral(property.key) || t.isNumericLiteral(property.key)\n ? String(property.key.value)\n : null;\n if (key == null) {\n throw new Error(\"Unsupported config object key.\");\n }\n if (t.isObjectMethod(property)) {\n throw new Error(\"Config objects cannot contain methods.\");\n }\n if (!t.isExpression(property.value)) {\n throw new Error(\"Unsupported config object value.\");\n }\n result[key] = evaluateStaticConfigExpression(property.value);\n }\n return result;\n }\n throw new Error(`Unsupported config expression: ${unwrapped.type}`);\n}\n\nexport function parseHexclaveConfigFileContent(content: string, filePath: string): ParsedStackConfig {\n if (content.trim() === \"\") return {};\n const ast = parser.parse(content, {\n sourceType: \"module\",\n plugins: [\"typescript\"],\n });\n\n for (const statement of ast.program.body) {\n if (!t.isExportNamedDeclaration(statement) || !t.isVariableDeclaration(statement.declaration)) {\n continue;\n }\n for (const declaration of statement.declaration.declarations) {\n if (!t.isIdentifier(declaration.id) || declaration.id.name !== \"config\") {\n continue;\n }\n if (declaration.init == null || !t.isExpression(declaration.init)) {\n throw new Error(`Config export in ${filePath} must have an initializer.`);\n }\n return evaluateStaticConfigExpression(declaration.init) as ParsedStackConfig;\n }\n }\n\n throw new Error(`Invalid config in ${filePath}. The file must export a plain \\`config\\` object or \"show-onboarding\".`);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hexclave-config-file.js","names":["t","parser"],"sources":["../src/hexclave-config-file.ts"],"sourcesContent":["import * as parser from \"@babel/parser\";\nimport * as t from \"@babel/types\";\nimport { isValidConfig, normalize } from \"./config/format\";\n\nexport const showOnboardingHexclaveConfigValue = \"show-onboarding\";\n\nconst DEFAULT_CONFIG_IMPORT_PACKAGE = \"@hexclave/js\";\n\n/**\n * Renders a config object into the source text of a `stack.config.ts` file.\n *\n * Browser-safe: kept here (next to `parseHexclaveConfigFileContent`) instead of in\n * `config-rendering.ts` so dashboard client code can render config files\n * without pulling in `fs` / `path`.\n */\nexport function renderConfigFileContent(config: unknown, importPackage?: string): string {\n if (!isValidConfig(config)) {\n throw new Error(\"Invalid config: expected a plain object.\");\n }\n\n const droppedKeys: string[] = [];\n const normalizedConfig = normalize(config, {\n onDotIntoNonObject: \"ignore\",\n onDotIntoNull: \"empty-object\",\n droppedKeys,\n });\n if (droppedKeys.length > 0) {\n throw new Error(`Config has conflicting keys that would be dropped during normalization: ${droppedKeys.map(k => JSON.stringify(k)).join(\", \")}`);\n }\n const pkg = importPackage ?? DEFAULT_CONFIG_IMPORT_PACKAGE;\n // Import the `HexclaveConfig` type from the package's lightweight `/config`\n // entrypoint, which is free of framework runtime code and therefore safe for\n // tooling (e.g. the local dashboard) to load in a plain Node context. Only the\n // Hexclave-branded packages expose this subpath; legacy `@stackframe/*`\n // releases predate it, so fall back to their package root.\n const importSpecifier = pkg.startsWith(\"@hexclave/\") ? `${pkg}/config` : pkg;\n const importLine = `import type { HexclaveConfig } from \"${importSpecifier}\";`;\n return `${importLine}\\n\\nexport const config: HexclaveConfig = ${JSON.stringify(normalizedConfig, null, 2)};\\n`;\n}\n\ntype ParsedStackConfig = Record<string, unknown> | typeof showOnboardingHexclaveConfigValue;\n\nfunction unwrapStaticConfigExpression(expression: t.Expression): t.Expression {\n if (\n t.isTSAsExpression(expression)\n || t.isTSSatisfiesExpression(expression)\n || t.isTSTypeAssertion(expression)\n || t.isTSNonNullExpression(expression)\n ) {\n return unwrapStaticConfigExpression(expression.expression);\n }\n return expression;\n}\n\nfunction evaluateStaticConfigExpression(expression: t.Expression): unknown {\n const unwrapped = unwrapStaticConfigExpression(expression);\n if (t.isStringLiteral(unwrapped)) return unwrapped.value;\n if (t.isBooleanLiteral(unwrapped)) return unwrapped.value;\n if (t.isNumericLiteral(unwrapped)) return unwrapped.value;\n if (t.isNullLiteral(unwrapped)) return null;\n if (t.isIdentifier(unwrapped) && unwrapped.name === \"undefined\") return undefined;\n if (t.isUnaryExpression(unwrapped) && unwrapped.operator === \"-\" && t.isNumericLiteral(unwrapped.argument)) {\n return -unwrapped.argument.value;\n }\n if (t.isArrayExpression(unwrapped)) {\n return unwrapped.elements.map((element) => {\n if (element == null || t.isSpreadElement(element)) {\n throw new Error(\"Config arrays cannot contain holes or spreads.\");\n }\n return evaluateStaticConfigExpression(element);\n });\n }\n if (t.isObjectExpression(unwrapped)) {\n const result: Record<string, unknown> = {};\n for (const property of unwrapped.properties) {\n if (t.isSpreadElement(property)) {\n throw new Error(\"Config objects cannot contain spreads.\");\n }\n if (property.computed) {\n throw new Error(\"Config object keys cannot be computed.\");\n }\n const key = t.isIdentifier(property.key)\n ? property.key.name\n : t.isStringLiteral(property.key) || t.isNumericLiteral(property.key)\n ? String(property.key.value)\n : null;\n if (key == null) {\n throw new Error(\"Unsupported config object key.\");\n }\n if (t.isObjectMethod(property)) {\n throw new Error(\"Config objects cannot contain methods.\");\n }\n if (!t.isExpression(property.value)) {\n throw new Error(\"Unsupported config object value.\");\n }\n result[key] = evaluateStaticConfigExpression(property.value);\n }\n return result;\n }\n throw new Error(`Unsupported config expression: ${unwrapped.type}`);\n}\n\n/**\n * Like {@link parseHexclaveConfigFileContent}, but returns `null` instead of\n * throwing when the file is not a plain static config (e.g. it wraps the config\n * in a helper call, references imported values, or has a syntax error). Useful\n * for deciding whether a config file can be safely regenerated deterministically\n * or whether it has custom structure that must be preserved.\n */\nexport function tryParseHexclaveConfigFileContent(content: string, filePath: string): ParsedStackConfig | null {\n try {\n return parseHexclaveConfigFileContent(content, filePath);\n } catch {\n return null;\n }\n}\n\n/**\n * Returns whether `content` parses as a module that exports a `config` binding.\n * Used as a lightweight structural sanity check after editing config files whose\n * values can't be evaluated by our loader (e.g. they import external text\n * files), where a full semantic comparison isn't possible.\n */\nexport function hexclaveConfigFileExportsConfig(content: string, filePath: string): boolean {\n let ast: parser.ParseResult<t.File>;\n try {\n ast = parser.parse(content, {\n sourceType: \"module\",\n sourceFilename: filePath,\n plugins: [\"typescript\", \"importAttributes\"],\n });\n } catch {\n return false;\n }\n for (const statement of ast.program.body) {\n if (!t.isExportNamedDeclaration(statement)) {\n continue;\n }\n // Ignore type-only exports (`export type { config }`): they don't produce a\n // runtime `config` value, so they must not satisfy the structural check.\n if (statement.exportKind === \"type\") {\n continue;\n }\n if (t.isVariableDeclaration(statement.declaration)) {\n for (const declaration of statement.declaration.declarations) {\n if (t.isIdentifier(declaration.id) && declaration.id.name === \"config\" && declaration.init != null) {\n return true;\n }\n }\n }\n for (const specifier of statement.specifiers) {\n if (t.isExportSpecifier(specifier) && specifier.exportKind !== \"type\") {\n const exportedName = t.isIdentifier(specifier.exported) ? specifier.exported.name : specifier.exported.value;\n if (exportedName === \"config\") {\n return true;\n }\n }\n }\n }\n return false;\n}\n\n/**\n * Returns the relative import sources (those starting with `./` or `../`)\n * declared in `content`. Used to discover the external files a config update may\n * touch — e.g. `import x from \"./welcome-email.tsx\" with { type: \"text\" }` — so\n * they can be snapshotted and rolled back if an in-place update fails. Returns\n * an empty array if the file can't be parsed.\n */\nexport function getRelativeImportSpecifiers(content: string): string[] {\n let ast: parser.ParseResult<t.File>;\n try {\n ast = parser.parse(content, {\n sourceType: \"module\",\n plugins: [\"typescript\", \"importAttributes\"],\n });\n } catch {\n return [];\n }\n const sources: string[] = [];\n for (const statement of ast.program.body) {\n if (t.isImportDeclaration(statement)) {\n const source = statement.source.value;\n if (source.startsWith(\"./\") || source.startsWith(\"../\")) {\n sources.push(source);\n }\n }\n }\n return sources;\n}\n\nexport function parseHexclaveConfigFileContent(content: string, filePath: string): ParsedStackConfig {\n if (content.trim() === \"\") return {};\n const ast = parser.parse(content, {\n sourceType: \"module\",\n plugins: [\"typescript\", \"importAttributes\"],\n });\n\n for (const statement of ast.program.body) {\n if (!t.isExportNamedDeclaration(statement) || !t.isVariableDeclaration(statement.declaration)) {\n continue;\n }\n for (const declaration of statement.declaration.declarations) {\n if (!t.isIdentifier(declaration.id) || declaration.id.name !== \"config\") {\n continue;\n }\n if (declaration.init == null || !t.isExpression(declaration.init)) {\n throw new Error(`Config export in ${filePath} must have an initializer.`);\n }\n return evaluateStaticConfigExpression(declaration.init) as ParsedStackConfig;\n }\n }\n\n throw new Error(`Invalid config in ${filePath}. The file must export a plain \\`config\\` object or \"show-onboarding\".`);\n}\n"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { KnownErrors } from "../known-errors.js";
|
|
|
3
3
|
import { MoneyAmount } from "../utils/currency-constants.js";
|
|
4
4
|
import { RestrictedReason, branchConfigSourceSchema } from "../schema-fields.js";
|
|
5
5
|
import { AccessToken, InternalSession, RefreshToken } from "../sessions.js";
|
|
6
|
-
import { MetricsResponse, MetricsUserCounts, UserActivityResponse } from "./admin-metrics.js";
|
|
6
|
+
import { AnalyticsClickmapDevice, AnalyticsClickmapKind, AnalyticsClickmapResponse, AnalyticsClickmapTokenResponse, MetricsResponse, MetricsUserCounts, UserActivityResponse } from "./admin-metrics.js";
|
|
7
7
|
import { AnalyticsQueryOptions, AnalyticsQueryResponse } from "./crud/analytics.js";
|
|
8
8
|
import { EmailOutboxCrud } from "./crud/email-outbox.js";
|
|
9
9
|
import { InternalEmailsCrud } from "./crud/emails.js";
|
|
@@ -127,6 +127,24 @@ declare class HexclaveAdminInterface extends HexclaveServerInterface {
|
|
|
127
127
|
until?: string;
|
|
128
128
|
}): Promise<MetricsResponse>;
|
|
129
129
|
getUserActivity(userId: string): Promise<UserActivityResponse>;
|
|
130
|
+
getAnalyticsClickmap(options: {
|
|
131
|
+
kind: AnalyticsClickmapKind;
|
|
132
|
+
member_user_ids?: string[];
|
|
133
|
+
route_path?: string;
|
|
134
|
+
route_regex?: string;
|
|
135
|
+
url_pattern?: string;
|
|
136
|
+
user_id?: string;
|
|
137
|
+
replay_id?: string;
|
|
138
|
+
device?: AnalyticsClickmapDevice;
|
|
139
|
+
viewport_width_min?: number;
|
|
140
|
+
viewport_width_max?: number;
|
|
141
|
+
sampling?: number;
|
|
142
|
+
since: string;
|
|
143
|
+
until: string;
|
|
144
|
+
}): Promise<AnalyticsClickmapResponse>;
|
|
145
|
+
createAnalyticsClickmapToken(options: {
|
|
146
|
+
origin: string;
|
|
147
|
+
}): Promise<AnalyticsClickmapTokenResponse>;
|
|
130
148
|
getMetricsUserCounts(): Promise<MetricsUserCounts>;
|
|
131
149
|
sendTestEmail(data: {
|
|
132
150
|
recipient_email: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-interface.d.ts","names":[],"sources":["../../src/interface/admin-interface.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"admin-interface.d.ts","names":[],"sources":["../../src/interface/admin-interface.ts"],"mappings":"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"}
|
|
@@ -184,6 +184,20 @@ var HexclaveAdminInterface = class extends __server_interface_js.HexclaveServerI
|
|
|
184
184
|
async getUserActivity(userId) {
|
|
185
185
|
return await (await this.sendAdminRequest(___utils_urls_js.urlString`/internal/user-activity?user_id=${userId}`, { method: "GET" }, null)).json();
|
|
186
186
|
}
|
|
187
|
+
async getAnalyticsClickmap(options) {
|
|
188
|
+
return await (await this.sendAdminRequest("/internal/analytics/clickmap", {
|
|
189
|
+
method: "POST",
|
|
190
|
+
headers: { "content-type": "application/json" },
|
|
191
|
+
body: JSON.stringify(options)
|
|
192
|
+
}, null)).json();
|
|
193
|
+
}
|
|
194
|
+
async createAnalyticsClickmapToken(options) {
|
|
195
|
+
return await (await this.sendAdminRequest("/internal/analytics/clickmap-token", {
|
|
196
|
+
method: "POST",
|
|
197
|
+
headers: { "content-type": "application/json" },
|
|
198
|
+
body: JSON.stringify(options)
|
|
199
|
+
}, null)).json();
|
|
200
|
+
}
|
|
187
201
|
async getMetricsUserCounts() {
|
|
188
202
|
return await (await this.sendAdminRequest("/internal/metrics/user-counts", { method: "GET" }, null)).json();
|
|
189
203
|
}
|