@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.
@@ -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-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.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",
@@ -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,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