This commit is contained in:
2026-05-10 22:03:32 +07:00
parent b857b73132
commit 530b39c749
246 changed files with 27965 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
+5
View File
@@ -0,0 +1,5 @@
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->
+1
View File
@@ -0,0 +1 @@
@AGENTS.md
+40
View File
@@ -0,0 +1,40 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: ""
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
+19
View File
@@ -0,0 +1,19 @@
---
name: CI/CD
about: Report issues with CI/CD pipeline or suggest improvements
title: "[CI/CD]"
labels: ci-cd
assignees: ""
---
**Describe the CI/CD issue**
A clear and concise description of the CI/CD problem.
**Current pipeline behavior**
Describe what's happening in the current pipeline.
**Expected pipeline behavior**
Describe what should happen in the pipeline.
**Additional context**
Add any other context about the CI/CD issue here.
+55
View File
@@ -0,0 +1,55 @@
---
name: Code of Conduct Violation
about: Report a violation of our Code of Conduct
title: "[CONDUCT]"
labels: ["CONDUCT", "community"]
assignees: ""
---
## Code of Conduct Violation Report
**IMPORTANT**: This issue will be handled privately and with respect for all parties involved.
### Type of Violation
<!-- Please select the type of violation -->
- [ ] Harassment or bullying
- [ ] Inappropriate language or behavior
- [ ] Privacy violation (sharing personal information)
- [ ] Spam or trolling
- [ ] Discrimination
- [ ] Other (please describe)
### Description
<!-- Please provide a clear and detailed description of the incident -->
### When did this occur?
<!-- Date and time if known -->
### Where did this occur?
<!-- Please specify where the incident took place -->
- [ ] GitHub Issues
- [ ] GitHub Discussions
- [ ] GitHub Pull Requests
- [ ] GitHub Comments
- [ ] External communication (Discord, email, etc.)
- [ ] Other (please specify)
### People Involved
<!-- Please list the usernames of people involved (if known) -->
### Evidence
<!-- Please provide any relevant links, screenshots, or other evidence -->
<!-- You can drag and drop images here -->
### Impact
<!-- How did this incident affect you or the community? -->
### Additional Context
<!-- Any additional information that might be helpful -->
### Preferred Resolution
<!-- What would you like to see happen? (optional) -->
---
**Note**: This report will be reviewed by the team and handled according to our [Code of Conduct](https://github.com/RFS-ADRENO/zca-js/blob/main/CODE_OF_CONDUCT.md). We are committed to maintaining a safe and welcoming community for everyone.
+19
View File
@@ -0,0 +1,19 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FEAT]"
labels: enhancement
assignees: ""
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
@@ -0,0 +1,16 @@
---
name: Help Wanted request
about: Ask for help with something
title: "[HELP]"
labels: help wanted
assignees: ""
---
**Is your help wanted request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I need help with a problem [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Additional context**
Add any other context or screenshots about the help wanted request here.
+19
View File
@@ -0,0 +1,19 @@
---
name: Performance
about: Report performance issues or suggest optimizations
title: "[PERF]"
labels: performance
assignees: ""
---
**Describe the performance issue**
A clear and concise description of the performance problem.
**Current behavior**
Describe the current performance metrics or behavior.
**Expected behavior**
Describe what performance you expect to see.
**Additional context**
Add any other context about the performance issue here.
+16
View File
@@ -0,0 +1,16 @@
---
name: Question
about: Questions arising during use.
title: "[Question] Some question..."
labels: question
assignees: ""
---
**Ask the questions you want!**
A clear and concise question about what. Ex. When to use API [...]
**Describe the solution you'd like**
A clear and concise description of what you want to
**Additional context**
Add any other context or screenshots about the question here.
+74
View File
@@ -0,0 +1,74 @@
---
name: Security Vulnerability Report
about: Report a security vulnerability
title: "[SECURITY]"
labels: security
assignees: ""
---
## Security Vulnerability Report
**IMPORTANT**: This issue will be handled privately and with the highest priority. Please do not disclose details publicly until the issue is resolved.
### Vulnerability Type
<!-- Please select the type of vulnerability -->
- [ ] Authentication bypass
- [ ] Data exposure/information disclosure
- [ ] Code injection
- [ ] Cross-site scripting (XSS)
- [ ] Cross-site request forgery (CSRF)
- [ ] Denial of service (DoS)
- [ ] Privilege escalation
- [ ] Dependency vulnerability
- [ ] Other (please describe)
### Severity Level
<!-- Please assess the severity -->
- [ ] Critical (immediate action required)
- [ ] High (action required within 24 hours)
- [ ] Medium (action required within 1 week)
- [ ] Low (action required within 1 month)
### Description
<!-- Please provide a clear and detailed description of the vulnerability -->
### Steps to Reproduce
<!-- Please provide clear steps to reproduce the vulnerability -->
1.
2.
3.
### Expected Behavior
<!-- What should happen normally? -->
### Actual Behavior
<!-- What actually happens due to the vulnerability? -->
### Environment
<!-- Please provide details about the environment -->
- **zca-js Version**:
- **Node.js Version**:
- **Operating System**:
- **Browser** (if applicable):
### Impact Assessment
<!-- What is the potential impact of this vulnerability? -->
- **Data at Risk**:
- **Users Affected**:
- **Business Impact**:
### Suggested Fix
<!-- Do you have any suggestions for fixing this vulnerability? (optional) -->
### Additional Information
<!-- Any additional context, logs, or evidence -->
<!-- You can drag and drop files here -->
### Disclosure Timeline
<!-- When do you plan to disclose this publicly? (if applicable) -->
---
**Note**: This report will be reviewed by the security team and handled according to our [Security Policy](https://github.com/RFS-ADRENO/zca-js/blob/main/SECURITY.md). We appreciate your responsible disclosure and will work to resolve this issue promptly.
**⚠️ Warning**: This is an unofficial API library. Please ensure your testing does not violate Zalo's terms of service or put any accounts at risk.
+19
View File
@@ -0,0 +1,19 @@
---
name: Testing
about: Report testing issues or suggest test improvements
title: "[TEST]"
labels: testing
assignees: ""
---
**Describe the testing issue**
A clear and concise description of the testing problem.
**Test case**
Describe the test case that's failing or needs improvement.
**Expected test result**
Describe what the test should verify.
**Additional context**
Add any other context about the testing issue here.
+18
View File
@@ -0,0 +1,18 @@
## What does this PR do?
<!-- Briefly describe the changes you have made -->
## Reason for this PR
<!-- Why is this change needed? -->
## How did you verify your code works?
- [ ] All related features have been fully tested
- [ ] Unit tests have been updated/created if needed
- [ ] No lint/format errors
- [ ] Documentation has been updated if needed
- [ ] Code changes
## Related Issue (if any)
<!-- Attach a link to the related issue or ticket -->
## Testing Instructions
<!-- Provide instructions for reviewers to test this PR -->
+22
View File
@@ -0,0 +1,22 @@
name: lint
on:
pull_request:
branches:
- main
jobs:
lint:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: "18.x"
- run: npm install
- run: npm run build:clean && npm run build:esm && npm run build:cjs
- run: npm run lint
+136
View File
@@ -0,0 +1,136 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
bun.lockb
cookies.json
credentials.json
/.dev
test/**/*.test.*
+1
View File
@@ -0,0 +1 @@
bunx lint-staged
+15
View File
@@ -0,0 +1,15 @@
.dev
examples
src
test
bun.lockb
bun.lock
package-lock.json
tsconfig.json
.husky
.github
.vscode
scripts
+5
View File
@@ -0,0 +1,5 @@
{
"tabWidth": 4,
"printWidth": 120,
"semi": true
}
+3
View File
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules\\typescript\\lib"
}
+163
View File
@@ -0,0 +1,163 @@
# Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement through:
- **GitHub Issues**: Create a private issue with the `[CONDUCT]` label
- **GitHub Discussions**: Use the "Community" category for general concerns
- **Direct Contact**: Reach out to any team member through GitHub
- **Team Members**:
- [@RFS-ADRENO](https://github.com/RFS-ADRENO)
- [@truong9c2208](https://github.com/truong9c2208)
- [@JustKemForFun](https://github.com/JustKemForFun)
All complaints will be reviewed and investigated promptly and fairly by the team.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
## Special Considerations for zca-js
Given that zca-js is an unofficial API library for Zalo, we have additional
guidelines specific to our project:
### Responsible Usage
* **Respect Zalo's Terms of Service**: While this is an unofficial library,
users should be aware of and respect Zalo's terms of service
* **Account Safety**: Do not encourage or provide guidance on circumventing
Zalo's security measures
* **Privacy**: Respect user privacy and do not share personal information
obtained through the API
* **Rate Limiting**: Encourage responsible usage that doesn't overload Zalo's
servers
### Technical Discussions
* **Security**: When discussing security-related topics, use appropriate
channels and follow responsible disclosure practices
* **Bugs and Issues**: Report bugs and issues through proper channels
* **Documentation**: Help improve documentation and examples for the community
---
**Note**: This Code of Conduct is a living document and may be updated as our
community grows and evolves.
+470
View File
@@ -0,0 +1,470 @@
# Contributing to zca-js
Thank you for your interest in contributing to zca-js! This project is maintained by the community and we welcome all contributions.
## Table of Contents
- [Code of Conduct](#code-of-conduct)
- [Getting Started](#getting-started)
- [Development Setup](#development-setup)
- [How to Contribute](#how-to-contribute)
- [Pull Request Process](#pull-request-process)
- [Code Style Guidelines](#code-style-guidelines)
- [Testing Guidelines](#testing-guidelines)
- [Documentation Guidelines](#documentation-guidelines)
- [Security Guidelines](#security-guidelines)
- [Release Process](#release-process)
- [Getting Help](#getting-help)
## Code of Conduct
This project adheres to our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you agree to abide by these rules.
## Getting Started
### Prerequisites
- Node.js >= 18.0.0
- Bun (recommended) or npm
- Git
### Fork and Clone
1. Fork this repository
2. Clone your fork:
```bash
git clone https://github.com/YOUR_USERNAME/zca-js.git
cd zca-js
```
3. Add upstream remote:
```bash
git remote add upstream https://github.com/RFS-ADRENO/zca-js.git
```
## Development Setup
### Install Dependencies
```bash
# Using Bun (recommended)
bun install
# Or using npm
npm install
```
### Build Project
```bash
# Build both ESM and CJS
bun run build
# Build ESM only
bun run build:esm
# Build CJS only
bun run build:cjs
```
### Run Tests
```bash
# Run feature tests
bun run test:feat
# Run specific test file
bun run test/test.ts
```
### Code Formatting
```bash
# Format code with Prettier
bun run prettier
```
## How to Contribute
### Types of Contributions
We welcome the following types of contributions:
- 🐛 **Bug Reports**: Report bugs and issues
- ✨ **Feature Requests**: Suggest new features
- 🔧 **Code Contributions**: Fix bugs and add features
- 📚 **Documentation**: Improve docs and examples
- 🧪 **Tests**: Add or improve tests
- 🔒 **Security**: Report security vulnerabilities
- 🌐 **Translations**: Translate docs to other languages
### Before You Start
1. **Check existing issues**: Search for existing issues before creating new ones
2. **Discuss major changes**: Create an issue to discuss major changes
3. **Follow the roadmap**: Check the current roadmap and priorities
## Pull Request Process
### Creating a Pull Request
1. **Create a feature branch**:
```bash
git checkout -b feature/your-feature-name
# or
git checkout -b fix/your-bug-fix
```
2. **Make your changes**:
- Follow code style guidelines
- Add tests for new functionality
- Update documentation if needed
3. **Test your changes**:
```bash
bun run build
bun run test:feat
```
4. **Commit your changes**:
```bash
git add .
git commit -m "feat: add new API method for group management"
```
5. **Push to your fork**:
```bash
git push origin feature/your-feature-name
```
6. **Create a Pull Request**:
- Use the provided PR template
- Link related issues
- Provide clear description of changes
### PR Review Process
1. **Automated checks** must pass
2. **Code review** by at least one maintainer
3. **Security review** for security-related changes
4. **Documentation review** for API changes
5. **Final approval** before merge
## Code Style Guidelines
### TypeScript Guidelines
- Use TypeScript strict mode
- Prefer interfaces over types for object shapes
- Use meaningful variable and function names
- Add JSDoc comments for public APIs
- Use async/await over Promises when possible
### Code Organization
The project follows a modular structure for better maintainability and organization:
```
zca-js/
├── src/ # Source code directory
│ ├── apis/ # API methods (100+ files)
│ │ ├── sendMessage.ts # Core messaging functionality
│ │ ├── login.ts # Authentication methods
│ │ ├── loginQR.ts # QR code login
│ │ ├── listen.ts # Event listening
│ │ ├── sendVideo.ts # Video sending
│ │ ├── sendVoice.ts # Voice sending
│ │ ├── sendSticker.ts # Sticker sending
│ │ ├── createGroup.ts # Group management
│ │ ├── addReaction.ts # Message reactions
│ │ ├── uploadAttachment.ts # File uploads
│ │ └── ... # 90+ other API methods
│ ├── models/ # TypeScript interfaces and types
│ │ ├── Message.ts # Message interface
│ │ ├── Attachment.ts # File attachment types
│ │ ├── Reaction.ts # Reaction types
│ │ ├── FriendEvent.ts # Friend event types
│ │ ├── GroupEvent.ts # Group event types
│ │ ├── Typing.ts # Typing indicators
│ │ ├── SeenMessage.ts # Message seen events
│ │ ├── DeliveredMessage.ts # Message delivery events
│ │ ├── Undo.ts # Undo functionality
│ │ ├── Enum.ts # Enumerations
│ │ └── index.ts # Model exports
│ ├── Errors/ # Error handling
│ │ ├── ZaloApiError.ts # Custom API error class
│ │ └── index.ts # Error exports
│ ├── context.ts # Context management and state
│ ├── utils.ts # Utility functions and helpers
│ ├── zalo.ts # Main Zalo class implementation
│ ├── update.ts # Update checking functionality
│ └── index.ts # Public API exports
├── examples/ # Usage examples
│ └── echobot.ts # Echo bot example
├── test/ # Test files
│ ├── feat.ts # Feature tests
│ ├── feat.test.ts # Feature test suite
│ ├── test.ts # General tests
│ └── a.png # Test assets
├── .github/ # GitHub configuration
│ └── ISSUE_TEMPLATE/ # Issue templates
├── .dev/ # Development tools (developer generated)
├── dist/ # Build output (generated)
├── node_modules/ # Dependencies (generated)
├── package.json # Project configuration
├── tsconfig.json # TypeScript configuration
├── rollup.config.js # Build configuration
├── README.md # Project documentation
├── CONTRIBUTING.md # Contribution guidelines
├── SECURITY.md # Security policy
├── CODE_OF_CONDUCT.md # Community guidelines
└── LICENSE # MIT License
```
### Key Directories Explained
- **`src/apis/`**: Contains all API method implementations (~100 files)
- **`src/models/`**: TypeScript interfaces and type definitions
- Core data structures for messages, events, and API responses
- Ensures type safety across the application
- **`src/Errors/`**: Custom error handling
- `ZaloApiError.ts`: Handles API-specific errors
- Provides consistent error handling across the library
- **`examples/`**: Usage examples and demonstrations
- `echobot.ts`: Complete example of a Zalo bot implementation
- **`test/`**: Test suites and test assets
- Feature tests for core functionality
- Integration tests for API methods
### Naming Conventions
- **Files**: camelCase (e.g., `sendMessage.ts`)
- **Classes**: PascalCase (e.g., `ZaloApiError`)
- **Functions**: camelCase (e.g., `sendMessage`)
- **Constants**: UPPER_SNAKE_CASE (e.g., `API_BASE_URL`)
- **Interfaces**: PascalCase with `I` prefix (e.g., `IMessage`)
### Error Handling
```typescript
// Good
try {
const result = await api.sendMessage(message);
return result;
} catch (error) {
if (error instanceof ZaloApiError) {
throw error;
}
throw new ZaloApiError(`Failed to send message: ${error.message}`);
}
// Bad
try {
const result = await api.sendMessage(message);
return result;
} catch (error) {
console.error(error);
return null;
}
```
## Testing Guidelines
### Test Structure
```typescript
describe('API Method', () => {
beforeEach(() => {
// Setup
});
afterEach(() => {
// Cleanup
});
it('should handle success case', async () => {
// Test implementation
});
it('should handle error case', async () => {
// Test error handling
});
});
```
### Testing Best Practices
- Test both success and failure scenarios
- Mock external dependencies
- Use descriptive test names
- Keep tests independent
- Test edge cases and error conditions
### Running Tests
```bash
# Run all tests
bun run test:feat
# Run specific test
bun run test/test.ts
# Run with coverage (if available)
bun run test:coverage
```
## Documentation Guidelines
### API Documentation
- Document all public methods with JSDoc
- Include parameter types and descriptions
- Provide usage examples
- Document error conditions
```typescript
/**
* Sends a message to a specific thread
* @param message - The message object containing content and metadata
* @param threadId - The ID of the thread to send the message to
* @param threadType - The type of thread (User or Group)
* @returns Promise<Message> - The sent message object
* @throws {ZaloApiError} When the API request fails
* @example
* ```typescript
* const message = await api.sendMessage(
* { msg: "Hello, world!" },
* "123456789",
* ThreadType.User
* );
* ```
*/
async sendMessage(message: IMessage, threadId: string, threadType: ThreadType): Promise<Message>
```
### README Updates
- Update README.md for new features
- Add examples for new APIs
- Update installation instructions if needed
- Keep the table of contents updated
## Security Guidelines
### Security Best Practices
- Never commit sensitive data (tokens, passwords, etc.)
- Use environment variables for configuration
- Validate all user inputs
- Follow the principle of least privilege
- Report security issues privately
### Security Reporting
If you discover a security vulnerability:
1. **DO NOT** create a public issue
2. Use the [SECURITY.md](SECURITY.md) reporting process
3. Create a private issue with `[SECURITY]` label
4. Contact team members directly for urgent issues
### Code Security
```typescript
// Good - Validate inputs
function sendMessage(content: string, threadId: string) {
if (!content || typeof content !== 'string') {
throw new ZaloApiError('Content must be a non-empty string');
}
if (!threadId || typeof threadId !== 'string') {
throw new ZaloApiError('ThreadId must be a non-empty string');
}
// Implementation
}
// Bad - No validation
function sendMessage(content: any, threadId: any) {
// Implementation without validation
}
```
## Release Process
### Versioning
We follow [Semantic Versioning](https://semver.org/):
- **MAJOR**: Breaking changes
- **MINOR**: New features (backward compatible)
- **PATCH**: Bug fixes (backward compatible)
### Release Checklist
- [ ] All tests pass
- [ ] Documentation is updated
- [ ] Version is bumped in package.json
- [ ] Build is successful
- [ ] Release notes are prepared
### Publishing
```bash
# Build the project
bun run build
# Run tests
bun run test:feat
# Publish to npm
npm publish
```
## Getting Help
### Communication Channels
- **GitHub Issues**: For bug reports and feature requests
- **GitHub Discussions**: For questions and general discussion
- **Pull Requests**: For code contributions
- **Security Issues**: Use `[SECURITY]` label
### Team Members
- [@RFS-ADRENO](https://github.com/RFS-ADRENO)
- [@truong9c2208](https://github.com/truong9c2208)
- [@JustKemForFun](https://github.com/JustKemForFun)
### Resources
- [API Documentation](https://zca-js.tdung.com)
- [Examples](examples/)
- [Security Policy](SECURITY.md)
- [Code of Conduct](CODE_OF_CONDUCT.md)
## Special Considerations for zca-js
### Unofficial API Library
> [!IMPORTANT]
> ⚠️ zca-js is an unofficial API library for Zalo. Please be aware of:
- **Account Risk**: Using this API may result in account suspension
- **Terms of Service**: Respect Zalo's ToS in your contributions
- **Rate Limiting**: Be mindful of API usage limits
- **Privacy**: Protect user privacy and data
### Responsible Development
- Test changes thoroughly before submitting
- Avoid introducing features that could harm users
- Consider the impact on Zalo's infrastructure
- Document any risks or limitations
---
**Thank you for contributing to zca-js!** 🚀
Your contributions help make this library better for the entire community.
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 - 2025 RFS-ADRENO, truong9c2208, JustKemForFun
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+225
View File
@@ -0,0 +1,225 @@
# ZCA-JS
> [!NOTE]
> This is an unofficial Zalo API for personal account. It work by simulating the browser to interact with Zalo Web.
> [!WARNING]
> Using this API could get your account locked or banned. We are not responsible for any issues that may happen. Use it at your own risk.
---
## Table of Contents
- [Installation](#installation)
- [Migrate to V2](#migrate-to-v2)
- [Documentation](#documentation)
- [Basic Usages](#basic-usages)
- [Login](#login)
- [Listen for new messages](#listen-for-new-messages)
- [Send a message](#send-a-message)
- [Get/Send a sticker](#getsend-a-sticker)
- [Example](#example)
- [Projects & Useful Resources](#projects--useful-resources)
- [Contributing](#contributing)
- [License](#license)
- [Support Us](#support-us)
## Installation
```bash
bun add zca-js # or npm install zca-js
```
### Migrate to V2
Since official version 2.0.0, `zca-js` has removed sharp dependency for image metadata extraction. It now requires users to provide their own `imageMetadataGetter` function when initializing the `Zalo` class if they want to send images/gifs by file path.
Example of custom `imageMetadataGetter` using `sharp`:
```bash
bun add sharp # or npm install sharp
```
```javascript
import { Zalo } from "zca-js";
import sharp from "sharp";
import fs from "node:fs";
async function imageMetadataGetter(filePath) {
const data = await fs.promises.readFile(filePath);
const metadata = await sharp(data).metadata();
return {
height: metadata.height,
width: metadata.width,
size: metadata.size || data.length,
};
}
const zalo = new Zalo({
imageMetadataGetter,
});
```
---
## Documentation
See [API Documentation](https://zca-js.tdung.com) for more details.
---
## Basic Usages
### Login
```javascript
import { Zalo } from "zca-js";
const zalo = new Zalo();
const api = await zalo.loginQR();
```
### Listen for new messages
```javascript
import { Zalo, ThreadType } from "zca-js";
const zalo = new Zalo();
const api = await zalo.loginQR();
api.listener.on("message", (message) => {
const isPlainText = typeof message.data.content === "string";
switch (message.type) {
case ThreadType.User: {
if (isPlainText) {
// received plain text direct message
}
break;
}
case ThreadType.Group: {
if (isPlainText) {
// received plain text group message
}
break;
}
}
});
api.listener.start();
```
> [!IMPORTANT]
> Only one web listener can run per account at a time. If you open Zalo in the browser while the listener is active, the listener will be automatically stopped.
### Send a message
```javascript
import { Zalo, ThreadType } from "zca-js";
const zalo = new Zalo();
const api = await zalo.loginQR();
// Echo bot
api.listener.on("message", (message) => {
const isPlainText = typeof message.data.content === "string";
if (message.isSelf || !isPlainText) return;
switch (message.type) {
case ThreadType.User: {
api.sendMessage(
{
msg: "echo: " + message.data.content,
quote: message.data, // the message to reply to (optional)
},
message.threadId,
message.type, // ThreadType.User
);
break;
}
case ThreadType.Group: {
api.sendMessage(
{
msg: "echo: " + message.data.content,
quote: message.data, // the message to reply to (optional)
},
message.threadId,
message.type, // ThreadType.Group
);
break;
}
}
});
api.listener.start();
```
### Get/Send a sticker
```javascript
api.getStickers("hello").then(async (stickerIds) => {
// Get the first sticker
const stickerObject = await api.getStickersDetail(stickerIds[0]);
api.sendMessageSticker(
stickerObject,
message.threadId,
message.type, // ThreadType.User or ThreadType.Group
);
});
```
---
## Example
See [examples](examples) folder for more details.
---
## Projects & Useful Resources
<div align="center">
| Repository | Description |
| :--- | :--- |
| [**ZaloDataExtractor**](https://github.com/JustKemForFun/ZaloDataExtractor) | A browser `Extension` to extract IMEI, cookies, and user agent from Zalo Web. |
| [**MultiZlogin**](https://github.com/ChickenAI/multizlogin) | A multi-account Zalo management system that lets you log in to and manage multiple accounts simultaneously, with proxy and webhook integration. |
| [**n8n-nodes-zalo-tools**](https://github.com/ChickenAI/zalo-node) | N8N node for personal Zalo account. |
| [**Zalo-F12**](https://github.com/ElectroHeavenVN/Zalo-F12) | A collection of JavaScript code snippets to paste into DevTools to change how Zalo Web/PC works. |
| [**Zalo-F12-Tools**](https://github.com/JustKemForFun/Zalo-F12-Tools) | Toggle hidden modes for Zalo Web. |
</div>
---
## Contributing
We welcome contributions from the community! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details on how to:
- 🐛 Report bugs and issues
- ✨ Suggest new features
- 🔧 Submit code contributions
- 📚 Improve documentation
- 🧪 Add or improve tests
- 🔒 Report security vulnerabilities
For more information, please read our [Code of Conduct](CODE_OF_CONDUCT.md) and [Security Policy](SECURITY.md) before participating.
---
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
---
## **Support Us**
-**Star our repositories** if you find them useful!
- 🔄 **Share** with your network to help us grow
- 💡 **Contribute** your ideas and code
-**A coffee**:
- [Buy Me a Coffee](https://ko-fi.com/grosse)
- [Paypal](https://www.paypal.com/paypalme/dungto213)
- [VietQR](https://github.com/user-attachments/assets/e1f319d6-9d11-4082-8248-55b55e645caa)
- [Momo](https://me.momo.vn/gMIMulsaUqsbf6iAiXt3)
+83
View File
@@ -0,0 +1,83 @@
# Security Policy
## Supported Versions
We actively maintain and provide security updates for the following versions:
| Version | Supported |
| ------- | ------------------ |
| 2.0.x | :white_check_mark: |
| 1.x.x | :x: |
| < 1.0 | :x: |
## Reporting a Vulnerability
We take security vulnerabilities seriously. If you discover a security vulnerability in zca-js, please follow these steps:
### 1. **DO NOT** create a public GitHub issue
Security vulnerabilities should be reported privately to prevent potential exploitation.
### 2. Report the vulnerability
Send an email to the maintainers with the following information:
- **Subject**: `[SECURITY] zca-js vulnerability report`
- **Description**: Detailed description of the vulnerability
- **Steps to reproduce**: Clear steps to reproduce the issue
- **Impact assessment**: Potential impact of the vulnerability
- **Suggested fix** (if available): Any suggestions for fixing the issue
### 3. Response timeline
- **Initial response**: Within 48 hours
- **Status update**: Within 1 week
- **Resolution**: As soon as possible, typically within 30 days
## Security Considerations
### Important Warnings
⚠️ **This is an unofficial API library** that simulates browser interactions with Zalo Web. Please be aware of the following security considerations:
1. **Account Risk**: Using this API may result in your Zalo account being locked or banned. Use at your own risk.
2. **Authentication**: The library handles sensitive authentication data. Ensure proper security measures when storing or transmitting this information.
3. **Rate Limiting**: Respect Zalo's rate limits to avoid triggering security measures.
4. **Data Privacy**: Be mindful of user privacy and comply with relevant data protection regulations.
### Best Practices
1. **Environment Variables**: Store sensitive configuration in environment variables, not in code
2. **HTTPS Only**: Always use HTTPS when transmitting data
3. **Input Validation**: Validate all inputs before processing
4. **Error Handling**: Implement proper error handling to avoid information disclosure
5. **Regular Updates**: Keep the library updated to the latest version
### Known Limitations
- This library is not officially supported by Zalo
- API endpoints and behavior may change without notice
- No guarantee of service availability or stability
- May break with Zalo Web updates
## Security Updates
Security updates will be released as patch versions (e.g., 2.0.1, 2.0.2) and will be clearly marked in the changelog.
## Contact Information
For security-related issues, please contact:
- **GitHub Issues**: Create a private issue with the `[SECURITY]` label
- **GitHub Discussions**: Use the "Security" category for general security questions
- **Team Members**:
- [@RFS-ADRENO](https://github.com/RFS-ADRENO)
- [@truong9c2208](https://github.com/truong9c2208)
- [@JustKemForFun](https://github.com/JustKemForFun)
- **Alternative**: Contact any team member through GitHub for urgent security matters
## Acknowledgments
We appreciate security researchers and community members who responsibly disclose vulnerabilities. Contributors will be acknowledged in our security advisories unless they prefer to remain anonymous.
---
**Note**: This security policy is subject to change. Please check back regularly for updates.
+546
View File
@@ -0,0 +1,546 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "zca-js",
"dependencies": {
"crypto-js": "^4.2.0",
"form-data": "^4.0.4",
"json-bigint": "^1.0.0",
"pako": "^2.1.0",
"semver": "^7.6.3",
"spark-md5": "^3.0.2",
"tough-cookie": "^5.0.0",
"ws": "^8.18.0",
},
"devDependencies": {
"@eslint/js": "^9.34.0",
"@rollup/plugin-typescript": "^12.1.0",
"@types/bun": "^1.1.14",
"@types/crypto-js": "^4.2.2",
"@types/json-bigint": "^1.0.4",
"@types/node": "^20.14.10",
"@types/pako": "^2.0.3",
"@types/semver": "^7.5.8",
"@types/spark-md5": "^3.0.4",
"@types/ws": "^8.5.11",
"eslint": "^9.34.0",
"globals": "^16.3.0",
"husky": "^9.1.7",
"lint-staged": "^16.1.5",
"prettier": "^3.3.3",
"rimraf": "^5.0.10",
"rollup": "^4.24.0",
"typescript": "^5.5.3",
"typescript-eslint": "^8.41.0",
},
},
},
"packages": {
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
"@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.3.1", "", {}, "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA=="],
"@eslint/core": ["@eslint/core@0.15.2", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
"@eslint/js": ["@eslint/js@9.34.0", "", {}, "sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.5", "", { "dependencies": { "@eslint/core": "^0.15.2", "levn": "^0.4.1" } }, "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
"@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="],
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
"@rollup/plugin-typescript": ["@rollup/plugin-typescript@12.1.0", "", { "dependencies": { "@rollup/pluginutils": "^5.1.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.14.0||^3.0.0||^4.0.0", "tslib": "*", "typescript": ">=3.7.0" } }, "sha512-Kzs8KGJofe7cfTRODsnG1jNGxSvU8gVoNNd7Z/QaY25AYwe2LSSUpx/kPxqF38NYkpR8de3m51r9uwJpDlz6dg=="],
"@rollup/pluginutils": ["@rollup/pluginutils@5.1.2", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^2.3.1" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" } }, "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.24.0", "", { "os": "android", "cpu": "arm" }, "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.24.0", "", { "os": "android", "cpu": "arm64" }, "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.24.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.24.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.24.0", "", { "os": "linux", "cpu": "arm" }, "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.24.0", "", { "os": "linux", "cpu": "arm" }, "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.24.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.24.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw=="],
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.24.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.24.0", "", { "os": "linux", "cpu": "none" }, "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.24.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.24.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.24.0", "", { "os": "linux", "cpu": "x64" }, "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.24.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.24.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.24.0", "", { "os": "win32", "cpu": "x64" }, "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw=="],
"@types/bun": ["@types/bun@1.1.14", "", { "dependencies": { "bun-types": "1.1.37" } }, "sha512-opVYiFGtO2af0dnWBdZWlioLBoxSdDO5qokaazLhq8XQtGZbY4pY3/JxY8Zdf/hEwGubbp7ErZXoN1+h2yesxA=="],
"@types/crypto-js": ["@types/crypto-js@4.2.2", "", {}, "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ=="],
"@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
"@types/json-bigint": ["@types/json-bigint@1.0.4", "", {}, "sha512-ydHooXLbOmxBbubnA7Eh+RpBzuaIiQjh8WGJYQB50JFGFrdxW7JzVlyEV7fAXw0T2sqJ1ysTneJbiyNLqZRAag=="],
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
"@types/node": ["@types/node@20.14.10", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ=="],
"@types/pako": ["@types/pako@2.0.3", "", {}, "sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q=="],
"@types/semver": ["@types/semver@7.5.8", "", {}, "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ=="],
"@types/spark-md5": ["@types/spark-md5@3.0.4", "", {}, "sha512-qtOaDz+IXiNndPgYb6t1YoutnGvFRtWSNzpVjkAPCfB2UzTyybuD4Tjgs7VgRawum3JnJNRwNQd4N//SvrHg1Q=="],
"@types/ws": ["@types/ws@8.5.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.41.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.41.0", "@typescript-eslint/type-utils": "8.41.0", "@typescript-eslint/utils": "8.41.0", "@typescript-eslint/visitor-keys": "8.41.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.41.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-8fz6oa6wEKZrhXWro/S3n2eRJqlRcIa6SlDh59FXJ5Wp5XRZ8B9ixpJDcjadHq47hMx0u+HW6SNa6LjJQ6NLtw=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.41.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.41.0", "@typescript-eslint/types": "8.41.0", "@typescript-eslint/typescript-estree": "8.41.0", "@typescript-eslint/visitor-keys": "8.41.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-gTtSdWX9xiMPA/7MV9STjJOOYtWwIJIYxkQxnSV1U3xcE+mnJSH3f6zI0RYP+ew66WSlZ5ed+h0VCxsvdC1jJg=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.41.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.41.0", "@typescript-eslint/types": "^8.41.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-b8V9SdGBQzQdjJ/IO3eDifGpDBJfvrNTp2QD9P2BeqWTGrRibgfgIlBSw6z3b6R7dPzg752tOs4u/7yCLxksSQ=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.41.0", "", { "dependencies": { "@typescript-eslint/types": "8.41.0", "@typescript-eslint/visitor-keys": "8.41.0" } }, "sha512-n6m05bXn/Cd6DZDGyrpXrELCPVaTnLdPToyhBoFkLIMznRUQUEQdSp96s/pcWSQdqOhrgR1mzJ+yItK7T+WPMQ=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.41.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-TDhxYFPUYRFxFhuU5hTIJk+auzM/wKvWgoNYOPcOf6i4ReYlOoYN8q1dV5kOTjNQNJgzWN3TUUQMtlLOcUgdUw=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.41.0", "", { "dependencies": { "@typescript-eslint/types": "8.41.0", "@typescript-eslint/typescript-estree": "8.41.0", "@typescript-eslint/utils": "8.41.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-63qt1h91vg3KsjVVonFJWjgSK7pZHSQFKH6uwqxAH9bBrsyRhO6ONoKyXxyVBzG1lJnFAJcKAcxLS54N1ee1OQ=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.41.0", "", {}, "sha512-9EwxsWdVqh42afLbHP90n2VdHaWU/oWgbH2P0CfcNfdKL7CuKpwMQGjwev56vWu9cSKU7FWSu6r9zck6CVfnag=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.41.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.41.0", "@typescript-eslint/tsconfig-utils": "8.41.0", "@typescript-eslint/types": "8.41.0", "@typescript-eslint/visitor-keys": "8.41.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-D43UwUYJmGhuwHfY7MtNKRZMmfd8+p/eNSfFe6tH5mbVDto+VQCayeAt35rOx3Cs6wxD16DQtIKw/YXxt5E0UQ=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.41.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.41.0", "@typescript-eslint/types": "8.41.0", "@typescript-eslint/typescript-estree": "8.41.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-udbCVstxZ5jiPIXrdH+BZWnPatjlYwJuJkDA4Tbo3WyYLh8NvB+h/bKeSZHDOFKfphsZYJQqaFtLeXEqurQn1A=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.41.0", "", { "dependencies": { "@typescript-eslint/types": "8.41.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-+GeGMebMCy0elMNg67LRNoVnUFPIm37iu5CmHESVx56/9Jsfdpsvbv605DQ81Pi/x11IdKUsS5nzgTYbCQU9fg=="],
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
"ansi-escapes": ["ansi-escapes@7.0.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw=="],
"ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
"bun-types": ["bun-types@1.1.37", "", { "dependencies": { "@types/node": "~20.12.8", "@types/ws": "~8.5.10" } }, "sha512-C65lv6eBr3LPJWFZ2gswyrGZ82ljnH8flVE03xeXxKhi2ZGtFiO4isRKTKnitbSqtRAcaqYSR6djt1whI66AbA=="],
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
"cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="],
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
"commander": ["commander@14.0.0", "", {}, "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"crypto-js": ["crypto-js@4.2.0", "", {}, "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="],
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
"emoji-regex": ["emoji-regex@10.5.0", "", {}, "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg=="],
"environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="],
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@9.34.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.34.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg=="],
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
"eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
"esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
"estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
"eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
"foreground-child": ["foreground-child@3.3.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" } }, "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg=="],
"form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
"get-east-asian-width": ["get-east-asian-width@1.3.0", "", {}, "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ=="],
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
"glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
"globals": ["globals@16.3.0", "", {}, "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ=="],
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
"has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="],
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
"is-core-module": ["is-core-module@2.15.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
"is-fullwidth-code-point": ["is-fullwidth-code-point@4.0.0", "", {}, "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ=="],
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
"json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="],
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
"lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
"lint-staged": ["lint-staged@16.1.5", "", { "dependencies": { "chalk": "^5.5.0", "commander": "^14.0.0", "debug": "^4.4.1", "lilconfig": "^3.1.3", "listr2": "^9.0.1", "micromatch": "^4.0.8", "nano-spawn": "^1.0.2", "pidtree": "^0.6.0", "string-argv": "^0.3.2", "yaml": "^2.8.1" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-uAeQQwByI6dfV7wpt/gVqg+jAPaSp8WwOA8kKC/dv1qw14oGpnpAisY65ibGHUGDUv0rYaZ8CAJZ/1U8hUvC2A=="],
"listr2": ["listr2@9.0.2", "", { "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-VVd7cS6W+vLJu2wmq4QmfVj14Iep7cz4r/OWNk36Aq5ZOY7G8/BfCrQFexcwB1OIxB3yERiePfE/REBjEFulag=="],
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
"log-update": ["log-update@6.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="],
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nano-spawn": ["nano-spawn@1.0.2", "", {}, "sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg=="],
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
"onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
"pako": ["pako@2.1.0", "", {}, "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="],
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
"path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"pidtree": ["pidtree@0.6.0", "", { "bin": { "pidtree": "bin/pidtree.js" } }, "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g=="],
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
"prettier": ["prettier@3.3.3", "", { "bin": "bin/prettier.cjs" }, "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
"restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
"rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="],
"rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": "dist/esm/bin.mjs" }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="],
"rollup": ["rollup@4.24.0", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.24.0", "@rollup/rollup-android-arm64": "4.24.0", "@rollup/rollup-darwin-arm64": "4.24.0", "@rollup/rollup-darwin-x64": "4.24.0", "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", "@rollup/rollup-linux-arm-musleabihf": "4.24.0", "@rollup/rollup-linux-arm64-gnu": "4.24.0", "@rollup/rollup-linux-arm64-musl": "4.24.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", "@rollup/rollup-linux-riscv64-gnu": "4.24.0", "@rollup/rollup-linux-s390x-gnu": "4.24.0", "@rollup/rollup-linux-x64-gnu": "4.24.0", "@rollup/rollup-linux-x64-musl": "4.24.0", "@rollup/rollup-win32-arm64-msvc": "4.24.0", "@rollup/rollup-win32-ia32-msvc": "4.24.0", "@rollup/rollup-win32-x64-msvc": "4.24.0", "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg=="],
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"semver": ["semver@7.6.3", "", { "bin": "bin/semver.js" }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
"slice-ansi": ["slice-ansi@5.0.0", "", { "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" } }, "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ=="],
"spark-md5": ["spark-md5@3.0.2", "", {}, "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw=="],
"string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="],
"string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
"strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
"tldts": ["tldts@6.1.64", "", { "dependencies": { "tldts-core": "^6.1.64" }, "bin": "bin/cli.js" }, "sha512-ph4AE5BXWIOsSy9stpoeo7bYe/Cy7VfpciIH4RhVZUPItCJmhqWCN0EVzxd8BOHiyNb42vuJc6NWTjJkg91Tuw=="],
"tldts-core": ["tldts-core@6.1.64", "", {}, "sha512-uqnl8vGV16KsyflHOzqrYjjArjfXaU6rMPXYy2/ZWoRKCkXtghgB4VwTDXUG+t0OTGeSewNAG31/x1gCTfLt+Q=="],
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
"tough-cookie": ["tough-cookie@5.0.0", "", { "dependencies": { "tldts": "^6.1.32" } }, "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q=="],
"ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
"tslib": ["tslib@2.6.3", "", {}, "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="],
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
"typescript": ["typescript@5.5.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ=="],
"typescript-eslint": ["typescript-eslint@8.41.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.41.0", "@typescript-eslint/parser": "8.41.0", "@typescript-eslint/typescript-estree": "8.41.0", "@typescript-eslint/utils": "8.41.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-n66rzs5OBXW3SFSnZHr2T685q1i4ODm2nulFJhMZBotaTavsS8TrI3d7bDlRSs9yWo7HmyWrN9qDu14Qv7Y0Dw=="],
"undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
"wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="],
"wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
"yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="],
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
"@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
"@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"bun-types/@types/node": ["@types/node@20.12.14", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg=="],
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"lint-staged/chalk": ["chalk@5.6.0", "", {}, "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ=="],
"log-update/slice-ansi": ["slice-ansi@7.1.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg=="],
"slice-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
"string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"string-width-cjs/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
"@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"log-update/slice-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
"log-update/slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.0.0", "", { "dependencies": { "get-east-asian-width": "^1.0.0" } }, "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA=="],
"string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"wrap-ansi-cjs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
"wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
}
}
+21
View File
@@ -0,0 +1,21 @@
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig, globalIgnores } from "eslint/config";
export default defineConfig([
{
files: ["**/*.{js,ts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.node },
},
tseslint.configs.recommended,
{
rules: {
"@typescript-eslint/consistent-type-imports": "error",
"no-extra-boolean-cast": "off",
},
},
globalIgnores(["dist/*"]),
]);
+56
View File
@@ -0,0 +1,56 @@
import fs from "node:fs";
import type { API, Credentials} from "../src/index.js";
import { ThreadType, Zalo } from "../src/index.js";
const zalo = new Zalo();
const credentials: Partial<Credentials> = {
cookie: JSON.parse(fs.readFileSync("./examples/cookies.json", "utf-8")),
imei: "",
userAgent: "", // Same userAgent is recommended
};
const isValid = (credentials: Partial<Credentials>): credentials is Credentials => {
return !!credentials.cookie && !!credentials.imei && !!credentials.userAgent;
};
let api: API | undefined;
if (isValid(credentials)) {
api = await zalo.login(credentials);
} else {
api = await zalo.loginQR({ qrPath: "./qr.png", userAgent: "" }, () => {
console.log("QR Code has been generated");
});
const context = api.getContext();
// Save credentials for later use
credentials.imei = context.imei;
credentials.userAgent = context.userAgent;
credentials.cookie = context.cookie.toJSON()?.cookies;
}
const { listener } = api;
listener.on("message", (message) => {
const isDirectMessage = message.type === ThreadType.User;
if (isDirectMessage && !message.isSelf && typeof message.data.content === "string") {
console.log("Message:", message.data.content, message.threadId);
api.sendMessage(message.data.content, message.threadId, message.type);
}
});
listener.onConnected(() => {
console.log("Connected");
});
listener.onClosed(() => {
console.log("Closed");
});
listener.onError((error) => {
console.error("Error:", error);
});
listener.start();
+40
View File
@@ -0,0 +1,40 @@
import type { Credentials } from "../src";
import { Zalo } from "../src";
import fs from "node:fs";
const zalo = new Zalo();
const credentialsPath = "./examples/credentials.json";
function validateCredentials(credentials: Partial<Credentials>): credentials is Credentials {
return !!credentials.cookie && !!credentials.imei && !!credentials.userAgent;
}
function getCredentials() {
if (!fs.existsSync(credentialsPath)) {
return null;
}
const raw = fs.readFileSync(credentialsPath, "utf-8") || "{}";
const credentials = JSON.parse(raw);
return validateCredentials(credentials) ? credentials : null;
}
const credentials = getCredentials();
const isValidCredentials = credentials !== null;
const api = isValidCredentials ? await zalo.login(credentials) : await zalo.loginQR();
if (!isValidCredentials) {
const apiContext = api.getContext();
const credentials: Credentials = {
cookie: apiContext.cookie.toJSON()?.cookies || [],
imei: apiContext.imei,
userAgent: apiContext.userAgent,
};
fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), "utf-8");
}
const myProfile = await api.fetchAccountInfo();
console.log("My profile:", myProfile);
+2
View File
@@ -0,0 +1,2 @@
export * from "./dist";
export as namespace Zalo;
+3505
View File
File diff suppressed because it is too large Load Diff
+78
View File
@@ -0,0 +1,78 @@
{
"name": "zca-js",
"version": "2.1.2",
"description": "Unofficial Zalo API for JavaScript",
"main": "dist/index.js",
"type": "module",
"exports": {
".": {
"require": "./dist/cjs/index.cjs",
"types": "./index.d.ts",
"default": "./dist/index.js"
}
},
"scripts": {
"prebuild": "bun run scripts/buildAPI.js",
"build:clean": "rimraf dist",
"build:esm": "tsc",
"build:cjs": "rollup -c rollup.config.js",
"build": "bun run build:clean && bun run build:esm && bun run build:cjs",
"test:feat": "bun run test/feat.ts",
"prettier": "prettier --write .",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"prepare": "husky"
},
"repository": {
"type": "git",
"url": "git+https://github.com/RFS-ADRENO/zca-js.git"
},
"homepage": "https://github.com/RFS-ADRENO/zca-js",
"bugs": {
"url": "https://github.com/RFS-ADRENO/zca-js/issues"
},
"engines": {
"node": ">=18.0.0"
},
"keywords": [
"chatbot",
"zalo",
"api"
],
"author": "RFS-ADRENO, truong9c2208, JustKemForFun",
"license": "MIT",
"dependencies": {
"crypto-js": "^4.2.0",
"form-data": "^4.0.4",
"json-bigint": "^1.0.0",
"pako": "^2.1.0",
"semver": "^7.6.3",
"spark-md5": "^3.0.2",
"tough-cookie": "^5.0.0",
"ws": "^8.18.0"
},
"devDependencies": {
"@eslint/js": "^9.34.0",
"@rollup/plugin-typescript": "^12.1.0",
"@types/bun": "^1.1.14",
"@types/crypto-js": "^4.2.2",
"@types/json-bigint": "^1.0.4",
"@types/node": "^20.14.10",
"@types/pako": "^2.0.3",
"@types/semver": "^7.5.8",
"@types/spark-md5": "^3.0.4",
"@types/ws": "^8.5.11",
"eslint": "^9.34.0",
"globals": "^16.3.0",
"husky": "^9.1.7",
"lint-staged": "^16.1.5",
"prettier": "^3.3.3",
"rimraf": "^5.0.10",
"rollup": "^4.24.0",
"typescript": "^5.5.3",
"typescript-eslint": "^8.41.0"
},
"lint-staged": {
"*.{js,ts}": "bunx eslint"
}
}
+28
View File
@@ -0,0 +1,28 @@
// rollup.config.js
export default {
input: "dist/index.js",
output: {
dir: "dist/cjs",
entryFileNames: "[name].cjs",
format: "cjs",
preserveModules: true,
},
external: [
"crypto-js",
"events",
"form-data",
"fs",
"node:crypto",
"node:fs",
"node:fs/promises",
"node:path",
"pako",
"semver",
"sharp",
"spark-md5",
"tough-cookie",
"ws",
"json-bigint"
],
};
+72
View File
@@ -0,0 +1,72 @@
import fs from "fs";
import path from "path";
const apisDir = path.join(process.cwd(), "src", "apis");
const outputFile = path.join(process.cwd(), "src", "apis.ts");
function getAllApiFiles(dir) {
const ignoreFiles = ["listen.ts", "login.ts", "loginQR.ts", "custom.ts"];
return fs
.readdirSync(dir)
.filter((file) => file.endsWith(".ts") && !ignoreFiles.includes(file))
.map((file) => {
const nonExtension = file.slice(0, -3); // Remove .ts extension
return {
name: nonExtension,
factoryName: `${nonExtension}Factory`,
};
});
}
function generateAPIsFile() {
const allApiFiles = getAllApiFiles(apisDir);
const importLines = allApiFiles.map((file) => {
return `import { ${file.factoryName} } from "./apis/${file.name}.js";`;
});
const propertyLines = allApiFiles.map((file) => {
return ` public ${file.name}: ReturnType<typeof ${file.factoryName}>;`;
});
const constructorLines = allApiFiles.map((file) => {
return ` this.${file.name} = ${file.factoryName}(ctx, this);`;
});
const emptyNewLine = "\n";
const content =
"" +
'import { Listener } from "./apis/listen.js";\n' +
emptyNewLine +
importLines.join("\n") +
emptyNewLine +
'import { customFactory } from "./apis/custom.js";\n' +
'import type { ZPWServiceMap, ContextSession } from "./context.js";\n' +
emptyNewLine +
"export class API {\n" +
" public zpwServiceMap: ZPWServiceMap;\n" +
" public listener: Listener;\n" +
emptyNewLine +
propertyLines.join("\n") +
emptyNewLine +
emptyNewLine +
" public custom: ReturnType<typeof customFactory>;\n" +
emptyNewLine +
" constructor(ctx: ContextSession, zpwServiceMap: ZPWServiceMap, wsUrls: string[]) {\n" +
" this.zpwServiceMap = zpwServiceMap;\n" +
" this.listener = new Listener(ctx, wsUrls);\n" +
emptyNewLine +
constructorLines.join("\n") +
emptyNewLine +
emptyNewLine +
" this.custom = customFactory(ctx, this);\n" +
" }\n" +
"}\n";
fs.writeFileSync(outputFile, content, "utf-8");
console.log(`\nAPIs file generated at ${outputFile}\n`);
}
generateAPIsFile();
+10
View File
@@ -0,0 +1,10 @@
export class ZaloApiError extends Error {
public code: number | null;
constructor(message: string, code?: number) {
super(message);
this.name = "ZcaApiError";
this.code = code || null;
}
}
@@ -0,0 +1,8 @@
import { ZaloApiError } from "./ZaloApiError.js";
export class ZaloApiLoginQRAborted extends ZaloApiError {
constructor(message: string = "Operation aborted") {
super(message);
this.name = "ZaloApiLoginQRAborted";
}
}
@@ -0,0 +1,8 @@
import { ZaloApiError } from "./ZaloApiError.js";
export class ZaloApiLoginQRDeclined extends ZaloApiError {
constructor(message: string = "Login QR request declined") {
super(message);
this.name = "ZaloApiLoginQRDeclined";
}
}
@@ -0,0 +1,8 @@
import { ZaloApiError } from "./ZaloApiError.js";
export class ZaloApiMissingImageMetadataGetter extends ZaloApiError {
constructor() {
super("Missing `imageMetadataGetter`. Please provide it in the Zalo object options.");
this.name = "ZaloApiMissingImageMetadataGetter";
}
}
+4
View File
@@ -0,0 +1,4 @@
export * from "./ZaloApiError.js";
export * from "./ZaloApiMissingImageMetadataGetter.js";
export * from "./ZaloApiLoginQRAborted.js";
export * from "./ZaloApiLoginQRDeclined.js";
+455
View File
@@ -0,0 +1,455 @@
import { Listener } from "./apis/listen.js";
import { acceptFriendRequestFactory } from "./apis/acceptFriendRequest.js";
import { addGroupBlockedMemberFactory } from "./apis/addGroupBlockedMember.js";
import { addGroupDeputyFactory } from "./apis/addGroupDeputy.js";
import { addPollOptionsFactory } from "./apis/addPollOptions.js";
import { addQuickMessageFactory } from "./apis/addQuickMessage.js";
import { addReactionFactory } from "./apis/addReaction.js";
import { addUnreadMarkFactory } from "./apis/addUnreadMark.js";
import { addUserToGroupFactory } from "./apis/addUserToGroup.js";
import { blockUserFactory } from "./apis/blockUser.js";
import { blockViewFeedFactory } from "./apis/blockViewFeed.js";
import { changeAccountAvatarFactory } from "./apis/changeAccountAvatar.js";
import { changeFriendAliasFactory } from "./apis/changeFriendAlias.js";
import { changeGroupAvatarFactory } from "./apis/changeGroupAvatar.js";
import { changeGroupNameFactory } from "./apis/changeGroupName.js";
import { changeGroupOwnerFactory } from "./apis/changeGroupOwner.js";
import { createAutoReplyFactory } from "./apis/createAutoReply.js";
import { createCatalogFactory } from "./apis/createCatalog.js";
import { createGroupFactory } from "./apis/createGroup.js";
import { createNoteFactory } from "./apis/createNote.js";
import { createPollFactory } from "./apis/createPoll.js";
import { createProductCatalogFactory } from "./apis/createProductCatalog.js";
import { createReminderFactory } from "./apis/createReminder.js";
import { deleteAutoReplyFactory } from "./apis/deleteAutoReply.js";
import { deleteAvatarFactory } from "./apis/deleteAvatar.js";
import { deleteCatalogFactory } from "./apis/deleteCatalog.js";
import { deleteChatFactory } from "./apis/deleteChat.js";
import { deleteGroupInviteBoxFactory } from "./apis/deleteGroupInviteBox.js";
import { deleteMessageFactory } from "./apis/deleteMessage.js";
import { deleteProductCatalogFactory } from "./apis/deleteProductCatalog.js";
import { disableGroupLinkFactory } from "./apis/disableGroupLink.js";
import { disperseGroupFactory } from "./apis/disperseGroup.js";
import { editNoteFactory } from "./apis/editNote.js";
import { editReminderFactory } from "./apis/editReminder.js";
import { enableGroupLinkFactory } from "./apis/enableGroupLink.js";
import { fetchAccountInfoFactory } from "./apis/fetchAccountInfo.js";
import { findUserFactory } from "./apis/findUser.js";
import { findUserByUsernameFactory } from "./apis/findUserByUsername.js";
import { forwardMessageFactory } from "./apis/forwardMessage.js";
import { getAliasListFactory } from "./apis/getAliasList.js";
import { getAllFriendsFactory } from "./apis/getAllFriends.js";
import { getAllGroupsFactory } from "./apis/getAllGroups.js";
import { getArchivedChatListFactory } from "./apis/getArchivedChatList.js";
import { getAutoDeleteChatFactory } from "./apis/getAutoDeleteChat.js";
import { getAutoReplyListFactory } from "./apis/getAutoReplyList.js";
import { getAvatarListFactory } from "./apis/getAvatarList.js";
import { getAvatarUrlProfileFactory } from "./apis/getAvatarUrlProfile.js";
import { getBizAccountFactory } from "./apis/getBizAccount.js";
import { getCatalogListFactory } from "./apis/getCatalogList.js";
import { getCloseFriendsFactory } from "./apis/getCloseFriends.js";
import { getContextFactory } from "./apis/getContext.js";
import { getCookieFactory } from "./apis/getCookie.js";
import { getFriendBoardListFactory } from "./apis/getFriendBoardList.js";
import { getFriendOnlinesFactory } from "./apis/getFriendOnlines.js";
import { getFriendRecommendationsFactory } from "./apis/getFriendRecommendations.js";
import { getFriendRequestStatusFactory } from "./apis/getFriendRequestStatus.js";
import { getFullAvatarFactory } from "./apis/getFullAvatar.js";
import { getGroupBlockedMemberFactory } from "./apis/getGroupBlockedMember.js";
import { getGroupChatHistoryFactory } from "./apis/getGroupChatHistory.js";
import { getGroupInfoFactory } from "./apis/getGroupInfo.js";
import { getGroupInviteBoxInfoFactory } from "./apis/getGroupInviteBoxInfo.js";
import { getGroupInviteBoxListFactory } from "./apis/getGroupInviteBoxList.js";
import { getGroupLinkDetailFactory } from "./apis/getGroupLinkDetail.js";
import { getGroupLinkInfoFactory } from "./apis/getGroupLinkInfo.js";
import { getGroupMembersInfoFactory } from "./apis/getGroupMembersInfo.js";
import { getHiddenConversationsFactory } from "./apis/getHiddenConversations.js";
import { getLabelsFactory } from "./apis/getLabels.js";
import { getListBoardFactory } from "./apis/getListBoard.js";
import { getListReminderFactory } from "./apis/getListReminder.js";
import { getMultiUsersByPhonesFactory } from "./apis/getMultiUsersByPhones.js";
import { getMuteFactory } from "./apis/getMute.js";
import { getOwnIdFactory } from "./apis/getOwnId.js";
import { getPendingGroupMembersFactory } from "./apis/getPendingGroupMembers.js";
import { getPinConversationsFactory } from "./apis/getPinConversations.js";
import { getPollDetailFactory } from "./apis/getPollDetail.js";
import { getProductCatalogListFactory } from "./apis/getProductCatalogList.js";
import { getQRFactory } from "./apis/getQR.js";
import { getQuickMessageListFactory } from "./apis/getQuickMessageList.js";
import { getRelatedFriendGroupFactory } from "./apis/getRelatedFriendGroup.js";
import { getReminderFactory } from "./apis/getReminder.js";
import { getReminderResponsesFactory } from "./apis/getReminderResponses.js";
import { getSentFriendRequestFactory } from "./apis/getSentFriendRequest.js";
import { getSettingsFactory } from "./apis/getSettings.js";
import { getStickerCategoryDetailFactory } from "./apis/getStickerCategoryDetail.js";
import { getStickersFactory } from "./apis/getStickers.js";
import { getStickersDetailFactory } from "./apis/getStickersDetail.js";
import { getUnreadMarkFactory } from "./apis/getUnreadMark.js";
import { getUserInfoFactory } from "./apis/getUserInfo.js";
import { inviteUserToGroupsFactory } from "./apis/inviteUserToGroups.js";
import { joinGroupInviteBoxFactory } from "./apis/joinGroupInviteBox.js";
import { joinGroupLinkFactory } from "./apis/joinGroupLink.js";
import { keepAliveFactory } from "./apis/keepAlive.js";
import { lastOnlineFactory } from "./apis/lastOnline.js";
import { leaveGroupFactory } from "./apis/leaveGroup.js";
import { lockPollFactory } from "./apis/lockPoll.js";
import { parseLinkFactory } from "./apis/parseLink.js";
import { rejectFriendRequestFactory } from "./apis/rejectFriendRequest.js";
import { removeFriendFactory } from "./apis/removeFriend.js";
import { removeFriendAliasFactory } from "./apis/removeFriendAlias.js";
import { removeGroupBlockedMemberFactory } from "./apis/removeGroupBlockedMember.js";
import { removeGroupDeputyFactory } from "./apis/removeGroupDeputy.js";
import { removeQuickMessageFactory } from "./apis/removeQuickMessage.js";
import { removeReminderFactory } from "./apis/removeReminder.js";
import { removeUnreadMarkFactory } from "./apis/removeUnreadMark.js";
import { removeUserFromGroupFactory } from "./apis/removeUserFromGroup.js";
import { resetHiddenConversPinFactory } from "./apis/resetHiddenConversPin.js";
import { reuseAvatarFactory } from "./apis/reuseAvatar.js";
import { reviewPendingMemberRequestFactory } from "./apis/reviewPendingMemberRequest.js";
import { searchStickerFactory } from "./apis/searchSticker.js";
import { sendBankCardFactory } from "./apis/sendBankCard.js";
import { sendCardFactory } from "./apis/sendCard.js";
import { sendDeliveredEventFactory } from "./apis/sendDeliveredEvent.js";
import { sendFriendRequestFactory } from "./apis/sendFriendRequest.js";
import { sendLinkFactory } from "./apis/sendLink.js";
import { sendMessageFactory } from "./apis/sendMessage.js";
import { sendReportFactory } from "./apis/sendReport.js";
import { sendSeenEventFactory } from "./apis/sendSeenEvent.js";
import { sendStickerFactory } from "./apis/sendSticker.js";
import { sendTypingEventFactory } from "./apis/sendTypingEvent.js";
import { sendVideoFactory } from "./apis/sendVideo.js";
import { sendVoiceFactory } from "./apis/sendVoice.js";
import { setHiddenConversationsFactory } from "./apis/setHiddenConversations.js";
import { setMuteFactory } from "./apis/setMute.js";
import { setPinnedConversationsFactory } from "./apis/setPinnedConversations.js";
import { sharePollFactory } from "./apis/sharePoll.js";
import { unblockUserFactory } from "./apis/unblockUser.js";
import { undoFactory } from "./apis/undo.js";
import { undoFriendRequestFactory } from "./apis/undoFriendRequest.js";
import { updateActiveStatusFactory } from "./apis/updateActiveStatus.js";
import { updateArchivedChatListFactory } from "./apis/updateArchivedChatList.js";
import { updateAutoDeleteChatFactory } from "./apis/updateAutoDeleteChat.js";
import { updateAutoReplyFactory } from "./apis/updateAutoReply.js";
import { updateCatalogFactory } from "./apis/updateCatalog.js";
import { updateGroupSettingsFactory } from "./apis/updateGroupSettings.js";
import { updateHiddenConversPinFactory } from "./apis/updateHiddenConversPin.js";
import { updateLabelsFactory } from "./apis/updateLabels.js";
import { updateLangFactory } from "./apis/updateLang.js";
import { updateProductCatalogFactory } from "./apis/updateProductCatalog.js";
import { updateProfileFactory } from "./apis/updateProfile.js";
import { updateProfileBioFactory } from "./apis/updateProfileBio.js";
import { updateQuickMessageFactory } from "./apis/updateQuickMessage.js";
import { updateSettingsFactory } from "./apis/updateSettings.js";
import { upgradeGroupToCommunityFactory } from "./apis/upgradeGroupToCommunity.js";
import { uploadAttachmentFactory } from "./apis/uploadAttachment.js";
import { uploadProductPhotoFactory } from "./apis/uploadProductPhoto.js";
import { votePollFactory } from "./apis/votePoll.js";
import { customFactory } from "./apis/custom.js";
import type { ZPWServiceMap, ContextSession } from "./context.js";
export class API {
public zpwServiceMap: ZPWServiceMap;
public listener: Listener;
public acceptFriendRequest: ReturnType<typeof acceptFriendRequestFactory>;
public addGroupBlockedMember: ReturnType<typeof addGroupBlockedMemberFactory>;
public addGroupDeputy: ReturnType<typeof addGroupDeputyFactory>;
public addPollOptions: ReturnType<typeof addPollOptionsFactory>;
public addQuickMessage: ReturnType<typeof addQuickMessageFactory>;
public addReaction: ReturnType<typeof addReactionFactory>;
public addUnreadMark: ReturnType<typeof addUnreadMarkFactory>;
public addUserToGroup: ReturnType<typeof addUserToGroupFactory>;
public blockUser: ReturnType<typeof blockUserFactory>;
public blockViewFeed: ReturnType<typeof blockViewFeedFactory>;
public changeAccountAvatar: ReturnType<typeof changeAccountAvatarFactory>;
public changeFriendAlias: ReturnType<typeof changeFriendAliasFactory>;
public changeGroupAvatar: ReturnType<typeof changeGroupAvatarFactory>;
public changeGroupName: ReturnType<typeof changeGroupNameFactory>;
public changeGroupOwner: ReturnType<typeof changeGroupOwnerFactory>;
public createAutoReply: ReturnType<typeof createAutoReplyFactory>;
public createCatalog: ReturnType<typeof createCatalogFactory>;
public createGroup: ReturnType<typeof createGroupFactory>;
public createNote: ReturnType<typeof createNoteFactory>;
public createPoll: ReturnType<typeof createPollFactory>;
public createProductCatalog: ReturnType<typeof createProductCatalogFactory>;
public createReminder: ReturnType<typeof createReminderFactory>;
public deleteAutoReply: ReturnType<typeof deleteAutoReplyFactory>;
public deleteAvatar: ReturnType<typeof deleteAvatarFactory>;
public deleteCatalog: ReturnType<typeof deleteCatalogFactory>;
public deleteChat: ReturnType<typeof deleteChatFactory>;
public deleteGroupInviteBox: ReturnType<typeof deleteGroupInviteBoxFactory>;
public deleteMessage: ReturnType<typeof deleteMessageFactory>;
public deleteProductCatalog: ReturnType<typeof deleteProductCatalogFactory>;
public disableGroupLink: ReturnType<typeof disableGroupLinkFactory>;
public disperseGroup: ReturnType<typeof disperseGroupFactory>;
public editNote: ReturnType<typeof editNoteFactory>;
public editReminder: ReturnType<typeof editReminderFactory>;
public enableGroupLink: ReturnType<typeof enableGroupLinkFactory>;
public fetchAccountInfo: ReturnType<typeof fetchAccountInfoFactory>;
public findUser: ReturnType<typeof findUserFactory>;
public findUserByUsername: ReturnType<typeof findUserByUsernameFactory>;
public forwardMessage: ReturnType<typeof forwardMessageFactory>;
public getAliasList: ReturnType<typeof getAliasListFactory>;
public getAllFriends: ReturnType<typeof getAllFriendsFactory>;
public getAllGroups: ReturnType<typeof getAllGroupsFactory>;
public getArchivedChatList: ReturnType<typeof getArchivedChatListFactory>;
public getAutoDeleteChat: ReturnType<typeof getAutoDeleteChatFactory>;
public getAutoReplyList: ReturnType<typeof getAutoReplyListFactory>;
public getAvatarList: ReturnType<typeof getAvatarListFactory>;
public getAvatarUrlProfile: ReturnType<typeof getAvatarUrlProfileFactory>;
public getBizAccount: ReturnType<typeof getBizAccountFactory>;
public getCatalogList: ReturnType<typeof getCatalogListFactory>;
public getCloseFriends: ReturnType<typeof getCloseFriendsFactory>;
public getContext: ReturnType<typeof getContextFactory>;
public getCookie: ReturnType<typeof getCookieFactory>;
public getFriendBoardList: ReturnType<typeof getFriendBoardListFactory>;
public getFriendOnlines: ReturnType<typeof getFriendOnlinesFactory>;
public getFriendRecommendations: ReturnType<typeof getFriendRecommendationsFactory>;
public getFriendRequestStatus: ReturnType<typeof getFriendRequestStatusFactory>;
public getFullAvatar: ReturnType<typeof getFullAvatarFactory>;
public getGroupBlockedMember: ReturnType<typeof getGroupBlockedMemberFactory>;
public getGroupChatHistory: ReturnType<typeof getGroupChatHistoryFactory>;
public getGroupInfo: ReturnType<typeof getGroupInfoFactory>;
public getGroupInviteBoxInfo: ReturnType<typeof getGroupInviteBoxInfoFactory>;
public getGroupInviteBoxList: ReturnType<typeof getGroupInviteBoxListFactory>;
public getGroupLinkDetail: ReturnType<typeof getGroupLinkDetailFactory>;
public getGroupLinkInfo: ReturnType<typeof getGroupLinkInfoFactory>;
public getGroupMembersInfo: ReturnType<typeof getGroupMembersInfoFactory>;
public getHiddenConversations: ReturnType<typeof getHiddenConversationsFactory>;
public getLabels: ReturnType<typeof getLabelsFactory>;
public getListBoard: ReturnType<typeof getListBoardFactory>;
public getListReminder: ReturnType<typeof getListReminderFactory>;
public getMultiUsersByPhones: ReturnType<typeof getMultiUsersByPhonesFactory>;
public getMute: ReturnType<typeof getMuteFactory>;
public getOwnId: ReturnType<typeof getOwnIdFactory>;
public getPendingGroupMembers: ReturnType<typeof getPendingGroupMembersFactory>;
public getPinConversations: ReturnType<typeof getPinConversationsFactory>;
public getPollDetail: ReturnType<typeof getPollDetailFactory>;
public getProductCatalogList: ReturnType<typeof getProductCatalogListFactory>;
public getQR: ReturnType<typeof getQRFactory>;
public getQuickMessageList: ReturnType<typeof getQuickMessageListFactory>;
public getRelatedFriendGroup: ReturnType<typeof getRelatedFriendGroupFactory>;
public getReminder: ReturnType<typeof getReminderFactory>;
public getReminderResponses: ReturnType<typeof getReminderResponsesFactory>;
public getSentFriendRequest: ReturnType<typeof getSentFriendRequestFactory>;
public getSettings: ReturnType<typeof getSettingsFactory>;
public getStickerCategoryDetail: ReturnType<typeof getStickerCategoryDetailFactory>;
public getStickers: ReturnType<typeof getStickersFactory>;
public getStickersDetail: ReturnType<typeof getStickersDetailFactory>;
public getUnreadMark: ReturnType<typeof getUnreadMarkFactory>;
public getUserInfo: ReturnType<typeof getUserInfoFactory>;
public inviteUserToGroups: ReturnType<typeof inviteUserToGroupsFactory>;
public joinGroupInviteBox: ReturnType<typeof joinGroupInviteBoxFactory>;
public joinGroupLink: ReturnType<typeof joinGroupLinkFactory>;
public keepAlive: ReturnType<typeof keepAliveFactory>;
public lastOnline: ReturnType<typeof lastOnlineFactory>;
public leaveGroup: ReturnType<typeof leaveGroupFactory>;
public lockPoll: ReturnType<typeof lockPollFactory>;
public parseLink: ReturnType<typeof parseLinkFactory>;
public rejectFriendRequest: ReturnType<typeof rejectFriendRequestFactory>;
public removeFriend: ReturnType<typeof removeFriendFactory>;
public removeFriendAlias: ReturnType<typeof removeFriendAliasFactory>;
public removeGroupBlockedMember: ReturnType<typeof removeGroupBlockedMemberFactory>;
public removeGroupDeputy: ReturnType<typeof removeGroupDeputyFactory>;
public removeQuickMessage: ReturnType<typeof removeQuickMessageFactory>;
public removeReminder: ReturnType<typeof removeReminderFactory>;
public removeUnreadMark: ReturnType<typeof removeUnreadMarkFactory>;
public removeUserFromGroup: ReturnType<typeof removeUserFromGroupFactory>;
public resetHiddenConversPin: ReturnType<typeof resetHiddenConversPinFactory>;
public reuseAvatar: ReturnType<typeof reuseAvatarFactory>;
public reviewPendingMemberRequest: ReturnType<typeof reviewPendingMemberRequestFactory>;
public searchSticker: ReturnType<typeof searchStickerFactory>;
public sendBankCard: ReturnType<typeof sendBankCardFactory>;
public sendCard: ReturnType<typeof sendCardFactory>;
public sendDeliveredEvent: ReturnType<typeof sendDeliveredEventFactory>;
public sendFriendRequest: ReturnType<typeof sendFriendRequestFactory>;
public sendLink: ReturnType<typeof sendLinkFactory>;
public sendMessage: ReturnType<typeof sendMessageFactory>;
public sendReport: ReturnType<typeof sendReportFactory>;
public sendSeenEvent: ReturnType<typeof sendSeenEventFactory>;
public sendSticker: ReturnType<typeof sendStickerFactory>;
public sendTypingEvent: ReturnType<typeof sendTypingEventFactory>;
public sendVideo: ReturnType<typeof sendVideoFactory>;
public sendVoice: ReturnType<typeof sendVoiceFactory>;
public setHiddenConversations: ReturnType<typeof setHiddenConversationsFactory>;
public setMute: ReturnType<typeof setMuteFactory>;
public setPinnedConversations: ReturnType<typeof setPinnedConversationsFactory>;
public sharePoll: ReturnType<typeof sharePollFactory>;
public unblockUser: ReturnType<typeof unblockUserFactory>;
public undo: ReturnType<typeof undoFactory>;
public undoFriendRequest: ReturnType<typeof undoFriendRequestFactory>;
public updateActiveStatus: ReturnType<typeof updateActiveStatusFactory>;
public updateArchivedChatList: ReturnType<typeof updateArchivedChatListFactory>;
public updateAutoDeleteChat: ReturnType<typeof updateAutoDeleteChatFactory>;
public updateAutoReply: ReturnType<typeof updateAutoReplyFactory>;
public updateCatalog: ReturnType<typeof updateCatalogFactory>;
public updateGroupSettings: ReturnType<typeof updateGroupSettingsFactory>;
public updateHiddenConversPin: ReturnType<typeof updateHiddenConversPinFactory>;
public updateLabels: ReturnType<typeof updateLabelsFactory>;
public updateLang: ReturnType<typeof updateLangFactory>;
public updateProductCatalog: ReturnType<typeof updateProductCatalogFactory>;
public updateProfile: ReturnType<typeof updateProfileFactory>;
public updateProfileBio: ReturnType<typeof updateProfileBioFactory>;
public updateQuickMessage: ReturnType<typeof updateQuickMessageFactory>;
public updateSettings: ReturnType<typeof updateSettingsFactory>;
public upgradeGroupToCommunity: ReturnType<typeof upgradeGroupToCommunityFactory>;
public uploadAttachment: ReturnType<typeof uploadAttachmentFactory>;
public uploadProductPhoto: ReturnType<typeof uploadProductPhotoFactory>;
public votePoll: ReturnType<typeof votePollFactory>;
public custom: ReturnType<typeof customFactory>;
constructor(ctx: ContextSession, zpwServiceMap: ZPWServiceMap, wsUrls: string[]) {
this.zpwServiceMap = zpwServiceMap;
this.listener = new Listener(ctx, wsUrls);
this.acceptFriendRequest = acceptFriendRequestFactory(ctx, this);
this.addGroupBlockedMember = addGroupBlockedMemberFactory(ctx, this);
this.addGroupDeputy = addGroupDeputyFactory(ctx, this);
this.addPollOptions = addPollOptionsFactory(ctx, this);
this.addQuickMessage = addQuickMessageFactory(ctx, this);
this.addReaction = addReactionFactory(ctx, this);
this.addUnreadMark = addUnreadMarkFactory(ctx, this);
this.addUserToGroup = addUserToGroupFactory(ctx, this);
this.blockUser = blockUserFactory(ctx, this);
this.blockViewFeed = blockViewFeedFactory(ctx, this);
this.changeAccountAvatar = changeAccountAvatarFactory(ctx, this);
this.changeFriendAlias = changeFriendAliasFactory(ctx, this);
this.changeGroupAvatar = changeGroupAvatarFactory(ctx, this);
this.changeGroupName = changeGroupNameFactory(ctx, this);
this.changeGroupOwner = changeGroupOwnerFactory(ctx, this);
this.createAutoReply = createAutoReplyFactory(ctx, this);
this.createCatalog = createCatalogFactory(ctx, this);
this.createGroup = createGroupFactory(ctx, this);
this.createNote = createNoteFactory(ctx, this);
this.createPoll = createPollFactory(ctx, this);
this.createProductCatalog = createProductCatalogFactory(ctx, this);
this.createReminder = createReminderFactory(ctx, this);
this.deleteAutoReply = deleteAutoReplyFactory(ctx, this);
this.deleteAvatar = deleteAvatarFactory(ctx, this);
this.deleteCatalog = deleteCatalogFactory(ctx, this);
this.deleteChat = deleteChatFactory(ctx, this);
this.deleteGroupInviteBox = deleteGroupInviteBoxFactory(ctx, this);
this.deleteMessage = deleteMessageFactory(ctx, this);
this.deleteProductCatalog = deleteProductCatalogFactory(ctx, this);
this.disableGroupLink = disableGroupLinkFactory(ctx, this);
this.disperseGroup = disperseGroupFactory(ctx, this);
this.editNote = editNoteFactory(ctx, this);
this.editReminder = editReminderFactory(ctx, this);
this.enableGroupLink = enableGroupLinkFactory(ctx, this);
this.fetchAccountInfo = fetchAccountInfoFactory(ctx, this);
this.findUser = findUserFactory(ctx, this);
this.findUserByUsername = findUserByUsernameFactory(ctx, this);
this.forwardMessage = forwardMessageFactory(ctx, this);
this.getAliasList = getAliasListFactory(ctx, this);
this.getAllFriends = getAllFriendsFactory(ctx, this);
this.getAllGroups = getAllGroupsFactory(ctx, this);
this.getArchivedChatList = getArchivedChatListFactory(ctx, this);
this.getAutoDeleteChat = getAutoDeleteChatFactory(ctx, this);
this.getAutoReplyList = getAutoReplyListFactory(ctx, this);
this.getAvatarList = getAvatarListFactory(ctx, this);
this.getAvatarUrlProfile = getAvatarUrlProfileFactory(ctx, this);
this.getBizAccount = getBizAccountFactory(ctx, this);
this.getCatalogList = getCatalogListFactory(ctx, this);
this.getCloseFriends = getCloseFriendsFactory(ctx, this);
this.getContext = getContextFactory(ctx, this);
this.getCookie = getCookieFactory(ctx, this);
this.getFriendBoardList = getFriendBoardListFactory(ctx, this);
this.getFriendOnlines = getFriendOnlinesFactory(ctx, this);
this.getFriendRecommendations = getFriendRecommendationsFactory(ctx, this);
this.getFriendRequestStatus = getFriendRequestStatusFactory(ctx, this);
this.getFullAvatar = getFullAvatarFactory(ctx, this);
this.getGroupBlockedMember = getGroupBlockedMemberFactory(ctx, this);
this.getGroupChatHistory = getGroupChatHistoryFactory(ctx, this);
this.getGroupInfo = getGroupInfoFactory(ctx, this);
this.getGroupInviteBoxInfo = getGroupInviteBoxInfoFactory(ctx, this);
this.getGroupInviteBoxList = getGroupInviteBoxListFactory(ctx, this);
this.getGroupLinkDetail = getGroupLinkDetailFactory(ctx, this);
this.getGroupLinkInfo = getGroupLinkInfoFactory(ctx, this);
this.getGroupMembersInfo = getGroupMembersInfoFactory(ctx, this);
this.getHiddenConversations = getHiddenConversationsFactory(ctx, this);
this.getLabels = getLabelsFactory(ctx, this);
this.getListBoard = getListBoardFactory(ctx, this);
this.getListReminder = getListReminderFactory(ctx, this);
this.getMultiUsersByPhones = getMultiUsersByPhonesFactory(ctx, this);
this.getMute = getMuteFactory(ctx, this);
this.getOwnId = getOwnIdFactory(ctx, this);
this.getPendingGroupMembers = getPendingGroupMembersFactory(ctx, this);
this.getPinConversations = getPinConversationsFactory(ctx, this);
this.getPollDetail = getPollDetailFactory(ctx, this);
this.getProductCatalogList = getProductCatalogListFactory(ctx, this);
this.getQR = getQRFactory(ctx, this);
this.getQuickMessageList = getQuickMessageListFactory(ctx, this);
this.getRelatedFriendGroup = getRelatedFriendGroupFactory(ctx, this);
this.getReminder = getReminderFactory(ctx, this);
this.getReminderResponses = getReminderResponsesFactory(ctx, this);
this.getSentFriendRequest = getSentFriendRequestFactory(ctx, this);
this.getSettings = getSettingsFactory(ctx, this);
this.getStickerCategoryDetail = getStickerCategoryDetailFactory(ctx, this);
this.getStickers = getStickersFactory(ctx, this);
this.getStickersDetail = getStickersDetailFactory(ctx, this);
this.getUnreadMark = getUnreadMarkFactory(ctx, this);
this.getUserInfo = getUserInfoFactory(ctx, this);
this.inviteUserToGroups = inviteUserToGroupsFactory(ctx, this);
this.joinGroupInviteBox = joinGroupInviteBoxFactory(ctx, this);
this.joinGroupLink = joinGroupLinkFactory(ctx, this);
this.keepAlive = keepAliveFactory(ctx, this);
this.lastOnline = lastOnlineFactory(ctx, this);
this.leaveGroup = leaveGroupFactory(ctx, this);
this.lockPoll = lockPollFactory(ctx, this);
this.parseLink = parseLinkFactory(ctx, this);
this.rejectFriendRequest = rejectFriendRequestFactory(ctx, this);
this.removeFriend = removeFriendFactory(ctx, this);
this.removeFriendAlias = removeFriendAliasFactory(ctx, this);
this.removeGroupBlockedMember = removeGroupBlockedMemberFactory(ctx, this);
this.removeGroupDeputy = removeGroupDeputyFactory(ctx, this);
this.removeQuickMessage = removeQuickMessageFactory(ctx, this);
this.removeReminder = removeReminderFactory(ctx, this);
this.removeUnreadMark = removeUnreadMarkFactory(ctx, this);
this.removeUserFromGroup = removeUserFromGroupFactory(ctx, this);
this.resetHiddenConversPin = resetHiddenConversPinFactory(ctx, this);
this.reuseAvatar = reuseAvatarFactory(ctx, this);
this.reviewPendingMemberRequest = reviewPendingMemberRequestFactory(ctx, this);
this.searchSticker = searchStickerFactory(ctx, this);
this.sendBankCard = sendBankCardFactory(ctx, this);
this.sendCard = sendCardFactory(ctx, this);
this.sendDeliveredEvent = sendDeliveredEventFactory(ctx, this);
this.sendFriendRequest = sendFriendRequestFactory(ctx, this);
this.sendLink = sendLinkFactory(ctx, this);
this.sendMessage = sendMessageFactory(ctx, this);
this.sendReport = sendReportFactory(ctx, this);
this.sendSeenEvent = sendSeenEventFactory(ctx, this);
this.sendSticker = sendStickerFactory(ctx, this);
this.sendTypingEvent = sendTypingEventFactory(ctx, this);
this.sendVideo = sendVideoFactory(ctx, this);
this.sendVoice = sendVoiceFactory(ctx, this);
this.setHiddenConversations = setHiddenConversationsFactory(ctx, this);
this.setMute = setMuteFactory(ctx, this);
this.setPinnedConversations = setPinnedConversationsFactory(ctx, this);
this.sharePoll = sharePollFactory(ctx, this);
this.unblockUser = unblockUserFactory(ctx, this);
this.undo = undoFactory(ctx, this);
this.undoFriendRequest = undoFriendRequestFactory(ctx, this);
this.updateActiveStatus = updateActiveStatusFactory(ctx, this);
this.updateArchivedChatList = updateArchivedChatListFactory(ctx, this);
this.updateAutoDeleteChat = updateAutoDeleteChatFactory(ctx, this);
this.updateAutoReply = updateAutoReplyFactory(ctx, this);
this.updateCatalog = updateCatalogFactory(ctx, this);
this.updateGroupSettings = updateGroupSettingsFactory(ctx, this);
this.updateHiddenConversPin = updateHiddenConversPinFactory(ctx, this);
this.updateLabels = updateLabelsFactory(ctx, this);
this.updateLang = updateLangFactory(ctx, this);
this.updateProductCatalog = updateProductCatalogFactory(ctx, this);
this.updateProfile = updateProfileFactory(ctx, this);
this.updateProfileBio = updateProfileBioFactory(ctx, this);
this.updateQuickMessage = updateQuickMessageFactory(ctx, this);
this.updateSettings = updateSettingsFactory(ctx, this);
this.upgradeGroupToCommunity = upgradeGroupToCommunityFactory(ctx, this);
this.uploadAttachment = uploadAttachmentFactory(ctx, this);
this.uploadProductPhoto = uploadProductPhotoFactory(ctx, this);
this.votePoll = votePollFactory(ctx, this);
this.custom = customFactory(ctx, this);
}
}
@@ -0,0 +1,34 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type AcceptFriendRequestResponse = "";
export const acceptFriendRequestFactory = apiFactory<AcceptFriendRequestResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.friend[0]}/api/friend/accept`);
/**
* Accept a friend request from a User
*
* @param friendId The friend ID to user request is accept
*
* @throws {ZaloApiError}
*/
return async function acceptFriendRequest(friendId: string) {
const params = {
fid: friendId,
language: ctx.language,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
@@ -0,0 +1,34 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type AddGroupBlockedMemberResponse = "";
export const addGroupBlockedMemberFactory = apiFactory<AddGroupBlockedMemberResponse>()((api, _, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/blockedmems/add`);
/**
* Add group blocked member
*
* @param memberId member id(s)
* @param groupId group id
*
* @throws {ZaloApiError}
*/
return async function addGroupBlockedMember(memberId: string | string[], groupId: string) {
if (!Array.isArray(memberId)) memberId = [memberId];
const params = {
grid: groupId,
members: memberId,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+36
View File
@@ -0,0 +1,36 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type AddGroupDeputyResponse = "";
export const addGroupDeputyFactory = apiFactory<AddGroupDeputyResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/admins/add`);
/**
* Add group deputy
*
* @param memberId user Id or list of user Ids
* @param groupId group Id
*
* @throws {ZaloApiError}
*
*/
return async function addGroupDeputy(memberId: string | string[], groupId: string) {
if (!Array.isArray(memberId)) memberId = [memberId];
const params = {
grid: groupId,
members: memberId,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+46
View File
@@ -0,0 +1,46 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { PollOptions } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type AddPollOptionsOption = {
voted: boolean;
content: string;
};
export type AddPollOptionsPayload = {
pollId: number;
options: AddPollOptionsOption[];
votedOptionIds: number[];
};
export type AddPollOptionsResponse = {
options: PollOptions[];
};
export const addPollOptionsFactory = apiFactory<AddPollOptionsResponse>()((api, _ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/poll/option/add`);
/**
* Add new option to poll
*
* @param payload
*
* @throws {ZaloApiError}
*/
return async function addPollOptions(payload: AddPollOptionsPayload) {
const params = {
poll_id: payload.pollId,
new_options: JSON.stringify(payload.options),
voted_option_ids: payload.votedOptionIds,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+79
View File
@@ -0,0 +1,79 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { QuickMessage, AttachmentSource } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type AddQuickMessagePayload = {
keyword: string;
title: string;
media?: AttachmentSource;
};
export type AddQuickMessageResponse = {
item: QuickMessage;
version: number;
};
export const addQuickMessageFactory = apiFactory<AddQuickMessageResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.quick_message[0]}/api/quickmessage/create`);
/**
* Add quick message
*
* @param addPayload - The payload containing data to add the quick message
*
* @note Zalo might throw an error with code 821 if you have reached the limit of quick messages.
*
* @throws {ZaloApiError}
*/
return async function addQuickMessage(addPayload: AddQuickMessagePayload) {
const isType = !addPayload.media ? 0 : 1;
const params: Record<string, unknown> = {
keyword: addPayload.keyword,
message: {
title: addPayload.title,
params: "",
},
type: isType,
imei: ctx.imei,
};
if (isType === 1) {
if (!addPayload.media) throw new ZaloApiError("Media is required");
const uploadMedia = await api.uploadProductPhoto({
file: addPayload.media,
});
const photoId = uploadMedia.photoId;
const thumbUrl = uploadMedia.thumbUrl;
const normalUrl = uploadMedia.normalUrl;
const hdUrl = uploadMedia.hdUrl;
params.media = {
items: [
{
type: 0,
photoId: photoId,
title: "",
width: "",
height: "",
previewThumb: thumbUrl,
rawUrl: normalUrl || hdUrl,
thumbUrl: thumbUrl,
normalUrl: normalUrl || hdUrl,
hdUrl: hdUrl || normalUrl,
},
],
};
}
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+321
View File
@@ -0,0 +1,321 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { ThreadType, Reactions } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type AddReactionResponse = {
msgIds: number[];
};
export type CustomReaction = {
rType: number;
source: number;
icon: string;
};
export type AddReactionDestination = {
data: {
msgId: string;
cliMsgId: string;
};
threadId: string;
type: ThreadType;
};
export const addReactionFactory = apiFactory<AddReactionResponse>()((api, ctx, utils) => {
const serviceURLs = {
[ThreadType.User]: utils.makeURL(`${api.zpwServiceMap.reaction[0]}/api/message/reaction`),
[ThreadType.Group]: utils.makeURL(`${api.zpwServiceMap.reaction[0]}/api/group/reaction`),
};
/**
* Add reaction to a message
*
* @param icon Reaction icon
* @param dest Destination data including message IDs and thread information
*
* @throws {ZaloApiError}
*/
return async function addReaction(icon: Reactions | CustomReaction, dest: AddReactionDestination) {
const serviceURL = serviceURLs[dest.type];
let rType, source;
if (typeof icon == "object") {
rType = icon.rType;
source = icon.source;
} else
switch (icon) {
case Reactions.HAHA:
rType = 0;
source = 6;
break;
case Reactions.LIKE:
rType = 3;
source = 6;
break;
case Reactions.HEART:
rType = 5;
source = 6;
break;
case Reactions.WOW:
rType = 32;
source = 6;
break;
case Reactions.CRY:
rType = 2;
source = 6;
break;
case Reactions.ANGRY:
rType = 20;
source = 6;
break;
case Reactions.KISS:
rType = 8;
source = 6;
break;
case Reactions.TEARS_OF_JOY:
rType = 7;
source = 6;
break;
case Reactions.SHIT:
rType = 66;
source = 6;
break;
case Reactions.ROSE:
rType = 120;
source = 6;
break;
case Reactions.BROKEN_HEART:
rType = 65;
source = 6;
break;
case Reactions.DISLIKE:
rType = 4;
source = 6;
break;
case Reactions.LOVE:
rType = 29;
source = 6;
break;
case Reactions.CONFUSED:
rType = 51;
source = 6;
break;
case Reactions.WINK:
rType = 45;
source = 6;
break;
case Reactions.FADE:
rType = 121;
source = 6;
break;
case Reactions.SUN:
rType = 67;
source = 6;
break;
case Reactions.BIRTHDAY:
rType = 126;
source = 6;
break;
case Reactions.BOMB:
rType = 127;
source = 6;
break;
case Reactions.OK:
rType = 68;
source = 6;
break;
case Reactions.PEACE:
rType = 69;
source = 6;
break;
case Reactions.THANKS:
rType = 70;
source = 6;
break;
case Reactions.PUNCH:
rType = 71;
source = 6;
break;
case Reactions.SHARE:
rType = 72;
source = 6;
break;
case Reactions.PRAY:
rType = 73;
source = 6;
break;
case Reactions.NO:
rType = 131;
source = 6;
break;
case Reactions.BAD:
rType = 132;
source = 6;
break;
case Reactions.LOVE_YOU:
rType = 133;
source = 6;
break;
case Reactions.SAD:
rType = 1;
source = 6;
break;
case Reactions.VERY_SAD:
rType = 16;
source = 6;
break;
case Reactions.COOL:
rType = 21;
source = 6;
break;
case Reactions.NERD:
rType = 22;
source = 6;
break;
case Reactions.BIG_SMILE:
rType = 23;
source = 6;
break;
case Reactions.SUNGLASSES:
rType = 26;
source = 6;
break;
case Reactions.NEUTRAL:
rType = 30;
source = 6;
break;
case Reactions.SAD_FACE:
rType = 35;
source = 6;
break;
case Reactions.BYE:
rType = 36;
source = 6;
break;
case Reactions.SLEEPY:
rType = 38;
source = 6;
break;
case Reactions.WIPE:
rType = 39;
source = 6;
break;
case Reactions.DIG:
rType = 42;
source = 6;
break;
case Reactions.ANGUISH:
rType = 44;
source = 6;
break;
case Reactions.HANDCLAP:
rType = 46;
source = 6;
break;
case Reactions.ANGRY_FACE:
rType = 47;
source = 6;
break;
case Reactions.F_CHAIR:
rType = 48;
source = 6;
break;
case Reactions.L_CHAIR:
rType = 49;
source = 6;
break;
case Reactions.R_CHAIR:
rType = 50;
source = 6;
break;
case Reactions.SILENT:
rType = 52;
source = 6;
break;
case Reactions.SURPRISE:
rType = 53;
source = 6;
break;
case Reactions.EMBARRASSED:
rType = 54;
source = 6;
break;
case Reactions.AFRAID:
rType = 60;
source = 6;
break;
case Reactions.SAD2:
rType = 61;
source = 6;
break;
case Reactions.BIG_LAUGH:
rType = 62;
source = 6;
break;
case Reactions.RICH:
rType = 63;
source = 6;
break;
case Reactions.BEER:
rType = 99;
source = 6;
break;
default:
rType = -1;
source = 6;
}
const rIcon = typeof icon == "object" ? icon.icon : icon;
if (rType == undefined || source == undefined || rIcon == undefined) {
throw new ZaloApiError("Invalid reaction");
}
const params: Record<string, unknown> = {
react_list: [
{
message: JSON.stringify({
rMsg: [
{
gMsgID: parseInt(dest.data.msgId),
cMsgID: parseInt(dest.data.cliMsgId),
msgType: 1,
},
],
rIcon,
rType,
source,
}),
clientId: Date.now(),
},
],
};
if (dest.type == ThreadType.User) {
params.toid = dest.threadId;
} else {
params.grid = dest.threadId;
params.imei = ctx.imei;
}
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt message");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response, (result) => {
if (typeof (result.data as { msgIds: unknown }).msgIds === "string") {
return {
msgIds: JSON.parse((result.data as { msgIds: string }).msgIds),
};
}
return result.data as AddReactionResponse;
});
};
});
+65
View File
@@ -0,0 +1,65 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { ThreadType } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type AddUnreadMarkResponse = {
data: {
updateId: number;
};
status: number;
};
export const addUnreadMarkFactory = apiFactory<AddUnreadMarkResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.conversation[0]}/api/conv/addUnreadMark`);
/**
* Add unread mark to conversation
*
* @param threadId Thread ID
* @param type Thread type (User/Group)
*
* @throws {ZaloApiError}
*/
return async function addUnreadMark(threadId: string, type: ThreadType = ThreadType.User) {
const timestamp = Date.now();
const timestampString = timestamp.toString();
const isGroup = type === ThreadType.Group;
const requestParams = {
param: JSON.stringify({
[isGroup ? "convsGroup" : "convsUser"]: [
{
id: threadId,
cliMsgId: timestampString,
fromUid: "0",
ts: timestamp,
},
],
[isGroup ? "convsUser" : "convsGroup"]: [],
imei: ctx.imei,
}),
};
const encryptedParams = utils.encodeAES(JSON.stringify(requestParams));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response, (result) => {
const data = result.data as { data: unknown; status: number };
if (typeof data.data === "string") {
return {
data: JSON.parse(data.data),
status: data.status,
};
}
return result.data as AddUnreadMarkResponse;
});
};
});
+43
View File
@@ -0,0 +1,43 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type AddUserToGroupResponse = {
errorMembers: string[];
error_data: Record<string, string[]>;
};
export const addUserToGroupFactory = apiFactory<AddUserToGroupResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/invite/v2`);
/**
* Add user to existing group
*
* @param memberId User ID or list of user IDs to add
* @param groupId Group ID
*
* @throws {ZaloApiError}
*/
return async function addUserToGroup(memberId: string | string[], groupId: string) {
if (!Array.isArray(memberId)) memberId = [memberId];
const params = {
grid: groupId,
members: memberId,
memberTypes: memberId.map(() => -1),
imei: ctx.imei,
clientLang: ctx.language,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+34
View File
@@ -0,0 +1,34 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type BlockUserResponse = "";
export const blockUserFactory = apiFactory<BlockUserResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.friend[0]}/api/friend/block`);
/**
* Block a User
*
* @param userId The ID of the User to block
*
* @throws {ZaloApiError}
*/
return async function blockUser(userId: string) {
const params = {
fid: userId,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+36
View File
@@ -0,0 +1,36 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type BlockViewFeedResponse = "";
export const blockViewFeedFactory = apiFactory<BlockViewFeedResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.friend[0]}/api/friend/feed/block`);
/**
* Block/Unblock friend view feed by ID
*
* @param isBlockFeed Boolean to block/unblock view feed
* @param userId User ID to block/unblock view feed
*
* @throws {ZaloApiError}
*/
return async function blockViewFeed(isBlockFeed: boolean, userId: string) {
const params = {
fid: userId,
isBlockFeed: isBlockFeed ? 1 : 0,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
@@ -0,0 +1,65 @@
import FormData from "form-data";
import fs from "node:fs";
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { AttachmentSource } from "../models/index.js";
import { apiFactory, formatTime, getImageMetaData } from "../utils.js";
export type ChangeAccountAvatarResponse = "";
export const changeAccountAvatarFactory = apiFactory<ChangeAccountAvatarResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.file[0]}/api/profile/upavatar`);
/**
* Change account avatar
*
* @param avatarSource Attachment source, can be a file path or an Attachment object
*
* @throws {ZaloApiError | ZaloApiMissingImageMetadataGetter}
*/
return async function changeAccountAvatar(avatarSource: AttachmentSource) {
const isSourceFilePath = typeof avatarSource == "string";
const imageMetaData = isSourceFilePath ? await getImageMetaData(ctx, avatarSource) : avatarSource.metadata;
const fileSize = imageMetaData.totalSize || 0;
const params = {
avatarSize: 120,
clientId: String(ctx.uid + formatTime("%H:%M %d/%m/%Y")),
language: ctx.language,
metaData: JSON.stringify({
origin: {
width: imageMetaData.width || 1080,
height: imageMetaData.height || 1080,
},
processed: {
width: imageMetaData.width || 1080,
height: imageMetaData.height || 1080,
size: fileSize,
},
}),
};
const avatarData = isSourceFilePath ? fs.readFileSync(avatarSource) : avatarSource.data;
const formData = new FormData();
formData.append("fileContent", avatarData, {
filename: "blob",
contentType: "image/jpeg",
});
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(
utils.makeURL(serviceURL, {
params: encryptedParams,
}),
{
method: "POST",
headers: formData.getHeaders(),
body: formData.getBuffer(),
},
);
return utils.resolve(response);
};
});
@@ -0,0 +1,33 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type ChangeFriendAliasResponse = "";
export const changeFriendAliasFactory = apiFactory<ChangeFriendAliasResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.alias[0]}/api/alias/update`);
/**
* Change friend's alias
*
* @param alias new alias (nickname - bietdanh)
* @param friendId friend id
*
* @throws {ZaloApiError}
*/
return async function changeFriendAlias(alias: string, friendId: string) {
const params = {
friendId: friendId,
alias: alias,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
@@ -0,0 +1,57 @@
import FormData from "form-data";
import fs from "node:fs";
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { AttachmentSource } from "../models/index.js";
import { apiFactory, getFullTimeFromMillisecond, getImageMetaData } from "../utils.js";
export type ChangeGroupAvatarResponse = "";
export const changeGroupAvatarFactory = apiFactory<ChangeGroupAvatarResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.file[0]}/api/group/upavatar`);
/**
* Change group avatar
*
* @param avatarSource Attachment source, can be a file path or an Attachment object
* @param groupId Group ID
*
* @throws {ZaloApiError | ZaloApiMissingImageMetadataGetter}
*/
return async function changeGroupAvatar(avatarSource: AttachmentSource, groupId: string) {
const params: Record<string, unknown> = {
grid: groupId,
avatarSize: 120,
clientId: `g${groupId}${getFullTimeFromMillisecond(new Date().getTime())}`,
imei: ctx.imei,
};
const isSourceFilePath = typeof avatarSource == "string";
const imageMetaData = isSourceFilePath ? await getImageMetaData(ctx, avatarSource) : avatarSource.metadata;
params.originWidth = imageMetaData.width || 1080;
params.originHeight = imageMetaData.height || 1080;
const avatarData = isSourceFilePath ? fs.readFileSync(avatarSource) : avatarSource.data;
const formData = new FormData();
formData.append("fileContent", avatarData, {
filename: "blob",
contentType: "image/jpeg",
});
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(
utils.makeURL(serviceURL, {
params: encryptedParams,
}),
{
method: "POST",
headers: formData.getHeaders(),
body: formData.getBuffer(),
},
);
return utils.resolve(response);
};
});
+40
View File
@@ -0,0 +1,40 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type ChangeGroupNameResponse = {
status: number;
};
export const changeGroupNameFactory = apiFactory<ChangeGroupNameResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/updateinfo`);
/**
* Change group name
*
* @param name New group name
* @param groupId Group ID
*
* @throws {ZaloApiError}
*/
return async function changeGroupName(name: string, groupId: string) {
if (name.length == 0) name = Date.now().toString();
const params = {
grid: groupId,
gname: name,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+38
View File
@@ -0,0 +1,38 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type ChangeGroupOwnerResponse = {
time: number;
};
export const changeGroupOwnerFactory = apiFactory<ChangeGroupOwnerResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/change-owner`);
/**
* Change group owner
*
* @param memberId User Id of new group owner
* @param groupId Group Id
* @note Be careful when changing the key, as it will result in losing group admin rights
*
* @throws {ZaloApiError}
*
*/
return async function changeGroupOwner(memberId: string, groupId: string) {
const params = {
grid: groupId,
newAdminId: memberId,
imei: ctx.imei,
language: ctx.language,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+58
View File
@@ -0,0 +1,58 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import type { AutoReplyItem, AutoReplyScope } from "../models/index.js";
export type CreateAutoReplyPayload = {
content: string;
isEnable: boolean;
startTime: number;
endTime: number;
scope: AutoReplyScope;
uids?: string | string[];
};
export type CreateAutoReplyResponse = {
item: AutoReplyItem;
version: number;
};
export const createAutoReplyFactory = apiFactory<CreateAutoReplyResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.auto_reply[0]}/api/autoreply/create`);
/**
* Create auto reply
*
* @param payload payload
*
* @note this API used for zBusiness
* @throws {ZaloApiError}
*/
return async function createAutoReply(payload: CreateAutoReplyPayload) {
const uids = Array.isArray(payload.uids) ? payload.uids : [payload.uids];
const resultUids = (payload.scope === 2 || payload.scope === 3) ? uids : [];
const params = {
cliLang: ctx.language,
enable: payload.isEnable,
content: payload.content,
startTime: payload.startTime,
endTime: payload.endTime,
recurrence: ["RRULE:FREQ=DAILY;"],
scope: payload.scope,
uids: resultUids,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+41
View File
@@ -0,0 +1,41 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import type { CatalogItem } from "../models/index.js";
export type CreateCatalogResponse = {
item: CatalogItem;
version_ls_catalog: number;
version_catalog: number;
};
export const createCatalogFactory = apiFactory<CreateCatalogResponse>()((api, _, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.catalog[0]}/api/prodcatalog/catalog/create`);
/**
* Create catalog?
*
* @param catalogName catalog name
*
* @note this API is used for zBusiness
* @throws {ZaloApiError}
*/
return async function createCatalog(catalogName: string) {
const params = {
catalog_name: catalogName,
catalog_photo: "",
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+77
View File
@@ -0,0 +1,77 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { AttachmentSource } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type CreateGroupResponse = {
groupType: number;
sucessMembers: string[];
groupId: string;
errorMembers: string[];
error_data: Record<string, unknown>;
};
export type CreateGroupOptions = {
/**
* Group name
*/
name?: string;
/**
* List of member IDs to add to the group
*/
members: string[];
/**
* Avatar source, can be a file path or an Attachment object
*/
avatarSource?: AttachmentSource;
/**
* Path to the avatar image file
* @deprecated Use `avatarSource` instead
*/
avatarPath?: string;
};
export const createGroupFactory = apiFactory<CreateGroupResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/create/v2`);
/**
* Create a new group
*
* @param options Group options
*
* @throws {ZaloApiError}
*/
return async function createGroup(options: CreateGroupOptions) {
if (options.members.length == 0) throw new ZaloApiError("Group must have at least one member");
const params = {
clientId: Date.now(),
gname: String(Date.now()),
gdesc: null,
members: options.members,
membersTypes: options.members.map(() => -1),
nameChanged: 0,
createLink: 1,
clientLang: ctx.language,
imei: ctx.imei,
zsource: 601,
};
if (options.name && options.name.length > 0) {
params.gname = options.name;
params.nameChanged = 1;
}
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt message");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "POST",
});
const data = await utils.resolve(response);
options.avatarSource = options.avatarSource || options.avatarPath;
if (options.avatarSource) await api.changeGroupAvatar(options.avatarSource, data.groupId).catch(utils.logger.error);
return data;
};
});
+62
View File
@@ -0,0 +1,62 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { NoteDetail } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type CreateNoteOptions = {
title: string;
pinAct?: boolean;
};
export type CreateNoteResponse = NoteDetail;
export const createNoteFactory = apiFactory<CreateNoteResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group_board[0]}/api/board/topic/createv2`);
/**
* Create a note in a group
*
* @param options note options
* @param options.title note title
* @param options.pinAct pin action (pin note)
* @param groupId group id
*
* @throws {ZaloApiError}
*/
return async function createNote(options: CreateNoteOptions, groupId: string) {
const params = {
grid: groupId,
type: 0,
color: -16777216,
emoji: "",
startTime: -1,
duration: -1,
params: JSON.stringify({
title: options.title,
}),
repeat: 0,
src: 1,
imei: ctx.imei,
pinAct: options.pinAct ? 1 : 0,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response, (result) => {
if (typeof (result.data as { params: unknown }).params === "string") {
(result.data as CreateNoteResponse).params = JSON.parse(
(result.data as { params: string }).params,
);
}
return result.data as CreateNoteResponse;
});
};
});
+87
View File
@@ -0,0 +1,87 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import type { PollDetail } from "../models/index.js";
/**
* Options for creating a poll.
*/
export type CreatePollOptions = {
/**
* Question for the poll.
*/
question: string;
/**
* List of options for the poll.
*/
options: string[];
/**
* Poll expiration time in milliseconds (0 = no expiration).
*/
expiredTime?: number;
/**
* Allows multiple choices in the poll.
*/
allowMultiChoices?: boolean;
/**
* Allows members to add new options to the poll.
*/
allowAddNewOption?: boolean;
/**
* Hides voting results until the user has voted.
*/
hideVotePreview?: boolean;
/**
* Hides poll voters (anonymous poll).
*/
isAnonymous?: boolean;
};
export type CreatePollResponse = PollDetail;
export const createPollFactory = apiFactory<CreatePollResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/poll/create`);
/**
* Create a poll in a group.
*
* @param options Poll options
* @param groupId Group ID to create poll from
*
* @throws {ZaloApiError}
*/
return async function createPoll(options: CreatePollOptions, groupId: string) {
const params = {
group_id: groupId,
question: options.question,
options: options.options,
expired_time: options.expiredTime ?? 0,
pinAct: false,
allow_multi_choices: !!options.allowMultiChoices,
allow_add_new_option: !!options.allowAddNewOption,
is_hide_vote_preview: !!options.hideVotePreview,
is_anonymous: !!options.isAnonymous,
poll_type: 0,
src: 1,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
@@ -0,0 +1,86 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import type { AttachmentSource, ProductCatalogItem } from "../models/index.js";
export type CreateProductCatalogPayload = {
catalogId: string;
productName: string;
price: string;
description: string;
/**
* Upto 5 media files are allowed, will be ignored if product_photos is provided
*/
files?: AttachmentSource[];
/**
* List of product photo URLs, upto 5
*
* You can manually get the URL using `uploadProductPhoto` api
*/
product_photos?: string[];
};
export type CreateProductCatalogResponse = {
item: ProductCatalogItem;
version_ls_catalog: number;
version_catalog: number;
};
export const createProductCatalogFactory = apiFactory<CreateProductCatalogResponse>()((api, _, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.catalog[0]}/api/prodcatalog/product/create`);
/**
* Create product catalog?
*
* @param payload payload
*
* @note this API is used for zBussiness - Maximum 5 media files are supported
* @throws {ZaloApiError}
*/
return async function createProductCatalog(payload: CreateProductCatalogPayload) {
const productPhoto = payload.product_photos || [];
if (payload.files && payload.files.length == 0) {
if (payload.files.length > 5) {
throw new ZaloApiError("Maximum 5 media files are allowed");
}
for (const mediaFile of payload.files) {
const uploadMedia = await api.uploadProductPhoto({
file: mediaFile,
});
const url = uploadMedia.normalUrl || uploadMedia.hdUrl;
productPhoto.push(url);
}
}
if (productPhoto.length > 5) {
throw new ZaloApiError("Maximum 5 media files are allowed");
}
const params = {
product_name: payload.productName,
price: payload.price,
description: payload.description,
product_photos: productPhoto,
catalog_id: payload.catalogId,
currency_unit: "₫", // $
create_time: Date.now(),
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+84
View File
@@ -0,0 +1,84 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { ReminderGroup, ReminderUser} from "../models/index.js";
import { ReminderRepeatMode, ThreadType } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type CreateReminderOptions = {
title: string;
emoji?: string;
startTime?: number;
repeat?: ReminderRepeatMode;
};
export type CreateReminderUser = ReminderUser;
export type CreateReminderGroup = Omit<ReminderGroup, "responseMem">;
export type CreateReminderResponse = CreateReminderUser | CreateReminderGroup;
export const createReminderFactory = apiFactory<CreateReminderResponse>()((api, ctx, utils) => {
const serviceURL = {
[ThreadType.User]: utils.makeURL(`${api.zpwServiceMap.group_board[0]}/api/board/oneone/create`),
[ThreadType.Group]: utils.makeURL(`${api.zpwServiceMap.group_board[0]}/api/board/topic/createv2`),
};
/**
* Create a reminder in a group
*
* @param options reminder options
* @param threadId Group ID to create note from
* @param type Thread type (User or Group)
*
* @throws {ZaloApiError}
*/
return async function createReminder(
options: CreateReminderOptions,
threadId: string,
type: ThreadType = ThreadType.User,
): Promise<CreateReminderResponse> {
const params =
type === ThreadType.User
? {
objectData: JSON.stringify({
toUid: threadId,
type: 0,
color: -16245706,
emoji: options.emoji ?? "⏰",
startTime: options.startTime ?? Date.now(),
duration: -1,
params: { title: options.title },
needPin: false,
repeat: options.repeat ?? ReminderRepeatMode.None,
creatorUid: ctx.uid, // Note: for some reason, you can put any valid UID here instead of your own and it still works, atleast for mobile
src: 1,
}),
imei: ctx.imei,
}
: {
grid: threadId,
type: 0,
color: -16245706,
emoji: options.emoji ?? "⏰",
startTime: options.startTime ?? Date.now(),
duration: -1,
params: JSON.stringify({
title: options.title,
}),
repeat: options.repeat ?? ReminderRepeatMode.None,
src: 1,
imei: ctx.imei,
pinAct: 0,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL[type], {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+19
View File
@@ -0,0 +1,19 @@
import { type ContextSession } from "../context.js";
import { apiFactory, type FactoryUtils } from "../utils.js";
export type CustomAPIProps<T, K> = { ctx: ContextSession; utils: FactoryUtils<T>; props: K };
export type CustomAPICallback<T, K> = (props: CustomAPIProps<T, K>) => T | Promise<T>;
/* eslint-disable */
export const customFactory = apiFactory<any>()((api, ctx, utils) => {
return function custom<T, K = any>(name: string, callback: CustomAPICallback<T, K>) {
Object.defineProperty(api, name, {
value: function (props: K) {
return callback({ ctx, utils, props });
},
writable: false,
enumerable: false,
configurable: false,
});
};
});
+38
View File
@@ -0,0 +1,38 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type DeleteAutoReplyResponse = {
item: number;
version: number;
};
export const deleteAutoReplyFactory = apiFactory<DeleteAutoReplyResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.auto_reply[0]}/api/autoreply/delete`);
/**
* Delete auto reply
*
* @param id id of auto reply
*
* @note this API used for zBusiness
* @throws {ZaloApiError}
*/
return async function deleteAutoReply(id: number) {
const params = {
cliLang: ctx.language,
id: id,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+41
View File
@@ -0,0 +1,41 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type DeleteAvatarResponse = {
delPhotoIds: string[];
errMap: {
[key: string]: {
err: number;
};
};
};
export const deleteAvatarFactory = apiFactory<DeleteAvatarResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/del-avatars`);
/**
* Delete avatar from avatar list
*
* @param photoId avatar photo ID(s) to delete - can be a single string or array of strings
*
* @throws {ZaloApiError}
*/
return async function deleteAvatar(photoId: string | string[]) {
const photoIds = Array.isArray(photoId) ? photoId : [photoId];
const delPhotos = photoIds.map((id) => ({ photoId: id }));
const params = {
delPhotos: JSON.stringify(delPhotos),
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+34
View File
@@ -0,0 +1,34 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type DeleteCatalogResponse = "";
export const deleteCatalogFactory = apiFactory<DeleteCatalogResponse>()((api, _, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.catalog[0]}/api/prodcatalog/catalog/delete`);
/**
* Delete catalog?
*
* @param catalogId catalog id
*
* @note this API is used for zBusiness
* @throws {ZaloApiError}
*/
return async function deleteCatalog(catalogId: string) {
const params = {
catalog_id: catalogId,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+79
View File
@@ -0,0 +1,79 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { ThreadType } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type DeleteChatResponse = {
status: number;
};
export type DeleteChatLastMessage = {
/**
* Last message owner ID to delete backwards
*/
ownerId: string;
/**
* Last message client ID to delete backwards
*/
cliMsgId: string;
/**
* Last message global ID to delete backwards
*/
globalMsgId: string;
};
export const deleteChatFactory = apiFactory<DeleteChatResponse>()((api, ctx, utils) => {
const serviceURL = {
[ThreadType.User]: utils.makeURL(`${api.zpwServiceMap.chat[0]}/api/message/deleteconver`, {
nretry: 0,
}),
[ThreadType.Group]: utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/deleteconver`, {
nretry: 0,
}),
};
/**
* Delete chat
*
* @param lastMessage Last message info
* @param threadId Thread ID
* @param type Thread type
*
* @throws {ZaloApiError}
*/
return async function deleteChat(
lastMessage: DeleteChatLastMessage,
threadId: string,
type: ThreadType = ThreadType.User,
) {
const timestampString = Date.now().toString();
const params =
type === ThreadType.User
? {
toid: threadId,
cliMsgId: timestampString,
conver: lastMessage,
onlyMe: 1,
imei: ctx.imei,
}
: {
grid: threadId,
cliMsgId: timestampString,
conver: lastMessage,
onlyMe: 1,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL[type], {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
@@ -0,0 +1,41 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type DeleteGroupInviteBoxResponse = {
delInvitaionIds: string[];
errMap: {
[groupId: string]: {
err: number;
};
};
};
export const deleteGroupInviteBoxFactory = apiFactory<DeleteGroupInviteBoxResponse>()((api, _, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/inv-box/mdel-inv`);
/**
* Delete group invite box
*
* @param groupId - The group id
* @param blockFutureInvite - Whether to block future invites from this group
*
* @throws {ZaloApiError}
*/
return async function deleteGroupInviteBox(groupId: string | string[], blockFutureInvite: boolean = false) {
const grids = Array.isArray(groupId) ? groupId : [groupId];
const params = {
invitations: JSON.stringify(grids.map((grid) => ({ grid }))),
block: blockFutureInvite ? 1 : 0,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+72
View File
@@ -0,0 +1,72 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { ThreadType } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type DeleteMessageResponse = {
status: number;
};
export type DeleteMessageDestination = {
data: {
cliMsgId: string;
msgId: string;
uidFrom: string;
};
threadId: string;
type?: ThreadType;
};
export const deleteMessageFactory = apiFactory<DeleteMessageResponse>()((api, ctx, utils) => {
const serviceURL = {
[ThreadType.User]: utils.makeURL(`${api.zpwServiceMap.chat[0]}/api/message/delete`),
[ThreadType.Group]: utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/deletemsg`),
};
/**
* Delete a message
*
* @param dest Delete target
* @param onlyMe Delete message for only you
*
* @throws {ZaloApiError}
*/
return async function deleteMessage(dest: DeleteMessageDestination, onlyMe = false) {
const { threadId, type = ThreadType.User, data } = dest;
const isGroup = type === ThreadType.Group;
const isSelf = ctx.uid == data.uidFrom;
if (isSelf && onlyMe === false)
throw new ZaloApiError("To delete your message for everyone, use undo api instead");
if (!isGroup && onlyMe === false) throw new ZaloApiError("Can't delete message for everyone in a private chat");
const params = {
[isGroup ? "grid" : "toid"]: threadId,
cliMsgId: Date.now(),
msgs: [
{
cliMsgId: data.cliMsgId,
globalMsgId: data.msgId,
ownerId: data.uidFrom,
destId: threadId,
},
],
onlyMe: onlyMe ? 1 : 0,
};
if (!isGroup) {
params.imei = ctx.imei;
}
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt message");
const response = await utils.request(serviceURL[type], {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
@@ -0,0 +1,46 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type DeleteProductCatalogPayload = {
productIds: string | string[];
catalogId: string;
};
export type DeleteProductCatalogResponse = {
item: number[];
version_ls_catalog: number;
version_catalog: number;
};
export const deleteProductCatalogFactory = apiFactory<DeleteProductCatalogResponse>()((api, _, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.catalog[0]}/api/prodcatalog/product/mdelete`);
/**
* Delete product catalog?
*
* @param payload payload
*
* @note this API is used for zBusiness
* @throws {ZaloApiError}
*/
return async function deleteProductCatalog(payload: DeleteProductCatalogPayload) {
if (!Array.isArray(payload.productIds)) payload.productIds = [payload.productIds];
const params = {
product_ids: payload.productIds,
catalog_id: payload.catalogId,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+30
View File
@@ -0,0 +1,30 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type DisableGroupLinkResponse = "";
export const disableGroupLinkFactory = apiFactory<DisableGroupLinkResponse>()((api, _ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/link/disable`);
/**
* Disable group link
*
* @param groupId The group id
*
* @throws {ZaloApiError}
*/
return async function disableGroupLink(groupId: string) {
const params = {
grid: groupId,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+34
View File
@@ -0,0 +1,34 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type DisperseGroupResponse = "";
export const disperseGroupFactory = apiFactory<DisperseGroupResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/disperse`);
/**
* Disperse Group
*
* @param groupId Group ID to disperse Group from
*
* @throws {ZaloApiError}
*/
return async function disperseGroup(groupId: string) {
const params = {
grid: groupId,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+70
View File
@@ -0,0 +1,70 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import type { NoteDetail } from "../models/index.js";
export type EditNoteOptions = {
/**
* New note title
*/
title: string;
/**
* Topic ID to edit note from
*/
topicId: string;
/**
* Should the note be pinned?
*/
pinAct?: boolean;
};
export type EditNoteResponse = NoteDetail;
export const editNoteFactory = apiFactory<EditNoteResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group_board[0]}/api/board/topic/updatev2`);
/**
* Edit an existing note in a group
*
* @param options Options for editing the note
* @param groupId Group ID to create note from
*
* @throws {ZaloApiError}
*/
return async function editNote(options: EditNoteOptions, groupId: string) {
const params = {
grid: groupId,
type: 0,
color: -16777216,
emoji: "",
startTime: -1,
duration: -1,
params: JSON.stringify({
title: options.title,
}),
topicId: options.topicId,
repeat: 0,
imei: ctx.imei,
pinAct: options.pinAct ? 1 : 2,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response, (result) => {
const data = result.data as Omit<NoteDetail, "params"> & { params: unknown };
if (typeof data.params == "string") {
data.params = JSON.parse(data.params);
}
return data as NoteDetail;
});
};
});
+83
View File
@@ -0,0 +1,83 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { ReminderRepeatMode, ReminderGroup, ReminderUser} from "../models/index.js";
import { ThreadType } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type EditReminderOptions = {
title: string;
topicId: string;
emoji?: string;
startTime?: number;
repeat?: ReminderRepeatMode;
};
export type EditReminderUser = ReminderUser;
export type EditReminderGroup = Omit<ReminderGroup, "responseMem">;
export type EditReminderResponse = EditReminderUser | EditReminderGroup;
export const editReminderFactory = apiFactory<EditReminderResponse>()((api, ctx, utils) => {
const serviceURL = {
[ThreadType.User]: utils.makeURL(`${api.zpwServiceMap.group_board[0]}/api/board/oneone/update`),
[ThreadType.Group]: utils.makeURL(`${api.zpwServiceMap.group_board[0]}/api/board/topic/updatev2`),
};
/**
* Edit an existing reminder
*
* @param options Reminder parameters
* @param threadId Thread ID
* @param type Thread type (User/Group)
*
* @throws {ZaloApiError}
*/
return async function editReminder(
options: EditReminderOptions,
threadId: string,
type: ThreadType = ThreadType.User,
) {
const requestParams =
type === ThreadType.User
? {
objectData: JSON.stringify({
toUid: threadId,
type: 0,
color: -16777216,
emoji: options.emoji ?? "",
startTime: options.startTime ?? Date.now(),
duration: -1,
params: { title: options.title },
needPin: false,
reminderId: options.topicId,
repeat: options.repeat ?? 0,
}),
}
: {
grid: threadId,
type: 0,
color: -16777216,
emoji: options.emoji ?? "",
startTime: options.startTime ?? Date.now(),
duration: -1,
params: JSON.stringify({
title: options.title,
}),
topicId: options.topicId,
repeat: options.repeat ?? 0,
imei: ctx.imei,
pinAct: 2,
};
const encryptedParams = utils.encodeAES(JSON.stringify(requestParams));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL[type], {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+35
View File
@@ -0,0 +1,35 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type EnableGroupLinkResponse = {
link: string;
expiration_date: number;
enabled: number;
};
export const enableGroupLinkFactory = apiFactory<EnableGroupLinkResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/link/new`);
/**
* Enable and create new group link
*
* @param groupId The group id
*
* @throws {ZaloApiError}
*/
return async function enableGroupLink(groupId: string) {
const params = {
grid: groupId,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+17
View File
@@ -0,0 +1,17 @@
import { apiFactory } from "../utils.js";
import type { User } from "../models/index.js";
export type FetchAccountInfoResponse = { profile: User };
export const fetchAccountInfoFactory = apiFactory<FetchAccountInfoResponse>()((api, _, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/profile/me-v2`);
return async function fetchAccountInfo() {
const response = await utils.request(serviceURL, {
method: "GET",
});
return utils.resolve(response);
};
});
+52
View File
@@ -0,0 +1,52 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import { AvatarSize, type UserBasic } from "../models/index.js";
export type FindUserResponse = UserBasic;
export const findUserFactory = apiFactory<FindUserResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.friend[0]}/api/friend/profile/get`);
/**
* Find user by phone number
*
* @param phoneNumber Phone number
* @param avatarSize Avatar size (default: AvatarSize.Large)
*
* @throws {ZaloApiError}
*/
return async function findUser(phoneNumber: string, avatarSize: AvatarSize = AvatarSize.Large) {
if (!phoneNumber) throw new ZaloApiError("Missing phoneNumber");
if (phoneNumber.startsWith("0")) {
if (ctx.language == "vi") phoneNumber = "84" + phoneNumber.slice(1);
}
const params = {
phone: phoneNumber,
avatar_size: avatarSize,
language: ctx.language,
imei: ctx.imei,
reqSrc: 40,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt message");
const finalServiceUrl = new URL(serviceURL);
finalServiceUrl.searchParams.append("params", encryptedParams);
const response = await utils.request(
utils.makeURL(finalServiceUrl.toString(), {
params: encryptedParams,
}),
);
return utils.resolve(response, (result) => {
if (result.error && result.error.code != 216)
throw new ZaloApiError(result.error.message, result.error.code);
return result.data as FindUserResponse;
});
};
});
@@ -0,0 +1,34 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import { AvatarSize, type UserBasic } from "../models/index.js";
export type FindUserByUsernameResponse = UserBasic;
export const findUserByUsernameFactory = apiFactory<FindUserByUsernameResponse>()((api, _ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.friend[0]}/api/friend/search/by-user-name`);
/**
* Find user by username
*
* @param username username for find
* @param avatarSize Avatar size (default: AvatarSize.Large)
*
* @throws {ZaloApiError}
*/
return async function findUserByUsername(username: string, avatarSize: AvatarSize = AvatarSize.Large) {
const params = {
user_name: username,
avatar_size: avatarSize,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+127
View File
@@ -0,0 +1,127 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { ThreadType } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type ForwardMessagePayload = {
message: string;
ttl?: number;
reference?: {
id: string;
ts: number;
logSrcType: number;
fwLvl: number;
};
};
export type ForwardMessageSuccess = {
clientId: string;
msgId: string;
};
export type ForwardMessageFail = {
clientId: string;
error_code: string;
};
export type ForwardMessageResponse = {
success: ForwardMessageSuccess[];
fail: ForwardMessageFail[];
};
export const forwardMessageFactory = apiFactory<ForwardMessageResponse>()((api, ctx, utils) => {
const serviceURL = {
[ThreadType.User]: utils.makeURL(`${api.zpwServiceMap.file[0]}/api/message/mforward`),
[ThreadType.Group]: utils.makeURL(`${api.zpwServiceMap.file[0]}/api/group/mforward`),
};
/**
* Forward message to multiple threads
*
* @param payload Forward message payload
* @param threadId Thread ID(s)
* @param type Thread type (User/Group)
*
* @throws {ZaloApiError}
*/
return async function forwardMessage(
payload: ForwardMessagePayload,
threadIds: string[],
type: ThreadType = ThreadType.User,
) {
if (!payload.message) throw new ZaloApiError("Missing message content");
if (!threadIds || threadIds.length === 0) throw new ZaloApiError("Missing thread IDs");
const timestamp = Date.now();
const clientId = timestamp.toString();
const msgInfo = {
message: payload.message,
reference: payload.reference
? JSON.stringify({
type: 3,
data: JSON.stringify(payload.reference),
})
: undefined,
};
const decorLog = payload.reference
? {
fw: {
pmsg: {
st: 1,
ts: payload.reference.ts,
id: payload.reference.id,
},
rmsg: {
st: 1,
ts: payload.reference.ts,
id: payload.reference.id,
},
fwLvl: payload.reference.fwLvl,
},
}
: null;
let params;
if (type === ThreadType.User) {
params = {
toIds: threadIds.map((threadId) => ({
clientId,
toUid: threadId,
ttl: payload.ttl ?? 0,
})),
imei: ctx.imei,
ttl: payload.ttl ?? 0,
msgType: "1",
totalIds: threadIds.length,
msgInfo: JSON.stringify(msgInfo),
decorLog: JSON.stringify(decorLog),
};
} else {
params = {
grids: threadIds.map((threadId) => ({
clientId,
grid: threadId,
ttl: payload.ttl ?? 0,
})),
ttl: payload.ttl ?? 0,
msgType: "1",
totalIds: threadIds.length,
msgInfo: JSON.stringify(msgInfo),
decorLog: JSON.stringify(decorLog),
};
}
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL[type], {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+39
View File
@@ -0,0 +1,39 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type GetAliasListResponse = {
items: {
userId: string;
alias: string;
}[];
updateTime: string;
};
export const getAliasListFactory = apiFactory<GetAliasListResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.alias[0]}/api/alias/list`);
/**
* Get alias list
*
* @param count Page size (default: 100)
* @param page Page number (default: 1)
*
* @throws {ZaloApiError}
*/
return async function getAliasList(count: number = 100, page: number = 1) {
const params = {
page,
count,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+44
View File
@@ -0,0 +1,44 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import { AvatarSize, type User } from "../models/index.js";
export type GetAllFriendsResponse = User[];
export const getAllFriendsFactory = apiFactory<GetAllFriendsResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/friend/getfriends`);
/**
* Get all friends
*
* @param count Page size (default: 20000)
* @param page Page number (default: 1)
* @param avatarSize Avatar size (default: AvatarSize.Small)
*
* @throws {ZaloApiError}
*/
return async function getAllFriends(count: number = 20000, page: number = 1, avatarSize: AvatarSize = AvatarSize.Small) {
const params = {
incInvalid: 1,
page,
count,
avatar_size: avatarSize,
actiontime: 0,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt message");
const response = await utils.request(
utils.makeURL(serviceURL, {
params: encryptedParams,
}),
{
method: "GET",
},
);
return utils.resolve(response);
};
});
+20
View File
@@ -0,0 +1,20 @@
import { apiFactory } from "../utils.js";
export type GetAllGroupsResponse = {
version: string;
gridVerMap: {
[groupId: string]: string;
};
};
export const getAllGroupsFactory = apiFactory<GetAllGroupsResponse>()((api, _, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group_poll[0]}/api/group/getlg/v4`);
return async function getAllGroups() {
const response = await utils.request(serviceURL, {
method: "GET",
});
return utils.resolve(response);
};
});
@@ -0,0 +1,32 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type GetArchivedChatListResponse = {
items: unknown[]; // @TODO: check type
version: number;
};
export const getArchivedChatListFactory = apiFactory<GetArchivedChatListResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.label[0]}/api/archivedchat/list`);
/**
* Get arcnived chat list
*
* @throws {ZaloApiError}
*/
return async function getArchivedChatList() {
const params = {
version: 1,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
@@ -0,0 +1,34 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type GetAutoDeleteChatResponse = {
convers: {
destId: string;
isGroup: boolean;
ttl: number;
createdAt: number;
}[];
};
export const getAutoDeleteChatFactory = apiFactory<GetAutoDeleteChatResponse>()((api, _ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.conversation[0]}/api/conv/autodelete/getConvers`);
/**
* Get auto delete chat
*
* @throws {ZaloApiError}
*
*/
return async function getAutoDeleteChat() {
const params = {};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+34
View File
@@ -0,0 +1,34 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import type { AutoReplyItem } from "../models/index.js";
export type GetAutoReplyListResponse = {
item: AutoReplyItem[];
version: number;
};
export const getAutoReplyListFactory = apiFactory<GetAutoReplyListResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.auto_reply[0]}/api/autoreply/list`);
/**
* Get auto reply list
*
* @note this API used for zBusiness
* @throws {ZaloApiError}
*/
return async function getAutoReplyList() {
const params = {
version: 0,
cliLang: ctx.language,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+44
View File
@@ -0,0 +1,44 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type GetAvatarListResponse = {
albumId: string;
nextPhotoId: string;
hasMore: number;
photos: {
photoId: string;
thumbnail: string;
url: string;
bkUrl: string;
}[];
};
export const getAvatarListFactory = apiFactory<GetAvatarListResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/avatar-list`);
/**
* Get avatar list
*
* @param count The number of avatars to fetch (default: 50)
* @param page The page number to fetch (default: 1)
*
* @throws {ZaloApiError}
*/
return async function getAvatarList(count: number = 50, page: number = 1) {
const params = {
page,
albumId: "0",
count,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
@@ -0,0 +1,40 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { AvatarSize } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type GetAvatarUrlProfileResponse = {
[userId: string]: {
avatar: string;
};
};
export const getAvatarUrlProfileFactory = apiFactory<GetAvatarUrlProfileResponse>()((api, _ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/profile/avatar-url`);
/**
* Get avatar url profile
*
* @param friendId friend id(s)
* @param avatarSize Avatar size (default: AvatarSize.Large)
*
* @throws {ZaloApiError}
*/
return async function getAvatarUrlProfile(friendIds: string | string[], avatarSize: AvatarSize = AvatarSize.Large) {
if (!Array.isArray(friendIds)) friendIds = [friendIds];
const params = {
friend_ids: friendIds,
avatar_size: avatarSize,
srcReq: -1,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+55
View File
@@ -0,0 +1,55 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { BusinessCategory } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type GetBizAccountResponse = {
biz?: {
desc: string | null;
cate: BusinessCategory;
addr: string;
website: string;
email: string;
};
setting_start_page?: {
enable_biz_label: number;
enable_cate: number;
enable_add: number;
cta_profile: number;
/**
* Relative path used to build the catalog URL.
*
* Example: https://catalog.zalo.me/${cta_catalog}
*/
cta_catalog: string | null;
} | null;
pkgId: number;
};
export const getBizAccountFactory = apiFactory<GetBizAccountResponse>()((api, _ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/friend/get-bizacc`);
/**
* Get biz account
*
* @param friendId The friend ID to get biz account
*
* @throws {ZaloApiError}
*/
return async function getBizAccount(friendId: string) {
const params = {
fid: friendId,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+55
View File
@@ -0,0 +1,55 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import type { CatalogItem } from "../models/index.js";
export type GetCatalogListPayload = {
/**
* Number of items to retrieve (default: 20)
*/
limit?: number;
lastProductId?: number;
/**
* Page number (default: 0)
*/
page?: number;
};
export type GetCatalogListResponse = {
items: CatalogItem[];
version: number;
has_more: number;
};
export const getCatalogListFactory = apiFactory<GetCatalogListResponse>()((api, _, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.catalog[0]}/api/prodcatalog/catalog/list`);
/**
* Get catalog list?
*
* @param payload payload
*
* @note this API is used for zBusiness
* @throws {ZaloApiError}
*/
return async function getCatalogList(payload?: GetCatalogListPayload) {
const params = {
version_list_catalog: 0,
limit: payload?.limit ?? 20,
last_product_id: payload?.lastProductId ?? -1,
page: payload?.page ?? 0,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
+27
View File
@@ -0,0 +1,27 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { User } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type GetCloseFriendsResponse = User[];
export const getCloseFriendsFactory = apiFactory<GetCloseFriendsResponse>()((api, _ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/friend/getclosedfriends`);
/**
* Get close friends
*
* @throws {ZaloApiError}
*/
return async function getCloseFriends() {
const params = {};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+5
View File
@@ -0,0 +1,5 @@
import { apiFactory } from "../utils.js";
export const getContextFactory = apiFactory()((_, ctx) => {
return () => ctx;
});
+10
View File
@@ -0,0 +1,10 @@
import { apiFactory } from "../utils.js";
export const getCookieFactory = apiFactory()((_, ctx) => {
/**
* Get the current cookie string
*/
return function getCookie() {
return ctx.cookie;
};
});
@@ -0,0 +1,35 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type GetFriendBoardListResponse = {
data: string[];
version: number;
};
export const getFriendBoardListFactory = apiFactory<GetFriendBoardListResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.friend_board[0]}/api/friendboard/list`);
/**
* Get friend board list
*
* @param conversationId conversation id
*
* @throws {ZaloApiError}
*/
return async function getFriendBoardList(conversationId: string) {
const params = {
conversationId: conversationId,
version: 0,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+53
View File
@@ -0,0 +1,53 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type GetFriendOnlinesStatus = {
userId: string;
status: string;
};
export type GetFriendOnlinesResponse = {
predefine: string[];
ownerStatus: string;
onlines: GetFriendOnlinesStatus[];
};
export const getFriendOnlinesFactory = apiFactory<GetFriendOnlinesResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/friend/onlines`);
/**
* Get friend onlines?
*
* @throws {ZaloApiError}
*/
return async function getFriendOnlines() {
const params = {
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response, (result) => {
const data = result.data as GetFriendOnlinesResponse;
if (Array.isArray(data.onlines)) {
for (const online of data.onlines) {
if (typeof online.status === "string") {
const parsed = JSON.parse(online.status);
if (parsed && typeof (parsed as { status?: unknown }).status === "string") {
online.status = (parsed as { status: string }).status;
}
}
}
}
return data as GetFriendOnlinesResponse;
});
};
});
@@ -0,0 +1,72 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { Gender, ZBusinessPackage } from "../models/index.js";
import { apiFactory } from "../utils.js";
export enum FriendRecommendationsType {
RecommendedFriend = 1,
ReceivedFriendRequest = 2,
}
export type FriendRecommendationsCollapseMsgListConfig = {
collapseId: number;
collapseXItem: number;
collapseYItem: number;
};
export type FriendRecommendationsDataInfo = {
userId: string;
zaloName: string;
displayName: string;
avatar: string;
phoneNumber: string;
status: string;
gender: Gender;
dob: number;
type: number;
recommType: FriendRecommendationsType;
recommSrc: number;
recommTime: number;
recommInfo: {
suggestWay: number;
source: number;
message: string;
customText: string | null;
};
bizPkg: ZBusinessPackage;
isSeenFriendReq: boolean;
};
export type FriendRecommendationsRecommItem = {
recommItemType: number;
dataInfo: FriendRecommendationsDataInfo;
};
export type GetFriendRecommendationsResponse = {
expiredDuration: number;
collapseMsgListConfig: FriendRecommendationsCollapseMsgListConfig;
recommItems: FriendRecommendationsRecommItem[];
};
export const getFriendRecommendationsFactory = apiFactory<GetFriendRecommendationsResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.friend[0]}/api/friend/recommendsv2/list`);
/**
* Get friend recommendations/received friend requests
*
* @throws {ZaloApiError}
*/
return async function getFriendRecommendations() {
const params = {
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
@@ -0,0 +1,37 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type GetFriendRequestStatusResponse = {
addFriendPrivacy: number;
isSeenFriendReq: boolean;
is_friend: number;
is_requested: number;
is_requesting: number;
};
export const getFriendRequestStatusFactory = apiFactory<GetFriendRequestStatusResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.friend[0]}/api/friend/reqstatus`);
/**
* Get friend request status
*
* @param friendId friend id
*
* @throws {ZaloApiError}
*/
return async function getFriendRequestStatus(friendId: string) {
const params = {
fid: friendId,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
+34
View File
@@ -0,0 +1,34 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type GetFullAvatarResponse = {
bk_full_avatar: string;
full_avatar: string;
};
export const getFullAvatarFactory = apiFactory<GetFullAvatarResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/profile/avatar`);
/**
* Get full avatar
*
* @param friendId friend id
*
* @throws {ZaloApiError}
*/
return async function getFullAvatar(friendId: string) {
const params = {
fid: friendId,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
@@ -0,0 +1,56 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
export type GetGroupBlockedMemberPayload = {
/**
* Page number (default: 1)
*/
page?: number;
/**
* Number of items to retrieve (default: 50)
*/
count?: number;
};
export type GetGroupBlockedMemberResponse = {
blocked_members: {
id: string;
dName: string;
zaloName: string;
avatar: string;
avatar_25: string;
accountStatus: number;
type: number;
}[];
has_more: number;
};
export const getGroupBlockedMemberFactory = apiFactory<GetGroupBlockedMemberResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/blockedmems/list`);
/**
* Get group blocked member
*
* @param payload payload
* @param groupId group id
*
* @throws {ZaloApiError}
*/
return async function getGroupBlockedMember(payload: GetGroupBlockedMemberPayload, groupId: string) {
const params = {
grid: groupId,
page: payload.page ?? 1,
count: payload.count ?? 50,
imei: ctx.imei,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response);
};
});
@@ -0,0 +1,51 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import { GroupMessage, type TGroupMessage } from "../models/index.js";
export type GetGroupChatHistoryResponse = {
lastActionId: string;
lastActionIdOther: string;
more: number;
groupMsgs: GroupMessage[];
};
export const getGroupChatHistoryFactory = apiFactory<GetGroupChatHistoryResponse>()((api, ctx, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/history`);
/**
* Get group chat history
*
* @param groupId group id
* @param count count of messages to return (default: 50)
*
* @throws {ZaloApiError}
*/
return async function getGroupChatHistory(groupId: string, count: number = 50) {
const params = {
grid: groupId,
count: count,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response, (result) => {
let data = result.data as unknown as GetGroupChatHistoryResponse | string;
if (typeof data === "string") {
data = JSON.parse(data) as GetGroupChatHistoryResponse;
}
for (let i = 0; i < data.groupMsgs.length; i++) {
data.groupMsgs[i] = new GroupMessage(ctx.uid, data.groupMsgs[i] as unknown as TGroupMessage);
}
return data;
});
};
});
+55
View File
@@ -0,0 +1,55 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import type { GroupInfo } from "../models/index.js";
import { apiFactory } from "../utils.js";
export type GroupInfoResponse = {
removedsGroup: string[];
unchangedsGroup: string[];
gridInfoMap: {
[groupId: string]: GroupInfo & {
memVerList: string[];
pendingApprove: GroupInfoPendingApprove;
};
};
};
export type GroupInfoPendingApprove = {
time: number;
uids: string[] | null;
};
export const getGroupInfoFactory = apiFactory<GroupInfoResponse>()((api, _, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/getmg-v2`);
/**
* Get group information
*
* @param groupId Group ID or list of group IDs
*
* @throws {ZaloApiError}
*/
return async function getGroupInfo(groupId: string | string[]) {
if (!Array.isArray(groupId)) groupId = [groupId];
const params = {
gridVerMap: JSON.stringify(
groupId.reduce<Record<string, number>>((acc, id) => {
acc[id] = 0;
return acc;
}, {}),
),
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt message");
const response = await utils.request(serviceURL, {
method: "POST",
body: new URLSearchParams({
params: encryptedParams,
}),
});
return utils.resolve(response);
};
});
@@ -0,0 +1,79 @@
import { ZaloApiError } from "../Errors/ZaloApiError.js";
import { apiFactory } from "../utils.js";
import type { GroupInfo, GroupTopic } from "../models/index.js";
export type GetGroupInviteBoxInfoPayload = {
groupId: string;
mpage?: number;
mcount?: number;
};
export type GetGroupInviteBoxInfoResponse = {
groupInfo: GroupInfo & {
topic?: Omit<GroupTopic, "action">;
};
inviterInfo: {
id: string;
dName: string;
zaloName: string;
avatar: string;
avatar_25: string;
accountStatus: number;
type: number;
};
grCreatorInfo: {
id: string;
dName: string;
zaloName: string;
avatar: string;
avatar_25: string;
accountStatus: number;
type: number;
};
expiredTs: string;
type: number;
};
export const getGroupInviteBoxInfoFactory = apiFactory<GetGroupInviteBoxInfoResponse>()((api, _, utils) => {
const serviceURL = utils.makeURL(`${api.zpwServiceMap.group[0]}/api/group/inv-box/inv-info`);
/**
* Get group invite box info
*
* @param payload - The payload of the request
*
* @throws {ZaloApiError}
*/
return async function getGroupInviteBoxInfo(payload: GetGroupInviteBoxInfoPayload) {
const params = {
grId: payload.groupId,
mcount: payload.mcount ?? 10,
mpage: payload.mpage ?? 1,
};
const encryptedParams = utils.encodeAES(JSON.stringify(params));
if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params");
const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
method: "GET",
});
return utils.resolve(response, (result) => {
const data = result.data as GetGroupInviteBoxInfoResponse;
const topic = data.groupInfo.topic as GetGroupInviteBoxInfoResponse["groupInfo"]["topic"] & {
params: unknown;
};
if (typeof topic.params == "string") {
const params = JSON.parse(topic.params);
if (typeof params.extra == "string") {
params.extra = JSON.parse(params.extra);
}
topic.params = params;
}
return data as GetGroupInviteBoxInfoResponse;
});
};
});

Some files were not shown because too many files have changed in this diff Show More