@techninja/clearstack 0.2.16 → 0.2.19

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.
Files changed (38) hide show
  1. package/docs/BACKEND_API_SPEC.md +85 -48
  2. package/docs/BUILD_LOG.md +42 -19
  3. package/docs/COMPONENT_PATTERNS.md +57 -51
  4. package/docs/CONVENTIONS.md +43 -31
  5. package/docs/FRONTEND_IMPLEMENTATION_RULES.md +57 -58
  6. package/docs/JSDOC_TYPING.md +1 -0
  7. package/docs/QUICKSTART.md +20 -18
  8. package/docs/SERVER_AND_DEPS.md +28 -29
  9. package/docs/STATE_AND_ROUTING.md +53 -52
  10. package/docs/TESTING.md +38 -37
  11. package/docs/app-spec/ENTITIES.md +16 -16
  12. package/docs/app-spec/README.md +4 -4
  13. package/lib/check.js +42 -77
  14. package/lib/package-gen.js +3 -0
  15. package/lib/spec-utils.js +109 -0
  16. package/package.json +5 -2
  17. package/templates/fullstack/data/seed.json +1 -1
  18. package/templates/shared/.configs/.markdownlint.jsonc +9 -0
  19. package/templates/shared/.configs/.stylelintrc.json +16 -0
  20. package/templates/shared/.configs/jsconfig.json +2 -9
  21. package/templates/shared/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  22. package/templates/shared/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
  23. package/templates/shared/.github/ISSUE_TEMPLATE/spec_correction.md +1 -1
  24. package/templates/shared/.github/pull_request_template.md +3 -0
  25. package/templates/shared/.github/workflows/spec.yml +3 -3
  26. package/templates/shared/docs/app-spec/README.md +8 -8
  27. package/templates/shared/docs/clearstack/BACKEND_API_SPEC.md +85 -48
  28. package/templates/shared/docs/clearstack/BUILD_LOG.md +42 -19
  29. package/templates/shared/docs/clearstack/COMPONENT_PATTERNS.md +57 -51
  30. package/templates/shared/docs/clearstack/CONVENTIONS.md +43 -31
  31. package/templates/shared/docs/clearstack/FRONTEND_IMPLEMENTATION_RULES.md +57 -58
  32. package/templates/shared/docs/clearstack/JSDOC_TYPING.md +1 -0
  33. package/templates/shared/docs/clearstack/QUICKSTART.md +20 -18
  34. package/templates/shared/docs/clearstack/SERVER_AND_DEPS.md +28 -29
  35. package/templates/shared/docs/clearstack/STATE_AND_ROUTING.md +53 -52
  36. package/templates/shared/docs/clearstack/TESTING.md +38 -37
  37. package/templates/shared/src/public/index.html +23 -23
  38. package/templates/shared/src/styles/shared.css +3 -3
@@ -1,4 +1,5 @@
1
1
  # Conventions
2
+
2
3
  ## Naming Rules & Anti-Patterns
3
4
 
4
5
  > Quick reference for naming and what to avoid.
@@ -13,37 +14,37 @@
13
14
 
14
15
  All custom element tags use **kebab-case** with an `app-` prefix:
15
16
 
16
- | Thing | Name | Tag |
17
- |---|---|---|
18
- | Button atom | `app-button` | `<app-button>` |
19
- | Header organism | `app-header` | `<app-header>` |
17
+ | Thing | Name | Tag |
18
+ | -------------------- | ------------- | --------------- |
19
+ | Button atom | `app-button` | `<app-button>` |
20
+ | Header organism | `app-header` | `<app-header>` |
20
21
  | Page layout template | `page-layout` | `<page-layout>` |
21
- | Home page view | `home-view` | `<home-view>` |
22
+ | Home page view | `home-view` | `<home-view>` |
22
23
 
23
24
  The `app-` prefix prevents collisions with native elements and third-party
24
25
  components. Page views and templates may drop the prefix when unambiguous.
25
26
 
26
27
  ### Files & Directories
27
28
 
