惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog RSS Feed
Jina AI
Jina AI
雷峰网
雷峰网
Blog — PlanetScale
Blog — PlanetScale
Hugging Face - Blog
Hugging Face - Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
博客园 - 司徒正美
罗磊的独立博客
J
Java Code Geeks
Engineering at Meta
Engineering at Meta
WordPress大学
WordPress大学
Vercel News
Vercel News
A
About on SuperTechFans
I
InfoQ
D
DataBreaches.Net
爱范儿
爱范儿
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
U
Unit 42
aimingoo的专栏
aimingoo的专栏
宝玉的分享
宝玉的分享
P
Proofpoint News Feed
Microsoft Azure Blog
Microsoft Azure Blog
美团技术团队

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
perf(push): lazy load web push runtime · openclaw/opencla...
steipete · 2026-04-29 · via Recent Commits to openclaw:main

@@ -1,6 +1,5 @@

11

import { createHash, randomUUID } from "node:crypto";

22

import path from "node:path";

3-

import webPush from "web-push";

43

import { resolveStateDir } from "../config/paths.js";

54

import { createAsyncLock, readJsonFile, writeJsonAtomic } from "./json-files.js";

65

@@ -41,6 +40,18 @@ const DEFAULT_VAPID_SUBJECT = "mailto:openclaw@localhost";

41404241

const withLock = createAsyncLock();

434243+

type WebPushRuntime = typeof import("web-push");

44+

type WebPushRuntimeModule = WebPushRuntime & { default?: WebPushRuntime };

45+46+

let webPushRuntimePromise: Promise<WebPushRuntime> | undefined;

47+48+

async function loadWebPushRuntime(): Promise<WebPushRuntime> {

49+

webPushRuntimePromise ??= import("web-push").then(

50+

(mod: WebPushRuntimeModule) => mod.default ?? mod,

51+

);

52+

return await webPushRuntimePromise;

53+

}

54+4455

// --- Helpers ---

45564657

function resolveWebPushStatePath(baseDir?: string): string {

@@ -115,6 +126,7 @@ export async function resolveVapidKeys(baseDir?: string): Promise<VapidKeyPair>

115126

};

116127

}

117128129+

const webPush = await loadWebPushRuntime();

118130

const keys = webPush.generateVAPIDKeys();

119131

const pair: VapidKeyPair = {

120132

publicKey: keys.publicKey,

@@ -238,7 +250,7 @@ export type WebPushPayload = {

238250

url?: string;

239251

};

240252241-

function applyVapidDetails(keys: VapidKeyPair): void {

253+

function applyVapidDetails(webPush: WebPushRuntime, keys: VapidKeyPair): void {

242254

webPush.setVapidDetails(keys.subject, keys.publicKey, keys.privateKey);

243255

}

244256

@@ -248,12 +260,14 @@ export async function sendWebPushNotification(

248260

vapidKeys?: VapidKeyPair,

249261

): Promise<WebPushSendResult> {

250262

const keys = vapidKeys ?? (await resolveVapidKeys());

251-

applyVapidDetails(keys);

263+

const webPush = await loadWebPushRuntime();

264+

applyVapidDetails(webPush, keys);

252265253-

return sendPreparedWebPushNotification(subscription, payload);

266+

return sendPreparedWebPushNotification(webPush, subscription, payload);

254267

}

255268256269

async function sendPreparedWebPushNotification(

270+

webPush: WebPushRuntime,

257271

subscription: WebPushSubscription,

258272

payload: WebPushPayload,

259273

): Promise<WebPushSendResult> {

@@ -300,12 +314,13 @@ export async function broadcastWebPush(

300314

}

301315302316

const vapidKeys = await resolveVapidKeys(baseDir);

317+

const webPush = await loadWebPushRuntime();

303318304319

// Set VAPID details once before fanning out concurrent sends.

305-

applyVapidDetails(vapidKeys);

320+

applyVapidDetails(webPush, vapidKeys);

306321307322

const results = await Promise.allSettled(

308-

subscriptions.map((sub) => sendPreparedWebPushNotification(sub, payload)),

323+

subscriptions.map((sub) => sendPreparedWebPushNotification(webPush, sub, payload)),

309324

);

310325311326

const mapped = results.map((r, i) =>