@plitzi/sdk-shared 0.38.6 → 0.38.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +381 -0
  2. package/dist/authoring/declare.d.ts +1 -1
  3. package/dist/authoring/index.mjs +4 -4
  4. package/dist/authoring/paramSpec.d.ts +2 -1
  5. package/dist/authoring/paramSpec.mjs +20 -11
  6. package/dist/dataSource/globalSources.d.ts +34 -1
  7. package/dist/dataSource/globalSources.mjs +22 -2
  8. package/dist/dataSource/hooks/index.d.ts +2 -1
  9. package/dist/dataSource/hooks/index.mjs +2 -1
  10. package/dist/dataSource/hooks/useResolvedVariables.d.ts +12 -0
  11. package/dist/dataSource/hooks/useResolvedVariables.mjs +28 -0
  12. package/dist/dataSource/index.mjs +2 -1
  13. package/dist/dataSource/resolveVariables.d.ts +2 -2
  14. package/dist/devTools/chrome.d.ts +1 -1
  15. package/dist/flags/useFlagResolution.mjs +6 -6
  16. package/dist/helpers/canonicalJson.d.ts +6 -0
  17. package/dist/helpers/canonicalJson.mjs +5 -0
  18. package/dist/index.mjs +62 -58
  19. package/dist/network/spaceEvents.d.ts +31 -1
  20. package/dist/network/spaceEvents.mjs +150 -147
  21. package/dist/project/layout.d.ts +197 -0
  22. package/dist/project/layout.mjs +394 -0
  23. package/dist/project/paths.d.ts +84 -0
  24. package/dist/project/paths.mjs +4 -0
  25. package/dist/project/root.d.ts +24 -0
  26. package/dist/project/root.mjs +26 -0
  27. package/dist/queries/index.d.ts +12 -2
  28. package/dist/queries/index.mjs +27 -17
  29. package/dist/queries/serverQueries.d.ts +22 -0
  30. package/dist/queries/serverQueries.mjs +9 -0
  31. package/dist/queries/useServerQuery.d.ts +19 -0
  32. package/dist/queries/useServerQuery.mjs +21 -0
  33. package/dist/server/rsc/refreshRsc.d.ts +22 -10
  34. package/dist/server/rsc/refreshRsc.mjs +65 -53
  35. package/dist/server/rsc/useRscRefresh.d.ts +2 -1
  36. package/dist/server/rsc/useRscRefresh.mjs +1 -1
  37. package/dist/source/export.d.ts +2 -2
  38. package/dist/source/import.d.ts +1 -1
  39. package/dist/store/index.d.ts +45 -45
  40. package/dist/style/cssLayers.d.ts +1 -1
  41. package/dist/style/index.d.ts +3 -0
  42. package/dist/style/index.mjs +5 -2
  43. package/dist/style/keyframes.d.ts +39 -0
  44. package/dist/style/keyframes.mjs +41 -0
  45. package/dist/style/notifications.d.ts +34 -12
  46. package/dist/style/notifications.mjs +69 -32
  47. package/dist/style/styleConditions.d.ts +43 -0
  48. package/dist/style/styleConditions.mjs +29 -0
  49. package/dist/style/styleConstants.d.ts +3 -2
  50. package/dist/style/styleConstants.mjs +2 -0
  51. package/dist/style/stylePseudos.d.ts +40 -0
  52. package/dist/style/stylePseudos.mjs +109 -0
  53. package/dist/style/styleStates.d.ts +35 -8
  54. package/dist/style/styleStates.mjs +38 -15
  55. package/dist/style/styleTarget.d.ts +23 -0
  56. package/dist/style/styleTarget.mjs +35 -0
  57. package/dist/types/AuthTypes.d.ts +5 -0
  58. package/dist/types/CommonTypes.d.ts +12 -0
  59. package/dist/types/SchemaTypes.d.ts +2 -0
  60. package/dist/types/ServerTypes.d.ts +11 -4
  61. package/dist/types/StoreTypes.d.ts +5 -1
  62. package/dist/types/StyleTypes.d.ts +20 -2
  63. package/package.json +46 -2
