makersclaw 0.6.0 → 0.7.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 +48 -8
- package/package.json +1 -1
- package/r/annotate.json +4 -4
- package/r/approval-request.json +3 -3
- package/r/audio-player.json +3 -3
- package/r/auth-form.json +2 -2
- package/r/board.json +4 -4
- package/r/calendar-view.json +4 -4
- package/r/cart.json +3 -3
- package/r/chart.json +3 -3
- package/r/chat.json +3 -3
- package/r/code-editor.json +4 -4
- package/r/comment-box.json +4 -4
- package/r/contact-section.json +3 -3
- package/r/core.json +3 -3
- package/r/csv-import.json +4 -4
- package/r/data-table.json +3 -3
- package/r/diagram.json +3 -3
- package/r/doc-editor.json +4 -4
- package/r/doc-page.json +4 -4
- package/r/email-render.json +2 -2
- package/r/faq.json +2 -2
- package/r/file-upload.json +3 -3
- package/r/flow-canvas.json +4 -4
- package/r/footer.json +3 -3
- package/r/gantt.json +4 -4
- package/r/job-panel.json +3 -3
- package/r/json-editor.json +4 -4
- package/r/map.json +5 -5
- package/r/menubar.json +2 -2
- package/r/mind-map.json +4 -4
- package/r/navigation-menu.json +2 -2
- package/r/order-detail.json +2 -2
- package/r/org-chart.json +4 -4
- package/r/page-builder.json +6 -6
- package/r/payment-methods.json +2 -2
- package/r/pdf-document.json +2 -2
- package/r/pdf-viewer.json +6 -6
- package/r/product-detail.json +3 -3
- package/r/product-grid.json +4 -4
- package/r/record-form.json +3 -3
- package/r/record-notes.json +5 -5
- package/r/registry.json +121 -121
- package/r/search-dialog.json +3 -3
- package/r/settings-list.json +3 -3
- package/r/setup-checklist.json +3 -3
- package/r/share-dialog.json +3 -3
- package/r/sidebar.json +2 -2
- package/r/signature-pad.json +3 -3
- package/r/sketch-canvas.json +5 -5
- package/r/spreadsheet.json +3 -3
- package/r/stat-cards.json +4 -4
- package/r/task-list.json +4 -4
- package/r/task-model.json +3 -3
- package/r/testimonials.json +2 -2
- package/r/transaction-list.json +3 -3
- package/r/whiteboard.json +4 -4
- package/registry/blocks/annotate/README.md +14 -5
- package/registry/blocks/approval-request/README.md +15 -8
- package/registry/blocks/audio-player/README.md +17 -10
- package/registry/blocks/board/README.md +13 -9
- package/registry/blocks/board/board.jsx +1 -1
- package/registry/blocks/calendar-view/README.md +28 -4
- package/registry/blocks/cart/README.md +14 -10
- package/registry/blocks/chart/README.md +14 -7
- package/registry/blocks/chat/README.md +43 -13
- package/registry/blocks/code-editor/README.md +4 -0
- package/registry/blocks/code-editor/code-editor.jsx +1 -1
- package/registry/blocks/comment-box/README.md +20 -13
- package/registry/blocks/contact-section/README.md +7 -6
- package/registry/blocks/csv-import/README.md +34 -12
- package/registry/blocks/data-table/README.md +41 -8
- package/registry/blocks/diagram/diagram.jsx +1 -1
- package/registry/blocks/doc-editor/README.md +18 -6
- package/registry/blocks/doc-editor/doc-editor.jsx +1 -1
- package/registry/blocks/doc-page/README.md +16 -6
- package/registry/blocks/file-upload/README.md +7 -1
- package/registry/blocks/flow-canvas/README.md +16 -5
- package/registry/blocks/flow-canvas/flow-canvas.jsx +1 -1
- package/registry/blocks/footer/README.md +4 -2
- package/registry/blocks/gantt/README.md +18 -12
- package/registry/blocks/job-panel/README.md +1 -1
- package/registry/blocks/json-editor/README.md +16 -4
- package/registry/blocks/map/README.md +19 -3
- package/registry/blocks/map/map-view.jsx +1 -1
- package/registry/blocks/map/maplibre.js +1 -1
- package/registry/blocks/mind-map/README.md +16 -5
- package/registry/blocks/org-chart/README.md +10 -7
- package/registry/blocks/page-builder/README.md +13 -6
- package/registry/blocks/page-builder/page-builder.jsx +1 -1
- package/registry/blocks/page-builder/page-view.jsx +1 -1
- package/registry/blocks/page-builder/page.js +1 -1
- package/registry/blocks/pdf-viewer/README.md +22 -20
- package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1 -1
- package/registry/blocks/pdf-viewer/pdfjs.js +1 -1
- package/registry/blocks/pdf-viewer/ssr-shim.js +1 -1
- package/registry/blocks/product-detail/README.md +13 -7
- package/registry/blocks/product-detail/demo.jsx +1 -1
- package/registry/blocks/product-grid/README.md +12 -10
- package/registry/blocks/record-form/README.md +26 -9
- package/registry/blocks/record-notes/README.md +42 -30
- package/registry/blocks/search-dialog/README.md +38 -7
- package/registry/blocks/settings-list/README.md +29 -17
- package/registry/blocks/setup-checklist/README.md +12 -14
- package/registry/blocks/share-dialog/README.md +1 -1
- package/registry/blocks/signature-pad/README.md +15 -4
- package/registry/blocks/sketch-canvas/README.md +13 -4
- package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1 -1
- package/registry/blocks/sketch-canvas/ssr-shim.js +3 -3
- package/registry/blocks/spreadsheet/README.md +17 -8
- package/registry/blocks/stat-cards/README.md +17 -8
- package/registry/blocks/task-list/README.md +14 -11
- package/registry/blocks/task-model/README.md +3 -3
- package/registry/blocks/transaction-list/README.md +15 -7
- package/registry/blocks/whiteboard/README.md +19 -13
- package/src/cli.mjs +31 -4
- package/src/install.mjs +263 -21
- package/src/registry.mjs +78 -1
- package/templates/next/browser/app/auto-refresh.jsx +67 -0
- package/templates/next/browser/app/layout.jsx +94 -0
- package/templates/next/browser/app/page.jsx +60 -0
- package/templates/next/browser/app/s/[key]/page.jsx +95 -0
- package/templates/next/browser/lib/actions.js +16 -0
- package/templates/next/browser/lib/data.js +43 -0
- package/templates/next/files/README.md +810 -79
- package/templates/next/files/app/frame.js +128 -4
- package/templates/next/files/check/run.mjs +1438 -41
- package/templates/next/files/components/ui/item.jsx +2 -2
- package/templates/next/files/components/ui/notice.jsx +1 -1
- package/templates/next/files/components/ui/separator.jsx +1 -1
- package/templates/next/files/lib/actions.js +170 -51
- package/templates/next/files/lib/brain-server.js +96 -0
- package/templates/next/files/lib/brain.js +413 -0
- package/templates/next/files/lib/claw.js +11 -0
- package/templates/next/files/lib/data.js +119 -29
- package/templates/next/files/lib/db.js +97 -17
- package/templates/next/files/lib/door.js +680 -0
- package/templates/next/files/next.config.mjs +36 -2
- package/templates/next/files/surfaces.js +3 -2
- package/templates/next/template.json +9 -3
- package/templates/next/files/schema.sql +0 -22
|
@@ -63,7 +63,8 @@ export const PRESENCE_EVENTS = ["pointerdown", "pointermove", "keydown", "wheel"
|
|
|
63
63
|
* and no probe, while any element on the page carries it. For a surface
|
|
64
64
|
* whose rows only its own writes change, or one too big to send every
|
|
65
65
|
* few seconds (a base of 4,812 records was about 2 MB a refresh). Its
|
|
66
|
-
* writes still re-render it (lib/actions.js revalidates
|
|
66
|
+
* writes still re-render it (a server app's lib/actions.js revalidates;
|
|
67
|
+
* a browser app's writes call lib/door.js dataChanged()), and so does
|
|
67
68
|
* every navigation. */
|
|
68
69
|
export const REFRESH_OFF = '[data-claw-refresh="off"]';
|
|
69
70
|
|
|
@@ -195,6 +196,123 @@ export async function answering(url, fetchImpl = globalThis.fetch, timeoutMs = P
|
|
|
195
196
|
}
|
|
196
197
|
}
|
|
197
198
|
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// Auto-refresh in a browser app
|
|
201
|
+
|
|
202
|
+
// A browser app (makersclaw.json "mode": "browser") has no server to ask
|
|
203
|
+
// and nothing to re-render from: its pages are files, prerendered once,
|
|
204
|
+
// and its rows come from the platform's data door through lib/door.js's
|
|
205
|
+
// hooks. So its refresh is not router.refresh(): under an export that
|
|
206
|
+
// fetches the same prebuilt payload and shows nothing new. It is the
|
|
207
|
+
// hooks reading again (lib/door.js dataChanged(), then whenLanded()),
|
|
208
|
+
// and only when something changed: a question the door answers in one
|
|
209
|
+
// small request, where the server app's refresh re-rendered every
|
|
210
|
+
// surface every 5 s whether anything had changed or not (claw's
|
|
211
|
+
// STATIC-SPEC §3, a browser app's auto-refresh).
|
|
212
|
+
//
|
|
213
|
+
// The question is the door's change feed, GET _claw/data/changes (claw's
|
|
214
|
+
// CONTRACTS §8), which answers two things:
|
|
215
|
+
// - `changes`: the company brain's changes in the app's kinds and the
|
|
216
|
+
// member's areas since the cursor, and `next`, the cursor after them;
|
|
217
|
+
// - `tables`: a stamp of the app's own tables (Postgres's counters:
|
|
218
|
+
// rows written, then rows live). It moves with any write to them, the
|
|
219
|
+
// agent's, a job's, another member's. The platform's counters lag:
|
|
220
|
+
// a write shows in the stamp within about 11 s, two or three ticks.
|
|
221
|
+
// The first answer only sets the cursor and the stamp: the hooks read
|
|
222
|
+
// the rows on their own as the page opened. After it, "something
|
|
223
|
+
// changed" is a brain change, a cursor that moved (a brain that
|
|
224
|
+
// appeared, or an app whose grant went away), or a different stamp, up
|
|
225
|
+
// or down. A stamp that moved for nothing (autovacuum re-counting, a
|
|
226
|
+
// rolled-back write, a restart that zeroed the counters) costs one read
|
|
227
|
+
// too many, never one too few; so does the page's own write, which
|
|
228
|
+
// reads again at once and then shows in the stamp too.
|
|
229
|
+
|
|
230
|
+
/** The feed's path under _claw/: the changes after `since`, the last
|
|
231
|
+
* answer's `next`. None yet: the door answers where the feed is now. */
|
|
232
|
+
export function changesPath(since) {
|
|
233
|
+
return since === undefined || since === null || since === "" ? "data/changes" : `data/changes?since=${encodeURIComponent(String(since))}`;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** An abort signal that fires at the deadline or on `stop`, whichever is
|
|
237
|
+
* first. A browser without AbortSignal.any keeps the deadline: a held
|
|
238
|
+
* request must not stall every tick after it. */
|
|
239
|
+
function askSignal(timeoutMs, stop) {
|
|
240
|
+
const timeout = typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(timeoutMs) : undefined;
|
|
241
|
+
if (!timeout || !stop) return timeout ?? stop;
|
|
242
|
+
return typeof AbortSignal.any === "function" ? AbortSignal.any([timeout, stop]) : timeout;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* The browser app's probe: has anything changed since the last refresh?
|
|
247
|
+
* `ask(path, signal)` sends GET _claw/<path> and resolves to lib/claw.js
|
|
248
|
+
* claw()'s answer ({ ok, status, data, unavailable }); it may throw, and
|
|
249
|
+
* a throw is no answer. → { probe, covered, stop }
|
|
250
|
+
*
|
|
251
|
+
* - probe() resolves true when a change was seen that no refresh has
|
|
252
|
+
* covered yet. It asks the door every time (one ask at a time: a
|
|
253
|
+
* second probe while one is out shares its answer), within
|
|
254
|
+
* PROBE_TIMEOUT_MS.
|
|
255
|
+
* - covered(): a refresh has started, so what was seen is on its way.
|
|
256
|
+
* A change stays owed until then: a tick that saw one and found the
|
|
257
|
+
* founder typing refreshes on a later tick, not never.
|
|
258
|
+
* - A failed answer changes nothing: the cursor and the stamp stay, and
|
|
259
|
+
* the next tick asks again. A 5xx, a 401 (a grant gone stale), no
|
|
260
|
+
* network, no answer in time. A refresh would read nothing new.
|
|
261
|
+
* - A 404 that names no code is no door at all (a Makersclaw from
|
|
262
|
+
* before it, a `next dev` with nothing in front of it): the feed
|
|
263
|
+
* stops asking for the page's life, so the console does not log a
|
|
264
|
+
* failed request every five seconds.
|
|
265
|
+
* - stop() aborts an ask in flight; every probe after it is false.
|
|
266
|
+
*/
|
|
267
|
+
export function changeFeed(ask, { timeoutMs = PROBE_TIMEOUT_MS } = {}) {
|
|
268
|
+
let first = true; // no answer yet: the next one only sets where we are
|
|
269
|
+
let cursor = null; // the feed's `next`: where the next ask starts
|
|
270
|
+
let stamp = null; // the own tables' stamp, as last answered
|
|
271
|
+
let owed = false; // a change seen and not yet covered by a refresh
|
|
272
|
+
let gone = false; // no door answers here
|
|
273
|
+
let stopped = false;
|
|
274
|
+
let asking = null; // the ask in flight
|
|
275
|
+
const halt = typeof AbortController === "function" ? new AbortController() : null;
|
|
276
|
+
|
|
277
|
+
async function askOnce() {
|
|
278
|
+
let answer;
|
|
279
|
+
try {
|
|
280
|
+
answer = await ask(changesPath(cursor), askSignal(timeoutMs, halt?.signal));
|
|
281
|
+
} catch {
|
|
282
|
+
return; // no answer
|
|
283
|
+
}
|
|
284
|
+
if (stopped || !answer) return;
|
|
285
|
+
if (!answer.ok) {
|
|
286
|
+
if (answer.status === 404 && answer.unavailable) gone = true;
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const data = answer.data;
|
|
290
|
+
if (!data || typeof data !== "object" || Array.isArray(data) || data.ok === false) return;
|
|
291
|
+
const next = data.next === undefined || data.next === null ? null : String(data.next);
|
|
292
|
+
const tables = data.tables === undefined || data.tables === null ? null : String(data.tables);
|
|
293
|
+
const changed = (Array.isArray(data.changes) && data.changes.length > 0) || next !== cursor || tables !== stamp;
|
|
294
|
+
if (!first && changed) owed = true;
|
|
295
|
+
first = false;
|
|
296
|
+
cursor = next;
|
|
297
|
+
stamp = tables;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
probe() {
|
|
302
|
+
if (stopped || gone) return Promise.resolve(false);
|
|
303
|
+
if (!asking) asking = askOnce().finally(() => (asking = null));
|
|
304
|
+
return asking.then(() => owed && !stopped);
|
|
305
|
+
},
|
|
306
|
+
covered() {
|
|
307
|
+
owed = false;
|
|
308
|
+
},
|
|
309
|
+
stop() {
|
|
310
|
+
stopped = true;
|
|
311
|
+
halt?.abort();
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
198
316
|
/** `promise`, or undefined once `ms` have passed, whichever comes first. */
|
|
199
317
|
function within(promise, ms, timers) {
|
|
200
318
|
let timer = null;
|
|
@@ -205,8 +323,14 @@ function within(promise, ms, timers) {
|
|
|
205
323
|
/**
|
|
206
324
|
* The refresh loop app/auto-refresh.jsx runs, as plain code over a
|
|
207
325
|
* document so `npm test` can drive it. `refresh()` starts one refresh and
|
|
208
|
-
* resolves when it has landed (
|
|
209
|
-
*
|
|
326
|
+
* resolves when it has landed; `probe()` is asked first, and a tick
|
|
327
|
+
* refreshes only on its yes. → { stop() }
|
|
328
|
+
*
|
|
329
|
+
* The two modes differ only in those two. A server app's refresh is
|
|
330
|
+
* router.refresh() in a transition, landed when the transition settles,
|
|
331
|
+
* and its probe is `answering` (the default here): will the app answer?
|
|
332
|
+
* A browser app's refresh is lib/door.js dataChanged() then whenLanded(),
|
|
333
|
+
* and its probe is a changeFeed's: has anything changed?
|
|
210
334
|
*
|
|
211
335
|
* Until 0.5.0 a timer fired every REFRESH_MS whatever was in flight: the
|
|
212
336
|
* probe was guarded, the refresh was not, so a render slower than the
|
|
@@ -223,7 +347,7 @@ function within(promise, ms, timers) {
|
|
|
223
347
|
* (PRESENCE_EVENTS, in the frame): the next sign refreshes at once
|
|
224
348
|
* and the loop goes on. Coming back from hidden is such a sign;
|
|
225
349
|
* - a tick refreshes only when shouldRefresh says so, with the probe's
|
|
226
|
-
*
|
|
350
|
+
* yes, and never while a surface has opted out (REFRESH_OFF).
|
|
227
351
|
*
|
|
228
352
|
* The rules are asked again after the probe: typing may have started, or
|
|
229
353
|
* the tab changed, while it was on its way.
|