@loadbare/app 0.8.2 → 0.10.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/README.md +3 -3
- package/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +74 -66
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/expand.d.ts.map +1 -1
- package/dist/build/expand.js +20 -19
- package/dist/build/expand.js.map +1 -1
- package/dist/build/locations.d.ts +2 -3
- package/dist/build/locations.d.ts.map +1 -1
- package/dist/build/locations.js +2 -3
- package/dist/build/locations.js.map +1 -1
- package/dist/build/pages.d.ts +3 -4
- package/dist/build/pages.d.ts.map +1 -1
- package/dist/build/pages.js +3 -4
- package/dist/build/pages.js.map +1 -1
- package/dist/core/lb-constants.d.ts +25 -23
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +95 -158
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/core/lb-types.d.ts +73 -75
- package/dist/core/lb-types.d.ts.map +1 -1
- package/dist/core/lb-types.js +58 -5
- package/dist/core/lb-types.js.map +1 -1
- package/dist/hub/lb-apply.d.ts +47 -37
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +174 -193
- package/dist/hub/lb-apply.js.map +1 -1
- package/dist/hub/lb-hub.browser.d.ts +1 -1
- package/dist/hub/lb-hub.browser.d.ts.map +1 -1
- package/dist/hub/lb-hub.browser.js +419 -415
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/dist/server/lb-express.d.ts +20 -13
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-express.js +50 -52
- package/dist/server/lb-express.js.map +1 -1
- package/dist/server/lb-server.d.ts +81 -116
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/server/lb-server.js +151 -48
- package/dist/server/lb-server.js.map +1 -1
- package/docs/TECHREF-1.0.md +893 -558
- package/docs/comparison.md +222 -185
- package/docs/prior-art.md +15 -14
- package/docs/reference/builder.md +9 -3
- package/docs/reference/chrome.md +107 -56
- package/docs/reference/custom-elements.md +199 -173
- package/docs/reference/data-binding.md +375 -370
- package/docs/reference/overview.md +12 -10
- package/docs/reference/page-files.md +161 -86
- package/docs/reference/server.md +13 -7
- package/docs/reference/widgets.md +104 -110
- package/docs/roadmap.md +36 -31
- package/docs/terms-of-art.md +57 -0
- package/docs/testing.md +97 -68
- package/docs/theory.md +92 -58
- package/docs/tutorials/010-pages-and-navigation.md +20 -12
- package/docs/tutorials/020-css.md +6 -3
- package/docs/tutorials/030-html-decomposition.md +9 -7
- package/docs/tutorials/040-displaying-data.md +30 -13
- package/docs/tutorials/{050-actions.md → 050-requests.md} +25 -15
- package/docs/tutorials/060-custom-element-code.md +17 -16
- package/docs/tutorials/065-conditional-rendering.md +34 -23
- package/docs/tutorials/070-displaying-a-list.md +29 -21
- package/docs/tutorials/072-inserting-into-a-list.md +24 -16
- package/docs/tutorials/074-deleting-from-a-list.md +9 -7
- package/docs/tutorials/076-updating-a-list-item.md +11 -10
- package/docs/tutorials/080-widget-requests.md +71 -43
- package/docs/tutorials/090-using-widget-libraries.md +22 -22
- package/package.json +1 -1
- package/skills/loadbare-app/SKILL.md +178 -111
- package/skills/loadbare-app/references/TECHREF-1.0.md +893 -558
- package/skills/loadbare-app/references/builder.md +9 -3
- package/skills/loadbare-app/references/chrome.md +107 -56
- package/skills/loadbare-app/references/custom-elements.md +199 -173
- package/skills/loadbare-app/references/data-binding.md +375 -370
- package/skills/loadbare-app/references/overview.md +12 -10
- package/skills/loadbare-app/references/page-files.md +161 -86
- package/skills/loadbare-app/references/server.md +13 -7
- package/skills/loadbare-app/references/widgets.md +104 -110
- package/docs/analysis-accidental-complexity.md +0 -149
- package/docs/analysis-closed-set.md +0 -210
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This reference is organized into four groups that reflect how an application is
|
|
4
4
|
put together: the shell it lives in, the build that assembles it, the pages it
|
|
5
|
-
serves, and the
|
|
5
|
+
serves, and the custom elements those pages are made of.
|
|
6
6
|
|
|
7
7
|
## The application shell
|
|
8
8
|
|
|
@@ -24,15 +24,17 @@ serves, and the widgets those pages are made of.
|
|
|
24
24
|
|
|
25
25
|
| Topic | Description |
|
|
26
26
|
|---------------------------------------------------------|--------------------------------|
|
|
27
|
-
| [`<
|
|
28
|
-
| [`<
|
|
29
|
-
| [`<
|
|
27
|
+
| [`<stub>.page.html`](./page-files.md#html) | The page's HTML |
|
|
28
|
+
| [`<stub>.queries.ts`](./page-files.md#queries) | The queries the page shows |
|
|
29
|
+
| [`<stub>.requests.ts`](./page-files.md#requests) | The page's request handlers |
|
|
30
30
|
| [Data Binding](./data-binding.md) | Connecting HTML to server data |
|
|
31
|
+
| [The URL](./chrome.md#the-url) | Pages, links and query parms |
|
|
31
32
|
|
|
32
|
-
##
|
|
33
|
+
## Custom elements
|
|
33
34
|
|
|
34
|
-
| Topic
|
|
35
|
-
|
|
36
|
-
| [What a
|
|
37
|
-
| [`<tag-name>.html`](./custom-elements.md#html)
|
|
38
|
-
| [`<tag-name>.ts`](./custom-elements.md#code) | The class the tag registers |
|
|
35
|
+
| Topic | Description |
|
|
36
|
+
|--------------------------------------------------------|---------------------------------|
|
|
37
|
+
| [What a custom element is](./custom-elements.md) | An HTML file, a script, or both |
|
|
38
|
+
| [`<tag-name>.html`](./custom-elements.md#html) | The markup the tag expands into |
|
|
39
|
+
| [`<tag-name>.browser.ts`](./custom-elements.md#code) | The class the tag registers |
|
|
40
|
+
| [The Basic Widget Library](./widgets.md) | `@loadbare/widgets` |
|
|
@@ -1,92 +1,112 @@
|
|
|
1
1
|
# Page Files
|
|
2
2
|
|
|
3
|
-
A page is a set of files sharing one
|
|
4
|
-
HTML, and adds queries and requests when the page
|
|
3
|
+
A page is a set of files sharing one stub, the file name less its suffix.
|
|
4
|
+
The application writes the HTML, and adds queries and requests when the page
|
|
5
|
+
shows data.
|
|
5
6
|
|
|
6
7
|
| File | Holds |
|
|
7
8
|
|----------------------|-------------------------------|
|
|
8
|
-
| `<
|
|
9
|
-
| `<
|
|
10
|
-
| `<
|
|
9
|
+
| `<stub>.page.html` | The page's HTML |
|
|
10
|
+
| `<stub>.queries.ts` | The queries the page shows |
|
|
11
|
+
| `<stub>.requests.ts` | What the page does when asked |
|
|
11
12
|
|
|
12
13
|
Name the landing page `index.page.html`. A bare `/` resolves to `index`, and
|
|
13
|
-
every other path names the page
|
|
14
|
+
every other path names the page whose stub it is.
|
|
14
15
|
|
|
15
|
-
Put the files anywhere under `src/`. The builder pairs them by
|
|
16
|
-
|
|
16
|
+
Put the files anywhere under `src/`. The builder pairs them by stub, not by
|
|
17
|
+
directory; `src/pages/` is the convention.
|
|
17
18
|
|
|
18
19
|
## HTML
|
|
19
20
|
|
|
20
|
-
Write the page as a fragment. The fragment
|
|
21
|
-
|
|
21
|
+
Write the page as a fragment. The fragment lands in `<main>`, which
|
|
22
|
+
[chrome.html](./chrome.md) supplies.
|
|
22
23
|
|
|
23
24
|
```html
|
|
24
25
|
<!-- src/pages/about.page.html -->
|
|
26
|
+
<title>About</title>
|
|
25
27
|
<h1>About</h1>
|
|
26
28
|
<p>This is the about page.</p>
|
|
27
29
|
|
|
28
|
-
<div lb-
|
|
29
|
-
<p>This page has been visited <span lb-
|
|
30
|
+
<div lb-query="visits">
|
|
31
|
+
<p>This page has been visited <span lb-column="count"></span> times.</p>
|
|
30
32
|
</div>
|
|
31
33
|
```
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
Show data with `lb-query`, `lb-column`, and the rest of the attributes in
|
|
36
|
+
[Data Binding](./data-binding.md).
|
|
35
37
|
|
|
36
|
-
A page that
|
|
38
|
+
A page that shows no data needs no other file.
|
|
39
|
+
|
|
40
|
+
### The page title
|
|
41
|
+
|
|
42
|
+
Write a `<title>` in the page file to name the page. The builder removes it
|
|
43
|
+
from the page and stamps its text on the page's `<template>` as
|
|
44
|
+
`lb-page-title`. The hub shows it as the `lb-url` column `lb-page-label`, and
|
|
45
|
+
sets the document title to it; see [The URL](./chrome.md#the-url). A page
|
|
46
|
+
with no `<title>` is labeled by its stub.
|
|
37
47
|
|
|
38
48
|
## Queries
|
|
39
49
|
|
|
40
|
-
Export `queries` from `<
|
|
41
|
-
|
|
42
|
-
that
|
|
50
|
+
Export `queries` from `<stub>.queries.ts`. Each key is a query name the HTML
|
|
51
|
+
names with `lb-query`, and each value declares the query's kind, its key
|
|
52
|
+
column, and the function that answers it:
|
|
43
53
|
|
|
44
54
|
```ts
|
|
45
|
-
// src/pages/
|
|
46
|
-
import { row, type Queries } from "@loadbare/app/server";
|
|
55
|
+
// src/pages/directory.queries.ts
|
|
56
|
+
import { row, rows, type Queries } from "@loadbare/app/server";
|
|
47
57
|
|
|
48
58
|
export const queries: Queries = {
|
|
49
|
-
visits: row(async (ctx) => ({
|
|
59
|
+
visits: row("page", async (ctx) => ({
|
|
60
|
+
page: "directory",
|
|
61
|
+
count: String(await ctx.db.visitCount()),
|
|
62
|
+
})),
|
|
63
|
+
directory: rows("id", (ctx) => ctx.db.directory()),
|
|
50
64
|
};
|
|
51
65
|
```
|
|
52
66
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
67
|
+
| Declared with | Answers with |
|
|
68
|
+
|-------------------|-------------------------------------------|
|
|
69
|
+
| `row(key, run)` | One row, an object |
|
|
70
|
+
| `rows(key, run)` | All its rows, an array of objects, in order |
|
|
57
71
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
computes.
|
|
72
|
+
`key` names the column that identifies a row. Give every row that column,
|
|
73
|
+
including a `row` query's: an aggregate row answers with a constant key. The
|
|
74
|
+
hub matches rows to live rows by key, and a request names a row by key.
|
|
62
75
|
|
|
63
|
-
|
|
64
|
-
|
|
76
|
+
Kind and key belong to the name, so one name answers with one shape, always,
|
|
77
|
+
and `createHub` leaves out an answer that disagrees with its declaration. A
|
|
78
|
+
page that needs the same data as one row and as a set declares two queries.
|
|
65
79
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
import { list, type Queries } from "@loadbare/app/server";
|
|
80
|
+
The hub hands each value to the browser untouched, so what a number, a date
|
|
81
|
+
or a null looks like is decided here, in the query.
|
|
69
82
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
83
|
+
Return the full answer every time, and the rows in the order the page shows
|
|
84
|
+
them. Sending only what changed is a request's job — see
|
|
85
|
+
[refresh and patch](#refresh-and-patch).
|
|
86
|
+
|
|
87
|
+
## Requests
|
|
74
88
|
|
|
75
|
-
|
|
76
|
-
|
|
89
|
+
Export `requests` from `<stub>.requests.ts`. It holds three keys, each
|
|
90
|
+
optional:
|
|
77
91
|
|
|
78
|
-
|
|
79
|
-
|
|
92
|
+
| Key | Runs |
|
|
93
|
+
|---------------|--------------------------------------------------------|
|
|
94
|
+
| `onPageEnter` | Before the page's queries, when the page loads |
|
|
95
|
+
| `handlers` | The page's declared requests, by request name |
|
|
96
|
+
| `crud` | The requests Loadbare provides, by query name |
|
|
80
97
|
|
|
81
|
-
|
|
98
|
+
Every request arrives with one shape, and a handler receives it less its
|
|
99
|
+
name:
|
|
82
100
|
|
|
83
|
-
|
|
101
|
+
| Field | Holds |
|
|
102
|
+
|----------|----------------------------------------------------------|
|
|
103
|
+
| `name` | The request name, from `lb-request` |
|
|
104
|
+
| `query` | The query the request is for |
|
|
105
|
+
| `key` | The key of the row the request is for |
|
|
106
|
+
| `values` | The gathered control values, by column |
|
|
84
107
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
| `onPageEnter` | Before the page's queries, on entering the page |
|
|
88
|
-
| `actions` | What the page may be asked to do, by name |
|
|
89
|
-
| `crud` | The three operations a list permits on its rows |
|
|
108
|
+
The hub sends `query`, `key` and `values` when it finds them; see
|
|
109
|
+
[Gathering](./data-binding.md#gathering).
|
|
90
110
|
|
|
91
111
|
### onPageEnter
|
|
92
112
|
|
|
@@ -101,51 +121,39 @@ export const requests: Requests = {
|
|
|
101
121
|
|
|
102
122
|
Declare no refresh set here. The page's queries run afterward.
|
|
103
123
|
|
|
104
|
-
###
|
|
124
|
+
### handlers
|
|
105
125
|
|
|
106
|
-
Declare
|
|
126
|
+
Declare a request under the name the HTML gives `lb-request`. Pair what it
|
|
107
127
|
does with the queries to re-run once it has:
|
|
108
128
|
|
|
109
129
|
```ts
|
|
110
130
|
export const requests: Requests = {
|
|
111
|
-
|
|
131
|
+
handlers: {
|
|
112
132
|
resetVisits: {
|
|
113
133
|
run: (ctx) => ctx.db.resetVisits(),
|
|
114
134
|
refresh: ["visits"],
|
|
115
135
|
},
|
|
136
|
+
sendReminder: {
|
|
137
|
+
run: (ctx, { key }) => ctx.mail.remind(key),
|
|
138
|
+
refresh: [],
|
|
139
|
+
},
|
|
116
140
|
},
|
|
117
141
|
};
|
|
118
142
|
```
|
|
119
143
|
|
|
120
|
-
Declare every
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
Read where the interaction happened from `run`'s second argument, which
|
|
124
|
-
carries `list` or `row`, whichever attribute scoped the element, plus `key`,
|
|
125
|
-
`cell` and `value` when the element that dispatched the request had them.
|
|
144
|
+
Declare every request the page allows. The server refuses a name the page
|
|
145
|
+
does not declare.
|
|
126
146
|
|
|
127
147
|
### crud
|
|
128
148
|
|
|
129
|
-
Declare
|
|
130
|
-
|
|
131
|
-
row inside a list, so a single-row scope is read-only and a declared action is
|
|
132
|
-
the only thing it can send. Each operation takes the binding its trigger
|
|
133
|
-
supplies:
|
|
149
|
+
Declare what the three requests Loadbare provides do under `crud`, keyed by
|
|
150
|
+
the query they operate on:
|
|
134
151
|
|
|
135
|
-
|
|
|
136
|
-
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
140
|
-
|
|
141
|
-
Write `rowUpdate` to set the columns `values` names and leave every other
|
|
142
|
-
column as it is. A form sends the cells it holds, and a widget cell sends
|
|
143
|
-
itself alone. Check the names in `values` against the columns the list lets
|
|
144
|
-
the page edit.
|
|
145
|
-
|
|
146
|
-
The operation names are reserved: a name beginning with `lb-` cannot be
|
|
147
|
-
declared under `actions` or as a query, and `createHub` refuses a page that
|
|
148
|
-
tries.
|
|
152
|
+
| Request name | Runs | `run` receives |
|
|
153
|
+
|-----------------|-------------|------------------|
|
|
154
|
+
| `lb-row-insert` | `rowInsert` | `query`, `values` |
|
|
155
|
+
| `lb-row-update` | `rowUpdate` | `query`, `key`, `values` |
|
|
156
|
+
| `lb-row-delete` | `rowDelete` | `query`, `key` |
|
|
149
157
|
|
|
150
158
|
```ts
|
|
151
159
|
// src/pages/directory.requests.ts
|
|
@@ -161,30 +169,46 @@ export const requests: Requests = {
|
|
|
161
169
|
},
|
|
162
170
|
refresh: [],
|
|
163
171
|
},
|
|
172
|
+
rowUpdate: {
|
|
173
|
+
run: async (ctx, { key, values }) => {
|
|
174
|
+
const entry = await ctx.db.updateDirectoryEntry(key, values);
|
|
175
|
+
return { directory: patch({ rows: [entry] }) };
|
|
176
|
+
},
|
|
177
|
+
refresh: [],
|
|
178
|
+
},
|
|
164
179
|
},
|
|
165
180
|
},
|
|
166
181
|
};
|
|
167
182
|
```
|
|
168
183
|
|
|
169
|
-
Declare every
|
|
170
|
-
|
|
184
|
+
Declare every request the query permits. The server refuses a request a
|
|
185
|
+
query does not declare, and a query with no `crud` entry permits none.
|
|
186
|
+
|
|
187
|
+
Write `rowUpdate` to set the columns `values` names and leave every other
|
|
188
|
+
column as it is. A form or a live row sends every control it gathers, and a
|
|
189
|
+
single control sends itself alone. Check the names in `values` against the
|
|
190
|
+
columns the page may edit.
|
|
191
|
+
|
|
192
|
+
Every value in `values` is a string, as a control's value is.
|
|
171
193
|
|
|
172
194
|
### refresh and patch
|
|
173
195
|
|
|
174
|
-
List in `refresh` every query whose whole answer the
|
|
196
|
+
List in `refresh` every query whose whole answer the request changed.
|
|
175
197
|
|
|
176
|
-
Return
|
|
177
|
-
would. What `run` returns is laid over the refreshed
|
|
198
|
+
Return answers from `run` to state a narrower change than re-running a query
|
|
199
|
+
would. What `run` returns is keyed by query name and laid over the refreshed
|
|
200
|
+
queries:
|
|
178
201
|
|
|
179
|
-
|
|
|
202
|
+
| Answer | States |
|
|
180
203
|
|--------------------------|---------------------------------------------|
|
|
181
|
-
| `
|
|
204
|
+
| `{ ... }` | The row of a `row` query |
|
|
205
|
+
| `[...]` | All rows of a `rows` query, and their order |
|
|
182
206
|
| `patch({ rows: [...] })` | These rows arrive or change; the rest stand |
|
|
183
207
|
| `patch({ drop: [...] })` | These keys are gone; the rest stand |
|
|
184
208
|
|
|
185
|
-
Return a patch for a change the
|
|
209
|
+
Return a patch for a change the request knows the extent of — one row added,
|
|
186
210
|
one row dropped, one row edited — and leave `refresh` empty. Re-run the query
|
|
187
|
-
instead when membership or order changed in a way the
|
|
211
|
+
instead when membership or order changed in a way the request cannot name:
|
|
188
212
|
|
|
189
213
|
```ts
|
|
190
214
|
resetRoster: {
|
|
@@ -192,3 +216,54 @@ resetRoster: {
|
|
|
192
216
|
refresh: ["roster"],
|
|
193
217
|
},
|
|
194
218
|
```
|
|
219
|
+
|
|
220
|
+
### Moving the URL
|
|
221
|
+
|
|
222
|
+
Return `url()` from `run` when the request changes what the URL should say:
|
|
223
|
+
after an insert, only the server knows the new key, and after a delete, only
|
|
224
|
+
the server knows the parm should go. `url()` takes columns of the `lb-url`
|
|
225
|
+
query; see [The URL](./chrome.md#the-url).
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
// src/pages/accounts.requests.ts
|
|
229
|
+
import { url, type Requests } from "@loadbare/app/server";
|
|
230
|
+
|
|
231
|
+
export const requests: Requests = {
|
|
232
|
+
crud: {
|
|
233
|
+
accounts: {
|
|
234
|
+
rowInsert: {
|
|
235
|
+
run: async (ctx, { values }) => {
|
|
236
|
+
const id = await ctx.db.addAccount(values);
|
|
237
|
+
return url({ acct: String(id) });
|
|
238
|
+
},
|
|
239
|
+
refresh: [],
|
|
240
|
+
},
|
|
241
|
+
rowDelete: {
|
|
242
|
+
run: async (ctx, { key }) => {
|
|
243
|
+
await ctx.db.deleteAccount(key);
|
|
244
|
+
if (key === ctx.acct) return url({ acct: "" });
|
|
245
|
+
},
|
|
246
|
+
refresh: ["accounts"],
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
A column other than `lb-path` is a query parm: set, or taken out when its
|
|
254
|
+
value is an empty string. Name at least one column, and give each a string.
|
|
255
|
+
With `lb-path` naming another page, the page is entered with only the parms
|
|
256
|
+
named:
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
return url({ "lb-path": "/accounts", acct: String(id) });
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The server loads the page at the new URL in the same round trip, as a cold
|
|
263
|
+
load of it would, and the hub writes the URL: it pushes a history entry when
|
|
264
|
+
the page changes, or when the element that sent the request carries
|
|
265
|
+
`lb-url-push`, and replaces the current one otherwise. This is
|
|
266
|
+
Post/Redirect/Get without the redirect. The refresh set does not run, and
|
|
267
|
+
nothing else `run` returned is sent, since both answered for the URL the page
|
|
268
|
+
left. The loaded page reads the new parms through `contextFor`; see
|
|
269
|
+
[the Express server](./server.md#database-layer).
|
|
@@ -64,7 +64,7 @@ Register authentication before `hubRoutes`.
|
|
|
64
64
|
|
|
65
65
|
Serve `dist/app.html` for every route the application does not claim,
|
|
66
66
|
including a path that names no page. See [`chrome.html`](./chrome.md) for the
|
|
67
|
-
`<dialog lb-unknown
|
|
67
|
+
`<dialog lb-url-unknown>` that announces that case to the user.
|
|
68
68
|
|
|
69
69
|
Give the server the origin root. The hub reaches its own route by absolute
|
|
70
70
|
path, so the application cannot be hosted under a subpath such as
|
|
@@ -137,17 +137,23 @@ declare module "@loadbare/app/server" {
|
|
|
137
137
|
}
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
The query string the browser is showing arrives on every data request,
|
|
141
|
-
`
|
|
142
|
-
reads from them, and treat them as user input:
|
|
140
|
+
The query string the browser is showing arrives on every data request, and
|
|
141
|
+
`contextFor` gets its parms as a second argument. Put on the context whatever
|
|
142
|
+
a query reads from them, and treat them as user input:
|
|
143
143
|
|
|
144
144
|
```ts
|
|
145
|
-
function contextFor(req: Request): HubContext {
|
|
146
|
-
|
|
147
|
-
return { db: openDb(), team: typeof team === "string" ? team : "" };
|
|
145
|
+
function contextFor(req: Request, parms: URLSearchParams): HubContext {
|
|
146
|
+
return { db: openDb(), team: parms.get("team") ?? "" };
|
|
148
147
|
}
|
|
149
148
|
```
|
|
150
149
|
|
|
150
|
+
Read the parms from that argument, not from `req.query`. When a server
|
|
151
|
+
response changes the query parms, `contextFor` is called a second time for
|
|
152
|
+
that request, with the new parms, to load the page at them; see [Moving the URL](./page-files.md#moving-the-url). Write it to
|
|
153
|
+
be safe to call twice, and make a write visible to the second context by the
|
|
154
|
+
time `run` returns: a handle opened per request, with no transaction held
|
|
155
|
+
open across the two, is both.
|
|
156
|
+
|
|
151
157
|
Add a field for anything else a request needs — the authenticated user, a
|
|
152
158
|
request id, a feature flag set. Queries and requests read them from `ctx`; see
|
|
153
159
|
[page files](./page-files.md).
|