@@ -0,0 +1,84 @@
1
+ /**
2
+ * The layout of a project `@plitzi/cli` writes, relative to its root: the one place the CLI that writes and checks it,
3
+ * the server that serves it (`@plitzi/sdk-server/project`) and the authoring that checks its space
4
+ * (`@plitzi/sdk-authoring/node`'s `projectAuthoring`) read it from.
5
+ *
6
+ * `tmp/` is what the project writes for itself, never committed, everything in it rebuilt when it is missing — the
7
+ * server's plugin bundles (`tmp/.sdk-plugins`) and resized pictures (`tmp/images`), both `@plitzi/sdk-server`'s
8
+ * defaults, beside what the files below name. One folder, so a reader of the project — a person, an agent — knows at a
9
+ * glance what is the project and what is a by-product of running it.
10
+ */
11
+ export declare const PROJECT_TMP = "tmp";
12
+ /** The project's own code — its space, plugins, data, functions and server — which the server watches while developing. */
13
+ export declare const SOURCE_DIR = "src";
14
+ /**
15
+ * The CLI's own part of a project — the script that authors the space, the types its plugins import besides code, the
16
+ * page's base styles — apart from `src/`, which is the project's: `plitzi upgrade` keeps this folder current, and a
17
+ * person reads `src/` without wading through it.
18
+ */
19
+ export declare const CLI_DIR = "plitzi";
20
+ /**
21
+ * What authors the space and says what it found: `npm run author`, and the server's re-authoring on a save, which runs
22
+ * it in a process of its own and is handed the documents over IPC (`--ipc`).
23
+ */
24
+ export declare const AUTHOR_FILE = "plitzi/author.ts";
25
+ /**
26
+ * The space, in a folder of its own — it grows a page, a layout, a component at a time — whose `index.ts` exports it as
27
+ * `space`: what the server's entry point, the author script, the visual test and the CLI's checks import.
28
+ */
29
+ export declare const SPACE_DIR = "src/space";
30
+ export declare const SPACE_ENTRY = "src/space/index.ts";
31
+ /**
32
+ * The project's own components: every folder is one, registered under its name in camelCase — `src/plugins/StatCard`
33
+ * renders a space's `custom({ renderType: 'statCard' })` — built from its entry (`PLUGIN_ENTRIES`) and declared by its
34
+ * `declaration.ts`.
35
+ */
36
+ export declare const PLUGINS_DIR = "src/plugins";
37
+ /**
38
+ * What a plugin folder is built from: `index.ts`, or `index.tsx` for one that writes its JSX there — TypeScript both,
39
+ * and one of them, never both.
40
+ */
41
+ export declare const PLUGIN_ENTRIES: readonly ["index.ts", "index.tsx"];
42
+ /** What a plugin folder declares itself in — its type, attributes, triggers — as `plitzi plugin add` writes it. */
43
+ export declare const PLUGIN_DECLARATION_FILE = "declaration.ts";
44
+ /** A plugin's server half, a folder of its own beside its component: built from its `index.ts`. */
45
+ export declare const PLUGIN_FUNCTIONS_DIR = "functions";
46
+ /**
47
+ * Plugins no source of was kept, as they were built (a project made from a space): `vendor/plugins/<type>/`, each
48
+ * beside the manifest it was published with (`PLUGIN_MANIFEST_FILE`).
49
+ */
50
+ export declare const VENDOR_PLUGINS_DIR = "vendor/plugins";
51
+ /** What `plitzi plugin pack` writes beside a plugin's bundle: its version, its files, and the elements it provides. */
52
+ export declare const PLUGIN_MANIFEST_FILE = "plugin-manifest.json";
53
+ /** A runtime that came across built only (a project made from a space): run as it was built. */
54
+ export declare const RUNTIME_BUNDLE = "vendor/runtime.bundle";
55
+ /** Served to anyone as it is: pictures, a favicon — every file in it is on the internet once the project is deployed. */
56
+ export declare const PUBLIC_DIR = "public";
57
+ /**
58
+ * The project's own data, server mode: JSON its server reads (`dataDir`) and never serves — a provider asks for
59
+ * `/data/<file>` on the server. A project with no server keeps it in `public/data/`, where the browser fetches it.
60
+ */
61
+ export declare const DATA_DIR = "src/data";
62
+ /** The project's own server code — the tasks and `/fn/` routes `defineFunctions` declares — built at boot. */
63
+ export declare const FUNCTIONS_DIR = "src/functions";
64
+ /**
65
+ * The space's runtime — its own server code, run as a process of its own on Plitzi and by the project's server in its
66
+ * process — a folder like the space, whose `index.ts` exports it.
67
+ */
68
+ export declare const RUNTIME_DIR = "src/runtime";
69
+ export declare const RUNTIME_ENTRY = "src/runtime/index.ts";
70
+ /**
71
+ * What `npm run build` compiles `src/` into — the server's own code, as JavaScript, for `start:prod` to run with no
72
+ * TypeScript in the process. The same tree: `src/runtime/index.ts` is `dist/runtime/index.js`.
73
+ */
74
+ export declare const BUILD_DIR = "dist";
75
+ /**
76
+ * What the running server keeps for the space — its `kv`: saved layouts, counters, a source's cached answer. Not
77
+ * committed either, but not a by-product: it is the deployment's state, so it is never rebuilt and `tmp/` is no place
78
+ * for it. A deployment that keeps it elsewhere says so in `src/config/serverOptions.ts` (`action.kv`).
79
+ */
80
+ export declare const PROJECT_STATE = "state";
81
+ /** The `kv` a project's server keeps, as one JSON file (`createFileKv`). */
82
+ export declare const KV_FILE = "state/kv.json";
83
+ /** The port the server took and the name its `/health` answers with: what `check`, `shot` and `visual` find it by. */
84
+ export declare const DEV_SERVER_FILE = "tmp/dev-server.json";
@@ -0,0 +1,4 @@
1
+ //#region src/project/paths.ts
2
+ var e = "tmp", t = "src", n = "plitzi", r = `${n}/author.ts`, i = "src/space", a = `${i}/index.ts`, o = "src/plugins", s = ["index.ts", "index.tsx"], c = "declaration.ts", l = "functions", u = "vendor/plugins", d = "plugin-manifest.json", f = "vendor/runtime.bundle", p = "public", m = "src/data", h = "src/functions", g = "src/runtime", _ = `${g}/index.ts`, v = "dist", y = "state", b = `${y}/kv.json`, x = "tmp/dev-server.json";
3
+ //#endregion
4
+ export { r as AUTHOR_FILE, v as BUILD_DIR, n as CLI_DIR, m as DATA_DIR, x as DEV_SERVER_FILE, h as FUNCTIONS_DIR, b as KV_FILE, o as PLUGINS_DIR, c as PLUGIN_DECLARATION_FILE, s as PLUGIN_ENTRIES, l as PLUGIN_FUNCTIONS_DIR, d as PLUGIN_MANIFEST_FILE, y as PROJECT_STATE, e as PROJECT_TMP, p as PUBLIC_DIR, f as RUNTIME_BUNDLE, g as RUNTIME_DIR, _ as RUNTIME_ENTRY, t as SOURCE_DIR, i as SPACE_DIR, a as SPACE_ENTRY, u as VENDOR_PLUGINS_DIR };
@@ -0,0 +1,24 @@
1
+ /** A process started outside the project's root: its message names what is missing, and where to run it instead. */
2
+ export declare class ProjectRootError extends Error {
3
+ constructor(root: string, missing: readonly string[]);
4
+ }
5
+ /**
6
+ * `root`, when it is the root of a project `@plitzi/cli` writes; refused otherwise, naming what it lacks. What
7
+ * `projectRoot` holds the working directory to — and what a tool working on a project from another folder (the CLI, run
8
+ * anywhere inside one) holds the root it found to.
9
+ */
10
+ export declare const checkProjectRoot: (root: string) => string;
11
+ /**
12
+ * The root of the project this process runs: its working directory. Every script of the project's `package.json` runs
13
+ * there, and a deployment starts `node dist/main.js` there too — so the root is never worked out from where a file is,
14
+ * and a process started from anywhere else is refused, saying what is missing (`checkProjectRoot`).
15
+ */
16
+ export declare const projectRoot: () => string;
17
+ /**
18
+ * Where a module of the project's source (`entry`, under `src/` — `src/space/index.ts`) is, in the form the process
19
+ * runs in: what `build` emitted (`dist/space/index.js`) when it was started on that — `node dist/main.js`, which carries
20
+ * no TypeScript at all — and the source otherwise. Told by the script the process was started with (`script`,
21
+ * `process.argv[1]`), followed through any link, rather than by `NODE_ENV`: a production server run from its source
22
+ * still finds the source, and one run compiled never imports a `.ts` file.
23
+ */
24
+ export declare const projectModule: (root: string, entry: string, script: string | undefined) => string;
@@ -0,0 +1,26 @@
1
+ import { BUILD_DIR as e } from "./paths.mjs";
2
+ import t from "node:path";
3
+ import { existsSync as n, realpathSync as r } from "node:fs";
4
+ //#region src/project/root.ts
5
+ var i = ["package.json", "src/"], a = class extends Error {
6
+ constructor(e, t) {
7
+ super(`${e} is not the root of a Plitzi project: it has no ${t.join(" and no ")}. Run it from the project's root, the folder its package.json is in — where its scripts run it (npm start, npm run author).`), this.name = "ProjectRootError";
8
+ }
9
+ };
10
+ Object.defineProperty(a, "name", { value: "ProjectRootError" });
11
+ var o = (e) => {
12
+ let r = i.filter((r) => !n(t.join(e, r)));
13
+ if (r.length > 0) throw new a(e, r);
14
+ return e;
15
+ }, s = () => o(process.cwd()), c = (e) => {
16
+ try {
17
+ return r(e);
18
+ } catch {
19
+ return t.resolve(e);
20
+ }
21
+ }, l = (n, r, i) => {
22
+ let a = c(t.join(n, e)), o = i !== void 0 && c(i).startsWith(`${a}${t.sep}`);
23
+ return t.join(n, o ? t.join(e, t.relative("src", r)).replace(/\.tsx?$/, ".js") : r);
24
+ };
25
+ //#endregion
26
+ export { a as ProjectRootError, o as checkProjectRoot, l as projectModule, s as projectRoot };
@@ -1,10 +1,15 @@
1
1
  import { default as queryCache, QueryMeta } from './queryCache';
