@plitzi/sdk-shared 0.38.4 → 0.38.5

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 (68) hide show
  1. package/CHANGELOG.md +329 -0
  2. package/dist/actions/functions.d.ts +10 -0
  3. package/dist/actions/functions.mjs +10 -10
  4. package/dist/actions/index.d.ts +1 -1
  5. package/dist/actions/index.mjs +6 -6
  6. package/dist/helpers/twigWrapper/inspectTemplate.mjs +14 -7
  7. package/dist/helpers/twigWrapper/processTwig/processTwig.d.ts +4 -3
  8. package/dist/helpers/twigWrapper/processTwig/processTwig.mjs +32 -22
  9. package/dist/history/types.d.ts +4 -4
  10. package/dist/index.mjs +38 -37
  11. package/dist/network/graphql/builder/Mutations/Space/data/SpaceSaveDataMutation.d.ts +10 -0
  12. package/dist/network/graphql/builder/Mutations/Space/data/SpaceSaveDataMutation.mjs +4 -0
  13. package/dist/network/graphql/builder/Mutations/index.d.ts +2 -0
  14. package/dist/network/graphql/builder/Mutations/index.mjs +124 -122
  15. package/dist/network/graphql/builder/Queries/InitQuery.d.ts +1 -3
  16. package/dist/network/graphql/builder/Queries/InitQuery.mjs +1 -1
  17. package/dist/network/graphql/builder/Queries/Space/SpaceDataQuery.d.ts +6 -0
  18. package/dist/network/graphql/builder/Queries/Space/SpaceDataQuery.mjs +4 -0
  19. package/dist/network/graphql/builder/Queries/index.d.ts +2 -0
  20. package/dist/network/graphql/builder/Queries/index.mjs +22 -20
  21. package/dist/network/spaceEvents.d.ts +2 -2
  22. package/dist/plugins/bundle.d.ts +26 -0
  23. package/dist/plugins/bundle.mjs +62 -0
  24. package/dist/plugins/declaration.d.ts +12 -0
  25. package/dist/plugins/declaration.mjs +9 -0
  26. package/dist/queries/queryCache.d.ts +7 -0
  27. package/dist/queries/queryCache.mjs +14 -7
  28. package/dist/queries/useQuery.d.ts +2 -0
  29. package/dist/queries/useQuery.mjs +5 -2
  30. package/dist/schema/anchor.d.ts +11 -0
  31. package/dist/schema/anchor.mjs +6 -2
  32. package/dist/schema/index.mjs +6 -6
  33. package/dist/schema/markdownHeadings.d.ts +13 -0
  34. package/dist/schema/markdownHeadings.mjs +24 -0
  35. package/dist/schema/motion.mjs +1 -1
  36. package/dist/schema/pageElements.d.ts +12 -0
  37. package/dist/schema/pageElements.mjs +41 -0
  38. package/dist/server/index.mjs +4 -4
  39. package/dist/server/rsc/projectData.d.ts +6 -0
  40. package/dist/server/rsc/projectData.mjs +4 -0
  41. package/dist/server/rsc/refreshRsc.d.ts +18 -5
  42. package/dist/server/rsc/refreshRsc.mjs +80 -20
  43. package/dist/server/rsc/useRscSync.mjs +26 -15
  44. package/dist/server/usePluginRoute.d.ts +18 -0
  45. package/dist/server/usePluginRoute.mjs +14 -0
  46. package/dist/source/export.d.ts +13 -0
  47. package/dist/store/index.d.ts +45 -45
  48. package/dist/style/cssLayers.d.ts +18 -0
  49. package/dist/style/cssLayers.mjs +14 -0
  50. package/dist/style/index.d.ts +1 -0
  51. package/dist/style/index.mjs +11 -10
  52. package/dist/style/useDisplayMode.d.ts +11 -0
  53. package/dist/style/useDisplayMode.mjs +18 -0
  54. package/dist/types/ActionTypes.d.ts +3 -3
  55. package/dist/types/ComponentTypes.d.ts +13 -0
  56. package/dist/types/DataTypes.d.ts +36 -0
  57. package/dist/types/InteractionTypes.d.ts +16 -2
  58. package/dist/types/SchemaTypes.d.ts +3 -1
  59. package/dist/types/SchemaTypes.mjs +2 -1
  60. package/dist/types/ServerTypes.d.ts +58 -7
  61. package/dist/types/StoreTypes.d.ts +19 -6
  62. package/dist/types/index.d.ts +1 -2
  63. package/package.json +46 -28
  64. package/setupTests.ts +16 -13
  65. package/dist/types/AITypes.d.ts +0 -80
  66. package/dist/types/McpTypes/index.d.ts +0 -56
  67. package/dist/types/McpTypes/index.mjs +0 -0
  68. /package/dist/types/{AITypes.mjs → DataTypes.mjs} +0 -0
