@openstax/ts-utils 1.21.12 → 1.23.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/cjs/errors/index.d.ts +11 -0
- package/dist/cjs/errors/index.js +15 -1
- package/dist/cjs/middleware/apiErrorHandler.d.ts +4 -3
- package/dist/cjs/middleware/apiErrorHandler.js +4 -3
- package/dist/cjs/misc/helpers.js +1 -1
- package/dist/cjs/services/accountsGateway/index.js +3 -4
- package/dist/cjs/services/apiGateway/index.d.ts +6 -2
- package/dist/cjs/services/apiGateway/index.js +17 -5
- package/dist/cjs/services/fileServer/index.d.ts +0 -2
- package/dist/cjs/services/fileServer/localFileServer.d.ts +0 -4
- package/dist/cjs/services/fileServer/localFileServer.js +0 -57
- package/dist/cjs/services/fileServer/s3FileServer.js +0 -24
- package/dist/cjs/services/lrsGateway/index.js +1 -1
- package/dist/cjs/services/postgresConnection/index.js +1 -3
- package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +1 -1
- package/dist/esm/errors/index.d.ts +11 -0
- package/dist/esm/errors/index.js +13 -0
- package/dist/esm/middleware/apiErrorHandler.d.ts +4 -3
- package/dist/esm/middleware/apiErrorHandler.js +5 -4
- package/dist/esm/misc/helpers.js +1 -1
- package/dist/esm/services/accountsGateway/index.js +3 -4
- package/dist/esm/services/apiGateway/index.d.ts +6 -2
- package/dist/esm/services/apiGateway/index.js +18 -6
- package/dist/esm/services/fileServer/index.d.ts +0 -2
- package/dist/esm/services/fileServer/localFileServer.d.ts +0 -4
- package/dist/esm/services/fileServer/localFileServer.js +0 -57
- package/dist/esm/services/fileServer/s3FileServer.js +1 -25
- package/dist/esm/services/lrsGateway/index.js +1 -1
- package/dist/esm/services/postgresConnection/index.js +1 -3
- package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +1 -1
- package/package.json +16 -16
- package/script/bin/deploy.bash +8 -0
- package/script/bin/get-env-param.bash +3 -3
- package/script/bin/init-params-script.bash +10 -1
- package/script/bin/upload-params.bash +3 -3
|
@@ -42,6 +42,17 @@ export declare class UnauthorizedError extends Error {
|
|
|
42
42
|
static matches: (e: any) => e is typeof UnauthorizedError;
|
|
43
43
|
constructor(message?: string);
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Forbidden error
|
|
47
|
+
*
|
|
48
|
+
* `ForbiddenError.matches(error)` is a reliable way to check if an error is a
|
|
49
|
+
* `ForbiddenError`; `instanceof` checks may not work if code is split into multiple bundles
|
|
50
|
+
*/
|
|
51
|
+
export declare class ForbiddenError extends Error {
|
|
52
|
+
static readonly TYPE = "ForbiddenError";
|
|
53
|
+
static matches: (e: any) => e is typeof ForbiddenError;
|
|
54
|
+
constructor(message?: string);
|
|
55
|
+
}
|
|
45
56
|
/**
|
|
46
57
|
* Not found error
|
|
47
58
|
*
|
package/dist/cjs/errors/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SessionExpiredError = exports.NotFoundError = exports.UnauthorizedError = exports.ValidationError = exports.InvalidRequestError = exports.isAppError = void 0;
|
|
3
|
+
exports.SessionExpiredError = exports.NotFoundError = exports.ForbiddenError = exports.UnauthorizedError = exports.ValidationError = exports.InvalidRequestError = exports.isAppError = void 0;
|
|
4
4
|
/*
|
|
5
5
|
* if code is split into multiple bundles, sometimes each bundle
|
|
6
6
|
* will get its own definition of this module and then instanceof checks
|
|
@@ -65,6 +65,20 @@ class UnauthorizedError extends Error {
|
|
|
65
65
|
exports.UnauthorizedError = UnauthorizedError;
|
|
66
66
|
UnauthorizedError.TYPE = 'UnauthorizedError';
|
|
67
67
|
UnauthorizedError.matches = errorIsType(UnauthorizedError);
|
|
68
|
+
/**
|
|
69
|
+
* Forbidden error
|
|
70
|
+
*
|
|
71
|
+
* `ForbiddenError.matches(error)` is a reliable way to check if an error is a
|
|
72
|
+
* `ForbiddenError`; `instanceof` checks may not work if code is split into multiple bundles
|
|
73
|
+
*/
|
|
74
|
+
class ForbiddenError extends Error {
|
|
75
|
+
constructor(message) {
|
|
76
|
+
super(message || ForbiddenError.TYPE);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.ForbiddenError = ForbiddenError;
|
|
80
|
+
ForbiddenError.TYPE = 'ForbiddenError';
|
|
81
|
+
ForbiddenError.matches = errorIsType(ForbiddenError);
|
|
68
82
|
/**
|
|
69
83
|
* Not found error
|
|
70
84
|
*
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { InvalidRequestError, NotFoundError, SessionExpiredError, UnauthorizedError, ValidationError } from '../errors';
|
|
1
|
+
import { ForbiddenError, InvalidRequestError, NotFoundError, SessionExpiredError, UnauthorizedError, ValidationError } from '../errors';
|
|
2
2
|
import type { ApiResponse } from '../routing';
|
|
3
3
|
import type { Logger } from '../services/logger';
|
|
4
4
|
export declare type DefaultErrors = {
|
|
5
|
+
InvalidRequestError: InvalidRequestError;
|
|
5
6
|
UnauthorizedError: UnauthorizedError;
|
|
6
|
-
|
|
7
|
+
ForbiddenError: ForbiddenError;
|
|
7
8
|
NotFoundError: NotFoundError;
|
|
8
|
-
InvalidRequestError: InvalidRequestError;
|
|
9
9
|
ValidationError: ValidationError;
|
|
10
|
+
SessionExpiredError: SessionExpiredError;
|
|
10
11
|
};
|
|
11
12
|
export declare type Handlers<E> = {
|
|
12
13
|
[T in keyof E]: (e: E[T], logger: Logger) => ApiResponse<number, any>;
|
|
@@ -5,11 +5,12 @@ const errors_1 = require("../errors");
|
|
|
5
5
|
const routing_1 = require("../routing");
|
|
6
6
|
const logger_1 = require("../services/logger");
|
|
7
7
|
exports.defaultHandlers = {
|
|
8
|
-
UnauthorizedError: () => (0, routing_1.apiTextResponse)(401, '401 UnauthorizedError'),
|
|
9
|
-
SessionExpiredError: () => (0, routing_1.apiTextResponse)(440, '440 SessionExpiredError'),
|
|
10
|
-
NotFoundError: (e) => (0, routing_1.apiTextResponse)(404, `404 ${e.message}`),
|
|
11
8
|
InvalidRequestError: (e) => (0, routing_1.apiTextResponse)(400, `400 ${e.message}`),
|
|
9
|
+
UnauthorizedError: (e) => (0, routing_1.apiTextResponse)(401, `401 ${e.message}`),
|
|
10
|
+
ForbiddenError: (e) => (0, routing_1.apiTextResponse)(403, `403 ${e.message}`),
|
|
11
|
+
NotFoundError: (e) => (0, routing_1.apiTextResponse)(404, `404 ${e.message}`),
|
|
12
12
|
ValidationError: (e) => (0, routing_1.apiJsonResponse)(422, e.getData()),
|
|
13
|
+
SessionExpiredError: (e) => (0, routing_1.apiTextResponse)(440, `440 ${e.message}`),
|
|
13
14
|
};
|
|
14
15
|
/**
|
|
15
16
|
* Creates an error handler. Provides default handlers for `UnauthorizedError`,
|
package/dist/cjs/misc/helpers.js
CHANGED
|
@@ -84,7 +84,7 @@ const retryWithDelay = (fn, options) => {
|
|
|
84
84
|
reject(e);
|
|
85
85
|
}
|
|
86
86
|
else {
|
|
87
|
-
(_a = options === null || options === void 0 ? void 0 : options.logger) === null || _a === void 0 ? void 0 : _a.log(`failed try ${n} of ${retries}. ${e.message}`);
|
|
87
|
+
(_a = options === null || options === void 0 ? void 0 : options.logger) === null || _a === void 0 ? void 0 : _a.log(`failed try ${n + 1} of ${retries}. ${e.message}`);
|
|
88
88
|
setTimeout(() => (0, exports.retryWithDelay)(fn, { ...options, n: n + 1 }).then(resolve, reject), timeout);
|
|
89
89
|
}
|
|
90
90
|
});
|
|
@@ -23,11 +23,10 @@ const accountsGateway = (initializer) => (configProvider) => {
|
|
|
23
23
|
const request = async (method, path, options, statuses = [200, 201]) => {
|
|
24
24
|
const host = (await accountsBase).replace(/\/+$/, '');
|
|
25
25
|
const url = `${host}/api/${path}`;
|
|
26
|
-
const token = options.token || await accountsAuthToken;
|
|
27
26
|
const config = {
|
|
28
|
-
headers:
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
headers: {
|
|
28
|
+
Authorization: `Bearer ${options.token || await accountsAuthToken}`,
|
|
29
|
+
},
|
|
31
30
|
method,
|
|
32
31
|
};
|
|
33
32
|
if (options.body) {
|
|
@@ -3,6 +3,7 @@ import { ConfigProviderForConfig } from '../../config';
|
|
|
3
3
|
import { ConfigForFetch, GenericFetch, Response } from '../../fetch';
|
|
4
4
|
import { AnyRoute, ApiResponse, OutputForRoute, ParamsForRoute, PayloadForRoute, QueryParams } from '../../routing';
|
|
5
5
|
import { UnwrapPromise } from '../../types';
|
|
6
|
+
import { Logger } from '../logger';
|
|
6
7
|
declare type TResponsePayload<R> = R extends ApiResponse<any, infer P> ? P : never;
|
|
7
8
|
declare type TResponseStatus<R> = R extends ApiResponse<infer S, any> ? S : never;
|
|
8
9
|
declare type RouteClient<R> = {
|
|
@@ -49,8 +50,11 @@ export declare const loadResponse: (response: Response) => () => Promise<any>;
|
|
|
49
50
|
interface MakeApiGateway<F> {
|
|
50
51
|
<Ru>(config: ConfigProviderForConfig<{
|
|
51
52
|
apiBase: string;
|
|
52
|
-
}>, routes: MapRoutesToConfig<Ru>,
|
|
53
|
-
|
|
53
|
+
}>, routes: MapRoutesToConfig<Ru>, appProvider?: {
|
|
54
|
+
authProvider?: {
|
|
55
|
+
getAuthorizedFetchConfig: () => Promise<ConfigForFetch<F>>;
|
|
56
|
+
};
|
|
57
|
+
logger?: Logger;
|
|
54
58
|
}): MapRoutesToClient<Ru>;
|
|
55
59
|
}
|
|
56
60
|
export declare const createApiGateway: <F extends GenericFetch<import("../../fetch").FetchConfig, Response>>(initializer: {
|
|
@@ -29,10 +29,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
29
29
|
exports.createApiGateway = exports.loadResponse = void 0;
|
|
30
30
|
const pathToRegexp = __importStar(require("path-to-regexp"));
|
|
31
31
|
const query_string_1 = __importDefault(require("query-string"));
|
|
32
|
+
const uuid_1 = require("uuid");
|
|
32
33
|
const __1 = require("../..");
|
|
33
34
|
const config_1 = require("../../config");
|
|
34
35
|
const errors_1 = require("../../errors");
|
|
35
36
|
const fetchStatusRetry_1 = require("../../fetch/fetchStatusRetry");
|
|
37
|
+
const logger_1 = require("../logger");
|
|
36
38
|
/** Pulls the content out of a response based on the content type */
|
|
37
39
|
const loadResponse = (response) => () => {
|
|
38
40
|
const [contentType] = (response.headers.get('content-type') || '').split(';');
|
|
@@ -46,7 +48,7 @@ const loadResponse = (response) => () => {
|
|
|
46
48
|
}
|
|
47
49
|
};
|
|
48
50
|
exports.loadResponse = loadResponse;
|
|
49
|
-
const makeRouteClient = (initializer, config, route,
|
|
51
|
+
const makeRouteClient = (initializer, config, route, appProvider) => {
|
|
50
52
|
/* TODO this duplicates code with makeRenderRouteUrl, reuse that */
|
|
51
53
|
const renderUrl = async ({ params, query }) => {
|
|
52
54
|
const apiBase = await (0, config_1.resolveConfigValue)(config.apiBase);
|
|
@@ -55,21 +57,31 @@ const makeRouteClient = (initializer, config, route, authProvider) => {
|
|
|
55
57
|
return apiBase.replace(/\/+$/, '') + getPathForParams(params || {}) + (search ? `?${search}` : '');
|
|
56
58
|
};
|
|
57
59
|
const routeClient = async ({ params, payload, query, fetchConfig }) => {
|
|
60
|
+
var _a, _b;
|
|
61
|
+
const { fetch } = initializer;
|
|
58
62
|
const url = await renderUrl({ params, query });
|
|
59
63
|
const body = payload ? JSON.stringify(payload) : undefined;
|
|
60
|
-
const baseOptions = (0, __1.merge)((await (
|
|
61
|
-
const
|
|
64
|
+
const baseOptions = (0, __1.merge)((await ((_a = appProvider === null || appProvider === void 0 ? void 0 : appProvider.authProvider) === null || _a === void 0 ? void 0 : _a.getAuthorizedFetchConfig())) || {}, fetchConfig || {});
|
|
65
|
+
const requestId = (0, uuid_1.v4)();
|
|
66
|
+
const requestLogger = (_b = appProvider === null || appProvider === void 0 ? void 0 : appProvider.logger) === null || _b === void 0 ? void 0 : _b.createSubContext();
|
|
67
|
+
requestLogger === null || requestLogger === void 0 ? void 0 : requestLogger.setContext({ requestId, url, timeStamp: new Date().getTime() });
|
|
68
|
+
const fetcher = (0, fetchStatusRetry_1.fetchStatusRetry)(fetch, { retries: 1, status: [502], logger: requestLogger });
|
|
69
|
+
requestLogger === null || requestLogger === void 0 ? void 0 : requestLogger.log('Request Initiated', logger_1.Level.Info);
|
|
62
70
|
return fetcher(url, (0, __1.merge)(baseOptions, {
|
|
63
71
|
method: route.method,
|
|
64
72
|
body,
|
|
65
73
|
headers: {
|
|
66
74
|
...fetchConfig === null || fetchConfig === void 0 ? void 0 : fetchConfig.headers,
|
|
67
75
|
...(body ? { 'content-type': 'application/json' } : {}),
|
|
76
|
+
'X-Request-ID': requestId,
|
|
68
77
|
}
|
|
69
78
|
})).then(response => {
|
|
70
79
|
if (response.status === 401) {
|
|
71
80
|
throw new errors_1.UnauthorizedError();
|
|
72
81
|
}
|
|
82
|
+
if (response.status === 403) {
|
|
83
|
+
throw new errors_1.ForbiddenError();
|
|
84
|
+
}
|
|
73
85
|
if (response.status === 440) {
|
|
74
86
|
throw new errors_1.SessionExpiredError();
|
|
75
87
|
}
|
|
@@ -89,8 +101,8 @@ const makeRouteClient = (initializer, config, route, authProvider) => {
|
|
|
89
101
|
routeClient.renderUrl = renderUrl;
|
|
90
102
|
return routeClient;
|
|
91
103
|
};
|
|
92
|
-
const createApiGateway = (initializer) => (config, routes,
|
|
104
|
+
const createApiGateway = (initializer) => (config, routes, appProvider) => {
|
|
93
105
|
return Object.fromEntries(Object.entries(routes)
|
|
94
|
-
.map(([key, routeConfig]) => ([key, makeRouteClient(initializer, config, routeConfig,
|
|
106
|
+
.map(([key, routeConfig]) => ([key, makeRouteClient(initializer, config, routeConfig, appProvider)])));
|
|
95
107
|
};
|
|
96
108
|
exports.createApiGateway = createApiGateway;
|
|
@@ -12,8 +12,6 @@ export declare type FolderValue = {
|
|
|
12
12
|
export declare const isFileValue: (thing: any) => thing is FileValue;
|
|
13
13
|
export declare const isFolderValue: (thing: any) => thing is FolderValue;
|
|
14
14
|
export interface FileServerAdapter {
|
|
15
|
-
putFileContent: (source: FileValue, content: string) => Promise<FileValue>;
|
|
16
|
-
getSignedViewerUrl: (source: FileValue) => Promise<string>;
|
|
17
15
|
getFileContent: (source: FileValue) => Promise<Buffer>;
|
|
18
16
|
}
|
|
19
17
|
export declare const isFileOrFolder: (thing: any) => thing is FileValue | FolderValue;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { ConfigProviderForConfig } from '../../config';
|
|
2
2
|
import { FileServerAdapter } from '.';
|
|
3
3
|
export declare type Config = {
|
|
4
|
-
port?: string;
|
|
5
|
-
host?: string;
|
|
6
4
|
storagePrefix: string;
|
|
7
5
|
};
|
|
8
6
|
interface Initializer<C> {
|
|
@@ -10,8 +8,6 @@ interface Initializer<C> {
|
|
|
10
8
|
configSpace?: C;
|
|
11
9
|
}
|
|
12
10
|
export declare const localFileServer: <C extends string = "local">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
13
|
-
port?: import("../../config").ConfigValueProvider<string> | undefined;
|
|
14
|
-
host?: import("../../config").ConfigValueProvider<string> | undefined;
|
|
15
11
|
storagePrefix: import("../../config").ConfigValueProvider<string>;
|
|
16
12
|
}; }) => FileServerAdapter;
|
|
17
13
|
export {};
|
|
@@ -8,73 +8,16 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const config_1 = require("../../config");
|
|
10
10
|
const guards_1 = require("../../guards");
|
|
11
|
-
const cors_1 = __importDefault(require("cors"));
|
|
12
|
-
const express_1 = __importDefault(require("express"));
|
|
13
|
-
const multer_1 = __importDefault(require("multer"));
|
|
14
|
-
const https_1 = __importDefault(require("https"));
|
|
15
|
-
const helpers_1 = require("../../misc/helpers");
|
|
16
|
-
const assertions_1 = require("../../assertions");
|
|
17
|
-
/* istanbul ignore next */
|
|
18
|
-
const startServer = (0, helpers_1.once)((port, uploadDir) => {
|
|
19
|
-
// TODO - re-evaluate the `preservePath` behavior to match whatever s3 does
|
|
20
|
-
const upload = (0, multer_1.default)({ dest: uploadDir, preservePath: true });
|
|
21
|
-
const fileServerApp = (0, express_1.default)();
|
|
22
|
-
fileServerApp.use((0, cors_1.default)());
|
|
23
|
-
fileServerApp.use(express_1.default.static(uploadDir));
|
|
24
|
-
fileServerApp.post('/', upload.single('file'), async (req, res) => {
|
|
25
|
-
const file = req.file;
|
|
26
|
-
if (!file) {
|
|
27
|
-
return res.status(400).send({ message: 'file is required' });
|
|
28
|
-
}
|
|
29
|
-
const destinationName = req.body.key.replace('${filename}', file.originalname);
|
|
30
|
-
const destinationPath = path_1.default.join(uploadDir, destinationName);
|
|
31
|
-
const destinationDirectory = path_1.default.dirname(destinationPath);
|
|
32
|
-
await fs_1.default.promises.mkdir(destinationDirectory, { recursive: true });
|
|
33
|
-
await fs_1.default.promises.rename(file.path, destinationPath);
|
|
34
|
-
res.status(201).send();
|
|
35
|
-
});
|
|
36
|
-
const server = https_1.default.createServer({
|
|
37
|
-
key: fs_1.default.readFileSync((0, assertions_1.assertString)(process.env.SSL_KEY_FILE, new Error('ssl key is required for localFileServer')), 'utf8'),
|
|
38
|
-
cert: fs_1.default.readFileSync((0, assertions_1.assertString)(process.env.SSL_CRT_FILE, new Error('ssl key is required for localFileServer')), 'utf8'),
|
|
39
|
-
}, fileServerApp);
|
|
40
|
-
server.once('error', function (err) {
|
|
41
|
-
if (err.code === 'EADDRINUSE') {
|
|
42
|
-
// when the local dev server reloads files on every request it doesn't
|
|
43
|
-
// actually tear down the old modules, so this server only starts on the
|
|
44
|
-
// first execution and changes in its code will not be reloaded
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
throw err;
|
|
48
|
-
});
|
|
49
|
-
server.listen(port);
|
|
50
|
-
return true;
|
|
51
|
-
});
|
|
52
11
|
const localFileServer = (initializer) => (configProvider) => {
|
|
53
12
|
const config = configProvider[(0, guards_1.ifDefined)(initializer.configSpace, 'local')];
|
|
54
|
-
const port = (0, config_1.resolveConfigValue)(config.port || '');
|
|
55
|
-
const host = (0, config_1.resolveConfigValue)(config.host || '');
|
|
56
13
|
const storagePrefix = (0, config_1.resolveConfigValue)(config.storagePrefix);
|
|
57
14
|
const fileDir = storagePrefix.then((prefix) => path_1.default.join(initializer.dataDir, prefix));
|
|
58
|
-
Promise.all([port, fileDir])
|
|
59
|
-
.then(([port, fileDir]) => port && startServer(port, fileDir));
|
|
60
|
-
const getSignedViewerUrl = async (source) => {
|
|
61
|
-
return `https://${await host}:${await port}/${source.path}`;
|
|
62
|
-
};
|
|
63
15
|
const getFileContent = async (source) => {
|
|
64
16
|
const filePath = path_1.default.join(await fileDir, source.path);
|
|
65
17
|
return fs_1.default.promises.readFile(filePath);
|
|
66
18
|
};
|
|
67
|
-
const putFileContent = async (source, content) => {
|
|
68
|
-
const filePath = path_1.default.join(await fileDir, source.path);
|
|
69
|
-
const directory = path_1.default.dirname(filePath);
|
|
70
|
-
await fs_1.default.promises.mkdir(directory, { recursive: true });
|
|
71
|
-
await fs_1.default.promises.writeFile(filePath, content);
|
|
72
|
-
return source;
|
|
73
|
-
};
|
|
74
19
|
return {
|
|
75
|
-
getSignedViewerUrl,
|
|
76
20
|
getFileContent,
|
|
77
|
-
putFileContent,
|
|
78
21
|
};
|
|
79
22
|
};
|
|
80
23
|
exports.localFileServer = localFileServer;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.s3FileServer = void 0;
|
|
4
4
|
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
5
|
-
const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
|
|
6
5
|
const __1 = require("../..");
|
|
7
6
|
const assertions_1 = require("../../assertions");
|
|
8
7
|
const config_1 = require("../../config");
|
|
@@ -13,37 +12,14 @@ const s3FileServer = (initializer) => (configProvider) => {
|
|
|
13
12
|
const bucketRegion = (0, __1.once)(() => (0, config_1.resolveConfigValue)(config.bucketRegion));
|
|
14
13
|
const client = (0, guards_1.ifDefined)(initializer.s3Client, client_s3_1.S3Client);
|
|
15
14
|
const s3Service = (0, __1.once)(async () => new client({ apiVersion: '2012-08-10', region: await bucketRegion() }));
|
|
16
|
-
/*
|
|
17
|
-
* https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html
|
|
18
|
-
*/
|
|
19
|
-
const getSignedViewerUrl = async (source) => {
|
|
20
|
-
const bucket = (await bucketName());
|
|
21
|
-
const command = new client_s3_1.GetObjectCommand({ Bucket: bucket, Key: source.path });
|
|
22
|
-
return (0, s3_request_presigner_1.getSignedUrl)(await s3Service(), command, {
|
|
23
|
-
expiresIn: 3600, // 1 hour
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
15
|
const getFileContent = async (source) => {
|
|
27
16
|
const bucket = await bucketName();
|
|
28
17
|
const command = new client_s3_1.GetObjectCommand({ Bucket: bucket, Key: source.path });
|
|
29
18
|
const response = await (await s3Service()).send(command);
|
|
30
19
|
return Buffer.from(await (0, assertions_1.assertDefined)(response.Body, new Error('Invalid Response from s3')).transformToByteArray());
|
|
31
20
|
};
|
|
32
|
-
const putFileContent = async (source, content) => {
|
|
33
|
-
const bucket = await bucketName();
|
|
34
|
-
const command = new client_s3_1.PutObjectCommand({
|
|
35
|
-
Bucket: bucket,
|
|
36
|
-
Key: source.path,
|
|
37
|
-
Body: content,
|
|
38
|
-
ContentType: source.mimeType,
|
|
39
|
-
});
|
|
40
|
-
await (await s3Service()).send(command);
|
|
41
|
-
return source;
|
|
42
|
-
};
|
|
43
21
|
return {
|
|
44
22
|
getFileContent,
|
|
45
|
-
putFileContent,
|
|
46
|
-
getSignedViewerUrl,
|
|
47
23
|
};
|
|
48
24
|
};
|
|
49
25
|
exports.s3FileServer = s3FileServer;
|
|
@@ -108,7 +108,7 @@ ${await response.text()}`);
|
|
|
108
108
|
const response = await fetchXapiStatements(fetchParams).catch(abort);
|
|
109
109
|
const consistentThrough = response.headers.get('X-Experience-API-Consistent-Through');
|
|
110
110
|
if (!consistentThrough || new Date(consistentThrough) < date) {
|
|
111
|
-
throw new Error(`xAPI consistent through ${consistentThrough}; not in sync with current date ${date}.`);
|
|
111
|
+
throw new Error(`xAPI consistent through ${consistentThrough}; not in sync with current date ${date.toISOString()}.`);
|
|
112
112
|
}
|
|
113
113
|
return formatGetXapiStatementsResponse(response);
|
|
114
114
|
}, { retries: 4, logger });
|
|
@@ -18,9 +18,7 @@ const postgresConnection = (initializer) => (configProvider) => {
|
|
|
18
18
|
database: await (0, config_1.resolveConfigValue)(config.database),
|
|
19
19
|
username: await (0, config_1.resolveConfigValue)(config.username),
|
|
20
20
|
password: await (0, config_1.resolveConfigValue)(config.password),
|
|
21
|
-
transform:
|
|
22
|
-
column: { to: postgres_1.default.fromCamel, from: postgres_1.default.toCamel },
|
|
23
|
-
},
|
|
21
|
+
transform: postgres_1.default.camel,
|
|
24
22
|
}));
|
|
25
23
|
const connections = [];
|
|
26
24
|
const sql = (0, helpers_1.once)(async () => {
|