@plitzi/sdk-shared 0.38.6 → 0.38.7

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 (53) hide show
  1. package/CHANGELOG.md +197 -0
  2. package/dist/dataSource/globalSources.d.ts +34 -1
  3. package/dist/dataSource/globalSources.mjs +22 -2
  4. package/dist/dataSource/hooks/index.d.ts +2 -1
  5. package/dist/dataSource/hooks/index.mjs +2 -1
  6. package/dist/dataSource/hooks/useResolvedVariables.d.ts +12 -0
  7. package/dist/dataSource/hooks/useResolvedVariables.mjs +28 -0
  8. package/dist/dataSource/index.mjs +2 -1
  9. package/dist/dataSource/resolveVariables.d.ts +2 -2
  10. package/dist/flags/useFlagResolution.mjs +6 -6
  11. package/dist/index.mjs +62 -58
  12. package/dist/network/spaceEvents.d.ts +30 -0
  13. package/dist/network/spaceEvents.mjs +150 -147
  14. package/dist/project/layout.d.ts +197 -0
  15. package/dist/project/layout.mjs +394 -0
  16. package/dist/project/paths.d.ts +84 -0
  17. package/dist/project/paths.mjs +4 -0
  18. package/dist/project/root.d.ts +24 -0
  19. package/dist/project/root.mjs +26 -0
  20. package/dist/queries/index.d.ts +12 -2
  21. package/dist/queries/index.mjs +27 -17
  22. package/dist/queries/serverQueries.d.ts +22 -0
  23. package/dist/queries/serverQueries.mjs +9 -0
  24. package/dist/queries/useServerQuery.d.ts +19 -0
  25. package/dist/queries/useServerQuery.mjs +21 -0
  26. package/dist/server/rsc/refreshRsc.d.ts +22 -10
  27. package/dist/server/rsc/refreshRsc.mjs +65 -53
  28. package/dist/server/rsc/useRscRefresh.d.ts +2 -1
  29. package/dist/server/rsc/useRscRefresh.mjs +1 -1
  30. package/dist/store/index.d.ts +45 -45
  31. package/dist/style/index.d.ts +3 -0
  32. package/dist/style/index.mjs +5 -2
  33. package/dist/style/keyframes.d.ts +39 -0
  34. package/dist/style/keyframes.mjs +41 -0
  35. package/dist/style/notifications.d.ts +34 -12
  36. package/dist/style/notifications.mjs +69 -32
  37. package/dist/style/styleConditions.d.ts +43 -0
  38. package/dist/style/styleConditions.mjs +29 -0
  39. package/dist/style/styleConstants.d.ts +3 -2
  40. package/dist/style/styleConstants.mjs +2 -0
  41. package/dist/style/stylePseudos.d.ts +40 -0
  42. package/dist/style/stylePseudos.mjs +109 -0
  43. package/dist/style/styleStates.d.ts +35 -8
  44. package/dist/style/styleStates.mjs +38 -15
  45. package/dist/style/styleTarget.d.ts +23 -0
  46. package/dist/style/styleTarget.mjs +35 -0
  47. package/dist/types/AuthTypes.d.ts +5 -0
  48. package/dist/types/CommonTypes.d.ts +12 -0
  49. package/dist/types/SchemaTypes.d.ts +2 -0
  50. package/dist/types/ServerTypes.d.ts +11 -4
  51. package/dist/types/StoreTypes.d.ts +5 -1
  52. package/dist/types/StyleTypes.d.ts +20 -2
  53. package/package.json +42 -2
