camox 0.58.1 → 0.60.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.
Files changed (102) hide show
  1. package/dist/core/createBlock.js +1 -1
  2. package/dist/core/editing/createEditableBlock.js +2 -2
  3. package/dist/core/lib/recordScope.js +1 -1
  4. package/dist/features/canvas/CamoxCanvas.js +2 -2
  5. package/dist/features/canvas/CanvasOverlays.js +1 -1
  6. package/dist/features/canvas/sidebar/LayoutPageSeo.js +1 -1
  7. package/dist/features/canvas/sidebar/PageInspector.js +1 -1
  8. package/dist/features/content/CamoxContent.js +1 -1
  9. package/dist/features/content/components/MissingFromLocale.js +1 -1
  10. package/dist/features/page/CuratedPageContent.js +1 -1
  11. package/dist/features/preview/CamoxPreview.js +3 -3
  12. package/dist/features/preview/components/AddBlockSheet.js +1 -1
  13. package/dist/features/preview/components/AssetLightbox.js +1 -1
  14. package/dist/features/preview/components/BlockActionsPopover.js +1 -1
  15. package/dist/features/preview/components/CreatePageModal.js +2 -2
  16. package/dist/features/preview/components/FieldOverlayStyles.js +1 -1
  17. package/dist/features/preview/components/MobilePreviewDrawer.js +1 -1
  18. package/dist/features/preview/components/Overlays.js +1 -1
  19. package/dist/features/preview/components/PageInfo.js +1 -1
  20. package/dist/features/preview/components/PagePicker.js +1 -1
  21. package/dist/features/preview/components/PageTree.js +1 -1
  22. package/dist/features/preview/components/PreviewPanel.js +1 -1
  23. package/dist/features/preview/components/PreviewToolbar.js +1 -1
  24. package/dist/features/preview/components/SelectionEditor.js +2 -2
  25. package/dist/features/preview/components/StudioEditingFallback.js +1 -1
  26. package/dist/features/provider/AuthenticatedCamoxProvider.js +1 -1
  27. package/dist/features/provider/CamoxProvider.js +1 -1
  28. package/dist/features/provider/CoreCamoxProvider.js +3 -3
  29. package/dist/features/provider/components/CommandPalette.js +1 -1
  30. package/dist/features/renderer/RendererApp.js +187 -103
  31. package/dist/features/renderer/rendererHost.js +3 -7
  32. package/dist/features/routes/pageRuntime.d.ts +2 -5
  33. package/dist/features/routes/pageRuntime.js +1 -2
  34. package/dist/features/runtime/RuntimeChrome.js +1 -1
  35. package/dist/features/runtime/loopbackFetch.d.ts +8 -0
  36. package/dist/features/runtime/navigationTarget.js +1 -2
  37. package/dist/features/runtime/pageApp.js +1 -1
  38. package/dist/features/runtime/publicCache.d.ts +21 -0
  39. package/dist/features/runtime/publishingDraft.d.ts +4 -0
  40. package/dist/features/runtime/rendererClient.js +1 -1
  41. package/dist/features/runtime/runtime.d.ts +0 -5
  42. package/dist/features/runtime/runtime.js +80 -33
  43. package/dist/features/runtime/worker.js +4 -7
  44. package/dist/features/runtime/workerRequest.d.ts +8 -0
  45. package/dist/features/runtime/workerRuntime.d.ts +5 -0
  46. package/dist/features/runtime/workerRuntime.js +6 -0
  47. package/dist/features/sdkBundle/buildSdkBundle.d.ts +40 -0
  48. package/dist/features/sdkBundle/buildSdkBundle.js +323 -0
  49. package/dist/features/sdkBundle/localSdkBundle.d.ts +44 -0
  50. package/dist/features/sdkBundle/localSdkBundle.js +162 -0
  51. package/dist/features/sdkBundle/sdkBundle.d.ts +3 -0
  52. package/dist/features/sdkBundle/sdkBundle.js +4 -0
  53. package/dist/features/sdkBundle/sdkBundleName.d.ts +59 -0
  54. package/dist/features/sdkBundle/sdkBundleName.js +164 -0
  55. package/dist/features/sdkBundle/specifiers.d.ts +34 -0
  56. package/dist/features/sdkBundle/specifiers.js +146 -0
  57. package/dist/features/settings/FaviconSettings.js +1 -1
  58. package/dist/features/settings/SocialProfilesSettings.js +284 -151
  59. package/dist/features/studio/CamoxStudio.js +1 -1
  60. package/dist/features/studio/FollowAgentProvider.js +72 -13
  61. package/dist/features/studio/components/ChatWidget.js +86 -44
  62. package/dist/features/studio/components/DraftsControl.js +232 -201
  63. package/dist/features/studio/components/LocalePicker.js +2 -2
  64. package/dist/features/studio/components/Navbar.js +3 -3
  65. package/dist/features/studio/components/Patrol.js +312 -209
  66. package/dist/features/studio/components/ProjectMenu.js +2 -2
  67. package/dist/features/studio/components/ReviewDraftSheet.js +9 -15
  68. package/dist/features/studio/components/Squareling.js +164 -66
  69. package/dist/features/studio/components/ThreadComposer.js +139 -69
  70. package/dist/features/studio/components/ThreadMessages.js +216 -64
  71. package/dist/features/studio/components/UserButton.js +2 -2
  72. package/dist/features/studio/draftLabel.js +1 -2
  73. package/dist/features/studio/draftNotice.js +0 -1
  74. package/dist/features/studio/editorWhereContext.js +11 -0
  75. package/dist/features/studio/showInCanvas.js +1 -1
  76. package/dist/features/studio/useEditorSelection.js +135 -0
  77. package/dist/features/vite/definitionsSync.js +14 -60
  78. package/dist/features/vite/devSignIn.js +1 -1
  79. package/dist/features/vite/hostedChecks.js +1 -1
  80. package/dist/features/vite/runtimeDev.js +2 -2
  81. package/dist/features/vite/sdkBundleBuild.js +74 -0
  82. package/dist/features/vite/staticAssetHeaders.js +7 -4
  83. package/dist/features/vite/vite.d.ts +8 -7
  84. package/dist/features/vite/vite.js +67 -28
  85. package/dist/lib/api-client-server.js +25 -8
  86. package/dist/lib/api-client.js +2 -6
  87. package/dist/lib/auth.js +25 -59
  88. package/dist/lib/draft-scope.js +5 -25
  89. package/dist/lib/preview-handoff.js +1 -1
  90. package/dist/lib/server-auth-cookie.js +23 -11
  91. package/dist/lib/stored-auth-cookies.js +76 -0
  92. package/dist/lib/studio-reads.js +1 -1
  93. package/dist/lib/use-thread.js +40 -40
  94. package/dist/package.js +1 -1
  95. package/dist/studio.css +1 -1
  96. package/package.json +17 -4
  97. package/skills/camox/references/block-definitions.md +1 -1
  98. package/dist/features/vite/publishSeededContent.js +0 -30
  99. package/skills/camox-cli/SKILL.md +0 -15
  100. package/skills/camox-cli/references/cli-common.md +0 -58
  101. package/skills/camox-cli/references/cli-content.md +0 -181
  102. package/skills/camox-cli/references/cli-publishing.md +0 -26