28
- | Type | Convention | Example |
29
- |---|---|---|
30
- | Component file | Match tag name | `app-button.js` |
31
- | Component CSS | Match tag name | `app-button.css` |
32
- | Component dir | Match tag name | `app-button/` |
33
- | Re-export | Always `index.js` | `index.js` |
34
- | Store model | PascalCase | `UserModel.js` |
35
- | Utility function | camelCase | `formatDate.js` |
36
- | Shared CSS | Descriptive kebab | `tokens.css`, `reset.css` |
29
+ | Type | Convention | Example |
30
+ | ---------------- | ----------------- | ------------------------- |
31
+ | Component file | Match tag name | `app-button.js` |
32
+ | Component CSS | Match tag name | `app-button.css` |
33
+ | Component dir | Match tag name | `app-button/` |
34
+ | Re-export | Always `index.js` | `index.js` |
35
+ | Store model | PascalCase | `UserModel.js` |
36
+ | Utility function | camelCase | `formatDate.js` |
37
+ | Shared CSS | Descriptive kebab | `tokens.css`, `reset.css` |
37
38
 
38
39
  ### JavaScript
39
40
 
40
- | Type | Convention | Example |
41
- |---|---|---|
42
- | Event handlers | `handle` + action | `handleClick`, `handleSubmit` |
43
- | Store models | PascalCase noun | `UserModel`, `AppState` |
44
- | Utility functions | camelCase verb | `formatDate`, `parseQuery` |
45
- | Constants | UPPER_SNAKE | `MAX_RETRIES`, `API_BASE` |
46
- | JSDoc typedefs | PascalCase | `@typedef {Object} User` |
41
+ | Type | Convention | Example |
42
+ | ----------------- | ----------------- | ----------------------------- |
43
+ | Event handlers | `handle` + action | `handleClick`, `handleSubmit` |
44
+ | Store models | PascalCase noun | `UserModel`, `AppState` |
45
+ | Utility functions | camelCase verb | `formatDate`, `parseQuery` |
46
+ | Constants | UPPER_SNAKE | `MAX_RETRIES`, `API_BASE` |
47
+ | JSDoc typedefs | PascalCase | `@typedef {Object} User` |
47
48
 
48
49
  ---
49
50
 
@@ -52,12 +53,14 @@ components. Page views and templates may drop the prefix when unambiguous.
52
53
  ### ❌ Never Do This
53
54
 
54
55
  **DOM queries inside components:**
56
+
55
57
  ```javascript
56
58
  // BAD — breaks encapsulation, ignores shadow DOM
57
59
  const el = document.querySelector('.my-thing');
58
60
  ```
59
61
 
60
62
  **Manual event listeners:**
63
+
61
64
  ```javascript
62
65
  // BAD — leaks memory, bypasses hybrids lifecycle
63
66
  connectedCallback() {
@@ -66,18 +69,21 @@ connectedCallback() {
66
69
  ```
67
70
 
68
71
  **Global mutable state:**
72
+
69
73
  ```javascript
70
74
  // BAD — invisible dependencies, untraceable bugs
71
75
  window.appState = { user: null };
72
76
  ```
73
77
 
74
78
  **Imperative DOM manipulation:**
79
+
75
80
  ```javascript
76
81
  // BAD — fights the reactive render cycle
77
82
  host.shadowRoot.querySelector('span').textContent = 'updated';
78
83
  ```
79
84
 
80
85
  **Business logic in render:**
86
+
81
87
  ```javascript
82
88
  // BAD — render should be pure projection of state
83
89
  render: ({ items }) => html`
@@ -86,11 +92,13 @@ render: ({ items }) => html`
86
92
  ```
87
93
 
88
94
  **Files over 150 lines:**
95
+
89
96
  ```
90
97
  // BAD — extract to utils/ or split into sub-components
91
98
  ```
92
99
 
93
100
  **Deep nesting (>3 component levels):**
