Compare commits
21 Commits
jazz-brows
...
jazz-brows
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8def1bb29e | ||
|
|
d379b04e33 | ||
|
|
17a30e054e | ||
|
|
7d8f4b4c00 | ||
|
|
e2a3896bf0 | ||
|
|
446de8e0ff | ||
|
|
5ae6c95878 | ||
|
|
7cde349a50 | ||
|
|
61e640f574 | ||
|
|
ed122d9d8e | ||
|
|
34817f4536 | ||
|
|
0998a0eabf | ||
|
|
a96108478b | ||
|
|
a4cf4c40d4 | ||
|
|
934fe4d29b | ||
|
|
408012f2e5 | ||
|
|
d0078b830e | ||
|
|
e52948b2b7 | ||
|
|
53bb1b230b | ||
|
|
54e83aeaaa | ||
|
|
aa3129cab5 |
106
.github/workflows/build-and-deploy.yaml
vendored
106
.github/workflows/build-and-deploy.yaml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
# example: ["chat", "todo", "pets", "twit", "file-drop"]
|
||||
example: ["twit", "chat"]
|
||||
example: ["twit", "chat", "counter-js-auth0"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -54,32 +54,32 @@ jobs:
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
# build-homepage:
|
||||
# runs-on: ubuntu-latest
|
||||
build-homepage:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# with:
|
||||
# submodules: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
# - name: Set up Docker Buildx
|
||||
# uses: docker/setup-buildx-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
# - name: Login to GitHub Container Registry
|
||||
# uses: docker/login-action@v2
|
||||
# with:
|
||||
# registry: ghcr.io
|
||||
# username: gardencmp
|
||||
# password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: gardencmp
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# - name: Docker Build & Push
|
||||
# uses: docker/build-push-action@v4
|
||||
# with:
|
||||
# context: ./homepage/homepage-jazz
|
||||
# push: true
|
||||
# tags: ghcr.io/gardencmp/${{github.event.repository.name}}-homepage-jazz:${{github.head_ref || github.ref_name}}-${{github.sha}}-${{github.run_number}}-${{github.run_attempt}}
|
||||
# cache-from: type=gha
|
||||
# cache-to: type=gha,mode=max
|
||||
- name: Docker Build & Push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: ./homepage
|
||||
push: true
|
||||
tags: ghcr.io/gardencmp/${{github.event.repository.name}}-homepage-jazz:${{github.head_ref || github.ref_name}}-${{github.sha}}-${{github.run_number}}-${{github.run_attempt}}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
deploy-examples:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
# example: ["chat", "todo", "pets", "twit", "file-drop"]
|
||||
example: ["twit", "chat"]
|
||||
example: ["twit", "chat", "counter-js-auth0"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -115,38 +115,38 @@ 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:
|
||||
# runs-on: ubuntu-latest
|
||||
# needs: build-homepage
|
||||
deploy-homepage:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-homepage
|
||||
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# with:
|
||||
# submodules: true
|
||||
# - uses: gacts/install-nomad@v1
|
||||
# - name: Tailscale
|
||||
# uses: tailscale/github-action@v1
|
||||
# with:
|
||||
# authkey: ${{ secrets.TAILSCALE_AUTHKEY }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: gacts/install-nomad@v1
|
||||
- name: Tailscale
|
||||
uses: tailscale/github-action@v1
|
||||
with:
|
||||
authkey: ${{ secrets.TAILSCALE_AUTHKEY }}
|
||||
|
||||
# - name: Deploy on Nomad
|
||||
# run: |
|
||||
# if [ "${{github.ref_name}}" == "main" ]; then
|
||||
# export BRANCH_SUFFIX="";
|
||||
# export BRANCH_SUBDOMAIN="";
|
||||
# else
|
||||
# export BRANCH_SUFFIX=-${{github.head_ref || github.ref_name}};
|
||||
# export BRANCH_SUBDOMAIN=${{github.head_ref || github.ref_name}}.;
|
||||
# fi
|
||||
- name: Deploy on Nomad
|
||||
run: |
|
||||
if [ "${{github.ref_name}}" == "main" ]; then
|
||||
export BRANCH_SUFFIX="";
|
||||
export BRANCH_SUBDOMAIN="";
|
||||
else
|
||||
export BRANCH_SUFFIX=-${{github.head_ref || github.ref_name}};
|
||||
export BRANCH_SUBDOMAIN=${{github.head_ref || github.ref_name}}.;
|
||||
fi
|
||||
|
||||
# export DOCKER_USER=gardencmp;
|
||||
# export DOCKER_PASSWORD=${{ secrets.DOCKER_PULL_PAT }};
|
||||
# export DOCKER_TAG=ghcr.io/gardencmp/${{github.event.repository.name}}-homepage-jazz:${{github.head_ref || github.ref_name}}-${{github.sha}}-${{github.run_number}}-${{github.run_attempt}};
|
||||
export DOCKER_USER=gardencmp;
|
||||
export DOCKER_PASSWORD=${{ secrets.DOCKER_PULL_PAT }};
|
||||
export DOCKER_TAG=ghcr.io/gardencmp/${{github.event.repository.name}}-homepage-jazz:${{github.head_ref || github.ref_name}}-${{github.sha}}-${{github.run_number}}-${{github.run_attempt}};
|
||||
|
||||
# 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;
|
||||
# working-directory: ./homepage/homepage-jazz
|
||||
envsubst '${DOCKER_USER} ${DOCKER_PASSWORD} ${DOCKER_TAG} ${BRANCH_SUFFIX} ${BRANCH_SUBDOMAIN}' < job-template.nomad > job-instance.nomad;
|
||||
cat job-instance.nomad;
|
||||
NOMAD_ADDR=${{ secrets.NOMAD_ADDR }} nomad job run job-instance.nomad;
|
||||
working-directory: ./homepage
|
||||
18
examples/chat-passphrase/.eslintrc.cjs
Normal file
18
examples/chat-passphrase/.eslintrc.cjs
Normal file
@@ -0,0 +1,18 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
24
examples/chat-passphrase/.gitignore
vendored
Normal file
24
examples/chat-passphrase/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
17
examples/chat-passphrase/CHANGELOG.md
Normal file
17
examples/chat-passphrase/CHANGELOG.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# jazz-example-chat
|
||||
|
||||
## 0.0.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Implement passphrase based auth
|
||||
- Updated dependencies
|
||||
- jazz-react-auth-passphrase@0.5.1
|
||||
|
||||
## 0.0.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-react@0.5.0
|
||||
- jazz-react-auth-local@0.4.16
|
||||
4
examples/chat-passphrase/Dockerfile
Normal file
4
examples/chat-passphrase/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
||||
FROM caddy:2.7.3-alpine
|
||||
LABEL org.opencontainers.image.source="https://github.com/gardencmp/jazz"
|
||||
|
||||
COPY ./dist /usr/share/caddy/
|
||||
64
examples/chat-passphrase/README.md
Normal file
64
examples/chat-passphrase/README.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Jazz Todo List Example
|
||||
|
||||
Live version: https://example-todo.jazz.tools
|
||||
|
||||
## Installing & running the example locally
|
||||
|
||||
Start by checking out just the example app to a folder:
|
||||
|
||||
```bash
|
||||
npx degit gardencmp/jazz/examples/todo jazz-example-todo
|
||||
cd jazz-example-todo
|
||||
```
|
||||
|
||||
(This ensures that you have the example app without git history or our multi-package monorepo)
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Start the dev server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
- [`src/basicComponents`](./src/basicComponents): simple components to build the UI, unrelated to Jazz (uses [shadcn/ui](https://ui.shadcn.com))
|
||||
- [`src/components`](./src/components/): helper components that do contain Jazz-specific logic, but aren't very relevant to understand the basics of Jazz and CoJSON
|
||||
- [`src/1_types.ts`](./src/1_types.ts),
|
||||
[`src/2_main.tsx`](./src/2_main.tsx),
|
||||
[`src/3_NewProjectForm.tsx`](./src/3_NewProjectForm.tsx),
|
||||
[`src/4_ProjectTodoTable.tsx`](./src/4_ProjectTodoTable.tsx): the main files for this example, see the walkthrough below
|
||||
|
||||
## Walkthrough
|
||||
|
||||
### Main parts
|
||||
|
||||
1. Defining the data model with CoJSON: [`src/1_types.ts`](./src/1_types.ts)
|
||||
|
||||
2. The top-level provider `<WithJazz/>` and routing: [`src/2_main.tsx`](./src/2_main.tsx)
|
||||
|
||||
3. Creating a new todo project: [`src/3_NewProjectForm.tsx`](./src/3_NewProjectForm.tsx)
|
||||
|
||||
4. Reactively rendering a todo project as a table, adding and editing tasks: [`src/4_ProjectTodoTable.tsx`](./src/4_ProjectTodoTable.tsx)
|
||||
|
||||
### Helpers
|
||||
|
||||
- (not yet explained) Creating invite links/QR codes with `<InviteButton/>`: [`src/components/InviteButton.tsx`](./src/components/InviteButton.tsx)
|
||||
|
||||
This is the whole Todo List app!
|
||||
|
||||
## Questions / problems / feedback
|
||||
|
||||
If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or open an issue or PR to fix something that seems wrong.
|
||||
|
||||
|
||||
## Configuration: sync server
|
||||
|
||||
By default, the example app uses [Jazz Global Mesh](https://jazz.tools/mesh) (`wss://sync.jazz.tools`) - so cross-device use, invites and collaboration should just work.
|
||||
|
||||
You can also run a local sync server by running `npx cojson-simple-sync` and adding the query param `?sync=ws://localhost:4200` to the URL of the example app (for example: `http://localhost:5173/?sync=ws://localhost:4200`), or by setting the `sync` parameter of the `<WithJazz>` provider component in [./src/2_main.tsx](./src/2_main.tsx).
|
||||
14
examples/chat-passphrase/index.html
Normal file
14
examples/chat-passphrase/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/png" href="/jazz-logo.png" />
|
||||
<link rel="stylesheet" href="/src/index.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Jazz Chat Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/app.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
56
examples/chat-passphrase/job-template.nomad
Normal file
56
examples/chat-passphrase/job-template.nomad
Normal file
@@ -0,0 +1,56 @@
|
||||
job "chat$BRANCH_SUFFIX" {
|
||||
region = "global"
|
||||
datacenters = ["*"]
|
||||
|
||||
group "static" {
|
||||
count = 4
|
||||
|
||||
network {
|
||||
port "http" {
|
||||
to = 80
|
||||
}
|
||||
}
|
||||
|
||||
constraint {
|
||||
attribute = "${node.class}"
|
||||
operator = "="
|
||||
value = "mesh"
|
||||
}
|
||||
|
||||
spread {
|
||||
attribute = "${node.datacenter}"
|
||||
weight = 100
|
||||
}
|
||||
|
||||
constraint {
|
||||
distinct_hosts = true
|
||||
}
|
||||
|
||||
task "server" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "$DOCKER_TAG"
|
||||
ports = ["http"]
|
||||
|
||||
auth = {
|
||||
username = "$DOCKER_USER"
|
||||
password = "$DOCKER_PASSWORD"
|
||||
}
|
||||
}
|
||||
|
||||
service {
|
||||
tags = ["public"]
|
||||
name = "chat$BRANCH_SUFFIX"
|
||||
port = "http"
|
||||
provider = "consul"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 50 # MHz
|
||||
memory = 50 # MB
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# deploy bump 4
|
||||
48
examples/chat-passphrase/package.json
Normal file
48
examples/chat-passphrase/package.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "jazz-example-chat-passphrase",
|
||||
"private": true,
|
||||
"version": "0.0.47",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@radix-ui/react-toast": "^1.1.4",
|
||||
"@types/qrcode": "^1.5.1",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"hash-slash": "^0.1.3",
|
||||
"jazz-react": "^0.5.0",
|
||||
"jazz-react-auth-passphrase": "^0.5.1",
|
||||
"lucide-react": "^0.274.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router": "^6.16.0",
|
||||
"react-router-dom": "^6.16.0",
|
||||
"react-use": "^17.4.0",
|
||||
"tailwind-merge": "^1.14.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"uniqolor": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.15",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.3",
|
||||
"postcss": "^8.4.27",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^4.4.5"
|
||||
}
|
||||
}
|
||||
6
examples/chat-passphrase/postcss.config.js
Normal file
6
examples/chat-passphrase/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
BIN
examples/chat-passphrase/public/jazz-logo.png
Normal file
BIN
examples/chat-passphrase/public/jazz-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
45
examples/chat-passphrase/src/app.tsx
Normal file
45
examples/chat-passphrase/src/app.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import { WithJazz, useJazz } from 'jazz-react';
|
||||
import { PassphraseAuth, PassphraseAuthBasicUI } from 'jazz-react-auth-passphrase';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { HashRoute } from 'hash-slash';
|
||||
import { ChatWindow } from './chatWindow.tsx';
|
||||
import { Chat } from './dataModel.ts';
|
||||
|
||||
import {wordlist} from '@scure/bip39/wordlists/english';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<WithJazz
|
||||
auth={PassphraseAuth({
|
||||
appName: 'Jazz Chat Example',
|
||||
wordlist,
|
||||
Component: PassphraseAuthBasicUI
|
||||
})}
|
||||
apiKey="api_z9d034j3t34ht034ir"
|
||||
>
|
||||
<App />
|
||||
</WithJazz>,
|
||||
);
|
||||
|
||||
function App() {
|
||||
return <div className='flex flex-col items-center justify-between w-screen h-screen p-2 dark:bg-black dark:text-white'>
|
||||
<button onClick={useJazz().logOut} className='rounded mb-5 px-2 py-1 bg-stone-200 dark:bg-stone-800 dark:text-white self-end'>
|
||||
Log Out
|
||||
</button>
|
||||
{HashRoute({
|
||||
'/': <Home />,
|
||||
'/chat/:id': (id) => <ChatWindow chatId={id as Chat['id']} />,
|
||||
}, { reportToParentFrame: true })}
|
||||
</div>
|
||||
}
|
||||
|
||||
function Home() {
|
||||
const { me } = useJazz();
|
||||
return <button className='rounded py-2 px-4 bg-stone-200 dark:bg-stone-800 dark:text-white my-auto'
|
||||
onClick={() => {
|
||||
const group = me.createGroup().addMember('everyone', 'writer');
|
||||
const chat = group.createList<Chat>();
|
||||
location.hash = '/chat/' + chat.id;
|
||||
}}>
|
||||
Create New Chat
|
||||
</button>
|
||||
}
|
||||
43
examples/chat-passphrase/src/chatWindow.tsx
Normal file
43
examples/chat-passphrase/src/chatWindow.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { useAutoSub } from 'jazz-react';
|
||||
import { Chat, Message } from './dataModel.ts';
|
||||
|
||||
export function ChatWindow(props: { chatId: Chat['id'] }) {
|
||||
const chat = useAutoSub(props.chatId);
|
||||
|
||||
return chat ? <div className='w-full max-w-xl h-full flex flex-col items-stretch'>
|
||||
{
|
||||
chat.map((msg, i) => (
|
||||
<ChatBubble key={msg?.id}
|
||||
text={msg?.text}
|
||||
by={chat.meta.edits[i].by?.profile?.name}
|
||||
byMe={chat.meta.edits[i].by?.isMe}
|
||||
at={chat.meta.edits[i].at} />
|
||||
))
|
||||
}
|
||||
<ChatInput onSubmit={(text) => {
|
||||
const msg = chat.meta.group.createMap<Message>({ text });
|
||||
chat.append(msg.id);
|
||||
}}/>
|
||||
</div> : <div>Loading...</div>;
|
||||
}
|
||||
|
||||
function ChatBubble(props: { text?: string, by?: string, at?: Date, byMe?: boolean }) {
|
||||
return <div className={`${props.byMe ? 'items-end' : 'items-start'} flex flex-col`}>
|
||||
<div className='rounded-xl bg-stone-100 dark:bg-stone-700 dark:text-white py-2 px-4 mt-2 min-w-[5rem]'>
|
||||
{ props.text }
|
||||
</div>
|
||||
<div className='text-xs text-neutral-500 ml-2'>
|
||||
{ props.by } { props.at?.getHours() }:{ props.at?.getMinutes() }
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function ChatInput(props: { onSubmit: (text: string) => void }) {
|
||||
return <input className='rounded p-2 border mt-auto dark:bg-black dark:text-white dark:border-stone-700'
|
||||
placeholder='Type a message and press Enter'
|
||||
onKeyDown={({ key, currentTarget: input }) => {
|
||||
if (key !== 'Enter' || !input.value) return;
|
||||
props.onSubmit(input.value);
|
||||
input.value = '';
|
||||
}}/>
|
||||
}
|
||||
4
examples/chat-passphrase/src/dataModel.ts
Normal file
4
examples/chat-passphrase/src/dataModel.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { CoMap, CoList } from 'cojson';
|
||||
|
||||
export type Chat = CoList<Message['id']>;
|
||||
export type Message = CoMap<{ text: string }>;
|
||||
78
examples/chat-passphrase/src/index.css
Normal file
78
examples/chat-passphrase/src/index.css
Normal file
@@ -0,0 +1,78 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 20 14.3% 4.1%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 20 14.3% 4.1%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 20 14.3% 4.1%;
|
||||
|
||||
--primary: 24 9.8% 10%;
|
||||
--primary-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--secondary: 60 4.8% 95.9%;
|
||||
--secondary-foreground: 24 9.8% 10%;
|
||||
|
||||
--muted: 60 4.8% 95.9%;
|
||||
--muted-foreground: 25 5.3% 44.7%;
|
||||
|
||||
--accent: 60 4.8% 95.9%;
|
||||
--accent-foreground: 24 9.8% 10%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--border: 20 5.9% 90%;
|
||||
--input: 20 5.9% 90%;
|
||||
--ring: 20 14.3% 4.1%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 20 14.3% 4.1%;
|
||||
--foreground: 60 9.1% 97.8%;
|
||||
|
||||
--card: 20 14.3% 4.1%;
|
||||
--card-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--popover: 20 14.3% 4.1%;
|
||||
--popover-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--primary: 60 9.1% 97.8%;
|
||||
--primary-foreground: 24 9.8% 10%;
|
||||
|
||||
--secondary: 12 6.5% 15.1%;
|
||||
--secondary-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--muted: 12 6.5% 15.1%;
|
||||
--muted-foreground: 24 5.4% 63.9%;
|
||||
|
||||
--accent: 12 6.5% 15.1%;
|
||||
--accent-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 60 9.1% 97.8%;
|
||||
|
||||
--border: 12 6.5% 15.1%;
|
||||
--input: 12 6.5% 15.1%;
|
||||
--ring: 24 5.7% 82.9%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
1
examples/chat-passphrase/src/vite-env.d.ts
vendored
Normal file
1
examples/chat-passphrase/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
75
examples/chat-passphrase/tailwind.config.js
Normal file
75
examples/chat-passphrase/tailwind.config.js
Normal file
@@ -0,0 +1,75 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
'./pages/**/*.{ts,tsx}',
|
||||
'./components/**/*.{ts,tsx}',
|
||||
'./app/**/*.{ts,tsx}',
|
||||
'./src/**/*.{ts,tsx}',
|
||||
],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: "2rem",
|
||||
screens: {
|
||||
"2xl": "1400px",
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
background: "hsl(var(--background))",
|
||||
foreground: "hsl(var(--foreground))",
|
||||
primary: {
|
||||
DEFAULT: "hsl(var(--primary))",
|
||||
foreground: "hsl(var(--primary-foreground))",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "hsl(var(--secondary))",
|
||||
foreground: "hsl(var(--secondary-foreground))",
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "hsl(var(--destructive))",
|
||||
foreground: "hsl(var(--destructive-foreground))",
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "hsl(var(--muted))",
|
||||
foreground: "hsl(var(--muted-foreground))",
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "hsl(var(--accent))",
|
||||
foreground: "hsl(var(--accent-foreground))",
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: "hsl(var(--popover))",
|
||||
foreground: "hsl(var(--popover-foreground))",
|
||||
},
|
||||
card: {
|
||||
DEFAULT: "hsl(var(--card))",
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
sm: "calc(var(--radius) - 4px)",
|
||||
},
|
||||
keyframes: {
|
||||
"accordion-down": {
|
||||
from: { height: 0 },
|
||||
to: { height: "var(--radix-accordion-content-height)" },
|
||||
},
|
||||
"accordion-up": {
|
||||
from: { height: "var(--radix-accordion-content-height)" },
|
||||
to: { height: 0 },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
}
|
||||
29
examples/chat-passphrase/tsconfig.json
Normal file
29
examples/chat-passphrase/tsconfig.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
10
examples/chat-passphrase/tsconfig.node.json
Normal file
10
examples/chat-passphrase/tsconfig.node.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
16
examples/chat-passphrase/vite.config.ts
Normal file
16
examples/chat-passphrase/vite.config.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react-swc'
|
||||
import path from "path";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
minify: false
|
||||
}
|
||||
})
|
||||
24
examples/counter-js-auth0/.gitignore
vendored
Normal file
24
examples/counter-js-auth0/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
4
examples/counter-js-auth0/Dockerfile
Normal file
4
examples/counter-js-auth0/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
||||
FROM caddy:2.7.3-alpine
|
||||
LABEL org.opencontainers.image.source="https://github.com/gardencmp/jazz"
|
||||
|
||||
COPY ./dist /usr/share/caddy/
|
||||
16
examples/counter-js-auth0/index.html
Normal file
16
examples/counter-js-auth0/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Jazz Counter Example (Auth0)</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">
|
||||
<div id="count">...initializing</div>
|
||||
<button id="increment">Increment</button>
|
||||
<button id="login">Login</button>
|
||||
</div>
|
||||
<script type="module" src="/index.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
113
examples/counter-js-auth0/index.ts
Normal file
113
examples/counter-js-auth0/index.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import * as auth0 from "@auth0/auth0-spa-js";
|
||||
import { Account, CoID, CoList, CoMap, Profile } from "cojson";
|
||||
import {
|
||||
ResolvedAccount,
|
||||
autoSub,
|
||||
autoSubResolution,
|
||||
createBrowserNode,
|
||||
} from "jazz-browser";
|
||||
import { BrowserAuth0 } from "jazz-browser-auth0";
|
||||
|
||||
const auth0options = {
|
||||
domain: "dev-12uyj8w4t4yjzkwa.us.auth0.com",
|
||||
clientId: "TcYtq9an3PDyInQJvD1k8PtqupYG4PnA",
|
||||
};
|
||||
|
||||
const authorizationParams = {
|
||||
redirect_uri: window.location.origin,
|
||||
audience: `https://${auth0options.domain}/api/v2/`,
|
||||
scope: "read:current_user update:current_user_metadata",
|
||||
};
|
||||
|
||||
window.onload = async () => {
|
||||
const auth0Client = await auth0.createAuth0Client(auth0options);
|
||||
|
||||
const query = window.location.search;
|
||||
if (query.includes("code=") && query.includes("state=")) {
|
||||
await auth0Client.handleRedirectCallback();
|
||||
window.history.replaceState({}, document.title, "/");
|
||||
} else {
|
||||
document
|
||||
.getElementById("login")
|
||||
?.addEventListener("click", async () => {
|
||||
await auth0Client.loginWithRedirect({
|
||||
authorizationParams,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!(await auth0Client.isAuthenticated())) {
|
||||
return;
|
||||
}
|
||||
|
||||
let accessToken: string | undefined;
|
||||
try {
|
||||
accessToken = await auth0Client.getTokenSilently({
|
||||
authorizationParams,
|
||||
});
|
||||
} catch (e) {
|
||||
alert(
|
||||
"Failed to get access token silently, creating popup - this should only happen on localhost. Otherwise, check that allowed callback URLs are set correctly."
|
||||
);
|
||||
accessToken = await auth0Client.getTokenWithPopup({
|
||||
authorizationParams,
|
||||
});
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
throw new Error("No access token");
|
||||
}
|
||||
|
||||
const { node, done } = await createBrowserNode({
|
||||
auth: new BrowserAuth0(
|
||||
{
|
||||
domain: auth0options.domain,
|
||||
clientID: auth0options.clientId,
|
||||
accessToken,
|
||||
},
|
||||
auth0options.domain,
|
||||
"jazz-browser-auth0-example"
|
||||
),
|
||||
migration: (account) => {
|
||||
if (!account.get("root")) {
|
||||
account.set(
|
||||
"root",
|
||||
account.createMap({
|
||||
countIncrements: account.createList([]).id,
|
||||
}).id
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
autoSub<Account<Profile, CoMap<{ countIncrements: CoID<CoList<number>> }>>>(
|
||||
"me",
|
||||
node,
|
||||
(me) => {
|
||||
if (me?.root?.countIncrements) {
|
||||
document.getElementById("count")!.innerText =
|
||||
me.root.countIncrements.reduce((sum, inc) => sum + inc, 0) +
|
||||
"";
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const increments = await autoSubResolution(
|
||||
"me",
|
||||
(
|
||||
me: ResolvedAccount<
|
||||
Account<
|
||||
Profile,
|
||||
CoMap<{ countIncrements: CoID<CoList<number>> }>
|
||||
>
|
||||
>
|
||||
) => {
|
||||
return me?.root?.countIncrements;
|
||||
},
|
||||
node
|
||||
);
|
||||
|
||||
document.getElementById("increment")!.addEventListener("click", () => {
|
||||
increments.append(1);
|
||||
});
|
||||
};
|
||||
56
examples/counter-js-auth0/job-template.nomad
Normal file
56
examples/counter-js-auth0/job-template.nomad
Normal file
@@ -0,0 +1,56 @@
|
||||
job "counter-js-auth0$BRANCH_SUFFIX" {
|
||||
region = "global"
|
||||
datacenters = ["*"]
|
||||
|
||||
group "static" {
|
||||
count = 4
|
||||
|
||||
network {
|
||||
port "http" {
|
||||
to = 80
|
||||
}
|
||||
}
|
||||
|
||||
constraint {
|
||||
attribute = "${node.class}"
|
||||
operator = "="
|
||||
value = "mesh"
|
||||
}
|
||||
|
||||
spread {
|
||||
attribute = "${node.datacenter}"
|
||||
weight = 100
|
||||
}
|
||||
|
||||
constraint {
|
||||
distinct_hosts = true
|
||||
}
|
||||
|
||||
task "server" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "$DOCKER_TAG"
|
||||
ports = ["http"]
|
||||
|
||||
auth = {
|
||||
username = "$DOCKER_USER"
|
||||
password = "$DOCKER_PASSWORD"
|
||||
}
|
||||
}
|
||||
|
||||
service {
|
||||
tags = ["public"]
|
||||
name = "counter-js-auth0$BRANCH_SUFFIX"
|
||||
port = "http"
|
||||
provider = "consul"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 50 # MHz
|
||||
memory = 50 # MB
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# deploy bump 4
|
||||
22
examples/counter-js-auth0/package.json
Normal file
22
examples/counter-js-auth0/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "counter-js-auth0",
|
||||
"private": true,
|
||||
"version": "0.0.46",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth0/auth0-spa-js": "^2.1.2",
|
||||
"jazz-browser": "^0.6.0",
|
||||
"jazz-browser-auth0": "^0.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^4.4.5"
|
||||
}
|
||||
}
|
||||
29
examples/counter-js-auth0/tsconfig.json
Normal file
29
examples/counter-js-auth0/tsconfig.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
10
examples/counter-js-auth0/tsconfig.node.json
Normal file
10
examples/counter-js-auth0/tsconfig.node.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
16
examples/counter-js-auth0/vite.config.ts
Normal file
16
examples/counter-js-auth0/vite.config.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react-swc'
|
||||
import path from "path";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
minify: false
|
||||
}
|
||||
})
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -49,7 +49,7 @@ export default function RootLayout({
|
||||
mainLogo={<JazzLogo className="w-24" />}
|
||||
items={[
|
||||
{ title: "Toolkit", href: "/" },
|
||||
{ title: "Global Mesh", href: "/mesh" },
|
||||
{ title: "Mesh / Pricing", href: "/mesh" },
|
||||
{
|
||||
title: "Docs & Guides",
|
||||
href: "https://github.com/gardencmp/jazz/blob/main/DOCS.md",
|
||||
248
homepage/app/mesh/page.mdx
Normal file
248
homepage/app/mesh/page.mdx
Normal file
@@ -0,0 +1,248 @@
|
||||
import { Slogan, Grid, GridCard, GridItem, ComingSoonBadge } from '@/components/forMdx';
|
||||
import { fmtPrice, pricePer1MtxSyncedOut, pricePerTxSyncedOut, pricePer1MtxStored, pricePerTxStored } from '@/components/pricing';
|
||||
|
||||
export const metadata = {
|
||||
title: "jazz - Jazz Mesh",
|
||||
description: "Serverless sync & storage for Jazz apps.",
|
||||
};
|
||||
|
||||
# Jazz Mesh
|
||||
|
||||
<Slogan>Serverless sync & storage for Jazz apps.</Slogan>
|
||||
|
||||
Real-time sync and storage infrastructure that scales up to millions of users.<br/>
|
||||
Pricing that scales down to zero.
|
||||
|
||||
## The first Collaboration Delivery Network
|
||||
|
||||
<Slogan small>Build demanding apps with distributed state, backed by a new kind of cloud.</Slogan>
|
||||
|
||||
<Grid>
|
||||
<GridCard>
|
||||
#### Optimal mesh routing.
|
||||
|
||||
Get ultra-low latency between any group of users with our decentralized mesh interconnect.
|
||||
</GridCard>
|
||||
<GridCard>
|
||||
#### Smart caching.
|
||||
|
||||
Give users instant load times, with their latest data state always cached close to them.
|
||||
</GridCard>
|
||||
<GridCard>
|
||||
#### Blob storage & media streaming.
|
||||
|
||||
Store files and media streams as idiomatic `CoValues` without S3.
|
||||
</GridCard>
|
||||
</Grid>
|
||||
|
||||
## Pricing
|
||||
|
||||
<Slogan small></Slogan>
|
||||
|
||||
<Grid>
|
||||
<GridCard>
|
||||
### Mesh Free
|
||||
<span className="text-2xl">$0</span>
|
||||
|
||||
- Unlimited projects
|
||||
- For individual developers
|
||||
- Low-latency sync
|
||||
- Egress/mo: 5 million ops <span className="text-xs">or 50GB blobs</span>
|
||||
- Storage: 2.5 million ops <span className="text-xs">or 25GB blobs</span>
|
||||
</GridCard>
|
||||
<GridCard>
|
||||
### Mesh Starter <ComingSoonBadge/>
|
||||
<span className="text-2xl">$9</span>/developer/mo
|
||||
|
||||
- Unlimited projects
|
||||
- Up to 3 developers
|
||||
- Low-latency sync
|
||||
- Egress/mo: 50 million ops <span className="text-xs">or 500GB blobs</span>
|
||||
- Storage: 25 million ops <span className="text-xs">or 250GB blobs</span>
|
||||
|
||||
<div className="text-xs">
|
||||
- Extra egress: {fmtPrice(10 * pricePer1MtxSyncedOut)} per 10 million ops or 100GB blobs
|
||||
- Extra storage: {fmtPrice(10 * pricePer1MtxStored)} per 10 million ops or 100GB blobs
|
||||
</div>
|
||||
</GridCard>
|
||||
<GridCard>
|
||||
### Mesh Pro <ComingSoonBadge/>
|
||||
<span className="text-2xl">$19</span>/developer/mo
|
||||
|
||||
- Unlimited projects
|
||||
- Up to 50 developers, SSO/SAML
|
||||
- Ultra-low-latency sync
|
||||
- Egress/mo: 100 million ops <span className="text-xs">or 1TB blobs</span>
|
||||
- Storage: 50 million ops <span className="text-xs">or 500GB blobs</span>
|
||||
|
||||
<div className="text-xs">
|
||||
- Extra egress: {fmtPrice(10 * pricePer1MtxSyncedOut)} per 10 million ops or 100GB blobs
|
||||
- Extra storage: {fmtPrice(10 * pricePer1MtxStored)} per 10 million ops or 100GB blobs
|
||||
</div>
|
||||
</GridCard>
|
||||
{/*<GridCard>
|
||||
### Mesh Enterprise <ComingSoonBadge/>
|
||||
|
||||
<span className="text-2xl">Custom</span>
|
||||
- Custom SLA
|
||||
- Custom cloud deployment
|
||||
- Dedicated support
|
||||
- Audit logs
|
||||
</GridCard>*/}
|
||||
</Grid>
|
||||
|
||||
An operation represents an **individual user action**, or **10KB of data** for blobs/streams.
|
||||
|
||||
|
||||
<Grid>
|
||||
<GridItem className="col-start-1">
|
||||
#### Egress:
|
||||
<div className="text-sm">
|
||||
- Operations sent out from Jazz Mesh, each counted once for every device it is synced out to.
|
||||
- Depending on cache behavior each op should only be synced out once per connection, ideally once per device requesting it.
|
||||
</div>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
#### Operations stored:
|
||||
<div className="text-sm">
|
||||
- Operations that are continuously persisted.
|
||||
- Includes backups, hot storage and edge caches.
|
||||
</div>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
|
||||
**Examples:**
|
||||
|
||||
The number of ops generated is highly app-specific and depends on user behaviour, but here are some examples:
|
||||
|
||||
<div className="text-sm">
|
||||
- **Session A: 4 users co-oping 10 pages of text, typing them out as individual character inserts:**
|
||||
- 3,000 inserts/page × 10 pages = 30,000 ops -> 30k ops stored
|
||||
- 30,000 ops, each synced out to 3 other users -> 90k ops egress (one-time)
|
||||
- **You could have ~50 such sessions/mo within Mesh Free** and you can keep storing ~80 such texts.
|
||||
- **You could have ~500 such sessions/mo within Mesh Starter included usage** and you can keep storing ~800 such texts.
|
||||
- **You could have ~1000 such sessions/mo within Mesh Pro included usage** and you can keep storing ~1600 such texts.
|
||||
- Each further such session would cost you about {fmtPrice(90000 * pricePerTxSyncedOut)} and {fmtPrice(30000 * pricePerTxStored)} per month to keep storing the text.
|
||||
- **Session B: 3 users collaborating on a canvas, moving shapes around at 10 FPS for 10s/min for 5 hours**
|
||||
- 3 users × 10 FPS × 10s/min × 60min/h × 5h = 90k ops -> 90k ops stored
|
||||
- 90k ops, each synced out to 2 other users -> 180k ops egress (one-time)
|
||||
- **You could have ~20 such sessions/mo within Mesh Free** and you can keep storing 20 such canvases.
|
||||
- **You could have ~250 such sessions/mo within Mesh Starter included usage** and you can keep storing 250 such canvases.
|
||||
- **You could have ~500 such sessions/mo within Mesh Pro included usage** and you can keep storing 500 such canvases.
|
||||
- Each further such session would cost you about {fmtPrice(180000 * pricePerTxSyncedOut)} and {fmtPrice(90000 * pricePerTxStored)} per month to keep storing the canvas.
|
||||
- **Session C: A livestreamer streaming video (1GB total) to 25 viewers (combined live & on-demand)**
|
||||
- 1GB = 100,000 ops (10KB each) -> 100k ops stored
|
||||
- 100,000 ops, each synced out to 25 viewers -> 2.5M ops egress (one-time)
|
||||
- **You could have ~2 such livestreams/mo within Mesh Free** and you can keep storing 25 such videos.
|
||||
- **You could have ~20 such livestreams/mo within Mesh Starter included usage** and you can keep storing 250 such videos.
|
||||
- **You could have ~40 such livestreams/mo within Mesh Pro included usage** and you can keep storing 500 such videos.
|
||||
- Each further such livestream would cost you about {fmtPrice(2500000 * pricePerTxSyncedOut)} and {fmtPrice(100000 * pricePerTxStored)} per month to keep storing the video.
|
||||
</div>
|
||||
|
||||
## Global Footprint
|
||||
|
||||
We're rapidly expanding our network of sync & storage nodes. This is our current best-effort coverage:
|
||||
|
||||
<Grid className="grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
|
||||
<GridItem>
|
||||
<div className="text-sm">
|
||||
**Under 50ms RTT**
|
||||
- Frankfurt
|
||||
- New York
|
||||
- Newark
|
||||
- North California
|
||||
- North Virginia
|
||||
- San Francisco
|
||||
- Singapore
|
||||
- Toronto
|
||||
</div>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<div className="text-sm">
|
||||
**Under 100ms RTT**
|
||||
- Amsterdam
|
||||
- Atlanta
|
||||
- London
|
||||
- Ohio
|
||||
- Paris
|
||||
</div>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<div className="text-sm">
|
||||
**Under 200ms RTT**
|
||||
- Bangalore
|
||||
- Dallas
|
||||
- Mumbai
|
||||
- Oregon
|
||||
|
||||
**Under 300ms RTT**
|
||||
- Seoul
|
||||
- Tokyo
|
||||
</div>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<div className="text-sm">
|
||||
**Under 400ms RTT**
|
||||
- Sao Paulo
|
||||
- Sydney
|
||||
|
||||
**Under 500ms RTT**
|
||||
- Cape Town
|
||||
</div>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
|
||||
### Enterprise
|
||||
|
||||
Custom deployment in the cloud, your private cloud, on-premises or hybrids?
|
||||
|
||||
SLAs and dedicated support? White-glove integration services?
|
||||
|
||||
Let's talk: <a href="mailto:hello@gcmp.io">hello@gcmp.io</a>
|
||||
|
||||
## Custom Deployment Scenarios
|
||||
|
||||
<Slogan>You can rely on Jazz Mesh. But you don't have to.</Slogan>
|
||||
|
||||
<p>Because Jazz is open-source, you can optionally run your own sync nodes — in a variety of setups.</p>
|
||||
|
||||
<Grid>
|
||||
<GridCard>
|
||||
#### Jazz Mesh + Data Backup Node.
|
||||
|
||||
<p className="no-prose text-base">Connect your users to Jazz Mesh for all its benefits, but also run and connect your own data backup node (just in case.)</p>
|
||||
|
||||
<div className="text-sm">
|
||||
Extra costs:
|
||||
- Instance costs for the backup node.
|
||||
- Moderate self-hosted storage costs.
|
||||
- Every op is additionally synced to your backup node and counted as synced out.
|
||||
</div>
|
||||
</GridCard>
|
||||
<GridCard>
|
||||
#### Jazz Mesh + DIY Mesh.
|
||||
|
||||
<p className="no-prose text-base">Connect your users to Jazz Mesh, or your own nodes as a lower-performance fallback. The two networks stay in constant sync.</p>
|
||||
|
||||
<div className="text-sm">
|
||||
Extra costs:
|
||||
- N × instance cost for your sync nodes.
|
||||
- Typically moderate self-hosted egress costs.
|
||||
- High self-hosted storage costs.
|
||||
- Every op is additionally synced to your DIY mesh and counted as synced out.
|
||||
</div>
|
||||
</GridCard>
|
||||
<GridCard>
|
||||
#### Completely DIY Mesh.
|
||||
|
||||
<p className="no-prose text-base">Build your own network of sync and storage nodes.
|
||||
Handle networking, security and backups yourself.</p>
|
||||
|
||||
<div className="text-sm">
|
||||
Costs:
|
||||
- N × instance cost for your sync nodes.
|
||||
- Very high self-hosted egress costs.
|
||||
- High self-hosted storage costs.
|
||||
</div>
|
||||
</GridCard>
|
||||
</Grid>
|
||||
@@ -34,7 +34,7 @@ Jazz is an open-source toolkit for building apps with **sync** & **secure collab
|
||||
|
||||
<h2 className="md:mt-24">Hard things are easy now</h2>
|
||||
|
||||
Jazz replaces APIs, DBs and message queues with **a single new abstraction: CoJSON**.
|
||||
Jazz replaces APIs, databases and message queues with **a single new abstraction: collaborative data**.
|
||||
|
||||
This means you get **built-in capabilities** that took best-in-class apps years to build:
|
||||
|
||||
@@ -71,20 +71,7 @@ This means you get **built-in capabilities** that took best-in-class apps years
|
||||
</Grid>
|
||||
</div>
|
||||
|
||||
## CoJSON
|
||||
<Slogan small>The collaborative core.</Slogan>
|
||||
|
||||
Jazz is built around **CoJSON,** a new abstraction for **sync** & **secure collaborative data.** And while it does all the heavy lifting...
|
||||
|
||||
- **multi-device co-editing**
|
||||
- **user identities & accounts**
|
||||
- **permissions** & **roles**
|
||||
- **sync** & **caching**
|
||||
- **persistence**
|
||||
|
||||
...its API couldn't be simpler: CoJSON makes collaboration and secure access control feel like **inherent properties of your data**.
|
||||
|
||||
### Collaborative Values
|
||||
## Collaborative Values
|
||||
|
||||
<Slogan small>Your new building blocks.</Slogan>
|
||||
|
||||
@@ -99,7 +86,7 @@ CoValues also **keep their full edit history,** including author metadata and po
|
||||
<div className="text-sm">
|
||||
- Collaborative key-value map
|
||||
- Possible values:
|
||||
- Immutable JSON & IDs of other CoValues
|
||||
- Immutable JSON & other CoValues
|
||||
</div>
|
||||
</GridCard>
|
||||
<GridCard>
|
||||
@@ -107,7 +94,7 @@ CoValues also **keep their full edit history,** including author metadata and po
|
||||
<div className="text-sm">
|
||||
- Collaborative ordered list
|
||||
- Possible items:
|
||||
- Immutable JSON & IDs of other CoValues
|
||||
- Immutable JSON & other CoValues
|
||||
</div>
|
||||
</GridCard>
|
||||
<GridItem className="col-span-full lg:col-span-1 mb-10 lg:ml-4 [&>p]:m-0 pt-4">
|
||||
@@ -139,7 +126,7 @@ A shocking amount of UI is text editing. CoJSON offers correct, versatile primit
|
||||
### `CoStream`
|
||||
<div className="text-sm">
|
||||
- Collection of independent per-user items streams:
|
||||
- Immutable JSON & IDs of other CoValues
|
||||
- Immutable JSON & other CoValues
|
||||
- Great for presence, reactions, polls, replies etc.
|
||||
</div>
|
||||
</GridCard>
|
||||
@@ -185,7 +172,7 @@ A simple API to define access control from anywhere, verifiably enforced by encr
|
||||
|
||||
## The Jazz Toolkit
|
||||
|
||||
<Slogan small>Idiomatic bindings for CoJSON, with batteries included.</Slogan>
|
||||
<Slogan small>A high-level toolkit for building apps around CoValues.</Slogan>
|
||||
|
||||
Supported environments:
|
||||
<div className="text-sm">
|
||||
@@ -264,15 +251,15 @@ Supported environments:
|
||||
</GridCard>
|
||||
</Grid>
|
||||
|
||||
## Global Mesh
|
||||
## Jazz Mesh
|
||||
|
||||
<Slogan small>Serverless sync & storage for Jazz apps</Slogan>
|
||||
|
||||
To give you sync & secure collaborative data instantly on a global scale, we're running Global Mesh. It works with any CoJSON-based app, requires no setup and has straightforward, scale-to-zero pricing.
|
||||
To give you sync and secure collaborative data instantly on a global scale, we're running Jazz Mesh. It works with any Jazz-based app, requires no setup and has straightforward, scale-to-zero pricing.
|
||||
|
||||
Global Mesh is currently free — and it's set up as the default sync & storage peer in Jazz, letting you start building multi-user apps with persistence right away, no backend needed.
|
||||
Jazz Mesh is currently free — and it's set up as the default sync & storage peer in Jazz, letting you start building multi-user apps with persistence right away, no backend needed.
|
||||
|
||||
<Link href="/mesh" target="_blank">Learn more about Global Mesh</Link>
|
||||
<Link href="/mesh" target="_blank">Learn more about Jazz Mesh</Link>
|
||||
|
||||
## Get Started
|
||||
|
||||
14
homepage/codeSamples/examples/chat/src/index.tsx
Normal file
14
homepage/codeSamples/examples/chat/src/index.tsx
Normal file
File diff suppressed because one or more lines are too long
@@ -1,11 +1,19 @@
|
||||
import { ComingSoonBadge, Grid, GridCard, GridItem } from "./forMdx";
|
||||
|
||||
export const pricePer1MtxSyncedOut = 1;
|
||||
export const pricePer1MtxStored = 2;
|
||||
export const pricePer1MtxSyncedOut = 0.1;
|
||||
export const pricePer1MtxStored = 0.2;
|
||||
|
||||
export const pricePerTxSyncedOut = pricePer1MtxSyncedOut / 1_000_000;
|
||||
export const pricePerTxStored = pricePer1MtxStored / 1_000_000;
|
||||
|
||||
export function fmtPrice(raw: number) {
|
||||
return raw.toLocaleString("en-US", {
|
||||
style: "currency",
|
||||
currency: "USD",
|
||||
maximumSignificantDigits: 2,
|
||||
});
|
||||
}
|
||||
|
||||
export function Pricing() {
|
||||
|
||||
const worstCaseBytesPerTx = 200_000;
|
||||
@@ -1,202 +0,0 @@
|
||||
import { Slogan, Grid, GridCard, GridItem, ComingSoonBadge } from '@/components/forMdx';
|
||||
import { pricePer1MtxSyncedOut, pricePerTxSyncedOut, pricePer1MtxStored, pricePerTxStored } from '@/components/pricing';
|
||||
|
||||
export const metadata = {
|
||||
title: "jazz - Global Mesh",
|
||||
description: "Serverless sync & storage for Jazz apps.",
|
||||
};
|
||||
|
||||
# Jazz Global Mesh
|
||||
|
||||
<Slogan>Serverless sync & storage for Jazz apps.</Slogan>
|
||||
|
||||
Real-time sync and storage infrastructure that scales up to millions of users.<br/>
|
||||
Pricing that scales down to zero.
|
||||
|
||||
## The first Collaboration Delivery Network
|
||||
|
||||
<Slogan small>Build demanding apps with distributed state, backed by a new kind of cloud.</Slogan>
|
||||
|
||||
<Grid>
|
||||
<GridCard>
|
||||
#### Optimal mesh routing.
|
||||
|
||||
Get ultra-low latency between any group of users with our decentralized mesh interconnect.
|
||||
</GridCard>
|
||||
<GridCard>
|
||||
#### Smart caching.
|
||||
|
||||
Give users instant load times, with their latest data state always cached close to them.
|
||||
</GridCard>
|
||||
<GridCard>
|
||||
#### Blob storage & media streaming.
|
||||
|
||||
Store files and media streams as idiomatic `CoValues` without S3.
|
||||
</GridCard>
|
||||
</Grid>
|
||||
|
||||
## Pricing
|
||||
|
||||
<Slogan small></Slogan>
|
||||
|
||||
### Free Tier
|
||||
<span className="text-lg font-medium bg-emerald-200 dark:bg-emerald-800 px-2 py-1 rounded">Until we implement billing all usage of Global Mesh is free!</span>
|
||||
<p className="text-sm">Later, any usage under $1/mo will be free.</p>
|
||||
|
||||
|
||||
|
||||
<Grid>
|
||||
<GridItem className="md:col-span-2">
|
||||
### Unlimited <ComingSoonBadge/>
|
||||
|
||||
|
||||
<div className="lg:text-2xl border rounded-lg px-1 py-3 text-center">${pricePer1MtxSyncedOut} <small>per 1M TXs synced out</small> + ${pricePer1MtxStored}<small>/mo per 1M TXs stored</small></div>
|
||||
|
||||
<p><small>$6/mo minimum usage</small></p>
|
||||
|
||||
A TX (transaction) represents an **individual user action**, or **up to 100KB of binary data**.
|
||||
</GridItem>
|
||||
|
||||
<GridItem className="col-start-1">
|
||||
#### Transactions synced out:
|
||||
<div className="text-sm">
|
||||
- Transactions sent out from Global Mesh, each counted once for every device it is synced out to.
|
||||
- Depending on cache behavior each transaction should only be synced out once per connection, ideally once per device requesting it.
|
||||
</div>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
#### Transactions stored:
|
||||
<div className="text-sm">
|
||||
- Transactions that are continuously persisted.
|
||||
- Counted per second.
|
||||
- Includes backups, hot storage and edge caches.
|
||||
</div>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
|
||||
**Examples:**
|
||||
|
||||
The number of transactions generated is highly app-specific and depends on user behaviour, but here are some examples:
|
||||
|
||||
<div className="text-sm">
|
||||
- 4 users co-editing 10 pages of text, typing them out as individual character inserts:
|
||||
- 3,000 inserts/page × 10 pages = 30,000 transactions
|
||||
- 30,000 transactions stored = ${30000 * pricePerTxStored} / mo
|
||||
- 3 × 30,000 transactions synced out = ${3 * 30000 * pricePerTxSyncedOut} one-time
|
||||
- 4 users collaborating on a canvas, moving shapes around at 10 FPS for 10s/min for 2h/day for a month
|
||||
- 4 users × 10 FPS × 10s/min × 60min/h * 2h/day × 30days = 1.44M transactions
|
||||
- 1.44M transactions stored = ${1440000 * pricePerTxStored} / mo = ${1440000 * pricePerTxStored / 4} / mo / user
|
||||
- 3 × 1.44M transactions synced out = ${(3 * 1440000 * pricePerTxSyncedOut).toLocaleString("en-US", { maximumSignificantDigits: 3, })} one-time = ${(3 * 1440000 * pricePerTxSyncedOut / 4).toLocaleString("en-US", { maximumSignificantDigits: 3, })} one-time / user
|
||||
- A livestreamer streaming video (1GB total) to 100 viewers (combined live & on-demand)
|
||||
- 1GB = 10,000 transactions (100KB each)
|
||||
- 10,000 transactions stored = ${10000 * pricePerTxStored} / mo (= ${10000 * 1000 * pricePerTxStored} per 1TB stored)
|
||||
- 100 × 10,000 transaction synced out = ${100 * 10000 * pricePerTxSyncedOut} one-time (= ${10000 * 1000 * pricePerTxSyncedOut} per 1TB egress)
|
||||
</div>
|
||||
|
||||
## Global Footprint
|
||||
|
||||
We're rapidly expanding our network of sync & storage nodes. This is our current best-effort coverage:
|
||||
|
||||
<Grid className="grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
|
||||
<GridItem>
|
||||
<div className="text-sm">
|
||||
**Under 50ms RTT**
|
||||
- Frankfurt
|
||||
- New York
|
||||
- Newark
|
||||
- North California
|
||||
- North Virginia
|
||||
- San Francisco
|
||||
- Singapore
|
||||
- Toronto
|
||||
</div>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<div className="text-sm">
|
||||
**Under 100ms RTT**
|
||||
- Amsterdam
|
||||
- Atlanta
|
||||
- London
|
||||
- Ohio
|
||||
- Paris
|
||||
</div>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<div className="text-sm">
|
||||
**Under 200ms RTT**
|
||||
- Bangalore
|
||||
- Dallas
|
||||
- Mumbai
|
||||
- Oregon
|
||||
|
||||
**Under 300ms RTT**
|
||||
- Seoul
|
||||
- Tokyo
|
||||
</div>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<div className="text-sm">
|
||||
**Under 400ms RTT**
|
||||
- Sao Paulo
|
||||
- Sydney
|
||||
|
||||
**Under 500ms RTT**
|
||||
- Cape Town
|
||||
</div>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
|
||||
### Enterprise
|
||||
|
||||
Custom deployment in the cloud, your private cloud, on-premises or hybrids?
|
||||
|
||||
SLAs and dedicated support? White-glove integration services?
|
||||
|
||||
Let's talk: <a href="mailto:hello@gcmp.io">hello@gcmp.io</a>
|
||||
|
||||
## Custom Deployment Scenarios
|
||||
|
||||
<Slogan>You can rely on Global Mesh. But you don't have to.</Slogan>
|
||||
|
||||
<p>Because Jazz is open-source, you can optionally run your own sync nodes — in a variety of setups.</p>
|
||||
|
||||
<Grid>
|
||||
<GridCard>
|
||||
#### Global Mesh + Data Backup Node.
|
||||
|
||||
<p className="no-prose text-base">Connect your users to Global Mesh for all its benefits, but also run and connect your own data backup node (just in case.)</p>
|
||||
|
||||
<div className="text-sm">
|
||||
Extra costs:
|
||||
- Instance costs for the backup node.
|
||||
- Moderate self-hosted storage costs.
|
||||
- Every transaction is additionally synced to your backup node and counted as synced out.
|
||||
</div>
|
||||
</GridCard>
|
||||
<GridCard>
|
||||
#### Global Mesh + DIY Mesh.
|
||||
|
||||
<p className="no-prose text-base">Connect your users to Global Mesh, or your own nodes as a lower-performance fallback. The two networks stay in constant sync.</p>
|
||||
|
||||
<div className="text-sm">
|
||||
Extra costs:
|
||||
- N × instance cost for your sync nodes.
|
||||
- Typically moderate self-hosted egress costs.
|
||||
- High self-hosted storage costs.
|
||||
- Every transaction is additionally synced to your DIY mesh and counted as synced out.
|
||||
</div>
|
||||
</GridCard>
|
||||
<GridCard>
|
||||
#### Completely DIY Mesh.
|
||||
|
||||
<p className="no-prose text-base">Build your own network of sync and storage nodes.
|
||||
Handle networking, security and backups yourself.</p>
|
||||
|
||||
<div className="text-sm">
|
||||
Costs:
|
||||
- N × instance cost for your sync nodes.
|
||||
- Very high self-hosted egress costs.
|
||||
- High self-hosted storage costs.
|
||||
</div>
|
||||
</GridCard>
|
||||
</Grid>
|
||||
@@ -22,14 +22,14 @@ await rm("./codeSamples", { recursive: true, force: true });
|
||||
(
|
||||
await Promise.all(
|
||||
(
|
||||
await readdir(path.join("../../", dir))
|
||||
await readdir(path.join("../", dir))
|
||||
).map(async (f) =>
|
||||
(f.endsWith(".ts") && f !== "vite-env.d.ts") ||
|
||||
f.endsWith(".tsx")
|
||||
? [
|
||||
f,
|
||||
await readFile(
|
||||
path.join("../../", dir, f),
|
||||
path.join("../", dir, f),
|
||||
"utf8"
|
||||
),
|
||||
]
|
||||
@@ -18,5 +18,6 @@
|
||||
"updated": "lerna updated --include-merged-tags",
|
||||
"publish-all": "yarn run gen-docs && lerna publish --include-merged-tags",
|
||||
"gen-docs": "ts-node generateDocs.ts"
|
||||
}
|
||||
},
|
||||
"version": "0.0.0"
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
228
packages/cojson-storage-indexeddb/src/syncPromises.ts
Normal file
228
packages/cojson-storage-indexeddb/src/syncPromises.ts
Normal file
@@ -0,0 +1,228 @@
|
||||
/* eslint @typescript-eslint/no-explicit-any: 0 */
|
||||
const isFunction = (func: any) => typeof func === 'function';
|
||||
|
||||
const isObject = (supposedObject: any) =>
|
||||
typeof supposedObject === 'object' &&
|
||||
supposedObject !== null &&
|
||||
!Array.isArray(supposedObject);
|
||||
|
||||
const isThenable = (obj: any) => isObject(obj) && isFunction(obj.then);
|
||||
|
||||
const identity = (val: any) => val;
|
||||
|
||||
export { isObject, isThenable, identity, isFunction };
|
||||
|
||||
enum States {
|
||||
PENDING = 'PENDING',
|
||||
RESOLVED = 'RESOLVED',
|
||||
REJECTED = 'REJECTED',
|
||||
}
|
||||
|
||||
interface Handler<T, U> {
|
||||
onSuccess: HandlerOnSuccess<T, U>;
|
||||
onFail: HandlerOnFail<U>;
|
||||
}
|
||||
|
||||
type HandlerOnSuccess<T, U = any> = (value: T) => U | Thenable<U>;
|
||||
type HandlerOnFail<U = any> = (reason: any) => U | Thenable<U>;
|
||||
type Finally<U> = () => U | Thenable<U>;
|
||||
|
||||
interface Thenable<T> {
|
||||
then<U>(
|
||||
onSuccess?: HandlerOnSuccess<T, U>,
|
||||
onFail?: HandlerOnFail<U>,
|
||||
): Thenable<U>;
|
||||
then<U>(
|
||||
onSuccess?: HandlerOnSuccess<T, U>,
|
||||
onFail?: (reason: any) => void,
|
||||
): Thenable<U>;
|
||||
}
|
||||
|
||||
type Resolve<R> = (value?: R | Thenable<R>) => void;
|
||||
type Reject = (value?: any) => void;
|
||||
|
||||
export class SyncPromise<T> {
|
||||
private state: States = States.PENDING;
|
||||
private handlers: Handler<T, any>[] = [];
|
||||
private value: T | any;
|
||||
|
||||
public constructor(callback: (resolve: Resolve<T>, reject: Reject) => void) {
|
||||
try {
|
||||
callback(this.resolve as Resolve<T>, this.reject);
|
||||
} catch (e) {
|
||||
this.reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
private resolve = (value: T) => {
|
||||
return this.setResult(value, States.RESOLVED);
|
||||
};
|
||||
|
||||
private reject = (reason: any) => {
|
||||
return this.setResult(reason, States.REJECTED);
|
||||
};
|
||||
|
||||
private setResult = (value: T | any, state: States) => {
|
||||
const set = () => {
|
||||
if (this.state !== States.PENDING) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isThenable(value)) {
|
||||
return (value as Thenable<T>).then(this.resolve, this.reject);
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
this.state = state;
|
||||
|
||||
return this.executeHandlers();
|
||||
};
|
||||
|
||||
set();
|
||||
};
|
||||
|
||||
private executeHandlers = () => {
|
||||
if (this.state === States.PENDING) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.handlers.forEach((handler) => {
|
||||
if (this.state === States.REJECTED) {
|
||||
return handler.onFail(this.value);
|
||||
}
|
||||
|
||||
return handler.onSuccess(this.value);
|
||||
});
|
||||
|
||||
this.handlers = [];
|
||||
};
|
||||
|
||||
private attachHandler = (handler: Handler<T, any>) => {
|
||||
this.handlers = [...this.handlers, handler];
|
||||
|
||||
this.executeHandlers();
|
||||
};
|
||||
|
||||
public then<U>(
|
||||
onSuccess: HandlerOnSuccess<T, U>,
|
||||
onFail?: HandlerOnFail<U>,
|
||||
) {
|
||||
return new SyncPromise<U>((resolve, reject) => {
|
||||
return this.attachHandler({
|
||||
onSuccess: (result) => {
|
||||
try {
|
||||
return resolve(onSuccess(result));
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
},
|
||||
onFail: (reason) => {
|
||||
if (!onFail) {
|
||||
return reject(reason);
|
||||
}
|
||||
|
||||
try {
|
||||
return resolve(onFail(reason));
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public catch<U>(onFail: HandlerOnFail<U>) {
|
||||
return this.then<U>(identity, onFail);
|
||||
}
|
||||
|
||||
// methods
|
||||
|
||||
public toString() {
|
||||
return `[object SyncPromise]`;
|
||||
}
|
||||
|
||||
public finally<U>(cb: Finally<U>) {
|
||||
return new SyncPromise<U>((resolve, reject) => {
|
||||
let val: U | any;
|
||||
let isRejected: boolean;
|
||||
|
||||
return this.then(
|
||||
(value) => {
|
||||
isRejected = false;
|
||||
val = value;
|
||||
return cb();
|
||||
},
|
||||
(reason) => {
|
||||
isRejected = true;
|
||||
val = reason;
|
||||
return cb();
|
||||
},
|
||||
).then(() => {
|
||||
if (isRejected) {
|
||||
return reject(val);
|
||||
}
|
||||
|
||||
return resolve(val);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public spread<U>(handler: (...args: any[]) => U) {
|
||||
return this.then<U>((collection) => {
|
||||
if (Array.isArray(collection)) {
|
||||
return handler(...collection);
|
||||
}
|
||||
|
||||
return handler(collection);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
|
||||
public static resolve<U = any>(value?: U | Thenable<U>) {
|
||||
return new SyncPromise<U>((resolve) => {
|
||||
return resolve(value);
|
||||
});
|
||||
}
|
||||
|
||||
public static reject<U>(reason?: any) {
|
||||
return new SyncPromise<U>((resolve, reject) => {
|
||||
return reject(reason);
|
||||
});
|
||||
}
|
||||
|
||||
public static all<U = any>(collection: (U | Thenable<U>)[]) {
|
||||
return new SyncPromise<U[]>((resolve, reject) => {
|
||||
if (!Array.isArray(collection)) {
|
||||
return reject(new TypeError('An array must be provided.'));
|
||||
}
|
||||
|
||||
if (collection.length === 0) {
|
||||
return resolve([]);
|
||||
}
|
||||
|
||||
let counter = collection.length;
|
||||
const resolvedCollection: U[] = [];
|
||||
|
||||
const tryResolve = (value: U, index: number) => {
|
||||
counter -= 1;
|
||||
resolvedCollection[index] = value;
|
||||
|
||||
if (counter !== 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return resolve(resolvedCollection);
|
||||
};
|
||||
|
||||
return collection.forEach((item, index) => {
|
||||
return SyncPromise.resolve(item)
|
||||
.then((value) => {
|
||||
return tryResolve(value, index);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,23 @@
|
||||
# cojson
|
||||
|
||||
## 0.6.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Implement passphrase based auth
|
||||
|
||||
## 0.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Add peersToLoadFrom for node creation as well
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Provide localNode to AccountMigrations
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"types": "src/index.ts",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.3",
|
||||
"devDependencies": {
|
||||
"@noble/curves": "^1.2.0",
|
||||
"@types/jest": "^29.5.3",
|
||||
|
||||
@@ -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
|
||||
@@ -169,5 +170,6 @@ export type AccountMigration<
|
||||
Meta extends AccountMeta = AccountMeta
|
||||
> = (
|
||||
account: ControlledAccount<P, R, Meta>,
|
||||
profile: P
|
||||
profile: P,
|
||||
localNode: LocalNode
|
||||
) => void | Promise<void>;
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
CoValueCore,
|
||||
newRandomSessionID,
|
||||
MAX_RECOMMENDED_TX_SIZE,
|
||||
idforHeader,
|
||||
} from "./coValueCore.js";
|
||||
import { accountOrAgentIDfromSessionID } from "./typeUtils/accountOrAgentIDfromSessionID.js";
|
||||
import { LocalNode } from "./localNode.js";
|
||||
@@ -36,7 +37,7 @@ import { Group, EVERYONE } from "./coValues/group.js";
|
||||
import type { Everyone } from "./coValues/group.js";
|
||||
import { base64URLtoBytes, bytesToBase64url } from "./base64url.js";
|
||||
import { parseJSON } from "./jsonStringify.js";
|
||||
import { Account, Profile } from "./coValues/account.js";
|
||||
import { Account, Profile, accountHeaderForInitialAgentSecret } from "./coValues/account.js";
|
||||
import { expectGroup } from "./typeUtils/expectGroup.js";
|
||||
import { isAccountID } from "./typeUtils/isAccountID.js";
|
||||
|
||||
@@ -80,6 +81,8 @@ export const cojsonInternals = {
|
||||
parseJSON,
|
||||
accountOrAgentIDfromSessionID,
|
||||
isAccountID,
|
||||
accountHeaderForInitialAgentSecret,
|
||||
idforHeader
|
||||
};
|
||||
|
||||
export {
|
||||
|
||||
@@ -74,10 +74,12 @@ export class LocalNode {
|
||||
Meta extends AccountMeta = AccountMeta
|
||||
>({
|
||||
name,
|
||||
peersToLoadFrom,
|
||||
migration,
|
||||
initialAgentSecret = newRandomAgentSecret(),
|
||||
}: {
|
||||
name: string;
|
||||
peersToLoadFrom?: Peer[];
|
||||
migration?: AccountMigration<P, R, Meta>;
|
||||
initialAgentSecret?: AgentSecret;
|
||||
}): Promise<{
|
||||
@@ -107,8 +109,14 @@ export class LocalNode {
|
||||
"After creating account"
|
||||
);
|
||||
|
||||
if (peersToLoadFrom) {
|
||||
for (const peer of peersToLoadFrom) {
|
||||
nodeWithAccount.syncManager.addPeer(peer);
|
||||
}
|
||||
}
|
||||
|
||||
if (migration) {
|
||||
await migration(accountOnNodeWithAccount, profile as P);
|
||||
await migration(accountOnNodeWithAccount, profile as P, nodeWithAccount);
|
||||
}
|
||||
|
||||
nodeWithAccount.account = new ControlledAccount(
|
||||
@@ -196,7 +204,8 @@ export class LocalNode {
|
||||
if (migration) {
|
||||
await migration(
|
||||
controlledAccount as ControlledAccount<P, R, Meta>,
|
||||
profile as P
|
||||
profile as P,
|
||||
node
|
||||
);
|
||||
node.account = new ControlledAccount(
|
||||
controlledAccount.core,
|
||||
|
||||
@@ -160,10 +160,8 @@ export function newStreamPair<T>(
|
||||
// make sure write resolves before corresponding read, but make sure writes are still in order
|
||||
await lastWritePromise;
|
||||
lastWritePromise = new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
enqueue(chunk);
|
||||
resolve();
|
||||
});
|
||||
enqueue(chunk);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -195,7 +195,7 @@ export class SyncManager {
|
||||
return await this.handleKnownState(msg, peer);
|
||||
}
|
||||
case "content":
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, 0));
|
||||
// await new Promise<void>((resolve) => setTimeout(resolve, 0));
|
||||
return await this.handleNewContent(msg, peer);
|
||||
case "done":
|
||||
return await this.handleUnsubscribe(msg);
|
||||
@@ -355,9 +355,9 @@ export class SyncManager {
|
||||
e
|
||||
);
|
||||
});
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, 0);
|
||||
});
|
||||
// await new Promise<void>((resolve) => {
|
||||
// setTimeout(resolve, 0);
|
||||
// });
|
||||
} catch (e) {
|
||||
console.error(
|
||||
new Date(),
|
||||
|
||||
@@ -288,9 +288,16 @@ export function autoSub(
|
||||
|
||||
if (!effectiveId) return () => {};
|
||||
|
||||
// const ctxId = Math.random().toString(16).slice(2);
|
||||
// let updateN = 0;
|
||||
|
||||
const context = new AutoSubContext(node, () => {
|
||||
const rootResolved = context.values[effectiveId]?.lastLoaded;
|
||||
// const n = updateN;
|
||||
// updateN++;
|
||||
// console.time("AutoSubContext.onUpdate " + n + " " + ctxId);
|
||||
callback(rootResolved);
|
||||
// console.timeEnd("AutoSubContext.onUpdate " + n + " " + ctxId);
|
||||
});
|
||||
|
||||
context.autoSub(effectiveId, [], "");
|
||||
|
||||
21
packages/jazz-browser-auth-passphrase/.eslintrc.cjs
Normal file
21
packages/jazz-browser-auth-passphrase/.eslintrc.cjs
Normal file
@@ -0,0 +1,21 @@
|
||||
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",
|
||||
},
|
||||
root: true,
|
||||
rules: {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
||||
],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
},
|
||||
};
|
||||
171
packages/jazz-browser-auth-passphrase/.gitignore
vendored
Normal file
171
packages/jazz-browser-auth-passphrase/.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-browser-auth-passphrase/.npmignore
Normal file
2
packages/jazz-browser-auth-passphrase/.npmignore
Normal file
@@ -0,0 +1,2 @@
|
||||
coverage
|
||||
node_modules
|
||||
33
packages/jazz-browser-auth-passphrase/CHANGELOG.md
Normal file
33
packages/jazz-browser-auth-passphrase/CHANGELOG.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# jazz-browser-auth-local
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Implement passphrase based auth
|
||||
|
||||
## 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
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-browser@0.5.0
|
||||
18
packages/jazz-browser-auth-passphrase/package.json
Normal file
18
packages/jazz-browser-auth-passphrase/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "jazz-browser-auth-passphrase",
|
||||
"version": "0.5.1",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@scure/bip39": "^1.2.2",
|
||||
"jazz-browser": "^0.6.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"build": "npm run lint && rm -rf ./dist && tsc --sourceMap --outDir dist",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"gitHead": "33c27053293b4801b968c61d5c4c989f93a67d13"
|
||||
}
|
||||
177
packages/jazz-browser-auth-passphrase/src/index.ts
Normal file
177
packages/jazz-browser-auth-passphrase/src/index.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
import {
|
||||
AccountID,
|
||||
AccountMigration,
|
||||
AgentSecret,
|
||||
cojsonInternals,
|
||||
LocalNode,
|
||||
Peer,
|
||||
} from "cojson";
|
||||
import { agentSecretFromSecretSeed } from "cojson/src/crypto";
|
||||
import { AuthProvider, SessionProvider } from "jazz-browser";
|
||||
|
||||
type SessionStorageData = {
|
||||
accountID: AccountID;
|
||||
accountSecret: AgentSecret;
|
||||
};
|
||||
|
||||
const sessionStorageKey = "jazz-logged-in-secret";
|
||||
|
||||
export interface BrowserPassphraseAuthDriver {
|
||||
onReady: (next: {
|
||||
signUp: (username: string, passphrase: string) => Promise<void>;
|
||||
logIn: (passphrase: string) => Promise<void>;
|
||||
}) => void;
|
||||
onSignedIn: (next: { logOut: () => void }) => void;
|
||||
}
|
||||
|
||||
export class BrowserPassphraseAuth implements AuthProvider {
|
||||
driver: BrowserPassphraseAuthDriver;
|
||||
appName: string;
|
||||
appHostname: string;
|
||||
wordlist: string[];
|
||||
|
||||
constructor(
|
||||
driver: BrowserPassphraseAuthDriver,
|
||||
wordlist: string[],
|
||||
appName: string,
|
||||
// TODO: is this a safe default?
|
||||
appHostname: string = window.location.hostname
|
||||
) {
|
||||
this.driver = driver;
|
||||
this.wordlist = wordlist;
|
||||
this.appName = appName;
|
||||
this.appHostname = appHostname;
|
||||
}
|
||||
|
||||
async createNode(
|
||||
getSessionFor: SessionProvider,
|
||||
initialPeers: Peer[],
|
||||
migration?: AccountMigration
|
||||
): Promise<LocalNode> {
|
||||
if (sessionStorage[sessionStorageKey]) {
|
||||
const sessionStorageData = JSON.parse(
|
||||
sessionStorage[sessionStorageKey]
|
||||
) as SessionStorageData;
|
||||
|
||||
const sessionID = await getSessionFor(sessionStorageData.accountID);
|
||||
|
||||
const node = await LocalNode.withLoadedAccount({
|
||||
accountID: sessionStorageData.accountID,
|
||||
accountSecret: sessionStorageData.accountSecret,
|
||||
sessionID,
|
||||
peersToLoadFrom: initialPeers,
|
||||
migration,
|
||||
});
|
||||
|
||||
this.driver.onSignedIn({ logOut });
|
||||
|
||||
return Promise.resolve(node);
|
||||
} else {
|
||||
const node = await new Promise<LocalNode>(
|
||||
(doneSigningUpOrLoggingIn) => {
|
||||
this.driver.onReady({
|
||||
signUp: async (username, passphrase) => {
|
||||
const node = await signUp(
|
||||
username,
|
||||
passphrase,
|
||||
this.wordlist,
|
||||
getSessionFor,
|
||||
this.appName,
|
||||
this.appHostname,
|
||||
migration
|
||||
);
|
||||
for (const peer of initialPeers) {
|
||||
node.syncManager.addPeer(peer);
|
||||
}
|
||||
doneSigningUpOrLoggingIn(node);
|
||||
this.driver.onSignedIn({ logOut });
|
||||
},
|
||||
logIn: async (passphrase: string) => {
|
||||
const node = await logIn(
|
||||
passphrase,
|
||||
this.wordlist,
|
||||
getSessionFor,
|
||||
this.appHostname,
|
||||
initialPeers,
|
||||
migration
|
||||
);
|
||||
doneSigningUpOrLoggingIn(node);
|
||||
this.driver.onSignedIn({ logOut });
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import * as bip39 from '@scure/bip39';
|
||||
|
||||
async function signUp(
|
||||
username: string,
|
||||
passphrase: string,
|
||||
wordlist: string[],
|
||||
getSessionFor: SessionProvider,
|
||||
appName: string,
|
||||
appHostname: string,
|
||||
migration?: AccountMigration
|
||||
): Promise<LocalNode> {
|
||||
const secretSeed = bip39.mnemonicToEntropy(passphrase, wordlist);
|
||||
|
||||
const { node, accountID, accountSecret } =
|
||||
await LocalNode.withNewlyCreatedAccount({
|
||||
name: username,
|
||||
initialAgentSecret: agentSecretFromSecretSeed(secretSeed),
|
||||
migration,
|
||||
});
|
||||
|
||||
sessionStorage[sessionStorageKey] = JSON.stringify({
|
||||
accountID,
|
||||
accountSecret,
|
||||
} satisfies SessionStorageData);
|
||||
|
||||
node.currentSessionID = await getSessionFor(accountID);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
async function logIn(
|
||||
passphrase: string,
|
||||
wordlist: string[],
|
||||
getSessionFor: SessionProvider,
|
||||
appHostname: string,
|
||||
initialPeers: Peer[],
|
||||
migration?: AccountMigration
|
||||
): Promise<LocalNode> {
|
||||
|
||||
const accountSecretSeed = bip39.mnemonicToEntropy(passphrase, wordlist);
|
||||
|
||||
const accountSecret = agentSecretFromSecretSeed(accountSecretSeed);
|
||||
|
||||
if (!accountSecret) {
|
||||
throw new Error("Invalid credential");
|
||||
}
|
||||
|
||||
const accountID = cojsonInternals.idforHeader(cojsonInternals.accountHeaderForInitialAgentSecret(accountSecret)) as AccountID;
|
||||
|
||||
sessionStorage[sessionStorageKey] = JSON.stringify({
|
||||
accountID,
|
||||
accountSecret,
|
||||
} satisfies SessionStorageData);
|
||||
|
||||
const node = await LocalNode.withLoadedAccount({
|
||||
accountID,
|
||||
accountSecret,
|
||||
sessionID: await getSessionFor(accountID),
|
||||
peersToLoadFrom: initialPeers,
|
||||
migration,
|
||||
});
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function logOut() {
|
||||
delete sessionStorage[sessionStorageKey];
|
||||
}
|
||||
16
packages/jazz-browser-auth-passphrase/tsconfig.json
Normal file
16
packages/jazz-browser-auth-passphrase/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"module": "esnext",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"strict": true,
|
||||
"jsx": "react",
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"esModuleInterop": true,
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
}
|
||||
83
packages/jazz-browser-auth-passphrase/yarn.lock
Normal file
83
packages/jazz-browser-auth-passphrase/yarn.lock
Normal file
@@ -0,0 +1,83 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@noble/ciphers@^0.1.3":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.1.4.tgz#96327dca147829ed9eee0d96cfdf7c57915765f0"
|
||||
integrity sha512-d3ZR8vGSpy3v/nllS+bD/OMN5UZqusWiQqkyj7AwzTnhXFH72pF5oB4Ach6DQ50g5kXxC28LdaYBEpsyv9KOUQ==
|
||||
|
||||
"@noble/curves@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d"
|
||||
integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==
|
||||
dependencies:
|
||||
"@noble/hashes" "1.3.1"
|
||||
|
||||
"@noble/hashes@1.3.1", "@noble/hashes@^1.3.1":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
|
||||
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
|
||||
|
||||
"@scure/base@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
|
||||
integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
|
||||
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
|
||||
|
||||
"@types/react@^18.2.19":
|
||||
version "18.2.19"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.19.tgz#f77cb2c8307368e624d464a25b9675fa35f95a8b"
|
||||
integrity sha512-e2S8wmY1ePfM517PqCG80CcE48Xs5k0pwJzuDZsfE8IZRRBfOMCF+XqnFxu6mWtyivum1MQm4aco+WIt6Coimw==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/scheduler@*":
|
||||
version "0.16.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
|
||||
integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==
|
||||
|
||||
cojson@^0.0.14:
|
||||
version "0.0.14"
|
||||
resolved "https://registry.yarnpkg.com/cojson/-/cojson-0.0.14.tgz#e7b190ade1efc20d6f0fa12411d7208cdc0f19f7"
|
||||
integrity sha512-TFenIGswEEhnZlCmq+B1NZPztjovZ72AjK1YkkZca54ZFbB1lAHdPt2hqqu/QBO24C9+6DtuoS2ixm6gbSBWCg==
|
||||
dependencies:
|
||||
"@noble/ciphers" "^0.1.3"
|
||||
"@noble/curves" "^1.1.0"
|
||||
"@noble/hashes" "^1.3.1"
|
||||
"@scure/base" "^1.1.1"
|
||||
fast-json-stable-stringify "^2.1.0"
|
||||
isomorphic-streams "https://github.com/sgwilym/isomorphic-streams.git#aa9394781bfc92f8d7c981be7daf8af4b4cd4fae"
|
||||
|
||||
csstype@^3.0.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
|
||||
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
||||
|
||||
fast-json-stable-stringify@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
||||
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
|
||||
|
||||
"isomorphic-streams@git+https://github.com/sgwilym/isomorphic-streams.git#aa9394781bfc92f8d7c981be7daf8af4b4cd4fae":
|
||||
version "1.0.3"
|
||||
resolved "git+https://github.com/sgwilym/isomorphic-streams.git#aa9394781bfc92f8d7c981be7daf8af4b4cd4fae"
|
||||
|
||||
jazz-react@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/jazz-react/-/jazz-react-0.0.6.tgz#53b0245720b10ec31ac8deba45fd8a052b313b06"
|
||||
integrity sha512-JlYTKUVPpuK3T7cLfk2YwHh3yH+2BPVSuWIQui35U52/gce+HmTMGolqFYGghWMVQtwclaZ0IoEbtuycPiADOQ==
|
||||
dependencies:
|
||||
cojson "^0.0.14"
|
||||
typescript "^5.1.6"
|
||||
|
||||
typescript@^5.1.6:
|
||||
version "5.1.6"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274"
|
||||
integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
|
||||
21
packages/jazz-browser-auth0/.eslintrc.cjs
Normal file
21
packages/jazz-browser-auth0/.eslintrc.cjs
Normal file
@@ -0,0 +1,21 @@
|
||||
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",
|
||||
},
|
||||
root: true,
|
||||
rules: {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
||||
],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
},
|
||||
};
|
||||
171
packages/jazz-browser-auth0/.gitignore
vendored
Normal file
171
packages/jazz-browser-auth0/.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-browser-auth0/.npmignore
Normal file
2
packages/jazz-browser-auth0/.npmignore
Normal file
@@ -0,0 +1,2 @@
|
||||
coverage
|
||||
node_modules
|
||||
39
packages/jazz-browser-auth0/CHANGELOG.md
Normal file
39
packages/jazz-browser-auth0/CHANGELOG.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# jazz-browser-auth-local
|
||||
|
||||
## 0.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix bug where user_metadata wasn't received
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Initial implementation
|
||||
|
||||
## 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
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-browser@0.5.0
|
||||
21
packages/jazz-browser-auth0/package.json
Normal file
21
packages/jazz-browser-auth0/package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "jazz-browser-auth0",
|
||||
"version": "0.6.2",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"auth0-js": "^9.23.3",
|
||||
"jazz-browser": "^0.6.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"build": "npm run lint && rm -rf ./dist && tsc --sourceMap --outDir dist",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"gitHead": "33c27053293b4801b968c61d5c4c989f93a67d13",
|
||||
"devDependencies": {
|
||||
"@types/auth0-js": "^9.21.5"
|
||||
}
|
||||
}
|
||||
123
packages/jazz-browser-auth0/src/index.ts
Normal file
123
packages/jazz-browser-auth0/src/index.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import {
|
||||
AccountID,
|
||||
AccountMigration,
|
||||
AgentSecret,
|
||||
LocalNode,
|
||||
Peer,
|
||||
} from "cojson";
|
||||
import { AuthProvider, SessionProvider } from "jazz-browser";
|
||||
import { Auth0UserProfile, Authentication, Management } from "auth0-js";
|
||||
|
||||
type CredentialData = {
|
||||
accountID: AccountID;
|
||||
accountSecret: AgentSecret;
|
||||
};
|
||||
|
||||
export class BrowserAuth0 implements AuthProvider {
|
||||
clientID: string;
|
||||
auth0domain: string;
|
||||
accessToken: string;
|
||||
|
||||
appName: string;
|
||||
appHostname: string;
|
||||
|
||||
/** Create or use Jazz account linked to an Auth0 account. The access token must have been retreived from a WebAuthn instance created with the following options:
|
||||
*
|
||||
* - `audience: https://{yourDomain}/api/v2/`
|
||||
* - `scope: "read:current_user update:current_user_metadata"`
|
||||
*/
|
||||
constructor(
|
||||
auth0Options: {
|
||||
clientID: string;
|
||||
domain: string;
|
||||
accessToken: string;
|
||||
},
|
||||
appName: string,
|
||||
// TODO: is this a safe default?
|
||||
appHostname: string = window.location.hostname
|
||||
) {
|
||||
this.clientID = auth0Options.clientID;
|
||||
this.auth0domain = auth0Options.domain;
|
||||
this.accessToken = auth0Options.accessToken;
|
||||
this.appName = appName;
|
||||
this.appHostname = appHostname;
|
||||
}
|
||||
|
||||
async createNode(
|
||||
getSessionFor: SessionProvider,
|
||||
initialPeers: Peer[],
|
||||
migration?: AccountMigration
|
||||
): Promise<LocalNode> {
|
||||
const auth0client = new Authentication({
|
||||
clientID: this.clientID,
|
||||
domain: this.auth0domain,
|
||||
});
|
||||
|
||||
const user = await new Promise<Auth0UserProfile>((resolve, reject) => {
|
||||
auth0client.userInfo(this.accessToken, (err, user) => {
|
||||
if (err) reject(err);
|
||||
else resolve(user);
|
||||
});
|
||||
});
|
||||
|
||||
const management = new Management({
|
||||
token: this.accessToken,
|
||||
domain: this.auth0domain,
|
||||
});
|
||||
|
||||
const metadata = await new Promise<Record<string, string>>(
|
||||
(resolve, reject) => {
|
||||
management.getUser(user.sub, (err, profile) => {
|
||||
if (err) reject(err);
|
||||
else resolve(profile.user_metadata);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const existingCredentialString = metadata?.["jazz_credential"];
|
||||
|
||||
if (existingCredentialString) {
|
||||
const existingCredential = JSON.parse(
|
||||
existingCredentialString
|
||||
) as CredentialData;
|
||||
|
||||
return LocalNode.withLoadedAccount({
|
||||
accountID: existingCredential.accountID,
|
||||
accountSecret: existingCredential.accountSecret,
|
||||
sessionID: await getSessionFor(existingCredential.accountID),
|
||||
peersToLoadFrom: initialPeers,
|
||||
migration,
|
||||
});
|
||||
} else {
|
||||
|
||||
|
||||
const username =
|
||||
user.nickname || user.name || user.email || user.sub;
|
||||
|
||||
const { node, accountID, accountSecret } =
|
||||
await LocalNode.withNewlyCreatedAccount({
|
||||
name: username,
|
||||
migration,
|
||||
peersToLoadFrom: initialPeers,
|
||||
});
|
||||
|
||||
await new Promise<void>((resolve, reject) =>
|
||||
management.patchUserMetadata(
|
||||
user.sub,
|
||||
{
|
||||
jazz_credential: JSON.stringify({
|
||||
accountID,
|
||||
accountSecret,
|
||||
} as CredentialData),
|
||||
},
|
||||
(err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
packages/jazz-browser-auth0/tsconfig.json
Normal file
16
packages/jazz-browser-auth0/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"module": "esnext",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"strict": true,
|
||||
"jsx": "react",
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"esModuleInterop": true,
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
}
|
||||
83
packages/jazz-browser-auth0/yarn.lock
Normal file
83
packages/jazz-browser-auth0/yarn.lock
Normal file
@@ -0,0 +1,83 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@noble/ciphers@^0.1.3":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.1.4.tgz#96327dca147829ed9eee0d96cfdf7c57915765f0"
|
||||
integrity sha512-d3ZR8vGSpy3v/nllS+bD/OMN5UZqusWiQqkyj7AwzTnhXFH72pF5oB4Ach6DQ50g5kXxC28LdaYBEpsyv9KOUQ==
|
||||
|
||||
"@noble/curves@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d"
|
||||
integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==
|
||||
dependencies:
|
||||
"@noble/hashes" "1.3.1"
|
||||
|
||||
"@noble/hashes@1.3.1", "@noble/hashes@^1.3.1":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
|
||||
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
|
||||
|
||||
"@scure/base@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
|
||||
integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
|
||||
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
|
||||
|
||||
"@types/react@^18.2.19":
|
||||
version "18.2.19"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.19.tgz#f77cb2c8307368e624d464a25b9675fa35f95a8b"
|
||||
integrity sha512-e2S8wmY1ePfM517PqCG80CcE48Xs5k0pwJzuDZsfE8IZRRBfOMCF+XqnFxu6mWtyivum1MQm4aco+WIt6Coimw==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/scheduler@*":
|
||||
version "0.16.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
|
||||
integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==
|
||||
|
||||
cojson@^0.0.14:
|
||||
version "0.0.14"
|
||||
resolved "https://registry.yarnpkg.com/cojson/-/cojson-0.0.14.tgz#e7b190ade1efc20d6f0fa12411d7208cdc0f19f7"
|
||||
integrity sha512-TFenIGswEEhnZlCmq+B1NZPztjovZ72AjK1YkkZca54ZFbB1lAHdPt2hqqu/QBO24C9+6DtuoS2ixm6gbSBWCg==
|
||||
dependencies:
|
||||
"@noble/ciphers" "^0.1.3"
|
||||
"@noble/curves" "^1.1.0"
|
||||
"@noble/hashes" "^1.3.1"
|
||||
"@scure/base" "^1.1.1"
|
||||
fast-json-stable-stringify "^2.1.0"
|
||||
isomorphic-streams "https://github.com/sgwilym/isomorphic-streams.git#aa9394781bfc92f8d7c981be7daf8af4b4cd4fae"
|
||||
|
||||
csstype@^3.0.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
|
||||
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
||||
|
||||
fast-json-stable-stringify@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
||||
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
|
||||
|
||||
"isomorphic-streams@git+https://github.com/sgwilym/isomorphic-streams.git#aa9394781bfc92f8d7c981be7daf8af4b4cd4fae":
|
||||
version "1.0.3"
|
||||
resolved "git+https://github.com/sgwilym/isomorphic-streams.git#aa9394781bfc92f8d7c981be7daf8af4b4cd4fae"
|
||||
|
||||
jazz-react@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/jazz-react/-/jazz-react-0.0.6.tgz#53b0245720b10ec31ac8deba45fd8a052b313b06"
|
||||
integrity sha512-JlYTKUVPpuK3T7cLfk2YwHh3yH+2BPVSuWIQui35U52/gce+HmTMGolqFYGghWMVQtwclaZ0IoEbtuycPiADOQ==
|
||||
dependencies:
|
||||
cojson "^0.0.14"
|
||||
typescript "^5.1.6"
|
||||
|
||||
typescript@^5.1.6:
|
||||
version "5.1.6"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274"
|
||||
integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
|
||||
@@ -1,5 +1,19 @@
|
||||
# jazz-autosub
|
||||
|
||||
## 0.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Add peersToLoadFrom for node creation as well
|
||||
- Updated dependencies
|
||||
- cojson@0.6.2
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix wrong import from cojson
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
"types": "src/index.ts",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.2",
|
||||
"dependencies": {
|
||||
"cojson": "^0.6.0",
|
||||
"cojson": "^0.6.2",
|
||||
"cojson-transport-nodejs-ws": "^0.5.1",
|
||||
"jazz-autosub": "^0.6.0"
|
||||
},
|
||||
|
||||
@@ -17,8 +17,8 @@ import {
|
||||
Profile,
|
||||
SessionID,
|
||||
cojsonReady,
|
||||
cojsonInternals
|
||||
} from "cojson";
|
||||
import { newRandomSessionID } from "cojson/src/coValueCore";
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
|
||||
if (!("crypto" in globalThis)) {
|
||||
@@ -72,7 +72,7 @@ export async function createOrResumeWorker<
|
||||
// TODO: locked sessions similar to browser
|
||||
const sessionID =
|
||||
process.env.JAZZ_WORKER_SESSION ||
|
||||
newRandomSessionID(existingCredentials.accountID);
|
||||
cojsonInternals.newRandomSessionID(existingCredentials.accountID);
|
||||
|
||||
console.log("Loading worker", existingCredentials.accountID);
|
||||
|
||||
@@ -94,13 +94,12 @@ export async function createOrResumeWorker<
|
||||
} else {
|
||||
const newWorker = await LocalNode.withNewlyCreatedAccount({
|
||||
name: workerName,
|
||||
peersToLoadFrom: [wsPeer],
|
||||
migration,
|
||||
});
|
||||
|
||||
localNode = newWorker.node;
|
||||
|
||||
localNode.syncManager.addPeer(wsPeer);
|
||||
|
||||
await credentialStorage.save(
|
||||
workerName,
|
||||
newWorker.accountID,
|
||||
|
||||
21
packages/jazz-react-auth-passphrase/.eslintrc.cjs
Normal file
21
packages/jazz-react-auth-passphrase/.eslintrc.cjs
Normal file
@@ -0,0 +1,21 @@
|
||||
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",
|
||||
},
|
||||
root: true,
|
||||
rules: {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
||||
],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
},
|
||||
};
|
||||
171
packages/jazz-react-auth-passphrase/.gitignore
vendored
Normal file
171
packages/jazz-react-auth-passphrase/.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-react-auth-passphrase/.npmignore
Normal file
2
packages/jazz-react-auth-passphrase/.npmignore
Normal file
@@ -0,0 +1,2 @@
|
||||
coverage
|
||||
node_modules
|
||||
25
packages/jazz-react-auth-passphrase/CHANGELOG.md
Normal file
25
packages/jazz-react-auth-passphrase/CHANGELOG.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# jazz-react-auth-local
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Implement passphrase based auth
|
||||
- Updated dependencies
|
||||
- jazz-browser-auth-passphrase@0.5.1
|
||||
|
||||
## 0.4.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-browser-auth-local@0.5.0
|
||||
- jazz-react@0.5.1
|
||||
|
||||
## 0.4.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-react@0.5.0
|
||||
- jazz-browser-auth-local@0.4.16
|
||||
24
packages/jazz-react-auth-passphrase/package.json
Normal file
24
packages/jazz-react-auth-passphrase/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "jazz-react-auth-passphrase",
|
||||
"version": "0.5.1",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.tsx",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jazz-browser-auth-passphrase": "^0.5.1",
|
||||
"jazz-react": "^0.5.1",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.19"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "17 - 18"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint src/**/*.tsx",
|
||||
"build": "npm run lint && rm -rf ./dist && tsc --sourceMap --outDir dist",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"gitHead": "33c27053293b4801b968c61d5c4c989f93a67d13"
|
||||
}
|
||||
234
packages/jazz-react-auth-passphrase/src/index.tsx
Normal file
234
packages/jazz-react-auth-passphrase/src/index.tsx
Normal file
@@ -0,0 +1,234 @@
|
||||
import { useMemo, useState, ReactNode } from "react";
|
||||
import { BrowserPassphraseAuth } from "jazz-browser-auth-passphrase";
|
||||
import { ReactAuthHook } from "jazz-react";
|
||||
|
||||
import { generateMnemonic } from "@scure/bip39";
|
||||
import { cojsonInternals } from "cojson";
|
||||
|
||||
export type PassphraseAuthComponent = (props: {
|
||||
loading: boolean;
|
||||
logIn: (passphrase: string) => void;
|
||||
signUp: (username: string, passphrase: string) => void;
|
||||
generateRandomPassphrase: () => string;
|
||||
}) => ReactNode;
|
||||
|
||||
export function PassphraseAuth({
|
||||
appName,
|
||||
appHostname,
|
||||
wordlist,
|
||||
Component = PassphraseAuthBasicUI,
|
||||
}: {
|
||||
appName: string;
|
||||
appHostname?: string;
|
||||
wordlist: string[];
|
||||
Component?: PassphraseAuthComponent;
|
||||
}): ReactAuthHook {
|
||||
return function useLocalAuth() {
|
||||
const [authState, setAuthState] = useState<
|
||||
| { state: "loading" }
|
||||
| {
|
||||
state: "ready";
|
||||
logIn: (passphrase: string) => void;
|
||||
signUp: (username: string, passphrase: string) => void;
|
||||
}
|
||||
| { state: "signedIn"; logOut: () => void }
|
||||
>({ state: "loading" });
|
||||
|
||||
const [logOutCounter, setLogOutCounter] = useState(0);
|
||||
|
||||
const auth = useMemo(() => {
|
||||
return new BrowserPassphraseAuth(
|
||||
{
|
||||
onReady(next) {
|
||||
setAuthState({
|
||||
state: "ready",
|
||||
logIn: next.logIn,
|
||||
signUp: next.signUp,
|
||||
});
|
||||
},
|
||||
onSignedIn(next) {
|
||||
setAuthState({
|
||||
state: "signedIn",
|
||||
logOut: () => {
|
||||
next.logOut();
|
||||
setAuthState({ state: "loading" });
|
||||
setLogOutCounter((c) => c + 1);
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
wordlist,
|
||||
appName,
|
||||
appHostname
|
||||
);
|
||||
}, [appName, appHostname, logOutCounter]);
|
||||
|
||||
const generateRandomPassphrase = () => {
|
||||
return generateMnemonic(
|
||||
wordlist,
|
||||
cojsonInternals.secretSeedLength * 8
|
||||
);
|
||||
};
|
||||
|
||||
const AuthUI =
|
||||
authState.state === "ready"
|
||||
? Component({
|
||||
loading: false,
|
||||
logIn: authState.logIn,
|
||||
signUp: authState.signUp,
|
||||
generateRandomPassphrase,
|
||||
})
|
||||
: Component({
|
||||
loading: false,
|
||||
logIn: () => {},
|
||||
signUp: (_) => {},
|
||||
generateRandomPassphrase,
|
||||
});
|
||||
|
||||
return {
|
||||
auth,
|
||||
AuthUI,
|
||||
logOut:
|
||||
authState.state === "signedIn" ? authState.logOut : undefined,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const PassphraseAuthBasicUI = ({
|
||||
logIn,
|
||||
signUp,
|
||||
generateRandomPassphrase,
|
||||
}: {
|
||||
logIn: (passphrase: string) => void;
|
||||
signUp: (username: string, passphrase: string) => void;
|
||||
generateRandomPassphrase: () => string;
|
||||
}) => {
|
||||
const [username, setUsername] = useState<string>("");
|
||||
const [passphrase, setPassphrase] = useState<string>("");
|
||||
const [loginPassphrase, setLoginPassphrase] = useState<string>("");
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: "30rem",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "2rem",
|
||||
}}
|
||||
>
|
||||
<form
|
||||
style={{
|
||||
width: "30rem",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "0.5rem",
|
||||
}}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
setPassphrase("");
|
||||
setUsername("");
|
||||
signUp(username, passphrase);
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", gap: "0.5rem" }}>
|
||||
<textarea
|
||||
placeholder="Passphrase"
|
||||
value={passphrase}
|
||||
onChange={(e) => setPassphrase(e.target.value)}
|
||||
style={{
|
||||
border: "2px solid #000",
|
||||
padding: "11px 8px",
|
||||
borderRadius: "6px",
|
||||
height: "7rem",
|
||||
flex: 1
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
setPassphrase(generateRandomPassphrase());
|
||||
e.preventDefault();
|
||||
}}
|
||||
style={{
|
||||
padding: "11px 8px",
|
||||
borderRadius: "6px",
|
||||
background: "#eee",
|
||||
}}
|
||||
>
|
||||
Random
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
placeholder="Display name"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
style={{
|
||||
border: "2px solid #000",
|
||||
padding: "11px 8px",
|
||||
borderRadius: "6px",
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="submit"
|
||||
value="Sign Up as new account"
|
||||
style={{
|
||||
background: "#000",
|
||||
color: "#fff",
|
||||
padding: "13px 5px",
|
||||
border: "none",
|
||||
borderRadius: "6px",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
/>
|
||||
</form>
|
||||
<div style={{textAlign: "center"}}>— or —</div>
|
||||
<form
|
||||
style={{
|
||||
width: "30rem",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "0.5rem",
|
||||
}}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
setLoginPassphrase("");
|
||||
logIn(loginPassphrase);
|
||||
}}
|
||||
>
|
||||
<textarea
|
||||
placeholder="Passphrase"
|
||||
value={loginPassphrase}
|
||||
onChange={(e) => setLoginPassphrase(e.target.value)}
|
||||
style={{
|
||||
border: "2px solid #000",
|
||||
padding: "11px 8px",
|
||||
borderRadius: "6px",
|
||||
height: "7rem",
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="submit"
|
||||
value="Log in as existing account"
|
||||
style={{
|
||||
background: "#000",
|
||||
color: "#fff",
|
||||
padding: "13px 5px",
|
||||
border: "none",
|
||||
borderRadius: "6px",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
16
packages/jazz-react-auth-passphrase/tsconfig.json
Normal file
16
packages/jazz-react-auth-passphrase/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"module": "esnext",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"strict": true,
|
||||
"jsx": "react-jsx",
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"esModuleInterop": true,
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
}
|
||||
83
packages/jazz-react-auth-passphrase/yarn.lock
Normal file
83
packages/jazz-react-auth-passphrase/yarn.lock
Normal file
@@ -0,0 +1,83 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@noble/ciphers@^0.1.3":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.1.4.tgz#96327dca147829ed9eee0d96cfdf7c57915765f0"
|
||||
integrity sha512-d3ZR8vGSpy3v/nllS+bD/OMN5UZqusWiQqkyj7AwzTnhXFH72pF5oB4Ach6DQ50g5kXxC28LdaYBEpsyv9KOUQ==
|
||||
|
||||
"@noble/curves@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d"
|
||||
integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==
|
||||
dependencies:
|
||||
"@noble/hashes" "1.3.1"
|
||||
|
||||
"@noble/hashes@1.3.1", "@noble/hashes@^1.3.1":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
|
||||
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
|
||||
|
||||
"@scure/base@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
|
||||
integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
|
||||
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
|
||||
|
||||
"@types/react@^18.2.19":
|
||||
version "18.2.19"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.19.tgz#f77cb2c8307368e624d464a25b9675fa35f95a8b"
|
||||
integrity sha512-e2S8wmY1ePfM517PqCG80CcE48Xs5k0pwJzuDZsfE8IZRRBfOMCF+XqnFxu6mWtyivum1MQm4aco+WIt6Coimw==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/scheduler@*":
|
||||
version "0.16.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
|
||||
integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==
|
||||
|
||||
cojson@^0.0.14:
|
||||
version "0.0.14"
|
||||
resolved "https://registry.yarnpkg.com/cojson/-/cojson-0.0.14.tgz#e7b190ade1efc20d6f0fa12411d7208cdc0f19f7"
|
||||
integrity sha512-TFenIGswEEhnZlCmq+B1NZPztjovZ72AjK1YkkZca54ZFbB1lAHdPt2hqqu/QBO24C9+6DtuoS2ixm6gbSBWCg==
|
||||
dependencies:
|
||||
"@noble/ciphers" "^0.1.3"
|
||||
"@noble/curves" "^1.1.0"
|
||||
"@noble/hashes" "^1.3.1"
|
||||
"@scure/base" "^1.1.1"
|
||||
fast-json-stable-stringify "^2.1.0"
|
||||
isomorphic-streams "https://github.com/sgwilym/isomorphic-streams.git#aa9394781bfc92f8d7c981be7daf8af4b4cd4fae"
|
||||
|
||||
csstype@^3.0.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
|
||||
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
||||
|
||||
fast-json-stable-stringify@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
||||
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
|
||||
|
||||
"isomorphic-streams@git+https://github.com/sgwilym/isomorphic-streams.git#aa9394781bfc92f8d7c981be7daf8af4b4cd4fae":
|
||||
version "1.0.3"
|
||||
resolved "git+https://github.com/sgwilym/isomorphic-streams.git#aa9394781bfc92f8d7c981be7daf8af4b4cd4fae"
|
||||
|
||||
jazz-react@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/jazz-react/-/jazz-react-0.0.6.tgz#53b0245720b10ec31ac8deba45fd8a052b313b06"
|
||||
integrity sha512-JlYTKUVPpuK3T7cLfk2YwHh3yH+2BPVSuWIQui35U52/gce+HmTMGolqFYGghWMVQtwclaZ0IoEbtuycPiADOQ==
|
||||
dependencies:
|
||||
cojson "^0.0.14"
|
||||
typescript "^5.1.6"
|
||||
|
||||
typescript@^5.1.6:
|
||||
version "5.1.6"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274"
|
||||
integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
|
||||
165
yarn.lock
165
yarn.lock
@@ -25,6 +25,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.10.1.tgz#70e45678f06c72fa2e350e8553ec4a4d72b92e06"
|
||||
integrity sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==
|
||||
|
||||
"@auth0/auth0-spa-js@^2.1.2":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@auth0/auth0-spa-js/-/auth0-spa-js-2.1.2.tgz#2217db13ce0feb480a190ed165b36681bd48633c"
|
||||
integrity sha512-xdA65Z/U7++Y7L9Uwh8Q8OVOs6qgFz+fb7GAzHFjpr1icO37B//xdzLXm7ZRgA19RWrsNe1nme3h896igJSvvw==
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.21.4", "@babel/code-frame@^7.22.10", "@babel/code-frame@^7.22.5":
|
||||
version "7.22.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3"
|
||||
@@ -1149,6 +1154,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
|
||||
integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==
|
||||
|
||||
"@noble/hashes@~1.3.2":
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699"
|
||||
integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||
@@ -1749,6 +1759,19 @@
|
||||
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
|
||||
integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
|
||||
|
||||
"@scure/base@~1.1.4":
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.5.tgz#1d85d17269fe97694b9c592552dd9e5e33552157"
|
||||
integrity sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==
|
||||
|
||||
"@scure/bip39@^1.2.2":
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.2.tgz#f3426813f4ced11a47489cbcf7294aa963966527"
|
||||
integrity sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==
|
||||
dependencies:
|
||||
"@noble/hashes" "~1.3.2"
|
||||
"@scure/base" "~1.1.4"
|
||||
|
||||
"@sigstore/bundle@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@sigstore/bundle/-/bundle-1.1.0.tgz#17f8d813b09348b16eeed66a8cf1c3d6bd3d04f1"
|
||||
@@ -1918,6 +1941,11 @@
|
||||
"@tufjs/canonical-json" "1.0.0"
|
||||
minimatch "^9.0.0"
|
||||
|
||||
"@types/auth0-js@^9.21.5":
|
||||
version "9.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/auth0-js/-/auth0-js-9.21.5.tgz#2adec936a48ddaaf761a9118a759dfcdecfa3316"
|
||||
integrity sha512-hQInFZkMPjrV8s49lefXBd6nym8+kdFxhdzzjlMAvy+7qHSk+TLCwUoMhvU6FQP3prj2j4NTtsufaqkUwiPgug==
|
||||
|
||||
"@types/babel__core@^7.1.14":
|
||||
version "7.20.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.1.tgz#916ecea274b0c776fec721e333e55762d3a9614b"
|
||||
@@ -2649,6 +2677,11 @@ arrify@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
|
||||
integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
|
||||
|
||||
asap@^2.0.0:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
|
||||
integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
|
||||
|
||||
assertion-error@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
|
||||
@@ -2671,6 +2704,20 @@ asynckit@^0.4.0:
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||
|
||||
auth0-js@^9.23.3:
|
||||
version "9.23.3"
|
||||
resolved "https://registry.yarnpkg.com/auth0-js/-/auth0-js-9.23.3.tgz#ec3c1e04eeb409fac780c84d32388dd80d3a52d7"
|
||||
integrity sha512-VVh3/1SiECWlwDU3XQ3Xhg40W9Buu18jYZYO93PEerApacm508v67SxBLKh5WeCGaqCUyPamU+NusguhWVn1Qw==
|
||||
dependencies:
|
||||
base64-js "^1.5.1"
|
||||
idtoken-verifier "^2.2.4"
|
||||
js-cookie "^2.2.0"
|
||||
minimist "^1.2.5"
|
||||
qs "^6.10.1"
|
||||
superagent "^7.1.5"
|
||||
url-join "^4.0.1"
|
||||
winchan "^0.2.2"
|
||||
|
||||
autoprefixer@^10.4.14:
|
||||
version "10.4.15"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.15.tgz#a1230f4aeb3636b89120b34a1f513e2f6834d530"
|
||||
@@ -2767,7 +2814,7 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
base64-js@^1.2.0, base64-js@^1.3.1:
|
||||
base64-js@^1.2.0, base64-js@^1.3.1, base64-js@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||
@@ -3303,6 +3350,11 @@ compare-func@^2.0.0:
|
||||
array-ify "^1.0.0"
|
||||
dot-prop "^5.1.0"
|
||||
|
||||
component-emitter@^1.3.0:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17"
|
||||
integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==
|
||||
|
||||
compress-commons@^4.1.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d"
|
||||
@@ -3416,6 +3468,11 @@ convert-source-map@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
|
||||
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
|
||||
|
||||
cookiejar@^2.1.3:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b"
|
||||
integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==
|
||||
|
||||
copy-to-clipboard@^3.3.1:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0"
|
||||
@@ -3481,6 +3538,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
crypto-js@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
|
||||
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
|
||||
|
||||
css-in-js-utils@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz#640ae6a33646d401fc720c54fc61c42cd76ae2bb"
|
||||
@@ -3736,6 +3798,14 @@ devtools-protocol@^0.0.1182435:
|
||||
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1182435.tgz#68155464f987d66390fae28b02782a1b9c153a0c"
|
||||
integrity sha512-EmlkWb62wSbQNE1gRZZsi4KZYRaF5Skpp183LhRU7+sadKR06O1dHCjZmFSEG6Kv7P6S/UYLxcY3NlYwqKM99w==
|
||||
|
||||
dezalgo@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81"
|
||||
integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==
|
||||
dependencies:
|
||||
asap "^2.0.0"
|
||||
wrappy "1"
|
||||
|
||||
didyoumean@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
|
||||
@@ -3985,6 +4055,11 @@ es-to-primitive@^1.2.1:
|
||||
is-date-object "^1.0.1"
|
||||
is-symbol "^1.0.2"
|
||||
|
||||
es6-promise@^4.2.8:
|
||||
version "4.2.8"
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
|
||||
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
|
||||
|
||||
esbuild-android-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
|
||||
@@ -4436,6 +4511,11 @@ fast-loops@^1.1.3:
|
||||
resolved "https://registry.yarnpkg.com/fast-loops/-/fast-loops-1.1.3.tgz#ce96adb86d07e7bf9b4822ab9c6fac9964981f75"
|
||||
integrity sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g==
|
||||
|
||||
fast-safe-stringify@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
|
||||
integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
|
||||
|
||||
fast-shallow-equal@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b"
|
||||
@@ -4606,6 +4686,16 @@ formdata-polyfill@^4.0.10:
|
||||
dependencies:
|
||||
fetch-blob "^3.1.2"
|
||||
|
||||
formidable@^2.0.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.1.2.tgz#fa973a2bec150e4ce7cac15589d7a25fc30ebd89"
|
||||
integrity sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==
|
||||
dependencies:
|
||||
dezalgo "^1.0.4"
|
||||
hexoid "^1.0.0"
|
||||
once "^1.4.0"
|
||||
qs "^6.11.0"
|
||||
|
||||
fraction.js@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
|
||||
@@ -5128,6 +5218,11 @@ hdr-histogram-percentiles-obj@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz#9409f4de0c2dda78e61de2d9d78b1e9f3cba283c"
|
||||
integrity sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==
|
||||
|
||||
hexoid@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18"
|
||||
integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==
|
||||
|
||||
hosted-git-info@^2.1.4:
|
||||
version "2.8.9"
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
|
||||
@@ -5241,6 +5336,18 @@ iconv-lite@^0.6.2:
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
idtoken-verifier@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/idtoken-verifier/-/idtoken-verifier-2.2.4.tgz#5749bd3fc9b757db40ad764484173584fb19fb55"
|
||||
integrity sha512-5t7O8cNHpJBB8FnwLD0qFZqy/+qGICObQKUl0njD6vXKHhpZPLEe8LU7qv/GBWB3Qv5e/wAIFHYVi4SoQwdOxQ==
|
||||
dependencies:
|
||||
base64-js "^1.5.1"
|
||||
crypto-js "^4.2.0"
|
||||
es6-promise "^4.2.8"
|
||||
jsbn "^1.1.0"
|
||||
unfetch "^4.2.0"
|
||||
url-join "^4.0.1"
|
||||
|
||||
ieee754@^1.1.13:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||
@@ -6083,7 +6190,7 @@ jiti@^1.18.2:
|
||||
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.1.tgz#fa99e4b76a23053e0e7cde098efe1704a14c16f1"
|
||||
integrity sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==
|
||||
|
||||
js-cookie@^2.2.1:
|
||||
js-cookie@^2.2.0, js-cookie@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
|
||||
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
|
||||
@@ -6108,6 +6215,11 @@ js-yaml@^3.10.0, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.6.1:
|
||||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
|
||||
jsbn@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
|
||||
integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==
|
||||
|
||||
jsesc@^2.5.1:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
|
||||
@@ -6696,6 +6808,11 @@ merge2@^1.3.0, merge2@^1.4.1:
|
||||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||
|
||||
methods@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
||||
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
|
||||
|
||||
micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
|
||||
@@ -6716,6 +6833,11 @@ mime-types@^2.1.12:
|
||||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
mime@2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
|
||||
integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
|
||||
|
||||
mimic-fn@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
||||
@@ -8004,6 +8126,13 @@ qrcode@^1.5.3:
|
||||
pngjs "^5.0.0"
|
||||
yargs "^15.3.1"
|
||||
|
||||
qs@^6.10.1, qs@^6.10.3, qs@^6.11.0:
|
||||
version "6.11.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9"
|
||||
integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
query-selector-shadow-dom@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.1.tgz#1c7b0058eff4881ac44f45d8f84ede32e9a2f349"
|
||||
@@ -9028,6 +9157,23 @@ sucrase@^3.32.0:
|
||||
pirates "^4.0.1"
|
||||
ts-interface-checker "^0.1.9"
|
||||
|
||||
superagent@^7.1.5:
|
||||
version "7.1.6"
|
||||
resolved "https://registry.yarnpkg.com/superagent/-/superagent-7.1.6.tgz#64f303ed4e4aba1e9da319f134107a54cacdc9c6"
|
||||
integrity sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g==
|
||||
dependencies:
|
||||
component-emitter "^1.3.0"
|
||||
cookiejar "^2.1.3"
|
||||
debug "^4.3.4"
|
||||
fast-safe-stringify "^2.1.1"
|
||||
form-data "^4.0.0"
|
||||
formidable "^2.0.1"
|
||||
methods "^1.1.2"
|
||||
mime "2.6.0"
|
||||
qs "^6.10.3"
|
||||
readable-stream "^3.6.0"
|
||||
semver "^7.3.7"
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
@@ -9532,6 +9678,11 @@ unbzip2-stream@1.4.3:
|
||||
buffer "^5.2.1"
|
||||
through "^2.3.8"
|
||||
|
||||
unfetch@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be"
|
||||
integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==
|
||||
|
||||
uniqolor@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/uniqolor/-/uniqolor-1.1.0.tgz#7519f81133cd54a1f4a59c33c81dbe04a3ad155d"
|
||||
@@ -9602,6 +9753,11 @@ uri-js@^4.2.2:
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
url-join@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7"
|
||||
integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==
|
||||
|
||||
use-callback-ref@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5"
|
||||
@@ -9895,6 +10051,11 @@ wide-align@^1.1.5:
|
||||
dependencies:
|
||||
string-width "^1.0.2 || 2 || 3 || 4"
|
||||
|
||||
winchan@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/winchan/-/winchan-0.2.2.tgz#6766917b88e5e1cb75f455ffc7cc13f51e5c834e"
|
||||
integrity sha512-pvN+IFAbRP74n/6mc6phNyCH8oVkzXsto4KCHPJ2AScniAnA1AmeLI03I2BzjePpaClGSI4GUMowzsD3qz5PRQ==
|
||||
|
||||
wordwrap@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
|
||||
|
||||
Reference in New Issue
Block a user