2
2
  export { QueryCache, GC_TIME, queryId, queryPath } from './queryCache';
3
+ export { registerServerQuery } from './serverQueries';
3
4
  export { default as useQuery } from './useQuery';
5
+ export { default as useServerQuery } from './useServerQuery';
4
6
  export type { QueriesState, QueryEntry, QueryMeta, QueryObserverOptions } from './queryCache';
7
+ export type { ServerQuery } from './serverQueries';
5
8
  export type { UseQueryOptions, UseQueryResult } from './useQuery';
9
+ export type { UseServerQueryOptions } from './useServerQuery';
6
10
  /**
7
- * Every query that could have read what `url` just wrote: the ones on the same origin.
11
+ * Every query that could have read what `url` just wrote: the ones on the same origin — a server provider's too, when
12
+ * it reads a URL.
8
13
  *
9
14
  * The origin, not the path: `POST /api/cart/items` changes what `GET /api/cart` answers, and no path rule tells
10
15
  * those apart from two unrelated resources. Another origin is another backend, and nothing it writes shows up here.
@@ -25,7 +30,12 @@ export type QuerySelector = {
25
30
  * template nobody can write down.
26
31
  */
27
32
  export declare const matchesQuery: ({ url, elements }: QuerySelector) => (meta: QueryMeta) => boolean;
