@balena/pinejs 19.7.2 → 20.0.0-build-esm-724decc895c0df04c6238f249763a742cc5efa39-1
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/.pinejs-cache.json +1 -1
- package/.versionbot/CHANGELOG.yml +45 -1
- package/CHANGELOG.md +8 -0
- package/{Gruntfile.ts → Gruntfile.cts} +9 -22
- package/VERSION +1 -1
- package/bin/abstract-sql-compiler.js +1 -1
- package/bin/odata-compiler.js +1 -1
- package/bin/sbvr-compiler.js +1 -1
- package/build/{browser.ts → browser.cts} +1 -1
- package/build/{config.ts → config.cts} +5 -1
- package/build/{module.ts → module.cts} +1 -1
- package/build/{server.ts → server.cts} +1 -1
- package/out/bin/abstract-sql-compiler.js +17 -19
- package/out/bin/abstract-sql-compiler.js.map +1 -1
- package/out/bin/odata-compiler.js +19 -21
- package/out/bin/odata-compiler.js.map +1 -1
- package/out/bin/sbvr-compiler.js +19 -54
- package/out/bin/sbvr-compiler.js.map +1 -1
- package/out/bin/utils.d.ts +3 -3
- package/out/bin/utils.js +21 -53
- package/out/bin/utils.js.map +1 -1
- package/out/config-loader/config-loader.d.ts +7 -7
- package/out/config-loader/config-loader.js +23 -63
- package/out/config-loader/config-loader.js.map +1 -1
- package/out/config-loader/env.d.ts +1 -1
- package/out/config-loader/env.js +24 -66
- package/out/config-loader/env.js.map +1 -1
- package/out/data-server/sbvr-server.d.ts +3 -3
- package/out/data-server/sbvr-server.js +5 -42
- package/out/data-server/sbvr-server.js.map +1 -1
- package/out/database-layer/db.d.ts +3 -3
- package/out/database-layer/db.js +37 -83
- package/out/database-layer/db.js.map +1 -1
- package/out/express-emulator/express.js.map +1 -1
- package/out/extended-sbvr-parser/extended-sbvr-parser.js +8 -11
- package/out/extended-sbvr-parser/extended-sbvr-parser.js.map +1 -1
- package/out/http-transactions/transactions.d.ts +2 -2
- package/out/http-transactions/transactions.js +4 -4
- package/out/http-transactions/transactions.js.map +1 -1
- package/out/migrator/async.d.ts +2 -2
- package/out/migrator/async.js +20 -60
- package/out/migrator/async.js.map +1 -1
- package/out/migrator/migrations.js +1 -2
- package/out/migrator/sync.d.ts +6 -6
- package/out/migrator/sync.js +20 -61
- package/out/migrator/sync.js.map +1 -1
- package/out/migrator/utils.d.ts +4 -4
- package/out/migrator/utils.js +42 -97
- package/out/migrator/utils.js.map +1 -1
- package/out/odata-metadata/odata-metadata-generator.js +7 -14
- package/out/odata-metadata/odata-metadata-generator.js.map +1 -1
- package/out/passport-pinejs/mount-login-router.d.ts +1 -1
- package/out/passport-pinejs/mount-login-router.js +4 -41
- package/out/passport-pinejs/mount-login-router.js.map +1 -1
- package/out/passport-pinejs/passport-pinejs.d.ts +3 -3
- package/out/passport-pinejs/passport-pinejs.js +11 -46
- package/out/passport-pinejs/passport-pinejs.js.map +1 -1
- package/out/pinejs-session-store/pinejs-session-store.d.ts +1 -1
- package/out/pinejs-session-store/pinejs-session-store.js +11 -48
- package/out/pinejs-session-store/pinejs-session-store.js.map +1 -1
- package/out/sbvr-api/abstract-sql.d.ts +3 -3
- package/out/sbvr-api/abstract-sql.js +22 -65
- package/out/sbvr-api/abstract-sql.js.map +1 -1
- package/out/sbvr-api/cached-compile.js +8 -15
- package/out/sbvr-api/cached-compile.js.map +1 -1
- package/out/sbvr-api/common-types.js +1 -2
- package/out/sbvr-api/control-flow.d.ts +1 -1
- package/out/sbvr-api/control-flow.js +12 -25
- package/out/sbvr-api/control-flow.js.map +1 -1
- package/out/sbvr-api/dev.js +1 -2
- package/out/sbvr-api/errors.d.ts +1 -1
- package/out/sbvr-api/errors.js +47 -95
- package/out/sbvr-api/errors.js.map +1 -1
- package/out/sbvr-api/express-extension.d.ts +2 -2
- package/out/sbvr-api/express-extension.js +1 -2
- package/out/sbvr-api/hooks.d.ts +4 -4
- package/out/sbvr-api/hooks.js +23 -35
- package/out/sbvr-api/hooks.js.map +1 -1
- package/out/sbvr-api/odata-response.d.ts +2 -2
- package/out/sbvr-api/odata-response.js +19 -29
- package/out/sbvr-api/odata-response.js.map +1 -1
- package/out/sbvr-api/permissions.d.ts +9 -9
- package/out/sbvr-api/permissions.js +106 -159
- package/out/sbvr-api/permissions.js.map +1 -1
- package/out/sbvr-api/sbvr-utils.d.ts +40 -18
- package/out/sbvr-api/sbvr-utils.js +222 -285
- package/out/sbvr-api/sbvr-utils.js.map +1 -1
- package/out/sbvr-api/translations.d.ts +1 -1
- package/out/sbvr-api/translations.js +10 -17
- package/out/sbvr-api/translations.js.map +1 -1
- package/out/sbvr-api/uri-parser.d.ts +7 -7
- package/out/sbvr-api/uri-parser.js +39 -84
- package/out/sbvr-api/uri-parser.js.map +1 -1
- package/out/sbvr-api/user.js +1 -2
- package/out/server-glue/global-ext.d.ts +0 -3
- package/out/server-glue/module.d.ts +16 -16
- package/out/server-glue/module.js +20 -59
- package/out/server-glue/module.js.map +1 -1
- package/out/server-glue/sbvr-loader.d.ts +2 -1
- package/out/server-glue/sbvr-loader.js +4 -11
- package/out/server-glue/sbvr-loader.js.map +1 -1
- package/out/server-glue/server.d.ts +2 -2
- package/out/server-glue/server.js +17 -59
- package/out/server-glue/server.js.map +1 -1
- package/out/tasks/common.d.ts +1 -1
- package/out/tasks/common.js +3 -9
- package/out/tasks/common.js.map +1 -1
- package/out/tasks/index.d.ts +8 -8
- package/out/tasks/index.js +25 -63
- package/out/tasks/index.js.map +1 -1
- package/out/tasks/tasks.js +1 -2
- package/out/tasks/worker.d.ts +3 -3
- package/out/tasks/worker.js +14 -51
- package/out/tasks/worker.js.map +1 -1
- package/out/webresource-handler/handlers/NoopHandler.d.ts +1 -1
- package/out/webresource-handler/handlers/NoopHandler.js +1 -5
- package/out/webresource-handler/handlers/NoopHandler.js.map +1 -1
- package/out/webresource-handler/handlers/index.d.ts +1 -2
- package/out/webresource-handler/handlers/index.js +1 -18
- package/out/webresource-handler/handlers/index.js.map +1 -1
- package/out/webresource-handler/index.d.ts +3 -3
- package/out/webresource-handler/index.js +37 -87
- package/out/webresource-handler/index.js.map +1 -1
- package/package.json +15 -14
- package/src/bin/abstract-sql-compiler.ts +3 -3
- package/src/bin/odata-compiler.ts +3 -3
- package/src/bin/sbvr-compiler.ts +2 -2
- package/src/bin/utils.ts +23 -15
- package/src/config-loader/config-loader.ts +12 -12
- package/src/config-loader/env.ts +3 -3
- package/src/data-server/sbvr-server.ts +4 -4
- package/src/database-layer/db.ts +18 -11
- package/src/extended-sbvr-parser/extended-sbvr-parser.ts +5 -5
- package/src/http-transactions/transactions.js +4 -4
- package/src/migrator/async.ts +5 -5
- package/src/migrator/sync.ts +8 -8
- package/src/migrator/utils.ts +7 -7
- package/src/odata-metadata/odata-metadata-generator.ts +3 -2
- package/src/passport-pinejs/mount-login-router.ts +3 -3
- package/src/passport-pinejs/passport-pinejs.ts +6 -6
- package/src/pinejs-session-store/pinejs-session-store.ts +4 -4
- package/src/sbvr-api/abstract-sql.ts +6 -6
- package/src/sbvr-api/cached-compile.ts +2 -2
- package/src/sbvr-api/control-flow.ts +1 -1
- package/src/sbvr-api/errors.ts +1 -1
- package/src/sbvr-api/express-extension.ts +2 -2
- package/src/sbvr-api/hooks.ts +5 -5
- package/src/sbvr-api/odata-response.ts +8 -4
- package/src/sbvr-api/permissions.ts +19 -19
- package/src/sbvr-api/sbvr-utils.ts +39 -33
- package/src/sbvr-api/translations.ts +1 -1
- package/src/sbvr-api/uri-parser.ts +10 -10
- package/src/server-glue/global-ext.d.ts +0 -3
- package/src/server-glue/module.ts +20 -20
- package/src/server-glue/sbvr-loader.ts +15 -27
- package/src/server-glue/server.ts +13 -24
- package/src/tasks/common.ts +1 -1
- package/src/tasks/index.ts +14 -14
- package/src/tasks/worker.ts +8 -8
- package/src/webresource-handler/handlers/NoopHandler.ts +5 -1
- package/src/webresource-handler/handlers/index.ts +1 -2
- package/src/webresource-handler/index.ts +13 -13
- package/tsconfig.dev.json +4 -2
- package/tsconfig.json +1 -1
- package/typings/lf-to-abstract-sql.d.ts +2 -2
- package/typings/memoizee.d.ts +2 -2
- package/out/webresource-handler/handlers/S3Handler.d.ts +0 -28
- package/out/webresource-handler/handlers/S3Handler.js +0 -104
- package/out/webresource-handler/handlers/S3Handler.js.map +0 -1
- package/src/webresource-handler/handlers/S3Handler.ts +0 -143
@@ -1,28 +0,0 @@
|
|
1
|
-
import { type IncomingFile, type UploadResponse, type WebResourceHandler } from '..';
|
2
|
-
import type { WebResourceType as WebResource } from '@balena/sbvr-types';
|
3
|
-
export interface S3HandlerProps {
|
4
|
-
region: string;
|
5
|
-
accessKey: string;
|
6
|
-
secretKey: string;
|
7
|
-
endpoint: string;
|
8
|
-
bucket: string;
|
9
|
-
maxSize?: number;
|
10
|
-
signedUrlExpireTimeSeconds?: number;
|
11
|
-
signedUrlCacheExpireTimeSeconds?: number;
|
12
|
-
}
|
13
|
-
export declare class S3Handler implements WebResourceHandler {
|
14
|
-
private readonly config;
|
15
|
-
private readonly bucket;
|
16
|
-
private readonly maxFileSize;
|
17
|
-
protected readonly signedUrlExpireTimeSeconds: number;
|
18
|
-
protected readonly signedUrlCacheExpireTimeSeconds: number;
|
19
|
-
protected cachedGetSignedUrl: (fileKey: string) => Promise<string>;
|
20
|
-
private client;
|
21
|
-
constructor(config: S3HandlerProps);
|
22
|
-
handleFile(resource: IncomingFile): Promise<UploadResponse>;
|
23
|
-
removeFile(href: string): Promise<void>;
|
24
|
-
onPreRespond(webResource: WebResource): Promise<WebResource>;
|
25
|
-
private s3SignUrl;
|
26
|
-
private getS3URL;
|
27
|
-
private getKeyFromHref;
|
28
|
-
}
|
@@ -1,104 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
-
};
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.S3Handler = void 0;
|
7
|
-
const __1 = require("..");
|
8
|
-
const client_s3_1 = require("@aws-sdk/client-s3");
|
9
|
-
const lib_storage_1 = require("@aws-sdk/lib-storage");
|
10
|
-
const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
|
11
|
-
const crypto_1 = require("crypto");
|
12
|
-
const memoizee_1 = __importDefault(require("memoizee"));
|
13
|
-
class S3Handler {
|
14
|
-
config;
|
15
|
-
bucket;
|
16
|
-
maxFileSize;
|
17
|
-
signedUrlExpireTimeSeconds;
|
18
|
-
signedUrlCacheExpireTimeSeconds;
|
19
|
-
cachedGetSignedUrl;
|
20
|
-
client;
|
21
|
-
constructor(config) {
|
22
|
-
this.config = {
|
23
|
-
region: config.region,
|
24
|
-
credentials: {
|
25
|
-
accessKeyId: config.accessKey,
|
26
|
-
secretAccessKey: config.secretKey,
|
27
|
-
},
|
28
|
-
endpoint: config.endpoint,
|
29
|
-
forcePathStyle: true,
|
30
|
-
};
|
31
|
-
this.signedUrlExpireTimeSeconds =
|
32
|
-
config.signedUrlExpireTimeSeconds ?? 86400;
|
33
|
-
this.signedUrlCacheExpireTimeSeconds =
|
34
|
-
config.signedUrlCacheExpireTimeSeconds ?? 82800;
|
35
|
-
this.maxFileSize = config.maxSize ?? 52428800;
|
36
|
-
this.bucket = config.bucket;
|
37
|
-
this.client = new client_s3_1.S3Client(this.config);
|
38
|
-
this.cachedGetSignedUrl = (0, memoizee_1.default)(this.s3SignUrl, {
|
39
|
-
maxAge: this.signedUrlCacheExpireTimeSeconds * 1000,
|
40
|
-
});
|
41
|
-
}
|
42
|
-
async handleFile(resource) {
|
43
|
-
let size = 0;
|
44
|
-
const key = `${resource.fieldname}_${(0, crypto_1.randomUUID)()}_${resource.originalname}`;
|
45
|
-
const params = {
|
46
|
-
Bucket: this.bucket,
|
47
|
-
Key: key,
|
48
|
-
Body: resource.stream,
|
49
|
-
ContentType: resource.mimetype,
|
50
|
-
};
|
51
|
-
const upload = new lib_storage_1.Upload({ client: this.client, params });
|
52
|
-
upload.on('httpUploadProgress', async (ev) => {
|
53
|
-
size = ev.total ?? ev.loaded;
|
54
|
-
if (size > this.maxFileSize) {
|
55
|
-
await upload.abort();
|
56
|
-
}
|
57
|
-
});
|
58
|
-
try {
|
59
|
-
await upload.done();
|
60
|
-
}
|
61
|
-
catch (err) {
|
62
|
-
resource.stream.resume();
|
63
|
-
if (size > this.maxFileSize) {
|
64
|
-
throw new __1.FileSizeExceededError(this.maxFileSize);
|
65
|
-
}
|
66
|
-
throw new __1.WebResourceError(err);
|
67
|
-
}
|
68
|
-
const filename = this.getS3URL(key);
|
69
|
-
return { size, filename };
|
70
|
-
}
|
71
|
-
async removeFile(href) {
|
72
|
-
const fileKey = this.getKeyFromHref(href);
|
73
|
-
const command = new client_s3_1.DeleteObjectCommand({
|
74
|
-
Bucket: this.bucket,
|
75
|
-
Key: fileKey,
|
76
|
-
});
|
77
|
-
await this.client.send(command);
|
78
|
-
}
|
79
|
-
async onPreRespond(webResource) {
|
80
|
-
if (webResource.href != null) {
|
81
|
-
const fileKey = this.getKeyFromHref(webResource.href);
|
82
|
-
webResource.href = await this.cachedGetSignedUrl(fileKey);
|
83
|
-
}
|
84
|
-
return webResource;
|
85
|
-
}
|
86
|
-
s3SignUrl(fileKey) {
|
87
|
-
const command = new client_s3_1.GetObjectCommand({
|
88
|
-
Bucket: this.bucket,
|
89
|
-
Key: fileKey,
|
90
|
-
});
|
91
|
-
return (0, s3_request_presigner_1.getSignedUrl)(this.client, command, {
|
92
|
-
expiresIn: this.signedUrlExpireTimeSeconds,
|
93
|
-
});
|
94
|
-
}
|
95
|
-
getS3URL(key) {
|
96
|
-
return `${this.config.endpoint}/${this.bucket}/${key}`;
|
97
|
-
}
|
98
|
-
getKeyFromHref(href) {
|
99
|
-
const hrefWithoutParams = (0, __1.normalizeHref)(href);
|
100
|
-
return hrefWithoutParams.substring(hrefWithoutParams.lastIndexOf('/') + 1);
|
101
|
-
}
|
102
|
-
}
|
103
|
-
exports.S3Handler = S3Handler;
|
104
|
-
//# sourceMappingURL=S3Handler.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"S3Handler.js","sourceRoot":"","sources":["../../../src/webresource-handler/handlers/S3Handler.ts"],"names":[],"mappings":"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"}
|
@@ -1,143 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
FileSizeExceededError,
|
3
|
-
type IncomingFile,
|
4
|
-
normalizeHref,
|
5
|
-
type UploadResponse,
|
6
|
-
WebResourceError,
|
7
|
-
type WebResourceHandler,
|
8
|
-
} from '..';
|
9
|
-
import {
|
10
|
-
S3Client,
|
11
|
-
type S3ClientConfig,
|
12
|
-
DeleteObjectCommand,
|
13
|
-
type PutObjectCommandInput,
|
14
|
-
GetObjectCommand,
|
15
|
-
} from '@aws-sdk/client-s3';
|
16
|
-
import { Upload } from '@aws-sdk/lib-storage';
|
17
|
-
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
18
|
-
|
19
|
-
import { randomUUID } from 'crypto';
|
20
|
-
import type { WebResourceType as WebResource } from '@balena/sbvr-types';
|
21
|
-
import memoize from 'memoizee';
|
22
|
-
|
23
|
-
export interface S3HandlerProps {
|
24
|
-
region: string;
|
25
|
-
accessKey: string;
|
26
|
-
secretKey: string;
|
27
|
-
endpoint: string;
|
28
|
-
bucket: string;
|
29
|
-
maxSize?: number;
|
30
|
-
signedUrlExpireTimeSeconds?: number;
|
31
|
-
signedUrlCacheExpireTimeSeconds?: number;
|
32
|
-
}
|
33
|
-
|
34
|
-
export class S3Handler implements WebResourceHandler {
|
35
|
-
private readonly config: S3ClientConfig;
|
36
|
-
private readonly bucket: string;
|
37
|
-
private readonly maxFileSize: number;
|
38
|
-
|
39
|
-
protected readonly signedUrlExpireTimeSeconds: number;
|
40
|
-
protected readonly signedUrlCacheExpireTimeSeconds: number;
|
41
|
-
protected cachedGetSignedUrl: (fileKey: string) => Promise<string>;
|
42
|
-
|
43
|
-
private client: S3Client;
|
44
|
-
|
45
|
-
constructor(config: S3HandlerProps) {
|
46
|
-
this.config = {
|
47
|
-
region: config.region,
|
48
|
-
credentials: {
|
49
|
-
accessKeyId: config.accessKey,
|
50
|
-
secretAccessKey: config.secretKey,
|
51
|
-
},
|
52
|
-
endpoint: config.endpoint,
|
53
|
-
forcePathStyle: true,
|
54
|
-
};
|
55
|
-
|
56
|
-
this.signedUrlExpireTimeSeconds =
|
57
|
-
config.signedUrlExpireTimeSeconds ?? 86400; // 24h
|
58
|
-
this.signedUrlCacheExpireTimeSeconds =
|
59
|
-
config.signedUrlCacheExpireTimeSeconds ?? 82800; // 22h
|
60
|
-
|
61
|
-
this.maxFileSize = config.maxSize ?? 52428800;
|
62
|
-
this.bucket = config.bucket;
|
63
|
-
this.client = new S3Client(this.config);
|
64
|
-
|
65
|
-
// Memoize expects maxAge in MS and s3 signing method in seconds.
|
66
|
-
// Normalization to use only seconds and therefore convert here from seconds to MS
|
67
|
-
this.cachedGetSignedUrl = memoize(this.s3SignUrl, {
|
68
|
-
maxAge: this.signedUrlCacheExpireTimeSeconds * 1000,
|
69
|
-
});
|
70
|
-
}
|
71
|
-
|
72
|
-
public async handleFile(resource: IncomingFile): Promise<UploadResponse> {
|
73
|
-
let size = 0;
|
74
|
-
const key = `${resource.fieldname}_${randomUUID()}_${
|
75
|
-
resource.originalname
|
76
|
-
}`;
|
77
|
-
const params: PutObjectCommandInput = {
|
78
|
-
Bucket: this.bucket,
|
79
|
-
Key: key,
|
80
|
-
Body: resource.stream,
|
81
|
-
ContentType: resource.mimetype,
|
82
|
-
};
|
83
|
-
const upload = new Upload({ client: this.client, params });
|
84
|
-
|
85
|
-
upload.on('httpUploadProgress', async (ev) => {
|
86
|
-
size = ev.total ?? ev.loaded!;
|
87
|
-
if (size > this.maxFileSize) {
|
88
|
-
await upload.abort();
|
89
|
-
}
|
90
|
-
});
|
91
|
-
|
92
|
-
try {
|
93
|
-
await upload.done();
|
94
|
-
} catch (err: any) {
|
95
|
-
resource.stream.resume();
|
96
|
-
if (size > this.maxFileSize) {
|
97
|
-
throw new FileSizeExceededError(this.maxFileSize);
|
98
|
-
}
|
99
|
-
throw new WebResourceError(err);
|
100
|
-
}
|
101
|
-
|
102
|
-
const filename = this.getS3URL(key);
|
103
|
-
return { size, filename };
|
104
|
-
}
|
105
|
-
|
106
|
-
public async removeFile(href: string): Promise<void> {
|
107
|
-
const fileKey = this.getKeyFromHref(href);
|
108
|
-
|
109
|
-
const command = new DeleteObjectCommand({
|
110
|
-
Bucket: this.bucket,
|
111
|
-
Key: fileKey,
|
112
|
-
});
|
113
|
-
|
114
|
-
await this.client.send(command);
|
115
|
-
}
|
116
|
-
|
117
|
-
public async onPreRespond(webResource: WebResource): Promise<WebResource> {
|
118
|
-
if (webResource.href != null) {
|
119
|
-
const fileKey = this.getKeyFromHref(webResource.href);
|
120
|
-
webResource.href = await this.cachedGetSignedUrl(fileKey);
|
121
|
-
}
|
122
|
-
return webResource;
|
123
|
-
}
|
124
|
-
|
125
|
-
private s3SignUrl(fileKey: string): Promise<string> {
|
126
|
-
const command = new GetObjectCommand({
|
127
|
-
Bucket: this.bucket,
|
128
|
-
Key: fileKey,
|
129
|
-
});
|
130
|
-
return getSignedUrl(this.client, command, {
|
131
|
-
expiresIn: this.signedUrlExpireTimeSeconds,
|
132
|
-
});
|
133
|
-
}
|
134
|
-
|
135
|
-
private getS3URL(key: string): string {
|
136
|
-
return `${this.config.endpoint}/${this.bucket}/${key}`;
|
137
|
-
}
|
138
|
-
|
139
|
-
private getKeyFromHref(href: string): string {
|
140
|
-
const hrefWithoutParams = normalizeHref(href);
|
141
|
-
return hrefWithoutParams.substring(hrefWithoutParams.lastIndexOf('/') + 1);
|
142
|
-
}
|
143
|
-
}
|