@prismatic-io/spectral 6.1.1 → 6.4.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.
- package/dist/clients/http/inputs.d.ts +9 -0
- package/dist/clients/http/inputs.js +9 -0
- package/dist/serverTypes/convert.d.ts +1 -1
- package/dist/serverTypes/convert.js +24 -31
- package/dist/serverTypes/index.d.ts +25 -15
- package/dist/serverTypes/index.js +2 -1
- package/dist/serverTypes/perform.d.ts +10 -0
- package/dist/serverTypes/perform.js +39 -0
- package/dist/testing.d.ts +13 -4
- package/dist/testing.js +36 -2
- package/dist/types/ActionInputParameters.d.ts +5 -4
- package/dist/types/ComponentDefinition.d.ts +4 -7
- package/dist/types/Inputs.d.ts +92 -19
- package/dist/types/Inputs.js +11 -0
- package/dist/types/TriggerPayload.d.ts +2 -0
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.js +0 -1
- package/package.json +1 -1
- package/dist/types/InputFieldType.d.ts +0 -15
- package/dist/types/InputFieldType.js +0 -13
|
@@ -6,6 +6,7 @@ export declare const url: {
|
|
|
6
6
|
required: true;
|
|
7
7
|
comments: string;
|
|
8
8
|
example: string;
|
|
9
|
+
clean: (value: unknown) => string;
|
|
9
10
|
};
|
|
10
11
|
export declare const data: {
|
|
11
12
|
label: string;
|
|
@@ -14,6 +15,7 @@ export declare const data: {
|
|
|
14
15
|
required: false;
|
|
15
16
|
comments: string;
|
|
16
17
|
example: string;
|
|
18
|
+
clean: (value: unknown) => string;
|
|
17
19
|
};
|
|
18
20
|
export declare const timeout: {
|
|
19
21
|
label: string;
|
|
@@ -21,6 +23,7 @@ export declare const timeout: {
|
|
|
21
23
|
required: false;
|
|
22
24
|
comments: string;
|
|
23
25
|
example: string;
|
|
26
|
+
clean: (value: unknown) => number;
|
|
24
27
|
};
|
|
25
28
|
export declare const method: {
|
|
26
29
|
label: string;
|
|
@@ -30,6 +33,7 @@ export declare const method: {
|
|
|
30
33
|
value: Method;
|
|
31
34
|
}[];
|
|
32
35
|
comments: string;
|
|
36
|
+
clean: (value: unknown) => string;
|
|
33
37
|
};
|
|
34
38
|
export declare const responseType: {
|
|
35
39
|
label: string;
|
|
@@ -42,6 +46,7 @@ export declare const responseType: {
|
|
|
42
46
|
label: ResponseType;
|
|
43
47
|
value: ResponseType;
|
|
44
48
|
}[];
|
|
49
|
+
clean: (value: unknown) => string;
|
|
45
50
|
};
|
|
46
51
|
export declare const headers: {
|
|
47
52
|
label: string;
|
|
@@ -67,6 +72,7 @@ export declare const maxRetries: {
|
|
|
67
72
|
required: false;
|
|
68
73
|
comments: string;
|
|
69
74
|
default: string;
|
|
75
|
+
clean: (value: unknown) => number;
|
|
70
76
|
};
|
|
71
77
|
export declare const retryDelayMS: {
|
|
72
78
|
label: string;
|
|
@@ -82,6 +88,7 @@ export declare const useExponentialBackoff: {
|
|
|
82
88
|
default: string;
|
|
83
89
|
required: false;
|
|
84
90
|
comments: string;
|
|
91
|
+
clean: (value: unknown) => boolean;
|
|
85
92
|
};
|
|
86
93
|
export declare const retryOnAllErrors: {
|
|
87
94
|
label: string;
|
|
@@ -89,6 +96,7 @@ export declare const retryOnAllErrors: {
|
|
|
89
96
|
default: string;
|
|
90
97
|
required: false;
|
|
91
98
|
comments: string;
|
|
99
|
+
clean: (value: unknown) => boolean;
|
|
92
100
|
};
|
|
93
101
|
export declare const formData: {
|
|
94
102
|
label: string;
|
|
@@ -113,4 +121,5 @@ export declare const debugRequest: {
|
|
|
113
121
|
type: "boolean";
|
|
114
122
|
required: false;
|
|
115
123
|
comments: string;
|
|
124
|
+
clean: (value: unknown) => boolean;
|
|
116
125
|
};
|
|
@@ -27,6 +27,7 @@ exports.url = (0, __1.input)({
|
|
|
27
27
|
required: true,
|
|
28
28
|
comments: "This is the URL to call.",
|
|
29
29
|
example: "/sobjects/Account",
|
|
30
|
+
clean: (value) => __1.util.types.toString(value),
|
|
30
31
|
});
|
|
31
32
|
exports.data = (0, __1.input)({
|
|
32
33
|
label: "Data",
|
|
@@ -35,6 +36,7 @@ exports.data = (0, __1.input)({
|
|
|
35
36
|
required: false,
|
|
36
37
|
comments: "The HTTP body payload to send to the URL. Must be a string or a reference to output from a previous step.",
|
|
37
38
|
example: '{"exampleKey": "Example Data"}',
|
|
39
|
+
clean: (value) => __1.util.types.toString(value),
|
|
38
40
|
});
|
|
39
41
|
exports.timeout = (0, __1.input)({
|
|
40
42
|
label: "Timeout",
|
|
@@ -42,12 +44,14 @@ exports.timeout = (0, __1.input)({
|
|
|
42
44
|
required: false,
|
|
43
45
|
comments: "The maximum time that a client will await a response to its request",
|
|
44
46
|
example: "2000",
|
|
47
|
+
clean: (value) => __1.util.types.toNumber(value),
|
|
45
48
|
});
|
|
46
49
|
exports.method = (0, __1.input)({
|
|
47
50
|
label: "Method",
|
|
48
51
|
type: "string",
|
|
49
52
|
model: supportedMethods.map((method) => ({ label: method, value: method })),
|
|
50
53
|
comments: "The HTTP method to use.",
|
|
54
|
+
clean: (value) => __1.util.types.toString(value),
|
|
51
55
|
});
|
|
52
56
|
exports.responseType = (0, __1.input)({
|
|
53
57
|
label: "Response Type",
|
|
@@ -60,6 +64,7 @@ exports.responseType = (0, __1.input)({
|
|
|
60
64
|
label: responseType,
|
|
61
65
|
value: responseType,
|
|
62
66
|
})),
|
|
67
|
+
clean: (value) => __1.util.types.toString(value),
|
|
63
68
|
});
|
|
64
69
|
exports.headers = (0, __1.input)({
|
|
65
70
|
label: "Header",
|
|
@@ -85,6 +90,7 @@ exports.maxRetries = (0, __1.input)({
|
|
|
85
90
|
required: false,
|
|
86
91
|
comments: "The maximum number of retries to attempt.",
|
|
87
92
|
default: "0",
|
|
93
|
+
clean: (value) => __1.util.types.toNumber(value),
|
|
88
94
|
});
|
|
89
95
|
exports.retryDelayMS = (0, __1.input)({
|
|
90
96
|
label: "Retry Delay (ms)",
|
|
@@ -100,6 +106,7 @@ exports.useExponentialBackoff = (0, __1.input)({
|
|
|
100
106
|
default: "false",
|
|
101
107
|
required: false,
|
|
102
108
|
comments: "Specifies whether to use a pre-defined exponential backoff strategy for retries.",
|
|
109
|
+
clean: (value) => __1.util.types.toBool(value),
|
|
103
110
|
});
|
|
104
111
|
exports.retryOnAllErrors = (0, __1.input)({
|
|
105
112
|
label: "Retry On All Errors",
|
|
@@ -107,6 +114,7 @@ exports.retryOnAllErrors = (0, __1.input)({
|
|
|
107
114
|
default: "false",
|
|
108
115
|
required: false,
|
|
109
116
|
comments: "If true, retries on all erroneous responses regardless of type.",
|
|
117
|
+
clean: (value) => __1.util.types.toBool(value),
|
|
110
118
|
});
|
|
111
119
|
exports.formData = (0, __1.input)({
|
|
112
120
|
label: "Form Data",
|
|
@@ -131,4 +139,5 @@ exports.debugRequest = (0, __1.input)({
|
|
|
131
139
|
type: "boolean",
|
|
132
140
|
required: false,
|
|
133
141
|
comments: "Enabling this flag will log out the current request.",
|
|
142
|
+
clean: (value) => __1.util.types.toBool(value),
|
|
134
143
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { ComponentDefinition } from "../types";
|
|
2
2
|
import { Component as ServerComponent } from ".";
|
|
3
|
-
export declare const convertComponent: <TPublic extends boolean
|
|
3
|
+
export declare const convertComponent: <TPublic extends boolean>({ connections, actions, triggers, hooks, ...definition }: ComponentDefinition<TPublic>) => ServerComponent;
|
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
var __rest = (this && this.__rest) || function (s, e) {
|
|
12
3
|
var t = {};
|
|
13
4
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
@@ -21,40 +12,42 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
21
12
|
};
|
|
22
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
14
|
exports.convertComponent = void 0;
|
|
24
|
-
const serialize_error_1 = require("serialize-error");
|
|
25
|
-
const util_1 = require("../util");
|
|
26
15
|
const types_1 = require("../types");
|
|
27
|
-
const
|
|
28
|
-
return (...args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
29
|
-
try {
|
|
30
|
-
return yield fn(...args);
|
|
31
|
-
}
|
|
32
|
-
catch (error) {
|
|
33
|
-
throw new Error((0, util_1.toJSON)((0, serialize_error_1.serializeError)(errorHandler(error))));
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
};
|
|
16
|
+
const perform_1 = require("./perform");
|
|
37
17
|
const convertInput = (key, _a) => {
|
|
38
18
|
var { default: defaultValue, type, label, collection } = _a, rest = __rest(_a, ["default", "type", "label", "collection"]);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
19
|
+
const keyLabel = collection === "keyvaluelist" && typeof label === "object"
|
|
20
|
+
? label.key
|
|
21
|
+
: undefined;
|
|
22
|
+
return Object.assign(Object.assign({}, rest), { key,
|
|
23
|
+
type, default: defaultValue !== null && defaultValue !== void 0 ? defaultValue : types_1.InputFieldDefaultMap[type], collection, label: typeof label === "string" ? label : label.value, keyLabel });
|
|
43
24
|
};
|
|
44
25
|
const convertAction = (actionKey, _a, hooks) => {
|
|
45
26
|
var { inputs = {}, perform } = _a, action = __rest(_a, ["inputs", "perform"]);
|
|
46
|
-
|
|
27
|
+
const convertedInputs = Object.entries(inputs).map(([key, value]) => convertInput(key, value));
|
|
28
|
+
const inputCleaners = Object.entries(inputs).reduce((result, [key, { clean }]) => (Object.assign(Object.assign({}, result), { [key]: clean })), {});
|
|
29
|
+
return Object.assign(Object.assign({}, action), { key: actionKey, inputs: convertedInputs, perform: (0, perform_1.createPerform)(perform, {
|
|
30
|
+
inputCleaners,
|
|
31
|
+
errorHandler: hooks === null || hooks === void 0 ? void 0 : hooks.error,
|
|
32
|
+
}) });
|
|
47
33
|
};
|
|
48
34
|
const convertTrigger = (triggerKey, _a, hooks) => {
|
|
49
35
|
var { inputs = {}, perform } = _a, trigger = __rest(_a, ["inputs", "perform"]);
|
|
50
|
-
|
|
36
|
+
const convertedInputs = Object.entries(inputs).map(([key, value]) => convertInput(key, value));
|
|
37
|
+
return Object.assign(Object.assign({}, trigger), { key: triggerKey, inputs: convertedInputs, perform: (0, perform_1.createPerform)(perform, {
|
|
38
|
+
inputCleaners: {},
|
|
39
|
+
errorHandler: hooks === null || hooks === void 0 ? void 0 : hooks.error,
|
|
40
|
+
}) });
|
|
51
41
|
};
|
|
52
|
-
const convertConnection = (
|
|
53
|
-
var _a;
|
|
54
|
-
|
|
42
|
+
const convertConnection = (_a) => {
|
|
43
|
+
var { inputs = {} } = _a, connection = __rest(_a, ["inputs"]);
|
|
44
|
+
const convertedInputs = Object.entries(inputs).map(([key, value]) => convertInput(key, value));
|
|
45
|
+
return Object.assign(Object.assign({}, connection), { inputs: convertedInputs });
|
|
55
46
|
};
|
|
56
47
|
const convertComponent = (_a) => {
|
|
57
48
|
var { connections = [], actions = {}, triggers = {}, hooks } = _a, definition = __rest(_a, ["connections", "actions", "triggers", "hooks"]);
|
|
58
|
-
|
|
49
|
+
const convertedActions = Object.entries(actions).reduce((result, [actionKey, action]) => (Object.assign(Object.assign({}, result), { [actionKey]: convertAction(actionKey, action, hooks) })), {});
|
|
50
|
+
const convertedTriggers = Object.entries(triggers).reduce((result, [triggerKey, trigger]) => (Object.assign(Object.assign({}, result), { [triggerKey]: convertTrigger(triggerKey, trigger, hooks) })), {});
|
|
51
|
+
return Object.assign(Object.assign({}, definition), { connections: connections.map(convertConnection), actions: convertedActions, triggers: convertedTriggers });
|
|
59
52
|
};
|
|
60
53
|
exports.convertComponent = convertComponent;
|
|
@@ -3,7 +3,7 @@ interface DisplayDefinition {
|
|
|
3
3
|
label: string;
|
|
4
4
|
description: string;
|
|
5
5
|
}
|
|
6
|
-
interface Component {
|
|
6
|
+
export interface Component {
|
|
7
7
|
key: string;
|
|
8
8
|
public?: boolean;
|
|
9
9
|
documentationUrl?: string;
|
|
@@ -15,7 +15,7 @@ interface Component {
|
|
|
15
15
|
triggers: Record<string, Trigger>;
|
|
16
16
|
connections: Connection[];
|
|
17
17
|
}
|
|
18
|
-
interface Action {
|
|
18
|
+
export interface Action {
|
|
19
19
|
key: string;
|
|
20
20
|
display: DisplayDefinition & {
|
|
21
21
|
directions?: string;
|
|
@@ -30,8 +30,8 @@ interface Action {
|
|
|
30
30
|
perform: ActionPerformFunction;
|
|
31
31
|
examplePayload?: unknown;
|
|
32
32
|
}
|
|
33
|
-
declare type ActionLoggerFunction = (...args: unknown[]) => void;
|
|
34
|
-
interface ActionLogger {
|
|
33
|
+
export declare type ActionLoggerFunction = (...args: unknown[]) => void;
|
|
34
|
+
export interface ActionLogger {
|
|
35
35
|
metric: ActionLoggerFunction;
|
|
36
36
|
trace: ActionLoggerFunction;
|
|
37
37
|
debug: ActionLoggerFunction;
|
|
@@ -40,7 +40,7 @@ interface ActionLogger {
|
|
|
40
40
|
warn: ActionLoggerFunction;
|
|
41
41
|
error: ActionLoggerFunction;
|
|
42
42
|
}
|
|
43
|
-
interface ActionContext {
|
|
43
|
+
export interface ActionContext {
|
|
44
44
|
logger: ActionLogger;
|
|
45
45
|
instanceState: Record<string, unknown>;
|
|
46
46
|
crossFlowState: Record<string, unknown>;
|
|
@@ -49,7 +49,7 @@ interface ActionContext {
|
|
|
49
49
|
executionId: string;
|
|
50
50
|
}
|
|
51
51
|
declare type TriggerOptionChoice = "invalid" | "valid" | "required";
|
|
52
|
-
interface TriggerPayload {
|
|
52
|
+
export interface TriggerPayload {
|
|
53
53
|
headers: Record<string, string>;
|
|
54
54
|
queryParameters: Record<string, string>;
|
|
55
55
|
rawBody: {
|
|
@@ -60,6 +60,7 @@ interface TriggerPayload {
|
|
|
60
60
|
data: unknown;
|
|
61
61
|
contentType?: string;
|
|
62
62
|
};
|
|
63
|
+
pathFragment: string;
|
|
63
64
|
webhookUrls: Record<string, string>;
|
|
64
65
|
webhookApiKeys: Record<string, string[]>;
|
|
65
66
|
invokeUrl: string;
|
|
@@ -90,9 +91,9 @@ interface TriggerBaseResult {
|
|
|
90
91
|
interface TriggerBranchingResult extends TriggerBaseResult {
|
|
91
92
|
branch: string;
|
|
92
93
|
}
|
|
93
|
-
declare type TriggerResult = TriggerBranchingResult | TriggerBaseResult | undefined;
|
|
94
|
-
declare type TriggerPerformFunction = (context: ActionContext, payload: TriggerPayload, params: Record<string, unknown>) => Promise<TriggerResult>;
|
|
95
|
-
interface Trigger {
|
|
94
|
+
export declare type TriggerResult = TriggerBranchingResult | TriggerBaseResult | undefined;
|
|
95
|
+
export declare type TriggerPerformFunction = (context: ActionContext, payload: TriggerPayload, params: Record<string, unknown>) => Promise<TriggerResult>;
|
|
96
|
+
export interface Trigger {
|
|
96
97
|
key: string;
|
|
97
98
|
display: DisplayDefinition & {
|
|
98
99
|
directions?: string;
|
|
@@ -110,11 +111,11 @@ interface Trigger {
|
|
|
110
111
|
examplePayload?: unknown;
|
|
111
112
|
isCommonTrigger?: boolean;
|
|
112
113
|
}
|
|
113
|
-
declare enum OAuth2Type {
|
|
114
|
+
export declare enum OAuth2Type {
|
|
114
115
|
ClientCredentials = "client_credentials",
|
|
115
116
|
AuthorizationCode = "authorization_code"
|
|
116
117
|
}
|
|
117
|
-
interface Connection {
|
|
118
|
+
export interface Connection {
|
|
118
119
|
key: string;
|
|
119
120
|
label: string;
|
|
120
121
|
comments?: string;
|
|
@@ -124,6 +125,15 @@ interface Connection {
|
|
|
124
125
|
shown?: boolean;
|
|
125
126
|
})[];
|
|
126
127
|
}
|
|
128
|
+
export interface ConnectionValue {
|
|
129
|
+
key: string;
|
|
130
|
+
configVarKey: string;
|
|
131
|
+
fields: {
|
|
132
|
+
[key: string]: unknown;
|
|
133
|
+
};
|
|
134
|
+
token?: Record<string, unknown>;
|
|
135
|
+
context?: Record<string, unknown>;
|
|
136
|
+
}
|
|
127
137
|
interface ServerPerformDataStructureReturn {
|
|
128
138
|
data: boolean | number | string | Record<string, unknown> | unknown[] | unknown;
|
|
129
139
|
contentType?: string;
|
|
@@ -146,13 +156,13 @@ interface ServerPerformBranchingDataStructureReturn extends ServerPerformDataStr
|
|
|
146
156
|
interface ServerPerformBranchingDataReturn extends ServerPerformDataReturn {
|
|
147
157
|
branch: string;
|
|
148
158
|
}
|
|
149
|
-
declare type ActionPerformReturn = ServerPerformDataStructureReturn | ServerPerformBranchingDataStructureReturn | ServerPerformDataReturn | ServerPerformBranchingDataReturn | undefined;
|
|
150
|
-
declare type ActionPerformFunction = (context: ActionContext, params: Record<string, unknown>) => Promise<ActionPerformReturn>;
|
|
159
|
+
export declare type ActionPerformReturn = ServerPerformDataStructureReturn | ServerPerformBranchingDataStructureReturn | ServerPerformDataReturn | ServerPerformBranchingDataReturn | undefined;
|
|
160
|
+
export declare type ActionPerformFunction = (context: ActionContext, params: Record<string, unknown>) => Promise<ActionPerformReturn>;
|
|
151
161
|
interface InputFieldChoice {
|
|
152
162
|
label: string;
|
|
153
163
|
value: string;
|
|
154
164
|
}
|
|
155
|
-
interface Input {
|
|
165
|
+
export interface Input {
|
|
156
166
|
key: string;
|
|
157
167
|
label: string;
|
|
158
168
|
keyLabel?: string;
|
|
@@ -166,4 +176,4 @@ interface Input {
|
|
|
166
176
|
model?: InputFieldChoice[];
|
|
167
177
|
language?: string;
|
|
168
178
|
}
|
|
169
|
-
export
|
|
179
|
+
export {};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OAuth2Type = void 0;
|
|
3
4
|
var OAuth2Type;
|
|
4
5
|
(function (OAuth2Type) {
|
|
5
6
|
OAuth2Type["ClientCredentials"] = "client_credentials";
|
|
6
7
|
OAuth2Type["AuthorizationCode"] = "authorization_code";
|
|
7
|
-
})(OAuth2Type || (OAuth2Type = {}));
|
|
8
|
+
})(OAuth2Type = exports.OAuth2Type || (exports.OAuth2Type = {}));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ErrorHandler } from "../types";
|
|
2
|
+
declare type PerformFn = (...args: any[]) => Promise<any>;
|
|
3
|
+
export declare type CleanFn = (...args: any[]) => any;
|
|
4
|
+
export declare type InputCleaners = Record<string, CleanFn | undefined>;
|
|
5
|
+
interface CreatePerformProps {
|
|
6
|
+
inputCleaners: InputCleaners;
|
|
7
|
+
errorHandler?: ErrorHandler;
|
|
8
|
+
}
|
|
9
|
+
export declare const createPerform: (performFn: PerformFn, { inputCleaners, errorHandler }: CreatePerformProps) => PerformFn;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.createPerform = void 0;
|
|
13
|
+
const serialize_error_1 = require("serialize-error");
|
|
14
|
+
const util_1 = require("../util");
|
|
15
|
+
const cleanParams = (params, cleaners) => Object.entries(params).reduce((result, [key, value]) => {
|
|
16
|
+
const cleanFn = cleaners[key];
|
|
17
|
+
return Object.assign(Object.assign({}, result), { [key]: cleanFn ? cleanFn(value) : value });
|
|
18
|
+
}, {});
|
|
19
|
+
const createPerform = (performFn, { inputCleaners, errorHandler }) => {
|
|
20
|
+
return (...args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
|
+
try {
|
|
22
|
+
if (args.length === 2) {
|
|
23
|
+
const [context, params] = args;
|
|
24
|
+
return yield performFn(context, cleanParams(params, inputCleaners));
|
|
25
|
+
}
|
|
26
|
+
const [context, payload, params] = args;
|
|
27
|
+
return yield performFn(context, payload, cleanParams(params, inputCleaners));
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (!errorHandler) {
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
const handled = errorHandler(error);
|
|
34
|
+
const serialized = (0, util_1.toJSON)((0, serialize_error_1.serializeError)(handled));
|
|
35
|
+
throw new Error(serialized);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
exports.createPerform = createPerform;
|
package/dist/testing.d.ts
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* information on unit testing, check out our docs:
|
|
5
5
|
* https://prismatic.io/docs/custom-components/writing-custom-components/#testing-a-component
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
export declare const createConnection: <T extends
|
|
7
|
+
import { TriggerPayload, TriggerResult, Connection, ConnectionValue, ActionLogger, Component, ActionContext, ActionPerformReturn } from "./serverTypes";
|
|
8
|
+
import { ConnectionDefinition, ActionDefinition, TriggerDefinition, Inputs, ActionInputParameters } from "./types";
|
|
9
|
+
export declare const createConnection: <T extends Connection>({ key }: T, values: Record<string, unknown>) => ConnectionValue;
|
|
10
10
|
/**
|
|
11
11
|
* Pre-built mock of ActionLogger. Suitable for asserting logs are created as expected.
|
|
12
12
|
* See https://prismatic.io/docs/custom-components/writing-custom-components/#verifying-correct-logging-in-action-tests for information on testing correct logging behavior in your custom component.
|
|
@@ -34,9 +34,18 @@ export declare const defaultTriggerPayload: () => TriggerPayload;
|
|
|
34
34
|
* trigger result and a mock logger for asserting logging.
|
|
35
35
|
*/
|
|
36
36
|
export declare const invokeTrigger: <T extends Inputs>({ perform }: TriggerDefinition<T>, context?: Partial<ActionContext> | undefined, payload?: TriggerPayload | undefined, params?: ActionInputParameters<T> | undefined) => Promise<InvokeReturn<import("./types").TriggerResult<boolean | undefined>>>;
|
|
37
|
+
export declare class ComponentTestHarness<TComponent extends Component> {
|
|
38
|
+
component: TComponent;
|
|
39
|
+
constructor(component: TComponent);
|
|
40
|
+
connectionValue({ key }: ConnectionDefinition): ConnectionValue;
|
|
41
|
+
trigger(key: string, payload?: TriggerPayload, params?: Record<string, unknown>, context?: Partial<ActionContext>): Promise<TriggerResult>;
|
|
42
|
+
action(key: string, params?: Record<string, unknown>, context?: Partial<ActionContext>): Promise<ActionPerformReturn>;
|
|
43
|
+
}
|
|
44
|
+
export declare const createHarness: <TComponent extends Component>(component: TComponent) => ComponentTestHarness<TComponent>;
|
|
37
45
|
declare const _default: {
|
|
46
|
+
loggerMock: () => ActionLogger;
|
|
38
47
|
invoke: <T extends Inputs>({ perform }: ActionDefinition<T>, params: ActionInputParameters<T>, context?: Partial<ActionContext> | undefined) => Promise<InvokeReturn<import("./types").ActionPerformReturn<boolean | undefined, unknown>>>;
|
|
39
48
|
invokeTrigger: <T_1 extends Inputs>({ perform }: TriggerDefinition<T_1>, context?: Partial<ActionContext> | undefined, payload?: TriggerPayload | undefined, params?: ActionInputParameters<T_1> | undefined) => Promise<InvokeReturn<import("./types").TriggerResult<boolean | undefined>>>;
|
|
40
|
-
|
|
49
|
+
createHarness: <TComponent extends Component>(component: TComponent) => ComponentTestHarness<TComponent>;
|
|
41
50
|
};
|
|
42
51
|
export default _default;
|
package/dist/testing.js
CHANGED
|
@@ -15,7 +15,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
15
15
|
});
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.invokeTrigger = exports.defaultTriggerPayload = exports.invoke = exports.loggerMock = exports.createConnection = void 0;
|
|
18
|
+
exports.createHarness = exports.ComponentTestHarness = exports.invokeTrigger = exports.defaultTriggerPayload = exports.invoke = exports.loggerMock = exports.createConnection = void 0;
|
|
19
19
|
const jest_mock_1 = require("jest-mock");
|
|
20
20
|
const createConnection = ({ key }, values) => ({
|
|
21
21
|
configVarKey: "",
|
|
@@ -68,6 +68,7 @@ const defaultTriggerPayload = () => {
|
|
|
68
68
|
data: JSON.stringify(payloadData),
|
|
69
69
|
contentType,
|
|
70
70
|
},
|
|
71
|
+
pathFragment: "",
|
|
71
72
|
webhookUrls: {
|
|
72
73
|
"Flow 1": "https://example.com",
|
|
73
74
|
},
|
|
@@ -105,8 +106,41 @@ const invokeTrigger = ({ perform }, context, payload, params) => __awaiter(void
|
|
|
105
106
|
};
|
|
106
107
|
});
|
|
107
108
|
exports.invokeTrigger = invokeTrigger;
|
|
109
|
+
class ComponentTestHarness {
|
|
110
|
+
constructor(component) {
|
|
111
|
+
this.component = component;
|
|
112
|
+
}
|
|
113
|
+
connectionValue({ key }) {
|
|
114
|
+
const { PRISMATIC_CONNECTION_VALUE: value } = process.env;
|
|
115
|
+
if (!value) {
|
|
116
|
+
throw new Error("Unable to find connection value.");
|
|
117
|
+
}
|
|
118
|
+
const result = Object.assign(Object.assign({}, JSON.parse(value)), { key });
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
trigger(key, payload, params, context) {
|
|
122
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
const realizedContext = Object.assign({ logger: (0, exports.loggerMock)(), instanceState: {}, crossFlowState: {}, executionState: {}, stepId: "mockStepId", executionId: "mockExecutionId" }, context);
|
|
124
|
+
const trigger = this.component.triggers[key];
|
|
125
|
+
return trigger.perform(realizedContext, Object.assign(Object.assign({}, (0, exports.defaultTriggerPayload)()), payload), Object.assign({}, params));
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
action(key, params, context) {
|
|
129
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
130
|
+
const realizedContext = Object.assign({ logger: (0, exports.loggerMock)(), instanceState: {}, crossFlowState: {}, executionState: {}, stepId: "mockStepId", executionId: "mockExecutionId" }, context);
|
|
131
|
+
const action = this.component.actions[key];
|
|
132
|
+
return action.perform(realizedContext, Object.assign({}, params));
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
exports.ComponentTestHarness = ComponentTestHarness;
|
|
137
|
+
const createHarness = (component) => {
|
|
138
|
+
return new ComponentTestHarness(component);
|
|
139
|
+
};
|
|
140
|
+
exports.createHarness = createHarness;
|
|
108
141
|
exports.default = {
|
|
142
|
+
loggerMock: exports.loggerMock,
|
|
109
143
|
invoke: exports.invoke,
|
|
110
144
|
invokeTrigger: exports.invokeTrigger,
|
|
111
|
-
|
|
145
|
+
createHarness: exports.createHarness,
|
|
112
146
|
};
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Inputs } from ".";
|
|
2
|
+
import { ConditionalExpression } from "./conditional-logic";
|
|
3
|
+
import { InputFieldCollection, InputCleanFunction, Connection } from "./Inputs";
|
|
2
4
|
/**
|
|
3
5
|
* Collection of input parameters.
|
|
4
6
|
* Inputs can be static values, references to config variables, or
|
|
5
7
|
* references to previous steps' outputs.
|
|
6
8
|
*/
|
|
7
9
|
export declare type ActionInputParameters<TInputs extends Inputs> = {
|
|
8
|
-
[Property in keyof TInputs]: ExtractValue<TInputs[Property]>;
|
|
10
|
+
[Property in keyof TInputs]: TInputs[Property]["clean"] extends InputCleanFunction<any> ? ReturnType<TInputs[Property]["clean"]> : TInputs[Property]["type"] extends "connection" ? ExtractValue<Connection, TInputs[Property]["collection"]> : TInputs[Property]["type"] extends "conditional" ? ExtractValue<ConditionalExpression, TInputs[Property]["collection"]> : ExtractValue<TInputs[Property]["default"], TInputs[Property]["collection"]>;
|
|
9
11
|
};
|
|
10
|
-
export declare type ExtractValue<
|
|
11
|
-
export declare type MapCollectionValues<TType, TCollection extends InputFieldDefinition["collection"]> = TCollection extends "keyvaluelist" ? KeyValuePair<TType>[] : TCollection extends "valuelist" ? TType[] : TType;
|
|
12
|
+
export declare type ExtractValue<TType, TCollection extends InputFieldCollection | undefined> = TCollection extends "keyvaluelist" ? KeyValuePair<TType>[] : TCollection extends "valuelist" ? TType[] : TType;
|
|
12
13
|
/**
|
|
13
14
|
* KeyValuePair input parameter type.
|
|
14
15
|
* This allows users to input multiple keys / values as an input.
|
|
@@ -4,13 +4,12 @@ export interface ComponentHooks {
|
|
|
4
4
|
/** Defines a global error handler that automatically wraps the component's action/trigger perform functions. */
|
|
5
5
|
error?: ErrorHandler;
|
|
6
6
|
}
|
|
7
|
-
|
|
7
|
+
/** Defines attributes of a Component. */
|
|
8
|
+
export declare type ComponentDefinition<TPublic extends boolean> = {
|
|
8
9
|
/** Specifies unique key for this Component. */
|
|
9
10
|
key: string;
|
|
10
11
|
/** Specifies if this Component is available for all Organizations or only your own @default false */
|
|
11
12
|
public?: TPublic;
|
|
12
|
-
/** Specified the URL for the Component Documentation. */
|
|
13
|
-
documentationUrl?: string;
|
|
14
13
|
/** Defines how the Component is displayed in the Prismatic interface. */
|
|
15
14
|
display: ComponentDisplayDefinition<TPublic>;
|
|
16
15
|
/** Specifies the supported Actions of this Component. */
|
|
@@ -21,9 +20,7 @@ interface BaseComponentDefinition<TPublic extends boolean = false> {
|
|
|
21
20
|
connections?: ConnectionDefinition[];
|
|
22
21
|
/** Hooks */
|
|
23
22
|
hooks?: ComponentHooks;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
export declare type ComponentDefinition<TPublic extends boolean = false> = BaseComponentDefinition<TPublic> & (TPublic extends true ? {
|
|
23
|
+
} & (TPublic extends true ? {
|
|
24
|
+
/** Specified the URL for the Component Documentation. */
|
|
27
25
|
documentationUrl: string;
|
|
28
26
|
} : unknown);
|
|
29
|
-
export {};
|
package/dist/types/Inputs.d.ts
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConditionalExpression } from "./conditional-logic";
|
|
2
|
+
/** InputField type enumeration. */
|
|
3
|
+
export declare type InputFieldType = InputFieldDefinition["type"];
|
|
4
|
+
export declare const InputFieldDefaultMap: Record<InputFieldType, string | undefined>;
|
|
2
5
|
export declare type Inputs = Record<string, InputFieldDefinition>;
|
|
3
|
-
export declare type ConnectionInput =
|
|
6
|
+
export declare type ConnectionInput = (StringInputField | DataInputField | TextInputField | PasswordInputField | BooleanInputField) & {
|
|
4
7
|
shown?: boolean;
|
|
5
8
|
};
|
|
6
|
-
export declare type InputFieldDefinition =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
type: InputFieldType;
|
|
9
|
+
export declare type InputFieldDefinition = StringInputField | DataInputField | TextInputField | PasswordInputField | BooleanInputField | CodeInputField | ConditionalInputField | ConnectionInputField;
|
|
10
|
+
export declare type InputCleanFunction<TValue, TResult = TValue> = (value: TValue) => TResult;
|
|
11
|
+
interface BaseInputField {
|
|
10
12
|
/** Interface label of the InputField. */
|
|
11
13
|
label: {
|
|
12
14
|
key: string;
|
|
13
15
|
value: string;
|
|
14
16
|
} | string;
|
|
15
|
-
/** Collection type of the InputField */
|
|
16
|
-
collection?: InputFieldCollection;
|
|
17
17
|
/** Text to show as the InputField placeholder. */
|
|
18
18
|
placeholder?: string;
|
|
19
|
-
/** Default value for this field. */
|
|
20
|
-
default?: typeof InputFieldDefaultMap[this["type"]];
|
|
21
19
|
/** Additional text to give guidance to the user configuring the InputField. */
|
|
22
20
|
comments?: string;
|
|
23
21
|
/** Example valid input for this InputField. */
|
|
@@ -25,27 +23,102 @@ interface BaseInputFieldDefinition {
|
|
|
25
23
|
/** Indicate if this InputField is required. */
|
|
26
24
|
required?: boolean;
|
|
27
25
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
type:
|
|
26
|
+
export interface StringInputField extends BaseInputField {
|
|
27
|
+
/** Data type the InputField will collect. */
|
|
28
|
+
type: "string";
|
|
29
|
+
/** Collection type of the InputField */
|
|
30
|
+
collection?: InputFieldCollection;
|
|
31
|
+
/** Default value for this field. */
|
|
32
|
+
default?: unknown;
|
|
33
|
+
/** Dictates possible choices for the input. */
|
|
34
|
+
model?: InputFieldChoice[];
|
|
35
|
+
/** Clean function */
|
|
36
|
+
clean?: InputCleanFunction<NonNullable<this["default"]>>;
|
|
37
|
+
}
|
|
38
|
+
export interface DataInputField extends BaseInputField {
|
|
39
|
+
/** Data type the InputField will collect. */
|
|
40
|
+
type: "data";
|
|
41
|
+
/** Collection type of the InputField */
|
|
42
|
+
collection?: InputFieldCollection;
|
|
43
|
+
/** Default value for this field. */
|
|
44
|
+
default?: unknown;
|
|
45
|
+
/** Dictates possible choices for the input. */
|
|
46
|
+
model?: InputFieldChoice[];
|
|
47
|
+
/** Clean function */
|
|
48
|
+
clean?: InputCleanFunction<NonNullable<this["default"]>>;
|
|
49
|
+
}
|
|
50
|
+
export interface TextInputField extends BaseInputField {
|
|
51
|
+
/** Data type the InputField will collect. */
|
|
52
|
+
type: "text";
|
|
53
|
+
/** Collection type of the InputField */
|
|
54
|
+
collection?: InputFieldCollection;
|
|
55
|
+
/** Default value for this field. */
|
|
56
|
+
default?: unknown;
|
|
31
57
|
/** Dictates possible choices for the input. */
|
|
32
58
|
model?: InputFieldChoice[];
|
|
59
|
+
/** Clean function */
|
|
60
|
+
clean?: InputCleanFunction<NonNullable<this["default"]>>;
|
|
61
|
+
}
|
|
62
|
+
export interface PasswordInputField extends BaseInputField {
|
|
63
|
+
/** Data type the InputField will collect. */
|
|
64
|
+
type: "password";
|
|
65
|
+
/** Collection type of the InputField */
|
|
66
|
+
collection?: InputFieldCollection;
|
|
67
|
+
/** Default value for this field. */
|
|
68
|
+
default?: unknown;
|
|
69
|
+
/** Dictates possible choices for the input. */
|
|
70
|
+
model?: InputFieldChoice[];
|
|
71
|
+
/** Clean function */
|
|
72
|
+
clean?: InputCleanFunction<NonNullable<this["default"]>>;
|
|
73
|
+
}
|
|
74
|
+
export interface BooleanInputField extends BaseInputField {
|
|
75
|
+
/** Data type the InputField will collect. */
|
|
76
|
+
type: "boolean";
|
|
77
|
+
/** Collection type of the InputField */
|
|
78
|
+
collection?: InputFieldCollection;
|
|
79
|
+
/** Default value for this field. */
|
|
80
|
+
default?: unknown;
|
|
81
|
+
/** Dictates possible choices for the input. */
|
|
82
|
+
model?: InputFieldChoice[];
|
|
83
|
+
/** Clean function */
|
|
84
|
+
clean?: InputCleanFunction<NonNullable<this["default"]>>;
|
|
33
85
|
}
|
|
34
86
|
/** Defines attributes of a CodeInputField. */
|
|
35
|
-
export interface
|
|
36
|
-
type
|
|
87
|
+
export interface CodeInputField extends BaseInputField {
|
|
88
|
+
/** Data type the InputField will collect. */
|
|
89
|
+
type: "code";
|
|
90
|
+
/** Collection type of the InputField */
|
|
91
|
+
collection?: InputFieldCollection;
|
|
92
|
+
/** Default value for this field. */
|
|
93
|
+
default?: unknown;
|
|
37
94
|
/** Code language of this field. */
|
|
38
95
|
language?: string;
|
|
39
96
|
/** Dictates possible choices for the input. */
|
|
40
97
|
model?: InputFieldChoice[];
|
|
98
|
+
/** Clean function */
|
|
99
|
+
clean?: InputCleanFunction<NonNullable<this["default"]>>;
|
|
41
100
|
}
|
|
42
101
|
/** Defines attributes of a ConditionalInputField. */
|
|
43
|
-
export interface ConditionalInputField extends
|
|
44
|
-
type
|
|
102
|
+
export interface ConditionalInputField extends BaseInputField {
|
|
103
|
+
/** Data type the InputField will collect. */
|
|
104
|
+
type: "conditional";
|
|
105
|
+
/** Collection type of the InputField */
|
|
106
|
+
collection: Extract<InputFieldCollection, "valuelist">;
|
|
107
|
+
/** Default value for this field. */
|
|
108
|
+
default?: ConditionalExpression;
|
|
109
|
+
/** Clean function */
|
|
110
|
+
clean?: InputCleanFunction<NonNullable<this["default"]>>;
|
|
45
111
|
}
|
|
46
112
|
/** Defines attributes of a ConnectionInputField. */
|
|
47
|
-
export interface ConnectionInputField extends
|
|
48
|
-
type
|
|
113
|
+
export interface ConnectionInputField extends BaseInputField {
|
|
114
|
+
/** Data type the InputField will collect. */
|
|
115
|
+
type: "connection";
|
|
116
|
+
/** Collection type of the InputField */
|
|
117
|
+
collection?: InputFieldCollection;
|
|
118
|
+
/** Default value for this field. */
|
|
119
|
+
default?: Connection;
|
|
120
|
+
/** Clean function */
|
|
121
|
+
clean?: InputCleanFunction<NonNullable<this["default"]>>;
|
|
49
122
|
}
|
|
50
123
|
export interface Connection {
|
|
51
124
|
/** Key of the Connection type. */
|
package/dist/types/Inputs.js
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InputFieldDefaultMap = void 0;
|
|
4
|
+
exports.InputFieldDefaultMap = {
|
|
5
|
+
string: "",
|
|
6
|
+
data: "",
|
|
7
|
+
text: "",
|
|
8
|
+
password: "",
|
|
9
|
+
boolean: "false",
|
|
10
|
+
code: "",
|
|
11
|
+
conditional: undefined,
|
|
12
|
+
connection: undefined,
|
|
13
|
+
};
|
|
@@ -14,6 +14,8 @@ export interface TriggerPayload {
|
|
|
14
14
|
data: unknown;
|
|
15
15
|
contentType?: string;
|
|
16
16
|
};
|
|
17
|
+
/** Extended path information from the webhook trigger */
|
|
18
|
+
pathFragment: string;
|
|
17
19
|
/** The webhook URLs assigned to this integration's flows upon instance deploy */
|
|
18
20
|
webhookUrls: {
|
|
19
21
|
[key: string]: string;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -12,7 +12,6 @@ export * from "./DisplayDefinition";
|
|
|
12
12
|
export * from "./ActionInputParameters";
|
|
13
13
|
export * from "./ActionLogger";
|
|
14
14
|
export * from "./ActionPerformFunction";
|
|
15
|
-
export * from "./InputFieldType";
|
|
16
15
|
export * from "./conditional-logic";
|
|
17
16
|
export * from "./TriggerResult";
|
|
18
17
|
export * from "./TriggerPerformFunction";
|
package/dist/types/index.js
CHANGED
|
@@ -28,7 +28,6 @@ __exportStar(require("./DisplayDefinition"), exports);
|
|
|
28
28
|
__exportStar(require("./ActionInputParameters"), exports);
|
|
29
29
|
__exportStar(require("./ActionLogger"), exports);
|
|
30
30
|
__exportStar(require("./ActionPerformFunction"), exports);
|
|
31
|
-
__exportStar(require("./InputFieldType"), exports);
|
|
32
31
|
__exportStar(require("./conditional-logic"), exports);
|
|
33
32
|
__exportStar(require("./TriggerResult"), exports);
|
|
34
33
|
__exportStar(require("./TriggerPerformFunction"), exports);
|
package/package.json
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Connection } from ".";
|
|
2
|
-
import { ConditionalExpression } from "./conditional-logic";
|
|
3
|
-
/** InputField type enumeration. */
|
|
4
|
-
export declare type InputFieldType = keyof InputFieldTypeMap;
|
|
5
|
-
export declare type InputFieldTypeMap = {
|
|
6
|
-
string: unknown;
|
|
7
|
-
data: unknown;
|
|
8
|
-
text: unknown;
|
|
9
|
-
password: unknown;
|
|
10
|
-
boolean: unknown;
|
|
11
|
-
code: unknown;
|
|
12
|
-
conditional: ConditionalExpression;
|
|
13
|
-
connection: Connection;
|
|
14
|
-
};
|
|
15
|
-
export declare const InputFieldDefaultMap: Record<InputFieldType, string | undefined>;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.InputFieldDefaultMap = void 0;
|
|
4
|
-
exports.InputFieldDefaultMap = {
|
|
5
|
-
string: "",
|
|
6
|
-
data: "",
|
|
7
|
-
text: "",
|
|
8
|
-
password: "",
|
|
9
|
-
boolean: "false",
|
|
10
|
-
code: "",
|
|
11
|
-
conditional: undefined,
|
|
12
|
-
connection: undefined,
|
|
13
|
-
};
|