@@ -0,0 +1,62 @@
1
+ import e from "node:fs/promises";
2
+ import t from "node:path";
3
+ //#region src/plugins/bundle.ts
4
+ var n = [
5
+ ".png",
6
+ ".jpg",
7
+ ".jpeg",
8
+ ".gif",
9
+ ".svg",
10
+ ".webp",
11
+ ".avif",
12
+ ".woff",
13
+ ".woff2",
14
+ ".ttf",
15
+ ".otf"
16
+ ], r = () => Object.fromEntries(n.map((e) => [e, "dataurl"])), i = /\?(raw|inline)$/, a = {
17
+ ".wasm": "application/wasm",
18
+ ".js": "text/javascript",
19
+ ".mjs": "text/javascript",
20
+ ".json": "application/json",
21
+ ".css": "text/css",
22
+ ".svg": "image/svg+xml",
23
+ ".png": "image/png",
24
+ ".jpg": "image/jpeg",
25
+ ".jpeg": "image/jpeg",
26
+ ".webp": "image/webp",
27
+ ".woff2": "font/woff2"
28
+ }, o = () => ({
29
+ name: "plitzi-import-queries",
30
+ setup: (n) => {
31
+ n.onResolve({ filter: i }, async (e) => {
32
+ let t = i.exec(e.path)?.[1] ?? "raw", r = await n.resolve(e.path.replace(i, ""), {
33
+ kind: e.kind,
34
+ importer: e.importer,
35
+ resolveDir: e.resolveDir
36
+ });
37
+ return r.errors.length > 0 ? { errors: r.errors } : {
38
+ path: r.path,
39
+ namespace: `plitzi-${t}`
40
+ };
41
+ }), n.onLoad({
42
+ filter: /.*/,
43
+ namespace: "plitzi-raw"
44
+ }, async (t) => ({
45
+ contents: await e.readFile(t.path),
46
+ loader: "text",
47
+ watchFiles: [t.path]
48
+ })), n.onLoad({
49
+ filter: /.*/,
50
+ namespace: "plitzi-inline"
51
+ }, async (n) => {
52
+ let r = a[t.extname(n.path).toLowerCase()] ?? "application/octet-stream", i = (await e.readFile(n.path)).toString("base64");
53
+ return {
54
+ contents: `export default ${JSON.stringify(`data:${r};base64,${i}`)};`,
55
+ loader: "js",
56
+ watchFiles: [n.path]
57
+ };
58
+ });
59
+ }
60
+ });
61
+ //#endregion
62
+ export { n as PLUGIN_INLINED_ASSETS, r as pluginAssetLoaders, o as pluginImportQueries };
@@ -0,0 +1,12 @@
1
+ import { ComponentDefinition, PluginDeclaration } from '../types';
2
+ import { FC } from 'react';
3
+ /** A plugin as its bundle exports it: the component, with the declaration its `index.ts` assigned onto it. */
4
+ export type DeclaredPlugin = FC<never> & {
5
+ content?: ComponentDefinition;
6
+ version?: string;
7
+ initialItems?: string[];
8
+ plugins?: Record<string, DeclaredPlugin>;
9
+ };
10
+ export declare const pluginDeclarationOf: (plugin: DeclaredPlugin) => PluginDeclaration;
11
+ /** The element types a plugin registered under `type` renders: its own and its sub-plugins', at any depth. */
12
+ export declare const pluginTypesOf: (type: string, declaration: PluginDeclaration) => string[];
@@ -0,0 +1,9 @@
1
+ //#region src/plugins/declaration.ts
2
+ var e = (e) => typeof e == "object" && !!e && "$$typeof" in e, t = (t) => JSON.parse(JSON.stringify(t, (t, n) => typeof n == "function" || e(n) ? void 0 : n)), n = (e) => ({
3
+ ...e.content ? { content: t(e.content) } : {},
4
+ ...e.version ? { version: e.version } : {},
5
+ ...e.initialItems ? { initialItems: [...e.initialItems] } : {},
6
+ ...e.plugins ? { plugins: Object.fromEntries(Object.entries(e.plugins).map(([e, t]) => [e, n(t)])) } : {}
7
+ }), r = (e, t) => [e, ...Object.entries(t.plugins ?? {}).flatMap(([e, t]) => r(e, t))];
8
+ //#endregion
9
+ export { n as pluginDeclarationOf, r as pluginTypesOf };
@@ -100,6 +100,13 @@ export declare class QueryCache {
100
100
  fetchQuery<T>(key: string, options: QueryObserverOptions<T> & {
101
101
  gcTime?: number;
102
102
  }): Promise<T | undefined>;
103
+ /**
104
+ * Stops the request out for `key`: the answer it would have brought lands nowhere, and what is held stays on screen.
105
+ *
106
+ * What a STOP is — the visitor is done waiting. The query is left as it was before it asked, so the next reader, or
107
+ * the next `refetch`, asks again.
108
+ */
109
+ cancel(key: string): boolean;
103
110
  /** Asks again for `key` now, whatever the age of what is held — the explicit "reload this". */
104
111
  refetch(key: string): Promise<void>;
105
112
  /**
@@ -67,6 +67,13 @@ var t = 3e5, n = (e) => {
67
67
  let a = this.getEntry(e)?.data;
68
68
  return this.scheduleGc(n), a;
69
69
  }
70
+ cancel(e) {
71
+ let t = this.runtimes.get(n(e));
72
+ if (!t?.controller) return !1;
73
+ t.controller.abort(), t.controller = void 0, t.inFlight = void 0;
74
+ let i = r(e);
75
+ return this.getEntry(e) ? this.store.setState(`${i}.isFetching`, !1) : this.markUnasked(t), !0;
76
+ }
70
77
  refetch(e) {
71
78
  let t = this.runtimes.get(n(e));
72
79
  return t ? this.invalidateOne(t) : Promise.resolve();
@@ -121,10 +128,10 @@ var t = 3e5, n = (e) => {
121
128
  tags: o,
122
129
  isFetching: !0
123
130
  });
124
- let c = this.epochValue, l = e.version, u = (r) => {
125
- if (c !== this.epochValue || this.runtimes.get(n(i)) !== e) return Promise.resolve();
131
+ let c = this.epochValue, l = e.version, u = new AbortController(), d = (r) => {
132
+ if (c !== this.epochValue || this.runtimes.get(n(i)) !== e || e.controller !== u) return Promise.resolve();
126
133
  e.inFlight = void 0, e.controller = void 0;
127
- let u = l !== e.version;
134
+ let d = l !== e.version;
128
135
  if ("error" in r) {
129
136
  let e = this.getEntry(i);
130
137
  this.store.setState(s, {
@@ -136,7 +143,7 @@ var t = 3e5, n = (e) => {
136
143
  isFetching: !1
137
144
  }, { ttl: 0 });
138
145
  } else {
139
- let n = !u && (t.isCacheable?.(r.data) ?? !0);
146
+ let n = !d && (t.isCacheable?.(r.data) ?? !0);
140
147
  this.store.setState(s, {
141
148
  key: i,
142
149
  url: a,
@@ -145,9 +152,9 @@ var t = 3e5, n = (e) => {
145
152
  isFetching: !1
146
153
  }, { ttl: n ? this.ttlOf(e, t) : 0 });
147
154
  }
148
- return u ? this.fetchActive(e) : Promise.resolve();
149
- }, d = new AbortController();
150
- return e.controller = d, e.inFlight = t.fetcher(d.signal).then((e) => u({ data: e }), (e) => u({ error: e })), e.inFlight;
155
+ return d ? this.fetchActive(e) : Promise.resolve();
156
+ };
157
+ return e.controller = u, e.inFlight = t.fetcher(u.signal).then((e) => d({ data: e }), (e) => d({ error: e })), e.inFlight;
151
158
  }
152
159
  ttlOf(e, t) {
153
160
  let n = e.observers.size > 0 ? Infinity : t.staleTime;
@@ -18,6 +18,8 @@ export type UseQueryResult<T> = {
18
18
  /** Nothing to render with yet — as opposed to a refresh of something already on screen. */
19
19
  isLoading: boolean;
20
20
  refetch: () => void;
21
+ /** Stops the request out, if there is one: what is held stays, and nothing is asked until the next reader or refetch. */
22
+ cancel: () => void;
21
23
  };
