jazz-tools 0.20.0 → 0.20.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 (146) hide show
  1. package/.turbo/turbo-build.log +56 -56
  2. package/CHANGELOG.md +21 -0
  3. package/dist/{chunk-3CAPPS2F.js → chunk-Q5RNSSUM.js} +269 -95
  4. package/dist/chunk-Q5RNSSUM.js.map +1 -0
  5. package/dist/chunk-ZQWSQH6L.js +20 -0
  6. package/dist/index.js +2 -2
  7. package/dist/inspector/{chunk-MCTB5ZJC.js → chunk-6JPVMI3V.js} +302 -182
  8. package/dist/inspector/chunk-6JPVMI3V.js.map +1 -0
  9. package/dist/inspector/{custom-element-5YWVZBWA.js → custom-element-PWRX4VCA.js} +1337 -206
  10. package/dist/inspector/custom-element-PWRX4VCA.js.map +1 -0
  11. package/dist/inspector/in-app.d.ts +1 -0
  12. package/dist/inspector/in-app.d.ts.map +1 -1
  13. package/dist/inspector/index.d.ts +1 -0
  14. package/dist/inspector/index.d.ts.map +1 -1
  15. package/dist/inspector/index.js +1044 -17
  16. package/dist/inspector/index.js.map +1 -1
  17. package/dist/inspector/pages/home.d.ts +4 -1
  18. package/dist/inspector/pages/home.d.ts.map +1 -1
  19. package/dist/inspector/pages/performance/PerformancePage.d.ts +7 -0
  20. package/dist/inspector/pages/performance/PerformancePage.d.ts.map +1 -0
  21. package/dist/inspector/pages/performance/SubscriptionDetailPanel.d.ts +8 -0
  22. package/dist/inspector/pages/performance/SubscriptionDetailPanel.d.ts.map +1 -0
  23. package/dist/inspector/pages/performance/SubscriptionRow.d.ts +11 -0
  24. package/dist/inspector/pages/performance/SubscriptionRow.d.ts.map +1 -0
  25. package/dist/inspector/pages/performance/Timeline.d.ts +12 -0
  26. package/dist/inspector/pages/performance/Timeline.d.ts.map +1 -0
  27. package/dist/inspector/pages/performance/helpers.d.ts +5 -0
  28. package/dist/inspector/pages/performance/helpers.d.ts.map +1 -0
  29. package/dist/inspector/pages/performance/index.d.ts +3 -0
  30. package/dist/inspector/pages/performance/index.d.ts.map +1 -0
  31. package/dist/inspector/pages/performance/types.d.ts +13 -0
  32. package/dist/inspector/pages/performance/types.d.ts.map +1 -0
  33. package/dist/inspector/pages/performance/usePerformanceEntries.d.ts +3 -0
  34. package/dist/inspector/pages/performance/usePerformanceEntries.d.ts.map +1 -0
  35. package/dist/inspector/register-custom-element.js +3 -1
  36. package/dist/inspector/register-custom-element.js.map +1 -1
  37. package/dist/inspector/standalone.js +1 -1
  38. package/dist/inspector/tests/pages/performance/PerformancePage.test.d.ts +2 -0
  39. package/dist/inspector/tests/pages/performance/PerformancePage.test.d.ts.map +1 -0
  40. package/dist/inspector/tests/pages/performance/SubscriptionDetailPanel.test.d.ts +2 -0
  41. package/dist/inspector/tests/pages/performance/SubscriptionDetailPanel.test.d.ts.map +1 -0
  42. package/dist/inspector/tests/pages/performance/SubscriptionRow.test.d.ts +2 -0
  43. package/dist/inspector/tests/pages/performance/SubscriptionRow.test.d.ts.map +1 -0
  44. package/dist/inspector/tests/pages/performance/Timeline.test.d.ts +2 -0
  45. package/dist/inspector/tests/pages/performance/Timeline.test.d.ts.map +1 -0
  46. package/dist/inspector/tests/pages/performance/helpers.test.d.ts +2 -0
  47. package/dist/inspector/tests/pages/performance/helpers.test.d.ts.map +1 -0
  48. package/dist/inspector/viewer/delete-local-data.d.ts.map +1 -1
  49. package/dist/inspector/viewer/header.d.ts +4 -2
  50. package/dist/inspector/viewer/header.d.ts.map +1 -1
  51. package/dist/inspector/viewer/page-stack.d.ts +3 -1
  52. package/dist/inspector/viewer/page-stack.d.ts.map +1 -1
  53. package/dist/react-core/hooks.d.ts +2 -2
  54. package/dist/react-core/hooks.d.ts.map +1 -1
  55. package/dist/react-core/index.js +50 -18
  56. package/dist/react-core/index.js.map +1 -1
  57. package/dist/react-core/subscription-provider.d.ts.map +1 -1
  58. package/dist/react-native-core/media/image.d.ts +1 -1
  59. package/dist/svelte/jazz.class.svelte.d.ts.map +1 -1
  60. package/dist/svelte/jazz.class.svelte.js +27 -22
  61. package/dist/testing.js +2 -2
  62. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  63. package/dist/tools/exports.d.ts +1 -1
  64. package/dist/tools/exports.d.ts.map +1 -1
  65. package/dist/tools/implementation/zodSchema/runtimeConverters/coValueSchemaTransformation.d.ts.map +1 -1
  66. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  67. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +2 -1
  68. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
  69. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +2 -1
  70. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
  71. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +2 -1
  72. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
  73. package/dist/tools/implementation/zodSchema/schemaTypes/CoVectorSchema.d.ts +3 -1
  74. package/dist/tools/implementation/zodSchema/schemaTypes/CoVectorSchema.d.ts.map +1 -1
  75. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +3 -1
  76. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -1
  77. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts +2 -1
  78. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts.map +1 -1
  79. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts +6 -1
  80. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts.map +1 -1
  81. package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
  82. package/dist/tools/ssr.js +1 -1
  83. package/dist/tools/subscribe/SubscriptionCache.d.ts +2 -2
  84. package/dist/tools/subscribe/SubscriptionCache.d.ts.map +1 -1
  85. package/dist/tools/subscribe/SubscriptionScope.d.ts +19 -12
  86. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  87. package/dist/tools/subscribe/errorReporting.d.ts +6 -0
  88. package/dist/tools/subscribe/errorReporting.d.ts.map +1 -1
  89. package/dist/tools/subscribe/index.d.ts +4 -4
  90. package/dist/tools/subscribe/index.d.ts.map +1 -1
  91. package/dist/tools/subscribe/types.d.ts +48 -3
  92. package/dist/tools/subscribe/types.d.ts.map +1 -1
  93. package/dist/tools/subscribe/utils.d.ts +1 -1
  94. package/dist/tools/subscribe/utils.d.ts.map +1 -1
  95. package/dist/tools/tests/SubscriptionScope.performance.test.d.ts +2 -0
  96. package/dist/tools/tests/SubscriptionScope.performance.test.d.ts.map +1 -0
  97. package/package.json +4 -4
  98. package/src/inspector/in-app.tsx +41 -3
  99. package/src/inspector/index.tsx +5 -1
  100. package/src/inspector/pages/home.tsx +26 -3
  101. package/src/inspector/pages/performance/PerformancePage.tsx +215 -0
  102. package/src/inspector/pages/performance/SubscriptionDetailPanel.tsx +182 -0
  103. package/src/inspector/pages/performance/SubscriptionRow.tsx +242 -0
  104. package/src/inspector/pages/performance/Timeline.tsx +513 -0
  105. package/src/inspector/pages/performance/helpers.ts +70 -0
  106. package/src/inspector/pages/performance/index.ts +2 -0
  107. package/src/inspector/pages/performance/types.ts +12 -0
  108. package/src/inspector/pages/performance/usePerformanceEntries.ts +53 -0
  109. package/src/inspector/register-custom-element.ts +3 -0
  110. package/src/inspector/tests/pages/performance/PerformancePage.test.tsx +83 -0
  111. package/src/inspector/tests/pages/performance/SubscriptionDetailPanel.test.tsx +68 -0
  112. package/src/inspector/tests/pages/performance/SubscriptionRow.test.tsx +93 -0
  113. package/src/inspector/tests/pages/performance/Timeline.test.tsx +57 -0
  114. package/src/inspector/tests/pages/performance/helpers.test.ts +91 -0
  115. package/src/inspector/viewer/delete-local-data.tsx +24 -5
  116. package/src/inspector/viewer/header.tsx +96 -17
  117. package/src/inspector/viewer/page-stack.tsx +22 -18
  118. package/src/react-core/hooks.ts +34 -4
  119. package/src/react-core/subscription-provider.tsx +17 -8
  120. package/src/svelte/jazz.class.svelte.ts +51 -33
  121. package/src/tools/coValues/coList.ts +73 -37
  122. package/src/tools/coValues/interfaces.ts +3 -0
  123. package/src/tools/exports.ts +1 -0
  124. package/src/tools/implementation/zodSchema/runtimeConverters/coValueSchemaTransformation.ts +13 -0
  125. package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +0 -2
  126. package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +5 -2
  127. package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +5 -2
  128. package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +5 -2
  129. package/src/tools/implementation/zodSchema/schemaTypes/CoVectorSchema.ts +6 -2
  130. package/src/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +6 -2
  131. package/src/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.ts +5 -2
  132. package/src/tools/implementation/zodSchema/schemaTypes/RichTextSchema.ts +9 -2
  133. package/src/tools/subscribe/SubscriptionCache.ts +6 -4
  134. package/src/tools/subscribe/SubscriptionScope.ts +141 -23
  135. package/src/tools/subscribe/errorReporting.ts +1 -1
  136. package/src/tools/subscribe/index.ts +1 -1
  137. package/src/tools/subscribe/types.ts +62 -9
  138. package/src/tools/subscribe/utils.ts +2 -2
  139. package/src/tools/tests/SubscriptionScope.performance.test.ts +149 -0
  140. package/src/tools/tests/coList.test.ts +262 -0
  141. package/src/tools/tests/schema.withPermissions.test.ts +27 -4
  142. package/dist/chunk-3CAPPS2F.js.map +0 -1
  143. package/dist/chunk-PZ5AY32C.js +0 -10
  144. package/dist/inspector/chunk-MCTB5ZJC.js.map +0 -1
  145. package/dist/inspector/custom-element-5YWVZBWA.js.map +0 -1
  146. /package/dist/{chunk-PZ5AY32C.js.map → chunk-ZQWSQH6L.js.map} +0 -0
