okno 1.0.0-alpha.2 → 1.0.0-alpha.21

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 (58) hide show
  1. package/dist/acorn-CZBJD705.js +3143 -0
  2. package/dist/boot.d.ts +88 -0
  3. package/dist/boot.d.ts.map +1 -0
  4. package/dist/boot.js +98 -0
  5. package/dist/cli.d.ts +3 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +22 -0
  8. package/dist/codegen/generate.d.ts +5 -1
  9. package/dist/codegen/generate.d.ts.map +1 -1
  10. package/dist/codegen/scan-imports.d.ts +9 -0
  11. package/dist/codegen/scan-imports.d.ts.map +1 -0
  12. package/dist/content-encode-DoojdsVU.js +80 -0
  13. package/dist/core/content-encode.d.ts +44 -0
  14. package/dist/core/content-encode.d.ts.map +1 -0
  15. package/dist/core/order.d.ts +18 -0
  16. package/dist/core/order.d.ts.map +1 -0
  17. package/dist/core/parse.d.ts +15 -0
  18. package/dist/core/parse.d.ts.map +1 -0
  19. package/dist/editor/index.js +29645 -15293
  20. package/dist/index-B1PShnsc.js +132 -0
  21. package/dist/index-B2WzdTzI.js +14263 -0
  22. package/dist/index-ButdD9Pf.js +1825 -0
  23. package/dist/index-DKF0siIz.js +5497 -0
  24. package/dist/index-q-7MEoHz.js +47 -0
  25. package/dist/index.d.ts +1 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +1 -1
  28. package/dist/init.d.ts +39 -0
  29. package/dist/init.d.ts.map +1 -0
  30. package/dist/init.js +221 -0
  31. package/dist/mcp.d.ts +4 -0
  32. package/dist/mcp.d.ts.map +1 -0
  33. package/dist/mcp.js +140 -0
  34. package/dist/okno.css +1 -0
  35. package/dist/order-bAkdncZC.js +21 -0
  36. package/dist/plugin-Cy62173B.js +1080 -0
  37. package/dist/runtime/wrap.d.ts +48 -1
  38. package/dist/runtime/wrap.d.ts.map +1 -1
  39. package/dist/runtime/wrap.js +274 -0
  40. package/dist/types/fields.d.ts +54 -6
  41. package/dist/types/fields.d.ts.map +1 -1
  42. package/dist/types/index.d.ts +3 -2
  43. package/dist/types/index.d.ts.map +1 -1
  44. package/dist/types/permissions.d.ts +22 -0
  45. package/dist/types/permissions.d.ts.map +1 -0
  46. package/dist/types/schema.d.ts +41 -6
  47. package/dist/types/schema.d.ts.map +1 -1
  48. package/dist/vite/dev-server.d.ts +8 -0
  49. package/dist/vite/dev-server.d.ts.map +1 -1
  50. package/dist/vite/index.js +1 -1
  51. package/dist/vite/local-engine.d.ts +34 -0
  52. package/dist/vite/local-engine.d.ts.map +1 -0
  53. package/dist/vite/plugin.d.ts.map +1 -1
  54. package/package.json +42 -11
  55. package/skills/connect-okno/SKILL.md +367 -0
  56. package/src/runtime/wrap.test.ts +82 -0
  57. package/src/runtime/wrap.ts +684 -0
  58. package/dist/plugin-Cwwh6E1P.js +0 -440
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Compose a localized value from the default-locale `base` and a map of
3
+ * per-locale override objects: `{ ...base, <loc>: deepMerge(base, override) }`.
4
+ * The default stays flat at the root; each locale inherits the default then
5
+ * applies its overrides. Generated by the Vite plugin for localized content.
6
+ */
7
+ export declare function __oknoLocalize(base: Record<string, unknown>, overrides: Record<string, Record<string, unknown>>): Record<string, unknown>;
1
8
  /**
2
9
  * Wraps content data in a Proxy that:
3
10
  * - Returns `data-okno` attribute when spread ({...value})
@@ -7,5 +14,45 @@
7
14
  * - Returns empty proxies for non-existing fields
8
15
  * - Supports .on(callback) for reactive change subscriptions
9
16
  */
