Started Adding Liveblocks

This commit is contained in:
Ahmad 2024-02-17 14:43:59 -05:00
parent cde7e7ab6e
commit 03dd8df0f1
No known key found for this signature in database
GPG key ID: 8FD8A93530D182BF
4 changed files with 248 additions and 3 deletions

View file

@ -0,0 +1,26 @@
import { Liveblocks } from '@liveblocks/node';
import { useUser, auth } from '@clerk/nextjs';
const liveblocks = new Liveblocks({
secret: process.env.LIVEBLOCKS_SECRET_DEV_API_KEY!,
});
export async function POST(req: Request) {
const { user } = useUser();
const { orgId } = auth();
if (!orgId || !user) return new Response('Unauthorized', { status: 401 });
// Start an auth session inside your endpoint
const session = liveblocks.prepareSession(user.id);
// Implement your own security, and give the user access to the room
const { room } = await req.json();
if (room) {
session.allow(room, session.FULL_ACCESS);
}
// Authorize the user and return the result
const { status, body } = await session.authorize();
return new Response(body, { status });
}

127
liveblocks.config.ts Normal file
View file

@ -0,0 +1,127 @@
import { createClient } from '@liveblocks/client';
import { createRoomContext } from '@liveblocks/react';
const client = createClient({
// publicApiKey: process.env.LIVEBLOCKS_PUBLIC_DEV_API_KEY!,
authEndpoint: '/api/liveblocks-auth',
// throttle: 100,
});
// Presence represents the properties that exist on every user in the Room
// and that will automatically be kept in sync. Accessible through the
// `user.presence` property. Must be JSON-serializable.
type Presence = {
// cursor: { x: number, y: number } | null,
// ...
};
// Optionally, Storage represents the shared document that persists in the
// Room, even after all users leave. Fields under Storage typically are
// LiveList, LiveMap, LiveObject instances, for which updates are
// automatically persisted and synced to all connected clients.
type Storage = {
// author: LiveObject<{ firstName: string, lastName: string }>,
// ...
};
// Optionally, UserMeta represents static/readonly metadata on each user, as
// provided by your own custom auth back end (if used). Useful for data that
// will not change during a session, like a user's name or avatar.
type UserMeta = {
id?: string; // Accessible through `user.id`
// info?: Json, // Accessible through `user.info`
};
// Optionally, the type of custom events broadcast and listened to in this
// room. Use a union for multiple events. Must be JSON-serializable.
type RoomEvent = {
// type: "NOTIFICATION",
// ...
};
// Optionally, when using Comments, ThreadMetadata represents metadata on
// each thread. Can only contain booleans, strings, and numbers.
export type ThreadMetadata = {
// resolved: boolean;
// quote: string;
// time: number;
};
export const {
suspense: {
RoomProvider,
useRoom,
useMyPresence,
useUpdateMyPresence,
useSelf,
useOthers,
useOthersMapped,
useOthersConnectionIds,
useOther,
useBroadcastEvent,
useEventListener,
useErrorListener,
useStorage,
useObject,
useMap,
useList,
useBatch,
useHistory,
useUndo,
useRedo,
useCanUndo,
useCanRedo,
useMutation,
useStatus,
useLostConnectionListener,
useThreads,
useUser,
useCreateThread,
useEditThreadMetadata,
useCreateComment,
useEditComment,
useDeleteComment,
useAddReaction,
useRemoveReaction,
},
} = createRoomContext<Presence, Storage, UserMeta, RoomEvent, ThreadMetadata>(
client,
{
async resolveUsers({ userIds }) {
// Used only for Comments. Return a list of user information retrieved
// from `userIds`. This info is used in comments, mentions etc.
// const usersData = await __fetchUsersFromDB__(userIds);
//
// return usersData.map((userData) => ({
// name: userData.name,
// avatar: userData.avatar.src,
// }));
return [];
},
async resolveMentionSuggestions({ text, roomId }) {
// Used only for Comments. Return a list of userIds that match `text`.
// These userIds are used to create a mention list when typing in the
// composer.
//
// For example when you type "@jo", `text` will be `"jo"`, and
// you should to return an array with John and Joanna's userIds:
// ["john@example.com", "joanna@example.com"]
// const userIds = await __fetchAllUserIdsFromDB__(roomId);
//
// Return all userIds if no `text`
// if (!text) {
// return userIds;
// }
//
// Otherwise, filter userIds for the search `text` and return
// return userIds.filter((userId) =>
// userId.toLowerCase().includes(text.toLowerCase())
// );
return [];
},
}
);

89
package-lock.json generated
View file