101
+
94
102
  ```
95
103
  // BAD — flatten by composing at the page level
96
104
  <app-layout>
@@ -109,14 +117,14 @@ let everything else propagate.
109
117
 
110
118
  ### Boundary Rules
111
119
 
112
- | Layer | Responsibility | Example |
113
- |---|---|---|
114
- | **Utils** | Never catch. Return error values or throw. Caller decides. | `formatDate(null)` returns `''` |
115
- | **Store connectors** | Let fetch failures propagate. Hybrids' `store.error()` catches them. | Don't wrap fetch in try/catch |
116
- | **Components** | Display `store.pending()` / `store.error()` states. Never try/catch in render. | `${store.error(model) && html`<div class="error-message">...</div>`}` |
117
- | **Event handlers** | Guard with `store.ready()` before accessing store properties. | `if (!store.ready(host.state)) return;` |
118
- | **Server routes** | Return HTTP status + JSON error body. Never crash the process. | `res.status(404).json({ error: 'Not found' })` |
119
- | **Server infra** | Handle process-level errors with clear messages and exit codes. | Port conflict → log message → `process.exit(1)` |
120
+ | Layer | Responsibility | Example |
121
+ | -------------------- | ------------------------------------------------------------------------------ | --------------------------------------------------------------------- |
122
+ | **Utils** | Never catch. Return error values or throw. Caller decides. | `formatDate(null)` returns `''` |
123
+ | **Store connectors** | Let fetch failures propagate. Hybrids' `store.error()` catches them. | Don't wrap fetch in try/catch |
124
+ | **Components** | Display `store.pending()` / `store.error()` states. Never try/catch in render. | `${store.error(model) && html`<div class="error-message">...</div>`}` |
125
+ | **Event handlers** | Guard with `store.ready()` before accessing store properties. | `if (!store.ready(host.state)) return;` |
126
+ | **Server routes** | Return HTTP status + JSON error body. Never crash the process. | `res.status(404).json({ error: 'Not found' })` |
127
+ | **Server infra** | Handle process-level errors with clear messages and exit codes. | Port conflict → log message → `process.exit(1)` |
120
128
 
121
129
  ### Why This Matters
122
130
 
@@ -141,7 +149,7 @@ next layer up to handle what it can't.
141
149
  // BAD — accesses store properties without ready guard
142
150
  function toggle(host) {
143
151
  const next = host.state.theme === 'light' ? 'dark' : 'light';
144
- store.set(host.state, { theme: next }); // crashes if model is in error state
152
+ store.set(host.state, { theme: next }); // crashes if model is in error state
145
153
  }
146
154
  ```
147
155
 
