@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.
- package/dist/index.cjs +289 -19
- package/dist/index.d.cts +168 -2
- package/dist/index.d.ts +168 -2
- package/dist/index.module.js +279 -19
- package/package.json +1 -1
- package/src/action/action.ts +1 -0
- package/src/action/builder.ts +73 -1
- package/src/action/index.ts +1 -0
- package/src/action/optionList.ts +94 -0
- package/src/action/trigger.test.ts +132 -0
- package/src/action/trigger.ts +7 -0
- package/src/action/triggerGroup.test.ts +172 -0
- package/src/action/triggerGroup.ts +248 -5
- package/src/crypto/hmac.test.ts +17 -1
- package/src/crypto/hmac.ts +11 -6
- package/src/dedup/index.test.ts +47 -0
- package/src/dedup/index.ts +25 -0
- package/src/error/api.test.ts +22 -0
- package/src/error/api.ts +8 -0
- package/src/error/index.ts +1 -0
- package/src/error/parse.test.ts +29 -0
- package/src/error/parse.ts +14 -0
- package/src/index.ts +2 -0
- package/src/pagination/index.test.ts +21 -0
- package/src/pagination/index.ts +15 -0
- package/src/specification/slate.test.ts +123 -3
- package/src/specification/slate.ts +33 -7
package/dist/index.module.js
CHANGED
|
@@ -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
|
|
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 ??
|
|
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
|
-
|
|
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
|
|
2985
|
-
let expected = createHmacSignature(options);
|
|
3192
|
+
var timingSafeStringEqual = (expected, received) => {
|
|
2986
3193
|
let expectedBytes = Buffer.from(expected);
|
|
2987
|
-
let
|
|
2988
|
-
let lengthsMatch =
|
|
2989
|
-
let
|
|
2990
|
-
return timingSafeEqual(
|
|
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
|
|
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 (
|
|
3410
|
+
if (configuredWebhookTriggerGroups.length > 1) {
|
|
3175
3411
|
throw new SlateDeclarationError(
|
|
3176
|
-
`Only one trigger group may use manual webhook registration, but found: ${
|
|
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
|
|
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 :
|
|
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
package/src/action/action.ts
CHANGED
|
@@ -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<
|
package/src/action/builder.ts
CHANGED
|
@@ -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
|
|