10
- export declare function __oknoWrap(data: unknown, prefix: string): any;
17
+ export declare function __oknoWrap(data: unknown, prefix: string, slot?: string): any;
18
+ /**
19
+ * Replace reference fields (id or id[]) on a raw record with `__oknoRef` markers
20
+ * carrying the resolved collection item's RAW data + its `<collection>.<id>`
21
+ * path. Driven by the entry's schema `fields` (emitted by the build plugin);
22
+ * `collections` is the `okno:collections` namespace. Non-reference fields pass
23
+ * through untouched. Resolution is one level deep — a referenced item's own
24
+ * references are not re-resolved (avoids cycles).
25
+ */
26
+ export declare function __oknoResolveRefs(raw: unknown, fields: Record<string, any> | undefined, collections: Record<string, any>): unknown;
27
+ export interface OknoStructureDetail {
28
+ /** The array field path, e.g. "home.block" or "home.featuredArticles". */
29
+ list: string;
30
+ op: "reorder" | "remove" | "insert";
31
+ /** reorder */
32
+ from?: number;
33
+ to?: number;
34
+ /** remove / insert — the affected index (insert position). */
35
+ index?: number;
36
+ /** insert (references only): remap the cloned template's CONTENT paths
37
+ * (`data-okno`) from one collection-item prefix to another, since a
38
+ * reference item's content lives at `<collection>.<slug>`, not under the
39
+ * list. Slot boundaries (`data-okno-item`) are always renumbered by list. */
40
+ remap?: {
41
+ from: string;
42
+ to: string;
43
+ };
44
+ /** insert: absolute content path → string value, used to fill the cloned
45
+ * item's text leaves (so a new reference shows the linked item's content;
46
+ * block defaults are empty so the clone is just cleared). */
47
+ values?: Record<string, string>;
48
+ }
49
+ /**
50
+ * Apply a structural op to the live DOM. Attached to `okno:structure` by
51
+ * `__oknoInitStructure()`. The editor calls `updateField` for its optimistic
52
+ * state in the same tick; this keeps the rendered page in sync without a reload.
53
+ */
54
+ export declare function __oknoApplyStructure(detail: OknoStructureDetail): void;
55
+ /** Attach the `okno:structure` listener once. Called by the editor (which is
56
+ * the reliable client-side presence) on scan; safe to call repeatedly. */
57
+ export declare function __oknoInitStructure(): void;
11
58
  //# sourceMappingURL=wrap.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wrap.d.ts","sourceRoot":"","sources":["../../src/runtime/wrap.ts"],"names":[],"mappings":"AAmEA;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,CA0I7D"}
