@loadbare/app 0.7.4 → 0.8.1

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 (48) hide show
  1. package/dist/build/skills-cli.d.ts +12 -0
  2. package/dist/build/skills-cli.d.ts.map +1 -0
  3. package/dist/build/skills-cli.js +81 -0
  4. package/dist/build/skills-cli.js.map +1 -0
  5. package/dist/build/skills.d.ts +47 -0
  6. package/dist/build/skills.d.ts.map +1 -0
  7. package/dist/build/skills.js +124 -0
  8. package/dist/build/skills.js.map +1 -0
  9. package/dist/core/lb-constants.d.ts +1 -2
  10. package/dist/core/lb-constants.d.ts.map +1 -1
  11. package/dist/core/lb-constants.js +13 -12
  12. package/dist/core/lb-constants.js.map +1 -1
  13. package/dist/core/lb-types.d.ts +4 -10
  14. package/dist/core/lb-types.d.ts.map +1 -1
  15. package/dist/core/lb-types.js.map +1 -1
  16. package/dist/hub/lb-hub.browser.d.ts.map +1 -1
  17. package/dist/hub/lb-hub.browser.js +47 -24
  18. package/dist/hub/lb-hub.browser.js.map +1 -1
  19. package/dist/server/lb-express.d.ts.map +1 -1
  20. package/dist/server/lb-express.js +2 -7
  21. package/dist/server/lb-express.js.map +1 -1
  22. package/dist/server/lb-server.d.ts +8 -15
  23. package/dist/server/lb-server.d.ts.map +1 -1
  24. package/dist/server/lb-server.js +0 -3
  25. package/dist/server/lb-server.js.map +1 -1
  26. package/docs/TECHREF-1.0.md +21 -13
  27. package/docs/analysis-closed-set.md +16 -9
  28. package/docs/comparison.md +7 -6
  29. package/docs/reference/custom-elements.md +11 -6
  30. package/docs/reference/data-binding.md +36 -12
  31. package/docs/reference/page-files.md +13 -9
  32. package/docs/reference/widgets.md +4 -4
  33. package/docs/roadmap.md +1 -1
  34. package/docs/testing.md +5 -1
  35. package/docs/theory.md +1 -1
  36. package/docs/tutorials/080-widget-requests.md +9 -28
  37. package/package.json +8 -4
  38. package/skills/loadbare-app/SKILL.md +258 -0
  39. package/skills/loadbare-app/references/TECHREF-1.0.md +1189 -0
  40. package/skills/loadbare-app/references/builder.md +134 -0
  41. package/skills/loadbare-app/references/chrome.md +158 -0
  42. package/skills/loadbare-app/references/css.md +44 -0
  43. package/skills/loadbare-app/references/custom-elements.md +397 -0
  44. package/skills/loadbare-app/references/data-binding.md +457 -0
  45. package/skills/loadbare-app/references/overview.md +38 -0
  46. package/skills/loadbare-app/references/page-files.md +194 -0
  47. package/skills/loadbare-app/references/server.md +142 -0
  48. package/skills/loadbare-app/references/widgets.md +174 -0
