Compare commits

..

20 Commits

Author SHA1 Message Date
Giordano Ricci
c1193c3c63 add explainer for counters restarts 2025-04-08 11:43:48 +01:00
Giordano Ricci
f30130b92f reduce possible priority values 2025-04-08 11:43:48 +01:00
Giordano Ricci
1a77233ecb force metric creation on queue creation 2025-04-08 11:43:48 +01:00
Giordano Ricci
09a95b8542 move queue initialization into constructor 2025-04-08 11:43:48 +01:00
Giordano Ricci
f46329ac68 move meter 2025-04-08 11:43:48 +01:00
Giordano Ricci
c551839179 extract queue meter logic, add tests 2025-04-08 11:43:47 +01:00
Giordano Ricci
a0683f9d21 add role attribute to queue metrics 2025-04-08 11:43:47 +01:00
Giordano Ricci
a56958c69e WIP: queue counters 2025-04-08 11:43:47 +01:00
Guido D'Orsi
9f336103e8 Merge pull request #1820 from garden-co/changeset-release/main
Version Packages
2025-04-07 21:13:46 +02:00
github-actions[bot]
1174942a4e Version Packages 2025-04-07 19:12:40 +00:00
Guido D'Orsi
267920b7dc Merge pull request #1819 from garden-co/re-export-clerk
fix: add exports for clerk and crypto to make import shortcuts work everywhere
2025-04-07 21:10:16 +02:00
Guido D'Orsi
63a7aa0f54 fix: add exports for clerk and crypto to make import shortcuts work everywhere 2025-04-07 20:51:43 +02:00
Benjamin S. Leveritt
2b7534d30c Merge pull request #1808 from garden-co/docs/add-multicursor-example
Docs for multicursor example
2025-04-07 16:03:49 +01:00
Trisha Lim
be23a81b1b fix: create-jazz-app command showing $EXAMPLE instead of app slug 2025-04-07 19:55:03 +07:00
Guido D'Orsi
68416784fd docs(expo-clerk): fix outdated storage property 2025-04-07 14:39:49 +02:00
Guido D'Orsi
84d3c09cb1 docs: remove the nativewind section 2025-04-07 14:38:41 +02:00
Guido D'Orsi
53e8c39e8d docs: fix the clerk expo import 2025-04-07 14:36:46 +02:00
Trisha Lim
87b41fefad add multicursors example to cofeeds docs 2025-04-07 18:56:35 +07:00
Trisha Lim
265a4e8cc5 update readme for multi-cursors example 2025-04-07 18:53:03 +07:00
Trisha Lim
623467503f add multicursors example to examples page 2025-04-07 18:33:50 +07:00
32 changed files with 416 additions and 138 deletions

View File

@@ -0,0 +1,5 @@
---
"cojson": patch
---
Add jazz.messagequeue.pushed/pulled counters, remove jazz.messagequeue.size gauge

View File

@@ -1,5 +1,12 @@
# chat-rn-expo-clerk
## 1.0.94
### Patch Changes
- Updated dependencies [63a7aa0]
- jazz-expo@0.13.1
## 1.0.93
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "chat-rn-expo-clerk",
"main": "index.js",
"version": "1.0.93",
"version": "1.0.94",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",

View File

@@ -1,6 +1,5 @@
import { useClerk } from "@clerk/clerk-expo";
// FIXME: why isn't the export working? IDE is fine, Metro doesn't like the non 'dist' import
import { JazzProviderWithClerk } from "jazz-expo/dist/auth/clerk";
import { JazzProviderWithClerk } from "jazz-expo/auth/clerk";
import React, { PropsWithChildren } from "react";
import { apiKey } from "./apiKey";

View File

@@ -1,5 +1,12 @@
# chat-rn-expo
## 1.0.81
### Patch Changes
- Updated dependencies [63a7aa0]
- jazz-expo@0.13.1
## 1.0.80
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn-expo",
"version": "1.0.80",
"version": "1.0.81",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",

View File

