@slates/provider 1.0.0-rc.33 → 1.0.0-rc.35

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.
@@ -1266,6 +1266,11 @@ var getApiErrorResponse = (error) => {
1266
1266
  };
1267
1267
  };
1268
1268
  var getApiErrorStatus = (error) => getApiErrorResponse(error)?.status;
1269
+ var getUpstreamErrorStatus = (error) => {
1270
+ let value = error instanceof ServiceError ? error.data.upstreamStatus : getApiErrorStatus(error);
1271
+ let status = Number(value);
1272
+ return Number.isInteger(status) && status >= 100 && status <= 599 ? status : void 0;
1273
+ };
1269
1274
  var getApiErrorResponseWithBody = (error) => {
1270
1275
  let response = getApiErrorResponse(error);
1271
1276
  if (response?.data !== void 0) return response;
@@ -1773,6 +1778,13 @@ var SlateDeclarationError = class _SlateDeclarationError extends SlateError {
1773
1778
  }
1774
1779
  };
1775
1780
 
1781
+ // src/error/parse.ts
1782
+ var parseWithServiceError = (schema, value, message, options = {}) => {
1783
+ let result = schema.safeParse(value);
1784
+ if (!result.success) throw createApiServiceError(message, options);
1785
+ return result.data;
1786
+ };
1787
+
1776
1788
  // src/action/scopes.ts