package/dist/lib/auth.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { actionsStore } from "../features/provider/actionsStore.js";
2
2
  import { validatePreviewTarget } from "./preview-handoff.js";
3
- import { SERVER_AUTH_COOKIE_NAME, buildClearServerAuthCookieHeader, getServerAuthCookieHeader } from "./server-auth-cookie.js";
3
+ import { buildClearServerAuthCookieHeader, buildServerAuthCookieHeader, getServerAuthCookieHeader, readServerAuthCookie } from "./server-auth-cookie.js";
4
+ import { getCookie, getSetCookie, parseSetCookieHeader, withCookieHeader } from "./stored-auth-cookies.js";
4
5
  import { c } from "react/compiler-runtime";
5
6
  import * as React from "react";
6
7
  import { oneTimeTokenClient, organizationClient } from "better-auth/client/plugins";
@@ -9,60 +10,26 @@ import { createAuthClient } from "better-auth/react";
9
10
  //#region src/lib/auth.ts
10
11
  function writeServerAuthCookie(cookie) {
11
12
  if (typeof document === "undefined") return;
12
- const secure = window.location.protocol === "https:" ? "; Secure" : "";
13
+ const secure = window.location.protocol === "https:";
13
14
  if (!cookie) {
14
- document.cookie = `${buildClearServerAuthCookieHeader()}${secure}`;
15
+ document.cookie = `${buildClearServerAuthCookieHeader()}${secure ? "; Secure" : ""}`;
15
16
  return;
16
17
  }
17
- document.cookie = `${SERVER_AUTH_COOKIE_NAME}=${encodeURIComponent(cookie)}; Path=/; SameSite=Lax; Max-Age=2592000${secure}`;
18
+ document.cookie = buildServerAuthCookieHeader(cookie, { secure });
18
19
  }
