jazz-tools 0.19.10 → 0.19.12

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 (112) hide show
  1. package/.turbo/turbo-build.log +58 -54
  2. package/CHANGELOG.md +23 -0
  3. package/dist/{chunk-FFEEPZEG.js → chunk-AGF4HEDH.js} +61 -28
  4. package/dist/chunk-AGF4HEDH.js.map +1 -0
  5. package/dist/index.js +1 -1
  6. package/dist/inspector/account-switcher.d.ts +4 -0
  7. package/dist/inspector/account-switcher.d.ts.map +1 -0
  8. package/dist/inspector/chunk-YQNK5Y7B.js +4108 -0
  9. package/dist/inspector/chunk-YQNK5Y7B.js.map +1 -0
  10. package/dist/inspector/contexts/node.d.ts +19 -0
  11. package/dist/inspector/contexts/node.d.ts.map +1 -0
  12. package/dist/inspector/{custom-element-P76EIWEV.js → custom-element-KYV64IOC.js} +1057 -918
  13. package/dist/inspector/custom-element-KYV64IOC.js.map +1 -0
  14. package/dist/inspector/{viewer/new-app.d.ts → in-app.d.ts} +3 -3
  15. package/dist/inspector/in-app.d.ts.map +1 -0
  16. package/dist/inspector/index.d.ts +0 -11
  17. package/dist/inspector/index.d.ts.map +1 -1
  18. package/dist/inspector/index.js +56 -3910
  19. package/dist/inspector/index.js.map +1 -1
  20. package/dist/inspector/pages/home.d.ts +2 -0
  21. package/dist/inspector/pages/home.d.ts.map +1 -0
  22. package/dist/inspector/register-custom-element.js +1 -1
  23. package/dist/inspector/router/context.d.ts +12 -0
  24. package/dist/inspector/router/context.d.ts.map +1 -0
  25. package/dist/inspector/router/hash-router.d.ts +7 -0
  26. package/dist/inspector/router/hash-router.d.ts.map +1 -0
  27. package/dist/inspector/router/in-memory-router.d.ts +7 -0
  28. package/dist/inspector/router/in-memory-router.d.ts.map +1 -0
  29. package/dist/inspector/router/index.d.ts +5 -0
  30. package/dist/inspector/router/index.d.ts.map +1 -0
  31. package/dist/inspector/standalone.d.ts +6 -0
  32. package/dist/inspector/standalone.d.ts.map +1 -0
  33. package/dist/inspector/standalone.js +420 -0
  34. package/dist/inspector/standalone.js.map +1 -0
  35. package/dist/inspector/tests/router/hash-router.test.d.ts +2 -0
  36. package/dist/inspector/tests/router/hash-router.test.d.ts.map +1 -0
  37. package/dist/inspector/tests/router/in-memory-router.test.d.ts +2 -0
  38. package/dist/inspector/tests/router/in-memory-router.test.d.ts.map +1 -0
  39. package/dist/inspector/tests/utils/transactions-changes.test.d.ts +2 -0
  40. package/dist/inspector/tests/utils/transactions-changes.test.d.ts.map +1 -0
  41. package/dist/inspector/ui/modal.d.ts +1 -0
  42. package/dist/inspector/ui/modal.d.ts.map +1 -1
  43. package/dist/inspector/utils/transactions-changes.d.ts +13 -13
  44. package/dist/inspector/utils/transactions-changes.d.ts.map +1 -1
  45. package/dist/inspector/viewer/breadcrumbs.d.ts +1 -7
  46. package/dist/inspector/viewer/breadcrumbs.d.ts.map +1 -1
  47. package/dist/inspector/viewer/header.d.ts +7 -0
  48. package/dist/inspector/viewer/header.d.ts.map +1 -0
  49. package/dist/inspector/viewer/page-stack.d.ts +4 -13
  50. package/dist/inspector/viewer/page-stack.d.ts.map +1 -1
  51. package/dist/inspector/viewer/page.d.ts.map +1 -1
  52. package/dist/react/index.js +4 -1
  53. package/dist/react/index.js.map +1 -1
  54. package/dist/react/provider.d.ts.map +1 -1
  55. package/dist/react-core/index.js +2 -2
  56. package/dist/react-core/index.js.map +1 -1
  57. package/dist/react-native/index.js +4 -1
  58. package/dist/react-native/index.js.map +1 -1
  59. package/dist/react-native-core/index.js +4 -1
  60. package/dist/react-native-core/index.js.map +1 -1
  61. package/dist/react-native-core/provider.d.ts.map +1 -1
  62. package/dist/testing.js +1 -1
  63. package/dist/tools/coValues/account.d.ts +7 -1
  64. package/dist/tools/coValues/account.d.ts.map +1 -1
  65. package/dist/tools/implementation/ContextManager.d.ts.map +1 -1
  66. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +8 -1
  67. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  68. package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
  69. package/dist/tools/subscribe/SubscriptionScope.d.ts +3 -6
  70. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  71. package/dist/tools/testing.d.ts.map +1 -1
  72. package/package.json +9 -4
  73. package/src/inspector/account-switcher.tsx +440 -0
  74. package/src/inspector/contexts/node.tsx +129 -0
  75. package/src/inspector/custom-element.tsx +2 -2
  76. package/src/inspector/in-app.tsx +61 -0
  77. package/src/inspector/index.tsx +2 -22
  78. package/src/inspector/pages/home.tsx +77 -0
  79. package/src/inspector/router/context.ts +21 -0
  80. package/src/inspector/router/hash-router.tsx +128 -0
  81. package/src/inspector/{viewer/use-page-path.ts → router/in-memory-router.tsx} +31 -29
  82. package/src/inspector/router/index.ts +4 -0
  83. package/src/inspector/standalone.tsx +60 -0
  84. package/src/inspector/tests/router/hash-router.test.tsx +847 -0
  85. package/src/inspector/tests/router/in-memory-router.test.tsx +724 -0
  86. package/src/inspector/tests/utils/transactions-changes.test.ts +102 -0
  87. package/src/inspector/ui/icons/add-icon.tsx +3 -3
  88. package/src/inspector/ui/modal.tsx +5 -2
  89. package/src/inspector/utils/history.ts +6 -6
  90. package/src/inspector/utils/transactions-changes.ts +37 -3
  91. package/src/inspector/viewer/breadcrumbs.tsx +5 -11
  92. package/src/inspector/viewer/header.tsx +67 -0
  93. package/src/inspector/viewer/history-view.tsx +13 -13
  94. package/src/inspector/viewer/page-stack.tsx +18 -26
  95. package/src/inspector/viewer/page.tsx +0 -1
  96. package/src/react/provider.tsx +6 -1
  97. package/src/react-core/hooks.ts +2 -2
  98. package/src/react-core/tests/useSuspenseCoState.test.tsx +47 -0
  99. package/src/react-native-core/provider.tsx +6 -1
  100. package/src/tools/coValues/account.ts +13 -2
  101. package/src/tools/implementation/ContextManager.ts +10 -0
  102. package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +8 -1
  103. package/src/tools/subscribe/SubscriptionScope.ts +61 -39
  104. package/src/tools/tests/account.test.ts +11 -4
  105. package/src/tools/tests/schema.resolved.test.ts +3 -3
  106. package/tsup.config.ts +1 -0
  107. package/dist/chunk-FFEEPZEG.js.map +0 -1
  108. package/dist/inspector/custom-element-P76EIWEV.js.map +0 -1
  109. package/dist/inspector/viewer/new-app.d.ts.map +0 -1
  110. package/dist/inspector/viewer/use-page-path.d.ts +0 -10
  111. package/dist/inspector/viewer/use-page-path.d.ts.map +0 -1
  112. package/src/inspector/viewer/new-app.tsx +0 -156