1777
1789
  var scopeClause = (...scopes) => {
1778
1790
  assertScopeValues(scopes);
@@ -1841,6 +1853,45 @@ var isClause = (value) => typeof value === "object" && value !== null && "OR" in
1841
1853
  var isScopes = (value) => typeof value === "object" && value !== null && "AND" in value && Array.isArray(value.AND);
1842
1854
 
1843
1855
  // src/action/builder.ts
1856
+ var EVENT_ATTRIBUTE_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
1857
+ var EVENT_ATTRIBUTE_MAX_KEYS = 8;
1858
+ var checkEventAttributeNames = (fields) => {
1859
+ if (!Array.isArray(fields)) {
1860
+ throw new SlateDeclarationError("Event attributes must be a list of output field names");
1861
+ }
1862
+ if (fields.length > EVENT_ATTRIBUTE_MAX_KEYS) {
1863
+ throw new SlateDeclarationError(
1864
+ `A trigger can declare at most ${EVENT_ATTRIBUTE_MAX_KEYS} event attributes`
1865
+ );
1866
+ }
1867
+ let seen = /* @__PURE__ */ new Set();
1868
+ for (let field of fields) {
1869
+ if (typeof field !== "string" || !EVENT_ATTRIBUTE_KEY_PATTERN.test(field)) {
1870
+ throw new SlateDeclarationError(
1871
+ `Event attribute "${field}" must start with a letter and contain only letters, digits and underscores (at most 64 characters)`
1872
+ );
1873
+ }
1874
+ if (seen.has(field)) {
1875
+ throw new SlateDeclarationError(`Event attribute "${field}" is declared more than once`);
1876
+ }
1877
+ seen.add(field);
1878
+ }
1879
+ };
1880
+ var checkEventAttributeFields = (fields, outputSchema) => {
1881
+ if (outputSchema._zod?.def?.type !== "object") {
1882
+ throw new SlateDeclarationError(
1883
+ "Event attributes require the output schema to be a zod object"
1884
+ );
1885
+ }
1886
+ let shape = outputSchema.shape;
1887
+ for (let field of fields) {
1888
+ if (!Object.hasOwn(shape, field)) {
1889
+ throw new SlateDeclarationError(
1890
+ `Event attribute "${field}" is not a top-level property of the output schema`
1891
+ );
1892
+ }
1893
+ }
1894
+ };
1844
1895
  var SlateActionBuilder = class {
1845
1896
  constructor(type, spec2, params, factory, isPublicTool = false) {
1846
1897
  this.type = type;
@@ -1866,6 +1917,7 @@ var SlateActionBuilder = class {
1866
1917
  #triggerGroup = null;
1867
1918
  #triggerMatches = null;
1868
1919
  #triggerMap = null;
1920
+ #eventAttributes = null;
1869
1921
  #interfaceLocked = false;
1870
1922
  input(schema) {
1871
1923
  if (this.#interfaceLocked) {
@@ -1936,6 +1988,21 @@ var SlateActionBuilder = class {
1936
1988
  this.#triggerMap = handler;
1937
1989
  return this;
1938
1990
  }
1991
+ /**
1992
+ * Returns the values of these top-level output fields with every mapped event, so events
1993
+ * can be filtered by them. Strings, finite numbers, booleans and arrays of those are used.
1994
+ */
1995
+ eventAttributes(fields) {
1996
+ if (this.type !== "trigger") {
1997
+ throw new SlateDeclarationError("eventAttributes can only be set for trigger actions");
1998
+ }
1999
+ checkEventAttributeNames(fields);
2000
+ if (this.#outputSchema) {
2001
+ checkEventAttributeFields(fields, this.#outputSchema);
2002
+ }
2003
+ this.#eventAttributes = [...fields];
2004
+ return this;
2005
+ }
1939
2006
  build() {
1940
2007
  let scopes = this.#scopes ?? this.params.scopes;
1941
2008
  if (scopes) {
@@ -1963,11 +2030,15 @@ var SlateActionBuilder = class {
1963
2030
  if (this.type === "trigger" && !this.#triggerMap) {
1964
2031
  throw new SlateDeclarationError("Trigger map handler is not defined");
1965
2032
  }
2033
+ if (this.#eventAttributes) {
2034
+ checkEventAttributeFields(this.#eventAttributes, this.#outputSchema);
2035
+ }
1966
2036
  let triggerParams = this.type === "trigger" ? {
1967
2037
  type: "trigger",
1968
2038
  triggerGroup: this.#triggerGroup,
1969
2039
  matches: this.#triggerMatches,
1970
- map: this.#triggerMap
2040
+ map: this.#triggerMap,
2041
+ ...this.#eventAttributes?.length ? { eventAttributes: this.#eventAttributes } : {}
1971
2042
  } : null;
1972
2043
  return this.factory({
1973
2044
  ...this.params,
@@ -2039,6 +2110,41 @@ var getFileUrlTool = (spec2, handleGetFileUrl) => tool(spec2, {
2039
2110
  };
2040
2111
  }).build();
2041
2112
 
2113
+ // src/action/optionList.ts
2114
+ import { z as z2 } from "zod";
2115
+ var SlateOptionList = class _SlateOptionList {
2116
+ constructor(_spec, _params, _paramsSchema) {
2117
+ this._spec = _spec;
2118
+ this._params = _params;
2119
+ this._paramsSchema = _paramsSchema;
2120
+ }
2121
+ _spec;
2122
+ _params;
2123
+ _paramsSchema;
2124
+ static create(spec2, params) {
2125
+ let paramsSchema = params.paramsSchema ?? z2.object({});
2126
+ if (paramsSchema?._zod?.def?.type !== "object") {
2127
+ throw new SlateDeclarationError(
2128
+ `Option list "${params.key}" params schema must be a zod object`
2129
+ );
2130
+ }
2131
+ return new _SlateOptionList(spec2, params, paramsSchema.strict());
2132
+ }
2133
+ get spec() {
2134
+ return this._spec;
2135
+ }
2136
+ get key() {
2137
+ return this._params.key;
2138
+ }
2139
+ get paramsSchema() {
2140
+ return this._paramsSchema;
2141
+ }
2142
+ get list() {
2143
+ return this._params.list;
2144
+ }
2145
+ };
2146
+ var optionList = (spec2, params) => SlateOptionList.create(spec2, params);
2147
+
2042
2148
  // src/action/publicTool.ts
2043
2149
  var SlatePublicTool = class {
2044
2150
  constructor() {
@@ -2092,11 +2198,13 @@ var SlateTrigger = class _SlateTrigger extends SlateAction {
2092
2198
  #triggerGroup;
2093
2199
  #matches;
2094
2200
  #map;
2201
+ #eventAttributes;
2095
2202
  constructor(spec2, inputSchema, outputSchema, params) {
2096
2203
  super("trigger", spec2, inputSchema, outputSchema, params);
2097
2204
  this.#triggerGroup = params.triggerGroup;
2098
2205
  this.#matches = params.matches;
2099
2206
  this.#map = params.map;
2207
+ this.#eventAttributes = params.eventAttributes ?? [];
2100
2208
  }
2101
2209
  static create(spec2, params) {
2102
2210
  return new SlateActionBuilder("trigger", spec2, params, (params2) => {
@@ -2113,12 +2221,53 @@ var SlateTrigger = class _SlateTrigger extends SlateAction {
2113
2221
  get map() {
2114
2222
  return this.#map;
2115
2223
  }
2224
+ get eventAttributes() {
2225
+ return [...this.#eventAttributes];
2226
+ }
2116
2227
  };
2117
2228
  var trigger = (spec2, params) => SlateTrigger.create(spec2, params);
2118
2229
 
2119
2230
  // src/action/triggerGroup.ts
2120
- import { z as z2 } from "zod";
2231
+ import { z as z3 } from "zod";
2121
2232
  var SlateDefaultPollingIntervalSeconds = 60 * 10;
2233
+ var LINKED_SLATE_PATTERN = /^[^/\s]+\/[^/\s]+$/;
2234
+ var checkSelectionOptions = (field, sources, shape) => {
2235
+ if (!Object.hasOwn(shape, field)) {
2236
+ throw new SlateDeclarationError(
2237
+ `Selection field "${field}" is not a top-level property of the selection schema`
2238
+ );
2239
+ }
2240
+ if (typeof sources !== "object" || sources === null) {
2241
+ throw new SlateDeclarationError(
2242
+ `Selection field "${field}" must be declared as { list, linked }`
2243
+ );
2244
+ }
2245
+ let { list, linked } = sources;
2246
+ if (!list && !linked) {
2247
+ throw new SlateDeclarationError(
2248
+ `Selection field "${field}" needs its own options list, a linked option list, or both`
2249
+ );
2250
+ }
2251
+ if (list !== void 0 && typeof list !== "function") {
2252
+ throw new SlateDeclarationError(`Selection field "${field}" list must be a function`);
2253
+ }
2254
+ if (linked) {
2255
+ if (typeof linked.slate !== "string" || !LINKED_SLATE_PATTERN.test(linked.slate)) {
2256
+ throw new SlateDeclarationError(
2257
+ `Selection field "${field}" links to slate "${linked.slate}", which must be written as <scope>/<name>`
2258
+ );
2259
+ }
2260
+ if (typeof linked.optionList !== "string" || !linked.optionList.trim()) {
2261
+ throw new SlateDeclarationError(
2262
+ `Selection field "${field}" must name the option list it links to`
2263
+ );
2264
+ }
2265
+ }
2266
+ return {
2267
+ ...list ? { list } : {},
2268
+ ...linked ? { linked } : {}
2269
+ };
2270
+ };
2122
2271
  var SlateTriggerGroup = class _SlateTriggerGroup {
2123
2272
  constructor(_spec, _params) {
2124
2273
  this._spec = _spec;
@@ -2145,11 +2294,14 @@ var SlateTriggerGroup = class _SlateTriggerGroup {
2145
2294
  return this._params.metadata;
2146
2295
  }
2147
2296
  get eventSchema() {
2148
- return this._params.eventSchema ?? z2.object({}).passthrough();
2297
+ return this._params.eventSchema ?? z3.object({}).passthrough();
2149
2298
  }
2150
2299
  get source() {
2151
2300
  return this._params.source;
2152
2301
  }
2302
+ get selectionSchema() {
2303
+ return this._params.selectionSchema;
2304
+ }
2153
2305
  get polling() {
2154
2306
  return this._params.polling;
2155
2307
  }
@@ -2162,6 +2314,9 @@ var SlateTriggerGroup = class _SlateTriggerGroup {
2162
2314
  get routingMatchers() {
2163
2315
  return this._params.routingMatchers;
2164
2316
  }
2317
+ get selectionOptions() {
2318
+ return this._params.selectionOptions ?? {};
2319
+ }
2165
2320
  };
2166
2321
  var SlateTriggerGroupBuilder = class {
2167
2322
  constructor(spec2, params, factory) {
@@ -2177,6 +2332,7 @@ var SlateTriggerGroupBuilder = class {
2177
2332
  #webhook = null;
2178
2333
  #gateway = null;
2179
2334
  #routingMatchers = null;
2335
+ #selectionOptions = {};
2180
2336
  polling(props) {
2181
2337
  if (this.#source) {
2182
2338
  throw new SlateDeclarationError("Trigger group invocation is already defined");
@@ -2197,11 +2353,41 @@ var SlateTriggerGroupBuilder = class {
2197
2353
  "Webhook trigger groups require exactly one of autoRegistration or manualRegistration"
2198
2354
  );
2199
2355
  }
2356
+ if (props.deliveryConfig !== void 0) {
2357
+ if (!props.autoRegistration) {
2358
+ throw new SlateDeclarationError(
2359
+ "A webhook delivery config requires automatic webhook registration"
2360
+ );
2361
+ }
2362
+ if (!props.deliveryConfig.finish) {
2363
+ throw new SlateDeclarationError("A webhook delivery config requires a finish handler");
2364
+ }
2365
+ if (!props.deliveryConfig.authenticate) {
2366
+ throw new SlateDeclarationError(
2367
+ "A webhook delivery config requires an authenticate handler"
2368
+ );
2369
+ }
2370
+ }
2371
+ if (props.reconcileIntervalSeconds !== void 0) {
2372
+ if (!Number.isSafeInteger(props.reconcileIntervalSeconds) || props.reconcileIntervalSeconds < 900) {
2373
+ throw new SlateDeclarationError(
2374
+ "Webhook reconciliation interval must be an integer of at least 900 seconds"
2375
+ );
2376
+ }
2377
+ if (!props.expandWebhook) {
2378
+ throw new SlateDeclarationError(
2379
+ "Webhook reconciliation requires an expandWebhook handler"
2380
+ );
2381
+ }
2382
+ }
2200
2383
  this.#source = "webhook";
2201
2384
  this.#webhook = {
2202
2385
  autoRegistration: props.autoRegistration,
2203
2386
  manualRegistration: props.manualRegistration,
2204
- process: props.process
2387
+ deliveryConfig: props.deliveryConfig,
2388
+ process: props.process,
2389
+ expandWebhook: props.expandWebhook,
2390
+ reconcileIntervalSeconds: props.reconcileIntervalSeconds
2205
2391
  };
2206
2392
  return this;
2207
2393
  }
@@ -2218,6 +2404,27 @@ var SlateTriggerGroupBuilder = class {
2218
2404
  this.#routingMatchers = handler;
2219
2405
  return this;
2220
2406
  }
2407
+ /**
2408
+ * Lets the dashboard offer a list for these selection fields instead of a typed-in value.
2409
+ * Each field must be a top-level property of the selection schema, which must be a zod object.
2410
+ * For an array property the listed options are values for its items.
2411
+ */
2412
+ selectionOptions(declarations) {
2413
+ let schema = this.params.selectionSchema;
2414
+ if (!schema) {
2415
+ throw new SlateDeclarationError("Selection options require a selection schema");
2416
+ }
2417
+ if (schema._zod?.def?.type !== "object") {
2418
+ throw new SlateDeclarationError(
2419
+ "Selection options require the selection schema to be a zod object"
2420
+ );
2421
+ }
2422
+ let shape = schema.shape;
2423
+ for (let [field, sources] of Object.entries(declarations)) {
2424
+ this.#selectionOptions[field] = checkSelectionOptions(field, sources, shape);
2425
+ }
2426
+ return this;
2427
+ }
2221
2428
  build() {
2222
2429
  if (!this.#source) {
2223
2430
  throw new SlateDeclarationError(
@@ -2233,7 +2440,8 @@ var SlateTriggerGroupBuilder = class {
2233
2440
  polling: this.#polling ?? void 0,
2234
2441
  webhook: this.#webhook ?? void 0,
2235
2442
  gateway: this.#gateway ?? void 0,
2236
- routingMatchers: this.#routingMatchers
2443
+ routingMatchers: this.#routingMatchers,
2444
+ selectionOptions: this.#selectionOptions
2237
2445
  });
2238
2446
  }
2239
2447
  };
@@ -2981,13 +3189,29 @@ var createHmacSignature = ({
2981
3189
  digest,
2982
3190
  prefix = ""
2983
3191
  }) => `${prefix}${createHmac(algorithm, secret).update(payload).digest(digest)}`;
2984
- var verifyHmacSignature = (options) => {
2985
- let expected = createHmacSignature(options);
3192
+ var timingSafeStringEqual = (expected, received) => {
2986
3193
  let expectedBytes = Buffer.from(expected);
2987
- let signatureBytes = Buffer.from(options.signature);
2988
- let lengthsMatch = signatureBytes.length === expectedBytes.length;
2989
- let comparableSignature = lengthsMatch ? signatureBytes : Buffer.alloc(expectedBytes.length);
2990
- return timingSafeEqual(comparableSignature, expectedBytes) && lengthsMatch;
3194
+ let receivedBytes = Buffer.from(received ?? "");
3195
+ let lengthsMatch = receivedBytes.length === expectedBytes.length;
3196
+ let comparable = lengthsMatch ? receivedBytes : Buffer.alloc(expectedBytes.length);
3197
+ return timingSafeEqual(comparable, expectedBytes) && lengthsMatch && expectedBytes.length > 0;
3198
+ };
3199
+ var verifyHmacSignature = (options) => timingSafeStringEqual(createHmacSignature(options), options.signature);
3200
+
3201
+ // src/dedup/index.ts
3202
+ import { createHash } from "crypto";
3203
+ import { z as z4 } from "zod";
3204
+ var seenEntrySchema = z4.object({ key: z4.string().min(1), at: z4.number().finite() });
3205
+ var seenEntryKey = (idempotencyKey) => createHash("sha256").update(idempotencyKey).digest("base64url").slice(0, 16);
3206
+ var pruneSeenEntries = (entries, options) => {
3207
+ let kept = [];
3208
+ for (let { key, at, retain } of entries) {
3209
+ if (retain || at >= options.cutoff) kept.push({ key, at });
3210
+ }
3211
+ kept.sort((a, b) => b.at - a.at || (a.key < b.key ? -1 : 1));
3212
+ if (kept.length <= options.maxEntries) return kept;
3213
+ options.onOverflow?.(kept.length - options.maxEntries);
3214
+ return kept.slice(0, options.maxEntries);
2991
3215
  };
2992
3216
 
2993
3217
  // src/file/index.ts
@@ -3117,15 +3341,26 @@ var setIfDefined = (target, key, value) => {
3117
3341
  return target;
3118
3342
  };
3119
3343
 
3344
+ // src/pagination/index.ts
3345
+ var rememberPageToken = (seen, token) => {
3346
+ if (seen.has(token)) return false;
3347
+ seen.add(token);
3348
+ return true;
3349
+ };
3350
+ var assertNewPageToken = (seen, token, repeated) => {
3351
+ if (token && !rememberPageToken(seen, token)) throw repeated();
3352
+ };
3353
+
3120
3354
  // src/specification/slate.ts
3121
3355
  var Slate = class _Slate {
3122
- constructor(_spec, _actions, _adapters, _triggerGroups, _toolCategories, _toolCategoryKeysByActionKey) {
3356
+ constructor(_spec, _actions, _adapters, _triggerGroups, _toolCategories, _toolCategoryKeysByActionKey, _optionLists) {
3123
3357
  this._spec = _spec;
3124
3358
  this._actions = _actions;
3125
3359
  this._adapters = _adapters;
3126
3360
  this._triggerGroups = _triggerGroups;
3127
3361
  this._toolCategories = _toolCategories;
3128
3362
  this._toolCategoryKeysByActionKey = _toolCategoryKeysByActionKey;
3363
+ this._optionLists = _optionLists;
3129
3364
  }
3130
3365
  _spec;
3131
3366
  _actions;
@@ -3133,6 +3368,7 @@ var Slate = class _Slate {
3133
3368
  _triggerGroups;
3134
3369
  _toolCategories;
3135
3370
  _toolCategoryKeysByActionKey;
3371
+ _optionLists;
3136
3372
  static create(params) {
3137
3373
  let adapters = params.adapters ?? [];
3138
3374
  let actions = [...params.triggers, ...params.tools];
@@ -3168,14 +3404,24 @@ var Slate = class _Slate {
3168
3404
  }
3169
3405
  seenTriggerGroupKeys.add(group.key);
3170
3406
  }
3171
- let manualWebhookTriggerGroups = triggerGroups.filter(
3172
- (group) => group.source === "webhook" && group.webhook?.manualRegistration
3407
+ let configuredWebhookTriggerGroups = triggerGroups.filter(
3408
+ (group) => group.source === "webhook" && (group.webhook?.manualRegistration || group.webhook?.deliveryConfig)
3173
3409
  );
3174
- if (manualWebhookTriggerGroups.length > 1) {
3410
+ if (configuredWebhookTriggerGroups.length > 1) {
3175
3411
  throw new SlateDeclarationError(
3176
- `Only one trigger group may use manual webhook registration, but found: ${manualWebhookTriggerGroups.map((group) => group.key).join(", ")}`
3412
+ `Only one trigger group may use manual webhook registration or a delivery config, but found: ${configuredWebhookTriggerGroups.map((group) => group.key).join(", ")}`
3177
3413
  );
3178
3414
  }
3415
+ let optionLists = params.optionLists ?? [];
3416
+ let seenOptionListKeys = /* @__PURE__ */ new Set();
3417
+ for (let list of optionLists) {
3418
+ if (seenOptionListKeys.has(list.key)) {
3419
+ throw new SlateDeclarationError(
3420
+ `Option list "${list.key}" is registered more than once`
3421
+ );
3422
+ }
3423
+ seenOptionListKeys.add(list.key);
3424
+ }
3179
3425
  let toolCategories = params.toolCategories ?? [];
3180
3426
  let toolCategoryKeysByActionKey = resolveToolCategoryMembership(toolCategories, actions);
3181
3427
  return new _Slate(
@@ -3184,7 +3430,8 @@ var Slate = class _Slate {
3184
3430
  adapters,
3185
3431
  triggerGroups,
3186
3432
  toolCategories,
3187
- toolCategoryKeysByActionKey
3433
+ toolCategoryKeysByActionKey,
3434
+ optionLists
3188
3435
  );
3189
3436
  }
3190
3437
  get spec() {
@@ -3202,6 +3449,9 @@ var Slate = class _Slate {
3202
3449
  get toolCategories() {
3203
3450
  return this._toolCategories ?? [];
3204
3451
  }
3452
+ get optionLists() {
3453
+ return this._optionLists ?? [];
3454
+ }
3205
3455
  // Keys of the tool categories an action belongs to, in declared category order.
3206
3456
  getToolCategoryKeys(actionKey) {
3207
3457
  return [...this._toolCategoryKeysByActionKey?.get(actionKey) ?? []];
@@ -3275,7 +3525,7 @@ var resolveToolCategoryMembership = (toolCategories, actions) => {
3275
3525
  };
3276
3526
 
3277
3527
  // src/specification/specification.ts
3278
- import z3 from "zod";
3528
+ import z5 from "zod";
3279
3529
  var SlateSpecification = class _SlateSpecification {
3280
3530
  constructor(_config, _auth, _params) {
3281
3531
  this._config = _config;
@@ -3292,7 +3542,7 @@ var SlateSpecification = class _SlateSpecification {
3292
3542
  return this._config.configSchema;
3293
3543
  }
3294
3544
  get authSchema() {
3295
- return "outputSchema" in this._auth ? this._auth.outputSchema : z3.object({});
3545
+ return "outputSchema" in this._auth ? this._auth.outputSchema : z5.object({});
3296
3546
  }
3297
3547
  get config() {
3298
3548
  return this._config;
@@ -3396,6 +3646,7 @@ export {
3396
3646
  SlateDefaultPollingIntervalSeconds,
3397
3647
  SlateError,
3398
3648
  SlateLogger,
3649
+ SlateOptionList,
3399
3650
  SlatePublicContext,
3400
3651
  SlatePublicTool,
3401
3652
  SlateSpecification,
@@ -3407,6 +3658,7 @@ export {
3407
3658
  adapterSpec,
3408
3659
  allOf,
3409
3660
  anyOf,
3661
+ assertNewPageToken,
3410
3662
  auth,
3411
3663
  axios,
3412
3664
  buildApiServiceError,
@@ -3436,6 +3688,7 @@ export {
3436
3688
  getResponseHeaderValue,
3437
3689
  getRuntimeInfo,
3438
3690
  getServiceErrorData,
3691
+ getUpstreamErrorStatus,
3439
3692
  graphWebhookHttp,
3440
3693
  inferSlateErrorFromAxios,
3441
3694
  isApiErrorRecord,
@@ -3448,19 +3701,26 @@ export {
3448
3701
  mergeScopes,
3449
3702
  metaWebhookHttp,
3450
3703
  normalizeOAuthTokenResponse,
3704
+ optionList,
3705
+ parseWithServiceError,
3451
3706
  pickDefined,
3707
+ pruneSeenEntries,
3452
3708
  publicTool,
3453
3709
  pushBoundedApiErrorDetail,
3454
3710
  readApiErrorText,
3455
3711
  redactUrlAttachmentSecrets,
3712
+ rememberPageToken,
3456
3713
  requestAxios,
3457
3714
  requestAxiosData,
3458
3715
  runWithContext,
3459
3716
  scopeClause,
3717
+ seenEntryKey,
3718
+ seenEntrySchema,
3460
3719
  setIfDefined,
3461
3720
  skipWebhook,
3462
3721
  spec,
3463
3722
  statusLabelForApiError,
3723
+ timingSafeStringEqual,
3464
3724
  tool,
3465
3725
  toolCategory,
3466
3726
  trigger,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slates/provider",
3
- "version": "1.0.0-rc.33",
3
+ "version": "1.0.0-rc.35",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -92,6 +92,7 @@ export interface SlateActionParametersTrigger<
92
92
  triggerGroup: SlateTriggerGroup<ConfigType, AuthType>;
93
93
  matches: SlateTriggerMatchesHandler;
94
94
  map: SlateTriggerMappingHandler<ConfigType, AuthType, InputType, OutputType>;
95
+ eventAttributes?: string[];
95
96
  }
96
97
 
97
98
  export type SlateActionParametersAny<
@@ -17,6 +17,51 @@ import type {
17
17
  import { validateScopes } from './scopes';
18
18
  import type { SlateTriggerGroup } from './triggerGroup';
19
19
 
20
+ // Mirrors the event attribute limits in @slates/proto.
21
+ let EVENT_ATTRIBUTE_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
22
+ let EVENT_ATTRIBUTE_MAX_KEYS = 8;
23
+
24
+ let checkEventAttributeNames = (fields: string[]) => {
25
+ if (!Array.isArray(fields)) {
26
+ throw new SlateDeclarationError('Event attributes must be a list of output field names');
27
+ }
28
+ if (fields.length > EVENT_ATTRIBUTE_MAX_KEYS) {
29
+ throw new SlateDeclarationError(
30
+ `A trigger can declare at most ${EVENT_ATTRIBUTE_MAX_KEYS} event attributes`
31
+ );
32
+ }
33
+
34
+ let seen = new Set<string>();
35
+ for (let field of fields) {
36
+ if (typeof field !== 'string' || !EVENT_ATTRIBUTE_KEY_PATTERN.test(field)) {
37
+ throw new SlateDeclarationError(
38
+ `Event attribute "${field}" must start with a letter and contain only letters, digits and underscores (at most 64 characters)`
39
+ );
40
+ }
41
+ if (seen.has(field)) {
42
+ throw new SlateDeclarationError(`Event attribute "${field}" is declared more than once`);
43
+ }
44
+ seen.add(field);
45
+ }
46
+ };
47
+
48
+ let checkEventAttributeFields = (fields: string[], outputSchema: z.ZodType<any>) => {
49
+ if ((outputSchema as any)._zod?.def?.type !== 'object') {
50
+ throw new SlateDeclarationError(
51
+ 'Event attributes require the output schema to be a zod object'
52
+ );
53
+ }
54
+
55
+ let shape = (outputSchema as z.ZodObject<any>).shape;
56
+ for (let field of fields) {
57
+ if (!Object.hasOwn(shape, field)) {
58
+ throw new SlateDeclarationError(
59
+ `Event attribute "${field}" is not a top-level property of the output schema`
60
+ );
61
+ }
62
+ }
63
+ };
64
+
20
65
  export class SlateActionBuilder<
21
66
  Type extends SlateActionType,
22
67
  ConfigType extends {},
@@ -39,6 +84,7 @@ export class SlateActionBuilder<
39
84
  #triggerMatches: SlateTriggerMatchesHandler | null = null;
40
85
  #triggerMap: SlateTriggerMappingHandler<ConfigType, AuthType, InputType, OutputType> | null =
41
86
  null;
87
+ #eventAttributes: string[] | null = null;
42
88
  #interfaceLocked = false;
43
89
 
44
90
  constructor(
@@ -190,6 +236,26 @@ export class SlateActionBuilder<
190
236
  return this;
191
237
  }
192
238
 
239
+ /**
240
+ * Returns the values of these top-level output fields with every mapped event, so events
241
+ * can be filtered by them. Strings, finite numbers, booleans and arrays of those are used.
242
+ */
243
+ eventAttributes(
244
+ fields: (keyof OutputType & string)[]
245
+ ): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result, IsPublic> {
246
+ if (this.type !== 'trigger') {
247
+ throw new SlateDeclarationError('eventAttributes can only be set for trigger actions');
248
+ }
249
+
250
+ checkEventAttributeNames(fields);
251
+ if (this.#outputSchema) {
252
+ checkEventAttributeFields(fields, this.#outputSchema);
253
+ }
254
+
255
+ this.#eventAttributes = [...fields];
256
+ return this;
257
+ }
258
+
193
259
  build() {
194
260
  let scopes = this.#scopes ?? this.params.scopes;
195
261
  if (scopes) {
@@ -219,6 +285,9 @@ export class SlateActionBuilder<
219
285
  if (this.type === 'trigger' && !this.#triggerMap) {
220
286
  throw new SlateDeclarationError('Trigger map handler is not defined');
221
287
  }
288
+ if (this.#eventAttributes) {
289
+ checkEventAttributeFields(this.#eventAttributes, this.#outputSchema);
290
+ }
222
291
 
223
292
  let triggerParams: SlateActionParametersTrigger<
224
293
  ConfigType,
@@ -231,7 +300,10 @@ export class SlateActionBuilder<
231
300
  type: 'trigger',
232
301
  triggerGroup: this.#triggerGroup!,
233
302
  matches: this.#triggerMatches!,
234
- map: this.#triggerMap! as any
303
+ map: this.#triggerMap! as any,
304
+ ...(this.#eventAttributes?.length
305
+ ? { eventAttributes: this.#eventAttributes }
306
+ : {})
235
307
  }
236
308
  : null;
237
309
 
@@ -1,6 +1,7 @@
1
1
  export * from './action';
2
2
  export * from './builder';
3
3
  export * from './getFileUrlTool';
4
+ export * from './optionList';
4
5
  export * from './publicTool';
5
6
  export * from './scopes';
6
7
  export * from './tool';