22
24
  declare const useQuery: <T>({ key, meta, fetcher, enabled, staleTime, gcTime, isCacheable }: UseQueryOptions<T>) => UseQueryResult<T>;
23
25
  export default useQuery;
@@ -35,12 +35,15 @@ var { useStore: s } = o(), c = ({ key: o, meta: c, fetcher: l, enabled: u = !0,
35
35
  };
36
36
  let w = S ?? C.current?.data, T = (g?.isFetching ?? !1) || u && m && !_, E = r(() => {
37
37
  u && o !== void 0 && e.refetch(o);
38
- }, [u, o]);
38
+ }, [u, o]), D = r(() => {
39
+ o !== void 0 && e.cancel(o);
40
+ }, [o]);
39
41
  return {
40
42
  data: w,
41
43
  isFetching: T,
42
44
  isLoading: T && w === void 0,
43
- refetch: E
45
+ refetch: E,
46
+ cancel: D
44
47
  };
45
48
  };
46
49
  //#endregion
@@ -6,3 +6,14 @@
6
6
  */
7
7
  export declare const ANCHOR_PATTERN: RegExp;
8
8
  export declare const isAnchor: (value: unknown) => value is string;
9
+ /**
10
+ * The anchor a piece of text reads as: its words, accents dropped and lowercased, a hyphen for every run of anything
11
+ * else, and nothing before the first letter — `Server-resolved data` is `server-resolved-data`. What a Markdown
12
+ * heading's `id` is, and what authoring offers an element that needs an anchor.
13
+ */
14
+ export declare const anchorOf: (text: string) => string;
15
+ /**
16
+ * The anchor `text` takes on a page that already carries `taken` — `faq`, then `faq-2`, `faq-3` — recorded in `taken`,
17
+ * so the next heading of the same words gets the next one. A page renders its headings in order, and so numbers them.
18
+ */
19
+ export declare const uniqueAnchor: (text: string, taken: Set<string>) => string;
@@ -1,4 +1,8 @@
1
1
  //#region src/schema/anchor.ts
