@genoacms/adapter-gcp 0.1.1 → 0.3.8

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.
@@ -0,0 +1,2 @@
1
+ declare const _default: Config<object, object, object>;
2
+ export default _default;
package/dist/config.js ADDED
@@ -0,0 +1,2 @@
1
+ import { config } from '@genoacms/cloudabstraction';
2
+ export default config;
@@ -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.1.1",
3
+ "version": "0.3.8",
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.1.7",
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",
@@ -51,6 +51,9 @@
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,4 @@
1
+ import type Config from './genoa.config.js'
2
+ import { config } from '@genoacms/cloudabstraction'
3
+
4
+ export default config satisfies Config
@@ -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 { config } from '@genoacms/cloudabstraction'
4
+ import { type Bucket, Storage } from '@google-cloud/storage'
5
+ import config from '../../config.js'
6
6
 
7
7
  const storage = new Storage({
8
- // @ts-expect-error: TODO: type this adapter
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 listDirectory: storageT.listDirectory = async ({ limit, prefix }) => {
15
- const [files] = await bucket.getFiles({
16
- prefix,
17
- maxResults: limit
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
- // @ts-expect-error: Handle this
24
- lastModified: new Date(file.metadata.updated)
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
- listDirectory
61
+ getObject,
62
+ uploadObject,
63
+ deleteObject,
64
+ listDirectory,
65
+ createDirectory
31
66
  }
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,3 +0,0 @@
1
- import type { storage as storageT } from '@genoacms/cloudabstraction';
2
- declare const listDirectory: storageT.listDirectory;
3
- export { listDirectory };
@@ -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