@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.
@@ -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 storageArea = chromeApi?.storage?.session ?? chromeApi?.storage?.local;
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 storageArea2 = chrome.storage?.session ?? chrome.storage?.local;
502
- var localStorageArea = chrome.storage?.local ?? chrome.storage?.session;
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 (!storageArea2) {
544
+ if (!storageArea) {
509
545
  return {};
510
546
  }
511
- const stored = await storageArea2.get(EXTENSION_RUNTIME_STATE_KEY);
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 (storageArea2) {
521
- await storageArea2.set({
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
- if (!storageArea2) {
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
- await storageArea2.set({
532
- [getOrderCheckpointStorageKey(checkpoint.orderId)]: checkpoint
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
- if (!storageArea2) {
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
- const stored = await storageArea2.get(null);
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 (!localStorageArea) {
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: localStorageArea
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
- chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
984
- handleRuntimeMessage(message, sender).then(sendResponse).catch(async (error) => sendResponse(await toPopupError(message?.messageId, error)));
985
- return true;
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
- chrome.runtime.onInstalled?.addListener(() => {
996
- ensureNativePort().catch(() => {
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
- ensureSelectorConfig().catch(() => {
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
- ensureNativePort().catch(() => {
1004
- return;
1005
- });
1006
- ensureSelectorConfig().catch(() => {
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 storageArea = chromeApi?.storage?.session ?? chromeApi?.storage?.local;
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 = () => storageArea;
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.session is unavailable in the Coupang content script.");
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 sendBackgroundEnvelope(createEnvelope(type, nextCheckpoint, {
918
+ await sendEnvelope(createEnvelope(type, nextCheckpoint, {
850
919
  source: "extension:content",
851
- messageId: createRequestId(),
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)
@@ -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.0",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.0"?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)}
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buygent/cli",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Buygent CLI for one-command installation and extension setup.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",