Skip to content

Commit 2f9026d

Browse files
authored
fix: [WPN-29] Remove top-level await in crypto.ts (#61)
* fix: add input validation and fix payload padding edge case * chore: migrate npm publishing to OIDC trusted publishing * feat!: simplify CLI to use subcommands BREAKING CHANGE: use `npx @pushforge/builder vapid` instead of `generate-vapid-keys` * fix!: remove top-level await for bundler compatibility BREAKING CHANGE: Requires Node.js 20+ * docs: improve READMEs with examples and comparison table * docs: add live demo and update logo to webp
1 parent 4aa88ef commit 2f9026d

File tree

19 files changed

+2136
-357
lines changed

19 files changed

+2136
-357
lines changed

.github/workflows/release.yml

Lines changed: 83 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,83 @@
1-
name: Package Release
2-
3-
on:
4-
push:
5-
branches:
6-
- latest-release
7-
- beta
8-
9-
permissions:
10-
contents: write
11-
issues: write
12-
pull-requests: write
13-
14-
jobs:
15-
release-builder:
16-
runs-on: ubuntu-latest
17-
defaults:
18-
run:
19-
working-directory: packages/builder
20-
steps:
21-
- uses: actions/checkout@v4
22-
with:
23-
fetch-depth: 0 # Important for semantic release to work correctly
24-
25-
- name: Setup Node.js
26-
uses: actions/setup-node@v4
27-
with:
28-
node-version: "22"
29-
registry-url: "https://registry.npmjs.org"
30-
31-
- name: Setup pnpm
32-
uses: pnpm/action-setup@v2
33-
with:
34-
version: "10.8.1"
35-
run_install: false
36-
37-
- name: Get pnpm store directory
38-
id: pnpm-cache
39-
shell: bash
40-
run: |
41-
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
42-
43-
- uses: actions/cache@v3
44-
name: Setup pnpm cache
45-
with:
46-
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
47-
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
48-
restore-keys: |
49-
${{ runner.os }}-pnpm-store-
50-
51-
- name: Install dependencies
52-
run: pnpm install --frozen-lockfile
53-
54-
- name: Build package
55-
run: pnpm build
56-
57-
- name: Release
58-
env:
59-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
60-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
61-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
62-
run: pnpm semantic-release
63-
64-
# Add more jobs for additional packages as repo grows
1+
name: Package Release
2+
3+
on:
4+
push:
5+
branches:
6+
- latest-release
7+
- beta
8+
9+
workflow_dispatch:
10+
11+
permissions:
12+
contents: write
13+
issues: write
14+
pull-requests: write
15+
id-token: write # Required for npm OIDC trusted publishing
16+
17+
concurrency:
18+
group: release-${{ github.ref }}
19+
cancel-in-progress: true
20+
21+
jobs:
22+
release-builder:
23+
runs-on: ubuntu-latest
24+
defaults:
25+
run:
26+
working-directory: packages/builder
27+
steps:
28+
- uses: actions/checkout@v4
29+
with:
30+
fetch-depth: 0 # Important for semantic release to work correctly
31+
32+
- name: Setup Node.js
33+
uses: actions/setup-node@v4
34+
with:
35+
node-version: "22"
36+
registry-url: "https://registry.npmjs.org"
37+
38+
- name: Setup pnpm
39+
uses: pnpm/action-setup@v2
40+
with:
41+
version: "10.8.1"
42+
run_install: false
43+
44+
- name: Get pnpm store directory
45+
id: pnpm-cache
46+
shell: bash
47+
run: |
48+
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
49+
50+
- uses: actions/cache@v4
51+
name: Setup pnpm cache
52+
with:
53+
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
54+
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
55+
restore-keys: |
56+
${{ runner.os }}-pnpm-store-
57+
58+
- name: Install dependencies
59+
run: pnpm install --frozen-lockfile
60+
working-directory: .
61+
62+
- name: Build package
63+
run: pnpm build
64+
working-directory: .
65+
66+
- name: Semantic Release
67+
id: semantic
68+
env:
69+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
70+
run: pnpm semantic-release
71+
72+
- name: Publish to npm with OIDC
73+
if: steps.semantic.outcome == 'success'
74+
run: |
75+
# Check if package.json version was updated (not 0.0.0-development)
76+
VERSION=$(node -p "require('./package.json').version")
77+
if [ "$VERSION" != "0.0.0-development" ]; then
78+
echo "Publishing version $VERSION to npm with OIDC provenance..."
79+
npm publish --provenance --access public
80+
else
81+
echo "No new version to publish"
82+
fi
83+

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
node_modules
22
dist
33
coverage
4+
sites
45

56
*.tsbuildinfo

.vscode/pushforge.code-workspace

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
{
44
"path": "../packages/builder",
55
},
6+
{
7+
"path": "../sites/test",
8+
},
69
{
710
"path": "..",
811
},

README.md

Lines changed: 93 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,139 @@
1-
# PushForge 🚀
2-
31
<div align="center">
42

5-
<img src="images/pushforge_logo.png" alt="PushForge Logo" width="150" />
3+
<img src="images/logo.webp" alt="PushForge Logo" width="120" />
4+
5+
# PushForge
66

7-
**Modern, Cross-Platform Web Push Notifications**
7+
**Web Push Notifications for the Modern Stack**
88

9+
[![npm version](https://img.shields.io/npm/v/@pushforge/builder.svg)](https://www.npmjs.com/package/@pushforge/builder)
910
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
10-
[![Node Version](https://img.shields.io/badge/node-%3E%3D16.0.0-brightgreen)](https://nodejs.org/)
11-
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
11+
[![TypeScript](https://img.shields.io/badge/TypeScript-first--class-blue.svg)](https://www.typescriptlang.org/)
1212

13-
</div>
13+
Zero dependencies · Works everywhere · TypeScript-first
1414

15-
## What is PushForge?
15+
[Documentation](packages/builder) · [npm](https://www.npmjs.com/package/@pushforge/builder) · [Report Bug](https://github.com/draphy/pushforge/issues)
1616

17-
PushForge is a comprehensive toolkit for implementing Web Push Notifications in modern web applications. It handles the complex parts of push notifications so you can focus on building great user experiences.
17+
**[Try the Live Demo →](https://pushforge.draphy.org)**
1818

19-
**Zero dependencies. Cross-platform. TypeScript-first.**
19+
</div>
2020

21-
### Features
21+
---
2222

23-
- 🔐 Compliant VAPID authentication
24-
- 📦 Streamlined payload encryption
25-
- 🌐 Works everywhere: Node.js, Browsers, Deno, Bun, Cloudflare Workers
26-
- 🧩 Modular architecture for flexible implementation
27-
- 🛠️ Built with TypeScript for robust type safety
23+
## Live Demo
2824

29-
## Packages
25+
See PushForge in action at **[pushforge.draphy.org](https://pushforge.draphy.org)** — a fully working test site powered by PushForge on Cloudflare Workers.
3026

31-
| Package | Description | Path |
32-
| -------------------------------------- | --------------------------------------------------------------------------------- | --------------------------------------- |
33-
| [@pushforge/builder](packages/builder) | Core library for building push notification requests with proper VAPID encryption | [`packages/builder/`](packages/builder) |
27+
- **Enable push notifications** on your device with a single toggle
28+
- **Send a test notification** to all active devices — anyone visiting the page can send and receive
29+
- **See it working across browsers** — Chrome, Firefox, Edge, Safari 16+, and more
30+
- Subscriptions auto-expire after 5 minutes — no permanent data stored
3431

35-
_More packages coming soon!_
32+
The entire backend is a single Cloudflare Worker using `buildPushHTTPRequest()` from `@pushforge/builder` with zero additional dependencies.
3633

37-
## Quick Start
34+
## The Problem
3835

39-
```bash
40-
# Install the core package
41-
npm install @pushforge/builder
36+
Traditional web push libraries like `web-push` rely on Node.js-specific APIs that don't work in modern edge runtimes:
4237

43-
# Generate VAPID keys for push authentication
44-
npx @pushforge/builder generate-vapid-keys
38+
```
39+
❌ Cloudflare Workers - "crypto.createECDH is not a function"
40+
❌ Vercel Edge - "https.request is not available"
41+
❌ Convex - "Top-level await is not supported"
4542
```
4643

47-
Check out the complete documentation in each package's README for detailed usage examples.
44+
## The Solution
4845

49-
## Project Structure
46+
PushForge uses standard Web APIs that work everywhere:
5047

51-
```
52-
pushforge/
53-
├── packages/
54-
│ └── builder/ # Core push notification builder
55-
│ ├── lib/ # Source code
56-
│ ├── examples/ # Usage examples (coming soon...)
57-
│ └── README.md # Package documentation
58-
└── README.md # This file
59-
```
48+
```typescript
49+
import { buildPushHTTPRequest } from "@pushforge/builder";
6050

61-
## Requirements
51+
const { endpoint, headers, body } = await buildPushHTTPRequest({
52+
privateJWK: VAPID_PRIVATE_KEY,
53+
subscription: userSubscription,
54+
message: {
55+
payload: { title: "Hello!", body: "This works everywhere." },
56+
adminContact: "mailto:admin@example.com"
57+
}
58+
});
6259

63-
- **Node.js**: v16.0.0 or higher (for WebCrypto API support)
64-
- **NPM**, **Yarn**, or **pnpm** for package management
60+
await fetch(endpoint, { method: "POST", headers, body });
61+
```
6562

66-
## Development Setup
63+
## Why PushForge?
6764

68-
1. Clone the repository:
65+
| | PushForge | web-push |
66+
|---|:---:|:---:|
67+
| Dependencies | **0** | 5+ |
68+
| Cloudflare Workers || [](https://github.com/web-push-libs/web-push/issues/718) |
69+
| Vercel Edge |||
70+
| Convex |||
71+
| Deno / Bun || Limited |
72+
| TypeScript | Native | @types |
6973

70-
```bash
71-
git clone https://github.com/draphy/pushforge.git
72-
cd pushforge
73-
```
74+
## Quick Start
7475

75-
2. Install dependencies:
76+
```bash
77+
# Install
78+
npm install @pushforge/builder
7679

77-
```bash
78-
pnpm install
79-
```
80+
# Generate VAPID keys
81+
npx @pushforge/builder vapid
82+
```
8083

81-
3. Build packages:
84+
**Frontend** - Subscribe users:
8285

83-
```bash
84-
pnpm build
85-
```
86+
```javascript
87+
const subscription = await registration.pushManager.subscribe({
88+
userVisibleOnly: true,
89+
applicationServerKey: VAPID_PUBLIC_KEY
90+
});
91+
// Send subscription.toJSON() to your server
92+
```
8693

87-
4. Available Commands:
94+
**Backend** - Send notifications:
8895

89-
```bash
90-
# Format and lint code
91-
pnpm biome:format # Format code with Biome
92-
pnpm biome:lint # Lint code with Biome
93-
pnpm biome:check # Check code with Biome
94-
pnpm biome:fix # Fix issues automatically with Biome
96+
```typescript
97+
import { buildPushHTTPRequest } from "@pushforge/builder";
9598

96-
# Type checking
97-
pnpm type:check # Run TypeScript type checking
99+
const { endpoint, headers, body } = await buildPushHTTPRequest({
100+
privateJWK: process.env.VAPID_PRIVATE_KEY,
101+
subscription,
102+
message: {
103+
payload: { title: "New Message", body: "You have a notification!" },
104+
adminContact: "mailto:admin@example.com"
105+
}
106+
});
98107

99-
# Commit checks (run before committing)
100-
pnpm commit:check # Run formatting, type checking and build
101-
```
108+
await fetch(endpoint, { method: "POST", headers, body });
109+
```
102110

103-
## Contributing
111+
See the [full documentation](packages/builder) for platform-specific examples (Cloudflare Workers, Vercel Edge, Convex, Deno, Bun).
104112

105-
Contributions are always welcome! We follow a structured workflow for contributions - see our [Contributing Guidelines](CONTRIBUTING.md) for details.
113+
## Packages
106114

107-
Whether you want to:
115+
| Package | Description |
116+
|---------|-------------|
117+
| [@pushforge/builder](packages/builder) | Core library for building push notification requests |
108118

109-
- 🐛 Report a bug
110-
- 💡 Suggest new features
111-
- 🧪 Improve tests
112-
- 📚 Enhance documentation
113-
- 💻 Submit a PR
119+
## Requirements
114120

115-
We appreciate your help making PushForge better for everyone.
121+
- **Node.js 20+** or any runtime with Web Crypto API
122+
- Supported: Cloudflare Workers, Vercel Edge, Convex, Deno, Bun, modern browsers
116123

117-
## Reporting Issues
124+
## Development
118125

119-
Found a bug or have a feature request? Please [open an issue](https://github.com/draphy/pushforge/issues/new) and provide as much detail as possible.
126+
```bash
127+
git clone https://github.com/draphy/pushforge.git
128+
cd pushforge
129+
pnpm install
130+
pnpm build
131+
```
120132

121-
## Sponsorship
133+
## Contributing
122134

123-
If you find PushForge valuable, consider [sponsoring the project](https://github.com/sponsors/draphy). Your sponsorship helps maintain and improve the library.
135+
Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
124136

125137
## License
126138

127-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
128-
129-
---
130-
131-
<div align="center">
132-
<sub>Built with ❤️ by <a href="https://github.com/draphy">David Raphi</a></sub>
133-
</div>
139+
MIT © [David Raphi](https://github.com/draphy)

0 commit comments

Comments
 (0)