├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .github
└── workflows
│ ├── auto-invite-comment.yml
│ ├── cla-assistant.yml
│ ├── comment-check.yml
│ ├── help-comment-issue.yml
│ ├── issue-translator.yml
│ └── release.yml
├── .gitignore
├── .husky
├── .gitignore
├── pre-commit
└── prepare-commit-msg
├── .prettierrc
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── assets
├── openIM.wasm
├── sql-wasm.wasm
└── wasm_exec.js
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── api
│ ├── database
│ │ ├── alter.ts
│ │ ├── black.ts
│ │ ├── conversation.ts
│ │ ├── friend.ts
│ │ ├── friendRequest.ts
│ │ ├── groupMember.ts
│ │ ├── groupRequest.ts
│ │ ├── groups.ts
│ │ ├── index.ts
│ │ ├── init.ts
│ │ ├── instance.ts
│ │ ├── localAppSdkVersion.ts
│ │ ├── message.ts
│ │ ├── notification.ts
│ │ ├── sendingMessages.ts
│ │ ├── stranger.ts
│ │ ├── superGroup.ts
│ │ ├── tableMaster.ts
│ │ ├── tempCacheChatLogs.ts
│ │ ├── unreadMessage.ts
│ │ ├── upload.ts
│ │ ├── users.ts
│ │ └── versionSync.ts
│ ├── index.ts
│ ├── upload.ts
│ └── worker.ts
├── constant
│ └── index.ts
├── index.ts
├── sdk
│ ├── index.ts
│ └── initialize.ts
├── sqls
│ ├── index.ts
│ ├── localAdminGroupRequests.ts
│ ├── localAppSdkVersion.ts
│ ├── localBlack.ts
│ ├── localChatLogsConversationID.ts
│ ├── localConversationUnreadMessages.ts
│ ├── localConversations.ts
│ ├── localFriend.ts
│ ├── localFriendRequest.ts
│ ├── localGroupMembers.ts
│ ├── localGroupRequests.ts
│ ├── localGroups.ts
│ ├── localNotification.ts
│ ├── localSendingMessages.ts
│ ├── localStranger.ts
│ ├── localSuperGroups.ts
│ ├── localTableMaster.ts
│ ├── localUpload.ts
│ ├── localUsers.ts
│ ├── localVersionSync.ts
│ └── tempCacheLocalChatLogs.ts
├── types
│ ├── @jlongster
│ │ └── sql.js
│ │ │ └── index.d.ts
│ ├── absurd-sql-optimized
│ │ └── index.d.ts
│ ├── entity.ts
│ ├── enum.ts
│ ├── eventData.ts
│ ├── index.d.ts
│ └── params.ts
└── utils
│ ├── emitter.ts
│ ├── escape.ts
│ ├── index.ts
│ ├── is.ts
│ ├── key.ts
│ ├── logFormat.ts
│ ├── response.ts
│ ├── timer.ts
│ └── value.ts
├── tsconfig.build.json
└── tsconfig.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | src/types/global.d.ts
2 | assets/
3 | lib/
4 | wasm_exec.js
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: '@typescript-eslint/parser',
4 | plugins: ['@typescript-eslint', 'node', 'prettier'],
5 | parserOptions: {
6 | tsconfigRootDir: __dirname,
7 | project: ['./tsconfig.json'],
8 | },
9 | extends: [
10 | 'eslint:recommended',
11 | 'plugin:node/recommended',
12 | 'plugin:@typescript-eslint/eslint-recommended',
13 | 'plugin:@typescript-eslint/recommended',
14 | 'plugin:@typescript-eslint/recommended-requiring-type-checking',
15 | 'plugin:prettier/recommended',
16 | ],
17 | rules: {
18 | 'prettier/prettier': 'warn',
19 | 'node/no-missing-import': 'off',
20 | 'node/no-empty-function': 'off',
21 | 'node/no-unsupported-features/es-syntax': 'off',
22 | 'node/no-missing-require': 'off',
23 | 'node/shebang': 'off',
24 | '@typescript-eslint/no-use-before-define': 'off',
25 | quotes: ['warn', 'single', { avoidEscape: true }],
26 | 'node/no-unpublished-import': 'off',
27 | '@typescript-eslint/no-unsafe-assignment': 'off',
28 | '@typescript-eslint/no-var-requires': 'off',
29 | '@typescript-eslint/ban-ts-comment': 'off',
30 | '@typescript-eslint/no-explicit-any': 'off',
31 | '@typescript-eslint/explicit-module-boundary-types': 'off',
32 | '@typescript-eslint/restrict-template-expressions': 'off',
33 | '@typescript-eslint/no-unsafe-return': 'off',
34 | '@typescript-eslint/no-floating-promises': 'off',
35 | '@typescript-eslint/no-empty-function': 'off',
36 | '@typescript-eslint/no-misused-promises': 'off',
37 | 'no-async-promise-executor': 'off',
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the repository to show as TypeScript rather than JS in GitHub
2 | *.js linguist-detectable=false
--------------------------------------------------------------------------------
/.github/workflows/auto-invite-comment.yml:
--------------------------------------------------------------------------------
1 | name: Invite users to join OpenIM Community.
2 | on:
3 | issue_comment:
4 | types:
5 | - created
6 | jobs:
7 | issue_comment:
8 | name: Invite users to join OpenIM Community
9 | if: ${{ github.event.comment.body == '/invite' || github.event.comment.body == '/close' || github.event.comment.body == '/comment' }}
10 | runs-on: ubuntu-latest
11 | permissions:
12 | issues: write
13 | steps:
14 |
15 | - name: Invite user to join OpenIM Community
16 | uses: peter-evans/create-or-update-comment@v4
17 | with:
18 | token: ${{ secrets.BOT_GITHUB_TOKEN }}
19 | issue-number: ${{ github.event.issue.number }}
20 | body: |
21 | We value close connections with our users, developers, and contributors here at Open-IM-Server. With a large community and maintainer team, we're always here to help and support you. Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us.
22 |
23 | Our most recommended way to get in touch is through [Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q). Even if you're in China, Slack is usually not blocked by firewalls, making it an easy way to connect with us. Our Slack community is the ideal place to discuss and share ideas and suggestions with other users and developers of Open-IM-Server. You can ask technical questions, seek help, or share your experiences with other users of Open-IM-Server.
24 |
25 | In addition to Slack, we also offer the following ways to get in touch:
26 |
27 | +
We also have Slack channels for you to communicate and discuss. To join, visit https://slack.com/ and join our [👀 Open-IM-Server slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) team channel.
28 | +
Get in touch with us on [Gmail](https://mail.google.com/mail/u/0/?fs=1&tf=cm&to=winxu81@gmail.com). If you have any questions or issues that need resolving, or any suggestions and feedback for our open source projects, please feel free to contact us via email.
29 | +
Read our [blog](https://doc.rentsoft.cn/). Our blog is a great place to stay up-to-date with Open-IM-Server projects and trends. On the blog, we share our latest developments, tech trends, and other interesting information.
30 | +
Add [Wechat](https://github.com/OpenIMSDK/OpenIM-Docs/blob/main/docs/images/WechatIMG20.jpeg) and indicate that you are a user or developer of Open-IM-Server. We will process your request as soon as possible.
31 |
32 | # - name: Close Issue
33 | # uses: peter-evans/close-issue@v3
34 | # with:
35 | # token: ${{ secrets.BOT_GITHUB_TOKEN }}
36 | # issue-number: ${{ github.event.issue.number }}
37 | # comment: 🤖 Auto-closing issue, if you still need help please reopen the issue or ask for help in the community above
38 | # labels: |
39 | # accepted
--------------------------------------------------------------------------------
/.github/workflows/cla-assistant.yml:
--------------------------------------------------------------------------------
1 | name: CLA Assistant
2 | on:
3 | issue_comment:
4 | types: [created]
5 | pull_request_target:
6 | types: [opened,closed,synchronize]
7 |
8 | # explicitly configure permissions, in case your GITHUB_TOKEN workflow permissions are set to read-only in repository settings
9 | permissions:
10 | actions: write
11 | contents: write # this can be 'read' if the signatures are in remote repository
12 | pull-requests: write
13 | statuses: write
14 |
15 | jobs:
16 | CLA-Assistant:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: "CLA Assistant"
20 | if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
21 | uses: contributor-assistant/github-action@v2.4.0
22 | env:
23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24 | PERSONAL_ACCESS_TOKEN: ${{ secrets.BOT_TOKEN }}
25 | with:
26 | path-to-signatures: 'signatures/cla.json'
27 | path-to-document: 'https://github.com/OpenIM-Robot/cla/blob/main/README.md' # e.g. a CLA or a DCO document
28 | branch: 'main'
29 | allowlist: 'bot*,*bot,OpenIM-Robot'
30 |
31 | # the followings are the optional inputs - If the optional inputs are not given, then default values will be taken
32 | remote-organization-name: OpenIM-Robot
33 | remote-repository-name: cla
34 | create-file-commit-message: 'Creating file for storing CLA Signatures'
35 | # signed-commit-message: '$contributorName has signed the CLA in $owner/$repo#$pullRequestNo'
36 | custom-notsigned-prcomment: '💕 Thank you for your contribution and please kindly read and sign our CLA. [CLA Docs](https://github.com/OpenIM-Robot/cla/blob/main/README.md)'
37 | custom-pr-sign-comment: 'I have read the CLA Document and I hereby sign the CLA'
38 | custom-allsigned-prcomment: '🤖 All Contributors have signed the [CLA](https://github.com/OpenIM-Robot/cla/blob/main/README.md).
The signed information is recorded [**here**](https://github.com/OpenIM-Robot/cla/blob/main/signatures/cla.json)'
39 | #lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
40 | #use-dco-flag: true - If you are using DCO instead of CLA
--------------------------------------------------------------------------------
/.github/workflows/comment-check.yml:
--------------------------------------------------------------------------------
1 | name: Non-English Comments Check
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - main
7 | workflow_dispatch:
8 |
9 | jobs:
10 | non-english-comments-check:
11 | runs-on: ubuntu-latest
12 |
13 | env:
14 | # need ignore Dirs
15 | EXCLUDE_DIRS: ".git docs tests scripts assets node_modules build"
16 | # need ignore Files
17 | EXCLUDE_FILES: "*.md *.txt *.html *.css *.min.js *.mdx"
18 |
19 | steps:
20 | - uses: actions/checkout@v4
21 |
22 | - name: Search for Non-English comments
23 | run: |
24 | set -e
25 | # Define the regex pattern to match Chinese characters
26 | pattern='[\p{Han}]'
27 |
28 | # Process the directories to be excluded
29 | exclude_dirs=""
30 | for dir in $EXCLUDE_DIRS; do
31 | exclude_dirs="$exclude_dirs --exclude-dir=$dir"
32 | done
33 |
34 | # Process the file types to be excluded
35 | exclude_files=""
36 | for file in $EXCLUDE_FILES; do
37 | exclude_files="$exclude_files --exclude=$file"
38 | done
39 |
40 | # Use grep to find all comments containing Non-English characters and save to file
41 | grep -Pnr "$pattern" . $exclude_dirs $exclude_files > non_english_comments.txt || true
42 |
43 | - name: Output non-English comments are found
44 | run: |
45 | if [ -s non_english_comments.txt ]; then
46 | echo "Non-English comments found in the following locations:"
47 | cat non_english_comments.txt
48 | exit 1 # terminate the workflow
49 | else
50 | echo "No Non_English comments found."
51 | fi
--------------------------------------------------------------------------------
/.github/workflows/help-comment-issue.yml:
--------------------------------------------------------------------------------
1 | name: Good frist issue add comment
2 | on:
3 | issues:
4 | types:
5 | - labeled
6 |
7 | jobs:
8 | add-comment:
9 | if: github.event.label.name == 'help wanted' || github.event.label.name == 'good first issue'
10 | runs-on: ubuntu-latest
11 | permissions:
12 | issues: write
13 | steps:
14 | - name: Add comment
15 | uses: peter-evans/create-or-update-comment@v4
16 | with:
17 | issue-number: ${{ github.event.issue.number }}
18 | token: ${{ secrets.BOT_TOKEN }}
19 | body: |
20 | This issue is available for anyone to work on. **Make sure to reference this issue in your pull request.** :sparkles: Thank you for your contribution! :sparkles:
21 | [Join slack 🤖](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) to connect and communicate with our developers.
22 | If you wish to accept this assignment, please leave a comment in the comments section: `/accept`.🎯
--------------------------------------------------------------------------------
/.github/workflows/issue-translator.yml:
--------------------------------------------------------------------------------
1 | name: 'issue-translator'
2 | on:
3 | issue_comment:
4 | types: [created]
5 | issues:
6 | types: [opened]
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: usthe/issues-translate-action@v2.7
13 | with:
14 | BOT_GITHUB_TOKEN: ${{ secrets.BOT_TOKEN }}
15 | IS_MODIFY_TITLE: true
16 | # not require, default false, . Decide whether to modify the issue title
17 | # if true, the robot account @Issues-translate-bot must have modification permissions, invite @Issues-translate-bot to your project or use your custom bot.
18 | CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
19 | # not require. Customize the translation robot prefix message.
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*'
7 | workflow_dispatch:
8 | inputs:
9 | version:
10 | description: 'Version to release'
11 | required: true
12 |
13 | jobs:
14 | release:
15 | name: Release
16 | runs-on: ubuntu-latest
17 |
18 | steps:
19 | - name: Checkout code
20 | uses: actions/checkout@v2
21 |
22 | - name: Set up Node.js
23 | uses: actions/setup-node@v3
24 | with:
25 | node-version: '20'
26 |
27 | - name: Install dependencies
28 | run: npm install
29 |
30 | - name: Extract version from tag or dispatch
31 | id: get_version
32 | run: |
33 | if [ "${{ github.event_name }}" == "push" ]; then
34 | echo "Version from tag ${GITHUB_REF##*/}"
35 | echo "::set-output name=version::${GITHUB_REF##*/v}"
36 | elif [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
37 | echo "Version from dispatch input ${{ github.event.inputs.version }}"
38 | echo "::set-output name=version::${{ github.event.inputs.version }}"
39 | fi
40 |
41 | - name: Update version in package.json
42 | run: npm version ${{ steps.get_version.outputs.version }} --no-git-tag-version
43 |
44 | - name: Build
45 | run: npm run build
46 |
47 | - name: Authenticate with npm registry
48 | run: npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
49 |
50 | - name: Config npm
51 | run: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc
52 | env:
53 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
54 |
55 | - name: Publish
56 | env:
57 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
58 | run: npm publish --access public --no-git-checks
59 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # Snowpack dependency directory (https://snowpack.dev/)
45 | web_modules/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env.test
73 | .env.local
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 | .parcel-cache
78 |
79 | # Next.js build output
80 | .next
81 | out
82 |
83 | # Nuxt.js build / generate output
84 | .nuxt
85 | dist
86 |
87 | # Gatsby files
88 | .cache/
89 | # Comment in the public line in if your project uses Gatsby and not Next.js
90 | # https://nextjs.org/blog/next-9-1#public-directory-support
91 | # public
92 |
93 | # vuepress build output
94 | .vuepress/dist
95 |
96 | # Serverless directories
97 | .serverless/
98 |
99 | # FuseBox cache
100 | .fusebox/
101 |
102 | # DynamoDB Local files
103 | .dynamodb/
104 |
105 | # TernJS port file
106 | .tern-port
107 |
108 | # Stores VSCode versions used for testing VSCode extensions
109 | .vscode-test
110 |
111 | # yarn v2
112 | .yarn/cache
113 | .yarn/unplugged
114 | .yarn/build-state.yml
115 | .yarn/install-state.gz
116 | .pnp.*
117 |
118 | # Compiled code
119 | lib/
120 |
--------------------------------------------------------------------------------
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
2 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
--------------------------------------------------------------------------------
/.husky/prepare-commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | exec ` tag.
34 |
35 | ### Possible Issues ❗
36 |
37 | > if you are using webpack4, you may flow this issue [How to import @openim/wasm-client-sdk in webpack4.x](https://github.com/openimsdk/open-im-sdk-web-wasm/issues/73).
38 |
39 | ## Usage 🚀
40 |
41 | The following examples demonstrate how to use the SDK. TypeScript is used, providing complete type hints.
42 |
43 | ### Importing the SDK
44 |
45 | ```typescript
46 | import { getSDK } from '@openim/wasm-client-sdk';
47 |
48 | const OpenIM = getSDK();
49 | ```
50 |
51 | ### Logging In and Listening for Connection Status
52 |
53 | > Note: You need to [deploy](https://github.com/openimsdk/open-im-server#rocket-quick-start) OpenIM Server first, the default port of OpenIM Server is 10001, 10002.
54 |
55 | ```typescript
56 | import { CbEvents } from '@openim/wasm-client-sdk';
57 | import type { WSEvent } from '@openim/wasm-client-sdk/lib/types/entity';
58 |
59 | OpenIM.on(CbEvents.OnConnecting, handleConnecting);
60 | OpenIM.on(CbEvents.OnConnectFailed, handleConnectFailed);
61 | OpenIM.on(CbEvents.OnConnectSuccess, handleConnectSuccess);
62 |
63 | OpenIM.login({
64 | userID: 'IM user ID',
65 | token: 'IM user token',
66 | platformID: 5,
67 | apiAddr: 'http://your-server-ip:10002',
68 | wsAddr: 'ws://your-server-ip:10001',
69 | });
70 |
71 | function handleConnecting() {
72 | // Connecting...
73 | }
74 |
75 | function handleConnectFailed({ errCode, errMsg }: WSEvent) {
76 | // Connection failed ❌
77 | console.log(errCode, errMsg);
78 | }
79 |
80 | function handleConnectSuccess() {
81 | // Connection successful ✅
82 | }
83 | ```
84 |
85 | To log into the IM server, you need to create an account and obtain a user ID and token. Refer to the [access token documentation](https://docs.openim.io/restapi/userManagement/userRegister) for details.
86 |
87 | ### Receiving and Sending Messages 💬
88 |
89 | OpenIM makes it easy to send and receive messages. By default, there is no restriction on having a friend relationship to send messages (although you can configure other policies on the server). If you know the user ID of the recipient, you can conveniently send a message to them.
90 |
91 | ```typescript
92 | import { CbEvents } from '@openim/wasm-client-sdk';
93 | import type {
94 | WSEvent,
95 | MessageItem,
96 | } from '@openim/wasm-client-sdk/lib/types/entity';
97 |
98 | // Listenfor new messages 📩
99 | OpenIM.on(CbEvents.OnRecvNewMessages, handleNewMessages);
100 |
101 | const message = (await OpenIM.createTextMessage('hello openim')).data;
102 |
103 | OpenIM.sendMessage({
104 | recvID: 'recipient user ID',
105 | groupID: '',
106 | message,
107 | })
108 | .then(() => {
109 | // Message sent successfully ✉️
110 | })
111 | .catch(err => {
112 | // Failed to send message ❌
113 | console.log(err);
114 | });
115 |
116 | function handleNewMessages({ data }: WSEvent) {
117 | // New message list 📨
118 | console.log(data);
119 | }
120 | ```
121 |
122 | ## Examples 🌟
123 |
124 | You can find a demo web app that uses the SDK in the [openim-pc-web-demo](https://github.com/openimsdk/open-im-pc-web-demo) repository.
125 |
126 | ## Browser Support 🌐
127 |
128 | | Browser | Desktop OS | Mobile OS |
129 | | ------------------- | --------------------- | --------- |
130 | | Chrome (61+) | Windows, macOS, Linux | Android |
131 | | Firefox (58+) | Windows, macOS, Linux | Android |
132 | | Safari (15+) | macOS | iOS |
133 | | Edge (Chromium 16+) | Windows, macOS | |
134 |
135 | ## Community :busts_in_silhouette:
136 |
137 | - 📚 [OpenIM Community](https://github.com/OpenIMSDK/community)
138 | - 💕 [OpenIM Interest Group](https://github.com/Openim-sigs)
139 | - 🚀 [Join our Slack community](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A)
140 | - :eyes: [Join our wechat (微信群)](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg)
141 |
142 | ## Community Meetings :calendar:
143 |
144 | We want anyone to get involved in our community and contributing code, we offer gifts and rewards, and we welcome you to join us every Thursday night.
145 |
146 | Our conference is in the [OpenIM Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A) 🎯, then you can search the Open-IM-Server pipeline to join
147 |
148 | We take notes of each [biweekly meeting](https://github.com/orgs/OpenIMSDK/discussions/categories/meeting) in [GitHub discussions](https://github.com/openimsdk/open-im-server/discussions/categories/meeting), Our historical meeting notes, as well as replays of the meetings are available at [Google Docs :bookmark_tabs:](https://docs.google.com/document/d/1nx8MDpuG74NASx081JcCpxPgDITNTpIIos0DS6Vr9GU/edit?usp=sharing).
149 |
150 | ## Who are using OpenIM :eyes:
151 |
152 | Check out our [user case studies](https://github.com/OpenIMSDK/community/blob/main/ADOPTERS.md) page for a list of the project users. Don't hesitate to leave a [📝comment](https://github.com/openimsdk/open-im-server/issues/379) and share your use case.
153 |
154 | ## License :page_facing_up:
155 |
156 | This software is licensed under a dual-license model:
157 |
158 | - The GNU Affero General Public License (AGPL), Version 3 or later; **OR**
159 | - Commercial license terms from OpenIMSDK.
160 |
161 | If you wish to use this software under commercial terms, please contact us at: contact@openim.io
162 |
163 | For more information, see: https://www.openim.io/en/licensing
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/assets/openIM.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openimsdk/openim-sdk-js-wasm/82bdcf63418c113c71f58bc7a99f3ddd2e47e565/assets/openIM.wasm
--------------------------------------------------------------------------------
/assets/sql-wasm.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openimsdk/openim-sdk-js-wasm/82bdcf63418c113c71f58bc7a99f3ddd2e47e565/assets/sql-wasm.wasm
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@openim/wasm-client-sdk",
3 | "version": "3.8.2-1",
4 | "description": "open im sdk for web",
5 | "source": "src/index.ts",
6 | "main": "lib/index.js",
7 | "unpkg": "lib/index.umd.js",
8 | "module": "lib/index.es.js",
9 | "jsdelivr": "lib/index.umd.js",
10 | "types": "lib/index.d.ts",
11 | "exports": {
12 | ".": {
13 | "import": "./lib/index.es.js",
14 | "require": "./lib/index.js",
15 | "types": "./lib/index.d.ts"
16 | }
17 | },
18 | "files": [
19 | "lib/**/*",
20 | "assets/**/*"
21 | ],
22 | "scripts": {
23 | "build": "rimraf lib && rollup -c && tsc-alias",
24 | "cm": "cz",
25 | "lint": "eslint ./src/ --fix",
26 | "prepare": "husky install",
27 | "semantic-release": "semantic-release",
28 | "test:watch": "jest --watch",
29 | "test": "jest --coverage",
30 | "typecheck": "tsc --noEmit"
31 | },
32 | "repository": {
33 | "type": "git",
34 | "url": "git+https://github.com/OpenIMSDK/Open-IM-SDK-Web-Wasm.git"
35 | },
36 | "license": "MIT",
37 | "author": {
38 | "name": "blooming",
39 | "email": "blooming2477@gmail.com",
40 | "url": "https://github.com/Bloomingg"
41 | },
42 | "engines": {
43 | "node": ">=12.0"
44 | },
45 | "keywords": [
46 | "openim"
47 | ],
48 | "bugs": {
49 | "url": "https://github.com/OpenIMSDK/Open-IM-SDK-Web-Wasm/issues"
50 | },
51 | "homepage": "https://github.com/OpenIMSDK/Open-IM-SDK-Web-Wasm#readme",
52 | "devDependencies": {
53 | "@commitlint/cli": "^16.2.4",
54 | "@commitlint/config-conventional": "^16.2.4",
55 | "@jlongster/sql.js": "^1.6.7",
56 | "@rollup/plugin-alias": "^5.1.0",
57 | "@rollup/plugin-commonjs": "^25.0.7",
58 | "@rollup/plugin-node-resolve": "^15.2.3",
59 | "@rollup/plugin-terser": "^0.4.4",
60 | "@types/jest": "^27.5.2",
61 | "@types/node": "^12.20.11",
62 | "@types/uuid": "^8.3.4",
63 | "@typescript-eslint/eslint-plugin": "^4.22.0",
64 | "@typescript-eslint/parser": "^4.22.0",
65 | "absurd-sql": "^0.0.53",
66 | "absurd-sql-optimized": "^0.0.1",
67 | "conventional-changelog-conventionalcommits": "^5.0.0",
68 | "eslint": "^7.25.0",
69 | "eslint-config-prettier": "^8.3.0",
70 | "eslint-plugin-node": "^11.1.0",
71 | "eslint-plugin-prettier": "^3.4.0",
72 | "husky": "^6.0.0",
73 | "jest": "^27.2.0",
74 | "lint-staged": "^10.5.4",
75 | "prettier": "^2.2.1",
76 | "rollup": "^2.79.1",
77 | "rollup-plugin-polyfill-node": "^0.13.0",
78 | "rollup-plugin-typescript2": "^0.36.0",
79 | "rpc-shooter": "^0.0.14",
80 | "semantic-release": "^19.0.2",
81 | "squel": "^5.13.0",
82 | "tsc-alias": "^1.7.0",
83 | "typescript": "^4.2.4",
84 | "uuid": "^9.0.0"
85 | },
86 | "config": {
87 | "commitizen": {
88 | "path": "./node_modules/@commitlint/cz-conventional-changelog"
89 | }
90 | },
91 | "lint-staged": {
92 | "*.ts": "eslint --cache --cache-location .eslintcache --fix"
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import typescript from 'rollup-plugin-typescript2';
2 | import resolve from '@rollup/plugin-node-resolve';
3 | import commonjs from '@rollup/plugin-commonjs';
4 | import alias from '@rollup/plugin-alias';
5 | import polyfillNode from 'rollup-plugin-polyfill-node';
6 | import terser from '@rollup/plugin-terser';
7 |
8 | export default [
9 | {
10 | input: 'src/index.ts',
11 | output: [
12 | {
13 | file: 'lib/index.js',
14 | format: 'cjs',
15 | inlineDynamicImports: true,
16 | sourcemap: false,
17 | },
18 | {
19 | file: 'lib/index.es.js',
20 | format: 'esm',
21 | inlineDynamicImports: true,
22 | sourcemap: false,
23 | },
24 | {
25 | file: 'lib/index.umd.js',
26 | format: 'umd',
27 | name: 'openImSdkWasm',
28 | inlineDynamicImports: true,
29 | sourcemap: false,
30 | },
31 | ],
32 | plugins: [alias(), typescript(), resolve(), commonjs()],
33 | },
34 | {
35 | input: 'src/api/worker.ts',
36 | output: [
37 | {
38 | file: 'lib/worker.js',
39 | format: 'esm',
40 | sourcemap: false,
41 | },
42 | {
43 | file: 'lib/worker-legacy.js',
44 | format: 'iife',
45 | sourcemap: false,
46 | },
47 | ],
48 | plugins: [
49 | alias(),
50 | typescript({
51 | tsconfig: './tsconfig.build.json',
52 | }),
53 | resolve(),
54 | commonjs(),
55 | polyfillNode(),
56 | terser(),
57 | ],
58 | },
59 | ];
60 |
--------------------------------------------------------------------------------
/src/api/database/alter.ts:
--------------------------------------------------------------------------------
1 | import { Database } from '@jlongster/sql.js';
2 |
3 | export function alterTable(db: Database) {
4 | alter351(db);
5 | alter380(db);
6 | }
7 |
8 | function alter351(db: Database) {
9 | try {
10 | db.exec(
11 | `
12 | ALTER TABLE local_friends ADD COLUMN is_pinned numeric;
13 | `
14 | );
15 | } catch (error) {
16 | // alter table error
17 | }
18 | }
19 |
20 | function alter380(db: Database) {
21 | try {
22 | db.exec(
23 | `
24 | ALTER TABLE local_groups ADD COLUMN display_is_read numeric;
25 | `
26 | );
27 | } catch (error) {
28 | // alter table error
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/api/database/black.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | getBlackList as databaseGetBlackList,
4 | getBlackListUserID as databaseGetBlackListUserID,
5 | getBlackInfoByBlockUserID as databaseGetBlackInfoByBlockUserID,
6 | getBlackInfoList as databaseGetBlackInfoList,
7 | insertBlack as databaseInsertBlack,
8 | deleteBlack as databasedeleteBlack,
9 | updateBlack as databaseupdateBlack,
10 | LocalBlack,
11 | } from '@/sqls';
12 | import {
13 | converSqlExecResult,
14 | convertObjectField,
15 | convertToSnakeCaseObject,
16 | formatResponse,
17 | } from '@/utils';
18 | import { getInstance } from './instance';
19 |
20 | export async function getBlackList(): Promise {
21 | try {
22 | const db = await getInstance();
23 |
24 | const execResult = databaseGetBlackList(db);
25 |
26 | return formatResponse(
27 | converSqlExecResult(execResult[0], 'CamelCase', [], {
28 | block_user_id: 'userID',
29 | })
30 | );
31 | } catch (e) {
32 | console.error(e);
33 |
34 | return formatResponse(
35 | undefined,
36 | DatabaseErrorCode.ErrorInit,
37 | JSON.stringify(e)
38 | );
39 | }
40 | }
41 |
42 | export async function getBlackListUserID(): Promise {
43 | try {
44 | const db = await getInstance();
45 |
46 | const execResult = databaseGetBlackListUserID(db);
47 |
48 | return formatResponse(converSqlExecResult(execResult[0], 'CamelCase'));
49 | } catch (e) {
50 | console.error(e);
51 |
52 | return formatResponse(
53 | undefined,
54 | DatabaseErrorCode.ErrorInit,
55 | JSON.stringify(e)
56 | );
57 | }
58 | }
59 |
60 | export async function getBlackInfoByBlockUserID(
61 | blockUserID: string,
62 | loginUserID: string
63 | ): Promise {
64 | try {
65 | const db = await getInstance();
66 |
67 | const execResult = databaseGetBlackInfoByBlockUserID(
68 | db,
69 | blockUserID,
70 | loginUserID
71 | );
72 |
73 | return formatResponse(converSqlExecResult(execResult[0], 'CamelCase'));
74 | } catch (e) {
75 | console.error(e);
76 |
77 | return formatResponse(
78 | undefined,
79 | DatabaseErrorCode.ErrorInit,
80 | JSON.stringify(e)
81 | );
82 | }
83 | }
84 |
85 | export async function getBlackInfoList(
86 | blockUserIDListStr: string
87 | ): Promise {
88 | try {
89 | const db = await getInstance();
90 |
91 | const execResult = databaseGetBlackInfoList(
92 | db,
93 | JSON.parse(blockUserIDListStr)
94 | );
95 |
96 | return formatResponse(converSqlExecResult(execResult[0], 'CamelCase'));
97 | } catch (e) {
98 | console.error(e);
99 |
100 | return formatResponse(
101 | undefined,
102 | DatabaseErrorCode.ErrorInit,
103 | JSON.stringify(e)
104 | );
105 | }
106 | }
107 |
108 | export async function insertBlack(localBlackStr: string): Promise {
109 | try {
110 | const db = await getInstance();
111 |
112 | const localBlack = convertToSnakeCaseObject(
113 | convertObjectField(JSON.parse(localBlackStr), {
114 | userID: 'block_user_id',
115 | name: 'nickname',
116 | })
117 | ) as LocalBlack;
118 |
119 | databaseInsertBlack(db, localBlack);
120 |
121 | return formatResponse('');
122 | } catch (e) {
123 | console.error(e);
124 |
125 | return formatResponse(
126 | undefined,
127 | DatabaseErrorCode.ErrorInit,
128 | JSON.stringify(e)
129 | );
130 | }
131 | }
132 |
133 | export async function deleteBlack(
134 | blockUserID: string,
135 | loginUserID: string
136 | ): Promise {
137 | try {
138 | const db = await getInstance();
139 |
140 | databasedeleteBlack(db, blockUserID, loginUserID);
141 |
142 | return formatResponse('');
143 | } catch (e) {
144 | console.error(e);
145 |
146 | return formatResponse(
147 | undefined,
148 | DatabaseErrorCode.ErrorInit,
149 | JSON.stringify(e)
150 | );
151 | }
152 | }
153 |
154 | export async function updateBlack(localBlackStr: string): Promise {
155 | try {
156 | const db = await getInstance();
157 |
158 | const localBlack = convertToSnakeCaseObject(
159 | convertObjectField(JSON.parse(localBlackStr))
160 | ) as LocalBlack;
161 |
162 | databaseupdateBlack(db, localBlack);
163 |
164 | return formatResponse('');
165 | } catch (e) {
166 | console.error(e);
167 |
168 | return formatResponse(
169 | undefined,
170 | DatabaseErrorCode.ErrorInit,
171 | JSON.stringify(e)
172 | );
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/src/api/database/friend.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | insertFriend as databaseInsertFriend,
4 | deleteFriend as databasedeleteFriend,
5 | updateFriend as databaseupdateFriend,
6 | updateColumnsFriend as databaseupdateColumnsFriend,
7 | getAllFriendList as databaseGetAllFriendList,
8 | getPageFriendList as databaseGetPageFriendList,
9 | searchFriendList as databasesearchFriendList,
10 | getFriendInfoByFriendUserID as databaseGetFriendInfoByFriendUserID,
11 | getFriendInfoList as databaseGetFriendInfoList,
12 | getFriendListCount as databaseGetFriendListCount,
13 | deleteAllFriend as databaseDeleteAllFriend,
14 | LocalFriend,
15 | } from '@/sqls';
16 | import {
17 | converSqlExecResult,
18 | convertObjectField,
19 | convertToSnakeCaseObject,
20 | formatResponse,
21 | } from '@/utils';
22 | import { getInstance } from './instance';
23 |
24 | export async function insertFriend(localFriendStr: string): Promise {
25 | try {
26 | const db = await getInstance();
27 | const localFriend = convertToSnakeCaseObject(
28 | convertObjectField(JSON.parse(localFriendStr), {
29 | userID: 'friend_user_id',
30 | nickname: 'name',
31 | })
32 | ) as LocalFriend;
33 |
34 | databaseInsertFriend(db, localFriend);
35 |
36 | return formatResponse('');
37 | } catch (e) {
38 | console.error(e);
39 |
40 | return formatResponse(
41 | undefined,
42 | DatabaseErrorCode.ErrorInit,
43 | JSON.stringify(e)
44 | );
45 | }
46 | }
47 |
48 | export async function deleteFriend(
49 | friendUserID: string,
50 | loginUserID: string
51 | ): Promise {
52 | try {
53 | const db = await getInstance();
54 |
55 | databasedeleteFriend(db, friendUserID, loginUserID);
56 |
57 | return formatResponse('');
58 | } catch (e) {
59 | console.error(e);
60 |
61 | return formatResponse(
62 | undefined,
63 | DatabaseErrorCode.ErrorInit,
64 | JSON.stringify(e)
65 | );
66 | }
67 | }
68 |
69 | export async function updateFriend(localFriendStr: string): Promise {
70 | try {
71 | const db = await getInstance();
72 | const localFriend = convertToSnakeCaseObject(
73 | convertObjectField(JSON.parse(localFriendStr), {
74 | userID: 'friend_user_id',
75 | nickname: 'name',
76 | })
77 | ) as LocalFriend;
78 |
79 | databaseupdateFriend(db, localFriend);
80 |
81 | return formatResponse('');
82 | } catch (e) {
83 | console.error(e);
84 |
85 | return formatResponse(
86 | undefined,
87 | DatabaseErrorCode.ErrorInit,
88 | JSON.stringify(e)
89 | );
90 | }
91 | }
92 |
93 | export async function getAllFriendList(loginUserID: string): Promise {
94 | try {
95 | const db = await getInstance();
96 |
97 | const execResult = databaseGetAllFriendList(db, loginUserID);
98 |
99 | return formatResponse(
100 | converSqlExecResult(execResult[0], 'CamelCase', ['isPinned'], {
101 | name: 'nickname',
102 | friend_user_id: 'userID',
103 | })
104 | );
105 | } catch (e) {
106 | console.error(e);
107 |
108 | return formatResponse(
109 | undefined,
110 | DatabaseErrorCode.ErrorInit,
111 | JSON.stringify(e)
112 | );
113 | }
114 | }
115 |
116 | export async function getPageFriendList(
117 | offset: number,
118 | count: number,
119 | loginUserID: string
120 | ): Promise {
121 | try {
122 | const db = await getInstance();
123 |
124 | const execResult = databaseGetPageFriendList(
125 | db,
126 | offset,
127 | count,
128 | loginUserID
129 | );
130 |
131 | return formatResponse(
132 | converSqlExecResult(execResult[0], 'CamelCase', ['isPinned'], {
133 | name: 'nickname',
134 | friend_user_id: 'userID',
135 | })
136 | );
137 | } catch (e) {
138 | console.error(e);
139 |
140 | return formatResponse(
141 | undefined,
142 | DatabaseErrorCode.ErrorInit,
143 | JSON.stringify(e)
144 | );
145 | }
146 | }
147 |
148 | export async function searchFriendList(
149 | key: string,
150 | isSearchUserID: boolean,
151 | isSearchNickname: boolean,
152 | isSearchRemark: boolean
153 | ): Promise {
154 | try {
155 | const db = await getInstance();
156 |
157 | const execResult = databasesearchFriendList(
158 | db,
159 | key,
160 | isSearchUserID,
161 | isSearchNickname,
162 | isSearchRemark
163 | );
164 |
165 | return formatResponse(
166 | converSqlExecResult(execResult[0], 'CamelCase', ['isPinned'], {
167 | name: 'nickname',
168 | friend_user_id: 'userID',
169 | })
170 | );
171 | } catch (e) {
172 | console.error(e);
173 |
174 | return formatResponse(
175 | undefined,
176 | DatabaseErrorCode.ErrorInit,
177 | JSON.stringify(e)
178 | );
179 | }
180 | }
181 |
182 | export async function getFriendInfoByFriendUserID(
183 | friendUserID: string,
184 | loginUserID: string
185 | ): Promise {
186 | try {
187 | const db = await getInstance();
188 |
189 | const execResult = databaseGetFriendInfoByFriendUserID(
190 | db,
191 | friendUserID,
192 | loginUserID
193 | );
194 |
195 | if (execResult.length === 0) {
196 | return formatResponse(
197 | '',
198 | DatabaseErrorCode.ErrorNoRecord,
199 | `no friend with id ${friendUserID}`
200 | );
201 | }
202 |
203 | return formatResponse(
204 | converSqlExecResult(execResult[0], 'CamelCase', ['isPinned'], {
205 | name: 'nickname',
206 | friend_user_id: 'userID',
207 | })[0]
208 | );
209 | } catch (e) {
210 | console.error(e);
211 |
212 | return formatResponse(
213 | undefined,
214 | DatabaseErrorCode.ErrorInit,
215 | JSON.stringify(e)
216 | );
217 | }
218 | }
219 |
220 | export async function getFriendInfoList(
221 | friendUserIDListStr: string
222 | ): Promise {
223 | try {
224 | const db = await getInstance();
225 |
226 | const execResult = databaseGetFriendInfoList(
227 | db,
228 | JSON.parse(friendUserIDListStr)
229 | );
230 |
231 | return formatResponse(
232 | converSqlExecResult(execResult[0], 'CamelCase', ['isPinned'], {
233 | name: 'nickname',
234 | friend_user_id: 'userID',
235 | })
236 | );
237 | } catch (e) {
238 | console.error(e);
239 |
240 | return formatResponse(
241 | undefined,
242 | DatabaseErrorCode.ErrorInit,
243 | JSON.stringify(e)
244 | );
245 | }
246 | }
247 |
248 | export async function updateColumnsFriend(
249 | friendUserIDListStr: string,
250 | localFriendStr: string
251 | ): Promise {
252 | try {
253 | const db = await getInstance();
254 | const localFriend = convertToSnakeCaseObject(
255 | convertObjectField(JSON.parse(localFriendStr), {
256 | userID: 'friend_user_id',
257 | nickname: 'name',
258 | })
259 | ) as LocalFriend;
260 |
261 | databaseupdateColumnsFriend(
262 | db,
263 | JSON.parse(friendUserIDListStr),
264 | localFriend
265 | );
266 |
267 | return formatResponse('');
268 | } catch (e) {
269 | console.error(e);
270 |
271 | return formatResponse(
272 | undefined,
273 | DatabaseErrorCode.ErrorInit,
274 | JSON.stringify(e)
275 | );
276 | }
277 | }
278 |
279 | export async function getFriendListCount(): Promise {
280 | try {
281 | const db = await getInstance();
282 |
283 | const execResult = databaseGetFriendListCount(db);
284 |
285 | return formatResponse(execResult[0]?.values[0]?.[0] ?? 0);
286 | } catch (e) {
287 | console.error(e);
288 |
289 | return formatResponse(
290 | undefined,
291 | DatabaseErrorCode.ErrorInit,
292 | JSON.stringify(e)
293 | );
294 | }
295 | }
296 |
297 | export async function batchInsertFriend(
298 | localFriendListStr: string
299 | ): Promise {
300 | try {
301 | const db = await getInstance();
302 |
303 | const list = JSON.parse(localFriendListStr) as LocalFriend[];
304 |
305 | list.map(item => {
306 | const localFriend = convertToSnakeCaseObject(
307 | convertObjectField(item, {
308 | userID: 'friend_user_id',
309 | nickname: 'name',
310 | })
311 | ) as LocalFriend;
312 | databaseInsertFriend(db, localFriend);
313 |
314 | return null;
315 | });
316 |
317 | return formatResponse('');
318 | } catch (e) {
319 | console.error(e);
320 |
321 | return formatResponse(
322 | undefined,
323 | DatabaseErrorCode.ErrorInit,
324 | JSON.stringify(e)
325 | );
326 | }
327 | }
328 |
329 | export async function deleteAllFriend(): Promise {
330 | try {
331 | const db = await getInstance();
332 |
333 | databaseDeleteAllFriend(db);
334 |
335 | return formatResponse('');
336 | } catch (e) {
337 | console.error(e);
338 |
339 | return formatResponse(
340 | undefined,
341 | DatabaseErrorCode.ErrorInit,
342 | JSON.stringify(e)
343 | );
344 | }
345 | }
346 |
--------------------------------------------------------------------------------
/src/api/database/friendRequest.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | insertFriendRequest as databaseInsertFriendRequest,
4 | deleteFriendRequestBothUserID as databasedeleteFriendRequestBothUserID,
5 | updateFriendRequest as databaseupdateFriendRequest,
6 | getRecvFriendApplication as databaseGetRecvFriendApplication,
7 | getSendFriendApplication as databaseGetSendFriendApplication,
8 | getFriendApplicationByBothID as databaseGetFriendApplicationByBothID,
9 | getBothFriendReq as databaseGetBothFriendReq,
10 | LocalFriendRequest,
11 | } from '@/sqls';
12 | import {
13 | converSqlExecResult,
14 | convertObjectField,
15 | convertToSnakeCaseObject,
16 | formatResponse,
17 | } from '@/utils';
18 | import { getInstance } from './instance';
19 |
20 | export async function insertFriendRequest(
21 | localFriendRequestStr: string
22 | ): Promise {
23 | try {
24 | const db = await getInstance();
25 | const localFriendRequest = convertToSnakeCaseObject(
26 | convertObjectField(JSON.parse(localFriendRequestStr))
27 | ) as LocalFriendRequest;
28 |
29 | databaseInsertFriendRequest(db, localFriendRequest);
30 |
31 | return formatResponse('');
32 | } catch (e) {
33 | console.error(e);
34 |
35 | return formatResponse(
36 | undefined,
37 | DatabaseErrorCode.ErrorInit,
38 | JSON.stringify(e)
39 | );
40 | }
41 | }
42 |
43 | export async function deleteFriendRequestBothUserID(
44 | fromUserID: string,
45 | toUserID: string
46 | ): Promise {
47 | try {
48 | const db = await getInstance();
49 |
50 | databasedeleteFriendRequestBothUserID(db, fromUserID, toUserID);
51 |
52 | return formatResponse('');
53 | } catch (e) {
54 | console.error(e);
55 |
56 | return formatResponse(
57 | undefined,
58 | DatabaseErrorCode.ErrorInit,
59 | JSON.stringify(e)
60 | );
61 | }
62 | }
63 |
64 | export async function updateFriendRequest(
65 | localFriendRequestStr: string
66 | ): Promise {
67 | try {
68 | const db = await getInstance();
69 | const localFriendRequest = convertToSnakeCaseObject(
70 | convertObjectField(JSON.parse(localFriendRequestStr))
71 | ) as LocalFriendRequest;
72 | databaseupdateFriendRequest(db, localFriendRequest);
73 |
74 | return formatResponse('');
75 | } catch (e) {
76 | console.error(e);
77 |
78 | return formatResponse(
79 | undefined,
80 | DatabaseErrorCode.ErrorInit,
81 | JSON.stringify(e)
82 | );
83 | }
84 | }
85 |
86 | export async function getRecvFriendApplication(
87 | loginUserID: string
88 | ): Promise {
89 | try {
90 | const db = await getInstance();
91 |
92 | const execResult = databaseGetRecvFriendApplication(db, loginUserID);
93 |
94 | return formatResponse(converSqlExecResult(execResult[0], 'CamelCase'));
95 | } catch (e) {
96 | console.error(e);
97 |
98 | return formatResponse(
99 | undefined,
100 | DatabaseErrorCode.ErrorInit,
101 | JSON.stringify(e)
102 | );
103 | }
104 | }
105 |
106 | export async function getSendFriendApplication(
107 | fromUserId: string
108 | ): Promise {
109 | try {
110 | const db = await getInstance();
111 |
112 | const execResult = databaseGetSendFriendApplication(db, fromUserId);
113 |
114 | return formatResponse(converSqlExecResult(execResult[0], 'CamelCase'));
115 | } catch (e) {
116 | console.error(e);
117 |
118 | return formatResponse(
119 | undefined,
120 | DatabaseErrorCode.ErrorInit,
121 | JSON.stringify(e)
122 | );
123 | }
124 | }
125 |
126 | export async function getFriendApplicationByBothID(
127 | fromUserID: string,
128 | toUserID: boolean
129 | ): Promise {
130 | try {
131 | const db = await getInstance();
132 |
133 | const execResult = databaseGetFriendApplicationByBothID(
134 | db,
135 | fromUserID,
136 | toUserID
137 | );
138 |
139 | return formatResponse(converSqlExecResult(execResult[0], 'CamelCase'));
140 | } catch (e) {
141 | console.error(e);
142 |
143 | return formatResponse(
144 | undefined,
145 | DatabaseErrorCode.ErrorInit,
146 | JSON.stringify(e)
147 | );
148 | }
149 | }
150 |
151 | export async function getBothFriendReq(
152 | fromUserID: string,
153 | toUserID: boolean
154 | ): Promise {
155 | try {
156 | const db = await getInstance();
157 |
158 | const execResult = databaseGetBothFriendReq(db, fromUserID, toUserID);
159 |
160 | return formatResponse(converSqlExecResult(execResult[0], 'CamelCase'));
161 | } catch (e) {
162 | console.error(e);
163 |
164 | return formatResponse(
165 | undefined,
166 | DatabaseErrorCode.ErrorInit,
167 | JSON.stringify(e)
168 | );
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/src/api/database/groupRequest.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | insertGroupRequest as databaseInsertGroupRequest,
4 | deleteGroupRequest as databaseDeleteGroupRequest,
5 | updateGroupRequest as databaseUpdateGroupRequest,
6 | getSendGroupApplication as databaseGetSendGroupApplication,
7 | insertAdminGroupRequest as databaseInsertAdminGroupRequest,
8 | deleteAdminGroupRequest as databaseDeleteAdminGroupRequest,
9 | updateAdminGroupRequest as databaseUpdateAdminGroupRequest,
10 | getAdminGroupApplication as databaseGetAdminGroupApplication,
11 | LocalGroupRequest,
12 | } from '@/sqls';
13 | import {
14 | convertToSnakeCaseObject,
15 | convertObjectField,
16 | formatResponse,
17 | converSqlExecResult,
18 | } from '@/utils';
19 | import { getInstance } from './instance';
20 |
21 | export async function insertGroupRequest(
22 | localGroupRequestStr: string
23 | ): Promise {
24 | try {
25 | const db = await getInstance();
26 |
27 | const localGroupRequest = convertToSnakeCaseObject(
28 | convertObjectField(JSON.parse(localGroupRequestStr), {
29 | groupFaceURL: 'face_url',
30 | userFaceURL: 'user_face_url',
31 | handledMsg: 'handle_msg',
32 | handledTime: 'handle_time',
33 | })
34 | ) as LocalGroupRequest;
35 |
36 | databaseInsertGroupRequest(db, localGroupRequest);
37 |
38 | return formatResponse('');
39 | } catch (e) {
40 | console.error(e);
41 |
42 | return formatResponse(
43 | undefined,
44 | DatabaseErrorCode.ErrorInit,
45 | JSON.stringify(e)
46 | );
47 | }
48 | }
49 |
50 | export async function deleteGroupRequest(
51 | groupID: string,
52 | userID: string
53 | ): Promise {
54 | try {
55 | const db = await getInstance();
56 |
57 | databaseDeleteGroupRequest(db, groupID, userID);
58 |
59 | return formatResponse('');
60 | } catch (e) {
61 | console.error(e);
62 |
63 | return formatResponse(
64 | undefined,
65 | DatabaseErrorCode.ErrorInit,
66 | JSON.stringify(e)
67 | );
68 | }
69 | }
70 |
71 | export async function updateGroupRequest(
72 | localGroupRequestStr: string
73 | ): Promise {
74 | try {
75 | const db = await getInstance();
76 | const localGroupRequest = convertToSnakeCaseObject(
77 | convertObjectField(JSON.parse(localGroupRequestStr), {
78 | groupFaceURL: 'face_url',
79 | userFaceURL: 'user_face_url',
80 | handledMsg: 'handle_msg',
81 | handledTime: 'handle_time',
82 | })
83 | ) as LocalGroupRequest;
84 | databaseUpdateGroupRequest(db, localGroupRequest);
85 |
86 | return formatResponse('');
87 | } catch (e) {
88 | console.error(e);
89 |
90 | return formatResponse(
91 | undefined,
92 | DatabaseErrorCode.ErrorInit,
93 | JSON.stringify(e)
94 | );
95 | }
96 | }
97 |
98 | export async function getSendGroupApplication(): Promise {
99 | try {
100 | const db = await getInstance();
101 |
102 | const execResult = databaseGetSendGroupApplication(db);
103 |
104 | return formatResponse(
105 | converSqlExecResult(execResult[0], 'CamelCase', [], {
106 | face_url: 'groupFaceURL',
107 | user_face_url: 'userFaceURL',
108 | handle_msg: 'handledMsg',
109 | handle_time: 'handledTime',
110 | })
111 | );
112 | } catch (e) {
113 | console.error(e);
114 |
115 | return formatResponse(
116 | undefined,
117 | DatabaseErrorCode.ErrorInit,
118 | JSON.stringify(e)
119 | );
120 | }
121 | }
122 |
123 | export async function insertAdminGroupRequest(
124 | localAdminGroupRequestStr: string
125 | ): Promise {
126 | try {
127 | const db = await getInstance();
128 |
129 | const localAminGroupRequest = convertToSnakeCaseObject(
130 | convertObjectField(JSON.parse(localAdminGroupRequestStr), {
131 | groupFaceURL: 'face_url',
132 | userFaceURL: 'user_face_url',
133 | handledMsg: 'handle_msg',
134 | handledTime: 'handle_time',
135 | })
136 | ) as LocalGroupRequest;
137 |
138 | databaseInsertAdminGroupRequest(db, localAminGroupRequest);
139 |
140 | return formatResponse('');
141 | } catch (e) {
142 | console.error(e);
143 |
144 | return formatResponse(
145 | undefined,
146 | DatabaseErrorCode.ErrorInit,
147 | JSON.stringify(e)
148 | );
149 | }
150 | }
151 |
152 | export async function deleteAdminGroupRequest(
153 | groupID: string,
154 | userID: string
155 | ): Promise {
156 | try {
157 | const db = await getInstance();
158 |
159 | databaseDeleteAdminGroupRequest(db, groupID, userID);
160 |
161 | return formatResponse('');
162 | } catch (e) {
163 | console.error(e);
164 |
165 | return formatResponse(
166 | undefined,
167 | DatabaseErrorCode.ErrorInit,
168 | JSON.stringify(e)
169 | );
170 | }
171 | }
172 |
173 | export async function updateAdminGroupRequest(
174 | localGroupRequestStr: string
175 | ): Promise {
176 | try {
177 | const db = await getInstance();
178 | const localGroupRequest = convertToSnakeCaseObject(
179 | convertObjectField(JSON.parse(localGroupRequestStr), {
180 | groupFaceURL: 'face_url',
181 | userFaceURL: 'user_face_url',
182 | handledMsg: 'handle_msg',
183 | handledTime: 'handle_time',
184 | })
185 | ) as LocalGroupRequest;
186 | databaseUpdateAdminGroupRequest(db, localGroupRequest);
187 |
188 | return formatResponse('');
189 | } catch (e) {
190 | console.error(e);
191 |
192 | return formatResponse(
193 | undefined,
194 | DatabaseErrorCode.ErrorInit,
195 | JSON.stringify(e)
196 | );
197 | }
198 | }
199 |
200 | export async function getAdminGroupApplication(): Promise {
201 | try {
202 | const db = await getInstance();
203 |
204 | const execResult = databaseGetAdminGroupApplication(db);
205 |
206 | return formatResponse(
207 | converSqlExecResult(execResult[0], 'CamelCase', [], {
208 | face_url: 'groupFaceURL',
209 | user_face_url: 'userFaceURL',
210 | handle_msg: 'handledMsg',
211 | handle_time: 'handledTime',
212 | })
213 | );
214 | } catch (e) {
215 | console.error(e);
216 |
217 | return formatResponse(
218 | undefined,
219 | DatabaseErrorCode.ErrorInit,
220 | JSON.stringify(e)
221 | );
222 | }
223 | }
224 |
--------------------------------------------------------------------------------
/src/api/database/groups.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | insertGroup as databaseInsertGroup,
4 | deleteGroup as databasedeleteGroup,
5 | updateGroup as databaseupdateGroup,
6 | getJoinedGroupList as databaseGetJoinedGroupList,
7 | getGroupInfoByGroupID as databaseGetGroupInfoByGroupID,
8 | getGroupMemberAllGroupIDs as databaseGetGroupMemberAllGroupIDs,
9 | getAllGroupInfoByGroupIDOrGroupName as databaseGetAllGroupInfoByGroupIDOrGroupName,
10 | subtractMemberCount as databaseSubtractMemberCount,
11 | addMemberCount as databaseAddMemberCount,
12 | getGroups as databaseGetGroups,
13 | deleteAllGroup as databaseDeleteAllGroup,
14 | LocalGroup,
15 | } from '@/sqls';
16 | import {
17 | converSqlExecResult,
18 | convertObjectField,
19 | convertToSnakeCaseObject,
20 | formatResponse,
21 | } from '@/utils';
22 | import { getInstance } from './instance';
23 |
24 | export async function insertGroup(localGroupStr: string): Promise {
25 | try {
26 | const db = await getInstance();
27 |
28 | const localGroup = convertToSnakeCaseObject(
29 | convertObjectField(JSON.parse(localGroupStr), { groupName: 'name' })
30 | ) as LocalGroup;
31 |
32 | databaseInsertGroup(db, localGroup);
33 |
34 | return formatResponse('');
35 | } catch (e) {
36 | console.error(e);
37 |
38 | return formatResponse(
39 | undefined,
40 | DatabaseErrorCode.ErrorInit,
41 | JSON.stringify(e)
42 | );
43 | }
44 | }
45 |
46 | export async function deleteGroup(groupID: string): Promise {
47 | try {
48 | const db = await getInstance();
49 |
50 | databasedeleteGroup(db, groupID);
51 |
52 | return formatResponse('');
53 | } catch (e) {
54 | console.error(e);
55 |
56 | return formatResponse(
57 | undefined,
58 | DatabaseErrorCode.ErrorInit,
59 | JSON.stringify(e)
60 | );
61 | }
62 | }
63 |
64 | export async function updateGroup(
65 | groupID: string,
66 | localGroupStr: string
67 | ): Promise {
68 | try {
69 | const db = await getInstance();
70 |
71 | const localGroup = convertToSnakeCaseObject(
72 | convertObjectField(JSON.parse(localGroupStr), { groupName: 'name' })
73 | ) as LocalGroup;
74 |
75 | databaseupdateGroup(db, groupID, localGroup);
76 |
77 | return formatResponse('');
78 | } catch (e) {
79 | console.error(e);
80 |
81 | return formatResponse(
82 | undefined,
83 | DatabaseErrorCode.ErrorInit,
84 | JSON.stringify(e)
85 | );
86 | }
87 | }
88 |
89 | export async function getJoinedGroupList(): Promise {
90 | try {
91 | const db = await getInstance();
92 |
93 | const execResult = databaseGetJoinedGroupList(db);
94 |
95 | return formatResponse(
96 | converSqlExecResult(execResult[0], 'CamelCase', ['displayIsRead'], {
97 | name: 'groupName',
98 | })
99 | );
100 | } catch (e) {
101 | console.error(e);
102 |
103 | return formatResponse(
104 | undefined,
105 | DatabaseErrorCode.ErrorInit,
106 | JSON.stringify(e)
107 | );
108 | }
109 | }
110 |
111 | export async function getGroupInfoByGroupID(groupID: string): Promise {
112 | try {
113 | const db = await getInstance();
114 |
115 | const execResult = databaseGetGroupInfoByGroupID(db, groupID);
116 |
117 | if (execResult.length === 0) {
118 | return formatResponse(
119 | '',
120 | DatabaseErrorCode.ErrorNoRecord,
121 | `no group with id ${groupID}`
122 | );
123 | }
124 |
125 | return formatResponse(
126 | converSqlExecResult(execResult[0], 'CamelCase', ['displayIsRead'], {
127 | name: 'groupName',
128 | })[0]
129 | );
130 | } catch (e) {
131 | console.error(e);
132 |
133 | return formatResponse(
134 | undefined,
135 | DatabaseErrorCode.ErrorInit,
136 | JSON.stringify(e)
137 | );
138 | }
139 | }
140 |
141 | export async function getAllGroupInfoByGroupIDOrGroupName(
142 | keyword: string,
143 | isSearchGroupID: boolean,
144 | isSearchGroupName: boolean
145 | ): Promise {
146 | try {
147 | const db = await getInstance();
148 |
149 | const execResult = databaseGetAllGroupInfoByGroupIDOrGroupName(
150 | db,
151 | keyword,
152 | isSearchGroupID,
153 | isSearchGroupName
154 | );
155 |
156 | return formatResponse(
157 | converSqlExecResult(execResult[0], 'CamelCase', ['displayIsRead'], {
158 | name: 'groupName',
159 | })
160 | );
161 | } catch (e) {
162 | console.error(e);
163 |
164 | return formatResponse(
165 | undefined,
166 | DatabaseErrorCode.ErrorInit,
167 | JSON.stringify(e)
168 | );
169 | }
170 | }
171 |
172 | export async function subtractMemberCount(groupID: string): Promise {
173 | try {
174 | const db = await getInstance();
175 |
176 | databaseSubtractMemberCount(db, groupID);
177 |
178 | return formatResponse('');
179 | } catch (e) {
180 | console.error(e);
181 |
182 | return formatResponse(
183 | undefined,
184 | DatabaseErrorCode.ErrorInit,
185 | JSON.stringify(e)
186 | );
187 | }
188 | }
189 |
190 | export async function addMemberCount(groupID: string): Promise {
191 | try {
192 | const db = await getInstance();
193 |
194 | databaseAddMemberCount(db, groupID);
195 |
196 | return formatResponse('');
197 | } catch (e) {
198 | console.error(e);
199 |
200 | return formatResponse(
201 | undefined,
202 | DatabaseErrorCode.ErrorInit,
203 | JSON.stringify(e)
204 | );
205 | }
206 | }
207 |
208 | export async function getJoinedWorkingGroupIDList(): Promise {
209 | try {
210 | const db = await getInstance();
211 |
212 | const execResult = databaseGetJoinedGroupList(db);
213 | const allJoinedGroupList = converSqlExecResult(execResult[0], 'CamelCase', [
214 | 'displayIsRead',
215 | ]);
216 | const filterIDList = [] as string[];
217 | allJoinedGroupList.forEach(group => {
218 | if (group.groupType === 2) {
219 | filterIDList.push(group.groupID as string);
220 | }
221 | });
222 | return formatResponse(JSON.stringify(filterIDList));
223 | } catch (e) {
224 | console.error(e);
225 |
226 | return formatResponse(
227 | undefined,
228 | DatabaseErrorCode.ErrorInit,
229 | JSON.stringify(e)
230 | );
231 | }
232 | }
233 |
234 | export async function getJoinedWorkingGroupList(): Promise {
235 | try {
236 | const db = await getInstance();
237 |
238 | const execResult = databaseGetJoinedGroupList(db);
239 | const allJoinedGroupList = converSqlExecResult(
240 | execResult[0],
241 | 'CamelCase',
242 | ['displayIsRead'],
243 | { name: 'groupName' }
244 | );
245 | const filterList = allJoinedGroupList.filter(
246 | group => group.groupType === 2
247 | );
248 |
249 | return formatResponse(JSON.stringify(filterList));
250 | } catch (e) {
251 | console.error(e);
252 |
253 | return formatResponse(
254 | undefined,
255 | DatabaseErrorCode.ErrorInit,
256 | JSON.stringify(e)
257 | );
258 | }
259 | }
260 |
261 | export async function getGroupMemberAllGroupIDs(): Promise {
262 | try {
263 | const db = await getInstance();
264 |
265 | const execResult = databaseGetGroupMemberAllGroupIDs(db);
266 | return formatResponse(
267 | converSqlExecResult(execResult[0], 'CamelCase', ['displayIsRead']).map(
268 | item => item.groupID
269 | )
270 | );
271 | } catch (e) {
272 | console.error(e);
273 |
274 | return formatResponse(
275 | undefined,
276 | DatabaseErrorCode.ErrorInit,
277 | JSON.stringify(e)
278 | );
279 | }
280 | }
281 |
282 | export async function getGroups(groupIDListStr: string): Promise {
283 | try {
284 | const db = await getInstance();
285 |
286 | const execResult = databaseGetGroups(db, JSON.parse(groupIDListStr));
287 | const allJoinedGroupList = converSqlExecResult(
288 | execResult[0],
289 | 'CamelCase',
290 | ['displayIsRead'],
291 | { name: 'groupName' }
292 | );
293 | return formatResponse(JSON.stringify(allJoinedGroupList));
294 | } catch (e) {
295 | console.error(e);
296 |
297 | return formatResponse(
298 | undefined,
299 | DatabaseErrorCode.ErrorInit,
300 | JSON.stringify(e)
301 | );
302 | }
303 | }
304 |
305 | export async function batchInsertGroup(
306 | localGroupListStr: string
307 | ): Promise {
308 | try {
309 | const db = await getInstance();
310 |
311 | const list = JSON.parse(localGroupListStr) as LocalGroup[];
312 |
313 | list.map(item => {
314 | const localGroup = convertToSnakeCaseObject(
315 | convertObjectField(item, { groupName: 'name' })
316 | ) as LocalGroup;
317 | databaseInsertGroup(db, localGroup);
318 |
319 | return null;
320 | });
321 |
322 | return formatResponse('');
323 | } catch (e) {
324 | console.error(e);
325 |
326 | return formatResponse(
327 | undefined,
328 | DatabaseErrorCode.ErrorInit,
329 | JSON.stringify(e)
330 | );
331 | }
332 | }
333 |
334 | export async function deleteAllGroup(): Promise {
335 | try {
336 | const db = await getInstance();
337 |
338 | databaseDeleteAllGroup(db);
339 |
340 | return formatResponse('');
341 | } catch (e) {
342 | console.error(e);
343 |
344 | return formatResponse(
345 | undefined,
346 | DatabaseErrorCode.ErrorInit,
347 | JSON.stringify(e)
348 | );
349 | }
350 | }
351 |
--------------------------------------------------------------------------------
/src/api/database/index.ts:
--------------------------------------------------------------------------------
1 | export * from './init';
2 | export * from './message';
3 | export * from './conversation';
4 | export * from './users';
5 | export * from './superGroup';
6 | export * from './unreadMessage';
7 | export * from './black';
8 | export * from './friend';
9 | export * from './friendRequest';
10 | export * from './groups';
11 | export * from './groupRequest';
12 | export * from './groupMember';
13 | export * from './tempCacheChatLogs';
14 | export * from './upload';
15 | export * from './stranger';
16 | export * from './sendingMessages';
17 | export * from './localAppSdkVersion';
18 | export * from './versionSync';
19 | export * from './notification';
20 | export * from './tableMaster';
21 |
--------------------------------------------------------------------------------
/src/api/database/init.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | locaBlacks,
4 | localFriends,
5 | localGroups,
6 | localFriendRequests,
7 | localGroupRequests,
8 | localAdminGroupRequests,
9 | localConversations,
10 | localUsers,
11 | localSuperGroups,
12 | localConversationUnreadMessages,
13 | localGroupMembers,
14 | tempCacheLocalChatLogs,
15 | localNotification,
16 | localUploads,
17 | localStranger,
18 | localSendingMessages,
19 | localAppSDKVersions,
20 | localVersionSyncs,
21 | } from '@/sqls';
22 | import { formatResponse } from '@/utils';
23 | import { QueryExecResult } from '@jlongster/sql.js';
24 | import { getInstance, resetInstance } from './instance';
25 | import { alterTable } from './alter';
26 |
27 | let sqlWasmPath: string;
28 |
29 | export function setSqlWasmPath(wasmPath: string) {
30 | sqlWasmPath = wasmPath;
31 | }
32 |
33 | export async function init(userId: string, dir: string): Promise {
34 | // console.info(
35 | // `=> (database api) invoke init with args ${JSON.stringify({
36 | // userId,
37 | // dir,
38 | // })}`
39 | // );
40 |
41 | try {
42 | // console.time('SDK => (performance measure) init database used ');
43 |
44 | const db = await getInstance(`${dir}${userId}.sqlite`, sqlWasmPath);
45 | const results: QueryExecResult[][] = [];
46 | const execResultLocalUploads = localUploads(db);
47 | const execResultLocalStrangers = localStranger(db);
48 | const execResultLocalConversations = localConversations(db);
49 | const execResultLocalUsers = localUsers(db);
50 | const execResultLocalBlack = locaBlacks(db);
51 | const execResultLocalFriend = localFriends(db);
52 | const execResuLocalGroup = localGroups(db);
53 | const execResuLocalGroupRequest = localGroupRequests(db);
54 | const execResuLocalGroupMembers = localGroupMembers(db);
55 | const execResuLocalAdminGroupRequest = localAdminGroupRequests(db);
56 | const execResultlocaFendRequest = localFriendRequests(db);
57 | const execResultLocalSuperGroups = localSuperGroups(db);
58 | const execResultTempCacheLocalChatLogs = tempCacheLocalChatLogs(db);
59 | const execResultLocalNotification = localNotification(db);
60 | const execResultLocalSendMessages = localSendingMessages(db);
61 | const execResultLocalConversationUnreadMessages =
62 | localConversationUnreadMessages(db);
63 | const execResultLocalAppSDKVersions = localAppSDKVersions(db);
64 | const execResultLocalVersionSync = localVersionSyncs(db);
65 | alterTable(db);
66 | results.push(
67 | ...[
68 | execResultLocalUploads,
69 | execResultLocalStrangers,
70 | execResultLocalConversations,
71 | execResultLocalUsers,
72 | execResultLocalSuperGroups,
73 | execResultLocalConversationUnreadMessages,
74 | execResultLocalBlack,
75 | execResultLocalFriend,
76 | execResuLocalGroup,
77 | execResuLocalGroupMembers,
78 | execResultlocaFendRequest,
79 | execResuLocalGroupRequest,
80 | execResuLocalAdminGroupRequest,
81 | execResultTempCacheLocalChatLogs,
82 | execResultLocalNotification,
83 | execResultLocalSendMessages,
84 | execResultLocalAppSDKVersions,
85 | execResultLocalVersionSync,
86 | ]
87 | );
88 |
89 | return formatResponse(results);
90 | } catch (e) {
91 | console.error(e);
92 |
93 | return formatResponse(
94 | undefined,
95 | DatabaseErrorCode.ErrorInit,
96 | JSON.stringify(e)
97 | );
98 | } finally {
99 | // console.timeEnd('SDK => (performance measure) init database used ');
100 | }
101 | }
102 |
103 | export async function close() {
104 | // console.info('=> (database api) invoke close');
105 |
106 | try {
107 | await resetInstance();
108 |
109 | return formatResponse('');
110 | } catch (e) {
111 | console.error(e);
112 |
113 | return formatResponse(
114 | undefined,
115 | DatabaseErrorCode.ErrorInit,
116 | JSON.stringify(e)
117 | );
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/api/database/instance.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unsafe-member-access */
2 | /* eslint-disable @typescript-eslint/no-unsafe-call */
3 | import initSqlJs, { Database, SqlJsStatic } from '@jlongster/sql.js';
4 | import { SQLiteFS } from 'absurd-sql-optimized';
5 | import IndexedDBBackend from 'absurd-sql-optimized/dist/indexeddb-backend';
6 | (self as any).$RefreshReg$ = () => {};
7 | (self as any).$RefreshSig$ = () => () => {};
8 |
9 | let instance: Promise | undefined;
10 | let SQL: SqlJsStatic | undefined;
11 |
12 | async function InitializeDB(filePath: string, sqlWasmPath = '/sql-wasm.wasm') {
13 | if (!SQL) {
14 | SQL = await initSqlJs({ locateFile: () => sqlWasmPath });
15 | const sqlFS = new SQLiteFS(SQL.FS, new IndexedDBBackend());
16 |
17 | SQL.register_for_idb(sqlFS);
18 | SQL.FS.mkdir('/sql');
19 | SQL.FS.mount(sqlFS, {}, '/sql');
20 | }
21 |
22 | const path = `/sql/${filePath}`;
23 |
24 | const db = new SQL.Database(path, { filename: true });
25 |
26 | if (typeof SharedArrayBuffer === 'undefined') {
27 | // @ts-ignore
28 | const stream = SQL.FS.open(path, 'a+');
29 | await stream.node.contents.readIfFallback();
30 | // @ts-ignore
31 | SQL.FS.close(stream);
32 | }
33 |
34 | db.exec(`
35 | PRAGMA page_size=8192;
36 | PRAGMA journal_mode=MEMORY;
37 | `);
38 |
39 | return db;
40 | }
41 |
42 | export function getInstance(
43 | filePath?: string,
44 | sqlWasmPath?: string
45 | ): Promise {
46 | if (instance) {
47 | return instance;
48 | }
49 |
50 | if (!filePath) {
51 | throw new Error('must speciefic database file');
52 | }
53 |
54 | instance = new Promise((resolve, reject) => {
55 | const db = InitializeDB(filePath, sqlWasmPath);
56 | db.then(res => resolve(res)).catch(err => reject(err));
57 | });
58 |
59 | return instance;
60 | }
61 |
62 | export async function resetInstance() {
63 | if (!instance) {
64 | return;
65 | }
66 |
67 | const db = await instance;
68 |
69 | db.close();
70 | instance = undefined;
71 | }
72 |
--------------------------------------------------------------------------------
/src/api/database/localAppSdkVersion.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | LocalAppSDKVersion,
4 | getAppSDKVersion as databaseGetAppSDKVersion,
5 | insertAppSDKVersion as databaseInsertAppSDKVersion,
6 | updateAppSDKVersion as databaseUpdateAppSDKVersion,
7 | } from '@/sqls';
8 | import {
9 | converSqlExecResult,
10 | convertObjectField,
11 | convertToSnakeCaseObject,
12 | formatResponse,
13 | } from '@/utils';
14 | import { getInstance } from './instance';
15 |
16 | export async function getAppSDKVersion(): Promise {
17 | try {
18 | const db = await getInstance();
19 |
20 | const execResult = databaseGetAppSDKVersion(db);
21 |
22 | if (execResult.length === 0) {
23 | return formatResponse(
24 | '',
25 | DatabaseErrorCode.ErrorNoRecord,
26 | 'no app version with database'
27 | );
28 | }
29 |
30 | return formatResponse(
31 | converSqlExecResult(execResult[0], 'CamelCase', [])[0]
32 | );
33 | } catch (e) {
34 | console.error(e);
35 |
36 | return formatResponse(
37 | undefined,
38 | DatabaseErrorCode.ErrorInit,
39 | JSON.stringify(e)
40 | );
41 | }
42 | }
43 |
44 | export async function setAppSDKVersion(
45 | appSdkVersionStr: string
46 | ): Promise {
47 | try {
48 | const db = await getInstance();
49 |
50 | const localAppSDKVersion = convertToSnakeCaseObject(
51 | convertObjectField(JSON.parse(appSdkVersionStr))
52 | ) as LocalAppSDKVersion;
53 |
54 | const execResult = databaseGetAppSDKVersion(db);
55 |
56 | const result = converSqlExecResult(execResult[0], 'CamelCase', []);
57 | if (result[0] && result[0].version) {
58 | databaseUpdateAppSDKVersion(
59 | db,
60 | result[0].version as string,
61 | localAppSDKVersion
62 | );
63 | return formatResponse('');
64 | } else {
65 | databaseInsertAppSDKVersion(db, localAppSDKVersion);
66 | return formatResponse('');
67 | }
68 | } catch (e) {
69 | console.error(e);
70 |
71 | return formatResponse(
72 | undefined,
73 | DatabaseErrorCode.ErrorInit,
74 | JSON.stringify(e)
75 | );
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/api/database/notification.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | insertNotificationSeq as databaseInsertNotificationSeq,
4 | setNotificationSeq as databaseSetNotificationSeq,
5 | getNotificationAllSeqs as databaseGetNotificationAllSeqs,
6 | LocalNotification,
7 | } from '@/sqls';
8 | import { converSqlExecResult, formatResponse } from '@/utils';
9 | import { getInstance } from './instance';
10 |
11 | export async function setNotificationSeq(
12 | conversationID: string,
13 | seq: number
14 | ): Promise {
15 | try {
16 | const db = await getInstance();
17 | let execResult = databaseSetNotificationSeq(db, conversationID, seq);
18 |
19 | const modified = db.getRowsModified();
20 | if (modified === 0) {
21 | execResult = databaseInsertNotificationSeq(db, conversationID, seq);
22 | }
23 |
24 | return formatResponse(execResult[0]);
25 | } catch (e) {
26 | console.error(e);
27 |
28 | return formatResponse(
29 | undefined,
30 | DatabaseErrorCode.ErrorInit,
31 | JSON.stringify(e)
32 | );
33 | }
34 | }
35 |
36 | export async function getNotificationAllSeqs(): Promise {
37 | try {
38 | const db = await getInstance();
39 | const execResult = databaseGetNotificationAllSeqs(db);
40 |
41 | return formatResponse(converSqlExecResult(execResult[0], 'CamelCase'));
42 | } catch (e) {
43 | console.error(e);
44 |
45 | return formatResponse(
46 | undefined,
47 | DatabaseErrorCode.ErrorInit,
48 | JSON.stringify(e)
49 | );
50 | }
51 | }
52 |
53 | export async function batchInsertNotificationSeq(
54 | local_notification_seqs: string
55 | ): Promise {
56 | try {
57 | const list = JSON.parse(local_notification_seqs) as LocalNotification[];
58 | const db = await getInstance();
59 |
60 | list.map(item => {
61 | const { conversationID, seq } = item;
62 | databaseInsertNotificationSeq(db, conversationID, seq);
63 | });
64 |
65 | return formatResponse('');
66 | } catch (e) {
67 | console.error(e);
68 |
69 | return formatResponse(
70 | undefined,
71 | DatabaseErrorCode.ErrorInit,
72 | JSON.stringify(e)
73 | );
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/api/database/sendingMessages.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | LocalSendingMessage,
4 | insertSendingMessage as databaseInsertSendingMessage,
5 | deleteSendingMessage as databaseDeleteSendingMessage,
6 | getAllSendingMessages as datbaseGetAllSendingMessages,
7 | } from '@/sqls';
8 | import {
9 | converSqlExecResult,
10 | convertToSnakeCaseObject,
11 | formatResponse,
12 | } from '@/utils';
13 | import { getInstance } from './instance';
14 |
15 | export async function insertSendingMessage(
16 | sendMessageStr: string
17 | ): Promise {
18 | try {
19 | const db = await getInstance();
20 | const message = convertToSnakeCaseObject(
21 | JSON.parse(sendMessageStr)
22 | ) as LocalSendingMessage;
23 |
24 | const execResult = databaseInsertSendingMessage(db, message);
25 |
26 | return formatResponse(execResult);
27 | } catch (e) {
28 | console.error(e);
29 |
30 | return formatResponse(
31 | undefined,
32 | DatabaseErrorCode.ErrorInit,
33 | JSON.stringify(e)
34 | );
35 | }
36 | }
37 |
38 | export async function deleteSendingMessage(
39 | conversationID: string,
40 | clientMsgID: string
41 | ): Promise {
42 | try {
43 | const db = await getInstance();
44 |
45 | const execResult = databaseDeleteSendingMessage(
46 | db,
47 | conversationID,
48 | clientMsgID
49 | );
50 |
51 | return formatResponse(execResult);
52 | } catch (e) {
53 | console.error(e);
54 |
55 | return formatResponse(
56 | undefined,
57 | DatabaseErrorCode.ErrorInit,
58 | JSON.stringify(e)
59 | );
60 | }
61 | }
62 |
63 | export async function getAllSendingMessages(): Promise {
64 | try {
65 | const db = await getInstance();
66 |
67 | const execResult = datbaseGetAllSendingMessages(db);
68 |
69 | return formatResponse(
70 | converSqlExecResult(execResult[0], 'CamelCase', [
71 | 'isRead',
72 | 'isReact',
73 | 'isExternalExtensions',
74 | ])
75 | );
76 | } catch (e) {
77 | console.error(e);
78 |
79 | return formatResponse(
80 | undefined,
81 | DatabaseErrorCode.ErrorInit,
82 | JSON.stringify(e)
83 | );
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/api/database/stranger.ts:
--------------------------------------------------------------------------------
1 | import {
2 | LocalStranger,
3 | getStrangerInfo as databaseGetStrangerInfo,
4 | insertStrangerInfo as databseInsertStrangerInfo,
5 | updateStrangerInfo as databaseUpdateStrangerInfo,
6 | } from '@/sqls';
7 | import { getInstance } from './instance';
8 | import {
9 | converSqlExecResult,
10 | convertObjectField,
11 | convertToSnakeCaseObject,
12 | formatResponse,
13 | } from '@/utils';
14 | import { DatabaseErrorCode } from '@/constant';
15 |
16 | export async function getStrangerInfo(userIDListStr: string): Promise {
17 | try {
18 | const db = await getInstance();
19 | const execResult = databaseGetStrangerInfo(db, JSON.parse(userIDListStr));
20 |
21 | return formatResponse(
22 | converSqlExecResult(execResult[0], 'CamelCase', [], {
23 | name: 'nickname',
24 | })
25 | );
26 | } catch (e) {
27 | console.error(e);
28 |
29 | return formatResponse(
30 | undefined,
31 | DatabaseErrorCode.ErrorInit,
32 | JSON.stringify(e)
33 | );
34 | }
35 | }
36 |
37 | export function setStrangerInfo(
38 | localStrangerInfoListStr: string
39 | ): Promise {
40 | try {
41 | const localStrangerInfoList = (
42 | JSON.parse(localStrangerInfoListStr) as LocalStranger[]
43 | ).map(
44 | item =>
45 | convertToSnakeCaseObject(
46 | convertObjectField(item, {
47 | nickname: 'name',
48 | })
49 | ) as LocalStranger
50 | );
51 | localStrangerInfoList.map((localStrangerInfo: LocalStranger) =>
52 | setSingleStrangerInfo(localStrangerInfo)
53 | );
54 |
55 | return Promise.resolve(formatResponse(''));
56 | } catch (e) {
57 | console.error(e);
58 |
59 | return Promise.resolve(
60 | formatResponse(undefined, DatabaseErrorCode.ErrorInit, JSON.stringify(e))
61 | );
62 | }
63 | }
64 |
65 | export async function setSingleStrangerInfo(
66 | localStrangerInfo: LocalStranger
67 | ): Promise {
68 | try {
69 | const db = await getInstance();
70 |
71 | const execResult = databaseGetStrangerInfo(db, [localStrangerInfo.user_id]);
72 | const result = converSqlExecResult(execResult[0]);
73 | if (result.length) {
74 | databaseUpdateStrangerInfo(db, localStrangerInfo);
75 | } else {
76 | databseInsertStrangerInfo(db, localStrangerInfo);
77 | }
78 | return formatResponse('');
79 | } catch (e) {
80 | console.error(e);
81 |
82 | return formatResponse(
83 | undefined,
84 | DatabaseErrorCode.ErrorInit,
85 | JSON.stringify(e)
86 | );
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/api/database/superGroup.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | getJoinedSuperGroupList as databaseGetJoinedSuperGroupList,
4 | insertSuperGroup as databaseInsertSuperGroup,
5 | updateSuperGroup as databaseUpdateSuperGroup,
6 | deleteSuperGroup as databaseDeleteSuperGroup,
7 | getSuperGroupInfoByGroupID as databaseGetSuperGroupInfoByGroupID,
8 | ClientGroup,
9 | } from '@/sqls';
10 | import {
11 | formatResponse,
12 | converSqlExecResult,
13 | convertToSnakeCaseObject,
14 | convertObjectField,
15 | } from '@/utils';
16 | import { getInstance } from './instance';
17 |
18 | export async function getJoinedSuperGroupList(): Promise {
19 | try {
20 | const db = await getInstance();
21 |
22 | const execResult = databaseGetJoinedSuperGroupList(db);
23 |
24 | return formatResponse(converSqlExecResult(execResult[0]));
25 | } catch (e) {
26 | console.error(e);
27 |
28 | return formatResponse(
29 | undefined,
30 | DatabaseErrorCode.ErrorInit,
31 | JSON.stringify(e)
32 | );
33 | }
34 | }
35 |
36 | export async function getJoinedSuperGroupIDList(): Promise {
37 | try {
38 | const db = await getInstance();
39 |
40 | const execResult = databaseGetJoinedSuperGroupList(db);
41 | const records = converSqlExecResult(execResult[0]);
42 | const groupIds = records.map(r => r.groupID);
43 |
44 | return formatResponse(groupIds);
45 | } catch (e) {
46 | console.error(e);
47 |
48 | return formatResponse(
49 | undefined,
50 | DatabaseErrorCode.ErrorInit,
51 | JSON.stringify(e)
52 | );
53 | }
54 | }
55 |
56 | export async function getSuperGroupInfoByGroupID(
57 | groupID: string
58 | ): Promise {
59 | try {
60 | const db = await getInstance();
61 |
62 | const execResult = databaseGetSuperGroupInfoByGroupID(db, groupID);
63 |
64 | if (execResult.length === 0) {
65 | return formatResponse(
66 | '',
67 | DatabaseErrorCode.ErrorNoRecord,
68 | `no super group with id ${groupID}`
69 | );
70 | }
71 |
72 | return formatResponse(converSqlExecResult(execResult[0])[0]);
73 | } catch (e) {
74 | console.error(e);
75 |
76 | return formatResponse(
77 | undefined,
78 | DatabaseErrorCode.ErrorInit,
79 | JSON.stringify(e)
80 | );
81 | }
82 | }
83 |
84 | export async function deleteSuperGroup(groupID: string): Promise {
85 | try {
86 | const db = await getInstance();
87 |
88 | const execResult = databaseDeleteSuperGroup(db, groupID);
89 |
90 | return formatResponse(execResult);
91 | } catch (e) {
92 | console.error(e);
93 |
94 | return formatResponse(
95 | undefined,
96 | DatabaseErrorCode.ErrorInit,
97 | JSON.stringify(e)
98 | );
99 | }
100 | }
101 |
102 | export async function insertSuperGroup(groupStr: string): Promise {
103 | try {
104 | const db = await getInstance();
105 | const group = convertToSnakeCaseObject(
106 | convertObjectField(JSON.parse(groupStr), { groupName: 'name' })
107 | ) as ClientGroup;
108 |
109 | const execResult = databaseInsertSuperGroup(db, group);
110 |
111 | return formatResponse(execResult);
112 | } catch (e) {
113 | console.error(e);
114 |
115 | return formatResponse(
116 | undefined,
117 | DatabaseErrorCode.ErrorInit,
118 | JSON.stringify(e)
119 | );
120 | }
121 | }
122 |
123 | export async function updateSuperGroup(
124 | groupID: string,
125 | groupStr: string
126 | ): Promise {
127 | try {
128 | const db = await getInstance();
129 | const group = convertToSnakeCaseObject(
130 | convertObjectField(JSON.parse(groupStr), { groupName: 'name' })
131 | ) as ClientGroup;
132 |
133 | const execResult = databaseUpdateSuperGroup(db, groupID, group);
134 | const modifed = db.getRowsModified();
135 | if (modifed === 0) {
136 | throw 'updateSuperGroup no record updated';
137 | }
138 |
139 | return formatResponse(execResult);
140 | } catch (e) {
141 | console.error(e);
142 |
143 | return formatResponse(
144 | undefined,
145 | DatabaseErrorCode.ErrorInit,
146 | JSON.stringify(e)
147 | );
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/src/api/database/tableMaster.ts:
--------------------------------------------------------------------------------
1 | import { converSqlExecResult, formatResponse } from '@/utils';
2 | import { getExistedTables as databaseGetExistedTables } from '@/sqls';
3 | import { DatabaseErrorCode } from '@/constant';
4 | import { getInstance } from './instance';
5 |
6 | export async function getExistedTables(): Promise {
7 | try {
8 | const db = await getInstance();
9 |
10 | const execResult = databaseGetExistedTables(db);
11 |
12 | return formatResponse(
13 | converSqlExecResult(execResult[0], 'CamelCase', [], {
14 | tbl_name: 'tblName',
15 | })
16 | );
17 | } catch (e) {
18 | console.error(e);
19 |
20 | return formatResponse(
21 | undefined,
22 | DatabaseErrorCode.ErrorInit,
23 | JSON.stringify(e)
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/api/database/tempCacheChatLogs.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | TempCacheClientMessage,
4 | batchInsertTempCacheMessageList as databseBatchInsertTempCacheMessageList,
5 | } from '@/sqls';
6 | import { convertToSnakeCaseObject, formatResponse } from '@/utils';
7 | import { getInstance } from './instance';
8 |
9 | export async function batchInsertTempCacheMessageList(
10 | messageListStr: string
11 | ): Promise {
12 | try {
13 | const db = await getInstance();
14 | const messageList = (
15 | JSON.parse(messageListStr) as TempCacheClientMessage[]
16 | ).map((v: Record) => convertToSnakeCaseObject(v));
17 |
18 | const execResult = databseBatchInsertTempCacheMessageList(db, messageList);
19 |
20 | return formatResponse(execResult[0]);
21 | } catch (e) {
22 | console.error(e);
23 |
24 | return formatResponse(
25 | undefined,
26 | DatabaseErrorCode.ErrorInit,
27 | JSON.stringify(e)
28 | );
29 | }
30 | }
31 |
32 | export async function InsertTempCacheMessage(
33 | messageStr: string
34 | ): Promise {
35 | return batchInsertTempCacheMessageList(`[${messageStr}]`);
36 | }
37 |
--------------------------------------------------------------------------------
/src/api/database/unreadMessage.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | ClientLocalConversationUnreadMessage,
4 | batchInsertConversationUnreadMessageList as databaseBatchInsertConversationUnreadMessageList,
5 | deleteConversationUnreadMessageList as databaseDeleteConversationUnreadMessageList,
6 | } from '@/sqls';
7 | import { convertToSnakeCaseObject, formatResponse } from '@/utils';
8 | import { getInstance } from './instance';
9 |
10 | export async function deleteConversationUnreadMessageList(
11 | conversationID: string,
12 | sendTime: number
13 | ): Promise {
14 | try {
15 | const db = await getInstance();
16 |
17 | databaseDeleteConversationUnreadMessageList(db, conversationID, sendTime);
18 | const modifed = db.getRowsModified();
19 |
20 | return formatResponse(modifed);
21 | } catch (e) {
22 | console.error(e);
23 |
24 | return formatResponse(
25 | undefined,
26 | DatabaseErrorCode.ErrorInit,
27 | JSON.stringify(e)
28 | );
29 | }
30 | }
31 |
32 | export async function batchInsertConversationUnreadMessageList(
33 | messageListStr: string
34 | ): Promise {
35 | try {
36 | const db = await getInstance();
37 | const messageList = (
38 | JSON.parse(messageListStr) as ClientLocalConversationUnreadMessage[]
39 | ).map((v: Record) => convertToSnakeCaseObject(v));
40 |
41 | const execResult = databaseBatchInsertConversationUnreadMessageList(
42 | db,
43 | messageList
44 | );
45 |
46 | return formatResponse(execResult[0]);
47 | } catch (e) {
48 | console.error(e);
49 |
50 | return formatResponse(
51 | undefined,
52 | DatabaseErrorCode.ErrorInit,
53 | JSON.stringify(e)
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/api/database/upload.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | ClientUpload,
4 | getUpload as databaseGetUpload,
5 | insertUpload as databaseInsertUpload,
6 | updateUpload as databaseUpdateUpload,
7 | deleteUpload as databaseDeleteUpload,
8 | } from '@/sqls';
9 | import {
10 | converSqlExecResult,
11 | convertObjectField,
12 | convertToSnakeCaseObject,
13 | formatResponse,
14 | } from '@/utils';
15 | import { getInstance } from './instance';
16 |
17 | export async function getUpload(partHash: string): Promise {
18 | try {
19 | const db = await getInstance();
20 |
21 | const execResult = databaseGetUpload(db, partHash);
22 |
23 | const upload = converSqlExecResult(execResult[0], 'CamelCase');
24 | if (upload.length === 0) {
25 | throw `no upload with partHash = ${partHash}`;
26 | }
27 |
28 | return formatResponse(upload[0]);
29 | } catch (e) {
30 | console.error(e);
31 |
32 | return formatResponse(
33 | undefined,
34 | DatabaseErrorCode.ErrorInit,
35 | JSON.stringify(e)
36 | );
37 | }
38 | }
39 |
40 | export async function insertUpload(uploadStr: string): Promise {
41 | try {
42 | const db = await getInstance();
43 | const upload = convertToSnakeCaseObject(
44 | convertObjectField(JSON.parse(uploadStr))
45 | ) as ClientUpload;
46 |
47 | const execResult = databaseInsertUpload(db, upload);
48 |
49 | return formatResponse(execResult);
50 | } catch (e) {
51 | console.error(e);
52 |
53 | return formatResponse(
54 | undefined,
55 | DatabaseErrorCode.ErrorInit,
56 | JSON.stringify(e)
57 | );
58 | }
59 | }
60 |
61 | export async function updateUpload(uploadStr: string): Promise {
62 | try {
63 | const db = await getInstance();
64 | const upload = convertToSnakeCaseObject(
65 | convertObjectField(JSON.parse(uploadStr))
66 | ) as ClientUpload;
67 |
68 | const execResult = databaseUpdateUpload(db, upload);
69 |
70 | return formatResponse(execResult);
71 | } catch (e) {
72 | console.error(e);
73 |
74 | return formatResponse(
75 | undefined,
76 | DatabaseErrorCode.ErrorInit,
77 | JSON.stringify(e)
78 | );
79 | }
80 | }
81 |
82 | export async function deleteUpload(partHash: string): Promise {
83 | try {
84 | const db = await getInstance();
85 |
86 | const execResult = databaseDeleteUpload(db, partHash);
87 |
88 | return formatResponse(execResult);
89 | } catch (e) {
90 | console.error(e);
91 |
92 | return formatResponse(
93 | undefined,
94 | DatabaseErrorCode.ErrorInit,
95 | JSON.stringify(e)
96 | );
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/api/database/users.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | ClientUser,
4 | getLoginUser as databaseGetLoginUser,
5 | insertLoginUser as databaseInsertLoginUser,
6 | updateLoginUser as databaseUpdateLoginUser,
7 | } from '@/sqls';
8 | import {
9 | formatResponse,
10 | converSqlExecResult,
11 | convertToSnakeCaseObject,
12 | convertObjectField,
13 | } from '@/utils';
14 | import { getInstance } from './instance';
15 |
16 | export async function getLoginUser(userID: string): Promise {
17 | try {
18 | const db = await getInstance();
19 |
20 | const execResult = databaseGetLoginUser(db, userID);
21 |
22 | if (execResult.length === 0) {
23 | return formatResponse(
24 | '',
25 | DatabaseErrorCode.ErrorNoRecord,
26 | `no login user with id ${userID}`
27 | );
28 | }
29 |
30 | return formatResponse(
31 | converSqlExecResult(execResult[0], 'CamelCase', [], {
32 | name: 'nickname',
33 | })[0]
34 | );
35 | } catch (e) {
36 | console.error(e);
37 |
38 | return formatResponse(
39 | undefined,
40 | DatabaseErrorCode.ErrorInit,
41 | JSON.stringify(e)
42 | );
43 | }
44 | }
45 |
46 | export async function insertLoginUser(userStr: string): Promise {
47 | try {
48 | const db = await getInstance();
49 | const user = convertToSnakeCaseObject(
50 | convertObjectField(JSON.parse(userStr), { nickname: 'name' })
51 | ) as ClientUser;
52 |
53 | const execResult = databaseInsertLoginUser(db, user);
54 |
55 | return formatResponse(execResult);
56 | } catch (e) {
57 | console.error(e);
58 |
59 | return formatResponse(
60 | undefined,
61 | DatabaseErrorCode.ErrorInit,
62 | JSON.stringify(e)
63 | );
64 | }
65 | }
66 |
67 | export async function updateLoginUser(userStr: string): Promise {
68 | try {
69 | const db = await getInstance();
70 | const user = convertToSnakeCaseObject(
71 | convertObjectField(JSON.parse(userStr), { nickname: 'name' })
72 | ) as ClientUser;
73 |
74 | const execResult = databaseUpdateLoginUser(db, user);
75 | const modifed = db.getRowsModified();
76 | if (modifed === 0) {
77 | throw 'updateLoginUser no record updated';
78 | }
79 | return formatResponse(execResult);
80 | } catch (e) {
81 | console.error(e);
82 |
83 | return formatResponse(
84 | undefined,
85 | DatabaseErrorCode.ErrorInit,
86 | JSON.stringify(e)
87 | );
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/api/database/versionSync.ts:
--------------------------------------------------------------------------------
1 | import { DatabaseErrorCode } from '@/constant';
2 | import {
3 | LocalVersionSync,
4 | getVersionSync as databaseGetVersionSync,
5 | insertVersionSync as databaseInsertVersionSync,
6 | updateVersionSync as databaseUpdateVersionSync,
7 | deleteVersionSync as databaseDeleteVersionSync,
8 | } from '@/sqls';
9 | import {
10 | converSqlExecResult,
11 | convertObjectField,
12 | convertToSnakeCaseObject,
13 | formatResponse,
14 | } from '@/utils';
15 | import { getInstance } from './instance';
16 |
17 | export async function getVersionSync(
18 | tableName: string,
19 | entityID: string
20 | ): Promise {
21 | try {
22 | const db = await getInstance();
23 |
24 | const execResult = databaseGetVersionSync(db, tableName, entityID);
25 |
26 | if (execResult.length === 0) {
27 | return formatResponse(
28 | '',
29 | DatabaseErrorCode.ErrorNoRecord,
30 | `no sync version with tableName ${tableName}, entityID ${entityID}`
31 | );
32 | }
33 |
34 | const result = converSqlExecResult(execResult[0], 'CamelCase', [], {
35 | id_list: 'uidList',
36 | })[0];
37 | result.uidList = JSON.parse(result.uidList as string);
38 |
39 | return formatResponse(result);
40 | } catch (e) {
41 | console.error(e);
42 |
43 | return formatResponse(
44 | undefined,
45 | DatabaseErrorCode.ErrorInit,
46 | JSON.stringify(e)
47 | );
48 | }
49 | }
50 |
51 | export async function setVersionSync(versionSyncStr: string): Promise {
52 | try {
53 | const db = await getInstance();
54 |
55 | const localVersionSync = convertToSnakeCaseObject(
56 | convertObjectField(JSON.parse(versionSyncStr))
57 | ) as LocalVersionSync;
58 |
59 | localVersionSync.id_list = JSON.stringify(localVersionSync.uid_list);
60 | delete localVersionSync.uid_list;
61 |
62 | const execResult = databaseGetVersionSync(
63 | db,
64 | localVersionSync.table_name,
65 | localVersionSync.entity_id
66 | );
67 | const result = converSqlExecResult(execResult[0], 'CamelCase', []);
68 |
69 | if (result[0] && result[0].tableName) {
70 | databaseUpdateVersionSync(
71 | db,
72 | result[0].tableName as string,
73 | result[0].entityID as string,
74 | localVersionSync
75 | );
76 | return formatResponse('');
77 | } else {
78 | databaseInsertVersionSync(db, localVersionSync);
79 | return formatResponse('');
80 | }
81 | } catch (e) {
82 | console.error(e);
83 |
84 | return formatResponse(
85 | undefined,
86 | DatabaseErrorCode.ErrorInit,
87 | JSON.stringify(e)
88 | );
89 | }
90 | }
91 |
92 | export async function deleteVersionSync(
93 | tablename: string,
94 | entityID: string
95 | ): Promise {
96 | try {
97 | const db = await getInstance();
98 |
99 | databaseDeleteVersionSync(db, tablename, entityID);
100 |
101 | return formatResponse('');
102 | } catch (e) {
103 | console.error(e);
104 |
105 | return formatResponse(
106 | undefined,
107 | DatabaseErrorCode.ErrorInit,
108 | JSON.stringify(e)
109 | );
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/api/upload.ts:
--------------------------------------------------------------------------------
1 | import { formatResponse } from '@/utils';
2 |
3 | const fileMap = new Map();
4 |
5 | export const fileMapSet = (uuid: string, file: File) => {
6 | fileMap.set(uuid, file);
7 | return formatResponse(uuid);
8 | };
9 |
10 | export const fileMapClear = () => {
11 | fileMap.clear();
12 | return formatResponse('');
13 | };
14 |
15 | export const wasmOpen = (uuid: string) => {
16 | return new Promise((resolve, reject) => {
17 | const file = fileMap.get(uuid);
18 | if (!file) {
19 | reject('file not found');
20 | } else {
21 | resolve(formatResponse(file.size));
22 | }
23 | });
24 | };
25 |
26 | export const wasmClose = async (uuid: string) => {
27 | return new Promise(resolve => {
28 | fileMap.delete(uuid);
29 | resolve(formatResponse(uuid));
30 | });
31 | };
32 |
33 | export const wasmRead = (uuid: string, offset: number, length: number) => {
34 | const file = fileMap.get(uuid);
35 | if (!file) {
36 | throw 'file not found';
37 | }
38 | const blob = file.slice(offset, offset + length);
39 | return new Promise((resolve, reject) => {
40 | const reader = new FileReader();
41 | reader.onload = () => {
42 | resolve(reader.result);
43 | };
44 | reader.onerror = () => {
45 | reject(reader.error);
46 | };
47 | reader.readAsArrayBuffer(blob);
48 | });
49 | };
50 |
--------------------------------------------------------------------------------
/src/constant/index.ts:
--------------------------------------------------------------------------------
1 | export const DatabaseErrorCode = {
2 | ErrorInit: 10001,
3 | ErrorNoRecord: 10002,
4 | ErrorDBTimeout: 10003,
5 | };
6 |
7 | export enum CbEvents {
8 | Login = 'Login',
9 | OnConnectFailed = 'OnConnectFailed',
10 | OnConnectSuccess = 'OnConnectSuccess',
11 | OnConnecting = 'OnConnecting',
12 | OnKickedOffline = 'OnKickedOffline',
13 | OnSelfInfoUpdated = 'OnSelfInfoUpdated',
14 | OnUserTokenExpired = 'OnUserTokenExpired',
15 | OnUserTokenInvalid = 'OnUserTokenInvalid',
16 | OnProgress = 'OnProgress',
17 | OnRecvNewMessage = 'OnRecvNewMessage',
18 | OnRecvNewMessages = 'OnRecvNewMessages',
19 | OnRecvOnlineOnlyMessage = 'OnRecvOnlineOnlyMessage',
20 | OnRecvOfflineNewMessage = 'onRecvOfflineNewMessage',
21 | OnRecvOnlineOnlyMessages = 'OnRecvOnlineOnlyMessages',
22 | OnRecvOfflineNewMessages = 'onRecvOfflineNewMessages',
23 | OnRecvMessageRevoked = 'OnRecvMessageRevoked',
24 | OnNewRecvMessageRevoked = 'OnNewRecvMessageRevoked',
25 | OnRecvC2CReadReceipt = 'OnRecvC2CReadReceipt',
26 | OnRecvGroupReadReceipt = 'OnRecvGroupReadReceipt',
27 | OnConversationChanged = 'OnConversationChanged',
28 | OnNewConversation = 'OnNewConversation',
29 | OnConversationUserInputStatusChanged = 'OnConversationUserInputStatusChanged',
30 | OnSyncServerFailed = 'OnSyncServerFailed',
31 | OnSyncServerFinish = 'OnSyncServerFinish',
32 | OnSyncServerProgress = 'OnSyncServerProgress',
33 | OnSyncServerStart = 'OnSyncServerStart',
34 | OnTotalUnreadMessageCountChanged = 'OnTotalUnreadMessageCountChanged',
35 | OnBlackAdded = 'OnBlackAdded',
36 | OnBlackDeleted = 'OnBlackDeleted',
37 | OnFriendApplicationAccepted = 'OnFriendApplicationAccepted',
38 | OnFriendApplicationAdded = 'OnFriendApplicationAdded',
39 | OnFriendApplicationDeleted = 'OnFriendApplicationDeleted',
40 | OnFriendApplicationRejected = 'OnFriendApplicationRejected',
41 | OnFriendInfoChanged = 'OnFriendInfoChanged',
42 | OnFriendAdded = 'OnFriendAdded',
43 | OnFriendDeleted = 'OnFriendDeleted',
44 | OnJoinedGroupAdded = 'OnJoinedGroupAdded',
45 | OnJoinedGroupDeleted = 'OnJoinedGroupDeleted',
46 | OnGroupDismissed = 'OnGroupDismissed',
47 | OnGroupMemberAdded = 'OnGroupMemberAdded',
48 | OnGroupMemberDeleted = 'OnGroupMemberDeleted',
49 | OnGroupApplicationAdded = 'OnGroupApplicationAdded',
50 | OnGroupApplicationDeleted = 'OnGroupApplicationDeleted',
51 | OnGroupInfoChanged = 'OnGroupInfoChanged',
52 | OnGroupMemberInfoChanged = 'OnGroupMemberInfoChanged',
53 | OnGroupApplicationAccepted = 'OnGroupApplicationAccepted',
54 | OnGroupApplicationRejected = 'OnGroupApplicationRejected',
55 |
56 | UploadComplete = 'UploadComplete',
57 | OnRecvCustomBusinessMessage = 'OnRecvCustomBusinessMessage',
58 | OnUserStatusChanged = 'OnUserStatusChanged',
59 | OnUploadLogsProgress = 'OnUploadLogsProgress',
60 |
61 | // rtc
62 | OnReceiveNewInvitation = 'OnReceiveNewInvitation',
63 | OnInviteeAccepted = 'OnInviteeAccepted',
64 | OnInviteeRejected = 'OnInviteeRejected',
65 | OnInvitationCancelled = 'OnInvitationCancelled',
66 | OnHangUp = 'OnHangUp',
67 | OnInvitationTimeout = 'OnInvitationTimeout',
68 | OnInviteeAcceptedByOtherDevice = 'OnInviteeAcceptedByOtherDevice',
69 | OnInviteeRejectedByOtherDevice = 'OnInviteeRejectedByOtherDevice',
70 |
71 | // meeting
72 | OnStreamChange = 'OnStreamChange',
73 | OnRoomParticipantConnected = 'OnRoomParticipantConnected',
74 | OnRoomParticipantDisconnected = 'OnRoomParticipantDisconnected',
75 | OnReceiveCustomSignal = 'OnReceiveCustomSignal',
76 |
77 | // unuse
78 | UnUsedEvent = 'UnUsedEvent',
79 | }
80 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export { getSDK } from './sdk';
2 |
3 | export { CbEvents } from './constant';
4 | export * from './types/enum';
5 | export * from './types/entity';
6 | export * from './types/eventData';
7 | export * from './types/params';
8 |
--------------------------------------------------------------------------------
/src/sdk/initialize.ts:
--------------------------------------------------------------------------------
1 | import { wait } from '@/utils';
2 |
3 | let initialized = false;
4 | let go: Go;
5 | let goExitPromise: Promise | undefined;
6 |
7 | const CACHE_KEY = 'openim-wasm-cache';
8 |
9 | export async function initializeWasm(url: string): Promise {
10 | if (initialized) {
11 | return null;
12 | }
13 |
14 | if (typeof window === 'undefined') {
15 | return Promise.resolve(null);
16 | }
17 |
18 | go = new Go();
19 | let wasm;
20 | try {
21 | if ('instantiateStreaming' in WebAssembly) {
22 | wasm = await WebAssembly.instantiateStreaming(
23 | fetchWithCache(url),
24 | go.importObject
25 | );
26 | } else {
27 | const bytes = await fetchWithCache(url).then(resp => resp.arrayBuffer());
28 | wasm = await WebAssembly.instantiate(bytes, go.importObject);
29 | }
30 | go.run(wasm.instance);
31 | } catch (error) {
32 | console.error('Failed to initialize WASM:', error);
33 | return null;
34 | }
35 |
36 | await wait(100);
37 | initialized = true;
38 | return go;
39 | }
40 |
41 | export function reset() {
42 | initialized = false;
43 | }
44 |
45 | export function getGO() {
46 | return go;
47 | }
48 |
49 | export function getGoExitPromise() {
50 | return goExitPromise;
51 | }
52 |
53 | async function fetchWithCache(url: string): Promise {
54 | if (!('caches' in window)) {
55 | return fetch(url);
56 | }
57 |
58 | const isResourceUpdated = async () => {
59 | const serverResponse = await fetch(url, { method: 'HEAD' });
60 | const etag = serverResponse.headers.get('ETag');
61 | const lastModified = serverResponse.headers.get('Last-Modified');
62 | return (
63 | serverResponse.ok &&
64 | (etag !== cachedResponse?.headers.get('ETag') ||
65 | lastModified !== cachedResponse?.headers.get('Last-Modified'))
66 | );
67 | };
68 |
69 | const cache = await caches.open(CACHE_KEY);
70 | const cachedResponse = await cache.match(url);
71 | if (cachedResponse && !(await isResourceUpdated())) {
72 | return cachedResponse;
73 | }
74 |
75 | return fetchAndUpdateCache(url, cache);
76 | }
77 |
78 | async function fetchAndUpdateCache(
79 | url: string,
80 | cache: Cache
81 | ): Promise {
82 | const response = await fetch(url, { cache: 'no-cache' });
83 | try {
84 | await cache.put(url, response.clone());
85 | } catch (error) {
86 | console.warn('Failed to put cache');
87 | }
88 | return response;
89 | }
90 |
--------------------------------------------------------------------------------
/src/sqls/index.ts:
--------------------------------------------------------------------------------
1 | export * from './localChatLogsConversationID';
2 | export * from './localConversations';
3 | export * from './localUsers';
4 | export * from './localSuperGroups';
5 | export * from './localConversationUnreadMessages';
6 | export * from './localBlack';
7 | export * from './localFriend';
8 | export * from './localGroups';
9 | export * from './localGroupRequests';
10 | export * from './localAdminGroupRequests';
11 | export * from './localFriendRequest';
12 | export * from './localGroupMembers';
13 | export * from './tempCacheLocalChatLogs';
14 | export * from './localNotification';
15 | export * from './localUpload';
16 | export * from './localStranger';
17 | export * from './localSendingMessages';
18 | export * from './localAppSdkVersion';
19 | export * from './localVersionSync';
20 | export * from './localTableMaster';
21 |
--------------------------------------------------------------------------------
/src/sqls/localAdminGroupRequests.ts:
--------------------------------------------------------------------------------
1 | import { Database, QueryExecResult } from '@jlongster/sql.js';
2 | import squel from 'squel';
3 |
4 | export type LocalAdminGroupRequest = { [key: string]: any };
5 |
6 | export function localAdminGroupRequests(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists "local_admin_group_requests" (
10 | "group_id" varchar(64),
11 | "group_name" text,
12 | "notification" varchar(255),
13 | "introduction" varchar(255),
14 | "face_url" varchar(255),
15 | "create_time" integer,
16 | "status" integer,
17 | "creator_user_id" varchar(64),
18 | "group_type" integer,
19 | "owner_user_id" varchar(64),
20 | "member_count" integer,
21 | "user_id" varchar(64),
22 | "nickname" varchar(255),
23 | "user_face_url" varchar(255),
24 | "gender" integer,
25 | "handle_result" integer,
26 | "req_msg" varchar(255),
27 | "handle_msg" varchar(255),
28 | "req_time" integer,
29 | "handle_user_id" varchar(64),
30 | "handle_time" integer,
31 | "ex" varchar(1024),
32 | "attached_info" varchar(1024),
33 | "join_source" integer,
34 | "inviter_user_id" text,
35 | PRIMARY KEY ("group_id", "user_id")
36 | );
37 | `
38 | );
39 | }
40 |
41 | export function insertAdminGroupRequest(
42 | db: Database,
43 | localGroupRequest: LocalAdminGroupRequest
44 | ): QueryExecResult[] {
45 | const sql = squel
46 | .insert()
47 | .into('local_admin_group_requests')
48 | .setFields(localGroupRequest)
49 | .toString();
50 |
51 | return db.exec(sql);
52 | }
53 |
54 | export function deleteAdminGroupRequest(
55 | db: Database,
56 | groupID: string,
57 | userID: string
58 | ): QueryExecResult[] {
59 | return db.exec(
60 | `
61 | delete
62 | from local_admin_group_requests
63 | where group_id = "${groupID}"
64 | and user_id = "${userID}"
65 | `
66 | );
67 | }
68 |
69 | export function updateAdminGroupRequest(
70 | db: Database,
71 | localGroupRequest: LocalAdminGroupRequest
72 | ): QueryExecResult[] {
73 | const sql = squel
74 | .update()
75 | .table('local_admin_group_requests')
76 | .setFields(localGroupRequest)
77 | .where(
78 | `group_id = '${localGroupRequest.group_id}' and user_id = '${localGroupRequest.user_id}'`
79 | )
80 | .toString();
81 |
82 | return db.exec(sql);
83 | }
84 |
85 | export function getAdminGroupApplication(db: Database): QueryExecResult[] {
86 | return db.exec(
87 | `
88 | select *
89 | from local_admin_group_requests
90 | order by create_time desc
91 | `
92 | );
93 | }
94 |
--------------------------------------------------------------------------------
/src/sqls/localAppSdkVersion.ts:
--------------------------------------------------------------------------------
1 | import squel from 'squel';
2 | import { Database, QueryExecResult } from '@jlongster/sql.js';
3 |
4 | export type LocalAppSDKVersion = { [key: string]: any };
5 |
6 | export function localAppSDKVersions(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_app_sdk_version' (
10 | 'version' varchar(255),
11 | primary key ('version')
12 | )
13 | `
14 | );
15 | }
16 |
17 | export function getAppSDKVersion(db: Database): QueryExecResult[] {
18 | return db.exec(
19 | `
20 | SELECT * FROM local_app_sdk_version LIMIT 1
21 | `
22 | );
23 | }
24 |
25 | export function insertAppSDKVersion(
26 | db: Database,
27 | localAppSDKVersion: LocalAppSDKVersion
28 | ): QueryExecResult[] {
29 | const sql = squel
30 | .insert()
31 | .into('local_app_sdk_version')
32 | .setFields(localAppSDKVersion)
33 | .toString();
34 |
35 | return db.exec(sql);
36 | }
37 |
38 | export function updateAppSDKVersion(
39 | db: Database,
40 | oldVersion: string,
41 | localAppSDKVersion: LocalAppSDKVersion
42 | ): QueryExecResult[] {
43 | const sql = squel
44 | .update()
45 | .table('local_app_sdk_version')
46 | .setFields(localAppSDKVersion)
47 | .where(`version = '${oldVersion}'`)
48 | .toString();
49 |
50 | return db.exec(sql);
51 | }
52 |
--------------------------------------------------------------------------------
/src/sqls/localBlack.ts:
--------------------------------------------------------------------------------
1 | import squel from 'squel';
2 | import { Database, QueryExecResult } from '@jlongster/sql.js';
3 |
4 | export type LocalBlack = { [key: string]: any };
5 |
6 | export function locaBlacks(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_blacks' (
10 | 'owner_user_id' varchar(64),
11 | 'block_user_id' varchar(64),
12 | 'nickname' varchar(255),
13 | 'face_url' varchar(255),
14 | 'gender' INTEGER,
15 | 'create_time' INTEGER,
16 | 'add_source' INTEGER,
17 | 'operator_user_id' varchar(64),
18 | 'ex' varchar(1024),
19 | 'attached_info' varchar(1024),
20 | primary key ('owner_user_id', 'block_user_id')
21 | )
22 | `
23 | );
24 | }
25 |
26 | export function getBlackList(db: Database): QueryExecResult[] {
27 | return db.exec(
28 | `
29 | select *
30 | from local_blacks
31 | `
32 | );
33 | }
34 |
35 | export function getBlackListUserID(db: Database): QueryExecResult[] {
36 | return db.exec(
37 | `
38 | SELECT block_user_id
39 | FROM local_blacks
40 | `
41 | );
42 | }
43 |
44 | export function getBlackInfoByBlockUserID(
45 | db: Database,
46 | blockUserID: string,
47 | loginUserID: string
48 | ): QueryExecResult[] {
49 | return db.exec(
50 | `
51 | SELECT *
52 | FROM local_blacks
53 | WHERE owner_user_id = "${loginUserID}"
54 | AND block_user_id = "${blockUserID}"
55 | LIMIT 1
56 | `
57 | );
58 | }
59 |
60 | export function getBlackInfoList(
61 | db: Database,
62 | blockUserIDList: string[]
63 | ): QueryExecResult[] {
64 | const ids = blockUserIDList.map(v => `'${v}'`);
65 | return db.exec(
66 | `
67 | select *
68 | from local_blacks
69 | where block_user_id in (${ids.join(',')})
70 | `
71 | );
72 | }
73 |
74 | export function insertBlack(
75 | db: Database,
76 | localBlack: LocalBlack
77 | ): QueryExecResult[] {
78 | const sql = squel
79 | .insert()
80 | .into('local_blacks')
81 | .setFields(localBlack)
82 | .toString();
83 |
84 | return db.exec(sql);
85 | }
86 |
87 | export function updateBlack(
88 | db: Database,
89 | localBlack: LocalBlack
90 | ): QueryExecResult[] {
91 | const sql = squel
92 | .update()
93 | .table('local_blacks')
94 | .setFields(localBlack)
95 | .where(
96 | `owner_user_id = '${localBlack.owner_user_id}' and block_user_id = '${localBlack.block_user_id}'`
97 | )
98 | .toString();
99 |
100 | return db.exec(sql);
101 | }
102 |
103 | export function deleteBlack(
104 | db: Database,
105 | blockUserID: string,
106 | loginUserID: string
107 | ): QueryExecResult[] {
108 | return db.exec(
109 | `
110 | delete
111 | from local_blacks
112 | where owner_user_id = "${loginUserID}"
113 | and block_user_id = "${blockUserID}"
114 | `
115 | );
116 | }
117 |
--------------------------------------------------------------------------------
/src/sqls/localConversationUnreadMessages.ts:
--------------------------------------------------------------------------------
1 | import squel from 'squel';
2 | import { Database, QueryExecResult } from '@jlongster/sql.js';
3 |
4 | export type ClientLocalConversationUnreadMessage = { [key: string]: any };
5 |
6 | export function localConversationUnreadMessages(
7 | db: Database
8 | ): QueryExecResult[] {
9 | return db.exec(
10 | `
11 | create table if not exists 'local_conversation_unread_messages' (
12 | 'conversation_id' char(128),
13 | 'client_msg_id' char(64),
14 | 'send_time' integer,
15 | 'ex' varchar(1024),
16 | primary key (
17 | 'conversation_id',
18 | 'client_msg_id'
19 | )
20 | );
21 | `
22 | );
23 | }
24 |
25 | export function deleteConversationUnreadMessageList(
26 | db: Database,
27 | conversationID: string,
28 | sendTime: number
29 | ): QueryExecResult[] {
30 | return db.exec(
31 | `
32 | delete from local_conversation_unread_messages where conversation_id = '${conversationID}' and send_time <= ${sendTime};
33 | `
34 | );
35 | }
36 |
37 | export function batchInsertConversationUnreadMessageList(
38 | db: Database,
39 | messageList: ClientLocalConversationUnreadMessage[]
40 | ): QueryExecResult[] {
41 | const sql = squel
42 | .insert()
43 | .into('local_conversation_unread_messages')
44 | .setFieldsRows(messageList)
45 | .toString();
46 |
47 | return db.exec(sql);
48 | }
49 |
--------------------------------------------------------------------------------
/src/sqls/localConversations.ts:
--------------------------------------------------------------------------------
1 | import squel from 'squel';
2 | import { Database, QueryExecResult } from '@jlongster/sql.js';
3 |
4 | export type ClientConversation = { [key: string]: any };
5 |
6 | export function localConversations(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_conversations' (
10 | 'conversation_id' char(128),
11 | 'conversation_type' integer,
12 | 'user_id' char(64),
13 | 'group_id' char(128),
14 | 'show_name' varchar(255),
15 | 'face_url' varchar(255),
16 | 'recv_msg_opt' integer,
17 | 'unread_count' integer,
18 | 'group_at_type' integer,
19 | 'latest_msg' varchar(1000),
20 | 'latest_msg_send_time' integer,
21 | 'draft_text' text,
22 | 'draft_text_time' integer,
23 | 'is_pinned' numeric,
24 | 'burn_duration' integer,
25 | 'is_private_chat' numeric,
26 | 'is_not_in_group' numeric,
27 | 'update_unread_count_time' integer,
28 | 'attached_info' varchar(1024),
29 | 'ex' varchar(1024),
30 | 'max_seq' integer,
31 | 'min_seq' integer,
32 | 'has_read_seq' integer,
33 | 'msg_destruct_time' integer default 604800,
34 | 'is_msg_destruct' numeric default false,
35 | primary key ('conversation_id')
36 | )
37 | `
38 | );
39 | }
40 |
41 | export function getConversationByUserID(
42 | db: Database,
43 | userID: string
44 | ): QueryExecResult[] {
45 | return db.exec(
46 | `
47 | select * from local_conversations where user_id = "${userID}" limit 1;
48 | `
49 | );
50 | }
51 |
52 | export function getAllConversationList(db: Database): QueryExecResult[] {
53 | return db.exec(
54 | `
55 | select * from local_conversations where latest_msg_send_time > 0 order by case when is_pinned=1 then 0 else 1 end,max(latest_msg_send_time,draft_text_time) desc;
56 | `
57 | );
58 | }
59 |
60 | export function getAllConversationListToSync(db: Database): QueryExecResult[] {
61 | return db.exec(
62 | `
63 | select * from local_conversations;
64 | `
65 | );
66 | }
67 |
68 | export function getAllSingleConversationIDList(
69 | db: Database
70 | ): QueryExecResult[] {
71 | return db.exec(
72 | `
73 | select conversation_id from local_conversations where conversation_type = 1;
74 | `
75 | );
76 | }
77 |
78 | export function getAllConversationIDList(db: Database): QueryExecResult[] {
79 | return db.exec(
80 | `
81 | select conversation_id from local_conversations;
82 | `
83 | );
84 | }
85 |
86 | export function getHiddenConversationList(db: Database): QueryExecResult[] {
87 | return db.exec(
88 | `
89 | select * from local_conversations where latest_msg_send_time = 0;
90 | `
91 | );
92 | }
93 |
94 | export function getConversationListSplit(
95 | db: Database,
96 | offset: number,
97 | count: number
98 | ): QueryExecResult[] {
99 | return db.exec(
100 | `
101 | SELECT *
102 | FROM local_conversations
103 | WHERE latest_msg_send_time > 0
104 | ORDER BY case
105 | when is_pinned = 1 then 0
106 | else 1 end, max(latest_msg_send_time, draft_text_time) DESC
107 | LIMIT ${count} OFFSET ${offset}
108 | `
109 | );
110 | }
111 |
112 | export function getConversation(
113 | db: Database,
114 | conversationID: string
115 | ): QueryExecResult[] {
116 | return db.exec(
117 | `
118 | select * from local_conversations where conversation_id = '${conversationID}' limit 1;
119 | `
120 | );
121 | }
122 |
123 | export function getMultipleConversation(
124 | db: Database,
125 | conversationIDList: string[]
126 | ): QueryExecResult[] {
127 | const ids = conversationIDList.map(v => `'${v}'`);
128 |
129 | return db.exec(
130 | `
131 | select * from local_conversations where conversation_id in (${ids.join(
132 | ','
133 | )});
134 | `
135 | );
136 | }
137 |
138 | export function updateColumnsConversation(
139 | db: Database,
140 | conversationID: string,
141 | conversation: ClientConversation
142 | ): QueryExecResult[] {
143 | const sql = squel
144 | .update()
145 | .table('local_conversations')
146 | .setFields(conversation)
147 | .where(`conversation_id = '${conversationID}'`)
148 | .toString();
149 |
150 | return db.exec(sql);
151 | }
152 |
153 | export function incrConversationUnreadCount(
154 | db: Database,
155 | conversationID: string
156 | ): QueryExecResult[] {
157 | return db.exec(
158 | `
159 | update local_conversations set
160 | unread_count=unread_count+1
161 | where conversation_id = '${conversationID}';
162 | `
163 | );
164 | }
165 |
166 | export function decrConversationUnreadCount(
167 | db: Database,
168 | conversationID: string,
169 | count: number
170 | ): QueryExecResult[] {
171 | db.exec('begin');
172 | db.exec(
173 | `
174 | update local_conversations set
175 | unread_count=unread_count-${count}
176 | where conversation_id = '${conversationID}';
177 | `
178 | );
179 | const current = db.exec(
180 | `select unread_count from local_conversations where conversation_id = '${conversationID}'`
181 | );
182 |
183 | if (Number(current[0].values[0]) < 0) {
184 | db.exec(
185 | `
186 | update local_conversations set
187 | unread_count=${0}
188 | where conversation_id = '${conversationID}';
189 | `
190 | );
191 | }
192 | return db.exec('commit');
193 | }
194 |
195 | export function batchInsertConversationList(
196 | db: Database,
197 | conversationList: ClientConversation[]
198 | ): QueryExecResult[] {
199 | const sql = squel
200 | .insert()
201 | .into('local_conversations')
202 | .setFieldsRows(conversationList)
203 | .toString();
204 |
205 | return db.exec(sql);
206 | }
207 |
208 | export function insertConversation(
209 | db: Database,
210 | localConversation: ClientConversation
211 | ): QueryExecResult[] {
212 | const sql = squel
213 | .insert()
214 | .into('local_conversations')
215 | .setFields(localConversation)
216 | .toString();
217 |
218 | return db.exec(sql);
219 | }
220 |
221 | export function updateConversation(
222 | db: Database,
223 | localConversation: ClientConversation
224 | ): QueryExecResult[] {
225 | const sql = squel
226 | .update()
227 | .table('local_conversations')
228 | .setFields(localConversation)
229 | .where(`conversation_id = '${localConversation.conversation_id}'`)
230 | .toString();
231 |
232 | return db.exec(sql);
233 | }
234 |
235 | export function deleteConversation(
236 | db: Database,
237 | conversationID: string
238 | ): QueryExecResult[] {
239 | return db.exec(`
240 | DELETE
241 | FROM local_conversations
242 | WHERE conversation_id = "${conversationID}"
243 | `);
244 | }
245 |
246 | export function deleteAllConversation(db: Database): QueryExecResult[] {
247 | return db.exec(`
248 | DELETE FROM local_conversations;
249 | `);
250 | }
251 |
252 | export function conversationIfExists(
253 | db: Database,
254 | conversationID: string
255 | ): QueryExecResult[] {
256 | return db.exec(`
257 | SELECT count(*)
258 | FROM local_conversations
259 | WHERE conversation_id = "${conversationID}"
260 | `);
261 | }
262 |
263 | export function resetConversation(
264 | db: Database,
265 | conversationID: string
266 | ): QueryExecResult[] {
267 | return db.exec(`
268 | UPDATE local_conversations
269 | SET unread_count=0,
270 | latest_msg="",
271 | latest_msg_send_time=0,
272 | draft_text="",
273 | draft_text_time=0
274 | WHERE conversation_id = "${conversationID}"
275 | `);
276 | }
277 |
278 | export function resetAllConversation(db: Database): QueryExecResult[] {
279 | return db.exec(`
280 | UPDATE local_conversations
281 | SET unread_count=0,
282 | latest_msg="",
283 | latest_msg_send_time=0,
284 | draft_text="",
285 | draft_text_time=0
286 | `);
287 | }
288 |
289 | export function clearConversation(
290 | db: Database,
291 | conversationID: string
292 | ): QueryExecResult[] {
293 | return db.exec(`
294 | UPDATE local_conversations
295 | SET unread_count=0,
296 | latest_msg="",
297 | draft_text="",
298 | draft_text_time=0
299 | WHERE conversation_id = "${conversationID}"
300 | `);
301 | }
302 |
303 | export function clearAllConversation(db: Database): QueryExecResult[] {
304 | return db.exec(`
305 | UPDATE local_conversations
306 | SET unread_count=0,
307 | latest_msg="",
308 | draft_text="",
309 | draft_text_time=0
310 | `);
311 | }
312 |
313 | export function setConversationDraft(
314 | db: Database,
315 | conversationID: string,
316 | draftText: string
317 | ): QueryExecResult[] {
318 | const nowDate = new Date().getTime();
319 | return db.exec(`
320 | update local_conversations
321 | set draft_text='${draftText}',
322 | draft_text_time=${nowDate},
323 | latest_msg_send_time=case when latest_msg_send_time = 0 then ${nowDate} else latest_msg_send_time end
324 | where conversation_id = "${conversationID}"
325 | `);
326 | }
327 |
328 | export function removeConversationDraft(
329 | db: Database,
330 | conversationID: string,
331 | draftText: string
332 | ): QueryExecResult[] {
333 | return db.exec(`
334 | update local_conversations
335 | set draft_text="${draftText}",
336 | draft_text_time=0
337 | where conversation_id = "${conversationID}"
338 | `);
339 | }
340 |
341 | export function unPinConversation(
342 | db: Database,
343 | conversationID: string,
344 | isPinned: number
345 | ): QueryExecResult[] {
346 | return db.exec(`
347 | update local_conversations
348 | set is_pinned=${isPinned},
349 | draft_text_time=case when draft_text = "" then 0 else draft_text_time end
350 | where conversation_id = "${conversationID}"
351 | `);
352 | }
353 |
354 | export function getTotalUnreadMsgCount(db: Database): QueryExecResult[] {
355 | return db.exec(
356 | `
357 | select sum(unread_count) from local_conversations where recv_msg_opt < 2 and latest_msg_send_time > 0;
358 | `
359 | );
360 | }
361 |
362 | export function setMultipleConversationRecvMsgOpt(
363 | db: Database,
364 | conversationIDList: string[],
365 | opt: number
366 | ): QueryExecResult[] {
367 | const values = conversationIDList.map(v => `'${v}'`).join(',');
368 | return db.exec(
369 | `
370 | UPDATE local_conversations
371 | SET recv_msg_opt=${opt}
372 | WHERE conversation_id IN (${values})
373 | `
374 | );
375 | }
376 |
377 | export function getAllConversations(db: Database): QueryExecResult[] {
378 | return db.exec(
379 | `
380 | SELECT * FROM local_conversations
381 | `
382 | );
383 | }
384 |
385 | export function searchConversations(
386 | db: Database,
387 | keyword: string
388 | ): QueryExecResult[] {
389 | return db.exec(
390 | `
391 | SELECT * FROM local_conversations
392 | WHERE show_name LIKE '%${keyword}%'
393 | ORDER BY latest_msg_send_time DESC
394 | `
395 | );
396 | }
397 |
--------------------------------------------------------------------------------
/src/sqls/localFriend.ts:
--------------------------------------------------------------------------------
1 | import squel from 'squel';
2 | import { Database, QueryExecResult } from '@jlongster/sql.js';
3 |
4 | export type LocalFriend = { [key: string]: any };
5 |
6 | export function localFriends(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_friends'
10 | (
11 | 'owner_user_id' varchar(64),
12 | 'friend_user_id' varchar(64),
13 | 'remark' varchar(255),
14 | 'create_time' INTEGER,
15 | 'add_source' INTEGER,
16 | 'operator_user_id' varchar(64),
17 | 'name' varchar(255),
18 | 'face_url' varchar(255),
19 | 'ex' varchar(1024),
20 | 'attached_info' varchar(1024),
21 | 'is_pinned' numeric,
22 | primary key ('owner_user_id', 'friend_user_id')
23 | )
24 | `
25 | );
26 | }
27 |
28 | export function insertFriend(
29 | db: Database,
30 | localFriend: LocalFriend
31 | ): QueryExecResult[] {
32 | const sql = squel
33 | .insert()
34 | .into('local_friends')
35 | .setFields(localFriend)
36 | .toString();
37 |
38 | return db.exec(sql);
39 | }
40 |
41 | export function deleteFriend(
42 | db: Database,
43 | friendUserID: string,
44 | loginUserID: string
45 | ): QueryExecResult[] {
46 | return db.exec(
47 | `
48 | DELETE FROM local_friends
49 | WHERE owner_user_id="${loginUserID}"
50 | and friend_user_id="${friendUserID}"
51 | `
52 | );
53 | }
54 | export function updateFriend(
55 | db: Database,
56 | localFriend: LocalFriend
57 | ): QueryExecResult[] {
58 | const sql = squel
59 | .update()
60 | .table('local_friends')
61 | .setFields(localFriend)
62 | .where(
63 | `owner_user_id = '${localFriend.owner_user_id}' and friend_user_id = '${localFriend.friend_user_id}'`
64 | )
65 | .toString();
66 |
67 | return db.exec(sql);
68 | }
69 |
70 | export function getAllFriendList(
71 | db: Database,
72 | loginUser: string
73 | ): QueryExecResult[] {
74 | return db.exec(
75 | `
76 | select *
77 | from local_friends
78 | where owner_user_id = "${loginUser}"
79 | `
80 | );
81 | }
82 |
83 | export function getPageFriendList(
84 | db: Database,
85 | offset: number,
86 | count: number,
87 | loginUser: string
88 | ): QueryExecResult[] {
89 | return db.exec(
90 | `
91 | select *
92 | from local_friends
93 | where owner_user_id = "${loginUser}"
94 | order by name
95 | limit ${count} offset ${offset}
96 | `
97 | );
98 | }
99 |
100 | export function searchFriendList(
101 | db: Database,
102 | keyword: string,
103 | isSearchUserID: boolean,
104 | isSearchNickname: boolean,
105 | isSearchRemark: boolean
106 | ): QueryExecResult[] {
107 | let totalConditionStr = '';
108 | const userIDCondition = `friend_user_id like "%${keyword}%"`;
109 | const nicknameCondition = `name like "%${keyword}%"`;
110 | const remarkCondition = `remark like "%${keyword}%"`;
111 | if (isSearchUserID) {
112 | totalConditionStr = userIDCondition;
113 | }
114 | if (isSearchNickname) {
115 | totalConditionStr = totalConditionStr
116 | ? totalConditionStr + ' or ' + nicknameCondition
117 | : nicknameCondition;
118 | }
119 | if (isSearchRemark) {
120 | totalConditionStr = totalConditionStr
121 | ? totalConditionStr + ' or ' + remarkCondition
122 | : remarkCondition;
123 | }
124 | return db.exec(
125 | `
126 | select *
127 | from local_friends
128 | where ${totalConditionStr}
129 | order by create_time desc
130 | `
131 | );
132 | }
133 |
134 | export function getFriendInfoByFriendUserID(
135 | db: Database,
136 | friendUserID: string,
137 | loginUser: string
138 | ): QueryExecResult[] {
139 | return db.exec(
140 | `
141 | select *
142 | from local_friends
143 | where owner_user_id = "${loginUser}"
144 | and friend_user_id = "${friendUserID}"
145 | limit 1
146 | `
147 | );
148 | }
149 |
150 | export function getFriendInfoList(
151 | db: Database,
152 | friendUserIDList: string[]
153 | ): QueryExecResult[] {
154 | const values = friendUserIDList.map(v => `'${v}'`).join(',');
155 | return db.exec(
156 | `
157 | select *
158 | from local_friends
159 | where friend_user_id in (${values})
160 | `
161 | );
162 | }
163 |
164 | export function updateColumnsFriend(
165 | db: Database,
166 | friendUserIDs: string[],
167 | localFriend: LocalFriend
168 | ): QueryExecResult[] {
169 | const values = friendUserIDs.map(v => `'${v}'`).join(',');
170 | const sql = squel
171 | .update()
172 | .table('local_friends')
173 | .setFields(localFriend)
174 | .where(`friend_user_id IN (${values})`)
175 | .toString();
176 |
177 | return db.exec(sql);
178 | }
179 |
180 | export function getFriendListCount(db: Database): QueryExecResult[] {
181 | return db.exec(
182 | `
183 | SELECT COUNT(*) FROM local_friends;
184 | `
185 | );
186 | }
187 |
188 | export function deleteAllFriend(db: Database): QueryExecResult[] {
189 | return db.exec(
190 | `
191 | DELETE FROM local_friends;
192 | `
193 | );
194 | }
195 |
--------------------------------------------------------------------------------
/src/sqls/localFriendRequest.ts:
--------------------------------------------------------------------------------
1 | import squel from 'squel';
2 | import { Database, QueryExecResult } from '@jlongster/sql.js';
3 |
4 | export type LocalFriendRequest = { [key: string]: any };
5 |
6 | export function localFriendRequests(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_friend_requests'
10 | (
11 | 'from_user_id' varchar(64),
12 | 'from_nickname' varchar(255),
13 | 'from_face_url' varchar(255),
14 | 'to_user_id' varchar(64),
15 | 'to_nickname' varchar(255),
16 | 'to_face_url' varchar(255),
17 | 'handle_result' INTEGER,
18 | 'req_msg' varchar(255),
19 | 'create_time' INTEGER,
20 | 'handler_user_id' varchar(64),
21 | 'handle_msg' varchar(255),
22 | 'handle_time' INTEGER,
23 | 'ex' varchar(1024),
24 | 'attached_info' varchar(1024),
25 | primary key ('from_user_id', 'to_user_id')
26 | );
27 | `
28 | );
29 | }
30 |
31 | export function insertFriendRequest(
32 | db: Database,
33 | localFriendRequest: LocalFriendRequest
34 | ): QueryExecResult[] {
35 | const sql = squel
36 | .insert()
37 | .into('local_friend_requests')
38 | .setFields(localFriendRequest)
39 | .toString();
40 |
41 | return db.exec(sql);
42 | }
43 |
44 | export function deleteFriendRequestBothUserID(
45 | db: Database,
46 | fromUserID: string,
47 | toUserID: string
48 | ): QueryExecResult[] {
49 | return db.exec(
50 | `
51 | delete
52 | from local_friend_requests
53 | where from_user_id = "${fromUserID}"
54 | and to_user_id = "${toUserID}"
55 | `
56 | );
57 | }
58 |
59 | export function updateFriendRequest(
60 | db: Database,
61 | localFriendRequest: LocalFriendRequest
62 | ): QueryExecResult[] {
63 | const sql = squel
64 | .update()
65 | .table('local_friend_requests')
66 | .setFields(localFriendRequest)
67 | .where(
68 | `from_user_id = '${localFriendRequest.from_user_id}' and to_user_id = '${localFriendRequest.to_user_id}'`
69 | )
70 | .toString();
71 |
72 | return db.exec(sql);
73 | }
74 |
75 | export function getRecvFriendApplication(
76 | db: Database,
77 | loginUserID: string
78 | ): QueryExecResult[] {
79 | return db.exec(
80 | `
81 | select *
82 | from local_friend_requests
83 | where to_user_id = "${loginUserID}"
84 | order by create_time desc
85 | `
86 | );
87 | }
88 |
89 | export function getSendFriendApplication(
90 | db: Database,
91 | loginUserID: string
92 | ): QueryExecResult[] {
93 | return db.exec(
94 | `
95 | select * from local_friend_requests
96 | where from_user_id = "${loginUserID}"
97 | order by create_time desc
98 | `
99 | );
100 | }
101 |
102 | export function getFriendApplicationByBothID(
103 | db: Database,
104 | fromUserID: string,
105 | toUserID: boolean
106 | ): QueryExecResult[] {
107 | return db.exec(
108 | `
109 | select *
110 | from local_friend_requests
111 | where from_user_id = "${fromUserID}"
112 | and to_user_id = "${toUserID}"
113 | limit 1
114 | `
115 | );
116 | }
117 |
118 | export function getBothFriendReq(
119 | db: Database,
120 | fromUserID: string,
121 | toUserID: boolean
122 | ): QueryExecResult[] {
123 | return db.exec(
124 | `
125 | select *
126 | from local_friend_requests
127 | where (from_user_id = "${fromUserID}"
128 | and to_user_id = "${toUserID}")
129 | or (from_user_id = "${toUserID}"
130 | and to_user_id = "${fromUserID}")
131 | `
132 | );
133 | }
134 |
--------------------------------------------------------------------------------
/src/sqls/localGroupRequests.ts:
--------------------------------------------------------------------------------
1 | import { Database, QueryExecResult } from '@jlongster/sql.js';
2 | import squel from 'squel';
3 |
4 | export type LocalGroupRequest = { [key: string]: any };
5 |
6 | export function localGroupRequests(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists "local_group_requests" (
10 | "group_id" varchar(64),
11 | "group_name" text,
12 | "notification" varchar(255),
13 | "introduction" varchar(255),
14 | "face_url" varchar(255),
15 | "create_time" integer,
16 | "status" integer,
17 | "creator_user_id" varchar(64),
18 | "group_type" integer,
19 | "owner_user_id" varchar(64),
20 | "member_count" integer,
21 | "user_id" varchar(64),
22 | "nickname" varchar(255),
23 | "user_face_url" varchar(255),
24 | "gender" integer,
25 | "handle_result" integer,
26 | "req_msg" varchar(255),
27 | "handle_msg" varchar(255),
28 | "req_time" integer,
29 | "handle_user_id" varchar(64),
30 | "handle_time" integer,
31 | "ex" varchar(1024),
32 | "attached_info" varchar(1024),
33 | "join_source" integer,
34 | "inviter_user_id" text,
35 | PRIMARY KEY ("group_id", "user_id")
36 | );
37 | `
38 | );
39 | }
40 |
41 | export function insertGroupRequest(
42 | db: Database,
43 | localGroupRequest: LocalGroupRequest
44 | ): QueryExecResult[] {
45 | const sql = squel
46 | .insert()
47 | .into('local_group_requests')
48 | .setFields(localGroupRequest)
49 | .toString();
50 |
51 | return db.exec(sql);
52 | }
53 |
54 | export function deleteGroupRequest(
55 | db: Database,
56 | groupID: string,
57 | userID: string
58 | ): QueryExecResult[] {
59 | return db.exec(
60 | `
61 | delete
62 | from local_group_requests
63 | where group_id = "${groupID}"
64 | and user_id = "${userID}"
65 | `
66 | );
67 | }
68 |
69 | export function updateGroupRequest(
70 | db: Database,
71 | localGroupRequest: LocalGroupRequest
72 | ): QueryExecResult[] {
73 | const sql = squel
74 | .update()
75 | .table('local_group_requests')
76 | .setFields(localGroupRequest)
77 | .where(
78 | `group_id = '${localGroupRequest.group_id}' and user_id = '${localGroupRequest.user_id}'`
79 | )
80 | .toString();
81 |
82 | return db.exec(sql);
83 | }
84 |
85 | export function getSendGroupApplication(db: Database): QueryExecResult[] {
86 | return db.exec(
87 | `
88 | select *
89 | from local_group_requests
90 | order by create_time desc
91 | `
92 | );
93 | }
94 |
--------------------------------------------------------------------------------
/src/sqls/localGroups.ts:
--------------------------------------------------------------------------------
1 | import squel from 'squel';
2 | import { Database, QueryExecResult } from '@jlongster/sql.js';
3 |
4 | export type LocalGroup = { [key: string]: any };
5 |
6 | export function localGroups(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_groups'
10 | (
11 | 'group_id' varchar(64) PRIMARY KEY,
12 | 'name' TEXT,
13 | 'notification' varchar(255),
14 | 'introduction' varchar(255),
15 | 'face_url' varchar(255),
16 | 'create_time' INTEGER,
17 | 'status' INTEGER,
18 | 'creator_user_id' varchar(64),
19 | 'group_type' INTEGER,
20 | 'owner_user_id' varchar(64),
21 | 'member_count' INTEGER,
22 | 'ex' varchar(1024),
23 | 'attached_info' varchar(1024),
24 | 'need_verification' INTEGER,
25 | 'look_member_info' INTEGER,
26 | 'apply_member_friend' INTEGER,
27 | 'notification_update_time' INTEGER,
28 | 'notification_user_id' TEXT,
29 | 'display_is_read' numeric
30 | )
31 | `
32 | );
33 | }
34 |
35 | export function insertGroup(
36 | db: Database,
37 | localGroup: LocalGroup
38 | ): QueryExecResult[] {
39 | const sql = squel
40 | .insert()
41 | .into('local_groups')
42 | .setFields(localGroup)
43 | .toString();
44 |
45 | return db.exec(sql);
46 | }
47 |
48 | export function deleteGroup(db: Database, groupID: string): QueryExecResult[] {
49 | return db.exec(
50 | `
51 | DELETE FROM local_groups
52 | WHERE group_id="${groupID}"
53 | `
54 | );
55 | }
56 |
57 | export function updateGroup(
58 | db: Database,
59 | groupID: string,
60 | localGroup: LocalGroup
61 | ): QueryExecResult[] {
62 | const sql = squel
63 | .update()
64 | .table('local_groups')
65 | .setFields(localGroup)
66 | .where(`group_id = '${groupID}'`)
67 | .toString();
68 |
69 | return db.exec(sql);
70 | }
71 |
72 | export function getJoinedGroupList(db: Database): QueryExecResult[] {
73 | return db.exec(
74 | `
75 | SELECT * FROM local_groups
76 | `
77 | );
78 | }
79 |
80 | export function getGroupInfoByGroupID(
81 | db: Database,
82 | groupID: string
83 | ): QueryExecResult[] {
84 | return db.exec(
85 | `
86 | SELECT *
87 | FROM local_groups
88 | WHERE group_id = "${groupID}"
89 | `
90 | );
91 | }
92 |
93 | export function getAllGroupInfoByGroupIDOrGroupName(
94 | db: Database,
95 | keyword: string,
96 | isSearchGroupID: boolean,
97 | isSearchGroupName: boolean
98 | ): QueryExecResult[] {
99 | let totalConditionStr = '';
100 | const groupIDCondition = `group_id like "%${keyword}%"`;
101 | const groupNameCondition = `name like "%${keyword}%"`;
102 | if (isSearchGroupID) {
103 | totalConditionStr = groupIDCondition;
104 | }
105 | if (isSearchGroupName) {
106 | totalConditionStr = groupNameCondition;
107 | }
108 | if (isSearchGroupName && isSearchGroupID) {
109 | totalConditionStr = groupIDCondition + ' or ' + groupNameCondition;
110 | }
111 | return db.exec(
112 | `
113 | select *
114 | from local_groups
115 | where ${totalConditionStr}
116 | order by create_time desc
117 | `
118 | );
119 | }
120 |
121 | export function subtractMemberCount(
122 | db: Database,
123 | groupID: string
124 | ): QueryExecResult[] {
125 | return db.exec(
126 | `
127 | update local_groups set member_count = member_count-1 where group_id = '${groupID}'
128 | `
129 | );
130 | }
131 |
132 | export function addMemberCount(
133 | db: Database,
134 | groupID: string
135 | ): QueryExecResult[] {
136 | return db.exec(
137 | `
138 | update local_groups set member_count = member_count+1 where group_id = '${groupID}'
139 | `
140 | );
141 | }
142 |
143 | export function getGroupMemberAllGroupIDs(db: Database): QueryExecResult[] {
144 | return db.exec(
145 | `
146 | select distinct group_id from local_group_members
147 | `
148 | );
149 | }
150 |
151 | export function getGroups(db: Database, groupIDs: string[]): QueryExecResult[] {
152 | const values = groupIDs.map(v => `'${v}'`).join(',');
153 | return db.exec(
154 | `
155 | select * from local_groups where group_id in (${values});
156 | `
157 | );
158 | }
159 |
160 | export function deleteAllGroup(db: Database): QueryExecResult[] {
161 | return db.exec(
162 | `
163 | DELETE FROM local_groups;
164 | `
165 | );
166 | }
167 |
--------------------------------------------------------------------------------
/src/sqls/localNotification.ts:
--------------------------------------------------------------------------------
1 | import { Database, QueryExecResult } from '@jlongster/sql.js';
2 |
3 | export type LocalNotification = { [key: string]: any };
4 |
5 | export function localNotification(db: Database): QueryExecResult[] {
6 | return db.exec(
7 | `
8 | create table if not exists 'local_notification_seqs'
9 | (
10 | 'conversation_id' char(128),
11 | 'seq' integer,
12 | PRIMARY KEY ('conversation_id')
13 | )
14 | `
15 | );
16 | }
17 |
18 | export function insertNotificationSeq(
19 | db: Database,
20 | conversationID: string,
21 | seq: number
22 | ): QueryExecResult[] {
23 | return db.exec(
24 | `INSERT INTO local_notification_seqs (conversation_id, seq) VALUES ("${conversationID}", ${seq});`
25 | );
26 | }
27 |
28 | export function setNotificationSeq(
29 | db: Database,
30 | conversationID: string,
31 | seq: number
32 | ): QueryExecResult[] {
33 | return db.exec(
34 | `UPDATE local_notification_seqs set seq = ${seq} where conversation_id = "${conversationID}"`
35 | );
36 | }
37 |
38 | export function getNotificationAllSeqs(db: Database): QueryExecResult[] {
39 | return db.exec('SELECT * from local_notification_seqs where 1 = 1;');
40 | }
41 |
--------------------------------------------------------------------------------
/src/sqls/localSendingMessages.ts:
--------------------------------------------------------------------------------
1 | import { Database, QueryExecResult } from '@jlongster/sql.js';
2 | import squel from 'squel';
3 |
4 | export type LocalSendingMessage = { [key: string]: any };
5 |
6 | export function localSendingMessages(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_sending_messages'
10 | (
11 | conversation_id varchar(128),
12 | client_msg_id varchar(64),
13 | ex varchar(1024),
14 | PRIMARY KEY ('conversation_id', 'client_msg_id')
15 | );
16 | `
17 | );
18 | }
19 |
20 | export function insertSendingMessage(
21 | db: Database,
22 | localSendingMessage: LocalSendingMessage
23 | ): QueryExecResult[] {
24 | const sql = squel
25 | .insert()
26 | .into('local_sending_messages')
27 | .setFields(localSendingMessage)
28 | .toString();
29 |
30 | return db.exec(sql);
31 | }
32 |
33 | export function deleteSendingMessage(
34 | db: Database,
35 | conversationID: string,
36 | clientMsgID: string
37 | ): QueryExecResult[] {
38 | const sql = squel
39 | .delete()
40 | .from('local_sending_messages')
41 | .where(`conversation_id = '${conversationID}'`)
42 | .where(`client_msg_id = '${clientMsgID}'`)
43 | .toString();
44 |
45 | return db.exec(sql);
46 | }
47 |
48 | export function getAllSendingMessages(db: Database): QueryExecResult[] {
49 | const sql = squel.select().from('local_sending_messages').toString();
50 |
51 | return db.exec(sql);
52 | }
53 |
--------------------------------------------------------------------------------
/src/sqls/localStranger.ts:
--------------------------------------------------------------------------------
1 | import { Database, QueryExecResult } from '@jlongster/sql.js';
2 | import squel from 'squel';
3 |
4 | export type LocalStranger = { [key: string]: any };
5 |
6 | export function localStranger(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_stranger'
10 | (
11 | 'user_id' varchar(64),
12 | 'name' varchar(255),
13 | 'face_url' varchar(255),
14 | 'create_time' integer,
15 | 'app_manger_level' integer,
16 | 'ex' varchar(1024),
17 | 'attached_info' varchar(1024),
18 | 'global_recv_msg_opt' integer,
19 | PRIMARY KEY ('user_id')
20 | )
21 | `
22 | );
23 | }
24 |
25 | export function getStrangerInfo(
26 | db: Database,
27 | userIDList: string[]
28 | ): QueryExecResult[] {
29 | const ids = userIDList.map(v => `'${v}'`);
30 | return db.exec(
31 | `
32 | select *
33 | from local_stranger
34 | WHERE user_id = (${ids.join(',')})
35 | `
36 | );
37 | }
38 |
39 | export function insertStrangerInfo(
40 | db: Database,
41 | localStranger: LocalStranger
42 | ): QueryExecResult[] {
43 | const sql = squel
44 | .insert()
45 | .into('local_stranger')
46 | .setFields(localStranger)
47 | .toString();
48 |
49 | return db.exec(sql);
50 | }
51 |
52 | export function updateStrangerInfo(
53 | db: Database,
54 | localStranger: LocalStranger
55 | ): QueryExecResult[] {
56 | const sql = squel
57 | .update()
58 | .table('local_stranger')
59 | .setFields(localStranger)
60 | .where(`user_id = '${localStranger.user_id}'`)
61 | .toString();
62 |
63 | return db.exec(sql);
64 | }
65 |
--------------------------------------------------------------------------------
/src/sqls/localSuperGroups.ts:
--------------------------------------------------------------------------------
1 | import squel from 'squel';
2 | import { Database, QueryExecResult } from '@jlongster/sql.js';
3 |
4 | export type ClientGroup = { [key: string]: unknown };
5 |
6 | export function localSuperGroups(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_super_groups' (
10 | 'group_id' varchar(64),
11 | 'name' text,
12 | 'notification' varchar(255),
13 | 'introduction' varchar(255),
14 | 'face_url' varchar(255),
15 | 'create_time' integer,
16 | 'status' integer,
17 | 'creator_user_id' varchar(64),
18 | 'group_type' integer,
19 | 'owner_user_id' varchar(64),
20 | 'member_count' integer,
21 | 'ex' varchar(1024),
22 | 'attached_info' varchar(1024),
23 | 'need_verification' integer,
24 | 'look_member_info' integer,
25 | 'apply_member_friend' integer,
26 | 'notification_update_time' integer,
27 | 'notification_user_id' text,
28 | primary key ('group_id')
29 | )
30 | `
31 | );
32 | }
33 |
34 | export function getJoinedSuperGroupList(db: Database): QueryExecResult[] {
35 | return db.exec(
36 | `
37 | select * from local_super_groups;
38 | `
39 | );
40 | }
41 |
42 | export function insertSuperGroup(
43 | db: Database,
44 | group: ClientGroup
45 | ): QueryExecResult[] {
46 | const sql = squel
47 | .insert()
48 | .into('local_super_groups')
49 | .setFields(group)
50 | .toString();
51 |
52 | return db.exec(sql);
53 | }
54 |
55 | export function updateSuperGroup(
56 | db: Database,
57 | groupID: string,
58 | group: ClientGroup
59 | ): QueryExecResult[] {
60 | const sql = squel
61 | .update()
62 | .table('local_super_groups')
63 | .setFields(group)
64 | .where(`group_id = '${groupID}'`)
65 | .toString();
66 |
67 | return db.exec(sql);
68 | }
69 |
70 | export function deleteSuperGroup(
71 | db: Database,
72 | groupID: string
73 | ): QueryExecResult[] {
74 | return db.exec(
75 | `
76 | delete from local_super_groups where group_id = '${groupID}';
77 | `
78 | );
79 | }
80 |
81 | export function getSuperGroupInfoByGroupID(
82 | db: Database,
83 | groupID: string
84 | ): QueryExecResult[] {
85 | return db.exec(
86 | `
87 | select * from local_super_groups where group_id = '${groupID}' LIMIT 1;
88 | `
89 | );
90 | }
91 |
--------------------------------------------------------------------------------
/src/sqls/localTableMaster.ts:
--------------------------------------------------------------------------------
1 | import { Database, QueryExecResult } from '@jlongster/sql.js';
2 |
3 | export type LocalTableMaster = { [key: string]: any };
4 |
5 | // Init Table Tips:
6 | // This table is automatically generated by sqlite and does not need to be manually created!
7 | export function getExistedTables(db: Database): QueryExecResult[] {
8 | return db.exec(
9 | `
10 | SELECT name FROM sqlite_master WHERE type="table";
11 | `
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/src/sqls/localUpload.ts:
--------------------------------------------------------------------------------
1 | import squel from 'squel';
2 | import { Database, QueryExecResult } from '@jlongster/sql.js';
3 |
4 | export type ClientUpload = { [key: string]: unknown };
5 |
6 | export function localUploads(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_uploads' (
10 | 'part_hash' text,
11 | 'upload_id' varchar(1000),
12 | 'upload_info' varchar(2000),
13 | 'expire_time' integer,
14 | 'create_time' integer,
15 | PRIMARY KEY ('part_hash')
16 | )
17 | `
18 | );
19 | }
20 |
21 | export function getUpload(db: Database, partHash: string): QueryExecResult[] {
22 | return db.exec(
23 | `
24 | select * from local_uploads where part_hash = '${partHash}' limit 1;
25 | `
26 | );
27 | }
28 |
29 | export function insertUpload(
30 | db: Database,
31 | upload: ClientUpload
32 | ): QueryExecResult[] {
33 | const sql = squel.insert().into('local_uploads').setFields(upload).toString();
34 |
35 | return db.exec(sql);
36 | }
37 |
38 | export function updateUpload(
39 | db: Database,
40 | upload: ClientUpload
41 | ): QueryExecResult[] {
42 | const sql = squel
43 | .update()
44 | .table('local_uploads')
45 | .setFields(upload)
46 | .where(`part_hash = '${upload.part_hash}'`)
47 | .toString();
48 |
49 | return db.exec(sql);
50 | }
51 |
52 | export function deleteUpload(
53 | db: Database,
54 | partHash: string
55 | ): QueryExecResult[] {
56 | const sql = squel
57 | .delete()
58 | .from('local_uploads')
59 | .where(`part_hash = '${partHash}'`)
60 | .toString();
61 |
62 | return db.exec(sql);
63 | }
64 |
65 | export function deleteExpireUpload(db: Database): QueryExecResult[] {
66 | const sql = squel
67 | .delete()
68 | .from('local_uploads')
69 | .where(`expire_time <= ${Date.now()}`)
70 | .toString();
71 |
72 | return db.exec(sql);
73 | }
74 |
--------------------------------------------------------------------------------
/src/sqls/localUsers.ts:
--------------------------------------------------------------------------------
1 | import squel from 'squel';
2 | import { Database, QueryExecResult } from '@jlongster/sql.js';
3 |
4 | export type ClientUser = { [key: string]: unknown };
5 |
6 | export function localUsers(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_users' (
10 | 'user_id' varchar(64),
11 | 'name' varchar(255),
12 | 'face_url' varchar(255),
13 | 'create_time' integer,
14 | 'app_manger_level' integer,
15 | 'ex' varchar(1024),
16 | 'attached_info' varchar(1024),
17 | 'global_recv_msg_opt' integer,
18 | primary key ('user_id')
19 | )
20 | `
21 | );
22 | }
23 |
24 | export function getLoginUser(db: Database, userID: string): QueryExecResult[] {
25 | return db.exec(
26 | `
27 | select *, name as nickname from local_users where user_id = '${userID}' limit 1;
28 | `
29 | );
30 | }
31 |
32 | export function insertLoginUser(
33 | db: Database,
34 | user: ClientUser
35 | ): QueryExecResult[] {
36 | const sql = squel.insert().into('local_users').setFields(user).toString();
37 |
38 | return db.exec(sql);
39 | }
40 |
41 | export function updateLoginUser(
42 | db: Database,
43 | user: ClientUser
44 | ): QueryExecResult[] {
45 | const sql = squel
46 | .update()
47 | .table('local_users')
48 | .setFields(user)
49 | .where(`user_id = '${user.user_id}'`)
50 | .toString();
51 |
52 | return db.exec(sql);
53 | }
54 |
--------------------------------------------------------------------------------
/src/sqls/localVersionSync.ts:
--------------------------------------------------------------------------------
1 | import squel from 'squel';
2 | import { Database, QueryExecResult } from '@jlongster/sql.js';
3 |
4 | export type LocalVersionSync = { [key: string]: any };
5 |
6 | export function localVersionSyncs(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'local_sync_version' (
10 | 'table_name' varchar(255),
11 | 'entity_id' varchar(255),
12 | 'version_id' text,
13 | 'version' integer,
14 | 'create_time' integer,
15 | 'id_list' text,
16 | primary key ('table_name','entity_id')
17 | )
18 | `
19 | );
20 | }
21 |
22 | export function getVersionSync(
23 | db: Database,
24 | tableName: string,
25 | entityID: string
26 | ): QueryExecResult[] {
27 | return db.exec(
28 | `
29 | SELECT * FROM local_sync_version WHERE table_name = "${tableName}" AND entity_id = "${entityID}"
30 | `
31 | );
32 | }
33 |
34 | export function insertVersionSync(
35 | db: Database,
36 | localVersionSync: LocalVersionSync
37 | ): QueryExecResult[] {
38 | delete localVersionSync.table;
39 | const sql = squel
40 | .insert()
41 | .into('local_sync_version')
42 | .setFields(localVersionSync)
43 | .toString();
44 |
45 | return db.exec(sql);
46 | }
47 |
48 | export function updateVersionSync(
49 | db: Database,
50 | oldTable: string,
51 | oldEntityID: string,
52 | localVersionSync: LocalVersionSync
53 | ): QueryExecResult[] {
54 | delete localVersionSync.table;
55 | const sql = squel
56 | .update()
57 | .table('local_sync_version')
58 | .setFields(localVersionSync)
59 | .where(`table_name = '${oldTable}' AND entity_id = '${oldEntityID}'`)
60 | .toString();
61 |
62 | return db.exec(sql);
63 | }
64 |
65 | export function deleteVersionSync(
66 | db: Database,
67 | tableName: string,
68 | entityID: string
69 | ): QueryExecResult[] {
70 | return db.exec(
71 | `
72 | DELETE FROM local_sync_version WHERE table_name = "${tableName}" AND entity_id = "${entityID}";
73 | `
74 | );
75 | }
76 |
--------------------------------------------------------------------------------
/src/sqls/tempCacheLocalChatLogs.ts:
--------------------------------------------------------------------------------
1 | import { Database, QueryExecResult } from '@jlongster/sql.js';
2 | import squel from 'squel';
3 |
4 | export type TempCacheClientMessage = { [key: string]: any };
5 |
6 | export function tempCacheLocalChatLogs(db: Database): QueryExecResult[] {
7 | return db.exec(
8 | `
9 | create table if not exists 'temp_cache_local_chat_logs' (
10 | 'client_msg_id' char(64),
11 | 'server_msg_id' char(64),
12 | 'send_id' char(64),
13 | 'recv_id' char(64),
14 | 'sender_platform_id' integer,
15 | 'sender_nick_name' varchar(255),
16 | 'sender_face_url' varchar(255),
17 | 'session_type' integer,
18 | 'msg_from' integer,
19 | 'content_type' integer,
20 | 'content' varchar(1000),
21 | 'is_read' numeric,
22 | 'status' integer,
23 | 'seq' integer DEFAULT 0,
24 | 'send_time' integer,
25 | 'create_time' integer,
26 | 'attached_info' varchar(1024),
27 | 'ex' varchar(1024),
28 | PRIMARY KEY ('client_msg_id')
29 | );
30 | `
31 | );
32 | }
33 |
34 | export function batchInsertTempCacheMessageList(
35 | db: Database,
36 | messageList: TempCacheClientMessage[]
37 | ): QueryExecResult[] {
38 | const sql = squel
39 | .insert()
40 | .into('temp_cache_local_chat_logs')
41 | .setFieldsRows(messageList)
42 | .toString();
43 |
44 | return db.exec(sql);
45 | }
46 |
--------------------------------------------------------------------------------
/src/types/@jlongster/sql.js/index.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2 | declare module '@jlongster/sql.js' {
3 | ///
4 | ///
5 |
6 | export type SqlValue = number | string | Uint8Array | null;
7 | export type ParamsObject = Record;
8 | export type ParamsCallback = (obj: ParamsObject) => void;
9 | export type SqlJsConfig = {
10 | locateFile: (str: string) => string;
11 | };
12 | export type BindParams = SqlValue[] | ParamsObject | null;
13 |
14 | export interface QueryExecResult {
15 | columns: string[];
16 | values: SqlValue[][];
17 | }
18 |
19 | export interface StatementIteratorResult {
20 | /** `true` if there are no more available statements */
21 | done: boolean;
22 | /** the next available Statement (as returned by `Database.prepare`) */
23 | value: Statement;
24 | }
25 |
26 | export interface SqlJsStatic {
27 | Database: typeof Database;
28 | Statement: typeof Statement;
29 |
30 | register_for_idb: (v: any) => any;
31 | FS: {
32 | mkdir: (path: string) => void;
33 | mount: (...args: any[]) => void;
34 | };
35 | }
36 |
37 | export interface InitSqlJsStatic extends Function {
38 | (config?: SqlJsConfig): Promise;
39 | readonly default: this;
40 | }
41 |
42 | export declare class Database {
43 | /**
44 | * Represents an SQLite database
45 | * @see [https://sql.js.org/documentation/Database.html#Database](https://sql.js.org/documentation/Database.html#Database)
46 | *
47 | * @param data An array of bytes representing an SQLite database file
48 | */
49 | constructor(data?: ArrayLike | Buffer | null | string, opts?: any);
50 |
51 | /**
52 | * Close the database, and all associated prepared statements. The
53 | * memory associated to the database and all associated statements will
54 | * be freed.
55 | *
56 | * **Warning**: A statement belonging to a database that has been closed
57 | * cannot be used anymore.
58 | *
59 | * Databases must be closed when you're finished with them, or the
60 | * memory consumption will grow forever
61 | * @see [https://sql.js.org/documentation/Database.html#["close"]](https://sql.js.org/documentation/Database.html#%5B%22close%22%5D)
62 | */
63 | close(): void;
64 |
65 | /**
66 | * Register a custom function with SQLite
67 | * @see [https://sql.js.org/documentation/Database.html#["create_function"]](https://sql.js.org/documentation/Database.html#%5B%22create_function%22%5D)
68 | *
69 | * @param name the name of the function as referenced in SQL statements.
70 | * @param func the actual function to be executed.
71 | */
72 | create_function(name: string, func: (...args: any[]) => any): Database;
73 |
74 | /**
75 | * Execute an sql statement, and call a callback for each row of result.
76 | *
77 | * Currently this method is synchronous, it will not return until the
78 | * callback has been called on every row of the result. But this might
79 | * change.
80 | * @see [https://sql.js.org/documentation/Database.html#["each"]](https://sql.js.org/documentation/Database.html#%5B%22each%22%5D)
81 | *
82 | * @param sql A string of SQL text. Can contain placeholders that will
83 | * be bound to the parameters given as the second argument
84 | * @param params Parameters to bind to the query
85 | * @param callback Function to call on each row of result
86 | * @param done A function that will be called when all rows have been
87 | * retrieved
88 | */
89 | each(
90 | sql: string,
91 | params: BindParams,
92 | callback: ParamsCallback,
93 | done: () => void
94 | ): Database;
95 | each(sql: string, callback: ParamsCallback, done: () => void): Database;
96 |
97 | /**
98 | * Execute an SQL query, and returns the result.
99 | *
100 | * This is a wrapper against `Database.prepare`, `Statement.bind`, `Statement.step`, `Statement.get`, and `Statement.free`.
101 | *
102 | * The result is an array of result elements. There are as many result elements as the number of statements in your sql string (statements are separated by a semicolon)
103 | * @see [https://sql.js.org/documentation/Database.html#["exec"]](https://sql.js.org/documentation/Database.html#%5B%22exec%22%5D)
104 | *
105 | * @param sql a string containing some SQL text to execute
106 | * @param params When the SQL statement contains placeholders, you can
107 | * pass them in here. They will be bound to the statement before it is
108 | * executed. If you use the params argument as an array, you **cannot**
109 | * provide an sql string that contains several statements (separated by
110 | * `;`). This limitation does not apply to params as an object.
111 | */
112 | exec(sql: string, params?: BindParams): QueryExecResult[];
113 |
114 | /**
115 | * Exports the contents of the database to a binary array
116 | * @see [https://sql.js.org/documentation/Database.html#["export"]](https://sql.js.org/documentation/Database.html#%5B%22export%22%5D)
117 | */
118 | export(): Uint8Array;
119 |
120 | /**
121 | * Returns the number of changed rows (modified, inserted or deleted) by
122 | * the latest completed `INSERT`, `UPDATE` or `DELETE` statement on the
123 | * database. Executing any other type of SQL statement does not modify
124 | * the value returned by this function.
125 | * @see [https://sql.js.org/documentation/Database.html#["getRowsModified"]](https://sql.js.org/documentation/Database.html#%5B%22getRowsModified%22%5D)
126 | */
127 | getRowsModified(): number;
128 |
129 | /**
130 | * Analyze a result code, return null if no error occured, and throw an
131 | * error with a descriptive message otherwise
132 | * @see [https://sql.js.org/documentation/Database.html#["handleError"]](https://sql.js.org/documentation/Database.html#%5B%22handleError%22%5D)
133 | */
134 | handleError(): null | never;
135 |
136 | /**
137 | * Iterate over multiple SQL statements in a SQL string. This function
138 | * returns an iterator over Statement objects. You can use a `for..of`
139 | * loop to execute the returned statements one by one.
140 | * @see [https://sql.js.org/documentation/Database.html#["iterateStatements"]](https://sql.js.org/documentation/Database.html#%5B%22iterateStatements%22%5D)
141 | *
142 | * @param sql a string of SQL that can contain multiple statements
143 | */
144 | iterateStatements(sql: string): StatementIterator;
145 |
146 | /**
147 | * Prepare an SQL statement
148 | * @see [https://sql.js.org/documentation/Database.html#["prepare"]](https://sql.js.org/documentation/Database.html#%5B%22prepare%22%5D)
149 | *
150 | * @param sql a string of SQL, that can contain placeholders (`?`, `:VVV`, `:AAA`, `@AAA`)
151 | * @param params values to bind to placeholders
152 | */
153 | prepare(sql: string, params?: BindParams): Statement;
154 |
155 | /**
156 | * Execute an SQL query, ignoring the rows it returns.
157 | * @see [https://sql.js.org/documentation/Database.html#["run"]](https://sql.js.org/documentation/Database.html#%5B%22run%22%5D)
158 | *
159 | * @param sql a string containing some SQL text to execute
160 | * @param params When the SQL statement contains placeholders, you can
161 | * pass them in here. They will be bound to the statement before it is
162 | * executed. If you use the params argument as an array, you **cannot**
163 | * provide an sql string that contains several statements (separated by
164 | * `;`). This limitation does not apply to params as an object.
165 | */
166 | run(sql: string, params?: BindParams): Database;
167 | }
168 |
169 | export declare class Statement {
170 | /**
171 | * Bind values to the parameters, after having reseted the statement. If
172 | * values is null, do nothing and return true.
173 | *
174 | * SQL statements can have parameters, named '?', '?NNN', ':VVV',
175 | * '@VVV', '$VVV', where NNN is a number and VVV a string. This function
176 | * binds these parameters to the given values.
177 | *
178 | * Warning: ':', '@', and '$' are included in the parameters names
179 | *
180 | * ### Value types
181 | *
182 | * |Javascript type|SQLite type|
183 | * |-|-|
184 | * |number|REAL, INTEGER|
185 | * |boolean|INTEGER|
186 | * |string|TEXT|
187 | * |Array, Uint8Array|BLOB|
188 | * |null|NULL|
189 | * @see [https://sql.js.org/documentation/Statement.html#["bind"]](https://sql.js.org/documentation/Statement.html#%5B%22bind%22%5D)
190 | *
191 | * @param values The values to bind
192 | */
193 | bind(values?: BindParams): boolean;
194 |
195 | /**
196 | * Free the memory used by the statement
197 | * @see [https://sql.js.org/documentation/Statement.html#["free"]](https://sql.js.org/documentation/Statement.html#%5B%22free%22%5D)
198 | */
199 | free(): boolean;
200 |
201 | /**
202 | * Free the memory allocated during parameter binding
203 | * @see [https://sql.js.org/documentation/Statement.html#["freemem"]](https://sql.js.org/documentation/Statement.html#%5B%22freemem%22%5D)
204 | */
205 | freemem(): void;
206 |
207 | /**
208 | * Get one row of results of a statement. If the first parameter is not
209 | * provided, step must have been called before.
210 | * @see [https://sql.js.org/documentation/Statement.html#["get"]](https://sql.js.org/documentation/Statement.html#%5B%22get%22%5D)
211 | *
212 | * @param params If set, the values will be bound to the statement
213 | * before it is executed
214 | */
215 | get(params?: BindParams): SqlValue[];
216 |
217 | /**
218 | * Get one row of result as a javascript object, associating column
219 | * names with their value in the current row
220 | * @see [https://sql.js.org/documentation/Statement.html#["getAsObject"]](https://sql.js.org/documentation/Statement.html#%5B%22getAsObject%22%5D)
221 | *
222 | * @param params If set, the values will be bound to the statement, and
223 | * it will be executed
224 | */
225 | getAsObject(params?: BindParams): ParamsObject;
226 |
227 | /**
228 | * Get the list of column names of a row of result of a statement.
229 | * @see [https://sql.js.org/documentation/Statement.html#["getColumnNames"]](https://sql.js.org/documentation/Statement.html#%5B%22getColumnNames%22%5D)
230 | */
231 | getColumnNames(): string[];
232 |
233 | /**
234 | * Get the SQLite's normalized version of the SQL string used in
235 | * preparing this statement. The meaning of "normalized" is not
236 | * well-defined: see
237 | * [the SQLite documentation](https://sqlite.org/c3ref/expanded_sql.html).
238 | * @see [https://sql.js.org/documentation/Statement.html#["getNormalizedSQL"]](https://sql.js.org/documentation/Statement.html#%5B%22getNormalizedSQL%22%5D)
239 | */
240 | getNormalizedSQL(): string;
241 |
242 | /**
243 | * Get the SQL string used in preparing this statement.
244 | * @see [https://sql.js.org/documentation/Statement.html#["getSQL"]](https://sql.js.org/documentation/Statement.html#%5B%22getSQL%22%5D)
245 | */
246 | getSQL(): string;
247 |
248 | /**
249 | * Reset a statement, so that it's parameters can be bound to new
250 | * values. It also clears all previous bindings, freeing the memory used
251 | * by bound parameters.
252 | * @see [https://sql.js.org/documentation/Statement.html#["reset"]](https://sql.js.org/documentation/Statement.html#%5B%22reset%22%5D)
253 | */
254 | reset(): void;
255 |
256 | /**
257 | * Shorthand for bind + step + reset Bind the values, execute the
258 | * statement, ignoring the rows it returns, and resets it
259 | * @param values Value to bind to the statement
260 | */
261 | run(values?: BindParams): void;
262 |
263 | /**
264 | * Execute the statement, fetching the the next line of result, that can
265 | * be retrieved with `Statement.get`.
266 | * @see [https://sql.js.org/documentation/Statement.html#["step"]](https://sql.js.org/documentation/Statement.html#%5B%22step%22%5D)
267 | */
268 | step(): boolean;
269 | }
270 |
271 | /**
272 | * An iterator over multiple SQL statements in a string, preparing and
273 | * returning a Statement object for the next SQL statement on each
274 | * iteration.
275 | *
276 | * You can't instantiate this class directly, you have to use a Database
277 | * object in order to create a statement iterator
278 | * @see [https://sql.js.org/documentation/StatementIterator.html#StatementIterator](https://sql.js.org/documentation/StatementIterator.html#StatementIterator)
279 | */
280 | export declare class StatementIterator
281 | implements Iterator, Iterable
282 | {
283 | [Symbol.iterator](): Iterator;
284 | /**
285 | * Get any un-executed portions remaining of the original SQL string
286 | * @see [https://sql.js.org/documentation/StatementIterator.html#["getRemainingSQL"]](https://sql.js.org/documentation/StatementIterator.html#%5B%22getRemainingSQL%22%5D)
287 | */
288 | getRemainingSql(): string;
289 |
290 | /**
291 | * Prepare the next available SQL statement
292 | * @see [https://sql.js.org/documentation/StatementIterator.html#["next"]](https://sql.js.org/documentation/StatementIterator.html#%5B%22next%22%5D)
293 | */
294 | next(): StatementIteratorResult;
295 | }
296 |
297 | declare global {
298 | let SqlJs: InitSqlJsStatic;
299 | }
300 |
301 | export default SqlJs;
302 | }
303 |
--------------------------------------------------------------------------------
/src/types/absurd-sql-optimized/index.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2 | declare module 'absurd-sql-optimized' {
3 | export class SQLiteFS {
4 | constructor(fs: any, backend: any);
5 | }
6 | }
7 | declare module 'absurd-sql-optimized/dist/memory-backend' {
8 | export default class MemoryBBackend {}
9 | }
10 |
11 | declare module 'absurd-sql-optimized/dist/indexeddb-backend' {
12 | export default class IndexedDBBackend {}
13 | }
14 |
15 | declare module 'absurd-sql-optimized/dist/indexeddb-main-thread' {
16 | export function initBackend(worker: Worker);
17 | }
18 |
--------------------------------------------------------------------------------
/src/types/entity.ts:
--------------------------------------------------------------------------------
1 | import { CbEvents } from '../constant';
2 | import {
3 | GroupType,
4 | SessionType,
5 | MessageType,
6 | Platform,
7 | MessageStatus,
8 | GroupStatus,
9 | GroupVerificationType,
10 | AllowType,
11 | GroupJoinSource,
12 | GroupMemberRole,
13 | MessageReceiveOptType,
14 | GroupAtType,
15 | LogLevel,
16 | ApplicationHandleResult,
17 | Relationship,
18 | OnlineState,
19 | } from './enum';
20 | export type WSEvent = {
21 | event: CbEvents;
22 | data: T;
23 | errCode: number;
24 | errMsg: string;
25 | operationID: string;
26 | };
27 | export type WsResponse = {
28 | event: string;
29 | errCode: number;
30 | errMsg: string;
31 | data: T;
32 | operationID: string;
33 | };
34 | export type IMConfig = {
35 | platformID: Platform;
36 | apiAddr: string;
37 | wsAddr: string;
38 | dataDir: string;
39 | logLevel: LogLevel;
40 | isLogStandardOutput: boolean;
41 | logFilePath: string;
42 | isExternalExtensions: boolean;
43 | };
44 | export type MessageEntity = {
45 | type: string;
46 | offset: number;
47 | length: number;
48 | url?: string;
49 | info?: string;
50 | };
51 | export type PicBaseInfo = {
52 | uuid: string;
53 | type: string;
54 | size: number;
55 | width: number;
56 | height: number;
57 | url: string;
58 | };
59 | export type AtUsersInfoItem = {
60 | atUserID: string;
61 | groupNickname: string;
62 | };
63 | export type GroupApplicationItem = {
64 | createTime: number;
65 | creatorUserID: string;
66 | ex: string;
67 | groupFaceURL: string;
68 | groupID: string;
69 | groupName: string;
70 | groupType: GroupType;
71 | handleResult: ApplicationHandleResult;
72 | handleUserID: string;
73 | handledMsg: string;
74 | handledTime: number;
75 | introduction: string;
76 | memberCount: number;
77 | nickname: string;
78 | notification: string;
79 | ownerUserID: string;
80 | reqMsg: string;
81 | reqTime: number;
82 | joinSource: GroupJoinSource;
83 | status: GroupStatus;
84 | userFaceURL: string;
85 | userID: string;
86 | };
87 | export type FriendApplicationItem = {
88 | createTime: number;
89 | ex: string;
90 | fromFaceURL: string;
91 | fromNickname: string;
92 | fromUserID: string;
93 | handleMsg: string;
94 | handleResult: ApplicationHandleResult;
95 | handleTime: number;
96 | handlerUserID: string;
97 | reqMsg: string;
98 | toFaceURL: string;
99 | toNickname: string;
100 | toUserID: string;
101 | };
102 | export type PublicUserItem = {
103 | nickname: string;
104 | userID: string;
105 | faceURL: string;
106 | ex: string;
107 | };
108 | export type SelfUserInfo = {
109 | createTime: number;
110 | ex: string;
111 | faceURL: string;
112 | nickname: string;
113 | userID: string;
114 | globalRecvMsgOpt: MessageReceiveOptType;
115 | };
116 | export type PartialUserInfo = {
117 | userID: string;
118 | } & Partial>;
119 | export type FriendUserItem = {
120 | addSource: number;
121 | createTime: number;
122 | ex: string;
123 | faceURL: string;
124 | userID: string;
125 | nickname: string;
126 | operatorUserID: string;
127 | ownerUserID: string;
128 | remark: string;
129 | isPinned: boolean;
130 | attachedInfo: string;
131 | };
132 | export type SearchedFriendsInfo = FriendUserItem & {
133 | relationship: Relationship;
134 | };
135 | export type FriendshipInfo = {
136 | result: number;
137 | userID: string;
138 | };
139 | export type BlackUserItem = {
140 | addSource: number;
141 | userID: string;
142 | createTime: number;
143 | ex: string;
144 | faceURL: string;
145 | nickname: string;
146 | operatorUserID: string;
147 | ownerUserID: string;
148 | };
149 | export type GroupItem = {
150 | groupID: string;
151 | groupName: string;
152 | notification: string;
153 | notificationUserID: string;
154 | notificationUpdateTime: number;
155 | introduction: string;
156 | faceURL: string;
157 | ownerUserID: string;
158 | createTime: number;
159 | memberCount: number;
160 | status: GroupStatus;
161 | creatorUserID: string;
162 | groupType: GroupType;
163 | needVerification: GroupVerificationType;
164 | ex: string;
165 | applyMemberFriend: AllowType;
166 | lookMemberInfo: AllowType;
167 | displayIsRead: boolean;
168 | };
169 | export type GroupMemberItem = {
170 | groupID: string;
171 | userID: string;
172 | nickname: string;
173 | faceURL: string;
174 | roleLevel: GroupMemberRole;
175 | muteEndTime: number;
176 | joinTime: number;
177 | joinSource: GroupJoinSource;
178 | inviterUserID: string;
179 | operatorUserID: string;
180 | ex: string;
181 | };
182 | export type ConversationItem = {
183 | conversationID: string;
184 | conversationType: SessionType;
185 | userID: string;
186 | groupID: string;
187 | showName: string;
188 | faceURL: string;
189 | recvMsgOpt: MessageReceiveOptType;
190 | unreadCount: number;
191 | groupAtType: GroupAtType;
192 | latestMsg: string;
193 | latestMsgSendTime: number;
194 | draftText: string;
195 | draftTextTime: number;
196 | burnDuration: number;
197 | msgDestructTime: number;
198 | isPinned: boolean;
199 | isNotInGroup: boolean;
200 | isPrivateChat: boolean;
201 | isMsgDestruct: boolean;
202 | attachedInfo: string;
203 | ex?: string;
204 | };
205 | export type MessageItem = {
206 | clientMsgID: string;
207 | serverMsgID: string;
208 | createTime: number;
209 | sendTime: number;
210 | sessionType: SessionType;
211 | sendID: string;
212 | recvID: string;
213 | msgFrom: number;
214 | contentType: MessageType;
215 | senderPlatformID: Platform;
216 | senderNickname: string;
217 | senderFaceUrl: string;
218 | groupID: string;
219 | content: string;
220 | seq: number;
221 | isRead: boolean;
222 | status: MessageStatus;
223 | isReact?: boolean;
224 | isExternalExtensions?: boolean;
225 | offlinePush?: OfflinePush;
226 | ex?: string;
227 | localEx?: string;
228 | textElem?: TextElem;
229 | cardElem?: CardElem;
230 | pictureElem?: PictureElem;
231 | soundElem?: SoundElem;
232 | videoElem?: VideoElem;
233 | fileElem?: FileElem;
234 | mergeElem?: MergeElem;
235 | atTextElem?: AtTextElem;
236 | faceElem?: FaceElem;
237 | locationElem?: LocationElem;
238 | customElem?: CustomElem;
239 | quoteElem?: QuoteElem;
240 | notificationElem?: NotificationElem;
241 | advancedTextElem?: AdvancedTextElem;
242 | typingElem?: TypingElem;
243 | attachedInfoElem: AttachedInfoElem;
244 | };
245 | export type TextElem = {
246 | content: string;
247 | };
248 | export type CardElem = {
249 | userID: string;
250 | nickname: string;
251 | faceURL: string;
252 | ex: string;
253 | };
254 | export type AtTextElem = {
255 | text: string;
256 | atUserList: string[];
257 | atUsersInfo?: AtUsersInfoItem[];
258 | quoteMessage?: MessageItem;
259 | isAtSelf?: boolean;
260 | };
261 | export type NotificationElem = {
262 | detail: string;
263 | };
264 | export type AdvancedTextElem = {
265 | text: string;
266 | messageEntityList: MessageEntity[];
267 | };
268 | export type TypingElem = {
269 | msgTips: string;
270 | };
271 | export type CustomElem = {
272 | data: string;
273 | description: string;
274 | extension: string;
275 | };
276 | export type FileElem = {
277 | filePath: string;
278 | uuid: string;
279 | sourceUrl: string;
280 | fileName: string;
281 | fileSize: number;
282 | };
283 | export type FaceElem = {
284 | index: number;
285 | data: string;
286 | };
287 | export type LocationElem = {
288 | description: string;
289 | longitude: number;
290 | latitude: number;
291 | };
292 | export type MergeElem = {
293 | title: string;
294 | abstractList: string[];
295 | multiMessage: MessageItem[];
296 | messageEntityList: MessageEntity[];
297 | };
298 | export type OfflinePush = {
299 | title: string;
300 | desc: string;
301 | ex: string;
302 | iOSPushSound: string;
303 | iOSBadgeCount: boolean;
304 | };
305 | export type PictureElem = {
306 | sourcePath: string;
307 | sourcePicture: Picture;
308 | bigPicture: Picture;
309 | snapshotPicture: Picture;
310 | };
311 | export type AttachedInfoElem = {
312 | groupHasReadInfo: GroupHasReadInfo;
313 | isPrivateChat: boolean;
314 | isEncryption: boolean;
315 | inEncryptStatus: boolean;
316 | burnDuration: number;
317 | hasReadTime: number;
318 | messageEntityList?: MessageEntity[];
319 | uploadProgress?: UploadProgress;
320 | };
321 | export type UploadProgress = {
322 | total: number;
323 | save: number;
324 | current: number;
325 | };
326 | export type GroupHasReadInfo = {
327 | hasReadCount: number;
328 | unreadCount: number;
329 | hasReadUserIDList: string[];
330 | groupMemberCount: number;
331 | };
332 | export type Picture = {
333 | uuid: string;
334 | type: string;
335 | size: number;
336 | width: number;
337 | height: number;
338 | url: string;
339 | };
340 | export type QuoteElem = {
341 | text: string;
342 | quoteMessage: MessageItem;
343 | };
344 | export type SoundElem = {
345 | uuid: string;
346 | soundPath: string;
347 | sourceUrl: string;
348 | dataSize: number;
349 | duration: number;
350 | };
351 | export type VideoElem = {
352 | videoPath: string;
353 | videoUUID: string;
354 | videoUrl: string;
355 | videoType: string;
356 | videoSize: number;
357 | duration: number;
358 | snapshotPath: string;
359 | snapshotUUID: string;
360 | snapshotSize: number;
361 | snapshotUrl: string;
362 | snapshotWidth: number;
363 | snapshotHeight: number;
364 | };
365 | export type AdvancedRevokeContent = {
366 | clientMsgID: string;
367 | revokeTime: number;
368 | revokerID: string;
369 | revokerNickname: string;
370 | revokerRole: number;
371 | seq: number;
372 | sessionType: SessionType;
373 | sourceMessageSendID: string;
374 | sourceMessageSendTime: number;
375 | sourceMessageSenderNickname: string;
376 | };
377 |
378 | export type RevokedInfo = {
379 | revokerID: string;
380 | revokerRole: number;
381 | clientMsgID: string;
382 | revokerNickname: string;
383 | revokeTime: number;
384 | sourceMessageSendTime: number;
385 | sourceMessageSendID: string;
386 | sourceMessageSenderNickname: string;
387 | sessionType: number;
388 | seq: number;
389 | ex: string;
390 | };
391 |
392 | export type ReceiptInfo = {
393 | userID: string;
394 | groupID: string;
395 | msgIDList: string[];
396 | readTime: number;
397 | msgFrom: number;
398 | contentType: MessageType;
399 | sessionType: SessionType;
400 | };
401 |
402 | export type SearchMessageResult = {
403 | totalCount: number;
404 | searchResultItems?: SearchMessageResultItem[];
405 | findResultItems?: SearchMessageResultItem[];
406 | };
407 |
408 | export type SearchMessageResultItem = {
409 | conversationID: string;
410 | messageCount: number;
411 | conversationType: SessionType;
412 | showName: string;
413 | faceURL: string;
414 | messageList: MessageItem[];
415 | };
416 |
417 | export type AdvancedGetMessageResult = {
418 | isEnd: boolean;
419 | lastMinSeq: number;
420 | errCode: number;
421 | errMsg: string;
422 | messageList: MessageItem[];
423 | };
424 |
425 | export type RtcInvite = {
426 | inviterUserID: string;
427 | inviteeUserIDList: string[];
428 | customData?: string;
429 | groupID: string;
430 | roomID: string;
431 | timeout: number;
432 | mediaType: string;
433 | sessionType: number;
434 | platformID: number;
435 | initiateTime?: number;
436 | busyLineUserIDList?: string[];
437 | };
438 |
439 | export type UserOnlineState = {
440 | platformIDs?: Platform[];
441 | status: OnlineState;
442 | userID: string;
443 | };
444 |
445 | export type ConversationInputStatus = {
446 | conversationID: string;
447 | userID: string;
448 | platformIDs: Platform[];
449 | };
450 |
451 | export type GroupMessageReceiptInfo = {
452 | conversationID: string;
453 | groupMessageReadInfo: GroupMessageReadInfo[];
454 | };
455 | export type GroupMessageReadInfo = {
456 | clientMsgID: string;
457 | hasReadCount: number;
458 | unreadCount: number;
459 | readMembers: GroupMemberItem[];
460 | };
461 |
462 | export type RtcInviteResults = {
463 | liveURL: string;
464 | roomID: string;
465 | token: string;
466 | busyLineUserIDList?: string[];
467 | };
468 |
469 | export type ParticipantInfo = {
470 | userInfo: PublicUserItem;
471 | groupMemberInfo?: GroupMemberItem;
472 | groupInfo?: GroupItem;
473 | };
474 |
475 | export type CallingRoomData = {
476 | participant?: ParticipantInfo[];
477 | invitation?: RtcInvite;
478 | roomID: string;
479 | };
480 |
--------------------------------------------------------------------------------
/src/types/enum.ts:
--------------------------------------------------------------------------------
1 | export enum MessageReceiveOptType {
2 | Normal = 0,
3 | NotReceive = 1,
4 | NotNotify = 2,
5 | }
6 | export enum AllowType {
7 | Allowed = 0,
8 | NotAllowed = 1,
9 | }
10 | export enum GroupType {
11 | Group = 2,
12 | WorkingGroup = 2,
13 | }
14 | export enum GroupJoinSource {
15 | Invitation = 2,
16 | Search = 3,
17 | QrCode = 4,
18 | }
19 | export enum GroupMemberRole {
20 | Normal = 20,
21 | Admin = 60,
22 | Owner = 100,
23 | }
24 | export enum GroupVerificationType {
25 | ApplyNeedInviteNot = 0,
26 | AllNeed = 1,
27 | AllNot = 2,
28 | }
29 | export enum MessageStatus {
30 | Sending = 1,
31 | Succeed = 2,
32 | Failed = 3,
33 | }
34 | export enum Platform {
35 | iOS = 1,
36 | Android = 2,
37 | Windows = 3,
38 | MacOSX = 4,
39 | Web = 5,
40 | Linux = 7,
41 | AndroidPad = 8,
42 | iPad = 9,
43 | }
44 | export enum LogLevel {
45 | Verbose = 6,
46 | Debug = 5,
47 | Info = 4,
48 | Warn = 3,
49 | Error = 2,
50 | Fatal = 1,
51 | Panic = 0,
52 | }
53 | export enum ApplicationHandleResult {
54 | Unprocessed = 0,
55 | Agree = 1,
56 | Reject = -1,
57 | }
58 | export enum MessageType {
59 | TextMessage = 101,
60 | PictureMessage = 102,
61 | VoiceMessage = 103,
62 | VideoMessage = 104,
63 | FileMessage = 105,
64 | AtTextMessage = 106,
65 | MergeMessage = 107,
66 | CardMessage = 108,
67 | LocationMessage = 109,
68 | CustomMessage = 110,
69 | TypingMessage = 113,
70 | QuoteMessage = 114,
71 | FaceMessage = 115,
72 | FriendAdded = 1201,
73 | OANotification = 1400,
74 | GroupCreated = 1501,
75 | GroupInfoUpdated = 1502,
76 | MemberQuit = 1504,
77 | GroupOwnerTransferred = 1507,
78 | MemberKicked = 1508,
79 | MemberInvited = 1509,
80 | MemberEnter = 1510,
81 | GroupDismissed = 1511,
82 | GroupMemberMuted = 1512,
83 | GroupMemberCancelMuted = 1513,
84 | GroupMuted = 1514,
85 | GroupCancelMuted = 1515,
86 | GroupAnnouncementUpdated = 1519,
87 | GroupNameUpdated = 1520,
88 | BurnMessageChange = 1701,
89 | RevokeMessage = 2101,
90 | }
91 | export enum SessionType {
92 | Single = 1,
93 | Group = 3,
94 | WorkingGroup = 3,
95 | Notification = 4,
96 | }
97 | export enum GroupStatus {
98 | Normal = 0,
99 | Banned = 1,
100 | Dismissed = 2,
101 | Muted = 3,
102 | }
103 | export enum GroupAtType {
104 | AtNormal = 0,
105 | AtMe = 1,
106 | AtAll = 2,
107 | AtAllAtMe = 3,
108 | AtGroupNotice = 4,
109 | }
110 | export enum GroupMemberFilter {
111 | All = 0,
112 | Owner = 1,
113 | Admin = 2,
114 | Normal = 3,
115 | AdminAndNormal = 4,
116 | AdminAndOwner = 5,
117 | }
118 | export enum Relationship {
119 | isBlack = 0,
120 | isFriend = 1,
121 | }
122 | export enum LoginStatus {
123 | Logout = 1,
124 | Logging = 2,
125 | Logged = 3,
126 | }
127 | export enum OnlineState {
128 | Online = 1,
129 | Offline = 0,
130 | }
131 | export enum GroupMessageReaderFilter {
132 | Read = 0,
133 | UnRead = 1,
134 | }
135 |
--------------------------------------------------------------------------------
/src/types/eventData.ts:
--------------------------------------------------------------------------------
1 | import { CbEvents } from '..';
2 | import {
3 | BlackUserItem,
4 | ConversationInputStatus,
5 | ConversationItem,
6 | FriendApplicationItem,
7 | FriendUserItem,
8 | GroupApplicationItem,
9 | GroupItem,
10 | GroupMemberItem,
11 | GroupMessageReceiptInfo,
12 | MessageItem,
13 | ReceiptInfo,
14 | RevokedInfo,
15 | SelfUserInfo,
16 | UserOnlineState,
17 | } from './entity';
18 |
19 | export type EventDataMap = {
20 | [CbEvents.OnProgress]: { progress: number; clientMsgID: string };
21 | [CbEvents.OnBlackAdded]: BlackUserItem;
22 | [CbEvents.OnBlackDeleted]: BlackUserItem;
23 | [CbEvents.OnConversationChanged]: ConversationItem[];
24 | [CbEvents.OnFriendAdded]: FriendUserItem;
25 | [CbEvents.OnFriendApplicationAdded]: FriendApplicationItem;
26 | [CbEvents.OnFriendApplicationDeleted]: FriendApplicationItem;
27 | [CbEvents.OnFriendApplicationRejected]: FriendApplicationItem;
28 | [CbEvents.OnFriendDeleted]: FriendUserItem;
29 | [CbEvents.OnFriendInfoChanged]: FriendUserItem;
30 | [CbEvents.OnGroupApplicationAdded]: GroupApplicationItem;
31 | [CbEvents.OnGroupApplicationDeleted]: GroupApplicationItem;
32 | [CbEvents.OnGroupApplicationRejected]: GroupApplicationItem;
33 | [CbEvents.OnGroupApplicationAccepted]: GroupApplicationItem;
34 | [CbEvents.OnGroupDismissed]: GroupItem;
35 | [CbEvents.OnGroupMemberDeleted]: GroupMemberItem;
36 | [CbEvents.OnGroupMemberInfoChanged]: GroupMemberItem;
37 | [CbEvents.OnJoinedGroupAdded]: GroupItem;
38 | [CbEvents.OnJoinedGroupDeleted]: GroupItem;
39 | [CbEvents.OnNewConversation]: ConversationItem[];
40 | [CbEvents.OnConversationUserInputStatusChanged]: ConversationInputStatus;
41 | [CbEvents.OnNewRecvMessageRevoked]: RevokedInfo;
42 | [CbEvents.OnRecvC2CReadReceipt]: ReceiptInfo[];
43 | [CbEvents.OnRecvGroupReadReceipt]: GroupMessageReceiptInfo;
44 | [CbEvents.OnRecvNewMessage]: MessageItem;
45 | [CbEvents.OnRecvNewMessages]: MessageItem[];
46 | [CbEvents.OnRecvOfflineNewMessage]: MessageItem;
47 | [CbEvents.OnRecvOnlineOnlyMessage]: MessageItem;
48 | [CbEvents.OnRecvOfflineNewMessages]: MessageItem[];
49 | [CbEvents.OnRecvOnlineOnlyMessages]: MessageItem[];
50 | [CbEvents.OnSelfInfoUpdated]: SelfUserInfo;
51 | [CbEvents.OnSyncServerFailed]: void;
52 | [CbEvents.OnSyncServerStart]: boolean;
53 | [CbEvents.OnSyncServerProgress]: number;
54 | [CbEvents.OnSyncServerFinish]: void;
55 | [CbEvents.OnTotalUnreadMessageCountChanged]: number;
56 | [CbEvents.OnUserStatusChanged]: UserOnlineState;
57 | [CbEvents.OnConnectFailed]: void;
58 | [CbEvents.OnConnectSuccess]: void;
59 | [CbEvents.OnConnecting]: void;
60 | [CbEvents.OnKickedOffline]: void;
61 | [CbEvents.OnUserTokenExpired]: void;
62 | [CbEvents.OnUserTokenInvalid]: void;
63 | };
64 |
65 | export type DataOfEvent = E extends keyof EventDataMap
66 | ? EventDataMap[E]
67 | : never;
68 |
--------------------------------------------------------------------------------
/src/types/params.ts:
--------------------------------------------------------------------------------
1 | import {
2 | MessageEntity,
3 | OfflinePush,
4 | PicBaseInfo,
5 | AtUsersInfoItem,
6 | MessageItem,
7 | SelfUserInfo,
8 | RtcInvite,
9 | GroupItem,
10 | } from './entity';
11 | import {
12 | AllowType,
13 | GroupJoinSource,
14 | GroupVerificationType,
15 | MessageType,
16 | MessageReceiveOptType,
17 | GroupMemberRole,
18 | GroupMemberFilter,
19 | LogLevel,
20 | GroupMessageReaderFilter,
21 | GroupAtType,
22 | } from './enum';
23 |
24 | export type WasmPathConfig = {
25 | coreWasmPath?: string;
26 | sqlWasmPath?: string;
27 | debug?: boolean;
28 | };
29 |
30 | export type InitAndLoginConfig = {
31 | userID: string;
32 | token: string;
33 | platformID: number;
34 | apiAddr: string;
35 | wsAddr: string;
36 | logLevel?: LogLevel;
37 | isLogStandardOutput?: boolean;
38 | isExternalExtensions?: boolean;
39 | tryParse?: boolean;
40 | };
41 |
42 | export type GetOneConversationParams = {
43 | sourceID: string;
44 | sessionType: number;
45 | };
46 | export type GetAdvancedHistoryMsgParams = {
47 | userID?: string;
48 | groupID?: string;
49 | lastMinSeq: number;
50 | count: number;
51 | startClientMsgID: string;
52 | conversationID: string;
53 | };
54 | export type GetHistoryMsgParams = {
55 | userID: string;
56 | groupID: string;
57 | count: number;
58 | startClientMsgID: string;
59 | conversationID?: string;
60 | };
61 | export type SendGroupReadReceiptParams = {
62 | conversationID: string;
63 | clientMsgIDList: string[];
64 | };
65 | export type GetGroupMessageReaderParams = {
66 | conversationID: string;
67 | clientMsgID: string;
68 | filter: GroupMessageReaderFilter;
69 | offset: number;
70 | count: number;
71 | };
72 | export type GetGroupMemberParams = {
73 | groupID: string;
74 | filter: GroupMemberFilter;
75 | offset: number;
76 | count: number;
77 | };
78 | export type SendMsgParams = {
79 | recvID: string;
80 | groupID: string;
81 | offlinePushInfo?: OfflinePush;
82 | message: MessageItem;
83 | isOnlineOnly?: boolean;
84 | };
85 | export type SetMessageLocalExParams = {
86 | conversationID: string;
87 | clientMsgID: string;
88 | localEx: string;
89 | };
90 | export type ImageMsgParamsByURL = {
91 | sourcePicture: PicBaseInfo;
92 | bigPicture: PicBaseInfo;
93 | snapshotPicture: PicBaseInfo;
94 | sourcePath: string;
95 | };
96 | export type VideoMsgParamsByURL = {
97 | videoPath: string;
98 | duration: number;
99 | videoType: string;
100 | snapshotPath: string;
101 | videoUUID: string;
102 | videoUrl: string;
103 | videoSize: number;
104 | snapshotUUID: string;
105 | snapshotSize: number;
106 | snapshotUrl: string;
107 | snapshotWidth: number;
108 | snapshotHeight: number;
109 | snapShotType?: string;
110 | };
111 | export type VideoMsgParamsByFullPath = {
112 | videoFullPath: string;
113 | videoType: string;
114 | duration: number;
115 | snapshotFullPath: string;
116 | };
117 | export type CustomMsgParams = {
118 | data: string;
119 | extension: string;
120 | description: string;
121 | };
122 | export type QuoteMsgParams = {
123 | text: string;
124 | message: string;
125 | };
126 | export type AdvancedQuoteMsgParams = {
127 | text: string;
128 | message: MessageItem;
129 | messageEntityList?: MessageEntity[];
130 | };
131 | export type AdvancedMsgParams = {
132 | text: string;
133 | messageEntityList?: MessageEntity[];
134 | };
135 | export type SetConversationParams = {
136 | conversationID: string;
137 | recvMsgOpt?: MessageReceiveOptType;
138 | groupAtType?: GroupAtType;
139 | burnDuration?: number;
140 | msgDestructTime?: number;
141 | isPinned?: boolean;
142 | isPrivateChat?: boolean;
143 | isMsgDestruct?: boolean;
144 | ex?: string;
145 | };
146 | export type SetConversationPrivateStateParams = {
147 | conversationID: string;
148 | isPrivate: boolean;
149 | };
150 | export type SplitConversationParams = {
151 | offset: number;
152 | count: number;
153 | };
154 | export type SetConversationDraftParams = {
155 | conversationID: string;
156 | draftText: string;
157 | };
158 | export type SetConversationPinParams = {
159 | conversationID: string;
160 | isPinned: boolean;
161 | };
162 | export type JoinGroupParams = {
163 | groupID: string;
164 | reqMsg: string;
165 | joinSource: GroupJoinSource;
166 | ex?: string;
167 | };
168 | export type SearchGroupParams = {
169 | keywordList: string[];
170 | isSearchGroupID: boolean;
171 | isSearchGroupName: boolean;
172 | };
173 | export type ChangeGroupMuteParams = {
174 | groupID: string;
175 | isMute: boolean;
176 | };
177 | export type ChangeGroupMemberMuteParams = {
178 | groupID: string;
179 | userID: string;
180 | mutedSeconds: number;
181 | };
182 | export type TransferGroupParams = {
183 | groupID: string;
184 | newOwnerUserID: string;
185 | };
186 | export type AccessGroupApplicationParams = {
187 | groupID: string;
188 | fromUserID: string;
189 | handleMsg: string;
190 | };
191 | export type SetGroupRoleParams = {
192 | groupID: string;
193 | userID: string;
194 | roleLevel: GroupMemberRole;
195 | };
196 | export type SetGroupVerificationParams = {
197 | verification: GroupVerificationType;
198 | groupID: string;
199 | };
200 | export type SetBurnDurationParams = {
201 | conversationID: string;
202 | burnDuration: number;
203 | };
204 | export type AtMsgParams = {
205 | text: string;
206 | atUserIDList: string[];
207 | atUsersInfo?: AtUsersInfoItem[];
208 | message?: MessageItem;
209 | };
210 | export type SoundMsgParamsByURL = {
211 | uuid: string;
212 | soundPath: string;
213 | sourceUrl: string;
214 | dataSize: number;
215 | duration: number;
216 | soundType?: string;
217 | };
218 | export type FileMsgParamsByURL = {
219 | filePath: string;
220 | fileName: string;
221 | uuid: string;
222 | sourceUrl: string;
223 | fileSize: number;
224 | fileType?: string;
225 | };
226 | export type FileMsgParamsByFullPath = {
227 | fileFullPath: string;
228 | fileName: string;
229 | };
230 | export type SoundMsgParamsByFullPath = {
231 | soundPath: string;
232 | duration: number;
233 | };
234 | export type MergerMsgParams = {
235 | messageList: MessageItem[];
236 | title: string;
237 | summaryList: string[];
238 | };
239 | export type FaceMessageParams = {
240 | index: number;
241 | data: string;
242 | };
243 | export type LocationMsgParams = {
244 | description: string;
245 | longitude: number;
246 | latitude: number;
247 | };
248 | export type InsertSingleMsgParams = {
249 | message: MessageItem;
250 | recvID: string;
251 | sendID: string;
252 | };
253 | export type InsertGroupMsgParams = {
254 | message: MessageItem;
255 | groupID: string;
256 | sendID: string;
257 | };
258 | export type AccessMessageParams = {
259 | conversationID: string;
260 | clientMsgID: string;
261 | };
262 | export type TypingUpdateParams = {
263 | recvID: string;
264 | msgTip: string;
265 | };
266 | export type ChangeInputStatesParams = {
267 | conversationID: string;
268 | focus: boolean;
269 | };
270 | export type GetInputstatesParams = {
271 | conversationID: string;
272 | userID: string;
273 | };
274 | export type SetConversationExParams = {
275 | conversationID: string;
276 | ex: string;
277 | };
278 | export type SetConversationRecvOptParams = {
279 | conversationID: string;
280 | opt: MessageReceiveOptType;
281 | };
282 | export type SearchLocalParams = {
283 | conversationID: string;
284 | keywordList: string[];
285 | keywordListMatchType?: number;
286 | senderUserIDList?: string[];
287 | messageTypeList?: MessageType[];
288 | searchTimePosition?: number;
289 | searchTimePeriod?: number;
290 | pageIndex?: number;
291 | count?: number;
292 | };
293 | export type AddFriendParams = {
294 | toUserID: string;
295 | reqMsg: string;
296 | };
297 | export type SearchFriendParams = {
298 | keywordList: string[];
299 | isSearchUserID: boolean;
300 | isSearchNickname: boolean;
301 | isSearchRemark: boolean;
302 | };
303 | export type GetSpecifiedFriendsParams = {
304 | friendUserIDList: string[];
305 | filterBlack?: boolean;
306 | };
307 | export type UpdateFriendsParams = {
308 | friendUserIDs: string[];
309 | isPinned?: boolean;
310 | remark?: boolean;
311 | ex?: boolean;
312 | };
313 | export type RemarkFriendParams = {
314 | toUserID: string;
315 | remark: string;
316 | };
317 | export type PinFriendParams = {
318 | toUserIDs: string[];
319 | isPinned: boolean;
320 | };
321 | export type SetFriendExParams = {
322 | toUserIDs: string[];
323 | ex: string;
324 | };
325 | export type AccessFriendApplicationParams = {
326 | toUserID: string;
327 | handleMsg: string;
328 | };
329 | export type AddBlackParams = {
330 | toUserID: string;
331 | ex?: string;
332 | };
333 | export type AccessToGroupParams = {
334 | groupID: string;
335 | reason: string;
336 | userIDList: string[];
337 | };
338 | export type GetGroupMemberByTimeParams = {
339 | groupID: string;
340 | filterUserIDList: string[];
341 | offset: number;
342 | count: number;
343 | joinTimeBegin: number;
344 | joinTimeEnd: number;
345 | };
346 | export type SearchGroupMemberParams = {
347 | groupID: string;
348 | keywordList: string[];
349 | isSearchUserID: boolean;
350 | isSearchMemberNickname: boolean;
351 | offset: number;
352 | count: number;
353 | };
354 | export type SetMemberPermissionParams = {
355 | rule: AllowType;
356 | groupID: string;
357 | };
358 | export type OffsetParams = {
359 | offset: number;
360 | count: number;
361 | };
362 | export type CreateGroupParams = {
363 | memberUserIDs: string[];
364 | groupInfo: Partial;
365 | adminUserIDs?: string[];
366 | ownerUserID?: string;
367 | };
368 | export type SetGroupMemberNickParams = {
369 | groupID: string;
370 | userID: string;
371 | groupMemberNickname: string;
372 | };
373 | export type UpdateMemberInfoParams = {
374 | groupID: string;
375 | userID: string;
376 | nickname?: string;
377 | faceURL?: string;
378 | roleLevel?: GroupMemberRole;
379 | ex?: string;
380 | };
381 | export type FindMessageParams = {
382 | conversationID: string;
383 | clientMsgIDList: string[];
384 | };
385 | export type UploadFileParams = {
386 | name: string;
387 | contentType: string;
388 | uuid: string;
389 | file?: File;
390 | filepath?: string;
391 | cause?: string;
392 | };
393 | export type PartialUserItem = Partial;
394 |
395 | export type SignalingInviteParams = {
396 | invitation: RtcInvite;
397 | offlinePushInfo?: OfflinePush;
398 | };
399 | export type RtcActionParams = {
400 | opUserID: string;
401 | invitation: RtcInvite;
402 | };
403 | export type CustomSignalParams = {
404 | roomID: string;
405 | customInfo: string;
406 | };
407 |
408 | export type SetConversationMsgDestructParams = {
409 | conversationID: string;
410 | isMsgDestruct: boolean;
411 | };
412 |
413 | export type SetConversationMsgDestructTimeParams = {
414 | conversationID: string;
415 | msgDestructTime: number;
416 | };
417 |
--------------------------------------------------------------------------------
/src/utils/emitter.ts:
--------------------------------------------------------------------------------
1 | import { WSEvent } from '@/types/entity';
2 | import { CbEvents } from '../constant';
3 | import { DataOfEvent } from '../types/eventData';
4 |
5 | interface Events {
6 | [key: string]: Cbfn[];
7 | }
8 |
9 | type Cbfn = (data: WSEvent>) => void;
10 |
11 | class Emitter {
12 | private events: Events;
13 |
14 | constructor() {
15 | this.events = {};
16 | }
17 |
18 | emit(event: E, data: WSEvent>) {
19 | if (this.events[event]) {
20 | this.events[event].forEach(fn => {
21 | return fn(data);
22 | });
23 | }
24 |
25 | return this;
26 | }
27 |
28 | on(event: E, fn: Cbfn) {
29 | if (this.events[event]) {
30 | this.events[event].push(fn);
31 | } else {
32 | this.events[event] = [fn];
33 | }
34 |
35 | return this;
36 | }
37 |
38 | off(event: E, fn: Cbfn) {
39 | if (event && typeof fn === 'function' && this.events[event]) {
40 | const listeners = this.events[event];
41 | if (!listeners || listeners.length === 0) {
42 | return;
43 | }
44 | const index = listeners.findIndex(_fn => {
45 | return _fn === fn;
46 | });
47 | if (index !== -1) {
48 | listeners.splice(index, 1);
49 | }
50 | }
51 |
52 | return this;
53 | }
54 | }
55 |
56 | export default Emitter;
57 |
--------------------------------------------------------------------------------
/src/utils/escape.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line no-control-regex
2 | const CHARS_GLOBAL_BACKSLASH_SUPPORTED_RX = /[\0\b\t\n\r\x1a"'\\]/g;
3 | const CHARS_ESCAPE_BACKSLASH_SUPPORTED_MAP: Record = {
4 | '\0': '\\0',
5 | '\b': '\\b',
6 | '\t': '\\t',
7 | '\n': '\\n',
8 | '\r': '\\r',
9 | '\x1a': '\\Z',
10 | '"': '\\"',
11 | "'": "\\'",
12 | '\\': '\\\\',
13 | };
14 |
15 | /**
16 | * Escapes the given string to protect against SQL injection attacks.
17 | *
18 | * By default it assumes that backslashes are not supported as they are not part of the standard SQL spec.
19 | * Quoting from the [SQLlite web site](https://sqlite.org/lang_expr.html):
20 | *
21 | * > C-style escapes using the backslash character are not supported because they are not standard SQL.
22 | *
23 | * This means three things:
24 | *
25 | * - backslashes and double quotes `"` are not escaped by default
26 | * - single quotes are escaped via `''` instead of `\'`
27 | * - your sql engine should throw an error when encountering a backslash escape
28 | * as part of a string, unless it is a literal backslash, i.e. `'backslash: \\'`.
29 | *
30 | * It is recommended to set the `backslashSupported` option `true` if your SQL
31 | * engine supports it. In that case backslash sequences are escaped and single
32 | * and double quotes are escaped via a backslash, i.e. `'\''`.
33 | *
34 | */
35 | export function escapeString(
36 | val: string,
37 | opts: { backslashSupported: boolean } = { backslashSupported: false }
38 | ) {
39 | if (val == null) {
40 | throw new Error('Need to pass a valid string');
41 | }
42 | opts = opts || {};
43 | const backslashSupported = !!opts.backslashSupported;
44 |
45 | if (!backslashSupported) return "'" + val.replace(/'/g, "''") + "'";
46 |
47 | const charsRx = CHARS_GLOBAL_BACKSLASH_SUPPORTED_RX;
48 | const charsEscapeMap = CHARS_ESCAPE_BACKSLASH_SUPPORTED_MAP;
49 | let chunkIndex = (charsRx.lastIndex = 0);
50 | let escapedVal = '';
51 | let match;
52 |
53 | while ((match = charsRx.exec(val))) {
54 | escapedVal += val.slice(chunkIndex, match.index) + charsEscapeMap[match[0]];
55 | chunkIndex = charsRx.lastIndex;
56 | }
57 |
58 | // Nothing was escaped
59 | if (chunkIndex === 0) return "'" + val + "'";
60 |
61 | if (chunkIndex < val.length)
62 | return "'" + escapedVal + val.slice(chunkIndex) + "'";
63 | return "'" + escapedVal + "'";
64 | }
65 |
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from './response';
2 | export * from './timer';
3 | export * from './key';
4 | export * from './value';
5 | export * from './is';
6 | export * from './escape';
7 | export * from './logFormat';
8 |
--------------------------------------------------------------------------------
/src/utils/is.ts:
--------------------------------------------------------------------------------
1 | export function isString(value: unknown) {
2 | return typeof value === 'string';
3 | }
4 |
5 | export function isNumber(value: unknown) {
6 | return typeof value === 'number';
7 | }
8 |
9 | export function isBoolean(value: unknown) {
10 | return typeof value === 'boolean';
11 | }
12 |
13 | export function isUndefined(value: unknown) {
14 | return typeof value === 'undefined';
15 | }
16 |
17 | export function isObject(value: unknown) {
18 | return typeof value === 'object' && value !== null;
19 | }
20 |
21 | export function isFunction(value: unknown) {
22 | return typeof value === 'function';
23 | }
24 |
--------------------------------------------------------------------------------
/src/utils/key.ts:
--------------------------------------------------------------------------------
1 | export type KeyType = 'CamelCase' | 'SnakeCase';
2 |
3 | const InternalConstraint = [
4 | ['user_id', 'userID'],
5 | ['group_id', 'groupID'],
6 | ['client_msg_id', 'clientMsgID'],
7 | ['server_msg_id', 'serverMsgID'],
8 | ['send_id', 'sendID'],
9 | ['recv_id', 'recvID'],
10 | ['sender_platform_id', 'senderPlatformID'],
11 | ['sender_nick_name', 'senderNickname'],
12 | ['sender_face_url', 'senderFaceURL'],
13 | ['session_type', 'sessionType'],
14 | ['msg_from', 'msgFrom'],
15 | ['content_type', 'contentType'],
16 | ['content', 'content'],
17 | ['is_read', 'isRead'],
18 | ['is_react', 'isReact'],
19 | ['is_external_extensions', 'isExternalExtensions'],
20 | ['msg_first_modify_time', 'msgFirstModifyTime'],
21 | ['status', 'status'],
22 | ['seq', 'seq'],
23 | ['send_time', 'sendTime'],
24 | ['create_time', 'createTime'],
25 | ['attached_info', 'attachedInfo'],
26 | ['ex', 'ex'],
27 | ['face_url', 'faceURL'],
28 | ['creator_user_id', 'creatorUserID'],
29 | ['conversation_id', 'conversationID'],
30 | ['owner_user_id', 'ownerUserID'],
31 | ['notification_user_id', 'notificationUserID'],
32 | ['operator_user_id', 'operatorUserID'],
33 | ['from_face_url', 'fromFaceURL'],
34 | ['from_user_id', 'fromUserID'],
35 | ['from_gender', 'fromGender'],
36 | ['from_nickname', 'fromNickname'],
37 | ['to_user_id', 'toUserID'],
38 | ['to_nickname', 'toNickname'],
39 | ['to_face_url', 'toFaceURL'],
40 | ['to_gender', 'toGender'],
41 | ['req_msg', 'reqMsg'],
42 | ['handle_msg', 'handleMsg'],
43 | ['handle_time', 'handleTime'],
44 | ['handle_result', 'handleResult'],
45 | ['handler_user_id', 'handlerUserID'],
46 | ['handle_user_id', 'handleUserID'],
47 | ['inviter_user_id', 'inviterUserID'],
48 | ['mute_end_time', 'muteEndTime'],
49 | ['role_level', 'roleLevel'],
50 | ['join_time', 'joinTime'],
51 | ['join_source', 'joinSource'],
52 | ['friend_user_id', 'friendUserID'],
53 | ['recv_msg_opt', 'recvMsgOpt'],
54 | ['group_at_type', 'groupAtType'],
55 | ['latest_msg_send_time', 'latestMsgSendTime'],
56 | ['draft_text_time', 'draftTextTime'],
57 | ['is_private_chat', 'isPrivateChat'],
58 | ['is_not_in_group', 'isNotInGroup'],
59 | ['update_unread_count_time', 'updateUnreadCountTime'],
60 | ['is_msg_destruct', 'isMsgDestruct'],
61 | ['msg_destruct_time', 'msgDestructTime'],
62 | ['part_hash', 'partHash'],
63 | ['upload_id', 'uploadID'],
64 | ['upload_info', 'uploadInfo'],
65 | ['expire_time', 'expireTime'],
66 | ['entity_id', 'entityID'],
67 | ['version_id', 'versionID'],
68 | ['display_is_read', 'displayIsRead'],
69 | ];
70 |
71 | function _getInternalCamelCaseBySnakeCase(key: string) {
72 | const pair = InternalConstraint.find(p => {
73 | return p[0] === key;
74 | });
75 |
76 | if (pair) {
77 | return pair[1];
78 | }
79 | }
80 |
81 | function _getInternalSnakeCaseByCamelCase(key: string) {
82 | const pair = InternalConstraint.find(p => {
83 | return p[1] === key;
84 | });
85 |
86 | if (pair) {
87 | return pair[0];
88 | }
89 | }
90 |
91 | export function convertSnakeCaseToCamelCase(key: string) {
92 | const internalKey = _getInternalCamelCaseBySnakeCase(key);
93 | if (internalKey) {
94 | return internalKey;
95 | }
96 |
97 | const cArr = [];
98 | let lastSign = -2;
99 | for (let i = 0; i < key.length; i++) {
100 | const c = key[i];
101 |
102 | if (c === '_' && i < key.length - 1) {
103 | lastSign = i;
104 | continue;
105 | }
106 |
107 | if (i - 1 === lastSign) {
108 | cArr.push(c.toUpperCase());
109 | } else {
110 | cArr.push(c);
111 | }
112 | }
113 |
114 | return cArr.join('');
115 | }
116 |
117 | export function convertCamelCaseToSnakeCase(key: string) {
118 | const internalKey = _getInternalSnakeCaseByCamelCase(key);
119 | if (internalKey) {
120 | return internalKey;
121 | }
122 |
123 | const cArr = [];
124 | for (let i = 0; i < key.length; i++) {
125 | const c = key[i];
126 |
127 | if (c.toLowerCase() !== c) {
128 | cArr.push('_');
129 | }
130 |
131 | cArr.push(c.toLowerCase());
132 | }
133 |
134 | return cArr.join('');
135 | }
136 |
--------------------------------------------------------------------------------
/src/utils/logFormat.ts:
--------------------------------------------------------------------------------
1 | export function logBoxStyleValue(backgroundColor?: string, color?: string) {
2 | return `font-size:14px; background:${backgroundColor ?? '#ffffff'}; color:${
3 | color ?? '#000000'
4 | }; border-radius:4px; padding-inline:4px;`;
5 | }
6 |
--------------------------------------------------------------------------------
/src/utils/response.ts:
--------------------------------------------------------------------------------
1 | export function formatResponse(
2 | data: unknown,
3 | errCode?: number,
4 | errMsg?: string
5 | ): any {
6 | let serializedData = data;
7 | if (typeof data === 'object') {
8 | serializedData = JSON.stringify(data);
9 | }
10 |
11 | return {
12 | data: data !== undefined ? serializedData : '{}',
13 | errCode: errCode || 0,
14 | errMsg: errMsg || '',
15 | };
16 | }
17 |
--------------------------------------------------------------------------------
/src/utils/timer.ts:
--------------------------------------------------------------------------------
1 | export async function wait(duration: number) {
2 | return new Promise(resolve => {
3 | const timer = setTimeout(() => {
4 | clearTimeout(timer);
5 | resolve(null);
6 | }, duration);
7 | });
8 | }
9 |
--------------------------------------------------------------------------------
/src/utils/value.ts:
--------------------------------------------------------------------------------
1 | import { QueryExecResult } from '@jlongster/sql.js';
2 | import { escapeString } from './escape';
3 | import { isString } from './is';
4 | import {
5 | KeyType,
6 | convertSnakeCaseToCamelCase,
7 | convertCamelCaseToSnakeCase,
8 | } from './key';
9 |
10 | export function converSqlExecResult(
11 | record: QueryExecResult,
12 | keyType: KeyType = 'CamelCase',
13 | booleanKeys: string[] = [],
14 | convertMap: Record = {}
15 | ) {
16 | const { columns = [], values = [] } = record || {};
17 | const result: Record[] = [];
18 |
19 | values.forEach(v => {
20 | const converted: Record = {};
21 | columns.forEach((k, i) => {
22 | let ck = k;
23 | let cv: unknown = v[i];
24 |
25 | if (keyType === 'CamelCase') {
26 | ck = convertSnakeCaseToCamelCase(k);
27 | }
28 | if (keyType === 'SnakeCase') {
29 | ck = convertCamelCaseToSnakeCase(k);
30 | }
31 | if (booleanKeys.find(bk => bk === ck)) {
32 | cv = !!cv;
33 | }
34 |
35 | ck = convertMap[k] || ck;
36 |
37 | converted[ck] = cv;
38 | });
39 | result.push(converted);
40 | });
41 |
42 | return result;
43 | }
44 |
45 | export function convertToCamelCaseObject(obj: Record) {
46 | const retObj: Record = {};
47 |
48 | Object.keys(obj).forEach(k => {
49 | retObj[convertSnakeCaseToCamelCase(k)] = obj[k];
50 | });
51 |
52 | return retObj;
53 | }
54 |
55 | export function convertToSnakeCaseObject(
56 | obj: Record,
57 | escape = true
58 | ) {
59 | const retObj: Record = {};
60 |
61 | Object.keys(obj).forEach(k => {
62 | let value = obj[k];
63 | if (escape && isString(value)) {
64 | value = escapeString(value as string).slice(1, -1);
65 | }
66 | retObj[convertCamelCaseToSnakeCase(k)] = value;
67 | });
68 |
69 | return retObj;
70 | }
71 |
72 | export function convertObjectField(
73 | obj: Record,
74 | convertMap: Record = {}
75 | ) {
76 | const ret: Record = {};
77 |
78 | Object.keys(obj).forEach(k => {
79 | const nk = convertMap[k] || k;
80 |
81 | ret[nk] = obj[k];
82 | });
83 |
84 | return ret;
85 | }
86 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "declaration": false
5 | },
6 | "exclude": ["test/**/*.spec.ts"]
7 | }
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2018",
4 | "module": "esnext",
5 | "declaration": true,
6 | "outDir": "./lib/",
7 | "strict": true,
8 | "moduleResolution": "node",
9 | "types": ["./src/types"],
10 | "esModuleInterop": true,
11 | "skipLibCheck": true,
12 | "forceConsistentCasingInFileNames": true,
13 | "baseUrl": "./",
14 | "paths": {
15 | "@/*": ["src/*"]
16 | }
17 | },
18 | "include": ["src/**/*.ts"]
19 | }
20 |
--------------------------------------------------------------------------------