@slates/provider 1.0.0-rc.17 → 1.0.0-rc.18

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.
@@ -54,6 +54,12 @@ var SlateAction = class {
54
54
  get docs() {
55
55
  return this._params.docs;
56
56
  }
57
+ get adapter() {
58
+ return this._params.adapter ?? null;
59
+ }
60
+ get isPublic() {
61
+ return this._params.isPublic === true;
62
+ }
57
63
  };
58
64
 
59
65
  // src/error/api.ts
@@ -798,11 +804,12 @@ var isScopes = (value) => typeof value === "object" && value !== null && "AND" i
798
804
 
799
805
  // src/action/builder.ts
800
806
  var SlateActionBuilder = class {
801
- constructor(type, spec2, params, factory) {
807
+ constructor(type, spec2, params, factory, isPublicTool = false) {
802
808
  this.type = type;
803
809
  this.spec = spec2;
804
810
  this.params = params;
805
811
  this.factory = factory;
812
+ this.isPublicTool = isPublicTool;
806
813
  this.#configSchema = spec2.configSchema;
807
814
  this.#authSchema = spec2.authSchema;
808
815
  }
@@ -810,6 +817,7 @@ var SlateActionBuilder = class {
810
817
  spec;
811
818
  params;
812
819
  factory;
820
+ isPublicTool;
813
821
  #configSchema;
814
822
  #authSchema;
815
823
  #inputSchema = null;
@@ -818,20 +826,34 @@ var SlateActionBuilder = class {
818
826
  #authMethods;
819
827
  #toolParams = null;
820
828
  #triggerParams = null;
829
+ #interfaceLocked = false;
821
830
  input(schema) {
831
+ if (this.#interfaceLocked) {
832
+ throw new SlateDeclarationError("Adapter contract input schema cannot be changed");
833
+ }
822
834
  this.#inputSchema = schema;
823
835
  return this;
824
836
  }
825
837
  output(schema) {
838
+ if (this.#interfaceLocked) {
839
+ throw new SlateDeclarationError("Adapter contract output schema cannot be changed");
840
+ }
826
841
  this.#outputSchema = schema;
827
842
  return this;
828
843
  }
844
+ lockInterface() {
845
+ this.#interfaceLocked = true;
846
+ return this;
847
+ }
829
848
  scopes(scopes) {
830
849
  validateScopes(scopes);
831
850
  this.#scopes = scopes;
832
851
  return this;
833
852
  }
834
853
  authMethods(authMethods) {
854
+ if (this.isPublicTool) {
855
+ throw new SlateDeclarationError("Public tools cannot require authentication methods");
856
+ }
835
857
  this.#authMethods = this.validateAuthMethods(authMethods);
836
858
  return this;
837
859
  }
@@ -887,6 +909,9 @@ var SlateActionBuilder = class {
887
909
  validateScopes(scopes);
888
910
  }
889
911
  let authMethods = this.validateAuthMethods(this.#authMethods ?? this.params.authMethods);
912
+ if (this.isPublicTool && authMethods) {
913
+ throw new SlateDeclarationError("Public tools cannot require authentication methods");
914
+ }
890
915
  if (!this.#inputSchema) {
891
916
  throw new SlateDeclarationError("Input schema is not defined");
892
917
  }
@@ -903,6 +928,7 @@ var SlateActionBuilder = class {
903
928
  ...this.params,
904
929
  scopes,
905
930
  authMethods,
931
+ isPublic: this.isPublicTool === true,
906
932
  configSchema: this.#configSchema,
907
933
  authSchema: this.#authSchema,
908
934
  inputSchema: this.#inputSchema,
@@ -922,16 +948,40 @@ var SlateTool = class _SlateTool extends SlateAction {
922
948
  }
923
949
  static create(spec2, params) {
924
950
  return new SlateActionBuilder("tool", spec2, params, (params2) => {
925
- if (params2.type !== "tool") throw new Error("Invalid action type for tool");
926
- return new _SlateTool(spec2, params2.inputSchema, params2.outputSchema, params2);
951
+ return _SlateTool.fromCreateParameters(spec2, params2);
927
952
  });
928
953
  }
954
+ static fromCreateParameters(spec2, params) {
955
+ if (params.type !== "tool") throw new Error("Invalid action type for tool");
956
+ return new _SlateTool(spec2, params.inputSchema, params.outputSchema, params);
957
+ }
929
958
  get handleInvocation() {
930
959
  return this.#handleInvocation;
931
960
  }
932
961
  };
933
962
  var tool = (spec2, params) => SlateTool.create(spec2, params);
934
963
 
964
+ // src/action/publicTool.ts
965
+ var SlatePublicTool = class {
966
+ constructor() {
967
+ }
968
+ static create(spec2, params) {
969
+ return new SlateActionBuilder(
970
+ "tool",
971
+ spec2,
972
+ params,
973
+ (params2) => {
974
+ return SlateTool.fromCreateParameters(spec2, {
975
+ ...params2,
976
+ isPublic: true
977
+ });
978
+ },
979
+ true
980
+ );
981
+ }
982
+ };
983
+ var publicTool = (spec2, params) => SlatePublicTool.create(spec2, params);
984
+
935
985
  // src/action/trigger.ts
936
986
  var SlateDefaultPollingIntervalSeconds = 60 * 10;
937
987
  var SlateTrigger = class _SlateTrigger extends SlateAction {
@@ -1014,6 +1064,135 @@ var createTextAttachment = (content, mimeType) => ({
1014
1064
  }
1015
1065
  });
1016
1066
 
1067
+ // src/adapter/adapter.ts
1068
+ var SlateAdapter = class {
1069
+ constructor(_spec, _tools, _triggers) {
1070
+ this._spec = _spec;
1071
+ this._tools = _tools;
1072
+ this._triggers = _triggers;
1073
+ }
1074
+ _spec;
1075
+ _tools;
1076
+ _triggers;
1077
+ get spec() {
1078
+ return this._spec;
1079
+ }
1080
+ get id() {
1081
+ return this._spec.id;
1082
+ }
1083
+ get name() {
1084
+ return this._spec.name;
1085
+ }
1086
+ get capabilities() {
1087
+ return this._spec.capabilities;
1088
+ }
1089
+ get tools() {
1090
+ return this._tools;
1091
+ }
1092
+ get triggers() {
1093
+ return this._triggers;
1094
+ }
1095
+ get actions() {
1096
+ return [...this._triggers, ...this._tools];
1097
+ }
1098
+ };
1099
+
1100
+ // src/adapter/spec.ts
1101
+ var SlateAdapterSpec = class _SlateAdapterSpec {
1102
+ constructor(_params) {
1103
+ this._params = _params;
1104
+ }
1105
+ _params;
1106
+ static create(params) {
1107
+ let id = params.id?.trim();
1108
+ let name = params.name?.trim();
1109
+ if (!id) {
1110
+ throw new SlateDeclarationError("Adapter id must be a non-empty string");
1111
+ }
1112
+ if (!name) {
1113
+ throw new SlateDeclarationError("Adapter name must be a non-empty string");
1114
+ }
1115
+ return new _SlateAdapterSpec({
1116
+ id,
1117
+ name,
1118
+ capabilities: validateCapabilities(params.capabilities ?? [])
1119
+ });
1120
+ }
1121
+ get id() {
1122
+ return this._params.id;
1123
+ }
1124
+ get name() {
1125
+ return this._params.name;
1126
+ }
1127
+ get capabilities() {
1128
+ return this._params.capabilities;
1129
+ }
1130
+ get parameters() {
1131
+ return this._params;
1132
+ }
1133
+ tool(spec2, params) {
1134
+ return SlateTool.create(spec2, this.linkAction(params));
1135
+ }
1136
+ publicTool(spec2, params) {
1137
+ return SlatePublicTool.create(spec2, this.linkAction(params));
1138
+ }
1139
+ trigger(spec2, params) {
1140
+ return SlateTrigger.create(spec2, this.linkAction(params));
1141
+ }
1142
+ register(params) {
1143
+ let actions = [...params.tools, ...params.triggers];
1144
+ let seenKeys = /* @__PURE__ */ new Set();
1145
+ for (let action of actions) {
1146
+ if (action.adapter && action.adapter !== this.id) {
1147
+ throw new SlateDeclarationError(
1148
+ `Action "${action.key}" is linked to adapter "${action.adapter}", not "${this.id}"`
1149
+ );
1150
+ }
1151
+ if (!action.adapter) {
1152
+ throw new SlateDeclarationError(
1153
+ `Action "${action.key}" must be created with this adapter's tool(), publicTool(), or trigger() helpers`
1154
+ );
1155
+ }
1156
+ if (seenKeys.has(action.key)) {
1157
+ throw new SlateDeclarationError(
1158
+ `Adapter "${this.id}" already has an action with key "${action.key}"`
1159
+ );
1160
+ }
1161
+ seenKeys.add(action.key);
1162
+ }
1163
+ return new SlateAdapter(this, params.tools, params.triggers);
1164
+ }
1165
+ linkAction(params) {
1166
+ if (params.adapter != null && params.adapter !== this.id) {
1167
+ throw new SlateDeclarationError(
1168
+ `Action "${params.key}" cannot be linked to adapter "${this.id}" because it is already linked to "${params.adapter}"`
1169
+ );
1170
+ }
1171
+ return {
1172
+ ...params,
1173
+ adapter: this.id
1174
+ };
1175
+ }
1176
+ };
1177
+ var adapterSpec = (params) => SlateAdapterSpec.create(params);
1178
+ var validateCapabilities = (capabilities) => {
1179
+ let seenIds = /* @__PURE__ */ new Set();
1180
+ return capabilities.map((capability) => {
1181
+ let id = capability.id?.trim();
1182
+ if (!id) {
1183
+ throw new SlateDeclarationError("Adapter capability ids must be non-empty strings");
1184
+ }
1185
+ if (seenIds.has(id)) {
1186
+ throw new SlateDeclarationError(`Adapter capability "${id}" is defined more than once`);
1187
+ }
1188
+ seenIds.add(id);
1189
+ return {
1190
+ id,
1191
+ value: capability.value
1192
+ };
1193
+ });
1194
+ };
1195
+
1017
1196
  // src/auth/auth.ts
1018
1197
  var SlateAuth = class _SlateAuth {
1019
1198
  #outputSchema = null;
@@ -1813,26 +1992,19 @@ var SlateConfig = class _SlateConfig {
1813
1992
  var config = (schema) => SlateConfig.create(schema);
1814
1993
 
1815
1994
  // src/context/context.ts
1816
- var SlateContext = class {
1817
- constructor(config2, input, auth2, spec2, logger) {
1995
+ var SlatePublicContext = class {
1996
+ constructor(input, spec2, logger) {
1818
1997
  this.spec = spec2;
1819
1998
  this.logger = logger;
1820
- this.#config = config2;
1821
1999
  this.#input = input;
1822
- this.#auth = auth2;
1823
2000
  }
1824
2001
  spec;
1825
2002
  logger;
1826
- #config;
1827
2003
  #input;
1828
- #auth;
1829
2004
  #httpTraces = [];
1830
2005
  get specification() {
1831
2006
  return this.spec;
1832
2007
  }
1833
- get config() {
1834
- return Object.freeze(this.#config);
1835
- }
1836
2008
  get input() {
1837
2009
  return Object.freeze(this.#input);
1838
2010
  }
@@ -1850,9 +2022,6 @@ var SlateContext = class {
1850
2022
  this.#input.registrationDetails
1851
2023
  );
1852
2024
  }
1853
- get auth() {
1854
- return Object.freeze(this.#auth);
1855
- }
1856
2025
  recordHttpTrace(trace) {
1857
2026
  this.#httpTraces.push(trace);
1858
2027
  }
@@ -1887,6 +2056,21 @@ var SlateContext = class {
1887
2056
  this.logger.progress(message);
1888
2057
  }
1889
2058
  };
2059
+ var SlateContext = class extends SlatePublicContext {
2060
+ #config;
2061
+ #auth;
2062
+ constructor(config2, input, auth2, spec2, logger) {
2063
+ super(input, spec2, logger);
2064
+ this.#config = config2;
2065
+ this.#auth = auth2;
2066
+ }
2067
+ get config() {
2068
+ return Object.freeze(this.#config);
2069
+ }
2070
+ get auth() {
2071
+ return Object.freeze(this.#auth);
2072
+ }
2073
+ };
1890
2074
 
1891
2075
  // src/crypto/hmac.ts
1892
2076
  import { createHmac, timingSafeEqual } from "crypto";
@@ -2035,14 +2219,40 @@ var setIfDefined = (target, key, value) => {
2035
2219
 
2036
2220
  // src/specification/slate.ts
2037
2221
  var Slate = class _Slate {
2038
- constructor(_spec, _actions) {
2222
+ constructor(_spec, _actions, _adapters) {
2039
2223
  this._spec = _spec;
2040
2224
  this._actions = _actions;
2225
+ this._adapters = _adapters;
2041
2226
  }
2042
2227
  _spec;
2043
2228
  _actions;
2229
+ _adapters;
2044
2230
  static create(params) {
2045
- return new _Slate(params.spec, [...params.triggers, ...params.tools]);
2231
+ let adapters = params.adapters ?? [];
2232
+ let actions = [...params.triggers, ...params.tools];
2233
+ let seenAdapterIds = /* @__PURE__ */ new Set();
2234
+ let seenActionKeys = new Map(actions.map((action) => [action.key, action]));
2235
+ for (let adapter of adapters) {
2236
+ if (seenAdapterIds.has(adapter.id)) {
2237
+ throw new SlateDeclarationError(
2238
+ `Adapter "${adapter.id}" is registered more than once`
2239
+ );
2240
+ }
2241
+ seenAdapterIds.add(adapter.id);
2242
+ for (let action of adapter.actions) {
2243
+ let existing = seenActionKeys.get(action.key);
2244
+ if (existing && existing !== action) {
2245
+ throw new SlateDeclarationError(
2246
+ `Adapter "${adapter.id}" action "${action.key}" conflicts with another action`
2247
+ );
2248
+ }
2249
+ if (!existing) {
2250
+ actions.push(action);
2251
+ seenActionKeys.set(action.key, action);
2252
+ }
2253
+ }
2254
+ }
2255
+ return new _Slate(params.spec, actions, adapters);
2046
2256
  }
2047
2257
  get spec() {
2048
2258
  return this._spec;
@@ -2050,6 +2260,9 @@ var Slate = class _Slate {
2050
2260
  get actions() {
2051
2261
  return this._actions;
2052
2262
  }
2263
+ get adapters() {
2264
+ return this._adapters;
2265
+ }
2053
2266
  };
2054
2267
 
2055
2268
  // src/specification/specification.ts
@@ -2151,6 +2364,9 @@ var getMetaWebhookVerificationResponse = (request, expectedVerifyToken) => {
2151
2364
  export {
2152
2365
  Slate,
2153
2366
  SlateAction,
2367
+ SlateActionBuilder,
2368
+ SlateAdapter,
2369
+ SlateAdapterSpec,
2154
2370
  SlateAuth,
2155
2371
  SlateConfig,
2156
2372
  SlateContext,
@@ -2158,9 +2374,12 @@ export {
2158
2374
  SlateDefaultPollingIntervalSeconds,
2159
2375
  SlateError,
2160
2376
  SlateLogger,
2377
+ SlatePublicContext,
2378
+ SlatePublicTool,
2161
2379
  SlateSpecification,
2162
2380
  SlateTool,
2163
2381
  SlateTrigger,
2382
+ adapterSpec,
2164
2383
  allOf,
2165
2384
  anyOf,
2166
2385
  auth,
@@ -2197,6 +2416,7 @@ export {
2197
2416
  metaWebhookHttp,
2198
2417
  normalizeOAuthTokenResponse,
2199
2418
  pickDefined,
2419
+ publicTool,
2200
2420
  requestAxios,
2201
2421
  requestAxiosData,
2202
2422
  runWithContext,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slates/provider",
3
- "version": "1.0.0-rc.17",
3
+ "version": "1.0.0-rc.18",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -42,4 +42,4 @@
42
42
  "typescript": "5.8.2",
43
43
  "vitest": "^3.1.2"
44
44
  }
45
- }
45
+ }
@@ -1,5 +1,5 @@
1
1
  import type { z } from 'zod';
2
- import type { SlateContext } from '../context';
2
+ import type { SlateContext, SlatePublicContext } from '../context';
3
3
  import type { SlateActionDocsReference } from '../docs';
4
4
  import type { SlateSpecification } from '../specification/specification';
5
5
  import type { SlateAttachment } from './attachment';
@@ -29,6 +29,8 @@ export interface SlateActionParameters {
29
29
  scopes?: SlateActionScopes;
30
30
  authMethods?: string[];
31
31
  docs?: SlateActionDocsReference[];
32
+ adapter?: string | null;
33
+ isPublic?: boolean;
32
34
  }
33
35
 
34
36
  export type SlateToolInvocationHandler<
@@ -42,6 +44,14 @@ export type SlateToolInvocationHandler<
42
44
  attachments?: SlateAttachment[];
43
45
  }>;
44
46
 
47
+ export type SlatePublicToolInvocationHandler<InputType extends {}, OutputType extends {}> = (
48
+ context: SlatePublicContext<InputType>
49
+ ) => Promise<{
50
+ output: OutputType;
51
+ message: string;
52
+ attachments?: SlateAttachment[];
53
+ }>;
54
+
45
55
  export type SlateTriggerMappingHandler<
46
56
  ConfigType extends {},
47
57
  AuthType extends {},
@@ -258,4 +268,12 @@ export abstract class SlateAction<
258
268
  get docs() {
259
269
  return this._params.docs;
260
270
  }
271
+
272
+ get adapter() {
273
+ return this._params.adapter ?? null;
274
+ }
275
+
276
+ get isPublic() {
277
+ return this._params.isPublic === true;
278
+ }
261
279
  }
@@ -0,0 +1,136 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { z } from 'zod';
3
+ import { SlateAuth } from '../auth';
4
+ import { SlateConfig } from '../config';
5
+ import { SlatePublicContext } from '../context';
6
+ import { SlateSpecification } from '../specification/specification';
7
+ import { SlatePublicTool } from './publicTool';
8
+ import { SlateTool } from './tool';
9
+
10
+ let createTestSpec = () => {
11
+ let config = SlateConfig.create(
12
+ z.object({
13
+ prefix: z.string()
14
+ })
15
+ );
16
+ let auth = SlateAuth.create<{ token: string }>().output(
17
+ z.object({
18
+ token: z.string()
19
+ })
20
+ );
21
+
22
+ return SlateSpecification.create({
23
+ key: 'demo',
24
+ name: 'Demo',
25
+ config,
26
+ auth
27
+ });
28
+ };
29
+
30
+ describe('SlateActionBuilder.lockInterface', () => {
31
+ it('prevents changing input and output schemas after the interface is locked', () => {
32
+ let spec = createTestSpec();
33
+ let builder = SlateTool.create(spec, {
34
+ key: 'send',
35
+ name: 'Send'
36
+ })
37
+ .input(z.object({ to: z.string() }))
38
+ .output(z.object({ id: z.string() }))
39
+ .lockInterface();
40
+
41
+ expect(() => builder.input(z.object({}))).toThrow(
42
+ 'Adapter contract input schema cannot be changed'
43
+ );
44
+ expect(() => builder.output(z.object({}))).toThrow(
45
+ 'Adapter contract output schema cannot be changed'
46
+ );
47
+ });
48
+ });
49
+
50
+ describe('SlatePublicTool', () => {
51
+ it('builds a public tool that omits config and auth from the handler context', async () => {
52
+ let spec = createTestSpec();
53
+ let tool = SlatePublicTool.create(spec, {
54
+ key: 'setup',
55
+ name: 'Setup'
56
+ })
57
+ .input(
58
+ z.object({
59
+ name: z.string()
60
+ })
61
+ )
62
+ .output(
63
+ z.object({
64
+ greeting: z.string()
65
+ })
66
+ )
67
+ .handleInvocation(async ctx => {
68
+ expect(ctx).not.toHaveProperty('config');
69
+ expect(ctx).not.toHaveProperty('auth');
70
+
71
+ return {
72
+ output: { greeting: `Hello ${ctx.input.name}` },
73
+ message: 'ok'
74
+ };
75
+ })
76
+ .build();
77
+
78
+ expect(tool.isPublic).toBe(true);
79
+ expect(tool.key).toBe('setup');
80
+
81
+ let result = await tool.handleInvocation(
82
+ new SlatePublicContext({ name: 'Ada' }, spec, {
83
+ debug: () => {},
84
+ error: () => {},
85
+ info: () => {},
86
+ progress: () => {},
87
+ warn: () => {}
88
+ } as any) as any
89
+ );
90
+
91
+ expect(result.output).toEqual({ greeting: 'Hello Ada' });
92
+ });
93
+
94
+ it('keeps regular tools private by default', () => {
95
+ let spec = createTestSpec();
96
+ let tool = SlateTool.create(spec, {
97
+ key: 'send',
98
+ name: 'Send'
99
+ })
100
+ .input(z.object({}))
101
+ .output(z.object({}))
102
+ .handleInvocation(async () => ({
103
+ output: {},
104
+ message: 'ok'
105
+ }))
106
+ .build();
107
+
108
+ expect(tool.isPublic).toBe(false);
109
+ });
110
+
111
+ it('rejects authentication methods on public tools', () => {
112
+ let spec = createTestSpec();
113
+
114
+ expect(() =>
115
+ SlatePublicTool.create(spec, {
116
+ key: 'setup',
117
+ name: 'Setup'
118
+ }).authMethods(['token_auth'])
119
+ ).toThrow('Public tools cannot require authentication methods');
120
+
121
+ expect(() =>
122
+ SlatePublicTool.create(spec, {
123
+ key: 'setup',
124
+ name: 'Setup',
125
+ authMethods: ['token_auth']
126
+ })
127
+ .input(z.object({}))
128
+ .output(z.object({}))
129
+ .handleInvocation(async () => ({
130
+ output: {},
131
+ message: 'ok'
132
+ }))
133
+ .build()
134
+ ).toThrow('Public tools cannot require authentication methods');
135
+ });
136
+ });