@resolveio/server-lib 22.3.32 → 22.3.33
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/package.json +137 -137
- package/util/ai-runner-qa-auth.js +81 -1
- package/util/ai-runner-qa-auth.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,139 +1,139 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
2
|
+
"name": "@resolveio/server-lib",
|
|
3
|
+
"version": "22.3.33",
|
|
4
|
+
"description": "",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"package": "./build_package.sh",
|
|
7
|
+
"library": "node_modules/gulp/bin/gulp.js watch:dist",
|
|
8
|
+
"server": "./start_server.sh",
|
|
9
|
+
"postserver": "node_modules/gulp/bin/gulp.js mongo-stop",
|
|
10
|
+
"build-prod": "node_modules/gulp/bin/gulp.js build-prod",
|
|
11
|
+
"dependency-test": "node --require ts-node/register tests/subscription-dependency-context.test.ts",
|
|
12
|
+
"subscription-invalidation-test": "node --require ts-node/register tests/subscription-manager-invalidation.test.ts",
|
|
13
|
+
"subscription-connect-race-test": "node --require ts-node/register tests/subscription-connect-race.test.ts",
|
|
14
|
+
"error-reporter-test": "node --require ts-node/register tests/error-reporter.test.ts",
|
|
15
|
+
"ai-assistant-utils-test": "node --require ts-node/register tests/ai-assistant-utils.test.ts",
|
|
16
|
+
"ai-assistant-routing-eval-test": "node --require ts-node/register tests/ai-assistant-routing-eval.test.ts",
|
|
17
|
+
"ai-assistant-preflight-matrix": "node --require ts-node/register tests/ai-assistant-preflight-matrix.ts",
|
|
18
|
+
"ai-assistant-snf-live-eval": "node --require ts-node/register tests/ai-assistant-snf-live-eval.ts",
|
|
19
|
+
"ai-assistant-openai-e2e": "node --require ts-node/register tests/ai-assistant-openai-e2e.ts",
|
|
20
|
+
"ai-assistant-openai-e2e:wo-this-week-customer": "AI_ASSISTANT_E2E_CASES=wo_this_week_customer_summary node --require ts-node/register tests/ai-assistant-openai-e2e.ts",
|
|
21
|
+
"ai-assistant-openai-e2e:wo-this-week-customer:soak": "AI_ASSISTANT_E2E_CASES=wo_this_week_customer_summary AI_ASSISTANT_E2E_REPEAT=50 node --require ts-node/register tests/ai-assistant-openai-e2e.ts",
|
|
22
|
+
"ai-assistant-openai-git-e2e": "node --require ts-node/register tests/ai-assistant-openai-git-e2e.ts",
|
|
23
|
+
"ai-assistant-eval-triage": "node --require ts-node/register tests/ai-assistant-eval-triage.ts",
|
|
24
|
+
"ai-assistant-data-parity-e2e": "node --require ts-node/register tests/ai-assistant-data-parity-e2e.ts",
|
|
25
|
+
"ai-assistant-corpus-build": "node --require ts-node/register tests/ai-assistant-corpus-build.ts",
|
|
26
|
+
"ai-assistant-corpus-replay-e2e": "node --require ts-node/register tests/ai-assistant-corpus-replay-e2e.ts",
|
|
27
|
+
"method-publication-generator-test": "node --require ts-node/register tests/method-publication-generator.test.ts",
|
|
28
|
+
"ai-assistant-nightly-eval": "npm run ai-assistant-corpus-build && npm run ai-assistant-data-parity-e2e && npm run ai-assistant-corpus-replay-e2e && npm run ai-assistant-eval-triage"
|
|
29
|
+
},
|
|
30
|
+
"author": "",
|
|
31
|
+
"license": "ISC",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=22.0.0 <23"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@aws-sdk/client-s3": "3.1043.0",
|
|
37
|
+
"@aws-sdk/client-sesv2": "3.1043.0",
|
|
38
|
+
"@aws-sdk/s3-request-presigner": "3.1043.0",
|
|
39
|
+
"@openai/codex-sdk": "0.128.0",
|
|
40
|
+
"async": "3.2.6",
|
|
41
|
+
"axios": "1.16.0",
|
|
42
|
+
"clone": "2.1.2",
|
|
43
|
+
"cron": "4.4.0",
|
|
44
|
+
"deep-diff": "1.0.2",
|
|
45
|
+
"deep-object-diff": "1.1.9",
|
|
46
|
+
"exceljs": "4.4.0",
|
|
47
|
+
"express": "5.2.1",
|
|
48
|
+
"express-xml-bodyparser": "0.4.1",
|
|
49
|
+
"handlebars": "4.7.9",
|
|
50
|
+
"imap": "0.8.19",
|
|
51
|
+
"js-tiktoken": "1.0.21",
|
|
52
|
+
"json2csv": "6.0.0-alpha.2",
|
|
53
|
+
"jsonwebtoken": "9.0.3",
|
|
54
|
+
"jwt-decode": "4.0.0",
|
|
55
|
+
"moment-timezone": "0.6.2",
|
|
56
|
+
"mongodb": "7.2.0",
|
|
57
|
+
"msgpackr": "2.0.1",
|
|
58
|
+
"node-cache": "5.1.2",
|
|
59
|
+
"node-google-timezone": "0.1.1",
|
|
60
|
+
"nodemailer": "8.0.7",
|
|
61
|
+
"path": "0.12.7",
|
|
62
|
+
"pdf-lib": "1.17.1",
|
|
63
|
+
"pm2": "7.0.1",
|
|
64
|
+
"puppeteer": "24.43.0",
|
|
65
|
+
"rus-diff": "1.1.0",
|
|
66
|
+
"rxjs": "7.8.2",
|
|
67
|
+
"scmp": "2.1.0",
|
|
68
|
+
"sift": "17.1.3",
|
|
69
|
+
"simpl-schema": "1.12.0",
|
|
70
|
+
"string_score": "0.1.22",
|
|
71
|
+
"string-similarity": "4.0.4",
|
|
72
|
+
"twilio": "6.0.1",
|
|
73
|
+
"ws": "8.20.0",
|
|
74
|
+
"xlsx": "0.18.5"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@types/express": "5.0.6",
|
|
78
|
+
"@types/handlebars": "4.1.0",
|
|
79
|
+
"@types/jsonwebtoken": "9.0.10",
|
|
80
|
+
"@types/nodemailer": "8.0.0",
|
|
81
|
+
"@types/ws": "8.18.1",
|
|
82
|
+
"@typescript-eslint/eslint-plugin": "8.59.2",
|
|
83
|
+
"@typescript-eslint/parser": "8.59.2",
|
|
84
|
+
"del": "3.0.0",
|
|
85
|
+
"eslint": "10.3.0",
|
|
86
|
+
"eslint-plugin-promise": "7.3.0",
|
|
87
|
+
"gulp": "5.0.1",
|
|
88
|
+
"gulp-if": "3.0.0",
|
|
89
|
+
"gulp-nodemon": "2.5.0",
|
|
90
|
+
"gulp-rename": "2.1.0",
|
|
91
|
+
"gulp-shell": "0.8.0",
|
|
92
|
+
"gulp-sourcemaps": "3.0.0",
|
|
93
|
+
"gulp-typescript": "5.0.1",
|
|
94
|
+
"gulp-uglify": "3.0.2",
|
|
95
|
+
"gulp-zip": "6.1.0",
|
|
96
|
+
"mkdirs": "1.0.0",
|
|
97
|
+
"ts-node": "10.9.2",
|
|
98
|
+
"typescript": "5.9.3"
|
|
99
|
+
},
|
|
100
|
+
"peerDependencies": {
|
|
101
|
+
"@aws-sdk/client-s3": "3.1043.0",
|
|
102
|
+
"@aws-sdk/client-sesv2": "3.1043.0",
|
|
103
|
+
"@aws-sdk/s3-request-presigner": "3.1043.0",
|
|
104
|
+
"@openai/codex-sdk": "0.128.0",
|
|
105
|
+
"axios": "1.16.0",
|
|
106
|
+
"body-parser": "2.2.0",
|
|
107
|
+
"clone": "2.1.2",
|
|
108
|
+
"cron": "4.4.0",
|
|
109
|
+
"deep-diff": "1.0.2",
|
|
110
|
+
"deep-object-diff": "1.1.9",
|
|
111
|
+
"exceljs": "4.4.0",
|
|
112
|
+
"express": "5.2.1",
|
|
113
|
+
"express-xml-bodyparser": "0.4.1",
|
|
114
|
+
"handlebars": "4.7.9",
|
|
115
|
+
"imap": "0.8.19",
|
|
116
|
+
"js-tiktoken": "1.0.21",
|
|
117
|
+
"json2csv": "6.0.0-alpha.2",
|
|
118
|
+
"jsonwebtoken": "9.0.3",
|
|
119
|
+
"jwt-decode": "4.0.0",
|
|
120
|
+
"moment-timezone": "0.6.2",
|
|
121
|
+
"mongodb": "7.2.0",
|
|
122
|
+
"msgpackr": "2.0.1",
|
|
123
|
+
"node-cache": "5.1.2",
|
|
124
|
+
"node-google-timezone": "0.1.1",
|
|
125
|
+
"nodemailer": "8.0.7",
|
|
126
|
+
"path": "0.12.7",
|
|
127
|
+
"pdf-lib": "1.17.1",
|
|
128
|
+
"pm2": "7.0.1",
|
|
129
|
+
"puppeteer": "24.43.0",
|
|
130
|
+
"rus-diff": "1.1.0",
|
|
131
|
+
"scmp": "2.1.0",
|
|
132
|
+
"simpl-schema": "1.12.0",
|
|
133
|
+
"string_score": "0.1.22",
|
|
134
|
+
"string-similarity": "4.0.4",
|
|
135
|
+
"twilio": "6.0.1",
|
|
136
|
+
"ws": "8.20.0",
|
|
137
|
+
"xlsx": "0.18.5"
|
|
138
|
+
}
|
|
139
139
|
}
|
|
@@ -10,6 +10,7 @@ function buildResolveIORunnerQaAuthBootstrapScript(options) {
|
|
|
10
10
|
"'use strict';",
|
|
11
11
|
'',
|
|
12
12
|
'const fs = require("fs");',
|
|
13
|
+
'const crypto = require("crypto");',
|
|
13
14
|
'const http = require("http");',
|
|
14
15
|
'const https = require("https");',
|
|
15
16
|
'const path = require("path");',
|
|
@@ -32,6 +33,79 @@ function buildResolveIORunnerQaAuthBootstrapScript(options) {
|
|
|
32
33
|
' return String(value || "").replace(/\\/+$/, "");',
|
|
33
34
|
'}',
|
|
34
35
|
'',
|
|
36
|
+
'function isLocalhostUrl(value) {',
|
|
37
|
+
' try {',
|
|
38
|
+
' const parsed = new URL(value);',
|
|
39
|
+
' return ["localhost", "127.0.0.1", "::1"].includes(parsed.hostname);',
|
|
40
|
+
' }',
|
|
41
|
+
' catch (error) {',
|
|
42
|
+
' return false;',
|
|
43
|
+
' }',
|
|
44
|
+
'}',
|
|
45
|
+
'',
|
|
46
|
+
'function resolveLocalMongoUrl() {',
|
|
47
|
+
' return process.env.MONGO_URL || process.env.RESOLVEIO_RUNNER_QA_MONGO_URL || process.env.RESOLVEIO_SUPPORT_QA_MONGO_URL || `mongodb://127.0.0.1:${process.env.RESOLVEIO_SUPPORT_QA_MONGO_PORT || "3001"}/resolveio?directConnection=true`;',
|
|
48
|
+
'}',
|
|
49
|
+
'',
|
|
50
|
+
'function requireMongoClient() {',
|
|
51
|
+
' const candidates = [',
|
|
52
|
+
' path.join(projectRoot, "server", "node_modules", "mongodb"),',
|
|
53
|
+
' path.join(projectRoot, "node_modules", "mongodb"),',
|
|
54
|
+
' path.join(process.cwd(), "server", "node_modules", "mongodb"),',
|
|
55
|
+
' path.join(process.cwd(), "node_modules", "mongodb"),',
|
|
56
|
+
' "mongodb"',
|
|
57
|
+
' ];',
|
|
58
|
+
' for (const candidate of candidates) {',
|
|
59
|
+
' try { return require(candidate).MongoClient; }',
|
|
60
|
+
' catch (error) {}',
|
|
61
|
+
' }',
|
|
62
|
+
' throw new Error("Unable to require mongodb from project/server node_modules or global resolution");',
|
|
63
|
+
'}',
|
|
64
|
+
'',
|
|
65
|
+
'async function ensureLocalQaUser() {',
|
|
66
|
+
' if (!isLocalhostUrl(serverUrl) || process.env.RESOLVEIO_RUNNER_QA_DISABLE_LOCAL_USER_REPAIR === "true" || process.env.RESOLVEIO_SUPPORT_QA_DISABLE_LOCAL_USER_REPAIR === "true") {',
|
|
67
|
+
' return false;',
|
|
68
|
+
' }',
|
|
69
|
+
' const MongoClient = requireMongoClient();',
|
|
70
|
+
' const client = new MongoClient(resolveLocalMongoUrl());',
|
|
71
|
+
' await client.connect();',
|
|
72
|
+
' try {',
|
|
73
|
+
' const db = client.db();',
|
|
74
|
+
' const users = db.collection("users");',
|
|
75
|
+
' const now = new Date();',
|
|
76
|
+
' const salt = crypto.randomBytes(32).toString("hex");',
|
|
77
|
+
' const hash = crypto.pbkdf2Sync(password, salt, 25000, 512, "sha256").toString("hex");',
|
|
78
|
+
' const existing = await users.findOne({ $or: [{ username }, { email: username }] }, { projection: { _id: 1 } });',
|
|
79
|
+
' const baseUser = {',
|
|
80
|
+
' __v: 0,',
|
|
81
|
+
' username,',
|
|
82
|
+
' email: username.includes("@") ? username : "dev@resolveio.com",',
|
|
83
|
+
' fullname: "QA Admin",',
|
|
84
|
+
' roles: { super_admin: true, approvals: [], groups: [], notifications: [], miscs: [] },',
|
|
85
|
+
' active: true,',
|
|
86
|
+
' other: { yards: [] },',
|
|
87
|
+
' phonenumber: "",',
|
|
88
|
+
' readonly: false,',
|
|
89
|
+
' is_customer: false,',
|
|
90
|
+
' hash,',
|
|
91
|
+
' salt,',
|
|
92
|
+
' attempts: 0,',
|
|
93
|
+
' services: {},',
|
|
94
|
+
' updatedAt: now',
|
|
95
|
+
' };',
|
|
96
|
+
' if (existing && existing._id) {',
|
|
97
|
+
' await users.updateOne({ _id: existing._id }, { $set: baseUser });',
|
|
98
|
+
' }',
|
|
99
|
+
' else {',
|
|
100
|
+
' await users.insertOne({ _id: crypto.randomBytes(12).toString("hex"), createdAt: now, ...baseUser });',
|
|
101
|
+
' }',
|
|
102
|
+
' return true;',
|
|
103
|
+
' }',
|
|
104
|
+
' finally {',
|
|
105
|
+
' await client.close().catch(() => undefined);',
|
|
106
|
+
' }',
|
|
107
|
+
'}',
|
|
108
|
+
'',
|
|
35
109
|
'function writeResult(payload) {',
|
|
36
110
|
' fs.mkdirSync(artifactDir, { recursive: true });',
|
|
37
111
|
' fs.writeFileSync(resultPath, JSON.stringify(payload, null, 2));',
|
|
@@ -94,7 +168,13 @@ function buildResolveIORunnerQaAuthBootstrapScript(options) {
|
|
|
94
168
|
' if (!password) {',
|
|
95
169
|
' throw new Error("QA password is empty; source .resolveio-support-tools/env.sh or set RESOLVEIO_RUNNER_QA_PASSWORD before auth bootstrap");',
|
|
96
170
|
' }',
|
|
97
|
-
'
|
|
171
|
+
' let loginJson = await requestJson(`${serverUrl}/login`, { username, password });',
|
|
172
|
+
' if ((loginJson && loginJson.error) && /Invalid Username And Password|Too Many Attempts/i.test(String(loginJson.result || ""))) {',
|
|
173
|
+
' const repaired = await ensureLocalQaUser();',
|
|
174
|
+
' if (repaired) {',
|
|
175
|
+
' loginJson = await requestJson(`${serverUrl}/login`, { username, password });',
|
|
176
|
+
' }',
|
|
177
|
+
' }',
|
|
98
178
|
' const refreshToken = loginJson && loginJson.result && loginJson.result.token;',
|
|
99
179
|
' if (loginJson.error || !refreshToken) {',
|
|
100
180
|
' throw new Error(`Login failed: ${JSON.stringify(loginJson).slice(0, 800)}`);',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/ai-runner-qa-auth.ts"],"names":[],"mappings":"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","file":"ai-runner-qa-auth.js","sourcesContent":["export interface ResolveIORunnerQaAuthBootstrapScriptOptions {\n\tdefaultUsername?: string;\n\tdefaultPassword?: string;\n}\n\nexport function buildResolveIORunnerQaAuthBootstrapScript(options: ResolveIORunnerQaAuthBootstrapScriptOptions = {}): string {\n\tconst defaultUsername = options.defaultUsername || 'admin';\n\tconst defaultPassword = options.defaultPassword || '';\n\treturn [\n\t\t'#!/usr/bin/env node',\n\t\t\"'use strict';\",\n\t\t'',\n\t\t'const fs = require(\"fs\");',\n\t\t'const http = require(\"http\");',\n\t\t'const https = require(\"https\");',\n\t\t'const path = require(\"path\");',\n\t\t'',\n\t\t'const projectRoot = path.resolve(process.argv[2] || process.cwd());',\n\t\t'const routeArg = process.argv[3] || process.env.RESOLVEIO_RUNNER_QA_TARGET_ROUTE || process.env.RESOLVEIO_SUPPORT_QA_TARGET_ROUTE || process.env.RESOLVEIO_SUPPORT_QA_LAST_URL || \"/\";',\n\t\t'const targetRoute = routeArg.startsWith(\"/\") ? routeArg : `/${routeArg}`;',\n\t\t'const clientUrl = stripTrailingSlash(process.env.RESOLVEIO_RUNNER_QA_CLIENT_URL || process.env.RESOLVEIO_SUPPORT_QA_CLIENT_URL || `http://localhost:${process.env.RESOLVEIO_SUPPORT_QA_CLIENT_PORT || \"4200\"}`);',\n\t\t'const serverUrl = stripTrailingSlash(process.env.RESOLVEIO_RUNNER_QA_SERVER_URL || process.env.RESOLVEIO_SUPPORT_QA_SERVER_URL || \"http://localhost:8080\");',\n\t\t`const username = process.env.RESOLVEIO_RUNNER_QA_USERNAME || process.env.RESOLVEIO_SUPPORT_QA_USERNAME || ${JSON.stringify(defaultUsername)};`,\n\t\t`const password = process.env.RESOLVEIO_RUNNER_QA_PASSWORD || process.env.RESOLVEIO_SUPPORT_QA_PASSWORD || ${JSON.stringify(defaultPassword)};`,\n\t\t'const artifactDir = path.resolve(process.env.RESOLVEIO_RUNNER_QA_ARTIFACT_DIR || process.env.RESOLVEIO_SUPPORT_QA_ARTIFACT_DIR || path.join(projectRoot, \"qa-artifacts\"));',\n\t\t'const viewportWidth = Number(process.env.RESOLVEIO_RUNNER_QA_VIEWPORT_WIDTH || process.env.RESOLVEIO_SUPPORT_QA_VIEWPORT_WIDTH || 1920);',\n\t\t'const viewportHeight = Number(process.env.RESOLVEIO_RUNNER_QA_VIEWPORT_HEIGHT || process.env.RESOLVEIO_SUPPORT_QA_VIEWPORT_HEIGHT || 1080);',\n\t\t'const resultPath = path.join(artifactDir, \"auth-bootstrap-result.json\");',\n\t\t'const readyScreenshotPath = path.join(artifactDir, \"auth-bootstrap-ready.png\");',\n\t\t'const failureScreenshotPath = path.join(artifactDir, \"auth-bootstrap-failed.png\");',\n\t\t'',\n\t\t'function stripTrailingSlash(value) {',\n\t\t'\treturn String(value || \"\").replace(/\\\\/+$/, \"\");',\n\t\t'}',\n\t\t'',\n\t\t'function writeResult(payload) {',\n\t\t'\tfs.mkdirSync(artifactDir, { recursive: true });',\n\t\t'\tfs.writeFileSync(resultPath, JSON.stringify(payload, null, 2));',\n\t\t'}',\n\t\t'',\n\t\t'function requestJson(url, payload) {',\n\t\t'\treturn new Promise((resolve, reject) => {',\n\t\t'\t\tconst body = JSON.stringify(payload || {});',\n\t\t'\t\tconst parsed = new URL(url);',\n\t\t'\t\tconst mod = parsed.protocol === \"https:\" ? https : http;',\n\t\t'\t\tconst req = mod.request(parsed, {',\n\t\t'\t\t\tmethod: \"POST\",',\n\t\t'\t\t\ttimeout: 20000,',\n\t\t'\t\t\theaders: {',\n\t\t'\t\t\t\t\"content-type\": \"application/json\",',\n\t\t'\t\t\t\t\"content-length\": Buffer.byteLength(body),',\n\t\t'\t\t\t\t\"origin\": clientUrl',\n\t\t'\t\t\t}',\n\t\t'\t\t}, (res) => {',\n\t\t'\t\t\tlet raw = \"\";',\n\t\t'\t\t\tres.setEncoding(\"utf8\");',\n\t\t'\t\t\tres.on(\"data\", (chunk) => { raw += chunk; });',\n\t\t'\t\t\tres.on(\"end\", () => {',\n\t\t'\t\t\t\tlet json = null;',\n\t\t'\t\t\t\ttry { json = raw ? JSON.parse(raw) : {}; }',\n\t\t'\t\t\t\tcatch (error) {',\n\t\t'\t\t\t\t\treject(new Error(`${url} returned non-JSON HTTP ${res.statusCode}: ${raw.slice(0, 300)}`));',\n\t\t'\t\t\t\t\treturn;',\n\t\t'\t\t\t\t}',\n\t\t'\t\t\t\tif (!res.statusCode || res.statusCode >= 400) {',\n\t\t'\t\t\t\t\treject(new Error(`${url} returned HTTP ${res.statusCode}: ${JSON.stringify(json).slice(0, 500)}`));',\n\t\t'\t\t\t\t\treturn;',\n\t\t'\t\t\t\t}',\n\t\t'\t\t\t\tresolve(json);',\n\t\t'\t\t\t});',\n\t\t'\t\t});',\n\t\t'\t\treq.on(\"timeout\", () => req.destroy(new Error(`${url} timed out`)));',\n\t\t'\t\treq.on(\"error\", reject);',\n\t\t'\t\treq.write(body);',\n\t\t'\t\treq.end();',\n\t\t'\t});',\n\t\t'}',\n\t\t'',\n\t\t'function requirePuppeteer() {',\n\t\t'\tconst candidates = [',\n\t\t'\t\tpath.join(projectRoot, \"server\", \"node_modules\", \"puppeteer\", \"lib\", \"cjs\", \"puppeteer\", \"puppeteer.js\"),',\n\t\t'\t\tpath.join(projectRoot, \"node_modules\", \"puppeteer\", \"lib\", \"cjs\", \"puppeteer\", \"puppeteer.js\"),',\n\t\t'\t\tpath.join(process.cwd(), \"server\", \"node_modules\", \"puppeteer\", \"lib\", \"cjs\", \"puppeteer\", \"puppeteer.js\"),',\n\t\t'\t\tpath.join(process.cwd(), \"node_modules\", \"puppeteer\", \"lib\", \"cjs\", \"puppeteer\", \"puppeteer.js\"),',\n\t\t'\t\t\"puppeteer\"',\n\t\t'\t];',\n\t\t'\tfor (const candidate of candidates) {',\n\t\t'\t\ttry { return require(candidate); }',\n\t\t'\t\tcatch (error) {}',\n\t\t'\t}',\n\t\t'\tthrow new Error(\"Unable to require puppeteer from project/server node_modules or global resolution\");',\n\t\t'}',\n\t\t'',\n\t\t'async function login() {',\n\t\t'\tif (!password) {',\n\t\t'\t\tthrow new Error(\"QA password is empty; source .resolveio-support-tools/env.sh or set RESOLVEIO_RUNNER_QA_PASSWORD before auth bootstrap\");',\n\t\t'\t}',\n\t\t'\tconst loginJson = await requestJson(`${serverUrl}/login`, { username, password });',\n\t\t'\tconst refreshToken = loginJson && loginJson.result && loginJson.result.token;',\n\t\t'\tif (loginJson.error || !refreshToken) {',\n\t\t'\t\tthrow new Error(`Login failed: ${JSON.stringify(loginJson).slice(0, 800)}`);',\n\t\t'\t}',\n\t\t'\tconst accessJson = await requestJson(`${serverUrl}/accessToken`, { refreshToken });',\n\t\t'\tconst accessToken = accessJson && accessJson.result && accessJson.result.token;',\n\t\t'\tconst user = accessJson && accessJson.result && accessJson.result.user;',\n\t\t'\tif (accessJson.error || !accessToken || !user) {',\n\t\t'\t\tthrow new Error(`Access token failed: ${JSON.stringify(accessJson).slice(0, 800)}`);',\n\t\t'\t}',\n\t\t'\treturn { refreshToken, accessToken, user };',\n\t\t'}',\n\t\t'',\n\t\t'async function launchBrowser(puppeteer) {',\n\t\t'\tconst browserUrl = process.env.RESOLVEIO_RUNNER_QA_BROWSER_URL || process.env.RESOLVEIO_SUPPORT_QA_BROWSER_URL || \"\";',\n\t\t'\tif (browserUrl) {',\n\t\t'\t\treturn puppeteer.connect({ browserURL: browserUrl, protocolTimeout: 30000, defaultViewport: null });',\n\t\t'\t}',\n\t\t'\tconst launchOptions = {',\n\t\t'\t\theadless: true,',\n\t\t'\t\tdefaultViewport: { width: viewportWidth, height: viewportHeight },',\n\t\t'\t\targs: [\"--no-sandbox\", \"--disable-setuid-sandbox\", \"--disable-dev-shm-usage\", `--window-size=${viewportWidth},${viewportHeight}`]',\n\t\t'\t};',\n\t\t'\tif (process.env.PUPPETEER_EXECUTABLE_PATH || process.env.CHROME_BIN) {',\n\t\t'\t\tlaunchOptions.executablePath = process.env.PUPPETEER_EXECUTABLE_PATH || process.env.CHROME_BIN;',\n\t\t'\t}',\n\t\t'\treturn puppeteer.launch(launchOptions);',\n\t\t'}',\n\t\t'',\n\t\t'async function resetBrowserState(page) {',\n\t\t'\tawait page.goto(clientUrl, { waitUntil: \"domcontentloaded\", timeout: 45000 });',\n\t\t'\tawait page.evaluate(async () => {',\n\t\t'\t\ttry {',\n\t\t'\t\t\tconst registrations = await navigator.serviceWorker.getRegistrations();',\n\t\t'\t\t\tawait Promise.all(registrations.map((registration) => registration.unregister().catch(() => false)));',\n\t\t'\t\t} catch (error) {}',\n\t\t'\t\ttry {',\n\t\t'\t\t\tif (window.caches && window.caches.keys) {',\n\t\t'\t\t\t\tconst keys = await window.caches.keys();',\n\t\t'\t\t\t\tawait Promise.all(keys.map((key) => window.caches.delete(key).catch(() => false)));',\n\t\t'\t\t\t}',\n\t\t'\t\t} catch (error) {}',\n\t\t'\t\ttry {',\n\t\t'\t\t\tif (window.indexedDB && window.indexedDB.databases) {',\n\t\t'\t\t\t\tconst databases = await window.indexedDB.databases();',\n\t\t'\t\t\t\tawait Promise.all(databases.filter((database) => database && database.name).map((database) => new Promise((resolve) => {',\n\t\t'\t\t\t\t\tconst request = window.indexedDB.deleteDatabase(database.name);',\n\t\t'\t\t\t\t\trequest.onsuccess = () => resolve(true);',\n\t\t'\t\t\t\t\trequest.onerror = () => resolve(false);',\n\t\t'\t\t\t\t\trequest.onblocked = () => resolve(false);',\n\t\t'\t\t\t\t})));',\n\t\t'\t\t\t}',\n\t\t'\t\t} catch (error) {}',\n\t\t'\t\tlocalStorage.clear();',\n\t\t'\t\tsessionStorage.clear();',\n\t\t'\t});',\n\t\t'}',\n\t\t'',\n\t\t'async function seedAuth(page, auth) {',\n\t\t'\tawait page.evaluate((payload) => {',\n\t\t'\t\tlocalStorage.setItem(\"refreshToken\", payload.refreshToken);',\n\t\t'\t\tlocalStorage.setItem(\"accessToken\", payload.accessToken);',\n\t\t'\t\tlocalStorage.setItem(\"user\", JSON.stringify(payload.user));',\n\t\t'\t\tlocalStorage.setItem(\"lastURL\", payload.lastURL);',\n\t\t'\t\tlocalStorage.setItem(\"resolveio.runnerQaAuthBootstrappedAt\", payload.bootstrappedAt);',\n\t\t'\t}, { ...auth, lastURL: targetRoute, bootstrappedAt: new Date().toISOString() });',\n\t\t'}',\n\t\t'',\n\t\t'function delay(ms) {',\n\t\t'\treturn new Promise((resolve) => setTimeout(resolve, ms));',\n\t\t'}',\n\t\t'',\n\t\t'async function waitForAuthenticatedApp(page) {',\n\t\t'\tconst url = `${clientUrl}${targetRoute}`;',\n\t\t'\tawait page.goto(url, { waitUntil: \"domcontentloaded\", timeout: 60000 });',\n\t\t'\tawait page.waitForFunction(() => {',\n\t\t'\t\tconst text = (document.body && document.body.innerText || \"\").replace(/\\\\s+/g, \" \").trim();',\n\t\t'\t\tconst hasTokens = !!localStorage.getItem(\"refreshToken\") && !!localStorage.getItem(\"accessToken\") && !!localStorage.getItem(\"user\");',\n\t\t'\t\tconst hasLogin = /Employee\\\\/Customer Login|Employee Sign In|Customer Access|Unable to sign in/i.test(text);',\n\t\t'\t\tconst hasOffline = text.includes(\"*** OFFLINE MODE ***\");',\n\t\t'\t\treturn hasTokens && !hasLogin && !hasOffline && text.length > 40;',\n\t\t'\t}, { timeout: Number(process.env.RESOLVEIO_RUNNER_QA_AUTH_TIMEOUT_MS || process.env.RESOLVEIO_SUPPORT_QA_AUTH_TIMEOUT_MS || 60000) });',\n\t\t'\tawait delay(1000);',\n\t\t'}',\n\t\t'',\n\t\t'async function pageSummary(page) {',\n\t\t'\treturn page.evaluate(() => {',\n\t\t'\t\tconst bodyText = (document.body && document.body.innerText || \"\").replace(/\\\\s+/g, \" \").trim();',\n\t\t'\t\treturn {',\n\t\t'\t\t\turl: location.href,',\n\t\t'\t\t\ttitle: document.title,',\n\t\t'\t\t\thasAngularDebug: !!window.ng,',\n\t\t'\t\t\thasRefreshToken: !!localStorage.getItem(\"refreshToken\"),',\n\t\t'\t\t\thasAccessToken: !!localStorage.getItem(\"accessToken\"),',\n\t\t'\t\t\thasUser: !!localStorage.getItem(\"user\"),',\n\t\t'\t\t\thasOfflineModeText: bodyText.includes(\"*** OFFLINE MODE ***\"),',\n\t\t'\t\t\thasLoginText: /Employee\\\\/Customer Login|Employee Sign In|Customer Access|Unable to sign in/i.test(bodyText),',\n\t\t'\t\t\tbodyTextSnippet: bodyText.slice(0, 800),',\n\t\t'\t\t\tlocalStorageKeys: Object.keys(localStorage).sort()',\n\t\t'\t\t};',\n\t\t'\t});',\n\t\t'}',\n\t\t'',\n\t\t'(async () => {',\n\t\t'\tfs.mkdirSync(artifactDir, { recursive: true });',\n\t\t'\tconst auth = await login();',\n\t\t'\tconst puppeteer = requirePuppeteer();',\n\t\t'\tconst browser = await launchBrowser(puppeteer);',\n\t\t'\tlet page;',\n\t\t'\ttry {',\n\t\t'\t\tpage = await browser.newPage();',\n\t\t'\t\tawait page.setViewport({ width: viewportWidth, height: viewportHeight });',\n\t\t'\t\tpage.on(\"console\", (msg) => {',\n\t\t'\t\t\tconst text = msg.text();',\n\t\t'\t\t\tif ([\"error\", \"warning\"].includes(msg.type()) || /error/i.test(text)) {',\n\t\t'\t\t\t\tconsole.log(\"[browser console]\", msg.type(), text);',\n\t\t'\t\t\t}',\n\t\t'\t\t});',\n\t\t'\t\tpage.on(\"pageerror\", (error) => console.log(\"[pageerror]\", error.message));',\n\t\t'\t\tawait resetBrowserState(page);',\n\t\t'\t\tawait seedAuth(page, auth);',\n\t\t'\t\tawait waitForAuthenticatedApp(page);',\n\t\t'\t\tawait page.screenshot({ path: readyScreenshotPath, fullPage: true });',\n\t\t'\t\tconst summary = {',\n\t\t'\t\t\tstatus: \"pass\",',\n\t\t'\t\t\tclientUrl,',\n\t\t'\t\t\tserverUrl,',\n\t\t'\t\t\ttargetRoute,',\n\t\t'\t\t\tscreenshot: readyScreenshotPath,',\n\t\t'\t\t\tuser: { _id: auth.user && auth.user._id, username: auth.user && auth.user.username, fullname: auth.user && auth.user.fullname },',\n\t\t'\t\t\tpage: await pageSummary(page)',\n\t\t'\t\t};',\n\t\t'\t\twriteResult(summary);',\n\t\t'\t\tconsole.log(JSON.stringify(summary, null, 2));',\n\t\t'\t}',\n\t\t'\tcatch (error) {',\n\t\t'\t\tlet summary = { status: \"fail\", clientUrl, serverUrl, targetRoute, screenshot: failureScreenshotPath, error: error && error.stack || String(error) };',\n\t\t'\t\ttry {',\n\t\t'\t\t\tif (page) {',\n\t\t'\t\t\t\tawait page.screenshot({ path: failureScreenshotPath, fullPage: true });',\n\t\t'\t\t\t\tsummary.page = await pageSummary(page);',\n\t\t'\t\t\t}',\n\t\t'\t\t} catch (screenshotError) {',\n\t\t'\t\t\tsummary.screenshotError = screenshotError && screenshotError.stack || String(screenshotError);',\n\t\t'\t\t}',\n\t\t'\t\twriteResult(summary);',\n\t\t'\t\tconsole.error(JSON.stringify(summary, null, 2));',\n\t\t'\t\tprocess.exitCode = 1;',\n\t\t'\t}',\n\t\t'\tfinally {',\n\t\t'\t\tif (browser && typeof browser.close === \"function\") {',\n\t\t'\t\t\tawait browser.close().catch(() => undefined);',\n\t\t'\t\t}',\n\t\t'\t}',\n\t\t'})();',\n\t\t''\n\t].join('\\n');\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/util/ai-runner-qa-auth.ts"],"names":[],"mappings":"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","file":"ai-runner-qa-auth.js","sourcesContent":["export interface ResolveIORunnerQaAuthBootstrapScriptOptions {\n\tdefaultUsername?: string;\n\tdefaultPassword?: string;\n}\n\nexport function buildResolveIORunnerQaAuthBootstrapScript(options: ResolveIORunnerQaAuthBootstrapScriptOptions = {}): string {\n\tconst defaultUsername = options.defaultUsername || 'admin';\n\tconst defaultPassword = options.defaultPassword || '';\n\treturn [\n\t\t'#!/usr/bin/env node',\n\t\t\"'use strict';\",\n\t\t'',\n\t\t'const fs = require(\"fs\");',\n\t\t'const crypto = require(\"crypto\");',\n\t\t'const http = require(\"http\");',\n\t\t'const https = require(\"https\");',\n\t\t'const path = require(\"path\");',\n\t\t'',\n\t\t'const projectRoot = path.resolve(process.argv[2] || process.cwd());',\n\t\t'const routeArg = process.argv[3] || process.env.RESOLVEIO_RUNNER_QA_TARGET_ROUTE || process.env.RESOLVEIO_SUPPORT_QA_TARGET_ROUTE || process.env.RESOLVEIO_SUPPORT_QA_LAST_URL || \"/\";',\n\t\t'const targetRoute = routeArg.startsWith(\"/\") ? routeArg : `/${routeArg}`;',\n\t\t'const clientUrl = stripTrailingSlash(process.env.RESOLVEIO_RUNNER_QA_CLIENT_URL || process.env.RESOLVEIO_SUPPORT_QA_CLIENT_URL || `http://localhost:${process.env.RESOLVEIO_SUPPORT_QA_CLIENT_PORT || \"4200\"}`);',\n\t\t'const serverUrl = stripTrailingSlash(process.env.RESOLVEIO_RUNNER_QA_SERVER_URL || process.env.RESOLVEIO_SUPPORT_QA_SERVER_URL || \"http://localhost:8080\");',\n\t\t`const username = process.env.RESOLVEIO_RUNNER_QA_USERNAME || process.env.RESOLVEIO_SUPPORT_QA_USERNAME || ${JSON.stringify(defaultUsername)};`,\n\t\t`const password = process.env.RESOLVEIO_RUNNER_QA_PASSWORD || process.env.RESOLVEIO_SUPPORT_QA_PASSWORD || ${JSON.stringify(defaultPassword)};`,\n\t\t'const artifactDir = path.resolve(process.env.RESOLVEIO_RUNNER_QA_ARTIFACT_DIR || process.env.RESOLVEIO_SUPPORT_QA_ARTIFACT_DIR || path.join(projectRoot, \"qa-artifacts\"));',\n\t\t'const viewportWidth = Number(process.env.RESOLVEIO_RUNNER_QA_VIEWPORT_WIDTH || process.env.RESOLVEIO_SUPPORT_QA_VIEWPORT_WIDTH || 1920);',\n\t\t'const viewportHeight = Number(process.env.RESOLVEIO_RUNNER_QA_VIEWPORT_HEIGHT || process.env.RESOLVEIO_SUPPORT_QA_VIEWPORT_HEIGHT || 1080);',\n\t\t'const resultPath = path.join(artifactDir, \"auth-bootstrap-result.json\");',\n\t\t'const readyScreenshotPath = path.join(artifactDir, \"auth-bootstrap-ready.png\");',\n\t\t'const failureScreenshotPath = path.join(artifactDir, \"auth-bootstrap-failed.png\");',\n\t\t'',\n\t\t'function stripTrailingSlash(value) {',\n\t\t'\treturn String(value || \"\").replace(/\\\\/+$/, \"\");',\n\t\t'}',\n\t\t'',\n\t\t'function isLocalhostUrl(value) {',\n\t\t'\ttry {',\n\t\t'\t\tconst parsed = new URL(value);',\n\t\t'\t\treturn [\"localhost\", \"127.0.0.1\", \"::1\"].includes(parsed.hostname);',\n\t\t'\t}',\n\t\t'\tcatch (error) {',\n\t\t'\t\treturn false;',\n\t\t'\t}',\n\t\t'}',\n\t\t'',\n\t\t'function resolveLocalMongoUrl() {',\n\t\t'\treturn process.env.MONGO_URL || process.env.RESOLVEIO_RUNNER_QA_MONGO_URL || process.env.RESOLVEIO_SUPPORT_QA_MONGO_URL || `mongodb://127.0.0.1:${process.env.RESOLVEIO_SUPPORT_QA_MONGO_PORT || \"3001\"}/resolveio?directConnection=true`;',\n\t\t'}',\n\t\t'',\n\t\t'function requireMongoClient() {',\n\t\t'\tconst candidates = [',\n\t\t'\t\tpath.join(projectRoot, \"server\", \"node_modules\", \"mongodb\"),',\n\t\t'\t\tpath.join(projectRoot, \"node_modules\", \"mongodb\"),',\n\t\t'\t\tpath.join(process.cwd(), \"server\", \"node_modules\", \"mongodb\"),',\n\t\t'\t\tpath.join(process.cwd(), \"node_modules\", \"mongodb\"),',\n\t\t'\t\t\"mongodb\"',\n\t\t'\t];',\n\t\t'\tfor (const candidate of candidates) {',\n\t\t'\t\ttry { return require(candidate).MongoClient; }',\n\t\t'\t\tcatch (error) {}',\n\t\t'\t}',\n\t\t'\tthrow new Error(\"Unable to require mongodb from project/server node_modules or global resolution\");',\n\t\t'}',\n\t\t'',\n\t\t'async function ensureLocalQaUser() {',\n\t\t'\tif (!isLocalhostUrl(serverUrl) || process.env.RESOLVEIO_RUNNER_QA_DISABLE_LOCAL_USER_REPAIR === \"true\" || process.env.RESOLVEIO_SUPPORT_QA_DISABLE_LOCAL_USER_REPAIR === \"true\") {',\n\t\t'\t\treturn false;',\n\t\t'\t}',\n\t\t'\tconst MongoClient = requireMongoClient();',\n\t\t'\tconst client = new MongoClient(resolveLocalMongoUrl());',\n\t\t'\tawait client.connect();',\n\t\t'\ttry {',\n\t\t'\t\tconst db = client.db();',\n\t\t'\t\tconst users = db.collection(\"users\");',\n\t\t'\t\tconst now = new Date();',\n\t\t'\t\tconst salt = crypto.randomBytes(32).toString(\"hex\");',\n\t\t'\t\tconst hash = crypto.pbkdf2Sync(password, salt, 25000, 512, \"sha256\").toString(\"hex\");',\n\t\t'\t\tconst existing = await users.findOne({ $or: [{ username }, { email: username }] }, { projection: { _id: 1 } });',\n\t\t'\t\tconst baseUser = {',\n\t\t'\t\t\t__v: 0,',\n\t\t'\t\t\tusername,',\n\t\t'\t\t\temail: username.includes(\"@\") ? username : \"dev@resolveio.com\",',\n\t\t'\t\t\tfullname: \"QA Admin\",',\n\t\t'\t\t\troles: { super_admin: true, approvals: [], groups: [], notifications: [], miscs: [] },',\n\t\t'\t\t\tactive: true,',\n\t\t'\t\t\tother: { yards: [] },',\n\t\t'\t\t\tphonenumber: \"\",',\n\t\t'\t\t\treadonly: false,',\n\t\t'\t\t\tis_customer: false,',\n\t\t'\t\t\thash,',\n\t\t'\t\t\tsalt,',\n\t\t'\t\t\tattempts: 0,',\n\t\t'\t\t\tservices: {},',\n\t\t'\t\t\tupdatedAt: now',\n\t\t'\t\t};',\n\t\t'\t\tif (existing && existing._id) {',\n\t\t'\t\t\tawait users.updateOne({ _id: existing._id }, { $set: baseUser });',\n\t\t'\t\t}',\n\t\t'\t\telse {',\n\t\t'\t\t\tawait users.insertOne({ _id: crypto.randomBytes(12).toString(\"hex\"), createdAt: now, ...baseUser });',\n\t\t'\t\t}',\n\t\t'\t\treturn true;',\n\t\t'\t}',\n\t\t'\tfinally {',\n\t\t'\t\tawait client.close().catch(() => undefined);',\n\t\t'\t}',\n\t\t'}',\n\t\t'',\n\t\t'function writeResult(payload) {',\n\t\t'\tfs.mkdirSync(artifactDir, { recursive: true });',\n\t\t'\tfs.writeFileSync(resultPath, JSON.stringify(payload, null, 2));',\n\t\t'}',\n\t\t'',\n\t\t'function requestJson(url, payload) {',\n\t\t'\treturn new Promise((resolve, reject) => {',\n\t\t'\t\tconst body = JSON.stringify(payload || {});',\n\t\t'\t\tconst parsed = new URL(url);',\n\t\t'\t\tconst mod = parsed.protocol === \"https:\" ? https : http;',\n\t\t'\t\tconst req = mod.request(parsed, {',\n\t\t'\t\t\tmethod: \"POST\",',\n\t\t'\t\t\ttimeout: 20000,',\n\t\t'\t\t\theaders: {',\n\t\t'\t\t\t\t\"content-type\": \"application/json\",',\n\t\t'\t\t\t\t\"content-length\": Buffer.byteLength(body),',\n\t\t'\t\t\t\t\"origin\": clientUrl',\n\t\t'\t\t\t}',\n\t\t'\t\t}, (res) => {',\n\t\t'\t\t\tlet raw = \"\";',\n\t\t'\t\t\tres.setEncoding(\"utf8\");',\n\t\t'\t\t\tres.on(\"data\", (chunk) => { raw += chunk; });',\n\t\t'\t\t\tres.on(\"end\", () => {',\n\t\t'\t\t\t\tlet json = null;',\n\t\t'\t\t\t\ttry { json = raw ? JSON.parse(raw) : {}; }',\n\t\t'\t\t\t\tcatch (error) {',\n\t\t'\t\t\t\t\treject(new Error(`${url} returned non-JSON HTTP ${res.statusCode}: ${raw.slice(0, 300)}`));',\n\t\t'\t\t\t\t\treturn;',\n\t\t'\t\t\t\t}',\n\t\t'\t\t\t\tif (!res.statusCode || res.statusCode >= 400) {',\n\t\t'\t\t\t\t\treject(new Error(`${url} returned HTTP ${res.statusCode}: ${JSON.stringify(json).slice(0, 500)}`));',\n\t\t'\t\t\t\t\treturn;',\n\t\t'\t\t\t\t}',\n\t\t'\t\t\t\tresolve(json);',\n\t\t'\t\t\t});',\n\t\t'\t\t});',\n\t\t'\t\treq.on(\"timeout\", () => req.destroy(new Error(`${url} timed out`)));',\n\t\t'\t\treq.on(\"error\", reject);',\n\t\t'\t\treq.write(body);',\n\t\t'\t\treq.end();',\n\t\t'\t});',\n\t\t'}',\n\t\t'',\n\t\t'function requirePuppeteer() {',\n\t\t'\tconst candidates = [',\n\t\t'\t\tpath.join(projectRoot, \"server\", \"node_modules\", \"puppeteer\", \"lib\", \"cjs\", \"puppeteer\", \"puppeteer.js\"),',\n\t\t'\t\tpath.join(projectRoot, \"node_modules\", \"puppeteer\", \"lib\", \"cjs\", \"puppeteer\", \"puppeteer.js\"),',\n\t\t'\t\tpath.join(process.cwd(), \"server\", \"node_modules\", \"puppeteer\", \"lib\", \"cjs\", \"puppeteer\", \"puppeteer.js\"),',\n\t\t'\t\tpath.join(process.cwd(), \"node_modules\", \"puppeteer\", \"lib\", \"cjs\", \"puppeteer\", \"puppeteer.js\"),',\n\t\t'\t\t\"puppeteer\"',\n\t\t'\t];',\n\t\t'\tfor (const candidate of candidates) {',\n\t\t'\t\ttry { return require(candidate); }',\n\t\t'\t\tcatch (error) {}',\n\t\t'\t}',\n\t\t'\tthrow new Error(\"Unable to require puppeteer from project/server node_modules or global resolution\");',\n\t\t'}',\n\t\t'',\n\t\t'async function login() {',\n\t\t'\tif (!password) {',\n\t\t'\t\tthrow new Error(\"QA password is empty; source .resolveio-support-tools/env.sh or set RESOLVEIO_RUNNER_QA_PASSWORD before auth bootstrap\");',\n\t\t'\t}',\n\t\t'\tlet loginJson = await requestJson(`${serverUrl}/login`, { username, password });',\n\t\t'\tif ((loginJson && loginJson.error) && /Invalid Username And Password|Too Many Attempts/i.test(String(loginJson.result || \"\"))) {',\n\t\t'\t\tconst repaired = await ensureLocalQaUser();',\n\t\t'\t\tif (repaired) {',\n\t\t'\t\t\tloginJson = await requestJson(`${serverUrl}/login`, { username, password });',\n\t\t'\t\t}',\n\t\t'\t}',\n\t\t'\tconst refreshToken = loginJson && loginJson.result && loginJson.result.token;',\n\t\t'\tif (loginJson.error || !refreshToken) {',\n\t\t'\t\tthrow new Error(`Login failed: ${JSON.stringify(loginJson).slice(0, 800)}`);',\n\t\t'\t}',\n\t\t'\tconst accessJson = await requestJson(`${serverUrl}/accessToken`, { refreshToken });',\n\t\t'\tconst accessToken = accessJson && accessJson.result && accessJson.result.token;',\n\t\t'\tconst user = accessJson && accessJson.result && accessJson.result.user;',\n\t\t'\tif (accessJson.error || !accessToken || !user) {',\n\t\t'\t\tthrow new Error(`Access token failed: ${JSON.stringify(accessJson).slice(0, 800)}`);',\n\t\t'\t}',\n\t\t'\treturn { refreshToken, accessToken, user };',\n\t\t'}',\n\t\t'',\n\t\t'async function launchBrowser(puppeteer) {',\n\t\t'\tconst browserUrl = process.env.RESOLVEIO_RUNNER_QA_BROWSER_URL || process.env.RESOLVEIO_SUPPORT_QA_BROWSER_URL || \"\";',\n\t\t'\tif (browserUrl) {',\n\t\t'\t\treturn puppeteer.connect({ browserURL: browserUrl, protocolTimeout: 30000, defaultViewport: null });',\n\t\t'\t}',\n\t\t'\tconst launchOptions = {',\n\t\t'\t\theadless: true,',\n\t\t'\t\tdefaultViewport: { width: viewportWidth, height: viewportHeight },',\n\t\t'\t\targs: [\"--no-sandbox\", \"--disable-setuid-sandbox\", \"--disable-dev-shm-usage\", `--window-size=${viewportWidth},${viewportHeight}`]',\n\t\t'\t};',\n\t\t'\tif (process.env.PUPPETEER_EXECUTABLE_PATH || process.env.CHROME_BIN) {',\n\t\t'\t\tlaunchOptions.executablePath = process.env.PUPPETEER_EXECUTABLE_PATH || process.env.CHROME_BIN;',\n\t\t'\t}',\n\t\t'\treturn puppeteer.launch(launchOptions);',\n\t\t'}',\n\t\t'',\n\t\t'async function resetBrowserState(page) {',\n\t\t'\tawait page.goto(clientUrl, { waitUntil: \"domcontentloaded\", timeout: 45000 });',\n\t\t'\tawait page.evaluate(async () => {',\n\t\t'\t\ttry {',\n\t\t'\t\t\tconst registrations = await navigator.serviceWorker.getRegistrations();',\n\t\t'\t\t\tawait Promise.all(registrations.map((registration) => registration.unregister().catch(() => false)));',\n\t\t'\t\t} catch (error) {}',\n\t\t'\t\ttry {',\n\t\t'\t\t\tif (window.caches && window.caches.keys) {',\n\t\t'\t\t\t\tconst keys = await window.caches.keys();',\n\t\t'\t\t\t\tawait Promise.all(keys.map((key) => window.caches.delete(key).catch(() => false)));',\n\t\t'\t\t\t}',\n\t\t'\t\t} catch (error) {}',\n\t\t'\t\ttry {',\n\t\t'\t\t\tif (window.indexedDB && window.indexedDB.databases) {',\n\t\t'\t\t\t\tconst databases = await window.indexedDB.databases();',\n\t\t'\t\t\t\tawait Promise.all(databases.filter((database) => database && database.name).map((database) => new Promise((resolve) => {',\n\t\t'\t\t\t\t\tconst request = window.indexedDB.deleteDatabase(database.name);',\n\t\t'\t\t\t\t\trequest.onsuccess = () => resolve(true);',\n\t\t'\t\t\t\t\trequest.onerror = () => resolve(false);',\n\t\t'\t\t\t\t\trequest.onblocked = () => resolve(false);',\n\t\t'\t\t\t\t})));',\n\t\t'\t\t\t}',\n\t\t'\t\t} catch (error) {}',\n\t\t'\t\tlocalStorage.clear();',\n\t\t'\t\tsessionStorage.clear();',\n\t\t'\t});',\n\t\t'}',\n\t\t'',\n\t\t'async function seedAuth(page, auth) {',\n\t\t'\tawait page.evaluate((payload) => {',\n\t\t'\t\tlocalStorage.setItem(\"refreshToken\", payload.refreshToken);',\n\t\t'\t\tlocalStorage.setItem(\"accessToken\", payload.accessToken);',\n\t\t'\t\tlocalStorage.setItem(\"user\", JSON.stringify(payload.user));',\n\t\t'\t\tlocalStorage.setItem(\"lastURL\", payload.lastURL);',\n\t\t'\t\tlocalStorage.setItem(\"resolveio.runnerQaAuthBootstrappedAt\", payload.bootstrappedAt);',\n\t\t'\t}, { ...auth, lastURL: targetRoute, bootstrappedAt: new Date().toISOString() });',\n\t\t'}',\n\t\t'',\n\t\t'function delay(ms) {',\n\t\t'\treturn new Promise((resolve) => setTimeout(resolve, ms));',\n\t\t'}',\n\t\t'',\n\t\t'async function waitForAuthenticatedApp(page) {',\n\t\t'\tconst url = `${clientUrl}${targetRoute}`;',\n\t\t'\tawait page.goto(url, { waitUntil: \"domcontentloaded\", timeout: 60000 });',\n\t\t'\tawait page.waitForFunction(() => {',\n\t\t'\t\tconst text = (document.body && document.body.innerText || \"\").replace(/\\\\s+/g, \" \").trim();',\n\t\t'\t\tconst hasTokens = !!localStorage.getItem(\"refreshToken\") && !!localStorage.getItem(\"accessToken\") && !!localStorage.getItem(\"user\");',\n\t\t'\t\tconst hasLogin = /Employee\\\\/Customer Login|Employee Sign In|Customer Access|Unable to sign in/i.test(text);',\n\t\t'\t\tconst hasOffline = text.includes(\"*** OFFLINE MODE ***\");',\n\t\t'\t\treturn hasTokens && !hasLogin && !hasOffline && text.length > 40;',\n\t\t'\t}, { timeout: Number(process.env.RESOLVEIO_RUNNER_QA_AUTH_TIMEOUT_MS || process.env.RESOLVEIO_SUPPORT_QA_AUTH_TIMEOUT_MS || 60000) });',\n\t\t'\tawait delay(1000);',\n\t\t'}',\n\t\t'',\n\t\t'async function pageSummary(page) {',\n\t\t'\treturn page.evaluate(() => {',\n\t\t'\t\tconst bodyText = (document.body && document.body.innerText || \"\").replace(/\\\\s+/g, \" \").trim();',\n\t\t'\t\treturn {',\n\t\t'\t\t\turl: location.href,',\n\t\t'\t\t\ttitle: document.title,',\n\t\t'\t\t\thasAngularDebug: !!window.ng,',\n\t\t'\t\t\thasRefreshToken: !!localStorage.getItem(\"refreshToken\"),',\n\t\t'\t\t\thasAccessToken: !!localStorage.getItem(\"accessToken\"),',\n\t\t'\t\t\thasUser: !!localStorage.getItem(\"user\"),',\n\t\t'\t\t\thasOfflineModeText: bodyText.includes(\"*** OFFLINE MODE ***\"),',\n\t\t'\t\t\thasLoginText: /Employee\\\\/Customer Login|Employee Sign In|Customer Access|Unable to sign in/i.test(bodyText),',\n\t\t'\t\t\tbodyTextSnippet: bodyText.slice(0, 800),',\n\t\t'\t\t\tlocalStorageKeys: Object.keys(localStorage).sort()',\n\t\t'\t\t};',\n\t\t'\t});',\n\t\t'}',\n\t\t'',\n\t\t'(async () => {',\n\t\t'\tfs.mkdirSync(artifactDir, { recursive: true });',\n\t\t'\tconst auth = await login();',\n\t\t'\tconst puppeteer = requirePuppeteer();',\n\t\t'\tconst browser = await launchBrowser(puppeteer);',\n\t\t'\tlet page;',\n\t\t'\ttry {',\n\t\t'\t\tpage = await browser.newPage();',\n\t\t'\t\tawait page.setViewport({ width: viewportWidth, height: viewportHeight });',\n\t\t'\t\tpage.on(\"console\", (msg) => {',\n\t\t'\t\t\tconst text = msg.text();',\n\t\t'\t\t\tif ([\"error\", \"warning\"].includes(msg.type()) || /error/i.test(text)) {',\n\t\t'\t\t\t\tconsole.log(\"[browser console]\", msg.type(), text);',\n\t\t'\t\t\t}',\n\t\t'\t\t});',\n\t\t'\t\tpage.on(\"pageerror\", (error) => console.log(\"[pageerror]\", error.message));',\n\t\t'\t\tawait resetBrowserState(page);',\n\t\t'\t\tawait seedAuth(page, auth);',\n\t\t'\t\tawait waitForAuthenticatedApp(page);',\n\t\t'\t\tawait page.screenshot({ path: readyScreenshotPath, fullPage: true });',\n\t\t'\t\tconst summary = {',\n\t\t'\t\t\tstatus: \"pass\",',\n\t\t'\t\t\tclientUrl,',\n\t\t'\t\t\tserverUrl,',\n\t\t'\t\t\ttargetRoute,',\n\t\t'\t\t\tscreenshot: readyScreenshotPath,',\n\t\t'\t\t\tuser: { _id: auth.user && auth.user._id, username: auth.user && auth.user.username, fullname: auth.user && auth.user.fullname },',\n\t\t'\t\t\tpage: await pageSummary(page)',\n\t\t'\t\t};',\n\t\t'\t\twriteResult(summary);',\n\t\t'\t\tconsole.log(JSON.stringify(summary, null, 2));',\n\t\t'\t}',\n\t\t'\tcatch (error) {',\n\t\t'\t\tlet summary = { status: \"fail\", clientUrl, serverUrl, targetRoute, screenshot: failureScreenshotPath, error: error && error.stack || String(error) };',\n\t\t'\t\ttry {',\n\t\t'\t\t\tif (page) {',\n\t\t'\t\t\t\tawait page.screenshot({ path: failureScreenshotPath, fullPage: true });',\n\t\t'\t\t\t\tsummary.page = await pageSummary(page);',\n\t\t'\t\t\t}',\n\t\t'\t\t} catch (screenshotError) {',\n\t\t'\t\t\tsummary.screenshotError = screenshotError && screenshotError.stack || String(screenshotError);',\n\t\t'\t\t}',\n\t\t'\t\twriteResult(summary);',\n\t\t'\t\tconsole.error(JSON.stringify(summary, null, 2));',\n\t\t'\t\tprocess.exitCode = 1;',\n\t\t'\t}',\n\t\t'\tfinally {',\n\t\t'\t\tif (browser && typeof browser.close === \"function\") {',\n\t\t'\t\t\tawait browser.close().catch(() => undefined);',\n\t\t'\t\t}',\n\t\t'\t}',\n\t\t'})();',\n\t\t''\n\t].join('\\n');\n}\n"]}
|