Compare commits

...

2 Commits

Author SHA1 Message Date
Anselm
ad40b883eb Pre-release 2024-09-02 17:29:47 +01:00
Anselm
1c64ae1bba First sketch of creating and finding unique CoMaps 2024-09-02 17:28:03 +01:00
44 changed files with 287 additions and 66 deletions

View File

@@ -0,0 +1,6 @@
---
"jazz-tools": patch
"cojson": patch
---
First sketch of API for creating and finding unique CoValues

View File

@@ -1,27 +1,28 @@
{
"mode": "pre",
"tag": "new-auth",
"tag": "unique",
"initialVersions": {
"jazz-example-chat": "0.0.81",
"jazz-example-chat-clerk": "0.0.79",
"jazz-example-chat": "0.0.82-new-auth.1",
"jazz-example-chat-clerk": "0.0.80-new-auth.1",
"jazz-inspector": "0.0.59",
"jazz-example-pets": "0.0.99",
"jazz-example-todo": "0.0.98",
"jazz-example-pets": "0.0.100-new-auth.1",
"jazz-example-todo": "0.0.99-new-auth.1",
"cojson": "0.7.34",
"cojson-storage-indexeddb": "0.7.34",
"cojson-storage-sqlite": "0.7.34",
"cojson-transport-ws": "0.7.34",
"hash-slash": "0.2.0",
"jazz-browser": "0.7.34",
"jazz-browser-auth-clerk": "0.7.32",
"jazz-browser-media-images": "0.7.34",
"jazz-nodejs": "0.7.34",
"jazz-react": "0.7.34",
"jazz-react-auth-clerk": "0.7.32",
"jazz-run": "0.7.34",
"jazz-tools": "0.7.34"
"jazz-browser": "0.7.35-new-auth.0",
"jazz-browser-auth-clerk": "0.7.33-new-auth.0",
"jazz-browser-media-images": "0.7.35-new-auth.0",
"jazz-nodejs": "0.7.35-new-auth.0",
"jazz-react": "0.7.35-new-auth.1",
"jazz-react-auth-clerk": "0.7.33-new-auth.1",
"jazz-run": "0.7.35-new-auth.0",
"jazz-tools": "0.7.35-new-auth.0"
},
"changesets": [
"dirty-plants-sniff",
"small-students-buy",
"smart-mice-camp",
"twelve-lobsters-pull"

View File

@@ -1,5 +1,15 @@
# jazz-example-chat
## 0.0.80-unique.2
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- cojson@0.7.35-unique.2
- jazz-react@0.7.35-unique.2
- jazz-react-auth-clerk@0.7.33-unique.2
## 0.0.80-new-auth.1
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat-clerk",
"private": true,
"version": "0.0.80-new-auth.1",
"version": "0.0.80-unique.2",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,14 @@
# jazz-example-chat
## 0.0.82-unique.2
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- cojson@0.7.35-unique.2
- jazz-react@0.7.35-unique.2
## 0.0.82-new-auth.1
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.82-new-auth.1",
"version": "0.0.82-unique.2",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,13 @@
# jazz-example-chat
## 0.0.60-unique.0
### Patch Changes
- Updated dependencies
- cojson@0.7.35-unique.2
- cojson-transport-ws@0.7.35-unique.2
## 0.0.59
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector",
"private": true,
"version": "0.0.59",
"version": "0.0.60-unique.0",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,14 @@
# jazz-example-pets
## 0.0.100-unique.2
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- jazz-browser-media-images@0.7.35-unique.2
- jazz-react@0.7.35-unique.2
## 0.0.100-new-auth.1
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-pets",
"private": true,
"version": "0.0.100-new-auth.1",
"version": "0.0.100-unique.2",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,13 @@
# jazz-example-todo
## 0.0.99-unique.2
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- jazz-react@0.7.35-unique.2
## 0.0.99-new-auth.1
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.99-new-auth.1",
"version": "0.0.99-unique.2",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# cojson-storage-indexeddb
## 0.7.35-unique.2
### Patch Changes
- Updated dependencies
- cojson@0.7.35-unique.2
## 0.7.34
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "cojson-storage-indexeddb",
"version": "0.7.34",
"version": "0.7.35-unique.2",
"main": "dist/index.js",
"type": "module",
"types": "src/index.ts",

View File

@@ -1,5 +1,12 @@
# cojson-storage-sqlite
## 0.7.35-unique.2
### Patch Changes
- Updated dependencies
- cojson@0.7.35-unique.2
## 0.7.34
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "cojson-storage-sqlite",
"type": "module",
"version": "0.7.34",
"version": "0.7.35-unique.2",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",

View File

@@ -1,5 +1,12 @@
# cojson-transport-nodejs-ws
## 0.7.35-unique.2
### Patch Changes
- Updated dependencies
- cojson@0.7.35-unique.2
## 0.7.34
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "cojson-transport-ws",
"type": "module",
"version": "0.7.34",
"version": "0.7.35-unique.2",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",

View File

@@ -1,5 +1,11 @@
# cojson
## 0.7.35-unique.2
### Patch Changes
- First sketch of API for creating and finding unique CoValues
## 0.7.34
### Patch Changes

View File

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

View File

@@ -41,9 +41,9 @@ export type CoValueHeader = {
type: AnyRawCoValue["type"];
ruleset: RulesetDef;
meta: JsonObject | null;
createdAt: `2${string}` | null;
uniqueness: `z${string}` | null;
};
} & CoValueUniqueness;
export type CoValueUniqueness = {uniqueness: JsonValue, createdAt?: `2${string}` | null}
export function idforHeader(
header: CoValueHeader,

View File

@@ -1,4 +1,4 @@
import { CoValueCore, CoValueHeader } from "../coValueCore.js";
import { CoValueCore, CoValueHeader, CoValueUniqueness } from "../coValueCore.js";
import { CoID, RawCoValue } from "../coValue.js";
import {
AgentSecret,
@@ -92,8 +92,8 @@ export class RawControlledAccount<Meta extends AccountMeta = AccountMeta>
* Creates a new group (with the current account as the group's first admin).
* @category 1. High-level
*/
createGroup() {
return this.core.node.createGroup();
createGroup(uniqueness: CoValueUniqueness = this.core.crypto.createdNowUnique()) {
return this.core.node.createGroup(uniqueness);
}
async acceptInvite<T extends RawCoValue>(

View File

@@ -8,6 +8,7 @@ import { AgentID, isAgentID } from "../ids.js";
import { RawAccount, RawAccountID, ControlledAccountOrAgent } from "./account.js";
import { Role } from "../permissions.js";
import { base58 } from "@scure/base";
import { CoValueUniqueness } from "../coValueCore.js";
export const EVERYONE = "everyone" as const;
export type Everyone = "everyone";
@@ -255,6 +256,7 @@ export class RawGroup<
init?: M["_shape"],
meta?: M["headerMeta"],
initPrivacy: "trusting" | "private" = "private",
uniqueness: CoValueUniqueness = this.core.crypto.createdNowUnique()
): M {
const map = this.core.node
.createCoValue({
@@ -264,7 +266,7 @@ export class RawGroup<
group: this.id,
},
meta: meta || null,
...this.core.crypto.createdNowUnique(),
...uniqueness
})
.getCurrentContent() as M;
@@ -287,6 +289,7 @@ export class RawGroup<
init?: L["_item"][],
meta?: L["headerMeta"],
initPrivacy: "trusting" | "private" = "private",
uniqueness: CoValueUniqueness = this.core.crypto.createdNowUnique()
): L {
const list = this.core.node
.createCoValue({
@@ -296,7 +299,7 @@ export class RawGroup<
group: this.id,
},
meta: meta || null,
...this.core.crypto.createdNowUnique(),
...uniqueness
})
.getCurrentContent() as L;
@@ -310,7 +313,7 @@ export class RawGroup<
}
/** @category 3. Value creation */
createStream<C extends RawCoStream>(meta?: C["headerMeta"]): C {
createStream<C extends RawCoStream>(meta?: C["headerMeta"], uniqueness: CoValueUniqueness = this.core.crypto.createdNowUnique()): C {
return this.core.node
.createCoValue({
type: "costream",
@@ -319,7 +322,7 @@ export class RawGroup<
group: this.id,
},
meta: meta || null,
...this.core.crypto.createdNowUnique(),
...uniqueness
})
.getCurrentContent() as C;
}
@@ -327,6 +330,7 @@ export class RawGroup<
/** @category 3. Value creation */
createBinaryStream<C extends RawBinaryCoStream>(
meta: C["headerMeta"] = { type: "binary" },
uniqueness: CoValueUniqueness = this.core.crypto.createdNowUnique()
): C {
return this.core.node
.createCoValue({
@@ -336,7 +340,7 @@ export class RawGroup<
group: this.id,
},
meta: meta,
...this.core.crypto.createdNowUnique(),
...uniqueness
})
.getCurrentContent() as C;
}

View File

@@ -1,5 +1,6 @@
import {
CoValueCore,
type CoValueUniqueness,
newRandomSessionID,
MAX_RECOMMENDED_TX_SIZE,
idforHeader,
@@ -130,6 +131,7 @@ export type {
OutgoingSyncQueue,
DisconnectedError,
PingTimeoutError,
CoValueUniqueness
};
// eslint-disable-next-line @typescript-eslint/no-namespace

View File

@@ -2,6 +2,7 @@ import { AgentSecret, CryptoProvider } from "./crypto/crypto.js";
import {
CoValueCore,
CoValueHeader,
CoValueUniqueness,
newRandomSessionID,
} from "./coValueCore.js";
import {
@@ -606,12 +607,12 @@ export class LocalNode {
/**
* @deprecated use Account.createGroup() instead
*/
createGroup(): RawGroup {
createGroup(uniqueness: CoValueUniqueness = this.crypto.createdNowUnique()): RawGroup {
const groupCoValue = this.createCoValue({
type: "comap",
ruleset: { type: "group", initialAdmin: this.account.id },
meta: null,
...this.crypto.createdNowUnique(),
...uniqueness
});
const group = expectGroup(groupCoValue.getCurrentContent());

View File

@@ -1,5 +1,14 @@
# jazz-browser-media-images
## 0.7.33-unique.1
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- cojson@0.7.35-unique.2
- jazz-browser@0.7.35-unique.2
## 0.7.33-new-auth.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser-auth-clerk",
"version": "0.7.33-new-auth.0",
"version": "0.7.33-unique.1",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,13 @@
# jazz-browser-media-images
## 0.7.35-unique.2
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- jazz-browser@0.7.35-unique.2
## 0.7.35-new-auth.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser-media-images",
"version": "0.7.35-new-auth.0",
"version": "0.7.35-unique.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,15 @@
# jazz-browser
## 0.7.35-unique.2
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- cojson@0.7.35-unique.2
- cojson-storage-indexeddb@0.7.35-unique.2
- cojson-transport-ws@0.7.35-unique.2
## 0.7.35-new-auth.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser",
"version": "0.7.35-new-auth.0",
"version": "0.7.35-unique.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,14 @@
# jazz-autosub
## 0.7.35-unique.2
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- cojson@0.7.35-unique.2
- cojson-transport-ws@0.7.35-unique.2
## 0.7.35-new-auth.0
### Patch Changes

View File

@@ -5,7 +5,7 @@
"types": "src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.7.35-new-auth.0",
"version": "0.7.35-unique.2",
"dependencies": {
"cojson": "workspace:*",
"cojson-transport-ws": "workspace:*",

View File

@@ -1,5 +1,15 @@
# jazz-browser-media-images
## 0.7.33-unique.2
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- cojson@0.7.35-unique.2
- jazz-browser-auth-clerk@0.7.33-unique.1
- jazz-react@0.7.35-unique.2
## 0.7.33-new-auth.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-react-auth-clerk",
"version": "0.7.33-new-auth.1",
"version": "0.7.33-unique.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.tsx",

View File

@@ -1,5 +1,14 @@
# jazz-react
## 0.7.35-unique.2
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- cojson@0.7.35-unique.2
- jazz-browser@0.7.35-unique.2
## 0.7.35-new-auth.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-react",
"version": "0.7.35-new-auth.1",
"version": "0.7.35-unique.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,14 @@
# jazz-autosub
## 0.7.35-unique.2
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- cojson@0.7.35-unique.2
- cojson-transport-ws@0.7.35-unique.2
## 0.7.35-new-auth.0
### Patch Changes

View File

@@ -3,7 +3,7 @@
"bin": "./dist/index.js",
"type": "module",
"license": "MIT",
"version": "0.7.35-new-auth.0",
"version": "0.7.35-unique.2",
"scripts": {
"lint": "eslint . --ext ts,tsx",
"format": "prettier --write './src/**/*.{ts,tsx}'",

View File

@@ -1,5 +1,13 @@
# jazz-autosub
## 0.7.35-unique.2
### Patch Changes
- First sketch of API for creating and finding unique CoValues
- Updated dependencies
- cojson@0.7.35-unique.2
## 0.7.35-new-auth.0
### Patch Changes

View File

@@ -5,7 +5,7 @@
"types": "./src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.7.35-new-auth.0",
"version": "0.7.35-unique.2",
"dependencies": {
"cojson": "workspace:*",
"fast-check": "^3.17.2"

View File

@@ -1,4 +1,9 @@
import type { JsonValue, RawCoMap } from "cojson";
import {
cojsonInternals,
type CoValueUniqueness,
type JsonValue,
type RawCoMap,
} from "cojson";
import type {
CoValue,
Schema,
@@ -35,8 +40,10 @@ type CoMapEdit<V> = {
};
export type Simplify<A> = {
[K in keyof A]: A[K]
} extends infer B ? B : never
[K in keyof A]: A[K];
} extends infer B
? B
: never;
/**
* CoMaps are collaborative versions of plain objects, mapping string-like keys to values.
@@ -237,10 +244,19 @@ export class CoMap extends CoValueBase implements CoValue {
static create<M extends CoMap>(
this: CoValueClass<M>,
init: Simplify<CoMapInit<M>>,
options: { owner: Account | Group },
options: {
owner: Account | Group;
unique?: CoValueUniqueness["uniqueness"];
},
) {
const instance = new this();
const raw = instance.rawFromInit(init, options.owner);
const raw = instance.rawFromInit(
init,
options.owner,
options.unique === undefined
? undefined
: { uniqueness: options.unique },
);
Object.defineProperties(instance, {
id: {
value: raw.id,
@@ -293,6 +309,7 @@ export class CoMap extends CoValueBase implements CoValue {
rawFromInit<Fields extends object = Record<string, any>>(
init: Simplify<CoMapInit<Fields>> | undefined,
owner: Account | Group,
uniqueness?: CoValueUniqueness,
) {
const rawOwner = owner._raw;
@@ -326,7 +343,7 @@ export class CoMap extends CoValueBase implements CoValue {
}
}
return rawOwner.createMap(rawInit);
return rawOwner.createMap(rawInit, null, "private", uniqueness);
}
/**
@@ -426,6 +443,27 @@ export class CoMap extends CoValueBase implements CoValue {
return subscribeToCoValue<M, Depth>(this, id, as, depth, listener);
}
static findUnique<M extends CoMap>(
this: CoValueClass<M>,
unique: CoValueUniqueness['uniqueness'],
ownerID: ID<Account> | ID<Group>,
as: Account | Group,
) {
const header = {
type: "comap" as const,
ruleset: {
type: "ownedByGroup" as const,
group: ownerID,
},
meta: null,
uniqueness: unique,
};
return cojsonInternals.idforHeader(
header,
as._raw.core.crypto,
) as ID<M>;
}
/**
* Given an already loaded `CoMap`, ensure that the specified fields are loaded to the specified depth.
*

View File

@@ -11,6 +11,7 @@ export type {
AgentID,
SyncMessage,
CryptoProvider,
CoValueUniqueness,
} from "cojson";
export type { ID, CoValue } from "./internal.js";

View File

@@ -11,32 +11,32 @@ import {
createJazzContext,
fixedCredentialsAuth,
} from "../index.js";
import { randomSessionProvider } from "../internal.js";
import { Group, randomSessionProvider } from "../internal.js";
const Crypto = await WasmCrypto.create();
class TestMap extends CoMap {
color = co.string;
_height = co.number;
birthday = co.encoded(Encoders.Date);
name? = co.string;
nullable = co.optional.encoded<string | undefined>({
encode: (value: string | undefined) => value || null,
decode: (value: unknown) => (value as string) || undefined,
});
optionalDate = co.optional.encoded(Encoders.Date);
get roughColor() {
return this.color + "ish";
}
}
describe("Simple CoMap operations", async () => {
const me = await Account.create({
creationProps: { name: "Hermes Puggington" },
crypto: Crypto,
});
class TestMap extends CoMap {
color = co.string;
_height = co.number;
birthday = co.encoded(Encoders.Date);
name? = co.string;
nullable = co.optional.encoded<string | undefined>({
encode: (value: string | undefined) => value || null,
decode: (value: unknown) => (value as string) || undefined,
});
optionalDate = co.optional.encoded(Encoders.Date);
get roughColor() {
return this.color + "ish";
}
}
console.log("TestMap schema", TestMap.prototype._schema);
const birthday = new Date();
@@ -738,3 +738,28 @@ describe("CoMap applyDiff", async () => {
expect((map as any).invalidField).toBeUndefined();
});
});
describe("Creating and finding unique CoMaps", async () => {
test("Creating and finding unique CoMaps", async () => {
const me = await Account.create({
creationProps: { name: "Tester McTesterson" },
crypto: Crypto,
});
const group = await Group.create({
owner: me,
});
const alice = TestMap.create({
name: "Alice",
_height: 100,
birthday: new Date("1990-01-01"),
color: "red",
}, { owner: group, unique: { name: "Alice" } });
const foundAlice = TestMap.findUnique({ name: "Alice" }, group.id, me);
expect(foundAlice).toEqual(alice.id);
});
});