19
- function parseSetCookieHeader(header) {
20
- const cookieMap = /* @__PURE__ */ new Map();
21
- header.split(", ").forEach((cookie) => {
22
- const [nameValue, ...attributes] = cookie.split("; ");
23
- const [name, value] = nameValue.split("=");
24
- const cookieObj = { value };
25
- attributes.forEach((attr) => {
26
- const [attrName, attrValue] = attr.split("=");
27
- cookieObj[attrName.toLowerCase()] = attrValue;
28
- });
29
- cookieMap.set(name, cookieObj);
30
- });
31
- return cookieMap;
32
- }
33
- function getSetCookie(header, prevCookie) {
34
- const parsed = parseSetCookieHeader(header);
35
- let toSetCookie = {};
36
- parsed.forEach((cookie, key) => {
37
- const expiresAt = cookie["expires"];
38
- const maxAge = cookie["max-age"];
39
- let expires = null;
40
- if (expiresAt) expires = new Date(String(expiresAt));
41
- else if (maxAge) expires = new Date(Date.now() + Number(maxAge) * 1e3);
42
- toSetCookie[key] = {
43
- value: cookie["value"],
44
- expires: expires ? expires.toISOString() : null
45
- };
46
- });
47
- if (prevCookie) try {
48
- toSetCookie = {
49
- ...JSON.parse(prevCookie),
50
- ...toSetCookie
51
- };
52
- } catch {}
53
- return JSON.stringify(toSetCookie);
54
- }
55
- function getCookie(cookie) {
56
- let parsed = {};
57
- try {
58
- parsed = JSON.parse(cookie);
59
- } catch {}
60
- const parts = [];
61
- for (const [key, value] of Object.entries(parsed)) {
62
- if (value.expires && new Date(value.expires) < /* @__PURE__ */ new Date()) continue;
63
- parts.push(`${key}=${value.value}`);
64
- }
65
- return parts.join("; ");
20
+ const STORED_COOKIES_KEY = "better-auth_cookie";
21
+ /**
22
+ * The stored cookies, with the session the website's Worker signed in with added: it exchanges a
23
+ * sign-in's one-time token itself and sets only the mirror. Read storage through this alone,
24
+ * since reading it writes the mirror back from storage.
25
+ */
26
+ function readStoredCookies(storage, key = STORED_COOKIES_KEY) {
27
+ const stored = storage.getItem(key) || "{}";
28
+ if (typeof document === "undefined") return stored;
29
+ const adopted = withCookieHeader(stored, readServerAuthCookie(document.cookie));
30
+ if (!adopted) return stored;
31
+ storage.setItem(key, adopted);
32
+ return adopted;
66
33
  }
67
34
  /**
68
35
  * Read the cross-domain auth cookie from localStorage and return it as a
@@ -70,7 +37,7 @@ function getCookie(cookie) {
70
37
  */
71
38
  function getAuthCookieHeader() {
72
39
  if (typeof window === "undefined") return "";
73
- const cookie = getCookie(localStorage.getItem("better-auth_cookie") || "{}");
40
+ const cookie = getCookie(readStoredCookies(localStorage));
74
41
  writeServerAuthCookie(cookie);
75
42
  return cookie;
76
43
  }
@@ -87,10 +54,7 @@ function crossDomainClient(opts = {}) {
87
54
  getActions(_, $store) {
88
55
  store = $store;
89
56
  return {
90
- getCookie: () => {
91
- const cookie = storage?.getItem(cookieName);
92
- return getCookie(cookie || "{}");
93
- },
57
+ getCookie: () => storage ? getCookie(readStoredCookies(storage, cookieName)) : "",
94
58
  updateSession: () => {
95
59
  $store.notify("$sessionSignal");
96
60
  },
@@ -143,7 +107,7 @@ function crossDomainClient(opts = {}) {
143
107
  options
144
108
  };
145
109
  options = options || {};
146
- const cookie = getCookie(storage.getItem(cookieName) || "{}");
110
+ const cookie = getCookie(readStoredCookies(storage, cookieName));
147
111
  writeServerAuthCookie(cookie);
148
112
  options.credentials = getAuthRequestCredentials(cookie);
149
113
  options.headers = {
@@ -181,6 +145,8 @@ function createCamoxAuthClient(apiUrl) {
181
145
  /**
182
146
  * Process a `?ott=` one-time token from the URL before the provider mounts.
183
147
  * Verifies the token against the API backend and notifies the session store.
148
+ * The Worker exchanges a studio sign-in's token before rendering, so this handles a preview
149
+ * link's, and any token the Worker couldn't exchange.
184
150
  *
185
151
  * Reports completion and explicit handoff failures instead of silently showing live content.
186
152
  * Keeps the handoff marker until SSR confirms authentication on the subsequent load.
@@ -230,7 +196,7 @@ function useProcessOtt(authClient, target, initialAuthenticated = false) {
230
196
  window.location.reload();
231
197
  return;
232
198
  } catch {
233
- setError("Preview sign-in failed. The link may have expired or already been used. Run camox preview again for a fresh link.");
199
+ setError("Preview sign-in failed. The link may have expired or already been used. Restart the dev server for a fresh link.");
234
200
  }
235
201
  setReady(true);
236
202
  })();
@@ -258,7 +224,7 @@ function useProjectUuid() {
258
224
  }
259
225
  const subscribeToHydration = () => () => {};
260
226
  function hasStoredAuthCookie() {
261
- return getCookie(localStorage.getItem("better-auth_cookie") || "{}") !== "";
227
+ return getCookie(readStoredCookies(localStorage)) !== "";
262
228
  }
263
229
  const noSubscription = () => () => {};
264
230
  /**
@@ -1,9 +1,8 @@
1
1
  import { UNNAMED_DEFAULT_LOCALE, localeHeaders } from "./locale-path.js";
2
- import { getApiClient } from "./api-client.js";
3
2
  import { c } from "react/compiler-runtime";
4
3
  import * as React from "react";
5
4
  import { generateUuidv7 } from "@camox/api-contract/ids";
6
- import { DEVELOPMENT_DRAFT, DRAFT_CREATE_HEADER, DRAFT_HEADER, DRAFT_SEARCH_PARAM } from "@camox/api-contract/drafts";
5
+ import { DRAFT_CREATE_HEADER, DRAFT_HEADER, DRAFT_SEARCH_PARAM } from "@camox/api-contract/drafts";
7
6
  import { LIVE_KEY_SCOPE, scopeOfKey } from "@camox/api-contract/query-keys";
8
7
 
9
8
  //#region src/lib/draft-scope.ts
@@ -17,22 +16,14 @@ function withoutDraft(href) {
17
16
  url.searchParams.delete(DRAFT_SEARCH_PARAM);
18
17
  return url.href;
19
18
  }
20
- function buildIsDevelopmentMode() {
21
- return typeof __CAMOX_DEVELOPMENT_DRAFT__ !== "undefined" && __CAMOX_DEVELOPMENT_DRAFT__;
22
- }
23
- function createDraftScope({ queryClient, browser, developmentMode = buildIsDevelopmentMode(), loadDevelopmentDraftId = async (projectId) => (await getApiClient().drafts.get({ projectId }))?.id }) {
24
- let current = developmentMode ? DEVELOPMENT_DRAFT : null;
19
+ function createDraftScope({ queryClient, browser }) {
20
+ let current = null;
25
21
  let locale = UNNAMED_DEFAULT_LOCALE;
26
22
  let pending = null;
27
- let developmentDraftId;
28
23
  let adoptedRender = false;
29
24
  const listeners = /* @__PURE__ */ new Set();
30
25
  const noticeListeners = /* @__PURE__ */ new Set();
31
26
  const pendingNotices = [];
32
- const draftOfRender = (rendered) => {
33
- if (!developmentMode) return rendered.draftId ?? null;
34
- return rendered.refusedDraft ? null : DEVELOPMENT_DRAFT;
35
- };
36
27
  const notify = (move) => {
37
28
  for (const listener of listeners) listener({
38
29
  draftId: current,
@@ -75,7 +66,7 @@ function createDraftScope({ queryClient, browser, developmentMode = buildIsDevel
75
66
  },
76
67
  settle: noop
77
68
  };
78
- if (!contentWrite || developmentMode) return {
69
+ if (!contentWrite) return {
79
70
  headers: inLocale,
80
71
  settle: noop
81
72
  };
@@ -102,7 +93,6 @@ function createDraftScope({ queryClient, browser, developmentMode = buildIsDevel
102
93
  return {
103
94
  current: () => current,
104
95
  locale: () => locale,
105
- developmentMode,
106
96
  subscribe(listener) {
107
97
  listeners.add(listener);
108
98
  return () => listeners.delete(listener);
@@ -114,7 +104,6 @@ function createDraftScope({ queryClient, browser, developmentMode = buildIsDevel
114
104
  return true;
115
105
  },
116
106
  hrefFor(to, { from, draft } = {}) {
117
- if (developmentMode) return to;
118
107
  const base = new URL(from ?? browser?.location.href ?? "http://camox.local");
119
108
  const target = new URL(to, base);
120
109
  if (target.origin !== base.origin) return to;
@@ -131,7 +120,7 @@ function createDraftScope({ queryClient, browser, developmentMode = buildIsDevel
131
120
  replaceUrl(null);
132
121
  if (rendered.refusedDraft.notice) report(rendered.refusedDraft.notice);
133
122
  }
134
- const next = draftOfRender(rendered);
123
+ const next = rendered.draftId ?? null;
135
124
  if (next !== null) pending = null;
136
125
  const firstRender = !adoptedRender;
137
126
  adoptedRender = true;
@@ -149,7 +138,6 @@ function createDraftScope({ queryClient, browser, developmentMode = buildIsDevel
149
138
  },
150
139
  leave(ended, { notice = false } = {}) {
151
140
  queryClient.invalidateQueries({ queryKey: ["camox"] });
152
- if (developmentMode) return false;
153
141
  pending = null;
154
142
  current = null;
155
143
  replaceUrl(null);
@@ -158,19 +146,11 @@ function createDraftScope({ queryClient, browser, developmentMode = buildIsDevel
158
146
  ...ended
159
147
  });
160
148
  notify("left");
161
- return true;
162
149
  },
163
150
  onNotice(listener) {
164
151
  noticeListeners.add(listener);
165
152
  for (const notice of pendingNotices.splice(0)) listener(notice);
166
153
  return () => noticeListeners.delete(listener);
167
- },
168
- async keyScopeOfDraft(draftId, projectId) {
169
- if (current !== DEVELOPMENT_DRAFT) return draftId;
170
- developmentDraftId ??= loadDevelopmentDraftId(projectId).catch(() => {
171
- developmentDraftId = void 0;
172
- });
173
- return draftId === await developmentDraftId ? DEVELOPMENT_DRAFT : draftId;
174
154
  }
175
155
  };
176
156
  }
@@ -6,7 +6,7 @@ function validatePreviewTarget(raw, target) {
6
6
  const expected = JSON.parse(raw);
7
7
  if (expected.projectUuid === target.projectUuid && typeof expected.apiUrl === "string" && expected.apiUrl.replace(/\/+$/, "") === target.apiUrl.replace(/\/+$/, "")) return null;
8
8
  } catch {}
9
- return "Preview destination does not match the CLI project or backend. Check --cwd and --url, then run camox preview again.";
9
+ return "This sign-in link is for another project or backend. Open the one your dev server printed.";
10
10
  }
11
11
 
12
12
  //#endregion
@@ -1,21 +1,33 @@
1
1
  //#region src/lib/server-auth-cookie.ts
2
2
  const SERVER_AUTH_COOKIE_NAME = "camox_auth_cookie";
3
+ /** How long the mirror lasts. The API still refuses a session that expired before it. */
4
+ const SERVER_AUTH_COOKIE_MAX_AGE = 2592e3;
3
5
  function buildClearServerAuthCookieHeader() {
4
6
  return `${SERVER_AUTH_COOKIE_NAME}=; Path=/; SameSite=Lax; Max-Age=0`;
5
7
  }
6
- /** Forward credentials to the API for validation; cookie presence is not authentication.
7
- * Cross-domain sessions use the mirror. Same-host sessions (including localhost
8
- * on different ports) may only have Better Auth's native, HttpOnly cookie.
8
+ /** Sets the mirror to a session, as a `Cookie` header's value. */
9
+ function buildServerAuthCookieHeader(cookie, { secure }) {
10
+ return `${SERVER_AUTH_COOKIE_NAME}=${encodeURIComponent(cookie)}; Path=/; SameSite=Lax; Max-Age=${SERVER_AUTH_COOKIE_MAX_AGE}${secure ? "; Secure" : ""}`;
11
+ }
12
+ /**
13
+ * The session to forward to the API for validation; cookie presence is not authentication. Only
14
+ * the studio's session counts, which the SDK mirrors into `camox_auth_cookie`. Better Auth's own
15
+ * cookies don't: on a Custom Domain like camox.ai they're the dashboard's session, set for every
16
+ * host (ADR 0028). Mirrored in apps/dispatch/src/previews.ts: keep the two in sync.
9
17
  */
10
18
  function getServerAuthCookieHeader(headers) {
11
- const cookies = (headers.get("Cookie") ?? "").split(";").map((part) => part.trim());
12
- const mirror = cookies.find((part) => part.startsWith(`${SERVER_AUTH_COOKIE_NAME}=`));
13
- if (mirror) try {
14
- const value = decodeURIComponent(mirror.slice(18));
15
- if (value) return value;
16
- } catch {}
17
- return cookies.filter((part) => part.startsWith("better-auth.session_token=") || part.startsWith("__Secure-better-auth.session_token=")).join("; ");
19
+ return readServerAuthCookie(headers.get("Cookie") ?? "");
20
+ }
21
+ /** The mirror's session in a `Cookie` header's value, or `document.cookie`. */
22
+ function readServerAuthCookie(cookieHeader) {
23
+ const mirror = cookieHeader.split(";").map((part) => part.trim()).find((part) => part.startsWith(`${SERVER_AUTH_COOKIE_NAME}=`));
24
+ if (!mirror) return "";
25
+ try {
26
+ return decodeURIComponent(mirror.slice(18));
27
+ } catch {
28
+ return "";
29
+ }
18
30
  }
19
31
 
20
32
  //#endregion
21
- export { SERVER_AUTH_COOKIE_NAME, buildClearServerAuthCookieHeader, getServerAuthCookieHeader };
33
+ export { SERVER_AUTH_COOKIE_NAME, buildClearServerAuthCookieHeader, buildServerAuthCookieHeader, getServerAuthCookieHeader, readServerAuthCookie };
@@ -0,0 +1,76 @@
1
+ //#region src/lib/stored-auth-cookies.ts
2
+ function parseSetCookieHeader(header) {
3
+ const cookieMap = /* @__PURE__ */ new Map();
4
+ header.split(", ").forEach((cookie) => {
5
+ const [nameValue, ...attributes] = cookie.split("; ");
6
+ const [name, value] = nameValue.split("=");
7
+ const cookieObj = { value };
8
+ attributes.forEach((attr) => {
9
+ const [attrName, attrValue] = attr.split("=");
10
+ cookieObj[attrName.toLowerCase()] = attrValue;
11
+ });
12
+ cookieMap.set(name, cookieObj);
13
+ });
14
+ return cookieMap;
15
+ }
16
+ function getSetCookie(header, prevCookie) {
17
+ const parsed = parseSetCookieHeader(header);
18
+ let toSetCookie = {};
19
+ parsed.forEach((cookie, key) => {
20
+ const expiresAt = cookie["expires"];
21
+ const maxAge = cookie["max-age"];
22
+ let expires = null;
23
+ if (expiresAt) expires = new Date(String(expiresAt));
24
+ else if (maxAge) expires = new Date(Date.now() + Number(maxAge) * 1e3);
25
+ toSetCookie[key] = {
26
+ value: cookie["value"],
27
+ expires: expires ? expires.toISOString() : null
28
+ };
29
+ });
30
+ if (prevCookie) try {
31
+ toSetCookie = {
32
+ ...JSON.parse(prevCookie),
33
+ ...toSetCookie
34
+ };
35
+ } catch {}
36
+ return JSON.stringify(toSetCookie);
37
+ }
38
+ function getCookie(cookie) {
39
+ let parsed = {};
40
+ try {
41
+ parsed = JSON.parse(cookie);
42
+ } catch {}
43
+ const parts = [];
44
+ for (const [key, value] of Object.entries(parsed)) {
45
+ if (value.expires && new Date(value.expires) < /* @__PURE__ */ new Date()) continue;
46
+ parts.push(`${key}=${value.value}`);
47
+ }
48
+ return parts.join("; ");
49
+ }
50
+ /**
51
+ * The stored cookies with those of a `Cookie` header's value added, when it holds one they don't:
52
+ * a session the website's Worker signed in with. Null when they hold it already, even expired.
53
+ */
54
+ function withCookieHeader(stored, header) {
55
+ let parsed = {};
56
+ try {
57
+ parsed = JSON.parse(stored);
58
+ } catch {}
59
+ let added = false;
60
+ for (const pair of header.split("; ")) {
61
+ const separator = pair.indexOf("=");
62
+ if (separator <= 0) continue;
63
+ const name = pair.slice(0, separator);
64
+ const value = pair.slice(separator + 1);
65
+ if (parsed[name]?.value === value) continue;
66
+ parsed[name] = {
67
+ value,
68
+ expires: null
69
+ };
70
+ added = true;
71
+ }
72
+ return added ? JSON.stringify(parsed) : null;
73
+ }
74
+
75
+ //#endregion
76
+ export { getCookie, getSetCookie, parseSetCookieHeader, withCookieHeader };
@@ -484,7 +484,7 @@ function createStudioCache({ queryClient, scope, api, runtimeJson = (endpoint, b
484
484
  message,
485
485
  projectId
486
486
  });
487
- const keyScope = message.draftId === null ? null : await scope.keyScopeOfDraft(message.draftId, projectId);
487
+ const keyScope = message.draftId;
488
488
  await Promise.all(message.targets.map((queryKey) => queryClient.invalidateQueries({
489
489
  queryKey,
490
490
  predicate: keyScope === null ? void 0 : (query) => scopeOfKey(query.queryKey) === keyScope
@@ -1,7 +1,6 @@
1
1
  import { apiSocketOptions } from "./api-socket.js";
2
2
  import { c } from "react/compiler-runtime";
3
3
  import * as React from "react";
4
- import { DEVELOPMENT_DRAFT } from "@camox/api-contract/drafts";
5
4
  import { usePartySocket } from "partysocket/react";
6
5
  import { EMPTY_THREAD_STATE, THREAD_ENDED_CLOSE_CODE, reduceThreadFrame, threadViewOf } from "@camox/api-contract/threads";
7
6
 
@@ -11,10 +10,10 @@ const OPEN = 1;
11
10
  /**
12
11
  * Follows a thread in a project over its socket, folding Pi's events into the thread's view: the
13
12
  * signed-in editor's Live thread when `draftId` is null, or the draft's thread, which `draftId`
14
- * names as the draft header does (`development` in dev mode). A message is resent with its
13
+ * names. A message is resent with its
15
14
  * operation id each time the thread shows itself after the socket opens, until it accepts it,
16
15
  * which records it once, or turns it down. A draft's thread that ended with its draft isn't
17
- * reconnected to, but for a development draft's, which moves on to a new thread. Mount it once
16
+ * reconnected to. Mount it once
18
17
  * per project and draft.
19
18
  *
20
19
  * When the agent on Live hands a request off to a draft it started, the studio that sent a
@@ -25,7 +24,7 @@ const OPEN = 1;
25
24
  * of only, so that the studio follows the agent; teammates' runs leave it where it is.
26
25
  */
27
26
  function useThread(apiUrl, projectId, draftId, t0) {
28
- const $ = c(47);
27
+ const $ = c(46);
29
28
  let t1;
30
29
  if ($[0] !== t0) {
31
30
  t1 = t0 === void 0 ? {} : t0;
@@ -71,17 +70,14 @@ function useThread(apiUrl, projectId, draftId, t0) {
71
70
  basePath: draftId ? `threads/draft/${projectId}/${draftId}` : `threads/live/${projectId}`,
72
71
  maxEnqueuedMessages: 0,
73
72
  shouldReconnectOnClose: _temp,
74
- onClose(event_0) {
75
- if (event_0.code === THREAD_ENDED_CLOSE_CODE && draftId === DEVELOPMENT_DRAFT) socket.reconnect();
76
- },
77
73
  onOpen() {
78
74
  shown.current = false;
79
75
  },
80
- onMessage(event_1) {
81
- if (typeof event_1.data !== "string") return;
76
+ onMessage(event_0) {
77
+ if (typeof event_0.data !== "string") return;
82
78
  let frame;
83
79
  try {
84
- frame = JSON.parse(event_1.data);
80
+ frame = JSON.parse(event_0.data);
85
81
  } catch {
86
82
  return;
87
83
  }
@@ -156,10 +152,10 @@ function useThread(apiUrl, projectId, draftId, t0) {
156
152
  let t9;
157
153
  if ($[23] !== socket || $[24] !== unaccepted) {
158
154
  t9 = () => {
159
- for (const [operationId_2, text] of unaccepted) transmit(socket, {
155
+ for (const [operationId_2, message] of unaccepted) transmit(socket, {
160
156
  type: "send",
161
157
  operationId: operationId_2,
162
- text
158
+ ...message
163
159
  });
164
160
  };
165
161
  $[23] = socket;
@@ -184,6 +180,7 @@ function useThread(apiUrl, projectId, draftId, t0) {
184
180
  } else t11 = $[30];
185
181
  React.useEffect(t10, t11);
186
182
  let t12;
183
+ let t13;
187
184
  if ($[31] !== socket) {
188
185
  t12 = () => {
189
186
  const resync = () => {
@@ -192,44 +189,47 @@ function useThread(apiUrl, projectId, draftId, t0) {
192
189
  document.addEventListener("visibilitychange", resync);
193
190
  return () => document.removeEventListener("visibilitychange", resync);
194
191
  };
192
+ t13 = [socket];
195
193
  $[31] = socket;
196
194
  $[32] = t12;
197
- } else t12 = $[32];
198
- let t13;
199
- if ($[33] !== socket) {
200
- t13 = [socket];
201
- $[33] = socket;
202
- $[34] = t13;
203
- } else t13 = $[34];
195
+ $[33] = t13;
196
+ } else {
197
+ t12 = $[32];
198
+ t13 = $[33];
199
+ }
204
200
  React.useEffect(t12, t13);
205
201
  let t14;
206
- if ($[35] !== sent || $[36] !== socket) {
207
- t14 = (text_0) => {
202
+ if ($[34] !== sent || $[35] !== socket) {
203
+ t14 = (text, where) => {
208
204
  const operationId_3 = crypto.randomUUID();
205
+ const message_0 = where ? {
206
+ text,
207
+ where
208
+ } : { text };
209
209
  sent.add(operationId_3);
210
210
  setError(void 0);
211
- setUnaccepted((current_3) => new Map(current_3).set(operationId_3, text_0));
211
+ setUnaccepted((current_3) => new Map(current_3).set(operationId_3, message_0));
212
212
  transmit(socket, {
213
213
  type: "send",
214
214
  operationId: operationId_3,
215
- text: text_0
215
+ ...message_0
216
216
  });
217
217
  };
218
- $[35] = sent;
219
- $[36] = socket;
220
- $[37] = t14;
221
- } else t14 = $[37];
218
+ $[34] = sent;
219
+ $[35] = socket;
220
+ $[36] = t14;
221
+ } else t14 = $[36];
222
222
  const send = t14;
223
223
  let t15;
224
- if ($[38] !== socket) {
224
+ if ($[37] !== socket) {
225
225
  t15 = () => transmit(socket, { type: "stop" });
226
- $[38] = socket;
227
- $[39] = t15;
228
- } else t15 = $[39];
226
+ $[37] = socket;
227
+ $[38] = t15;
228
+ } else t15 = $[38];
229
229
  const stop = t15;
230
230
  const t16 = unaccepted.size > 0;
231
231
  let t17;
232
- if ($[40] !== error || $[41] !== send || $[42] !== stop || $[43] !== t16 || $[44] !== touched || $[45] !== view) {
232
+ if ($[39] !== error || $[40] !== send || $[41] !== stop || $[42] !== t16 || $[43] !== touched || $[44] !== view) {
233
233
  t17 = {
234
234
  view,
235
235
  sending: t16,
@@ -238,14 +238,14 @@ function useThread(apiUrl, projectId, draftId, t0) {
238
238
  error,
239
239
  touched
240
240
  };
241
- $[40] = error;
242
- $[41] = send;
243
- $[42] = stop;
244
- $[43] = t16;
245
- $[44] = touched;
246
- $[45] = view;
247
- $[46] = t17;
248
- } else t17 = $[46];
241
+ $[39] = error;
242
+ $[40] = send;
243
+ $[41] = stop;
244
+ $[42] = t16;
245
+ $[43] = touched;
246
+ $[44] = view;
247
+ $[45] = t17;
248
+ } else t17 = $[45];
249
249
  return t17;
250
250
  }
251
251
  function _temp2(count) {
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.58.1";
2
+ var version = "0.60.2";
3
3
 
4
4
  //#endregion
5
5
  export { version };