@@ -0,0 +1,77 @@
1
+ import { styled } from "goober";
2
+ import { useNode } from "../contexts/node";
3
+ import { Heading } from "../ui/heading";
4
+ import { Button, Input } from "../ui";
5
+ import { useState } from "react";
6
+ import { CoID, RawCoValue } from "cojson";
7
+ import { useRouter } from "../router";
8
+
9
+ export function HomePage() {
10
+ const { localNode, accountID } = useNode();
11
+ const { path, setPage } = useRouter();
12
+ const [coValueId, setCoValueId] = useState<CoID<RawCoValue> | "">("");
13
+
14
+ if (!localNode || !accountID) {
15
+ return <div>Loading...</div>;
16
+ }
17
+
18
+ const handleCoValueIdSubmit = (e: React.FormEvent) => {
19
+ e.preventDefault();
20
+ if (coValueId) {
21
+ setPage(coValueId);
22
+ }
23
+ setCoValueId("");
24
+ };
25
+
26
+ return (
27
+ <>
28
+ <CenteredForm
29
+ onSubmit={handleCoValueIdSubmit}
30
+ aria-hidden={path.length !== 0}
31
+ >
32
+ <Heading>Jazz CoValue Inspector</Heading>
33
+
34
+ <Input
35
+ label="CoValue ID"
36
+ className="font-mono"
37
+ hideLabel
38
+ placeholder="co_z1234567890abcdef123456789"
39
+ value={coValueId}
40
+ onChange={(e) => setCoValueId(e.target.value as CoID<RawCoValue>)}
41
+ />
42
+
43
+ <Button type="submit" variant="primary">
44
+ Inspect CoValue
45
+ </Button>
46
+
47
+ <OrText>or</OrText>
48
+
49
+ <Button
50
+ variant="secondary"
51
+ onClick={() => {
52
+ setPage(accountID);
53
+ }}
54
+ >
55
+ Inspect my account
56
+ </Button>
57
+ </CenteredForm>
58
+ </>
59
+ );
60
+ }
61
+
62
+ const CenteredForm = styled("form")`
63
+ display: flex;
64
+ flex-direction: column;
65
+ position: relative;
66
+ top: -1.5rem;
67
+ justify-content: center;
68
+ gap: 0.5rem;
69
+ height: 100%;
70
+ width: 100%;
71
+ max-width: 24rem;
72
+ margin: 0 auto;
73
+ `;
74
+
75
+ const OrText = styled("p")`
76
+ text-align: center;
77
+ `;
@@ -0,0 +1,21 @@
1
+ import { CoID, RawCoValue } from "cojson";
2
+ import { PageInfo } from "../viewer/types.js";
3
+ import { createContext, useContext } from "react";
4
+
5
+ export interface Router {
6
+ path: PageInfo[];
7
+ setPage: (coId: CoID<RawCoValue>) => void;
8
+ addPages: (newPages: PageInfo[]) => void;
9
+ goToIndex: (index: number) => void;
10
+ goBack: () => void;
11
+ }
12
+
13
+ export const RouterContext = createContext<Router | null>(null);
14
+
15
+ export function useRouter(): Router {
16
+ const context = useContext(RouterContext);
17
+ if (!context) {
18
+ throw new Error("useRouter must be used within a RouterProvider");
19
+ }
20
+ return context;
21
+ }
@@ -0,0 +1,128 @@
1
+ import React, {
2
+ ReactNode,
3
+ useState,
4
+ useCallback,
5
+ useEffect,
6
+ useMemo,
7
+ } from "react";
8
+ import { Router, RouterContext } from "./context.js";
9
+ import { PageInfo } from "../viewer/types.js";
10
+ import { CoID, RawCoValue } from "cojson";
11
+
12
+ export function HashRouterProvider({
13
+ children,
14
+ defaultPath,
15
+ }: {
16
+ children: ReactNode;
17
+ defaultPath?: PageInfo[];
18
+ }) {
19
+ const [path, setPath] = useState<PageInfo[]>(() => {
20
+ if (typeof window === "undefined") return defaultPath || [];
21
+ const hash = window.location.hash.slice(2); // Remove '#/'
22
+
23
+ const defaultEncoded = encodePathToHash(defaultPath || []);
24
+
25
+ if (defaultPath) {
26
+ window.history.pushState({}, "", `#/${defaultEncoded}`);
27
+ return defaultPath;
28
+ }
29
+
30
+ if (hash) {
31
+ const path = decodePathFromHash(hash);
32
+ return path;
33
+ }
34
+
35
+ window.history.pushState({}, "", `#/${encodePathToHash([])}`);
36
+ return [];
37
+ });
38
+
39
+ const updatePath = useCallback((newPath: PageInfo[]) => {
40
+ setPath(newPath);
41
+ if (typeof window !== "undefined") {
42
+ const hash = encodePathToHash(newPath);
43
+ window.history.pushState({}, "", `#/${hash}`);
44
+ }
45
+ }, []);
46
+
47
+ useEffect(() => {
48
+ if (typeof window === "undefined") return;
49
+
50
+ const handleHashChange = () => {
51
+ const hash = window.location.hash.slice(2);
52
+ const currentPath = encodePathToHash(path);
53
+
54
+ if (hash === currentPath) return;
55
+
56
+ if (hash) {
57
+ try {
58
+ const newPath = decodePathFromHash(hash);
59
+ setPath(newPath);
60
+ } catch (e) {
61
+ console.error("Failed to parse hash:", e);
62
+ }
63
+ } else if (defaultPath) {
64
+ setPath(defaultPath);
65
+ }
66
+ };
67
+
68
+ window.addEventListener("hashchange", handleHashChange);
69
+ return () => window.removeEventListener("hashchange", handleHashChange);
70
+ }, [path, defaultPath]);
71
+
72
+ useEffect(() => {
73
+ if (defaultPath) {
74
+ updatePath(defaultPath);
75
+ }
76
+ }, [defaultPath]);
77
+
78
+ const router: Router = useMemo(() => {
79
+ const addPages = (newPages: PageInfo[]) => {
80
+ updatePath([...path, ...newPages]);
81
+ };
82
+
83
+ const goToIndex = (index: number) => {
84
+ updatePath(path.slice(0, index + 1));
85
+ };
86
+
87
+ const setPage = (coId: CoID<RawCoValue>) => {
88
+ updatePath([{ coId, name: "Root" }]);
89
+ };
90
+
91
+ const goBack = () => {
92
+ updatePath(path.slice(0, path.length - 1));
93
+ };
94
+
95
+ return {
96
+ path,
97
+ addPages,
98
+ goToIndex,
99
+ setPage,
100
+ goBack,
101
+ };
102
+ }, [path, updatePath]);
103
+
104
+ return (
105
+ <RouterContext.Provider value={router}>{children}</RouterContext.Provider>
106
+ );
107
+ }
108
+
109
+ function encodePathToHash(path: PageInfo[]): string {
110
+ return path
111
+ .map((page) => {
112
+ if (page.name && page.name !== "Root") {
113
+ return `${page.coId}:${encodeURIComponent(page.name)}`;
114
+ }
115
+ return page.coId;
116
+ })
117
+ .join("/");
118
+ }
119
+
120
+ function decodePathFromHash(hash: string): PageInfo[] {
121
+ return hash.split("/").map((segment) => {
122
+ const [coId, encodedName] = segment.split(":");
123
+ return {
124
+ coId,
125
+ name: encodedName ? decodeURIComponent(encodedName) : undefined,
126
+ } as PageInfo;
127
+ });
128
+ }
@@ -1,10 +1,17 @@
1
- import { CoID, RawCoValue } from "cojson";
2
- import { useCallback, useEffect, useState } from "react";
3
- import { PageInfo } from "./types.js";
1
+ import { ReactNode, useCallback, useEffect, useMemo, useState } from "react";
2
+ import type { CoID, RawCoValue } from "cojson";
3
+ import { Router, RouterContext } from "./context.js";
4
+ import { PageInfo } from "../viewer/types.js";
4
5
 
