Compare commits

...

9 Commits

Author SHA1 Message Date
Anselm
5dfd74d7f5 Publish
- jazz-example-todo@0.0.5
 - jazz-react@0.0.11
 - jazz-react-auth-local@0.0.8
2023-08-17 14:02:50 +01:00
Anselm
5fbd598cfe Fix missing dependency 2023-08-17 14:01:22 +01:00
Anselm
d54b53737d Try removing awareness of workspace 2023-08-17 13:59:35 +01:00
Anselm
0f0cd08c36 Try removing local yarn lock 2023-08-17 13:51:11 +01:00
Anselm
4bb3834333 Try newer node version 2023-08-17 13:45:31 +01:00
Anselm
b9007dd1b5 Publish
- jazz-example-todo@0.0.4
 - cojson@0.0.18
 - jazz-react@0.0.10
 - jazz-react-auth-local@0.0.7
 - jazz-storage-indexeddb@0.0.5
2023-08-17 13:43:46 +01:00
Anselm
ee1e5b06e4 Fix bundling of packages 2023-08-17 13:43:30 +01:00
Anselm
fae290c4cf Add exports to cojson 2023-08-17 12:36:58 +01:00
Anselm
381d68019f Try deploying jazz-example 2023-08-17 12:33:28 +01:00
30 changed files with 308 additions and 1950 deletions

81
.github/workflows/build-and-deploy.yaml vendored Normal file
View File

@@ -0,0 +1,81 @@
name: Build and Deploy
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true
- uses: actions/setup-node@v3
with:
node-version: 18
cache: 'yarn'
cache-dependency-path: yarn.lock
- name: Nuke Workspace
run: |
rm package.json yarn.lock;
- name: Yarn Build
run: |
yarn install --frozen-lockfile;
yarn build;
working-directory: ./examples/todo
- uses: satackey/action-docker-layer-caching@v0.0.11
continue-on-error: true
with:
key: docker-layer-caching-${{ github.workflow }}-{hash}
restore-keys: |
docker-layer-caching-${{ github.workflow }}-
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: gardencmp
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker Build & Push
run: |
export DOCKER_TAG=ghcr.io/gardencmp/jazz-example-todo:${{github.head_ref || github.ref_name}}-${{github.sha}}-$(date +%s) ;
docker build . --file Dockerfile --tag $DOCKER_TAG;
docker push $DOCKER_TAG;
echo "DOCKER_TAG=$DOCKER_TAG" >> $GITHUB_ENV
working-directory: ./examples/todo
- 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=${{ env.DOCKER_TAG }};
for region in ${{ vars.DEPLOY_REGIONS }}
do
export REGION=$region;
envsubst '${DOCKER_USER} ${DOCKER_PASSWORD} ${DOCKER_TAG} ${BRANCH_SUFFIX} ${BRANCH_SUBDOMAIN} ${REGION}' < job-template.nomad > job-instance.nomad;
cat job-instance.nomad;
NOMAD_ADDR='${{ secrets.NOMAD_ADDR }}' nomad job run job-instance.nomad;
done
working-directory: ./examples/todo

6
examples/todo/Dockerfile Normal file
View File

@@ -0,0 +1,6 @@
FROM caddy:2.7.3-alpine
LABEL org.opencontainers.image.source="https://github.com/gardencmp/jazz"
COPY ./dist /usr/share/caddy/
RUN caddy

View File