28
- /** The `invalidateQueries` step, and anything else that knows which data changed. */
33
+ /**
34
+ * The `invalidateQueries` step, and anything else that knows which data changed.
35
+ *
36
+ * Both halves of the page's data: the cached browser requests, and the providers the page server answers, which
37
+ * never pass through the cache. Either is marked and asks when shown if nobody is looking at it now.
38
+ */
29
39
  export declare const invalidateQueries: (selector?: QuerySelector) => Promise<void>;
30
40
  /**
31
41
  * One key for one request, whoever makes it — an api container and a webhook step asking the same thing share the
@@ -1,37 +1,47 @@
1
1
  import e, { GC_TIME as t, QueryCache as n, queryId as r, queryPath as i } from "./queryCache.mjs";
2
- import a from "./useQuery.mjs";
2
+ import { refreshServerQueries as a, registerServerQuery as o } from "./serverQueries.mjs";
3
+ import s from "./useQuery.mjs";
4
+ import c from "./useServerQuery.mjs";
3
5
  //#region src/queries/index.ts
4
- var o = () => typeof location > "u" ? void 0 : location.href, s = (e) => {
6
+ var l = () => typeof location > "u" ? void 0 : location.href, u = (e) => {
5
7
  try {
6
- return new URL(e, o()).origin;
8
+ return new URL(e, l()).origin;
7
9
  } catch {
8
10
  return;
9
11
  }
10
- }, c = (t) => {
11
- let n = s(t);
12
- return n ? e.invalidate((e) => s(e.url) === n) : Promise.resolve();
13
- }, l = (e) => Array.isArray(e) ? e.filter((e) => typeof e == "string" && e.trim() !== "").map((e) => e.trim()) : typeof e == "string" ? e.split(",").map((e) => e.trim()).filter(Boolean) : [], u = (e) => {
12
+ }, d = (e, t) => ({ id: n, url: r }) => (!t || r !== void 0) && e({
13
+ url: r ?? "",
14
+ tags: [n]
15
+ }), f = (t) => {
16
+ let n = u(t);
17
+ if (!n) return Promise.resolve();
18
+ let r = (e) => u(e.url) === n;
19
+ return Promise.all([e.invalidate(r), a(d(r, !0))]).then(() => void 0);
20
+ }, p = (e) => Array.isArray(e) ? e.filter((e) => typeof e == "string" && e.trim() !== "").map((e) => e.trim()) : typeof e == "string" ? e.split(",").map((e) => e.trim()).filter(Boolean) : [], m = (e) => {
14
21
  try {
15
- return new URL(e, o()).href;
22
+ return new URL(e, l()).href;
16
23
  } catch {
17
24
  return e;
18
25
  }
19
- }, d = ({ url: e, elements: t }) => {
20
- let n = e ? u(e) : void 0;
21
- return (e) => (n === void 0 || u(e.url).startsWith(n)) && (!t?.length || t.some((t) => e.tags?.includes(t) ?? !1));
22
- }, f = (t = {}) => t.url || t.elements?.length ? e.invalidate(d(t)) : e.invalidate(), p = ({ method: e, url: t, credentials: n, headers: r }) => JSON.stringify([
26
+ }, h = ({ url: e, elements: t }) => {
27
+ let n = e ? m(e) : void 0;
28
+ return (e) => (n === void 0 || m(e.url).startsWith(n)) && (!t?.length || t.some((t) => e.tags?.includes(t) ?? !1));
29
+ }, g = (t = {}) => {
30
+ let n = t.url || t.elements?.length ? h(t) : void 0;
31
+ return Promise.all([e.invalidate(n), a(n && d(n, !!t.url))]).then(() => void 0);
32
+ }, _ = ({ method: e, url: t, credentials: n, headers: r }) => JSON.stringify([
23
33
  e.toLowerCase(),
24
34
  t,
25
35
  n,
26
36
  Object.entries(r).filter(([e]) => e.toLowerCase() !== "content-type").sort(([e], [t]) => e < t ? -1 : +(e > t))
27
- ]), m = ({ mode: e, fallback: t, elements: n, url: r }) => {
37
+ ]), v = ({ mode: e, fallback: t, elements: n, url: r }) => {
28
38
  let i = e === "origin" || e === "all" || e === "elements" || e === "none" ? e : t;
29
39
  if (i === "none") return Promise.resolve();
30
40
  if (i === "elements") {
31
- let e = l(n);
32
- return e.length > 0 ? f({ elements: e }) : Promise.resolve();
41
+ let e = p(n);
42
+ return e.length > 0 ? g({ elements: e }) : Promise.resolve();
33
43
  }
34
- return i === "origin" && r ? c(r) : f();
44
+ return i === "origin" && r ? f(r) : g();
35
45
  };
36
46
  //#endregion
37
- export { t as GC_TIME, n as QueryCache, m as invalidateAfterWrite, f as invalidateQueries, c as invalidateQueriesForWrite, d as matchesQuery, l as parseIds, e as queryCache, r as queryId, i as queryPath, p as requestKey, a as useQuery };
47
+ export { t as GC_TIME, n as QueryCache, v as invalidateAfterWrite, g as invalidateQueries, f as invalidateQueriesForWrite, h as matchesQuery, p as parseIds, e as queryCache, r as queryId, i as queryPath, o as registerServerQuery, _ as requestKey, s as useQuery, c as useServerQuery };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * A query the page server answers for a provider (`runtime: 'server'`), as the invalidations see it.
3
+ *
4
+ * Its answer arrives in the RSC payload, never through the {@link QueryCache}, so an invalidation that only reached
5
+ * the cache left every server-driven list showing what it held before the write.
6
+ */
7
+ export type ServerQuery = {
8
+ /** The provider's element id: what an invalidation naming containers names. */
9
+ id: string;
10
+ /** The URL the server reads for it — only a provider that has nothing but a `query`; a connector or action has none. */
11
+ url?: string;
12
+ /** Asks the server again for this provider's slice, around every cache. */
13
+ refresh: () => Promise<void>;
14
+ };
15
+ /** Makes `query` reachable by the invalidations until the returned function is called. */
16
+ export declare const registerServerQuery: (query: ServerQuery) => (() => void);
17
+ /**
18
+ * Asks again for every server query `matches` accepts — all of them without one.
19
+ *
20
+ * Settled, not all-or-nothing: one provider that could not ask again is its own to report, and the rest still refresh.
21
+ */
22
+ export declare const refreshServerQueries: (matches?: (query: ServerQuery) => boolean) => Promise<void>;
@@ -0,0 +1,9 @@
1
+ //#region src/queries/serverQueries.ts
2
+ var e = /* @__PURE__ */ new Set(), t = (t) => {
3
+ let n = { ...t };
4
+ return e.add(n), () => {
5
+ e.delete(n);
6
+ };
7
+ }, n = (t) => Promise.allSettled([...e].filter((e) => !t || t(e)).map((e) => e.refresh())).then(() => void 0);
8
+ //#endregion
9
+ export { n as refreshServerQueries, t as registerServerQuery };
@@ -0,0 +1,19 @@
1
+ export type UseServerQueryOptions = {
2
+ id: string;
3
+ /** The URL the server reads for a provider that has nothing but a `query`. */
4
+ url?: string;
5
+ /** Whether the provider has a live answer to refresh at all — never in the builder, which has no page server. */
6
+ enabled: boolean;
7
+ /** Whether it is on screen: an invalidation of a hidden one waits until it is shown, as a cached query does. */
8
+ active: boolean;
9
+ refresh: () => Promise<void>;
10
+ };
11
+ /**
12
+ * Keeps a server-driven provider reachable by the invalidations — `invalidateQueries`, and the refresh a write step
13
+ * asks for — for as long as it is mounted and `enabled`.
14
+ *
15
+ * The same saving the cache makes for a hidden query: a provider in a tab nobody is looking at is only marked, and
16
+ * asks when it is shown, so a write does not turn into a request for every section the visitor cannot see.
17
+ */
18
+ declare const useServerQuery: ({ id, url, enabled, active, refresh }: UseServerQueryOptions) => void;
19
+ export default useServerQuery;
@@ -0,0 +1,21 @@
1
+ import { registerServerQuery as e } from "./serverQueries.mjs";
2
+ import { useEffect as t, useRef as n } from "react";
3
+ //#region src/queries/useServerQuery.ts
4
+ var r = ({ id: r, url: i, enabled: a, active: o, refresh: s }) => {
5
+ let c = n(!1);
6
+ t(() => {
7
+ if (a) return o && c.current && (c.current = !1, s()), e({
8
+ id: r,
9
+ url: i,
10
+ refresh: () => o ? s() : (c.current = !0, Promise.resolve())
11
+ });
12
+ }, [
13
+ a,
14
+ o,
15
+ r,
16
+ i,
17
+ s
18
+ ]);
19
+ };
20
+ //#endregion
21
+ export { r as default };
@@ -13,6 +13,25 @@ export declare const currentRscLocation: () => string;
13
13
  export declare const cancelRsc: (store: StoreApi<CommonState>, ids?: readonly string[]) => void;
