@buygent/cli 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +132 -131
- package/dist/extension/background.js +110 -32
- package/dist/extension/content/coupang.js +78 -9
- package/dist/native-host.js +1 -1
- package/package.json +1 -1
|
@@ -169,7 +169,8 @@ var CHECKOUT_URL_PATTERN = /checkout\.coupang\.com|\/order-form|\/payment/u;
|
|
|
169
169
|
|
|
170
170
|
// extension/content/order-state.ts
|
|
171
171
|
var chromeApi = globalThis.chrome;
|
|
172
|
-
var
|
|
172
|
+
var sessionStorageArea = chromeApi?.storage?.session;
|
|
173
|
+
var localStorageArea = chromeApi?.storage?.local;
|
|
173
174
|
|
|
174
175
|
// extension/content/coupang-order.ts
|
|
175
176
|
var COUPANG_CART_URL = "https://cart.coupang.com/cartView.pang";
|
|
@@ -498,17 +499,52 @@ var resolveCoupangSelectorConfig = async (options) => {
|
|
|
498
499
|
};
|
|
499
500
|
|
|
500
501
|
// extension/background.ts
|
|
501
|
-
var
|
|
502
|
-
var
|
|
502
|
+
var storageArea = chrome.storage?.session ?? chrome.storage?.local;
|
|
503
|
+
var sessionStorageArea2 = chrome.storage?.session;
|
|
504
|
+
var localStorageArea2 = chrome.storage?.local ?? chrome.storage?.session;
|
|
503
505
|
var COUPANG_URL_FILTER = ["*://*.coupang.com/*"];
|
|
504
506
|
var NATIVE_REQUEST_TIMEOUT_MS = 5000;
|
|
507
|
+
var SESSION_STORAGE_ACCESS_LEVEL = "TRUSTED_AND_UNTRUSTED_CONTEXTS";
|
|
508
|
+
var EXTENSION_WARNING_PREFIX = "[buygent extension]";
|
|
505
509
|
var createRequestId = () => globalThis.crypto?.randomUUID?.() ?? `req_${Date.now()}_${Math.random().toString(16).slice(2)}`;
|
|
506
510
|
var toErrorMessage = (error) => error instanceof Error ? error.message : typeof error === "string" ? error : "Unknown extension error";
|
|
511
|
+
var listCheckpointStorageAreas = () => {
|
|
512
|
+
const seen = new Set;
|
|
513
|
+
return [storageArea, localStorageArea2].filter((area) => {
|
|
514
|
+
if (!area || seen.has(area)) {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
seen.add(area);
|
|
518
|
+
return true;
|
|
519
|
+
});
|
|
520
|
+
};
|
|
521
|
+
var readCheckpointRecordFromArea = async (area, key) => {
|
|
522
|
+
try {
|
|
523
|
+
const stored = await area.get(key);
|
|
524
|
+
return stored[key];
|
|
525
|
+
} catch {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
var configureSessionStorageAccessForContentScripts = async () => {
|
|
530
|
+
if (typeof sessionStorageArea2?.setAccessLevel !== "function") {
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
try {
|
|
534
|
+
await sessionStorageArea2.setAccessLevel({
|
|
535
|
+
accessLevel: SESSION_STORAGE_ACCESS_LEVEL
|
|
536
|
+
});
|
|
537
|
+
return true;
|
|
538
|
+
} catch (error) {
|
|
539
|
+
console.warn(`${EXTENSION_WARNING_PREFIX} Failed to widen chrome.storage.session access for content scripts; order checkpoints may fall back to chrome.storage.local.`, toErrorMessage(error));
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
};
|
|
507
543
|
var readStoredState = async () => {
|
|
508
|
-
if (!
|
|
544
|
+
if (!storageArea) {
|
|
509
545
|
return {};
|
|
510
546
|
}
|
|
511
|
-
const stored = await
|
|
547
|
+
const stored = await storageArea.get(EXTENSION_RUNTIME_STATE_KEY);
|
|
512
548
|
return stored[EXTENSION_RUNTIME_STATE_KEY] ?? {};
|
|
513
549
|
};
|
|
514
550
|
var writeStoredState = async (patch) => {
|
|
@@ -517,32 +553,57 @@ var writeStoredState = async (patch) => {
|
|
|
517
553
|
...patch,
|
|
518
554
|
lastUpdatedAt: new Date().toISOString()
|
|
519
555
|
};
|
|
520
|
-
if (
|
|
521
|
-
await
|
|
556
|
+
if (storageArea) {
|
|
557
|
+
await storageArea.set({
|
|
522
558
|
[EXTENSION_RUNTIME_STATE_KEY]: next
|
|
523
559
|
});
|
|
524
560
|
}
|
|
525
561
|
return next;
|
|
526
562
|
};
|
|
527
563
|
var writeOrderCheckpointToStorage = async (checkpoint) => {
|
|
528
|
-
|
|
564
|
+
const key = getOrderCheckpointStorageKey(checkpoint.orderId);
|
|
565
|
+
for (const area of listCheckpointStorageAreas()) {
|
|
566
|
+
const existing = await readCheckpointRecordFromArea(area, key);
|
|
567
|
+
if (!existing) {
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
await area.set({
|
|
571
|
+
[key]: checkpoint
|
|
572
|
+
});
|
|
529
573
|
return checkpoint;
|
|
530
574
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
575
|
+
const targetStorageArea = storageArea ?? localStorageArea2;
|
|
576
|
+
if (targetStorageArea) {
|
|
577
|
+
await targetStorageArea.set({
|
|
578
|
+
[key]: checkpoint
|
|
579
|
+
});
|
|
580
|
+
}
|
|
534
581
|
return checkpoint;
|
|
535
582
|
};
|
|
536
583
|
var listActiveOrderCheckpoints = async () => {
|
|
537
|
-
|
|
584
|
+
const checkpoints = new Map;
|
|
585
|
+
for (const area of listCheckpointStorageAreas()) {
|
|
586
|
+
let stored;
|
|
587
|
+
try {
|
|
588
|
+
stored = await area.get(null);
|
|
589
|
+
} catch {
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
for (const [key, value] of Object.entries(stored)) {
|
|
593
|
+
if (!key.startsWith("buygentOrderCheckpoint:") || !value || checkpoints.has(value.orderId) || isTerminalOrderState(value.state)) {
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
checkpoints.set(value.orderId, value);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
if (checkpoints.size === 0) {
|
|
538
600
|
return [];
|
|
539
601
|
}
|
|
540
|
-
|
|
541
|
-
return Object.entries(stored).filter(([key, value]) => key.startsWith("buygentOrderCheckpoint:") && Boolean(value)).map(([, value]) => value).filter((checkpoint) => !isTerminalOrderState(checkpoint.state));
|
|
602
|
+
return [...checkpoints.values()];
|
|
542
603
|
};
|
|
543
604
|
var selectorConfigPromise;
|
|
544
605
|
var ensureSelectorConfig = async () => {
|
|
545
|
-
if (!
|
|
606
|
+
if (!localStorageArea2) {
|
|
546
607
|
return await resolveCoupangSelectorConfig({
|
|
547
608
|
storage: {
|
|
548
609
|
async get() {
|
|
@@ -555,7 +616,7 @@ var ensureSelectorConfig = async () => {
|
|
|
555
616
|
}
|
|
556
617
|
if (!selectorConfigPromise) {
|
|
557
618
|
selectorConfigPromise = resolveCoupangSelectorConfig({
|
|
558
|
-
storage:
|
|
619
|
+
storage: localStorageArea2
|
|
559
620
|
}).finally(() => {
|
|
560
621
|
selectorConfigPromise = undefined;
|
|
561
622
|
});
|
|
@@ -980,29 +1041,46 @@ var handleRuntimeMessage = async (rawMessage, sender) => {
|
|
|
980
1041
|
});
|
|
981
1042
|
}
|
|
982
1043
|
};
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
});
|
|
987
|
-
chrome.runtime.onStartup?.addListener(() => {
|
|
1044
|
+
var backgroundListenersRegistered = false;
|
|
1045
|
+
var warmBackgroundServices = async () => {
|
|
1046
|
+
await configureSessionStorageAccessForContentScripts();
|
|
988
1047
|
ensureNativePort().catch(() => {
|
|
989
1048
|
return;
|
|
990
1049
|
});
|
|
991
1050
|
ensureSelectorConfig().catch(() => {
|
|
992
1051
|
return;
|
|
993
1052
|
});
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
|
|
1053
|
+
};
|
|
1054
|
+
var registerBackgroundListeners = () => {
|
|
1055
|
+
if (backgroundListenersRegistered) {
|
|
997
1056
|
return;
|
|
1057
|
+
}
|
|
1058
|
+
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
1059
|
+
handleRuntimeMessage(message, sender).then(sendResponse).catch(async (error) => sendResponse(await toPopupError(message?.messageId, error)));
|
|
1060
|
+
return true;
|
|
998
1061
|
});
|
|
999
|
-
|
|
1062
|
+
chrome.runtime.onStartup?.addListener(() => {
|
|
1063
|
+
warmBackgroundServices().catch(() => {
|
|
1064
|
+
return;
|
|
1065
|
+
});
|
|
1066
|
+
});
|
|
1067
|
+
chrome.runtime.onInstalled?.addListener(() => {
|
|
1068
|
+
warmBackgroundServices().catch(() => {
|
|
1069
|
+
return;
|
|
1070
|
+
});
|
|
1071
|
+
});
|
|
1072
|
+
backgroundListenersRegistered = true;
|
|
1073
|
+
};
|
|
1074
|
+
var bootBackground = async () => {
|
|
1075
|
+
registerBackgroundListeners();
|
|
1076
|
+
await warmBackgroundServices();
|
|
1077
|
+
};
|
|
1078
|
+
if (!globalThis.__BUYGENT_DISABLE_BACKGROUND_AUTOBOOT__) {
|
|
1079
|
+
bootBackground().catch(() => {
|
|
1000
1080
|
return;
|
|
1001
1081
|
});
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
return;
|
|
1008
|
-
});
|
|
1082
|
+
}
|
|
1083
|
+
export {
|
|
1084
|
+
configureSessionStorageAccessForContentScripts,
|
|
1085
|
+
bootBackground
|
|
1086
|
+
};
|
|
@@ -1,4 +1,48 @@
|
|
|
1
1
|
(() => {
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
function __accessProp(key) {
|
|
7
|
+
return this[key];
|
|
8
|
+
}
|
|
9
|
+
var __toCommonJS = (from) => {
|
|
10
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
11
|
+
if (entry)
|
|
12
|
+
return entry;
|
|
13
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (var key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(entry, key))
|
|
17
|
+
__defProp(entry, key, {
|
|
18
|
+
get: __accessProp.bind(from, key),
|
|
19
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
__moduleCache.set(from, entry);
|
|
23
|
+
return entry;
|
|
24
|
+
};
|
|
25
|
+
var __moduleCache;
|
|
26
|
+
var __returnValue = (v) => v;
|
|
27
|
+
function __exportSetter(name, newValue) {
|
|
28
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
29
|
+
}
|
|
30
|
+
var __export = (target, all) => {
|
|
31
|
+
for (var name in all)
|
|
32
|
+
__defProp(target, name, {
|
|
33
|
+
get: all[name],
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: true,
|
|
36
|
+
set: __exportSetter.bind(all, name)
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// extension/content/coupang.ts
|
|
41
|
+
var exports_coupang = {};
|
|
42
|
+
__export(exports_coupang, {
|
|
43
|
+
runOrder: () => runOrder
|
|
44
|
+
});
|
|
45
|
+
|
|
2
46
|
// extension/protocol.ts
|
|
3
47
|
var BUYGENT_PROTOCOL_VERSION = 1;
|
|
4
48
|
var BUYGENT_NATIVE_HOST_NAME = "com.buygent.host";
|
|
@@ -503,7 +547,14 @@
|
|
|
503
547
|
|
|
504
548
|
// extension/content/order-state.ts
|
|
505
549
|
var chromeApi = globalThis.chrome;
|
|
506
|
-
var
|
|
550
|
+
var ORDER_CHECKPOINT_STORAGE_WARNING_PREFIX = "[buygent extension]";
|
|
551
|
+
var sessionStorageArea = chromeApi?.storage?.session;
|
|
552
|
+
var localStorageArea = chromeApi?.storage?.local;
|
|
553
|
+
var storageAreaPromise;
|
|
554
|
+
var toStorageAccessReason = (error) => error instanceof Error ? error.message : typeof error === "string" ? error : "Unknown storage access error.";
|
|
555
|
+
var warnOrderCheckpointStorageFallback = (message, error) => {
|
|
556
|
+
console.warn(`${ORDER_CHECKPOINT_STORAGE_WARNING_PREFIX} ${message}`, toStorageAccessReason(error));
|
|
557
|
+
};
|
|
507
558
|
var ORDER_TRANSITIONS = {
|
|
508
559
|
idle: ["navigating", "aborted"],
|
|
509
560
|
navigating: ["product_loaded", "aborted"],
|
|
@@ -537,7 +588,23 @@
|
|
|
537
588
|
observedAt
|
|
538
589
|
};
|
|
539
590
|
};
|
|
540
|
-
var createStorageArea = () =>
|
|
591
|
+
var createStorageArea = async (options = {}) => {
|
|
592
|
+
if (!storageAreaPromise) {
|
|
593
|
+
const warn = options.warn ?? warnOrderCheckpointStorageFallback;
|
|
594
|
+
storageAreaPromise = (async () => {
|
|
595
|
+
if (sessionStorageArea) {
|
|
596
|
+
try {
|
|
597
|
+
await sessionStorageArea.get(null);
|
|
598
|
+
return sessionStorageArea;
|
|
599
|
+
} catch (error) {
|
|
600
|
+
await warn("chrome.storage.session is unavailable in the Buygent content script; falling back to chrome.storage.local for order checkpoints.", error);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return localStorageArea;
|
|
604
|
+
})();
|
|
605
|
+
}
|
|
606
|
+
return await storageAreaPromise;
|
|
607
|
+
};
|
|
541
608
|
var readOrderCheckpoint = async (storage, orderId) => {
|
|
542
609
|
const key = getOrderCheckpointStorageKey(orderId);
|
|
543
610
|
const stored = await storage.get(key);
|
|
@@ -839,23 +906,25 @@
|
|
|
839
906
|
});
|
|
840
907
|
}
|
|
841
908
|
};
|
|
842
|
-
var runOrder = async (message) => {
|
|
843
|
-
const storage = createStorageArea();
|
|
909
|
+
var runOrder = async (message, dependencies = {}) => {
|
|
910
|
+
const storage = await (dependencies.createStorageArea ?? createStorageArea)();
|
|
844
911
|
if (!storage) {
|
|
845
|
-
throw new Error("chrome.storage
|
|
912
|
+
throw new Error("chrome.storage is unavailable in the Coupang content script.");
|
|
846
913
|
}
|
|
847
914
|
const checkpoint = await resumeOrderCheckpoint(storage, message.payload, message.sentAt);
|
|
915
|
+
const sendEnvelope = dependencies.sendBackgroundEnvelope ?? sendBackgroundEnvelope;
|
|
916
|
+
const nextRequestId = dependencies.createRequestId ?? createRequestId;
|
|
848
917
|
const emit = async (type, nextCheckpoint) => {
|
|
849
|
-
await
|
|
918
|
+
await sendEnvelope(createEnvelope(type, nextCheckpoint, {
|
|
850
919
|
source: "extension:content",
|
|
851
|
-
messageId:
|
|
920
|
+
messageId: nextRequestId(),
|
|
852
921
|
requestId: message.messageId
|
|
853
922
|
}));
|
|
854
923
|
};
|
|
855
|
-
await runCoupangDryRunFlow({
|
|
924
|
+
await (dependencies.runDryRunFlow ?? runCoupangDryRunFlow)({
|
|
856
925
|
request: message.payload,
|
|
857
926
|
initialCheckpoint: checkpoint,
|
|
858
|
-
adapter: createDocumentOrderRuntimeAdapter(document, window.location, resolveSelectorConfig(message.payload.selectorConfig)),
|
|
927
|
+
adapter: (dependencies.createRuntimeAdapter ?? createDocumentOrderRuntimeAdapter)(dependencies.document ?? document, dependencies.location ?? window.location, resolveSelectorConfig(message.payload.selectorConfig)),
|
|
859
928
|
persistCheckpoint: async (nextCheckpoint) => await writeOrderCheckpoint(storage, nextCheckpoint),
|
|
860
929
|
emitStatus: async (nextCheckpoint) => await emit("order:status", nextCheckpoint),
|
|
861
930
|
emitCheckpoint: async (nextCheckpoint) => await emit("order:checkpoint", nextCheckpoint)
|
package/dist/native-host.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @bun
|
|
3
|
-
import{createServer as q}from"net";import{existsSync as f,mkdirSync as w,readFileSync as b,rmSync as m}from"fs";import{homedir as R}from"os";import{dirname as g,join as h}from"path";import{fileURLToPath as V}from"url";var x="0.0.0-dev",E="0.3.
|
|
3
|
+
import{createServer as q}from"net";import{existsSync as f,mkdirSync as w,readFileSync as b,rmSync as m}from"fs";import{homedir as R}from"os";import{dirname as g,join as h}from"path";import{fileURLToPath as V}from"url";var x="0.0.0-dev",E="0.3.2",A=()=>{let e=g(V(import.meta.url));while(!0){let t=h(e,"package.json");if(f(t)){let o=JSON.parse(b(t,"utf8"));if(typeof o.version==="string"&&o.version.trim().length>0)return o.version}let r=g(e);if(r===e)break;e=r}return E==="0.3.2"?x:E},B=A(),T=1,c=h(R(),".buygent","chrome-extension","com.buygent.host.sock"),n=Buffer.alloc(0),s=new Map,p=new Map,l=new WeakMap,i=()=>globalThis.crypto?.randomUUID?.()??`req_${Date.now()}_${Math.random().toString(16).slice(2)}`,_=(e,t,r)=>({protocolVersion:T,type:e,messageId:r.messageId,...r.requestId?{requestId:r.requestId}:{},sentAt:r.sentAt??new Date().toISOString(),source:r.source,payload:t}),d=(e,t)=>_("error",e,t),O=(e)=>{if(!e||typeof e!=="object"||Array.isArray(e))return{ok:!1,error:d({code:"invalid_envelope",message:"Expected a JSON object envelope."},{source:"native-host",messageId:i()})};let t=e;if(t.protocolVersion!==T)return{ok:!1,error:d({code:"unsupported_protocol_version",message:`Unsupported protocolVersion: ${String(t.protocolVersion??"missing")}`},{source:"native-host",messageId:i()})};if(typeof t.type!=="string"||typeof t.messageId!=="string"||typeof t.sentAt!=="string"||typeof t.source!=="string")return{ok:!1,error:d({code:"invalid_envelope",message:"Envelope must include type, messageId, sentAt, and source fields."},{source:"native-host",messageId:i()})};return{ok:!0,envelope:e}},D=(e)=>JSON.stringify(e),u=(e)=>{let t=Buffer.from(JSON.stringify(e),"utf8"),r=Buffer.alloc(4);r.writeUInt32LE(t.length,0),process.stdout.write(r),process.stdout.write(t)},a=(e,t)=>{e.write(`${D(t)}
|
|
4
4
|
`)},P=(e,t)=>{let r=p.get(e)??new Set;r.add(t),p.set(e,r)},S=(e)=>{for(let[t,r]of p.entries())if(r.delete(e),r.size===0)p.delete(t);for(let[t,r]of s.entries())if(r===e)s.delete(t)},k=(e,t)=>{let r=p.get(e);if(!r)return;for(let o of r)a(o,t)},U=(e)=>{if(e.type==="native:ping"){u(_("native:pong",{hostVersion:B,receivedAt:new Date().toISOString()},{source:"native-host",messageId:i(),requestId:e.messageId}));return}if(e.type==="order:ack"){if(e.requestId){let t=s.get(e.requestId);if(t)P(e.payload.orderId,t),a(t,e)}return}if(e.type==="runtime:state"){if(e.requestId){let t=s.get(e.requestId);if(t)s.delete(e.requestId),a(t,e)}return}if(e.type==="order:status"||e.type==="order:checkpoint"){k(e.payload.orderId,e);return}if(e.type==="error"){let t=typeof e.payload.details==="object"&&e.payload.details&&!Array.isArray(e.payload.details)?e.payload.details.orderId:void 0;if(typeof t==="string"){k(t,e);return}if(e.requestId){let r=s.get(e.requestId);if(r)s.delete(e.requestId),a(r,e)}}},L=(e)=>{let t=O(e);if(!t.ok){u(t.error);return}U(t.envelope)},H=(e,t)=>{let r=O(JSON.parse(t));if(!r.ok){a(e,r.error);return}let o=r.envelope;if(o.type==="order:start"||o.type==="runtime:get-state"){s.set(o.messageId,e),u(o);return}a(e,d({code:"unsupported_message",message:`Unsupported CLI/native-host message: ${o.type}`},{source:"native-host",messageId:i(),requestId:o.messageId}))},J=()=>{if(w(g(c),{recursive:!0,mode:448}),f(c))m(c,{force:!0})};J();var M=q((e)=>{e.setEncoding("utf8"),l.set(e,""),e.on("data",(t)=>{let o=`${l.get(e)??""}${t}`.split(/\r?\n/u);l.set(e,o.pop()??"");for(let N of o){let y=N.trim();if(!y)continue;try{H(e,y)}catch(I){a(e,d({code:"invalid_message",message:I instanceof Error?I.message:"Invalid CLI/native-host payload."},{source:"native-host",messageId:i()}))}}}),e.on("close",()=>{S(e)}),e.on("error",()=>{S(e)})});M.listen(c);process.stdin.on("data",(e)=>{n=Buffer.concat([n,e]);while(n.length>=4){let t=n.readUInt32LE(0);if(n.length<4+t)return;let r=n.subarray(4,4+t);n=n.subarray(4+t);try{L(JSON.parse(r.toString("utf8")))}catch(o){u(d({code:"invalid_message",message:o instanceof Error?o.message:"Invalid JSON payload."},{source:"native-host",messageId:i()}))}}});var v=()=>{if(M.close(),f(c))m(c,{force:!0})};process.stdin.on("end",()=>{v(),process.exit(0)});process.on("SIGTERM",()=>{v(),process.exit(0)});process.on("SIGINT",()=>{v(),process.exit(0)});process.stdin.resume();
|