@isomorph.ai/app-sdk 1.19.0 → 1.21.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 +111 -0
- package/dist/index.d.ts +770 -4
- package/dist/index.js +4 -4
- package/dist/integration-execute-input-rules.d.ts +1195 -1
- package/dist/integration-execute-input-rules.js +393 -1
- package/dist/integration-operations.d.ts +315 -0
- package/dist/integration-operations.js +405 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -215,6 +215,117 @@ await isomorph.integrations.execute('company-sharepoint', {
|
|
|
215
215
|
|
|
216
216
|
(1.16.0; contracts 0.78.0)
|
|
217
217
|
|
|
218
|
+
Google Workspace — Calendar, Drive, Docs and Sheets — runs as the signed-in
|
|
219
|
+
person after their consent, on the person's own data: there is nothing for IT
|
|
220
|
+
to map, so every operation names the provider's one fixed alias (`primary`,
|
|
221
|
+
`my-drive`, `my-docs`, `my-sheets`). Creating an event, folder, document or
|
|
222
|
+
spreadsheet, uploading a file or appending rows is an explicit action with a
|
|
223
|
+
fresh UUID; an update, cancel, append to a document, replace or clear has one
|
|
224
|
+
outcome however often it runs and needs none. A Sheet used as a small table:
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
// The person's week, then one event they created
|
|
228
|
+
const week = await isomorph.integrations.execute('company-calendar', {
|
|
229
|
+
operation: 'calendar.event.list', resource: 'primary',
|
|
230
|
+
input: { timeMin: '2026-10-20T00:00:00+05:30', timeMax: '2026-10-27T00:00:00+05:30' },
|
|
231
|
+
});
|
|
232
|
+
const walkthrough = await isomorph.integrations.execute('company-calendar', {
|
|
233
|
+
operation: 'calendar.event.create', resource: 'primary',
|
|
234
|
+
input: { title: 'Venue walkthrough', start: '2026-10-20T09:30:00+05:30', end: '2026-10-20T10:30:00+05:30', timeZone: 'Asia/Kolkata', attendees: ['jane@example.com'] },
|
|
235
|
+
idempotencyKey: crypto.randomUUID(),
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// A Sheet as a table: read the header and rows, append two, overwrite one cell
|
|
239
|
+
const orders = await isomorph.integrations.execute('company-sheets', {
|
|
240
|
+
operation: 'sheets.values.read', resource: 'my-sheets',
|
|
241
|
+
input: { spreadsheetId: '1FixtureSpreadsheetB1cD2eF3gH4iJ5kL6mN7o', range: 'Orders!A1:D' },
|
|
242
|
+
});
|
|
243
|
+
const [header, ...rows] = orders.values; // each cell a string, a number, a boolean or null
|
|
244
|
+
await isomorph.integrations.execute('company-sheets', {
|
|
245
|
+
operation: 'sheets.values.append', resource: 'my-sheets',
|
|
246
|
+
input: { spreadsheetId: '1FixtureSpreadsheetB1cD2eF3gH4iJ5kL6mN7o', range: 'Orders!A:D', values: [['Acme', 3, false, '2026-10-20'], ['Globex', 1, true, null]] },
|
|
247
|
+
idempotencyKey: crypto.randomUUID(),
|
|
248
|
+
});
|
|
249
|
+
await isomorph.integrations.execute('company-sheets', {
|
|
250
|
+
operation: 'sheets.values.update', resource: 'my-sheets',
|
|
251
|
+
input: { spreadsheetId: '1FixtureSpreadsheetB1cD2eF3gH4iJ5kL6mN7o', range: 'Orders!C2', values: [[true]] },
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// A Doc from a template: read it, fill the placeholders, append the decisions
|
|
255
|
+
const minutes = await isomorph.integrations.execute('company-docs', {
|
|
256
|
+
operation: 'docs.document.create', resource: 'my-docs',
|
|
257
|
+
input: { title: 'Venue minutes', text: 'Customer: {{customer}}\n' }, idempotencyKey: crypto.randomUUID(),
|
|
258
|
+
});
|
|
259
|
+
await isomorph.integrations.execute('company-docs', {
|
|
260
|
+
operation: 'docs.text.replace', resource: 'my-docs',
|
|
261
|
+
input: { documentId: minutes.id, replacements: [{ find: '{{customer}}', replace: 'Acme' }] },
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Drive: a search, one file's bytes (a Google Doc exported as pdf), an upload into a new folder
|
|
265
|
+
const found = await isomorph.integrations.execute('company-drive', {
|
|
266
|
+
operation: 'drive.file.search', resource: 'my-drive', input: { q: 'venue contract' },
|
|
267
|
+
});
|
|
268
|
+
const contract = await isomorph.integrations.execute('company-drive', {
|
|
269
|
+
operation: 'drive.file.read', resource: 'my-drive', input: { fileId: found.files[0].id, exportAs: 'pdf' },
|
|
270
|
+
});
|
|
271
|
+
const folder = await isomorph.integrations.execute('company-drive', {
|
|
272
|
+
operation: 'drive.folder.create', resource: 'my-drive', input: { title: 'Signed' }, idempotencyKey: crypto.randomUUID(),
|
|
273
|
+
});
|
|
274
|
+
await isomorph.integrations.execute('company-drive', {
|
|
275
|
+
operation: 'drive.file.upload', resource: 'my-drive',
|
|
276
|
+
input: { filename: contract.filename, contentType: contract.mimeType, dataBase64: contract.dataBase64, folderId: folder.id },
|
|
277
|
+
idempotencyKey: crypto.randomUUID(),
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Microsoft 365 — Outlook, OneDrive, Excel and Teams — runs as the signed-in
|
|
282
|
+
person the same way. Outlook, OneDrive and Excel act on the person's own
|
|
283
|
+
mailbox, drive and workbooks on a fixed alias (`inbox`, `my-drive`,
|
|
284
|
+
`my-workbooks`); Teams is the exception: like Slack, every operation names a
|
|
285
|
+
channel alias IT mapped to one channel of one team. Ids are opaque Microsoft
|
|
286
|
+
Graph ids. A send, reply, post, upload, folder or worksheet create and a table
|
|
287
|
+
row add are explicit actions with a fresh UUID; an event update or cancel and
|
|
288
|
+
a range update need none. An Excel workbook is the same small table:
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
// Unread mail about the venue, one message's text, a reply
|
|
292
|
+
const mail = await isomorph.integrations.execute('company-outlook', {
|
|
293
|
+
operation: 'outlook.message.list', resource: 'inbox', input: { q: 'venue' },
|
|
294
|
+
});
|
|
295
|
+
const message = await isomorph.integrations.execute('company-outlook', {
|
|
296
|
+
operation: 'outlook.message.read', resource: 'inbox', input: { messageId: mail.mailMessages[0].id },
|
|
297
|
+
});
|
|
298
|
+
await isomorph.integrations.execute('company-outlook', {
|
|
299
|
+
operation: 'outlook.message.reply', resource: 'inbox',
|
|
300
|
+
input: { messageId: message.id, text: 'Confirmed for Monday.' }, idempotencyKey: crypto.randomUUID(),
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// The workbook's tables, then two rows added to one of them
|
|
304
|
+
const { files } = await isomorph.integrations.execute('company-onedrive', {
|
|
305
|
+
operation: 'onedrive.file.search', resource: 'my-drive', input: { q: 'orders.xlsx' },
|
|
306
|
+
});
|
|
307
|
+
const { tables } = await isomorph.integrations.execute('company-excel', {
|
|
308
|
+
operation: 'excel.table.list', resource: 'my-workbooks', input: { fileId: files[0].id },
|
|
309
|
+
});
|
|
310
|
+
await isomorph.integrations.execute('company-excel', {
|
|
311
|
+
operation: 'excel.row.add', resource: 'my-workbooks',
|
|
312
|
+
input: { fileId: files[0].id, tableName: tables[0].name, values: [['Acme', 3, false], ['Globex', 1, true]] },
|
|
313
|
+
idempotencyKey: crypto.randomUUID(),
|
|
314
|
+
});
|
|
315
|
+
const range = await isomorph.integrations.execute('company-excel', {
|
|
316
|
+
operation: 'excel.range.read', resource: 'my-workbooks', input: { fileId: files[0].id, worksheet: tables[0].worksheet },
|
|
317
|
+
}); // range.address is what Excel answered, range.values the grid
|
|
318
|
+
|
|
319
|
+
// A summary to the mapped Teams channel
|
|
320
|
+
await isomorph.integrations.execute('company-teams', {
|
|
321
|
+
operation: 'teams.message.post', resource: 'project-updates',
|
|
322
|
+
input: { text: `Venue confirmed; ${range.values.length - 1} orders on the sheet.` },
|
|
323
|
+
idempotencyKey: crypto.randomUUID(),
|
|
324
|
+
});
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
(1.21.0; contracts 0.86.0)
|
|
328
|
+
|
|
218
329
|
## Trusted actions
|
|
219
330
|
|
|
220
331
|
A normal action runs with the signed-in person's rights, so a rule in it is advice: whatever it may write, the browser may write directly. A business rule that must hold goes in a trusted action: `export const trusted = true;` beside the default export. Its data calls run as the app on behalf of the caller (the database sees `harbour.user_id = 'workload:…'` and `harbour.on_behalf_of` = the person, with the person's email, groups and role), so the tables it writes give people no write rule (`WITH CHECK (current_setting('harbour.user_id', true) LIKE 'workload:%')`). `ctx.transaction(fn)` runs every call inside `fn` as one database transaction, committed when `fn` returns and rolled back when it throws; `.forUpdate()` on a select locks the row until then. A thrown `Error` with `code` (an error category such as `FORBIDDEN` or `CONFLICT`) and `message` reaches the page with that status and text.
|