@@ -1,5 +1,12 @@
# chat-rn
## 1.0.90
### Patch Changes
- Updated dependencies [63a7aa0]
- jazz-react-native@0.13.1
## 1.0.89
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.89",
"version": "1.0.90",
"main": "index.js",
"scripts": {
"android": "react-native run-android",

View File

@@ -1,3 +1,64 @@
# Multi-cursor example
# Jazz Multi-Cursors Example
An example app of using Jazz for showing multiple-cursors on a simple canvas.
Track user presence on a canvas with multiple cursors and out of bounds indicators.
## Getting started
You can either
1. Clone the jazz repository, and run the app within the monorepo.
2. Or create a new Jazz project using this example as a template.
### Using the example as a template
Create a new Jazz project, and use this example as a template.
```bash
npx create-jazz-app@latest multi-cursors-app --example multi-cursors
```
Go to the new project directory.
```bash
cd multi-cursors-app
```
Run the dev server.
```bash
npm run dev
```
### Using the monorepo
This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
Clone the jazz repository.
```bash
git clone https://github.com/garden-co/jazz.git
```
Install and build dependencies.
```bash
pnpm i && npx turbo build
```
Go to the example directory.
```bash
cd jazz/examples/multi-cursors/
```
Start the dev server.
```bash
pnpm dev
```
Open [http://localhost:5173](http://localhost:5173) with your browser to see the result.
## 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 Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
You can also run a local sync server by running `npx jazz-run sync` and adding the query param `?sync=ws://localhost:4200` to the URL of the example app (for example: `http://localhost:5173/?peer=ws://localhost:4200`), or by setting the `sync` parameter of `JazzProvider` component in [./src/main.tsx](./src/main.tsx).

View File

@@ -1,5 +1,4 @@
import {
AlertCircleIcon,
AlertTriangleIcon,
ArrowDownIcon,
ArrowRightIcon,
@@ -27,6 +26,7 @@ import {
MessageCircleQuestionIcon,
MonitorSmartphoneIcon,
MoonIcon,
MousePointer2Icon,
MousePointerSquareDashedIcon,
ScanFace,
ScrollIcon,
@@ -50,6 +50,7 @@ const icons = {
close: XIcon,
code: CodeIcon,
copy: ClipboardIcon,
cursor: MousePointer2Icon,
darkTheme: MoonIcon,
delete: TrashIcon,
devices: MonitorSmartphoneIcon,

View File

@@ -209,13 +209,14 @@ However, once authenticated, your users won't need to interact with Clerk anymor
<ContentByFramework framework="react">
The clerk provider is not built into `jazz-react` and needs the `jazz-react-auth-clerk` package to be installed.
After installing the package you can use the `JazzProviderWithClerk` component to wrap your app:
</ContentByFramework>
<ContentByFramework framework="react-native-expo">
The clerk provider is not built into `jazz-expo` and needs the `jazz-expo/auth/clerk` import to be installed. Note the `__experimental_resourceCache` option. This helps render Clerk components when offline.
You can use the `JazzProviderWithClerk` component to wrap your app. Note the `__experimental_resourceCache` option. This helps render Clerk components when offline.
</ContentByFramework>
After installing the package you can use the `JazzProviderWithClerk` component to wrap your app:
<ContentByFramework framework="react">
<CodeGroup>
```tsx

View File

@@ -79,10 +79,10 @@ If you're using Clerk auth in your Expo application, you'll need to:
```tsx twoslash
// @noErrors: 2300 2307
// Before
import { ClerkAuthProvider, useClerkAuth } from "jazz-react-native-clerk"; // [!code --]
import { JazzProviderWithClerk } from "jazz-react-native-clerk"; // [!code --]
// After
import { ClerkAuthProvider, useClerkAuth } from "jazz-expo/auth/clerk"; // [!code ++]
import { JazzProviderWithClerk } from "jazz-expo/auth/clerk"; // [!code ++]
```
</CodeGroup>
@@ -134,31 +134,6 @@ declare module "jazz-expo" { // [!code ++:5]
The `jazz-expo` implementation supports the Expo New Architecture.
## Styling with NativeWind
For Expo projects, remember to use NativeWind CSS for styling, which is the recommended approach for Jazz applications built with Expo:
<CodeGroup>
```tsx twoslash
// @noErrors: 2305 2686
import { View, Text } from "react-native";
import { styled } from "nativewind";
const StyledView = styled(View);
const StyledText = styled(Text);
export function MyComponent() {
return (
<StyledView className="p-4 bg-white dark:bg-slate-800">
<StyledText className="text-black dark:text-white text-lg font-bold">
Hello, Jazz with Expo!
</StyledText>
</StyledView>
);
}
```
</CodeGroup>
## For More Information
For detailed setup instructions, refer to the [React Native Expo Setup Guide](/docs/react-native-expo/project-setup)

View File

@@ -8,7 +8,9 @@ CoFeeds are append-only data structures that track entries from different user s
Each account can have multiple sessions (different browser tabs, devices, or app instances), making CoFeeds ideal for building features like activity logs, presence indicators, and notification systems.
The [Reactions example](https://github.com/garden-co/jazz/tree/main/examples/reactions) demonstrates a practical use of CoFeeds.
The following examples demonstrate a practical use of CoFeeds:
- [Multi-cursors](https://github.com/garden-co/jazz/tree/main/examples/multi-cursors) - track user presence on a canvas with multiple cursors and out of bounds indicators
- [Reactions](https://github.com/garden-co/jazz/tree/main/examples/reactions) - store per-user emoji reaction using a CoFeed
## Creating CoFeeds

View File

@@ -253,6 +253,38 @@ const ReactionsIllustration = () => (
</div>
);
const MultiCursorIllustration = () => (
<div className="flex bg-stone-100 h-full flex-col items-center justify-center dark:bg-transparent p-4">
<div className=" bg-white md:aspect-[3/2] flex flex-col rounded-md shadow-xl shadow-stone-400/20 dark:shadow-none">
<div className="w-full py-2 flex items-center gap-1.5 px-2 border-b dark:border-b-stone-200">
<span className="rounded-full size-2 bg-stone-200"></span>
<span className="rounded-full size-2 bg-stone-200"></span>
<span className="rounded-full size-2 bg-stone-200"></span>
</div>
<div className="h-full mx-auto flex flex-col justify-center p-12 sm:p-16">
<div className="inline-block relative px-1 ring-1 ring-blue-400">
<div className="absolute size-2 bg-white border border-blue-400 -left-1 -top-1"></div>
<div className="absolute size-2 bg-white border border-blue-400 -right-1 -top-1"></div>
<div className="absolute size-2 bg-white border border-blue-400 -left-1 -bottom-1"></div>
<div className="absolute size-2 bg-white border border-blue-400 -right-1 -bottom-1"></div>
<span className="text-lg font-semibold md:text-2xl md:font-bold text-stone-800 ">
Hello, world!
</span>
<div className="absolute -top-10 right-4 text-rose-600 flex items-end gap-1">
<Icon name="cursor"></Icon> <span className="text-xs">Mia</span>
</div>
<div className="absolute -bottom-10 left-4 text-green-600 flex items-end gap-1">
<Icon name="cursor"></Icon>{" "}
<span className="text-xs">Sebastian</span>
</div>
</div>
</div>
</div>
</div>
);
const PetIllustration = () => (
<div className="h-full p-4 bg-[url('/dog.jpg')] bg-cover bg-center p-4 flex items-end">
<div className="inline-flex justify-center gap-1 mx-auto">
@@ -395,6 +427,16 @@ const reactExamples: Example[] = [
demoUrl: "https://reactions-demo.jazz.tools",
illustration: <ReactionsIllustration />,
},
{
name: "Cursor presence",
slug: "multi-cursors",
description:
"Track user presence on a canvas with multiple cursors and out of bounds indicators.",
tech: [tech.react],
features: [features.coFeed],
demoUrl: "https://jazz-multi-cursors.vercel.app",
illustration: <MultiCursorIllustration />,
},
{
name: "Rate my pet",
slug: "pets",
@@ -484,7 +526,8 @@ const rnExamples: Example[] = [
{
name: "Chat",
slug: "chat-rn",
description: "A simple React Native app that creates a chat room with a shareable link.",
description:
"A simple React Native app that creates a chat room with a shareable link.",
tech: [tech.reactNative],
illustration: <ChatIllustration />,
},
@@ -492,7 +535,8 @@ const rnExamples: Example[] = [
{
name: "Chat",
slug: "chat-rn-expo",
description: "A simple Expo app that creates a chat room with a shareable link.",
description:
"A simple Expo app that creates a chat room with a shareable link.",
tech: [tech.reactNative, tech.expo],
illustration: <ChatIllustration />,
},
@@ -500,7 +544,8 @@ const rnExamples: Example[] = [
{
name: "Chat",
slug: "chat-rn-expo-clerk",
description: "Exactly like the React Native Expo chat app, with Clerk for auth.",
description:
"Exactly like the React Native Expo chat app, with Clerk for auth.",
tech: [tech.reactNative, tech.expo],
features: [features.clerk],
illustration: <ClerkIllustration />,

View File

@@ -56,8 +56,8 @@ export const docNavigationItems = [
"react-native": 100,
"react-native-expo": 100,
},
}
]
},
],
},
{
name: "Tools",
@@ -82,7 +82,7 @@ export const docNavigationItems = [
{
name: "0.13.0 - React Native Split",
href: "/docs/upgrade/0-13-0",
done: 100
done: 100,
},
{
// upgrade guides

View File

@@ -26,13 +26,11 @@ export function InterpolateInCode(replace: { [key: string]: string }) {
}: { highlightedCode: string }) => {
const newHighlightedCode = Object.entries(replace).reduce(
(acc, [key, value]) => {
return acc.replaceAll(
key.replaceAll("$", "&#36;").replaceAll("_", "&#95;"),
value,
);
return acc.replaceAll(key, value);
},
highlightedCode,
);
return <div dangerouslySetInnerHTML={{ __html: newHighlightedCode }} />;
},
};

View File

@@ -126,7 +126,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);
@@ -214,7 +214,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);
@@ -243,7 +243,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);
@@ -269,7 +269,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
const stream: SyncMessage[] = [];
@@ -316,7 +316,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
const stream: SyncMessage[] = [];
@@ -365,7 +365,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);
@@ -411,7 +411,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);
@@ -450,7 +450,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);

View File

@@ -10,10 +10,21 @@ import { CO_VALUE_PRIORITY } from "./priority.js";
import { Peer, SyncMessage } from "./sync.js";
export class PeerState {
private queue: PriorityBasedMessageQueue;
constructor(
private peer: Peer,
knownStates: PeerKnownStates | undefined,
) {
/**
* We set as default priority HIGH to handle all the messages without a
* priority property as HIGH priority.
*
* This way we consider all the non-content messsages as HIGH priority.
*/
this.queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.HIGH, {
peerRole: peer.role,
});
this.optimisticKnownStates = knownStates?.clone() ?? new PeerKnownStates();
// We assume that exchanges with storage peers are always successful
@@ -76,13 +87,6 @@ export class PeerState {
return this.peer.role === "server" || this.peer.role === "storage";
}
/**
* We set as default priority HIGH to handle all the messages without a
* priority property as HIGH priority.
*
* This way we consider all the non-content messsages as HIGH priority.
*/
private queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.HIGH);
private processing = false;
public closed = false;

View File

@@ -1,5 +1,5 @@
import { ValueType, metrics } from "@opentelemetry/api";
import type { CoValuePriority } from "./priority.js";
import { Counter, ValueType, metrics } from "@opentelemetry/api";
import { CO_VALUE_PRIORITY, type CoValuePriority } from "./priority.js";
import type { SyncMessage } from "./sync.js";
function promiseWithResolvers<R>() {
@@ -34,7 +34,7 @@ type Tuple<T, N extends number, A extends unknown[] = []> = A extends {
? A
: Tuple<T, N, [...A, T]>;
type QueueTuple = Tuple<LinkedList<QueueEntry>, 8>;
type QueueTuple = Tuple<LinkedList<QueueEntry>, 3>;
type LinkedListNode<T> = {
value: T;
@@ -46,6 +46,8 @@ type LinkedListNode<T> = {
* as our queues can grow very large when the system is under pressure.
*/
export class LinkedList<T> {
constructor(private meter?: QueueMeter) {}
head: LinkedListNode<T> | undefined = undefined;
tail: LinkedListNode<T> | undefined = undefined;
length = 0;
@@ -64,6 +66,7 @@ export class LinkedList<T> {
}
this.length++;
this.meter?.push();
}
shift() {
@@ -82,34 +85,83 @@ export class LinkedList<T> {
this.length--;
this.meter?.pull();
return value;
}
}
export class PriorityBasedMessageQueue {
private queues: QueueTuple = [
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
];
queueSizeCounter = metrics
.getMeter("cojson")
.createUpDownCounter("jazz.messagequeue.size", {
description: "Size of the message queue",
valueType: ValueType.INT,
unit: "entry",
});
class QueueMeter {
private pullCounter: Counter;
private pushCounter: Counter;
private getQueue(priority: CoValuePriority) {
return this.queues[priority];
constructor(
prefix: string,
private attrs?: Record<string, string | number>,
) {
this.pullCounter = metrics
.getMeter("cojosn")
.createCounter(`${prefix}.pulled`, {
description: "Number of messages pulled from the queue",
valueType: ValueType.INT,
unit: "1",
});
this.pushCounter = metrics
.getMeter("cojosn")
.createCounter(`${prefix}.pushed`, {
description: "Number of messages pushed to the queue",
valueType: ValueType.INT,
unit: "1",
});
/**
* This makes sure that those metrics are generated (and emitted) as soon as the queue is created.
* This is to avoid edge cases where one series reset is delayed, which would cause spikes or dips
* when queried - and it also more correctly represents the actual state of the queue after a restart.
*/
this.pullCounter.add(0, this.attrs);
this.pushCounter.add(0, this.attrs);
}
constructor(private defaultPriority: CoValuePriority) {}
public pull() {
this.pullCounter.add(1, this.attrs);
}
public push() {
this.pushCounter.add(1, this.attrs);
}
}
function meteredList<T>(attrs?: Record<string, string | number>) {
return new LinkedList<T>(new QueueMeter("jazz.messagequeue", attrs));
}
const PRIORITY_TO_QUEUE_INDEX = {
[CO_VALUE_PRIORITY.HIGH]: 0,
[CO_VALUE_PRIORITY.MEDIUM]: 1,
[CO_VALUE_PRIORITY.LOW]: 2,
} as const;
export class PriorityBasedMessageQueue {
private queues: QueueTuple;
constructor(
private defaultPriority: CoValuePriority,
/**
* Optional attributes to be added to the generated metrics.
* By default the metrics will have the priority as an attribute.
*/
attrs?: Record<string, string | number>,
) {
this.queues = [
meteredList({ priority: CO_VALUE_PRIORITY.HIGH, ...attrs }),
meteredList({ priority: CO_VALUE_PRIORITY.MEDIUM, ...attrs }),
meteredList({ priority: CO_VALUE_PRIORITY.LOW, ...attrs }),
];
}
private getQueue(priority: CoValuePriority) {
return this.queues[PRIORITY_TO_QUEUE_INDEX[priority]];
}
public push(msg: SyncMessage) {
const { promise, resolve, reject } = promiseWithResolvers<void>();
@@ -119,24 +171,12 @@ export class PriorityBasedMessageQueue {
this.getQueue(priority).push(entry);
this.queueSizeCounter.add(1, {
priority,
});
return promise;
}
public pull() {
const priority = this.queues.findIndex((queue) => queue.length > 0);
if (priority === -1) {
return;
}
this.queueSizeCounter.add(-1, {
priority,
});
return this.queues[priority]?.shift();
}
}

View File

@@ -7,7 +7,7 @@ import { type CoValueHeader } from "./coValueCore.js";
* The priority value is handled as weight in the weighed round robin algorithm
* used to determine the order in which messages are sent.
*
* Follows the HTTP urgency range and order:
* Loosely follows the HTTP urgency range and order, but limited to 3 values:
* - https://www.rfc-editor.org/rfc/rfc9218.html#name-urgency
*/
export const CO_VALUE_PRIORITY = {
@@ -16,7 +16,7 @@ export const CO_VALUE_PRIORITY = {
LOW: 6,
} as const;
export type CoValuePriority = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
export type CoValuePriority = 0 | 3 | 6;
export function getPriorityFromHeader(
header: CoValueHeader | undefined | boolean,

View File

@@ -7,9 +7,9 @@ import {
tearDownTestMetricReader,
} from "./testUtils.js";
function setup() {
function setup(attrs?: Record<string, string | number>) {
const metricReader = createTestMetricReader();
const queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.MEDIUM);
const queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.MEDIUM, attrs);
return { queue, metricReader };
}
@@ -18,10 +18,133 @@ describe("PriorityBasedMessageQueue", () => {
tearDownTestMetricReader();
});
describe("meteredQueue", () => {
test("should corretly count pushes", async () => {
const { queue, metricReader } = setup();
const message: SyncMessage = {
action: "load",
id: "co_ztest-id",
header: false,
sessions: {},
};
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(0);
void queue.push(message);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(1);
void queue.push(message);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(2);
});
test("should corretly count pulls", async () => {
const { queue, metricReader } = setup();
const message: SyncMessage = {
action: "load",
id: "co_ztest-id",
header: false,
sessions: {},
};
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(0);
void queue.push(message);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(0);
void queue.pull();
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(1);
// We only have one item in the queue, so this should not change the metric value
void queue.pull();
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(1);
});
test("should corretly set custom attributes to the metrics", async () => {
const { queue, metricReader } = setup({ role: "server" });
const message: SyncMessage = {
action: "load",
id: "co_ztest-id",
header: false,
sessions: {},
};
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "server",
}),
).toBe(0);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "client",
}),
).toBeUndefined();
void queue.push(message);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "server",
}),
).toBe(1);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "server",
}),
).toBe(0);
void queue.pull();
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "server",
}),
).toBe(1);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "server",
}),
).toBe(1);
});
});
test("should initialize with correct properties", () => {
const { queue } = setup();
expect(queue["defaultPriority"]).toBe(CO_VALUE_PRIORITY.MEDIUM);
expect(queue["queues"].length).toBe(8);
expect(queue["queues"].length).toBe(3);
expect(queue["queues"].every((q) => !q.length)).toBe(true);
});
@@ -52,7 +175,7 @@ describe("PriorityBasedMessageQueue", () => {
});
test("should pull messages in priority order", async () => {
const { queue, metricReader } = setup();
const { queue } = setup();
const lowPriorityMsg: SyncMessage = {
action: "content",
id: "co_zlow",
@@ -73,42 +196,12 @@ describe("PriorityBasedMessageQueue", () => {
};
void queue.push(lowPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: lowPriorityMsg.priority,
}),
).toBe(1);
void queue.push(mediumPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: mediumPriorityMsg.priority,
}),
).toBe(1);
void queue.push(highPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: highPriorityMsg.priority,
}),
).toBe(1);
expect(queue.pull()?.msg).toEqual(highPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: highPriorityMsg.priority,
}),
).toBe(0);
expect(queue.pull()?.msg).toEqual(mediumPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: mediumPriorityMsg.priority,
}),
).toBe(0);
expect(queue.pull()?.msg).toEqual(lowPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: lowPriorityMsg.priority,
}),
).toBe(0);
});
test("should return undefined when pulling from empty queue", () => {

View File

@@ -1,5 +1,11 @@
# jazz-browser
## 0.13.1
### Patch Changes
- 63a7aa0: Add exports for clerk and crypto to make import shortcuts work everywhere
## 0.13.0
### Minor Changes

2
packages/jazz-expo/auth/clerk.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
// Re-export the Clerk provider from the dist folder to make the `jazz-expo/auth/clerk` import work everywhere
export * from "../dist/auth/clerk";

View File

@@ -0,0 +1,2 @@
// Re-export the Clerk provider from the dist folder to make the `jazz-expo/auth/clerk` import work everywhere
export * from "../dist/auth/clerk";

2
packages/jazz-expo/crypto/index.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
// Re-export the crypto module from the dist folder to make the `jazz-expo/crypto` import work everywhere
export * from "jazz-react-native-core/dist/crypto";

View File

@@ -0,0 +1,2 @@
// Re-export the crypto module from the dist folder to make the `jazz-expo/crypto` import work everywhere
export * from "jazz-react-native-core/dist/crypto";

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-expo",
"version": "0.13.0",
"version": "0.13.1",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -22,6 +22,11 @@
"types": "./dist/auth/clerk/index.d.ts",
"default": "./dist/auth/clerk/index.js"
},
"./crypto": {
"react-native": "./crypto/index.js",
"types": "./crypto/index.d.ts",
"default": "./crypto/index.js"
},
"./testing": {
"react-native": "./dist/testing.js",
"types": "./dist/testing.d.ts",

View File

@@ -22,7 +22,6 @@ function JazzProvider({ children }: { children: React.ReactNode }) {
return (
<JazzProviderWithClerk
clerk={clerk}
storage="sqlite"
sync={{
peer: "wss://cloud.jazz.tools/?key=chat-rn-expo-clerk-example-jazz@garden.co",
}}

View File

@@ -1,5 +1,11 @@
# jazz-browser
## 0.13.1
### Patch Changes
- 63a7aa0: Add exports for clerk and crypto to make import shortcuts work everywhere
## 0.13.0
### Minor Changes

View File

@@ -0,0 +1,2 @@
// Re-export the crypto module from the dist folder to make the `jazz-react-native/crypto` import work everywhere
export * from "jazz-react-native-core/dist/crypto";

View File

@@ -0,0 +1,2 @@
// Re-export the crypto module from the dist folder to make the `jazz-react-native/crypto` import work everywhere
export * from "jazz-react-native-core/dist/crypto";

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-react-native",
"version": "0.13.0",
"version": "0.13.1",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -12,6 +12,11 @@
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./crypto": {
"react-native": "./crypto/index.js",
"types": "./crypto/index.d.ts",
"default": "./crypto/index.js"
},
"./testing": {
"react-native": "./dist/testing.js",
"types": "./dist/testing.d.ts",