Compare commits

...

10 Commits

Author SHA1 Message Date
Anselm
01817db873 Add docs for jazz-nodejs 2023-10-25 14:31:27 +01:00
Anselm
46fcbd6c01 Implement first version of jazz-nodejs 2023-10-25 14:27:55 +01:00
Anselm
aa3e3de09e Update docs 2023-10-20 11:09:19 +01:00
Anselm
af3d48764d Reset allTweets 2023-10-20 10:50:29 +01:00
Anselm
091f36b736 Update all tweets 2023-10-20 10:38:56 +01:00
Anselm
7107f79f42 Update all tweets 2023-10-20 10:32:30 +01:00
Anselm
9922db2336 Cosmetic fixes 2023-10-20 10:23:40 +01:00
Anselm
75db570198 Use DemoAuth in Twit example 2023-10-20 10:18:14 +01:00
Anselm
28a09f377b Fix weird TypeScript error 2023-10-20 10:11:31 +01:00
Anselm
fd2e0855bb Deploy twit and chat 2023-10-20 09:56:09 +01:00
24 changed files with 3242 additions and 63 deletions

View File

@@ -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

57
DOCS.md
View File

@@ -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,53 @@ 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?)`
<sup>(function in `jazz-nodejs`)</sup>
```typescript
export function createOrResumeWorker(workerName: string, syncServer: string): Promise<{
localNode: LocalNode,
worker: ControlledAccount<Profile<ProfileShape, ProfileMeta>, CoMap<{
[key: string]: JsonValue | undefined }, null | JsonObject>, AccountMeta>,
}>
```
TODO: document
### Parameters:
| name | description |
| ----: | ---- |
| `workerName` | TODO: document |
| `syncServer?` | 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 |

View File

@@ -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(

View File

@@ -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";

View File

@@ -22,3 +22,5 @@ dist-ssr
*.njsproj
*.sln
*.sw?
.env

View File

@@ -9,32 +9,13 @@ 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(
"TwitStressTestBot" + Math.random().toString(36).slice(2),
);
console.log(
"profile",

View File

@@ -3,30 +3,15 @@ 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(
"TwitAllTwitsCreator"
);
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);

View File

@@ -6,8 +6,7 @@
"license": "MIT",
"private": true,
"dependencies": {
"cojson": "^0.5.0",
"cojson-transport-nodejs-ws": "^0.5.0"
"jazz-nodejs": "^0.5.0"
},
"scripts": {
"build": "rm -rf ./dist && tsc --sourceMap --outDir dist",

View File

@@ -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')) {

View File

@@ -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>
);

View File

@@ -39,7 +39,7 @@ export function ProfilePage() {
? null
: twit?.isReplyTo
: twit
);
) || [];
}, [profile?.twits]);
const [qr, setQr] = useState<string>('');

View File

@@ -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) {

View File

@@ -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}`],

View 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
View 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

View File

@@ -0,0 +1,2 @@
coverage
node_modules

View File

@@ -0,0 +1,18 @@
# jazz-autosub
## 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

View 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.

View File

@@ -0,0 +1,3 @@
# CoJSON
[See the top-level README](../../README.md#cojson)

View File

@@ -0,0 +1,43 @@
{
"name": "jazz-nodejs",
"module": "dist/index.js",
"main": "dist/index.js",
"types": "src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.5.1",
"dependencies": {
"cojson": "^0.5.0",
"cojson-transport-nodejs-ws": "^0.5.0",
"dotenv": "^16.3.1",
"jazz-autosub": "^0.5.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/"
]
}
}

View File

@@ -0,0 +1,67 @@
import {
websocketReadableStream,
websocketWritableStream,
} from "cojson-transport-nodejs-ws";
import { WebSocket } from "ws";
import "dotenv/config";
import { webcrypto } from "node:crypto";
import { AccountID, AgentSecret, ControlledAccount, LocalNode, Peer, SessionID, cojsonReady } from "cojson";
import { newRandomSessionID } from "cojson/src/coValueCore";
if (!("crypto" in globalThis)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).crypto = webcrypto;
}
import { writeFile } from "node:fs/promises"
export async function createOrResumeWorker(workerName: string, syncServer = "wss://sync.jazz.tools") {
await cojsonReady;
const existingID = process.env.JAZZ_WORKER_ID;
const existingSecret = process.env.JAZZ_WORKER_SECRET;
let localNode: LocalNode;
const ws = new WebSocket(syncServer);
const wsPeer: Peer = {
id: "globalMesh",
role: "server",
incoming: websocketReadableStream(ws),
outgoing: websocketWritableStream(ws),
};
if (existingID && existingSecret) {
// TODO: locked sessions similar to browser
const sessionID = process.env.JAZZ_WORKER_SESSION || newRandomSessionID(existingID as AccountID);
console.log("Loading worker", existingID);
localNode = await LocalNode.withLoadedAccount({
accountID: existingID as AccountID,
accountSecret: existingSecret as AgentSecret,
sessionID: sessionID as SessionID,
peersToLoadFrom: [wsPeer]
});
console.log("Resuming worker", existingID, localNode.expectProfileLoaded(localNode.account.id as AccountID).get("name"));
} else {
const newWorker = await LocalNode.withNewlyCreatedAccount({
name: workerName,
});
localNode = newWorker.node;
localNode.syncManager.addPeer(wsPeer);
await writeFile(".env", `JAZZ_WORKER_ID=${newWorker.accountID}\nJAZZ_WORKER_SECRET=${newWorker.accountSecret}\n`);
console.log("Created worker", newWorker.accountID, workerName);
console.log("!!! Make sure to exclude .env from git, as it now contains your worker's credentials !!!")
}
return { localNode, worker: localNode.account as ControlledAccount };
}
export { autoSub } from "jazz-autosub";

View 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.*"],
}

File diff suppressed because it is too large Load Diff

View File

@@ -3782,6 +3782,11 @@ dot-prop@^5.1.0:
dependencies:
is-obj "^2.0.0"
dotenv@^16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e"
integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==
dotenv@~10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"