Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/auth/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ export class Auth {

return { writeCap: cap };
} catch (err) {
return new ValidationError(err);
return new ValidationError(err as string);
}
}

Expand Down
12 changes: 7 additions & 5 deletions src/schemes/schemes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,7 @@ export function makeMeadowcapParams(
};
}

export function makeAuthorisationScheme(
ed25519: Ed25519Driver<Uint8Array>,
blake3: Blake3Driver,
): Willow.AuthorisationScheme<
export type AuthorizationScheme = Willow.AuthorisationScheme<
SharePublicKey,
IdentityPublicKey,
Uint8Array,
Expand All @@ -255,7 +252,12 @@ export function makeAuthorisationScheme(
Uint8Array,
Uint8Array
>
> {
>;

export function makeAuthorisationScheme(
ed25519: Ed25519Driver<Uint8Array>,
blake3: Blake3Driver,
): AuthorizationScheme {
const meadowcapParams = makeMeadowcapParams(ed25519, blake3);
const meadowcap = new Meadowcap.Meadowcap(
meadowcapParams,
Expand Down
31 changes: 31 additions & 0 deletions src/store/store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -556,3 +556,34 @@ Deno.test("Store.queryIdentities", async () => {
}));
assertEquals(identities, [identityDisplay]);
});

Deno.test("Store.createDrop() and Store.ingestDrop()", async () => {
const source = newStore();
await source.set({
identity: identityDisplay,
path: Path.fromStrings("hello", "a"),
payload: new TextEncoder().encode("b"),
timestamp: 1000n,
});
await source.set({
identity: identityDisplay,
path: Path.fromStrings("hello", "c"),
payload: new TextEncoder().encode("d"),
timestamp: 2000n,
});

const dropStream = source.createDrop({
timestampGte: 1500n,
});
if (isErr(dropStream)) throw dropStream;

const target = newStore();
await target.ingestDrop(dropStream);

const v1 = await target.get(identityDisplay, Path.fromStrings("hello", "a"));
assertEquals(undefined, v1);

const v2 = await target.get(identityDisplay, Path.fromStrings("hello", "c"));
if (isErr(v2)) throw v2;
assertEquals(new TextEncoder().encode("d"), await v2?.payload?.bytes());
});
66 changes: 61 additions & 5 deletions src/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as Willow from "@earthstar/willow";
import { OPEN_END, successorPath } from "@earthstar/willow-utils";
import type { Auth, AuthorisationToken } from "../auth/auth.ts";
import {
type AuthorizationScheme,
fingerprintScheme,
makeAuthorisationScheme,
makePayloadScheme,
Expand Down Expand Up @@ -59,6 +60,7 @@ import { Path } from "../path/path.ts";
*/
export class Store extends EventTarget {
private auth: Auth;
private payloadScheme: Willow.PayloadScheme<Uint8Array>;

/** The underlying Willow `Store`, made accessible for advanced usage and shenanigans. */
willow: Willow.Store<
Expand All @@ -70,6 +72,7 @@ export class Store extends EventTarget {
PreFingerprint,
Uint8Array
>;
authorizationScheme: AuthorizationScheme;

/** The tag of the share this {@linkcode Store} belongs to. */
get share(): ShareTag {
Expand All @@ -93,18 +96,20 @@ export class Store extends EventTarget {
throw sharePublicKey;
}

this.payloadScheme = makePayloadScheme(drivers.runtimeDriver.blake3);
this.authorizationScheme = makeAuthorisationScheme(
drivers.runtimeDriver.ed25519,
drivers.runtimeDriver.blake3
);
this.willow = new Willow.Store({
namespace: sharePublicKey,
schemes: {
namespace: namespaceScheme,
subspace: subspaceScheme,
path: pathScheme,
payload: makePayloadScheme(drivers.runtimeDriver.blake3),
payload: this.payloadScheme,
fingerprint: fingerprintScheme,
authorisation: makeAuthorisationScheme(
drivers.runtimeDriver.ed25519,
drivers.runtimeDriver.blake3,
),
authorisation: this.authorizationScheme,
},
entryDriver: drivers.entryDriver || undefined,
payloadDriver: drivers.payloadDriver || undefined,
Expand All @@ -113,6 +118,57 @@ export class Store extends EventTarget {
relayWillowEvents(this, this.willow);
}


createDrop(
query: Query,
encryptTransform: TransformStream<Uint8Array> = new TransformStream()
): ReadableStream<Uint8Array> | ValidationError {
const willowQueryParams = queryToWillowQueryParams(query);

if (isErr(willowQueryParams)) {
return willowQueryParams;
}

return Willow.createDrop({
areaOfInterest: willowQueryParams.areaOfInterest,
schemes: {
namespace: namespaceScheme,
subspace: subspaceScheme,
path: pathScheme,
payload: this.payloadScheme,
},
store: this.willow,
encodeAuthorisationToken: this.authorizationScheme.tokenEncoding.encode,
encryptTransform,
});
}

async ingestDrop(
drop: ReadableStream<Uint8Array>,
decryptTransform: TransformStream<Uint8Array> = new TransformStream()
) {
await Willow.ingestDrop({
decodeStreamAuthorisationToken:
this.authorizationScheme.tokenEncoding.decodeStream,
decryptTransform,
dropStream: drop,
// deno-lint-ignore require-await
getStore: async (namespace) => {
if (namespaceScheme.isEqual(namespace, this.willow.namespace)) {
return this.willow;
} else {
throw new EarthstarError("Cannot ingest drop: drop is for different namespace")
}
},
schemes: {
namespace: namespaceScheme,
subspace: subspaceScheme,
path: pathScheme,
payload: this.payloadScheme,
},
});
}

/** Create (or update) a document for a given identity and path.
*
* ```ts
Expand Down