@@ -168,16 +176,19 @@ function toggle(host) {
168
176
  ### ✅ Always Do This
169
177
 
170
178
  **Declarative event binding:**
179
+
171
180
  ```javascript
172
- html`<button onclick="${handleClick}">Go</button>`
181
+ html`<button onclick="${handleClick}">Go</button>`;
173
182
  ```
174
183
 
175
184
  **Store for shared state:**
185
+
176
186
  ```javascript
177
187
  state: store(AppState),
178
188
  ```
179
189
 
180
190
  **Pure functions for logic:**
191
+
181
192
  ```javascript
182
193
  // In src/utils/filterActive.js
183
194
  export const filterActive = (items) => items.filter(i => i.active);
@@ -188,6 +199,7 @@ render: ({ items }) => html`<ul>${filterActive(items).map(...)}</ul>`,
188
199
  ```
189
200
 
190
201
  **JSDoc on all exports:**
202
+
191
203
  ```javascript
192
204
  /** @param {User} user */
193
205
  export const fullName = (user) => `${user.firstName} ${user.lastName}`;
@@ -1,4 +1,5 @@
1
1
  # Frontend Implementation Rules
2
+
2
3
  ## Hybrids.js "No-Build" Web Component Specification
3
4
 
4
5
  > A concise, LLM-and-human-friendly specification for building web applications
@@ -17,15 +18,15 @@
17
18
 
18
19
  **Sub-specifications:**
19
20
 
20
- | Document | Covers |
21
- |---|---|
22
- | [COMPONENT_PATTERNS.md](./COMPONENT_PATTERNS.md) | Authoring, light DOM, styling, layout engine, file size rules |
23
- | [JSDOC_TYPING.md](./JSDOC_TYPING.md) | JSDoc typing strategy, tsc validation, component/model/handler patterns |
24
- | [STATE_AND_ROUTING.md](./STATE_AND_ROUTING.md) | Store, routing, unified app state, realtime sync |
25
- | [CONVENTIONS.md](./CONVENTIONS.md) | Naming conventions, anti-patterns |
26
- | [SERVER_AND_DEPS.md](./SERVER_AND_DEPS.md) | Express server, import maps, vendor dependency loading |
27
- | [BACKEND_API_SPEC.md](./BACKEND_API_SPEC.md) | REST endpoints, JSON Schema via HEAD, entity CRUD, realtime sync |
28
- | [TESTING.md](./TESTING.md) | Testing philosophy, tools, patterns, build-phase checkpoints |
21
+ | Document | Covers |
22
+ | ------------------------------------------------ | ----------------------------------------------------------------------- |
23
+ | [COMPONENT_PATTERNS.md](./COMPONENT_PATTERNS.md) | Authoring, light DOM, styling, layout engine, file size rules |
24
+ | [JSDOC_TYPING.md](./JSDOC_TYPING.md) | JSDoc typing strategy, tsc validation, component/model/handler patterns |
25
+ | [STATE_AND_ROUTING.md](./STATE_AND_ROUTING.md) | Store, routing, unified app state, realtime sync |
26
+ | [CONVENTIONS.md](./CONVENTIONS.md) | Naming conventions, anti-patterns |
27
+ | [SERVER_AND_DEPS.md](./SERVER_AND_DEPS.md) | Express server, import maps, vendor dependency loading |
28
+ | [BACKEND_API_SPEC.md](./BACKEND_API_SPEC.md) | REST endpoints, JSON Schema via HEAD, entity CRUD, realtime sync |
29
+ | [TESTING.md](./TESTING.md) | Testing philosophy, tools, patterns, build-phase checkpoints |
29
30
 
30
31
  ---
31
32
 
@@ -36,16 +37,16 @@ no transpiler, no compile step. Code runs exactly as written.
36
37
 
37
38
  ### Core Principles
38
39
 
39
- | Principle | Rule |
40
- |---|---|
41
- | No build tools | No Webpack, Vite, Rollup, esbuild, or Babel |
42
- | ES modules only | All `.js` files are native ES modules served to the browser |
43
- | Import maps | Bare specifiers (e.g. `"hybrids"`) resolved via `<script type="importmap">` |
44
- | Small files | Every file ≤ **150 lines** before extracting shared logic |
45
- | Explicit over implicit | Name things clearly; avoid magic strings and hidden conventions |
46
- | Readable over clever | Optimize for comprehension by humans and LLMs alike |
47
- | Declarative over imperative | Use framework patterns, not raw DOM manipulation |
48
- | Composition over inheritance | Build complex UIs by composing small components |
40
+ | Principle | Rule |
41
+ | ---------------------------- | --------------------------------------------------------------------------- |
42
+ | No build tools | No Webpack, Vite, Rollup, esbuild, or Babel |
43
+ | ES modules only | All `.js` files are native ES modules served to the browser |
44
+ | Import maps | Bare specifiers (e.g. `"hybrids"`) resolved via `<script type="importmap">` |
45
+ | Small files | Every file ≤ **150 lines** before extracting shared logic |
46
+ | Explicit over implicit | Name things clearly; avoid magic strings and hidden conventions |
47
+ | Readable over clever | Optimize for comprehension by humans and LLMs alike |
48
+ | Declarative over imperative | Use framework patterns, not raw DOM manipulation |
49
+ | Composition over inheritance | Build complex UIs by composing small components |
49
50
 
50
51
  ### What This Means in Practice
51
52
 
@@ -72,15 +73,15 @@ web component framework built on plain objects and pure functions.
72
73
 
73
74
  ### Why Hybrids
74
75
 
75
- | Need | Hybrids Provides |
76
- |---|---|
77
- | Components | `define()` — plain object definitions, no classes |
78
- | Templating | `html``` — tagged template literals with reactive bindings |
79
- | State | `store()` — global state with async storage, caching, relations |
80
- | Routing | `router()` — view-graph-based routing with guards and dialogs |
81
- | Layout | `layout=""` attribute — CSS layout engine in templates |
82
- | Localization | `localize()` — automatic template translation |
83
- | ES modules | Ships as raw ES modules in `src/` — no build needed |
76
+ | Need | Hybrids Provides |
77
+ | ------------ | --------------------------------------------------------------- |
78
+ | Components | `define()` — plain object definitions, no classes |
79
+ | Templating | `html``` — tagged template literals with reactive bindings |
80
+ | State | `store()` — global state with async storage, caching, relations |
81
+ | Routing | `router()` — view-graph-based routing with guards and dialogs |
82
+ | Layout | `layout=""` attribute — CSS layout engine in templates |
83
+ | Localization | `localize()` — automatic template translation |
84
+ | ES modules | Ships as raw ES modules in `src/` — no build needed |
84
85
 
85
86
  ### API Surface (v9.1)
86
87
 
@@ -88,27 +89,27 @@ These are the only imports you need:
88
89
 
89
90
  ```javascript
90
91
  import {
91
- define, // Register a component
92
- html, // Template tagged literal
93
- store, // State management
94
- router, // Routing
95
- mount, // Mount component on existing element
96
- parent, // Access parent component
97
- children, // Access child components
98
- dispatch, // Dispatch custom events
99
- msg, // Localization messages
100
- localize, // Register translations
92
+ define, // Register a component
93
+ html, // Template tagged literal
94
+ store, // State management
95
+ router, // Routing
96
+ mount, // Mount component on existing element
97
+ parent, // Access parent component
98
+ children, // Access child components
99
+ dispatch, // Dispatch custom events
100
+ msg, // Localization messages
101
+ localize, // Register translations
101
102
  } from 'hybrids';
102
103
  ```
103
104
 
104
105
  ### Why Not Alternatives
105
106
 
106
- | Alternative | Reason to pass |
107
- |---|---|
108
- | **Lit** | Class-based, heavier API surface, decorators encourage build tools |
109
- | **Stencil** | Requires a compiler — violates no-build constraint |
110
- | **Vanilla** | No state management, no templating — too much boilerplate |
111
- | **React/Vue/Svelte** | Require build steps, not native web components |
107
+ | Alternative | Reason to pass |
108
+ | -------------------- | ------------------------------------------------------------------ |
109
+ | **Lit** | Class-based, heavier API surface, decorators encourage build tools |
110
+ | **Stencil** | Requires a compiler — violates no-build constraint |
111
+ | **Vanilla** | No state management, no templating — too much boilerplate |
112
+ | **React/Vue/Svelte** | Require build steps, not native web components |
112
113
 
113
114
  ---
114
115
 
@@ -185,12 +186,12 @@ import direction: **higher tiers import from lower tiers, never the reverse.**
185
186
 
186
187
  ### Tiers
187
188
 
188
- | Tier | Location | Scope | Examples |
189
- |---|---|---|---|
190
- | **Atom** | `components/atoms/` | Single-purpose UI primitive. One element, one job. | `app-button`, `app-icon`, `app-input` |
191
- | **Molecule** | `components/molecules/` | Small composition of 2–4 atoms that form a reusable unit. | `nav-link`, `search-bar`, `form-field` |
189
+ | Tier | Location | Scope | Examples |
190
+ | ------------ | ----------------------- | ------------------------------------------------------------------ | --------------------------------------- |
191
+ | **Atom** | `components/atoms/` | Single-purpose UI primitive. One element, one job. | `app-button`, `app-icon`, `app-input` |
192
+ | **Molecule** | `components/molecules/` | Small composition of 2–4 atoms that form a reusable unit. | `nav-link`, `search-bar`, `form-field` |
192
193
  | **Organism** | `components/organisms/` | Complex UI section. May contain molecules, atoms, and local state. | `app-header`, `app-footer`, `user-card` |
193
- | **Template** | `components/templates/` | Page-level layout shell. Defines slot regions, no business logic. | `page-layout`, `dashboard-layout` |
194
+ | **Template** | `components/templates/` | Page-level layout shell. Defines slot regions, no business logic. | `page-layout`, `dashboard-layout` |
194
195
 
195
196
  **Pages** (`src/pages/`) sit outside the component hierarchy. They are
196
197
  route-bound views that compose templates and organisms.
@@ -214,13 +215,13 @@ Pages → Templates → Organisms → Molecules → Atoms
214
215
 
215
216
  Use this checklist to decide if a component belongs at a higher tier:
216
217
 
217
- | Signal | Action |
218
- |---|---|
219
- | It renders a single HTML element with props | Keep as **atom** |
220
- | It composes 2–4 atoms into a reusable group | Make it a **molecule** |
221
- | It has its own local state or fetches data | Promote to **organism** |
222
- | It defines layout regions via slots, no logic | Make it a **template** |
223
- | It's bound to a route and composes a full page | Put it in **pages/** |
218
+ | Signal | Action |
219
+ | ---------------------------------------------- | ----------------------- |
220
+ | It renders a single HTML element with props | Keep as **atom** |
221
+ | It composes 2–4 atoms into a reusable group | Make it a **molecule** |
222
+ | It has its own local state or fetches data | Promote to **organism** |
223
+ | It defines layout regions via slots, no logic | Make it a **template** |
224
+ | It's bound to a route and composes a full page | Put it in **pages/** |
224
225
 
225
226
  ### File Anatomy (All Tiers)
226
227
 
@@ -235,5 +236,3 @@ app-button/
235
236
 
236
237
  If a component needs helpers that push it past 150 lines, extract them to
237
238
  `src/utils/` — not into sibling files within the component directory.
238
-
239
-
@@ -1,4 +1,5 @@
1
1
  # JSDoc Typing Strategy
2
+
2
3
  ## Type Safety Without TypeScript
3
4
 
4
5
  > JSDoc annotations provide editor intellisense, LLM comprehension, and
@@ -28,12 +28,12 @@ npx clearstack init -y # non-interactive (defaults)
28
28
 
29
29
  The interactive prompt asks for:
30
30
 
31
- | Prompt | Default | Notes |
32
- |---|---|---|
33
- | Project name | current directory name | Used in package.json and templates |
34
- | Description | `A Clearstack project` | Goes into package.json |
35
- | Mode | — | **Fullstack**: Express + WebSocket + JSON DB + SSE. **Static**: localStorage only |
36
- | Port | `3000` | Fullstack only. Set in `.env` |
31
+ | Prompt | Default | Notes |
32
+ | ------------ | ---------------------- | --------------------------------------------------------------------------------- |
33
+ | Project name | current directory name | Used in package.json and templates |
34
+ | Description | `A Clearstack project` | Goes into package.json |
35
+ | Mode | — | **Fullstack**: Express + WebSocket + JSON DB + SSE. **Static**: localStorage only |
36
+ | Port | `3000` | Fullstack only. Set in `.env` |
37
37
 
38
38
  If a `package.json` already exists, Clearstack merges into it — your existing fields (`author`, `license`, `engines`, `keywords`, etc.) are preserved.
39
39
 
@@ -120,10 +120,12 @@ git diff docs/ .configs/ # review what changed
120
120
  ```
121
121
 
122
122
  This updates:
123
+
123
124
  - `docs/clearstack/*.md` — spec documentation
124
125
  - `.configs/*` — linter, formatter, type checker, test runner configs
125
126
 
126
127
  This never touches:
128
+
127
129
  - `docs/app-spec/` — your project specs
128
130
  - `src/` — your code
129
131
  - `scripts/` — your build scripts
@@ -163,15 +165,15 @@ spec:code → spec:docs → lint → format → typecheck → test
163
165
 
164
166
  ## Summary
165
167
 
166
- | Task | Command |
167
- |---|---|
168
- | Install Clearstack | `npm install -D @techninja/clearstack` |
169
- | Scaffold a project | `npx clearstack init` |
170
- | Install dependencies | `npm install` |
171
- | Start dev server | `npm run dev` / `npx serve public` |
172
- | Lint + format | `npm run lint:fix && npm run format` |
173
- | Type check | `npm run typecheck` |
174
- | Run tests | `npm test` |
175
- | Full spec check | `npm run spec` |
176
- | Update spec + configs | `npm run spec:update` |
177
- | Review spec changes | `git diff docs/ .configs/` |
168
+ | Task | Command |
169
+ | --------------------- | -------------------------------------- |
170
+ | Install Clearstack | `npm install -D @techninja/clearstack` |
171
+ | Scaffold a project | `npx clearstack init` |
172
+ | Install dependencies | `npm install` |
173
+ | Start dev server | `npm run dev` / `npx serve public` |
174
+ | Lint + format | `npm run lint:fix && npm run format` |
175
+ | Type check | `npm run typecheck` |
176
+ | Run tests | `npm test` |
177
+ | Full spec check | `npm run spec` |
178
+ | Update spec + configs | `npm run spec:update` |
179
+ | Review spec changes | `git diff docs/ .configs/` |
@@ -1,4 +1,5 @@
1
1
  # Server & Dependencies
2
+
2
3
  ## Express Server, Import Maps & Vendor Loading
3
4
 
4
5
  > How the backend serves the frontend and how dependencies are resolved
@@ -13,13 +14,13 @@
13
14
 
14
15
  ### Responsibilities
15
16
 
16
- | Route | Serves |
17
- |---|---|
18
- | `/` | `public/index.html` (app shell) |
19
- | `/vendor/*` | `public/vendor/` (vendored ES modules) |
20
- | `/src/*` | `src/` (application source, as-is) |
21
- | `/api/*` | REST endpoints (see BACKEND_API_SPEC) |
22
- | `/api/events` | SSE stream for realtime sync |
17
+ | Route | Serves |
18
+ | ------------- | -------------------------------------- |
19
+ | `/` | `public/index.html` (app shell) |
20
+ | `/vendor/*` | `public/vendor/` (vendored ES modules) |
21
+ | `/src/*` | `src/` (application source, as-is) |
22
+ | `/api/*` | REST endpoints (see BACKEND_API_SPEC) |
23
+ | `/api/events` | SSE stream for realtime sync |
23
24
 
24
25
  ### Key Rules
25
26
 
@@ -65,9 +66,7 @@ import { cpSync, mkdirSync } from 'node:fs';
65
66
  import { resolve } from 'node:path';
66
67
 
67
68
  const VENDOR_DIR = resolve('public/vendor');
68
- const DEPS = [
69
- { name: 'hybrids', src: 'node_modules/hybrids/src' },
70
- ];
69
+ const DEPS = [{ name: 'hybrids', src: 'node_modules/hybrids/src' }];
71
70
 
72
71
  mkdirSync(VENDOR_DIR, { recursive: true });
73
72
 
@@ -112,25 +111,25 @@ declared in `public/index.html`.
112
111
  ```html
113
112
  <!DOCTYPE html>
114
113
  <html lang="en">
115
- <head>
116
- <meta charset="UTF-8">
117
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
118
- <title>App</title>
119
- <link rel="stylesheet" href="/src/styles/reset.css">
120
- <link rel="stylesheet" href="/src/styles/tokens.css">
121
-
122
- <script type="importmap">
123
- {
124
- "imports": {
125
- "hybrids": "/vendor/hybrids/index.js"
126
- }
127
- }
128
- </script>
129
- </head>
130
- <body>
131
- <app-router></app-router>
132
- <script type="module" src="/src/router/index.js"></script>
133
- </body>
114
+ <head>
115
+ <meta charset="UTF-8" />
116
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
117
+ <title>App</title>
118
+ <link rel="stylesheet" href="/src/styles/reset.css" />
119
+ <link rel="stylesheet" href="/src/styles/tokens.css" />
120
+
121
+ <script type="importmap">
122
+ {
123
+ "imports": {
124
+ "hybrids": "/vendor/hybrids/index.js"
125
+ }
126
+ }
127
+ </script>
128
+ </head>
129
+ <body>
130
+ <app-router></app-router>
131
+ <script type="module" src="/src/router/index.js"></script>
132
+ </body>
134
133
  </html>
135
134
  ```
136
135