14
14
  /** Every refresh of this root aborted and forgotten — the SDK root that owned them is going away. */
15
15
  export declare const releaseRscRequests: (instance: string) => void;
16
+ export type RscRefreshOptions = {
17
+ /**
18
+ * Resolve for somewhere the visitor is not yet.
19
+ *
20
+ * A route change that renders first and fetches after paints a page whose sections have no answer, so the
21
+ * navigation asks for the destination BEFORE it commits. Absent means where the visitor already is, which is
22
+ * every other caller: the initial load, a pager, an element refreshing itself.
23
+ */
24
+ location?: string;
25
+ /**
26
+ * Ask the server itself, around the browser's cache and the page server's.
27
+ *
28
+ * Outside `main` an answer is kept for a while on both — the same question from many visitors is resolved once —
29
+ * which is right for a page window and wrong for a refresh that exists because something changed: a write, an
30
+ * explicit reload. Asked through either cache, that refresh is answered with the slice from before the write. A
31
+ * header rather than a query parameter, because every parameter of the request is input to what it resolves.
32
+ */
33
+ fresh?: boolean;
34
+ };
16
35
  /**
17
36
  * Re-fetches RSC data into the store.
18
37
  *
@@ -20,7 +39,8 @@ export declare const releaseRscRequests: (instance: string) => void;
20
39
  * has what it needs through the store it can reach, and an element buried under any number of scopes writes to the
21
40
  * root by delegation (nothing but the root owns `rsc`).
22
41
  *
23
- * Pass `ids` to refresh only those elements — the response is merged over the existing payload. Omit them for a full
42
+ * Pass `requestedIds` to refresh only those elements — the response is merged over the existing payload; of them,
43
+ * only the ones the server resolves at that location are asked for, and none is no request. Omit them for a full
24
44
  * refresh, which replaces it. `params` ride along on the query string; that is how a provider asks for a different
25
45
  * page window.
26
46
  *
@@ -29,13 +49,5 @@ export declare const releaseRscRequests: (instance: string) => void;
29
49
  * again, an element asked for again — is aborted, here and on the server. Before this a click on a link asked twice
30
50
  * (its prefetch, then the route change), and a slow answer could land over a newer one.
31
51
  */
