@segment/actions-core 1.3.0-next.0

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 (81) hide show
  1. package/dist/cjs/create-request-client.d.ts +5 -0
  2. package/dist/cjs/create-request-client.js +24 -0
  3. package/dist/cjs/dayjs.d.ts +2 -0
  4. package/dist/cjs/dayjs.js +10 -0
  5. package/dist/cjs/defaults.d.ts +2 -0
  6. package/dist/cjs/defaults.js +15 -0
  7. package/dist/cjs/destination-kit/action.d.ts +86 -0
  8. package/dist/cjs/destination-kit/action.js +217 -0
  9. package/dist/cjs/destination-kit/fields-to-jsonschema.d.ts +4 -0
  10. package/dist/cjs/destination-kit/fields-to-jsonschema.js +38 -0
  11. package/dist/cjs/destination-kit/index.d.ts +84 -0
  12. package/dist/cjs/destination-kit/index.js +165 -0
  13. package/dist/cjs/destination-kit/step.d.ts +38 -0
  14. package/dist/cjs/destination-kit/step.js +54 -0
  15. package/dist/cjs/destination-kit/types.d.ts +39 -0
  16. package/dist/cjs/destination-kit/types.js +3 -0
  17. package/dist/cjs/get.d.ts +5 -0
  18. package/dist/cjs/get.js +22 -0
  19. package/dist/cjs/index.d.ts +12 -0
  20. package/dist/cjs/index.js +26 -0
  21. package/dist/cjs/json-object.d.ts +11 -0
  22. package/dist/cjs/json-object.js +3 -0
  23. package/dist/cjs/mapping-kit/index.d.ts +8 -0
  24. package/dist/cjs/mapping-kit/index.js +182 -0
  25. package/dist/cjs/mapping-kit/is-directive.d.ts +2 -0
  26. package/dist/cjs/mapping-kit/is-directive.js +22 -0
  27. package/dist/cjs/mapping-kit/placeholders.d.ts +4 -0
  28. package/dist/cjs/mapping-kit/placeholders.js +51 -0
  29. package/dist/cjs/mapping-kit/validate.d.ts +1 -0
  30. package/dist/cjs/mapping-kit/validate.js +280 -0
  31. package/dist/cjs/omit.d.ts +4 -0
  32. package/dist/cjs/omit.js +15 -0
  33. package/dist/cjs/real-type-of.d.ts +12 -0
  34. package/dist/cjs/real-type-of.js +25 -0
  35. package/dist/cjs/remove-undefined.d.ts +1 -0
  36. package/dist/cjs/remove-undefined.js +24 -0
  37. package/dist/cjs/segment-event.d.ts +127 -0
  38. package/dist/cjs/segment-event.js +3 -0
  39. package/dist/cjs/time.d.ts +8 -0
  40. package/dist/cjs/time.js +18 -0
  41. package/dist/esm/create-request-client.d.ts +5 -0
  42. package/dist/esm/create-request-client.js +18 -0
  43. package/dist/esm/dayjs.d.ts +2 -0
  44. package/dist/esm/dayjs.js +5 -0
  45. package/dist/esm/defaults.d.ts +2 -0
  46. package/dist/esm/defaults.js +11 -0
  47. package/dist/esm/destination-kit/action.d.ts +86 -0
  48. package/dist/esm/destination-kit/action.js +209 -0
  49. package/dist/esm/destination-kit/fields-to-jsonschema.d.ts +4 -0
  50. package/dist/esm/destination-kit/fields-to-jsonschema.js +33 -0
  51. package/dist/esm/destination-kit/index.d.ts +84 -0
  52. package/dist/esm/destination-kit/index.js +157 -0
  53. package/dist/esm/destination-kit/step.d.ts +38 -0
  54. package/dist/esm/destination-kit/step.js +49 -0
  55. package/dist/esm/destination-kit/types.d.ts +39 -0
  56. package/dist/esm/destination-kit/types.js +2 -0
  57. package/dist/esm/get.d.ts +5 -0
  58. package/dist/esm/get.js +18 -0
  59. package/dist/esm/index.d.ts +12 -0
  60. package/dist/esm/index.js +9 -0
  61. package/dist/esm/json-object.d.ts +11 -0
  62. package/dist/esm/json-object.js +2 -0
  63. package/dist/esm/mapping-kit/index.d.ts +8 -0
  64. package/dist/esm/mapping-kit/index.js +175 -0
  65. package/dist/esm/mapping-kit/is-directive.d.ts +2 -0
  66. package/dist/esm/mapping-kit/is-directive.js +18 -0
  67. package/dist/esm/mapping-kit/placeholders.d.ts +4 -0
  68. package/dist/esm/mapping-kit/placeholders.js +47 -0
  69. package/dist/esm/mapping-kit/validate.d.ts +1 -0
  70. package/dist/esm/mapping-kit/validate.js +274 -0
  71. package/dist/esm/omit.d.ts +4 -0
  72. package/dist/esm/omit.js +11 -0
  73. package/dist/esm/real-type-of.d.ts +12 -0
  74. package/dist/esm/real-type-of.js +18 -0
  75. package/dist/esm/remove-undefined.d.ts +1 -0
  76. package/dist/esm/remove-undefined.js +20 -0
  77. package/dist/esm/segment-event.d.ts +127 -0
  78. package/dist/esm/segment-event.js +2 -0
  79. package/dist/esm/time.d.ts +8 -0
  80. package/dist/esm/time.js +13 -0
  81. package/package.json +74 -0