5
6
  const STORAGE_KEY = "jazz-inspector-paths";
6
7
 
7
- export function usePagePath(defaultPath?: PageInfo[]) {
8
+ export function InMemoryRouterProvider({
9
+ children,
10
+ defaultPath,
11
+ }: {
12
+ children: ReactNode;
13
+ defaultPath?: PageInfo[];
14
+ }) {
8
15
  const [path, setPath] = useState<PageInfo[]>(() => {
9
16
  if (typeof window === "undefined") return [];
10
17
  const stored = localStorage.getItem(STORAGE_KEY);
@@ -29,38 +36,33 @@ export function usePagePath(defaultPath?: PageInfo[]) {
29
36
  }
30
37
  }, [defaultPath, path, updatePath]);
31
38
 
32
- const addPages = useCallback(
33
- (newPages: PageInfo[]) => {
39
+ const router: Router = useMemo(() => {
40
+ const addPages = (newPages: PageInfo[]) => {
34
41
  updatePath([...path, ...newPages]);
35
- },
36
- [path, updatePath],
37
- );
42
+ };
38
43
 
39
- const goToIndex = useCallback(
40
- (index: number) => {
44
+ const goToIndex = (index: number) => {
41
45
  updatePath(path.slice(0, index + 1));
42
- },
43
- [path, updatePath],
44
- );
46
+ };
45
47
 
46
- const setPage = useCallback(
47
- (coId: CoID<RawCoValue>) => {
48
+ const setPage = (coId: CoID<RawCoValue>) => {
48
49
  updatePath([{ coId, name: "Root" }]);
49
- },
50
- [updatePath],
51
- );
50
+ };
52
51
 
53
- const goBack = useCallback(() => {
54
- if (path.length > 1) {
52
+ const goBack = () => {
55
53
  updatePath(path.slice(0, path.length - 1));
56
- }
54
+ };
55
+
56
+ return {
57
+ path,
58
+ addPages,
59
+ goToIndex,
60
+ setPage,
61
+ goBack,
62
+ };
57
63
  }, [path, updatePath]);
58
64
 
59
- return {
60
- path,
61
- setPage,
62
- addPages,
63
- goToIndex,
64
- goBack,
65
- };
65
+ return (
66
+ <RouterContext.Provider value={router}>{children}</RouterContext.Provider>
67
+ );
66
68
  }
@@ -0,0 +1,4 @@
1
+ export type { Router } from "./context.js";
2
+ export { useRouter } from "./context.js";
3
+ export { InMemoryRouterProvider } from "./in-memory-router.js";
4
+ export { HashRouterProvider } from "./hash-router.js";
@@ -0,0 +1,60 @@
1
+ import React from "react";
2
+ import { HashRouterProvider } from "./router";
3
+ import { setup, styled } from "goober";
4
+ import { NodeContext, NodeProvider } from "./contexts/node";
5
+ import { Header } from "./viewer/header";
6
+ import { GlobalStyles } from "./ui/global-styles";
7
+ import { PageStack } from "./viewer/page-stack";
8
+ import { AccountSwitcher } from "./account-switcher";
9
+
10
+ type InspectorAppProps = {
11
+ defaultSyncServer?: string;
12
+ };
13
+
14
+ setup(React.createElement);
15
+
16
+ export default function InspectorStandalone(props: InspectorAppProps) {
17
+ return (
18
+ <HashRouterProvider>
19
+ <NodeProvider>
20
+ <InspectorContainer as={GlobalStyles}>
21
+ <Header>
22
+ <AccountSwitcher defaultSyncServer={props.defaultSyncServer} />
23
+ </Header>
24
+ <NodeContext.Consumer>
25
+ {({ accountID }) =>
26
+ accountID ? (
27
+ <PageStack />
28
+ ) : (
29
+ <CenteredMessage>
30
+ Select an account to connect to the inspector.
31
+ </CenteredMessage>
32
+ )
33
+ }
34
+ </NodeContext.Consumer>
35
+ </InspectorContainer>
36
+ </NodeProvider>
37
+ </HashRouterProvider>
38
+ );
39
+ }
40
+
41
+ const InspectorContainer = styled("div")`
42
+ height: 100vh;
43
+ overflow: hidden;
44
+ display: flex;
45
+ flex-direction: column;
46
+ color: #44403c; /* text-stone-700 */
47
+ background-color: #fff; /* bg-white */
48
+
49
+ @media (prefers-color-scheme: dark) {
50
+ color: #d6d3d1; /* text-stone-300 */
51
+ background-color: #0c0a09; /* bg-stone-950 */
52
+ }
53
+ `;
54
+
55
+ const CenteredMessage = styled("p")`
56
+ text-align: center;
57
+ margin: 0;
58
+ padding: 1rem;
59
+ color: var(--j-text-color);
60
+ `;