opencode-mobile 1.0.0
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.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/push-notifications.d.ts +4 -0
- package/dist/push-notifications.d.ts.map +1 -0
- package/dist/push-notifications.js +299 -0
- package/dist/push-notifications.js.map +1 -0
- package/dist/reverse-proxy.d.ts +9 -0
- package/dist/reverse-proxy.d.ts.map +1 -0
- package/dist/reverse-proxy.js +72 -0
- package/dist/reverse-proxy.js.map +1 -0
- package/dist/sdk-logger.d.ts +17 -0
- package/dist/sdk-logger.d.ts.map +1 -0
- package/dist/sdk-logger.js +94 -0
- package/dist/sdk-logger.js.map +1 -0
- package/dist/src/push/formatter.d.ts +25 -0
- package/dist/src/push/formatter.d.ts.map +1 -0
- package/dist/src/push/formatter.js +142 -0
- package/dist/src/push/formatter.js.map +1 -0
- package/dist/src/push/index.d.ts +8 -0
- package/dist/src/push/index.d.ts.map +1 -0
- package/dist/src/push/index.js +8 -0
- package/dist/src/push/index.js.map +1 -0
- package/dist/src/push/sender.d.ts +9 -0
- package/dist/src/push/sender.d.ts.map +1 -0
- package/dist/src/push/sender.js +75 -0
- package/dist/src/push/sender.js.map +1 -0
- package/dist/src/push/token-store.d.ts +17 -0
- package/dist/src/push/token-store.d.ts.map +1 -0
- package/dist/src/push/token-store.js +42 -0
- package/dist/src/push/token-store.js.map +1 -0
- package/dist/src/push/types.d.ts +51 -0
- package/dist/src/push/types.d.ts.map +1 -0
- package/dist/src/push/types.js +5 -0
- package/dist/src/push/types.js.map +1 -0
- package/dist/src/tunnel/cloudflare.d.ts +17 -0
- package/dist/src/tunnel/cloudflare.d.ts.map +1 -0
- package/dist/src/tunnel/cloudflare.js +74 -0
- package/dist/src/tunnel/cloudflare.js.map +1 -0
- package/dist/src/tunnel/index.d.ts +31 -0
- package/dist/src/tunnel/index.d.ts.map +1 -0
- package/dist/src/tunnel/index.js +83 -0
- package/dist/src/tunnel/index.js.map +1 -0
- package/dist/src/tunnel/localtunnel.d.ts +13 -0
- package/dist/src/tunnel/localtunnel.d.ts.map +1 -0
- package/dist/src/tunnel/localtunnel.js +31 -0
- package/dist/src/tunnel/localtunnel.js.map +1 -0
- package/dist/src/tunnel/ngrok.d.ts +21 -0
- package/dist/src/tunnel/ngrok.d.ts.map +1 -0
- package/dist/src/tunnel/ngrok.js +91 -0
- package/dist/src/tunnel/ngrok.js.map +1 -0
- package/dist/src/tunnel/qrcode.d.ts +12 -0
- package/dist/src/tunnel/qrcode.d.ts.map +1 -0
- package/dist/src/tunnel/qrcode.js +24 -0
- package/dist/src/tunnel/qrcode.js.map +1 -0
- package/dist/src/tunnel/types.d.ts +32 -0
- package/dist/src/tunnel/types.d.ts.map +1 -0
- package/dist/src/tunnel/types.js +5 -0
- package/dist/src/tunnel/types.js.map +1 -0
- package/dist/src/utils/port.d.ts +12 -0
- package/dist/src/utils/port.d.ts.map +1 -0
- package/dist/src/utils/port.js +41 -0
- package/dist/src/utils/port.js.map +1 -0
- package/dist/tunnel-manager.d.ts +30 -0
- package/dist/tunnel-manager.d.ts.map +1 -0
- package/dist/tunnel-manager.js +639 -0
- package/dist/tunnel-manager.js.map +1 -0
- package/package.json +60 -0
- package/push-notifications.ts +346 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
import { truncate } from "./token-store";
|
|
5
|
+
/**
|
|
6
|
+
* Extract project path from event
|
|
7
|
+
*/
|
|
8
|
+
export function extractProjectPath(event, ctx) {
|
|
9
|
+
const properties = event.properties;
|
|
10
|
+
const { type } = event;
|
|
11
|
+
switch (type) {
|
|
12
|
+
case "session.updated":
|
|
13
|
+
return properties?.info?.directory || null;
|
|
14
|
+
case "message.updated":
|
|
15
|
+
return (properties?.info?.path?.cwd || properties?.info?.path?.root || null);
|
|
16
|
+
case "session.idle":
|
|
17
|
+
case "session.error":
|
|
18
|
+
case "permission.updated":
|
|
19
|
+
return ctx?.directory || ctx?.worktree || null;
|
|
20
|
+
default:
|
|
21
|
+
return (properties?.projectPath ||
|
|
22
|
+
properties?.directory ||
|
|
23
|
+
properties?.info?.directory ||
|
|
24
|
+
properties?.info?.path?.cwd ||
|
|
25
|
+
ctx?.directory ||
|
|
26
|
+
ctx?.worktree ||
|
|
27
|
+
null);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Extract session ID from event
|
|
32
|
+
*/
|
|
33
|
+
export function extractSessionId(event) {
|
|
34
|
+
const properties = event.properties;
|
|
35
|
+
return (properties?.sessionId ||
|
|
36
|
+
properties?.sessionID ||
|
|
37
|
+
event?.sessionId ||
|
|
38
|
+
event?.sessionID ||
|
|
39
|
+
properties?.info?.sessionID ||
|
|
40
|
+
properties?.info?.id ||
|
|
41
|
+
null);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if event is a child session
|
|
45
|
+
*/
|
|
46
|
+
export function isChildSession(event) {
|
|
47
|
+
const properties = event.properties;
|
|
48
|
+
return !!(properties?.parentSessionId ||
|
|
49
|
+
properties?.parentId ||
|
|
50
|
+
properties?.parentSessionID ||
|
|
51
|
+
event?.parentSessionId ||
|
|
52
|
+
event?.parentId ||
|
|
53
|
+
properties?.info?.parentSessionId ||
|
|
54
|
+
properties?.info?.parentId);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extract last assistant message from event
|
|
58
|
+
*/
|
|
59
|
+
export function extractLastAssistantMessage(event) {
|
|
60
|
+
const properties = event.properties;
|
|
61
|
+
if (properties?.messages && Array.isArray(properties.messages)) {
|
|
62
|
+
const assistantMessages = properties.messages.filter((m) => m.role === "assistant" || m.sender === "assistant");
|
|
63
|
+
if (assistantMessages.length > 0) {
|
|
64
|
+
const lastMessage = assistantMessages[assistantMessages.length - 1];
|
|
65
|
+
return lastMessage.content || lastMessage.text || "";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (properties?.lastAssistantMessage) {
|
|
69
|
+
return properties.lastAssistantMessage;
|
|
70
|
+
}
|
|
71
|
+
if (properties?.conversation && Array.isArray(properties.conversation)) {
|
|
72
|
+
const assistantMessages = properties.conversation.filter((m) => m.role === "assistant" || m.sender === "assistant");
|
|
73
|
+
if (assistantMessages.length > 0) {
|
|
74
|
+
const lastMessage = assistantMessages[assistantMessages.length - 1];
|
|
75
|
+
return lastMessage.content || lastMessage.text || "";
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return "";
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Format a notification from an event
|
|
82
|
+
*/
|
|
83
|
+
export function formatNotification(event, serverUrl, ctx) {
|
|
84
|
+
const properties = event.properties;
|
|
85
|
+
const { type } = event;
|
|
86
|
+
const projectPath = extractProjectPath(event, ctx);
|
|
87
|
+
const sessionId = extractSessionId(event);
|
|
88
|
+
const baseData = { type, serverUrl, projectPath, sessionId };
|
|
89
|
+
if (type === "session.idle") {
|
|
90
|
+
if (isChildSession(event)) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
switch (type) {
|
|
95
|
+
case "session.idle": {
|
|
96
|
+
const lastAssistantMessage = extractLastAssistantMessage(event);
|
|
97
|
+
console.log("[PushPlugin] Last assistant message:", lastAssistantMessage
|
|
98
|
+
? lastAssistantMessage.substring(0, 100) + "..."
|
|
99
|
+
: "none");
|
|
100
|
+
const sessionTitle = properties?.title || properties?.sessionTitle || "Session";
|
|
101
|
+
const expandableContent = lastAssistantMessage || properties?.summary || "";
|
|
102
|
+
return {
|
|
103
|
+
title: "Session Complete",
|
|
104
|
+
body: sessionTitle,
|
|
105
|
+
data: {
|
|
106
|
+
...baseData,
|
|
107
|
+
messageId: properties?.messageId,
|
|
108
|
+
lastAssistantMessage,
|
|
109
|
+
},
|
|
110
|
+
android: {
|
|
111
|
+
notification: {
|
|
112
|
+
channelId: "opencode-sessions",
|
|
113
|
+
style: {
|
|
114
|
+
type: "bigtext",
|
|
115
|
+
text: expandableContent,
|
|
116
|
+
title: sessionTitle,
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
ios: {
|
|
121
|
+
threadId: sessionId || undefined,
|
|
122
|
+
summaryArg: sessionTitle,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
case "session.error":
|
|
127
|
+
return {
|
|
128
|
+
title: "Session Error",
|
|
129
|
+
body: truncate(properties?.error || properties?.message || "An error occurred", 100),
|
|
130
|
+
data: baseData,
|
|
131
|
+
};
|
|
132
|
+
case "permission.updated":
|
|
133
|
+
return {
|
|
134
|
+
title: "Permission Required",
|
|
135
|
+
body: `Approve ${properties?.tool || "action"} ${properties?.type || "execute"}?`,
|
|
136
|
+
data: { ...baseData, permissionId: properties?.permissionId },
|
|
137
|
+
};
|
|
138
|
+
default:
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../../src/push/formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/push/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/push/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push notification sender
|
|
3
|
+
*/
|
|
4
|
+
import type { Notification } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Send push notification to all registered devices
|
|
7
|
+
*/
|
|
8
|
+
export declare function sendPush(notification: Notification): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=sender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sender.d.ts","sourceRoot":"","sources":["../../../src/push/sender.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAS5C;;GAEG;AACH,wBAAsB,QAAQ,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA2ExE"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push notification sender
|
|
3
|
+
*/
|
|
4
|
+
import { loadTokens, saveTokens } from "./token-store";
|
|
5
|
+
const EXPO_PUSH_URL = "https://exp.host/--/api/v2/push/send";
|
|
6
|
+
/**
|
|
7
|
+
* Send push notification to all registered devices
|
|
8
|
+
*/
|
|
9
|
+
export async function sendPush(notification) {
|
|
10
|
+
const tokens = loadTokens();
|
|
11
|
+
if (tokens.length === 0) {
|
|
12
|
+
console.log("[PushPlugin] No push tokens registered, skipping notification");
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
console.log(`[PushPlugin] Sending notification to ${tokens.length} device(s)`);
|
|
16
|
+
console.log("[PushPlugin] Notification details:", {
|
|
17
|
+
title: notification.title,
|
|
18
|
+
body: notification.body,
|
|
19
|
+
data: notification.data,
|
|
20
|
+
android: notification.android ? "configured" : "not configured",
|
|
21
|
+
ios: notification.ios ? "configured" : "not configured"
|
|
22
|
+
});
|
|
23
|
+
const messages = tokens.map(({ token }) => ({
|
|
24
|
+
to: token,
|
|
25
|
+
sound: "default",
|
|
26
|
+
title: notification.title,
|
|
27
|
+
body: notification.body,
|
|
28
|
+
data: notification.data,
|
|
29
|
+
priority: "high",
|
|
30
|
+
...(notification.android && { android: notification.android }),
|
|
31
|
+
...(notification.ios && { ios: notification.ios }),
|
|
32
|
+
}));
|
|
33
|
+
try {
|
|
34
|
+
const res = await fetch(EXPO_PUSH_URL, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: { "Content-Type": "application/json" },
|
|
37
|
+
body: JSON.stringify(messages),
|
|
38
|
+
});
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
console.error("[PushPlugin] Expo push API error:", res.status);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const result = (await res.json());
|
|
44
|
+
console.log("[PushPlugin] Push send result:");
|
|
45
|
+
console.log(` Status: ${res.status}`);
|
|
46
|
+
console.log(` Messages sent: ${result.data?.length || 0}`);
|
|
47
|
+
// Log individual message results
|
|
48
|
+
result.data?.forEach((item, i) => {
|
|
49
|
+
if (item.status === "ok") {
|
|
50
|
+
console.log(` [${i + 1}] ✅ Delivered successfully`);
|
|
51
|
+
}
|
|
52
|
+
else if (item.status === "error") {
|
|
53
|
+
console.log(` [${i + 1}] ❌ Error: ${item.details?.error || "unknown"}`);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.log(` [${i + 1}] ℹ️ Status: ${item.status}`);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const invalidTokens = new Set();
|
|
60
|
+
result.data?.forEach((item, i) => {
|
|
61
|
+
if (item.status === "error" &&
|
|
62
|
+
["DeviceNotRegistered", "InvalidCredentials"].includes(item.details?.error)) {
|
|
63
|
+
invalidTokens.add(tokens[i].token);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
if (invalidTokens.size > 0) {
|
|
67
|
+
saveTokens(tokens.filter((t) => !invalidTokens.has(t.token)));
|
|
68
|
+
console.log(`[PushPlugin] Removed ${invalidTokens.size} invalid token(s)`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
console.error("[PushPlugin] Send error:", e);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=sender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sender.js","sourceRoot":"","sources":["../../../src/push/sender.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token storage for push notifications
|
|
3
|
+
*/
|
|
4
|
+
import type { PushToken } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Load stored push tokens from disk
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadTokens(): PushToken[];
|
|
9
|
+
/**
|
|
10
|
+
* Save push tokens to disk
|
|
11
|
+
*/
|
|
12
|
+
export declare function saveTokens(tokens: PushToken[]): void;
|
|
13
|
+
/**
|
|
14
|
+
* Truncate text to a maximum length
|
|
15
|
+
*/
|
|
16
|
+
export declare function truncate(text: string | undefined, max: number): string;
|
|
17
|
+
//# sourceMappingURL=token-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-store.d.ts","sourceRoot":"","sources":["../../../src/push/token-store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAKzC;;GAEG;AACH,wBAAgB,UAAU,IAAI,SAAS,EAAE,CASxC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAIpD;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAMtE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token storage for push notifications
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
const CONFIG_DIR = path.join(process.env.HOME || "", ".config/opencode");
|
|
7
|
+
const TOKEN_FILE = path.join(CONFIG_DIR, "push-tokens.json");
|
|
8
|
+
/**
|
|
9
|
+
* Load stored push tokens from disk
|
|
10
|
+
*/
|
|
11
|
+
export function loadTokens() {
|
|
12
|
+
try {
|
|
13
|
+
if (fs.existsSync(TOKEN_FILE)) {
|
|
14
|
+
return JSON.parse(fs.readFileSync(TOKEN_FILE, "utf-8"));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
console.error("[PushPlugin] Load error:", e);
|
|
19
|
+
}
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Save push tokens to disk
|
|
24
|
+
*/
|
|
25
|
+
export function saveTokens(tokens) {
|
|
26
|
+
const dir = path.dirname(TOKEN_FILE);
|
|
27
|
+
if (!fs.existsSync(dir))
|
|
28
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
29
|
+
fs.writeFileSync(TOKEN_FILE, JSON.stringify(tokens, null, 2));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Truncate text to a maximum length
|
|
33
|
+
*/
|
|
34
|
+
export function truncate(text, max) {
|
|
35
|
+
if (!text)
|
|
36
|
+
return "";
|
|
37
|
+
const cleaned = text.replace(/\n/g, " ").trim();
|
|
38
|
+
return cleaned.length <= max
|
|
39
|
+
? cleaned
|
|
40
|
+
: cleaned.substring(0, max - 3) + "...";
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=token-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../../src/push/token-store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,kBAAkB,CAAC,CAAC;AACzE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;AAE7D;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAmB;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAwB,EAAE,GAAW;IAC5D,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAChD,OAAO,OAAO,CAAC,MAAM,IAAI,GAAG;QAC1B,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push notification types
|
|
3
|
+
*/
|
|
4
|
+
export interface PushToken {
|
|
5
|
+
token: string;
|
|
6
|
+
platform: "ios" | "android";
|
|
7
|
+
deviceId: string;
|
|
8
|
+
registeredAt: string;
|
|
9
|
+
}
|
|
10
|
+
export interface Notification {
|
|
11
|
+
title: string;
|
|
12
|
+
body: string;
|
|
13
|
+
data: Record<string, unknown>;
|
|
14
|
+
android?: AndroidNotificationConfig;
|
|
15
|
+
ios?: iOSNotificationConfig;
|
|
16
|
+
}
|
|
17
|
+
export interface AndroidNotificationConfig {
|
|
18
|
+
notification?: {
|
|
19
|
+
channelId?: string;
|
|
20
|
+
style?: {
|
|
21
|
+
type: "bigtext" | "inbox";
|
|
22
|
+
text?: string;
|
|
23
|
+
title?: string;
|
|
24
|
+
lines?: string[];
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export interface iOSNotificationConfig {
|
|
29
|
+
attachments?: Array<{
|
|
30
|
+
url: string;
|
|
31
|
+
hideThumbnail?: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
summaryArg?: string;
|
|
34
|
+
threadId?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface NotificationEvent {
|
|
37
|
+
type: string;
|
|
38
|
+
properties: Record<string, unknown>;
|
|
39
|
+
sessionId?: string;
|
|
40
|
+
sessionID?: string;
|
|
41
|
+
parentSessionId?: string;
|
|
42
|
+
parentId?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface PluginContext {
|
|
45
|
+
directory?: string;
|
|
46
|
+
worktree?: string;
|
|
47
|
+
serverUrl?: {
|
|
48
|
+
port?: string | number;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/push/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,yBAAyB,CAAC;IACpC,GAAG,CAAC,EAAE,qBAAqB,CAAC;CAC7B;AAED,MAAM,WAAW,yBAAyB;IACxC,YAAY,CAAC,EAAE;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE;YACN,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;YAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;SAClB,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,GAAG,EAAE,MAAM,CAAC;QACZ,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC,CAAC;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;KACxB,CAAC;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/push/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare tunnel provider implementation
|
|
3
|
+
*/
|
|
4
|
+
import type { TunnelConfig, TunnelInfo } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Start a Cloudflare tunnel
|
|
7
|
+
*/
|
|
8
|
+
export declare function startCloudflareTunnel(config: TunnelConfig): Promise<TunnelInfo>;
|
|
9
|
+
/**
|
|
10
|
+
* Stop the Cloudflare tunnel
|
|
11
|
+
*/
|
|
12
|
+
export declare function stopCloudflareTunnel(): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Check if cloudflared is installed
|
|
15
|
+
*/
|
|
16
|
+
export declare function isCloudflareInstalled(): Promise<boolean>;
|
|
17
|
+
//# sourceMappingURL=cloudflare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../../src/tunnel/cloudflare.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAKxD;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CA2CrF;AAED;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM1D;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAS9D"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare tunnel provider implementation
|
|
3
|
+
*/
|
|
4
|
+
import { spawn } from "child_process";
|
|
5
|
+
let cloudflareProcess = null;
|
|
6
|
+
let cloudflareUrl = null;
|
|
7
|
+
/**
|
|
8
|
+
* Start a Cloudflare tunnel
|
|
9
|
+
*/
|
|
10
|
+
export async function startCloudflareTunnel(config) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
try {
|
|
13
|
+
const cloudflared = spawn("cloudflared", [
|
|
14
|
+
"tunnel",
|
|
15
|
+
"--url",
|
|
16
|
+
`http://127.0.0.1:${config.port}`,
|
|
17
|
+
]);
|
|
18
|
+
cloudflareProcess = cloudflared;
|
|
19
|
+
let output = "";
|
|
20
|
+
cloudflared.stdout.on("data", (data) => {
|
|
21
|
+
output += data.toString();
|
|
22
|
+
const match = output.match(/https:\/\/[^\s]+\\.trycloudflare\\.com/);
|
|
23
|
+
if (match) {
|
|
24
|
+
cloudflareUrl = match[0];
|
|
25
|
+
resolve({
|
|
26
|
+
url: cloudflareUrl,
|
|
27
|
+
tunnelId: "cloudflare",
|
|
28
|
+
port: config.port,
|
|
29
|
+
provider: "cloudflare",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
cloudflared.stderr.on("data", (data) => {
|
|
34
|
+
console.error("[Tunnel] Cloudflare stderr:", data.toString());
|
|
35
|
+
});
|
|
36
|
+
cloudflared.on("error", (err) => {
|
|
37
|
+
reject(new Error(`Cloudflare tunnel failed: ${err.message}`));
|
|
38
|
+
});
|
|
39
|
+
cloudflared.on("close", (code) => {
|
|
40
|
+
if (code !== 0 && !cloudflareUrl) {
|
|
41
|
+
reject(new Error(`Cloudflare tunnel exited with code ${code}`));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
reject(new Error(`Cloudflare tunnel failed: ${error.message}`));
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Stop the Cloudflare tunnel
|
|
52
|
+
*/
|
|
53
|
+
export async function stopCloudflareTunnel() {
|
|
54
|
+
if (cloudflareProcess) {
|
|
55
|
+
cloudflareProcess.kill();
|
|
56
|
+
cloudflareProcess = null;
|
|
57
|
+
cloudflareUrl = null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if cloudflared is installed
|
|
62
|
+
*/
|
|
63
|
+
export async function isCloudflareInstalled() {
|
|
64
|
+
try {
|
|
65
|
+
const { promisify } = await import("util");
|
|
66
|
+
const execAsync = promisify((await import("child_process")).exec);
|
|
67
|
+
await execAsync("which cloudflared");
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=cloudflare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare.js","sourceRoot":"","sources":["../../../src/tunnel/cloudflare.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAGtC,IAAI,iBAAiB,GAAQ,IAAI,CAAC;AAClC,IAAI,aAAa,GAAkB,IAAI,CAAC;AAExC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAAoB;IAC9D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,KAAK,CAAC,aAAa,EAAE;gBACvC,QAAQ;gBACR,OAAO;gBACP,oBAAoB,MAAM,CAAC,IAAI,EAAE;aAClC,CAAC,CAAC;YAEH,iBAAiB,GAAG,WAAW,CAAC;YAEhC,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBAC7C,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;gBACrE,IAAI,KAAK,EAAE,CAAC;oBACV,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBACzB,OAAO,CAAC;wBACN,GAAG,EAAE,aAAa;wBAClB,QAAQ,EAAE,YAAY;wBACtB,IAAI,EAAE,MAAM,CAAC,IAAI;wBACjB,QAAQ,EAAE,YAAY;qBACvB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBAC7C,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YAChE,CAAC,CAAC,CAAC;YAEH,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;gBACrC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAChE,CAAC,CAAC,CAAC;YAEH,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE;gBACvC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;oBACjC,MAAM,CAAC,IAAI,KAAK,CAAC,sCAAsC,IAAI,EAAE,CAAC,CAAC,CAAC;gBAClE,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAClE,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,IAAI,iBAAiB,EAAE,CAAC;QACtB,iBAAiB,CAAC,IAAI,EAAE,CAAC;QACzB,iBAAiB,GAAG,IAAI,CAAC;QACzB,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,IAAI,CAAC;QACH,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3C,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClE,MAAM,SAAS,CAAC,mBAAmB,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tunnel manager - unified interface for all tunnel providers
|
|
3
|
+
*/
|
|
4
|
+
import type { TunnelConfig, TunnelInfo, TunnelDetails } from "./types";
|
|
5
|
+
import { displayQRCode } from "./qrcode";
|
|
6
|
+
/**
|
|
7
|
+
* Start a tunnel with the specified provider
|
|
8
|
+
*/
|
|
9
|
+
export declare function startTunnel(config: TunnelConfig): Promise<TunnelInfo>;
|
|
10
|
+
/**
|
|
11
|
+
* Stop the current tunnel
|
|
12
|
+
*/
|
|
13
|
+
export declare function stopTunnel(): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Display QR code for tunnel URL
|
|
16
|
+
*/
|
|
17
|
+
export declare function displayQR(tunnelInfo: TunnelInfo): void;
|
|
18
|
+
/**
|
|
19
|
+
* Get current tunnel details
|
|
20
|
+
*/
|
|
21
|
+
export declare function getTunnelDetails(): TunnelDetails;
|
|
22
|
+
/**
|
|
23
|
+
* Get current tunnel info
|
|
24
|
+
*/
|
|
25
|
+
export declare function getTunnelInfo(): TunnelInfo | null;
|
|
26
|
+
/**
|
|
27
|
+
* Get current server URL from tunnel
|
|
28
|
+
*/
|
|
29
|
+
export declare function getServerUrl(): string;
|
|
30
|
+
export { displayQRCode };
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tunnel/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAIvE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAkB3E;AAED;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAkBhD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAEtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAQhD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAKrC;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tunnel manager - unified interface for all tunnel providers
|
|
3
|
+
*/
|
|
4
|
+
import { startNgrokTunnel, stopNgrokTunnel } from "./ngrok";
|
|
5
|
+
import { startLocaltunnel, stopLocaltunnel } from "./localtunnel";
|
|
6
|
+
import { startCloudflareTunnel, stopCloudflareTunnel } from "./cloudflare";
|
|
7
|
+
import { displayQRCode } from "./qrcode";
|
|
8
|
+
let currentTunnel = null;
|
|
9
|
+
/**
|
|
10
|
+
* Start a tunnel with the specified provider
|
|
11
|
+
*/
|
|
12
|
+
export async function startTunnel(config) {
|
|
13
|
+
const provider = config.provider || "ngrok";
|
|
14
|
+
switch (provider) {
|
|
15
|
+
case "ngrok":
|
|
16
|
+
currentTunnel = await startNgrokTunnel(config);
|
|
17
|
+
break;
|
|
18
|
+
case "localtunnel":
|
|
19
|
+
currentTunnel = await startLocaltunnel(config);
|
|
20
|
+
break;
|
|
21
|
+
case "cloudflare":
|
|
22
|
+
currentTunnel = await startCloudflareTunnel(config);
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
throw new Error(`Unknown tunnel provider: ${provider}`);
|
|
26
|
+
}
|
|
27
|
+
return currentTunnel;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Stop the current tunnel
|
|
31
|
+
*/
|
|
32
|
+
export async function stopTunnel() {
|
|
33
|
+
if (!currentTunnel) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
switch (currentTunnel.provider) {
|
|
37
|
+
case "ngrok":
|
|
38
|
+
await stopNgrokTunnel();
|
|
39
|
+
break;
|
|
40
|
+
case "localtunnel":
|
|
41
|
+
await stopLocaltunnel();
|
|
42
|
+
break;
|
|
43
|
+
case "cloudflare":
|
|
44
|
+
await stopCloudflareTunnel();
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
currentTunnel = null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Display QR code for tunnel URL
|
|
51
|
+
*/
|
|
52
|
+
export function displayQR(tunnelInfo) {
|
|
53
|
+
displayQRCode(tunnelInfo.url);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get current tunnel details
|
|
57
|
+
*/
|
|
58
|
+
export function getTunnelDetails() {
|
|
59
|
+
return {
|
|
60
|
+
type: currentTunnel?.provider || "none",
|
|
61
|
+
url: currentTunnel?.url || null,
|
|
62
|
+
loginStatus: "unknown",
|
|
63
|
+
loginId: null,
|
|
64
|
+
configPath: null,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get current tunnel info
|
|
69
|
+
*/
|
|
70
|
+
export function getTunnelInfo() {
|
|
71
|
+
return currentTunnel;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get current server URL from tunnel
|
|
75
|
+
*/
|
|
76
|
+
export function getServerUrl() {
|
|
77
|
+
if (!currentTunnel) {
|
|
78
|
+
throw new Error("No tunnel active");
|
|
79
|
+
}
|
|
80
|
+
return currentTunnel.url;
|
|
81
|
+
}
|
|
82
|
+
export { displayQRCode };
|
|
83
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tunnel/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAiB,MAAM,SAAS,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,IAAI,aAAa,GAAsB,IAAI,CAAC;AAE5C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAoB;IACpD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,OAAO,CAAC;IAE5C,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,OAAO;YACV,aAAa,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC/C,MAAM;QACR,KAAK,aAAa;YAChB,aAAa,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC/C,MAAM;QACR,KAAK,YAAY;YACf,aAAa,GAAG,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAC;YACpD,MAAM;QACR;YACE,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO;IACT,CAAC;IAED,QAAQ,aAAa,CAAC,QAAQ,EAAE,CAAC;QAC/B,KAAK,OAAO;YACV,MAAM,eAAe,EAAE,CAAC;YACxB,MAAM;QACR,KAAK,aAAa;YAChB,MAAM,eAAe,EAAE,CAAC;YACxB,MAAM;QACR,KAAK,YAAY;YACf,MAAM,oBAAoB,EAAE,CAAC;YAC7B,MAAM;IACV,CAAC;IAED,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,UAAsB;IAC9C,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,IAAI,EAAE,aAAa,EAAE,QAAQ,IAAI,MAAM;QACvC,GAAG,EAAE,aAAa,EAAE,GAAG,IAAI,IAAI;QAC/B,WAAW,EAAE,SAAS;QACtB,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,IAAI;KACjB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,aAAa,CAAC,GAAG,CAAC;AAC3B,CAAC;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Localtunnel tunnel provider implementation
|
|
3
|
+
*/
|
|
4
|
+
import type { TunnelConfig, TunnelInfo } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Start a localtunnel
|
|
7
|
+
*/
|
|
8
|
+
export declare function startLocaltunnel(config: TunnelConfig): Promise<TunnelInfo>;
|
|
9
|
+
/**
|
|
10
|
+
* Stop the localtunnel
|
|
11
|
+
*/
|
|
12
|
+
export declare function stopLocaltunnel(): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=localtunnel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localtunnel.d.ts","sourceRoot":"","sources":["../../../src/tunnel/localtunnel.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAIxD;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAchF;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAKrD"}
|