2
- var e = /^[a-z][a-z0-9-]*$/, t = (t) => typeof t == "string" && e.test(t);
2
+ var e = /^[a-z][a-z0-9-]*$/, t = (t) => typeof t == "string" && e.test(t), n = (e) => e.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^[^a-z]+|-+$/g, "") || "section", r = (e, t) => {
3
+ let r = n(e), i = r;
4
+ for (let e = 2; t.has(i); e += 1) i = `${r}-${String(e)}`;
5
+ return t.add(i), i;
6
+ };
3
7
  //#endregion
4
- export { e as ANCHOR_PATTERN, t as isAnchor };
8
+ export { e as ANCHOR_PATTERN, n as anchorOf, t as isAnchor, r as uniqueAnchor };
@@ -1,7 +1,7 @@
1
1
  import e from "./SchemaContext.mjs";
2
- import { ANCHOR_PATTERN as t, isAnchor as n } from "./anchor.mjs";
3
- import { COMPONENT_PROPS_SOURCE as r, EMPTY_SCHEMA as i, VARIABLE_REGEX as a } from "./schemaConstants.mjs";
4
- import { findLayoutCycle as o, resolveLayoutChain as s } from "./layoutChain.mjs";
5
- import { collectServerElements as c, hasServerElements as l } from "./serverElements.mjs";
6
- import { isSnippet as u } from "./snippet.mjs";
7
- export { t as ANCHOR_PATTERN, r as COMPONENT_PROPS_SOURCE, i as EMPTY_SCHEMA, e as SchemaContext, a as VARIABLE_REGEX, c as collectServerElements, o as findLayoutCycle, l as hasServerElements, n as isAnchor, u as isSnippet, s as resolveLayoutChain };
2
+ import { ANCHOR_PATTERN as t, anchorOf as n, isAnchor as r, uniqueAnchor as i } from "./anchor.mjs";
3
+ import { COMPONENT_PROPS_SOURCE as a, EMPTY_SCHEMA as o, VARIABLE_REGEX as s } from "./schemaConstants.mjs";
4
+ import { findLayoutCycle as c, resolveLayoutChain as l } from "./layoutChain.mjs";
5
+ import { collectServerElements as u, hasServerElements as d } from "./serverElements.mjs";
6
+ import { isSnippet as f } from "./snippet.mjs";
7
+ export { t as ANCHOR_PATTERN, a as COMPONENT_PROPS_SOURCE, o as EMPTY_SCHEMA, e as SchemaContext, s as VARIABLE_REGEX, n as anchorOf, u as collectServerElements, c as findLayoutCycle, d as hasServerElements, r as isAnchor, f as isSnippet, l as resolveLayoutChain, i as uniqueAnchor };
@@ -0,0 +1,13 @@
1
+ export type MarkdownHeading = {
2
+ level: number;
3
+ text: string;
4
+ anchor: string;
5
+ };
6
+ /** A heading's words as a reader sees them: the inline Markdown around them taken away, as the renderer takes it. */
7
+ export declare const headingText: (source: string) => string;
8
+ /**
9
+ * Every heading of a Markdown document, in order, with the anchor its `id` is when it renders — what a table of
10
+ * contents links to, and what a link's `hash` may name. ATX headings (`## Title`), outside fenced code; every level
11
+ * shares one set of anchors, as the rendered page does.
12
+ */
13
+ export declare const markdownHeadings: (source: string) => MarkdownHeading[];
@@ -0,0 +1,24 @@
1
+ import { uniqueAnchor as e } from "./anchor.mjs";
2
+ //#region src/schema/markdownHeadings.ts
3
+ var t = /^ {0,3}(`{3,}|~{3,})/, n = /^ {0,3}(#{1,6})[ \t]+(.*?)(?:[ \t]+#+)?[ \t]*$/, r = (e) => e.replace(/!\[[^\]]*\]\([^)]*\)/g, "").replace(/<[^>]+>/g, "").replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/`+([^`]*?)`+/g, "$1").replace(/(\*\*|~~)(.+?)\1/g, "$2").replace(/\*(.+?)\*/g, "$1").replace(/\b__(.+?)__\b/g, "$1").replace(/\b_(.+?)_\b/g, "$1").replace(/\\([\\`*_{}[\]()#+\-.!|~>])/g, "$1").trim(), i = (i) => {
4
+ let a = /* @__PURE__ */ new Set(), o = [], s;
5
+ for (let c of i.split("\n")) {
6
+ let i = t.exec(c)?.[1];
7
+ if (i) {
8
+ s ? i[0] === s[0] && i.length >= s.length && (s = void 0) : s = i;
9
+ continue;
10
+ }
11
+ let l = s ? null : n.exec(c);
12
+ if (l) {
13
+ let t = r(l[2]);
14
+ o.push({
15
+ level: l[1].length,
16
+ text: t,
17
+ anchor: e(t, a)
18
+ });
19
+ }
20
+ }
21
+ return o;
22
+ };
23
+ //#endregion
24
+ export { r as headingText, i as markdownHeadings };
@@ -239,7 +239,7 @@ var t = [
239
239
  "stagger",
240
240
  "loop"
241
241
  ]), p = (i) => {
242
- if (!e(i)) return ["motion is an object: `{ enter: 'fade-up', on: 'view' }`"];
242
+ if (!e(i)) return ["motion is an object: `{ enter: \"fade-up\", on: \"view\" }`"];
243
243
  let a = [];
244
244
  for (let e of Object.keys(i)) f.has(e) || a.push(`motion has no "${e}" — it takes enter, on, duration, delay, stagger and loop`);
245
245
  i.enter !== void 0 && !d(t, i.enter) && a.push(`motion.enter is one of ${t.join(", ")}`), i.on !== void 0 && !d(n, i.on) && a.push(`motion.on is ${n.slice(0, -1).join(", ")} or ${String(n.at(-1))}`), i.loop !== void 0 && !d(r, i.loop) && a.push(`motion.loop is one of ${r.join(", ")}`);
@@ -0,0 +1,12 @@
1
+ import { Schema } from '../types';
2
+ /**
3
+ * The element types a page can draw — what decides which plugins a page has to have before it hydrates, and which can
4
+ * wait until a page that draws them is opened.
5
+ *
6
+ * Generous on purpose, because the two mistakes do not cost the same: a type counted that is never drawn only loads a
7
+ * plugin early, while one missed hydrates a page without the component the server drew. So it walks the page and
8
+ * every shell around it, into every component an instance names and every element a reference copies, and it counts
9
+ * what a flag or a visibility binding might hide: those are decided as the page renders, and may change while it is
10
+ * open. A `custom` element counts as the plugin it names (`renderType`), which is what it renders.
11
+ */
12
+ export declare const pageElementTypes: (schema: Schema, pageId: string) => Set<string>;
@@ -0,0 +1,41 @@
1
+ import { resolveLayoutChain as e } from "./layoutChain.mjs";
2
+ //#region src/schema/pageElements.ts
3
+ var t = (e) => typeof e == "string" ? e : "", n = (n, r) => {
4
+ let i = /* @__PURE__ */ new Set(), a = n.flat[r];
5
+ if (!a) return i;
6
+ let o = [r, ...e((e) => n.flat[e], t(a.attributes.layout), t(a.attributes.layoutContainer)).map((e) => e.layout)].map((e) => ({
7
+ flat: n.flat,
8
+ id: e
9
+ })), s = /* @__PURE__ */ new Map();
10
+ for (; o.length > 0;) {
11
+ let e = o.pop();
12
+ if (!e) break;
13
+ let { flat: r, id: a } = e, c = s.get(r) ?? /* @__PURE__ */ new Set();
14
+ s.set(r, c);
15
+ let l = r[a];
16
+ if (!l || c.has(a)) continue;
17
+ c.add(a);
18
+ let { type: u, items: d } = l.definition;
19
+ i.add(u);
20
+ let f = t(l.attributes.renderType);
21
+ u === "custom" && f && i.add(f);
22
+ let p = t(l.attributes.referenceId);
23
+ if (u === "reference" && p) {
24
+ let e = l.attributes.referenceType === "component" ? n.components[p] : void 0;
25
+ o.push(e ? {
26
+ flat: e.flat,
27
+ id: e.rootId
28
+ } : {
29
+ flat: n.flat,
30
+ id: p
31
+ });
32
+ }
33
+ d && o.push(...d.map((e) => ({
34
+ flat: r,
35
+ id: e
36
+ })));
37
+ }
38
+ return i;
39
+ };
40
+ //#endregion
41
+ export { n as pageElementTypes };
@@ -1,5 +1,5 @@
1
1
  import e from "./actions/useActionsSync.mjs";
2
- import t, { currentRscLocation as n, rscDataPath as r } from "./rsc/refreshRsc.mjs";
3
- import i from "./rsc/useRscRefresh.mjs";
4
- import a from "./rsc/useRscSync.mjs";
5
- export { n as currentRscLocation, t as refreshRsc, r as rscDataPath, e as useActionsSync, i as useRscRefresh, a as useRscSync };
2
+ import t, { cancelRsc as n, currentRscLocation as r, releaseRscRequests as i, rscDataPath as a } from "./rsc/refreshRsc.mjs";
3
+ import o from "./rsc/useRscRefresh.mjs";
4
+ import s from "./rsc/useRscSync.mjs";
5
+ export { n as cancelRsc, r as currentRscLocation, t as refreshRsc, i as releaseRscRequests, a as rscDataPath, e as useActionsSync, o as useRscRefresh, s as useRscSync };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Where a project's own data answers: a provider whose `query` is `/data/<file>` reads `<file>` from the folder the
3
+ * server keeps it in (`dataDir`), which is never served — so only a provider resolved on the server reads it. The
4
+ * server's resolver and the authoring check that refuses a browser read hold the same prefix.
5
+ */
6
+ export declare const PROJECT_DATA_PREFIX = "/data/";
@@ -0,0 +1,4 @@
1
+ //#region src/server/rsc/projectData.ts
2
+ var e = "/data/";
3
+ //#endregion
4
+ export { e as PROJECT_DATA_PREFIX };
@@ -1,6 +1,18 @@
1
1
  import { CommonState } from '../../types';
2
2
  import { PathOf, StoreApi } from '@plitzi/nexus';
3
3
  export declare const rscDataPath: (id: string) => PathOf<CommonState>;
4
+ /** Where the visitor is, spelled the way the server reads it back. */
5
+ export declare const currentRscLocation: () => string;
6
+ /**
7
+ * Stops what a refresh in flight is asking the server for — the request, and the work behind it on the server — and
8
+ * leaves the payload as it is.
9
+ *
10
+ * `ids` cancels the refreshes of those elements; nothing cancels every refresh in flight, a navigation's included.
11
+ * What a STOP button is: the visitor is done waiting, and what is on screen stays.
12
+ */
13
+ export declare const cancelRsc: (store: StoreApi<CommonState>, ids?: readonly string[]) => void;
14
+ /** Every refresh of this root aborted and forgotten — the SDK root that owned them is going away. */
15
+ export declare const releaseRscRequests: (instance: string) => void;
4
16
  /**
5
17
  * Re-fetches RSC data into the store.
6
18
  *
@@ -11,9 +23,12 @@ export declare const rscDataPath: (id: string) => PathOf<CommonState>;
11
23
  * Pass `ids` to refresh only those elements — the response is merged over the existing payload. Omit them for a full
12
24
  * refresh, which replaces it. `params` ride along on the query string; that is how a provider asks for a different
13
25
  * page window.
26
+ *
27
+ * One request per question, and the newest question wins: asking again for what is already in flight is answered by
28
+ * the request in flight, and a request whose answer a newer one would overwrite anyway — a whole payload asked for
29
+ * again, an element asked for again — is aborted, here and on the server. Before this a click on a link asked twice
30
+ * (its prefetch, then the route change), and a slow answer could land over a newer one.
14
31
  */
15
- /** Where the visitor is, spelled the way the server reads it back. */
16
- export declare const currentRscLocation: () => string;
17
32
  export declare const refreshRsc: (store: StoreApi<CommonState>, ids?: string[], params?: Record<string, string>,
18
33
  /**
19
34
  * Resolve for somewhere the visitor is not yet.
@@ -22,7 +37,5 @@ export declare const refreshRsc: (store: StoreApi<CommonState>, ids?: string[],
22
37
  * navigation asks for the destination BEFORE it commits. Absent means where the visitor already is, which is
23
38
  * every other caller: the initial load, a pager, an element refreshing itself.
24
39
  */
25
- location?: string,
26
- /** Whether this is the one second asking, after a refusal that renewed the session. */
27
- retried?: boolean) => Promise<void>;
40
+ location?: string) => Promise<void>;
28
41
  export default refreshRsc;
@@ -7,30 +7,90 @@ var o = (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
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 = async (i, a, u, d, f = !1) => {
11
- let { enabled: p, endpoint: m } = i.get("rsc") ?? {};
12
- if (!p || !m || typeof window > "u") return;
13
- let h = d ?? c(), g = i.get("schema"), _ = i.get("runtime.sources.auth"), v = d ? o(g, d, !!_?.details) : i.get("navigation.currentPageId"), y = d ? void 0 : i.get("runtime.sources.flags");
14
- if (g && r(g, v, y)) try {
15
- let r = new URLSearchParams({ location: h });
16
- a?.length && r.set("ids", a.join(",")), Object.entries(u ?? {}).forEach(([e, t]) => r.set(e, t));
17
- let o = await fetch(`${m}?${r.toString()}`, { headers: { Accept: "application/json" } });
18
- if (!o.ok) {
19
- let n = e(o.status, await o.json().catch(() => void 0));
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 = () => ({
11
+ seq: 0,
12
+ inFlight: /* @__PURE__ */ new Set(),
13
+ asked: /* @__PURE__ */ new Map()
14
+ }), p = (e) => {
15
+ let t = e.get("rsc.instance");
16
+ if (typeof t == "string" && t) {
17
+ let e = u.get(t);
18
+ if (e) return e;
19
+ let n = f();
20
+ return u.set(t, n), n;
21
+ }
22
+ let n = d.get(e);
23
+ if (n) return n;
24
+ let r = f();
25
+ return d.set(e, r), r;
26
+ }, m = (e, t) => {
27
+ let n = {};
28
+ t.inFlight.forEach((e) => {
29
+ e.here && (e.ids ?? [l]).forEach((e) => {
30
+ n[e] = !0;
31
+ });
32
+ }), 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) => {
35
+ (!t || e.ids?.some((e) => t.includes(e))) && e.controller.abort();
36
+ });
37
+ }, _ = (e) => {
38
+ u.get(e)?.inFlight.forEach((e) => e.controller.abort()), u.delete(e);
39
+ }, v = (e, t, n, r, i) => {
40
+ let { ids: a, seq: o } = n;
41
+ e.batch(() => {
42
+ 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);
44
+ });
45
+ 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))]);
47
+ e.set("rsc.data", a);
48
+ }
49
+ e.set("rsc.loaded", !0), e.set("rsc.stale", !1), e.set("rsc.location", i);
50
+ });
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();
62
+ });
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,
71
+ promise: Promise.resolve()
72
+ }, k = async (r) => {
73
+ let a = await fetch(C, {
74
+ headers: { Accept: "application/json" },
75
+ signal: D.signal
76
+ });
77
+ if (!a.ok) {
78
+ let n = e(a.status, await a.json().catch(() => void 0));
20
79
  if (n && await t({
21
80
  reason: n,
22
- url: m
23
- }) && !f) return await l(i, a, u, d, !0);
81
+ url: f
82
+ }) && !r) return k(!0);
24
83
  i.set("rsc.stale", !0);
