Compare commits

..

12 Commits

Author SHA1 Message Date
Anselm
07ea59fdcb Release 2024-07-12 11:14:15 +01:00
Anselm
932a84a47f Update to Effect 3.5.2 2024-07-12 11:13:41 +01:00
Anselm
34dda7bdbd Release 2024-07-05 11:18:53 +01:00
Anselm
49fa153581 Merge branch 'fix-fs' 2024-07-05 11:17:54 +01:00
Anselm
c80b827775 Release 2024-06-30 16:28:53 +01:00
Anselm Eickhoff
a2bf9f988a Merge pull request #218 from Schniz/fix-mutating-nullable-field 2024-06-30 08:31:57 +01:00
Gal Schlezinger
ac27b2d5c2 jazz-tools: allow to mutate nullable fields into null
when having a co.encoded(Schema.NullOr(Schema.String)), construction
with null works well, but mutating a value into null throws.
This commit fixes it and adds a test that verifies it actually works.
2024-06-30 09:49:15 +03:00
Anselm
c813518fdc Release 2024-06-28 16:27:15 +01:00
Anselm
d5034ed5c3 Provide current res in ProgressiveImg 2024-06-28 16:26:03 +01:00
Anselm
cf2c29a365 Use verce lanalytics & speed insights 2024-06-28 14:54:58 +01:00
Anselm
d948823db6 Add package manager to package.json 2024-06-28 12:08:23 +01:00
Anselm
060ad4630d Resurrect inspector 2024-06-27 16:54:23 +01:00
58 changed files with 4133 additions and 2786 deletions

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
example: ["chat", "pets", "todo"]
example: ["chat", "pets", "todo", "inspector"]
# example: ["twit", "chat", "counter-js-auth0", "pets", "twit", "file-drop", "inspector"]
steps:
@@ -105,7 +105,7 @@ jobs:
needs: build-examples
strategy:
matrix:
example: ["chat", "pets", "todo"]
example: ["chat", "pets", "todo", "inspector"]
# example: ["twit", "chat", "counter-js-auth0", "pets", "twit", "file-drop", "inspector"]
steps:

View File

