@2bad/bitrix 2.5.1 → 3.0.0
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/README.md +94 -188
- package/build/bin.d.ts +1 -0
- package/build/bin.js +160 -0
- package/build/client-Bk76ySik.js +769 -0
- package/build/index.d.ts +2881 -0
- package/build/index.js +1 -0
- package/package.json +46 -73
- package/build/main/bitrix.d.ts +0 -114
- package/build/main/bitrix.integration.test.d.ts +0 -0
- package/build/main/bitrix.integration.test.js +0 -31
- package/build/main/bitrix.js +0 -61
- package/build/main/bitrix.unit.test.d.ts +0 -1
- package/build/main/bitrix.unit.test.js +0 -44
- package/build/main/client/client.unit.test.d.ts +0 -1
- package/build/main/client/client.unit.test.js +0 -70
- package/build/main/client/hooks/addAccessToken.d.ts +0 -6
- package/build/main/client/hooks/addAccessToken.js +0 -13
- package/build/main/client/hooks/addAccessToken.unit.test.d.ts +0 -1
- package/build/main/client/hooks/addAccessToken.unit.test.js +0 -31
- package/build/main/client/index.d.ts +0 -15
- package/build/main/client/index.js +0 -53
- package/build/main/client/methods/batch.d.ts +0 -40
- package/build/main/client/methods/batch.js +0 -85
- package/build/main/client/methods/batch.unit.test.d.ts +0 -1
- package/build/main/client/methods/batch.unit.test.js +0 -494
- package/build/main/client/methods/call.d.ts +0 -17
- package/build/main/client/methods/call.js +0 -36
- package/build/main/client/methods/call.unit.test.d.ts +0 -1
- package/build/main/client/methods/call.unit.test.js +0 -183
- package/build/main/client/methods/list.d.ts +0 -30
- package/build/main/client/methods/list.js +0 -66
- package/build/main/client/methods/list.unit.test.d.ts +0 -1
- package/build/main/client/methods/list.unit.test.js +0 -277
- package/build/main/commands.d.ts +0 -10
- package/build/main/commands.js +0 -2
- package/build/main/methods.d.ts +0 -92
- package/build/main/methods.js +0 -41
- package/build/main/payloads.d.ts +0 -40
- package/build/main/payloads.js +0 -2
- package/build/main/services/common.d.ts +0 -22
- package/build/main/services/common.js +0 -2
- package/build/main/services/companies/entities.d.ts +0 -54
- package/build/main/services/companies/entities.js +0 -2
- package/build/main/services/companies/index.d.ts +0 -26
- package/build/main/services/companies/index.integration.test.d.ts +0 -1
- package/build/main/services/companies/index.integration.test.js +0 -19
- package/build/main/services/companies/index.js +0 -10
- package/build/main/services/companies/index.unit.test.d.ts +0 -1
- package/build/main/services/companies/index.unit.test.js +0 -72
- package/build/main/services/companies/methods.d.ts +0 -44
- package/build/main/services/companies/methods.js +0 -3
- package/build/main/services/contacts/entities.d.ts +0 -45
- package/build/main/services/contacts/entities.js +0 -2
- package/build/main/services/contacts/index.d.ts +0 -26
- package/build/main/services/contacts/index.integration.test.d.ts +0 -1
- package/build/main/services/contacts/index.integration.test.js +0 -19
- package/build/main/services/contacts/index.js +0 -10
- package/build/main/services/contacts/index.unit.test.d.ts +0 -1
- package/build/main/services/contacts/index.unit.test.js +0 -72
- package/build/main/services/contacts/methods.d.ts +0 -44
- package/build/main/services/contacts/methods.js +0 -3
- package/build/main/services/currencies/entities.d.ts +0 -15
- package/build/main/services/currencies/entities.js +0 -2
- package/build/main/services/deals/entities.d.ts +0 -43
- package/build/main/services/deals/entities.js +0 -2
- package/build/main/services/deals/index.d.ts +0 -26
- package/build/main/services/deals/index.integration.test.d.ts +0 -1
- package/build/main/services/deals/index.integration.test.js +0 -19
- package/build/main/services/deals/index.js +0 -10
- package/build/main/services/deals/index.unit.test.d.ts +0 -1
- package/build/main/services/deals/index.unit.test.js +0 -72
- package/build/main/services/deals/methods.d.ts +0 -44
- package/build/main/services/deals/methods.js +0 -3
- package/build/main/services/leads/entities.d.ts +0 -49
- package/build/main/services/leads/entities.js +0 -2
- package/build/main/services/leads/index.d.ts +0 -26
- package/build/main/services/leads/index.integration.test.d.ts +0 -1
- package/build/main/services/leads/index.integration.test.js +0 -19
- package/build/main/services/leads/index.js +0 -10
- package/build/main/services/leads/index.unit.test.d.ts +0 -1
- package/build/main/services/leads/index.unit.test.js +0 -72
- package/build/main/services/leads/methods.d.ts +0 -44
- package/build/main/services/leads/methods.js +0 -3
- package/build/main/services/statuses/entities.d.ts +0 -16
- package/build/main/services/statuses/entities.js +0 -2
- package/build/main/services/statuses/index.d.ts +0 -14
- package/build/main/services/statuses/index.integration.test.d.ts +0 -1
- package/build/main/services/statuses/index.integration.test.js +0 -90
- package/build/main/services/statuses/index.js +0 -11
- package/build/main/services/statuses/index.unit.test.d.ts +0 -1
- package/build/main/services/statuses/index.unit.test.js +0 -60
- package/build/main/services/statuses/methods.d.ts +0 -51
- package/build/main/services/statuses/methods.js +0 -3
- package/build/main/services/users/entities.d.ts +0 -40
- package/build/main/services/users/entities.js +0 -2
- package/build/main/services/users/index.d.ts +0 -9
- package/build/main/services/users/index.integration.test.d.ts +0 -1
- package/build/main/services/users/index.integration.test.js +0 -33
- package/build/main/services/users/index.js +0 -7
- package/build/main/services/users/index.unit.test.d.ts +0 -1
- package/build/main/services/users/index.unit.test.js +0 -25
- package/build/main/services/users/methods.d.ts +0 -17
- package/build/main/services/users/methods.js +0 -3
- package/build/main/utils/Diff.d.ts +0 -1
- package/build/main/utils/Diff.js +0 -2
- package/build/main/utils/ExtractValue.d.ts +0 -6
- package/build/main/utils/ExtractValue.js +0 -2
- package/build/main/utils/isArray.d.ts +0 -2
- package/build/main/utils/isArray.js +0 -4
- package/build/module/bitrix.d.ts +0 -114
- package/build/module/bitrix.integration.test.d.ts +0 -0
- package/build/module/bitrix.integration.test.js +0 -31
- package/build/module/bitrix.js +0 -40
- package/build/module/bitrix.unit.test.d.ts +0 -1
- package/build/module/bitrix.unit.test.js +0 -16
- package/build/module/client/client.unit.test.d.ts +0 -1
- package/build/module/client/client.unit.test.js +0 -65
- package/build/module/client/hooks/addAccessToken.d.ts +0 -6
- package/build/module/client/hooks/addAccessToken.js +0 -11
- package/build/module/client/hooks/addAccessToken.unit.test.d.ts +0 -1
- package/build/module/client/hooks/addAccessToken.unit.test.js +0 -26
- package/build/module/client/index.d.ts +0 -15
- package/build/module/client/index.js +0 -48
- package/build/module/client/methods/batch.d.ts +0 -40
- package/build/module/client/methods/batch.js +0 -76
- package/build/module/client/methods/batch.unit.test.d.ts +0 -1
- package/build/module/client/methods/batch.unit.test.js +0 -466
- package/build/module/client/methods/call.d.ts +0 -17
- package/build/module/client/methods/call.js +0 -28
- package/build/module/client/methods/call.unit.test.d.ts +0 -1
- package/build/module/client/methods/call.unit.test.js +0 -155
- package/build/module/client/methods/list.d.ts +0 -30
- package/build/module/client/methods/list.js +0 -55
- package/build/module/client/methods/list.unit.test.d.ts +0 -1
- package/build/module/client/methods/list.unit.test.js +0 -252
- package/build/module/commands.d.ts +0 -10
- package/build/module/commands.js +0 -1
- package/build/module/methods.d.ts +0 -92
- package/build/module/methods.js +0 -38
- package/build/module/payloads.d.ts +0 -40
- package/build/module/payloads.js +0 -1
- package/build/module/services/common.d.ts +0 -22
- package/build/module/services/common.js +0 -1
- package/build/module/services/companies/entities.d.ts +0 -54
- package/build/module/services/companies/entities.js +0 -1
- package/build/module/services/companies/index.d.ts +0 -26
- package/build/module/services/companies/index.integration.test.d.ts +0 -1
- package/build/module/services/companies/index.integration.test.js +0 -14
- package/build/module/services/companies/index.js +0 -8
- package/build/module/services/companies/index.unit.test.d.ts +0 -1
- package/build/module/services/companies/index.unit.test.js +0 -67
- package/build/module/services/companies/methods.d.ts +0 -44
- package/build/module/services/companies/methods.js +0 -1
- package/build/module/services/contacts/entities.d.ts +0 -45
- package/build/module/services/contacts/entities.js +0 -1
- package/build/module/services/contacts/index.d.ts +0 -26
- package/build/module/services/contacts/index.integration.test.d.ts +0 -1
- package/build/module/services/contacts/index.integration.test.js +0 -14
- package/build/module/services/contacts/index.js +0 -8
- package/build/module/services/contacts/index.unit.test.d.ts +0 -1
- package/build/module/services/contacts/index.unit.test.js +0 -67
- package/build/module/services/contacts/methods.d.ts +0 -44
- package/build/module/services/contacts/methods.js +0 -1
- package/build/module/services/currencies/entities.d.ts +0 -15
- package/build/module/services/currencies/entities.js +0 -1
- package/build/module/services/deals/entities.d.ts +0 -43
- package/build/module/services/deals/entities.js +0 -1
- package/build/module/services/deals/index.d.ts +0 -26
- package/build/module/services/deals/index.integration.test.d.ts +0 -1
- package/build/module/services/deals/index.integration.test.js +0 -14
- package/build/module/services/deals/index.js +0 -8
- package/build/module/services/deals/index.unit.test.d.ts +0 -1
- package/build/module/services/deals/index.unit.test.js +0 -67
- package/build/module/services/deals/methods.d.ts +0 -44
- package/build/module/services/deals/methods.js +0 -1
- package/build/module/services/leads/entities.d.ts +0 -49
- package/build/module/services/leads/entities.js +0 -1
- package/build/module/services/leads/index.d.ts +0 -26
- package/build/module/services/leads/index.integration.test.d.ts +0 -1
- package/build/module/services/leads/index.integration.test.js +0 -14
- package/build/module/services/leads/index.js +0 -8
- package/build/module/services/leads/index.unit.test.d.ts +0 -1
- package/build/module/services/leads/index.unit.test.js +0 -67
- package/build/module/services/leads/methods.d.ts +0 -44
- package/build/module/services/leads/methods.js +0 -1
- package/build/module/services/statuses/entities.d.ts +0 -16
- package/build/module/services/statuses/entities.js +0 -1
- package/build/module/services/statuses/index.d.ts +0 -14
- package/build/module/services/statuses/index.integration.test.d.ts +0 -1
- package/build/module/services/statuses/index.integration.test.js +0 -85
- package/build/module/services/statuses/index.js +0 -9
- package/build/module/services/statuses/index.unit.test.d.ts +0 -1
- package/build/module/services/statuses/index.unit.test.js +0 -55
- package/build/module/services/statuses/methods.d.ts +0 -51
- package/build/module/services/statuses/methods.js +0 -1
- package/build/module/services/users/entities.d.ts +0 -40
- package/build/module/services/users/entities.js +0 -1
- package/build/module/services/users/index.d.ts +0 -9
- package/build/module/services/users/index.integration.test.d.ts +0 -1
- package/build/module/services/users/index.integration.test.js +0 -28
- package/build/module/services/users/index.js +0 -5
- package/build/module/services/users/index.unit.test.d.ts +0 -1
- package/build/module/services/users/index.unit.test.js +0 -20
- package/build/module/services/users/methods.d.ts +0 -17
- package/build/module/services/users/methods.js +0 -1
- package/build/module/utils/Diff.d.ts +0 -1
- package/build/module/utils/Diff.js +0 -1
- package/build/module/utils/ExtractValue.d.ts +0 -6
- package/build/module/utils/ExtractValue.js +0 -1
- package/build/module/utils/isArray.d.ts +0 -2
- package/build/module/utils/isArray.js +0 -2
package/README.md
CHANGED
|
@@ -1,214 +1,120 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
# Bitrix24 REST API client that doesn't suck
|
|
1
|
+
# @2bad/bitrix
|
|
4
2
|
|
|
5
3
|
[](https://www.npmjs.com/package/@2bad/bitrix)
|
|
6
4
|
[](https://www.npmjs.com/package/@2bad/bitrix)
|
|
7
5
|
[](https://codecov.io/gh/2BAD/bitrix)
|
|
8
|
-
[](https://github.com/2BAD/bitrix/actions?query=workflow%3A%22Integration+testing%22)
|
|
10
|
-
[](https://github.com/2BAD/bitrix/search?l=typescript)
|
|
11
|
-
|
|
12
|
-
- 🔥 No bullshit
|
|
13
|
-
- ✨ Expressive API
|
|
14
|
-
- 💪 Strongly typed methods and requests results with TypeScript
|
|
15
|
-
- 🚀 Handles records batching and rate limiting for you
|
|
16
|
-
- ❤️ Promise-based
|
|
17
|
-
|
|
18
|
-

|
|
19
|
-
|
|
20
|
-
### Install
|
|
21
|
-
|
|
22
|
-
```shell
|
|
23
|
-
npm install @2bad/bitrix
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Usage
|
|
27
|
-
|
|
28
|
-
Init client with Bitrix API endpoint and access token and use the client to ease your Bitrix pain:
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
import Bitrix from '@2bad/bitrix'
|
|
32
|
-
// or for ESM
|
|
33
|
-
import { Bitrix } from '@2bad/bitrix'
|
|
34
|
-
|
|
35
|
-
const bitrix = Bitrix('https://PORTAL_NAME.bitrix24.ru/rest', 'ACCESS_TOKEN')
|
|
36
|
-
|
|
37
|
-
// Get deal
|
|
38
|
-
bitrix.deals.get('77')
|
|
39
|
-
.then(({ result }) => {
|
|
40
|
-
// Get typed payload
|
|
41
|
-
const { TITLE } = result // string
|
|
42
|
-
console.log(TITLE)
|
|
43
|
-
})
|
|
44
|
-
.catch(console.error)
|
|
45
|
-
|
|
46
|
-
// Get all deals
|
|
47
|
-
bitrix.deals.list({ select: ["*", "UF_*"] })
|
|
48
|
-
.then(({ result }) => {
|
|
49
|
-
const titles = result.map((e) => e.TITLE)
|
|
50
|
-
console.log(titles)
|
|
51
|
-
})
|
|
52
|
-
.catch(console.error)
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Authentication
|
|
56
|
-
|
|
57
|
-
Before you'll be able to use Bitrix REST API, you need to authenticate.
|
|
58
|
-
|
|
59
|
-
There are two ways to do that:
|
|
60
|
-
|
|
61
|
-
1. **A harder, but proper way** — create a Bitrix application and then authenticate with an OAuth.
|
|
62
|
-
|
|
63
|
-
Authentication with an OAuth requires some additional steps and that's up to you to deal with it using a lambda function, some server or a Postman.
|
|
64
|
-
|
|
65
|
-
That will yield an access token. Use it to init the client:
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
const bitrix = Bitrix('https://PORTAL_NAME.bitrix24.ru/rest', 'ACCESS_TOKEN')
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Note, that access token lives only 30 minutes and should be refreshed periodically with provided by OAuth refresh token, which in turn lives 1 month.
|
|
72
|
-
|
|
73
|
-
2. **An easier way** — create a Bitrix inbound webhook with required permissions.
|
|
74
|
-
|
|
75
|
-
It will instantly give you an endpoint with a token inside of it. No additional authentication or access tokens required to use it:
|
|
76
|
-
|
|
77
|
-
```typescript
|
|
78
|
-
const bitrix = Bitrix('https://PORTAL_NAME.bitrix24.ru/rest/1/WEBHOOK_TOKEN')
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
That endpoint lives indefinitely. Rejoice and hope that it won't backfire on you.
|
|
82
|
-
|
|
83
|
-
### API
|
|
6
|
+
[](https://github.com/2BAD/bitrix/actions/workflows/build.yml)
|
|
84
7
|
|
|
85
|
-
|
|
86
|
-
- [`call()`](docs/methods.md#call)
|
|
87
|
-
- [`list()`](docs/methods.md#list)
|
|
88
|
-
- [`batch()`](docs/methods.md#batch)
|
|
89
|
-
- CRM
|
|
90
|
-
- [Company](docs/services/companies.md)
|
|
91
|
-
- [Contact](docs/services/contacts.md)
|
|
92
|
-
- [Currency](docs/services/currencies.md)
|
|
93
|
-
- [Deal](docs/services/deals.md)
|
|
94
|
-
- [Lead](docs/services/leads.md)
|
|
95
|
-
- [Status](docs/services/statuses.md)
|
|
96
|
-
- [User](docs/services/users.md)
|
|
8
|
+
Bitrix24 REST API client for TypeScript with zero runtime dependencies.
|
|
97
9
|
|
|
98
|
-
|
|
10
|
+
## Why
|
|
99
11
|
|
|
100
|
-
|
|
12
|
+
Bitrix24 ships half-finished APIs to production and leaves you to find out how they actually work. Every module has its own field names, error formats and paging rules. The documentation is incomplete, out of date or wrong, a good part of the behavior isn't documented at all, and support won't help you. Every integration turns into reverse engineering, fixing one broken assumption at a time.
|
|
101
13
|
|
|
102
|
-
|
|
14
|
+
We did that work so you don't have to. This client takes whatever Bitrix throws at it and gives you something you can actually build on.
|
|
103
15
|
|
|
104
|
-
|
|
16
|
+
## What you get
|
|
105
17
|
|
|
106
|
-
|
|
18
|
+
- No bullshit
|
|
19
|
+
- Expressive API
|
|
20
|
+
- Strongly typed, including the custom fields of your portal
|
|
21
|
+
- Handles batching, rate limits and retries for you
|
|
22
|
+
- Zero dependencies, runs anywhere `fetch` does
|
|
107
23
|
|
|
108
|
-
|
|
24
|
+
## Install
|
|
109
25
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
3. **Services** — each [service](docs/services/README.md) provides an expressive interface to work with a specific group of Bitrix REST API operations. In essence, they do orchestrate generic client methods and parameters to get proper results.
|
|
113
|
-
4. **Bitrix client** — a top-level [provider](source/bitrix.ts) of generic method and services. An effortless way to deal with Bitrix REST API by using an intuitive API, which takes care of all underlying complexity.
|
|
114
|
-
|
|
115
|
-
### FAQ
|
|
116
|
-
|
|
117
|
-
> Is it finished?
|
|
118
|
-
|
|
119
|
-
The core is ready and stable. It can be used to arbitrary invoke any Bitrix REST API methods.
|
|
120
|
-
|
|
121
|
-
However, not all Bitrix REST API methods are exposed as convenient client services yet \(the ones like `bitrix.deals.list()`\).
|
|
122
|
-
|
|
123
|
-
If you need specific service, add one by making a Pull Request, following the structure of already existing [services](source/services/README.md) and ["Adding new methods"](./#adding-new-methods) instructions.
|
|
124
|
-
|
|
125
|
-
> I'm not a Typed Language Master Race user. Can I use it with a regular JavaScript?
|
|
126
|
-
|
|
127
|
-
Sure. Just install and import it as any other NPM module. But The Type Police is already on the way for you.
|
|
128
|
-
|
|
129
|
-
Note that this library wasn't designed with regular JavaScript in mind, so it doesn't make unnecessary dynamic checks. Don't be too persistent in passing on wrong parameters — it might yield unexpected results. After all, TypeScript is a recommended way to use it.
|
|
130
|
-
|
|
131
|
-
> Should I check payloads `error` properties for errors?
|
|
132
|
-
|
|
133
|
-
You shouldn't. Catch rejections instead, as the library will reject if there are any errors in a payload.
|
|
134
|
-
|
|
135
|
-
> List method does not return user fields!
|
|
136
|
-
|
|
137
|
-
Bitrix API doesn't do that by default. Use wildcards in `select` param to force inclusion of user fields:
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
bitrix.deals.list({ select: ['*', 'UF_*'] })
|
|
26
|
+
```sh
|
|
27
|
+
npm install @2bad/bitrix
|
|
141
28
|
```
|
|
142
29
|
|
|
143
|
-
|
|
30
|
+
ESM only. Requires Node.js 26 or later.
|
|
144
31
|
|
|
145
|
-
|
|
32
|
+
## Quick start
|
|
146
33
|
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
.then(({ result }) => {
|
|
150
|
-
// known property of type `string`
|
|
151
|
-
const title = result.TITLE
|
|
152
|
-
|
|
153
|
-
// unknown property of type `string`
|
|
154
|
-
const someData = result.UF_23232323
|
|
155
|
-
|
|
156
|
-
console.log(title, someData)
|
|
157
|
-
})
|
|
158
|
-
```
|
|
34
|
+
```ts
|
|
35
|
+
import { createClient } from '@2bad/bitrix'
|
|
159
36
|
|
|
160
|
-
|
|
37
|
+
const bitrix = createClient({ url: 'https://portal.bitrix24.com/rest/1/WEBHOOK_TOKEN' })
|
|
161
38
|
|
|
162
|
-
|
|
39
|
+
const deal = await bitrix.deals.get(77)
|
|
40
|
+
console.log(deal.TITLE, deal.STAGE_ID) // Pump delivery C2:WON
|
|
163
41
|
|
|
164
|
-
|
|
165
|
-
bitrix.call('some.new.get' as any, { ID: '77' } as any)
|
|
166
|
-
.then((payload) => payload as GetPayload<NewPayload>)
|
|
167
|
-
|
|
168
|
-
bitrix.list('some.new.list' as any, { select: ["TITLE"] })
|
|
169
|
-
.then((payload) => payload as ListPayload<NewPayload>)
|
|
42
|
+
const open = await bitrix.deals.list({ filter: { CLOSED: 'N' }, select: ['ID', 'TITLE'] })
|
|
170
43
|
```
|
|
171
44
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
45
|
+
## Examples
|
|
46
|
+
|
|
47
|
+
- [Connecting](examples/connecting.md): webhooks, OAuth, rate limits, logging and custom `fetch`
|
|
48
|
+
- [Services](examples/services.md): deals, leads, contacts, companies, activities, smart processes, linked contacts, products, statuses, currencies and users
|
|
49
|
+
- [Lists](examples/lists.md): pagination modes, changes since the last sync and progress
|
|
50
|
+
- [Batch and bulk writes](examples/batch.md): many commands per request, `createMany`, `updateMany`, `deleteMany`
|
|
51
|
+
- [Types](examples/types.md): user field types from your portal and typing other methods
|
|
52
|
+
- [Errors](examples/errors.md): `BitrixError`, retries and cancellation
|
|
53
|
+
- [Migrating from 2.x](examples/migrating.md)
|
|
54
|
+
|
|
55
|
+
## API
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
function createClient(options: ClientOptions): Client
|
|
59
|
+
|
|
60
|
+
type Client = {
|
|
61
|
+
call(method, params?, options?: { raw?; signal? }): Promise<Result> // the whole response with { raw: true }
|
|
62
|
+
list(method, params?, options?: PaginateOptions): Promise<Row[]>
|
|
63
|
+
paginate(method, params?, options?: PaginateOptions): AsyncGenerator<Row>
|
|
64
|
+
batch(commands, options?: { halt?; signal? }): Promise<{ results; errors }>
|
|
65
|
+
|
|
66
|
+
activities: CrmService<Activity>
|
|
67
|
+
companies: CrmService<Company> & { contacts: Links }
|
|
68
|
+
contacts: CrmService<Contact> & { companies: Links }
|
|
69
|
+
currencies: CurrenciesService
|
|
70
|
+
deals: CrmService<Deal> & { productRows: ProductRows; contacts: Links }
|
|
71
|
+
items(entityTypeId): ItemsService // smart processes and other crm.item.* types
|
|
72
|
+
leads: CrmService<Lead> & { productRows: ProductRows; contacts: Links }
|
|
73
|
+
products: ProductsService
|
|
74
|
+
statuses: StatusesService
|
|
75
|
+
users: UsersService
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
type CrmService<Entity> = {
|
|
79
|
+
fields(): Promise<Fields>
|
|
80
|
+
get(id): Promise<Entity>
|
|
81
|
+
list(params?, options?: PaginateOptions): Promise<Entity[]> // rows typed by params.select
|
|
82
|
+
paginate(params?, options?: PaginateOptions): AsyncGenerator<Entity>
|
|
83
|
+
changedSince(since: Date | string, params?, options?): AsyncGenerator<Entity> // oldest change first
|
|
84
|
+
create(fields, params?): Promise<number>
|
|
85
|
+
update(id, fields, params?): Promise<boolean>
|
|
86
|
+
delete(id): Promise<boolean>
|
|
87
|
+
createMany(items, params?): Promise<BulkResult<number>>
|
|
88
|
+
updateMany(items: { id; fields }[], params?): Promise<BulkResult<boolean>>
|
|
89
|
+
deleteMany(ids): Promise<BulkResult<boolean>>
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
type ProductRows = { get(id): Promise<ProductRow[]>; set(id, rows): Promise<boolean> }
|
|
93
|
+
type Links = { get(id); set(id, links); add(id, link); delete(id, linkedId); clear(id) }
|
|
94
|
+
type ItemsService = { fields(); get(id); list(params?); paginate(params?); changedSince(since, params?); create(fields); update(id, fields); delete(id) }
|
|
95
|
+
type ProductsService = { fields(iblockId); get(id); list(params); paginate(params); create(fields); update(id, fields); delete(id) }
|
|
96
|
+
type StatusesService = { fields(); get(id); list(params?); create(fields); update(id, fields); delete(id, { forced? }) }
|
|
97
|
+
type CurrenciesService = { fields(); get(code); list(params?); create(fields); update(code, fields); delete(code); base(); setBase(code) }
|
|
98
|
+
type UsersService = { fields(); current(); get(id); list(params?); paginate(params?) }
|
|
99
|
+
|
|
100
|
+
type PaginateOptions = {
|
|
101
|
+
mode?: 'cursor' | 'offset' | 'modified' // cursor by default, modified needs since
|
|
102
|
+
since?: Date | string
|
|
103
|
+
modifiedField?: string // DATE_MODIFY by default
|
|
104
|
+
idField?: string // ID by default
|
|
105
|
+
signal?: AbortSignal
|
|
106
|
+
onProgress?: (progress: { read: number; total?: number }) => void
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
type BulkResult<R> = { results: (R | undefined)[]; errors: (BitrixError | undefined)[] } // in input order
|
|
181
110
|
```
|
|
182
111
|
|
|
183
|
-
|
|
112
|
+
```sh
|
|
113
|
+
bitrix-types [--url <rest url>] [--out <file>] [--entities deal,lead,contact,company]
|
|
114
|
+
```
|
|
184
115
|
|
|
185
|
-
|
|
116
|
+
Every error is a `BitrixError` with `code`, `description`, `method` and `status`.
|
|
186
117
|
|
|
187
|
-
|
|
188
|
-
const bitrix = Bitrix('https://PORTAL_NAME.bitrix24.ru/rest', 'ACCESS_TOKEN', {https: { rejectUnauthorized: false }})
|
|
189
|
-
```
|
|
118
|
+
## License
|
|
190
119
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
- `npm test` — run all tests and collect full coverage report
|
|
194
|
-
- `npm run test:unit` — run unit tests and collect coverage report
|
|
195
|
-
- `npm run test:integration` — run integration tests and collect coverage report
|
|
196
|
-
- `npm run test:watch` — watch for changes and run all tests
|
|
197
|
-
- `npm run test:unit:watch` — watch for changes and run unit tests
|
|
198
|
-
- `npm run test:integration:watch` — watch for changes and run integration tests
|
|
199
|
-
- `npm run build` — build the library for the release
|
|
200
|
-
|
|
201
|
-
#### Adding new methods
|
|
202
|
-
|
|
203
|
-
Proper method parameters and payload types handling requires some routine when adding any new method. Hopefully, we can do it better in future, but for now follow those steps:
|
|
204
|
-
|
|
205
|
-
1. Add new method into the [`Method`](source/methods.ts) enum.
|
|
206
|
-
2. Add it into the [`LISTABLE_METHODS`](source/methods.ts) array if it is listable \(paginated\). Not everything that lists is listable, so check it.
|
|
207
|
-
3. Add or update related [service](source/services/README.md):
|
|
208
|
-
1. Put exposed by the service public methods into the `index.ts` file. Ensure that you're properly mapping service method arguments to `call` or `list` params.
|
|
209
|
-
2. Add related entities into the `entities.ts`.
|
|
210
|
-
3. Add interface describing service methods into the `methods.ts`. Test and check method payload type to be sure you've described it correctly!
|
|
211
|
-
4. Extend [`Methods`](source/methods.ts) interface with the added service-specific interface. That way the client will know how to resolve parameters and payload types for the added method.
|
|
212
|
-
5. Add tests into the `index.unit.test.ts`.
|
|
213
|
-
4. Re-export service public types like Entities in the [bitrix.ts](source/bitrix.ts) to make them available to the end-users.
|
|
214
|
-
5. Document addition in the [docs](docs/README.md).
|
|
120
|
+
MIT
|
package/build/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/build/bin.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as createClient } from "./client-Bk76ySik.js";
|
|
3
|
+
import { writeFile } from "node:fs/promises";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
// source/user-fields.ts
|
|
6
|
+
const USER_FIELD_ENTITIES = {
|
|
7
|
+
deal: "DealUserFields",
|
|
8
|
+
lead: "LeadUserFields",
|
|
9
|
+
contact: "ContactUserFields",
|
|
10
|
+
company: "CompanyUserFields"
|
|
11
|
+
};
|
|
12
|
+
const STRING_TYPES = /* @__PURE__ */ new Set([
|
|
13
|
+
"string",
|
|
14
|
+
"url",
|
|
15
|
+
"address",
|
|
16
|
+
"money",
|
|
17
|
+
"date",
|
|
18
|
+
"datetime",
|
|
19
|
+
"employee",
|
|
20
|
+
"crm",
|
|
21
|
+
"crm_status",
|
|
22
|
+
"iblock_element",
|
|
23
|
+
"iblock_section"
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* Value type as Bitrix returns it in `get` and `list`: enumerations as item ids, strings in single fields
|
|
27
|
+
* and numbers in multiple ones, multiple fields as arrays or `false` when empty
|
|
28
|
+
* @param field field description from `crm.<entity>.fields`
|
|
29
|
+
*/
|
|
30
|
+
const valueType = (field) => {
|
|
31
|
+
const multiple = field.isMultiple;
|
|
32
|
+
const items = field.items ?? [];
|
|
33
|
+
const single = (() => {
|
|
34
|
+
if (field.type === "enumeration" && items.length > 0) return items.map(({ ID }) => multiple ? String(Number(ID)) : `'${ID.replaceAll("'", "\\'")}'`).join(" | ");
|
|
35
|
+
if (field.type === "boolean") return `'0' | '1'`;
|
|
36
|
+
if (field.type === "integer" || field.type === "double") return "number | string";
|
|
37
|
+
if (field.type === "file") return "UserFieldFile";
|
|
38
|
+
if (field.type === "enumeration" || STRING_TYPES.has(field.type)) return "string";
|
|
39
|
+
return "unknown";
|
|
40
|
+
})();
|
|
41
|
+
const usesFile = field.type === "file";
|
|
42
|
+
if (single === "unknown") return {
|
|
43
|
+
type: single,
|
|
44
|
+
usesFile
|
|
45
|
+
};
|
|
46
|
+
return multiple ? {
|
|
47
|
+
type: `ReadonlyArray<${single}> | false`,
|
|
48
|
+
usesFile
|
|
49
|
+
} : {
|
|
50
|
+
type: `${single} | null`,
|
|
51
|
+
usesFile
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
const comment = (field, indent) => {
|
|
55
|
+
const lines = [field.formLabel || field.listLabel || field.title, ...(field.items ?? []).map(({ ID, VALUE }) => `- ${ID}: ${VALUE}`)].map((line) => line.replaceAll(/\s+/g, " ").trim().replaceAll("*/", "*\\/"));
|
|
56
|
+
return lines.length === 1 ? `${indent}/** ${lines[0]} */` : [
|
|
57
|
+
`${indent}/**`,
|
|
58
|
+
...lines.map((line) => `${indent} * ${line}`),
|
|
59
|
+
`${indent} */`
|
|
60
|
+
].join("\n");
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Renders a declaration file that augments the client entity types with the user fields of a portal
|
|
64
|
+
* @param fields `crm.<entity>.fields` results by entity
|
|
65
|
+
* @param origin portal origin for the header, without any token
|
|
66
|
+
*/
|
|
67
|
+
const renderUserFields = (fields, origin) => {
|
|
68
|
+
let usesFile = false;
|
|
69
|
+
const interfaces = Object.entries(USER_FIELD_ENTITIES).flatMap(([entity, name]) => {
|
|
70
|
+
const entityFields = fields[entity];
|
|
71
|
+
if (!entityFields) return [];
|
|
72
|
+
const members = Object.entries(entityFields).filter(([key]) => key.startsWith("UF_")).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, field]) => {
|
|
73
|
+
const value = valueType(field);
|
|
74
|
+
usesFile ||= value.usesFile;
|
|
75
|
+
return `${comment(field, " ")}\n readonly ${key}: ${value.type}`;
|
|
76
|
+
});
|
|
77
|
+
return [members.length === 0 ? ` interface ${name} {}` : ` interface ${name} {\n${members.join("\n")}\n }`];
|
|
78
|
+
});
|
|
79
|
+
return [
|
|
80
|
+
`// Generated by bitrix-types from ${origin}. Run it again instead of editing this file.`,
|
|
81
|
+
...usesFile ? [`import type { UserFieldFile } from '@2bad/bitrix'`] : [],
|
|
82
|
+
"",
|
|
83
|
+
`declare module '@2bad/bitrix' {`,
|
|
84
|
+
interfaces.join("\n\n"),
|
|
85
|
+
"}",
|
|
86
|
+
"",
|
|
87
|
+
"export {}",
|
|
88
|
+
""
|
|
89
|
+
].join("\n");
|
|
90
|
+
};
|
|
91
|
+
// source/cli.ts
|
|
92
|
+
const USAGE = `Usage: bitrix-types [--url <rest url>] [--out <file>] [--entities deal,lead,contact,company]
|
|
93
|
+
|
|
94
|
+
Writes TypeScript declarations for the user fields of a Bitrix24 portal to stdout or --out.
|
|
95
|
+
The url can also come from BITRIX_URL, an OAuth access token from BITRIX_TOKEN.`;
|
|
96
|
+
const isEntity = (entity) => Object.hasOwn(USER_FIELD_ENTITIES, entity);
|
|
97
|
+
/**
|
|
98
|
+
* Runs `bitrix-types` and resolves with the exit code
|
|
99
|
+
* @param args command line arguments without the node binary and script
|
|
100
|
+
* @param env environment variables
|
|
101
|
+
* @param io output streams, file writer and an optional fetch
|
|
102
|
+
*/
|
|
103
|
+
const run = async (args, env, io) => {
|
|
104
|
+
const fail = (message) => {
|
|
105
|
+
io.stderr(`${message}\n`);
|
|
106
|
+
return 1;
|
|
107
|
+
};
|
|
108
|
+
let values;
|
|
109
|
+
try {
|
|
110
|
+
({values} = parseArgs({
|
|
111
|
+
args: [...args],
|
|
112
|
+
options: {
|
|
113
|
+
url: { type: "string" },
|
|
114
|
+
out: { type: "string" },
|
|
115
|
+
entities: { type: "string" },
|
|
116
|
+
help: {
|
|
117
|
+
type: "boolean",
|
|
118
|
+
short: "h"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}));
|
|
122
|
+
} catch (error) {
|
|
123
|
+
return fail(`${error.message}\n\n${USAGE}`);
|
|
124
|
+
}
|
|
125
|
+
if (values.help) {
|
|
126
|
+
io.stdout(`${USAGE}\n`);
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
const url = values.url ?? env["BITRIX_URL"];
|
|
130
|
+
if (!url) return fail(`Missing the portal url\n\n${USAGE}`);
|
|
131
|
+
const entities = values.entities?.split(",").map((entity) => entity.trim()) ?? Object.keys(USER_FIELD_ENTITIES);
|
|
132
|
+
const unknown = entities.filter((entity) => !isEntity(entity));
|
|
133
|
+
if (unknown.length > 0) return fail(`Unknown entities: ${unknown.join(", ")}\n\n${USAGE}`);
|
|
134
|
+
const token = env["BITRIX_TOKEN"];
|
|
135
|
+
try {
|
|
136
|
+
const { results, errors } = await createClient({
|
|
137
|
+
url,
|
|
138
|
+
...token && { auth: token },
|
|
139
|
+
...io.fetch && { fetch: io.fetch }
|
|
140
|
+
}).batch(Object.fromEntries(entities.map((entity) => [entity, { method: `crm.${entity}.fields` }])));
|
|
141
|
+
const failed = Object.values(errors).filter((error) => error !== void 0);
|
|
142
|
+
if (failed.length > 0) return fail(failed.map((error) => error.message).join("\n"));
|
|
143
|
+
const output = renderUserFields(results, new URL(url).origin);
|
|
144
|
+
if (values.out === void 0) io.stdout(output);
|
|
145
|
+
else {
|
|
146
|
+
await io.writeFile(values.out, output);
|
|
147
|
+
io.stderr(`Wrote user field types for ${entities.join(", ")} to ${values.out}\n`);
|
|
148
|
+
}
|
|
149
|
+
return 0;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
return fail(error.message);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
// source/bin.ts
|
|
155
|
+
process.exitCode = await run(process.argv.slice(2), process.env, {
|
|
156
|
+
stdout: (text) => process.stdout.write(text),
|
|
157
|
+
stderr: (text) => process.stderr.write(text),
|
|
158
|
+
writeFile
|
|
159
|
+
});
|
|
160
|
+
export {};
|