@lotics/app-sdk 0.45.0 → 0.46.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.
- package/AGENTS.md +6 -1
- package/dist/src/row.d.ts +10 -0
- package/dist/src/row.js +4 -0
- package/dist/src/rpc.js +32 -5
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -133,7 +133,12 @@ Pick by intent. (→ open the `.d.ts` for the exact signature.)
|
|
|
133
133
|
- **`readSelect(cell)`** → `ResolvedOption[]` `{ key, label, color? }` (a cell carries key+label; the
|
|
134
134
|
`color` is populated by `useFieldOptions`, not the cell). **`readMembers(cell)`** → `{ id, name,
|
|
135
135
|
email? }[]`. **`readLinks(cell)` / `row.link`** → `{ id, display }`. **`readFiles(cell)`** →
|
|
136
|
-
`AppFile[]` with presigned `url` + `thumbnail_url` (24 h)
|
|
136
|
+
`AppFile[]` with presigned `url` + `thumbnail_url` (24 h) **+ `size` (bytes) + `created_at` (ISO
|
|
137
|
+
date-added), resolved from the file object at read**. Surface size/date as **dedicated sortable
|
|
138
|
+
`Table` columns over the RAW numeric** — the `tpl_documents` document-register pattern (a `Size`
|
|
139
|
+
column `align:"right"` + an `Added` column, formatted only at display; NOT a crammed `FileRow` `meta`
|
|
140
|
+
string, which sorts wrong — "8.4 MB" < "96 KB"). `size` is absent for older files until backfilled —
|
|
141
|
+
render it only when present. **`readLocked(row)`** → `boolean` from the
|
|
137
142
|
`__source_locked` addressing column.
|
|
138
143
|
- **`project` only what you render** and `filter` server-side: a bare `from_table` ships every column
|
|
139
144
|
— incl. `files` with storage keys — to the client (over-exposure + presign-500 at scale). A code
|
package/dist/src/row.d.ts
CHANGED
|
@@ -68,6 +68,16 @@ export interface AppFile {
|
|
|
68
68
|
url: string;
|
|
69
69
|
/** Presigned thumbnail URL for images, when the server produced one. */
|
|
70
70
|
thumbnail_url?: string;
|
|
71
|
+
/** Byte size of the file, resolved from the file object at serving time. Absent
|
|
72
|
+
* for older files not yet backfilled — show a size only when present. Prefer a
|
|
73
|
+
* dedicated sortable `Table` column over the RAW number (the `tpl_documents`
|
|
74
|
+
* register: a right-aligned "Size" column, formatted at display) — not a crammed
|
|
75
|
+
* `FileRow` meta string, which sorts wrong ("8.4 MB" < "96 KB"). */
|
|
76
|
+
size?: number | null;
|
|
77
|
+
/** ISO upload timestamp (date-added), resolved at serving time. Show as a
|
|
78
|
+
* dedicated "Added" `Table` column (format with `formatDate`), sortable over the
|
|
79
|
+
* raw ISO value. */
|
|
80
|
+
created_at?: string;
|
|
71
81
|
}
|
|
72
82
|
/**
|
|
73
83
|
* files field → the attached files with their presigned `url` (empty if none).
|
package/dist/src/row.js
CHANGED
|
@@ -123,12 +123,16 @@ export function readFiles(v) {
|
|
|
123
123
|
const filename = f.filename;
|
|
124
124
|
const mime = f.mime_type;
|
|
125
125
|
const thumb = f.thumbnail_url;
|
|
126
|
+
const size = f.size;
|
|
127
|
+
const created_at = f.created_at;
|
|
126
128
|
out.push({
|
|
127
129
|
id,
|
|
128
130
|
filename: typeof filename === "string" ? filename : "",
|
|
129
131
|
mime_type: typeof mime === "string" ? mime : "",
|
|
130
132
|
url,
|
|
131
133
|
thumbnail_url: typeof thumb === "string" ? thumb : undefined,
|
|
134
|
+
size: typeof size === "number" ? size : undefined,
|
|
135
|
+
created_at: typeof created_at === "string" ? created_at : undefined,
|
|
132
136
|
});
|
|
133
137
|
}
|
|
134
138
|
return out;
|
package/dist/src/rpc.js
CHANGED
|
@@ -365,6 +365,12 @@ export function transportErrorMessage(status, parsed) {
|
|
|
365
365
|
? gatewayErrorMessage(status)
|
|
366
366
|
: jsonMessage;
|
|
367
367
|
}
|
|
368
|
+
// Standalone requests carried no timeout: a hung or slow backend pinned the
|
|
369
|
+
// fetch — and one of the browser's few per-origin connections — indefinitely,
|
|
370
|
+
// surfacing as an app that "loads forever". Bound every standalone call the way
|
|
371
|
+
// the bridged host path already bounds its own (`apiFetch`, 30s): a stalled
|
|
372
|
+
// request fails fast with a gateway-timeout message instead of spinning.
|
|
373
|
+
const API_TIMEOUT_MS = 30_000;
|
|
368
374
|
async function apiCall(method, path, body, opts) {
|
|
369
375
|
const headers = {};
|
|
370
376
|
if (body)
|
|
@@ -372,11 +378,32 @@ async function apiCall(method, path, body, opts) {
|
|
|
372
378
|
if (sessionToken && !opts?.skipAuth) {
|
|
373
379
|
headers["authorization"] = `Bearer ${sessionToken}`;
|
|
374
380
|
}
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
381
|
+
const controller = new AbortController();
|
|
382
|
+
let didTimeout = false;
|
|
383
|
+
const timeoutId = setTimeout(() => {
|
|
384
|
+
didTimeout = true;
|
|
385
|
+
controller.abort();
|
|
386
|
+
}, API_TIMEOUT_MS);
|
|
387
|
+
let res;
|
|
388
|
+
try {
|
|
389
|
+
res = await fetch(`${API_BASE}${path}`, {
|
|
390
|
+
method,
|
|
391
|
+
headers,
|
|
392
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
393
|
+
signal: controller.signal,
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
catch (err) {
|
|
397
|
+
// A timeout abort surfaces as an AbortError — convert it to the same
|
|
398
|
+
// body-free gateway-timeout message a 524 produces, never a raw abort.
|
|
399
|
+
if (didTimeout && err instanceof DOMException && err.name === "AbortError") {
|
|
400
|
+
throw new Error(gatewayErrorMessage(524));
|
|
401
|
+
}
|
|
402
|
+
throw err;
|
|
403
|
+
}
|
|
404
|
+
finally {
|
|
405
|
+
clearTimeout(timeoutId);
|
|
406
|
+
}
|
|
380
407
|
const text = await res.text();
|
|
381
408
|
let parsed = null;
|
|
382
409
|
if (text) {
|