Compare commits
3 Commits
jazz-react
...
jazz-react
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b09e35e372 | ||
|
|
d2c8121c9c | ||
|
|
380bb88ffa |
@@ -1,5 +1,14 @@
|
|||||||
# jazz-example-chat
|
# 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
|
## 0.0.69
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "jazz-example-chat",
|
"name": "jazz-example-chat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.69",
|
"version": "0.0.70",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# jazz-example-chat
|
# jazz-example-chat
|
||||||
|
|
||||||
|
## 0.0.51
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- cojson@0.7.23
|
||||||
|
- cojson-transport-ws@0.7.23
|
||||||
|
|
||||||
## 0.0.50
|
## 0.0.50
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "jazz-inspector",
|
"name": "jazz-inspector",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.50",
|
"version": "0.0.51",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# jazz-example-pets
|
# 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
|
## 0.0.87
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "jazz-example-pets",
|
"name": "jazz-example-pets",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.87",
|
"version": "0.0.88",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# jazz-example-todo
|
# jazz-example-todo
|
||||||
|
|
||||||
|
## 0.0.87
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- jazz-react@0.7.23
|
||||||
|
- jazz-tools@0.7.23
|
||||||
|
|
||||||
## 0.0.86
|
## 0.0.86
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "jazz-example-todo",
|
"name": "jazz-example-todo",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.86",
|
"version": "0.0.87",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# cojson-storage-indexeddb
|
# cojson-storage-indexeddb
|
||||||
|
|
||||||
|
## 0.7.23
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- cojson@0.7.23
|
||||||
|
|
||||||
## 0.7.18
|
## 0.7.18
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cojson-storage-indexeddb",
|
"name": "cojson-storage-indexeddb",
|
||||||
"version": "0.7.18",
|
"version": "0.7.23",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# cojson-storage-sqlite
|
# cojson-storage-sqlite
|
||||||
|
|
||||||
|
## 0.7.23
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- cojson@0.7.23
|
||||||
|
|
||||||
## 0.7.18
|
## 0.7.18
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "cojson-storage-sqlite",
|
"name": "cojson-storage-sqlite",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.7.18",
|
"version": "0.7.23",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# cojson-transport-nodejs-ws
|
# cojson-transport-nodejs-ws
|
||||||
|
|
||||||
|
## 0.7.23
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- cojson@0.7.23
|
||||||
|
|
||||||
## 0.7.22
|
## 0.7.22
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "cojson-transport-ws",
|
"name": "cojson-transport-ws",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.7.22",
|
"version": "0.7.23",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# cojson
|
# cojson
|
||||||
|
|
||||||
|
## 0.7.23
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Mostly complete OPFS implementation (single-tab only)
|
||||||
|
|
||||||
## 0.7.18
|
## 0.7.18
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "0.7.18",
|
"version": "0.7.23",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.3",
|
"@types/jest": "^29.5.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { CoValueChunk } from "./index.js";
|
|||||||
import { RawCoID } from "../ids.js";
|
import { RawCoID } from "../ids.js";
|
||||||
import { CryptoProvider, StreamingHash } from "../crypto/crypto.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 }[];
|
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>>(
|
export function writeBlock<WH, RH, FS extends FileSystem<WH, RH>>(
|
||||||
chunks: Map<RawCoID, CoValueChunk>,
|
chunks: Map<RawCoID, CoValueChunk>,
|
||||||
level: number,
|
level: number,
|
||||||
|
blockNumber: number,
|
||||||
fs: FS,
|
fs: FS,
|
||||||
): Effect.Effect<void, FSErr> {
|
): Effect.Effect<BlockFilename, FSErr> {
|
||||||
if (chunks.size === 0) {
|
if (chunks.size === 0) {
|
||||||
return Effect.die(new Error("No chunks to write"));
|
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${
|
const filename: BlockFilename = `L${level}-${(
|
||||||
headerBytes.length
|
blockNumber + ""
|
||||||
}.jsonl`;
|
).padStart(3, "0")}-${hash
|
||||||
|
.digest()
|
||||||
|
.replace("hash_", "")
|
||||||
|
.slice(0, 15)}-H${headerBytes.length}.jsonl`;
|
||||||
// console.log("renaming to" + filename);
|
// console.log("renaming to" + filename);
|
||||||
yield* $(fs.closeAndRename(file, filename));
|
yield* $(fs.closeAndRename(file, filename));
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
|
||||||
// console.log("Wrote block", filename, blockHeader);
|
// console.log("Wrote block", filename, blockHeader);
|
||||||
// console.log("IDs in block", blockHeader.map(e => e.id));
|
// 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,
|
...chunk,
|
||||||
};
|
};
|
||||||
const bytes = textEncoder.encode(JSON.stringify(walEntry) + "\n");
|
const bytes = textEncoder.encode(JSON.stringify(walEntry) + "\n");
|
||||||
|
console.log("writing to WAL", handle, id, bytes.length);
|
||||||
yield* $(fs.append(handle, bytes));
|
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 { RawCoID } from "../ids.js";
|
||||||
import { CoValueHeader, Transaction } from "../coValueCore.js";
|
import { CoValueHeader, Transaction } from "../coValueCore.js";
|
||||||
import { Signature } from "../crypto/crypto.js";
|
import { Signature } from "../crypto/crypto.js";
|
||||||
@@ -30,6 +37,8 @@ import {
|
|||||||
} from "./FileSystem.js";
|
} from "./FileSystem.js";
|
||||||
export type { FSErr, BlockFilename, WalFilename } from "./FileSystem.js";
|
export type { FSErr, BlockFilename, WalFilename } from "./FileSystem.js";
|
||||||
|
|
||||||
|
const MAX_N_LEVELS = 3;
|
||||||
|
|
||||||
export type CoValueChunk = {
|
export type CoValueChunk = {
|
||||||
header?: CoValueHeader;
|
header?: CoValueHeader;
|
||||||
sessionEntries: {
|
sessionEntries: {
|
||||||
@@ -51,6 +60,10 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
|
|||||||
BlockFilename,
|
BlockFilename,
|
||||||
{ [id: RawCoID]: { start: number; length: number } }
|
{ [id: RawCoID]: { start: number; length: number } }
|
||||||
>();
|
>();
|
||||||
|
blockFileHandles = new Map<
|
||||||
|
BlockFilename,
|
||||||
|
Deferred.Deferred<{ handle: RH; size: number }, FSErr>
|
||||||
|
>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public fs: FS,
|
public fs: FS,
|
||||||
@@ -192,7 +205,7 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
|
|||||||
let newWal = wal;
|
let newWal = wal;
|
||||||
if (!newWal) {
|
if (!newWal) {
|
||||||
newWal = yield* this.fs.createFile(
|
newWal = yield* this.fs.createFile(
|
||||||
`wal-${new Date().toISOString()}-${Math.random()
|
`wal-${Date.now()}-${Math.random()
|
||||||
.toString(36)
|
.toString(36)
|
||||||
.slice(2)}.jsonl`,
|
.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,
|
id: RawCoID,
|
||||||
fs: FS,
|
fs: FS,
|
||||||
): Effect.Effect<CoValueChunk | undefined, FSErr> {
|
): Effect.Effect<CoValueChunk | undefined, FSErr> {
|
||||||
// return _loadChunkFromWal(id, fs);
|
|
||||||
return Effect.gen(this, function* () {
|
return Effect.gen(this, function* () {
|
||||||
const files = this.fileCache || (yield* fs.listFiles());
|
const files = this.fileCache || (yield* fs.listFiles());
|
||||||
this.fileCache = files;
|
this.fileCache = files;
|
||||||
const blockFiles = files.filter((name) =>
|
const blockFiles = (
|
||||||
name.startsWith("hash_"),
|
files.filter((name) => name.startsWith("L")) as BlockFilename[]
|
||||||
) as BlockFilename[];
|
).sort();
|
||||||
|
|
||||||
|
let result;
|
||||||
|
|
||||||
for (const blockFile of blockFiles) {
|
for (const blockFile of blockFiles) {
|
||||||
let cachedHeader:
|
let cachedHeader:
|
||||||
| { [id: RawCoID]: { start: number; length: number } }
|
| { [id: RawCoID]: { start: number; length: number } }
|
||||||
| undefined = this.headerCache.get(blockFile);
|
| 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);
|
// 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);
|
// console.log("Header entry", id, headerEntry);
|
||||||
|
|
||||||
let result;
|
|
||||||
if (headerEntry) {
|
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);
|
// yield* fs.close(handle);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,11 +498,150 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
|
|||||||
yield* this.fs.close(handle);
|
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) {
|
for (const walFile of walFiles) {
|
||||||
yield* this.fs.removeFile(walFile);
|
yield* this.fs.removeFile(walFile);
|
||||||
}
|
}
|
||||||
this.fileCache = undefined;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# jazz-browser-media-images
|
# jazz-browser-media-images
|
||||||
|
|
||||||
|
## 0.7.23
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- jazz-tools@0.7.23
|
||||||
|
- jazz-browser@0.7.23
|
||||||
|
|
||||||
## 0.7.22
|
## 0.7.22
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jazz-browser-media-images",
|
"name": "jazz-browser-media-images",
|
||||||
"version": "0.7.22",
|
"version": "0.7.23",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
# jazz-browser
|
# 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
|
## 0.7.22
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jazz-browser",
|
"name": "jazz-browser",
|
||||||
"version": "0.7.22",
|
"version": "0.7.23",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
} from "cojson";
|
} from "cojson";
|
||||||
import { Effect } from "effect";
|
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;
|
opfsWorker: Worker;
|
||||||
callbacks: Map<number, (event: MessageEvent) => void> = new Map();
|
callbacks: Map<number, (event: MessageEvent) => void> = new Map();
|
||||||
nextRequestId = 0;
|
nextRequestId = 0;
|
||||||
@@ -31,13 +31,13 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
|||||||
listFiles(): Effect.Effect<string[], FSErr, never> {
|
listFiles(): Effect.Effect<string[], FSErr, never> {
|
||||||
return Effect.async((cb) => {
|
return Effect.async((cb) => {
|
||||||
const requestId = this.nextRequestId++;
|
const requestId = this.nextRequestId++;
|
||||||
performance.mark("listFiles" + requestId);
|
performance.mark("listFiles" + requestId + "_listFiles");
|
||||||
this.callbacks.set(requestId, (event) => {
|
this.callbacks.set(requestId, (event) => {
|
||||||
performance.mark("listFilesEnd" + requestId);
|
performance.mark("listFilesEnd" + requestId + "_listFiles");
|
||||||
performance.measure(
|
performance.measure(
|
||||||
"listFiles" + requestId,
|
"listFiles" + requestId + "_listFiles",
|
||||||
"listFiles" + requestId,
|
"listFiles" + requestId + "_listFiles",
|
||||||
"listFilesEnd" + requestId,
|
"listFilesEnd" + requestId + "_listFiles",
|
||||||
);
|
);
|
||||||
cb(Effect.succeed(event.data.fileNames));
|
cb(Effect.succeed(event.data.fileNames));
|
||||||
});
|
});
|
||||||
@@ -47,22 +47,22 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
|||||||
|
|
||||||
openToRead(
|
openToRead(
|
||||||
filename: string,
|
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) => {
|
return Effect.async((cb) => {
|
||||||
const requestId = this.nextRequestId++;
|
const requestId = this.nextRequestId++;
|
||||||
performance.mark("openToRead" + requestId);
|
performance.mark("openToRead" + "_" + filename);
|
||||||
this.callbacks.set(requestId, (event) => {
|
this.callbacks.set(requestId, (event) => {
|
||||||
cb(
|
cb(
|
||||||
Effect.succeed({
|
Effect.succeed({
|
||||||
handle: event.data.handle,
|
handle: {id: event.data.handle, filename},
|
||||||
size: event.data.size,
|
size: event.data.size,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
performance.mark("openToReadEnd" + requestId);
|
performance.mark("openToReadEnd" + "_" + filename);
|
||||||
performance.measure(
|
performance.measure(
|
||||||
"openToRead" + requestId,
|
"openToRead" + "_" + filename,
|
||||||
"openToRead" + requestId,
|
"openToRead" + "_" + filename,
|
||||||
"openToReadEnd" + requestId,
|
"openToReadEnd" + "_" + filename,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
this.opfsWorker.postMessage({
|
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) => {
|
return Effect.async((cb) => {
|
||||||
const requestId = this.nextRequestId++;
|
const requestId = this.nextRequestId++;
|
||||||
performance.mark("createFile" + requestId);
|
performance.mark("createFile" + "_" + filename);
|
||||||
this.callbacks.set(requestId, (event) => {
|
this.callbacks.set(requestId, (event) => {
|
||||||
performance.mark("createFileEnd" + requestId);
|
performance.mark("createFileEnd" + "_" + filename);
|
||||||
performance.measure(
|
performance.measure(
|
||||||
"createFile" + requestId,
|
"createFile" + "_" + filename,
|
||||||
"createFile" + requestId,
|
"createFile" + "_" + filename,
|
||||||
"createFileEnd" + requestId,
|
"createFileEnd" + "_" + filename,
|
||||||
);
|
);
|
||||||
cb(Effect.succeed(event.data.handle));
|
cb(Effect.succeed({id: event.data.handle, filename}));
|
||||||
});
|
});
|
||||||
this.opfsWorker.postMessage({
|
this.opfsWorker.postMessage({
|
||||||
type: "createFile",
|
type: "createFile",
|
||||||
@@ -96,18 +96,18 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
|||||||
|
|
||||||
openToWrite(
|
openToWrite(
|
||||||
filename: string,
|
filename: string,
|
||||||
): Effect.Effect<FileSystemFileHandle, FSErr, never> {
|
): Effect.Effect<{id: number, filename: string}, FSErr, never> {
|
||||||
return Effect.async((cb) => {
|
return Effect.async((cb) => {
|
||||||
const requestId = this.nextRequestId++;
|
const requestId = this.nextRequestId++;
|
||||||
performance.mark("openToWrite" + requestId);
|
performance.mark("openToWrite" + "_" + filename);
|
||||||
this.callbacks.set(requestId, (event) => {
|
this.callbacks.set(requestId, (event) => {
|
||||||
performance.mark("openToWriteEnd" + requestId);
|
performance.mark("openToWriteEnd" + "_" + filename);
|
||||||
performance.measure(
|
performance.measure(
|
||||||
"openToWrite" + requestId,
|
"openToWrite" + "_" + filename,
|
||||||
"openToWrite" + requestId,
|
"openToWrite" + "_" + filename,
|
||||||
"openToWriteEnd" + requestId,
|
"openToWriteEnd" + "_" + filename,
|
||||||
);
|
);
|
||||||
cb(Effect.succeed(event.data.handle));
|
cb(Effect.succeed({id: event.data.handle, filename}));
|
||||||
});
|
});
|
||||||
this.opfsWorker.postMessage({
|
this.opfsWorker.postMessage({
|
||||||
type: "openToWrite",
|
type: "openToWrite",
|
||||||
@@ -118,24 +118,24 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
append(
|
append(
|
||||||
handle: number,
|
handle: {id: number, filename: string},
|
||||||
data: Uint8Array,
|
data: Uint8Array,
|
||||||
): Effect.Effect<void, FSErr, never> {
|
): Effect.Effect<void, FSErr, never> {
|
||||||
return Effect.async((cb) => {
|
return Effect.async((cb) => {
|
||||||
const requestId = this.nextRequestId++;
|
const requestId = this.nextRequestId++;
|
||||||
performance.mark("append" + requestId);
|
performance.mark("append" + "_" + handle.filename);
|
||||||
this.callbacks.set(requestId, (_) => {
|
this.callbacks.set(requestId, (_) => {
|
||||||
performance.mark("appendEnd" + requestId);
|
performance.mark("appendEnd" + "_" + handle.filename);
|
||||||
performance.measure(
|
performance.measure(
|
||||||
"append" + requestId,
|
"append" + "_" + handle.filename,
|
||||||
"append" + requestId,
|
"append" + "_" + handle.filename,
|
||||||
"appendEnd" + requestId,
|
"appendEnd" + "_" + handle.filename,
|
||||||
);
|
);
|
||||||
cb(Effect.succeed(undefined));
|
cb(Effect.succeed(undefined));
|
||||||
});
|
});
|
||||||
this.opfsWorker.postMessage({
|
this.opfsWorker.postMessage({
|
||||||
type: "append",
|
type: "append",
|
||||||
handle,
|
handle: handle.id,
|
||||||
data,
|
data,
|
||||||
requestId,
|
requestId,
|
||||||
});
|
});
|
||||||
@@ -143,25 +143,25 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
read(
|
read(
|
||||||
handle: number,
|
handle: {id: number, filename: string},
|
||||||
offset: number,
|
offset: number,
|
||||||
length: number,
|
length: number,
|
||||||
): Effect.Effect<Uint8Array, FSErr, never> {
|
): Effect.Effect<Uint8Array, FSErr, never> {
|
||||||
return Effect.async((cb) => {
|
return Effect.async((cb) => {
|
||||||
const requestId = this.nextRequestId++;
|
const requestId = this.nextRequestId++;
|
||||||
performance.mark("read" + requestId);
|
performance.mark("read" + "_" + handle.filename);
|
||||||
this.callbacks.set(requestId, (event) => {
|
this.callbacks.set(requestId, (event) => {
|
||||||
performance.mark("readEnd" + requestId);
|
performance.mark("readEnd" + "_" + handle.filename);
|
||||||
performance.measure(
|
performance.measure(
|
||||||
"read" + requestId,
|
"read" + "_" + handle.filename,
|
||||||
"read" + requestId,
|
"read" + "_" + handle.filename,
|
||||||
"readEnd" + requestId,
|
"readEnd" + "_" + handle.filename,
|
||||||
);
|
);
|
||||||
cb(Effect.succeed(event.data.data));
|
cb(Effect.succeed(event.data.data));
|
||||||
});
|
});
|
||||||
this.opfsWorker.postMessage({
|
this.opfsWorker.postMessage({
|
||||||
type: "read",
|
type: "read",
|
||||||
handle,
|
handle: handle.id,
|
||||||
offset,
|
offset,
|
||||||
length,
|
length,
|
||||||
requestId,
|
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) => {
|
return Effect.async((cb) => {
|
||||||
const requestId = this.nextRequestId++;
|
const requestId = this.nextRequestId++;
|
||||||
performance.mark("close" + requestId);
|
performance.mark("close" + "_" + handle.filename);
|
||||||
this.callbacks.set(requestId, (_) => {
|
this.callbacks.set(requestId, (_) => {
|
||||||
performance.mark("closeEnd" + requestId);
|
performance.mark("closeEnd" + "_" + handle.filename);
|
||||||
performance.measure(
|
performance.measure(
|
||||||
"close" + requestId,
|
"close" + "_" + handle.filename,
|
||||||
"close" + requestId,
|
"close" + "_" + handle.filename,
|
||||||
"closeEnd" + requestId,
|
"closeEnd" + "_" + handle.filename,
|
||||||
);
|
);
|
||||||
cb(Effect.succeed(undefined));
|
cb(Effect.succeed(undefined));
|
||||||
});
|
});
|
||||||
this.opfsWorker.postMessage({
|
this.opfsWorker.postMessage({
|
||||||
type: "close",
|
type: "close",
|
||||||
handle,
|
handle: handle.id,
|
||||||
requestId,
|
requestId,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
closeAndRename(
|
closeAndRename(
|
||||||
handle: number,
|
handle: {id: number, filename: string},
|
||||||
filename: BlockFilename,
|
filename: BlockFilename,
|
||||||
): Effect.Effect<void, FSErr, never> {
|
): Effect.Effect<void, FSErr, never> {
|
||||||
return Effect.async((cb) => {
|
return Effect.async((cb) => {
|
||||||
const requestId = this.nextRequestId++;
|
const requestId = this.nextRequestId++;
|
||||||
performance.mark("closeAndRename" + requestId);
|
performance.mark("closeAndRename" + "_" + handle.filename);
|
||||||
this.callbacks.set(requestId, () => {
|
this.callbacks.set(requestId, () => {
|
||||||
performance.mark("closeAndRenameEnd" + requestId);
|
performance.mark(
|
||||||
|
"closeAndRenameEnd" + "_" + handle.filename,
|
||||||
|
);
|
||||||
performance.measure(
|
performance.measure(
|
||||||
"closeAndRename" + requestId,
|
"closeAndRename" + "_" + handle.filename,
|
||||||
"closeAndRename" + requestId,
|
"closeAndRename" + "_" + handle.filename,
|
||||||
"closeAndRenameEnd" + requestId,
|
"closeAndRenameEnd" + "_" + handle.filename,
|
||||||
);
|
);
|
||||||
cb(Effect.succeed(undefined));
|
cb(Effect.succeed(undefined));
|
||||||
});
|
});
|
||||||
this.opfsWorker.postMessage({
|
this.opfsWorker.postMessage({
|
||||||
type: "closeAndRename",
|
type: "closeAndRename",
|
||||||
handle,
|
handle: handle.id,
|
||||||
filename,
|
filename,
|
||||||
requestId,
|
requestId,
|
||||||
});
|
});
|
||||||
@@ -220,13 +222,13 @@ export class OPFSFilesystem implements FileSystem<number, number> {
|
|||||||
): Effect.Effect<void, FSErr, never> {
|
): Effect.Effect<void, FSErr, never> {
|
||||||
return Effect.async((cb) => {
|
return Effect.async((cb) => {
|
||||||
const requestId = this.nextRequestId++;
|
const requestId = this.nextRequestId++;
|
||||||
performance.mark("removeFile" + requestId);
|
performance.mark("removeFile" + "_" + filename);
|
||||||
this.callbacks.set(requestId, () => {
|
this.callbacks.set(requestId, () => {
|
||||||
performance.mark("removeFileEnd" + requestId);
|
performance.mark("removeFileEnd" + "_" + filename);
|
||||||
performance.measure(
|
performance.measure(
|
||||||
"removeFile" + requestId,
|
"removeFile" + "_" + filename,
|
||||||
"removeFile" + requestId,
|
"removeFile" + "_" + filename,
|
||||||
"removeFileEnd" + requestId,
|
"removeFileEnd" + "_" + filename,
|
||||||
);
|
);
|
||||||
cb(Effect.succeed(undefined));
|
cb(Effect.succeed(undefined));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export async function createJazzBrowserContext<Acc extends Account>({
|
|||||||
auth: AuthProvider<Acc>;
|
auth: AuthProvider<Acc>;
|
||||||
peer: `wss://${string}` | `ws://${string}`;
|
peer: `wss://${string}` | `ws://${string}`;
|
||||||
reconnectionTimeout?: number;
|
reconnectionTimeout?: number;
|
||||||
storage?: "indexedDB" | "experimentalOPFSdoNotUseOrYouWillBeFired";
|
storage?: "indexedDB" | "singleTabOPFS";
|
||||||
crypto?: CryptoProvider;
|
crypto?: CryptoProvider;
|
||||||
}): Promise<BrowserContext<Acc>> {
|
}): Promise<BrowserContext<Acc>> {
|
||||||
const crypto = customCrypto || (await WasmCrypto.create());
|
const crypto = customCrypto || (await WasmCrypto.create());
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# jazz-autosub
|
# 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
|
## 0.7.22
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "0.7.22",
|
"version": "0.7.23",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cojson": "workspace:*",
|
"cojson": "workspace:*",
|
||||||
"cojson-transport-ws": "workspace:*",
|
"cojson-transport-ws": "workspace:*",
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
# jazz-react
|
# 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
|
## 0.7.22
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jazz-react",
|
"name": "jazz-react",
|
||||||
"version": "0.7.22",
|
"version": "0.7.23",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export function createJazzReactContext<Acc extends Account>({
|
|||||||
}: {
|
}: {
|
||||||
auth: ReactAuthHook<Acc>;
|
auth: ReactAuthHook<Acc>;
|
||||||
peer: `wss://${string}` | `ws://${string}`;
|
peer: `wss://${string}` | `ws://${string}`;
|
||||||
storage?: "indexedDB" | "experimentalOPFSdoNotUseOrYouWillBeFired";
|
storage?: "indexedDB" | "singleTabOPFS";
|
||||||
}): JazzReactContext<Acc> {
|
}): JazzReactContext<Acc> {
|
||||||
const JazzContext = React.createContext<
|
const JazzContext = React.createContext<
|
||||||
| {
|
| {
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# jazz-autosub
|
# 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
|
## 0.7.22
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"bin": "./dist/index.js",
|
"bin": "./dist/index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "0.7.22",
|
"version": "0.7.23",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint . --ext ts,tsx",
|
"lint": "eslint . --ext ts,tsx",
|
||||||
"format": "prettier --write './src/**/*.{ts,tsx}'",
|
"format": "prettier --write './src/**/*.{ts,tsx}'",
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# jazz-autosub
|
# jazz-autosub
|
||||||
|
|
||||||
|
## 0.7.23
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Mostly complete OPFS implementation (single-tab only)
|
||||||
|
- Updated dependencies
|
||||||
|
- cojson@0.7.23
|
||||||
|
|
||||||
## 0.7.21
|
## 0.7.21
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"types": "./src/index.ts",
|
"types": "./src/index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "0.7.21",
|
"version": "0.7.23",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@effect/schema": "^0.66.16",
|
"@effect/schema": "^0.66.16",
|
||||||
"cojson": "workspace:*",
|
"cojson": "workspace:*",
|
||||||
|
|||||||
Reference in New Issue
Block a user