@backmatter/studio 0.0.1 → 0.0.2

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.
@@ -3,7 +3,7 @@ var Ze = (e, t, n) => t in e ? Qe(e, t, { enumerable: !0, configurable: !0, writ
3
3
  var D = (e, t, n) => Ze(e, typeof t != "symbol" ? t + "" : t, n);
4
4
  import { jsxs as R, jsx as o, Fragment as be } from "react/jsx-runtime";
5
5
  import { useRef as et, useCallback as tt, useSyncExternalStore as nt, useState as E, useEffect as J, Suspense as we, lazy as rt } from "react";
6
- import { _ as st, $ as Ce, a0 as it, T as O, a1 as at, p as ot, a2 as lt, a3 as Ie, a4 as qe, a5 as Fe, a6 as ct, a7 as ut, W as ze, a8 as dt, a9 as ae, e as V, b as Be, aa as ft, ab as Me, B as ht, S as se, F as Z, I as ee, a as ye, ac as pt, Z as z, ad as gt, M as ve, ae as te, P as mt, af as xt, ag as yt, o as vt, ah as bt, ai as wt, aj as St, A as kt, G as Et, ak as De, L as Rt, al as _t, am as Ot, an as Tt, N as Pt, R as Lt, O as Ut, Q as Nt, U as jt, V as q, X as At, Y as Ct } from "./WorkspaceRoutes-DgRtdie8.js";
6
+ import { _ as st, $ as Ce, a0 as it, T as O, a1 as at, p as ot, a2 as lt, a3 as Ie, a4 as qe, a5 as Fe, a6 as ct, a7 as ut, W as ze, a8 as dt, a9 as ae, e as V, b as Be, aa as ft, ab as Me, B as ht, S as se, F as Z, I as ee, a as ye, ac as pt, Z as z, ad as gt, M as ve, ae as te, P as mt, af as xt, ag as yt, o as vt, ah as bt, ai as wt, aj as St, A as kt, G as Et, ak as De, L as Rt, al as _t, am as Ot, an as Tt, N as Pt, R as Lt, O as Ut, Q as Nt, U as jt, V as q, X as At, Y as Ct } from "./WorkspaceRoutes-DyRVES9t.js";
7
7
  const ne = /* @__PURE__ */ Object.create(null), W = (e) => {
8
8
  var t, n;
9
9
  return ((t = globalThis.process) == null ? void 0 : t.env) || ((n = globalThis.Deno) == null ? void 0 : n.env.toObject()) || globalThis.__env__ || (e ? ne : globalThis);
@@ -1676,7 +1676,7 @@ function vr({
1676
1676
  /* @__PURE__ */ o(Be, { to: "/", variant: "secondary", children: "Back to the dashboard" })
1677
1677
  ] }) }) });
1678
1678
  }
