@metacall/protocol 0.1.28 → 0.1.29
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/index.d.ts +2 -2
- package/dist/login.js +15 -13
- package/dist/protocol.d.ts +13 -10
- package/dist/protocol.js +170 -107
- package/dist/signup.js +15 -13
- package/package.json +3 -4
- package/src/index.ts +2 -2
- package/src/login.ts +20 -13
- package/src/protocol.ts +240 -159
- package/src/signup.ts +22 -13
- package/tsconfig.json +1 -1
package/dist/index.d.ts
CHANGED
package/dist/login.js
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const axios_1 = __importDefault(require("axios"));
|
|
7
3
|
const url_1 = require("url");
|
|
8
|
-
exports.default = (email, password, baseURL) => {
|
|
4
|
+
exports.default = async (email, password, baseURL) => {
|
|
9
5
|
const request = {
|
|
10
6
|
email,
|
|
11
7
|
password
|
|
12
8
|
};
|
|
13
|
-
if (!baseURL.includes('localhost'))
|
|
14
|
-
request['g-recaptcha-response'] = 'empty'; //TODO: Review the captcha
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
if (!baseURL.includes('localhost')) {
|
|
10
|
+
request['g-recaptcha-response'] = 'empty'; // TODO: Review the captcha
|
|
11
|
+
}
|
|
12
|
+
const res = await fetch(baseURL + '/login', {
|
|
13
|
+
method: 'POST',
|
|
17
14
|
headers: {
|
|
18
15
|
Accept: 'application/json, text/plain, */*',
|
|
19
16
|
Host: new url_1.URL(baseURL).host,
|
|
20
|
-
Origin: baseURL
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
.
|
|
17
|
+
Origin: baseURL,
|
|
18
|
+
'Content-Type': 'application/json'
|
|
19
|
+
},
|
|
20
|
+
body: JSON.stringify(request)
|
|
21
|
+
});
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
throw new Error(res.statusText);
|
|
24
|
+
}
|
|
25
|
+
return res.text();
|
|
24
26
|
};
|
package/dist/protocol.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { AxiosError } from 'axios';
|
|
2
1
|
import { Create, Deployment, LogType, MetaCallJSON } from './deployment';
|
|
3
2
|
import { Plans } from './plan';
|
|
3
|
+
export declare class ProtocolError extends Error {
|
|
4
|
+
status?: number;
|
|
5
|
+
data?: unknown;
|
|
6
|
+
constructor(message: string, status?: number, data?: unknown);
|
|
7
|
+
}
|
|
4
8
|
/**
|
|
5
|
-
* Type guard for protocol-specific errors
|
|
9
|
+
* Type guard for protocol-specific errors.
|
|
6
10
|
* @param err - The unknown error to check.
|
|
7
11
|
* @returns True if the error is an ProtocolError, false otherwise.
|
|
8
12
|
*/
|
|
9
|
-
export declare const isProtocolError: (err: unknown) =>
|
|
10
|
-
export { AxiosError as ProtocolError };
|
|
13
|
+
export declare const isProtocolError: (err: unknown) => err is ProtocolError;
|
|
11
14
|
declare type SubscriptionMap = Record<string, number>;
|
|
12
15
|
export interface SubscriptionDeploy {
|
|
13
16
|
id: string;
|
|
@@ -19,7 +22,7 @@ export declare enum ResourceType {
|
|
|
19
22
|
Package = "Package",
|
|
20
23
|
Repository = "Repository"
|
|
21
24
|
}
|
|
22
|
-
export interface
|
|
25
|
+
export interface Resource {
|
|
23
26
|
id: string;
|
|
24
27
|
}
|
|
25
28
|
export interface Branches {
|
|
@@ -66,8 +69,8 @@ export interface API {
|
|
|
66
69
|
listSubscriptionsDeploys(): Promise<SubscriptionDeploy[]>;
|
|
67
70
|
inspect(): Promise<Deployment[]>;
|
|
68
71
|
inspectByName(suffix: string): Promise<Deployment>;
|
|
69
|
-
upload(name: string, blob: unknown, jsons?: MetaCallJSON[], runners?: string[]): Promise<
|
|
70
|
-
add(url: string, branch: string, jsons: MetaCallJSON[]): Promise<
|
|
72
|
+
upload(name: string, blob: unknown, jsons?: MetaCallJSON[], runners?: string[]): Promise<Resource>;
|
|
73
|
+
add(url: string, branch: string, jsons: MetaCallJSON[]): Promise<Resource>;
|
|
71
74
|
deploy(name: string, env: {
|
|
72
75
|
name: string;
|
|
73
76
|
value: string;
|
|
@@ -82,8 +85,8 @@ export interface API {
|
|
|
82
85
|
}
|
|
83
86
|
declare const _default: (token: string, baseURL: string) => API;
|
|
84
87
|
export default _default;
|
|
85
|
-
export declare const MaxRetries =
|
|
86
|
-
export declare const MaxRetryInterval =
|
|
88
|
+
export declare const MaxRetries = 100;
|
|
89
|
+
export declare const MaxRetryInterval = 5000;
|
|
87
90
|
export declare const MaxFuncLength = 64;
|
|
88
91
|
/**
|
|
89
92
|
* Executes an asynchronous function with automatic retry logic.
|
|
@@ -122,4 +125,4 @@ export declare const MaxFuncLength = 64;
|
|
|
122
125
|
* );
|
|
123
126
|
* ```
|
|
124
127
|
*/
|
|
125
|
-
export declare const waitFor: <T>(fn: () => Promise<T>, maxRetries?: number, interval?: number) => Promise<T>;
|
|
128
|
+
export declare const waitFor: <T>(fn: (cancel: (message: string) => void) => Promise<T>, maxRetries?: number, interval?: number) => Promise<T>;
|
package/dist/protocol.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
this is just a client that implements all the rest API from the FaaS, so each function it contains is an endpoint in the FaaS for deploying and similar
|
|
3
|
+
This is just a client that implements all the rest API from the FaaS,
|
|
4
|
+
so each function it contains is an endpoint in the FaaS for deploying:
|
|
7
5
|
|
|
8
6
|
refresh: updates the auth token
|
|
9
7
|
validate: validates the auth token
|
|
@@ -18,41 +16,25 @@
|
|
|
18
16
|
branchList: get the branches of a repository
|
|
19
17
|
fileList: get files of a repository by branch
|
|
20
18
|
*/
|
|
21
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
22
|
-
if (k2 === undefined) k2 = k;
|
|
23
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
24
|
-
}) : (function(o, m, k, k2) {
|
|
25
|
-
if (k2 === undefined) k2 = k;
|
|
26
|
-
o[k2] = m[k];
|
|
27
|
-
}));
|
|
28
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
-
}) : function(o, v) {
|
|
31
|
-
o["default"] = v;
|
|
32
|
-
});
|
|
33
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
34
|
-
if (mod && mod.__esModule) return mod;
|
|
35
|
-
var result = {};
|
|
36
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
37
|
-
__setModuleDefault(result, mod);
|
|
38
|
-
return result;
|
|
39
|
-
};
|
|
40
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
-
};
|
|
43
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
-
exports.waitFor = exports.MaxFuncLength = exports.MaxRetryInterval = exports.MaxRetries = exports.InvokeType = exports.ResourceType = exports.
|
|
45
|
-
const axios_1 = __importStar(require("axios"));
|
|
46
|
-
Object.defineProperty(exports, "ProtocolError", { enumerable: true, get: function () { return axios_1.AxiosError; } });
|
|
47
|
-
const form_data_1 = __importDefault(require("form-data"));
|
|
20
|
+
exports.waitFor = exports.MaxFuncLength = exports.MaxRetryInterval = exports.MaxRetries = exports.InvokeType = exports.ResourceType = exports.isProtocolError = exports.ProtocolError = void 0;
|
|
48
21
|
const url_1 = require("url");
|
|
49
22
|
const deployment_1 = require("./deployment");
|
|
23
|
+
class ProtocolError extends Error {
|
|
24
|
+
constructor(message, status, data) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = 'ProtocolError';
|
|
27
|
+
this.status = status;
|
|
28
|
+
this.data = data;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.ProtocolError = ProtocolError;
|
|
50
32
|
/**
|
|
51
|
-
* Type guard for protocol-specific errors
|
|
33
|
+
* Type guard for protocol-specific errors.
|
|
52
34
|
* @param err - The unknown error to check.
|
|
53
35
|
* @returns True if the error is an ProtocolError, false otherwise.
|
|
54
36
|
*/
|
|
55
|
-
const isProtocolError = (err) =>
|
|
37
|
+
const isProtocolError = (err) => err instanceof ProtocolError;
|
|
56
38
|
exports.isProtocolError = isProtocolError;
|
|
57
39
|
var ResourceType;
|
|
58
40
|
(function (ResourceType) {
|
|
@@ -64,33 +46,90 @@ var InvokeType;
|
|
|
64
46
|
InvokeType["Call"] = "call";
|
|
65
47
|
InvokeType["Await"] = "await";
|
|
66
48
|
})(InvokeType = exports.InvokeType || (exports.InvokeType = {}));
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
49
|
+
class Request {
|
|
50
|
+
constructor(token, baseURL) {
|
|
51
|
+
this.token = token;
|
|
52
|
+
this.baseURL = baseURL;
|
|
53
|
+
this.impl = {
|
|
54
|
+
url: '',
|
|
55
|
+
headers: new Headers({
|
|
56
|
+
Authorization: 'jwt ' + this.token
|
|
57
|
+
}),
|
|
58
|
+
method: 'GET',
|
|
59
|
+
body: undefined
|
|
75
60
|
};
|
|
76
|
-
}
|
|
61
|
+
}
|
|
62
|
+
url(path) {
|
|
63
|
+
this.impl.url = new url_1.URL(path, this.baseURL).toString();
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
headers(headers = {}) {
|
|
67
|
+
this.impl.headers = new Headers({
|
|
68
|
+
Authorization: 'jwt ' + this.token,
|
|
69
|
+
...headers
|
|
70
|
+
});
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
method(method) {
|
|
74
|
+
this.impl.method = method;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
blob(body) {
|
|
78
|
+
this.impl.body = body;
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
body(body) {
|
|
82
|
+
this.impl.body = JSON.stringify(body);
|
|
83
|
+
this.impl.headers.set('Content-Type', 'application/json');
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
async execute() {
|
|
87
|
+
const config = {
|
|
88
|
+
method: this.impl.method,
|
|
89
|
+
headers: this.impl.headers
|
|
90
|
+
};
|
|
91
|
+
if (this.impl.body !== undefined) {
|
|
92
|
+
config.body = this.impl.body;
|
|
93
|
+
}
|
|
94
|
+
const res = await fetch(this.impl.url, config);
|
|
95
|
+
if (!res.ok) {
|
|
96
|
+
const data = await res.text().catch(() => null);
|
|
97
|
+
throw new Error(`HTTP ${res.status}: ${res.statusText}${data ? ` - ${data}` : ''}`);
|
|
98
|
+
}
|
|
99
|
+
return res;
|
|
100
|
+
}
|
|
101
|
+
async asJson() {
|
|
102
|
+
const res = await this.execute();
|
|
103
|
+
return res.json();
|
|
104
|
+
}
|
|
105
|
+
async asText() {
|
|
106
|
+
const res = await this.execute();
|
|
107
|
+
return res.text();
|
|
108
|
+
}
|
|
109
|
+
async asStatus() {
|
|
110
|
+
const res = await this.execute();
|
|
111
|
+
return res.status;
|
|
112
|
+
}
|
|
113
|
+
async asResponse() {
|
|
114
|
+
return await this.execute();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.default = (token, baseURL) => {
|
|
118
|
+
const request = (url = baseURL) => new Request(token, url);
|
|
77
119
|
const api = {
|
|
78
|
-
refresh: () =>
|
|
79
|
-
|
|
80
|
-
.
|
|
81
|
-
|
|
82
|
-
.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
.get(getURL('/validate'), getConfig())
|
|
86
|
-
.then(res => res.data),
|
|
87
|
-
deployEnabled: () => axios_1.default
|
|
88
|
-
.get(getURL('/api/account/deploy-enabled'), getConfig())
|
|
89
|
-
.then(res => res.data),
|
|
120
|
+
refresh: () => request().url('/api/account/refresh-token').asText(),
|
|
121
|
+
ready: () => request()
|
|
122
|
+
.url('/api/readiness')
|
|
123
|
+
.asStatus()
|
|
124
|
+
.then(status => status === 200),
|
|
125
|
+
validate: () => request().url('/validate').asJson(),
|
|
126
|
+
deployEnabled: () => request().url('/api/account/deploy-enabled').asJson(),
|
|
90
127
|
listSubscriptions: async () => {
|
|
91
|
-
const
|
|
128
|
+
const subscriptionsList = await request()
|
|
129
|
+
.url('/api/billing/list-subscriptions')
|
|
130
|
+
.asJson();
|
|
92
131
|
const subscriptions = {};
|
|
93
|
-
for (const id of
|
|
132
|
+
for (const id of subscriptionsList) {
|
|
94
133
|
if (subscriptions[id] === undefined) {
|
|
95
134
|
subscriptions[id] = 1;
|
|
96
135
|
}
|
|
@@ -100,12 +139,10 @@ exports.default = (token, baseURL) => {
|
|
|
100
139
|
}
|
|
101
140
|
return subscriptions;
|
|
102
141
|
},
|
|
103
|
-
listSubscriptionsDeploys: () =>
|
|
104
|
-
.
|
|
105
|
-
.
|
|
106
|
-
inspect: () =>
|
|
107
|
-
.get(getURL('/api/inspect'), getConfig())
|
|
108
|
-
.then(res => res.data),
|
|
142
|
+
listSubscriptionsDeploys: () => request()
|
|
143
|
+
.url('/api/billing/list-subscriptions')
|
|
144
|
+
.asJson(),
|
|
145
|
+
inspect: () => request().url('/api/inspect').asJson(),
|
|
109
146
|
inspectByName: async (suffix) => {
|
|
110
147
|
const deployments = await api.inspect();
|
|
111
148
|
const deploy = deployments.find(deploy => deploy.suffix == suffix);
|
|
@@ -115,78 +152,97 @@ exports.default = (token, baseURL) => {
|
|
|
115
152
|
return deploy;
|
|
116
153
|
},
|
|
117
154
|
upload: async (name, blob, jsons = [], runners = []) => {
|
|
118
|
-
const fd = new
|
|
155
|
+
const fd = new FormData();
|
|
119
156
|
fd.append('id', name);
|
|
120
157
|
fd.append('type', 'application/x-zip-compressed');
|
|
121
158
|
fd.append('jsons', JSON.stringify(jsons));
|
|
122
159
|
fd.append('runners', JSON.stringify(runners));
|
|
123
|
-
fd.append('raw', blob,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return res.data;
|
|
160
|
+
fd.append('raw', blob, 'blob');
|
|
161
|
+
return await request()
|
|
162
|
+
.url('/api/package/create')
|
|
163
|
+
.method('POST')
|
|
164
|
+
.blob(fd)
|
|
165
|
+
.asJson();
|
|
130
166
|
},
|
|
131
|
-
add: (url, branch, jsons = []) =>
|
|
132
|
-
.
|
|
167
|
+
add: (url, branch, jsons = []) => request()
|
|
168
|
+
.url('/api/repository/add')
|
|
169
|
+
.method('POST')
|
|
170
|
+
.body({
|
|
133
171
|
url,
|
|
134
172
|
branch,
|
|
135
173
|
jsons
|
|
136
|
-
}
|
|
137
|
-
.
|
|
138
|
-
branchList: (url) =>
|
|
139
|
-
.
|
|
174
|
+
})
|
|
175
|
+
.asJson(),
|
|
176
|
+
branchList: (url) => request()
|
|
177
|
+
.url('/api/repository/branchlist')
|
|
178
|
+
.method('POST')
|
|
179
|
+
.body({
|
|
140
180
|
url
|
|
141
|
-
}
|
|
142
|
-
.
|
|
143
|
-
deploy: (name, env, plan, resourceType, release = Date.now().toString(16), version = 'v1') =>
|
|
144
|
-
.
|
|
181
|
+
})
|
|
182
|
+
.asJson(),
|
|
183
|
+
deploy: (name, env, plan, resourceType, release = Date.now().toString(16), version = 'v1') => request()
|
|
184
|
+
.url('/api/deploy/create')
|
|
185
|
+
.method('POST')
|
|
186
|
+
.body({
|
|
145
187
|
resourceType,
|
|
146
188
|
suffix: name,
|
|
147
189
|
release,
|
|
148
190
|
env,
|
|
149
191
|
plan,
|
|
150
192
|
version
|
|
151
|
-
}
|
|
152
|
-
.
|
|
153
|
-
deployDelete: (prefix, suffix, version = 'v1') =>
|
|
154
|
-
.
|
|
193
|
+
})
|
|
194
|
+
.asJson(),
|
|
195
|
+
deployDelete: (prefix, suffix, version = 'v1') => request()
|
|
196
|
+
.url('/api/deploy/delete')
|
|
197
|
+
.method('POST')
|
|
198
|
+
.body({
|
|
155
199
|
prefix,
|
|
156
200
|
suffix,
|
|
157
201
|
version
|
|
158
|
-
}
|
|
159
|
-
.
|
|
160
|
-
logs: (container, type = deployment_1.LogType.Deploy, suffix, prefix, version = 'v1') =>
|
|
161
|
-
.
|
|
202
|
+
})
|
|
203
|
+
.asJson(),
|
|
204
|
+
logs: (container, type = deployment_1.LogType.Deploy, suffix, prefix, version = 'v1') => request()
|
|
205
|
+
.url('/api/deploy/logs')
|
|
206
|
+
.method('POST')
|
|
207
|
+
.body({
|
|
162
208
|
container,
|
|
163
209
|
type,
|
|
164
210
|
suffix,
|
|
165
211
|
prefix,
|
|
166
212
|
version
|
|
167
|
-
}
|
|
168
|
-
.
|
|
169
|
-
fileList: (url, branch) =>
|
|
170
|
-
.
|
|
213
|
+
})
|
|
214
|
+
.asJson(),
|
|
215
|
+
fileList: (url, branch) => request()
|
|
216
|
+
.url('/api/repository/filelist')
|
|
217
|
+
.method('POST')
|
|
218
|
+
.body({
|
|
171
219
|
url,
|
|
172
220
|
branch
|
|
173
|
-
}
|
|
174
|
-
.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const req =
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
221
|
+
})
|
|
222
|
+
.asJson()
|
|
223
|
+
.then(res => res['files']),
|
|
224
|
+
invoke: async (type, prefix, suffix, version = 'v1', name, args) => {
|
|
225
|
+
// Old API
|
|
226
|
+
// const req = request('https://api.metacall.io').url(
|
|
227
|
+
// `/${prefix}/${suffix}/${version}/${type}/${name}`
|
|
228
|
+
// );
|
|
229
|
+
// New API
|
|
230
|
+
const req = request(`https://${version}-${suffix}-${prefix}.api.metacall.io`).url(`/${type}/${name}`);
|
|
231
|
+
if (args === undefined) {
|
|
232
|
+
req.method('GET');
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
req.method('POST').body(args);
|
|
236
|
+
}
|
|
237
|
+
return await req.asJson();
|
|
182
238
|
},
|
|
183
239
|
call: (prefix, suffix, version = 'v1', name, args) => api.invoke(InvokeType.Call, prefix, suffix, version, name, args),
|
|
184
240
|
await: (prefix, suffix, version = 'v1', name, args) => api.invoke(InvokeType.Await, prefix, suffix, version, name, args)
|
|
185
241
|
};
|
|
186
242
|
return api;
|
|
187
243
|
};
|
|
188
|
-
exports.MaxRetries =
|
|
189
|
-
exports.MaxRetryInterval =
|
|
244
|
+
exports.MaxRetries = 100;
|
|
245
|
+
exports.MaxRetryInterval = 5000;
|
|
190
246
|
exports.MaxFuncLength = 64;
|
|
191
247
|
/**
|
|
192
248
|
* Executes an asynchronous function with automatic retry logic.
|
|
@@ -227,9 +283,14 @@ exports.MaxFuncLength = 64;
|
|
|
227
283
|
*/
|
|
228
284
|
const waitFor = async (fn, maxRetries = exports.MaxRetries, interval = exports.MaxRetryInterval) => {
|
|
229
285
|
let retry = 0;
|
|
286
|
+
let cancellation = undefined;
|
|
287
|
+
const cancel = (message) => {
|
|
288
|
+
retry = exports.MaxRetries;
|
|
289
|
+
cancellation = `Operation cancelled with message: ${message}`;
|
|
290
|
+
};
|
|
230
291
|
for (;;) {
|
|
231
292
|
try {
|
|
232
|
-
return await fn();
|
|
293
|
+
return await fn(cancel);
|
|
233
294
|
}
|
|
234
295
|
catch (error) {
|
|
235
296
|
retry++;
|
|
@@ -239,11 +300,13 @@ const waitFor = async (fn, maxRetries = exports.MaxRetries, interval = exports.M
|
|
|
239
300
|
(fnStr.length > exports.MaxFuncLength
|
|
240
301
|
? fnStr.slice(0, exports.MaxFuncLength) + '...'
|
|
241
302
|
: fnStr);
|
|
242
|
-
const message =
|
|
243
|
-
?
|
|
244
|
-
: error
|
|
303
|
+
const message = cancellation !== undefined
|
|
304
|
+
? cancellation
|
|
305
|
+
: exports.isProtocolError(error)
|
|
245
306
|
? error.message
|
|
246
|
-
:
|
|
307
|
+
: error instanceof Error
|
|
308
|
+
? error.message
|
|
309
|
+
: String(error);
|
|
247
310
|
throw new Error(`Failed to execute '${func}' after ${maxRetries} retries: ${message}`);
|
|
248
311
|
}
|
|
249
312
|
await new Promise(r => setTimeout(r, interval));
|
package/dist/signup.js
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const axios_1 = __importDefault(require("axios"));
|
|
7
3
|
const url_1 = require("url");
|
|
8
|
-
exports.default = (email, password, alias, baseURL) => {
|
|
4
|
+
exports.default = async (email, password, alias, baseURL) => {
|
|
9
5
|
const request = {
|
|
10
6
|
email,
|
|
11
7
|
password,
|
|
12
8
|
alias
|
|
13
9
|
};
|
|
14
|
-
if (!baseURL.includes('localhost'))
|
|
15
|
-
request['g-recaptcha-response'] = 'empty';
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
if (!baseURL.includes('localhost')) {
|
|
11
|
+
request['g-recaptcha-response'] = 'empty'; // TODO: Review the captcha
|
|
12
|
+
}
|
|
13
|
+
const res = await fetch(baseURL + '/signup', {
|
|
14
|
+
method: 'POST',
|
|
18
15
|
headers: {
|
|
19
16
|
Accept: 'application/json, text/plain, */*',
|
|
20
17
|
Host: new url_1.URL(baseURL).host,
|
|
21
|
-
Origin: baseURL
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.
|
|
18
|
+
Origin: baseURL,
|
|
19
|
+
'Content-Type': 'application/json'
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify(request)
|
|
22
|
+
});
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
throw new Error(res.statusText);
|
|
25
|
+
}
|
|
26
|
+
return res.text();
|
|
25
27
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metacall/protocol",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"description": "Tool for deploying into MetaCall FaaS platform.",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./*": "./dist/*.js",
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
+
"pretest": "npm --prefix ./src/test/resources/integration/api install",
|
|
21
22
|
"test": "npm run --silent build && mocha dist/test",
|
|
22
|
-
"unit": "npm run --silent test -- --ignore
|
|
23
|
+
"unit": "npm run --silent test -- --ignore **/**.integration.**",
|
|
23
24
|
"prepublishOnly": "npm run --silent build",
|
|
24
25
|
"postinstall": "node -e \"require('fs').existsSync('githooks') && require('./githooks/configure.js').configure()\"",
|
|
25
26
|
"build": "npm run --silent lint && tsc",
|
|
@@ -85,8 +86,6 @@
|
|
|
85
86
|
}
|
|
86
87
|
},
|
|
87
88
|
"dependencies": {
|
|
88
|
-
"axios": "^1.13.5",
|
|
89
|
-
"form-data": "^3.0.0",
|
|
90
89
|
"ignore-walk": "^3.0.4",
|
|
91
90
|
"jsonwebtoken": "^9.0.0"
|
|
92
91
|
},
|
package/src/index.ts
CHANGED
package/src/login.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
1
|
import { URL } from 'url';
|
|
3
2
|
|
|
4
3
|
interface Request {
|
|
@@ -7,7 +6,7 @@ interface Request {
|
|
|
7
6
|
'g-recaptcha-response'?: string;
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
export default (
|
|
9
|
+
export default async (
|
|
11
10
|
email: string,
|
|
12
11
|
password: string,
|
|
13
12
|
baseURL: string
|
|
@@ -17,16 +16,24 @@ export default (
|
|
|
17
16
|
password
|
|
18
17
|
};
|
|
19
18
|
|
|
20
|
-
if (!baseURL.includes('localhost'))
|
|
21
|
-
request['g-recaptcha-response'] = 'empty'; //TODO: Review the captcha
|
|
19
|
+
if (!baseURL.includes('localhost')) {
|
|
20
|
+
request['g-recaptcha-response'] = 'empty'; // TODO: Review the captcha
|
|
21
|
+
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
.
|
|
23
|
+
const res = await fetch(baseURL + '/login', {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
headers: {
|
|
26
|
+
Accept: 'application/json, text/plain, */*',
|
|
27
|
+
Host: new URL(baseURL).host,
|
|
28
|
+
Origin: baseURL,
|
|
29
|
+
'Content-Type': 'application/json'
|
|
30
|
+
},
|
|
31
|
+
body: JSON.stringify(request)
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
throw new Error(res.statusText);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return res.text();
|
|
32
39
|
};
|
package/src/protocol.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
this is just a client that implements all the rest API from the FaaS, so each function it contains is an endpoint in the FaaS for deploying and similar
|
|
2
|
+
This is just a client that implements all the rest API from the FaaS,
|
|
3
|
+
so each function it contains is an endpoint in the FaaS for deploying:
|
|
6
4
|
|
|
7
5
|
refresh: updates the auth token
|
|
8
6
|
validate: validates the auth token
|
|
@@ -18,22 +16,29 @@
|
|
|
18
16
|
fileList: get files of a repository by branch
|
|
19
17
|
*/
|
|
20
18
|
|
|
21
|
-
import axios, { AxiosError, AxiosRequestConfig } from 'axios';
|
|
22
|
-
import FormData from 'form-data';
|
|
23
19
|
import { URL } from 'url';
|
|
24
20
|
import { Create, Deployment, LogType, MetaCallJSON } from './deployment';
|
|
25
21
|
import { Plans } from './plan';
|
|
26
|
-
|
|
22
|
+
|
|
23
|
+
export class ProtocolError extends Error {
|
|
24
|
+
status?: number;
|
|
25
|
+
data?: unknown;
|
|
26
|
+
|
|
27
|
+
constructor(message: string, status?: number, data?: unknown) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = 'ProtocolError';
|
|
30
|
+
this.status = status;
|
|
31
|
+
this.data = data;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
27
34
|
|
|
28
35
|
/**
|
|
29
|
-
* Type guard for protocol-specific errors
|
|
36
|
+
* Type guard for protocol-specific errors.
|
|
30
37
|
* @param err - The unknown error to check.
|
|
31
38
|
* @returns True if the error is an ProtocolError, false otherwise.
|
|
32
39
|
*/
|
|
33
|
-
export const isProtocolError = (err: unknown):
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
export { AxiosError as ProtocolError };
|
|
40
|
+
export const isProtocolError = (err: unknown): err is ProtocolError =>
|
|
41
|
+
err instanceof ProtocolError;
|
|
37
42
|
|
|
38
43
|
type SubscriptionMap = Record<string, number>;
|
|
39
44
|
|
|
@@ -49,7 +54,7 @@ export enum ResourceType {
|
|
|
49
54
|
Repository = 'Repository'
|
|
50
55
|
}
|
|
51
56
|
|
|
52
|
-
export interface
|
|
57
|
+
export interface Resource {
|
|
53
58
|
id: string;
|
|
54
59
|
}
|
|
55
60
|
|
|
@@ -106,12 +111,8 @@ export interface API {
|
|
|
106
111
|
blob: unknown,
|
|
107
112
|
jsons?: MetaCallJSON[],
|
|
108
113
|
runners?: string[]
|
|
109
|
-
): Promise<
|
|
110
|
-
add(
|
|
111
|
-
url: string,
|
|
112
|
-
branch: string,
|
|
113
|
-
jsons: MetaCallJSON[]
|
|
114
|
-
): Promise<AddResponse>;
|
|
114
|
+
): Promise<Resource>;
|
|
115
|
+
add(url: string, branch: string, jsons: MetaCallJSON[]): Promise<Resource>;
|
|
115
116
|
deploy(
|
|
116
117
|
name: string,
|
|
117
118
|
env: { name: string; value: string }[],
|
|
@@ -158,50 +159,131 @@ export interface API {
|
|
|
158
159
|
): Promise<Result>;
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
interface RequestImpl {
|
|
163
|
+
url: string;
|
|
164
|
+
headers: Headers;
|
|
165
|
+
method: string;
|
|
166
|
+
body?: BodyInit;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
class Request {
|
|
170
|
+
private token: string;
|
|
171
|
+
private baseURL: string;
|
|
172
|
+
private impl: RequestImpl;
|
|
173
|
+
|
|
174
|
+
constructor(token: string, baseURL: string) {
|
|
175
|
+
this.token = token;
|
|
176
|
+
this.baseURL = baseURL;
|
|
177
|
+
this.impl = {
|
|
178
|
+
url: '',
|
|
179
|
+
headers: new Headers({
|
|
180
|
+
Authorization: 'jwt ' + this.token
|
|
181
|
+
}),
|
|
182
|
+
method: 'GET',
|
|
183
|
+
body: undefined
|
|
169
184
|
};
|
|
170
|
-
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
url(path: string): Request {
|
|
188
|
+
this.impl.url = new URL(path, this.baseURL).toString();
|
|
189
|
+
return this;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
headers(headers = {}): Request {
|
|
193
|
+
this.impl.headers = new Headers({
|
|
194
|
+
Authorization: 'jwt ' + this.token,
|
|
195
|
+
...headers
|
|
196
|
+
});
|
|
197
|
+
return this;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
method(method: string): Request {
|
|
201
|
+
this.impl.method = method;
|
|
202
|
+
return this;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
blob(body: BodyInit): Request {
|
|
206
|
+
this.impl.body = body;
|
|
207
|
+
return this;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
body(body: unknown): Request {
|
|
211
|
+
this.impl.body = JSON.stringify(body);
|
|
212
|
+
this.impl.headers.set('Content-Type', 'application/json');
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private async execute(): Promise<Response> {
|
|
217
|
+
const config: RequestInit = {
|
|
218
|
+
method: this.impl.method,
|
|
219
|
+
headers: this.impl.headers
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
if (this.impl.body !== undefined) {
|
|
223
|
+
config.body = this.impl.body;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const res = await fetch(this.impl.url, config);
|
|
227
|
+
|
|
228
|
+
if (!res.ok) {
|
|
229
|
+
const data = await res.text().catch(() => null);
|
|
230
|
+
throw new Error(
|
|
231
|
+
`HTTP ${res.status}: ${res.statusText}${
|
|
232
|
+
data ? ` - ${data}` : ''
|
|
233
|
+
}`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return res;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async asJson<T>(): Promise<T> {
|
|
241
|
+
const res = await this.execute();
|
|
242
|
+
return res.json() as Promise<T>;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async asText(): Promise<string> {
|
|
246
|
+
const res = await this.execute();
|
|
247
|
+
return res.text();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async asStatus(): Promise<number> {
|
|
251
|
+
const res = await this.execute();
|
|
252
|
+
return res.status;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async asResponse(): Promise<Response> {
|
|
256
|
+
return await this.execute();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export default (token: string, baseURL: string): API => {
|
|
261
|
+
const request = (url = baseURL) => new Request(token, url);
|
|
171
262
|
|
|
172
263
|
const api: API = {
|
|
173
264
|
refresh: (): Promise<string> =>
|
|
174
|
-
|
|
175
|
-
.get<string>(getURL('/api/account/refresh-token'), getConfig())
|
|
176
|
-
.then(res => res.data),
|
|
265
|
+
request().url('/api/account/refresh-token').asText(),
|
|
177
266
|
|
|
178
267
|
ready: (): Promise<boolean> =>
|
|
179
|
-
|
|
180
|
-
.
|
|
181
|
-
.
|
|
268
|
+
request()
|
|
269
|
+
.url('/api/readiness')
|
|
270
|
+
.asStatus()
|
|
271
|
+
.then(status => status === 200),
|
|
182
272
|
|
|
183
273
|
validate: (): Promise<boolean> =>
|
|
184
|
-
|
|
185
|
-
.get<boolean>(getURL('/validate'), getConfig())
|
|
186
|
-
.then(res => res.data),
|
|
274
|
+
request().url('/validate').asJson<boolean>(),
|
|
187
275
|
|
|
188
276
|
deployEnabled: (): Promise<boolean> =>
|
|
189
|
-
|
|
190
|
-
.get<boolean>(
|
|
191
|
-
getURL('/api/account/deploy-enabled'),
|
|
192
|
-
getConfig()
|
|
193
|
-
)
|
|
194
|
-
.then(res => res.data),
|
|
277
|
+
request().url('/api/account/deploy-enabled').asJson<boolean>(),
|
|
195
278
|
|
|
196
279
|
listSubscriptions: async (): Promise<SubscriptionMap> => {
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
);
|
|
280
|
+
const subscriptionsList = await request()
|
|
281
|
+
.url('/api/billing/list-subscriptions')
|
|
282
|
+
.asJson<string[]>();
|
|
201
283
|
|
|
202
284
|
const subscriptions: SubscriptionMap = {};
|
|
203
285
|
|
|
204
|
-
for (const id of
|
|
286
|
+
for (const id of subscriptionsList) {
|
|
205
287
|
if (subscriptions[id] === undefined) {
|
|
206
288
|
subscriptions[id] = 1;
|
|
207
289
|
} else {
|
|
@@ -213,17 +295,12 @@ export default (token: string, baseURL: string): API => {
|
|
|
213
295
|
},
|
|
214
296
|
|
|
215
297
|
listSubscriptionsDeploys: (): Promise<SubscriptionDeploy[]> =>
|
|
216
|
-
|
|
217
|
-
.
|
|
218
|
-
|
|
219
|
-
getConfig()
|
|
220
|
-
)
|
|
221
|
-
.then(res => res.data),
|
|
298
|
+
request()
|
|
299
|
+
.url('/api/billing/list-subscriptions')
|
|
300
|
+
.asJson<SubscriptionDeploy[]>(),
|
|
222
301
|
|
|
223
302
|
inspect: (): Promise<Deployment[]> =>
|
|
224
|
-
|
|
225
|
-
.get<Deployment[]>(getURL('/api/inspect'), getConfig())
|
|
226
|
-
.then(res => res.data),
|
|
303
|
+
request().url('/api/inspect').asJson<Deployment[]>(),
|
|
227
304
|
|
|
228
305
|
inspectByName: async (suffix: string): Promise<Deployment> => {
|
|
229
306
|
const deployments = await api.inspect();
|
|
@@ -239,52 +316,48 @@ export default (token: string, baseURL: string): API => {
|
|
|
239
316
|
|
|
240
317
|
upload: async (
|
|
241
318
|
name: string,
|
|
242
|
-
blob:
|
|
319
|
+
blob: Blob,
|
|
243
320
|
jsons: MetaCallJSON[] = [],
|
|
244
321
|
runners: string[] = []
|
|
245
|
-
): Promise<
|
|
322
|
+
): Promise<Resource> => {
|
|
246
323
|
const fd = new FormData();
|
|
324
|
+
|
|
247
325
|
fd.append('id', name);
|
|
248
326
|
fd.append('type', 'application/x-zip-compressed');
|
|
249
327
|
fd.append('jsons', JSON.stringify(jsons));
|
|
250
328
|
fd.append('runners', JSON.stringify(runners));
|
|
251
|
-
fd.append('raw', blob,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
getConfig() // Axios automatically sets multipart headers
|
|
259
|
-
);
|
|
260
|
-
return res.data;
|
|
329
|
+
fd.append('raw', blob, 'blob');
|
|
330
|
+
|
|
331
|
+
return await request()
|
|
332
|
+
.url('/api/package/create')
|
|
333
|
+
.method('POST')
|
|
334
|
+
.blob(fd)
|
|
335
|
+
.asJson<Resource>();
|
|
261
336
|
},
|
|
337
|
+
|
|
262
338
|
add: (
|
|
263
339
|
url: string,
|
|
264
340
|
branch: string,
|
|
265
341
|
jsons: MetaCallJSON[] = []
|
|
266
|
-
): Promise<
|
|
267
|
-
|
|
268
|
-
.
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
.then(res => res.data),
|
|
342
|
+
): Promise<Resource> =>
|
|
343
|
+
request()
|
|
344
|
+
.url('/api/repository/add')
|
|
345
|
+
.method('POST')
|
|
346
|
+
.body({
|
|
347
|
+
url,
|
|
348
|
+
branch,
|
|
349
|
+
jsons
|
|
350
|
+
})
|
|
351
|
+
.asJson<Resource>(),
|
|
352
|
+
|
|
278
353
|
branchList: (url: string): Promise<Branches> =>
|
|
279
|
-
|
|
280
|
-
.
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
)
|
|
287
|
-
.then(res => res.data),
|
|
354
|
+
request()
|
|
355
|
+
.url('/api/repository/branchlist')
|
|
356
|
+
.method('POST')
|
|
357
|
+
.body({
|
|
358
|
+
url
|
|
359
|
+
})
|
|
360
|
+
.asJson<Branches>(),
|
|
288
361
|
|
|
289
362
|
deploy: (
|
|
290
363
|
name: string,
|
|
@@ -294,37 +367,33 @@ export default (token: string, baseURL: string): API => {
|
|
|
294
367
|
release: string = Date.now().toString(16),
|
|
295
368
|
version = 'v1'
|
|
296
369
|
): Promise<Create> =>
|
|
297
|
-
|
|
298
|
-
.
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
)
|
|
310
|
-
.then(res => res.data),
|
|
370
|
+
request()
|
|
371
|
+
.url('/api/deploy/create')
|
|
372
|
+
.method('POST')
|
|
373
|
+
.body({
|
|
374
|
+
resourceType,
|
|
375
|
+
suffix: name,
|
|
376
|
+
release,
|
|
377
|
+
env,
|
|
378
|
+
plan,
|
|
379
|
+
version
|
|
380
|
+
})
|
|
381
|
+
.asJson<Create>(),
|
|
311
382
|
|
|
312
383
|
deployDelete: (
|
|
313
384
|
prefix: string,
|
|
314
385
|
suffix: string,
|
|
315
386
|
version = 'v1'
|
|
316
387
|
): Promise<string> =>
|
|
317
|
-
|
|
318
|
-
.
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
)
|
|
327
|
-
.then(res => res.data),
|
|
388
|
+
request()
|
|
389
|
+
.url('/api/deploy/delete')
|
|
390
|
+
.method('POST')
|
|
391
|
+
.body({
|
|
392
|
+
prefix,
|
|
393
|
+
suffix,
|
|
394
|
+
version
|
|
395
|
+
})
|
|
396
|
+
.asJson<string>(),
|
|
328
397
|
|
|
329
398
|
logs: (
|
|
330
399
|
container: string,
|
|
@@ -333,33 +402,30 @@ export default (token: string, baseURL: string): API => {
|
|
|
333
402
|
prefix: string,
|
|
334
403
|
version = 'v1'
|
|
335
404
|
): Promise<string> =>
|
|
336
|
-
|
|
337
|
-
.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
)
|
|
348
|
-
.then(res => res.data),
|
|
405
|
+
request()
|
|
406
|
+
.url('/api/deploy/logs')
|
|
407
|
+
.method('POST')
|
|
408
|
+
.body({
|
|
409
|
+
container,
|
|
410
|
+
type,
|
|
411
|
+
suffix,
|
|
412
|
+
prefix,
|
|
413
|
+
version
|
|
414
|
+
})
|
|
415
|
+
.asJson<string>(),
|
|
349
416
|
|
|
350
417
|
fileList: (url: string, branch: string): Promise<string[]> =>
|
|
351
|
-
|
|
352
|
-
.
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
invoke: <Result, Args = unknown>(
|
|
418
|
+
request()
|
|
419
|
+
.url('/api/repository/filelist')
|
|
420
|
+
.method('POST')
|
|
421
|
+
.body({
|
|
422
|
+
url,
|
|
423
|
+
branch
|
|
424
|
+
})
|
|
425
|
+
.asJson<{ [k: string]: string[] }>()
|
|
426
|
+
.then(res => res['files']),
|
|
427
|
+
|
|
428
|
+
invoke: async <Result, Args = unknown>(
|
|
363
429
|
type: InvokeType,
|
|
364
430
|
prefix: string,
|
|
365
431
|
suffix: string,
|
|
@@ -367,17 +433,23 @@ export default (token: string, baseURL: string): API => {
|
|
|
367
433
|
name: string,
|
|
368
434
|
args?: Args
|
|
369
435
|
): Promise<Result> => {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
436
|
+
// Old API
|
|
437
|
+
// const req = request('https://api.metacall.io').url(
|
|
438
|
+
// `/${prefix}/${suffix}/${version}/${type}/${name}`
|
|
439
|
+
// );
|
|
440
|
+
|
|
441
|
+
// New API
|
|
442
|
+
const req = request(
|
|
443
|
+
`https://${version}-${suffix}-${prefix}.api.metacall.io`
|
|
444
|
+
).url(`/${type}/${name}`);
|
|
445
|
+
|
|
446
|
+
if (args === undefined) {
|
|
447
|
+
req.method('GET');
|
|
448
|
+
} else {
|
|
449
|
+
req.method('POST').body(args);
|
|
450
|
+
}
|
|
379
451
|
|
|
380
|
-
return req.
|
|
452
|
+
return await req.asJson<Result>();
|
|
381
453
|
},
|
|
382
454
|
|
|
383
455
|
call: <Result, Args = unknown>(
|
|
@@ -402,8 +474,8 @@ export default (token: string, baseURL: string): API => {
|
|
|
402
474
|
return api;
|
|
403
475
|
};
|
|
404
476
|
|
|
405
|
-
export const MaxRetries =
|
|
406
|
-
export const MaxRetryInterval =
|
|
477
|
+
export const MaxRetries = 100;
|
|
478
|
+
export const MaxRetryInterval = 5000;
|
|
407
479
|
export const MaxFuncLength = 64;
|
|
408
480
|
|
|
409
481
|
/**
|
|
@@ -444,15 +516,21 @@ export const MaxFuncLength = 64;
|
|
|
444
516
|
* ```
|
|
445
517
|
*/
|
|
446
518
|
export const waitFor = async <T>(
|
|
447
|
-
fn: () => Promise<T>,
|
|
519
|
+
fn: (cancel: (message: string) => void) => Promise<T>,
|
|
448
520
|
maxRetries: number = MaxRetries,
|
|
449
521
|
interval: number = MaxRetryInterval
|
|
450
522
|
): Promise<T> => {
|
|
451
523
|
let retry = 0;
|
|
524
|
+
let cancellation = undefined;
|
|
525
|
+
|
|
526
|
+
const cancel = (message: string) => {
|
|
527
|
+
retry = MaxRetries;
|
|
528
|
+
cancellation = `Operation cancelled with message: ${message}`;
|
|
529
|
+
};
|
|
452
530
|
|
|
453
531
|
for (;;) {
|
|
454
532
|
try {
|
|
455
|
-
return await fn();
|
|
533
|
+
return await fn(cancel);
|
|
456
534
|
} catch (error) {
|
|
457
535
|
retry++;
|
|
458
536
|
if (retry >= maxRetries) {
|
|
@@ -462,11 +540,14 @@ export const waitFor = async <T>(
|
|
|
462
540
|
(fnStr.length > MaxFuncLength
|
|
463
541
|
? fnStr.slice(0, MaxFuncLength) + '...'
|
|
464
542
|
: fnStr);
|
|
465
|
-
const message =
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
543
|
+
const message =
|
|
544
|
+
cancellation !== undefined
|
|
545
|
+
? cancellation
|
|
546
|
+
: isProtocolError(error)
|
|
547
|
+
? error.message
|
|
548
|
+
: error instanceof Error
|
|
549
|
+
? error.message
|
|
550
|
+
: String(error);
|
|
470
551
|
|
|
471
552
|
throw new Error(
|
|
472
553
|
`Failed to execute '${func}' after ${maxRetries} retries: ${message}`
|
package/src/signup.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
1
|
import { URL } from 'url';
|
|
3
2
|
interface Request {
|
|
4
3
|
email: string;
|
|
@@ -7,7 +6,7 @@ interface Request {
|
|
|
7
6
|
'g-recaptcha-response'?: string;
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
export default (
|
|
9
|
+
export default async (
|
|
11
10
|
email: string,
|
|
12
11
|
password: string,
|
|
13
12
|
alias: string,
|
|
@@ -18,15 +17,25 @@ export default (
|
|
|
18
17
|
password,
|
|
19
18
|
alias
|
|
20
19
|
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
|
|
21
|
+
if (!baseURL.includes('localhost')) {
|
|
22
|
+
request['g-recaptcha-response'] = 'empty'; // TODO: Review the captcha
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const res = await fetch(baseURL + '/signup', {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
headers: {
|
|
28
|
+
Accept: 'application/json, text/plain, */*',
|
|
29
|
+
Host: new URL(baseURL).host,
|
|
30
|
+
Origin: baseURL,
|
|
31
|
+
'Content-Type': 'application/json'
|
|
32
|
+
},
|
|
33
|
+
body: JSON.stringify(request)
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (!res.ok) {
|
|
37
|
+
throw new Error(res.statusText);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return res.text();
|
|
32
41
|
};
|