action-lens 1.0.78 → 1.0.80
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/index.d.mts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +250 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +252 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -22,6 +22,9 @@ declare class ActionLensPlayer {
|
|
|
22
22
|
sessions: (ActionRecordSession & {
|
|
23
23
|
userData: User<"customer">;
|
|
24
24
|
})[];
|
|
25
|
+
currentUrl: string | null;
|
|
26
|
+
startTime: number;
|
|
27
|
+
sessionInfo: ActionRecordSession | null;
|
|
25
28
|
constructor(userId: string, targetDivId: string, _db?: Firestore, prefix?: string);
|
|
26
29
|
initialize(userId: string): Promise<void>;
|
|
27
30
|
replayRrwebSession(sessionId: string): Promise<any[]>;
|
|
@@ -48,7 +51,15 @@ declare class ActionLensPlayer {
|
|
|
48
51
|
organizationId?: string;
|
|
49
52
|
recordTime: number;
|
|
50
53
|
ipAddress?: string;
|
|
54
|
+
ipOriginal?: string;
|
|
51
55
|
userAgent?: string;
|
|
56
|
+
place?: {
|
|
57
|
+
region: string;
|
|
58
|
+
latitude: number;
|
|
59
|
+
country: string;
|
|
60
|
+
longitude: number;
|
|
61
|
+
city: string;
|
|
62
|
+
};
|
|
52
63
|
} & _ism_tech_actionlens_type_src_DefaultType.DefaultType & {
|
|
53
64
|
userData: User<"customer">;
|
|
54
65
|
})[]>;
|
|
@@ -78,6 +89,7 @@ declare class ActionLensRc {
|
|
|
78
89
|
}, metaData?: Record<string, any>): Promise<void>;
|
|
79
90
|
startConsoleRecording(): void;
|
|
80
91
|
startTimelineRecording(): void;
|
|
92
|
+
startNetworkRecording(): void;
|
|
81
93
|
startRrwebRecordingForStore(): Promise<void>;
|
|
82
94
|
stopRrwebRecordingForStore(): void;
|
|
83
95
|
updateActionRecordSession(): Promise<void>;
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,9 @@ declare class ActionLensPlayer {
|
|
|
22
22
|
sessions: (ActionRecordSession & {
|
|
23
23
|
userData: User<"customer">;
|
|
24
24
|
})[];
|
|
25
|
+
currentUrl: string | null;
|
|
26
|
+
startTime: number;
|
|
27
|
+
sessionInfo: ActionRecordSession | null;
|
|
25
28
|
constructor(userId: string, targetDivId: string, _db?: Firestore, prefix?: string);
|
|
26
29
|
initialize(userId: string): Promise<void>;
|
|
27
30
|
replayRrwebSession(sessionId: string): Promise<any[]>;
|
|
@@ -48,7 +51,15 @@ declare class ActionLensPlayer {
|
|
|
48
51
|
organizationId?: string;
|
|
49
52
|
recordTime: number;
|
|
50
53
|
ipAddress?: string;
|
|
54
|
+
ipOriginal?: string;
|
|
51
55
|
userAgent?: string;
|
|
56
|
+
place?: {
|
|
57
|
+
region: string;
|
|
58
|
+
latitude: number;
|
|
59
|
+
country: string;
|
|
60
|
+
longitude: number;
|
|
61
|
+
city: string;
|
|
62
|
+
};
|
|
52
63
|
} & _ism_tech_actionlens_type_src_DefaultType.DefaultType & {
|
|
53
64
|
userData: User<"customer">;
|
|
54
65
|
})[]>;
|
|
@@ -78,6 +89,7 @@ declare class ActionLensRc {
|
|
|
78
89
|
}, metaData?: Record<string, any>): Promise<void>;
|
|
79
90
|
startConsoleRecording(): void;
|
|
80
91
|
startTimelineRecording(): void;
|
|
92
|
+
startNetworkRecording(): void;
|
|
81
93
|
startRrwebRecordingForStore(): Promise<void>;
|
|
82
94
|
stopRrwebRecordingForStore(): void;
|
|
83
95
|
updateActionRecordSession(): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -71,6 +71,12 @@ var ActionLensPlayer = class {
|
|
|
71
71
|
// プレイヤーの高さ
|
|
72
72
|
sessions = [];
|
|
73
73
|
// セッションのリスト
|
|
74
|
+
currentUrl = null;
|
|
75
|
+
// 現在のURLを保持するための変数
|
|
76
|
+
startTime = 0;
|
|
77
|
+
// セッションの開始時間
|
|
78
|
+
sessionInfo = null;
|
|
79
|
+
// セッション情報を保持するための変数
|
|
74
80
|
constructor(userId, targetDivId, _db = db, prefix = "") {
|
|
75
81
|
this.userId = userId;
|
|
76
82
|
this.targetDivId = targetDivId;
|
|
@@ -102,7 +108,6 @@ var ActionLensPlayer = class {
|
|
|
102
108
|
const data = doc3.data();
|
|
103
109
|
return data.rrwebRecord ? JSON.parse(data.rrwebRecord) : data.rrwebRecords ? data.rrwebRecords?.map((r) => JSON.parse(r)) || [] : [];
|
|
104
110
|
});
|
|
105
|
-
console.log("events", events);
|
|
106
111
|
if (events.length === 0) {
|
|
107
112
|
console.warn(
|
|
108
113
|
`\u30BB\u30C3\u30B7\u30E7\u30F3ID ${sessionId} \u306E\u30C7\u30FC\u30BF\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002`
|
|
@@ -130,11 +135,9 @@ var ActionLensPlayer = class {
|
|
|
130
135
|
this.width = this.replayer.wrapper.clientWidth;
|
|
131
136
|
this.height = this.replayer.wrapper.clientHeight;
|
|
132
137
|
this.replayer.on("custom-event", (event) => {
|
|
133
|
-
console.log("Custom event:", event);
|
|
134
138
|
this.handleCustomEvent(event);
|
|
135
139
|
});
|
|
136
140
|
this.replayer.on("finish", () => {
|
|
137
|
-
console.log("Replay finished");
|
|
138
141
|
this.replayer?.pause(0);
|
|
139
142
|
this.playerStatus = "stopped";
|
|
140
143
|
this.currentTime = this.replayer?.getCurrentTime() || 0;
|
|
@@ -142,7 +145,6 @@ var ActionLensPlayer = class {
|
|
|
142
145
|
});
|
|
143
146
|
this.replayer.on("resize", (e) => {
|
|
144
147
|
const { width, height } = e;
|
|
145
|
-
console.log("Replayer resized:", width, height);
|
|
146
148
|
this.width = width;
|
|
147
149
|
this.height = height;
|
|
148
150
|
});
|
|
@@ -167,7 +169,6 @@ var ActionLensPlayer = class {
|
|
|
167
169
|
});
|
|
168
170
|
this.replayer.play();
|
|
169
171
|
this.playerStatus = "playing";
|
|
170
|
-
console.log(`\u30BB\u30C3\u30B7\u30E7\u30F3ID ${sessionId} \u306E\u518D\u751F\u3092\u958B\u59CB\u3057\u307E\u3057\u305F\u3002`);
|
|
171
172
|
this.setTimeoutTimeline();
|
|
172
173
|
return events.map((e) => (0, import_packer.unpack)(e));
|
|
173
174
|
} catch (error) {
|
|
@@ -190,6 +191,7 @@ var ActionLensPlayer = class {
|
|
|
190
191
|
break;
|
|
191
192
|
case "navigation":
|
|
192
193
|
const { url } = event.data;
|
|
194
|
+
this.currentUrl = url;
|
|
193
195
|
this.displayEvent(`[${timeString}] Navigation to ${url}`, "navigation");
|
|
194
196
|
break;
|
|
195
197
|
case "performance":
|
|
@@ -200,7 +202,6 @@ var ActionLensPlayer = class {
|
|
|
200
202
|
);
|
|
201
203
|
break;
|
|
202
204
|
default:
|
|
203
|
-
console.warn("\u4E0D\u660E\u306A\u30AB\u30B9\u30BF\u30E0\u30A4\u30D9\u30F3\u30C8:", event.data.type);
|
|
204
205
|
}
|
|
205
206
|
}
|
|
206
207
|
// イベントをオーバーレイに表示
|
|
@@ -256,7 +257,6 @@ var ActionLensPlayer = class {
|
|
|
256
257
|
this.setTimeoutTimeline();
|
|
257
258
|
if (this.replayer) {
|
|
258
259
|
const offset = this.replayer.getCurrentTime();
|
|
259
|
-
console.log("offset", offset);
|
|
260
260
|
this.replayer.play(offset);
|
|
261
261
|
this.playerStatus = "playing";
|
|
262
262
|
this.currentTime = this.replayer?.getCurrentTime() || 0;
|
|
@@ -558,7 +558,7 @@ var ActionLensRc = class {
|
|
|
558
558
|
consoleMethods.forEach((method) => {
|
|
559
559
|
console[method] = (...args) => {
|
|
560
560
|
originalConsole[method](...args);
|
|
561
|
-
import_rrweb2.record.addCustomEvent("console", { method
|
|
561
|
+
import_rrweb2.record.addCustomEvent("console", { method, args });
|
|
562
562
|
};
|
|
563
563
|
});
|
|
564
564
|
} catch (error) {
|
|
@@ -586,12 +586,43 @@ var ActionLensRc = class {
|
|
|
586
586
|
if (window.performance) {
|
|
587
587
|
const observer = new PerformanceObserver((list) => {
|
|
588
588
|
for (const entry of list.getEntries()) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
589
|
+
if (entry.entryType === "resource") {
|
|
590
|
+
const resourceEntry = entry;
|
|
591
|
+
import_rrweb2.record.addCustomEvent("network_resource", {
|
|
592
|
+
name: resourceEntry.name,
|
|
593
|
+
entryType: resourceEntry.entryType,
|
|
594
|
+
initiatorType: resourceEntry.initiatorType,
|
|
595
|
+
// websocket, script, document, font, xmlhttprequest, fetch, preflight etc.
|
|
596
|
+
nextHopProtocol: resourceEntry.nextHopProtocol,
|
|
597
|
+
encodedBodySize: resourceEntry.encodedBodySize,
|
|
598
|
+
decodedBodySize: resourceEntry.decodedBodySize,
|
|
599
|
+
transferSize: resourceEntry.transferSize,
|
|
600
|
+
duration: resourceEntry.duration,
|
|
601
|
+
startTime: resourceEntry.startTime,
|
|
602
|
+
fetchStart: resourceEntry.fetchStart,
|
|
603
|
+
domainLookupStart: resourceEntry.domainLookupStart,
|
|
604
|
+
domainLookupEnd: resourceEntry.domainLookupEnd,
|
|
605
|
+
connectStart: resourceEntry.connectStart,
|
|
606
|
+
connectEnd: resourceEntry.connectEnd,
|
|
607
|
+
secureConnectionStart: resourceEntry.secureConnectionStart,
|
|
608
|
+
requestStart: resourceEntry.requestStart,
|
|
609
|
+
responseStart: resourceEntry.responseStart,
|
|
610
|
+
responseEnd: resourceEntry.responseEnd,
|
|
611
|
+
workerStart: resourceEntry.workerStart,
|
|
612
|
+
redirectStart: resourceEntry.redirectStart,
|
|
613
|
+
redirectEnd: resourceEntry.redirectEnd,
|
|
614
|
+
// responseStatus is experimental, may not be available
|
|
615
|
+
responseStatus: resourceEntry.responseStatus || void 0,
|
|
616
|
+
serverTiming: resourceEntry.serverTiming
|
|
617
|
+
});
|
|
618
|
+
} else {
|
|
619
|
+
import_rrweb2.record.addCustomEvent("performance", {
|
|
620
|
+
name: entry.name,
|
|
621
|
+
entryType: entry.entryType,
|
|
622
|
+
startTime: entry.startTime,
|
|
623
|
+
duration: entry.duration
|
|
624
|
+
});
|
|
625
|
+
}
|
|
595
626
|
}
|
|
596
627
|
});
|
|
597
628
|
observer.observe({ entryTypes: ["resource", "navigation", "paint"] });
|
|
@@ -601,6 +632,173 @@ var ActionLensRc = class {
|
|
|
601
632
|
throw error;
|
|
602
633
|
}
|
|
603
634
|
}
|
|
635
|
+
// ネットワークリクエストをキャプチャ(新規追加)
|
|
636
|
+
startNetworkRecording() {
|
|
637
|
+
try {
|
|
638
|
+
const originalFetch = window.fetch;
|
|
639
|
+
window.fetch = (...args) => {
|
|
640
|
+
const startTime = Date.now();
|
|
641
|
+
let input = args[0];
|
|
642
|
+
let init = args[1];
|
|
643
|
+
let urlStr;
|
|
644
|
+
let method = "GET";
|
|
645
|
+
let requestBody;
|
|
646
|
+
if (input instanceof Request) {
|
|
647
|
+
urlStr = input.url;
|
|
648
|
+
method = input.method;
|
|
649
|
+
requestBody = input.body;
|
|
650
|
+
} else {
|
|
651
|
+
urlStr = input instanceof URL ? input.href : input.toString();
|
|
652
|
+
method = init?.method || "GET";
|
|
653
|
+
requestBody = init?.body;
|
|
654
|
+
}
|
|
655
|
+
import_rrweb2.record.addCustomEvent("network_request", {
|
|
656
|
+
type: "fetch",
|
|
657
|
+
method,
|
|
658
|
+
url: urlStr,
|
|
659
|
+
requestBody,
|
|
660
|
+
startTime,
|
|
661
|
+
status: "pending"
|
|
662
|
+
// 初期状態は保留中
|
|
663
|
+
});
|
|
664
|
+
return originalFetch(...args).then((response) => {
|
|
665
|
+
const endTime = Date.now();
|
|
666
|
+
const duration = endTime - startTime;
|
|
667
|
+
const clonedResponse = response.clone();
|
|
668
|
+
clonedResponse.text().then((responseBody) => {
|
|
669
|
+
import_rrweb2.record.addCustomEvent("network_response", {
|
|
670
|
+
type: "fetch",
|
|
671
|
+
url: urlStr,
|
|
672
|
+
status: response.status,
|
|
673
|
+
statusText: response.statusText,
|
|
674
|
+
responseBody,
|
|
675
|
+
duration,
|
|
676
|
+
endTime
|
|
677
|
+
});
|
|
678
|
+
}).catch((err) => {
|
|
679
|
+
console.error(
|
|
680
|
+
"\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u30EC\u30B9\u30DD\u30F3\u30B9\u30DC\u30C7\u30A3\u8AAD\u307F\u8FBC\u307F\u30A8\u30E9\u30FC:",
|
|
681
|
+
err
|
|
682
|
+
);
|
|
683
|
+
});
|
|
684
|
+
return response;
|
|
685
|
+
}).catch((error) => {
|
|
686
|
+
const endTime = Date.now();
|
|
687
|
+
const duration = endTime - startTime;
|
|
688
|
+
import_rrweb2.record.addCustomEvent("network_error", {
|
|
689
|
+
type: "fetch",
|
|
690
|
+
url: urlStr,
|
|
691
|
+
error: error.message,
|
|
692
|
+
duration,
|
|
693
|
+
endTime
|
|
694
|
+
});
|
|
695
|
+
throw error;
|
|
696
|
+
});
|
|
697
|
+
};
|
|
698
|
+
const OriginalXMLHttpRequest = window.XMLHttpRequest;
|
|
699
|
+
class HookedXMLHttpRequest extends OriginalXMLHttpRequest {
|
|
700
|
+
_method;
|
|
701
|
+
_url;
|
|
702
|
+
_startTime;
|
|
703
|
+
static UNSENT = 0;
|
|
704
|
+
static OPENED = 1;
|
|
705
|
+
static HEADERS_RECEIVED = 2;
|
|
706
|
+
static LOADING = 3;
|
|
707
|
+
static DONE = 4;
|
|
708
|
+
open(method, url, async = true, username = null, password = null) {
|
|
709
|
+
this._method = method;
|
|
710
|
+
this._url = url.toString();
|
|
711
|
+
this._startTime = Date.now();
|
|
712
|
+
import_rrweb2.record.addCustomEvent("network_request", {
|
|
713
|
+
type: "xhr",
|
|
714
|
+
method,
|
|
715
|
+
url: this._url,
|
|
716
|
+
startTime: this._startTime,
|
|
717
|
+
status: "pending"
|
|
718
|
+
// 初期状態は保留中
|
|
719
|
+
});
|
|
720
|
+
return super.open(method, url, async, username, password);
|
|
721
|
+
}
|
|
722
|
+
send(body) {
|
|
723
|
+
this.addEventListener("load", () => {
|
|
724
|
+
const endTime = Date.now();
|
|
725
|
+
const duration = endTime - (this._startTime || 0);
|
|
726
|
+
import_rrweb2.record.addCustomEvent("network_response", {
|
|
727
|
+
type: "xhr",
|
|
728
|
+
url: this._url,
|
|
729
|
+
status: this.status,
|
|
730
|
+
statusText: this.statusText,
|
|
731
|
+
responseBody: this.responseText,
|
|
732
|
+
duration,
|
|
733
|
+
endTime
|
|
734
|
+
});
|
|
735
|
+
});
|
|
736
|
+
this.addEventListener("error", () => {
|
|
737
|
+
const endTime = Date.now();
|
|
738
|
+
const duration = endTime - (this._startTime || 0);
|
|
739
|
+
import_rrweb2.record.addCustomEvent("network_error", {
|
|
740
|
+
type: "xhr",
|
|
741
|
+
url: this._url,
|
|
742
|
+
error: "XHR error",
|
|
743
|
+
duration,
|
|
744
|
+
endTime
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
return super.send(body);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
window.XMLHttpRequest = HookedXMLHttpRequest;
|
|
751
|
+
const OriginalWebSocket = window.WebSocket;
|
|
752
|
+
window.WebSocket = class HookedWebSocket extends OriginalWebSocket {
|
|
753
|
+
constructor(url, protocols) {
|
|
754
|
+
super(url, protocols);
|
|
755
|
+
const wsUrl = url.toString();
|
|
756
|
+
import_rrweb2.record.addCustomEvent("network_websocket_open", {
|
|
757
|
+
type: "websocket",
|
|
758
|
+
url: wsUrl,
|
|
759
|
+
startTime: Date.now()
|
|
760
|
+
});
|
|
761
|
+
this.addEventListener("message", (event) => {
|
|
762
|
+
import_rrweb2.record.addCustomEvent("network_websocket_message", {
|
|
763
|
+
type: "websocket",
|
|
764
|
+
url: wsUrl,
|
|
765
|
+
data: event.data,
|
|
766
|
+
time: Date.now()
|
|
767
|
+
});
|
|
768
|
+
});
|
|
769
|
+
this.addEventListener("close", (event) => {
|
|
770
|
+
import_rrweb2.record.addCustomEvent("network_websocket_close", {
|
|
771
|
+
type: "websocket",
|
|
772
|
+
url: wsUrl,
|
|
773
|
+
code: event.code,
|
|
774
|
+
reason: event.reason,
|
|
775
|
+
endTime: Date.now()
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
this.addEventListener("error", (event) => {
|
|
779
|
+
import_rrweb2.record.addCustomEvent("network_websocket_error", {
|
|
780
|
+
type: "websocket",
|
|
781
|
+
url: wsUrl,
|
|
782
|
+
error: "WebSocket error",
|
|
783
|
+
time: Date.now()
|
|
784
|
+
});
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
send(data) {
|
|
788
|
+
import_rrweb2.record.addCustomEvent("network_websocket_send", {
|
|
789
|
+
type: "websocket",
|
|
790
|
+
url: this.url,
|
|
791
|
+
data,
|
|
792
|
+
time: Date.now()
|
|
793
|
+
});
|
|
794
|
+
return super.send(data);
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
} catch (error) {
|
|
798
|
+
console.error("\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u9332\u753B\u30A8\u30E9\u30FC:", error);
|
|
799
|
+
throw error;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
604
802
|
async startRrwebRecordingForStore() {
|
|
605
803
|
try {
|
|
606
804
|
if (this.stopFnForStore) return;
|
|
@@ -634,10 +832,26 @@ var ActionLensRc = class {
|
|
|
634
832
|
updatedBy: userId
|
|
635
833
|
});
|
|
636
834
|
try {
|
|
835
|
+
console.log("setSessionDetail\u95A2\u6570\u3092\u547C\u3073\u51FA\u3057\u307E\u3059", this.sessionId);
|
|
637
836
|
await setSessionDetail({ sessionId: this.sessionId });
|
|
638
837
|
} catch (error) {
|
|
639
838
|
console.error("setSessionDetail\u95A2\u6570\u306E\u547C\u3073\u51FA\u3057\u306B\u5931\u6557:", error);
|
|
640
839
|
}
|
|
840
|
+
const docRef = (0, import_firestore3.doc)(
|
|
841
|
+
(0, import_firestore3.collection)(this.db, "ActionRecordSession"),
|
|
842
|
+
this.sessionId
|
|
843
|
+
);
|
|
844
|
+
await (0, import_firestore3.getDoc)(docRef).then(async (doc3) => {
|
|
845
|
+
if (doc3.exists()) {
|
|
846
|
+
const data = doc3.data();
|
|
847
|
+
const ipAddress = data?.ipAddress || "";
|
|
848
|
+
const placeData = await getPlaceFromIp(ipAddress);
|
|
849
|
+
console.log("placeData", placeData);
|
|
850
|
+
await (0, import_firestore3.updateDoc)(docRef, { place: placeData });
|
|
851
|
+
}
|
|
852
|
+
}).catch((error) => {
|
|
853
|
+
console.error("IP\u30A2\u30C9\u30EC\u30B9\u306E\u53D6\u5F97\u306B\u5931\u6557:", error);
|
|
854
|
+
});
|
|
641
855
|
this.stopFnForStore = (0, import_rrweb2.record)({
|
|
642
856
|
packFn: import_packer2.pack,
|
|
643
857
|
collectFonts: true,
|
|
@@ -651,7 +865,7 @@ var ActionLensRc = class {
|
|
|
651
865
|
try {
|
|
652
866
|
const deffTime = (/* @__PURE__ */ new Date()).getTime() - pinTime;
|
|
653
867
|
rrwebRecords.push(JSON.stringify(event));
|
|
654
|
-
if (rrwebRecords.length >=
|
|
868
|
+
if (rrwebRecords.length >= 100 || deffTime >= 5e3 && rrwebRecords.length > 0) {
|
|
655
869
|
pinTime = (/* @__PURE__ */ new Date()).getTime();
|
|
656
870
|
const record2 = {
|
|
657
871
|
id: "",
|
|
@@ -681,6 +895,8 @@ var ActionLensRc = class {
|
|
|
681
895
|
recordCanvas: false
|
|
682
896
|
});
|
|
683
897
|
this.startConsoleRecording();
|
|
898
|
+
this.startTimelineRecording();
|
|
899
|
+
this.startNetworkRecording();
|
|
684
900
|
} catch (error) {
|
|
685
901
|
console.error("rrweb\u9332\u753B\u30A8\u30E9\u30FC:", error);
|
|
686
902
|
throw error;
|
|
@@ -727,6 +943,25 @@ var ActionLensRc = class {
|
|
|
727
943
|
}
|
|
728
944
|
};
|
|
729
945
|
var ActionLens = new ActionLensRc();
|
|
946
|
+
var getPlaceFromIp = async (ip) => {
|
|
947
|
+
try {
|
|
948
|
+
const response = await fetch(`https://ipapi.co/${ip}/json/`);
|
|
949
|
+
if (!response.ok) {
|
|
950
|
+
throw new Error(`IP\u60C5\u5831\u53D6\u5F97\u30A8\u30E9\u30FC: ${response.statusText}`);
|
|
951
|
+
}
|
|
952
|
+
const data = await response.json();
|
|
953
|
+
return {
|
|
954
|
+
city: data.city,
|
|
955
|
+
region: data.region,
|
|
956
|
+
country: data.country_name,
|
|
957
|
+
latitude: data.latitude,
|
|
958
|
+
longitude: data.longitude
|
|
959
|
+
};
|
|
960
|
+
} catch (error) {
|
|
961
|
+
console.error("IP\u60C5\u5831\u53D6\u5F97\u30A8\u30E9\u30FC:", error);
|
|
962
|
+
return null;
|
|
963
|
+
}
|
|
964
|
+
};
|
|
730
965
|
// Annotate the CommonJS export names for ESM import in node:
|
|
731
966
|
0 && (module.exports = {
|
|
732
967
|
ActionLens,
|