@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.
@@ -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
+ };
package/dist/index.mjs ADDED
@@ -0,0 +1,8 @@
1
+ import {
2
+ startJamiexiongrHub
3
+ } from "./chunk-U232OX2V.mjs";
4
+ import "./chunk-GWABPEUH.mjs";
5
+ import "./chunk-JY3C7BVD.mjs";
6
+ export {
7
+ startJamiexiongrHub
8
+ };