1
+ {"version":3,"file":"wrap.d.ts","sourceRoot":"","sources":["../../src/runtime/wrap.ts"],"names":[],"mappings":"AAyGA;;;;;GAKG;AACH,wBAAgB,cAAc,CAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAChD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,GAAG,CA2L5E;AAoDD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACvC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC9B,OAAO,CA8BT;AAiBD,MAAM,WAAW,mBAAmB;IACnC,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAA;IACnC,cAAc;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;kFAG8E;IAC9E,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;IACpC;;kEAE8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAsGD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CA6DtE;AA6DD;2EAC2E;AAC3E,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C"}
@@ -0,0 +1,274 @@
1
+ const y = /* @__PURE__ */ new Map();
2
+ let g = !1;
3
+ function T() {
4
+ const t = globalThis;
5
+ g || typeof t.document > "u" || (g = !0, t.document.addEventListener("okno:change", (r) => {
6
+ const { path: i, value: s } = r.detail;
7
+ y.get(i)?.forEach((n) => n(s));
8
+ }));
9
+ }
10
+ const E = /* @__PURE__ */ new Set([
11
+ "src",
12
+ "href",
13
+ "alt",
14
+ "id",
15
+ "class",
16
+ "className",
17
+ "width",
18
+ "height",
19
+ "type",
20
+ "name",
21
+ "value"
22
+ ]);
23
+ function j(t) {
24
+ return t.replace(/[-_]+/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim().replace(/^./, (r) => r.toUpperCase());
25
+ }
26
+ function b(t, r = "") {
27
+ if (t == null) {
28
+ if (!r) return "";
29
+ const i = r.split(".").pop() ?? "";
30
+ return !i || E.has(i) ? "" : j(i);
31
+ }
32
+ return typeof t != "object" ? String(t) : m(t) ? t.text ?? "" : "";
33
+ }
34
+ function A(t) {
35
+ return typeof t == "object" && t !== null && !Array.isArray(t) && "src" in t;
36
+ }
37
+ function m(t) {
38
+ return typeof t == "object" && t !== null && !Array.isArray(t) && "url" in t && "text" in t && "external" in t;
39
+ }
40
+ function k(t, r) {
41
+ if (r === void 0) return t;
42
+ if (t === null || typeof t != "object" || Array.isArray(t) || r === null || typeof r != "object" || Array.isArray(r))
43
+ return r;
44
+ const i = { ...t };
45
+ for (const s of Object.keys(r))
46
+ i[s] = k(t[s], r[s]);
47
+ return i;
48
+ }
49
+ function q(t, r) {
50
+ const i = { ...t };
51
+ for (const s of Object.keys(r))
52
+ i[s] = k(t, r[s]);
53
+ return i;
54
+ }
55
+ function p(t, r, i) {
56
+ const s = { __raw: t, __path: r, __slot: i };
57
+ return new Proxy(s, {
58
+ get(n, e) {
59
+ if (e === "data-okno") return n.__path;
60
+ if (e === "slot") return { "data-okno-item": n.__slot ?? n.__path };
61
+ if (e === Symbol.toPrimitive || e === "toString" || e === "valueOf")
62
+ return () => b(n.__raw, n.__path);
63
+ if (e === Symbol.iterator) {
64
+ const f = b(n.__raw, n.__path);
65
+ return function* () {
66
+ yield f;
67
+ };
68
+ }
69
+ if (typeof e == "symbol") return;
70
+ if (e === "toJSON") return () => n.__raw;
71
+ if (e === "on")
72
+ return (f) => {
73
+ T();
74
+ const c = n.__path;
75
+ return y.has(c) || y.set(c, /* @__PURE__ */ new Set()), y.get(c).add(f), () => {
76
+ y.get(c)?.delete(f), y.get(c)?.size === 0 && y.delete(c);
77
+ };
78
+ };
79
+ if (e === "locale")
80
+ return (f) => {
81
+ const c = n.__raw;
82
+ return f && c !== null && typeof c == "object" && !Array.isArray(c) && typeof c[f] == "object" && c[f] !== null ? p(
83
+ c[f],
84
+ n.__path
85
+ ) : p(c, n.__path);
86
+ };
87
+ const o = n.__raw, a = n.__path ? `${n.__path}.${String(e)}` : String(e);
88
+ if (m(o) && typeof e == "string") {
89
+ if (e === "href") return o.url ?? "";
90
+ if (e === "target" && o.external) return "_blank";
91
+ if (e === "rel" && o.external) return "noopener noreferrer";
92
+ }
93
+ if (o != null && typeof o != "object") {
94
+ const f = o[e];
95
+ return f !== void 0 ? typeof f == "function" ? (...c) => f.apply(o, c) : f : p(null, a);
96
+ }
97
+ if (o != null && typeof o == "object" && !Array.isArray(o)) {
98
+ const f = o[String(e)];
99
+ return f == null ? p(null, a) : $(f, a);
100
+ }
101
+ return p(null, a);
102
+ },
103
+ // For spread: expose data-okno, plus all keys for file objects (src, alt, width, height, etc.)
104
+ ownKeys(n) {
105
+ const e = n.__raw;
106
+ return A(e) ? [...Object.keys(e), "data-okno"] : m(e) ? e.external ? ["href", "target", "rel", "data-okno"] : ["href", "data-okno"] : ["data-okno"];
107
+ },
108
+ getOwnPropertyDescriptor(n, e) {
109
+ if (e === "data-okno")
110
+ return {
111
+ value: n.__path,
112
+ enumerable: !0,
113
+ configurable: !0
114
+ };
115
+ const o = n.__raw;
116
+ if (A(o) && typeof e == "string" && e in o)
117
+ return {
118
+ value: o[e],
119
+ enumerable: !0,
120
+ configurable: !0
121
+ };
122
+ if (m(o) && (e === "href" || o.external && (e === "target" || e === "rel")))
123
+ return { value: void 0, enumerable: !0, configurable: !0 };
124
+ },
125
+ has(n, e) {
126
+ if (e === "data-okno" || e === Symbol.toPrimitive || e === "toString") return !0;
127
+ const o = n.__raw;
128
+ return typeof o == "object" && o !== null ? e in o : o != null ? e in Object(o) : !1;
129
+ }
130
+ });
131
+ }
132
+ function w(t) {
133
+ return t !== null && typeof t == "object" && !Array.isArray(t) && "__oknoRef" in t;
134
+ }
135
+ function $(t, r, i) {
136
+ if (w(t)) {
137
+ const { path: s, data: n } = t.__oknoRef;
138
+ return p(n, s, i ?? s);
139
+ }
140
+ if (Array.isArray(t)) {
141
+ const s = t.map((n, e) => $(n, `${r}.${e}`, `${r}.${e}`));
142
+ return Object.defineProperty(s, "toJSON", {
143
+ value: () => t.map((n) => w(n) ? n.__oknoRef.data : n),
144
+ enumerable: !1
145
+ }), s;
146
+ }
147
+ return p(t, r, i);
148
+ }
149
+ function z(t, r, i) {
150
+ if (!t || typeof t != "object" || Array.isArray(t) || !r) return t;
151
+ const s = { ...t };
152
+ for (const n of Object.keys(r)) {
153
+ const e = r[n];
154
+ if (!e || e.type !== "reference" || typeof e.collection != "string") continue;
155
+ const o = i?.[e.collection] ?? i?.[e.collection.replace(/-/g, "_")] ?? [], a = /* @__PURE__ */ new Map();
156
+ for (const u of o) {
157
+ const l = typeof u?.toJSON == "function" ? u.toJSON() : u;
158
+ l && typeof l == "object" && typeof l.slug == "string" && a.set(l.slug, u);
159
+ }
160
+ const f = (u) => {
161
+ if (typeof u != "string" || !u) return null;
162
+ const l = a.get(u);
163
+ if (!l) return null;
164
+ const S = typeof l.toJSON == "function" ? l.toJSON() : l;
165
+ return { __oknoRef: { path: `${e.collection}.${u}`, data: S } };
166
+ }, c = t[n];
167
+ s[n] = Array.isArray(c) ? c.map(f).filter(Boolean) : f(c);
168
+ }
169
+ return s;
170
+ }
171
+ const _ = "data-okno-item", h = "data-okno", O = [h, _];
172
+ function d(t, r, i, s = O) {
173
+ if (r === i) return;
174
+ const n = (e) => {
175
+ for (const o of s) {
176
+ const a = e.getAttribute(o);
177
+ a != null && (a === r ? e.setAttribute(o, i) : a.startsWith(r + ".") && e.setAttribute(o, i + a.slice(r.length)));
178
+ }
179
+ };
180
+ n(t);
181
+ for (const e of s) t.querySelectorAll(`[${e}]`).forEach(n);
182
+ }
183
+ function x(t) {
184
+ if (typeof document > "u") return [];
185
+ const r = new RegExp(`^${t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\.(\\d+)$`), i = /* @__PURE__ */ new Map();
186
+ document.querySelectorAll(`[${_}]`).forEach((n) => {
187
+ const e = n.getAttribute(_);
188
+ if (!e || !r.test(e) || !n.parentElement || !(n instanceof HTMLElement)) return;
189
+ const o = i.get(n.parentElement) ?? [];
190
+ o.push(n), i.set(n.parentElement, o);
191
+ });
192
+ const s = (n) => Number(n.getAttribute(_).match(r)[1]);
193
+ return [...i.entries()].map(([n, e]) => ({
194
+ parent: n,
195
+ wrappers: e.sort((o, a) => s(o) - s(a))
196
+ }));
197
+ }
198
+ function L(t) {
199
+ t.querySelectorAll(`[${h}]`).forEach((r) => {
200
+ r.children.length === 0 && (r.textContent = "");
201
+ });
202
+ }
203
+ function M(t, r) {
204
+ t.querySelectorAll(`[${h}]`).forEach((i) => {
205
+ const s = i.getAttribute(h);
206
+ s && s in r && i.children.length === 0 && (i.textContent = r[s] ?? "");
207
+ });
208
+ }
209
+ function N() {
210
+ return typeof window < "u" && typeof window.matchMedia == "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
211
+ }
212
+ function R(t) {
213
+ const r = document;
214
+ return typeof r.startViewTransition != "function" || N() ? (t(), Promise.resolve()) : r.startViewTransition(t).finished.catch(() => {
215
+ });
216
+ }
217
+ let C = 0;
218
+ function H(t) {
219
+ if (typeof document > "u" || !t?.list || !t.op) return;
220
+ const { list: r, op: i } = t, s = x(r);
221
+ if (i === "insert" && s.every((u) => u.wrappers.length === 0) || s.length === 0) return;
222
+ const n = [], e = (u) => {
223
+ u.style.viewTransitionName = `okno-vt-${++C}`, n.push(u);
224
+ };
225
+ for (const u of s) for (const l of u.wrappers) e(l);
226
+ const o = document.documentElement;
227
+ o.classList.add("okno-vt-active");
228
+ const a = document.getElementById("okno-shadow-root"), f = a instanceof HTMLElement ? a.style.cssText : null;
229
+ a instanceof HTMLElement && (a.style.cssText = `${f};position:fixed;inset:0;pointer-events:none;view-transition-name:okno-editor`), R(() => {
230
+ for (const u of s)
231
+ i === "reorder" ? I(u, r, t.from, t.to) : i === "remove" ? J(u, r, t.index) : i === "insert" && V(u, r, t, e);
232
+ }).finally(() => {
233
+ for (const u of n) u.style.viewTransitionName = "";
234
+ o.classList.remove("okno-vt-active"), a instanceof HTMLElement && f !== null && (a.style.cssText = f);
235
+ });
236
+ }
237
+ function I(t, r, i, s) {
238
+ const n = t.wrappers, e = n.length;
239
+ if (i < 0 || i >= e || s < 0 || s >= e || i === s) return;
240
+ const o = n.slice(), [a] = o.splice(i, 1);
241
+ o.splice(s, 0, a);
242
+ const f = o.map((u) => u.getAttribute(_));
243
+ o.forEach((u, l) => d(u, f[l], `${r}.${l}`));
244
+ const c = n[e - 1].nextSibling;
245
+ for (const u of o) t.parent.insertBefore(u, c);
246
+ }
247
+ function J(t, r, i) {
248
+ const s = t.wrappers;
249
+ if (!(i < 0 || i >= s.length)) {
250
+ s[i].remove();
251
+ for (let n = i + 1; n < s.length; n++) d(s[n], `${r}.${n}`, `${r}.${n - 1}`);
252
+ }
253
+ }
254
+ function V(t, r, i, s) {
255
+ const n = t.wrappers, e = n.length;
256
+ if (e === 0) return;
257
+ const o = Math.max(0, Math.min(i.index ?? e, e)), a = o < e ? o : e - 1, f = n[a].getAttribute(_), c = n[a].cloneNode(!0);
258
+ for (let l = e - 1; l >= o; l--) d(n[l], `${r}.${l}`, `${r}.${l + 1}`);
259
+ d(c, f, `${r}.${o}`), i.remap && d(c, i.remap.from, i.remap.to, [h]), i.values ? M(c, i.values) : L(c), c.style.viewTransitionName = "", s(c);
260
+ const u = o < e ? n[o] : n[e - 1].nextSibling;
261
+ t.parent.insertBefore(c, u);
262
+ }
263
+ let v = !1;
264
+ function B() {
265
+ const t = globalThis;
266
+ v || typeof t.document > "u" || (v = !0, t.document.addEventListener("okno:structure", (r) => H(r.detail)));
267
+ }
268
+ export {
269
+ H as __oknoApplyStructure,
270
+ B as __oknoInitStructure,
271
+ q as __oknoLocalize,
272
+ z as __oknoResolveRefs,
273
+ p as __oknoWrap
274
+ };
@@ -1,5 +1,8 @@
1
1
  /** Base properties shared by all field types */
2
2
  interface FieldBase {
3
+ /** Display label shown above the field in the editor (falls back to a
4
+ * humanized version of the field key). */
5
+ label?: string;
3
6
  required?: boolean;
4
7
  localized?: boolean;
5
8
  hidden?: boolean;
@@ -9,6 +12,7 @@ interface FieldBase {
9
12
  export interface StringField extends FieldBase {
10
13
  type: "string";
11
14
  default?: string;
15
+ placeholder?: string;
12
16
  min?: number;
13
17
  max?: number;
14
18
  pattern?: string;
@@ -42,14 +46,39 @@ export interface EnumField extends FieldBase {
42
46
  multiple?: boolean;
43
47
  default?: string | string[];
44
48
  }
45
- /** Rich text / HTML content */
49
+ /** Rich text / HTML content. `features` restricts what authors can apply
50
+ * (bold, italic, headings, links, lists…); omitted = a curated default set,
51
+ * an empty array = plain paragraphs only. Each value is a Tiptap mark/node
52
+ * key or a heading level (`h1`/`h2`/`h3`). */
46
53
  export interface RichtextField extends FieldBase {
47
54
  type: "richtext";
55
+ features?: string[];
48
56
  }
49
- /** Files file (image, video, audio, document) */
50
- export interface FileField extends FieldBase {
51
- type: "file";
52
- accept?: "image" | "video" | "audio" | "document" | "*";
57
+ /** Media kinds a {@link MediaField} can accept. */
58
+ export type MediaKind = "image" | "video" | "audio" | "document";
59
+ /** Media field — image, video, audio, or file. `accept` restricts which kinds
60
+ * are allowed (omitted/empty = any kind). `multiple` turns it into a gallery
61
+ * (an array of media items instead of one). Replaces the old Image/Gallery/File
62
+ * split: a hero image is `{ accept: ["image"] }`, a photo+clip gallery is
63
+ * `{ accept: ["image", "video"], multiple: true }`, downloadable docs are
64
+ * `{ accept: ["document"], multiple: true }`. */
65
+ export interface MediaField extends FieldBase {
66
+ type: "media";
67
+ accept?: MediaKind[];
68
+ multiple?: boolean;
69
+ /** Files folder this field's uploads are saved to (folder id, "" = root). */
70
+ uploadFolder?: string;
71
+ }
72
+ /** Color field — stores a raw CSS color string (any valid CSS color). Edited
73
+ * via a dependency-free HSV picker. Foundation for the Theme global. */
74
+ export interface ColorField extends FieldBase {
75
+ type: "color";
76
+ default?: string;
77
+ }
78
+ /** Link field — stores `{ text, url, external }`. Spreads onto an `<a>`
79
+ * (url→href, +target/rel when external) and renders its text as the child. */
80
+ export interface LinkField extends FieldBase {
81
+ type: "link";
53
82
  }
54
83
  /** Auto-generated URL slug from another field */
55
84
  export interface SlugField extends FieldBase {
@@ -67,7 +96,26 @@ export interface GroupField {
67
96
  type: "group";
68
97
  fields: Record<string, AnyField>;
69
98
  }
99
+ /** One or more embedded instances of a reusable Block (a named field shape from
100
+ * `schema.blocks`). Each placement owns its OWN values — an embed, not a
101
+ * reference. `multiple` makes it a repeatable array of instances. */
102
+ export interface BlockField extends FieldBase {
103
+ type: "block";
104
+ block: string;
105
+ multiple?: boolean;
106
+ }
107
+ /** Editor-only section divider. Organizes the field list into labeled,
108
+ * collapsible sections; it does NOT nest or namespace the stored data (fields
109
+ * after it stay flat). Purely presentational — replaces nesting groups for the
110
+ * common "just break up the list" case. */
111
+ export interface DividerField {
112
+ type: "divider";
113
+ /** Section label shown in the editor. */
114
+ label?: string;
115
+ /** Start the section collapsed. */
116
+ collapsed?: boolean;
117
+ }
70
118
  /** Union of all field types */
71
- export type AnyField = StringField | NumberField | BooleanField | DateField | EnumField | RichtextField | FileField | SlugField | ReferenceField | GroupField;
119
+ export type AnyField = StringField | NumberField | BooleanField | DateField | EnumField | RichtextField | MediaField | ColorField | LinkField | SlugField | ReferenceField | GroupField | BlockField | DividerField;
72
120
  export {};
73
121
  //# sourceMappingURL=fields.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../src/types/fields.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,UAAU,SAAS;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;CACb;AAED,uBAAuB;AACvB,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC7C,IAAI,EAAE,QAAQ,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,SAAS,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,oBAAoB;AACpB,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC7C,IAAI,EAAE,QAAQ,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,qBAAqB;AACrB,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC9C,IAAI,EAAE,SAAS,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,0BAA0B;AAC1B,MAAM,WAAW,SAAU,SAAQ,SAAS;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CACxB;AAED,8BAA8B;AAC9B,MAAM,WAAW,SAAU,SAAQ,SAAS;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC3B;AAED,+BAA+B;AAC/B,MAAM,WAAW,aAAc,SAAQ,SAAS;IAC/C,IAAI,EAAE,UAAU,CAAA;CAChB;AAED,iDAAiD;AACjD,MAAM,WAAW,SAAU,SAAQ,SAAS;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,GAAG,CAAA;CACvD;AAED,iDAAiD;AACjD,MAAM,WAAW,SAAU,SAAQ,SAAS;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACZ;AAED,sCAAsC;AACtC,MAAM,WAAW,cAAe,SAAQ,SAAS;IAChD,IAAI,EAAE,WAAW,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,yBAAyB;AACzB,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;CAChC;AAED,+BAA+B;AAC/B,MAAM,MAAM,QAAQ,GACjB,WAAW,GACX,WAAW,GACX,YAAY,GACZ,SAAS,GACT,SAAS,GACT,aAAa,GACb,SAAS,GACT,SAAS,GACT,cAAc,GACd,UAAU,CAAA"}
1
+ {"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../src/types/fields.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
- export type { StringField, NumberField, BooleanField, DateField, EnumField, RichtextField, FileField, SlugField, ReferenceField, GroupField, AnyField, } from "./fields.ts";
2
- export type { Fields, PageDef, CollectionDef, GlobalDef, OknoSchema, OknoConfig, } from "./schema.ts";
1
+ export type { StringField, NumberField, BooleanField, DateField, EnumField, RichtextField, MediaField, MediaKind, SlugField, ReferenceField, GroupField, BlockField, DividerField, AnyField, } from "./fields.ts";
2
+ export type { Fields, PageDef, CollectionDef, GlobalDef, BlockDef, OknoSchema, Schema, OknoConfig, } from "./schema.ts";
3
+ export type { ResourcePermissions, RolePermissions, PermissionsConfig } from "./permissions.ts";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACZ,SAAS,EACT,SAAS,EACT,aAAa,EACb,SAAS,EACT,SAAS,EACT,cAAc,EACd,UAAU,EACV,QAAQ,GACR,MAAM,aAAa,CAAA;AAEpB,YAAY,EACX,MAAM,EACN,OAAO,EACP,aAAa,EACb,SAAS,EACT,UAAU,EACV,UAAU,GACV,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACZ,SAAS,EACT,SAAS,EACT,aAAa,EACb,UAAU,EACV,SAAS,EACT,SAAS,EACT,cAAc,EACd,UAAU,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,GACR,MAAM,aAAa,CAAA;AAEpB,YAAY,EACX,MAAM,EACN,OAAO,EACP,aAAa,EACb,SAAS,EACT,QAAQ,EACR,UAAU,EACV,MAAM,EACN,UAAU,GACV,MAAM,aAAa,CAAA;AAEpB,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,22 @@
1
+ /** The actions a role may perform on a resource. Shape of every entry in
2
+ * `okno/permissions.ts`. */
3
+ export interface ResourcePermissions {
4
+ read: boolean;
5
+ write: boolean;
6
+ delete: boolean;
7
+ publish: boolean;
8
+ }
9
+ /** Per-resource permissions for a single role. */
10
+ export interface RolePermissions {
11
+ pages: ResourcePermissions;
12
+ collections: ResourcePermissions;
13
+ globals: ResourcePermissions;
14
+ users: ResourcePermissions;
15
+ permissions: ResourcePermissions;
16
+ }
17
+ /** The full permissions config users define in `okno/permissions.ts`
18
+ * (`export default { roles: { ... } } satisfies PermissionsConfig`). */
19
+ export interface PermissionsConfig {
20
+ roles: Record<string, RolePermissions>;
21
+ }
22
+ //# sourceMappingURL=permissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/types/permissions.ts"],"names":[],"mappings":"AAAA;6BAC6B;AAC7B,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;CAChB;AAED,kDAAkD;AAClD,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,mBAAmB,CAAA;IAC1B,WAAW,EAAE,mBAAmB,CAAA;IAChC,OAAO,EAAE,mBAAmB,CAAA;IAC5B,KAAK,EAAE,mBAAmB,CAAA;IAC1B,WAAW,EAAE,mBAAmB,CAAA;CAChC;AAED;yEACyE;AACzE,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;CACtC"}
@@ -1,33 +1,63 @@
1
- import type { AnyField } from "./fields.ts";
1
+ import type { AnyField, SlugField } from "./fields.ts";
2
2
  /** Fields definition - a record of field name to field config */
3
3
  export type Fields = Record<string, AnyField>;
4
4
  /** Page definition - a singleton content type */
5
5
  export interface PageDef {
6
6
  /** Display name shown in editor (sidebar, page title). Falls back to slug. */
7
7
  name?: string;
8
+ /** Relative URL this page lives at on the live site (e.g. "/about"). Lets the
9
+ * editor deep-link to this page on open and offer a "Visit page" jump. */
10
+ url?: string;
8
11
  fields: Fields;
9
12
  }
10
13
  /** Collection definition - multiple items with required slug */
11
14
  export interface CollectionDef {
12
15
  name?: string;
16
+ /** Manual item order, as a list of item slugs. okno owns no other ordering —
17
+ * any date/field sort is the dev's own `.sort()` before `.map()`. Items not
18
+ * listed here (e.g. added outside the editor) sort after, in file order. New
19
+ * items prepend, so the default reads newest-first. Maintained by the editor
20
+ * (drag-to-reorder, create, delete); drives `okno:collections` iteration. */
21
+ order?: string[];
22
+ /** Opt-in draft workflow. When true, items carry a `status` ("draft" | "live")
23
+ * the editor toggles, and items with `status: "draft"` are EXCLUDED from
24
+ * `okno:collections` at build (so references to them resolve to nothing too).
25
+ * Off → the collection has no status concept at all. Orthogonal to git publish:
26
+ * a draft item still lives in the repo, it just isn't served. */
27
+ drafts?: boolean;
28
+ /** Route pattern for this collection's items, with field-key tokens — e.g.
29
+ * `/blog/[category]/[slug]`. Drives the editor's "Visit page" link + deep-link
30
+ * routing (read in `app/editor/lib/urls.ts`). */
31
+ url?: string;
13
32
  fields: Fields & {
14
- slug: {
15
- type: "slug";
16
- from: string;
17
- };
33
+ slug: SlugField;
18
34
  };
19
35
  }
20
- /** Global definition - site-wide singleton */
36
+ /** Global definition - a singleton content type. One shared entry with its own
37
+ * values at `globals/<slug>.ts`, read everywhere (Navigation, SEO defaults,
38
+ * Site Settings). Edited once, reflected across the whole site. */
21
39
  export interface GlobalDef {
22
40
  name?: string;
23
41
  fields: Fields;
24
42
  }
43
+ /** Block definition - a reusable field shape embedded into pages/collections
44
+ * via a Block field (`{ type: "block", block: "<key>" }`). Has NO standalone
45
+ * entry or content file; each placement owns its own values (an embed, not a
46
+ * reference). Use for repeating structures like cards or FAQ items. */
47
+ export interface BlockDef {
48
+ name?: string;
49
+ fields: Fields;
50
+ }
25
51
  /** The full schema that users define in okno/schema.ts */
26
52
  export interface OknoSchema {
27
53
  pages?: Record<string, PageDef>;
28
54
  collections?: Record<string, CollectionDef>;
29
55
  globals?: Record<string, GlobalDef>;
56
+ blocks?: Record<string, BlockDef>;
30
57
  }
58
+ /** Alias for {@link OknoSchema} — the name used in scaffolded `okno/schema.ts`
59
+ * files (`export default { ... } satisfies Schema`). */
60
+ export type Schema = OknoSchema;
31
61
  /** Plugin configuration */
32
62
  export interface OknoConfig {
33
63
  /** Path to the okno content directory (default: "okno") */
@@ -36,6 +66,11 @@ export interface OknoConfig {
36
66
  apiUrl?: string;
37
67
  /** Whether this is the editor build (disables HMR on content changes) */
38
68
  isEditor?: boolean;
69
+ /** Public demo mode: the editor boots login-less, reads content from a
70
+ * static `okno-demo.json` snapshot, and no-ops every write (nothing is
71
+ * persisted; a reload resets). For showcasing okno on a marketing site —
72
+ * see `docs/demo-mode.md`. A demo build never reaches the backend. */
73
+ demo?: boolean;
39
74
  /** Localization configuration */
40
75
  locales?: {
41
76
  /** Default/base locale code (e.g. "en") */
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/types/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE3C,iEAAiE;AACjE,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AAE7C,iDAAiD;AACjD,MAAM,WAAW,OAAO;IACvB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACd;AAED,gEAAgE;AAChE,MAAM,WAAW,aAAa;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,GAAG;QAChB,IAAI,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KACpC,CAAA;CACD;AAED,8CAA8C;AAC9C,MAAM,WAAW,SAAS;IACzB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACd;AAED,0DAA0D;AAC1D,MAAM,WAAW,UAAU;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CACnC;AAED,2BAA2B;AAC3B,MAAM,WAAW,UAAU;IAC1B,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,yEAAyE;IACzE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,iCAAiC;IACjC,OAAO,CAAC,EAAE;QACT,2CAA2C;QAC3C,OAAO,EAAE,MAAM,CAAA;QACf,uDAAuD;QACvD,SAAS,EAAE,MAAM,EAAE,CAAA;KACnB,CAAA;CACD"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/types/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEtD,iEAAiE;AACjE,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AAE7C,iDAAiD;AACjD,MAAM,WAAW,OAAO;IACvB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;+EAC2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACd;AAED,gEAAgE;AAChE,MAAM,WAAW,aAAa;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;kFAI8E;IAC9E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB;;;;sEAIkE;IAClE,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;sDAEkD;IAClD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,GAAG;QAChB,IAAI,EAAE,SAAS,CAAA;KACf,CAAA;CACD;AAED;;oEAEoE;AACpE,MAAM,WAAW,SAAS;IACzB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACd;AAED;;;wEAGwE;AACxE,MAAM,WAAW,QAAQ;IACxB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACd;AAED,0DAA0D;AAC1D,MAAM,WAAW,UAAU;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;CACjC;AAED;yDACyD;AACzD,MAAM,MAAM,MAAM,GAAG,UAAU,CAAA;AAE/B,2BAA2B;AAC3B,MAAM,WAAW,UAAU;IAC1B,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,yEAAyE;IACzE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;2EAGuE;IACvE,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,iCAAiC;IACjC,OAAO,CAAC,EAAE;QACT,2CAA2C;QAC3C,OAAO,EAAE,MAAM,CAAA;QACf,uDAAuD;QACvD,SAAS,EAAE,MAAM,EAAE,CAAA;KACnB,CAAA;CACD"}
@@ -1,4 +1,12 @@
1
1
  import type { ViteDevServer } from "vite";
2
+ /**
3
+ * Resolve a request path to a file strictly inside {oknoDir}/files, or null if
4
+ * it escapes (path traversal). Node's HTTP server does not normalize `..`, so
5
+ * `join(oknoDir, "files", rawPath)` alone would happily serve `../../secret`.
6
+ * We decode, then verify the canonical resolved path stays under the files
7
+ * root — a substring `..` check is not enough once decoding is in play.
8
+ */
9
+ export declare function resolveOknoFile(oknoDir: string, rawPath: string): string | null;
2
10
  /**
3
11
  * Dev server middleware: single endpoint for syncing local files with remote.
4
12
  * All content CRUD goes through the backend. This just pulls changes
@@ -1 +1 @@
1
- {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../src/vite/dev-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AAczC;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,QA+FrE"}
1
+ {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../src/vite/dev-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AAMzC;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc/E;AAcD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,QAoJrE"}
@@ -1,4 +1,4 @@
1
- import { o as a } from "../plugin-Cwwh6E1P.js";
1
+ import { o as a } from "../plugin-Cy62173B.js";
2
2
  export {
3
3
  a as okno
4
4
  };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Local engine — dev-only content I/O straight to the working tree.
3
+ *
4
+ * In dev the editor talks to these `/__okno/api/*` routes instead of the hosted
5
+ * backend (`api.okno.build`). They mirror the backend's content/schema/publish
6
+ * request+response shapes 1:1 so the editor only swaps the base URL (see
7
+ * `Project.contentApiBase`). No GitHub, no network, no billing — content lives
8
+ * in the working tree on whatever branch is checked out, and "publish" is a
9
+ * local `git commit && push` of that branch.
10
+ *
11
+ * NOT a security boundary — localhost dev only.
12
+ */
13
+ import type { ViteDevServer } from "vite";
14
+ export declare function markSelfWritten(abs: string): void;
15
+ /** True if `abs` was engine-written in the last few seconds. TTL-based (not
16
+ * delete-on-read) so a duplicate watcher event for the same write is still
17
+ * recognized; a genuine later edit (ts now stale) falls through to HMR. */
18
+ export declare function consumeSelfWritten(abs: string): boolean;
19
+ /** The full content snapshot the editor's load() consumes: raw `schema.ts`
20
+ * text, raw `users.json` text, and every content `.ts` keyed by relative path.
21
+ * Shared by the dev GET /content handler and the demo-mode build emit so both
22
+ * produce a byte-identical shape (see `docs/demo-mode.md`). */
23
+ export declare function snapshotContent(oknoDir: string): {
24
+ schema: string | null;
25
+ users: string | null;
26
+ content: Record<string, string>;
27
+ files: Array<{
28
+ path: string;
29
+ filename: string;
30
+ size: number;
31
+ }>;
32
+ };
33
+ export declare function registerLocalEngine(server: ViteDevServer, oknoDir: string): void;
34
+ //# sourceMappingURL=local-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-engine.d.ts","sourceRoot":"","sources":["../../src/vite/local-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AAiBzC,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEjD;AACD;;4EAE4E;AAC5E,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGvD;AAgCD;;;gEAGgE;AAChE,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG;IACjD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC9D,CAYA;AAmQD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CA+XhF"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAClC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAepD,wBAAgB,IAAI,CAAC,MAAM,GAAE,UAAe,GAAG,MAAM,CAqHpD"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAClC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAsEpD,wBAAgB,IAAI,CAAC,MAAM,GAAE,UAAe,GAAG,MAAM,CAyUpD"}