@tangle-network/agent-integrations 0.37.0 → 0.39.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.
Files changed (49) hide show
  1. package/README.md +1 -1
  2. package/dist/catalog.d.ts +2 -2
  3. package/dist/catalog.js +7 -7
  4. package/dist/{chunk-YV3O5SO2.js → chunk-6MUBOVI4.js} +1839 -1587
  5. package/dist/chunk-6MUBOVI4.js.map +1 -0
  6. package/dist/{chunk-O553GSCX.js → chunk-FAFQZJPZ.js} +2 -2
  7. package/dist/{chunk-53NQJZAT.js → chunk-IA5GCKM6.js} +2 -3
  8. package/dist/chunk-IA5GCKM6.js.map +1 -0
  9. package/dist/{chunk-CR35IEKW.js → chunk-IKCXDQVP.js} +2 -2
  10. package/dist/{chunk-ZDK7Y4QG.js → chunk-OMLQCESJ.js} +1 -1
  11. package/dist/chunk-OMLQCESJ.js.map +1 -0
  12. package/dist/{chunk-SPLJV5J7.js → chunk-P3RWMLK3.js} +6 -4
  13. package/dist/{chunk-SPLJV5J7.js.map → chunk-P3RWMLK3.js.map} +1 -1
  14. package/dist/{chunk-D57YS6XC.js → chunk-TC5OMANJ.js} +2 -2
  15. package/dist/connect/index.d.ts +2 -2
  16. package/dist/connect/index.js +2 -2
  17. package/dist/connectors/adapters/index.d.ts +89 -96
  18. package/dist/connectors/adapters/index.js +8 -12
  19. package/dist/connectors/index.d.ts +3 -3
  20. package/dist/connectors/index.js +8 -12
  21. package/dist/{consumer-Dzt2uOo_.d.ts → consumer-Cxcpp_bi.d.ts} +1 -1
  22. package/dist/consumer.d.ts +3 -3
  23. package/dist/consumer.js +2 -2
  24. package/dist/{core-types-D4MGC44S.d.ts → core-types-DMDmeutI.d.ts} +1 -1
  25. package/dist/coverage-catalog.d.ts +2 -2
  26. package/dist/{importers-DANyqwIT.d.ts → importers-BAVOQvUf.d.ts} +1 -1
  27. package/dist/index.d.ts +9 -9
  28. package/dist/index.js +13 -17
  29. package/dist/mcp.d.ts +3 -3
  30. package/dist/mcp.js +7 -7
  31. package/dist/middleware/index.d.ts +2 -2
  32. package/dist/middleware/index.js +2 -2
  33. package/dist/registry.d.ts +2 -2
  34. package/dist/registry.js +7 -7
  35. package/dist/runtime.d.ts +2 -2
  36. package/dist/runtime.js +7 -7
  37. package/dist/specs.d.ts +2 -2
  38. package/dist/specs.js +1 -1
  39. package/dist/{tangle-id-hDDWP-2f.d.ts → tangle-id-BMScmNjp.d.ts} +1 -1
  40. package/dist/{types-Bxg-wJkW.d.ts → types-eAvAgnKr.d.ts} +4 -0
  41. package/docs/adapter-triage.md +3 -3
  42. package/docs/catalog-registry.md +1 -1
  43. package/package.json +1 -1
  44. package/dist/chunk-53NQJZAT.js.map +0 -1
  45. package/dist/chunk-YV3O5SO2.js.map +0 -1
  46. package/dist/chunk-ZDK7Y4QG.js.map +0 -1
  47. /package/dist/{chunk-O553GSCX.js.map → chunk-FAFQZJPZ.js.map} +0 -0
  48. /package/dist/{chunk-CR35IEKW.js.map → chunk-IKCXDQVP.js.map} +0 -0
  49. /package/dist/{chunk-D57YS6XC.js.map → chunk-TC5OMANJ.js.map} +0 -0
@@ -12,7 +12,7 @@ import {
12
12
  TangleIdentityUnreachableError,
13
13
  createTangleIdentityClient,
14
14
  tangleIdentity
15
- } from "./chunk-ZDK7Y4QG.js";
15
+ } from "./chunk-OMLQCESJ.js";
16
16
  import {
17
17
  __export
18
18
  } from "./chunk-PZ5AY32C.js";
