@slates/provider 1.0.0-rc.15 → 1.0.0-rc.17
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 +414 -5
- package/dist/index.d.cts +190 -1
- package/dist/index.d.ts +190 -1
- package/dist/index.module.js +388 -2
- package/package.json +2 -2
- package/src/action/action.ts +50 -1
- package/src/action/builder.ts +26 -2
- package/src/action/trigger.ts +9 -1
- package/src/auth/index.ts +1 -0
- package/src/auth/oauth.test.ts +83 -0
- package/src/auth/oauth.ts +150 -0
- package/src/auth/types.ts +31 -6
- package/src/axios/http.test.ts +83 -0
- package/src/axios/index.ts +59 -1
- package/src/context/context.ts +8 -0
- package/src/crypto/hmac.test.ts +40 -0
- package/src/crypto/hmac.ts +32 -0
- package/src/crypto/index.ts +1 -0
- package/src/error/api.test.ts +114 -0
- package/src/error/api.ts +236 -0
- package/src/error/index.ts +1 -0
- package/src/file/index.test.ts +36 -0
- package/src/file/index.ts +27 -0
- package/src/index.ts +4 -0
- package/src/object/index.test.ts +38 -0
- package/src/object/index.ts +12 -0
- package/src/webhook/graph.test.ts +37 -0
- package/src/webhook/graph.ts +22 -0
- package/src/webhook/index.ts +2 -0
- package/src/webhook/meta.test.ts +52 -0
- package/src/webhook/meta.ts +43 -0
package/dist/index.module.js
CHANGED
|
@@ -48,11 +48,132 @@ var SlateAction = class {
|
|
|
48
48
|
get scopes() {
|
|
49
49
|
return this._params.scopes;
|
|
50
50
|
}
|
|
51
|
+
get authMethods() {
|
|
52
|
+
return this._params.authMethods;
|
|
53
|
+
}
|
|
51
54
|
get docs() {
|
|
52
55
|
return this._params.docs;
|
|
53
56
|
}
|
|
54
57
|
};
|
|
55
58
|
|
|
59
|
+
// src/error/api.ts
|
|
60
|
+
import { badRequestError, ServiceError } from "@lowerdeck/error";
|
|
61
|
+
var DEFAULT_DETAIL_KEYS = ["message", "detail", "error", "error_description", "code"];
|
|
62
|
+
var DEFAULT_NESTED_KEYS = ["errors"];
|
|
63
|
+
var isApiErrorRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
64
|
+
var pushDetail = (details, value, options = {}) => {
|
|
65
|
+
if (typeof value !== "string" && (options.includeNumbers === false || typeof value !== "number")) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
let detail = String(value).trim();
|
|
69
|
+
if (detail && !details.includes(detail)) {
|
|
70
|
+
details.push(detail);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var collectApiErrorDetails = (value, details, options = {}) => {
|
|
74
|
+
if (Array.isArray(value)) {
|
|
75
|
+
for (let item of value) {
|
|
76
|
+
collectApiErrorDetails(item, details, options);
|
|
77
|
+
}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (!isApiErrorRecord(value)) {
|
|
81
|
+
pushDetail(details, value, options);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
for (let key of options.detailKeys ?? DEFAULT_DETAIL_KEYS) {
|
|
85
|
+
pushDetail(details, value[key], options);
|
|
86
|
+
}
|
|
87
|
+
for (let key of options.nestedKeys ?? DEFAULT_NESTED_KEYS) {
|
|
88
|
+
collectApiErrorDetails(value[key], details, options);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
var getSlateErrorResponse = (error) => {
|
|
92
|
+
if (error.name !== "SlateError" || !isApiErrorRecord(error.data)) {
|
|
93
|
+
return void 0;
|
|
94
|
+
}
|
|
95
|
+
let data = error.data;
|
|
96
|
+
let upstream = isApiErrorRecord(data.upstream) ? data.upstream : void 0;
|
|
97
|
+
let status = upstream?.status ?? data.status;
|
|
98
|
+
return typeof status === "number" || typeof status === "string" ? { status } : void 0;
|
|
99
|
+
};
|
|
100
|
+
var getApiErrorResponse = (error) => {
|
|
101
|
+
if (!isApiErrorRecord(error)) {
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
if (!isApiErrorRecord(error.response)) {
|
|
105
|
+
return getSlateErrorResponse(error);
|
|
106
|
+
}
|
|
107
|
+
let response = error.response;
|
|
108
|
+
return {
|
|
109
|
+
status: typeof response.status === "number" || typeof response.status === "string" ? response.status : void 0,
|
|
110
|
+
statusText: typeof response.statusText === "string" ? response.statusText : void 0,
|
|
111
|
+
data: response.data
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
var getApiErrorStatus = (error) => getApiErrorResponse(error)?.status;
|
|
115
|
+
var statusLabelForApiError = (status, statusText) => status !== void 0 ? `HTTP ${status}${statusText ? ` ${statusText}` : ""}: ` : "";
|
|
116
|
+
var extractApiErrorMessage = (error, options = {}) => {
|
|
117
|
+
let details = [];
|
|
118
|
+
let response = options.response ?? getApiErrorResponse(error);
|
|
119
|
+
collectApiErrorDetails(response?.data, details, options);
|
|
120
|
+
if (details.length > 0) {
|
|
121
|
+
return details.join(options.separator ?? " - ");
|
|
122
|
+
}
|
|
123
|
+
if (error instanceof Error && error.message) {
|
|
124
|
+
return error.message;
|
|
125
|
+
}
|
|
126
|
+
return options.fallbackMessage ?? "Unknown error";
|
|
127
|
+
};
|
|
128
|
+
var createApiServiceError = (message, options = {}) => {
|
|
129
|
+
let error = new ServiceError(badRequestError({ message }));
|
|
130
|
+
if (options.reason !== void 0) {
|
|
131
|
+
error.data.reason = options.reason;
|
|
132
|
+
}
|
|
133
|
+
if ("upstreamStatus" in options) {
|
|
134
|
+
error.data.upstreamStatus = options.upstreamStatus;
|
|
135
|
+
}
|
|
136
|
+
if ("upstreamCode" in options) {
|
|
137
|
+
error.data.upstreamCode = options.upstreamCode;
|
|
138
|
+
}
|
|
139
|
+
if (options.parent instanceof Error) {
|
|
140
|
+
error.setParent(options.parent);
|
|
141
|
+
}
|
|
142
|
+
return error;
|
|
143
|
+
};
|
|
144
|
+
var helpers = {
|
|
145
|
+
collectDetails: collectApiErrorDetails,
|
|
146
|
+
extractMessage: extractApiErrorMessage,
|
|
147
|
+
getResponse: getApiErrorResponse,
|
|
148
|
+
getStatus: getApiErrorStatus,
|
|
149
|
+
isRecord: isApiErrorRecord,
|
|
150
|
+
statusLabelFor: statusLabelForApiError
|
|
151
|
+
};
|
|
152
|
+
var buildApiServiceError = (error, options) => {
|
|
153
|
+
if (error instanceof ServiceError) {
|
|
154
|
+
return error;
|
|
155
|
+
}
|
|
156
|
+
let operation = options.operation ?? "request";
|
|
157
|
+
let response = options.extractResponse?.(error, helpers) ?? getApiErrorResponse(error);
|
|
158
|
+
let status = options.extractStatus?.(error, response, helpers) ?? response?.status;
|
|
159
|
+
let message = options.extractMessage?.(error, helpers) ?? extractApiErrorMessage(error, { ...options, response });
|
|
160
|
+
let statusLabel = statusLabelForApiError(status, response?.statusText);
|
|
161
|
+
let fullMessage = options.formatMessage?.({
|
|
162
|
+
providerLabel: options.providerLabel,
|
|
163
|
+
operation,
|
|
164
|
+
statusLabel,
|
|
165
|
+
message,
|
|
166
|
+
response,
|
|
167
|
+
status
|
|
168
|
+
}) ?? `${options.providerLabel} API ${operation} failed: ${statusLabel}${message}`;
|
|
169
|
+
return createApiServiceError(fullMessage, {
|
|
170
|
+
reason: options.reason,
|
|
171
|
+
upstreamStatus: status,
|
|
172
|
+
upstreamCode: options.extractUpstreamCode?.(error, response, helpers),
|
|
173
|
+
parent: options.parent ?? error
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
|
|
56
177
|
// src/error/axios.ts
|
|
57
178
|
import { isAxiosError } from "axios";
|
|
58
179
|
|
|
@@ -694,6 +815,7 @@ var SlateActionBuilder = class {
|
|
|
694
815
|
#inputSchema = null;
|
|
695
816
|
#outputSchema = null;
|
|
696
817
|
#scopes;
|
|
818
|
+
#authMethods;
|
|
697
819
|
#toolParams = null;
|
|
698
820
|
#triggerParams = null;
|
|
699
821
|
input(schema) {
|
|
@@ -709,6 +831,18 @@ var SlateActionBuilder = class {
|
|
|
709
831
|
this.#scopes = scopes;
|
|
710
832
|
return this;
|
|
711
833
|
}
|
|
834
|
+
authMethods(authMethods) {
|
|
835
|
+
this.#authMethods = this.validateAuthMethods(authMethods);
|
|
836
|
+
return this;
|
|
837
|
+
}
|
|
838
|
+
validateAuthMethods(authMethods) {
|
|
839
|
+
if (!authMethods) return void 0;
|
|
840
|
+
let normalized = [...new Set(authMethods.map((authMethod) => authMethod.trim()))];
|
|
841
|
+
if (normalized.some((authMethod) => !authMethod)) {
|
|
842
|
+
throw new SlateDeclarationError("Auth method IDs must be non-empty strings");
|
|
843
|
+
}
|
|
844
|
+
return normalized;
|
|
845
|
+
}
|
|
712
846
|
handleInvocation(handler) {
|
|
713
847
|
if (this.type !== "tool") {
|
|
714
848
|
throw new SlateDeclarationError("handleInvocation can only be set for tool actions");
|
|
@@ -729,7 +863,8 @@ var SlateActionBuilder = class {
|
|
|
729
863
|
handleEvent: props.handleEvent,
|
|
730
864
|
handleRequest: props.handleRequest,
|
|
731
865
|
autoRegisterWebhook: props.autoRegisterWebhook,
|
|
732
|
-
autoUnregisterWebhook: props.autoUnregisterWebhook
|
|
866
|
+
autoUnregisterWebhook: props.autoUnregisterWebhook,
|
|
867
|
+
http: props.http
|
|
733
868
|
};
|
|
734
869
|
return this;
|
|
735
870
|
}
|
|
@@ -751,6 +886,7 @@ var SlateActionBuilder = class {
|
|
|
751
886
|
if (scopes) {
|
|
752
887
|
validateScopes(scopes);
|
|
753
888
|
}
|
|
889
|
+
let authMethods = this.validateAuthMethods(this.#authMethods ?? this.params.authMethods);
|
|
754
890
|
if (!this.#inputSchema) {
|
|
755
891
|
throw new SlateDeclarationError("Input schema is not defined");
|
|
756
892
|
}
|
|
@@ -766,6 +902,7 @@ var SlateActionBuilder = class {
|
|
|
766
902
|
return this.factory({
|
|
767
903
|
...this.params,
|
|
768
904
|
scopes,
|
|
905
|
+
authMethods,
|
|
769
906
|
configSchema: this.#configSchema,
|
|
770
907
|
authSchema: this.#authSchema,
|
|
771
908
|
inputSchema: this.#inputSchema,
|
|
@@ -802,6 +939,7 @@ var SlateTrigger = class _SlateTrigger extends SlateAction {
|
|
|
802
939
|
#polling;
|
|
803
940
|
#handleEvent;
|
|
804
941
|
#handleRequest;
|
|
942
|
+
#http;
|
|
805
943
|
#pollEvents;
|
|
806
944
|
#autoRegisterWebhook;
|
|
807
945
|
#autoUnregisterWebhook;
|
|
@@ -813,6 +951,7 @@ var SlateTrigger = class _SlateTrigger extends SlateAction {
|
|
|
813
951
|
};
|
|
814
952
|
this.#handleEvent = params.handleEvent;
|
|
815
953
|
this.#handleRequest = params.handleRequest;
|
|
954
|
+
this.#http = params.http;
|
|
816
955
|
this.#pollEvents = params.pollEvents;
|
|
817
956
|
this.#autoRegisterWebhook = params.autoRegisterWebhook;
|
|
818
957
|
this.#autoUnregisterWebhook = params.autoUnregisterWebhook;
|
|
@@ -835,6 +974,9 @@ var SlateTrigger = class _SlateTrigger extends SlateAction {
|
|
|
835
974
|
get handleRequest() {
|
|
836
975
|
return this.#handleRequest;
|
|
837
976
|
}
|
|
977
|
+
get http() {
|
|
978
|
+
return this.#http;
|
|
979
|
+
}
|
|
838
980
|
get pollEvents() {
|
|
839
981
|
return this.#pollEvents;
|
|
840
982
|
}
|
|
@@ -929,6 +1071,90 @@ var SlateAuth = class _SlateAuth {
|
|
|
929
1071
|
};
|
|
930
1072
|
var auth = () => SlateAuth.create();
|
|
931
1073
|
|
|
1074
|
+
// src/auth/oauth.ts
|
|
1075
|
+
var isOAuthTokenResponse = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1076
|
+
var formatOAuthTokenResponseMessage = (fieldLabel, providerLabel = "OAuth provider", operation = "token response") => `${providerLabel} OAuth ${operation} did not return ${fieldLabel}.`;
|
|
1077
|
+
var getOAuthExpiresAtFromExpiresIn = (expiresIn, options = {}) => {
|
|
1078
|
+
let {
|
|
1079
|
+
nowMs = Date.now(),
|
|
1080
|
+
providerLabel,
|
|
1081
|
+
operation,
|
|
1082
|
+
required = false,
|
|
1083
|
+
expiresInType = "numberLike",
|
|
1084
|
+
message
|
|
1085
|
+
} = options;
|
|
1086
|
+
if (expiresIn === void 0 || expiresIn === null || expiresIn === "") {
|
|
1087
|
+
if (required) {
|
|
1088
|
+
throw createApiServiceError(
|
|
1089
|
+
message ?? formatOAuthTokenResponseMessage(
|
|
1090
|
+
"a valid expires_in value",
|
|
1091
|
+
providerLabel,
|
|
1092
|
+
operation
|
|
1093
|
+
),
|
|
1094
|
+
{ reason: "oauth_token_response" }
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
return void 0;
|
|
1098
|
+
}
|
|
1099
|
+
let seconds = typeof expiresIn === "number" ? expiresIn : expiresInType === "numberLike" && typeof expiresIn === "string" ? Number(expiresIn) : Number.NaN;
|
|
1100
|
+
if (!Number.isFinite(seconds)) {
|
|
1101
|
+
throw createApiServiceError(
|
|
1102
|
+
message ?? formatOAuthTokenResponseMessage("a valid expires_in value", providerLabel, operation),
|
|
1103
|
+
{ reason: "oauth_token_response" }
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
return new Date(nowMs + seconds * 1e3).toISOString();
|
|
1107
|
+
};
|
|
1108
|
+
var getRefreshToken = (refreshToken, previousRefreshToken, fallbackMode) => {
|
|
1109
|
+
if (typeof refreshToken === "string") {
|
|
1110
|
+
if (fallbackMode === "falsy" && !refreshToken) {
|
|
1111
|
+
return previousRefreshToken;
|
|
1112
|
+
}
|
|
1113
|
+
return refreshToken;
|
|
1114
|
+
}
|
|
1115
|
+
if (fallbackMode === "falsy" && !refreshToken) {
|
|
1116
|
+
return previousRefreshToken;
|
|
1117
|
+
}
|
|
1118
|
+
return refreshToken === void 0 || refreshToken === null ? previousRefreshToken : void 0;
|
|
1119
|
+
};
|
|
1120
|
+
var normalizeOAuthTokenResponse = (data, options = {}) => {
|
|
1121
|
+
let {
|
|
1122
|
+
providerLabel,
|
|
1123
|
+
operation,
|
|
1124
|
+
previousRefreshToken,
|
|
1125
|
+
refreshTokenFallbackMode = "nullish",
|
|
1126
|
+
accessTokenMessage,
|
|
1127
|
+
expiresInMessage,
|
|
1128
|
+
...expiresAtOptions
|
|
1129
|
+
} = options;
|
|
1130
|
+
if (!isOAuthTokenResponse(data)) {
|
|
1131
|
+
throw createApiServiceError(
|
|
1132
|
+
accessTokenMessage ?? formatOAuthTokenResponseMessage("a token response object", providerLabel, operation),
|
|
1133
|
+
{ reason: "oauth_token_response" }
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
if (typeof data.access_token !== "string" || !data.access_token) {
|
|
1137
|
+
throw createApiServiceError(
|
|
1138
|
+
accessTokenMessage ?? formatOAuthTokenResponseMessage("an access token", providerLabel, operation),
|
|
1139
|
+
{ reason: "oauth_token_response" }
|
|
1140
|
+
);
|
|
1141
|
+
}
|
|
1142
|
+
return {
|
|
1143
|
+
token: data.access_token,
|
|
1144
|
+
refreshToken: getRefreshToken(
|
|
1145
|
+
data.refresh_token,
|
|
1146
|
+
previousRefreshToken,
|
|
1147
|
+
refreshTokenFallbackMode
|
|
1148
|
+
),
|
|
1149
|
+
expiresAt: getOAuthExpiresAtFromExpiresIn(data.expires_in, {
|
|
1150
|
+
...expiresAtOptions,
|
|
1151
|
+
providerLabel,
|
|
1152
|
+
operation,
|
|
1153
|
+
message: expiresInMessage
|
|
1154
|
+
})
|
|
1155
|
+
};
|
|
1156
|
+
};
|
|
1157
|
+
|
|
932
1158
|
// src/axios/index.ts
|
|
933
1159
|
import baseAxios, { getAdapter, isAxiosError as isAxiosError2 } from "axios";
|
|
934
1160
|
|
|
@@ -1512,6 +1738,35 @@ var createAxios = (config2) => {
|
|
|
1512
1738
|
applySlateInterceptors(instance, errorMapping);
|
|
1513
1739
|
return instance;
|
|
1514
1740
|
};
|
|
1741
|
+
var createAuthenticatedAxios = (config2) => {
|
|
1742
|
+
let { authHeader, contentType = "application/json", errorAdapter, ...axiosConfig } = config2;
|
|
1743
|
+
let instance = createAxios({
|
|
1744
|
+
...axiosConfig,
|
|
1745
|
+
headers: {
|
|
1746
|
+
...contentType === false ? {} : { "Content-Type": contentType },
|
|
1747
|
+
...authHeader ? { [authHeader.name ?? "Authorization"]: authHeader.value } : {},
|
|
1748
|
+
...axiosConfig.headers
|
|
1749
|
+
}
|
|
1750
|
+
});
|
|
1751
|
+
if (errorAdapter) {
|
|
1752
|
+
instance.interceptors.response.use(
|
|
1753
|
+
(response) => response,
|
|
1754
|
+
(error) => Promise.reject(errorAdapter(error))
|
|
1755
|
+
);
|
|
1756
|
+
}
|
|
1757
|
+
return instance;
|
|
1758
|
+
};
|
|
1759
|
+
var requestAxios = async (operation, request, errorAdapter) => {
|
|
1760
|
+
try {
|
|
1761
|
+
return await request();
|
|
1762
|
+
} catch (error) {
|
|
1763
|
+
throw errorAdapter(error, operation);
|
|
1764
|
+
}
|
|
1765
|
+
};
|
|
1766
|
+
var requestAxiosData = async (operation, request, errorAdapter) => {
|
|
1767
|
+
let response = await requestAxios(operation, request, errorAdapter);
|
|
1768
|
+
return response.data;
|
|
1769
|
+
};
|
|
1515
1770
|
var axios = createAxios();
|
|
1516
1771
|
|
|
1517
1772
|
// src/config/config.ts
|
|
@@ -1590,6 +1845,11 @@ var SlateContext = class {
|
|
|
1590
1845
|
get request() {
|
|
1591
1846
|
return Object.freeze(this.#input.request);
|
|
1592
1847
|
}
|
|
1848
|
+
get registrationDetails() {
|
|
1849
|
+
return Object.freeze(
|
|
1850
|
+
this.#input.registrationDetails
|
|
1851
|
+
);
|
|
1852
|
+
}
|
|
1593
1853
|
get auth() {
|
|
1594
1854
|
return Object.freeze(this.#auth);
|
|
1595
1855
|
}
|
|
@@ -1628,6 +1888,45 @@ var SlateContext = class {
|
|
|
1628
1888
|
}
|
|
1629
1889
|
};
|
|
1630
1890
|
|
|
1891
|
+
// src/crypto/hmac.ts
|
|
1892
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
1893
|
+
var createHmacSignature = ({
|
|
1894
|
+
secret,
|
|
1895
|
+
payload,
|
|
1896
|
+
algorithm = "sha256",
|
|
1897
|
+
digest,
|
|
1898
|
+
prefix = ""
|
|
1899
|
+
}) => `${prefix}${createHmac(algorithm, secret).update(payload).digest(digest)}`;
|
|
1900
|
+
var verifyHmacSignature = (options) => {
|
|
1901
|
+
let expected = createHmacSignature(options);
|
|
1902
|
+
let expectedBytes = Buffer.from(expected);
|
|
1903
|
+
let signatureBytes = Buffer.from(options.signature);
|
|
1904
|
+
let lengthsMatch = signatureBytes.length === expectedBytes.length;
|
|
1905
|
+
let comparableSignature = lengthsMatch ? signatureBytes : Buffer.alloc(expectedBytes.length);
|
|
1906
|
+
return timingSafeEqual(comparableSignature, expectedBytes) && lengthsMatch;
|
|
1907
|
+
};
|
|
1908
|
+
|
|
1909
|
+
// src/file/index.ts
|
|
1910
|
+
var getResponseHeaderValue = (headers, name) => {
|
|
1911
|
+
if (!headers) return void 0;
|
|
1912
|
+
if (typeof headers.get === "function") {
|
|
1913
|
+
let value = headers.get(name);
|
|
1914
|
+
return typeof value === "string" ? value : void 0;
|
|
1915
|
+
}
|
|
1916
|
+
if (typeof headers !== "object") return void 0;
|
|
1917
|
+
let lowerName = name.toLowerCase();
|
|
1918
|
+
for (let [headerName, value] of Object.entries(headers)) {
|
|
1919
|
+
if (headerName.toLowerCase() !== lowerName) continue;
|
|
1920
|
+
if (Array.isArray(value)) {
|
|
1921
|
+
let first = value.find((item) => typeof item === "string");
|
|
1922
|
+
return typeof first === "string" ? first : void 0;
|
|
1923
|
+
}
|
|
1924
|
+
return typeof value === "string" ? value : void 0;
|
|
1925
|
+
}
|
|
1926
|
+
return void 0;
|
|
1927
|
+
};
|
|
1928
|
+
var getBase64ByteLength = (contentBase64) => Buffer.from(contentBase64, "base64").byteLength;
|
|
1929
|
+
|
|
1631
1930
|
// src/logger/logger.ts
|
|
1632
1931
|
import { encode } from "@toon-format/toon";
|
|
1633
1932
|
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -1723,6 +2022,17 @@ var SlateLogger = class {
|
|
|
1723
2022
|
}
|
|
1724
2023
|
};
|
|
1725
2024
|
|
|
2025
|
+
// src/object/index.ts
|
|
2026
|
+
var pickDefined = (value) => Object.fromEntries(
|
|
2027
|
+
Object.entries(value).filter(([, child]) => child !== void 0)
|
|
2028
|
+
);
|
|
2029
|
+
var setIfDefined = (target, key, value) => {
|
|
2030
|
+
if (value !== void 0) {
|
|
2031
|
+
target[key] = value;
|
|
2032
|
+
}
|
|
2033
|
+
return target;
|
|
2034
|
+
};
|
|
2035
|
+
|
|
1726
2036
|
// src/specification/slate.ts
|
|
1727
2037
|
var Slate = class _Slate {
|
|
1728
2038
|
constructor(_spec, _actions) {
|
|
@@ -1785,6 +2095,59 @@ var SlateSpecification = class _SlateSpecification {
|
|
|
1785
2095
|
}
|
|
1786
2096
|
};
|
|
1787
2097
|
var spec = (params) => SlateSpecification.create(params);
|
|
2098
|
+
|
|
2099
|
+
// src/webhook/graph.ts
|
|
2100
|
+
var graphWebhookHttp = {
|
|
2101
|
+
methods: ["POST"],
|
|
2102
|
+
sync: {
|
|
2103
|
+
mode: "match",
|
|
2104
|
+
match: [{ hasQueryParam: "validationToken" }]
|
|
2105
|
+
}
|
|
2106
|
+
};
|
|
2107
|
+
var getGraphWebhookValidationResponse = (request) => {
|
|
2108
|
+
let validationToken = new URL(request.url).searchParams.get("validationToken");
|
|
2109
|
+
if (validationToken === null) return null;
|
|
2110
|
+
return {
|
|
2111
|
+
status: 200,
|
|
2112
|
+
headers: { "content-type": "text/plain" },
|
|
2113
|
+
body: validationToken
|
|
2114
|
+
};
|
|
2115
|
+
};
|
|
2116
|
+
|
|
2117
|
+
// src/webhook/meta.ts
|
|
2118
|
+
var metaWebhookHttp = {
|
|
2119
|
+
methods: ["GET", "POST"],
|
|
2120
|
+
sync: {
|
|
2121
|
+
mode: "match",
|
|
2122
|
+
match: [{ method: "GET", hasQueryParam: "hub.mode" }]
|
|
2123
|
+
}
|
|
2124
|
+
};
|
|
2125
|
+
var getMetaWebhookVerificationResponse = (request, expectedVerifyToken) => {
|
|
2126
|
+
if (request.method !== "GET") return null;
|
|
2127
|
+
let url = new URL(request.url);
|
|
2128
|
+
let mode = url.searchParams.get("hub.mode");
|
|
2129
|
+
let verifyToken = url.searchParams.get("hub.verify_token");
|
|
2130
|
+
let challenge = url.searchParams.get("hub.challenge");
|
|
2131
|
+
if (mode !== "subscribe" || challenge === null) {
|
|
2132
|
+
return {
|
|
2133
|
+
status: 400,
|
|
2134
|
+
headers: { "content-type": "text/plain" },
|
|
2135
|
+
body: "invalid webhook verification request"
|
|
2136
|
+
};
|
|
2137
|
+
}
|
|
2138
|
+
if (expectedVerifyToken !== void 0 && verifyToken !== expectedVerifyToken) {
|
|
2139
|
+
return {
|
|
2140
|
+
status: 403,
|
|
2141
|
+
headers: { "content-type": "text/plain" },
|
|
2142
|
+
body: "invalid verify token"
|
|
2143
|
+
};
|
|
2144
|
+
}
|
|
2145
|
+
return {
|
|
2146
|
+
status: 200,
|
|
2147
|
+
headers: { "content-type": "text/plain" },
|
|
2148
|
+
body: challenge
|
|
2149
|
+
};
|
|
2150
|
+
};
|
|
1788
2151
|
export {
|
|
1789
2152
|
Slate,
|
|
1790
2153
|
SlateAction,
|
|
@@ -1802,24 +2165,47 @@ export {
|
|
|
1802
2165
|
anyOf,
|
|
1803
2166
|
auth,
|
|
1804
2167
|
axios,
|
|
2168
|
+
buildApiServiceError,
|
|
2169
|
+
collectApiErrorDetails,
|
|
1805
2170
|
config,
|
|
2171
|
+
createApiServiceError,
|
|
2172
|
+
createAuthenticatedAxios,
|
|
1806
2173
|
createAxios,
|
|
1807
2174
|
createBase64Attachment,
|
|
2175
|
+
createHmacSignature,
|
|
1808
2176
|
createSlateError,
|
|
1809
2177
|
createTextAttachment,
|
|
1810
2178
|
createUrlAttachment,
|
|
2179
|
+
extractApiErrorMessage,
|
|
2180
|
+
getApiErrorResponse,
|
|
2181
|
+
getApiErrorStatus,
|
|
2182
|
+
getBase64ByteLength,
|
|
1811
2183
|
getCurrentContext,
|
|
2184
|
+
getGraphWebhookValidationResponse,
|
|
2185
|
+
getMetaWebhookVerificationResponse,
|
|
2186
|
+
getOAuthExpiresAtFromExpiresIn,
|
|
2187
|
+
getResponseHeaderValue,
|
|
1812
2188
|
getServiceErrorData,
|
|
2189
|
+
graphWebhookHttp,
|
|
1813
2190
|
inferSlateErrorFromAxios,
|
|
2191
|
+
isApiErrorRecord,
|
|
1814
2192
|
isAxiosErrorLike,
|
|
1815
2193
|
isServiceErrorData,
|
|
1816
2194
|
mapServiceErrorCode,
|
|
1817
2195
|
mapServiceErrorToSlateErrorInput,
|
|
1818
2196
|
mergeScopes,
|
|
2197
|
+
metaWebhookHttp,
|
|
2198
|
+
normalizeOAuthTokenResponse,
|
|
2199
|
+
pickDefined,
|
|
2200
|
+
requestAxios,
|
|
2201
|
+
requestAxiosData,
|
|
1819
2202
|
runWithContext,
|
|
1820
2203
|
scopeClause,
|
|
2204
|
+
setIfDefined,
|
|
1821
2205
|
spec,
|
|
2206
|
+
statusLabelForApiError,
|
|
1822
2207
|
tool,
|
|
1823
2208
|
trigger,
|
|
1824
|
-
validateScopes
|
|
2209
|
+
validateScopes,
|
|
2210
|
+
verifyHmacSignature
|
|
1825
2211
|
};
|
package/package.json
CHANGED
package/src/action/action.ts
CHANGED
|
@@ -27,6 +27,7 @@ export interface SlateActionParameters {
|
|
|
27
27
|
};
|
|
28
28
|
metadata?: Record<string, any>;
|
|
29
29
|
scopes?: SlateActionScopes;
|
|
30
|
+
authMethods?: string[];
|
|
30
31
|
docs?: SlateActionDocsReference[];
|
|
31
32
|
}
|
|
32
33
|
|
|
@@ -61,15 +62,58 @@ export type SlateTriggerPollingHandler<
|
|
|
61
62
|
updatedState?: any;
|
|
62
63
|
}>;
|
|
63
64
|
|
|
65
|
+
export interface SlateWebhookHttpResponseInit {
|
|
66
|
+
status?: number;
|
|
67
|
+
headers?: Record<string, string>;
|
|
68
|
+
body?: string | Uint8Array | null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type SlateWebhookHttpMethod =
|
|
72
|
+
| 'GET'
|
|
73
|
+
| 'POST'
|
|
74
|
+
| 'PUT'
|
|
75
|
+
| 'PATCH'
|
|
76
|
+
| 'DELETE'
|
|
77
|
+
| 'HEAD'
|
|
78
|
+
| 'OPTIONS';
|
|
79
|
+
|
|
80
|
+
export interface SlateWebhookRequestMatcher {
|
|
81
|
+
method?: string;
|
|
82
|
+
hasQueryParam?: string;
|
|
83
|
+
hasHeader?: string;
|
|
84
|
+
jsonBodyField?: {
|
|
85
|
+
path: string;
|
|
86
|
+
equals?: string;
|
|
87
|
+
};
|
|
88
|
+
formBodyField?: {
|
|
89
|
+
path: string;
|
|
90
|
+
equals?: string;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface SlateWebhookHttpOptions {
|
|
95
|
+
methods?: SlateWebhookHttpMethod[];
|
|
96
|
+
sync?: {
|
|
97
|
+
mode: 'never' | 'match' | 'always';
|
|
98
|
+
match?: SlateWebhookRequestMatcher[];
|
|
99
|
+
timeoutMs?: number;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
64
103
|
export type SlateTriggerWebhookRequestHandler<
|
|
65
104
|
ConfigType extends {},
|
|
66
105
|
AuthType extends {},
|
|
67
106
|
InputType extends {}
|
|
68
107
|
> = (
|
|
69
|
-
context: SlateContext<
|
|
108
|
+
context: SlateContext<
|
|
109
|
+
ConfigType,
|
|
110
|
+
AuthType,
|
|
111
|
+
{ request: Request; state: any | null; registrationDetails: any | null }
|
|
112
|
+
>
|
|
70
113
|
) => Promise<{
|
|
71
114
|
inputs: InputType[];
|
|
72
115
|
updatedState?: any;
|
|
116
|
+
response?: Response | SlateWebhookHttpResponseInit;
|
|
73
117
|
}>;
|
|
74
118
|
|
|
75
119
|
export type SlateTriggerWebhookAutoRegistrationHandler<
|
|
@@ -116,6 +160,7 @@ export interface SlateActionParametersTrigger<
|
|
|
116
160
|
polling?: SlatePollingOptions;
|
|
117
161
|
handleEvent: SlateTriggerMappingHandler<ConfigType, AuthType, InputType, OutputType>;
|
|
118
162
|
handleRequest?: SlateTriggerWebhookRequestHandler<ConfigType, AuthType, InputType>;
|
|
163
|
+
http?: SlateWebhookHttpOptions;
|
|
119
164
|
pollEvents?: SlateTriggerPollingHandler<ConfigType, AuthType, InputType>;
|
|
120
165
|
autoRegisterWebhook?: SlateTriggerWebhookAutoRegistrationHandler<ConfigType, AuthType>;
|
|
121
166
|
autoUnregisterWebhook?: SlateTriggerWebhookAutoUnregistrationHandler<ConfigType, AuthType>;
|
|
@@ -206,6 +251,10 @@ export abstract class SlateAction<
|
|
|
206
251
|
return this._params.scopes;
|
|
207
252
|
}
|
|
208
253
|
|
|
254
|
+
get authMethods() {
|
|
255
|
+
return this._params.authMethods;
|
|
256
|
+
}
|
|
257
|
+
|
|
209
258
|
get docs() {
|
|
210
259
|
return this._params.docs;
|
|
211
260
|
}
|
package/src/action/builder.ts
CHANGED
|
@@ -15,7 +15,8 @@ import type {
|
|
|
15
15
|
SlateTriggerPollingHandler,
|
|
16
16
|
SlateTriggerWebhookAutoRegistrationHandler,
|
|
17
17
|
SlateTriggerWebhookAutoUnregistrationHandler,
|
|
18
|
-
SlateTriggerWebhookRequestHandler
|
|
18
|
+
SlateTriggerWebhookRequestHandler,
|
|
19
|
+
SlateWebhookHttpOptions
|
|
19
20
|
} from './action';
|
|
20
21
|
import { validateScopes } from './scopes';
|
|
21
22
|
|
|
@@ -32,6 +33,7 @@ export class SlateActionBuilder<
|
|
|
32
33
|
#inputSchema: z.ZodType<InputType> | null = null;
|
|
33
34
|
#outputSchema: z.ZodType<OutputType> | null = null;
|
|
34
35
|
#scopes: SlateActionScopes | undefined;
|
|
36
|
+
#authMethods: string[] | undefined;
|
|
35
37
|
|
|
36
38
|
#toolParams: SlateActionParametersTool<ConfigType, AuthType, InputType, OutputType> | null =
|
|
37
39
|
null;
|
|
@@ -76,6 +78,24 @@ export class SlateActionBuilder<
|
|
|
76
78
|
return this;
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
authMethods(
|
|
82
|
+
authMethods: string[]
|
|
83
|
+
): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result> {
|
|
84
|
+
this.#authMethods = this.validateAuthMethods(authMethods);
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private validateAuthMethods(authMethods: string[] | undefined) {
|
|
89
|
+
if (!authMethods) return undefined;
|
|
90
|
+
|
|
91
|
+
let normalized = [...new Set(authMethods.map(authMethod => authMethod.trim()))];
|
|
92
|
+
if (normalized.some(authMethod => !authMethod)) {
|
|
93
|
+
throw new SlateDeclarationError('Auth method IDs must be non-empty strings');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return normalized;
|
|
97
|
+
}
|
|
98
|
+
|
|
79
99
|
handleInvocation(
|
|
80
100
|
handler: SlateToolInvocationHandler<ConfigType, AuthType, InputType, OutputType>
|
|
81
101
|
): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result> {
|
|
@@ -96,6 +116,7 @@ export class SlateActionBuilder<
|
|
|
96
116
|
handleRequest: SlateTriggerWebhookRequestHandler<ConfigType, AuthType, InputType>;
|
|
97
117
|
autoRegisterWebhook?: SlateTriggerWebhookAutoRegistrationHandler<ConfigType, AuthType>;
|
|
98
118
|
autoUnregisterWebhook?: SlateTriggerWebhookAutoUnregistrationHandler<ConfigType, AuthType>;
|
|
119
|
+
http?: SlateWebhookHttpOptions;
|
|
99
120
|
}): SlateActionBuilder<Type, ConfigType, AuthType, InputType, OutputType, Result> {
|
|
100
121
|
if (this.type !== 'trigger') {
|
|
101
122
|
throw new SlateDeclarationError('handleEvent can only be set for trigger actions');
|
|
@@ -107,7 +128,8 @@ export class SlateActionBuilder<
|
|
|
107
128
|
handleEvent: props.handleEvent,
|
|
108
129
|
handleRequest: props.handleRequest,
|
|
109
130
|
autoRegisterWebhook: props.autoRegisterWebhook,
|
|
110
|
-
autoUnregisterWebhook: props.autoUnregisterWebhook
|
|
131
|
+
autoUnregisterWebhook: props.autoUnregisterWebhook,
|
|
132
|
+
http: props.http
|
|
111
133
|
};
|
|
112
134
|
|
|
113
135
|
return this;
|
|
@@ -138,6 +160,7 @@ export class SlateActionBuilder<
|
|
|
138
160
|
if (scopes) {
|
|
139
161
|
validateScopes(scopes);
|
|
140
162
|
}
|
|
163
|
+
let authMethods = this.validateAuthMethods(this.#authMethods ?? this.params.authMethods);
|
|
141
164
|
|
|
142
165
|
if (!this.#inputSchema) {
|
|
143
166
|
throw new SlateDeclarationError('Input schema is not defined');
|
|
@@ -155,6 +178,7 @@ export class SlateActionBuilder<
|
|
|
155
178
|
return this.factory({
|
|
156
179
|
...this.params,
|
|
157
180
|
scopes,
|
|
181
|
+
authMethods,
|
|
158
182
|
configSchema: this.#configSchema,
|
|
159
183
|
authSchema: this.#authSchema,
|
|
160
184
|
inputSchema: this.#inputSchema,
|