@slates/provider 1.0.0-rc.2 → 1.0.0-rc.20

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 (124) hide show
  1. package/dist/index.cjs +2847 -2
  2. package/dist/index.d.cts +1019 -0
  3. package/dist/index.d.ts +1019 -9
  4. package/dist/index.module.js +2737 -2
  5. package/package.json +9 -6
  6. package/src/action/action.ts +92 -4
  7. package/src/action/attachment.ts +87 -0
  8. package/src/action/builder.test.ts +136 -0
  9. package/src/action/builder.ts +113 -15
  10. package/src/action/directUpload.ts +59 -0
  11. package/src/action/getFileUrlTool.ts +41 -0
  12. package/src/action/index.ts +4 -2
  13. package/src/action/publicTool.ts +36 -0
  14. package/src/action/scopes.test.ts +76 -0
  15. package/src/action/scopes.ts +103 -0
  16. package/src/action/tool.ts +22 -6
  17. package/src/action/trigger.ts +19 -11
  18. package/src/adapter/adapter.ts +38 -0
  19. package/src/adapter/index.test.ts +322 -0
  20. package/src/adapter/index.ts +2 -0
  21. package/src/adapter/spec.ts +154 -0
  22. package/src/auth/auth.ts +3 -3
  23. package/src/auth/index.ts +2 -0
  24. package/src/auth/oauth.test.ts +83 -0
  25. package/src/auth/oauth.ts +150 -0
  26. package/src/auth/redact.test.ts +103 -0
  27. package/src/auth/redact.ts +111 -0
  28. package/src/auth/types.ts +72 -13
  29. package/src/axios/http.test.ts +83 -0
  30. package/src/axios/index.ts +116 -10
  31. package/src/axios/trace.test.ts +377 -0
  32. package/src/axios/trace.ts +803 -0
  33. package/src/config/config.ts +14 -3
  34. package/src/context/context.ts +264 -17
  35. package/src/context/hook.test.ts +46 -0
  36. package/src/context/hook.ts +15 -6
  37. package/src/context/index.ts +1 -0
  38. package/src/context/pQueue.ts +4 -0
  39. package/src/crypto/hmac.test.ts +40 -0
  40. package/src/crypto/hmac.ts +32 -0
  41. package/src/crypto/index.ts +1 -0
  42. package/src/docs.ts +22 -0
  43. package/src/error/api.test.ts +114 -0
  44. package/src/error/api.ts +236 -0
  45. package/src/error/axios.ts +220 -0
  46. package/src/error/base.test.ts +178 -0
  47. package/src/error/base.ts +108 -2
  48. package/src/error/declaration.ts +7 -2
  49. package/src/error/defaults.ts +50 -0
  50. package/src/error/index.ts +4 -0
  51. package/src/error/service.ts +170 -0
  52. package/src/error/types.ts +75 -0
  53. package/src/error/utils.ts +157 -0
  54. package/src/file/index.test.ts +36 -0
  55. package/src/file/index.ts +27 -0
  56. package/src/index.ts +8 -0
  57. package/src/logger/logger.test.ts +57 -0
  58. package/src/logger/logger.ts +72 -11
  59. package/src/module/resolveDefaultExport.test.ts +32 -0
  60. package/src/module/resolveDefaultExport.ts +14 -0
  61. package/src/object/index.test.ts +38 -0
  62. package/src/object/index.ts +12 -0
  63. package/src/specification/slate.ts +40 -4
  64. package/src/specification/specification.ts +10 -6
  65. package/src/webhook/graph.test.ts +37 -0
  66. package/src/webhook/graph.ts +22 -0
  67. package/src/webhook/index.ts +2 -0
  68. package/src/webhook/meta.test.ts +52 -0
  69. package/src/webhook/meta.ts +43 -0
  70. package/dist/action/action.d.ts +0 -98
  71. package/dist/action/action.d.ts.map +0 -1
  72. package/dist/action/builder.d.ts +0 -27
  73. package/dist/action/builder.d.ts.map +0 -1
  74. package/dist/action/index.d.ts +0 -5
  75. package/dist/action/index.d.ts.map +0 -1
  76. package/dist/action/tool.d.ts +0 -14
  77. package/dist/action/tool.d.ts.map +0 -1
  78. package/dist/action/trigger.d.ts +0 -32
  79. package/dist/action/trigger.d.ts.map +0 -1
  80. package/dist/auth/auth.d.ts +0 -30
  81. package/dist/auth/auth.d.ts.map +0 -1
  82. package/dist/auth/index.d.ts +0 -3
  83. package/dist/auth/index.d.ts.map +0 -1
  84. package/dist/auth/types.d.ts +0 -148
  85. package/dist/auth/types.d.ts.map +0 -1
  86. package/dist/axios/index.d.ts +0 -4
  87. package/dist/axios/index.d.ts.map +0 -1
  88. package/dist/config/config.d.ts +0 -26
  89. package/dist/config/config.d.ts.map +0 -1
  90. package/dist/config/index.d.ts +0 -2
  91. package/dist/config/index.d.ts.map +0 -1
  92. package/dist/context/context.d.ts +0 -20
  93. package/dist/context/context.d.ts.map +0 -1
  94. package/dist/context/hook.d.ts +0 -4
  95. package/dist/context/hook.d.ts.map +0 -1
  96. package/dist/context/index.d.ts +0 -2
  97. package/dist/context/index.d.ts.map +0 -1
  98. package/dist/error/base.d.ts +0 -5
  99. package/dist/error/base.d.ts.map +0 -1
  100. package/dist/error/declaration.d.ts +0 -6
  101. package/dist/error/declaration.d.ts.map +0 -1
  102. package/dist/error/index.d.ts +0 -3
  103. package/dist/error/index.d.ts.map +0 -1
  104. package/dist/index.cjs.map +0 -1
  105. package/dist/index.d.ts.map +0 -1
  106. package/dist/index.modern.js +0 -2
  107. package/dist/index.modern.js.map +0 -1
  108. package/dist/index.module.js.map +0 -1
  109. package/dist/index.umd.js +0 -2
  110. package/dist/index.umd.js.map +0 -1
  111. package/dist/logger/index.d.ts +0 -2
  112. package/dist/logger/index.d.ts.map +0 -1
  113. package/dist/logger/logger.d.ts +0 -20
  114. package/dist/logger/logger.d.ts.map +0 -1
  115. package/dist/specification/index.d.ts +0 -3
  116. package/dist/specification/index.d.ts.map +0 -1
  117. package/dist/specification/slate.d.ts +0 -15
  118. package/dist/specification/slate.d.ts.map +0 -1
  119. package/dist/specification/specification.d.ts +0 -30
  120. package/dist/specification/specification.d.ts.map +0 -1
  121. package/dist/specification/zero.d.ts +0 -13
  122. package/dist/specification/zero.d.ts.map +0 -1
  123. package/dist/tokens.d.ts +0 -34
  124. package/dist/tokens.d.ts.map +0 -1
