ab-ecosystem-cpass 1.0.9 → 1.0.10
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 +38 -0
- package/dist/resources/data-stores.d.ts +92 -19
- package/dist/resources/data-stores.js +91 -18
- package/dist/resources/data-stores.js.map +1 -1
- package/dist/types/datastore.d.ts +71 -5
- package/dist/types/datastore.js +17 -2
- package/dist/types/datastore.js.map +1 -1
- package/docs/campaign/campaigns.md +12 -0
- package/docs/data-store.md +99 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -159,6 +159,44 @@ try {
|
|
|
159
159
|
Common codes: `422` for a body or query that fails validation (`details` lists
|
|
160
160
|
the paths), `404 not_found`, `409 conflict` for a name or slug already taken.
|
|
161
161
|
|
|
162
|
+
### Plan limits
|
|
163
|
+
|
|
164
|
+
Every call needs an active subscription, and the metered resources are capped at
|
|
165
|
+
what the plan includes. Both refusals are `402`, told apart by `code`:
|
|
166
|
+
|
|
167
|
+
| Code | When | `details` |
|
|
168
|
+
| --- | --- | --- |
|
|
169
|
+
| `subscription_required` | The account has no subscription, or it has lapsed. Any call. | — |
|
|
170
|
+
| `not_included` | The plan includes none of that resource. | `{ resource }` |
|
|
171
|
+
| `quota_exceeded` | The plan's allowance is used up. | `{ resource, limit, used }` |
|
|
172
|
+
|
|
173
|
+
What counts, and against which inclusion:
|
|
174
|
+
|
|
175
|
+
| `resource` | Counted as | Inclusion |
|
|
176
|
+
| --- | --- | --- |
|
|
177
|
+
| `contact` | one contact | `contact_18472` — **1 unit = 1000 contacts** |
|
|
178
|
+
| `canned_reply` | one reply | `canned_reply_14172` |
|
|
179
|
+
| `scheduled_series` | one series, whatever its length — a one-off `schedule` is free | `series_91922` |
|
|
180
|
+
| `data_store` | one registered store | `data_store_52360` |
|
|
181
|
+
| `campaign` | one campaign | `campaign_73018` |
|
|
182
|
+
| `super_field` | one custom field | `super_field_29689` |
|
|
183
|
+
| `whatsapp_channel` | one live WhatsApp channel | `whatsapp_channels_28335` |
|
|
184
|
+
|
|
185
|
+
Counts are of what exists now, so deleting a row gives the allowance back.
|
|
186
|
+
`limit` and `used` are returned on `quota_exceeded` so a panel can say how far
|
|
187
|
+
over the account is without a second call.
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
try {
|
|
191
|
+
await crm.campaigns.create(input);
|
|
192
|
+
} catch (err) {
|
|
193
|
+
if (err instanceof CrmApiError && err.status === 402) {
|
|
194
|
+
// err.code: 'subscription_required' | 'not_included' | 'quota_exceeded'
|
|
195
|
+
console.error(err.message, err.details);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
162
200
|
## Modules
|
|
163
201
|
|
|
164
202
|
One page per resource, every action with its payload, query and response. The
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { BulkDeleteDataStoreRecordsInput, BulkUpdateDataStoreRecordsInput, CreateDataStoreCollectionInput, CreateDataStoreInput, DataStore, DataStoreCollection, DataStoreDeleteResult, DataStoreRecord, DataStoreTestResult, DataStoreUpdateResult, DataStoreWriteResult, InsertDataStoreRecordsInput, ListDataStoreRecordsQuery, ListQuery, Paginated, SearchDataStoreRecordsInput, UpdateDataStoreCollectionInput, UpdateDataStoreInput, UpdateDataStoreRecordInput } from '../types';
|
|
1
|
+
import type { BulkDeleteDataStoreRecordsInput, CloudDataStoreRegion, BulkUpdateDataStoreRecordsInput, CreateDataStoreCollectionInput, CreateDataStoreInput, DataStore, DataStoreCollection, DataStoreDeleteResult, DataStoreRecord, DataStoreTestResult, DataStoreUpdateResult, DataStoreWriteResult, InsertDataStoreRecordsInput, ListDataStoreRecordsQuery, ListQuery, Paginated, SearchDataStoreRecordsInput, UpdateDataStoreCollectionInput, UpdateDataStoreInput, UpdateDataStoreRecordInput } from '../types';
|
|
2
2
|
import type { HttpClient } from '../http';
|
|
3
3
|
/**
|
|
4
|
-
* Data stores: a MongoDB
|
|
4
|
+
* Data stores: a MongoDB you own, or one the platform runs for you.
|
|
5
5
|
*
|
|
6
6
|
* ```ts
|
|
7
|
+
* // your own cluster, registered with a credential
|
|
7
8
|
* const store = await crm.dataStores.create({
|
|
8
9
|
* title: 'Orders DB',
|
|
9
10
|
* credentials: {
|
|
@@ -15,6 +16,9 @@ import type { HttpClient } from '../http';
|
|
|
15
16
|
* },
|
|
16
17
|
* });
|
|
17
18
|
*
|
|
19
|
+
* // or one of the platform's -- no credential, no cluster to run
|
|
20
|
+
* const hosted = await crm.dataStores.create({ title: 'Leads', type: 'cloud' });
|
|
21
|
+
*
|
|
18
22
|
* const orders = await crm.dataStoreCollections.create(store.id, {
|
|
19
23
|
* title: 'Orders',
|
|
20
24
|
* fields: [
|
|
@@ -29,12 +33,30 @@ import type { HttpClient } from '../http';
|
|
|
29
33
|
* });
|
|
30
34
|
* ```
|
|
31
35
|
*
|
|
36
|
+
* ## Which kind to pick
|
|
37
|
+
*
|
|
38
|
+
* A **cloud** store (`type: 'cloud'`) is a database the platform provisions on
|
|
39
|
+
* one of its clusters, in a location you choose from `regions()` -- Germany for
|
|
40
|
+
* now. There is no credential to manage, nothing to expose to the internet, and
|
|
41
|
+
* no IP access list to maintain. Use it for data that does not already live
|
|
42
|
+
* somewhere.
|
|
43
|
+
*
|
|
44
|
+
* A **self** store is your own cluster, and the default. Use it when the data is
|
|
45
|
+
* already there, or has to stay there.
|
|
46
|
+
*
|
|
47
|
+
* The difference that matters beyond setup is **who the system of record is**,
|
|
48
|
+
* and it shows up on delete -- see below.
|
|
49
|
+
*
|
|
32
50
|
* ## What the platform holds, and what it does not
|
|
33
51
|
*
|
|
34
|
-
*
|
|
35
|
-
* **none of your data**: records are read from and written to
|
|
36
|
-
* every call, so nothing here is a copy that can go stale, and
|
|
37
|
-
* survives you revoking the credential.
|
|
52
|
+
* For a `self` store it holds the credential -- encrypted -- and the schemas you
|
|
53
|
+
* declare. It holds **none of your data**: records are read from and written to
|
|
54
|
+
* your cluster on every call, so nothing here is a copy that can go stale, and
|
|
55
|
+
* nothing here survives you revoking the credential.
|
|
56
|
+
*
|
|
57
|
+
* For a `cloud` store it holds the database itself. Nothing about that cluster
|
|
58
|
+
* is returned -- no host, no user, no connection string -- because there is no
|
|
59
|
+
* second way in: the API is the only door to those records.
|
|
38
60
|
*
|
|
39
61
|
* Which also means every record call costs a round trip to your database. The
|
|
40
62
|
* platform keeps the connection open between calls, so that is one query's
|
|
@@ -42,14 +64,17 @@ import type { HttpClient } from '../http';
|
|
|
42
64
|
* single inserts is a thousand round trips: send them as one `insert` with
|
|
43
65
|
* `records` instead.
|
|
44
66
|
*
|
|
45
|
-
* ## Deleting never deletes your data
|
|
67
|
+
* ## Deleting a `self` store never deletes your data. Deleting a `cloud` store does
|
|
68
|
+
*
|
|
69
|
+
* On a **self** store, `remove()` forgets the credential and the schemas, and
|
|
70
|
+
* `remove()` on a collection forgets the declaration. **Neither touches your
|
|
71
|
+
* database** -- the collections and every document in them are exactly as they
|
|
72
|
+
* were, and re-registering the same credential with the same collection name
|
|
73
|
+
* reads it all straight back.
|
|
46
74
|
*
|
|
47
|
-
* `remove()`
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* re-registering the same credential with the same collection name reads it all
|
|
51
|
-
* straight back. Deleting *records* is the only thing here that deletes
|
|
52
|
-
* anything of yours.
|
|
75
|
+
* On a **cloud** store, `remove()` **destroys the database**. Every record in it
|
|
76
|
+
* is gone, there is no undo, and re-creating the store gets a fresh empty one.
|
|
77
|
+
* Ask before you call it.
|
|
53
78
|
*
|
|
54
79
|
* ## The host must be reachable from the internet
|
|
55
80
|
*
|
|
@@ -62,6 +87,21 @@ import type { HttpClient } from '../http';
|
|
|
62
87
|
export declare class DataStores {
|
|
63
88
|
private readonly http;
|
|
64
89
|
constructor(http: HttpClient);
|
|
90
|
+
/**
|
|
91
|
+
* `GET /v1/datastores/cloud-regions` -- `{ data: [{ code, location }] }`.
|
|
92
|
+
*
|
|
93
|
+
* The clusters a cloud store can be provisioned on. Read it to render the
|
|
94
|
+
* location choice rather than hardcoding one: locations are added over time,
|
|
95
|
+
* and the `code` is what a create takes.
|
|
96
|
+
*
|
|
97
|
+
* An **empty list** means this deployment provisions none -- an on-premise
|
|
98
|
+
* install, typically -- and a `type: 'cloud'` create would be refused.
|
|
99
|
+
*
|
|
100
|
+
* Scope: `datastores:read`.
|
|
101
|
+
*/
|
|
102
|
+
regions(): Promise<{
|
|
103
|
+
data: CloudDataStoreRegion[];
|
|
104
|
+
}>;
|
|
65
105
|
/**
|
|
66
106
|
* `POST /v1/datastores` -- 201 with the store.
|
|
67
107
|
*
|
|
@@ -70,7 +110,25 @@ export declare class DataStores {
|
|
|
70
110
|
* | Field | Type | Required | Notes |
|
|
71
111
|
* | --- | --- | --- | --- |
|
|
72
112
|
* | `title` | string | yes | What you call it. 1-120 characters. |
|
|
73
|
-
* | `
|
|
113
|
+
* | `type` | `'self' \| 'cloud'` | no | Default `self`: your own database. |
|
|
114
|
+
* | `credentials` | object | for `self` | Either form below. Refused for `cloud`. |
|
|
115
|
+
* | `code` | string | no | `cloud` only: a cluster from `regions()`. Defaults to the platform's. |
|
|
116
|
+
*
|
|
117
|
+
* ### A cloud store
|
|
118
|
+
*
|
|
119
|
+
* ```ts
|
|
120
|
+
* await crm.dataStores.create({ title: 'Leads', type: 'cloud' });
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* That is the whole payload: the platform provisions a database of its own,
|
|
124
|
+
* in the default location, and the response carries the `code` and `location`
|
|
125
|
+
* it ended up in. Nothing below about credentials, hosts or IP access lists
|
|
126
|
+
* applies -- and neither does the 502 pair, because there is no cluster of
|
|
127
|
+
* yours to be unreachable.
|
|
128
|
+
*
|
|
129
|
+
* | Status | Code | Meaning |
|
|
130
|
+
* | --- | --- | --- |
|
|
131
|
+
* | 422 | `validation_failed` | Credentials sent with `type: 'cloud'`, or a `code` that is not on offer -- including when this deployment offers none. |
|
|
74
132
|
*
|
|
75
133
|
* **`credentials.type: 'field'`**
|
|
76
134
|
*
|
|
@@ -128,7 +186,13 @@ export declare class DataStores {
|
|
|
128
186
|
* | Field | Type | Notes |
|
|
129
187
|
* | --- | --- | --- |
|
|
130
188
|
* | `title` | string | |
|
|
131
|
-
* | `credentials` | object | Replaced whole, and tested before it is stored. |
|
|
189
|
+
* | `credentials` | object | Replaced whole, and tested before it is stored. `self` stores only. |
|
|
190
|
+
*
|
|
191
|
+
* `type` and `code` are not editable: they say where the records are, not how
|
|
192
|
+
* the store is configured. Sending `credentials` for a **cloud** store is a
|
|
193
|
+
* `422` -- there is nothing to replace, and re-pointing it would leave its
|
|
194
|
+
* records in a database nothing addresses. Register your own database as a
|
|
195
|
+
* second store instead.
|
|
132
196
|
*
|
|
133
197
|
* A partial credential is not accepted: send all four fields, or the whole
|
|
134
198
|
* URI. New credentials go through the same checks as `create`, and the old
|
|
@@ -141,10 +205,19 @@ export declare class DataStores {
|
|
|
141
205
|
/**
|
|
142
206
|
* `DELETE /v1/datastores/:store` -- 204.
|
|
143
207
|
*
|
|
144
|
-
*
|
|
145
|
-
* not touched
|
|
146
|
-
* registering the same credential again with the same collection
|
|
147
|
-
* them straight back.
|
|
208
|
+
* **A `self` store:** forgets the credential and every schema declared on it.
|
|
209
|
+
* Your database is not touched -- the collections and all their documents
|
|
210
|
+
* remain, and registering the same credential again with the same collection
|
|
211
|
+
* names reads them straight back.
|
|
212
|
+
*
|
|
213
|
+
* **A `cloud` store:** drops every collection in its database, which destroys
|
|
214
|
+
* the database with them. Every record is gone, there is no undo, and a new
|
|
215
|
+
* store of the same name is a new empty database. Confirm with the user before
|
|
216
|
+
* calling this on one.
|
|
217
|
+
*
|
|
218
|
+
* | Status | Code | Meaning |
|
|
219
|
+
* | --- | --- | --- |
|
|
220
|
+
* | 502 | `datastore_purge_failed` | A collection could not be deleted, named in `details`. Nothing was removed -- the store is intact and the call can be retried. |
|
|
148
221
|
*
|
|
149
222
|
* Scope: `datastores:write`.
|
|
150
223
|
*/
|
|
@@ -8,9 +8,10 @@ const collectionsPath = (store) => `${storePath(store)}/collections`;
|
|
|
8
8
|
const collectionPath = (store, collection) => `${collectionsPath(store)}/${(0, paths_1.seg)(collection)}`;
|
|
9
9
|
const recordsPath = (store, collection) => `${collectionPath(store, collection)}/records`;
|
|
10
10
|
/**
|
|
11
|
-
* Data stores: a MongoDB
|
|
11
|
+
* Data stores: a MongoDB you own, or one the platform runs for you.
|
|
12
12
|
*
|
|
13
13
|
* ```ts
|
|
14
|
+
* // your own cluster, registered with a credential
|
|
14
15
|
* const store = await crm.dataStores.create({
|
|
15
16
|
* title: 'Orders DB',
|
|
16
17
|
* credentials: {
|
|
@@ -22,6 +23,9 @@ const recordsPath = (store, collection) => `${collectionPath(store, collection)}
|
|
|
22
23
|
* },
|
|
23
24
|
* });
|
|
24
25
|
*
|
|
26
|
+
* // or one of the platform's -- no credential, no cluster to run
|
|
27
|
+
* const hosted = await crm.dataStores.create({ title: 'Leads', type: 'cloud' });
|
|
28
|
+
*
|
|
25
29
|
* const orders = await crm.dataStoreCollections.create(store.id, {
|
|
26
30
|
* title: 'Orders',
|
|
27
31
|
* fields: [
|
|
@@ -36,12 +40,30 @@ const recordsPath = (store, collection) => `${collectionPath(store, collection)}
|
|
|
36
40
|
* });
|
|
37
41
|
* ```
|
|
38
42
|
*
|
|
43
|
+
* ## Which kind to pick
|
|
44
|
+
*
|
|
45
|
+
* A **cloud** store (`type: 'cloud'`) is a database the platform provisions on
|
|
46
|
+
* one of its clusters, in a location you choose from `regions()` -- Germany for
|
|
47
|
+
* now. There is no credential to manage, nothing to expose to the internet, and
|
|
48
|
+
* no IP access list to maintain. Use it for data that does not already live
|
|
49
|
+
* somewhere.
|
|
50
|
+
*
|
|
51
|
+
* A **self** store is your own cluster, and the default. Use it when the data is
|
|
52
|
+
* already there, or has to stay there.
|
|
53
|
+
*
|
|
54
|
+
* The difference that matters beyond setup is **who the system of record is**,
|
|
55
|
+
* and it shows up on delete -- see below.
|
|
56
|
+
*
|
|
39
57
|
* ## What the platform holds, and what it does not
|
|
40
58
|
*
|
|
41
|
-
*
|
|
42
|
-
* **none of your data**: records are read from and written to
|
|
43
|
-
* every call, so nothing here is a copy that can go stale, and
|
|
44
|
-
* survives you revoking the credential.
|
|
59
|
+
* For a `self` store it holds the credential -- encrypted -- and the schemas you
|
|
60
|
+
* declare. It holds **none of your data**: records are read from and written to
|
|
61
|
+
* your cluster on every call, so nothing here is a copy that can go stale, and
|
|
62
|
+
* nothing here survives you revoking the credential.
|
|
63
|
+
*
|
|
64
|
+
* For a `cloud` store it holds the database itself. Nothing about that cluster
|
|
65
|
+
* is returned -- no host, no user, no connection string -- because there is no
|
|
66
|
+
* second way in: the API is the only door to those records.
|
|
45
67
|
*
|
|
46
68
|
* Which also means every record call costs a round trip to your database. The
|
|
47
69
|
* platform keeps the connection open between calls, so that is one query's
|
|
@@ -49,14 +71,17 @@ const recordsPath = (store, collection) => `${collectionPath(store, collection)}
|
|
|
49
71
|
* single inserts is a thousand round trips: send them as one `insert` with
|
|
50
72
|
* `records` instead.
|
|
51
73
|
*
|
|
52
|
-
* ## Deleting never deletes your data
|
|
74
|
+
* ## Deleting a `self` store never deletes your data. Deleting a `cloud` store does
|
|
75
|
+
*
|
|
76
|
+
* On a **self** store, `remove()` forgets the credential and the schemas, and
|
|
77
|
+
* `remove()` on a collection forgets the declaration. **Neither touches your
|
|
78
|
+
* database** -- the collections and every document in them are exactly as they
|
|
79
|
+
* were, and re-registering the same credential with the same collection name
|
|
80
|
+
* reads it all straight back.
|
|
53
81
|
*
|
|
54
|
-
* `remove()`
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* re-registering the same credential with the same collection name reads it all
|
|
58
|
-
* straight back. Deleting *records* is the only thing here that deletes
|
|
59
|
-
* anything of yours.
|
|
82
|
+
* On a **cloud** store, `remove()` **destroys the database**. Every record in it
|
|
83
|
+
* is gone, there is no undo, and re-creating the store gets a fresh empty one.
|
|
84
|
+
* Ask before you call it.
|
|
60
85
|
*
|
|
61
86
|
* ## The host must be reachable from the internet
|
|
62
87
|
*
|
|
@@ -71,6 +96,21 @@ class DataStores {
|
|
|
71
96
|
constructor(http) {
|
|
72
97
|
this.http = http;
|
|
73
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* `GET /v1/datastores/cloud-regions` -- `{ data: [{ code, location }] }`.
|
|
101
|
+
*
|
|
102
|
+
* The clusters a cloud store can be provisioned on. Read it to render the
|
|
103
|
+
* location choice rather than hardcoding one: locations are added over time,
|
|
104
|
+
* and the `code` is what a create takes.
|
|
105
|
+
*
|
|
106
|
+
* An **empty list** means this deployment provisions none -- an on-premise
|
|
107
|
+
* install, typically -- and a `type: 'cloud'` create would be refused.
|
|
108
|
+
*
|
|
109
|
+
* Scope: `datastores:read`.
|
|
110
|
+
*/
|
|
111
|
+
regions() {
|
|
112
|
+
return this.http.request('GET', `${BASE}/cloud-regions`);
|
|
113
|
+
}
|
|
74
114
|
/**
|
|
75
115
|
* `POST /v1/datastores` -- 201 with the store.
|
|
76
116
|
*
|
|
@@ -79,7 +119,25 @@ class DataStores {
|
|
|
79
119
|
* | Field | Type | Required | Notes |
|
|
80
120
|
* | --- | --- | --- | --- |
|
|
81
121
|
* | `title` | string | yes | What you call it. 1-120 characters. |
|
|
82
|
-
* | `
|
|
122
|
+
* | `type` | `'self' \| 'cloud'` | no | Default `self`: your own database. |
|
|
123
|
+
* | `credentials` | object | for `self` | Either form below. Refused for `cloud`. |
|
|
124
|
+
* | `code` | string | no | `cloud` only: a cluster from `regions()`. Defaults to the platform's. |
|
|
125
|
+
*
|
|
126
|
+
* ### A cloud store
|
|
127
|
+
*
|
|
128
|
+
* ```ts
|
|
129
|
+
* await crm.dataStores.create({ title: 'Leads', type: 'cloud' });
|
|
130
|
+
* ```
|
|
131
|
+
*
|
|
132
|
+
* That is the whole payload: the platform provisions a database of its own,
|
|
133
|
+
* in the default location, and the response carries the `code` and `location`
|
|
134
|
+
* it ended up in. Nothing below about credentials, hosts or IP access lists
|
|
135
|
+
* applies -- and neither does the 502 pair, because there is no cluster of
|
|
136
|
+
* yours to be unreachable.
|
|
137
|
+
*
|
|
138
|
+
* | Status | Code | Meaning |
|
|
139
|
+
* | --- | --- | --- |
|
|
140
|
+
* | 422 | `validation_failed` | Credentials sent with `type: 'cloud'`, or a `code` that is not on offer -- including when this deployment offers none. |
|
|
83
141
|
*
|
|
84
142
|
* **`credentials.type: 'field'`**
|
|
85
143
|
*
|
|
@@ -143,7 +201,13 @@ class DataStores {
|
|
|
143
201
|
* | Field | Type | Notes |
|
|
144
202
|
* | --- | --- | --- |
|
|
145
203
|
* | `title` | string | |
|
|
146
|
-
* | `credentials` | object | Replaced whole, and tested before it is stored. |
|
|
204
|
+
* | `credentials` | object | Replaced whole, and tested before it is stored. `self` stores only. |
|
|
205
|
+
*
|
|
206
|
+
* `type` and `code` are not editable: they say where the records are, not how
|
|
207
|
+
* the store is configured. Sending `credentials` for a **cloud** store is a
|
|
208
|
+
* `422` -- there is nothing to replace, and re-pointing it would leave its
|
|
209
|
+
* records in a database nothing addresses. Register your own database as a
|
|
210
|
+
* second store instead.
|
|
147
211
|
*
|
|
148
212
|
* A partial credential is not accepted: send all four fields, or the whole
|
|
149
213
|
* URI. New credentials go through the same checks as `create`, and the old
|
|
@@ -158,10 +222,19 @@ class DataStores {
|
|
|
158
222
|
/**
|
|
159
223
|
* `DELETE /v1/datastores/:store` -- 204.
|
|
160
224
|
*
|
|
161
|
-
*
|
|
162
|
-
* not touched
|
|
163
|
-
* registering the same credential again with the same collection
|
|
164
|
-
* them straight back.
|
|
225
|
+
* **A `self` store:** forgets the credential and every schema declared on it.
|
|
226
|
+
* Your database is not touched -- the collections and all their documents
|
|
227
|
+
* remain, and registering the same credential again with the same collection
|
|
228
|
+
* names reads them straight back.
|
|
229
|
+
*
|
|
230
|
+
* **A `cloud` store:** drops every collection in its database, which destroys
|
|
231
|
+
* the database with them. Every record is gone, there is no undo, and a new
|
|
232
|
+
* store of the same name is a new empty database. Confirm with the user before
|
|
233
|
+
* calling this on one.
|
|
234
|
+
*
|
|
235
|
+
* | Status | Code | Meaning |
|
|
236
|
+
* | --- | --- | --- |
|
|
237
|
+
* | 502 | `datastore_purge_failed` | A collection could not be deleted, named in `details`. Nothing was removed -- the store is intact and the call can be retried. |
|
|
165
238
|
*
|
|
166
239
|
* Scope: `datastores:write`.
|
|
167
240
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-stores.js","sourceRoot":"","sources":["../../src/resources/data-stores.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"data-stores.js","sourceRoot":"","sources":["../../src/resources/data-stores.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Data Store: a customer's own MongoDB, registered with the platform.
|
|
3
3
|
*
|
|
4
|
+
* A store is one of two things, and `type` says which:
|
|
5
|
+
*
|
|
6
|
+
* - **`self`** -- a database **you** own, registered with a credential. The
|
|
7
|
+
* platform holds that credential and nothing else: no copy, no mirror, and
|
|
8
|
+
* deleting the store never touches your data.
|
|
9
|
+
* - **`cloud`** -- a database the **platform** provisions for you, on one of its
|
|
10
|
+
* clusters, in a location you pick. No credential to manage, nothing to open
|
|
11
|
+
* to the internet -- and the platform is then the system of record, so
|
|
12
|
+
* deleting the store deletes the records with it.
|
|
13
|
+
*
|
|
14
|
+
* Everything else is identical: the same collections, the same records, the same
|
|
15
|
+
* calls. Pick `cloud` to store data you do not already have somewhere, and
|
|
16
|
+
* `self` to work with a database you do.
|
|
17
|
+
*
|
|
4
18
|
* Three nested things:
|
|
5
19
|
*
|
|
6
|
-
* 1. **A data store** --
|
|
7
|
-
* holds the credential and nothing else: no copy of the data, no
|
|
20
|
+
* 1. **A data store** -- the database, yours or ours. For a `self` store the
|
|
21
|
+
* platform holds the credential and nothing else: no copy of the data, no
|
|
22
|
+
* mirror.
|
|
8
23
|
* 2. **A collection** -- a schema you declare, naming a collection inside that
|
|
9
24
|
* database and the fields in it.
|
|
10
25
|
* 3. **Records** -- the documents. They live in your database, and every record
|
|
@@ -16,6 +31,21 @@
|
|
|
16
31
|
* guarantee -- a document may carry fields the schema never mentioned, or lack
|
|
17
32
|
* ones it does.
|
|
18
33
|
*/
|
|
34
|
+
/** Whose database the records are in. */
|
|
35
|
+
export type DataStoreType = 'self' | 'cloud';
|
|
36
|
+
/**
|
|
37
|
+
* One cluster the platform can provision a cloud store on.
|
|
38
|
+
*
|
|
39
|
+
* `code` identifies the cluster and is what you send on a create; `location` is
|
|
40
|
+
* the country it is in, which is the half worth showing a user. New locations
|
|
41
|
+
* appear in this list rather than in a release note -- read it, do not hardcode
|
|
42
|
+
* it -- and an existing store never moves when one is added, which is why its
|
|
43
|
+
* `code` is returned on the store itself.
|
|
44
|
+
*/
|
|
45
|
+
export interface CloudDataStoreRegion {
|
|
46
|
+
code: string;
|
|
47
|
+
location: string;
|
|
48
|
+
}
|
|
19
49
|
/** The five storage types a field can declare. */
|
|
20
50
|
export type DataStoreFieldType = 'String' | 'Number' | 'Boolean' | 'Date' | 'Array';
|
|
21
51
|
/**
|
|
@@ -55,9 +85,32 @@ export type DataStoreCredentials = {
|
|
|
55
85
|
*/
|
|
56
86
|
uri: string;
|
|
57
87
|
};
|
|
88
|
+
/**
|
|
89
|
+
* Register your own database, or ask for one of the platform's.
|
|
90
|
+
*
|
|
91
|
+
* ```ts
|
|
92
|
+
* // yours
|
|
93
|
+
* await crm.dataStores.create({ title: 'Orders DB', credentials: { … } });
|
|
94
|
+
*
|
|
95
|
+
* // theirs, in Germany
|
|
96
|
+
* await crm.dataStores.create({ title: 'Leads', type: 'cloud' });
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* `type` defaults to `self`, so existing code is unaffected. The two halves do
|
|
100
|
+
* not mix: a `self` store needs `credentials` and takes no `code`, a `cloud`
|
|
101
|
+
* store takes a `code` and no credentials, and anything else is a `422`.
|
|
102
|
+
*/
|
|
58
103
|
export interface CreateDataStoreInput {
|
|
59
104
|
title: string;
|
|
60
|
-
|
|
105
|
+
/** `self` -- your database. `cloud` -- one of the platform's. Default `self`. */
|
|
106
|
+
type?: DataStoreType;
|
|
107
|
+
/** Required for `self`, and refused for `cloud`. */
|
|
108
|
+
credentials?: DataStoreCredentials;
|
|
109
|
+
/**
|
|
110
|
+
* `cloud` only: which cluster to put it on, from
|
|
111
|
+
* {@link DataStores.regions}. Omitted, the platform picks its default.
|
|
112
|
+
*/
|
|
113
|
+
code?: string;
|
|
61
114
|
}
|
|
62
115
|
/**
|
|
63
116
|
* Rename, re-point, or both.
|
|
@@ -81,12 +134,25 @@ export interface UpdateDataStoreInput {
|
|
|
81
134
|
export interface DataStore {
|
|
82
135
|
id: string;
|
|
83
136
|
title: string;
|
|
84
|
-
|
|
137
|
+
/** Whose database it is. Stores created before cloud stores existed are `self`. */
|
|
138
|
+
type: DataStoreType;
|
|
139
|
+
/** `cloud` only: the cluster it is on. Quote it in a support request. */
|
|
140
|
+
code?: string;
|
|
141
|
+
/** `cloud` only: where that cluster is -- `Germany`. */
|
|
142
|
+
location?: string;
|
|
143
|
+
/** How the credential was given. Absent on a `cloud` store, which has none. */
|
|
144
|
+
credentialType?: 'field' | 'string';
|
|
85
145
|
engine: 'mongodb';
|
|
146
|
+
/** Your host. Empty on a `cloud` store: the platform's own is not disclosed. */
|
|
86
147
|
host: string;
|
|
87
148
|
database: string;
|
|
149
|
+
/** Your database user. Empty on a `cloud` store. */
|
|
88
150
|
username: string;
|
|
89
|
-
/**
|
|
151
|
+
/**
|
|
152
|
+
* For display. The connection string with the password removed for a `self`
|
|
153
|
+
* store, and `cloud://<location>/<database>` for a cloud one -- a label, not
|
|
154
|
+
* something to connect with.
|
|
155
|
+
*/
|
|
90
156
|
summary: string;
|
|
91
157
|
/** When the connection was last proven to work: a create, an update, or a test. */
|
|
92
158
|
verifiedAt?: string;
|
package/dist/types/datastore.js
CHANGED
|
@@ -2,10 +2,25 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Data Store: a customer's own MongoDB, registered with the platform.
|
|
4
4
|
*
|
|
5
|
+
* A store is one of two things, and `type` says which:
|
|
6
|
+
*
|
|
7
|
+
* - **`self`** -- a database **you** own, registered with a credential. The
|
|
8
|
+
* platform holds that credential and nothing else: no copy, no mirror, and
|
|
9
|
+
* deleting the store never touches your data.
|
|
10
|
+
* - **`cloud`** -- a database the **platform** provisions for you, on one of its
|
|
11
|
+
* clusters, in a location you pick. No credential to manage, nothing to open
|
|
12
|
+
* to the internet -- and the platform is then the system of record, so
|
|
13
|
+
* deleting the store deletes the records with it.
|
|
14
|
+
*
|
|
15
|
+
* Everything else is identical: the same collections, the same records, the same
|
|
16
|
+
* calls. Pick `cloud` to store data you do not already have somewhere, and
|
|
17
|
+
* `self` to work with a database you do.
|
|
18
|
+
*
|
|
5
19
|
* Three nested things:
|
|
6
20
|
*
|
|
7
|
-
* 1. **A data store** --
|
|
8
|
-
* holds the credential and nothing else: no copy of the data, no
|
|
21
|
+
* 1. **A data store** -- the database, yours or ours. For a `self` store the
|
|
22
|
+
* platform holds the credential and nothing else: no copy of the data, no
|
|
23
|
+
* mirror.
|
|
9
24
|
* 2. **A collection** -- a schema you declare, naming a collection inside that
|
|
10
25
|
* database and the fields in it.
|
|
11
26
|
* 3. **Records** -- the documents. They live in your database, and every record
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"datastore.js","sourceRoot":"","sources":["../../src/types/datastore.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"datastore.js","sourceRoot":"","sources":["../../src/types/datastore.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG"}
|
|
@@ -425,6 +425,18 @@ const { data, nextCursor } = await crm.campaigns.list({ limit: 50, status: 'comp
|
|
|
425
425
|
const campaign = await crm.campaigns.get(id);
|
|
426
426
|
```
|
|
427
427
|
|
|
428
|
+
### What a campaign's `id` is
|
|
429
|
+
|
|
430
|
+
The `id` on a campaign is its own identity and the only one this API accepts —
|
|
431
|
+
the same value the campaign manager is handed as `broadcast.id` and stamps on
|
|
432
|
+
every report row as `cid`. So it is what you pass to `get`, `trigger`, `report`,
|
|
433
|
+
and what a re-target filter's `cid` must name.
|
|
434
|
+
|
|
435
|
+
It is a 24-character ObjectId string, but it is not the document's `_id`: that
|
|
436
|
+
is Mongo's key and never appears in a request or a response. The `nextCursor`
|
|
437
|
+
from [`list`](#list) is a paging position rather than an id — pass it back as a
|
|
438
|
+
cursor, never as a campaign id.
|
|
439
|
+
|
|
428
440
|
## `create`
|
|
429
441
|
|
|
430
442
|
For an audience you have already expressed as `filters` — every contact,
|
package/docs/data-store.md
CHANGED
|
@@ -2,9 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
`crm.dataStores`, `crm.dataStoreCollections`, `crm.dataStoreRecords` — `/v1/datastores`
|
|
4
4
|
|
|
5
|
-
A MongoDB **
|
|
6
|
-
|
|
7
|
-
the API
|
|
5
|
+
A MongoDB — **yours**, registered with a credential, or **ours**, provisioned
|
|
6
|
+
for you in a location you pick. Either way you declare the collections and
|
|
7
|
+
fields you want and read and write records through the API: from a chatbot flow,
|
|
8
|
+
an automation, or your own code.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
// your own cluster
|
|
12
|
+
await crm.dataStores.create({ title: 'Orders DB', credentials: { … } });
|
|
13
|
+
|
|
14
|
+
// or one of ours, no credential to manage
|
|
15
|
+
await crm.dataStores.create({ title: 'Leads', type: 'cloud' });
|
|
16
|
+
```
|
|
8
17
|
|
|
9
18
|
This runs as **its own service**, with its own database and its own deployment.
|
|
10
19
|
Nothing else in the platform depends on it, and it depends on nothing else: a
|
|
@@ -22,12 +31,84 @@ connections it holds to customer clusters cannot crowd out anything but itself.
|
|
|
22
31
|
Three things, nested:
|
|
23
32
|
|
|
24
33
|
```
|
|
25
|
-
data store a
|
|
34
|
+
data store a database — yours by credential, or ours by request
|
|
26
35
|
└── collection a schema: one collection name, and its fields
|
|
27
|
-
└── records the documents, in
|
|
36
|
+
└── records the documents, in that database
|
|
28
37
|
```
|
|
29
38
|
|
|
30
|
-
|
|
39
|
+
## Two kinds of store
|
|
40
|
+
|
|
41
|
+
`type` on a store says whose database the records are actually in, and it is the
|
|
42
|
+
one decision here with consequences:
|
|
43
|
+
|
|
44
|
+
| | `self` *(default)* | `cloud` |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| The database | Yours | Ours, provisioned per store |
|
|
47
|
+
| To create one | A credential, tested before anything is stored | Nothing. Optionally a `code` for the location |
|
|
48
|
+
| Reachability | Your cluster must be reachable from the internet, and usually needs our egress in its IP access list | Nothing to open, nothing to allow |
|
|
49
|
+
| System of record | You. Anything else with the credential writes the same documents | Us. The API is the only door |
|
|
50
|
+
| `remove()` on the store | Forgets the credential. **Your data stays** | **Drops the database.** The records are gone |
|
|
51
|
+
|
|
52
|
+
Pick `cloud` for data that does not already live somewhere — a form's
|
|
53
|
+
submissions, a chatbot's answers, a lookup table someone maintains in the panel.
|
|
54
|
+
Pick `self` when the data is already in your cluster, or has to stay there.
|
|
55
|
+
|
|
56
|
+
Everything past this point — collections, records, filters, paging — is
|
|
57
|
+
identical for both.
|
|
58
|
+
|
|
59
|
+
### Where a cloud store lives
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
const { data: regions } = await crm.dataStores.regions();
|
|
63
|
+
// [{ code: '6869Z798672Z296Z152Z286Z307', location: 'Germany' }]
|
|
64
|
+
|
|
65
|
+
const store = await crm.dataStores.create({
|
|
66
|
+
title: 'Leads',
|
|
67
|
+
type: 'cloud',
|
|
68
|
+
code: regions[0].code, // omit it and the platform picks its default
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
store.location; // 'Germany'
|
|
72
|
+
store.code; // the cluster it is on — quote it in a support request
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Read `regions()` rather than hardcoding a code: locations are added over time,
|
|
76
|
+
and an existing store **never moves** when one is added. That is why the code
|
|
77
|
+
comes back on the store itself, and it is the answer to a data-residency
|
|
78
|
+
question in writing.
|
|
79
|
+
|
|
80
|
+
An empty `regions()` means this deployment provisions none — an on-premise
|
|
81
|
+
install, typically — and a `type: 'cloud'` create is then a `422`.
|
|
82
|
+
|
|
83
|
+
Nothing about our cluster is returned on a cloud store: `host` and `username`
|
|
84
|
+
are empty, there is no `credentialType`, and `summary` is a label
|
|
85
|
+
(`cloud://Germany/ds_…`) rather than a connection string. There is no second way
|
|
86
|
+
into those records, by design.
|
|
87
|
+
|
|
88
|
+
## What `remove()` deletes
|
|
89
|
+
|
|
90
|
+
Worth stating before anything else, because the opposite assumption is the
|
|
91
|
+
expensive one in both directions:
|
|
92
|
+
|
|
93
|
+
| Call | What it removes |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `dataStores.remove()` on a **`self`** store | The stored credential, and every schema on it. **Your database is untouched.** |
|
|
96
|
+
| `dataStores.remove()` on a **`cloud`** store | The schemas, and **every collection in its database — which destroys the database, irreversibly.** |
|
|
97
|
+
| `dataStoreCollections.remove()` | The schema. The collection and its documents remain, in either kind of store. |
|
|
98
|
+
| `dataStoreRecords.remove()` / `bulkRemove()` | Documents, irreversibly. |
|
|
99
|
+
|
|
100
|
+
For a `self` store: register the same credential again, declare the same
|
|
101
|
+
collection name, and all of it reads straight back. For a `cloud` store there is
|
|
102
|
+
nothing to re-register — the database was named after that store and a new one
|
|
103
|
+
is empty — so confirm with the user before calling it.
|
|
104
|
+
|
|
105
|
+
If a collection cannot be deleted, the call is a `502 datastore_purge_failed`
|
|
106
|
+
naming it, and **nothing** has been removed: the store and its schemas are
|
|
107
|
+
intact and the call can be retried once the cause is fixed.
|
|
108
|
+
|
|
109
|
+
## What the platform holds
|
|
110
|
+
|
|
111
|
+
For a `self` store, **the credential and the schemas, and nothing else**. There
|
|
31
112
|
is no copy of your data here, no mirror and no sync: a record read is a live
|
|
32
113
|
query against your cluster, and a record write lands in it before the response
|
|
33
114
|
comes back.
|
|
@@ -43,19 +124,9 @@ Two consequences worth holding on to:
|
|
|
43
124
|
TLS handshake each time — but a loop of a thousand single inserts is a
|
|
44
125
|
thousand round trips. Send one `insert` with `records`.
|
|
45
126
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
expensive one:
|
|
50
|
-
|
|
51
|
-
| Call | What it removes |
|
|
52
|
-
| --- | --- |
|
|
53
|
-
| `dataStores.remove()` | The stored credential, and every schema on it. **Your database is untouched.** |
|
|
54
|
-
| `dataStoreCollections.remove()` | The schema. **Your collection and its documents remain.** |
|
|
55
|
-
| `dataStoreRecords.remove()` / `bulkRemove()` | Documents, from your database, irreversibly. |
|
|
56
|
-
|
|
57
|
-
Register the same credential again, declare the same collection name, and all of
|
|
58
|
-
it reads straight back. Only the record calls delete anything of yours.
|
|
127
|
+
For a `cloud` store the platform holds the database too, and the first
|
|
128
|
+
consequence does not apply: nothing else can write those documents. The second
|
|
129
|
+
still does — it is a different cluster, not a local one.
|
|
59
130
|
|
|
60
131
|
---
|
|
61
132
|
|
|
@@ -140,6 +211,15 @@ order to show which database it is looking at. Host, user and database come back
|
|
|
140
211
|
in the clear because an edit form has to render them, and none of them opens a
|
|
141
212
|
connection on its own.
|
|
142
213
|
|
|
214
|
+
A cloud store takes no credentials at all:
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
await crm.dataStores.create({ title: 'Leads', type: 'cloud' });
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Sending both is a `422`, as is a `code` on a `self` store: the two halves of the
|
|
221
|
+
body do not mix.
|
|
222
|
+
|
|
143
223
|
### Re-pointing one
|
|
144
224
|
|
|
145
225
|
```ts
|