@lotics/app-sdk 0.124.6 → 0.124.8
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/AGENTS.md +1 -1
- package/dist/{chunk-BWMAO5IY.js → chunk-YONY7UPS.js} +1 -0
- package/dist/hooks.d.ts +1 -2
- package/dist/index.d.ts +6 -6
- package/dist/index.js +40 -22
- package/dist/mock.d.ts +7 -0
- package/dist/queries.d.ts +8 -0
- package/dist/rename_file.d.ts +1 -1
- package/dist/router.js +1 -1
- package/dist/row.d.ts +0 -28
- package/dist/rpc.d.ts +2 -2
- package/dist/shared_types.d.ts +29 -3
- package/dist/upload/pipeline.d.ts +1 -1
- package/docs/data_fetching.md +5 -2
- package/docs/files.md +1 -1
- package/docs/runtime.md +4 -3
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Upload: optimize (images) → presigned URL → PUT with retry → complete. */
|
|
2
2
|
import { type ImageFidelity } from "./optimize.js";
|
|
3
|
-
import type { PhotoPlace } from "../
|
|
3
|
+
import type { PhotoPlace } from "../shared_types.js";
|
|
4
4
|
interface UploadInitResponse {
|
|
5
5
|
upload_url: string;
|
|
6
6
|
file_id: string;
|
package/docs/data_fetching.md
CHANGED
|
@@ -25,6 +25,7 @@ untyped. It is written from the app's live bindings by `lotics app create --cust
|
|
|
25
25
|
| `useQueries(calls, opts?)` | one state per `{ alias, params?, filter?, sort?, aggregate?, total?, rows? }`, in order — a `sort` orders that call's rows before the cap cuts them | reads that are DATA — a list known only at render, one read per item, or one count per stage (`rows: false, total: true`, each state's `.total`); the deploy's alias scan reads a list as dynamic, so every alias in it is still declared. With `aggregate` a call answers the groups of its filtered rows instead of the rows ([queries](./queries.md)) |
|
|
26
26
|
| `queryAll(alias, params?, { filter, sort })` | a promise of every row | outside React, for a job that must hold the whole narrowed set in the browser (the ids an act runs on): it asks page after page until the server says the set ended, never stopping at the 10,000-row cap. The server's rows as stored — no write of this app is drawn over them |
|
|
27
27
|
| `exportQuery(alias, { params, filter, sort, tabs?, report, file, labels? })` | a promise of an `ExportedFile`: `{ filename, mime_type, url, size, created_at }` | every row the narrowed set holds, made into one file by the server — no row reaches the browser. `tabs` (2 to 5, each `{ tab, label, filter?, sort?, totals? }`; `totals` is `{ query, params, via, columns }`, the read of a totals tab beside its rows, joined on the link column `via`, refused where that read lacks `via` or a column or answers two groups for one row) are each read as the export's own rows are — same query and params, under the tab's own filter and sort (absent, the declared order) — and a template reads each one's rows under its `tab`, a name none of the report's keys nor the template's `rows` key holds. `report` is `{ title, lines, readings, dates?, period?, per?, per_row?, filename? }` — `dates` each date filter's `{ from?, to? }` by field alias, each bound a day (`yyyy-MM-dd`) or a minute of one (`yyyy-MM-ddTHH:mm`) with no zone; `period` the tabs' `{ from, to }`, bounds of the same form; `per` the value the report was picked for, in the reader's words; `per_row` the picked row's fields by field alias, each a text, number, boolean or `null`, which `filename` and a template read as `per_row.<field>`; `filename` the file's name in the template grammar over one value each — `title`, `at` (the moment the server made the file), `dates.<field>.from` or `.to`, `period.from` or `.to`, `per`, `per_row.<field>`, `lines | lookup:<n>`, with `| add_days:<n>` shifting a date by whole days — at most 200 bytes once filled (absent, the template's name, or `title`); `file` is `{ kind: "workbook", language, sheet, columns }` (the default report workbook, its head closing with the moment the server made it, each column `{ key, header, type }` an output column of the query — a `number` one on a number column, a `date` one on a date or datetime; with `tabs`, one sheet per tab named by its `label` in place of `sheet`) or `{ kind: "template", template }`, one the query declares under `templates` by name ([queries](./queries.md)). `labels`, by `select` output column, the words each option key prints as in either file — a cell no field of the query names (a union's literal column) arrives as its bare key; a cell its field's option names prints as that, a key the map lacks as itself, and a column no select of the query holds as it is. Past 20,000 rows, in any tab, it rejects, never cuts; each caller makes at most 60 exports a minute. The file has no `id` — it is a download, not a workspace file a workflow or a field takes: its `url` is signed for the caller for at most an hour, so download it with `downloadFileFromUrl(url, filename)` (`@lotics/ui/download`) when the promise resolves — a tab `openExternal` opens seconds after the click is a pop-up the browser blocks; the server deletes the file a day after it is made |
|
|
28
|
+
| `exportApp(key, narrowing)` | a promise of an `ExportedFile`, as `exportQuery`'s | the file the server makes of an Export `key` of a JSON app's tree (a custom-code app has no Export and makes its files with `exportQuery`) over the register as `narrowing` states it (`tab`, `status`, `filters`, `search`, `overdue`, `waiting`, `period`, `window`, `sort`, `group`, `folder`, `per`; a `filters` entry `null` clears the chip the register opens on): the server reads the rows, the band's readings and the names under the caller's own access. Download it as `exportQuery`'s |
|
|
28
29
|
|
|
29
30
|
Every hook answers the same `QueryState`: `rows`, `truncated`, `total`, `counts`, `loading`,
|
|
30
31
|
`isValidating`, `answeredAt`, `error`, `pending`, `refetch`, `page`, `setPage`, `pageCount`, `hasMore`,
|
|
@@ -144,7 +145,8 @@ write it as `{ node_type: "condition", type: "record_id", operator, value }`.
|
|
|
144
145
|
inline `{ status: "open" }` each render is the same key; you never need to memoize params.
|
|
145
146
|
- **The cache survives unmount/remount**, and **arrival is a refresh event**: returning to a screen
|
|
146
147
|
renders the cached rows instantly *and* re-reads them in the background, so a list reflects what
|
|
147
|
-
another screen changed while you were away.
|
|
148
|
+
another screen changed while you were away. Arrival re-reads a read that answered, not one whose
|
|
149
|
+
last ask failed. Identical concurrent reads share one request, and reads asked within a few milliseconds of each other go to the server together, each answered or refused on its own.
|
|
148
150
|
Freshness comes from four places — arrival, window focus / tab return / network reconnect
|
|
149
151
|
(`revalidateOnFocus`, default on; a read asked within the last minute is not asked again,
|
|
150
152
|
and the reads it asks again re-render together, as a push's do — so what changed while the tab
|
|
@@ -188,7 +190,8 @@ write it as `{ node_type: "condition", type: "record_id", operator, value }`.
|
|
|
188
190
|
where `answeredAt` moved and the call is the same.
|
|
189
191
|
- **`error`** is a `string | null`. A failed query surfaces immediately — there is **no automatic
|
|
190
192
|
retry** (no retry loop that masks the error). The last successful rows for the same key stay
|
|
191
|
-
rendered.
|
|
193
|
+
rendered. It stays failed until a realtime push or this app's own write names it, a focus or
|
|
194
|
+
reconnect re-read, or an explicit `refetch()`; mounting the screen again does not re-run it.
|
|
192
195
|
- **Never derive a FIGURE from `rows` without gating on `error`.** A first read that fails leaves
|
|
193
196
|
`rows` at `[]`, and `[]` is indistinguishable from a genuinely empty result — so `rows.reduce(…)`
|
|
194
197
|
returns `0`, `rows.length` returns `0`, and a screen states a confident number that no query
|
package/docs/files.md
CHANGED
|
@@ -240,7 +240,7 @@ A caller outside the app's organization receives only `id`, `filename`, `mime_ty
|
|
|
240
240
|
`thumbnail_url`, `preview_url`, `size`, `created_at` and `document_template_id` — never the storage
|
|
241
241
|
address, and never a place.
|
|
242
242
|
|
|
243
|
-
Decode with `readFiles(cell)` → `AppFile[]` (`dist/
|
|
243
|
+
Decode with `readFiles(cell)` → `AppFile[]` (`dist/shared_types.d.ts`):
|
|
244
244
|
|
|
245
245
|
| Field | Type | Notes |
|
|
246
246
|
|---|---|---|
|
package/docs/runtime.md
CHANGED
|
@@ -68,7 +68,7 @@ Activation is a **two-step gate** — both must hold, so demo data shipping in t
|
|
|
68
68
|
bundle never leaks into normal traffic:
|
|
69
69
|
|
|
70
70
|
1. A fixture is registered via `mount({ fixture })` (`AppFixture` type:
|
|
71
|
-
`dist/mock.d.ts` — `{ queries?, workflows?, agents?, exports?, recordings? }`).
|
|
71
|
+
`dist/mock.d.ts` — `{ queries?, workflows?, agents?, exports?, exportApps?, recordings? }`).
|
|
72
72
|
2. The page URL carries `?__mock=1` (exactly `1`). Without the flag the fixture
|
|
73
73
|
is completely inert.
|
|
74
74
|
|
|
@@ -79,7 +79,7 @@ the fixture nothing, as it asks the server nothing. **Partial mocking is
|
|
|
79
79
|
supported**: an alias absent from the fixture still flows through the real
|
|
80
80
|
transport. `fixture.exports[alias]` answers `exportQuery(alias, call)` — a
|
|
81
81
|
function of the call returning an `ExportedFile`, or a promise of one to review the
|
|
82
|
-
pending state. Calling `mount` again (HMR) replaces the registration last-write-wins.
|
|
82
|
+
pending state; `fixture.exportApps[key]` answers `exportApp(key, narrowing)` the same way. Calling `mount` again (HMR) replaces the registration last-write-wins.
|
|
83
83
|
|
|
84
84
|
- **Fixture rows stand in for wire rows.** They pass through the same code path
|
|
85
85
|
as fetched rows, so shape them exactly like the query's real output — the same
|
|
@@ -258,7 +258,8 @@ semantics are documented:
|
|
|
258
258
|
| Op | Payload | Resolves to | Owning doc |
|
|
259
259
|
|---|---|---|---|
|
|
260
260
|
| `query` | `{ alias, params?, limit?, offset?, … }` | `{ rows }` | [queries](./queries.md), [data fetching](./data_fetching.md) |
|
|
261
|
-
| `export` | `{ alias, params?, filter?, sort?, report, file }` | `{ file }` | [data fetching](./data_fetching.md) |
|
|
261
|
+
| `export` | `{ alias, params?, filter?, sort?, report, file }` (`exportQuery`) or `{ export: { key, … } }` (`exportApp`) | `{ file }` | [data fetching](./data_fetching.md) |
|
|
262
|
+
| `spec` | `{}` | `HostSpec`: the app's compiled `app.json` itself (format 29: `lists`, `pages` by entity, `entities`, flat `acts` and `checks`; a dashboard's readings), never the route's wrapper | this doc |
|
|
262
263
|
| `field_options` | `{ alias }` | `{ fields }` | [members & options](./members_and_options.md) |
|
|
263
264
|
| `workflow` | `{ alias, inputs }` | `WorkflowResult` | [mutations](./mutations.md) |
|
|
264
265
|
| `upload` | `{ file: File }` (the `File` crosses the bridge by structured clone) | uploaded-file object | [files](./files.md) |
|
package/package.json
CHANGED