@@ -196,6 +196,7 @@ __export(adapters_exports, {
196
196
  gitlabConnector: () => gitlabConnector,
197
197
  glideConnector: () => glideConnector,
198
198
  gmail: () => gmail,
199
+ googleAnalyticsConnector: () => googleAnalyticsConnector,
199
200
  googleBigqueryConnector: () => googleBigqueryConnector,
200
201
  googleCalendar: () => googleCalendar,
201
202
  googleCloudStorageConnector: () => googleCloudStorageConnector,
@@ -204,6 +205,7 @@ __export(adapters_exports, {
204
205
  googleDrive: () => googleDrive,
205
206
  googleForms: () => googleForms,
206
207
  googleGeminiConnector: () => googleGeminiConnector,
208
+ googleMeetConnector: () => googleMeetConnector,
207
209
  googleMyBusinessConnector: () => googleMyBusinessConnector,
208
210
  googleSearchConnector: () => googleSearchConnector,
209
211
  googleSearchConsoleConnector: () => googleSearchConsoleConnector,
@@ -319,12 +321,8 @@ __export(adapters_exports, {
319
321
  microsoftDynamicsCrmConnector: () => microsoftDynamicsCrmConnector,
320
322
  microsoftExcel365Connector: () => microsoftExcel365Connector,
321
323
  microsoftGraph: () => microsoftGraph,
322
- microsoftOnedriveConnector: () => microsoftOnedriveConnector,
323
324
  microsoftOnenoteConnector: () => microsoftOnenoteConnector,
324
- microsoftOutlookCalendarConnector: () => microsoftOutlookCalendarConnector,
325
- microsoftOutlookConnector: () => microsoftOutlookConnector,
326
325
  microsoftPowerBiConnector: () => microsoftPowerBiConnector,
327
- microsoftSharepointConnector: () => microsoftSharepointConnector,
328
326
  microsoftTeams: () => microsoftTeams,
329
327
  microsoftTodoConnector: () => microsoftTodoConnector,
330
328
  millionverifierConnector: () => millionverifierConnector,
@@ -342,8 +340,8 @@ __export(adapters_exports, {
342
340
  niftyConnector: () => niftyConnector,
343
341
  ninjapipeConnector: () => ninjapipeConnector,
344
342
  nocodbConnector: () => nocodbConnector,
343
+ notion: () => notion,
345
344
  notionConnector: () => notionConnector,
346
- notionDatabase: () => notionDatabase,
347
345
  ntfyConnector: () => ntfyConnector,
348
346
  odooConnector: () => odooConnector,
349
347
  omniCoConnector: () => omniCoConnector,
@@ -3134,91 +3132,253 @@ function microsoftCalendar(opts) {
3134
3132
  attendees: {
3135
3133
  type: "array",
3136
3134
  items: { type: "string", description: "attendee email" }
3137
- }
3135
+ },
3136
+ // Optional rich create fields (ported from microsoft-outlook-calendar
3137
+ // create.event). All additive — the freebusy pre-flight and
3138
+ // alternative-slot behavior below is unchanged when these are absent.
3139
+ calendarId: {
3140
+ type: "string",
3141
+ description: "Target calendar id; defaults to the user's primary calendar (/me/events) when omitted."
3142
+ },
3143
+ location: {
3144
+ type: "object",
3145
+ description: 'Graph location resource, e.g. { displayName: "Room 1" }.'
3146
+ },
3147
+ recurrence: {
3148
+ type: "object",
3149
+ description: "Graph patternedRecurrence resource ({ pattern, range })."
3150
+ },
3151
+ isOnlineMeeting: { type: "boolean", description: "Provision an online meeting (Teams) for the event." },
3152
+ onlineMeetingProvider: {
3153
+ type: "string",
3154
+ description: "Online meeting provider, e.g. 'teamsForBusiness'."
3155
+ },
3156
+ reminderMinutesBeforeStart: {
3157
+ type: "integer",
3158
+ description: "Minutes before start to fire the reminder."
3159
+ },
3160
+ isAllDay: { type: "boolean", description: "Mark the event as all-day (start/end must be midnight-aligned)." },
3161
+ categories: {
3162
+ type: "array",
3163
+ items: { type: "string", description: "Outlook category name" }
3164
+ },
3165
+ importance: { type: "string", description: "Event importance: 'low' | 'normal' | 'high'." }
3138
3166
  },
3139
3167
  required: ["start", "end", "summary"]
3140
3168
  }
3169
+ },
3170
+ {
3171
+ name: "delete_event",
3172
+ class: "mutation",
3173
+ description: "Delete an event by id from the connected Outlook calendar. Graph returns 204 on success; a re-delete of a missing event surfaces as 404 mapped to an idempotent tombstone. Honors If-Match against the event etag when the caller supplies expectedEtag.",
3174
+ cas: "native-idempotency",
3175
+ externalEffect: true,
3176
+ parameters: {
3177
+ type: "object",
3178
+ properties: {
3179
+ eventId: { type: "string", description: "Graph event id to delete." }
3180
+ },
3181
+ required: ["eventId"]
3182
+ }
3183
+ },
3184
+ {
3185
+ name: "list_events",
3186
+ class: "read",
3187
+ description: "List actual event objects on a calendar with OData paging/filtering ($top, $skip, $filter, $select, $orderby, $search). Targets the user's primary calendar (/me/events) unless calendarId is supplied. Distinct from list_availability, which returns busy windows.",
3188
+ parameters: {
3189
+ type: "object",
3190
+ properties: {
3191
+ calendarId: { type: "string", description: "Calendar id; defaults to the user's primary calendar when omitted." },
3192
+ $top: { type: "integer", description: "Max events to return (OData page size)." },
3193
+ $skip: { type: "integer", description: "Number of events to skip (OData paging offset)." },
3194
+ $filter: { type: "string", description: "OData $filter expression." },
3195
+ $select: { type: "string", description: "Comma-separated event fields to project." },
3196
+ $orderby: { type: "string", description: "OData $orderby expression." },
3197
+ $search: { type: "string", description: "OData $search query." }
3198
+ }
3199
+ }
3141
3200
  }
3142
3201
  ]
3143
3202
  },
3144
3203
  async executeRead(inv) {
3145
- if (inv.capabilityName !== "list_availability") {
3146
- throw new Error(`microsoft-calendar: unknown read capability ${inv.capabilityName}`);
3147
- }
3148
- const userPrincipal = readMetaString2(inv.source.metadata, "userPrincipal");
3149
- const { timeMin, timeMax } = inv.args;
3150
3204
  const accessToken = await ensureFreshAccessToken5(inv.source.credentials, clientId, clientSecret);
3151
- const busy = await getScheduleBusy({ accessToken, userPrincipal, timeMin, timeMax });
3152
- return {
3153
- data: { busy },
3154
- fetchedAt: Date.now()
3155
- };
3205
+ if (inv.capabilityName === "list_availability") {
3206
+ const userPrincipal = readMetaString2(inv.source.metadata, "userPrincipal");
3207
+ const { timeMin, timeMax } = inv.args;
3208
+ const busy = await getScheduleBusy({ accessToken, userPrincipal, timeMin, timeMax });
3209
+ return {
3210
+ data: { busy },
3211
+ fetchedAt: Date.now()
3212
+ };
3213
+ }
3214
+ if (inv.capabilityName === "list_events") {
3215
+ const {
3216
+ calendarId,
3217
+ $top,
3218
+ $skip,
3219
+ $filter,
3220
+ $select,
3221
+ $orderby,
3222
+ $search
3223
+ } = inv.args;
3224
+ const base = calendarId ? `https://graph.microsoft.com/v1.0/me/calendars/${encodeURIComponent(calendarId)}/events` : "https://graph.microsoft.com/v1.0/me/events";
3225
+ const qs = new URLSearchParams();
3226
+ if ($top !== void 0) qs.set("$top", String($top));
3227
+ if ($skip !== void 0) qs.set("$skip", String($skip));
3228
+ if ($filter) qs.set("$filter", $filter);
3229
+ if ($select) qs.set("$select", $select);
3230
+ if ($orderby) qs.set("$orderby", $orderby);
3231
+ if ($search) qs.set("$search", $search);
3232
+ const query = qs.toString();
3233
+ const url = query ? `${base}?${query}` : base;
3234
+ const res = await fetch(url, {
3235
+ headers: { authorization: `Bearer ${accessToken}` },
3236
+ signal: AbortSignal.timeout(15e3)
3237
+ });
3238
+ if (res.status === 401 || res.status === 403) {
3239
+ throw new CredentialsExpired(`Microsoft Graph rejected token (${res.status})`, inv.source.id);
3240
+ }
3241
+ if (!res.ok) {
3242
+ const text = await res.text().catch(() => "");
3243
+ throw new Error(`microsoft-calendar list_events ${res.status}: ${text.slice(0, 200)}`);
3244
+ }
3245
+ const json = await res.json();
3246
+ return {
3247
+ data: { events: json.value ?? [], nextLink: json["@odata.nextLink"] },
3248
+ fetchedAt: Date.now()
3249
+ };
3250
+ }
3251
+ throw new Error(`microsoft-calendar: unknown read capability ${inv.capabilityName}`);
3156
3252
  },
3157
3253
  async executeMutation(inv) {
3158
- if (inv.capabilityName !== "book_slot") {
3159
- throw new Error(`microsoft-calendar: unknown mutation capability ${inv.capabilityName}`);
3160
- }
3161
- const userPrincipal = readMetaString2(inv.source.metadata, "userPrincipal");
3162
- const { start, end, summary, description, attendees } = inv.args;
3163
3254
  const accessToken = await ensureFreshAccessToken5(inv.source.credentials, clientId, clientSecret);
3164
- const busy = await getScheduleBusy({ accessToken, userPrincipal, timeMin: start, timeMax: end });
3165
- if (busy.length > 0) {
3166
- const startMs = Date.parse(start);
3167
- const endMs = Date.parse(end);
3168
- const durMs = endMs - startMs;
3169
- const alternatives = await findNextFreeSlots2({
3170
- accessToken,
3171
- userPrincipal,
3172
- searchFromMs: endMs,
3173
- durationMs: durMs,
3174
- wanted: 3
3255
+ if (inv.capabilityName === "book_slot") {
3256
+ const userPrincipal = readMetaString2(inv.source.metadata, "userPrincipal");
3257
+ const {
3258
+ start,
3259
+ end,
3260
+ summary,
3261
+ description,
3262
+ attendees,
3263
+ calendarId,
3264
+ location,
3265
+ recurrence,
3266
+ isOnlineMeeting,
3267
+ onlineMeetingProvider,
3268
+ reminderMinutesBeforeStart,
3269
+ isAllDay,
3270
+ categories,
3271
+ importance
3272
+ } = inv.args;
3273
+ const busy = await getScheduleBusy({ accessToken, userPrincipal, timeMin: start, timeMax: end });
3274
+ if (busy.length > 0) {
3275
+ const startMs = Date.parse(start);
3276
+ const endMs = Date.parse(end);
3277
+ const durMs = endMs - startMs;
3278
+ const alternatives = await findNextFreeSlots2({
3279
+ accessToken,
3280
+ userPrincipal,
3281
+ searchFromMs: endMs,
3282
+ durationMs: durMs,
3283
+ wanted: 3
3284
+ });
3285
+ throw new ResourceContention(
3286
+ `requested slot ${start}\u2013${end} is no longer free`,
3287
+ alternatives,
3288
+ { busy }
3289
+ );
3290
+ }
3291
+ const event = {
3292
+ subject: summary,
3293
+ body: description ? { contentType: "text", content: description } : void 0,
3294
+ start: { dateTime: start, timeZone: "UTC" },
3295
+ end: { dateTime: end, timeZone: "UTC" },
3296
+ attendees: attendees?.map((email) => ({
3297
+ emailAddress: { address: email },
3298
+ type: "required"
3299
+ }))
3300
+ };
3301
+ if (location !== void 0) event.location = location;
3302
+ if (recurrence !== void 0) event.recurrence = recurrence;
3303
+ if (isOnlineMeeting !== void 0) event.isOnlineMeeting = isOnlineMeeting;
3304
+ if (onlineMeetingProvider !== void 0) event.onlineMeetingProvider = onlineMeetingProvider;
3305
+ if (reminderMinutesBeforeStart !== void 0) event.reminderMinutesBeforeStart = reminderMinutesBeforeStart;
3306
+ if (isAllDay !== void 0) event.isAllDay = isAllDay;
3307
+ if (categories !== void 0) event.categories = categories;
3308
+ if (importance !== void 0) event.importance = importance;
3309
+ const url = calendarId ? `https://graph.microsoft.com/v1.0/me/calendars/${encodeURIComponent(calendarId)}/events` : "https://graph.microsoft.com/v1.0/me/events";
3310
+ const res = await fetch(url, {
3311
+ method: "POST",
3312
+ headers: {
3313
+ authorization: `Bearer ${accessToken}`,
3314
+ "content-type": "application/json"
3315
+ },
3316
+ body: JSON.stringify(event),
3317
+ signal: AbortSignal.timeout(15e3)
3175
3318
  });
3176
- throw new ResourceContention(
3177
- `requested slot ${start}\u2013${end} is no longer free`,
3178
- alternatives,
3179
- { busy }
3180
- );
3181
- }
3182
- const event = {
3183
- subject: summary,
3184
- body: description ? { contentType: "text", content: description } : void 0,
3185
- start: { dateTime: start, timeZone: "UTC" },
3186
- end: { dateTime: end, timeZone: "UTC" },
3187
- attendees: attendees?.map((email) => ({
3188
- emailAddress: { address: email },
3189
- type: "required"
3190
- }))
3191
- };
3192
- const res = await fetch("https://graph.microsoft.com/v1.0/me/events", {
3193
- method: "POST",
3194
- headers: {
3195
- authorization: `Bearer ${accessToken}`,
3196
- "content-type": "application/json"
3197
- },
3198
- body: JSON.stringify(event),
3199
- signal: AbortSignal.timeout(15e3)
3200
- });
3201
- if (res.status === 401 || res.status === 403) {
3202
- throw new CredentialsExpired(`Microsoft Graph rejected token (${res.status})`, inv.source.id);
3319
+ if (res.status === 401 || res.status === 403) {
3320
+ throw new CredentialsExpired(`Microsoft Graph rejected token (${res.status})`, inv.source.id);
3321
+ }
3322
+ if (res.status === 412 || res.status === 409) {
3323
+ throw new ResourceContention(
3324
+ `Microsoft Graph reported conflict on book_slot (${res.status})`,
3325
+ []
3326
+ );
3327
+ }
3328
+ if (!res.ok) {
3329
+ const text = await res.text().catch(() => "");
3330
+ throw new Error(`microsoft-calendar book_slot ${res.status}: ${text.slice(0, 200)}`);
3331
+ }
3332
+ const created = await res.json();
3333
+ return {
3334
+ status: "committed",
3335
+ data: { eventId: created.id, webLink: created.webLink },
3336
+ etagAfter: created["@odata.etag"],
3337
+ committedAt: Date.now(),
3338
+ idempotentReplay: false
3339
+ };
3203
3340
  }
3204
- if (res.status === 412 || res.status === 409) {
3205
- throw new ResourceContention(
3206
- `Microsoft Graph reported conflict on book_slot (${res.status})`,
3207
- []
3341
+ if (inv.capabilityName === "delete_event") {
3342
+ const { eventId } = inv.args;
3343
+ const headers = { authorization: `Bearer ${accessToken}` };
3344
+ if (inv.expectedEtag) headers["if-match"] = inv.expectedEtag;
3345
+ const res = await fetch(
3346
+ `https://graph.microsoft.com/v1.0/me/events/${encodeURIComponent(eventId)}`,
3347
+ {
3348
+ method: "DELETE",
3349
+ headers,
3350
+ signal: AbortSignal.timeout(15e3)
3351
+ }
3208
3352
  );
3353
+ if (res.status === 401 || res.status === 403) {
3354
+ throw new CredentialsExpired(`Microsoft Graph rejected token (${res.status})`, inv.source.id);
3355
+ }
3356
+ if (res.status === 412 || res.status === 409) {
3357
+ throw new ResourceContention(
3358
+ `Microsoft Graph reported conflict on delete_event (${res.status})`,
3359
+ []
3360
+ );
3361
+ }
3362
+ if (res.status === 404) {
3363
+ return {
3364
+ status: "committed",
3365
+ data: { eventId, deleted: true, alreadyMissing: true },
3366
+ committedAt: Date.now(),
3367
+ idempotentReplay: true
3368
+ };
3369
+ }
3370
+ if (!res.ok) {
3371
+ const text = await res.text().catch(() => "");
3372
+ throw new Error(`microsoft-calendar delete_event ${res.status}: ${text.slice(0, 200)}`);
3373
+ }
3374
+ return {
3375
+ status: "committed",
3376
+ data: { eventId, deleted: true },
3377
+ committedAt: Date.now(),
3378
+ idempotentReplay: false
3379
+ };
3209
3380
  }
3210
- if (!res.ok) {
3211
- const text = await res.text().catch(() => "");
3212
- throw new Error(`microsoft-calendar book_slot ${res.status}: ${text.slice(0, 200)}`);
3213
- }
3214
- const created = await res.json();
3215
- return {
3216
- status: "committed",
3217
- data: { eventId: created.id, webLink: created.webLink },
3218
- etagAfter: created["@odata.etag"],
3219
- committedAt: Date.now(),
3220
- idempotentReplay: false
3221
- };
3381
+ throw new Error(`microsoft-calendar: unknown mutation capability ${inv.capabilityName}`);
3222
3382
  },
3223
3383
  async exchangeOAuth(input) {
3224
3384
  if (!clientId || !clientSecret) {
@@ -4438,518 +4598,6 @@ async function uploadFile2(inv, accessToken, timeoutMs) {
4438
4598
  };
4439
4599
  }
4440
4600
 
4441
- // src/connectors/adapters/notion-database.ts
4442
- var AUTH_URL8 = "https://api.notion.com/v1/oauth/authorize";
4443
- var TOKEN_URL8 = "https://api.notion.com/v1/oauth/token";
4444
- var API5 = "https://api.notion.com/v1";
4445
- var NOTION_VERSION = "2022-06-28";
4446
- function notionDatabase(opts) {
4447
- const { clientId, clientSecret } = opts;
4448
- const adapter = {
4449
- manifest: {
4450
- kind: "notion-database",
4451
- displayName: "Notion (database)",
4452
- description: "Query a Notion database, create new pages, and update existing ones with optimistic concurrency via last_edited_time.",
4453
- auth: {
4454
- kind: "oauth2",
4455
- authorizationUrl: AUTH_URL8,
4456
- tokenUrl: TOKEN_URL8,
4457
- // Notion does not use OAuth scopes — the workspace owner picks
4458
- // which pages/databases the integration sees during install. We
4459
- // declare an empty scope list so the consent screen renders cleanly.
4460
- scopes: [],
4461
- clientIdEnv: "NOTION_OAUTH_CLIENT_ID",
4462
- clientSecretEnv: "NOTION_OAUTH_CLIENT_SECRET",
4463
- extraAuthParams: { owner: "user" }
4464
- },
4465
- category: "doc",
4466
- defaultConsistencyModel: "authoritative",
4467
- capabilities: [
4468
- {
4469
- name: "query_database",
4470
- class: "read",
4471
- description: "Query the connected Notion database with an optional filter object (Notion query DSL).",
4472
- parameters: {
4473
- type: "object",
4474
- properties: {
4475
- filter: { type: "object", description: "Notion API filter object \u2014 passed through verbatim." },
4476
- pageSize: { type: "integer", minimum: 1, maximum: 100, default: 50 },
4477
- startCursor: { type: "string" }
4478
- }
4479
- }
4480
- },
4481
- {
4482
- name: "create_page",
4483
- class: "mutation",
4484
- description: "Create a new page inside the connected database.",
4485
- cas: "native-idempotency",
4486
- externalEffect: true,
4487
- parameters: {
4488
- type: "object",
4489
- properties: {
4490
- properties: {
4491
- type: "object",
4492
- description: "Notion property map keyed by property name."
4493
- }
4494
- },
4495
- required: ["properties"]
4496
- }
4497
- },
4498
- {
4499
- name: "update_page",
4500
- class: "mutation",
4501
- description: "Update properties on an existing page. If `expectedLastEditedTime` is supplied and stale, the update is rejected with conflict.",
4502
- cas: "etag-if-match",
4503
- externalEffect: true,
4504
- parameters: {
4505
- type: "object",
4506
- properties: {
4507
- pageId: { type: "string" },
4508
- properties: { type: "object" },
4509
- expectedLastEditedTime: {
4510
- type: "string",
4511
- description: "RFC3339 timestamp the agent observed on its last read. Drift triggers ResourceContention."
4512
- }
4513
- },
4514
- required: ["pageId", "properties"]
4515
- }
4516
- },
4517
- {
4518
- name: "pages.archive",
4519
- class: "mutation",
4520
- description: "Archive (soft-delete) a Notion page. Restorable via update_page with archived:false.",
4521
- cas: "native-idempotency",
4522
- externalEffect: true,
4523
- parameters: {
4524
- type: "object",
4525
- properties: { pageId: { type: "string" } },
4526
- required: ["pageId"]
4527
- }
4528
- },
4529
- {
4530
- name: "databases.create",
4531
- class: "mutation",
4532
- description: "Create a new Notion database underneath a parent page.",
4533
- cas: "native-idempotency",
4534
- externalEffect: true,
4535
- parameters: {
4536
- type: "object",
4537
- properties: {
4538
- parentPageId: { type: "string", description: "Parent page id under which to create the database." },
4539
- title: {
4540
- type: "array",
4541
- description: "Notion rich_text array used as the database title."
4542
- },
4543
- properties: {
4544
- type: "object",
4545
- description: "Schema map \u2014 property name \u2192 Notion property schema."
4546
- }
4547
- },
4548
- required: ["parentPageId", "title", "properties"]
4549
- }
4550
- },
4551
- {
4552
- name: "databases.update",
4553
- class: "mutation",
4554
- description: "Update a database title and/or schema.",
4555
- cas: "native-idempotency",
4556
- externalEffect: true,
4557
- parameters: {
4558
- type: "object",
4559
- properties: {
4560
- databaseId: { type: "string" },
4561
- title: { type: "array", description: "Optional new rich_text title." },
4562
- properties: { type: "object", description: "Optional partial schema update." }
4563
- },
4564
- required: ["databaseId"]
4565
- }
4566
- },
4567
- {
4568
- name: "blocks.append",
4569
- class: "mutation",
4570
- description: "Append child blocks to a page or block.",
4571
- cas: "native-idempotency",
4572
- externalEffect: true,
4573
- parameters: {
4574
- type: "object",
4575
- properties: {
4576
- blockId: { type: "string", description: "Parent page or block id." },
4577
- children: { type: "array", description: "Block descriptor array per Notion schema." }
4578
- },
4579
- required: ["blockId", "children"]
4580
- }
4581
- }
4582
- ]
4583
- },
4584
- async executeRead(inv) {
4585
- if (inv.capabilityName !== "query_database") {
4586
- throw new Error(`notion-database: unknown read capability ${inv.capabilityName}`);
4587
- }
4588
- const accessToken = readToken(inv.source.credentials);
4589
- const databaseId = readMetaString3(inv.source.metadata, "databaseId");
4590
- const { filter, pageSize, startCursor } = inv.args;
4591
- const body = {
4592
- page_size: Math.min(Math.max(1, pageSize ?? 50), 100)
4593
- };
4594
- if (filter) body.filter = filter;
4595
- if (startCursor) body.start_cursor = startCursor;
4596
- const res = await fetch(`${API5}/databases/${encodeURIComponent(databaseId)}/query`, {
4597
- method: "POST",
4598
- headers: notionHeaders(accessToken),
4599
- body: JSON.stringify(body),
4600
- signal: AbortSignal.timeout(1e4)
4601
- });
4602
- if (res.status === 401) {
4603
- throw new CredentialsExpired("Notion rejected token (401)", inv.source.id);
4604
- }
4605
- if (!res.ok) {
4606
- const text = await res.text().catch(() => "");
4607
- throw new Error(`notion-database query_database ${res.status}: ${text.slice(0, 200)}`);
4608
- }
4609
- const json = await res.json();
4610
- return {
4611
- data: {
4612
- results: json.results ?? [],
4613
- hasMore: json.has_more ?? false,
4614
- nextCursor: json.next_cursor ?? null
4615
- },
4616
- fetchedAt: Date.now()
4617
- };
4618
- },
4619
- async executeMutation(inv) {
4620
- const accessToken = readToken(inv.source.credentials);
4621
- if (inv.capabilityName === "create_page") return createPage(inv, accessToken);
4622
- if (inv.capabilityName === "update_page") return updatePage(inv, accessToken);
4623
- if (inv.capabilityName === "pages.archive") return archivePage(inv, accessToken);
4624
- if (inv.capabilityName === "databases.create") return createDatabase(inv, accessToken);
4625
- if (inv.capabilityName === "databases.update") return updateDatabase(inv, accessToken);
4626
- if (inv.capabilityName === "blocks.append") return appendBlocks(inv, accessToken);
4627
- throw new Error(`notion-database: unknown mutation capability ${inv.capabilityName}`);
4628
- },
4629
- async exchangeOAuth(input) {
4630
- if (!clientId || !clientSecret) {
4631
- throw new Error("Notion OAuth client not configured (NOTION_OAUTH_CLIENT_ID / _SECRET)");
4632
- }
4633
- const body = new URLSearchParams({
4634
- grant_type: "authorization_code",
4635
- code: input.code,
4636
- redirect_uri: input.redirectUri,
4637
- code_verifier: input.codeVerifier
4638
- });
4639
- const res = await fetch(TOKEN_URL8, {
4640
- method: "POST",
4641
- headers: {
4642
- authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
4643
- "content-type": "application/x-www-form-urlencoded",
4644
- accept: "application/json",
4645
- "Notion-Version": NOTION_VERSION
4646
- },
4647
- body
4648
- });
4649
- if (!res.ok) {
4650
- const text = await res.text().catch(() => "");
4651
- throw new Error(`Notion OAuth token exchange failed: ${res.status} \u2014 ${text.slice(0, 200)}`);
4652
- }
4653
- const json = await res.json();
4654
- return {
4655
- credentials: {
4656
- kind: "oauth2",
4657
- accessToken: json.access_token,
4658
- refreshToken: json.refresh_token
4659
- },
4660
- scopes: [],
4661
- metadata: {
4662
- botId: json.bot_id,
4663
- workspaceId: json.workspace_id,
4664
- workspaceName: json.workspace_name,
4665
- // Operator picks the database in a follow-up step; default empty.
4666
- databaseId: ""
4667
- }
4668
- };
4669
- },
4670
- async refreshToken(creds) {
4671
- if (creds.kind !== "oauth2" || !creds.refreshToken) {
4672
- if (creds.kind === "oauth2" && creds.accessToken && !creds.expiresAt) {
4673
- return creds;
4674
- }
4675
- throw new Error("notion-database.refreshToken: missing refresh token");
4676
- }
4677
- const refreshed = await refreshAccessToken({
4678
- tokenUrl: TOKEN_URL8,
4679
- clientId,
4680
- clientSecret,
4681
- refreshToken: creds.refreshToken
4682
- });
4683
- return {
4684
- kind: "oauth2",
4685
- accessToken: refreshed.accessToken,
4686
- refreshToken: refreshed.refreshToken ?? creds.refreshToken,
4687
- expiresAt: refreshed.expiresIn ? Date.now() + refreshed.expiresIn * 1e3 : void 0
4688
- };
4689
- },
4690
- async test(source) {
4691
- try {
4692
- const accessToken = readToken(source.credentials);
4693
- const res = await fetch(`${API5}/users/me`, {
4694
- headers: notionHeaders(accessToken),
4695
- signal: AbortSignal.timeout(8e3)
4696
- });
4697
- if (res.status === 401) return { ok: false, reason: "Notion rejected token (401) \u2014 reconnect required" };
4698
- if (!res.ok) return { ok: false, reason: `Notion returned ${res.status}` };
4699
- return { ok: true };
4700
- } catch (err) {
4701
- return { ok: false, reason: err instanceof Error ? err.message : String(err) };
4702
- }
4703
- }
4704
- };
4705
- return adapter;
4706
- }
4707
- async function createPage(inv, accessToken) {
4708
- const databaseId = readMetaString3(inv.source.metadata, "databaseId");
4709
- const { properties } = inv.args;
4710
- const res = await fetch(`${API5}/pages`, {
4711
- method: "POST",
4712
- headers: {
4713
- ...notionHeaders(accessToken),
4714
- "Idempotency-Key": inv.idempotencyKey
4715
- },
4716
- body: JSON.stringify({
4717
- parent: { database_id: databaseId },
4718
- properties
4719
- }),
4720
- signal: AbortSignal.timeout(15e3)
4721
- });
4722
- if (res.status === 401) {
4723
- throw new CredentialsExpired("Notion rejected token (401)", inv.source.id);
4724
- }
4725
- if (res.status === 409) {
4726
- throw new ResourceContention("Notion idempotency-key conflict \u2014 different args under same key");
4727
- }
4728
- if (!res.ok) {
4729
- const text = await res.text().catch(() => "");
4730
- throw new Error(`notion-database create_page ${res.status}: ${text.slice(0, 200)}`);
4731
- }
4732
- const created = await res.json();
4733
- return {
4734
- status: "committed",
4735
- data: { pageId: created.id, url: created.url, lastEditedTime: created.last_edited_time },
4736
- etagAfter: created.last_edited_time,
4737
- committedAt: Date.now(),
4738
- idempotentReplay: false
4739
- };
4740
- }
4741
- async function updatePage(inv, accessToken) {
4742
- const { pageId, properties, expectedLastEditedTime } = inv.args;
4743
- if (expectedLastEditedTime) {
4744
- const headRes = await fetch(`${API5}/pages/${encodeURIComponent(pageId)}`, {
4745
- headers: notionHeaders(accessToken),
4746
- signal: AbortSignal.timeout(1e4)
4747
- });
4748
- if (headRes.status === 401) {
4749
- throw new CredentialsExpired("Notion rejected token (401)", inv.source.id);
4750
- }
4751
- if (!headRes.ok) {
4752
- const text = await headRes.text().catch(() => "");
4753
- throw new Error(`notion-database update_page (preflight) ${headRes.status}: ${text.slice(0, 200)}`);
4754
- }
4755
- const page = await headRes.json();
4756
- if (page.last_edited_time && page.last_edited_time !== expectedLastEditedTime) {
4757
- throw new ResourceContention(
4758
- `Notion page ${pageId} was modified since the agent last read it`,
4759
- [],
4760
- { last_edited_time: page.last_edited_time, properties: page.properties }
4761
- );
4762
- }
4763
- }
4764
- const res = await fetch(`${API5}/pages/${encodeURIComponent(pageId)}`, {
4765
- method: "PATCH",
4766
- headers: notionHeaders(accessToken),
4767
- body: JSON.stringify({ properties }),
4768
- signal: AbortSignal.timeout(15e3)
4769
- });
4770
- if (res.status === 401) {
4771
- throw new CredentialsExpired("Notion rejected token (401)", inv.source.id);
4772
- }
4773
- if (res.status === 409 || res.status === 412) {
4774
- throw new ResourceContention(`Notion update_page conflict (${res.status})`);
4775
- }
4776
- if (!res.ok) {
4777
- const text = await res.text().catch(() => "");
4778
- throw new Error(`notion-database update_page ${res.status}: ${text.slice(0, 200)}`);
4779
- }
4780
- const updated = await res.json();
4781
- return {
4782
- status: "committed",
4783
- data: { pageId: updated.id, url: updated.url, lastEditedTime: updated.last_edited_time },
4784
- etagAfter: updated.last_edited_time,
4785
- committedAt: Date.now(),
4786
- idempotentReplay: false
4787
- };
4788
- }
4789
- async function archivePage(inv, accessToken) {
4790
- const { pageId } = inv.args;
4791
- if (typeof pageId !== "string" || pageId.length === 0) {
4792
- throw new Error("notion-database pages.archive: pageId is required");
4793
- }
4794
- const res = await fetch(`${API5}/pages/${encodeURIComponent(pageId)}`, {
4795
- method: "PATCH",
4796
- headers: {
4797
- ...notionHeaders(accessToken),
4798
- "Idempotency-Key": inv.idempotencyKey
4799
- },
4800
- body: JSON.stringify({ archived: true }),
4801
- signal: AbortSignal.timeout(15e3)
4802
- });
4803
- if (res.status === 401) {
4804
- throw new CredentialsExpired("Notion rejected token (401)", inv.source.id);
4805
- }
4806
- if (res.status === 409) {
4807
- throw new ResourceContention("Notion idempotency-key conflict \u2014 different args under same key");
4808
- }
4809
- if (!res.ok) {
4810
- const text = await res.text().catch(() => "");
4811
- throw new Error(`notion-database pages.archive ${res.status}: ${text.slice(0, 200)}`);
4812
- }
4813
- const archived = await res.json();
4814
- return {
4815
- status: "committed",
4816
- data: { pageId: archived.id, archived: archived.archived ?? true, lastEditedTime: archived.last_edited_time },
4817
- etagAfter: archived.last_edited_time,
4818
- committedAt: Date.now(),
4819
- idempotentReplay: false
4820
- };
4821
- }
4822
- async function createDatabase(inv, accessToken) {
4823
- const { parentPageId, title, properties } = inv.args;
4824
- if (typeof parentPageId !== "string" || parentPageId.length === 0) {
4825
- throw new Error("notion-database databases.create: parentPageId is required");
4826
- }
4827
- if (!title) throw new Error("notion-database databases.create: title is required");
4828
- if (!properties) throw new Error("notion-database databases.create: properties is required");
4829
- const res = await fetch(`${API5}/databases`, {
4830
- method: "POST",
4831
- headers: {
4832
- ...notionHeaders(accessToken),
4833
- "Idempotency-Key": inv.idempotencyKey
4834
- },
4835
- body: JSON.stringify({
4836
- parent: { type: "page_id", page_id: parentPageId },
4837
- title,
4838
- properties
4839
- }),
4840
- signal: AbortSignal.timeout(15e3)
4841
- });
4842
- if (res.status === 401) {
4843
- throw new CredentialsExpired("Notion rejected token (401)", inv.source.id);
4844
- }
4845
- if (res.status === 409) {
4846
- throw new ResourceContention("Notion idempotency-key conflict \u2014 different args under same key");
4847
- }
4848
- if (!res.ok) {
4849
- const text = await res.text().catch(() => "");
4850
- throw new Error(`notion-database databases.create ${res.status}: ${text.slice(0, 200)}`);
4851
- }
4852
- const created = await res.json();
4853
- return {
4854
- status: "committed",
4855
- data: { databaseId: created.id, url: created.url, lastEditedTime: created.last_edited_time },
4856
- etagAfter: created.last_edited_time,
4857
- committedAt: Date.now(),
4858
- idempotentReplay: false
4859
- };
4860
- }
4861
- async function updateDatabase(inv, accessToken) {
4862
- const { databaseId, title, properties } = inv.args;
4863
- if (typeof databaseId !== "string" || databaseId.length === 0) {
4864
- throw new Error("notion-database databases.update: databaseId is required");
4865
- }
4866
- const body = {};
4867
- if (title !== void 0) body.title = title;
4868
- if (properties !== void 0) body.properties = properties;
4869
- const res = await fetch(`${API5}/databases/${encodeURIComponent(databaseId)}`, {
4870
- method: "PATCH",
4871
- headers: {
4872
- ...notionHeaders(accessToken),
4873
- "Idempotency-Key": inv.idempotencyKey
4874
- },
4875
- body: JSON.stringify(body),
4876
- signal: AbortSignal.timeout(15e3)
4877
- });
4878
- if (res.status === 401) {
4879
- throw new CredentialsExpired("Notion rejected token (401)", inv.source.id);
4880
- }
4881
- if (res.status === 409) {
4882
- throw new ResourceContention("Notion idempotency-key conflict \u2014 different args under same key");
4883
- }
4884
- if (!res.ok) {
4885
- const text = await res.text().catch(() => "");
4886
- throw new Error(`notion-database databases.update ${res.status}: ${text.slice(0, 200)}`);
4887
- }
4888
- const updated = await res.json();
4889
- return {
4890
- status: "committed",
4891
- data: { databaseId: updated.id, url: updated.url, lastEditedTime: updated.last_edited_time },
4892
- etagAfter: updated.last_edited_time,
4893
- committedAt: Date.now(),
4894
- idempotentReplay: false
4895
- };
4896
- }
4897
- async function appendBlocks(inv, accessToken) {
4898
- const { blockId, children } = inv.args;
4899
- if (typeof blockId !== "string" || blockId.length === 0) {
4900
- throw new Error("notion-database blocks.append: blockId is required");
4901
- }
4902
- if (!Array.isArray(children)) {
4903
- throw new Error("notion-database blocks.append: children must be an array");
4904
- }
4905
- const res = await fetch(`${API5}/blocks/${encodeURIComponent(blockId)}/children`, {
4906
- method: "PATCH",
4907
- headers: {
4908
- ...notionHeaders(accessToken),
4909
- "Idempotency-Key": inv.idempotencyKey
4910
- },
4911
- body: JSON.stringify({ children }),
4912
- signal: AbortSignal.timeout(15e3)
4913
- });
4914
- if (res.status === 401) {
4915
- throw new CredentialsExpired("Notion rejected token (401)", inv.source.id);
4916
- }
4917
- if (res.status === 409) {
4918
- throw new ResourceContention("Notion idempotency-key conflict \u2014 different args under same key");
4919
- }
4920
- if (!res.ok) {
4921
- const text = await res.text().catch(() => "");
4922
- throw new Error(`notion-database blocks.append ${res.status}: ${text.slice(0, 200)}`);
4923
- }
4924
- const json = await res.json();
4925
- return {
4926
- status: "committed",
4927
- data: { results: json.results ?? [] },
4928
- committedAt: Date.now(),
4929
- idempotentReplay: false
4930
- };
4931
- }
4932
- function notionHeaders(accessToken) {
4933
- return {
4934
- authorization: `Bearer ${accessToken}`,
4935
- "Notion-Version": NOTION_VERSION,
4936
- "content-type": "application/json"
4937
- };
4938
- }
4939
- function readToken(creds) {
4940
- if (creds.kind !== "oauth2" || typeof creds.accessToken !== "string") {
4941
- throw new Error("notion-database: expected oauth2 credentials");
4942
- }
4943
- return creds.accessToken;
4944
- }
4945
- function readMetaString3(meta, key) {
4946
- const v = meta[key];
4947
- if (typeof v !== "string" || v.length === 0) {
4948
- throw new Error(`notion-database DataSource.metadata.${key} is missing`);
4949
- }
4950
- return v;
4951
- }
4952
-
4953
4601
  // src/connectors/adapters/docuseal.ts
4954
4602
  import { createHmac, timingSafeEqual } from "crypto";
4955
4603
  var DEFAULT_BASE = "https://api.docuseal.com";
@@ -5249,7 +4897,7 @@ async function voidSubmission(inv, apiKey, baseUrl, timeoutMs) {
5249
4897
  }
5250
4898
 
5251
4899
  // src/connectors/adapters/twilio-sms.ts
5252
- var API6 = "https://api.twilio.com/2010-04-01";
4900
+ var API5 = "https://api.twilio.com/2010-04-01";
5253
4901
  var LOOKUP_API = "https://lookups.twilio.com/v1";
5254
4902
  var twilioSmsConnector = {
5255
4903
  manifest: {
@@ -5406,7 +5054,7 @@ var twilioSmsConnector = {
5406
5054
  params.set("PageSize", String(Math.min(Math.max(1, limit ?? 20), 100)));
5407
5055
  if (to) params.set("To", to);
5408
5056
  if (from) params.set("From", from);
5409
- const url = `${API6}/Accounts/${encodeURIComponent(auth.accountSid)}/Messages.json?${params.toString()}`;
5057
+ const url = `${API5}/Accounts/${encodeURIComponent(auth.accountSid)}/Messages.json?${params.toString()}`;
5410
5058
  const res = await fetch(url, {
5411
5059
  headers: { authorization: basicAuth(auth) },
5412
5060
  signal: AbortSignal.timeout(1e4)
@@ -5427,7 +5075,7 @@ var twilioSmsConnector = {
5427
5075
  const params = new URLSearchParams();
5428
5076
  params.set("PageSize", String(Math.min(Math.max(1, limit ?? 50), 100)));
5429
5077
  if (phoneNumber) params.set("PhoneNumber", phoneNumber);
5430
- const url = `${API6}/Accounts/${encodeURIComponent(auth.accountSid)}/IncomingPhoneNumbers.json?${params.toString()}`;
5078
+ const url = `${API5}/Accounts/${encodeURIComponent(auth.accountSid)}/IncomingPhoneNumbers.json?${params.toString()}`;
5431
5079
  const res = await fetch(url, {
5432
5080
  headers: { authorization: basicAuth(auth) },
5433
5081
  signal: AbortSignal.timeout(1e4)
@@ -5449,13 +5097,13 @@ var twilioSmsConnector = {
5449
5097
  const auth = parseAuth(inv.source.credentials);
5450
5098
  if (inv.capabilityName === "send_sms") {
5451
5099
  const { to, body, from } = inv.args;
5452
- const fromNumber = from ?? readMetaString4(inv.source.metadata, "fromNumber");
5100
+ const fromNumber = from ?? readMetaString3(inv.source.metadata, "fromNumber");
5453
5101
  const formBody = new URLSearchParams({ To: to, From: fromNumber, Body: body });
5454
5102
  return await postMessages(inv, auth, formBody, "send_sms");
5455
5103
  }
5456
5104
  if (inv.capabilityName === "send_mms") {
5457
5105
  const { to, body, from, mediaUrl } = inv.args;
5458
- const fromNumber = from ?? readMetaString4(inv.source.metadata, "fromNumber");
5106
+ const fromNumber = from ?? readMetaString3(inv.source.metadata, "fromNumber");
5459
5107
  const formBody = new URLSearchParams();
5460
5108
  formBody.set("To", to);
5461
5109
  formBody.set("From", fromNumber);
@@ -5467,7 +5115,7 @@ var twilioSmsConnector = {
5467
5115
  if (inv.capabilityName === "send_whatsapp") {
5468
5116
  const { to, body, from } = inv.args;
5469
5117
  const ensureWhatsapp = (n) => n.startsWith("whatsapp:") ? n : `whatsapp:${n}`;
5470
- const fromRaw = from ?? readMetaStringOptional(inv.source.metadata, "whatsappFromNumber") ?? readMetaString4(inv.source.metadata, "fromNumber");
5118
+ const fromRaw = from ?? readMetaStringOptional(inv.source.metadata, "whatsappFromNumber") ?? readMetaString3(inv.source.metadata, "fromNumber");
5471
5119
  const formBody = new URLSearchParams({
5472
5120
  To: ensureWhatsapp(to),
5473
5121
  From: ensureWhatsapp(fromRaw),
@@ -5477,7 +5125,7 @@ var twilioSmsConnector = {
5477
5125
  }
5478
5126
  if (inv.capabilityName === "redact_message") {
5479
5127
  const { messageSid } = inv.args;
5480
- const url = `${API6}/Accounts/${encodeURIComponent(auth.accountSid)}/Messages/${encodeURIComponent(messageSid)}.json`;
5128
+ const url = `${API5}/Accounts/${encodeURIComponent(auth.accountSid)}/Messages/${encodeURIComponent(messageSid)}.json`;
5481
5129
  const formBody = new URLSearchParams({ Body: "" });
5482
5130
  const res = await fetch(url, {
5483
5131
  method: "POST",
@@ -5510,7 +5158,7 @@ var twilioSmsConnector = {
5510
5158
  async test(source) {
5511
5159
  try {
5512
5160
  const auth = parseAuth(source.credentials);
5513
- const res = await fetch(`${API6}/Accounts/${encodeURIComponent(auth.accountSid)}.json`, {
5161
+ const res = await fetch(`${API5}/Accounts/${encodeURIComponent(auth.accountSid)}.json`, {
5514
5162
  headers: { authorization: basicAuth(auth) },
5515
5163
  signal: AbortSignal.timeout(8e3)
5516
5164
  });
@@ -5546,7 +5194,7 @@ function parseAuth(creds) {
5546
5194
  function basicAuth(auth) {
5547
5195
  return `Basic ${Buffer.from(`${auth.username}:${auth.password}`).toString("base64")}`;
5548
5196
  }
5549
- function readMetaString4(meta, key) {
5197
+ function readMetaString3(meta, key) {
5550
5198
  const v = meta[key];
5551
5199
  if (typeof v !== "string" || v.length === 0) {
5552
5200
  throw new Error(`twilio-sms DataSource.metadata.${key} is missing`);
@@ -5558,7 +5206,7 @@ function readMetaStringOptional(meta, key) {
5558
5206
  return typeof v === "string" && v.length > 0 ? v : void 0;
5559
5207
  }
5560
5208
  async function postMessages(inv, auth, formBody, label) {
5561
- const url = `${API6}/Accounts/${encodeURIComponent(auth.accountSid)}/Messages.json`;
5209
+ const url = `${API5}/Accounts/${encodeURIComponent(auth.accountSid)}/Messages.json`;
5562
5210
  const res = await fetch(url, {
5563
5211
  method: "POST",
5564
5212
  headers: {
@@ -5587,7 +5235,7 @@ async function postMessages(inv, auth, formBody, label) {
5587
5235
  }
5588
5236
 
5589
5237
  // src/connectors/adapters/phony.ts
5590
- var API7 = "https://api.ph0ny.com";
5238
+ var API6 = "https://api.ph0ny.com";
5591
5239
  var E164 = /^\+[1-9]\d{7,14}$/;
5592
5240
  var phonyConnector = {
5593
5241
  manifest: {
@@ -5857,7 +5505,7 @@ var phonyConnector = {
5857
5505
  const json = await getJson(
5858
5506
  inv,
5859
5507
  token,
5860
- `${API7}/v1/agents?${params.toString()}`,
5508
+ `${API6}/v1/agents?${params.toString()}`,
5861
5509
  "list_agents"
5862
5510
  );
5863
5511
  return {
@@ -5870,7 +5518,7 @@ var phonyConnector = {
5870
5518
  const json = await getJson(
5871
5519
  inv,
5872
5520
  token,
5873
- `${API7}/v1/outbound/${encodeURIComponent(id)}`,
5521
+ `${API6}/v1/outbound/${encodeURIComponent(id)}`,
5874
5522
  "get_call"
5875
5523
  );
5876
5524
  return { data: { call: json.call ?? null }, fetchedAt: Date.now() };
@@ -5883,7 +5531,7 @@ var phonyConnector = {
5883
5531
  const json = await getJson(
5884
5532
  inv,
5885
5533
  token,
5886
- `${API7}/v1/outbound?${params.toString()}`,
5534
+ `${API6}/v1/outbound?${params.toString()}`,
5887
5535
  "list_calls"
5888
5536
  );
5889
5537
  return { data: { calls: json.calls ?? [] }, fetchedAt: Date.now() };
@@ -5894,7 +5542,7 @@ var phonyConnector = {
5894
5542
  if (limit !== void 0) payload.limit = limit;
5895
5543
  if (threshold !== void 0) payload.threshold = threshold;
5896
5544
  if (includeMetadata !== void 0) payload.includeMetadata = includeMetadata;
5897
- const res = await fetch(`${API7}/v1/collections/${encodeURIComponent(collectionId)}/search`, {
5545
+ const res = await fetch(`${API6}/v1/collections/${encodeURIComponent(collectionId)}/search`, {
5898
5546
  method: "POST",
5899
5547
  headers: {
5900
5548
  authorization: `Bearer ${token}`,
@@ -5935,7 +5583,7 @@ var phonyConnector = {
5935
5583
  if (args.callerProfile !== void 0) payload.callerProfile = args.callerProfile;
5936
5584
  if (args.voiceCloneId !== void 0) payload.voiceCloneId = args.voiceCloneId;
5937
5585
  if (args.dryRun !== void 0) payload.dryRun = args.dryRun;
5938
- const res = await fetch(`${API7}/v1/outbound/start`, {
5586
+ const res = await fetch(`${API6}/v1/outbound/start`, {
5939
5587
  method: "POST",
5940
5588
  headers: {
5941
5589
  authorization: `Bearer ${token}`,
@@ -5965,7 +5613,7 @@ var phonyConnector = {
5965
5613
  }
5966
5614
  if (inv.capabilityName === "create_agent") {
5967
5615
  const payload = pick(inv.args, AGENT_FIELDS);
5968
- const json = await postJson(inv, token, `${API7}/v1/agents`, payload, "create_agent");
5616
+ const json = await postJson(inv, token, `${API6}/v1/agents`, payload, "create_agent");
5969
5617
  return {
5970
5618
  status: "committed",
5971
5619
  data: { agent: json },
@@ -5981,7 +5629,7 @@ var phonyConnector = {
5981
5629
  const json = await postJson(
5982
5630
  inv,
5983
5631
  token,
5984
- `${API7}/v1/agents/provision`,
5632
+ `${API6}/v1/agents/provision`,
5985
5633
  payload,
5986
5634
  "provision_agent"
5987
5635
  );
@@ -6001,7 +5649,7 @@ var phonyConnector = {
6001
5649
  const payload = { name };
6002
5650
  if (description !== void 0) payload.description = description;
6003
5651
  if (metadata !== void 0) payload.metadata = metadata;
6004
- const json = await postJson(inv, token, `${API7}/v1/collections`, payload, "kb_create_collection");
5652
+ const json = await postJson(inv, token, `${API6}/v1/collections`, payload, "kb_create_collection");
6005
5653
  return {
6006
5654
  status: "committed",
6007
5655
  data: { collection: json },
@@ -6015,7 +5663,7 @@ var phonyConnector = {
6015
5663
  const json = await postJson(
6016
5664
  inv,
6017
5665
  token,
6018
- `${API7}/v1/collections/${encodeURIComponent(collectionId)}/ingest`,
5666
+ `${API6}/v1/collections/${encodeURIComponent(collectionId)}/ingest`,
6019
5667
  payload,
6020
5668
  "kb_ingest"
6021
5669
  );
@@ -6035,7 +5683,7 @@ var phonyConnector = {
6035
5683
  async test(source) {
6036
5684
  try {
6037
5685
  const token = bearerToken(source.credentials);
6038
- const res = await fetch(`${API7}/v1/outbound?limit=1`, {
5686
+ const res = await fetch(`${API6}/v1/outbound?limit=1`, {
6039
5687
  headers: { authorization: `Bearer ${token}` },
6040
5688
  signal: AbortSignal.timeout(8e3)
6041
5689
  });
@@ -6180,9 +5828,9 @@ var INGEST_FIELDS = [
6180
5828
 
6181
5829
  // src/connectors/adapters/whatsapp-business.ts
6182
5830
  var SCOPES5 = ["whatsapp_business_messaging", "whatsapp_business_management", "business_management"];
6183
- var AUTH_URL9 = "https://www.facebook.com/v21.0/dialog/oauth";
6184
- var TOKEN_URL9 = "https://graph.facebook.com/v21.0/oauth/access_token";
6185
- var API8 = "https://graph.facebook.com/v21.0";
5831
+ var AUTH_URL8 = "https://www.facebook.com/v21.0/dialog/oauth";
5832
+ var TOKEN_URL8 = "https://graph.facebook.com/v21.0/oauth/access_token";
5833
+ var API7 = "https://graph.facebook.com/v21.0";
6186
5834
  function whatsappBusiness(opts) {
6187
5835
  const { clientId, clientSecret } = opts;
6188
5836
  const adapter = {
@@ -6192,8 +5840,8 @@ function whatsappBusiness(opts) {
6192
5840
  description: "Send text and template messages from a verified WhatsApp Business number, and read your approved message templates. Advisory surface \u2014 WhatsApp sends are append-only.",
6193
5841
  auth: {
6194
5842
  kind: "oauth2",
6195
- authorizationUrl: AUTH_URL9,
6196
- tokenUrl: TOKEN_URL9,
5843
+ authorizationUrl: AUTH_URL8,
5844
+ tokenUrl: TOKEN_URL8,
6197
5845
  scopes: SCOPES5,
6198
5846
  clientIdEnv: "WHATSAPP_BUSINESS_OAUTH_CLIENT_ID",
6199
5847
  clientSecretEnv: "WHATSAPP_BUSINESS_OAUTH_CLIENT_SECRET"
@@ -6330,12 +5978,12 @@ function whatsappBusiness(opts) {
6330
5978
  async executeRead(inv) {
6331
5979
  const accessToken = readAccessToken(inv.source.credentials);
6332
5980
  if (inv.capabilityName === "list_message_templates") {
6333
- const wabaId = readMetaString5(inv.source.metadata, "wabaId");
5981
+ const wabaId = readMetaString4(inv.source.metadata, "wabaId");
6334
5982
  const { limit, status } = inv.args;
6335
5983
  const params = new URLSearchParams();
6336
5984
  params.set("limit", String(Math.min(Math.max(1, limit ?? 50), 200)));
6337
5985
  if (status) params.set("status", status);
6338
- const url = `${API8}/${encodeURIComponent(wabaId)}/message_templates?${params.toString()}`;
5986
+ const url = `${API7}/${encodeURIComponent(wabaId)}/message_templates?${params.toString()}`;
6339
5987
  const json = await graphGet(url, accessToken, inv.source.id);
6340
5988
  const data = json.data ?? [];
6341
5989
  return {
@@ -6352,11 +6000,11 @@ function whatsappBusiness(opts) {
6352
6000
  };
6353
6001
  }
6354
6002
  if (inv.capabilityName === "get_business_phone_number") {
6355
- const phoneNumberId = readMetaString5(inv.source.metadata, "phoneNumberId");
6003
+ const phoneNumberId = readMetaString4(inv.source.metadata, "phoneNumberId");
6356
6004
  const params = new URLSearchParams({
6357
6005
  fields: "display_phone_number,verified_name,quality_rating,code_verification_status,platform_type"
6358
6006
  });
6359
- const url = `${API8}/${encodeURIComponent(phoneNumberId)}?${params.toString()}`;
6007
+ const url = `${API7}/${encodeURIComponent(phoneNumberId)}?${params.toString()}`;
6360
6008
  const json = await graphGet(url, accessToken, inv.source.id);
6361
6009
  return {
6362
6010
  data: {
@@ -6382,8 +6030,8 @@ function whatsappBusiness(opts) {
6382
6030
  if (inv.capabilityName === "templates.delete") {
6383
6031
  return deleteTemplate(inv, accessToken);
6384
6032
  }
6385
- const phoneNumberId = readMetaString5(inv.source.metadata, "phoneNumberId");
6386
- const url = `${API8}/${encodeURIComponent(phoneNumberId)}/messages`;
6033
+ const phoneNumberId = readMetaString4(inv.source.metadata, "phoneNumberId");
6034
+ const url = `${API7}/${encodeURIComponent(phoneNumberId)}/messages`;
6387
6035
  let body;
6388
6036
  if (inv.capabilityName === "send_text_message") {
6389
6037
  const { to, body: text, previewUrl } = inv.args;
@@ -6464,7 +6112,7 @@ function whatsappBusiness(opts) {
6464
6112
  throw new Error("WhatsApp Business OAuth client not configured (WHATSAPP_BUSINESS_OAUTH_CLIENT_ID / _SECRET)");
6465
6113
  }
6466
6114
  const tokens = await exchangeAuthorizationCode({
6467
- tokenUrl: TOKEN_URL9,
6115
+ tokenUrl: TOKEN_URL8,
6468
6116
  clientId,
6469
6117
  clientSecret,
6470
6118
  code: input.code,
@@ -6488,7 +6136,7 @@ function whatsappBusiness(opts) {
6488
6136
  try {
6489
6137
  const accessToken = readAccessToken(source.credentials);
6490
6138
  const phoneNumberId = typeof source.metadata.phoneNumberId === "string" ? source.metadata.phoneNumberId : void 0;
6491
- const probeUrl = phoneNumberId ? `${API8}/${encodeURIComponent(phoneNumberId)}?fields=display_phone_number` : `${API8}/me?fields=id`;
6139
+ const probeUrl = phoneNumberId ? `${API7}/${encodeURIComponent(phoneNumberId)}?fields=display_phone_number` : `${API7}/me?fields=id`;
6492
6140
  const res = await fetch(probeUrl, {
6493
6141
  headers: { authorization: `Bearer ${accessToken}` },
6494
6142
  signal: AbortSignal.timeout(8e3)
@@ -6512,7 +6160,7 @@ function readAccessToken(creds) {
6512
6160
  }
6513
6161
  return creds.accessToken;
6514
6162
  }
6515
- function readMetaString5(meta, key) {
6163
+ function readMetaString4(meta, key) {
6516
6164
  const v = meta[key];
6517
6165
  if (typeof v !== "string" || v.length === 0) {
6518
6166
  throw new Error(`whatsapp-business DataSource.metadata.${key} is missing \u2014 set it at connect-time from the Embedded Signup callback`);
@@ -6541,7 +6189,7 @@ function decodeBase64(value) {
6541
6189
  return bytes;
6542
6190
  }
6543
6191
  async function uploadMedia(inv, accessToken) {
6544
- const phoneNumberId = readMetaString5(inv.source.metadata, "phoneNumberId");
6192
+ const phoneNumberId = readMetaString4(inv.source.metadata, "phoneNumberId");
6545
6193
  const { dataBase64, mimeType, filename } = inv.args;
6546
6194
  if (typeof dataBase64 !== "string" || dataBase64.length === 0) {
6547
6195
  throw new Error("whatsapp-business media.upload: dataBase64 is required");
@@ -6554,7 +6202,7 @@ async function uploadMedia(inv, accessToken) {
6554
6202
  form.set("messaging_product", "whatsapp");
6555
6203
  form.set("type", mimeType);
6556
6204
  form.set("file", new Blob([bytes], { type: mimeType }), filename ?? "upload");
6557
- const url = `${API8}/${encodeURIComponent(phoneNumberId)}/media`;
6205
+ const url = `${API7}/${encodeURIComponent(phoneNumberId)}/media`;
6558
6206
  const res = await fetch(url, {
6559
6207
  method: "POST",
6560
6208
  headers: { authorization: `Bearer ${accessToken}` },
@@ -6577,7 +6225,7 @@ async function uploadMedia(inv, accessToken) {
6577
6225
  };
6578
6226
  }
6579
6227
  async function createTemplate(inv, accessToken) {
6580
- const wabaId = readMetaString5(inv.source.metadata, "wabaId");
6228
+ const wabaId = readMetaString4(inv.source.metadata, "wabaId");
6581
6229
  const { name, language, category, components } = inv.args;
6582
6230
  if (typeof name !== "string" || name.length === 0) {
6583
6231
  throw new Error("whatsapp-business templates.create: name is required");
@@ -6591,7 +6239,7 @@ async function createTemplate(inv, accessToken) {
6591
6239
  if (!Array.isArray(components)) {
6592
6240
  throw new Error("whatsapp-business templates.create: components must be an array");
6593
6241
  }
6594
- const url = `${API8}/${encodeURIComponent(wabaId)}/message_templates`;
6242
+ const url = `${API7}/${encodeURIComponent(wabaId)}/message_templates`;
6595
6243
  const res = await fetch(url, {
6596
6244
  method: "POST",
6597
6245
  headers: {
@@ -6617,7 +6265,7 @@ async function createTemplate(inv, accessToken) {
6617
6265
  };
6618
6266
  }
6619
6267
  async function deleteTemplate(inv, accessToken) {
6620
- const wabaId = readMetaString5(inv.source.metadata, "wabaId");
6268
+ const wabaId = readMetaString4(inv.source.metadata, "wabaId");
6621
6269
  const { name, hsmId } = inv.args;
6622
6270
  if (typeof name !== "string" || name.length === 0) {
6623
6271
  throw new Error("whatsapp-business templates.delete: name is required");
@@ -6625,7 +6273,7 @@ async function deleteTemplate(inv, accessToken) {
6625
6273
  const params = new URLSearchParams();
6626
6274
  params.set("name", name);
6627
6275
  if (typeof hsmId === "string" && hsmId.length > 0) params.set("hsm_id", hsmId);
6628
- const url = `${API8}/${encodeURIComponent(wabaId)}/message_templates?${params.toString()}`;
6276
+ const url = `${API7}/${encodeURIComponent(wabaId)}/message_templates?${params.toString()}`;
6629
6277
  const res = await fetch(url, {
6630
6278
  method: "DELETE",
6631
6279
  headers: { authorization: `Bearer ${accessToken}` },
@@ -6648,7 +6296,7 @@ async function deleteTemplate(inv, accessToken) {
6648
6296
  }
6649
6297
 
6650
6298
  // src/connectors/adapters/stripe-pack.ts
6651
- var API9 = "https://api.stripe.com/v1";
6299
+ var API8 = "https://api.stripe.com/v1";
6652
6300
  var stripePackConnector = {
6653
6301
  manifest: {
6654
6302
  kind: "stripe-pack",
@@ -6848,7 +6496,7 @@ var stripePackConnector = {
6848
6496
  throw new Error(`stripe-pack: unknown read capability ${inv.capabilityName}`);
6849
6497
  }
6850
6498
  const { email } = inv.args;
6851
- const url = `${API9}/customers/search?query=${encodeURIComponent(`email:'${email.toLowerCase()}'`)}&limit=1`;
6499
+ const url = `${API8}/customers/search?query=${encodeURIComponent(`email:'${email.toLowerCase()}'`)}&limit=1`;
6852
6500
  const res = await fetch(url, {
6853
6501
  headers: { authorization: `Bearer ${apiKey}` },
6854
6502
  signal: AbortSignal.timeout(1e4)
@@ -6881,7 +6529,7 @@ var stripePackConnector = {
6881
6529
  async test(source) {
6882
6530
  try {
6883
6531
  const apiKey = readApiKey(source.credentials);
6884
- const res = await fetch(`${API9}/account`, {
6532
+ const res = await fetch(`${API8}/account`, {
6885
6533
  headers: { authorization: `Bearer ${apiKey}` },
6886
6534
  signal: AbortSignal.timeout(8e3)
6887
6535
  });
@@ -6907,7 +6555,7 @@ async function createInvoice(inv, apiKey) {
6907
6555
  quantity: String(it.quantity ?? 1)
6908
6556
  });
6909
6557
  if (it.description) body.set("description", it.description);
6910
- const res = await fetch(`${API9}/invoiceitems`, {
6558
+ const res = await fetch(`${API8}/invoiceitems`, {
6911
6559
  method: "POST",
6912
6560
  headers: {
6913
6561
  authorization: `Bearer ${apiKey}`,
@@ -6932,7 +6580,7 @@ async function createInvoice(inv, apiKey) {
6932
6580
  collection_method: "send_invoice",
6933
6581
  days_until_due: "14"
6934
6582
  });
6935
- const invRes = await fetch(`${API9}/invoices`, {
6583
+ const invRes = await fetch(`${API8}/invoices`, {
6936
6584
  method: "POST",
6937
6585
  headers: {
6938
6586
  authorization: `Bearer ${apiKey}`,
@@ -6970,7 +6618,7 @@ async function createCheckoutSession(inv, apiKey) {
6970
6618
  body.set(`line_items[${i}][price]`, it.price);
6971
6619
  body.set(`line_items[${i}][quantity]`, String(it.quantity ?? 1));
6972
6620
  });
6973
- const res = await fetch(`${API9}/checkout/sessions`, {
6621
+ const res = await fetch(`${API8}/checkout/sessions`, {
6974
6622
  method: "POST",
6975
6623
  headers: {
6976
6624
  authorization: `Bearer ${apiKey}`,
@@ -7001,7 +6649,7 @@ async function listSubscriptions(inv, apiKey) {
7001
6649
  const params = new URLSearchParams({ customer: customerId, limit: String(limit ?? 10) });
7002
6650
  if (status && status !== "all") params.set("status", status);
7003
6651
  else params.set("status", "all");
7004
- const res = await fetch(`${API9}/subscriptions?${params.toString()}`, {
6652
+ const res = await fetch(`${API8}/subscriptions?${params.toString()}`, {
7005
6653
  headers: { authorization: `Bearer ${apiKey}` },
7006
6654
  signal: AbortSignal.timeout(1e4)
7007
6655
  });
@@ -7036,7 +6684,7 @@ async function cancelSubscription(inv, apiKey) {
7036
6684
  let res;
7037
6685
  if (atPeriodEnd) {
7038
6686
  const body = new URLSearchParams({ cancel_at_period_end: "true" });
7039
- res = await fetch(`${API9}/subscriptions/${encodeURIComponent(subscriptionId)}`, {
6687
+ res = await fetch(`${API8}/subscriptions/${encodeURIComponent(subscriptionId)}`, {
7040
6688
  method: "POST",
7041
6689
  headers: {
7042
6690
  authorization: `Bearer ${apiKey}`,
@@ -7047,7 +6695,7 @@ async function cancelSubscription(inv, apiKey) {
7047
6695
  signal: AbortSignal.timeout(15e3)
7048
6696
  });
7049
6697
  } else {
7050
- res = await fetch(`${API9}/subscriptions/${encodeURIComponent(subscriptionId)}`, {
6698
+ res = await fetch(`${API8}/subscriptions/${encodeURIComponent(subscriptionId)}`, {
7051
6699
  method: "DELETE",
7052
6700
  headers: {
7053
6701
  authorization: `Bearer ${apiKey}`,
@@ -7082,7 +6730,7 @@ async function cancelSubscription(inv, apiKey) {
7082
6730
  async function createBillingPortalSession(inv, apiKey) {
7083
6731
  const { customerId, returnUrl } = inv.args;
7084
6732
  const body = new URLSearchParams({ customer: customerId, return_url: returnUrl });
7085
- const res = await fetch(`${API9}/billing_portal/sessions`, {
6733
+ const res = await fetch(`${API8}/billing_portal/sessions`, {
7086
6734
  method: "POST",
7087
6735
  headers: {
7088
6736
  authorization: `Bearer ${apiKey}`,
@@ -7130,7 +6778,7 @@ async function createPaymentIntent(inv, apiKey) {
7130
6778
  body.set(`metadata[${k}]`, String(v));
7131
6779
  }
7132
6780
  }
7133
- const res = await fetch(`${API9}/payment_intents`, {
6781
+ const res = await fetch(`${API8}/payment_intents`, {
7134
6782
  method: "POST",
7135
6783
  headers: {
7136
6784
  authorization: `Bearer ${apiKey}`,
@@ -7178,7 +6826,7 @@ async function createRefund(inv, apiKey) {
7178
6826
  if (args.charge) body.set("charge", args.charge);
7179
6827
  if (typeof args.amount === "number") body.set("amount", String(args.amount));
7180
6828
  if (args.reason) body.set("reason", args.reason);
7181
- const res = await fetch(`${API9}/refunds`, {
6829
+ const res = await fetch(`${API8}/refunds`, {
7182
6830
  method: "POST",
7183
6831
  headers: {
7184
6832
  authorization: `Bearer ${apiKey}`,
@@ -7226,7 +6874,7 @@ async function createCustomer(inv, apiKey) {
7226
6874
  body.set(`metadata[${k}]`, String(v));
7227
6875
  }
7228
6876
  }
7229
- const res = await fetch(`${API9}/customers`, {
6877
+ const res = await fetch(`${API8}/customers`, {
7230
6878
  method: "POST",
7231
6879
  headers: {
7232
6880
  authorization: `Bearer ${apiKey}`,
@@ -7302,7 +6950,7 @@ var webhookConnector = {
7302
6950
  ]
7303
6951
  },
7304
6952
  async executeRead(inv) {
7305
- const url = readMetaString6(inv.source.metadata, "url");
6953
+ const url = readMetaString5(inv.source.metadata, "url");
7306
6954
  const params = inv.args && typeof inv.args === "object" ? inv.args : {};
7307
6955
  const u = new URL(url);
7308
6956
  for (const [k, v] of Object.entries(params)) {
@@ -7324,7 +6972,7 @@ var webhookConnector = {
7324
6972
  };
7325
6973
  },
7326
6974
  async executeMutation(inv) {
7327
- const url = readMetaString6(inv.source.metadata, "url");
6975
+ const url = readMetaString5(inv.source.metadata, "url");
7328
6976
  const body = JSON.stringify(inv.args ?? {});
7329
6977
  const res = await fetch(url, {
7330
6978
  method: "POST",
@@ -7354,7 +7002,7 @@ var webhookConnector = {
7354
7002
  },
7355
7003
  async test(source) {
7356
7004
  try {
7357
- const url = readMetaString6(source.metadata, "url");
7005
+ const url = readMetaString5(source.metadata, "url");
7358
7006
  const res = await fetch(url, {
7359
7007
  method: "HEAD",
7360
7008
  headers: signHeaders(source.credentials, "", `health-${Date.now()}`),
@@ -7367,7 +7015,7 @@ var webhookConnector = {
7367
7015
  }
7368
7016
  }
7369
7017
  };
7370
- function readMetaString6(meta, key) {
7018
+ function readMetaString5(meta, key) {
7371
7019
  const v = meta[key];
7372
7020
  if (typeof v !== "string" || v.length === 0) {
7373
7021
  throw new Error(`webhook DataSource.metadata.${key} is missing`);
@@ -37415,8 +37063,8 @@ var SCOPES7 = [
37415
37063
  "request_signature",
37416
37064
  "signature_request_access"
37417
37065
  ];
37418
- var AUTH_URL10 = "https://app.hellosign.com/oauth/authorize";
37419
- var TOKEN_URL10 = "https://app.hellosign.com/oauth/token";
37066
+ var AUTH_URL9 = "https://app.hellosign.com/oauth/authorize";
37067
+ var TOKEN_URL9 = "https://app.hellosign.com/oauth/token";
37420
37068
  var DEFAULT_API_BASE = "https://api.hellosign.com/v3";
37421
37069
  function hellosign(opts) {
37422
37070
  const { clientId, clientSecret } = opts;
@@ -37429,11 +37077,15 @@ function hellosign(opts) {
37429
37077
  description: "Send documents for e-signature via Dropbox Sign templates, poll signature-request status, cancel in-flight requests, and react to push events when signers complete.",
37430
37078
  auth: {
37431
37079
  kind: "oauth2",
37432
- authorizationUrl: AUTH_URL10,
37433
- tokenUrl: TOKEN_URL10,
37080
+ authorizationUrl: AUTH_URL9,
37081
+ tokenUrl: TOKEN_URL9,
37434
37082
  scopes: SCOPES7,
37435
37083
  clientIdEnv: "HELLOSIGN_OAUTH_CLIENT_ID",
37436
- clientSecretEnv: "HELLOSIGN_OAUTH_CLIENT_SECRET"
37084
+ clientSecretEnv: "HELLOSIGN_OAUTH_CLIENT_SECRET",
37085
+ // Dropbox Sign rejects a per-request `scope` param ("Custom scopes
37086
+ // are not supported yet") — scopes are pinned in the API app
37087
+ // settings, so the authorization URL must omit scope.
37088
+ sendScopeParam: false
37437
37089
  },
37438
37090
  category: "doc",
37439
37091
  defaultConsistencyModel: "authoritative",
@@ -37583,7 +37235,7 @@ function hellosign(opts) {
37583
37235
  throw new Error("Dropbox Sign OAuth client not configured (HELLOSIGN_OAUTH_CLIENT_ID / _SECRET)");
37584
37236
  }
37585
37237
  const tokens = await exchangeAuthorizationCode({
37586
- tokenUrl: TOKEN_URL10,
37238
+ tokenUrl: TOKEN_URL9,
37587
37239
  clientId,
37588
37240
  clientSecret,
37589
37241
  code: input.code,
@@ -37606,7 +37258,7 @@ function hellosign(opts) {
37606
37258
  throw new Error("hellosign.refreshToken: missing refresh token");
37607
37259
  }
37608
37260
  const refreshed = await refreshAccessToken({
37609
- tokenUrl: TOKEN_URL10,
37261
+ tokenUrl: TOKEN_URL9,
37610
37262
  clientId,
37611
37263
  clientSecret,
37612
37264
  refreshToken: creds.refreshToken
@@ -37897,7 +37549,7 @@ async function ensureFreshAccessToken7(creds, clientId, clientSecret, inv) {
37897
37549
  throw new CredentialsExpired("Dropbox Sign access token expired and no refresh token", inv?.source.id ?? "");
37898
37550
  }
37899
37551
  const refreshed = await refreshAccessToken({
37900
- tokenUrl: TOKEN_URL10,
37552
+ tokenUrl: TOKEN_URL9,
37901
37553
  clientId,
37902
37554
  clientSecret,
37903
37555
  refreshToken: creds.refreshToken
@@ -37916,12 +37568,12 @@ async function ensureFreshAccessToken7(creds, clientId, clientSecret, inv) {
37916
37568
 
37917
37569
  // src/connectors/adapters/pandadoc.ts
37918
37570
  var SCOPES8 = ["read", "read+write"];
37919
- var AUTH_URL11 = "https://app.pandadoc.com/oauth2/authorize";
37920
- var TOKEN_URL11 = "https://api.pandadoc.com/oauth2/access_token";
37921
- var API10 = "https://api.pandadoc.com/public/v1";
37571
+ var AUTH_URL10 = "https://app.pandadoc.com/oauth2/authorize";
37572
+ var TOKEN_URL10 = "https://api.pandadoc.com/oauth2/access_token";
37573
+ var API9 = "https://api.pandadoc.com/public/v1";
37922
37574
  function pandadoc(opts) {
37923
37575
  const { clientId, clientSecret } = opts;
37924
- const baseUrl = (opts.baseUrl ?? API10).replace(/\/$/, "");
37576
+ const baseUrl = (opts.baseUrl ?? API9).replace(/\/$/, "");
37925
37577
  const timeoutMs = opts.timeoutMs ?? 3e4;
37926
37578
  const adapter = {
37927
37579
  manifest: {
@@ -37930,8 +37582,8 @@ function pandadoc(opts) {
37930
37582
  description: "Draft contracts and proposals from PandaDoc templates, send them for signature, poll signing status, and cancel in-flight documents.",
37931
37583
  auth: {
37932
37584
  kind: "oauth2",
37933
- authorizationUrl: AUTH_URL11,
37934
- tokenUrl: TOKEN_URL11,
37585
+ authorizationUrl: AUTH_URL10,
37586
+ tokenUrl: TOKEN_URL10,
37935
37587
  scopes: SCOPES8,
37936
37588
  clientIdEnv: "PANDADOC_OAUTH_CLIENT_ID",
37937
37589
  clientSecretEnv: "PANDADOC_OAUTH_CLIENT_SECRET"
@@ -38079,7 +37731,7 @@ function pandadoc(opts) {
38079
37731
  throw new Error("PandaDoc OAuth client not configured (PANDADOC_OAUTH_CLIENT_ID / _SECRET)");
38080
37732
  }
38081
37733
  const tokens = await exchangeAuthorizationCode({
38082
- tokenUrl: TOKEN_URL11,
37734
+ tokenUrl: TOKEN_URL10,
38083
37735
  clientId,
38084
37736
  clientSecret,
38085
37737
  code: input.code,
@@ -38102,7 +37754,7 @@ function pandadoc(opts) {
38102
37754
  throw new Error("pandadoc.refreshToken: missing refresh token");
38103
37755
  }
38104
37756
  const refreshed = await refreshAccessToken({
38105
- tokenUrl: TOKEN_URL11,
37757
+ tokenUrl: TOKEN_URL10,
38106
37758
  clientId,
38107
37759
  clientSecret,
38108
37760
  refreshToken: creds.refreshToken
@@ -38410,7 +38062,7 @@ async function ensureFreshAccessTokenFromCreds(creds, clientId, clientSecret, on
38410
38062
  throw new CredentialsExpired("PandaDoc access token expired and no refresh token", "");
38411
38063
  }
38412
38064
  const refreshed = await refreshAccessToken({
38413
- tokenUrl: TOKEN_URL11,
38065
+ tokenUrl: TOKEN_URL10,
38414
38066
  clientId,
38415
38067
  clientSecret,
38416
38068
  refreshToken: creds.refreshToken
@@ -38434,9 +38086,9 @@ var SCOPES9 = [
38434
38086
  "https://www.googleapis.com/auth/documents",
38435
38087
  "https://www.googleapis.com/auth/drive.file"
38436
38088
  ];
38437
- var AUTH_URL12 = "https://accounts.google.com/o/oauth2/v2/auth";
38438
- var TOKEN_URL12 = "https://oauth2.googleapis.com/token";
38439
- var API11 = "https://docs.googleapis.com/v1";
38089
+ var AUTH_URL11 = "https://accounts.google.com/o/oauth2/v2/auth";
38090
+ var TOKEN_URL11 = "https://oauth2.googleapis.com/token";
38091
+ var API10 = "https://docs.googleapis.com/v1";
38440
38092
  var DRIVE_API = "https://www.googleapis.com/drive/v3";
38441
38093
  var EXPORT_MIME = {
38442
38094
  pdf: "application/pdf",
@@ -38460,8 +38112,8 @@ function googleDocs(opts) {
38460
38112
  description: "Read and draft into the user's Google Docs. Fetch a document's plaintext body, create a new doc from a title + initial body, and append text with optional revision-id CAS guarding concurrent edits.",
38461
38113
  auth: {
38462
38114
  kind: "oauth2",
38463
- authorizationUrl: AUTH_URL12,
38464
- tokenUrl: TOKEN_URL12,
38115
+ authorizationUrl: AUTH_URL11,
38116
+ tokenUrl: TOKEN_URL11,
38465
38117
  scopes: SCOPES9,
38466
38118
  clientIdEnv: "GOOGLE_OAUTH_CLIENT_ID",
38467
38119
  clientSecretEnv: "GOOGLE_OAUTH_CLIENT_SECRET",
@@ -38575,7 +38227,7 @@ function googleDocs(opts) {
38575
38227
  throw new Error("Google OAuth client not configured (GOOGLE_OAUTH_CLIENT_ID / _SECRET)");
38576
38228
  }
38577
38229
  const tokens = await exchangeAuthorizationCode({
38578
- tokenUrl: TOKEN_URL12,
38230
+ tokenUrl: TOKEN_URL11,
38579
38231
  clientId,
38580
38232
  clientSecret,
38581
38233
  code: input.code,
@@ -38598,7 +38250,7 @@ function googleDocs(opts) {
38598
38250
  throw new Error("google-docs.refreshToken: missing refresh token");
38599
38251
  }
38600
38252
  const refreshed = await refreshAccessToken({
38601
- tokenUrl: TOKEN_URL12,
38253
+ tokenUrl: TOKEN_URL11,
38602
38254
  clientId,
38603
38255
  clientSecret,
38604
38256
  refreshToken: creds.refreshToken
@@ -38652,7 +38304,7 @@ function findAppendIndex(doc) {
38652
38304
  }
38653
38305
  async function getDocument2(inv, accessToken, timeoutMs) {
38654
38306
  const { documentId } = inv.args ?? {};
38655
- const res = await fetch(`${API11}/documents/${encodeURIComponent(documentId)}`, {
38307
+ const res = await fetch(`${API10}/documents/${encodeURIComponent(documentId)}`, {
38656
38308
  headers: { authorization: `Bearer ${accessToken}` },
38657
38309
  signal: AbortSignal.timeout(timeoutMs)
38658
38310
  });
@@ -38686,7 +38338,7 @@ async function createDocument2(inv, accessToken, timeoutMs) {
38686
38338
  if (!title || typeof title !== "string") {
38687
38339
  throw new Error("google-docs create_document: title is required");
38688
38340
  }
38689
- const createRes = await fetch(`${API11}/documents`, {
38341
+ const createRes = await fetch(`${API10}/documents`, {
38690
38342
  method: "POST",
38691
38343
  headers: {
38692
38344
  authorization: `Bearer ${accessToken}`,
@@ -38706,7 +38358,7 @@ async function createDocument2(inv, accessToken, timeoutMs) {
38706
38358
  let revisionId = created.revisionId;
38707
38359
  if (typeof body === "string" && body.length > 0) {
38708
38360
  const insertRes = await fetch(
38709
- `${API11}/documents/${encodeURIComponent(created.documentId)}:batchUpdate`,
38361
+ `${API10}/documents/${encodeURIComponent(created.documentId)}:batchUpdate`,
38710
38362
  {
38711
38363
  method: "POST",
38712
38364
  headers: {
@@ -38749,7 +38401,7 @@ async function appendText(inv, accessToken, timeoutMs) {
38749
38401
  if (!text) {
38750
38402
  throw new Error("google-docs append_text: text is required");
38751
38403
  }
38752
- const docRes = await fetch(`${API11}/documents/${encodeURIComponent(documentId)}?fields=documentId,revisionId,body(content(endIndex))`, {
38404
+ const docRes = await fetch(`${API10}/documents/${encodeURIComponent(documentId)}?fields=documentId,revisionId,body(content(endIndex))`, {
38753
38405
  headers: { authorization: `Bearer ${accessToken}` },
38754
38406
  signal: AbortSignal.timeout(timeoutMs)
38755
38407
  });
@@ -38779,7 +38431,7 @@ async function appendText(inv, accessToken, timeoutMs) {
38779
38431
  body.writeControl = { requiredRevisionId };
38780
38432
  }
38781
38433
  const res = await fetch(
38782
- `${API11}/documents/${encodeURIComponent(documentId)}:batchUpdate`,
38434
+ `${API10}/documents/${encodeURIComponent(documentId)}:batchUpdate`,
38783
38435
  {
38784
38436
  method: "POST",
38785
38437
  headers: {
@@ -38900,7 +38552,7 @@ async function ensureFreshAccessToken9(creds, clientId, clientSecret) {
38900
38552
  throw new CredentialsExpired("Google Docs access token expired and no refresh token", "");
38901
38553
  }
38902
38554
  const refreshed = await refreshAccessToken({
38903
- tokenUrl: TOKEN_URL12,
38555
+ tokenUrl: TOKEN_URL11,
38904
38556
  clientId,
38905
38557
  clientSecret,
38906
38558
  refreshToken: creds.refreshToken
@@ -38918,9 +38570,9 @@ var SCOPES10 = [
38918
38570
  "https://www.googleapis.com/auth/forms.responses.readonly",
38919
38571
  SCOPE_WRITE3
38920
38572
  ];
38921
- var AUTH_URL13 = "https://accounts.google.com/o/oauth2/v2/auth";
38922
- var TOKEN_URL13 = "https://oauth2.googleapis.com/token";
38923
- var API12 = "https://forms.googleapis.com/v1";
38573
+ var AUTH_URL12 = "https://accounts.google.com/o/oauth2/v2/auth";
38574
+ var TOKEN_URL12 = "https://oauth2.googleapis.com/token";
38575
+ var API11 = "https://forms.googleapis.com/v1";
38924
38576
  function googleForms(opts) {
38925
38577
  const { clientId, clientSecret } = opts;
38926
38578
  const timeoutMs = opts.timeoutMs ?? 3e4;
@@ -38931,8 +38583,8 @@ function googleForms(opts) {
38931
38583
  description: "Read a Google Form's schema and paginate its responses for KB ingest, lead routing, or analytics. Returns answers keyed by questionId with the original item tree available for question\u2192title joins.",
38932
38584
  auth: {
38933
38585
  kind: "oauth2",
38934
- authorizationUrl: AUTH_URL13,
38935
- tokenUrl: TOKEN_URL13,
38586
+ authorizationUrl: AUTH_URL12,
38587
+ tokenUrl: TOKEN_URL12,
38936
38588
  scopes: SCOPES10,
38937
38589
  clientIdEnv: "GOOGLE_OAUTH_CLIENT_ID",
38938
38590
  clientSecretEnv: "GOOGLE_OAUTH_CLIENT_SECRET",
@@ -39076,7 +38728,7 @@ function googleForms(opts) {
39076
38728
  throw new Error("Google OAuth client not configured (GOOGLE_OAUTH_CLIENT_ID / _SECRET)");
39077
38729
  }
39078
38730
  const tokens = await exchangeAuthorizationCode({
39079
- tokenUrl: TOKEN_URL13,
38731
+ tokenUrl: TOKEN_URL12,
39080
38732
  clientId,
39081
38733
  clientSecret,
39082
38734
  code: input.code,
@@ -39099,7 +38751,7 @@ function googleForms(opts) {
39099
38751
  throw new Error("google-forms.refreshToken: missing refresh token");
39100
38752
  }
39101
38753
  const refreshed = await refreshAccessToken({
39102
- tokenUrl: TOKEN_URL13,
38754
+ tokenUrl: TOKEN_URL12,
39103
38755
  clientId,
39104
38756
  clientSecret,
39105
38757
  refreshToken: creds.refreshToken
@@ -39145,7 +38797,7 @@ function flattenAnswers(answers) {
39145
38797
  async function getForm(inv, accessToken, timeoutMs) {
39146
38798
  const { formId } = inv.args ?? {};
39147
38799
  if (!formId) throw new Error("google-forms get_form: formId is required");
39148
- const res = await fetch(`${API12}/forms/${encodeURIComponent(formId)}`, {
38800
+ const res = await fetch(`${API11}/forms/${encodeURIComponent(formId)}`, {
39149
38801
  headers: { authorization: `Bearer ${accessToken}` },
39150
38802
  signal: AbortSignal.timeout(timeoutMs)
39151
38803
  });
@@ -39180,7 +38832,7 @@ async function listResponses(inv, accessToken, timeoutMs) {
39180
38832
  if (pageToken) params.set("pageToken", pageToken);
39181
38833
  if (filter) params.set("filter", filter);
39182
38834
  const qs = params.toString();
39183
- const url = `${API12}/forms/${encodeURIComponent(formId)}/responses${qs ? `?${qs}` : ""}`;
38835
+ const url = `${API11}/forms/${encodeURIComponent(formId)}/responses${qs ? `?${qs}` : ""}`;
39184
38836
  const res = await fetch(url, {
39185
38837
  headers: { authorization: `Bearer ${accessToken}` },
39186
38838
  signal: AbortSignal.timeout(timeoutMs)
@@ -39217,7 +38869,7 @@ async function getResponse(inv, accessToken, timeoutMs) {
39217
38869
  if (!formId) throw new Error("google-forms get_response: formId is required");
39218
38870
  if (!responseId) throw new Error("google-forms get_response: responseId is required");
39219
38871
  const res = await fetch(
39220
- `${API12}/forms/${encodeURIComponent(formId)}/responses/${encodeURIComponent(responseId)}`,
38872
+ `${API11}/forms/${encodeURIComponent(formId)}/responses/${encodeURIComponent(responseId)}`,
39221
38873
  {
39222
38874
  headers: { authorization: `Bearer ${accessToken}` },
39223
38875
  signal: AbortSignal.timeout(timeoutMs)
@@ -39251,7 +38903,7 @@ async function createForm(inv, accessToken, timeoutMs) {
39251
38903
  if (!title) throw new Error("google-forms create_form: title is required");
39252
38904
  const info = { title };
39253
38905
  if (documentTitle) info.documentTitle = documentTitle;
39254
- const res = await fetch(`${API12}/forms`, {
38906
+ const res = await fetch(`${API11}/forms`, {
39255
38907
  method: "POST",
39256
38908
  headers: {
39257
38909
  authorization: `Bearer ${accessToken}`,
@@ -39290,7 +38942,7 @@ async function batchUpdate(inv, accessToken, timeoutMs) {
39290
38942
  const body = { requests };
39291
38943
  if (typeof includeFormInResponse === "boolean") body.includeFormInResponse = includeFormInResponse;
39292
38944
  if (writeControl) body.writeControl = writeControl;
39293
- const res = await fetch(`${API12}/forms/${encodeURIComponent(formId)}:batchUpdate`, {
38945
+ const res = await fetch(`${API11}/forms/${encodeURIComponent(formId)}:batchUpdate`, {
39294
38946
  method: "POST",
39295
38947
  headers: {
39296
38948
  authorization: `Bearer ${accessToken}`,
@@ -39330,7 +38982,7 @@ async function ensureFreshAccessToken10(creds, clientId, clientSecret) {
39330
38982
  throw new CredentialsExpired("Google Forms access token expired and no refresh token", "");
39331
38983
  }
39332
38984
  const refreshed = await refreshAccessToken({
39333
- tokenUrl: TOKEN_URL13,
38985
+ tokenUrl: TOKEN_URL12,
39334
38986
  clientId,
39335
38987
  clientSecret,
39336
38988
  refreshToken: creds.refreshToken
@@ -39351,8 +39003,8 @@ var SCOPES11 = [
39351
39003
  // offline_access is required on v2.0 to receive a refresh_token.
39352
39004
  "offline_access"
39353
39005
  ];
39354
- var AUTH_URL14 = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
39355
- var TOKEN_URL14 = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
39006
+ var AUTH_URL13 = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
39007
+ var TOKEN_URL13 = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
39356
39008
  var GRAPH = "https://graph.microsoft.com/v1.0";
39357
39009
  function microsoftGraph(opts) {
39358
39010
  const { clientId, clientSecret } = opts;
@@ -39363,8 +39015,8 @@ function microsoftGraph(opts) {
39363
39015
  description: "Query the Microsoft 365 directory \u2014 look up users by email, list organizations, enumerate groups, and resolve group membership. Read-only identity surface shared across the Outlook, Teams, SharePoint, and OneDrive adapters.",
39364
39016
  auth: {
39365
39017
  kind: "oauth2",
39366
- authorizationUrl: AUTH_URL14,
39367
- tokenUrl: TOKEN_URL14,
39018
+ authorizationUrl: AUTH_URL13,
39019
+ tokenUrl: TOKEN_URL13,
39368
39020
  scopes: SCOPES11,
39369
39021
  clientIdEnv: "MS_OAUTH_CLIENT_ID",
39370
39022
  clientSecretEnv: "MS_OAUTH_CLIENT_SECRET"
@@ -39549,7 +39201,7 @@ function microsoftGraph(opts) {
39549
39201
  throw new Error("Microsoft OAuth client not configured (MS_OAUTH_CLIENT_ID / _SECRET)");
39550
39202
  }
39551
39203
  const tokens = await exchangeAuthorizationCode({
39552
- tokenUrl: TOKEN_URL14,
39204
+ tokenUrl: TOKEN_URL13,
39553
39205
  clientId,
39554
39206
  clientSecret,
39555
39207
  code: input.code,
@@ -39572,7 +39224,7 @@ function microsoftGraph(opts) {
39572
39224
  throw new Error("microsoft-graph.refreshToken: missing refresh token");
39573
39225
  }
39574
39226
  const refreshed = await refreshAccessToken({
39575
- tokenUrl: TOKEN_URL14,
39227
+ tokenUrl: TOKEN_URL13,
39576
39228
  clientId,
39577
39229
  clientSecret,
39578
39230
  refreshToken: creds.refreshToken
@@ -39614,7 +39266,7 @@ async function ensureFreshAccessToken11(creds, clientId, clientSecret) {
39614
39266
  throw new CredentialsExpired("Microsoft Graph access token expired and no refresh token", "");
39615
39267
  }
39616
39268
  const refreshed = await refreshAccessToken({
39617
- tokenUrl: TOKEN_URL14,
39269
+ tokenUrl: TOKEN_URL13,
39618
39270
  clientId,
39619
39271
  clientSecret,
39620
39272
  refreshToken: creds.refreshToken
@@ -39651,9 +39303,9 @@ var SCOPE_READ2 = "https://graph.microsoft.com/Mail.Read";
39651
39303
  var SCOPE_SEND2 = "https://graph.microsoft.com/Mail.Send";
39652
39304
  var SCOPE_RW = "https://graph.microsoft.com/Mail.ReadWrite";
39653
39305
  var SCOPE_OFFLINE = "offline_access";
39654
- var AUTH_URL15 = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
39655
- var TOKEN_URL15 = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
39656
- var API13 = "https://graph.microsoft.com/v1.0";
39306
+ var AUTH_URL14 = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
39307
+ var TOKEN_URL14 = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
39308
+ var API12 = "https://graph.microsoft.com/v1.0";
39657
39309
  function outlookMail(opts) {
39658
39310
  const { clientId, clientSecret } = opts;
39659
39311
  const timeoutMs = opts.timeoutMs ?? 3e4;
@@ -39665,8 +39317,8 @@ function outlookMail(opts) {
39665
39317
  description: "Read inbox messages from a Microsoft 365 / Outlook mailbox, fetch a single message with body + attachment manifest, reply on a conversation, and subscribe to a folder for new mail webhooks.",
39666
39318
  auth: {
39667
39319
  kind: "oauth2",
39668
- authorizationUrl: AUTH_URL15,
39669
- tokenUrl: TOKEN_URL15,
39320
+ authorizationUrl: AUTH_URL14,
39321
+ tokenUrl: TOKEN_URL14,
39670
39322
  scopes,
39671
39323
  clientIdEnv: "MS_OAUTH_CLIENT_ID",
39672
39324
  clientSecretEnv: "MS_OAUTH_CLIENT_SECRET"
@@ -39750,6 +39402,19 @@ function outlookMail(opts) {
39750
39402
  type: "boolean",
39751
39403
  default: false,
39752
39404
  description: "When true, set Graph body.contentType=HTML and send body as HTML; otherwise text. Graph does NOT auto-derive a plain alternative \u2014 set html only when the body is HTML."
39405
+ },
39406
+ attachments: {
39407
+ type: "array",
39408
+ description: "Optional file attachments. Each item is { name, contentType?, contentBytes } where contentBytes is base64-encoded file data. Sent as Graph #microsoft.graph.fileAttachment entries.",
39409
+ items: {
39410
+ type: "object",
39411
+ properties: {
39412
+ name: { type: "string" },
39413
+ contentType: { type: "string" },
39414
+ contentBytes: { type: "string", description: "Base64-encoded attachment bytes." }
39415
+ },
39416
+ required: ["name", "contentBytes"]
39417
+ }
39753
39418
  }
39754
39419
  },
39755
39420
  required: ["to", "subject", "body"]
@@ -39780,6 +39445,19 @@ function outlookMail(opts) {
39780
39445
  type: "boolean",
39781
39446
  default: false,
39782
39447
  description: "When true, set Graph body.contentType=HTML; otherwise text."
39448
+ },
39449
+ attachments: {
39450
+ type: "array",
39451
+ description: "Optional file attachments. Each item is { name, contentType?, contentBytes } where contentBytes is base64-encoded file data. Stored as Graph #microsoft.graph.fileAttachment entries on the draft.",
39452
+ items: {
39453
+ type: "object",
39454
+ properties: {
39455
+ name: { type: "string" },
39456
+ contentType: { type: "string" },
39457
+ contentBytes: { type: "string", description: "Base64-encoded attachment bytes." }
39458
+ },
39459
+ required: ["name", "contentBytes"]
39460
+ }
39783
39461
  }
39784
39462
  },
39785
39463
  required: ["to", "subject", "body"]
@@ -39802,6 +39480,94 @@ function outlookMail(opts) {
39802
39480
  },
39803
39481
  required: ["notificationUrl"]
39804
39482
  }
39483
+ },
39484
+ {
39485
+ name: "forward_message",
39486
+ class: "mutation",
39487
+ description: "Forward an existing message to one or more recipients with an optional comment. Graph POST /me/messages/{id}/forward.",
39488
+ cas: "native-idempotency",
39489
+ externalEffect: true,
39490
+ requiredScopes: [SCOPE_SEND2],
39491
+ parameters: {
39492
+ type: "object",
39493
+ properties: {
39494
+ messageId: { type: "string", description: "Graph message id to forward." },
39495
+ to: {
39496
+ oneOf: [
39497
+ { type: "string" },
39498
+ { type: "array", items: { type: "string" } }
39499
+ ],
39500
+ description: "Recipient address(es). String OR array of strings."
39501
+ },
39502
+ comment: { type: "string", description: "Optional comment prepended to the forwarded body." }
39503
+ },
39504
+ required: ["messageId", "to"]
39505
+ }
39506
+ },
39507
+ {
39508
+ name: "move_message",
39509
+ class: "mutation",
39510
+ description: "Move a message to a destination mail folder by id (or well-known name like inbox/archive). Graph POST /me/messages/{id}/move; returns the relocated message (new id).",
39511
+ cas: "native-idempotency",
39512
+ externalEffect: true,
39513
+ requiredScopes: [SCOPE_RW],
39514
+ parameters: {
39515
+ type: "object",
39516
+ properties: {
39517
+ messageId: { type: "string", description: "Graph message id to move." },
39518
+ destinationId: { type: "string", description: "Destination folder id or well-known name (inbox, archive, deleteditems, ...)." }
39519
+ },
39520
+ required: ["messageId", "destinationId"]
39521
+ }
39522
+ },
39523
+ {
39524
+ name: "set_labels",
39525
+ class: "mutation",
39526
+ description: "Set the full set of Outlook categories (labels) on a message. Graph PATCH /me/messages/{id} replaces the categories array, so supply the complete desired set (the caller computes adds/removes against the current set).",
39527
+ cas: "optimistic-read-verify",
39528
+ externalEffect: false,
39529
+ requiredScopes: [SCOPE_RW],
39530
+ parameters: {
39531
+ type: "object",
39532
+ properties: {
39533
+ messageId: { type: "string", description: "Graph message id to tag." },
39534
+ categories: {
39535
+ type: "array",
39536
+ items: { type: "string" },
39537
+ description: "Full desired category set. Graph replaces (not merges) the categories array."
39538
+ }
39539
+ },
39540
+ required: ["messageId", "categories"]
39541
+ }
39542
+ },
39543
+ {
39544
+ name: "send_draft",
39545
+ class: "mutation",
39546
+ description: "Send a previously created draft message by id. Graph POST /me/messages/{id}/send. Pairs with create_draft.",
39547
+ cas: "native-idempotency",
39548
+ externalEffect: true,
39549
+ requiredScopes: [SCOPE_SEND2],
39550
+ parameters: {
39551
+ type: "object",
39552
+ properties: {
39553
+ messageId: { type: "string", description: "Graph draft message id to send." }
39554
+ },
39555
+ required: ["messageId"]
39556
+ }
39557
+ },
39558
+ {
39559
+ name: "download_attachment",
39560
+ class: "read",
39561
+ description: "Read an attachment record for a message including base64 contentBytes for file attachments. Graph GET /me/messages/{messageId}/attachments/{attachmentId}. Fills the attachment-bytes gap that read_message defers.",
39562
+ requiredScopes: [SCOPE_READ2],
39563
+ parameters: {
39564
+ type: "object",
39565
+ properties: {
39566
+ messageId: { type: "string", description: "Graph message id owning the attachment." },
39567
+ attachmentId: { type: "string", description: "Graph attachment id (from read_message attachments[].id)." }
39568
+ },
39569
+ required: ["messageId", "attachmentId"]
39570
+ }
39805
39571
  }
39806
39572
  ]
39807
39573
  },
@@ -39809,6 +39575,7 @@ function outlookMail(opts) {
39809
39575
  const accessToken = await ensureFreshAccessToken12(inv.source.credentials, clientId, clientSecret, inv.onCredentialsRotated);
39810
39576
  if (inv.capabilityName === "list_messages") return listMessages2(inv, accessToken, timeoutMs);
39811
39577
  if (inv.capabilityName === "read_message") return readMessage2(inv, accessToken, timeoutMs);
39578
+ if (inv.capabilityName === "download_attachment") return downloadAttachment(inv, accessToken, timeoutMs);
39812
39579
  throw new Error(`outlook-mail: unknown read capability ${inv.capabilityName}`);
39813
39580
  },
39814
39581
  async executeMutation(inv) {
@@ -39817,6 +39584,10 @@ function outlookMail(opts) {
39817
39584
  if (inv.capabilityName === "send_message") return sendMessage(inv, accessToken, timeoutMs);
39818
39585
  if (inv.capabilityName === "create_draft") return createDraft(inv, accessToken, timeoutMs);
39819
39586
  if (inv.capabilityName === "subscribe_folder") return subscribeFolder(inv, accessToken, timeoutMs);
39587
+ if (inv.capabilityName === "forward_message") return forwardMessage(inv, accessToken, timeoutMs);
39588
+ if (inv.capabilityName === "move_message") return moveMessage(inv, accessToken, timeoutMs);
39589
+ if (inv.capabilityName === "set_labels") return setLabels(inv, accessToken, timeoutMs);
39590
+ if (inv.capabilityName === "send_draft") return sendDraft(inv, accessToken, timeoutMs);
39820
39591
  throw new Error(`outlook-mail: unknown mutation capability ${inv.capabilityName}`);
39821
39592
  },
39822
39593
  async exchangeOAuth(input) {
@@ -39824,7 +39595,7 @@ function outlookMail(opts) {
39824
39595
  throw new Error("Outlook Mail OAuth client not configured (MS_OAUTH_CLIENT_ID / _SECRET)");
39825
39596
  }
39826
39597
  const tokens = await exchangeAuthorizationCode({
39827
- tokenUrl: TOKEN_URL15,
39598
+ tokenUrl: TOKEN_URL14,
39828
39599
  clientId,
39829
39600
  clientSecret,
39830
39601
  code: input.code,
@@ -39847,7 +39618,7 @@ function outlookMail(opts) {
39847
39618
  throw new Error("outlook-mail.refreshToken: missing refresh token");
39848
39619
  }
39849
39620
  const refreshed = await refreshAccessToken({
39850
- tokenUrl: TOKEN_URL15,
39621
+ tokenUrl: TOKEN_URL14,
39851
39622
  clientId,
39852
39623
  clientSecret,
39853
39624
  refreshToken: creds.refreshToken
@@ -39862,7 +39633,7 @@ function outlookMail(opts) {
39862
39633
  async test(source) {
39863
39634
  try {
39864
39635
  const accessToken = await ensureFreshAccessToken12(source.credentials, clientId, clientSecret);
39865
- const res = await fetch(`${API13}/me?$select=id,userPrincipalName`, {
39636
+ const res = await fetch(`${API12}/me?$select=id,userPrincipalName`, {
39866
39637
  headers: { authorization: `Bearer ${accessToken}` },
39867
39638
  signal: AbortSignal.timeout(8e3)
39868
39639
  });
@@ -39890,7 +39661,7 @@ async function listMessages2(inv, accessToken, timeoutMs) {
39890
39661
  if (args.skipToken) params.set("$skiptoken", args.skipToken);
39891
39662
  const headers = { authorization: `Bearer ${accessToken}` };
39892
39663
  if (args.query) headers["ConsistencyLevel"] = "eventual";
39893
- const res = await fetch(`${API13}/me/mailFolders/${folder}/messages?${params.toString()}`, {
39664
+ const res = await fetch(`${API12}/me/mailFolders/${folder}/messages?${params.toString()}`, {
39894
39665
  headers,
39895
39666
  signal: AbortSignal.timeout(timeoutMs)
39896
39667
  });
@@ -39924,7 +39695,7 @@ function toMessageSummary2(m) {
39924
39695
  }
39925
39696
  async function readMessage2(inv, accessToken, timeoutMs) {
39926
39697
  const { id } = inv.args;
39927
- const url = `${API13}/me/messages/${encodeURIComponent(id)}?$expand=attachments($select=id,name,contentType,size,isInline)`;
39698
+ const url = `${API12}/me/messages/${encodeURIComponent(id)}?$expand=attachments($select=id,name,contentType,size,isInline)`;
39928
39699
  const res = await fetch(url, {
39929
39700
  headers: { authorization: `Bearer ${accessToken}` },
39930
39701
  signal: AbortSignal.timeout(timeoutMs)
@@ -39967,7 +39738,7 @@ async function readMessage2(inv, accessToken, timeoutMs) {
39967
39738
  async function sendReply2(inv, accessToken, timeoutMs) {
39968
39739
  const { messageId, body, bodyType, replyAll, comment } = inv.args;
39969
39740
  const action = replyAll ? "createReplyAll" : "createReply";
39970
- const draftRes = await fetch(`${API13}/me/messages/${encodeURIComponent(messageId)}/${action}`, {
39741
+ const draftRes = await fetch(`${API12}/me/messages/${encodeURIComponent(messageId)}/${action}`, {
39971
39742
  method: "POST",
39972
39743
  headers: {
39973
39744
  authorization: `Bearer ${accessToken}`,
@@ -39990,7 +39761,7 @@ async function sendReply2(inv, accessToken, timeoutMs) {
39990
39761
  { name: "X-Tangle-Idempotency-Key", value: inv.idempotencyKey }
39991
39762
  ]
39992
39763
  };
39993
- const patchRes = await fetch(`${API13}/me/messages/${encodeURIComponent(draft.id)}`, {
39764
+ const patchRes = await fetch(`${API12}/me/messages/${encodeURIComponent(draft.id)}`, {
39994
39765
  method: "PATCH",
39995
39766
  headers: {
39996
39767
  authorization: `Bearer ${accessToken}`,
@@ -40006,7 +39777,7 @@ async function sendReply2(inv, accessToken, timeoutMs) {
40006
39777
  const text = await patchRes.text().catch(() => "");
40007
39778
  throw new Error(`outlook-mail send_reply patch ${patchRes.status}: ${text.slice(0, 200)}`);
40008
39779
  }
40009
- const sendRes = await fetch(`${API13}/me/messages/${encodeURIComponent(draft.id)}/send`, {
39780
+ const sendRes = await fetch(`${API12}/me/messages/${encodeURIComponent(draft.id)}/send`, {
40010
39781
  method: "POST",
40011
39782
  headers: { authorization: `Bearer ${accessToken}` },
40012
39783
  signal: AbortSignal.timeout(timeoutMs)
@@ -40053,12 +39824,25 @@ function buildMessagePayload(args, idempotencyKey, cap) {
40053
39824
  if (args.bcc?.length) {
40054
39825
  payload.bccRecipients = args.bcc.map((address) => ({ emailAddress: { address } }));
40055
39826
  }
39827
+ if (args.attachments?.length) {
39828
+ payload.attachments = args.attachments.map((a) => {
39829
+ if (!a?.name) throw new Error(`outlook-mail ${cap}: attachment \`name\` is required`);
39830
+ if (!a?.contentBytes) throw new Error(`outlook-mail ${cap}: attachment \`contentBytes\` (base64) is required`);
39831
+ const att = {
39832
+ "@odata.type": "#microsoft.graph.fileAttachment",
39833
+ name: a.name,
39834
+ contentBytes: a.contentBytes
39835
+ };
39836
+ if (a.contentType) att.contentType = a.contentType;
39837
+ return att;
39838
+ });
39839
+ }
40056
39840
  return payload;
40057
39841
  }
40058
39842
  async function sendMessage(inv, accessToken, timeoutMs) {
40059
39843
  const args = inv.args ?? {};
40060
39844
  const message = buildMessagePayload(args, inv.idempotencyKey, "send_message");
40061
- const res = await fetch(`${API13}/me/sendMail`, {
39845
+ const res = await fetch(`${API12}/me/sendMail`, {
40062
39846
  method: "POST",
40063
39847
  headers: {
40064
39848
  authorization: `Bearer ${accessToken}`,
@@ -40088,7 +39872,7 @@ async function sendMessage(inv, accessToken, timeoutMs) {
40088
39872
  async function createDraft(inv, accessToken, timeoutMs) {
40089
39873
  const args = inv.args ?? {};
40090
39874
  const message = buildMessagePayload(args, inv.idempotencyKey, "create_draft");
40091
- const res = await fetch(`${API13}/me/messages`, {
39875
+ const res = await fetch(`${API12}/me/messages`, {
40092
39876
  method: "POST",
40093
39877
  headers: {
40094
39878
  authorization: `Bearer ${accessToken}`,
@@ -40129,7 +39913,7 @@ async function subscribeFolder(inv, accessToken, timeoutMs) {
40129
39913
  expirationDateTime,
40130
39914
  clientState: clientState ?? inv.idempotencyKey
40131
39915
  };
40132
- const res = await fetch(`${API13}/subscriptions`, {
39916
+ const res = await fetch(`${API12}/subscriptions`, {
40133
39917
  method: "POST",
40134
39918
  headers: {
40135
39919
  authorization: `Bearer ${accessToken}`,
@@ -40158,6 +39942,162 @@ async function subscribeFolder(inv, accessToken, timeoutMs) {
40158
39942
  idempotentReplay: false
40159
39943
  };
40160
39944
  }
39945
+ async function forwardMessage(inv, accessToken, timeoutMs) {
39946
+ const { messageId, to, comment } = inv.args;
39947
+ if (!messageId) throw new Error("outlook-mail forward_message: `messageId` is required");
39948
+ if (!to || Array.isArray(to) && to.length === 0) {
39949
+ throw new Error("outlook-mail forward_message: `to` is required");
39950
+ }
39951
+ const toList = Array.isArray(to) ? to : [to];
39952
+ const toRecipients = toList.map((address) => ({ emailAddress: { address } }));
39953
+ const fwdBody = {
39954
+ toRecipients
39955
+ };
39956
+ if (comment !== void 0) fwdBody.comment = comment;
39957
+ const res = await fetch(`${API12}/me/messages/${encodeURIComponent(messageId)}/forward`, {
39958
+ method: "POST",
39959
+ headers: {
39960
+ authorization: `Bearer ${accessToken}`,
39961
+ "content-type": "application/json"
39962
+ },
39963
+ body: JSON.stringify(fwdBody),
39964
+ signal: AbortSignal.timeout(timeoutMs)
39965
+ });
39966
+ if (res.status === 401 || res.status === 403) {
39967
+ throw new CredentialsExpired(`Outlook Mail rejected token (${res.status})`, inv.source.id);
39968
+ }
39969
+ if (!res.ok && res.status !== 202) {
39970
+ const text = await res.text().catch(() => "");
39971
+ throw new Error(`outlook-mail forward_message ${res.status}: ${text.slice(0, 200)}`);
39972
+ }
39973
+ return {
39974
+ status: "committed",
39975
+ data: { forwarded: true, messageId, to: toList },
39976
+ committedAt: Date.now(),
39977
+ idempotentReplay: false
39978
+ };
39979
+ }
39980
+ async function moveMessage(inv, accessToken, timeoutMs) {
39981
+ const { messageId, destinationId } = inv.args;
39982
+ if (!messageId) throw new Error("outlook-mail move_message: `messageId` is required");
39983
+ if (!destinationId) throw new Error("outlook-mail move_message: `destinationId` is required");
39984
+ const res = await fetch(`${API12}/me/messages/${encodeURIComponent(messageId)}/move`, {
39985
+ method: "POST",
39986
+ headers: {
39987
+ authorization: `Bearer ${accessToken}`,
39988
+ "content-type": "application/json"
39989
+ },
39990
+ body: JSON.stringify({ destinationId }),
39991
+ signal: AbortSignal.timeout(timeoutMs)
39992
+ });
39993
+ if (res.status === 401 || res.status === 403) {
39994
+ throw new CredentialsExpired(`Outlook Mail rejected token (${res.status})`, inv.source.id);
39995
+ }
39996
+ if (!res.ok) {
39997
+ const text = await res.text().catch(() => "");
39998
+ throw new Error(`outlook-mail move_message ${res.status}: ${text.slice(0, 200)}`);
39999
+ }
40000
+ const json = await res.json().catch(() => ({}));
40001
+ return {
40002
+ status: "committed",
40003
+ data: {
40004
+ moved: true,
40005
+ messageId: json.id ?? messageId,
40006
+ parentFolderId: json.parentFolderId ?? destinationId,
40007
+ destinationId
40008
+ },
40009
+ committedAt: Date.now(),
40010
+ idempotentReplay: false
40011
+ };
40012
+ }
40013
+ async function setLabels(inv, accessToken, timeoutMs) {
40014
+ const { messageId, categories } = inv.args;
40015
+ if (!messageId) throw new Error("outlook-mail set_labels: `messageId` is required");
40016
+ if (!Array.isArray(categories)) {
40017
+ throw new Error("outlook-mail set_labels: `categories` must be an array (the full desired set)");
40018
+ }
40019
+ const res = await fetch(`${API12}/me/messages/${encodeURIComponent(messageId)}`, {
40020
+ method: "PATCH",
40021
+ headers: {
40022
+ authorization: `Bearer ${accessToken}`,
40023
+ "content-type": "application/json"
40024
+ },
40025
+ body: JSON.stringify({ categories }),
40026
+ signal: AbortSignal.timeout(timeoutMs)
40027
+ });
40028
+ if (res.status === 401 || res.status === 403) {
40029
+ throw new CredentialsExpired(`Outlook Mail rejected token (${res.status})`, inv.source.id);
40030
+ }
40031
+ if (!res.ok) {
40032
+ const text = await res.text().catch(() => "");
40033
+ throw new Error(`outlook-mail set_labels ${res.status}: ${text.slice(0, 200)}`);
40034
+ }
40035
+ const json = await res.json().catch(() => ({}));
40036
+ return {
40037
+ status: "committed",
40038
+ data: {
40039
+ messageId: json.id ?? messageId,
40040
+ categories: json.categories ?? categories
40041
+ },
40042
+ committedAt: Date.now(),
40043
+ idempotentReplay: false
40044
+ };
40045
+ }
40046
+ async function sendDraft(inv, accessToken, timeoutMs) {
40047
+ const { messageId } = inv.args;
40048
+ if (!messageId) throw new Error("outlook-mail send_draft: `messageId` is required");
40049
+ const res = await fetch(`${API12}/me/messages/${encodeURIComponent(messageId)}/send`, {
40050
+ method: "POST",
40051
+ headers: { authorization: `Bearer ${accessToken}` },
40052
+ signal: AbortSignal.timeout(timeoutMs)
40053
+ });
40054
+ if (res.status === 401 || res.status === 403) {
40055
+ throw new CredentialsExpired(`Outlook Mail rejected token (${res.status})`, inv.source.id);
40056
+ }
40057
+ if (!res.ok && res.status !== 202) {
40058
+ const text = await res.text().catch(() => "");
40059
+ throw new Error(`outlook-mail send_draft ${res.status}: ${text.slice(0, 200)}`);
40060
+ }
40061
+ return {
40062
+ status: "committed",
40063
+ data: { sent: true, messageId },
40064
+ committedAt: Date.now(),
40065
+ idempotentReplay: false
40066
+ };
40067
+ }
40068
+ async function downloadAttachment(inv, accessToken, timeoutMs) {
40069
+ const { messageId, attachmentId } = inv.args;
40070
+ const url = `${API12}/me/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachmentId)}`;
40071
+ const res = await fetch(url, {
40072
+ headers: { authorization: `Bearer ${accessToken}` },
40073
+ signal: AbortSignal.timeout(timeoutMs)
40074
+ });
40075
+ if (res.status === 401 || res.status === 403) {
40076
+ throw new CredentialsExpired(`Outlook Mail rejected token (${res.status})`, inv.source.id);
40077
+ }
40078
+ if (res.status === 404) {
40079
+ throw new Error(`outlook-mail download_attachment: attachment ${attachmentId} on message ${messageId} not found`);
40080
+ }
40081
+ if (!res.ok) {
40082
+ const text = await res.text().catch(() => "");
40083
+ throw new Error(`outlook-mail download_attachment ${res.status}: ${text.slice(0, 200)}`);
40084
+ }
40085
+ const a = await res.json();
40086
+ return {
40087
+ data: {
40088
+ id: a.id ?? attachmentId,
40089
+ name: a.name ?? "",
40090
+ contentType: a.contentType ?? "application/octet-stream",
40091
+ size: a.size ?? 0,
40092
+ isInline: a.isInline ?? false,
40093
+ attachmentType: a["@odata.type"],
40094
+ // Base64 bytes for file attachments; null for item/reference attachments
40095
+ // which carry no inline contentBytes.
40096
+ contentBytes: a.contentBytes ?? null
40097
+ },
40098
+ fetchedAt: Date.now()
40099
+ };
40100
+ }
40161
40101
  async function ensureFreshAccessToken12(creds, clientId, clientSecret, onCredentialsRotated) {
40162
40102
  if (creds.kind !== "oauth2") {
40163
40103
  throw new Error("outlook-mail: expected oauth2 credentials");
@@ -40169,7 +40109,7 @@ async function ensureFreshAccessToken12(creds, clientId, clientSecret, onCredent
40169
40109
  throw new CredentialsExpired("Outlook Mail access token expired and no refresh token", "");
40170
40110
  }
40171
40111
  const refreshed = await refreshAccessToken({
40172
- tokenUrl: TOKEN_URL15,
40112
+ tokenUrl: TOKEN_URL14,
40173
40113
  clientId,
40174
40114
  clientSecret,
40175
40115
  refreshToken: creds.refreshToken
@@ -40197,8 +40137,8 @@ var SCOPES12 = [
40197
40137
  // offline_access is required on v2.0 to receive a refresh_token.
40198
40138
  "offline_access"
40199
40139
  ];
40200
- var AUTH_URL16 = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
40201
- var TOKEN_URL16 = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
40140
+ var AUTH_URL15 = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
40141
+ var TOKEN_URL15 = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
40202
40142
  var GRAPH2 = "https://graph.microsoft.com/v1.0";
40203
40143
  function microsoftTeams(opts) {
40204
40144
  const { clientId, clientSecret } = opts;
@@ -40209,8 +40149,8 @@ function microsoftTeams(opts) {
40209
40149
  description: "Post messages from the agent into Microsoft Teams channels and 1:1/group chats, list teams and channels, and look up users by email. Advisory surface \u2014 Teams posts are informational, not transactional.",
40210
40150
  auth: {
40211
40151
  kind: "oauth2",
40212
- authorizationUrl: AUTH_URL16,
40213
- tokenUrl: TOKEN_URL16,
40152
+ authorizationUrl: AUTH_URL15,
40153
+ tokenUrl: TOKEN_URL15,
40214
40154
  scopes: SCOPES12,
40215
40155
  clientIdEnv: "MS_OAUTH_CLIENT_ID",
40216
40156
  clientSecretEnv: "MS_OAUTH_CLIENT_SECRET"
@@ -40396,7 +40336,7 @@ function microsoftTeams(opts) {
40396
40336
  throw new Error("Microsoft OAuth client not configured (MS_OAUTH_CLIENT_ID / _SECRET)");
40397
40337
  }
40398
40338
  const tokens = await exchangeAuthorizationCode({
40399
- tokenUrl: TOKEN_URL16,
40339
+ tokenUrl: TOKEN_URL15,
40400
40340
  clientId,
40401
40341
  clientSecret,
40402
40342
  code: input.code,
@@ -40419,7 +40359,7 @@ function microsoftTeams(opts) {
40419
40359
  throw new Error("microsoft-teams.refreshToken: missing refresh token");
40420
40360
  }
40421
40361
  const refreshed = await refreshAccessToken({
40422
- tokenUrl: TOKEN_URL16,
40362
+ tokenUrl: TOKEN_URL15,
40423
40363
  clientId,
40424
40364
  clientSecret,
40425
40365
  refreshToken: creds.refreshToken
@@ -40461,7 +40401,7 @@ async function ensureFreshAccessToken13(creds, clientId, clientSecret) {
40461
40401
  throw new CredentialsExpired("Microsoft Teams access token expired and no refresh token", "");
40462
40402
  }
40463
40403
  const refreshed = await refreshAccessToken({
40464
- tokenUrl: TOKEN_URL16,
40404
+ tokenUrl: TOKEN_URL15,
40465
40405
  clientId,
40466
40406
  clientSecret,
40467
40407
  refreshToken: creds.refreshToken
@@ -40513,9 +40453,9 @@ function escapeOData2(value) {
40513
40453
  var SCOPE_READ3 = "https://graph.microsoft.com/Files.Read";
40514
40454
  var SCOPE_WRITE4 = "https://graph.microsoft.com/Files.ReadWrite";
40515
40455
  var SCOPE_OFFLINE2 = "offline_access";
40516
- var AUTH_URL17 = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
40517
- var TOKEN_URL17 = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
40518
- var API14 = "https://graph.microsoft.com/v1.0";
40456
+ var AUTH_URL16 = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
40457
+ var TOKEN_URL16 = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
40458
+ var API13 = "https://graph.microsoft.com/v1.0";
40519
40459
  function oneDrive(opts) {
40520
40460
  const { clientId, clientSecret } = opts;
40521
40461
  const timeoutMs = opts.timeoutMs ?? 3e4;
@@ -40527,8 +40467,8 @@ function oneDrive(opts) {
40527
40467
  description: "Read and watch files in the user's OneDrive. List a folder, fetch a document's contents (Word/Excel/PowerPoint/PDF/images), and subscribe to folder change notifications via Graph subscriptions.",
40528
40468
  auth: {
40529
40469
  kind: "oauth2",
40530
- authorizationUrl: AUTH_URL17,
40531
- tokenUrl: TOKEN_URL17,
40470
+ authorizationUrl: AUTH_URL16,
40471
+ tokenUrl: TOKEN_URL16,
40532
40472
  scopes,
40533
40473
  clientIdEnv: "MS_OAUTH_CLIENT_ID",
40534
40474
  clientSecretEnv: "MS_OAUTH_CLIENT_SECRET"
@@ -40705,7 +40645,7 @@ function oneDrive(opts) {
40705
40645
  throw new Error("OneDrive OAuth client not configured (MS_OAUTH_CLIENT_ID / _SECRET)");
40706
40646
  }
40707
40647
  const tokens = await exchangeAuthorizationCode({
40708
- tokenUrl: TOKEN_URL17,
40648
+ tokenUrl: TOKEN_URL16,
40709
40649
  clientId,
40710
40650
  clientSecret,
40711
40651
  code: input.code,
@@ -40728,7 +40668,7 @@ function oneDrive(opts) {
40728
40668
  throw new Error("onedrive.refreshToken: missing refresh token");
40729
40669
  }
40730
40670
  const refreshed = await refreshAccessToken({
40731
- tokenUrl: TOKEN_URL17,
40671
+ tokenUrl: TOKEN_URL16,
40732
40672
  clientId,
40733
40673
  clientSecret,
40734
40674
  refreshToken: creds.refreshToken
@@ -40743,7 +40683,7 @@ function oneDrive(opts) {
40743
40683
  async test(source) {
40744
40684
  try {
40745
40685
  const accessToken = await ensureFreshAccessToken14(source.credentials, clientId, clientSecret);
40746
- const res = await fetch(`${API14}/me/drive?$select=id`, {
40686
+ const res = await fetch(`${API13}/me/drive?$select=id`, {
40747
40687
  headers: { authorization: `Bearer ${accessToken}` },
40748
40688
  signal: AbortSignal.timeout(8e3)
40749
40689
  });
@@ -40772,7 +40712,7 @@ async function listFiles2(inv, accessToken, timeoutMs) {
40772
40712
  if (args.query) headers["ConsistencyLevel"] = "eventual";
40773
40713
  const path = args.folderId ? `/me/drive/items/${encodeURIComponent(args.folderId)}/children` : "/me/drive/root/children";
40774
40714
  const useSearchEndpoint = !!args.query && !args.folderId;
40775
- const url = useSearchEndpoint ? `${API14}/me/drive/root/search(q=${encodeURIComponent(`'${args.query.replace(/'/g, "''")}'`)})?${stripSearch(params).toString()}` : `${API14}${path}?${params.toString()}`;
40715
+ const url = useSearchEndpoint ? `${API13}/me/drive/root/search(q=${encodeURIComponent(`'${args.query.replace(/'/g, "''")}'`)})?${stripSearch(params).toString()}` : `${API13}${path}?${params.toString()}`;
40776
40716
  const res = await fetch(url, {
40777
40717
  headers,
40778
40718
  signal: AbortSignal.timeout(timeoutMs)
@@ -40802,7 +40742,7 @@ function stripSearch(params) {
40802
40742
  async function readFile2(inv, accessToken, timeoutMs) {
40803
40743
  const { fileId } = inv.args ?? {};
40804
40744
  if (!fileId) throw new Error("onedrive read_file: fileId is required");
40805
- const metaUrl = `${API14}/me/drive/items/${encodeURIComponent(fileId)}?$select=id,name,eTag,lastModifiedDateTime,size,file,folder`;
40745
+ const metaUrl = `${API13}/me/drive/items/${encodeURIComponent(fileId)}?$select=id,name,eTag,lastModifiedDateTime,size,file,folder`;
40806
40746
  const metaRes = await fetch(metaUrl, {
40807
40747
  headers: { authorization: `Bearer ${accessToken}` },
40808
40748
  signal: AbortSignal.timeout(timeoutMs)
@@ -40823,7 +40763,7 @@ async function readFile2(inv, accessToken, timeoutMs) {
40823
40763
  }
40824
40764
  const mimeType = meta.file?.mimeType ?? "application/octet-stream";
40825
40765
  const fetchedAt = Date.now();
40826
- const contentRes = await fetch(`${API14}/me/drive/items/${encodeURIComponent(fileId)}/content`, {
40766
+ const contentRes = await fetch(`${API13}/me/drive/items/${encodeURIComponent(fileId)}/content`, {
40827
40767
  headers: { authorization: `Bearer ${accessToken}` },
40828
40768
  signal: AbortSignal.timeout(timeoutMs)
40829
40769
  });
@@ -40876,7 +40816,7 @@ async function watchFolder2(inv, accessToken, timeoutMs) {
40876
40816
  expirationDateTime,
40877
40817
  clientState: clientState ?? inv.idempotencyKey
40878
40818
  };
40879
- const res = await fetch(`${API14}/subscriptions`, {
40819
+ const res = await fetch(`${API13}/subscriptions`, {
40880
40820
  method: "POST",
40881
40821
  headers: {
40882
40822
  authorization: `Bearer ${accessToken}`,
@@ -40916,7 +40856,7 @@ async function uploadFile3(inv, accessToken, timeoutMs) {
40916
40856
  }
40917
40857
  const body = encoding === "base64" ? Buffer.from(fileContent, "base64") : Buffer.from(fileContent, "utf-8");
40918
40858
  const parentSegment = folderId === "root" ? "/me/drive/root" : `/me/drive/items/${encodeURIComponent(folderId)}`;
40919
- const url = `${API14}${parentSegment}:/${encodeURIComponent(fileName)}:/content`;
40859
+ const url = `${API13}${parentSegment}:/${encodeURIComponent(fileName)}:/content`;
40920
40860
  const res = await fetch(url, {
40921
40861
  method: "PUT",
40922
40862
  headers: {
@@ -40952,7 +40892,7 @@ async function uploadFile3(inv, accessToken, timeoutMs) {
40952
40892
  async function deleteItem(inv, accessToken, timeoutMs) {
40953
40893
  const { itemId } = inv.args ?? {};
40954
40894
  if (!itemId) throw new Error("onedrive files.delete: itemId is required");
40955
- const res = await fetch(`${API14}${itemPath(itemId)}`, {
40895
+ const res = await fetch(`${API13}${itemPath(itemId)}`, {
40956
40896
  method: "DELETE",
40957
40897
  headers: { authorization: `Bearer ${accessToken}` },
40958
40898
  signal: AbortSignal.timeout(timeoutMs)
@@ -40990,7 +40930,7 @@ async function moveItem(inv, accessToken, timeoutMs) {
40990
40930
  body.parentReference = newParentId === "root" ? { path: "/drive/root" } : { id: newParentId };
40991
40931
  }
40992
40932
  if (newName) body.name = newName;
40993
- const res = await fetch(`${API14}${itemPath(itemId)}`, {
40933
+ const res = await fetch(`${API13}${itemPath(itemId)}`, {
40994
40934
  method: "PATCH",
40995
40935
  headers: {
40996
40936
  authorization: `Bearer ${accessToken}`,
@@ -41030,7 +40970,7 @@ async function shareItem(inv, accessToken, timeoutMs) {
41030
40970
  };
41031
40971
  if (password) body.password = password;
41032
40972
  if (expirationDateTime) body.expirationDateTime = expirationDateTime;
41033
- const res = await fetch(`${API14}${itemPath(itemId)}/createLink`, {
40973
+ const res = await fetch(`${API13}${itemPath(itemId)}/createLink`, {
41034
40974
  method: "POST",
41035
40975
  headers: {
41036
40976
  authorization: `Bearer ${accessToken}`,
@@ -41069,7 +41009,7 @@ async function createFolder2(inv, accessToken, timeoutMs) {
41069
41009
  folder: {},
41070
41010
  "@microsoft.graph.conflictBehavior": conflictBehavior ?? "fail"
41071
41011
  };
41072
- const res = await fetch(`${API14}${parentSegment}`, {
41012
+ const res = await fetch(`${API13}${parentSegment}`, {
41073
41013
  method: "POST",
41074
41014
  headers: {
41075
41015
  authorization: `Bearer ${accessToken}`,
@@ -41111,7 +41051,7 @@ async function ensureFreshAccessToken14(creds, clientId, clientSecret, onCredent
41111
41051
  throw new CredentialsExpired("OneDrive access token expired and no refresh token", "");
41112
41052
  }
41113
41053
  const refreshed = await refreshAccessToken({
41114
- tokenUrl: TOKEN_URL17,
41054
+ tokenUrl: TOKEN_URL16,
41115
41055
  clientId,
41116
41056
  clientSecret,
41117
41057
  refreshToken: creds.refreshToken
@@ -41130,13 +41070,13 @@ async function ensureFreshAccessToken14(creds, clientId, clientSecret, onCredent
41130
41070
 
41131
41071
  // src/connectors/adapters/sharepoint.ts
41132
41072
  var SCOPES13 = [
41133
- "https://graph.microsoft.com/Sites.Read.All",
41073
+ "https://graph.microsoft.com/Sites.ReadWrite.All",
41134
41074
  "https://graph.microsoft.com/Files.ReadWrite.All",
41135
41075
  // offline_access is required on v2.0 to receive a refresh_token.
41136
41076
  "offline_access"
41137
41077
  ];
41138
- var AUTH_URL18 = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
41139
- var TOKEN_URL18 = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
41078
+ var AUTH_URL17 = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
41079
+ var TOKEN_URL17 = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
41140
41080
  var GRAPH3 = "https://graph.microsoft.com/v1.0";
41141
41081
  var MAX_INLINE_BYTES = 4 * 1024 * 1024;
41142
41082
  function sharepoint(opts) {
@@ -41148,8 +41088,8 @@ function sharepoint(opts) {
41148
41088
  description: "Let your agent discover SharePoint sites, list/search their document libraries, read small file contents, upload files, and create folders. Etag-CAS available on every DriveItem for follow-up patch/delete flows.",
41149
41089
  auth: {
41150
41090
  kind: "oauth2",
41151
- authorizationUrl: AUTH_URL18,
41152
- tokenUrl: TOKEN_URL18,
41091
+ authorizationUrl: AUTH_URL17,
41092
+ tokenUrl: TOKEN_URL17,
41153
41093
  scopes: SCOPES13,
41154
41094
  clientIdEnv: "MS_OAUTH_CLIENT_ID",
41155
41095
  clientSecretEnv: "MS_OAUTH_CLIENT_SECRET"
@@ -41352,6 +41292,136 @@ function sharepoint(opts) {
41352
41292
  },
41353
41293
  required: ["siteId", "listId", "fields"]
41354
41294
  }
41295
+ },
41296
+ {
41297
+ name: "get_site_info",
41298
+ class: "read",
41299
+ description: "Read the metadata for a SharePoint site by site id (id, name, displayName, webUrl, description).",
41300
+ parameters: {
41301
+ type: "object",
41302
+ properties: {
41303
+ siteId: { type: "string", description: 'Graph site id (composite "host,site-id,web-id").' }
41304
+ },
41305
+ required: ["siteId"]
41306
+ }
41307
+ },
41308
+ {
41309
+ name: "lists.items.find",
41310
+ class: "read",
41311
+ description: "List items in a SharePoint list, optionally filtered with $filter and shaped with $expand (e.g. fields($select=...)).",
41312
+ parameters: {
41313
+ type: "object",
41314
+ properties: {
41315
+ siteId: { type: "string", description: "Graph site id." },
41316
+ listId: { type: "string", description: "SharePoint list id (or list display name resolved by the caller)." },
41317
+ filter: { type: "string", description: "Optional OData $filter expression." },
41318
+ expand: { type: "string", description: "Optional OData $expand, e.g. fields($select=Title,Status)." },
41319
+ top: { type: "integer", minimum: 1, maximum: 200, default: 50 }
41320
+ },
41321
+ required: ["siteId", "listId"]
41322
+ }
41323
+ },
41324
+ {
41325
+ name: "copy_item",
41326
+ class: "mutation",
41327
+ description: "Copy a file or folder DriveItem. Graph copy is asynchronous \u2014 it returns 202 Accepted with a Location monitor URL rather than the new DriveItem. Supply either a cross-drive parentReference (driveId + id) or a same-site target parent id via targetParentId; optionally rename via name.",
41328
+ cas: "native-idempotency",
41329
+ externalEffect: true,
41330
+ parameters: {
41331
+ type: "object",
41332
+ properties: {
41333
+ siteId: { type: "string", description: "Graph site id." },
41334
+ itemId: { type: "string", description: "DriveItem id of the file or folder to copy." },
41335
+ parentReference: {
41336
+ type: "object",
41337
+ description: "Cross-drive destination reference (driveId + id). Provide this OR targetParentId.",
41338
+ additionalProperties: true
41339
+ },
41340
+ targetParentId: {
41341
+ type: "string",
41342
+ description: "Same-site destination parent folder DriveItem id. Provide this OR parentReference."
41343
+ },
41344
+ name: { type: "string", description: "Optional new name for the copied item." }
41345
+ },
41346
+ required: ["siteId", "itemId"]
41347
+ }
41348
+ },
41349
+ {
41350
+ name: "lists.create",
41351
+ class: "mutation",
41352
+ description: "Create a SharePoint list on the site. displayName is required; columns and list (e.g. { template }) are optional.",
41353
+ cas: "native-idempotency",
41354
+ externalEffect: true,
41355
+ parameters: {
41356
+ type: "object",
41357
+ properties: {
41358
+ siteId: { type: "string", description: "Graph site id." },
41359
+ displayName: { type: "string", description: "Display name of the new list." },
41360
+ columns: {
41361
+ type: "array",
41362
+ description: "Optional column definitions for the list.",
41363
+ items: { type: "object", additionalProperties: true }
41364
+ },
41365
+ list: {
41366
+ type: "object",
41367
+ description: 'Optional list facet, e.g. { template: "genericList" }.',
41368
+ additionalProperties: true
41369
+ }
41370
+ },
41371
+ required: ["siteId", "displayName"]
41372
+ }
41373
+ },
41374
+ {
41375
+ name: "lists.items.update",
41376
+ class: "mutation",
41377
+ description: "Patch the fields on an existing list item. Supports etag-CAS via If-Match \u2014 pass the item's etag to guard against concurrent writes; a mismatch surfaces as ResourceContention.",
41378
+ cas: "etag-if-match",
41379
+ externalEffect: true,
41380
+ parameters: {
41381
+ type: "object",
41382
+ properties: {
41383
+ siteId: { type: "string", description: "Graph site id." },
41384
+ listId: { type: "string", description: "SharePoint list id." },
41385
+ itemId: { type: "string", description: "List item id to update." },
41386
+ fields: {
41387
+ type: "object",
41388
+ description: "Map of column internal-name \u2192 new value.",
41389
+ additionalProperties: true
41390
+ }
41391
+ },
41392
+ required: ["siteId", "listId", "itemId", "fields"]
41393
+ }
41394
+ },
41395
+ {
41396
+ name: "lists.items.delete",
41397
+ class: "mutation",
41398
+ description: "Delete a list item by id. Graph returns 204 on success. (siteId, listId, itemId) is the natural idempotency tuple \u2014 a re-delete of a missing item surfaces as 404 mapped to a tombstone result.",
41399
+ cas: "native-idempotency",
41400
+ externalEffect: true,
41401
+ parameters: {
41402
+ type: "object",
41403
+ properties: {
41404
+ siteId: { type: "string", description: "Graph site id." },
41405
+ listId: { type: "string", description: "SharePoint list id." },
41406
+ itemId: { type: "string", description: "List item id to delete." }
41407
+ },
41408
+ required: ["siteId", "listId", "itemId"]
41409
+ }
41410
+ },
41411
+ {
41412
+ name: "pages.publish",
41413
+ class: "mutation",
41414
+ description: "Publish a SharePoint site page by page id.",
41415
+ cas: "native-idempotency",
41416
+ externalEffect: true,
41417
+ parameters: {
41418
+ type: "object",
41419
+ properties: {
41420
+ siteId: { type: "string", description: "Graph site id." },
41421
+ pageId: { type: "string", description: "Site page id to publish." }
41422
+ },
41423
+ required: ["siteId", "pageId"]
41424
+ }
41355
41425
  }
41356
41426
  ]
41357
41427
  },
@@ -41501,6 +41571,41 @@ function sharepoint(opts) {
41501
41571
  fetchedAt: Date.now()
41502
41572
  };
41503
41573
  }
41574
+ if (inv.capabilityName === "get_site_info") {
41575
+ const { siteId } = inv.args;
41576
+ const url = `${GRAPH3}/sites/${encodeURIComponent(siteId)}?$select=id,name,displayName,webUrl,description`;
41577
+ const site = await graphGet4(url, accessToken, inv.source.id);
41578
+ return {
41579
+ data: {
41580
+ id: site.id,
41581
+ name: site.displayName ?? site.name,
41582
+ webUrl: site.webUrl,
41583
+ description: site.description
41584
+ },
41585
+ fetchedAt: Date.now()
41586
+ };
41587
+ }
41588
+ if (inv.capabilityName === "lists.items.find") {
41589
+ const { siteId, listId, filter, expand, top } = inv.args;
41590
+ const t = clamp(top ?? 50, 1, 200);
41591
+ const params = new URLSearchParams();
41592
+ params.set("$top", String(t));
41593
+ if (typeof filter === "string" && filter.length > 0) params.set("$filter", filter);
41594
+ if (typeof expand === "string" && expand.length > 0) params.set("$expand", expand);
41595
+ const url = `${GRAPH3}/sites/${encodeURIComponent(siteId)}/lists/${encodeURIComponent(listId)}/items?${params.toString()}`;
41596
+ const json = await graphGet4(url, accessToken, inv.source.id);
41597
+ const items = (json.value ?? []).map((it) => ({
41598
+ id: it.id,
41599
+ webUrl: it.webUrl,
41600
+ etag: it.eTag,
41601
+ lastModifiedAt: it.lastModifiedDateTime,
41602
+ fields: it.fields
41603
+ }));
41604
+ return {
41605
+ data: { items, nextLink: json["@odata.nextLink"] },
41606
+ fetchedAt: Date.now()
41607
+ };
41608
+ }
41504
41609
  throw new Error(`sharepoint: unknown read capability ${inv.capabilityName}`);
41505
41610
  },
41506
41611
  async executeMutation(inv) {
@@ -41810,6 +41915,211 @@ function sharepoint(opts) {
41810
41915
  idempotentReplay: false
41811
41916
  };
41812
41917
  }
41918
+ if (inv.capabilityName === "copy_item") {
41919
+ const { siteId, itemId, parentReference, targetParentId, name } = inv.args;
41920
+ const ref = parentReference && Object.keys(parentReference).length > 0 ? parentReference : typeof targetParentId === "string" && targetParentId.length > 0 ? { id: targetParentId } : void 0;
41921
+ if (!ref) {
41922
+ throw new Error(
41923
+ "sharepoint copy_item: provide either parentReference (cross-drive) or targetParentId (same-site)"
41924
+ );
41925
+ }
41926
+ const url = `${GRAPH3}/sites/${encodeURIComponent(siteId)}/drive/items/${encodeURIComponent(itemId)}/copy`;
41927
+ const body = { parentReference: ref };
41928
+ if (typeof name === "string" && name.length > 0) body.name = name;
41929
+ const res = await fetch(url, {
41930
+ method: "POST",
41931
+ headers: {
41932
+ authorization: `Bearer ${accessToken}`,
41933
+ "content-type": "application/json",
41934
+ accept: "application/json"
41935
+ },
41936
+ body: JSON.stringify(body),
41937
+ signal: AbortSignal.timeout(15e3)
41938
+ });
41939
+ if (res.status === 401 || res.status === 403) {
41940
+ throw new CredentialsExpired(
41941
+ `Microsoft Graph rejected token (${res.status})`,
41942
+ inv.source.id
41943
+ );
41944
+ }
41945
+ if (res.status === 409 || res.status === 412) {
41946
+ throw new ResourceContention(
41947
+ `Microsoft Graph reported conflict on copy_item (${res.status})`,
41948
+ []
41949
+ );
41950
+ }
41951
+ if (!res.ok && res.status !== 202) {
41952
+ const text = await res.text().catch(() => "");
41953
+ throw new Error(`sharepoint copy_item ${res.status}: ${text.slice(0, 200)}`);
41954
+ }
41955
+ const monitorUrl = res.headers.get("location") ?? void 0;
41956
+ return {
41957
+ status: "committed",
41958
+ data: { id: itemId, accepted: true, async: true, monitorUrl },
41959
+ committedAt: Date.now(),
41960
+ idempotentReplay: false
41961
+ };
41962
+ }
41963
+ if (inv.capabilityName === "lists.create") {
41964
+ const { siteId, displayName, columns, list } = inv.args;
41965
+ const url = `${GRAPH3}/sites/${encodeURIComponent(siteId)}/lists`;
41966
+ const body = { displayName };
41967
+ if (Array.isArray(columns)) body.columns = columns;
41968
+ if (list && typeof list === "object") body.list = list;
41969
+ const res = await fetch(url, {
41970
+ method: "POST",
41971
+ headers: {
41972
+ authorization: `Bearer ${accessToken}`,
41973
+ "content-type": "application/json",
41974
+ accept: "application/json"
41975
+ },
41976
+ body: JSON.stringify(body),
41977
+ signal: AbortSignal.timeout(15e3)
41978
+ });
41979
+ if (res.status === 401 || res.status === 403) {
41980
+ throw new CredentialsExpired(
41981
+ `Microsoft Graph rejected token (${res.status})`,
41982
+ inv.source.id
41983
+ );
41984
+ }
41985
+ if (res.status === 409 || res.status === 412) {
41986
+ throw new ResourceContention(
41987
+ `Microsoft Graph reported conflict on lists.create (${res.status})`,
41988
+ []
41989
+ );
41990
+ }
41991
+ if (!res.ok) {
41992
+ const text = await res.text().catch(() => "");
41993
+ throw new Error(`sharepoint lists.create ${res.status}: ${text.slice(0, 200)}`);
41994
+ }
41995
+ const created = await res.json();
41996
+ return {
41997
+ status: "committed",
41998
+ data: {
41999
+ id: created.id,
42000
+ displayName: created.displayName ?? created.name,
42001
+ webUrl: created.webUrl
42002
+ },
42003
+ etagAfter: created["@odata.etag"] ?? created.eTag,
42004
+ committedAt: Date.now(),
42005
+ idempotentReplay: false
42006
+ };
42007
+ }
42008
+ if (inv.capabilityName === "lists.items.update") {
42009
+ const { siteId, listId, itemId, fields } = inv.args;
42010
+ const url = `${GRAPH3}/sites/${encodeURIComponent(siteId)}/lists/${encodeURIComponent(listId)}/items/${encodeURIComponent(itemId)}/fields`;
42011
+ const headers = {
42012
+ authorization: `Bearer ${accessToken}`,
42013
+ "content-type": "application/json",
42014
+ accept: "application/json"
42015
+ };
42016
+ if (typeof inv.expectedEtag === "string" && inv.expectedEtag.length > 0) {
42017
+ headers["if-match"] = inv.expectedEtag;
42018
+ }
42019
+ const res = await fetch(url, {
42020
+ method: "PATCH",
42021
+ headers,
42022
+ body: JSON.stringify(fields),
42023
+ signal: AbortSignal.timeout(15e3)
42024
+ });
42025
+ if (res.status === 401 || res.status === 403) {
42026
+ throw new CredentialsExpired(
42027
+ `Microsoft Graph rejected token (${res.status})`,
42028
+ inv.source.id
42029
+ );
42030
+ }
42031
+ if (res.status === 409 || res.status === 412) {
42032
+ throw new ResourceContention(
42033
+ `Microsoft Graph reported conflict on lists.items.update (${res.status})`,
42034
+ []
42035
+ );
42036
+ }
42037
+ if (!res.ok) {
42038
+ const text = await res.text().catch(() => "");
42039
+ throw new Error(`sharepoint lists.items.update ${res.status}: ${text.slice(0, 200)}`);
42040
+ }
42041
+ const updated = await res.json();
42042
+ return {
42043
+ status: "committed",
42044
+ data: { id: itemId, fields: updated },
42045
+ etagAfter: updated["@odata.etag"] ?? updated.eTag,
42046
+ committedAt: Date.now(),
42047
+ idempotentReplay: false
42048
+ };
42049
+ }
42050
+ if (inv.capabilityName === "lists.items.delete") {
42051
+ const { siteId, listId, itemId } = inv.args;
42052
+ const url = `${GRAPH3}/sites/${encodeURIComponent(siteId)}/lists/${encodeURIComponent(listId)}/items/${encodeURIComponent(itemId)}`;
42053
+ const res = await fetch(url, {
42054
+ method: "DELETE",
42055
+ headers: { authorization: `Bearer ${accessToken}` },
42056
+ signal: AbortSignal.timeout(15e3)
42057
+ });
42058
+ if (res.status === 401 || res.status === 403) {
42059
+ throw new CredentialsExpired(
42060
+ `Microsoft Graph rejected token (${res.status})`,
42061
+ inv.source.id
42062
+ );
42063
+ }
42064
+ if (res.status === 412 || res.status === 409) {
42065
+ throw new ResourceContention(
42066
+ `Microsoft Graph reported conflict on lists.items.delete (${res.status})`,
42067
+ []
42068
+ );
42069
+ }
42070
+ if (res.status === 404) {
42071
+ return {
42072
+ status: "committed",
42073
+ data: { id: itemId, deleted: true, alreadyMissing: true },
42074
+ committedAt: Date.now(),
42075
+ idempotentReplay: true
42076
+ };
42077
+ }
42078
+ if (!res.ok) {
42079
+ const text = await res.text().catch(() => "");
42080
+ throw new Error(`sharepoint lists.items.delete ${res.status}: ${text.slice(0, 200)}`);
42081
+ }
42082
+ return {
42083
+ status: "committed",
42084
+ data: { id: itemId, deleted: true },
42085
+ committedAt: Date.now(),
42086
+ idempotentReplay: false
42087
+ };
42088
+ }
42089
+ if (inv.capabilityName === "pages.publish") {
42090
+ const { siteId, pageId } = inv.args;
42091
+ const url = `${GRAPH3}/sites/${encodeURIComponent(siteId)}/pages/${encodeURIComponent(pageId)}/microsoft.graph.sitePage/publish`;
42092
+ const res = await fetch(url, {
42093
+ method: "POST",
42094
+ headers: {
42095
+ authorization: `Bearer ${accessToken}`,
42096
+ accept: "application/json"
42097
+ },
42098
+ signal: AbortSignal.timeout(15e3)
42099
+ });
42100
+ if (res.status === 401 || res.status === 403) {
42101
+ throw new CredentialsExpired(
42102
+ `Microsoft Graph rejected token (${res.status})`,
42103
+ inv.source.id
42104
+ );
42105
+ }
42106
+ if (res.status === 409 || res.status === 412) {
42107
+ throw new ResourceContention(
42108
+ `Microsoft Graph reported conflict on pages.publish (${res.status})`,
42109
+ []
42110
+ );
42111
+ }
42112
+ if (!res.ok) {
42113
+ const text = await res.text().catch(() => "");
42114
+ throw new Error(`sharepoint pages.publish ${res.status}: ${text.slice(0, 200)}`);
42115
+ }
42116
+ return {
42117
+ status: "committed",
42118
+ data: { id: pageId, published: true },
42119
+ committedAt: Date.now(),
42120
+ idempotentReplay: false
42121
+ };
42122
+ }
41813
42123
  throw new Error(`sharepoint: unknown mutation capability ${inv.capabilityName}`);
41814
42124
  },
41815
42125
  async exchangeOAuth(input) {
@@ -41817,7 +42127,7 @@ function sharepoint(opts) {
41817
42127
  throw new Error("Microsoft OAuth client not configured (MS_OAUTH_CLIENT_ID / _SECRET)");
41818
42128
  }
41819
42129
  const tokens = await exchangeAuthorizationCode({
41820
- tokenUrl: TOKEN_URL18,
42130
+ tokenUrl: TOKEN_URL17,
41821
42131
  clientId,
41822
42132
  clientSecret,
41823
42133
  code: input.code,
@@ -41840,7 +42150,7 @@ function sharepoint(opts) {
41840
42150
  throw new Error("sharepoint.refreshToken: missing refresh token");
41841
42151
  }
41842
42152
  const refreshed = await refreshAccessToken({
41843
- tokenUrl: TOKEN_URL18,
42153
+ tokenUrl: TOKEN_URL17,
41844
42154
  clientId,
41845
42155
  clientSecret,
41846
42156
  refreshToken: creds.refreshToken
@@ -41889,7 +42199,7 @@ async function ensureFreshAccessToken15(creds, clientId, clientSecret) {
41889
42199
  throw new CredentialsExpired("SharePoint access token expired and no refresh token", "");
41890
42200
  }
41891
42201
  const refreshed = await refreshAccessToken({
41892
- tokenUrl: TOKEN_URL18,
42202
+ tokenUrl: TOKEN_URL17,
41893
42203
  clientId,
41894
42204
  clientSecret,
41895
42205
  refreshToken: creds.refreshToken
@@ -71097,6 +71407,609 @@ var googleSearchConsoleConnector = declarativeRestConnector({
71097
71407
  ]
71098
71408
  });
71099
71409
 
71410
+ // src/connectors/adapters/google-analytics.ts
71411
+ var googleAnalyticsConnector = declarativeRestConnector({
71412
+ kind: "google-analytics",
71413
+ displayName: "Google Analytics",
71414
+ description: "Run reports, pivot reports, realtime reports, and batch reports against connected GA4 properties. Read-only: GA4 ingest happens through gtag / Measurement Protocol, not the management API.",
71415
+ auth: {
71416
+ kind: "oauth2",
71417
+ authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
71418
+ tokenUrl: "https://oauth2.googleapis.com/token",
71419
+ scopes: ["https://www.googleapis.com/auth/analytics.readonly"],
71420
+ clientIdEnv: "GOOGLE_OAUTH_CLIENT_ID",
71421
+ clientSecretEnv: "GOOGLE_OAUTH_CLIENT_SECRET",
71422
+ extraAuthParams: { access_type: "offline", prompt: "consent", include_granted_scopes: "true" }
71423
+ },
71424
+ category: "database",
71425
+ defaultConsistencyModel: "cache",
71426
+ baseUrl: "https://analyticsdata.googleapis.com",
71427
+ // accountSummaries.list lives on the Admin API host and is the cheapest
71428
+ // probe that confirms the token can reach GA4 at all. Absolute URL routes
71429
+ // around the single-baseUrl constraint of the declarative-rest runtime.
71430
+ test: {
71431
+ method: "GET",
71432
+ path: "https://analyticsadmin.googleapis.com/v1beta/accountSummaries",
71433
+ query: { pageSize: 1 }
71434
+ },
71435
+ capabilities: [
71436
+ {
71437
+ name: "accountSummaries.list",
71438
+ class: "read",
71439
+ description: "List GA4 account summaries reachable by the connected identity. Each summary nests its properties so the agent can discover propertyId values without a second round-trip (GET analyticsadmin.googleapis.com/v1beta/accountSummaries).",
71440
+ parameters: {
71441
+ type: "object",
71442
+ properties: {
71443
+ pageSize: { type: "integer", minimum: 1, maximum: 200, description: "Max account summaries per page; server caps at 200." },
71444
+ pageToken: { type: "string", description: "Continuation token returned by a prior call." }
71445
+ }
71446
+ },
71447
+ request: {
71448
+ method: "GET",
71449
+ path: "https://analyticsadmin.googleapis.com/v1beta/accountSummaries",
71450
+ query: { pageSize: "{pageSize}", pageToken: "{pageToken}" }
71451
+ },
71452
+ requiredScopes: ["https://www.googleapis.com/auth/analytics.readonly"]
71453
+ },
71454
+ {
71455
+ name: "properties.get",
71456
+ class: "read",
71457
+ description: "Fetch GA4 property settings (display name, timezone, currency, industry) by numeric property id (GET analyticsadmin.googleapis.com/v1beta/properties/{propertyId}).",
71458
+ parameters: {
71459
+ type: "object",
71460
+ properties: {
71461
+ propertyId: { type: "string", description: 'Numeric GA4 property id, e.g. "123456789".' }
71462
+ },
71463
+ required: ["propertyId"]
71464
+ },
71465
+ request: {
71466
+ method: "GET",
71467
+ path: "https://analyticsadmin.googleapis.com/v1beta/properties/{propertyId}"
71468
+ },
71469
+ requiredScopes: ["https://www.googleapis.com/auth/analytics.readonly"]
71470
+ },
71471
+ {
71472
+ name: "properties.metadata.get",
71473
+ class: "read",
71474
+ description: "List every dimension and metric available on a GA4 property, including custom dimensions/metrics defined by the customer. Use this before runReport to discover valid dimension/metric names (GET /v1beta/properties/{propertyId}/metadata).",
71475
+ parameters: {
71476
+ type: "object",
71477
+ properties: {
71478
+ propertyId: { type: "string", description: "Numeric GA4 property id." }
71479
+ },
71480
+ required: ["propertyId"]
71481
+ },
71482
+ request: {
71483
+ method: "GET",
71484
+ path: "/v1beta/properties/{propertyId}/metadata"
71485
+ },
71486
+ requiredScopes: ["https://www.googleapis.com/auth/analytics.readonly"]
71487
+ },
71488
+ {
71489
+ name: "properties.runReport",
71490
+ class: "read",
71491
+ description: 'Run a core report against a GA4 property. Pass dimensions, metrics, dateRanges (e.g. {startDate:"7daysAgo",endDate:"today"}), optional filters, ordering, and a row limit. Returns the rows, totals, and metadata GA4 emits in the standard runReport response (POST /v1beta/properties/{propertyId}:runReport).',
71492
+ parameters: {
71493
+ type: "object",
71494
+ properties: {
71495
+ propertyId: { type: "string", description: "Numeric GA4 property id." },
71496
+ dimensions: {
71497
+ type: "array",
71498
+ description: 'Dimension specs, e.g. [{ "name": "country" }, { "name": "deviceCategory" }].',
71499
+ items: {
71500
+ type: "object",
71501
+ properties: {
71502
+ name: { type: "string" },
71503
+ dimensionExpression: { type: "object", description: "Composite/lower-case/concatenate expression (optional)." }
71504
+ },
71505
+ required: ["name"]
71506
+ }
71507
+ },
71508
+ metrics: {
71509
+ type: "array",
71510
+ description: 'Metric specs, e.g. [{ "name": "activeUsers" }, { "name": "sessions" }].',
71511
+ items: {
71512
+ type: "object",
71513
+ properties: {
71514
+ name: { type: "string" },
71515
+ expression: { type: "string", description: "Derived metric expression (optional)." },
71516
+ invisible: { type: "boolean" }
71517
+ },
71518
+ required: ["name"]
71519
+ }
71520
+ },
71521
+ dateRanges: {
71522
+ type: "array",
71523
+ description: 'One or two date ranges; GA4 accepts ISO dates ("2026-05-01"), "today", "yesterday", or "NdaysAgo".',
71524
+ items: {
71525
+ type: "object",
71526
+ properties: {
71527
+ startDate: { type: "string" },
71528
+ endDate: { type: "string" },
71529
+ name: { type: "string", description: "Optional label included in the response row keys when comparing two ranges." }
71530
+ },
71531
+ required: ["startDate", "endDate"]
71532
+ }
71533
+ },
71534
+ dimensionFilter: { type: "object", description: "GA4 FilterExpression (and/or/not) applied to dimensions." },
71535
+ metricFilter: { type: "object", description: "GA4 FilterExpression applied to metrics after aggregation." },
71536
+ orderBys: { type: "array", items: { type: "object" } },
71537
+ limit: { type: "integer", minimum: 1, maximum: 25e4, description: "Max rows per page; GA4 caps at 250000." },
71538
+ offset: { type: "integer", minimum: 0 },
71539
+ keepEmptyRows: { type: "boolean" },
71540
+ returnPropertyQuota: { type: "boolean", description: "Include per-property quota consumption in the response \u2014 useful for back-pressure decisions." },
71541
+ currencyCode: { type: "string", description: "ISO-4217 currency, overrides the property default for monetary metrics." },
71542
+ cohortSpec: { type: "object", description: "CohortSpec for cohort analysis (optional)." }
71543
+ },
71544
+ required: ["propertyId", "metrics", "dateRanges"]
71545
+ },
71546
+ request: {
71547
+ method: "POST",
71548
+ path: "/v1beta/properties/{propertyId}:runReport",
71549
+ body: {
71550
+ dimensions: "{dimensions}",
71551
+ metrics: "{metrics}",
71552
+ dateRanges: "{dateRanges}",
71553
+ dimensionFilter: "{dimensionFilter}",
71554
+ metricFilter: "{metricFilter}",
71555
+ orderBys: "{orderBys}",
71556
+ limit: "{limit}",
71557
+ offset: "{offset}",
71558
+ keepEmptyRows: "{keepEmptyRows}",
71559
+ returnPropertyQuota: "{returnPropertyQuota}",
71560
+ currencyCode: "{currencyCode}",
71561
+ cohortSpec: "{cohortSpec}"
71562
+ }
71563
+ },
71564
+ requiredScopes: ["https://www.googleapis.com/auth/analytics.readonly"]
71565
+ },
71566
+ {
71567
+ name: "properties.batchRunReports",
71568
+ class: "read",
71569
+ description: "Run up to 5 reports against the same GA4 property in a single request \u2014 cheaper than 5 round-trips and counted as fewer quota tokens (POST /v1beta/properties/{propertyId}:batchRunReports).",
71570
+ parameters: {
71571
+ type: "object",
71572
+ properties: {
71573
+ propertyId: { type: "string", description: "Numeric GA4 property id." },
71574
+ requests: {
71575
+ type: "array",
71576
+ description: "Up to 5 report requests; each takes the same shape as runReport (dimensions/metrics/dateRanges/etc.).",
71577
+ items: { type: "object" },
71578
+ maxItems: 5
71579
+ }
71580
+ },
71581
+ required: ["propertyId", "requests"]
71582
+ },
71583
+ request: {
71584
+ method: "POST",
71585
+ path: "/v1beta/properties/{propertyId}:batchRunReports",
71586
+ body: { requests: "{requests}" }
71587
+ },
71588
+ requiredScopes: ["https://www.googleapis.com/auth/analytics.readonly"]
71589
+ },
71590
+ {
71591
+ name: "properties.runPivotReport",
71592
+ class: "read",
71593
+ description: "Run a pivot report \u2014 like runReport but with one or more pivot specifications that rotate dimensions into columns (POST /v1beta/properties/{propertyId}:runPivotReport).",
71594
+ parameters: {
71595
+ type: "object",
71596
+ properties: {
71597
+ propertyId: { type: "string", description: "Numeric GA4 property id." },
71598
+ dimensions: { type: "array", items: { type: "object" } },
71599
+ metrics: { type: "array", items: { type: "object" } },
71600
+ dateRanges: { type: "array", items: { type: "object" } },
71601
+ pivots: {
71602
+ type: "array",
71603
+ description: "Pivot specifications \u2014 each names the dimensions to pivot, an order, a limit, and optional offset.",
71604
+ items: {
71605
+ type: "object",
71606
+ properties: {
71607
+ fieldNames: { type: "array", items: { type: "string" } },
71608
+ orderBys: { type: "array", items: { type: "object" } },
71609
+ offset: { type: "string", description: "String-encoded long." },
71610
+ limit: { type: "string", description: "String-encoded long." },
71611
+ metricAggregations: { type: "array", items: { type: "string" } }
71612
+ },
71613
+ required: ["fieldNames"]
71614
+ }
71615
+ },
71616
+ dimensionFilter: { type: "object" },
71617
+ metricFilter: { type: "object" },
71618
+ currencyCode: { type: "string" },
71619
+ cohortSpec: { type: "object" },
71620
+ keepEmptyRows: { type: "boolean" },
71621
+ returnPropertyQuota: { type: "boolean" }
71622
+ },
71623
+ required: ["propertyId", "metrics", "dateRanges", "pivots"]
71624
+ },
71625
+ request: {
71626
+ method: "POST",
71627
+ path: "/v1beta/properties/{propertyId}:runPivotReport",
71628
+ body: {
71629
+ dimensions: "{dimensions}",
71630
+ metrics: "{metrics}",
71631
+ dateRanges: "{dateRanges}",
71632
+ pivots: "{pivots}",
71633
+ dimensionFilter: "{dimensionFilter}",
71634
+ metricFilter: "{metricFilter}",
71635
+ currencyCode: "{currencyCode}",
71636
+ cohortSpec: "{cohortSpec}",
71637
+ keepEmptyRows: "{keepEmptyRows}",
71638
+ returnPropertyQuota: "{returnPropertyQuota}"
71639
+ }
71640
+ },
71641
+ requiredScopes: ["https://www.googleapis.com/auth/analytics.readonly"]
71642
+ },
71643
+ {
71644
+ name: "properties.runRealtimeReport",
71645
+ class: "read",
71646
+ description: "Run a realtime report \u2014 surfaces events that happened in the last 30 minutes. No dateRanges; the realtime window is implicit (POST /v1beta/properties/{propertyId}:runRealtimeReport).",
71647
+ parameters: {
71648
+ type: "object",
71649
+ properties: {
71650
+ propertyId: { type: "string", description: "Numeric GA4 property id." },
71651
+ dimensions: { type: "array", items: { type: "object" } },
71652
+ metrics: { type: "array", items: { type: "object" } },
71653
+ dimensionFilter: { type: "object" },
71654
+ metricFilter: { type: "object" },
71655
+ limit: { type: "integer", minimum: 1, maximum: 25e4 },
71656
+ metricAggregations: { type: "array", items: { type: "string" } },
71657
+ orderBys: { type: "array", items: { type: "object" } },
71658
+ returnPropertyQuota: { type: "boolean" },
71659
+ minuteRanges: {
71660
+ type: "array",
71661
+ description: 'Optional minute-window specifications, e.g. [{ "name": "last5", "startMinutesAgo": 5, "endMinutesAgo": 0 }]. Defaults to the last 30 minutes.',
71662
+ items: {
71663
+ type: "object",
71664
+ properties: {
71665
+ name: { type: "string" },
71666
+ startMinutesAgo: { type: "integer", minimum: 0, maximum: 29 },
71667
+ endMinutesAgo: { type: "integer", minimum: 0, maximum: 29 }
71668
+ }
71669
+ }
71670
+ }
71671
+ },
71672
+ required: ["propertyId", "metrics"]
71673
+ },
71674
+ request: {
71675
+ method: "POST",
71676
+ path: "/v1beta/properties/{propertyId}:runRealtimeReport",
71677
+ body: {
71678
+ dimensions: "{dimensions}",
71679
+ metrics: "{metrics}",
71680
+ dimensionFilter: "{dimensionFilter}",
71681
+ metricFilter: "{metricFilter}",
71682
+ limit: "{limit}",
71683
+ metricAggregations: "{metricAggregations}",
71684
+ orderBys: "{orderBys}",
71685
+ returnPropertyQuota: "{returnPropertyQuota}",
71686
+ minuteRanges: "{minuteRanges}"
71687
+ }
71688
+ },
71689
+ requiredScopes: ["https://www.googleapis.com/auth/analytics.readonly"]
71690
+ },
71691
+ {
71692
+ name: "properties.checkCompatibility",
71693
+ class: "read",
71694
+ description: "Check whether a given dimension/metric combination is compatible before issuing a full runReport \u2014 GA4 rejects incompatible combos (e.g. cohort dimensions with non-cohort metrics) with a hard error (POST /v1beta/properties/{propertyId}:checkCompatibility).",
71695
+ parameters: {
71696
+ type: "object",
71697
+ properties: {
71698
+ propertyId: { type: "string", description: "Numeric GA4 property id." },
71699
+ dimensions: { type: "array", items: { type: "object" } },
71700
+ metrics: { type: "array", items: { type: "object" } },
71701
+ dimensionFilter: { type: "object" },
71702
+ metricFilter: { type: "object" },
71703
+ compatibilityFilter: {
71704
+ type: "string",
71705
+ enum: ["COMPATIBILITY_UNSPECIFIED", "COMPATIBLE", "INCOMPATIBLE"],
71706
+ description: "Restrict the response to compatible or incompatible entries only."
71707
+ }
71708
+ },
71709
+ required: ["propertyId"]
71710
+ },
71711
+ request: {
71712
+ method: "POST",
71713
+ path: "/v1beta/properties/{propertyId}:checkCompatibility",
71714
+ body: {
71715
+ dimensions: "{dimensions}",
71716
+ metrics: "{metrics}",
71717
+ dimensionFilter: "{dimensionFilter}",
71718
+ metricFilter: "{metricFilter}",
71719
+ compatibilityFilter: "{compatibilityFilter}"
71720
+ }
71721
+ },
71722
+ requiredScopes: ["https://www.googleapis.com/auth/analytics.readonly"]
71723
+ }
71724
+ ]
71725
+ });
71726
+
71727
+ // src/connectors/adapters/google-meet.ts
71728
+ var googleMeetConnector = declarativeRestConnector({
71729
+ kind: "google-meet",
71730
+ displayName: "Google Meet",
71731
+ description: "Create Google Meet spaces, fetch post-meeting conference records, and read participants, recordings, and transcripts via the Google Meet REST API v2.",
71732
+ auth: {
71733
+ kind: "oauth2",
71734
+ authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
71735
+ tokenUrl: "https://oauth2.googleapis.com/token",
71736
+ scopes: [
71737
+ "https://www.googleapis.com/auth/meetings.space.created",
71738
+ "https://www.googleapis.com/auth/meetings.space.readonly",
71739
+ "https://www.googleapis.com/auth/meetings.space.settings",
71740
+ "https://www.googleapis.com/auth/drive.readonly"
71741
+ ],
71742
+ clientIdEnv: "GOOGLE_OAUTH_CLIENT_ID",
71743
+ clientSecretEnv: "GOOGLE_OAUTH_CLIENT_SECRET",
71744
+ extraAuthParams: {
71745
+ access_type: "offline",
71746
+ prompt: "consent",
71747
+ include_granted_scopes: "true"
71748
+ }
71749
+ },
71750
+ category: "calendar",
71751
+ defaultConsistencyModel: "authoritative",
71752
+ baseUrl: "https://meet.googleapis.com",
71753
+ // /v2/spaces/{name} requires a real space id; the cheapest token-validity
71754
+ // probe Meet exposes is creating a throwaway space, which has a side effect
71755
+ // we don't want in a connection test. Skip the in-band test — the adapter
71756
+ // contract treats a missing `test` as ok and connection issuance still
71757
+ // catches the auth handshake at exchange time.
71758
+ capabilities: [
71759
+ {
71760
+ name: "spaces.create",
71761
+ class: "mutation",
71762
+ description: "Create a Meet space and return its meet.google.com URL. The space lives until the calling user deletes it or it expires per Google retention rules.",
71763
+ parameters: {
71764
+ type: "object",
71765
+ properties: {
71766
+ config: {
71767
+ type: "object",
71768
+ description: "Optional SpaceConfig: accessType (OPEN | TRUSTED | RESTRICTED), entryPointAccess (ALL | CREATOR_APP_ONLY), moderation, attendanceReport, artifactConfig, chatRestriction, presentRestriction, defaultJoinAsViewerType."
71769
+ }
71770
+ }
71771
+ },
71772
+ request: {
71773
+ method: "POST",
71774
+ path: "/v2/spaces",
71775
+ body: {
71776
+ config: "{config}"
71777
+ }
71778
+ },
71779
+ // Meet's spaces.create is a pure side-effect; no upstream idempotency
71780
+ // key on this endpoint, so a retry produces a second space. Mark
71781
+ // accordingly so the MutationGuard layer enforces idempotency.
71782
+ cas: "none",
71783
+ externalEffect: true,
71784
+ requiredScopes: ["https://www.googleapis.com/auth/meetings.space.created"]
71785
+ },
71786
+ {
71787
+ name: "spaces.get",
71788
+ class: "read",
71789
+ description: 'Read a Meet space by resource name (e.g. "spaces/abc-defg-hij") or by short meeting code.',
71790
+ parameters: {
71791
+ type: "object",
71792
+ properties: {
71793
+ name: {
71794
+ type: "string",
71795
+ description: 'Resource name like "spaces/{space_id}" or "spaces/{meeting_code}".'
71796
+ }
71797
+ },
71798
+ required: ["name"]
71799
+ },
71800
+ request: {
71801
+ method: "GET",
71802
+ path: "/v2/{name}"
71803
+ },
71804
+ requiredScopes: ["https://www.googleapis.com/auth/meetings.space.readonly"]
71805
+ },
71806
+ {
71807
+ name: "spaces.update",
71808
+ class: "mutation",
71809
+ description: "Patch a Meet space (accessType, entryPointAccess, moderation toggles, artifactConfig, chat/present restrictions). Caller supplies updateMask to specify mutated fields.",
71810
+ parameters: {
71811
+ type: "object",
71812
+ properties: {
71813
+ name: { type: "string", description: 'Resource name like "spaces/{space_id}".' },
71814
+ updateMask: {
71815
+ type: "string",
71816
+ description: 'Comma-separated FieldMask of mutated fields, e.g. "config.accessType,config.moderation".'
71817
+ },
71818
+ config: { type: "object", description: "New SpaceConfig values." }
71819
+ },
71820
+ required: ["name"]
71821
+ },
71822
+ request: {
71823
+ method: "PATCH",
71824
+ path: "/v2/{name}",
71825
+ query: {
71826
+ updateMask: "{updateMask}"
71827
+ },
71828
+ body: {
71829
+ config: "{config}"
71830
+ }
71831
+ },
71832
+ cas: "native-idempotency",
71833
+ externalEffect: true,
71834
+ requiredScopes: ["https://www.googleapis.com/auth/meetings.space.settings"]
71835
+ },
71836
+ {
71837
+ name: "spaces.endActiveConference",
71838
+ class: "mutation",
71839
+ description: "Terminate the currently active conference inside a Meet space. No-op (HTTP 200) if no conference is active.",
71840
+ parameters: {
71841
+ type: "object",
71842
+ properties: {
71843
+ name: { type: "string", description: 'Resource name like "spaces/{space_id}".' }
71844
+ },
71845
+ required: ["name"]
71846
+ },
71847
+ request: {
71848
+ method: "POST",
71849
+ path: "/v2/{name}:endActiveConference",
71850
+ body: {}
71851
+ },
71852
+ cas: "native-idempotency",
71853
+ externalEffect: true,
71854
+ requiredScopes: ["https://www.googleapis.com/auth/meetings.space.created"]
71855
+ },
71856
+ {
71857
+ name: "conferenceRecords.list",
71858
+ class: "read",
71859
+ description: "List conference records for meetings the calling user attended or hosted. Supports server-side filtering by space.name and end_time.",
71860
+ parameters: {
71861
+ type: "object",
71862
+ properties: {
71863
+ pageSize: { type: "integer", minimum: 1, maximum: 100 },
71864
+ pageToken: { type: "string" },
71865
+ filter: {
71866
+ type: "string",
71867
+ description: `EBNF filter, e.g. 'space.name="spaces/abc"' or 'end_time>="2024-01-01T00:00:00Z"'.`
71868
+ }
71869
+ }
71870
+ },
71871
+ request: {
71872
+ method: "GET",
71873
+ path: "/v2/conferenceRecords",
71874
+ query: {
71875
+ pageSize: "{pageSize}",
71876
+ pageToken: "{pageToken}",
71877
+ filter: "{filter}"
71878
+ }
71879
+ },
71880
+ requiredScopes: ["https://www.googleapis.com/auth/meetings.space.readonly"]
71881
+ },
71882
+ {
71883
+ name: "conferenceRecords.get",
71884
+ class: "read",
71885
+ description: 'Read a conference record by resource name (e.g. "conferenceRecords/abc123").',
71886
+ parameters: {
71887
+ type: "object",
71888
+ properties: {
71889
+ name: { type: "string", description: 'Resource name like "conferenceRecords/{conference_record_id}".' }
71890
+ },
71891
+ required: ["name"]
71892
+ },
71893
+ request: {
71894
+ method: "GET",
71895
+ path: "/v2/{name}"
71896
+ },
71897
+ requiredScopes: ["https://www.googleapis.com/auth/meetings.space.readonly"]
71898
+ },
71899
+ {
71900
+ name: "conferenceRecords.participants.list",
71901
+ class: "read",
71902
+ description: "List participants for a finished conference, including anonymous and phone-dial-in attendees.",
71903
+ parameters: {
71904
+ type: "object",
71905
+ properties: {
71906
+ parent: { type: "string", description: "Parent conferenceRecords/{conference_record_id}." },
71907
+ pageSize: { type: "integer", minimum: 1, maximum: 250 },
71908
+ pageToken: { type: "string" },
71909
+ filter: { type: "string", description: `EBNF filter, e.g. 'earliest_start_time<="2024-01-01T00:00:00Z"'.` }
71910
+ },
71911
+ required: ["parent"]
71912
+ },
71913
+ request: {
71914
+ method: "GET",
71915
+ path: "/v2/{parent}/participants",
71916
+ query: {
71917
+ pageSize: "{pageSize}",
71918
+ pageToken: "{pageToken}",
71919
+ filter: "{filter}"
71920
+ }
71921
+ },
71922
+ requiredScopes: ["https://www.googleapis.com/auth/meetings.space.readonly"]
71923
+ },
71924
+ {
71925
+ name: "conferenceRecords.recordings.list",
71926
+ class: "read",
71927
+ description: "List recordings for a conference record. Each entry includes the Drive file id and DriveFileExportUri for downstream Drive fetches.",
71928
+ parameters: {
71929
+ type: "object",
71930
+ properties: {
71931
+ parent: { type: "string", description: "Parent conferenceRecords/{conference_record_id}." },
71932
+ pageSize: { type: "integer", minimum: 1, maximum: 100 },
71933
+ pageToken: { type: "string" }
71934
+ },
71935
+ required: ["parent"]
71936
+ },
71937
+ request: {
71938
+ method: "GET",
71939
+ path: "/v2/{parent}/recordings",
71940
+ query: {
71941
+ pageSize: "{pageSize}",
71942
+ pageToken: "{pageToken}"
71943
+ }
71944
+ },
71945
+ requiredScopes: ["https://www.googleapis.com/auth/meetings.space.readonly"]
71946
+ },
71947
+ {
71948
+ name: "conferenceRecords.recordings.get",
71949
+ class: "read",
71950
+ description: "Read a single recording by resource name.",
71951
+ parameters: {
71952
+ type: "object",
71953
+ properties: {
71954
+ name: {
71955
+ type: "string",
71956
+ description: 'Resource name like "conferenceRecords/{conference_record_id}/recordings/{recording_id}".'
71957
+ }
71958
+ },
71959
+ required: ["name"]
71960
+ },
71961
+ request: {
71962
+ method: "GET",
71963
+ path: "/v2/{name}"
71964
+ },
71965
+ requiredScopes: ["https://www.googleapis.com/auth/meetings.space.readonly"]
71966
+ },
71967
+ {
71968
+ name: "conferenceRecords.transcripts.list",
71969
+ class: "read",
71970
+ description: "List transcripts (auto-generated captions exports) for a conference record.",
71971
+ parameters: {
71972
+ type: "object",
71973
+ properties: {
71974
+ parent: { type: "string", description: "Parent conferenceRecords/{conference_record_id}." },
71975
+ pageSize: { type: "integer", minimum: 1, maximum: 100 },
71976
+ pageToken: { type: "string" }
71977
+ },
71978
+ required: ["parent"]
71979
+ },
71980
+ request: {
71981
+ method: "GET",
71982
+ path: "/v2/{parent}/transcripts",
71983
+ query: {
71984
+ pageSize: "{pageSize}",
71985
+ pageToken: "{pageToken}"
71986
+ }
71987
+ },
71988
+ requiredScopes: ["https://www.googleapis.com/auth/meetings.space.readonly"]
71989
+ },
71990
+ {
71991
+ name: "conferenceRecords.transcripts.get",
71992
+ class: "read",
71993
+ description: "Read a transcript by resource name; payload links to the Drive Doc holding the transcript text.",
71994
+ parameters: {
71995
+ type: "object",
71996
+ properties: {
71997
+ name: {
71998
+ type: "string",
71999
+ description: 'Resource name like "conferenceRecords/{conference_record_id}/transcripts/{transcript_id}".'
72000
+ }
72001
+ },
72002
+ required: ["name"]
72003
+ },
72004
+ request: {
72005
+ method: "GET",
72006
+ path: "/v2/{name}"
72007
+ },
72008
+ requiredScopes: ["https://www.googleapis.com/auth/meetings.space.readonly"]
72009
+ }
72010
+ ]
72011
+ });
72012
+
71100
72013
  // src/connectors/adapters/youtube-data.ts
71101
72014
  var youtubeDataConnector = declarativeRestConnector({
71102
72015
  kind: "youtube",
@@ -86860,123 +87773,6 @@ var microsoftPowerBiConnector = declarativeRestConnector({
86860
87773
  ]
86861
87774
  });
86862
87775
 
86863
- // src/connectors/adapters/microsoft-outlook-calendar.ts
86864
- var microsoftOutlookCalendarConnector = declarativeRestConnector({
86865
- kind: "microsoft-outlook-calendar",
86866
- displayName: "Microsoft Outlook Calendar",
86867
- description: "Create, list, and delete Outlook/Microsoft 365 calendar events via Microsoft Graph.",
86868
- auth: {
86869
- kind: "oauth2",
86870
- authorizationUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
86871
- tokenUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
86872
- scopes: ["offline_access", "Calendars.ReadWrite", "User.Read"],
86873
- clientIdEnv: "MS_OAUTH_CLIENT_ID",
86874
- clientSecretEnv: "MS_OAUTH_CLIENT_SECRET"
86875
- },
86876
- category: "calendar",
86877
- defaultConsistencyModel: "authoritative",
86878
- baseUrl: "https://graph.microsoft.com/v1.0",
86879
- test: { method: "GET", path: "/me" },
86880
- capabilities: [
86881
- {
86882
- name: "create.event",
86883
- class: "mutation",
86884
- description: "Create a calendar event on the signed-in user's primary calendar, or on a specific calendarId when supplied.",
86885
- parameters: {
86886
- type: "object",
86887
- properties: {
86888
- calendarId: { type: "string" },
86889
- subject: { type: "string" },
86890
- body: { type: "object" },
86891
- start: { type: "object" },
86892
- end: { type: "object" },
86893
- location: { type: "object" },
86894
- attendees: { type: "array", items: { type: "object" } },
86895
- isOnlineMeeting: { type: "boolean" },
86896
- onlineMeetingProvider: { type: "string" },
86897
- showAs: { type: "string" },
86898
- sensitivity: { type: "string" },
86899
- importance: { type: "string" },
86900
- categories: { type: "array", items: { type: "string" } },
86901
- reminderMinutesBeforeStart: { type: "integer" },
86902
- isAllDay: { type: "boolean" },
86903
- recurrence: { type: "object" },
86904
- transactionId: { type: "string" }
86905
- },
86906
- required: ["subject", "start", "end"]
86907
- },
86908
- request: {
86909
- method: "POST",
86910
- path: "/me/calendars/{calendarId}/events",
86911
- body: {
86912
- subject: "{subject}",
86913
- body: "{body}",
86914
- start: "{start}",
86915
- end: "{end}",
86916
- location: "{location}",
86917
- attendees: "{attendees}",
86918
- isOnlineMeeting: "{isOnlineMeeting}",
86919
- onlineMeetingProvider: "{onlineMeetingProvider}",
86920
- showAs: "{showAs}",
86921
- sensitivity: "{sensitivity}",
86922
- importance: "{importance}",
86923
- categories: "{categories}",
86924
- reminderMinutesBeforeStart: "{reminderMinutesBeforeStart}",
86925
- isAllDay: "{isAllDay}",
86926
- recurrence: "{recurrence}",
86927
- transactionId: "{transactionId}"
86928
- }
86929
- },
86930
- cas: "native-idempotency",
86931
- requiredScopes: ["Calendars.ReadWrite"]
86932
- },
86933
- {
86934
- name: "delete.event",
86935
- class: "mutation",
86936
- description: "Delete a calendar event by id from the signed-in user mailbox.",
86937
- parameters: {
86938
- type: "object",
86939
- properties: { eventId: { type: "string" } },
86940
- required: ["eventId"]
86941
- },
86942
- request: { method: "DELETE", path: "/me/events/{eventId}" },
86943
- cas: "native-idempotency",
86944
- externalEffect: true,
86945
- requiredScopes: ["Calendars.ReadWrite"]
86946
- },
86947
- {
86948
- name: "list.events",
86949
- class: "read",
86950
- description: "List events on a calendar with OData paging/filtering ($top, $skip, $filter, $select, $orderby, $search). Targets the user's primary calendar unless calendarId is supplied.",
86951
- parameters: {
86952
- type: "object",
86953
- properties: {
86954
- calendarId: { type: "string" },
86955
- $top: { type: "integer" },
86956
- $skip: { type: "integer" },
86957
- $filter: { type: "string" },
86958
- $select: { type: "string" },
86959
- $orderby: { type: "string" },
86960
- $search: { type: "string" }
86961
- }
86962
- },
86963
- request: {
86964
- method: "GET",
86965
- path: "/me/calendars/{calendarId}/events",
86966
- query: {
86967
- $top: "{$top}",
86968
- $skip: "{$skip}",
86969
- $filter: "{$filter}",
86970
- $select: "{$select}",
86971
- $orderby: "{$orderby}",
86972
- $search: "{$search}"
86973
- }
86974
- },
86975
- requiredScopes: ["Calendars.ReadWrite"]
86976
- }
86977
- ]
86978
- });
86979
-
86980
87776
  // src/connectors/adapters/microsoft-onenote.ts
86981
87777
  var microsoftOnenoteConnector = declarativeRestConnector({
86982
87778
  kind: "microsoft-onenote",
@@ -87196,299 +87992,6 @@ var microsoftOnenoteConnector = declarativeRestConnector({
87196
87992
  ]
87197
87993
  });
87198
87994
 
87199
- // src/connectors/adapters/microsoft-outlook.ts
87200
- var microsoftOutlookConnector = declarativeRestConnector({
87201
- kind: "microsoft-outlook",
87202
- displayName: "Microsoft Outlook",
87203
- description: "Send, draft, reply to, forward, search, label, and organize email in the signed-in user's Outlook mailbox via Microsoft Graph.",
87204
- auth: {
87205
- kind: "oauth2",
87206
- authorizationUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
87207
- tokenUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
87208
- scopes: [
87209
- "offline_access",
87210
- "User.Read",
87211
- "Mail.ReadWrite",
87212
- "Mail.Send",
87213
- "MailboxSettings.Read"
87214
- ],
87215
- clientIdEnv: "MS_OAUTH_CLIENT_ID",
87216
- clientSecretEnv: "MS_OAUTH_CLIENT_SECRET"
87217
- },
87218
- category: "comms",
87219
- defaultConsistencyModel: "authoritative",
87220
- baseUrl: "https://graph.microsoft.com/v1.0",
87221
- test: { method: "GET", path: "/me" },
87222
- capabilities: [
87223
- {
87224
- name: "email.send",
87225
- class: "mutation",
87226
- description: "Send an email immediately from the signed-in user's mailbox. Optionally saves the sent message to the Sent Items folder.",
87227
- parameters: {
87228
- type: "object",
87229
- properties: {
87230
- subject: { type: "string" },
87231
- body: { type: "object" },
87232
- toRecipients: { type: "array", items: { type: "object" } },
87233
- ccRecipients: { type: "array", items: { type: "object" } },
87234
- bccRecipients: { type: "array", items: { type: "object" } },
87235
- attachments: { type: "array", items: { type: "object" } },
87236
- saveToSentItems: { type: "boolean" }
87237
- },
87238
- required: ["subject", "body", "toRecipients"]
87239
- },
87240
- request: {
87241
- method: "POST",
87242
- path: "/me/sendMail",
87243
- body: {
87244
- message: {
87245
- subject: "{subject}",
87246
- body: "{body}",
87247
- toRecipients: "{toRecipients}",
87248
- ccRecipients: "{ccRecipients}",
87249
- bccRecipients: "{bccRecipients}",
87250
- attachments: "{attachments}"
87251
- },
87252
- saveToSentItems: "{saveToSentItems}"
87253
- }
87254
- },
87255
- cas: "none",
87256
- externalEffect: true,
87257
- requiredScopes: ["Mail.Send"]
87258
- },
87259
- {
87260
- name: "email.draft.create",
87261
- class: "mutation",
87262
- description: "Create a draft email in the signed-in user mailbox without sending it.",
87263
- parameters: {
87264
- type: "object",
87265
- properties: {
87266
- subject: { type: "string" },
87267
- body: { type: "object" },
87268
- toRecipients: { type: "array", items: { type: "object" } },
87269
- ccRecipients: { type: "array", items: { type: "object" } },
87270
- bccRecipients: { type: "array", items: { type: "object" } },
87271
- importance: { type: "string" },
87272
- categories: { type: "array", items: { type: "string" } }
87273
- },
87274
- required: ["subject", "body"]
87275
- },
87276
- request: {
87277
- method: "POST",
87278
- path: "/me/messages",
87279
- body: {
87280
- subject: "{subject}",
87281
- body: "{body}",
87282
- toRecipients: "{toRecipients}",
87283
- ccRecipients: "{ccRecipients}",
87284
- bccRecipients: "{bccRecipients}",
87285
- importance: "{importance}",
87286
- categories: "{categories}"
87287
- }
87288
- },
87289
- cas: "native-idempotency",
87290
- requiredScopes: ["Mail.ReadWrite"]
87291
- },
87292
- {
87293
- name: "email.draft.send",
87294
- class: "mutation",
87295
- description: "Send a previously created draft message by id.",
87296
- parameters: {
87297
- type: "object",
87298
- properties: { messageId: { type: "string" } },
87299
- required: ["messageId"]
87300
- },
87301
- request: { method: "POST", path: "/me/messages/{messageId}/send" },
87302
- cas: "none",
87303
- externalEffect: true,
87304
- requiredScopes: ["Mail.Send"]
87305
- },
87306
- {
87307
- name: "email.reply",
87308
- class: "mutation",
87309
- description: "Reply to an existing message. When comment is provided alone, Graph generates the reply body; when message is provided, it overrides recipients/body.",
87310
- parameters: {
87311
- type: "object",
87312
- properties: {
87313
- messageId: { type: "string" },
87314
- comment: { type: "string" },
87315
- message: { type: "object" }
87316
- },
87317
- required: ["messageId"]
87318
- },
87319
- request: {
87320
- method: "POST",
87321
- path: "/me/messages/{messageId}/reply",
87322
- body: { comment: "{comment}", message: "{message}" }
87323
- },
87324
- cas: "none",
87325
- externalEffect: true,
87326
- requiredScopes: ["Mail.Send"]
87327
- },
87328
- {
87329
- name: "email.forward",
87330
- class: "mutation",
87331
- description: "Forward an existing message to one or more recipients with an optional comment.",
87332
- parameters: {
87333
- type: "object",
87334
- properties: {
87335
- messageId: { type: "string" },
87336
- toRecipients: { type: "array", items: { type: "object" } },
87337
- comment: { type: "string" }
87338
- },
87339
- required: ["messageId", "toRecipients"]
87340
- },
87341
- request: {
87342
- method: "POST",
87343
- path: "/me/messages/{messageId}/forward",
87344
- body: { toRecipients: "{toRecipients}", comment: "{comment}" }
87345
- },
87346
- cas: "none",
87347
- externalEffect: true,
87348
- requiredScopes: ["Mail.Send"]
87349
- },
87350
- {
87351
- name: "email.move",
87352
- class: "mutation",
87353
- description: "Move a message to a destination mail folder by id (or well-known name like inbox/archive).",
87354
- parameters: {
87355
- type: "object",
87356
- properties: {
87357
- messageId: { type: "string" },
87358
- destinationId: { type: "string" }
87359
- },
87360
- required: ["messageId", "destinationId"]
87361
- },
87362
- request: {
87363
- method: "POST",
87364
- path: "/me/messages/{messageId}/move",
87365
- body: { destinationId: "{destinationId}" }
87366
- },
87367
- cas: "native-idempotency",
87368
- requiredScopes: ["Mail.ReadWrite"]
87369
- },
87370
- {
87371
- name: "email.label.add",
87372
- class: "mutation",
87373
- description: "Tag a message with one or more Outlook categories (labels). Pass the desired full set; Graph replaces the categories array.",
87374
- parameters: {
87375
- type: "object",
87376
- properties: {
87377
- messageId: { type: "string" },
87378
- categories: { type: "array", items: { type: "string" } }
87379
- },
87380
- required: ["messageId", "categories"]
87381
- },
87382
- request: {
87383
- method: "PATCH",
87384
- path: "/me/messages/{messageId}",
87385
- body: { categories: "{categories}" }
87386
- },
87387
- cas: "optimistic-read-verify",
87388
- requiredScopes: ["Mail.ReadWrite"]
87389
- },
87390
- {
87391
- name: "email.label.remove",
87392
- class: "mutation",
87393
- description: "Remove labels from a message by writing the surviving categories array. Caller computes the remaining set and supplies it explicitly.",
87394
- parameters: {
87395
- type: "object",
87396
- properties: {
87397
- messageId: { type: "string" },
87398
- categories: { type: "array", items: { type: "string" } }
87399
- },
87400
- required: ["messageId", "categories"]
87401
- },
87402
- request: {
87403
- method: "PATCH",
87404
- path: "/me/messages/{messageId}",
87405
- body: { categories: "{categories}" }
87406
- },
87407
- cas: "optimistic-read-verify",
87408
- externalEffect: true,
87409
- requiredScopes: ["Mail.ReadWrite"]
87410
- },
87411
- {
87412
- name: "email.find",
87413
- class: "read",
87414
- description: "Search messages in a folder using OData $search/$filter with $top, $select, $orderby. Folder defaults to the well-known inbox if omitted.",
87415
- parameters: {
87416
- type: "object",
87417
- properties: {
87418
- mailFolderId: { type: "string" },
87419
- $search: { type: "string" },
87420
- $filter: { type: "string" },
87421
- $select: { type: "string" },
87422
- $top: { type: "integer" },
87423
- $orderby: { type: "string" }
87424
- }
87425
- },
87426
- request: {
87427
- method: "GET",
87428
- path: "/me/mailFolders/{mailFolderId}/messages",
87429
- query: {
87430
- $search: "{$search}",
87431
- $filter: "{$filter}",
87432
- $select: "{$select}",
87433
- $top: "{$top}",
87434
- $orderby: "{$orderby}"
87435
- }
87436
- },
87437
- requiredScopes: ["Mail.ReadWrite"]
87438
- },
87439
- {
87440
- name: "email.attachment.download",
87441
- class: "read",
87442
- description: "Read an attachment record (metadata plus base64 contentBytes for file attachments) for a message by attachment id.",
87443
- parameters: {
87444
- type: "object",
87445
- properties: {
87446
- messageId: { type: "string" },
87447
- attachmentId: { type: "string" }
87448
- },
87449
- required: ["messageId", "attachmentId"]
87450
- },
87451
- request: {
87452
- method: "GET",
87453
- path: "/me/messages/{messageId}/attachments/{attachmentId}"
87454
- },
87455
- requiredScopes: ["Mail.ReadWrite"]
87456
- },
87457
- {
87458
- name: "email.approval.request",
87459
- class: "mutation",
87460
- description: "Send an approval-request email by composing a structured message body and sending it through /me/sendMail. The body should encode the approval prompt and reply-handling instructions.",
87461
- parameters: {
87462
- type: "object",
87463
- properties: {
87464
- subject: { type: "string" },
87465
- body: { type: "object" },
87466
- toRecipients: { type: "array", items: { type: "object" } },
87467
- ccRecipients: { type: "array", items: { type: "object" } },
87468
- saveToSentItems: { type: "boolean" }
87469
- },
87470
- required: ["subject", "body", "toRecipients"]
87471
- },
87472
- request: {
87473
- method: "POST",
87474
- path: "/me/sendMail",
87475
- body: {
87476
- message: {
87477
- subject: "{subject}",
87478
- body: "{body}",
87479
- toRecipients: "{toRecipients}",
87480
- ccRecipients: "{ccRecipients}"
87481
- },
87482
- saveToSentItems: "{saveToSentItems}"
87483
- }
87484
- },
87485
- cas: "none",
87486
- externalEffect: true,
87487
- requiredScopes: ["Mail.Send"]
87488
- }
87489
- ]
87490
- });
87491
-
87492
87995
  // src/connectors/adapters/microsoft-excel-365.ts
87493
87996
  var microsoftExcel365Connector = declarativeRestConnector({
87494
87997
  kind: "microsoft-excel-365",
@@ -88362,348 +88865,6 @@ var microsoftTodoConnector = declarativeRestConnector({
88362
88865
  ]
88363
88866
  });
88364
88867
 
88365
- // src/connectors/adapters/microsoft-sharepoint.ts
88366
- var microsoftSharepointConnector = declarativeRestConnector({
88367
- kind: "microsoft-sharepoint",
88368
- displayName: "Microsoft SharePoint",
88369
- description: "Read SharePoint site metadata, list items, and files; create folders, lists, list items, and pages via Microsoft Graph.",
88370
- auth: {
88371
- kind: "oauth2",
88372
- authorizationUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
88373
- tokenUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
88374
- scopes: [
88375
- "offline_access",
88376
- "Sites.ReadWrite.All",
88377
- "Files.ReadWrite.All"
88378
- ],
88379
- clientIdEnv: "MICROSOFT_SHAREPOINT_OAUTH_CLIENT_ID",
88380
- clientSecretEnv: "MICROSOFT_SHAREPOINT_OAUTH_CLIENT_SECRET"
88381
- },
88382
- category: "storage",
88383
- defaultConsistencyModel: "authoritative",
88384
- baseUrl: "https://graph.microsoft.com/v1.0",
88385
- test: { method: "GET", path: "/sites/root" },
88386
- capabilities: [
88387
- // ---------- Sites ----------
88388
- {
88389
- name: "find.site",
88390
- class: "read",
88391
- description: "Search SharePoint sites by display name or keyword (Graph $search).",
88392
- parameters: {
88393
- type: "object",
88394
- properties: {
88395
- search: { type: "string" },
88396
- $top: { type: "integer" }
88397
- },
88398
- required: ["search"]
88399
- },
88400
- request: {
88401
- method: "GET",
88402
- path: "/sites",
88403
- query: { search: "{search}", $top: "{$top}" }
88404
- },
88405
- requiredScopes: ["Sites.ReadWrite.All"]
88406
- },
88407
- {
88408
- name: "get.site.information",
88409
- class: "read",
88410
- description: "Read the metadata for a SharePoint site by site id.",
88411
- parameters: {
88412
- type: "object",
88413
- properties: { siteId: { type: "string" } },
88414
- required: ["siteId"]
88415
- },
88416
- request: { method: "GET", path: "/sites/{siteId}" },
88417
- requiredScopes: ["Sites.ReadWrite.All"]
88418
- },
88419
- // ---------- Folders / files ----------
88420
- {
88421
- name: "create.folder",
88422
- class: "mutation",
88423
- description: "Create a folder inside a site drive. Parent is identified by its drive item id (use the drive root id for top-level folders).",
88424
- parameters: {
88425
- type: "object",
88426
- properties: {
88427
- siteId: { type: "string" },
88428
- parentItemId: { type: "string" },
88429
- name: { type: "string" },
88430
- conflictBehavior: { type: "string" }
88431
- },
88432
- required: ["siteId", "parentItemId", "name"]
88433
- },
88434
- request: {
88435
- method: "POST",
88436
- path: "/sites/{siteId}/drive/items/{parentItemId}/children",
88437
- body: {
88438
- name: "{name}",
88439
- folder: {},
88440
- "@microsoft.graph.conflictBehavior": "{conflictBehavior}"
88441
- }
88442
- },
88443
- cas: "native-idempotency",
88444
- requiredScopes: ["Files.ReadWrite.All", "Sites.ReadWrite.All"]
88445
- },
88446
- {
88447
- name: "get.folder.contents",
88448
- class: "read",
88449
- description: "List the children of a folder in a site drive.",
88450
- parameters: {
88451
- type: "object",
88452
- properties: {
88453
- siteId: { type: "string" },
88454
- itemId: { type: "string" },
88455
- $top: { type: "integer" },
88456
- $select: { type: "string" }
88457
- },
88458
- required: ["siteId", "itemId"]
88459
- },
88460
- request: {
88461
- method: "GET",
88462
- path: "/sites/{siteId}/drive/items/{itemId}/children",
88463
- query: { $top: "{$top}", $select: "{$select}" }
88464
- },
88465
- requiredScopes: ["Files.ReadWrite.All", "Sites.ReadWrite.All"]
88466
- },
88467
- {
88468
- name: "find.file",
88469
- class: "read",
88470
- description: "Search drive items inside a site drive by name or content (Graph drive search).",
88471
- parameters: {
88472
- type: "object",
88473
- properties: {
88474
- siteId: { type: "string" },
88475
- query: { type: "string" },
88476
- $top: { type: "integer" }
88477
- },
88478
- required: ["siteId", "query"]
88479
- },
88480
- request: {
88481
- method: "GET",
88482
- path: "/sites/{siteId}/drive/root/search(q='{query}')",
88483
- query: { $top: "{$top}" }
88484
- },
88485
- requiredScopes: ["Files.ReadWrite.All", "Sites.ReadWrite.All"]
88486
- },
88487
- {
88488
- name: "upload.file",
88489
- class: "mutation",
88490
- description: "Upload (or replace) a small file at the given drive path. The body must be the JSON-encoded contents the agent provides as `content` (base64-encoded for binary payloads). For files larger than 4 MiB the caller should use the upload-session flow instead.",
88491
- parameters: {
88492
- type: "object",
88493
- properties: {
88494
- siteId: { type: "string" },
88495
- parentItemId: { type: "string" },
88496
- fileName: { type: "string" },
88497
- content: { type: "string" },
88498
- conflictBehavior: { type: "string" }
88499
- },
88500
- required: ["siteId", "parentItemId", "fileName", "content"]
88501
- },
88502
- request: {
88503
- method: "PUT",
88504
- path: "/sites/{siteId}/drive/items/{parentItemId}:/{fileName}:/content",
88505
- body: "{content}"
88506
- },
88507
- cas: "optimistic-read-verify",
88508
- requiredScopes: ["Files.ReadWrite.All", "Sites.ReadWrite.All"]
88509
- },
88510
- {
88511
- name: "copy.item",
88512
- class: "mutation",
88513
- description: "Copy a drive item into another drive. The destination is identified by a parentReference (driveId + id) and an optional new name.",
88514
- parameters: {
88515
- type: "object",
88516
- properties: {
88517
- siteId: { type: "string" },
88518
- itemId: { type: "string" },
88519
- parentReference: { type: "object" },
88520
- name: { type: "string" }
88521
- },
88522
- required: ["siteId", "itemId", "parentReference"]
88523
- },
88524
- request: {
88525
- method: "POST",
88526
- path: "/sites/{siteId}/drive/items/{itemId}/copy",
88527
- body: { parentReference: "{parentReference}", name: "{name}" }
88528
- },
88529
- cas: "native-idempotency",
88530
- requiredScopes: ["Files.ReadWrite.All", "Sites.ReadWrite.All"]
88531
- },
88532
- {
88533
- name: "copy.item.within.site",
88534
- class: "mutation",
88535
- description: "Copy a drive item to another folder inside the same site drive. The destination parent is identified by the target folder id.",
88536
- parameters: {
88537
- type: "object",
88538
- properties: {
88539
- siteId: { type: "string" },
88540
- itemId: { type: "string" },
88541
- targetParentId: { type: "string" },
88542
- name: { type: "string" }
88543
- },
88544
- required: ["siteId", "itemId", "targetParentId"]
88545
- },
88546
- request: {
88547
- method: "POST",
88548
- path: "/sites/{siteId}/drive/items/{itemId}/copy",
88549
- body: { parentReference: { id: "{targetParentId}" }, name: "{name}" }
88550
- },
88551
- cas: "native-idempotency",
88552
- requiredScopes: ["Files.ReadWrite.All", "Sites.ReadWrite.All"]
88553
- },
88554
- {
88555
- name: "move.file",
88556
- class: "mutation",
88557
- description: "Move (re-parent or rename) a drive item by patching its parentReference and/or name.",
88558
- parameters: {
88559
- type: "object",
88560
- properties: {
88561
- siteId: { type: "string" },
88562
- itemId: { type: "string" },
88563
- parentReference: { type: "object" },
88564
- name: { type: "string" }
88565
- },
88566
- required: ["siteId", "itemId", "parentReference"]
88567
- },
88568
- request: {
88569
- method: "PATCH",
88570
- path: "/sites/{siteId}/drive/items/{itemId}",
88571
- body: { parentReference: "{parentReference}", name: "{name}" }
88572
- },
88573
- cas: "etag-if-match",
88574
- requiredScopes: ["Files.ReadWrite.All", "Sites.ReadWrite.All"]
88575
- },
88576
- // ---------- Lists & list items ----------
88577
- {
88578
- name: "create.list",
88579
- class: "mutation",
88580
- description: "Create a SharePoint list on the site. `displayName` is required; `columns` and `list.template` are optional.",
88581
- parameters: {
88582
- type: "object",
88583
- properties: {
88584
- siteId: { type: "string" },
88585
- displayName: { type: "string" },
88586
- columns: { type: "array", items: { type: "object" } },
88587
- list: { type: "object" }
88588
- },
88589
- required: ["siteId", "displayName"]
88590
- },
88591
- request: {
88592
- method: "POST",
88593
- path: "/sites/{siteId}/lists",
88594
- body: { displayName: "{displayName}", columns: "{columns}", list: "{list}" }
88595
- },
88596
- cas: "native-idempotency",
88597
- requiredScopes: ["Sites.ReadWrite.All"]
88598
- },
88599
- {
88600
- name: "create.list.item",
88601
- class: "mutation",
88602
- description: "Create a new list item. `fields` is the column -> value map.",
88603
- parameters: {
88604
- type: "object",
88605
- properties: {
88606
- siteId: { type: "string" },
88607
- listId: { type: "string" },
88608
- fields: { type: "object" }
88609
- },
88610
- required: ["siteId", "listId", "fields"]
88611
- },
88612
- request: {
88613
- method: "POST",
88614
- path: "/sites/{siteId}/lists/{listId}/items",
88615
- body: { fields: "{fields}" }
88616
- },
88617
- cas: "native-idempotency",
88618
- requiredScopes: ["Sites.ReadWrite.All"]
88619
- },
88620
- {
88621
- name: "update.list.item",
88622
- class: "mutation",
88623
- description: "Patch the fields on an existing list item.",
88624
- parameters: {
88625
- type: "object",
88626
- properties: {
88627
- siteId: { type: "string" },
88628
- listId: { type: "string" },
88629
- itemId: { type: "string" },
88630
- fields: { type: "object" }
88631
- },
88632
- required: ["siteId", "listId", "itemId", "fields"]
88633
- },
88634
- request: {
88635
- method: "PATCH",
88636
- path: "/sites/{siteId}/lists/{listId}/items/{itemId}/fields",
88637
- body: "{fields}"
88638
- },
88639
- cas: "etag-if-match",
88640
- requiredScopes: ["Sites.ReadWrite.All"]
88641
- },
88642
- {
88643
- name: "delete.list.item",
88644
- class: "mutation",
88645
- description: "Delete a list item by id.",
88646
- parameters: {
88647
- type: "object",
88648
- properties: {
88649
- siteId: { type: "string" },
88650
- listId: { type: "string" },
88651
- itemId: { type: "string" }
88652
- },
88653
- required: ["siteId", "listId", "itemId"]
88654
- },
88655
- request: {
88656
- method: "DELETE",
88657
- path: "/sites/{siteId}/lists/{listId}/items/{itemId}"
88658
- },
88659
- cas: "native-idempotency",
88660
- requiredScopes: ["Sites.ReadWrite.All"]
88661
- },
88662
- {
88663
- name: "find.list.item",
88664
- class: "read",
88665
- description: "List items in a SharePoint list, optionally filtered with $filter / $expand=fields($select=...).",
88666
- parameters: {
88667
- type: "object",
88668
- properties: {
88669
- siteId: { type: "string" },
88670
- listId: { type: "string" },
88671
- $filter: { type: "string" },
88672
- $expand: { type: "string" },
88673
- $top: { type: "integer" }
88674
- },
88675
- required: ["siteId", "listId"]
88676
- },
88677
- request: {
88678
- method: "GET",
88679
- path: "/sites/{siteId}/lists/{listId}/items",
88680
- query: { $filter: "{$filter}", $expand: "{$expand}", $top: "{$top}" }
88681
- },
88682
- requiredScopes: ["Sites.ReadWrite.All"]
88683
- },
88684
- // ---------- Pages ----------
88685
- {
88686
- name: "publish.page",
88687
- class: "mutation",
88688
- description: "Publish a SharePoint site page by page id.",
88689
- parameters: {
88690
- type: "object",
88691
- properties: {
88692
- siteId: { type: "string" },
88693
- pageId: { type: "string" }
88694
- },
88695
- required: ["siteId", "pageId"]
88696
- },
88697
- request: {
88698
- method: "POST",
88699
- path: "/sites/{siteId}/pages/{pageId}/microsoft.graph.sitePage/publish"
88700
- },
88701
- cas: "native-idempotency",
88702
- requiredScopes: ["Sites.ReadWrite.All"]
88703
- }
88704
- ]
88705
- });
88706
-
88707
88868
  // src/connectors/adapters/millionverifier.ts
88708
88869
  var millionverifierConnector = declarativeRestConnector({
88709
88870
  kind: "millionverifier",
@@ -92605,82 +92766,6 @@ var mindStudioConnector = declarativeRestConnector({
92605
92766
  ]
92606
92767
  });
92607
92768
 
92608
- // src/connectors/adapters/microsoft-onedrive.ts
92609
- var microsoftOnedriveConnector = declarativeRestConnector({
92610
- kind: "microsoft-onedrive",
92611
- displayName: "Microsoft OneDrive",
92612
- description: "Upload, download, list files and folders in Microsoft OneDrive.",
92613
- auth: {
92614
- kind: "oauth2",
92615
- authorizationUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
92616
- tokenUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
92617
- scopes: ["Files.ReadWrite"],
92618
- clientIdEnv: "MICROSOFT_ONEDRIVE_OAUTH_CLIENT_ID",
92619
- clientSecretEnv: "MICROSOFT_ONEDRIVE_OAUTH_CLIENT_SECRET"
92620
- },
92621
- category: "storage",
92622
- defaultConsistencyModel: "authoritative",
92623
- baseUrl: "https://graph.microsoft.com/v1.0/me/drive",
92624
- test: { method: "GET", path: "/root" },
92625
- capabilities: [
92626
- {
92627
- name: "files.list",
92628
- class: "read",
92629
- description: "List files in OneDrive.",
92630
- parameters: {
92631
- type: "object",
92632
- properties: {
92633
- folderId: { type: "string", description: "Folder ID to list files from (optional, defaults to root)" }
92634
- },
92635
- required: []
92636
- },
92637
- request: { method: "GET", path: "/items/{folderId}/children", query: { $select: "id,name,size,webUrl,folder,file" } }
92638
- },
92639
- {
92640
- name: "folders.list",
92641
- class: "read",
92642
- description: "List folders in OneDrive.",
92643
- parameters: {
92644
- type: "object",
92645
- properties: {
92646
- parentId: { type: "string", description: "Parent folder ID (optional, defaults to root)" }
92647
- },
92648
- required: []
92649
- },
92650
- request: { method: "GET", path: "/items/{parentId}/children", query: { $filter: "folder ne null", $select: "id,name,webUrl" } }
92651
- },
92652
- {
92653
- name: "files.download",
92654
- class: "read",
92655
- description: "Download a file from OneDrive.",
92656
- parameters: {
92657
- type: "object",
92658
- properties: {
92659
- fileId: { type: "string" }
92660
- },
92661
- required: ["fileId"]
92662
- },
92663
- request: { method: "GET", path: "/items/{fileId}/content" }
92664
- },
92665
- {
92666
- name: "files.upload",
92667
- class: "mutation",
92668
- description: "Upload a file to OneDrive.",
92669
- parameters: {
92670
- type: "object",
92671
- properties: {
92672
- folderId: { type: "string", description: "Destination folder ID (optional, defaults to root)" },
92673
- fileName: { type: "string", description: "Name of the file to upload" },
92674
- fileContent: { type: "string", description: "File content (base64-encoded or raw)" }
92675
- },
92676
- required: ["fileName", "fileContent"]
92677
- },
92678
- request: { method: "PUT", path: "/items/{folderId}:/{fileName}:/content", body: "{fileContent}" },
92679
- cas: "native-idempotency"
92680
- }
92681
- ]
92682
- });
92683
-
92684
92769
  // src/connectors/adapters/mongodb.ts
92685
92770
  var mongodbConnector = declarativeRestConnector({
92686
92771
  kind: "mongodb",
@@ -93842,21 +93927,31 @@ var nocodbConnector = declarativeRestConnector({
93842
93927
  });
93843
93928
 
93844
93929
  // src/connectors/adapters/notion.ts
93845
- var notionConnector = declarativeRestConnector({
93930
+ var TOKEN_URL18 = "https://api.notion.com/v1/oauth/token";
93931
+ var NOTION_VERSION = "2022-06-28";
93932
+ var NOTION_SPEC = {
93846
93933
  kind: "notion",
93847
93934
  displayName: "Notion",
93848
93935
  description: "Query and manipulate Notion databases, pages, and blocks.",
93849
93936
  auth: {
93850
93937
  kind: "oauth2",
93851
- authorizationUrl: "https://api.notion.com/oauth/authorize",
93938
+ authorizationUrl: "https://api.notion.com/v1/oauth/authorize",
93852
93939
  tokenUrl: "https://api.notion.com/v1/oauth/token",
93853
- scopes: ["read", "write"],
93940
+ // Notion does not use OAuth scopes the workspace owner picks which
93941
+ // pages/databases the integration sees during install. We declare an
93942
+ // empty scope list so the consent screen renders cleanly.
93943
+ scopes: [],
93854
93944
  clientIdEnv: "NOTION_OAUTH_CLIENT_ID",
93855
- clientSecretEnv: "NOTION_OAUTH_CLIENT_SECRET"
93945
+ clientSecretEnv: "NOTION_OAUTH_CLIENT_SECRET",
93946
+ extraAuthParams: { owner: "user" }
93856
93947
  },
93857
93948
  category: "doc",
93858
93949
  defaultConsistencyModel: "authoritative",
93859
93950
  baseUrl: "https://api.notion.com/v1",
93951
+ // Notion rejects any request without a Notion-Version header (400
93952
+ // invalid_request). The declarative executor merges defaultHeaders into
93953
+ // every read/mutation, so the whole surface carries it.
93954
+ defaultHeaders: { "Notion-Version": NOTION_VERSION },
93860
93955
  test: { method: "GET", path: "/users/me" },
93861
93956
  capabilities: [
93862
93957
  {
@@ -94087,9 +94182,168 @@ var notionConnector = declarativeRestConnector({
94087
94182
  },
94088
94183
  cas: "native-idempotency",
94089
94184
  externalEffect: true
94185
+ },
94186
+ {
94187
+ name: "databases.create",
94188
+ class: "mutation",
94189
+ description: "Create a new Notion database underneath a parent page.",
94190
+ parameters: {
94191
+ type: "object",
94192
+ properties: {
94193
+ parentPageId: { type: "string", description: "Parent page id under which to create the database." },
94194
+ title: {
94195
+ type: "array",
94196
+ description: "Notion rich_text array used as the database title."
94197
+ },
94198
+ properties: {
94199
+ type: "object",
94200
+ description: "Schema map \u2014 property name \u2192 Notion property schema."
94201
+ }
94202
+ },
94203
+ required: ["parentPageId", "title", "properties"]
94204
+ },
94205
+ request: {
94206
+ method: "POST",
94207
+ path: "/databases",
94208
+ body: {
94209
+ parent: { type: "page_id", page_id: "{parentPageId}" },
94210
+ title: "{title}",
94211
+ properties: "{properties}"
94212
+ }
94213
+ },
94214
+ cas: "native-idempotency",
94215
+ externalEffect: true
94216
+ },
94217
+ {
94218
+ name: "databases.update",
94219
+ class: "mutation",
94220
+ description: "Update a database title and/or schema.",
94221
+ parameters: {
94222
+ type: "object",
94223
+ properties: {
94224
+ databaseId: { type: "string" },
94225
+ title: { type: "array", description: "Optional new rich_text title." },
94226
+ properties: { type: "object", description: "Optional partial schema update." }
94227
+ },
94228
+ required: ["databaseId"]
94229
+ },
94230
+ request: {
94231
+ method: "PATCH",
94232
+ path: "/databases/{databaseId}",
94233
+ body: { title: "{title}", properties: "{properties}" }
94234
+ },
94235
+ cas: "native-idempotency",
94236
+ externalEffect: true
94090
94237
  }
94091
94238
  ]
94092
- });
94239
+ };
94240
+ async function databasesUpdate(inv) {
94241
+ const { title, properties } = inv.args;
94242
+ const body = {};
94243
+ if (title !== void 0) body.title = "{title}";
94244
+ if (properties !== void 0) body.properties = "{properties}";
94245
+ const response = await executeRestRequest(
94246
+ NOTION_SPEC,
94247
+ { method: "PATCH", path: "/databases/{databaseId}", body },
94248
+ inv
94249
+ );
94250
+ return {
94251
+ status: "committed",
94252
+ data: response.data,
94253
+ etagAfter: response.etag,
94254
+ committedAt: Date.now(),
94255
+ idempotentReplay: false
94256
+ };
94257
+ }
94258
+ function withNotionOverrides(base) {
94259
+ return {
94260
+ ...base,
94261
+ async executeMutation(inv) {
94262
+ if (inv.capabilityName === "databases.update") return databasesUpdate(inv);
94263
+ return base.executeMutation(inv);
94264
+ }
94265
+ };
94266
+ }
94267
+ var notionConnector = withNotionOverrides(declarativeRestConnector(NOTION_SPEC));
94268
+ function notion(opts) {
94269
+ const { clientId, clientSecret } = opts;
94270
+ return {
94271
+ ...withNotionOverrides(declarativeRestConnector(NOTION_SPEC)),
94272
+ /**
94273
+ * Notion's token endpoint follows RFC 6749 with one twist — it REQUIRES
94274
+ * HTTP Basic auth (client_id:client_secret) and does NOT accept the client
94275
+ * credentials in the form body, so we POST inline rather than via the
94276
+ * generic `exchangeAuthorizationCode` helper. The workspace_id/bot_id come
94277
+ * back in the response and we stash them in `metadata` so the agent can
94278
+ * address resources by workspace where useful.
94279
+ */
94280
+ async exchangeOAuth(input) {
94281
+ if (!clientId || !clientSecret) {
94282
+ throw new Error("Notion OAuth client not configured (NOTION_OAUTH_CLIENT_ID / _SECRET)");
94283
+ }
94284
+ const body = new URLSearchParams({
94285
+ grant_type: "authorization_code",
94286
+ code: input.code,
94287
+ redirect_uri: input.redirectUri,
94288
+ code_verifier: input.codeVerifier
94289
+ });
94290
+ const res = await fetch(TOKEN_URL18, {
94291
+ method: "POST",
94292
+ headers: {
94293
+ authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
94294
+ "content-type": "application/x-www-form-urlencoded",
94295
+ accept: "application/json",
94296
+ "Notion-Version": NOTION_VERSION
94297
+ },
94298
+ body,
94299
+ signal: AbortSignal.timeout(15e3)
94300
+ });
94301
+ if (!res.ok) {
94302
+ const text = await res.text().catch(() => "");
94303
+ throw new Error(`Notion OAuth token exchange failed: ${res.status} \u2014 ${text.slice(0, 200)}`);
94304
+ }
94305
+ const json = await res.json();
94306
+ return {
94307
+ credentials: {
94308
+ kind: "oauth2",
94309
+ accessToken: json.access_token,
94310
+ refreshToken: json.refresh_token
94311
+ },
94312
+ scopes: [],
94313
+ metadata: {
94314
+ botId: json.bot_id,
94315
+ workspaceId: json.workspace_id,
94316
+ workspaceName: json.workspace_name,
94317
+ // Operator picks the database in a follow-up step; default empty.
94318
+ databaseId: ""
94319
+ }
94320
+ };
94321
+ },
94322
+ /** Notion's standard tokens don't expire and don't ship a refresh_token.
94323
+ * If we have neither expiresAt nor refreshToken, treat the existing
94324
+ * access token as durable and return it unchanged. */
94325
+ async refreshToken(creds) {
94326
+ if (creds.kind !== "oauth2" || !creds.refreshToken) {
94327
+ if (creds.kind === "oauth2" && creds.accessToken && !creds.expiresAt) {
94328
+ return creds;
94329
+ }
94330
+ throw new Error("notion.refreshToken: missing refresh token");
94331
+ }
94332
+ const refreshed = await refreshAccessToken({
94333
+ tokenUrl: TOKEN_URL18,
94334
+ clientId,
94335
+ clientSecret,
94336
+ refreshToken: creds.refreshToken
94337
+ });
94338
+ return {
94339
+ kind: "oauth2",
94340
+ accessToken: refreshed.accessToken,
94341
+ refreshToken: refreshed.refreshToken ?? creds.refreshToken,
94342
+ expiresAt: refreshed.expiresIn ? Date.now() + refreshed.expiresIn * 1e3 : void 0
94343
+ };
94344
+ }
94345
+ };
94346
+ }
94093
94347
 
94094
94348
  // src/connectors/adapters/ntfy.ts
94095
94349
  var ntfyConnector = declarativeRestConnector({
@@ -111280,7 +111534,7 @@ var twinLabsConnector = declarativeRestConnector({
111280
111534
  });
111281
111535
 
111282
111536
  // src/connectors/adapters/twitter.ts
111283
- var AUTH_URL19 = "https://twitter.com/i/oauth2/authorize";
111537
+ var AUTH_URL18 = "https://twitter.com/i/oauth2/authorize";
111284
111538
  var TOKEN_URL19 = "https://api.twitter.com/2/oauth2/token";
111285
111539
  var SCOPES14 = ["tweet.read", "tweet.write", "users.read", "like.write", "offline.access"];
111286
111540
  var TWITTER_SPEC = {
@@ -111293,7 +111547,7 @@ var TWITTER_SPEC = {
111293
111547
  options: [
111294
111548
  {
111295
111549
  kind: "oauth2",
111296
- authorizationUrl: AUTH_URL19,
111550
+ authorizationUrl: AUTH_URL18,
111297
111551
  tokenUrl: TOKEN_URL19,
111298
111552
  scopes: SCOPES14,
111299
111553
  clientIdEnv: "TWITTER_OAUTH_CLIENT_ID",
@@ -118452,7 +118706,6 @@ export {
118452
118706
  microsoftCalendar,
118453
118707
  hubspot,
118454
118708
  slack,
118455
- notionDatabase,
118456
118709
  docuseal,
118457
118710
  twilioSmsConnector,
118458
118711
  phonyConnector,
@@ -118689,6 +118942,8 @@ export {
118689
118942
  ghostcmsConnector,
118690
118943
  gistlyConnector,
118691
118944
  googleSearchConsoleConnector,
118945
+ googleAnalyticsConnector,
118946
+ googleMeetConnector,
118692
118947
  youtubeDataConnector,
118693
118948
  googleCloudStorageConnector,
118694
118949
  googleBigqueryConnector,
@@ -118766,12 +119021,9 @@ export {
118766
119021
  microsoftDynamics365BusinessCentralConnector,
118767
119022
  microsoft365PlannerConnector,
118768
119023
  microsoftPowerBiConnector,
118769
- microsoftOutlookCalendarConnector,
118770
119024
  microsoftOnenoteConnector,
118771
- microsoftOutlookConnector,
118772
119025
  microsoftExcel365Connector,
118773
119026
  microsoftTodoConnector,
118774
- microsoftSharepointConnector,
118775
119027
  millionverifierConnector,
118776
119028
  mindeeConnector,
118777
119029
  mixmaxConnector,
@@ -118802,12 +119054,12 @@ export {
118802
119054
  mollieConnector,
118803
119055
  metabaseConnector,
118804
119056
  mindStudioConnector,
118805
- microsoftOnedriveConnector,
118806
119057
  mongodbConnector,
118807
119058
  niftyConnector,
118808
119059
  ninjapipeConnector,
118809
119060
  nocodbConnector,
118810
119061
  notionConnector,
119062
+ notion,
118811
119063
  ntfyConnector,
118812
119064
  odooConnector,
118813
119065
  omniCoConnector,
@@ -118936,4 +119188,4 @@ export {
118936
119188
  pipedreamConnector,
118937
119189
  adapters_exports
118938
119190
  };
118939
- //# sourceMappingURL=chunk-YV3O5SO2.js.map
119191
+ //# sourceMappingURL=chunk-6MUBOVI4.js.map