@applitools/core-nlp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/LICENSE +26 -0
- package/dist/account.js +91 -0
- package/dist/ax-provider.js +46 -0
- package/dist/constants.js +16 -0
- package/dist/index.js +12 -0
- package/dist/messages.js +13 -0
- package/dist/nlp.js +185 -0
- package/dist/types.js +2 -0
- package/package.json +63 -0
- package/types/account.d.ts +43 -0
- package/types/ax-provider.d.ts +9 -0
- package/types/constants.d.ts +13 -0
- package/types/index.d.ts +5 -0
- package/types/messages.d.ts +7 -0
- package/types/nlp.d.ts +12 -0
- package/types/types.d.ts +107 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0](https://github.com/Applitools-Dev/sdk/compare/js/core-nlp@0.0.1...js/core-nlp@0.1.0) (2026-09-15)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* NLP authoring (eyes.run) for eyes-playwright via the Eyes NLP service | AD-13296 ([#3936](https://github.com/Applitools-Dev/sdk/issues/3936)) ([c0f81d1](https://github.com/Applitools-Dev/sdk/commit/c0f81d1d3237945001ddf918954ee22a962aea03))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* @applitools/core-base bumped to 1.39.0
|
|
14
|
+
#### Features
|
|
15
|
+
|
|
16
|
+
* NLP authoring (eyes.run) for eyes-playwright via the Eyes NLP service | AD-13296 ([#3936](https://github.com/Applitools-Dev/sdk/issues/3936)) ([c0f81d1](https://github.com/Applitools-Dev/sdk/commit/c0f81d1d3237945001ddf918954ee22a962aea03))
|
package/LICENSE
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
- -
|
|
2
|
+
SDK LICENSE AGREEMENT
|
|
3
|
+
IMPORTANT - PLEASE READ CAREFULLY THE TERMS OF THIS LICENSE AGREEMENT (“AGREEMENT”). BY INSTALLING, ACCESSING AND/OR USING THE SOFTWARE (AS DEFINED BELOW), YOU EXPRESSLY ACKNOWLEDGE AND AGREE THAT YOU, OR THE COMPANY YOU REPRESENT, (“YOU” OR “LICENSEE”) ARE ENTERING INTO A LEGAL AGREEMENT WITH APPLITOOLS LTD. AND ITS AFFILIATES (“APPLITOOLS”), AND HAVE UNDERSTOOD AND AGREE TO COMPLY WITH, AND BE LEGALLY BOUND BY, THE TERMS AND CONDITIONS OF THIS AGREEMENT. YOU HEREBY WAIVE ANY RIGHTS OR REQUIREMENTS UNDER ANY LAWS OR REGULATIONS IN ANY JURISDICTION WHICH REQUIRE AN ORIGINAL (NON-ELECTRONIC) SIGNATURE OR DELIVERY OR RETENTION OF NON-ELECTRONIC RECORDS, TO THE EXTENT PERMITTED UNDER APPLICABLE LAW.
|
|
4
|
+
THE SOFTWARE MAY BE USED SOLELY FOR YOUR PERSONAL, NON-COMMERCIAL PURPOSES. FOR COMMERCIAL PURPOSES PLEASE CONTACT THE REGIONAL APPLITOOLS BUSINESS REPRESENTATIVE.
|
|
5
|
+
1. Definitions. For purposes of this Agreement, the following capitalized terms shall have the following meaning:
|
|
6
|
+
1. “Documentation” means the user’s guides and technical manuals delivered by Applitools to Licensee.
|
|
7
|
+
2. “Feedback” means suggestions, comments or feedback (whether orally or in writing) with respect to the Software.
|
|
8
|
+
3. “Intellectual Property Rights” means all intangible legal rights, titles and interests evidenced by or embodied in all: (i) inventions (regardless of patentability and whether or not reduced to practice), improvements thereto, patents, patent applications, patent disclosures, together with all reissuances, continuations, continuations in part, revisions, extensions and reexaminations thereof; (ii) trademarks, service marks, trade dress, logos, trade names, corporate names, together with translations, adaptations, derivations and combinations thereof, including goodwill associated therewith, and applications, registrations, and renewals in connection therewith; (iii) any work of authorship, regardless of copyrightable, copyrightable works, copyrights (including moral rights), and applications, registrations and renewals in connection therewith; (iv) mask works and applications, registrations and renewals in connection therewith; (v) trade secrets and Confidential Information; and (vi) other proprietary rights and any other similar rights, in each case on a worldwide basis, and copies and tangible embodiments thereof, in whatever form or medium.
|
|
9
|
+
4. “License” means the right to use the Software pursuant to Section 2.1 to this Agreement.
|
|
10
|
+
5. “Software” means Applitools’ software development kit software in object or source code version, Documentation and any updates and upgrade thereto (to the extent delivered).
|
|
11
|
+
1. License
|
|
12
|
+
1. Grant of License. Subject to the terms and conditions of this Agreement, Applitools grants You, during the Term, a personal, non-exclusive, non-sublicensable, non-transferable, revocable license to: (i) use the Software solely for Your own personal (non-commercial) use and (ii) use and display Applitools’ Marks solely for the purpose of publicizing or advertising that You are using the Software.
|
|
13
|
+
2. Documentation. Applitools may make available Documentation to Licensee for Licensee to use solely in connection with Licensee’s use of the Software during the term of this Agreement. Licensee may print or copy the Documentation as needed for its own purposes provided that all copyright notices are included therein. The Documentation shall be considered the Confidential Information of Applitools.
|
|
14
|
+
1. Reservation of Rights; Use Restrictions. Other than the rights explicitly granted in this Agreement, Licensee shall have no other rights, express or implied, in the Software. Without limiting the generality of the foregoing, Licensee agrees and undertakes not to: (i) allow any third party to use the Software in any manner, including but not limited to, sell, lease, sublicense or distribute the Software, or any part thereof; (ii) modify, revise, or alter the Software or reverse engineer, decompile, disassemble or otherwise reduce to human-perceivable form the Software’s source code; (iii) copy or allow copies of the Software to be made; (iv) remove, alter or obscure any proprietary notice or identification, including copyright, trademark, patent or other notices, contained in or displayed on or via the Software; (v) use the Software to violate any applicable laws, rules or regulations, or for any unlawful, harmful, irresponsible, or inappropriate purpose, or in any manner that breaches this Agreement, and/or (vi) represent that it possesses any proprietary interest in the Software.
|
|
15
|
+
1. Third Party Software. Licensee acknowledges and agrees that any third party software (“Third Party Software”) that provided with the Software is provided under the terms of the license attached/linked thereto or, if no such license is attached, such Third Party Software is provided for free and on “AS IS” basis. Applitools is not liable for any losses or damages which may occur resulting from the use of any Third Party Software. Applitools does not possess any proprietary interest in such Third Party Software.
|
|
16
|
+
1. Open Source Licenses. The Software includes certain open source code software and materials (as shall be listed in the documentation of the Software) (“Open Source Software”) that are subject to their respective open source licenses (“Open Source Licenses”). Such Open Source Licenses contain a list of conditions with respect to warranty, copyright policy and other provisions. By executing this Agreement, Licensee undertakes to strictly comply with the terms and condition of the Open Source Licenses, as may be amended from time to time. In order to comply with the Open Source Licenses, Licensee shall read the respective licenses or notices, such list of Open Source Licenses may be amended from time to time by Applitools, at its sole discretion. In the event of any inconsistencies or conflicting provisions between the provisions of the Open Source Licenses and the provisions of this Agreement, the provisions of the Open Source Licenses shall prevail. Without derogating from the generality of the foregoing, it is clarified that any Open Source Software is provided on an “AS IS” basis, without indemnity or warranty of any kind, whether express or implied. For clarity, the representations and warranties set forth in Section 4 hereunder shall not apply to any Open Source Software.
|
|
17
|
+
1. Title & Ownership. APPLITOOLS DOES NOT SELL OR TRANSFER TITLE IN THE SOFTWARE, OR ANY PART THEREOF, TO LICENSEE. The Documentation, Software (excluding any Open Source Software and Third Party Software therein which are owned by their respective licensors) and/or any copies thereof, including without limitation any derivative works made (regardless of whether such derivative works were made and/or developed pursuant to the request and/or specifications of Licensee, and irrespective of any support and/or assistance Applitools may, will or had received from Licensee, or any third party on its behalf, with respect thereto), as well as any updates or upgrades thereto, if provided to Applitools pursuant to this Agreement, shall remain Applitools’ sole and exclusive property. All Intellectual Property Rights evidenced by or embodied in and/or attached/connected/related to the Software, or part thereof, are and shall be owned solely and exclusively by Applitools. Nothing in this Agreement shall constitute a waiver of Applitools’ Intellectual Property Rights under any law, or be in any way construed or interpreted as such. It is further agreed that to the extent Licensee provides Applitools with Feedback, Licensee acknowledges that any and all rights, including Intellectual Property Rights in such Feedback shall belong exclusively to Applitools and Licensee hereby irrevocably and unconditionally transfers and assigns to Applitools all intellectual property rights in such Feedback and waives any and all moral rights that Licensee may have in respect thereto. It is further understood that use of Feedback, if any, may be made by Applitools at its sole discretion, and that Applitools in no way shall be obliged to make use of any kind of the Feedback or part thereof.
|
|
18
|
+
1. Warranty. Applitools warrants that to its knowledge it has the right to grant the license under this Agreement. Applitools’ sole liability for any breach of this warranty or any other warranty under this Agreement shall be, at Applitools’ sole discretion: (i) to replace or repair the Software or the applicable portion thereof; or (ii) to terminate this Agreement.
|
|
19
|
+
2. Warranty Exclusions. The warranties set forth in Section 4 are contingent upon Licensee’s proper use of the Software, and shall not apply to damage caused by abuse, misuse, alteration, neglect or unauthorized repair or installation, or by the use or attempted use of Software other than that supplied and supported by Applitools. Applitools will use reasonable commercial efforts to repair or replace the Software or the applicable portion thereof, pursuant to the foregoing warranty within thirty (30) days of being so notified.
|
|
20
|
+
1. Warranty Disclaimers. AS BETWEEN LICENSEE AND APPLITOOLS, EXCEPT AS SET IN SECTION 4, THE SOFTWARE IS PROVIDED ON AN “AS IS” AND “AS AVAILABLE” BASIS WITHOUT WARRANTIES OF ANY KIND INCLUDING, WITHOUT LIMITATION, REPRESENTATIONS, WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR INTENDED OR PARTICULAR PURPOSE, TITLE, NON-INFRINGEMENT, THAT THE SOFTWARE WILL MEET LICENSEE’S REQUIREMENTS OR EXPECTATIONS OR WILL ACHIEVE ANY SPECIFIC RESULTS AND THOSE ARISING BY STATUTE OR FROM A COURSE OF DEALING OR USAGE OF TRADE. Applicable law may not allow the exclusion of certain warranties, so to that extent such exclusions may not apply.
|
|
21
|
+
1. High Risk Activities. You acknowledge that the Software is not fault tolerant and is not designed, manufactured, or intended for use or resale as on-line control equipment in hazardous or high risk environments and activities requiring fail-safe performance (such as in the operation of nuclear facilities, aircraft navigation or communication systems, air traffic control, direct life support machines and/or devices, or weapons systems) in which the failure of the Software could lead directly to death, personal injury, or severe physical or environmental damage, and You agree not to use or allow the use of the Software or any portion thereof for, or in connection with, any such environment or activity.
|
|
22
|
+
1. Indemnify. You agree that Applitools shall have no liability whatsoever for any use made of the Software by You or any third party. You hereby agree to defend, indemnify and hold harmless Applitools and its affiliates and their respective officers, directors, agents and employees from any and all claims, damages, liabilities, costs, and expenses (including attorney’s fees) arising from claims related to Your use of the Software as well as from Your failure to comply with this Agreement.
|
|
23
|
+
1. Limitation of Liability. UNDER NO CIRCUMSTANCES SHALL APPLITOOLS AND/OR ITS AFFILIATES BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, PUNITIVE OR CONSEQUENTIAL DAMAGES, OR FOR ANY LOSS OF DATA, REVENUE, BUSINESS OR REPUTATION, THAT ARISES UNDER OR IN CONNECTION WITH THIS AGREEMENT, OR THAT RESULTS FROM THE USE OF, OR THE INABILITY TO USE, THE SOFTWARE. APPLITOOLS’S TOTAL AGGREGATE LIABILITY FOR ANY AND ALL DIRECT DAMAGES AND LOSSES THAT ARISE UNDER OR IN CONNECTION WITH THIS AGREEMENT SHALL NOT IN ANY CIRCUMSTANCE EXCEED THE AMOUNT OF 100.00 (ONE HUNDRED) UNITED STATES DOLLARS. THE FOREGOING LIMITATIONS AND EXCLUSIONS IN THIS SECTION 7 SHALL APPLY: (I) EVEN IF APPLITOOLS HAS BEEN ADVISED OF THE POSSIBILITY OF ANY DAMAGES OR LOSSES; (II) EVEN IF ANY REMEDY SET FORTH HEREIN FAILS OF ITS ESSENTIAL PURPOSE; AND (III) REGARDLESS OF THE BASIS OR THEORY OF LIABILITY.
|
|
24
|
+
1. Export Laws. Licensee agrees to comply fully with all U.S., EU, Israeli, and all applicable export laws and regulations to ensure that neither the Software nor any technical data related thereto are exported or re-exported directly or indirectly in violation of, or used for any purposes prohibited by, such laws and regulations. For clarity, and without derogating from Section 11 below, in case of any change of any applicable law, policy or regulation, which might affect Applitools’ business, Applitools will have the right to terminate this Agreement and the license granted hereunder and the Licensee shall have no claims regarding such termination.
|
|
25
|
+
1. Term and Termination. This Agreement shall continue until terminated as set forth in this section (the “Term”). You may terminate this Agreement at any time by removing the Software from Your system and destroying all copies of the Software and Documentation relating to the Software. Unauthorized copying of the Software or otherwise failing to comply with this Agreement will result in automatic immediate termination of this Agreement and will make available to Applitools legal remedies. Applitools reserves the right to terminate this Agreement and the License at any time and without notice. Upon termination of this Agreement, the License will terminate and You: (i) will cease any and all rights to use the Software, and (ii) will remove the Software from all hard drives, networks and other storage media and destroy all copies of the Software in your possession or under your control. The provisions of Sections 2.3, 2.4, 2.5, 6, 7, 8, 9, 10, 11 and 12 shall survive the termination, expiration or other ending of this Agreement.
|
|
26
|
+
1. Miscellaneous. This Agreement represents the complete agreement concerning the Software between You and Applitools and supersedes all prior agreements and representations between You and Applitools. If any provision of this Agreement is held to be unenforceable for any reason, such provision shall be reformed only to the extent necessary to make it enforceable. Any waiver of any provision of this Agreement will be effective only if in writing and signed by Applitools. This Agreement is personal to You and may not be assigned or transferred for any reason whatsoever without the consent of Applitools and any action or conduct in violation of the foregoing shall be void and without effect. Applitools expressly reserves the right to assign this Agreement and to delegate any of its obligations hereunder. This Agreement are governed by and construed under the laws of the State of Israel, excluding its conflicts of law rules. You expressly agree that the exclusive jurisdiction for any claim or action arising out of or relating to this Agreement shall be the courts located in Tel Aviv, Israel, and You further agree and submit to the exercise of personal jurisdiction of such courts for the purpose of litigating any such claim or action. In any action or proceeding to enforce rights under this Agreement, the prevailing party shall be entitled to recover costs and attorneys’ fees.
|
package/dist/account.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.probeNlpAccount = exports.resolveEyesServerSettings = void 0;
|
|
27
|
+
const core_base_1 = require("@applitools/core-base");
|
|
28
|
+
const utils = __importStar(require("@applitools/utils"));
|
|
29
|
+
const constants_1 = require("./constants");
|
|
30
|
+
/**
|
|
31
|
+
* Mirrors core's `populateEyesServerSettings`, which lives above core-base and can't be imported
|
|
32
|
+
* here. Callers comparing two credential sets must both come through this: an unset config value
|
|
33
|
+
* and the `APPLITOOLS_*` variable it falls back to are the same account.
|
|
34
|
+
*/
|
|
35
|
+
function resolveEyesServerSettings(server = {}) {
|
|
36
|
+
var _a, _b, _c, _d, _e;
|
|
37
|
+
const proxyUrl = utils.general.getEnvValue('PROXY_URL');
|
|
38
|
+
return {
|
|
39
|
+
eyesServerUrl: (_c = (_b = (_a = server.serverUrl) !== null && _a !== void 0 ? _a : utils.general.getEnvValue('EYES_SERVER_URL')) !== null && _b !== void 0 ? _b : utils.general.getEnvValue('SERVER_URL')) !== null && _c !== void 0 ? _c : constants_1.DEFAULT_EYES_SERVER_URL,
|
|
40
|
+
apiKey: (_d = server.apiKey) !== null && _d !== void 0 ? _d : utils.general.getEnvValue('API_KEY'),
|
|
41
|
+
proxy: (_e = server.proxy) !== null && _e !== void 0 ? _e : (proxyUrl ? { url: proxyUrl } : undefined),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
exports.resolveEyesServerSettings = resolveEyesServerSettings;
|
|
45
|
+
/**
|
|
46
|
+
* Entitlement is read from renderinfo, where the NLP endpoint appears only when the flag is on.
|
|
47
|
+
* Goes through core-base's **cached** requests singleton so a caller probing before opening a
|
|
48
|
+
* session shares that request rather than adding one.
|
|
49
|
+
*
|
|
50
|
+
* Never throws and never outlives `timeout`: it gates an optional capability from
|
|
51
|
+
* latency-sensitive paths, and the request layer retries 5xx/network behind a multi-minute
|
|
52
|
+
* connection timeout. Actual NLP use still fails loudly later, with a precise message.
|
|
53
|
+
*/
|
|
54
|
+
async function probeNlpAccount(server = {}, { timeout = constants_1.DEFAULT_ACCOUNT_PROBE_TIMEOUT, logger } = {}) {
|
|
55
|
+
const settings = resolveEyesServerSettings(server);
|
|
56
|
+
if (!settings.apiKey)
|
|
57
|
+
return { enabled: false, reason: 'no-api-key' };
|
|
58
|
+
let timer;
|
|
59
|
+
const deadline = new Promise(resolve => {
|
|
60
|
+
var _a;
|
|
61
|
+
timer = setTimeout(() => resolve({ enabled: false, reason: 'unreachable', message: `account lookup timed out after ${timeout}ms` }), timeout);
|
|
62
|
+
// Never hold the process open for an optional capability's probe.
|
|
63
|
+
(_a = timer.unref) === null || _a === void 0 ? void 0 : _a.call(timer);
|
|
64
|
+
});
|
|
65
|
+
try {
|
|
66
|
+
return await Promise.race([lookup(), deadline]);
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
clearTimeout(timer);
|
|
70
|
+
}
|
|
71
|
+
async function lookup() {
|
|
72
|
+
var _a;
|
|
73
|
+
try {
|
|
74
|
+
const account = await (0, core_base_1.makeCoreRequestsWithCache)({ logger }).getAccountInfo({
|
|
75
|
+
settings: { eyesServerUrl: settings.eyesServerUrl, apiKey: settings.apiKey, proxy: settings.proxy },
|
|
76
|
+
logger,
|
|
77
|
+
});
|
|
78
|
+
if (account.nlpServer)
|
|
79
|
+
return { enabled: true };
|
|
80
|
+
// An explicit `false` is the server's authoritative denial; anything else (entitled but no
|
|
81
|
+
// endpoint, or a server that never mentions the flag) is an environment gap, not a setting.
|
|
82
|
+
if (account.nlpEnabled === false)
|
|
83
|
+
return { enabled: false, reason: 'not-entitled' };
|
|
84
|
+
return { enabled: false, reason: 'service-unavailable' };
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
return { enabled: false, reason: 'unreachable', message: (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : String(error) };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.probeNlpAccount = probeNlpAccount;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeRemoteAXProvider = void 0;
|
|
4
|
+
const core_base_1 = require("@applitools/core-base");
|
|
5
|
+
const req_1 = require("@applitools/req");
|
|
6
|
+
const account_1 = require("./account");
|
|
7
|
+
/**
|
|
8
|
+
* `HttpRemoteAXProvider` is injected because it is runtime-only (loaded via `importESM` in nlp.ts).
|
|
9
|
+
* The service is resolved eagerly so a missing feature flag fails here, before any CDP work.
|
|
10
|
+
*/
|
|
11
|
+
async function makeRemoteAXProvider(HttpRemoteAXProvider, options = {}, { logger } = {}) {
|
|
12
|
+
const { eyesServerUrl, apiKey, proxy } = (0, account_1.resolveEyesServerSettings)(options);
|
|
13
|
+
// core-base validates the key only by round-tripping and reading a 401; this fails immediately.
|
|
14
|
+
if (!apiKey)
|
|
15
|
+
throw new core_base_1.MissingApiKeyError();
|
|
16
|
+
const resolver = (0, core_base_1.makeNLPServiceResolver)({ settings: { eyesServerUrl, apiKey, proxy }, logger });
|
|
17
|
+
const { serviceUrl } = await resolver.getService();
|
|
18
|
+
// The built-in transport is the global fetch: no proxy awareness, and it calls `.json()` on
|
|
19
|
+
// whatever comes back. Ours keeps the wire format and adds both.
|
|
20
|
+
const axClient = proxy ? (0, req_1.makeReq)({ proxy }) : undefined;
|
|
21
|
+
const axFetch = async ({ url, method, token, body }) => {
|
|
22
|
+
const request = {
|
|
23
|
+
method,
|
|
24
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${token}` },
|
|
25
|
+
body: JSON.stringify(body),
|
|
26
|
+
};
|
|
27
|
+
const response = axClient ? await axClient(url, request) : await globalThis.fetch(url, request);
|
|
28
|
+
return {
|
|
29
|
+
async json() {
|
|
30
|
+
var _a;
|
|
31
|
+
const contentType = (_a = response.headers.get('content-type')) !== null && _a !== void 0 ? _a : undefined;
|
|
32
|
+
if (!response.ok || !(contentType === null || contentType === void 0 ? void 0 : contentType.includes('json'))) {
|
|
33
|
+
throw new core_base_1.NlpServiceRequestError({ url, status: response.status, contentType });
|
|
34
|
+
}
|
|
35
|
+
return response.json();
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
return new HttpRemoteAXProvider({
|
|
40
|
+
url: serviceUrl,
|
|
41
|
+
// Called per AX request; the resolver re-fetches renderinfo only as the token nears expiry.
|
|
42
|
+
getAuthToken: async () => (await resolver.getService()).accessToken,
|
|
43
|
+
fetch: axFetch,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
exports.makeRemoteAXProvider = makeRemoteAXProvider;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_EYES_SERVER_URL = exports.MIN_NODE_VERSION = exports.NLP_WEB_RUNNER = exports.DEFAULT_ACCOUNT_PROBE_TIMEOUT = exports.DEFAULT_FIND_TIMEOUT = exports.NLP_LOG_PREFIX = void 0;
|
|
4
|
+
/** Prefixes every NLP message, so a line is identifiable even where the logger's tags aren't shown. */
|
|
5
|
+
exports.NLP_LOG_PREFIX = '[nlp]';
|
|
6
|
+
exports.DEFAULT_FIND_TIMEOUT = 10000;
|
|
7
|
+
/** The launch-time probe sits on the browser-launch path, so it must fail fast, not just closed. */
|
|
8
|
+
exports.DEFAULT_ACCOUNT_PROBE_TIMEOUT = 10000;
|
|
9
|
+
exports.NLP_WEB_RUNNER = '@applitools/nlp-web-runner';
|
|
10
|
+
/**
|
|
11
|
+
* Enforced at runtime too: the optional-dependency mechanism keeps the engine off older Node at
|
|
12
|
+
* install time, but a force-installed setup can smuggle it onto Node < 24, where `import()` may
|
|
13
|
+
* succeed yet behaviour is undefined.
|
|
14
|
+
*/
|
|
15
|
+
exports.MIN_NODE_VERSION = '24.16.0';
|
|
16
|
+
exports.DEFAULT_EYES_SERVER_URL = 'https://eyesapi.applitools.com';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NlpStepError = exports.resolveEyesServerSettings = exports.probeNlpAccount = exports.makeNlp = void 0;
|
|
4
|
+
var nlp_1 = require("./nlp");
|
|
5
|
+
Object.defineProperty(exports, "makeNlp", { enumerable: true, get: function () { return nlp_1.makeNlp; } });
|
|
6
|
+
var account_1 = require("./account");
|
|
7
|
+
Object.defineProperty(exports, "probeNlpAccount", { enumerable: true, get: function () { return account_1.probeNlpAccount; } });
|
|
8
|
+
Object.defineProperty(exports, "resolveEyesServerSettings", { enumerable: true, get: function () { return account_1.resolveEyesServerSettings; } });
|
|
9
|
+
// Re-exported so an SDK can recognise a failed NLP step (and re-wrap it in its own user-facing
|
|
10
|
+
// error type) without taking a direct dependency on @applitools/core-base.
|
|
11
|
+
var core_base_1 = require("@applitools/core-base");
|
|
12
|
+
Object.defineProperty(exports, "NlpStepError", { enumerable: true, get: function () { return core_base_1.NlpStepError; } });
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.messages = void 0;
|
|
4
|
+
const constants_1 = require("./constants");
|
|
5
|
+
exports.messages = {
|
|
6
|
+
/** Replaces the raw internal failure, which surfaces as e.g. undici's `Socks5ProxyAgent not found`. */
|
|
7
|
+
engineUnavailable: (detail) => `NLP is unavailable: eyes.run requires Node >= ${constants_1.MIN_NODE_VERSION} with the optional engine ` +
|
|
8
|
+
`(${constants_1.NLP_WEB_RUNNER}) installed. (${detail})`,
|
|
9
|
+
missingApiKey: () => 'NLP requires an API key: set it in the configuration or via APPLITOOLS_API_KEY.',
|
|
10
|
+
unresolvedCdpTarget: () => 'Could not resolve a CDP connection target for the NLP runner',
|
|
11
|
+
runAborted: () => 'The NLP run was aborted before it finished, so the instruction did not execute. This usually ' +
|
|
12
|
+
'means the page navigated away, the browser closed, or the run exceeded its deadline.',
|
|
13
|
+
};
|
package/dist/nlp.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeNlp = exports.reportStep = void 0;
|
|
4
|
+
const core_base_1 = require("@applitools/core-base");
|
|
5
|
+
const ax_provider_1 = require("./ax-provider");
|
|
6
|
+
const constants_1 = require("./constants");
|
|
7
|
+
const messages_1 = require("./messages");
|
|
8
|
+
// Native dynamic import that survives CommonJS transpilation. @applitools/nlp-web-runner is
|
|
9
|
+
// ESM-only (no `require`/`default` export condition), and the Mocha harness transpiles via SWC
|
|
10
|
+
// targeting CJS, which would down-level a literal `import()` into `require()` and fail to load it.
|
|
11
|
+
// Routing through a Function constructor keeps the call site opaque to SWC/TS so the native
|
|
12
|
+
// `import()` stays.
|
|
13
|
+
const importESM = new Function('specifier', 'return import(specifier)');
|
|
14
|
+
const [MIN_NODE_MAJOR, MIN_NODE_MINOR] = constants_1.MIN_NODE_VERSION.split('.').map(Number);
|
|
15
|
+
function nodeSupportsNlp() {
|
|
16
|
+
const [major, minor] = process.versions.node.split('.').map(Number);
|
|
17
|
+
return major > MIN_NODE_MAJOR || (major === MIN_NODE_MAJOR && minor >= MIN_NODE_MINOR);
|
|
18
|
+
}
|
|
19
|
+
let modulesPromise;
|
|
20
|
+
async function loadNlpModules() {
|
|
21
|
+
if (!nodeSupportsNlp()) {
|
|
22
|
+
throw new Error(messages_1.messages.engineUnavailable(`current Node ${process.versions.node}`));
|
|
23
|
+
}
|
|
24
|
+
if (!modulesPromise) {
|
|
25
|
+
modulesPromise = importESM(constants_1.NLP_WEB_RUNNER)
|
|
26
|
+
.then(runnerMod => ({
|
|
27
|
+
makeBrowser: runnerMod.makeBrowser,
|
|
28
|
+
makeRunner: runnerMod.makeRunner,
|
|
29
|
+
HttpRemoteAXProvider: runnerMod.HttpRemoteAXProvider,
|
|
30
|
+
}))
|
|
31
|
+
.catch(error => {
|
|
32
|
+
var _a;
|
|
33
|
+
// Reset the cache on failure so a later call can retry.
|
|
34
|
+
modulesPromise = undefined;
|
|
35
|
+
throw new Error(messages_1.messages.engineUnavailable((_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : String(error)));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return modulesPromise;
|
|
39
|
+
}
|
|
40
|
+
function makeNlpLogger(logger) {
|
|
41
|
+
if (!logger)
|
|
42
|
+
return undefined;
|
|
43
|
+
// Forwarded, not pre-joined: the engine logs objects and joining renders them "[object Object]".
|
|
44
|
+
const write = (...args) => logger.log(constants_1.NLP_LOG_PREFIX, ...args);
|
|
45
|
+
return { log: write, error: write, trace: write, debug: write };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* `testStep` is carried so a line reads on its own, without matching it back to a call site.
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
function reportStep(logger, testStep, result) {
|
|
52
|
+
if (!logger)
|
|
53
|
+
return;
|
|
54
|
+
const payload = {
|
|
55
|
+
testStep,
|
|
56
|
+
stepSuccessful: result.stepSuccessful,
|
|
57
|
+
status: result.status,
|
|
58
|
+
};
|
|
59
|
+
if (!result.stepSuccessful && result.reason)
|
|
60
|
+
payload.reason = result.reason;
|
|
61
|
+
logger.log(constants_1.NLP_LOG_PREFIX, JSON.stringify(payload));
|
|
62
|
+
}
|
|
63
|
+
exports.reportStep = reportStep;
|
|
64
|
+
function makeNlp(adapter, options = {}) {
|
|
65
|
+
var _a, _b, _c;
|
|
66
|
+
// Tagged once, so every NLP line is greppable as `(nlp)` in the Eyes log — and the engine's own
|
|
67
|
+
// diagnostics as `(nlp/engine)`, which is the axis a debug flag used to stand in for.
|
|
68
|
+
const logger = (_a = options.logger) === null || _a === void 0 ? void 0 : _a.extend({ tags: ['nlp'] });
|
|
69
|
+
const engineLogger = logger === null || logger === void 0 ? void 0 : logger.extend({ tags: ['engine'] });
|
|
70
|
+
const findTimeout = (_c = (_b = options.timeouts) === null || _b === void 0 ? void 0 : _b.findTimeout) !== null && _c !== void 0 ? _c : constants_1.DEFAULT_FIND_TIMEOUT;
|
|
71
|
+
// The browser handle is ours: the runner receives it as `automator` but does not own it,
|
|
72
|
+
// so every path that created a browser must also close it (createRunner on failure,
|
|
73
|
+
// dispose() otherwise). Closing is best-effort — the CDP socket may already be gone.
|
|
74
|
+
let browser;
|
|
75
|
+
let runnerPromise;
|
|
76
|
+
async function closeBrowser(instance) {
|
|
77
|
+
if (!instance)
|
|
78
|
+
return;
|
|
79
|
+
try {
|
|
80
|
+
if (instance.close)
|
|
81
|
+
await instance.close();
|
|
82
|
+
else if (instance.dispose)
|
|
83
|
+
await instance.dispose();
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// already closed / connection gone — nothing left to release
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function createRunner(step) {
|
|
90
|
+
var _a;
|
|
91
|
+
// Availability first: these checks do no CDP work, while getCdpTarget() does — an
|
|
92
|
+
// unsupported-Node user should see the friendly "NLP is unavailable" message (and a
|
|
93
|
+
// flag-less account the "NLP is not enabled" one) before the adapter probes anything
|
|
94
|
+
// (on old Node the probe itself can crash with a raw `fetch is not defined`).
|
|
95
|
+
let modules;
|
|
96
|
+
let axProvider;
|
|
97
|
+
try {
|
|
98
|
+
modules = await loadNlpModules();
|
|
99
|
+
// AX-tree extraction/description/finding is served by the Eyes NLP AX service; the
|
|
100
|
+
// service URL and its Bearer token come from the Eyes server's renderinfo endpoint.
|
|
101
|
+
axProvider = await (0, ax_provider_1.makeRemoteAXProvider)(modules.HttpRemoteAXProvider, options.server, { logger });
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
throw new core_base_1.NlpStepError(step, { message: (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : String(error) });
|
|
105
|
+
}
|
|
106
|
+
const target = await adapter.getCdpTarget();
|
|
107
|
+
if (!target || Object.keys(target).length === 0) {
|
|
108
|
+
throw new core_base_1.NlpStepError(step, { message: messages_1.messages.unresolvedCdpTarget() });
|
|
109
|
+
}
|
|
110
|
+
const browserInstance = await modules.makeBrowser(target);
|
|
111
|
+
browser = browserInstance;
|
|
112
|
+
try {
|
|
113
|
+
const runnerInstance = await modules.makeRunner({
|
|
114
|
+
automator: browserInstance,
|
|
115
|
+
axProvider,
|
|
116
|
+
timeouts: { findTimeout },
|
|
117
|
+
logger: makeNlpLogger(engineLogger),
|
|
118
|
+
});
|
|
119
|
+
// Diagnostics only — never used to build results; shows which phase the runner is in.
|
|
120
|
+
runnerInstance.on('statusChanged', event => engineLogger === null || engineLogger === void 0 ? void 0 : engineLogger.log(constants_1.NLP_LOG_PREFIX, `status: ${event.status}`));
|
|
121
|
+
return runnerInstance;
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
// The runner never took the browser — close the CDP connection instead of leaking it.
|
|
125
|
+
browser = undefined;
|
|
126
|
+
await closeBrowser(browserInstance);
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function getRunner(step) {
|
|
131
|
+
// Cache the construction promise (same idiom as modulesPromise), not just the result, so
|
|
132
|
+
// two concurrent first calls share one browser+runner instead of each building a pair and
|
|
133
|
+
// leaking the loser. A failed construction resets the cache so a later call can retry.
|
|
134
|
+
if (!runnerPromise) {
|
|
135
|
+
runnerPromise = createRunner(step).catch(error => {
|
|
136
|
+
runnerPromise = undefined;
|
|
137
|
+
throw error;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return runnerPromise;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
async run(step) {
|
|
144
|
+
var _a;
|
|
145
|
+
const activeRunner = await getRunner(step);
|
|
146
|
+
const res = await activeRunner.run(step);
|
|
147
|
+
if (res.status === 'error') {
|
|
148
|
+
reportStep(logger, step, { stepSuccessful: false, status: 'error', reason: res.error });
|
|
149
|
+
throw new core_base_1.NlpStepError(step, { message: res.error, reason: res.error });
|
|
150
|
+
}
|
|
151
|
+
// An aborted run never executed the instruction. Falling through would map its (empty)
|
|
152
|
+
// results to `[]` and hand the caller a successful no-op for work that did not happen.
|
|
153
|
+
if (res.status === 'aborted') {
|
|
154
|
+
const reason = messages_1.messages.runAborted();
|
|
155
|
+
reportStep(logger, step, { stepSuccessful: false, status: 'aborted', reason });
|
|
156
|
+
throw new core_base_1.NlpStepError(step, { message: reason, reason: 'aborted' });
|
|
157
|
+
}
|
|
158
|
+
// Spread, not project: the engine's own fields survive, so a field it adds needs no change
|
|
159
|
+
// here or downstream. `testStep` is the SDK's stable name for the phrase an action came from
|
|
160
|
+
// — the engine reports it as `text`, and the whole phrase stands in when it does not.
|
|
161
|
+
const results = ((_a = res.results) !== null && _a !== void 0 ? _a : []).map(r => {
|
|
162
|
+
var _a;
|
|
163
|
+
return ({
|
|
164
|
+
...r,
|
|
165
|
+
testStep: (_a = r.text) !== null && _a !== void 0 ? _a : step,
|
|
166
|
+
stepSuccessful: r.status !== 'error',
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
for (const result of results)
|
|
170
|
+
reportStep(logger, step, result);
|
|
171
|
+
return results;
|
|
172
|
+
},
|
|
173
|
+
async dispose() {
|
|
174
|
+
const activeRunnerPromise = runnerPromise;
|
|
175
|
+
runnerPromise = undefined;
|
|
176
|
+
const activeBrowser = browser;
|
|
177
|
+
browser = undefined;
|
|
178
|
+
const activeRunner = await (activeRunnerPromise === null || activeRunnerPromise === void 0 ? void 0 : activeRunnerPromise.catch(() => undefined));
|
|
179
|
+
await (activeRunner === null || activeRunner === void 0 ? void 0 : activeRunner.dispose().catch(() => { }));
|
|
180
|
+
// The runner does not own the browser we created for it — close it too.
|
|
181
|
+
await closeBrowser(activeBrowser);
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
exports.makeNlp = makeNlp;
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@applitools/core-nlp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"nlp",
|
|
6
|
+
"natural language",
|
|
7
|
+
"chrome devtools protocol",
|
|
8
|
+
"cdp",
|
|
9
|
+
"applitools",
|
|
10
|
+
"eyes",
|
|
11
|
+
"automation",
|
|
12
|
+
"testing",
|
|
13
|
+
"tests"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://applitools.com",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/applitools/eyes.sdk.javascript1/issues"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git://github.com/applitools/eyes.sdk.javascript1.git",
|
|
22
|
+
"directory": "js/packages/core-nlp"
|
|
23
|
+
},
|
|
24
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
25
|
+
"author": {
|
|
26
|
+
"name": "Applitools Team",
|
|
27
|
+
"email": "team@applitools.com"
|
|
28
|
+
},
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"types": "./types/index.d.ts",
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"types"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"lint": "run --top-level eslint '**/*.ts'",
|
|
37
|
+
"build": "run --top-level tspc --project ./tsconfig.build.json",
|
|
38
|
+
"test": "run --top-level mocha './test/**/*.spec.ts' --exit"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@applitools/core-base": "1.39.0",
|
|
42
|
+
"@applitools/logger": "2.3.1",
|
|
43
|
+
"@applitools/req": "1.11.3",
|
|
44
|
+
"@applitools/utils": "1.15.2"
|
|
45
|
+
},
|
|
46
|
+
"optionalDependencies": {
|
|
47
|
+
"@applitools/nlp-web-runner": "^5.15.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^12.20.55"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=12.13.0"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
},
|
|
58
|
+
"lavamoat": {
|
|
59
|
+
"allowScripts": {
|
|
60
|
+
"@applitools/core-base>@applitools/image>sharp": false
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Logger } from '@applitools/logger';
|
|
2
|
+
import type { NlpServerSettings } from './types';
|
|
3
|
+
export type ResolvedEyesServerSettings = {
|
|
4
|
+
eyesServerUrl: string;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
proxy?: {
|
|
7
|
+
url: string;
|
|
8
|
+
username?: string;
|
|
9
|
+
password?: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Mirrors core's `populateEyesServerSettings`, which lives above core-base and can't be imported
|
|
14
|
+
* here. Callers comparing two credential sets must both come through this: an unset config value
|
|
15
|
+
* and the `APPLITOOLS_*` variable it falls back to are the same account.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveEyesServerSettings(server?: NlpServerSettings): ResolvedEyesServerSettings;
|
|
18
|
+
export type NlpAccountProbe = {
|
|
19
|
+
enabled: true;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* `not-entitled` — flag off; the organization can enable it. `service-unavailable` — entitled (or
|
|
23
|
+
* silent) but no endpoint, so nothing the user can change. `unreachable` — lookup failed or
|
|
24
|
+
* outlived its deadline.
|
|
25
|
+
*/
|
|
26
|
+
| {
|
|
27
|
+
enabled: false;
|
|
28
|
+
reason: 'no-api-key' | 'not-entitled' | 'service-unavailable' | 'unreachable';
|
|
29
|
+
message?: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Entitlement is read from renderinfo, where the NLP endpoint appears only when the flag is on.
|
|
33
|
+
* Goes through core-base's **cached** requests singleton so a caller probing before opening a
|
|
34
|
+
* session shares that request rather than adding one.
|
|
35
|
+
*
|
|
36
|
+
* Never throws and never outlives `timeout`: it gates an optional capability from
|
|
37
|
+
* latency-sensitive paths, and the request layer retries 5xx/network behind a multi-minute
|
|
38
|
+
* connection timeout. Actual NLP use still fails loudly later, with a precise message.
|
|
39
|
+
*/
|
|
40
|
+
export declare function probeNlpAccount(server?: NlpServerSettings, { timeout, logger }?: {
|
|
41
|
+
timeout?: number;
|
|
42
|
+
logger?: Logger;
|
|
43
|
+
}): Promise<NlpAccountProbe>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Logger } from '@applitools/logger';
|
|
2
|
+
import type { AXProvider, HttpRemoteAXProviderCtor, NlpServerSettings } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* `HttpRemoteAXProvider` is injected because it is runtime-only (loaded via `importESM` in nlp.ts).
|
|
5
|
+
* The service is resolved eagerly so a missing feature flag fails here, before any CDP work.
|
|
6
|
+
*/
|
|
7
|
+
export declare function makeRemoteAXProvider(HttpRemoteAXProvider: HttpRemoteAXProviderCtor, options?: NlpServerSettings, { logger }?: {
|
|
8
|
+
logger?: Logger;
|
|
9
|
+
}): Promise<AXProvider>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Prefixes every NLP message, so a line is identifiable even where the logger's tags aren't shown. */
|
|
2
|
+
export declare const NLP_LOG_PREFIX = "[nlp]";
|
|
3
|
+
export declare const DEFAULT_FIND_TIMEOUT = 10000;
|
|
4
|
+
/** The launch-time probe sits on the browser-launch path, so it must fail fast, not just closed. */
|
|
5
|
+
export declare const DEFAULT_ACCOUNT_PROBE_TIMEOUT = 10000;
|
|
6
|
+
export declare const NLP_WEB_RUNNER = "@applitools/nlp-web-runner";
|
|
7
|
+
/**
|
|
8
|
+
* Enforced at runtime too: the optional-dependency mechanism keeps the engine off older Node at
|
|
9
|
+
* install time, but a force-installed setup can smuggle it onto Node < 24, where `import()` may
|
|
10
|
+
* succeed yet behaviour is undefined.
|
|
11
|
+
*/
|
|
12
|
+
export declare const MIN_NODE_VERSION = "24.16.0";
|
|
13
|
+
export declare const DEFAULT_EYES_SERVER_URL = "https://eyesapi.applitools.com";
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { makeNlp } from './nlp';
|
|
2
|
+
export { probeNlpAccount, resolveEyesServerSettings } from './account';
|
|
3
|
+
export type { NlpAccountProbe, ResolvedEyesServerSettings } from './account';
|
|
4
|
+
export type { StepResult, NlpAdapter, MakeNlpOptions, NlpServerSettings, Nlp } from './types';
|
|
5
|
+
export { NlpStepError } from '@applitools/core-base';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const messages: {
|
|
2
|
+
/** Replaces the raw internal failure, which surfaces as e.g. undici's `Socks5ProxyAgent not found`. */
|
|
3
|
+
engineUnavailable: (detail: string) => string;
|
|
4
|
+
missingApiKey: () => string;
|
|
5
|
+
unresolvedCdpTarget: () => string;
|
|
6
|
+
runAborted: () => string;
|
|
7
|
+
};
|
package/types/nlp.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Logger } from '@applitools/logger';
|
|
2
|
+
import type { MakeNlpOptions, Nlp, NlpAdapter } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* `testStep` is carried so a line reads on its own, without matching it back to a call site.
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export declare function reportStep(logger: Logger | undefined, testStep: string, result: {
|
|
8
|
+
stepSuccessful: boolean;
|
|
9
|
+
status: string;
|
|
10
|
+
reason?: string;
|
|
11
|
+
}): void;
|
|
12
|
+
export declare function makeNlp(adapter: NlpAdapter, options?: MakeNlpOptions): Nlp;
|
package/types/types.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { Logger } from '@applitools/logger';
|
|
2
|
+
/**
|
|
3
|
+
* Per-action result returned by `run`, one entry per action the engine reported.
|
|
4
|
+
*
|
|
5
|
+
* The engine owns this shape: every field it reports is passed through untouched, so fields it
|
|
6
|
+
* gains (element `info`, …) reach callers without a change here. Two fields are added: `stepSuccessful`,
|
|
7
|
+
* derived from the engine's `status`, and `testStep`, the SDK's stable name for the phrase an action
|
|
8
|
+
* came from (the engine reports it as `text`).
|
|
9
|
+
*/
|
|
10
|
+
export type StepResult = {
|
|
11
|
+
stepSuccessful: boolean;
|
|
12
|
+
status: string;
|
|
13
|
+
} & Record<string, unknown>;
|
|
14
|
+
/**
|
|
15
|
+
* The only SDK-specific seam. An adapter bridges the SDK-agnostic orchestrator
|
|
16
|
+
* to a concrete automation framework by providing the CDP connection target.
|
|
17
|
+
*/
|
|
18
|
+
export interface NlpAdapter {
|
|
19
|
+
getCdpTarget(): Promise<Record<string, unknown>>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Eyes server credentials used to discover the NLP AX service: the orchestrator calls
|
|
23
|
+
* `GET /api/sessions/renderinfo` with them to obtain the service URL and its auth token
|
|
24
|
+
* (see ./ax-provider.ts). Every field falls back to the standard environment variables
|
|
25
|
+
* (`APPLITOOLS_SERVER_URL`, `APPLITOOLS_API_KEY`, `APPLITOOLS_PROXY_URL`).
|
|
26
|
+
*/
|
|
27
|
+
export type NlpServerSettings = {
|
|
28
|
+
serverUrl?: string;
|
|
29
|
+
apiKey?: string;
|
|
30
|
+
proxy?: {
|
|
31
|
+
url: string;
|
|
32
|
+
username?: string;
|
|
33
|
+
password?: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export interface MakeNlpOptions {
|
|
37
|
+
/**
|
|
38
|
+
* The SDK's logger. Every consumer already builds one, so the orchestrator uses that type
|
|
39
|
+
* directly rather than a structural subset — it needs the `console` channel (always-visible,
|
|
40
|
+
* user-facing output) and the level-gated `debug` channel, both of which `Logger` guarantees.
|
|
41
|
+
* SDKs on the `@applitools/eyes` wrapper pass the underlying logger: `eyes.getLogger().getLogger()`.
|
|
42
|
+
*/
|
|
43
|
+
logger?: Logger;
|
|
44
|
+
timeouts?: {
|
|
45
|
+
findTimeout?: number;
|
|
46
|
+
};
|
|
47
|
+
server?: NlpServerSettings;
|
|
48
|
+
}
|
|
49
|
+
export interface Nlp {
|
|
50
|
+
run(step: string): Promise<StepResult[]>;
|
|
51
|
+
dispose(): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
export type Browser = {
|
|
54
|
+
close?(): Promise<void>;
|
|
55
|
+
dispose?(): Promise<void>;
|
|
56
|
+
};
|
|
57
|
+
export type RunResult = ({
|
|
58
|
+
status: 'success' | 'aborted';
|
|
59
|
+
} | {
|
|
60
|
+
status: 'error';
|
|
61
|
+
error: string;
|
|
62
|
+
}) & {
|
|
63
|
+
results?: ({
|
|
64
|
+
status: string;
|
|
65
|
+
} & Record<string, unknown>)[];
|
|
66
|
+
};
|
|
67
|
+
export type Runner = {
|
|
68
|
+
run(input: string): Promise<RunResult>;
|
|
69
|
+
dispose(): Promise<void>;
|
|
70
|
+
on(type: 'statusChanged', listener: (event: {
|
|
71
|
+
status: string;
|
|
72
|
+
previousStatus?: string;
|
|
73
|
+
}) => void): () => void;
|
|
74
|
+
};
|
|
75
|
+
export type NlpLogger = {
|
|
76
|
+
log(...args: any[]): void;
|
|
77
|
+
error(...args: any[]): void;
|
|
78
|
+
trace(...args: any[]): void;
|
|
79
|
+
debug(...args: any[]): void;
|
|
80
|
+
};
|
|
81
|
+
export type AXProvider = object;
|
|
82
|
+
export type AXServerRequest = {
|
|
83
|
+
url: string;
|
|
84
|
+
method: string;
|
|
85
|
+
token: string;
|
|
86
|
+
body: unknown;
|
|
87
|
+
};
|
|
88
|
+
export type AXServerFetch = (request: AXServerRequest) => Promise<{
|
|
89
|
+
json(): Promise<any>;
|
|
90
|
+
}>;
|
|
91
|
+
export type HttpRemoteAXProviderCtor = new (options: {
|
|
92
|
+
url: string;
|
|
93
|
+
getAuthToken: () => string | Promise<string>;
|
|
94
|
+
fetch?: AXServerFetch;
|
|
95
|
+
}) => AXProvider;
|
|
96
|
+
export type NlpModules = {
|
|
97
|
+
makeBrowser(options: Record<string, unknown>): Promise<Browser>;
|
|
98
|
+
makeRunner(options: {
|
|
99
|
+
automator: Browser;
|
|
100
|
+
axProvider: AXProvider;
|
|
101
|
+
timeouts?: {
|
|
102
|
+
findTimeout?: number;
|
|
103
|
+
};
|
|
104
|
+
logger?: NlpLogger;
|
|
105
|
+
}): Promise<Runner>;
|
|
106
|
+
HttpRemoteAXProvider: HttpRemoteAXProviderCtor;
|
|
107
|
+
};
|