@genoacms/adapter-gcp 0.4.2 → 0.5.2-fix.10
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/deployment/snippets/index.js +8 -0
- package/dist/services/deployment/deploy.d.ts +2 -0
- package/dist/services/deployment/deploy.js +111 -0
- package/dist/services/deployment/index.d.ts +4 -0
- package/dist/services/deployment/index.js +6 -0
- package/dist/services/storage/index.js +7 -18
- package/dist/services/storage/storage.d.ts +3 -0
- package/dist/services/storage/storage.js +12 -0
- package/package.json +14 -3
- package/src/services/deployment/deploy.ts +120 -0
- package/src/services/deployment/index.ts +13 -0
- package/src/services/storage/index.ts +8 -19
- package/src/services/storage/storage.ts +16 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import config from '../../config.js';
|
|
2
|
+
import { createReadStream, createWriteStream } from 'node:fs';
|
|
3
|
+
import { resolve, dirname, basename } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { v2 } from '@google-cloud/functions';
|
|
6
|
+
import archiver from 'archiver';
|
|
7
|
+
const { FunctionServiceClient } = v2;
|
|
8
|
+
const functionsClient = new FunctionServiceClient({
|
|
9
|
+
credentials: config.deployment.credentials
|
|
10
|
+
});
|
|
11
|
+
const projectId = config.deployment.projectId;
|
|
12
|
+
const region = config.deployment.region;
|
|
13
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
async function createZip(source, injectPaths, ignorePaths, out) {
|
|
15
|
+
await new Promise((resolve, reject) => {
|
|
16
|
+
const output = createWriteStream(out);
|
|
17
|
+
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
18
|
+
output.on('close', () => {
|
|
19
|
+
resolve();
|
|
20
|
+
});
|
|
21
|
+
archive.on('error', (err) => {
|
|
22
|
+
reject(err);
|
|
23
|
+
});
|
|
24
|
+
archive.pipe(output);
|
|
25
|
+
archive.glob(source, { ignore: ignorePaths });
|
|
26
|
+
for (const path of injectPaths) {
|
|
27
|
+
archive.file(path, { name: basename(path) });
|
|
28
|
+
}
|
|
29
|
+
archive.finalize();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async function uploadSource(sourceArchivePath) {
|
|
33
|
+
const location = functionsClient.locationPath(projectId, region);
|
|
34
|
+
const [urlResponse] = await functionsClient.generateUploadUrl({ parent: location });
|
|
35
|
+
const uploadUrl = urlResponse.uploadUrl;
|
|
36
|
+
const storageSource = urlResponse.storageSource;
|
|
37
|
+
if (!uploadUrl || !storageSource)
|
|
38
|
+
throw new Error('Upload URL not found');
|
|
39
|
+
const sourceArchiveStream = createReadStream(sourceArchivePath);
|
|
40
|
+
await fetch(uploadUrl, {
|
|
41
|
+
method: 'PUT',
|
|
42
|
+
// @ts-expect-error: invalid typings
|
|
43
|
+
body: sourceArchiveStream,
|
|
44
|
+
duplex: 'half',
|
|
45
|
+
headers: {
|
|
46
|
+
'Content-Type': 'application/zip'
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return storageSource;
|
|
50
|
+
}
|
|
51
|
+
async function deployFunction(functionName, storageSource) {
|
|
52
|
+
const location = functionsClient.locationPath(projectId, region);
|
|
53
|
+
const name = functionsClient.functionPath(projectId, region, functionName);
|
|
54
|
+
let isFunctionExisting;
|
|
55
|
+
try {
|
|
56
|
+
await functionsClient.getFunction({ name });
|
|
57
|
+
isFunctionExisting = true;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
isFunctionExisting = false;
|
|
61
|
+
}
|
|
62
|
+
const operationParams = {
|
|
63
|
+
functionId: functionName,
|
|
64
|
+
parent: location,
|
|
65
|
+
function: {
|
|
66
|
+
name,
|
|
67
|
+
buildConfig: {
|
|
68
|
+
entryPoint: 'genoacms',
|
|
69
|
+
runtime: 'nodejs20',
|
|
70
|
+
source: {
|
|
71
|
+
storageSource
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
serviceConfig: {
|
|
75
|
+
minInstanceCount: 0,
|
|
76
|
+
maxInstanceCount: 1,
|
|
77
|
+
ingressSettings: 1,
|
|
78
|
+
environmentVariables: {
|
|
79
|
+
NODE_ENV: 'production'
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
let response;
|
|
85
|
+
if (isFunctionExisting) {
|
|
86
|
+
[response] = await functionsClient.updateFunction(operationParams);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
[response] = await functionsClient.createFunction(operationParams);
|
|
90
|
+
}
|
|
91
|
+
console.log(response);
|
|
92
|
+
}
|
|
93
|
+
async function deploy() {
|
|
94
|
+
const buildDirectoryPath = '**';
|
|
95
|
+
const buildArchivePath = resolve(currentDir, '../../../deployment/build.zip');
|
|
96
|
+
const functionEntryScriptPath = resolve(currentDir, '../../../deployment/snippets/index.js');
|
|
97
|
+
const ignoreArchivePaths = [
|
|
98
|
+
'node_modules/**',
|
|
99
|
+
'.git/**',
|
|
100
|
+
'.github/**',
|
|
101
|
+
'.gitignore',
|
|
102
|
+
'build/**'
|
|
103
|
+
];
|
|
104
|
+
const injectArchivePaths = [
|
|
105
|
+
functionEntryScriptPath
|
|
106
|
+
];
|
|
107
|
+
await createZip(buildDirectoryPath, injectArchivePaths, ignoreArchivePaths, buildArchivePath);
|
|
108
|
+
const functionStorageSource = await uploadSource(buildArchivePath);
|
|
109
|
+
await deployFunction('genoacms', functionStorageSource);
|
|
110
|
+
}
|
|
111
|
+
export default deploy;
|
|
@@ -1,14 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
const storage = new Storage({
|
|
4
|
-
credentials: config.storage.credentials
|
|
5
|
-
});
|
|
6
|
-
const getBucket = (name) => {
|
|
7
|
-
if (!config.storage.buckets.includes(name))
|
|
8
|
-
throw new Error('bucket-unregistered');
|
|
9
|
-
const bucket = storage.bucket(name);
|
|
10
|
-
return bucket;
|
|
11
|
-
};
|
|
1
|
+
import { getBucket } from './storage.js';
|
|
2
|
+
import { join } from 'path';
|
|
12
3
|
const getObject = async ({ bucket, name }) => {
|
|
13
4
|
const bucketInstance = getBucket(bucket);
|
|
14
5
|
const file = bucketInstance.file(name);
|
|
@@ -21,21 +12,19 @@ const getPublicURL = async ({ bucket, name }) => {
|
|
|
21
12
|
const file = bucketInstance.file(name);
|
|
22
13
|
return file.publicUrl();
|
|
23
14
|
};
|
|
24
|
-
const getSignedURL = async ({ bucket, name }) => {
|
|
15
|
+
const getSignedURL = async ({ bucket, name }, expires) => {
|
|
25
16
|
const bucketInstance = getBucket(bucket);
|
|
26
17
|
const file = bucketInstance.file(name);
|
|
27
|
-
const expires = new Date();
|
|
28
|
-
expires.setTime(expires.getTime() + 60 * 60 * 1_000);
|
|
29
18
|
const [url] = await file.getSignedUrl({
|
|
30
19
|
action: 'read',
|
|
31
20
|
expires
|
|
32
21
|
});
|
|
33
22
|
return url;
|
|
34
23
|
};
|
|
35
|
-
const uploadObject = async ({ bucket, name }, stream) => {
|
|
24
|
+
const uploadObject = async ({ bucket, name }, stream, options) => {
|
|
36
25
|
const bucketInstance = getBucket(bucket);
|
|
37
26
|
const file = bucketInstance.file(name);
|
|
38
|
-
await file.save(stream);
|
|
27
|
+
await file.save(stream, options);
|
|
39
28
|
};
|
|
40
29
|
const deleteObject = async ({ bucket, name }) => {
|
|
41
30
|
const bucketInstance = getBucket(bucket);
|
|
@@ -46,7 +35,7 @@ const listDirectory = async ({ bucket, name }, listingParams = {}) => {
|
|
|
46
35
|
const bucketInstance = getBucket(bucket);
|
|
47
36
|
const options = {
|
|
48
37
|
autoPaginate: false,
|
|
49
|
-
prefix: name,
|
|
38
|
+
prefix: join(name, '/'),
|
|
50
39
|
maxResults: listingParams?.limit,
|
|
51
40
|
startOffset: listingParams?.startAfter,
|
|
52
41
|
delimiter: '/'
|
|
@@ -62,7 +51,7 @@ const listDirectory = async ({ bucket, name }, listingParams = {}) => {
|
|
|
62
51
|
lastModified: new Date(file.metadata.updated)
|
|
63
52
|
};
|
|
64
53
|
}),
|
|
65
|
-
directories: apiResponse?.prefixes ?? []
|
|
54
|
+
directories: (apiResponse?.prefixes ?? []).filter((item) => item !== name)
|
|
66
55
|
};
|
|
67
56
|
};
|
|
68
57
|
const createDirectory = async ({ bucket, name }) => {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import config from '../../config.js';
|
|
2
|
+
import { Storage } from '@google-cloud/storage';
|
|
3
|
+
const storage = new Storage({
|
|
4
|
+
credentials: config.storage.credentials
|
|
5
|
+
});
|
|
6
|
+
const getBucket = (name) => {
|
|
7
|
+
if (!config.storage.buckets.includes(name))
|
|
8
|
+
throw new Error('bucket-unregistered');
|
|
9
|
+
const bucket = storage.bucket(name);
|
|
10
|
+
return bucket;
|
|
11
|
+
};
|
|
12
|
+
export { getBucket };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genoacms/adapter-gcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.2-fix.10",
|
|
4
4
|
"description": "Implementation of abstraction layer of GenoaCMS for GCP",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,12 +17,15 @@
|
|
|
17
17
|
"homepage": "https://github.com/GenoaCMS/adapter-gcp#readme",
|
|
18
18
|
"type": "module",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@genoacms/cloudabstraction": "0.
|
|
20
|
+
"@genoacms/cloudabstraction": "^0.5.2",
|
|
21
21
|
"@google-cloud/firestore": "^7.1.0",
|
|
22
|
+
"@google-cloud/functions": "^3.4.0",
|
|
22
23
|
"@google-cloud/resource-manager": "^5.1.0",
|
|
23
|
-
"@google-cloud/storage": "^7.7.0"
|
|
24
|
+
"@google-cloud/storage": "^7.7.0",
|
|
25
|
+
"archiver": "^7.0.0"
|
|
24
26
|
},
|
|
25
27
|
"devDependencies": {
|
|
28
|
+
"@types/archiver": "^6.0.2",
|
|
26
29
|
"@typescript-eslint/eslint-plugin": "^6.9.0",
|
|
27
30
|
"eslint": "^8.52.0",
|
|
28
31
|
"eslint-config-standard-with-typescript": "^39.1.1",
|
|
@@ -33,8 +36,12 @@
|
|
|
33
36
|
"typescript": "^5.2.2",
|
|
34
37
|
"vitest": "^1.0.4"
|
|
35
38
|
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@sveltejs/adapter-node": "^4.0.1"
|
|
41
|
+
},
|
|
36
42
|
"files": [
|
|
37
43
|
"src",
|
|
44
|
+
"deployment",
|
|
38
45
|
"dist"
|
|
39
46
|
],
|
|
40
47
|
"exports": {
|
|
@@ -46,6 +53,10 @@
|
|
|
46
53
|
"import": "./dist/services/database/index.js",
|
|
47
54
|
"types": "./dist/services/database/index.d.ts"
|
|
48
55
|
},
|
|
56
|
+
"./deployment": {
|
|
57
|
+
"import": "./dist/services/deployment/index.js",
|
|
58
|
+
"types": "./dist/services/deployment/index.d.ts"
|
|
59
|
+
},
|
|
49
60
|
"./storage": {
|
|
50
61
|
"import": "./dist/services/storage/index.js",
|
|
51
62
|
"types": "./dist/services/storage/index.d.ts"
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import config from '../../config.js'
|
|
2
|
+
import { createReadStream, createWriteStream } from 'node:fs'
|
|
3
|
+
import { resolve, dirname, basename } from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { v2 } from '@google-cloud/functions'
|
|
6
|
+
import archiver from 'archiver'
|
|
7
|
+
import type { google } from '@google-cloud/functions/build/protos/protos.js'
|
|
8
|
+
type IStorageSource = google.cloud.functions.v2.IStorageSource
|
|
9
|
+
|
|
10
|
+
const { FunctionServiceClient } = v2
|
|
11
|
+
const functionsClient = new FunctionServiceClient({
|
|
12
|
+
credentials: config.deployment.credentials
|
|
13
|
+
})
|
|
14
|
+
const projectId = config.deployment.projectId
|
|
15
|
+
const region = config.deployment.region
|
|
16
|
+
|
|
17
|
+
const currentDir = dirname(fileURLToPath(import.meta.url))
|
|
18
|
+
|
|
19
|
+
async function createZip (source: string, injectPaths: string[], ignorePaths: string[], out: string): Promise<void> {
|
|
20
|
+
await new Promise<void>((resolve, reject) => {
|
|
21
|
+
const output = createWriteStream(out)
|
|
22
|
+
const archive = archiver('zip', { zlib: { level: 9 } })
|
|
23
|
+
|
|
24
|
+
output.on('close', () => {
|
|
25
|
+
resolve()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
archive.on('error', (err) => {
|
|
29
|
+
reject(err)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
archive.pipe(output)
|
|
33
|
+
archive.glob(source, { ignore: ignorePaths })
|
|
34
|
+
for (const path of injectPaths) {
|
|
35
|
+
archive.file(path, { name: basename(path) })
|
|
36
|
+
}
|
|
37
|
+
archive.finalize()
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function uploadSource (sourceArchivePath: string): Promise<IStorageSource> {
|
|
42
|
+
const location = functionsClient.locationPath(projectId, region)
|
|
43
|
+
const [urlResponse] = await functionsClient.generateUploadUrl({ parent: location })
|
|
44
|
+
const uploadUrl = urlResponse.uploadUrl
|
|
45
|
+
const storageSource = urlResponse.storageSource
|
|
46
|
+
if (!uploadUrl || !storageSource) throw new Error('Upload URL not found')
|
|
47
|
+
const sourceArchiveStream = createReadStream(sourceArchivePath)
|
|
48
|
+
await fetch(uploadUrl, {
|
|
49
|
+
method: 'PUT',
|
|
50
|
+
// @ts-expect-error: invalid typings
|
|
51
|
+
body: sourceArchiveStream,
|
|
52
|
+
duplex: 'half',
|
|
53
|
+
headers: {
|
|
54
|
+
'Content-Type': 'application/zip'
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
return storageSource
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function deployFunction (functionName: string, storageSource: IStorageSource): Promise<void> {
|
|
61
|
+
const location = functionsClient.locationPath(projectId, region)
|
|
62
|
+
const name = functionsClient.functionPath(projectId, region, functionName)
|
|
63
|
+
let isFunctionExisting: boolean
|
|
64
|
+
try {
|
|
65
|
+
await functionsClient.getFunction({ name })
|
|
66
|
+
isFunctionExisting = true
|
|
67
|
+
} catch (error) {
|
|
68
|
+
isFunctionExisting = false
|
|
69
|
+
}
|
|
70
|
+
const operationParams = {
|
|
71
|
+
functionId: functionName,
|
|
72
|
+
parent: location,
|
|
73
|
+
function: {
|
|
74
|
+
name,
|
|
75
|
+
buildConfig: {
|
|
76
|
+
entryPoint: 'genoacms',
|
|
77
|
+
runtime: 'nodejs20',
|
|
78
|
+
source: {
|
|
79
|
+
storageSource
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
serviceConfig: {
|
|
83
|
+
minInstanceCount: 0,
|
|
84
|
+
maxInstanceCount: 1,
|
|
85
|
+
ingressSettings: 1, // ALLOW_ALL
|
|
86
|
+
environmentVariables: {
|
|
87
|
+
NODE_ENV: 'production'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
let response
|
|
93
|
+
if (isFunctionExisting) {
|
|
94
|
+
[response] = await functionsClient.updateFunction(operationParams)
|
|
95
|
+
} else {
|
|
96
|
+
[response] = await functionsClient.createFunction(operationParams)
|
|
97
|
+
}
|
|
98
|
+
console.log(response)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function deploy (): Promise<void> {
|
|
102
|
+
const buildDirectoryPath = '**'
|
|
103
|
+
const buildArchivePath = resolve(currentDir, '../../../deployment/build.zip')
|
|
104
|
+
const functionEntryScriptPath = resolve(currentDir, '../../../deployment/snippets/index.js')
|
|
105
|
+
const ignoreArchivePaths = [
|
|
106
|
+
'node_modules/**',
|
|
107
|
+
'.git/**',
|
|
108
|
+
'.github/**',
|
|
109
|
+
'.gitignore',
|
|
110
|
+
'build/**'
|
|
111
|
+
]
|
|
112
|
+
const injectArchivePaths = [
|
|
113
|
+
functionEntryScriptPath
|
|
114
|
+
]
|
|
115
|
+
await createZip(buildDirectoryPath, injectArchivePaths, ignoreArchivePaths, buildArchivePath)
|
|
116
|
+
const functionStorageSource = await uploadSource(buildArchivePath)
|
|
117
|
+
await deployFunction('genoacms', functionStorageSource)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export default deploy
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Adapter } from '@genoacms/cloudabstraction/deployment'
|
|
2
|
+
|
|
3
|
+
const svelteKitAdapter: Adapter.svelteKitAdapter = '@sveltejs/adapter-node'
|
|
4
|
+
|
|
5
|
+
const deployProcedure: Adapter.deployProcedure = async () => {
|
|
6
|
+
const deploy = (await import('./deploy.js')).default
|
|
7
|
+
await deploy()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
svelteKitAdapter,
|
|
12
|
+
deployProcedure
|
|
13
|
+
}
|
|
@@ -2,18 +2,9 @@ import type {
|
|
|
2
2
|
Adapter,
|
|
3
3
|
StorageObject
|
|
4
4
|
} from '@genoacms/cloudabstraction/storage'
|
|
5
|
-
import { type
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
const storage = new Storage({
|
|
9
|
-
credentials: config.storage.credentials
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
const getBucket = (name: string): Bucket => {
|
|
13
|
-
if (!config.storage.buckets.includes(name)) throw new Error('bucket-unregistered')
|
|
14
|
-
const bucket = storage.bucket(name)
|
|
15
|
-
return bucket
|
|
16
|
-
}
|
|
5
|
+
import { type File } from '@google-cloud/storage'
|
|
6
|
+
import { getBucket } from './storage.js'
|
|
7
|
+
import { join } from 'path'
|
|
17
8
|
|
|
18
9
|
const getObject: Adapter.getObject = async ({ bucket, name }) => {
|
|
19
10
|
const bucketInstance = getBucket(bucket)
|
|
@@ -30,11 +21,9 @@ const getPublicURL: Adapter.getPublicURL = async ({ bucket, name }) => {
|
|
|
30
21
|
return file.publicUrl()
|
|
31
22
|
}
|
|
32
23
|
|
|
33
|
-
const getSignedURL: Adapter.getSignedURL = async ({ bucket, name }) => {
|
|
24
|
+
const getSignedURL: Adapter.getSignedURL = async ({ bucket, name }, expires) => {
|
|
34
25
|
const bucketInstance = getBucket(bucket)
|
|
35
26
|
const file = bucketInstance.file(name)
|
|
36
|
-
const expires = new Date()
|
|
37
|
-
expires.setTime(expires.getTime() + 60 * 60 * 1_000)
|
|
38
27
|
const [url] = await file.getSignedUrl({
|
|
39
28
|
action: 'read',
|
|
40
29
|
expires
|
|
@@ -42,10 +31,10 @@ const getSignedURL: Adapter.getSignedURL = async ({ bucket, name }) => {
|
|
|
42
31
|
return url
|
|
43
32
|
}
|
|
44
33
|
|
|
45
|
-
const uploadObject: Adapter.uploadObject = async ({ bucket, name }, stream) => {
|
|
34
|
+
const uploadObject: Adapter.uploadObject = async ({ bucket, name }, stream, options) => {
|
|
46
35
|
const bucketInstance = getBucket(bucket)
|
|
47
36
|
const file = bucketInstance.file(name)
|
|
48
|
-
await file.save(stream)
|
|
37
|
+
await file.save(stream, options)
|
|
49
38
|
}
|
|
50
39
|
|
|
51
40
|
const deleteObject: Adapter.deleteObject = async ({ bucket, name }) => {
|
|
@@ -58,7 +47,7 @@ const listDirectory: Adapter.listDirectory = async ({ bucket, name }, listingPar
|
|
|
58
47
|
const bucketInstance = getBucket(bucket)
|
|
59
48
|
const options = {
|
|
60
49
|
autoPaginate: false,
|
|
61
|
-
prefix: name,
|
|
50
|
+
prefix: join(name, '/'),
|
|
62
51
|
maxResults: listingParams?.limit,
|
|
63
52
|
startOffset: listingParams?.startAfter,
|
|
64
53
|
delimiter: '/'
|
|
@@ -77,7 +66,7 @@ const listDirectory: Adapter.listDirectory = async ({ bucket, name }, listingPar
|
|
|
77
66
|
lastModified: new Date(file.metadata.updated as string)
|
|
78
67
|
} satisfies StorageObject
|
|
79
68
|
}),
|
|
80
|
-
directories: apiResponse?.prefixes ?? []
|
|
69
|
+
directories: (apiResponse?.prefixes ?? []).filter((item) => item !== name)
|
|
81
70
|
}
|
|
82
71
|
}
|
|
83
72
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import config from '../../config.js'
|
|
2
|
+
import { type Bucket, Storage } from '@google-cloud/storage'
|
|
3
|
+
|
|
4
|
+
const storage = new Storage({
|
|
5
|
+
credentials: config.storage.credentials
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
const getBucket = (name: string): Bucket => {
|
|
9
|
+
if (!config.storage.buckets.includes(name)) throw new Error('bucket-unregistered')
|
|
10
|
+
const bucket = storage.bucket(name)
|
|
11
|
+
return bucket
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
getBucket
|
|
16
|
+
}
|