32
- export declare const refreshRsc: (store: StoreApi<CommonState>, ids?: string[], params?: Record<string, string>,
33
- /**
34
- * Resolve for somewhere the visitor is not yet.
35
- *
36
- * A route change that renders first and fetches after paints a page whose sections have no answer, so the
37
- * navigation asks for the destination BEFORE it commits. Absent means where the visitor already is, which is
38
- * every other caller: the initial load, a pager, an element refreshing itself.
39
- */
40
- location?: string) => Promise<void>;
52
+ export declare const refreshRsc: (store: StoreApi<CommonState>, requestedIds?: string[], params?: Record<string, string>, { location, fresh }?: RscRefreshOptions) => Promise<void>;
41
53
  export default refreshRsc;
@@ -1,96 +1,108 @@
1
1
  import { authFailureFromResponse as e, reportAuthFailure as t } from "../../auth/failureChannel.mjs";
2
2
  import { recordRenderActionRuns as n } from "../../store/actionRuns/actionRunsRecorder.mjs";
3
- import { hasServerElements as r } from "../../schema/serverElements.mjs";
4
- import { getPaths as i, matchRoutePath as a } from "../../navigation/routes.mjs";
3
+ import { collectServerElements as r, hasServerElements as i } from "../../schema/serverElements.mjs";
4
+ import { getPaths as a, matchRoutePath as o } from "../../navigation/routes.mjs";
5
5
  //#region src/server/rsc/refreshRsc.ts