@@ -0,0 +1,394 @@
1
+ import { isRecord as e } from "../helpers/isRecord.mjs";
2
+ import { AUTHOR_FILE as t, DATA_DIR as n, FUNCTIONS_DIR as r, PLUGINS_DIR as i, PLUGIN_DECLARATION_FILE as a, PLUGIN_ENTRIES as o, PLUGIN_FUNCTIONS_DIR as s, PLUGIN_MANIFEST_FILE as c, PUBLIC_DIR as l, RUNTIME_DIR as u, SPACE_DIR as d, SPACE_ENTRY as f, VENDOR_PLUGINS_DIR as p } from "./paths.mjs";
3
+ import m from "node:path";
4
+ import { readFileSync as h, readdirSync as g, statSync as _ } from "node:fs";
5
+ //#region src/project/layout.ts
6
+ var v = {
7
+ "plugin-entry-missing": {
8
+ level: "error",
9
+ means: "a folder of src/plugins/ with no index.ts (or index.tsx), which the server builds the plugin from"
10
+ },
11
+ "plugin-entry-ambiguous": {
12
+ level: "error",
13
+ means: "a folder of src/plugins/ with both index.ts and index.tsx: a plugin starts at one"
14
+ },
15
+ "entry-not-typescript": {
16
+ level: "error",
17
+ means: "an entry the server builds or runs written as JavaScript (index.js, .jsx, .mjs, .cjs): the project is TypeScript"
18
+ },
19
+ "plugin-name-invalid": {
20
+ level: "error",
21
+ means: "a folder of src/plugins/ whose name cannot be an element type: a letter, then letters and digits"
22
+ },
23
+ "plugin-type-taken": {
24
+ level: "error",
25
+ means: "two folders of src/plugins/ that are the same element type (StoryEditor and storyEditor)"
26
+ },
27
+ "plugin-shadowed": {
28
+ level: "error",
29
+ means: "a plugin both in src/plugins/ and, as it was built, in vendor/plugins/: the built one runs"
30
+ },
31
+ "plugin-functions-entry-missing": {
32
+ level: "error",
33
+ means: "a plugin’s functions/ with code and no index.ts, which its server half is built from"
34
+ },
35
+ "functions-entry-missing": {
36
+ level: "error",
37
+ means: "src/functions/ with code and no index.ts, which the project’s functions are built from"
38
+ },
39
+ "runtime-entry-missing": {
40
+ level: "error",
41
+ means: "src/runtime/ with code and no index.ts, which the space’s runtime starts at"
42
+ },
43
+ "space-entry-missing": {
44
+ level: "error",
45
+ means: "a space written in the project with no src/space/index.ts, which the server and npm run author import"
46
+ },
47
+ "space-default-export": {
48
+ level: "error",
49
+ means: "src/space/index.ts exporting the space by default, where it is imported by name: `space`"
50
+ },
51
+ "vendor-manifest-missing": {
52
+ level: "error",
53
+ means: "a built plugin (vendor/plugins/<type>/) with no plugin-manifest.json"
54
+ },
55
+ "vendor-manifest-invalid": {
56
+ level: "error",
57
+ means: "a built plugin’s plugin-manifest.json that is not a manifest"
58
+ },
59
+ "vendor-script-missing": {
60
+ level: "error",
61
+ means: "a built plugin’s manifest naming no script to run, or one that is not there"
62
+ },
63
+ "env-in-src": {
64
+ level: "error",
65
+ means: ".env inside src/: Node reads the project’s settings from the .env at its root"
66
+ },
67
+ "folder-misplaced": {
68
+ level: "error",
69
+ means: "code in a folder named like one the server reads (src/plugin/, plugins/ at the root): nothing reads it"
70
+ },
71
+ "folder-near-miss": {
72
+ level: "warning",
73
+ means: "a folder named like one the server reads (src/Data/, src/runtimes/), which nothing reads"
74
+ },
75
+ "plugin-declaration-missing": {
76
+ level: "warning",
77
+ means: "a plugin folder with no declaration.ts: the space’s use of the plugin is held to nothing"
78
+ },
79
+ "plugin-file-loose": {
80
+ level: "warning",
81
+ means: "a file directly in src/plugins/, where every plugin is a folder"
82
+ },
83
+ "data-not-json": {
84
+ level: "warning",
85
+ means: "a file of src/data/ that is not JSON, which no provider and no ctx.data reads"
86
+ },
87
+ "env-missing": {
88
+ level: "warning",
89
+ means: "no .env at the project’s root: none of its settings is set"
90
+ },
91
+ "env-example-missing": {
92
+ level: "warning",
93
+ means: "no .env.example: a clone does not know what .env must hold"
94
+ },
95
+ "public-data": {
96
+ level: "warning",
97
+ means: "JSON in public/data/ of a project with a server: served to anyone who asks"
98
+ },
99
+ "public-secret-file": {
100
+ level: "warning",
101
+ means: "a file in public/ named like a secret (.env, a key, a dump): served to anyone who asks"
102
+ }
103
+ }, y = (e, t, n, r, i) => ({
104
+ level: v[e].level,
105
+ code: e,
106
+ file: t,
107
+ message: n,
108
+ fix: r,
109
+ ...i ? { autofix: i } : {}
110
+ }), b = /* @__PURE__ */ new Set([
111
+ ".gitkeep",
112
+ "README.md",
113
+ ".DS_Store"
114
+ ]), ee = /^index\.(?:js|jsx|mjs|cjs)$/, x = /^[A-Za-z][A-Za-z0-9]*$/, S = (e) => {
115
+ let t = {
116
+ files: [],
117
+ folders: []
118
+ };
119
+ try {
120
+ for (let n of g(e, { withFileTypes: !0 })) {
121
+ let r = n.isSymbolicLink() ? _(m.join(e, n.name), { throwIfNoEntry: !1 }) : void 0;
122
+ n.isFile() || r?.isFile() ? t.files.push(n.name) : (n.isDirectory() || r?.isDirectory()) && t.folders.push(n.name);
123
+ }
124
+ } catch {
125
+ return t;
126
+ }
127
+ return {
128
+ files: t.files.sort(),
129
+ folders: t.folders.sort()
130
+ };
131
+ }, C = (e, t, n) => {
132
+ let r = t.split("/").filter((e) => e !== "" && e !== "."), i = e;
133
+ for (let [e, t] of r.entries()) {
134
+ let { files: a, folders: o } = S(i);
135
+ if (!(e === r.length - 1 && n === "file" ? a : o).includes(t)) return !1;
136
+ i = m.join(i, t);
137
+ }
138
+ return !0;
139
+ }, w = (e, t, n = /* @__PURE__ */ new Set()) => {
140
+ let { files: r, folders: i } = S(m.join(e, t));
141
+ return [...r.map((e) => `${t}/${e}`), ...i.filter((e) => !n.has(e)).flatMap((r) => w(e, `${t}/${r}`, n))];
142
+ }, T = ({ files: e, folders: t }) => t.length > 0 || e.some((e) => !b.has(e)), E = (e, t) => e.toLowerCase() === t.toLowerCase(), D = (e) => `${e.charAt(0).toUpperCase()}${e.slice(1)}`, O = (e, t) => {
143
+ let n = Array.from({ length: e.length + 1 }, (e, n) => Array.from({ length: t.length + 1 }, (e, t) => Math.max(n, t) * Number(n === 0 || t === 0)));
144
+ for (let r = 1; r <= e.length; r++) for (let i = 1; i <= t.length; i++) {
145
+ let a = e[r - 1] === t[i - 1] ? 0 : 1;
146
+ n[r][i] = Math.min(n[r - 1][i] + 1, n[r][i - 1] + 1, n[r - 1][i - 1] + a), r > 1 && i > 1 && e[r - 1] === t[i - 2] && e[r - 2] === t[i - 1] && (n[r][i] = Math.min(n[r][i], n[r - 2][i - 2] + 1));
147
+ }
148
+ return n[e.length][t.length];
149
+ }, k = (e, t) => {
150
+ if (e === t) return !1;
151
+ let n = e.toLowerCase(), r = t.toLowerCase();
152
+ return n === r || n === `${r}s` || `${n}s` === r || r.length >= 5 && O(n, r) <= 1;
153
+ }, A = "macOS and Windows disks ignore case, so it is found there — and not on Linux, where the project is deployed.", j = (e, t) => E(e, t) ? `git mv ${e} ${e}-tmp && git mv ${e}-tmp ${t}` : `git mv ${e} ${t}`, M = (e) => `${e.charAt(0).toLowerCase()}${e.slice(1)}`, N = (e) => {
154
+ let t = e.split(/[^A-Za-z0-9]+/).filter(Boolean).map(D).join(""), n = /^\d+/.exec(t)?.[0] ?? "", r = `${D(t.slice(n.length))}${n}`;
155
+ return x.test(r) ? r : void 0;
156
+ }, P = (e) => {
157
+ let { files: t } = S(e), n = o.filter((e) => t.includes(e));
158
+ return n.length === 1 ? m.join(e, n[0]) : void 0;
159
+ }, F = (e, t) => x.test(t) ? P(m.join(e, i, t)) : void 0, I = (e) => e.length > 1 ? `${e[0]} (or ${e.slice(1).join(", ")})` : e[0], L = (e, t) => {
160
+ let { folder: n, accepted: r, code: i, lost: a } = t, o = S(m.join(e, n)), s = r.filter((e) => o.files.includes(e));
161
+ if (s.length === 1) return [];
162
+ if (s.length > 1) return [y("plugin-entry-ambiguous", `${n}/`, `${n}/ has both ${s.join(" and ")}, and a plugin is built from one of them.`, `Keep one — ${s[s.length - 1]} when it writes JSX — and delete the other.`)];
163
+ let c = o.files.find((e) => ee.test(e));
164
+ if (c) {
165
+ let e = c.endsWith(".jsx") && r.includes("index.tsx") ? "index.tsx" : "index.ts";
166
+ return [y("entry-not-typescript", `${n}/${c}`, `${n}/${c} is JavaScript, and ${n}/ is built from ${I(r)}: the project's code is TypeScript, so ${a}.`, `Rename it ${e} — JavaScript is TypeScript already, types left out: ${j(`${n}/${c}`, `${n}/${e}`)}`, {
167
+ action: "move",
168
+ from: `${n}/${c}`,
169
+ to: `${n}/${e}`
170
+ })];
171
+ }
172
+ let l = o.files.find((e) => r.some((t) => k(e, t)));
173
+ if (l) {
174
+ let e = r.find((e) => k(l, e)) ?? r[0];
175
+ return [y(i, `${n}/${l}`, `${n}/ has no ${e} — did you mean ${l}? Named otherwise, ${a}.${E(l, e) ? ` ${A}` : ""}`, `Rename it ${e}: ${j(`${n}/${l}`, `${n}/${e}`)}`, {
176
+ action: "move",
177
+ from: `${n}/${l}`,
178
+ to: `${n}/${e}`
179
+ })];
180
+ }
181
+ let u = o.folders.find((t) => r.some((r) => C(e, `${n}/${t}/${r}`, "file")));
182
+ return u ? [y(i, `${n}/${u}/`, `${n}/ has no ${I(r)}, and ${n}/${u}/ has: one folder too deep, so ${a}.`, `Move what ${n}/${u}/ holds up into ${n}/.`, {
183
+ action: "move",
184
+ from: `${n}/${u}/`,
185
+ to: `${n}/`
186
+ })] : [y(i, `${n}/`, `${n}/ has no ${I(r)}, so ${a}.`, t.write)];
187
+ }, R = (e, t) => T(S(m.join(e, t.folder))) ? L(e, t) : [], te = (e) => {
188
+ let t = N(e), n = `${i}/${e}`;
189
+ return y("plugin-name-invalid", `${n}/`, `${n}/ cannot be a plugin: a folder of ${i}/ is registered as the element type its name makes, and a type is a letter followed by letters and digits.${t ? ` Did you mean ${t}?` : ""}`, t ? `Rename it ${t} — the type ${M(t)}: ${j(n, `${i}/${t}`)}; then type: '${M(t)}' in its ${a}, and renderType: '${M(t)}' where the space renders it.` : "Rename it with letters and digits, starting with a letter: StatCard is the type statCard.");
190
+ }, ne = (e, t) => e.find((e) => e === `${t}.tsx`) ?? e.find((e) => e === `${t}.ts`), z = (e, t) => {
191
+ let n = `${i}/${t}`, { files: r } = S(m.join(e, n));
192
+ if (r.includes("declaration.ts")) return [];
193
+ let o = M(t), s = `authoring holds none of the space's ${o} elements to its attributes, and the builder does not offer it`, c = r.find((e) => k(e, a));
194
+ return c ? [y("plugin-declaration-missing", `${n}/${c}`, `${n}/ has no ${a} — did you mean ${c}? Named otherwise, ${s}.${E(c, "declaration.ts") ? ` ${A}` : ""}`, `Rename it ${a}: ${j(`${n}/${c}`, `${n}/${a}`)}`, {
195
+ action: "move",
196
+ from: `${n}/${c}`,
197
+ to: `${n}/${a}`
198
+ })] : [y("plugin-declaration-missing", `${n}/`, `${n}/ has no ${a}: ${s}.`, `Write ${n}/${a} — export default { type: '${o}', … } — as npx plitzi add plugin writes one beside the component it makes.`)];
199
+ }, B = (e, t) => {
200
+ if (!x.test(t)) return [te(t)];
201
+ let n = `${i}/${t}`, r = M(t), a = ne(S(m.join(e, n)).files, t);
202
+ return [
203
+ ...L(e, {
204
+ folder: n,
205
+ accepted: o,
206
+ code: "plugin-entry-missing",
207
+ lost: `the server cannot build the plugin ${r}`,
208
+ write: `Write ${n}/index.ts exporting the component by default${a ? ` — export { default } from './${a}';` : ""} — as npx plitzi add plugin writes it. Every folder of ${i}/ is a plugin: code several plugins share goes outside it (src/shared/).`
209
+ }),
210
+ ...R(e, {
211
+ folder: `${n}/${s}`,
212
+ accepted: ["index.ts"],
213
+ code: "plugin-functions-entry-missing",
214
+ lost: `none of the plugin's server half runs (its routes under /fn/plugins/${r}/)`,
215
+ write: `Write ${n}/${s}/index.ts exporting defineFunctions({ … }) by default — as npx plitzi add plugin --server writes it.`
216
+ }),
217
+ ...z(e, t)
218
+ ];
219
+ }, V = (e) => {
220
+ let t = /* @__PURE__ */ new Map();
221
+ for (let n of e.filter((e) => x.test(e))) t.set(M(n), [...t.get(M(n)) ?? [], n]);
222
+ return [...t].flatMap(([e, t]) => t.slice(1).map((n) => y("plugin-type-taken", `${i}/${n}/`, `${i}/${t[0]}/ and ${i}/${n}/ are both the plugin ${e}: the server registers a folder by its name with a small first letter, and keeps one.`, `Put them in one folder, or rename one: git mv ${i}/${n} ${i}/<AnotherName>`)));
223
+ }, H = (t) => e(t.assets) ? Object.values(t.assets).flatMap((t) => e(t) && typeof t.src == "string" && typeof t.type == "string" ? [{
224
+ src: t.src,
225
+ type: t.type,
226
+ isMain: t.isMain === !0
227
+ }] : []) : [], U = (t, n) => {
228
+ let r = `${p}/${n}`, i = `${r}/${c}`, a = `npx plitzi pull brings it again — or delete ${r}/, and the space renders no ${n}.`;
229
+ if (!C(t, i, "file")) return { problem: y("vendor-manifest-missing", `${r}/`, `${r}/ has no ${c}: the server runs a built plugin by what its manifest names, so ${n} does not run.`, a) };
230
+ let o;
231
+ try {
232
+ o = JSON.parse(h(m.join(t, i), "utf-8"));
233
+ } catch (e) {
234
+ return { problem: y("vendor-manifest-invalid", i, `${i} is not JSON (${e instanceof Error ? e.message : String(e)}), so ${n} does not run.`, a) };
235
+ }
236
+ if (!e(o)) return { problem: y("vendor-manifest-invalid", i, `${i} is not a manifest, so ${n} does not run.`, a) };
237
+ let s = H(o), l = s.find((e) => e.type === "script" && e.isMain) ?? s.find((e) => e.type === "script");
238
+ if (!l) return { problem: y("vendor-script-missing", i, `${i} names no script to run, so ${n} does not run.`, a) };
239
+ if (!C(t, m.posix.join(r, l.src), "file")) return { problem: y("vendor-script-missing", i, `${i} names ${l.src} as the script to run, and ${r}/${l.src} is not there, so ${n} does not run.`, a) };
240
+ let u = s.find((e) => e.type === "style");
241
+ return {
242
+ script: m.join(t, r, l.src),
243
+ ...u ? { style: m.join(t, r, u.src) } : {},
244
+ version: typeof o.version == "string" ? o.version : "1.0.0",
245
+ ...typeof o.functions == "string" ? { functions: m.join(t, r, o.functions) } : {}
246
+ };
247
+ }, W = (e) => {
248
+ let { files: t, folders: n } = S(m.join(e, i)), r = t.filter((e) => !b.has(e) && e !== "declarations.ts").map((e) => {
249
+ let { name: t } = m.parse(e), n = t !== "index" && N(t) || "<Name>";
250
+ return y("plugin-file-loose", `${i}/${e}`, `${i}/${e} is a file, and every plugin is a folder of ${i}/: the server reads nothing of it.`, `Give it a folder with an index.ts that exports it by default — ${i}/${n}/${e} and ${i}/${n}/index.ts, as npx plitzi add plugin writes them — or move it out of ${i}/.`);
251
+ }), a = S(m.join(e, p)).folders, o = new Set(n.filter((e) => x.test(e)).map(M)), s = a.filter((e) => o.has(e)).map((e) => y("plugin-shadowed", `${p}/${e}/`, `${e} is both ${p}/${e}/, as it was built, and a folder of ${i}/: the server runs the built one, and a change to the source shows nowhere.`, `Delete ${p}/${e}/: the source is the plugin now.`)), c = a.flatMap((t) => {
252
+ let n = U(e, t);
253
+ return "problem" in n ? [n.problem] : [];
254
+ });
255
+ return [
256
+ ...n.flatMap((t) => B(e, t)),
257
+ ...V(n),
258
+ ...r,
259
+ ...s,
260
+ ...c
261
+ ];
262
+ }, G = (e, t) => t.map((t) => e.find((e) => E(e, t))).find((e) => e !== void 0), K = (e) => (t) => {
263
+ for (let n of S(m.join(e, t)).folders) {
264
+ let r = G(S(m.join(e, t, n)).files, [...o, a]);
265
+ if (r) return `${t}/${n}/${r}`;
266
+ }
267
+ }, q = (e) => (t) => {
268
+ let n = G(S(m.join(e, t)).files, ["index.ts"]);
269
+ return n ? `${t}/${n}` : void 0;
270
+ }, J = (e, { mode: a, space: o }) => [
271
+ {
272
+ at: i,
273
+ reads: `the server builds plugins from ${i}/ only`,
274
+ holds: K(e)
275
+ },
276
+ {
277
+ at: r,
278
+ reads: `the project's functions are built from ${r}/ only`,
279
+ holds: q(e)
280
+ },
281
+ {
282
+ at: u,
283
+ reads: `the space's runtime is run from ${u}/ only`,
284
+ holds: q(e)
285
+ },
286
+ ...o === "local" ? [{
287
+ at: d,
288
+ reads: `the server's entry point and ${t} import the space from ${f}`,
289
+ holds: q(e)
290
+ }] : [],
291
+ ...a === "server" ? [{
292
+ at: n,
293
+ reads: `the server reads the project's data from ${n}/ only (/data/<file>, ctx.data)`
294
+ }] : [],
295
+ {
296
+ at: l,
297
+ reads: `the server serves ${l}/ only, at the site's root`
298
+ }
299
+ ], Y = (e, t) => {
300
+ let n = m.posix.dirname(t), r = m.posix.basename(t), i = n === "." ? "src" : ".", a = S(m.join(e, n)).folders.filter((e) => k(e, r)).map((e) => m.posix.join(n, e)), o = S(m.join(e, i)).folders.filter((e) => e === r || k(e, r)).map((e) => m.posix.join(i, e));
301
+ return [...a, ...o];
302
+ }, X = (e, t) => J(e, t).flatMap(({ at: t, reads: n, holds: r }) => Y(e, t).map((i) => {
303
+ let a = r?.(i), o = E(i, t), s = `did you mean ${t}/? ${D(n)}.${o ? ` ${A}` : ""}`, c = `Move it: ${j(i, t)}`;
304
+ o ? c = `Rename it: ${j(i, t)}` : C(e, t, "folder") && (c = `Move what it holds into ${t}/, and delete it.`);
305
+ let l = {
306
+ action: "move",
307
+ from: `${i}/`,
308
+ to: `${t}/`
309
+ };
310
+ return a ? y("folder-misplaced", `${i}/`, `${i}/ holds ${a}, and nothing reads it there — ${s}`, c, l) : y("folder-near-miss", `${i}/`, `${i}/ is read by nothing — ${s}`, c, l);
311
+ })), re = (e, n) => {
312
+ if (!C(e, f, "file")) return n.some((e) => e.code === "folder-misplaced" && e.autofix?.action === "move" && e.autofix.to === "src/space/") ? [] : L(e, {
313
+ folder: d,
314
+ accepted: ["index.ts"],
315
+ code: "space-entry-missing",
316
+ lost: `the server's entry point and ${t}, which import the space from ${f}, do not start`,
317
+ write: `Write ${f} exporting the space — export const space = { name, permanentUrl, pages } — or bring back the one git has: git checkout -- ${f}`
318
+ });
319
+ let r = h(m.join(e, f), "utf-8"), i = /^\s*export\s+default\b/m.test(r), a = /\bexport\s+(?:const|let|var|function)\s+space\b/.test(r) || /\bexport\s*\{[^}]*\bspace\b[^}]*\}/.test(r);
320
+ return i && !a ? [y("space-default-export", f, `${f} exports the space by default, and it is imported by name — import { space } from './space/index.ts' — so the server's entry point and ${t} find no space.`, "Export it as `export const space = …` instead of `export default …`.")] : [];
321
+ }, ie = (e) => e.split("\n").map((e) => e.replace(/^(\s*(?:export\s+)?[A-Za-z_][A-Za-z0-9_]*\s*=).*$/, "$1")).join("\n"), ae = (e) => {
322
+ let t = S(e).files, n = t.includes(".env"), r = t.includes(".env.example"), i = w(e, "src", /* @__PURE__ */ new Set(["node_modules"])).filter((e) => m.posix.basename(e) === ".env"), a = !n && i.length === 1, o = i.map((e) => y("env-in-src", e, `${e} is never read: Node reads the project's settings from the .env at its root, as its scripts start it (--env-file-if-exists=.env).`, a ? `Move it to the root: mv ${e} .env` : `Copy what it sets into the root's .env, then delete ${e}.`, a ? {
323
+ action: "move",
324
+ from: e,
325
+ to: ".env"
326
+ } : void 0)), s = n || o.length > 0 ? [] : [y("env-missing", ".env", ".env is missing at the project’s root: none of its settings is set — the keys and secrets its code reads from process.env.", r ? "Copy .env.example and fill it in: cp .env.example .env" : "Write .env with the settings the project reads (process.env.*), and .env.example naming them.", r ? {
327
+ action: "copy",
328
+ from: ".env.example",
329
+ to: ".env"
330
+ } : void 0)], c = r ? [] : [y("env-example-missing", ".env.example", ".env.example is missing: committed where .env never is, it names the settings .env holds, with no secret in them — so a clone knows what to fill in.", n ? "Write it from .env with every value left empty, and commit it." : "Write it — each setting the project reads, as KEY= with no value — and commit it.", n ? {
331
+ action: "write",
332
+ file: ".env.example",
333
+ contents: ie(h(m.join(e, ".env"), "utf-8"))
334
+ } : void 0)];
335
+ return [
336
+ ...o,
337
+ ...s,
338
+ ...c
339
+ ];
340
+ }, oe = (e) => w(e, n).filter((e) => !b.has(m.posix.basename(e)) && !e.endsWith(".json")).map((e) => y("data-not-json", e, `${e} is not JSON: a provider's /data/<file> and ctx.data read JSON files only, and plitzi push leaves it behind.`, `Keep it as JSON (${e.replace(/\.[^./]*$/, "")}.json), or move it out of ${n}/.`)), se = /^\.env(?:\..*)?$|\.(?:pem|key|p12|pfx|jks|keystore|sqlite3?|db|sql|dump)$|secret|credential|password|passwd|private[-_.]?key|id_rsa|id_ed25519|service[-_]?account/i, ce = (e, t) => {
341
+ let r = w(e, l, /* @__PURE__ */ new Set(["node_modules"])), i = r.filter((e) => se.test(m.posix.basename(e))).map((e) => y("public-secret-file", e, `${e} is served to anyone who asks, as it is — everything in ${l}/ is on the internet once the project is deployed — and its name says it holds a secret, a key or a database.`, `Take it out of ${l}/: settings go in the root's .env${t === "server" ? `, data only the server reads in ${n}/` : ""}.`)), a = `${l}/data`, o = t === "server" ? r.filter((e) => e.startsWith(`${a}/`) && e.endsWith(".json")) : [], s = o.slice(0, 3).map((e) => m.posix.basename(e)), c = o.length > 0 ? [y("public-data", `${a}/`, `${a}/ holds ${String(o.length)} JSON file${o.length === 1 ? "" : "s"} (${s.join(", ")}${o.length > s.length ? ", …" : ""}), served to anyone who asks: every visitor can read all of ${o.length === 1 ? "it" : "them"}, not only what a page shows.`, `Data only the server should read goes in ${n}/ — a provider reads it on the server (runtime: 'server', query: '/data/<file>'), a function with ctx.data('<file>'), and neither serves the file. What every visitor may read can stay.`)] : [];
342
+ return [...i, ...c];
343
+ }, Z = (t) => {
344
+ try {
345
+ let n = JSON.parse(h(m.join(t, "package.json"), "utf-8"));
346
+ return e(n) && [n.dependencies, n.devDependencies].some((t) => e(t) && "@plitzi/sdk-server" in t);
347
+ } catch {
348
+ return !1;
349
+ }
350
+ }, le = (e, n) => ({
351
+ mode: n.mode ?? (Z(e) ? "server" : "client"),
352
+ space: n.space ?? (C(e, "src/space", "folder") || C(e, t, "file") ? "local" : "cloud")
353
+ }), Q = (e, t = {}) => {
354
+ let n = le(e, t), i = X(e, n), a = [
355
+ ...W(e),
356
+ ...R(e, {
357
+ folder: r,
358
+ accepted: ["index.ts"],
359
+ code: "functions-entry-missing",
360
+ lost: "none of the project’s functions runs",
361
+ write: `Write ${r}/index.ts exporting defineFunctions({ … }) by default.`
362
+ }),
363
+ ...R(e, {
364
+ folder: u,
365
+ accepted: ["index.ts"],
366
+ code: "runtime-entry-missing",
367
+ lost: "the space’s runtime does not run",
368
+ write: `Write ${u}/index.ts exporting defineRuntime(…) by default — npx plitzi add runtime writes one.`
369
+ }),
370
+ ...n.space === "local" ? re(e, i) : [],
371
+ ...i,
372
+ ...ae(e),
373
+ ...n.mode === "server" ? oe(e) : [],
374
+ ...ce(e, n.mode)
375
+ ];
376
+ return [...a.filter((e) => e.level === "error"), ...a.filter((e) => e.level === "warning")];
377
+ }, ue = (e) => `${e.message}\n → ${e.fix}`, $ = class extends Error {
378
+ #e;
379
+ get findings() {
380
+ return this.#e;
381
+ }
382
+ constructor(e) {
383
+ let t = e.length === 1 ? "one error" : `${String(e.length)} errors`, n = e.map((e, t) => `${String(t + 1)}. ${e.message}\n → ${e.fix}`).join("\n\n"), r = e.filter((e) => e.autofix).length, i = r === e.length ? "these fixes" : `${String(r)} of these fixes`, a = r > 0 ? `npx plitzi doctor --fix makes ${i} itself.` : "npx plitzi doctor says these with the rest of the project.";
384
+ super(`The project is not laid out as Plitzi reads it — ${t}:\n\n${n}\n\n${a}`), this.name = "ProjectLayoutError", this.#e = e;
385
+ }
386
+ };
387
+ Object.defineProperty($, "name", { value: "ProjectLayoutError" });
388
+ var de = (e, t = {}) => {
389
+ let n = Q(e, t), r = n.filter((e) => e.level === "error");
390
+ if (r.length > 0) throw new $(r);
391
+ return n;
392
+ };
393
+ //#endregion
394
+ export { v as PROJECT_LAYOUT_CODES, $ as ProjectLayoutError, de as assertProjectLayout, B as checkPluginFolder, Q as checkProjectLayout, P as elementEntry, ue as layoutFindingText, F as pluginEntry, M as pluginTypeOf, U as readVendorPlugin };
@@ -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 add plugin` 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 pack plugin` 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 };