25
84
  return;
26
85
  }
27
- let { serverData: c, actionRuns: p } = await o.json();
28
- p?.length && n(p), i.batch(() => {
29
- a?.length ? Object.entries(c ?? {}).forEach(([e, t]) => i.set(s(e), t)) : i.set("rsc.data", c ?? {}), i.set("rsc.loaded", !0), i.set("rsc.stale", !1), i.set("rsc.location", h);
30
- });
31
- } catch {
32
- i.set("rsc.stale", !0);
33
- }
86
+ let { serverData: o, actionRuns: s } = await a.json();
87
+ s?.length && n(s), v(i, w, O, o ?? {}, g);
88
+ };
89
+ return O.promise = k(!1).catch(() => {
90
+ D.signal.aborted || i.set("rsc.stale", !0);
91
+ }).finally(() => {
92
+ w.inFlight.delete(O), m(i, w);
93
+ }), w.inFlight.add(O), m(i, w), O.promise;
34
94
  };
35
95
  //#endregion
36
- export { c as currentRscLocation, l as default, l as refreshRsc, s as rscDataPath };
96
+ export { g as cancelRsc, c as currentRscLocation, y as default, y as refreshRsc, _ as releaseRscRequests, s as rscDataPath };
@@ -1,27 +1,38 @@
1
1
  import { useCommonStore as e, useCommonStoreSync as t } from "../../store/index.mjs";