@@ -0,0 +1,54 @@
job "example-todo$BRANCH_SUFFIX" {
region = "$REGION"
datacenters = ["$REGION"]
group "static" {
// count = 3
network {
port "http" {
to = 80
}
}
constraint {
attribute = "${node.class}"
operator = "="
value = "edge"
}
// spread {
// attribute = "${node.datacenter}"
// weight = 100
// }
task "server" {
driver = "docker"
config {
image = "$DOCKER_TAG"
ports = ["http"]
auth = {
username = "$DOCKER_USER"
password = "$DOCKER_PASSWORD"
}
}
service {
tags = ["public"]
meta {
public_name = "${BRANCH_SUBDOMAIN}example-todo"
}
port = "http"
provider = "consul"
}
resources {
cpu = 50 # MHz
memory = 50 # MB
}
}
}
}
# deploy bump 4

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.3",
"version": "0.0.5",
"type": "module",
"scripts": {
"dev": "vite",
@@ -14,8 +14,8 @@
"@radix-ui/react-slot": "^1.0.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"jazz-react": "^0.0.9",
"jazz-react-auth-local": "^0.0.6",
"jazz-react": "^0.0.11",
"jazz-react-auth-local": "^0.0.8",
"lucide-react": "^0.265.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",

View File

@@ -26,7 +26,7 @@ function App() {
const createList = () => {
const listTeam = localNode.createTeam();
const list = listTeam.createMap<TodoListContent, null>();
const list = listTeam.createMap<TodoListContent>();
list.edit((list) => {
list.set("title", "My Todo List");
@@ -47,7 +47,7 @@ function App() {
}, [])
return (
<div className="flex flex-col h-full items-center justify-center gap-10">
<div className="flex flex-col h-full items-center justify-start gap-10 pt-10 md:pt-[30vh] pb-10">
{listId && <TodoList listId={listId} />}
<Button onClick={createList}>Create New List</Button>
</div>
@@ -59,7 +59,7 @@ export function TodoList({ listId }: { listId: CoID<TodoList> }) {
const createTodo = (text: string) => {
if (!list) return;
let task = list.coValue.getTeam().createMap<TaskContent, {}>();
let task = list.coValue.getTeam().createMap<TaskContent>();
task = task.edit((task) => {
task.set("text", text);

View File

@@ -1,4 +1,3 @@
import React from "react";
import { Input } from "./components/ui/input.tsx";
import { Button } from "./components/ui/button.tsx";
import { AuthComponent } from "jazz-react";

View File

@@ -7,7 +7,7 @@ import { LocalAuth } from "./LocalAuth.tsx";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<WithJazz auth={LocalAuth}>
<WithJazz auth={LocalAuth} syncAddress={new URLSearchParams(window.location.search).get("sync") || undefined}>
<App />
</WithJazz>
</React.StrictMode>

View File

@@ -2,7 +2,7 @@
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
"types": "src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.0.17",
"version": "0.0.18",
"devDependencies": {
"@types/jest": "^29.5.3",
"@typescript-eslint/eslint-plugin": "^6.2.1",

View File

@@ -1,10 +1,16 @@
import { CoValue, newRandomSessionID } from "./coValue.js";
import { LocalNode } from "./node.js";
import { CoMap } from "./contentTypes/coMap.js";
import { agentSecretFromBytes, agentSecretToBytes } from "./crypto.js";
import {
agentSecretFromBytes,
agentSecretToBytes,
getAgentID,
newRandomAgentSecret,
} from "./crypto.js";
import { connectedPeers } from "./streamUtils.js";
import { AnonymousControlledAccount, ControlledAccount } from "./account.js";
import type { SessionID } from "./ids.js";
import type { SessionID, AgentID } from "./ids.js";
import type { CoID, ContentType } from "./contentType.js";
import type { JsonValue } from "./jsonValue.js";
import type { SyncMessage } from "./sync.js";
@@ -12,14 +18,23 @@ import type { AgentSecret } from "./crypto.js";
type Value = JsonValue | ContentType;
const internals = {
export const cojsonInternals = {
agentSecretFromBytes,
agentSecretToBytes,
newRandomSessionID,
connectedPeers
newRandomAgentSecret,
connectedPeers,
getAgentID,
};
export { LocalNode, CoValue, CoMap, internals };
export {
LocalNode,
CoValue,
CoMap,
cojsonInternals as internals,
AnonymousControlledAccount,
ControlledAccount,
};
export type {
Value,
@@ -29,4 +44,17 @@ export type {
AgentSecret,
SessionID,
SyncMessage,
AgentID,
};
export namespace CojsonInternalTypes {
export type CoValueKnownState = import("./sync.js").CoValueKnownState;
export type DoneMessage = import("./sync.js").DoneMessage;
export type KnownStateMessage = import("./sync.js").KnownStateMessage;
export type LoadMessage = import("./sync.js").LoadMessage;
export type NewContentMessage = import("./sync.js").NewContentMessage;
export type CoValueHeader = import("./coValue.js").CoValueHeader;
export type Transaction = import("./coValue.js").Transaction;
export type Signature = import("./crypto.js").Signature;
export type RawCoID = import("./ids.js").RawCoID;
}

View File

@@ -352,7 +352,7 @@ export class Team {
this.rotateReadKey();
}
createMap<M extends { [key: string]: JsonValue }, Meta extends JsonObject | null>(
createMap<M extends { [key: string]: JsonValue }, Meta extends JsonObject | null = null>(
meta?: Meta
): CoMap<M, Meta> {
return this.node

View File

@@ -100,14 +100,14 @@ export function newStreamPair<T>(): [ReadableStream<T>, WritableStream<T>] {
);
},
cancel(reason) {
cancel(_reason) {
console.log("Manually closing reader");
readerClosed = true;
},
});
const writable = new WritableStream<T>({
write(chunk, controller) {
write(chunk) {
if (readerClosed) {
console.log("Reader closed, not writing chunk", chunk);
throw new Error("Reader closed, not writing chunk");
@@ -118,7 +118,7 @@ export function newStreamPair<T>(): [ReadableStream<T>, WritableStream<T>] {
setTimeout(() => resolveNextItemReady());
}
},
abort(reason) {
abort(_reason) {
console.log("Manually closing writer");
writerClosed = true;
resolveNextItemReady();

View File

@@ -1,4 +1,4 @@
import { Hash, Signature } from "./crypto.js";
import { Signature } from "./crypto.js";
import { CoValueHeader, Transaction } from "./coValue.js";
import { CoValue } from "./coValue.js";
import { LocalNode } from "./node.js";

View File

@@ -1,18 +1,21 @@
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:require-extensions/recommended",
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint", "require-extensions"],
parserOptions: {
project: './tsconfig.json',
project: "./tsconfig.json",
},
root: true,
rules: {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }],
"@typescript-eslint/no-unused-vars": [
"error",
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
],
"@typescript-eslint/no-floating-promises": "error",
},
};
};

View File

@@ -0,0 +1,2 @@
coverage
node_modules

View File

@@ -1,17 +1,22 @@
{
"name": "jazz-react-auth-local",
"version": "0.0.6",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"jazz-react": "^0.0.9",
"typescript": "^5.1.6"
},
"devDependencies": {
"@types/react": "^18.2.19"
},
"peerDependencies": {
"react": "^17.0.2"
}
"name": "jazz-react-auth-local",
"version": "0.0.8",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"jazz-react": "^0.0.11",
"typescript": "^5.1.6"
},
"devDependencies": {
"@types/react": "^18.2.19"
},
"peerDependencies": {
"react": "^17.0.2"
},
"scripts": {
"lint": "eslint src/**/*.ts",
"build": "npm run lint && rm -rf ./dist && tsc --declaration --sourceMap --outDir dist",
"prepublishOnly": "npm run build"
}
}

View File

@@ -1,5 +1,5 @@
import { newRandomAgentSecret, AgentSecret, agentSecretToBytes, agentSecretFromBytes} from "cojson/src/crypto";
import React, { useCallback, useEffect, useState } from "react";
import { cojsonInternals, AgentSecret } from "cojson";
import { useCallback, useEffect, useState } from "react";
export function useLocalAuth(onCredential: (credentials: AgentSecret) => void) {
const [displayName, setDisplayName] = useState<string>("");
@@ -12,8 +12,8 @@ export function useLocalAuth(onCredential: (credentials: AgentSecret) => void) {
}, [onCredential]);
const signUp = useCallback(() => {
(async function () {
const credential = newRandomAgentSecret();
void (async function () {
const credential = cojsonInternals.newRandomAgentSecret();
console.log(credential);
@@ -26,7 +26,7 @@ export function useLocalAuth(onCredential: (credentials: AgentSecret) => void) {
id: window.location.hostname,
},
user: {
id: agentSecretToBytes(credential),
id: cojsonInternals.agentSecretToBytes(credential),
name: displayName,
displayName: displayName,
},
@@ -42,7 +42,7 @@ export function useLocalAuth(onCredential: (credentials: AgentSecret) => void) {
console.log(
webAuthNCredential,
credential,
agentSecretToBytes(credential)
cojsonInternals.agentSecretToBytes(credential)
);
sessionStorage.credential = JSON.stringify(credential);
@@ -51,7 +51,7 @@ export function useLocalAuth(onCredential: (credentials: AgentSecret) => void) {
}, [displayName]);
const signIn = useCallback(() => {
(async function () {
void (async function () {
const webAuthNCredential = await navigator.credentials.get({
publicKey: {
challenge: Uint8Array.from([0, 1, 2]),
@@ -62,11 +62,19 @@ export function useLocalAuth(onCredential: (credentials: AgentSecret) => void) {
},
});
if (!webAuthNCredential) {
throw new Error("Couldn't log in");
}
const userIdBytes = new Uint8Array(
(webAuthNCredential as any).response.userHandle
(
webAuthNCredential as unknown as {
response: { userHandle: ArrayBuffer };
}
).response.userHandle
);
const credential =
agentSecretFromBytes(userIdBytes);
cojsonInternals.agentSecretFromBytes(userIdBytes);
if (!credential) {
throw new Error("Invalid credential");
@@ -78,4 +86,4 @@ export function useLocalAuth(onCredential: (credentials: AgentSecret) => void) {
}, []);
return { displayName, setDisplayName, signUp, signIn };
}
}

View File

@@ -2,18 +2,12 @@
"compilerOptions": {
"lib": ["ESNext", "DOM"],
"module": "esnext",
"target": "esnext",
"target": "ES2020",
"moduleResolution": "bundler",
"moduleDetection": "force",
"allowImportingTsExtensions": true,
"strict": true,
"downlevelIteration": true,
"skipLibCheck": true,
"jsx": "preserve",
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"noEmit": true,
"noUncheckedIndexedAccess": true,
"esModuleInterop": true,
},

View File

@@ -6,7 +6,7 @@ module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
project: './tsconfig.json',
project: "./tsconfig.json",
},
root: true,
rules: {
@@ -14,5 +14,4 @@ module.exports = {
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }],
"@typescript-eslint/no-floating-promises": "error",
},
};
};

View File

@@ -0,0 +1,2 @@
coverage
node_modules

View File

@@ -1,11 +1,12 @@
{
"name": "jazz-react",
"version": "0.0.9",
"version": "0.0.11",
"main": "src/index.tsx",
"types": "src/index.tsx",
"license": "MIT",
"dependencies": {
"cojson": "^0.0.17",
"cojson": "^0.0.18",
"jazz-storage-indexeddb": "^0.0.5",
"typescript": "^5.1.6"
},
"devDependencies": {
@@ -13,5 +14,10 @@
},
"peerDependencies": {
"react": "^17.0.2"
},
"scripts": {
"lint": "eslint src/**/*.tsx",
"build": "npm run lint && rm -rf ./dist && tsc --declaration --sourceMap --outDir dist",
"prepublishOnly": "npm run build"
}
}

View File

@@ -1,17 +1,16 @@
import {
LocalNode,
internals as cojsonInternals,
cojsonInternals,
SessionID,
ContentType,
SyncMessage,
AgentSecret,
CoID,
AnonymousControlledAccount,
AgentID
} from "cojson";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { ReadableStream, WritableStream } from "isomorphic-streams";
import { CoID } from "cojson";
import { AgentID } from "cojson/src/ids";
import { getAgentID } from "cojson/src/crypto";
import { AnonymousControlledAccount } from "cojson/src/account";
import { IDBStorage } from "jazz-storage-indexeddb";
type JazzContext = {
@@ -37,10 +36,10 @@ export function WithJazz({
const sessionDone = useRef<() => void>();
const onCredential = useCallback((credential: AgentSecret) => {
const agentID = getAgentID(credential);
const agentID = cojsonInternals.getAgentID(credential);
const sessionHandle = getSessionFor(agentID);
sessionHandle.session.then((sessionID) =>
void sessionHandle.session.then((sessionID) =>
setNode(
new LocalNode(
new AnonymousControlledAccount(credential),
@@ -60,12 +59,12 @@ export function WithJazz({
useEffect(() => {
if (node) {
IDBStorage.connectTo(node, { trace: true });
void IDBStorage.connectTo(node, { trace: true });
let shouldTryToReconnect = true;
let ws: WebSocket | undefined;
(async function websocketReconnectLoop() {
void (async function websocketReconnectLoop() {
while (shouldTryToReconnect) {
ws = new WebSocket(syncAddress);
@@ -134,7 +133,7 @@ function getSessionFor(agentID: AgentID): SessionHandle {
resolveSession = resolve;
});
(async function () {
void (async function () {
for (let idx = 0; idx < 100; idx++) {
// To work better around StrictMode
for (let retry = 0; retry < 2; retry++) {
@@ -209,6 +208,8 @@ export function useTelepathicState<T extends ContentType>(id: CoID<T>) {
);
setState(newState as T);
});
}).catch((e) => {
console.log("Failed to load", id, e);
});
return () => {

View File

@@ -2,18 +2,13 @@
"compilerOptions": {
"lib": ["ESNext", "DOM"],
"module": "esnext",
"target": "esnext",
"target": "ES2020",
"moduleResolution": "bundler",
"moduleDetection": "force",
"allowImportingTsExtensions": true,
"strict": true,
"downlevelIteration": true,
"skipLibCheck": true,
"jsx": "preserve",
"allowSyntheticDefaultImports": true,
"jsx": "react",
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"noEmit": true,
"noUncheckedIndexedAccess": true,
"esModuleInterop": true,
},

View File

@@ -6,13 +6,12 @@ module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
project: './tsconfig.json',
project: "./tsconfig.json",
},
root: true,
rules: {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }],
"@typescript-eslint/no-floating-promises": "error",
// "@typescript-eslint/no-floating-promises": "error",
},
};
};

View File

@@ -0,0 +1,2 @@
coverage
node_modules

View File

@@ -1,11 +1,11 @@
{
"name": "jazz-storage-indexeddb",
"version": "0.0.4",
"version": "0.0.5",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"cojson": "^0.0.17",
"cojson": "^0.0.18",
"typescript": "^5.1.6"
},
"devDependencies": {
@@ -14,6 +14,9 @@
"webdriverio": "^8.15.0"
},
"scripts": {
"test": "vitest --browser chrome"
"test": "vitest --browser chrome",
"lint": "eslint src/**/*.ts",
"build": "npm run lint && rm -rf ./dist && tsc --declaration --sourceMap --outDir dist",
"prepublishOnly": "npm run build"
}
}

View File

@@ -17,7 +17,7 @@ test.skip("Should be able to initialize and load from empty DB", async () => {
console.log("yay!");
const team = node.createTeam();
const _team = node.createTeam();
await new Promise((resolve) => setTimeout(resolve, 200));

View File

@@ -1,21 +1,5 @@
import {
LocalNode,
internals as cojsonInternals,
SessionID,
ContentType,
SyncMessage,
JsonValue,
} from "cojson";
import { CoValueHeader, Transaction } from "cojson/src/coValue";
import { Signature } from "cojson/src/crypto";
import { RawCoID } from "cojson/src/ids";
import {
CoValueKnownState,
DoneMessage,
KnownStateMessage,
LoadMessage,
NewContentMessage,
} from "cojson/src/sync";
import { LocalNode, cojsonInternals, SessionID, SyncMessage } from "cojson";
import { CojsonInternalTypes } from "cojson";
import {
ReadableStream,
WritableStream,
@@ -24,8 +8,8 @@ import {
} from "isomorphic-streams";
type CoValueRow = {
id: RawCoID;
header: CoValueHeader;
id: CojsonInternalTypes.RawCoID;
header: CojsonInternalTypes.CoValueHeader;
};
type StoredCoValueRow = CoValueRow & { rowID: number };
@@ -34,7 +18,7 @@ type SessionRow = {
coValue: number;
sessionID: SessionID;
lastIdx: number;
lastSignature: Signature;
lastSignature: CojsonInternalTypes.Signature;
};
type StoredSessionRow = SessionRow & { rowID: number };
@@ -42,7 +26,7 @@ type StoredSessionRow = SessionRow & { rowID: number };
type TransactionRow = {
ses: number;
idx: number;
tx: Transaction;
tx: CojsonInternalTypes.Transaction;
};
export class IDBStorage {
@@ -60,13 +44,14 @@ export class IDBStorage {
this.toLocalNode = toLocalNode.getWriter();
(async () => {
while (true) {
const { done, value } = await this.fromLocalNode.read();
if (done) {
break;
}
let done = false;
while (!done) {
const result = await this.fromLocalNode.read();
done = result.done;
this.handleSyncMessage(value);
if (result.value) {
this.handleSyncMessage(result.value);
}
}
})();
}
@@ -159,7 +144,7 @@ export class IDBStorage {
}
async sendNewContentAfter(
theirKnown: CoValueKnownState,
theirKnown: CojsonInternalTypes.CoValueKnownState,
{
coValues,
sessions,
@@ -169,7 +154,7 @@ export class IDBStorage {
sessions: IDBObjectStore;
transactions: IDBObjectStore;
},
asDependencyOf?: RawCoID
asDependencyOf?: CojsonInternalTypes.RawCoID
) {
const coValueRow = await promised<StoredCoValueRow | undefined>(
coValues.index("coValuesById").get(theirKnown.id)
@@ -181,13 +166,13 @@ export class IDBStorage {
)
: [];
const ourKnown: CoValueKnownState = {
const ourKnown: CojsonInternalTypes.CoValueKnownState = {
id: theirKnown.id,
header: !!coValueRow,
sessions: {},
};
const newContent: NewContentMessage = {
const newContent: CojsonInternalTypes.NewContentMessage = {
action: "content",
id: theirKnown.id,
header: theirKnown.header ? undefined : coValueRow?.header,
@@ -237,7 +222,7 @@ export class IDBStorage {
change.key
)
.filter(
(key): key is RawCoID =>
(key): key is CojsonInternalTypes.RawCoID =>
typeof key === "string" &&
key.startsWith("co_")
);
@@ -258,7 +243,7 @@ export class IDBStorage {
await this.toLocalNode.write({
action: "known",
...ourKnown,
asDependencyOf
asDependencyOf,
});
if (newContent.header || Object.keys(newContent.new).length > 0) {
@@ -266,11 +251,11 @@ export class IDBStorage {
}
}
handleLoad(msg: LoadMessage) {
handleLoad(msg: CojsonInternalTypes.LoadMessage) {
return this.sendNewContentAfter(msg, this.inTransaction("readonly"));
}
async handleContent(msg: NewContentMessage) {
async handleContent(msg: CojsonInternalTypes.NewContentMessage) {
const { coValues, sessions, transactions } =
this.inTransaction("readwrite");
@@ -320,7 +305,7 @@ export class IDBStorage {
};
});
const ourKnown: CoValueKnownState = {
const ourKnown: CojsonInternalTypes.CoValueKnownState = {
id: msg.id,
header: true,
sessions: {},
@@ -389,11 +374,11 @@ export class IDBStorage {
}
}
handleKnown(msg: KnownStateMessage) {
handleKnown(msg: CojsonInternalTypes.KnownStateMessage) {
return this.sendNewContentAfter(msg, this.inTransaction("readonly"));
}
handleDone(msg: DoneMessage) {}
handleDone(_msg: CojsonInternalTypes.DoneMessage) {}
inTransaction(mode: "readwrite" | "readonly"): {
coValues: IDBObjectStore;
@@ -406,11 +391,13 @@ export class IDBStorage {
);
tx.onerror = (event) => {
const target = event.target as {
error: DOMException;
source?: { name: string };
} | null;
throw new Error(
`Error in transaction (${
(event.target as any).source?.name
}): ${(event.target as any).error}`,
{ cause: (event.target as any).error }
`Error in transaction (${target?.source?.name}): ${target?.error}`,
{ cause: target?.error }
);
};
const coValues = tx.objectStore("coValues");

View File

@@ -2,18 +2,12 @@
"compilerOptions": {
"lib": ["ESNext", "DOM"],
"module": "esnext",
"target": "esnext",
"target": "ES2020",
"moduleResolution": "bundler",
"moduleDetection": "force",
"allowImportingTsExtensions": true,
"strict": true,
"downlevelIteration": true,
"skipLibCheck": true,
"jsx": "preserve",
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"noEmit": true,
"noUncheckedIndexedAccess": true,
"esModuleInterop": true,
},