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 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 **you** own, registered with the platform.
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
- * It holds the credential -- encrypted -- and the schemas you declare. It holds
35
- * **none of your data**: records are read from and written to your cluster on
36
- * every call, so nothing here is a copy that can go stale, and nothing here
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()` on a store forgets the credential and the schemas. `remove()` on a
48
- * collection forgets the declaration. **Neither touches your database** -- the
49
- * collections and every document in them are exactly as they were, and
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
- * | `credentials` | object | yes | Either form below. |
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
- * Forgets the credential and every schema declared on it. **Your database is
145
- * not touched**: the collections and all their documents remain, and
146
- * registering the same credential again with the same collection names reads
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 **you** own, registered with the platform.
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
- * It holds the credential -- encrypted -- and the schemas you declare. It holds
42
- * **none of your data**: records are read from and written to your cluster on
43
- * every call, so nothing here is a copy that can go stale, and nothing here
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()` on a store forgets the credential and the schemas. `remove()` on a
55
- * collection forgets the declaration. **Neither touches your database** -- the
56
- * collections and every document in them are exactly as they were, and
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
- * | `credentials` | object | yes | Either form below. |
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
- * Forgets the credential and every schema declared on it. **Your database is
162
- * not touched**: the collections and all their documents remain, and
163
- * registering the same credential again with the same collection names reads
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":"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"}
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** -- a connection to a database *you* own. The platform
7
- * holds the credential and nothing else: no copy of the data, no mirror.
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
- credentials: DataStoreCredentials;
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
- credentialType: 'field' | 'string';
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
- /** The connection string with the password removed, for display. */
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;
@@ -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** -- a connection to a database *you* own. The platform
8
- * holds the credential and nothing else: no copy of the data, no mirror.
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;;;;;;;;;;;;;;;;;GAiBG"}
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,
@@ -2,9 +2,18 @@
2
2
 
3
3
  `crm.dataStores`, `crm.dataStoreCollections`, `crm.dataStoreRecords` — `/v1/datastores`
4
4
 
5
- A MongoDB **you** own, registered with the platform. You give it a connection,
6
- declare the collections and fields you want, and read and write records through
7
- the API — from a chatbot flow, an automation, or your own code.
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 connection to a database you own
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 your database
36
+ └── records the documents, in that database
28
37
  ```
29
38
 
30
- The platform holds **the credential and the schemas, and nothing else**. There
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
- ## Deleting never deletes your data
47
-
48
- Worth stating before anything else, because the opposite assumption is the
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ab-ecosystem-cpass",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "JavaScript/TypeScript SDK for the CPaaS CRM gateway: audience and channels",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",