@slates/provider-handler 1.0.0-rc.4 → 1.0.0-rc.41

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 (74) hide show
  1. package/dist/index.cjs +1702 -2
  2. package/dist/index.d.cts +8 -0
  3. package/dist/index.d.ts +6 -3
  4. package/dist/index.module.js +1685 -2
  5. package/package.json +12 -10
  6. package/src/adminSetup.test.ts +189 -0
  7. package/src/attachments.test.ts +171 -0
  8. package/src/exposure.test.ts +216 -0
  9. package/src/index.ts +1301 -134
  10. package/src/pQueue.test.ts +18 -0
  11. package/src/pQueue.ts +18 -0
  12. package/src/spec.test.ts +232 -0
  13. package/src/spec.ts +219 -19
  14. package/src/validation.ts +1 -1
  15. package/src/webhook.test.ts +65 -0
  16. package/src/webhook.ts +69 -0
  17. package/src/webhookProcess.test.ts +99 -0
  18. package/dist/action/action.d.ts +0 -90
  19. package/dist/action/action.d.ts.map +0 -1
  20. package/dist/action/builder.d.ts +0 -27
  21. package/dist/action/builder.d.ts.map +0 -1
  22. package/dist/action/index.d.ts +0 -5
  23. package/dist/action/index.d.ts.map +0 -1
  24. package/dist/action/tool.d.ts +0 -11
  25. package/dist/action/tool.d.ts.map +0 -1
  26. package/dist/action/trigger.d.ts +0 -14
  27. package/dist/action/trigger.d.ts.map +0 -1
  28. package/dist/auth/auth.d.ts +0 -26
  29. package/dist/auth/auth.d.ts.map +0 -1
  30. package/dist/auth/index.d.ts +0 -3
  31. package/dist/auth/index.d.ts.map +0 -1
  32. package/dist/auth/types.d.ts +0 -148
  33. package/dist/auth/types.d.ts.map +0 -1
  34. package/dist/axios/index.d.ts +0 -4
  35. package/dist/axios/index.d.ts.map +0 -1
  36. package/dist/config/config.d.ts +0 -22
  37. package/dist/config/config.d.ts.map +0 -1
  38. package/dist/config/index.d.ts +0 -2
  39. package/dist/config/index.d.ts.map +0 -1
  40. package/dist/context/context.d.ts +0 -20
  41. package/dist/context/context.d.ts.map +0 -1
  42. package/dist/context/hook.d.ts +0 -4
  43. package/dist/context/hook.d.ts.map +0 -1
  44. package/dist/context/index.d.ts +0 -2
  45. package/dist/context/index.d.ts.map +0 -1
  46. package/dist/error/base.d.ts +0 -5
  47. package/dist/error/base.d.ts.map +0 -1
  48. package/dist/error/declaration.d.ts +0 -6
  49. package/dist/error/declaration.d.ts.map +0 -1
  50. package/dist/error/index.d.ts +0 -3
  51. package/dist/error/index.d.ts.map +0 -1
  52. package/dist/index.cjs.map +0 -1
  53. package/dist/index.d.ts.map +0 -1
  54. package/dist/index.modern.js +0 -2
  55. package/dist/index.modern.js.map +0 -1
  56. package/dist/index.module.js.map +0 -1
  57. package/dist/index.umd.js +0 -2
  58. package/dist/index.umd.js.map +0 -1
  59. package/dist/spec.d.ts +0 -14
  60. package/dist/spec.d.ts.map +0 -1
  61. package/dist/specification/index.d.ts +0 -3
  62. package/dist/specification/index.d.ts.map +0 -1
  63. package/dist/specification/slate.d.ts +0 -15
  64. package/dist/specification/slate.d.ts.map +0 -1
  65. package/dist/specification/specification.d.ts +0 -30
  66. package/dist/specification/specification.d.ts.map +0 -1
  67. package/dist/specification/zero.d.ts +0 -13
  68. package/dist/specification/zero.d.ts.map +0 -1
  69. package/dist/state.d.ts +0 -8
  70. package/dist/state.d.ts.map +0 -1
  71. package/dist/tokens.d.ts +0 -34
  72. package/dist/tokens.d.ts.map +0 -1
  73. package/dist/validation.d.ts +0 -5
  74. package/dist/validation.d.ts.map +0 -1