2
- import n, { currentRscLocation as r } from "./refreshRsc.mjs";
3
- import { useEffect as i, useRef as a } from "react";
4
- import { useStoreById as o } from "@plitzi/nexus/react";
2
+ import n, { currentRscLocation as r, releaseRscRequests as i } from "./refreshRsc.mjs";
3
+ import { useEffect as a, useId as o } from "react";
4
+ import { useStoreById as s } from "@plitzi/nexus/react";
5
5
  //#region src/server/rsc/useRscSync.ts
6
- var s = (s) => {
7
- let c = o(), [l] = e("schema.rsc", { mode: "mount" }), [u] = e("runtime.sources.navigation"), { rscData: d, rscPath: f } = s ?? {}, p = (l?.enabled ?? !1) && !!f;
8
- t(["rsc.enabled", "rsc.endpoint"], [p, f]), t([
6
+ var c = (c) => {
7
+ let l = s(), u = o(), [d] = e("schema.rsc", { mode: "mount" }), [f] = e([
8
+ "navigation.routeParams",
9
+ "navigation.queryParams",
10
+ "navigation.currentPageId",
11
+ "navigation.href"
12
+ ]), p = JSON.stringify(f), { rscData: m, rscPath: h } = c ?? {}, g = (d?.enabled ?? !1) && !!h;
13
+ t([
14
+ "rsc.enabled",
15
+ "rsc.endpoint",
16
+ "rsc.instance"
17
+ ], [
18
+ g,
19
+ h,
20
+ u
21
+ ]), t([
9
22
  "rsc.data",
10
23
  "rsc.loaded",
11
24
  "rsc.location"
12
25
  ], [
13
- d?.serverData ?? {},
14
- d !== void 0,
26
+ m?.serverData ?? {},
27
+ m !== void 0,
15
28
  r()
16
- ], { mode: "mount" });
17
- let m = JSON.stringify(u ?? {}), h = a(d === void 0 ? void 0 : m);
18
- i(() => {
19
- p && m !== h.current && (h.current = m, n(c));
29
+ ], { mode: "mount" }), a(() => () => i(u), [u]), a(() => {
30
+ !g || l.get("rsc.loaded") && l.get("rsc.location") === r() && !l.get("rsc.stale") || n(l);
20
31
  }, [
32
+ g,
21
33
  p,
22
- m,
23
- c
34
+ l
24
35
  ]);
25
36
  };
26
37
  //#endregion
27
- export { s as default };
38
+ export { c as default };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Where a plugin's own server half answers, for its component: `route('/layout')` is the URL of the plugin's
3
+ * `GET /layout`, served under `/fn/plugins/<type>/` by the server this page came from — with no flow, no server action
4
+ * and nothing for the space to wire.
5
+ *
6
+ * ```tsx
7
+ * const route = usePluginRoute('board');
8
+ * const url = route('/layout');
9
+ * if (url) {
10
+ * await fetch(url, { method: 'POST', body: JSON.stringify(layout), credentials: 'same-origin' });
11
+ * }
12
+ * ```
13
+ *
14
+ * `undefined` while the page is served without a server that runs code — the builder's canvas, an embed, an offline
15
+ * render — the same answer that leaves a `runServerAction` step inert there, rather than a request to a guaranteed 404.
16
+ */
17
+ declare const usePluginRoute: (plugin: string) => (path?: string) => string | undefined;
18
+ export default usePluginRoute;
@@ -0,0 +1,14 @@
1
+ import { pluginRoutePath as e } from "../actions/functions.mjs";
2
+ import { useCommonStore as t } from "../store/index.mjs";
3
+ import { useCallback as n } from "react";
4
+ //#region src/server/usePluginRoute.ts
5
+ var r = (r) => {
6
+ let [i] = t("actions.endpoint");
7
+ return n((t = "/") => {
8
+ if (!i) return;
9
+ let n = e(r, t);
10
+ return typeof window > "u" ? n : new URL(n, new URL(i, window.location.href)).href;
11
+ }, [i, r]);
12
+ };
13
+ //#endregion
14
+ export { r as default };
@@ -60,6 +60,14 @@ export type SpaceExport = {
60
60
  version: string;
61
61
  files: Record<string, string>;
62
62
  };
63
+ /**
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.
66
+ */
67
+ data: {
68
+ version: string;
69
+ files: Record<string, string>;
70
+ };
63
71
  /**
64
72
  * The source its plugins and runtime were built from, merged: every file by its path in the project (bytes in
65
73
  * base64), the packages they need, and where each build starts.
@@ -77,9 +85,14 @@ export type SpaceExport = {
77
85
  };
78
86
  /** What there is no source of: kept built, so the project runs it as it is and cannot change it. */
79
87
  builtOnly: {
88
+ /**
89
+ * Each plugin's built files, and its server half's source when it brings one (by path in its `functions/`): the
90
+ * platform keeps that privately, so it travels here rather than as a file on the CDN.
91
+ */
80
92
  plugins: {
81
93
  type: string;
82
94
  files: SpaceExportFile[];
95
+ functions?: Record<string, string>;
83
96
  }[];
84
97
  /** The packed runtime, in base64 — what `@plitzi/sdk-server/runtime` loads. */
85
98
  runtime: string | null;