6
- var o = (e, t, n) => {
6
+ var s = (e, t, n) => {
7
7
  if (!e) return;
8
8
  let r = e.pages.reduce((t, n) => (n in e.flat && (t[n] = e.flat[n]), t), {});
9
- return a(i(r, e.pageFolders, n), t.split("?")[0], n).pageId;
10
- }, s = (e) => `rsc.data.${e}`, c = () => typeof window > "u" ? "" : `${window.location.pathname}${window.location.search}`, l = "*", u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new WeakMap(), f = () => ({
9
+ return o(a(r, e.pageFolders, n), t.split("?")[0], n).pageId;
10
+ }, c = (e, t, n, i) => {
11
+ let a = new Set(r(e, t, [...n], i).map(({ id: e }) => e));
12
+ return n.filter((e) => a.has(e));
13
+ }, l = (e) => `rsc.data.${e}`, u = () => typeof window > "u" ? "" : `${window.location.pathname}${window.location.search}`, d = "*", f = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new WeakMap(), m = () => ({
11
14
  seq: 0,
12
15
  inFlight: /* @__PURE__ */ new Set(),
13
16
  asked: /* @__PURE__ */ new Map()
14
- }), p = (e) => {
17
+ }), h = (e) => {
15
18
  let t = e.get("rsc.instance");
16
19
  if (typeof t == "string" && t) {
17
- let e = u.get(t);
20
+ let e = f.get(t);
18
21
  if (e) return e;
19
- let n = f();
20
- return u.set(t, n), n;
22
+ let n = m();
23
+ return f.set(t, n), n;
21
24
  }
22
- let n = d.get(e);
25
+ let n = p.get(e);
23
26
  if (n) return n;
24
- let r = f();
25
- return d.set(e, r), r;
26
- }, m = (e, t) => {
27
+ let r = m();
28
+ return p.set(e, r), r;
29
+ }, g = (e, t) => {
27
30
  let n = {};
28
31
  t.inFlight.forEach((e) => {
29
- e.here && (e.ids ?? [l]).forEach((e) => {
32
+ e.here && (e.ids ?? [d]).forEach((e) => {
30
33
  n[e] = !0;
31
34
  });
32
35
  }), e.set("rsc.refreshing", n);
33
- }, h = (e, t) => !e || !!t && t.every((t) => e.includes(t)), g = (e, t) => {
34
- p(e).inFlight.forEach((e) => {
36
+ }, _ = (e, t) => !e || !!t && t.every((t) => e.includes(t)), v = (e, t) => {
37
+ h(e).inFlight.forEach((e) => {
35
38
  (!t || e.ids?.some((e) => t.includes(e))) && e.controller.abort();
36
39
  });
37
- }, _ = (e) => {
38
- u.get(e)?.inFlight.forEach((e) => e.controller.abort()), u.delete(e);
39
- }, v = (e, t, n, r, i) => {
40
+ }, y = (e) => {
41
+ f.get(e)?.inFlight.forEach((e) => e.controller.abort()), f.delete(e);
42
+ }, b = (e, t, n, r, i) => {
40
43
  let { ids: a, seq: o } = n;
41
44
  e.batch(() => {
42
45
  if (a?.length) Object.entries(r).forEach(([n, r]) => {
43
- (t.asked.get(n) ?? 0) <= o && (t.asked.get(l) ?? 0) <= o && e.set(s(n), r);
46
+ (t.asked.get(n) ?? 0) <= o && (t.asked.get(d) ?? 0) <= o && e.set(l(n), r);
44
47
  });
45
48
  else {
46
- let n = e.get("rsc.data") ?? {}, i = (e) => e !== l && (t.asked.get(e) ?? 0) > o, a = Object.fromEntries([...Object.entries(r).filter(([e]) => !i(e)), ...Object.entries(n).filter(([e]) => i(e))]);
49
+ let n = e.get("rsc.data") ?? {}, i = (e) => e !== d && (t.asked.get(e) ?? 0) > o, a = Object.fromEntries([...Object.entries(r).filter(([e]) => !i(e)), ...Object.entries(n).filter(([e]) => i(e))]);
47
50
  e.set("rsc.data", a);
48
51
  }
49
52
  e.set("rsc.loaded", !0), e.set("rsc.stale", !1), e.set("rsc.location", i);
50
53
  });
51
- }, y = async (i, a, s, u) => {
52
- let { enabled: d, endpoint: f } = i.get("rsc") ?? {};
53
- if (!d || !f || typeof window > "u") return;
54
- let g = u ?? c(), _ = i.get("schema"), y = i.get("runtime.sources.auth"), b = u ? o(_, u, !!y?.details) : i.get("navigation.currentPageId"), x = u ? void 0 : i.get("runtime.sources.flags");
55
- if (!_ || !r(_, b, x)) return;
56
- let S = new URLSearchParams({ location: g });
57
- a?.length && S.set("ids", a.join(",")), Object.entries(s ?? {}).forEach(([e, t]) => S.set(e, t));
58
- let C = `${f}?${S.toString()}`, w = p(i), T = [...w.inFlight].find((e) => e.url === C);
59
- if (T) return T.promise;
60
- w.inFlight.forEach((e) => {
61
- h(a, e.ids) && e.controller.abort();
54
+ }, x = async (r, a, o, { location: l, fresh: f = !1 } = {}) => {
55
+ let { enabled: p, endpoint: m } = r.get("rsc") ?? {};
56
+ if (!p || !m || typeof window > "u") return;
57
+ let v = l ?? u(), y = r.get("schema"), x = r.get("runtime.sources.auth"), S = l ? s(y, l, !!x?.details) : r.get("navigation.currentPageId"), C = l ? void 0 : r.get("runtime.sources.flags");
58
+ if (!y) return;
59
+ let w = a?.length ? c(y, S, a, C) : void 0;
60
+ if (w ? !w.length : !i(y, S, C)) return;
61
+ let T = new URLSearchParams({ location: v });
62
+ w?.length && T.set("ids", w.join(",")), Object.entries(o ?? {}).forEach(([e, t]) => T.set(e, t));
63
+ let E = `${m}?${T.toString()}`, D = h(r), O = [...D.inFlight].find((e) => e.url === E && (e.fresh || !f));
64
+ if (O) return O.promise;
65
+ D.inFlight.forEach((e) => {
66
+ _(w, e.ids) && e.controller.abort();
62
67
  });
63
- let E = ++w.seq;
64
- a?.length ? a.forEach((e) => w.asked.set(e, E)) : (w.asked.clear(), w.asked.set(l, E));
65
- let D = new AbortController(), O = {
66
- url: C,
67
- ...a?.length ? { ids: a } : {},
68
- here: g === c(),
69
- seq: E,
70
- controller: D,
68
+ let k = ++D.seq;
69
+ w?.length ? w.forEach((e) => D.asked.set(e, k)) : (D.asked.clear(), D.asked.set(d, k));
70
+ let A = new AbortController(), j = {
71
+ url: E,
72
+ ...w?.length ? { ids: w } : {},
73
+ here: v === u(),
74
+ fresh: f,
75
+ seq: k,
76
+ controller: A,
71
77
  promise: Promise.resolve()
72
- }, k = async (r) => {
73
- let a = await fetch(C, {
74
- headers: { Accept: "application/json" },
75
- signal: D.signal
78
+ }, M = async (i) => {
79
+ let a = await fetch(E, {
80
+ ...f ? {
81
+ cache: "no-cache",
82
+ headers: {
83
+ Accept: "application/json",
84
+ "Cache-Control": "no-cache"
85
+ }
86
+ } : { headers: { Accept: "application/json" } },
87
+ signal: A.signal
76
88
  });
77
89
  if (!a.ok) {
78
90
  let n = e(a.status, await a.json().catch(() => void 0));
79
91
  if (n && await t({
80
92
  reason: n,
81
- url: f
82
- }) && !r) return k(!0);
83
- i.set("rsc.stale", !0);
93
+ url: m
94
+ }) && !i) return M(!0);
95
+ r.set("rsc.stale", !0);
84
96
  return;
85
97
  }
86
98
  let { serverData: o, actionRuns: s } = await a.json();
87
- s?.length && n(s), v(i, w, O, o ?? {}, g);
99
+ s?.length && n(s), b(r, D, j, o ?? {}, v);
88
100
  };
89
- return O.promise = k(!1).catch(() => {
90
- D.signal.aborted || i.set("rsc.stale", !0);
101
+ return j.promise = M(!1).catch(() => {
102
+ A.signal.aborted || r.set("rsc.stale", !0);
91
103
  }).finally(() => {
92
- w.inFlight.delete(O), m(i, w);
93
- }), w.inFlight.add(O), m(i, w), O.promise;
104
+ D.inFlight.delete(j), g(r, D);
105
+ }), D.inFlight.add(j), g(r, D), j.promise;
94
106
  };
95
107
  //#endregion
96
- export { g as cancelRsc, c as currentRscLocation, y as default, y as refreshRsc, _ as releaseRscRequests, s as rscDataPath };
108
+ export { v as cancelRsc, u as currentRscLocation, x as default, x as refreshRsc, y as releaseRscRequests, l as rscDataPath };
@@ -1,2 +1,3 @@
1
- declare const useRscRefresh: () => (ids?: string[], params?: Record<string, string>) => Promise<void>;
1
+ import { RscRefreshOptions } from './refreshRsc';
2
+ declare const useRscRefresh: () => (ids?: string[], params?: Record<string, string>, { fresh }?: Pick<RscRefreshOptions, "fresh">) => Promise<void>;
2
3
  export default useRscRefresh;
@@ -4,7 +4,7 @@ import { useStoreById as n } from "@plitzi/nexus/react";
4
4
  //#region src/server/rsc/useRscRefresh.ts
5
5
  var r = () => {
6
6
  let r = n();
7
- return t((t, n) => e(r, t, n), [r]);
7
+ return t((t, n, { fresh: i } = {}) => e(r, t, n, { fresh: i }), [r]);
8
8
  };
9
9
  //#endregion
10
10
  export { r as default };
@@ -29,7 +29,7 @@ export type SpaceExport = {
29
29
  /** The version taken out: the draft (`main`, revision 0), or a snapshot an environment holds. */
30
30
  version: Pick<SpaceVersionContents, 'environment' | 'revision' | 'snapshot'>;
31
31
  /**
32
- * Which state of the draft's documents this is — its schema, style, actions and connectors — what `plitzi push`
32
+ * Which state of the draft's documents this is — its schema, style, actions and connectors — what `plitzi space push`
33
33
  * checks the space's draft has not moved on from. `null` for a snapshot, which no push writes.
34
34
  */
35
35
  draft: string | null;
@@ -62,7 +62,7 @@ export type SpaceExport = {
62
62
  };
63
63
  /**
64
64
  * The space's own data, by path in `src/data/` (JSON its providers read on the server, never served), and the version
65
- * of it this is — what `plitzi push` checks the space's copy has not moved on from.
65
+ * of it this is — what `plitzi space push` checks the space's copy has not moved on from.
66
66
  */
67
67
  data: {
68
68
  version: string;
@@ -1,6 +1,6 @@
1
1
  import { Schema, Style } from '../types';
2
2
  /**
3
- * A project's space put back on Plitzi as the space's draft (docs/en/projects-from-spaces.md): what `plitzi push` sends
3
+ * A project's space put back on Plitzi as the space's draft (docs/en/projects-from-spaces.md): what `plitzi space push` sends
4
4
  * to `PUT /spaces/:spaceId/import`, and what it is answered. The way back of `SpaceExport` — one shape for both ends.
5
5
  */
6
6
  export declare const SPACE_IMPORT_FORMAT = 1;