Compare commits
41 Commits
react-perf
...
jazz-nodej
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b09e35e372 | ||
|
|
d2c8121c9c | ||
|
|
380bb88ffa | ||
|
|
6ab53c263d | ||
|
|
e7f3e4e242 | ||
|
|
8bb5201647 | ||
|
|
a9fc94f53d | ||
|
|
ca7c0510d1 | ||
|
|
1bf16f0859 | ||
|
|
21b503c188 | ||
|
|
0053e9796c | ||
|
|
e84941b1b1 | ||
|
|
57f6f8d67e | ||
|
|
5b8e69d973 | ||
|
|
7213b1bfa3 | ||
|
|
11f0770f08 | ||
|
|
44e6dc3ae8 | ||
|
|
b5d20d2488 | ||
|
|
0185545838 | ||
|
|
8c8f85859c | ||
|
|
104384409e | ||
|
|
179827ae56 | ||
|
|
6645829876 | ||
|
|
68cb302722 | ||
|
|
8dc33f2790 | ||
|
|
5f64ba326c | ||
|
|
7ccb15107c | ||
|
|
b102964743 | ||
|
|
216d50a09c | ||
|
|
07ea59fdcb | ||
|
|
932a84a47f | ||
|
|
34dda7bdbd | ||
|
|
49fa153581 | ||
|
|
c80b827775 | ||
|
|
a2bf9f988a | ||
|
|
ac27b2d5c2 | ||
|
|
c813518fdc | ||
|
|
d5034ed5c3 | ||
|
|
cf2c29a365 | ||
|
|
d948823db6 | ||
|
|
060ad4630d |
86
.github/workflows/build-and-deploy.yaml
vendored
86
.github/workflows/build-and-deploy.yaml
vendored
@@ -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:
|
||||
@@ -53,59 +53,12 @@ jobs:
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
build-homepage:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: gardencmp
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Pnpm Install (root)
|
||||
run: |
|
||||
pnpm install
|
||||
working-directory: .
|
||||
|
||||
- name: Pnpm Install & Build (homepage)
|
||||
run: |
|
||||
pnpm install
|
||||
pnpm build;
|
||||
working-directory: ./homepage/homepage
|
||||
|
||||
- name: Docker Build & Push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: ./homepage
|
||||
push: true
|
||||
tags: ghcr.io/gardencmp/${{github.event.repository.name}}-homepage-jazz:${{github.head_ref || github.ref_name}}-${{github.sha}}-${{github.run_number}}-${{github.run_attempt}}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
deploy-examples:
|
||||
runs-on: ubuntu-latest
|
||||
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:
|
||||
@@ -135,37 +88,4 @@ jobs:
|
||||
envsubst '${DOCKER_USER} ${DOCKER_PASSWORD} ${DOCKER_TAG} ${BRANCH_SUFFIX} ${BRANCH_SUBDOMAIN}' < job-template.nomad > job-instance.nomad;
|
||||
cat job-instance.nomad;
|
||||
NOMAD_ADDR=${{ secrets.NOMAD_ADDR }} nomad job run job-instance.nomad;
|
||||
working-directory: ./examples/${{ matrix.example }}
|
||||
|
||||
deploy-homepage:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-homepage
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: gacts/install-nomad@v1
|
||||
- name: Tailscale
|
||||
uses: tailscale/github-action@v1
|
||||
with:
|
||||
authkey: ${{ secrets.TAILSCALE_AUTHKEY }}
|
||||
|
||||
- name: Deploy on Nomad
|
||||
run: |
|
||||
if [ "${{github.ref_name}}" == "main" ]; then
|
||||
export BRANCH_SUFFIX="";
|
||||
export BRANCH_SUBDOMAIN="";
|
||||
else
|
||||
export BRANCH_SUFFIX=-${{github.head_ref || github.ref_name}};
|
||||
export BRANCH_SUBDOMAIN=${{github.head_ref || github.ref_name}}.;
|
||||
fi
|
||||
|
||||
export DOCKER_USER=gardencmp;
|
||||
export DOCKER_PASSWORD=${{ secrets.DOCKER_PULL_PAT }};
|
||||
export DOCKER_TAG=ghcr.io/gardencmp/${{github.event.repository.name}}-homepage-jazz:${{github.head_ref || github.ref_name}}-${{github.sha}}-${{github.run_number}}-${{github.run_attempt}};
|
||||
|
||||
envsubst '${DOCKER_USER} ${DOCKER_PASSWORD} ${DOCKER_TAG} ${BRANCH_SUFFIX} ${BRANCH_SUBDOMAIN}' < job-template.nomad > job-instance.nomad;
|
||||
cat job-instance.nomad;
|
||||
NOMAD_ADDR=${{ secrets.NOMAD_ADDR }} nomad job run job-instance.nomad;
|
||||
working-directory: ./homepage
|
||||
working-directory: ./examples/${{ matrix.example }}
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
@@ -1,5 +1,77 @@
|
||||
# jazz-example-chat
|
||||
|
||||
## 0.0.70
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.23
|
||||
- jazz-react@0.7.23
|
||||
- jazz-tools@0.7.23
|
||||
|
||||
## 0.0.69
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.7.22
|
||||
|
||||
## 0.0.68
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.21
|
||||
- jazz-react@0.7.21
|
||||
|
||||
## 0.0.67
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.20
|
||||
- jazz-react@0.7.20
|
||||
|
||||
## 0.0.66
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.19
|
||||
- jazz-react@0.7.19
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-chat",
|
||||
"private": true,
|
||||
"version": "0.0.61",
|
||||
"version": "0.0.70",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
49
examples/inspector/CHANGELOG.md
Normal file
49
examples/inspector/CHANGELOG.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# jazz-example-chat
|
||||
|
||||
## 0.0.51
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.23
|
||||
- cojson-transport-ws@0.7.23
|
||||
|
||||
## 0.0.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-transport-ws@0.7.22
|
||||
|
||||
## 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
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.6.7
|
||||
- jazz-react@0.5.5
|
||||
- jazz-react-auth-local@0.4.18
|
||||
|
||||
## 0.0.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-react@0.5.0
|
||||
- jazz-react-auth-local@0.4.16
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "inspector",
|
||||
"name": "jazz-inspector",
|
||||
"private": true,
|
||||
"version": "0.0.47",
|
||||
"version": "0.0.51",
|
||||
"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",
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
309
examples/inspector/src/app.tsx
Normal file
309
examples/inspector/src/app.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
249
examples/inspector/src/cojson-tree.tsx
Normal file
249
examples/inspector/src/cojson-tree.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,80 @@
|
||||
# jazz-example-pets
|
||||
|
||||
## 0.0.88
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-react@0.7.23
|
||||
- jazz-tools@0.7.23
|
||||
- jazz-browser-media-images@0.7.23
|
||||
|
||||
## 0.0.87
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-browser-media-images@0.7.22
|
||||
- jazz-react@0.7.22
|
||||
|
||||
## 0.0.86
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.21
|
||||
- jazz-browser-media-images@0.7.21
|
||||
- jazz-react@0.7.21
|
||||
|
||||
## 0.0.85
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.20
|
||||
- jazz-browser-media-images@0.7.20
|
||||
- jazz-react@0.7.20
|
||||
|
||||
## 0.0.84
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.19
|
||||
- jazz-browser-media-images@0.7.19
|
||||
- jazz-react@0.7.19
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-pets",
|
||||
"private": true,
|
||||
"version": "0.0.79",
|
||||
"version": "0.0.88",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,72 @@
|
||||
# jazz-example-todo
|
||||
|
||||
## 0.0.87
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-react@0.7.23
|
||||
- jazz-tools@0.7.23
|
||||
|
||||
## 0.0.86
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.7.22
|
||||
|
||||
## 0.0.85
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.21
|
||||
- jazz-react@0.7.21
|
||||
|
||||
## 0.0.84
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.20
|
||||
- jazz-react@0.7.20
|
||||
|
||||
## 0.0.83
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.19
|
||||
- jazz-react@0.7.19
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-todo",
|
||||
"private": true,
|
||||
"version": "0.0.78",
|
||||
"version": "0.0.87",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -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"
|
||||
@@ -108,7 +112,7 @@ export default function RootLayout({
|
||||
<div className="col-span-full md:col-span-1 sm:row-start-4 md:row-start-auto lg:col-span-2 md:row-span-2 md:flex-1 flex flex-row md:flex-col max-sm:mt-4 justify-between max-sm:items-start gap-2 text-sm min-w-[10rem]">
|
||||
<GcmpLogo monochrome className="w-32" />
|
||||
<p className="max-sm:text-right">
|
||||
© 2023
|
||||
© {new Date().getFullYear()}
|
||||
<br />
|
||||
Garden Computing, Inc.
|
||||
</p>
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -83,4 +83,4 @@ export function GcmpLogo({
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
5244
homepage/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,18 +0,0 @@
|
||||
# jazz-example-chat
|
||||
|
||||
## 0.0.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.6.7
|
||||
- jazz-react@0.5.5
|
||||
- jazz-react-auth-local@0.4.18
|
||||
|
||||
## 0.0.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-react@0.5.0
|
||||
- jazz-react-auth-local@0.4.16
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>;
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,9 @@
|
||||
"packages/*",
|
||||
"examples/*"
|
||||
],
|
||||
"packageManager": "pnpm@9.1.4",
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.27.3",
|
||||
"husky": "^9.0.11",
|
||||
"lint-staged": "^15.2.2",
|
||||
"prettier": "^3.1.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"turbo": "^1.11.2",
|
||||
@@ -24,8 +23,7 @@
|
||||
"format": "pnpm run -r format && cd homepage/homepage && pnpm run format",
|
||||
"changeset": "changeset",
|
||||
"changeset-version": "changeset version",
|
||||
"release": "pnpm changeset publish && git push --follow-tags",
|
||||
"prepare": "husky"
|
||||
"release": "pnpm changeset publish && git push --follow-tags"
|
||||
},
|
||||
"lint-staged": {},
|
||||
"version": "0.0.0"
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# cojson-storage-indexeddb
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.23
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "cojson-storage-indexeddb",
|
||||
"version": "0.7.14",
|
||||
"version": "0.7.23",
|
||||
"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": {
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# cojson-storage-sqlite
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.23
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"name": "cojson-storage-sqlite",
|
||||
"type": "module",
|
||||
"version": "0.7.14",
|
||||
"version": "0.7.23",
|
||||
"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": {
|
||||
|
||||
@@ -1,5 +1,32 @@
|
||||
# cojson-transport-nodejs-ws
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.23
|
||||
|
||||
## 0.7.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Increase disconnect timeout for now
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "cojson-transport-ws",
|
||||
"type": "module",
|
||||
"version": "0.7.14",
|
||||
"version": "0.7.23",
|
||||
"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": {
|
||||
|
||||
@@ -1,20 +1,37 @@
|
||||
import { DisconnectedError, Peer, PingTimeoutError, SyncMessage } from "cojson";
|
||||
import { Either, Stream, Queue, Effect, Exit } from "effect";
|
||||
import { Stream, Queue, Effect, Console } from "effect";
|
||||
|
||||
interface WebsocketEvents {
|
||||
close: { code: number; reason: string };
|
||||
message: { data: unknown };
|
||||
open: void;
|
||||
}
|
||||
interface PingMsg {
|
||||
time: number;
|
||||
dc: string;
|
||||
}
|
||||
|
||||
interface AnyWebSocket {
|
||||
addEventListener(
|
||||
type: "close",
|
||||
listener: (event: { code: number; reason: string }) => void,
|
||||
addEventListener<K extends keyof WebsocketEvents>(
|
||||
type: K,
|
||||
listener: (event: WebsocketEvents[K]) => void,
|
||||
): void;
|
||||
addEventListener(
|
||||
type: "message",
|
||||
listener: (event: { data: string | unknown }) => void,
|
||||
removeEventListener<K extends keyof WebsocketEvents>(
|
||||
type: K,
|
||||
listener: (event: WebsocketEvents[K]) => void,
|
||||
): void;
|
||||
addEventListener(type: "open", listener: () => void): void;
|
||||
close(): void;
|
||||
send(data: string): void;
|
||||
}
|
||||
|
||||
const g: typeof globalThis & {
|
||||
jazzPings?: {
|
||||
received: number;
|
||||
sent: number;
|
||||
dc: string;
|
||||
}[];
|
||||
} = globalThis;
|
||||
|
||||
export function createWebSocketPeer(options: {
|
||||
id: string;
|
||||
websocket: AnyWebSocket;
|
||||
@@ -22,87 +39,81 @@ export function createWebSocketPeer(options: {
|
||||
}): Effect.Effect<Peer> {
|
||||
return Effect.gen(function* () {
|
||||
const ws = options.websocket;
|
||||
const ws_ = ws as unknown as Stream.EventListener<WebsocketEvents["message"]>;
|
||||
|
||||
const incoming =
|
||||
yield* Queue.unbounded<
|
||||
Either.Either<SyncMessage, DisconnectedError | PingTimeoutError>
|
||||
>();
|
||||
const outgoing = yield* Queue.unbounded<SyncMessage>();
|
||||
|
||||
ws.addEventListener("close", (event) => {
|
||||
void Effect.runPromiseExit(
|
||||
Queue.offer(
|
||||
incoming,
|
||||
Either.left(
|
||||
new DisconnectedError(`${event.code}: ${event.reason}`),
|
||||
const closed = once(ws, "close").pipe(
|
||||
Effect.flatMap(
|
||||
(event) =>
|
||||
new DisconnectedError({
|
||||
message: `${event.code}: ${event.reason}`,
|
||||
}),
|
||||
),
|
||||
Stream.fromEffect,
|
||||
);
|
||||
|
||||
const isSyncMessage = (msg: unknown): msg is SyncMessage => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
if ((msg as any)?.type === "ping") {
|
||||
const ping = msg as PingMsg;
|
||||
g.jazzPings ||= [];
|
||||
g.jazzPings.push({
|
||||
received: Date.now(),
|
||||
sent: ping.time,
|
||||
dc: ping.dc,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
yield* Effect.forkDaemon(Effect.gen(function* () {
|
||||
yield* once(ws, "open");
|
||||
yield* Queue.take(outgoing).pipe(
|
||||
Effect.andThen((message) => ws.send(JSON.stringify(message))),
|
||||
Effect.forever,
|
||||
);
|
||||
}));
|
||||
|
||||
type E = WebsocketEvents["message"];
|
||||
const messages = Stream.fromEventListener<E>(ws_, "message").pipe(
|
||||
Stream.timeoutFail(() => new PingTimeoutError(), "10 seconds"),
|
||||
Stream.tapError((_e) =>
|
||||
Console.warn("Ping timeout").pipe(
|
||||
Effect.andThen(Effect.try(() => ws.close())),
|
||||
Effect.catchAll((e) =>
|
||||
Console.error(
|
||||
"Error while trying to close ws on ping timeout",
|
||||
e,
|
||||
),
|
||||
),
|
||||
),
|
||||
).then((e) => {
|
||||
if (Exit.isFailure(e) && !Exit.isInterrupted(e)) {
|
||||
console.warn("Failed closing ws", e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let pingTimeout: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
ws.addEventListener("message", (event) => {
|
||||
const msg = JSON.parse(event.data as string);
|
||||
|
||||
if (pingTimeout) {
|
||||
clearTimeout(pingTimeout);
|
||||
}
|
||||
|
||||
pingTimeout = setTimeout(() => {
|
||||
console.debug("Ping timeout");
|
||||
void Effect.runPromise(
|
||||
Queue.offer(incoming, Either.left(new PingTimeoutError())),
|
||||
);
|
||||
try {
|
||||
ws.close();
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"Error while trying to close ws on ping timeout",
|
||||
e,
|
||||
);
|
||||
}
|
||||
}, 2500);
|
||||
|
||||
if (msg.type === "ping") {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(globalThis as any).jazzPings =
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(globalThis as any).jazzPings || [];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(globalThis as any).jazzPings.push({
|
||||
received: Date.now(),
|
||||
sent: msg.time,
|
||||
dc: msg.dc,
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
void Effect.runPromise(
|
||||
Queue.offer(incoming, Either.right(msg)),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
ws.addEventListener("open", () => {
|
||||
void Stream.fromQueue(outgoing).pipe(
|
||||
Stream.runForEach((msg) =>
|
||||
Effect.sync(() => ws.send(JSON.stringify(msg))),
|
||||
),
|
||||
Effect.runPromise,
|
||||
);
|
||||
});
|
||||
),
|
||||
Stream.mergeLeft(closed),
|
||||
Stream.map((_) => JSON.parse(_.data as string)),
|
||||
Stream.filter(isSyncMessage),
|
||||
Stream.buffer({ capacity: "unbounded" }),
|
||||
Stream.onDone(() => Queue.shutdown(outgoing)),
|
||||
);
|
||||
|
||||
return {
|
||||
id: options.id,
|
||||
incoming: Stream.fromQueue(incoming, { shutdown: true }).pipe(
|
||||
Stream.mapEffect((either) => either),
|
||||
),
|
||||
incoming: messages,
|
||||
outgoing,
|
||||
role: options.role,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const once = <Event extends keyof WebsocketEvents>(
|
||||
ws: AnyWebSocket,
|
||||
event: Event,
|
||||
) =>
|
||||
Effect.async<WebsocketEvents[Event]>((register) => {
|
||||
const cb = (msg: WebsocketEvents[Event]) => {
|
||||
ws.removeEventListener(event, cb);
|
||||
register(Effect.succeed(msg));
|
||||
};
|
||||
ws.addEventListener(event, cb);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# cojson
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Mostly complete OPFS implementation (single-tab only)
|
||||
|
||||
## 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"types": "src/index.ts",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.7.14",
|
||||
"version": "0.7.23",
|
||||
"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": {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { CoValueChunk } from "./index.js";
|
||||
import { RawCoID } from "../ids.js";
|
||||
import { CryptoProvider, StreamingHash } from "../crypto/crypto.js";
|
||||
|
||||
export type BlockFilename = `${string}-L${number}-H${number}.jsonl`;
|
||||
export type BlockFilename = `L${number}-${string}-${string}-H${number}.jsonl`;
|
||||
|
||||
export type BlockHeader = { id: RawCoID; start: number; length: number }[];
|
||||
|
||||
@@ -78,8 +78,9 @@ export function readHeader<RH, FS extends FileSystem<unknown, RH>>(
|
||||
export function writeBlock<WH, RH, FS extends FileSystem<WH, RH>>(
|
||||
chunks: Map<RawCoID, CoValueChunk>,
|
||||
level: number,
|
||||
blockNumber: number,
|
||||
fs: FS,
|
||||
): Effect.Effect<void, FSErr> {
|
||||
): Effect.Effect<BlockFilename, FSErr> {
|
||||
if (chunks.size === 0) {
|
||||
return Effect.die(new Error("No chunks to write"));
|
||||
}
|
||||
@@ -125,12 +126,17 @@ export function writeBlock<WH, RH, FS extends FileSystem<WH, RH>>(
|
||||
// ),
|
||||
// );
|
||||
|
||||
const filename: BlockFilename = `${hash.digest()}-L${level}-H${
|
||||
headerBytes.length
|
||||
}.jsonl`;
|
||||
const filename: BlockFilename = `L${level}-${(
|
||||
blockNumber + ""
|
||||
).padStart(3, "0")}-${hash
|
||||
.digest()
|
||||
.replace("hash_", "")
|
||||
.slice(0, 15)}-H${headerBytes.length}.jsonl`;
|
||||
// console.log("renaming to" + filename);
|
||||
yield* $(fs.closeAndRename(file, filename));
|
||||
|
||||
return filename;
|
||||
|
||||
// console.log("Wrote block", filename, blockHeader);
|
||||
// console.log("IDs in block", blockHeader.map(e => e.id));
|
||||
});
|
||||
@@ -148,6 +154,7 @@ export function writeToWal<WH, RH, FS extends FileSystem<WH, RH>>(
|
||||
...chunk,
|
||||
};
|
||||
const bytes = textEncoder.encode(JSON.stringify(walEntry) + "\n");
|
||||
console.log("writing to WAL", handle, id, bytes.length);
|
||||
yield* $(fs.append(handle, bytes));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import { Effect, Either, Queue, Stream, SynchronizedRef } from "effect";
|
||||
import {
|
||||
Effect,
|
||||
Either,
|
||||
Queue,
|
||||
Stream,
|
||||
SynchronizedRef,
|
||||
Deferred,
|
||||
} from "effect";
|
||||
import { RawCoID } from "../ids.js";
|
||||
import { CoValueHeader, Transaction } from "../coValueCore.js";
|
||||
import { Signature } from "../crypto/crypto.js";
|
||||
@@ -30,6 +37,8 @@ import {
|
||||
} from "./FileSystem.js";
|
||||
export type { FSErr, BlockFilename, WalFilename } from "./FileSystem.js";
|
||||
|
||||
const MAX_N_LEVELS = 3;
|
||||
|
||||
export type CoValueChunk = {
|
||||
header?: CoValueHeader;
|
||||
sessionEntries: {
|
||||
@@ -51,6 +60,10 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
|
||||
BlockFilename,
|
||||
{ [id: RawCoID]: { start: number; length: number } }
|
||||
>();
|
||||
blockFileHandles = new Map<
|
||||
BlockFilename,
|
||||
Deferred.Deferred<{ handle: RH; size: number }, FSErr>
|
||||
>();
|
||||
|
||||
constructor(
|
||||
public fs: FS,
|
||||
@@ -192,7 +205,7 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
|
||||
let newWal = wal;
|
||||
if (!newWal) {
|
||||
newWal = yield* this.fs.createFile(
|
||||
`wal-${new Date().toISOString()}-${Math.random()
|
||||
`wal-${Date.now()}-${Math.random()
|
||||
.toString(36)
|
||||
.slice(2)}.jsonl`,
|
||||
);
|
||||
@@ -314,24 +327,63 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
|
||||
);
|
||||
}
|
||||
|
||||
loadCoValue<WH, RH, FS extends FileSystem<WH, RH>>(
|
||||
getBlockHandle(
|
||||
blockFile: BlockFilename,
|
||||
fs: FS,
|
||||
): Effect.Effect<{ handle: RH; size: number }, FSErr> {
|
||||
return Effect.gen(this, function* () {
|
||||
let handleAndSize = this.blockFileHandles.get(blockFile);
|
||||
if (!handleAndSize) {
|
||||
handleAndSize = yield* Deferred.make<
|
||||
{ handle: RH; size: number },
|
||||
FSErr
|
||||
>();
|
||||
this.blockFileHandles.set(blockFile, handleAndSize);
|
||||
yield* Deferred.complete(
|
||||
handleAndSize,
|
||||
fs.openToRead(blockFile),
|
||||
);
|
||||
}
|
||||
|
||||
return yield* Deferred.await(handleAndSize);
|
||||
});
|
||||
}
|
||||
|
||||
loadCoValue(
|
||||
id: RawCoID,
|
||||
fs: FS,
|
||||
): Effect.Effect<CoValueChunk | undefined, FSErr> {
|
||||
// return _loadChunkFromWal(id, fs);
|
||||
return Effect.gen(this, function* () {
|
||||
const files = this.fileCache || (yield* fs.listFiles());
|
||||
this.fileCache = files;
|
||||
const blockFiles = files.filter((name) =>
|
||||
name.startsWith("hash_"),
|
||||
) as BlockFilename[];
|
||||
const blockFiles = (
|
||||
files.filter((name) => name.startsWith("L")) as BlockFilename[]
|
||||
).sort();
|
||||
|
||||
let result;
|
||||
|
||||
for (const blockFile of blockFiles) {
|
||||
let cachedHeader:
|
||||
| { [id: RawCoID]: { start: number; length: number } }
|
||||
| undefined = this.headerCache.get(blockFile);
|
||||
|
||||
const { handle, size } = yield* fs.openToRead(blockFile);
|
||||
let handleAndSize = this.blockFileHandles.get(blockFile);
|
||||
if (!handleAndSize) {
|
||||
handleAndSize = yield* Deferred.make<
|
||||
{ handle: RH; size: number },
|
||||
FSErr
|
||||
>();
|
||||
this.blockFileHandles.set(blockFile, handleAndSize);
|
||||
yield* Deferred.complete(
|
||||
handleAndSize,
|
||||
fs.openToRead(blockFile),
|
||||
);
|
||||
}
|
||||
|
||||
const { handle, size } = yield* this.getBlockHandle(
|
||||
blockFile,
|
||||
fs,
|
||||
);
|
||||
|
||||
// console.log("Attempting to load", id, blockFile);
|
||||
|
||||
@@ -356,17 +408,29 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
|
||||
|
||||
// console.log("Header entry", id, headerEntry);
|
||||
|
||||
let result;
|
||||
if (headerEntry) {
|
||||
result = yield* readChunk(handle, headerEntry, fs);
|
||||
const nextChunk = yield* readChunk(handle, headerEntry, fs);
|
||||
if (result) {
|
||||
const merged = mergeChunks(result, nextChunk);
|
||||
|
||||
if (Either.isRight(merged)) {
|
||||
yield* Effect.logWarning(
|
||||
"Non-contigous chunks while loading " + id,
|
||||
result,
|
||||
nextChunk,
|
||||
);
|
||||
} else {
|
||||
result = merged.left;
|
||||
}
|
||||
} else {
|
||||
result = nextChunk;
|
||||
}
|
||||
}
|
||||
|
||||
yield* fs.close(handle);
|
||||
|
||||
return result;
|
||||
// yield* fs.close(handle);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -434,11 +498,150 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
|
||||
yield* this.fs.close(handle);
|
||||
}
|
||||
|
||||
yield* writeBlock(coValues, 0, this.fs);
|
||||
const highestBlockNumber = fileNames.reduce((acc, name) => {
|
||||
if (name.startsWith("L" + MAX_N_LEVELS)) {
|
||||
const num = parseInt(name.split("-")[1]!);
|
||||
if (num > acc) {
|
||||
return num;
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, 0);
|
||||
|
||||
console.log(
|
||||
[...coValues.keys()],
|
||||
fileNames,
|
||||
highestBlockNumber,
|
||||
);
|
||||
|
||||
yield* writeBlock(
|
||||
coValues,
|
||||
MAX_N_LEVELS,
|
||||
highestBlockNumber + 1,
|
||||
this.fs,
|
||||
);
|
||||
|
||||
for (const walFile of walFiles) {
|
||||
yield* this.fs.removeFile(walFile);
|
||||
}
|
||||
this.fileCache = undefined;
|
||||
|
||||
const fileNames2 = yield* this.fs.listFiles();
|
||||
|
||||
const blockFiles = (
|
||||
fileNames2.filter((name) =>
|
||||
name.startsWith("L"),
|
||||
) as BlockFilename[]
|
||||
).sort();
|
||||
|
||||
const blockFilesByLevelInOrder: {
|
||||
[level: number]: BlockFilename[];
|
||||
} = {};
|
||||
|
||||
for (const blockFile of blockFiles) {
|
||||
const level = parseInt(blockFile.split("-")[0]!.slice(1));
|
||||
if (!blockFilesByLevelInOrder[level]) {
|
||||
blockFilesByLevelInOrder[level] = [];
|
||||
}
|
||||
blockFilesByLevelInOrder[level]!.push(blockFile);
|
||||
}
|
||||
|
||||
console.log(blockFilesByLevelInOrder);
|
||||
|
||||
for (let level = MAX_N_LEVELS; level > 0; level--) {
|
||||
const nBlocksDesired = Math.pow(2, level);
|
||||
const blocksInLevel = blockFilesByLevelInOrder[level];
|
||||
|
||||
if (
|
||||
blocksInLevel &&
|
||||
blocksInLevel.length > nBlocksDesired
|
||||
) {
|
||||
yield* Effect.log("Compacting blocks in level", level, blocksInLevel);
|
||||
|
||||
const coValues = new Map<RawCoID, CoValueChunk>();
|
||||
|
||||
for (const blockFile of blocksInLevel) {
|
||||
const {
|
||||
handle,
|
||||
size,
|
||||
}: { handle: RH; size: number } =
|
||||
yield* this.getBlockHandle(blockFile, this.fs);
|
||||
|
||||
if (size === 0) {
|
||||
continue;
|
||||
}
|
||||
const header = yield* readHeader(
|
||||
blockFile,
|
||||
handle,
|
||||
size,
|
||||
this.fs,
|
||||
);
|
||||
for (const entry of header) {
|
||||
const chunk = yield* readChunk(
|
||||
handle,
|
||||
entry,
|
||||
this.fs,
|
||||
);
|
||||
|
||||
const existingChunk = coValues.get(entry.id);
|
||||
|
||||
if (existingChunk) {
|
||||
const merged = mergeChunks(
|
||||
existingChunk,
|
||||
chunk,
|
||||
);
|
||||
if (Either.isRight(merged)) {
|
||||
yield* Effect.logWarning(
|
||||
"Non-contigous chunks in " +
|
||||
entry.id +
|
||||
", " +
|
||||
blockFile,
|
||||
existingChunk,
|
||||
chunk,
|
||||
);
|
||||
} else {
|
||||
coValues.set(entry.id, merged.left);
|
||||
}
|
||||
} else {
|
||||
coValues.set(entry.id, chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let levelBelow = blockFilesByLevelInOrder[level - 1];
|
||||
if (!levelBelow) {
|
||||
levelBelow = [];
|
||||
blockFilesByLevelInOrder[level - 1] = levelBelow;
|
||||
}
|
||||
|
||||
const highestBlockNumberInLevelBelow =
|
||||
levelBelow.reduce((acc, name) => {
|
||||
const num = parseInt(name.split("-")[1]!);
|
||||
if (num > acc) {
|
||||
return num;
|
||||
}
|
||||
return acc;
|
||||
}, 0);
|
||||
|
||||
const newBlockName = yield* writeBlock(
|
||||
coValues,
|
||||
level - 1,
|
||||
highestBlockNumberInLevelBelow + 1,
|
||||
this.fs,
|
||||
);
|
||||
levelBelow.push(newBlockName);
|
||||
|
||||
// delete blocks that went into this one
|
||||
for (const blockFile of blocksInLevel) {
|
||||
const handle = yield* this.getBlockHandle(
|
||||
blockFile,
|
||||
this.fs,
|
||||
);
|
||||
yield* this.fs.close(handle.handle);
|
||||
yield* this.fs.removeFile(blockFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -47,18 +47,24 @@ export function newQueuePair(
|
||||
const queue = yield* Queue.unbounded<SyncMessage>();
|
||||
|
||||
if (options.traceAs) {
|
||||
return [Stream.fromQueue(queue).pipe(Stream.tap((msg) => Console.debug(
|
||||
options.traceAs,
|
||||
JSON.stringify(
|
||||
msg,
|
||||
(k, v) =>
|
||||
k === "changes" ||
|
||||
k === "encryptedChanges"
|
||||
? v.slice(0, 20) + "..."
|
||||
: v,
|
||||
2,
|
||||
return [
|
||||
Stream.fromQueue(queue).pipe(
|
||||
Stream.tap((msg) =>
|
||||
Console.debug(
|
||||
options.traceAs,
|
||||
JSON.stringify(
|
||||
msg,
|
||||
(k, v) =>
|
||||
k === "changes" || k === "encryptedChanges"
|
||||
? v.slice(0, 20) + "..."
|
||||
: v,
|
||||
2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
))), queue];
|
||||
queue,
|
||||
];
|
||||
} else {
|
||||
return [Stream.fromQueue(queue), queue];
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { CoValueHeader, Transaction } from "./coValueCore.js";
|
||||
import { CoValueCore } from "./coValueCore.js";
|
||||
import { LocalNode, newLoadingState } from "./localNode.js";
|
||||
import { RawCoID, SessionID } from "./ids.js";
|
||||
import { Effect, Queue, Stream } from "effect";
|
||||
import { Data, Effect, Queue, Stream } from "effect";
|
||||
|
||||
export type CoValueKnownState = {
|
||||
id: RawCoID;
|
||||
@@ -56,12 +56,9 @@ export type DoneMessage = {
|
||||
|
||||
export type PeerID = string;
|
||||
|
||||
export class DisconnectedError extends Error {
|
||||
readonly _tag = "DisconnectedError";
|
||||
constructor(public message: string) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
export class DisconnectedError extends Data.TaggedError("DisconnectedError")<{
|
||||
message: string;
|
||||
}> {}
|
||||
|
||||
export class PingTimeoutError extends Error {
|
||||
readonly _tag = "PingTimeoutError";
|
||||
|
||||
@@ -53,13 +53,15 @@ test("Can create account with one node, and then load it on another", async () =
|
||||
map.set("foo", "bar", "private");
|
||||
expect(map.get("foo")).toEqual("bar");
|
||||
|
||||
const [node1asPeer, node2asPeer] = await Effect.runPromise(connectedPeers("node1", "node2", {
|
||||
trace: true,
|
||||
peer1role: "server",
|
||||
peer2role: "client",
|
||||
}));
|
||||
const [node1asPeer, node2asPeer] = await Effect.runPromise(
|
||||
connectedPeers("node1", "node2", {
|
||||
trace: true,
|
||||
peer1role: "server",
|
||||
peer2role: "client",
|
||||
}),
|
||||
);
|
||||
|
||||
console.log("After connected peers")
|
||||
console.log("After connected peers");
|
||||
|
||||
node.syncManager.addPeer(node2asPeer);
|
||||
|
||||
|
||||
@@ -1,5 +1,65 @@
|
||||
# jazz-browser-media-images
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.23
|
||||
- jazz-browser@0.7.23
|
||||
|
||||
## 0.7.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-browser@0.7.22
|
||||
|
||||
## 0.7.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.21
|
||||
- jazz-browser@0.7.21
|
||||
|
||||
## 0.7.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.20
|
||||
- jazz-browser@0.7.20
|
||||
|
||||
## 0.7.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.19
|
||||
- jazz-browser@0.7.19
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jazz-browser-media-images",
|
||||
"version": "0.7.14",
|
||||
"version": "0.7.23",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
|
||||
@@ -1,5 +1,70 @@
|
||||
# jazz-browser
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.23
|
||||
- jazz-tools@0.7.23
|
||||
- cojson-storage-indexeddb@0.7.23
|
||||
- cojson-transport-ws@0.7.23
|
||||
|
||||
## 0.7.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-transport-ws@0.7.22
|
||||
|
||||
## 0.7.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.21
|
||||
|
||||
## 0.7.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.20
|
||||
|
||||
## 0.7.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.19
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jazz-browser",
|
||||
"version": "0.7.14",
|
||||
"version": "0.7.23",
|
||||
"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"
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from "cojson";
|
||||
import { Effect } from "effect";
|
||||
|
||||
export class OPFSFilesystem implements FileSystem<number, number> {
|
||||
export class OPFSFilesystem implements FileSystem<{id: number, filename: string}, {id: number, filename: string}> {
|
||||
opfsWorker: Worker;
|
||||
callbacks: Map<number, (event: MessageEvent) => void> = new Map();
|
||||
nextRequestId = 0;
|
||||
@@ -31,13 +31,13 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
||||
listFiles(): Effect.Effect<string[], FSErr, never> {
|
||||
return Effect.async((cb) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("listFiles" + requestId);
|
||||
performance.mark("listFiles" + requestId + "_listFiles");
|
||||
this.callbacks.set(requestId, (event) => {
|
||||
performance.mark("listFilesEnd" + requestId);
|
||||
performance.mark("listFilesEnd" + requestId + "_listFiles");
|
||||
performance.measure(
|
||||
"listFiles" + requestId,
|
||||
"listFiles" + requestId,
|
||||
"listFilesEnd" + requestId,
|
||||
"listFiles" + requestId + "_listFiles",
|
||||
"listFiles" + requestId + "_listFiles",
|
||||
"listFilesEnd" + requestId + "_listFiles",
|
||||
);
|
||||
cb(Effect.succeed(event.data.fileNames));
|
||||
});
|
||||
@@ -47,22 +47,22 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
||||
|
||||
openToRead(
|
||||
filename: string,
|
||||
): Effect.Effect<{ handle: number; size: number }, FSErr, never> {
|
||||
): Effect.Effect<{ handle: {id: number, filename: string}; size: number }, FSErr, never> {
|
||||
return Effect.async((cb) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("openToRead" + requestId);
|
||||
performance.mark("openToRead" + "_" + filename);
|
||||
this.callbacks.set(requestId, (event) => {
|
||||
cb(
|
||||
Effect.succeed({
|
||||
handle: event.data.handle,
|
||||
handle: {id: event.data.handle, filename},
|
||||
size: event.data.size,
|
||||
}),
|
||||
);
|
||||
performance.mark("openToReadEnd" + requestId);
|
||||
performance.mark("openToReadEnd" + "_" + filename);
|
||||
performance.measure(
|
||||
"openToRead" + requestId,
|
||||
"openToRead" + requestId,
|
||||
"openToReadEnd" + requestId,
|
||||
"openToRead" + "_" + filename,
|
||||
"openToRead" + "_" + filename,
|
||||
"openToReadEnd" + "_" + filename,
|
||||
);
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
@@ -73,18 +73,18 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
||||
});
|
||||
}
|
||||
|
||||
createFile(filename: string): Effect.Effect<number, FSErr, never> {
|
||||
createFile(filename: string): Effect.Effect<{id: number, filename: string}, FSErr, never> {
|
||||
return Effect.async((cb) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("createFile" + requestId);
|
||||
performance.mark("createFile" + "_" + filename);
|
||||
this.callbacks.set(requestId, (event) => {
|
||||
performance.mark("createFileEnd" + requestId);
|
||||
performance.mark("createFileEnd" + "_" + filename);
|
||||
performance.measure(
|
||||
"createFile" + requestId,
|
||||
"createFile" + requestId,
|
||||
"createFileEnd" + requestId,
|
||||
"createFile" + "_" + filename,
|
||||
"createFile" + "_" + filename,
|
||||
"createFileEnd" + "_" + filename,
|
||||
);
|
||||
cb(Effect.succeed(event.data.handle));
|
||||
cb(Effect.succeed({id: event.data.handle, filename}));
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "createFile",
|
||||
@@ -96,18 +96,18 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
||||
|
||||
openToWrite(
|
||||
filename: string,
|
||||
): Effect.Effect<FileSystemFileHandle, FSErr, never> {
|
||||
): Effect.Effect<{id: number, filename: string}, FSErr, never> {
|
||||
return Effect.async((cb) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("openToWrite" + requestId);
|
||||
performance.mark("openToWrite" + "_" + filename);
|
||||
this.callbacks.set(requestId, (event) => {
|
||||
performance.mark("openToWriteEnd" + requestId);
|
||||
performance.mark("openToWriteEnd" + "_" + filename);
|
||||
performance.measure(
|
||||
"openToWrite" + requestId,
|
||||
"openToWrite" + requestId,
|
||||
"openToWriteEnd" + requestId,
|
||||
"openToWrite" + "_" + filename,
|
||||
"openToWrite" + "_" + filename,
|
||||
"openToWriteEnd" + "_" + filename,
|
||||
);
|
||||
cb(Effect.succeed(event.data.handle));
|
||||
cb(Effect.succeed({id: event.data.handle, filename}));
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "openToWrite",
|
||||
@@ -118,24 +118,24 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
||||
}
|
||||
|
||||
append(
|
||||
handle: number,
|
||||
handle: {id: number, filename: string},
|
||||
data: Uint8Array,
|
||||
): Effect.Effect<void, FSErr, never> {
|
||||
return Effect.async((cb) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("append" + requestId);
|
||||
performance.mark("append" + "_" + handle.filename);
|
||||
this.callbacks.set(requestId, (_) => {
|
||||
performance.mark("appendEnd" + requestId);
|
||||
performance.mark("appendEnd" + "_" + handle.filename);
|
||||
performance.measure(
|
||||
"append" + requestId,
|
||||
"append" + requestId,
|
||||
"appendEnd" + requestId,
|
||||
"append" + "_" + handle.filename,
|
||||
"append" + "_" + handle.filename,
|
||||
"appendEnd" + "_" + handle.filename,
|
||||
);
|
||||
cb(Effect.succeed(undefined));
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "append",
|
||||
handle,
|
||||
handle: handle.id,
|
||||
data,
|
||||
requestId,
|
||||
});
|
||||
@@ -143,25 +143,25 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
||||
}
|
||||
|
||||
read(
|
||||
handle: number,
|
||||
handle: {id: number, filename: string},
|
||||
offset: number,
|
||||
length: number,
|
||||
): Effect.Effect<Uint8Array, FSErr, never> {
|
||||
return Effect.async((cb) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("read" + requestId);
|
||||
performance.mark("read" + "_" + handle.filename);
|
||||
this.callbacks.set(requestId, (event) => {
|
||||
performance.mark("readEnd" + requestId);
|
||||
performance.mark("readEnd" + "_" + handle.filename);
|
||||
performance.measure(
|
||||
"read" + requestId,
|
||||
"read" + requestId,
|
||||
"readEnd" + requestId,
|
||||
"read" + "_" + handle.filename,
|
||||
"read" + "_" + handle.filename,
|
||||
"readEnd" + "_" + handle.filename,
|
||||
);
|
||||
cb(Effect.succeed(event.data.data));
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "read",
|
||||
handle,
|
||||
handle: handle.id,
|
||||
offset,
|
||||
length,
|
||||
requestId,
|
||||
@@ -169,46 +169,48 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
||||
});
|
||||
}
|
||||
|
||||
close(handle: number): Effect.Effect<void, FSErr, never> {
|
||||
close(handle: {id: number, filename: string}): Effect.Effect<void, FSErr, never> {
|
||||
return Effect.async((cb) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("close" + requestId);
|
||||
performance.mark("close" + "_" + handle.filename);
|
||||
this.callbacks.set(requestId, (_) => {
|
||||
performance.mark("closeEnd" + requestId);
|
||||
performance.mark("closeEnd" + "_" + handle.filename);
|
||||
performance.measure(
|
||||
"close" + requestId,
|
||||
"close" + requestId,
|
||||
"closeEnd" + requestId,
|
||||
"close" + "_" + handle.filename,
|
||||
"close" + "_" + handle.filename,
|
||||
"closeEnd" + "_" + handle.filename,
|
||||
);
|
||||
cb(Effect.succeed(undefined));
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "close",
|
||||
handle,
|
||||
handle: handle.id,
|
||||
requestId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
closeAndRename(
|
||||
handle: number,
|
||||
handle: {id: number, filename: string},
|
||||
filename: BlockFilename,
|
||||
): Effect.Effect<void, FSErr, never> {
|
||||
return Effect.async((cb) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("closeAndRename" + requestId);
|
||||
performance.mark("closeAndRename" + "_" + handle.filename);
|
||||
this.callbacks.set(requestId, () => {
|
||||
performance.mark("closeAndRenameEnd" + requestId);
|
||||
performance.mark(
|
||||
"closeAndRenameEnd" + "_" + handle.filename,
|
||||
);
|
||||
performance.measure(
|
||||
"closeAndRename" + requestId,
|
||||
"closeAndRename" + requestId,
|
||||
"closeAndRenameEnd" + requestId,
|
||||
"closeAndRename" + "_" + handle.filename,
|
||||
"closeAndRename" + "_" + handle.filename,
|
||||
"closeAndRenameEnd" + "_" + handle.filename,
|
||||
);
|
||||
cb(Effect.succeed(undefined));
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "closeAndRename",
|
||||
handle,
|
||||
handle: handle.id,
|
||||
filename,
|
||||
requestId,
|
||||
});
|
||||
@@ -220,13 +222,13 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
||||
): Effect.Effect<void, FSErr, never> {
|
||||
return Effect.async((cb) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("removeFile" + requestId);
|
||||
performance.mark("removeFile" + "_" + filename);
|
||||
this.callbacks.set(requestId, () => {
|
||||
performance.mark("removeFileEnd" + requestId);
|
||||
performance.mark("removeFileEnd" + "_" + filename);
|
||||
performance.measure(
|
||||
"removeFile" + requestId,
|
||||
"removeFile" + requestId,
|
||||
"removeFileEnd" + requestId,
|
||||
"removeFile" + "_" + filename,
|
||||
"removeFile" + "_" + filename,
|
||||
"removeFileEnd" + "_" + filename,
|
||||
);
|
||||
cb(Effect.succeed(undefined));
|
||||
});
|
||||
|
||||
@@ -10,10 +10,7 @@ import {
|
||||
WasmCrypto,
|
||||
CryptoProvider,
|
||||
} from "jazz-tools";
|
||||
import {
|
||||
AccountID,
|
||||
LSMStorage,
|
||||
} from "cojson";
|
||||
import { AccountID, LSMStorage } from "cojson";
|
||||
import { AuthProvider } from "./auth/auth.js";
|
||||
import { OPFSFilesystem } from "./OPFSFilesystem.js";
|
||||
import { IDBStorage } from "cojson-storage-indexeddb";
|
||||
@@ -39,7 +36,7 @@ export async function createJazzBrowserContext<Acc extends Account>({
|
||||
auth: AuthProvider<Acc>;
|
||||
peer: `wss://${string}` | `ws://${string}`;
|
||||
reconnectionTimeout?: number;
|
||||
storage?: "indexedDB" | "experimentalOPFSdoNotUseOrYouWillBeFired";
|
||||
storage?: "indexedDB" | "singleTabOPFS";
|
||||
crypto?: CryptoProvider;
|
||||
}): Promise<BrowserContext<Acc>> {
|
||||
const crypto = customCrypto || (await WasmCrypto.create());
|
||||
|
||||
@@ -1,5 +1,67 @@
|
||||
# jazz-autosub
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.23
|
||||
- jazz-tools@0.7.23
|
||||
- cojson-transport-ws@0.7.23
|
||||
|
||||
## 0.7.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-transport-ws@0.7.22
|
||||
|
||||
## 0.7.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.21
|
||||
|
||||
## 0.7.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.20
|
||||
|
||||
## 0.7.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.19
|
||||
|
||||
## 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
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
"types": "src/index.ts",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.7.14",
|
||||
"version": "0.7.23",
|
||||
"dependencies": {
|
||||
"cojson": "workspace:*",
|
||||
"cojson-transport-ws": "workspace:*",
|
||||
"effect": "^3.1.5",
|
||||
"effect": "^3.5.2",
|
||||
"jazz-tools": "workspace:*",
|
||||
"ws": "^8.14.2"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,77 @@
|
||||
# jazz-react
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Mostly complete OPFS implementation (single-tab only)
|
||||
- Updated dependencies
|
||||
- cojson@0.7.23
|
||||
- jazz-tools@0.7.23
|
||||
- jazz-browser@0.7.23
|
||||
|
||||
## 0.7.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-browser@0.7.22
|
||||
|
||||
## 0.7.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.21
|
||||
- jazz-browser@0.7.21
|
||||
|
||||
## 0.7.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.20
|
||||
- jazz-browser@0.7.20
|
||||
|
||||
## 0.7.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.19
|
||||
- jazz-browser@0.7.19
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jazz-react",
|
||||
"version": "0.7.14",
|
||||
"version": "0.7.23",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
|
||||
@@ -104,7 +104,10 @@ const DemoAuthBasicUI = ({
|
||||
signUp: (username: string) => void;
|
||||
}) => {
|
||||
const [username, setUsername] = useState<string>("");
|
||||
const darkMode = typeof window !== 'undefined' ? window.matchMedia("(prefers-color-scheme: dark)").matches : false;
|
||||
const darkMode =
|
||||
typeof window !== "undefined"
|
||||
? window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
: false;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -23,7 +23,7 @@ export function createJazzReactContext<Acc extends Account>({
|
||||
}: {
|
||||
auth: ReactAuthHook<Acc>;
|
||||
peer: `wss://${string}` | `ws://${string}`;
|
||||
storage?: "indexedDB" | "experimentalOPFSdoNotUseOrYouWillBeFired";
|
||||
storage?: "indexedDB" | "singleTabOPFS";
|
||||
}): JazzReactContext<Acc> {
|
||||
const JazzContext = React.createContext<
|
||||
| {
|
||||
@@ -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>({
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,5 +1,67 @@
|
||||
# jazz-autosub
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.23
|
||||
- jazz-tools@0.7.23
|
||||
- cojson-transport-ws@0.7.23
|
||||
|
||||
## 0.7.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-transport-ws@0.7.22
|
||||
|
||||
## 0.7.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.21
|
||||
|
||||
## 0.7.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.20
|
||||
|
||||
## 0.7.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.19
|
||||
|
||||
## 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"bin": "./dist/index.js",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.7.14",
|
||||
"version": "0.7.23",
|
||||
"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"
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Command, Options } from "@effect/cli";
|
||||
import { NodeContext, NodeRuntime } from "@effect/platform-node";
|
||||
import { Console, Effect } from "effect";
|
||||
import { createWebSocketPeer } from "cojson-transport-ws";
|
||||
import { WebSocket } from "ws"
|
||||
import { WebSocket } from "ws";
|
||||
import {
|
||||
Account,
|
||||
WasmCrypto,
|
||||
|
||||
@@ -1,5 +1,51 @@
|
||||
# jazz-autosub
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Mostly complete OPFS implementation (single-tab only)
|
||||
- Updated dependencies
|
||||
- cojson@0.7.23
|
||||
|
||||
## 0.7.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix another bug in CoMap 'has' proxy trap
|
||||
|
||||
## 0.7.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix bug in CoMap 'has' trap
|
||||
|
||||
## 0.7.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Add support for "in" operator in CoMaps
|
||||
|
||||
## 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
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
"types": "./src/index.ts",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.7.14",
|
||||
"version": "0.7.23",
|
||||
"dependencies": {
|
||||
"@effect/schema": "^0.66.16",
|
||||
"cojson": "workspace:*",
|
||||
"effect": "^3.1.5",
|
||||
"effect": "^3.5.2",
|
||||
"fast-check": "^3.17.2"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -224,11 +224,13 @@ export class Account extends CoValueBase implements CoValue {
|
||||
},
|
||||
) {
|
||||
// TODO: is there a cleaner way to do this?
|
||||
const connectedPeers = await Effect.runPromise(cojsonInternals.connectedPeers(
|
||||
"creatingAccount",
|
||||
"createdAccount",
|
||||
{ peer1role: "server", peer2role: "client" },
|
||||
));
|
||||
const connectedPeers = await Effect.runPromise(
|
||||
cojsonInternals.connectedPeers(
|
||||
"creatingAccount",
|
||||
"createdAccount",
|
||||
{ peer1role: "server", peer2role: "client" },
|
||||
),
|
||||
);
|
||||
|
||||
as._raw.core.node.syncManager.addPeer(connectedPeers[1]);
|
||||
|
||||
|
||||
@@ -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 ||= {};
|
||||
@@ -609,6 +610,16 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
|
||||
}
|
||||
}
|
||||
},
|
||||
has(target, key) {
|
||||
const descriptor = (target._schema?.[key as keyof CoMap["_schema"]] ||
|
||||
target._schema?.[ItemsSym]) as Schema;
|
||||
|
||||
if (target._raw && typeof key === "string" && descriptor) {
|
||||
return target._raw.get(key) !== undefined;
|
||||
} else {
|
||||
return Reflect.has(target, key);
|
||||
}
|
||||
},
|
||||
deleteProperty(target, key) {
|
||||
const descriptor = (target._schema[key as keyof CoMap["_schema"]] ||
|
||||
target._schema[ItemsSym]) as Schema;
|
||||
|
||||
@@ -17,6 +17,36 @@ export type IfCo<C, R> = C extends infer _A | infer B
|
||||
: never;
|
||||
export type UnCo<T> = T extends co<infer A> ? A : T;
|
||||
|
||||
const optional = {
|
||||
ref: optionalRef,
|
||||
json<T extends JsonValue>(): co<T | undefined> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return { [SchemaInit]: "json" satisfies Schema } as any;
|
||||
},
|
||||
encoded<T>(arg: OptionalEncoder<T>): co<T> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return { [SchemaInit]: { encoded: arg } satisfies Schema } as any;
|
||||
},
|
||||
string: {
|
||||
[SchemaInit]: "json" satisfies Schema,
|
||||
} as unknown as co<string | undefined>,
|
||||
number: {
|
||||
[SchemaInit]: "json" satisfies Schema,
|
||||
} as unknown as co<number | undefined>,
|
||||
boolean: {
|
||||
[SchemaInit]: "json" satisfies Schema,
|
||||
} as unknown as co<boolean | undefined>,
|
||||
null: {
|
||||
[SchemaInit]: "json" satisfies Schema,
|
||||
} as unknown as co<null | undefined>,
|
||||
literal<T extends (string | number | boolean)[]>(
|
||||
..._lit: T
|
||||
): co<T[number] | undefined> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return { [SchemaInit]: "json" satisfies Schema } as any;
|
||||
},
|
||||
};
|
||||
|
||||
/** @category Schema definition */
|
||||
export const co = {
|
||||
string: {
|
||||
@@ -48,8 +78,15 @@ export const co = {
|
||||
ref,
|
||||
items: ItemsSym as ItemsSym,
|
||||
members: MembersSym as MembersSym,
|
||||
optional,
|
||||
};
|
||||
|
||||
function optionalRef<C extends CoValueClass>(
|
||||
arg: C | ((_raw: InstanceType<C>["_raw"]) => C),
|
||||
): co<InstanceType<C> | null | undefined> {
|
||||
return ref(arg, { optional: true });
|
||||
}
|
||||
|
||||
function ref<C extends CoValueClass>(
|
||||
arg: C | ((_raw: InstanceType<C>["_raw"]) => C),
|
||||
): co<InstanceType<C> | null>;
|
||||
@@ -131,6 +168,10 @@ export type EffectSchemaWithInputAndOutput<A, I = A> = EffectSchema<
|
||||
};
|
||||
|
||||
export type Encoder<V> = EffectSchemaWithInputAndOutput<V, JsonValue>;
|
||||
export type OptionalEncoder<V> = EffectSchemaWithInputAndOutput<
|
||||
V,
|
||||
JsonValue | undefined
|
||||
>;
|
||||
|
||||
import { Date } from "@effect/schema/Schema";
|
||||
import { SchemaInit, ItemsSym, MembersSym } from "./symbols.js";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -157,11 +157,12 @@ describe("CoList resolution", async () => {
|
||||
test("Loading and availability", async () => {
|
||||
const { me, list } = await initNodeAndList();
|
||||
|
||||
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";
|
||||
}
|
||||
@@ -216,11 +217,12 @@ describe("CoList resolution", async () => {
|
||||
test("Subscription & auto-resolution", async () => {
|
||||
const { me, list } = await initNodeAndList();
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
@@ -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.optional.encoded(Schema.NullishOr(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,11 @@ describe("Simple CoMap operations", async () => {
|
||||
expect(map._height).toEqual(20);
|
||||
expect(map._raw.get("_height")).toEqual(20);
|
||||
|
||||
map.nullable = "not null";
|
||||
map.nullable = null;
|
||||
delete map.nullable;
|
||||
map.nullable = undefined;
|
||||
|
||||
map.name = "Secret name";
|
||||
expect(map.name).toEqual("Secret name");
|
||||
map.name = undefined;
|
||||
@@ -95,6 +108,21 @@ describe("Simple CoMap operations", async () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("property existence", () => {
|
||||
class TestMap extends CoMap.Record(co.string) {}
|
||||
test("CoMap", () => {
|
||||
const map = TestMap.create(
|
||||
{ name: "test" },
|
||||
{
|
||||
owner: me,
|
||||
},
|
||||
);
|
||||
|
||||
expect("name" in map).toBe(true);
|
||||
expect("something" in map).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
class RecursiveMap extends CoMap {
|
||||
name = co.string;
|
||||
next?: co<RecursiveMap | null> = co.ref(RecursiveMap);
|
||||
@@ -253,11 +281,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 +352,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";
|
||||
}
|
||||
@@ -414,7 +444,7 @@ describe("CoMap resolution", async () => {
|
||||
|
||||
class TestMapWithOptionalRef extends CoMap {
|
||||
color = co.string;
|
||||
nested = co.ref(NestedMap, { optional: true });
|
||||
nested = co.optional.ref(NestedMap);
|
||||
}
|
||||
|
||||
test("Construction with optional", async () => {
|
||||
|
||||
@@ -39,10 +39,12 @@ describe("Deep loading with depth arg", async () => {
|
||||
crypto: Crypto,
|
||||
});
|
||||
|
||||
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";
|
||||
}
|
||||
@@ -252,10 +254,12 @@ test("Deep loading a record-like coMap", async () => {
|
||||
crypto: Crypto,
|
||||
});
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
404
pnpm-lock.yaml
generated
404
pnpm-lock.yaml
generated
@@ -11,12 +11,6 @@ importers:
|
||||
'@changesets/cli':
|
||||
specifier: ^2.27.3
|
||||
version: 2.27.3
|
||||
husky:
|
||||
specifier: ^9.0.11
|
||||
version: 9.0.11
|
||||
lint-staged:
|
||||
specifier: ^15.2.2
|
||||
version: 15.2.2
|
||||
prettier:
|
||||
specifier: ^3.1.1
|
||||
version: 3.1.1
|
||||
@@ -136,6 +130,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 +445,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 +482,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 +507,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 +523,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 +560,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 +603,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 +651,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 +665,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 +691,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
|
||||
@@ -1844,10 +1941,6 @@ packages:
|
||||
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
ansi-escapes@6.2.1:
|
||||
resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -2097,14 +2190,6 @@ packages:
|
||||
class-variance-authority@0.7.0:
|
||||
resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==}
|
||||
|
||||
cli-cursor@4.0.0:
|
||||
resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
cli-truncate@4.0.0:
|
||||
resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
cliui@6.0.0:
|
||||
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
|
||||
|
||||
@@ -2133,13 +2218,6 @@ packages:
|
||||
color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
colorette@2.0.20:
|
||||
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||
|
||||
commander@11.1.0:
|
||||
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
commander@4.1.1:
|
||||
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -2358,15 +2436,12 @@ 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==}
|
||||
|
||||
emoji-regex@10.3.0:
|
||||
resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==}
|
||||
|
||||
emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
|
||||
@@ -2514,9 +2589,6 @@ packages:
|
||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
eventemitter3@5.0.1:
|
||||
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
||||
|
||||
execa@8.0.1:
|
||||
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
|
||||
engines: {node: '>=16.17'}
|
||||
@@ -2681,10 +2753,6 @@ packages:
|
||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
|
||||
get-east-asian-width@1.2.0:
|
||||
resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
get-func-name@2.0.2:
|
||||
resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
|
||||
|
||||
@@ -2839,11 +2907,6 @@ packages:
|
||||
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
|
||||
engines: {node: '>=16.17.0'}
|
||||
|
||||
husky@9.0.11:
|
||||
resolution: {integrity: sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
hyphenate-style-name@1.0.4:
|
||||
resolution: {integrity: sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==}
|
||||
|
||||
@@ -2943,14 +3006,6 @@ packages:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-fullwidth-code-point@4.0.0:
|
||||
resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
is-fullwidth-code-point@5.0.0:
|
||||
resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -3124,18 +3179,9 @@ packages:
|
||||
lines-and-columns@1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
|
||||
lint-staged@15.2.2:
|
||||
resolution: {integrity: sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
hasBin: true
|
||||
|
||||
listenercount@1.0.1:
|
||||
resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==}
|
||||
|
||||
listr2@8.0.1:
|
||||
resolution: {integrity: sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
load-yaml-file@0.2.0:
|
||||
resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -3174,10 +3220,6 @@ packages:
|
||||
lodash@4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
|
||||
log-update@6.0.0:
|
||||
resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
loglevel-plugin-prefix@0.8.4:
|
||||
resolution: {integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==}
|
||||
|
||||
@@ -3262,10 +3304,6 @@ packages:
|
||||
engines: {node: '>=10.0.0'}
|
||||
hasBin: true
|
||||
|
||||
mimic-fn@2.1.0:
|
||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
mimic-fn@4.0.0:
|
||||
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -3436,10 +3474,6 @@ packages:
|
||||
once@1.4.0:
|
||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||
|
||||
onetime@5.1.2:
|
||||
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
onetime@6.0.0:
|
||||
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -3560,11 +3594,6 @@ packages:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
pidtree@0.6.0:
|
||||
resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
|
||||
engines: {node: '>=0.10'}
|
||||
hasBin: true
|
||||
|
||||
pify@2.3.0:
|
||||
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -3835,17 +3864,10 @@ packages:
|
||||
resq@1.11.0:
|
||||
resolution: {integrity: sha512-G10EBz+zAAy3zUd/CDoBbXRL6ia9kOo3xRHrMDsHljI0GDkhYlyjwoCx5+3eCC4swi1uCoZQhskuJkj7Gp57Bw==}
|
||||
|
||||
restore-cursor@4.0.0:
|
||||
resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
reusify@1.0.4:
|
||||
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
|
||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||
|
||||
rfdc@1.3.1:
|
||||
resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==}
|
||||
|
||||
rgb2hex@0.2.5:
|
||||
resolution: {integrity: sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==}
|
||||
|
||||
@@ -3978,14 +4000,6 @@ packages:
|
||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
slice-ansi@5.0.0:
|
||||
resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
slice-ansi@7.1.0:
|
||||
resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
smart-buffer@4.2.0:
|
||||
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
|
||||
engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
|
||||
@@ -4065,10 +4079,6 @@ packages:
|
||||
streamx@2.15.6:
|
||||
resolution: {integrity: sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==}
|
||||
|
||||
string-argv@0.3.2:
|
||||
resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
|
||||
engines: {node: '>=0.6.19'}
|
||||
|
||||
string-width@4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -4077,10 +4087,6 @@ packages:
|
||||
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
string-width@7.1.0:
|
||||
resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
string.prototype.trim@1.2.9:
|
||||
resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -4633,10 +4639,6 @@ packages:
|
||||
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
wrap-ansi@9.0.0:
|
||||
resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
wrappy@1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
|
||||
@@ -4912,29 +4914,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 +4944,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
|
||||
@@ -6065,8 +6067,6 @@ snapshots:
|
||||
|
||||
ansi-colors@4.1.3: {}
|
||||
|
||||
ansi-escapes@6.2.1: {}
|
||||
|
||||
ansi-regex@5.0.1: {}
|
||||
|
||||
ansi-regex@6.0.1: {}
|
||||
@@ -6341,15 +6341,6 @@ snapshots:
|
||||
dependencies:
|
||||
clsx: 2.0.0
|
||||
|
||||
cli-cursor@4.0.0:
|
||||
dependencies:
|
||||
restore-cursor: 4.0.0
|
||||
|
||||
cli-truncate@4.0.0:
|
||||
dependencies:
|
||||
slice-ansi: 5.0.0
|
||||
string-width: 7.1.0
|
||||
|
||||
cliui@6.0.0:
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
@@ -6378,10 +6369,6 @@ snapshots:
|
||||
|
||||
color-name@1.1.4: {}
|
||||
|
||||
colorette@2.0.20: {}
|
||||
|
||||
commander@11.1.0: {}
|
||||
|
||||
commander@4.1.1: {}
|
||||
|
||||
commander@9.5.0: {}
|
||||
@@ -6581,12 +6568,10 @@ snapshots:
|
||||
unzipper: 0.10.14
|
||||
which: 4.0.0
|
||||
|
||||
effect@3.2.1: {}
|
||||
effect@3.5.2: {}
|
||||
|
||||
electron-to-chromium@1.4.615: {}
|
||||
|
||||
emoji-regex@10.3.0: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
|
||||
emoji-regex@9.2.2: {}
|
||||
@@ -6844,8 +6829,6 @@ snapshots:
|
||||
|
||||
esutils@2.0.3: {}
|
||||
|
||||
eventemitter3@5.0.1: {}
|
||||
|
||||
execa@8.0.1:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.3
|
||||
@@ -7039,8 +7022,6 @@ snapshots:
|
||||
|
||||
get-caller-file@2.0.5: {}
|
||||
|
||||
get-east-asian-width@1.2.0: {}
|
||||
|
||||
get-func-name@2.0.2: {}
|
||||
|
||||
get-intrinsic@1.2.4:
|
||||
@@ -7220,8 +7201,6 @@ snapshots:
|
||||
|
||||
human-signals@5.0.0: {}
|
||||
|
||||
husky@9.0.11: {}
|
||||
|
||||
hyphenate-style-name@1.0.4: {}
|
||||
|
||||
iconv-lite@0.4.24:
|
||||
@@ -7311,12 +7290,6 @@ snapshots:
|
||||
|
||||
is-fullwidth-code-point@3.0.0: {}
|
||||
|
||||
is-fullwidth-code-point@4.0.0: {}
|
||||
|
||||
is-fullwidth-code-point@5.0.0:
|
||||
dependencies:
|
||||
get-east-asian-width: 1.2.0
|
||||
|
||||
is-glob@4.0.3:
|
||||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
@@ -7475,32 +7448,8 @@ snapshots:
|
||||
|
||||
lines-and-columns@1.2.4: {}
|
||||
|
||||
lint-staged@15.2.2:
|
||||
dependencies:
|
||||
chalk: 5.3.0
|
||||
commander: 11.1.0
|
||||
debug: 4.3.4
|
||||
execa: 8.0.1
|
||||
lilconfig: 3.0.0
|
||||
listr2: 8.0.1
|
||||
micromatch: 4.0.5
|
||||
pidtree: 0.6.0
|
||||
string-argv: 0.3.2
|
||||
yaml: 2.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
listenercount@1.0.1: {}
|
||||
|
||||
listr2@8.0.1:
|
||||
dependencies:
|
||||
cli-truncate: 4.0.0
|
||||
colorette: 2.0.20
|
||||
eventemitter3: 5.0.1
|
||||
log-update: 6.0.0
|
||||
rfdc: 1.3.1
|
||||
wrap-ansi: 9.0.0
|
||||
|
||||
load-yaml-file@0.2.0:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
@@ -7539,14 +7488,6 @@ snapshots:
|
||||
|
||||
lodash@4.17.21: {}
|
||||
|
||||
log-update@6.0.0:
|
||||
dependencies:
|
||||
ansi-escapes: 6.2.1
|
||||
cli-cursor: 4.0.0
|
||||
slice-ansi: 7.1.0
|
||||
strip-ansi: 7.1.0
|
||||
wrap-ansi: 9.0.0
|
||||
|
||||
loglevel-plugin-prefix@0.8.4: {}
|
||||
|
||||
loglevel@1.8.1: {}
|
||||
@@ -7619,8 +7560,6 @@ snapshots:
|
||||
|
||||
mime@3.0.0: {}
|
||||
|
||||
mimic-fn@2.1.0: {}
|
||||
|
||||
mimic-fn@4.0.0: {}
|
||||
|
||||
mimic-response@3.1.0: {}
|
||||
@@ -7773,10 +7712,6 @@ snapshots:
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
|
||||
onetime@5.1.2:
|
||||
dependencies:
|
||||
mimic-fn: 2.1.0
|
||||
|
||||
onetime@6.0.0:
|
||||
dependencies:
|
||||
mimic-fn: 4.0.0
|
||||
@@ -7894,8 +7829,6 @@ snapshots:
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
||||
pidtree@0.6.0: {}
|
||||
|
||||
pify@2.3.0: {}
|
||||
|
||||
pify@4.0.1: {}
|
||||
@@ -8224,15 +8157,8 @@ snapshots:
|
||||
dependencies:
|
||||
fast-deep-equal: 2.0.1
|
||||
|
||||
restore-cursor@4.0.0:
|
||||
dependencies:
|
||||
onetime: 5.1.2
|
||||
signal-exit: 3.0.7
|
||||
|
||||
reusify@1.0.4: {}
|
||||
|
||||
rfdc@1.3.1: {}
|
||||
|
||||
rgb2hex@0.2.5: {}
|
||||
|
||||
rimraf@2.7.1:
|
||||
@@ -8379,16 +8305,6 @@ snapshots:
|
||||
|
||||
slash@3.0.0: {}
|
||||
|
||||
slice-ansi@5.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.1
|
||||
is-fullwidth-code-point: 4.0.0
|
||||
|
||||
slice-ansi@7.1.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.1
|
||||
is-fullwidth-code-point: 5.0.0
|
||||
|
||||
smart-buffer@4.2.0: {}
|
||||
|
||||
smartwrap@2.0.2:
|
||||
@@ -8476,8 +8392,6 @@ snapshots:
|
||||
fast-fifo: 1.3.2
|
||||
queue-tick: 1.0.1
|
||||
|
||||
string-argv@0.3.2: {}
|
||||
|
||||
string-width@4.2.3:
|
||||
dependencies:
|
||||
emoji-regex: 8.0.0
|
||||
@@ -8490,12 +8404,6 @@ snapshots:
|
||||
emoji-regex: 9.2.2
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
string-width@7.1.0:
|
||||
dependencies:
|
||||
emoji-regex: 10.3.0
|
||||
get-east-asian-width: 1.2.0
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
string.prototype.trim@1.2.9:
|
||||
dependencies:
|
||||
call-bind: 1.0.7
|
||||
@@ -9204,12 +9112,6 @@ snapshots:
|
||||
string-width: 5.1.2
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
wrap-ansi@9.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.1
|
||||
string-width: 7.1.0
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
wrappy@1.0.2: {}
|
||||
|
||||
ws@8.13.0: {}
|
||||
|
||||
Reference in New Issue
Block a user