@@ -31782,13 +31782,14 @@ var require_jsx_runtime = __commonJS({
31782
31782
  });
31783
31783
 
31784
31784
  // src/inspector/custom-element.tsx
31785
- var import_react32 = __toESM(require_react(), 1);
31785
+ var import_react36 = __toESM(require_react(), 1);
31786
31786
  var import_client = __toESM(require_client(), 1);
31787
31787
  import { setup } from "goober";
31788
31788
  import { Account } from "jazz-tools";
31789
31789
 
31790
31790
  // src/inspector/in-app.tsx
31791
- import { styled as styled29 } from "goober";
31791
+ var import_react35 = __toESM(require_react(), 1);
31792
+ import { styled as styled33 } from "goober";
31792
31793
 
31793
31794
  // src/inspector/viewer/page-stack.tsx
31794
31795
  import { styled as styled24 } from "goober";
@@ -35336,7 +35337,7 @@ function useNode() {
35336
35337
 
35337
35338
  // src/inspector/pages/home.tsx
35338
35339
  import { styled as styled23 } from "goober";
35339
- var import_react27 = __toESM(require_react(), 1);
35340
+ var import_react28 = __toESM(require_react(), 1);
35340
35341
 
35341
35342
  // src/inspector/router/in-memory-router.tsx
35342
35343
  var import_react25 = __toESM(require_react(), 1);
@@ -35395,14 +35396,161 @@ function InMemoryRouterProvider({
35395
35396
  var import_react26 = __toESM(require_react(), 1);
35396
35397
  var import_jsx_runtime38 = __toESM(require_jsx_runtime(), 1);
35397
35398
 
35398
- // src/inspector/pages/home.tsx
35399
+ // src/inspector/viewer/delete-local-data.tsx
35400
+ var import_react27 = __toESM(require_react(), 1);
35399
35401
  var import_jsx_runtime39 = __toESM(require_jsx_runtime(), 1);
35400
- function HomePage() {
35402
+ import { useJazzContext } from "jazz-tools/react-core";
35403
+ var DELETE_LOCAL_DATA_STRING = "delete my local data";
35404
+ function DeleteLocalData() {
35405
+ const [showDeleteModal, setShowDeleteModal] = (0, import_react27.useState)(false);
35406
+ const [confirmDeleteString, setConfirmDeleteString] = (0, import_react27.useState)("");
35407
+ const jazzContext = useJazzContext();
35408
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
35409
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
35410
+ Button,
35411
+ {
35412
+ variant: "destructive",
35413
+ onClick: () => setShowDeleteModal(true),
35414
+ title: "Delete my local data",
35415
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
35416
+ "svg",
35417
+ {
35418
+ width: "16",
35419
+ height: "16",
35420
+ viewBox: "0 0 16 16",
35421
+ fill: "none",
35422
+ xmlns: "http://www.w3.org/2000/svg",
35423
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
35424
+ "path",
35425
+ {
35426
+ d: "M2 4h12M5.333 4V2.667a1.333 1.333 0 011.334-1.334h2.666a1.333 1.333 0 011.334 1.334V4m2 0v9.333a1.333 1.333 0 01-1.334 1.334H4.667a1.333 1.333 0 01-1.334-1.334V4h9.334z",
35427
+ stroke: "currentColor",
35428
+ strokeWidth: "1.5",
35429
+ strokeLinecap: "round",
35430
+ strokeLinejoin: "round"
35431
+ }
35432
+ )
35433
+ }
35434
+ )
35435
+ }
35436
+ ),
35437
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
35438
+ Modal,
35439
+ {
35440
+ isOpen: showDeleteModal,
35441
+ onClose: () => setShowDeleteModal(false),
35442
+ heading: "Delete Local Data",
35443
+ showButtons: false,
35444
+ children: [
35445
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
35446
+ "div",
35447
+ {
35448
+ style: {
35449
+ margin: "0 0 1rem 0",
35450
+ color: "var(--j-text-color)",
35451
+ display: "flex",
35452
+ flexDirection: "column",
35453
+ gap: "0.5rem"
35454
+ },
35455
+ children: [
35456
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { children: [
35457
+ "This action ",
35458
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("strong", { children: "cannot" }),
35459
+ " be undone."
35460
+ ] }),
35461
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { children: [
35462
+ "Be aware that the following data will be",
35463
+ " ",
35464
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("strong", { children: "permanently" }),
35465
+ " deleted:"
35466
+ ] }),
35467
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("ul", { style: { listStyleType: "disc", paddingLeft: "1rem" }, children: [
35468
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("li", { children: [
35469
+ "Unsynced data for ",
35470
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("strong", { children: "all apps" }),
35471
+ " on",
35472
+ " ",
35473
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("code", { children: window.location.origin })
35474
+ ] }),
35475
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("li", { children: "Accounts" }),
35476
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("li", { children: "Logged in sessions" })
35477
+ ] }),
35478
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", {})
35479
+ ]
35480
+ }
35481
+ ),
35482
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
35483
+ Input,
35484
+ {
35485
+ label: `Type "${DELETE_LOCAL_DATA_STRING}" to confirm`,
35486
+ placeholder: DELETE_LOCAL_DATA_STRING,
35487
+ value: confirmDeleteString,
35488
+ onChange: (e) => {
35489
+ setConfirmDeleteString(e.target.value);
35490
+ }
35491
+ }
35492
+ ),
35493
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
35494
+ "p",
35495
+ {
35496
+ style: {
35497
+ margin: "0 0 1rem 0",
35498
+ color: "var(--j-text-color)",
35499
+ display: "flex",
35500
+ flexDirection: "column",
35501
+ gap: "0.5rem"
35502
+ },
35503
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("small", { children: [
35504
+ "Data synced to a sync server will ",
35505
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("strong", { children: "not" }),
35506
+ " be deleted, and will be synced when you log in again."
35507
+ ] })
35508
+ }
35509
+ ),
35510
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
35511
+ "div",
35512
+ {
35513
+ style: {
35514
+ display: "flex",
35515
+ marginTop: "0.5rem",
35516
+ justifyContent: "flex-end",
35517
+ gap: "0.5rem"
35518
+ },
35519
+ children: [
35520
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Button, { variant: "secondary", onClick: () => setShowDeleteModal(false), children: "Cancel" }),
35521
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
35522
+ Button,
35523
+ {
35524
+ variant: "destructive",
35525
+ disabled: confirmDeleteString !== DELETE_LOCAL_DATA_STRING,
35526
+ onClick: () => {
35527
+ localStorage.removeItem(
35528
+ jazzContext.getAuthSecretStorage().getStorageKey()
35529
+ );
35530
+ indexedDB.deleteDatabase("jazz-storage");
35531
+ window.location.reload();
35532
+ setShowDeleteModal(false);
35533
+ },
35534
+ children: "I'm sure, delete my local data"
35535
+ }
35536
+ )
35537
+ ]
35538
+ }
35539
+ )
35540
+ ]
35541
+ }
35542
+ )
35543
+ ] });
35544
+ }
35545
+
35546
+ // src/inspector/pages/home.tsx
35547
+ var import_jsx_runtime40 = __toESM(require_jsx_runtime(), 1);
35548
+ function HomePage({ showDeleteLocalData }) {
35401
35549
  const { localNode, accountID } = useNode();
35402
35550
  const { path, setPage } = useRouter();
35403
- const [coValueId, setCoValueId] = (0, import_react27.useState)("");
35551
+ const [coValueId, setCoValueId] = (0, import_react28.useState)("");
35404
35552
  if (!localNode || !accountID) {
35405
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { children: "Loading..." });
35553
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { children: "Loading..." });
35406
35554
  }
35407
35555
  const handleCoValueIdSubmit = (e) => {
35408
35556
  e.preventDefault();
@@ -35411,40 +35559,48 @@ function HomePage() {
35411
35559
  }
35412
35560
  setCoValueId("");
35413
35561
  };
35414
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_jsx_runtime39.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
35415
- CenteredForm,
35416
- {
35417
- onSubmit: handleCoValueIdSubmit,
35418
- "aria-hidden": path.length !== 0,
35419
- children: [
35420
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Heading, { children: "Jazz CoValue Inspector" }),
35421
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
35422
- Input,
35423
- {
35424
- label: "CoValue ID",
35425
- className: "font-mono",
35426
- hideLabel: true,
35427
- placeholder: "co_z1234567890abcdef123456789",
35428
- value: coValueId,
35429
- onChange: (e) => setCoValueId(e.target.value)
35430
- }
35431
- ),
35432
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Button, { type: "submit", variant: "primary", children: "Inspect CoValue" }),
35433
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(OrText, { children: "or" }),
35434
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
35435
- Button,
35436
- {
35437
- variant: "secondary",
35438
- onClick: () => {
35439
- setPage(accountID);
35440
- },
35441
- children: "Inspect my account"
35442
- }
35443
- )
35444
- ]
35445
- }
35446
- ) });
35562
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(PageContainer2, { children: [
35563
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
35564
+ CenteredForm,
35565
+ {
35566
+ onSubmit: handleCoValueIdSubmit,
35567
+ "aria-hidden": path.length !== 0,
35568
+ children: [
35569
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Heading, { children: "Jazz CoValue Inspector" }),
35570
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
35571
+ Input,
35572
+ {
35573
+ label: "CoValue ID",
35574
+ className: "font-mono",
35575
+ hideLabel: true,
35576
+ placeholder: "co_z1234567890abcdef123456789",
35577
+ value: coValueId,
35578
+ onChange: (e) => setCoValueId(e.target.value)
35579
+ }
35580
+ ),
35581
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Button, { type: "submit", variant: "primary", children: "Inspect CoValue" }),
35582
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(OrText, { children: "or" }),
35583
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
35584
+ Button,
35585
+ {
35586
+ variant: "secondary",
35587
+ onClick: () => {
35588
+ setPage(accountID);
35589
+ },
35590
+ children: "Inspect my account"
35591
+ }
35592
+ )
35593
+ ]
35594
+ }
35595
+ ),
35596
+ showDeleteLocalData && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(BottomRight, { children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(DeleteLocalData, {}) })
35597
+ ] });
35447
35598
  }