@ -11,6 +11,9 @@
"dependencies": { "dependencies": {
"@clerk/nextjs": "^4.29.3", "@clerk/nextjs": "^4.29.3",
"@hello-pangea/dnd": "^16.5.0", "@hello-pangea/dnd": "^16.5.0",
"@liveblocks/client": "^1.9.8",
"@liveblocks/node": "^1.9.8",
"@liveblocks/react": "^1.9.8",
"@prisma/client": "^5.9.1", "@prisma/client": "^5.9.1",
"@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-avatar": "^1.0.4",
@ -480,6 +483,44 @@
"@jridgewell/sourcemap-codec": "^1.4.14" "@jridgewell/sourcemap-codec": "^1.4.14"
} }
}, },
"node_modules/@liveblocks/client": {
"version": "1.9.8",
"resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-1.9.8.tgz",
"integrity": "sha512-qNFHMKOLLPNlo0HaVL7jfh877PngWYIxuZrpfnFdttR/NtDlt1gH9cL/xoyV5roULf6a5tONcMt2NqJXAFkVEw==",
"dependencies": {
"@liveblocks/core": "1.9.8"
}
},
"node_modules/@liveblocks/core": {
"version": "1.9.8",
"resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-1.9.8.tgz",
"integrity": "sha512-sIt/pqQzdMSePYxT/9YAhsR8KKDSGDo9uO8S4LJKp7wR2AgzjfXJfEFMXUe2W3D+ugzo5RZODccJS6OdgGzEnQ=="
},
"node_modules/@liveblocks/node": {
"version": "1.9.8",
"resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-1.9.8.tgz",
"integrity": "sha512-bK88vp0k3P9UngomiZjqhsiyUWKbyUvHmqeCgeSSksu1pjoivVDFu22WJrJRQws4g7+DdfCXN7kzQMD5QKVSzg==",
"dependencies": {
"@liveblocks/core": "1.9.8",
"@stablelib/base64": "^1.0.1",
"fast-sha256": "^1.3.0",
"node-fetch": "^2.6.1"
}
},
"node_modules/@liveblocks/react": {
"version": "1.9.8",
"resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-1.9.8.tgz",
"integrity": "sha512-8ZXHeG8StX5g/YZ5LYejgHBPC5WAQX8vqxshsT0kVyvP+vZCId0FCA/74uAp5DTzP0UVyQ28mINWsHqVC7t/9w==",
"dependencies": {
"@liveblocks/client": "1.9.8",
"@liveblocks/core": "1.9.8",
"nanoid": "^3",
"use-sync-external-store": "^1.2.0"
},
"peerDependencies": {
"react": "^16.14.0 || ^17 || ^18"
}
},
"node_modules/@next/env": { "node_modules/@next/env": {
"version": "14.0.4", "version": "14.0.4",
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.4.tgz", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.4.tgz",
@ -1471,6 +1512,11 @@
"integrity": "sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==", "integrity": "sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==",
"dev": true "dev": true
}, },
"node_modules/@stablelib/base64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz",
"integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ=="
},
"node_modules/@swc/helpers": { "node_modules/@swc/helpers": {
"version": "0.5.2", "version": "0.5.2",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
@ -3555,6 +3601,11 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true "dev": true
}, },
"node_modules/fast-sha256": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz",
"integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ=="
},
"node_modules/fastq": { "node_modules/fastq": {
"version": "1.17.1", "version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
@ -4823,6 +4874,25 @@
"tslib": "^2.0.3" "tslib": "^2.0.3"
} }
}, },
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-fetch-native": { "node_modules/node-fetch-native": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.0.1.tgz", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.0.1.tgz",
@ -6403,6 +6473,11 @@
"to-no-case": "^1.0.0" "to-no-case": "^1.0.0"
} }
}, },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/ts-api-utils": { "node_modules/ts-api-utils": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz",
@ -6711,6 +6786,20 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
}, },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View file

@ -14,6 +14,9 @@
"dependencies": { "dependencies": {
"@clerk/nextjs": "^4.29.3", "@clerk/nextjs": "^4.29.3",
"@hello-pangea/dnd": "^16.5.0", "@hello-pangea/dnd": "^16.5.0",
"@liveblocks/client": "^1.9.8",
"@liveblocks/node": "^1.9.8",
"@liveblocks/react": "^1.9.8",
"@prisma/client": "^5.9.1", "@prisma/client": "^5.9.1",
"@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-avatar": "^1.0.4",
@ -42,20 +45,20 @@
"zustand": "^4.4.7" "zustand": "^4.4.7"
}, },
"devDependencies": { "devDependencies": {
"@next/eslint-plugin-next": "^14.1.0",
"@types/lodash": "^4.14.202", "@types/lodash": "^4.14.202",
"@types/node": "^20", "@types/node": "^20",
"@types/react": "^18", "@types/react": "^18",
"@types/react-dom": "^18", "@types/react-dom": "^18",
"autoprefixer": "^10.0.1",
"@next/eslint-plugin-next": "^14.1.0",
"@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^7.0.0", "@typescript-eslint/parser": "^7.0.0",
"autoprefixer": "^10.0.1",
"eslint": "^8.56.0", "eslint": "^8.56.0",
"eslint-config-next": "^14.1.0", "eslint-config-next": "^14.1.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"postcss": "^8",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"prettier-plugin-tailwindcss": "^0.5.11", "prettier-plugin-tailwindcss": "^0.5.11",
"postcss": "^8",
"prisma": "^5.9.1", "prisma": "^5.9.1",
"tailwindcss": "^3.3.0", "tailwindcss": "^3.3.0",
"typescript": "^5" "typescript": "^5"