@bigbinary/neeto-playwright-commons 3.0.8 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/index.cjs.js +287 -42
- package/index.cjs.js.map +1 -1
- package/index.d.ts +112 -31
- package/index.js +287 -44
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/neeto-chat-widget/setup.sh +15 -0
package/README.md
CHANGED
|
@@ -132,6 +132,7 @@ import { COMMON_SELECTORS } from "@bigbinary/neeto-playwright-common";
|
|
|
132
132
|
- [MailerUtils](./docs/utils/mailer-utils.md)
|
|
133
133
|
- [EmailDeliveryUtils](./docs/utils/email-delivery-utils.md)
|
|
134
134
|
- [NeetoAuthServer](./docs/utils/neeto-auth-server.md)
|
|
135
|
+
- [NeetoChatWidget](./docs/utils/neeto-chat-widget.md)
|
|
135
136
|
- [Util functions](./docs/utils)
|
|
136
137
|
- [POMs](./docs/poms)
|
|
137
138
|
- [Integration](./docs/integration)
|
package/index.cjs.js
CHANGED
|
@@ -60529,7 +60529,7 @@ class RailsEmailUtils {
|
|
|
60529
60529
|
});
|
|
60530
60530
|
return otp || undefined;
|
|
60531
60531
|
};
|
|
60532
|
-
getEmailAttachment = async (
|
|
60532
|
+
getEmailAttachment = async ({ name, type }, messageSearchCriteria = {}, { receivedAfter = new Date(new Date().valueOf() - 60 * 60 * 1000), expectedEmailCount = 1, timeout = 10_000, } = {}, shouldThrowErrorOnTimeout = true) => {
|
|
60533
60533
|
const attachmentDetails = (await this.neetoPlaywrightUtilities.executeRecursively({
|
|
60534
60534
|
callback: async () => {
|
|
60535
60535
|
const railsEmail = await this.railsEmailClient.getLatestEmail({
|
|
@@ -60538,7 +60538,11 @@ class RailsEmailUtils {
|
|
|
60538
60538
|
});
|
|
60539
60539
|
if (!railsEmail)
|
|
60540
60540
|
return null;
|
|
60541
|
-
const attachment = railsEmail.attachments?.find(att =>
|
|
60541
|
+
const attachment = railsEmail.attachments?.find(att => {
|
|
60542
|
+
const matchesName = name ? att.name?.includes(name) : true;
|
|
60543
|
+
const matchesType = type ? att.type?.startsWith(type) : true;
|
|
60544
|
+
return matchesName && matchesType;
|
|
60545
|
+
});
|
|
60542
60546
|
if (!attachment)
|
|
60543
60547
|
return null;
|
|
60544
60548
|
return {
|
|
@@ -60722,19 +60726,26 @@ class MailerUtils {
|
|
|
60722
60726
|
return codes?.[0];
|
|
60723
60727
|
};
|
|
60724
60728
|
generateRandomEmail = () => faker.faker.internet.email({ provider: process.env.FASTMAIL_DOMAIN_NAME });
|
|
60725
|
-
getEmailAttachment = async (
|
|
60726
|
-
if (IS_DEV_ENV)
|
|
60727
|
-
return this.railsEmailUtils.getEmailAttachment(
|
|
60728
|
-
}
|
|
60729
|
+
getEmailAttachment = async ({ name, type }, messageSearchCriteria = {}, { timeout = 10_000, receivedAfter = dateTimeOneHourAgo(), expectedEmailCount = 1, } = {}, shouldThrowErrorOnTimeout = true) => {
|
|
60730
|
+
if (IS_DEV_ENV)
|
|
60731
|
+
return this.railsEmailUtils.getEmailAttachment({ name, type }, messageSearchCriteria, { receivedAfter, expectedEmailCount, timeout: timeout / 3 }, shouldThrowErrorOnTimeout);
|
|
60729
60732
|
const { blobId, attachments: attachmentNameAndTypes } = await this.findMessage(messageSearchCriteria, { expectedEmailCount, receivedAfter, timeout }, shouldThrowErrorOnTimeout);
|
|
60730
|
-
const attachment = attachmentNameAndTypes.find(
|
|
60733
|
+
const attachment = attachmentNameAndTypes.find(att => {
|
|
60734
|
+
const matchesName = name ? att.name?.includes(name) : true;
|
|
60735
|
+
const matchesType = type ? att.type?.startsWith(type) : true;
|
|
60736
|
+
return matchesName && matchesType;
|
|
60737
|
+
});
|
|
60731
60738
|
if (!attachment)
|
|
60732
60739
|
throw new Error("No such attachment exists");
|
|
60733
60740
|
const emailAttachment = await this.fastmailApi.fetchAttachments(blobId, attachment.name);
|
|
60734
60741
|
const buffer = await emailAttachment.body();
|
|
60735
60742
|
const parsedEmail = await mailparserExports.simpleParser(buffer);
|
|
60736
60743
|
const attachments = parsedEmail.attachments;
|
|
60737
|
-
return attachments.find(
|
|
60744
|
+
return attachments.find(att => {
|
|
60745
|
+
const matchesName = name ? att.filename?.includes(name) : true;
|
|
60746
|
+
const matchesType = type ? att.contentType?.startsWith(type) : true;
|
|
60747
|
+
return matchesName && matchesType;
|
|
60748
|
+
});
|
|
60738
60749
|
};
|
|
60739
60750
|
}
|
|
60740
60751
|
|
|
@@ -125124,22 +125135,22 @@ async function warmup({ urls = DEFAULT_WARMUP_URLS, timeout = 60_000, } = {}) {
|
|
|
125124
125135
|
}
|
|
125125
125136
|
}
|
|
125126
125137
|
|
|
125127
|
-
const CONFIG = {
|
|
125138
|
+
const CONFIG$1 = {
|
|
125128
125139
|
DIR: "/tmp/neeto-auth-web",
|
|
125129
125140
|
LOG: "/tmp/neeto-auth-server.log",
|
|
125130
125141
|
PORT: 9000,
|
|
125131
125142
|
MAX_WAIT_MS: 120_000,
|
|
125132
125143
|
EMAIL_INIT: "/tmp/neeto-auth-web/config/initializers/playwright_email_capture.rb",
|
|
125133
125144
|
};
|
|
125134
|
-
const SCRIPTS_DIR = path__namespace.join(__dirname, "scripts", "neeto-auth");
|
|
125145
|
+
const SCRIPTS_DIR$1 = path__namespace.join(__dirname, "scripts", "neeto-auth");
|
|
125135
125146
|
const escapeRubyString = (value) => value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
125136
125147
|
const buildEmailCaptureInitializer = (targetApp) => {
|
|
125137
|
-
const template = fs__namespace.readFileSync(path__namespace.join(SCRIPTS_DIR, "playwright_email_capture.rb.template"), "utf-8");
|
|
125148
|
+
const template = fs__namespace.readFileSync(path__namespace.join(SCRIPTS_DIR$1, "playwright_email_capture.rb.template"), "utf-8");
|
|
125138
125149
|
return template.replace("{{TARGET_APP}}", escapeRubyString(targetApp));
|
|
125139
125150
|
};
|
|
125140
|
-
const log = (msg) => console.log(`[NeetoAuth] ${msg}`);
|
|
125141
|
-
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
125142
|
-
const httpCheck = (port, timeout = 3000) => new Promise(resolve => {
|
|
125151
|
+
const log$1 = (msg) => console.log(`[NeetoAuth] ${msg}`);
|
|
125152
|
+
const sleep$1 = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
125153
|
+
const httpCheck$1 = (port, timeout = 3000) => new Promise(resolve => {
|
|
125143
125154
|
const req = http__namespace.get(`http://localhost:${port}/`, () => resolve(true));
|
|
125144
125155
|
req.on("error", () => resolve(false));
|
|
125145
125156
|
req.setTimeout(timeout, () => {
|
|
@@ -125166,7 +125177,7 @@ class NeetoAuthServer {
|
|
|
125166
125177
|
while (Date.now() < deadline) {
|
|
125167
125178
|
try {
|
|
125168
125179
|
process.kill(pid, 0);
|
|
125169
|
-
await sleep(500);
|
|
125180
|
+
await sleep$1(500);
|
|
125170
125181
|
}
|
|
125171
125182
|
catch {
|
|
125172
125183
|
return;
|
|
@@ -125175,27 +125186,27 @@ class NeetoAuthServer {
|
|
|
125175
125186
|
};
|
|
125176
125187
|
killServerOnPort = async () => {
|
|
125177
125188
|
try {
|
|
125178
|
-
child_process.execSync(`lsof -ti tcp:${CONFIG.PORT} | xargs kill -9`, {
|
|
125189
|
+
child_process.execSync(`lsof -ti tcp:${CONFIG$1.PORT} | xargs kill -9`, {
|
|
125179
125190
|
stdio: "ignore",
|
|
125180
125191
|
});
|
|
125181
|
-
await sleep(1000);
|
|
125192
|
+
await sleep$1(1000);
|
|
125182
125193
|
}
|
|
125183
125194
|
catch {
|
|
125184
125195
|
// No process on that port — nothing to kill.
|
|
125185
125196
|
}
|
|
125186
125197
|
};
|
|
125187
125198
|
ensureSetup = () => {
|
|
125188
|
-
if (fs__namespace.existsSync(`${CONFIG.DIR}/Gemfile`)) {
|
|
125189
|
-
log("Already set up, skipping.");
|
|
125199
|
+
if (fs__namespace.existsSync(`${CONFIG$1.DIR}/Gemfile`)) {
|
|
125200
|
+
log$1("Already set up, skipping.");
|
|
125190
125201
|
return;
|
|
125191
125202
|
}
|
|
125192
125203
|
if (!process.env.GITHUB_TOKEN) {
|
|
125193
125204
|
throw new Error("[NeetoAuth] GITHUB_TOKEN is not set. Cannot clone neeto-auth-web.");
|
|
125194
125205
|
}
|
|
125195
|
-
log("Running first-time setup...");
|
|
125196
|
-
const setupScript = path__namespace.join(SCRIPTS_DIR, "setup.sh");
|
|
125206
|
+
log$1("Running first-time setup...");
|
|
125207
|
+
const setupScript = path__namespace.join(SCRIPTS_DIR$1, "setup.sh");
|
|
125197
125208
|
try {
|
|
125198
|
-
child_process.execSync(`bash "${setupScript}" "${CONFIG.DIR}"`, {
|
|
125209
|
+
child_process.execSync(`bash "${setupScript}" "${CONFIG$1.DIR}"`, {
|
|
125199
125210
|
stdio: "inherit",
|
|
125200
125211
|
env: this.serverEnv,
|
|
125201
125212
|
});
|
|
@@ -125203,73 +125214,73 @@ class NeetoAuthServer {
|
|
|
125203
125214
|
catch {
|
|
125204
125215
|
throw new Error("[NeetoAuth] First-time setup failed. Check the output above for details.");
|
|
125205
125216
|
}
|
|
125206
|
-
log("Setup complete.");
|
|
125217
|
+
log$1("Setup complete.");
|
|
125207
125218
|
};
|
|
125208
|
-
waitForServer = async (timeoutMs = CONFIG.MAX_WAIT_MS) => {
|
|
125219
|
+
waitForServer = async (timeoutMs = CONFIG$1.MAX_WAIT_MS) => {
|
|
125209
125220
|
const startTime = Date.now();
|
|
125210
125221
|
while (Date.now() - startTime < timeoutMs) {
|
|
125211
125222
|
if (this.process !== null && this.process.exitCode !== null) {
|
|
125212
|
-
const logContent = fs__namespace.existsSync(CONFIG.LOG)
|
|
125213
|
-
? fs__namespace.readFileSync(CONFIG.LOG, "utf-8")
|
|
125223
|
+
const logContent = fs__namespace.existsSync(CONFIG$1.LOG)
|
|
125224
|
+
? fs__namespace.readFileSync(CONFIG$1.LOG, "utf-8")
|
|
125214
125225
|
: "<no log file>";
|
|
125215
125226
|
throw new Error(`[NeetoAuth] Server process exited unexpectedly with code ${this.process.exitCode}.\nLog:\n${logContent}`);
|
|
125216
125227
|
}
|
|
125217
|
-
if (await httpCheck(CONFIG.PORT))
|
|
125228
|
+
if (await httpCheck$1(CONFIG$1.PORT))
|
|
125218
125229
|
return;
|
|
125219
|
-
await sleep(3000);
|
|
125230
|
+
await sleep$1(3000);
|
|
125220
125231
|
}
|
|
125221
|
-
const logContent = fs__namespace.existsSync(CONFIG.LOG)
|
|
125222
|
-
? fs__namespace.readFileSync(CONFIG.LOG, "utf-8")
|
|
125232
|
+
const logContent = fs__namespace.existsSync(CONFIG$1.LOG)
|
|
125233
|
+
? fs__namespace.readFileSync(CONFIG$1.LOG, "utf-8")
|
|
125223
125234
|
: "<no log file>";
|
|
125224
125235
|
throw new Error(`[NeetoAuth] Server did not start within ${timeoutMs / 1000}s.\nLog:\n${logContent}`);
|
|
125225
125236
|
};
|
|
125226
125237
|
injectEmailCaptureInitializer = () => {
|
|
125227
|
-
fs__namespace.writeFileSync(CONFIG.EMAIL_INIT, buildEmailCaptureInitializer(this.targetApp));
|
|
125238
|
+
fs__namespace.writeFileSync(CONFIG$1.EMAIL_INIT, buildEmailCaptureInitializer(this.targetApp));
|
|
125228
125239
|
};
|
|
125229
125240
|
isRunningForCurrentApp = () => {
|
|
125230
|
-
if (!fs__namespace.existsSync(CONFIG.EMAIL_INIT))
|
|
125241
|
+
if (!fs__namespace.existsSync(CONFIG$1.EMAIL_INIT))
|
|
125231
125242
|
return false;
|
|
125232
|
-
const currentContent = fs__namespace.readFileSync(CONFIG.EMAIL_INIT, "utf-8");
|
|
125243
|
+
const currentContent = fs__namespace.readFileSync(CONFIG$1.EMAIL_INIT, "utf-8");
|
|
125233
125244
|
return currentContent === buildEmailCaptureInitializer(this.targetApp);
|
|
125234
125245
|
};
|
|
125235
125246
|
start = async () => {
|
|
125236
125247
|
if (IS_STAGING_ENV)
|
|
125237
125248
|
return;
|
|
125238
|
-
if (await httpCheck(CONFIG.PORT)) {
|
|
125249
|
+
if (await httpCheck$1(CONFIG$1.PORT)) {
|
|
125239
125250
|
if (this.isRunningForCurrentApp()) {
|
|
125240
|
-
log("Server already running for this app.");
|
|
125251
|
+
log$1("Server already running for this app.");
|
|
125241
125252
|
return;
|
|
125242
125253
|
}
|
|
125243
|
-
log("Server running for a different app — restarting...");
|
|
125254
|
+
log$1("Server running for a different app — restarting...");
|
|
125244
125255
|
await this.killServerOnPort();
|
|
125245
125256
|
}
|
|
125246
125257
|
this.ensureSetup();
|
|
125247
125258
|
this.injectEmailCaptureInitializer();
|
|
125248
|
-
log("Starting server...");
|
|
125249
|
-
const logStream = fs__namespace.createWriteStream(CONFIG.LOG);
|
|
125259
|
+
log$1("Starting server...");
|
|
125260
|
+
const logStream = fs__namespace.createWriteStream(CONFIG$1.LOG);
|
|
125250
125261
|
this.process = child_process.spawn("bundle", [
|
|
125251
125262
|
"exec",
|
|
125252
125263
|
"rails",
|
|
125253
125264
|
"server",
|
|
125254
125265
|
"-p",
|
|
125255
|
-
CONFIG.PORT.toString(),
|
|
125266
|
+
CONFIG$1.PORT.toString(),
|
|
125256
125267
|
"-b",
|
|
125257
125268
|
"0.0.0.0",
|
|
125258
125269
|
], {
|
|
125259
|
-
cwd: CONFIG.DIR,
|
|
125270
|
+
cwd: CONFIG$1.DIR,
|
|
125260
125271
|
stdio: ["ignore", "pipe", "pipe"],
|
|
125261
125272
|
env: this.serverEnv,
|
|
125262
125273
|
});
|
|
125263
125274
|
this.process.stdout?.pipe(logStream);
|
|
125264
125275
|
this.process.stderr?.pipe(logStream);
|
|
125265
125276
|
await this.waitForServer();
|
|
125266
|
-
log("Server ready.");
|
|
125277
|
+
log$1("Server ready.");
|
|
125267
125278
|
};
|
|
125268
125279
|
stop = async () => {
|
|
125269
125280
|
if (IS_STAGING_ENV || !this.process)
|
|
125270
125281
|
return;
|
|
125271
125282
|
const pid = this.process.pid;
|
|
125272
|
-
log("Stopping server...");
|
|
125283
|
+
log$1("Stopping server...");
|
|
125273
125284
|
this.process.kill("SIGTERM");
|
|
125274
125285
|
this.process = null;
|
|
125275
125286
|
if (pid) {
|
|
@@ -125278,6 +125289,238 @@ class NeetoAuthServer {
|
|
|
125278
125289
|
};
|
|
125279
125290
|
}
|
|
125280
125291
|
|
|
125292
|
+
const CONFIG = {
|
|
125293
|
+
DIR: "/tmp/neeto-chat-widget",
|
|
125294
|
+
LOG: "/tmp/neeto-chat-widget.log",
|
|
125295
|
+
PORT: 8081,
|
|
125296
|
+
MAX_WAIT_MS: 180_000,
|
|
125297
|
+
LOCK_RETRY_MS: 500,
|
|
125298
|
+
SERVER_POLL_INTERVAL_MS: 3000,
|
|
125299
|
+
WEBPACK_DEV_FILE: "/tmp/neeto-chat-widget/webpack.dev.js",
|
|
125300
|
+
LOCK_DIR: "/tmp/neeto-chat-widget.lock",
|
|
125301
|
+
STATE_FILE: "/tmp/neeto-chat-widget.state.json",
|
|
125302
|
+
};
|
|
125303
|
+
const DEFAULT_STATE = { pid: null, refCount: 0 };
|
|
125304
|
+
const WIDGET_BASE_URL = `http://localhost:${CONFIG.PORT}`;
|
|
125305
|
+
const SCRIPTS_DIR = path__namespace.join(__dirname, "scripts", "neeto-chat-widget");
|
|
125306
|
+
const log = (msg) => console.log(`[NeetoChatWidget] ${msg}`);
|
|
125307
|
+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
125308
|
+
const httpCheck = (timeout = 3000) => new Promise(resolve => {
|
|
125309
|
+
const req = http__namespace.get(`${WIDGET_BASE_URL}/main.js`, () => resolve(true));
|
|
125310
|
+
req.on("error", () => resolve(false));
|
|
125311
|
+
req.setTimeout(timeout, () => {
|
|
125312
|
+
req.destroy();
|
|
125313
|
+
resolve(false);
|
|
125314
|
+
});
|
|
125315
|
+
});
|
|
125316
|
+
class NeetoChatWidget {
|
|
125317
|
+
process = null;
|
|
125318
|
+
hasLease = false;
|
|
125319
|
+
logStream = null;
|
|
125320
|
+
get serverEnv() {
|
|
125321
|
+
return { ...process.env };
|
|
125322
|
+
}
|
|
125323
|
+
withLock = async (fn) => {
|
|
125324
|
+
while (true) {
|
|
125325
|
+
try {
|
|
125326
|
+
fs$4.mkdirSync(CONFIG.LOCK_DIR);
|
|
125327
|
+
break;
|
|
125328
|
+
}
|
|
125329
|
+
catch (error) {
|
|
125330
|
+
const nodeError = error;
|
|
125331
|
+
if (nodeError.code !== "EEXIST")
|
|
125332
|
+
throw error;
|
|
125333
|
+
await sleep(CONFIG.LOCK_RETRY_MS);
|
|
125334
|
+
}
|
|
125335
|
+
}
|
|
125336
|
+
try {
|
|
125337
|
+
return await Promise.resolve(fn());
|
|
125338
|
+
}
|
|
125339
|
+
finally {
|
|
125340
|
+
fs$4.rmSync(CONFIG.LOCK_DIR, { force: true, recursive: true });
|
|
125341
|
+
}
|
|
125342
|
+
};
|
|
125343
|
+
parseState = (raw) => {
|
|
125344
|
+
if (!raw || typeof raw !== "object")
|
|
125345
|
+
return DEFAULT_STATE;
|
|
125346
|
+
const state = raw;
|
|
125347
|
+
const pid = typeof state.pid === "number" ? state.pid : null;
|
|
125348
|
+
const refCount = typeof state.refCount === "number" && state.refCount > 0
|
|
125349
|
+
? state.refCount
|
|
125350
|
+
: 0;
|
|
125351
|
+
return { pid, refCount };
|
|
125352
|
+
};
|
|
125353
|
+
readState = () => {
|
|
125354
|
+
if (!fs$4.existsSync(CONFIG.STATE_FILE))
|
|
125355
|
+
return DEFAULT_STATE;
|
|
125356
|
+
try {
|
|
125357
|
+
return this.parseState(JSON.parse(fs$4.readFileSync(CONFIG.STATE_FILE, "utf-8")));
|
|
125358
|
+
}
|
|
125359
|
+
catch {
|
|
125360
|
+
return DEFAULT_STATE;
|
|
125361
|
+
}
|
|
125362
|
+
};
|
|
125363
|
+
writeState = (state) => {
|
|
125364
|
+
fs$4.writeFileSync(CONFIG.STATE_FILE, JSON.stringify(state));
|
|
125365
|
+
};
|
|
125366
|
+
clearState = () => {
|
|
125367
|
+
fs$4.existsSync(CONFIG.STATE_FILE) && fs$4.rmSync(CONFIG.STATE_FILE, { force: true });
|
|
125368
|
+
};
|
|
125369
|
+
getLogContent = () => fs$4.existsSync(CONFIG.LOG)
|
|
125370
|
+
? fs$4.readFileSync(CONFIG.LOG, "utf-8")
|
|
125371
|
+
: "<no log file>";
|
|
125372
|
+
ensureSetup = () => {
|
|
125373
|
+
if (fs$4.existsSync(CONFIG.WEBPACK_DEV_FILE)) {
|
|
125374
|
+
this.patchWebpackPublicPath();
|
|
125375
|
+
log("Already set up, skipping.");
|
|
125376
|
+
return;
|
|
125377
|
+
}
|
|
125378
|
+
fs$4.existsSync(CONFIG.DIR) &&
|
|
125379
|
+
fs$4.rmSync(CONFIG.DIR, { force: true, recursive: true });
|
|
125380
|
+
const setupScript = path__namespace.join(SCRIPTS_DIR, "setup.sh");
|
|
125381
|
+
log("Running first-time setup...");
|
|
125382
|
+
try {
|
|
125383
|
+
child_process.execSync(`bash "${setupScript}" "${CONFIG.DIR}"`, {
|
|
125384
|
+
stdio: "inherit",
|
|
125385
|
+
env: this.serverEnv,
|
|
125386
|
+
});
|
|
125387
|
+
}
|
|
125388
|
+
catch {
|
|
125389
|
+
throw new Error("[NeetoChatWidget] First-time setup failed. Check the output above for details.");
|
|
125390
|
+
}
|
|
125391
|
+
this.patchWebpackPublicPath();
|
|
125392
|
+
log("Setup complete.");
|
|
125393
|
+
};
|
|
125394
|
+
patchWebpackPublicPath = () => {
|
|
125395
|
+
if (!fs$4.existsSync(CONFIG.WEBPACK_DEV_FILE)) {
|
|
125396
|
+
throw new Error(`[NeetoChatWidget] Missing webpack config at ${CONFIG.WEBPACK_DEV_FILE}`);
|
|
125397
|
+
}
|
|
125398
|
+
const fileContent = fs$4.readFileSync(CONFIG.WEBPACK_DEV_FILE, "utf-8");
|
|
125399
|
+
const targetPublicPath = `publicPath: "${WIDGET_BASE_URL}/"`;
|
|
125400
|
+
if (fileContent.includes(targetPublicPath))
|
|
125401
|
+
return;
|
|
125402
|
+
const oldConfig = ` devServer: {\n contentBase: "./src",\n allowedHosts: [".lvh.me"],\n },\n`;
|
|
125403
|
+
const newConfig = ` devServer: {\n contentBase: "./src",\n allowedHosts: [".lvh.me"],\n publicPath: "${WIDGET_BASE_URL}/",\n },\n output: {\n publicPath: "${WIDGET_BASE_URL}/",\n },\n`;
|
|
125404
|
+
if (!fileContent.includes(oldConfig)) {
|
|
125405
|
+
throw new Error("[NeetoChatWidget] Unable to patch webpack.dev.js for local widget serving.");
|
|
125406
|
+
}
|
|
125407
|
+
fs$4.writeFileSync(CONFIG.WEBPACK_DEV_FILE, fileContent.replace(oldConfig, newConfig));
|
|
125408
|
+
};
|
|
125409
|
+
closeLogStream = () => {
|
|
125410
|
+
if (this.logStream) {
|
|
125411
|
+
this.logStream.end();
|
|
125412
|
+
this.logStream = null;
|
|
125413
|
+
}
|
|
125414
|
+
};
|
|
125415
|
+
waitForProcessExit = async (pid) => {
|
|
125416
|
+
const deadline = Date.now() + 10_000;
|
|
125417
|
+
while (Date.now() < deadline) {
|
|
125418
|
+
try {
|
|
125419
|
+
process.kill(pid, 0);
|
|
125420
|
+
await sleep(500);
|
|
125421
|
+
}
|
|
125422
|
+
catch {
|
|
125423
|
+
return;
|
|
125424
|
+
}
|
|
125425
|
+
}
|
|
125426
|
+
};
|
|
125427
|
+
killServer = (pid) => {
|
|
125428
|
+
if (!pid)
|
|
125429
|
+
return;
|
|
125430
|
+
try {
|
|
125431
|
+
process.kill(pid, "SIGTERM");
|
|
125432
|
+
}
|
|
125433
|
+
catch {
|
|
125434
|
+
// process may already be gone
|
|
125435
|
+
}
|
|
125436
|
+
};
|
|
125437
|
+
killProcessOnWidgetPort = async () => {
|
|
125438
|
+
try {
|
|
125439
|
+
child_process.execSync(`lsof -ti tcp:${CONFIG.PORT} | xargs kill -9`, {
|
|
125440
|
+
stdio: "ignore",
|
|
125441
|
+
});
|
|
125442
|
+
await sleep(1000);
|
|
125443
|
+
}
|
|
125444
|
+
catch {
|
|
125445
|
+
// No process on that port — nothing to kill.
|
|
125446
|
+
}
|
|
125447
|
+
};
|
|
125448
|
+
waitForServer = async (timeoutMs = CONFIG.MAX_WAIT_MS) => {
|
|
125449
|
+
const startTime = Date.now();
|
|
125450
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
125451
|
+
if (this.process !== null && this.process.exitCode !== null) {
|
|
125452
|
+
throw new Error(`[NeetoChatWidget] Server process exited unexpectedly with code ${this.process.exitCode}.\nLog:\n${this.getLogContent()}`);
|
|
125453
|
+
}
|
|
125454
|
+
if (await httpCheck())
|
|
125455
|
+
return;
|
|
125456
|
+
await sleep(CONFIG.SERVER_POLL_INTERVAL_MS);
|
|
125457
|
+
}
|
|
125458
|
+
throw new Error(`[NeetoChatWidget] Widget did not start within ${timeoutMs / 1000}s.\nLog:\n${this.getLogContent()}`);
|
|
125459
|
+
};
|
|
125460
|
+
start = async () => {
|
|
125461
|
+
if (IS_STAGING_ENV)
|
|
125462
|
+
return;
|
|
125463
|
+
await this.withLock(async () => {
|
|
125464
|
+
const state = this.readState();
|
|
125465
|
+
if (await httpCheck()) {
|
|
125466
|
+
this.hasLease = true;
|
|
125467
|
+
this.writeState({ ...state, refCount: state.refCount + 1 });
|
|
125468
|
+
log("Server already running.");
|
|
125469
|
+
return;
|
|
125470
|
+
}
|
|
125471
|
+
this.ensureSetup();
|
|
125472
|
+
log("Starting server...");
|
|
125473
|
+
this.logStream = fs$4.createWriteStream(CONFIG.LOG);
|
|
125474
|
+
this.process = child_process.spawn("yarn", ["start"], {
|
|
125475
|
+
cwd: CONFIG.DIR,
|
|
125476
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
125477
|
+
});
|
|
125478
|
+
this.process.stdout?.pipe(this.logStream);
|
|
125479
|
+
this.process.stderr?.pipe(this.logStream);
|
|
125480
|
+
try {
|
|
125481
|
+
await this.waitForServer();
|
|
125482
|
+
}
|
|
125483
|
+
catch (error) {
|
|
125484
|
+
const pid = this.process?.pid;
|
|
125485
|
+
this.killServer(pid);
|
|
125486
|
+
pid && (await this.waitForProcessExit(pid));
|
|
125487
|
+
(await httpCheck()) && (await this.killProcessOnWidgetPort());
|
|
125488
|
+
this.process = null;
|
|
125489
|
+
this.closeLogStream();
|
|
125490
|
+
throw error;
|
|
125491
|
+
}
|
|
125492
|
+
this.hasLease = true;
|
|
125493
|
+
this.writeState({
|
|
125494
|
+
pid: this.process.pid ?? null,
|
|
125495
|
+
refCount: state.refCount + 1,
|
|
125496
|
+
});
|
|
125497
|
+
log("Server ready.");
|
|
125498
|
+
});
|
|
125499
|
+
};
|
|
125500
|
+
stop = async () => {
|
|
125501
|
+
if (IS_STAGING_ENV || !this.hasLease)
|
|
125502
|
+
return;
|
|
125503
|
+
await this.withLock(async () => {
|
|
125504
|
+
const state = this.readState();
|
|
125505
|
+
const nextRefCount = Math.max(state.refCount - 1, 0);
|
|
125506
|
+
this.hasLease = false;
|
|
125507
|
+
if (nextRefCount > 0) {
|
|
125508
|
+
this.writeState({ ...state, refCount: nextRefCount });
|
|
125509
|
+
return;
|
|
125510
|
+
}
|
|
125511
|
+
if (state.pid) {
|
|
125512
|
+
log("Stopping server...");
|
|
125513
|
+
this.killServer(state.pid);
|
|
125514
|
+
await this.waitForProcessExit(state.pid);
|
|
125515
|
+
(await httpCheck()) && (await this.killProcessOnWidgetPort());
|
|
125516
|
+
}
|
|
125517
|
+
this.process = null;
|
|
125518
|
+
this.closeLogStream();
|
|
125519
|
+
this.clearState();
|
|
125520
|
+
});
|
|
125521
|
+
};
|
|
125522
|
+
}
|
|
125523
|
+
|
|
125281
125524
|
const NEETO_EMAIL_DELIVERY_TESTING_BASE_URL = "/neeto_email_delivery/api/v1/testing";
|
|
125282
125525
|
class NeetoEmailDeliveryApi {
|
|
125283
125526
|
neetoPlaywrightUtilities;
|
|
@@ -126226,6 +126469,7 @@ exports.CREDENTIALS = CREDENTIALS;
|
|
|
126226
126469
|
exports.CURRENT_TIME_RANGES = CURRENT_TIME_RANGES;
|
|
126227
126470
|
exports.CUSTOM_DOMAIN_SELECTORS = CUSTOM_DOMAIN_SELECTORS;
|
|
126228
126471
|
exports.CUSTOM_DOMAIN_SUFFIX = CUSTOM_DOMAIN_SUFFIX;
|
|
126472
|
+
exports.ColorPickerUtils = ColorPickerUtils;
|
|
126229
126473
|
exports.CustomCommands = CustomCommands;
|
|
126230
126474
|
exports.CustomDomainApi = CustomDomainApi;
|
|
126231
126475
|
exports.CustomDomainPage = CustomDomainPage;
|
|
@@ -126293,6 +126537,7 @@ exports.NEETO_ROUTES = NEETO_ROUTES;
|
|
|
126293
126537
|
exports.NEETO_SEO_SELECTORS = NEETO_SEO_SELECTORS;
|
|
126294
126538
|
exports.NEETO_TEXT_MODIFIER_SELECTORS = NEETO_TEXT_MODIFIER_SELECTORS;
|
|
126295
126539
|
exports.NeetoAuthServer = NeetoAuthServer;
|
|
126540
|
+
exports.NeetoChatWidget = NeetoChatWidget;
|
|
126296
126541
|
exports.NeetoEmailDeliveryApi = NeetoEmailDeliveryApi;
|
|
126297
126542
|
exports.NeetoTowerApi = NeetoTowerApi;
|
|
126298
126543
|
exports.ONBOARDING_SELECTORS = ONBOARDING_SELECTORS;
|