35599
+ var PageContainer2 = styled23("div")`
35600
+ position: relative;
35601
+ height: 100%;
35602
+ width: 100%;
35603
+ `;
35448
35604
  var CenteredForm = styled23("form")`
35449
35605
  display: flex;
35450
35606
  flex-direction: column;
@@ -35460,9 +35616,14 @@ var CenteredForm = styled23("form")`
35460
35616
  var OrText = styled23("p")`
35461
35617
  text-align: center;
35462
35618
  `;
35619
+ var BottomRight = styled23("div")`
35620
+ position: absolute;
35621
+ bottom: 0.75rem;
35622
+ right: 0;
35623
+ `;
35463
35624
 
35464
35625
  // src/inspector/viewer/page-stack.tsx
35465
- var import_jsx_runtime40 = __toESM(require_jsx_runtime(), 1);
35626
+ var import_jsx_runtime41 = __toESM(require_jsx_runtime(), 1);
35466
35627
  var PageStackContainer = styled24("article")`
35467
35628
  position: relative;
35468
35629
  padding: 0 0.75rem;
@@ -35471,15 +35632,15 @@ var PageStackContainer = styled24("article")`
35471
35632
  color: var(--j-text-color);
35472
35633
  font-size: 16px;
35473
35634
  `;
35474
- function PageStack({ homePage }) {
35635
+ function PageStack({ homePage, style }) {
35475
35636
  const { path, addPages, goBack } = useRouter();
35476
35637
  const { localNode } = useNode();
35477
35638
  const page = path[path.length - 1];
35478
35639
  const index = path.length - 1;
35479
35640
  if (path.length <= 0) {
35480
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(PageStackContainer, { children: homePage ?? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(HomePage, {}) });
35641
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(PageStackContainer, { style, children: homePage ?? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(HomePage, {}) });
35481
35642
  }
35482
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_jsx_runtime40.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(PageStackContainer, { children: localNode && page && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ErrorBoundary, { title: "An error occurred while rendering this CoValue", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
35643
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(PageStackContainer, { style, children: localNode && page && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ErrorBoundary, { title: "An error occurred while rendering this CoValue", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
35483
35644
  Page,
35484
35645
  {
35485
35646
  coId: page.coId,
@@ -35489,7 +35650,7 @@ function PageStack({ homePage }) {
35489
35650
  onNavigate: addPages,
35490
35651
  isTopLevel: index === path.length - 1
35491
35652
  }
35492
- ) }) }) });
35653
+ ) }) });
35493
35654
  }
35494
35655
 
35495
35656
  // src/inspector/ui/global-styles.tsx
@@ -35568,7 +35729,7 @@ var GlobalStyles = styled25("div")`
35568
35729
  `;
35569
35730
 
35570
35731
  // src/inspector/viewer/inspector-button.tsx
35571
- var import_jsx_runtime41 = __toESM(require_jsx_runtime(), 1);
35732
+ var import_jsx_runtime42 = __toESM(require_jsx_runtime(), 1);
35572
35733
  import { styled as styled26 } from "goober";
35573
35734
  var StyledInspectorButton = styled26("button")`
35574
35735
  position: fixed;
