@genoacms/adapter-gcp 0.7.1 → 0.7.9
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 +1 -1
- package/dist/services/authorization/index.js +5 -4
- package/dist/services/database/index.js +2 -1
- package/dist/services/deployment/deploy.js +7 -4
- package/dist/services/storage/index.d.ts +4 -1
- package/dist/services/storage/index.js +30 -5
- package/dist/services/storage/storage.js +8 -3
- package/package.json +2 -2
- package/src/services/authorization/index.ts +5 -4
- package/src/services/database/index.ts +2 -1
- package/src/services/deployment/deploy.ts +6 -3
- package/src/services/storage/index.ts +37 -5
- package/src/services/storage/storage.ts +10 -4
@@ -1,13 +1,14 @@
|
|
1
1
|
import config from '../../config.js';
|
2
2
|
import { ProjectsClient } from '@google-cloud/resource-manager';
|
3
|
-
const
|
3
|
+
const PROVIDER_NAME = '@genoacms/adapter-gcp/authorization';
|
4
|
+
const authorizationConfig = config.authorization.providers.find((provider) => provider.name === PROVIDER_NAME);
|
4
5
|
if (!authorizationConfig)
|
5
6
|
throw new Error('authorization-provider-not-found');
|
7
|
+
const projectId = authorizationConfig.projectId;
|
6
8
|
const resourceManager = new ProjectsClient({
|
7
|
-
projectId
|
8
|
-
credentials:
|
9
|
+
projectId,
|
10
|
+
credentials: authorizationConfig.credentials
|
9
11
|
});
|
10
|
-
const projectId = config.authorization.projectId;
|
11
12
|
const isEmailAdmins = async (email) => {
|
12
13
|
const resource = `projects/${projectId}`;
|
13
14
|
const role = resource + '/roles/genoacms';
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import config from '../../config.js';
|
2
2
|
import { Firestore } from '@google-cloud/firestore';
|
3
|
-
const
|
3
|
+
const PROVIDER_NAME = '@genoacms/adapter-gcp/database';
|
4
|
+
const firestoreConfig = config.database.providers.find((provider) => provider.name === PROVIDER_NAME);
|
4
5
|
if (!firestoreConfig)
|
5
6
|
throw new Error('firestore-provider-not-found');
|
6
7
|
const firestore = new Firestore({
|
@@ -22,7 +22,7 @@ async function createZip(source, injectPaths, ignorePaths, out) {
|
|
22
22
|
reject(err);
|
23
23
|
});
|
24
24
|
archive.pipe(output);
|
25
|
-
archive.glob(source, { ignore: ignorePaths });
|
25
|
+
archive.glob(source, { ignore: ignorePaths, follow: true });
|
26
26
|
for (const path of injectPaths) {
|
27
27
|
archive.file(path, { name: basename(path) });
|
28
28
|
}
|
@@ -74,7 +74,7 @@ async function deployFunction(functionName, storageSource) {
|
|
74
74
|
serviceConfig: {
|
75
75
|
minInstanceCount: 0,
|
76
76
|
maxInstanceCount: 1,
|
77
|
-
ingressSettings: 1,
|
77
|
+
ingressSettings: 1, // ALLOW_ALL
|
78
78
|
environmentVariables: {
|
79
79
|
NODE_ENV: 'production'
|
80
80
|
}
|
@@ -92,17 +92,20 @@ async function deployFunction(functionName, storageSource) {
|
|
92
92
|
}
|
93
93
|
async function deploy() {
|
94
94
|
const buildDirectoryPath = '**';
|
95
|
-
const buildArchivePath = resolve(currentDir, '
|
95
|
+
const buildArchivePath = resolve(currentDir, '../../../../../../.genoacms/build.zip');
|
96
96
|
const functionEntryScriptPath = resolve(currentDir, '../../../deployment/snippets/index.js');
|
97
|
+
const builderScriptPath = resolve(currentDir, '../../../deployment/snippets/build.js');
|
97
98
|
const ignoreArchivePaths = [
|
98
99
|
'node_modules/**',
|
99
100
|
'.git/**',
|
100
101
|
'.github/**',
|
101
102
|
'.gitignore',
|
103
|
+
'.genoacms/**',
|
102
104
|
'build/**'
|
103
105
|
];
|
104
106
|
const injectArchivePaths = [
|
105
|
-
functionEntryScriptPath
|
107
|
+
functionEntryScriptPath,
|
108
|
+
builderScriptPath
|
106
109
|
];
|
107
110
|
await createZip(buildDirectoryPath, injectArchivePaths, ignoreArchivePaths, buildArchivePath);
|
108
111
|
const functionStorageSource = await uploadSource(buildArchivePath);
|
@@ -3,7 +3,10 @@ declare const getObject: Adapter['getObject'];
|
|
3
3
|
declare const getPublicURL: Adapter['getPublicURL'];
|
4
4
|
declare const getSignedURL: Adapter['getSignedURL'];
|
5
5
|
declare const uploadObject: Adapter['uploadObject'];
|
6
|
+
declare const moveObject: Adapter['moveObject'];
|
6
7
|
declare const deleteObject: Adapter['deleteObject'];
|
7
8
|
declare const listDirectory: Adapter['listDirectory'];
|
8
9
|
declare const createDirectory: Adapter['createDirectory'];
|
9
|
-
|
10
|
+
declare const deleteDirectory: Adapter['deleteDirectory'];
|
11
|
+
declare const moveDirectory: Adapter['moveDirectory'];
|
12
|
+
export { getObject, getPublicURL, getSignedURL, uploadObject, moveObject, deleteObject, listDirectory, createDirectory, deleteDirectory, moveDirectory };
|
@@ -1,5 +1,4 @@
|
|
1
1
|
import { getBucket } from './storage.js';
|
2
|
-
import { join } from 'path';
|
3
2
|
const getObject = async ({ bucket, name }) => {
|
4
3
|
const bucketInstance = getBucket(bucket);
|
5
4
|
const file = bucketInstance.file(name);
|
@@ -26,6 +25,11 @@ const uploadObject = async ({ bucket, name }, stream, options) => {
|
|
26
25
|
const file = bucketInstance.file(name);
|
27
26
|
await file.save(stream, options);
|
28
27
|
};
|
28
|
+
const moveObject = async ({ bucket, name }, newName) => {
|
29
|
+
const bucketInstance = getBucket(bucket);
|
30
|
+
const file = bucketInstance.file(name);
|
31
|
+
await file.move(newName);
|
32
|
+
};
|
29
33
|
const deleteObject = async ({ bucket, name }) => {
|
30
34
|
const bucketInstance = getBucket(bucket);
|
31
35
|
const file = bucketInstance.file(name);
|
@@ -35,7 +39,7 @@ const listDirectory = async ({ bucket, name }, listingParams = {}) => {
|
|
35
39
|
const bucketInstance = getBucket(bucket);
|
36
40
|
const options = {
|
37
41
|
autoPaginate: false,
|
38
|
-
prefix:
|
42
|
+
prefix: name,
|
39
43
|
maxResults: listingParams?.limit,
|
40
44
|
startOffset: listingParams?.startAfter,
|
41
45
|
delimiter: '/'
|
@@ -43,7 +47,7 @@ const listDirectory = async ({ bucket, name }, listingParams = {}) => {
|
|
43
47
|
let [files, , apiResponse] = (await bucketInstance.getFiles(options));
|
44
48
|
files = files.filter((file) => !file.name.endsWith('.folderPlaceholder'));
|
45
49
|
return {
|
46
|
-
files: files.map((file) => {
|
50
|
+
files: files.filter(f => f.name !== name).map((file) => {
|
47
51
|
return {
|
48
52
|
name: file.name,
|
49
53
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
@@ -51,7 +55,13 @@ const listDirectory = async ({ bucket, name }, listingParams = {}) => {
|
|
51
55
|
lastModified: new Date(file.metadata.updated)
|
52
56
|
};
|
53
57
|
}),
|
54
|
-
directories: (apiResponse?.prefixes ?? []).filter((item) => item !== name)
|
58
|
+
directories: (apiResponse?.prefixes ?? []).filter((item) => item !== name).map(i => {
|
59
|
+
const object = {
|
60
|
+
bucket,
|
61
|
+
name: i
|
62
|
+
};
|
63
|
+
return object;
|
64
|
+
})
|
55
65
|
};
|
56
66
|
};
|
57
67
|
const createDirectory = async ({ bucket, name }) => {
|
@@ -59,4 +69,19 @@ const createDirectory = async ({ bucket, name }) => {
|
|
59
69
|
const file = bucketInstance.file(`${name}/.folderPlaceholder`);
|
60
70
|
await file.save('');
|
61
71
|
};
|
62
|
-
|
72
|
+
const deleteDirectory = async ({ bucket, name }) => {
|
73
|
+
const bucketInstance = getBucket(bucket);
|
74
|
+
const [files] = await bucketInstance.getFiles({ prefix: name });
|
75
|
+
const deletePromises = files.map(async (file) => await file.delete());
|
76
|
+
await Promise.all(deletePromises);
|
77
|
+
};
|
78
|
+
const moveDirectory = async ({ bucket, name }, newName) => {
|
79
|
+
const bucketInstance = getBucket(bucket);
|
80
|
+
const [files] = await bucketInstance.getFiles({ prefix: name });
|
81
|
+
const movePromises = files.map(async (file) => {
|
82
|
+
const newFileName = file.name.replace(name, newName);
|
83
|
+
await file.move(newFileName);
|
84
|
+
});
|
85
|
+
await Promise.all(movePromises);
|
86
|
+
};
|
87
|
+
export { getObject, getPublicURL, getSignedURL, uploadObject, moveObject, deleteObject, listDirectory, createDirectory, deleteDirectory, moveDirectory };
|
@@ -1,13 +1,18 @@
|
|
1
1
|
import config from '../../config.js';
|
2
2
|
import { Storage } from '@google-cloud/storage';
|
3
|
-
const
|
3
|
+
const PROVIDER_NAME = '@genoacms/adapter-gcp/storage';
|
4
|
+
const storageConfig = config.storage.providers.find((provider) => provider.name === PROVIDER_NAME);
|
4
5
|
if (!storageConfig)
|
5
6
|
throw new Error('storage-provider-not-found');
|
6
7
|
const storage = new Storage({
|
7
|
-
credentials:
|
8
|
+
credentials: storageConfig.credentials
|
8
9
|
});
|
10
|
+
const hasBucket = (name) => {
|
11
|
+
const has = config.storage.buckets.find((bucket) => bucket.name === name && bucket.providerName === PROVIDER_NAME);
|
12
|
+
return !!has;
|
13
|
+
};
|
9
14
|
const getBucket = (name) => {
|
10
|
-
if (!
|
15
|
+
if (!hasBucket(name))
|
11
16
|
throw new Error('bucket-unregistered');
|
12
17
|
const bucket = storage.bucket(name);
|
13
18
|
return bucket;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@genoacms/adapter-gcp",
|
3
|
-
"version": "0.7.
|
3
|
+
"version": "0.7.9",
|
4
4
|
"type": "module",
|
5
5
|
"description": "Implementation of abstraction layer of GenoaCMS for GCP",
|
6
6
|
"repository": {
|
@@ -20,7 +20,7 @@
|
|
20
20
|
"provenance": true
|
21
21
|
},
|
22
22
|
"dependencies": {
|
23
|
-
"@genoacms/cloudabstraction": "^0.7.
|
23
|
+
"@genoacms/cloudabstraction": "^0.7.9",
|
24
24
|
"@google-cloud/firestore": "^7.1.0",
|
25
25
|
"@google-cloud/functions": "^3.4.0",
|
26
26
|
"@google-cloud/resource-manager": "^5.1.0",
|
@@ -2,13 +2,14 @@ import type { Adapter, AuthorizationProvider } from '@genoacms/cloudabstraction/
|
|
2
2
|
import config from '../../config.js'
|
3
3
|
import { ProjectsClient } from '@google-cloud/resource-manager'
|
4
4
|
|
5
|
-
const
|
5
|
+
const PROVIDER_NAME = '@genoacms/adapter-gcp/authorization'
|
6
|
+
const authorizationConfig = config.authorization.providers.find((provider: AuthorizationProvider) => provider.name === PROVIDER_NAME)
|
6
7
|
if (!authorizationConfig) throw new Error('authorization-provider-not-found')
|
8
|
+
const projectId = authorizationConfig.projectId
|
7
9
|
const resourceManager = new ProjectsClient({
|
8
|
-
projectId
|
9
|
-
credentials:
|
10
|
+
projectId,
|
11
|
+
credentials: authorizationConfig.credentials
|
10
12
|
})
|
11
|
-
const projectId = config.authorization.projectId
|
12
13
|
|
13
14
|
const isEmailAdmins: Adapter.isEmailAdmins = async (email: string) => {
|
14
15
|
const resource = `projects/${projectId}`
|
@@ -10,7 +10,8 @@ import type {
|
|
10
10
|
import config from '../../config.js'
|
11
11
|
import { Firestore } from '@google-cloud/firestore'
|
12
12
|
|
13
|
-
const
|
13
|
+
const PROVIDER_NAME = '@genoacms/adapter-gcp/database'
|
14
|
+
const firestoreConfig = config.database.providers.find((provider: DatabaseProvider) => provider.name === PROVIDER_NAME)
|
14
15
|
if (!firestoreConfig) throw new Error('firestore-provider-not-found')
|
15
16
|
const firestore = new Firestore({
|
16
17
|
credentials: firestoreConfig.credentials,
|
@@ -30,7 +30,7 @@ async function createZip (source: string, injectPaths: string[], ignorePaths: st
|
|
30
30
|
})
|
31
31
|
|
32
32
|
archive.pipe(output)
|
33
|
-
archive.glob(source, { ignore: ignorePaths })
|
33
|
+
archive.glob(source, { ignore: ignorePaths, follow: true })
|
34
34
|
for (const path of injectPaths) {
|
35
35
|
archive.file(path, { name: basename(path) })
|
36
36
|
}
|
@@ -100,17 +100,20 @@ async function deployFunction (functionName: string, storageSource: IStorageSour
|
|
100
100
|
|
101
101
|
async function deploy (): Promise<void> {
|
102
102
|
const buildDirectoryPath = '**'
|
103
|
-
const buildArchivePath = resolve(currentDir, '
|
103
|
+
const buildArchivePath = resolve(currentDir, '../../../../../../.genoacms/build.zip')
|
104
104
|
const functionEntryScriptPath = resolve(currentDir, '../../../deployment/snippets/index.js')
|
105
|
+
const builderScriptPath = resolve(currentDir, '../../../deployment/snippets/build.js')
|
105
106
|
const ignoreArchivePaths = [
|
106
107
|
'node_modules/**',
|
107
108
|
'.git/**',
|
108
109
|
'.github/**',
|
109
110
|
'.gitignore',
|
111
|
+
'.genoacms/**',
|
110
112
|
'build/**'
|
111
113
|
]
|
112
114
|
const injectArchivePaths = [
|
113
|
-
functionEntryScriptPath
|
115
|
+
functionEntryScriptPath,
|
116
|
+
builderScriptPath
|
114
117
|
]
|
115
118
|
await createZip(buildDirectoryPath, injectArchivePaths, ignoreArchivePaths, buildArchivePath)
|
116
119
|
const functionStorageSource = await uploadSource(buildArchivePath)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import type {
|
2
2
|
Adapter,
|
3
|
+
ObjectReference,
|
3
4
|
StorageObject
|
4
5
|
} from '@genoacms/cloudabstraction/storage'
|
5
6
|
import { type File } from '@google-cloud/storage'
|
6
7
|
import { getBucket } from './storage.js'
|
7
|
-
import { join } from 'path'
|
8
8
|
|
9
9
|
const getObject: Adapter['getObject'] = async ({ bucket, name }) => {
|
10
10
|
const bucketInstance = getBucket(bucket)
|
@@ -37,6 +37,12 @@ const uploadObject: Adapter['uploadObject'] = async ({ bucket, name }, stream, o
|
|
37
37
|
await file.save(stream, options)
|
38
38
|
}
|
39
39
|
|
40
|
+
const moveObject: Adapter['moveObject'] = async ({ bucket, name }, newName) => {
|
41
|
+
const bucketInstance = getBucket(bucket)
|
42
|
+
const file = bucketInstance.file(name)
|
43
|
+
await file.move(newName)
|
44
|
+
}
|
45
|
+
|
40
46
|
const deleteObject: Adapter['deleteObject'] = async ({ bucket, name }) => {
|
41
47
|
const bucketInstance = getBucket(bucket)
|
42
48
|
const file = bucketInstance.file(name)
|
@@ -47,7 +53,7 @@ const listDirectory: Adapter['listDirectory'] = async ({ bucket, name }, listing
|
|
47
53
|
const bucketInstance = getBucket(bucket)
|
48
54
|
const options = {
|
49
55
|
autoPaginate: false,
|
50
|
-
prefix:
|
56
|
+
prefix: name,
|
51
57
|
maxResults: listingParams?.limit,
|
52
58
|
startOffset: listingParams?.startAfter,
|
53
59
|
delimiter: '/'
|
@@ -58,7 +64,7 @@ const listDirectory: Adapter['listDirectory'] = async ({ bucket, name }, listing
|
|
58
64
|
files = files.filter((file) => !file.name.endsWith('.folderPlaceholder'))
|
59
65
|
|
60
66
|
return {
|
61
|
-
files: files.map((file) => {
|
67
|
+
files: files.filter(f => f.name !== name).map((file) => {
|
62
68
|
return {
|
63
69
|
name: file.name,
|
64
70
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
@@ -66,7 +72,13 @@ const listDirectory: Adapter['listDirectory'] = async ({ bucket, name }, listing
|
|
66
72
|
lastModified: new Date(file.metadata.updated as string)
|
67
73
|
} satisfies StorageObject
|
68
74
|
}),
|
69
|
-
directories: (apiResponse?.prefixes ?? []).filter((item) => item !== name)
|
75
|
+
directories: (apiResponse?.prefixes ?? []).filter((item) => item !== name).map(i => {
|
76
|
+
const object: ObjectReference = {
|
77
|
+
bucket,
|
78
|
+
name: i
|
79
|
+
}
|
80
|
+
return object
|
81
|
+
})
|
70
82
|
}
|
71
83
|
}
|
72
84
|
|
@@ -76,12 +88,32 @@ const createDirectory: Adapter['createDirectory'] = async ({ bucket, name }) =>
|
|
76
88
|
await file.save('')
|
77
89
|
}
|
78
90
|
|
91
|
+
const deleteDirectory: Adapter['deleteDirectory'] = async ({ bucket, name }) => {
|
92
|
+
const bucketInstance = getBucket(bucket)
|
93
|
+
const [files] = await bucketInstance.getFiles({ prefix: name })
|
94
|
+
const deletePromises = files.map(async (file) => await file.delete())
|
95
|
+
await Promise.all(deletePromises)
|
96
|
+
}
|
97
|
+
|
98
|
+
const moveDirectory: Adapter['moveDirectory'] = async ({ bucket, name }, newName) => {
|
99
|
+
const bucketInstance = getBucket(bucket)
|
100
|
+
const [files] = await bucketInstance.getFiles({ prefix: name })
|
101
|
+
const movePromises = files.map(async (file) => {
|
102
|
+
const newFileName = file.name.replace(name, newName)
|
103
|
+
await file.move(newFileName)
|
104
|
+
})
|
105
|
+
await Promise.all(movePromises)
|
106
|
+
}
|
107
|
+
|
79
108
|
export {
|
80
109
|
getObject,
|
81
110
|
getPublicURL,
|
82
111
|
getSignedURL,
|
83
112
|
uploadObject,
|
113
|
+
moveObject,
|
84
114
|
deleteObject,
|
85
115
|
listDirectory,
|
86
|
-
createDirectory
|
116
|
+
createDirectory,
|
117
|
+
deleteDirectory,
|
118
|
+
moveDirectory
|
87
119
|
}
|
@@ -1,15 +1,21 @@
|
|
1
1
|
import config from '../../config.js'
|
2
2
|
import { type Bucket, Storage } from '@google-cloud/storage'
|
3
|
-
import type { StorageProvider } from '@genoacms/cloudabstraction/storage'
|
3
|
+
import type { StorageProvider, BucketInit } from '@genoacms/cloudabstraction/storage'
|
4
4
|
|
5
|
-
const
|
5
|
+
const PROVIDER_NAME = '@genoacms/adapter-gcp/storage'
|
6
|
+
const storageConfig = config.storage.providers.find((provider: StorageProvider) => provider.name === PROVIDER_NAME)
|
6
7
|
if (!storageConfig) throw new Error('storage-provider-not-found')
|
7
8
|
const storage = new Storage({
|
8
|
-
credentials:
|
9
|
+
credentials: storageConfig.credentials
|
9
10
|
})
|
10
11
|
|
12
|
+
const hasBucket = (name: string): boolean => {
|
13
|
+
const has = config.storage.buckets.find((bucket: BucketInit) => bucket.name === name && bucket.providerName === PROVIDER_NAME)
|
14
|
+
return !!has
|
15
|
+
}
|
16
|
+
|
11
17
|
const getBucket = (name: string): Bucket => {
|
12
|
-
if (!
|
18
|
+
if (!hasBucket(name)) throw new Error('bucket-unregistered')
|
13
19
|
const bucket = storage.bucket(name)
|
14
20
|
return bucket
|
15
21
|
}
|