1679
- const Q = De() ? rt(() => import("./UiKitPage-CgNMOqfE.js").then((e) => ({
1679
+ const Q = De() ? rt(() => import("./UiKitPage-CTZtLwJ0.js").then((e) => ({
1680
1680
  default: e.UiKitPage
1681
1681
  }))) : null;
1682
1682
  function br(e) {
@@ -1,7 +1,7 @@
1
1
  var Rs = Object.defineProperty;
2
2
  var Es = (r, e, t) => e in r ? Rs(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
3
3
  var M = (r, e, t) => Es(r, typeof e != "symbol" ? e + "" : e, t);
4
- import { ao as Bt, ap as Bs, aq as a0, ar as ct, as as xt, at as ea, au as Gn, av as Is, aw as Ls, ax as Ds, ay as La, az as Ps, aA as Os, aB as Le, aC as qs } from "./WorkspaceRoutes-DgRtdie8.js";
4
+ import { ao as Bt, ap as Bs, aq as a0, ar as ct, as as xt, at as ea, au as Gn, av as Is, aw as Ls, ax as Ds, ay as La, az as Ps, aA as Os, aB as Le, aC as qs } from "./WorkspaceRoutes-DyRVES9t.js";
5
5
  function Fs() {
6
6
  return {
7
7
  enter: {
package/dist/dashboard.js CHANGED
@@ -1,5 +1,5 @@
1
- import { A as a, i as s } from "./chunks/dashboard-XKKZuJGm.js";
2
- import { J as t, K as f } from "./chunks/WorkspaceRoutes-DgRtdie8.js";
1
+ import { A as a, i as s } from "./chunks/dashboard-nvFBzpZv.js";
2
+ import { J as t, K as f } from "./chunks/WorkspaceRoutes-DyRVES9t.js";
3
3
  export {
4
4
  a as DashboardApp,
5
5
  t as configureStudio,
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { jsx as n, jsxs as g } from "react/jsx-runtime";
2
- import { useLayoutEffect as Y, useEffect as p, useRef as J, useState as v, useMemo as Q } from "react";
3
- import { i as B, h as X, E as Z, C as ee, j as te, k as ne, l as ie, D as M, m as re, n as _, o as G, q as $, r as oe, T as b, a as C, I as se, s as S, t as ae, v as ce, w as le, x as ue, y as de, z as fe, A as me, G as he, H as ge, J as j, K as P, L as pe, M as ve, N as we, R as be, O as ye, Q as xe, U as ke, V as R, W as D, X as Ee, Y as Ce, Z as Se } from "./chunks/WorkspaceRoutes-DgRtdie8.js";
4
- import { _ as We } from "./chunks/WorkspaceRoutes-DgRtdie8.js";
1
+ import { jsx as n, jsxs as p } from "react/jsx-runtime";
2
+ import { useLayoutEffect as Y, useEffect as g, useRef as J, useState as w, useMemo as Q } from "react";
3
+ import { i as B, h as X, E as Z, C as ee, j as te, k as ne, l as ie, D as M, m as oe, n as _, o as G, q as $, r as re, T as b, a as C, I as se, s as S, t as ae, v as ce, w as le, x as ue, y as de, z as fe, A as me, G as he, H as pe, J as j, K as P, L as ge, M as we, N as ve, R as be, O as ye, Q as xe, U as ke, V as R, W as D, X as Ee, Y as Ce, Z as Se } from "./chunks/WorkspaceRoutes-DyRVES9t.js";
4
+ import { _ as We } from "./chunks/WorkspaceRoutes-DyRVES9t.js";
5
5
  import { u as Re, S as ze } from "./chunks/define-studio-BYtYDGLX.js";
6
6
  import { d as Je } from "./chunks/define-studio-BYtYDGLX.js";
7
7
  const z = {
@@ -15,19 +15,19 @@ function Pe(e) {
15
15
  }
16
16
  const Ue = [z.accent, z.accentHover, z.focus];
17
17
  function Ne() {
18
- var t, o;
19
- const e = (o = (t = Re().theme) == null ? void 0 : t.accent) == null ? void 0 : o.trim();
18
+ var t, r;
19
+ const e = (r = (t = Re().theme) == null ? void 0 : t.accent) == null ? void 0 : r.trim();
20
20
  return Y(() => {
21
21
  if (!e) return;
22
- const a = document.documentElement, s = Ue.map(Pe).filter((r) => !!r);
23
- for (const r of s) a.style.setProperty(r, e);
22
+ const a = document.documentElement, s = Ue.map(Pe).filter((o) => !!o);
23
+ for (const o of s) a.style.setProperty(o, e);
24
24
  return () => {
25
- for (const r of s) a.style.removeProperty(r);
25
+ for (const o of s) a.style.removeProperty(o);
26
26
  };
27
27
  }, [e]), null;
28
28
  }
29
29
  function Le({ workspaceId: e }) {
30
- return p(() => B(), []), /* @__PURE__ */ n(X, { children: /* @__PURE__ */ n(Z, { children: /* @__PURE__ */ n(ee, { workspaceId: e, startOpen: !0, children: /* @__PURE__ */ g(te, { children: [
30
+ return g(() => B(), []), /* @__PURE__ */ n(X, { children: /* @__PURE__ */ n(Z, { children: /* @__PURE__ */ n(ee, { workspaceId: e, startOpen: !0, children: /* @__PURE__ */ p(te, { children: [
31
31
  /* @__PURE__ */ n(Te, {}),
32
32
  /* @__PURE__ */ n(Me, {}),
33
33
  /* @__PURE__ */ n(ne, { fill: !0 })
@@ -43,46 +43,46 @@ function k() {
43
43
  }
44
44
  function Te() {
45
45
  const { setFocus: e } = ie();
46
- return p(() => {
46
+ return g(() => {
47
47
  const t = k();
48
- function o(a) {
48
+ function r(a) {
49
49
  if (!t || a.origin !== t) return;
50
50
  const s = a.data;
51
51
  if ((s == null ? void 0 : s.type) !== "backmatter:focus") return;
52
- const r = s.doc;
53
- !(r != null && r.locale) || !r.type || !r.slug || e({
54
- docRef: { locale: r.locale, type: r.type, slug: r.slug },
52
+ const o = s.doc;
53
+ !(o != null && o.locale) || !o.type || !o.slug || e({
54
+ docRef: { locale: o.locale, type: o.type, slug: o.slug },
55
55
  frontmatter: {},
56
56
  body: "",
57
57
  selection: null
58
58
  });
59
59
  }
60
- return window.addEventListener("message", o), t && window.parent.postMessage({ type: "backmatter:chat-ready" }, t), () => window.removeEventListener("message", o);
61
- }, [e]), p(() => {
60
+ return window.addEventListener("message", r), t && window.parent.postMessage({ type: "backmatter:chat-ready" }, t), () => window.removeEventListener("message", r);
61
+ }, [e]), g(() => {
62
62
  const t = k();
63
- function o(a) {
63
+ function r(a) {
64
64
  const s = a.detail;
65
65
  !t || !(s != null && s.docRef) || window.parent.postMessage({ type: "backmatter:doc-changed", doc: s.docRef }, t);
66
66
  }
67
- return window.addEventListener(M, o), () => window.removeEventListener(M, o);
67
+ return window.addEventListener(M, r), () => window.removeEventListener(M, r);
68
68
  }, []), null;
69
69
  }
70
70
  function Me() {
71
- const { panel: e, dispatch: t } = re(), o = e.mode, a = J(o);
72
- return p(() => {
71
+ const { panel: e, dispatch: t } = oe(), r = e.mode, a = J(r);
72
+ return g(() => {
73
73
  const s = k();
74
74
  if (!s || window.parent === window) return;
75
- const r = _(a.current);
76
- a.current = o, r && !_(o) && window.parent.postMessage({ type: "backmatter:chat-closed" }, s);
77
- }, [o]), p(() => {
75
+ const o = _(a.current);
76
+ a.current = r, o && !_(r) && window.parent.postMessage({ type: "backmatter:chat-closed" }, s);
77
+ }, [r]), g(() => {
78
78
  const s = k();
79
- function r(d) {
79
+ function o(d) {
80
80
  var f;
81
81
  !s || d.origin !== s || ((f = d.data) == null ? void 0 : f.type) === "backmatter:chat-open" && (t({ type: "open" }), requestAnimationFrame(() => {
82
82
  window.dispatchEvent(new Event("backmatter:chat-focus"));
83
83
  }));
84
84
  }
85
- return window.addEventListener("message", r), () => window.removeEventListener("message", r);
85
+ return window.addEventListener("message", o), () => window.removeEventListener("message", o);
86
86
  }, [t]), null;
87
87
  }
88
88
  const _e = 8e3;
@@ -105,9 +105,9 @@ function q(e) {
105
105
  function De({
106
106
  workspaceId: e
107
107
  }) {
108
- p(() => B(), []);
109
- const [t, o] = v(null), [a, s] = v("viewer"), [r, d] = v(""), [f, m] = v(null), [c, y] = v(!1), [U, N] = v(null);
110
- p(() => {
108
+ g(() => B(), []);
109
+ const [t, r] = w(null), [a, s] = w("viewer"), [o, d] = w(""), [f, m] = w(null), [c, y] = w(!1), [U, N] = w(null);
110
+ g(() => {
111
111
  let i = !1;
112
112
  return G(e).then((l) => {
113
113
  i || s(l.workspace.role);
@@ -116,12 +116,12 @@ function De({
116
116
  }), () => {
117
117
  i = !0;
118
118
  };
119
- }, [e]), p(() => {
119
+ }, [e]), g(() => {
120
120
  let i = !1;
121
121
  const l = () => {
122
122
  S(e).then((u) => {
123
123
  if (i) return;
124
- o(u);
124
+ r(u);
125
125
  const T = O();
126
126
  T && window.parent.postMessage({
127
127
  type: "backmatter:git",
@@ -133,15 +133,15 @@ function De({
133
133
  });
134
134
  };
135
135
  l();
136
- const w = window.setInterval(l, _e);
136
+ const v = window.setInterval(l, _e);
137
137
  return () => {
138
- i = !0, window.clearInterval(w);
138
+ i = !0, window.clearInterval(v);
139
139
  };
140
140
  }, [e]);
141
- const h = (t == null ? void 0 : t.changes) ?? [], x = $(t), E = ae(x, fe(a)), V = Q(() => h.filter((i) => i.status === "conflict"), [h]), F = oe(h);
141
+ const h = (t == null ? void 0 : t.changes) ?? [], x = $(t), E = ae(x, fe(a)), V = Q(() => h.filter((i) => i.status === "conflict"), [h]), F = re(h);
142
142
  async function L(i, l) {
143
- const w = `${q(i)}:${l}`;
144
- N(w), m(null);
143
+ const v = `${q(i)}:${l}`;
144
+ N(v), m(null);
145
145
  try {
146
146
  await ce(e, i.locale, i.type, i.slug, l), le({
147
147
  workspaceId: e,
@@ -151,7 +151,7 @@ function De({
151
151
  status: l === "theirs" ? "clean" : "modified"
152
152
  });
153
153
  const u = await S(e);
154
- o(u);
154
+ r(u);
155
155
  } catch (u) {
156
156
  m(u instanceof Error ? u.message : "Resolve failed");
157
157
  } finally {
@@ -162,12 +162,12 @@ function De({
162
162
  if (i.preventDefault(), !(c || E !== "commit" || h.length === 0)) {
163
163
  y(!0), m(null);
164
164
  try {
165
- const l = await ue(e, r);
165
+ const l = await ue(e, o);
166
166
  d(""), de(e, l.files);
167
- const w = O();
168
- w && window.parent.postMessage({
167
+ const v = O();
168
+ v && window.parent.postMessage({
169
169
  type: "backmatter:published"
170
- }, w), o(await S(e));
170
+ }, v), r(await S(e));
171
171
  } catch (l) {
172
172
  m($e(l));
173
173
  } finally {
@@ -176,22 +176,22 @@ function De({
176
176
  }
177
177
  }
178
178
  const W = c ? "Committing…" : x > 0 ? `Resolve ${x} ${x === 1 ? "conflict" : "conflicts"}` : E === "blocked" ? "Writers cannot publish" : h.length === 0 ? "Nothing to publish" : `Deploy ${h.length} ${h.length === 1 ? "change" : "changes"}`;
179
- return /* @__PURE__ */ g("form", { className: "x78zum5 xdt5ytf x11cgr9k x1us19tq x9f619 x1t7e3gq x1hb2obb xqjzbou x1vrk1b5", onSubmit: (i) => void H(i), children: [
179
+ return /* @__PURE__ */ p("form", { className: "x78zum5 xdt5ytf x11cgr9k x1us19tq x9f619 x1t7e3gq x1hb2obb xqjzbou x1vrk1b5", onSubmit: (i) => void H(i), children: [
180
180
  /* @__PURE__ */ n(b, { as: "p", size: "sm", weight: "medium", tone: "muted", children: (t == null ? void 0 : t.currentBranch) ?? "Publish" }),
181
- h.length === 0 ? /* @__PURE__ */ n(b, { as: "p", size: "sm", tone: "muted", children: "Nothing to publish" }) : /* @__PURE__ */ n("ul", { className: "x1ghz6dp x1717udv xe8uvvx x78zum5 xdt5ytf x1ndbd79", children: h.map((i) => /* @__PURE__ */ g("li", { className: "x78zum5 xdt5ytf x3smv4v", children: [
182
- /* @__PURE__ */ g("span", { children: [
181
+ h.length === 0 ? /* @__PURE__ */ n(b, { as: "p", size: "sm", tone: "muted", children: "Nothing to publish" }) : /* @__PURE__ */ n("ul", { className: "x1ghz6dp x1717udv xe8uvvx x78zum5 xdt5ytf x1ndbd79", children: h.map((i) => /* @__PURE__ */ p("li", { className: "x78zum5 xdt5ytf x3smv4v", children: [
182
+ /* @__PURE__ */ p("span", { children: [
183
183
  i.status,
184
184
  " ",
185
185
  i.type,
186
186
  "/",
187
187
  i.slug
188
188
  ] }),
189
- i.status === "conflict" ? /* @__PURE__ */ g("span", { className: "x78zum5 x3smv4v", children: [
189
+ i.status === "conflict" ? /* @__PURE__ */ p("span", { className: "x78zum5 x3smv4v", children: [
190
190
  /* @__PURE__ */ n(C, { size: "sm", variant: "secondary", disabled: U !== null, onClick: () => void L(i, "mine"), children: "Keep mine" }),
191
191
  /* @__PURE__ */ n(C, { size: "sm", variant: "secondary", disabled: U !== null, onClick: () => void L(i, "theirs"), children: "Take theirs" })
192
192
  ] }) : null
193
193
  ] }, q(i))) }),
194
- V.length > 0 ? null : /* @__PURE__ */ n(se, { value: r, placeholder: F, "aria-label": "Commit message", onChange: (i) => d(i.target.value) }),
194
+ V.length > 0 ? null : /* @__PURE__ */ n(se, { value: o, placeholder: F, "aria-label": "Commit message", onChange: (i) => d(i.target.value) }),
195
195
  f ? /* @__PURE__ */ n(b, { as: "p", size: "sm", tone: "danger", children: f }) : null,
196
196
  /* @__PURE__ */ n(C, { type: "submit", size: "sm", disabled: c || E !== "commit" || h.length === 0, children: W })
197
197
  ] });
@@ -199,11 +199,14 @@ function De({
199
199
  const I = "backmatter:enter-at", Oe = 1e4;
200
200
  function K(e, t) {
201
201
  if (typeof window > "u") return !1;
202
- const o = Number(window.sessionStorage.getItem(I) ?? 0);
203
- return Date.now() - o < Oe ? !1 : (window.sessionStorage.setItem(I, String(Date.now())), window.location.assign(ge(t, {
202
+ const r = Number(window.sessionStorage.getItem(I) ?? 0);
203
+ if (Date.now() - r < Oe) return !1;
204
+ window.sessionStorage.setItem(I, String(Date.now()));
205
+ const a = window.top && window.top !== window ? window.top : window;
206
+ return a.location.assign(pe(t, {
204
207
  workspaceId: e,
205
- returnUrl: window.location.href
206
- })), !0);
208
+ returnUrl: a.location.href
209
+ })), !0;
207
210
  }
208
211
  function qe(e) {
209
212
  const t = e.dashboardUrl ?? "https://dash.backmatter.app";
@@ -215,22 +218,22 @@ function qe(e) {
215
218
  version: e.version,
216
219
  dashboardUrl: t,
217
220
  onUnauthorized: ({
218
- status: o
221
+ status: r
219
222
  }) => {
220
- o === 401 && K(e.workspaceId, t);
223
+ r === 401 && K(e.workspaceId, t);
221
224
  }
222
225
  }), P();
223
226
  }
224
227
  function Ve(e) {
225
- const t = e.basePath ?? "/backmatter", [o] = v(() => qe(e));
226
- return /* @__PURE__ */ n(ze, { definition: e.studio, children: /* @__PURE__ */ g(me, { children: [
228
+ const t = e.basePath ?? "/backmatter", [r] = w(() => qe(e));
229
+ return /* @__PURE__ */ n(ze, { definition: e.studio, children: /* @__PURE__ */ p(me, { children: [
227
230
  /* @__PURE__ */ n(Ne, {}),
228
231
  /* @__PURE__ */ n(he, { basename: t, children: /* @__PURE__ */ n(Ie, { ...e }) })
229
232
  ] }) });
230
233
  }
231
234
  function Ie(e) {
232
- const t = pe(), o = e.dashboardUrl ?? "https://dash.backmatter.app", [a, s] = v("loading");
233
- if (p(() => {
235
+ const t = ge(), r = e.dashboardUrl ?? "https://dash.backmatter.app", [a, s] = w("loading");
236
+ if (g(() => {
234
237
  let f = !1;
235
238
  const m = P().onUnauthorized;
236
239
  return j({
@@ -238,10 +241,10 @@ function Ie(e) {
238
241
  onUnauthorized: (c) => {
239
242
  c.status === 426 ? s("outdated") : m == null || m(c);
240
243
  }
241
- }), ve().then(async (c) => {
244
+ }), we().then(async (c) => {
242
245
  if (f) return;
243
246
  if (!(c != null && c.user)) {
244
- K(e.workspaceId, o) || s("unauthorized");
247
+ K(e.workspaceId, r) || s("unauthorized");
245
248
  return;
246
249
  }
247
250
  const {
@@ -259,9 +262,9 @@ function Ie(e) {
259
262
  }), () => {
260
263
  f = !0;
261
264
  };
262
- }, [e.workspaceId, o]), a === "loading") return /* @__PURE__ */ n(we, {});
265
+ }, [e.workspaceId, r]), a === "loading") return /* @__PURE__ */ n(ve, {});
263
266
  if (a === "outdated")
264
- return /* @__PURE__ */ g(A, { title: "This site's editor is out of date", children: [
267
+ return /* @__PURE__ */ p(A, { title: "This site's editor is out of date", children: [
265
268
  "Update ",
266
269
  /* @__PURE__ */ n("code", { children: "@backmatter/studio" }),
267
270
  " and ",
@@ -269,18 +272,18 @@ function Ie(e) {
269
272
  " on the site, then reload."
270
273
  ] });
271
274
  if (a === "unauthorized")
272
- return /* @__PURE__ */ g(A, { title: "Could not start editing", children: [
275
+ return /* @__PURE__ */ p(A, { title: "Could not start editing", children: [
273
276
  "The site did not receive a session from the dashboard. Check that this site's origin is listed in the workspace settings and that ",
274
277
  /* @__PURE__ */ n("code", { children: "/api/backmatter" }),
275
278
  " routes are deployed."
276
279
  ] });
277
- const r = t.pathname.match(/^\/embed\/chat\/([^/]+)\/?$/);
278
- if (r != null && r[1])
279
- return /* @__PURE__ */ n(Le, { workspaceId: decodeURIComponent(r[1]) });
280
+ const o = t.pathname.match(/^\/embed\/chat\/([^/]+)\/?$/);
281
+ if (o != null && o[1])
282
+ return /* @__PURE__ */ n(Le, { workspaceId: decodeURIComponent(o[1]) });
280
283
  const d = t.pathname.match(/^\/embed\/publish\/([^/]+)\/?$/);
281
284
  return d != null && d[1] ? /* @__PURE__ */ n(De, { workspaceId: decodeURIComponent(d[1]) }) : /* @__PURE__ */ n(be, { user: a.user, children: /* @__PURE__ */ n(ye, { children: /* @__PURE__ */ n(xe, { userId: a.user.id, email: a.user.email, onLogout: () => {
282
- Ae(e.previewEntryPath ?? "/api/backmatter/preview", o);
283
- }, children: /* @__PURE__ */ g(ke, { children: [
285
+ Ae(e.previewEntryPath ?? "/api/backmatter/preview", r);
286
+ }, children: /* @__PURE__ */ p(ke, { children: [
284
287
  /* @__PURE__ */ n(R, { path: "/", element: /* @__PURE__ */ n(D, { to: `/${a.slug}`, replace: !0 }) }),
285
288
  /* @__PURE__ */ n(R, { path: "/workspaces/:workspaceId/*", element: /* @__PURE__ */ n(Ee, {}) }),
286
289
  Ce(),
@@ -301,7 +304,7 @@ function A({
301
304
  title: e,
302
305
  children: t
303
306
  }) {
304
- return /* @__PURE__ */ n("div", { className: "x1ov3xa9 xrvj5dj x1ku5rj1 x1t7e3gq", children: /* @__PURE__ */ g("div", { className: "x78zum5 xdt5ytf x1ndbd79 xq2pcee x1t7e3gq x4pepcl x1d0qn7y", children: [
307
+ return /* @__PURE__ */ n("div", { className: "x1ov3xa9 xrvj5dj x1ku5rj1 x1t7e3gq", children: /* @__PURE__ */ p("div", { className: "x78zum5 xdt5ytf x1ndbd79 xq2pcee x1t7e3gq x4pepcl x1d0qn7y", children: [
305
308
  /* @__PURE__ */ n(b, { size: "lg", weight: "medium", children: e }),
306
309
  /* @__PURE__ */ n(b, { tone: "muted", children: t })
307
310
  ] }) });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backmatter/studio",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "The Backmatter editing surface: document editor, AI chat, publish. Mounted on your site or hosted on the dashboard.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -63,6 +63,7 @@ import {
63
63
  type PanelAction,
64
64
  type PanelState,
65
65
  } from "./chat-state";
66
+ import { fetchNotifyingSessionExpiry } from "./session-expiry";
66
67
 
67
68
  // ---------------------------------------------------------------------------
68
69
  // UI-level context (panel, thread selection, model, chips)
@@ -513,6 +514,10 @@ function LiveSession({
513
514
  api: aiMessagesUrl(workspaceId, threadId),
514
515
  credentials: apiCredentials(),
515
516
  headers: apiHeaders(),
517
+ fetch: fetchNotifyingSessionExpiry(
518
+ typeof location === "undefined" ? "" : location.origin,
519
+ typeof window !== "undefined" && window.parent !== window ? window.parent : null,
520
+ ),
516
521
  prepareSendMessagesRequest: ({ messages, body }) => ({
517
522
  body: {
518
523
  message: messages[messages.length - 1],
@@ -0,0 +1,20 @@
1
+ // packages/studio/src/chat/session-expiry.ts
2
+ // The chat send does not go through the Studio API helper, so a dead site
3
+ // session would otherwise show up as a composer error. Tell the parent page,
4
+ // which holds the bar, so it can sign the editor back in.
5
+
6
+ export const SESSION_EXPIRED_MESSAGE = "backmatter:session-expired";
7
+
8
+ export function fetchNotifyingSessionExpiry(
9
+ origin: string,
10
+ parent: { postMessage: (message: unknown, targetOrigin: string) => void } | null,
11
+ base: typeof fetch = fetch,
12
+ ): typeof fetch {
13
+ return async (input, init) => {
14
+ const res = await base(input, init);
15
+ if (res.status === 401 && parent && origin) {
16
+ parent.postMessage({ type: SESSION_EXPIRED_MESSAGE }, origin);
17
+ }
18
+ return res;
19
+ };
20
+ }
package/src/site.tsx CHANGED
@@ -54,8 +54,11 @@ export function bounceToEnter(workspaceId: string, dashboardUrl: string): boolea
54
54
  const last = Number(window.sessionStorage.getItem(ENTER_GUARD_KEY) ?? 0);
55
55
  if (Date.now() - last < ENTER_LOOP_MS) return false;
56
56
  window.sessionStorage.setItem(ENTER_GUARD_KEY, String(Date.now()));
57
- window.location.assign(
58
- studioEnterUrl(dashboardUrl, { workspaceId, returnUrl: window.location.href }),
57
+ // A panel is a frame of this site. Send the top window, or the login form
58
+ // appears inside the chat instead of taking the page.
59
+ const nav = window.top && window.top !== window ? window.top : window;
60
+ nav.location.assign(
61
+ studioEnterUrl(dashboardUrl, { workspaceId, returnUrl: nav.location.href }),
59
62
  );
60
63
  return true;
61
64
  }