@@ -35612,8 +35773,8 @@ function InspectorButton({
35612
35773
  position = "right",
35613
35774
  ...buttonProps
35614
35775
  }) {
35615
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(StyledInspectorButton, { position, ...buttonProps, children: [
35616
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
35776
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(StyledInspectorButton, { position, ...buttonProps, children: [
35777
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
35617
35778
  JazzIcon,
35618
35779
  {
35619
35780
  xmlns: "http://www.w3.org/2000/svg",
@@ -35621,7 +35782,7 @@ function InspectorButton({
35621
35782
  height: "115",
35622
35783
  viewBox: "0 0 119 115",
35623
35784
  fill: "none",
35624
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
35785
+ children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
35625
35786
  "path",
35626
35787
  {
35627
35788
  fillRule: "evenodd",
@@ -35632,7 +35793,7 @@ function InspectorButton({
35632
35793
  )
35633
35794
  }
35634
35795
  ),
35635
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
35796
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
35636
35797
  "span",
35637
35798
  {
35638
35799
  style: {
@@ -35653,15 +35814,15 @@ function InspectorButton({
35653
35814
  }
35654
35815
 
35655
35816
  // src/inspector/viewer/use-open-inspector.ts
35656
- var import_react28 = __toESM(require_react(), 1);
35817
+ var import_react29 = __toESM(require_react(), 1);
35657
35818
  var STORAGE_KEY2 = "jazz-inspector-open";
35658
35819
  function useOpenInspector() {
35659
- const [open, setOpen] = (0, import_react28.useState)(() => {
35820
+ const [open, setOpen] = (0, import_react29.useState)(() => {
35660
35821
  if (typeof window === "undefined") return false;
35661
35822
  const stored = localStorage.getItem(STORAGE_KEY2);
35662
35823
  return stored ? JSON.parse(stored) : false;
35663
35824
  });
35664
- (0, import_react28.useEffect)(() => {
35825
+ (0, import_react29.useEffect)(() => {
35665
35826
  localStorage.setItem(STORAGE_KEY2, JSON.stringify(open));
35666
35827
  }, [open]);
35667
35828
  return [open, setOpen];
@@ -35672,9 +35833,9 @@ var import_react31 = __toESM(require_react(), 1);
35672
35833
  import { styled as styled28 } from "goober";
35673
35834
 
35674
35835
  // src/inspector/viewer/breadcrumbs.tsx
35675
- var import_react29 = __toESM(require_react(), 1);
35836
+ var import_react30 = __toESM(require_react(), 1);
35676
35837
  import { styled as styled27 } from "goober";
35677
- var import_jsx_runtime42 = __toESM(require_jsx_runtime(), 1);
35838
+ var import_jsx_runtime43 = __toESM(require_jsx_runtime(), 1);
35678
35839
  var BreadcrumbsContainer = styled27("div")`
35679
35840
  position: relative;
35680
35841
  z-index: 20;
@@ -35687,8 +35848,8 @@ var Separator = styled27("span")`
35687
35848
  `;
35688
35849
  var Breadcrumbs = () => {
35689
35850
  const { path, goToIndex } = useRouter();
35690
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(BreadcrumbsContainer, { children: [
35691
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
35851
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(BreadcrumbsContainer, { children: [
35852
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
35692
35853
  Button,
35693
35854
  {
35694
35855
  variant: "link",
@@ -35698,9 +35859,9 @@ var Breadcrumbs = () => {
35698
35859
  }
35699
35860
  ),
35700
35861
  path.map((page, index) => {
35701
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_react29.default.Fragment, { children: [
35702
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Separator, { "aria-hidden": true, children: "/" }),
35703
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
35862
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_react30.default.Fragment, { children: [
35863
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Separator, { "aria-hidden": true, children: "/" }),
35864
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
35704
35865
  Button,
35705
35866
  {
35706
35867
  variant: "link",
@@ -35714,131 +35875,13 @@ var Breadcrumbs = () => {
35714
35875
  ] });
35715
35876
  };
35716
35877
 
35717
- // src/inspector/viewer/delete-local-data.tsx
35718
- var import_react30 = __toESM(require_react(), 1);
35719
- var import_jsx_runtime43 = __toESM(require_jsx_runtime(), 1);
35720
- var DELETE_LOCAL_DATA_STRING = "delete my local data";
35721
- function DeleteLocalData() {
35722
- const [showDeleteModal, setShowDeleteModal] = (0, import_react30.useState)(false);
35723
- const [confirmDeleteString, setConfirmDeleteString] = (0, import_react30.useState)("");
35724
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
35725
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, { variant: "destructive", onClick: () => setShowDeleteModal(true), children: "Delete my local data" }),
35726
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
35727
- Modal,
35728
- {
35729
- isOpen: showDeleteModal,
35730
- onClose: () => setShowDeleteModal(false),
35731
- heading: "Delete Local Data",
35732
- showButtons: false,
35733
- children: [
35734
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
35735
- "div",
35736
- {
35737
- style: {
35738
- margin: "0 0 1rem 0",
35739
- color: "var(--j-text-color)",
35740
- display: "flex",
35741
- flexDirection: "column",
35742
- gap: "0.5rem"
35743
- },
35744
- children: [
35745
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { children: [
35746
- "This action ",
35747
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: "cannot" }),
35748
- " be undone."
35749
- ] }),
35750
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { children: [
35751
- "Be aware that the following data will be",
35752
- " ",
35753
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: "permanently" }),
35754
- " deleted:"
35755
- ] }),
35756
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("ul", { style: { listStyleType: "disc", paddingLeft: "1rem" }, children: [
35757
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("li", { children: [
35758
- "Unsynced data for ",
35759
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: "all apps" }),
35760
- " on",
35761
- " ",
35762
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("code", { children: window.location.origin })
35763
- ] }),
35764
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { children: "Accounts" }),
35765
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { children: "Logged in sessions" })
35766
- ] }),
35767
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", {})
35768
- ]
35769
- }
35770
- ),
35771
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
35772
- Input,
35773
- {
35774
- label: `Type "${DELETE_LOCAL_DATA_STRING}" to confirm`,
35775
- placeholder: DELETE_LOCAL_DATA_STRING,
35776
- value: confirmDeleteString,
35777
- onChange: (e) => {
35778
- setConfirmDeleteString(e.target.value);
35779
- }
35780
- }
35781
- ),
35782
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
35783
- "p",
35784
- {
35785
- style: {
35786
- margin: "0 0 1rem 0",
35787
- color: "var(--j-text-color)",
35788
- display: "flex",
35789
- flexDirection: "column",
35790
- gap: "0.5rem"
35791
- },
35792
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("small", { children: [
35793
- "Data synced to a sync server will ",
35794
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: "not" }),
35795
- " be deleted, and will be synced when you log in again."
35796
- ] })
35797
- }
35798
- ),
35799
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
35800
- "div",
35801
- {
35802
- style: {
35803
- display: "flex",
35804
- marginTop: "0.5rem",
35805
- justifyContent: "flex-end",
35806
- gap: "0.5rem"
35807
- },
35808
- children: [
35809
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, { variant: "secondary", onClick: () => setShowDeleteModal(false), children: "Cancel" }),
35810
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
35811
- Button,
35812
- {
35813
- variant: "destructive",
35814
- disabled: confirmDeleteString !== DELETE_LOCAL_DATA_STRING,
35815
- onClick: () => {
35816
- const jazzKeys = Object.keys(localStorage).filter(
35817
- (key) => key.startsWith("jazz-") || key.startsWith("co_z")
35818
- );
35819
- jazzKeys.forEach((key) => localStorage.removeItem(key));
35820
- indexedDB.deleteDatabase("jazz-storage");
35821
- window.location.reload();
35822
- setShowDeleteModal(false);
35823
- },
35824
- children: "I'm sure, delete my local data"
35825
- }
35826
- )
35827
- ]
35828
- }
35829
- )
35830
- ]
35831
- }
35832
- )
35833
- ] });
35834
- }
35835
-
35836
35878
  // src/inspector/viewer/header.tsx
35837
35879
  var import_jsx_runtime44 = __toESM(require_jsx_runtime(), 1);
35838
35880
  function Header({
35839
- showDeleteLocalData = false,
35840
35881
  showClose = false,
35841
35882
  onClose,
35883
+ activeTab,
35884
+ onTabChange,
35842
35885
  children
35843
35886
  }) {
35844
35887
  const [coValueId, setCoValueId] = (0, import_react31.useState)("");
@@ -35851,21 +35894,59 @@ function Header({
35851
35894
  setCoValueId("");
35852
35895
  };
35853
35896
  return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(HeaderContainer2, { children: [
35854
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Breadcrumbs, {}),
35855
- path.length !== 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Form, { onSubmit: handleCoValueIdSubmit, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
35856
- Input,
35857
- {
35858
- label: "CoValue ID",
35859
- style: { fontFamily: "monospace" },
35860
- hideLabel: true,
35861
- placeholder: "co_z1234567890abcdef123456789",
35862
- value: coValueId,
35863
- onChange: (e) => setCoValueId(e.target.value)
35864
- }
35865
- ) }),
35897
+ activeTab && onTabChange && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(TabBar, { children: [
35898
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
35899
+ Tab,
35900
+ {
35901
+ active: activeTab === "inspector",
35902
+ onClick: () => onTabChange("inspector"),
35903
+ children: "Inspector"
35904
+ }
35905
+ ),
35906
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
35907
+ Tab,
35908
+ {
35909
+ active: activeTab === "performance",
35910
+ onClick: () => onTabChange("performance"),
35911
+ children: "Performance"
35912
+ }
35913
+ )
35914
+ ] }),
35915
+ (activeTab === "inspector" || !activeTab) && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
35916
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Breadcrumbs, {}),
35917
+ path.length !== 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Form, { onSubmit: handleCoValueIdSubmit, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
35918
+ Input,
35919
+ {
35920
+ label: "CoValue ID",
35921
+ style: { fontFamily: "monospace" },
35922
+ hideLabel: true,
35923
+ placeholder: "co_z1234567890abcdef123456789",
35924
+ value: coValueId,
35925
+ onChange: (e) => setCoValueId(e.target.value)
35926
+ }
35927
+ ) })
35928
+ ] }),
35866
35929
  children,
35867
- showDeleteLocalData && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(DeleteLocalData, {}),
35868
- showClose && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Button, { variant: "plain", type: "button", onClick: onClose, children: "Close" })
35930
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Spacer, {}),
35931
+ showClose && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Button, { variant: "plain", type: "button", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
35932
+ "svg",
35933
+ {
35934
+ width: "14",
35935
+ height: "14",
35936
+ viewBox: "0 0 14 14",
35937
+ fill: "none",
35938
+ xmlns: "http://www.w3.org/2000/svg",
35939
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
35940
+ "path",
35941
+ {
35942
+ d: "M1 1L13 13M1 13L13 1",
35943
+ stroke: "currentColor",
35944
+ strokeWidth: "2",
35945
+ strokeLinecap: "round"
35946
+ }
35947
+ )
35948
+ }
35949
+ ) })
35869
35950
  ] });
35870
35951
  }
35871
35952
  var HeaderContainer2 = styled28("div")`
@@ -35878,31 +35959,1081 @@ var HeaderContainer2 = styled28("div")`
35878
35959
  var Form = styled28("form")`
35879
35960
  width: 24rem;
35880
35961
  `;
35962
+ var TabBar = styled28("div")`
35963
+ display: flex;
35964
+ gap: 0.25rem;
35965
+ background-color: var(--j-foreground);
35966
+ border-radius: var(--j-radius-lg);
35967
+ padding: 0.25rem;
35968
+ `;
35969
+ var Tab = styled28("button")`
35970
+ padding: 0.375rem 0.75rem;
35971
+ border: none;
35972
+ border-radius: var(--j-radius-md);
35973
+ font-size: 0.875rem;
35974
+ font-weight: 500;
35975
+ cursor: pointer;
35976
+ transition: all 0.15s ease;
35881
35977
 
35882
- // src/inspector/in-app.tsx
35978
+ ${(props) => props.active ? `
35979
+ background-color: white;
35980
+ color: var(--j-text-color-strong);
35981
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
35982
+
35983
+ @media (prefers-color-scheme: dark) {
35984
+ background-color: var(--j-neutral-800);
35985
+ }
35986
+ ` : `
35987
+ background-color: transparent;
35988
+ color: var(--j-neutral-500);
35989
+
35990
+ &:hover {
35991
+ color: var(--j-text-color-strong);
35992
+ }
35993
+ `}
35994
+ `;
35995
+ var Spacer = styled28("div")`
35996
+ flex: 1;
35997
+ `;
35998
+
35999
+ // src/inspector/pages/performance/PerformancePage.tsx
36000
+ var import_react34 = __toESM(require_react(), 1);
36001
+ import { styled as styled32 } from "goober";
36002
+
36003
+ // src/inspector/pages/performance/Timeline.tsx
36004
+ var import_react32 = __toESM(require_react(), 1);
36005
+ import { styled as styled29 } from "goober";
36006
+
36007
+ // src/inspector/pages/performance/helpers.ts
36008
+ function formatTime(startTime) {
36009
+ const date = new Date(performance.timeOrigin + startTime);
36010
+ return date.toLocaleTimeString(void 0, {
36011
+ hour: "2-digit",
36012
+ minute: "2-digit",
36013
+ second: "2-digit",
36014
+ fractionalSecondDigits: 3
36015
+ });
36016
+ }
36017
+ function formatDuration(duration) {
36018
+ if (duration < 1) {
36019
+ return `${(duration * 1e3).toFixed(0)}\u03BCs`;
36020
+ }
36021
+ if (duration < 1e3) {
36022
+ return `${duration.toFixed(2)}ms`;
36023
+ }
36024
+ return `${(duration / 1e3).toFixed(2)}s`;
36025
+ }
36026
+ function getCallerLocation(stack) {
36027
+ if (!stack) return void 0;
36028
+ const lines = stack.split("\n").slice(2, 15);
36029
+ const normalizeLine = (line) => line.replace(/https?:\/\/[^/\s)]+/g, "");
36030
+ const userFrame = lines.find(
36031
+ (line) => !line.includes("node_modules") && !line.includes("useCoValueSubscription") && !line.includes("useCoState") && !line.includes("useAccount") && !line.includes("useSuspenseCoState") && !line.includes("useSuspenseAccount") && !line.includes("jazz-tools") && !line.includes("trackLoadingPerformance")
36032
+ );
36033
+ if (userFrame) {
36034
+ const cleanedFrame = normalizeLine(userFrame).trim();
36035
+ const match = cleanedFrame.match(/\(?([^)]+:\d+:\d+)\)?$/);
36036
+ if (match) {
36037
+ return match[1];
36038
+ }
36039
+ return cleanedFrame;
36040
+ }
36041
+ return lines[0] ? normalizeLine(lines[0]).trim() : void 0;
36042
+ }
36043
+ function getCallerStack(stack) {
36044
+ if (!stack) return void 0;
36045
+ const lines = stack.split("\n").slice(2, 15);
36046
+ return lines.filter(
36047
+ (line) => !line.includes("Error:") && !line.includes("renderWithHooks") && !line.includes("react-stack-bottom-frame")
36048
+ ).map((line) => line.replace(/https?:\/\/[^/\s)]+/g, "").trim()).reverse().join("\n");
36049
+ }
36050
+
36051
+ // src/inspector/pages/performance/Timeline.tsx
35883
36052
  var import_jsx_runtime45 = __toESM(require_jsx_runtime(), 1);
36053
+ var TimelineContainer = styled29("div")`
36054
+ position: relative;
36055
+ display: flex;
36056
+ flex-direction: column;
36057
+ background-color: var(--j-foreground);
36058
+ border: 1px solid var(--j-border-color);
36059
+ border-radius: var(--j-radius-sm);
36060
+ overflow: hidden;
36061
+ `;
36062
+ var TimelineTrack = styled29("div")`
36063
+ position: relative;
36064
+ height: 48px;
36065
+ background-color: var(--j-background);
36066
+ cursor: crosshair;
36067
+ user-select: none;
36068
+ `;
36069
+ var TimeMarker = styled29("div")`
36070
+ position: absolute;
36071
+ font-size: 0.5rem;
36072
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
36073
+ color: var(--j-text-color);
36074
+ padding: 2px 4px;
36075
+ white-space: nowrap;
36076
+
36077
+ @media (prefers-color-scheme: dark) {
36078
+ color: var(--j-neutral-500);
36079
+ }
36080
+
36081
+ &::after {
36082
+ content: "";
36083
+ position: absolute;
36084
+ left: 0;
36085
+ top: 100%;
36086
+ width: 1px;
36087
+ height: 32px;
36088
+ background-color: var(--j-border-color);
36089
+ }
36090
+ `;
36091
+ var TimelineBars = styled29("div")`
36092
+ position: absolute;
36093
+ top: 16px;
36094
+ left: 0;
36095
+ right: 0;
36096
+ bottom: 0;
36097
+ pointer-events: none;
36098
+ `;
36099
+ var TimelineBar = styled29("div")`
36100
+ position: absolute;
36101
+ border-radius: 1px;
36102
+ min-width: 2px;
36103
+ `;
36104
+ var TimelineSelection = styled29("div")`
36105
+ position: absolute;
36106
+ top: 0;
36107
+ bottom: 0;
36108
+ background-color: var(--j-primary-color);
36109
+ opacity: 0.2;
36110
+ cursor: grab;
36111
+ pointer-events: auto;
36112
+
36113
+ &:active {
36114
+ cursor: grabbing;
36115
+ }
36116
+ `;
36117
+ var TimelineSelectionHandle = styled29("div")`
36118
+ position: absolute;
36119
+ top: 0;
36120
+ bottom: 0;
36121
+ width: 2px;
36122
+ background-color: var(--j-primary-color);
36123
+ cursor: ew-resize;
36124
+ pointer-events: auto;
36125
+
36126
+ &::after {
36127
+ content: "";
36128
+ position: absolute;
36129
+ top: 50%;
36130
+ left: 50%;
36131
+ transform: translate(-50%, -50%);
36132
+ width: 8px;
36133
+ height: 16px;
36134
+ background-color: var(--j-primary-color);
36135
+ border-radius: 2px;
36136
+ }
36137
+ `;
36138
+ var ClearSelectionButton = styled29("button")`
36139
+ position: absolute;
36140
+ top: 4px;
36141
+ right: 4px;
36142
+ display: flex;
36143
+ align-items: center;
36144
+ gap: 4px;
36145
+ padding: 2px 6px;
36146
+ font-size: 0.5rem;
36147
+ background-color: var(--j-foreground);
36148
+ border: 1px solid var(--j-border-color);
36149
+ border-radius: var(--j-radius-sm);
36150
+ cursor: pointer;
36151
+ color: var(--j-neutral-500);
36152
+ z-index: 10;
36153
+
36154
+ &:hover {
36155
+ background-color: var(--j-background);
36156
+ color: var(--j-text-color);
36157
+ }
36158
+ `;
36159
+ function Timeline({
36160
+ entries,
36161
+ timeRange,
36162
+ selection,
36163
+ onSelectionChange
36164
+ }) {
36165
+ const trackRef = (0, import_react32.useRef)(null);
36166
+ const [dragMode, setDragMode] = (0, import_react32.useState)(null);
36167
+ const [dragStartTime, setDragStartTime] = (0, import_react32.useState)(null);
36168
+ const [dragCurrentTime, setDragCurrentTime] = (0, import_react32.useState)(null);
36169
+ const [dragInitialSelection, setDragInitialSelection] = (0, import_react32.useState)(null);
36170
+ const duration = timeRange.max - timeRange.min;
36171
+ const timeMarkers = (0, import_react32.useMemo)(() => {
36172
+ const markers = [];
36173
+ if (duration <= 0) return markers;
36174
+ const maxMarkers = 5;
36175
+ const minInterval = duration / maxMarkers;
36176
+ const magnitude = Math.pow(10, Math.floor(Math.log10(minInterval)));
36177
+ const normalized = minInterval / magnitude;
36178
+ let niceMultiplier;
36179
+ if (normalized <= 1) niceMultiplier = 1;
36180
+ else if (normalized <= 2) niceMultiplier = 2;
36181
+ else if (normalized <= 5) niceMultiplier = 5;
36182
+ else niceMultiplier = 10;
36183
+ const interval = niceMultiplier * magnitude;
36184
+ const startMarker = Math.ceil(timeRange.min / interval) * interval;
36185
+ for (let time = startMarker; time <= timeRange.max; time += interval) {
36186
+ const position = (time - timeRange.min) / duration * 100;
36187
+ markers.push({
36188
+ time,
36189
+ label: formatDuration(time),
36190
+ position
36191
+ });
36192
+ }
36193
+ return markers;
36194
+ }, [timeRange, duration]);
36195
+ const getTimeFromPosition = (clientX) => {
36196
+ if (!trackRef.current) return 0;
36197
+ const rect = trackRef.current.getBoundingClientRect();
36198
+ const position = Math.max(
36199
+ 0,
36200
+ Math.min(1, (clientX - rect.left) / rect.width)
36201
+ );
36202
+ return timeRange.min + position * duration;
36203
+ };
36204
+ const handleTrackMouseDown = (e) => {
36205
+ const time = getTimeFromPosition(e.clientX);
36206
+ setDragMode("creating");
36207
+ setDragStartTime(time);
36208
+ setDragCurrentTime(time);
36209
+ };
36210
+ const handleSelectionMouseDown = (e) => {
36211
+ e.stopPropagation();
36212
+ if (!selection) return;
36213
+ const time = getTimeFromPosition(e.clientX);
36214
+ setDragMode("moving");
36215
+ setDragStartTime(time);
36216
+ setDragCurrentTime(time);
36217
+ setDragInitialSelection(selection);
36218
+ };
36219
+ const handleLeftHandleMouseDown = (e) => {
36220
+ e.stopPropagation();
36221
+ if (!selection) return;
36222
+ setDragMode("resizing-left");
36223
+ setDragStartTime(selection[0]);
36224
+ setDragCurrentTime(selection[0]);
36225
+ setDragInitialSelection(selection);
36226
+ };
36227
+ const handleRightHandleMouseDown = (e) => {
36228
+ e.stopPropagation();
36229
+ if (!selection) return;
36230
+ setDragMode("resizing-right");
36231
+ setDragStartTime(selection[1]);
36232
+ setDragCurrentTime(selection[1]);
36233
+ setDragInitialSelection(selection);
36234
+ };
36235
+ (0, import_react32.useEffect)(() => {
36236
+ if (!dragMode) return;
36237
+ const handleMouseMove = (e) => {
36238
+ const time = getTimeFromPosition(e.clientX);
36239
+ setDragCurrentTime(time);
36240
+ };
36241
+ const handleMouseUp = () => {
36242
+ if (dragMode === "creating" && dragStartTime !== null && dragCurrentTime !== null) {
36243
+ const start = Math.min(dragStartTime, dragCurrentTime);
36244
+ const end = Math.max(dragStartTime, dragCurrentTime);
36245
+ if ((end - start) / duration > 0.01) {
36246
+ onSelectionChange([start, end]);
36247
+ }
36248
+ } else if (dragMode === "moving" && dragInitialSelection && dragStartTime !== null && dragCurrentTime !== null) {
36249
+ const delta = dragCurrentTime - dragStartTime;
36250
+ const selectionWidth2 = dragInitialSelection[1] - dragInitialSelection[0];
36251
+ let newStart = dragInitialSelection[0] + delta;
36252
+ let newEnd = dragInitialSelection[1] + delta;
36253
+ if (newStart < timeRange.min) {
36254
+ newStart = timeRange.min;
36255
+ newEnd = timeRange.min + selectionWidth2;
36256
+ }
36257
+ if (newEnd > timeRange.max) {
36258
+ newEnd = timeRange.max;
36259
+ newStart = timeRange.max - selectionWidth2;
36260
+ }
36261
+ onSelectionChange([newStart, newEnd]);
36262
+ } else if (dragMode === "resizing-left" && dragInitialSelection && dragCurrentTime !== null) {
36263
+ const newStart = Math.min(
36264
+ dragCurrentTime,
36265
+ dragInitialSelection[1] - duration * 0.01
36266
+ );
36267
+ onSelectionChange([
36268
+ Math.max(timeRange.min, newStart),
36269
+ dragInitialSelection[1]
36270
+ ]);
36271
+ } else if (dragMode === "resizing-right" && dragInitialSelection && dragCurrentTime !== null) {
36272
+ const newEnd = Math.max(
36273
+ dragCurrentTime,
36274
+ dragInitialSelection[0] + duration * 0.01
36275
+ );
36276
+ onSelectionChange([
36277
+ dragInitialSelection[0],
36278
+ Math.min(timeRange.max, newEnd)
36279
+ ]);
36280
+ }
36281
+ setDragMode(null);
36282
+ setDragStartTime(null);
36283
+ setDragCurrentTime(null);
36284
+ setDragInitialSelection(null);
36285
+ };
36286
+ window.addEventListener("mousemove", handleMouseMove);
36287
+ window.addEventListener("mouseup", handleMouseUp);
36288
+ return () => {
36289
+ window.removeEventListener("mousemove", handleMouseMove);
36290
+ window.removeEventListener("mouseup", handleMouseUp);
36291
+ };
36292
+ }, [
36293
+ dragMode,
36294
+ dragStartTime,
36295
+ dragCurrentTime,
36296
+ dragInitialSelection,
36297
+ duration,
36298
+ timeRange,
36299
+ onSelectionChange
36300
+ ]);
36301
+ const laneAssignments = (0, import_react32.useMemo)(() => {
36302
+ const now = performance.now();
36303
+ const barHeight = 3;
36304
+ const barGap = 1;
36305
+ const maxLanes = 8;
36306
+ const sortedEntries = [...entries].sort(
36307
+ (a, b) => a.startTime - b.startTime
36308
+ );
36309
+ const laneEndTimes = Array(maxLanes).fill(0);
36310
+ const assignments = /* @__PURE__ */ new Map();
36311
+ for (const entry of sortedEntries) {
36312
+ const entryEnd = entry.endTime ?? now;
36313
+ let assignedLane = laneEndTimes.findIndex(
36314
+ (endTime) => entry.startTime >= endTime
36315
+ );
36316
+ if (assignedLane === -1) {
36317
+ const earliestEnd = Math.min(...laneEndTimes);
36318
+ assignedLane = laneEndTimes.indexOf(earliestEnd);
36319
+ }
36320
+ laneEndTimes[assignedLane] = entryEnd;
36321
+ assignments.set(entry.uuid, assignedLane * (barHeight + barGap));
36322
+ }
36323
+ return assignments;
36324
+ }, [entries]);
36325
+ const getBarStyle = (entry) => {
36326
+ const now = performance.now();
36327
+ const start = entry.startTime;
36328
+ const end = entry.endTime ?? now;
36329
+ const left = (start - timeRange.min) / duration * 100;
36330
+ const width = Math.max(0.5, (end - start) / duration * 100);
36331
+ const color = entry.status === "pending" ? "var(--j-warning-color)" : entry.status === "error" ? "var(--j-error-color)" : "var(--j-success-color)";
36332
+ const top = laneAssignments.get(entry.uuid) ?? 0;
36333
+ return {
36334
+ left: `${left}%`,
36335
+ width: `${width}%`,
36336
+ backgroundColor: color,
36337
+ top: `${top}px`,
36338
+ height: "3px"
36339
+ };
36340
+ };
36341
+ const currentSelection = (0, import_react32.useMemo)(() => {
36342
+ if (dragMode === "creating" && dragStartTime !== null && dragCurrentTime !== null) {
36343
+ return [
36344
+ Math.min(dragStartTime, dragCurrentTime),
36345
+ Math.max(dragStartTime, dragCurrentTime)
36346
+ ];
36347
+ }
36348
+ if (dragMode === "moving" && dragInitialSelection && dragStartTime !== null && dragCurrentTime !== null) {
36349
+ const delta = dragCurrentTime - dragStartTime;
36350
+ const selectionWidth2 = dragInitialSelection[1] - dragInitialSelection[0];
36351
+ let newStart = dragInitialSelection[0] + delta;
36352
+ let newEnd = dragInitialSelection[1] + delta;
36353
+ if (newStart < timeRange.min) {
36354
+ newStart = timeRange.min;
36355
+ newEnd = timeRange.min + selectionWidth2;
36356
+ }
36357
+ if (newEnd > timeRange.max) {
36358
+ newEnd = timeRange.max;
36359
+ newStart = timeRange.max - selectionWidth2;
36360
+ }
36361
+ return [newStart, newEnd];
36362
+ }
36363
+ if (dragMode === "resizing-left" && dragInitialSelection && dragCurrentTime !== null) {
36364
+ const newStart = Math.max(
36365
+ timeRange.min,
36366
+ Math.min(dragCurrentTime, dragInitialSelection[1] - duration * 0.01)
36367
+ );
36368
+ return [newStart, dragInitialSelection[1]];
36369
+ }
36370
+ if (dragMode === "resizing-right" && dragInitialSelection && dragCurrentTime !== null) {
36371
+ const newEnd = Math.min(
36372
+ timeRange.max,
36373
+ Math.max(dragCurrentTime, dragInitialSelection[0] + duration * 0.01)
36374
+ );
36375
+ return [dragInitialSelection[0], newEnd];
36376
+ }
36377
+ return selection;
36378
+ }, [
36379
+ dragMode,
36380
+ dragStartTime,
36381
+ dragCurrentTime,
36382
+ dragInitialSelection,
36383
+ selection,
36384
+ timeRange,
36385
+ duration
36386
+ ]);
36387
+ const selectionLeft = currentSelection ? (currentSelection[0] - timeRange.min) / duration * 100 : 0;
36388
+ const selectionWidth = currentSelection ? (currentSelection[1] - currentSelection[0]) / duration * 100 : 0;
36389
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(TimelineContainer, { children: [
36390
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(TimelineTrack, { ref: trackRef, onMouseDown: handleTrackMouseDown, children: [
36391
+ timeMarkers.map((marker) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TimeMarker, { style: { left: `${marker.position}%` }, children: marker.label }, marker.time)),
36392
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TimelineBars, { children: entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TimelineBar, { style: getBarStyle(entry) }, entry.uuid)) }),
36393
+ currentSelection && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
36394
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
36395
+ TimelineSelection,
36396
+ {
36397
+ style: {
36398
+ left: `${selectionLeft}%`,
36399
+ width: `${selectionWidth}%`
36400
+ },
36401
+ onMouseDown: handleSelectionMouseDown
36402
+ }
36403
+ ),
36404
+ !dragMode && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
36405
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
36406
+ TimelineSelectionHandle,
36407
+ {
36408
+ style: { left: `${selectionLeft}%` },
36409
+ onMouseDown: handleLeftHandleMouseDown
36410
+ }
36411
+ ),
36412
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
36413
+ TimelineSelectionHandle,
36414
+ {
36415
+ style: { left: `${selectionLeft + selectionWidth}%` },
36416
+ onMouseDown: handleRightHandleMouseDown
36417
+ }
36418
+ )
36419
+ ] })
36420
+ ] })
36421
+ ] }),
36422
+ currentSelection && !dragMode && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
36423
+ ClearSelectionButton,
36424
+ {
36425
+ onClick: (e) => {
36426
+ e.stopPropagation();
36427
+ onSelectionChange(null);
36428
+ },
36429
+ children: "Clear selection"
36430
+ }
36431
+ )
36432
+ ] });
36433
+ }
36434
+
36435
+ // src/inspector/pages/performance/SubscriptionRow.tsx
36436
+ import { styled as styled30 } from "goober";
36437
+ var import_jsx_runtime46 = __toESM(require_jsx_runtime(), 1);
36438
+ var RowWrapper = styled30("div")`
36439
+ display: grid;
36440
+ grid-template-columns: subgrid;
36441
+ grid-column: 1 / -1;
36442
+ position: relative;
36443
+ cursor: pointer;
36444
+
36445
+ &:hover,
36446
+ &:focus {
36447
+ background-color: var(--j-foreground);
36448
+ outline: none;
36449
+ }
36450
+
36451
+ &:focus-visible {
36452
+ outline: 2px solid var(--j-primary-color);
36453
+ outline-offset: -2px;
36454
+ }
36455
+
36456
+ &[data-expanded="true"] {
36457
+ background-color: var(--j-foreground);
36458
+ }
36459
+ `;
36460
+ var TimeBar = styled30("div")`
36461
+ position: absolute;
36462
+ bottom: 0;
36463
+ height: 4px;
36464
+ transition: transform 0.15s ease;
36465
+ z-index: 1;
36466
+ container-type: inline-size;
36467
+
36468
+ .row-wrapper:hover &, [data-expanded="true"] & {
36469
+ transform: scaleY(4);
36470
+
36471
+ .time-label {
36472
+ opacity: 1;
36473
+ }
36474
+ }
36475
+
36476
+ &[data-status="pending"] {
36477
+ animation: pulse 1.5s ease-in-out infinite;
36478
+ }
36479
+
36480
+ @keyframes pulse {
36481
+ 0%,
36482
+ 100% {
36483
+ opacity: 1;
36484
+ }
36485
+ 50% {
36486
+ opacity: 0.5;
36487
+ }
36488
+ }
36489
+ `;
36490
+ var TimeLabel = styled30("span")`
36491
+ position: absolute;
36492
+ top: 50%;
36493
+ transform: translateY(-50%) scaleY(0.25);
36494
+ font-size: 0.5rem;
36495
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
36496
+ color: white;
36497
+ white-space: nowrap;
36498
+ opacity: 0;
36499
+ transition: opacity 0.15s ease;
36500
+ pointer-events: none;
36501
+ left: 4px;
36502
+ --time-label-overflow-color: black;
36503
+
36504
+ @media (prefers-color-scheme: dark) {
36505
+ --time-label-overflow-color: white;
36506
+ }
36507
+
36508
+ @container (max-width: 50px) {
36509
+ color: var(--time-label-overflow-color);
36510
+ left: 100%;
36511
+ margin-left: 4px;
36512
+ }
36513
+
36514
+ [data-near-edge="true"] & {
36515
+ @container (max-width: 50px) {
36516
+ left: auto;
36517
+ right: 100%;
36518
+ margin-left: 0;
36519
+ margin-right: 4px;
36520
+ }
36521
+ }
36522
+ `;
36523
+ var Cell = styled30("div")`
36524
+ padding: 0.5rem;
36525
+ padding-bottom: 0.75rem;
36526
+ font-size: 0.625rem;
36527
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
36528
+ border-bottom: 1px solid var(--j-border-color);
36529
+ overflow: hidden;
36530
+ text-overflow: ellipsis;
36531
+ white-space: nowrap;
36532
+
36533
+ &[data-clickable="true"] {
36534
+ cursor: pointer;
36535
+ color: var(--j-link-color);
36536
+ &:hover {
36537
+ text-decoration: underline;
36538
+ }
36539
+ }
36540
+ `;
36541
+ var StatusBadge = styled30("span")`
36542
+ display: inline-flex;
36543
+ align-items: center;
36544
+ gap: 0.25rem;
36545
+ padding: 0.125rem 0.375rem;
36546
+ border-radius: 0.25rem;
36547
+ font-size: 0.625rem;
36548
+
36549
+ &[data-status="pending"] {
36550
+ background-color: var(--j-warning-bg);
36551
+ color: var(--j-warning-color);
36552
+ }
36553
+ &[data-status="loaded"] {
36554
+ background-color: var(--j-success-bg);
36555
+ color: var(--j-success-color);
36556
+ }
36557
+ &[data-status="error"] {
36558
+ background-color: var(--j-error-bg);
36559
+ color: var(--j-error-color);
36560
+ }
36561
+ `;
36562
+ var PendingDot = styled30("span")`
36563
+ display: inline-block;
36564
+ width: 8px;
36565
+ height: 8px;
36566
+ border-radius: 50%;
36567
+ background-color: var(--j-warning-color);
36568
+ animation: pendingPulse 1.5s ease-in-out infinite;
36569
+
36570
+ @keyframes pendingPulse {
36571
+ 0%,
36572
+ 100% {
36573
+ opacity: 1;
36574
+ }
36575
+ 50% {
36576
+ opacity: 0.4;
36577
+ }
36578
+ }
36579
+ `;
36580
+ function SubscriptionRow({
36581
+ entry,
36582
+ isSelected,
36583
+ onSelect,
36584
+ barLeft,
36585
+ barWidth,
36586
+ barColor
36587
+ }) {
36588
+ const handleKeyDown = (e) => {
36589
+ if (e.key === "Enter" || e.key === " ") {
36590
+ e.preventDefault();
36591
+ onSelect();
36592
+ }
36593
+ };
36594
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
36595
+ RowWrapper,
36596
+ {
36597
+ className: "row-wrapper",
36598
+ "data-expanded": isSelected,
36599
+ onClick: onSelect,
36600
+ onKeyDown: handleKeyDown,
36601
+ tabIndex: 0,
36602
+ role: "button",
36603
+ "aria-label": `View details for ${entry.source} ${entry.id}`,
36604
+ children: [
36605
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Cell, { children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(StatusBadge, { "data-status": entry.status, children: entry.source }) }),
36606
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Cell, { children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
36607
+ "div",
36608
+ {
36609
+ style: {
36610
+ display: "flex",
36611
+ flexDirection: "column",
36612
+ gap: "0.125rem"
36613
+ },
36614
+ children: [
36615
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { children: entry.id }),
36616
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { style: { color: "var(--j-neutral-500)" }, children: entry.resolve })
36617
+ ]
36618
+ }
36619
+ ) }),
36620
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Cell, { children: getCallerLocation(entry.callerStack) ?? "-" }),
36621
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Cell, { children: entry.duration !== void 0 ? entry.duration === 0 ? "\u26A1 cached" : formatDuration(entry.duration) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(PendingDot, {}) }),
36622
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
36623
+ TimeBar,
36624
+ {
36625
+ className: "time-bar",
36626
+ "data-status": entry.status,
36627
+ "data-near-edge": parseFloat(barLeft) + parseFloat(barWidth) > 85,
36628
+ style: {
36629
+ left: barLeft,
36630
+ width: barWidth,
36631
+ backgroundColor: barColor
36632
+ },
36633
+ children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(TimeLabel, { className: "time-label", children: entry.duration === 0 ? "\u26A1 cached" : entry.duration ? formatDuration(entry.duration) : "-" })
36634
+ }
36635
+ )
36636
+ ]
36637
+ }
36638
+ );
36639
+ }
36640
+
36641
+ // src/inspector/pages/performance/SubscriptionDetailPanel.tsx
36642
+ import { styled as styled31 } from "goober";
36643
+ var import_jsx_runtime47 = __toESM(require_jsx_runtime(), 1);
36644
+ var DetailPanel = styled31("div")`
36645
+ width: 320px;
36646
+ flex-shrink: 0;
36647
+ padding: 0.75rem 1rem;
36648
+ background-color: var(--j-foreground);
36649
+ border: 1px solid var(--j-border-color);
36650
+ border-radius: var(--j-radius-sm);
36651
+ overflow-y: auto;
36652
+ position: relative;
36653
+ `;
36654
+ var CloseButton2 = styled31("button")`
36655
+ position: absolute;
36656
+ top: 0.5rem;
36657
+ right: 0.5rem;
36658
+ display: flex;
36659
+ align-items: center;
36660
+ justify-content: center;
36661
+ width: 18px;
36662
+ height: 18px;
36663
+ padding: 0;
36664
+ background: none;
36665
+ border: none;
36666
+ border-radius: var(--j-radius-sm);
36667
+ cursor: pointer;
36668
+ color: var(--j-neutral-500);
36669
+
36670
+ &:hover {
36671
+ background-color: var(--j-background);
36672
+ color: var(--j-text-color);
36673
+ }
36674
+
36675
+ &:focus-visible {
36676
+ outline: 2px solid var(--j-primary-color);
36677
+ outline-offset: -2px;
36678
+ }
36679
+ `;
36680
+ var DetailsGrid = styled31("div")`
36681
+ display: grid;
36682
+ grid-template-columns: auto 1fr;
36683
+ gap: 0.5rem 1rem;
36684
+ font-size: 0.625rem;
36685
+ `;
36686
+ var DetailLabel = styled31("span")`
36687
+ color: var(--j-neutral-500);
36688
+ font-weight: 500;
36689
+ `;
36690
+ var DetailValue = styled31("span")`
36691
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
36692
+ color: var(--j-text-color);
36693
+ `;
36694
+ var Pre = styled31("pre")`
36695
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
36696
+ font-size: 0.625rem;
36697
+ color: var(--j-text-color);
36698
+ margin: 0;
36699
+ white-space: pre-wrap;
36700
+ word-break: break-all;
36701
+ max-height: 200px;
36702
+ overflow-y: auto;
36703
+ background-color: var(--j-background);
36704
+ padding: 0.5rem;
36705
+ border-radius: var(--j-radius-sm);
36706
+ `;
36707
+ var StatusBadge2 = styled31("span")`
36708
+ display: inline-flex;
36709
+ align-items: center;
36710
+ gap: 0.25rem;
36711
+ padding: 0.125rem 0.375rem;
36712
+ border-radius: 0.25rem;
36713
+ font-size: 0.625rem;
36714
+
36715
+ &[data-status="pending"] {
36716
+ background-color: var(--j-warning-bg);
36717
+ color: var(--j-warning-color);
36718
+ }
36719
+ &[data-status="loaded"] {
36720
+ background-color: var(--j-success-bg);
36721
+ color: var(--j-success-color);
36722
+ }
36723
+ &[data-status="error"] {
36724
+ background-color: var(--j-error-bg);
36725
+ color: var(--j-error-color);
36726
+ }
36727
+ `;
36728
+ function SubscriptionDetailPanel({
36729
+ entry,
36730
+ onNavigate,
36731
+ onClose
36732
+ }) {
36733
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(DetailPanel, { children: [
36734
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(CloseButton2, { onClick: onClose, "aria-label": "Close detail panel", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
36735
+ "svg",
36736
+ {
36737
+ width: "10",
36738
+ height: "10",
36739
+ viewBox: "0 0 14 14",
36740
+ fill: "none",
36741
+ xmlns: "http://www.w3.org/2000/svg",
36742
+ children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
36743
+ "path",
36744
+ {
36745
+ d: "M1 1L13 13M1 13L13 1",
36746
+ stroke: "currentColor",
36747
+ strokeWidth: "2",
36748
+ strokeLinecap: "round"
36749
+ }
36750
+ )
36751
+ }
36752
+ ) }),
36753
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(DetailsGrid, { children: [
36754
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(DetailLabel, { children: "Source" }),
36755
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(DetailValue, { children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(StatusBadge2, { "data-status": entry.status, children: entry.source }) }),
36756
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(DetailLabel, { children: "CoValue" }),
36757
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(DetailValue, { children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
36758
+ "button",
36759
+ {
36760
+ title: "Click to navigate to CoValue",
36761
+ onClick: () => onNavigate(entry.id),
36762
+ style: {
36763
+ color: "var(--j-link-color)",
36764
+ cursor: "pointer",
36765
+ background: "none",
36766
+ border: "none",
36767
+ padding: 0,
36768
+ font: "inherit"
36769
+ },
36770
+ children: entry.id
36771
+ }
36772
+ ) }),
36773
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(DetailLabel, { children: "Time" }),
36774
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(DetailValue, { children: [
36775
+ formatTime(entry.startTime),
36776
+ " -",
36777
+ " ",
36778
+ entry.duration !== void 0 ? formatTime(entry.startTime + entry.duration) : "Pending..."
36779
+ ] }),
36780
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(DetailLabel, { children: "Duration" }),
36781
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(DetailValue, { children: entry.duration !== void 0 ? formatDuration(entry.duration) : "Pending..." }),
36782
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(DetailLabel, { children: "Resolve Query" }),
36783
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Pre, { children: JSON.stringify(JSON.parse(entry.resolve), null, 2) }),
36784
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(DetailLabel, { children: "Stack Trace" }),
36785
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Pre, { children: getCallerStack(entry.callerStack) ?? "No stack trace available" })
36786
+ ] })
36787
+ ] });
36788
+ }
36789
+
36790
+ // src/inspector/pages/performance/usePerformanceEntries.ts
36791
+ var import_react33 = __toESM(require_react(), 1);
36792
+ function usePerformanceEntries() {
36793
+ const [entries, setEntries] = (0, import_react33.useState)([]);
36794
+ (0, import_react33.useEffect)(() => {
36795
+ const entriesByUuid = /* @__PURE__ */ new Map();
36796
+ const handlePerformanceEntries = (entries2) => {
36797
+ for (const mark of entries2) {
36798
+ const detail = mark.detail;
36799
+ if (detail?.type !== "jazz-subscription") continue;
36800
+ const prevEntry = entriesByUuid.get(detail.uuid);
36801
+ if (mark.entryType === "mark" && prevEntry) continue;
36802
+ entriesByUuid.set(detail.uuid, {
36803
+ uuid: detail.uuid,
36804
+ id: detail.id,
36805
+ source: detail.source,
36806
+ resolve: JSON.stringify(detail.resolve),
36807
+ status: detail.status,
36808
+ startTime: mark.startTime,
36809
+ callerStack: detail.callerStack ?? prevEntry?.callerStack,
36810
+ duration: mark.entryType === "mark" ? void 0 : mark.duration,
36811
+ endTime: mark.startTime + mark.duration,
36812
+ errorType: detail.errorType
36813
+ });
36814
+ }
36815
+ };
36816
+ handlePerformanceEntries(performance.getEntriesByType("mark"));
36817
+ handlePerformanceEntries(performance.getEntriesByType("measure"));
36818
+ setEntries(Array.from(entriesByUuid.values()));
36819
+ const observer = new PerformanceObserver((list) => {
36820
+ handlePerformanceEntries(list.getEntries());
36821
+ setEntries(Array.from(entriesByUuid.values()));
36822
+ });
36823
+ observer.observe({ entryTypes: ["mark", "measure"] });
36824
+ return () => observer.disconnect();
36825
+ }, []);
36826
+ return entries;
36827
+ }
36828
+
36829
+ // src/inspector/pages/performance/PerformancePage.tsx
36830
+ var import_jsx_runtime48 = __toESM(require_jsx_runtime(), 1);
36831
+ import { SubscriptionScope } from "jazz-tools";
36832
+ var Container2 = styled32("div")`
36833
+ display: flex;
36834
+ flex-direction: column;
36835
+ gap: 0.5rem;
36836
+ padding: 1rem;
36837
+ height: 100%;
36838
+ min-height: 0;
36839
+ `;
36840
+ var MainLayout = styled32("div")`
36841
+ display: flex;
36842
+ flex: 1;
36843
+ min-height: 0;
36844
+ gap: 1rem;
36845
+ `;
36846
+ var ListPanel = styled32("div")`
36847
+ flex: 1;
36848
+ min-width: 0;
36849
+ display: flex;
36850
+ flex-direction: column;
36851
+ `;
36852
+ var Grid2 = styled32("div")`
36853
+ display: grid;
36854
+ grid-template-columns:
36855
+ minmax(100px, 150px)
36856
+ minmax(150px, 1fr)
36857
+ minmax(100px, 200px)
36858
+ 80px;
36859
+ grid-template-rows: min-content;
36860
+ overflow-y: auto;
36861
+ overflow-x: hidden;
36862
+ flex: 1;
36863
+ min-height: 0;
36864
+ position: relative;
36865
+ `;
36866
+ var HeaderCell = styled32("div")`
36867
+ padding: 0.5rem;
36868
+ font-size: 0.625rem;
36869
+ font-weight: 600;
36870
+ color: var(--j-neutral-500);
36871
+ border-bottom: 1px solid var(--j-border-color);
36872
+ text-transform: uppercase;
36873
+ letter-spacing: 0.05em;
36874
+ `;
36875
+ var EmptyState = styled32("div")`
36876
+ text-align: center;
36877
+ padding: 2rem;
36878
+ color: var(--j-neutral-500);
36879
+ font-size: 0.875rem;
36880
+ `;
36881
+ function PerformancePage({ onNavigate, style }) {
36882
+ const entries = usePerformanceEntries();
36883
+ const [selectedRow, setSelectedRow] = (0, import_react34.useState)(null);
36884
+ const [timeSelection, setTimeSelection] = (0, import_react34.useState)(
36885
+ null
36886
+ );
36887
+ const deferredSelection = (0, import_react34.useDeferredValue)(timeSelection);
36888
+ const { setPage } = useRouter();
36889
+ const selectRow = (uuid) => {
36890
+ setSelectedRow((prev) => prev === uuid ? null : uuid);
36891
+ };
36892
+ const sortedEntries = (0, import_react34.useMemo)(() => {
36893
+ return [...entries].sort((a, b) => a.startTime - b.startTime);
36894
+ }, [entries]);
36895
+ const overallTimeRange = (0, import_react34.useMemo)(() => {
36896
+ if (entries.length === 0) return null;
36897
+ const now = performance.now();
36898
+ return {
36899
+ min: Math.min(...entries.map((e) => e.startTime)),
36900
+ max: Math.max(...entries.map((e) => e.endTime ?? now))
36901
+ };
36902
+ }, [entries]);
36903
+ const filteredEntries = (0, import_react34.useMemo)(() => {
36904
+ if (!deferredSelection) return sortedEntries;
36905
+ const [startTime, endTime] = deferredSelection;
36906
+ const now = performance.now();
36907
+ return sortedEntries.filter((entry) => {
36908
+ const entryEnd = entry.endTime ?? now;
36909
+ return entry.startTime <= endTime && entryEnd >= startTime;
36910
+ });
36911
+ }, [sortedEntries, deferredSelection]);
36912
+ const displayRange = deferredSelection ? { min: deferredSelection[0], max: deferredSelection[1] } : overallTimeRange;
36913
+ const getBarProps = (entry) => {
36914
+ const range = (displayRange?.max ?? 1) - (displayRange?.min ?? 0) || 1;
36915
+ const now = performance.now();
36916
+ const clampedStart = Math.max(entry.startTime, displayRange?.min ?? 0);
36917
+ const clampedEnd = Math.min(entry.endTime ?? now, displayRange?.max ?? now);
36918
+ const left = Math.max(
36919
+ 0,
36920
+ (clampedStart - (displayRange?.min ?? 0)) / range * 100
36921
+ );
36922
+ const width = Math.max(0.5, (clampedEnd - clampedStart) / range * 100);
36923
+ const color = entry.status === "pending" ? "var(--j-warning-color)" : entry.status === "error" ? "var(--j-error-color)" : "var(--j-success-color)";
36924
+ return {
36925
+ barLeft: `${left}%`,
36926
+ barWidth: `${width}%`,
36927
+ barColor: color
36928
+ };
36929
+ };
36930
+ const handleNavigateToCoValue = (id) => {
36931
+ setPage(id);
36932
+ onNavigate();
36933
+ };
36934
+ if (!SubscriptionScope.isProfilingEnabled) {
36935
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Container2, { style, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(EmptyState, { children: "Profiling is not enabled in production builds." }) });
36936
+ }
36937
+ if (entries.length === 0) {
36938
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Container2, { style, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(EmptyState, { children: "No subscriptions recorded yet. Interact with your app to see subscription performance data." }) });
36939
+ }
36940
+ const selectedEntry = selectedRow ? filteredEntries.find((e) => e.uuid === selectedRow) : null;
36941
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(Container2, { style, children: [
36942
+ overallTimeRange && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
36943
+ Timeline,
36944
+ {
36945
+ entries: sortedEntries,
36946
+ timeRange: overallTimeRange,
36947
+ selection: timeSelection,
36948
+ onSelectionChange: setTimeSelection
36949
+ }
36950
+ ),
36951
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(MainLayout, { children: [
36952
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ListPanel, { children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(Grid2, { children: [
36953
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(HeaderCell, { children: "Source" }),
36954
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(HeaderCell, { children: "CoValue" }),
36955
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(HeaderCell, { children: "Caller" }),
36956
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(HeaderCell, { children: "Duration" }),
36957
+ filteredEntries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
36958
+ SubscriptionRow,
36959
+ {
36960
+ entry,
36961
+ isSelected: selectedRow === entry.uuid,
36962
+ onSelect: () => selectRow(entry.uuid),
36963
+ ...getBarProps(entry)
36964
+ },
36965
+ entry.uuid
36966
+ ))
36967
+ ] }) }),
36968
+ selectedEntry && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
36969
+ SubscriptionDetailPanel,
36970
+ {
36971
+ entry: selectedEntry,
36972
+ onNavigate: handleNavigateToCoValue,
36973
+ onClose: () => setSelectedRow(null)
36974
+ }
36975
+ )
36976
+ ] })
36977
+ ] });
36978
+ }
36979
+
36980
+ // src/inspector/in-app.tsx
36981
+ var import_jsx_runtime49 = __toESM(require_jsx_runtime(), 1);
36982
+ var STORAGE_KEY3 = "jazz-inspector-tab";
36983
+ function getStoredTab() {
36984
+ try {
36985
+ const stored = localStorage.getItem(STORAGE_KEY3);
36986
+ if (stored === "inspector" || stored === "performance") {
36987
+ return stored;
36988
+ }
36989
+ } catch {
36990
+ }
36991
+ return "inspector";
36992
+ }
35884
36993
  function InspectorInApp({
35885
36994
  position = "right",
35886
36995
  localNode,
35887
36996
  accountId
35888
36997
  }) {
35889
36998
  const [open, setOpen] = useOpenInspector();
36999
+ const [activeTab, setActiveTabState] = (0, import_react35.useState)(getStoredTab);
37000
+ const setActiveTab = (0, import_react35.useCallback)((tab) => {
37001
+ setActiveTabState(tab);
37002
+ try {
37003
+ localStorage.setItem(STORAGE_KEY3, tab);
37004
+ } catch {
37005
+ }
37006
+ }, []);
35890
37007
  if (!open) {
35891
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(InspectorButton, { position, onClick: () => setOpen(true) });
37008
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(InspectorButton, { position, onClick: () => setOpen(true) });
35892
37009
  }
35893
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(NodeProvider, { localNode: localNode ?? null, accountID: accountId ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(InMemoryRouterProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(InspectorContainer, { as: GlobalStyles, style: { zIndex: 999 }, children: [
35894
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
37010
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(NodeProvider, { localNode: localNode ?? null, accountID: accountId ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(InMemoryRouterProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(InspectorContainer, { as: GlobalStyles, style: { zIndex: 999 }, children: [
37011
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
35895
37012
  Header,
35896
37013
  {
35897
- showDeleteLocalData: true,
35898
37014
  showClose: true,
35899
- onClose: () => setOpen(false)
37015
+ onClose: () => setOpen(false),
37016
+ activeTab,
37017
+ onTabChange: setActiveTab
37018
+ }
37019
+ ),
37020
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
37021
+ PageStack,
37022
+ {
37023
+ style: { display: activeTab === "inspector" ? "flex" : "none" },
37024
+ homePage: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(HomePage, { showDeleteLocalData: true })
35900
37025
  }
35901
37026
  ),
35902
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(PageStack, {})
37027
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
37028
+ PerformancePage,
37029
+ {
37030
+ style: { display: activeTab === "performance" ? "flex" : "none" },
37031
+ onNavigate: () => setActiveTab("inspector")
37032
+ }
37033
+ )
35903
37034
  ] }) }) });
35904
37035
  }
35905
- var InspectorContainer = styled29("div")`
37036
+ var InspectorContainer = styled33("div")`
35906
37037
  position: fixed;
35907
37038
  height: 50vh;
35908
37039
  max-height: 800px;
@@ -35921,8 +37052,8 @@ var InspectorContainer = styled29("div")`
35921
37052
  `;
35922
37053
 
35923
37054
  // src/inspector/custom-element.tsx
35924
- var import_jsx_runtime46 = __toESM(require_jsx_runtime(), 1);
35925
- setup(import_react32.default.createElement);
37055
+ var import_jsx_runtime50 = __toESM(require_jsx_runtime(), 1);
37056
+ setup(import_react36.default.createElement);
35926
37057
  var JazzInspectorElement = class extends HTMLElement {
35927
37058
  constructor() {
35928
37059
  super(...arguments);
@@ -35964,7 +37095,7 @@ var JazzInspectorElement = class extends HTMLElement {
35964
37095
  return;
35965
37096
  }
35966
37097
  this.root?.render(
35967
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
37098
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
35968
37099
  InspectorInApp,
35969
37100
  {
35970
37101
  localNode: this.account.$jazz.localNode,
@@ -36090,4 +37221,4 @@ react/cjs/react-jsx-runtime.development.js:
36090
37221
  * LICENSE file in the root directory of this source tree.
36091
37222
  *)
36092
37223
  */
36093
- //# sourceMappingURL=custom-element-5YWVZBWA.js.map
37224
+ //# sourceMappingURL=custom-element-PWRX4VCA.js.map