@@ -0,0 +1,258 @@
1
+ ---
2
+ name: loadbare-app
3
+ description: Build server-bound web applications with Loadbare/app. Covers the file conventions the builder finds by name (`chrome.html`, `*.page.html`, `*.queries.ts`, `*.requests.ts`, `imports.ts`, `<tag>.html`, `<tag>.browser.ts`); the `lb-*` attribute vocabulary that binds HTML to server data and sends requests (`lb-list`, `lb-row`, `lb-cell`, `lb-key`, `lb-show`, `lb-action`); build-time widget expansion with `exp-*` parameters, `lb-slot` and `lb-template`; custom element code; the Express wiring with `hubRoutes`; and the `@loadbare/widgets` library. Use whenever a task involves `@loadbare/app`, `@loadbare/widgets`, `loadbare-app-build`, an `lb-` attribute, or a page, query, request or widget file in a Loadbare application. The model is not React, htmx or REST, and cannot be inferred from them.
4
+ license: Apache-2.0
5
+ metadata:
6
+ package: "@loadbare/app"
7
+ homepage: https://gitlab.com/kendowns/loadbare
8
+ ---
9
+
10
+ # Working with Loadbare/app
11
+
12
+ Loadbare/app builds a whole application into one HTML document, one client
13
+ script and one stylesheet. The server answers named queries with rows and
14
+ performs named requests; the browser lands those rows on elements that name
15
+ them. No component renders anything, and no page fetches anything.
16
+
17
+ The wire is relational. A name answers with one row or a set of rows, a
18
+ row holds cells, and a cell holds one value. Hold on to that: most wrong
19
+ designs come from sending a shape a relational answer cannot have.
20
+
21
+ ## Build every change before handing it over
22
+
23
+ `loadbare-app-build` is the checker. It expands every page and widget and
24
+ refuses what it cannot ship, naming the tag and the file:
25
+
26
+ ```bash
27
+ loadbare-app-build --src src --out dist
28
+ ```
29
+
30
+ It exits non-zero on the first failure and prints
31
+ `loadbare-app-build: <message>`. A clean run prints the files it wrote and
32
+ the number of custom elements it bundled.
33
+
34
+ Type-check the server side as well:
35
+
36
+ ```bash
37
+ tsc --noEmit
38
+ ```
39
+
40
+ `dist/pages.ts` imports page files with their `.ts` extensions, so the
41
+ application's `tsconfig.json` needs `allowImportingTsExtensions`.
42
+
43
+ **Write, build, fix, repeat until it is clean.** Then start the server:
44
+ `createHub` refuses a query that answers with the wrong shape and a page
45
+ that declares a reserved name, and those refusals only appear at run time.
46
+ Restart the server after adding or changing a `.queries.ts` or
47
+ `.requests.ts` file.
48
+
49
+ ## The shape of an application
50
+
51
+ The builder classifies files by name, never by directory:
52
+
53
+ ```
54
+ src/
55
+ chrome.html exactly one; the document every page lands in
56
+ imports.ts at most one; the widget packages to scan
57
+ 00-reset.css any .css anywhere, concatenated
58
+ pages/
59
+ index.page.html the page for /
60
+ members.page.html the page for /members
61
+ members.queries.ts what members displays
62
+ members.requests.ts what members may be asked to do
63
+ widgets/
64
+ note-card.html the markup <note-card> expands into
65
+ visit-count.browser.ts the class <visit-count> registers
66
+ server.ts
67
+ ```
68
+
69
+ The chrome carries `<lb-hub>` inside `<body>`, an empty `<main>` inside the
70
+ hub, and `<script src="/client.js" defer>`. Everything a user touches sits
71
+ inside `<lb-hub>`.
72
+
73
+ A page is an HTML fragment that lands in `<main>`:
74
+
75
+ ```html
76
+ <!-- src/pages/members.page.html -->
77
+ <p lb-row="dues">Collected this year: <span lb-cell="total"></span></p>
78
+
79
+ <section lb-list="roster">
80
+ <form lb-action="lb-row-insert">
81
+ <input lb-cell="name" />
82
+ <button type="submit">Add</button>
83
+ </form>
84
+ <ul>
85
+ <template lb-key="id">
86
+ <li>
87
+ <span lb-cell="name"></span>
88
+ <button lb-action="lb-row-delete">Remove</button>
89
+ </li>
90
+ </template>
91
+ </ul>
92
+ </section>
93
+ ```
94
+
95
+ ```ts
96
+ // src/pages/members.queries.ts
97
+ import { list, row, type Queries } from "@loadbare/app/server";
98
+
99
+ export const queries: Queries = {
100
+ dues: row((ctx) => ctx.db.duesTotal()),
101
+ roster: list((ctx) => ctx.db.members()),
102
+ };
103
+ ```
104
+
105
+ ```ts
106
+ // src/pages/members.requests.ts
107
+ import { patch, type Requests } from "@loadbare/app/server";
108
+
109
+ export const requests: Requests = {
110
+ crud: {
111
+ roster: {
112
+ rowInsert: {
113
+ run: async (ctx, { values }) => ({
114
+ roster: patch({ rows: [await ctx.db.addMember(values)] }),
115
+ }),
116
+ refresh: ["dues"],
117
+ },
118
+ rowDelete: {
119
+ run: async (ctx, { key }) => {
120
+ await ctx.db.removeMember(key);
121
+ return { roster: patch({ drop: [key] }) };
122
+ },
123
+ refresh: ["dues"],
124
+ },
125
+ },
126
+ },
127
+ };
128
+ ```
129
+
130
+ ## Where front-end knowledge misleads
131
+
132
+ Re-read this list when a build fails or a design will not fit. Each item is
133
+ a place a reasonable instinct from React, Vue, htmx or REST produces an
134
+ error or a dead end.
135
+
136
+ **There is no template language.** No `{#if}`, no `v-for`, no `map()`. A
137
+ list is an element carrying `lb-list` with a `<template lb-key="...">`
138
+ inside it, and the hub clones the template once per row. A condition is
139
+ `lb-show="<column>"`: write every possibility into the page and let a column
140
+ decide which is present. The column must be a boolean or null; the string
141
+ `"false"` counts as present.
142
+
143
+ **`{{placeholder}}` is build time only.** It reads an `exp-` attribute on
144
+ the tag, never data. Write it as an entire attribute value or an entire
145
+ text node. Name parameters in lowercase with hyphens: HTML lowercases
146
+ `exp-inputClass` before expansion sees it.
147
+
148
+ **Scope comes from ancestry, not props.** An `lb-cell` binds to the row on
149
+ its nearest ancestor carrying `lb-row` or a live list row. An element
150
+ outside every scope displays nothing. A value of `lb-cell` is a column name.
151
+
152
+ **One name, one cardinality.** Declare every query with `row()` or
153
+ `list()`. A page that needs the same data as a row and as a set declares
154
+ two queries.
155
+
156
+ **A cell never holds rows.** Master-detail is a row and a list under two
157
+ names. Many masters with their details is one list of joined rows, grouped
158
+ for display by a widget's `lbPlaceRow`. A list nested inside another list's
159
+ rows receives the same rows in every outer row; use it for a picker, never
160
+ for per-row detail.
161
+
162
+ **A URL names a page, never a resource.** Do not design `/accounts/42`. A
163
+ row is addressed by `list` and `key`, taken from where the element sits.
164
+ Queries take no arguments from the browser; which record a page shows is
165
+ server state reached through `ctx`.
166
+
167
+ **There are no endpoints to write.** `hubRoutes(hub, contextFor)` is the
168
+ whole data channel. Declare every action under `actions` and every
169
+ permitted operation under `crud`; anything undeclared is refused.
170
+
171
+ **All three CRUD operations are list operations.** Each needs a key, and a
172
+ key exists only on a live row inside `lb-list`. An `lb-row` scope is
173
+ read-only; give a writable single row a list that answers with one row.
174
+
175
+ **Write `rowUpdate` as a partial update.** A form sends every cell it
176
+ holds; a widget carrying `lb-cell` and `lb-action="lb-row-update"` sends its
177
+ one cell. Set the columns `values` names, leave the rest alone, and check
178
+ the names against the columns the page may edit.
179
+
180
+ **Put `lb-row-insert` and `lb-row-update` on a `<form>` or a button.** The
181
+ hub gathers the nearest `<form>`, `<tr>` or live row. Cells in a bare
182
+ `<div>` belong to no row and the request is refused. A native `<input>`
183
+ carrying `lb-row-update` is refused; commit one cell with a widget such as
184
+ `<lb-input>`. Inside a form, leave `lb-action` off the widgets.
185
+
186
+ **Return a patch when the change has a known extent.** `patch({ rows })`
187
+ for rows added or edited, `patch({ drop })` for keys removed, with
188
+ `refresh: []`. List a query in `refresh` only when its membership or order
189
+ changed in a way the operation cannot name.
190
+
191
+ **Format values in the query.** The hub does no type conversion. What a
192
+ number, date or null looks like is decided on the server.
193
+
194
+ **Checkboxes, radio buttons and file inputs are not bound.** They receive
195
+ no value and are not gathered. This is an open item, not a mistake in the
196
+ page.
197
+
198
+ **`lb-` belongs to Loadbare.** Invent no `lb-` attribute, and name no
199
+ query or action with the prefix. Import attribute names in widget code from
200
+ `@loadbare/app/constants`; never write them as string literals.
201
+
202
+ **Name a widget script `<tag>.browser.ts`.** A plain `<tag>.ts` stays on
203
+ the server and the tag goes unregistered.
204
+
205
+ **Light DOM, global CSS.** No shadow root, no scoping. Style empty lists
206
+ with `[lb-row-count="0"]`, pending requests with `[lb-pending]`, and failed
207
+ ones with `[lb-error]`.
208
+
209
+ **Host at the origin root.** The hub reaches its route by absolute path, so
210
+ a subpath such as `example.com/myapp/` does not work.
211
+
212
+ ## Widgets
213
+
214
+ A widget is `<tag>.html`, `<tag>.browser.ts`, or both, and a tag with
215
+ neither is a build error. The HTML is expanded at build time into the tag's
216
+ children; the class is an ordinary custom element with no base class.
217
+
218
+ Reach for a widget only when plain HTML cannot do the job. A list, a form
219
+ and a condition need none. A widget exists to wrap a control that decides
220
+ its own moment to send (`<lb-input>` on `change`), or to place and scaffold
221
+ rows (`lbPlaceRow`, `lbRowsLanded`).
222
+
223
+ Before writing one, check `@loadbare/widgets`: `lb-input`, `lb-select`,
224
+ `lb-options`, `lb-table`, `lb-picker`, `lb-unknown-page`. Install it and
225
+ list it in `src/imports.ts`:
226
+
227
+ ```ts
228
+ export default ["@loadbare/widgets"];
229
+ ```
230
+
231
+ The application's own definition of a tag overrides a package's.
232
+
233
+ ## Reference material
234
+
235
+ Read these when the summary above does not settle the question. They ship
236
+ with the package, so no network is needed.
237
+
238
+ - [`references/overview.md`](references/overview.md) — the map of the
239
+ reference, by part of the application.
240
+ - [`references/data-binding.md`](references/data-binding.md) — every `lb-`
241
+ attribute, requests, forms, conditions and request state. Start here for
242
+ anything in a page.
243
+ - [`references/page-files.md`](references/page-files.md) — queries,
244
+ `onPageEnter`, actions, CRUD, refresh and patch.
245
+ - [`references/custom-elements.md`](references/custom-elements.md) —
246
+ expansion, parameters, slots, destinations, and widget code.
247
+ - [`references/chrome.md`](references/chrome.md) — the chrome,
248
+ navigation and `lb-navigation`.
249
+ - [`references/server.md`](references/server.md) — the Express server and
250
+ the request context.
251
+ - [`references/builder.md`](references/builder.md) — the builder's options,
252
+ what it reads, and where it looks.
253
+ - [`references/css.md`](references/css.md) — how stylesheets are ordered.
254
+ - [`references/widgets.md`](references/widgets.md) — the basic widget
255
+ library.
256
+ - [`references/TECHREF-1.0.md`](references/TECHREF-1.0.md) — the reserved
257
+ names, and the open items that block 1.0. Read it before designing around
258
+ something the other references do not mention.