@genoacms/adapter-gcp 0.1.1 → 0.3.8-1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/config.d.ts +2 -0
- package/dist/config.js +2 -0
- package/dist/services/database/index.d.ts +7 -0
- package/dist/services/database/index.js +61 -0
- package/dist/services/storage/index.d.ts +7 -0
- package/dist/services/storage/index.js +49 -0
- package/package.json +14 -11
- package/src/config.ts +4 -0
- package/src/genoa.config.d.ts +30 -0
- package/src/services/database/index.ts +76 -0
- package/src/services/storage/index.ts +50 -15
- package/dist/database/index.d.ts +0 -1
- package/dist/database/index.js +0 -1
- package/dist/storage/index.d.ts +0 -3
- package/dist/storage/index.js +0 -23
- /package/dist/{auth → services/auth}/index.d.ts +0 -0
- /package/dist/{auth → services/auth}/index.js +0 -0
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
import type { database as databaseT } from '@genoacms/cloudabstraction';
|
2
|
+
declare const createDocument: databaseT.createDocument;
|
3
|
+
declare const getCollection: databaseT.getCollection;
|
4
|
+
declare const getDocument: databaseT.getDocument;
|
5
|
+
declare const updateDocument: databaseT.updateDocument;
|
6
|
+
declare const deleteDocument: databaseT.deleteDocument;
|
7
|
+
export { createDocument, getDocument, getCollection, updateDocument, deleteDocument };
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import { Firestore } from '@google-cloud/firestore';
|
2
|
+
import config from '../../config.js';
|
3
|
+
const firestore = new Firestore({
|
4
|
+
credentials: config.database.credentials,
|
5
|
+
databaseId: config.database.databaseId,
|
6
|
+
projectId: config.database.projectId
|
7
|
+
});
|
8
|
+
const createDocument = async (reference, data) => {
|
9
|
+
const document = await firestore.collection(reference.name).add(data);
|
10
|
+
const documentReference = {
|
11
|
+
collection: reference,
|
12
|
+
id: document.id
|
13
|
+
};
|
14
|
+
return {
|
15
|
+
reference: documentReference,
|
16
|
+
data
|
17
|
+
};
|
18
|
+
};
|
19
|
+
const getCollection = async (reference) => {
|
20
|
+
const collection = await firestore.collection(reference.name).get();
|
21
|
+
const documents = [];
|
22
|
+
collection.forEach(document => {
|
23
|
+
const documentData = {};
|
24
|
+
Object.keys(reference.schema.properties).forEach(key => {
|
25
|
+
documentData[key] = document.get(key);
|
26
|
+
});
|
27
|
+
documents.push({
|
28
|
+
reference: {
|
29
|
+
collection: reference,
|
30
|
+
id: document.id
|
31
|
+
},
|
32
|
+
data: document.data()
|
33
|
+
});
|
34
|
+
});
|
35
|
+
return documents;
|
36
|
+
};
|
37
|
+
const getDocument = async ({ collection, id }) => {
|
38
|
+
const document = await firestore.collection(collection.name).doc(id).get();
|
39
|
+
if (!document.exists)
|
40
|
+
return undefined;
|
41
|
+
const documentReference = {
|
42
|
+
collection,
|
43
|
+
id
|
44
|
+
};
|
45
|
+
const documentSnapshot = {
|
46
|
+
reference: documentReference,
|
47
|
+
data: document.data()
|
48
|
+
};
|
49
|
+
return documentSnapshot;
|
50
|
+
};
|
51
|
+
const updateDocument = async (reference, document) => {
|
52
|
+
await firestore.collection(reference.collection.name).doc(reference.id).update(document);
|
53
|
+
return {
|
54
|
+
reference,
|
55
|
+
data: document
|
56
|
+
};
|
57
|
+
};
|
58
|
+
const deleteDocument = async (reference) => {
|
59
|
+
await firestore.collection(reference.collection.name).doc(reference.id).delete();
|
60
|
+
};
|
61
|
+
export { createDocument, getDocument, getCollection, updateDocument, deleteDocument };
|
@@ -0,0 +1,7 @@
|
|
1
|
+
import type { storage as storageT } from '@genoacms/cloudabstraction';
|
2
|
+
declare const getObject: storageT.getObject;
|
3
|
+
declare const uploadObject: storageT.uploadObject;
|
4
|
+
declare const deleteObject: storageT.deleteObject;
|
5
|
+
declare const listDirectory: storageT.listDirectory;
|
6
|
+
declare const createDirectory: storageT.createDirectory;
|
7
|
+
export { getObject, uploadObject, deleteObject, listDirectory, createDirectory };
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import { Storage } from '@google-cloud/storage';
|
2
|
+
import config from '../../config.js';
|
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
|
+
const getObject = async ({ bucket, name }) => {
|
13
|
+
const bucketInstance = getBucket(bucket);
|
14
|
+
const file = bucketInstance.file(name);
|
15
|
+
return {
|
16
|
+
data: file.createReadStream()
|
17
|
+
};
|
18
|
+
};
|
19
|
+
const uploadObject = async ({ bucket, name }, stream) => {
|
20
|
+
const bucketInstance = getBucket(bucket);
|
21
|
+
const file = bucketInstance.file(name);
|
22
|
+
await file.save(stream);
|
23
|
+
};
|
24
|
+
const deleteObject = async ({ bucket, name }) => {
|
25
|
+
const bucketInstance = getBucket(bucket);
|
26
|
+
const file = bucketInstance.file(name);
|
27
|
+
await file.delete();
|
28
|
+
};
|
29
|
+
const listDirectory = async ({ bucket, name }, listingParams = {}) => {
|
30
|
+
const bucketInstance = getBucket(bucket);
|
31
|
+
const [files] = await bucketInstance.getFiles({
|
32
|
+
prefix: name,
|
33
|
+
maxResults: listingParams?.limit,
|
34
|
+
startOffset: listingParams?.startAfter
|
35
|
+
});
|
36
|
+
return files.map((file) => {
|
37
|
+
return {
|
38
|
+
name: file.name,
|
39
|
+
size: file.metadata.size ? parseInt(file.metadata.size) : 0,
|
40
|
+
lastModified: new Date(file.metadata.updated)
|
41
|
+
};
|
42
|
+
});
|
43
|
+
};
|
44
|
+
const createDirectory = async ({ bucket, name }) => {
|
45
|
+
const bucketInstance = getBucket(bucket);
|
46
|
+
const file = bucketInstance.file(`${name}/.folderPlaceholder`);
|
47
|
+
await file.save('');
|
48
|
+
};
|
49
|
+
export { getObject, uploadObject, deleteObject, listDirectory, createDirectory };
|
package/package.json
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@genoacms/adapter-gcp",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.3.8-1",
|
4
4
|
"description": "Implementation of abstraction layer of GenoaCMS for GCP",
|
5
|
-
"main": "index.js",
|
6
5
|
"repository": {
|
7
6
|
"type": "git",
|
8
7
|
"url": "git+https://github.com/GenoaCMS/adapter-gcp.git"
|
@@ -18,7 +17,7 @@
|
|
18
17
|
"homepage": "https://github.com/GenoaCMS/adapter-gcp#readme",
|
19
18
|
"type": "module",
|
20
19
|
"dependencies": {
|
21
|
-
"@genoacms/cloudabstraction": "^0.
|
20
|
+
"@genoacms/cloudabstraction": "^0.3.8",
|
22
21
|
"@google-cloud/firestore": "^7.1.0",
|
23
22
|
"@google-cloud/storage": "^7.4.0"
|
24
23
|
},
|
@@ -30,7 +29,8 @@
|
|
30
29
|
"eslint-plugin-n": "^16.2.0",
|
31
30
|
"eslint-plugin-promise": "^6.1.1",
|
32
31
|
"rimraf": "^5.0.5",
|
33
|
-
"typescript": "^5.2.2"
|
32
|
+
"typescript": "^5.2.2",
|
33
|
+
"vitest": "^1.0.4"
|
34
34
|
},
|
35
35
|
"files": [
|
36
36
|
"src",
|
@@ -38,19 +38,22 @@
|
|
38
38
|
],
|
39
39
|
"exports": {
|
40
40
|
"./auth": {
|
41
|
-
"import": "./dist/auth/index.js",
|
42
|
-
"types": "./dist/auth/index.d.ts"
|
41
|
+
"import": "./dist/services/auth/index.js",
|
42
|
+
"types": "./dist/services/auth/index.d.ts"
|
43
43
|
},
|
44
44
|
"./database": {
|
45
|
-
"import": "./dist/database/index.js",
|
46
|
-
"types": "./dist/database/index.d.ts"
|
45
|
+
"import": "./dist/services/database/index.js",
|
46
|
+
"types": "./dist/services/database/index.d.ts"
|
47
47
|
},
|
48
48
|
"./storage": {
|
49
|
-
"import": "./dist/storage/index.js",
|
50
|
-
"types": "./dist/storage/index.d.ts"
|
49
|
+
"import": "./dist/services/storage/index.js",
|
50
|
+
"types": "./dist/services/storage/index.d.ts"
|
51
51
|
}
|
52
52
|
},
|
53
53
|
"scripts": {
|
54
|
-
"build": "rimraf dist && tsc"
|
54
|
+
"build": "rimraf dist && tsc",
|
55
|
+
"test:all": "npm run build && vitest --silent=false --config node_modules/@genoacms/cloudabstraction/test/vitest.config.js --run node_modules/@genoacms/cloudabstraction/test/all.test.js",
|
56
|
+
"test:database": "npm run build && vitest --silent=false --config node_modules/@genoacms/cloudabstraction/test/vitest.config.js --run node_modules/@genoacms/cloudabstraction/test/database.test.js",
|
57
|
+
"test:storage": "npm run build && vitest --silent=false --config node_modules/@genoacms/cloudabstraction/test/vitest.config.js --run node_modules/@genoacms/cloudabstraction/test/storage.test.js"
|
55
58
|
}
|
56
59
|
}
|
package/src/config.ts
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
import type Config from '@genoacms/cloudabstraction/src/genoa.config.js'
|
2
|
+
|
3
|
+
interface Credentials {
|
4
|
+
type: string
|
5
|
+
'project_id': string
|
6
|
+
'private_key_id': string
|
7
|
+
'private_key': string
|
8
|
+
'client_email': string
|
9
|
+
'client_id': string
|
10
|
+
'auth_uri': string
|
11
|
+
'token_uri': string
|
12
|
+
'auth_provider_x509_cert_url': string
|
13
|
+
'client_x509_cert_url': string
|
14
|
+
'universe_domain': string
|
15
|
+
}
|
16
|
+
|
17
|
+
interface DatabaseConfig {
|
18
|
+
credentials: Credentials
|
19
|
+
databaseId: string
|
20
|
+
region: string
|
21
|
+
}
|
22
|
+
|
23
|
+
interface StorageConfig {
|
24
|
+
credentials: Credentials
|
25
|
+
buckets: string[]
|
26
|
+
}
|
27
|
+
|
28
|
+
interface ConfigGCP extends Config<object, DatabaseConfig, StorageConfig> {}
|
29
|
+
|
30
|
+
export default ConfigGCP
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import { Firestore } from '@google-cloud/firestore'
|
2
|
+
import config from '../../config.js'
|
3
|
+
import type { database as databaseT } from '@genoacms/cloudabstraction'
|
4
|
+
|
5
|
+
const firestore = new Firestore({
|
6
|
+
credentials: config.database.credentials,
|
7
|
+
databaseId: config.database.databaseId,
|
8
|
+
projectId: config.database.projectId
|
9
|
+
})
|
10
|
+
|
11
|
+
const createDocument: databaseT.createDocument = async (reference, data) => {
|
12
|
+
const document = await firestore.collection(reference.name).add(data)
|
13
|
+
const documentReference: databaseT.DocumentReference<typeof reference> = {
|
14
|
+
collection: reference,
|
15
|
+
id: document.id
|
16
|
+
}
|
17
|
+
return {
|
18
|
+
reference: documentReference,
|
19
|
+
data
|
20
|
+
} satisfies databaseT.DocumentSnapshot<typeof reference>
|
21
|
+
}
|
22
|
+
|
23
|
+
const getCollection: databaseT.getCollection = async (reference) => {
|
24
|
+
const collection = await firestore.collection(reference.name).get()
|
25
|
+
const documents: databaseT.CollectionSnapshot<typeof reference> = []
|
26
|
+
|
27
|
+
collection.forEach(document => {
|
28
|
+
const documentData: databaseT.Document<typeof reference.schema> = {}
|
29
|
+
Object.keys(reference.schema.properties).forEach(key => {
|
30
|
+
documentData[key] = document.get(key)
|
31
|
+
})
|
32
|
+
|
33
|
+
documents.push({
|
34
|
+
reference: {
|
35
|
+
collection: reference,
|
36
|
+
id: document.id
|
37
|
+
},
|
38
|
+
data: document.data() as databaseT.Document<typeof reference.schema>
|
39
|
+
})
|
40
|
+
})
|
41
|
+
return documents
|
42
|
+
}
|
43
|
+
|
44
|
+
const getDocument: databaseT.getDocument = async ({ collection, id }) => {
|
45
|
+
const document = await firestore.collection(collection.name).doc(id).get()
|
46
|
+
if (!document.exists) return undefined
|
47
|
+
const documentReference: databaseT.DocumentReference<typeof collection> = {
|
48
|
+
collection,
|
49
|
+
id
|
50
|
+
}
|
51
|
+
const documentSnapshot: databaseT.DocumentSnapshot<typeof collection> = {
|
52
|
+
reference: documentReference,
|
53
|
+
data: document.data() as databaseT.Document<typeof collection>
|
54
|
+
}
|
55
|
+
return documentSnapshot
|
56
|
+
}
|
57
|
+
|
58
|
+
const updateDocument: databaseT.updateDocument = async (reference, document) => {
|
59
|
+
await firestore.collection(reference.collection.name).doc(reference.id).update(document)
|
60
|
+
return {
|
61
|
+
reference,
|
62
|
+
data: document
|
63
|
+
} satisfies databaseT.UpdateSnapshot<typeof reference.collection>
|
64
|
+
}
|
65
|
+
|
66
|
+
const deleteDocument: databaseT.deleteDocument = async (reference) => {
|
67
|
+
await firestore.collection(reference.collection.name).doc(reference.id).delete()
|
68
|
+
}
|
69
|
+
|
70
|
+
export {
|
71
|
+
createDocument,
|
72
|
+
getDocument,
|
73
|
+
getCollection,
|
74
|
+
updateDocument,
|
75
|
+
deleteDocument
|
76
|
+
}
|
@@ -1,31 +1,66 @@
|
|
1
1
|
import type {
|
2
2
|
storage as storageT
|
3
3
|
} from '@genoacms/cloudabstraction'
|
4
|
-
import { Storage } from '@google-cloud/storage'
|
5
|
-
import
|
4
|
+
import { type Bucket, Storage } from '@google-cloud/storage'
|
5
|
+
import config from '../../config.js'
|
6
6
|
|
7
7
|
const storage = new Storage({
|
8
|
-
|
9
|
-
credentials: config.adapter.gcp.credentials
|
8
|
+
credentials: config.storage.credentials
|
10
9
|
})
|
11
|
-
// @ts-expect-error: TODO: type this adapter
|
12
|
-
const bucket = storage.bucket(config.adapter.gcp.storage.bucket)
|
13
10
|
|
14
|
-
const
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
const getBucket = (name: string): Bucket => {
|
12
|
+
if (!config.storage.buckets.includes(name)) throw new Error('bucket-unregistered')
|
13
|
+
const bucket = storage.bucket(name)
|
14
|
+
return bucket
|
15
|
+
}
|
16
|
+
|
17
|
+
const getObject: storageT.getObject = async ({ bucket, name }) => {
|
18
|
+
const bucketInstance = getBucket(bucket)
|
19
|
+
const file = bucketInstance.file(name)
|
20
|
+
|
21
|
+
return {
|
22
|
+
data: file.createReadStream()
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
const uploadObject: storageT.uploadObject = async ({ bucket, name }, stream) => {
|
27
|
+
const bucketInstance = getBucket(bucket)
|
28
|
+
const file = bucketInstance.file(name)
|
29
|
+
await file.save(stream)
|
30
|
+
}
|
31
|
+
|
32
|
+
const deleteObject: storageT.deleteObject = async ({ bucket, name }) => {
|
33
|
+
const bucketInstance = getBucket(bucket)
|
34
|
+
const file = bucketInstance.file(name)
|
35
|
+
await file.delete()
|
36
|
+
}
|
37
|
+
|
38
|
+
const listDirectory: storageT.listDirectory = async ({ bucket, name }, listingParams = {}) => {
|
39
|
+
const bucketInstance = getBucket(bucket)
|
40
|
+
const [files] = await bucketInstance.getFiles({
|
41
|
+
prefix: name,
|
42
|
+
maxResults: listingParams?.limit,
|
43
|
+
startOffset: listingParams?.startAfter
|
18
44
|
})
|
19
45
|
return files.map((file) => {
|
20
46
|
return {
|
21
47
|
name: file.name,
|
22
|
-
size: file.metadata.size,
|
23
|
-
|
24
|
-
|
25
|
-
} as storageT.StorageObject
|
48
|
+
size: file.metadata.size ? parseInt(file.metadata.size as string) : 0,
|
49
|
+
lastModified: new Date(file.metadata.updated as string)
|
50
|
+
} satisfies storageT.StorageObject
|
26
51
|
})
|
27
52
|
}
|
28
53
|
|
54
|
+
const createDirectory: storageT.createDirectory = async ({ bucket, name }) => {
|
55
|
+
const bucketInstance = getBucket(bucket)
|
56
|
+
const file = bucketInstance.file(`${name}/.folderPlaceholder`)
|
57
|
+
await file.save('')
|
58
|
+
}
|
59
|
+
|
29
60
|
export {
|
30
|
-
|
61
|
+
getObject,
|
62
|
+
uploadObject,
|
63
|
+
deleteObject,
|
64
|
+
listDirectory,
|
65
|
+
createDirectory
|
31
66
|
}
|
package/dist/database/index.d.ts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export {};
|
package/dist/database/index.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export {};
|
package/dist/storage/index.d.ts
DELETED
package/dist/storage/index.js
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
import { Storage } from '@google-cloud/storage';
|
2
|
-
import { config } from '@genoacms/cloudabstraction';
|
3
|
-
const storage = new Storage({
|
4
|
-
// @ts-expect-error: TODO: type this adapter
|
5
|
-
credentials: config.adapter.gcp.credentials
|
6
|
-
});
|
7
|
-
// @ts-expect-error: TODO: type this adapter
|
8
|
-
const bucket = storage.bucket(config.adapter.gcp.storage.bucket);
|
9
|
-
const listDirectory = async ({ limit, prefix }) => {
|
10
|
-
const [files] = await bucket.getFiles({
|
11
|
-
prefix,
|
12
|
-
maxResults: limit
|
13
|
-
});
|
14
|
-
return files.map((file) => {
|
15
|
-
return {
|
16
|
-
name: file.name,
|
17
|
-
size: file.metadata.size,
|
18
|
-
// @ts-expect-error: Handle this
|
19
|
-
lastModified: new Date(file.metadata.updated)
|
20
|
-
};
|
21
|
-
});
|
22
|
-
};
|
23
|
-
export { listDirectory };
|
File without changes
|
File without changes
|