feat: add basic webui
This commit is contained in:
31
packages/collaboration/auth.ts
Normal file
31
packages/collaboration/auth.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'server-only';
|
||||
import { env } from '@konobangu/env';
|
||||
import { Liveblocks as LiveblocksNode } from '@liveblocks/node';
|
||||
|
||||
type AuthenticateOptions = {
|
||||
userId: string;
|
||||
orgId: string;
|
||||
userInfo: Liveblocks['UserMeta']['info'];
|
||||
};
|
||||
|
||||
export const authenticate = async ({
|
||||
userId,
|
||||
orgId,
|
||||
userInfo,
|
||||
}: AuthenticateOptions) => {
|
||||
const liveblocks = new LiveblocksNode({
|
||||
secret: env.LIVEBLOCKS_SECRET,
|
||||
});
|
||||
|
||||
// Start an auth session inside your endpoint
|
||||
const session = liveblocks.prepareSession(userId, { userInfo });
|
||||
|
||||
// Use a naming pattern to allow access to rooms with wildcards
|
||||
// Giving the user write access on their organization
|
||||
session.allow(`${orgId}:*`, session.FULL_ACCESS);
|
||||
|
||||
// Authorize the user and return the result
|
||||
const { status, body } = await session.authorize();
|
||||
|
||||
return new Response(body, { status });
|
||||
};
|
||||
49
packages/collaboration/config.ts
Normal file
49
packages/collaboration/config.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
// Define Liveblocks types for your application
|
||||
// https://liveblocks.io/docs/api-reference/liveblocks-react#Typing-your-data
|
||||
declare global {
|
||||
interface Liveblocks {
|
||||
// Each user's Presence, for useMyPresence, useOthers, etc.
|
||||
Presence: {
|
||||
// Example, real-time cursor coordinates
|
||||
cursor: { x: number; y: number } | null;
|
||||
};
|
||||
|
||||
// The Storage tree for the room, for useMutation, useStorage, etc.
|
||||
Storage: {
|
||||
// Example, a conflict-free list
|
||||
// animals: LiveList<string>;
|
||||
};
|
||||
|
||||
// Custom user info set when authenticating with a secret key
|
||||
UserMeta: {
|
||||
id: string;
|
||||
info: {
|
||||
name?: string;
|
||||
avatar?: string;
|
||||
color: string;
|
||||
};
|
||||
};
|
||||
|
||||
// Custom events, for useBroadcastEvent, useEventListener
|
||||
RoomEvent: {};
|
||||
// Example has two events, using a union
|
||||
// | { type: "PLAY" }
|
||||
// | { type: "REACTION"; emoji: "🔥" };
|
||||
|
||||
// Custom metadata set on threads, for useThreads, useCreateThread, etc.
|
||||
ThreadMetadata: {
|
||||
// Example, attaching coordinates to a thread
|
||||
// x: number;
|
||||
// y: number;
|
||||
};
|
||||
|
||||
// Custom room info set with resolveRoomsInfo, for useRoomInfo
|
||||
RoomInfo: {
|
||||
// Example, rooms with a title and url
|
||||
// title: string;
|
||||
// url: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
1
packages/collaboration/hooks.ts
Normal file
1
packages/collaboration/hooks.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from '@liveblocks/react/suspense';
|
||||
23
packages/collaboration/package.json
Normal file
23
packages/collaboration/package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "@konobangu/collaboration",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"clean": "git clean -xdf .cache .turbo dist node_modules",
|
||||
"typecheck": "tsc --noEmit --emitDeclarationOnly false"
|
||||
},
|
||||
"dependencies": {
|
||||
"@konobangu/env": "workspace:*",
|
||||
"@liveblocks/client": "^2.14.0",
|
||||
"@liveblocks/node": "^2.14.0",
|
||||
"@liveblocks/react": "^2.14.0",
|
||||
"react": "^19.0.0",
|
||||
"server-only": "^0.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@konobangu/typescript-config": "workspace:*",
|
||||
"@types/node": "22.10.1",
|
||||
"@types/react": "19.0.1",
|
||||
"@types/react-dom": "^19.0.2"
|
||||
}
|
||||
}
|
||||
37
packages/collaboration/room.tsx
Normal file
37
packages/collaboration/room.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
'use client';
|
||||
|
||||
import type { ResolveMentionSuggestionsArgs } from '@liveblocks/client';
|
||||
import type { ResolveUsersArgs } from '@liveblocks/node';
|
||||
import {
|
||||
ClientSideSuspense,
|
||||
LiveblocksProvider,
|
||||
RoomProvider,
|
||||
} from '@liveblocks/react/suspense';
|
||||
import type { ComponentProps, ReactNode } from 'react';
|
||||
|
||||
type RoomProps = ComponentProps<typeof LiveblocksProvider> & {
|
||||
id: string;
|
||||
children: ReactNode;
|
||||
authEndpoint: string;
|
||||
fallback: ReactNode;
|
||||
resolveUsers?: (
|
||||
args: ResolveUsersArgs
|
||||
) => Promise<Liveblocks['UserMeta']['info'][]>;
|
||||
resolveMentionSuggestions?: (
|
||||
args: ResolveMentionSuggestionsArgs
|
||||
) => Promise<string[]>;
|
||||
};
|
||||
|
||||
export const Room = ({
|
||||
id,
|
||||
children,
|
||||
authEndpoint,
|
||||
fallback,
|
||||
...props
|
||||
}: RoomProps) => (
|
||||
<LiveblocksProvider authEndpoint={authEndpoint} {...props}>
|
||||
<RoomProvider id={id} initialPresence={{ cursor: null }}>
|
||||
<ClientSideSuspense fallback={fallback}>{children}</ClientSideSuspense>
|
||||
</RoomProvider>
|
||||
</LiveblocksProvider>
|
||||
);
|
||||
8
packages/collaboration/tsconfig.json
Normal file
8
packages/collaboration/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@konobangu/typescript-config/react-library.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "."
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user