@techninja/clearstack 0.3.17 → 0.3.20
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/docs/BUILD_LOG.md +11 -1
- package/docs/CONVENTIONS.md +43 -4
- package/docs/PLATFORM_STACKING.md +486 -0
- package/docs/STATE_AND_ROUTING.md +54 -49
- package/lib/check.js +13 -53
- package/lib/init.js +5 -0
- package/lib/package-gen.js +1 -0
- package/lib/platform-files.js +113 -0
- package/lib/platform.js +52 -0
- package/lib/spec-config.js +55 -0
- package/lib/spec-utils.js +5 -2
- package/lib/update.js +8 -0
- package/package.json +1 -1
- package/templates/fullstack/src/store/realtimeSync.js +4 -4
- package/templates/shared/.configs/eslint.config.js +1 -0
- package/templates/shared/.github/workflows/release.yml +53 -0
- package/templates/shared/docs/clearstack/CONVENTIONS.md +43 -4
- package/templates/shared/docs/clearstack/STATE_AND_ROUTING.md +54 -49
- package/templates/shared/scripts/release.js +81 -0
- package/templates/shared/docs/clearstack/BUILD_LOG.md +0 -349
package/docs/BUILD_LOG.md
CHANGED
|
@@ -204,6 +204,14 @@ These are the significant corrections:
|
|
|
204
204
|
- **Fix:** Cast params to `any` before accessing custom properties
|
|
205
205
|
- **Documented in:** JSDOC_TYPING.md → `list` Connector Params
|
|
206
206
|
|
|
207
|
+
### Array model prototype items persist as real data
|
|
208
|
+
|
|
209
|
+
- **Expected:** `items: [{ sku: '', quantity: 0 }]` only defines the schema
|
|
210
|
+
- **Actual:** The prototype item exists as a real entry in the array at runtime
|
|
211
|
+
- **Impact:** Cart showed a ghost item with empty sku and 0 quantity; Stripe rejected the 0-price line item
|
|
212
|
+
- **Fix:** Always filter array model data with `.filter(i => i.sku)` before use
|
|
213
|
+
- **Documented in:** STATE_AND_ROUTING.md → Store Array Properties
|
|
214
|
+
|
|
207
215
|
---
|
|
208
216
|
|
|
209
217
|
## Metrics
|
|
@@ -316,8 +324,10 @@ Five new hybrids gotchas were found and documented:
|
|
|
316
324
|
3. **Enumerable models need `@type {any}`** — tsc can't type `id: true`
|
|
317
325
|
4. **List store descriptors need 3 casts** — descriptor, ready(), and map()
|
|
318
326
|
5. **`list` connector params need cast** — `ModelIdentifier` not plain object
|
|
327
|
+
6. **Array prototype items persist as real data** — the prototype item
|
|
328
|
+
used to define the array shape is included in the actual data
|
|
319
329
|
|
|
320
|
-
All
|
|
330
|
+
All six are hybrids type system friction, not architectural issues. The
|
|
321
331
|
runtime behavior is correct — it's the JSDoc/tsc layer that struggles.
|
|
322
332
|
Each was fixed in under 2 minutes once identified.
|
|
323
333
|
|
package/docs/CONVENTIONS.md
CHANGED
|
@@ -197,6 +197,20 @@ function toggle(host) {
|
|
|
197
197
|
}
|
|
198
198
|
```
|
|
199
199
|
|
|
200
|
+
```javascript
|
|
201
|
+
// BAD — silent catch hides the failure completely
|
|
202
|
+
try {
|
|
203
|
+
store.clear([Model]);
|
|
204
|
+
} catch {
|
|
205
|
+
/* list may not exist */
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Never use empty `catch` blocks.** If you catch to prevent crashing,
|
|
210
|
+
you must `console.warn` or `console.error` so the failure is visible.
|
|
211
|
+
Silent catches turn bugs into ghosts — things "just don't work" with
|
|
212
|
+
zero console output to trace.
|
|
213
|
+
|
|
200
214
|
### ✅ Do
|
|
201
215
|
|
|
202
216
|
```javascript
|
|
@@ -215,6 +229,15 @@ function toggle(host) {
|
|
|
215
229
|
}
|
|
216
230
|
```
|
|
217
231
|
|
|
232
|
+
```javascript
|
|
233
|
+
// GOOD — catch to prevent crash, but log so failures are visible
|
|
234
|
+
try {
|
|
235
|
+
store.clear([Model]);
|
|
236
|
+
} catch (e) {
|
|
237
|
+
console.warn('[store] clear failed:', e.message);
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
218
241
|
---
|
|
219
242
|
|
|
220
243
|
### ✅ Always Do This
|
|
@@ -251,10 +274,24 @@ export const fullName = (user) => `${user.firstName} ${user.lastName}`;
|
|
|
251
274
|
|
|
252
275
|
---
|
|
253
276
|
|
|
254
|
-
## File Size:
|
|
277
|
+
## File Size: Why 150 Lines
|
|
278
|
+
|
|
279
|
+
The 150-line limit isn't about the number — it's about **context cost**.
|
|
280
|
+
A 400-line file isn't hard to scroll through, but it's expensive to
|
|
281
|
+
_hold in mind_. Humans can only reason about a limited scope at once.
|
|
282
|
+
LLMs face the same constraint differently: every token spent reading a
|
|
283
|
+
bloated file is a token not spent on the actual task. Small files mean
|
|
284
|
+
context is spent on _building_, not on _understanding what you're
|
|
285
|
+
looking at_.
|
|
286
|
+
|
|
287
|
+
When every file is small enough to comprehend in one pass, both humans
|
|
288
|
+
and LLMs can generate, review, and modify code without re-reading
|
|
289
|
+
unrelated sections. Refactors become safe because the blast radius of
|
|
290
|
+
any change is one small file. The limit forces decomposition into
|
|
291
|
+
concept-sized units — not arbitrary chunks, but files where each one
|
|
292
|
+
answers a single question.
|
|
255
293
|
|
|
256
|
-
|
|
257
|
-
light.** When a file passes 120 lines:
|
|
294
|
+
Treat **~120 lines as a yellow light.** When a file passes 120 lines:
|
|
258
295
|
|
|
259
296
|
1. Add a `// SPLIT CANDIDATE:` comment noting where a logical split could happen
|
|
260
297
|
2. Continue working — don't split mid-feature
|
|
@@ -270,7 +307,9 @@ function moveObj(o, dx, dy) { ... }
|
|
|
270
307
|
### When a File Exceeds 150 Lines
|
|
271
308
|
|
|
272
309
|
The **only correct response** is to split the file into two or more files.
|
|
273
|
-
|
|
310
|
+
The concepts have outgrown the container — find the seam between them
|
|
311
|
+
and give each its own file. Never do any of the following to reduce
|
|
312
|
+
line count:
|
|
274
313
|
|
|
275
314
|
- Remove or shorten JSDoc comments
|
|
276
315
|
- Collapse multi-line expressions onto one line
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
# Platform Stacking
|
|
2
|
+
|
|
3
|
+
## How Clearstack Projects Become Scaffoldable Platforms
|
|
4
|
+
|
|
5
|
+
> A Clearstack project can declare itself as a **platform** — a reusable
|
|
6
|
+
> foundation that scaffolds child projects with vendor files, config schemas,
|
|
7
|
+
> and override layers. This spec defines the contract.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## The Problem
|
|
12
|
+
|
|
13
|
+
Clearstack scaffolds vanilla projects. But some Clearstack projects are
|
|
14
|
+
themselves platforms — they provide components, store models, API handlers,
|
|
15
|
+
and build scripts that other projects consume and customize.
|
|
16
|
+
|
|
17
|
+
Without a stacking API, each platform reinvents its own CLI, its own
|
|
18
|
+
vendor sync, its own override conventions, and its own update-without-
|
|
19
|
+
clobbering logic. That's the same problem Clearstack already solved for
|
|
20
|
+
itself.
|
|
21
|
+
|
|
22
|
+
## The Stack
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
Clearstack (spec + CLI)
|
|
26
|
+
└── Platform (Clearstack project that declares itself scaffoldable)
|
|
27
|
+
└── Project (consumes the platform, overrides what it needs)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Concrete example:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Clearstack v0.3.17
|
|
34
|
+
└── StatiCart v1.x (e-commerce platform)
|
|
35
|
+
└── "My Coffee Shop" (store built on StatiCart)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Each layer owns different things and has different update rules.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 1. Platform Manifest
|
|
43
|
+
|
|
44
|
+
A Clearstack project becomes a platform by adding a `platform` key to its
|
|
45
|
+
`package.json`. This is the only requirement.
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"name": "@techninja/staticart",
|
|
50
|
+
"version": "1.0.0",
|
|
51
|
+
"clearstack": {
|
|
52
|
+
"platform": {
|
|
53
|
+
"prefix": "staticart",
|
|
54
|
+
"vendorDir": "src/vendor/staticart",
|
|
55
|
+
"configFile": "staticart.config.json",
|
|
56
|
+
"configSchema": "staticart.schema.json",
|
|
57
|
+
"templates": "templates/",
|
|
58
|
+
"vendor": "vendor/",
|
|
59
|
+
"docs": "docs/staticart/",
|
|
60
|
+
"scripts": "scripts/",
|
|
61
|
+
"api": "api/"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Manifest Fields
|
|
68
|
+
|
|
69
|
+
| Field | Required | Purpose |
|
|
70
|
+
| -------------- | -------- | ---------------------------------------------------------------- |
|
|
71
|
+
| `prefix` | Yes | Import map prefix (`#staticart/`). Must be unique per platform. |
|
|
72
|
+
| `vendorDir` | Yes | Where platform files land in the child project. Gitignored. |
|
|
73
|
+
| `configFile` | Yes | Project-level config file name. Never overwritten on update. |
|
|
74
|
+
| `configSchema` | No | JSON Schema for the config file. Used for validation. |
|
|
75
|
+
| `templates` | Yes | Directory in the npm package containing scaffold templates. |
|
|
76
|
+
| `vendor` | Yes | Directory in the npm package containing vendorable source files. |
|
|
77
|
+
| `docs` | No | Platform docs synced to child project on update. |
|
|
78
|
+
| `scripts` | No | Build/admin scripts copied on init, skipped on update. |
|
|
79
|
+
| `api` | No | API handler templates copied on init, skipped on update. |
|
|
80
|
+
|
|
81
|
+
### The `prefix` Contract
|
|
82
|
+
|
|
83
|
+
The platform prefix becomes an import map namespace in the child project.
|
|
84
|
+
It follows the same `#prefix/` convention Clearstack uses for `#store/`,
|
|
85
|
+
`#atoms/`, etc.
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<script type="importmap">
|
|
89
|
+
{
|
|
90
|
+
"imports": {
|
|
91
|
+
"#staticart/": "/vendor/staticart/",
|
|
92
|
+
"#store/": "/store/",
|
|
93
|
+
"#atoms/": "/components/atoms/"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
</script>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The child project can override any platform module by remapping a specific
|
|
100
|
+
path before the wildcard:
|
|
101
|
+
|
|
102
|
+
```html
|
|
103
|
+
<script type="importmap">
|
|
104
|
+
{
|
|
105
|
+
"imports": {
|
|
106
|
+
"#staticart/product-card": "/components/my-product-card.js",
|
|
107
|
+
"#staticart/": "/vendor/staticart/"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
</script>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Import map specificity rules (longer prefix wins) make this work natively.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 2. File Ownership Model
|
|
118
|
+
|
|
119
|
+
Every file in a stacked project belongs to exactly one layer. The layer
|
|
120
|
+
determines who creates it, who updates it, and who must never touch it.
|
|
121
|
+
|
|
122
|
+
### Ownership Table
|
|
123
|
+
|
|
124
|
+
| Owner | Creates | Updates | Examples |
|
|
125
|
+
| -------------- | ---------------------- | ----------------------------- | -------------------------------------------------------- |
|
|
126
|
+
| **Clearstack** | `init` | `update` (always) | `docs/clearstack/`, `.configs/` |
|
|
127
|
+
| **Platform** | `init` | `update` (vendor + docs only) | `src/vendor/<prefix>/`, `docs/<prefix>/` |
|
|
128
|
+
| **Project** | `init` (from template) | Never (project owns it) | `src/components/`, config file, `tokens.css`, data files |
|
|
129
|
+
|
|
130
|
+
### The Three Update Behaviors
|
|
131
|
+
|
|
132
|
+
**Always overwrite:** Spec docs and vendor files. These are the platform's
|
|
133
|
+
source of truth. The child project must not edit them directly.
|
|
134
|
+
|
|
135
|
+
- `docs/clearstack/*.md`
|
|
136
|
+
- `docs/<prefix>/*.md`
|
|
137
|
+
- `src/vendor/<prefix>/`
|
|
138
|
+
|
|
139
|
+
**Create once, never overwrite:** Templates that the project customizes.
|
|
140
|
+
On `update`, these are skipped unless `--force` is passed.
|
|
141
|
+
|
|
142
|
+
- `.configs/*`
|
|
143
|
+
- `scripts/*`
|
|
144
|
+
- `api/` handlers
|
|
145
|
+
- `src/index.html`
|
|
146
|
+
|
|
147
|
+
**Never touch:** Project-owned files. No init or update command writes
|
|
148
|
+
to these after initial creation.
|
|
149
|
+
|
|
150
|
+
- Config file (`staticart.config.json`)
|
|
151
|
+
- `src/styles/tokens.css`
|
|
152
|
+
- `src/data/`
|
|
153
|
+
- `src/locales/overrides*.json`
|
|
154
|
+
- `src/components/` (project overrides)
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 3. CLI Integration
|
|
159
|
+
|
|
160
|
+
The Clearstack CLI gains platform awareness. No new top-level commands —
|
|
161
|
+
platforms hook into the existing `init` and `update` flow.
|
|
162
|
+
|
|
163
|
+
### `clearstack init`
|
|
164
|
+
|
|
165
|
+
Current behavior (unchanged):
|
|
166
|
+
|
|
167
|
+
1. Scaffold Clearstack project structure
|
|
168
|
+
2. Create `.configs/`, `docs/clearstack/`, `scripts/`, `src/`
|
|
169
|
+
|
|
170
|
+
New behavior when a platform is detected in `devDependencies`: 3. Read the platform's manifest from its `package.json` 4. Copy `templates/` → project root (respecting ownership rules) 5. Vendor `vendor/` → `src/vendor/<prefix>/` 6. Copy `docs/` → `docs/<prefix>/` 7. Copy `scripts/` → `scripts/` (skip existing) 8. Copy `api/` → `api/` (skip existing) 9. Generate import map entries for `#<prefix>/` 10. Create config file from template (if not exists)
|
|
171
|
+
|
|
172
|
+
### `clearstack update`
|
|
173
|
+
|
|
174
|
+
Current behavior (unchanged):
|
|
175
|
+
|
|
176
|
+
1. Sync `docs/clearstack/` (always overwrite)
|
|
177
|
+
2. Sync `.configs/` (skip existing, `--force` to overwrite)
|
|
178
|
+
|
|
179
|
+
New behavior when a platform is detected: 3. Re-vendor `vendor/` → `src/vendor/<prefix>/` (always overwrite) 4. Sync `docs/<prefix>/` (always overwrite) 5. Skip everything else (config, templates, scripts, api)
|
|
180
|
+
|
|
181
|
+
### Platform CLI Passthrough
|
|
182
|
+
|
|
183
|
+
A platform can also provide its own CLI commands via a `bin` entry. The
|
|
184
|
+
Clearstack CLI doesn't need to know about these — they're standard npm
|
|
185
|
+
bin scripts.
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"bin": {
|
|
190
|
+
"staticart": "./bin/cli.js"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The platform CLI can call Clearstack's API programmatically for shared
|
|
196
|
+
operations (vendoring, doc sync) rather than reimplementing them.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 4. Vendor Sync
|
|
201
|
+
|
|
202
|
+
Platform vendor files are the equivalent of Clearstack's `src/vendor/hybrids/`
|
|
203
|
+
pattern — source files copied from `node_modules` into the project so the
|
|
204
|
+
browser can serve them directly.
|
|
205
|
+
|
|
206
|
+
### How It Works
|
|
207
|
+
|
|
208
|
+
The platform's `vendor/` directory in the npm package contains the source
|
|
209
|
+
files that child projects consume. On `init` and `update`, these are copied
|
|
210
|
+
to `src/vendor/<prefix>/`.
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
node_modules/@techninja/staticart/vendor/
|
|
214
|
+
├── components/
|
|
215
|
+
│ ├── atoms/
|
|
216
|
+
│ ├── molecules/
|
|
217
|
+
│ └── organisms/
|
|
218
|
+
├── store/
|
|
219
|
+
├── utils/
|
|
220
|
+
└── styles/
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Becomes:
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
src/vendor/staticart/
|
|
227
|
+
├── components/
|
|
228
|
+
├── store/
|
|
229
|
+
├── utils/
|
|
230
|
+
└── styles/
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Vendor Directory Rules
|
|
234
|
+
|
|
235
|
+
- Always gitignored. Regenerated from the installed package version.
|
|
236
|
+
- Always overwritten on `update`. The platform owns these files.
|
|
237
|
+
- The child project never edits files in `src/vendor/<prefix>/`.
|
|
238
|
+
- To customize a vendored component, override it via the import map.
|
|
239
|
+
|
|
240
|
+
### `postinstall` Hook
|
|
241
|
+
|
|
242
|
+
The platform should provide a setup script that runs on `npm install`,
|
|
243
|
+
similar to how Clearstack's `vendor-deps.js` works:
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
// In the platform's postinstall or the child project's setup.js
|
|
247
|
+
const PLATFORM_VENDOR = 'node_modules/@techninja/staticart/vendor';
|
|
248
|
+
const DEST = 'src/vendor/staticart';
|
|
249
|
+
cpSync(PLATFORM_VENDOR, DEST, { recursive: true });
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
This ensures vendor files stay in sync with the installed package version
|
|
253
|
+
without requiring a manual `clearstack update`.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 5. Override Layers
|
|
258
|
+
|
|
259
|
+
A stacked project has multiple override layers. Each layer can customize
|
|
260
|
+
the one below it without forking.
|
|
261
|
+
|
|
262
|
+
### Component Overrides (Import Map)
|
|
263
|
+
|
|
264
|
+
The child project replaces a platform component by remapping its import:
|
|
265
|
+
|
|
266
|
+
```html
|
|
267
|
+
<script type="importmap">
|
|
268
|
+
{
|
|
269
|
+
"imports": {
|
|
270
|
+
"#staticart/product-card": "/components/my-product-card.js",
|
|
271
|
+
"#staticart/": "/vendor/staticart/"
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
</script>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
The override component can:
|
|
278
|
+
|
|
279
|
+
- Replace the platform component entirely
|
|
280
|
+
- Import and wrap the original (decorator pattern)
|
|
281
|
+
- Import the original's helpers and compose differently
|
|
282
|
+
|
|
283
|
+
### Style Overrides (CSS Custom Properties)
|
|
284
|
+
|
|
285
|
+
The platform defines all visual properties as CSS custom properties in its
|
|
286
|
+
vendored `tokens.css`. The child project overrides them in its own
|
|
287
|
+
`tokens.css`, which loads after the platform's:
|
|
288
|
+
|
|
289
|
+
```css
|
|
290
|
+
/* src/styles/tokens.css — project overrides */
|
|
291
|
+
:root {
|
|
292
|
+
--color-primary: #8b4513; /* coffee brown, overrides platform blue */
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Config Overrides (Config File)
|
|
297
|
+
|
|
298
|
+
The platform reads its config file at runtime. The child project owns
|
|
299
|
+
this file entirely. The platform provides defaults for any missing keys.
|
|
300
|
+
|
|
301
|
+
### i18n Overrides (Locale Files)
|
|
302
|
+
|
|
303
|
+
Four-layer cascade, split by responsibility:
|
|
304
|
+
|
|
305
|
+
| Layer | Owner | File | Purpose |
|
|
306
|
+
| ------------------- | -------- | ------------------------------- | ------------------------ |
|
|
307
|
+
| 1. Defaults | Platform | Hardcoded in `i18n.js` | English UI chrome |
|
|
308
|
+
| 2. Locale | Platform | `locales/<lang>.json` | Translated UI chrome |
|
|
309
|
+
| 3. Overrides | Project | `locales/overrides.json` | English project terms |
|
|
310
|
+
| 4. Locale overrides | Project | `locales/overrides.<lang>.json` | Translated project terms |
|
|
311
|
+
|
|
312
|
+
The platform translates its own UI strings (buttons, labels, status text).
|
|
313
|
+
The project translates its own domain terms (category names, variant labels,
|
|
314
|
+
product descriptions). Neither layer needs to know about the other's keys.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## 6. Spec Check Composition
|
|
319
|
+
|
|
320
|
+
Clearstack's spec checks must work across the stack. The platform can
|
|
321
|
+
declare additional check requirements that compose with Clearstack's base
|
|
322
|
+
checks.
|
|
323
|
+
|
|
324
|
+
### What Composes Automatically
|
|
325
|
+
|
|
326
|
+
These Clearstack checks apply to all code regardless of layer:
|
|
327
|
+
|
|
328
|
+
- Line count limits (≤150 lines)
|
|
329
|
+
- Import map alias enforcement (no `../`)
|
|
330
|
+
- Prettier formatting
|
|
331
|
+
- ESLint rules
|
|
332
|
+
- Stylelint rules
|
|
333
|
+
- Security audit
|
|
334
|
+
|
|
335
|
+
### What the Platform Can Add
|
|
336
|
+
|
|
337
|
+
The platform manifest can declare additional `jsconfig.json` paths for
|
|
338
|
+
type checking:
|
|
339
|
+
|
|
340
|
+
```json
|
|
341
|
+
{
|
|
342
|
+
"clearstack": {
|
|
343
|
+
"platform": {
|
|
344
|
+
"tscDomains": ["api/jsconfig.json"]
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Clearstack's type checker auto-discovers `jsconfig.json` files, so this
|
|
351
|
+
usually works without explicit declaration. The manifest field exists for
|
|
352
|
+
edge cases where the platform needs type checking in non-standard locations.
|
|
353
|
+
|
|
354
|
+
### Vendor Files Are Excluded
|
|
355
|
+
|
|
356
|
+
Spec checks skip `src/vendor/` by default (already in `SPEC_IGNORE_DIRS`).
|
|
357
|
+
Platform vendor files are the platform's responsibility to keep compliant —
|
|
358
|
+
the child project doesn't lint them.
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## 7. Multi-Platform Stacking
|
|
363
|
+
|
|
364
|
+
A project can consume multiple platforms. Each gets its own prefix,
|
|
365
|
+
vendor directory, and config file.
|
|
366
|
+
|
|
367
|
+
```html
|
|
368
|
+
<script type="importmap">
|
|
369
|
+
{
|
|
370
|
+
"imports": {
|
|
371
|
+
"#staticart/": "/vendor/staticart/",
|
|
372
|
+
"#blogengine/": "/vendor/blogengine/",
|
|
373
|
+
"#store/": "/store/"
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
</script>
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Conflict Resolution
|
|
380
|
+
|
|
381
|
+
- Import map prefixes must be unique. Two platforms cannot use the same prefix.
|
|
382
|
+
- Config files must have different names.
|
|
383
|
+
- CSS custom properties use platform-prefixed names to avoid collisions:
|
|
384
|
+
`--staticart-color-primary`, `--blogengine-color-primary`.
|
|
385
|
+
- Shared dependencies (e.g. both platforms need hybrids) are vendored once
|
|
386
|
+
at the Clearstack level (`src/vendor/hybrids/`), not per-platform.
|
|
387
|
+
|
|
388
|
+
### Practical Limits
|
|
389
|
+
|
|
390
|
+
Multi-platform stacking is supported but not the common case. Most projects
|
|
391
|
+
use one platform. The architecture supports multiple platforms to avoid
|
|
392
|
+
painting into a corner, not because it's a recommended pattern.
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## 8. Build Pipeline Integration
|
|
397
|
+
|
|
398
|
+
Platforms often provide build scripts (e.g. StatiCart's `build-products.js`).
|
|
399
|
+
These integrate with the child project's build pipeline.
|
|
400
|
+
|
|
401
|
+
### Script Ownership
|
|
402
|
+
|
|
403
|
+
| Script | Copied on | Updated on | Owner |
|
|
404
|
+
| --------------------------- | ------------ | ---------- | --------------------------------- |
|
|
405
|
+
| `scripts/setup.js` | init | never | Project (may customize) |
|
|
406
|
+
| `scripts/vendor-deps.js` | init | never | Project (adds platform vendor) |
|
|
407
|
+
| `scripts/build-products.js` | init | never | Project (may customize) |
|
|
408
|
+
| Platform-internal scripts | never copied | n/a | Platform (runs from node_modules) |
|
|
409
|
+
|
|
410
|
+
The child project's `setup.js` (run on `postinstall`) should vendor both
|
|
411
|
+
Clearstack dependencies and platform files:
|
|
412
|
+
|
|
413
|
+
```javascript
|
|
414
|
+
// scripts/setup.js
|
|
415
|
+
await import('./vendor-deps.js'); // hybrids → src/vendor/hybrids/
|
|
416
|
+
await import('./vendor-platform.js'); // staticart → src/vendor/staticart/
|
|
417
|
+
await import('./build-icons.js'); // lucide → icons.json
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### CI/CD
|
|
421
|
+
|
|
422
|
+
The platform's GitHub Actions workflow template is copied on `init`. The
|
|
423
|
+
child project owns it and can customize. The platform documents what
|
|
424
|
+
environment variables and secrets are required.
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## 9. Version Compatibility
|
|
429
|
+
|
|
430
|
+
### Clearstack ↔ Platform
|
|
431
|
+
|
|
432
|
+
The platform declares its required Clearstack version as a `peerDependency`
|
|
433
|
+
(e.g. `"@techninja/clearstack": ">=0.3.17"`).
|
|
434
|
+
|
|
435
|
+
### Platform ↔ Project
|
|
436
|
+
|
|
437
|
+
The child project pins the platform version in `dependencies` or
|
|
438
|
+
`devDependencies`. `npm update` + `clearstack update` brings in new
|
|
439
|
+
vendor files. The project's config, overrides, and custom components
|
|
440
|
+
are untouched.
|
|
441
|
+
|
|
442
|
+
### Breaking Changes
|
|
443
|
+
|
|
444
|
+
When a platform makes a breaking change (new required config key, renamed
|
|
445
|
+
component, changed store model shape):
|
|
446
|
+
|
|
447
|
+
1. Platform bumps major version
|
|
448
|
+
2. Platform's `CHANGELOG.md` documents migration steps
|
|
449
|
+
3. `clearstack update` warns if the installed platform version has a
|
|
450
|
+
major bump since last update
|
|
451
|
+
4. `--force` is required to proceed with major version updates
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## 10. Example
|
|
456
|
+
|
|
457
|
+
See `docs/app-spec/` for project-specific platform examples (e.g.
|
|
458
|
+
StatiCart package structure, child project layout, i18n layer mapping).
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## Summary
|
|
463
|
+
|
|
464
|
+
| Concept | Mechanism |
|
|
465
|
+
| -------------------- | ------------------------------------------------------------------------------------------ |
|
|
466
|
+
| Platform declaration | `clearstack.platform` in `package.json` |
|
|
467
|
+
| Component override | Import map specificity (`#prefix/component` before `#prefix/`) |
|
|
468
|
+
| Style override | CSS custom properties in project `tokens.css` |
|
|
469
|
+
| Config override | Project-owned config file, platform provides defaults |
|
|
470
|
+
| i18n override | 4-layer cascade: platform defaults → locale → project overrides → project locale overrides |
|
|
471
|
+
| Vendor sync | `postinstall` + `clearstack update` copies platform source to `src/vendor/<prefix>/` |
|
|
472
|
+
| Spec checks | Clearstack checks compose automatically; vendor files excluded |
|
|
473
|
+
| Version management | semver + `peerDependencies` + `clearstack update` warnings |
|
|
474
|
+
|
|
475
|
+
### Design Principles
|
|
476
|
+
|
|
477
|
+
1. **Convention over configuration.** The import map prefix, vendor directory,
|
|
478
|
+
and override cascade all follow predictable patterns.
|
|
479
|
+
2. **Ownership is explicit.** Every file belongs to exactly one layer.
|
|
480
|
+
No ambiguity about who can edit what.
|
|
481
|
+
3. **Update without clobbering.** `clearstack update` never destroys
|
|
482
|
+
project customizations. Vendor files are regenerable. Config is sacred.
|
|
483
|
+
4. **Override without forking.** Import maps, CSS custom properties, and
|
|
484
|
+
i18n cascades let projects customize without modifying platform source.
|
|
485
|
+
5. **Spec checks compose.** A stacked project passes the same checks as
|
|
486
|
+
a vanilla Clearstack project. No special configuration needed.
|