@@ -0,0 +1,41 @@
1
+ import { z } from 'zod';
2
+ import type { SlateContext } from '../context/context';
3
+ import type { SlateSpecification } from '../specification/specification';
4
+ import { tool } from './tool';
5
+
6
+ export let GET_FILE_URL_TOOL_ID = 'metorial$getFileUrl';
7
+
8
+ export let getFileUrlToolInputSchema = z.object({
9
+ url: z.string(),
10
+ reference: z.any().nullable()
11
+ });
12
+ export type GetFileUrlToolInput = z.infer<typeof getFileUrlToolInputSchema>;
13
+
14
+ export let getFileUrlToolOutputSchema = z.object({
15
+ url: z.string(),
16
+ expiresAt: z.string(),
17
+ headers: z.record(z.string(), z.string()).optional(),
18
+ query: z.record(z.string(), z.string()).optional()
19
+ });
20
+ export type GetFileUrlToolOutput = z.infer<typeof getFileUrlToolOutputSchema>;
21
+
22
+ export type GetFileUrlHandler<ConfigType extends {}, AuthType extends {}> = (
23
+ context: SlateContext<ConfigType, AuthType, GetFileUrlToolInput>
24
+ ) => Promise<GetFileUrlToolOutput>;
25
+
26
+ export let getFileUrlTool = <ConfigType extends {}, AuthType extends {}>(
27
+ spec: SlateSpecification<ConfigType, AuthType>,
28
+ handleGetFileUrl: GetFileUrlHandler<ConfigType, AuthType>
29
+ ) =>
30
+ tool(spec, {
31
+ key: GET_FILE_URL_TOOL_ID,
32
+ name: 'Get File URL',
33
+ description: 'Reserved: refreshes an expiring attachment download URL. Hub-internal only.'
34
+ })
35
+ .input(getFileUrlToolInputSchema)
36
+ .output(getFileUrlToolOutputSchema)
37
+ .handleInvocation(async ctx => ({
38
+ output: await handleGetFileUrl(ctx),
39
+ message: 'ok'
40
+ }))
41
+ .build();
@@ -1,5 +1,7 @@
1
1
  export * from './action';
