web-manager 4.3.1 → 4.3.3
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/CLAUDE.md +4 -0
- package/docs/bindings.md +223 -0
- package/docs/cdp-debugging.md +29 -0
- package/docs/modules.md +1 -0
- package/package.json +9 -3
- package/src/index.js +702 -0
- package/src/modules/analytics.js +250 -0
- package/src/modules/auth.js +420 -0
- package/src/modules/bindings.js +314 -0
- package/src/modules/dom.js +96 -0
- package/src/modules/firestore.js +306 -0
- package/src/modules/notifications.js +391 -0
- package/src/modules/sentry.js +199 -0
- package/src/modules/service-worker.js +196 -0
- package/src/modules/storage.js +133 -0
- package/src/modules/usage.js +264 -0
- package/src/modules/utilities.js +310 -0
- package/CHANGELOG.md +0 -233
- package/TODO.md +0 -54
- package/_legacy/helpers/auth-pages.js +0 -24
- package/_legacy/index.js +0 -1854
- package/_legacy/lib/account.js +0 -666
- package/_legacy/lib/debug.js +0 -56
- package/_legacy/lib/dom.js +0 -351
- package/_legacy/lib/require.js +0 -5
- package/_legacy/lib/storage.js +0 -78
- package/_legacy/lib/utilities.js +0 -180
- package/_legacy/service-worker copy.js +0 -347
- package/_legacy/test/test.js +0 -158
package/CLAUDE.md
CHANGED
|
@@ -69,6 +69,8 @@ Whenever you make a behavioral change (new module, new method, new pattern, remo
|
|
|
69
69
|
|
|
70
70
|
Don't ship behavioral changes with stale docs. Validate first, then document — write docs that describe shipped reality, not intentions.
|
|
71
71
|
|
|
72
|
+
**The OMEGA docs are structurally MIRRORED.** WM follows the library subset of the canonical OMEGA CLAUDE.md skeleton (the scaffolding frameworks UJM / BEM / BXM / EM / MAM carry the full skeleton + a consumer template). Never add, rename, or reorder a section here without checking the sister repos and the canonical skeletons + omission rules in the `omega:main` skill's `mirror-spec.md` resource.
|
|
73
|
+
|
|
72
74
|
## Documentation
|
|
73
75
|
|
|
74
76
|
Deep references live in `docs/`. Treat docs as a first-class deliverable. **Whenever you make a behavioral change, update both this overview AND the relevant `docs/*.md` deep reference.**
|
|
@@ -76,7 +78,9 @@ Deep references live in `docs/`. Treat docs as a first-class deliverable. **When
|
|
|
76
78
|
- [docs/architecture.md](docs/architecture.md) — singleton pattern, directory structure, module dependency graph
|
|
77
79
|
- [docs/code-patterns.md](docs/code-patterns.md) — early returns, `$`-prefixed DOM vars, logical operator placement, Firestore path syntax, dynamic imports, config deep-merge, event delegation
|
|
78
80
|
- [docs/modules.md](docs/modules.md) — full module quick reference (Storage, Auth + `resolveSubscription` + Settler Pattern, Bindings, Firestore, Notifications, ServiceWorker, Sentry, DOM, Utilities)
|
|
81
|
+
- [docs/bindings.md](docs/bindings.md) — `data-wm-bind` deep reference: actions, comma syntax, condition operators, state paths, skeleton loaders, root-key update filtering
|
|
79
82
|
- [docs/build-system.md](docs/build-system.md) — `prepare-package` ES5 transpile, build commands, package exports
|
|
80
83
|
- [docs/testing.md](docs/testing.md) — Mocha test setup
|
|
84
|
+
- [docs/cdp-debugging.md](docs/cdp-debugging.md) — driving a live browser (per-session isolated Chrome via the `chrome-devtools` MCP) to verify WM inside a consuming site
|
|
81
85
|
- [docs/common-tasks.md](docs/common-tasks.md) — adding a utility, adding a module, modifying config defaults, payment config (OMEGA SSOT shape), adding a binding action
|
|
82
86
|
- [docs/dependencies.md](docs/dependencies.md) — dependencies table + important notes (no TypeScript, prefer fs-jetpack, no backwards-compat requirement, etc.)
|
package/docs/bindings.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Bindings (`data-wm-bind`)
|
|
2
|
+
|
|
3
|
+
The `data-wm-bind` attribute declaratively binds DOM elements to state data (auth, plan, roles, usage, custom state) managed by `webManager.bindings()`. **Always prefer wm-bindings over manual JS class toggling** for anything based on user/auth state — if an element's visibility or content depends on the user object, use `data-wm-bind` in HTML, not `classList.toggle('d-none', ...)` or `.hidden` from JS.
|
|
4
|
+
|
|
5
|
+
## HTML Syntax
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<element data-wm-bind="@action path.to.data"></element>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Multiple Bindings: MUST Use Commas
|
|
12
|
+
|
|
13
|
+
Multiple bindings are **comma-separated**. The parser splits by comma first, then parses each part as `@action expression`.
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<!-- CORRECT: comma-separated -->
|
|
17
|
+
<element data-wm-bind="@show auth.user, @attr src auth.user.photoURL"></element>
|
|
18
|
+
|
|
19
|
+
<!-- WRONG: space-separated — gets parsed as ONE binding with action=@show, expression="auth.user @attr src auth.user.photoURL" -->
|
|
20
|
+
<element data-wm-bind="@show auth.user @attr src auth.user.photoURL"></element>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Why this matters:** The parser splits on `,` then finds the first space within each part to separate `@action` from `expression`. Without commas, everything after the first `@action` is treated as a single expression string, producing broken behavior with no error.
|
|
24
|
+
|
|
25
|
+
## Supported Actions
|
|
26
|
+
|
|
27
|
+
| Action | Syntax | Description |
|
|
28
|
+
|--------|--------|-------------|
|
|
29
|
+
| `@text` | `@text path` | Set text content |
|
|
30
|
+
| `@value` | `@value path` | Set input/textarea value |
|
|
31
|
+
| `@show` | `@show condition` | Show element if truthy |
|
|
32
|
+
| `@hide` | `@hide condition` | Hide element if truthy |
|
|
33
|
+
| `@attr` | `@attr name path` | Set HTML attribute value |
|
|
34
|
+
| `@style` | `@style property path` | Set CSS property or CSS variable |
|
|
35
|
+
|
|
36
|
+
## Condition Operators
|
|
37
|
+
|
|
38
|
+
```html
|
|
39
|
+
<!-- Truthy check -->
|
|
40
|
+
<div data-wm-bind="@show auth.user">Visible when logged in</div>
|
|
41
|
+
|
|
42
|
+
<!-- Negation (!) -->
|
|
43
|
+
<div data-wm-bind="@show !auth.user">Visible when NOT logged in</div>
|
|
44
|
+
|
|
45
|
+
<!-- Comparisons (===, !==, ==, !=, >, <, >=, <=) -->
|
|
46
|
+
<div data-wm-bind="@show auth.account.plan.id === 'premium'">Premium only</div>
|
|
47
|
+
<div data-wm-bind="@show checkout.errorCount > 0">Has errors</div>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
No logic operators (`&&`, `||`) in conditions — keep conditions simple. Right-side comparison values are auto-parsed: quoted strings, numbers, booleans, null.
|
|
51
|
+
|
|
52
|
+
## Common Auth Patterns
|
|
53
|
+
|
|
54
|
+
```html
|
|
55
|
+
<!-- Show for anonymous users -->
|
|
56
|
+
<div data-wm-bind="@show !auth.user">
|
|
57
|
+
<a href="/signup">Create free account</a>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<!-- Show for signed-in users -->
|
|
61
|
+
<div data-wm-bind="@show auth.user">
|
|
62
|
+
<a href="/pricing">Upgrade your plan</a>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<!-- Admin-only elements -->
|
|
66
|
+
<div data-wm-bind="@show auth.account.roles.admin">Admin panel</div>
|
|
67
|
+
|
|
68
|
+
<!-- User data binding -->
|
|
69
|
+
<img data-wm-bind="@show auth.user, @attr src auth.user.photoURL, @attr alt auth.user.displayName">
|
|
70
|
+
<span data-wm-bind="@text auth.user.displayName">Loading...</span>
|
|
71
|
+
<input data-wm-bind="@value auth.user.email">
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Available State Paths
|
|
75
|
+
|
|
76
|
+
### Auth paths (automatically populated by web-manager)
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
auth.user # Firebase user object (truthy = signed in)
|
|
80
|
+
auth.user.uid # User ID
|
|
81
|
+
auth.user.email # Email
|
|
82
|
+
auth.user.displayName # Display name
|
|
83
|
+
auth.user.photoURL # Avatar URL
|
|
84
|
+
auth.user.emailVerified # Boolean
|
|
85
|
+
auth.account.plan.id # Plan ID (e.g. 'basic', 'premium')
|
|
86
|
+
auth.account.roles.admin # Boolean
|
|
87
|
+
auth.account.roles.betaTester # Boolean
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Usage paths (auto-populated by web-manager + authorized-fetch)
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
usage.{feature}.monthly # Current monthly usage count
|
|
94
|
+
usage.{feature}.daily # Current daily usage count
|
|
95
|
+
usage.{feature}.limit # Plan limit for this feature
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Example: `usage.credits.monthly`, `usage.credits.limit`
|
|
99
|
+
|
|
100
|
+
Seeded on auth settle from `account.usage` + the site's payment plan config. Refreshed after every `authorizedFetch` call from `bm-properties` response headers.
|
|
101
|
+
|
|
102
|
+
### Custom state (set via JS)
|
|
103
|
+
|
|
104
|
+
Any custom paths set via `webManager.bindings().update(stateObject)`.
|
|
105
|
+
|
|
106
|
+
## JavaScript API
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
// Update bindings with state data
|
|
110
|
+
webManager.bindings().update({
|
|
111
|
+
checkout: {
|
|
112
|
+
product: { name: 'Pro Plan' },
|
|
113
|
+
error: { show: false, message: '' },
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Get current binding context
|
|
118
|
+
const context = webManager.bindings().getContext();
|
|
119
|
+
|
|
120
|
+
// Clear all bindings
|
|
121
|
+
webManager.bindings().clear();
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Skeleton Loaders
|
|
125
|
+
|
|
126
|
+
### How Skeletons Work
|
|
127
|
+
|
|
128
|
+
The `wm-binding-skeleton` class shows a shimmer animation until data loads. Skeletons resolve **only when at least one of the element's bindings is actually processed** — meaning the binding's root key must be in the `updatedKeys` for that `update()` call.
|
|
129
|
+
|
|
130
|
+
When `_updateBindings` processes an element:
|
|
131
|
+
|
|
132
|
+
1. Executes each binding action (`@text`, `@show`, `@attr`, etc.)
|
|
133
|
+
2. Each action returns `true` (processed) or `false` (skipped because root key wasn't updated)
|
|
134
|
+
3. **Only if at least one action was processed:** adds `wm-bound` class (triggers CSS fade-out transition)
|
|
135
|
+
4. After 300ms, removes `wm-binding-skeleton` class (shimmer disappears)
|
|
136
|
+
|
|
137
|
+
**Root key scoping matters for skeletons.** If an element is bound to `checkout.pricing.total` and `update({ auth: ... })` fires, that element's skeleton is NOT resolved — the binding is skipped entirely because `checkout` is not in `updatedKeys`.
|
|
138
|
+
|
|
139
|
+
```html
|
|
140
|
+
<!-- Skeleton resolves when 'auth' key is updated -->
|
|
141
|
+
<span class="wm-binding-skeleton" data-wm-bind="@text auth.user.displayName"> </span>
|
|
142
|
+
|
|
143
|
+
<!-- Skeleton resolves when 'checkout' key is updated (NOT when 'auth' updates) -->
|
|
144
|
+
<span class="wm-binding-skeleton" data-wm-bind="@text checkout.pricing.total"> </span>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Multi-phase binding example (e.g., checkout page)
|
|
148
|
+
|
|
149
|
+
When bindings fire in phases, skeletons resolve independently per root key:
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
// Phase 1: Global auth bindings fire
|
|
153
|
+
webManager.bindings().update({ auth: { user: {...} } });
|
|
154
|
+
// → Only elements bound to 'auth.*' resolve their skeletons
|
|
155
|
+
// → Elements bound to 'checkout.*' keep their skeletons
|
|
156
|
+
|
|
157
|
+
// Phase 2: After API fetches complete
|
|
158
|
+
webManager.bindings().update({ checkout: { pricing: {...} } });
|
|
159
|
+
// → Now elements bound to 'checkout.*' resolve their skeletons
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
This prevents checkout skeletons from disappearing prematurely when global auth bindings fire before checkout data is available.
|
|
163
|
+
|
|
164
|
+
### Skeleton Pattern
|
|
165
|
+
|
|
166
|
+
Use ` ` as placeholder content (prevents zero-width collapse so the shimmer is visible):
|
|
167
|
+
|
|
168
|
+
```html
|
|
169
|
+
<span class="wm-binding-skeleton" data-wm-bind="@text auth.user.displayName"> </span>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Do NOT use text like "Loading..." as placeholder** — it flashes visible text before the shimmer kicks in. Use ` ` for a clean shimmer-only experience.
|
|
173
|
+
|
|
174
|
+
### Composite Text in Skeletons
|
|
175
|
+
|
|
176
|
+
For composite text (e.g., "$0.00 due today"), do NOT mix static text with a binding span inside a skeleton div. Instead, create a dedicated pre-formatted value in the state and bind with a single `@text`:
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
// CORRECT: compose the text in JS, bind as single value
|
|
180
|
+
webManager.bindings().update({
|
|
181
|
+
checkout: {
|
|
182
|
+
totalDueText: `${formatCurrency(prices.total)} due today`,
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```html
|
|
188
|
+
<!-- CORRECT: single binding for composite text -->
|
|
189
|
+
<span class="wm-binding-skeleton" data-wm-bind="@text checkout.totalDueText"> </span>
|
|
190
|
+
|
|
191
|
+
<!-- WRONG: mixing static text with binding inside skeleton -->
|
|
192
|
+
<span class="wm-binding-skeleton">
|
|
193
|
+
<span data-wm-bind="@text checkout.pricing.total"></span> due today
|
|
194
|
+
</span>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Implementation Notes
|
|
198
|
+
|
|
199
|
+
- Uses the `hidden` attribute for show/hide (`[hidden] { display: none !important; }`)
|
|
200
|
+
- Queries `[data-wm-bind]` on each `update()` call — handles dynamic elements
|
|
201
|
+
- Auth bindings are auto-populated when `webManager.auth().listen()` fires
|
|
202
|
+
- When `updatedKeys` is `null` (e.g., from `clear()`), ALL bindings fire
|
|
203
|
+
|
|
204
|
+
### Root Key Update Filtering
|
|
205
|
+
|
|
206
|
+
`_shouldUpdatePath` checks the **root key** (first segment before `.`) of each binding's expression path against the `updatedKeys` from the `update()` call. A binding only fires when its root key was updated.
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
// This update ONLY triggers bindings whose expression starts with 'checkout'
|
|
210
|
+
webManager.bindings().update({
|
|
211
|
+
checkout: { pricing: { total: 9.99 } },
|
|
212
|
+
});
|
|
213
|
+
// Fires: @text checkout.pricing.total, @show checkout.active
|
|
214
|
+
// Skips: @text auth.user.displayName (root key is 'auth', not updated)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Negation (`!`) is stripped before root-key checking, so `@show !auth.user` fires when `auth` is updated.
|
|
218
|
+
|
|
219
|
+
## See also
|
|
220
|
+
|
|
221
|
+
- [modules.md](modules.md) — quick reference for all nine modules
|
|
222
|
+
- [architecture.md](architecture.md) — module dependency graph
|
|
223
|
+
- `src/modules/bindings.js` — the implementation
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# CDP Debugging (driving a live browser)
|
|
2
|
+
|
|
3
|
+
How to drive a browser you can CONTROL — see a consuming site live, screenshot it, click, type, read console logs, inspect network requests — for agents (Claude via MCP/CDP) and humans. WM has no dev server of its own; it runs INSIDE consumers (UJM sites, BXM extensions, EM renderers), so browser verification means driving a consumer.
|
|
4
|
+
|
|
5
|
+
> Mirrored across the five sister frameworks (UJM / BEM / BXM / EM / WM) — same core section, framework-flavored. Edit all five together.
|
|
6
|
+
|
|
7
|
+
## The browser: your Claude session owns one
|
|
8
|
+
|
|
9
|
+
Browser work runs through the **`chrome-devtools` MCP** (via mcp-router). There is NO launch procedure anymore — no ports, no profile dirs, no curl checks:
|
|
10
|
+
|
|
11
|
+
- **Just call the tools** — `new_page`, `navigate_page`, `take_screenshot`, `click`, `fill`, `evaluate_script`, `list_console_messages`, `list_network_requests`. The browser auto-launches on the first call.
|
|
12
|
+
- **Each Claude session gets its OWN private Chrome** (`--isolated`): temp profile, CDP over an internal pipe. Parallel sessions cannot see or touch each other's pages — open and close pages freely, the whole browser is yours.
|
|
13
|
+
- **It dies with the session.** No orphans, no cleanup, nothing to kill.
|
|
14
|
+
- **Ephemeral profile** — cookies/logins do NOT persist between sessions. If a flow needs auth, log in during the task.
|
|
15
|
+
- **Self-signed HTTPS is pre-accepted** (`--acceptInsecureCerts` in the upstream) — dev servers load without certificate interstitials.
|
|
16
|
+
- **NEVER quit/kill Chrome by app name** (`killall "Google Chrome"`, osascript) — that's the user's personal browser, not yours.
|
|
17
|
+
|
|
18
|
+
Humans: the agent's Chrome window is visible — you can watch it drive. Full reference: `~/.claude/mcp-server/servers/chrome-devtools/CLAUDE.md`.
|
|
19
|
+
|
|
20
|
+
## Electron apps are the exception (attach, don't launch)
|
|
21
|
+
|
|
22
|
+
An Electron dev app is a running singleton — you ATTACH to it instead of launching a browser: the `chrome-devtools-electron` MCP upstream (reads `EM_CDP_PORT`, default 9222, expanded once at session start) or EM's per-invocation `npx mgr cdp`. See EM's `docs/cdp-debugging.md`.
|
|
23
|
+
|
|
24
|
+
## WM specifics
|
|
25
|
+
|
|
26
|
+
- **Verify WM behavior through a consumer.** The usual host is a UJM site's dev server: **`https://localhost:4000` — NEVER the LAN IP** (`https://192.168.x.x:...`); port 4000 by default, increments (4001, …) when multiple sites run — exact port in the WEBSITE project's `.temp/_config_browsersync.yml`. To test uncommitted WM changes, link the local web-manager into the consumer first (see the consumer framework's dev-install flow), then drive the site.
|
|
27
|
+
- What to exercise from the browser: auth flows (`webManager.auth()` states, the Settler Pattern), `data-wm-bind` bindings reacting to state changes (`evaluate_script` to mutate state, `take_snapshot`/`take_screenshot` to verify DOM), Firestore reads/writes on the network tab, and console cleanliness (WM logs its module lifecycle).
|
|
28
|
+
- Ephemeral profile ⇒ auth'd testing means logging in through the consumer's real UI at the start of the session (test creds).
|
|
29
|
+
- WM inside a BXM extension or EM renderer: drive those through their own surfaces — BXM's `chrome-devtools-extension` upstream, EM's `chrome-devtools-electron`/`mgr cdp` (see those repos' `docs/cdp-debugging.md`).
|
package/docs/modules.md
CHANGED
|
@@ -45,6 +45,7 @@ Auth uses a promise-based settler (`_authReady`) that resolves once Firebase's f
|
|
|
45
45
|
- **Key Methods**: `update(data)`, `getContext()`, `clear()`
|
|
46
46
|
- **HTML Attr**: `data-wm-bind`
|
|
47
47
|
- **Actions**: `@text`, `@value`, `@show`, `@hide`, `@attr`, `@style`
|
|
48
|
+
- **Deep reference**: [bindings.md](bindings.md) — comma syntax, condition operators, state paths, skeleton loaders, root-key filtering
|
|
48
49
|
|
|
49
50
|
## Firestore (`firestore.js`)
|
|
50
51
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "web-manager",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.3",
|
|
4
4
|
"description": "Easily access important variables such as the query string, current domain, and current page in a single object.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist/",
|
|
8
|
+
"src/",
|
|
9
|
+
"docs/",
|
|
10
|
+
"CLAUDE.md"
|
|
11
|
+
],
|
|
6
12
|
"module": "src/index.js",
|
|
7
13
|
"exports": {
|
|
8
14
|
".": "./dist/index.js",
|
|
@@ -43,9 +49,9 @@
|
|
|
43
49
|
"@sentry/browser": "Resolved by using OVERRIDES in web-manager (lighthouse is the issue"
|
|
44
50
|
},
|
|
45
51
|
"dependencies": {
|
|
46
|
-
"@sentry/browser": "^10.
|
|
52
|
+
"@sentry/browser": "^10.57.0",
|
|
47
53
|
"chatsy": "^2.0.14",
|
|
48
|
-
"firebase": "^12.
|
|
54
|
+
"firebase": "^12.14.0",
|
|
49
55
|
"itwcw-package-analytics": "^1.0.8",
|
|
50
56
|
"lodash": "^4.18.1"
|
|
51
57
|
},
|