@@ -1,5 +1,38 @@
# jazz-example-chat
## 0.0.65
### Patch Changes
- Updated dependencies
- cojson@0.7.18
- jazz-react@0.7.18
- jazz-tools@0.7.18
## 0.0.64
### Patch Changes
- Updated dependencies
- cojson@0.7.17
- jazz-react@0.7.17
- jazz-tools@0.7.17
## 0.0.63
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.16
- jazz-react@0.7.16
## 0.0.62
### Patch Changes
- Updated dependencies
- jazz-react@0.7.15
## 0.0.61
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.61",
"version": "0.0.65",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,21 @@
# jazz-example-chat
## 0.0.49
### Patch Changes
- Updated dependencies
- cojson@0.7.18
- cojson-transport-ws@0.7.18
## 0.0.48
### Patch Changes
- Updated dependencies
- cojson@0.7.17
- cojson-transport-ws@0.7.17
## 0.0.47
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "inspector",
"name": "jazz-inspector",
"private": true,
"version": "0.0.47",
"version": "0.0.49",
"type": "module",
"scripts": {
"dev": "vite",
@@ -17,9 +17,9 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"hash-slash": "workspace:*",
"jazz-react": "workspace:*",
"jazz-react-auth-local": "workspace:*",
"cojson": "workspace:*",
"cojson-transport-ws": "workspace:*",
"effect": "^3.5.2",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.2.0",

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -0,0 +1,309 @@
import ReactDOM from "react-dom/client";
import {
RawAccount,
CoID,
RawCoValue,
SessionID,
LocalNode,
AgentSecret,
AccountID,
cojsonInternals,
WasmCrypto,
} from "cojson";
import { clsx } from "clsx";
import { AccountInfo, CoJsonTree, Tag } from "./cojson-tree";
import { useEffect, useState } from "react";
import { createWebSocketPeer } from "cojson-transport-ws";
import { Effect } from "effect";
ReactDOM.createRoot(document.getElementById("root")!).render(<App />);
function App() {
const [accountID, setAccountID] = useState<CoID<RawAccount>>(
localStorage["inspectorAccountID"]
);
const [accountSecret, setAccountSecret] = useState<AgentSecret>(
localStorage["inspectorAccountSecret"]
);
const [coValueId, setCoValueId] = useState<CoID<RawCoValue>>(
window.location.hash.slice(2) as CoID<RawCoValue>
);
useEffect(() => {
window.addEventListener("hashchange", () => {
setCoValueId(window.location.hash.slice(2) as CoID<RawCoValue>);
});
});
const [localNode, setLocalNode] = useState<LocalNode>();
useEffect(() => {
if (!accountID || !accountSecret) return;
WasmCrypto.create().then(async (crypto) => {
const wsPeer = await Effect.runPromise(
createWebSocketPeer({
id: "mesh",
websocket: new WebSocket("wss://mesh.jazz.tools"),
role: "server",
})
);
const node = await LocalNode.withLoadedAccount({
accountID: accountID,
accountSecret: accountSecret,
sessionID: cojsonInternals.newRandomSessionID(accountID),
peersToLoadFrom: [wsPeer],
crypto,
migration: async () => {
console.log("Not running any migration in inspector");
},
});
setLocalNode(node);
});
}, [accountID, accountSecret]);
return (
<div className="flex flex-col items-center w-screen h-screen p-2 gap-2">
<div className="flex gap-2 items-center">
Account
<input
className="border p-2 rounded"
placeholder="Account ID"
value={accountID}
onChange={(e) => {
setAccountID(e.target.value as AccountID);
localStorage["inspectorAccountID"] = e.target.value;
}}
/>
<input
type="password"
className="border p-2 rounded"
placeholder="Account Secret"
value={accountSecret}
onChange={(e) => {
setAccountSecret(e.target.value as AgentSecret);
localStorage["inspectorAccountSecret"] = e.target.value;
}}
/>
{localNode ? (
<AccountInfo accountID={accountID} node={localNode} />
) : (
""
)}
</div>
<div className="flex gap-2 items-center">
CoValue ID
<input
className="border p-2 rounded min-w-[20rem]"
placeholder="CoValue ID"
value={coValueId}
onChange={(e) =>
setCoValueId(e.target.value as CoID<RawCoValue>)
}
/>
</div>
{coValueId && localNode ? (
<Inspect coValueId={coValueId} node={localNode} />
) : null}
</div>
);
}
// function ImageCoValue({ value }: { value: ImageDefinition["_shape"] }) {
// const keys = Object.keys(value);
// const keyIncludingRes = keys.find((key) => key.includes("x"));
// const idToResolve = keyIncludingRes
// ? value[keyIncludingRes as `${number}x${number}`]
// : null;
// if (!idToResolve) return <div>Can't find image</div>;
// const [blobURL, setBlobURL] = useState<string>();
// useEffect(() => {
// })
// return (
// <img
// src={image?.blobURL || value.placeholderDataURL}
// alt="placeholder"
// />
// );
// }
function Inspect({
coValueId,
node,
}: {
coValueId: CoID<RawCoValue>;
node: LocalNode;
}) {
const [coValue, setCoValue] = useState<RawCoValue | "unavailable">();
useEffect(() => {
return node.subscribe(coValueId, (coValue) => {
setCoValue(coValue);
});
}, [node, coValueId]);
if (coValue === "unavailable") {
return <div>Unavailable</div>;
}
const values = coValue?.toJSON() || {};
const isImage =
typeof values === "object" && "placeholderDataURL" in values;
const isGroup = coValue?.core.header.ruleset?.type === "group";
const entires = Object.entries(values as any) as [string, string][];
const onlyCoValues = entires.filter(([key]) => key.startsWith("co_"));
let title = "";
if (isImage) {
title = "Image";
} else if (isGroup) {
title = "Group";
}
return (
<div className="mb-auto">
<h1 className="text-xl font-bold mb-2">
Inspecting {title}{" "}
<span className="text-gray-500 text-sm">{coValueId}</span>
</h1>
{isGroup ? (
<p>
{onlyCoValues.length > 0 ? <h3>Permissions</h3> : ""}
<div className="flex gap-2 flex-col">
{onlyCoValues?.map(([key, value]) => (
<div className="flex gap-1 items-center">
<span className="bg-gray-200 text-xs px-2 py-0.5 rounded">
{value}
</span>
<AccountInfo
accountID={key as CoID<RawAccount>}
node={node}
/>
</div>
))}
</div>
</p>
) : (
<span className="">
Group{" "}
<Tag href={`#/${coValue?.group.id}`}>
{coValue?.group.id}
</Tag>
</span>
)}
{/* {isImage ? (
<div className="my-2">
<ImageCoValue value={values as any} />
</div>
) : null} */}
<pre className="max-w-[80vw] overflow-scroll text-sm mt-4">
<CoJsonTree coValueId={coValueId} node={node} />
</pre>
<h2 className="text-lg font-semibold mt-10 mb-4">Sessions</h2>
{coValue && <Sessions coValue={coValue} node={node} />}
</div>
);
}
function Sessions({ coValue, node }: { coValue: RawCoValue; node: LocalNode }) {
const validTx = coValue.core.getValidSortedTransactions();
return (
<div className="max-w-[80vw] border rounded">
{[...coValue.core.sessionLogs.entries()].map(
([sessionID, session]) => (
<div
key={sessionID}
className="mv-10 flex gap-2 border-b p-5 flex-wrap flex-col"
>
<div className="flex gap-2 flex-row">
<SessionInfo
sessionID={sessionID}
transactionCount={session.transactions.length}
node={node}
/>
</div>
<div className="flex gap-1 flex-wrap max-h-64 overflow-y-auto p-1 bg-gray-50 rounded">
{session.transactions.map((tx, txIdx) => {
const correspondingValidTx = validTx.find(
(validTx) =>
validTx.txID.sessionID === sessionID &&
validTx.txID.txIndex == txIdx
);
return (
<div
key={txIdx}
className={clsx(
"text-xs flex-1 p-2 border rounded min-w-36 max-w-40 overflow-scroll bg-white",
!correspondingValidTx &&
"bg-red-50 border-red-100"
)}
>
<div>
{new Date(
tx.madeAt
).toLocaleString()}
</div>
<div>{tx.privacy}</div>
<pre>
{correspondingValidTx
? JSON.stringify(
correspondingValidTx.changes,
undefined,
2
)
: "invalid/undecryptable"}
</pre>
</div>
);
})}
</div>
<div className="text-xs">
{session.lastHash} / {session.lastSignature}{" "}
</div>
</div>
)
)}
</div>
);
}
function SessionInfo({
sessionID,
transactionCount,
node,
}: {
sessionID: SessionID;
transactionCount: number;
node: LocalNode;
}) {
let Prefix = sessionID.startsWith("co_") ? (
<AccountInfo
accountID={sessionID.split("_session_")[0] as CoID<RawAccount>}
node={node}
/>
) : (
<pre className="text-xs">{sessionID.split("_session_")[0]}</pre>
);
return (
<div>
{Prefix}
<div>
<span className="text-xs">
Session {sessionID.split("_session_")[1]}
</span>
<span className="text-xs text-gray-600 font-medium">
{" "}
- {transactionCount} txs
</span>
</div>
</div>
);
}

View File

@@ -0,0 +1,249 @@
import clsx from "clsx";
import { AccountID, CoID, LocalNode, RawAccount, RawCoMap, RawCoValue } from "cojson";
import { useEffect, useState } from "react";
import { LinkIcon } from "./link-icon";
export function CoJsonTree({
coValueId,
node,
}: {
coValueId: CoID<RawCoValue>;
node: LocalNode;
}) {
const [coValue, setCoValue] = useState<RawCoValue | "unavailable">();
useEffect(() => {
return node.subscribe(coValueId, (value) => {
setCoValue(value);
});
});
if (coValue === "unavailable") {
return <div className="text-red-500">Unavailable</div>;
}
const values = coValue?.toJSON() || {};
return <RenderCoValueJSON json={values} node={node} />;
}
function RenderObject({
json,
node,
}: {
json: Record<string, any>;
node: LocalNode;
}) {
const [limit, setLimit] = useState(10);
const hasMore = Object.keys(json).length > limit;
const entries = Object.entries(json).slice(0, limit);
return (
<div className="flex gap-x-1 flex-col font-mono text-xs overflow-auto">
{"{"}
{entries.map(([key, value]) => {
return (
<RenderObjectValue
property={key}
value={value}
node={node}
/>
);
})}
{hasMore ? (
<div
className="text-gray-500 cursor-pointer"
onClick={() => setLimit((l) => l + 10)}
>
... {Object.keys(json).length - limit} more
</div>
) : null}
{"}"}
</div>
);
}
function RenderObjectValue({
property,
value,
node,
}: {
property: string;
value: any;
node: LocalNode;
}) {
const [shouldLoad, setShouldLoad] = useState(false);
const isCoValue =
typeof value === "string" ? value?.startsWith("co_") : false;
return (
<div className={clsx(`flex group`)}>
<div className="text-gray-500 flex items-start">
<div className="flex items-center">
<RenderCoValueJSON json={property} node={node} />:{" "}
</div>
</div>
{isCoValue ? (
<div className={clsx(shouldLoad && "pb-2")}>
<div className="flex items-center ">
<div onClick={() => setShouldLoad((s) => !s)}>
<div className="w-8 text-center text-gray-700 font-mono px-1 text-xs rounded hover:bg-gray-300 cursor-pointer">
{shouldLoad ? `-` : `...`}
</div>
</div>
<a
href={`#/${value}`}
className="ml-2 group-hover:block hidden"
>
<LinkIcon />
</a>
</div>
<span>
{shouldLoad ? (
<CoJsonTree coValueId={value} node={node} />
) : null}
</span>
</div>
) : (
<div className="">
<RenderCoValueJSON json={value} node={node} />
</div>
)}
</div>
);
}
function RenderCoValueArray({ json, node }: { json: any[]; node: LocalNode }) {
const [limit, setLimit] = useState(10);
const hasMore = json.length > limit;
const entries = json.slice(0, limit);
return (
<div className="flex gap-x-1 flex-col font-mono text-xs overflow-auto">
{entries.map((value, idx) => {
return (
<div key={idx} className="flex gap-x-1">
<RenderCoValueJSON json={value} node={node} />
</div>
);
})}
{hasMore ? (
<div
className="text-gray-500 cursor-pointer"
onClick={() => setLimit((l) => l + 10)}
>
... {json.length - limit} more
</div>
) : null}
</div>
);
}
function RenderCoValueJSON({
json,
node,
}: {
json:
| Record<string, any>
| any[]
| string
| null
| number
| boolean
| undefined;
node: LocalNode;
}) {
if (typeof json === "undefined") {
return <>"undefined"</>;
} else if (Array.isArray(json)) {
return (
<div className="">
<span className="text-gray-500">[</span>
<div className="ml-2">
<RenderCoValueArray json={json} node={node} />
</div>
<span className="text-gray-500">]</span>
</div>
);
} else if (
typeof json === "object" &&
json &&
Object.getPrototypeOf(json) === Object.prototype
) {
return <RenderObject json={json} node={node} />;
} else if (typeof json === "string") {
if (json?.startsWith("co_")) {
if (json.includes("_session_")) {
return (
<>
<AccountInfo accountID={json.split("_session_")[0] as AccountID} node={node}/>{" "}
(sess {json.split("_session_")[1]})
</>
);
} else {
return (
<>
<a className="underline" href={`#/${json}`}>
{'"'}
{json}
{'"'}
</a>
</>
);
}
} else {
return <div className="truncate max-w-64 ml-1">{json}</div>;
}
} else {
return <div className="truncate max-w-64">{JSON.stringify(json)}</div>;
}
}
export function AccountInfo({ accountID, node }: { accountID: CoID<RawAccount>, node: LocalNode }) {
const [name, setName] = useState<string | null>(null);
useEffect(() => {
(async () => {
const account = await node.load(accountID);
if (account === "unavailable") return;
const profileID = account?.get("profile");
if (profileID === undefined) return;
const profile = await node.load(profileID as CoID<RawCoMap>);
if (profile === "unavailable") return;
setName(profile?.get("name") as string);
})()
}, [accountID, node]);
return name ? (
<Tag href={`#/${accountID}`} title={accountID}><h1>{name}</h1></Tag>
) : (
<Tag href={`#/${accountID}`}>{accountID}</Tag>
);
}
export function Tag({
children,
href,
title
}: {
children: React.ReactNode;
href?: string;
title?: string;
}) {
if (href) {
return (
<a
href={href}
className="border text-xs px-2 py-0.5 rounded hover:underline"
title={title}
>
{children}
</a>
);
}
return (
<span className="border text-xs px-2 py-0.5 rounded">{children}</span>
);
}

View File

@@ -1,5 +1,37 @@
# jazz-example-pets
## 0.0.83
### Patch Changes
- jazz-react@0.7.18
- jazz-tools@0.7.18
- jazz-browser-media-images@0.7.18
## 0.0.82
### Patch Changes
- jazz-react@0.7.17
- jazz-tools@0.7.17
- jazz-browser-media-images@0.7.17
## 0.0.81
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.16
- jazz-browser-media-images@0.7.16
- jazz-react@0.7.16
## 0.0.80
### Patch Changes
- Updated dependencies
- jazz-react@0.7.15
## 0.0.79
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-pets",
"private": true,
"version": "0.0.79",
"version": "0.0.83",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,34 @@
# jazz-example-todo
## 0.0.82
### Patch Changes
- jazz-react@0.7.18
- jazz-tools@0.7.18
## 0.0.81
### Patch Changes
- jazz-react@0.7.17
- jazz-tools@0.7.17
## 0.0.80
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.16
- jazz-react@0.7.16
## 0.0.79
### Patch Changes
- Updated dependencies
- jazz-react@0.7.15
## 0.0.78
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.78",
"version": "0.0.82",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -9,9 +9,11 @@ import localFont from "next/font/local";
import { GcmpLogo, JazzLogo } from "@/components/logos";
import { SiGithub, SiDiscord, SiTwitter } from "@icons-pack/react-simple-icons";
import { Nav, NavLink, Newsletter, NewsletterButton } from "@/components/nav";
import { MailIcon } from "lucide-react";
import { DocNav } from "@/components/docs/nav";
import { SpeedInsights } from "@vercel/speed-insights/next"
import { Analytics } from "@vercel/analytics/react"
// If loading a variable font, you don't need to specify the font weight
const manrope = Manrope({
subsets: ["latin"],
@@ -48,6 +50,8 @@ export default function RootLayout({
"flex flex-col items-center bg-stone-50 dark:bg-stone-950 overflow-x-hidden",
].join(" ")}
>
<SpeedInsights/>
<Analytics/>
<ThemeProvider
attribute="class"
defaultTheme="system"
@@ -192,12 +196,6 @@ export default function RootLayout({
</div>
</footer>
</ThemeProvider>
<script
defer
data-api="/api/event"
data-domain="jazz.tools"
src="/js/script.js"
></script>
</body>
</html>
);

View File

@@ -14,6 +14,7 @@
"*.{ts,tsx}": "eslint --fix",
"*.{js,jsx,mdx,json}": "prettier --write"
},
"packageManager": "pnpm@9.1.4",
"dependencies": {
"@evilmartians/harmony": "^1.0.0",
"@icons-pack/react-simple-icons": "^9.1.0",
@@ -21,6 +22,8 @@
"@mdx-js/react": "^2.3.0",
"@next/mdx": "^13.5.4",
"@types/mdx": "^2.0.8",
"@vercel/analytics": "^1.3.1",
"@vercel/speed-insights": "^1.0.12",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"lucide-react": "^0.284.0",

5244
homepage/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,243 +0,0 @@
import {
WithJazz,
useJazz,
DemoAuth,
useAutoSub,
useBinaryStream,
} from "jazz-react";
import ReactDOM from "react-dom/client";
import { HashRoute } from "hash-slash";
import { Account, CoID, CoValue, SessionID } from "cojson";
import { clsx } from "clsx";
import { ImageDefinition } from "cojson/src/media";
import { CoJsonTree } from "./cojson-tree";
ReactDOM.createRoot(document.getElementById("root")!).render(
<WithJazz
auth={DemoAuth({ appName: "Jazz Chat Example" })}
apiKey="api_z9d034j3t34ht034ir"
>
<App />
</WithJazz>
);
function App() {
return (
<div className="flex flex-col items-center justify-between w-screen h-screen p-2 ">
<button
onClick={useJazz().logOut}
className="rounded mb-5 px-2 py-1 bg-stone-200 dark:bg-stone-800 dark:text-white self-end"
>
Log Out
</button>
{HashRoute(
{
"/": <Home />,
"/:id": (id) => <Inspect coValueId={id as CoID<CoValue>} />,
},
{ reportToParentFrame: true }
)}
</div>
);
}
function Home() {
return (
<form
className="mb-auto"
onSubmit={(event) => {
const coValueId = (event.target as any).coValueId
.value as CoID<CoValue>;
location.hash = "/" + coValueId;
event.preventDefault();
}}
>
<input name="coValueId" className="border" />
<button>Inspect</button>
</form>
);
}
function Tag({ children, href }: { children: React.ReactNode; href?: string }) {
if (href) {
return (
<a
href={href}
className="border text-xs px-2 py-0.5 rounded hover:underline"
>
{children}
</a>
);
}
return <span className="border text-xs px-2 py-0.5 rounded">{children}</span>;
}
function ImageCoValue({ value }: { value: ImageDefinition["_shape"] }) {
const keys = Object.keys(value);
const keyIncludingRes = keys.find((key) => key.includes("x"));
const idToResolve = keyIncludingRes
? value[keyIncludingRes as `${number}x${number}`]
: null;
if (!idToResolve) return <div>Can't find image</div>;
const image = useBinaryStream(idToResolve);
return (
<img src={image?.blobURL || value.placeholderDataURL} alt="placeholder" />
);
}
function Inspect({ coValueId }: { coValueId: CoID<CoValue> }) {
const coValue = useAutoSub(coValueId);
const values = coValue?.meta.coValue.toJSON() || {};
const isImage = "placeholderDataURL" in values;
const isGroup = coValue?.meta.group.id === coValueId;
const entires = Object.entries(values as any) as [string, string][];
const onlyCoValues = entires.filter(([key]) => key.startsWith("co_"));
let title = "";
if (isImage) {
title = "Image";
} else if (isGroup) {
title = "Group";
}
return (
<div className="mb-auto">
<h1 className="text-xl font-bold mb-2">
Inspecting {title}{" "}
<span className="text-gray-500 text-sm">{coValueId}</span>
</h1>
{isGroup ? (
<p>
{onlyCoValues.length > 0 ? <h3>Permissions</h3> : ""}
<div className="flex gap-2 flex-col">
{onlyCoValues?.map(([key, value]) => (
<div className="flex gap-1 items-center">
<span className="bg-gray-200 text-xs px-2 py-0.5 rounded">
{value}
</span>
<AccountInfo accountID={key as CoID<Account>} />
</div>
))}
</div>
</p>
) : (
<span className="">
Group{" "}
<Tag href={`#/${coValue?.meta.group.id}`}>
{coValue?.meta.group.id}
</Tag>
</span>
)}
{isImage ? (
<div className="my-2">
<ImageCoValue value={values as any} />
</div>
) : null}
<pre className="max-w-[80vw] overflow-scroll text-sm mt-4">
<CoJsonTree coValueId={coValueId} />
</pre>
<h2 className="text-lg font-semibold mt-10 mb-4">Sessions</h2>
{coValue && <Sessions coValue={coValue.meta.coValue} />}
</div>
);
}
function Sessions({ coValue }: { coValue: CoValue }) {
const validTx = coValue.core.getValidSortedTransactions();
return (
<div className="max-w-[80vw] border rounded">
{[...coValue.core.sessionLogs.entries()].map(([sessionID, session]) => (
<div
key={sessionID}
className="mv-10 flex gap-2 border-b p-5 flex-wrap flex-col"
>
<div className="flex gap-2 flex-row">
<SessionInfo
sessionID={sessionID}
transactionCount={session.transactions.length}
/>
</div>
<div className="flex gap-1 flex-wrap max-h-64 overflow-y-auto p-1 bg-gray-50 rounded">
{session.transactions.map((tx, txIdx) => {
const correspondingValidTx = validTx.find(
(validTx) =>
validTx.txID.sessionID === sessionID &&
validTx.txID.txIndex == txIdx
);
return (
<div
key={txIdx}
className={clsx(
"text-xs flex-1 p-2 border rounded min-w-36 max-w-40 overflow-scroll bg-white",
!correspondingValidTx && "bg-red-50 border-red-100"
)}
>
<div>{new Date(tx.madeAt).toLocaleString()}</div>
<div>{tx.privacy}</div>
<pre>
{correspondingValidTx
? JSON.stringify(
correspondingValidTx.changes,
undefined,
2
)
: "invalid/undecryptable"}
</pre>
</div>
);
})}
</div>
<div className="text-xs">
{session.lastHash} / {session.lastSignature}{" "}
</div>
</div>
))}
</div>
);
}
function SessionInfo({
sessionID,
transactionCount,
}: {
sessionID: SessionID;
transactionCount: number;
}) {
let Prefix = sessionID.startsWith("co_") ? (
<AccountInfo accountID={sessionID.split("_session_")[0] as CoID<Account>} />
) : (
<pre className="text-xs">{sessionID.split("_session_")[0]}</pre>
);
return (
<div>
{Prefix}
<div>
<span className="text-xs">
Session {sessionID.split("_session_")[1]}
</span>
<span className="text-xs text-gray-600 font-medium">
{" "}
- {transactionCount} txs
</span>
</div>
</div>
);
}
function AccountInfo({ accountID }: { accountID: CoID<Account> }) {
const account = useAutoSub(accountID);
return (
<div className="flex items-center gap-2">
<h1>{account?.profile?.name}</h1>
<Tag href={`#/${accountID}`}>{account?.id}</Tag>
</div>
);
}

View File

@@ -1,151 +0,0 @@
import clsx from "clsx";
import { CoID, CoValue } from "cojson";
import { useAutoSub } from "jazz-react";
import { useState } from "react";
import { LinkIcon } from "./link-icon";
export function CoJsonTree({ coValueId }: { coValueId: CoID<CoValue> }) {
const coValue = useAutoSub(coValueId);
const values = coValue?.meta.coValue.toJSON() || {};
return <RenderCoValueJSON json={values} />;
}
function RenderObject({ json }: { json: Record<string, any> }) {
const [limit, setLimit] = useState(10);
const hasMore = Object.keys(json).length > limit;
const entries = Object.entries(json).slice(0, limit);
return (
<div className="flex gap-x-1 flex-col font-mono text-xs overflow-auto">
{entries.map(([key, value]) => {
return <RenderObjectValue property={key} value={value} />;
})}
{hasMore ? (
<div
className="text-gray-500 cursor-pointer"
onClick={() => setLimit((l) => l + 10)}
>
... {Object.keys(json).length - limit} more
</div>
) : null}
</div>
);
}
function RenderObjectValue({
property,
value,
}: {
property: string;
value: any;
}) {
const [shouldLoad, setShouldLoad] = useState(false);
const isCoValue =
typeof value === "string" ? value?.startsWith("co_") : false;
return (
<div className={clsx(`flex group`)}>
<span className="text-gray-500 flex">
<RenderCoValueJSON json={property} />:{" "}
</span>
{isCoValue ? (
<div className={clsx(shouldLoad && "pb-2")}>
<div className="flex items-center ">
<div onClick={() => setShouldLoad((s) => !s)}>
<div className="w-8 text-center text-gray-700 font-mono px-1 text-xs rounded hover:bg-gray-300 cursor-pointer">
{shouldLoad ? `-` : `...`}
</div>
</div>
<a href={`#/${value}`} className="ml-2 group-hover:block hidden">
<LinkIcon />
</a>
</div>
<span>{shouldLoad ? <CoJsonTree coValueId={value} /> : null}</span>
</div>
) : (
<div className="">
<RenderCoValueJSON json={value} />
</div>
)}
</div>
);
}
function RenderCoValueArray({ json }: { json: any[] }) {
const [limit, setLimit] = useState(10);
const hasMore = json.length > limit;
const entries = json.slice(0, limit);
return (
<div className="flex gap-x-1 flex-col font-mono text-xs overflow-auto">
{entries.map((value, idx) => {
return (
<div key={idx} className="flex gap-x-1">
<RenderCoValueJSON json={value} />
</div>
);
})}
{hasMore ? (
<div
className="text-gray-500 cursor-pointer"
onClick={() => setLimit((l) => l + 10)}
>
... {json.length - limit} more
</div>
) : null}
</div>
);
}
function RenderCoValueJSON({
json,
}: {
json:
| Record<string, any>
| any[]
| string
| null
| number
| boolean
| undefined;
}) {
if (typeof json === "undefined") {
return <>"undefined"</>;
} else if (Array.isArray(json)) {
return (
<div className="">
<span className="text-gray-500">[</span>
<div className="ml-2">
<RenderCoValueArray json={json} />
</div>
<span className="text-gray-500">]</span>
</div>
);
} else if (
typeof json === "object" &&
json &&
Object.getPrototypeOf(json) === Object.prototype
) {
return <RenderObject json={json} />;
} else if (typeof json === "string") {
if (json?.startsWith("co_")) {
return (
<>
<a className="underline" href={`#/${json}`}>
{'"'}
{json}
{'"'}
</a>
</>
);
} else {
return <div className="truncate max-w-64 ml-1">{json}</div>;
}
} else {
return <div className="truncate max-w-64">{JSON.stringify(json)}</div>;
}
}

View File

@@ -6,6 +6,7 @@
"packages/*",
"examples/*"
],
"packageManager": "pnpm@9.1.4",
"devDependencies": {
"@changesets/cli": "^2.27.3",
"husky": "^9.0.11",

View File

@@ -1,5 +1,19 @@
# cojson-storage-indexeddb
## 0.7.18
### Patch Changes
- Updated dependencies
- cojson@0.7.18
## 0.7.17
### Patch Changes
- Updated dependencies
- cojson@0.7.17
## 0.7.14
### Patch Changes

View File

@@ -1,13 +1,13 @@
{
"name": "cojson-storage-indexeddb",
"version": "0.7.14",
"version": "0.7.18",
"main": "dist/index.js",
"type": "module",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"cojson": "workspace:*",
"effect": "^3.1.5",
"effect": "^3.5.2",
"typescript": "^5.1.6"
},
"devDependencies": {

View File

@@ -1,5 +1,19 @@
# cojson-storage-sqlite
## 0.7.18
### Patch Changes
- Updated dependencies
- cojson@0.7.18
## 0.7.17
### Patch Changes
- Updated dependencies
- cojson@0.7.17
## 0.7.14
### Patch Changes

View File

@@ -1,14 +1,14 @@
{
"name": "cojson-storage-sqlite",
"type": "module",
"version": "0.7.14",
"version": "0.7.18",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"better-sqlite3": "^8.5.2",
"cojson": "workspace:*",
"effect": "^3.1.5",
"effect": "^3.5.2",
"typescript": "^5.1.6"
},
"devDependencies": {

View File

@@ -1,5 +1,19 @@
# cojson-transport-nodejs-ws
## 0.7.18
### Patch Changes
- Updated dependencies
- cojson@0.7.18
## 0.7.17
### Patch Changes
- Updated dependencies
- cojson@0.7.17
## 0.7.14
### Patch Changes

View File

@@ -1,13 +1,13 @@
{
"name": "cojson-transport-ws",
"type": "module",
"version": "0.7.14",
"version": "0.7.18",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"cojson": "workspace:*",
"effect": "^3.1.5",
"effect": "^3.5.2",
"typescript": "^5.1.6"
},
"scripts": {

View File

@@ -1,5 +1,17 @@
# cojson
## 0.7.18
### Patch Changes
- Update to Effect 3.5.2
## 0.7.17
### Patch Changes
- Fix bugs in new storage interface
## 0.7.14
### Patch Changes

View File

@@ -5,7 +5,7 @@
"types": "src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.7.14",
"version": "0.7.18",
"devDependencies": {
"@types/jest": "^29.5.3",
"@typescript-eslint/eslint-plugin": "^6.2.1",
@@ -22,7 +22,7 @@
"@noble/ciphers": "^0.1.3",
"@noble/hashes": "^1.4.0",
"@scure/base": "^1.1.1",
"effect": "^3.1.5",
"effect": "^3.5.2",
"hash-wasm": "^4.9.0"
},
"scripts": {

View File

@@ -1,5 +1,27 @@
# jazz-browser-media-images
## 0.7.18
### Patch Changes
- jazz-browser@0.7.18
- jazz-tools@0.7.18
## 0.7.17
### Patch Changes
- jazz-browser@0.7.17
- jazz-tools@0.7.17
## 0.7.16
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.16
- jazz-browser@0.7.16
## 0.7.14
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser-media-images",
"version": "0.7.14",
"version": "0.7.18",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,32 @@
# jazz-browser
## 0.7.18
### Patch Changes
- Updated dependencies
- cojson@0.7.18
- cojson-storage-indexeddb@0.7.18
- cojson-transport-ws@0.7.18
- jazz-tools@0.7.18
## 0.7.17
### Patch Changes
- Updated dependencies
- cojson@0.7.17
- cojson-storage-indexeddb@0.7.17
- cojson-transport-ws@0.7.17
- jazz-tools@0.7.17
## 0.7.16
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.16
## 0.7.14
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser",
"version": "0.7.14",
"version": "0.7.18",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",
@@ -10,7 +10,7 @@
"cojson": "workspace:*",
"cojson-storage-indexeddb": "workspace:*",
"cojson-transport-ws": "workspace:*",
"effect": "^3.1.5",
"effect": "^3.5.2",
"jazz-tools": "workspace:*",
"typescript": "^5.1.6"
},

View File

@@ -1,5 +1,30 @@
# jazz-autosub
## 0.7.18
### Patch Changes
- Updated dependencies
- cojson@0.7.18
- cojson-transport-ws@0.7.18
- jazz-tools@0.7.18
## 0.7.17
### Patch Changes
- Updated dependencies
- cojson@0.7.17
- cojson-transport-ws@0.7.17
- jazz-tools@0.7.17
## 0.7.16
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.16
## 0.7.14
### Patch Changes

View File

@@ -5,11 +5,11 @@
"types": "src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.7.14",
"version": "0.7.18",
"dependencies": {
"cojson": "workspace:*",
"cojson-transport-ws": "workspace:*",
"effect": "^3.1.5",
"effect": "^3.5.2",
"jazz-tools": "workspace:*",
"ws": "^8.14.2"
},

View File

@@ -1,5 +1,37 @@
# jazz-react
## 0.7.18
### Patch Changes
- Updated dependencies
- cojson@0.7.18
- jazz-browser@0.7.18
- jazz-tools@0.7.18
## 0.7.17
### Patch Changes
- Updated dependencies
- cojson@0.7.17
- jazz-browser@0.7.17
- jazz-tools@0.7.17
## 0.7.16
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.16
- jazz-browser@0.7.16
## 0.7.15
### Patch Changes
- Provide current res in ProgressiveImg
## 0.7.14
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-react",
"version": "0.7.14",
"version": "0.7.18",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -127,20 +127,20 @@ export function createJazzReactContext<Acc extends Account>({
id: ID<V> | undefined,
depth: D & DepthsIn<V> = [] as D & DepthsIn<V>,
): DeeplyLoaded<V, D> | undefined {
const [state, setState] = useState<DeeplyLoaded<V, D> | undefined>(
undefined,
);
const [state, setState] = useState<{
value: DeeplyLoaded<V, D> | undefined;
}>({ value: undefined });
const me = React.useContext(JazzContext)?.me;
useEffect(() => {
if (!id || !me) return;
return subscribeToCoValue(Schema, id, me, depth, (value) => {
setState(value);
setState({ value });
});
}, [Schema, id, me]);
return state;
return state.value;
}
function useAcceptInvite<V extends CoValue>({

View File

@@ -9,7 +9,10 @@ export function useProgressiveImg({
image: ImageDefinition | null | undefined;
maxWidth?: number;
}) {
const [src, setSrc] = useState<string | undefined>(undefined);
const [current, setCurrent] = useState<
| { src?: string; res?: `${number}x${number}` | "placeholder" }
| undefined
>(undefined);
useEffect(() => {
let lastHighestRes: string | undefined;
@@ -22,21 +25,28 @@ export function useProgressiveImg({
const blob = highestRes.stream.toBlob();
if (blob) {
const blobURI = URL.createObjectURL(blob);
setSrc(blobURI);
setCurrent({ src: blobURI, res: highestRes.res });
return () => {
setTimeout(() => URL.revokeObjectURL(blobURI), 200);
};
}
}
} else {
setSrc(update?.placeholderDataURL);
setCurrent({
src: update?.placeholderDataURL,
res: "placeholder",
});
}
});
return unsub;
}, [image?.id, maxWidth]);
return { src, originalSize: image?.originalSize };
return {
src: current?.src,
res: current?.res,
originalSize: image?.originalSize,
};
}
/** @category Media */
@@ -47,6 +57,7 @@ export function ProgressiveImg({
}: {
children: (result: {
src: string | undefined;
res: `${number}x${number}` | "placeholder" | undefined;
originalSize: readonly [number, number] | undefined;
}) => React.ReactNode;
image: ImageDefinition | null | undefined;

View File

@@ -1,5 +1,30 @@
# jazz-autosub
## 0.7.18
### Patch Changes
- Updated dependencies
- cojson@0.7.18
- cojson-transport-ws@0.7.18
- jazz-tools@0.7.18
## 0.7.17
### Patch Changes
- Updated dependencies
- cojson@0.7.17
- cojson-transport-ws@0.7.17
- jazz-tools@0.7.17
## 0.7.16
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.16
## 0.7.14
### Patch Changes

View File

@@ -3,7 +3,7 @@
"bin": "./dist/index.js",
"type": "module",
"license": "MIT",
"version": "0.7.14",
"version": "0.7.18",
"scripts": {
"lint": "eslint . --ext ts,tsx",
"format": "prettier --write './src/**/*.{ts,tsx}'",
@@ -16,7 +16,7 @@
"@effect/schema": "^0.66.16",
"cojson": "workspace:*",
"cojson-transport-ws": "workspace:*",
"effect": "^3.1.5",
"effect": "^3.5.2",
"fast-check": "^3.17.2",
"jazz-tools": "workspace:*",
"ws": "^8.14.2"

View File

@@ -1,5 +1,25 @@
# jazz-autosub
## 0.7.18
### Patch Changes
- Updated dependencies
- cojson@0.7.18
## 0.7.17
### Patch Changes
- Updated dependencies
- cojson@0.7.17
## 0.7.16
### Patch Changes
- Fix: allow null in encoded fields
## 0.7.14
### Patch Changes

View File

@@ -5,11 +5,11 @@
"types": "./src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.7.14",
"version": "0.7.18",
"dependencies": {
"@effect/schema": "^0.66.16",
"cojson": "workspace:*",
"effect": "^3.1.5",
"effect": "^3.5.2",
"fast-check": "^3.17.2"
},
"scripts": {

View File

@@ -539,6 +539,7 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
if (
(typeof key === "string" || ItemsSym) &&
typeof value === "object" &&
value !== null &&
SchemaInit in value
) {
(target.constructor as typeof CoMap)._schema ||= {};

View File

@@ -15,70 +15,6 @@ export const subscriptionsScopes = new WeakMap<
const TRACE_INVALIDATIONS = false;
let nSeconds = 1;
setInterval(() => console.log(nSeconds++ + "s passed"), 1000);
export interface ThrottleOptions {
/**
* Fire immediately on the first call.
*/
start?: boolean;
/**
* Fire as soon as `wait` has passed.
*/
middle?: boolean;
/**
* Cancel after the first successful call.
*/
once?: boolean;
}
interface Throttler<T extends unknown[]> {
(...args: T): void;
cancel(): void;
}
export function throttle<T extends unknown[]>(
callback: (...args: T) => unknown,
wait = 0,
{ start = true, middle = true, once = false }: ThrottleOptions = {},
): Throttler<T> {
let innerStart = start;
let last = 0;
let timer: ReturnType<typeof setTimeout>;
let cancelled = false;
function fn(this: unknown, ...args: T) {
if (cancelled) return;
const delta = Date.now() - last;
last = Date.now();
if (start && middle && delta >= wait) {
innerStart = true;
}
if (innerStart) {
innerStart = false;
callback.apply(this, args);
if (once) fn.cancel();
} else if ((middle && delta < wait) || !middle) {
clearTimeout(timer);
timer = setTimeout(
() => {
last = Date.now();
callback.apply(this, args);
if (once) fn.cancel();
},
!middle ? wait : wait - delta,
);
}
}
fn.cancel = () => {
clearTimeout(timer);
cancelled = true;
};
return fn;
}
export class SubscriptionScope<Root extends CoValue> {
scopeID: string = `scope-${Math.random().toString(36).slice(2)}`;
subscriber: Account;
@@ -112,11 +48,7 @@ export class SubscriptionScope<Root extends CoValue> {
subscriptionsScopes.set(root, this);
this.subscriber = root._loadedAs;
this.onUpdate = throttle((update) => {
console.log("onUpdate");
onUpdate(update);
}, 50);
this.onUpdate = onUpdate;
this.rootEntry.rawUnsub = root._raw.core.subscribe(
(rawUpdate: RawCoValue | undefined) => {
if (!rawUpdate) return;

View File

@@ -10,6 +10,7 @@ import {
WasmCrypto,
isControlledAccount,
} from "../index.js";
import { Schema } from "@effect/schema";
const Crypto = await WasmCrypto.create();
@@ -24,6 +25,7 @@ describe("Simple CoMap operations", async () => {
_height = co.number;
birthday = co.encoded(Encoders.Date);
name? = co.string;
nullable = co.encoded(Schema.NullOr(Schema.String));
get roughColor() {
return this.color + "ish";
@@ -39,6 +41,7 @@ describe("Simple CoMap operations", async () => {
color: "red",
_height: 10,
birthday: birthday,
nullable: null,
},
{ owner: me },
);
@@ -49,7 +52,12 @@ describe("Simple CoMap operations", async () => {
expect(map._height).toEqual(10);
expect(map.birthday).toEqual(birthday);
expect(map._raw.get("birthday")).toEqual(birthday.toISOString());
expect(Object.keys(map)).toEqual(["color", "_height", "birthday"]);
expect(Object.keys(map)).toEqual([
"color",
"_height",
"birthday",
"nullable",
]);
});
test("Construction with too many things provided", () => {
@@ -84,6 +92,9 @@ describe("Simple CoMap operations", async () => {
expect(map._height).toEqual(20);
expect(map._raw.get("_height")).toEqual(20);
map.nullable = "not null";
map.nullable = null;
map.name = "Secret name";
expect(map.name).toEqual("Secret name");
map.name = undefined;
@@ -253,11 +264,12 @@ describe("CoMap resolution", async () => {
test("Loading and availability", async () => {
const { me, map } = await initNodeAndMap();
const [initialAsPeer, secondPeer] = await Effect.runPromise(connectedPeers(
"initial",
"second",
{ peer1role: "server", peer2role: "client" },
));
const [initialAsPeer, secondPeer] = await Effect.runPromise(
connectedPeers("initial", "second", {
peer1role: "server",
peer2role: "client",
}),
);
if (!isControlledAccount(me)) {
throw "me is not a controlled account";
}
@@ -323,11 +335,12 @@ describe("CoMap resolution", async () => {
test("Subscription & auto-resolution", async () => {
const { me, map } = await initNodeAndMap();
const [initialAsPeer, secondAsPeer] = await Effect.runPromise(connectedPeers(
"initial",
"second",
{ peer1role: "server", peer2role: "client" },
));
const [initialAsPeer, secondAsPeer] = await Effect.runPromise(
connectedPeers("initial", "second", {
peer1role: "server",
peer2role: "client",
}),
);
if (!isControlledAccount(me)) {
throw "me is not a controlled account";
}

203
pnpm-lock.yaml generated
View File

@@ -136,6 +136,109 @@ importers:
specifier: ^5.0.10
version: 5.0.10(@types/node@20.10.5)
examples/inspector:
dependencies:
'@radix-ui/react-checkbox':
specifier: ^1.0.4
version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.45)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-slot':
specifier: ^1.0.2
version: 1.0.2(@types/react@18.2.45)(react@18.2.0)
'@radix-ui/react-toast':
specifier: ^1.1.4
version: 1.1.5(@types/react-dom@18.2.18)(@types/react@18.2.45)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@types/qrcode':
specifier: ^1.5.1
version: 1.5.5
class-variance-authority:
specifier: ^0.7.0
version: 0.7.0
clsx:
specifier: ^2.0.0
version: 2.0.0
cojson:
specifier: workspace:*
version: link:../../packages/cojson
cojson-transport-ws:
specifier: workspace:*
version: link:../../packages/cojson-transport-ws
effect:
specifier: ^3.5.2
version: 3.5.2
hash-slash:
specifier: workspace:*
version: link:../../packages/hash-slash
lucide-react:
specifier: ^0.274.0
version: 0.274.0(react@18.2.0)
qrcode:
specifier: ^1.5.3
version: 1.5.3
react:
specifier: ^18.2.0
version: 18.2.0
react-dom:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
react-router:
specifier: ^6.16.0
version: 6.21.0(react@18.2.0)
react-router-dom:
specifier: ^6.16.0
version: 6.21.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react-use:
specifier: ^17.4.0
version: 17.4.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
tailwind-merge:
specifier: ^1.14.0
version: 1.14.0
tailwindcss-animate:
specifier: ^1.0.7
version: 1.0.7(tailwindcss@3.4.0(ts-node@10.9.2(@swc/core@1.3.101)(@types/node@20.10.5)(typescript@5.3.3)))
uniqolor:
specifier: ^1.1.0
version: 1.1.1
devDependencies:
'@types/react':
specifier: ^18.2.15
version: 18.2.45
'@types/react-dom':
specifier: ^18.2.7
version: 18.2.18
'@typescript-eslint/eslint-plugin':
specifier: ^6.0.0
version: 6.15.0(@typescript-eslint/parser@6.15.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/parser':
specifier: ^6.0.0
version: 6.15.0(eslint@8.56.0)(typescript@5.3.3)
'@vitejs/plugin-react-swc':
specifier: ^3.3.2
version: 3.5.0(vite@5.0.10(@types/node@20.10.5))
autoprefixer:
specifier: ^10.4.14
version: 10.4.16(postcss@8.4.32)
eslint:
specifier: ^8.45.0
version: 8.56.0
eslint-plugin-react-hooks:
specifier: ^4.6.0
version: 4.6.0(eslint@8.56.0)
eslint-plugin-react-refresh:
specifier: ^0.4.3
version: 0.4.5(eslint@8.56.0)
postcss:
specifier: ^8.4.27
version: 8.4.32
tailwindcss:
specifier: ^3.3.3
version: 3.4.0(ts-node@10.9.2(@swc/core@1.3.101)(@types/node@20.10.5)(typescript@5.3.3))
typescript:
specifier: ^5.0.2
version: 5.3.3
vite:
specifier: ^5.0.10
version: 5.0.10(@types/node@20.10.5)
examples/pets:
dependencies:
'@radix-ui/react-checkbox':
@@ -348,8 +451,8 @@ importers:
specifier: ^1.1.1
version: 1.1.5
effect:
specifier: ^3.1.5
version: 3.2.1
specifier: ^3.5.2
version: 3.5.2
hash-wasm:
specifier: ^4.9.0
version: 4.11.0
@@ -385,8 +488,8 @@ importers:
specifier: workspace:*
version: link:../cojson
effect:
specifier: ^3.1.5
version: 3.2.1
specifier: ^3.5.2
version: 3.5.2
typescript:
specifier: ^5.1.6
version: 5.3.3
@@ -410,8 +513,8 @@ importers:
specifier: workspace:*
version: link:../cojson
effect:
specifier: ^3.1.5
version: 3.2.1
specifier: ^3.5.2
version: 3.5.2
typescript:
specifier: ^5.1.6
version: 5.3.3
@@ -426,8 +529,8 @@ importers:
specifier: workspace:*
version: link:../cojson
effect:
specifier: ^3.1.5
version: 3.2.1
specifier: ^3.5.2
version: 3.5.2
typescript:
specifier: ^5.1.6
version: 5.3.3
@@ -463,8 +566,8 @@ importers:
specifier: workspace:*
version: link:../cojson-transport-ws
effect:
specifier: ^3.1.5
version: 3.2.1
specifier: ^3.5.2
version: 3.5.2
jazz-tools:
specifier: workspace:*
version: link:../jazz-tools
@@ -506,8 +609,8 @@ importers:
specifier: workspace:*
version: link:../cojson-transport-ws
effect:
specifier: ^3.1.5
version: 3.2.1
specifier: ^3.5.2
version: 3.5.2
jazz-tools:
specifier: workspace:*
version: link:../jazz-tools
@@ -554,13 +657,13 @@ importers:
dependencies:
'@effect/cli':
specifier: ^0.36.21
version: 0.36.21(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1))(@effect/printer-ansi@0.33.12(@effect/typeclass@0.24.12(effect@3.2.1))(effect@3.2.1))(@effect/printer@0.33.12(@effect/typeclass@0.24.12(effect@3.2.1))(effect@3.2.1))(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1)
version: 0.36.21(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2))(@effect/printer-ansi@0.33.12(@effect/typeclass@0.24.12(effect@3.5.2))(effect@3.5.2))(@effect/printer@0.33.12(@effect/typeclass@0.24.12(effect@3.5.2))(effect@3.5.2))(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2)
'@effect/platform-node':
specifier: ^0.49.2
version: 0.49.2(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1))(effect@3.2.1)
version: 0.49.2(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2))(effect@3.5.2)
'@effect/schema':
specifier: ^0.66.16
version: 0.66.16(effect@3.2.1)(fast-check@3.17.2)
version: 0.66.16(effect@3.5.2)(fast-check@3.17.2)
cojson:
specifier: workspace:*
version: link:../cojson
@@ -568,8 +671,8 @@ importers:
specifier: workspace:*
version: link:../cojson-transport-ws
effect:
specifier: ^3.1.5
version: 3.2.1
specifier: ^3.5.2
version: 3.5.2
fast-check:
specifier: ^3.17.2
version: 3.17.2
@@ -594,13 +697,13 @@ importers:
dependencies:
'@effect/schema':
specifier: ^0.66.16
version: 0.66.16(effect@3.2.1)(fast-check@3.17.2)
version: 0.66.16(effect@3.5.2)(fast-check@3.17.2)
cojson:
specifier: workspace:*
version: link:../cojson
effect:
specifier: ^3.1.5
version: 3.2.1
specifier: ^3.5.2
version: 3.5.2
fast-check:
specifier: ^3.17.2
version: 3.17.2
@@ -2358,8 +2461,8 @@ packages:
resolution: {integrity: sha512-G0wNgFMFRDnFfKaXG2R6HiyVHqhKwdQ3EgoxW3wPlns2wKqem7F+HgkWBcevN7Vz0nN4AXtskID7/6jsYDXcKw==}
hasBin: true
effect@3.2.1:
resolution: {integrity: sha512-WnM7QyHekA+oWkJyD1g99BDqD3atAXKjarcDnUX9alIKLd8EFXdY333wpgcNJkSqtvXDsx8qYWOMbuivdwoN2w==}
effect@3.5.2:
resolution: {integrity: sha512-jZAZAgHHrnkqrRaaLBU/a6zEFm3+uOimr+ZJqvCqiHtw5k2AE6F0jiEPuM/MNJOe4r16JDo4SYa3IULIQuXvAw==}
electron-to-chromium@1.4.615:
resolution: {integrity: sha512-/bKPPcgZVUziECqDc+0HkT87+0zhaWSZHNXqF8FLd2lQcptpmUFwoCSWjCdOng9Gdq+afKArPdEg/0ZW461Eng==}
@@ -4912,29 +5015,29 @@ snapshots:
dependencies:
'@jridgewell/trace-mapping': 0.3.9
'@effect/cli@0.36.21(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1))(@effect/printer-ansi@0.33.12(@effect/typeclass@0.24.12(effect@3.2.1))(effect@3.2.1))(@effect/printer@0.33.12(@effect/typeclass@0.24.12(effect@3.2.1))(effect@3.2.1))(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1)':
'@effect/cli@0.36.21(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2))(@effect/printer-ansi@0.33.12(@effect/typeclass@0.24.12(effect@3.5.2))(effect@3.5.2))(@effect/printer@0.33.12(@effect/typeclass@0.24.12(effect@3.5.2))(effect@3.5.2))(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2)':
dependencies:
'@effect/platform': 0.53.2(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1)
'@effect/printer': 0.33.12(@effect/typeclass@0.24.12(effect@3.2.1))(effect@3.2.1)
'@effect/printer-ansi': 0.33.12(@effect/typeclass@0.24.12(effect@3.2.1))(effect@3.2.1)
'@effect/schema': 0.66.16(effect@3.2.1)(fast-check@3.17.2)
effect: 3.2.1
'@effect/platform': 0.53.2(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2)
'@effect/printer': 0.33.12(@effect/typeclass@0.24.12(effect@3.5.2))(effect@3.5.2)
'@effect/printer-ansi': 0.33.12(@effect/typeclass@0.24.12(effect@3.5.2))(effect@3.5.2)
'@effect/schema': 0.66.16(effect@3.5.2)(fast-check@3.17.2)
effect: 3.5.2
ini: 4.1.2
toml: 3.0.0
yaml: 2.4.2
'@effect/platform-node-shared@0.4.21(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1))(effect@3.2.1)':
'@effect/platform-node-shared@0.4.21(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2))(effect@3.5.2)':
dependencies:
'@effect/platform': 0.53.2(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1)
'@effect/platform': 0.53.2(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2)
'@parcel/watcher': 2.4.1
effect: 3.2.1
effect: 3.5.2
multipasta: 0.2.1
'@effect/platform-node@0.49.2(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1))(effect@3.2.1)':
'@effect/platform-node@0.49.2(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2))(effect@3.5.2)':
dependencies:
'@effect/platform': 0.53.2(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1)
'@effect/platform-node-shared': 0.4.21(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1))(effect@3.2.1)
effect: 3.2.1
'@effect/platform': 0.53.2(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2)
'@effect/platform-node-shared': 0.4.21(@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2))(effect@3.5.2)
effect: 3.5.2
mime: 3.0.0
undici: 6.16.1
ws: 8.17.0
@@ -4942,33 +5045,33 @@ snapshots:
- bufferutil
- utf-8-validate
'@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2))(effect@3.2.1)':
'@effect/platform@0.53.2(@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2))(effect@3.5.2)':
dependencies:
'@effect/schema': 0.66.16(effect@3.2.1)(fast-check@3.17.2)
effect: 3.2.1
'@effect/schema': 0.66.16(effect@3.5.2)(fast-check@3.17.2)
effect: 3.5.2
find-my-way-ts: 0.1.2
multipasta: 0.2.1
path-browserify: 1.0.1
'@effect/printer-ansi@0.33.12(@effect/typeclass@0.24.12(effect@3.2.1))(effect@3.2.1)':
'@effect/printer-ansi@0.33.12(@effect/typeclass@0.24.12(effect@3.5.2))(effect@3.5.2)':
dependencies:
'@effect/printer': 0.33.12(@effect/typeclass@0.24.12(effect@3.2.1))(effect@3.2.1)
'@effect/typeclass': 0.24.12(effect@3.2.1)
effect: 3.2.1
'@effect/printer': 0.33.12(@effect/typeclass@0.24.12(effect@3.5.2))(effect@3.5.2)
'@effect/typeclass': 0.24.12(effect@3.5.2)
effect: 3.5.2
'@effect/printer@0.33.12(@effect/typeclass@0.24.12(effect@3.2.1))(effect@3.2.1)':
'@effect/printer@0.33.12(@effect/typeclass@0.24.12(effect@3.5.2))(effect@3.5.2)':
dependencies:
'@effect/typeclass': 0.24.12(effect@3.2.1)
effect: 3.2.1
'@effect/typeclass': 0.24.12(effect@3.5.2)
effect: 3.5.2
'@effect/schema@0.66.16(effect@3.2.1)(fast-check@3.17.2)':
'@effect/schema@0.66.16(effect@3.5.2)(fast-check@3.17.2)':
dependencies:
effect: 3.2.1
effect: 3.5.2
fast-check: 3.17.2
'@effect/typeclass@0.24.12(effect@3.2.1)':
'@effect/typeclass@0.24.12(effect@3.5.2)':
dependencies:
effect: 3.2.1
effect: 3.5.2
'@esbuild/aix-ppc64@0.19.10':
optional: true
@@ -6581,7 +6684,7 @@ snapshots:
unzipper: 0.10.14
which: 4.0.0
effect@3.2.1: {}
effect@3.5.2: {}
electron-to-chromium@1.4.615: {}