2
+ export * from './builder';
3
+ export * from './getFileUrlTool';
4
+ export * from './publicTool';
5
+ export * from './scopes';
2
6
  export * from './tool';
3
7
  export * from './trigger';
4
-
5
- export type * from './builder';
@@ -0,0 +1,36 @@
1
+ import type { SlateSpecification } from '../specification/specification';
2
+ import type { SlateActionParameters, SlatePublicToolInvocationHandler } from './action';
3
+ import { SlateActionBuilder } from './builder';
4
+ import { SlateTool } from './tool';
5
+
6
+ export interface SlatePublicToolParameters<InputType extends {}, OutputType extends {}>
7
+ extends SlateActionParameters {
8
+ handleInvocation: SlatePublicToolInvocationHandler<InputType, OutputType>;
9
+ }
10
+
11
+ export class SlatePublicTool {
12
+ private constructor() {}
13
+
14
+ static create<ConfigType extends {}, AuthType extends {}>(
15
+ spec: SlateSpecification<ConfigType, AuthType>,
16
+ params: SlateActionParameters
17
+ ) {
18
+ return new SlateActionBuilder(
19
+ 'tool',
20
+ spec,
21
+ params,
22
+ params => {
23
+ return SlateTool.fromCreateParameters(spec, {
24
+ ...params,
25
+ isPublic: true
26
+ });
27
+ },
28
+ true
29
+ );
30
+ }
31
+ }
32
+
33
+ export let publicTool = <ConfigType extends {}, AuthType extends {}>(
34
+ spec: SlateSpecification<ConfigType, AuthType>,
35
+ params: SlateActionParameters
36
+ ) => SlatePublicTool.create(spec, params);
@@ -0,0 +1,76 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { allOf, anyOf, mergeScopes, scopeClause, validateScopes } from './scopes';
3
+
4
+ describe('action scope helpers', () => {
5
+ it('builds OR and AND scope clauses', () => {
6
+ expect(scopeClause('scope:read', 'scope:admin')).toEqual({
7
+ OR: ['scope:read', 'scope:admin']
8
+ });
9
+
10
+ expect(anyOf('scope:read', 'scope:admin')).toEqual({
11
+ AND: [{ OR: ['scope:read', 'scope:admin'] }]
12
+ });
13
+
14
+ expect(allOf(['scope:calendar'], ['scope:sharing', 'scope:sharing:admin'])).toEqual({
15
+ AND: [{ OR: ['scope:calendar'] }, { OR: ['scope:sharing', 'scope:sharing:admin'] }]
16
+ });
17
+ });
18
+
19
+ it('accepts nested scope structures and flattens them', () => {
20
+ expect(
21
+ allOf(
22
+ anyOf('scope:events.read', 'scope:events.write'),
23
+ scopeClause('scope:calendar'),
24
+ 'scope:profile'
25
+ )
26
+ ).toEqual({
27
+ AND: [
28
+ { OR: ['scope:events.read', 'scope:events.write'] },
29
+ { OR: ['scope:calendar'] },
30
+ { OR: ['scope:profile'] }
31
+ ]
32
+ });
33
+ });
34
+
35
+ it('merges multiple scope sets and skips empty inputs', () => {
36
+ expect(
37
+ mergeScopes(
38
+ anyOf('scope:calendar'),
39
+ undefined,
40
+ false,
41
+ allOf(['scope:events.read', 'scope:events.write'], 'scope:profile')
42
+ )
43
+ ).toEqual({
44
+ AND: [
45
+ { OR: ['scope:calendar'] },
46
+ { OR: ['scope:events.read', 'scope:events.write'] },
47
+ { OR: ['scope:profile'] }
48
+ ]
49
+ });
50
+
51
+ expect(mergeScopes(undefined, false, null)).toBeUndefined();
52
+ });
53
+
54
+ it('validates and clones incoming scope objects', () => {
55
+ let input = {
56
+ AND: [{ OR: ['scope:calendar', 'scope:calendar:admin'] }]
57
+ };
58
+ let validated = validateScopes(input);
59
+
60
+ expect(validated).toEqual({
61
+ AND: [{ OR: ['scope:calendar', 'scope:calendar:admin'] }]
62
+ });
63
+ expect(validated).not.toBe(input);
64
+ expect(validated.AND[0]).not.toBe(input.AND[0]);
65
+ });
66
+
67
+ it('throws helpful errors for invalid scope definitions', () => {
68
+ expect(() => scopeClause()).toThrow(
69
+ 'Each action scope clause must include at least one OR scope'
70
+ );
71
+ expect(() => scopeClause('')).toThrow('Action scopes must be non-empty strings');
72
+ expect(() => validateScopes({ AND: [] })).toThrow(
73
+ 'Action scopes must include at least one AND clause'
74
+ );
75
+ });
76
+ });
@@ -0,0 +1,103 @@
1
+ import { SlateDeclarationError } from '../error';
2
+ import type { SlateActionScopeClause, SlateActionScopes } from './action';
3
+
4
+ export type SlateActionScopeValue = string;
5
+
6
+ export type SlateActionScopeClauseInput =
7
+ | SlateActionScopeValue
8
+ | readonly SlateActionScopeValue[]
9
+ | SlateActionScopeClause;
10
+
11
+ export type SlateActionScopesInput = SlateActionScopeClauseInput | SlateActionScopes;
12
+
13
+ export let scopeClause = (...scopes: SlateActionScopeValue[]): SlateActionScopeClause => {
14
+ assertScopeValues(scopes);
15
+ return {
16
+ OR: [...scopes]
17
+ };
18
+ };
19
+
20
+ export let anyOf = (...scopes: SlateActionScopeValue[]): SlateActionScopes => ({
21
+ AND: [scopeClause(...scopes)]
22
+ });
23
+
24
+ export let allOf = (...inputs: SlateActionScopesInput[]): SlateActionScopes => {
25
+ let AND = inputs.flatMap(input => normalizeScopes(input).AND);
26
+ return validateScopes({ AND });
27
+ };
28
+
29
+ export let mergeScopes = (
30
+ ...inputs: Array<SlateActionScopes | null | undefined | false>
31
+ ): SlateActionScopes | undefined => {
32
+ let AND = inputs.flatMap(input => (input ? input.AND : []));
33
+ if (AND.length === 0) {
34
+ return undefined;
35
+ }
36
+
37
+ return validateScopes({ AND });
38
+ };
39
+
40
+ export let validateScopes = (scopes: SlateActionScopes): SlateActionScopes => {
41
+ if (!Array.isArray(scopes.AND) || scopes.AND.length === 0) {
42
+ throw new SlateDeclarationError('Action scopes must include at least one AND clause');
43
+ }
44
+
45
+ return {
46
+ AND: scopes.AND.map(clause => normalizeClause(clause))
47
+ };
48
+ };
49
+
50
+ let normalizeScopes = (input: SlateActionScopesInput): SlateActionScopes => {
51
+ if (isScopes(input)) {
52
+ return validateScopes(input);
53
+ }
54
+
55
+ return {
56
+ AND: [normalizeClause(input)]
57
+ };
58
+ };
59
+
60
+ let normalizeClause = (input: SlateActionScopeClauseInput): SlateActionScopeClause => {
61
+ if (typeof input === 'string') {
62
+ return scopeClause(input);
63
+ }
64
+
65
+ if (Array.isArray(input)) {
66
+ return scopeClause(...input);
67
+ }
68
+
69
+ if (!isClause(input)) {
70
+ throw new SlateDeclarationError('Action scope clauses must be strings or OR clauses');
71
+ }
72
+
73
+ assertScopeValues(input.OR);
74
+ return {
75
+ OR: [...input.OR]
76
+ };
77
+ };
78
+
79
+ let assertScopeValues = (scopes: readonly SlateActionScopeValue[]) => {
80
+ if (scopes.length === 0) {
81
+ throw new SlateDeclarationError(
82
+ 'Each action scope clause must include at least one OR scope'
83
+ );
84
+ }
85
+
86
+ for (let scope of scopes) {
87
+ if (typeof scope !== 'string' || scope.trim().length === 0) {
88
+ throw new SlateDeclarationError('Action scopes must be non-empty strings');
89
+ }
90
+ }
91
+ };
92
+
93
+ let isClause = (value: unknown): value is SlateActionScopeClause =>
94
+ typeof value === 'object' &&
95
+ value !== null &&
96
+ 'OR' in value &&
97
+ Array.isArray((value as SlateActionScopeClause).OR);
98
+
99
+ let isScopes = (value: unknown): value is SlateActionScopes =>
100
+ typeof value === 'object' &&
101
+ value !== null &&
102
+ 'AND' in value &&
103
+ Array.isArray((value as SlateActionScopes).AND);
@@ -1,6 +1,10 @@
1
- import z from 'zod';
2
- import { SlateSpecification } from '../specification/specification';
3
- import { SlateAction, SlateActionParameters, SlateToolInvocationHandler } from './action';
1
+ import type z from 'zod';
2
+ import type { SlateSpecification } from '../specification/specification';
3
+ import {
4
+ SlateAction,
5
+ type SlateActionParameters,
6
+ type SlateToolInvocationHandler
7
+ } from './action';
4
8
  import { SlateActionBuilder } from './builder';
