webhanger 1.0.1 → 1.0.4
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 +472 -82
- package/bin/cli.js +459 -4
- package/core/builder.js +133 -0
- package/core/registry.js +15 -6
- package/core/resolver.js +63 -0
- package/helper/accessControl.js +112 -0
- package/helper/breakdown.js +63 -0
- package/helper/bundler.js +17 -25
- package/helper/crypto.js +39 -0
- package/index.js +3 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,26 +1,51 @@
|
|
|
1
|
-
#
|
|
1
|
+
# WebHanger
|
|
2
2
|
|
|
3
|
-
Component-as-a-Service
|
|
3
|
+
> **Component-as-a-Service (CaaS)** — Bundle once. Encrypt with AES-256. Deliver via edge CDN. Load anywhere with zero code.
|
|
4
|
+
|
|
5
|
+
WebHanger is a secure, edge-delivered component distribution platform. Think of it as npm for UI components — but instead of installing packages, you deploy encrypted components to a CDN and load them into any website with a single HTML tag.
|
|
4
6
|
|
|
5
7
|
---
|
|
6
8
|
|
|
7
|
-
##
|
|
9
|
+
## Packages
|
|
10
|
+
|
|
11
|
+
| Package | Install | Description |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `webhanger` | `npm install -g webhanger` | CLI + Node.js library |
|
|
14
|
+
| `webhanger-front` | `npm install webhanger-front` | Browser SDK |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
8
19
|
|
|
9
20
|
```bash
|
|
10
|
-
# CLI
|
|
21
|
+
# 1. Install CLI
|
|
11
22
|
npm install -g webhanger
|
|
12
23
|
|
|
13
|
-
#
|
|
14
|
-
|
|
24
|
+
# 2. Setup your project (provisions S3 + CloudFront automatically)
|
|
25
|
+
wh init
|
|
26
|
+
|
|
27
|
+
# 3. Deploy all components, build site, zip for upload — one command
|
|
28
|
+
wh ship ./components ./docs 1.0.0 ./dist
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Load in any website — zero JS required:
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<script src="https://unpkg.com/webhanger-front@latest/browser.min.js"></script>
|
|
35
|
+
<script>WebHangerFront.initialize("./wh-manifest.json");</script>
|
|
36
|
+
|
|
37
|
+
<wh-component name="navbar"></wh-component>
|
|
38
|
+
<wh-component name="hero"></wh-component>
|
|
39
|
+
<wh-component name="footer"></wh-component>
|
|
15
40
|
```
|
|
16
41
|
|
|
17
42
|
---
|
|
18
43
|
|
|
19
|
-
## CLI
|
|
44
|
+
## CLI Reference
|
|
20
45
|
|
|
21
46
|
### `wh init`
|
|
22
47
|
|
|
23
|
-
Interactive setup. Provisions
|
|
48
|
+
Interactive project setup. Provisions infrastructure automatically.
|
|
24
49
|
|
|
25
50
|
```bash
|
|
26
51
|
wh init
|
|
@@ -30,147 +55,483 @@ Prompts:
|
|
|
30
55
|
- Project name
|
|
31
56
|
- Storage provider: `s3` | `r2` | `minio` | `local`
|
|
32
57
|
- Database provider: `firebase` | `supabase` | `mongodb`
|
|
33
|
-
- Credentials
|
|
58
|
+
- Credentials
|
|
59
|
+
|
|
60
|
+
For **S3**: automatically creates the bucket, configures CORS + versioning, spins up a CloudFront distribution. No AWS Console needed.
|
|
61
|
+
|
|
62
|
+
Optional: setup Cloudflare Edge Worker for token validation + geo routing at the edge.
|
|
63
|
+
|
|
64
|
+
Generates `webhanger.config.json`.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### `wh ship` ⭐ The main command
|
|
69
|
+
|
|
70
|
+
Deploy + build + zip in one shot.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
wh ship <components-dir> <site-dir> [version] [out-dir]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
wh ship ./components ./docs 1.0.0 ./dist
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
What it does:
|
|
81
|
+
1. Deploys all components (bundle → AES encrypt → upload → sign → register)
|
|
82
|
+
2. Resolves dependency graph
|
|
83
|
+
3. Writes `wh-manifest.json` (no sensitive data in HTML)
|
|
84
|
+
4. Production builds the site (minify HTML, inline CSS/JS)
|
|
85
|
+
5. Zips output for direct upload
|
|
34
86
|
|
|
35
|
-
|
|
87
|
+
```
|
|
88
|
+
🚀 [1/4] Deploying components...
|
|
89
|
+
navbar@1.0.0... ✅
|
|
90
|
+
hero@1.0.0... ✅
|
|
91
|
+
|
|
92
|
+
🔍 [2/4] Resolving dependency graph...
|
|
36
93
|
|
|
37
|
-
|
|
94
|
+
🏗️ [3/4] Building ./docs → ./dist...
|
|
95
|
+
index.html 4.2 kB
|
|
96
|
+
|
|
97
|
+
📦 [4/4] Zipping ./dist...
|
|
98
|
+
|
|
99
|
+
✅ Ship complete!
|
|
100
|
+
Deploy zip: ./deploy.zip (12.4 kB)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Upload `deploy.zip` to Netlify, S3, cPanel, or any static host.
|
|
38
104
|
|
|
39
105
|
---
|
|
40
106
|
|
|
41
107
|
### `wh deploy`
|
|
42
108
|
|
|
43
|
-
|
|
109
|
+
Deploy a single component.
|
|
44
110
|
|
|
45
111
|
```bash
|
|
46
112
|
wh deploy <component-dir> <name> <version>
|
|
113
|
+
wh deploy ./components/navbar navbar 1.0.0
|
|
47
114
|
```
|
|
48
115
|
|
|
116
|
+
Prompts for token (auto-generate or custom) and expiry (never or seconds).
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
### `wh graph-deploy`
|
|
121
|
+
|
|
122
|
+
Deploy all components in a directory and resolve the dependency graph.
|
|
123
|
+
|
|
49
124
|
```bash
|
|
50
|
-
wh deploy
|
|
125
|
+
wh graph-deploy <components-dir> [version] [out-dir]
|
|
126
|
+
wh graph-deploy ./components 1.0.0 ./output
|
|
51
127
|
```
|
|
52
128
|
|
|
53
|
-
|
|
54
|
-
- `index.html` — markup
|
|
55
|
-
- `style.css` — styles
|
|
56
|
-
- `script.js` — behaviour
|
|
129
|
+
---
|
|
57
130
|
|
|
58
|
-
|
|
131
|
+
### `wh build`
|
|
59
132
|
|
|
60
|
-
|
|
61
|
-
- Custom token? (or auto-generate)
|
|
62
|
-
- Set expiry? (or never expire)
|
|
133
|
+
Production build — minifies HTML, inlines local CSS/JS.
|
|
63
134
|
|
|
64
|
-
|
|
135
|
+
```bash
|
|
136
|
+
wh build <src-dir> [out-dir]
|
|
137
|
+
wh build ./docs ./dist
|
|
65
138
|
```
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### `wh zip`
|
|
143
|
+
|
|
144
|
+
Zip a directory for deployment.
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
wh zip <src-dir> [out-file]
|
|
148
|
+
wh zip ./dist ./deploy.zip
|
|
70
149
|
```
|
|
71
150
|
|
|
72
151
|
---
|
|
73
152
|
|
|
74
|
-
|
|
153
|
+
### `wh analyze`
|
|
154
|
+
|
|
155
|
+
Detect framework, styling approach, and CDN dependencies automatically.
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
wh analyze ./components/navbar
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
🔍 Component Analysis
|
|
163
|
+
|
|
164
|
+
Framework : vanilla
|
|
165
|
+
Styling : tailwind
|
|
166
|
+
Imports : gsap, axios
|
|
167
|
+
CDN Assets:
|
|
168
|
+
[script] https://cdn.tailwindcss.com
|
|
169
|
+
[script] https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### `wh convert`
|
|
175
|
+
|
|
176
|
+
Convert a vanilla HTML/CSS/JS component to any framework.
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
wh convert <dir> <name> <target> [out-dir]
|
|
180
|
+
wh convert ./components/navbar navbar react ./output
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Supported targets: `react` `vue` `svelte` `next` `angular` `astro`
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
### `wh access`
|
|
188
|
+
|
|
189
|
+
Role-based access control for teams.
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
wh access grant # generate API key with role
|
|
193
|
+
wh access revoke <key> # revoke a key
|
|
194
|
+
wh access list # list all keys
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Roles:
|
|
198
|
+
|
|
199
|
+
| Role | deploy | read | delete | manage_access |
|
|
200
|
+
|---|---|---|---|---|
|
|
201
|
+
| owner | ✅ | ✅ | ✅ | ✅ |
|
|
202
|
+
| admin | ✅ | ✅ | ✅ | ✅ |
|
|
203
|
+
| deployer | ✅ | ✅ | ❌ | ❌ |
|
|
204
|
+
| viewer | ❌ | ✅ | ❌ | ❌ |
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
### `wh edge-init`
|
|
209
|
+
|
|
210
|
+
Setup Cloudflare Edge Worker for production-grade delivery.
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
wh edge-init
|
|
214
|
+
# then:
|
|
215
|
+
cd edge && wrangler deploy
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Component Structure
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
components/
|
|
224
|
+
navbar/
|
|
225
|
+
index.html ← markup
|
|
226
|
+
style.css ← styles
|
|
227
|
+
script.js ← behaviour
|
|
228
|
+
webhanger.component.json ← assets + dependencies
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### `webhanger.component.json`
|
|
232
|
+
|
|
233
|
+
```json
|
|
234
|
+
{
|
|
235
|
+
"assets": [
|
|
236
|
+
{ "type": "script", "url": "https://cdn.tailwindcss.com" },
|
|
237
|
+
{ "type": "script", "url": "https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js" }
|
|
238
|
+
],
|
|
239
|
+
"dependencies": ["navbar@1.0.0", "chart@2.0.0"]
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
CDN assets are auto-detected by `wh analyze` and merged automatically on deploy.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Dependency Graph
|
|
248
|
+
|
|
249
|
+
npm-like dependency resolution for UI components.
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
dashboard@1.0.0
|
|
253
|
+
├── navbar@1.0.0
|
|
254
|
+
└── statsbar@1.0.0
|
|
255
|
+
└── chart@1.0.0
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
- Depth-first resolution
|
|
259
|
+
- Circular dependency detection with full chain error
|
|
260
|
+
- Deps load before parent component
|
|
261
|
+
- Stored in Firestore per project
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
wh graph-deploy ./components 1.0.0 ./output
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Programmatic:
|
|
75
268
|
|
|
76
269
|
```js
|
|
77
|
-
import {
|
|
270
|
+
import { resolveGraph } from "webhanger";
|
|
271
|
+
const graph = await resolveGraph(config.db, projectId, "dashboard", "1.0.0");
|
|
272
|
+
// Returns: [chart, navbar, statsbar, dashboard] — deps first
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Security
|
|
278
|
+
|
|
279
|
+
### AES-256-GCM Encryption
|
|
280
|
+
|
|
281
|
+
Every component chunk (HTML/CSS/JS) is encrypted before upload.
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
Key = SHA-256(projectId + salt)
|
|
285
|
+
Payload = iv:tag:ciphertext (base64)
|
|
286
|
+
Salts = "::html" | "::css" | "::js"
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### HMAC-SHA256 Signed URLs
|
|
78
290
|
|
|
79
|
-
const wh = new WebHanger();
|
|
80
291
|
```
|
|
292
|
+
token = HMAC-SHA256(projectId:componentPath:expires, secretKey)
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Integrity Check
|
|
296
|
+
|
|
297
|
+
SHA-256 hash of raw content stored in payload. Verified after decryption — detects tampering.
|
|
81
298
|
|
|
82
|
-
###
|
|
299
|
+
### Domain Restriction
|
|
83
300
|
|
|
84
301
|
```js
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
token: "my-custom-token", // optional — omit to auto-generate
|
|
88
|
-
dependencies: ["sidebar@1.0.0"] // optional
|
|
302
|
+
WebHangerFront.load(url, pid, token, 0, "[data-wh]", null, [], {
|
|
303
|
+
allowedDomains: ["mysite.com", "app.io"]
|
|
89
304
|
});
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Token Expiry
|
|
90
308
|
|
|
91
|
-
|
|
309
|
+
```js
|
|
310
|
+
// Never expires
|
|
311
|
+
wh.deploy("./navbar", "navbar", "1.0.0");
|
|
312
|
+
|
|
313
|
+
// Expires in 24 hours
|
|
314
|
+
wh.deploy("./navbar", "navbar", "1.0.0", { expiresInSeconds: 86400 });
|
|
92
315
|
```
|
|
93
316
|
|
|
94
|
-
###
|
|
317
|
+
### Manifest-based Delivery
|
|
95
318
|
|
|
96
|
-
|
|
319
|
+
Tokens, projectId, and CDN URLs never appear in HTML. Fetched at runtime from `wh-manifest.json`.
|
|
97
320
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Edge Worker (Cloudflare Workers)
|
|
324
|
+
|
|
325
|
+
Runs at the edge before S3:
|
|
326
|
+
|
|
327
|
+
- HMAC token validation
|
|
328
|
+
- Version resolution (`latest` → `1.2.0` from KV)
|
|
329
|
+
- Geo-based routing (India → ap-south-1, Europe → eu-west-1)
|
|
330
|
+
- Rate limiting (100 req/min per IP)
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
wh init # answer yes to edge worker setup
|
|
334
|
+
cd edge && wrangler deploy
|
|
101
335
|
```
|
|
102
336
|
|
|
103
|
-
|
|
337
|
+
Update `cdn.url` in `webhanger.config.json` to your worker URL — all requests now go through the edge.
|
|
338
|
+
|
|
339
|
+
---
|
|
104
340
|
|
|
105
|
-
|
|
341
|
+
## Multi-CDN Failover
|
|
342
|
+
|
|
343
|
+
```json
|
|
344
|
+
{
|
|
345
|
+
"cdn": {
|
|
346
|
+
"url": "https://primary.cloudfront.net",
|
|
347
|
+
"fallbacks": [
|
|
348
|
+
"https://fallback.r2.dev",
|
|
349
|
+
"https://backup.b-cdn.net"
|
|
350
|
+
]
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
SDK tries each URL in order. If primary fails, automatically falls back — zero code changes needed.
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Browser SDK
|
|
360
|
+
|
|
361
|
+
### Zero-code (recommended)
|
|
362
|
+
|
|
363
|
+
```html
|
|
364
|
+
<script src="https://unpkg.com/webhanger-front@latest/browser.min.js"></script>
|
|
365
|
+
<script>WebHangerFront.initialize("./wh-manifest.json");</script>
|
|
366
|
+
|
|
367
|
+
<wh-component name="navbar"></wh-component>
|
|
368
|
+
<wh-component name="hero"></wh-component>
|
|
369
|
+
<wh-component name="footer" sandbox></wh-component>
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Manual load
|
|
106
373
|
|
|
107
374
|
```js
|
|
108
|
-
|
|
109
|
-
|
|
375
|
+
WebHangerFront.load(
|
|
376
|
+
cdnUrl, // string or array (multi-CDN)
|
|
377
|
+
projectId, // decrypt key
|
|
378
|
+
token, // HMAC token
|
|
379
|
+
expires, // unix timestamp, 0 = never
|
|
380
|
+
selector, // CSS selector, default "[data-wh]"
|
|
381
|
+
onSignal, // optional signal callback
|
|
382
|
+
deps, // optional pre-resolved deps array
|
|
383
|
+
options // optional options object
|
|
384
|
+
);
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Lifecycle hooks
|
|
388
|
+
|
|
389
|
+
```js
|
|
390
|
+
WebHangerFront.load(url, pid, token, 0, "[data-wh]", null, [], {
|
|
391
|
+
beforeMount: ({ html }) => showSpinner(),
|
|
392
|
+
afterMount: ({ target }) => hideSpinner(),
|
|
393
|
+
onError: (err) => showFallback(err),
|
|
394
|
+
sandbox: true, // Shadow DOM isolation
|
|
395
|
+
allowedDomains: ["mysite.com"] // domain restriction
|
|
110
396
|
});
|
|
111
|
-
// { cdnUrl, token, expires }
|
|
112
397
|
```
|
|
113
398
|
|
|
114
|
-
###
|
|
399
|
+
### Signal callback
|
|
115
400
|
|
|
116
|
-
|
|
401
|
+
```js
|
|
402
|
+
WebHangerFront.load(url, pid, token, 0, "[data-wh]", ({ stage, ...detail }) => {
|
|
403
|
+
// stages: start → fetching → assets → deps → injecting → done | error
|
|
404
|
+
console.log(stage, detail.time, detail.source);
|
|
405
|
+
});
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Plugin system
|
|
117
409
|
|
|
118
410
|
```js
|
|
119
|
-
|
|
411
|
+
WebHangerFront.use({
|
|
412
|
+
install({ on, emit }) {
|
|
413
|
+
on("load", ({ time, source }) => analytics.track("load", { time, source }));
|
|
414
|
+
on("error", ({ message }) => errorTracker.capture(message));
|
|
415
|
+
on("metric", ({ name, value }) => dashboard.update(name, value));
|
|
416
|
+
}
|
|
417
|
+
});
|
|
120
418
|
```
|
|
121
419
|
|
|
122
|
-
###
|
|
420
|
+
### Observability
|
|
123
421
|
|
|
124
|
-
|
|
422
|
+
```js
|
|
423
|
+
WebHangerFront.on("load", ({ time, source }) => console.log(time, source));
|
|
424
|
+
WebHangerFront.on("metric", ({ name, value }) => console.log(name, value));
|
|
425
|
+
|
|
426
|
+
console.log(WebHangerFront.metrics);
|
|
427
|
+
// { loads: 5, cacheHits: 3, errors: 0, totalTime: 420 }
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Hard flush
|
|
125
431
|
|
|
126
432
|
```js
|
|
127
|
-
|
|
433
|
+
await WebHangerFront.clearCache();
|
|
434
|
+
// Clears: localStorage, IndexedDB, SW caches, sessionStorage, unregisters SW
|
|
128
435
|
```
|
|
129
436
|
|
|
130
437
|
---
|
|
131
438
|
|
|
132
|
-
##
|
|
439
|
+
## Caching
|
|
440
|
+
|
|
441
|
+
| Layer | Used for |
|
|
442
|
+
|---|---|
|
|
443
|
+
| `localStorage` | Components < 50KB |
|
|
444
|
+
| `IndexedDB` | Components ≥ 50KB |
|
|
445
|
+
| Service Worker | Offline fallback |
|
|
446
|
+
|
|
447
|
+
**Stale-while-revalidate** — returns cached version instantly, refreshes in background.
|
|
133
448
|
|
|
134
|
-
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Node.js API
|
|
452
|
+
|
|
453
|
+
```js
|
|
454
|
+
import { WebHanger } from "webhanger";
|
|
455
|
+
const wh = new WebHanger();
|
|
456
|
+
|
|
457
|
+
// Deploy
|
|
458
|
+
const result = await wh.deploy("./components/navbar", "navbar", "1.0.0", {
|
|
459
|
+
expiresInSeconds: 86400, // optional
|
|
460
|
+
token: "custom-token", // optional
|
|
461
|
+
dependencies: ["chart@1.0.0"]
|
|
462
|
+
});
|
|
463
|
+
// { cdnUrl, cdnUrls, token, expires, dependencies }
|
|
464
|
+
|
|
465
|
+
// Resolve
|
|
466
|
+
const comp = await wh.resolve("navbar", "1.0.0");
|
|
467
|
+
|
|
468
|
+
// Rotate token without redeploying
|
|
469
|
+
await wh.resign("navbar", "1.0.0", { expiresInSeconds: 3600 });
|
|
470
|
+
|
|
471
|
+
// Delete from storage
|
|
472
|
+
await wh.remove("navbar", "1.0.0");
|
|
473
|
+
|
|
474
|
+
// Get config
|
|
475
|
+
const config = wh.getConfig();
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Named exports
|
|
135
479
|
|
|
136
480
|
```js
|
|
137
481
|
import {
|
|
138
|
-
bundle,
|
|
139
|
-
signUrl,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
provisionBucket,
|
|
147
|
-
provisionCloudFront,
|
|
148
|
-
deploy,
|
|
482
|
+
bundle, encrypt, decrypt, integrityHash,
|
|
483
|
+
signUrl, verifyToken, generateSecretKey,
|
|
484
|
+
upload, remove,
|
|
485
|
+
registerComponent, getComponent,
|
|
486
|
+
deploy, resolveGraph,
|
|
487
|
+
convert, analyzeComponent,
|
|
488
|
+
build,
|
|
489
|
+
grantAccess, revokeAccess, checkPermission, listAccess, generateApiKey,
|
|
490
|
+
provisionBucket, provisionCloudFront,
|
|
149
491
|
loadConfig
|
|
150
492
|
} from "webhanger";
|
|
151
493
|
```
|
|
152
494
|
|
|
153
495
|
---
|
|
154
496
|
|
|
155
|
-
##
|
|
497
|
+
## Storage Providers
|
|
156
498
|
|
|
157
|
-
|
|
499
|
+
| Provider | Notes |
|
|
500
|
+
|---|---|
|
|
501
|
+
| `s3` | AWS S3 — auto-provisions bucket + CloudFront |
|
|
502
|
+
| `r2` | Cloudflare R2 — zero egress fees |
|
|
503
|
+
| `minio` | Self-hosted MinIO — S3-compatible |
|
|
504
|
+
| `local` | Local disk — dev/testing only |
|
|
505
|
+
|
|
506
|
+
## Database Providers
|
|
507
|
+
|
|
508
|
+
| Provider | Notes |
|
|
509
|
+
|---|---|
|
|
510
|
+
| `firebase` | Firebase Firestore — free tier, real-time |
|
|
511
|
+
| `supabase` | Supabase Postgres — open source |
|
|
512
|
+
| `mongodb` | MongoDB Atlas — flexible documents |
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## `webhanger.config.json`
|
|
158
517
|
|
|
159
518
|
```json
|
|
160
519
|
{
|
|
161
520
|
"project": "my-app",
|
|
162
521
|
"projectId": "wh_1234567890",
|
|
163
|
-
"secretKey": "
|
|
522
|
+
"secretKey": "64-char-hex-secret",
|
|
164
523
|
"webHangerVersion": "1.0.0",
|
|
165
524
|
"storage": {
|
|
166
525
|
"provider": "s3",
|
|
167
526
|
"accessKey": "...",
|
|
168
527
|
"secretKey": "...",
|
|
169
528
|
"bucket": "my-bucket",
|
|
170
|
-
"region": "ap-south-1"
|
|
529
|
+
"region": "ap-south-1",
|
|
530
|
+
"distributionId": "EXXXXX"
|
|
171
531
|
},
|
|
172
532
|
"cdn": {
|
|
173
|
-
"url": "https://
|
|
533
|
+
"url": "https://primary.cloudfront.net",
|
|
534
|
+
"fallbacks": ["https://fallback.r2.dev"]
|
|
174
535
|
},
|
|
175
536
|
"db": {
|
|
176
537
|
"provider": "firebase",
|
|
@@ -179,26 +540,55 @@ Generated by `wh init`. Keep this file private — never commit it.
|
|
|
179
540
|
}
|
|
180
541
|
```
|
|
181
542
|
|
|
543
|
+
> Keep this file private. Never commit it. Add to `.gitignore`.
|
|
544
|
+
|
|
182
545
|
---
|
|
183
546
|
|
|
184
|
-
##
|
|
547
|
+
## Architecture
|
|
185
548
|
|
|
186
549
|
```
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
550
|
+
Developer
|
|
551
|
+
└── wh ship ./components ./docs
|
|
552
|
+
├── wh analyze → detect Tailwind, GSAP, deps
|
|
553
|
+
├── wh bundle → html + css + js → single payload
|
|
554
|
+
├── AES-256-GCM → encrypt each chunk (SHA-256 key)
|
|
555
|
+
├── SHA-256 hash → integrity fingerprint
|
|
556
|
+
├── S3 upload → store encrypted payload
|
|
557
|
+
├── HMAC sign → project-scoped signed URL
|
|
558
|
+
├── Firestore → register metadata + dep graph
|
|
559
|
+
├── wh build → minify HTML, inline assets
|
|
560
|
+
└── wh zip → deploy.zip ready for upload
|
|
561
|
+
|
|
562
|
+
Browser
|
|
563
|
+
└── <wh-component name="navbar">
|
|
564
|
+
├── fetch wh-manifest.json
|
|
565
|
+
├── check token expiry
|
|
566
|
+
├── stale-while-revalidate cache
|
|
567
|
+
├── fetch from CloudFront (or Edge Worker)
|
|
568
|
+
│ └── Edge: validate token + geo route + rate limit
|
|
569
|
+
├── multi-CDN failover if primary fails
|
|
570
|
+
├── load CDN assets (Tailwind, GSAP, etc.)
|
|
571
|
+
├── resolve + load dependency graph
|
|
572
|
+
├── AES-256-GCM decrypt in memory
|
|
573
|
+
├── SHA-256 integrity verify
|
|
574
|
+
├── domain restriction check
|
|
575
|
+
├── inject CSS → HTML → JS (or Shadow DOM)
|
|
576
|
+
├── fire lifecycle hooks
|
|
577
|
+
└── emit metrics + plugin events
|
|
192
578
|
```
|
|
193
579
|
|
|
194
|
-
|
|
580
|
+
---
|
|
581
|
+
|
|
582
|
+
## Real-World Use Cases
|
|
583
|
+
|
|
584
|
+
- **Enterprise micro-frontends** — shared UI across 50+ apps, update once
|
|
585
|
+
- **Education platforms** — push UI updates to all school sites instantly
|
|
586
|
+
- **Low-bandwidth regions** — cache once, serve offline via Service Worker
|
|
587
|
+
- **Security platforms** — inject warnings/banners dynamically across sites
|
|
588
|
+
- **White-label SaaS** — per-tenant component customization
|
|
195
589
|
|
|
196
590
|
---
|
|
197
591
|
|
|
198
|
-
##
|
|
592
|
+
## License
|
|
199
593
|
|
|
200
|
-
|
|
201
|
-
- Each chunk (html/css/js) uses a different salt — `::html`, `::css`, `::js`
|
|
202
|
-
- CDN URLs are HMAC-SHA256 signed and scoped to your project
|
|
203
|
-
- Tokens can carry expiry or be permanent — your choice
|
|
204
|
-
- CloudFront forces HTTPS only
|
|
594
|
+
ISC
|