@jamiexiongr/panda-hub 0.0.0-fallback-test-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/README.md +32 -0
- package/bin/panda-hub.cjs +3 -0
- package/dist/chunk-GWABPEUH.mjs +37915 -0
- package/dist/chunk-JY3C7BVD.mjs +4083 -0
- package/dist/chunk-U232OX2V.mjs +108 -0
- package/dist/cli.mjs +15 -0
- package/dist/hub-web-push-C4D7EV3C.mjs +157 -0
- package/dist/index.mjs +8 -0
- package/dist/src-Q5JJZNJ2.mjs +1418 -0
- package/dist/web/apple-touch-icon.png +0 -0
- package/dist/web/assets/diagnostics-page-BmzeM8p1.css +1 -0
- package/dist/web/assets/diagnostics-page-alYFKOv4.js +1 -0
- package/dist/web/assets/index-CUZJj6Ss.css +1 -0
- package/dist/web/assets/index-DamKy_Z8.js +142 -0
- package/dist/web/assets/session-diff-preview-Dum-BJbr.js +3 -0
- package/dist/web/assets/web-BabjKXO0.js +1 -0
- package/dist/web/assets/web-C6gTc3M_.js +1 -0
- package/dist/web/assets/web-CvRFts-H.js +1 -0
- package/dist/web/assets/web-NGsqRsgv.js +1 -0
- package/dist/web/assets/web-lpHs9Cyy.js +1 -0
- package/dist/web/icon.svg +6 -0
- package/dist/web/index.html +23 -0
- package/dist/web/logo.png +0 -0
- package/dist/web/manifest.webmanifest +1 -0
- package/dist/web/maskable-512.png +0 -0
- package/dist/web/panda-ink-logo.svg +70 -0
- package/dist/web/pwa-192.png +0 -0
- package/dist/web/pwa-512.png +0 -0
- package/dist/web/pwa-home-logo.png +0 -0
- package/dist/web/registerSW.js +1 -0
- package/dist/web/small-icon.svg +4 -0
- package/dist/web/sw.js +2 -0
- package/package.json +30 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
configureTailscaleServe,
|
|
3
|
+
ensurePandaHubApiKey,
|
|
4
|
+
printTerminalQr,
|
|
5
|
+
resolveTailscalePublicationMode,
|
|
6
|
+
resolveTailscaleServePort,
|
|
7
|
+
startPandaSessionService
|
|
8
|
+
} from "./chunk-GWABPEUH.mjs";
|
|
9
|
+
|
|
10
|
+
// release/panda-hub/src/index.ts
|
|
11
|
+
import fs from "fs";
|
|
12
|
+
import path from "path";
|
|
13
|
+
import { fileURLToPath } from "url";
|
|
14
|
+
|
|
15
|
+
// release/panda-hub/package.json
|
|
16
|
+
var package_default = {
|
|
17
|
+
name: "@jamiexiongr/panda-hub",
|
|
18
|
+
version: "0.0.0-fallback-test-2",
|
|
19
|
+
type: "module",
|
|
20
|
+
private: false,
|
|
21
|
+
description: "Panda hub runtime",
|
|
22
|
+
dependencies: {
|
|
23
|
+
"@fastify/cors": "^10.0.2",
|
|
24
|
+
"@fastify/websocket": "^11.0.2",
|
|
25
|
+
fastify: "^5.2.1",
|
|
26
|
+
"web-push": "^3.6.7"
|
|
27
|
+
},
|
|
28
|
+
bin: {
|
|
29
|
+
"panda-hub": "./bin/panda-hub.cjs"
|
|
30
|
+
},
|
|
31
|
+
exports: {
|
|
32
|
+
".": "./dist/index.mjs"
|
|
33
|
+
},
|
|
34
|
+
files: [
|
|
35
|
+
"bin",
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
publishConfig: {
|
|
39
|
+
access: "public",
|
|
40
|
+
registry: "https://registry.npmjs.org/"
|
|
41
|
+
},
|
|
42
|
+
engines: {
|
|
43
|
+
node: ">=20.19.0"
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// release/panda-hub/src/index.ts
|
|
48
|
+
var currentDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
49
|
+
var resolveBundledWebUiDir = () => {
|
|
50
|
+
const candidates = [
|
|
51
|
+
path.resolve(currentDirectory, "web"),
|
|
52
|
+
path.resolve(currentDirectory, "../dist/web"),
|
|
53
|
+
path.resolve(currentDirectory, "../web")
|
|
54
|
+
];
|
|
55
|
+
return candidates.find((candidate) => fs.existsSync(candidate)) ?? candidates[0];
|
|
56
|
+
};
|
|
57
|
+
var startJamiexiongrHub = async (options) => {
|
|
58
|
+
const publishMode = options?.tailscalePublicationMode ?? resolveTailscalePublicationMode({
|
|
59
|
+
envPrefix: "PANDA_HUB"
|
|
60
|
+
});
|
|
61
|
+
const port = Number(process.env.PANDA_HUB_PORT ?? 4343);
|
|
62
|
+
const tailscaleServe = configureTailscaleServe({
|
|
63
|
+
enabled: publishMode !== "disabled",
|
|
64
|
+
mode: publishMode === "disabled" ? void 0 : publishMode,
|
|
65
|
+
serviceName: "panda-hub",
|
|
66
|
+
localPort: port,
|
|
67
|
+
servePort: resolveTailscaleServePort({
|
|
68
|
+
envPrefix: "PANDA_HUB",
|
|
69
|
+
defaultPort: 443
|
|
70
|
+
}),
|
|
71
|
+
logger: console
|
|
72
|
+
});
|
|
73
|
+
const hubApiKey = await ensurePandaHubApiKey({
|
|
74
|
+
configuredApiKey: process.env.PANDA_HUB_API_KEY ?? null,
|
|
75
|
+
codexHome: process.env.PANDA_CODEX_HOME ?? null,
|
|
76
|
+
logger: console
|
|
77
|
+
});
|
|
78
|
+
if (hubApiKey.apiKey) {
|
|
79
|
+
process.env.PANDA_HUB_API_KEY = hubApiKey.apiKey;
|
|
80
|
+
}
|
|
81
|
+
const webUiDir = resolveBundledWebUiDir();
|
|
82
|
+
const app = await startPandaSessionService({
|
|
83
|
+
serviceName: "panda-hub",
|
|
84
|
+
mode: "hub",
|
|
85
|
+
port,
|
|
86
|
+
transport: "hub-routed",
|
|
87
|
+
version: package_default.version,
|
|
88
|
+
webUiDir
|
|
89
|
+
});
|
|
90
|
+
if (tailscaleServe.active && tailscaleServe.baseUrl) {
|
|
91
|
+
if (tailscaleServe.mode === "funnel") {
|
|
92
|
+
console.info(`Panda hub Public HTTPS URL: ${tailscaleServe.baseUrl}`);
|
|
93
|
+
console.info(`Public PWA install URL: ${tailscaleServe.baseUrl}`);
|
|
94
|
+
} else {
|
|
95
|
+
console.info(`Panda hub Tailscale HTTPS URL: ${tailscaleServe.baseUrl}`);
|
|
96
|
+
console.info(`Agent hub URL env: PANDA_HUB_URL=${tailscaleServe.baseUrl}`);
|
|
97
|
+
}
|
|
98
|
+
printTerminalQr(tailscaleServe.baseUrl, {
|
|
99
|
+
logger: console,
|
|
100
|
+
label: tailscaleServe.mode === "funnel" ? "Scan this QR code to open the public Panda hub on your phone:" : "Scan this QR code to open Panda hub on your phone:"
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return app;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export {
|
|
107
|
+
startJamiexiongrHub
|
|
108
|
+
};
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
startJamiexiongrHub
|
|
3
|
+
} from "./chunk-U232OX2V.mjs";
|
|
4
|
+
import {
|
|
5
|
+
resolveTailscalePublicationMode
|
|
6
|
+
} from "./chunk-GWABPEUH.mjs";
|
|
7
|
+
import "./chunk-JY3C7BVD.mjs";
|
|
8
|
+
|
|
9
|
+
// release/panda-hub/src/cli.ts
|
|
10
|
+
void startJamiexiongrHub({
|
|
11
|
+
tailscalePublicationMode: resolveTailscalePublicationMode({
|
|
12
|
+
argv: process.argv.slice(2),
|
|
13
|
+
envPrefix: "PANDA_HUB"
|
|
14
|
+
})
|
|
15
|
+
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import {
|
|
2
|
+
external_exports
|
|
3
|
+
} from "./chunk-JY3C7BVD.mjs";
|
|
4
|
+
|
|
5
|
+
// packages/provider-codex/src/hub-web-push.ts
|
|
6
|
+
import fs from "fs/promises";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import webpush from "web-push";
|
|
9
|
+
var storedVapidConfigSchema = external_exports.object({
|
|
10
|
+
version: external_exports.literal(1),
|
|
11
|
+
public_key: external_exports.string(),
|
|
12
|
+
private_key: external_exports.string(),
|
|
13
|
+
subject: external_exports.string(),
|
|
14
|
+
created_at: external_exports.string(),
|
|
15
|
+
updated_at: external_exports.string()
|
|
16
|
+
});
|
|
17
|
+
var isoNow = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
18
|
+
var normalizeSubject = (value) => {
|
|
19
|
+
const trimmed = value?.trim() ?? "";
|
|
20
|
+
if (trimmed) {
|
|
21
|
+
return trimmed;
|
|
22
|
+
}
|
|
23
|
+
return "mailto:panda@localhost";
|
|
24
|
+
};
|
|
25
|
+
var loadStoredVapidConfig = async (storageFilePath) => {
|
|
26
|
+
try {
|
|
27
|
+
const raw = await fs.readFile(storageFilePath, "utf8");
|
|
28
|
+
return storedVapidConfigSchema.parse(JSON.parse(raw));
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error?.code === "ENOENT") {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var writeStoredVapidConfig = async (storageFilePath, config) => {
|
|
37
|
+
await fs.mkdir(path.dirname(storageFilePath), { recursive: true });
|
|
38
|
+
await fs.writeFile(storageFilePath, JSON.stringify(config, null, 2), "utf8");
|
|
39
|
+
};
|
|
40
|
+
var resolveVapidConfig = async (options) => {
|
|
41
|
+
const configuredPublicKey = options.publicKey?.trim() ?? "";
|
|
42
|
+
const configuredPrivateKey = options.privateKey?.trim() ?? "";
|
|
43
|
+
const subject = normalizeSubject(options.subject);
|
|
44
|
+
if (configuredPublicKey || configuredPrivateKey) {
|
|
45
|
+
if (!configuredPublicKey || !configuredPrivateKey) {
|
|
46
|
+
return {
|
|
47
|
+
publicConfig: {
|
|
48
|
+
supported: false,
|
|
49
|
+
vapid_public_key: null,
|
|
50
|
+
subject: subject ?? null,
|
|
51
|
+
reason: "PANDA_WEB_PUSH_PUBLIC_KEY and PANDA_WEB_PUSH_PRIVATE_KEY must both be set."
|
|
52
|
+
},
|
|
53
|
+
privateKey: null
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
publicConfig: {
|
|
58
|
+
supported: true,
|
|
59
|
+
vapid_public_key: configuredPublicKey,
|
|
60
|
+
subject,
|
|
61
|
+
reason: null
|
|
62
|
+
},
|
|
63
|
+
privateKey: configuredPrivateKey
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const stored = await loadStoredVapidConfig(options.storageFilePath);
|
|
67
|
+
if (stored) {
|
|
68
|
+
return {
|
|
69
|
+
publicConfig: {
|
|
70
|
+
supported: true,
|
|
71
|
+
vapid_public_key: stored.public_key,
|
|
72
|
+
subject: stored.subject,
|
|
73
|
+
reason: null
|
|
74
|
+
},
|
|
75
|
+
privateKey: stored.private_key
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const generated = webpush.generateVAPIDKeys();
|
|
79
|
+
const now = isoNow();
|
|
80
|
+
const persisted = storedVapidConfigSchema.parse({
|
|
81
|
+
version: 1,
|
|
82
|
+
public_key: generated.publicKey,
|
|
83
|
+
private_key: generated.privateKey,
|
|
84
|
+
subject,
|
|
85
|
+
created_at: now,
|
|
86
|
+
updated_at: now
|
|
87
|
+
});
|
|
88
|
+
await writeStoredVapidConfig(options.storageFilePath, persisted);
|
|
89
|
+
options.logger?.info?.(
|
|
90
|
+
{ storageFilePath: options.storageFilePath },
|
|
91
|
+
"Generated persistent Panda Web Push VAPID keys."
|
|
92
|
+
);
|
|
93
|
+
return {
|
|
94
|
+
publicConfig: {
|
|
95
|
+
supported: true,
|
|
96
|
+
vapid_public_key: persisted.public_key,
|
|
97
|
+
subject: persisted.subject,
|
|
98
|
+
reason: null
|
|
99
|
+
},
|
|
100
|
+
privateKey: persisted.private_key
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
var createHubWebPushNotifier = async (options) => {
|
|
104
|
+
const resolved = await resolveVapidConfig(options);
|
|
105
|
+
if (!resolved.publicConfig.supported || !resolved.publicConfig.vapid_public_key || !resolved.privateKey) {
|
|
106
|
+
return {
|
|
107
|
+
publicConfig: resolved.publicConfig,
|
|
108
|
+
async sendNotification() {
|
|
109
|
+
return {
|
|
110
|
+
ok: false,
|
|
111
|
+
statusCode: null,
|
|
112
|
+
shouldRemove: false,
|
|
113
|
+
message: "Hub Web Push is not configured."
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
webpush.setVapidDetails(
|
|
119
|
+
resolved.publicConfig.subject ?? normalizeSubject(options.subject),
|
|
120
|
+
resolved.publicConfig.vapid_public_key,
|
|
121
|
+
resolved.privateKey
|
|
122
|
+
);
|
|
123
|
+
return {
|
|
124
|
+
publicConfig: resolved.publicConfig,
|
|
125
|
+
async sendNotification(subscription, payload) {
|
|
126
|
+
try {
|
|
127
|
+
await webpush.sendNotification(
|
|
128
|
+
subscription,
|
|
129
|
+
JSON.stringify({
|
|
130
|
+
title: payload.title,
|
|
131
|
+
body: payload.body,
|
|
132
|
+
url: payload.url,
|
|
133
|
+
tag: payload.tag,
|
|
134
|
+
sessionId: payload.sessionId ?? null
|
|
135
|
+
}),
|
|
136
|
+
{
|
|
137
|
+
TTL: 60,
|
|
138
|
+
urgency: "high",
|
|
139
|
+
topic: payload.tag.slice(0, 32)
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
return { ok: true, statusCode: 201, shouldRemove: false };
|
|
143
|
+
} catch (error) {
|
|
144
|
+
const statusCode = typeof error === "object" && error !== null && "statusCode" in error && typeof error.statusCode === "number" ? error.statusCode : null;
|
|
145
|
+
return {
|
|
146
|
+
ok: false,
|
|
147
|
+
statusCode,
|
|
148
|
+
shouldRemove: statusCode === 404 || statusCode === 410,
|
|
149
|
+
message: error instanceof Error ? error.message : String(error)
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
export {
|
|
156
|
+
createHubWebPushNotifier
|
|
157
|
+
};
|