5
9
 
6
10
  export interface SlateToolParameters<
@@ -20,7 +24,7 @@ export class SlateTool<
20
24
  > extends SlateAction<'tool', ConfigType, AuthType, InputType, OutputType> {
21
25
  #handleInvocation: SlateToolInvocationHandler<ConfigType, AuthType, InputType, OutputType>;
22
26
 
23
- private constructor(
27
+ protected constructor(
24
28
  spec: SlateSpecification<ConfigType, AuthType>,
25
29
  inputSchema: z.ZodType<InputType>,
26
30
  outputSchema: z.ZodType<OutputType>,
@@ -36,11 +40,23 @@ export class SlateTool<
36
40
  params: SlateActionParameters
37
41
  ) {
38
42
  return new SlateActionBuilder('tool', spec, params, params => {
39
- if (params.type != 'tool') throw new Error('Invalid action type for tool');
40
- return new SlateTool(spec, params.inputSchema, params.outputSchema, params);
43
+ return SlateTool.fromCreateParameters(spec, params);
41
44
  });
42
45
  }
43
46
 
47
+ static fromCreateParameters<ConfigType extends {}, AuthType extends {}>(
48
+ spec: SlateSpecification<ConfigType, AuthType>,
49
+ params: {
50
+ type: string;
51
+ inputSchema: z.ZodType<any>;
52
+ outputSchema: z.ZodType<any>;
53
+ handleInvocation?: SlateToolInvocationHandler<ConfigType, AuthType, any, any>;
54
+ } & SlateActionParameters
55
+ ) {
56
+ if (params.type !== 'tool') throw new Error('Invalid action type for tool');
57
+ return new SlateTool(spec, params.inputSchema, params.outputSchema, params as any);
58
+ }
59
+
44
60
  get handleInvocation() {
45
61
  return this.#handleInvocation;
46
62
  }
@@ -1,18 +1,19 @@
1
- import z from 'zod';
2
- import { SlateSpecification } from '../specification/specification';
1
+ import type z from 'zod';
2
+ import type { SlateSpecification } from '../specification/specification';
3
3
  import {
4
4
  SlateAction,
5
- SlateActionParameters,
6
- SlatePollingOptions,
7
- SlateTriggerMappingHandler,
8
- SlateTriggerPollingHandler,
9
- SlateTriggerWebhookAutoRegistrationHandler,
10
- SlateTriggerWebhookAutoUnregistrationHandler,
11
- SlateTriggerWebhookRequestHandler
5
+ type SlateActionParameters,
6
+ type SlatePollingOptions,
7
+ type SlateTriggerMappingHandler,
8
+ type SlateTriggerPollingHandler,
9
+ type SlateTriggerWebhookAutoRegistrationHandler,
10
+ type SlateTriggerWebhookAutoUnregistrationHandler,
11
+ type SlateTriggerWebhookRequestHandler,
12
+ type SlateWebhookHttpOptions
12
13
  } from './action';
13
14
  import { SlateActionBuilder } from './builder';
14
15
 
15
- export const SlateDefaultPollingIntervalSeconds = 60 * 10;
16
+ export let SlateDefaultPollingIntervalSeconds = 60 * 10;
16
17
 
17
18
  export interface SlateTriggerParameters<
18
19
  ConfigType extends {},
@@ -27,6 +28,7 @@ export interface SlateTriggerParameters<
27
28
  polling?: SlatePollingOptions;
28
29
  handleEvent: SlateTriggerMappingHandler<ConfigType, AuthType, InputType, OutputType>;
29
30
  handleRequest?: SlateTriggerWebhookRequestHandler<ConfigType, AuthType, InputType>;
31
+ http?: SlateWebhookHttpOptions;
30
32
  pollEvents?: SlateTriggerPollingHandler<ConfigType, AuthType, InputType>;
31
33
  autoRegisterWebhook?: SlateTriggerWebhookAutoRegistrationHandler<ConfigType, AuthType>;
32
34
  autoUnregisterWebhook?: SlateTriggerWebhookAutoUnregistrationHandler<ConfigType, AuthType>;
@@ -44,6 +46,7 @@ export class SlateTrigger<
44
46
  #polling: SlatePollingOptions;
45
47
  #handleEvent: SlateTriggerMappingHandler<ConfigType, AuthType, InputType, OutputType>;
46
48
  #handleRequest?: SlateTriggerWebhookRequestHandler<ConfigType, AuthType, InputType>;
49
+ #http?: SlateWebhookHttpOptions;
47
50
  #pollEvents?: SlateTriggerPollingHandler<ConfigType, AuthType, InputType>;
48
51
  #autoRegisterWebhook?: SlateTriggerWebhookAutoRegistrationHandler<ConfigType, AuthType>;
49
52
  #autoUnregisterWebhook?: SlateTriggerWebhookAutoUnregistrationHandler<ConfigType, AuthType>;
@@ -62,6 +65,7 @@ export class SlateTrigger<
62
65
  };
63
66
  this.#handleEvent = params.handleEvent;
64
67
  this.#handleRequest = params.handleRequest;
68
+ this.#http = params.http;
65
69
  this.#pollEvents = params.pollEvents;
66
70
  this.#autoRegisterWebhook = params.autoRegisterWebhook;
67
71
  this.#autoUnregisterWebhook = params.autoUnregisterWebhook;
@@ -72,7 +76,7 @@ export class SlateTrigger<
72
76
  params: SlateActionParameters
73
77
  ) {
74
78
  return new SlateActionBuilder('trigger', spec, params, params => {
75
- if (params.type != 'trigger') throw new Error('Invalid action type for trigger');
79
+ if (params.type !== 'trigger') throw new Error('Invalid action type for trigger');
76
80
  return new SlateTrigger(spec, params.inputSchema, params.outputSchema, params);
77
81
  });
78
82
  }