@@ -1,2 +1,1685 @@
1
- import{ServiceError as t,validationError as e,badRequestError as n,notFoundError as r,preconditionFailedError as o}from"@lowerdeck/error";import{createSlatesProviderProtoHandler as i}from"@slates/proto";import{SlateDefaultPollingIntervalSeconds as a,SlateLogger as u,SlateContext as s}from"@slates/provider";import c from"zod";function l(t,e){if(!{}.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var h=0;function p(t){return"__private_"+h+++"_"+t}function f(){return f=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)({}).hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t},f.apply(null,arguments)}function d(t){var e=function(t){if("object"!=typeof t||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var n=e.call(t,"string");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==typeof e?e:e+""}var m=function(n,r,o,i){var a=n.safeParse(r);if(!a.success)throw new t(function(t,n,r){return e({message:n,entity:t,errors:r.issues.map(function(t){return f({},t,{path:t.path.map(function(t){return String(t)})})})})}(o,i,a.error));return a.data},v=function(t){return t.toJSONSchema({unrepresentable:"any",override:function(t){var e=t.zodSchema._zod.def;"date"===e.type&&(t.jsonSchema.type="string",t.jsonSchema.format="date-time"),"bigint"===e.type&&(t.jsonSchema.type="number")}})},g=function(e,r){var o=e.spec.auth.authStack.find(function(t){return t.key==r});if(!o)throw new t(n({message:"Invalid authentication method ID: "+r}));return o},P=function(t,e){var n;return{id:e.key,name:e.name,type:e.type,scopes:"scopes"in e?e.scopes.map(function(t){return{id:t.scope,title:t.title,description:t.description}}):void 0,inputSchema:v(null!=(n=e.inputSchema)?n:c.object({})),outputSchema:v(t.spec.auth.outputSchema),capabilities:{getDefaultInput:{enabled:!(!("getDefaultInput"in e)||!e.getDefaultInput)},handleTokenRefresh:{enabled:!(!("handleTokenRefresh"in e)||!e.handleTokenRefresh)},handleChangedInput:{enabled:!!e.onInputChanged},getProfile:{enabled:!!e.getProfile}}}},y=function(e,n){var o=e.actions.find(function(t){return t.key==n});if(!o)throw new t(r("action",n));return o},w=function(e,r,o){var i=y(e,o);if(i.type!=r)throw new t(n({message:"Action with ID "+o+" is not of type "+r}));return i},I=function(t,e){var n;return f({},{id:e.key,name:e.name,description:e.description,instructions:e.instructions,constraints:e.constraints,tags:e.tags,metadata:e.metadata,inputSchema:v(e.inputSchema),outputSchema:v(e.outputSchema)},"tool"==e.type?{type:"action.tool",capabilities:{}}:{type:"action.trigger",capabilities:{},invocation:"polling"==e.source?{type:"polling",intervalSeconds:null!=(n=e.polling.intervalInSeconds)?n:a}:{type:"webhook",autoRegistration:!!e.autoRegisterWebhook,autoUnregistration:!!e.autoUnregisterWebhook}})},b=/*#__PURE__*/p("value"),k=/*#__PURE__*/function(){function t(t){Object.defineProperty(this,b,{writable:!0,value:void 0}),l(this,b)[b]=t}var e,n,r=t.prototype;return r.get=function(){return l(this,b)[b]},r.set=function(t){l(this,b)[b]=t},e=t,(n=[{key:"value",get:function(){return l(this,b)[b]}}])&&function(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,d(r.key),r)}}(e.prototype,n),Object.defineProperty(e,"prototype",{writable:!1}),e}(),S=function(e,r){return i(function(i){try{var a=new k(null),c=new k(null),l=new k(null),h=new k(null),p=new k(null),d=new u(r),b=function(){var e=a.get(),n=c.get();if(!e||!n)throw new t(o({message:"Connection context has not been initialized"}));return{protocol:e,participants:n}},S=function(){var n=b(),r=h.get(),i=p.get(),a=l.get();if(!r||!i||!a&&e.spec.auth.authStack.length>0)throw new t(o({message:"Session context has not been initialized"}));return f({},n,{config:r.value,session:i,auth:a})};return i.onNotification("slates/hello",function(t){var e=t.params;try{return a.set(e.protocol),Promise.resolve()}catch(t){return Promise.reject(t)}}),i.onNotification("slates/participant.set",function(e){var n=e.params;try{if(!a.get())throw new t(o({message:"Connection protocol has not been initialized"}));return c.set(n.participants),Promise.resolve()}catch(t){return Promise.reject(t)}}),i.onNotification("slates/auth.set",function(t){var n=t.params;try{b(),g(e,n.authenticationMethodId);var r=m(e.spec.authSchema,n.output,"auth","Invalid authentication output for method ID: "+n.authenticationMethodId);return l.set({authenticationMethodId:n.authenticationMethodId,output:r}),Promise.resolve()}catch(t){return Promise.reject(t)}}),i.onNotification("slates/config.set",function(t){var n=t.params;try{b();var r=m(e.spec.configSchema,n.config,"config","Invalid configuration");return h.set({value:r}),Promise.resolve()}catch(t){return Promise.reject(t)}}),i.onNotification("slates/session.start",function(t){var e=t.params;try{return b(),p.set({id:e.sessionId,state:e.state}),Promise.resolve()}catch(t){return Promise.reject(t)}}),i.onRequest("slates/config.changed",function(t){var n=t.params;try{b();var r=m(e.spec.config.configSchema,n.newConfig,"config","Invalid configuration"),o=e.spec.config.handlers.configChanged;return o?Promise.resolve(o({previousConfig:n.previousConfig,newConfig:r})).then(function(t){var e;return{success:!0,config:null!=(e=null==t?void 0:t.config)?e:r}}):Promise.resolve({success:!0,config:r})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/config.get_default",function(t){try{b();var n=e.spec.config.handlers.getDefaultConfig;return n?Promise.resolve(n()).then(function(t){return{config:t}}):Promise.resolve({config:null})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/config.schema.get",function(t){try{return b(),Promise.resolve({schema:v(e.spec.configSchema)})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/provider.identify",function(t){try{return b(),Promise.resolve({protocol:"slates@2026-01-01",provider:{type:"provider",id:e.spec.key,name:e.spec.name,description:e.spec.description,metadata:e.spec.parameters.metadata}})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/auth.methods.list",function(t){try{return b(),Promise.resolve({authenticationMethods:e.spec.auth.authStack.map(function(t){return P(e,t)})})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/auth.method.get",function(t){var n=t.params;try{b();var r=g(e,n.authenticationMethodId);return Promise.resolve({authenticationMethod:P(e,r)})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/auth.input.get_default",function(t){var n=t.params;try{b();var r=g(e,n.authenticationMethodId);return r.getDefaultInput?Promise.resolve(r.getDefaultInput()).then(function(t){return{input:t}}):Promise.resolve({input:null})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/auth.input.changed",function(t){var n=t.params;try{b();var r=g(e,n.authenticationMethodId);return r.onInputChanged?Promise.resolve(r.onInputChanged({previousInput:n.previousInput,newInput:n.newInput})).then(function(t){var e;return{success:!0,input:null!=(e=null==t?void 0:t.input)?e:n.newInput}}):Promise.resolve({success:!0,input:n.newInput})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/auth.output.get",function(t){var n=t.params;try{var r,o=function(t){return r?t:{output:a}};b();var i=g(e,n.authenticationMethodId),a=n.input;i.inputSchema&&(a=m(i.inputSchema,a,"auth","Invalid authentication input for method ID: "+n.authenticationMethodId));var u=function(){if("getOutput"in i)return Promise.resolve(i.getOutput({input:a})).then(function(t){return r=1,{output:t.output}})}();return Promise.resolve(u&&u.then?u.then(o):o(u))}catch(t){return Promise.reject(t)}}),i.onRequest("slates/auth.authorization_callback.handle",function(n){var r=n.params;try{var i,a=function(e){if(i)return e;throw new t(o({message:"Authentication method does not support authorization callback handling: "+r.authenticationMethodId}))};b();var u=g(e,r.authenticationMethodId),s=function(){if("handleCallback"in u)return Promise.resolve(u.handleCallback({code:r.code,state:r.state,redirectUri:r.redirectUri,input:r.input,clientId:r.clientId,clientSecret:r.clientSecret,scopes:r.scopes})).then(function(t){return i=1,{output:t.output,input:t.input}})}();return Promise.resolve(s&&s.then?s.then(a):a(s))}catch(t){return Promise.reject(t)}}),i.onRequest("slates/auth.authorization_url.get",function(n){var r=n.params;try{var i,a=function(e){if(i)return e;throw new t(o({message:"Authentication method does not support authorization URL retrieval: "+r.authenticationMethodId}))};b();var u=g(e,r.authenticationMethodId),s=function(){if("getAuthorizationUrl"in u)return Promise.resolve(u.getAuthorizationUrl({redirectUri:r.redirectUri,state:r.state,input:r.input,clientId:r.clientId,clientSecret:r.clientSecret,scopes:r.scopes})).then(function(t){return i=1,{authorizationUrl:t.url,input:t.input}})}();return Promise.resolve(s&&s.then?s.then(a):a(s))}catch(t){return Promise.reject(t)}}),i.onRequest("slates/auth.profile.get",function(n){var r=n.params;try{var i,a=function(e){if(i)return e;throw new t(o({message:"Authentication method does not support profile retrieval: "+r.authenticationMethodId}))};b();var u=g(e,r.authenticationMethodId),s=function(){if(u.getProfile)return Promise.resolve(u.getProfile({output:r.output,input:r.input,scopes:r.scopes})).then(function(t){return i=1,{profile:t.profile}})}();return Promise.resolve(s&&s.then?s.then(a):a(s))}catch(t){return Promise.reject(t)}}),i.onRequest("slates/auth.token_refresh.handle",function(n){var r=n.params;try{var i,a=function(e){if(i)return e;throw new t(o({message:"Authentication method does not support token refresh handling: "+r.authenticationMethodId}))};b();var u=g(e,r.authenticationMethodId),s=function(){if("handleTokenRefresh"in u&&u.handleTokenRefresh)return Promise.resolve(u.handleTokenRefresh({output:r.output,input:r.input,clientId:r.clientId,clientSecret:r.clientSecret,scopes:r.scopes})).then(function(t){return i=1,{output:t.output,input:t.input}})}();return Promise.resolve(s&&s.then?s.then(a):a(s))}catch(t){return Promise.reject(t)}}),i.onRequest("slates/actions.list",function(t){try{return b(),Promise.resolve({actions:e.actions.map(function(t){return I(0,t)})})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/action.get",function(t){var n=t.params;try{b();var r=y(e,n.actionId);return Promise.resolve({action:I(0,r)})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/action.tool.invoke",function(t){var n=t.params;try{var r,o=S(),i=w(e,"tool",n.actionId),a=m(i.inputSchema,n.input,"input","Invalid input for tool ID: "+n.actionId);return Promise.resolve(i.handleInvocation(new s(o.config,a,null==(r=o.auth)?void 0:r.output,e.spec,d))).then(function(t){return{output:t.output,message:t.message}})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/action.trigger.map_event",function(t){var n=t.params;try{var r,o=S(),i=w(e,"trigger",n.actionId),a=m(i.inputSchema,n.input,"input","Invalid event for trigger ID: "+n.actionId);return Promise.resolve(i.handleEvent(new s(o.config,a,null==(r=o.auth)?void 0:r.output,e.spec,d))).then(function(t){return{id:t.id,type:t.type,output:t.output}})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/action.trigger.poll_events",function(r){var o=r.params;try{var i,a=S(),u=w(e,"trigger",o.actionId);if(!u.pollEvents)throw new t(n({message:"Trigger action does not support polling: "+o.actionId}));return Promise.resolve(u.pollEvents(new s(a.config,{state:o.state},null==(i=a.auth)?void 0:i.output,e.spec,d))).then(function(t){return{inputs:t.inputs,updatedState:t.updatedState}})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/action.trigger.webhook_handle",function(r){var o=r.params;try{var i,a=S(),u=w(e,"trigger",o.actionId);if(!u.handleRequest)throw new t(n({message:"Trigger action does not support webhook requests: "+o.actionId}));var c=new Request(o.url,{method:o.method,headers:o.headers,body:o.body?Uint8Array.from(atob(o.body.content),function(t){return t.charCodeAt(0)}):null});return Promise.resolve(u.handleRequest(new s(a.config,{request:c,state:o.state},null==(i=a.auth)?void 0:i.output,e.spec,d))).then(function(t){return{inputs:t.inputs,updatedState:t.updatedState}})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/action.trigger.webhook_register",function(r){var o=r.params;try{var i,a=S(),u=w(e,"trigger",o.actionId);if(!u.autoRegisterWebhook)throw new t(n({message:"Trigger action does not support webhook auto-registration: "+o.actionId}));return Promise.resolve(u.autoRegisterWebhook(new s(a.config,{webhookBaseUrl:o.webhookBaseUrl},null==(i=a.auth)?void 0:i.output,e.spec,d))).then(function(t){return{registrationDetails:t.registrationDetails,state:t.state}})}catch(t){return Promise.reject(t)}}),i.onRequest("slates/action.trigger.webhook_unregister",function(r){var o=r.params;try{var i,a=S(),u=w(e,"trigger",o.actionId);if(!u.autoUnregisterWebhook)throw new t(n({message:"Trigger action does not support webhook auto-unregistration: "+o.actionId}));return Promise.resolve(u.autoUnregisterWebhook(new s(a.config,{webhookBaseUrl:o.webhookBaseUrl,registrationDetails:o.registrationDetails,state:o.state},null==(i=a.auth)?void 0:i.output,e.spec,d))).then(function(){return{}})}catch(t){return Promise.reject(t)}}),Promise.resolve()}catch(t){return Promise.reject(t)}})};export{S as createProviderHandler};
2
- //# sourceMappingURL=index.module.js.map
1
+ // src/index.ts
2
+ import {
3
+ badRequestError as badRequestError3,
4
+ notFoundError as notFoundError2,
5
+ preconditionFailedError,
6
+ ServiceError as ServiceError4
7
+ } from "@lowerdeck/error";
8
+ import {
9
+ createSlatesProviderProtoHandler,
10
+ SLATES_PROTOCOL_VERSION
11
+ } from "@slates/proto";
12
+ import {
13
+ AuthConfigSecretRedactor,
14
+ redactUrlAttachmentSecrets,
15
+ runWithContext,
16
+ SlateContext,
17
+ SlateLogger,
18
+ SlatePublicContext,
19
+ uploadAttachmentDirect
20
+ } from "@slates/provider";
21
+
22
+ // src/pQueue.ts
23
+ import PQueueImport from "p-queue";
24
+ var resolveDefaultExport = (value) => {
25
+ let current = value;
26
+ for (let i = 0; i < 4; i++) {
27
+ if (typeof current === "function") return current;
28
+ if (current && typeof current === "object" && "default" in current) {
29
+ current = current.default;
30
+ continue;
31
+ }
32
+ break;
33
+ }
34
+ throw new TypeError("Module export is not a constructor");
35
+ };
36
+ var PQueue = resolveDefaultExport(PQueueImport);
37
+
38
+ // src/spec.ts
39
+ import { badRequestError, notFoundError, ServiceError as ServiceError2 } from "@lowerdeck/error";
40
+ import {
41
+ SlateDefaultPollingIntervalSeconds
42
+ } from "@slates/provider";
43
+ import z from "zod";
44
+
45
+ // src/validation.ts
46
+ import { ServiceError, validationError } from "@lowerdeck/error";
47
+ var zodToValidationError = (entity, message, e) => {
48
+ return validationError({
49
+ message,
50
+ entity,
51
+ errors: e.issues.map((i) => ({
52
+ ...i,
53
+ path: i.path.map((p) => String(p))
54
+ }))
55
+ });
56
+ };
57
+ var validate = (schema, data, entity, message) => {
58
+ let result = schema.safeParse(data);
59
+ if (!result.success) {
60
+ throw new ServiceError(zodToValidationError(entity, message, result.error));
61
+ }
62
+ return result.data;
63
+ };
64
+ var toJsonSchema = (schema) => schema.toJSONSchema({
65
+ unrepresentable: "any",
66
+ override: (ctx) => {
67
+ let def = ctx.zodSchema._zod.def;
68
+ if (def.type === "date") {
69
+ ctx.jsonSchema.type = "string";
70
+ ctx.jsonSchema.format = "date-time";
71
+ }
72
+ if (def.type === "bigint") {
73
+ ctx.jsonSchema.type = "number";
74
+ }
75
+ }
76
+ });
77
+
78
+ // src/spec.ts
79
+ var getAuthMethod = (slate, authenticationMethodId) => {
80
+ let authMethod = slate.spec.auth.authStack.find((m) => m.key === authenticationMethodId);
81
+ if (!authMethod) {
82
+ throw new ServiceError2(
83
+ badRequestError({
84
+ message: `Invalid authentication method ID: ${authenticationMethodId}`
85
+ })
86
+ );
87
+ }
88
+ return authMethod;
89
+ };
90
+ var mapAuthMethod = (slate, m) => ({
91
+ id: m.key,
92
+ name: m.name,
93
+ type: m.type,
94
+ scopes: "scopes" in m ? m.scopes.map((s) => ({
95
+ id: s.scope,
96
+ title: s.title,
97
+ description: s.description
98
+ })) : void 0,
99
+ adapters: "adapters" in m ? m.adapters : void 0,
100
+ ..."syncTokensAcrossConnections" in m && m.syncTokensAcrossConnections ? { syncTokensAcrossConnections: true } : {},
101
+ inputSchema: toJsonSchema(m.inputSchema ?? z.object({})),
102
+ outputSchema: toJsonSchema(slate.spec.auth.outputSchema),
103
+ capabilities: {
104
+ getDefaultInput: { enabled: !!("getDefaultInput" in m && m.getDefaultInput) },
105
+ handleTokenRefresh: {
106
+ enabled: !!("handleTokenRefresh" in m && m.handleTokenRefresh)
107
+ },
108
+ handleChangedInput: {
109
+ enabled: !!m.onInputChanged
110
+ },
111
+ getProfile: { enabled: !!m.getProfile },
112
+ ..."adminSetup" in m && m.adminSetup ? { adminSetup: { enabled: true } } : {}
113
+ },
114
+ docs: m.docs ?? []
115
+ });
116
+ var getAction = (slate, actionId) => {
117
+ let action = (slate.actions ?? []).find((m) => m.key === actionId);
118
+ if (!action) {
119
+ throw new ServiceError2(notFoundError(`action`, actionId));
120
+ }
121
+ return action;
122
+ };
123
+ var getAdapter = (slate, adapterId) => {
124
+ let adapter = (slate.adapters ?? []).find((m) => m.id === adapterId);
125
+ if (!adapter) {
126
+ throw new ServiceError2(notFoundError(`adapter`, adapterId));
127
+ }
128
+ return adapter;
129
+ };
130
+ var mapAdapter = (adapter) => ({
131
+ id: adapter.id,
132
+ name: adapter.name,
133
+ capabilities: adapter.capabilities ?? []
134
+ });
135
+ var getActionWithType = (slate, type, actionId) => {
136
+ let action = getAction(slate, actionId);
137
+ if (action.type !== type) {
138
+ throw new ServiceError2(
139
+ badRequestError({
140
+ message: `Action with ID ${actionId} is not of type ${type}`
141
+ })
142
+ );
143
+ }
144
+ return action;
145
+ };
146
+ var mapAction = (slate, a) => {
147
+ let base = {
148
+ id: a.key,
149
+ name: a.name,
150
+ description: a.description,
151
+ instructions: a.instructions,
152
+ constraints: a.constraints,
153
+ tags: a.tags,
154
+ metadata: a.metadata,
155
+ scopes: a.scopes,
156
+ authMethods: a.authMethods,
157
+ docs: a.docs ?? [],
158
+ ...a.adapter ? { adapter: a.adapter } : {},
159
+ inputSchema: toJsonSchema(a.inputSchema),
160
+ outputSchema: toJsonSchema(a.outputSchema)
161
+ };
162
+ if (a.type === "tool") {
163
+ let toolCategoryIds = slate.getToolCategoryKeys?.(a.key) ?? [];
164
+ return {
165
+ ...base,
166
+ type: "action.tool",
167
+ capabilities: {},
168
+ isPublic: a.isPublic,
169
+ ...toolCategoryIds.length ? { toolCategoryIds } : {}
170
+ };
171
+ }
172
+ return {
173
+ ...base,
174
+ type: "action.trigger",
175
+ capabilities: {},
176
+ triggerGroupId: a.triggerGroup.key
177
+ };
178
+ };
179
+ var isMappableTrigger = (action) => action.type !== "trigger" || !!action.triggerGroup;
180
+ var getMappableAction = (slate, actionId) => {
181
+ let action = getAction(slate, actionId);
182
+ if (!isMappableTrigger(action)) {
183
+ throw new ServiceError2(notFoundError(`action`, actionId));
184
+ }
185
+ return action;
186
+ };
187
+ var getExposedActions = (slate, includeAdapterActions) => (slate.actions ?? []).filter(
188
+ (action) => isMappableTrigger(action) && (includeAdapterActions || !action.adapter)
189
+ );
190
+ var getExposedAction = (slate, actionId, includeAdapterActions) => {
191
+ let action = getMappableAction(slate, actionId);
192
+ if (action.adapter && !includeAdapterActions) {
193
+ throw new ServiceError2(notFoundError(`action`, actionId));
194
+ }
195
+ return action;
196
+ };
197
+ var getTriggerGroup = (slate, triggerGroupId) => {
198
+ let group = (slate.triggerGroups ?? []).find((g) => g.key === triggerGroupId);
199
+ if (!group) {
200
+ throw new ServiceError2(notFoundError(`trigger_group`, triggerGroupId));
201
+ }
202
+ return group;
203
+ };
204
+ var getTriggersForGroup = (slate, triggerGroupId) => (slate.actions ?? []).filter(
205
+ (action) => action.type === "trigger" && action.triggerGroup?.key === triggerGroupId
206
+ );
207
+ var getExposedTriggerGroups = (slate, includeAdapterActions) => {
208
+ let triggerGroupIds = new Set(
209
+ getExposedActions(slate, includeAdapterActions).flatMap(
210
+ (action) => action.type === "trigger" && action.triggerGroup ? [action.triggerGroup.key] : []
211
+ )
212
+ );
213
+ return (slate.triggerGroups ?? []).filter((group) => triggerGroupIds.has(group.key));
214
+ };
215
+ var evaluateTriggerMatches = (slate, triggerGroupId, payload) => getTriggersForGroup(slate, triggerGroupId).filter((trigger) => trigger.matches(payload)).map((trigger) => trigger.key);
216
+ var getWebhookAutoRegistration = (group) => {
217
+ if (group.source !== "webhook" || !group.webhook?.autoRegistration) {
218
+ throw new ServiceError2(
219
+ badRequestError({
220
+ message: `Trigger group does not support webhook auto-registration: ${group.key}`
221
+ })
222
+ );
223
+ }
224
+ return group.webhook.autoRegistration;
225
+ };
226
+ var getWebhookManualRegistration = (group) => {
227
+ if (group.source !== "webhook" || !group.webhook?.manualRegistration) {
228
+ throw new ServiceError2(
229
+ badRequestError({
230
+ message: `Trigger group does not support manual webhook registration: ${group.key}`
231
+ })
232
+ );
233
+ }
234
+ return group.webhook.manualRegistration;
235
+ };
236
+ var mapToolCategory = (category) => ({
237
+ id: category.key,
238
+ name: category.name,
239
+ description: category.description,
240
+ imageUrl: category.imageUrl
241
+ });
242
+ var getExposedToolCategories = (slate, includeAdapterActions) => {
243
+ let exposedCategoryKeys = new Set(
244
+ getExposedActions(slate, includeAdapterActions).filter((action) => action.type === "tool").flatMap((action) => slate.getToolCategoryKeys?.(action.key) ?? [])
245
+ );
246
+ return (slate.toolCategories ?? []).filter(
247
+ (category) => exposedCategoryKeys.has(category.key)
248
+ );
249
+ };
250
+ var mapTriggerGroup = (group) => ({
251
+ id: group.key,
252
+ name: group.name,
253
+ description: group.description,
254
+ metadata: group.metadata,
255
+ invocation: group.source === "polling" ? {
256
+ type: "polling",
257
+ intervalSeconds: group.polling?.intervalSeconds ?? SlateDefaultPollingIntervalSeconds
258
+ } : group.source === "gateway" ? { type: "gateway" } : {
259
+ type: "webhook",
260
+ registration: group.webhook?.manualRegistration ? {
261
+ mode: "manual",
262
+ userConfigSchema: toJsonSchema(
263
+ group.webhook.manualRegistration.userConfigSchema
264
+ ),
265
+ fullConfigSchema: toJsonSchema(
266
+ group.webhook.manualRegistration.fullConfigSchema
267
+ )
268
+ } : { mode: "auto" }
269
+ }
270
+ });
271
+
272
+ // src/state.ts
273
+ var State = class {
274
+ #value;
275
+ get value() {
276
+ return this.#value;
277
+ }
278
+ get() {
279
+ return this.#value;
280
+ }
281
+ set(value) {
282
+ this.#value = value;
283
+ }
284
+ constructor(initialValue) {
285
+ this.#value = initialValue;
286
+ }
287
+ };
288
+
289
+ // src/webhook.ts
290
+ import { badRequestError as badRequestError2, ServiceError as ServiceError3 } from "@lowerdeck/error";
291
+ var SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES = 1024 * 1024;
292
+ var serializeBody = (body) => {
293
+ if (body === null) return null;
294
+ if (body.byteLength > SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES) {
295
+ throw new ServiceError3(
296
+ badRequestError2({
297
+ message: `Webhook response body exceeds the ${SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES}-byte limit`
298
+ })
299
+ );
300
+ }
301
+ return {
302
+ encoding: "base64",
303
+ content: Buffer.from(body).toString("base64")
304
+ };
305
+ };
306
+ var headersToObject = (headers) => {
307
+ let result = {};
308
+ headers.forEach((value, key) => {
309
+ result[key] = value;
310
+ });
311
+ return result;
312
+ };
313
+ var validateStatus = (status) => {
314
+ if (!Number.isInteger(status) || status < 100 || status > 599) {
315
+ throw new ServiceError3(
316
+ badRequestError2({
317
+ message: "Webhook response status must be an integer between 100 and 599"
318
+ })
319
+ );
320
+ }
321
+ };
322
+ var serializeWebhookHttpResponse = async (response) => {
323
+ if (response instanceof Response) {
324
+ validateStatus(response.status);
325
+ return {
326
+ status: response.status,
327
+ headers: headersToObject(response.headers),
328
+ body: serializeBody(
329
+ response.body === null ? null : new Uint8Array(await response.arrayBuffer())
330
+ )
331
+ };
332
+ }
333
+ let status = response.status ?? 200;
334
+ validateStatus(status);
335
+ let body = typeof response.body === "string" ? new TextEncoder().encode(response.body) : response.body ?? null;
336
+ return {
337
+ status,
338
+ headers: response.headers ?? {},
339
+ body: serializeBody(body)
340
+ };
341
+ };
342
+
343
+ // src/index.ts
344
+ var DEFAULT_MAX_ATTACHMENT_SIZE_BYTES = 1e8;
345
+ var routeAttachmentsThroughDirectUpload = async (attachments, live) => {
346
+ if (!attachments || attachments.length === 0 || !live) return attachments;
347
+ let contentEntries = attachments.map((attachment, index) => ({ attachment, index })).filter((entry) => entry.attachment.content.type === "content");
348
+ if (contentEntries.length === 0) return attachments;
349
+ let queue = new PQueue({ concurrency: 10 });
350
+ let replacements = /* @__PURE__ */ new Map();
351
+ await Promise.all(
352
+ contentEntries.map(
353
+ (entry) => queue.add(async () => {
354
+ try {
355
+ let body = entry.attachment.content.type === "content" ? entry.attachment.content.encoding === "base64" ? Buffer.from(entry.attachment.content.content, "base64") : Buffer.from(entry.attachment.content.content, "utf-8") : Buffer.alloc(0);
356
+ replacements.set(
357
+ entry.index,
358
+ await uploadAttachmentDirect({
359
+ live,
360
+ mimeType: entry.attachment.mimeType,
361
+ body
362
+ })
363
+ );
364
+ } catch {
365
+ replacements.set(entry.index, null);
366
+ }
367
+ })
368
+ )
369
+ );
370
+ return attachments.map(
371
+ (attachment, index) => replacements.has(index) ? replacements.get(index) : attachment
372
+ ).filter((a) => a != null);
373
+ };
374
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
375
+ var getObjectKeyCount = (value) => isRecord(value) ? Object.keys(value).length : void 0;
376
+ var DOWNLOAD_ATTACHMENT_URL_KEYS = /* @__PURE__ */ new Set([
377
+ "downloadUrl",
378
+ "fileUrl",
379
+ "temporaryDownloadUrl",
380
+ "webContentLink"
381
+ ]);
382
+ var isAttachmentUrl = (value) => /^[a-z][a-z0-9+.-]*:\/\//i.test(value);
383
+ var collectOutputUrlAttachments = (value, seen = /* @__PURE__ */ new Set()) => {
384
+ if (Array.isArray(value)) {
385
+ return value.flatMap((item) => collectOutputUrlAttachments(item, seen));
386
+ }
387
+ if (!isRecord(value)) {
388
+ return [];
389
+ }
390
+ let attachments = [];
391
+ for (let [key, nestedValue] of Object.entries(value)) {
392
+ if (DOWNLOAD_ATTACHMENT_URL_KEYS.has(key) && typeof nestedValue === "string" && nestedValue.length > 0 && isAttachmentUrl(nestedValue) && !seen.has(nestedValue)) {
393
+ seen.add(nestedValue);
394
+ attachments.push({
395
+ content: {
396
+ type: "url",
397
+ url: nestedValue
398
+ }
399
+ });
400
+ continue;
401
+ }
402
+ attachments.push(...collectOutputUrlAttachments(nestedValue, seen));
403
+ }
404
+ return attachments;
405
+ };
406
+ var mergeAttachments = (explicitAttachments, output) => {
407
+ let attachments = [...explicitAttachments ?? []];
408
+ let seen = new Set(attachments.map((attachment) => JSON.stringify(attachment)));
409
+ for (let attachment of collectOutputUrlAttachments(output)) {
410
+ let key = JSON.stringify(attachment);
411
+ if (seen.has(key)) continue;
412
+ seen.add(key);
413
+ attachments.push(attachment);
414
+ }
415
+ return attachments.length > 0 ? attachments : void 0;
416
+ };
417
+ var toErrorMetadata = (error) => {
418
+ if (error instanceof Error) {
419
+ return {
420
+ errorName: error.name,
421
+ errorMessage: error.message,
422
+ errorStack: error.stack
423
+ };
424
+ }
425
+ return {
426
+ errorValue: String(error)
427
+ };
428
+ };
429
+ var formatEntityLabel = (name, key) => `"${name}" (${key})`;
430
+ var resolveTraceMessage = (message, result) => typeof message === "function" ? message(result) : message;
431
+ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandler(async (manager) => {
432
+ let protocol = new State(null);
433
+ let participants = new State(null);
434
+ let auth = new State(null);
435
+ let config = new State(null);
436
+ let session = new State(null);
437
+ let hubCapabilities = new State(null);
438
+ let liveInvocation = new State(
439
+ null
440
+ );
441
+ let getLiveInvocation = () => {
442
+ let directUpload = hubCapabilities.get()?.attachments?.directUpload;
443
+ let live = liveInvocation.get();
444
+ if (!directUpload?.enabled || !live) return null;
445
+ return {
446
+ ...live,
447
+ maxAttachmentSizeBytes: directUpload.maxAttachmentSizeBytes ?? DEFAULT_MAX_ATTACHMENT_SIZE_BYTES
448
+ };
449
+ };
450
+ let supportsTriggerGroups = () => !!hubCapabilities.get()?.triggers;
451
+ let supportsAdapters = () => !!hubCapabilities.get()?.adapters;
452
+ let logger = new SlateLogger(listeners);
453
+ let providerTrace = {
454
+ providerId: slate.spec.key,
455
+ providerName: slate.spec.name
456
+ };
457
+ let traceProviderCall = async (trace, handler) => {
458
+ let startedAt = Date.now();
459
+ logger.info({
460
+ ...providerTrace,
461
+ ...trace.metadata,
462
+ component: trace.component,
463
+ functionName: trace.functionName,
464
+ phase: "start",
465
+ message: trace.message
466
+ });
467
+ try {
468
+ let result = await handler();
469
+ let successMessage = resolveTraceMessage(trace.successMessage, result);
470
+ logger.info({
471
+ ...providerTrace,
472
+ ...trace.metadata,
473
+ ...trace.onSuccess?.(result) ?? {},
474
+ component: trace.component,
475
+ functionName: trace.functionName,
476
+ phase: "success",
477
+ durationMs: Date.now() - startedAt,
478
+ message: successMessage
479
+ });
480
+ return result;
481
+ } catch (error) {
482
+ logger.error({
483
+ ...providerTrace,
484
+ ...trace.metadata,
485
+ ...toErrorMetadata(error),
486
+ component: trace.component,
487
+ functionName: trace.functionName,
488
+ phase: "error",
489
+ durationMs: Date.now() - startedAt,
490
+ message: trace.errorMessage ?? `${typeof trace.successMessage === "string" ? trace.successMessage : trace.message} failed`
491
+ });
492
+ throw error;
493
+ }
494
+ };
495
+ let getContextBasic = () => {
496
+ let currentProtocol = protocol.get();
497
+ let currentParticipants = participants.get();
498
+ if (!currentProtocol || !currentParticipants) {
499
+ throw new ServiceError4(
500
+ preconditionFailedError({
501
+ message: "Connection context has not been initialized"
502
+ })
503
+ );
504
+ }
505
+ return {
506
+ protocol: currentProtocol,
507
+ participants: currentParticipants
508
+ };
509
+ };
510
+ let getContextFull = () => {
511
+ let basic = getContextBasic();
512
+ let currentConfig = config.get();
513
+ let currentSession = session.get();
514
+ let currentAuth = auth.get();
515
+ if (!currentConfig || !currentSession || !currentAuth && slate.spec.auth.authStack.length > 0) {
516
+ throw new ServiceError4(
517
+ preconditionFailedError({
518
+ message: "Session context has not been initialized"
519
+ })
520
+ );
521
+ }
522
+ return {
523
+ ...basic,
524
+ config: currentConfig.value,
525
+ session: currentSession,
526
+ auth: currentAuth
527
+ };
528
+ };
529
+ let getAuthConfig = () => config.get()?.value ?? {};
530
+ let getEmptyContext = () => new SlateContext({}, {}, {}, slate.spec, logger);
531
+ let getAuthContext = () => new SlateContext(getAuthConfig(), {}, {}, slate.spec, logger);
532
+ let withRequestTraces = (context, result) => {
533
+ let requestTraces = context.getHttpTraces();
534
+ return requestTraces.length > 0 ? { ...result, requestTraces } : result;
535
+ };
536
+ let buildAuthorizationUrlContext = (params) => ({
537
+ redirectUri: params.redirectUri,
538
+ state: params.state,
539
+ input: params.input,
540
+ clientId: params.clientId,
541
+ clientSecret: params.clientSecret,
542
+ scopes: params.scopes,
543
+ config: getAuthConfig()
544
+ });
545
+ let buildCallbackContext = (params) => ({
546
+ state: params.state,
547
+ redirectUri: params.redirectUri,
548
+ input: params.input,
549
+ clientId: params.clientId,
550
+ clientSecret: params.clientSecret,
551
+ scopes: params.scopes,
552
+ callbackParams: params.callbackParams || {},
553
+ callbackState: params.callbackState || {},
554
+ config: getAuthConfig()
555
+ });
556
+ let getTracedAuthorizationUrl = async (params, authenticationMethodName, trace, getAuthorizationUrl) => {
557
+ let context = getEmptyContext();
558
+ let urlRes = await traceProviderCall(
559
+ {
560
+ component: "auth",
561
+ functionName: trace.functionName,
562
+ message: trace.message,
563
+ successMessage: trace.successMessage,
564
+ metadata: {
565
+ authenticationMethodId: params.authenticationMethodId,
566
+ authenticationMethodName,
567
+ scopeCount: params.scopes.length,
568
+ inputKeyCount: getObjectKeyCount(params.input),
569
+ ...trace.metadata
570
+ },
571
+ onSuccess: (result) => ({
572
+ returnedInput: !!result.input,
573
+ hasCallbackState: !!result.callbackState
574
+ })
575
+ },
576
+ () => runWithContext(
577
+ context,
578
+ () => getAuthorizationUrl(buildAuthorizationUrlContext(params))
579
+ )
580
+ );
581
+ return withRequestTraces(context, {
582
+ authorizationUrl: urlRes.url,
583
+ input: urlRes.input,
584
+ callbackState: urlRes.callbackState
585
+ });
586
+ };
587
+ manager.onNotification("slates/hello", async ({ params }) => {
588
+ protocol.set(params.protocol);
589
+ });
590
+ manager.onNotification("slates/participant.set", async ({ params }) => {
591
+ if (!protocol.get()) {
592
+ throw new ServiceError4(
593
+ preconditionFailedError({ message: "Connection protocol has not been initialized" })
594
+ );
595
+ }
596
+ participants.set(params.participants);
597
+ });
598
+ manager.onNotification("slates/auth.set", async ({ params }) => {
599
+ getContextBasic();
600
+ getAuthMethod(slate, params.authenticationMethodId);
601
+ let valRes = validate(
602
+ slate.spec.authSchema,
603
+ params.output,
604
+ "auth",
605
+ `Invalid authentication output for method ID: ${params.authenticationMethodId}`
606
+ );
607
+ auth.set({
608
+ authenticationMethodId: params.authenticationMethodId,
609
+ output: valRes
610
+ });
611
+ });
612
+ manager.onNotification("slates/config.set", async ({ params }) => {
613
+ getContextBasic();
614
+ let value = validate(
615
+ slate.spec.configSchema,
616
+ params.config,
617
+ "config",
618
+ "Invalid configuration"
619
+ );
620
+ config.set({ value });
621
+ });
622
+ manager.onNotification("slates/session.start", async ({ params }) => {
623
+ getContextBasic();
624
+ session.set({
625
+ id: params.sessionId,
626
+ state: params.state
627
+ });
628
+ });
629
+ manager.onNotification("slates/hub.capabilities.set", async ({ params }) => {
630
+ hubCapabilities.set(params.capabilities);
631
+ });
632
+ manager.onNotification("slates/hub.live_invocation.set", async ({ params }) => {
633
+ liveInvocation.set({
634
+ token: params.token,
635
+ baseUrl: params.baseUrl
636
+ });
637
+ });
638
+ manager.onRequest("slates/provider.capabilities.get", async () => ({
639
+ capabilities: {
640
+ hub: {
641
+ capabilitiesNotification: true,
642
+ liveInvocation: true
643
+ },
644
+ provider: {
645
+ triggerGroups: (slate.triggerGroups?.length ?? 0) > 0 && (slate.actions ?? []).every(isMappableTrigger),
646
+ toolCategories: (slate.toolCategories?.length ?? 0) > 0
647
+ }
648
+ }
649
+ }));
650
+ manager.onRequest("slates/config.changed", async ({ params }) => {
651
+ getContextBasic();
652
+ let newConfig = validate(
653
+ slate.spec.config.configSchema,
654
+ params.newConfig,
655
+ "config",
656
+ "Invalid configuration"
657
+ );
658
+ let configChanged = slate.spec.config.handlers.configChanged;
659
+ if (!configChanged) {
660
+ return { success: true, config: newConfig };
661
+ }
662
+ let context = getEmptyContext();
663
+ let updatedConfig = await traceProviderCall(
664
+ {
665
+ component: "config",
666
+ functionName: "configChanged",
667
+ message: "Running config change handler",
668
+ successMessage: "Config change handler completed",
669
+ metadata: {
670
+ hasPreviousConfig: params.previousConfig !== null,
671
+ newConfigKeyCount: getObjectKeyCount(newConfig)
672
+ },
673
+ onSuccess: (result) => ({
674
+ returnedConfig: !!result?.config
675
+ })
676
+ },
677
+ () => runWithContext(
678
+ context,
679
+ async () => configChanged({
680
+ previousConfig: params.previousConfig,
681
+ newConfig
682
+ })
683
+ )
684
+ );
685
+ return withRequestTraces(context, {
686
+ success: true,
687
+ config: updatedConfig?.config ?? newConfig
688
+ });
689
+ });
690
+ manager.onRequest("slates/config.get_default", async () => {
691
+ getContextBasic();
692
+ let getDefaultConfig = slate.spec.config.handlers.getDefaultConfig;
693
+ if (!getDefaultConfig) {
694
+ return { config: null };
695
+ }
696
+ let context = getEmptyContext();
697
+ let defaultConfig = await traceProviderCall(
698
+ {
699
+ component: "config",
700
+ functionName: "getDefaultConfig",
701
+ message: "Getting default config",
702
+ successMessage: "Default config retrieved",
703
+ onSuccess: (result) => ({
704
+ configKeyCount: getObjectKeyCount(result)
705
+ })
706
+ },
707
+ () => runWithContext(context, async () => getDefaultConfig())
708
+ );
709
+ return withRequestTraces(context, {
710
+ config: defaultConfig ?? null
711
+ });
712
+ });
713
+ manager.onRequest("slates/config.schema.get", async () => {
714
+ getContextBasic();
715
+ return {
716
+ schema: toJsonSchema(slate.spec.configSchema),
717
+ docs: slate.spec.config.docsReferences ?? []
718
+ };
719
+ });
720
+ manager.onRequest("slates/provider.identify", async () => {
721
+ getContextBasic();
722
+ return {
723
+ protocol: SLATES_PROTOCOL_VERSION,
724
+ provider: {
725
+ type: "provider",
726
+ id: slate.spec.key,
727
+ name: slate.spec.name,
728
+ description: slate.spec.description,
729
+ metadata: slate.spec.parameters.metadata
730
+ },
731
+ docs: slate.spec.docs ?? []
732
+ };
733
+ });
734
+ manager.onRequest("slates/auth.methods.list", async () => {
735
+ getContextBasic();
736
+ return {
737
+ authenticationMethods: slate.spec.auth.authStack.map((m) => mapAuthMethod(slate, m))
738
+ };
739
+ });
740
+ manager.onRequest("slates/auth.method.get", async ({ params }) => {
741
+ getContextBasic();
742
+ let authMethod = getAuthMethod(slate, params.authenticationMethodId);
743
+ return {
744
+ authenticationMethod: mapAuthMethod(slate, authMethod)
745
+ };
746
+ });
747
+ manager.onRequest("slates/auth.input.get_default", async ({ params }) => {
748
+ getContextBasic();
749
+ let authMethod = getAuthMethod(slate, params.authenticationMethodId);
750
+ if (!authMethod.getDefaultInput) {
751
+ return { input: null };
752
+ }
753
+ let context = getEmptyContext();
754
+ let input = await traceProviderCall(
755
+ {
756
+ component: "auth",
757
+ functionName: "getDefaultInput",
758
+ message: "Getting default authentication input",
759
+ successMessage: "Default authentication input retrieved",
760
+ metadata: {
761
+ authenticationMethodId: params.authenticationMethodId,
762
+ authenticationMethodName: authMethod.name
763
+ },
764
+ onSuccess: (result) => ({
765
+ inputKeyCount: getObjectKeyCount(result)
766
+ })
767
+ },
768
+ () => runWithContext(context, () => authMethod.getDefaultInput())
769
+ );
770
+ return withRequestTraces(context, { input });
771
+ });
772
+ manager.onRequest("slates/auth.input.changed", async ({ params }) => {
773
+ getContextBasic();
774
+ let authMethod = getAuthMethod(slate, params.authenticationMethodId);
775
+ if (!authMethod.onInputChanged) {
776
+ return { success: true, input: params.newInput };
777
+ }
778
+ let context = getEmptyContext();
779
+ let updatedInput = await traceProviderCall(
780
+ {
781
+ component: "auth",
782
+ functionName: "onInputChanged",
783
+ message: "Running authentication input change handler",
784
+ successMessage: "Authentication input change handler completed",
785
+ metadata: {
786
+ authenticationMethodId: params.authenticationMethodId,
787
+ authenticationMethodName: authMethod.name,
788
+ hasPreviousInput: params.previousInput !== null,
789
+ newInputKeyCount: getObjectKeyCount(params.newInput)
790
+ },
791
+ onSuccess: (result) => ({
792
+ returnedInput: !!result?.input
793
+ })
794
+ },
795
+ () => runWithContext(
796
+ context,
797
+ () => authMethod.onInputChanged({
798
+ previousInput: params.previousInput,
799
+ newInput: params.newInput
800
+ })
801
+ )
802
+ );
803
+ return withRequestTraces(context, {
804
+ success: true,
805
+ input: updatedInput?.input ?? params.newInput
806
+ });
807
+ });
808
+ manager.onRequest("slates/auth.output.get", async ({ params }) => {
809
+ getContextBasic();
810
+ let authMethod = getAuthMethod(slate, params.authenticationMethodId);
811
+ let input = params.input;
812
+ if (authMethod.inputSchema) {
813
+ input = validate(
814
+ authMethod.inputSchema,
815
+ input,
816
+ "auth",
817
+ `Invalid authentication input for method ID: ${params.authenticationMethodId}`
818
+ );
819
+ }
820
+ if ("getOutput" in authMethod) {
821
+ let context = getAuthContext();
822
+ let outputRes = await traceProviderCall(
823
+ {
824
+ component: "auth",
825
+ functionName: "getOutput",
826
+ message: "Getting authentication output",
827
+ successMessage: "Authentication output retrieved",
828
+ metadata: {
829
+ authenticationMethodId: params.authenticationMethodId,
830
+ authenticationMethodName: authMethod.name,
831
+ inputKeyCount: getObjectKeyCount(input)
832
+ },
833
+ onSuccess: (result) => ({
834
+ outputKeyCount: getObjectKeyCount(result.output),
835
+ scopeCount: result.scopes?.length ?? 0
836
+ })
837
+ },
838
+ () => runWithContext(
839
+ context,
840
+ () => authMethod.getOutput({
841
+ input,
842
+ config: getAuthConfig()
843
+ })
844
+ )
845
+ );
846
+ return withRequestTraces(context, {
847
+ output: outputRes.output,
848
+ scopes: outputRes.scopes
849
+ });
850
+ }
851
+ return { output: input };
852
+ });
853
+ manager.onRequest("slates/auth.authorization_callback.handle", async ({ params }) => {
854
+ getContextBasic();
855
+ let authMethod = getAuthMethod(slate, params.authenticationMethodId);
856
+ if ("handleCallback" in authMethod) {
857
+ let context = getEmptyContext();
858
+ let callbackRes = await traceProviderCall(
859
+ {
860
+ component: "auth",
861
+ functionName: "handleCallback",
862
+ message: "Handling authentication callback",
863
+ successMessage: "Authentication callback handled",
864
+ metadata: {
865
+ authenticationMethodId: params.authenticationMethodId,
866
+ authenticationMethodName: authMethod.name,
867
+ scopeCount: params.scopes.length,
868
+ hasCallbackState: !!params.callbackState
869
+ },
870
+ onSuccess: (result) => ({
871
+ outputKeyCount: getObjectKeyCount(result.output),
872
+ returnedInput: !!result.input,
873
+ returnedScopeCount: result.scopes?.length
874
+ })
875
+ },
876
+ () => runWithContext(
877
+ context,
878
+ () => authMethod.handleCallback({ ...buildCallbackContext(params), code: params.code })
879
+ )
880
+ );
881
+ return withRequestTraces(context, {
882
+ output: callbackRes.output,
883
+ input: callbackRes.input,
884
+ scopes: callbackRes.scopes
885
+ });
886
+ }
887
+ throw new ServiceError4(
888
+ preconditionFailedError({
889
+ message: `Authentication method does not support authorization callback handling: ${params.authenticationMethodId}`
890
+ })
891
+ );
892
+ });
893
+ manager.onRequest("slates/auth.authorization_url.get", async ({ params }) => {
894
+ getContextBasic();
895
+ let authMethod = getAuthMethod(slate, params.authenticationMethodId);
896
+ if ("getAuthorizationUrl" in authMethod) {
897
+ return getTracedAuthorizationUrl(
898
+ params,
899
+ authMethod.name,
900
+ {
901
+ functionName: "getAuthorizationUrl",
902
+ message: "Getting authentication authorization URL",
903
+ successMessage: "Authentication authorization URL retrieved"
904
+ },
905
+ (ctx) => authMethod.getAuthorizationUrl(ctx)
906
+ );
907
+ }
908
+ throw new ServiceError4(
909
+ preconditionFailedError({
910
+ message: `Authentication method does not support authorization URL retrieval: ${params.authenticationMethodId}`
911
+ })
912
+ );
913
+ });
914
+ manager.onRequest("slates/auth.admin_authorization_url.get", async ({ params }) => {
915
+ getContextBasic();
916
+ let authMethod = getAuthMethod(slate, params.authenticationMethodId);
917
+ if (authMethod.type === "auth.oauth" && authMethod.adminSetup) {
918
+ let { adminSetup } = authMethod;
919
+ return getTracedAuthorizationUrl(
920
+ params,
921
+ authMethod.name,
922
+ {
923
+ functionName: "adminSetup.getAuthorizationUrl",
924
+ message: "Getting admin setup authorization URL",
925
+ successMessage: "Admin setup authorization URL retrieved",
926
+ metadata: { usesDefault: !adminSetup.getAuthorizationUrl }
927
+ },
928
+ (ctx) => adminSetup.getAuthorizationUrl ? adminSetup.getAuthorizationUrl(ctx) : authMethod.getAuthorizationUrl(ctx)
929
+ );
930
+ }
931
+ throw new ServiceError4(
932
+ preconditionFailedError({
933
+ message: `Authentication method does not support admin setup: ${params.authenticationMethodId}`
934
+ })
935
+ );
936
+ });
937
+ manager.onRequest("slates/auth.admin_callback.handle", async ({ params }) => {
938
+ getContextBasic();
939
+ let authMethod = getAuthMethod(slate, params.authenticationMethodId);
940
+ if (authMethod.type === "auth.oauth" && authMethod.adminSetup) {
941
+ let { adminSetup } = authMethod;
942
+ let ctx = { ...buildCallbackContext(params), code: params.code };
943
+ let handleCallback = async () => {
944
+ if (adminSetup.handleCallback) return adminSetup.handleCallback(ctx);
945
+ let code = ctx.code;
946
+ if (!code) {
947
+ throw new ServiceError4(
948
+ badRequestError3({
949
+ message: `Admin setup callback did not include an authorization code: ${params.authenticationMethodId}`
950
+ })
951
+ );
952
+ }
953
+ await authMethod.handleCallback({ ...ctx, code });
954
+ return {};
955
+ };
956
+ let context = getEmptyContext();
957
+ let callbackRes = await traceProviderCall(
958
+ {
959
+ component: "auth",
960
+ functionName: "adminSetup.handleCallback",
961
+ message: "Handling admin setup callback",
962
+ successMessage: "Admin setup callback handled",
963
+ metadata: {
964
+ authenticationMethodId: params.authenticationMethodId,
965
+ authenticationMethodName: authMethod.name,
966
+ scopeCount: params.scopes.length,
967
+ hasCode: !!params.code,
968
+ hasCallbackState: !!params.callbackState,
969
+ usesDefault: !adminSetup.handleCallback
970
+ },
971
+ onSuccess: (result) => ({
972
+ returnedInstructions: !!result.instructions
973
+ })
974
+ },
975
+ () => runWithContext(context, handleCallback)
976
+ );
977
+ return withRequestTraces(context, {
978
+ instructions: callbackRes.instructions
979
+ });
980
+ }
981
+ throw new ServiceError4(
982
+ preconditionFailedError({
983
+ message: `Authentication method does not support admin setup: ${params.authenticationMethodId}`
984
+ })
985
+ );
986
+ });
987
+ manager.onRequest("slates/auth.profile.get", async ({ params }) => {
988
+ getContextBasic();
989
+ let authMethod = getAuthMethod(slate, params.authenticationMethodId);
990
+ if (authMethod.getProfile) {
991
+ let context = getAuthContext();
992
+ let profileRes = await traceProviderCall(
993
+ {
994
+ component: "auth",
995
+ functionName: "getProfile",
996
+ message: "Getting authentication profile",
997
+ successMessage: "Authentication profile retrieved",
998
+ metadata: {
999
+ authenticationMethodId: params.authenticationMethodId,
1000
+ authenticationMethodName: authMethod.name,
1001
+ scopeCount: params.scopes.length,
1002
+ inputKeyCount: getObjectKeyCount(params.input),
1003
+ outputKeyCount: getObjectKeyCount(params.output)
1004
+ },
1005
+ onSuccess: (result) => ({
1006
+ profileKeyCount: getObjectKeyCount(result.profile)
1007
+ })
1008
+ },
1009
+ () => runWithContext(context, () => {
1010
+ if (authMethod.type === "auth.oauth") {
1011
+ return authMethod.getProfile({
1012
+ output: params.output,
1013
+ input: params.input,
1014
+ scopes: params.scopes,
1015
+ config: getAuthConfig()
1016
+ });
1017
+ }
1018
+ return authMethod.getProfile({
1019
+ output: params.output,
1020
+ input: params.input,
1021
+ scopes: params.scopes,
1022
+ config: getAuthConfig()
1023
+ });
1024
+ })
1025
+ );
1026
+ return withRequestTraces(context, {
1027
+ profile: profileRes.profile
1028
+ });
1029
+ }
1030
+ throw new ServiceError4(
1031
+ preconditionFailedError({
1032
+ message: `Authentication method does not support profile retrieval: ${params.authenticationMethodId}`
1033
+ })
1034
+ );
1035
+ });
1036
+ manager.onRequest("slates/auth.token_refresh.handle", async ({ params }) => {
1037
+ getContextBasic();
1038
+ let authMethod = getAuthMethod(slate, params.authenticationMethodId);
1039
+ if ("handleTokenRefresh" in authMethod && authMethod.handleTokenRefresh) {
1040
+ let context = getAuthContext();
1041
+ let refreshRes = await traceProviderCall(
1042
+ {
1043
+ component: "auth",
1044
+ functionName: "handleTokenRefresh",
1045
+ message: "Refreshing authentication token",
1046
+ successMessage: "Authentication token refreshed",
1047
+ metadata: {
1048
+ authenticationMethodId: params.authenticationMethodId,
1049
+ authenticationMethodName: authMethod.name,
1050
+ scopeCount: params.scopes.length,
1051
+ inputKeyCount: getObjectKeyCount(params.input),
1052
+ outputKeyCount: getObjectKeyCount(params.output)
1053
+ },
1054
+ onSuccess: (result) => ({
1055
+ refreshedOutputKeyCount: getObjectKeyCount(result.output),
1056
+ returnedInput: !!result.input
1057
+ })
1058
+ },
1059
+ () => runWithContext(context, () => {
1060
+ if (authMethod.type === "auth.oauth") {
1061
+ return authMethod.handleTokenRefresh({
1062
+ output: params.output,
1063
+ input: params.input,
1064
+ clientId: params.clientId,
1065
+ clientSecret: params.clientSecret,
1066
+ scopes: params.scopes,
1067
+ config: getAuthConfig()
1068
+ });
1069
+ }
1070
+ return authMethod.handleTokenRefresh({
1071
+ output: params.output,
1072
+ input: params.input,
1073
+ clientId: params.clientId,
1074
+ clientSecret: params.clientSecret,
1075
+ scopes: params.scopes,
1076
+ config: getAuthConfig()
1077
+ });
1078
+ })
1079
+ );
1080
+ return withRequestTraces(context, {
1081
+ output: refreshRes.output,
1082
+ input: refreshRes.input
1083
+ });
1084
+ }
1085
+ throw new ServiceError4(
1086
+ preconditionFailedError({
1087
+ message: `Authentication method does not support token refresh handling: ${params.authenticationMethodId}`
1088
+ })
1089
+ );
1090
+ });
1091
+ manager.onRequest("slates/actions.list", async ({ params }) => {
1092
+ getContextBasic();
1093
+ let actions = getExposedActions(
1094
+ slate,
1095
+ !!params.includeAdapterActions && supportsAdapters()
1096
+ );
1097
+ if (!supportsTriggerGroups()) {
1098
+ actions = actions.filter((action) => action.type !== "trigger");
1099
+ }
1100
+ return {
1101
+ actions: actions.map((a) => mapAction(slate, a))
1102
+ };
1103
+ });
1104
+ manager.onRequest("slates/adapters.list", async () => {
1105
+ getContextBasic();
1106
+ return {
1107
+ adapters: supportsAdapters() ? (slate.adapters ?? []).map(mapAdapter) : []
1108
+ };
1109
+ });
1110
+ manager.onRequest("slates/adapter.get", async ({ params }) => {
1111
+ getContextBasic();
1112
+ if (!supportsAdapters()) {
1113
+ throw new ServiceError4(notFoundError2(`adapter`, params.adapterId));
1114
+ }
1115
+ let adapter = getAdapter(slate, params.adapterId);
1116
+ return {
1117
+ adapter: mapAdapter(adapter)
1118
+ };
1119
+ });
1120
+ manager.onRequest("slates/action.get", async ({ params }) => {
1121
+ getContextBasic();
1122
+ let action = getExposedAction(slate, params.actionId, supportsAdapters());
1123
+ return {
1124
+ action: mapAction(slate, action)
1125
+ };
1126
+ });
1127
+ manager.onRequest("slates/trigger_groups.list", async () => {
1128
+ getContextBasic();
1129
+ return {
1130
+ triggerGroups: getExposedTriggerGroups(slate, supportsAdapters()).map(mapTriggerGroup)
1131
+ };
1132
+ });
1133
+ manager.onRequest("slates/tool_categories.list", async () => {
1134
+ getContextBasic();
1135
+ return {
1136
+ toolCategories: getExposedToolCategories(slate, supportsAdapters()).map(
1137
+ mapToolCategory
1138
+ )
1139
+ };
1140
+ });
1141
+ manager.onRequest("slates/trigger_group.get", async ({ params }) => {
1142
+ getContextBasic();
1143
+ let triggerGroup = getTriggerGroup(slate, params.triggerGroupId);
1144
+ return {
1145
+ triggerGroup: mapTriggerGroup(triggerGroup)
1146
+ };
1147
+ });
1148
+ manager.onRequest("slates/action.tool.invoke", async ({ params }) => {
1149
+ let action = getActionWithType(slate, "tool", params.actionId);
1150
+ let input = validate(
1151
+ action.inputSchema,
1152
+ params.input,
1153
+ "input",
1154
+ `Invalid input for tool ID: ${params.actionId}`
1155
+ );
1156
+ let invoke = async (context) => {
1157
+ let res = await traceProviderCall(
1158
+ {
1159
+ component: "action",
1160
+ functionName: "handleInvocation",
1161
+ message: `Starting tool ${formatEntityLabel(action.name, action.key)}`,
1162
+ successMessage: `Completed tool ${formatEntityLabel(action.name, action.key)}`,
1163
+ errorMessage: `Tool ${formatEntityLabel(action.name, action.key)} failed`,
1164
+ metadata: {
1165
+ actionId: action.key,
1166
+ actionName: action.name,
1167
+ actionType: action.type,
1168
+ isPublic: action.isPublic,
1169
+ inputKeyCount: getObjectKeyCount(input)
1170
+ },
1171
+ onSuccess: (result) => ({
1172
+ hasMessage: !!result.message,
1173
+ actionResultMessage: result.message,
1174
+ outputKeyCount: getObjectKeyCount(result.output),
1175
+ attachmentCount: result.attachments?.length
1176
+ })
1177
+ },
1178
+ () => runWithContext(context, () => action.handleInvocation(context))
1179
+ );
1180
+ let contextAttachments = await context._finalizeAttachments();
1181
+ let merged = mergeAttachments(
1182
+ [...res.attachments ?? [], ...contextAttachments],
1183
+ res.output
1184
+ );
1185
+ let redacted = redactUrlAttachmentSecrets(
1186
+ merged,
1187
+ context._getAuthConfigForRedaction()
1188
+ );
1189
+ let finalAttachments = await routeAttachmentsThroughDirectUpload(
1190
+ redacted,
1191
+ getLiveInvocation()
1192
+ );
1193
+ return withRequestTraces(context, {
1194
+ output: res.output,
1195
+ message: res.message,
1196
+ attachments: finalAttachments
1197
+ });
1198
+ };
1199
+ if (action.isPublic) {
1200
+ getContextBasic();
1201
+ return invoke(new SlatePublicContext(input, slate.spec, logger, getLiveInvocation()));
1202
+ }
1203
+ let ctx = getContextFull();
1204
+ return invoke(
1205
+ new SlateContext(
1206
+ ctx.config,
1207
+ input,
1208
+ ctx.auth?.output,
1209
+ slate.spec,
1210
+ logger,
1211
+ getLiveInvocation()
1212
+ )
1213
+ );
1214
+ });
1215
+ manager.onRequest("slates/action.trigger.map_event", async ({ params }) => {
1216
+ let ctx = getContextFull();
1217
+ let action = getActionWithType(slate, "trigger", params.actionId);
1218
+ let input = validate(
1219
+ action.inputSchema,
1220
+ params.input,
1221
+ "input",
1222
+ `Invalid event for trigger ID: ${params.actionId}`
1223
+ );
1224
+ let context = new SlateContext(ctx.config, input, ctx.auth?.output, slate.spec, logger);
1225
+ let res = await traceProviderCall(
1226
+ {
1227
+ component: "action",
1228
+ functionName: "handleEvent",
1229
+ message: `Mapping event for trigger ${formatEntityLabel(action.name, action.key)}`,
1230
+ successMessage: (result) => `Mapped trigger event "${result.type}" for ${formatEntityLabel(action.name, action.key)}`,
1231
+ errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while mapping an event`,
1232
+ metadata: {
1233
+ actionId: action.key,
1234
+ actionName: action.name,
1235
+ actionType: action.type,
1236
+ inputKeyCount: getObjectKeyCount(input)
1237
+ },
1238
+ onSuccess: (result) => ({
1239
+ eventType: result.type,
1240
+ hasEventId: !!result.id,
1241
+ outputKeyCount: getObjectKeyCount(result.output)
1242
+ })
1243
+ },
1244
+ () => runWithContext(context, () => action.map(context))
1245
+ );
1246
+ return withRequestTraces(context, { id: res.id, type: res.type, output: res.output });
1247
+ });
1248
+ manager.onRequest("slates/action.trigger.poll_events", async ({ params }) => {
1249
+ getContextBasic();
1250
+ if (supportsTriggerGroups()) {
1251
+ throw new ServiceError4(
1252
+ badRequestError3({
1253
+ message: `Legacy trigger polling is disabled once trigger_group support is announced: ${params.actionId}`
1254
+ })
1255
+ );
1256
+ }
1257
+ return { inputs: [], updatedState: params.state };
1258
+ });
1259
+ manager.onRequest("slates/action.trigger.webhook_handle", async ({ params }) => {
1260
+ getContextBasic();
1261
+ if (supportsTriggerGroups()) {
1262
+ throw new ServiceError4(
1263
+ badRequestError3({
1264
+ message: `Legacy trigger webhook handling is disabled once trigger_group support is announced: ${params.actionId}`
1265
+ })
1266
+ );
1267
+ }
1268
+ return { inputs: [], updatedState: params.state, response: null };
1269
+ });
1270
+ manager.onRequest("slates/action.trigger.webhook_register", async ({ params }) => {
1271
+ getContextBasic();
1272
+ if (supportsTriggerGroups()) {
1273
+ throw new ServiceError4(
1274
+ badRequestError3({
1275
+ message: `Legacy trigger webhook registration is disabled once trigger_group support is announced: ${params.actionId}`
1276
+ })
1277
+ );
1278
+ }
1279
+ return { registrationDetails: null };
1280
+ });
1281
+ manager.onRequest("slates/action.trigger.webhook_unregister", async ({ params }) => {
1282
+ getContextBasic();
1283
+ if (supportsTriggerGroups()) {
1284
+ throw new ServiceError4(
1285
+ badRequestError3({
1286
+ message: `Legacy trigger webhook unregistration is disabled once trigger_group support is announced: ${params.actionId}`
1287
+ })
1288
+ );
1289
+ }
1290
+ return {};
1291
+ });
1292
+ manager.onRequest("slates/trigger_group.webhook.targets_list", async ({ params }) => {
1293
+ let ctx = getContextFull();
1294
+ let group = getTriggerGroup(slate, params.triggerGroupId);
1295
+ let autoRegistration = getWebhookAutoRegistration(group);
1296
+ let context = new SlateContext(
1297
+ ctx.config,
1298
+ { pageToken: params.pageToken ?? null },
1299
+ ctx.auth?.output,
1300
+ slate.spec,
1301
+ logger
1302
+ );
1303
+ let res = await traceProviderCall(
1304
+ {
1305
+ component: "action",
1306
+ functionName: "webhookTargetList",
1307
+ message: `Listing webhook targets for trigger group ${formatEntityLabel(group.name, group.key)}`,
1308
+ successMessage: (result) => `Listed ${result.targets.length} webhook target(s) for trigger group ${formatEntityLabel(group.name, group.key)}`,
1309
+ errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while listing webhook targets`,
1310
+ metadata: {
1311
+ triggerGroupId: group.key,
1312
+ triggerGroupName: group.name
1313
+ },
1314
+ onSuccess: (result) => ({
1315
+ targetCount: result.targets.length,
1316
+ hasNextPageToken: result.nextPageToken !== null
1317
+ })
1318
+ },
1319
+ () => runWithContext(context, () => autoRegistration.webhookTargetList(context))
1320
+ );
1321
+ return withRequestTraces(context, {
1322
+ targets: res.targets,
1323
+ nextPageToken: res.nextPageToken ?? null,
1324
+ isPartial: res.isPartial ?? false
1325
+ });
1326
+ });
1327
+ manager.onRequest("slates/trigger_group.webhook.register", async ({ params }) => {
1328
+ let ctx = getContextFull();
1329
+ let group = getTriggerGroup(slate, params.triggerGroupId);
1330
+ let autoRegistration = getWebhookAutoRegistration(group);
1331
+ let context = new SlateContext(
1332
+ ctx.config,
1333
+ {
1334
+ webhookTargetIdentifier: params.webhookTargetIdentifier,
1335
+ webhookTargetPayload: params.webhookTargetPayload,
1336
+ webhookUrl: params.webhookUrl
1337
+ },
1338
+ ctx.auth?.output,
1339
+ slate.spec,
1340
+ logger
1341
+ );
1342
+ let res = await traceProviderCall(
1343
+ {
1344
+ component: "action",
1345
+ functionName: "webhookRegister",
1346
+ message: `Registering webhook for trigger group ${formatEntityLabel(group.name, group.key)}`,
1347
+ successMessage: `Registered webhook for trigger group ${formatEntityLabel(group.name, group.key)}`,
1348
+ errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while registering a webhook`,
1349
+ metadata: {
1350
+ triggerGroupId: group.key,
1351
+ triggerGroupName: group.name,
1352
+ webhookTargetIdentifier: params.webhookTargetIdentifier
1353
+ }
1354
+ },
1355
+ () => runWithContext(context, () => autoRegistration.webhookRegister(context))
1356
+ );
1357
+ return withRequestTraces(context, {
1358
+ webhookRegistrationIdentifier: res.webhookRegistrationIdentifier,
1359
+ webhookRegistrationPayload: res.webhookRegistrationPayload
1360
+ });
1361
+ });
1362
+ manager.onRequest("slates/trigger_group.webhook.unregister", async ({ params }) => {
1363
+ let ctx = getContextFull();
1364
+ let group = getTriggerGroup(slate, params.triggerGroupId);
1365
+ let autoRegistration = getWebhookAutoRegistration(group);
1366
+ let context = new SlateContext(
1367
+ ctx.config,
1368
+ {
1369
+ webhookRegistrationIdentifier: params.webhookRegistrationIdentifier,
1370
+ webhookRegistrationPayload: params.webhookRegistrationPayload
1371
+ },
1372
+ ctx.auth?.output,
1373
+ slate.spec,
1374
+ logger
1375
+ );
1376
+ await traceProviderCall(
1377
+ {
1378
+ component: "action",
1379
+ functionName: "webhookUnregister",
1380
+ message: `Unregistering webhook for trigger group ${formatEntityLabel(group.name, group.key)}`,
1381
+ successMessage: `Unregistered webhook for trigger group ${formatEntityLabel(group.name, group.key)}`,
1382
+ errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while unregistering a webhook`,
1383
+ metadata: {
1384
+ triggerGroupId: group.key,
1385
+ triggerGroupName: group.name,
1386
+ webhookRegistrationIdentifier: params.webhookRegistrationIdentifier
1387
+ }
1388
+ },
1389
+ () => runWithContext(context, () => autoRegistration.webhookUnregister(context))
1390
+ );
1391
+ return withRequestTraces(context, {});
1392
+ });
1393
+ manager.onRequest("slates/trigger_group.webhook.manual_setup", async ({ params }) => {
1394
+ getContextBasic();
1395
+ let group = getTriggerGroup(slate, params.triggerGroupId);
1396
+ let manualRegistration = getWebhookManualRegistration(group);
1397
+ let context = new SlateContext(
1398
+ {},
1399
+ { webhookUrl: params.webhookUrl },
1400
+ {},
1401
+ slate.spec,
1402
+ logger
1403
+ );
1404
+ let res = await traceProviderCall(
1405
+ {
1406
+ component: "action",
1407
+ functionName: "webhookManualSetup",
1408
+ message: `Building manual webhook setup for trigger group ${formatEntityLabel(group.name, group.key)}`,
1409
+ successMessage: `Built manual webhook setup for trigger group ${formatEntityLabel(group.name, group.key)}`,
1410
+ errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while building a manual webhook setup`,
1411
+ metadata: {
1412
+ triggerGroupId: group.key,
1413
+ triggerGroupName: group.name
1414
+ }
1415
+ },
1416
+ () => runWithContext(context, () => manualRegistration.setup(context))
1417
+ );
1418
+ return {
1419
+ webhookSetupDocument: res.webhookSetupDocument,
1420
+ partialWebhookRegistrationPayload: res.partialWebhookRegistrationPayload
1421
+ };
1422
+ });
1423
+ manager.onRequest("slates/trigger_group.webhook.manual_finish", async ({ params }) => {
1424
+ getContextBasic();
1425
+ let group = getTriggerGroup(slate, params.triggerGroupId);
1426
+ let manualRegistration = getWebhookManualRegistration(group);
1427
+ if (!manualRegistration.finish) {
1428
+ throw new ServiceError4(
1429
+ badRequestError3({
1430
+ message: `Trigger group does not support manual webhook finish: ${params.triggerGroupId}`
1431
+ })
1432
+ );
1433
+ }
1434
+ let context = new SlateContext(
1435
+ {},
1436
+ {
1437
+ webhookUrl: params.webhookUrl,
1438
+ partialWebhookRegistrationPayload: params.partialWebhookRegistrationPayload,
1439
+ userWebhookRegistrationPayload: params.userWebhookRegistrationPayload
1440
+ },
1441
+ {},
1442
+ slate.spec,
1443
+ logger
1444
+ );
1445
+ let res = await traceProviderCall(
1446
+ {
1447
+ component: "action",
1448
+ functionName: "webhookManualFinish",
1449
+ message: `Finishing manual webhook setup for trigger group ${formatEntityLabel(group.name, group.key)}`,
1450
+ successMessage: `Finished manual webhook setup for trigger group ${formatEntityLabel(group.name, group.key)}`,
1451
+ errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while finishing a manual webhook setup`,
1452
+ metadata: {
1453
+ triggerGroupId: group.key,
1454
+ triggerGroupName: group.name
1455
+ }
1456
+ },
1457
+ () => runWithContext(context, () => manualRegistration.finish(context))
1458
+ );
1459
+ return withRequestTraces(context, {
1460
+ webhookRegistrationPayload: res.webhookRegistrationPayload
1461
+ });
1462
+ });
1463
+ manager.onRequest("slates/trigger_group.webhook.process", async ({ params }) => {
1464
+ let group = getTriggerGroup(slate, params.triggerGroupId);
1465
+ if (group.source !== "webhook" || !group.webhook) {
1466
+ throw new ServiceError4(
1467
+ badRequestError3({
1468
+ message: `Trigger group does not support webhook processing: ${params.triggerGroupId}`
1469
+ })
1470
+ );
1471
+ }
1472
+ let req = new Request(params.url, {
1473
+ method: params.method,
1474
+ headers: params.headers,
1475
+ body: params.body ? Uint8Array.from(atob(params.body.content), (c) => c.charCodeAt(0)) : null
1476
+ });
1477
+ let context = new SlateContext(
1478
+ {},
1479
+ {
1480
+ request: req,
1481
+ webhookRegistrationPayload: params.webhookRegistrationPayload
1482
+ },
1483
+ {},
1484
+ slate.spec,
1485
+ logger
1486
+ );
1487
+ let res = await traceProviderCall(
1488
+ {
1489
+ component: "action",
1490
+ functionName: "webhookProcess",
1491
+ message: `Processing webhook request for trigger group ${formatEntityLabel(group.name, group.key)}`,
1492
+ successMessage: (result) => `Extracted ${result.events.length} event(s) from webhook request for trigger group ${formatEntityLabel(group.name, group.key)}`,
1493
+ errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while processing a webhook request`,
1494
+ metadata: {
1495
+ triggerGroupId: group.key,
1496
+ triggerGroupName: group.name,
1497
+ requestMethod: params.method,
1498
+ hasRequestBody: !!params.body
1499
+ },
1500
+ onSuccess: (result) => ({
1501
+ eventCount: result.events.length,
1502
+ hasResponse: result.response !== void 0,
1503
+ skipped: !!result.skipped
1504
+ })
1505
+ },
1506
+ () => runWithContext(context, () => group.webhook.process(context))
1507
+ );
1508
+ for (let event of res.events) {
1509
+ if (!event.matchers) {
1510
+ throw new ServiceError4(
1511
+ preconditionFailedError({
1512
+ message: `Trigger group "${group.key}" process handler must return matchers for every event (return [] if there is nothing to assert)`
1513
+ })
1514
+ );
1515
+ }
1516
+ }
1517
+ let response = res.response === void 0 ? void 0 : await serializeWebhookHttpResponse(res.response);
1518
+ return withRequestTraces(context, {
1519
+ events: res.events.map((event) => ({
1520
+ matchers: event.matchers,
1521
+ payload: event.payload,
1522
+ idempotencyKey: event.idempotencyKey,
1523
+ triggerIds: evaluateTriggerMatches(slate, group.key, event.payload)
1524
+ })),
1525
+ response,
1526
+ skipped: res.skipped ?? null
1527
+ });
1528
+ });
1529
+ manager.onRequest("slates/trigger_group.routing_matchers.get", async ({ params }) => {
1530
+ let ctx = getContextFull();
1531
+ let group = getTriggerGroup(slate, params.triggerGroupId);
1532
+ let context = new SlateContext(ctx.config, {}, ctx.auth?.output, slate.spec, logger);
1533
+ let matchers = await traceProviderCall(
1534
+ {
1535
+ component: "action",
1536
+ functionName: "routingMatchers",
1537
+ message: `Getting routing matchers for trigger group ${formatEntityLabel(group.name, group.key)}`,
1538
+ successMessage: (result) => `Retrieved ${result.length} routing matcher(s) for trigger group ${formatEntityLabel(group.name, group.key)}`,
1539
+ errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while getting routing matchers`,
1540
+ metadata: {
1541
+ triggerGroupId: group.key,
1542
+ triggerGroupName: group.name
1543
+ },
1544
+ onSuccess: (result) => ({
1545
+ matcherCount: result.length
1546
+ })
1547
+ },
1548
+ () => runWithContext(context, () => group.routingMatchers(context))
1549
+ );
1550
+ return withRequestTraces(context, { matchers });
1551
+ });
1552
+ manager.onRequest("slates/trigger_group.polling.poll", async ({ params }) => {
1553
+ let ctx = getContextFull();
1554
+ let group = getTriggerGroup(slate, params.triggerGroupId);
1555
+ if (group.source !== "polling" || !group.polling) {
1556
+ throw new ServiceError4(
1557
+ badRequestError3({
1558
+ message: `Trigger group does not support polling: ${params.triggerGroupId}`
1559
+ })
1560
+ );
1561
+ }
1562
+ let context = new SlateContext(
1563
+ ctx.config,
1564
+ { state: params.state },
1565
+ ctx.auth?.output,
1566
+ slate.spec,
1567
+ logger
1568
+ );
1569
+ let res = await traceProviderCall(
1570
+ {
1571
+ component: "action",
1572
+ functionName: "pollEvents",
1573
+ message: `Polling events for trigger group ${formatEntityLabel(group.name, group.key)}`,
1574
+ successMessage: (result) => `Polled ${result.events.length} event(s) for trigger group ${formatEntityLabel(group.name, group.key)}`,
1575
+ errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while polling events`,
1576
+ metadata: {
1577
+ triggerGroupId: group.key,
1578
+ triggerGroupName: group.name,
1579
+ hasPreviousState: params.state !== null
1580
+ },
1581
+ onSuccess: (result) => ({
1582
+ eventCount: result.events.length,
1583
+ hasUpdatedState: result.updatedState !== void 0
1584
+ })
1585
+ },
1586
+ () => runWithContext(context, () => group.polling.pollEvents(context))
1587
+ );
1588
+ return withRequestTraces(context, {
1589
+ updatedState: res.updatedState,
1590
+ events: res.events.map((event) => ({
1591
+ payload: event.payload,
1592
+ idempotencyKey: event.idempotencyKey,
1593
+ triggerIds: evaluateTriggerMatches(slate, group.key, event.payload)
1594
+ }))
1595
+ });
1596
+ });
1597
+ let getGatewayTriggerGroup = (triggerGroupId) => {
1598
+ let group = getTriggerGroup(slate, triggerGroupId);
1599
+ if (group.source !== "gateway" || !group.gateway) {
1600
+ throw new ServiceError4(
1601
+ badRequestError3({
1602
+ message: `Trigger group does not support gateway connections: ${triggerGroupId}`
1603
+ })
1604
+ );
1605
+ }
1606
+ return { group, gateway: group.gateway };
1607
+ };
1608
+ manager.onRequest("slates/trigger_group.gateway.connect", async ({ params }) => {
1609
+ let ctx = getContextFull();
1610
+ let { group, gateway } = getGatewayTriggerGroup(params.triggerGroupId);
1611
+ let context = new SlateContext(
1612
+ ctx.config,
1613
+ { state: params.state },
1614
+ ctx.auth?.output,
1615
+ slate.spec,
1616
+ logger
1617
+ );
1618
+ let res = await traceProviderCall(
1619
+ {
1620
+ component: "action",
1621
+ functionName: "gatewayConnect",
1622
+ message: `Preparing gateway connection for trigger group ${formatEntityLabel(group.name, group.key)}`,
1623
+ successMessage: () => `Prepared gateway connection for trigger group ${formatEntityLabel(group.name, group.key)}`,
1624
+ errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while preparing a gateway connection`,
1625
+ metadata: {
1626
+ triggerGroupId: group.key,
1627
+ triggerGroupName: group.name,
1628
+ hasPreviousState: params.state !== null
1629
+ }
1630
+ },
1631
+ () => runWithContext(context, () => gateway.connect(context))
1632
+ );
1633
+ return withRequestTraces(context, { url: res.url, state: res.state });
1634
+ });
1635
+ manager.onRequest("slates/trigger_group.gateway.receive", async ({ params }) => {
1636
+ let ctx = getContextFull();
1637
+ let { group, gateway } = getGatewayTriggerGroup(params.triggerGroupId);
1638
+ let context = new SlateContext(
1639
+ ctx.config,
1640
+ { state: params.state, frames: params.frames, closed: params.closed ?? null },
1641
+ ctx.auth?.output,
1642
+ slate.spec,
1643
+ logger
1644
+ );
1645
+ let res = await traceProviderCall(
1646
+ {
1647
+ component: "action",
1648
+ functionName: "gatewayReceive",
1649
+ message: `Handling ${params.frames.length} gateway frame(s) for trigger group ${formatEntityLabel(group.name, group.key)}`,
1650
+ successMessage: (result) => `Handled gateway frames for trigger group ${formatEntityLabel(group.name, group.key)} (${result.events?.length ?? 0} event(s))`,
1651
+ errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while handling gateway frames`,
1652
+ metadata: {
1653
+ triggerGroupId: group.key,
1654
+ triggerGroupName: group.name,
1655
+ frameCount: params.frames.length,
1656
+ closed: params.closed ?? null
1657
+ },
1658
+ onSuccess: (result) => ({
1659
+ eventCount: result.events?.length ?? 0,
1660
+ sendCount: result.send?.length ?? 0,
1661
+ close: result.close ?? null
1662
+ })
1663
+ },
1664
+ () => runWithContext(context, () => gateway.receive(context))
1665
+ );
1666
+ return withRequestTraces(context, {
1667
+ state: res.state,
1668
+ // Outbound frames (e.g. IDENTIFY) embed credentials; the hub restores them at the socket.
1669
+ send: new AuthConfigSecretRedactor(
1670
+ context._getAuthConfigForRedaction()
1671
+ ).redactEmbedded(res.send ?? []),
1672
+ heartbeat: res.heartbeat ?? null,
1673
+ heartbeatAcked: res.heartbeatAcked,
1674
+ close: res.close ?? null,
1675
+ events: (res.events ?? []).map((event) => ({
1676
+ payload: event.payload,
1677
+ idempotencyKey: event.idempotencyKey,
1678
+ triggerIds: evaluateTriggerMatches(slate, group.key, event.payload)
1679
+ }))
1680
+ });
1681
+ });
1682
+ });
1683
+ export {
1684
+ createProviderHandler
1685
+ };