makersclaw 0.5.2 → 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 +73 -7
- package/package.json +3 -2
- 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 +65 -9
- package/src/install.mjs +360 -21
- package/src/lockfile.mjs +468 -0
- package/src/pm.mjs +473 -0
- package/src/registry.mjs +125 -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 +818 -82
- package/templates/next/files/app/claw-alive/route.js +2 -2
- package/templates/next/files/app/frame.js +134 -9
- package/templates/next/files/app/layout.jsx +2 -2
- package/templates/next/files/check/run.mjs +1491 -53
- 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 +171 -52
- 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 +120 -30
- 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 +85 -9
- package/templates/next/files/package.json +3 -3
- package/templates/next/files/{middleware.js → proxy.js} +13 -6
- package/templates/next/files/surfaces.js +3 -2
- package/templates/next/pnpm-lock.yaml +5870 -0
- package/templates/next/template.json +13 -6
- package/templates/next/files/schema.sql +0 -22
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import "./globals.css";
|
|
2
|
+
import { Examples } from "../components/parts/fixture";
|
|
3
|
+
import { surfaceNav } from "../surfaces";
|
|
4
|
+
import AutoRefresh from "./auto-refresh";
|
|
5
|
+
import ErrorRelay from "./error-relay";
|
|
6
|
+
import EscapeRelay from "./escape-relay";
|
|
7
|
+
import Shell from "./shell";
|
|
8
|
+
|
|
9
|
+
// FIXED — the platform agent does not edit this file. Design lives in
|
|
10
|
+
// app/shell.jsx and the surfaces; colour lives nowhere in the app.
|
|
11
|
+
//
|
|
12
|
+
// A browser app's layout (makersclaw.json "mode": "browser"). The app is
|
|
13
|
+
// files: `next build` prerenders every page once, with `output: "export"`
|
|
14
|
+
// (next.config.mjs), and the platform serves what it wrote. So nothing
|
|
15
|
+
// here reads the request. There is no request: no headers(), no
|
|
16
|
+
// cookies(), and no `dynamic` export, which an export refuses anyway.
|
|
17
|
+
// Everything the server layout decides per request is decided here at
|
|
18
|
+
// build, or in the browser.
|
|
19
|
+
export const metadata = { title: process.env.CLAW_PRODUCT || "Artifact" };
|
|
20
|
+
|
|
21
|
+
// The theme, decided in the browser before the body paints. It follows
|
|
22
|
+
// the desk: the OS window opens the app with ?theme=light|dark, and the
|
|
23
|
+
// product proxy keeps that query through its redirect and sets the
|
|
24
|
+
// claw_theme cookie (Path=/, readable here) on the same answer, so every
|
|
25
|
+
// later page reads the cookie. Dark when neither says: the desk is dark,
|
|
26
|
+
// and so is the data-theme the build writes.
|
|
27
|
+
//
|
|
28
|
+
// Why there is no flash: an inline script in <head> runs while the HTML
|
|
29
|
+
// is parsed, before anything paints, and _claw/theme.css after it still
|
|
30
|
+
// blocks the first paint. suppressHydrationWarning on <html> covers the
|
|
31
|
+
// one attribute React then finds changed. Anything that throws (a
|
|
32
|
+
// browser with cookies off) leaves the build's dark.
|
|
33
|
+
//
|
|
34
|
+
// A plain string, not a function turned into one: what runs is exactly
|
|
35
|
+
// what test/browser.test.mjs runs against a fake document.
|
|
36
|
+
const THEME = `(function () {
|
|
37
|
+
try {
|
|
38
|
+
var d = document.documentElement;
|
|
39
|
+
var q = new URLSearchParams(location.search).get("theme");
|
|
40
|
+
var m = document.cookie.match(/(?:^|; )claw_theme=(light|dark)(?:;|$)/);
|
|
41
|
+
d.dataset.theme = q === "light" || q === "dark" ? q : m ? m[1] : "dark";
|
|
42
|
+
} catch (e) {}
|
|
43
|
+
})();`;
|
|
44
|
+
|
|
45
|
+
// <html> carries what the browser-side code reads: the base path for
|
|
46
|
+
// lib/claw.js, the product name, the mode, the examples decision and
|
|
47
|
+
// data-theme.
|
|
48
|
+
//
|
|
49
|
+
// The palette follows the WORKSPACE: <head> links `_claw/theme.css`, the
|
|
50
|
+
// preset picked in System Settings → Appearance, served by the platform
|
|
51
|
+
// with the page's own cookie as identity. app/globals.css holds the same
|
|
52
|
+
// preset as defaults for a run with nothing serving it (a local `next
|
|
53
|
+
// dev`, where the link 404s harmlessly). The href is prefixed by hand:
|
|
54
|
+
// Next's basePath applies to next/link and assets, not to a literal
|
|
55
|
+
// <link>.
|
|
56
|
+
//
|
|
57
|
+
// Examples (components/parts/fixture.jsx) are off inside a workspace, by
|
|
58
|
+
// the server layout's own expression, read here at build: the platform
|
|
59
|
+
// builds every browser app with its CLAW_ARTIFACT_ID, and its publish
|
|
60
|
+
// refuses an export that says data-claw-examples="1". The store's own
|
|
61
|
+
// loop builds without one, and shows its examples. The title and
|
|
62
|
+
// data-claw-product are the name at build: a rename reaches them at the
|
|
63
|
+
// next ship.
|
|
64
|
+
export default function RootLayout({ children }) {
|
|
65
|
+
const basePath = process.env.CLAW_BASE_PATH || "";
|
|
66
|
+
const name = process.env.CLAW_PRODUCT || "Artifact";
|
|
67
|
+
const examples = process.env.CLAW_EXAMPLES === "1" || !process.env.CLAW_ARTIFACT_ID;
|
|
68
|
+
return (
|
|
69
|
+
<html
|
|
70
|
+
lang="en"
|
|
71
|
+
data-claw-base-path={basePath}
|
|
72
|
+
data-claw-product={name}
|
|
73
|
+
data-claw-mode="browser"
|
|
74
|
+
data-claw-examples={examples ? "1" : "0"}
|
|
75
|
+
data-theme="dark"
|
|
76
|
+
suppressHydrationWarning
|
|
77
|
+
>
|
|
78
|
+
<head>
|
|
79
|
+
<script dangerouslySetInnerHTML={{ __html: THEME }} />
|
|
80
|
+
<link rel="stylesheet" href={`${basePath}/_claw/theme.css`} />
|
|
81
|
+
</head>
|
|
82
|
+
<body>
|
|
83
|
+
<AutoRefresh />
|
|
84
|
+
<ErrorRelay />
|
|
85
|
+
<EscapeRelay />
|
|
86
|
+
<Examples allowed={examples}>
|
|
87
|
+
<Shell name={name} surfaces={surfaceNav()}>
|
|
88
|
+
{children}
|
|
89
|
+
</Shell>
|
|
90
|
+
</Examples>
|
|
91
|
+
</body>
|
|
92
|
+
</html>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { homeSurface } from "../surfaces";
|
|
2
|
+
|
|
3
|
+
// FIXED — the platform agent does not edit this file.
|
|
4
|
+
//
|
|
5
|
+
// A browser app's "/" (makersclaw.json "mode": "browser"). As in a server
|
|
6
|
+
// app it is never a page of its own: it sends the viewer to the home
|
|
7
|
+
// surface, the entry flagged `home` in surfaces.js, else the first one.
|
|
8
|
+
// Here the answer is decided once, at build.
|
|
9
|
+
//
|
|
10
|
+
// Not a redirect(). Under output "export" a redirect thrown while "/"
|
|
11
|
+
// prerenders turns the exported index.html into Next's error shell
|
|
12
|
+
// (<html id="__next_error__">, seen on 16.3.7): no layout, so no head
|
|
13
|
+
// script and no palette link. The browser then reaches the home surface
|
|
14
|
+
// by a client navigation, not a page load, so the head script never runs
|
|
15
|
+
// and data-theme stays the build's dark, whatever the desk said. Every
|
|
16
|
+
// member opens "/" first (the desk opens the app's home).
|
|
17
|
+
//
|
|
18
|
+
// So "/" is an ordinary page, rendered through the layout (its theme
|
|
19
|
+
// script and _claw/theme.css are in the HTML), that forwards:
|
|
20
|
+
// 1. a script, run as the HTML is parsed: location.replace to the home
|
|
21
|
+
// surface, keeping the query (?theme=, ?row=) and the hash. A full
|
|
22
|
+
// page load, so the surface's own head script runs.
|
|
23
|
+
// 2. <meta http-equiv="refresh"> for a browser with no JavaScript. The
|
|
24
|
+
// browser acts on it only once the page has loaded, so the script
|
|
25
|
+
// goes first. React puts the <meta> in <head>.
|
|
26
|
+
// The href is prefixed by hand: Next's basePath applies to next/link,
|
|
27
|
+
// not to a literal URL.
|
|
28
|
+
//
|
|
29
|
+
// With no entry at all there is nowhere to send the viewer, so the page
|
|
30
|
+
// says so instead of forwarding to /s/undefined. Plain Tailwind: this
|
|
31
|
+
// page is seen for seconds, before the platform agent writes the
|
|
32
|
+
// manifest.
|
|
33
|
+
export default function Home() {
|
|
34
|
+
const home = homeSurface();
|
|
35
|
+
if (home) {
|
|
36
|
+
const to = `${process.env.CLAW_BASE_PATH || ""}/s/${encodeURIComponent(home.key)}`;
|
|
37
|
+
return (
|
|
38
|
+
<>
|
|
39
|
+
<meta httpEquiv="refresh" content={`0;url=${to}`} />
|
|
40
|
+
<script dangerouslySetInnerHTML={{ __html: forward(to) }} />
|
|
41
|
+
<p className="text-sm text-muted-foreground">
|
|
42
|
+
<a href={to}>Open {home.label}</a>
|
|
43
|
+
</p>
|
|
44
|
+
</>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
return (
|
|
48
|
+
<div className="max-w-prose">
|
|
49
|
+
<p className="text-xs uppercase tracking-wide text-muted-foreground">Empty</p>
|
|
50
|
+
<h1 className="mt-1 text-lg font-semibold">No surfaces yet.</h1>
|
|
51
|
+
<p className="mt-2 text-sm text-muted-foreground">Makersclaw is listing them.</p>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The forwarding script. `to` is a JSON string, with `<` escaped so no
|
|
57
|
+
* key can close the <script> it sits in. */
|
|
58
|
+
function forward(to) {
|
|
59
|
+
return `location.replace(${JSON.stringify(to).replace(/</g, "\\u003c")} + location.search + location.hash);`;
|
|
60
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Suspense } from "react";
|
|
2
|
+
import { notFound } from "next/navigation";
|
|
3
|
+
import surfaces from "../../../surfaces";
|
|
4
|
+
|
|
5
|
+
// FIXED — the platform agent does not edit this file.
|
|
6
|
+
//
|
|
7
|
+
// A browser app's surface route (makersclaw.json "mode": "browser"). Every
|
|
8
|
+
// surface is a file: the build prerenders /s/<key> once per manifest
|
|
9
|
+
// entry, and a key that is not in the manifest is no page at all.
|
|
10
|
+
export const dynamicParams = false;
|
|
11
|
+
|
|
12
|
+
// The page a browser app builds while its manifest is empty. Next refuses
|
|
13
|
+
// a dynamic route whose list is empty under export, so an app with no
|
|
14
|
+
// surfaces yet builds this one page, which says so.
|
|
15
|
+
const NONE = "_none";
|
|
16
|
+
|
|
17
|
+
export function generateStaticParams() {
|
|
18
|
+
const keys = surfaces.map((s) => ({ key: s.key }));
|
|
19
|
+
return keys.length ? keys : [{ key: NONE }];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function generateMetadata({ params }) {
|
|
23
|
+
const { key } = await params;
|
|
24
|
+
const s = surfaces.find((x) => x.key === key);
|
|
25
|
+
const name = process.env.CLAW_PRODUCT || "Artifact";
|
|
26
|
+
return { title: s ? `${s.label} · ${name}` : name };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// One route for every surface. A manifest entry without a component is
|
|
30
|
+
// planned (the platform agent has named it but not built it yet) and
|
|
31
|
+
// says so; a built one renders its component with the entry's plain
|
|
32
|
+
// data (never the component itself: a client surface cannot receive a
|
|
33
|
+
// function).
|
|
34
|
+
//
|
|
35
|
+
// A page built once, as a file, has no request, so a surface gets no
|
|
36
|
+
// searchParams: it reads ?row= and the rest with useSearchParams(). A
|
|
37
|
+
// prerendered client component that reads useSearchParams outside a
|
|
38
|
+
// Suspense boundary fails the build, so the surface renders inside one.
|
|
39
|
+
// The export holds its fallback; the browser then renders the surface
|
|
40
|
+
// with the page's query, and its hooks read the rows through the door.
|
|
41
|
+
export default async function SurfacePage({ params }) {
|
|
42
|
+
const { key } = await params;
|
|
43
|
+
const s = surfaces.find((x) => x.key === key);
|
|
44
|
+
if (!s) {
|
|
45
|
+
if (key === NONE) return <NoSurfaces />;
|
|
46
|
+
notFound();
|
|
47
|
+
}
|
|
48
|
+
if (!s.component) return <Planned surface={s} />;
|
|
49
|
+
const Surface = s.component;
|
|
50
|
+
return (
|
|
51
|
+
<Suspense fallback={<SurfaceLoading />}>
|
|
52
|
+
<Surface surface={{ key: s.key, kind: s.kind ?? null, label: s.label, source: s.source ?? null }} />
|
|
53
|
+
</Suspense>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// What a surface shows until the browser renders it: one quiet line, the
|
|
58
|
+
// template's own, so a slow first paint never reads as an empty table.
|
|
59
|
+
function SurfaceLoading() {
|
|
60
|
+
return (
|
|
61
|
+
<p role="status" className="text-sm text-muted-foreground">
|
|
62
|
+
Loading…
|
|
63
|
+
</p>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function NoSurfaces() {
|
|
68
|
+
return (
|
|
69
|
+
<div className="max-w-prose">
|
|
70
|
+
<p className="text-xs uppercase tracking-wide text-muted-foreground">Empty</p>
|
|
71
|
+
<h1 className="mt-1 text-lg font-semibold">No surfaces yet.</h1>
|
|
72
|
+
<p className="mt-2 text-sm text-muted-foreground">Makersclaw is listing them.</p>
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function Planned({ surface }) {
|
|
78
|
+
return (
|
|
79
|
+
<div className="max-w-prose">
|
|
80
|
+
<p className="text-xs uppercase tracking-wide text-muted-foreground">Planned</p>
|
|
81
|
+
<h1 className="mt-1 text-lg font-semibold">Makersclaw is building this</h1>
|
|
82
|
+
<p className="mt-2 text-sm text-muted-foreground">
|
|
83
|
+
{surface.label}
|
|
84
|
+
{surface.kind ? ` will be a ${surface.kind}` : null}
|
|
85
|
+
{surface.source ? (
|
|
86
|
+
<>
|
|
87
|
+
{" "}
|
|
88
|
+
over <code className="font-mono text-xs">{surface.source}</code>
|
|
89
|
+
</>
|
|
90
|
+
) : null}
|
|
91
|
+
. It appears here as soon as it is built.
|
|
92
|
+
</p>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// A browser app's writes (makersclaw.json "mode": "browser"). The same names
|
|
2
|
+
// and shapes as a server app's lib/actions.js, so a surface keeps
|
|
3
|
+
// `import { updateRow } from "../lib/actions"`; here they are plain
|
|
4
|
+
// functions of the browser that go through the platform's data door
|
|
5
|
+
// (lib/door.js), not Server Actions: a browser app has no server of its
|
|
6
|
+
// own. Call them from "use client" files.
|
|
7
|
+
//
|
|
8
|
+
// Each resolves { ok } (insertRow { ok, id }, runAction { ok, result })
|
|
9
|
+
// or { ok: false, error, code }, and never throws. They go one at a time,
|
|
10
|
+
// in the order called. The door runs each in a transaction that knows
|
|
11
|
+
// the member (claw.member_id, claw.member_email) and writes its activity
|
|
12
|
+
// line, so nothing here logs. `surface` defaults to the <key> of /s/<key>
|
|
13
|
+
// in the page's path. A write that answers ok calls dataChanged(), and
|
|
14
|
+
// every hook on the page reads again.
|
|
15
|
+
|
|
16
|
+
export { deleteRow, insertRow, moveRow, runAction, saveSetting, updateRow } from "./door";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { surfaceOfPath } from "./platform";
|
|
2
|
+
|
|
3
|
+
// A browser app's reads (makersclaw.json "mode": "browser"). The same names
|
|
4
|
+
// and shapes as a server app's lib/data.js, so a surface keeps
|
|
5
|
+
// `import { loadRows } from "../lib/data"`; here they run in the browser
|
|
6
|
+
// and go through the platform's data door (lib/door.js), which knows who
|
|
7
|
+
// is asking. So there is no pg, no next/headers and no server action
|
|
8
|
+
// here: a browser app has no server of its own. Call them from "use
|
|
9
|
+
// client" files. Each read resolves { …, error } and never throws.
|
|
10
|
+
//
|
|
11
|
+
// Also here: the hooks, which read on mount and again on dataChanged()
|
|
12
|
+
// (every write that answers ok calls it), and whenLanded(), which waits
|
|
13
|
+
// for those reads.
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
countBy,
|
|
17
|
+
countRows,
|
|
18
|
+
dataChanged,
|
|
19
|
+
loadActivity,
|
|
20
|
+
loadRow,
|
|
21
|
+
loadRows,
|
|
22
|
+
useActivity,
|
|
23
|
+
useCount,
|
|
24
|
+
useCountBy,
|
|
25
|
+
useRow,
|
|
26
|
+
useRows,
|
|
27
|
+
whenLanded,
|
|
28
|
+
} from "./door";
|
|
29
|
+
|
|
30
|
+
/** Sample rows get stable ids and a `_sample: true` marker (lib/sample.js,
|
|
31
|
+
* pure), as in a server app. */
|
|
32
|
+
export { markSample } from "./sample";
|
|
33
|
+
|
|
34
|
+
/** The surface key of the page: the caller's (a string, or the page's
|
|
35
|
+
* `surface` object), else the <key> of /s/<key> in the page's path.
|
|
36
|
+
* null when there is none. A server app reads it from the request; a
|
|
37
|
+
* browser app's page is a file and has none, so it reads the path. */
|
|
38
|
+
export function currentSurface(explicit) {
|
|
39
|
+
if (typeof explicit === "string" && explicit) return explicit;
|
|
40
|
+
if (explicit && typeof explicit === "object" && typeof explicit.key === "string" && explicit.key) return explicit.key;
|
|
41
|
+
if (typeof location === "undefined") return null;
|
|
42
|
+
return surfaceOfPath(location.pathname) || null;
|
|
43
|
+
}
|