@@ -93,6 +97,10 @@ export class SlateTrigger<
93
97
  return this.#handleRequest;
94
98
  }
95
99
 
100
+ get http() {
101
+ return this.#http;
102
+ }
103
+
96
104
  get pollEvents() {
97
105
  return this.#pollEvents;
98
106
  }
@@ -0,0 +1,38 @@
1
+ import type { SlateTool, SlateTrigger } from '../action';
2
+ import type { SlateAdapterSpec } from './spec';
3
+
4
+ export class SlateAdapter<ConfigType extends {}, AuthType extends {}> {
5
+ constructor(
6
+ private readonly _spec: SlateAdapterSpec,
7
+ private readonly _tools: SlateTool<ConfigType, AuthType, any, any>[],
8
+ private readonly _triggers: SlateTrigger<ConfigType, AuthType, any, any>[]
9
+ ) {}
10
+
11
+ get spec() {
12
+ return this._spec;
13
+ }
14
+
15
+ get id() {
16
+ return this._spec.id;
17
+ }
18
+
19
+ get name() {
20
+ return this._spec.name;
21
+ }
22
+
23
+ get capabilities() {
24
+ return this._spec.capabilities;
25
+ }
26
+
27
+ get tools() {
28
+ return this._tools;
29
+ }
30
+
31
+ get triggers() {
32
+ return this._triggers;
33
+ }
34
+
35
+ get actions() {
36
+ return [...this._triggers, ...this._tools];
37
+ }
38
+ }