Compare commits
20 Commits
cojson@0.5
...
cojson@0.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
934fe4d29b | ||
|
|
408012f2e5 | ||
|
|
d0078b830e | ||
|
|
e52948b2b7 | ||
|
|
53bb1b230b | ||
|
|
54e83aeaaa | ||
|
|
aa3129cab5 | ||
|
|
90520dddd7 | ||
|
|
03eb77070a | ||
|
|
4ba5c255b6 | ||
|
|
01817db873 | ||
|
|
46fcbd6c01 | ||
|
|
aa3e3de09e | ||
|
|
af3d48764d | ||
|
|
091f36b736 | ||
|
|
7107f79f42 | ||
|
|
9922db2336 | ||
|
|
75db570198 | ||
|
|
28a09f377b | ||
|
|
fd2e0855bb |
8
.github/workflows/build-and-deploy.yaml
vendored
8
.github/workflows/build-and-deploy.yaml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
# example: ["chat", "todo", "pets", "twit", "file-drop"]
|
||||
example: ["twit"]
|
||||
example: ["twit", "chat"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
# example: ["chat", "todo", "pets", "twit", "file-drop"]
|
||||
example: ["twit"]
|
||||
example: ["twit", "chat"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -115,7 +115,7 @@ jobs:
|
||||
|
||||
envsubst '${DOCKER_USER} ${DOCKER_PASSWORD} ${DOCKER_TAG} ${BRANCH_SUFFIX} ${BRANCH_SUBDOMAIN}' < job-template.nomad > job-instance.nomad;
|
||||
cat job-instance.nomad;
|
||||
NOMAD_ADDR='http://control1v2-london:4646' nomad job run job-instance.nomad;
|
||||
NOMAD_ADDR=${{ secrets.NOMAD_ADDR }} nomad job run job-instance.nomad;
|
||||
working-directory: ./examples/${{ matrix.example }}
|
||||
|
||||
# deploy-homepage:
|
||||
@@ -148,5 +148,5 @@ jobs:
|
||||
|
||||
# envsubst '${DOCKER_USER} ${DOCKER_PASSWORD} ${DOCKER_TAG} ${BRANCH_SUFFIX} ${BRANCH_SUBDOMAIN}' < job-template.nomad > job-instance.nomad;
|
||||
# cat job-instance.nomad;
|
||||
# NOMAD_ADDR='http://control1v2-london:4646' nomad job run job-instance.nomad;
|
||||
# NOMAD_ADDR=${{ secrets.NOMAD_ADDR }} nomad job run job-instance.nomad;
|
||||
# working-directory: ./homepage/homepage-jazz
|
||||
62
DOCS.md
62
DOCS.md
@@ -1,5 +1,11 @@
|
||||
# Overview
|
||||
|
||||
---
|
||||
|
||||
## These are work-in-progress API docs. <br/> To start learning Jazz, see [Getting Started](./README.md#getting-started)
|
||||
|
||||
---
|
||||
|
||||
## Core packages
|
||||
|
||||
### `jazz-react` → [API](#jazz-react)
|
||||
@@ -15999,4 +16005,58 @@ export type Resolved<T extends CoValue> = T extends CoMap
|
||||
} ? never : ResolvedCoStream<T>
|
||||
: ResolvedAccount | ResolvedGroup | ResolvedCoMap<CoMap> | ResolvedCoList<CoList> | ResolvedCoStream<CoStream>
|
||||
```
|
||||
TODO: doc generator not implemented yet 2097152
|
||||
TODO: doc generator not implemented yet 2097152
|
||||
|
||||
|
||||
# jazz-nodejs
|
||||
|
||||
## `createOrResumeWorker({workerName, syncServer?, migration?})`
|
||||
|
||||
<sup>(function in `jazz-nodejs`)</sup>
|
||||
|
||||
```typescript
|
||||
export function createOrResumeWorker<P extends Profile<ProfileShape, ProfileMeta>, R extends CoMap<{
|
||||
[key: string]: JsonValue | undefined }, null | JsonObject>>({
|
||||
workerName: string,
|
||||
syncServer?: string,
|
||||
migration?: AccountMigration<P, R>,
|
||||
}): Promise<{
|
||||
localNode: LocalNode,
|
||||
worker: ControlledAccount<P, R, AccountMeta>,
|
||||
}>
|
||||
```
|
||||
TODO: document
|
||||
|
||||
### Parameters:
|
||||
|
||||
| name | description |
|
||||
| ----: | ---- |
|
||||
| `__namedParameters.workerName` | TODO: document |
|
||||
| `__namedParameters.syncServer?` | TODO: document |
|
||||
| `__namedParameters.migration?` | TODO: document |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
----
|
||||
|
||||
## `autoSub(id, node, callback)`
|
||||
|
||||
<sup>(function in `jazz-nodejs`)</sup>
|
||||
|
||||
```typescript
|
||||
export function autoSub<C extends CoValue>(id: undefined | CoID<C>, node: LocalNode, callback: (resolved: undefined | Resolved<C>) => void): () => void
|
||||
```
|
||||
TODO: document
|
||||
|
||||
### Parameters:
|
||||
|
||||
| name | description |
|
||||
| ----: | ---- |
|
||||
| `id` | TODO: document |
|
||||
| `node` | TODO: document |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -24,10 +24,15 @@ export type TodoProject = CoMap<{
|
||||
|
||||
export type ListOfProjects = CoList<TodoProject["id"]>;
|
||||
|
||||
/** The account root is an app-specific per-user private `CoMap`
|
||||
* where you can store top-level objects for that user */
|
||||
export type TodoAccountRoot = CoMap<{
|
||||
projects: ListOfProjects["id"];
|
||||
}>;
|
||||
|
||||
/** The account migration is run on account creation and on every log-in.
|
||||
* You can use it to set up the account root and any other initial CoValues you need.
|
||||
*/
|
||||
export const migration: AccountMigration<Profile, TodoAccountRoot> = (account) => {
|
||||
if (!account.get("root")) {
|
||||
account.set(
|
||||
|
||||
@@ -25,9 +25,11 @@ import { AccountMigration, Profile } from "cojson";
|
||||
* Walkthrough: The top-level provider `<WithJazz/>`
|
||||
*
|
||||
* This shows how to use the top-level provider `<WithJazz/>`,
|
||||
* which provides the rest of the app with a `LocalNode` (used through `useJazz` later),
|
||||
* based on `LocalAuth` that uses Passkeys (aka WebAuthn) to store a user's account secret
|
||||
* which provides the rest of the app with a controlled account (used through `useJazz` later).
|
||||
* Here we use `LocalAuth`, which uses Passkeys (aka WebAuthn) to store a user's account secret
|
||||
* - no backend needed.
|
||||
*
|
||||
* `<WithJazz/>` also runs our account migration
|
||||
*/
|
||||
|
||||
const appName = "Jazz Todo List Example";
|
||||
|
||||
3
examples/twit-stresstest/.gitignore
vendored
3
examples/twit-stresstest/.gitignore
vendored
@@ -22,3 +22,6 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
.env
|
||||
TwitAllTwitsCreatorCredentials.json
|
||||
@@ -1,5 +1,24 @@
|
||||
# twit-stresstest
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Make addMember and removeMember take loaded Accounts instead of just IDs
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-nodejs@0.6.0
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Allow account migrations to be async
|
||||
- Updated dependencies
|
||||
- jazz-nodejs@0.5.3
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -9,31 +9,12 @@ import {
|
||||
TwitProfile,
|
||||
migration,
|
||||
} from "../twit/src/1_dataModel.js";
|
||||
import {
|
||||
websocketReadableStream,
|
||||
websocketWritableStream,
|
||||
} from "cojson-transport-nodejs-ws";
|
||||
import { WebSocket } from "ws";
|
||||
import { autoSub } from "jazz-autosub";
|
||||
|
||||
import { webcrypto } from 'node:crypto'
|
||||
(globalThis as any).crypto = webcrypto
|
||||
import { createOrResumeWorker, autoSub } from "jazz-nodejs";
|
||||
|
||||
async function runner() {
|
||||
await cojsonReady;
|
||||
|
||||
const { node } = await LocalNode.withNewlyCreatedAccount({
|
||||
name: "Bot_" + Math.random().toString(36).slice(2),
|
||||
migration,
|
||||
});
|
||||
|
||||
const ws = new WebSocket("wss://sync.jazz.tools");
|
||||
|
||||
node.syncManager.addPeer({
|
||||
id: "globalMesh",
|
||||
role: "server",
|
||||
incoming: websocketReadableStream(ws),
|
||||
outgoing: websocketWritableStream(ws),
|
||||
const { localNode: node, worker } = await createOrResumeWorker({
|
||||
workerName: "TwitStressTestBot" + Math.random().toString(36).slice(2),
|
||||
});
|
||||
|
||||
console.log(
|
||||
@@ -64,8 +45,8 @@ async function runner() {
|
||||
if (startedPosting) return;
|
||||
startedPosting = true;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, Math.random() * 120000)
|
||||
await new Promise(
|
||||
(resolve) => setTimeout(resolve, Math.random() * 120000)
|
||||
// setTimeout(resolve, Math.random() * 5000)
|
||||
);
|
||||
const audience = me.root.peopleWhoCanSeeMyContent;
|
||||
@@ -89,7 +70,7 @@ async function runner() {
|
||||
|
||||
let blackHole = 0;
|
||||
|
||||
let lastUpdate = Date.now()
|
||||
let lastUpdate = Date.now();
|
||||
|
||||
autoSub(ALL_TWEETS_LIST_ID, node, (allTwits) => {
|
||||
if (Date.now() - lastUpdate < 33) return;
|
||||
|
||||
@@ -3,30 +3,16 @@ import {
|
||||
ListOfTwits,
|
||||
migration,
|
||||
} from "../twit/src/1_dataModel";
|
||||
import {
|
||||
websocketReadableStream,
|
||||
websocketWritableStream,
|
||||
} from "cojson-transport-nodejs-ws";
|
||||
import { WebSocket } from "ws";
|
||||
import { createOrResumeWorker, autoSub } from "jazz-nodejs"
|
||||
|
||||
await cojsonReady;
|
||||
|
||||
const { node } = await LocalNode.withNewlyCreatedAccount({
|
||||
name: "Bot_" + Math.random().toString(36).slice(2),
|
||||
migration,
|
||||
const { localNode: node, worker } = await createOrResumeWorker({
|
||||
workerName: "TwitAllTwitsCreator",
|
||||
migration
|
||||
});
|
||||
|
||||
const ws = new WebSocket("wss://sync.jazz.tools");
|
||||
|
||||
const allTweetsGroup = (node.account as ControlledAccount).createGroup();
|
||||
const allTweetsGroup = worker.createGroup();
|
||||
allTweetsGroup.addMember('everyone', 'writer');
|
||||
|
||||
const allTweets = allTweetsGroup.createList<ListOfTwits>();
|
||||
console.log("allTweets", allTweets.id);
|
||||
|
||||
node.syncManager.addPeer({
|
||||
id: "globalMesh",
|
||||
role: "server",
|
||||
incoming: websocketReadableStream(ws),
|
||||
outgoing: websocketWritableStream(ws),
|
||||
});
|
||||
console.log("allTweets", allTweets.id);
|
||||
@@ -1,13 +1,12 @@
|
||||
{
|
||||
"name": "twit-stresstest",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"main": "dist/twit-stresstest/index.js",
|
||||
"type":"module",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"cojson": "^0.5.0",
|
||||
"cojson-transport-nodejs-ws": "^0.5.0"
|
||||
"jazz-nodejs": "^0.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rm -rf ./dist && tsc --sourceMap --outDir dist",
|
||||
|
||||
@@ -33,7 +33,7 @@ export type TwitAccountRoot = CoMap<{
|
||||
peopleWhoCanInteractWithMe: Group['id'];
|
||||
}>;
|
||||
|
||||
export const ALL_TWEETS_LIST_ID = "co_zWjKkgPhrrrywAtEXSxiEPevmEW" as ListOfTwits['id'];
|
||||
export const ALL_TWEETS_LIST_ID = "co_zQEhxDTvZt3f4vWKqVNj9TCTRs4" as ListOfTwits['id'];
|
||||
|
||||
export const migration: AccountMigration<TwitProfile, TwitAccountRoot> = (account, profile) => {
|
||||
if (!account.get('root')) {
|
||||
|
||||
@@ -3,11 +3,9 @@ import { RouterProvider, createHashRouter } from 'react-router-dom';
|
||||
import './index.css';
|
||||
|
||||
import { AccountMigration } from 'cojson';
|
||||
import { WithJazz, useJazz } from 'jazz-react';
|
||||
import { LocalAuth } from 'jazz-react-auth-local';
|
||||
import { DemoAuth, WithJazz, useJazz } from 'jazz-react';
|
||||
|
||||
import { Button, ThemeProvider, TitleAndLogo } from './basicComponents/index.tsx';
|
||||
import { PrettyAuthUI } from './components/Auth.tsx';
|
||||
|
||||
import { migration } from './1_dataModel.ts';
|
||||
import { AllTwitsFeed, FollowingFeed } from './3_ChronoFeed.tsx';
|
||||
@@ -15,21 +13,20 @@ import { ProfilePage } from './5_ProfilePage.tsx';
|
||||
|
||||
const appName = 'Jazz Twit Example';
|
||||
|
||||
const auth = LocalAuth({
|
||||
appName,
|
||||
Component: PrettyAuthUI
|
||||
const auth = DemoAuth({
|
||||
appName
|
||||
});
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
// <React.StrictMode>
|
||||
<WithJazz auth={auth} migration={migration as AccountMigration}>
|
||||
<ThemeProvider>
|
||||
<TitleAndLogo name={appName} />
|
||||
<div className="flex flex-col h-full items-stretch justify-start gap-10 pt-10 pb-10 px-5 w-full max-w-xl mx-auto">
|
||||
<WithJazz auth={auth} migration={migration as AccountMigration}>
|
||||
<App />
|
||||
</WithJazz>
|
||||
<App />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</WithJazz>
|
||||
// </React.StrictMode>
|
||||
);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ export function ProfilePage() {
|
||||
? null
|
||||
: twit?.isReplyTo
|
||||
: twit
|
||||
);
|
||||
) || [];
|
||||
}, [profile?.twits]);
|
||||
|
||||
const [qr, setQr] = useState<string>('');
|
||||
|
||||
@@ -226,7 +226,7 @@ export function QuoteContainer(props: { children: React.ReactNode }) {
|
||||
}
|
||||
|
||||
export function MainH1(props: { children: React.ReactNode }) {
|
||||
return <h1 className="text-2xl mb-4 sticky top-0 p-4 -mx-4 bg-white dark:bg-black z-20">{props.children}</h1>;
|
||||
return <h1 className="text-2xl mb-4 sticky top-0 p-4 -mx-4 bg-background z-20">{props.children}</h1>;
|
||||
}
|
||||
|
||||
export function SmallInlineButton(props: { children: React.ReactNode } & ButtonProps) {
|
||||
|
||||
@@ -9,6 +9,7 @@ export async function genDocsMd() {
|
||||
"jazz-browser": "index.ts",
|
||||
"jazz-browser-media-images": "index.ts",
|
||||
"jazz-autosub": "index.ts",
|
||||
"jazz-nodejs": "index.ts",
|
||||
}).map(async ([packageName, entryPoint]) => {
|
||||
const app = await Application.bootstrapWithPlugins({
|
||||
entryPoints: [`packages/${packageName}/src/${entryPoint}`],
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# cojson-simple-sync
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Make addMember and removeMember take loaded Accounts instead of just IDs
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.6.0
|
||||
- cojson-storage-sqlite@0.5.2
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"types": "src/index.ts",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.3",
|
||||
"@types/ws": "^8.5.5",
|
||||
@@ -16,8 +16,8 @@
|
||||
"typescript": "5.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"cojson": "^0.5.0",
|
||||
"cojson-storage-sqlite": "^0.5.0",
|
||||
"cojson": "^0.6.0",
|
||||
"cojson-storage-sqlite": "^0.5.2",
|
||||
"ws": "^8.13.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AnonymousControlledAccount, LocalNode, cojsonInternals, cojsonReady } from "cojson";
|
||||
import { ControlledAgent, LocalNode, cojsonInternals, cojsonReady } from "cojson";
|
||||
import { WebSocketServer } from "ws";
|
||||
import { SQLiteStorage } from "cojson-storage-sqlite";
|
||||
import { websocketReadableStream, websocketWritableStream } from "./websocketStreams.js";
|
||||
@@ -15,7 +15,7 @@ const agentSecret = cojsonInternals.newRandomAgentSecret();
|
||||
const agentID = cojsonInternals.getAgentID(agentSecret);
|
||||
|
||||
const localNode = new LocalNode(
|
||||
new AnonymousControlledAccount(agentSecret),
|
||||
new ControlledAgent(agentSecret),
|
||||
cojsonInternals.newRandomSessionID(agentID)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# cojson-storage-indexeddb
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Make addMember and removeMember take loaded Accounts instead of just IDs
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.6.0
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "cojson-storage-indexeddb",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cojson": "^0.5.0",
|
||||
"cojson": "^0.6.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { expect, test } from "vitest";
|
||||
import { AnonymousControlledAccount, LocalNode, cojsonInternals } from "cojson";
|
||||
import { ControlledAgent, LocalNode, cojsonInternals } from "cojson";
|
||||
import { IDBStorage } from ".";
|
||||
|
||||
test.skip("Should be able to initialize and load from empty DB", async () => {
|
||||
const agentSecret = cojsonInternals.newRandomAgentSecret();
|
||||
|
||||
const node = new LocalNode(
|
||||
new AnonymousControlledAccount(agentSecret),
|
||||
new ControlledAgent(agentSecret),
|
||||
cojsonInternals.newRandomSessionID(
|
||||
cojsonInternals.getAgentID(agentSecret)
|
||||
)
|
||||
@@ -27,7 +27,7 @@ test("Should be able to sync data to database and then load that from a new node
|
||||
const agentSecret = cojsonInternals.newRandomAgentSecret();
|
||||
|
||||
const node1 = new LocalNode(
|
||||
new AnonymousControlledAccount(agentSecret),
|
||||
new ControlledAgent(agentSecret),
|
||||
cojsonInternals.newRandomSessionID(
|
||||
cojsonInternals.getAgentID(agentSecret)
|
||||
)
|
||||
@@ -50,7 +50,7 @@ test("Should be able to sync data to database and then load that from a new node
|
||||
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||
|
||||
const node2 = new LocalNode(
|
||||
new AnonymousControlledAccount(agentSecret),
|
||||
new ControlledAgent(agentSecret),
|
||||
cojsonInternals.newRandomSessionID(
|
||||
cojsonInternals.getAgentID(agentSecret)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# cojson-storage-sqlite
|
||||
|
||||
## 0.5.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.6.0
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "cojson-storage-sqlite",
|
||||
"type": "module",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.2",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"better-sqlite3": "^8.5.2",
|
||||
"cojson": "^0.5.0",
|
||||
"cojson": "^0.6.0",
|
||||
"typescript": "^5.1.6",
|
||||
"@types/better-sqlite3": "^7.6.4"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# cojson-transport-nodejs-ws
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.6.0
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "cojson-transport-nodejs-ws",
|
||||
"type": "module",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cojson": "^0.5.0",
|
||||
"cojson": "^0.6.0",
|
||||
"typescript": "^5.1.6",
|
||||
"ws": "^8.14.2"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# cojson
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Provide localNode to AccountMigrations
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Make addMember and removeMember take loaded Accounts instead of just IDs
|
||||
|
||||
## 0.5.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Allow account migrations to be async
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"types": "src/index.ts",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.5.1",
|
||||
"version": "0.6.1",
|
||||
"devDependencies": {
|
||||
"@noble/curves": "^1.2.0",
|
||||
"@types/jest": "^29.5.3",
|
||||
|
||||
@@ -27,7 +27,7 @@ import { Group } from "./coValues/group.js";
|
||||
import { LocalNode } from "./localNode.js";
|
||||
import { CoValueKnownState, NewContentMessage } from "./sync.js";
|
||||
import { AgentID, RawCoID, SessionID, TransactionID } from "./ids.js";
|
||||
import { AccountID, GeneralizedControlledAccount } from "./coValues/account.js";
|
||||
import { AccountID, ControlledAccountOrAgent } from "./coValues/account.js";
|
||||
import { Stringified, parseJSON, stableStringify } from "./jsonStringify.js";
|
||||
import { coreToCoValue } from "./coreToCoValue.js";
|
||||
import { expectGroup } from "./typeUtils/expectGroup.js";
|
||||
@@ -133,7 +133,7 @@ export class CoValueCore {
|
||||
}
|
||||
|
||||
testWithDifferentAccount(
|
||||
account: GeneralizedControlledAccount,
|
||||
account: ControlledAccountOrAgent,
|
||||
currentSessionID: SessionID
|
||||
): CoValueCore {
|
||||
const newNode = this.node.testWithDifferentAccount(
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import { AgentID } from "../ids.js";
|
||||
import { CoMap } from "./coMap.js";
|
||||
import { Group, InviteSecret } from "./group.js";
|
||||
import { LocalNode } from "../index.js";
|
||||
|
||||
export function accountHeaderForInitialAgentSecret(
|
||||
agentSecret: AgentSecret
|
||||
@@ -36,7 +37,7 @@ export class Account<
|
||||
R extends CoMap = CoMap,
|
||||
Meta extends AccountMeta = AccountMeta
|
||||
> extends Group<P, R, Meta> {
|
||||
getCurrentAgentID(): AgentID {
|
||||
currentAgentID(): AgentID {
|
||||
const agents = this.keys().filter((k): k is AgentID =>
|
||||
k.startsWith("sealer_")
|
||||
);
|
||||
@@ -51,7 +52,7 @@ export class Account<
|
||||
}
|
||||
}
|
||||
|
||||
export interface GeneralizedControlledAccount {
|
||||
export interface ControlledAccountOrAgent {
|
||||
id: AccountID | AgentID;
|
||||
agentSecret: AgentSecret;
|
||||
|
||||
@@ -64,12 +65,12 @@ export interface GeneralizedControlledAccount {
|
||||
|
||||
/** @hidden */
|
||||
export class ControlledAccount<
|
||||
P extends Profile = Profile,
|
||||
R extends CoMap = CoMap,
|
||||
Meta extends AccountMeta = AccountMeta
|
||||
>
|
||||
P extends Profile = Profile,
|
||||
R extends CoMap = CoMap,
|
||||
Meta extends AccountMeta = AccountMeta
|
||||
>
|
||||
extends Account<P, R, Meta>
|
||||
implements GeneralizedControlledAccount
|
||||
implements ControlledAccountOrAgent
|
||||
{
|
||||
agentSecret: AgentSecret;
|
||||
|
||||
@@ -116,8 +117,8 @@ Meta extends AccountMeta = AccountMeta
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
export class AnonymousControlledAccount
|
||||
implements GeneralizedControlledAccount
|
||||
export class ControlledAgent
|
||||
implements ControlledAccountOrAgent
|
||||
{
|
||||
agentSecret: AgentSecret;
|
||||
|
||||
@@ -158,10 +159,17 @@ export type ProfileShape = {
|
||||
};
|
||||
export type ProfileMeta = { type: "profile" };
|
||||
|
||||
export class Profile<Shape extends ProfileShape = ProfileShape, Meta extends ProfileMeta = ProfileMeta> extends CoMap<Shape, Meta> {
|
||||
export class Profile<
|
||||
Shape extends ProfileShape = ProfileShape,
|
||||
Meta extends ProfileMeta = ProfileMeta
|
||||
> extends CoMap<Shape, Meta> {}
|
||||
|
||||
}
|
||||
|
||||
export type AccountMigration< P extends Profile = Profile,
|
||||
R extends CoMap = CoMap,
|
||||
Meta extends AccountMeta = AccountMeta> = (account: ControlledAccount<P, R, Meta>, profile: P) => void;
|
||||
export type AccountMigration<
|
||||
P extends Profile = Profile,
|
||||
R extends CoMap = CoMap,
|
||||
Meta extends AccountMeta = AccountMeta
|
||||
> = (
|
||||
account: ControlledAccount<P, R, Meta>,
|
||||
profile: P,
|
||||
localNode: LocalNode
|
||||
) => void | Promise<void>;
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
getAgentID,
|
||||
} from "../crypto.js";
|
||||
import { AgentID, isAgentID } from "../ids.js";
|
||||
import { AccountID, Profile } from "./account.js";
|
||||
import { Account, AccountID, ControlledAccountOrAgent, Profile } from "./account.js";
|
||||
import { Role } from "../permissions.js";
|
||||
import { base58 } from "@scure/base";
|
||||
|
||||
@@ -94,13 +94,13 @@ export class Group<
|
||||
*
|
||||
* @category 2. Role changing
|
||||
*/
|
||||
addMember(accountID: AccountID | Everyone, role: Role): this {
|
||||
return this.addMemberInternal(accountID, role);
|
||||
addMember(account: Account | ControlledAccountOrAgent | Everyone, role: Role): this {
|
||||
return this.addMemberInternal(account, role);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
addMemberInternal(
|
||||
accountID: AccountID | AgentID | Everyone,
|
||||
account: Account | ControlledAccountOrAgent | AgentID | Everyone,
|
||||
role: Role
|
||||
): this {
|
||||
return this.mutate((mutable) => {
|
||||
@@ -110,15 +110,15 @@ export class Group<
|
||||
throw new Error("Can't add member without read key secret");
|
||||
}
|
||||
|
||||
if (accountID === EVERYONE) {
|
||||
if (account === EVERYONE) {
|
||||
if (!(role === "reader" || role === "writer")) {
|
||||
throw new Error(
|
||||
"Can't make everyone something other than reader or writer"
|
||||
);
|
||||
}
|
||||
mutable.set(accountID, role, "trusting");
|
||||
mutable.set(account, role, "trusting");
|
||||
|
||||
if (mutable.get(accountID) !== role) {
|
||||
if (mutable.get(account) !== role) {
|
||||
throw new Error("Failed to set role");
|
||||
}
|
||||
|
||||
@@ -128,18 +128,16 @@ export class Group<
|
||||
"trusting"
|
||||
);
|
||||
} else {
|
||||
const agent = this.core.node.resolveAccountAgent(
|
||||
accountID,
|
||||
"Expected to know agent to add them to group"
|
||||
);
|
||||
mutable.set(accountID, role, "trusting");
|
||||
const memberKey = typeof account === "string" ? account : account.id;
|
||||
const agent = typeof account === "string" ? account : account.currentAgentID();
|
||||
mutable.set(memberKey, role, "trusting");
|
||||
|
||||
if (mutable.get(accountID) !== role) {
|
||||
if (mutable.get(memberKey) !== role) {
|
||||
throw new Error("Failed to set role");
|
||||
}
|
||||
|
||||
mutable.set(
|
||||
`${currentReadKey.id}_for_${accountID}`,
|
||||
`${currentReadKey.id}_for_${memberKey}`,
|
||||
seal({
|
||||
message: currentReadKey.secret,
|
||||
from: this.core.node.account.currentSealerSecret(),
|
||||
@@ -225,15 +223,14 @@ export class Group<
|
||||
*
|
||||
* @category 2. Role changing
|
||||
*/
|
||||
removeMember(accountID: AccountID): this {
|
||||
return this.removeMemberInternal(accountID);
|
||||
removeMember(account: Account | ControlledAccountOrAgent | Everyone): this {
|
||||
return this.removeMemberInternal(account);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
removeMemberInternal(accountID: AccountID | AgentID): this {
|
||||
const afterRevoke = this.mutate((map) => {
|
||||
map.set(accountID, "revoked", "trusting");
|
||||
});
|
||||
removeMemberInternal(account: Account | ControlledAccountOrAgent | AgentID | Everyone): this {
|
||||
const memberKey = typeof account === "string" ? account : account.id;
|
||||
const afterRevoke = this.set(memberKey, "revoked", "trusting");
|
||||
|
||||
return afterRevoke.rotateReadKey();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
} from "./crypto.js";
|
||||
import { connectedPeers } from "./streamUtils.js";
|
||||
import {
|
||||
AnonymousControlledAccount,
|
||||
ControlledAgent,
|
||||
ControlledAccount,
|
||||
} from "./coValues/account.js";
|
||||
import type { Role } from "./permissions.js";
|
||||
@@ -108,7 +108,7 @@ export {
|
||||
SessionID,
|
||||
Media,
|
||||
CoValueCore,
|
||||
AnonymousControlledAccount,
|
||||
ControlledAgent,
|
||||
ControlledAccount,
|
||||
cryptoReady as cojsonReady,
|
||||
MAX_RECOMMENDED_TX_SIZE,
|
||||
|
||||
@@ -26,9 +26,9 @@ import {
|
||||
Account,
|
||||
AccountMeta,
|
||||
accountHeaderForInitialAgentSecret,
|
||||
GeneralizedControlledAccount,
|
||||
ControlledAccountOrAgent,
|
||||
ControlledAccount,
|
||||
AnonymousControlledAccount,
|
||||
ControlledAgent,
|
||||
AccountID,
|
||||
Profile,
|
||||
AccountMigration,
|
||||
@@ -52,7 +52,7 @@ export class LocalNode {
|
||||
/** @internal */
|
||||
coValues: { [key: RawCoID]: CoValueState } = {};
|
||||
/** @category 3. Low-level */
|
||||
account: GeneralizedControlledAccount;
|
||||
account: ControlledAccountOrAgent;
|
||||
/** @category 3. Low-level */
|
||||
currentSessionID: SessionID;
|
||||
/** @category 3. Low-level */
|
||||
@@ -60,7 +60,7 @@ export class LocalNode {
|
||||
|
||||
/** @category 3. Low-level */
|
||||
constructor(
|
||||
account: GeneralizedControlledAccount,
|
||||
account: ControlledAccountOrAgent,
|
||||
currentSessionID: SessionID
|
||||
) {
|
||||
this.account = account;
|
||||
@@ -68,27 +68,29 @@ export class LocalNode {
|
||||
}
|
||||
|
||||
/** @category 2. Node Creation */
|
||||
static withNewlyCreatedAccount<
|
||||
static async withNewlyCreatedAccount<
|
||||
P extends Profile = Profile,
|
||||
R extends CoMap = CoMap,
|
||||
Meta extends AccountMeta = AccountMeta
|
||||
>({
|
||||
name,
|
||||
peersToLoadFrom,
|
||||
migration,
|
||||
initialAgentSecret = newRandomAgentSecret(),
|
||||
}: {
|
||||
name: string;
|
||||
peersToLoadFrom?: Peer[];
|
||||
migration?: AccountMigration<P, R, Meta>;
|
||||
initialAgentSecret?: AgentSecret;
|
||||
}): {
|
||||
}): Promise<{
|
||||
node: LocalNode;
|
||||
accountID: AccountID;
|
||||
accountSecret: AgentSecret;
|
||||
sessionID: SessionID;
|
||||
} {
|
||||
}> {
|
||||
const throwawayAgent = newRandomAgentSecret();
|
||||
const setupNode = new LocalNode(
|
||||
new AnonymousControlledAccount(throwawayAgent),
|
||||
new ControlledAgent(throwawayAgent),
|
||||
newRandomSessionID(getAgentID(throwawayAgent))
|
||||
);
|
||||
|
||||
@@ -107,8 +109,14 @@ export class LocalNode {
|
||||
"After creating account"
|
||||
);
|
||||
|
||||
if (peersToLoadFrom) {
|
||||
for (const peer of peersToLoadFrom) {
|
||||
nodeWithAccount.syncManager.addPeer(peer);
|
||||
}
|
||||
}
|
||||
|
||||
if (migration) {
|
||||
migration(accountOnNodeWithAccount, profile as P);
|
||||
await migration(accountOnNodeWithAccount, profile as P, nodeWithAccount);
|
||||
}
|
||||
|
||||
nodeWithAccount.account = new ControlledAccount(
|
||||
@@ -156,7 +164,7 @@ export class LocalNode {
|
||||
migration?: AccountMigration<P, R, Meta>;
|
||||
}): Promise<LocalNode> {
|
||||
const loadingNode = new LocalNode(
|
||||
new AnonymousControlledAccount(accountSecret),
|
||||
new ControlledAgent(accountSecret),
|
||||
newRandomSessionID(accountID)
|
||||
);
|
||||
|
||||
@@ -194,9 +202,10 @@ export class LocalNode {
|
||||
const profile = await node.load(profileID);
|
||||
|
||||
if (migration) {
|
||||
migration(
|
||||
await migration(
|
||||
controlledAccount as ControlledAccount<P, R, Meta>,
|
||||
profile as P
|
||||
profile as P,
|
||||
node
|
||||
);
|
||||
node.account = new ControlledAccount(
|
||||
controlledAccount.core,
|
||||
@@ -370,14 +379,14 @@ export class LocalNode {
|
||||
const groupAsInvite = expectGroup(
|
||||
group.core
|
||||
.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(inviteAgentSecret),
|
||||
new ControlledAgent(inviteAgentSecret),
|
||||
newRandomSessionID(inviteAgentID)
|
||||
)
|
||||
.getCurrentContent()
|
||||
);
|
||||
|
||||
groupAsInvite.addMemberInternal(
|
||||
this.account.id,
|
||||
this.account,
|
||||
inviteRole === "adminInvite"
|
||||
? "admin"
|
||||
: inviteRole === "writerInvite"
|
||||
@@ -439,7 +448,7 @@ export class LocalNode {
|
||||
let account = expectGroup(
|
||||
this.createCoValue(accountHeaderForInitialAgentSecret(agentSecret))
|
||||
.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(agentSecret),
|
||||
new ControlledAgent(agentSecret),
|
||||
newRandomSessionID(accountAgentID)
|
||||
)
|
||||
.getCurrentContent()
|
||||
@@ -518,7 +527,7 @@ export class LocalNode {
|
||||
);
|
||||
}
|
||||
|
||||
return new Account(coValue).getCurrentAgentID();
|
||||
return new Account(coValue).currentAgentID();
|
||||
}
|
||||
|
||||
async resolveAccountAgentAsync(
|
||||
@@ -553,7 +562,7 @@ export class LocalNode {
|
||||
);
|
||||
}
|
||||
|
||||
return new Account(coValue).getCurrentAgentID();
|
||||
return new Account(coValue).currentAgentID();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -596,7 +605,7 @@ export class LocalNode {
|
||||
|
||||
/** @internal */
|
||||
testWithDifferentAccount(
|
||||
account: GeneralizedControlledAccount,
|
||||
account: ControlledAccountOrAgent,
|
||||
currentSessionID: SessionID
|
||||
): LocalNode {
|
||||
const newNode = new LocalNode(account, currentSessionID);
|
||||
|
||||
@@ -249,7 +249,7 @@ export function determineValidTransactions(
|
||||
const effectiveTransactor =
|
||||
transactor === groupContent.id &&
|
||||
groupAtTime instanceof Account
|
||||
? groupAtTime.getCurrentAgentID()
|
||||
? groupAtTime.currentAgentID()
|
||||
: transactor;
|
||||
const transactorRoleAtTxTime =
|
||||
groupAtTime.get(effectiveTransactor) ||
|
||||
|
||||
@@ -9,7 +9,7 @@ beforeEach(async () => {
|
||||
|
||||
test("Can create a node while creating a new account with profile", async () => {
|
||||
const { node, accountID, accountSecret, sessionID } =
|
||||
LocalNode.withNewlyCreatedAccount({ name: "Hermes Puggington" });
|
||||
await LocalNode.withNewlyCreatedAccount({ name: "Hermes Puggington" });
|
||||
|
||||
expect(node).not.toBeNull();
|
||||
expect(accountID).not.toBeNull();
|
||||
@@ -22,7 +22,7 @@ test("Can create a node while creating a new account with profile", async () =>
|
||||
});
|
||||
|
||||
test("A node with an account can create groups and and objects within them", async () => {
|
||||
const { node, accountID } = LocalNode.withNewlyCreatedAccount({
|
||||
const { node, accountID } = await LocalNode.withNewlyCreatedAccount({
|
||||
name: "Hermes Puggington",
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ test("A node with an account can create groups and and objects within them", asy
|
||||
|
||||
test("Can create account with one node, and then load it on another", async () => {
|
||||
const { node, accountID, accountSecret } =
|
||||
LocalNode.withNewlyCreatedAccount({ name: "Hermes Puggington" });
|
||||
await LocalNode.withNewlyCreatedAccount({ name: "Hermes Puggington" });
|
||||
|
||||
const group = await node.createGroup();
|
||||
expect(group).not.toBeNull();
|
||||
@@ -69,6 +69,7 @@ test("Can create account with one node, and then load it on another", async () =
|
||||
});
|
||||
|
||||
const map2 = await node2.load(map.id);
|
||||
if (map2 === "unavailable") throw new Error("Map unavailable");
|
||||
|
||||
expect(map2.get("foo")).toEqual("bar");
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
groupWithTwoAdmins,
|
||||
groupWithTwoAdminsHighLevel,
|
||||
} from "./testUtils.js";
|
||||
import { AnonymousControlledAccount, cojsonReady } from "../index.js";
|
||||
import { ControlledAgent, cojsonReady } from "../index.js";
|
||||
import { expectGroup } from "../typeUtils/expectGroup.js";
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -70,7 +70,7 @@ test("Added adming can add a third admin to a group (high level)", () => {
|
||||
|
||||
const thirdAdmin = groupAsOtherAdmin.core.node.createAccount("thirdAdmin");
|
||||
|
||||
groupAsOtherAdmin = groupAsOtherAdmin.addMember(thirdAdmin.id, "admin");
|
||||
groupAsOtherAdmin = groupAsOtherAdmin.addMember(thirdAdmin, "admin");
|
||||
|
||||
expect(groupAsOtherAdmin.get(thirdAdmin.id)).toEqual("admin");
|
||||
});
|
||||
@@ -166,7 +166,7 @@ test("Admins an add writers to a group, who can't add admins, writers, or reader
|
||||
|
||||
const writer = node.createAccount("writer");
|
||||
|
||||
group = group.addMember(writer.id, "writer");
|
||||
group = group.addMember(writer, "writer");
|
||||
expect(group.get(writer.id)).toEqual("writer");
|
||||
|
||||
const groupAsWriter = expectGroup(
|
||||
@@ -179,13 +179,13 @@ test("Admins an add writers to a group, who can't add admins, writers, or reader
|
||||
|
||||
const otherAgent = groupAsWriter.core.node.createAccount("otherAgent");
|
||||
|
||||
expect(() => groupAsWriter.addMember(otherAgent.id, "admin")).toThrow(
|
||||
expect(() => groupAsWriter.addMember(otherAgent, "admin")).toThrow(
|
||||
"Failed to set role"
|
||||
);
|
||||
expect(() => groupAsWriter.addMember(otherAgent.id, "writer")).toThrow(
|
||||
expect(() => groupAsWriter.addMember(otherAgent, "writer")).toThrow(
|
||||
"Failed to set role"
|
||||
);
|
||||
expect(() => groupAsWriter.addMember(otherAgent.id, "reader")).toThrow(
|
||||
expect(() => groupAsWriter.addMember(otherAgent, "reader")).toThrow(
|
||||
"Failed to set role"
|
||||
);
|
||||
|
||||
@@ -235,7 +235,7 @@ test("Admins can add readers to a group, who can't add admins, writers, or reade
|
||||
|
||||
const reader = node.createAccount("reader");
|
||||
|
||||
group = group.addMember(reader.id, "reader");
|
||||
group = group.addMember(reader, "reader");
|
||||
expect(group.get(reader.id)).toEqual("reader");
|
||||
|
||||
const groupAsReader = expectGroup(
|
||||
@@ -248,13 +248,13 @@ test("Admins can add readers to a group, who can't add admins, writers, or reade
|
||||
|
||||
const otherAgent = groupAsReader.core.node.createAccount("otherAgent");
|
||||
|
||||
expect(() => groupAsReader.addMember(otherAgent.id, "admin")).toThrow(
|
||||
expect(() => groupAsReader.addMember(otherAgent, "admin")).toThrow(
|
||||
"Failed to set role"
|
||||
);
|
||||
expect(() => groupAsReader.addMember(otherAgent.id, "writer")).toThrow(
|
||||
expect(() => groupAsReader.addMember(otherAgent, "writer")).toThrow(
|
||||
"Failed to set role"
|
||||
);
|
||||
expect(() => groupAsReader.addMember(otherAgent.id, "reader")).toThrow(
|
||||
expect(() => groupAsReader.addMember(otherAgent, "reader")).toThrow(
|
||||
"Failed to set role"
|
||||
);
|
||||
|
||||
@@ -337,7 +337,7 @@ test("Writers can write to an object that is owned by their group (high level)",
|
||||
|
||||
const writer = node.createAccount("writer");
|
||||
|
||||
group.addMember(writer.id, "writer");
|
||||
group.addMember(writer, "writer");
|
||||
|
||||
const childObject = group.createMap();
|
||||
|
||||
@@ -396,7 +396,7 @@ test("Readers can not write to an object that is owned by their group (high leve
|
||||
|
||||
const reader = node.createAccount("reader");
|
||||
|
||||
group.addMember(reader.id, "reader");
|
||||
group.addMember(reader, "reader");
|
||||
|
||||
const childObject = group.createMap();
|
||||
|
||||
@@ -548,7 +548,7 @@ test("Admins can set group read key and then writers can use it to create and re
|
||||
|
||||
const writer = node.createAccount("writer");
|
||||
|
||||
group.addMember(writer.id, "writer");
|
||||
group.addMember(writer, "writer");
|
||||
|
||||
const childObject = group.createMap();
|
||||
|
||||
@@ -637,7 +637,7 @@ test("Admins can set group read key and then use it to create private transactio
|
||||
|
||||
const reader = node.createAccount("reader");
|
||||
|
||||
group.addMember(reader.id, "reader");
|
||||
group.addMember(reader, "reader");
|
||||
|
||||
let childObject = group.createMap();
|
||||
|
||||
@@ -757,7 +757,7 @@ test("Admins can set group read key and then use it to create private transactio
|
||||
|
||||
const reader2 = node.createAccount("reader2");
|
||||
|
||||
group.addMember(reader1.id, "reader");
|
||||
group.addMember(reader1, "reader");
|
||||
|
||||
let childObject = group.createMap();
|
||||
|
||||
@@ -774,7 +774,7 @@ test("Admins can set group read key and then use it to create private transactio
|
||||
|
||||
expect(childContentAsReader1.get("foo")).toEqual("bar");
|
||||
|
||||
group.addMember(reader2.id, "reader");
|
||||
group.addMember(reader2, "reader");
|
||||
|
||||
const childContentAsReader2 = expectMap(
|
||||
childObject.core
|
||||
@@ -1013,7 +1013,7 @@ test("Admins can set group read key, make a private transaction in an owned obje
|
||||
|
||||
const reader = node.createAccount("reader");
|
||||
|
||||
group.addMember(reader.id, "reader");
|
||||
group.addMember(reader, "reader");
|
||||
|
||||
childObject = childObject.edit((editable) => {
|
||||
editable.set("foo2", "bar2", "private");
|
||||
@@ -1210,8 +1210,8 @@ test("Admins can set group read rey, make a private transaction in an owned obje
|
||||
|
||||
const reader2 = node.createAccount("reader2");
|
||||
|
||||
group.addMember(reader.id, "reader");
|
||||
group.addMember(reader2.id, "reader");
|
||||
group.addMember(reader, "reader");
|
||||
group.addMember(reader2, "reader");
|
||||
|
||||
childObject = childObject.edit((editable) => {
|
||||
editable.set("foo2", "bar2", "private");
|
||||
@@ -1314,7 +1314,7 @@ test("Admins can create an adminInvite, which can add an admin", () => {
|
||||
const groupAsInvite = expectGroup(
|
||||
groupCore
|
||||
.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(inviteSecret),
|
||||
new ControlledAgent(inviteSecret),
|
||||
newRandomSessionID(inviteID)
|
||||
)
|
||||
.getCurrentContent()
|
||||
@@ -1363,7 +1363,7 @@ test("Admins can create an adminInvite, which can add an admin (high-level)", as
|
||||
const invitedAdminID = getAgentID(invitedAdminSecret);
|
||||
|
||||
const nodeAsInvitedAdmin = node.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(invitedAdminSecret),
|
||||
new ControlledAgent(invitedAdminSecret),
|
||||
newRandomSessionID(invitedAdminID)
|
||||
);
|
||||
|
||||
@@ -1433,7 +1433,7 @@ test("Admins can create a writerInvite, which can add a writer", () => {
|
||||
const groupAsInvite = expectGroup(
|
||||
groupCore
|
||||
.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(inviteSecret),
|
||||
new ControlledAgent(inviteSecret),
|
||||
newRandomSessionID(inviteID)
|
||||
)
|
||||
.getCurrentContent()
|
||||
@@ -1482,7 +1482,7 @@ test("Admins can create a writerInvite, which can add a writer (high-level)", as
|
||||
const invitedWriterID = getAgentID(invitedWriterSecret);
|
||||
|
||||
const nodeAsInvitedWriter = node.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(invitedWriterSecret),
|
||||
new ControlledAgent(invitedWriterSecret),
|
||||
newRandomSessionID(invitedWriterID)
|
||||
);
|
||||
|
||||
@@ -1542,7 +1542,7 @@ test("Admins can create a readerInvite, which can add a reader", () => {
|
||||
const groupAsInvite = expectGroup(
|
||||
groupCore
|
||||
.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(inviteSecret),
|
||||
new ControlledAgent(inviteSecret),
|
||||
newRandomSessionID(inviteID)
|
||||
)
|
||||
.getCurrentContent()
|
||||
@@ -1591,7 +1591,7 @@ test("Admins can create a readerInvite, which can add a reader (high-level)", as
|
||||
const invitedReaderID = getAgentID(invitedReaderSecret);
|
||||
|
||||
const nodeAsInvitedReader = node.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(invitedReaderSecret),
|
||||
new ControlledAgent(invitedReaderSecret),
|
||||
newRandomSessionID(invitedReaderID)
|
||||
);
|
||||
|
||||
@@ -1651,7 +1651,7 @@ test("WriterInvites can not invite admins", () => {
|
||||
const groupAsInvite = expectGroup(
|
||||
groupCore
|
||||
.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(inviteSecret),
|
||||
new ControlledAgent(inviteSecret),
|
||||
newRandomSessionID(inviteID)
|
||||
)
|
||||
.getCurrentContent()
|
||||
@@ -1711,7 +1711,7 @@ test("ReaderInvites can not invite admins", () => {
|
||||
const groupAsInvite = expectGroup(
|
||||
groupCore
|
||||
.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(inviteSecret),
|
||||
new ControlledAgent(inviteSecret),
|
||||
newRandomSessionID(inviteID)
|
||||
)
|
||||
.getCurrentContent()
|
||||
@@ -1771,7 +1771,7 @@ test("ReaderInvites can not invite writers", () => {
|
||||
const groupAsInvite = expectGroup(
|
||||
groupCore
|
||||
.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(inviteSecret),
|
||||
new ControlledAgent(inviteSecret),
|
||||
newRandomSessionID(inviteID)
|
||||
)
|
||||
.getCurrentContent()
|
||||
@@ -1812,7 +1812,7 @@ test("Can give read permission to 'everyone'", () => {
|
||||
expect(editable.get("foo")).toEqual("bar");
|
||||
});
|
||||
|
||||
const newAccount = new AnonymousControlledAccount(newRandomAgentSecret());
|
||||
const newAccount = new ControlledAgent(newRandomAgentSecret());
|
||||
|
||||
const childContent2 = expectMap(
|
||||
childObject
|
||||
@@ -1840,12 +1840,12 @@ test("Can give read permissions to 'everyone' (high-level)", async () => {
|
||||
expect(editable.get("foo")).toEqual("bar");
|
||||
});
|
||||
|
||||
const newAccount = new AnonymousControlledAccount(newRandomAgentSecret());
|
||||
const newAccount = new ControlledAgent(newRandomAgentSecret());
|
||||
|
||||
const childContent2 = expectMap(
|
||||
childObject.core
|
||||
.testWithDifferentAccount(
|
||||
new AnonymousControlledAccount(newRandomAgentSecret()),
|
||||
new ControlledAgent(newRandomAgentSecret()),
|
||||
newRandomSessionID(newAccount.currentAgentID())
|
||||
)
|
||||
.getCurrentContent()
|
||||
@@ -1880,7 +1880,7 @@ test("Can give write permission to 'everyone'", () => {
|
||||
expect(editable.get("foo")).toEqual("bar");
|
||||
});
|
||||
|
||||
const newAccount = new AnonymousControlledAccount(newRandomAgentSecret());
|
||||
const newAccount = new ControlledAgent(newRandomAgentSecret());
|
||||
|
||||
const childContent2 = expectMap(
|
||||
childObject
|
||||
@@ -1913,7 +1913,7 @@ test("Can give write permissions to 'everyone' (high-level)", async () => {
|
||||
expect(editable.get("foo")).toEqual("bar");
|
||||
});
|
||||
|
||||
const newAccount = new AnonymousControlledAccount(newRandomAgentSecret());
|
||||
const newAccount = new ControlledAgent(newRandomAgentSecret());
|
||||
|
||||
const childContent2 = expectMap(
|
||||
childObject.core
|
||||
|
||||
@@ -2,17 +2,17 @@ import { AgentSecret, createdNowUnique, getAgentID, newRandomAgentSecret } from
|
||||
import { newRandomSessionID } from "../coValueCore.js";
|
||||
import { LocalNode } from "../localNode.js";
|
||||
import { expectGroup } from "../typeUtils/expectGroup.js";
|
||||
import { AnonymousControlledAccount } from "../coValues/account.js";
|
||||
import { ControlledAgent } from "../coValues/account.js";
|
||||
import { SessionID } from "../ids.js";
|
||||
// @ts-ignore
|
||||
import { expect } from "bun:test";
|
||||
|
||||
export function randomAnonymousAccountAndSessionID(): [AnonymousControlledAccount, SessionID] {
|
||||
export function randomAnonymousAccountAndSessionID(): [ControlledAgent, SessionID] {
|
||||
const agentSecret = newRandomAgentSecret();
|
||||
|
||||
const sessionID = newRandomSessionID(getAgentID(agentSecret));
|
||||
|
||||
return [new AnonymousControlledAccount(agentSecret), sessionID];
|
||||
return [new ControlledAgent(agentSecret), sessionID];
|
||||
}
|
||||
|
||||
export function newGroup() {
|
||||
@@ -73,7 +73,7 @@ export function groupWithTwoAdminsHighLevel() {
|
||||
|
||||
const otherAdmin = node.createAccount("otherAdmin");
|
||||
|
||||
group = group.addMember(otherAdmin.id, "admin");
|
||||
group = group.addMember(otherAdmin, "admin");
|
||||
|
||||
return { admin, node, group, otherAdmin };
|
||||
}
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# jazz-autosub
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Make addMember and removeMember take loaded Accounts instead of just IDs
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.6.0
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
"types": "src/index.ts",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"dependencies": {
|
||||
"cojson": "^0.5.0"
|
||||
"cojson": "^0.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
AccountID,
|
||||
Account,
|
||||
BinaryCoStream,
|
||||
CoID,
|
||||
CoList,
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
Role,
|
||||
} from "cojson";
|
||||
import { AutoSubContext, ValueOrResolvedRef } from "../autoSub.js";
|
||||
import { ControlledAccountOrAgent } from "cojson/src/coValues/account.js";
|
||||
|
||||
export class ResolvedGroupMeta<G extends Group> {
|
||||
coValue!: G;
|
||||
@@ -55,12 +56,12 @@ export class ResolvedGroup<G extends Group = Group> {
|
||||
);
|
||||
}
|
||||
|
||||
addMember(accountID: AccountID | Everyone, role: Role): G {
|
||||
addMember(accountID: Account | ControlledAccountOrAgent | Everyone, role: Role): G {
|
||||
return this.meta.group.addMember(accountID, role);
|
||||
}
|
||||
|
||||
removeMember(accountID: AccountID): G {
|
||||
return this.meta.group.removeMember(accountID);
|
||||
removeMember(account: Account | ControlledAccountOrAgent | Everyone): G {
|
||||
return this.meta.group.removeMember(account);
|
||||
}
|
||||
|
||||
createInvite(role: "reader" | "writer" | "admin"): InviteSecret {
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# jazz-browser-auth-local
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Make addMember and removeMember take loaded Accounts instead of just IDs
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-browser@0.6.0
|
||||
|
||||
## 0.4.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Allow account migrations to be async
|
||||
- Updated dependencies
|
||||
- jazz-browser@0.5.1
|
||||
|
||||
## 0.4.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "jazz-browser-auth-local",
|
||||
"version": "0.4.16",
|
||||
"version": "0.5.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jazz-browser": "^0.5.0",
|
||||
"jazz-browser": "^0.6.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -110,7 +110,7 @@ async function signUp(
|
||||
const secretSeed = cojsonInternals.newRandomSecretSeed();
|
||||
|
||||
const { node, accountID, accountSecret } =
|
||||
LocalNode.withNewlyCreatedAccount({
|
||||
await LocalNode.withNewlyCreatedAccount({
|
||||
name: username,
|
||||
initialAgentSecret: agentSecretFromSecretSeed(secretSeed),
|
||||
migration,
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# jazz-browser-media-images
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-autosub@0.6.0
|
||||
- jazz-browser@0.6.0
|
||||
- cojson@0.6.0
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "jazz-browser-media-images",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/image-blob-reduce": "^4.1.1",
|
||||
"cojson": "^0.5.0",
|
||||
"cojson": "^0.6.0",
|
||||
"image-blob-reduce": "^4.1.0",
|
||||
"jazz-autosub": "^0.5.0",
|
||||
"jazz-browser": "^0.5.0",
|
||||
"jazz-autosub": "^0.6.0",
|
||||
"jazz-browser": "^0.6.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# jazz-browser
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Make addMember and removeMember take loaded Accounts instead of just IDs
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-storage-indexeddb@0.6.0
|
||||
- jazz-autosub@0.6.0
|
||||
- cojson@0.6.0
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Allow account migrations to be async
|
||||
- Updated dependencies
|
||||
- cojson@0.5.2
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "jazz-browser",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cojson": "^0.5.0",
|
||||
"cojson-storage-indexeddb": "^0.5.0",
|
||||
"jazz-autosub": "^0.5.0",
|
||||
"cojson": "^0.6.0",
|
||||
"cojson-storage-indexeddb": "^0.6.0",
|
||||
"jazz-autosub": "^0.6.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -61,7 +61,7 @@ export class BrowserDemoAuth implements AuthProvider {
|
||||
this.driver.onReady({
|
||||
signUp: async (username) => {
|
||||
const { node, accountID, accountSecret } =
|
||||
LocalNode.withNewlyCreatedAccount({
|
||||
await LocalNode.withNewlyCreatedAccount({
|
||||
name: username,
|
||||
migration,
|
||||
});
|
||||
|
||||
22
packages/jazz-nodejs/.eslintrc.cjs
Normal file
22
packages/jazz-nodejs/.eslintrc.cjs
Normal file
@@ -0,0 +1,22 @@
|
||||
module.exports = {
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:require-extensions/recommended",
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
plugins: ["@typescript-eslint", "require-extensions"],
|
||||
parserOptions: {
|
||||
project: "./tsconfig.json",
|
||||
},
|
||||
ignorePatterns: [".eslint.cjs", "**/tests/*"],
|
||||
root: true,
|
||||
rules: {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
||||
],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
},
|
||||
};
|
||||
171
packages/jazz-nodejs/.gitignore
vendored
Normal file
171
packages/jazz-nodejs/.gitignore
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||
|
||||
# Logs
|
||||
|
||||
logs
|
||||
_.log
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
\*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
\*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
\*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
\*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
|
||||
.cache/
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.\*
|
||||
|
||||
.DS_Store
|
||||
2
packages/jazz-nodejs/.npmignore
Normal file
2
packages/jazz-nodejs/.npmignore
Normal file
@@ -0,0 +1,2 @@
|
||||
coverage
|
||||
node_modules
|
||||
51
packages/jazz-nodejs/CHANGELOG.md
Normal file
51
packages/jazz-nodejs/CHANGELOG.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# jazz-autosub
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix wrong import from cojson
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Make addMember and removeMember take loaded Accounts instead of just IDs
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-autosub@0.6.0
|
||||
- cojson@0.6.0
|
||||
- cojson-transport-nodejs-ws@0.5.1
|
||||
|
||||
## 0.5.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Allow account migrations to be async
|
||||
- Updated dependencies
|
||||
- cojson@0.5.2
|
||||
|
||||
## 0.5.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Expose migration for jazz-nodejs
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- First version of jazz-nodejs
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Adding a lot of performance improvements to cojson, add a stresstest for the twit example and make that run smoother in a lot of ways.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.5.0
|
||||
19
packages/jazz-nodejs/LICENSE.txt
Normal file
19
packages/jazz-nodejs/LICENSE.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright 2023, Garden Computing, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
3
packages/jazz-nodejs/README.md
Normal file
3
packages/jazz-nodejs/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# CoJSON
|
||||
|
||||
[See the top-level README](../../README.md#cojson)
|
||||
42
packages/jazz-nodejs/package.json
Normal file
42
packages/jazz-nodejs/package.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "jazz-nodejs",
|
||||
"module": "dist/index.js",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.6.1",
|
||||
"dependencies": {
|
||||
"cojson": "^0.6.0",
|
||||
"cojson-transport-nodejs-ws": "^0.5.1",
|
||||
"jazz-autosub": "^0.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"build": "npm run lint && rm -rf ./dist && tsc --sourceMap --outDir dist",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "ts-jest",
|
||||
"testEnvironment": "node",
|
||||
"transform": {
|
||||
"\\.[jt]sx?$": [
|
||||
"ts-jest",
|
||||
{
|
||||
"useESM": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"moduleNameMapper": {
|
||||
"(.+)\\.js": "$1"
|
||||
},
|
||||
"extensionsToTreatAsEsm": [
|
||||
".ts"
|
||||
],
|
||||
"modulePathIgnorePatterns": [
|
||||
"/node_modules/",
|
||||
"/dist/"
|
||||
]
|
||||
}
|
||||
}
|
||||
161
packages/jazz-nodejs/src/index.ts
Normal file
161
packages/jazz-nodejs/src/index.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import {
|
||||
websocketReadableStream,
|
||||
websocketWritableStream,
|
||||
} from "cojson-transport-nodejs-ws";
|
||||
import { WebSocket } from "ws";
|
||||
import "dotenv/config";
|
||||
|
||||
import { webcrypto } from "node:crypto";
|
||||
import {
|
||||
AccountID,
|
||||
AccountMigration,
|
||||
AgentSecret,
|
||||
CoMap,
|
||||
ControlledAccount,
|
||||
LocalNode,
|
||||
Peer,
|
||||
Profile,
|
||||
SessionID,
|
||||
cojsonReady,
|
||||
cojsonInternals
|
||||
} from "cojson";
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
|
||||
if (!("crypto" in globalThis)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(globalThis as any).crypto = webcrypto;
|
||||
}
|
||||
|
||||
interface WorkerCredentialStorage {
|
||||
load(
|
||||
workerName: string
|
||||
): Promise<
|
||||
{ accountID: AccountID; accountSecret: AgentSecret } | undefined
|
||||
>;
|
||||
save(
|
||||
workerName: string,
|
||||
accountID: AccountID,
|
||||
accountSecret: AgentSecret
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
export async function createOrResumeWorker<
|
||||
P extends Profile = Profile,
|
||||
R extends CoMap = CoMap
|
||||
>({
|
||||
workerName,
|
||||
credentialStorage = FileCredentialStorage,
|
||||
syncServer = "wss://sync.jazz.tools",
|
||||
migration,
|
||||
}: {
|
||||
workerName: string;
|
||||
credentialStorage?: WorkerCredentialStorage;
|
||||
syncServer?: string;
|
||||
migration?: AccountMigration<P, R>;
|
||||
}) {
|
||||
await cojsonReady;
|
||||
|
||||
const existingCredentials = await credentialStorage.load(workerName);
|
||||
|
||||
let localNode: LocalNode;
|
||||
|
||||
const ws = new WebSocket(syncServer);
|
||||
|
||||
const wsPeer: Peer = {
|
||||
id: "globalMesh",
|
||||
role: "server",
|
||||
incoming: websocketReadableStream(ws),
|
||||
outgoing: websocketWritableStream(ws),
|
||||
};
|
||||
|
||||
if (existingCredentials) {
|
||||
// TODO: locked sessions similar to browser
|
||||
const sessionID =
|
||||
process.env.JAZZ_WORKER_SESSION ||
|
||||
cojsonInternals.newRandomSessionID(existingCredentials.accountID);
|
||||
|
||||
console.log("Loading worker", existingCredentials.accountID);
|
||||
|
||||
localNode = await LocalNode.withLoadedAccount({
|
||||
accountID: existingCredentials.accountID,
|
||||
accountSecret: existingCredentials.accountSecret,
|
||||
sessionID: sessionID as SessionID,
|
||||
migration,
|
||||
peersToLoadFrom: [wsPeer],
|
||||
});
|
||||
|
||||
console.log(
|
||||
"Resuming worker",
|
||||
existingCredentials.accountID,
|
||||
localNode
|
||||
.expectProfileLoaded(localNode.account.id as AccountID)
|
||||
.get("name")
|
||||
);
|
||||
} else {
|
||||
const newWorker = await LocalNode.withNewlyCreatedAccount({
|
||||
name: workerName,
|
||||
peersToLoadFrom: [wsPeer],
|
||||
migration,
|
||||
});
|
||||
|
||||
localNode = newWorker.node;
|
||||
|
||||
await credentialStorage.save(
|
||||
workerName,
|
||||
newWorker.accountID,
|
||||
newWorker.accountSecret
|
||||
);
|
||||
|
||||
console.log("Created worker", newWorker.accountID, workerName);
|
||||
}
|
||||
|
||||
return { localNode, worker: localNode.account as ControlledAccount<P, R> };
|
||||
}
|
||||
|
||||
export { autoSub } from "jazz-autosub";
|
||||
|
||||
export const FileCredentialStorage: WorkerCredentialStorage = {
|
||||
async load(workerName: string): Promise<
|
||||
| {
|
||||
accountID: AccountID;
|
||||
accountSecret: `sealerSecret_z${string}/signerSecret_z${string}`;
|
||||
}
|
||||
| undefined
|
||||
> {
|
||||
try {
|
||||
const credentials = await readFile(
|
||||
`${workerName}Credentials.json`,
|
||||
"utf-8"
|
||||
);
|
||||
return JSON.parse(credentials);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
async save(
|
||||
workerName: string,
|
||||
accountID: AccountID,
|
||||
accountSecret: `sealerSecret_z${string}/signerSecret_z${string}`
|
||||
): Promise<void> {
|
||||
await writeFile(
|
||||
`${workerName}Credentials.json`,
|
||||
JSON.stringify({ accountID, accountSecret }, undefined, 2)
|
||||
);
|
||||
console.log(
|
||||
`Saved credentials for ${workerName} to ${workerName}Credentials.json`
|
||||
);
|
||||
try {
|
||||
const gitginore = await readFile(".gitignore", "utf-8");
|
||||
if (!gitginore.includes(`${workerName}Credentials.json`)) {
|
||||
await writeFile(
|
||||
".gitignore",
|
||||
gitginore + `\n${workerName}Credentials.json`
|
||||
);
|
||||
console.log(`Added ${workerName}Credentials.json to .gitignore`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`Couldn't add ${workerName}Credentials.json to .gitignore, please add it yourself.`)
|
||||
}
|
||||
},
|
||||
};
|
||||
16
packages/jazz-nodejs/tsconfig.json
Normal file
16
packages/jazz-nodejs/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"module": "esnext",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
"exclude": ["./src/**/*.test.*"],
|
||||
}
|
||||
2786
packages/jazz-nodejs/yarn.lock
Normal file
2786
packages/jazz-nodejs/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,13 @@
|
||||
# jazz-react-auth-local
|
||||
|
||||
## 0.4.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-browser-auth-local@0.5.0
|
||||
- jazz-react@0.5.1
|
||||
|
||||
## 0.4.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "jazz-react-auth-local",
|
||||
"version": "0.4.16",
|
||||
"version": "0.4.17",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.tsx",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jazz-browser-auth-local": "^0.4.16",
|
||||
"jazz-react": "^0.5.0",
|
||||
"jazz-browser-auth-local": "^0.5.0",
|
||||
"jazz-react": "^0.5.1",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# jazz-react
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-browser@0.6.0
|
||||
- cojson@0.6.0
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "jazz-react",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cojson": "^0.5.0",
|
||||
"jazz-browser": "^0.5.0",
|
||||
"cojson": "^0.6.0",
|
||||
"jazz-browser": "^0.6.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Reference in New Issue
Block a user