Collaboration
Caution
The collaborative editing functionality requires support from the Univer server. Please ensure that you have correctly installed and configured the Univer server. For details, please refer to: Upgrading to Pro
The collaborative editing feature allows multiple users to edit the same document simultaneously with real-time synchronization of changes. It is ideal for team collaboration and multi-user editing scenarios.
Preset Mode
Installation
The UniveSheetsCollaborationPreset preset from @univerjs/preset-sheets-collaboration depends on the UniverSheetsDrawingPreset and UniverSheetsAdvancedPreset presets at runtime. Please install @univerjs/preset-sheets-drawing and @univerjs/preset-sheets-advanced first.
npm install @univerjs/preset-sheets-drawing @univerjs/preset-sheets-advanced @univerjs/preset-sheets-collaborationUsage
import { UniverSheetsAdvancedPreset } from '@univerjs/preset-sheets-advanced'
import UniverPresetSheetsAdvancedEnUS from '@univerjs/preset-sheets-advanced/locales/en-US'
import { UniverSheetsCollaborationPreset } from '@univerjs/preset-sheets-collaboration'
import UniverPresetSheetsCollaborationEnUS from '@univerjs/preset-sheets-collaboration/locales/en-US'
import { UniverSheetsCorePreset } from '@univerjs/preset-sheets-core'
import UniverPresetSheetsCoreEnUS from '@univerjs/preset-sheets-core/locales/en-US'
import { UniverSheetsDrawingPreset } from '@univerjs/preset-sheets-drawing'
import UniverPresetSheetsDrawingEnUS from '@univerjs/preset-sheets-drawing/locales/en-US'
import { createUniver, LocaleType, mergeLocales } from '@univerjs/presets'
import '@univerjs/preset-sheets-core/lib/index.css'
import '@univerjs/preset-sheets-drawing/lib/index.css'
import '@univerjs/preset-sheets-advanced/lib/index.css'
import '@univerjs/preset-sheets-collaboration/lib/index.css'
const { univerAPI } = createUniver({
locale: LocaleType.En_US,
locales: {
[LocaleType.En_US]: mergeLocales(
UniverPresetSheetsCoreEnUS,
UniverPresetSheetsDrawingEnUS,
UniverPresetSheetsAdvancedEnUS,
UniverPresetSheetsCollaborationEnUS,
),
},
collaboration: true,
presets: [
UniverSheetsCorePreset(),
UniverSheetsDrawingPreset({
collaboration: true,
}),
UniverSheetsAdvancedPreset({
// configuration for advanced features
}),
UniverSheetsCollaborationPreset({
universerEndpoint: 'http://localhost:3010',
}),
],
})If you have a commercial license for Univer, please refer to Using License in Client for configuration.
Presets and Configuration
interface IUniverSheetsCollaborationPresetConfig {
/**
* Whether to report frontend error logs to Universer for viewing logs by searching the `Frontend` keyword.
* @default false
*/
enableFrontendLog?: boolean
}Plugin Mode
Installation
npm install @univerjs-pro/collaboration @univerjs-pro/collaboration-client @univerjs-pro/collaboration-client-uiUsage
import { UniverCollaborationPlugin } from '@univerjs-pro/collaboration'
import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client'
import { BrowserCollaborationSocketService, UniverCollaborationClientUIPlugin } from '@univerjs-pro/collaboration-client-ui'
import CollaborationClientEnUS from '@univerjs-pro/collaboration-client/locale/en-US'
import { IAuthzIoService, IMentionIOService, IUndoRedoService, LocaleType, mergeLocales, Univer } from '@univerjs/core'
import '@univerjs-pro/collaboration-client/facade'
import '@univerjs-pro/collaboration-client-ui/facade'
import '@univerjs-pro/collaboration-client/lib/index.css'
const univer = new Univer({
locale: LocaleType.En_US,
locales: {
[LocaleType.En_US]: mergeLocales(
CollaborationClientEnUS,
),
},
})
// By setting the override option to [[IAuthzIoService, null]], you can instruct Univer not to register the built-in IAuthzIoService.
// By setting the override option to [[IUndoRedoService, null]], you can instruct Univer not to register the built-in IUndoRedoService.
// By setting the override option to [[IMentionIOService, null]], you can instruct Univer not to register the built-in IMentionIOService.
// This way, Univer will use the services provided by the UniverCollaborationPlugin as the implementation for the authorization, undo/redo and mention functionalities.
const univer = new Univer({
override: [
[IAuthzIoService, null],
[IUndoRedoService, null],
[IMentionIOService, null],
],
})
const serverEndpoint = 'http://localhost:3010'
univer.registerPlugin(UniverCollaborationPlugin)
univer.registerPlugin(UniverCollaborationClientPlugin, {
socketService: BrowserCollaborationSocketService,
authzUrl: `${serverEndpoint}/universer-api/authz`,
snapshotServerUrl: `${serverEndpoint}/universer-api/snapshot`,
collabSubmitChangesetUrl: `${serverEndpoint}/universer-api/comb`,
collabWebSocketUrl: 'ws://localhost:3010/universer-api/comb/connect',
loginUrlKey: `${serverEndpoint}/universer-api/oidc/authpage`,
uploadFileServerUrl: `${serverEndpoint}/universer-api/stream/file/upload`,
signUrlServerUrl: `${serverEndpoint}/universer-api/file/{fileID}/sign-url`,
downloadEndpointUrl: `${serverEndpoint}/`,
wsSessionTicketUrl: `${serverEndpoint}/universer-api/user/session-ticket`,
startFormulaLimitUrl: `${serverEndpoint}/universer-api/license/formula/limit/start`,
getFormulaLimitStatusUrl: `${serverEndpoint}/universer-api/license/formula/limit/status`,
releaseFormulaLimitUrl: `${serverEndpoint}/universer-api/license/formula/limit/done`,
sendChangesetTimeout: 200,
})
univer.registerPlugin(UniverCollaborationClientUIPlugin) If you have a commercial license for Univer, please refer to Using License in Client for configuration.
Plugins and Configuration
interface IUniverCollaborationClientUIConfig {
/**
* Whether to report frontend error logs to Universer for viewing logs by searching the `Frontend` keyword.
* @default false
*/
enableFrontendLog?: boolean
}Collaborative Document Data
The collaborative editing plugin relies on the Univer server, and the data for collaborative documents is stored in the Univer server.
unitId
Each collaborative document in the Univer server has a unique unitId. The Univer collaboration client (collaborative editing plugin) uses the unitId to retrieve the corresponding collaborative document data from the Univer server for collaborative editing.
type
type is the type of the collaborative document, which determines the initial data structure of the collaborative document.
Creating Collaborative Documents
There are multiple ways to create collaborative documents in the Univer server:
- You can create a blank document using the Create Document API.
- You can import a
.xlsxfile into the Univer server using theFUniver.importXLSXToUnitIdAsyncmethod provided by the Import Plugin.
Loading Collaborative Documents via URL Parameters
The @univerjs-pro/collaboration-client plugin provides functionality to automatically load the corresponding data based on the URL parameters unit and type, which can simplify data loading logic in some scenarios.
If you want to use this feature, you need to modify the existing data loading logic appropriately and add the unit and type parameters to the URL, as shown below:
import { UniverInstanceType } from '@univerjs/core'
// In preset mode, `UniverInstanceType` can be imported from `@univerjs/presets`
import { UniverInstanceType } from '@univerjs/presets'
// The original logic, applicable to non-collaborative documents
univer.createUnit(UniverInstanceType.UNIVER_SHEET, {})
// The modified logic, applicable to collaborative documents
const url = new URL(window.location.href)
const unit = url.searchParams.get('unit')
if (unit) {
// If the URL contains the unit parameter, the data will be loaded automatically
} else {
// Or create a new document
fetch(`/universer-api/snapshot/${UniverInstanceType.UNIVER_SHEET}/unit/-/create`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: UniverInstanceType.UNIVER_SHEET, // instance type
name: 'New Sheet By Univer', // workbook name
creator: 'user', // creator name
}),
}).then((response) => {
if (!response.ok) {
throw new Error('create unit failed')
}
return response.json()
}).then((data) => {
if (!data.unitID) {
throw new Error('create unit failed')
}
url.searchParams.set('unit', data.unitID)
url.searchParams.set('type', String(UniverInstanceType.UNIVER_SHEET))
window.location.href = url.toString()
}).catch((error) => {
console.error(error)
})
} Facade API
Importing
Plugin mode note
Only plugin mode requires manually importing the Facade package. Preset mode already includes the corresponding Facade package, so no extra import is needed.
import '@univerjs-pro/collaboration-client/facade'
import '@univerjs-pro/collaboration-client-ui/facade'Loading Collaborative Documents
If you do not want to use URL parameters to load collaborative documents, you can also load collaborative documents through the Facade API.
const collaboration = univerAPI.getCollaboration()
const workbook = await collaboration.loadSheetAsync('your-unit-id')Collaborative Editing in Node.js Environment
import { FUniver } from '@univerjs/core/facade'
import { createUniverOnNode } from './univer'
async function run(): Promise<void> {
const univer = createUniverOnNode()
const univerAPI = FUniver.newAPI(univer)
await univerAPI.getCollaboration().loadSheetAsync('your-unit-id')
await TestSheetsPermissionAPI(univerAPI)
TestSheetsFacadeAPI(univerAPI)
TestSheetsConditionalFormattingAPI(univerAPI)
await TestSheetsDrawingAPI(univerAPI)
await TestSheetsChartFacadeAPI(univerAPI)
await TestSheetsShapeFacadeAPI(univerAPI)
await TestSheetsOutlineAPI(univerAPI)
}
run()
async function TestSheetsPermissionAPI(univerAPI: FUniver) {
const fWorkbook = univerAPI.getActiveWorkbook()
if (!fWorkbook) return
const fWorksheet = fWorkbook.getActiveSheet()
// Add some collaborators to the workbook
const workbookPermission = fWorkbook.getWorkbookPermission()
await workbookPermission.setCollaborators([
{
user: { userID: 'systemUser1', name: 'System User 1', avatar: '' },
role: univerAPI.Enum.UnitRole.Owner,
},
{
user: { userID: 'editorUser1', name: 'Editor User 1', avatar: '' },
role: univerAPI.Enum.UnitRole.Editor,
},
{
user: { userID: 'readerUser1', name: 'Reader User 1', avatar: '' },
role: univerAPI.Enum.UnitRole.Reader,
},
])
const fRange = fWorksheet.getRange('A1:B2')
const rangePermission = fRange.getRangePermission()
await rangePermission.protect({
name: 'Test Protection Rule',
allowedUsers: ['editorUser1'],
allowViewByOthers: true,
})
}
async function TestSheetsFacadeAPI(univerAPI: FUniver) {
const fWorkbook = univerAPI.getActiveWorkbook()
if (!fWorkbook) return
// Set workbook name
fWorkbook.setName('Test Workbook - Node Collaboration Client')
const fWorksheet = fWorkbook.getActiveSheet()
// Set a value in a cell A1
fWorksheet.getRange('A1').setValue(`Hello! message from the Node Collaboration Client! The current time is: ${new Date().toString()}.`)
// Merge C2:E4 range cells
const fRange2 = fWorksheet.getRange('C2:E4')
if (fRange2.isPartOfMerge() || fRange2.isMerged()) {
fRange2.breakApart()
}
fRange2.merge().setValue(1234).setNumberFormat('#,##0.00')
// Create a defined name for cell A1 and use it in cell A6
const definedNameBuilder = fWorkbook.newDefinedNameBuilder()
.setRef(`${fWorksheet.getSheetName()}!$A$1`)
.setName('MyDefinedName')
.build()
fWorkbook.insertDefinedNameBuilder(definedNameBuilder)
fWorksheet.getRange('A6').setValue('=MyDefinedName')
// Insert a new sheet
const newSheet = fWorkbook.insertSheet('New Sheet from Node Client', {
index: 1,
sheet: {
rowCount: 100,
columnCount: 20,
cellData: {
0: {
0: {
v: 1,
},
},
1: {
1: {
v: 2,
},
},
2: {
2: {
v: 3,
},
},
3: {
3: {
v: 4,
},
},
},
},
})
// Insert 3 rows after row 3 (0-based index).
newSheet.insertRowsAfter(2, 3)
const sheets = fWorkbook.getSheets()
if (sheets.length) {
// Rename the first sheet and set its row and column count
sheets[0].setName('Renamed Sheet 1').setRowCount(100).setColumnCount(10)
// Freeze first row and first column in the first sheet
sheets[0].setFrozenRows(1).setFrozenColumns(1)
// Set grid lines color to red in the first sheet
sheets[0].setGridLinesColor('#FF0000')
// Get data range of the first sheet and log its A1 notation
const dataRange = sheets[0].getDataRange()
console.warn(`Renamed Sheet 1 Data Range A1 Notation: ${dataRange.getA1Notation()}`)
// Clear content of the data range after 5 seconds
setTimeout(() => {
dataRange.clearContent()
}, 5000)
}
}
function TestSheetsConditionalFormattingAPI(univerAPI: FUniver) {
const fWorkbook = univerAPI.getActiveWorkbook()
if (!fWorkbook) return
const newSheet = fWorkbook.insertSheet('Conditional Formatting Sheet', {
sheet: {
cellData: {
0: {
0: { v: 1, t: 2 },
1: { v: 2, t: 2 },
2: { v: 3, t: 2 },
3: { v: 4, t: 2 },
},
1: {
0: { v: 2, t: 2 },
1: { v: 3, t: 2 },
2: { v: 4, t: 2 },
3: { v: 5, t: 2 },
},
2: {
0: { v: 3, t: 2 },
1: { v: 4, t: 2 },
2: { v: 5, t: 2 },
3: { v: 6, t: 2 },
},
3: {
0: { v: 4, t: 2 },
1: { v: 5, t: 2 },
2: { v: 6, t: 2 },
3: { v: 7, t: 2 },
},
},
},
})
// Add conditional formatting rule for range A1:D4: italic font, red background, green font color when cell value > 3
const fRange = newSheet.getRange('A1:D4')
const rule = newSheet.newConditionalFormattingRule()
.whenNumberGreaterThan(3)
.setRanges([fRange.getRange()])
.setItalic(true)
.setBackground('red')
.setFontColor('green')
.build()
newSheet.addConditionalFormattingRule(rule)
}
async function TestSheetsOutlineAPI(univerAPI: FUniver) {
const fWorkbook = univerAPI.getActiveWorkbook()
if (!fWorkbook) return
const fWorksheet = fWorkbook.getActiveSheet()
// Add an outline for rows 2-6 and rows 3-4 (0-based index).
fWorksheet.addRowOutline(1, 5).addRowOutline(2, 2)
// Add an outline for columns B-E and columns C-D (0-based index).
fWorksheet.addColumnOutline(1, 2)
await new Promise(resolve => setTimeout(resolve, 4000))
const rowOutlines = fWorksheet.getDimensionOutlines(univerAPI.Enum.DimensionOutlineAxis.ROW)
console.warn('rowOutlines', rowOutlines)
fWorksheet.setDimensionOutlineCollapsed(rowOutlines[0].id, true)
await new Promise(resolve => setTimeout(resolve, 4000))
fWorksheet.removeDimensionOutline(rowOutlines[1].id)
fWorksheet.clearDimensionOutlines(univerAPI.Enum.DimensionOutlineAxis.COLUMN, 1, 3)
}
async function TestSheetsDrawingAPI(univerAPI: FUniver) {
const fWorkbook = univerAPI.getActiveWorkbook()
if (!fWorkbook) return
const fWorksheet = fWorkbook.getActiveSheet()
const images = fWorksheet.getImages()
console.warn(`Current sheet has ${images.length} images.`)
const activeImages = fWorksheet.getActiveImages()
console.warn(`Current sheet has ${activeImages.length} active images.`)
const image = await fWorksheet.newOverGridImage()
.setSource('https://avatars.githubusercontent.com/u/61444807?s=48&v=4', univerAPI.Enum.ImageSourceType.URL)
.setColumn(5)
.setRow(5)
.setWidth(500)
.setHeight(300)
.buildAsync()
fWorksheet.insertImages([image])
// Update the image width to 100px and height to 50px.
await new Promise(resolve => setTimeout(resolve, 4000))
const insertedImage = fWorksheet.getImageById(image.drawingId)!
const newImage = await insertedImage.toBuilder()
.setWidth(100)
.setHeight(50)
.buildAsync()
fWorksheet.updateImages([newImage])
// Delete the image after 4 seconds.
await new Promise(resolve => setTimeout(resolve, 4000))
fWorksheet.deleteImages([insertedImage])
}
async function TestSheetsChartFacadeAPI(univerAPI: FUniver) {
const fWorkbook = univerAPI.getActiveWorkbook()
if (!fWorkbook) return
const fWorksheet = fWorkbook.getActiveSheet()
// Create a column chart with data source A1:D6.
// The starting position is upper-left corner of cell B2.
const chartInfo = fWorksheet.newChart()
.setChartType(univerAPI.Enum.ChartType.Column)
.addRange('A1:D6')
.setPosition(1, 1, 0, 0)
.build()
await fWorksheet.insertChart(chartInfo)
}
async function TestSheetsShapeFacadeAPI(univerAPI: FUniver) {
const fWorkbook = univerAPI.getActiveWorkbook()
if (!fWorkbook) return
const fWorksheet = fWorkbook.getActiveSheet()
// Create a rectangle shape at cell B2.
const shapeInfo = fWorksheet.newShape()
.setShapeType(univerAPI.Enum.ShapeTypeEnum.Rect)
.setPosition(1, 1, 0, 0)
.setWidth(200)
.setHeight(200)
.setStrokeColor('#000000')
.build()
await fWorksheet.insertShape(shapeInfo)
}import path from 'node:path'
import { UniverCollaborationPlugin } from '@univerjs-pro/collaboration'
import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client'
import { NodeCollaborationSocketService, UniverCollaborationClientNodePlugin } from '@univerjs-pro/collaboration-client-node'
import { UniverLicensePlugin } from '@univerjs-pro/license'
import { UniverSheetsChartPlugin } from '@univerjs-pro/sheets-chart'
import { UniverSheetsOutlinePlugin } from '@univerjs-pro/sheets-outline'
import { UniverSheetsPivotTablePlugin } from '@univerjs-pro/sheets-pivot'
import { UniverSheetsShapePlugin } from '@univerjs-pro/sheets-shape'
import { UniverSheetSparklinePlugin } from '@univerjs-pro/sheets-sparkline'
import { IAuthzIoService, IUndoRedoService, LocaleType, Univer } from '@univerjs/core'
import { UniverDataValidationPlugin } from '@univerjs/data-validation'
import { UniverDocsPlugin } from '@univerjs/docs'
import { UniverDocsDrawingPlugin } from '@univerjs/docs-drawing'
import { IImageIoService, UniverDrawingPlugin } from '@univerjs/drawing'
import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'
import { UniverRenderEnginePlugin } from '@univerjs/engine-render'
import { UniverNetworkPlugin } from '@univerjs/network'
import { UniverRPCNodeMainPlugin } from '@univerjs/rpc-node'
import { UniverSheetsPlugin } from '@univerjs/sheets'
import { UniverSheetsConditionalFormattingPlugin } from '@univerjs/sheets-conditional-formatting'
import { UniverSheetsDataValidationPlugin } from '@univerjs/sheets-data-validation'
import { UniverSheetsDrawingPlugin } from '@univerjs/sheets-drawing'
import { UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'
import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'
import { UniverSheetsHyperLinkPlugin } from '@univerjs/sheets-hyper-link'
import { UniverSheetsNotePlugin } from '@univerjs/sheets-note'
import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt'
import { UniverSheetsSortPlugin } from '@univerjs/sheets-sort'
import { UniverSheetsTablePlugin } from '@univerjs/sheets-table'
import { UniverThreadCommentPlugin } from '@univerjs/thread-comment'
import '@univerjs/engine-formula/facade'
import '@univerjs/sheets/facade'
import '@univerjs/sheets-formula/facade'
import '@univerjs/sheets-numfmt/facade'
import '@univerjs/sheets-conditional-formatting/facade'
import '@univerjs/sheets-data-validation/facade'
import '@univerjs/sheets-filter/facade'
import '@univerjs/sheets-hyper-link/facade'
import '@univerjs/sheets-note/facade'
import '@univerjs/sheets-table/facade'
import '@univerjs/sheets-drawing/facade'
import '@univerjs/sheets-thread-comment/facade'
import '@univerjs-pro/sheets-pivot/facade'
import '@univerjs-pro/sheets-sparkline/facade'
import '@univerjs-pro/sheets-chart/facade'
import '@univerjs-pro/sheets-shape/facade'
import '@univerjs-pro/sheets-outline/facade'
import '@univerjs-pro/collaboration-client/facade'
export interface ICreateUniverOnNodeOptions {
useComputingWorker?: boolean
}
export function createUniverOnNode(options: ICreateUniverOnNodeOptions = {}): Univer {
const { useComputingWorker = false } = options
const univer = new Univer({
locale: LocaleType.En_US,
locales: {},
override: [
[IAuthzIoService, null],
[IUndoRedoService, null],
],
})
univer.registerPlugin(UniverLicensePlugin, {
license: 'your-license',
})
registerBasicPlugins(univer, useComputingWorker)
registerSharedPlugins(univer)
if (useComputingWorker) {
registerRPCPlugin(univer)
}
registerDocPlugins(univer)
registerSheetPlugins(univer)
registerCollaborationPlugins(univer)
return univer
}
function registerBasicPlugins(univer: Univer, useComputingWorker: boolean): void {
univer.registerPlugin(UniverFormulaEnginePlugin, { notExecuteFormula: useComputingWorker })
}
function registerSharedPlugins(univer: Univer): void {
univer.registerPlugin(UniverRenderEnginePlugin)
univer.registerPlugin(UniverThreadCommentPlugin)
univer.registerPlugin(UniverDrawingPlugin, {
override: [[IImageIoService, null]],
})
}
function registerDocPlugins(univer: Univer): void {
univer.registerPlugin(UniverDocsPlugin)
univer.registerPlugin(UniverDocsDrawingPlugin)
}
function registerSheetPlugins(univer: Univer): void {
univer.registerPlugin(UniverSheetsPlugin)
univer.registerPlugin(UniverSheetsFormulaPlugin)
univer.registerPlugin(UniverSheetsNumfmtPlugin)
univer.registerPlugin(UniverSheetsConditionalFormattingPlugin)
univer.registerPlugin(UniverDataValidationPlugin)
univer.registerPlugin(UniverSheetsDataValidationPlugin)
univer.registerPlugin(UniverSheetsFilterPlugin)
univer.registerPlugin(UniverSheetsHyperLinkPlugin)
univer.registerPlugin(UniverSheetsNotePlugin)
univer.registerPlugin(UniverSheetsDrawingPlugin)
univer.registerPlugin(UniverSheetsSortPlugin)
univer.registerPlugin(UniverSheetsTablePlugin)
univer.registerPlugin(UniverSheetsChartPlugin)
univer.registerPlugin(UniverSheetsShapePlugin)
univer.registerPlugin(UniverSheetsPivotTablePlugin)
univer.registerPlugin(UniverSheetSparklinePlugin)
univer.registerPlugin(UniverSheetsOutlinePlugin)
}
function registerRPCPlugin(univer: Univer): void {
const childPath = path.join(__dirname, '../sdk/worker.js')
univer.registerPlugin(UniverRPCNodeMainPlugin, { workerSrc: childPath })
}
function registerCollaborationPlugins(univer: Univer): void {
univer.registerPlugin(UniverNetworkPlugin)
univer.registerPlugin(UniverCollaborationPlugin)
univer.registerPlugin(UniverCollaborationClientPlugin, {
socketService: NodeCollaborationSocketService,
enableOfflineEditing: false,
enableSingleActiveInstanceLock: false,
snapshotServerUrl: 'https://dev.univer.plus/universer-api/snapshot',
collabSubmitChangesetUrl: 'https://dev.univer.plus/universer-api/comb',
collabWebSocketUrl: 'http://dev.univer.plus/universer-api/comb/connect',
wsSessionTicketUrl: 'http://dev.univer.plus/universer-api/user/session-ticket',
uploadFileServerUrl: 'https://dev.univer.plus/universer-api/stream/file/upload',
signUrlServerUrl: 'https://dev.univer.plus/universer-api/file/{fileID}/sign-url',
downloadEndpointUrl: 'https://dev.univer.plus',
authzUrl: 'https://dev.univer.plus/universer-api/authz',
sendChangesetTimeout: 200,
retryConnectingInterval: 1000,
customHeaders: {
// Example: If your Univer server requires authentication via cookies, you can set the 'cookie' header here.
cookie: 'your-cookie',
// ... more headers
},
})
univer.registerPlugin(UniverCollaborationClientNodePlugin)
}import { LocaleType, Univer } from '@univerjs/core'
import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'
import { UniverRPCNodeWorkerPlugin } from '@univerjs/rpc-node'
import { UniverSheetsPlugin } from '@univerjs/sheets'
const univer = new Univer({
locale: LocaleType.En_US,
})
univer.registerPlugin(UniverSheetsPlugin, { onlyRegisterFormulaRelatedMutations: true })
univer.registerPlugin(UniverFormulaEnginePlugin)
univer.registerPlugin(UniverRPCNodeWorkerPlugin)Further Reading
If you want to learn more about how collaborative editing works, you can read the following article:
How is this guide?
