@asiyst/sdk 0.1.6 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -3
- package/dist/index.cjs +265 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -3
- package/dist/index.d.ts +50 -3
- package/dist/index.js +262 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,13 +20,27 @@ npx @asiyst/cli init
|
|
|
20
20
|
|
|
21
21
|
## Usage
|
|
22
22
|
|
|
23
|
+
Project ID is required. The value must be the public Project ID for the target Asiyst project, not the developer account user ID and not the internal Supabase UUID.
|
|
24
|
+
|
|
23
25
|
```ts
|
|
24
26
|
import { Asiyst } from "@asiyst/sdk";
|
|
25
27
|
|
|
26
28
|
await Asiyst.init({
|
|
27
|
-
projectId: "
|
|
28
|
-
publicKey: "
|
|
29
|
+
projectId: "<PUBLIC_PROJECT_ID>",
|
|
30
|
+
publicKey: "<PUBLIC_KEY>",
|
|
31
|
+
avatarId: "<PUBLIC_AVATAR_ID>",
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Do not pass a secret API key as `publicKey` or omit `projectId`.
|
|
36
|
+
|
|
37
|
+
`avatarId` selects the avatar that the dashboard configured for this project. It is a public identifier, not an authorization credential. The SDK sends it as a selection hint while the Asiyst API still authenticates and authorizes the project with the public project key.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
await Asiyst.init({
|
|
41
|
+
publicKey: "<PUBLIC_KEY>",
|
|
29
42
|
});
|
|
43
|
+
// throws: Asiyst SDK: projectId is required.
|
|
30
44
|
```
|
|
31
45
|
|
|
32
46
|
Mark important controls so the assistant can find them across layouts:
|
|
@@ -41,7 +55,7 @@ Mark important controls so the assistant can find them across layouts:
|
|
|
41
55
|
</button>
|
|
42
56
|
```
|
|
43
57
|
|
|
44
|
-
The production API base is `https://
|
|
58
|
+
The production API base is `https://nqhxpgsjofzqudyqkqib.supabase.co/functions/v1/api`. It is used by default and can only be overridden explicitly through `apiBaseUrl` for a controlled non-production deployment.
|
|
45
59
|
|
|
46
60
|
If Cloud is unreachable, the SDK keeps a fallback avatar configuration and exposes `getConnectionStatus()` as `offline`. Conversation replies and task plans are not invented locally; those requests fail until Cloud responds.
|
|
47
61
|
|
package/dist/index.cjs
CHANGED
|
@@ -59,6 +59,9 @@ var ALL_ACTION_KINDS = [
|
|
|
59
59
|
"scroll",
|
|
60
60
|
"type",
|
|
61
61
|
"select",
|
|
62
|
+
"open",
|
|
63
|
+
"close",
|
|
64
|
+
"filter",
|
|
62
65
|
"open-menu",
|
|
63
66
|
"open-modal",
|
|
64
67
|
"search",
|
|
@@ -68,8 +71,8 @@ var ALL_ACTION_KINDS = [
|
|
|
68
71
|
];
|
|
69
72
|
|
|
70
73
|
// src/core/constants.ts
|
|
71
|
-
var SDK_VERSION = "0.1.
|
|
72
|
-
var DEFAULT_API_BASE_URL = "https://
|
|
74
|
+
var SDK_VERSION = "0.1.9" ;
|
|
75
|
+
var DEFAULT_API_BASE_URL = "https://nqhxpgsjofzqudyqkqib.supabase.co/functions/v1/api";
|
|
73
76
|
var CONFIG_SCHEMA_VERSION = 1;
|
|
74
77
|
var HOST_ELEMENT_ID = "asiyst-host";
|
|
75
78
|
var DATA_ATTR = "data-asiyst";
|
|
@@ -124,6 +127,19 @@ var ANCHORS = [
|
|
|
124
127
|
"top-right",
|
|
125
128
|
"top-left"
|
|
126
129
|
];
|
|
130
|
+
var PUBLIC_IDENTIFIER_PATTERN = /^(?=.{1,128}$)[A-Za-z0-9_][A-Za-z0-9_-]*$/;
|
|
131
|
+
function isValidPublicIdentifier(value) {
|
|
132
|
+
if (typeof value !== "string") return false;
|
|
133
|
+
const trimmed = value.trim();
|
|
134
|
+
if (!trimmed || trimmed.length > 128) return false;
|
|
135
|
+
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(trimmed)) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
return PUBLIC_IDENTIFIER_PATTERN.test(trimmed);
|
|
139
|
+
}
|
|
140
|
+
function isValidProjectId(value) {
|
|
141
|
+
return isValidPublicIdentifier(value);
|
|
142
|
+
}
|
|
127
143
|
function isRecord(value) {
|
|
128
144
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
129
145
|
}
|
|
@@ -152,6 +168,88 @@ function parseAllowedActions(value, fallback) {
|
|
|
152
168
|
}
|
|
153
169
|
return next.length > 0 ? next : [...fallback];
|
|
154
170
|
}
|
|
171
|
+
function parseStringList(value) {
|
|
172
|
+
if (typeof value === "string") {
|
|
173
|
+
return value.split(",").map((item) => sanitizeText(item.trim(), 200)).filter(Boolean);
|
|
174
|
+
}
|
|
175
|
+
if (!Array.isArray(value)) {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
return value.filter((item) => typeof item === "string").map((item) => sanitizeText(item.trim(), 200)).filter(Boolean);
|
|
179
|
+
}
|
|
180
|
+
function parseRule(value) {
|
|
181
|
+
if (!isRecord(value)) return null;
|
|
182
|
+
const action = typeof value.action === "string" ? sanitizeText(value.action, 64) : void 0;
|
|
183
|
+
if (action && !ALL_ACTION_KINDS.includes(action)) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
const routeList = parseStringList(value.routes ?? value.route);
|
|
187
|
+
const domainList = parseStringList(value.domains ?? value.domain);
|
|
188
|
+
const hasAllowedValue = typeof value.allowed === "boolean";
|
|
189
|
+
const hasAnySemanticField = hasAllowedValue || typeof value.target === "string" || typeof value.route === "string" || routeList.length > 0 || typeof value.domain === "string" || domainList.length > 0 || typeof value.enabled === "boolean" || typeof value.sourceId === "string" || typeof value.dataSourceId === "string";
|
|
190
|
+
if (!hasAnySemanticField) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
const rule = {
|
|
194
|
+
action,
|
|
195
|
+
allowed: typeof value.allowed === "boolean" ? value.allowed : void 0,
|
|
196
|
+
target: typeof value.target === "string" ? sanitizeText(value.target, 200) : void 0,
|
|
197
|
+
route: typeof value.route === "string" ? sanitizeText(value.route, 200) : void 0,
|
|
198
|
+
routes: routeList,
|
|
199
|
+
domain: typeof value.domain === "string" ? sanitizeText(value.domain, 200) : void 0,
|
|
200
|
+
domains: domainList,
|
|
201
|
+
enabled: typeof value.enabled === "boolean" ? value.enabled : void 0,
|
|
202
|
+
sourceId: typeof value.sourceId === "string" ? sanitizeText(value.sourceId, 128) : void 0,
|
|
203
|
+
dataSourceId: typeof value.dataSourceId === "string" ? sanitizeText(value.dataSourceId, 128) : void 0
|
|
204
|
+
};
|
|
205
|
+
if (typeof value.allowed !== "undefined" && typeof value.allowed !== "boolean") {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
return rule;
|
|
209
|
+
}
|
|
210
|
+
function parseRules(value) {
|
|
211
|
+
if (!Array.isArray(value)) {
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
const rules = [];
|
|
215
|
+
for (const entry of value) {
|
|
216
|
+
const rule = parseRule(entry);
|
|
217
|
+
if (rule) {
|
|
218
|
+
rules.push(rule);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return rules;
|
|
222
|
+
}
|
|
223
|
+
function parseDataSources(value) {
|
|
224
|
+
if (!Array.isArray(value)) {
|
|
225
|
+
return [];
|
|
226
|
+
}
|
|
227
|
+
const next = [];
|
|
228
|
+
for (const entry of value) {
|
|
229
|
+
if (!isRecord(entry)) continue;
|
|
230
|
+
const id = typeof entry.id === "string" ? sanitizeText(entry.id, 128) : "";
|
|
231
|
+
if (!id) continue;
|
|
232
|
+
next.push({
|
|
233
|
+
id,
|
|
234
|
+
name: typeof entry.name === "string" ? sanitizeText(entry.name, 128) : void 0,
|
|
235
|
+
type: typeof entry.type === "string" ? sanitizeText(entry.type, 64) : void 0,
|
|
236
|
+
enabled: typeof entry.enabled === "boolean" ? entry.enabled : void 0,
|
|
237
|
+
url: typeof entry.url === "string" ? sanitizeText(entry.url, 400) : void 0,
|
|
238
|
+
method: typeof entry.method === "string" ? sanitizeText(entry.method, 20) : void 0,
|
|
239
|
+
headers: isRecord(entry.headers) ? (() => {
|
|
240
|
+
const safeHeaders = {};
|
|
241
|
+
for (const [key, value2] of Object.entries(entry.headers)) {
|
|
242
|
+
if (typeof value2 === "string") {
|
|
243
|
+
safeHeaders[sanitizeText(key, 64)] = sanitizeText(value2, 200);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return safeHeaders;
|
|
247
|
+
})() : void 0,
|
|
248
|
+
credentials: typeof entry.credentials === "string" ? "[redacted]" : void 0
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
return next;
|
|
252
|
+
}
|
|
155
253
|
function parseTheme(value) {
|
|
156
254
|
if (!isRecord(value)) {
|
|
157
255
|
return {};
|
|
@@ -222,6 +320,11 @@ function fallbackConfig() {
|
|
|
222
320
|
},
|
|
223
321
|
mode: "guided",
|
|
224
322
|
allowedActions: ["navigate", "highlight", "scroll", "wait", "explain", "complete"],
|
|
323
|
+
allowedDomains: [],
|
|
324
|
+
allowedRoutes: [],
|
|
325
|
+
blockedRoutes: [],
|
|
326
|
+
rules: [],
|
|
327
|
+
dataSources: [],
|
|
225
328
|
elementSelectors: {}
|
|
226
329
|
};
|
|
227
330
|
}
|
|
@@ -245,22 +348,41 @@ function normalizeProjectConfig(raw) {
|
|
|
245
348
|
behavior: { ...base.behavior, ...parseBehavior(raw.behavior) },
|
|
246
349
|
mode: raw.mode === "assist" ? "assist" : "guided",
|
|
247
350
|
allowedActions: parseAllowedActions(raw.allowedActions, base.allowedActions),
|
|
351
|
+
allowedDomains: parseStringList(raw.allowedDomains ?? raw.allowed_domains),
|
|
352
|
+
allowedRoutes: parseStringList(raw.allowedRoutes ?? raw.allowed_routes),
|
|
353
|
+
blockedRoutes: parseStringList(raw.blockedRoutes ?? raw.blocked_routes),
|
|
354
|
+
rules: parseRules(raw.rules ?? raw.avatarRules),
|
|
355
|
+
dataSources: parseDataSources(raw.dataSources ?? raw.enabledDataSources),
|
|
248
356
|
elementSelectors: parseElementSelectors(raw.elementSelectors)
|
|
249
357
|
};
|
|
250
358
|
}
|
|
251
359
|
function validateInitOptions(options) {
|
|
252
|
-
|
|
253
|
-
|
|
360
|
+
const projectIdValue = typeof options.projectId === "string" ? options.projectId.trim() : "";
|
|
361
|
+
if (!projectIdValue) {
|
|
362
|
+
throw new ConfigurationError("Asiyst SDK: projectId is required.");
|
|
363
|
+
}
|
|
364
|
+
if (!isValidProjectId(projectIdValue)) {
|
|
365
|
+
throw new ConfigurationError("Asiyst SDK: projectId is invalid. Use a public Project ID.");
|
|
254
366
|
}
|
|
255
367
|
if (typeof options.publicKey !== "string" || !options.publicKey.trim()) {
|
|
256
368
|
throw new ConfigurationError("publicKey is required");
|
|
257
369
|
}
|
|
258
|
-
if (
|
|
370
|
+
if (projectIdValue.length > 128 || options.publicKey.trim().length > 256) {
|
|
259
371
|
throw new ConfigurationError("project credentials exceed allowed length");
|
|
260
372
|
}
|
|
373
|
+
const avatarId = typeof options.avatarId === "string" ? options.avatarId.trim() : "";
|
|
374
|
+
if (options.avatarId !== void 0 && (!avatarId || avatarId.length > 128 || !/^[A-Za-z0-9_-]+$/.test(avatarId))) {
|
|
375
|
+
throw new ConfigurationError("Asiyst SDK: avatarId is invalid.");
|
|
376
|
+
}
|
|
377
|
+
const position = options.position === void 0 ? void 0 : ANCHORS.includes(options.position) ? options.position : void 0;
|
|
378
|
+
if (options.position !== void 0 && !position) {
|
|
379
|
+
throw new ConfigurationError("Asiyst SDK: position is invalid.");
|
|
380
|
+
}
|
|
261
381
|
return {
|
|
262
|
-
projectId:
|
|
263
|
-
publicKey: options.publicKey.trim()
|
|
382
|
+
projectId: projectIdValue,
|
|
383
|
+
publicKey: options.publicKey.trim(),
|
|
384
|
+
avatarId: avatarId || void 0,
|
|
385
|
+
position
|
|
264
386
|
};
|
|
265
387
|
}
|
|
266
388
|
|
|
@@ -311,6 +433,7 @@ var HttpTransport = class {
|
|
|
311
433
|
"Content-Type": "application/json",
|
|
312
434
|
"X-Asiyst-Project-Id": this.options.projectId,
|
|
313
435
|
"X-Asiyst-Public-Key": this.options.publicKey,
|
|
436
|
+
...this.options.avatarId ? { "X-Asiyst-Avatar-Id": this.options.avatarId } : {},
|
|
314
437
|
"X-Asiyst-SDK-Version": SDK_VERSION
|
|
315
438
|
},
|
|
316
439
|
body: req.body === void 0 ? void 0 : JSON.stringify(req.body),
|
|
@@ -540,6 +663,7 @@ var ConfigManager = class {
|
|
|
540
663
|
return {
|
|
541
664
|
...base,
|
|
542
665
|
mode: this.options.mode ?? base.mode,
|
|
666
|
+
position: this.options.position ?? base.position,
|
|
543
667
|
allowedActions: this.options.allowedActions ?? base.allowedActions
|
|
544
668
|
};
|
|
545
669
|
}
|
|
@@ -1637,14 +1761,110 @@ var AvatarController = class {
|
|
|
1637
1761
|
};
|
|
1638
1762
|
|
|
1639
1763
|
// src/interaction/permissions.ts
|
|
1640
|
-
function
|
|
1764
|
+
function normalizeHost(host) {
|
|
1765
|
+
return host.replace(/^https?:\/\//i, "").replace(/\/$/, "").toLowerCase();
|
|
1766
|
+
}
|
|
1767
|
+
function matchesRoutePattern(pathname, pattern) {
|
|
1768
|
+
const candidate = pathname;
|
|
1769
|
+
const normalized = pattern.trim();
|
|
1770
|
+
if (!normalized) {
|
|
1771
|
+
return false;
|
|
1772
|
+
}
|
|
1773
|
+
const escaped = normalized.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\\\*/g, ".*");
|
|
1774
|
+
return new RegExp(`^${escaped}$`, "i").test(candidate);
|
|
1775
|
+
}
|
|
1776
|
+
function isLikelyJavaScriptUrl(value) {
|
|
1777
|
+
const lower = value.trim().toLowerCase();
|
|
1778
|
+
return lower.startsWith("javascript:") || lower.startsWith("data:") || lower.startsWith("vbscript:") || lower.includes("eval(") || lower.includes("new function") || lower.includes("document.cookie");
|
|
1779
|
+
}
|
|
1780
|
+
function validateWebsiteDomain(config, currentUrl) {
|
|
1781
|
+
const allowedDomains = config.allowedDomains.map((domain) => normalizeHost(domain));
|
|
1782
|
+
if (allowedDomains.length === 0) {
|
|
1783
|
+
return { allowed: true };
|
|
1784
|
+
}
|
|
1785
|
+
try {
|
|
1786
|
+
const parsed = new URL(currentUrl);
|
|
1787
|
+
const host = normalizeHost(parsed.host);
|
|
1788
|
+
const allowed = allowedDomains.some((domain) => host === domain || host.endsWith(`.${domain}`));
|
|
1789
|
+
if (!allowed) {
|
|
1790
|
+
return { allowed: false, reason: "DOMAIN_NOT_AUTHORIZED" };
|
|
1791
|
+
}
|
|
1792
|
+
return { allowed: true };
|
|
1793
|
+
} catch {
|
|
1794
|
+
return { allowed: false, reason: "DOMAIN_NOT_AUTHORIZED" };
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
function canNavigateTo(config, targetUrl, currentUrl) {
|
|
1798
|
+
if (!targetUrl || typeof targetUrl !== "string") {
|
|
1799
|
+
return { allowed: false, reason: "ACTION_NOT_PERMITTED" };
|
|
1800
|
+
}
|
|
1801
|
+
if (isLikelyJavaScriptUrl(targetUrl)) {
|
|
1802
|
+
return { allowed: false, reason: "ACTION_NOT_PERMITTED" };
|
|
1803
|
+
}
|
|
1804
|
+
let target;
|
|
1805
|
+
try {
|
|
1806
|
+
target = new URL(targetUrl, currentUrl);
|
|
1807
|
+
} catch {
|
|
1808
|
+
return { allowed: false, reason: "ACTION_NOT_PERMITTED" };
|
|
1809
|
+
}
|
|
1810
|
+
if (!["http:", "https:"].includes(target.protocol)) {
|
|
1811
|
+
return { allowed: false, reason: "ACTION_NOT_PERMITTED" };
|
|
1812
|
+
}
|
|
1813
|
+
const domainCheck = validateWebsiteDomain(config, currentUrl);
|
|
1814
|
+
if (!domainCheck.allowed) {
|
|
1815
|
+
return domainCheck;
|
|
1816
|
+
}
|
|
1817
|
+
const host = normalizeHost(target.host);
|
|
1818
|
+
const allowedDomains = config.allowedDomains.map((domain) => normalizeHost(domain));
|
|
1819
|
+
if (allowedDomains.length > 0 && !allowedDomains.some((domain) => host === domain || host.endsWith(`.${domain}`))) {
|
|
1820
|
+
return { allowed: false, reason: "DOMAIN_NOT_ALLOWED" };
|
|
1821
|
+
}
|
|
1822
|
+
const pathname = target.pathname || "/";
|
|
1823
|
+
if (config.blockedRoutes.some((route) => matchesRoutePattern(pathname, route))) {
|
|
1824
|
+
return { allowed: false, reason: "ROUTE_BLOCKED" };
|
|
1825
|
+
}
|
|
1826
|
+
if (config.allowedRoutes.length > 0 && !config.allowedRoutes.some((route) => matchesRoutePattern(pathname, route))) {
|
|
1827
|
+
return { allowed: false, reason: "ROUTE_NOT_PERMITTED" };
|
|
1828
|
+
}
|
|
1829
|
+
return { allowed: true };
|
|
1830
|
+
}
|
|
1831
|
+
function evaluateActionPermission(action, config, currentUrl, target) {
|
|
1832
|
+
const explicitRule = config.rules.find((rule) => rule.action === action && rule.enabled !== false);
|
|
1833
|
+
if (explicitRule && typeof explicitRule.allowed === "boolean") {
|
|
1834
|
+
if (!explicitRule.allowed) {
|
|
1835
|
+
return { allowed: false, reason: "ACTION_NOT_PERMITTED" };
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
if (!config.allowedActions.includes(action)) {
|
|
1839
|
+
return { allowed: false, reason: "ACTION_NOT_PERMITTED" };
|
|
1840
|
+
}
|
|
1841
|
+
if (action === "navigate") {
|
|
1842
|
+
if (!target) {
|
|
1843
|
+
return { allowed: true };
|
|
1844
|
+
}
|
|
1845
|
+
return canNavigateTo(config, target, currentUrl);
|
|
1846
|
+
}
|
|
1847
|
+
const allowedDomains = config.allowedDomains;
|
|
1848
|
+
if (allowedDomains.length > 0) {
|
|
1849
|
+
const domainCheck = validateWebsiteDomain(config, currentUrl);
|
|
1850
|
+
if (!domainCheck.allowed) {
|
|
1851
|
+
return domainCheck;
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
return { allowed: true };
|
|
1855
|
+
}
|
|
1856
|
+
function isActionAllowed(action, config, source, currentUrl, target) {
|
|
1641
1857
|
if (source === "developer") {
|
|
1642
1858
|
return true;
|
|
1643
1859
|
}
|
|
1644
|
-
|
|
1860
|
+
if (currentUrl) {
|
|
1861
|
+
return evaluateActionPermission(action, config, currentUrl, target).allowed;
|
|
1862
|
+
}
|
|
1863
|
+
return config.allowedActions.includes(action) && !config.rules.some((rule) => rule.action === action && rule.allowed === false);
|
|
1645
1864
|
}
|
|
1646
|
-
function assertActionAllowed(action, config, source) {
|
|
1647
|
-
|
|
1865
|
+
function assertActionAllowed(action, config, source, currentUrl, target) {
|
|
1866
|
+
const allowed = isActionAllowed(action, config, source, currentUrl, target);
|
|
1867
|
+
if (!allowed) {
|
|
1648
1868
|
throw new ActionNotAllowedError(`Action "${action}" is not permitted for this project`);
|
|
1649
1869
|
}
|
|
1650
1870
|
}
|
|
@@ -1674,7 +1894,12 @@ var InteractionEngine = class {
|
|
|
1674
1894
|
}
|
|
1675
1895
|
async execute(step, source) {
|
|
1676
1896
|
const config = this.getConfig();
|
|
1677
|
-
|
|
1897
|
+
const currentUrl = this.win.location.href;
|
|
1898
|
+
const target = step.url ?? (typeof step.target === "string" ? step.target : void 0);
|
|
1899
|
+
const allowed = this.evaluatePermission(step.action, config, currentUrl, target, source);
|
|
1900
|
+
if (!allowed.ok) {
|
|
1901
|
+
return { ok: false, waitedForUser: false, allowed: false, reason: allowed.reason ?? "ACTION_NOT_PERMITTED" };
|
|
1902
|
+
}
|
|
1678
1903
|
const wait = shouldWaitForUser(step.action, config.mode, step.waitForUser);
|
|
1679
1904
|
switch (step.action) {
|
|
1680
1905
|
case "explain":
|
|
@@ -1705,6 +1930,14 @@ var InteractionEngine = class {
|
|
|
1705
1930
|
throw new TaskExecutionError("Unsupported action");
|
|
1706
1931
|
}
|
|
1707
1932
|
}
|
|
1933
|
+
evaluatePermission(action, config, currentUrl, target, source) {
|
|
1934
|
+
try {
|
|
1935
|
+
assertActionAllowed(action, config, source, currentUrl, target);
|
|
1936
|
+
return { ok: true };
|
|
1937
|
+
} catch {
|
|
1938
|
+
return { ok: false, reason: "ACTION_NOT_PERMITTED" };
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1708
1941
|
async highlight(step, source, wait) {
|
|
1709
1942
|
if (!step.target) {
|
|
1710
1943
|
throw new TaskExecutionError("Highlight requires a target");
|
|
@@ -1888,6 +2121,11 @@ var TaskEngine = class {
|
|
|
1888
2121
|
}
|
|
1889
2122
|
this.move(TaskStatus.ActionStarted);
|
|
1890
2123
|
const result = await this.interaction.execute(step, source);
|
|
2124
|
+
if (!result.ok) {
|
|
2125
|
+
this.events.emit("asiyst:task:failed", { taskId: task.id, reason: result.reason ?? "ACTION_NOT_PERMITTED" });
|
|
2126
|
+
this.analytics.track("task_failed", { taskId: task.id });
|
|
2127
|
+
return this.finish(TaskStatus.Failed, result.reason ?? "ACTION_NOT_PERMITTED");
|
|
2128
|
+
}
|
|
1891
2129
|
if (result.waitedForUser && result.elementId) {
|
|
1892
2130
|
this.move(TaskStatus.WaitingForUser);
|
|
1893
2131
|
const clicked = await this.interaction.waitForElementClick(result.elementId, step.timeoutMs ?? 3e4);
|
|
@@ -2133,7 +2371,8 @@ var AsiystRuntime = class {
|
|
|
2133
2371
|
const transport = new HttpTransport({
|
|
2134
2372
|
apiBaseUrl: options.apiBaseUrl ?? DEFAULT_API_BASE_URL,
|
|
2135
2373
|
projectId: options.projectId,
|
|
2136
|
-
publicKey: options.publicKey
|
|
2374
|
+
publicKey: options.publicKey,
|
|
2375
|
+
avatarId: options.avatarId
|
|
2137
2376
|
});
|
|
2138
2377
|
this.cloud = new CloudClient(transport, options.projectId);
|
|
2139
2378
|
this.config = new ConfigManager(options, this.cloud, this.events);
|
|
@@ -2190,6 +2429,15 @@ var AsiystRuntime = class {
|
|
|
2190
2429
|
async start() {
|
|
2191
2430
|
this.events.emit("asiyst:initialized", { projectId: this.options.projectId });
|
|
2192
2431
|
const cfg = await isolateAsync(() => this.config.refresh(), this.config.get());
|
|
2432
|
+
const domainCheck = validateWebsiteDomain(cfg, window.location.href);
|
|
2433
|
+
if (!domainCheck.allowed) {
|
|
2434
|
+
this.connectionStatus = "disconnected";
|
|
2435
|
+
this.events.emit("asiyst:error", {
|
|
2436
|
+
code: "domain_not_authorized",
|
|
2437
|
+
message: "This website is not authorized for the current Asiyst project."
|
|
2438
|
+
});
|
|
2439
|
+
return;
|
|
2440
|
+
}
|
|
2193
2441
|
this.avatar.applyConfig(cfg);
|
|
2194
2442
|
this.avatar.show();
|
|
2195
2443
|
try {
|
|
@@ -2396,12 +2644,16 @@ exports.TargetNotFoundError = TargetNotFoundError;
|
|
|
2396
2644
|
exports.TaskExecutionError = TaskExecutionError;
|
|
2397
2645
|
exports.TaskStatus = TaskStatus;
|
|
2398
2646
|
exports.anchorToViewport = anchorToViewport;
|
|
2647
|
+
exports.canNavigateTo = canNavigateTo;
|
|
2399
2648
|
exports.canTransition = canTransition;
|
|
2400
2649
|
exports.computeAvatarDestination = computeAvatarDestination;
|
|
2650
|
+
exports.evaluateActionPermission = evaluateActionPermission;
|
|
2401
2651
|
exports.fallbackConfig = fallbackConfig;
|
|
2652
|
+
exports.isActionAllowed = isActionAllowed;
|
|
2402
2653
|
exports.isSafeSelector = isSafeSelector;
|
|
2403
2654
|
exports.normalizeProjectConfig = normalizeProjectConfig;
|
|
2404
2655
|
exports.sanitizeText = sanitizeText;
|
|
2405
2656
|
exports.validateInitOptions = validateInitOptions;
|
|
2657
|
+
exports.validateWebsiteDomain = validateWebsiteDomain;
|
|
2406
2658
|
//# sourceMappingURL=index.cjs.map
|
|
2407
2659
|
//# sourceMappingURL=index.cjs.map
|