okno 1.0.0-beta.13 → 1.0.0-beta.14

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.
@@ -0,0 +1,459 @@
1
+ import { extname as z, join as w, dirname as B, relative as N, sep as L, resolve as m } from "node:path";
2
+ import { existsSync as E, readFileSync as U, mkdirSync as I, writeFileSync as R, cpSync as Y } from "node:fs";
3
+ import { execSync as Q } from "node:child_process";
4
+ import { fileURLToPath as Z } from "node:url";
5
+ import { i as x, g as q, s as v, b as tt, a as et, c as ot, e as nt, d as rt, f as it, h as M, j as $, k as st } from "./dispatch-C34WXMSB.js";
6
+ import { simpleGit as H } from "simple-git";
7
+ import "./acorn-CZBJD705.js";
8
+ function A(n, i, e) {
9
+ n.statusCode = i, n.setHeader("Content-Type", "application/json"), n.setHeader("Cache-Control", "no-store"), n.end(JSON.stringify(e));
10
+ }
11
+ function at(n) {
12
+ return new Promise((i) => {
13
+ let e = "";
14
+ n.on("data", (t) => e += t), n.on("end", () => {
15
+ try {
16
+ i(e ? JSON.parse(e) : {});
17
+ } catch {
18
+ i({});
19
+ }
20
+ }), n.on("error", () => i({}));
21
+ });
22
+ }
23
+ function lt(n) {
24
+ return new Promise((i, e) => {
25
+ const t = [];
26
+ n.on("data", (a) => t.push(a)), n.on("end", () => i(Buffer.concat(t))), n.on("error", e);
27
+ });
28
+ }
29
+ function ct(n, i) {
30
+ if (i) {
31
+ for (const e of new Set(i.modules)) {
32
+ const t = n.moduleGraph.getModuleById("\0okno:" + e);
33
+ t && n.moduleGraph.invalidateModule(t);
34
+ }
35
+ for (const e of new Set(i.files))
36
+ n.moduleGraph.getModulesByFile(e)?.forEach((t) => n.moduleGraph.invalidateModule(t));
37
+ }
38
+ }
39
+ function ut(n, i) {
40
+ n.middlewares.use(async (e, t, a) => {
41
+ if (!e.url?.startsWith("/__okno/api/")) return a();
42
+ const h = e.url.slice(12).split("?")[0], o = {
43
+ method: e.method || "GET",
44
+ route: h,
45
+ json: () => at(e),
46
+ binary: () => lt(e),
47
+ header: (r) => {
48
+ const s = e.headers[r];
49
+ return Array.isArray(s) ? s[0] : s;
50
+ }
51
+ };
52
+ try {
53
+ const r = await x(i, o);
54
+ if (!r) return a();
55
+ ct(n, r.invalidation), A(t, r.status, r.body);
56
+ } catch (r) {
57
+ A(t, 500, { error: r instanceof Error ? r.message : String(r) });
58
+ }
59
+ });
60
+ }
61
+ function dt(n, i) {
62
+ let e;
63
+ try {
64
+ e = decodeURIComponent(i);
65
+ } catch {
66
+ return null;
67
+ }
68
+ if (!e || e.includes("\0")) return null;
69
+ const t = m(n, "files"), a = m(t, e);
70
+ return a === t || !a.startsWith(t + L) ? null : a;
71
+ }
72
+ const P = "okno", ft = {
73
+ ".webp": "image/webp",
74
+ ".png": "image/png",
75
+ ".jpg": "image/jpeg",
76
+ ".jpeg": "image/jpeg",
77
+ ".gif": "image/gif",
78
+ ".svg": "image/svg+xml",
79
+ ".avif": "image/avif",
80
+ ".ico": "image/x-icon",
81
+ ".mp4": "video/mp4",
82
+ ".webm": "video/webm",
83
+ ".ogg": "video/ogg",
84
+ ".mp3": "audio/mpeg",
85
+ ".wav": "audio/wav",
86
+ ".flac": "audio/flac",
87
+ ".pdf": "application/pdf",
88
+ ".woff2": "font/woff2",
89
+ ".woff": "font/woff",
90
+ ".ttf": "font/ttf",
91
+ ".otf": "font/otf"
92
+ };
93
+ function pt(n, i) {
94
+ ut(n, i), n.middlewares.use((e, t, a) => {
95
+ if (e.method !== "GET" || !e.url?.startsWith("/okno/files/")) return a();
96
+ const h = e.url.slice(12).split("?")[0];
97
+ if (!h) return a();
98
+ const o = dt(i, h);
99
+ if (!o)
100
+ return t.statusCode = 403, t.end("Forbidden");
101
+ if (!E(o))
102
+ return t.statusCode = 404, t.end("Not found");
103
+ const r = z(o).toLowerCase();
104
+ t.setHeader("Content-Type", ft[r] || "application/octet-stream"), t.setHeader("Cache-Control", "public, max-age=3600"), t.end(U(o));
105
+ }), n.middlewares.use(async (e, t, a) => {
106
+ if (!e.url?.startsWith("/__okno/")) return a();
107
+ const h = e.url.slice(8);
108
+ t.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate"), t.setHeader("Pragma", "no-cache"), t.setHeader("Expires", "0");
109
+ try {
110
+ if (e.method === "GET" && h === "repo") {
111
+ t.setHeader("Content-Type", "application/json");
112
+ try {
113
+ const o = H(n.config.root), r = (await o.remote(["get-url", "origin"]))?.toString().trim(), s = (await o.revparse(["--abbrev-ref", "HEAD"])).trim(), { owner: p, repo: l } = gt(r);
114
+ return t.end(
115
+ JSON.stringify({ ok: !0, owner: p, repo: l, branch: s || null, remote: r || null })
116
+ );
117
+ } catch (o) {
118
+ return t.end(JSON.stringify({ ok: !1, error: String(o) }));
119
+ }
120
+ }
121
+ if (e.method === "POST" && h.startsWith("mirror")) {
122
+ const r = new URL(e.url, "http://localhost").searchParams.get("path");
123
+ if (!r || r.includes("..") || !r.startsWith("files/"))
124
+ return t.statusCode = 400, t.setHeader("Content-Type", "application/json"), t.end(JSON.stringify({ error: "Invalid path" }));
125
+ const s = w(i, r);
126
+ if (E(s))
127
+ return t.setHeader("Content-Type", "application/json"), t.end(JSON.stringify({ ok: !0, skipped: !0 }));
128
+ const p = await mt(e);
129
+ return I(B(s), { recursive: !0 }), R(s, p), t.setHeader("Content-Type", "application/json"), t.end(JSON.stringify({ ok: !0, written: r, bytes: p.length }));
130
+ }
131
+ if (e.method === "POST" && h === "sync") {
132
+ const r = (await ht(e))?.path;
133
+ if (r) {
134
+ if (r.includes("..") || r.includes("\0"))
135
+ return t.statusCode = 400, t.setHeader("Content-Type", "application/json"), t.end(JSON.stringify({ error: "Invalid path" }));
136
+ const u = w(i, r);
137
+ try {
138
+ const c = H(i);
139
+ await c.fetch("origin", P);
140
+ const g = (await c.revparse(["--show-toplevel"])).trim(), f = N(g, u).split(L).join("/"), y = await c.show([`origin/${P}:${f}`]);
141
+ I(B(u), { recursive: !0 }), R(u, y);
142
+ } catch (c) {
143
+ const g = c instanceof Error ? c.message : String(c);
144
+ console.warn(
145
+ `[okno] sync: could not materialize ${r} from origin/${P} — ${g.split(`
146
+ `)[0]}`
147
+ );
148
+ }
149
+ return F(n, r, u), t.setHeader("Content-Type", "application/json"), t.end(JSON.stringify({ ok: !0, invalidated: r }));
150
+ }
151
+ const s = H(i), p = await s.revparse(["--show-toplevel"]), l = N(p.trim(), i);
152
+ try {
153
+ const u = await s.pull();
154
+ for (const c of u.files)
155
+ if (c.startsWith(`${l}/`)) {
156
+ const g = c.slice(`${l}/`.length), f = w(i, g);
157
+ F(n, g, f);
158
+ }
159
+ return t.setHeader("Content-Type", "application/json"), t.end(JSON.stringify({ ok: !0, files: u.files }));
160
+ } catch (u) {
161
+ const c = u instanceof Error ? u.message : String(u);
162
+ return console.warn(`[okno] sync: git pull skipped — ${c.split(`
163
+ `)[0]}`), t.setHeader("Content-Type", "application/json"), t.end(JSON.stringify({ ok: !0, pullSkipped: !0, reason: c }));
164
+ }
165
+ }
166
+ a();
167
+ } catch (o) {
168
+ t.statusCode = 500, t.end(JSON.stringify({ error: String(o) }));
169
+ }
170
+ });
171
+ }
172
+ function gt(n) {
173
+ if (!n) return { owner: null, repo: null };
174
+ const i = n.match(/github\.com[:/]([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
175
+ return i ? { owner: i[1], repo: i[2] } : { owner: null, repo: null };
176
+ }
177
+ function mt(n) {
178
+ return new Promise((i, e) => {
179
+ const t = [];
180
+ n.on("data", (a) => t.push(a)), n.on("end", () => i(Buffer.concat(t))), n.on("error", e);
181
+ });
182
+ }
183
+ function ht(n) {
184
+ return new Promise((i) => {
185
+ let e = "";
186
+ n.on("data", (t) => {
187
+ e += t;
188
+ }), n.on("end", () => {
189
+ try {
190
+ i(e ? JSON.parse(e) : null);
191
+ } catch {
192
+ i(null);
193
+ }
194
+ }), n.on("error", () => i(null));
195
+ });
196
+ }
197
+ function F(n, i, e) {
198
+ const t = "\0okno:";
199
+ let a;
200
+ if (i.startsWith("pages/") ? a = t + "pages" : i.startsWith("collections/") ? a = t + "collections" : i.startsWith("globals/") && (a = t + "globals"), a) {
201
+ const h = n.moduleGraph.getModuleById(a);
202
+ h && n.moduleGraph.invalidateModule(h);
203
+ const o = n.moduleGraph.getModulesByFile(e);
204
+ o && o.forEach((r) => {
205
+ n.moduleGraph.invalidateModule(r);
206
+ });
207
+ }
208
+ }
209
+ function yt(n, i) {
210
+ const e = (n.split("?")[0] ?? "").replace(/\\/g, "/"), t = i.replace(/\\/g, "/");
211
+ return e === t || e.startsWith(t + "/");
212
+ }
213
+ function wt(n, i) {
214
+ for (const [e, t] of Object.entries(i)) {
215
+ if (n === e) return t;
216
+ if (n.startsWith(e + "/")) return t + n.slice(e.length);
217
+ }
218
+ return null;
219
+ }
220
+ const bt = "okno:", _ = "\0okno:", St = /* @__PURE__ */ new Set(["pages", "collections", "globals", "locales", "strings", "content"]), K = B(Z(import.meta.url)), _t = JSON.parse(U(m(K, "../package.json"), "utf-8")).version, D = q(), b = m(K, "../editor"), T = m(b, "index.ts"), kt = E(T), Ot = {
221
+ "@modules": m(b, "modules"),
222
+ "@lib": m(b, "lib"),
223
+ "@logger": m(b, "lib/logger.svelte.ts"),
224
+ "@utils": m(b, "lib/utils.ts"),
225
+ "@/types": m(b, "lib/types.ts"),
226
+ "@styles": m(b, "styles"),
227
+ "@components": m(b, "components"),
228
+ "@assets": m(b, "assets"),
229
+ "@pages": m(b, "pages"),
230
+ "@controllers": m(b, "controllers")
231
+ };
232
+ function vt() {
233
+ try {
234
+ const n = (a) => Q(a, { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }).trim(), e = n("git remote get-url origin").match(/github\.com[:/]([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
235
+ if (!e) return null;
236
+ const t = n("git rev-parse --abbrev-ref HEAD") || "main";
237
+ return `${e[1]}/${e[2]}@${t}`;
238
+ } catch {
239
+ return null;
240
+ }
241
+ }
242
+ function It(n = {}) {
243
+ const i = n.dir ?? "okno";
244
+ let e, t, a = !1, h = !1;
245
+ return n.isEditor, {
246
+ name: "okno",
247
+ enforce: "pre",
248
+ config(o, r) {
249
+ const s = r.command === "serve";
250
+ return h = r.command === "build", a = s && kt, {
251
+ define: {
252
+ __OKNO_API_URL__: JSON.stringify(n.apiUrl ?? "https://api.okno.build"),
253
+ __OKNO_VERSION__: JSON.stringify(_t),
254
+ // True when the consumer is running `vite dev` / `astro dev` /
255
+ // `sveltekit dev` — anything that serves locally. Replaced at
256
+ // consumer build time so the prebuilt editor bundle can honor
257
+ // the consumer's actual environment.
258
+ __OKNO_IS_DEV__: JSON.stringify(s),
259
+ // Public demo build: editor boots login-less, reads a static
260
+ // `okno-demo.json` snapshot, no-ops writes. See docs/demo-mode.md.
261
+ __OKNO_DEMO__: JSON.stringify(n.demo ?? !1),
262
+ // Repo identity (`owner/repo@branch`) baked from the app's git
263
+ // origin at the consumer's build time, so the deployed editor
264
+ // auto-targets its repo with no picker. null outside a git
265
+ // checkout → editor falls back to the picker. Dev ignores it
266
+ // (runtime /__okno/repo derivation is more current).
267
+ __OKNO_REPO__: JSON.stringify(vt())
268
+ },
269
+ // Source mode (monorepo dev only): skip prebundling so saves to
270
+ // `package/editor/**` propagate via HMR instead of needing
271
+ // `bun run build:pkg`. The editor's internal @-aliases are NOT exposed
272
+ // as a global `resolve.alias` here — that shadowed a consumer's own
273
+ // identically-named tsconfig aliases (`@components`, `@lib`, …). They
274
+ // are instead resolved per-importer in `resolveId`, scoped to imports
275
+ // originating inside the editor source tree. See editor-aliases.ts.
276
+ ...a && {
277
+ optimizeDeps: { exclude: ["okno", "okno/editor"] }
278
+ },
279
+ server: {
280
+ watch: {
281
+ // Only ignore binary assets and editor-only metadata. Page/
282
+ // collection/global .ts files SHOULD trigger Vite HMR — that's
283
+ // how users see updates when they `git pull` content from the
284
+ // drafts branch into their working tree. (Previously this list
285
+ // also blocked pages/collections/globals because in DEV_MODE
286
+ // the backend mirrored saves to disk, causing spurious full
287
+ // reloads. In production-mode the backend never touches local
288
+ // FS so blocking those is pure harm — pulls go unseen.)
289
+ ignored: [`**/${i}/files/**`, `**/${i}/.okno-tree.json`]
290
+ },
291
+ // Source mode: the editor loads via a dynamic `import("okno/editor")`
292
+ // from a separate package over `@fs`, so Vite's startup dep scan
293
+ // never crawls it — its transitive deps (bits-ui, tiptap, runed…)
294
+ // are discovered lazily on first import, triggering a mid-session
295
+ // re-optimize that 404s the now-stale prebundled chunks. Warming the
296
+ // editor entry forces that crawl at startup, so those deps land in
297
+ // the first optimize pass and never re-bundle under the user.
298
+ ...a && {
299
+ warmup: { clientFiles: [T] }
300
+ }
301
+ }
302
+ };
303
+ },
304
+ configResolved(o) {
305
+ e = o.root, t = m(e, i);
306
+ },
307
+ async buildStart() {
308
+ if (E(t) && (await M(t, e), n.demo)) {
309
+ const o = w(e, "public");
310
+ E(o) || I(o, { recursive: !0 }), R(
311
+ w(o, "okno-demo.json"),
312
+ JSON.stringify(st(t))
313
+ );
314
+ const r = w(t, "files");
315
+ E(r) && Y(r, w(o, "okno", "files"), {
316
+ recursive: !0,
317
+ filter: (s) => !s.endsWith(".okno-tree.json")
318
+ });
319
+ }
320
+ },
321
+ configureServer(o) {
322
+ pt(o, t);
323
+ const r = (p) => {
324
+ const l = N(t, p);
325
+ if (l.startsWith("..") || !l.endsWith(".ts")) return;
326
+ const u = l.split(/[\\/]/)[0];
327
+ if (u !== "pages" && u !== "collections" && u !== "globals") return;
328
+ const c = o.moduleGraph.getModuleById(_ + u);
329
+ c && o.moduleGraph.invalidateModule(c), o.moduleGraph.getModulesByFile(p)?.forEach((g) => o.moduleGraph.invalidateModule(g)), !$(p) && o.ws.send({ type: "full-reload" });
330
+ };
331
+ o.watcher.on("add", r), o.watcher.on("unlink", r), o.middlewares.use("/__okno/imports", async (p, l, u) => {
332
+ if (p.method !== "GET") return u();
333
+ try {
334
+ const [c, g, f] = await Promise.all([
335
+ v(e, "pages"),
336
+ v(e, "globals"),
337
+ v(e, "collections")
338
+ ]);
339
+ l.setHeader("Content-Type", "application/json"), l.setHeader("Cache-Control", "no-store"), l.end(JSON.stringify({
340
+ pages: Array.from(c),
341
+ globals: Array.from(g),
342
+ collections: Array.from(f)
343
+ }));
344
+ } catch (c) {
345
+ u(c);
346
+ }
347
+ });
348
+ const s = "/__okno_bootstrap.js";
349
+ o.middlewares.use(s, async (p, l, u) => {
350
+ try {
351
+ const c = await o.transformRequest("\0okno:bootstrap");
352
+ if (!c) {
353
+ l.statusCode = 500, l.end("okno bootstrap transform failed");
354
+ return;
355
+ }
356
+ l.setHeader("content-type", "text/javascript"), l.end(c.code);
357
+ } catch (c) {
358
+ u(c);
359
+ }
360
+ }), o.middlewares.use((p, l, u) => {
361
+ const c = "<script>window.__oknoDev=true<\/script>", g = n.demo ? "<script>window.__oknoDemo=true<\/script>" : "", f = `${c}${g}<script type="module" src="${s}"><\/script>`, y = [];
362
+ let k = null;
363
+ const V = l.write.bind(l), j = l.end.bind(l), X = l.setHeader.bind(l), G = () => {
364
+ const d = l.getHeader("content-type");
365
+ return typeof d == "string" && d.includes("text/html");
366
+ }, W = (d, S) => Buffer.isBuffer(d) ? d : d instanceof Uint8Array ? Buffer.from(d.buffer, d.byteOffset, d.byteLength) : typeof d == "string" ? Buffer.from(d, S || "utf-8") : Buffer.from(String(d));
367
+ l.write = (d, S, ...C) => (k === null && (k = G()), k ? (d && y.push(W(d, typeof S == "string" ? S : void 0)), !0) : V(d, S, ...C)), l.end = (d, S, ...C) => {
368
+ if (k === null && (k = G()), !k) return j(d, S, ...C);
369
+ d && y.push(W(d, typeof S == "string" ? S : void 0));
370
+ let O = Buffer.concat(y).toString("utf-8");
371
+ O.includes(f) || (O = O.includes("</body>") ? O.replace("</body>", `${f}</body>`) : O + f);
372
+ const J = Buffer.from(O, "utf-8");
373
+ if (!l.headersSent)
374
+ try {
375
+ X("content-length", String(J.length));
376
+ } catch {
377
+ }
378
+ return j(J, ...C);
379
+ }, u();
380
+ });
381
+ },
382
+ async handleHotUpdate(o) {
383
+ const r = w(t, "schema.ts"), s = w(t, "users.json"), p = w(t, "permissions.ts"), l = w(t, "modules.d.ts");
384
+ if (o.file === r) {
385
+ await M(t, e);
386
+ for (const f of ["pages", "collections", "globals", "locales", "content", "strings"]) {
387
+ const y = o.server.moduleGraph.getModuleById(_ + f);
388
+ y && o.server.moduleGraph.invalidateModule(y);
389
+ }
390
+ return [];
391
+ }
392
+ if (o.file === s || o.file === p || o.file === l)
393
+ return [];
394
+ const u = w(t, "strings.ts"), c = N(w(t, "strings"), o.file);
395
+ if (o.file === u || !c.startsWith("..") && c.endsWith(".ts")) {
396
+ await M(t, e);
397
+ for (const f of ["strings", "content"]) {
398
+ const y = o.server.moduleGraph.getModuleById(_ + f);
399
+ y && o.server.moduleGraph.invalidateModule(y);
400
+ }
401
+ }
402
+ const g = N(t, o.file);
403
+ if (!g.startsWith("..") && g.endsWith(".ts")) {
404
+ const f = g.split(/[\\/]/)[0];
405
+ if ((f === "pages" || f === "collections" || f === "globals") && $(o.file)) {
406
+ const y = o.server.moduleGraph.getModuleById(_ + f);
407
+ return y && o.server.moduleGraph.invalidateModule(y), [];
408
+ }
409
+ }
410
+ },
411
+ async resolveId(o, r) {
412
+ if (o.startsWith(bt))
413
+ return "\0" + o;
414
+ if (o.startsWith("okno/")) {
415
+ const s = o.slice(5);
416
+ if (St.has(s)) return _ + s;
417
+ }
418
+ if (a && o === "okno/editor")
419
+ return T;
420
+ if (a && r && yt(r, b)) {
421
+ const s = wt(o, Ot);
422
+ if (s)
423
+ return (await this.resolve(s, r, { skipSelf: !0 }))?.id;
424
+ }
425
+ },
426
+ async load(o) {
427
+ if (!o.startsWith(_)) return;
428
+ const r = o.slice(_.length);
429
+ if (r === "runtime") {
430
+ if (!D)
431
+ throw new Error("okno: runtime/wrap.js missing — run `bun run build:pkg`");
432
+ return D;
433
+ }
434
+ if (r === "bootstrap")
435
+ return 'import("okno/editor")';
436
+ if (r === "pages") {
437
+ const s = await v(e, "pages");
438
+ return await tt(t, s);
439
+ }
440
+ if (r === "collections") {
441
+ const s = await v(e, "collections");
442
+ return await et(t, s, h);
443
+ }
444
+ if (r === "globals") {
445
+ const s = await v(e, "globals");
446
+ return await ot(t, s);
447
+ }
448
+ if (r === "locales")
449
+ return nt(t);
450
+ if (r === "strings")
451
+ return await rt(t);
452
+ if (r === "content")
453
+ return it();
454
+ }
455
+ };
456
+ }
457
+ export {
458
+ It as o
459
+ };
@@ -1,4 +1,4 @@
1
- import { o as a } from "../plugin-DkXOrSVC.js";
1
+ import { o as a } from "../plugin-DmiwHDt_.js";
2
2
  export {
3
3
  a as okno
4
4
  };
@@ -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;AAiFpD,wBAAgB,IAAI,CAAC,MAAM,GAAE,UAAe,GAAG,MAAM,CA+XpD"}
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;AA+EpD,wBAAgB,IAAI,CAAC,MAAM,GAAE,UAAe,GAAG,MAAM,CAiYpD"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "okno",
3
3
  "description": "Git-backed CMS with live editing for any Vite framework",
4
4
  "author": "Gabriel Uhlíř",
5
- "version": "1.0.0-beta.13",
5
+ "version": "1.0.0-beta.14",
6
6
  "homepage": "https://okno.build",
7
7
  "type": "module",
8
8
  "types": "./dist/index.d.ts",