@lizzythelizard/whatsapp-mcp 0.1.3 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +1 -0
- package/dist/auth.js.map +1 -1
- package/dist/index.js +36 -9
- package/dist/index.js.map +1 -1
- package/dist/store.d.ts +23 -9
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +16 -10
- package/dist/store.js.map +1 -1
- package/dist/sync.d.ts +6 -2
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +61 -2
- package/dist/sync.js.map +1 -1
- package/dist/tools/chatTools.d.ts +5 -0
- package/dist/tools/chatTools.d.ts.map +1 -0
- package/dist/tools/chatTools.js +34 -0
- package/dist/tools/chatTools.js.map +1 -0
- package/dist/tools/common.d.ts +49 -0
- package/dist/tools/common.d.ts.map +1 -0
- package/dist/tools/common.js +18 -0
- package/dist/tools/common.js.map +1 -0
- package/dist/tools/contactTools.d.ts +4 -0
- package/dist/tools/contactTools.d.ts.map +1 -0
- package/dist/tools/contactTools.js +5 -0
- package/dist/tools/contactTools.js.map +1 -0
- package/dist/tools/messageTools.d.ts +5 -0
- package/dist/tools/messageTools.d.ts.map +1 -0
- package/dist/tools/messageTools.js +21 -0
- package/dist/tools/messageTools.js.map +1 -0
- package/package.json +16 -1
- package/.github/dependabot.yml +0 -20
- package/.github/workflows/auto-merge.yml +0 -19
- package/.github/workflows/ci.yml +0 -75
- package/.vscode/extensions.json +0 -7
- package/.vscode/settings.json +0 -12
- package/AGENTS.md +0 -42
- package/Dockerfile +0 -25
- package/eslint.config.mjs +0 -32
- package/src/auth.test.ts +0 -138
- package/src/auth.ts +0 -58
- package/src/index.ts +0 -45
- package/src/store.test.ts +0 -353
- package/src/store.ts +0 -182
- package/src/sync.test.ts +0 -304
- package/src/sync.ts +0 -170
- package/src/tools.test.ts +0 -254
- package/src/tools.ts +0 -132
- package/tsconfig.json +0 -19
- package/tsconfig.test.json +0 -7
- package/vitest.config.ts +0 -7
package/.github/dependabot.yml
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
version: 2
|
|
2
|
-
updates:
|
|
3
|
-
- package-ecosystem: "npm"
|
|
4
|
-
directory: "/"
|
|
5
|
-
schedule:
|
|
6
|
-
interval: "weekly"
|
|
7
|
-
day: "monday"
|
|
8
|
-
open-pull-requests-limit: 10
|
|
9
|
-
|
|
10
|
-
- package-ecosystem: "docker"
|
|
11
|
-
directory: "/"
|
|
12
|
-
schedule:
|
|
13
|
-
interval: "weekly"
|
|
14
|
-
day: "monday"
|
|
15
|
-
|
|
16
|
-
- package-ecosystem: "github-actions"
|
|
17
|
-
directory: "/"
|
|
18
|
-
schedule:
|
|
19
|
-
interval: "weekly"
|
|
20
|
-
day: "monday"
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
name: Dependabot Auto-Merge
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request_target:
|
|
5
|
-
|
|
6
|
-
permissions:
|
|
7
|
-
contents: write
|
|
8
|
-
pull-requests: write
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
auto-merge:
|
|
12
|
-
if: github.actor == 'dependabot[bot]'
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- name: Auto-merge Dependabot PRs
|
|
16
|
-
run: gh pr merge --auto --merge "$PR_URL"
|
|
17
|
-
env:
|
|
18
|
-
PR_URL: ${{ github.event.pull_request.html_url }}
|
|
19
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches: [main]
|
|
6
|
-
push:
|
|
7
|
-
branches: [main]
|
|
8
|
-
|
|
9
|
-
env:
|
|
10
|
-
DOCKER_IMAGE: ${{ secrets.DOCKER_USERNAME }}/whatsapp-mcp
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
checks:
|
|
14
|
-
runs-on: ubuntu-latest
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v7
|
|
17
|
-
- uses: actions/setup-node@v6
|
|
18
|
-
with:
|
|
19
|
-
node-version: 24
|
|
20
|
-
cache: npm
|
|
21
|
-
- run: npm ci
|
|
22
|
-
- run: npm run build
|
|
23
|
-
- run: npm run lint
|
|
24
|
-
- run: npm run typecheck
|
|
25
|
-
- run: npm test
|
|
26
|
-
- name: Check version can be published
|
|
27
|
-
run: npm publish --dry-run
|
|
28
|
-
|
|
29
|
-
docker:
|
|
30
|
-
runs-on: ubuntu-latest
|
|
31
|
-
needs: [checks]
|
|
32
|
-
permissions:
|
|
33
|
-
contents: read
|
|
34
|
-
packages: write
|
|
35
|
-
steps:
|
|
36
|
-
- uses: actions/checkout@v7
|
|
37
|
-
- uses: docker/setup-buildx-action@v4
|
|
38
|
-
- name: Log in to Docker Hub
|
|
39
|
-
if: github.ref == 'refs/heads/main'
|
|
40
|
-
uses: docker/login-action@v4
|
|
41
|
-
with:
|
|
42
|
-
username: ${{ secrets.DOCKER_USERNAME }}
|
|
43
|
-
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
44
|
-
- name: Extract metadata
|
|
45
|
-
id: meta
|
|
46
|
-
uses: docker/metadata-action@v6
|
|
47
|
-
with:
|
|
48
|
-
images: ${{ env.DOCKER_IMAGE }}
|
|
49
|
-
tags: |
|
|
50
|
-
type=sha,prefix=
|
|
51
|
-
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
|
52
|
-
- name: Build and push
|
|
53
|
-
uses: docker/build-push-action@v7
|
|
54
|
-
with:
|
|
55
|
-
context: .
|
|
56
|
-
push: ${{ github.ref == 'refs/heads/main' }}
|
|
57
|
-
tags: ${{ steps.meta.outputs.tags }}
|
|
58
|
-
labels: ${{ steps.meta.outputs.labels }}
|
|
59
|
-
cache-from: type=gha
|
|
60
|
-
cache-to: type=gha,mode=max
|
|
61
|
-
|
|
62
|
-
npm-publish:
|
|
63
|
-
runs-on: ubuntu-latest
|
|
64
|
-
needs: [checks]
|
|
65
|
-
if: github.ref == 'refs/heads/main'
|
|
66
|
-
steps:
|
|
67
|
-
- uses: actions/checkout@v7
|
|
68
|
-
- uses: actions/setup-node@v6
|
|
69
|
-
with:
|
|
70
|
-
node-version: 24
|
|
71
|
-
cache: npm
|
|
72
|
-
registry-url: "https://registry.npmjs.org"
|
|
73
|
-
- run: npm ci
|
|
74
|
-
- run: npm run build
|
|
75
|
-
- run: npm publish
|
package/.vscode/extensions.json
DELETED
package/.vscode/settings.json
DELETED
package/AGENTS.md
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# AGENTS.md
|
|
2
|
-
|
|
3
|
-
This file helps AI agents understand how to work with this project.
|
|
4
|
-
|
|
5
|
-
## Project Overview
|
|
6
|
-
|
|
7
|
-
A WhatsApp MCP (Model Context Protocol) server that exposes WhatsApp functionality as tools for AI assistants.
|
|
8
|
-
|
|
9
|
-
## Key Conventions
|
|
10
|
-
|
|
11
|
-
- TypeScript with ESM (`"type": "module"`)
|
|
12
|
-
- Source code lives in `src/`, tests in `tests/`
|
|
13
|
-
- Use `zod` for input validation
|
|
14
|
-
- Follow existing tool patterns when adding new tools
|
|
15
|
-
|
|
16
|
-
## Common Commands
|
|
17
|
-
|
|
18
|
-
- `npm run dev` — start dev server with auto-reload
|
|
19
|
-
- `npm test` — run test suite
|
|
20
|
-
- `npm run build` — compile to JavaScript
|
|
21
|
-
- `npm run lint` — check code quality
|
|
22
|
-
- `npm run typecheck` — run TypeScript type checking
|
|
23
|
-
|
|
24
|
-
## Architecture
|
|
25
|
-
|
|
26
|
-
The MCP server uses `@modelcontextprotocol/sdk` with stdio transport. Tools are registered in `src/index.ts` via `server.setRequestHandler`. Each tool has:
|
|
27
|
-
|
|
28
|
-
1. A `zod` schema for input validation
|
|
29
|
-
2. A definition in `ListToolsRequestSchema`
|
|
30
|
-
3. A handler in `CallToolRequestSchema`
|
|
31
|
-
|
|
32
|
-
## Adding a New Tool
|
|
33
|
-
|
|
34
|
-
1. Define a Zod schema for the tool's input
|
|
35
|
-
2. Add the tool definition to `ListToolsRequestSchema`
|
|
36
|
-
3. Add a case to the switch in `CallToolRequestSchema`
|
|
37
|
-
|
|
38
|
-
## Testing
|
|
39
|
-
|
|
40
|
-
- Write tests in `tests/` matching the source structure
|
|
41
|
-
- Use `vitest` with `describe`/`it`/`expect`
|
|
42
|
-
- Test input schemas and handler logic separately
|
package/Dockerfile
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
FROM node:26-alpine AS build
|
|
2
|
-
|
|
3
|
-
WORKDIR /app
|
|
4
|
-
|
|
5
|
-
COPY package*.json ./
|
|
6
|
-
RUN npm ci
|
|
7
|
-
|
|
8
|
-
COPY tsconfig.json ./
|
|
9
|
-
COPY src/ ./src/
|
|
10
|
-
RUN npm run build
|
|
11
|
-
|
|
12
|
-
FROM node:26-alpine AS production
|
|
13
|
-
|
|
14
|
-
WORKDIR /app
|
|
15
|
-
|
|
16
|
-
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
|
17
|
-
|
|
18
|
-
COPY package*.json ./
|
|
19
|
-
RUN npm ci --omit=dev
|
|
20
|
-
|
|
21
|
-
COPY --from=build /app/dist ./dist
|
|
22
|
-
|
|
23
|
-
USER appuser
|
|
24
|
-
|
|
25
|
-
CMD ["node", "dist/index.js"]
|
package/eslint.config.mjs
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import eslint from '@eslint/js'
|
|
2
|
-
import tseslint from 'typescript-eslint'
|
|
3
|
-
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
4
|
-
import stylistic from '@stylistic/eslint-plugin'
|
|
5
|
-
|
|
6
|
-
export default defineConfig([
|
|
7
|
-
eslint.configs.recommended,
|
|
8
|
-
tseslint.configs.recommendedTypeChecked,
|
|
9
|
-
tseslint.configs.strictTypeChecked,
|
|
10
|
-
tseslint.configs.stylisticTypeChecked,
|
|
11
|
-
stylistic.configs.recommended,
|
|
12
|
-
globalIgnores(['node_modules/**', 'dist/**']),
|
|
13
|
-
{
|
|
14
|
-
languageOptions: {
|
|
15
|
-
parserOptions: {
|
|
16
|
-
tsconfigRootDir: import.meta.dirname,
|
|
17
|
-
projectService: {
|
|
18
|
-
allowDefaultProject: ['src/*.test.ts'],
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
rules: {
|
|
23
|
-
'@typescript-eslint/no-extraneous-class': ['off'],
|
|
24
|
-
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
|
25
|
-
'@stylistic/max-statements-per-line': ['error', { max: 2 }],
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
files: ['**/*.js', '**/*.cjs', '**/*.mjs'],
|
|
30
|
-
extends: [tseslint.configs.disableTypeChecked],
|
|
31
|
-
},
|
|
32
|
-
])
|
package/src/auth.test.ts
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { createExportableAuth } from './auth.js'
|
|
3
|
-
|
|
4
|
-
describe('createExportableAuth', () => {
|
|
5
|
-
it('returns fresh auth with initAuthCreds when called without argument', () => {
|
|
6
|
-
const auth = createExportableAuth()
|
|
7
|
-
expect(auth.creds).toBeDefined()
|
|
8
|
-
expect(auth.keys).toBeDefined()
|
|
9
|
-
expect(typeof auth.toAuthState).toBe('function')
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
it('restores creds and keys from a JSON string', () => {
|
|
13
|
-
const original = createExportableAuth()
|
|
14
|
-
const json = original.toAuthState()
|
|
15
|
-
const restored = createExportableAuth(json)
|
|
16
|
-
expect(restored.creds.registrationId).toBe(original.creds.registrationId)
|
|
17
|
-
expect(restored.creds.noiseKey.public).toEqual(original.creds.noiseKey.public)
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('roundtrips through toAuthState and back', async () => {
|
|
21
|
-
const auth = createExportableAuth()
|
|
22
|
-
await auth.keys.set({ 'sender-key': { 'test@test:1': new Uint8Array([1, 2, 3]) } })
|
|
23
|
-
const json = auth.toAuthState()
|
|
24
|
-
const imported = createExportableAuth(json)
|
|
25
|
-
const retrieved = await imported.keys.get('sender-key', ['test@test:1'])
|
|
26
|
-
expect(retrieved['test@test:1']).toBeDefined()
|
|
27
|
-
expect(new Uint8Array(retrieved['test@test:1'])).toEqual(new Uint8Array([1, 2, 3]))
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
it('preserves Uint8Array values through export and import', async () => {
|
|
31
|
-
const auth = createExportableAuth()
|
|
32
|
-
const original = new Uint8Array([255, 254, 253])
|
|
33
|
-
await auth.keys.set({ 'sender-key': { 'test-id': original } })
|
|
34
|
-
const json = auth.toAuthState()
|
|
35
|
-
const imported = createExportableAuth(json)
|
|
36
|
-
const retrieved = await imported.keys.get('sender-key', ['test-id'])
|
|
37
|
-
expect(new Uint8Array(retrieved['test-id'])).toEqual(original)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('handles undefined input and returns fresh auth', () => {
|
|
41
|
-
const auth = createExportableAuth(undefined)
|
|
42
|
-
expect(auth.creds).toBeDefined()
|
|
43
|
-
expect(auth.creds.registrationId).toBeGreaterThan(0)
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
it('throws on invalid JSON string', () => {
|
|
47
|
-
expect(() => createExportableAuth('not valid json')).toThrow()
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('handles empty JSON object (no creds)', () => {
|
|
51
|
-
const auth = createExportableAuth('{}')
|
|
52
|
-
expect(typeof auth.toAuthState).toBe('function')
|
|
53
|
-
expect(auth.toAuthState()).toBe('{}')
|
|
54
|
-
})
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
describe('keys store (set/get)', () => {
|
|
58
|
-
it('stores and retrieves session values', async () => {
|
|
59
|
-
const auth = createExportableAuth()
|
|
60
|
-
const value = new Uint8Array([10, 20, 30])
|
|
61
|
-
await auth.keys.set({ session: { 'session-id': value } })
|
|
62
|
-
const result = await auth.keys.get('session', ['session-id'])
|
|
63
|
-
expect(result['session-id']).toBeDefined()
|
|
64
|
-
expect(new Uint8Array(result['session-id'])).toEqual(value)
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('stores and retrieves string values (lid-mapping)', async () => {
|
|
68
|
-
const auth = createExportableAuth()
|
|
69
|
-
await auth.keys.set({ 'lid-mapping': { test: 'mapped-value' } })
|
|
70
|
-
const result = await auth.keys.get('lid-mapping', ['test'])
|
|
71
|
-
expect(result.test).toBe('mapped-value')
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('stores and retrieves string array values (device-list)', async () => {
|
|
75
|
-
const auth = createExportableAuth()
|
|
76
|
-
await auth.keys.set({ 'device-list': { test: ['dev1', 'dev2'] } })
|
|
77
|
-
const result = await auth.keys.get('device-list', ['test'])
|
|
78
|
-
expect(result.test).toEqual(['dev1', 'dev2'])
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
it('returns empty object for missing keys', async () => {
|
|
82
|
-
const auth = createExportableAuth()
|
|
83
|
-
const result = await auth.keys.get('session', ['nonexistent'])
|
|
84
|
-
expect(result).toEqual({})
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
it('overwrites existing values on successive sets', async () => {
|
|
88
|
-
const auth = createExportableAuth()
|
|
89
|
-
await auth.keys.set({ session: { s1: new Uint8Array([1]) } })
|
|
90
|
-
await auth.keys.set({ session: { s1: new Uint8Array([2]) } })
|
|
91
|
-
const result = await auth.keys.get('session', ['s1'])
|
|
92
|
-
expect(new Uint8Array(result.s1)).toEqual(new Uint8Array([2]))
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
it('deletes key when value is set to null', async () => {
|
|
96
|
-
const auth = createExportableAuth()
|
|
97
|
-
await auth.keys.set({ session: { s1: new Uint8Array([1]) } })
|
|
98
|
-
await auth.keys.set({ session: { s1: null } })
|
|
99
|
-
const result = await auth.keys.get('session', ['s1'])
|
|
100
|
-
expect(result).toEqual({})
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
it('retrieves multiple ids in a single get call', async () => {
|
|
104
|
-
const auth = createExportableAuth()
|
|
105
|
-
await auth.keys.set({ 'lid-mapping': { id1: 'val1', id2: 'val2' } })
|
|
106
|
-
const result = await auth.keys.get('lid-mapping', ['id1', 'id2'])
|
|
107
|
-
expect(result.id1).toBe('val1')
|
|
108
|
-
expect(result.id2).toBe('val2')
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
it('handles app-state-sync-key with correct protobuf conversion', async () => {
|
|
112
|
-
const auth = createExportableAuth()
|
|
113
|
-
const keyData = {
|
|
114
|
-
keyData: new Uint8Array([1, 2, 3]),
|
|
115
|
-
timestamp: 1234567890,
|
|
116
|
-
}
|
|
117
|
-
await auth.keys.set({ 'app-state-sync-key': { key1: keyData } })
|
|
118
|
-
const result = await auth.keys.get('app-state-sync-key', ['key1'])
|
|
119
|
-
expect(result.key1).toBeDefined()
|
|
120
|
-
expect(result.key1.keyData).toBeDefined()
|
|
121
|
-
expect(Number(result.key1.timestamp)).toBe(1234567890)
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('stores and retrieves sender-key-memory (boolean map)', async () => {
|
|
125
|
-
const auth = createExportableAuth()
|
|
126
|
-
await auth.keys.set({ 'sender-key-memory': { jid1: { user1: true } } })
|
|
127
|
-
const result = await auth.keys.get('sender-key-memory', ['jid1'])
|
|
128
|
-
expect(result.jid1.user1).toBe(true)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
it('stores and retrieves tctoken', async () => {
|
|
132
|
-
const auth = createExportableAuth()
|
|
133
|
-
await auth.keys.set({ tctoken: { default: { token: Buffer.from('token-data'), timestamp: '123' } } })
|
|
134
|
-
const result = await auth.keys.get('tctoken', ['default'])
|
|
135
|
-
expect(result.default.token).toBeDefined()
|
|
136
|
-
expect(result.default.timestamp).toBe('123')
|
|
137
|
-
})
|
|
138
|
-
})
|
package/src/auth.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { AuthenticationCreds, BufferJSON, initAuthCreds, SignalDataTypeMap, proto, SignalDataSet, AuthenticationState } from '@whiskeysockets/baileys'
|
|
2
|
-
|
|
3
|
-
export interface ExportableAuthState extends AuthenticationState {
|
|
4
|
-
toAuthState: () => string
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
interface AuthStateInput { creds: AuthenticationCreds, keys: Record<string, string> }
|
|
8
|
-
|
|
9
|
-
export function createExportableAuth(input?: string): ExportableAuthState {
|
|
10
|
-
const { creds, keys } = fromString<AuthStateInput>(input) ?? { creds: initAuthCreds(), keys: {} }
|
|
11
|
-
return {
|
|
12
|
-
creds,
|
|
13
|
-
keys: { get: (t, ids) => getKey(t, ids, keys), set: (data) => { setKey(data, keys) } },
|
|
14
|
-
toAuthState: () => toString({ creds, keys }),
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|
|
19
|
-
function fromString<T>(str: string | undefined): T | undefined {
|
|
20
|
-
if (!str) return undefined
|
|
21
|
-
return JSON.parse(str, BufferJSON.reviver) as T
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function toString(data: unknown): string {
|
|
25
|
-
return JSON.stringify(data, BufferJSON.replacer)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function getKey<T extends keyof SignalDataTypeMap>(type: T, ids: string[], keys: Record<string, string>): Record<string, SignalDataTypeMap[T]> {
|
|
29
|
-
return ids.reduce<Record<string, SignalDataTypeMap[T]>>((acc, id) => {
|
|
30
|
-
const value = fromString<SignalDataTypeMap[T]>(keys[`${type}-${id}`])
|
|
31
|
-
if (!value) return acc
|
|
32
|
-
if (type === 'app-state-sync-key') {
|
|
33
|
-
const typedValue = value as SignalDataTypeMap['app-state-sync-key']
|
|
34
|
-
const converted = proto.Message.AppStateSyncKeyData.fromObject(typedValue)
|
|
35
|
-
const typeResult = converted as unknown as SignalDataTypeMap[T]
|
|
36
|
-
acc[id] = typeResult
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
acc[id] = value
|
|
40
|
-
}
|
|
41
|
-
return acc
|
|
42
|
-
}, {})
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function setKey(data: SignalDataSet, keys: Record<string, string>): void {
|
|
46
|
-
for (const category in data) {
|
|
47
|
-
const dataCategory = data[category as keyof SignalDataTypeMap]
|
|
48
|
-
for (const id in dataCategory) {
|
|
49
|
-
const value = dataCategory[id]
|
|
50
|
-
if (!value)
|
|
51
|
-
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
52
|
-
delete keys[`${category}-${id}`]
|
|
53
|
-
else {
|
|
54
|
-
keys[`${category}-${id}`] = JSON.stringify(value, BufferJSON.replacer)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
4
|
-
import pkg from '../package.json' with { type: 'json' }
|
|
5
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
6
|
-
import { createStore, DataStore } from './store.js'
|
|
7
|
-
import { createHandler } from './sync.js'
|
|
8
|
-
import { promises as fsp } from 'fs'
|
|
9
|
-
import { registerWhatsAppTools } from './tools.js'
|
|
10
|
-
|
|
11
|
-
const dataDir = process.env.DATA_DIR ?? './data'
|
|
12
|
-
|
|
13
|
-
async function readDataFromFile(): Promise<DataStore | undefined> {
|
|
14
|
-
const canAccess = await fsp.access(dataDir).then(() => true).catch(() => false)
|
|
15
|
-
if (!canAccess) return undefined
|
|
16
|
-
const chats = await fsp.readFile(`${dataDir}/chats.json`, 'utf-8')
|
|
17
|
-
const messages = await fsp.readFile(`${dataDir}/messages.json`, 'utf-8')
|
|
18
|
-
const contacts = await fsp.readFile(`${dataDir}/contacts.json`, 'utf-8')
|
|
19
|
-
const auth = await fsp.readFile(`${dataDir}/auth.json`, 'utf-8')
|
|
20
|
-
return { chats, messages, contacts, auth }
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async function writeDataToFile(data: DataStore): Promise<void> {
|
|
24
|
-
await fsp.mkdir(dataDir, { recursive: true })
|
|
25
|
-
await fsp.writeFile(`${dataDir}/chats.json`, data.chats, 'utf-8')
|
|
26
|
-
await fsp.writeFile(`${dataDir}/messages.json`, data.messages, 'utf-8')
|
|
27
|
-
await fsp.writeFile(`${dataDir}/contacts.json`, data.contacts, 'utf-8')
|
|
28
|
-
await fsp.writeFile(`${dataDir}/auth.json`, data.auth, 'utf-8')
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async function main() {
|
|
32
|
-
const server = new McpServer({ name: pkg.name, version: pkg.version })
|
|
33
|
-
const transport = new StdioServerTransport()
|
|
34
|
-
const inputData = await readDataFromFile()
|
|
35
|
-
const whatsappStore = createStore(writeDataToFile, inputData)
|
|
36
|
-
const whatsappSync = createHandler(whatsappStore)
|
|
37
|
-
registerWhatsAppTools(server, whatsappStore, whatsappSync)
|
|
38
|
-
await server.connect(transport)
|
|
39
|
-
console.info('whatsapp-mcp server running on stdio')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
main().catch((error: unknown) => {
|
|
43
|
-
console.error('Server error:', error)
|
|
44
|
-
process.exit(1)
|
|
45
|
-
})
|