@@ -0,0 +1,11 @@
1
+ export function defaultValues(fields) {
2
+ const obj = {};
3
+ for (const field of Object.keys(fields)) {
4
+ const defaultValue = fields[field].default;
5
+ if (typeof defaultValue !== 'undefined') {
6
+ obj[field] = defaultValue;
7
+ }
8
+ }
9
+ return obj;
10
+ }
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGVmYXVsdHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsTUFBTSxVQUFVLGFBQWEsQ0FBQyxNQUErQjtJQUMzRCxNQUFNLEdBQUcsR0FBb0MsRUFBRSxDQUFBO0lBRS9DLEtBQUssTUFBTSxLQUFLLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRTtRQUN2QyxNQUFNLFlBQVksR0FBSSxNQUFNLENBQUMsS0FBSyxDQUFpQixDQUFDLE9BQU8sQ0FBQTtRQUMzRCxJQUFJLE9BQU8sWUFBWSxLQUFLLFdBQVcsRUFBRTtZQUN2QyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsWUFBWSxDQUFBO1NBQzFCO0tBQ0Y7SUFFRCxPQUFPLEdBQUcsQ0FBQTtBQUNaLENBQUMifQ==
@@ -0,0 +1,86 @@
1
+ /// <reference types="node" />
2
+ import Ajv from 'ajv';
3
+ import { EventEmitter } from 'events';
4
+ import { Got } from 'got';
5
+ import { JSONLikeObject } from '../json-object';
6
+ import { ExecuteInput, Step, StepResult, Steps } from './step';
7
+ import type { InputField, RequestExtension } from './types';
8
+ export declare type RequestFn<Settings, Payload> = (request: Got, data: ExecuteInput<Settings, Payload>) => any;
9
+ export interface ActionDefinition<Settings, Payload = any> {
10
+ /** The unique identifier for the action, e.g. `postToChannel` */
11
+ /** The display title of the action */
12
+ title: string;
13
+ /** The display description of the action */
14
+ description: string;
15
+ /** Whether the action is recommended for quick setup */
16
+ recommended?: boolean;
17
+ /** An optional fql query that will be used to prepopulate the action when it is first set up */
18
+ defaultSubscription?: string;
19
+ /** Whether or not this action should be visible/configurable in the UI */
20
+ hidden?: boolean;
21
+ /**
22
+ * The fields used to perform the action. These fields should match what the partner API expects.
23
+ *
24
+ * This is a set of JSON Schema properties right now.
25
+ * We may eventually auto-generate the JSON Schema from a definition object
26
+ * instead of requiring devs to build and modify JSON Schema directly.
27
+ *
28
+ * Plus, JSON Schema cannot fully represent our action or field definitions
29
+ * without many custom keywords.
30
+ */
31
+ fields: Record<string, InputField>;
32
+ /**
33
+ * Temporary way to "register" autocomplete fields.
34
+ * This is likely going to change as we productionalize the data model and definition object
35
+ */
36
+ autocompleteFields?: {
37
+ [K in keyof Payload]?: RequestFn<Settings, Payload>;
38
+ };
39
+ /**
40
+ * Register fields that should be executed, cached and provided
41
+ * to the action's `perform` function
42
+ */
43
+ cachedFields?: {
44
+ [field: string]: {
45
+ key: (data: ExecuteInput<Settings, Payload>) => string;
46
+ ttl: number;
47
+ value: RequestFn<Settings, Payload>;
48
+ negative?: boolean;
49
+ };
50
+ };
51
+ /** The operation to perform when this action is triggered */
52
+ perform: RequestFn<Settings, Payload>;
53
+ }
54
+ export declare class Validate<Settings, Payload> extends Step<Settings, Payload> {
55
+ field: ExecuteInputField;
56
+ validate: Ajv.ValidateFunction;
57
+ constructor(field: ExecuteInputField, schema: object);
58
+ executeStep(data: ExecuteInput<Settings, Payload>): Promise<string>;
59
+ }
60
+ interface ExecuteAutocompleteInput<Settings, Payload> {
61
+ settings: Settings;
62
+ payload: Payload;
63
+ cachedFields: {
64
+ [key: string]: string;
65
+ };
66
+ page?: string;
67
+ }
68
+ declare type ExecuteInputField = 'payload' | 'settings';
69
+ /**
70
+ * Action is the beginning step for all partner actions. Entrypoints always start with the
71
+ * MapAndValidateInput step.
72
+ */
73
+ export declare class Action<Settings, Payload extends JSONLikeObject> extends EventEmitter {
74
+ readonly steps: Steps<Settings, Payload>;
75
+ private requestExtensions;
76
+ private autocompleteCache;
77
+ constructor(definition: ActionDefinition<Settings, Payload>, extendRequest?: RequestExtension<Settings, Payload>);
78
+ execute(data: ExecuteInput<Settings, Payload>): Promise<StepResult[]>;
79
+ executeAutocomplete(field: string, data: ExecuteAutocompleteInput<Settings, Payload>): any;
80
+ private loadDefinition;
81
+ private validatePayload;
82
+ private autocomplete;
83
+ private request;
84
+ private cachedRequest;
85
+ }
86
+ export {};
@@ -0,0 +1,209 @@
1
+ // @ts-ignore no types
2
+ import { AggregateAjvError } from '@segment/ajv-human-errors';
3
+ import Ajv from 'ajv';
4
+ import { EventEmitter } from 'events';
5
+ import NodeCache from 'node-cache';
6
+ import createRequestClient from '../create-request-client';
7
+ import { get } from '../get';
8
+ import { transform } from '../mapping-kit';
9
+ import { fieldsToJsonSchema } from './fields-to-jsonschema';
10
+ import { Step, Steps } from './step';
11
+ class MapInput extends Step {
12
+ executeStep(data) {
13
+ // Transforms the initial payload (event) + action settings (from `subscriptions[0].mapping`)
14
+ // into input data that the action can use to talk to partner apis
15
+ if (data.mapping) {
16
+ // Technically we can't know whether or not `transform` returns the exact shape of Payload here, hence the casting
17
+ // It will be validated in subsequent steps
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ data.payload = transform(data.mapping, data.payload);
20
+ }
21
+ return Promise.resolve('MapInput completed');
22
+ }
23
+ }
24
+ export class Validate extends Step {
25
+ constructor(field, schema) {
26
+ super();
27
+ this.field = field;
28
+ const ajv = new Ajv({
29
+ // Coerce types to be a bit more liberal.
30
+ coerceTypes: true,
31
+ // Return all validation errors, not just the first.
32
+ allErrors: true,
33
+ // Include reference to schema and data in error values.
34
+ verbose: true,
35
+ // Use a more parse-able format for JSON paths.
36
+ jsonPointers: true
37
+ });
38
+ this.validate = ajv.compile(schema);
39
+ }
40
+ executeStep(data) {
41
+ if (!this.validate(data[this.field])) {
42
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
43
+ throw new AggregateAjvError(this.validate.errors);
44
+ }
45
+ return Promise.resolve('Validate completed');
46
+ }
47
+ }
48
+ /**
49
+ * Request handles delivering a payload to an external API. It uses the `got` library under the hood.
50
+ *
51
+ * The callback should be able to return the raw request instead of needing to do `return response.data` etc.
52
+ */
53
+ class Request extends Step {
54
+ constructor(extensions, requestFn) {
55
+ super();
56
+ this.extensions = extensions || [];
57
+ this.requestFn = requestFn;
58
+ }
59
+ async executeStep(data) {
60
+ if (!this.requestFn) {
61
+ return '';
62
+ }
63
+ const request = this.createRequestClient(data);
64
+ const response = await this.requestFn(request, data);
65
+ if (response === null) {
66
+ return 'TODO: null';
67
+ }
68
+ return response.body;
69
+ }
70
+ createRequestClient(data) {
71
+ const options = this.extensions.map((extension) => extension(data));
72
+ const client = createRequestClient(...options).extend({
73
+ hooks: {
74
+ beforeError: [
75
+ (error) => {
76
+ // @ts-ignore the type is wrong in got
77
+ const { response } = error;
78
+ this.emit('response', response);
79
+ return error;
80
+ }
81
+ ],
82
+ afterResponse: [
83
+ (response) => {
84
+ this.emit('response', response);
85
+ return response;
86
+ }
87
+ ]
88
+ }
89
+ });
90
+ return client;
91
+ }
92
+ }
93
+ // CachedRequest is like Request but cached. Next question.
94
+ class CachedRequest extends Request {
95
+ constructor(extensions, config) {
96
+ super(extensions);
97
+ this.keyFn = config.key;
98
+ this.valueFn = config.value;
99
+ this.as = config.as;
100
+ this.negative = config.negative || false;
101
+ this.cache = new NodeCache({
102
+ stdTTL: config.ttl,
103
+ maxKeys: 1000
104
+ });
105
+ }
106
+ async executeStep(data) {
107
+ const k = this.keyFn(data);
108
+ let v = this.cache.get(k);
109
+ if (v !== undefined) {
110
+ data.cachedFields[this.as] = v;
111
+ return 'cache hit';
112
+ }
113
+ const request = this.createRequestClient(data);
114
+ try {
115
+ v = await this.valueFn(request, data);
116
+ }
117
+ catch (e) {
118
+ if (get(e, 'response.statusCode') === 404) {
119
+ v = undefined;
120
+ }
121
+ else {
122
+ throw e;
123
+ }
124
+ }
125
+ // Only cache if value is not negative *or* negative option is set. Negative caching is off by
126
+ // default because the common cases are: A) auth token generation, which should never be
127
+ // negative, and B) create-or-update patterns, where the resource should exist after the first
128
+ // negative value.
129
+ if ((v !== null && v !== undefined) || this.negative) {
130
+ this.cache.set(k, v);
131
+ }
132
+ return 'cache miss';
133
+ }
134
+ }
135
+ /**
136
+ * Action is the beginning step for all partner actions. Entrypoints always start with the
137
+ * MapAndValidateInput step.
138
+ */
139
+ export class Action extends EventEmitter {
140
+ constructor(definition, extendRequest) {
141
+ super();
142
+ this.steps = new Steps();
143
+ const step = new MapInput();
144
+ this.steps.push(step);
145
+ this.autocompleteCache = {};
146
+ this.requestExtensions = [];
147
+ if (extendRequest) {
148
+ // This must come before we load the definition because
149
+ // it instantiates "steps" with whatever request extensions
150
+ // are defined at that moment in time
151
+ this.requestExtensions.push(extendRequest);
152
+ }
153
+ this.loadDefinition(definition);
154
+ }
155
+ async execute(data) {
156
+ const results = await this.steps.execute(data);
157
+ const finalResult = results[results.length - 1];
158
+ if (finalResult.error) {
159
+ throw finalResult.error;
160
+ }
161
+ return results;
162
+ }
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
+ executeAutocomplete(field, data) {
165
+ if (!this.autocompleteCache[field]) {
166
+ return {
167
+ data: [],
168
+ pagination: {}
169
+ };
170
+ }
171
+ const step = new Request(this.requestExtensions, this.autocompleteCache[field]);
172
+ return step.executeStep(data);
173
+ }
174
+ loadDefinition(definition) {
175
+ var _a, _b;
176
+ if (definition.fields) {
177
+ this.validatePayload(definition.fields);
178
+ }
179
+ Object.entries((_a = definition.autocompleteFields) !== null && _a !== void 0 ? _a : {}).forEach(([field, callback]) => {
180
+ this.autocomplete(field, callback);
181
+ });
182
+ Object.entries((_b = definition.cachedFields) !== null && _b !== void 0 ? _b : {}).forEach(([field, cacheConfig]) => {
183
+ this.cachedRequest({
184
+ ...cacheConfig,
185
+ as: field
186
+ });
187
+ });
188
+ if (definition.perform) {
189
+ this.request(definition.perform);
190
+ }
191
+ }
192
+ validatePayload(fields) {
193
+ const step = new Validate('payload', fieldsToJsonSchema(fields));
194
+ this.steps.push(step);
195
+ }
196
+ autocomplete(field, callback) {
197
+ this.autocompleteCache[field] = callback;
198
+ }
199
+ request(requestFn) {
200
+ const step = new Request(this.requestExtensions, requestFn);
201
+ step.on('response', (response) => this.emit('response', response));
202
+ this.steps.push(step);
203
+ }
204
+ cachedRequest(config) {
205
+ const step = new CachedRequest(this.requestExtensions, config);
206
+ this.steps.push(step);
207
+ }
208
+ }
209
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Rlc3RpbmF0aW9uLWtpdC9hY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsc0JBQXNCO0FBQ3RCLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDJCQUEyQixDQUFBO0FBQzdELE9BQU8sR0FBRyxNQUFNLEtBQUssQ0FBQTtBQUNyQixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sUUFBUSxDQUFBO0FBRXJDLE9BQU8sU0FBUyxNQUFNLFlBQVksQ0FBQTtBQUNsQyxPQUFPLG1CQUFtQixNQUFNLDBCQUEwQixDQUFBO0FBQzFELE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxRQUFRLENBQUE7QUFFNUIsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBQzFDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHdCQUF3QixDQUFBO0FBQzNELE9BQU8sRUFBZ0IsSUFBSSxFQUFjLEtBQUssRUFBRSxNQUFNLFFBQVEsQ0FBQTtBQStEOUQsTUFBTSxRQUFtRCxTQUFRLElBQXVCO0lBQ3RGLFdBQVcsQ0FBQyxJQUFxQztRQUMvQyw2RkFBNkY7UUFDN0Ysa0VBQWtFO1FBQ2xFLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNoQixrSEFBa0g7WUFDbEgsMkNBQTJDO1lBQzNDLDhEQUE4RDtZQUM5RCxJQUFJLENBQUMsT0FBTyxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFjLENBQVksQ0FBQTtTQUN2RTtRQUVELE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFBO0lBQzlDLENBQUM7Q0FDRjtBQUVELE1BQU0sT0FBTyxRQUE0QixTQUFRLElBQXVCO0lBSXRFLFlBQVksS0FBd0IsRUFBRSxNQUFjO1FBQ2xELEtBQUssRUFBRSxDQUFBO1FBRVAsSUFBSSxDQUFDLEtBQUssR0FB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
@@ -0,0 +1,4 @@
1
+ import { JSONSchema4 } from 'json-schema';
2
+ import type { InputField } from './types';
3
+ export declare function fieldsToJsonSchema(fields?: Record<string, InputField>): JSONSchema4;
4
+ export declare function jsonSchemaToFields(schema?: JSONSchema4): Record<string, InputField>;
@@ -0,0 +1,33 @@
1
+ export function fieldsToJsonSchema(fields = {}) {
2
+ const required = [];
3
+ const properties = {};
4
+ for (const key of Object.keys(fields)) {
5
+ const field = fields[key];
6
+ // Remove the `required` property from fields because it'll get lifted up into an array of required keys
7
+ properties[key] = Object.assign({}, field);
8
+ delete properties[key].required;
9
+ // Grab all the field keys with `required: true`
10
+ if (field.required) {
11
+ required.push(key);
12
+ }
13
+ }
14
+ return {
15
+ $schema: 'http://json-schema.org/schema#',
16
+ type: 'object',
17
+ additionalProperties: false,
18
+ properties,
19
+ required
20
+ };
21
+ }
22
+ export function jsonSchemaToFields(schema = {}) {
23
+ var _a, _b;
24
+ const requiredFields = (_a = schema.required) !== null && _a !== void 0 ? _a : [];
25
+ const properties = (_b = schema.properties) !== null && _b !== void 0 ? _b : {};
26
+ for (const key of Object.keys(properties)) {
27
+ if (requiredFields.includes(key)) {
28
+ properties[key].required = true;
29
+ }
30
+ }
31
+ return properties;
32
+ }
33
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmllbGRzLXRvLWpzb25zY2hlbWEuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZGVzdGluYXRpb24ta2l0L2ZpZWxkcy10by1qc29uc2NoZW1hLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxTQUFxQyxFQUFFO0lBQ3hFLE1BQU0sUUFBUSxHQUFhLEVBQUUsQ0FBQTtJQUM3QixNQUFNLFVBQVUsR0FBZ0MsRUFBRSxDQUFBO0lBRWxELEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRTtRQUNyQyxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7UUFFekIsd0dBQXdHO1FBQ3hHLFVBQVUsQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQWdCLENBQUE7UUFDekQsT0FBTyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFBO1FBRS9CLGdEQUFnRDtRQUNoRCxJQUFJLEtBQUssQ0FBQyxRQUFRLEVBQUU7WUFDbEIsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtTQUNuQjtLQUNGO0lBRUQsT0FBTztRQUNMLE9BQU8sRUFBRSxnQ0FBZ0M7UUFDekMsSUFBSSxFQUFFLFFBQVE7UUFDZCxvQkFBb0IsRUFBRSxLQUFLO1FBQzNCLFVBQVU7UUFDVixRQUFRO0tBQ1QsQ0FBQTtBQUNILENBQUM7QUFFRCxNQUFNLFVBQVUsa0JBQWtCLENBQUMsU0FBc0IsRUFBRTs7SUFDekQsTUFBTSxjQUFjLFNBQUksTUFBTSxDQUFDLFFBQXFCLG1DQUFJLEVBQUUsQ0FBQTtJQUMxRCxNQUFNLFVBQVUsU0FBSSxNQUFNLENBQUMsVUFBeUMsbUNBQUksRUFBRSxDQUFBO0lBRTFFLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRTtRQUN6QyxJQUFJLGNBQWMsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDaEMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUE7U0FDaEM7S0FDRjtJQUVELE9BQU8sVUFBVSxDQUFBO0FBQ25CLENBQUMifQ==
@@ -0,0 +1,84 @@
1
+ import { CancelableRequest, Got, Response } from 'got';
2
+ import { JSONSchema4 } from 'json-schema';
3
+ import { Action, ActionDefinition } from './action';
4
+ import { ExecuteInput, StepResult } from './step';
5
+ import { JSONLikeObject, JSONObject } from '../json-object';
6
+ import { SegmentEvent } from '../segment-event';
7
+ import { fieldsToJsonSchema, jsonSchemaToFields } from './fields-to-jsonschema';
8
+ import type { InputField, RequestExtension } from './types';
9
+ export type { ActionDefinition, ExecuteInput };
10
+ export { fieldsToJsonSchema, jsonSchemaToFields };
11
+ export interface SubscriptionStats {
12
+ duration: number;
13
+ destination: string;
14
+ action: string;
15
+ subscribe: string;
16
+ state: string;
17
+ input: JSONLikeObject;
18
+ output: StepResult[] | null;
19
+ }
20
+ interface PartnerActions<Settings, Payload extends JSONLikeObject> {
21
+ [key: string]: Action<Settings, Payload>;
22
+ }
23
+ export interface DestinationDefinition<Settings = unknown> {
24
+ /** The name of the destination */
25
+ name: string;
26
+ /** An optional function to extend requests sent from the destination (including all actions) */
27
+ extendRequest?: RequestExtension<Settings>;
28
+ /** Optional authentication configuration */
29
+ authentication?: AuthenticationScheme<Settings>;
30
+ /** Actions */
31
+ actions: {
32
+ [key: string]: ActionDefinition<Settings>;
33
+ };
34
+ /** Subscription presets automatically applied in quick setup */
35
+ presets?: Subscription[];
36
+ }
37
+ export interface Subscription {
38
+ name?: string;
39
+ partnerAction: string;
40
+ subscribe: string;
41
+ mapping?: JSONObject;
42
+ }
43
+ interface TestAuthSettings<Settings> {
44
+ settings: Settings;
45
+ }
46
+ interface Authentication<Settings> {
47
+ scheme: 'basic' | 'custom';
48
+ fields: Record<string, InputField>;
49
+ testAuthentication: (req: Got, input: TestAuthSettings<Settings>) => CancelableRequest<Response<string>>;
50
+ }
51
+ export interface CustomAuthentication<Settings> extends Authentication<Settings> {
52
+ /** Typically used for "API Key" authentication. */
53
+ scheme: 'custom';
54
+ }
55
+ export interface BasicAuthentication<Settings> extends Authentication<Settings> {
56
+ scheme: 'basic';
57
+ }
58
+ export declare type AuthenticationScheme<Settings = any> = BasicAuthentication<Settings> | CustomAuthentication<Settings>;
59
+ interface EventInput<Settings> {
60
+ readonly event: SegmentEvent;
61
+ readonly mapping: JSONObject;
62
+ readonly settings: Settings;
63
+ }
64
+ export declare class Destination<Settings = JSONObject> {
65
+ readonly definition: DestinationDefinition<Settings>;
66
+ readonly name: string;
67
+ readonly authentication?: AuthenticationScheme<Settings>;
68
+ readonly extendRequest?: RequestExtension<Settings>;
69
+ readonly actions: PartnerActions<Settings, any>;
70
+ readonly responses: Response[];
71
+ readonly settingsSchema?: JSONSchema4;
72
+ constructor(destination: DestinationDefinition<Settings>);
73
+ testAuthentication(settings: Settings): Promise<void>;
74
+ private partnerAction;
75
+ protected executeAction(actionSlug: string, { event, mapping, settings }: EventInput<Settings>): Promise<StepResult[]>;
76
+ private onSubscription;
77
+ /**
78
+ * Note: Until we move subscriptions upstream (into int-consumer) we've opted
79
+ * to have failures abort the set of subscriptions and get potentially retried by centrifuge
80
+ */
81
+ onEvent(event: SegmentEvent, settings: JSONObject, onComplete?: (stats: SubscriptionStats) => void): Promise<StepResult[]>;
82
+ private getSubscriptions;
83
+ private getDestinationSettings;
84
+ }
@@ -0,0 +1,157 @@
1
+ import { validate, parseFql } from '@segment/fab5-subscriptions';
2
+ import { BadRequest } from 'http-errors';
3
+ import got from 'got';
4
+ import { Action, Validate } from './action';
5
+ import { time, duration } from '../time';
6
+ import { fieldsToJsonSchema, jsonSchemaToFields } from './fields-to-jsonschema';
7
+ export { fieldsToJsonSchema, jsonSchemaToFields };
8
+ export class Destination {
9
+ constructor(destination) {
10
+ var _a;
11
+ this.definition = destination;
12
+ this.name = destination.name;
13
+ this.extendRequest = destination.extendRequest;
14
+ this.actions = {};
15
+ this.authentication = destination.authentication;
16
+ this.responses = [];
17
+ // Convert to complete JSON Schema
18
+ if ((_a = this.authentication) === null || _a === void 0 ? void 0 : _a.fields) {
19
+ this.settingsSchema = fieldsToJsonSchema(this.authentication.fields);
20
+ }
21
+ for (const action of Object.keys(destination.actions)) {
22
+ this.partnerAction(action, destination.actions[action]);
23
+ }
24
+ }
25
+ async testAuthentication(settings) {
26
+ var _a;
27
+ const context = { settings, payload: {}, cachedFields: {} };
28
+ if (this.settingsSchema) {
29
+ const step = new Validate('settings', this.settingsSchema);
30
+ await step.executeStep(context);
31
+ }
32
+ if (!((_a = this.authentication) === null || _a === void 0 ? void 0 : _a.testAuthentication)) {
33
+ return;
34
+ }
35
+ let request = got.extend({
36
+ retry: 0,
37
+ timeout: 3000,
38
+ headers: {
39
+ 'user-agent': undefined
40
+ }
41
+ });
42
+ if (typeof this.extendRequest === 'function') {
43
+ request = request.extend(this.extendRequest(context));
44
+ }
45
+ try {
46
+ await this.authentication.testAuthentication(request, { settings });
47
+ }
48
+ catch (error) {
49
+ throw new Error('Credentials are invalid');
50
+ }
51
+ }
52
+ partnerAction(slug, definition) {
53
+ const action = new Action(definition, this.extendRequest);
54
+ action.on('response', (response) => {
55
+ if (response) {
56
+ this.responses.push(response);
57
+ }
58
+ });
59
+ this.actions[slug] = action;
60
+ return this;
61
+ }
62
+ executeAction(actionSlug, { event, mapping, settings }) {
63
+ const action = this.actions[actionSlug];
64
+ if (!action) {
65
+ throw new BadRequest(`"${actionSlug}" is not a valid action`);
66
+ }
67
+ return action.execute({
68
+ cachedFields: {},
69
+ mapping,
70
+ payload: event,
71
+ settings
72
+ });
73
+ }
74
+ async onSubscription(subscription, event, settings, onComplete) {
75
+ const subscriptionStartedAt = time();
76
+ const actionSlug = subscription.partnerAction;
77
+ const input = {
78
+ event,
79
+ mapping: subscription.mapping || {},
80
+ settings
81
+ };
82
+ let state = 'pending';
83
+ let results = null;
84
+ try {
85
+ if (typeof subscription.subscribe !== 'string') {
86
+ state = 'skipped';
87
+ results = [{ output: 'invalid subscription' }];
88
+ return results;
89
+ }
90
+ const isSubscribed = validate(parseFql(subscription.subscribe), event);
91
+ if (!isSubscribed) {
92
+ state = 'skipped';
93
+ results = [{ output: 'not subscribed' }];
94
+ return results;
95
+ }
96
+ results = await this.executeAction(actionSlug, input);
97
+ state = 'done';
98
+ return results;
99
+ }
100
+ catch (error) {
101
+ state = 'errored';
102
+ results = [{ error }];
103
+ throw error;
104
+ }
105
+ finally {
106
+ const subscriptionEndedAt = time();
107
+ const subscriptionDuration = duration(subscriptionStartedAt, subscriptionEndedAt);
108
+ onComplete === null || onComplete === void 0 ? void 0 : onComplete({
109
+ duration: subscriptionDuration,
110
+ destination: this.name,
111
+ action: actionSlug,
112
+ subscribe: subscription.subscribe,
113
+ state,
114
+ input: {
115
+ event: input.event,
116
+ mapping: input.mapping,
117
+ settings: input.settings
118
+ },
119
+ output: results
120
+ });
121
+ }
122
+ }
123
+ /**
124
+ * Note: Until we move subscriptions upstream (into int-consumer) we've opted
125
+ * to have failures abort the set of subscriptions and get potentially retried by centrifuge
126
+ */
127
+ async onEvent(event, settings, onComplete) {
128
+ const subscriptions = this.getSubscriptions(settings);
129
+ const destinationSettings = this.getDestinationSettings(settings);
130
+ const promises = subscriptions.map((subscription) => this.onSubscription(subscription, event, destinationSettings, onComplete));
131
+ const results = await Promise.all(promises);
132
+ return [].concat(...results);
133
+ }
134
+ getSubscriptions(settings) {
135
+ const { subscription, subscriptions } = settings;
136
+ let parsedSubscriptions;
137
+ // To support event tester we need to parse and validate multiple subscriptions from the settings
138
+ if (subscription) {
139
+ parsedSubscriptions = [subscription];
140
+ }
141
+ else if (typeof subscriptions === 'string') {
142
+ parsedSubscriptions = JSON.parse(subscriptions);
143
+ }
144
+ else if (Array.isArray(subscriptions)) {
145
+ parsedSubscriptions = subscriptions;
146
+ }
147
+ else {
148
+ parsedSubscriptions = [];
149
+ }
150
+ return parsedSubscriptions;
151
+ }
152
+ getDestinationSettings(settings) {
153
+ const { subcription, subscriptions, ...otherSettings } = settings;
154
+ return otherSettings;
155
+ }
156
+ }
157
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZGVzdGluYXRpb24ta2l0L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0sNkJBQTZCLENBQUE7QUFDaEUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUN4QyxPQUFPLEdBQXlDLE1BQU0sS0FBSyxDQUFBO0FBRTNELE9BQU8sRUFBRSxNQUFNLEVBQW9CLFFBQVEsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUU3RCxPQUFPLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxNQUFNLFNBQVMsQ0FBQTtBQUd4QyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQTtBQUkvRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQUUsQ0FBQTtBQXFFakQsTUFBTSxPQUFPLFdBQVc7SUFVdEIsWUFBWSxXQUE0Qzs7UUFDdEQsSUFBSSxDQUFDLFVBQVUsR0FBRyxXQUFXLENBQUE7UUFDN0IsSUFBSSxDQUFDLElBQUksR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFBO1FBQzVCLElBQUksQ0FBQyxhQUFhLEdBQUcsV0FBVyxDQUFDLGFBQWEsQ0FBQTtRQUM5QyxJQUFJLENBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQTtRQUNqQixJQUFJLENBQUMsY0FBYyxHQUFHLFdBQVcsQ0FBQyxjQUFjLENBQUE7UUFDaEQsSUFBSSxDQUFDLFNBQVMsR0FBRyxFQUFFLENBQUE7UUFFbkIsa0NBQWtDO1FBQ2xDLFVBQUksSUFBSSxDQUFDLGNBQWMsMENBQUUsTUFBTSxFQUFFO1lBQy9CLElBQUksQ0FBQyxjQUFjLEdBQUcsa0JBQWtCLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQTtTQUNyRTtRQUVELEtBQUssTUFBTSxNQUFNLElBQUksTUFB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
@@ -0,0 +1,38 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+ import { JSONObject } from '../json-object';
4
+ export interface StepResult {
5
+ output?: JSONObject | string | null | undefined;
6
+ error?: JSONObject | null;
7
+ }
8
+ export interface ExecuteInput<Settings, Payload> {
9
+ /** The subscription mapping definition */
10
+ readonly mapping?: JSONObject;
11
+ /** The global destination settings */
12
+ readonly settings: Settings;
13
+ /** The transformed input data, based on `mapping` + `event` */
14
+ payload: Payload;
15
+ /** The ids from cached requests */
16
+ cachedFields: {
17
+ [key: string]: string;
18
+ };
19
+ /** The page used in autocomplete */
20
+ page?: string;
21
+ }
22
+ /**
23
+ * Step is the base class for all discrete execution steps. It handles executing the step, logging,
24
+ * catching errors, and returning a result object.
25
+ */
26
+ export declare class Step<Settings, Payload> extends EventEmitter {
27
+ executeStep?(data: ExecuteInput<Settings, Payload>): Promise<string>;
28
+ execute(data: ExecuteInput<Settings, Payload>): Promise<StepResult>;
29
+ }
30
+ /**
31
+ * Steps is a list of one or more Step instances that can be executed in-order.
32
+ */
33
+ export declare class Steps<Settings, Payload> {
34
+ steps: Step<Settings, Payload>[];
35
+ constructor();
36
+ push(step: Step<Settings, Payload>): void;
37
+ execute(data: ExecuteInput<Settings, Payload>): Promise<StepResult[]>;
38
+ }