@omega.js/client 0.1.0
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/LICENSE +98 -0
- package/README.md +874 -0
- package/dist/index.js +999 -0
- package/dist/modules/analytics.js +584 -0
- package/dist/modules/auth.js +469 -0
- package/dist/modules/bindings.js +319 -0
- package/dist/modules/device.js +282 -0
- package/dist/modules/dom.js +96 -0
- package/dist/modules/features.js +30 -0
- package/dist/modules/firestore.js +313 -0
- package/dist/modules/form-manager.js +1577 -0
- package/dist/modules/icon-core.js +226 -0
- package/dist/modules/icon-renderer.js +149 -0
- package/dist/modules/live-page.js +235 -0
- package/dist/modules/logger.js +36 -0
- package/dist/modules/motion.js +853 -0
- package/dist/modules/notifications.js +433 -0
- package/dist/modules/path-prefix.js +22 -0
- package/dist/modules/request.js +223 -0
- package/dist/modules/sentry.js +108 -0
- package/dist/modules/service-worker.js +237 -0
- package/dist/modules/storage.js +133 -0
- package/dist/modules/triggers.js +117 -0
- package/dist/modules/utilities.js +479 -0
- package/dist/modules/vert-document.js +354 -0
- package/dist/modules/verts.js +1133 -0
- package/dist/vendor/account/engine.js +182 -0
- package/dist/vendor/account/features.js +220 -0
- package/dist/vendor/account/index.js +53 -0
- package/dist/vendor/account/schema.js +272 -0
- package/dist/vendor/account/subscription.js +38 -0
- package/dist/vendor/analytics/adapters/ga4.js +26 -0
- package/dist/vendor/analytics/adapters/meta.js +26 -0
- package/dist/vendor/analytics/adapters/resolve.js +130 -0
- package/dist/vendor/analytics/adapters/tiktok.js +27 -0
- package/dist/vendor/analytics/catalog.js +908 -0
- package/dist/vendor/analytics/consent.js +49 -0
- package/dist/vendor/analytics/core.js +141 -0
- package/dist/vendor/analytics/identity.js +136 -0
- package/dist/vendor/analytics/index.js +170 -0
- package/dist/vendor/analytics/logger.js +40 -0
- package/dist/vendor/analytics/transports/browser.js +110 -0
- package/dist/vendor/monitoring/browser.js +207 -0
- package/dist/vendor/monitoring/core.js +180 -0
- package/dist/vendor/monitoring/logger.js +39 -0
- package/docs/architecture.md +59 -0
- package/docs/bindings.md +235 -0
- package/docs/build-system.md +32 -0
- package/docs/cdp-debugging.md +29 -0
- package/docs/code-patterns.md +96 -0
- package/docs/common-tasks.md +36 -0
- package/docs/dependencies.md +19 -0
- package/docs/index.md +159 -0
- package/docs/modules.md +180 -0
- package/docs/shared/agent-docs.md +89 -0
- package/docs/shared/analytics.md +612 -0
- package/docs/shared/brands.md +51 -0
- package/docs/shared/breaking-changes.md +497 -0
- package/docs/shared/config.md +1387 -0
- package/docs/shared/deploys.md +215 -0
- package/docs/shared/icons.md +201 -0
- package/docs/shared/local-dev.md +147 -0
- package/docs/shared/logging.md +202 -0
- package/docs/shared/monitoring.md +153 -0
- package/docs/shared/publishing.md +183 -0
- package/docs/shared/rulings.md +34 -0
- package/docs/shared/testing.md +147 -0
- package/docs/shared/theming.md +604 -0
- package/docs/shared/translation.md +291 -0
- package/docs/shared/updates.md +61 -0
- package/docs/testing.md +9 -0
- package/package.json +65 -0
package/docs/bindings.md
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Bindings (`data-omega-bind`)
|
|
2
|
+
|
|
3
|
+
The `data-omega-bind` attribute declaratively binds DOM elements to state data (auth, plan, roles, usage, custom state) managed by `omega.bindings()`. **Always prefer omega-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-omega-bind` in HTML, not `classList.toggle('d-none', ...)` or `.hidden` from JS.
|
|
4
|
+
|
|
5
|
+
## HTML Syntax
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<element data-omega-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-omega-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-omega-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-omega-bind="@show auth.user">Visible when logged in</div>
|
|
41
|
+
|
|
42
|
+
<!-- Negation (!) -->
|
|
43
|
+
<div data-omega-bind="@show !auth.user">Visible when NOT logged in</div>
|
|
44
|
+
|
|
45
|
+
<!-- Comparisons (===, !==, ==, !=, >, <, >=, <=) -->
|
|
46
|
+
<div data-omega-bind="@show auth.account.plan.id === 'premium'">Premium only</div>
|
|
47
|
+
<div data-omega-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-omega-bind="@show !auth.user">
|
|
57
|
+
<a href="/signup">Create free account</a>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<!-- Show for signed-in users -->
|
|
61
|
+
<div data-omega-bind="@show auth.user">
|
|
62
|
+
<a href="/pricing">Upgrade your plan</a>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<!-- Admin-only elements -->
|
|
66
|
+
<div data-omega-bind="@show auth.account.roles.admin">Admin panel</div>
|
|
67
|
+
|
|
68
|
+
<!-- User data binding -->
|
|
69
|
+
<img data-omega-bind="@show auth.user, @attr src auth.user.photoURL, @attr alt auth.user.displayName">
|
|
70
|
+
<span data-omega-bind="@text auth.user.displayName">Loading...</span>
|
|
71
|
+
<input data-omega-bind="@value auth.user.email">
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Available State Paths
|
|
75
|
+
|
|
76
|
+
### Auth paths (automatically populated by @omega.js/client)
|
|
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 (server usage — auto-populated by @omega.js/client)
|
|
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 `omega.request()` call from the `omega-properties` response header — the backend attaches fresh usage counters to every response, so bound elements stay current automatically.
|
|
101
|
+
|
|
102
|
+
### Device paths (local stats — auto-populated on initialize)
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
device.installed # First-seen timestamp (ms)
|
|
106
|
+
device.session.count # Session count on this device
|
|
107
|
+
device.version.current # App version currently running
|
|
108
|
+
device.version.isNew # True on the first run after an update
|
|
109
|
+
device.duration.total.days # Time since install (also: session.*, other units)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
From the `device` module (localStorage / extension storage) — LOCAL device stats, deliberately a different key than the server-derived `usage` above.
|
|
113
|
+
|
|
114
|
+
### Custom state (set via JS)
|
|
115
|
+
|
|
116
|
+
Any custom paths set via `omega.bindings().update(stateObject)`.
|
|
117
|
+
|
|
118
|
+
## JavaScript API
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
// Update bindings with state data
|
|
122
|
+
omega.bindings().update({
|
|
123
|
+
checkout: {
|
|
124
|
+
product: { name: 'Pro Plan' },
|
|
125
|
+
error: { show: false, message: '' },
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Get current binding context
|
|
130
|
+
const context = omega.bindings().getContext();
|
|
131
|
+
|
|
132
|
+
// Clear all bindings
|
|
133
|
+
omega.bindings().clear();
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Skeleton Loaders
|
|
137
|
+
|
|
138
|
+
### How Skeletons Work
|
|
139
|
+
|
|
140
|
+
The `omega-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.
|
|
141
|
+
|
|
142
|
+
When `_updateBindings` processes an element:
|
|
143
|
+
|
|
144
|
+
1. Executes each binding action (`@text`, `@show`, `@attr`, etc.)
|
|
145
|
+
2. Each action returns `true` (processed) or `false` (skipped because root key wasn't updated)
|
|
146
|
+
3. **Only if at least one action was processed:** adds `omega-bound` class (triggers CSS fade-out transition)
|
|
147
|
+
4. After 300ms, removes `omega-binding-skeleton` class (shimmer disappears)
|
|
148
|
+
|
|
149
|
+
**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`.
|
|
150
|
+
|
|
151
|
+
```html
|
|
152
|
+
<!-- Skeleton resolves when 'auth' key is updated -->
|
|
153
|
+
<span class="omega-binding-skeleton" data-omega-bind="@text auth.user.displayName"> </span>
|
|
154
|
+
|
|
155
|
+
<!-- Skeleton resolves when 'checkout' key is updated (NOT when 'auth' updates) -->
|
|
156
|
+
<span class="omega-binding-skeleton" data-omega-bind="@text checkout.pricing.total"> </span>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Multi-phase binding example (e.g., checkout page)
|
|
160
|
+
|
|
161
|
+
When bindings fire in phases, skeletons resolve independently per root key:
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
// Phase 1: Global auth bindings fire
|
|
165
|
+
omega.bindings().update({ auth: { user: {...} } });
|
|
166
|
+
// → Only elements bound to 'auth.*' resolve their skeletons
|
|
167
|
+
// → Elements bound to 'checkout.*' keep their skeletons
|
|
168
|
+
|
|
169
|
+
// Phase 2: After API fetches complete
|
|
170
|
+
omega.bindings().update({ checkout: { pricing: {...} } });
|
|
171
|
+
// → Now elements bound to 'checkout.*' resolve their skeletons
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
This prevents checkout skeletons from disappearing prematurely when global auth bindings fire before checkout data is available.
|
|
175
|
+
|
|
176
|
+
### Skeleton Pattern
|
|
177
|
+
|
|
178
|
+
Use ` ` as placeholder content (prevents zero-width collapse so the shimmer is visible):
|
|
179
|
+
|
|
180
|
+
```html
|
|
181
|
+
<span class="omega-binding-skeleton" data-omega-bind="@text auth.user.displayName"> </span>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Do NOT use text like "Loading..." as placeholder** — it flashes visible text before the shimmer kicks in. Use ` ` for a clean shimmer-only experience.
|
|
185
|
+
|
|
186
|
+
### Composite Text in Skeletons
|
|
187
|
+
|
|
188
|
+
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`:
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
// CORRECT: compose the text in JS, bind as single value
|
|
192
|
+
omega.bindings().update({
|
|
193
|
+
checkout: {
|
|
194
|
+
totalDueText: `${formatCurrency(prices.total)} due today`,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
```html
|
|
200
|
+
<!-- CORRECT: single binding for composite text -->
|
|
201
|
+
<span class="omega-binding-skeleton" data-omega-bind="@text checkout.totalDueText"> </span>
|
|
202
|
+
|
|
203
|
+
<!-- WRONG: mixing static text with binding inside skeleton -->
|
|
204
|
+
<span class="omega-binding-skeleton">
|
|
205
|
+
<span data-omega-bind="@text checkout.pricing.total"></span> due today
|
|
206
|
+
</span>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Implementation Notes
|
|
210
|
+
|
|
211
|
+
- Uses the `hidden` attribute for show/hide (`[hidden] { display: none !important; }`)
|
|
212
|
+
- Queries `[data-omega-bind]` on each `update()` call — handles dynamic elements
|
|
213
|
+
- Auth bindings are auto-populated when `omega.auth().listen()` fires
|
|
214
|
+
- When `updatedKeys` is `null` (e.g., from `clear()`), ALL bindings fire
|
|
215
|
+
|
|
216
|
+
### Root Key Update Filtering
|
|
217
|
+
|
|
218
|
+
`_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.
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
// This update ONLY triggers bindings whose expression starts with 'checkout'
|
|
222
|
+
omega.bindings().update({
|
|
223
|
+
checkout: { pricing: { total: 9.99 } },
|
|
224
|
+
});
|
|
225
|
+
// Fires: @text checkout.pricing.total, @show checkout.active
|
|
226
|
+
// Skips: @text auth.user.displayName (root key is 'auth', not updated)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Negation (`!`) is stripped before root-key checking, so `@show !auth.user` fires when `auth` is updated.
|
|
230
|
+
|
|
231
|
+
## See also
|
|
232
|
+
|
|
233
|
+
- [modules.md](modules.md) — quick reference for all nine modules
|
|
234
|
+
- [architecture.md](architecture.md) — module dependency graph
|
|
235
|
+
- `src/modules/bindings.js` — the implementation
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Build System
|
|
2
|
+
|
|
3
|
+
## prepare-package
|
|
4
|
+
|
|
5
|
+
The library uses `prepare-package` for ES5 transpilation:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"preparePackage": {
|
|
10
|
+
"input": "./src",
|
|
11
|
+
"output": "./dist"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Commands**:
|
|
17
|
+
- `npm run prepare` — Build once
|
|
18
|
+
- `npm start` — Watch mode
|
|
19
|
+
- `npm test` — Run Mocha tests
|
|
20
|
+
|
|
21
|
+
## Package Exports
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"main": "dist/index.js",
|
|
26
|
+
"module": "src/index.js",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": "./dist/index.js",
|
|
29
|
+
"./modules/*": "./dist/modules/*"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
@@ -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. @omega.js/client has no dev server of its own; it runs INSIDE consumers (@omega.js/web sites, @omega.js/extension extensions, @omega.js/desktop renderers), so browser verification means driving a consumer.
|
|
4
|
+
|
|
5
|
+
> Mirrored across the five sister frameworks (UJM / @omega.js/backend / @omega.js/extension / @omega.js/desktop / @omega.js/client) — 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 `OMEGA_CDP_PORT`, default 9222, expanded once at session start) or @omega.js/desktop's per-invocation `npx omega cdp`. See @omega.js/desktop's `docs/cdp-debugging.md`.
|
|
23
|
+
|
|
24
|
+
## @omega.js/client specifics
|
|
25
|
+
|
|
26
|
+
- **Verify @omega.js/client 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 @omega.js/client changes, link the local @omega.js/client 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 (`omega.auth()` states, the Settler Pattern), `data-omega-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 (@omega.js/client 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
|
+
- @omega.js/client inside a @omega.js/extension extension or @omega.js/desktop renderer: drive those through their own surfaces — @omega.js/extension's `chrome-devtools-extension` upstream, @omega.js/desktop's `chrome-devtools-electron`/`mgr cdp` (see those repos' `docs/cdp-debugging.md`).
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Key Patterns
|
|
2
|
+
|
|
3
|
+
## 1. Early Return (Short-Circuit)
|
|
4
|
+
|
|
5
|
+
Always use early returns instead of nested conditionals:
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
// CORRECT
|
|
9
|
+
function doSomething() {
|
|
10
|
+
if (!condition) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
// Long code block...
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// WRONG
|
|
17
|
+
function doSomething() {
|
|
18
|
+
if (condition) {
|
|
19
|
+
// Long code block...
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 2. DOM Element Naming
|
|
25
|
+
|
|
26
|
+
Prefix DOM element variables with `$`:
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
const $button = document.querySelector('.submit-btn');
|
|
30
|
+
const $input = document.getElementById('email');
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 3. Logical Operator Formatting
|
|
34
|
+
|
|
35
|
+
Place operators at the START of continuation lines:
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
// CORRECT
|
|
39
|
+
const result = conditionA
|
|
40
|
+
|| conditionB
|
|
41
|
+
|| conditionC;
|
|
42
|
+
|
|
43
|
+
// WRONG
|
|
44
|
+
const result = conditionA ||
|
|
45
|
+
conditionB ||
|
|
46
|
+
conditionC;
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 4. Firestore Path Syntax
|
|
50
|
+
|
|
51
|
+
Prefer path syntax over collection/doc chaining:
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
// PREFERRED
|
|
55
|
+
db.doc('users/userId')
|
|
56
|
+
|
|
57
|
+
// ALSO SUPPORTED
|
|
58
|
+
db.doc('users', 'userId')
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 5. Dynamic Imports
|
|
62
|
+
|
|
63
|
+
Firebase modules are dynamically imported to reduce bundle size:
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
const { initializeApp } = await import('firebase/app');
|
|
67
|
+
const { getAuth } = await import('firebase/auth');
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 6. Configuration Deep Merge
|
|
71
|
+
|
|
72
|
+
User config is deep-merged with defaults in `_processConfiguration()`. Only override what you need:
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
// Defaults defined in _processConfiguration()
|
|
76
|
+
const defaults = {
|
|
77
|
+
environment: 'production',
|
|
78
|
+
firebase: { app: { enabled: true, config: {} } },
|
|
79
|
+
// ...
|
|
80
|
+
};
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 7. Click Triggers
|
|
84
|
+
|
|
85
|
+
Click-driven UI never hand-rolls a listener: it registers on the shared trigger
|
|
86
|
+
registry (`modules/triggers.js`), which owns the ONE delegated `document` click
|
|
87
|
+
listener. The class is always `omega-<name>` — callers never spell it:
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
import { registerTrigger } from '@omega.js/client/modules/triggers.js';
|
|
91
|
+
|
|
92
|
+
// A click on `.omega-signout` (or anything inside one) runs this
|
|
93
|
+
registerTrigger('signout', async (event, element) => {
|
|
94
|
+
// Handle signout
|
|
95
|
+
});
|
|
96
|
+
```
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Common Tasks
|
|
2
|
+
|
|
3
|
+
## Adding a New Utility Function
|
|
4
|
+
|
|
5
|
+
1. Add function to `src/modules/utilities.js`
|
|
6
|
+
2. Export it: `export function myFunction() { ... }`
|
|
7
|
+
3. Update README.md with documentation
|
|
8
|
+
4. Run `npm run prepare` to build
|
|
9
|
+
|
|
10
|
+
## Adding a New Module
|
|
11
|
+
|
|
12
|
+
1. Create `src/modules/my-module.js`
|
|
13
|
+
2. Export class: `export default class MyModule { constructor(manager) { ... } }`
|
|
14
|
+
3. Import in `src/index.js`: `import MyModule from './modules/my-module.js'`
|
|
15
|
+
4. Add to Manager constructor: `this._myModule = new MyModule(this)`
|
|
16
|
+
5. Add getter: `myModule() { return this._myModule; }`
|
|
17
|
+
6. Update README.md
|
|
18
|
+
7. Run `npm run prepare`
|
|
19
|
+
|
|
20
|
+
## Modifying Configuration Defaults
|
|
21
|
+
|
|
22
|
+
1. Edit `_processConfiguration()` in `src/index.js`
|
|
23
|
+
2. Add to `defaults` object (e.g., `payment: { providers: {}, products: [] }`)
|
|
24
|
+
3. Document in README.md Configuration section
|
|
25
|
+
|
|
26
|
+
## Payment Configuration
|
|
27
|
+
|
|
28
|
+
Payment config shape mirrors OMEGA (the SSOT) — same key names used in @omega.js/backend, UJM, and @omega.js/desktop:
|
|
29
|
+
- `providers`: Stripe, PayPal, Chargebee, Coinbase (publishable keys / client IDs)
|
|
30
|
+
- `products`: Array of `{ id, name, type, limits: { feature: N }, prices, trial, paypal, stripe, chargebee }` — used to resolve usage limits on the frontend AND drive checkout flows
|
|
31
|
+
|
|
32
|
+
## Adding a Data Binding Action
|
|
33
|
+
|
|
34
|
+
1. Edit `_executeAction()` in `src/modules/bindings.js`
|
|
35
|
+
2. Add case for new action (e.g., `@class`)
|
|
36
|
+
3. Document in README.md Data Binding section
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Dependencies & Important Notes
|
|
2
|
+
|
|
3
|
+
## Dependencies
|
|
4
|
+
|
|
5
|
+
| Package | Purpose |
|
|
6
|
+
|---------|---------|
|
|
7
|
+
| `firebase` (^12.x) | Auth, Firestore, Messaging |
|
|
8
|
+
| `@sentry/browser` (^10.x) | Error tracking |
|
|
9
|
+
| `lodash` (^4.x) | get/set for path-based access |
|
|
10
|
+
| `itwcw-package-analytics` | Analytics (internal) |
|
|
11
|
+
|
|
12
|
+
## Important Notes
|
|
13
|
+
|
|
14
|
+
1. **DO NOT MODIFY `_legacy/`** — Reference only for historical context
|
|
15
|
+
2. **Backwards compatibility is NOT required** — Just change to the new way
|
|
16
|
+
3. **Prefer `fs-jetpack`** over `fs` for any file operations in tests/scripts
|
|
17
|
+
4. **No TypeScript** — This is a pure JavaScript library
|
|
18
|
+
5. **Template strings** — Use backticks for string interpolation
|
|
19
|
+
6. **Modular design** — Keep modules focused and small
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# OMEGA Client (@omega.js/client)
|
|
2
|
+
|
|
3
|
+
> **Note for contributors and Claude:** This file is the guide for `@omega.js/client` — identity, top-level conventions, and a map to the deep references. It lives in the monorepo's `docs/` tree and is loaded on demand (the omega Claude plugin's hooks inject it by context; the repo-root AGENTS.md map is the one agent entry — packages carry no agent docs). The **meat** (module APIs, patterns, behavior tables) lives in the package's own [`docs/<topic>.md`](../docs) files. When extending or adding content, write it in the matching `docs/*.md` file and cross-link from here — do NOT inline it. If a topic doesn't have a doc yet, create one.
|
|
4
|
+
|
|
5
|
+
## Identity
|
|
6
|
+
|
|
7
|
+
OMEGA Client is a modern JavaScript utility library for web applications with Firebase integration. It runs in the browser, in Electron's renderer process, and inside browser extensions (content scripts, popups, background pages). Provides:
|
|
8
|
+
|
|
9
|
+
- A singleton `Manager` instance exposing authentication, reactive DOM data binding, Firestore, storage, push notifications, error tracking (Sentry), service-worker helpers, DOM/utility functions, and `omega.request()` — the harmonized API-fetch layer (fresh Bearer token, automatic `omega-properties` processing with server usage synced into bindings)
|
|
10
|
+
- Lazy Firebase imports to keep consumer bundles small
|
|
11
|
+
- Reactive `data-omega-bind` DOM directives wired to auth + usage state
|
|
12
|
+
- A `resolveSubscription()` helper unified with @omega.js/backend's `User.resolveSubscription()` so subscription-state logic is identical across frontend and backend
|
|
13
|
+
|
|
14
|
+
### Consumed by the frontend Manager family
|
|
15
|
+
|
|
16
|
+
OMEGA Client is the runtime singleton powering **@omega.js/web**, **@omega.js/extension**, and **@omega.js/desktop**. Each framework initializes the singleton once and exposes it as `manager.omega`. Any consumer of those frameworks gets a fully-wired @omega.js/client via `import omega from '@omega.js/client'`.
|
|
17
|
+
|
|
18
|
+
## Recommended skills
|
|
19
|
+
|
|
20
|
+
- **`omega:client`** — the router skill from the omega Claude plugin. The inject hook loads it automatically when the session works inside `packages/client` (own-name match only — a dependency on the runtime says nothing about the session); it points back to this guide + `docs/` (the SSOT).
|
|
21
|
+
- **`js:patterns`** — JavaScript/Node.js conventions: file structure, JSDoc, defensive coding (`?.` usage), template literals, `package.json` conventions. Auto-loads when creating new `.js` files or touching JS module structure.
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### For Consuming Projects
|
|
26
|
+
|
|
27
|
+
OMEGA Client is consumed indirectly through @omega.js/web, @omega.js/extension, or @omega.js/desktop — those frameworks initialize the singleton for you. Inside any consuming code:
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
import omega from '@omega.js/client';
|
|
31
|
+
|
|
32
|
+
omega.auth().listen({ once: true }, async () => { /* auth settled */ });
|
|
33
|
+
omega.utilities().escapeHTML(untrustedText);
|
|
34
|
+
omega.firestore().doc('users/abc').get();
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### For Framework Development (This Repository)
|
|
38
|
+
|
|
39
|
+
1. `npm install` — install OMEGA Client's own deps
|
|
40
|
+
2. `npm run prepare` — build once: copies `src/` → `dist/` via prepare-package (ES5 transpile)
|
|
41
|
+
3. `npm start` — watch mode (rebuild on change)
|
|
42
|
+
4. `npm test` — run Mocha tests
|
|
43
|
+
|
|
44
|
+
> **Important:** OMEGA Client is a library, not an app. There is no `npm run build` / `npm run serve` here. Consume it from inside an @omega.js/web / @omega.js/extension / @omega.js/desktop project for end-to-end behavior.
|
|
45
|
+
|
|
46
|
+
## Architecture
|
|
47
|
+
|
|
48
|
+
OMEGA Client exports a singleton `Manager` instance from `src/index.js`. Every `import omega from '@omega.js/client'` returns the same already-initialized object — do NOT call `new Manager()`, and do NOT pass `omega` through function params or module-level variables.
|
|
49
|
+
|
|
50
|
+
The singleton owns thirteen feature modules under `src/modules/`: `storage`, `auth`, `bindings`, `firestore`, `notifications`, `service-worker`, `sentry`, `dom`, `utilities` (the untrusted-text surface — `escapeHTML`, `sanitizeURL`, and the escape-first `renderMarkdown` that composes them, plus clipboard/notification/platform helpers), `device` (local install/session stats — binds the `device` key), `request` (harmonized API fetch — `omega.request()`; also consumed standalone by desktop main + the extension service worker via `createRequest`), `verts` (the fallback-ladder ad engine, adblock-safe naming — AdSense provider lane + in-house/company units, shared by web/desktop/extension), and `analytics` (runtime event tracking on every runtime, built on the shared `@omega.js/analytics` core — the one home of GA4 event-name and Measurement Protocol semantics; the extension posts through the Measurement Protocol, web hands the event to the page's own `gtag` so the api_secret never reaches a page, and desktop's renderer forwards over the preload's IPC bridge so the main process is the one sender ([#411](https://github.com/Omega-JS-Stack/omega/issues/411))). Firebase modules are dynamically imported to keep the bundle small. Alongside them live the transport-free standalone modules (`icon-core`, `icon-renderer`, `motion`, `live-page`, `vert-document` — the ONE vert unit document renderer, consumed by the verts module's promo lane and by `@omega.js/backend`'s serve route ([docs/web/ads-system.md](../web/ads-system.md)), `triggers` — the click-trigger registry below, `form-manager` — lightweight form state: initializing → ready ⇄ submitting) that embedding frameworks import by subpath and boot themselves — `motion` is the shared animation engine behind the `data-omega-*` attributes (classy v2), and `live-page` is the self-refreshing-page kit (`swap` writes a section only when its markup changed, `loading` is the first-paint spinner, `createFeedPoller` owns the declared feed table with its in-flight count and keep-last-good-on-failure rule, taking an `omega.request`-shaped fetcher as an argument). See [docs/architecture.md](../docs/architecture.md) for the directory structure and module dependency graph, and [docs/modules.md](../docs/modules.md) for the API reference of each module.
|
|
51
|
+
|
|
52
|
+
Pages built on this runtime follow the **page paint contract** ([docs/web/page-contract.md](../web/page-contract.md)): the client fills the `auth`, `usage`, `config` and `device` binding roots at auth settle so page code never hides its DOM waiting for a user, `bindings.update()` filters by root key so a spot that must wait for a server answer lives under a root the early paint does not publish, and `FormManager`'s `addGate()` / `resolveGate()` hold a form's submit controls disabled until every async answer it depends on has landed.
|
|
53
|
+
|
|
54
|
+
### The wakeup ping (`omega.request(url, { wakeup: true })`)
|
|
55
|
+
|
|
56
|
+
A fire-and-forget GET that warms a cold backend and nothing else. @omega.js/backend's middleware sees `wakeup` in the request data and answers it BEFORE it loads a route or authenticates ([docs/backend/index.md](../backend/index.md)), so any route warms the same function at the same cost and none of them runs. The call mints no ID token, reads no response body, and resolves rather than throwing when the network is down, so a caller can fire it and move on:
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
import { WAKEUP_ROUTE } from '@omega.js/client/modules/request.js';
|
|
60
|
+
|
|
61
|
+
omega.request(WAKEUP_ROUTE, { wakeup: true });
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**One route, every surface.** `WAKEUP_ROUTE` (`/omega/health`) is exported by `modules/request.js` and named by every caller instead of "the route I am about to need": a wakeup never runs a route, so a per-caller route would be a dozen spellings of one warm function — and desktop main and the extension cannot reach a web-side constant anyway ([#644](https://github.com/Omega-JS-Stack/omega/issues/644)).
|
|
65
|
+
|
|
66
|
+
**Where it fires.** Every entry point whose first user action is a backend call warms it on load, never awaited:
|
|
67
|
+
|
|
68
|
+
| Surface | Site | The call it is warming for |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| @omega.js/web | `/pricing` | the checkout the plan buttons lead to |
|
|
71
|
+
| @omega.js/web | `/payment/checkout` | `/omega/payments/intent` |
|
|
72
|
+
| @omega.js/web | `/signup` | `/omega/user/signup` — the 14-second cold start measured live 2026-08-27 |
|
|
73
|
+
| @omega.js/web | `/signin` | `/omega/user/signup` behind a first-time OAuth signin |
|
|
74
|
+
| @omega.js/web | `/account` | the billing portal, plan switch, cancel, refund, API key, data request, delete |
|
|
75
|
+
| @omega.js/web | `/token` | `/omega/user/token` (also where a desktop app and an extension sign in) |
|
|
76
|
+
| @omega.js/web | `/connections/callback` | `/omega/user/connections` |
|
|
77
|
+
| @omega.js/web | `/feedback` | `/omega/user/feedback` |
|
|
78
|
+
| @omega.js/web | `/portal/email-preferences` | `/omega/marketing/email-preferences` |
|
|
79
|
+
| @omega.js/web | `/download`, only where the notify-me form renders | `/omega/general/email` |
|
|
80
|
+
| @omega.js/web | the `newsletter-cta` band — on first FOCUS, not on load | `/omega/marketing/contact` |
|
|
81
|
+
| @omega.js/desktop | the renderer's auth bridge (`_wireAuthBridge`) | `/omega/user/token`, via main's sync-request |
|
|
82
|
+
| @omega.js/extension | every surface's `syncWithBackground()` | `/omega/user/token`, via background's sync |
|
|
83
|
+
|
|
84
|
+
The newsletter band is the one that waits for an interaction: it rides most pages, so a load-time ping would warm a function for every passive visitor scrolling past. A focus is the intent.
|
|
85
|
+
|
|
86
|
+
Deliberately NOT pinging: the payment confirmation page (its check is a Firestore read, not a backend call), the contact form (it posts to Slapform, a third party), and the admin dashboard (internal tooling, whose seven load-time fetches are their own warm-up).
|
|
87
|
+
|
|
88
|
+
### The session probe (`omega.auth().probeSession()`)
|
|
89
|
+
|
|
90
|
+
One forced token refresh at a moment of doubt, and nothing else ([#798](https://github.com/Omega-JS-Stack/omega/issues/798)). Firebase asks the Auth server about a persisted session at page load and at the hourly refresh and at no other moment, so a revoked, disabled or deleted account keeps an open tab signed in until a reload, and a dev stack whose auth emulator restarted leaves the page holding a session the server no longer has. The probe never asks OUR backend, so dev and production run the same code.
|
|
91
|
+
|
|
92
|
+
`probeSession()` exchanges the refresh token with the Auth server (`getIdToken(user, true)`) and classifies the answer:
|
|
93
|
+
|
|
94
|
+
| Result | When | What the client does |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `signed-out` | no `currentUser` | nothing; a probe on a signed-out client is a no-op |
|
|
97
|
+
| `alive` | the refresh succeeded | nothing |
|
|
98
|
+
| `gone` | a DEFINITE `auth/*` verdict, meaning any `auth/*` code that is not one of the three transient ones below (`auth/user-token-expired`, `auth/user-disabled`, `auth/user-not-found`, `auth/invalid-refresh-token`, …) | `signOut()`, whose `onAuthStateChanged` emission drives each surface's own policy listener |
|
|
99
|
+
| `unknown` | the three TRANSIENT codes (`auth/network-request-failed`, `auth/too-many-requests`, `auth/internal-error`), or an error carrying no auth code | keeps the user: a bad connection, a throttle and a failing Auth server are no verdict on the session, and neither is the "Backend starting" window |
|
|
100
|
+
|
|
101
|
+
**Three moments, no timer.** The tab coming back into view (`visibilitychange` to visible) and the network coming back (`online`) are wired once per manager instance beside the auth state listener, guarded for a host with no `document` (the extension's background service worker). The third is a 401 on an authenticated `omega.request()`: the request layer calls its optional `onUnauthorized` dep WITHOUT awaiting it and throws the caller's error unchanged, so nothing waits on a token refresh and a failed probe is never the request's failure. Probes coalesce, one in flight per Auth instance, because focus, online and a 401 arrive together all the time and are all asking the same question. A periodic ping would be a request per open tab for nothing; page load and the hourly refresh stay Firebase's own.
|
|
102
|
+
|
|
103
|
+
Web, desktop and extension get every bit of this from the client, with no framework code of their own. Web's page auth policy is what redirects on the resulting signed-out state ([docs/web/page-contract.md](../web/page-contract.md)).
|
|
104
|
+
|
|
105
|
+
### Click triggers (`modules/triggers.js`)
|
|
106
|
+
|
|
107
|
+
The ONE click-trigger registry every surface shares ([#16](https://github.com/Omega-JS-Stack/omega/issues/16)). A trigger is markup wiring — a class means "clicking this runs that action", with no per-page JS — and the client owns the single delegated `document` click listener behind all of them.
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
import { registerTrigger } from '@omega.js/client/modules/triggers.js';
|
|
111
|
+
|
|
112
|
+
registerTrigger('signout', async (event, element) => { /* ... */ });
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
- **The class is always `omega-<name>`** — `registerTrigger('signout', …)` answers `.omega-signout`. Callers never spell the class, so the naming can never drift (this replaced three conventions: `.auth-signout-btn`, `.auth-signin-btn`, `.uj-password-toggle`, with no aliases kept).
|
|
116
|
+
- **A click anywhere inside a trigger element counts** (`closest()`), which is what makes icon-only and label-wrapped buttons work. The INNERMOST trigger wins when triggers nest.
|
|
117
|
+
- **A trigger class means the framework owns the click**: the registry calls `preventDefault()` + `stopPropagation()` before the handler, so no default navigation and no page-level handler fires behind it.
|
|
118
|
+
- **Registration arms the listener**, so a surface may register before or after `omega.initialize()` — order never matters. Re-registering a name REPLACES the handler with a warning; it never stacks, so a double boot cannot double-fire.
|
|
119
|
+
- **Who registers what**: the client registers the GENERIC actions (`omega-signout` — confirm, sign out, notify — from `auth.setupEventListeners()`), and each surface registers its own. Today: @omega.js/extension registers `omega-signin` (opens the website's `/token` page in a tab) and `omega-account` (opens the website's `/account` page in a tab) from `setupAuthEventListeners()`; @omega.js/web registers `omega-password-toggle` (the password eye) from its global module.
|
|
120
|
+
- Transport-free and DOM-only like `motion` / `icon-renderer`: inert where there is no document (desktop main, the extension service worker).
|
|
121
|
+
|
|
122
|
+
Web's `data-shell-toggle` / `data-shell-dismiss` are NOT triggers — they are @omega.js/web's attribute-driven app-shell contract and stay there.
|
|
123
|
+
|
|
124
|
+
## File Conventions
|
|
125
|
+
|
|
126
|
+
- **CommonJS-friendly ES6+** in `src/`. `prepare-package` transpiles to ES5 in `dist/`.
|
|
127
|
+
- **`fs-jetpack`** over `fs` / `fs-extra` for any file operations in tests/scripts.
|
|
128
|
+
- **No TypeScript** — pure JavaScript library.
|
|
129
|
+
- **Template strings** — use backticks for string interpolation.
|
|
130
|
+
- **DO NOT modify `_legacy/`** — reference only, frozen for historical context.
|
|
131
|
+
- **No backwards compatibility** unless explicitly requested — just change to the new way.
|
|
132
|
+
- **Early-return / short-circuit** style throughout — see [docs/code-patterns.md](../docs/code-patterns.md) for the full code-pattern checklist (`$`-prefixed DOM vars, operators at start of continuation lines, Firestore path syntax, dynamic imports, config deep-merge, event delegation).
|
|
133
|
+
|
|
134
|
+
## Doc-update parity
|
|
135
|
+
|
|
136
|
+
Whenever you make a behavioral change (new module, new method, new pattern, removed feature), update:
|
|
137
|
+
|
|
138
|
+
1. **`README.md`** — user-facing summary
|
|
139
|
+
2. **`docs/client/index.md`** (this file) — architecture overview, one paragraph or cross-link
|
|
140
|
+
3. **`docs/<topic>.md`** — the meat. If a topic doesn't have a doc yet, create one.
|
|
141
|
+
4. **`CHANGELOG.md`** — if the project keeps one
|
|
142
|
+
|
|
143
|
+
Don't ship behavioral changes with stale docs. Validate first, then document — write docs that describe shipped reality, not intentions.
|
|
144
|
+
|
|
145
|
+
**The four framework guides are structurally MIRRORED** — this guide follows the library subset of that skeleton (the scaffolding frameworks [web](../web/index.md), [backend](../backend/index.md), [desktop](../desktop/index.md), and [extension](../extension/index.md) carry the full skeleton + a consumer template). Never add, rename, or reorder a section here without checking the sibling guides.
|
|
146
|
+
|
|
147
|
+
## Documentation
|
|
148
|
+
|
|
149
|
+
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.**
|
|
150
|
+
|
|
151
|
+
- [docs/architecture.md](../docs/architecture.md) — singleton pattern, directory structure, module dependency graph
|
|
152
|
+
- [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
|
|
153
|
+
- [docs/modules.md](../docs/modules.md) — full module quick reference (Storage, Auth + `resolveSubscription` + Settler Pattern, Bindings, Firestore, Notifications, ServiceWorker, Sentry, DOM, Utilities)
|
|
154
|
+
- [docs/bindings.md](../docs/bindings.md) — `data-omega-bind` deep reference: actions, comma syntax, condition operators, state paths, skeleton loaders, root-key update filtering
|
|
155
|
+
- [docs/build-system.md](../docs/build-system.md) — `prepare-package` ES5 transpile, build commands, package exports
|
|
156
|
+
- [docs/testing.md](../docs/testing.md) — Mocha test setup
|
|
157
|
+
- [docs/cdp-debugging.md](../docs/cdp-debugging.md) — driving a live browser (per-session isolated Chrome via the `chrome-devtools` MCP) to verify @omega.js/client inside a consuming site
|
|
158
|
+
- [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
|
|
159
|
+
- [docs/dependencies.md](../docs/dependencies.md) — dependencies table + important notes (no TypeScript, prefer fs-jetpack, no backwards-compat requirement, etc.)
|