Full Code of yorkie-team/yorkie-js-sdk for AI

main 4ae9fd555ddb cached
522 files
7.3 MB
1.9M tokens
2494 symbols
1 requests
Download .txt
Showing preview only (7,783K chars total). Download the full file or copy to clipboard to get everything.
Repository: yorkie-team/yorkie-js-sdk
Branch: main
Commit: 4ae9fd555ddb
Files: 522
Total size: 7.3 MB

Directory structure:
gitextract_9k73p22c/

├── .editorconfig
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.md
│   │   ├── common-issue.md
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── ci.yml
│       ├── devtools-publish.yml
│       ├── github-page-publish.yml
│       └── npm-publish.yml
├── .gitignore
├── .husky/
│   ├── commit-msg
│   └── pre-commit
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc.js
├── CHANGELOG.md
├── CLAUDE.md
├── CONTRIBUTING.md
├── LICENSE
├── MAINTAINING.md
├── README.md
├── codecov.yml
├── docker/
│   ├── docker-compose-ci.yml
│   └── docker-compose.yml
├── eslint.config.mjs
├── examples/
│   ├── CONTRIBUTING.md
│   ├── README.md
│   ├── nextjs-presence/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── app/
│   │   │   ├── App.css
│   │   │   ├── api/
│   │   │   │   └── channels/
│   │   │   │       └── route.ts
│   │   │   ├── globals.css
│   │   │   ├── layout.tsx
│   │   │   └── page.tsx
│   │   ├── components/
│   │   │   ├── RoomSelector.css
│   │   │   ├── RoomSelector.tsx
│   │   │   ├── RoomView.css
│   │   │   ├── RoomView.tsx
│   │   │   ├── SessionCounter.css
│   │   │   └── SessionCounter.tsx
│   │   ├── eslint.config.mjs
│   │   ├── lib/
│   │   │   └── rooms.ts
│   │   ├── next.config.ts
│   │   ├── package.json
│   │   └── tsconfig.json
│   ├── nextjs-scheduler/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── app/
│   │   │   ├── Scheduler.tsx
│   │   │   ├── layout.tsx
│   │   │   ├── not-found.tsx
│   │   │   ├── page.tsx
│   │   │   ├── styles/
│   │   │   │   ├── calendar.css
│   │   │   │   ├── globals.css
│   │   │   │   └── page.module.css
│   │   │   └── utils/
│   │   │       ├── handlePeers.ts
│   │   │       ├── parseDate.ts
│   │   │       └── types.ts
│   │   ├── eslint.config.mjs
│   │   ├── next.config.js
│   │   ├── package.json
│   │   └── tsconfig.json
│   ├── nextjs-todolist/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── app/
│   │   │   ├── globals.css
│   │   │   ├── layout.tsx
│   │   │   └── page.tsx
│   │   ├── components/
│   │   │   ├── TodoList.tsx
│   │   │   └── ui/
│   │   │       ├── button.tsx
│   │   │       ├── card.tsx
│   │   │       └── input.tsx
│   │   ├── components.json
│   │   ├── eslint.config.mjs
│   │   ├── lib/
│   │   │   └── utils.ts
│   │   ├── next.config.ts
│   │   ├── package.json
│   │   ├── postcss.config.mjs
│   │   └── tsconfig.json
│   ├── profile-stack/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── main.js
│   │   ├── package.json
│   │   ├── style.css
│   │   ├── util.js
│   │   └── vite.config.js
│   ├── react-document-limit/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── components/
│   │   │   │   ├── ConnectionStatus.tsx
│   │   │   │   ├── Counter.tsx
│   │   │   │   ├── CounterNumber.tsx
│   │   │   │   ├── IncrementButton.tsx
│   │   │   │   └── Peers.tsx
│   │   │   ├── hooks/
│   │   │   │   └── useDocumentSelector.tsx
│   │   │   ├── index.css
│   │   │   ├── main.tsx
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── react-flow/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.tsx
│   │   │   ├── index.css
│   │   │   ├── main.tsx
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── react-polling-playground/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── Leaderboard.tsx
│   │   │   ├── StockDetail.tsx
│   │   │   ├── StockRow.tsx
│   │   │   ├── WritePostPage.tsx
│   │   │   ├── main.tsx
│   │   │   ├── stocks.ts
│   │   │   ├── styles.css
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── react-revision/
│   │   ├── eslint.config.mjs
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.tsx
│   │   │   ├── RevisionPanel.tsx
│   │   │   ├── main.tsx
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── react-tldraw/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.tsx
│   │   │   ├── CustomCursor.tsx
│   │   │   ├── hooks/
│   │   │   │   ├── types.ts
│   │   │   │   └── useMultiplayerState.ts
│   │   │   ├── main.tsx
│   │   │   ├── tldraw.d.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── react-todomvc/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── eslint.config.mjs
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.tsx
│   │   │   ├── components/
│   │   │   │   ├── Footer.tsx
│   │   │   │   ├── Header.tsx
│   │   │   │   ├── MainSection.tsx
│   │   │   │   ├── TodoItem.tsx
│   │   │   │   └── TodoTextInput.tsx
│   │   │   ├── main.tsx
│   │   │   ├── model.ts
│   │   │   ├── todoReducer.ts
│   │   │   ├── useTodoReducer.tsx
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── simultaneous-cursors/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.jsx
│   │   │   ├── components/
│   │   │   │   ├── ColoredIcon.jsx
│   │   │   │   ├── Cursor.jsx
│   │   │   │   ├── CursorSelections.css
│   │   │   │   ├── CursorSelections.jsx
│   │   │   │   ├── FullAnimation.jsx
│   │   │   │   ├── PenCursor.jsx
│   │   │   │   ├── SingleAnimation.jsx
│   │   │   │   └── SingleAnimation.module.css
│   │   │   ├── hooks/
│   │   │   │   └── useInterval.jsx
│   │   │   └── main.jsx
│   │   └── vite.config.js
│   ├── vanilla-codemirror6/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── main.ts
│   │   │   ├── network.ts
│   │   │   ├── style.css
│   │   │   ├── type.ts
│   │   │   ├── utils.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.js
│   ├── vanilla-document-limit/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── connection.ts
│   │   │   ├── counter.ts
│   │   │   ├── index.css
│   │   │   ├── main.ts
│   │   │   ├── peer.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── vanilla-prosemirror/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── main.ts
│   │   │   ├── style.css
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.js
│   ├── vanilla-quill/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── main.ts
│   │   │   ├── network.ts
│   │   │   ├── style.css
│   │   │   ├── type.ts
│   │   │   ├── utils.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.js
│   └── vuejs-kanban/
│       ├── .gitignore
│       ├── README.md
│       ├── index.html
│       ├── package.json
│       ├── src/
│       │   ├── App.vue
│       │   ├── assets/
│       │   │   └── main.css
│       │   └── main.js
│       └── vite.config.js
├── lint-staged.config.mjs
├── package.json
├── packages/
│   ├── devtools/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── content.ts
│   │   │   ├── devtools/
│   │   │   │   ├── components/
│   │   │   │   │   ├── Code.tsx
│   │   │   │   │   ├── Detail.tsx
│   │   │   │   │   ├── JsonView.tsx
│   │   │   │   │   ├── ResizableSeparator.tsx
│   │   │   │   │   └── Tree.tsx
│   │   │   │   ├── contexts/
│   │   │   │   │   ├── SelectedNode.tsx
│   │   │   │   │   ├── SelectedPresence.tsx
│   │   │   │   │   └── YorkieSource.tsx
│   │   │   │   ├── icons/
│   │   │   │   │   └── index.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   ├── panel/
│   │   │   │   │   ├── code.css
│   │   │   │   │   ├── index.html
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── slider.css
│   │   │   │   │   └── styles.css
│   │   │   │   └── tabs/
│   │   │   │       ├── Document.tsx
│   │   │   │       ├── History.tsx
│   │   │   │       └── Presence.tsx
│   │   │   ├── popup/
│   │   │   │   └── index.tsx
│   │   │   └── port.ts
│   │   └── tsconfig.json
│   ├── prosemirror/
│   │   ├── README.md
│   │   ├── examples/
│   │   │   ├── basic.html
│   │   │   ├── basic.ts
│   │   │   ├── custom-schema.html
│   │   │   ├── custom-schema.ts
│   │   │   ├── index.html
│   │   │   ├── style.css
│   │   │   ├── tree-schema.html
│   │   │   └── tree-schema.ts
│   │   ├── package.json
│   │   ├── scripts/
│   │   │   └── setup-tree-schema.ts
│   │   ├── src/
│   │   │   ├── binding.ts
│   │   │   ├── convert.ts
│   │   │   ├── cursor.ts
│   │   │   ├── defaults.ts
│   │   │   ├── diff.ts
│   │   │   ├── index.ts
│   │   │   ├── position.ts
│   │   │   ├── selection-plugin.ts
│   │   │   ├── sync.ts
│   │   │   └── types.ts
│   │   ├── test/
│   │   │   ├── integration/
│   │   │   │   └── split_merge_test.ts
│   │   │   └── unit/
│   │   │       ├── convert_test.ts
│   │   │       ├── custom_schema_test.ts
│   │   │       ├── defaults_test.ts
│   │   │       ├── diff_test.ts
│   │   │       ├── helpers.ts
│   │   │       ├── position_test.ts
│   │   │       └── sync_test.ts
│   │   ├── tsconfig.json
│   │   ├── vite.build.ts
│   │   ├── vite.config.ts
│   │   └── vitest.config.ts
│   ├── react/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── ChannelProvider.tsx
│   │   │   ├── DocumentProvider.tsx
│   │   │   ├── YorkieProvider.tsx
│   │   │   ├── createChannelStore.ts
│   │   │   ├── createDocumentStore.ts
│   │   │   ├── createStore.ts
│   │   │   ├── index.ts
│   │   │   ├── shallowEqual.ts
│   │   │   ├── usePeekChannel.ts
│   │   │   ├── useSelector.ts
│   │   │   └── useYorkieDoc.ts
│   │   ├── test/
│   │   │   ├── integration/
│   │   │   │   └── integration.test.tsx
│   │   │   ├── test-setup.ts
│   │   │   └── unit/
│   │   │       ├── createDocumentSelector.test.tsx
│   │   │       ├── useRevisions.test.tsx
│   │   │       ├── useSelector.test.ts
│   │   │       └── useYorkieDoc.test.ts
│   │   ├── tsconfig.json
│   │   ├── vite.config.js
│   │   └── vitest.config.ts
│   ├── schema/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── antlr/
│   │   │   ├── YorkieSchema.g4
│   │   │   ├── YorkieSchema.interp
│   │   │   ├── YorkieSchema.tokens
│   │   │   ├── YorkieSchemaLexer.interp
│   │   │   ├── YorkieSchemaLexer.tokens
│   │   │   ├── YorkieSchemaLexer.ts
│   │   │   ├── YorkieSchemaListener.ts
│   │   │   ├── YorkieSchemaParser.ts
│   │   │   └── YorkieSchemaVisitor.ts
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── style.css
│   │   ├── src/
│   │   │   ├── index.ts
│   │   │   ├── main.ts
│   │   │   ├── rulesets.ts
│   │   │   ├── validator.ts
│   │   │   └── vite-env.d.ts
│   │   ├── test/
│   │   │   ├── ruleset.test.ts
│   │   │   └── validator.test.ts
│   │   ├── tsconfig.json
│   │   ├── vite.build.ts
│   │   └── vite.config.ts
│   └── sdk/
│       ├── README.md
│       ├── buf.gen.yaml
│       ├── eslint.config.mjs
│       ├── index.html
│       ├── package.json
│       ├── public/
│       │   ├── counter.html
│       │   ├── devtool/
│       │   │   ├── network.js
│       │   │   ├── object.css
│       │   │   ├── object.js
│       │   │   ├── text.css
│       │   │   └── text.js
│       │   ├── drawing.html
│       │   ├── multi.html
│       │   ├── presence.html
│       │   ├── quill.css
│       │   ├── quill.html
│       │   ├── schema.html
│       │   ├── style.css
│       │   ├── tree-schema.html
│       │   ├── whiteboard.css
│       │   └── whiteboard.html
│       ├── scripts/
│       │   └── update-examples.sh
│       ├── src/
│       │   ├── api/
│       │   │   ├── converter.ts
│       │   │   ├── revision.ts
│       │   │   └── yorkie/
│       │   │       └── v1/
│       │   │           ├── resources.proto
│       │   │           ├── resources_pb.ts
│       │   │           ├── yorkie.proto
│       │   │           └── yorkie_pb.ts
│       │   ├── channel/
│       │   │   └── channel.ts
│       │   ├── client/
│       │   │   ├── attachable.ts
│       │   │   ├── attachment.ts
│       │   │   ├── auth_interceptor.ts
│       │   │   ├── client.ts
│       │   │   ├── metric_interceptor.ts
│       │   │   └── watch.ts
│       │   ├── devtools/
│       │   │   ├── index.ts
│       │   │   ├── protocol.ts
│       │   │   └── types.ts
│       │   ├── document/
│       │   │   ├── change/
│       │   │   │   ├── change.ts
│       │   │   │   ├── change_id.ts
│       │   │   │   ├── change_pack.ts
│       │   │   │   ├── checkpoint.ts
│       │   │   │   └── context.ts
│       │   │   ├── crdt/
│       │   │   │   ├── array.ts
│       │   │   │   ├── counter.ts
│       │   │   │   ├── element.ts
│       │   │   │   ├── element_rht.ts
│       │   │   │   ├── gc.ts
│       │   │   │   ├── hll.ts
│       │   │   │   ├── object.ts
│       │   │   │   ├── primitive.ts
│       │   │   │   ├── rga_tree_list.ts
│       │   │   │   ├── rga_tree_split.ts
│       │   │   │   ├── rht.ts
│       │   │   │   ├── root.ts
│       │   │   │   ├── text.ts
│       │   │   │   └── tree.ts
│       │   │   ├── document.ts
│       │   │   ├── history.ts
│       │   │   ├── json/
│       │   │   │   ├── array.ts
│       │   │   │   ├── counter.ts
│       │   │   │   ├── element.ts
│       │   │   │   ├── object.ts
│       │   │   │   ├── strings.ts
│       │   │   │   ├── text.ts
│       │   │   │   └── tree.ts
│       │   │   ├── operation/
│       │   │   │   ├── add_operation.ts
│       │   │   │   ├── array_set_operation.ts
│       │   │   │   ├── edit_operation.ts
│       │   │   │   ├── increase_operation.ts
│       │   │   │   ├── move_operation.ts
│       │   │   │   ├── operation.ts
│       │   │   │   ├── remove_operation.ts
│       │   │   │   ├── set_operation.ts
│       │   │   │   ├── style_operation.ts
│       │   │   │   ├── tree_edit_operation.ts
│       │   │   │   └── tree_style_operation.ts
│       │   │   ├── presence/
│       │   │   │   ├── change.ts
│       │   │   │   └── presence.ts
│       │   │   ├── schema/
│       │   │   │   ├── content-expression.ts
│       │   │   │   ├── ruleset_validator.ts
│       │   │   │   └── tree-validator.ts
│       │   │   ├── time/
│       │   │   │   ├── actor_id.ts
│       │   │   │   ├── ticket.ts
│       │   │   │   └── version_vector.ts
│       │   │   └── yson/
│       │   │       ├── index.ts
│       │   │       ├── parser.ts
│       │   │       └── types.ts
│       │   ├── util/
│       │   │   ├── comparator.ts
│       │   │   ├── error.ts
│       │   │   ├── index_tree.ts
│       │   │   ├── llrb_tree.ts
│       │   │   ├── logger.ts
│       │   │   ├── number.ts
│       │   │   ├── object.ts
│       │   │   ├── observable.ts
│       │   │   ├── resource.ts
│       │   │   ├── splay_tree.ts
│       │   │   ├── uuid.ts
│       │   │   └── validator.ts
│       │   └── yorkie.ts
│       ├── test/
│       │   ├── bench/
│       │   │   ├── counter.bench.ts
│       │   │   ├── document.bench.ts
│       │   │   ├── editing-trace.json
│       │   │   ├── splay_tree.bench.ts
│       │   │   ├── text.bench.ts
│       │   │   └── tree.bench.ts
│       │   ├── helper/
│       │   │   ├── helper.ts
│       │   │   └── vector_utils.ts
│       │   ├── integration/
│       │   │   ├── array_test.ts
│       │   │   ├── broadcast_test.ts
│       │   │   ├── channel_polling_test.ts
│       │   │   ├── channel_test.ts
│       │   │   ├── client_test.ts
│       │   │   ├── counter_test.ts
│       │   │   ├── doc_presence_test.ts
│       │   │   ├── document_limit_test.ts
│       │   │   ├── document_polling_test.ts
│       │   │   ├── document_schema_test.ts
│       │   │   ├── document_test.ts
│       │   │   ├── epoch_mismatch_test.ts
│       │   │   ├── gc_test.ts
│       │   │   ├── history_array_test.ts
│       │   │   ├── history_text_test.ts
│       │   │   ├── history_tree_split_test.ts
│       │   │   ├── history_tree_test.ts
│       │   │   ├── integration_helper.ts
│       │   │   ├── object_test.ts
│       │   │   ├── presence_test.ts
│       │   │   ├── primitive_test.ts
│       │   │   ├── revision_test.ts
│       │   │   ├── snapshot_test.ts
│       │   │   ├── text_test.ts
│       │   │   ├── tree_concurrency_test.ts
│       │   │   ├── tree_test.ts
│       │   │   └── webhook_test.ts
│       │   ├── unit/
│       │   │   ├── api/
│       │   │   │   └── converter_test.ts
│       │   │   ├── channel/
│       │   │   │   └── channel_test.ts
│       │   │   ├── document/
│       │   │   │   ├── crdt/
│       │   │   │   │   ├── counter_test.ts
│       │   │   │   │   ├── element_rht_test.ts
│       │   │   │   │   ├── primitive_test.ts
│       │   │   │   │   ├── rht_test.ts
│       │   │   │   │   ├── root_test.ts
│       │   │   │   │   └── tree_test.ts
│       │   │   │   ├── document_size_test.ts
│       │   │   │   ├── document_test.ts
│       │   │   │   ├── gc_test.ts
│       │   │   │   ├── schema/
│       │   │   │   │   ├── content_expression_test.ts
│       │   │   │   │   ├── tree_schema_integration_test.ts
│       │   │   │   │   └── tree_validator_test.ts
│       │   │   │   └── yson_test.ts
│       │   │   ├── schema/
│       │   │   │   └── ruleset_validator_test.ts
│       │   │   └── util/
│       │   │       ├── index_tree_test.ts
│       │   │       ├── llrb_tree_test.ts
│       │   │       ├── logger_test.ts
│       │   │       └── splay_tree_test.ts
│       │   ├── vitest.d.ts
│       │   └── vitest.setup.ts
│       ├── tsconfig.json
│       ├── typedoc.json
│       ├── vite.build.ts
│       ├── vite.config.ts
│       └── vitest.config.ts
├── pnpm-workspace.yaml
└── scripts/
    ├── setup.sh
    ├── tasks-archive.sh
    └── tasks-index.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# EditorConfig is awesome: http://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 2


================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: Bug Report
about: Report a bug encountered while using Yorkie
labels: kind/bug

---

<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks!
-->


**What happened**:

**What you expected to happen**:

**How to reproduce it (as minimally and precisely as possible)**:

**Anything else we need to know?**:

**Environment**:
- Operating system:
- Browser and version:
- Yorkie version (use `yorkie version`):
- Yorkie JS SDK version:


================================================
FILE: .github/ISSUE_TEMPLATE/common-issue.md
================================================
---
name: Common Issue
about: A common issue with the Yorkie project
labels:

---
<!-- Please only use this template for submitting common issues -->

**Description**:

**Why**:


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--  Thanks for sending a pull request! -->

#### What this PR does / why we need it?


#### Any background context you want to provide?


#### What are the relevant tickets?
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
Fixes #

### Checklist
- [ ] Added relevant tests or not required
- [ ] Addressed and resolved all CodeRabbit review comments
- [ ] Didn't break anything


================================================
FILE: .github/workflows/ci.yml
================================================
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [22.x]
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 9

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'pnpm'

      - name: Cache pnpm store
        id: cache
        uses: actions/cache@v4
        with:
          path: ~/.pnpm-store
          key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-

      - name: Install Dependencies
        if: steps.cache.outputs.cache-hit != 'true'
        run: pnpm install

      - name: Lint
        run: pnpm lint

      - name: Build and Test SDK
        run: |
          pnpm sdk build
          docker compose -f docker/docker-compose-ci.yml up --build -d
          pnpm sdk test:ci
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v5
        with:
          files: ./coverage/lcov.info
        env:
          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

      - name: Build Examples
        run: pnpm build:examples

      - name: Build React and Test React
        run: |
          pnpm react build
          pnpm react test

      - name: Build and Test Schema
        run: |
          pnpm schema build
          pnpm schema test

      - name: Run benchmark
        run: pnpm sdk test:bench


================================================
FILE: .github/workflows/devtools-publish.yml
================================================
name: Publish Yorkie Devtools Extension
on:
  workflow_dispatch:
  push:
    branches:
      - 'main'
    paths:
      - packages/devtools/package.json
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout 🛎️
        uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 9

      - name: Setup Node 🔧
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'pnpm'

      - name: Install and Build 🔧
        env:
          PARCEL_WORKER_BACKEND: process
        run: |
          pnpm i
          pnpm devtools build

      - name: Deploy 🚀
        uses: PlasmoHQ/bpp@v3
        with:
          keys: ${{ secrets.BPP_KEYS }}
          chrome-file: 'packages/devtools/dist/chrome-mv3-prod.zip'


================================================
FILE: .github/workflows/github-page-publish.yml
================================================
name: Github Page Publish
on:
  push:
    branches:
      - 'main'
    paths-ignore:
      - 'test/**'
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout 🛎️
        uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 9

      - name: Setup Node 🔧
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'pnpm'
          cache-dependency-path: pnpm-lock.yaml

      - name: Cache pnpm store
        id: cache
        uses: actions/cache@v4
        with:
          path: ~/.pnpm-store
          key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-

      - name: Install Dependencies
        if: steps.cache.outputs.cache-hit != 'true'
        run: pnpm install

      - name: Build 🔧
        run: |
          pnpm sdk build
          pnpm sdk build:docs
          pnpm build:examples
          pnpm sdk build:ghpages

      - name: Deploy 🚀
        uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./packages/sdk/ghpages
          enable_jekyll: false


================================================
FILE: .github/workflows/npm-publish.yml
================================================
name: npm-publish
on:
  workflow_dispatch:
  release:
    types: [published]
jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write
    steps:
      - name: Checkout 🛎️
        uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 9

      - name: Setup Node 🔧
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'pnpm'
          cache-dependency-path: pnpm-lock.yaml
          registry-url: 'https://registry.npmjs.org'

      - name: Cache pnpm store
        id: cache
        uses: actions/cache@v4
        with:
          path: ~/.pnpm-store
          key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-

      - name: Install Dependencies
        if: steps.cache.outputs.cache-hit != 'true'
        run: pnpm install

      - name: SDK Build
        run: pnpm sdk build
      - name: SDK Publish
        run: pnpm publish --filter=@yorkie-js/sdk --no-git-checks --provenance
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: React Build
        run: pnpm react build
      - name: React Publish
        run: pnpm publish --filter=@yorkie-js/react --no-git-checks --provenance
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: Schema Build
        run: pnpm schema build
      - name: Schema Publish
        run: pnpm publish --filter=@yorkie-js/schema --no-git-checks --provenance
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: ProseMirror Build
        run: pnpm prosemirror build
      - name: ProseMirror Publish
        run: pnpm publish --filter=@yorkie-js/prosemirror --no-git-checks --provenance
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}


================================================
FILE: .gitignore
================================================

# Created by https://www.gitignore.io/api/vim,node
# Edit at https://www.gitignore.io/?templates=vim,node

### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-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/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# next.js build output
.next

# nuxt.js build output
.nuxt

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

### Vim ###
# Swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]

# Session
Session.vim
Sessionx.vim

# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~

# End of https://www.gitignore.io/api/vim,node

# Webstorm
.idea

# Dist files
dist/
bundle/

# Docs files (generated API docs)
docs/
!docs/design/
!docs/tasks/

# ghpages
ghpages/

# temp folder used by api-extractor
temp

# api review folder used by api-extractor
api-review

# lib folder used by api-extractor
packages/sdk/lib/
packages/prosemirror/lib/

.DS_Store

# vscode
.vscode

# profile output
*.cpuprofile

# npm
**/package-lock.json


================================================
FILE: .husky/commit-msg
================================================
#!/usr/bin/env bash
set -euo pipefail

# Strip comment lines (lines starting with #)
msg=$(sed '/^#/d' "$1")

# Skip empty messages (git handles this separately)
if [ -z "$msg" ]; then
  exit 0
fi

subject=$(echo "$msg" | head -n1)
subject_len=${#subject}

if [ "$subject_len" -gt 70 ]; then
  echo "commit-msg: subject line is $subject_len chars (max 70)" >&2
  exit 1
fi

line_count=$(echo "$msg" | wc -l | tr -d ' ')

if [ "$line_count" -ge 2 ]; then
  line2=$(echo "$msg" | sed -n '2p')
  if [ -n "$line2" ]; then
    echo "commit-msg: line 2 must be blank (found: '$line2')" >&2
    exit 1
  fi
fi

if [ "$line_count" -ge 3 ]; then
  line_num=0
  while IFS= read -r line; do
    line_num=$((line_num + 1))
    if [ "$line_num" -le 2 ]; then
      continue
    fi
    len=${#line}
    if [ "$len" -gt 80 ]; then
      echo "commit-msg: line $line_num is $len chars (max 80)" >&2
      exit 1
    fi
  done <<< "$msg"
fi


================================================
FILE: .husky/pre-commit
================================================
npx lint-staged


================================================
FILE: .npmrc
================================================
engine-strict=true
@buf:registry=https://buf.build/gen/npm/v1


================================================
FILE: .nvmrc
================================================
lts/*


================================================
FILE: .prettierignore
================================================
src/api/yorkie_grpc_web_pb.d.ts
src/api/yorkie_pb.d.ts


================================================
FILE: .prettierrc.js
================================================
// eslint-disable-next-line no-undef
module.exports = {
  bracketSpacing: true,
  singleQuote: true,
  trailingComma: 'all',
  printWidth: 80,
};


================================================
FILE: CHANGELOG.md
================================================
# Changelog

All notable changes to Yorkie JS SDK will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

- Channel lifecycle via RefreshChannel only by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/1258
- Silence post-success cleanup AbortError from connect-rpc unary calls by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1263

## [v0.7.9] - 2026-05-14

### Added

- Add PeekChannel client + usePeekChannel React hook by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/1256

### Fixed

- Fix Polling channel subscriber notification, expose polling via React by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/1247

## [v0.7.8] - 2026-05-05

### Added

- Add SyncMode.Polling for Channel and Document by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1243

### Changed

- Drop isRealtime from core SDK, keep it as React-only prop by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1245
- Bump dependencies to fix 25 Dependabot security alerts by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1240

### Fixed

- Filter pre-tombstoned descendants in tree reverseOp by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1239
- Clear history after attach and make undo/redo no-op on empty stack by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1238
- Fix editByPath split-then-merge and cross-boundary merge undo by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1237

## [v0.7.7] - 2026-04-26

### Added

- Support splitLevel>=2 undo/redo with multi-client convergence by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1234
- Add DedupCounter parse support in YSON by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1232

### Fixed

- Port splitLevel>=2 convergence fixes from Go server by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1233

## [v0.7.6] - 2026-04-23

### Added

- Implement toJSON for Bytes and Date primitive types by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1225

### Changed

- Unify presence event emission with reconcilePresence by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1229
- Prevent race conditions between sync loop and detach/deactivate by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1228
- Copy attributes to split node in cloneElement by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1224

### Fixed

- Apply array-move-convergence with LWW position register by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1227
- Register LWW-losing element in GC set on Set conflict by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1226

## [v0.7.5] - 2026-04-20

### Added

- Add Counter dedup mode with HyperLogLog for UV measurement by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1215
- Enable splitLevel=1 concurrent tests and add split undo/redo by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1219
- Add undo/redo support for TreeStyleOperation by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1221
- Add content correctness tests for overlapping undo by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1222

### Changed

- Simplify Counter interface and replace long with bigint by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1216
- Switch default transport from gRPC-Web to Connect Protocol by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1218

## [v0.7.4] - 2026-04-11

### Added

- Use native Tree.Edit split/merge in ProseMirror binding by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1207

### Fixed

- Fix tree style divergence on concurrent split via End-token guard by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1211
- Mirror tree merge snapshot encoding fix from Go SDK by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1210
- Fix SplitElement divergence on concurrent split inside merge range by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1206
- Fix split + delete divergence and splitElement tombstone handling by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1205
- Fix multi-level split + merge divergence via mergedFrom by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1204
- Fix split sibling convergence via position forwarding by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1203
- Fix convergence bugs in concurrent tree merge/split by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1202

## [v0.7.3] - 2026-04-02

### Added

- Add range-based styleByPath and removeStyleByPath for Tree by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1198
- Add epoch mismatch event for compaction recovery by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1193
- Export Tree, Text and Counter from @yorkie-js/react package by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1190

## [v0.7.2] - 2026-03-20

### Fixed

- Fix ElementRHT.set() producing duplicate ownKeys on timestamp reversal by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1188

## [v0.7.1] - 2026-03-19

### Added

- Add tree-level schema validation and ProseMirror example by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1181

### Fixed

- Retain peer presence across watch stream reconnections by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1186

## [v0.7.0] - 2026-03-05

### Added

- Add undo/redo support for Tree.Edit operations (Phase 1) by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1176

### Fixed

- Fix Korean IME composition breakage by pausing sync during composition by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1179

## [v0.6.49] - 2026-02-23

### Added

- Add remote selection range display and vanilla-prosemirror example by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1166
- Add fine-grained IME composition guard to prosemirror binding by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1167
- Add undo/redo support for Text.Style operations by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1174
- Add multi-user undo/redo support to vanilla-quill example by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1175
- Add useRevisions hook to @yorkie-js/react for revision API by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1177

### Changed

- Return unwrapped primitive values from Array iterator by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1178

### Fixed

- Fix remote cursor jumping to next line via intra-block diffing by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1168
- Fix cursor jump caused by text node fragmentation in downstream sync by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1169
- Fix remote cursor not updating on local edits in prosemirror binding by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1170
- Fix cursor focus jumping between editors on Safari by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1171
- Fix duplicate list items in nested block sync by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1173

## [v0.6.48] - 2026-02-11

### Added

- Add @yorkie-js/prosemirror package with ProseMirror-Yorkie Tree bindings by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1163

### Changed

- Replace WatchDocument and WatchChannel with unified Watch RPC by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1161
- Extract shared watch stream lifecycle into runWatchStream helper by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1160

### Fixed

- Remove --backend-disable-webhook-validation from docker-compose by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1162

## [v0.6.47] - 2026-02-06

### Changed

- Refactor channel terminology from presence to session by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/1154

### Fixed

- Add backend-disable-webhook-validation to CI by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1155
- Add NEXT_PUBLIC_BASE_PATH to production environment variables by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1158

## [v0.6.44] - 2026-01-19

### Fixed

- Fix SplayTree Find semantics for CRDT Array by @ggyuchive in https://github.com/yorkie-team/yorkie-js-sdk/pull/1150

## [v0.6.43] - 2026-01-13

### Changed

- Refactor room management with categories by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/1145

## [v0.6.42] - 2025-12-19

### Changed

- Rename presence_count to session_count by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/1142

## [v0.6.41] - 2025-12-09

### Added

- Enhance YSON parsing with generic type support by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1137
- Implement YSON module with parser and types by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1135
- Add GetRevision for retrieving specific revisions by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1133
- Implement reverse EditOperation for Text by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/1126

### Changed

- Bump up libs to the latest version by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1132

## [v0.6.40] - 2025-12-02

### Added

- Implement revision management by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1127

## [v0.6.39] - 2025-11-27

### Changed

- Add enableDevtools option to useYorkieDoc by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1120

### Fixed

- Fix various issues that occur in examples by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1117
- Handle selection changes on mouse release in Quill by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1118
- Insert images in Quill editor with user attribution by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1119
- Prevent minus retains of delta operations in Quill by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1121
- Fix local range calculation in delta for Quill by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1122
- Prevent selection updates during IME input in Quill by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1123
- Use deleteByID instead of filter for todo deletion in react-todomvc by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/1124

## [v0.6.38] - 2025-11-14

### Changed

- Bump up Quill to v2 by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1115

### Fixed

- Fix unexpected styles when refreshing Quill by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1112
- Fix code-block escape in Quill by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1113

## [v0.6.37] - 2025-11-11

### Added

- Add rpcAddr to options in ReactTodoMVC by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1106
- Add document key retrieval to use query string by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1108
- Refine channel shard key and add GetChannels API example by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/1109

### Fixed

- Add cancel watch stream test by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1105
- Fix nil pointer dereference in LLRB Floor function by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1107

## [v0.6.36] - 2025-11-06

### Added

- Add PresenceProvider and related hooks by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1099

### Changed

- Replace lodash to es-toolkit for bundle size reduction by @witch-factory in https://github.com/yorkie-team/yorkie-js-sdk/pull/1101
- Refactor broadcast handling in Presence by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1102
- Rename Presence to Channel by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1103

## [v0.6.35] - 2025-10-30

### Added

- Enhance presence with manual and realtime sync by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1096

### Fixed

- Fix removedAt timestamp handling for text deletions by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/1094
- Fix removedAt timestamp handling in tree deletions by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/1097
- Fix missing Tombstone nodes during ElementRHT encoding by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/1098

## [v0.6.34] - 2025-10-24

### Added

- Add real-time presence tracking @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1091

## [v0.6.29] - 2025-09-05

### Changed

- Ensure LWW concurrent deletions collapse to single tombstone timestamp by @PlusUltraCode in https://github.com/yorkie-team/yorkie-js-sdk/pull/1083
- Rename OperationInfo to OpInfo across the codebase by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1084
- Refactor JSON element types and streamline document core by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1085

### Fixed

- Fix garbage size accounting for Text nodes by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1086

## [v0.6.28] - 2025-09-02

### Added

- Add getOthersPresences and synchronous deactivation by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1081

## [v0.6.27] - 2025-08-29

### Added

- Support undo for move/set by fixing collisions by @KMSstudio in https://github.com/yorkie-team/yorkie-js-sdk/pull/1059

### Changed

- Remove optional methods from JSONArray/JSONObject by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1076

### Fixed

- Fix attachment constructor argument typo by @witch-factory in https://github.com/yorkie-team/yorkie-js-sdk/pull/1073

## [v0.6.26] - 2025-08-20

### Added

- Add edit name feature in Profile Stack by @saemileee in https://github.com/yorkie-team/yorkie-js-sdk/pull/1063
- Enhance drawing tools and smoothing pipeline by @echae22 in https://github.com/yorkie-team/yorkie-js-sdk/pull/1069

### Changed

- Normalize error in validation functions to lowercase by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1064
- Simplify examples by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1067

### Fixed

- Reset online clients on attachment cancellation by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1066
- Fix removedAt timestamp handling in text deletions by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1071

## [v0.6.25] - 2025-08-12

- Prevent watch stream creation after cancellation by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1056
- Modernize and align with React TodoMVC by @witch-factory in https://github.com/yorkie-team/yorkie-js-sdk/pull/1057
- Connect tldraw undo/redo to History API by @KMSstudio in https://github.com/yorkie-team/yorkie-js-sdk/pull/1060
- Fix incorrect deletion of compacted documents by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1061

## [v0.6.24] - 2025-08-06

### Added

- Support `array[idx] = val` via Proxy.set trap by @KMSstudio in https://github.com/yorkie-team/yorkie-js-sdk/pull/1041
- Add selector-based context system to reduce re-renders by @jaesoekjjang in https://github.com/yorkie-team/yorkie-js-sdk/pull/1031

### Changed

- Migrate to ESLint 9.x flat config across monorepo by @witch-factory in https://github.com/yorkie-team/yorkie-js-sdk/pull/1045

### Fixed

- Prevent document attachment before component mount by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1050
- Fix race condition between detach and syncLoop by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1051
- Prevent watch stream re-creation after detachment by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1052
- Prevent event loss by ensuring sync loop resumes after reconnect by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1054

## [0.6.23] - 2025-08-01

### Fixed

- Cleanup ESLint packages/react by @jaesoekjjang in https://github.com/yorkie-team/yorkie-js-sdk/pull/1027
- Remove deprecated SelectOperation by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1038
- Resolve convergence issues in Array.Move and Array.Set by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/1037

## [0.6.22] - 2025-07-28

### Changed

- Change VersionVector actorID encoding from hex to base64 by @mnnseong in https://github.com/yorkie-team/yorkie-js-sdk/pull/1030

### Fixed

- Fix eslint cleanup SDK by @pengooseDev https://github.com/yorkie-team/yorkie-js-sdk/pull/1023

## [0.6.21] - 2025-07-25

### Added

- Add nextjs-quill example using Yorkie and Quill v2 by @miinhho in https://github.com/yorkie-team/yorkie-js-sdk/pull/1032
- Support for object, array and enum in ruleset builder by @sigmaith in https://github.com/yorkie-team/yorkie-js-sdk/pull/1025

### Changed

- Migrate vanilla-quill example dependency to Quill v2 by @miinhho in https://github.com/yorkie-team/yorkie-js-sdk/pull/1034

## [0.6.20] - 2025-07-17

### Added

- Support Undo/Redo for array.add and array.remove by @KMSstudio in https://github.com/yorkie-team/yorkie-js-sdk/pull/1014

### Fixed

- Update CONTRIBUTING.md to use `pnpm i` by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1012
- Update deprecated pprof flag by @pengooseDev in https://github.com/yorkie-team/yorkie-js-sdk/pull/1020
- Change schema tests to use assert.include by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1024
- Fix typo in MaxDelimiter constant name by @jaesoekjjang in https://github.com/yorkie-team/yorkie-js-sdk/pull/1022

## [0.6.18] - 2025-07-01

### Added

- Add schema support by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/1010

### Changed

- Replace example project by @hackerwins in #f1c4dc9

## [0.6.15] - 2025-06-09

### Changed

- Improve Shard Key for Client Requests to Prevent Load Skew by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/1003

### Fixed

- Update eslint-plugin-jsdoc to support Node.js version>=20 by @witch-factory in https://github.com/yorkie-team/yorkie-js-sdk/pull/1001
- Remove obsolete version field from docker-compose.yml by @witch-factory in https://github.com/yorkie-team/yorkie-js-sdk/pull/1005

## [0.6.14] - 2025-06-02

### Fixed

- Remove recursion in registerElement to avoid duplicate registrations by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/995
- Fix non-deterministic test caused by realtime mode by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/997

## [0.6.13] - 2025-05-27

### Added

- Introduce size limit for documents by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/992

### Changed

- Update SnapshotThreshold to 500 by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/993

## [0.6.12] - 2025-05-16

### Changed

- Remove logical clock from presence-only changes by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/990

## [0.6.10] - 2025-05-09

### Removed

- Remove deprecated MinSyncedTicket and MaxCreatedAtMapByActor by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/969

## [0.6.9] - 2025-04-30

### Added

- Implement Split, Merge in json layer of Tree by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/982

### Fixed

- Update dependencies in ProseMirror by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/986

## [0.6.8] - 2025-04-28

### Added

- Add size tracking to CRDT by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/981
- Add document to DocumentContext by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/983

### Fixed

- Update client initialization to use rpcAddr option in examples by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/979
- Apply HMR in dev mode by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/984

## [0.6.7] - 2025-04-17

### Added

- Add beforeunload deactivation handler directly to Client by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/977

### Changed

- Refactor client initialization to use options for rpcAddr by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/975

### Fixed

- Add missing user agent to @yorkie-js/react by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/976

## [0.6.6] - 2025-04-07

### Added

- Add schema package with initial configuration by @hackerwins https://github.com/yorkie-team/yorkie-js-sdk/pull/968

### Changed

- Support StrictMode in React Standalone Mode by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/970

### Removed

- Remove create-yorkie-app package by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/967

## [0.6.5] - 2025-03-28

### Added

- Add nextjs-todolist example by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/964
- Add connection status hook in React Binder by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/960
- Add react-document-limit example by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/958
- Add vanilla-document-limit example by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/957

### Fixed

- Use useRef for client instance management in StrictMode by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/963
- Add missing initial presence in Yorkie React by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/959

## [0.6.3] - 2025-03-19

### Added

- Handle Attachment Limit per Document by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/955
- Add react-flow example by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/954

## [0.6.2] - 2025-03-14

### Added

- Handle Subscription limit per Document by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/952

## [0.6.1] - 2025-03-06

### Added

- Add @yorkie-js/react package with hooks for SDK integration by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/945
- Add YorkieProvider, DocumentProvider and suspense hooks by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/946
- Add keepalive option when detaching a document by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/948

### Changed

- Refactor package names to include scope by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/944
- Refactor import paths to use '@yorkie-js/sdk' by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/947
- Support React 18 and guard hasDocument check by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/950

## [0.6.0] - 2025-02-17

### Added

- Add metadata to Client for MAU tracking by @emplam27 in https://github.com/yorkie-team/yorkie-js-sdk/pull/942

### Changed

- Update github actions version by @DongjaJ in https://github.com/yorkie-team/yorkie-js-sdk/pull/936

### Fixed

- Fix type errors in devtools package by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/938

## [0.5.7] - 2024-12-11

### Changed

- Replace maxCreatedAtMap with version vector for causal-concurrent operations by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/932

### Fixed

- Enhance webhook tests and error handling for authentication by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/930
- Preserve Detached Client's Lamport in Version Vector by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/931
- Improve Version Vector Handling for Legacy SDK and Snapshots by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/933

## [0.5.6] - 2024-11-22

### Added

- Add keepalive option in client.deactivate by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/928

### Fixed

- Improve GC for deactivated client's nodes by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/926

## [0.5.5] - 2024-11-07

### Added

- Add dynamic token refresh and authentication error handling by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/911

### Fixed

- Fix tests for event batch publisher implementation by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/924
- Modify Snapshot Event to publish updated local changes by @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/923

## [0.5.4] - 2024-10-28

### Added

- Implement `InitialRoot` option for Document attachment by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/913
- Add doc.getStats for debugging purpose by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/920

### Fixed

- Export VersionVector by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/917

## [0.5.3] - 2024-10-23

### Changed

- Introducing version vector to solve GC problem by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/899

## [0.5.2] - 2024-10-22

### Changed

- Update target to ES2020 and replace Long with bigint by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/912

## [0.5.1] - 2024-10-15

### Added

- Add configurable retry mechanism to broadcast interface by @gwbaik9717 in https://github.com/yorkie-team/yorkie-js-sdk/pull/901

### Changed

- Ensure `find` and `indexOf` perform splay by @m4ushold in https://github.com/yorkie-team/yorkie-js-sdk/pull/904
- Restrict presence object type to JSON serializable values by @gwbaik9717 in https://github.com/yorkie-team/yorkie-js-sdk/pull/898

### Fixed

- Automate Linting with Husky and lint-staged to Prevent CI Failures by @gwbaik9717 in https://github.com/yorkie-team/yorkie-js-sdk/pull/896

## [0.5.0] - 2024-09-05

### Added

- Introduce broadcast API for event sharing by @gwbaik9717 in https://github.com/yorkie-team/yorkie-js-sdk/pull/884

### Fixed

- Update npm-publish command for sdk by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/886
- Update MAINTAINING.md by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/887
- Lock version of `@codemirror/view` to prevent potential issues with Korean character input by @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/890

## [0.4.31] - 2024-08-22

### Changed

- Update example version to v0.4.28 by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/877
- Unify error throwing methods by @gwbaik9717 https://github.com/yorkie-team/yorkie-js-sdk/pull/878
- Update docker compose command to V2 by @kokodak in https://github.com/yorkie-team/yorkie-js-sdk/pull/879
- Introduce monorepo to manage packages using pnpm @gwbaik9717 https://github.com/yorkie-team/yorkie-js-sdk/pull/880

## [0.4.28] - 2024-07-25

### Added

- Improve performance for creating crdt.TreeNode by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/875
- Add Root-Only Filter Feature in History Tab by @gwbaik9717 in https://github.com/yorkie-team/yorkie-js-sdk/pull/872

### Changed

- Update example version to v0.4.27 by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/870
- Adjust Default LogLevel to Warn by @gwbaik9717 in https://github.com/yorkie-team/yorkie-js-sdk/pull/871

## [0.4.27] - 2024-07-11

### Changed

- Add taskQueue to handle each request one by one by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/862

### Removed

- Remove Custom JSDOM by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/864
- Remove vitest-environment-custom-jsdom from dependencies by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/866
- Remove jsdom from dependencies by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/867

### Fixed

- Handle retry for syncLoop and watchLoop by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/863
- Handle ErrClientNotActivated and ErrClientNotFound by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/865
- Handle local changes correctly when receiving snapshot by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/868

## [0.4.26] - 2024-07-04

### Changed

- Update example version to v0.4.25 by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/858

### Fixed

- Remove node from indexes during GC by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/860

## [0.4.25] - 2024-07-03

### Added

- Add `doc.subscribe('status', callback)` function by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/828

### Changed

- Use module import style for Protobuf by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/853
- Remove reattach test code by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/855

## [0.4.24] - 2024-06-14

### Added

- Show removed node in devtools by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/835

## [0.4.23] - 2024-06-07

### Changed

- Update examples version to v0.4.22 by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/845

### Fixed

- Fix miscalculation of tree size in concurrent editing by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/846

## [0.4.22] - 2024-06-04

### Added

- Add RHTNode removal to converter for consistency by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/842

### Changed

- Update examples version to v0.4.21 by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/840
- Simplify type checking for style attributes in TreeStyleOpInfo by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/841

### Fixed

- Add conditional checks for `window` object by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/839

## [0.4.21] - 2024-06-03

### Changed

- Update example version to v0.4.20 by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/822
- Remove skip from style-style-test by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/829
- Include all nodes in tree.toJSInfoForTest by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/832
- Add ServerSeq into ChangeInfo by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/833

### Fixed

- Prevent remote-change events in RealtimeSyncOff mode by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/824
- Fix invalid error message in CRDTTreePos by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/830
- Fix incorrect tree snapshot encoding/decoding by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/836
- Fix incorrect indexes in TreeChange by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/837

## [0.4.20] - 2024-05-24

### Added

- Implement RHT.GC by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/815

### Changed

- Update examples version to v0.4.19 by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/812
- Enhance type inference in Document.subscribe by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/814
- Apply GCPair to TreeNode, TextNode by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/819

### Fixed

- Handle Tree.toXML to return proper XML string by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/805
- Avoid unnecessary syncs in push-only syncmode by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/818

## [0.4.19] - 2024-05-10

### Added

- Add Tree concurrency tests by @justiceHui, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/792

### Changed

- Update examples version to v0.4.18 by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/785
- Remove Client.subscribe by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/789
- Replace `benchmark.js` with `vitest bench` by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/793
- Replace webpack with vite by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/795
- Reset online clients when stream is disconnected by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/796
- Replace TSDoc with TypeDoc by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/800
- Add vite-plugin-dts to build yorkie-js-sdk.d.ts by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/801

### Fixed

- Export OpSource by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/786
- Add window type condition for using devtools by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/787
- Update GitHub Action workflow for create-yorkie-app by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/790
- Handle exception for the client without proper presence value in example by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/798
- Handle concurrent editing and styling in Tree by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/803
- Fix invalid tree style changes by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/804
- Fix gc for multiple nodes in text and tree type by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/806

## [0.4.18] - 2024-04-23

### Added

- Add history tab and enhance visualization features to devtools by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/760

## [0.4.17] - 2024-04-19

### Added

- Add RealtimeSyncOff and refactor interface of SyncMode by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/772

### Fixed

- Fix issue of incorrect display of remote selection in Quill example by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/769
- Reverse TreeChanges when Deleting in Tree by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/774
- Remove unnecessary stubs from the test code by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/776
- Provide CODECOV_TOKEN to codecov-action by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/777
- Fix issue of referencing process object on browser by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/778

## [0.4.16] - 2024-03-29

### Added

- Implement Protocol Changes for Tree.RemoveStyle by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/755

## [0.4.15] - 2024-03-11

### Added

- Implement Tree.RemoveStyle by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/745

### Changed

- Change actorID to be non-optional by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/747

### Fixed

- Fix invalid sync when editing multiple cursors in CodeMirror6 by @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/743
- Fix incorrect index returned when using posRangeToIndexRange by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/742
- Fix incorrect calculation in `indexTree.treePosToPath` operation by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/751
- Fix errors when editing Tree due to missing insPrevID in CRDTTree by @raararaara in https://github.com/yorkie-team/yorkie-js-sdk/pull/756
- Prevent remote-change events from occurring in push-only mode by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/759

## [0.4.14] - 2024-01-29

### Added

- Export LogLevel and setLogLevel @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/737
- Add design document for devtools extension by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/735

### Fixed

- Follow up work after devtools mvp by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/734
- Fix invalid TreeChanges in concurrent Tree.Style by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/738
- Restore interface changes due to server DB sharding by @sejongk https://github.com/yorkie-team/yorkie-js-sdk/pull/740

## [0.4.13] - 2024-01-19

### Added

- Implement devtools chrome extension by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/717

### Changed

- Reflect interface changes of server DB sharding by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/726
- Complement concurrent editing test cases in Tree by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/721
- Export devtools type by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/730
- Update examples version to v0.4.12 by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/722

### Fixed

- Fix multiple versions of prosemirror-model were loaded by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/728
- Fix invalid tree conversion by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/719

## [0.4.12] - 2024-01-05

### Added

- Add concurrent editing test cases in Tree by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/710

### Fixed

- Generate correct TreeChange in concurrent edits by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/712
- Add forced sync when switching to realtime mode by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/713
- Fix `getGarbageLen` to retrun correct size by @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/714
- Prevent deregisterElement from deregistering twice in nested object by @justiceHui in https://github.com/yorkie-team/yorkie-js-sdk/pull/716

## [0.4.11] - 2023-12-18

### Added

- Address duplicate node IDs in Tree.Split by @sejongk, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/707
- Add test filtering and log printing guide to CONTRIBUTING.md by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/708
- Support concurrent insertion and splitting in Tree by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/709

### Changed

- Migrate RPC to ConnectRPC by @krapie, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/698

## [0.4.10] - 2023-12-04

### Added

- Add create-yorkie-app by @se030, @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/690
- Implement splitLevel of Tree.Edit by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/704
- Add `removeIfNotAttached` to `client.detach()` options by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/703

### Fixed

- Fix reading wrong .env path by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/694
- Handle escape string for strings containing quotes by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/700
- Correct typos in the installation command on README.md in the example by @ymw0407 in https://github.com/yorkie-team/yorkie-js-sdk/pull/702

## [0.4.9] - 2023-11-25

### Added

- Implement merge elements in `Tree.Edit` by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/681
- Add README and thumbnail on example 'simultaneous-cursors'by @banma1234 in https://github.com/yorkie-team/yorkie-js-sdk/pull/683
- Support Undo/Redo for object.set and object.remove operations by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/658

### Changed

- Refactor ProseMirror example and Tree codes by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/686
- Enhance Set and Add for representing nested elements by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/691

### Fixed

- Add missing `removedAt` during Primitive deepcopy by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/692
- Prevent empty ops are applied during undo/redo by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/687

## [0.4.8] - 2023-11-01

### Changed

- Replace karma with vitest by @blurfx, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/665
- Remove vitest single thread config by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/667
- Publish npm package with provenance by @jongwooo in https://github.com/yorkie-team/yorkie-js-sdk/pull/669
- Update examples version to v0.4.7 by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/671
- Update nextjs-scheduler to export static files by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/672
- Bump browserify-sign from 4.2.1 to 4.2.2 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/678
- Bump @babel/traverse from 7.22.11 to 7.23.2 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/670

### Removed

- Remove redundant types from tree by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/666

### Fixed

- Fix missing collection of removed elements from the root by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/676
- Add more GC tests to reflect current server modifications by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/677
- Fit Next.js example style to the yorkie homepage by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/675
- Disable jekyll on github actions by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/674

## [0.4.7] - 2023-10-06

### Added

- Introduce basic architecture to support undo and redo by @hyemmie, @chacha912 and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/650
- Add Text devtool to CodeMirror example by @chacha912 and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/646
- Add DisableGC option to document by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/644
- Add toJS to return TreeNode of Tree by @JOOHOJANG and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/639
- Add Tree.Edit benchmark and improve performance by @JOOHOJANG and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/641
- Add simultaneous cursors example and Update examples to v0.4.6 by @YoonKiJin and @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/581
- Add nextjs-scheduler example by @banma1234 and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/637

### Changed

- Improve tldraw example performance by @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/640
- Drop node 16 support by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/653
- Strip internals from package d.ts files by @mojosoeun in https://github.com/yorkie-team/yorkie-js-sdk/pull/596
- Disable realtime sync in GC test (#656) by @sejongk and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/656

### Removed

- Remove unused trie by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/651
- Remove SelectOpInfo by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/636

### Fixed

- Support concurrent formatting of Text by @MoonGyu1 in https://github.com/yorkie-team/yorkie-js-sdk/pull/642
- Recover istanbul-instrumenter-loader to use debugger by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/659
- Recover Select to prevent unsupported operation by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/634

## [0.4.6] - 2023-08-25

### Added

- Build error on node 18+ by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/584
- Add .nvmrc to specify Node version to LTS by @kutta97 in https://github.com/yorkie-team/yorkie-js-sdk/pull/586
- Add client deactivation before unmount by @degurii in https://github.com/yorkie-team/yorkie-js-sdk/pull/595
- Add `presence.get()` to get presence value in doc.update() by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/600
- Add test for concurrent rich-text editing in the Peritext example by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/610
- Concurrent case handling for Yorkie.tree by @ehuas in https://github.com/yorkie-team/yorkie-js-sdk/pull/611
- Support multi-level and parital element selection by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/631

### Changed

- Move "Building & Testing" Guide to CONTRIBUTING.md by @g2hhh2ee in https://github.com/yorkie-team/yorkie-js-sdk/pull/589
- Define more specific condition to check whether the input is opened by @su-ram in https://github.com/yorkie-team/yorkie-js-sdk/pull/597
- Clean up methods related to presence by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/599
- Refactor presence event code in examples by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/614
- Change TreeNode to have IDs instead of insPrev, insNext by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/627
- Remove select operation from text by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/622
- Fix invalid path of style changes by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/632

### Removed

### Fixed

- Fix `pathToTreePos` TC by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/571
- Fix GC to remove all removed nodes by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/568
- Expose pathToIndex API by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/567
- Fix react-tldraw readme typo by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/598
- Fix event-related tests to be deterministic by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/602
- Fix high and critical vulnerabilities by @mojosoeun in https://github.com/yorkie-team/yorkie-js-sdk/pull/630

## [0.4.5] - 2023-07-20

### Added

- Move Presence from Client to Document by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/574
- Tree edit update by @ehuas in https://github.com/yorkie-team/yorkie-js-sdk/pull/576

### Changed

- Replace selection with presence by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/578
- Bump word-wrap from 1.2.3 to 1.2.4 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/575
- Bump up protobuf by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/570
- Prevent usage of `.` in JSONObject key by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/569

### Removed

- Remove duplicated test by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/564
- Remove InternalOpInfo by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/566

### Fixed

- Fix `pathToTreePos` TC by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/571
- Fix GC to remove all removed nodes by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/568
- Expose pathToIndex API by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/567

## [0.4.4] - 2023-07-05

### Changed

- Cleanup of test-related terminology by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/562
- Use TreeRangeStruct to represent tree selection by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/561

## [0.4.3] - 2023-06-29

### Added

- Apply garbage collection to tree by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/550

### Changed

- Cleanup TextChange by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/551

### Fixed

- Fix garbage collection bug by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/555

## [0.4.2] - 2023-06-19

### Added

- Support for OperationInfo inference on Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/535
- Add peer selection display example by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/544
- Implement Tree.Style and Tree.StyleByPath by @JOOHOJANG, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/542

## [0.4.1] - 2023-06-09

### Changed

- Bump vite from 3.2.5 to 3.2.7 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/531
- change to next method as synchronously by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/526
- Change the value of XXXChange to Change in Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/538
- Replace Tree.onChanges with Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/523

## [0.4.0] - 2023-06-05

### Added

- Implement yorkie.Tree for text editors using tree model by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/507

### Changed

- Bump socket.io-parser from 4.2.1 to 4.2.3 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/516
- Replace Text.onChanges with Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/519

## [0.3.5] - 2023-05-22

### Changed

- Bump yaml and husky by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/505
- Apply Integration of SDK and Admin RPC Server by @krapie in https://github.com/yorkie-team/yorkie-js-sdk/pull/512

### Fixed

- Fix quill example page image rendering issue by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/504
- Add actor to ChangeInfo / update api-reference by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/508

## [0.3.4] - 2023-04-18

### Added

- Add the `document.subscribe(targetPath, (event) => {})`, which enables users to subscribe to a specific target in a document by @chacha912 in #487
- Add the `document.getValueByPath()` to get the value of a document by specifying the path by @chacha912 in #487
- Add benchmark tests for yorkie.Document by @JOOHOJANG in #494
- Add client sync mode, which enables users to pause and resume remote changes by @chacha912 in #495
- Add x-shard-key to APIs by @hackerwins in #486
- Add yorkie user agent in grpc metadata by @emplam27 in #488

### Changed

- Change Counter.increase() to remove the decimal part instead of using Math.floor() when a decimal number is passed as an argument by @JOOHOJANG in #496

### Fixed

- Return undefined when searching for presence of non-existent peer by @chacha912 in #493

## [0.3.3] - 2023-03-24

### Added

- Add optimization option in production mode by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/474
- Add RemoveDocument API by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/480
- Add pause and resume to Client by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/482

### Changed

- Clarify the ClientEvent that is sent to client.subscribe by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/464
- Rename initialization to initialized in PeersChangedEvent by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/478

### Fixed

## [0.3.2] - 2023-02-27

### Fixed

- Fix ValueChange dependency by @krapie in https://github.com/yorkie-team/yorkie-js-sdk/pull/470

## [0.3.1] - 2023-02-27

### Added

- Add `delete` and `empty` method to `Text` data type by @cozitive in https://github.com/yorkie-team/yorkie-js-sdk/pull/454

### Changed

- Reduce bundle size for production by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/460
- Remove string dependency of RGATreeSplit value by @cozitive in https://github.com/yorkie-team/yorkie-js-sdk/pull/459
- Remove priority queue from RHTPQMap and entire project by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/462
- Modify config to run the webpack-bundle-analyzer when using `profile:bundle` script by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/468

### Fixed

- Fix invalid indexOf SplayTree with single node by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/463

## [0.3.0] - 2023-01-31

### Changed

- Merge Text and RichText by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/425
- Fix the value type of Counter and remove double type from Counter by @cozitive in https://github.com/yorkie-team/yorkie-js-sdk/pull/426
- Let Client.attach wait until stream initialization is finished by @cozitive in https://github.com/yorkie-team/yorkie-js-sdk/pull/440
- Add the toJS method to the ObjectProxy's handler by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/449

### Fixed

- Increase CRDT Counter in local change by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/441

## [0.2.20] - 2022-12-30

### Added

- Add benchmark tests by @parkeunae in #358, #359
- Add CodeMirror6 integration example by @blurfx in #394
- Add vuejs-kanban example by @hackerwins in #399
- Add profile-stack example by @chacha912 #414

### Changed

- Bump socket.io-parser from 4.0.4 to 4.0.5 by @dependabot in #403
- Bump engine.io and socket.io by @dependabot in #407
- Bump express from 4.17.1 to 4.18.2 by @dependabot in #411
- Bump minimatch from 3.0.4 to 3.1.2 by @dependabot in #412

### Fixed

- Fix issues identified during iOS SDK development by @hackerwins in #398
- Use uint64 for date value by @hackerwins in #408

## [0.2.19] - 2022-10-04

### Changed

- Rename keyOf to subPathOf: #391

### Fixed

- Remove unused nodeMapByCreatedAt in RHT: #386
- Change lamport from uint64 to int64: #390

## [0.2.16] - 2022-08-16

### Changed

- Apply generics to support any types of properties in RichText: #354

### Fixed

- Send peers-changed event to the user who updated one's own presence: #371
- Fix the error that occurs when importing JS SDK in Next.js: #378

## [0.2.15] - 2022-08-08

### Added

- Add snapshot event observer to Quill example: #365

### Changed

- Bump up proto files to the latest: #367
- Export Change APIs to generate history snapshots in admin: #368
- Change trie traverse parameter name to isTerminalIncluded: #363

## [0.2.14] - 2022-08-03

### Added

- Reduce the number of paths of change events: #351

### Fixed

- Fix the problem local changes were applied twice: #356
- Update CodeMirror example to handle snapshot events: #360

## [0.2.13] - 2022-07-27

### Added

- Support Quill embeds type to example project: #344

### Fixed

- Fix a bug when overwriting in Object: #349

## [0.2.12] - 2022-07-20

### Fixed

- Fix incorrect index for nodes newly created then concurrently removed: #334
- Fix initial value bug in counter proxy: #333

## [0.2.11] - 2022-07-14

### Fixed

- Escape string to return valid json: #330

## [0.2.10] - 2022-07-06

### Added

- Implement array methods with objects: #327

### Changed

- Improve performance deletion in Text: #326

### Fixed

- Fix a bug when deleting blocks concurrently: #328

## [0.2.9] - 2022-06-30

### Changed

- Implement inserting elements with splice() method: #318

### Fixed

- Revert text deletion improvements: #323

## [0.2.8] - 2022-06-22

### Added

- Add read-only Array methods to ArrayProxy: #310
- Add Array.splice to ArrayProxy: #317

### Changed

- Use types more strictly in Document.update: #314
- Revert Document and Text: #47478e7
- Improve performance deletion in Text: #312, #316

### Fixed

- Remove size cache from RGATreeList and use SplayTree instead: #315
- Fix bug when setting non-string values in Presence: #311

## [0.2.7] - 2022-05-25

### Fixed

- Expose constructors for user-accessible types

## [0.2.6] - 2022-05-25

### Changed

- Refine SDK interface: #300

## [0.2.5] - 2022-05-12

### Added

- Add apiKey option: #295

## [0.2.4] - 2022-05-10

### Changed

- Fix incorrect type hint in document.update handler: #289
- Rename Client Metadata to Presence: #293

### Removed

- Remove collection from document: #292

## [0.2.3] - 2022-04-07

### Changed

- Bump up yorkie.proto to 0.2.3

## [0.2.0] - 2021-12-19

2nd Year Release

### Added

- Garbage collection for Text and RichText
- Improve Client's metadata to be updatable
- Improved Peer Awareness
- Supporting TLS and Auth webhook

### Changed

### Removed

### Deprecated

## [0.1.11] - 2021-12-04

### Fixed

- Fix a bug where text nodes with tombstones were not counted: #263

## [0.1.10] - 2021-11-16

### Added

- Add Array.toJS() and Object.toJS(): #237

### Changed

- Print log message more accurately: #5ce95c6, #de05448

### Fixed

- Fix quill example page: #260

## [0.1.8] - 2021-10-21

### Fixed

- Hide clock from value of peers-changed event

## [0.1.7] - 2021-10-19

### Added

- Improve Client's metadata to be updatable: #240

### Fixed

- Fix reduce array size when deleting the same position: #229
- Handle special characters in keys of the path in change events: #247

## [0.1.6] - 2021-07-24

### Added

- Add client.getStatus and client.Metadata: #162f2d5

### Changed

- Change getElementByID to return undefined if the element doesnt exist: #208
- Change esnext to ES2019 in compiler target option: #197
- Clean up JS SDK Reference: #181, #218, #219

### Fixed

- Fix a bug where deleted values from objects are revivded after GC: #216

## [0.1.5] - 2021-06-05

### Added

- Add moveFront, moveAfter, moveLast, insertBefore to Array: #194, #203, #206, #207
- Add AuthInterceptor: #199

### Fixed

- Fix the concurrent editing issue of Move Operation: #196
- Fix a bug when pushing an array element in Array: #200

### Removed

- Delete RequestHeader in Protobuf

## [0.1.4] - 2021-05-15

### Added

### Changed

- Rename Document.getKey().toIDString() to Document.getKey(): #178
- Only display exported objects in JS SDK Reference: #179
- Rename Document to DocumentReplica: #10f2b72

### Fixed

- Fix a bug occurs when setting an empty string as a key: #182
- Fix a bug that the first element of an array was not deleted: #185
- Fix a bug that the size of the array increases when moving element: #186
- Fix a bug that did not move after pushing in same update: #188

## [0.1.3] - 2021-04-04

### Added

- Pass paths to change events: #162
- Support null and undefined values: #157
- Add type parameter to Document: #148

### Changed

- Rename getRootObject to getRoot: #158
- Rename updateSelection to select: #170

### Fixed

- Fix error that occurred when deleting value using missing key or index: #149
- Fix invalid states of SplayTree: #153
- Remove errors that occur when insPrev does not exist: #166

## [0.1.2] - 2021-02-14

### Added

- Add customizable metadata for peer awareness: #123
- Add garbage collection for Text and RichText: #137

### Changed

- Replace the type of client_id to a byte array to reduce payload: #133

### Fixed

- Fix a bug that attributes were lost when splitting RichText nodes: #136

## [0.1.1] - 2021-01-01

### Added

- Add garbage collect for Container type: #101

### Changed

- Update libs to fix security vulnerability: #103

### Fixed

- Fix quill paragraph style errors: #104
- Change Logger to receive all values: #100

## [0.1.0] - 2020-11-07

First public release

### Added

- Add `Client` and `Document`
- Add Custom CRDT data type `Text` for code editor
- Add Custom CRDT data type `RichText` for WYSIWYG editor
- Add examples: CodeMirror, Drawing, Quill
- Support Network Auto Recovery
- Add Peer Awareness
- Add Custom CRDT data type `Counter`

### Changed

### Removed

### Deprecated

[unreleased]: https://github.com/yorkie-team/yorkie-js-sdk/compare/v0.1.0...HEAD
[0.1.0]: https://github.com/yorkie-team/yorkie-js-sdk/releases/tag/v0.1.0#


================================================
FILE: CLAUDE.md
================================================
# Yorkie JavaScript SDK

pnpm monorepo with multiple packages for building collaborative editing applications.

## Development Commands

```sh
pnpm i                       # Install (pnpm enforced)
pnpm sdk build               # Build core SDK
pnpm sdk build:proto         # Regenerate protobuf code (buf generate)
pnpm lint                    # ESLint with auto-fix (zero warnings enforced)

# Tests require a running Yorkie server:
docker compose -f docker/docker-compose.yml up --build -d
pnpm sdk test                # Run all SDK tests
pnpm sdk test test/integration/tree_test.ts  # Specific test file
```

Package filters: `pnpm sdk`, `pnpm react`, `pnpm schema`, `pnpm prosemirror`, `pnpm devtools`

## After Making Changes

Always run before submitting:
```sh
pnpm lint && pnpm sdk build && pnpm sdk test
```

## Project Docs

- **Design docs**: `docs/design/` for architectural context. New docs use [TEMPLATE.md](docs/design/TEMPLATE.md).
- **Task tracking**: `docs/tasks/active/` for in-progress, `docs/tasks/archive/` for completed. Use `YYYYMMDD-<slug>-{todo,lessons}.md` pairs.
- **Setup**: Husky manages git hooks. Run `pnpm install` to set up automatically.

## Packages

- **`sdk`** (`@yorkie-js/sdk`) — Core: client, documents, CRDTs, protobuf API
- **`react`** (`@yorkie-js/react`) — React hooks/providers
- **`prosemirror`** (`@yorkie-js/prosemirror`) — ProseMirror binding
- **`schema`** (`@yorkie-js/schema`) — ANTLR-based schema validation (`antlr/YorkieSchema.g4`)
- **`devtools`** (`@yorkie-js/devtools`) — Chrome extension (Plasmo)
- **`mcp`** — Model Context Protocol integration

## Gotchas

- Protobuf source of truth is in [yorkie-team/yorkie](https://github.com/yorkie-team/yorkie/tree/main/api), not this repo
- ESLint enforces zero warnings — CI and pre-commit hooks will reject any warnings
- Tests use Vitest with custom-jsdom environment
- Use `.only` on `describe`/`it` blocks to run specific tests within a file
- Prettier config: single quotes, trailing commas, 80 char width

## Key Design Pattern

Internal state uses CRDTs (`crdt/`). Users interact through JSON proxies (`json/`) that automatically generate operations on mutation. Every operation is tagged with a `TimeTicket` (lamport timestamp + actorID).


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

## How to contribute

Yorkie is Apache 2.0 licensed and accepts contributions via GitHub pull requests. This document outlines some of the
conventions on commit message formatting, contact points for developers, and other resources to help get contributions
into Yorkie.

### Contacts

If you have any questions along the way, please don’t hesitate to ask us

- Discord: [Yorkie Discord](https://discord.com/invite/MVEAwz9sBy).

### Getting started

- Fork the repository on GitHub
- Read
  the [CONTRIBUTING.md](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/CONTRIBUTING.md#building-yorkie-js-sdk)
  for build instructions

## Contribution flow

This is a rough outline of what a contributor's workflow looks like:

- Create a topic branch from where to base the contribution. This is usually main
- Make commits of logical units
- Make sure commit messages are in the proper format
- Push changes in a topic branch to a personal fork of the repository
- Submit a pull request to yorkie-team/yorkie-js-sdk
- The PR must receive a LGTM from maintainers

Thanks for contributing!

## Building and Testing the SDK

### Building yorkie-js-sdk

For building yorkie-js-sdk, You'll first need Node.js installed(Node.js version 18+ and pnpm version 9.6+ are required).

- [Node.js](https://nodejs.org/en) (version 18+)
- [pnpm](https://pnpm.io/) (version 9.6+)

```bash
# install packages

# In the root directory of the repository.
$ pnpm i

# build

# In the root directory of the repository.
$ pnpm sdk build
```

To generate proto messages, we use protoc-gen-connect-es, which is a code generator plugin for Protocol Buffer compilers, like buf and protoc. It generates both clients and server definitions from Protocol Buffer schema.

For more details, see [@connectrpc/protoc-gen-connect-es](https://github.com/connectrpc/connect-es/tree/main/packages/protoc-gen-connect-es).

```bash
# generate proto messages and the service client stub classes

# In the root directory of the repository.
$ pnpm sdk build:proto
```

> Primary "source of truth" location of protobuf message is
> in [yorkie](https://github.com/yorkie-team/yorkie/tree/main/api). We manage the messages in the repository.

### Testing yorkie-js-sdk with Yorkie and MongoDB.

Start MongoDB, Yorkie in a terminal session.

```bash
$ docker compose -f docker/docker-compose.yml up --build -d
```

Start the test in another terminal session.

```bash
# In the root directory of the repository.
$ pnpm sdk test
```

To get the latest server locally, run the command below then restart containers again:

```bash
$ docker pull yorkieteam/yorkie:latest
$ docker compose -f docker/docker-compose.yml up --build -d
```

To print specific console logs, delete the line `return false` in the `onConsoleLog()` function within [`vitest.config.ts`](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/vitest.config.ts#L16).

```ts
export default defineConfig({
  test: {
    include: ['**/*_{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
    exclude: ['**/bench/*'],
    coverage: {
      provider: 'istanbul',
      reporter: ['lcov', 'text-summary'],
    },
    onConsoleLog() {
      return false; // <<------ delete here.
    },
    environment: 'custom-jsdom',
    globals: true,
    testTimeout: isCI ? 5000 : Infinity,
  },
  plugins: [tsconfigPaths()],
});
```

To run only specific suites or tests, use `.only` and execute the following command with the path to the desired test file.
Refer to [Test Filtering](https://vitest.dev/guide/filtering#selecting-suites-and-tests-to-run) in `vitest` for more details:

```bash
# In the root directory of the repository.
$ pnpm sdk test {test file path} # e.g. pnpm sdk test integration/tree_test.ts
```

### Starting co-editing example with CodeMirror

Start MongoDB and Yorkie in a terminal session.

```bash
$ docker compose -f docker/docker-compose.yml up --build -d
```

Start the webpack-dev-server in another terminal session.

```bash
# In the root directory of the repository.
$ pnpm sdk dev
```

Open the co-editing example page served by webpack-dev-server in your browser.

```bash
$ open http://0.0.0.0:9000/
```

### Code style

In order to format the code, we use [Husky](https://github.com/typicode/husky) to implement git hooks
and [Prettier](https://github.com/prettier/prettier)

Commit message validation is handled by Husky (`.husky/commit-msg`),
which is set up automatically when you run `pnpm install`.

### Format of the commit message

We follow a rough convention for commit messages that is designed to answer two questions: what changed and why. The
subject line should feature the what and the body of the commit should describe the why.

```
Remove the synced seq when detaching the document

To collect garbage like CRDT tombstones left on the document, all
the changes should be applied to other replicas before GC. For this
, if the document is no longer used by this client, it should be
detached.
```

The first line is the subject and should be no longer than 70 characters, the second line is always blank, and other
lines should be wrapped at 80 characters. This allows the message to be easier to read on GitHub as well as in various
git tools.

## Contributor License Agreement

We require that all contributors sign our Contributor License Agreement ("CLA") before we can accept the contribution.

### Signing the CLA

Open a pull request ("PR") to any of our open source projects to sign the CLA. A bot will comment on the PR asking you
to sign the CLA if you haven't already.

Follow the steps given by the bot to sign the CLA. This will require you to log in with GitHub. We will only use this
information for CLA tracking. You only have to sign the CLA once. Once you've signed the CLA, future contributions to
the project will not require you to sign again.

### Why Require a CLA?

Agreeing to a CLA explicitly states that you are entitled to provide a contribution, that you cannot withdraw permission
to use your contribution at a later date, and that Yorkie Team has permission to use your contribution.

This removes any ambiguities or uncertainties caused by not having a CLA and allows users and customers to confidently
adopt our projects. At the same time, the CLA ensures that all contributions to our open source projects are licensed
under the project's respective open source license, such as Apache-2.0 License.

Requiring a CLA is a common and well-accepted practice in open source. Major open source projects require CLAs such as
Apache Software Foundation projects, Facebook projects, Google projects, Python, Django, and more. Each of these
projects remains licensed under permissive OSS licenses such as MIT, Apache, BSD, and more.


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: MAINTAINING.md
================================================
# Maintaining yorkie-js-sdk

## Releasing a New Version Of Yorkie JS SDK

### 1. Update the version number.

Update `version` in **all** publishable packages. All packages must be bumped together to keep versions in sync:

- [packages/sdk/package.json](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/packages/sdk/package.json#L3)
- [packages/react/package.json](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/packages/react/package.json#L3)
- [packages/schema/package.json](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/packages/schema/package.json#L3)
- [packages/prosemirror/package.json](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/packages/prosemirror/package.json#L3)
- [packages/devtools/package.json](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/packages/devtools/package.json#L4)

> **Note:** The [npm-publish workflow](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/.github/workflows/npm-publish.yml) publishes sdk, react, schema, and prosemirror on every release. If a package version is not bumped, npm publish will fail with a version conflict.

### 2. Write changelog of this version in [CHANGELOG.md](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/CHANGELOG.md).

Copy the release notes automatically generated by GitHub and categorize them as `Added`/`Changed`/`Fixed`.

1. Click on the `Releases` in GitHub.
2. Click on the `Draft a new release` button.
3. Create a new tag.
4. Click on the `Generate release notes` button.
5. Copy the content generated into the body and categorize each item.

<img width="600" alt="image" src="https://user-images.githubusercontent.com/81357083/233356577-acc1dd33-5ad5-4b51-9f2e-6c771a063ccd.png">

### 3. Create [Pull Request](https://github.com/yorkie-team/yorkie-js-sdk/commits/main/CHANGELOG.md) for changelog and merge it into main.

### 4. Publish [a new release](https://github.com/yorkie-team/yorkie-js-sdk/releases/new).

After creating the release in step 2, click on the `Publish release` button.

### 5. Deploy

When you publish the release in step 4, [GitHub action](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/.github/workflows/npm-publish.yml) will deploy Yorkie JS SDK to [npm](https://www.npmjs.com/package/yorkie-js-sdk).  
After that, it will be updated on the [cdn](https://cdnjs.com/libraries/yorkie-js-sdk) after some time.


================================================
FILE: README.md
================================================
# Yorkie JavaScript SDK

[![codecov](https://codecov.io/gh/yorkie-team/yorkie-js-sdk/branch/main/graph/badge.svg)](https://codecov.io/gh/yorkie-team/yorkie-js-sdk)

The Yorkie JavaScript SDK implements the client-side libraries.

## How to use JS SDK

To get started using Yorkie JavaScript SDK, see: https://yorkie.dev/docs/sdks/js-sdk

## Packages

This is a pnpm monorepo. See each package's README for details:

- [packages/sdk/](packages/sdk/README.md) — Core SDK (`@yorkie-js/sdk`): client, documents, CRDTs
- [packages/react/](packages/react/README.md) — React hooks and providers (`@yorkie-js/react`)
- [packages/prosemirror/](packages/prosemirror/README.md) — ProseMirror binding (`@yorkie-js/prosemirror`)
- [packages/schema/](packages/schema/README.md) — Schema validation (`@yorkie-js/schema`)
- [packages/devtools/](packages/devtools/README.md) — Chrome devtools extension (`@yorkie-js/devtools`)
- [examples/](examples/README.md) — Sample apps using the SDK

## Documentation

- [docs/design/](docs/design/README.md) — Architectural design documents
- [docs/tasks/](docs/tasks/README.md) — Task tracking (active and archived)
- [CHANGELOG.md](CHANGELOG.md) — Release notes
- [MAINTAINING.md](MAINTAINING.md) — Release and maintenance procedures
- [CLAUDE.md](CLAUDE.md) — Agent instructions for AI-assisted development

## Contributing

See [CONTRIBUTING](CONTRIBUTING.md) for details on submitting patches and the contribution workflow.

## Contributors ✨

Thanks goes to these incredible people:

<a href="https://github.com/yorkie-team/yorkie-js-sdk/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=yorkie-team/yorkie-js-sdk" />
</a>



================================================
FILE: codecov.yml
================================================
coverage:
  status:
    project: off
    patch: off


================================================
FILE: docker/docker-compose-ci.yml
================================================
services:
  yorkie:
    image: "yorkieteam/yorkie:latest"
    container_name: "yorkie"
    command:
      [
        "server",
        "--mongo-connection-uri",
        "mongodb://mongo:27017",
      ]
    restart: always
    ports:
      - "8080:8080"
      - "8081:8081"
    depends_on:
      - mongo
    extra_hosts:
      - "host.docker.internal:host-gateway"
  mongo:
    image: "mongo:latest"
    container_name: "mongo"
    restart: always
    ports:
      - "27017:27017"


================================================
FILE: docker/docker-compose.yml
================================================
services:
  yorkie:
    image: "yorkieteam/yorkie:latest"
    container_name: "yorkie"
    command:
      ["server", "--pprof-enabled"]
    restart: always
    ports:
      - "8080:8080"
      - "8081:8081"
    extra_hosts:
      - "host.docker.internal:host-gateway"


================================================
FILE: eslint.config.mjs
================================================
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import prettierPlugin from 'eslint-plugin-prettier';
import jsdocPlugin from 'eslint-plugin-jsdoc';
import { globalIgnores } from 'eslint/config';

export default tseslint.config(
  eslint.configs.recommended,
  tseslint.configs.recommended,
  tseslint.configs.eslintRecommended,
  {
    plugins: {
      prettier: prettierPlugin,
      jsdoc: jsdocPlugin,
    },
    rules: {
      'prettier/prettier': 'error',
      'object-shorthand': ['error', 'always'],
      'no-unreachable': 'error',
    },
  },
  {
    files: ['**/*.ts', '**/*.tsx'],
    languageOptions: {
      parser: tseslint.parser,
    },
    rules: {
      '@typescript-eslint/no-non-null-assertion': 'off',
      '@typescript-eslint/no-explicit-any': 'off',
      '@typescript-eslint/ban-ts-comment': 'off',

      'jsdoc/require-jsdoc': [
        'error',
        {
          contexts: ['MethodDefinition:not([accessibility="private"])'],

          require: {
            ClassDeclaration: true,
          },

          checkConstructors: false,
          enableFixer: false,
        },
      ],

      '@typescript-eslint/naming-convention': [
        'error',
        {
          selector: 'variable',
          format: ['camelCase', 'PascalCase'],
          leadingUnderscore: 'allowDouble',
          trailingUnderscore: 'allowDouble',
        },
      ],

      '@typescript-eslint/no-restricted-types': [
        'error',
        {
          types: {
            null: 'Use undefined instead of null',
          },
        },
      ],

      '@typescript-eslint/array-type': [
        'error',
        {
          default: 'generic',
        },
      ],

      '@typescript-eslint/no-this-alias': [
        'error',
        {
          allowDestructuring: true,
          allowedNames: ['node'],
        },
      ],
    },
  },
  {
    files: ['examples/**/*'],
    rules: {
      'jsdoc/require-jsdoc': 'off',
    },
  },
  globalIgnores([
    // common
    '**/dist/*',
    '**/lib/*',
    // sdk
    'packages/sdk/src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts',
    'packages/sdk/src/api/yorkie/v1/yorkie_pb.d.ts',
    'packages/sdk/src/api/yorkie/v1/resources_grpc_web_pb.d.ts',
    'packages/sdk/src/api/yorkie/v1/resources_pb.d.ts',
    'packages/sdk/test/vitest.d.ts',
    // examples
    'examples/**/*',
    // schema
    'packages/schema/antlr',
  ]),
);


================================================
FILE: examples/CONTRIBUTING.md
================================================
# Contributing

See [CONTRIBUTING.md](../CONTRIBUTING.md) for the general guides for contribution.

## Keeping create-yorkie-app in sync with examples

When adding a new example, you have to update create-yorkie-app's [frameworks.ts](../tools//create-yorkie-app/frameworks.ts).

Add FrameworkVariant to the variants array under appropriate category like:

```js
export const FRAMEWORKS: Array<Framework> = [
  {
    name: 'vanilla',
    display: 'Vanilla',
    color: yellow,
    variants: [
      {
        name: 'vanilla-codemirror6',
        display: 'codemirror',
      },
      {
        name: 'vanilla-quill',
        display: 'quill',
      },
      {
        name: 'profile-stack',
        display: 'profile-stack',
      },
      // Your yorkie example in Vanilla JS
      {
        name: 'directory-name',
        display: 'display-name',
      },
    ],
  },
  // ...
];
```


================================================
FILE: examples/README.md
================================================
# Examples

This directory contains examples of how to use Yorkie in various libraries and frameworks.

## Usage

All examples need to run the Yorkie server. So you should run the server before running examples.

```bash
# In the root directory of the repository.
$ docker compose -f docker/docker-compose.yml up --build -d
```

The examples have own local dependencies. So you should install dependencies before running examples.

```bash
# In the root directory of the repository.
$ pnpm install
```

Then you can run the examples.

```bash
# In the root directory of the repository.
$ pnpm <EXAMPLE-NAME> dev

# Or in the directory of the example.
$ pnpm dev
```

Open the browser and go to the URL that is printed in the terminal.

## Releasing an example to https://yorkie.dev

To release an example, the example should export static files to `./dist` directory when running `pnpm <EXAMPLE-NAME> build` in the root directory of the repository or `pnpm build` in the directory of the example.

After the example is merged to the `main` branch, it is automatically deployed to https://yorkie.dev/yorkie-js-sdk/examples/{EXAMPLE-NAME}.

## Examples

- [nextjs-presence](nextjs-presence/README.md)
- [nextjs-scheduler](nextjs-scheduler/README.md)
- [nextjs-todolist](nextjs-todolist/README.md)
- [profile-stack](profile-stack/README.md)
- [react-document-limit](react-document-limit/README.md)
- [react-flow](react-flow/README.md)
- [react-tldraw](react-tldraw/README.md)
- [react-todomvc](react-todomvc/README.md)
- [simultaneous-cursors](simultaneous-cursors/README.md)
- [vanilla-codemirror6](vanilla-codemirror6/README.md)
- [vanilla-document-limit](vanilla-document-limit/README.md)
- [vanilla-prosemirror](vanilla-prosemirror/README.md)
- [vanilla-quill](vanilla-quill/README.md)
- [vuejs-kanban](vuejs-kanban/README.md)

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for guidance on contributing new examples.


================================================
FILE: examples/nextjs-presence/.gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/
/dist/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts


================================================
FILE: examples/nextjs-presence/README.md
================================================
# Yorkie Presence Rooms - Next.js Example

<p>
    <a href="https://yorkie.dev/yorkie-js-sdk/examples/nextjs-presence/" target="_blank">
        <img src="https://img.shields.io/badge/preview-message?style=flat-square&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMTUiIHZpZXdCb3g9IjAgMCAyNCAxNSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTYuODU3MTcgMi43ODE5OUwxMS4yNzUxIDkuMTI2NzhDMTEuNTU0NCA5LjUyODAxIDEyLjEwNjIgOS42MjY3NiAxMi41MDc0IDkuMzQ3NDRDMTIuNTkzNCA5LjI4NzUgMTIuNjY4MSA5LjIxMjggMTIuNzI4MSA5LjEyNjc4TDE3LjE0NiAyLjc4MTk5QzE3LjcwNDggMS45Nzk1NCAxNy41MDcyIDAuODc2MTMxIDE2LjcwNDggMC4zMTc0OTRDMTYuNDA4IDAuMTEwODM3IDE2LjA1NSAwIDE1LjY5MzIgMEg4LjMxMDAxQzcuMzMyMiAwIDYuNTM5NTUgMC43OTI2NTQgNi41Mzk1NSAxLjc3MDQ2QzYuNTM5NjggMi4xMzIxMSA2LjY1MDUxIDIuNDg1MTEgNi44NTcxNyAyLjc4MTk5WiIgZmlsbD0iIzUxNEM0OSIvPgo8cGF0aCBkPSJNMTMuODA4OSAxNC4yMzg4QzE0LjEyMzEgMTQuNDE4IDE0LjQ4NDcgMTQuNDk2NiAxNC44NDUgMTQuNDY0MkwyMi45MjYgMTMuNzM1QzIzLjU3NTMgMTMuNjc2NSAyNC4wNTQgMTMuMTAyNyAyMy45OTU1IDEyLjQ1MzVDMjMuOTkyNCAxMi40MTkyIDIzLjk4NzggMTIuMzg1MSAyMy45ODE3IDEyLjM1MTNDMjMuNzM4OSAxMC45OTY4IDIzLjI2MTEgOS42OTUyNyAyMi41Njk5IDguNTA1NDZDMjEuODc4NiA3LjMxNTY1IDIwLjk4NDggNi4yNTU3NyAxOS45Mjg2IDUuMzczOTFDMTkuNDI4MiA0Ljk1NjE0IDE4LjY4MzkgNS4wMjMwNyAxOC4yNjYyIDUuNTIzNTZDMTguMjQ0MiA1LjU0OTkgMTguMjIzMyA1LjU3NzI2IDE4LjIwMzYgNS42MDU1MUwxMy41NjcgMTIuMjY0MUMxMy4zNjAzIDEyLjU2MSAxMy4yNDk1IDEyLjkxNCAxMy4yNDk1IDEzLjI3NThWMTMuMjUzN0MxMy4yNDk1IDEzLjQ1NjIgMTMuMzAxNiAxMy42NTU0IDEzLjQwMDggMTMuODMxOUMxMy41MDUgMTQuMDA1NCAxMy42NTIxIDE0LjE0OTMgMTMuODI4MSAxNC4yNDk2IiBmaWxsPSIjRkRDNDMzIi8+CjxwYXRoIGQ9Ik0xMC42NDE2IDEzLjc0MzRDMTAuNTM3NSAxMy45NTU5IDEwLjM3MiAxNC4xMzIyIDEwLjE2NjUgMTQuMjQ5NEwxMC4xOTE1IDE0LjIzNTFDOS44NzczNCAxNC40MTQzIDkuNTE1NjkgMTQuNDkyOSA5LjE1NTQ0IDE0LjQ2MDVMMS4wNzQ0MSAxMy43MzEzQzEuMDQwMTggMTMuNzI4MyAxLjAwNjA3IDEzLjcyMzcgMC45NzIyMjUgMTMuNzE3NkMwLjMzMDYyIDEzLjYwMjUgLTAuMDk2MzExOSAxMi45ODkyIDAuMDE4NzI0MiAxMi4zNDc2QzAuMjYxNTIyIDEwLjk5MyAwLjczOTM1NCA5LjY5MTU2IDEuNDMwNDYgOC41MDE2M0MyLjEyMTU3IDcuMzExNjkgMy4wMTU1MSA2LjI1MjA2IDQuMDcxODQgNS4zNzAwOEM0LjA5ODE4IDUuMzQ4MDYgNC4xMjU1NCA1LjMyNzE5IDQuMTUzNzkgNS4zMDc0N0M0LjY4ODc2IDQuOTM1IDUuNDI0MjcgNS4wNjY3MSA1Ljc5Njg3IDUuNjAxNjhMMTAuNDMzNCAxMi4yNjA0QzEwLjY0MDEgMTIuNTU3MyAxMC43NTA5IDEyLjkxMDMgMTAuNzUwOSAxMy4yNzIxVjEzLjI0MzJDMTAuNzUwOSAxMy40Nzk3IDEwLjY3OTggMTMuNzExIDEwLjU0NjggMTMuOTA2NyIgZmlsbD0iI0ZEQzQzMyIvPgo8L3N2Zz4K&color=FEF3D7" alt="Live Preview" />
    </a>
</p>

A Next.js application demonstrating real-time user presence tracking across multiple rooms using [Yorkie](https://yorkie.dev).

## 🚀 Features

- **Multiple Rooms**: Switch between different chat rooms with independent presence tracking
- **Real-time Updates**: See sessions join and leave in real-time
- **Secure API Handling**: Secret keys are handled server-side via Next.js API Routes
- **Beautiful UI**: Modern gradient design with smooth animations
- **Responsive**: Works great on desktop and mobile devices

## 🔒 Security

This example supports two deployment modes:

### 1. Full-Featured Mode (with API Routes)

Uses **Next.js API Routes** to securely handle the Yorkie Admin API calls that require a secret key. The secret key is never exposed to the client browser.

**Architecture:**

- **Client Side**: Uses `NEXT_PUBLIC_YORKIE_API_KEY` for user authentication
- **Server Side (API Route)**: Uses `YORKIE_API_SECRET_KEY` for admin operations
- **API Endpoint**: `/api/channels` handles secure server-side requests to Yorkie's Admin API
- **Features**: Shows real-time presence counts for all rooms

### 2. Static Hosting Mode (GitHub Pages, etc.)

When deployed to static hosting platforms without a backend, the example still works with basic functionality.

**Architecture:**

- **Client Side Only**: Uses `NEXT_PUBLIC_YORKIE_API_KEY` for user authentication
- **No Secret Key**: Leave `YORKIE_API_SECRET_KEY` empty
- **Features**: Room presence tracking works, but initial presence counts show as 0

## 📋 Prerequisites

- Node.js 18+ and pnpm
- A Yorkie account with API keys from [Yorkie Dashboard](https://yorkie.dev/dashboard)

## 🛠️ Setup

1. Clone the repository and navigate to this example:

```bash
cd examples/nextjs-presence
```

2. Install dependencies:

```bash
pnpm install
```

3. Create a `.env.local` file in the root of this example with your Yorkie credentials:

**For Full-Featured Mode (with server):**

```bash
# Client-side API key (safe to expose)
NEXT_PUBLIC_YORKIE_API_KEY=your-api-key-here
NEXT_PUBLIC_YORKIE_API_ADDR=https://api.yorkie.dev

# Server-side secret key (NEVER expose to client)
# Setting this enables API server features
YORKIE_API_SECRET_KEY=your-secret-key-here
```

**For Static Hosting Mode (GitHub Pages, etc.):**

```bash
# Client-side API key (safe to expose)
NEXT_PUBLIC_YORKIE_API_KEY=your-api-key-here
NEXT_PUBLIC_YORKIE_API_ADDR=https://api.yorkie.dev

# Leave secret key empty for static hosting
YORKIE_API_SECRET_KEY=
```

> ⚠️ **Important**: Never commit your `.env.local` file or expose your secret key in client-side code!

## 🏃 Running the Example

```bash
# Development mode
pnpm dev

# Production build
pnpm build
pnpm start
```

Open [http://localhost:3000](http://localhost:3000) in multiple browser windows to see session counting in action!

## 📁 Project Structure

```text
nextjs-presence/
├── app/
│   ├── api/
│   │   └── channels/
│   │       └── route.ts          # Server-side API route (uses secret key)
│   ├── layout.tsx                # Root layout
│   ├── page.tsx                  # Main app component
│   ├── App.css                   # App styles
│   └── globals.css               # Global styles
├── components/
│   ├── RoomSelector.tsx          # Room selection component
│   ├── RoomSelector.css
│   ├── RoomView.tsx              # Individual room view
│   ├── RoomView.css
│   ├── SessionCounter.tsx        # Online session counter component
│   └── SessionCounter.css
├── .env                          # Example env file
├── .env.production               # Production env template
├── package.json
├── next.config.ts
└── README.md
```

## 🎯 How It Works

1. **Room Selection**: Users select a room from the main screen
2. **API Route**: Client fetches presence data from `/api/channels` (server-side)
3. **Server Request**: API route uses secret key to call Yorkie Admin API
4. **Real-time Connection**: Upon entering a room, client connects with `ChannelProvider`
5. **Presence Tracking**: `useChannel` hook tracks real-time session count
6. **Live Updates**: UI updates automatically as sessions join/leave

## 🔑 Environment Variables

### Client-side (NEXT*PUBLIC*\*)

- `NEXT_PUBLIC_YORKIE_API_KEY`: Your Yorkie API key for client authentication
- `NEXT_PUBLIC_YORKIE_API_ADDR`: Yorkie API server address

### Server-side

- `YORKIE_API_SECRET_KEY`: Your Yorkie secret key (used in API routes only)

## 🧪 Testing

1. Open the app in multiple browser windows or tabs
2. Select different rooms in each window
3. Watch the session counters update in real-time
4. Try switching rooms to see independent tracking

## 📚 Learn More

- [Yorkie Documentation](https://yorkie.dev/docs)
- [Yorkie JS SDK](https://github.com/yorkie-team/yorkie-js-sdk)
- [Next.js Documentation](https://nextjs.org/docs)
- [Next.js API Routes](https://nextjs.org/docs/app/building-your-application/routing/route-handlers)

## 🤝 Contributing

Contributions are welcome! Please check out our [contributing guidelines](../../CONTRIBUTING.md).

## 📄 License

Apache License 2.0


================================================
FILE: examples/nextjs-presence/app/App.css
================================================
.app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.app-header {
  text-align: center;
  padding: 2rem 1rem;
  color: white;
  background: rgba(0, 0, 0, 0.2);
  backdrop-filter: blur(10px);
}

.app-header h1 {
  font-size: 2.5rem;
  margin-bottom: 0.5rem;
  font-weight: 700;
}

.app-header p {
  font-size: 1.1rem;
  opacity: 0.9;
}

.app-main {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1rem;
}

.app-footer {
  text-align: center;
  padding: 1.5rem 1rem;
  color: white;
  background: rgba(0, 0, 0, 0.2);
  backdrop-filter: blur(10px);
  font-size: 0.9rem;
}

.app-footer a {
  color: white;
  text-decoration: underline;
  transition: opacity 0.2s;
}

.app-footer a:hover {
  opacity: 0.8;
}

@media (max-width: 768px) {
  .app-header h1 {
    font-size: 2rem;
  }

  .app-header p {
    font-size: 1rem;
  }

  .app-main {
    padding: 1rem;
  }
}


================================================
FILE: examples/nextjs-presence/app/api/channels/route.ts
================================================
export async function POST(request: Request) {
  try {
    // Check if secret key is available (required for admin API)
    const secretKey = process.env.YORKIE_API_SECRET_KEY;
    if (!secretKey) {
      return Response.json(
        { error: 'API server features not available in static hosting mode' },
        { status: 503 },
      );
    }

    const { channel_keys, include_sub_path } = await request.json();

    const url = `${process.env.NEXT_PUBLIC_YORKIE_API_ADDR}/yorkie.v1.AdminService/GetChannels`;

    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `API-Key ${secretKey}`,
      },
      body: JSON.stringify({
        channel_keys,
        include_sub_path,
      }),
    });

    if (!response.ok) {
      throw new Error(`Failed to fetch channels: ${response.statusText}`);
    }

    const data = await response.json();
    return Response.json(data);
  } catch (error) {
    console.error('Error fetching channels:', error);
    return Response.json(
      { error: 'Failed to fetch channels' },
      { status: 500 },
    );
  }
}


================================================
FILE: examples/nextjs-presence/app/globals.css
================================================
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

button {
  font-family: inherit;
}


================================================
FILE: examples/nextjs-presence/app/layout.tsx
================================================
import type { Metadata } from 'next';
import './globals.css';

export const metadata: Metadata = {
  title: 'Yorkie Presence Rooms',
  description:
    'Real-time user presence tracking across multiple rooms using Yorkie',
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}


================================================
FILE: examples/nextjs-presence/app/page.tsx
================================================
'use client';

import { useEffect, useState } from 'react';
import { YorkieProvider } from '@yorkie-js/react';
import RoomSelector from '@/components/RoomSelector';
import RoomView from '@/components/RoomView';
import { ROOMS, ROOM_CATEGORIES } from '@/lib/rooms';
import './App.css';

function App() {
  const [currentRoom, setCurrentRoom] = useState<string | null>(null);
  const [sessions, setSessions] = useState<
    { key: string; sessionCount: number }[]
  >([]);

  useEffect(() => {
    if (currentRoom !== null) {
      return;
    }

    const fetchChannels = async () => {
      try {
        const categoryKeys = ROOM_CATEGORIES.map((category) => category.id);
        const response = await fetch('/api/channels', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            channel_keys: [...categoryKeys, ...ROOMS.map((room) => room.key)],
            include_sub_path: true,
          }),
        });
        const data = await response.json();
        const roomSessions = ROOMS.map((room) => {
          const roomSessionCount =
            data.channels?.find((ch) => ch.key === room.key)?.sessionCount ??
            0;
          return {
            key: room.key,
            sessionCount: roomSessionCount,
          };
        });

        const categorySessions = ROOM_CATEGORIES.map((category) => {
          const categoryKey = `${category.id}`;
          const categorySessionCount =
            data.channels?.find((ch) => ch.key === categoryKey)
              ?.sessionCount ?? 0;
          return {
            key: categoryKey,
            sessionCount: categorySessionCount,
          };
        });

        // Calculate total from all category sessionCounts
        const totalSessionCount = categorySessions.reduce(
          (acc, cat) => acc + cat.sessionCount,
          0,
        );
        const totalSession = {
          key: 'total',
          sessionCount: totalSessionCount,
        };

        setSessions([totalSession, ...categorySessions, ...roomSessions]);
      } catch (error) {
        console.error('Failed to fetch channels:', error);
        // Fallback to zero presence counts on error (e.g., static hosting mode)
        const fallbackSessions = ROOMS.map((room) => ({
          key: room.key,
          sessionCount: 0,
        }));
        const fallbackCategorySessions = ROOM_CATEGORIES.map((category) => ({
          key: category.id,
          sessionCount: 0,
        }));
        const fallbackTotal = {
          key: 'total',
          sessionCount: 0,
        };
        setSessions([
          fallbackTotal,
          ...fallbackCategorySessions,
          ...fallbackSessions,
        ]);
      }
    };

    fetchChannels();
  }, [currentRoom]);

  return (
    <YorkieProvider
      apiKey={process.env.NEXT_PUBLIC_YORKIE_API_KEY || ''}
      rpcAddr={
        process.env.NEXT_PUBLIC_YORKIE_API_ADDR || 'http://localhost:8080'
      }
    >
      <div className="app">
        <header className="app-header">
          <div className="app-header-title">
            <h1>Yorkie Presence Rooms</h1>
          </div>
          <p>Real-time user presence tracking across multiple rooms</p>
        </header>

        <main className="app-main">
          {currentRoom ? (
            <RoomView
              roomId={currentRoom}
              onLeave={() => setCurrentRoom(null)}
            />
          ) : (
            <RoomSelector onRoomSelect={setCurrentRoom} sessions={sessions} />
          )}
        </main>

        <footer className="app-footer">
          <p>
            Open multiple browser windows to see real-time presence updates! •{' '}
            <a
              href="https://github.com/yorkie-team/yorkie-js-sdk"
              target="_blank"
              rel="noopener noreferrer"
            >
              View on GitHub
            </a>
          </p>
        </footer>
      </div>
    </YorkieProvider>
  );
}

export default App;


================================================
FILE: examples/nextjs-presence/components/RoomSelector.css
================================================
.room-selector {
  max-width: 900px;
  width: 100%;
  padding: 2rem;
  background: white;
  border-radius: 20px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}

.room-selector-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 2rem;
  margin-bottom: 2rem;
}

.room-selector-title-wrapper {
  flex: 1;
}

.room-selector h2 {
  font-size: 2rem;
  margin: 0 0 0.5rem 0;
  color: #333;
  text-align: left;
}

.room-selector p {
  text-align: left;
  color: #888;
  margin: 0;
  font-size: 1rem;
}

.room-selector-badge-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  flex-shrink: 0;
}

.room-selector-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  height: 40px;
  padding: 0 16px;
  background: rgba(102, 126, 234, 0.15);
  backdrop-filter: blur(10px);
  border: 2px solid rgba(102, 126, 234, 0.3);
  border-radius: 20px;
  font-size: 1rem;
  font-weight: 700;
  color: #667eea;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.room-selector-label {
  font-size: 0.75rem;
  color: #999;
  font-weight: 400;
  opacity: 0.7;
  letter-spacing: 0.01em;
  text-transform: lowercase;
}

.room-selector-subtitle {
  text-align: center;
  color: #666;
  margin-bottom: 2rem;
  font-size: 1.1rem;
}

.room-category {
  margin-bottom: 2.5rem;
  padding: 1.5rem;
  background: linear-gradient(to bottom, #f8f9fc 0%, #ffffff 100%);
  border-radius: 16px;
  border: 1px solid #e8eaf0;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
  transition: all 0.3s ease;
}

.room-category:hover {
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
}

.room-category:last-of-type {
  margin-bottom: 2rem;
}

.room-category-header {
  margin-bottom: 1.5rem;
  padding-bottom: 1rem;
  border-bottom: 2px solid #e8eaf0;
}

.room-category-title {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.room-category-name {
  flex: 1;
}

.room-category-header h3 {
  margin: 0 0 0.5rem 0;
  font-size: 1.5rem;
  color: #333;
  font-weight: 600;
}

.room-category-name p {
  margin: 0;
  color: #666;
  font-size: 0.95rem;
}

.room-category-badge-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}

.room-category-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 12px;
  background: rgba(102, 126, 234, 0.15);
  backdrop-filter: blur(10px);
  border: 2px solid rgba(102, 126, 234, 0.3);
  border-radius: 16px;
  font-size: 0.9rem;
  font-weight: 700;
  color: #667eea;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.room-category-label {
  font-size: 0.7rem;
  color: #999;
  font-weight: 400;
  opacity: 0.7;
  letter-spacing: 0.01em;
  text-transform: lowercase;
}

.room-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
  margin-bottom: 1rem;
}

.room-card {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border: none;
  border-radius: 12px;
  padding: 1rem;
  cursor: pointer;
  transition: all 0.3s ease;
  color: white;
  text-align: left;
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
  position: relative;
  min-height: 80px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.room-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
}

.room-card:active {
  transform: translateY(-1px);
}

.room-card-header {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 0.5rem;
}

.room-card-header h3 {
  font-size: 1.1rem;
  margin: 0;
  font-weight: 600;
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.room-card-badge-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  flex-shrink: 0;
  margin-left: 0.5rem;
}

.room-card-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 8px;
  background: rgba(255, 255, 255, 0.25);
  backdrop-filter: blur(10px);
  border: 2px solid rgba(255, 255, 255, 0.3);
  border-radius: 12px;
  font-size: 0.75rem;
  font-weight: 700;
  color: white;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  transition: all 0.3s ease;
}

.room-card-label {
  font-size: 0.6rem;
  color: rgba(255, 255, 255, 0.6);
  font-weight: 400;
  opacity: 0.8;
  letter-spacing: 0.01em;
  text-transform: lowercase;
}

.room-card-description {
  color: rgba(255, 255, 255, 0.9);
  margin-bottom: 1rem;
  font-size: 0.95rem;
  line-height: 1.5;
}

.room-card-action {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  gap: 0.5rem;
  opacity: 0.9;
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.02em;
  transition: all 0.2s ease;
}

.room-card:hover .room-card-action {
  opacity: 1;
  gap: 0.7rem;
}

.room-card-action::before {
  content: '▶';
  font-size: 0.7rem;
  transition: transform 0.2s ease;
}

.room-card:hover .room-card-action::before {
  transform: translateX(2px);
}

.room-selector-tip {
  text-align: center;
  padding: 1rem;
  background: #f8f9fa;
  border-radius: 10px;
  color: #666;
  font-size: 0.95rem;
}

@media (prefers-color-scheme: dark) {
  .room-selector {
    background: #1a1a1a;
  }

  .room-selector h2 {
    color: #fff;
  }

  .room-selector-badge {
    background: rgba(102, 126, 234, 0.25);
    border-color: rgba(102, 126, 234, 0.4);
    color: #9db4ff;
  }

  .room-selector-label {
    color: #888;
    opacity: 0.8;
  }

  .room-selector-subtitle {
    color: #aaa;
  }

  .room-category {
    background: linear-gradient(to bottom, #2a2a2a 0%, #1f1f1f 100%);
    border-color: #333;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
  }

  .room-category:hover {
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
  }

  .room-category-header {
    border-bottom-color: #333;
  }

  .room-category-header h3 {
    color: #fff;
  }

  .room-category-badge {
    background: rgba(102, 126, 234, 0.25);
    border-color: rgba(102, 126, 234, 0.4);
    color: #9db4ff;
  }

  .room-category-label {
    color: #666;
    opacity: 0.8;
  }

  .room-category-name p {
    color: #aaa;
  }

  .room-selector-tip {
    background: #2a2a2a;
    color: #aaa;
  }
}

@media (max-width: 768px) {
  .room-selector {
    padding: 1.5rem;
  }

  .room-selector-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 1.5rem;
    margin-bottom: 1.5rem;
  }

  .room-selector h2 {
    font-size: 1.5rem;
  }

  .room-selector-subtitle {
    font-size: 0.9rem;
  }

  .room-selector-badge-wrapper {
    align-items: flex-start;
  }

  .room-selector-badge {
    font-size: 0.95rem;
    min-width: 50px;
    height: 36px;
    padding: 0 14px;
  }

  .room-selector-label {
    font-size: 0.7rem;
  }

  .room-category {
    padding: 1rem;
    margin-bottom: 2rem;
  }

  .room-grid {
    grid-template-columns: 1fr;
    gap: 1rem;
  }

  .room-card {
    padding: 1.25rem;
  }
}


================================================
FILE: examples/nextjs-presence/components/RoomSelector.tsx
================================================
import { ROOMS, ROOM_CATEGORIES } from '@/lib/rooms';
import './RoomSelector.css';

interface RoomSelectorProps {
  onRoomSelect: (roomId: string) => void;
  sessions: { key: string; sessionCount: number }[];
}

function RoomSelector({ onRoomSelect, sessions }: RoomSelectorProps) {
  const totalCount =
    sessions.find((p) => p.key === 'total')?.sessionCount ?? 0;

  return (
    <div className="room-selector">
      <div className="room-selector-header">
        <div className="room-selector-title-wrapper">
          <h2>Choose a Room</h2>
          <p>Join a room to see live online sessions</p>
        </div>
        <div className="room-selector-badge-wrapper">
          <span className="room-selector-badge">{totalCount} online</span>
          <span className="room-selector-label">in total</span>
        </div>
      </div>

      {ROOM_CATEGORIES.map((category) => {
        const categoryRooms = ROOMS.filter(
          (room) => room.categoryId === category.id,
        );
        const categoryKey = `${category.id}`;
        const categorySessionCount =
          sessions.find((p) => p.key === categoryKey)?.sessionCount || 0;

        return (
          <div key={category.id} className="room-category">
            <div className="room-category-header">
              <div className="room-category-title">
                <div className="room-category-name">
                  <h3>
                    {category.emoji} {category.name}
                  </h3>
                  <p>{category.description}</p>
                </div>
                <div className="room-category-badge-wrapper">
                  <span className="room-category-badge">
                    {categorySessionCount} online
                  </span>
                  <span className="room-category-label">in category</span>
                </div>
              </div>
            </div>

            <div className="room-grid">
              {categoryRooms.map((room) => {
                const sessionCount =
                  sessions.find((p) => p.key === room.key)?.sessionCount || 0;
                return (
                  <button
                    key={room.id}
                    className="room-card"
                    onClick={() => onRoomSelect(room.id)}
                  >
                    <div className="room-card-header">
                      <h3>{room.name}</h3>
                      <div className="room-card-badge-wrapper">
                        <span className="room-card-badge">
                          {sessionCount} online
                        </span>
                        <span className="room-card-label">in room</span>
                      </div>
                    </div>
                    <div className="room-card-action">
                      <span>Join Room</span>
                    </div>
                  </button>
                );
              })}
            </div>
          </div>
        );
      })}

      <div className="room-selector-tip">
        💡 Tip: Open multiple browser windows to test presence tracking!
      </div>
    </div>
  );
}

export default RoomSelector;


================================================
FILE: examples/nextjs-presence/components/RoomView.css
================================================
.room-view {
  max-width: 800px;
  width: 100%;
  background: white;
  border-radius: 20px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
  overflow: hidden;
}

.room-view.error {
  padding: 2rem;
  text-align: center;
}

.room-view-header {
  padding: 1.5rem 2rem;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.back-button {
  background: rgba(255, 255, 255, 0.2);
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: white;
  padding: 0.5rem 1rem;
  border-radius: 8px;
  cursor: pointer;
  font-size: 0.95rem;
  font-weight: 500;
  transition: all 0.2s;
  backdrop-filter: blur(10px);
}

.back-button:hover {
  background: rgba(255, 255, 255, 0.3);
  transform: translateX(-2px);
}

.room-view-content {
  padding: 2rem;
}

.room-info {
  text-align: center;
  margin-bottom: 2rem;
}

.room-info h2 {
  font-size: 2rem;
  margin-bottom: 0.5rem;
  color: #333;
}

.room-info p {
  color: #666;
  font-size: 1.1rem;
}

.room-instructions {
  background: #f8f9fa;
  border-radius: 12px;
  padding: 1.5rem;
  margin-top: 2rem;
}

.room-instructions h3 {
  color: #333;
  margin-bottom: 1rem;
  font-size: 1.3rem;
}

.room-instructions ul {
  list-style: none;
  padding: 0;
}

.room-instructions li {
  padding: 0.5rem 0;
  color: #555;
  font-size: 1rem;
  line-height: 1.6;
}

.room-demo-area {
  margin-top: 2rem;
  padding: 1.5rem;
  background: linear-gradient(
    135deg,
    rgba(102, 126, 234, 0.1) 0%,
    rgba(118, 75, 162, 0.1) 100%
  );
  border-radius: 12px;
  border: 2px solid rgba(102, 126, 234, 0.2);
}

.room-demo-area h3 {
  color: #667eea;
  margin-bottom: 0.75rem;
  font-size: 1.3rem;
}

.room-demo-area p {
  color: #555;
  margin-bottom: 0.5rem;
  line-height: 1.6;
}

.room-demo-area code {
  background: rgba(102, 126, 234, 0.1);
  padding: 0.2rem 0.5rem;
  border-radius: 4px;
  font-family: 'Courier New', monospace;
  color: #764ba2;
  font-weight: 600;
}

.demo-hint {
  font-size: 0.9rem;
  color: #777;
  margin-top: 0.5rem;
}

@media (prefers-color-scheme: dark) {
  .room-view {
    background: #1a1a1a;
  }

  .room-info h2 {
    color: #fff;
  }

  .room-info p {
    color: #aaa;
  }

  .room-instructions {
    background: #2a2a2a;
  }

  .room-instructions h3 {
    color: #fff;
  }

  .room-instructions li {
    color: #ccc;
  }

  .room-demo-area {
    background: rgba(102, 126, 234, 0.15);
    border-color: rgba(102, 126, 234, 0.3);
  }

  .room-demo-area p {
    color: #ccc;
  }

  .room-demo-area code {
    background: rgba(102, 126, 234, 0.2);
    color: #a78bfa;
  }

  .demo-hint {
    color: #999;
  }
}

@media (max-width: 768px) {
  .room-view-header {
    padding: 1rem 1.5rem;
  }

  .room-view-content {
    padding: 1.5rem;
  }

  .room-info h2 {
    font-size: 1.5rem;
  }

  .room-instructions,
  .room-demo-area {
    padding: 1rem;
  }

  .room-instructions h3,
  .room-demo-area h3 {
    font-size: 1.1rem;
  }
}


================================================
FILE: examples/nextjs-presence/components/RoomView.tsx
================================================
'use client';

import { ChannelProvider } from '@yorkie-js/react';
import { ROOMS } from '@/lib/rooms';
import SessionCounter from './SessionCounter';
import './RoomView.css';

interface RoomViewProps {
  roomId: string;
  onLeave: () => void;
}

function RoomView({ roomId, onLeave }: RoomViewProps) {
  const room = ROOMS.find((r) => r.id === roomId);

  if (!room) {
    return (
      <div className="room-view error">
        <p>Room not found</p>
        <button onClick={onLeave}>Go Back</button>
      </div>
    );
  }

  return (
    <ChannelProvider channelKey={room.key}>
      <div className="room-view">
        <div className="room-view-header">
          <button className="back-button" onClick={onLeave}>
            ← Back to Rooms
          </button>
        </div>

        <div className="room-view-content">
          <div className="room-info">
            <h2>{room.name}</h2>
            <p>{room.description}</p>
          </div>

          <SessionCounter />

          <div className="room-instructions">
            <h3>Try it out!</h3>
            <ul>
              <li>🪟 Open this page in multiple browser windows or tabs</li>
              <li>
                👀 Watch the user count update in real-time as you join/leave
              </li>
              <li>🏠 Switch rooms to see independent presence tracking</li>
            </ul>
          </div>

          <div className="room-demo-area">
            <h3>You&apos;re connected!</h3>
            <p>
              This is room <strong>{room.id}</strong> with channel key:{' '}
              <code>{room.key}</code>
            </p>
            <p className="demo-hint">
              Each room has its own channel key, allowing independent session
              counting.
            </p>
          </div>
        </div>
      </div>
    </ChannelProvider>
  );
}

export default RoomView;


================================================
FILE: examples/nextjs-presence/components/SessionCounter.css
================================================
.session-counter {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 2rem;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-radius: 15px;
  color: white;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
  margin: 2rem 0;
  min-height: 180px;
  justify-content: center;
  position: relative;
}

.session-counter.loading,
.session-counter.error {
  flex-direction: row;
  gap: 1rem;
  justify-content: center;
  align-items: center;
  min-height: 120px;
}

.session-counter.error {
  background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}

.spinner {
  width: 24px;
  height: 24px;
  border: 3px solid rgba(255, 255, 255, 0.3);
  border-top-color: white;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.error-icon {
  font-size: 1.5rem;
}

.session-status {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
  font-size: 0.9rem;
  font-weight: 500;
  opacity: 0.9;
}

.status-indicator {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #10b981;
  box-shadow: 0 0 10px rgba(16, 185, 129, 0.5);
  animation: pulse 2s ease-in-out infinite;
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.5;
  }
}

.session-count {
  text-align: center;
  transition: transform 0.3s ease;
}

.session-count.increase {
  animation: countIncrease 0.6s ease;
}

.session-count.decrease {
  animation: countDecrease 0.6s ease;
}

@keyframes countIncrease {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.2);
  }
  100% {
    transform: scale(1);
  }
}

@keyframes countDecrease {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(0.9);
  }
  100% {
    transform: scale(1);
  }
}

.count-value {
  font-size: 4rem;
  font-weight: 700;
  line-height: 1;
  margin-bottom: 0.5rem;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}

.count-label {
  font-size: 1.2rem;
  font-weight: 500;
  opacity: 0.9;
  text-transform: uppercase;
  letter-spacing: 1px;
}

.session-change {
  position: absolute;
  bottom: -1rem;
  animation: slideUp 0.5s ease;
}

@keyframes slideUp {
  from {
    transform: translateY(10px);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

.change-badge {
  display: inline-block;
  padding: 0.5rem 1rem;
  border-radius: 20px;
  font-size: 0.9rem;
  font-weight: 600;
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}

.change-badge.join {
  background: #10b981;
  color: white;
}

.change-badge.leave {
  background: #f59e0b;
  color: white;
}

/* Simple counter styles */
.simple-counter {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  background: #10b981;
  color: white;
  border-radius: 20px;
  font-weight: 600;
  box-shadow: 0 2px 10px rgba(16, 185, 129, 0.3);
}

.online-dot {
  width: 8px;
  height: 8px;
  background: white;
  border-radius: 50%;
  animation: pulse 2s ease-in-out infinite;
}

@media (max-width: 768px) {
  .session-counter {
    padding: 1.5rem;
    margin: 1rem 0;
  }

  .count-value {
    font-size: 3rem;
  }

  .count-label {
    font-size: 1rem;
  }

  .change-badge {
    font-size: 0.8rem;
    padding: 0.4rem 0.8rem;
  }
}


================================================
FILE: examples/nextjs-presence/components/SessionCounter.tsx
================================================
'use client';

import { useChannel, useChannelSessionCount } from '@yorkie-js/react';
import { useEffect, useState } from 'react';
import './SessionCounter.css';

function SessionCounter() {
  const { sessionCount, loading, error } = useChannel();
  const [prevCount, setPrevCount] = useState(0);
  const [isIncreasing, setIsIncreasing] = useState<boolean | null>(null);

  useEffect(() => {
    if (!loading && sessionCount !== prevCount) {
      setTimeout(() => {
        setIsIncreasing(sessionCount > prevCount);
        setPrevCount(sessionCount);
      }, 0);

      // Clear the animation state after animation completes
      const timer = setTimeout(() => {
        setIsIncreasing(null);
      }, 600);

      return () => clearTimeout(timer);
    }
  }, [sessionCount, loading, prevCount]);

  if (loading) {
    return (
      <div className="session-counter loading">
        <div className="spinner"></div>
        <p>Connecting to room...</p>
      </div>
    );
  }

  if (error) {
    return (
      <div className="session-counter error">
        <span className="error-icon">⚠️</span>
        <p>Error: {error.message}</p>
      </div>
    );
  }

  return (
    <div className="session-counter">
      <div className="session-status">
        <span className="status-indicator online"></span>
        <span className="status-text">Live</span>
      </div>

      <div
        className={`session-count ${isIncreasing === true ? 'increase' : ''} ${
          isIncreasing === false ? 'decrease' : ''
        }`}
      >
        <div className="count-value">{sessionCount}</div>
        <div className="count-label">
          {sessionCount === 1 ? 'user online' : 'users online'}
        </div>
      </div>

      {isIncreasing !== null && (
        <div className="session-change">
          {isIncreasing ? (
            <span className="change-badge join">👋 Someone joined!</span>
          ) : (
            <span className="change-badge leave">👋 Someone left</span>
          )}
        </div>
      )}
    </div>
  );
}

// Alternative simpler component using only useChannel hook
export function SimpleSessionCounter() {
  const sessionCount = useChannelSessionCount();

  return (
    <div className="simple-counter">
      <span className="online-dot"></span>
      <span>{sessionCount} online</span>
    </div>
  );
}

export default SessionCounter;


================================================
FILE: examples/nextjs-presence/eslint.config.mjs
================================================
import nextConfig from 'eslint-config-next';

const eslintConfig = [...nextConfig];

export default eslintConfig;


================================================
FILE: examples/nextjs-presence/lib/rooms.ts
================================================
// Room category definition
export interface RoomCategory {
  id: string;
  name: string;
  emoji: string;
  description: string;
}

// Individual room definition
export interface Room {
  id: string;
  name: string;
  description: string;
  key: string;
  categoryId: string;
}

// Room categories
export const ROOM_CATEGORIES: RoomCategory[] = [
  {
    id: 'general',
    name: 'General',
    emoji: '💬',
    description: 'General discussion',
  },
  {
    id: 'development',
    name: 'Development',
    emoji: '💻',
    description: 'Tech talk and coding',
  },
  {
    id: 'random',
    name: 'Random',
    emoji: '🎲',
    description: 'Off-topic chat',
  },
  {
    id: 'music',
    name: 'Music',
    emoji: '🎵',
    description: 'Share your favorite tunes',
  },
];

// Generate rooms with hierarchical structure
const generateRooms = (): Room[] => {
  const rooms: Room[] = [];
  const roomsPerCategory = 4;

  ROOM_CATEGORIES.forEach((category) => {
    for (let i = 1; i <= roomsPerCategory; i++) {
      rooms.push({
        id: `${category.id}.${i}`,
        name: `${category.emoji} ${category.name} #${i}`,
        description: category.description,
        key: `${category.id}.${i}`,
        categoryId: category.id,
      });
    }
  });

  return rooms;
};

// Available rooms with hierarchical structure
export const ROOMS = generateRooms();


================================================
FILE: examples/nextjs-presence/next.config.ts
================================================
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  output: 'export',
  distDir: 'dist',
  basePath: process.env.NEXT_PUBLIC_BASE_PATH || '',
  assetPrefix: process.env.NEXT_PUBLIC_BASE_PATH || '',
  reactStrictMode: false,
};

export default nextConfig;


================================================
FILE: examples/nextjs-presence/package.json
================================================
{
  "name": "nextjs-presence",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint ."
  },
  "dependencies": {
    "@yorkie-js/react": "workspace:*",
    "@yorkie-js/sdk": "workspace:*",
    "next": "16.2.6",
    "react": "19.2.1",
    "react-dom": "19.2.1"
  },
  "devDependencies": {
    "@types/node": "^24.10.1",
    "@types/react": "^19.2.7",
    "@types/react-dom": "^19.2.3",
    "eslint": "^9.39.1",
    "eslint-config-next": "16.2.6",
    "typescript": "^5.9.3"
  }
}


================================================
FILE: examples/nextjs-presence/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "ESNext",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": false,
    "skipLibCheck": true,
    "strict": false,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "EsNext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": [
        "./*"
      ],
      "react": [
        "./node_modules/@types/react"
      ],
      "@yorkie-js/sdk/src/*": [
        "../../packages/sdk/src/*"
      ]
    }
  },
  "include": [
    "**/*.ts",
    "**/*.tsx",
    ".next/types/**/*.ts",
    "next-env.d.ts",
    "dist/types/**/*.ts",
    ".next/dev/types/**/*.ts",
    "dist/dev/types/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}


================================================
FILE: examples/nextjs-scheduler/.gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts


================================================
FILE: examples/nextjs-scheduler/README.md
================================================
# Yorkie Next.js scheduler Example

<p>
    <a href="https://yorkie.dev/yorkie-js-sdk/examples/nextjs-scheduler/" target="_blank">
        <img src="https://img.shields.io/badge/preview-message?style=flat-square&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMTUiIHZpZXdCb3g9IjAgMCAyNCAxNSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTYuODU3MTcgMi43ODE5OUwxMS4yNzUxIDkuMTI2NzhDMTEuNTU0NCA5LjUyODAxIDEyLjEwNjIgOS42MjY3NiAxMi41MDc0IDkuMzQ3NDRDMTIuNTkzNCA5LjI4NzUgMTIuNjY4MSA5LjIxMjggMTIuNzI4MSA5LjEyNjc4TDE3LjE0NiAyLjc4MTk5QzE3LjcwNDggMS45Nzk1NCAxNy41MDcyIDAuODc2MTMxIDE2LjcwNDggMC4zMTc0OTRDMTYuNDA4IDAuMTEwODM3IDE2LjA1NSAwIDE1LjY5MzIgMEg4LjMxMDAxQzcuMzMyMiAwIDYuNTM5NTUgMC43OTI2NTQgNi41Mzk1NSAxLjc3MDQ2QzYuNTM5NjggMi4xMzIxMSA2LjY1MDUxIDIuNDg1MTEgNi44NTcxNyAyLjc4MTk5WiIgZmlsbD0iIzUxNEM0OSIvPgo8cGF0aCBkPSJNMTMuODA4OSAxNC4yMzg4QzE0LjEyMzEgMTQuNDE4IDE0LjQ4NDcgMTQuNDk2NiAxNC44NDUgMTQuNDY0MkwyMi45MjYgMTMuNzM1QzIzLjU3NTMgMTMuNjc2NSAyNC4wNTQgMTMuMTAyNyAyMy45OTU1IDEyLjQ1MzVDMjMuOTkyNCAxMi40MTkyIDIzLjk4NzggMTIuMzg1MSAyMy45ODE3IDEyLjM1MTNDMjMuNzM4OSAxMC45OTY4IDIzLjI2MTEgOS42OTUyNyAyMi41Njk5IDguNTA1NDZDMjEuODc4NiA3LjMxNTY1IDIwLjk4NDggNi4yNTU3NyAxOS45Mjg2IDUuMzczOTFDMTkuNDI4MiA0Ljk1NjE0IDE4LjY4MzkgNS4wMjMwNyAxOC4yNjYyIDUuNTIzNTZDMTguMjQ0MiA1LjU0OTkgMTguMjIzMyA1LjU3NzI2IDE4LjIwMzYgNS42MDU1MUwxMy41NjcgMTIuMjY0MUMxMy4zNjAzIDEyLjU2MSAxMy4yNDk1IDEyLjkxNCAxMy4yNDk1IDEzLjI3NThWMTMuMjUzN0MxMy4yNDk1IDEzLjQ1NjIgMTMuMzAxNiAxMy42NTU0IDEzLjQwMDggMTMuODMxOUMxMy41MDUgMTQuMDA1NCAxMy42NTIxIDE0LjE0OTMgMTMuODI4MSAxNC4yNDk2IiBmaWxsPSIjRkRDNDMzIi8+CjxwYXRoIGQ9Ik0xMC42NDE2IDEzLjc0MzRDMTAuNTM3NSAxMy45NTU5IDEwLjM3MiAxNC4xMzIyIDEwLjE2NjUgMTQuMjQ5NEwxMC4xOTE1IDE0LjIzNTFDOS44NzczNCAxNC40MTQzIDkuNTE1NjkgMTQuNDkyOSA5LjE1NTQ0IDE0LjQ2MDVMMS4wNzQ0MSAxMy43MzEzQzEuMDQwMTggMTMuNzI4MyAxLjAwNjA3IDEzLjcyMzcgMC45NzIyMjUgMTMuNzE3NkMwLjMzMDYyIDEzLjYwMjUgLTAuMDk2MzExOSAxMi45ODkyIDAuMDE4NzI0MiAxMi4zNDc2QzAuMjYxNTIyIDEwLjk5MyAwLjczOTM1NCA5LjY5MTU2IDEuNDMwNDYgOC41MDE2M0MyLjEyMTU3IDcuMzExNjkgMy4wMTU1MSA2LjI1MjA2IDQuMDcxODQgNS4zNzAwOEM0LjA5ODE4IDUuMzQ4MDYgNC4xMjU1NCA1LjMyNzE5IDQuMTUzNzkgNS4zMDc0N0M0LjY4ODc2IDQuOTM1IDUuNDI0MjcgNS4wNjY3MSA1Ljc5Njg3IDUuNjAxNjhMMTAuNDMzNCAxMi4yNjA0QzEwLjY0MDEgMTIuNTU3MyAxMC43NTA5IDEyLjkxMDMgMTAuNzUwOSAxMy4yNzIxVjEzLjI0MzJDMTAuNzUwOSAxMy40Nzk3IDEwLjY3OTggMTMuNzExIDEwLjU0NjggMTMuOTA2NyIgZmlsbD0iI0ZEQzQzMyIvPgo8L3N2Zz4K&color=FEF3D7" alt="Live Preview" />
    </a>
</p>

<img width="500" alt="Next.js scheduler" src="thumbnail.jpg"/>

## How to run demo

At project root, run below command to start Yorkie server.

```bash
$ docker compose -f docker/docker-compose.yml up --build -d
```

Then install dependencies and run the demo.

```bash
# In the root directory of the repository.
$ pnpm install
```

Now you can run the demo.

```bash
# In the root directory of the repository.
$ pnpm nextjs-scheduler dev

# Or in the directory of the example.
$ pnpm dev
```


================================================
FILE: examples/nextjs-scheduler/app/Scheduler.tsx
================================================
'use client';

import React, { useEffect, useMemo, useState } from 'react';
import './styles/calendar.css';
import styles from './styles/page.module.css';

import { EditorPropsTypes, CalendarValue } from './utils/types';
import { parseDate } from './utils/parseDate';
import Calendar from 'react-calendar';

/**
 * handle calendar component
 */
export default function Scheduler(props: EditorPropsTypes) {
  const { content, actions } = props;
  const [date, onChange] = useState<CalendarValue>(new Date());
  const [text, setText] = useState<string>('');

  const currentDate = date ? parseDate(new Date(date.toString())) : '';

  const existing = useMemo(
    () => content.find((item) => item.date === currentDate),
    [content, currentDate],
  );

  // If a date with an event is selected and editor empty, preload text
  useEffect(() => {
    if (existing && text === '') {
      setText(existing.text);
    }
    if (!existing) {
      setText('');
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [existing?.date]);

  const canSave = !!currentDate && text.trim().length > 0;

  const handleSave = () => {
    if (!canSave) return;
    if (existing) {
      actions.updateContent(currentDate, text.trim());
    } else {
      actions.addContent(currentDate, text.trim());
    }
    setText('');
  };

  const handleDelete = () => {
    if (existing) {
      actions.deleteContent(currentDate);
      setText('');
    }
  };

  return (
    <section className={styles.board} aria-label="Scheduler board">
      <div className={styles.calendarWrapper}>
        <div className={styles.calendarWithDots}>
          <Calendar
            onChange={onChange}
            value={date}
            locale="en-EN"
            showNeighboringMonth={false}
            formatDay={(locale, date) =>
              date.toLocaleString('en', { day: 'numeric' })
            }
            tileContent={({ date }) => {
              const matched = content.some(
                (item) => item.date === parseDate(date),
              );
              return matched ? <span className="dot" /> : null;
            }}
          />
        </div>
      </div>
      <div className={styles.panel}>
        <p className={styles.muted}>
          Selected: <strong>{currentDate || '—'}</strong>
        </p>

        <div className={styles.formGroup}>
          <label className={styles.formLabel} htmlFor="event-text">
            {existing ? 'Edit Event' : 'New Event'}
          </label>
          <textarea
            id="event-text"
            placeholder={
              existing ? 'Update selected event…' : 'Describe the event…'
            }
            className={styles.textArea}
            value={text}
            onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
              setText(e.target.value)
            }
            maxLength={500}
          />
        </div>
        <div className={styles.buttonBar}>
          <button
            className={styles.buttonPrimary}
            disabled={!canSave}
            onClick={handleSave}
            aria-disabled={!canSave}
          >
            {existing ? 'Save Changes' : 'Add Event'}
          </button>
          <button
            className={`${styles.buttonPrimary} ${styles.buttonDanger}`}
            disabled={!existing}
            onClick={handleDelete}
            aria-disabled={!existing}
          >
            Delete
          </button>
        </div>
      </div>
    </section>
  );
}


================================================
FILE: examples/nextjs-scheduler/app/layout.tsx
================================================
import './styles/globals.css';
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'Next.js react-calendar example',
  description: 'example of yorkie-js-sdk with next.js & react-calendar',
  icons: {
    icon: './favicon.ico',
  },
};

/**
 * default root layout of service
 */
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}


================================================
FILE: examples/nextjs-scheduler/app/not-found.tsx
================================================
/**
 * 404-not found
 */
export default function notFound() {
  return <h1>404 not found</h1>;
}


================================================
FILE: examples/nextjs-scheduler/app/page.tsx
================================================
/**
 * yorkie-js-sdk must be loaded on client-side
 */
'use client';

import styles from './styles/page.module.css';
import React, { useEffect, useState } from 'react';

import { ContentTypes, ENVtypes } from './utils/types';
import { displayPeers, createRandomPeers } from './utils/handlePeers';
import { parseDate } from './utils/parseDate';
import yorkie, { Document, JSONArray, DocEventType } from '@yorkie-js/sdk';
import Scheduler from './Scheduler';

// parseDate() value's format = "DD-MM-YYYY"
const defaultContent = [
  {
    date: parseDate(new Date()).replace(/^\d{2}/, '01'),
    text: 'payday',
  },
  {
    date: parseDate(new Date()).replace(/^\d{2}/, '17'),
    text: "Garry's birthday",
  },
] as JSONArray<ContentTypes>;

const ENV: ENVtypes = {
  url: process.env.NEXT_PUBLIC_YORKIE_API_ADDR!,
  apiKey: process.env.NEXT_PUBLIC_YORKIE_API_KEY!,
};

const documentKey = `next.js-Scheduler-${parseDate(new Date())}`;

/**
 * main page
 */
export default function Editor() {
  const [peers, setPeers] = useState<Array<string>>([]);
  const [content, setContent] = useState<Array<ContentTypes>>(defaultContent);

  // create Yorkie Document with useState value
  const [doc] = useState<Document<{ content: JSONArray<ContentTypes> }>>(
    () =>
      new yorkie.Document<{ content: JSONArray<ContentTypes> }>(documentKey),
  );

  const actions = {
    // push new content to Yorkie's database
    addContent(date: string, text: string) {
      doc.update((root) => {
        root.content.push({ date, text });
      });
    },

    // delete selected content at Yorkie's database
    deleteContent(date: string) {
      doc.update((root) => {
        const idx = root.content.findIndex((item) => item.date === date);
        if (idx !== -1) {
          root.content.delete?.(idx);
        }
      });
    },

    // edit selected content at Yorkie's database
    updateContent(date: string, text: string) {
      doc.update((root) => {
        let target;
        for (const item of root.content) {
          if (item.date === date) {
            target = item;
            break;
          }
        }

        if (target) {
          target.text = text;
        }
      });
    },
  };

  useEffect(() => {
    // create Yorkie Client at client-side
    const client = new yorkie.Client({
      rpcAddr: ENV.url,
      apiKey: ENV.apiKey,
    });

    // subscribe document event of "PresenceChanged"(="peers-changed")
    doc.subscribe('presence', (event) => {
      if (event.type !== DocEventType.PresenceChanged) {
        setPeers(displayPeers(doc.getPresences()));
      }
    });

    /**
     * `attachDoc` is a helper function to attach the document into the client.
     */
    async function attachDoc(
      doc: Document<{ content: JSONArray<ContentTypes> }>,
      callback: (props: JSONArray<ContentTypes>) => void,
    ) {
      // 01. activate client
      await client.activate();
      // 02. attach the document into the client with presence
      await client.attach(doc, {
        initialPresence: {
          userName: createRandomPeers(),
        },
      });

      // 03. create default content if not exists.
      doc.update((root) => {
        if (!root.content) {
          root.content = defaultContent;
        }
      }, 'create default content if not exists');

      // 04. subscribe doc's change event from local and remote.
      doc.subscribe(() => {
        callback(doc.getRoot().content);
      });

      // 05. set content to the attached document.
      callback(doc.getRoot().content);
    }

    attachDoc(doc, (content) => setContent(content));
  }, []);

  return (
    <main className={styles.main}>
      <header>
        <div className={styles.peersRow} aria-label="Active collaborators">
          {peers.length === 0 && (
            <span className={styles.muted}>No peers connected</span>
          )}
          {peers.map((p, i) => (
            <span className={styles.peerChip} key={i}>
              {p}
            </span>
          ))}
        </div>
      </header>
      <Scheduler content={content} actions={actions} />
    </main>
  );
}


================================================
FILE: examples/nextjs-scheduler/app/styles/calendar.css
================================================
/* custom css code */

.react-calendar {
  width: 350px;
  max-width: 100%;
  background: linear-gradient(#ffffff, #fcfdfd);
  border: 1px solid #d8ecea;
  border-radius: 12px;
  font-family: Arial, Helvetica, sans-serif;
  line-height: 1.125em;
  color: #22403d;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
}

.react-calendar--doubleView {
  width: 700px;
}

.react-calendar--doubleView .react-calendar__viewContainer {
  display: flex;
  margin: -0.5em;
}

.react-calendar--doubleView .react-calendar__viewContainer > * {
  width: 50%;
  margin: 0.5em;
}

.react-calendar,
.react-calendar *,
.react-calendar *:before,
.react-calendar *:after {
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}

.react-calendar button {
  margin: 0;
  border: 0;
  outline: none;
}

.react-calendar button:enabled:hover {
  cursor: pointer;
}

.react-calendar__navigation {
  display: flex;
  height: 44px;
  margin-bottom: 0.75em;
}

.react-calendar__navigation button {
  min-width: 44px;
  background: none;
  font-weight: 600;
  color: #0d5a52;
  transition:
    background 0.15s ease,
    color 0.15s ease;
  border-radius: 8px;
  margin: 2px;
}

.react-calendar__navigation button:disabled {
  background-color: #eef3f2;
  color: #7a8a88;
}

.react-calendar__navigation button:enabled:hover,
.react-calendar__navigation button:enabled:focus {
  background-color: #e5f3f1;
  color: #00887a;
}

.react-calendar__month-view__weekdays {
  text-align: center;
  text-transform: uppercase;
  font-weight: bold;
  font-size: 0.75em;
}

.react-calendar__month-view__weekdays__weekday {
  padding: 0.5em;
}

.react-calendar__month-view__weekNumbers .react-calendar__tile {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75em;
  font-weight: bold;
}

.react-calendar__month-view__days__day--weekend {
  color: #c24444;
  font-weight: 500;
}

.react-calendar__month-view__days__day--neighboringMonth {
  color: #94a5a3;
}

.react-calendar__year-view .react-calendar__tile,
.react-calendar__decade-view .react-calendar__tile,
.react-calendar__century-view .react-calendar__tile {
  padding: 2em 0.5em;
}

.react-calendar__tile {
  max-width: 100%;
  padding: 10px 6.6667px;
  background: none;
  text-align: center;
  line-height: 16px;
  border-radius: 8px;
  transition:
    background 0.12s ease,
    color 0.12s ease,
    box-shadow 0.12s ease;
  position: relative;
}

.react-calendar__tile:disabled {
  background-color: #f0f0f0;
}

.react-calendar__tile:enabled:hover,
.react-calendar__tile:enabled:focus {
  background-color: #eaf7f5;
}

.react-calendar__tile--now {
  background: #f0fbfa;
  box-shadow: inset 0 0 0 2px #83d6cd;
  border-radius: 8px;
  font-weight: 600;
}

.react-calendar__tile--now:enabled:hover,
.react-calendar__tile--now:enabled:focus {
  background: #e2f6f3;
}

.react-calendar__tile--hasActive {
  background: #00887a;
  color: #ffffff;
  font-weight: 600;
}

.react-calendar__tile--hasActive:enabled:hover,
.react-calendar__tile--hasActive:enabled:focus {
  background: #006f64;
}

.react-calendar__tile--active {
  background: #80c5be;
  color: #ffffff;
  font-weight: 600;
}

.react-calendar__tile--active:enabled:hover,
.react-calendar__tile--active:enabled:focus {
  background: #80c5be;
}

.react-calendar--selectRange .react-calendar__tile--hover {
  background-color: #e6e6e6;
}


================================================
FILE: examples/nextjs-scheduler/app/styles/globals.css
================================================
body {
  display: flex;
  padding: 1rem;
  justify-content: center;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
    "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-size: 17px;
  color: #2f2f2f;
  background-color: #cccccc;
}

input {
  width: 22rem;
  height: 3.5rem;
  outline: none;
  margin-left: 1rem;
  border: none;
  font-size: 20px;
}

textarea {
  resize: none;
  outline: none;
  font-size: 17px;
}

.button {
  font-size: 17px;
  cursor: pointer;
  border: none;
  padding: 1rem 2rem 1rem 2rem;
  color: #f0f3f5;
  background-color: #00887a;
}
.button:hover {
  background-color: #00557a;
}


================================================
FILE: examples/nextjs-scheduler/app/styles/page.module.css
================================================
/* Layout */
.main {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  width: 100%;
  max-width: 880px;
  margin: 0 auto;
}

.board {
  display: flex;
  gap: 2rem;
  flex-wrap: wrap;
  background: #ffffff;
  border-radius: 16px;
  padding: 1.5rem 1.75rem 2rem;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}

.calendarWrapper {
  flex: 0 0 350px;
}

.panel {
  flex: 1 1 320px;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  min-width: 300px;
}

/* Peers */
.peersRow {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  font-size: 14px;
}

.peerChip {
  background: linear-gradient(135deg, #00887a, #00a98f);
  color: #fff;
  padding: 2px 10px 3px;
  border-radius: 999px;
  font-weight: 500;
  line-height: 1.3;
}

/* Event List */
.eventList {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-height: 160px;
  overflow-y: auto;
  padding-right: 0.25rem;
}

.eventCard {
  position: relative;
  padding: 0.6rem 0.8rem 0.6rem 1rem;
  background: #f5f9f9;
  border: 1px solid #d8ecea;
  border-radius: 10px;
  font-size: 14px;
  line-height: 1.4;
  color: #22403d;
}

.eventCard button {
  all: unset;
}

.eventCardInteractive {
  cursor: pointer;
  transition:
    background 0.15s ease,
    border-color 0.15s ease;
}

.eventCardInteractive:hover {
  background: #eef7f6;
  border-color: #b7dbd7;
}

.eventCardActive {
  background: #e2f4f2;
  border-color: #83d6cd;
  box-shadow: 0 0 0 2px #c9ece7;
}

.eventCard:before {
  content: '';
  position: absolute;
  left: 0.5rem;
  top: 50%;
  width: 6px;
  height: 6px;
  background: #00887a;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.emptyState {
  font-size: 14px;
  color: #666;
  font-style: italic;
}

/* Form */
.formGroup {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

/* (Removed preview/counter/icon styles after simplification) */

.sectionTitle {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.formLabel {
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: #355752;
}

.textArea {
  min-height: 7rem;
  padding: 0.75rem 0.85rem;
  background: #fcfdfd;
  border: 1px solid #c9d9d7;
  border-radius: 10px;
  font-size: 14px;
  line-height: 1.4;
  color: #22403d;
}

.textArea:focus {
  outline: 2px solid #83d6cd;
  border-color: #5cb9ae;
}

.buttonBar {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.buttonPrimary {
  background: #00887a;
  border: none;
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  padding: 0.85rem 1.4rem;
  border-radius: 10px;
  cursor: pointer;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
  transition:
    background 0.15s ease,
    transform 0.15s ease;
}

.buttonPrimary:hover:not(:disabled) {
  background: #006f64;
}

.buttonPrimary:active:not(:disabled) {
  transform: translateY(1px);
}

.buttonDanger {
  background: #e64848;
}

.buttonDanger:hover:not(:disabled) {
  background: #c93636;
}

.buttonPrimary:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Calendar overrides */
.calendarWithDots :global(.react-calendar__tile) {
  position: relative;
}

.calendarWithDots :global(.react-calendar__tile .dot) {
  position: absolute;
  bottom: 4px;
  left: 50%;
  width: 6px;
  height: 6px;
  background: #00887a;
  border-radius: 50%;
  transform: translateX(-50%);
}

/* Utility */
.muted {
  color: #5c6d6b;
  font-size: 13px;
}

@media (max-width: 780px) {
  .calendarWrapper {
    flex: 1 1 100%;
    display: flex;
    justify-content: center;
    width: 100%;
    margin: 0 auto;
  }
  .panel {
    flex: 1 1 100%;
  }
}

@media (max-width: 480px) {
  .board {
    padding: 1.1rem 1rem 1.5rem;
  }
  .calendarWrapper {
    justify-content: center;
  }
  .calendarWithDots {
    transform: scale(0.95);
    transform-origin: top center;
  }
}


================================================
FILE: examples/nextjs-scheduler/app/utils/handlePeers.ts
================================================
import { Indexable } from '@yorkie-js/sdk';

const randomPeers = [
  'Alice',
  'Bob',
  'Carol',
  'Chuck',
  'Dave',
  'Erin',
  'Frank',
  'Grace',
  'Ivan',
  'Justin',
  'Matilda',
  'Oscar',
  'Steve',
  'Victor',
  'Zoe',
];

/**
 * display each peer's name
 */
export function displayPeers(
  peers: Array<{ clientID: string; presence: Indexable }>,
) {
  const users = [];
  for (const { presence } of peers) {
    users.push(presence.userName);
  }

  return users;
}

/**
 * create random name of anonymous peer
 */
export function createRandomPeers() {
  const index = Math.floor(Math.random() * randomPeers.length);

  return randomPeers[index];
}


================================================
FILE: examples/nextjs-scheduler/app/utils/parseDate.ts
================================================
/**
 * transform date format to DD-MM-YYYY
 */
export function parseDate(date: Date) {
  let [month, day, year] = date.toLocaleDateString('en').split('/');

  month = Number(month) > 9 ? month : '0' + month;
  day = Number(day) > 9 ? day : '0' + day;
  year = year.slice(2);

  return `${day}-${month}-${year}`;
}


================================================
FILE: examples/nextjs-scheduler/app/utils/types.ts
================================================
export interface ENVtypes {
  url: string;
  apiKey: string;
}

export interface ContentTypes {
  date: string;
  text: string;
}

export interface EditorPropsTypes {
  content: Array<ContentTypes>;
  actions: {
    addContent(date: string, text: string): void;
    deleteContent(date: string): void;
    updateContent(date: string, text: string): void;
  };
}

export type ChangeEventHandler = (
  event: React.ChangeEvent<HTMLInputElement>,
) => void;

type ValuePiece = Date;

export type CalendarValue = ValuePiece | [ValuePiece, ValuePiece];


================================================
FILE: examples/nextjs-scheduler/eslint.config.mjs
================================================
import nextConfig from 'eslint-config-next';
import { globalIgnores } from 'eslint/config';
import tseslint from 'typescript-eslint';
import prettierPlugin from 'eslint-plugin-prettier';

export default tseslint.config(
  ...nextConfig,
  {
    plugins: {
      prettier: prettierPlugin,
    },
    rules: {
      'prettier/prettier': 'error',
      '@next/next/no-html-link-for-pages': 'off',
    },
  },
  globalIgnores(['dist/*']),
);


================================================
FILE: examples/nextjs-scheduler/next.config.js
================================================
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export',
  distDir: 'dist',
  basePath: process.env.NEXT_PUBLIC_BASE_PATH || '',
  assetPrefix: process.env.NEXT_PUBLIC_BASE_PATH || '',
  reactStrictMode: false,
};

module.exports = nextConfig;


================================================
FILE: examples/nextjs-scheduler/package.json
================================================
{
  "name": "nextjs-scheduler",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "dev": "next dev -p 5174",
    "build": "next build",
    "start": "next start",
    "lint": "eslint ."
  },
  "dependencies": {
    "@yorkie-js/sdk": "workspace:*",
    "next": "16.2.6",
    "react": "19.2.1",
    "react-calendar": "^6.0.0",
    "react-dom": "19.2.1"
  },
  "devDependencies": {
    "@types/node": "24.10.1",
    "@types/react": "19.2.7",
    "@types/react-dom": "19.2.3",
    "eslint-config-next": "16.2.6",
    "eslint-config-prettier": "^10.1.8",
    "prettier": "^3.7.4",
    "typescript": "5.9.3"
  }
}


================================================
FILE: examples/nextjs-scheduler/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "ESNext",
    "lib": [
      "DOM",
      "DOM.Iterable",
      "ESNext"
    ],
    "allowJs": false,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "ESNext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": [
        "./*"
      ],
      "react": [
        "./node_modules/@types/react"
      ],
      "@yorkie-js/sdk/src/*": [
        "../../packages/sdk/src/*"
      ]
    }
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    ".next/types/**/*.ts",
    "dist/types/**/*.ts",
    ".next/dev/types/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}


================================================
FILE: examples/nextjs-todolist/.gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts


================================================
FILE: examples/nextjs-todolist/README.md
================================================
# Yorkie Nextjs Todo List Example

<p>
    <a href="https://yorkie.dev/yorkie-js-sdk/examples/nextjs-todolist/" target="_blank">
        <img src="https://img.shields.io/badge/preview-message?style=flat-square&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMTUiIHZpZXdCb3g9IjAgMCAyNCAxNSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTYuODU3MTcgMi43ODE5OUwxMS4yNzUxIDkuMTI2NzhDMTEuNTU0NCA5LjUyODAxIDEyLjEwNjIgOS42MjY3NiAxMi41MDc0IDkuMzQ3NDRDMTIuNTkzNCA5LjI4NzUgMTIuNjY4MSA5LjIxMjggMTIuNzI4MSA5LjEyNjc4TDE3LjE0NiAyLjc4MTk5QzE3LjcwNDggMS45Nzk1NCAxNy41MDcyIDAuODc2MTMxIDE2LjcwNDggMC4zMTc0OTRDMTYuNDA4IDAuMTEwODM3IDE2LjA1NSAwIDE1LjY5MzIgMEg4LjMxMDAxQzcuMzMyMiAwIDYuNTM5NTUgMC43OTI2NTQgNi41Mzk1NSAxLjc3MDQ2QzYuNTM5NjggMi4xMzIxMSA2LjY1MDUxIDIuNDg1MTEgNi44NTcxNyAyLjc4MTk5WiIgZmlsbD0iIzUxNEM0OSIvPgo8cGF0aCBkPSJNMTMuODA4OSAxNC4yMzg4QzE0LjEyMzEgMTQuNDE4IDE0LjQ4NDcgMTQuNDk2NiAxNC44NDUgMTQuNDY0MkwyMi45MjYgMTMuNzM1QzIzLjU3NTMgMTMuNjc2NSAyNC4wNTQgMTMuMTAyNyAyMy45OTU1IDEyLjQ1MzVDMjMuOTkyNCAxMi40MTkyIDIzLjk4NzggMTIuMzg1MSAyMy45ODE3IDEyLjM1MTNDMjMuNzM4OSAxMC45OTY4IDIzLjI2MTEgOS42OTUyNyAyMi41Njk5IDguNTA1NDZDMjEuODc4NiA3LjMxNTY1IDIwLjk4NDggNi4yNTU3NyAxOS45Mjg2IDUuMzczOTFDMTkuNDI4MiA0Ljk1NjE0IDE4LjY4MzkgNS4wMjMwNyAxOC4yNjYyIDUuNTIzNTZDMTguMjQ0MiA1LjU0OTkgMTguMjIzMyA1LjU3NzI2IDE4LjIwMzYgNS42MDU1MUwxMy41NjcgMTIuMjY0MUMxMy4zNjAzIDEyLjU2MSAxMy4yNDk1IDEyLjkxNCAxMy4yNDk1IDEzLjI3NThWMTMuMjUzN0MxMy4yNDk1IDEzLjQ1NjIgMTMuMzAxNiAxMy42NTU0IDEzLjQwMDggMTMuODMxOUMxMy41MDUgMTQuMDA1NCAxMy42NTIxIDE0LjE0OTMgMTMuODI4MSAxNC4yNDk2IiBmaWxsPSIjRkRDNDMzIi8+CjxwYXRoIGQ9Ik0xMC42NDE2IDEzLjc0MzRDMTAuNTM3NSAxMy45NTU5IDEwLjM3MiAxNC4xMzIyIDEwLjE2NjUgMTQuMjQ5NEwxMC4xOTE1IDE0LjIzNTFDOS44NzczNCAxNC40MTQzIDkuNTE1NjkgMTQuNDkyOSA5LjE1NTQ0IDE0LjQ2MDVMMS4wNzQ0MSAxMy43MzEzQzEuMDQwMTggMTMuNzI4MyAxLjAwNjA3IDEzLjcyMzcgMC45NzIyMjUgMTMuNzE3NkMwLjMzMDYyIDEzLjYwMjUgLTAuMDk2MzExOSAxMi45ODkyIDAuMDE4NzI0MiAxMi4zNDc2QzAuMjYxNTIyIDEwLjk5MyAwLjczOTM1NCA5LjY5MTU2IDEuNDMwNDYgOC41MDE2M0MyLjEyMTU3IDcuMzExNjkgMy4wMTU1MSA2LjI1MjA2IDQuMDcxODQgNS4zNzAwOEM0LjA5ODE4IDUuMzQ4MDYgNC4xMjU1NCA1LjMyNzE5IDQuMTUzNzkgNS4zMDc0N0M0LjY4ODc2IDQuOTM1IDUuNDI0MjcgNS4wNjY3MSA1Ljc5Njg3IDUuNjAxNjhMMTAuNDMzNCAxMi4yNjA0QzEwLjY0MDEgMTIuNTU3MyAxMC43NTA5IDEyLjkxMDMgMTAuNzUwOSAxMy4yNzIxVjEzLjI0MzJDMTAuNzUwOSAxMy40Nzk3IDEwLjY3OTggMTMuNzExIDEwLjU0NjggMTMuOTA2NyIgZmlsbD0iI0ZEQzQzMyIvPgo8L3N2Zz4K&color=FEF3D7" alt="Live Preview" />
    </a>
</p>

<img width="500" alt="Nextjs TodoList" src="thumbnail.jpg"/>

A real-time collaborative todo list that enables multiple users to edit simultaneously using [Yorkie](https://yorkie-dev/).

## How to run demo

### With Yorkie Dashboard

Install dependencies

```bash
# In the root directory of the repository.
$ pnpm install
```

Create an account on [Yorkie Dashboard](https://yorkie.dev/dashboard)
Create a new project and copy your public key from the dashboard
Update the `.env` file like so:

```
NEXT_PUBLIC_YORKIE_API_ADDR='https://api.yorkie.dev'
NEXT_PUBLIC_YORKIE_API_KEY='your_key_xxxx'
```

Start demo project

```bash
# In the root directory of the repository.
$ pnpm nextjs-todolist dev

# Or in the directory of the example.
$ pnpm dev
```

### With local Yorkie server

Install dependencies

```bash
# In the root directory of the repository.
$ pnpm install
```

At project root, run below command to start Yorkie.

```bash
$ docker compose -f docker/docker-compose.yml up --build -d
```

Update the `.env` file like so:

```
NEXT_PUBLIC_YORKIE_API_ADDR='http://localhost:8080'
NEXT_PUBLIC_YORKIE_API_KEY=''
```

Start demo project

```bash
# In the root directory of the repository.
$ pnpm nextjs-todolist dev

# Or in the directory of the example.
$ pnpm dev
```


================================================
FILE: examples/nextjs-todolist/app/globals.css
================================================
@import "tailwindcss";
@import "tw-animate-css";

@custom-variant dark (&:is(.dark *));

@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --font-sans: var(--font-geist-sans);
  --font-mono: var(--font-geist-mono);
  --color-sidebar-ring: var(--sidebar-ring);
  --color-sidebar-border: var(--sidebar-border);
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
  --color-sidebar-accent: var(--sidebar-accent);
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
  --color-sidebar-primary: var(--sidebar-primary);
  --color-sidebar-foreground: var(--sidebar-foreground);
  --color-sidebar: var(--sidebar);
  --color-chart-5: var(--chart-5);
  --color-chart-4: var(--chart-4);
  --color-chart-3: var(--chart-3);
  --color-chart-2: var(--chart-2);
  --color-chart-1: var(--chart-1);
  --color-ring: var(--ring);
  --color-input: var(--input);
  --color-border: var(--border);
  --color-destructive: var(--destructive);
  --color-accent-foreground: var(--accent-foreground);
  --color-accent: var(--accent);
  --color-muted-foreground: var(--muted-foreground);
  --color-muted: var(--muted);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-secondary: var(--secondary);
  --color-primary-foreground: var(--primary-foreground);
  --color-primary: var(--primary);
  --color-popover-foreground: var(--popover-foreground);
  --color-popover: var(--popover);
  --color-card-foreground: var(--card-foreground);
  --color-card: var(--card);
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);
}

:root {
  --radius: 0.625rem;
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.145 0 0);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.145 0 0);
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
  --secondary: oklch(0.97 0 0);
  --secondary-foreground: oklch(0.205 0 0);
  --muted: oklch(0.97 0 0);
  --muted-foreground: oklch(0.556 0 0);
  --accent: oklch(0.97 0 0);
  --accent-foreground: oklch(0.205 0 0);
  --destructive: oklch(0.577 0.245 27.325);
  --border: oklch(0.922 0 0);
  --input: oklch(0.922 0 0);
  --ring: oklch(0.708 0 0);
  --chart-1: oklch(0.646 0.222 41.116);
  --chart-2: oklch(0.6 0.118 184.704);
  --chart-3: oklch(0.398 0.07 227.392);
  --chart-4: oklch(0.828 0.189 84.429);
  --chart-5: oklch(0.769 0.188 70.08);
  --sidebar: oklch(0.985 0 0);
  --sidebar-foreground: oklch(0.145 0 0);
  --sidebar-primary: oklch(0.205 0 0);
  --sidebar-primary-foreground: oklch(0.985 0 0);
  --sidebar-accent: oklch(0.97 0 0);
  --sidebar-accent-foreground: oklch(0.205 0 0);
  --sidebar-border: oklch(0.922 0 0);
  --sidebar-ring: oklch(0.708 0 0);
}

.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  --card: oklch(0.205 0 0);
  --card-foreground: oklch(0.985 0 0);
  --popover: oklch(0.205 0 0);
  --popover-foreground: oklch(0.985 0 0);
  --primary: oklch(0.922 0 0);
  --primary-foreground: oklch(0.205 0 0);
  --secondary: oklch(0.269 0 0);
  --secondary-foreground: oklch(0.985 0 0);
  --muted: oklch(0.269 0 0);
  --muted-foreground: oklch(0.708 0 0);
  --accent: oklch(0.269 0 0);
  --accent-foreground: oklch(0.985 0 0);
  --destructive: oklch(0.704 0.191 22.216);
  --border: oklch(1 0 0 / 10%);
  --input: oklch(1 0 0 / 15%);
  --ring: oklch(0.556 0 0);
  --chart-1: oklch(0.488 0.243 264.376);
  --chart-2: oklch(0.696 0.17 162.48);
  --chart-3: oklch(0.769 0.188 70.08);
  --chart-4: oklch(0.627 0.265 303.9);
  --chart-5: oklch(0.645 0.246 16.439);
  --sidebar: oklch(0.205 0 0);
  --sidebar-foreground: oklch(0.985 0 0);
  --sidebar-primary: oklch(0.488 0.243 264.376);
  --sidebar-primary-foreground: oklch(0.985 0 0);
  --sidebar-accent: oklch(0.269 0 0);
  --sidebar-accent-foreground: oklch(0.985 0 0);
  --sidebar-border: oklch(1 0 0 / 10%);
  --sidebar-ring: oklch(0.556 0 0);
}

@layer base {
  * {
    @apply border-border outline-ring/50;
  }
  body {
    @apply bg-background text-foreground;
  }
}


================================================
FILE: examples/nextjs-todolist/app/layout.tsx
================================================
import type { Metadata } from 'next';
import { Geist, Geist_Mono } from 'next/font/google';
import './globals.css';

const geistSans = Geist({
  variable: '--font-geist-sans',
  subsets: ['latin'],
});

const geistMono = Geist_Mono({
  variable: '--font-geist-mono',
  subsets: ['latin'],
});

export const metadata: Metadata = {
  title: 'Yorkie • Next.js TodoList',
  description: 'Simple Collaborative TodoList using Yorkie and Next.js',
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
        {children}
      </body>
    </html>
  );
}


================================================
FILE: examples/nextjs-todolist/app/page.tsx
================================================
'use client';

import { YorkieProvider, DocumentProvider } from '@yorkie-js/react';
import TodoList from '../components/TodoList';

export default function Home() {
  return (
    <YorkieProvider
      apiKey={process.env.NEXT_PUBLIC_YORKIE_API_KEY || ''}
      rpcAddr={process.env.NEXT_PUBLIC_YORKIE_API_ADDR}
    >
      <DocumentProvider docKey="nextjs-todolist" initialRoot={{ todos: [] }}>
        <main className="container mx-auto p-4">
          <TodoList />
        </main>
      </DocumentProvider>
    </YorkieProvider>
  );
}


================================================
FILE: examples/nextjs-todolist/components/TodoList.tsx
================================================
'use client';

import React, { useState, useMemo } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from './ui/card';
import { Input } from './ui/input';
import { Button } from './ui/button';
import { Trash2, Check, Plus } from 'lucide-react';
import { useDocument, JSONArray, JSONObject } from '@yorkie-js/react';

type Todo = {
  id: string;
  text: string;
  completed: boolean;
};

const TodoList = () => {
  const [newTodo, setNewTodo] = useState('');
  const { root, presences, update, loading, error } = useDocument<{
    todos: JSONArray<JSONObject<Todo>>;
  }>();
  const userCount = useMemo(() => {
    return presences?.length;
  }, [presences]);

  const addTodo = () => {
    if (newTodo.trim() !== '') {
      update((root) => {
        root.todos.push({
          id: String(Date.now()),
          text: newTodo,
          completed: false,
        } as JSONObject<Todo>);
      });
      setNewTodo('');
    }
  };

  const toggleTodo = (id: string) => {
    update((root) => {
      for (const todo of root.todos) {
        if (todo.id === id) {
          todo.completed = !todo.completed;
          break;
        }
      }
    });
  };

  const deleteTodo = (id: string) => {
    update((root) => {
      const idx = root.todos.findIndex((todo) => todo.id === id);
      if (idx !== -1) {
        root.todos.delete?.(idx);
      }
    });
  };

  const handleKeyUp = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Enter') {
      addTodo();
    }
  };

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <Card className="w-full max-w-md mx-auto">
      <CardHeader>
        <CardTitle className="text-center">Todo List</CardTitle>
        <div className="text-center text-sm text-gray-500">
          {userCount > 0 ? (
            <div className="flex items-center justify-center gap-2">
              <div className="flex -space-x-2">
                {[...Array(Math.min(userCount, 3))].map((_, i) => (
                  <div
                    key={i}
                    className="h-8 w-8 rounded-full bg-gradient-to-r from-blue-200 to-blue-300 border-2 border-white flex items-center justify-center text-white text-xs"
                  >
                    👤
                  </div>
                ))}
              </div>
              <span>
                {userCount === 1
                  ? 'Working solo'
                  : `${userCount} people in this space`}
              </span>
            </div>
          ) : (
            <span className="text-gray-400">No participants</span>
          )}
        </div>
      </CardHeader>
      <CardContent>
        <div className="flex gap-2 mb-4">
          <Input
            type="text"
            value={newTodo}
            onChange={(e) => setNewTodo(e.target.value)}
            onKeyUp={handleKeyUp}
            placeholder="Enter a new todo"
            className="flex-1"
          />
          <Button onClick={addTodo} className="px-4">
            <Plus className="h-4 w-4" />
          </Button>
        </div>

        <div className="space-y-2">
          {root.todos.map((todo) => (
            <div
              key={todo.id}
              className="flex items-center justify-between p-3 bg-gray-50 rounded-lg"
            >
              <div className="flex items-center gap-2">
                <Button
                  variant={todo.completed ? 'default' : 'outline'}
                  size="sm"
                  onClick={() => toggleTodo(todo.id)}
                >
                  <Check className="h-4 w-4" />
                </Button>
                <span
                  className={`${
                    todo.completed ? 'line-through text-gray-500' : ''
                  }`}
                >
                  {todo.text}
                </span>
              </div>
              <Button
                variant="ghost"
                size="sm"
                onClick={() => deleteTodo(todo.id)}
                className="text-red-500 hover:text-red-700"
              >
                <Trash2 className="h-4 w-4" />
              </Button>
            </div>
          ))}
        </div>
      </CardContent>
    </Card>
  );
};

export default TodoList;


================================================
FILE: examples/nextjs-todolist/components/ui/button.tsx
================================================
import * as React from 'react';
import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from 'class-variance-authority';

import { cn } from '@/lib/utils';

const buttonVariants = cva(
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
  {
    variants: {
      variant: {
        default:
          'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
        destructive:
          'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
        outline:
          'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
        secondary:
          'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
        ghost:
          'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
        link: 'text-primary underline-offset-4 hover:underline',
      },
      size: {
        default: 'h-9 px-4 py-2 has-[>svg]:px-3',
        sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
        lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
        icon: 'size-9',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  },
);

function Button({
  className,
  variant,
  size,
  asChild = false,
  ...props
}: React.ComponentProps<'button'> &
  VariantProps<typeof buttonVariants> & {
    asChild?: boolean;
  }) {
  const Comp = asChild ? Slot : 'button';

  return (
    <Comp
      data-slot="button"
      className={cn(buttonVariants({ variant, size, className }))}
      {...props}
    />
  );
}

export { Button, buttonVariants };


================================================
FILE: examples/nextjs-todolist/components/ui/card.tsx
================================================
import * as React from 'react';

import { cn } from '@/lib/utils';

function Card({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      data-slot="card"
      className={cn(
        'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
        className,
      )}
      {...props}
    />
  );
}

function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      data-slot="card-header"
      className={cn(
        '@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
        className,
      )}
      {...props}
    />
  );
}

function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      data-slot="card-title"
      className={cn('leading-none font-semibold', className)}
      {...props}
    />
  );
}

function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      data-slot="card-description"
      className={cn('text-muted-foreground text-sm', className)}
      {...props}
    />
  );
}

function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      data-slot="card-action"
      className={cn(
        'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
        className,
      )}
      {...props}
    />
  );
}

function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      data-slot="card-content"
      className={cn('px-6', className)}
      {...props}
    />
  );
}

function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      data-slot="card-footer"
      className={cn('flex items-center px-6 [.border-t]:pt-6', className)}
      {...props}
    />
  );
}

export {
  Card,
  CardHeader,
  CardFooter,
  CardTitle,
  CardAction,
  CardDescription,
  CardContent,
};


================================================
FILE: examples/nextjs-todolist/components/ui/input.tsx
================================================
import * as React from 'react';

import { cn } from '@/lib/utils';

function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
  return (
    <input
      type={type}
      data-slot="input"
      className={cn(
        'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
        'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
        'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
        className,
      )}
      {...props}
    />
  );
}

export { Input };


================================================
FILE: examples/nextjs-todolist/components.json
================================================
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "",
    "css": "app/globals.css",
    "baseColor": "neutral",
    "cssVariables": true,
    "prefix": ""
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  },
  "iconLibrary": "lucide"
}


================================================
FILE: examples/nextjs-todolist/eslint.config.mjs
================================================
import nextConfig from 'eslint-config-next';
import { globalIgnores } from 'eslint/config';
import prettierPlugin from 'eslint-plugin-prettier';

const eslintConfig = [
  ...nextConfig,
  {
    plugins: {
      prettier: prettierPlugin,
    },
    rules: {
      'prettier/prettier': 'error',
    },
  },
  globalIgnores(['dist/*']),
];

export default eslintConfig;


================================================
FILE: examples/nextjs-todolist/lib/utils.ts
================================================
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

export const cn = (...inputs: Array<ClassValue>) => {
  return twMerge(clsx(inputs));
};


================================================
FILE: examples/nextjs-todolist/next.config.ts
================================================
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  output: 'export',
  distDir: 'dist',
  basePath: process.env.NEXT_PUBLIC_BASE_PATH || '',
  assetPrefix: process.env.NEXT_PUBLIC_BASE_PATH || '',
  reactStrictMode: false,
};

export default nextConfig;


================================================
FILE: examples/nextjs-todolist/package.json
================================================
{
  "name": "nextjs-todolist",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint ."
  },
  "dependencies": {
    "@radix-ui/react-slot": "^1.2.4",
    "@yorkie-js/react": "workspace:*",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "lucide-react": "^0.555.0",
    "next": "16.2.6",
    "react": "^19.2.1",
    "react-dom": "^19.2.1",
    "tailwind-merge": "^3.4.0",
    "tw-animate-css": "^1.4.0"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "^4.1.17",
    "@types/node": "^24.10.1",
    "@types/react": "^19.2.7",
    "@types/react-dom": "^19.2.3",
    "eslint": "^9.39.1",
    "eslint-config-next": "16.2.6",
    "tailwindcss": "^4.1.17",
    "typescript": "^5.9.3"
  }
}


================================================
FILE: examples/nextjs-todolist/postcss.config.mjs
================================================
const config = {
  plugins: ['@tailwindcss/postcss'],
};

export default config;


================================================
FILE: examples/nextjs-todolist/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "ESNext",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": [
        "./*"
      ],
      "react": [
        "./node_modules/@types/react"
      ],
      "@yorkie-js/sdk/src/*": [
        "../../packages/sdk/src/*"
      ]
    }
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    ".next/types/**/*.ts",
    "dist/types/**/*.ts",
    ".next/dev/types/**/*.ts",
    "dist/dev/types/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}


================================================
FILE: examples/profile-stack/.gitignore
================================================
# 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?


================================================
FILE: examples/profile-stack/README.md
================================================
# Yorkie Profile Stack Example

<p>
    <a href="https://yorkie.dev/yorkie-js-sdk/examples/profile-stack/" target="_blank">
        <img src="https://img.shields.io/badge/preview-message?style=flat-square&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMTUiIHZpZXdCb3g9IjAgMCAyNCAxNSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTYuODU3MTcgMi43ODE5OUwxMS4yNzUxIDkuMTI2NzhDMTEuNTU0NCA5LjUyODAxIDEyLjEwNjIgOS42MjY3NiAxMi41MDc0IDkuMzQ3NDRDMTIuNTkzNCA5LjI4NzUgMTIuNjY4MSA5LjIxMjggMTIuNzI4MSA5LjEyNjc4TDE3LjE0NiAyLjc4MTk5QzE3LjcwNDggMS45Nzk1NCAxNy41MDcyIDAuODc2MTMxIDE2LjcwNDggMC4zMTc0OTRDMTYuNDA4IDAuMTEwODM3IDE2LjA1NSAwIDE1LjY5MzIgMEg4LjMxMDAxQzcuMzMyMiAwIDYuNTM5NTUgMC43OTI2NTQgNi41Mzk1NSAxLjc3MDQ2QzYuNTM5NjggMi4xMzIxMSA2LjY1MDUxIDIuNDg1MTEgNi44NTcxNyAyLjc4MTk5WiIgZmlsbD0iIzUxNEM0OSIvPgo8cGF0aCBkPSJNMTMuODA4OSAxNC4yMzg4QzE0LjEyMzEgMTQuNDE4IDE0LjQ4NDcgMTQuNDk2NiAxNC44NDUgMTQuNDY0MkwyMi45MjYgMTMuNzM1QzIzLjU3NTMgMTMuNjc2NSAyNC4wNTQgMTMuMTAyNyAyMy45OTU1IDEyLjQ1MzVDMjMuOTkyNCAxMi40MTkyIDIzLjk4NzggMTIuMzg1MSAyMy45ODE3IDEyLjM1MTNDMjMuNzM4OSAxMC45OTY4IDIzLjI2MTEgOS42OTUyNyAyMi41Njk5IDguNTA1NDZDMjEuODc4NiA3LjMxNTY1IDIwLjk4NDggNi4yNTU3NyAxOS45Mjg2IDUuMzczOTFDMTkuNDI4MiA0Ljk1NjE0IDE4LjY4MzkgNS4wMjMwNyAxOC4yNjYyIDUuNTIzNTZDMTguMjQ0MiA1LjU0OTkgMTguMjIzMyA1LjU3NzI2IDE4LjIwMzYgNS42MDU1MUwxMy41NjcgMTIuMjY0MUMxMy4zNjAzIDEyLjU2MSAxMy4yNDk1IDEyLjkxNCAxMy4yNDk1IDEzLjI3NThWMTMuMjUzN0MxMy4yNDk1IDEzLjQ1NjIgMTMuMzAxNiAxMy42NTU0IDEzLjQwMDggMTMuODMxOUMxMy41MDUgMTQuMDA1NCAxMy42NTIxIDE0LjE0OTMgMTMuODI4MSAxNC4yNDk2IiBmaWxsPSIjRkRDNDMzIi8+CjxwYXRoIGQ9Ik0xMC42NDE2IDEzLjc0MzRDMTAuNTM3NSAxMy45NTU5IDEwLjM3MiAxNC4xMzIyIDEwLjE2NjUgMTQuMjQ5NEwxMC4xOTE1IDE0LjIzNTFDOS44NzczNCAxNC40MTQzIDkuNTE1NjkgMTQuNDkyOSA5LjE1NTQ0IDE0LjQ2MDVMMS4wNzQ0MSAxMy43MzEzQzEuMDQwMTggMTMuNzI4MyAxLjAwNjA3IDEzLjcyMzcgMC45NzIyMjUgMTMuNzE3NkMwLjMzMDYyIDEzLjYwMjUgLTAuMDk2MzExOSAxMi45ODkyIDAuMDE4NzI0MiAxMi4zNDc2QzAuMjYxNTIyIDEwLjk5MyAwLjczOTM1NCA5LjY5MTU2IDEuNDMwNDYgOC41MDE2M0MyLjEyMTU3IDcuMzExNjkgMy4wMTU1MSA2LjI1MjA2IDQuMDcxODQgNS4zNzAwOEM0LjA5ODE4IDUuMzQ4MDYgNC4xMjU1NCA1LjMyNzE5IDQuMTUzNzkgNS4zMDc0N0M0LjY4ODc2IDQuOTM1IDUuNDI0MjcgNS4wNjY3MSA1Ljc5Njg3IDUuNjAxNjhMMTAuNDMzNCAxMi4yNjA0QzEwLjY0MDEgMTIuNTU3MyAxMC43NTA5IDEyLjkxMDMgMTAuNzUwOSAxMy4yNzIxVjEzLjI0MzJDMTAuNzUwOSAxMy40Nzk3IDEwLjY3OTggMTMuNzExIDEwLjU0NjggMTMuOTA2NyIgZmlsbD0iI0ZEQzQzMyIvPgo8L3N2Zz4K&color=FEF3D7" alt="Live Preview" />
    </a>
</p>

<img width="500" alt="Profile Stack" src="thumbnail.jpg"/>

## How to run demo

At project root, run below command to start Yorkie.

```bash
$ docker compose -f docker/docker-compose.yml up --build -d
```

Install dependencies

```bash
# In the root directory of the repository.
$ pnpm install
```

Start demo project

```bash
# In the root directory of the repository.
$ pnpm profile-stack dev

# Or in the directory of the example.
$ pnpm dev
```


================================================
FILE: examples/profile-stack/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Profile Stack - Yorkie Example</title>
    <link rel="stylesheet" href="/style.css" />
  </head>
  <body>
    <div id="app">
      <div id="peerList"></div>
    </div>

    <!-- Edit Profile Modal -->
    <div id="editProfileModal" class="modal">
      <div class="modal-content">
        <div class="modal-header">
          <img alt="profile" class="profile-img" />
          <button class="close">&times;</button>
        </div>
        <div class="modal-body">
          <input
            type="text"
            id="usernameInput"
            placeholder="Enter new username"
          />
          <
Download .txt
gitextract_9k73p22c/

├── .editorconfig
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.md
│   │   ├── common-issue.md
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── ci.yml
│       ├── devtools-publish.yml
│       ├── github-page-publish.yml
│       └── npm-publish.yml
├── .gitignore
├── .husky/
│   ├── commit-msg
│   └── pre-commit
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc.js
├── CHANGELOG.md
├── CLAUDE.md
├── CONTRIBUTING.md
├── LICENSE
├── MAINTAINING.md
├── README.md
├── codecov.yml
├── docker/
│   ├── docker-compose-ci.yml
│   └── docker-compose.yml
├── eslint.config.mjs
├── examples/
│   ├── CONTRIBUTING.md
│   ├── README.md
│   ├── nextjs-presence/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── app/
│   │   │   ├── App.css
│   │   │   ├── api/
│   │   │   │   └── channels/
│   │   │   │       └── route.ts
│   │   │   ├── globals.css
│   │   │   ├── layout.tsx
│   │   │   └── page.tsx
│   │   ├── components/
│   │   │   ├── RoomSelector.css
│   │   │   ├── RoomSelector.tsx
│   │   │   ├── RoomView.css
│   │   │   ├── RoomView.tsx
│   │   │   ├── SessionCounter.css
│   │   │   └── SessionCounter.tsx
│   │   ├── eslint.config.mjs
│   │   ├── lib/
│   │   │   └── rooms.ts
│   │   ├── next.config.ts
│   │   ├── package.json
│   │   └── tsconfig.json
│   ├── nextjs-scheduler/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── app/
│   │   │   ├── Scheduler.tsx
│   │   │   ├── layout.tsx
│   │   │   ├── not-found.tsx
│   │   │   ├── page.tsx
│   │   │   ├── styles/
│   │   │   │   ├── calendar.css
│   │   │   │   ├── globals.css
│   │   │   │   └── page.module.css
│   │   │   └── utils/
│   │   │       ├── handlePeers.ts
│   │   │       ├── parseDate.ts
│   │   │       └── types.ts
│   │   ├── eslint.config.mjs
│   │   ├── next.config.js
│   │   ├── package.json
│   │   └── tsconfig.json
│   ├── nextjs-todolist/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── app/
│   │   │   ├── globals.css
│   │   │   ├── layout.tsx
│   │   │   └── page.tsx
│   │   ├── components/
│   │   │   ├── TodoList.tsx
│   │   │   └── ui/
│   │   │       ├── button.tsx
│   │   │       ├── card.tsx
│   │   │       └── input.tsx
│   │   ├── components.json
│   │   ├── eslint.config.mjs
│   │   ├── lib/
│   │   │   └── utils.ts
│   │   ├── next.config.ts
│   │   ├── package.json
│   │   ├── postcss.config.mjs
│   │   └── tsconfig.json
│   ├── profile-stack/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── main.js
│   │   ├── package.json
│   │   ├── style.css
│   │   ├── util.js
│   │   └── vite.config.js
│   ├── react-document-limit/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── components/
│   │   │   │   ├── ConnectionStatus.tsx
│   │   │   │   ├── Counter.tsx
│   │   │   │   ├── CounterNumber.tsx
│   │   │   │   ├── IncrementButton.tsx
│   │   │   │   └── Peers.tsx
│   │   │   ├── hooks/
│   │   │   │   └── useDocumentSelector.tsx
│   │   │   ├── index.css
│   │   │   ├── main.tsx
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── react-flow/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.tsx
│   │   │   ├── index.css
│   │   │   ├── main.tsx
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── react-polling-playground/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── Leaderboard.tsx
│   │   │   ├── StockDetail.tsx
│   │   │   ├── StockRow.tsx
│   │   │   ├── WritePostPage.tsx
│   │   │   ├── main.tsx
│   │   │   ├── stocks.ts
│   │   │   ├── styles.css
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── react-revision/
│   │   ├── eslint.config.mjs
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.tsx
│   │   │   ├── RevisionPanel.tsx
│   │   │   ├── main.tsx
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── react-tldraw/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.tsx
│   │   │   ├── CustomCursor.tsx
│   │   │   ├── hooks/
│   │   │   │   ├── types.ts
│   │   │   │   └── useMultiplayerState.ts
│   │   │   ├── main.tsx
│   │   │   ├── tldraw.d.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── react-todomvc/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── eslint.config.mjs
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.tsx
│   │   │   ├── components/
│   │   │   │   ├── Footer.tsx
│   │   │   │   ├── Header.tsx
│   │   │   │   ├── MainSection.tsx
│   │   │   │   ├── TodoItem.tsx
│   │   │   │   └── TodoTextInput.tsx
│   │   │   ├── main.tsx
│   │   │   ├── model.ts
│   │   │   ├── todoReducer.ts
│   │   │   ├── useTodoReducer.tsx
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── simultaneous-cursors/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.jsx
│   │   │   ├── components/
│   │   │   │   ├── ColoredIcon.jsx
│   │   │   │   ├── Cursor.jsx
│   │   │   │   ├── CursorSelections.css
│   │   │   │   ├── CursorSelections.jsx
│   │   │   │   ├── FullAnimation.jsx
│   │   │   │   ├── PenCursor.jsx
│   │   │   │   ├── SingleAnimation.jsx
│   │   │   │   └── SingleAnimation.module.css
│   │   │   ├── hooks/
│   │   │   │   └── useInterval.jsx
│   │   │   └── main.jsx
│   │   └── vite.config.js
│   ├── vanilla-codemirror6/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── main.ts
│   │   │   ├── network.ts
│   │   │   ├── style.css
│   │   │   ├── type.ts
│   │   │   ├── utils.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.js
│   ├── vanilla-document-limit/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── connection.ts
│   │   │   ├── counter.ts
│   │   │   ├── index.css
│   │   │   ├── main.ts
│   │   │   ├── peer.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── vanilla-prosemirror/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── main.ts
│   │   │   ├── style.css
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.js
│   ├── vanilla-quill/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── main.ts
│   │   │   ├── network.ts
│   │   │   ├── style.css
│   │   │   ├── type.ts
│   │   │   ├── utils.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.js
│   └── vuejs-kanban/
│       ├── .gitignore
│       ├── README.md
│       ├── index.html
│       ├── package.json
│       ├── src/
│       │   ├── App.vue
│       │   ├── assets/
│       │   │   └── main.css
│       │   └── main.js
│       └── vite.config.js
├── lint-staged.config.mjs
├── package.json
├── packages/
│   ├── devtools/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── content.ts
│   │   │   ├── devtools/
│   │   │   │   ├── components/
│   │   │   │   │   ├── Code.tsx
│   │   │   │   │   ├── Detail.tsx
│   │   │   │   │   ├── JsonView.tsx
│   │   │   │   │   ├── ResizableSeparator.tsx
│   │   │   │   │   └── Tree.tsx
│   │   │   │   ├── contexts/
│   │   │   │   │   ├── SelectedNode.tsx
│   │   │   │   │   ├── SelectedPresence.tsx
│   │   │   │   │   └── YorkieSource.tsx
│   │   │   │   ├── icons/
│   │   │   │   │   └── index.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   ├── panel/
│   │   │   │   │   ├── code.css
│   │   │   │   │   ├── index.html
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── slider.css
│   │   │   │   │   └── styles.css
│   │   │   │   └── tabs/
│   │   │   │       ├── Document.tsx
│   │   │   │       ├── History.tsx
│   │   │   │       └── Presence.tsx
│   │   │   ├── popup/
│   │   │   │   └── index.tsx
│   │   │   └── port.ts
│   │   └── tsconfig.json
│   ├── prosemirror/
│   │   ├── README.md
│   │   ├── examples/
│   │   │   ├── basic.html
│   │   │   ├── basic.ts
│   │   │   ├── custom-schema.html
│   │   │   ├── custom-schema.ts
│   │   │   ├── index.html
│   │   │   ├── style.css
│   │   │   ├── tree-schema.html
│   │   │   └── tree-schema.ts
│   │   ├── package.json
│   │   ├── scripts/
│   │   │   └── setup-tree-schema.ts
│   │   ├── src/
│   │   │   ├── binding.ts
│   │   │   ├── convert.ts
│   │   │   ├── cursor.ts
│   │   │   ├── defaults.ts
│   │   │   ├── diff.ts
│   │   │   ├── index.ts
│   │   │   ├── position.ts
│   │   │   ├── selection-plugin.ts
│   │   │   ├── sync.ts
│   │   │   └── types.ts
│   │   ├── test/
│   │   │   ├── integration/
│   │   │   │   └── split_merge_test.ts
│   │   │   └── unit/
│   │   │       ├── convert_test.ts
│   │   │       ├── custom_schema_test.ts
│   │   │       ├── defaults_test.ts
│   │   │       ├── diff_test.ts
│   │   │       ├── helpers.ts
│   │   │       ├── position_test.ts
│   │   │       └── sync_test.ts
│   │   ├── tsconfig.json
│   │   ├── vite.build.ts
│   │   ├── vite.config.ts
│   │   └── vitest.config.ts
│   ├── react/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── ChannelProvider.tsx
│   │   │   ├── DocumentProvider.tsx
│   │   │   ├── YorkieProvider.tsx
│   │   │   ├── createChannelStore.ts
│   │   │   ├── createDocumentStore.ts
│   │   │   ├── createStore.ts
│   │   │   ├── index.ts
│   │   │   ├── shallowEqual.ts
│   │   │   ├── usePeekChannel.ts
│   │   │   ├── useSelector.ts
│   │   │   └── useYorkieDoc.ts
│   │   ├── test/
│   │   │   ├── integration/
│   │   │   │   └── integration.test.tsx
│   │   │   ├── test-setup.ts
│   │   │   └── unit/
│   │   │       ├── createDocumentSelector.test.tsx
│   │   │       ├── useRevisions.test.tsx
│   │   │       ├── useSelector.test.ts
│   │   │       └── useYorkieDoc.test.ts
│   │   ├── tsconfig.json
│   │   ├── vite.config.js
│   │   └── vitest.config.ts
│   ├── schema/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── antlr/
│   │   │   ├── YorkieSchema.g4
│   │   │   ├── YorkieSchema.interp
│   │   │   ├── YorkieSchema.tokens
│   │   │   ├── YorkieSchemaLexer.interp
│   │   │   ├── YorkieSchemaLexer.tokens
│   │   │   ├── YorkieSchemaLexer.ts
│   │   │   ├── YorkieSchemaListener.ts
│   │   │   ├── YorkieSchemaParser.ts
│   │   │   └── YorkieSchemaVisitor.ts
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── style.css
│   │   ├── src/
│   │   │   ├── index.ts
│   │   │   ├── main.ts
│   │   │   ├── rulesets.ts
│   │   │   ├── validator.ts
│   │   │   └── vite-env.d.ts
│   │   ├── test/
│   │   │   ├── ruleset.test.ts
│   │   │   └── validator.test.ts
│   │   ├── tsconfig.json
│   │   ├── vite.build.ts
│   │   └── vite.config.ts
│   └── sdk/
│       ├── README.md
│       ├── buf.gen.yaml
│       ├── eslint.config.mjs
│       ├── index.html
│       ├── package.json
│       ├── public/
│       │   ├── counter.html
│       │   ├── devtool/
│       │   │   ├── network.js
│       │   │   ├── object.css
│       │   │   ├── object.js
│       │   │   ├── text.css
│       │   │   └── text.js
│       │   ├── drawing.html
│       │   ├── multi.html
│       │   ├── presence.html
│       │   ├── quill.css
│       │   ├── quill.html
│       │   ├── schema.html
│       │   ├── style.css
│       │   ├── tree-schema.html
│       │   ├── whiteboard.css
│       │   └── whiteboard.html
│       ├── scripts/
│       │   └── update-examples.sh
│       ├── src/
│       │   ├── api/
│       │   │   ├── converter.ts
│       │   │   ├── revision.ts
│       │   │   └── yorkie/
│       │   │       └── v1/
│       │   │           ├── resources.proto
│       │   │           ├── resources_pb.ts
│       │   │           ├── yorkie.proto
│       │   │           └── yorkie_pb.ts
│       │   ├── channel/
│       │   │   └── channel.ts
│       │   ├── client/
│       │   │   ├── attachable.ts
│       │   │   ├── attachment.ts
│       │   │   ├── auth_interceptor.ts
│       │   │   ├── client.ts
│       │   │   ├── metric_interceptor.ts
│       │   │   └── watch.ts
│       │   ├── devtools/
│       │   │   ├── index.ts
│       │   │   ├── protocol.ts
│       │   │   └── types.ts
│       │   ├── document/
│       │   │   ├── change/
│       │   │   │   ├── change.ts
│       │   │   │   ├── change_id.ts
│       │   │   │   ├── change_pack.ts
│       │   │   │   ├── checkpoint.ts
│       │   │   │   └── context.ts
│       │   │   ├── crdt/
│       │   │   │   ├── array.ts
│       │   │   │   ├── counter.ts
│       │   │   │   ├── element.ts
│       │   │   │   ├── element_rht.ts
│       │   │   │   ├── gc.ts
│       │   │   │   ├── hll.ts
│       │   │   │   ├── object.ts
│       │   │   │   ├── primitive.ts
│       │   │   │   ├── rga_tree_list.ts
│       │   │   │   ├── rga_tree_split.ts
│       │   │   │   ├── rht.ts
│       │   │   │   ├── root.ts
│       │   │   │   ├── text.ts
│       │   │   │   └── tree.ts
│       │   │   ├── document.ts
│       │   │   ├── history.ts
│       │   │   ├── json/
│       │   │   │   ├── array.ts
│       │   │   │   ├── counter.ts
│       │   │   │   ├── element.ts
│       │   │   │   ├── object.ts
│       │   │   │   ├── strings.ts
│       │   │   │   ├── text.ts
│       │   │   │   └── tree.ts
│       │   │   ├── operation/
│       │   │   │   ├── add_operation.ts
│       │   │   │   ├── array_set_operation.ts
│       │   │   │   ├── edit_operation.ts
│       │   │   │   ├── increase_operation.ts
│       │   │   │   ├── move_operation.ts
│       │   │   │   ├── operation.ts
│       │   │   │   ├── remove_operation.ts
│       │   │   │   ├── set_operation.ts
│       │   │   │   ├── style_operation.ts
│       │   │   │   ├── tree_edit_operation.ts
│       │   │   │   └── tree_style_operation.ts
│       │   │   ├── presence/
│       │   │   │   ├── change.ts
│       │   │   │   └── presence.ts
│       │   │   ├── schema/
│       │   │   │   ├── content-expression.ts
│       │   │   │   ├── ruleset_validator.ts
│       │   │   │   └── tree-validator.ts
│       │   │   ├── time/
│       │   │   │   ├── actor_id.ts
│       │   │   │   ├── ticket.ts
│       │   │   │   └── version_vector.ts
│       │   │   └── yson/
│       │   │       ├── index.ts
│       │   │       ├── parser.ts
│       │   │       └── types.ts
│       │   ├── util/
│       │   │   ├── comparator.ts
│       │   │   ├── error.ts
│       │   │   ├── index_tree.ts
│       │   │   ├── llrb_tree.ts
│       │   │   ├── logger.ts
│       │   │   ├── number.ts
│       │   │   ├── object.ts
│       │   │   ├── observable.ts
│       │   │   ├── resource.ts
│       │   │   ├── splay_tree.ts
│       │   │   ├── uuid.ts
│       │   │   └── validator.ts
│       │   └── yorkie.ts
│       ├── test/
│       │   ├── bench/
│       │   │   ├── counter.bench.ts
│       │   │   ├── document.bench.ts
│       │   │   ├── editing-trace.json
│       │   │   ├── splay_tree.bench.ts
│       │   │   ├── text.bench.ts
│       │   │   └── tree.bench.ts
│       │   ├── helper/
│       │   │   ├── helper.ts
│       │   │   └── vector_utils.ts
│       │   ├── integration/
│       │   │   ├── array_test.ts
│       │   │   ├── broadcast_test.ts
│       │   │   ├── channel_polling_test.ts
│       │   │   ├── channel_test.ts
│       │   │   ├── client_test.ts
│       │   │   ├── counter_test.ts
│       │   │   ├── doc_presence_test.ts
│       │   │   ├── document_limit_test.ts
│       │   │   ├── document_polling_test.ts
│       │   │   ├── document_schema_test.ts
│       │   │   ├── document_test.ts
│       │   │   ├── epoch_mismatch_test.ts
│       │   │   ├── gc_test.ts
│       │   │   ├── history_array_test.ts
│       │   │   ├── history_text_test.ts
│       │   │   ├── history_tree_split_test.ts
│       │   │   ├── history_tree_test.ts
│       │   │   ├── integration_helper.ts
│       │   │   ├── object_test.ts
│       │   │   ├── presence_test.ts
│       │   │   ├── primitive_test.ts
│       │   │   ├── revision_test.ts
│       │   │   ├── snapshot_test.ts
│       │   │   ├── text_test.ts
│       │   │   ├── tree_concurrency_test.ts
│       │   │   ├── tree_test.ts
│       │   │   └── webhook_test.ts
│       │   ├── unit/
│       │   │   ├── api/
│       │   │   │   └── converter_test.ts
│       │   │   ├── channel/
│       │   │   │   └── channel_test.ts
│       │   │   ├── document/
│       │   │   │   ├── crdt/
│       │   │   │   │   ├── counter_test.ts
│       │   │   │   │   ├── element_rht_test.ts
│       │   │   │   │   ├── primitive_test.ts
│       │   │   │   │   ├── rht_test.ts
│       │   │   │   │   ├── root_test.ts
│       │   │   │   │   └── tree_test.ts
│       │   │   │   ├── document_size_test.ts
│       │   │   │   ├── document_test.ts
│       │   │   │   ├── gc_test.ts
│       │   │   │   ├── schema/
│       │   │   │   │   ├── content_expression_test.ts
│       │   │   │   │   ├── tree_schema_integration_test.ts
│       │   │   │   │   └── tree_validator_test.ts
│       │   │   │   └── yson_test.ts
│       │   │   ├── schema/
│       │   │   │   └── ruleset_validator_test.ts
│       │   │   └── util/
│       │   │       ├── index_tree_test.ts
│       │   │       ├── llrb_tree_test.ts
│       │   │       ├── logger_test.ts
│       │   │       └── splay_tree_test.ts
│       │   ├── vitest.d.ts
│       │   └── vitest.setup.ts
│       ├── tsconfig.json
│       ├── typedoc.json
│       ├── vite.build.ts
│       ├── vite.config.ts
│       └── vitest.config.ts
├── pnpm-workspace.yaml
└── scripts/
    ├── setup.sh
    ├── tasks-archive.sh
    └── tasks-index.sh
Download .txt
Showing preview only (205K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2494 symbols across 235 files)

FILE: examples/nextjs-presence/app/api/channels/route.ts
  function POST (line 1) | async function POST(request: Request) {

FILE: examples/nextjs-presence/app/layout.tsx
  function RootLayout (line 10) | function RootLayout({

FILE: examples/nextjs-presence/app/page.tsx
  function App (line 10) | function App() {

FILE: examples/nextjs-presence/components/RoomSelector.tsx
  type RoomSelectorProps (line 4) | interface RoomSelectorProps {
  function RoomSelector (line 9) | function RoomSelector({ onRoomSelect, sessions }: RoomSelectorProps) {

FILE: examples/nextjs-presence/components/RoomView.tsx
  type RoomViewProps (line 8) | interface RoomViewProps {
  function RoomView (line 13) | function RoomView({ roomId, onLeave }: RoomViewProps) {

FILE: examples/nextjs-presence/components/SessionCounter.tsx
  function SessionCounter (line 7) | function SessionCounter() {
  function SimpleSessionCounter (line 78) | function SimpleSessionCounter() {

FILE: examples/nextjs-presence/lib/rooms.ts
  type RoomCategory (line 2) | interface RoomCategory {
  type Room (line 10) | interface Room {
  constant ROOM_CATEGORIES (line 19) | const ROOM_CATEGORIES: RoomCategory[] = [
  constant ROOMS (line 67) | const ROOMS = generateRooms();

FILE: examples/nextjs-scheduler/app/Scheduler.tsx
  function Scheduler (line 14) | function Scheduler(props: EditorPropsTypes) {

FILE: examples/nextjs-scheduler/app/layout.tsx
  function RootLayout (line 15) | function RootLayout({

FILE: examples/nextjs-scheduler/app/not-found.tsx
  function notFound (line 4) | function notFound() {

FILE: examples/nextjs-scheduler/app/page.tsx
  constant ENV (line 27) | const ENV: ENVtypes = {
  function Editor (line 37) | function Editor() {

FILE: examples/nextjs-scheduler/app/utils/handlePeers.ts
  function displayPeers (line 24) | function displayPeers(
  function createRandomPeers (line 38) | function createRandomPeers() {

FILE: examples/nextjs-scheduler/app/utils/parseDate.ts
  function parseDate (line 4) | function parseDate(date: Date) {

FILE: examples/nextjs-scheduler/app/utils/types.ts
  type ENVtypes (line 1) | interface ENVtypes {
  type ContentTypes (line 6) | interface ContentTypes {
  type EditorPropsTypes (line 11) | interface EditorPropsTypes {
  type ChangeEventHandler (line 20) | type ChangeEventHandler = (
  type ValuePiece (line 24) | type ValuePiece = Date;
  type CalendarValue (line 26) | type CalendarValue = ValuePiece | [ValuePiece, ValuePiece];

FILE: examples/nextjs-todolist/app/layout.tsx
  function RootLayout (line 20) | function RootLayout({

FILE: examples/nextjs-todolist/app/page.tsx
  function Home (line 6) | function Home() {

FILE: examples/nextjs-todolist/components/TodoList.tsx
  type Todo (line 10) | type Todo = {

FILE: examples/nextjs-todolist/components/ui/button.tsx
  function Button (line 38) | function Button({

FILE: examples/nextjs-todolist/components/ui/card.tsx
  function Card (line 5) | function Card({ className, ...props }: React.ComponentProps<'div'>) {
  function CardHeader (line 18) | function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
  function CardTitle (line 31) | function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
  function CardDescription (line 41) | function CardDescription({ className, ...props }: React.ComponentProps<'...
  function CardAction (line 51) | function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
  function CardContent (line 64) | function CardContent({ className, ...props }: React.ComponentProps<'div'...
  function CardFooter (line 74) | function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {

FILE: examples/nextjs-todolist/components/ui/input.tsx
  function Input (line 5) | function Input({ className, type, ...props }: React.ComponentProps<'inpu...

FILE: examples/profile-stack/main.js
  constant MAX_PEER_VIEW (line 18) | const MAX_PEER_VIEW = 3;
  constant SPEECH_BUBBLE_INDEX (line 19) | const SPEECH_BUBBLE_INDEX = {
  function main (line 29) | async function main() {

FILE: examples/profile-stack/util.js
  constant NAMES (line 1) | const NAMES = [
  constant COLORS (line 20) | const COLORS = ['red', 'yellow', 'orange', 'green', 'blue', 'purple'];

FILE: examples/react-document-limit/src/App.tsx
  function App (line 4) | function App() {

FILE: examples/react-document-limit/src/components/ConnectionStatus.tsx
  function ConnectionStatus (line 7) | function ConnectionStatus() {

FILE: examples/react-document-limit/src/components/Counter.tsx
  function Counter (line 12) | function Counter() {

FILE: examples/react-document-limit/src/components/CounterNumber.tsx
  function CounterNumber (line 6) | function CounterNumber() {

FILE: examples/react-document-limit/src/components/IncrementButton.tsx
  function IncrementButton (line 7) | function IncrementButton() {

FILE: examples/react-document-limit/src/components/Peers.tsx
  function Peers (line 7) | function Peers() {

FILE: examples/react-flow/src/App.tsx
  type Graph (line 15) | type Graph = {
  function App (line 20) | function App() {

FILE: examples/react-polling-playground/src/App.tsx
  type View (line 11) | type View = 'leaderboard' | 'stock' | 'write';
  constant SUB_VIEWS (line 13) | const SUB_VIEWS: ReadonlyArray<SubView> = ['overview', 'activity'];
  function readSelectedStock (line 20) | function readSelectedStock(): string | null {
  function readView (line 27) | function readView(): View {
  function readSubView (line 33) | function readSubView(): SubView {
  constant MIN_HEARTBEAT_MS (line 40) | const MIN_HEARTBEAT_MS = 500;
  constant DEFAULT_HEARTBEAT_MS (line 41) | const DEFAULT_HEARTBEAT_MS = 2000;
  function App (line 43) | function App() {

FILE: examples/react-polling-playground/src/Leaderboard.tsx
  type Props (line 4) | type Props = {
  function Leaderboard (line 8) | function Leaderboard({ onSelect }: Props) {

FILE: examples/react-polling-playground/src/StockDetail.tsx
  type SubView (line 10) | type SubView = 'overview' | 'activity';
  type ProviderPosition (line 11) | type ProviderPosition = 'inside' | 'outside';
  type AttachState (line 13) | type AttachState = 'attaching' | 'ok' | 'error';
  type LogEntry (line 15) | type LogEntry = {
  type Props (line 23) | type Props = {
  constant TABS (line 36) | const TABS: ReadonlyArray<SubView> = ['overview', 'activity'];
  function StockDetail (line 38) | function StockDetail({
  constant PEEK_SHOW_MS (line 127) | const PEEK_SHOW_MS = 3000;
  function WritersPeekCTA (line 129) | function WritersPeekCTA({
  type CardProps (line 184) | type CardProps = {
  function OverviewBody (line 194) | function OverviewBody({ stock, onSession }: CardProps) {
  function ActivityBody (line 200) | function ActivityBody({ stock, onSession }: CardProps) {
  function SessionCountCard (line 206) | function SessionCountCard({
  function SessionLogPanel (line 275) | function SessionLogPanel({

FILE: examples/react-polling-playground/src/StockRow.tsx
  type Props (line 3) | type Props = {
  function StockRow (line 9) | function StockRow({ stock, rank, onSelect }: Props) {

FILE: examples/react-polling-playground/src/WritePostPage.tsx
  type Props (line 4) | type Props = {
  function WritePostPage (line 12) | function WritePostPage({
  function WriterBody (line 36) | function WriterBody({ stock }: { stock: Stock }) {

FILE: examples/react-polling-playground/src/stocks.ts
  type Stock (line 1) | type Stock = {
  constant STOCKS (line 7) | const STOCKS: ReadonlyArray<Stock> = [

FILE: examples/react-polling-playground/src/vite-env.d.ts
  type ImportMetaEnv (line 3) | interface ImportMetaEnv {
  type ImportMeta (line 8) | interface ImportMeta {

FILE: examples/react-revision/src/App.tsx
  constant DOC_KEY (line 5) | const DOC_KEY = `react-revision-${new Date().toISOString().slice(0, 10)}`;
  type DocType (line 7) | interface DocType {
  function NoteEditor (line 11) | function NoteEditor() {
  function App (line 42) | function App() {

FILE: examples/react-revision/src/RevisionPanel.tsx
  function RevisionPanel (line 4) | function RevisionPanel() {

FILE: examples/react-tldraw/src/App.tsx
  function App (line 17) | function App() {

FILE: examples/react-tldraw/src/hooks/types.ts
  type YorkieDocType (line 5) | type YorkieDocType = {
  type YorkiePresenceType (line 11) | type YorkiePresenceType = {

FILE: examples/react-tldraw/src/hooks/useMultiplayerState.ts
  function useMultiplayerState (line 22) | function useMultiplayerState(roomId: string) {

FILE: examples/react-tldraw/src/tldraw.d.ts
  type TDUser (line 5) | interface TDUser extends Indexable {}

FILE: examples/react-todomvc/src/App.tsx
  function App (line 21) | function App() {

FILE: examples/react-todomvc/src/components/Footer.tsx
  type MouseEventHandler (line 11) | type MouseEventHandler = (
  type FooterProps (line 15) | interface FooterProps {
  function Footer (line 23) | function Footer({

FILE: examples/react-todomvc/src/components/Header.tsx
  type HeaderProps (line 5) | interface HeaderProps {
  function Header (line 9) | function Header({ dispatch }: HeaderProps) {

FILE: examples/react-todomvc/src/components/MainSection.tsx
  type Filter (line 8) | type Filter = 'SHOW_ALL' | 'SHOW_ACTIVE' | 'SHOW_COMPLETED';
  type MainSectionProps (line 15) | interface MainSectionProps {
  function MainSection (line 20) | function MainSection({ todos, dispatch }: MainSectionProps) {

FILE: examples/react-todomvc/src/components/TodoItem.tsx
  type TodoItemProps (line 7) | interface TodoItemProps {
  function TodoItem (line 12) | function TodoItem({ todo, dispatch }: TodoItemProps) {

FILE: examples/react-todomvc/src/components/TodoTextInput.tsx
  type TodoInputProps (line 3) | interface TodoInputProps {
  function TodoTextInput (line 12) | function TodoTextInput({ onSave, placeholder }: TodoInputProps) {

FILE: examples/react-todomvc/src/model.ts
  type Todo (line 1) | interface Todo {

FILE: examples/react-todomvc/src/todoReducer.ts
  type TodoAction (line 5) | type TodoAction =
  type TodoRoot (line 13) | type TodoRoot = {
  function todoReducer (line 17) | function todoReducer(root: TodoRoot, action: TodoAction): void {

FILE: examples/react-todomvc/src/useTodoReducer.tsx
  function useTodoReducer (line 6) | function useTodoReducer(initialRoot: { todos: JSONArray<Todo> }) {

FILE: examples/simultaneous-cursors/src/App.jsx
  function generateRandomColor (line 13) | function generateRandomColor() {
  function CursorsCanvas (line 51) | function CursorsCanvas() {
  function App (line 200) | function App() {

FILE: examples/simultaneous-cursors/src/components/ColoredIcon.jsx
  function ColoredIcon (line 1) | function ColoredIcon({ type, color }) {

FILE: examples/simultaneous-cursors/src/components/Cursor.jsx
  function Cursor (line 5) | function Cursor({

FILE: examples/simultaneous-cursors/src/components/CursorSelections.jsx
  function CursorSelections (line 4) | function CursorSelections({

FILE: examples/simultaneous-cursors/src/components/FullAnimation.jsx
  function FullAnimation (line 5) | function FullAnimation({

FILE: examples/simultaneous-cursors/src/components/PenCursor.jsx
  class Point (line 3) | class Point {
    method constructor (line 4) | constructor(x, y) {
  function rdp (line 15) | function rdp(points, eps) {
  function getSplinePoint (line 45) | function getSplinePoint(pts, t) {
  function distToSegment (line 68) | function distToSegment(px, py, ax, ay, bx, by) {
  function PenCursor (line 84) | function PenCursor({

FILE: examples/simultaneous-cursors/src/components/SingleAnimation.jsx
  function SingleAnimation (line 3) | function SingleAnimation({

FILE: examples/simultaneous-cursors/src/hooks/useInterval.jsx
  function useInterval (line 3) | function useInterval(callback, delay) {

FILE: examples/vanilla-codemirror6/src/main.ts
  function main (line 15) | async function main() {

FILE: examples/vanilla-codemirror6/src/type.ts
  type YorkieDoc (line 3) | type YorkieDoc = {
  type YorkiePresence (line 7) | type YorkiePresence = {

FILE: examples/vanilla-codemirror6/src/utils.ts
  function displayPeers (line 5) | function displayPeers(
  function displayLog (line 22) | function displayLog(

FILE: examples/vanilla-document-limit/src/counter.ts
  function displayCounter (line 4) | function displayCounter(elem: HTMLElement, counter: number) {

FILE: examples/vanilla-document-limit/src/main.ts
  function main (line 21) | async function main() {

FILE: examples/vanilla-document-limit/src/peer.ts
  function displayPeers (line 4) | function displayPeers(

FILE: examples/vanilla-prosemirror/src/main.ts
  function setStatus (line 31) | function setStatus(text: string, type: 'connecting' | 'connected' | 'err...
  function main (line 46) | async function main() {

FILE: examples/vanilla-quill/src/main.ts
  type TextValueType (line 11) | type TextValueType = {
  function filterNullAttrs (line 30) | function filterNullAttrs(attributes?: Indexable): Indexable | undefined {
  function toDeltaOperation (line 46) | function toDeltaOperation<T extends TextValueType>(
  function main (line 66) | async function main() {

FILE: examples/vanilla-quill/src/type.ts
  type YorkieDoc (line 3) | type YorkieDoc = {
  type YorkiePresence (line 7) | type YorkiePresence = {

FILE: examples/vanilla-quill/src/utils.ts
  function displayPeers (line 5) | function displayPeers(
  function displayLog (line 22) | function displayLog(

FILE: packages/devtools/src/devtools/components/Code.tsx
  function Code (line 75) | function Code({

FILE: packages/devtools/src/devtools/components/Detail.tsx
  type FlatTreeNodeInfo (line 25) | type FlatTreeNodeInfo = Devtools.TreeNodeInfo & {
  function TreeNode (line 49) | function TreeNode({ node }: { node: FlatTreeNodeInfo }) {
  function TreeGraph (line 110) | function TreeGraph({ tree }: { tree: Devtools.TreeNodeInfo }) {
  function TreeDetail (line 141) | function TreeDetail({
  function JSONDetail (line 189) | function JSONDetail({ json }: { json: string }) {

FILE: packages/devtools/src/devtools/components/JsonView.tsx
  function JSONView (line 25) | function JSONView({ src }) {

FILE: packages/devtools/src/devtools/components/ResizableSeparator.tsx
  function Separator (line 28) | function Separator({ id = 'drag-bar', dir, isDragging, ...props }: any) {

FILE: packages/devtools/src/devtools/components/Tree.tsx
  type RootTreeNode (line 37) | type RootTreeNode = Devtools.JSONElement & {
  type UserNode (line 43) | type UserNode = Devtools.Client & {
  type PresenceJsonNode (line 47) | type PresenceJsonNode = {
  type PresenceTreeNode (line 54) | type PresenceTreeNode = UserNode | PresenceJsonNode;
  function RootNodeRenderer (line 84) | function RootNodeRenderer(props: NodeRendererProps<RootTreeNode>) {
  function PresenceNodeRenderer (line 148) | function PresenceNodeRenderer(props: NodeRendererProps<PresenceTreeNode>) {
  function rootChildAccessor (line 202) | function rootChildAccessor(node: RootTreeNode): Array<RootTreeNode> {
  function presenceChildAccessor (line 232) | function presenceChildAccessor(
  function PresenceTree (line 251) | function PresenceTree({
  function RootTree (line 287) | function RootTree({ root }: { root: Devtools.JSONElement }) {

FILE: packages/devtools/src/devtools/contexts/SelectedNode.tsx
  type SelectedNodeContext (line 22) | type SelectedNodeContext = [
  type Props (line 29) | type Props = {
  function SelectedNodeProvider (line 39) | function SelectedNodeProvider({ children }: Props) {
  function useSelectedNode (line 55) | function useSelectedNode() {

FILE: packages/devtools/src/devtools/contexts/SelectedPresence.tsx
  type SelectedPresenceContext (line 22) | type SelectedPresenceContext = [
  type Props (line 31) | type Props = {
  function SelectedPresenceProvider (line 41) | function SelectedPresenceProvider({ children }: Props) {
  function useSelectedPresence (line 57) | function useSelectedPresence() {

FILE: packages/devtools/src/devtools/contexts/YorkieSource.tsx
  type Props (line 39) | type Props = {
  function YorkieSourceProvider (line 49) | function YorkieSourceProvider({ children }: Props) {
  function useCurrentDocKey (line 133) | function useCurrentDocKey() {
  function useYorkieDoc (line 150) | function useYorkieDoc() {
  type DocEventScope (line 164) | enum DocEventScope {
  function useDocEventsForReplay (line 194) | function useDocEventsForReplay() {

FILE: packages/devtools/src/devtools/icons/index.tsx
  function ObjectIcon (line 25) | function ObjectIcon(props: ComponentProps<'svg'>) {
  function ArrayIcon (line 50) | function ArrayIcon(props: ComponentProps<'svg'>) {
  function PrimitiveIcon (line 75) | function PrimitiveIcon(props: ComponentProps<'svg'>) {
  function TextIcon (line 100) | function TextIcon(props: ComponentProps<'svg'>) {
  function TreeIcon (line 125) | function TreeIcon(props: ComponentProps<'svg'>) {
  function CounterIcon (line 150) | function CounterIcon(props: ComponentProps<'svg'>) {
  function UserIcon (line 175) | function UserIcon(props: ComponentProps<'svg'>) {
  function CloseIcon (line 200) | function CloseIcon(props: ComponentProps<'svg'>) {
  function CodeIcon (line 225) | function CodeIcon(props: ComponentProps<'svg'>) {
  function GraphIcon (line 250) | function GraphIcon(props: ComponentProps<'svg'>) {
  function CursorIcon (line 275) | function CursorIcon(props: ComponentProps<'svg'>) {
  function DocumentIcon (line 300) | function DocumentIcon(props: ComponentProps<'svg'>) {

FILE: packages/devtools/src/devtools/index.tsx
  function Page (line 29) | function Page() {

FILE: packages/devtools/src/devtools/panel/index.tsx
  function PanelApp (line 176) | function PanelApp() {

FILE: packages/devtools/src/devtools/tabs/Document.tsx
  function Document (line 33) | function Document({ style, hidePresenceTab, setHidePresenceTab }) {

FILE: packages/devtools/src/devtools/tabs/History.tsx
  constant SLIDER_MARK_WIDTH (line 25) | const SLIDER_MARK_WIDTH = 24;
  function History (line 76) | function History({

FILE: packages/devtools/src/devtools/tabs/Presence.tsx
  function Presence (line 30) | function Presence() {

FILE: packages/devtools/src/popup/index.tsx
  function Popup (line 22) | function Popup() {

FILE: packages/prosemirror/examples/basic.ts
  function setStatus (line 34) | function setStatus(text: string, type: 'connecting' | 'connected' | 'err...
  function appendLog (line 43) | function appendLog(type: string, message: string) {
  function updateDebugPanels (line 50) | function updateDebugPanels(view: EditorView) {
  function debugPanelPlugin (line 71) | function debugPanelPlugin() {
  function main (line 126) | async function main() {

FILE: packages/prosemirror/examples/custom-schema.ts
  function setStatus (line 29) | function setStatus(text: string, type: 'connecting' | 'connected' | 'err...
  method toDOM (line 42) | toDOM() {
  method toDOM (line 51) | toDOM() {
  method toDOM (line 59) | toDOM() {
  method toDOM (line 66) | toDOM() {
  method toDOM (line 74) | toDOM() {
  method toDOM (line 83) | toDOM() {
  function appendLog (line 97) | function appendLog(type: string, message: string) {
  function updateDebugPanels (line 104) | function updateDebugPanels(view: EditorView) {
  function debugPanelPlugin (line 125) | function debugPanelPlugin() {
  function insertStar (line 139) | function insertStar(
  function main (line 165) | async function main() {

FILE: packages/prosemirror/examples/tree-schema.ts
  method toDOM (line 30) | toDOM() {
  method toDOM (line 43) | toDOM(node) {
  method toDOM (line 52) | toDOM() {
  method toDOM (line 58) | toDOM() {
  method toDOM (line 64) | toDOM() {
  function setStatus (line 90) | function setStatus(text: string, type: 'connecting' | 'connected' | 'err...
  function appendLog (line 98) | function appendLog(type: string, message: string) {
  function updateDebugPanels (line 105) | function updateDebugPanels(view: EditorView) {
  function debugPanelPlugin (line 122) | function debugPanelPlugin() {
  function showSetupGuide (line 169) | function showSetupGuide(errorMsg: string) {
  function isSchemaNotFoundError (line 186) | function isSchemaNotFoundError(msg: string): boolean {
  function main (line 193) | async function main() {

FILE: packages/prosemirror/scripts/setup-tree-schema.ts
  function adminPost (line 66) | async function adminPost(path: string, body: object, authHeader?: string) {
  function main (line 92) | async function main() {

FILE: packages/prosemirror/src/binding.ts
  class YorkieProseMirrorBinding (line 38) | class YorkieProseMirrorBinding {
    method constructor (line 63) | constructor(
    method initialize (line 88) | initialize(): void {
    method destroy (line 134) | destroy(): void {
    method getTree (line 154) | private getTree(): any {
    method setupCompositionListeners (line 158) | private setupCompositionListeners(): void {
    method getComposingBlockRange (line 179) | private getComposingBlockRange(): { from: number; to: number } | undef...
    method setRemoteSyncMode (line 198) | private setRemoteSyncMode(nextMode: SyncMode): void {
    method pauseRemoteSync (line 218) | private pauseRemoteSync(): void {
    method resumeRemoteSync (line 222) | private resumeRemoteSync(): void {
    method diffOverlapsComposingBlock (line 229) | private diffOverlapsComposingBlock(diff: DocDiff): boolean {
    method selectionsOverlapComposingBlock (line 240) | private selectionsOverlapComposingBlock(): boolean {
    method flushPendingRemoteChanges (line 252) | private flushPendingRemoteChanges(): void {
    method setupDispatchTransaction (line 295) | private setupDispatchTransaction(): void {
    method setupDocSubscription (line 382) | private setupDocSubscription(): void {
    method applyRemoteTreeOps (line 435) | private applyRemoteTreeOps(): void {
    method setupPresenceSubscription (line 454) | private setupPresenceSubscription(): void {
    method dispatchSelectionDecorations (line 502) | private dispatchSelectionDecorations(): void {
    method applySelectionDecorations (line 512) | private applySelectionDecorations(): void {
    method syncPresence (line 520) | private syncPresence(): void {

FILE: packages/prosemirror/src/convert.ts
  function deserializeAttrs (line 10) | function deserializeAttrs(
  function serializeAttrs (line 31) | function serializeAttrs(
  function marksEqual (line 49) | function marksEqual(
  function mergeAdjacentTextNodes (line 82) | function mergeAdjacentTextNodes(nodes: Array<PMNodeJSON>): Array<PMNodeJ...
  function pmToYorkie (line 111) | function pmToYorkie(
  function yorkieToJSON (line 198) | function yorkieToJSON(

FILE: packages/prosemirror/src/cursor.ts
  type CursorEntry (line 5) | type CursorEntry = {
  class CursorManager (line 16) | class CursorManager {
    method constructor (line 24) | constructor(options: CursorOptions) {
    method displayCursor (line 34) | displayCursor(
    method remapPositions (line 89) | remapPositions(mapping: { map(pos: number): number }): void {
    method repositionAll (line 99) | repositionAll(view: EditorView): void {
    method removeCursor (line 112) | removeCursor(clientID: string): void {
    method destroy (line 123) | destroy(): void {
    method positionCursorLayer (line 130) | private positionCursorLayer(view: EditorView, entry: CursorEntry): void {

FILE: packages/prosemirror/src/defaults.ts
  function buildMarkMapping (line 19) | function buildMarkMapping(
  function invertMapping (line 37) | function invertMapping(mapping: MarkMapping): Record<string, string> {

FILE: packages/prosemirror/src/diff.ts
  function yorkieNodesEqual (line 20) | function yorkieNodesEqual(
  function sameStructure (line 51) | function sameStructure(a: YorkieTreeJSON, b: YorkieTreeJSON): boolean {
  function diffText (line 83) | function diffText(
  function findTextDiffs (line 133) | function findTextDiffs(
  function tryIntraBlockDiff (line 170) | function tryIntraBlockDiff(
  function detectSplit (line 219) | function detectSplit(
  function detectMerge (line 243) | function detectMerge(
  function syncToYorkie (line 264) | function syncToYorkie(

FILE: packages/prosemirror/src/position.ts
  function yorkieNodeSize (line 9) | function yorkieNodeSize(node: YorkieTreeJSON): number {
  function blockIndexToYorkieIndex (line 23) | function blockIndexToYorkieIndex(
  function collectText (line 37) | function collectText(node: YorkieTreeJSON): string {
  function findTextSplitOffset (line 47) | function findTextSplitOffset(
  function computeSplitLevel (line 81) | function computeSplitLevel(
  function computeMergeBoundary (line 125) | function computeMergeBoundary(
  function buildPositionMap (line 177) | function buildPositionMap(
  function pmPosToYorkieIdx (line 230) | function pmPosToYorkieIdx(map: PositionMap, pmPos: number): number {
  function yorkieIdxToPmPos (line 251) | function yorkieIdxToPmPos(map: PositionMap, yorkieIdx: number): number {

FILE: packages/prosemirror/src/selection-plugin.ts
  type RemoteSelection (line 7) | type RemoteSelection = {
  function remoteSelectionPlugin (line 22) | function remoteSelectionPlugin(): Plugin<DecorationSet> {

FILE: packages/prosemirror/src/sync.ts
  type DocDiff (line 11) | type DocDiff = {
  function diffDocs (line 27) | function diffDocs(oldDoc: Node, newDoc: Node): DocDiff | undefined {
  function syncToPM (line 87) | function syncToPM(
  function buildDocFromYorkieTree (line 140) | function buildDocFromYorkieTree(
  function tryIntraBlockPMDiff (line 167) | function tryIntraBlockPMDiff(
  function findPositionAtCharOffset (line 223) | function findPositionAtCharOffset(
  function applyDocDiff (line 264) | function applyDocDiff(view: EditorView, diff: DocDiff): void {
  function syncToPMIncremental (line 315) | function syncToPMIncremental(

FILE: packages/prosemirror/src/types.ts
  type MarkMapping (line 7) | type MarkMapping = Record<string, string>;
  type YorkieTreeJSON (line 12) | type YorkieTreeJSON = {
  type PMNodeJSON (line 22) | type PMNodeJSON = {
  type PositionMap (line 34) | type PositionMap = {
  type TextEdit (line 42) | type TextEdit = {
  type CursorOptions (line 51) | type CursorOptions = {
  type YorkieProseMirrorOptions (line 65) | type YorkieProseMirrorOptions = {

FILE: packages/prosemirror/test/integration/split_merge_test.ts
  function treeBridge (line 16) | function treeBridge(tree: Tree) {

FILE: packages/prosemirror/test/unit/convert_test.ts
  function coerceAttrs (line 399) | function coerceAttrs(json: unknown): unknown {
  function roundTrip (line 427) | function roundTrip(pmNode: ReturnType<typeof doc>) {

FILE: packages/prosemirror/test/unit/custom_schema_test.ts
  method toDOM (line 25) | toDOM() {
  method toDOM (line 34) | toDOM() {
  method toDOM (line 42) | toDOM() {
  method toDOM (line 49) | toDOM() {
  method toDOM (line 57) | toDOM() {
  method toDOM (line 66) | toDOM() {
  function cDoc (line 74) | function cDoc(...content: Array<Node>) {
  function cParagraph (line 78) | function cParagraph(...content: Array<Node | string>) {
  function cBoringParagraph (line 86) | function cBoringParagraph(...content: Array<Node | string>) {
  function cNotegroup (line 94) | function cNotegroup(...notes: Array<Node>) {
  function cNote (line 98) | function cNote(...content: Array<Node | string>) {
  function cStar (line 106) | function cStar() {
  function cShouting (line 110) | function cShouting(text: string) {
  function coerceAttrs (line 122) | function coerceAttrs(json: unknown): unknown {
  function roundTrip (line 148) | function roundTrip(pmNode: Node) {

FILE: packages/prosemirror/test/unit/diff_test.ts
  method edit (line 333) | edit(from: number, to: number, content?: YorkieTreeJSON) {
  method edit (line 393) | edit(from: number, to: number, content?: YorkieTreeJSON) {
  method edit (line 416) | edit(from: number, to: number, content?: YorkieTreeJSON) {

FILE: packages/prosemirror/test/unit/helpers.ts
  function doc (line 9) | function doc(...content: Array<PMNode>) {
  function p (line 14) | function p(...content: Array<PMNode | string>) {
  function strong (line 23) | function strong(text: string) {
  function em (line 28) | function em(text: string) {
  function strongEm (line 33) | function strongEm(text: string) {
  function code (line 41) | function code(text: string) {
  function link (line 46) | function link(text: string, href: string) {
  function heading (line 51) | function heading(level: number, ...content: Array<PMNode | string>) {
  function blockquote (line 60) | function blockquote(...content: Array<PMNode>) {
  function hardBreak (line 65) | function hardBreak() {
  function hr (line 70) | function hr() {
  function yText (line 75) | function yText(value: string): YorkieTreeJSON {
  function yElem (line 80) | function yElem(
  function createMockTree (line 91) | function createMockTree(yorkieJSON: YorkieTreeJSON) {

FILE: packages/prosemirror/test/unit/sync_test.ts
  function createMockView (line 199) | function createMockView(d: ReturnType<typeof doc>) {
  method state (line 461) | get state() {
  method dispatch (line 464) | dispatch(tr: any) {

FILE: packages/react/src/ChannelProvider.tsx
  function useYorkieChannel (line 44) | function useYorkieChannel(
  type ChannelProviderProps (line 230) | type ChannelProviderProps = PropsWithChildren<{

FILE: packages/react/src/DocumentProvider.tsx
  function useYorkieDocument (line 52) | function useYorkieDocument<R, P extends Indexable = Indexable>(
  type DocumentContextType (line 199) | type DocumentContextType<R, P extends Indexable = Indexable> = {
  function useDocument (line 292) | function useDocument<

FILE: packages/react/src/YorkieProvider.tsx
  type YorkieContextType (line 28) | type YorkieContextType = {
  function useYorkieClient (line 50) | function useYorkieClient(opts: ClientOptions, activate: boolean = true) {
  type YorkieProviderProps (line 112) | type YorkieProviderProps = ClientOptions & {

FILE: packages/react/src/createChannelStore.ts
  type ChannelContextType (line 23) | type ChannelContextType = {
  function createChannelStore (line 60) | function createChannelStore(

FILE: packages/react/src/createStore.ts
  type Subscriber (line 17) | type Subscriber<T> = (state: T) => void;
  type Updater (line 19) | type Updater<T> = T | ((prevState: T) => T);
  type Store (line 21) | type Store<T> = {
  function createStore (line 31) | function createStore<T>(initialState: T): Store<T> {

FILE: packages/react/src/shallowEqual.ts
  function isIterable (line 22) | function isIterable(obj: any): obj is Iterable<unknown> {
  function hasIterableEntries (line 29) | function hasIterableEntries(
  function compareEntries (line 38) | function compareEntries(
  function compareIterables (line 61) | function compareIterables(
  function comparePlainObjects (line 85) | function comparePlainObjects(
  function shallowEqual (line 111) | function shallowEqual<T>(valueA: T, valueB: T): boolean {

FILE: packages/react/src/usePeekChannel.ts
  type UsePeekChannelOptions (line 23) | interface UsePeekChannelOptions {
  type UsePeekChannelResult (line 42) | interface UsePeekChannelResult {
  function usePeekChannel (line 108) | function usePeekChannel(

FILE: packages/react/src/useSelector.ts
  function useSelector (line 25) | function useSelector<T, R = T>(

FILE: packages/react/src/useYorkieDoc.ts
  function useYorkieDoc (line 35) | function useYorkieDoc<R, P extends Indexable = Indexable>(

FILE: packages/react/test/integration/integration.test.tsx
  type TestDocumentRoot (line 26) | interface TestDocumentRoot {
  type TestPresence (line 35) | interface TestPresence extends Indexable {
  method constructor (line 147) | constructor() {
  function TestComponent (line 183) | function TestComponent() {
  function TestComponent (line 225) | function TestComponent() {
  function CounterComponent (line 278) | function CounterComponent() {
  function UserComponent (line 284) | function UserComponent() {
  function MultiStateComponent (line 338) | function MultiStateComponent() {
  function TestComponent (line 407) | function TestComponent() {

FILE: packages/react/test/unit/createDocumentSelector.test.tsx
  method constructor (line 38) | constructor() {
  type TestDocumentRoot (line 72) | interface TestDocumentRoot {
  type TestPresence (line 81) | interface TestPresence extends Indexable {

FILE: packages/react/test/unit/useRevisions.test.tsx
  type TestDocumentRoot (line 27) | interface TestDocumentRoot {
  type TestPresence (line 31) | interface TestPresence extends Indexable {
  method constructor (line 129) | constructor() {
  function renderUseRevisions (line 145) | async function renderUseRevisions() {
  function TestComponent (line 298) | function TestComponent() {

FILE: packages/react/test/unit/useSelector.test.ts
  type TestState (line 23) | interface TestState {

FILE: packages/react/test/unit/useYorkieDoc.test.ts
  type TestDocumentRoot (line 24) | interface TestDocumentRoot {
  type TestPresence (line 32) | interface TestPresence extends Indexable {

FILE: packages/schema/antlr/YorkieSchemaLexer.ts
  class YorkieSchemaLexer (line 18) | class YorkieSchemaLexer extends Lexer {
    method vocabulary (line 99) | public get vocabulary(): Vocabulary {
    method constructor (line 105) | constructor(input: CharStream) {
    method grammarFileName (line 111) | public get grammarFileName(): string { return "YorkieSchema.g4"; }
    method ruleNames (line 114) | public get ruleNames(): string[] { return YorkieSchemaLexer.ruleNames; }
    method serializedATN (line 117) | public get serializedATN(): string { return YorkieSchemaLexer._seriali...
    method channelNames (line 120) | public get channelNames(): string[] { return YorkieSchemaLexer.channel...
    method modeNames (line 123) | public get modeNames(): string[] { return YorkieSchemaLexer.modeNames; }
    method _ATN (line 271) | public static get _ATN(): ATN {

FILE: packages/schema/antlr/YorkieSchemaListener.ts
  type YorkieSchemaListener (line 38) | interface YorkieSchemaListener extends ParseTreeListener {

FILE: packages/schema/antlr/YorkieSchemaParser.ts
  class YorkieSchemaParser (line 30) | class YorkieSchemaParser extends Parser {
    method vocabulary (line 127) | public get vocabulary(): Vocabulary {
    method grammarFileName (line 133) | public get grammarFileName(): string { return "YorkieSchema.g4"; }
    method ruleNames (line 136) | public get ruleNames(): string[] { return YorkieSchemaParser.ruleNames; }
    method serializedATN (line 139) | public get serializedATN(): string { return YorkieSchemaParser._serial...
    method createFailedPredicateException (line 141) | protected createFailedPredicateException(predicate?: string, message?:...
    method constructor (line 145) | constructor(input: TokenStream) {
    method document (line 150) | public document(): DocumentContext {
    method declaration (line 190) | public declaration(): DeclarationContext {
    method typeAliasDeclaration (line 230) | public typeAliasDeclaration(): TypeAliasDeclarationContext {
    method variableDeclaration (line 274) | public variableDeclaration(): VariableDeclarationContext {
    method typeAnnotation (line 326) | public typeAnnotation(): TypeAnnotationContext {
    method type (line 353) | public type(): TypeContext {
    method unionType (line 378) | public unionType(): UnionTypeContext {
    method intersectionType (line 420) | public intersectionType(): IntersectionTypeContext {
    method arrayType (line 462) | public arrayType(): ArrayTypeContext {
    method primaryType (line 540) | public primaryType(): PrimaryTypeContext {
    method primitiveType (line 622) | public primitiveType(): PrimitiveTypeContext {
    method objectType (line 658) | public objectType(): ObjectTypeContext {
    method propertySignature (line 700) | public propertySignature(): PropertySignatureContext {
    method propertyName (line 740) | public propertyName(): PropertyNameContext {
    method yorkieType (line 776) | public yorkieType(): YorkieTypeContext {
    method treeSchemaBody (line 876) | public treeSchemaBody(): TreeSchemaBodyContext {
    method treeNodeDef (line 920) | public treeNodeDef(): TreeNodeDefContext {
    method treeNodeProps (line 962) | public treeNodeProps(): TreeNodePropsContext {
    method treeNodeProp (line 1017) | public treeNodeProp(): TreeNodePropContext {
    method typeReference (line 1046) | public typeReference(): TypeReferenceContext {
    method parenthesizedType (line 1082) | public parenthesizedType(): ParenthesizedTypeContext {
    method typeParameters (line 1111) | public typeParameters(): TypeParametersContext {
    method typeParameter (line 1157) | public typeParameter(): TypeParameterContext {
    method typeArguments (line 1195) | public typeArguments(): TypeArgumentsContext {
    method expression (line 1241) | public expression(): ExpressionContext {
    method literal (line 1283) | public literal(): LiteralContext {
    method _ATN (line 1426) | public static get _ATN(): ATN {
  class DocumentContext (line 1436) | class DocumentContext extends ParserRuleContext {
    method EOF (line 1437) | public EOF(): TerminalNode { return this.getToken(YorkieSchemaParser.E...
    method declaration (line 1440) | public declaration(i?: number): DeclarationContext | DeclarationContex...
    method constructor (line 1447) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1451) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_docume...
    method enterRule (line 1453) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1459) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1465) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class DeclarationContext (line 1475) | class DeclarationContext extends ParserRuleContext {
    method typeAliasDeclaration (line 1476) | public typeAliasDeclaration(): TypeAliasDeclarationContext | undefined {
    method variableDeclaration (line 1479) | public variableDeclaration(): VariableDeclarationContext | undefined {
    method constructor (line 1482) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1486) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_declar...
    method enterRule (line 1488) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1494) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1500) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class TypeAliasDeclarationContext (line 1510) | class TypeAliasDeclarationContext extends ParserRuleContext {
    method Identifier (line 1511) | public Identifier(): TerminalNode { return this.getToken(YorkieSchemaP...
    method type (line 1512) | public type(): TypeContext {
    method typeParameters (line 1515) | public typeParameters(): TypeParametersContext | undefined {
    method constructor (line 1518) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1522) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_typeAl...
    method enterRule (line 1524) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1530) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1536) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class VariableDeclarationContext (line 1546) | class VariableDeclarationContext extends ParserRuleContext {
    method Identifier (line 1547) | public Identifier(): TerminalNode { return this.getToken(YorkieSchemaP...
    method typeAnnotation (line 1548) | public typeAnnotation(): TypeAnnotationContext | undefined {
    method expression (line 1551) | public expression(): ExpressionContext | undefined {
    method constructor (line 1554) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1558) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_variab...
    method enterRule (line 1560) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1566) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1572) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class TypeAnnotationContext (line 1582) | class TypeAnnotationContext extends ParserRuleContext {
    method type (line 1583) | public type(): TypeContext {
    method constructor (line 1586) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1590) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_typeAn...
    method enterRule (line 1592) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1598) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1604) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class TypeContext (line 1614) | class TypeContext extends ParserRuleContext {
    method unionType (line 1615) | public unionType(): UnionTypeContext {
    method constructor (line 1618) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1622) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_type; }
    method enterRule (line 1624) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1630) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1636) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class UnionTypeContext (line 1646) | class UnionTypeContext extends ParserRuleContext {
    method intersectionType (line 1649) | public intersectionType(i?: number): IntersectionTypeContext | Interse...
    method constructor (line 1656) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1660) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_unionT...
    method enterRule (line 1662) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1668) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1674) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class IntersectionTypeContext (line 1684) | class IntersectionTypeContext extends ParserRuleContext {
    method arrayType (line 1687) | public arrayType(i?: number): ArrayTypeContext | ArrayTypeContext[] {
    method constructor (line 1694) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1698) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_inters...
    method enterRule (line 1700) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1706) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1712) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class ArrayTypeContext (line 1722) | class ArrayTypeContext extends ParserRuleContext {
    method primaryType (line 1723) | public primaryType(): PrimaryTypeContext | undefined {
    method typeArguments (line 1726) | public typeArguments(): TypeArgumentsContext | undefined {
    method constructor (line 1729) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1733) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_arrayT...
    method enterRule (line 1735) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1741) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1747) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class PrimaryTypeContext (line 1757) | class PrimaryTypeContext extends ParserRuleContext {
    method parenthesizedType (line 1758) | public parenthesizedType(): ParenthesizedTypeContext | undefined {
    method primitiveType (line 1761) | public primitiveType(): PrimitiveTypeContext | undefined {
    method objectType (line 1764) | public objectType(): ObjectTypeContext | undefined {
    method yorkieType (line 1767) | public yorkieType(): YorkieTypeContext | undefined {
    method typeReference (line 1770) | public typeReference(): TypeReferenceContext | undefined {
    method literal (line 1773) | public literal(): LiteralContext | undefined {
    method constructor (line 1776) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1780) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_primar...
    method enterRule (line 1782) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1788) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1794) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class PrimitiveTypeContext (line 1804) | class PrimitiveTypeContext extends ParserRuleContext {
    method constructor (line 1805) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1809) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_primit...
    method enterRule (line 1811) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1817) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1823) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class ObjectTypeContext (line 1833) | class ObjectTypeContext extends ParserRuleContext {
    method propertySignature (line 1836) | public propertySignature(i?: number): PropertySignatureContext | Prope...
    method constructor (line 1843) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1847) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_object...
    method enterRule (line 1849) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1855) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1861) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class PropertySignatureContext (line 1871) | class PropertySignatureContext extends ParserRuleContext {
    method propertyName (line 1872) | public propertyName(): PropertyNameContext {
    method typeAnnotation (line 1875) | public typeAnnotation(): TypeAnnotationContext {
    method QUESTION (line 1878) | public QUESTION(): TerminalNode | undefined { return this.tryGetToken(...
    method constructor (line 1879) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1883) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_proper...
    method enterRule (line 1885) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1891) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1897) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class PropertyNameContext (line 1907) | class PropertyNameContext extends ParserRuleContext {
    method Identifier (line 1908) | public Identifier(): TerminalNode | undefined { return this.tryGetToke...
    method StringLiteral (line 1909) | public StringLiteral(): TerminalNode | undefined { return this.tryGetT...
    method constructor (line 1910) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1914) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_proper...
    method enterRule (line 1916) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1922) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1928) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class YorkieTypeContext (line 1938) | class YorkieTypeContext extends ParserRuleContext {
    method typeArguments (line 1939) | public typeArguments(): TypeArgumentsContext | undefined {
    method treeSchemaBody (line 1942) | public treeSchemaBody(): TreeSchemaBodyContext | undefined {
    method constructor (line 1945) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1949) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_yorkie...
    method enterRule (line 1951) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1957) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 1963) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class TreeSchemaBodyContext (line 1973) | class TreeSchemaBodyContext extends ParserRuleContext {
    method treeNodeDef (line 1976) | public treeNodeDef(i?: number): TreeNodeDefContext | TreeNodeDefContex...
    method constructor (line 1983) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 1987) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_treeSc...
    method enterRule (line 1989) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 1995) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 2001) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class TreeNodeDefContext (line 2011) | class TreeNodeDefContext extends ParserRuleContext {
    method Identifier (line 2012) | public Identifier(): TerminalNode { return this.getToken(YorkieSchemaP...
    method treeNodeProps (line 2013) | public treeNodeProps(): TreeNodePropsContext | undefined {
    method constructor (line 2016) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 2020) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_treeNo...
    method enterRule (line 2022) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 2028) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 2034) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class TreeNodePropsContext (line 2044) | class TreeNodePropsContext extends ParserRuleContext {
    method treeNodeProp (line 2047) | public treeNodeProp(i?: number): TreeNodePropContext | TreeNodePropCon...
    method constructor (line 2054) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 2058) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_treeNo...
    method enterRule (line 2060) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 2066) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 2072) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class TreeNodePropContext (line 2082) | class TreeNodePropContext extends ParserRuleContext {
    method Identifier (line 2083) | public Identifier(): TerminalNode { return this.getToken(YorkieSchemaP...
    method StringLiteral (line 2084) | public StringLiteral(): TerminalNode { return this.getToken(YorkieSche...
    method constructor (line 2085) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 2089) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_treeNo...
    method enterRule (line 2091) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 2097) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 2103) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class TypeReferenceContext (line 2113) | class TypeReferenceContext extends ParserRuleContext {
    method Identifier (line 2114) | public Identifier(): TerminalNode { return this.getToken(YorkieSchemaP...
    method typeArguments (line 2115) | public typeArguments(): TypeArgumentsContext | undefined {
    method constructor (line 2118) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 2122) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_typeRe...
    method enterRule (line 2124) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 2130) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 2136) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class ParenthesizedTypeContext (line 2146) | class ParenthesizedTypeContext extends ParserRuleContext {
    method type (line 2147) | public type(): TypeContext {
    method constructor (line 2150) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 2154) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_parent...
    method enterRule (line 2156) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 2162) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 2168) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class TypeParametersContext (line 2178) | class TypeParametersContext extends ParserRuleContext {
    method typeParameter (line 2181) | public typeParameter(i?: number): TypeParameterContext | TypeParameter...
    method constructor (line 2188) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 2192) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_typePa...
    method enterRule (line 2194) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 2200) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 2206) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class TypeParameterContext (line 2216) | class TypeParameterContext extends ParserRuleContext {
    method Identifier (line 2217) | public Identifier(): TerminalNode { return this.getToken(YorkieSchemaP...
    method type (line 2218) | public type(): TypeContext | undefined {
    method constructor (line 2221) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 2225) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_typePa...
    method enterRule (line 2227) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 2233) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 2239) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class TypeArgumentsContext (line 2249) | class TypeArgumentsContext extends ParserRuleContext {
    method type (line 2252) | public type(i?: number): TypeContext | TypeContext[] {
    method constructor (line 2259) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 2263) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_typeAr...
    method enterRule (line 2265) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 2271) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 2277) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class ExpressionContext (line 2287) | class ExpressionContext extends ParserRuleContext {
    method Identifier (line 2288) | public Identifier(): TerminalNode | undefined { return this.tryGetToke...
    method literal (line 2289) | public literal(): LiteralContext | undefined {
    method constructor (line 2292) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 2296) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_expres...
    method enterRule (line 2298) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 2304) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 2310) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {
  class LiteralContext (line 2320) | class LiteralContext extends ParserRuleContext {
    method StringLiteral (line 2321) | public StringLiteral(): TerminalNode | undefined { return this.tryGetT...
    method NumberLiteral (line 2322) | public NumberLiteral(): TerminalNode | undefined { return this.tryGetT...
    method BooleanLiteral (line 2323) | public BooleanLiteral(): TerminalNode | undefined { return this.tryGet...
    method constructor (line 2324) | constructor(parent: ParserRuleContext | undefined, invokingState: numb...
    method ruleIndex (line 2328) | public get ruleIndex(): number { return YorkieSchemaParser.RULE_litera...
    method enterRule (line 2330) | public enterRule(listener: YorkieSchemaListener): void {
    method exitRule (line 2336) | public exitRule(listener: YorkieSchemaListener): void {
    method accept (line 2342) | public accept<Result>(visitor: YorkieSchemaVisitor<Result>): Result {

FILE: packages/schema/antlr/YorkieSchemaVisitor.ts
  type YorkieSchemaVisitor (line 41) | interface YorkieSchemaVisitor<Result> extends ParseTreeVisitor<Result> {

FILE: packages/schema/src/rulesets.ts
  type Rule (line 37) | type Rule =
  type PrimitiveType (line 43) | type PrimitiveType =
  type YorkieType (line 52) | type YorkieType =
  type RuleType (line 58) | type RuleType =
  type RuleBase (line 67) | type RuleBase = {
  type PrimitiveRule (line 72) | type PrimitiveRule = {
  type ObjectRule (line 76) | type ObjectRule = {
  type ArrayRule (line 82) | type ArrayRule = {
  type TreeNodeRule (line 90) | type TreeNodeRule = {
  type YorkieTypeRule (line 97) | type YorkieTypeRule = {
  type EnumRule (line 102) | type EnumRule = {
  type TypeDefinition (line 108) | type TypeDefinition =
  type PropertyDefinition (line 135) | type PropertyDefinition = {
  class RulesetBuilder (line 144) | class RulesetBuilder implements YorkieSchemaListener {
    method enterTypeAliasDeclaration (line 160) | enterTypeAliasDeclaration(ctx: TypeAliasDeclarationContext) {
    method exitArrayType (line 169) | exitArrayType(ctx: ArrayTypeContext) {
    method exitTypeAliasDeclaration (line 189) | exitTypeAliasDeclaration() {
    method enterPrimitiveType (line 200) | enterPrimitiveType(ctx: PrimitiveTypeContext) {
    method enterYorkieType (line 208) | enterYorkieType(ctx: YorkieTypeContext) {
    method exitYorkieType (line 235) | exitYorkieType() {
    method enterTreeNodeDef (line 252) | enterTreeNodeDef(ctx: TreeNodeDefContext) {
    method exitTreeNodeDef (line 263) | exitTreeNodeDef() {
    method enterTreeNodeProp (line 271) | enterTreeNodeProp(ctx: TreeNodePropContext) {
    method enterTypeReference (line 285) | enterTypeReference(ctx: TypeReferenceContext) {
    method enterObjectType (line 293) | enterObjectType() {
    method exitObjectType (line 301) | exitObjectType() {
    method enterPropertySignature (line 310) | enterPropertySignature(ctx: PropertySignatureContext) {
    method exitPropertySignature (line 324) | exitPropertySignature() {
    method enterUnionType (line 335) | enterUnionType() {
    method exitUnionType (line 342) | exitUnionType() {
    method enterLiteral (line 352) | enterLiteral(ctx: LiteralContext) {
    method build (line 376) | build(): Array<Rule> {
    method expandType (line 390) | private expandType(
  function buildRuleset (line 590) | function buildRuleset(schema: string): Array<Rule> {

FILE: packages/schema/src/validator.ts
  type TypeSymbol (line 41) | type TypeSymbol = {
  type TypeReference (line 50) | type TypeReference = {
  type Diagnostic (line 60) | type Diagnostic = {
  class TypeCollectorListener (line 72) | class TypeCollectorListener implements YorkieSchemaListener {
    method enterTypeAliasDeclaration (line 84) | enterTypeAliasDeclaration(ctx: TypeAliasDeclarationContext) {
    method enterObjectType (line 108) | enterObjectType() {
    method exitObjectType (line 115) | exitObjectType() {
    method enterPropertyName (line 122) | enterPropertyName(ctx: PropertyNameContext) {
    method enterTreeSchemaBody (line 140) | enterTreeSchemaBody() {
    method exitTreeSchemaBody (line 147) | exitTreeSchemaBody() {
    method enterTreeNodeDef (line 154) | enterTreeNodeDef(ctx: TreeNodeDefContext) {
    method enterTypeReference (line 172) | enterTypeReference(ctx: TypeReferenceContext) {
  class LexerErrorListener (line 188) | class LexerErrorListener implements ANTLRErrorListener<number> {
    method constructor (line 189) | constructor(private errorList: Array<Diagnostic>) {}
    method syntaxError (line 194) | syntaxError<T extends number>(
  class ParserErrorListener (line 217) | class ParserErrorListener implements ANTLRErrorListener<CommonToken> {
    method constructor (line 218) | constructor(private errorList: Array<Diagnostic>) {}
    method syntaxError (line 223) | syntaxError<T extends Token>(
  function validate (line 254) | function validate(data: string): { errors: Array<Diagnostic> } {

FILE: packages/sdk/public/devtool/network.js
  class Network (line 4) | class Network {
    method constructor (line 5) | constructor(elem) {
    method showOffline (line 13) | showOffline() {
    method showOnline (line 21) | showOnline() {

FILE: packages/sdk/public/devtool/text.js
  function displayLog (line 44) | function displayLog(doc) {
  function displayBlockLog (line 57) | function displayBlockLog(doc) {
  function getEditBlock (line 132) | function getEditBlock(block) {
  function getDeleteBlock (line 154) | function getDeleteBlock(block) {
  function displayValue (line 176) | function displayValue(value) {
  function displayTreeLogWithTimer (line 193) | function displayTreeLogWithTimer(doc) {
  function displayTreeLog (line 210) | function displayTreeLog(doc) {
  function getNewSplayTree (line 244) | function getNewSplayTree(node, depth = 0, parent = null) {
  function getNewLLRBTree (line 270) | function getNewLLRBTree(node, depth = 0, parent = null) {
  function calculateTreeViewport (line 296) | function calculateTreeViewport(node) {
  function calculateAbsolutePosition (line 322) | function calculateAbsolutePosition(type, node, startX = 0, endX = 0) {
  function renderHeadLineView (line 388) | function renderHeadLineView(type, node) {
  function renderLineHTML (line 397) | function renderLineHTML(type, node) {
  function renderHeadHTML (line 414) | function renderHeadHTML(type, node) {
  function treeLogEventHandler (line 465) | function treeLogEventHandler(e) {
  function structureInfoEventHandler (line 491) | function structureInfoEventHandler(e) {
  function goPrevNode (line 509) | function goPrevNode(e) {
  function goNextNode (line 542) | function goNextNode(e) {
  function highlightAndMoveToSelectedItem (line 579) | function highlightAndMoveToSelectedItem(selectedKey) {
  function traverseTree (line 604) | function traverseTree(node, callback) {
  function displaySelectedItemInfo (line 624) | function displaySelectedItemInfo(node) {
  function highlightCMSelectedItem (line 657) | function highlightCMSelectedItem(selectedItem) {
  function highlightSelectedItem (line 675) | function highlightSelectedItem(selectedKey) {
  function moveToSelectedItem (line 725) | function moveToSelectedItem(panzoomInstance, rootRect, selectedItem) {
  function openTab (line 743) | function openTab(e, target) {
  function toggleDeletedNodeShow (line 765) | function toggleDeletedNodeShow() {
  function toggleText (line 769) | function toggleText() {
  function toggleSplayTree (line 773) | function toggleSplayTree() {
  function toggleLLRBTree (line 777) | function toggleLLRBTree() {
  function setHideDeletedNode (line 781) | function setHideDeletedNode(hide) {
  function setHideText (line 789) | function setHideText(hide) {
  function setHideSplayTree (line 796) | function setHideSplayTree(hide) {
  function setHideLLRBTree (line 803) | function setHideLLRBTree(hide) {
  function setUsersInfo (line 810) | function setUsersInfo(info) {
  function setCodeMirror (line 814) | function setCodeMirror(cm) {

FILE: packages/sdk/src/api/converter.ts
  function toPresence (line 153) | function toPresence(presence: Indexable): PbPresence {
  function toPresenceChange (line 164) | function toPresenceChange(
  function toCheckpoint (line 185) | function toCheckpoint(checkpoint: Checkpoint): PbCheckpoint {
  function toChangeID (line 195) | function toChangeID(changeID: ChangeID): PbChangeID {
  function toTimeTicket (line 207) | function toTimeTicket(ticket?: TimeTicket): PbTimeTicket | undefined {
  function toVersionVector (line 222) | function toVersionVector(vector?: VersionVector): PbVersionVector | unde...
  function toValueType (line 238) | function toValueType(valueType: PrimitiveType): PbValueType {
  function toCounterType (line 267) | function toCounterType(valueType: CounterType): PbValueType {
  function toElementSimple (line 286) | function toElementSimple(element: CRDTElement): PbJSONElementSimple {
  function toTextNodeID (line 335) | function toTextNodeID(id: RGATreeSplitNodeID): PbTextNodeID {
  function toTextNodePos (line 345) | function toTextNodePos(pos: RGATreeSplitPos): PbTextNodePos {
  function toTreePos (line 356) | function toTreePos(pos: CRDTTreePos): PbTreePos {
  function toTreeNodeID (line 366) | function toTreeNodeID(treeNodeID: CRDTTreeNodeID): PbTreeNodeID {
  function toOperation (line 376) | function toOperation(operation: Operation): PbOperation {
  function toOperations (line 544) | function toOperations(operations: Array<Operation>): Array<PbOperation> {
  function toChange (line 555) | function toChange(change: Change<Indexable>): PbChange {
  function toChanges (line 572) | function toChanges(changes: Array<Change<Indexable>>): Array<PbChange> {
  function toRHTNodes (line 583) | function toRHTNodes(rht: ElementRHT): Array<PbRHTNode> {
  function toRGANodes (line 601) | function toRGANodes(arr: CRDTArray): Array<PbRGANode> {
  function toTextNodes (line 631) | function toTextNodes(
  function toTreeNodesWhenEdit (line 660) | function toTreeNodesWhenEdit(nodes: Array<CRDTTreeNode>): Array<PbTreeNo...
  function toRHT (line 680) | function toRHT(rht: RHT): { [key: string]: PbNodeAttr } {
  function toTreeNodes (line 696) | function toTreeNodes(node: CRDTTreeNode): Array<PbTreeNode> {
  function toObject (line 740) | function toObject(obj: CRDTObject): PbJSONElement {
  function toArray (line 757) | function toArray(arr: CRDTArray): PbJSONElement {
  function toPrimitive (line 774) | function toPrimitive(primitive: Primitive): PbJSONElement {
  function toText (line 792) | function toText(text: CRDTText<Record<string, any>>): PbJSONElement {
  function toCounter (line 809) | function toCounter(counter: CRDTCounter): PbJSONElement {
  function toTree (line 828) | function toTree(tree: CRDTTree): PbJSONElement {
  function toElement (line 845) | function toElement(element: CRDTElement): PbJSONElement {
  function toChangePack (line 871) | function toChangePack(pack: ChangePack<Indexable>): PbChangePack {
  function toRevisionSummary (line 885) | function toRevisionSummary(
  function errorMetadataOf (line 902) | function errorMetadataOf(error: ConnectError): Record<string, string> {
  function errorCodeOf (line 920) | function errorCodeOf(error: ConnectError): string {
  function isErrorCode (line 927) | function isErrorCode(
  function fromChangeID (line 937) | function fromChangeID(pbChangeID: PbChangeID): ChangeID {
  function fromVersionVector (line 952) | function fromVersionVector(
  function fromTimeTicket (line 970) | function fromTimeTicket(pbTimeTicket?: PbTimeTicket): TimeTicket | undef...
  function fromPresence (line 985) | function fromPresence<P extends Indexable>(pbPresence: PbPresence): P {
  function fromPresenceChange (line 997) | function fromPresenceChange<P extends Indexable>(
  function fromPresences (line 1020) | function fromPresences<P extends Indexable>(pbPresences: {
  function fromValueType (line 1033) | function fromValueType(pbValueType: PbValueType): PrimitiveType {
  function fromCounterType (line 1061) | function fromCounterType(pbValueType: PbValueType): CounterType {
  function fromElementSimple (line 1079) | function fromElementSimple(pbElementSimple: PbJSONElementSimple): CRDTEl...
  function fromTextNodePos (line 1130) | function fromTextNodePos(pbTextNodePos: PbTextNodePos): RGATreeSplitPos {
  function fromTextNodeID (line 1143) | function fromTextNodeID(pbTextNodeID: PbTextNodeID): RGATreeSplitNodeID {
  function fromTextNode (line 1153) | function fromTextNode(pbTextNode: PbTextNode): RGATreeSplitNode<CRDTText...
  function fromTreePos (line 1170) | function fromTreePos(pbTreePos: PbTreePos): CRDTTreePos {
  function fromTreeNodeID (line 1180) | function fromTreeNodeID(pbTreeNodeID: PbTreeNodeID): CRDTTreeNodeID {
  function fromTreeNodesWhenEdit (line 1190) | function fromTreeNodesWhenEdit(
  function fromTreeNodes (line 1209) | function fromTreeNodes(
  function fromRHT (line 1240) | function fromRHT(pbRHT: { [key: string]: PbNodeAttr }): RHT {
  function fromTreeNode (line 1257) | function fromTreeNode(pbTreeNode: PbTreeNode): CRDTTreeNode {
  function fromOperation (line 1291) | function fromOperation(pbOperation: PbOperation): Operation | undefined {
  function fromOperations (line 1414) | function fromOperations(pbOperations: Array<PbOperation>): Array<Operati...
  function fromChanges (line 1428) | function fromChanges<P extends Indexable>(
  function fromCheckpoint (line 1452) | function fromCheckpoint(pbCheckpoint: PbCheckpoint): Checkpoint {
  function fromChangePack (line 1459) | function fromChangePack<P extends Indexable>(
  function fromObject (line 1475) | function fromObject(pbObject: PbJSONElement_JSONObject): CRDTObject {
  function fromArray (line 1491) | function fromArray(pbArray: PbJSONElement_JSONArray): CRDTArray {
  function fromPrimitive (line 1534) | function fromPrimitive(pbPrimitive: PbJSONElement_Primitive): Primitive {
  function fromText (line 1550) | function fromText<A extends Indexable>(
  function fromCounter (line 1574) | function fromCounter(pbCounter: PbJSONElement_Counter): CRDTCounter {
  function fromTree (line 1594) | function fromTree(pbTree: PbJSONElement_Tree): CRDTTree {
  function fromElement (line 1602) | function fromElement(pbElement: PbJSONElement): CRDTElement {
  function fromSchemaRules (line 1623) | function fromSchemaRules(pbRules: Array<PbRule>): Array<Rule> {
  function bytesToSnapshot (line 1644) | function bytesToSnapshot<P extends Indexable>(
  function versionVectorToHex (line 1667) | function versionVectorToHex(vector: VersionVector): string {
  function hexToVersionVector (line 1676) | function hexToVersionVector(hex: string): VersionVector {
  function bytesToObject (line 1686) | function bytesToObject(bytes?: Uint8Array): CRDTObject {
  function objectToBytes (line 1698) | function objectToBytes(obj: CRDTObject): Uint8Array {
  function bytesToArray (line 1705) | function bytesToArray(bytes?: Uint8Array): CRDTArray {
  function arrayToBytes (line 1717) | function arrayToBytes(array: CRDTArray): Uint8Array {
  function bytesToTree (line 1724) | function bytesToTree(bytes?: Uint8Array): CRDTTree {
  function treeToBytes (line 1736) | function treeToBytes(tree: CRDTTree): Uint8Array {
  function bytesToHex (line 1743) | function bytesToHex(bytes?: Uint8Array): string {
  function toHexString (line 1756) | function toHexString(bytes: Uint8Array): string {
  function hexToBytes (line 1763) | function hexToBytes(hex: string): Uint8Array {
  function base64ToUint8Array (line 1772) | function base64ToUint8Array(base64: string): Uint8Array {
  function toUint8Array (line 1795) | function toUint8Array(hex: string): Uint8Array {
  function uint8ArrayToBase64 (line 1802) | function uint8ArrayToBase64(bytes: Uint8Array): string {
  function bytesToChangeID (line 1822) | function bytesToChangeID(bytes: Uint8Array): ChangeID {
  function bytesToOperation (line 1830) | function bytesToOperation(bytes: Uint8Array): Operation {

FILE: packages/sdk/src/api/revision.ts
  type RevisionSummary (line 22) | interface RevisionSummary {

FILE: packages/sdk/src/api/yorkie/v1/resources_pb.ts
  type Snapshot (line 39) | type Snapshot = Message<"yorkie.v1.Snapshot"> & {
  type ChangePack (line 64) | type ChangePack = Message<"yorkie.v1.ChangePack"> & {
  type Change (line 113) | type Change = Message<"yorkie.v1.Change"> & {
  type ChangeID (line 145) | type ChangeID = Message<"yorkie.v1.ChangeID"> & {
  type VersionVector (line 182) | type VersionVector = Message<"yorkie.v1.VersionVector"> & {
  type Operation (line 199) | type Operation = Message<"yorkie.v1.Operation"> & {
  type Operation_Set (line 276) | type Operation_Set = Message<"yorkie.v1.Operation.Set"> & {
  type Operation_Add (line 308) | type Operation_Add = Message<"yorkie.v1.Operation.Add"> & {
  type Operation_Move (line 340) | type Operation_Move = Message<"yorkie.v1.Operation.Move"> & {
  type Operation_Remove (line 372) | type Operation_Remove = Message<"yorkie.v1.Operation.Remove"> & {
  type Operation_Edit (line 399) | type Operation_Edit = Message<"yorkie.v1.Operation.Edit"> & {
  type Operation_Style (line 448) | type Operation_Style = Message<"yorkie.v1.Operation.Style"> & {
  type Operation_Increase (line 497) | type Operation_Increase = Message<"yorkie.v1.Operation.Increase"> & {
  type Operation_TreeEdit (line 529) | type Operation_TreeEdit = Message<"yorkie.v1.Operation.TreeEdit"> & {
  type Operation_TreeStyle (line 578) | type Operation_TreeStyle = Message<"yorkie.v1.Operation.TreeStyle"> & {
  type Operation_ArraySet (line 627) | type Operation_ArraySet = Message<"yorkie.v1.Operation.ArraySet"> & {
  type JSONElementSimple (line 659) | type JSONElementSimple = Message<"yorkie.v1.JSONElementSimple"> & {
  type JSONElement (line 696) | type JSONElement = Message<"yorkie.v1.JSONElement"> & {
  type JSONElement_JSONObject (line 749) | type JSONElement_JSONObject = Message<"yorkie.v1.JSONElement.JSONObject"...
  type JSONElement_JSONArray (line 781) | type JSONElement_JSONArray = Message<"yorkie.v1.JSONElement.JSONArray"> & {
  type JSONElement_Primitive (line 813) | type JSONElement_Primitive = Message<"yorkie.v1.JSONElement.Primitive"> & {
  type JSONElement_Text (line 850) | type JSONElement_Text = Message<"yorkie.v1.JSONElement.Text"> & {
  type JSONElement_Counter (line 882) | type JSONElement_Counter = Message<"yorkie.v1.JSONElement.Counter"> & {
  type JSONElement_Tree (line 924) | type JSONElement_Tree = Message<"yorkie.v1.JSONElement.Tree"> & {
  type RHTNode (line 956) | type RHTNode = Message<"yorkie.v1.RHTNode"> & {
  type RGANode (line 978) | type RGANode = Message<"yorkie.v1.RGANode"> & {
  type NodeAttr (line 1015) | type NodeAttr = Message<"yorkie.v1.NodeAttr"> & {
  type TextNode (line 1042) | type TextNode = Message<"yorkie.v1.TextNode"> & {
  type TextNodeID (line 1079) | type TextNodeID = Message<"yorkie.v1.TextNodeID"> & {
  type TreeNode (line 1101) | type TreeNode = Message<"yorkie.v1.TreeNode"> & {
  type TreeNodes (line 1171) | type TreeNodes = Message<"yorkie.v1.TreeNodes"> & {
  type TreeNodeID (line 1188) | type TreeNodeID = Message<"yorkie.v1.TreeNodeID"> & {
  type TreePos (line 1210) | type TreePos = Message<"yorkie.v1.TreePos"> & {
  type User (line 1232) | type User = Message<"yorkie.v1.User"> & {
  type Member (line 1264) | type Member = Message<"yorkie.v1.Member"> & {
  type Project (line 1306) | type Project = Message<"yorkie.v1.Project"> & {
  type MetricPoint (line 1453) | type MetricPoint = Message<"yorkie.v1.MetricPoint"> & {
  type UpdatableProjectFields (line 1475) | type UpdatableProjectFields = Message<"yorkie.v1.UpdatableProjectFields"...
  type UpdatableProjectFields_AuthWebhookMethods (line 1597) | type UpdatableProjectFields_AuthWebhookMethods = Message<"yorkie.v1.Upda...
  type UpdatableProjectFields_EventWebhookEvents (line 1614) | type UpdatableProjectFields_EventWebhookEvents = Message<"yorkie.v1.Upda...
  type UpdatableProjectFields_AllowedOrigins (line 1631) | type UpdatableProjectFields_AllowedOrigins = Message<"yorkie.v1.Updatabl...
  type DocumentSummary (line 1648) | type DocumentSummary = Message<"yorkie.v1.DocumentSummary"> & {
  type PresenceChange (line 1710) | type PresenceChange = Message<"yorkie.v1.PresenceChange"> & {
  type PresenceChange_ChangeType (line 1732) | enum PresenceChange_ChangeType {
  type Presence (line 1763) | type Presence = Message<"yorkie.v1.Presence"> & {
  type ChannelSummary (line 1780) | type ChannelSummary = Message<"yorkie.v1.ChannelSummary"> & {
  type Checkpoint (line 1802) | type Checkpoint = Message<"yorkie.v1.Checkpoint"> & {
  type TextNodePos (line 1824) | type TextNodePos = Message<"yorkie.v1.TextNodePos"> & {
  type TimeTicket (line 1851) | type TimeTicket = Message<"yorkie.v1.TimeTicket"> & {
  type DocEventBody (line 1878) | type DocEventBody = Message<"yorkie.v1.DocEventBody"> & {
  type DocEvent (line 1900) | type DocEvent = Message<"yorkie.v1.DocEvent"> & {
  type ChannelEvent (line 1927) | type ChannelEvent = Message<"yorkie.v1.ChannelEvent"> & {
  type ChannelEvent_Type (line 1969) | enum ChannelEvent_Type {
  type DataSize (line 1995) | type DataSize = Message<"yorkie.v1.DataSize"> & {
  type DocSize (line 2017) | type DocSize = Message<"yorkie.v1.DocSize"> & {
  type Schema (line 2039) | type Schema = Message<"yorkie.v1.Schema"> & {
  type TreeNodeRule (line 2081) | type TreeNodeRule = Message<"yorkie.v1.TreeNodeRule"> & {
  type Rule (line 2113) | type Rule = Message<"yorkie.v1.Rule"> & {
  type RevisionSummary (line 2140) | type RevisionSummary = Message<"yorkie.v1.RevisionSummary"> & {
  type ValueType (line 2177) | enum ValueType {
  type DocEventType (line 2263) | enum DocEventType {

FILE: packages/sdk/src/api/yorkie/v1/yorkie_pb.ts
  type ActivateClientRequest (line 35) | type ActivateClientRequest = Message<"yorkie.v1.ActivateClientRequest"> & {
  type ActivateClientResponse (line 57) | type ActivateClientResponse = Message<"yorkie.v1.ActivateClientResponse"...
  type DeactivateClientRequest (line 74) | type DeactivateClientRequest = Message<"yorkie.v1.DeactivateClientReques...
  type DeactivateClientResponse (line 96) | type DeactivateClientResponse = Message<"yorkie.v1.DeactivateClientRespo...
  type AttachDocumentRequest (line 109) | type AttachDocumentRequest = Message<"yorkie.v1.AttachDocumentRequest"> & {
  type AttachDocumentResponse (line 136) | type AttachDocumentResponse = Message<"yorkie.v1.AttachDocumentResponse"...
  type DetachDocumentRequest (line 168) | type DetachDocumentRequest = Message<"yorkie.v1.DetachDocumentRequest"> & {
  type DetachDocumentResponse (line 200) | type DetachDocumentResponse = Message<"yorkie.v1.DetachDocumentResponse"...
  type WatchRequest (line 217) | type WatchRequest = Message<"yorkie.v1.WatchRequest"> & {
  type ResourceDescriptor (line 239) | type ResourceDescriptor = Message<"yorkie.v1.ResourceDescriptor"> & {
  type DocumentDescriptor (line 268) | type DocumentDescriptor = Message<"yorkie.v1.DocumentDescriptor"> & {
  type ChannelDescriptor (line 285) | type ChannelDescriptor = Message<"yorkie.v1.ChannelDescriptor"> & {
  type WatchResponse (line 302) | type WatchResponse = Message<"yorkie.v1.WatchResponse"> & {
  type WatchInitialization (line 331) | type WatchInitialization = Message<"yorkie.v1.WatchInitialization"> & {
  type ResourceInit (line 348) | type ResourceInit = Message<"yorkie.v1.ResourceInit"> & {
  type DocumentInit (line 377) | type DocumentInit = Message<"yorkie.v1.DocumentInit"> & {
  type ChannelInit (line 399) | type ChannelInit = Message<"yorkie.v1.ChannelInit"> & {
  type WatchEvent (line 426) | type WatchEvent = Message<"yorkie.v1.WatchEvent"> & {
  type DocWatchEvent (line 455) | type DocWatchEvent = Message<"yorkie.v1.DocWatchEvent"> & {
  type ChannelWatchEvent (line 477) | type ChannelWatchEvent = Message<"yorkie.v1.ChannelWatchEvent"> & {
  type WatchDocumentRequest (line 501) | type WatchDocumentRequest = Message<"yorkie.v1.WatchDocumentRequest"> & {
  type WatchDocumentResponse (line 525) | type WatchDocumentResponse = Message<"yorkie.v1.WatchDocumentResponse"> & {
  type WatchDocumentResponse_Initialization (line 554) | type WatchDocumentResponse_Initialization = Message<"yorkie.v1.WatchDocu...
  type WatchChannelRequest (line 573) | type WatchChannelRequest = Message<"yorkie.v1.WatchChannelRequest"> & {
  type WatchChannelResponse (line 597) | type WatchChannelResponse = Message<"yorkie.v1.WatchChannelResponse"> & {
  type WatchChannelInitialized (line 628) | type WatchChannelInitialized = Message<"yorkie.v1.WatchChannelInitialize...
  type RemoveDocumentRequest (line 650) | type RemoveDocumentRequest = Message<"yorkie.v1.RemoveDocumentRequest"> & {
  type RemoveDocumentResponse (line 677) | type RemoveDocumentResponse = Message<"yorkie.v1.RemoveDocumentResponse"...
  type PushPullChangesRequest (line 694) | type PushPullChangesRequest = Message<"yorkie.v1.PushPullChangesRequest"...
  type PushPullChangesResponse (line 726) | type PushPullChangesResponse = Message<"yorkie.v1.PushPullChangesRespons...
  type CreateRevisionRequest (line 743) | type CreateRevisionRequest = Message<"yorkie.v1.CreateRevisionRequest"> & {
  type CreateRevisionResponse (line 775) | type CreateRevisionResponse = Message<"yorkie.v1.CreateRevisionResponse"...
  type GetRevisionRequest (line 792) | type GetRevisionRequest = Message<"yorkie.v1.GetRevisionRequest"> & {
  type GetRevisionResponse (line 819) | type GetRevisionResponse = Message<"yorkie.v1.GetRevisionResponse"> & {
  type ListRevisionsRequest (line 836) | type ListRevisionsRequest = Message<"yorkie.v1.ListRevisionsRequest"> & {
  type ListRevisionsResponse (line 873) | type ListRevisionsResponse = Message<"yorkie.v1.ListRevisionsResponse"> & {
  type RestoreRevisionRequest (line 890) | type RestoreRevisionRequest = Message<"yorkie.v1.RestoreRevisionRequest"...
  type RestoreRevisionResponse (line 917) | type RestoreRevisionResponse = Message<"yorkie.v1.RestoreRevisionRespons...
  type AttachChannelRequest (line 930) | type AttachChannelRequest = Message<"yorkie.v1.AttachChannelRequest"> & {
  type AttachChannelResponse (line 952) | type AttachChannelResponse = Message<"yorkie.v1.AttachChannelResponse"> & {
  type DetachChannelRequest (line 974) | type DetachChannelRequest = Message<"yorkie.v1.DetachChannelRequest"> & {
  type DetachChannelResponse (line 1001) | type DetachChannelResponse = Message<"yorkie.v1.DetachChannelResponse"> & {
  type RefreshChannelRequest (line 1018) | type RefreshChannelRequest = Message<"yorkie.v1.RefreshChannelRequest"> & {
  type RefreshChannelResponse (line 1060) | type RefreshChannelResponse = Message<"yorkie.v1.RefreshChannelResponse"...
  type PeekChannelRequest (line 1096) | type PeekChannelRequest = Message<"yorkie.v1.PeekChannelRequest"> & {
  type PeekChannelResponse (line 1113) | type PeekChannelResponse = Message<"yorkie.v1.PeekChannelResponse"> & {
  type BroadcastRequest (line 1130) | type BroadcastRequest = Message<"yorkie.v1.BroadcastRequest"> & {
  type BroadcastResponse (line 1162) | type BroadcastResponse = Message<"yorkie.v1.BroadcastResponse"> & {

FILE: packages/sdk/src/channel/channel.ts
  type Observable (line 30) | interface Observable<T> {
  type ChannelStatus (line 37) | enum ChannelStatus {
  type BroadcastOptions (line 57) | interface BroadcastOptions {
  type ChannelEventType (line 72) | enum ChannelEventType {
  type PresenceEvent (line 111) | interface PresenceEvent {
  type BroadcastEvent (line 123) | interface BroadcastEvent {
  type LocalBroadcastEvent (line 131) | interface LocalBroadcastEvent {
  type AuthErrorEvent (line 142) | interface AuthErrorEvent {
  type SyncErrorEvent (line 164) | interface SyncErrorEvent {
  type ChannelEvent (line 184) | type ChannelEvent =
  type ChannelEventCallbackMap (line 194) | type ChannelEventCallbackMap = {
  class Channel (line 211) | class Channel implements Observable<ChannelEvent>, Attachable {
    method constructor (line 225) | constructor(key: string) {
    method getKey (line 239) | public getKey(): string {
    method getFirstKeyPath (line 246) | public getFirstKeyPath(): string {
    method getStatus (line 253) | public getStatus(): ChannelStatus {
    method applyStatus (line 260) | public applyStatus(status: ChannelStatus): void {
    method isAttached (line 267) | public isAttached(): boolean {
    method getActorID (line 274) | public getActorID(): ActorID | undefined {
    method setActor (line 281) | public setActor(actorID: ActorID): void {
    method getSessionID (line 288) | public getSessionID(): string | undefined {
    method setSessionID (line 295) | public setSessionID(sessionID: string): void {
    method getSessionCount (line 302) | public getSessionCount(): number {
    method updateSessionCount (line 310) | public updateSessionCount(sessionCount: number, seq: number): boolean {
    method hasLocalChanges (line 325) | public hasLocalChanges(): boolean {
    method subscribe (line 392) | public subscribe(
    method publish (line 484) | public publish(event: ChannelEvent): void {
    method broadcast (line 493) | public broadcast(
    method validateChannelKey (line 515) | private validateChannelKey(key: string): void {

FILE: packages/sdk/src/client/attachable.ts
  type ResourceStatus (line 22) | type ResourceStatus = 'detached' | 'attached' | 'removed';
  type Attachable (line 27) | interface Attachable {

FILE: packages/sdk/src/client/attachment.ts
  type WatchStream (line 25) | type WatchStream = AsyncIterable<unknown>;
  type WatchStreamCreator (line 32) | type WatchStreamCreator = (
  class Attachment (line 39) | class Attachment<R extends Attachable> {
    method constructor (line 69) | constructor(
    method changeSyncMode (line 94) | public changeSyncMode(syncMode: SyncMode) {
    method needRealtimeSync (line 102) | public needRealtimeSync(): boolean {
    method needSync (line 126) | public needSync(heartbeatInterval: number): boolean {
    method updateHeartbeatTime (line 147) | public updateHeartbeatTime(): void {
    method runWatchLoop (line 154) | public async runWatchLoop(
    method markDetaching (line 196) | public markDetaching(): void {
    method isDetaching (line 203) | public isDetaching(): boolean {
    method resetDetaching (line 211) | public resetDetaching(): void {
    method setSyncPromise (line 218) | public setSyncPromise(promise: Promise<void>): void {
    method clearSyncPromise (line 225) | public clearSyncPromise(): void {
    method waitForSyncComplete (line 232) | public async waitForSyncComplete(): Promise<void> {
    method resetCancelled (line 249) | public resetCancelled(): void {
    method cancelWatchStream (line 256) | public cancelWatchStream(): void {

FILE: packages/sdk/src/client/auth_interceptor.ts
  function createAuthInterceptor (line 23) | function createAuthInterceptor(

FILE: packages/sdk/src/client/client.ts
  type Key (line 71) | type Key = string;
  type SyncMode (line 77) | enum SyncMode {
  type ClientStatus (line 112) | enum ClientStatus {
  type ClientCondition (line 130) | enum ClientCondition {
  type ClientOptions (line 145) | interface ClientOptions {
  type DeactivateOptions (line 224) | interface DeactivateOptions {
  type AttachOptions (line 244) | interface AttachOptions<R, P> {
  type AttachChannelOptions (line 278) | interface AttachChannelOptions {
  class Client (line 339) | class Client {
    method constructor (line 365) | constructor(opts?: ClientOptions) {
    method activate (line 476) | public async activate(): Promise<void> {
    method deactivate (line 528) | public deactivate(
    method has (line 572) | public has(key: Key): boolean {
    method attach (line 599) | public attach<R, P extends Indexable>(
    method attachDocument (line 614) | private attachDocument<R, P extends Indexable>(
    method detach (line 744) | public detach(resource: any, opts?: any): Promise<any> {
    method detachDocument (line 760) | private detachDocument<R, P extends Indexable>(
    method attachChannel (line 831) | public async attachChannel(
    method detachChannel (line 915) | public async detachChannel(channel: Channel): Promise<Channel> {
    method changeSyncMode (line 969) | public async changeSyncMode(
    method changeDocumentSyncMode (line 981) | private async changeDocumentSyncMode<R, P extends Indexable>(
    method assertValidChannelSyncMode (line 1049) | private assertValidChannelSyncMode(syncMode: SyncMode): void {
    method changeChannelSyncMode (line 1062) | private async changeChannelSyncMode(
    method sync (line 1123) | public sync<R, P extends Indexable>(
    method remove (line 1209) | public remove<R, P extends Indexable>(doc: Document<R, P>): Promise<vo...
    method getID (line 1255) | public getID(): string | undefined {
    method getKey (line 1262) | public getKey(): string {
    method isActive (line 1269) | public isActive(): boolean {
    method getStatus (line 1276) | public getStatus(): ClientStatus {
    method getCondition (line 1283) | public getCondition(condition: ClientCondition): boolean {
    method createRevision (line 1290) | public async createRevision<R, P extends Indexable>(
    method listRevisions (line 1346) | public async listRevisions<R, P extends Indexable>(
    method getRevision (line 1401) | public async getRevision<R, P extends Indexable>(
    method restoreRevision (line 1455) | public async restoreRevision<R, P extends Indexable>(
    method peekChannel (line 1507) | public async peekChannel(channelKey: string): Promise<number> {
    method broadcast (line 1525) | public async broadcast(
    method runSyncLoop (line 1618) | private runSyncLoop(): void {
    method runWatchLoop (line 1725) | private async runWatchLoop(key: Key): Promise<void> {
    method createDocumentWatchStream (line 1786) | private createDocumentWatchStream<R, P extends Indexable>(
    method createChannelWatchStream (line 1881) | private createChannelWatchStream(
    method handleWatchChannelResponse (line 1944) | private handleWatchChannelResponse(
    method handleWatchDocumentResponse (line 2007) | private handleWatchDocumentResponse<R, P extends Indexable>(
    method deactivateInternal (line 2040) | private deactivateInternal() {
    method detachInternal (line 2053) | private detachInternal(key: Key) {
    method syncInternal (line 2077) | private async syncInternal<R, P extends Indexable>(
    method handleConnectError (line 2263) | private async handleConnectError(err: any): Promise<boolean> {
    method enqueueTask (line 2329) | private enqueueTask(task: () => Promise<any>): Promise<any> {
    method processNext (line 2343) | private async processNext() {

FILE: packages/sdk/src/client/metric_interceptor.ts
  function createMetricInterceptor (line 24) | function createMetricInterceptor(userAgent?: string): Interceptor {

FILE: packages/sdk/src/client/watch.ts
  type WatchStreamConfig (line 22) | interface WatchStreamConfig<Resp> {
  function runWatchStream (line 48) | function runWatchStream<Resp>(

FILE: packages/sdk/src/devtools/index.ts
  type DevtoolsStatus (line 23) | type DevtoolsStatus = 'connected' | 'disconnected' | 'synced';
  type Window (line 34) | interface Window {
  function sendToPanel (line 45) | function sendToPanel(
  function setupDevtools (line 67) | function setupDevtools<T, P extends Indexable>(

FILE: packages/sdk/src/devtools/protocol.ts
  type PanelToSDKMessage (line 34) | type PanelToSDKMessage =
  type SDKToPanelMessage (line 57) | type SDKToPanelMessage =
  type FullPanelToSDKMessage (line 90) | type FullPanelToSDKMessage = PanelToSDKMessage & {
  type FullSDKToPanelMessage (line 94) | type FullSDKToPanelMessage = SDKToPanelMessage & {

FILE: packages/sdk/src/devtools/types.ts
  type Client (line 39) | type Client = {
  type JSONElement (line 47) | type JSONElement = {
  type JSONElementType (line 54) | type JSONElementType =
  type JSONElementValue (line 68) | type JSONElementValue =
  type ContainerValue (line 78) | type ContainerValue = {
  type TreeNodeInfo (line 85) | type TreeNodeInfo = {
  type DocEventForReplay (line 106) | type DocEventForReplay<P extends Indexable = Indexable, T = OpInfo> =
  type DocEventsForReplay (line 119) | type DocEventsForReplay = Array<DocEventForReplay>;
  function isDocEventForReplay (line 124) | function isDocEventForReplay(
  function isDocEventsForReplay (line 144) | function isDocEventsForReplay(

FILE: packages/sdk/src/document/change/change.ts
  type ChangeStruct (line 38) | type ChangeStruct<P extends Indexable> = {
  class Change (line 51) | class Change<P extends Indexable> {
    method constructor (line 63) | constructor({
    method create (line 83) | public static create<P extends Indexable>({
    method getID (line 100) | public getID(): ChangeID {
    method getMessage (line 107) | public getMessage(): string | undefined {
    method hasOperations (line 114) | public hasOperations(): boolean {
    method getOperations (line 121) | public getOperations(): Array<Operation> {
    method setActor (line 128) | public setActor(actorID: ActorID): void {
    method hasPresenceChange (line 139) | public hasPresenceChange(): boolean {
    method getPresenceChange (line 146) | public getPresenceChange(): PresenceChange<P> | undefined {
    method execute (line 153) | public execute(
    method toTestString (line 202) | public toTestString(): string {
    method toStruct (line 211) | public toStruct(): ChangeStruct<P> {
    method fromStruct (line 225) | public static fromStruct<P extends Indexable>(

FILE: packages/sdk/src/document/change/change_id.ts
  class ChangeID (line 30) | class ChangeID {
    method constructor (line 50) | constructor(
    method hasClocks (line 67) | public hasClocks(): boolean {
    method of (line 74) | public static of(
    method next (line 87) | public next(excludeClocks = false): ChangeID {
    method syncClocks (line 113) | public syncClocks(other: ChangeID): ChangeID {
    method setClocks (line 136) | public setClocks(otherLamport: bigint, vector: VersionVector): ChangeID {
    method createTimeTicket (line 149) | public createTimeTicket(delimiter: number): TimeTicket {
    method setActor (line 156) | public setActor(actorID: ActorID): ChangeID {
    method setLamport (line 169) | public setLamport(lamport: bigint): ChangeID {
    method setVersionVector (line 182) | public setVersionVector(versionVector: VersionVector): ChangeID {
    method getClientSeq (line 195) | public getClientSeq(): number {
    method getServerSeq (line 202) | public getServerSeq(): string {
    method getLamport (line 212) | public getLamport(): bigint {
    method getLamportAsString (line 219) | public getLamportAsString(): string {
    method getActorID (line 226) | public getActorID(): string {
    method getVersionVector (line 233) | public getVersionVector(): VersionVector {
    method toTestString (line 240) | public toTestString(): string {

FILE: packages/sdk/src/document/change/change_pack.ts
  class ChangePack (line 26) | class ChangePack<P extends Indexable> {
    method constructor (line 53) | constructor(
    method create (line 71) | public static create<P extends Indexable>(
    method getDocumentKey (line 92) | public getDocumentKey(): string {
    method getCheckpoint (line 99) | public getCheckpoint(): Checkpoint {
    method getIsRemoved (line 106) | public getIsRemoved(): boolean {
    method getChanges (line 113) | public getChanges(): Array<Change<P>> {
    method hasChanges (line 120) | public hasChanges(): boolean {
    method getChangeSize (line 127) | public getChangeSize(): number {
    method hasSnapshot (line 134) | public hasSnapshot(): boolean {
    method getSnapshot (line 141) | public getSnapshot(): Uint8Array | undefined {
    method getVersionVector (line 148) | public getVersionVector(): VersionVector | undefined {

FILE: packages/sdk/src/document/change/checkpoint.ts
  class Checkpoint (line 22) | class Checkpoint {
    method constructor (line 26) | constructor(serverSeq: bigint, clientSeq: number) {
    method of (line 34) | public static of(serverSeq: bigint, clientSeq: number): Checkpoint {
    method increaseClientSeq (line 41) | public increaseClientSeq(inc: number): Checkpoint {
    method forward (line 53) | public forward(other: Checkpoint): Checkpoint {
    method getServerSeqAsString (line 68) | public getServerSeqAsString(): string {
    method getClientSeq (line 75) | public getClientSeq(): number {
    method getServerSeq (line 82) | public getServerSeq(): bigint {
    method equals (line 90) | public equals(other: Checkpoint): boolean {
    method toTestString (line 100) | public toTestString(): string {

FILE: packages/sdk/src/document/change/context.ts
  class ChangeContext (line 40) | class ChangeContext<P extends Indexable = Indexable> {
    method constructor (line 62) | constructor(prevID: ChangeID, root: CRDTRoot, presence: P, message?: s...
    method create (line 78) | public static create<P extends Indexable>(
    method push (line 90) | public push(operation: Operation): void {
    method registerElement (line 97) | public registerElement(element: CRDTElement, parent: CRDTContainer): v...
    method registerRemovedElement (line 104) | public registerRemovedElement(deleted: CRDTElement): void {
    method registerGCPair (line 111) | public registerGCPair(pair: GCPair): void {
    method getNextID (line 119) | public getNextID(): ChangeID {
    method toChange (line 135) | public toChange(): Change<P> {
    method isPresenceOnlyChange (line 154) | public isPresenceOnlyChange(): boolean {
    method hasChange (line 161) | public hasChange(): boolean {
    method setPresenceChange (line 168) | public setPresenceChange(presenceChange: PresenceChange<P>) {
    method setReversePresence (line 175) | public setReversePresence(
    method getReversePresence (line 191) | public getReversePresence() {
    method issueTimeTicket (line 204) | public issueTimeTicket(): TimeTicket {
    method getLastTimeTicket (line 212) | public getLastTimeTicket(): TimeTicket {
    method acc (line 219) | public acc(diff: DataSize) {

FILE: packages/sdk/src/document/crdt/array.ts
  class CRDTArray (line 32) | class CRDTArray extends CRDTContainer {
    method constructor (line 35) | constructor(createdAt: TimeTicket, elements: RGATreeList) {
    method create (line 43) | public static create(
    method subPathOf (line 61) | public subPathOf(createdAt: TimeTicket): string | undefined {
    method purge (line 68) | public purge(element: CRDTElement): void {
    method insertAfter (line 75) | public insertAfter(
    method moveAfter (line 87) | public moveAfter(
    method get (line 98) | public get(index: number): CRDTElement | undefined {
    method getByID (line 106) | public getByID(createdAt: TimeTicket): CRDTElement | undefined {
    method getHead (line 114) | public getHead(): CRDTElement {
    method getLast (line 121) | public getLast(): CRDTElement {
    method getPrevCreatedAt (line 129) | public getPrevCreatedAt(createdAt: TimeTicket): TimeTicket {
    method posCreatedAt (line 138) | public posCreatedAt(elemCreatedAt: TimeTicket): TimeTicket {
    method delete (line 145) | public delete(createdAt: TimeTicket, editedAt: TimeTicket): CRDTElement {
    method deleteByIndex (line 152) | public deleteByIndex(
    method set (line 163) | public set(
    method getLastCreatedAt (line 174) | public getLastCreatedAt(): TimeTicket {
    method length (line 181) | public get length(): number {
    method toTestString (line 201) | public toTestString(): string {
    method getDescendants (line 208) | public getDescendants(
    method getDataSize (line 229) | public getDataSize(): DataSize {
    method toJSON (line 239) | public toJSON(): string {
    method toJS (line 250) | public toJS(): any {
    method toJSForTest (line 257) | public toJSForTest(): Devtools.JSONElement {
    method toSortedJSON (line 278) | public toSortedJSON(): string {
    method getElements (line 285) | public getElements(): RGATreeList {
    method getRGATreeList (line 293) | public getRGATreeList(): RGATreeList {
    method getAllRGANodes (line 301) | public getAllRGANodes(): Array<RGATreeListNode> {
    method deepcopy (line 308) | public deepcopy(): CRDTArray {
  method [Symbol.iterator] (line 189) | public *[Symbol.iterator](): IterableIterator<CRDTElement> {

FILE: packages/sdk/src/document/crdt/counter.ts
  type CounterType (line 34) | enum CounterType {
  type CounterValue (line 40) | type CounterValue = number | bigint;
  class CRDTCounter (line 46) | class CRDTCounter extends CRDTElement {
    method constructor (line 51) | constructor(
    method create (line 94) | public static create(
    method valueFromBytes (line 105) | public static valueFromBytes(
    method getDataSize (line 126) | public getDataSize(): DataSize {
    method toJSON (line 144) | public toJSON(): string {
    method toSortedJSON (line 151) | public toSortedJSON(): string {
    method toJSForTest (line 158) | public toJSForTest(): Devtools.JSONElement {
    method deepcopy (line 169) | public deepcopy(): CRDTCounter {
    method getType (line 186) | public getType(): CounterType {
    method getCounterType (line 193) | public static getCounterType(value: CounterValue): CounterType | undef...
    method isSupport (line 211) | public static isSupport(value: CounterValue): boolean {
    method isInteger (line 218) | public static isInteger(num: number): boolean {
    method isNumericType (line 225) | public isNumericType(): boolean {
    method getValueType (line 237) | public getValueType(): CounterType {
    method getValue (line 244) | public getValue(): CounterValue {
    method toBytes (line 251) | public toBytes(): Uint8Array {
    method isDedup (line 277) | public isDedup(): boolean {
    method increaseDedup (line 285) | public increaseDedup(v: Primitive, actor: string): CRDTCounter {
    method hllBytes (line 315) | public hllBytes(): Uint8Array | undefined {
    method restoreHLL (line 322) | public restoreHLL(data: Uint8Array): void {
    method recomputeValue (line 333) | private recomputeValue(): void {
    method increase (line 342) | public increase(v: Primitive): CRDTCounter {

FILE: packages/sdk/src/document/crdt/element.ts
  method constructor (line 32) | constructor(createdAt: TimeTicket) {
  method getCreatedAt (line 39) | public getCreatedAt(): TimeTicket {
  method getID (line 46) | public getID(): TimeTicket {
  method getMovedAt (line 53) | public getMovedAt(): TimeTicket | undefined {
  method getRemovedAt (line 60) | public getRemovedAt(): TimeTicket | undefined {
  method getPositionedAt (line 68) | public getPositionedAt(): TimeTicket {
  method setCreatedAt (line 79) | public setCreatedAt(createdAt: TimeTicket) {
  method setMovedAt (line 86) | public setMovedAt(movedAt?: TimeTicket): boolean {
  method setRemovedAt (line 98) | public setRemovedAt(removedAt?: TimeTicket): void {
  method remove (line 105) | public remove(removedAt?: TimeTicket): boolean {
  method isRemoved (line 124) | public isRemoved(): boolean {
  method getMetaUsage (line 131) | public getMetaUsage(): number {
  method constructor (line 164) | constructor(createdAt: TimeTicket) {

FILE: packages/sdk/src/document/crdt/element_rht.ts
  class ElementRHTNode (line 24) | class ElementRHTNode {
    method constructor (line 28) | constructor(strKey: string, value: CRDTElement) {
    method of (line 36) | public static of(strKey: string, value: CRDTElement): ElementRHTNode {
    method isRemoved (line 43) | public isRemoved(): boolean {
    method getStrKey (line 50) | public getStrKey(): string {
    method getValue (line 57) | public getValue(): CRDTElement {
    method remove (line 64) | public remove(removedAt: TimeTicket): boolean {
  class ElementRHT (line 73) | class ElementRHT {
    method constructor (line 77) | constructor() {
    method create (line 85) | public static create(): ElementRHT {
    method set (line 92) | public set(
    method delete (line 119) | public delete(createdAt: TimeTicket, executedAt: TimeTicket): CRDTElem...
    method subPathOf (line 135) | public subPathOf(createdAt: TimeTicket): string | undefined {
    method purge (line 147) | public purge(element: CRDTElement): void {
    method deleteByKey (line 169) | public deleteByKey(
    method has (line 188) | public has(key: string): boolean {
    method getByID (line 199) | public getByID(createdAt: TimeTicket): ElementRHTNode | undefined {
    method get (line 206) | public get(key: string): ElementRHTNode | undefined {
    method deepcopy (line 218) | public deepcopy(): ElementRHT {
  method [Symbol.iterator] (line 240) | public *[Symbol.iterator](): IterableIterator<ElementRHTNode> {

FILE: packages/sdk/src/document/crdt/gc.ts
  type GCPair (line 24) | type GCPair = {
  type GCParent (line 32) | interface GCParent {
  type GCChild (line 39) | interface GCChild {

FILE: packages/sdk/src/document/crdt/hll.ts
  class HLL (line 33) | class HLL {
    method constructor (line 36) | constructor() {
    method add (line 43) | public add(value: string): boolean {
    method count (line 60) | public count(): number {
    method merge (line 80) | public merge(other: HLL): void {
    method toBytes (line 91) | public toBytes(): Uint8Array {
    method restore (line 99) | public restore(data: Uint8Array): void {
  function xxhash64 (line 113) | function xxhash64(input: string): bigint {
  function rotl64 (line 176) | function rotl64(x: bigint, r: bigint): bigint {
  function xxRound (line 181) | function xxRound(acc: bigint, input: bigint): bigint {
  function xxMergeRound (line 188) | function xxMergeRound(acc: bigint, val: bigint): bigint {
  function readU64LE (line 195) | function readU64LE(buf: Uint8Array, offset: number): bigint {
  function readU32LE (line 204) | function readU32LE(buf: Uint8Array, offset: number): bigint {
  function countLeadingZeros64 (line 214) | function countLeadingZeros64(x: bigint): number {

FILE: packages/sdk/src/document/crdt/object.ts
  class CRDTObject (line 32) | class CRDTObject extends CRDTContainer {
    method constructor (line 35) | constructor(createdAt: TimeTicket, memberNodes: ElementRHT) {
    method create (line 43) | public static create(
    method subPathOf (line 61) | public subPathOf(createdAt: TimeTicket): string | undefined {
    method purge (line 68) | public purge(value: CRDTElement): void {
    method set (line 75) | public set(
    method delete (line 86) | public delete(createdAt: TimeTicket, executedAt: TimeTicket): CRDTElem...
    method deleteByKey (line 93) | public deleteByKey(
    method get (line 103) | public get(key: string): CRDTElement | undefined {
    method getByID (line 111) | public getByID(createdAt: TimeTicket): CRDTElement | undefined {
    method has (line 119) | public has(key: string): boolean {
    method getDataSize (line 126) | public getDataSize(): DataSize {
    method toJSON (line 136) | public toJSON(): string {
    method toJS (line 147) | public toJS(): any {
    method toJSForTest (line 154) | public toJSForTest(): Devtools.JSONElement {
    method getKeys (line 175) | public getKeys(): Array<string> {
    method toSortedJSON (line 187) | public toSortedJSON(): string {
    method getRHT (line 205) | public getRHT(): ElementRHT {
    method deepcopy (line 212) | public deepcopy(): CRDTObject {
    method getDescendants (line 223) | public getDescendants(
  method [Symbol.iterator] (line 241) | public *[Symbol.iterator](): IterableIterator<[string, CRDTElement]> {

FILE: packages/sdk/src/document/crdt/primitive.ts
  type PrimitiveType (line 29) | enum PrimitiveType {
  type PrimitiveValue (line 44) | type PrimitiveValue =
  class Primitive (line 52) | class Primitive extends CRDTElement {
    method constructor (line 56) | constructor(value: PrimitiveValue, createdAt: TimeTicket) {
    method of (line 65) | public static of(value: PrimitiveValue, createdAt: TimeTicket): Primit...
    method valueFromBytes (line 72) | public static valueFromBytes(
    method getValueSize (line 110) | private getValueSize(): number {
    method getDataSize (line 141) | public getDataSize(): DataSize {
    method toJSON (line 151) | public toJSON(): string {
    method toSortedJSON (line 169) | public toSortedJSON(): string {
    method toJSForTest (line 176) | public toJSForTest(): Devtools.JSONElement {
    method deepcopy (line 187) | public deepcopy(): Primitive {
    method getType (line 197) | public getType(): PrimitiveType {
    method getPrimitiveType (line 204) | public static getPrimitiveType(value: unknown): PrimitiveType | undefi...
    method isSupport (line 236) | public static isSupport(value: unknown): boolean {
    method isInteger (line 247) | public static isInteger(num: number): boolean {
    method isNumericType (line 254) | public isNumericType(): boolean {
    method getValue (line 266) | public getValue(): PrimitiveValue {
    method toBytes (line 273) | public toBytes(): Uint8Array {

FILE: packages/sdk/src/document/crdt/rga_tree_list.ts
  class ElementEntry (line 34) | class ElementEntry {
    method constructor (line 39) | constructor(elem: CRDTElement) {
  class RGATreeListNode (line 48) | class RGATreeListNode
    method constructor (line 59) | constructor(elem: CRDTElement | undefined, createdAt: TimeTicket) {
    method createWithElement (line 69) | public static createWithElement(elem: CRDTElement): RGATreeListNode {
    method createBarePosition (line 81) | public static createBarePosition(createdAt: TimeTicket): RGATreeListNo...
    method createAfter (line 89) | public static createAfter(
    method insertNodeAfter (line 101) | public static insertNodeAfter(
    method remove (line 117) | public remove(removedAt: TimeTicket): boolean {
    method getCreatedAt (line 129) | public getCreatedAt(): TimeTicket {
    method getPositionedAt (line 142) | public getPositionedAt(): TimeTicket {
    method release (line 155) | public release(): void {
    method getLength (line 170) | public getLength(): number {
    method getPrev (line 180) | public getPrev(): RGATreeListNode | undefined {
    method getNext (line 187) | public getNext(): RGATreeListNode | undefined {
    method getValue (line 194) | public getValue(): CRDTElement {
    method getElement (line 206) | public getElement(): CRDTElement | undefined {
    method isRemoved (line 213) | public isRemoved(): boolean {
    method getElementEntry (line 223) | public getElementEntry(): ElementEntry | undefined {
    method setElementEntry (line 230) | public setElementEntry(entry: ElementEntry | undefined): void {
    method getPositionCreatedAt (line 237) | public getPositionCreatedAt(): TimeTicket {
    method getPositionMovedAt (line 245) | public getPositionMovedAt(): TimeTicket | undefined {
    method getRemovedAt (line 256) | public getRemovedAt(): TimeTicket | undefined {
    method setRemovedAt (line 263) | public setRemovedAt(removedAt: TimeTicket): void {
    method toIDString (line 271) | public toIDString(): string {
    method getDataSize (line 279) | public getDataSize(): DataSize {
  class RGATreeList (line 292) | class RGATreeList implements GCParent {
    method constructor (line 299) | constructor() {
    method create (line 318) | public static create(): RGATreeList {
    method length (line 325) | public get length(): number {
    method findNextBeforeExecutedAt (line 333) | private findNextBeforeExecutedAt(
    method release (line 346) | private release(node: RGATreeListNode): void {
    method insertAfter (line 362) | public insertAfter(
    method insertPositionAfter (line 401) | private insertPositionAfter(
    method moveAfter (line 431) | public moveAfter(
    method insert (line 488) | public insert(value: CRDTElement): void {
    method getByID (line 497) | public getByID(createdAt: TimeTicket): RGATreeListNode | undefined {
    method subPathOf (line 508) | public subPathOf(createdAt: TimeTicket): string | undefined {
    method purge (line 526) | public purge(child: GCChild | CRDTElement): void {
    method getByIndex (line 555) | public getByIndex(idx: number): RGATreeListNode | undefined {
    method findPrevCreatedAt (line 569) | public findPrevCreatedAt(createdAt: TimeTicket): TimeTicket {
    method getPrevCreatedAt (line 598) | public getPrevCreatedAt(createdAt: TimeTicket): TimeTicket {
    method delete (line 605) | public delete(createdAt: TimeTicket, editedAt: TimeTicket): CRDTElement {
    method set (line 625) | public set(
    method deleteByIndex (line 644) | public deleteByIndex(
    method getHead (line 662) | public getHead(): CRDTElement {
    method getLast (line 669) | public getLast(): CRDTElement {
    method getLastCreatedAt (line 678) | public getLastCreatedAt(): TimeTicket {
    method posCreatedAt (line 687) | public posCreatedAt(elemCreatedAt: TimeTicket): TimeTicket {
    method addDeadPosition (line 702) | public addDeadPosition(
    method addMovedElement (line 719) | public addMovedElement(
    method allNodes (line 743) | public allNodes(): Array<RGATreeListNode> {
    method toTestString (line 757) | public toTestString(): string {
  method [Symbol.iterator] (line 778) | public *[Symbol.iterator](): IterableIterator<RGATreeListNode> {

FILE: packages/sdk/src/document/crdt/rga_tree_split.ts
  type ValueChange (line 36) | interface ValueChange<T> {
  type RGATreeSplitValue (line 43) | interface RGATreeSplitValue {
  type RGATreeSplitPosStruct (line 53) | type RGATreeSplitPosStruct = {
  type RGATreeSplitNodeIDStruct (line 62) | type RGATreeSplitNodeIDStruct = {
  class RGATreeSplitNodeID (line 70) | class RGATreeSplitNodeID {
    method constructor (line 74) | constructor(createdAt: TimeTicket, offset: number) {
    method of (line 82) | public static of(createdAt: TimeTicket, offset: number): RGATreeSplitN...
    method fromStruct (line 89) | public static fromStruct(
    method getCreatedAt (line 101) | public getCreatedAt(): TimeTicket {
    method getOffset (line 108) | public getOffset(): number {
    method equals (line 115) | public equals(other: RGATreeSplitNodeID): boolean {
    method hasSameCreatedAt (line 125) | public hasSameCreatedAt(other: RGATreeSplitNodeID): boolean {
    method split (line 132) | public split(offset: number): RGATreeSplitNodeID {
    method toStruct (line 139) | public toStruct(): RGATreeSplitNodeIDStruct {
    method toTestString (line 150) | public toTestString(): string {
    method toIDString (line 157) | public toIDString(): string {
  class RGATreeSplitPos (line 167) | class RGATreeSplitPos {
    method constructor (line 171) | constructor(id: RGATreeSplitNodeID, relativeOffset: number) {
    method of (line 179) | public static of(
    method fromStruct (line 189) | public static fromStruct(struct: RGATreeSplitPosStruct): RGATreeSplitP...
    method getID (line 197) | public getID(): RGATreeSplitNodeID {
    method getRelativeOffset (line 204) | public getRelativeOffset(): number {
    method getAbsoluteID (line 211) | public getAbsoluteID(): RGATreeSplitNodeID {
    method toTestString (line 222) | public toTestString(): string {
    method toStruct (line 229) | public toStruct(): RGATreeSplitPosStruct {
    method equals (line 239) | public equals(other: RGATreeSplitPos): boolean {
  type RGATreeSplitPosRange (line 248) | type RGATreeSplitPosRange = [RGATreeSplitPos, RGATreeSplitPos];
  class RGATreeSplitNode (line 253) | class RGATreeSplitNode<T extends RGATreeSplitValue>
    method constructor (line 265) | constructor(id: RGATreeSplitNodeID, value?: T, removedAt?: TimeTicket) {
    method create (line 274) | public static create<T extends RGATreeSplitValue>(
    method createComparator (line 284) | public static createComparator(): Comparator<RGATreeSplitNodeID> {
    method getID (line 303) | public getID(): RGATreeSplitNodeID {
    method getCreatedAt (line 310) | public getCreatedAt(): TimeTicket {
    method getLength (line 317) | public getLength(): number {
    method getContentLength (line 327) | public getContentLength(): number {
    method getPrev (line 334) | public getPrev(): RGATreeSplitNode<T> | undefined {
    method getNext (line 341) | public getNext(): RGATreeSplitNode<T> | undefined {
    method getInsPrev (line 348) | public getInsPrev(): RGATreeSplitNode<T> | undefined {
    method getInsNext (line 355) | public getInsNext(): RGATreeSplitNode<T> | undefined {
    method getInsPrevID (line 362) | public getInsPrevID(): RGATreeSplitNodeID {
    method setPrev (line 369) | public setPrev(node?: RGATreeSplitNode<T>): void {
    method setNext (line 379) | public setNext(node?: RGATreeSplitNode<T>): void {
    method setInsPrev (line 389) | public setInsPrev(node?: RGATreeSplitNode<T>): void {
    method setInsNext (line 399) | public setInsNext(node?: RGATreeSplitNode<T>): void {
    method hasNext (line 409) | public hasNext(): boolean {
    method hasInsPrev (line 416) | public hasInsPrev(): boolean {
    method isRemoved (line 423) | public isRemoved(): boolean {
    method getRemovedAt (line 430) | public getRemovedAt(): TimeTicket | undefined {
    method split (line 437) | public split(offset: number): RGATreeSplitNode<T> {
    method canRemove (line 448) | public canRemove(
    method canStyle (line 474) | public canStyle(
    method setRemovedAt (line 487) | public setRemovedAt(removedAt?: TimeTicket): void {
    method remove (line 494) | public remove(removedAt: TimeTicket) {
    method createPosRange (line 510) | public createPosRange(): RGATreeSplitPosRange {
    method getDataSize (line 520) | public getDataSize(): DataSize {
    method deepcopy (line 537) | public deepcopy(): RGATreeSplitNode<T> {
    method toTestString (line 545) | public toTestString(): string {
    method splitValue (line 549) | private splitValue(offset: number): T {
    method toIDString (line 558) | public toIDString(): string {
  class RGATreeSplit (line 570) | class RGATreeSplit<T extends RGATreeSplitValue> implements GCParent {
    method constructor (line 575) | constructor() {
    method create (line 587) | public static create<T extends RGATreeSplitValue>(): RGATreeSplit<T> {
    method edit (line 602) | public edit(
    method indexToPos (line 680) | public indexToPos(idx: number): RGATreeSplitPos {
    method findIndexesFromRange (line 689) | public findIndexesFromRange(range: RGATreeSplitPosRange): [number, num...
    method posToIndex (line 697) | public posToIndex(pos: RGATreeSplitPos, preferToLeft: boolean): number {
    method findNode (line 718) | public findNode(id: RGATreeSplitNodeID): RGATreeSplitNode<T> {
    method length (line 725) | public get length(): number {
    method getTreeByIndex (line 732) | public getTreeByIndex(): SplayTree<T> {
    method getTreeByID (line 739) | public getTreeByID(): LLRBTree<RGATreeSplitNodeID, RGATreeSplitNode<T>> {
    method toString (line 746) | public toString(): string {
    method getHead (line 770) | public getHead(): RGATreeSplitNode<T> {
    method deepcopy (line 777) | public deepcopy(): RGATreeSplit<T> {
    method normalizePos (line 802) | public normalizePos(pos: RGATreeSplitPos): RGATreeSplitPos {
    method refinePos (line 844) | public refinePos(pos: RGATreeSplitPos): RGATreeSplitPos {
    method toTestString (line 875) | public toTestString(): string {
    method insertAfter (line 895) | public insertAfter(
    method findNodeWithSplit (line 914) | public findNodeWithSplit(
    method findFloorNodePreferToLeft (line 931) | private findFloorNodePreferToLeft(
    method findFloorNode (line 953) | private findFloorNode(
    method findBetween (line 971) | public findBetween(
    method splitNode (line 986) | private splitNode(
    method deleteNodes (line 1027) | private deleteNodes(
    method findEdgesOfCandidates (line 1096) | private findEdgesOfCandidates(
    method makeChanges (line 1105) | private makeChanges(
    method deleteIndexNodes (line 1147) | private deleteIndexNodes(
    method purge (line 1163) | public purge(node: RGATreeSplitNode<T>): void {
  method [Symbol.iterator] (line 759) | public *[Symbol.iterator](): IterableIterator<RGATreeSplitNode<T>> {

FILE: packages/sdk/src/document/crdt/rht.ts
  class RHTNode (line 28) | class RHTNode implements GCChild {
    method constructor (line 34) | constructor(
    method of (line 49) | public static of(
    method getKey (line 61) | public getKey(): string {
    method getValue (line 68) | public getValue(): string {
    method getUpdatedAt (line 75) | public getUpdatedAt(): TimeTicket {
    method isRemoved (line 82) | public isRemoved(): boolean {
    method toIDString (line 89) | public toIDString(): string {
    method getRemovedAt (line 96) | public getRemovedAt(): TimeTicket | undefined {
    method getDataSize (line 107) | public getDataSize(): DataSize {
  class RHT (line 119) | class RHT {
    method constructor (line 123) | constructor() {
    method create (line 131) | public static create(): RHT {
    method getNodeMapByKey (line 138) | public getNodeMapByKey(): Map<string, RHTNode> {
    method set (line 145) | public set(
    method setInternal (line 176) | public setInternal(
    method remove (line 193) | public remove(key: string, executedAt: TimeTicket): Array<RHTNode> {
    method has (line 229) | public has(key: string): boolean {
    method get (line 240) | public get(key: string): string | undefined {
    method deepcopy (line 251) | public deepcopy(): RHT {
    method toJSON (line 267) | public toJSON(): string {
    method size (line 284) | public size(): number {
    method toObject (line 291) | public toObject(): Record<string, string> {
    method purge (line 312) | public purge(child: RHTNode) {
  method [Symbol.iterator] (line 303) | public *[Symbol.iterator](): IterableIterator<RHTNode> {

FILE: packages/sdk/src/document/crdt/root.ts
  type CRDTElementPair (line 46) | interface CRDTElementPair {
  type RootStats (line 54) | interface RootStats {
  class CRDTRoot (line 79) | class CRDTRoot {
    method constructor (line 109) | constructor(rootObject: CRDTObject) {
    method create (line 144) | public static create(): CRDTRoot {
    method findByCreatedAt (line 151) | public findByCreatedAt(createdAt: TimeTicket): CRDTElement | undefined {
    method findElementPairByCreatedAt (line 164) | public findElementPairByCreatedAt(
    method createSubPaths (line 173) | public createSubPaths(createdAt: TimeTicket): Array<string> {
    method createPath (line 203) | public createPath(createdAt: TimeTicket): string {
    method registerElement (line 210) | public registerElement(element: CRDTElement, parent?: CRDTContainer): ...
    method deregisterElement (line 232) | public deregisterElement(element: CRDTElement): number {
    method registerRemovedElement (line 257) | public registerRemovedElement(element: CRDTElement): void {
    method registerGCPair (line 270) | public registerGCPair(pair: GCPair): void {
    method getElementMapSize (line 297) | public getElementMapSize(): number {
    method getGarbageElementSetSize (line 304) | public getGarbageElementSetSize(): number {
    method getObject (line 323) | public getObject(): CRDTObject {
    method getGarbageLen (line 330) | public getGarbageLen(): number {
    method getDocSize (line 337) | getDocSize(): DocSize {
    method deepcopy (line 344) | public deepcopy(): CRDTRoot {
    method garbageCollect (line 351) | public garbageCollect(minSyncedVersionVector: VersionVector): number {
    method toJSON (line 381) | public toJSON(): string {
    method toSortedJSON (line 388) | public toSortedJSON(): string {
    method getStats (line 396) | public getStats(): RootStats {
    method acc (line 407) | public acc(diff: DataSize) {
    method getGCElementPairs (line 415) | public *getGCElementPairs(): IterableIterator<CRDTElementPair> {

FILE: packages/sdk/src/document/crdt/text.ts
  type TextChangeType (line 45) | enum TextChangeType {
  type TextValueType (line 54) | interface TextValueType<A> {
  type TextChange (line 63) | interface TextChange<A = Indexable> extends ValueChange<TextValueType<A>> {
  class CRDTTextValue (line 73) | class CRDTTextValue {
    method constructor (line 77) | constructor(content: string) {
    method create (line 85) | public static create(content: string): CRDTTextValue {
    method length (line 92) | public get length(): number {
    method substring (line 99) | public substring(indexStart: number, indexEnd: number): CRDTTextValue {
    method setAttr (line 110) | public setAttr(
    method getAttrs (line 121) | public getAttrs(): RHT {
    method toString (line 128) | public toString(): string {
    method getDataSize (line 135) | public getDataSize(): DataSize {
    method toJSON (line 151) | public toJSON(): string {
    method getAttributes (line 173) | public getAttributes(): Record<string, string> {
    method getContent (line 180) | public getContent(): string {
    method purge (line 187) | public purge(node: GCChild): void {
    method getGCPairs (line 196) | public getGCPairs(): Array<GCPair> {
  class CRDTText (line 213) | class CRDTText<A extends Indexable = Indexable> extends CRDTElement {
    method constructor (line 216) | constructor(
    method create (line 227) | public static create<A extends Indexable>(
    method edit (line 237) | public edit(
    method setStyle (line 286) | public setStyle(
    method removeStyle (line 386) | public removeStyle(
    method indexRangeToPosRange (line 478) | public indexRangeToPosRange(
    method length (line 493) | public get length(): number {
    method getTreeByIndex (line 500) | public getTreeByIndex(): SplayTree<CRDTTextValue> {
    method getTreeByID (line 507) | public getTreeByID(): LLRBTree<
    method refinePos (line 517) | public refinePos(pos: RGATreeSplitPos): RGATreeSplitPos {
    method normalizePos (line 524) | public normalizePos(pos: RGATreeSplitPos): RGATreeSplitPos {
    method getDataSize (line 531) | public getDataSize(): DataSize {
    method toJSON (line 552) | public toJSON(): string {
    method toSortedJSON (line 567) | public toSortedJSON(): string {
    method toJSForTest (line 574) | public toJSForTest(): Devtools.JSONElement {
    method toString (line 585) | public toString(): string {
    method values (line 592) | public values(): Array<TextValueType<A>> {
    method getRGATreeSplit (line 611) | public getRGATreeSplit(): RGATreeSplit<CRDTTextValue> {
    method toTestString (line 619) | public toTestString(): string {
    method deepcopy (line 626) | public deepcopy(): CRDTText<A> {
    method findIndexesFromRange (line 639) | public findIndexesFromRange(range: RGATreeSplitPosRange): [number, num...
    method posToIndex (line 646) | public posToIndex(
    method getGCPairs (line 656) | public getGCPairs(): Array<GCPair> {

FILE: packages/sdk/src/document/crdt/tree.ts
  type TreeNode (line 53) | type TreeNode = TextNode | ElementNode;
  type ElementNode (line 58) | type ElementNode<A extends Indexable = Indexable> = {
  type TextNode (line 67) | type TextNode = {
  type TreeNodeForTest (line 76) | type TreeNodeForTest = TreeNode & {
  type TreeChangeType (line 85) | enum TreeChangeType {
  type TreeChange (line 94) | type TreeChange =
  class CRDTTreePos (line 132) | class CRDTTreePos {
    method constructor (line 136) | constructor(parentID: CRDTTreeNodeID, leftSiblingID: CRDTTreeNodeID) {
    method of (line 144) | public static of(parentID: CRDTTreeNodeID, leftSiblingID: CRDTTreeNode...
    method fromTreePos (line 151) | public static fromTreePos(pos: TreePos<CRDTTreeNode>): CRDTTreePos {
    method getParentID (line 181) | public getParentID() {
    method fromStruct (line 188) | public static fromStruct(struct: CRDTTreePosStruct): CRDTTreePos {
    method toStruct (line 204) | public toStruct(): CRDTTreePosStruct {
    method toTreeNodePair (line 223) | public toTreeNodePair(tree: CRDTTree): TreeNodePair {
    method getLeftSiblingID (line 255) | public getLeftSiblingID() {
    method equals (line 262) | public equals(other: CRDTTreePos): boolean {
  class CRDTTreeNodeID (line 285) | class CRDTTreeNodeID {
    method constructor (line 297) | constructor(createdAt: TimeTicket, offset: number) {
    method of (line 305) | public static of(createdAt: TimeTicket, offset: number): CRDTTreeNodeID {
    method fromStruct (line 312) | public static fromStruct(struct: CRDTTreeNodeIDStruct): CRDTTreeNodeID {
    method createComparator (line 322) | public static createComparator(): Comparator<CRDTTreeNodeID> {
    method getCreatedAt (line 340) | public getCreatedAt(): TimeTicket {
    method equals (line 347) | public equals(other: CRDTTreeNodeID): boolean {
    method getOffset (line 357) | public getOffset(): number {
    method setOffset (line 364) | public setOffset(offset: number): void {
    method toStruct (line 371) | public toStruct(): CRDTTreeNodeIDStruct {
    method toIDString (line 381) | public toIDString(): string {
    method toTestString (line 389) | public toTestString(): string {
  type CRDTTreePosStruct (line 397) | type CRDTTreePosStruct = {
  type CRDTTreeNodeIDStruct (line 406) | type CRDTTreeNodeIDStruct = {
  type TreePosRange (line 414) | type TreePosRange = [CRDTTreePos, CRDTTreePos];
  type TreeNodePair (line 420) | type TreeNodePair = [CRDTTreeNode, CRDTTreeNode];
  type TreePosStructRange (line 426) | type TreePosStructRange = [CRDTTreePosStruct, CRDTTreePosStruct];
  class CRDTTreeNode (line 432) | class CRDTTreeNode
    method constructor (line 478) | constructor(
    method toIDString (line 502) | toIDString(): string {
    method getRemovedAt (line 509) | getRemovedAt(): TimeTicket | undefined {
    method create (line 516) | static create(
    method deepcopy (line 528) | deepcopy(): CRDTTreeNode {
    method value (line 551) | get value() {
    method value (line 565) | set value(v: string) {
    method isRemoved (line 581) | get isRemoved(): boolean {
    method remove (line 588) | remove(removedAt: TimeTicket): boolean {
    method cloneText (line 608) | cloneText(offset: number): CRDTTreeNode {
    method cloneElement (line 624) | cloneElement(issueTimeTicket: () => TimeTicket): CRDTTreeNode {
    method split (line 637) | public split(
    method getCreatedAt (line 684) | public getCreatedAt(): TimeTicket {
    method getOffset (line 691) | public getOffset(): number {
    method canDelete (line 698) | public canDelete(
    method canStyle (line 723) | public canStyle(
    method setAttrs (line 739) | public setAttrs(
    method purge (line 758) | public purge(node: RHTNode): void {
    method getDataSize (line 767) | public getDataSize(): DataSize {
    method getGCPairs (line 800) | public getGCPairs(): Array<GCPair> {
  function ticketKnown (line 822) | function ticketKnown(
  function toTreeNode (line 836) | function toTreeNode(node: CRDTTreeNode): TreeNode {
  function toXML (line 860) | function toXML(node: CRDTTreeNode): string {
  function toTestTreeNode (line 891) | function toTestTreeNode(node: CRDTTreeNode): TreeNodeForTest {
  class CRDTTree (line 913) | class CRDTTree extends CRDTElement implements GCParent {
    method constructor (line 917) | constructor(root: CRDTTreeNode, createdAt: TimeTicket) {
    method rebuildMergeState (line 944) | private rebuildMergeState(): void {
    method create (line 968) | public static create(root: CRDTTreeNode, ticket: TimeTicket): CRDTTree {
    method findFloorNode (line 975) | public findFloorNode(id: CRDTTreeNodeID): CRDTTreeNode | undefined {
    method advancePastUnknownSplitSiblings (line 989) | private advancePastUnknownSplitSiblings(
    method hasUnknownSplitSibling (line 1041) | private hasUnknownSplitSibling(
    method registerNode (line 1071) | public registerNode(node: CRDTTreeNode): void {
    method findNodesAndSplitText (line 1086) | public findNodesAndSplitText(
    method style (line 1161) | public style(
    method removeStyle (line 1343) | public removeStyle(
    method edit (line 1478) | public edit(
    method editT (line 1845) | public editT(
    method move (line 1874) | public move(
    method pathToTreePos (line 1889) | public pathToTreePos(
    method purge (line 1898) | public purge(node: CRDTTreeNode): void {
    method getGCPairs (line 1922) | public getGCPairs(): Array<GCPair> {
    method findPos (line 1940) | public findPos(index: number, preferText = true): CRDTTreePos {
    method pathToPosRange (line 1948) | public pathToPosRange(path: Array<number>): [CRDTTreePos, CRDTTreePos] {
    method pathToPos (line 1956) | public pathToPos(path: Array<number>): CRDTTreePos {
    method getRoot (line 1964) | public getRoot(): CRDTTreeNode {
    method getSize (line 1971) | public getSize(): number {
    method getNodeSize (line 1978) | public getNodeSize(): number {
    method getIndexTree (line 1985) | public getIndexTree(): IndexTree<CRDTTreeNode> {
    method toXML (line 1992) | public toXML(): string {
    method getDataSize (line 1999) | public getDataSize(): DataSize {
    method toJSON (line 2021) | public toJSON(): string {
    method toJSForTest (line 2028) | public toJSForTest(): Devtools.JSONElement {
    method toJSInfoForTest (line 2039) | public toJSInfoForTest(): Devtools.TreeNodeInfo {
    method getRootTreeNode (line 2098) | public getRootTreeNode(): TreeNode {
    method toTestTreeNode (line 2105) | public toTestTreeNode(): TreeNodeForTest {
    method toSortedJSON (line 2112) | public toSortedJSON(): string {
    method deepcopy (line 2119) | public deepcopy(): CRDTTree {
    method toPath (line 2130) | public toPath(
    method toIndex (line 2146) | public toIndex(
    method indexToPath (line 2162) | public indexToPath(index: number): Array<number> {
    method pathToIndex (line 2169) | public pathToIndex(path: Array<number>): number {
    method indexRangeToPosRange (line 2176) | public indexRangeToPosRange(range: [number, number]): TreePosRange {
    method indexRangeToPosStructRange (line 2187) | public indexRangeToPosStructRange(
    method posRangeToPathRange (line 2202) | public posRangeToPathRange(
    method posRangeToIndexRange (line 2213) | public posRangeToIndexRange(range: TreePosRange): [number, number] {
    method traverseInPosRange (line 2223) | private traverseInPosRange(
    method toTreePos (line 2245) | private toTreePos(
    method makeDeletionChanges (line 2298) | private makeDeletionChanges(
    method findRightToken (line 2364) | private findRightToken([
    method findLeftToken (line 2393) | private findLeftToken([

FILE: packages/sdk/src/document/document.ts
  type DocumentOptions (line 91) | interface DocumentOptions {
  type DocStatus (line 106) | enum DocStatus {
  type DocEventType (line 127) | enum DocEventType {
  type DocEvent (line 195) | type DocEvent<P extends Indexable = Indexable, T = OpInfo> =
  type DocEvents (line 210) | type DocEvents<P extends Indexable = Indexable> = Array<DocEvent<P>>;
  type BaseDocEvent (line 212) | interface BaseDocEvent {
  type StatusChangedEvent (line 219) | interface StatusChangedEvent extends BaseDocEvent {
  type StreamConnectionStatus (line 231) | enum StreamConnectionStatus {
  type ConnectionChangedEvent (line 246) | interface ConnectionChangedEvent extends BaseDocEvent {
  type DocSyncStatus (line 254) | enum DocSyncStatus {
  type SyncStatusChangedEvent (line 269) | interface SyncStatusChangedEvent extends BaseDocEvent {
  type SnapshotEvent (line 278) | interface SnapshotEvent extends BaseDocEvent {
  type ChangeInfo (line 292) | interface ChangeInfo<T = OpInfo> {
  type PresenceEvent (line 303) | type PresenceEvent<P extends Indexable = Indexable> =
  type LocalChangeEvent (line 313) | interface LocalChangeEvent<
  type RemoteChangeEvent (line 327) | interface RemoteChangeEvent<
  type InitializedEvent (line 337) | interface InitializedEvent<P extends Indexable> extends BaseDocEvent {
  type WatchedEvent (line 343) | interface WatchedEvent<P extends Indexable> extends BaseDocEvent {
  type UnwatchedEvent (line 349) | interface UnwatchedEvent<P extends Indexable> extends BaseDocEvent {
  type PresenceChangedEvent (line 355) | interface PresenceChangedEvent<
  type AuthErrorEvent (line 363) | interface AuthErrorEvent extends BaseDocEvent {
  type EpochMismatchEvent (line 371) | interface EpochMismatchEvent extends BaseDocEvent {
  type DocEventCallbackMap (line 378) | type DocEventCallbackMap<P extends Indexable> = {
  type DocEventTopic (line 392) | type DocEventTopic = keyof DocEventCallbackMap<never>;
  type DocEventCallback (line 393) | type DocEventCallback<P extends Indexable> =
  type Json (line 400) | type Json = JsonPrimitive | JsonArray | JsonObject;
  type JsonPrimitive (line 403) | type JsonPrimitive = string | number | boolean | null;
  type JsonArray (line 404) | type JsonArray = Array<Json>;
  type JsonObject (line 405) | type JsonObject = { [key: string]: Json | undefined };
  type Indexable (line 412) | type Indexable = Record<string, Json>;
  type LeafElement (line 414) | type LeafElement = PrimitiveValue | Primitive | Text | Counter | Tree;
  type BaseArray (line 415) | type BaseArray<T> = JSONArray<T> | Array<T>;
  type BaseObject (line 416) | type BaseObject<T> = JSONObject<T> | T;
  type OpInfoOfElement (line 421) | type OpInfoOfElement<TElem> = TElem extends Text
  type OpInfoOfInner (line 437) | type OpInfoOfInner<
  type DecreasedDepthOf (line 454) | type DecreasedDepthOf<Depth extends number> = Depth extends 10
  type PathOfInner (line 479) | type PathOfInner<
  type OpInfoOf (line 514) | type OpInfoOf<
  type PathOf (line 525) | type PathOf<TRoot, Depth extends number = 10> = PathOfInner<TRoot, '$.',...
  class Document (line 532) | class Document<
    method constructor (line 561) | constructor(key: string, opts?: DocumentOptions) {
    method update (line 595) | public update(
    method subscribe (line 863) | public subscribe<TPath extends PathOf<R>, TOpInfo extends OpInfoOf<R, ...
    method publish (line 1084) | public publish(events: DocEvents<P>) {
    method applyChangePack (line 1096) | public applyChangePack(pack: ChangePack<P>): void {
    method getCheckpoint (line 1131) | public getCheckpoint(): Checkpoint {
    method getChangeID (line 1138) | public getChangeID(): ChangeID {
    method hasLocalChanges (line 1145) | public hasLocalChanges(): boolean {
    method ensureClone (line 1152) | public ensureClone(): void {
    method createChangePack (line 1167) | public createChangePack(): ChangePack<P> {
    method setActor (line 1183) | public setActor(actorID: ActorID): void {
    method isEnableDevtools (line 1196) | public isEnableDevtools(): boolean {
    method getKey (line 1203) | public getKey(): string {
    method getStatus (line 1210) | public getStatus(): DocStatus {
    method getClone (line 1217) | public getClone() {
    method getCloneRoot (line 1224) | public getCloneRoot(): CRDTObject | undefined {
    method getRoot (line 1235) | public getRoot(): JSONObject<R> {
    method getDocSize (line 1249) | public getDocSize(): DocSize {
    method getMaxSizePerDocument (line 1256) | public getMaxSizePerDocument() {
    method setMaxSizePerDocument (line 1263) | public setMaxSizePerDocument(size: number) {
    method getSchemaRules (line 1270) | public getSchemaRules() {
    method setSchemaRules (line 1277) | public setSchemaRules(rules: Array<Rule>) {
    method garbageCollect (line 1284) | public garbageCollect(minSyncedVersionVector: VersionVector): number {
    method getRootObject (line 1298) | public getRootObject(): CRDTObject {
    method getGarbageLen (line 1305) | public getGarbageLen(): number {
    method getRootCRDT (line 1313) | public getRootCRDT(): CRDTRoot {
    method getGarbageLenFromClone (line 1320) | public getGarbageLenFromClone(): number {
    method toJSON (line 1327) | public toJSON(): string {
    method toSortedJSON (line 1334) | public toSortedJSON(): string {
    method getStats (line 1341) | public getStats(): RootStats {
    method toJSForTest (line 1348) | public toJSForTest(): Devtools.JSONElement {
    method applySnapshot (line 1358) | public applySnapshot(
    method clearHistory (line 1403) | public clearHistory() {
    method applyChanges (line 1411) | public applyChanges(changes: Array<Change<P>>, source: OpSource): void {
    method applyChange (line 1446) | public applyChange(change: Change<P>, source: OpSource) {
    method applyWatchInit (line 1543) | public applyWatchInit(clientIDs: Array<string>) {
    method applyDocEvent (line 1578) | public applyDocEvent(type: PbDocEventType, publisher: string) {
    method applyStatus (line 1606) | public applyStatus(status: DocStatus) {
    method applyDocEventsForReplay (line 1642) | public applyDocEventsForReplay(events: Array<Devtools.DocEventForRepla...
    method getValueByPath (line 1700) | public getValueByPath(path: string): JSONElement | undefined {
    method setOnlineClients (line 1720) | public setOnlineClients(onlineClients: Set<ActorID>) {
    method resetOnlineClients (line 1727) | public resetOnlineClients() {
    method addOnlineClient (line 1734) | public addOnlineClient(clientID: ActorID) {
    method removeOnlineClient (line 1741) | public removeOnlineClient(clientID: ActorID) {
    method reconcilePresence (line 1758) | private reconcilePresence(
    method hasPresence (line 1813) | public hasPresence(clientID: ActorID): boolean {
    method getMyPresence (line 1820) | public getMyPresence(): P {
    method getOthersPresences (line 1834) | public getOthersPresences(): Array<{ clientID: ActorID; presence: P }> {
    method getPresence (line 1853) | public getPresence(clientID: ActorID): P | undefined {
    method getPresences (line 1866) | public getPresences(): Array<{ clientID: ActorID; presence: P }> {
    method getPresenceForTest (line 1888) | public getPresenceForTest(clientID: ActorID): P | undefined {
    method getSelfForTest (line 1896) | public getSelfForTest() {
    method getOthersForTest (line 1906) | public getOthersForTest() {
    method getUndoStackForTest (line 1917) | public getUndoStackForTest(): Array<Array<HistoryOperation<P>>> {
    method getRedoStackForTest (line 1924) | public getRedoStackForTest(): Array<Array<HistoryOperation<P>>> {
    method getVersionVector (line 1931) | public getVersionVector() {
    method isSameElementOrChildOf (line 1935) | private isSameElementOrChildOf(elem: string, parent: string): boolean {
    method removePushedLocalChanges (line 1950) | private removePushedLocalChanges(clientSeq: number) {
    method executeUndoRedo (line 1963) | private executeUndoRedo(isUndo: boolean): void {

FILE: packages/sdk/src/document/history.ts
  type HistoryOperation (line 29) | type HistoryOperation<P extends Indexable> =
  class History (line 44) | class History<P extends Indexable> {
    method hasUndo (line 51) | public hasUndo(): boolean {
    method hasRedo (line 58) | public hasRedo(): boolean {
    method pushUndo (line 65) | public pushUndo(undoOps: Array<HistoryOperation<P>>): void {
    method popUndo (line 75) | public popUndo(): Array<HistoryOperation<P>> | undefined {
    method pushRedo (line 82) | public pushRedo(redoOps: Array<HistoryOperation<P>>): void {
    method popRedo (line 92) | public popRedo(): Array<HistoryOperation<P>> | undefined {
    method clearRedo (line 99) | public clearRedo(): void {
    method clearUndo (line 106) | public clearUndo(): void {
    method getUndoStackForTest (line 113) | public getUndoStackForTest(): Array<Array<HistoryOperation<P>>> {
    method getRedoStackForTest (line 120) | public getRedoStackForTest(): Array<Array<HistoryOperation<P>>> {
    method reconcileCreatedAt (line 134) | public reconcileCreatedAt(
    method reconcileTextEdit (line 168) | public reconcileTextEdit(
    method reconcileTreeEdit (line 196) | public reconcileTreeEdit(

FILE: packages/sdk/src/document/json/array.ts
  type JSONArray (line 41) | type JSONArray<T> = {
  function createJSONArray (line 137) | function createJSONArray(
  function isNumericString (line 148) | function isNumericString(val: any): boolean {
  function isReadOnlyArrayMethod (line 158) | function isReadOnlyArrayMethod(method: string): boolean {
  class ArrayProxy (line 183) | class ArrayProxy {
    method constructor (line 188) | constructor(context: ChangeContext, array: CRDTArray) {
    method iteratorInternal (line 412) | public static *iteratorInternal(
    method wrappedIteratorInternal (line 422) | public static *wrappedIteratorInternal(
    method buildArrayElements (line 434) | public static buildArrayElements(
    method pushInternal (line 450) | public static pushInternal(
    method moveBeforeInternal (line 468) | public static moveBeforeInternal(
    method moveAfterInternal (line 498) | public static moveAfterInternal(
    method moveAfterByIndexInternal (line 535) | public static moveAfterByIndexInternal(
    method moveFrontInternal (line 569) | public static moveFrontInternal(
    method moveLastInternal (line 597) | public static moveLastInternal(
    method insertAfterInternal (line 620) | public static insertAfterInternal(
    method insertIntegerAfterInternal (line 644) | public static insertIntegerAfterInternal(
    method insertBeforeInternal (line 672) | public static insertBeforeInternal(
    method setValueInternal (line 689) | public static setValueInternal(
    method setByIndexInternal (line 710) | public static setByIndexInternal(
    method deleteInternalByIndex (line 739) | public static deleteInternalByIndex(
    method deleteInternalByID (line 764) | public static deleteInternalByID(
    method splice (line 785) | public static splice(
    method includes (line 839) | public static includes(
    method indexOf (line 875) | public static indexOf(
    method lastIndexOf (line 911) | public static lastIndexOf(
    method toTestString (line 947) | public static toTestString(target: CRDTArray): string {
    method getHandlers (line 954) | public getHandlers(): any {

FILE: packages/sdk/src/document/json/counter.ts
  class BaseCounter (line 32) | class BaseCounter {
    method constructor (line 38) | constructor(valueType: CounterType, value: number | bigint) {
    method initialize (line 46) | public initialize(context: ChangeContext, counter: CRDTCounter): void {
    method getID (line 56) | public getID(): TimeTicket {
    method getValueType (line 63) | public getValueType(): CounterType {
    method toJSForTest (line 70) | public toJSForTest(): Devtools.JSONElement {
    method ensureInitialized (line 84) | protected ensureInitialized(): void {
  class Counter (line 104) | class Counter extends BaseCounter {
    method constructor (line 105) | constructor(value: number | bigint) {
    method getValue (line 113) | public getValue(): number | bigint {
    method increase (line 120) | public increase(v: number | bigint): Counter {
  class DedupCounter (line 152) | class DedupCounter extends BaseCounter {
    method constructor (line 153) | constructor() {
    method getValue (line 161) | public getValue(): number {
    method add (line 169) | public add(actor: string): DedupCounter {
  function isCounter (line 195) | function isCounter(value: unknown): value is Counter | DedupCounter {

FILE: packages/sdk/src/document/json/element.ts
  function createJSON (line 53) | function createJSON<T>(
  type WrappedElement (line 63) | type WrappedElement<T = unknown, A extends Indexable = Indexable> =
  type JSONElement (line 76) | type JSONElement<T = unknown, A extends Indexable = Indexable> =
  function toWrappedElement (line 88) | function toWrappedElement(
  function toJSONElement (line 123) | function toJSONElement(
  function buildCRDTElement (line 138) | function buildCRDTElement(

FILE: packages/sdk/src/document/json/object.ts
  type JSONObject (line 35) | type JSONObject<T> = {
  function createJSONObject (line 60) | function createJSONObject<T>(
  class ObjectProxy (line 71) | class ObjectProxy {
    method constructor (line 75) | constructor(context: ChangeContext) {
    method setInternal (line 141) | public static setInternal(
    method buildObjectMembers (line 177) | public static buildObjectMembers(
    method deleteInternal (line 200) | public static deleteInternal(
    method getHandlers (line 224) | public getHandlers(): any {

FILE: packages/sdk/src/document/json/strings.ts
  function escapeString (line 4) | function escapeString(str: string): string {

FILE: packages/sdk/src/document/json/text.ts
  type TextPosStruct (line 47) | type TextPosStruct = {
  type TextPosStructRange (line 56) | type TextPosStructRange = [TextPosStruct, TextPosStruct];
  class Text (line 61) | class Text<A extends Indexable = Indexable> {
    method constructor (line 65) | constructor(context?: ChangeContext, text?: CRDTText<A>) {
    method initialize (line 73) | public initialize(context: ChangeContext, text: CRDTText<A>): void {
    method getID (line 81) | public getID(): TimeTicket {
    method edit (line 88) | edit(
    method delete (line 146) | delete(fromIdx: number, toIdx: number): [number, number] | undefined {
    method empty (line 153) | empty(): [number, number] | undefined {
    method setStyle (line 160) | setStyle(fromIdx: number, toIdx: number, attributes: A): boolean {
    method indexRangeToPosRange (line 210) | indexRangeToPosRange(range: [number, number]): TextPosStructRange {
    method posRangeToIndexRange (line 225) | posRangeToIndexRange(range: TextPosStructRange): [number, number] {
    method toTestString (line 244) | toTestString(): string {
    method values (line 258) | values(): Array<TextValueType<A>> {
    method length (line 272) | public get length(): number {
    method getTreeByIndex (line 279) | public getTreeByIndex(): SplayTree<CRDTTextValue> {
    method getTreeByID (line 286) | public getTreeByID(): LLRBTree<
    method toString (line 296) | toString(): string {
    method toJSON (line 310) | public toJSON(): string {
    method toJSForTest (line 324) | public toJSForTest(): Devtools.JSONElement {
    method createRangeForTest (line 339) | createRangeForTest(fromIdx: number, toIdx: number): RGATreeSplitPosRan...

FILE: packages/sdk/src/document/json/tree.ts
  function toTreeNode (line 70) | function toTreeNode(node: CRDTTreeNode): TreeNode {
  function createSplitNode (line 92) | function createSplitNode(
  function separateSplit (line 122) | function separateSplit(
  function separateMerge (line 157) | function separateMerge(
  function buildDescendants (line 199) | function buildDescendants(
  function createCRDTTreeNode (line 248) | function createCRDTTreeNode(context: ChangeContext, content: TreeNode) {
  function validateTextNode (line 288) | function validateTextNode(textNode: TextNode): boolean {
  function validateTreeNodes (line 302) | function validateTreeNodes(treeNodes: Array<TreeNode>): boolean {
  class Tree (line 338) | class Tree {
    method constructor (line 343) | constructor(initialRoot?: ElementNode) {
    method initialize (line 350) | public initialize(context: ChangeContext, tree: CRDTTree): void {
    method getID (line 358) | public getID(): TimeTicket {
    method buildRoot (line 366) | public buildRoot(context: ChangeContext): CRDTTreeNode {
    method getSize (line 390) | public getSize(): number {
    method getNodeSize (line 404) | public getNodeSize(): number {
    method getIndexTree (line 418) | public getIndexTree(): IndexTree<CRDTTreeNode> {
    method splitByPath (line 432) | public splitByPath(path: Array<number>) {
    method mergeByPath (line 462) | public mergeByPath(path: Array<number>) {
    method styleByPath (line 519) | public styleByPath(
    method style (line 596) | public style(
    method removeStyle (line 642) | public removeStyle(
    method removeStyleByPath (line 692) | public removeStyleByPath(
    method editInternal (line 744) | private editInternal(
    method editByPath (line 815) | public editByPath(
    method editBulkByPath (line 854) | public editBulkByPath(
    method edit (line 888) | public edit(
    method editBulk (line 921) | public editBulk(
    method toXML (line 949) | public toXML(): string {
    method toJSON (line 963) | public toJSON(): string {
    method toJSForTest (line 977) | public toJSForTest(): Devtools.JSONElement {
    method toJSInfoForTest (line 991) | public toJSInfoForTest(): Devtools.TreeNodeInfo {
    method getRootTreeNode (line 1005) | public getRootTreeNode() {
    method indexToPath (line 1019) | public indexToPath(index: number): Array<number> {
    method pathToIndex (line 1033) | public pathToIndex(path: Array<number>): number {
    method pathRangeToPosRange (line 1047) | pathRangeToPosRange(
    method indexRangeToPosRange (line 1068) | indexRangeToPosRange(range: [number, number]): TreePosStructRange {
    method posRangeToIndexRange (line 1082) | posRangeToIndexRange(range: TreePosStructRange): [number, number] {
    method posRangeToPathRange (line 1101) | posRangeToPathRange(

FILE: packages/sdk/src/document/operation/add_operation.ts
  class AddOperation (line 31) | class AddOperation extends Operation {
    method constructor (line 35) | constructor(
    method create (line 49) | public static create(
    method execute (line 61) | public execute(root: CRDTRoot): ExecutionResult {
    method toReverseOperation (line 92) | private toReverseOperation(): Operation {
    method getEffectedCreatedAt (line 105) | public getEffectedCreatedAt(): TimeTicket {
    method toTestString (line 112) | public toTestString(): string {
    method getPrevCreatedAt (line 119) | public getPrevCreatedAt(): TimeTicket {
    method getValue (line 126) | public getValue(): CRDTElement {
    method setPrevCreatedAt (line 133) | public setPrevCreatedAt(createdAt: TimeTicket) {

FILE: packages/sdk/src/document/operation/array_set_operation.ts
  class ArraySetOperation (line 30) | class ArraySetOperation extends Operation {
    method constructor (line 34) | constructor(
    method create (line 48) | public static create(
    method execute (line 60) | public execute(root: CRDTRoot): ExecutionResult {
    method toReverseOperation (line 100) | private toReverseOperation(
    method getEffectedCreatedAt (line 116) | public getEffectedCreatedAt(): TimeTicket {
    method toTestString (line 123) | public toTestString(): string {
    method getCreatedAt (line 130) | public getCreatedAt(): TimeTicket {
    method getValue (line 137) | public getValue(): CRDTElement {
    method setCreatedAt (line 144) | public setCreatedAt(createdAt: TimeTicket) {

FILE: packages/sdk/src/document/operation/edit_operation.ts
  class EditOperation (line 35) | class EditOperation extends Operation {
    method constructor (line 42) | constructor(
    method create (line 62) | public static create(
    method execute (line 85) | public execute<A extends Indexable>(
    method toReverseOperation (line 143) | private toReverseOperation(
    method normalizePos (line 176) | public normalizePos<A extends Indexable>(root: CRDTRoot): [number, num...
    method reconcileOperation (line 213) | public reconcileOperation(
    method getEffectedCreatedAt (line 295) | public getEffectedCreatedAt(): TimeTicket {
    method toTestString (line 302) | public toTestString(): string {
    method getFromPos (line 313) | public getFromPos(): RGATreeSplitPos {
    method getToPos (line 320) | public getToPos(): RGATreeSplitPos {
    method getContent (line 327) | public getContent(): string {
    method getAttributes (line 334) | public getAttributes(): Map<string, string> {

FILE: packages/sdk/src/document/operation/increase_operation.ts
  class IncreaseOperation (line 35) | class IncreaseOperation extends Operation {
    method constructor (line 39) | constructor(
    method create (line 53) | public static create(
    method getActor (line 65) | public getActor(): string {
    method execute (line 72) | public execute(root: CRDTRoot): ExecutionResult {
    method toReverseOperation (line 116) | private toReverseOperation(): Operation {
    method getEffectedCreatedAt (line 135) | public getEffectedCreatedAt(): TimeTicket {
    method toTestString (line 142) | public toTestString(): string {
    method getValue (line 149) | public getValue(): CRDTElement {

FILE: packages/sdk/src/document/operation/move_operation.ts
  class MoveOperation (line 30) | class MoveOperation extends Operation {
    method constructor (line 34) | constructor(
    method create (line 48) | public static create(
    method execute (line 65) | public execute(root: CRDTRoot): ExecutionResult {
    method toReverseOperation (line 110) | private toReverseOperation(array: CRDTArray): Operation {
    method getEffectedCreatedAt (line 125) | public getEffectedCreatedAt(): TimeTicket {
    method toTestString (line 132) | public toTestString(): string {
    method getPrevCreatedAt (line 140) | public getPrevCreatedAt(): TimeTicket {
    method getCreatedAt (line 147) | public getCreatedAt(): TimeTicket {
    method setPrevCreatedAt (line 155) | public setPrevCreatedAt(createdAt: TimeTicket) {
    method setCreatedAt (line 162) | public setCreatedAt(createdAt: TimeTicket) {

FILE: packages/sdk/src/document/operation/operation.ts
  type OpSource (line 30) | enum OpSource {
  type OpInfo (line 40) | type OpInfo =
  type TextOpInfo (line 50) | type TextOpInfo = EditOpInfo | StyleOpInfo;
  type CounterOpInfo (line 55) | type CounterOpInfo = IncreaseOpInfo;
  type ArrayOpInfo (line 60) | type ArrayOpInfo =
  type ObjectOpInfo (line 69) | type ObjectOpInfo = SetOpInfo | RemoveOpInfo;
  type TreeOpInfo (line 74) | type TreeOpInfo = TreeEditOpInfo | TreeStyleOpInfo;
  type AddOpInfo (line 79) | type AddOpInfo = {
  type MoveOpInfo (line 88) | type MoveOpInfo = {
  type SetOpInfo (line 98) | type SetOpInfo = {
  type ArraySetOpInfo (line 107) | type ArraySetOpInfo = {
  type RemoveOpInfo (line 115) | type RemoveOpInfo = {
  type IncreaseOpInfo (line 125) | type IncreaseOpInfo = {
  type EditOpInfo (line 134) | type EditOpInfo = {
  type StyleOpInfo (line 148) | type StyleOpInfo = {
  type TreeEditOpInfo (line 161) | type TreeEditOpInfo = {
  type TreeStyleOpInfo (line 175) | type TreeStyleOpInfo = {
  type ExecutionResult (line 191) | type ExecutionResult = {
  method constructor (line 206) | constructor(parentCreatedAt: TimeTicket, executedAt?: TimeTicket) {
  method getParentCreatedAt (line 215) | public getParentCreatedAt(): TimeTicket {
  method getExecutedAt (line 222) | public getExecutedAt(): TimeTicket {
  method setActor (line 235) | public setActor(actorID: ActorID): void {
  method setExecutedAt (line 244) | public setExecutedAt(executedAt: TimeTicket): void {

FILE: packages/sdk/src/document/operation/remove_operation.ts
  class RemoveOperation (line 38) | class RemoveOperation extends Operation {
    method constructor (line 41) | constructor(
    method create (line 53) | public static create(
    method execute (line 64) | public execute(
    method toReverseOperation (line 125) | private toReverseOperation(
    method getEffectedCreatedAt (line 160) | public getEffectedCreatedAt(): TimeTicket {
    method toTestString (line 167) | public toTestString(): string {
    method getCreatedAt (line 174) | public getCreatedAt(): TimeTicket {
    method setCreatedAt (line 181) | public setCreatedAt(createdAt: TimeTicket) {

FILE: packages/sdk/src/document/operation/set_operation.ts
  class SetOperation (line 33) | class SetOperation extends Operation {
    method constructor (line 37) | constructor(
    method create (line 51) | public static create(
    method execute (line 63) | public execute(
    method toReverseOperation (line 128) | private toReverseOperation(value: CRDTElement | undefined): Operation {
    method getEffectedCreatedAt (line 147) | public getEffectedCreatedAt(): TimeTicket {
    method toTestString (line 154) | public toTestString(): string {
    method getKey (line 163) | public getKey(): string {
    method getValue (line 170) | public getValue(): CRDTElement {

FILE: packages/sdk/src/document/operation/style_operation.ts
  class StyleOperation (line 35) | class StyleOperation extends Operation {
    method constructor (line 41) | constructor(
    method create (line 59) | public static create(
    method createRemoveStyleOperation (line 79) | public static createRemoveStyleOperation(
    method execute (line 99) | public execute<A extends Indexable>(
    method getEffectedCreatedAt (line 221) | public getEffectedCreatedAt(): TimeTicket {
    method toTestString (line 228) | public toTestString(): string {
    method getFromPos (line 239) | public getFromPos(): RGATreeSplitPos {
    method getToPos (line 246) | public getToPos(): RGATreeSplitPos {
    method getAttributes (line 253) | public getAttributes(): Map<string, string> {
    method getAttributesToRemove (line 260) | public getAttributesToRemove(): Array<string> {

FILE: packages/sdk/src/document/operation/tree_edit_operation.ts
  function cloneAndDropPreTombstoned (line 45) | function cloneAndDropPreTombstoned(
  function filterChildren (line 77) | function filterChildren(node: CRDTTreeNode, preTombstoned: Set<string>):...
  class TreeEditOperation (line 95) | class TreeEditOperation extends Operation {
    method constructor (line 113) | constructor(
    method create (line 137) | public static create(
    method execute (line 164) | public execute(
    method toReverseOperation (line 300) | private toReverseOperation(
    method toSplitReverseOperation (line 422) | private toSplitReverseOperation(
    method normalizePos (line 461) | public normalizePos(): [number, number] {
    method reconcileOperation (line 483) | public reconcileOperation(
    method getContentSize (line 568) | public getContentSize(): number {
    method getEffectedCreatedAt (line 576) | public getEffectedCreatedAt(): TimeTicket {
    method toTestString (line 583) | public toTestString(): string {
    method getFromPos (line 602) | public getFromPos(): CRDTTreePos {
    method getToPos (line 609) | public getToPos(): CRDTTreePos {
    method getContents (line 616) | public getContents(): Array<CRDTTreeNode> | undefined {
    method getSplitLevel (line 623) | public getSplitLevel(): number {

FILE: packages/sdk/src/document/operation/tree_style_operation.ts
  class TreeStyleOperation (line 38) | class TreeStyleOperation extends Operation {
    method constructor (line 44) | constructor(
    method create (line 62) | public static create(
    method createTreeRemoveStyleOperation (line 82) | public static createTreeRemoveStyleOperation(
    method execute (line 102) | public execute(
    method getEffectedCreatedAt (line 216) | public getEffectedCreatedAt(): TimeTicket {
    method toTestString (line 223) | public toTestString(): string {
    method getFromPos (line 244) | public getFromPos(): CRDTTreePos {
    method getToPos (line 251) | public getToPos(): CRDTTreePos {
    method getAttributes (line 258) | public getAttributes(): Map<string, string> {
    method getAttributesToRemove (line 265) | public getAttributesToRemove(): Array<string> {

FILE: packages/sdk/src/document/presence/change.ts
  type PresenceChangeType (line 22) | enum PresenceChangeType {
  type PresenceChange (line 30) | type PresenceChange<P extends Indexable> =

FILE: packages/sdk/src/document/presence/presence.ts
  class Channel (line 24) | class Channel<P extends Indexable> {
    method constructor (line 28) | constructor(changeContext: ChangeContext, presence: P) {
    method set (line 36) | public set(presence: Partial<P>, option?: { addToHistory: boolean }) {
    method get (line 52) | public get<K extends keyof P>(key: K): P[K] {
    method clear (line 59) | public clear() {

FILE: packages/sdk/src/document/schema/content-expression.ts
  type ContentExpr (line 27) | interface ContentExpr {
  type Token (line 35) | type Token = {
  function tokenize (line 43) | function tokenize(expr: string): Array<Token> {
  function parseAlternatives (line 90) | function parseAlternatives(
  function parseSequence (line 110) | function parseSequence(
  function parseElement (line 133) | function parseElement(
  function parseAtom (line 158) | function parseAtom(
  function parseContentExpression (line 192) | function parseContentExpression(expr: string): ContentExpr {
  function matchExpr (line 213) | function matchExpr(
  function matchContentExpression (line 287) | function matchContentExpression(

FILE: packages/sdk/src/document/schema/ruleset_validator.ts
  type ValidationResult (line 29) | type ValidationResult = {
  type ValidationError (line 34) | type ValidationError = {
  function validateYorkieRuleset (line 42) | function validateYorkieRuleset(
  function getValueByPath (line 66) | function getValueByPath(obj: any, path: string): any {
  function validateValue (line 88) | function validateValue(value: any, rule: Rule): ValidationResult {
  function getPrimitiveType (line 189) | function getPrimitiveType(type: string): PrimitiveType {
  function validatePrimitiveValue (line 215) | function validatePrimitiveValue(

FILE: packages/sdk/src/document/schema/tree-validator.ts
  type TreeNodeRuleInput (line 27) | type TreeNodeRuleInput = {
  type TreeValidationResult (line 37) | type TreeValidationResult = {
  function buildGroupResolver (line 48) | function buildGroupResolver(
  function validateTreeAgainstSchema (line 80) | function validateTreeAgainstSchema(
  function validateNode (line 98) | function validateNode(
  function validateChildMarks (line 170) | function validateChildMarks(

FILE: packages/sdk/src/document/time/actor_id.ts
  type ActorID (line 21) | type ActorID = string;

FILE: packages/sdk/src/document/time/ticket.ts
  type TimeTicketStruct (line 35) | type TimeTicketStruct = {
  class TimeTicket (line 51) | class TimeTicket {
    method constructor (line 56) | constructor(lamport: bigint, delimiter: number, actorID: string) {
    method of (line 65) | public static of(
    method fromStruct (line 76) | public static fromStruct(struct: TimeTicketStruct): TimeTicket {
    method toIDString (line 87) | public toIDString(): string {
    method toStruct (line 94) | public toStruct(): TimeTicketStruct {
    method toTestString (line 106) | public toTestString(): string {
    method setActor (line 115) | public setActor(actorID: ActorID): TimeTicket {
    method getLamportAsString (line 122) | public getLamportAsString(): string {
    method getLamport (line 129) | public getLamport(): bigint {
    method getDelimiter (line 136) | public getDelimiter(): number {
    method getActorID (line 143) | public getActorID(): string {
    method after (line 150) | public after(other: TimeTicket): boolean {
    method equals (line 157) | public equals(other: TimeTicket): boolean {
    method compare (line 166) | public compare(other: TimeTicket): number {

FILE: packages/sdk/src/document/time/version_vector.ts
  class VersionVector (line 25) | class VersionVector {
    method constructor (line 28) | constructor(vector?: Map<string, bigint>) {
    method set (line 35) | public set(actorID: string, lamport: bigint): void {
    method unset (line 42) | public unset(actorID: string): void {
    method get (line 49) | public get(actorID: string): bigint | undefined {
    method has (line 56) | public has(actorID: string): boolean {
    method maxLamport (line 63) | public maxLamport() {
    method max (line 78) | public max(other: VersionVector): VersionVector {
    method afterOrEqual (line 109) | public afterOrEqual(other: TimeTicket) {
    method deepcopy (line 122) | public deepcopy(): VersionVector {
    method filter (line 133) | public filter(versionVector: VersionVector) {
    method size (line 150) | public size(): number {
  method [Symbol.iterator] (line 155) | public *[Symbol.iterator](): IterableIterator<[string, bigint]> {

FILE: packages/sdk/src/document/yson/parser.ts
  function parse (line 54) | function parse<T = YSONValue>(yson: string): T {
  function preprocessYSON (line 85) | function preprocessYSON(yson: string): string {
  function postprocessValue (line 148) | function postprocessValue(value: any): YSONValue {
  function postprocessTextNode (line 261) | function postprocessTextNode(node: any): YSONTextNode {
  function postprocessTreeNode (line 282) | function postprocessTreeNode(node: any): YSONTreeNode {
  function textToString (line 325) | function textToString(text: YSONText): string {
  function treeToXML (line 335) | function treeToXML(tree: YSONTree): string {
  function treeNodeToXML (line 342) | function treeNodeToXML(node: YSONTreeNode): string {
  function escapeXML (line 368) | function escapeXML(str: string): string {

FILE: packages/sdk/src/document/yson/types.ts
  type YSONTextNode (line 25) | interface YSONTextNode {
  type YSONText (line 51) | interface YSONText {
  type YSONTreeNode (line 62) | interface YSONTreeNode {
  type YSONTree (line 100) | interface YSONTree {
  type YSONInt (line 113) | interface YSONInt {
  type YSONLong (line 126) | interface YSONLong {
  type YSONDate (line 139) | interface YSONDate {
  type YSONBinData (line 152) | interface YSONBinData {
  type YSONCounter (line 165) | interface YSONCounter {
  type YSONDedupCounter (line 179) | interface YSONDedupCounter {
  type YSONValue (line 194) | type YSONValue =
  function isText (line 214) | function isText(value: any): value is YSONText {
  function isTree (line 226) | function isTree(value: any): value is YSONTree {
  function isInt (line 238) | function isInt(value: any): value is YSONInt {
  function isLong (line 250) | function isLong(value: any): value is YSONLong {
  function isDate (line 262) | function isDate(value: any): value is YSONDate {
  function isBinData (line 274) | function isBinData(value: any): value is YSONBinData {
  function isCounter (line 286) | function isCounter(value: any): value is YSONCounter {
  function isDedupCounter (line 298) | function isDedupCounter(value: any): value is YSONDedupCounter {
  function isObject (line 311) | function isObject(value: any): value is { [key: string]: YSONValue } {

FILE: packages/sdk/src/util/comparator.ts
  type Comparator (line 17) | type Comparator<K> = (keyA: K, keyB: K) => number;

FILE: packages/sdk/src/util/error.ts
  type Code (line 17) | enum Code {
  class YorkieError (line 94) | class YorkieError extends Error {
    method constructor (line 98) | constructor(

FILE: packages/sdk/src/util/index_tree.ts
  type TreeNodeType (line 97) | type TreeNodeType = string;
  function addSizeOfLeftSiblings (line 103) | function addSizeOfLeftSiblings<T extends IndexTreeNode<T>>(
  method constructor (line 135) | constructor(type: TreeNodeType, children: Array<T> = []) {
  method updateAncestorsSize (line 151) | updateAncestorsSize(delta: number, includeRemoved: boolean = false): void {
  method updateDescendantsSize (line 176) | updateDescendantsSize(includeRemoved: boolean = false): number {
  method isText (line 199) | get isText(): boolean {
  method paddedSize (line 209) | paddedSize(includeRemoved: boolean = false): number {
  method isAncestorOf (line 223) | isAncestorOf(node: T): boolean {
  method nextSibling (line 230) | get nextSibling(): T | undefined {
  method prevSibling (line 243) | get prevSibling(): T | undefined {
  method splitText (line 287) | splitText(offset: number, absOffset: number): [T | undefined, DataSize] {
  method children (line 323) | get children(): Array<T> {
  method allChildren (line 334) | get allChildren(): Array<T> {
  method hasTextChild (line 341) | hasTextChild(): boolean {
  method getChildrenText (line 350) | getChildrenText(): string {
  method append (line 363) | append(...newNode: Array<T>): void {
  method prepend (line 380) | prepend(...newNode: Array<T>): void {
  method insertBefore (line 394) | insertBefore(newNode: T, referenceNode: T): void {
  method insertAfter (line 412) | insertAfter(newNode: T, referenceNode: T): void {
  method insertAt (line 430) | insertAt(newNode: T, offset: number): void {
  method removeChild (line 444) | removeChild(child: T) {
  method detachChild (line 470) | detachChild(child: T) {
  method splitElement (line 489) | splitElement(
  method insertAfterInternal (line 623) | insertAfterInternal(newNode: T, referenceNode: T): void {
  method insertAtInternal (line 640) | insertAtInternal(newNode: T, offset: number): void {
  method findOffset (line 653) | findOffset(node: T, includeRemoved: boolean = false): number {
  method findBranchOffset (line 681) | findBranchOffset(node: T): number {
  type TreePos (line 707) | type TreePos<T extends IndexTreeNode<T>> = {
  function ancestorOf (line 715) | function ancestorOf<T extends IndexTreeNode<T>>(ancestor: T, node: T): b...
  type TokenType (line 732) | enum TokenType {
  type TreeToken (line 752) | type TreeToken<T> = [T, TokenType];
  function tokensBetween (line 764) | function tokensBetween<T extends IndexTreeNode<T>>(
  function traverse (line 836) | function traverse<T extends IndexTreeNode<T>>(
  function traverseAll (line 850) | function traverseAll<T extends IndexTreeNode<T>>(
  function findTreePos (line 864) | function findTreePos<T extends IndexTreeNode<T>>(
  function getAncestors (line 919) | function getAncestors<T extends IndexTreeNode<T>>(node: T): Array<T> {
  function findCommonAncestor (line 932) | function findCommonAncestor<T extends IndexTreeNode<T>>(
  function findLeftmost (line 961) | function findLeftmost<T extends IndexTreeNode<T>>(node: T): T {
  function findTextPos (line 972) | function findTextPos<T extends IndexTreeNode<T>>(node: T, pathElement: n...
  class IndexTree (line 995) | class IndexTree<T extends IndexTreeNode<T>> {
    method constructor (line 998) | constructor(root: T) {
    method tokensBetween (line 1006) | tokensBetween(
    method traverse (line 1018) | traverse(callback: (node: T) => void): void {
    method traverseAll (line 1025) | traverseAll(callback: (node: T) => void): void {
    method findTreePos (line 1032) | public findTreePos(index: number, preferText = true): TreePos<T> {
    method treePosToPath (line 1039) | public treePosToPath(treePos: TreePos<T>) {
    method pathToIndex (line 1083) | public pathToIndex(path: Array<number>): number {
    method pathToTreePos (line 1092) | public pathToTreePos(path: Array<number>): TreePos<T> {
    method getRoot (line 1124) | public getRoot(): T {
    method size (line 1131) | public get size(): number {
    method findPostorderRight (line 1139) | public findPostorderRight(treePos: TreePos<T>): T | undefined {
    method indexOf (line 1166) | public indexOf(pos: TreePos<T>, includeRemoved: boolean = false): numb...
    method indexToPath (line 1206) | public indexToPath(index: number): Array<number> {

FILE: packages/sdk/src/util/llrb_tree.ts
  type Entry (line 22) | interface Entry<K, V> {
  class LLRBNode (line 30) | class LLRBNode<K, V> {
    method constructor (line 37) | constructor(key: K, value: V, isRed: boolean) {
  class SortedMapIterator (line 47) | class SortedMapIterator<K, V> {
    method constructor (line 50) | constructor(root: LLRBNode<K, V>) {
    method traverseInorder (line 56) | private traverseInorder(node: LLRBNode<K, V>): void {
  class LLRBTree (line 80) | class LLRBTree<K, V> {
    method constructor (line 85) | constructor(comparator?: Comparator<K>) {
    method put (line 94) | public put(key: K, value: V): V {
    method get (line 103) | public get(key: K): V | undefined {
    method remove (line 111) | public remove(key: K): void {
    method getIterator (line 125) | public getIterator(): SortedMapIterator<K, V> {
    method values (line 132) | public values(): Array<V> {
    method floorEntry (line 144) | public floorEntry(key: K): Entry<K, V> | undefined {
    method lastEntry (line 166) | public lastEntry(): Entry<K, V> | undefined {
    method size (line 181) | public size(): number {
    method isEmpty (line 188) | public isEmpty(): boolean {
    method getInternal (line 192) | private getInternal(
    method putInternal (line 210) | private putInternal(key: K, value: V, node?: LLRBNode<K, V>): LLRBNode...
    method removeInternal (line 240) | private removeInternal(
    method min (line 277) | private min(node: LLRBNode<K, V>): LLRBNode<K, V> {
    method removeMin (line 285) | private removeMin(node: LLRBNode<K, V>): LLRBNode<K, V> | undefined {
    method fixUp (line 298) | private fixUp(node: LLRBNode<K, V>): LLRBNode<K, V> {
    method moveRedLeft (line 314) | private moveRedLeft(node: LLRBNode<K, V>): LLRBNode<K, V> {
    method moveRedRight (line 324) | private moveRedRight(node: LLRBNode<K, V>): LLRBNode<K, V> {
    method isRed (line 333) | private isRed(node: LLRBNode<K, V>): boolean {
    method rotateLeft (line 337) | private rotateLeft(node: LLRBNode<K, V>): LLRBNode<K, V> {
    method rotateRight (line 346) | private rotateRight(node: LLRBNode<K, V>): LLRBNode<K, V> {
    method flipColors (line 355) | private flipColors(node: LLRBNode<K, V>): void {

FILE: packages/sdk/src/util/logger.ts
  type LogLevel (line 17) | enum LogLevel {
  function setLogLevel (line 31) | function setLogLevel(l: LogLevel): void {

FILE: packages/sdk/src/util/number.ts
  function bigintToBytesLE (line 26) | function bigintToBytesLE(value: bigint): Uint8Array {
  function bigintFromBytesLE (line 40) | function bigintFromBytesLE(bytes: Uint8Array): bigint {
  function bigintFromBytesLEUnsigned (line 51) | function bigintFromBytesLEUnsigned(bytes: Uint8Array): bigint {
  function bigintToInt32 (line 62) | function bigintToInt32(value: bigint): number {

FILE: packages/sdk/src/util/object.ts
  function deepcopy (line 22) | function deepcopy<T>(object: T): T {

FILE: packages/sdk/src/util/observable.ts
  type NextFn (line 21) | type NextFn<T> = (value: T) => void;
  type ErrorFn (line 23) | type ErrorFn = (error: Error) => void;
  type CompleteFn (line 25) | type CompleteFn = () => void;
  type Observer (line 27) | interface Observer<T> {
  type Unsubscribe (line 33) | type Unsubscribe = () => void;
  type SubscribeFn (line 35) | interface SubscribeFn<T> {
  type ObserverEntry (line 44) | interface ObserverEntry<T> {
  class ObserverProxy (line 56) | class ObserverProxy<T> implements Observer<T> {
    method constructor (line 62) | constructor(executor: Executor<T>) {
    method next (line 73) | public next(value: T): void {
    method error (line 82) | public error(error: Error): void {
    method complete (line 92) | public complete(): void {
    method subscribe (line 102) | public subscribe(
    method unsubscribeOne (line 164) | private unsubscribeOne(id: string): void {
    method forEachObserver (line 168) | private forEachObserver(fn: (observer: Observer<T>) => void): void {
    method sendOne (line 178) | private sendOne(i: number, fn: (observer: Observer<T>) => void): void {
    method close (line 188) | private close(err?: Error): void {
  type Observable (line 202) | interface Observable<T> {
  type Executor (line 207) | type Executor<T> = (observer: Observer<T>) => void;
  function createObservable (line 213) | function createObservable<T>(executor: Executor<T>): Observable<T> {

FILE: packages/sdk/src/util/resource.ts
  type DocSize (line 4) | type DocSize = {
  function totalDocSize (line 19) | function totalDocSize(d: DocSize | undefined): number {
  type DataSize (line 27) | type DataSize = {
  function totalDataSize (line 42) | function totalDataSize(d: DataSize): number {
  function addDataSizes (line 49) | function addDataSizes(
  function subDataSize (line 62) | function subDataSize(target: DataSize, other: DataSize): void {

FILE: packages/sdk/src/util/splay_tree.ts
  method constructor (line 30) | constructor(value: V) {
  method getNodeString (line 40) | public getNodeString(): string {
  method getValue (line 47) | public getValue(): V {
  method getLeftWeight (line 54) | public getLeftWeight(): number {
  method getRightWeight (line 61) | public getRightWeight(): number {
  method getWeight (line 68) | public getWeight(): number {
  method getLeft (line 75) | public getLeft(): SplayNode<V> | undefined {
  method getRight (line 82) | public getRight(): SplayNode<V> | undefined {
  method getParent (line 89) | public getParent(): SplayNode<V> | undefined {
  method hasLeft (line 96) | public hasLeft(): boolean {
  method hasRight (line 103) | public hasRight(): boolean {
  method hasParent (line 110) | public hasParent(): boolean {
  method setLeft (line 117) | public setLeft(left?: SplayNode<V>): void {
  method setRight (line 124) | public setRight(right?: SplayNode<V>): void {
  method setParent (line 131) | public setParent(parent?: SplayNode<V>): void {
  method unlink (line 138) | public unlink(): void {
  method hasLinks (line 147) | public hasLinks(): boolean {
  method increaseWeight (line 154) | public increaseWeight(weight: number): void {
  method initWeight (line 161) | public initWeight(): void {
  class SplayTree (line 171) | class SplayTree<V> {
    method constructor (line 174) | constructor(root?: SplayNode<V>) {
    method length (line 181) | public get length(): number {
    method findForText (line 189) | public findForText(pos: number): [SplayNode<V> | undefined, number] {
    method findForArray (line 223) | public findForArray(idx: number): SplayNode<V> | undefined {
    method indexOf (line 258) | public indexOf(node: SplayNode<V>): number {
    method getRoot (line 270) | public getRoot(): SplayNode<V> {
    method insert (line 277) | public insert(newNode: SplayNode<V>): SplayNode<V> {
    method insertAfter (line 284) | public insertAfter(
    method updateWeight (line 312) | public updateWeight(node: SplayNode<V>): void {
    method updateTreeWeight (line 323) | private updateTreeWeight(node: SplayNode<V>): void {
    method splayNode (line 333) | public splayNode(node: SplayNode<V> | undefined): void {
    method delete (line 377) | public delete(node: SplayNode<V>): void {
    method deleteRange (line 416) | public deleteRange(
    method cutOffRight (line 433) | private cutOffRight(root: SplayNode<V>): void {
    method toTestString (line 446) | public toTestString(): string {
    method checkWeight (line 458) | public checkWeight(): boolean {
    method getRightmost (line 472) | private getRightmost(): SplayNode<V> {
    method traverseInorder (line 480) | private traverseInorder(
    method traversePostorder (line 493) | private traversePostorder(
    method rotateLeft (line 506) | private rotateLeft(pivot: SplayNode<V>): void {
    method rotateRight (line 531) | private rotateRight(pivot: SplayNode<V>): void {
    method isLeftChild (line 556) | private isLeftChild(node?: SplayNode<V>): boolean {
    method isRightChild (line 563) | private isRightChild(node?: SplayNode<V>): boolean {

FILE: packages/sdk/src/util/uuid.ts
  type UUID (line 17) | type UUID = string;
  function uuid (line 23) | function uuid(): UUID {

FILE: packages/sdk/test/bench/splay_tree.bench.ts
  class StringNode (line 5) | class StringNode extends SplayNode<string> {
    method create (line 8) | public static create(value: string): StringNode {
    method getLength (line 12) | public getLength(): number {

FILE: packages/sdk/test/helper/helper.ts
  class EventCollector (line 54) | class EventCollector<E = string> {
    method constructor (line 57) | constructor() {
    method add (line 61) | public add(event: E) {
    method waitAndVerifyNthEvent (line 69) | public waitAndVerifyNthEvent(count: number, event: E) {
    method waitFor (line 99) | public waitFor(event: E) {
    method reset (line 112) | public reset() {
    method getLength (line 116) | public getLength() {
  function deepSort (line 121) | function deepSort(target: any): any {
  function deepEqual (line 139) | function deepEqual(actual: any, expected: any) {
  function compareFunction (line 169) | function compareFunction(a: any, b: any): number {
  function assertThrowsAsync (line 191) | async function assertThrowsAsync(
  class TextView (line 212) | class TextView {
    method constructor (line 215) | constructor() {
    method applyOperations (line 219) | public applyOperations(operations: Array<OpInfo>, enableLog = false): ...
    method toString (line 242) | public toString(): string {
  function buildIndexTree (line 250) | function buildIndexTree(node: ElementNode): IndexTree<CRDTTreeNode> {
  function toStringHistoryOp (line 258) | function toStringHistoryOp<P extends Indexable>(
  function posT (line 281) | function posT(offset = 0): CRDTTreeNodeID {
  function timeT (line 288) | function timeT(): TimeTicket {
  function maxVectorOf (line 295) | function maxVectorOf(actors: Array<string>) {
  function vectorOf (line 312) | function vectorOf(

FILE: packages/sdk/test/integration/array_test.ts
  type TestDoc (line 254) | type TestDoc = { k1: JSONArray<number> };
  type TestDoc (line 299) | type TestDoc = { k1: JSONArray<number> };
  type TestDoc (line 347) | type TestDoc = { k1: JSONArray<number> };
  type TestDoc (line 381) | type TestDoc = { k1: JSONArray<number> };
  type TestDoc (line 425) | type TestDoc = { k1: JSONArray<number> };
  type TestDoc (line 455) | type TestDoc = { k1: JSONArray<number> };
  type TestDoc (line 487) | type TestDoc = { k1: JSONArray<number> };
  type TestDoc (line 533) | type TestDoc = { k1: JSONArray<number> };
  type TestDoc (line 565) | type TestDoc = { k1: Array<string> };
  type TestDoc (line 588) | type TestDoc = { k1: JSONArray<number> };
  type TestDoc (line 620) | type TestDoc = { k1: JSONArray<number> };
  type TestDoc (line 656) | type TestDoc = { k1: JSONArray<number> };
  type TestDoc (line 755) | type TestDoc = { a: JSONArray<number> };
  type ArrayOp (line 763) | interface ArrayOp {
  type TestDoc (line 865) | type TestDoc = { a: JSONArray<number> };
  type ArrayOp (line 873) | interface ArrayOp {
  type TestDoc (line 975) | type TestDoc = { k1: JSONArray<number> };
  type ClientAndDocPair (line 1050) | interface ClientAndDocPair<T extends Indexable> {
  function syncClientsThenCheckEqual (line 1055) | async function syncClientsThenCheckEqual<T extends Indexable>(

FILE: packages/sdk/test/integration/broadcast_test.ts
  function waitForAttached (line 34) | async function waitForAttached(

FILE: packages/sdk/test/integration/channel_test.ts
  function waitFor (line 235) | async function waitFor(

FILE: packages/sdk/test/integration/client_test.ts
  type TestDoc (line 106) | type TestDoc = { k1: string; k2: string; k3: string };
  type TestDoc (line 856) | type TestDoc = { counter: Counter };

FILE: packages/sdk/test/integration/counter_test.ts
  type TestDoc (line 55) | type TestDoc = { age: Counter; length: Counter };
  type TestDoc (line 158) | type TestDoc = { counter: Counter };
  type TestDoc (line 217) | type TestDoc = { counter: Counter };

FILE: packages/sdk/test/integration/doc_presence_test.ts
  type PresenceType (line 33) | type PresenceType = { key: string };
  type PresenceType (line 63) | type PresenceType = { key: string };
  type PresenceType (line 98) | type PresenceType = { key: string };
  type EventForTest (line 124) | type EventForTest = Pick<DocEvent, 'type' | 'value'>;
  type PresenceType (line 206) | type PresenceType = { key: string; cursor: { x: number; y: number } };
  type PresenceType (line 245) | type PresenceType = { name: string; cursor: { x: number; y: number } };
  type EventForTest (line 251) | type EventForTest = Pick<DocEvent, 'type' | 'value'>;
  type PresenceType (line 309) | type PresenceType = { counter: number };
  type EventForTest (line 343) | type EventForTest = Pick<DocEvent, 'type' | 'value'>;
  type PresenceType (line 346) | type PresenceType = { name: string };
  type EventForTest (line 392) | type EventForTest = Pick<DocEvent, 'type' | 'value'>;
  type PresenceType (line 395) | type PresenceType = { name: string; cursor: { x: number; y: number } };
  type PresenceType (line 449) | type PresenceType = { name: string };
  type EventForTest (line 450) | type EventForTest = Pick<DocEvent, 'type' | 'value'>;
  type PresenceType (line 489) | type PresenceType = { name: string; cursor: { x: number; y: number } };
  type EventForTest (line 505) | type EventForTest = Pick<DocEvent, 'type' | 'value'>;
  type TestDoc (line 610) | type TestDoc = { counter: Counter };
  type Presence (line 611) | type Presence = { color: string };
  type Presence (line 668) | type Presence = { color: string; cursor: { x: number; y: number } };
  type Presence (line 788) | type Presence = { color: string };
  type PresenceType (line 869) | type PresenceType = { key: string };

FILE: packages/sdk/test/integration/document_test.ts
  type TestDoc (line 34) | type TestDoc = { k1: { ['k1-1']: string }; k2: Array<string> };
  type TestDoc (line 107) | type TestDoc = {
  type EventForTest (line 123) | type EventForTest = {
  type TestDoc (line 240) | type TestDoc = { counter: Counter; todos: Array<string> };
  type TestDoc (line 323) | type TestDoc = {
  type TestDoc (line 408) | type TestDoc = { k1: Array<number> };
  type TestDoc (line 445) | type TestDoc = { k1: Array<number> };
  type TestDoc (line 500) | type TestDoc = { k1: Array<number> };
  type TestDoc (line 533) | type TestDoc = { k1: Array<number> };
  type TestDoc (line 572) | type TestDoc = { k1: Array<number> };
  type TestDoc (line 606) | type TestDoc = { k1: Array<number> };
  type TestDoc (line 647) | type TestDoc = { k1: Array<number> };
  type TestDoc (line 872) | type TestDoc = { counter: Counter };
  type TestDoc (line 906) | type TestDoc = { counter: Counter };
  type TestDoc (line 942) | type TestDoc = { counter: Counter };
  type TestDoc (line 954) | type TestDoc = { counter: Counter };
  type TestDoc (line 987) | type TestDoc = { counter: Counter };
  type DocType (line 1177) | type DocType = {

FILE: packages/sdk/test/integration/gc_test.ts
  type TestDoc (line 18) | type TestDoc = { point?: { x?: number; y?: number } };
  type TestDoc (line 209) | type TestDoc = { 1: number; 2?: Array<number>; 3: number };
  type TestDoc (line 330) | type TestDoc = { text: Text; textWithAttr: Text };
  type TestDoc (line 454) | type TestDoc = {
  type TestDoc (line 552) | type TestDoc = { point: { x: number; y: number } };
  type TestDoc (line 588) | type TestDoc = { list: Array<number | Array<number>> };
  type TestDoc (line 629) | type TestDoc = { point: { x: number; y: number } };
  type TestDoc (line 729) | type TestDoc = { shape?: { point?: { x?: number; y?: number } } };
  type TestDoc (line 747) | type TestDoc = { t: Text };
  type TestDoc (line 876) | type TestDoc = { t: Tree };
  type TestDoc (line 1032) | type TestDoc = { t: Text };
  type TestDoc (line 1155) | type TestDoc = { t: Text };
  type TestDoc (line 1377) | type TestDoc = { t: Text };
  type TestDoc (line 1453) | type TestDoc = { t: Text };
  type TestDoc (line 1605) | type TestDoc = { t: Text };
  type TestDoc (line 1748) | type TestDoc = { t: Text };
  type TestDoc (line 1907) | type TestDoc = { t: Text };

FILE: packages/sdk/test/integration/history_array_test.ts
  type Op (line 6) | type Op = 'add' | 'move' | 'remove' | 'set';
  function applyOp1 (line 9) | function applyOp1(doc: Document<{ list: JSONArray<string> }>, op: Op) {
  function applyOp2 (line 39) | function applyOp2(doc: Document<{ list: JSONArray<string> }>, op: Op) {
  type TestDoc (line 149) | type TestDoc = { list: JSONArray<string> };

FILE: packages/sdk/test/integration/history_text_test.ts
  type TextOp (line 18) | type TextOp = 'insert' | 'delete' | 'replace' | 'style';
  function applyTextOp1 (line 21) | function applyTextOp1(doc: Document<{ t: Text }>, op: TextOp) {
  function applyTextOp2 (line 46) | function applyTextOp2(doc: Document<{ t: Text }>, op: TextOp) {
  type TestDoc (line 360) | type TestDoc = { t: Text };
  type TestDoc (line 388) | type TestDoc = { t: Text };
  type TestDoc (line 441) | type TestDoc = { t: Text };
  type TestDoc (line 478) | type TestDoc = { t: Text };
  type TestDoc (line 515) | type TestDoc = { t: Text };
  type TestDoc (line 552) | type TestDoc = { t: Text };
  type TestDoc (line 589) | type TestDoc = { t: Text };
  type TestDoc (line 626) | type TestDoc = { t: Text };
  type TestDoc (line 661) | type TestDoc = { t: Text };
  type TestDoc (line 708) | type TestDoc = { t: Text };
  type TestDoc (line 745) | type TestDoc = { t: Text };
  type TestDoc (line 781) | type TestDoc = { t: Text };
  type TestDoc (line 812) | type TestDoc = { t: Text };
  type TestDoc (line 842) | type TestDoc = { t: Text };
  type TestDoc (line 875) | type TestDoc = { t: Text };

FILE: packages/sdk/test/integration/history_tree_split_test.ts
  function topRedoTreeEdit (line 19) | function topRedoTreeEdit(
  function summarizeOp (line 31) | function summarizeOp(op: Operation | undefined): string {
  function initDoc (line 47) | function initDoc(): Document<{ t: Tree }> {
  function insertSiblingBlock (line 62) | function insertSiblingBlock(doc: Document<{ t: Tree }>) {
  function typeInSecondBlock (line 73) | function typeInSecondBlock(doc: Document<{ t: Tree }>, ch: string) {
  type SplitPos (line 200) | type SplitPos = 'front' | 'middle' | 'back';
  type SplitChainOp (line 307) | type SplitChainOp = 'split' | 'insert-text' | 'delete-text';
  type RemoteOp (line 370) | type RemoteOp = 'insert-text' | 'delete-text' | 'insert-element';
  type RemotePos (line 371) | type RemotePos = 'before-split' | 'after-split' | 'different-element';
  type TestDoc (line 452) | type TestDoc = { t: Tree };
  type TestDoc (line 591) | type TestDoc = { t: Tree };
  type SplitPos (line 643) | type SplitPos = 'front' | 'middle' | 'back';
  type SplitChainOp (line 768) | type SplitChainOp = 'split-l2' | 'insert-text' | 'delete-text';
  type RemoteOp (line 844) | type RemoteOp = 'insert-text' | 'delete-text' | 'insert-element';
  type RemotePos (line 845) | type RemotePos = 'before-split' | 'after-split' | 'different-element';
  type TestDoc (line 946) | type TestDoc = { t: Tree };
  type TestDoc (line 1013) | type TestDoc = { t: Tree };
  type TestDoc (line 1084) | type TestDoc = { t: Tree };
  type TestDoc (line 1137) | type TestDoc = { t: Tree };
  type TestDoc (line 1190) | type TestDoc = { t: Tree };

FILE: packages/sdk/test/integration/history_tree_test.ts
  type TreeOp (line 23) | type TreeOp =
  function initTree (line 40) | function initTree(doc: Document<{ t: Tree }>) {
  function applyTreeOp1 (line 57) | function applyTreeOp1(doc: Document<{ t: Tree }>, op: TreeOp) {
  function applyTreeOp2 (line 96) | function applyTreeOp2(doc: Document<{ t: Tree }>, op: TreeOp) {
  type TestDoc (line 379) | type TestDoc = { t: Tree };
  type TestDoc (line 417) | type TestDoc = { t: Tree };
  type TestDoc (line 482) | type TestDoc = { t: Tree };
  type TestDoc (line 529) | type TestDoc = { t: Tree };
  type TestDoc (line 577) | type TestDoc = { t: Tree };
  type TestDoc (line 622) | type TestDoc = { t: Tree };
  type TestDoc (line 670) | type TestDoc = { t: Tree };
  type TestDoc (line 715) | type TestDoc = { t: Tree };
  type TestDoc (line 757) | type TestDoc = { t: Tree };
  type TestDoc (line 807) | type TestDoc = { t: Tree };
  type TestDoc (line 852) | type TestDoc = { t: Tree };
  type TestDoc (line 900) | type TestDoc = { t: Tree };
  type StyleOp (line 954) | type StyleOp = 'set-bold' | 'set-italic' | 'set-color' | 'remove-bold';
  type LocalStyleOp (line 1101) | type LocalStyleOp = 'set-bold' | 'set-italic' | 'remove-bold';
  type RemoteStyleOp (line 1102) | type RemoteStyleOp = 'set-color' | 'set-bold' | 'remove-bold';
  type Target (line 1103) | type Target = 'same-element' | 'different-element';
  type TestDoc (line 1123) | type TestDoc = { t: Tree };
  type LocalStyleOp (line 1204) | type LocalStyleOp = 'set-bold' | 'set-italic' | 'remove-bold';
  type RemoteEditOp (line 1205) | type RemoteEditOp =
  type TestDoc (line 1228) | type TestDoc = { t: Tree };
  type TestDoc (line 1309) | type TestDoc = { t: Tree };
  type DocType (line 1397) | type DocType = { content: Tree };

FILE: packages/sdk/test/integration/integration_helper.ts
  function isYorkieContainerRunning (line 11) | function isYorkieContainerRunning() {
  function toDocKey (line 30) | function toDocKey(title: string): string {
  function withTwoClientsAndDocuments (line 37) | async function withTwoClientsAndDocuments<
  function withTwoClientsAndChannels (line 71) | async function withTwoClientsAndChannels(
  function assertUndoRedo (line 112) | function assertUndoRedo<T, P extends Indexable>(

FILE: packages/sdk/test/integration/object_test.ts
  type DocType (line 117) | type DocType = { content: JSONObject<{ a: number; b: number; c: number }...
  type TestDoc (line 374) | interface TestDoc {
  type TestDoc (line 418) | interface TestDoc {
  type TestDoc (line 468) | interface TestDoc {
  type TestDoc (line 538) | interface TestDoc {
  type TestDoc (line 582) | interface TestDoc {
  type TestDoc (line 643) | interface TestDoc {
  type TestDoc (line 719) | interface TestDoc {
  type TestDoc (line 795) | interface TestDoc {
  type TestDoc (line 851) | interface TestDoc {
  type TestDoc (line 903) | interface TestDoc {
  type TestDoc (line 952) | interface TestDoc {

FILE: packages/sdk/test/integration/presence_test.ts
  function waitForAttached (line 11) | async function waitForAttached(
  function waitForCount (line 31) | async function waitForCount(

FILE: packages/sdk/test/integration/revision_test.ts
  type TestDoc (line 12) | type TestDoc = { k1: string; k2?: string };
  type TestDoc (line 51) | type TestDoc = { count: number };
  type TestDoc (line 81) | type TestDoc = { k1: string; k2?: string; k3?: string };
  type TestDoc (line 133) | type TestDoc = { k1: string; k2?: string };
  type TestDoc (line 176) | type TestDoc = { k1: string; k2?: string };

FILE: packages/sdk/test/integration/snapshot_test.ts
  type TestDoc (line 8) | type TestDoc = Record<string, number> & { key: string };

FILE: packages/sdk/test/integration/text_test.ts
  function getAllNodes (line 846) | function getAllNodes(doc: typeof d1) {
  function getAllNodes (line 902) | function getAllNodes(doc: typeof d1) {
  function getAllNodes (line 965) | function getAllNodes(doc: typeof d1) {
  function getAllNodes (line 1031) | function getAllNodes(doc: typeof d1) {

FILE: packages/sdk/test/integration/tree_concurrency_test.ts
  function parseSimpleXML (line 26) | function parseSimpleXML(s: string): Array<string> {
  type TestResult (line 41) | interface TestResult {
  type RangeSelector (line 46) | enum RangeSelector {
  type RangeType (line 56) | interface RangeType {
  type RangeWithMiddleType (line 61) | interface RangeWithMiddleType {
  type TwoRangesType (line 67) | interface TwoRangesType {
  function getRange (line 72) | function getRange(
  function makeTwoRanges (line 100) | function makeTwoRanges(
  function getMergeRange (line 114) | function getMergeRange(xml: string, interval: RangeType): RangeType {
  type StyleOpCode (line 125) | enum StyleOpCode {
  type EditOpCode (line 131) | enum EditOpCode {
  type OperationInterface (line 138) | interface OperationInterface {
  class StyleOperationType (line 143) | class StyleOperationType implements OperationInterface {
    method constructor (line 144) | constructor(
    method getDesc (line 152) | getDesc(): string {
    method run (line 156) | async run(doc: Document<{ t: Tree }>, user: number, ranges: TwoRangesT...
  class EditOperationType (line 172) | class EditOperationType implements O
Condensed preview — 522 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (8,488K chars).
[
  {
    "path": ".editorconfig",
    "chars": 251,
    "preview": "# EditorConfig is awesome: http://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n# Unix-style newlines with"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.md",
    "chars": 559,
    "preview": "---\nname: Bug Report\nabout: Report a bug encountered while using Yorkie\nlabels: kind/bug\n\n---\n\n<!-- Please use this temp"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/common-issue.md",
    "chars": 178,
    "preview": "---\nname: Common Issue\nabout: A common issue with the Yorkie project\nlabels:\n\n---\n<!-- Please only use this template for"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 28,
    "preview": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 459,
    "preview": "<!--  Thanks for sending a pull request! -->\n\n#### What this PR does / why we need it?\n\n\n#### Any background context you"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1863,
    "preview": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versi"
  },
  {
    "path": ".github/workflows/devtools-publish.yml",
    "chars": 805,
    "preview": "name: Publish Yorkie Devtools Extension\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - 'main'\n    paths:\n      -"
  },
  {
    "path": ".github/workflows/github-page-publish.yml",
    "chars": 1219,
    "preview": "name: Github Page Publish\non:\n  push:\n    branches:\n      - 'main'\n    paths-ignore:\n      - 'test/**'\njobs:\n  build-and"
  },
  {
    "path": ".github/workflows/npm-publish.yml",
    "chars": 1872,
    "preview": "name: npm-publish\non:\n  workflow_dispatch:\n  release:\n    types: [published]\njobs:\n  build:\n    runs-on: ubuntu-latest\n "
  },
  {
    "path": ".gitignore",
    "chars": 2091,
    "preview": "\n# Created by https://www.gitignore.io/api/vim,node\n# Edit at https://www.gitignore.io/?templates=vim,node\n\n### Node ###"
  },
  {
    "path": ".husky/commit-msg",
    "chars": 924,
    "preview": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Strip comment lines (lines starting with #)\nmsg=$(sed '/^#/d' \"$1\")\n\n# Skip emp"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 16,
    "preview": "npx lint-staged\n"
  },
  {
    "path": ".npmrc",
    "chars": 62,
    "preview": "engine-strict=true\n@buf:registry=https://buf.build/gen/npm/v1\n"
  },
  {
    "path": ".nvmrc",
    "chars": 6,
    "preview": "lts/*\n"
  },
  {
    "path": ".prettierignore",
    "chars": 55,
    "preview": "src/api/yorkie_grpc_web_pb.d.ts\nsrc/api/yorkie_pb.d.ts\n"
  },
  {
    "path": ".prettierrc.js",
    "chars": 146,
    "preview": "// eslint-disable-next-line no-undef\nmodule.exports = {\n  bracketSpacing: true,\n  singleQuote: true,\n  trailingComma: 'a"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 59702,
    "preview": "# Changelog\n\nAll notable changes to Yorkie JS SDK will be documented in this file.\n\nThe format is based on [Keep a Chang"
  },
  {
    "path": "CLAUDE.md",
    "chars": 2251,
    "preview": "# Yorkie JavaScript SDK\n\npnpm monorepo with multiple packages for building collaborative editing applications.\n\n## Devel"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 6728,
    "preview": "# Contributing\n\n## How to contribute\n\nYorkie is Apache 2.0 licensed and accepts contributions via GitHub pull requests. "
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "MAINTAINING.md",
    "chars": 2370,
    "preview": "# Maintaining yorkie-js-sdk\n\n## Releasing a New Version Of Yorkie JS SDK\n\n### 1. Update the version number.\n\nUpdate `ver"
  },
  {
    "path": "README.md",
    "chars": 1670,
    "preview": "# Yorkie JavaScript SDK\n\n[![codecov](https://codecov.io/gh/yorkie-team/yorkie-js-sdk/branch/main/graph/badge.svg)](https"
  },
  {
    "path": "codecov.yml",
    "chars": 52,
    "preview": "coverage:\n  status:\n    project: off\n    patch: off\n"
  },
  {
    "path": "docker/docker-compose-ci.yml",
    "chars": 479,
    "preview": "services:\n  yorkie:\n    image: \"yorkieteam/yorkie:latest\"\n    container_name: \"yorkie\"\n    command:\n      [\n        \"ser"
  },
  {
    "path": "docker/docker-compose.yml",
    "chars": 268,
    "preview": "services:\n  yorkie:\n    image: \"yorkieteam/yorkie:latest\"\n    container_name: \"yorkie\"\n    command:\n      [\"server\", \"--"
  },
  {
    "path": "eslint.config.mjs",
    "chars": 2413,
    "preview": "import eslint from '@eslint/js';\nimport tseslint from 'typescript-eslint';\nimport prettierPlugin from 'eslint-plugin-pre"
  },
  {
    "path": "examples/CONTRIBUTING.md",
    "chars": 886,
    "preview": "# Contributing\n\nSee [CONTRIBUTING.md](../CONTRIBUTING.md) for the general guides for contribution.\n\n## Keeping create-yo"
  },
  {
    "path": "examples/README.md",
    "chars": 1928,
    "preview": "# Examples\n\nThis directory contains examples of how to use Yorkie in various libraries and frameworks.\n\n## Usage\n\nAll ex"
  },
  {
    "path": "examples/nextjs-presence/.gitignore",
    "chars": 375,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": "examples/nextjs-presence/README.md",
    "chars": 7470,
    "preview": "# Yorkie Presence Rooms - Next.js Example\n\n<p>\n    <a href=\"https://yorkie.dev/yorkie-js-sdk/examples/nextjs-presence/\" "
  },
  {
    "path": "examples/nextjs-presence/app/App.css",
    "chars": 993,
    "preview": ".app {\n  display: flex;\n  flex-direction: column;\n  min-height: 100vh;\n  background: linear-gradient(135deg, #667eea 0%,"
  },
  {
    "path": "examples/nextjs-presence/app/api/channels/route.ts",
    "chars": 1149,
    "preview": "export async function POST(request: Request) {\n  try {\n    // Check if secret key is available (required for admin API)\n"
  },
  {
    "path": "examples/nextjs-presence/app/globals.css",
    "chars": 352,
    "preview": "* {\n  box-sizing: border-box;\n  margin: 0;\n  padding: 0;\n}\n\nbody {\n  font-family: -apple-system, BlinkMacSystemFont, 'Se"
  },
  {
    "path": "examples/nextjs-presence/app/layout.tsx",
    "chars": 406,
    "preview": "import type { Metadata } from 'next';\nimport './globals.css';\n\nexport const metadata: Metadata = {\n  title: 'Yorkie Pres"
  },
  {
    "path": "examples/nextjs-presence/app/page.tsx",
    "chars": 4033,
    "preview": "'use client';\n\nimport { useEffect, useState } from 'react';\nimport { YorkieProvider } from '@yorkie-js/react';\nimport Ro"
  },
  {
    "path": "examples/nextjs-presence/components/RoomSelector.css",
    "chars": 7142,
    "preview": ".room-selector {\n  max-width: 900px;\n  width: 100%;\n  padding: 2rem;\n  background: white;\n  border-radius: 20px;\n  box-s"
  },
  {
    "path": "examples/nextjs-presence/components/RoomSelector.tsx",
    "chars": 3150,
    "preview": "import { ROOMS, ROOM_CATEGORIES } from '@/lib/rooms';\nimport './RoomSelector.css';\n\ninterface RoomSelectorProps {\n  onRo"
  },
  {
    "path": "examples/nextjs-presence/components/RoomView.css",
    "chars": 2902,
    "preview": ".room-view {\n  max-width: 800px;\n  width: 100%;\n  background: white;\n  border-radius: 20px;\n  box-shadow: 0 20px 60px rg"
  },
  {
    "path": "examples/nextjs-presence/components/RoomView.tsx",
    "chars": 1879,
    "preview": "'use client';\n\nimport { ChannelProvider } from '@yorkie-js/react';\nimport { ROOMS } from '@/lib/rooms';\nimport SessionCo"
  },
  {
    "path": "examples/nextjs-presence/components/SessionCounter.css",
    "chars": 3268,
    "preview": ".session-counter {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  padding: 2rem;\n  background: line"
  },
  {
    "path": "examples/nextjs-presence/components/SessionCounter.tsx",
    "chars": 2381,
    "preview": "'use client';\n\nimport { useChannel, useChannelSessionCount } from '@yorkie-js/react';\nimport { useEffect, useState } fro"
  },
  {
    "path": "examples/nextjs-presence/eslint.config.mjs",
    "chars": 114,
    "preview": "import nextConfig from 'eslint-config-next';\n\nconst eslintConfig = [...nextConfig];\n\nexport default eslintConfig;\n"
  },
  {
    "path": "examples/nextjs-presence/lib/rooms.ts",
    "chars": 1362,
    "preview": "// Room category definition\nexport interface RoomCategory {\n  id: string;\n  name: string;\n  emoji: string;\n  description"
  },
  {
    "path": "examples/nextjs-presence/next.config.ts",
    "chars": 279,
    "preview": "import type { NextConfig } from 'next';\n\nconst nextConfig: NextConfig = {\n  output: 'export',\n  distDir: 'dist',\n  baseP"
  },
  {
    "path": "examples/nextjs-presence/package.json",
    "chars": 578,
    "preview": "{\n  \"name\": \"nextjs-presence\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build"
  },
  {
    "path": "examples/nextjs-presence/tsconfig.json",
    "chars": 896,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n "
  },
  {
    "path": "examples/nextjs-scheduler/.gitignore",
    "chars": 368,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": "examples/nextjs-scheduler/README.md",
    "chars": 2912,
    "preview": "# Yorkie Next.js scheduler Example\n\n<p>\n    <a href=\"https://yorkie.dev/yorkie-js-sdk/examples/nextjs-scheduler/\" target"
  },
  {
    "path": "examples/nextjs-scheduler/app/Scheduler.tsx",
    "chars": 3494,
    "preview": "'use client';\n\nimport React, { useEffect, useMemo, useState } from 'react';\nimport './styles/calendar.css';\nimport style"
  },
  {
    "path": "examples/nextjs-scheduler/app/layout.tsx",
    "chars": 480,
    "preview": "import './styles/globals.css';\nimport type { Metadata } from 'next';\n\nexport const metadata: Metadata = {\n  title: 'Next"
  },
  {
    "path": "examples/nextjs-scheduler/app/not-found.tsx",
    "chars": 97,
    "preview": "/**\n * 404-not found\n */\nexport default function notFound() {\n  return <h1>404 not found</h1>;\n}\n"
  },
  {
    "path": "examples/nextjs-scheduler/app/page.tsx",
    "chars": 4122,
    "preview": "/**\n * yorkie-js-sdk must be loaded on client-side\n */\n'use client';\n\nimport styles from './styles/page.module.css';\nimp"
  },
  {
    "path": "examples/nextjs-scheduler/app/styles/calendar.css",
    "chars": 3377,
    "preview": "/* custom css code */\n\n.react-calendar {\n  width: 350px;\n  max-width: 100%;\n  background: linear-gradient(#ffffff, #fcfd"
  },
  {
    "path": "examples/nextjs-scheduler/app/styles/globals.css",
    "chars": 760,
    "preview": "body {\n  display: flex;\n  padding: 1rem;\n  justify-content: center;\n  font-family: -apple-system, BlinkMacSystemFont, \"S"
  },
  {
    "path": "examples/nextjs-scheduler/app/styles/page.module.css",
    "chars": 3879,
    "preview": "/* Layout */\n.main {\n  display: flex;\n  flex-direction: column;\n  gap: 1.5rem;\n  width: 100%;\n  max-width: 880px;\n  marg"
  },
  {
    "path": "examples/nextjs-scheduler/app/utils/handlePeers.ts",
    "chars": 661,
    "preview": "import { Indexable } from '@yorkie-js/sdk';\n\nconst randomPeers = [\n  'Alice',\n  'Bob',\n  'Carol',\n  'Chuck',\n  'Dave',\n "
  },
  {
    "path": "examples/nextjs-scheduler/app/utils/parseDate.ts",
    "chars": 314,
    "preview": "/**\n * transform date format to DD-MM-YYYY\n */\nexport function parseDate(date: Date) {\n  let [month, day, year] = date.t"
  },
  {
    "path": "examples/nextjs-scheduler/app/utils/types.ts",
    "chars": 547,
    "preview": "export interface ENVtypes {\n  url: string;\n  apiKey: string;\n}\n\nexport interface ContentTypes {\n  date: string;\n  text: "
  },
  {
    "path": "examples/nextjs-scheduler/eslint.config.mjs",
    "chars": 438,
    "preview": "import nextConfig from 'eslint-config-next';\nimport { globalIgnores } from 'eslint/config';\nimport tseslint from 'typesc"
  },
  {
    "path": "examples/nextjs-scheduler/next.config.js",
    "chars": 269,
    "preview": "/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  output: 'export',\n  distDir: 'dist',\n  basePath: process"
  },
  {
    "path": "examples/nextjs-scheduler/package.json",
    "chars": 618,
    "preview": "{\n  \"name\": \"nextjs-scheduler\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev -p 5174\",\n "
  },
  {
    "path": "examples/nextjs-scheduler/tsconfig.json",
    "chars": 912,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"lib\": [\n      \"DOM\",\n      \"DOM.Iterable\",\n      \"ESNext\"\n    ],\n "
  },
  {
    "path": "examples/nextjs-todolist/.gitignore",
    "chars": 454,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": "examples/nextjs-todolist/README.md",
    "chars": 3695,
    "preview": "# Yorkie Nextjs Todo List Example\n\n<p>\n    <a href=\"https://yorkie.dev/yorkie-js-sdk/examples/nextjs-todolist/\" target=\""
  },
  {
    "path": "examples/nextjs-todolist/app/globals.css",
    "chars": 4168,
    "preview": "@import \"tailwindcss\";\n@import \"tw-animate-css\";\n\n@custom-variant dark (&:is(.dark *));\n\n@theme inline {\n  --color-backg"
  },
  {
    "path": "examples/nextjs-todolist/app/layout.tsx",
    "chars": 725,
    "preview": "import type { Metadata } from 'next';\nimport { Geist, Geist_Mono } from 'next/font/google';\nimport './globals.css';\n\ncon"
  },
  {
    "path": "examples/nextjs-todolist/app/page.tsx",
    "chars": 539,
    "preview": "'use client';\n\nimport { YorkieProvider, DocumentProvider } from '@yorkie-js/react';\nimport TodoList from '../components/"
  },
  {
    "path": "examples/nextjs-todolist/components/TodoList.tsx",
    "chars": 4280,
    "preview": "'use client';\n\nimport React, { useState, useMemo } from 'react';\nimport { Card, CardContent, CardHeader, CardTitle } fro"
  },
  {
    "path": "examples/nextjs-todolist/components/ui/button.tsx",
    "chars": 2133,
    "preview": "import * as React from 'react';\nimport { Slot } from '@radix-ui/react-slot';\nimport { cva, type VariantProps } from 'cla"
  },
  {
    "path": "examples/nextjs-todolist/components/ui/card.tsx",
    "chars": 2002,
    "preview": "import * as React from 'react';\n\nimport { cn } from '@/lib/utils';\n\nfunction Card({ className, ...props }: React.Compone"
  },
  {
    "path": "examples/nextjs-todolist/components/ui/input.tsx",
    "chars": 972,
    "preview": "import * as React from 'react';\n\nimport { cn } from '@/lib/utils';\n\nfunction Input({ className, type, ...props }: React."
  },
  {
    "path": "examples/nextjs-todolist/components.json",
    "chars": 427,
    "preview": "{\n  \"$schema\": \"https://ui.shadcn.com/schema.json\",\n  \"style\": \"new-york\",\n  \"rsc\": true,\n  \"tsx\": true,\n  \"tailwind\": {"
  },
  {
    "path": "examples/nextjs-todolist/eslint.config.mjs",
    "chars": 367,
    "preview": "import nextConfig from 'eslint-config-next';\nimport { globalIgnores } from 'eslint/config';\nimport prettierPlugin from '"
  },
  {
    "path": "examples/nextjs-todolist/lib/utils.ts",
    "chars": 178,
    "preview": "import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport const cn = (...inputs: A"
  },
  {
    "path": "examples/nextjs-todolist/next.config.ts",
    "chars": 279,
    "preview": "import type { NextConfig } from 'next';\n\nconst nextConfig: NextConfig = {\n  output: 'export',\n  distDir: 'dist',\n  baseP"
  },
  {
    "path": "examples/nextjs-todolist/package.json",
    "chars": 810,
    "preview": "{\n  \"name\": \"nextjs-todolist\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build"
  },
  {
    "path": "examples/nextjs-todolist/postcss.config.mjs",
    "chars": 81,
    "preview": "const config = {\n  plugins: ['@tailwindcss/postcss'],\n};\n\nexport default config;\n"
  },
  {
    "path": "examples/nextjs-todolist/tsconfig.json",
    "chars": 895,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n "
  },
  {
    "path": "examples/profile-stack/.gitignore",
    "chars": 253,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
  },
  {
    "path": "examples/profile-stack/README.md",
    "chars": 2861,
    "preview": "# Yorkie Profile Stack Example\n\n<p>\n    <a href=\"https://yorkie.dev/yorkie-js-sdk/examples/profile-stack/\" target=\"_blan"
  },
  {
    "path": "examples/profile-stack/index.html",
    "chars": 973,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/"
  },
  {
    "path": "examples/profile-stack/main.js",
    "chars": 7330,
    "preview": "import yorkie from '@yorkie-js/sdk';\nimport { getRandomName, getRandomColor } from './util.js';\n\nconst client = new york"
  },
  {
    "path": "examples/profile-stack/package.json",
    "chars": 297,
    "preview": "{\n  \"name\": \"profile-stack\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vit"
  },
  {
    "path": "examples/profile-stack/style.css",
    "chars": 3574,
    "preview": "* {\n  margin: 0;\n  padding: 0;\n}\n\nbody {\n  --light-gray: #f5f3f1;\n  --gray: #c2bdba;\n  --black: #332e2b;\n  --white: #fef"
  },
  {
    "path": "examples/profile-stack/util.js",
    "chars": 474,
    "preview": "const NAMES = [\n  'Ali',\n  'Beatriz',\n  'Charles',\n  'Diya',\n  'Eric',\n  'Fatima',\n  'Gabriel',\n  'Hanna',\n  'Johnson',\n"
  },
  {
    "path": "examples/profile-stack/vite.config.js",
    "chars": 443,
    "preview": "import { defineConfig } from 'vite';\nimport path, { dirname } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst _"
  },
  {
    "path": "examples/react-document-limit/.gitignore",
    "chars": 253,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
  },
  {
    "path": "examples/react-document-limit/README.md",
    "chars": 2920,
    "preview": "# Yorkie React Document Limit Example\n\n<p>\n    <a href=\"https://yorkie.dev/yorkie-js-sdk/examples/react-document-limit/\""
  },
  {
    "path": "examples/react-document-limit/index.html",
    "chars": 317,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "examples/react-document-limit/package.json",
    "chars": 703,
    "preview": "{\n  \"name\": \"react-document-limit\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev"
  },
  {
    "path": "examples/react-document-limit/src/App.tsx",
    "chars": 543,
    "preview": "import { YorkieProvider, DocumentProvider } from '@yorkie-js/react';\nimport { Counter } from './components/Counter';\n\nfu"
  },
  {
    "path": "examples/react-document-limit/src/components/ConnectionStatus.tsx",
    "chars": 513,
    "preview": "import { useConnection } from '@yorkie-js/react';\nimport { StreamConnectionStatus } from '@yorkie-js/sdk';\n\n/**\n * Conne"
  },
  {
    "path": "examples/react-document-limit/src/components/Counter.tsx",
    "chars": 1246,
    "preview": "import { StreamConnectionStatus } from '@yorkie-js/sdk';\nimport { useConnection } from '@yorkie-js/react';\nimport { Conn"
  },
  {
    "path": "examples/react-document-limit/src/components/CounterNumber.tsx",
    "chars": 327,
    "preview": "import { useDocumentSelector } from '../hooks/useDocumentSelector';\n\n/**\n * CounterNumber component displays the current"
  },
  {
    "path": "examples/react-document-limit/src/components/IncrementButton.tsx",
    "chars": 578,
    "preview": "import { StreamConnectionStatus } from '@yorkie-js/sdk';\nimport { useDocumentSelector } from '../hooks/useDocumentSelect"
  },
  {
    "path": "examples/react-document-limit/src/components/Peers.tsx",
    "chars": 558,
    "preview": "import React from 'react';\nimport { usePresences } from '@yorkie-js/react';\n\n/**\n * Peers component displays the list of"
  },
  {
    "path": "examples/react-document-limit/src/hooks/useDocumentSelector.tsx",
    "chars": 145,
    "preview": "import { createDocumentSelector } from '@yorkie-js/react';\n\nexport const useDocumentSelector = createDocumentSelector<{\n"
  },
  {
    "path": "examples/react-document-limit/src/index.css",
    "chars": 2391,
    "preview": ":root {\n  font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;\n  line-height: 1.5;\n  font-weight: 400;\n\n  color"
  },
  {
    "path": "examples/react-document-limit/src/main.tsx",
    "chars": 235,
    "preview": "import { StrictMode } from 'react';\nimport { createRoot } from 'react-dom/client';\nimport './index.css';\nimport App from"
  },
  {
    "path": "examples/react-document-limit/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "examples/react-document-limit/tsconfig.app.json",
    "chars": 665,
    "preview": "{\n  \"compilerOptions\": {\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.app.tsbuildinfo\",\n    \"target\": \"ES2020\",\n"
  },
  {
    "path": "examples/react-document-limit/tsconfig.json",
    "chars": 119,
    "preview": "{\n  \"files\": [],\n  \"references\": [\n    { \"path\": \"./tsconfig.app.json\" },\n    { \"path\": \"./tsconfig.node.json\" }\n  ]\n}\n"
  },
  {
    "path": "examples/react-document-limit/tsconfig.node.json",
    "chars": 593,
    "preview": "{\n  \"compilerOptions\": {\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n    \"target\": \"ES2022\","
  },
  {
    "path": "examples/react-document-limit/vite.config.ts",
    "chars": 489,
    "preview": "import path from 'path';\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vite"
  },
  {
    "path": "examples/react-flow/.gitignore",
    "chars": 253,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
  },
  {
    "path": "examples/react-flow/README.md",
    "chars": 2886,
    "preview": "# Yorkie React Flow Example\n\n<p>\n    <a href=\"https://yorkie.dev/yorkie-js-sdk/examples/react-flow/\" target=\"_blank\">\n  "
  },
  {
    "path": "examples/react-flow/index.html",
    "chars": 366,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/"
  },
  {
    "path": "examples/react-flow/package.json",
    "chars": 747,
    "preview": "{\n  \"name\": \"react-flow\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\","
  },
  {
    "path": "examples/react-flow/src/App.css",
    "chars": 606,
    "preview": "#root {\n  max-width: 1280px;\n  margin: 0 auto;\n  padding: 2rem;\n  text-align: center;\n}\n\n.logo {\n  height: 6em;\n  paddin"
  },
  {
    "path": "examples/react-flow/src/App.tsx",
    "chars": 4346,
    "preview": "import { useCallback, useRef } from 'react';\nimport { JSONArray, useDocument } from '@yorkie-js/react';\nimport {\n  React"
  },
  {
    "path": "examples/react-flow/src/index.css",
    "chars": 74,
    "preview": ":root {\n  font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;\n}\n"
  },
  {
    "path": "examples/react-flow/src/main.tsx",
    "chars": 1477,
    "preview": "import { createRoot } from 'react-dom/client';\nimport { DocumentProvider, YorkieProvider } from '@yorkie-js/react';\nimpo"
  },
  {
    "path": "examples/react-flow/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "examples/react-flow/tsconfig.app.json",
    "chars": 606,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM."
  },
  {
    "path": "examples/react-flow/tsconfig.json",
    "chars": 119,
    "preview": "{\n  \"files\": [],\n  \"references\": [\n    { \"path\": \"./tsconfig.app.json\" },\n    { \"path\": \"./tsconfig.node.json\" }\n  ]\n}\n"
  },
  {
    "path": "examples/react-flow/tsconfig.node.json",
    "chars": 561,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"lib\": [\"ES2023\"],\n    \"module\": \"ESNext\",\n    \"skipLibCheck\": true"
  },
  {
    "path": "examples/react-flow/vite.config.ts",
    "chars": 489,
    "preview": "import path from 'path';\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vite"
  },
  {
    "path": "examples/react-polling-playground/README.md",
    "chars": 1802,
    "preview": "# react-polling-playground\n\nTrending stocks leaderboard demo built on Yorkie's `SyncMode.Polling` Channel.\nEach ticker i"
  },
  {
    "path": "examples/react-polling-playground/index.html",
    "chars": 312,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "examples/react-polling-playground/package.json",
    "chars": 575,
    "preview": "{\n  \"name\": \"react-polling-playground\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    "
  },
  {
    "path": "examples/react-polling-playground/src/App.tsx",
    "chars": 7929,
    "preview": "import { useCallback, useEffect, useMemo, useState } from 'react';\nimport { YorkieProvider, SyncMode } from '@yorkie-js/"
  },
  {
    "path": "examples/react-polling-playground/src/Leaderboard.tsx",
    "chars": 625,
    "preview": "import { STOCKS } from './stocks';\nimport StockRow from './StockRow';\n\ntype Props = {\n  onSelect: (ticker: string) => vo"
  },
  {
    "path": "examples/react-polling-playground/src/StockDetail.tsx",
    "chars": 8925,
    "preview": "import { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n  ChannelProvider,\n  SyncMode,\n  useChannel,\n"
  },
  {
    "path": "examples/react-polling-playground/src/StockRow.tsx",
    "chars": 674,
    "preview": "import type { Stock } from './stocks';\n\ntype Props = {\n  stock: Stock;\n  rank: number;\n  onSelect: (ticker: string) => v"
  },
  {
    "path": "examples/react-polling-playground/src/WritePostPage.tsx",
    "chars": 2121,
    "preview": "import { ChannelProvider, SyncMode, useChannel } from '@yorkie-js/react';\nimport type { Stock } from './stocks';\n\ntype P"
  },
  {
    "path": "examples/react-polling-playground/src/main.tsx",
    "chars": 249,
    "preview": "import ReactDOM from 'react-dom/client';\nimport { StrictMode } from 'react';\nimport App from './App';\nimport './styles.c"
  },
  {
    "path": "examples/react-polling-playground/src/stocks.ts",
    "chars": 446,
    "preview": "export type Stock = {\n  ticker: string;\n  name: string;\n  market: 'US' | 'KR';\n};\n\nexport const STOCKS: ReadonlyArray<St"
  },
  {
    "path": "examples/react-polling-playground/src/styles.css",
    "chars": 7964,
    "preview": "* {\n  box-sizing: border-box;\n}\nbody {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto"
  },
  {
    "path": "examples/react-polling-playground/src/vite-env.d.ts",
    "chars": 205,
    "preview": "/// <reference types=\"vite/client\" />\n\ninterface ImportMetaEnv {\n  readonly VITE_YORKIE_API_KEY: string;\n  readonly VITE"
  },
  {
    "path": "examples/react-polling-playground/tsconfig.json",
    "chars": 640,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"DOM\", \"DOM.Iterable\","
  },
  {
    "path": "examples/react-polling-playground/tsconfig.node.json",
    "chars": 184,
    "preview": "{\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"allowSynthe"
  },
  {
    "path": "examples/react-polling-playground/vite.config.ts",
    "chars": 527,
    "preview": "import path from 'path';\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport tsconfigP"
  },
  {
    "path": "examples/react-revision/eslint.config.mjs",
    "chars": 589,
    "preview": "import { globalIgnores } from 'eslint/config';\nimport prettierPlugin from 'eslint-plugin-prettier';\nimport reactHooks fr"
  },
  {
    "path": "examples/react-revision/index.html",
    "chars": 378,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/"
  },
  {
    "path": "examples/react-revision/package.json",
    "chars": 617,
    "preview": "{\n  \"name\": \"react-revision\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vi"
  },
  {
    "path": "examples/react-revision/src/App.css",
    "chars": 2964,
    "preview": "* {\n  box-sizing: border-box;\n  margin: 0;\n  padding: 0;\n}\n\nbody {\n  font-family:\n    -apple-system, BlinkMacSystemFont,"
  },
  {
    "path": "examples/react-revision/src/App.tsx",
    "chars": 1422,
    "preview": "import { YorkieProvider, DocumentProvider, useDocument } from '@yorkie-js/react';\nimport RevisionPanel from './RevisionP"
  },
  {
    "path": "examples/react-revision/src/RevisionPanel.tsx",
    "chars": 3666,
    "preview": "import { useState, useEffect } from 'react';\nimport { useRevisions, RevisionSummary } from '@yorkie-js/react';\n\nexport d"
  },
  {
    "path": "examples/react-revision/src/main.tsx",
    "chars": 226,
    "preview": "import ReactDOM from 'react-dom/client';\nimport App from './App';\nimport { StrictMode } from 'react';\n\nReactDOM.createRo"
  },
  {
    "path": "examples/react-revision/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "examples/react-revision/tsconfig.json",
    "chars": 640,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"DOM\", \"DOM.Iterable\","
  },
  {
    "path": "examples/react-revision/tsconfig.node.json",
    "chars": 184,
    "preview": "{\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"allowSynthe"
  },
  {
    "path": "examples/react-revision/vite.config.ts",
    "chars": 557,
    "preview": "import path from 'path';\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport tsconfigP"
  },
  {
    "path": "examples/react-tldraw/.gitignore",
    "chars": 253,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
  },
  {
    "path": "examples/react-tldraw/README.md",
    "chars": 2894,
    "preview": "# Yorkie React tldraw Example\n\n<p>\n    <a href=\"https://yorkie.dev/yorkie-js-sdk/examples/react-tldraw/\" target=\"_blank\""
  },
  {
    "path": "examples/react-tldraw/index.html",
    "chars": 299,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "examples/react-tldraw/package.json",
    "chars": 752,
    "preview": "{\n  \"name\": \"react-tldraw\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite"
  },
  {
    "path": "examples/react-tldraw/src/App.css",
    "chars": 313,
    "preview": "html,\n* {\n    box-sizing: border-box;\n}\n\nbody {\n    overscroll-behavior: none;\n    margin: 0px;\n    padding: 0px;\n    fo"
  },
  {
    "path": "examples/react-tldraw/src/App.tsx",
    "chars": 1022,
    "preview": "import { Tldraw, useFileSystem } from '@tldraw/tldraw';\nimport { useMultiplayerState } from './hooks/useMultiplayerState"
  },
  {
    "path": "examples/react-tldraw/src/CustomCursor.tsx",
    "chars": 776,
    "preview": "import { CursorComponent } from '@tldraw/core';\n\n// A custom cursor component.\n// Component overrides for the tldraw ren"
  },
  {
    "path": "examples/react-tldraw/src/hooks/types.ts",
    "chars": 427,
    "preview": "// Yorkie type for typescript\nimport type { TDAsset, TDBinding, TDShape, TDUser } from '@tldraw/tldraw';\nimport type { J"
  },
  {
    "path": "examples/react-tldraw/src/hooks/useMultiplayerState.ts",
    "chars": 10662,
    "preview": "import { useCallback, useEffect, useState, useRef } from 'react';\nimport {\n  TDUserStatus,\n  TDAsset,\n  TDBinding,\n  TDS"
  },
  {
    "path": "examples/react-tldraw/src/main.tsx",
    "chars": 229,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\n\nReactDOM.createRoot(docume"
  },
  {
    "path": "examples/react-tldraw/src/tldraw.d.ts",
    "chars": 190,
    "preview": "import { Indexable, Json } from '@yorkie-js/sdk/src/document/document';\nimport { TDUser } from '@tldraw/tldraw';\n\ndeclar"
  },
  {
    "path": "examples/react-tldraw/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "examples/react-tldraw/tsconfig.json",
    "chars": 640,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"DOM\", \"DOM.Iterable\","
  },
  {
    "path": "examples/react-tldraw/tsconfig.node.json",
    "chars": 184,
    "preview": "{\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"allowSynthe"
  },
  {
    "path": "examples/react-tldraw/vite.config.ts",
    "chars": 432,
    "preview": "import path from 'path';\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport tsconfigP"
  },
  {
    "path": "examples/react-todomvc/.gitignore",
    "chars": 253,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
  },
  {
    "path": "examples/react-todomvc/README.md",
    "chars": 2898,
    "preview": "# Yorkie React TodoMVC Example\n\n<p>\n    <a href=\"https://yorkie.dev/yorkie-js-sdk/examples/react-todomvc/\" target=\"_blan"
  },
  {
    "path": "examples/react-todomvc/eslint.config.mjs",
    "chars": 589,
    "preview": "import { globalIgnores } from 'eslint/config';\nimport prettierPlugin from 'eslint-plugin-prettier';\nimport reactHooks fr"
  },
  {
    "path": "examples/react-todomvc/index.html",
    "chars": 366,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/"
  },
  {
    "path": "examples/react-todomvc/package.json",
    "chars": 677,
    "preview": "{\n  \"name\": \"react-todomvc\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vit"
  },
  {
    "path": "examples/react-todomvc/src/App.css",
    "chars": 658,
    "preview": "body {\n  margin: 20px;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n    'Ubuntu', '"
  },
  {
    "path": "examples/react-todomvc/src/App.tsx",
    "chars": 1004,
    "preview": "import Header from './components/Header';\nimport MainSection from './components/MainSection';\nimport './App.css';\n\nimpor"
  },
  {
    "path": "examples/react-todomvc/src/components/Footer.tsx",
    "chars": 1524,
    "preview": "import React from 'react';\nimport classnames from 'classnames';\nimport { Filter } from './MainSection';\n\nconst filterTit"
  },
  {
    "path": "examples/react-todomvc/src/components/Header.tsx",
    "chars": 629,
    "preview": "import React from 'react';\nimport TodoTextInput from './TodoTextInput';\nimport { TodoAction } from '../todoReducer';\n\nin"
  },
  {
    "path": "examples/react-todomvc/src/components/MainSection.tsx",
    "chars": 1954,
    "preview": "import { useState } from 'react';\nimport { Todo } from '../model';\nimport Footer from './Footer';\nimport TodoItem from '"
  },
  {
    "path": "examples/react-todomvc/src/components/TodoItem.tsx",
    "chars": 1800,
    "preview": "import React, { useState } from 'react';\nimport classnames from 'classnames';\nimport { Todo } from '../model';\nimport To"
  },
  {
    "path": "examples/react-todomvc/src/components/TodoTextInput.tsx",
    "chars": 790,
    "preview": "import React, { useState } from 'react';\n\ninterface TodoInputProps {\n  onSave: (text: string) => void;\n  placeholder?: s"
  },
  {
    "path": "examples/react-todomvc/src/main.tsx",
    "chars": 226,
    "preview": "import ReactDOM from 'react-dom/client';\nimport App from './App';\nimport { StrictMode } from 'react';\n\nReactDOM.createRo"
  },
  {
    "path": "examples/react-todomvc/src/model.ts",
    "chars": 78,
    "preview": "export interface Todo {\n  id: string;\n  text: string;\n  completed: boolean;\n}\n"
  },
  {
    "path": "examples/react-todomvc/src/todoReducer.ts",
    "chars": 2155,
    "preview": "// examples/react-todomvc/src/todoReducer.ts\nimport { JSONArray } from '@yorkie-js/react';\nimport { Todo } from './model"
  },
  {
    "path": "examples/react-todomvc/src/useTodoReducer.tsx",
    "chars": 1006,
    "preview": "import { useCallback } from 'react';\nimport { TodoAction, todoReducer } from './todoReducer';\nimport { JSONArray, useYor"
  },
  {
    "path": "examples/react-todomvc/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "examples/react-todomvc/tsconfig.json",
    "chars": 640,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"DOM\", \"DOM.Iterable\","
  },
  {
    "path": "examples/react-todomvc/tsconfig.node.json",
    "chars": 184,
    "preview": "{\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"allowSynthe"
  },
  {
    "path": "examples/react-todomvc/vite.config.ts",
    "chars": 557,
    "preview": "import path from 'path';\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport tsconfigP"
  },
  {
    "path": "examples/simultaneous-cursors/.gitignore",
    "chars": 253,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
  },
  {
    "path": "examples/simultaneous-cursors/README.md",
    "chars": 3573,
    "preview": "# Yorkie Simultaneous-Cursors Example\n\n<p>\n    <a href=\"https://yorkie.dev/yorkie-js-sdk/examples/simultaneous-cursors/\""
  },
  {
    "path": "examples/simultaneous-cursors/index.html",
    "chars": 389,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/"
  },
  {
    "path": "examples/simultaneous-cursors/package.json",
    "chars": 462,
    "preview": "{\n  \"name\": \"simultaneous-cursors\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev"
  },
  {
    "path": "examples/simultaneous-cursors/src/App.css",
    "chars": 1867,
    "preview": "body {\n  max-width: 100vw;\n  min-height: 100vh;\n  overflow-x: hidden;\n}\n\n.general-container {\n  max-width: 100%;\n}\n\n.cur"
  },
  {
    "path": "examples/simultaneous-cursors/src/App.jsx",
    "chars": 6473,
    "preview": "import { useEffect, useState, useRef } from 'react';\nimport {\n  YorkieProvider,\n  DocumentProvider,\n  useDocument,\n} fro"
  },
  {
    "path": "examples/simultaneous-cursors/src/components/ColoredIcon.jsx",
    "chars": 6726,
    "preview": "export default function ColoredIcon({ type, color }) {\n  switch (type) {\n    case 'cursor':\n      return (\n        <svg\n"
  },
  {
    "path": "examples/simultaneous-cursors/src/components/Cursor.jsx",
    "chars": 2419,
    "preview": "import PenCursor from './PenCursor';\nimport FullAnimation from './FullAnimation';\nimport ColoredIcon from './ColoredIcon"
  },
  {
    "path": "examples/simultaneous-cursors/src/components/CursorSelections.css",
    "chars": 11791,
    "preview": "/* Theme variables */\n:root {\n  --yc-radius-xs: 4px;\n  --yc-radius-sm: 6px;\n  --yc-radius: 10px;\n  --yc-radius-lg: 14px;"
  },
  {
    "path": "examples/simultaneous-cursors/src/components/CursorSelections.jsx",
    "chars": 5809,
    "preview": "import { useState, useRef } from 'react';\nimport './CursorSelections.css';\n\nexport default function CursorSelections({\n "
  },
  {
    "path": "examples/simultaneous-cursors/src/components/FullAnimation.jsx",
    "chars": 1333,
    "preview": "import { useState } from 'react';\nimport SingleAnimation from './SingleAnimation';\nimport useInterval from '../hooks/use"
  },
  {
    "path": "examples/simultaneous-cursors/src/components/PenCursor.jsx",
    "chars": 8766,
    "preview": "import { useRef, useEffect } from 'react';\n\nclass Point {\n  constructor(x, y) {\n    this.x = x;\n    this.y = y;\n    this"
  },
  {
    "path": "examples/simultaneous-cursors/src/components/SingleAnimation.jsx",
    "chars": 697,
    "preview": "import styles from './SingleAnimation.module.css';\n\nexport default function SingleAnimation({\n  x,\n  y,\n  timestamp,\n  s"
  },
  {
    "path": "examples/simultaneous-cursors/src/components/SingleAnimation.module.css",
    "chars": 1348,
    "preview": ".goUp0 {\n  opacity: 0;\n  animation: goUpAnimation0 2s, fadeOut 2s;\n}\n\n@keyframes goUpAnimation0 {\n  from {\n    transform"
  },
  {
    "path": "examples/simultaneous-cursors/src/hooks/useInterval.jsx",
    "chars": 426,
    "preview": "import { useRef, useEffect } from 'react';\n\nexport default function useInterval(callback, delay) {\n  const savedCallback"
  },
  {
    "path": "examples/simultaneous-cursors/src/main.jsx",
    "chars": 215,
    "preview": "import { StrictMode } from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App.jsx';\n\nReactDOM.crea"
  },
  {
    "path": "examples/simultaneous-cursors/vite.config.js",
    "chars": 507,
    "preview": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport path, { dirname } from 'path';\nimp"
  },
  {
    "path": "examples/vanilla-codemirror6/.gitignore",
    "chars": 253,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
  },
  {
    "path": "examples/vanilla-codemirror6/README.md",
    "chars": 2869,
    "preview": "# Yorkie CodeMirror6 Example\n\n<p>\n    <a href=\"https://yorkie.dev/yorkie-js-sdk/examples/vanilla-codemirror6/\" target=\"_"
  },
  {
    "path": "examples/vanilla-codemirror6/index.html",
    "chars": 409,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "examples/vanilla-codemirror6/package.json",
    "chars": 435,
    "preview": "{\n  \"name\": \"vanilla-codemirror6\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\""
  },
  {
    "path": "examples/vanilla-codemirror6/src/main.ts",
    "chars": 6232,
    "preview": "import type { EditOpInfo, OpInfo } from '@yorkie-js/sdk';\nimport yorkie, { DocEventType } from '@yorkie-js/sdk';\nimport "
  }
]

// ... and 322 more files (download for full content)

About this extraction

This page contains the full source code of the yorkie-team/yorkie-js-sdk GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 522 files (7.3 MB), approximately 1.9M tokens, and a symbol index with 2494 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!