From 1be57ebf0d4924e4d2f11fda2dfdc5d678205807 Mon Sep 17 00:00:00 2001 From: Steven Vandevelde Date: Tue, 12 Dec 2023 13:06:26 +0100 Subject: [PATCH] wip --- packages/nest/src/class.ts | 2 +- packages/nest/src/mutations.ts | 60 ++++++------ packages/nest/src/queries.ts | 105 +++++++++++--------- packages/nest/src/references.ts | 46 +++++++++ packages/nest/src/root-tree.ts | 16 ++- packages/nest/src/root-tree/basic.ts | 140 ++++++++++++++++++--------- packages/nest/src/store.ts | 2 +- packages/nest/src/transaction.ts | 106 ++++++++++---------- packages/nest/src/types.ts | 11 ++- 9 files changed, 301 insertions(+), 187 deletions(-) create mode 100644 packages/nest/src/references.ts diff --git a/packages/nest/src/class.ts b/packages/nest/src/class.ts index 2b594e0..6246016 100644 --- a/packages/nest/src/class.ts +++ b/packages/nest/src/class.ts @@ -738,7 +738,7 @@ export class FileSystem { this.#blockStore, { ...this.#privateNodes }, this.#rng, - { ...this.#rootTree } + this.#rootTree.clone() ) } diff --git a/packages/nest/src/mutations.ts b/packages/nest/src/mutations.ts index 49e1330..86d0444 100644 --- a/packages/nest/src/mutations.ts +++ b/packages/nest/src/mutations.ts @@ -1,10 +1,6 @@ -import type { BlockStore } from 'wnfs' +import type { Blockstore } from 'interface-blockstore' import type * as Path from './path.js' - -// TODO: import * as Unix from "./unix.js" - -import { searchLatest } from './common.js' import type { Rng } from './rng.js' import type { RootTree } from './root-tree.js' import type { MutationType } from './types.js' @@ -15,6 +11,11 @@ import type { WnfsPublicResult, } from './types/internal.js' +import * as Store from './store.js' +import * as Unix from './unix.js' + +import { searchLatest } from './common.js' + // 🏔️ export const TYPES: Record = { @@ -25,7 +26,7 @@ export const TYPES: Record = { // PUBLIC export interface PublicParams { - blockStore: BlockStore + blockstore: Blockstore pathSegments: Path.Segments rootTree: RootTree } @@ -34,40 +35,39 @@ export type Public = (params: PublicParams) => Promise export const publicCreateDirectory = () => { return async (params: PublicParams): Promise => { - return await params.rootTree.publicRoot.mkdir( - params.pathSegments, - new Date(), - params.blockStore - ) + return await params.rootTree + .publicRoot() + .mkdir(params.pathSegments, new Date(), Store.wnfs(params.blockstore)) } } export const publicRemove = () => { return async (params: PublicParams): Promise => { - return await params.rootTree.publicRoot.rm( - params.pathSegments, - params.blockStore - ) + return await params.rootTree + .publicRoot() + .rm(params.pathSegments, Store.wnfs(params.blockstore)) } } export const publicWrite = (bytes: Uint8Array) => { return async (params: PublicParams): Promise => { - const cid = await Unix.importFile(bytes, params.dependencies.depot) - - return await params.rootTree.publicRoot.write( - params.pathSegments, - cid.bytes, - new Date(), - params.blockStore - ) + const cid = await Unix.importFile(bytes, params.blockstore) + + return await params.rootTree + .publicRoot() + .write( + params.pathSegments, + cid.bytes, + new Date(), + Store.wnfs(params.blockstore) + ) } } // PRIVATE export type PrivateParams = { - blockStore: BlockStore + blockstore: Blockstore privateNodes: MountedPrivateNodes rng: Rng rootTree: RootTree @@ -86,8 +86,8 @@ export const privateCreateDirectory = () => { params.remainder, searchLatest(), new Date(), - params.rootTree.privateForest, - params.blockStore, + params.rootTree.privateForest(), + Store.wnfs(params.blockstore), params.rng ) } @@ -104,8 +104,8 @@ export const privateRemove = () => { .rm( params.remainder, searchLatest(), - params.rootTree.privateForest, - params.blockStore + params.rootTree.privateForest(), + Store.wnfs(params.blockstore) ) } } @@ -123,8 +123,8 @@ export const privateWrite = (bytes: Uint8Array) => { searchLatest(), bytes, new Date(), - params.rootTree.privateForest, - params.blockStore, + params.rootTree.privateForest(), + Store.wnfs(params.blockstore), params.rng ) } diff --git a/packages/nest/src/queries.ts b/packages/nest/src/queries.ts index 1044194..0ff0f2a 100644 --- a/packages/nest/src/queries.ts +++ b/packages/nest/src/queries.ts @@ -1,6 +1,6 @@ +import type { Blockstore } from 'interface-blockstore' import type { AccessKey, - BlockStore, PrivateDirectory, PrivateFile, PublicDirectory, @@ -10,7 +10,9 @@ import type { import { PrivateNode } from 'wnfs' import { CID } from 'multiformats' +import * as Store from './store.js' import * as Path from './path.js' +import * as Unix from './unix.js' import type { Partitioned } from './path.js' import type { Rng } from './rng.js' @@ -27,7 +29,7 @@ import { findPrivateNode } from './mounts.js' // PUBLIC export interface PublicParams { - blockStore: BlockStore + blockstore: Blockstore pathSegments: Path.Segments rootTree: RootTree } @@ -41,7 +43,7 @@ export async function publicQuery( context: PublicContext ): Promise { return await qry({ - blockStore: context.blockStore, + blockstore: context.blockstore, pathSegments: Path.unwrap(Path.removePartition(path)), rootTree: context.rootTree, }) @@ -49,10 +51,9 @@ export async function publicQuery( export const publicExists = () => { return async (params: PublicParams): Promise => { - const result = await params.rootTree.publicRoot.getNode( - params.pathSegments, - params.blockStore - ) + const result = await params.rootTree + .publicRoot() + .getNode(params.pathSegments, Store.wnfs(params.blockstore)) return result !== null && result !== undefined } @@ -60,7 +61,9 @@ export const publicExists = () => { export const publicListDirectory = () => { return async (params: PublicParams): Promise => { - return params.rootTree.publicRoot.ls(params.pathSegments, params.blockStore) + return await params.rootTree + .publicRoot() + .ls(params.pathSegments, Store.wnfs(params.blockstore)) } } @@ -69,17 +72,22 @@ export const publicListDirectoryWithKind = () => { const dir: PublicDirectory = params.pathSegments.length === 0 ? params.rootTree.publicRoot - : await params.rootTree.publicRoot - .getNode(params.pathSegments, params.blockStore) + : await params.rootTree + .publicRoot() + .getNode(params.pathSegments, Store.wnfs(params.blockstore)) .then((a) => a.asDir()) - const items: DirectoryItem[] = await dir.ls([], params.blockStore) + const items: DirectoryItem[] = await dir.ls( + [], + Store.wnfs(params.blockstore) + ) const promises = items.map(async (item): Promise => { const node: PublicNode = await dir.lookupNode( item.name, - params.blockStore + Store.wnfs(params.blockstore) ) - const kind = node.isDir() === true ? Path.Kind.Directory : Path.Kind.File + + const kind = node.isDir() ? Path.Kind.Directory : Path.Kind.File return { ...item, @@ -97,10 +105,9 @@ export const publicListDirectoryWithKind = () => { export const publicRead = (options?: { offset: number; length: number }) => { return async (params: PublicParams): Promise => { - const result = await params.rootTree.publicRoot.read( - params.pathSegments, - params.blockStore - ) + const result = await params.rootTree + .publicRoot() + .read(params.pathSegments, Store.wnfs(params.blockstore)) return await publicReadFromCID(CID.decode(result), options)(params) } @@ -111,16 +118,14 @@ export const publicReadFromCID = ( options?: { offset: number; length: number } ) => { return async (context: PublicContext): Promise => { - // TODO: - // return Unix.exportFile(cid, context.dependencies.depot, options) - return new Uint8Array() + return await Unix.exportFile(cid, context.blockstore, options) } } // PRIVATE export type PrivateParams = { - blockStore: BlockStore + blockstore: Blockstore privateNodes: MountedPrivateNodes rng: Rng rootTree: RootTree @@ -139,7 +144,7 @@ export async function privateQuery( // Perform mutation return await qry({ ...priv, - blockStore: context.blockStore, + blockstore: context.blockstore, privateNodes: context.privateNodes, rng: context.rng, rootTree: context.rootTree, @@ -148,15 +153,15 @@ export async function privateQuery( export const privateExists = () => { return async (params: PrivateParams): Promise => { - if (params.node.isFile() === true) return true + if (params.node.isFile()) return true const result = await params.node .asDir() .getNode( params.remainder, searchLatest(), - params.rootTree.privateForest, - params.blockStore + params.rootTree.privateForest(), + Store.wnfs(params.blockstore) ) return result !== null && result !== undefined @@ -165,14 +170,14 @@ export const privateExists = () => { export const privateListDirectory = () => { return async (params: PrivateParams): Promise => { - if (params.node.isFile() === true) throw new Error('Cannot list a file') + if (params.node.isFile()) throw new Error('Cannot list a file') const { result } = await params.node .asDir() .ls( params.remainder, searchLatest(), - params.rootTree.privateForest, - params.blockStore + params.rootTree.privateForest(), + Store.wnfs(params.blockstore) ) return result } @@ -180,7 +185,7 @@ export const privateListDirectory = () => { export const privateListDirectoryWithKind = () => { return async (params: PrivateParams): Promise => { - if (params.node.isFile() === true) throw new Error('Cannot list a file') + if (params.node.isFile()) throw new Error('Cannot list a file') const dir: PrivateDirectory = params.remainder.length === 0 @@ -190,12 +195,17 @@ export const privateListDirectoryWithKind = () => { .getNode( params.remainder, searchLatest(), - params.rootTree.privateForest, - params.blockStore + params.rootTree.privateForest(), + Store.wnfs(params.blockstore) ) .then((a) => a.asDir()) const items: DirectoryItem[] = await dir - .ls([], searchLatest(), params.rootTree.privateForest, params.blockStore) + .ls( + [], + searchLatest(), + params.rootTree.privateForest(), + Store.wnfs(params.blockstore) + ) .then((a) => a.result) const parentPath = Path.combine( @@ -212,12 +222,11 @@ export const privateListDirectoryWithKind = () => { const node: PrivateNode = await dir.lookupNode( item.name, searchLatest(), - params.rootTree.privateForest, - params.blockStore + params.rootTree.privateForest(), + Store.wnfs(params.blockstore) ) - const kind = - node.isDir() === true ? Path.Kind.Directory : Path.Kind.File + const kind = node.isDir() ? Path.Kind.Directory : Path.Kind.File return { ...item, @@ -231,7 +240,7 @@ export const privateListDirectoryWithKind = () => { } } -export const privateRead = (options?: { offset: number; length: number }) => { +export const privateRead = (_options?: { offset: number; length: number }) => { return async (params: PrivateParams): Promise => { // TODO: Respect `offset` and `length` options when private streaming API is exposed in rs-wnfs // const offset = options?.offset @@ -239,18 +248,21 @@ export const privateRead = (options?: { offset: number; length: number }) => { let bytes - if (params.node.isFile() === true) { + if (params.node.isFile()) { bytes = await params.node .asFile() - .getContent(params.rootTree.privateForest, params.blockStore) + .getContent( + params.rootTree.privateForest(), + Store.wnfs(params.blockstore) + ) } else { const { result } = await params.node .asDir() .read( params.remainder, searchLatest(), - params.rootTree.privateForest, - params.blockStore + params.rootTree.privateForest(), + Store.wnfs(params.blockstore) ) bytes = result } @@ -261,7 +273,7 @@ export const privateRead = (options?: { offset: number; length: number }) => { export const privateReadFromAccessKey = ( accessKey: AccessKey, - options?: { offset: number; length: number } + _options?: { offset: number; length: number } ) => { return async (context: PrivateContext): Promise => { // TODO: Respect `offset` and `length` options when private streaming API is exposed in rs-wnfs @@ -271,15 +283,18 @@ export const privateReadFromAccessKey = ( // Retrieve node const node = await PrivateNode.load( accessKey, - context.rootTree.privateForest, - context.blockStore + context.rootTree.privateForest(), + Store.wnfs(context.blockstore) ) if (node.isFile() === true) { const file: PrivateFile = node.asFile() // TODO: Respect the offset and length options when available in rs-wnfs - return file.getContent(context.rootTree.privateForest, context.blockStore) + return await file.getContent( + context.rootTree.privateForest(), + Store.wnfs(context.blockstore) + ) } else { throw new Error('Expected a file, found a directory') } diff --git a/packages/nest/src/references.ts b/packages/nest/src/references.ts new file mode 100644 index 0000000..a8322e4 --- /dev/null +++ b/packages/nest/src/references.ts @@ -0,0 +1,46 @@ +import type { Blockstore } from 'interface-blockstore' +import type { PublicNode } from 'wnfs' + +import { CID } from 'multiformats' + +import type * as Path from './path.js' +import type { RootTree } from './root-tree.js' + +import * as Store from './store.js' +import { pathSegmentsWithoutPartition } from './common.js' + +export async function contentCID( + blockstore: Blockstore, + rootTree: RootTree, + path: Path.File> +): Promise { + const wnfsBlockstore = Store.wnfs(blockstore) + const result = await rootTree + .publicRoot() + .getNode(pathSegmentsWithoutPartition(path), wnfsBlockstore) + + const maybeNode: PublicNode | undefined = result ?? undefined + return maybeNode?.isFile() === true + ? CID.decode(maybeNode.asFile().contentCid()) + : undefined +} + +export async function capsuleCID( + blockstore: Blockstore, + rootTree: RootTree, + path: Path.Distinctive> +): Promise { + const wnfsBlockstore = Store.wnfs(blockstore) + const result = await rootTree + .publicRoot() + .getNode(pathSegmentsWithoutPartition(path), wnfsBlockstore) + + const maybeNode: PublicNode | undefined = result ?? undefined + return maybeNode === undefined + ? undefined + : CID.decode( + maybeNode.isFile() + ? await maybeNode.asFile().store(wnfsBlockstore) + : await maybeNode.asDir().store(wnfsBlockstore) + ) +} diff --git a/packages/nest/src/root-tree.ts b/packages/nest/src/root-tree.ts index f162ed5..9034073 100644 --- a/packages/nest/src/root-tree.ts +++ b/packages/nest/src/root-tree.ts @@ -2,14 +2,24 @@ import type { Blockstore } from 'interface-blockstore' import type { CID } from 'multiformats' import type { PrivateForest, PublicDirectory } from 'wnfs' +import type { FileSystemChange } from './types.js' + /** * The tree that ties different file systems together. */ export abstract class RootTree { - abstract privateForest: PrivateForest - abstract publicRoot: PublicDirectory + abstract privateForest(): PrivateForest + abstract replacePrivateForest( + forest: PrivateForest, + changes: FileSystemChange[] + ): Promise + abstract publicRoot(): PublicDirectory + abstract replacePublicRoot( + dir: PublicDirectory, + changes: FileSystemChange[] + ): Promise - abstract commit(privateForest: PrivateForest): Promise + abstract clone(): RootTree abstract store(): Promise static async create(_blockstore: Blockstore): Promise { diff --git a/packages/nest/src/root-tree/basic.ts b/packages/nest/src/root-tree/basic.ts index a4f4860..0ef1329 100644 --- a/packages/nest/src/root-tree/basic.ts +++ b/packages/nest/src/root-tree/basic.ts @@ -9,25 +9,28 @@ import { webcrypto } from 'iso-base/crypto' import { CID } from 'multiformats' import { PrivateForest, PublicDirectory } from 'wnfs' -import * as Unix from '../unix.js' +import * as Path from '../path.js' +import * as References from '../references.js' import * as Store from '../store.js' +import * as Unix from '../unix.js' import * as Version from '../version.js' +import type { RootTree } from '../root-tree.js' +import type { FileSystemChange } from '../types.js' + import { RootBranch } from '../path.js' import { makeRngInterface } from '../rng.js' -import type { RootTree } from '../root-tree.js' // CLASS export class BasicRootTree implements RootTree { readonly #blockstore: Blockstore readonly #exchangeRoot: PublicDirectory + readonly #privateForest: PrivateForest + readonly #publicRoot: PublicDirectory readonly #unix: PBNode readonly #version: string - publicRoot: PublicDirectory - privateForest: PrivateForest - constructor({ blockstore, exchangeRoot, @@ -38,18 +41,17 @@ export class BasicRootTree implements RootTree { }: { blockstore: Blockstore exchangeRoot: PublicDirectory - publicRoot: PublicDirectory privateForest: PrivateForest + publicRoot: PublicDirectory unix: PBNode version: string }) { this.#blockstore = blockstore this.#exchangeRoot = exchangeRoot + this.#privateForest = privateForest + this.#publicRoot = publicRoot this.#unix = unix this.#version = version - - this.publicRoot = publicRoot - this.privateForest = privateForest } /** @@ -77,7 +79,7 @@ export class BasicRootTree implements RootTree { blockstore: Blockstore ): Promise { const currentTime = new Date() - const wnfsStore = Store.wnfsStoreInterface(blockstore) + const wnfsStore = Store.wnfs(blockstore) // Retrieve links const links = await linksFromCID(cid, blockstore) @@ -142,48 +144,94 @@ export class BasicRootTree implements RootTree { }) } - async commit(_privateForest: PrivateForest): Promise { - throw new Error('Not implemented!') - - // const unixTree = await changes.reduce(async (oldRootPromise, change) => { - // const oldRoot = await oldRootPromise - - // if (!Path.isPartition('public', change.path)) { - // return oldRoot - // } - - // const path = Path.removePartition(change.path) - - // if (change.type === 'removed') { - // return Unix.removeNodeFromTree( - // oldRoot, - // path, - // context.#dependencies.depot - // ) - // } - - // const contentCID = - // Path.isFile(change.path) && - // Path.isPartitionedNonEmpty(change.path) - // ? await context.contentCID(change.path).then((a) => a ?? undefined) - // : undefined - - // return Unix.insertNodeIntoTree( - // oldRoot, - // path, - // context.#dependencies.depot, - // contentCID - // ) - // }, Promise.resolve(context.#rootTree.unix)) + privateForest(): PrivateForest { + return this.#privateForest + } + + async replacePrivateForest( + forest: PrivateForest, + _changes: FileSystemChange[] + ): Promise { + return new BasicRootTree({ + blockstore: this.#blockstore, + + exchangeRoot: this.#exchangeRoot, + publicRoot: this.#publicRoot, + privateForest: forest, + unix: this.#unix, + version: this.#version, + }) + } + + publicRoot(): PublicDirectory { + return this.#publicRoot + } + + async replacePublicRoot( + dir: PublicDirectory, + changes: FileSystemChange[] + ): Promise { + const unixTree = await changes.reduce(async (oldRootPromise, change) => { + const oldRoot = await oldRootPromise + + if (!Path.isPartition('public', change.path)) { + return oldRoot + } + + const path = Path.removePartition(change.path) + + if (change.type === 'removed') { + return await Unix.removeNodeFromTree(oldRoot, path, this.#blockstore) + } + + const contentCID = + Path.isFile(change.path) && + Path.isPartitionedNonEmpty(change.path) + ? await References.contentCID( + this.#blockstore, + this, + change.path + ).then((a) => a ?? undefined) + : undefined + + return await Unix.insertNodeIntoTree( + oldRoot, + path, + this.#blockstore, + contentCID + ) + }, Promise.resolve(this.#unix)) + + return new BasicRootTree({ + blockstore: this.#blockstore, + + exchangeRoot: this.#exchangeRoot, + publicRoot: dir, + privateForest: this.#privateForest, + unix: unixTree, + version: this.#version, + }) + } + + clone(): RootTree { + return new BasicRootTree({ + blockstore: this.#blockstore, + + exchangeRoot: this.#exchangeRoot, + publicRoot: this.#publicRoot, + privateForest: this.#privateForest, + unix: this.#unix, + version: this.#version, + }) } async store(): Promise { - const wnfsStore = Store.wnfsStoreInterface(this.#blockstore) + const wnfsStore = Store.wnfs(this.#blockstore) // Store all pieces const exchangeRoot = await this.#exchangeRoot.store(wnfsStore) - const privateForest = await this.privateForest.store(wnfsStore) - const publicRoot = await this.publicRoot.store(wnfsStore) + const privateForest = await this.#privateForest.store(wnfsStore) + const publicRoot = await this.#publicRoot.store(wnfsStore) const unixTree = await Store.store( DagPB.encode(this.#unix), DagPB.code, diff --git a/packages/nest/src/store.ts b/packages/nest/src/store.ts index 296cdb3..5758383 100644 --- a/packages/nest/src/store.ts +++ b/packages/nest/src/store.ts @@ -21,7 +21,7 @@ export async function cid(bytes: Uint8Array, codecId: number): Promise { return CID.createV1(codec.code, multihash) } -export function wnfsStoreInterface(blockstore: Blockstore): WnfsBlockStore { +export function wnfs(blockstore: Blockstore): WnfsBlockStore { return { async getBlock(cid: Uint8Array): Promise { const decodedCid = CID.decode(cid) diff --git a/packages/nest/src/transaction.ts b/packages/nest/src/transaction.ts index 7d6ff3c..886dc2b 100644 --- a/packages/nest/src/transaction.ts +++ b/packages/nest/src/transaction.ts @@ -1,12 +1,14 @@ +import type { PrivateForest, PrivateNode } from 'wnfs' +import type { Blockstore } from 'interface-blockstore' + import { CID } from 'multiformats' -import type { BlockStore, PrivateForest, PrivateNode, PublicNode } from 'wnfs' import { AccessKey, PublicFile } from 'wnfs' import * as Path from './path.js' import * as Mutations from './mutations.js' import * as Queries from './queries.js' - -// import * as Unix from './unix.js' +import * as References from './references.js' +import * as Store from './store.js' import type { Partition, @@ -14,13 +16,9 @@ import type { PartitionedNonEmpty, Private, Public, -} from './path/index.js' +} from './path.js' -import { - addOrIncreaseNameNumber, - pathSegmentsWithoutPartition, - searchLatest, -} from './common.js' +import { addOrIncreaseNameNumber, searchLatest } from './common.js' import { dataFromBytes, dataToBytes } from './data.js' import { partition as determinePartition, findPrivateNode } from './mounts.js' @@ -45,7 +43,7 @@ import type { /** @group File System */ export class TransactionContext { - readonly #blockStore: BlockStore + readonly #blockstore: Blockstore readonly #rng: Rng #privateNodes: MountedPrivateNodes @@ -58,12 +56,12 @@ export class TransactionContext { /** @internal */ constructor( - blockStore: BlockStore, + blockstore: Blockstore, privateNodes: MountedPrivateNodes, rng: Rng, rootTree: RootTree ) { - this.#blockStore = blockStore + this.#blockstore = blockstore this.#privateNodes = privateNodes this.#rng = rng this.#rootTree = rootTree @@ -98,16 +96,19 @@ export class TransactionContext { const [_newAccessKey, newForest] = await maybeNode.node.store( oldForest, - context.#blockStore, + Store.wnfs(context.#blockstore), context.#rng ) return newForest }, - Promise.resolve(context.#rootTree.privateForest) + Promise.resolve(context.#rootTree.privateForest()) ) // Replace forest - const rootTree = await context.#rootTree.commit(newForest) + const rootTree = await context.#rootTree.replacePrivateForest( + newForest, + changes + ) // Fin return { @@ -123,34 +124,14 @@ export class TransactionContext { async contentCID( path: Path.File> ): Promise { - const result = await this.#rootTree.publicRoot.getNode( - pathSegmentsWithoutPartition(path), - this.#blockStore - ) - - const maybeNode: PublicNode | undefined = result ?? undefined - return maybeNode?.isFile() === true - ? CID.decode(maybeNode.asFile().contentCid()) - : undefined + return await References.contentCID(this.#blockstore, this.#rootTree, path) } /** @group Querying */ async capsuleCID( path: Path.Distinctive> ): Promise { - const result = await this.#rootTree.publicRoot.getNode( - pathSegmentsWithoutPartition(path), - this.#blockStore - ) - - const maybeNode: PublicNode | undefined = result ?? undefined - return maybeNode === undefined - ? undefined - : CID.decode( - maybeNode.isFile() - ? await maybeNode.asFile().store(this.#blockStore) - : await maybeNode.asDir().store(this.#blockStore) - ) + return await References.capsuleCID(this.#blockstore, this.#rootTree, path) } /** @group Querying */ @@ -167,7 +148,11 @@ export class TransactionContext { return priv.remainder.length === 0 || priv.node.isFile() ? await priv.node - .store(this.#rootTree.privateForest, this.#blockStore, this.#rng) + .store( + this.#rootTree.privateForest(), + Store.wnfs(this.#blockstore), + this.#rng + ) .then(([accessKey]: [AccessKey, PrivateForest]) => accessKey.toBytes() ) @@ -176,16 +161,16 @@ export class TransactionContext { .getNode( priv.remainder, searchLatest(), - this.#rootTree.privateForest, - this.#blockStore + this.#rootTree.privateForest(), + Store.wnfs(this.#blockstore) ) .then(async (result: PrivateNode | undefined) => { return result === undefined ? undefined : await result .store( - this.#rootTree.privateForest, - this.#blockStore, + this.#rootTree.privateForest(), + Store.wnfs(this.#blockstore), this.#rng ) .then(([accessKey]: [AccessKey, PrivateForest]) => @@ -275,7 +260,7 @@ export class TransactionContext { // Public content from capsule CID const publicFile: PublicFile = await PublicFile.load( arg.capsuleCID.bytes, - this.#blockStore + Store.wnfs(this.#blockstore) ) return await this.read( @@ -569,20 +554,24 @@ export class TransactionContext { mut: Mutations.Public, mutType: MutationType ): Promise { + const change = { + type: mutType, + path: path, + } + const result = await mut({ - blockStore: this.#blockStore, + blockstore: this.#blockstore, pathSegments: Path.unwrap(Path.removePartition(path)), rootTree: this.#rootTree, }) // Replace public root - this.#rootTree = { ...this.#rootTree, publicRoot: result.rootDir } + this.#rootTree = await this.#rootTree.replacePublicRoot(result.rootDir, [ + change, + ]) // Mark node as changed - this.#changes.add({ - type: mutType, - path: path, - }) + this.#changes.add(change) } async #privateMutation( @@ -591,24 +580,27 @@ export class TransactionContext { mutType: MutationType ): Promise { const priv = findPrivateNode(path, this.#privateNodes) + const change = { + type: mutType, + path: path, + } // Perform mutation const result = await mut({ ...priv, - blockStore: this.#blockStore, + blockstore: this.#blockstore, privateNodes: this.#privateNodes, rng: this.#rng, rootTree: this.#rootTree, }) // Mark node as changed - this.#changes.add({ - type: mutType, - path: path, - }) + this.#changes.add(change) // Replace forest - this.#rootTree = { ...this.#rootTree, privateForest: result.forest } + this.#rootTree = await this.#rootTree.replacePrivateForest(result.forest, [ + change, + ]) // Replace private node const nodePosix = Path.toPosix(priv.path, { absolute: true }) @@ -624,14 +616,14 @@ export class TransactionContext { #publicContext(): Queries.PublicContext { return { - blockStore: this.#blockStore, + blockstore: this.#blockstore, rootTree: this.#rootTree, } } #privateContext(): Queries.PrivateContext { return { - blockStore: this.#blockStore, + blockstore: this.#blockstore, privateNodes: this.#privateNodes, rng: this.#rng, rootTree: this.#rootTree, diff --git a/packages/nest/src/types.ts b/packages/nest/src/types.ts index afd1f47..5f4e40a 100644 --- a/packages/nest/src/types.ts +++ b/packages/nest/src/types.ts @@ -37,6 +37,12 @@ export type DirectoryItemWithKind = DirectoryItem & { path: Path.Distinctive> } +/** @group File System */ +export interface FileSystemChange { + path: Path.Distinctive> + type: MutationType +} + /** @group File System */ export interface MutationOptions { skipPublish?: boolean @@ -96,10 +102,7 @@ export type PrivateMutationResult = DataRootChange & { /** @group File System */ export interface TransactionResult { - changes: Array<{ - path: Path.Distinctive> - type: MutationType - }> + changes: FileSystemChange[] dataRoot: CID publishingStatus: Promise }