@fourier-labs/harbour-contracts 0.80.0 → 0.82.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 +3 -3
- package/contract-release.json +22 -22
- package/dist/gen-ts/app-integrations-declaration.d.ts +6 -0
- package/dist/gen-ts/contract-release.d.ts +6 -6
- package/dist/gen-ts/contract-release.js +6 -6
- package/dist/gen-ts/data-grant-v2.d.ts +5 -5
- package/dist/gen-ts/integration-execute-input-rules.d.ts +41 -0
- package/dist/gen-ts/integration-execute-input-rules.js +37 -9
- package/dist/gen-ts/integration-execute-request.d.ts +20 -3
- package/dist/gen-ts/integration-operations.d.ts +14 -0
- package/dist/gen-ts/integration-operations.js +18 -0
- package/dist/gen-ts/resolved-app-serving.d.ts +10 -0
- package/dist/gen-ts/saas-connection.d.ts +7 -7
- package/gen-ts/app-integrations-declaration.ts +6 -0
- package/gen-ts/contract-release.ts +6 -6
- package/gen-ts/data-grant-v2.ts +6 -4
- package/gen-ts/integration-execute-input-rules.ts +34 -7
- package/gen-ts/integration-execute-request.ts +21 -2
- package/gen-ts/integration-operations.ts +18 -0
- package/gen-ts/resolved-app-serving.ts +10 -0
- package/gen-ts/saas-connection.ts +8 -6
- package/package.json +1 -1
- package/schema/app-integrations-declaration.schema.json +62 -1
- package/schema/data-grant-v2.schema.json +4 -4
- package/schema/integration-execute-request.schema.json +129 -1
- package/schema/resolved-app-serving.schema.json +11 -0
- package/schema/saas-connection.schema.json +22 -7
package/gen-ts/data-grant-v2.ts
CHANGED
|
@@ -33,9 +33,9 @@ export interface DataGrantV2 {
|
|
|
33
33
|
kind: 'saas' | 'database' | 'service';
|
|
34
34
|
status: DataGrantV2Status;
|
|
35
35
|
/**
|
|
36
|
-
* Approved operations; each must match this grant's mode. Empty until the first approval. At most the thirty-
|
|
36
|
+
* Approved operations; each must match this grant's mode. Empty until the first approval. At most the thirty-two SaaS operations (0.82.0: eleven Slack and Gmail, eleven Basecamp, nine SharePoint, one phone); a database grant holds up to two (warehouse.view.read, warehouse.table.append).
|
|
37
37
|
*
|
|
38
|
-
* @maxItems
|
|
38
|
+
* @maxItems 32
|
|
39
39
|
*/
|
|
40
40
|
operations: (
|
|
41
41
|
| 'slack.channel.history'
|
|
@@ -69,7 +69,9 @@ export interface DataGrantV2 {
|
|
|
69
69
|
| 'sharepoint.file.search'
|
|
70
70
|
| 'sharepoint.file.read'
|
|
71
71
|
| 'sharepoint.file.upload'
|
|
72
|
+
| 'phone.sms.list'
|
|
72
73
|
| 'warehouse.view.read'
|
|
74
|
+
| 'warehouse.table.append'
|
|
73
75
|
| 'service.request'
|
|
74
76
|
)[];
|
|
75
77
|
/**
|
|
@@ -120,7 +122,7 @@ export interface DataGrantV2 {
|
|
|
120
122
|
installation?: string;
|
|
121
123
|
}
|
|
122
124
|
/**
|
|
123
|
-
* One approved logical resource: a Slack channel alias, the fixed Gmail `inbox` alias, a Basecamp project alias or the fixed Basecamp `account` alias (0.76.0), a SharePoint site alias (0.78.0), or a warehouse view alias with the approved columns.
|
|
125
|
+
* One approved logical resource: a Slack channel alias, the fixed Gmail `inbox` alias, a Basecamp project alias or the fixed Basecamp `account` alias (0.76.0), a SharePoint site alias (0.78.0), a phone number alias (0.82.0), or a warehouse view alias with the approved columns.
|
|
124
126
|
*/
|
|
125
127
|
export interface IntegrationResource {
|
|
126
128
|
/**
|
|
@@ -128,7 +130,7 @@ export interface IntegrationResource {
|
|
|
128
130
|
*/
|
|
129
131
|
name: string;
|
|
130
132
|
/**
|
|
131
|
-
* warehouse.view.read only: the approved columns of the view.
|
|
133
|
+
* warehouse.view.read and warehouse.table.append only: the approved columns of the view.
|
|
132
134
|
*
|
|
133
135
|
* @minItems 1
|
|
134
136
|
* @maxItems 32
|
|
@@ -17,7 +17,8 @@ export type IntegrationExecuteInputFieldRule =
|
|
|
17
17
|
| { kind: 'object[]'; required: boolean; minItems: number; maxItems: number; fields: Readonly<Record<string, IntegrationExecuteInputFieldRule>> }
|
|
18
18
|
| { kind: 'value'; required: boolean; types: readonly IntegrationExecuteInputValueType[]; maxLength?: number; list?: { minItems: number; maxItems: number; types: readonly IntegrationExecuteInputValueType[] } }
|
|
19
19
|
| { kind: 'boolean'; required: boolean }
|
|
20
|
-
| { kind: 'record'; required: boolean; minProperties: number; maxProperties: number; types: readonly IntegrationExecuteInputRecordValueType[]; maxLength?: number }
|
|
20
|
+
| { kind: 'record'; required: boolean; minProperties: number; maxProperties: number; types: readonly IntegrationExecuteInputRecordValueType[]; maxLength?: number }
|
|
21
|
+
| { kind: 'record[]'; required: boolean; minItems: number; maxItems: number; minProperties: number; maxProperties: number; types: readonly IntegrationExecuteInputRecordValueType[]; maxLength?: number };
|
|
21
22
|
|
|
22
23
|
/** The scalar types a `value` input accepts, alone or in its list form. */
|
|
23
24
|
export type IntegrationExecuteInputValueType = 'string' | 'number' | 'boolean';
|
|
@@ -268,6 +269,13 @@ export const IntegrationExecuteInputRules = {
|
|
|
268
269
|
conflict: { kind: "enum", required: false, values: ["rename", "replace", "fail"], default: "rename" },
|
|
269
270
|
},
|
|
270
271
|
},
|
|
272
|
+
"phone.sms.list": {
|
|
273
|
+
idempotencyKey: false,
|
|
274
|
+
fields: {
|
|
275
|
+
since: { kind: "string", required: true, minLength: 1, pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]{1,9})?(Z|[+-][0-9]{2}:[0-9]{2})$" },
|
|
276
|
+
from: { kind: "string", required: false, minLength: 0, maxLength: 32 },
|
|
277
|
+
},
|
|
278
|
+
},
|
|
271
279
|
"warehouse.view.read": {
|
|
272
280
|
idempotencyKey: false,
|
|
273
281
|
fields: {
|
|
@@ -290,6 +298,12 @@ export const IntegrationExecuteInputRules = {
|
|
|
290
298
|
limit: { kind: "integer", required: false, minimum: 1, maximum: 1000, default: 100 },
|
|
291
299
|
},
|
|
292
300
|
},
|
|
301
|
+
"warehouse.table.append": {
|
|
302
|
+
idempotencyKey: true,
|
|
303
|
+
fields: {
|
|
304
|
+
rows: { kind: "record[]", required: true, minItems: 1, maxItems: 500, minProperties: 1, maxProperties: 64, types: ["string", "number", "boolean", "null"], maxLength: 4000 },
|
|
305
|
+
},
|
|
306
|
+
},
|
|
293
307
|
"service.request": {
|
|
294
308
|
idempotencyKey: false,
|
|
295
309
|
fields: {
|
|
@@ -363,6 +377,17 @@ function checkFields(operation: string, prefix: string, fields: Readonly<Record<
|
|
|
363
377
|
return { ok: true, value: out };
|
|
364
378
|
}
|
|
365
379
|
|
|
380
|
+
/** One record: a bounded count of free keys, every value one of the record's scalar types. */
|
|
381
|
+
function checkRecord(path: string, field: { minProperties: number; maxProperties: number; types: readonly IntegrationExecuteInputRecordValueType[]; maxLength?: number }, value: unknown): { ok: true; value: unknown } | Refusal {
|
|
382
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) return refuse(path, `${path} must be a JSON object`);
|
|
383
|
+
const keys = Object.keys(value);
|
|
384
|
+
if (keys.length < field.minProperties || keys.length > field.maxProperties) return refuse(path, `${path} must have ${field.minProperties} to ${field.maxProperties} properties`);
|
|
385
|
+
for (const key of keys) {
|
|
386
|
+
if (!isScalar(field.types, field.maxLength, (value as Record<string, unknown>)[key])) return refuse(`${path}.${key}`, `${path}.${key} must be ${either(scalarShapes(field.types, field.maxLength))}`);
|
|
387
|
+
}
|
|
388
|
+
return { ok: true, value };
|
|
389
|
+
}
|
|
390
|
+
|
|
366
391
|
function checkField(operation: string, path: string, name: string, field: IntegrationExecuteInputFieldRule, value: unknown): { ok: true; value: unknown } | Refusal {
|
|
367
392
|
switch (field.kind) {
|
|
368
393
|
case 'object':
|
|
@@ -371,12 +396,14 @@ function checkField(operation: string, path: string, name: string, field: Integr
|
|
|
371
396
|
case 'boolean':
|
|
372
397
|
if (typeof value !== 'boolean') return refuse(path, `${path} must be a boolean`);
|
|
373
398
|
return { ok: true, value };
|
|
374
|
-
case 'record':
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if (
|
|
378
|
-
for (const
|
|
379
|
-
if (
|
|
399
|
+
case 'record':
|
|
400
|
+
return checkRecord(path, field, value);
|
|
401
|
+
case 'record[]': {
|
|
402
|
+
if (!Array.isArray(value) || value.length < field.minItems || value.length > field.maxItems) return refuse(path, `${path} must list ${field.minItems} to ${field.maxItems} items`);
|
|
403
|
+
for (const [index, item] of value.entries()) {
|
|
404
|
+
if (item === null || typeof item !== 'object' || Array.isArray(item)) return refuse(path, `${path}[${index}] is not a valid ${name} entry`);
|
|
405
|
+
const entry = checkRecord(`${path}[${index}]`, field, item);
|
|
406
|
+
if (!entry.ok) return entry;
|
|
380
407
|
}
|
|
381
408
|
return { ok: true, value };
|
|
382
409
|
}
|
|
@@ -10,7 +10,7 @@ export type IntegrationExecuteRequest = {
|
|
|
10
10
|
*/
|
|
11
11
|
connection: string;
|
|
12
12
|
/**
|
|
13
|
-
* Closed operation set. Extending it is a contracts change. 0.78.0 (ADR 0024) adds the nine SharePoint operations, every one user mode only on a site alias (a key of the connection's `channels` map, holding a Microsoft Graph site id): sharepoint.list.list, sharepoint.item.list, sharepoint.item.create (a receipted write: explicit action, idempotencyKey), sharepoint.item.update (a PATCH, idempotent at Graph, no key), sharepoint.drive.list, sharepoint.file.list, sharepoint.file.search, sharepoint.file.read and sharepoint.file.upload (a receipted write). 0.76.0 (ADR 0022) adds the eleven Basecamp operations, every one user mode only like gmail.*: basecamp.project.list (the projects of the company's pinned Basecamp account; its resource is the fixed `account` alias), and on one mapped project (the resource is a project alias, a key of the connection's `channels` map) basecamp.todolist.list, basecamp.todo.list, basecamp.todo.create (a receipted write: explicit action, idempotencyKey), basecamp.todo.complete (idempotent at Basecamp, no key), basecamp.message.list, basecamp.message.post, basecamp.comment.list, basecamp.comment.post, basecamp.campfire.post (the three posts are receipted writes) and basecamp.people.list. gmail.message.send (0.50.0) sends one email as the signed-in person: a send like slack.message.post (explicit Send, idempotencyKey, write receipt) under user identity; since 0.71.0 it may carry an HTML body and attachments. slack.message.post (0.53.0) runs in the mode the app declares: app (the company's Slack app, under the IT-approved per-app name) or user (the signed-in person, after their consent); since 0.55.0 each call names which of the approved modes it runs under. 0.71.0 (ADR 0018) adds slack.message.update and slack.message.delete (declared mode, like post), slack.dm.send (app mode: a direct message to 1..8 workspace members named by email), slack.user.lookup (app mode: email to Slack user id), gmail.thread.read (every message of one thread) and gmail.attachment.read (one attachment's bytes), and lets slack.channel.history run in app mode as well as user mode.
|
|
13
|
+
* Closed operation set. Extending it is a contracts change. 0.78.0 (ADR 0024) adds the nine SharePoint operations, every one user mode only on a site alias (a key of the connection's `channels` map, holding a Microsoft Graph site id): sharepoint.list.list, sharepoint.item.list, sharepoint.item.create (a receipted write: explicit action, idempotencyKey), sharepoint.item.update (a PATCH, idempotent at Graph, no key), sharepoint.drive.list, sharepoint.file.list, sharepoint.file.search, sharepoint.file.read and sharepoint.file.upload (a receipted write). 0.76.0 (ADR 0022) adds the eleven Basecamp operations, every one user mode only like gmail.*: basecamp.project.list (the projects of the company's pinned Basecamp account; its resource is the fixed `account` alias), and on one mapped project (the resource is a project alias, a key of the connection's `channels` map) basecamp.todolist.list, basecamp.todo.list, basecamp.todo.create (a receipted write: explicit action, idempotencyKey), basecamp.todo.complete (idempotent at Basecamp, no key), basecamp.message.list, basecamp.message.post, basecamp.comment.list, basecamp.comment.post, basecamp.campfire.post (the three posts are receipted writes) and basecamp.people.list. gmail.message.send (0.50.0) sends one email as the signed-in person: a send like slack.message.post (explicit Send, idempotencyKey, write receipt) under user identity; since 0.71.0 it may carry an HTML body and attachments. slack.message.post (0.53.0) runs in the mode the app declares: app (the company's Slack app, under the IT-approved per-app name) or user (the signed-in person, after their consent); since 0.55.0 each call names which of the approved modes it runs under. 0.71.0 (ADR 0018) adds slack.message.update and slack.message.delete (declared mode, like post), slack.dm.send (app mode: a direct message to 1..8 workspace members named by email), slack.user.lookup (app mode: email to Slack user id), gmail.thread.read (every message of one thread) and gmail.attachment.read (one attachment's bytes), and lets slack.channel.history run in app mode as well as user mode. 0.82.0 (ADR 0028) adds phone.sms.list (app mode only, a number alias from a phone connection's `channels` map: the SMS received on that number since a time) and warehouse.table.append (app mode only on a database connection, a receipted write with idempotencyKey: rows appended to a view alias whose mapping says `access: append`).
|
|
14
14
|
*/
|
|
15
15
|
operation:
|
|
16
16
|
| 'slack.channel.history'
|
|
@@ -44,7 +44,9 @@ export type IntegrationExecuteRequest = {
|
|
|
44
44
|
| 'sharepoint.file.search'
|
|
45
45
|
| 'sharepoint.file.read'
|
|
46
46
|
| 'sharepoint.file.upload'
|
|
47
|
+
| 'phone.sms.list'
|
|
47
48
|
| 'warehouse.view.read'
|
|
49
|
+
| 'warehouse.table.append'
|
|
48
50
|
| 'service.request';
|
|
49
51
|
/**
|
|
50
52
|
* Tenant-wide logical alias of a connection (governance sourceId) or of a resource under it.
|
|
@@ -270,9 +272,26 @@ export type IntegrationExecuteRequest = {
|
|
|
270
272
|
body?: {
|
|
271
273
|
[k: string]: unknown;
|
|
272
274
|
};
|
|
275
|
+
/**
|
|
276
|
+
* warehouse.table.append (0.82.0): the rows to append, 1..500 of them, every one a record of the approved columns. Governance refuses an unapproved column, a value outside its column type and a request above 1 MB with ROW_VALUE_INVALID; nothing is coerced.
|
|
277
|
+
*
|
|
278
|
+
* @minItems 1
|
|
279
|
+
* @maxItems 500
|
|
280
|
+
*/
|
|
281
|
+
rows?: {
|
|
282
|
+
[k: string]: string | number | boolean | null;
|
|
283
|
+
}[];
|
|
284
|
+
/**
|
|
285
|
+
* phone.sms.list (0.82.0): the ISO 8601 date-time (with a zone) after which received messages are listed; inclusive. Messages are kept for 30 minutes, so an older `since` lists what is still held.
|
|
286
|
+
*/
|
|
287
|
+
since?: string;
|
|
288
|
+
/**
|
|
289
|
+
* phone.sms.list (0.82.0): only messages from this sender id or number (as the provider reports it, e.g. `VK-GSTNIN` or `+919876543210`); absent lists every sender.
|
|
290
|
+
*/
|
|
291
|
+
from?: string;
|
|
273
292
|
};
|
|
274
293
|
/**
|
|
275
|
-
* UUID of one explicit Send action; required for the sends (slack.message.post, slack.dm.send, gmail.message.send), the receipted Basecamp writes (basecamp.todo.create, basecamp.message.post, basecamp.comment.post, basecamp.campfire.post; 0.76.0)
|
|
294
|
+
* UUID of one explicit Send action; required for the sends (slack.message.post, slack.dm.send, gmail.message.send), the receipted Basecamp writes (basecamp.todo.create, basecamp.message.post, basecamp.comment.post, basecamp.campfire.post; 0.76.0) the receipted SharePoint writes (sharepoint.item.create, sharepoint.file.upload; 0.78.0) and the receipted warehouse append (warehouse.table.append; 0.82.0, where it is also the BigQuery load job id), refused everywhere else. The same key with the same payload and subject returns the recorded outcome for seven days.
|
|
276
295
|
*/
|
|
277
296
|
idempotencyKey?: string;
|
|
278
297
|
/**
|
|
@@ -286,6 +286,15 @@ export const IntegrationOperations = {
|
|
|
286
286
|
"declaredMode": false,
|
|
287
287
|
"idempotencyKey": true
|
|
288
288
|
},
|
|
289
|
+
"phone.sms.list": {
|
|
290
|
+
"kind": "saas",
|
|
291
|
+
"identities": [
|
|
292
|
+
"app"
|
|
293
|
+
],
|
|
294
|
+
"readOnly": true,
|
|
295
|
+
"declaredMode": false,
|
|
296
|
+
"idempotencyKey": false
|
|
297
|
+
},
|
|
289
298
|
"warehouse.view.read": {
|
|
290
299
|
"kind": "database",
|
|
291
300
|
"identities": [
|
|
@@ -295,6 +304,15 @@ export const IntegrationOperations = {
|
|
|
295
304
|
"declaredMode": false,
|
|
296
305
|
"idempotencyKey": false
|
|
297
306
|
},
|
|
307
|
+
"warehouse.table.append": {
|
|
308
|
+
"kind": "database",
|
|
309
|
+
"identities": [
|
|
310
|
+
"app"
|
|
311
|
+
],
|
|
312
|
+
"readOnly": false,
|
|
313
|
+
"declaredMode": false,
|
|
314
|
+
"idempotencyKey": true
|
|
315
|
+
},
|
|
298
316
|
"service.request": {
|
|
299
317
|
"kind": "service",
|
|
300
318
|
"identities": [
|
|
@@ -34,6 +34,16 @@ export interface ResolvedAppServing {
|
|
|
34
34
|
* Bare hostname of apiUrl.
|
|
35
35
|
*/
|
|
36
36
|
apiHost?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Present only while the tenant enforces a network access policy (governance ADR 0130): the effective list of client ranges the app's gateway SecurityPolicy allows, the tenant's ranges plus the platform cell's own egress, as textual CIDRs. Absent means every network.
|
|
39
|
+
*/
|
|
40
|
+
networkAccess?: {
|
|
41
|
+
/**
|
|
42
|
+
* @minItems 1
|
|
43
|
+
* @maxItems 128
|
|
44
|
+
*/
|
|
45
|
+
clientCidrs: string[];
|
|
46
|
+
};
|
|
37
47
|
/**
|
|
38
48
|
* Present only when source is tenant: the ready delegated company zone the page and API hosts live under, and the shared gateway/TLS secret the cell serves it with.
|
|
39
49
|
*/
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Code generated by tools/gen/gen.mjs from schema/*.json. DO NOT EDIT.
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Slack carries an installation and a channel map; Gmail is user-consent only; Basecamp is user-consent only with an IT-pinned account and a project map in `channels`; SharePoint (0.78.0) is user-consent only, pinned to the company's Microsoft 365 tenant in `account`, with a site map in `channels`.
|
|
5
|
+
* Slack carries an installation and a channel map; Gmail is user-consent only; Basecamp is user-consent only with an IT-pinned account and a project map in `channels`; SharePoint (0.78.0) is user-consent only, pinned to the company's Microsoft 365 tenant in `account`, with a site map in `channels`. Phone (0.82.0) is app mode only with no installation: the tenant's inbound SMS numbers (E.164) mapped from aliases in `channels`, and the SMS the platform received on them listed by phone.sms.list.
|
|
6
6
|
*/
|
|
7
|
-
export type SaasProvider = 'slack' | 'gmail' | 'basecamp' | 'sharepoint';
|
|
7
|
+
export type SaasProvider = 'slack' | 'gmail' | 'basecamp' | 'sharepoint' | 'phone';
|
|
8
8
|
/**
|
|
9
9
|
* DISABLED stops every app call immediately (details.code CONNECTION_DISABLED).
|
|
10
10
|
*/
|
|
@@ -47,19 +47,19 @@ export interface SaasConnection {
|
|
|
47
47
|
installation?: SaasInstallation;
|
|
48
48
|
account?: BasecampAccount;
|
|
49
49
|
/**
|
|
50
|
-
* Logical alias → provider resource id: a Slack channel id, a Basecamp project id
|
|
50
|
+
* Logical alias → provider resource id: a Slack channel id, a Basecamp project id, a SharePoint site id or a phone number. Always empty for Gmail.
|
|
51
51
|
*/
|
|
52
52
|
channels: {
|
|
53
53
|
/**
|
|
54
|
-
* A Slack channel id (public, non-archived), a Basecamp project id (digits)
|
|
54
|
+
* A Slack channel id (public, non-archived), a Basecamp project id (digits), a SharePoint site id (0.78.0: the Microsoft Graph composite `hostname,siteCollectionGuid,webGuid`) or a phone number (0.82.0: E.164, a leading `+` and digits).
|
|
55
55
|
*/
|
|
56
56
|
[k: string]: string;
|
|
57
57
|
};
|
|
58
58
|
/**
|
|
59
|
-
* Operations IT allows apps to request on this connection: the provider's own SaaS operations (Slack: slack.channel.history, slack.message.post, slack.message.update, slack.message.delete, slack.dm.send, slack.user.lookup; Gmail: gmail.thread.list, gmail.thread.read, gmail.message.read, gmail.message.send, gmail.attachment.read; Basecamp (0.76.0): basecamp.project.list, basecamp.todolist.list, basecamp.todo.list, basecamp.todo.create, basecamp.todo.complete, basecamp.message.list, basecamp.message.post, basecamp.comment.list, basecamp.comment.post, basecamp.campfire.post, basecamp.people.list; SharePoint (0.78.0): sharepoint.list.list, sharepoint.item.list, sharepoint.item.create, sharepoint.item.update, sharepoint.drive.list, sharepoint.file.list, sharepoint.file.search, sharepoint.file.read, sharepoint.file.upload). Never warehouse.view.read.
|
|
59
|
+
* Operations IT allows apps to request on this connection: the provider's own SaaS operations (Slack: slack.channel.history, slack.message.post, slack.message.update, slack.message.delete, slack.dm.send, slack.user.lookup; Gmail: gmail.thread.list, gmail.thread.read, gmail.message.read, gmail.message.send, gmail.attachment.read; Basecamp (0.76.0): basecamp.project.list, basecamp.todolist.list, basecamp.todo.list, basecamp.todo.create, basecamp.todo.complete, basecamp.message.list, basecamp.message.post, basecamp.comment.list, basecamp.comment.post, basecamp.campfire.post, basecamp.people.list; SharePoint (0.78.0): sharepoint.list.list, sharepoint.item.list, sharepoint.item.create, sharepoint.item.update, sharepoint.drive.list, sharepoint.file.list, sharepoint.file.search, sharepoint.file.read, sharepoint.file.upload). Never warehouse.view.read. Phone (0.82.0): phone.sms.list.
|
|
60
60
|
*
|
|
61
61
|
* @minItems 1
|
|
62
|
-
* @maxItems
|
|
62
|
+
* @maxItems 32
|
|
63
63
|
*/
|
|
64
64
|
operations: (
|
|
65
65
|
| 'slack.channel.history'
|
|
@@ -93,7 +93,9 @@ export interface SaasConnection {
|
|
|
93
93
|
| 'sharepoint.file.search'
|
|
94
94
|
| 'sharepoint.file.read'
|
|
95
95
|
| 'sharepoint.file.upload'
|
|
96
|
+
| 'phone.sms.list'
|
|
96
97
|
| 'warehouse.view.read'
|
|
98
|
+
| 'warehouse.table.append'
|
|
97
99
|
| 'service.request'
|
|
98
100
|
)[];
|
|
99
101
|
developmentPreapproval: DevelopmentPreapproval;
|
package/package.json
CHANGED
|
@@ -84,10 +84,12 @@
|
|
|
84
84
|
"sharepoint.file.search",
|
|
85
85
|
"sharepoint.file.read",
|
|
86
86
|
"sharepoint.file.upload",
|
|
87
|
+
"phone.sms.list",
|
|
87
88
|
"warehouse.view.read",
|
|
89
|
+
"warehouse.table.append",
|
|
88
90
|
"service.request"
|
|
89
91
|
],
|
|
90
|
-
"description": "Closed operation set. Extending it is a contracts change. 0.78.0 (ADR 0024) adds the nine SharePoint operations, every one user mode only on a site alias (a key of the connection's `channels` map, holding a Microsoft Graph site id): sharepoint.list.list, sharepoint.item.list, sharepoint.item.create (a receipted write: explicit action, idempotencyKey), sharepoint.item.update (a PATCH, idempotent at Graph, no key), sharepoint.drive.list, sharepoint.file.list, sharepoint.file.search, sharepoint.file.read and sharepoint.file.upload (a receipted write). 0.76.0 (ADR 0022) adds the eleven Basecamp operations, every one user mode only like gmail.*: basecamp.project.list (the projects of the company's pinned Basecamp account; its resource is the fixed `account` alias), and on one mapped project (the resource is a project alias, a key of the connection's `channels` map) basecamp.todolist.list, basecamp.todo.list, basecamp.todo.create (a receipted write: explicit action, idempotencyKey), basecamp.todo.complete (idempotent at Basecamp, no key), basecamp.message.list, basecamp.message.post, basecamp.comment.list, basecamp.comment.post, basecamp.campfire.post (the three posts are receipted writes) and basecamp.people.list. gmail.message.send (0.50.0) sends one email as the signed-in person: a send like slack.message.post (explicit Send, idempotencyKey, write receipt) under user identity; since 0.71.0 it may carry an HTML body and attachments. slack.message.post (0.53.0) runs in the mode the app declares: app (the company's Slack app, under the IT-approved per-app name) or user (the signed-in person, after their consent); since 0.55.0 each call names which of the approved modes it runs under. 0.71.0 (ADR 0018) adds slack.message.update and slack.message.delete (declared mode, like post), slack.dm.send (app mode: a direct message to 1..8 workspace members named by email), slack.user.lookup (app mode: email to Slack user id), gmail.thread.read (every message of one thread) and gmail.attachment.read (one attachment's bytes), and lets slack.channel.history run in app mode as well as user mode."
|
|
92
|
+
"description": "Closed operation set. Extending it is a contracts change. 0.78.0 (ADR 0024) adds the nine SharePoint operations, every one user mode only on a site alias (a key of the connection's `channels` map, holding a Microsoft Graph site id): sharepoint.list.list, sharepoint.item.list, sharepoint.item.create (a receipted write: explicit action, idempotencyKey), sharepoint.item.update (a PATCH, idempotent at Graph, no key), sharepoint.drive.list, sharepoint.file.list, sharepoint.file.search, sharepoint.file.read and sharepoint.file.upload (a receipted write). 0.76.0 (ADR 0022) adds the eleven Basecamp operations, every one user mode only like gmail.*: basecamp.project.list (the projects of the company's pinned Basecamp account; its resource is the fixed `account` alias), and on one mapped project (the resource is a project alias, a key of the connection's `channels` map) basecamp.todolist.list, basecamp.todo.list, basecamp.todo.create (a receipted write: explicit action, idempotencyKey), basecamp.todo.complete (idempotent at Basecamp, no key), basecamp.message.list, basecamp.message.post, basecamp.comment.list, basecamp.comment.post, basecamp.campfire.post (the three posts are receipted writes) and basecamp.people.list. gmail.message.send (0.50.0) sends one email as the signed-in person: a send like slack.message.post (explicit Send, idempotencyKey, write receipt) under user identity; since 0.71.0 it may carry an HTML body and attachments. slack.message.post (0.53.0) runs in the mode the app declares: app (the company's Slack app, under the IT-approved per-app name) or user (the signed-in person, after their consent); since 0.55.0 each call names which of the approved modes it runs under. 0.71.0 (ADR 0018) adds slack.message.update and slack.message.delete (declared mode, like post), slack.dm.send (app mode: a direct message to 1..8 workspace members named by email), slack.user.lookup (app mode: email to Slack user id), gmail.thread.read (every message of one thread) and gmail.attachment.read (one attachment's bytes), and lets slack.channel.history run in app mode as well as user mode. 0.82.0 (ADR 0028) adds phone.sms.list (app mode only, a number alias from a phone connection's `channels` map: the SMS received on that number since a time) and warehouse.table.append (app mode only on a database connection, a receipted write with idempotencyKey: rows appended to a view alias whose mapping says `access: append`)."
|
|
91
93
|
},
|
|
92
94
|
"IntegrationIdentityMode": {
|
|
93
95
|
"type": "string",
|
|
@@ -147,7 +149,16 @@
|
|
|
147
149
|
"required": [
|
|
148
150
|
"columns"
|
|
149
151
|
],
|
|
152
|
+
"description": "One declared warehouse alias: the columns the app uses and, since 0.82.0, how it uses them. `access` is read (warehouse.view.read, the default when absent, so every existing declaration and stored mapping is unchanged) or append (warehouse.table.append: the app writes rows with these columns and never reads). Governance refuses an append on a read alias and a read on an append alias with RESOURCE_NOT_APPROVED.",
|
|
150
153
|
"properties": {
|
|
154
|
+
"access": {
|
|
155
|
+
"type": "string",
|
|
156
|
+
"enum": [
|
|
157
|
+
"read",
|
|
158
|
+
"append"
|
|
159
|
+
],
|
|
160
|
+
"default": "read"
|
|
161
|
+
},
|
|
151
162
|
"columns": {
|
|
152
163
|
"type": "array",
|
|
153
164
|
"minItems": 1,
|
|
@@ -361,9 +372,15 @@
|
|
|
361
372
|
"sharepoint.file.upload": {
|
|
362
373
|
"$ref": "#/definitions/UserModeChannelOperation"
|
|
363
374
|
},
|
|
375
|
+
"phone.sms.list": {
|
|
376
|
+
"$ref": "#/definitions/AppModeChannelOperation"
|
|
377
|
+
},
|
|
364
378
|
"warehouse.view.read": {
|
|
365
379
|
"$ref": "#/definitions/AppModeViewOperation"
|
|
366
380
|
},
|
|
381
|
+
"warehouse.table.append": {
|
|
382
|
+
"$ref": "#/definitions/AppModeViewOperation"
|
|
383
|
+
},
|
|
367
384
|
"service.request": {
|
|
368
385
|
"$ref": "#/definitions/ServiceOperation"
|
|
369
386
|
}
|
|
@@ -389,6 +406,11 @@
|
|
|
389
406
|
"warehouse.view.read"
|
|
390
407
|
]
|
|
391
408
|
},
|
|
409
|
+
{
|
|
410
|
+
"required": [
|
|
411
|
+
"warehouse.table.append"
|
|
412
|
+
]
|
|
413
|
+
},
|
|
392
414
|
{
|
|
393
415
|
"required": [
|
|
394
416
|
"service.request"
|
|
@@ -568,6 +590,11 @@
|
|
|
568
590
|
"sharepoint.file.upload"
|
|
569
591
|
]
|
|
570
592
|
},
|
|
593
|
+
{
|
|
594
|
+
"required": [
|
|
595
|
+
"phone.sms.list"
|
|
596
|
+
]
|
|
597
|
+
},
|
|
571
598
|
{
|
|
572
599
|
"required": [
|
|
573
600
|
"service.request"
|
|
@@ -752,10 +779,20 @@
|
|
|
752
779
|
"sharepoint.file.upload"
|
|
753
780
|
]
|
|
754
781
|
},
|
|
782
|
+
{
|
|
783
|
+
"required": [
|
|
784
|
+
"phone.sms.list"
|
|
785
|
+
]
|
|
786
|
+
},
|
|
755
787
|
{
|
|
756
788
|
"required": [
|
|
757
789
|
"warehouse.view.read"
|
|
758
790
|
]
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
"required": [
|
|
794
|
+
"warehouse.table.append"
|
|
795
|
+
]
|
|
759
796
|
}
|
|
760
797
|
]
|
|
761
798
|
}
|
|
@@ -1008,6 +1045,17 @@
|
|
|
1008
1045
|
}
|
|
1009
1046
|
}
|
|
1010
1047
|
},
|
|
1048
|
+
"company-phone": {
|
|
1049
|
+
"kind": "saas",
|
|
1050
|
+
"operations": {
|
|
1051
|
+
"phone.sms.list": {
|
|
1052
|
+
"identity": "app",
|
|
1053
|
+
"resources": [
|
|
1054
|
+
"gstn-line"
|
|
1055
|
+
]
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
},
|
|
1011
1059
|
"sales-warehouse": {
|
|
1012
1060
|
"kind": "database",
|
|
1013
1061
|
"operations": {
|
|
@@ -1021,6 +1069,19 @@
|
|
|
1021
1069
|
]
|
|
1022
1070
|
}
|
|
1023
1071
|
}
|
|
1072
|
+
},
|
|
1073
|
+
"warehouse.table.append": {
|
|
1074
|
+
"identity": "app",
|
|
1075
|
+
"resources": {
|
|
1076
|
+
"esc_filings": {
|
|
1077
|
+
"access": "append",
|
|
1078
|
+
"columns": [
|
|
1079
|
+
"gstin",
|
|
1080
|
+
"period",
|
|
1081
|
+
"filed_at"
|
|
1082
|
+
]
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1024
1085
|
}
|
|
1025
1086
|
}
|
|
1026
1087
|
}
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
"status": { "$ref": "#/definitions/DataGrantV2Status" },
|
|
18
18
|
"operations": {
|
|
19
19
|
"type": "array",
|
|
20
|
-
"maxItems":
|
|
20
|
+
"maxItems": 32,
|
|
21
21
|
"uniqueItems": true,
|
|
22
22
|
"items": { "$ref": "app-integrations-declaration.schema.json#/definitions/IntegrationOperation" },
|
|
23
|
-
"description": "Approved operations; each must match this grant's mode. Empty until the first approval. At most the thirty-
|
|
23
|
+
"description": "Approved operations; each must match this grant's mode. Empty until the first approval. At most the thirty-two SaaS operations (0.82.0: eleven Slack and Gmail, eleven Basecamp, nine SharePoint, one phone); a database grant holds up to two (warehouse.view.read, warehouse.table.append)."
|
|
24
24
|
},
|
|
25
25
|
"resources": {
|
|
26
26
|
"type": "array",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"type": "object",
|
|
63
63
|
"additionalProperties": false,
|
|
64
64
|
"required": ["name"],
|
|
65
|
-
"description": "One approved logical resource: a Slack channel alias, the fixed Gmail `inbox` alias, a Basecamp project alias or the fixed Basecamp `account` alias (0.76.0), a SharePoint site alias (0.78.0), or a warehouse view alias with the approved columns.",
|
|
65
|
+
"description": "One approved logical resource: a Slack channel alias, the fixed Gmail `inbox` alias, a Basecamp project alias or the fixed Basecamp `account` alias (0.76.0), a SharePoint site alias (0.78.0), a phone number alias (0.82.0), or a warehouse view alias with the approved columns.",
|
|
66
66
|
"properties": {
|
|
67
67
|
"name": { "$ref": "app-integrations-declaration.schema.json#/definitions/IntegrationAlias" },
|
|
68
68
|
"columns": {
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"maxItems": 32,
|
|
72
72
|
"uniqueItems": true,
|
|
73
73
|
"items": { "$ref": "app-integrations-declaration.schema.json#/definitions/ColumnName" },
|
|
74
|
-
"description": "warehouse.view.read only: the approved columns of the view."
|
|
74
|
+
"description": "warehouse.view.read and warehouse.table.append only: the approved columns of the view."
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
},
|
|
@@ -359,13 +359,53 @@
|
|
|
359
359
|
"body": {
|
|
360
360
|
"type": "object",
|
|
361
361
|
"additionalProperties": true
|
|
362
|
+
},
|
|
363
|
+
"rows": {
|
|
364
|
+
"type": "array",
|
|
365
|
+
"minItems": 1,
|
|
366
|
+
"maxItems": 500,
|
|
367
|
+
"items": {
|
|
368
|
+
"type": "object",
|
|
369
|
+
"minProperties": 1,
|
|
370
|
+
"maxProperties": 64,
|
|
371
|
+
"additionalProperties": {
|
|
372
|
+
"oneOf": [
|
|
373
|
+
{
|
|
374
|
+
"type": "string",
|
|
375
|
+
"maxLength": 4000
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"type": "number"
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
"type": "boolean"
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
"type": "null"
|
|
385
|
+
}
|
|
386
|
+
]
|
|
387
|
+
},
|
|
388
|
+
"description": "One row keyed by column name, 1..64 columns; each value a string of at most 4000 characters, a number, a boolean or null. Which columns the alias approves, and whether a value fits its column type (the catalog's columnTypes, which only governance holds), is governance's check \u2014 the way warehouse.view.read's cross-field rules are."
|
|
389
|
+
},
|
|
390
|
+
"description": "warehouse.table.append (0.82.0): the rows to append, 1..500 of them, every one a record of the approved columns. Governance refuses an unapproved column, a value outside its column type and a request above 1 MB with ROW_VALUE_INVALID; nothing is coerced."
|
|
391
|
+
},
|
|
392
|
+
"since": {
|
|
393
|
+
"type": "string",
|
|
394
|
+
"minLength": 1,
|
|
395
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]{1,9})?(Z|[+-][0-9]{2}:[0-9]{2})$",
|
|
396
|
+
"description": "phone.sms.list (0.82.0): the ISO 8601 date-time (with a zone) after which received messages are listed; inclusive. Messages are kept for 30 minutes, so an older `since` lists what is still held."
|
|
397
|
+
},
|
|
398
|
+
"from": {
|
|
399
|
+
"type": "string",
|
|
400
|
+
"maxLength": 32,
|
|
401
|
+
"description": "phone.sms.list (0.82.0): only messages from this sender id or number (as the provider reports it, e.g. `VK-GSTNIN` or `+919876543210`); absent lists every sender."
|
|
362
402
|
}
|
|
363
403
|
}
|
|
364
404
|
},
|
|
365
405
|
"idempotencyKey": {
|
|
366
406
|
"type": "string",
|
|
367
407
|
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
|
|
368
|
-
"description": "UUID of one explicit Send action; required for the sends (slack.message.post, slack.dm.send, gmail.message.send), the receipted Basecamp writes (basecamp.todo.create, basecamp.message.post, basecamp.comment.post, basecamp.campfire.post; 0.76.0)
|
|
408
|
+
"description": "UUID of one explicit Send action; required for the sends (slack.message.post, slack.dm.send, gmail.message.send), the receipted Basecamp writes (basecamp.todo.create, basecamp.message.post, basecamp.comment.post, basecamp.campfire.post; 0.76.0) the receipted SharePoint writes (sharepoint.item.create, sharepoint.file.upload; 0.78.0) and the receipted warehouse append (warehouse.table.append; 0.82.0, where it is also the BigQuery load job id), refused everywhere else. The same key with the same payload and subject returns the recorded outcome for seven days."
|
|
369
409
|
},
|
|
370
410
|
"mode": {
|
|
371
411
|
"$ref": "app-integrations-declaration.schema.json#/definitions/IntegrationIdentityMode",
|
|
@@ -1494,6 +1534,65 @@
|
|
|
1494
1534
|
"resource"
|
|
1495
1535
|
]
|
|
1496
1536
|
}
|
|
1537
|
+
},
|
|
1538
|
+
{
|
|
1539
|
+
"if": {
|
|
1540
|
+
"properties": {
|
|
1541
|
+
"operation": {
|
|
1542
|
+
"const": "phone.sms.list"
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
},
|
|
1546
|
+
"then": {
|
|
1547
|
+
"x-read-only": true,
|
|
1548
|
+
"not": {
|
|
1549
|
+
"required": [
|
|
1550
|
+
"idempotencyKey"
|
|
1551
|
+
]
|
|
1552
|
+
},
|
|
1553
|
+
"properties": {
|
|
1554
|
+
"mode": false,
|
|
1555
|
+
"input": {
|
|
1556
|
+
"propertyNames": {
|
|
1557
|
+
"enum": [
|
|
1558
|
+
"since",
|
|
1559
|
+
"from"
|
|
1560
|
+
]
|
|
1561
|
+
},
|
|
1562
|
+
"required": [
|
|
1563
|
+
"since"
|
|
1564
|
+
]
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
},
|
|
1569
|
+
{
|
|
1570
|
+
"if": {
|
|
1571
|
+
"properties": {
|
|
1572
|
+
"operation": {
|
|
1573
|
+
"const": "warehouse.table.append"
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
},
|
|
1577
|
+
"then": {
|
|
1578
|
+
"x-read-only": false,
|
|
1579
|
+
"required": [
|
|
1580
|
+
"idempotencyKey"
|
|
1581
|
+
],
|
|
1582
|
+
"properties": {
|
|
1583
|
+
"mode": false,
|
|
1584
|
+
"input": {
|
|
1585
|
+
"propertyNames": {
|
|
1586
|
+
"enum": [
|
|
1587
|
+
"rows"
|
|
1588
|
+
]
|
|
1589
|
+
},
|
|
1590
|
+
"required": [
|
|
1591
|
+
"rows"
|
|
1592
|
+
]
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1497
1596
|
}
|
|
1498
1597
|
],
|
|
1499
1598
|
"definitions": {
|
|
@@ -2193,6 +2292,35 @@
|
|
|
2193
2292
|
"conflict": "replace"
|
|
2194
2293
|
},
|
|
2195
2294
|
"idempotencyKey": "6f1c2c1e-3a1c-4c3e-9f0e-2b6f7d8a9c21"
|
|
2295
|
+
},
|
|
2296
|
+
{
|
|
2297
|
+
"connection": "company-phone",
|
|
2298
|
+
"operation": "phone.sms.list",
|
|
2299
|
+
"resource": "gstn-line",
|
|
2300
|
+
"input": {
|
|
2301
|
+
"since": "2026-10-17T09:30:00Z",
|
|
2302
|
+
"from": "VK-GSTNIN"
|
|
2303
|
+
}
|
|
2304
|
+
},
|
|
2305
|
+
{
|
|
2306
|
+
"connection": "sales-warehouse",
|
|
2307
|
+
"operation": "warehouse.table.append",
|
|
2308
|
+
"resource": "esc_filings",
|
|
2309
|
+
"input": {
|
|
2310
|
+
"rows": [
|
|
2311
|
+
{
|
|
2312
|
+
"gstin": "27AAPFU0939F1ZV",
|
|
2313
|
+
"period": "2026-09",
|
|
2314
|
+
"filed_at": "2026-10-17T09:31:12Z"
|
|
2315
|
+
},
|
|
2316
|
+
{
|
|
2317
|
+
"gstin": "29AABCT1332L1ZT",
|
|
2318
|
+
"period": "2026-09",
|
|
2319
|
+
"filed_at": null
|
|
2320
|
+
}
|
|
2321
|
+
]
|
|
2322
|
+
},
|
|
2323
|
+
"idempotencyKey": "6f1c2c1e-3a1c-4c3e-9f0e-2b6f7d8a9c22"
|
|
2196
2324
|
}
|
|
2197
2325
|
]
|
|
2198
2326
|
}
|
|
@@ -27,6 +27,17 @@
|
|
|
27
27
|
"routingStoreArn": {"type": "string", "minLength": 1, "description": "The cell's CloudFront KeyValueStore ARN; equals edge.routingStoreArn unless the cell record names its own."},
|
|
28
28
|
"pageHost": {"type": "string", "format": "hostname", "description": "Bare hostname of frontendUrl."},
|
|
29
29
|
"apiHost": {"type": "string", "format": "hostname", "description": "Bare hostname of apiUrl."},
|
|
30
|
+
"networkAccess": {
|
|
31
|
+
"type": "object", "additionalProperties": false,
|
|
32
|
+
"description": "Present only while the tenant enforces a network access policy (governance ADR 0130): the effective list of client ranges the app's gateway SecurityPolicy allows, the tenant's ranges plus the platform cell's own egress, as textual CIDRs. Absent means every network.",
|
|
33
|
+
"required": ["clientCidrs"],
|
|
34
|
+
"properties": {
|
|
35
|
+
"clientCidrs": {
|
|
36
|
+
"type": "array", "minItems": 1, "maxItems": 128, "uniqueItems": true,
|
|
37
|
+
"items": {"type": "string", "pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}/(?:3[0-2]|[12]?[0-9])|(?=[0-9a-fA-F.]*:)[0-9a-fA-F:.]{2,45}/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))$", "description": "IPv4 `a.b.c.d/n` or IPv6 `addr/n`, each with an explicit prefix; `/0` is never produced."}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
30
41
|
"companyDomain": {
|
|
31
42
|
"type": "object", "additionalProperties": false,
|
|
32
43
|
"description": "Present only when source is tenant: the ready delegated company zone the page and API hosts live under, and the shared gateway/TLS secret the cell serves it with.",
|