@genoacms/adapter-gcp 0.5.2-fix.6 → 0.5.2-fix.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ import { handler } from './build/handler.js'
2
+
3
+ function genoacms (req, res) {
4
+ handler(req, res, undefined)
5
+ }
6
+
7
+ export { genoacms }
8
+
@@ -1,45 +1,16 @@
1
1
  import config from '../../config.js';
2
- import { readdir, lstat } from 'node:fs/promises';
3
2
  import { createReadStream, createWriteStream } from 'node:fs';
4
- import { join, resolve, dirname } from 'node:path';
3
+ import { resolve, dirname, basename } from 'node:path';
5
4
  import { fileURLToPath } from 'node:url';
6
- import { CloudFunctionsServiceClient } from '@google-cloud/functions';
5
+ import { v2 } from '@google-cloud/functions';
7
6
  import archiver from 'archiver';
8
- const functionsClient = new CloudFunctionsServiceClient({
7
+ const { FunctionServiceClient } = v2;
8
+ const functionsClient = new FunctionServiceClient({
9
9
  credentials: config.deployment.credentials
10
10
  });
11
11
  const projectId = config.deployment.projectId;
12
12
  const region = config.deployment.region;
13
- const { uploadObject, getSignedURL } = await config.storage.adapter;
14
- function locateFunctionEntryScript() {
15
- const currentDir = dirname(fileURLToPath(import.meta.url));
16
- const indexPath = resolve(currentDir, './snippets/index.js');
17
- return indexPath;
18
- }
19
- async function uploadFile(bucketName, filePath, destination) {
20
- const reference = { bucket: bucketName, name: destination };
21
- await uploadObject(reference, createReadStream(filePath));
22
- return await getSignedURL(reference, new Date(Date.now() + 1000 * 60 * 60 * 12));
23
- }
24
- async function uploadFileOrDirectory(bucketName, path, prefix = '') {
25
- const isDirectory = (await lstat(path)).isDirectory();
26
- if (isDirectory) {
27
- await uploadDirectory(bucketName, path, prefix);
28
- }
29
- else {
30
- await uploadFile(bucketName, path, prefix);
31
- }
32
- }
33
- async function uploadDirectory(bucketName, directoryPath, prefix = '') {
34
- const files = await readdir(directoryPath);
35
- const promises = [];
36
- for (const file of files) {
37
- const filePath = join(directoryPath, file);
38
- const destination = join(prefix, file);
39
- promises.push(uploadFileOrDirectory(bucketName, filePath, destination));
40
- }
41
- await Promise.all(promises);
42
- }
13
+ const currentDir = dirname(fileURLToPath(import.meta.url));
43
14
  async function createZip(source, injectPaths, ignorePaths, out) {
44
15
  await new Promise((resolve, reject) => {
45
16
  const output = createWriteStream(out);
@@ -53,7 +24,7 @@ async function createZip(source, injectPaths, ignorePaths, out) {
53
24
  archive.pipe(output);
54
25
  archive.glob(source, { ignore: ignorePaths });
55
26
  for (const path of injectPaths) {
56
- archive.append(path, { name: path });
27
+ archive.file(path, { name: basename(path) });
57
28
  }
58
29
  archive.finalize();
59
30
  });
@@ -62,7 +33,8 @@ async function uploadSource(sourceArchivePath) {
62
33
  const location = functionsClient.locationPath(projectId, region);
63
34
  const [urlResponse] = await functionsClient.generateUploadUrl({ parent: location });
64
35
  const uploadUrl = urlResponse.uploadUrl;
65
- if (!uploadUrl)
36
+ const storageSource = urlResponse.storageSource;
37
+ if (!uploadUrl || !storageSource)
66
38
  throw new Error('Upload URL not found');
67
39
  const sourceArchiveStream = createReadStream(sourceArchivePath);
68
40
  await fetch(uploadUrl, {
@@ -74,11 +46,11 @@ async function uploadSource(sourceArchivePath) {
74
46
  'Content-Type': 'application/zip'
75
47
  }
76
48
  });
77
- return uploadUrl;
49
+ return storageSource;
78
50
  }
79
- async function deployFunction(functionName, source) {
51
+ async function deployFunction(functionName, storageSource) {
80
52
  const location = functionsClient.locationPath(projectId, region);
81
- const name = functionsClient.cloudFunctionPath(projectId, region, functionName);
53
+ const name = functionsClient.functionPath(projectId, region, functionName);
82
54
  let isFunctionExisting;
83
55
  try {
84
56
  await functionsClient.getFunction({ name });
@@ -88,46 +60,52 @@ async function deployFunction(functionName, source) {
88
60
  isFunctionExisting = false;
89
61
  }
90
62
  const operationParams = {
91
- location,
63
+ functionId: functionName,
64
+ parent: location,
92
65
  function: {
93
66
  name,
94
- sourceUploadUrl: source,
95
- entryPoint: 'svelteKitApp',
96
- runtime: 'nodejs20',
97
- httpsTrigger: {},
98
- environmentVariables: {
99
- NODE_ENV: 'production'
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
+ }
100
81
  }
101
82
  }
102
83
  };
103
84
  let response;
104
85
  if (isFunctionExisting) {
105
- [response] = await functionsClient.updateFunction(operationParams, {});
86
+ [response] = await functionsClient.updateFunction(operationParams);
106
87
  }
107
88
  else {
108
- [response] = await functionsClient.createFunction(operationParams, {});
89
+ [response] = await functionsClient.createFunction(operationParams);
109
90
  }
110
- console.log(response, source);
91
+ console.log(response);
111
92
  }
112
93
  async function deploy() {
113
- const bucketName = config.storage.defaultBucket;
114
- const buildDirectoryPath = './*';
115
- const buildArchivePath = '.build.zip';
116
- const assetsDirectoryPath = './static';
117
- const assetsDestPath = '.genoacms/deployment/static';
94
+ const buildDirectoryPath = '**';
95
+ const buildArchivePath = resolve(currentDir, '../../../deployment/build.zip');
96
+ const functionEntryScriptPath = resolve(currentDir, '../../../deployment/snippets/index.js');
118
97
  const ignoreArchivePaths = [
119
- 'node_modules',
120
- '.git',
121
- '.github',
98
+ 'node_modules/**',
99
+ '.git/**',
100
+ '.github/**',
122
101
  '.gitignore',
123
- 'build'
102
+ 'build/**'
124
103
  ];
125
104
  const injectArchivePaths = [
126
- locateFunctionEntryScript()
105
+ functionEntryScriptPath
127
106
  ];
128
107
  await createZip(buildDirectoryPath, injectArchivePaths, ignoreArchivePaths, buildArchivePath);
129
- const uploadUrl = await uploadSource(buildArchivePath);
130
- await uploadDirectory(bucketName, assetsDirectoryPath, assetsDestPath);
131
- await deployFunction('genoacms', uploadUrl);
108
+ const functionStorageSource = await uploadSource(buildArchivePath);
109
+ await deployFunction('genoacms', functionStorageSource);
132
110
  }
133
111
  export default deploy;
@@ -1,4 +1,5 @@
1
1
  import { getBucket } from './storage.js';
2
+ import { join } from 'path';
2
3
  const getObject = async ({ bucket, name }) => {
3
4
  const bucketInstance = getBucket(bucket);
4
5
  const file = bucketInstance.file(name);
@@ -34,7 +35,7 @@ const listDirectory = async ({ bucket, name }, listingParams = {}) => {
34
35
  const bucketInstance = getBucket(bucket);
35
36
  const options = {
36
37
  autoPaginate: false,
37
- prefix: name,
38
+ prefix: join(name, '/'),
38
39
  maxResults: listingParams?.limit,
39
40
  startOffset: listingParams?.startAfter,
40
41
  delimiter: '/'
@@ -50,7 +51,7 @@ const listDirectory = async ({ bucket, name }, listingParams = {}) => {
50
51
  lastModified: new Date(file.metadata.updated)
51
52
  };
52
53
  }),
53
- directories: apiResponse?.prefixes ?? []
54
+ directories: (apiResponse?.prefixes ?? []).filter((item) => item !== name)
54
55
  };
55
56
  };
56
57
  const createDirectory = async ({ bucket, name }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genoacms/adapter-gcp",
3
- "version": "0.5.2-fix.6",
3
+ "version": "0.5.2-fix.9",
4
4
  "description": "Implementation of abstraction layer of GenoaCMS for GCP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,7 +20,6 @@
20
20
  "@genoacms/cloudabstraction": "^0.5.2",
21
21
  "@google-cloud/firestore": "^7.1.0",
22
22
  "@google-cloud/functions": "^3.2.0",
23
- "@google-cloud/functions-framework": "^3.3.0",
24
23
  "@google-cloud/resource-manager": "^5.1.0",
25
24
  "@google-cloud/storage": "^7.7.0",
26
25
  "archiver": "^7.0.0"
@@ -38,11 +37,11 @@
38
37
  "vitest": "^1.0.4"
39
38
  },
40
39
  "peerDependencies": {
41
- "@google-cloud/functions-framework": "^3.3.0",
42
40
  "@sveltejs/adapter-node": "^4.0.1"
43
41
  },
44
42
  "files": [
45
43
  "src",
44
+ "deployment",
46
45
  "dist"
47
46
  ],
48
47
  "exports": {
@@ -1,49 +1,20 @@
1
1
  import config from '../../config.js'
2
- import { readdir, lstat } from 'node:fs/promises'
3
2
  import { createReadStream, createWriteStream } from 'node:fs'
4
- import { join, resolve, dirname } from 'node:path'
3
+ import { resolve, dirname, basename } from 'node:path'
5
4
  import { fileURLToPath } from 'node:url'
6
- import { CloudFunctionsServiceClient } from '@google-cloud/functions'
5
+ import { v2 } from '@google-cloud/functions'
7
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
8
9
 
9
- const functionsClient = new CloudFunctionsServiceClient({
10
+ const { FunctionServiceClient } = v2
11
+ const functionsClient = new FunctionServiceClient({
10
12
  credentials: config.deployment.credentials
11
13
  })
12
14
  const projectId = config.deployment.projectId
13
15
  const region = config.deployment.region
14
- const { uploadObject, getSignedURL } = await config.storage.adapter
15
16
 
16
- function locateFunctionEntryScript (): string {
17
- const currentDir = dirname(fileURLToPath(import.meta.url))
18
- const indexPath = resolve(currentDir, './snippets/index.js')
19
- return indexPath
20
- }
21
- async function uploadFile (bucketName: string, filePath: string, destination: string): Promise<void> {
22
- const reference = { bucket: bucketName, name: destination }
23
- await uploadObject(reference, createReadStream(filePath))
24
- return await getSignedURL(reference, new Date(Date.now() + 1000 * 60 * 60 * 12))
25
- }
26
-
27
- async function uploadFileOrDirectory (bucketName: string, path: string, prefix = ''): Promise<void> {
28
- const isDirectory = (await lstat(path)).isDirectory()
29
- if (isDirectory) {
30
- await uploadDirectory(bucketName, path, prefix)
31
- } else {
32
- await uploadFile(bucketName, path, prefix)
33
- }
34
- }
35
-
36
- async function uploadDirectory (bucketName: string, directoryPath: string, prefix = ''): Promise<void> {
37
- const files = await readdir(directoryPath)
38
- const promises = []
39
-
40
- for (const file of files) {
41
- const filePath = join(directoryPath, file)
42
- const destination = join(prefix, file)
43
- promises.push(uploadFileOrDirectory(bucketName, filePath, destination))
44
- }
45
- await Promise.all(promises)
46
- }
17
+ const currentDir = dirname(fileURLToPath(import.meta.url))
47
18
 
48
19
  async function createZip (source: string, injectPaths: string[], ignorePaths: string[], out: string): Promise<void> {
49
20
  await new Promise<void>((resolve, reject) => {
@@ -61,17 +32,18 @@ async function createZip (source: string, injectPaths: string[], ignorePaths: st
61
32
  archive.pipe(output)
62
33
  archive.glob(source, { ignore: ignorePaths })
63
34
  for (const path of injectPaths) {
64
- archive.append(path, { name: path })
35
+ archive.file(path, { name: basename(path) })
65
36
  }
66
37
  archive.finalize()
67
38
  })
68
39
  }
69
40
 
70
- async function uploadSource (sourceArchivePath: string): Promise<string> {
41
+ async function uploadSource (sourceArchivePath: string): Promise<IStorageSource> {
71
42
  const location = functionsClient.locationPath(projectId, region)
72
43
  const [urlResponse] = await functionsClient.generateUploadUrl({ parent: location })
73
44
  const uploadUrl = urlResponse.uploadUrl
74
- if (!uploadUrl) throw new Error('Upload URL not found')
45
+ const storageSource = urlResponse.storageSource
46
+ if (!uploadUrl || !storageSource) throw new Error('Upload URL not found')
75
47
  const sourceArchiveStream = createReadStream(sourceArchivePath)
76
48
  await fetch(uploadUrl, {
77
49
  method: 'PUT',
@@ -82,12 +54,12 @@ async function uploadSource (sourceArchivePath: string): Promise<string> {
82
54
  'Content-Type': 'application/zip'
83
55
  }
84
56
  })
85
- return uploadUrl
57
+ return storageSource
86
58
  }
87
59
 
88
- async function deployFunction (functionName: string, source: string): Promise<void> {
60
+ async function deployFunction (functionName: string, storageSource: IStorageSource): Promise<void> {
89
61
  const location = functionsClient.locationPath(projectId, region)
90
- const name = functionsClient.cloudFunctionPath(projectId, region, functionName)
62
+ const name = functionsClient.functionPath(projectId, region, functionName)
91
63
  let isFunctionExisting: boolean
92
64
  try {
93
65
  await functionsClient.getFunction({ name })
@@ -96,47 +68,53 @@ async function deployFunction (functionName: string, source: string): Promise<vo
96
68
  isFunctionExisting = false
97
69
  }
98
70
  const operationParams = {
99
- location,
71
+ functionId: functionName,
72
+ parent: location,
100
73
  function: {
101
74
  name,
102
- sourceUploadUrl: source,
103
- entryPoint: 'svelteKitApp',
104
- runtime: 'nodejs20',
105
- httpsTrigger: {},
106
- environmentVariables: {
107
- NODE_ENV: 'production'
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
+ }
108
89
  }
109
90
  }
110
91
  }
111
92
  let response
112
93
  if (isFunctionExisting) {
113
- [response] = await functionsClient.updateFunction(operationParams, {})
94
+ [response] = await functionsClient.updateFunction(operationParams)
114
95
  } else {
115
- [response] = await functionsClient.createFunction(operationParams, {})
96
+ [response] = await functionsClient.createFunction(operationParams)
116
97
  }
117
- console.log(response, source)
98
+ console.log(response)
118
99
  }
119
100
 
120
101
  async function deploy (): Promise<void> {
121
- const bucketName = config.storage.defaultBucket
122
- const buildDirectoryPath = './*'
123
- const buildArchivePath = '.build.zip'
124
- const assetsDirectoryPath = './static'
125
- const assetsDestPath = '.genoacms/deployment/static'
102
+ const buildDirectoryPath = '**'
103
+ const buildArchivePath = resolve(currentDir, '../../../deployment/build.zip')
104
+ const functionEntryScriptPath = resolve(currentDir, '../../../deployment/snippets/index.js')
126
105
  const ignoreArchivePaths = [
127
- 'node_modules',
128
- '.git',
129
- '.github',
106
+ 'node_modules/**',
107
+ '.git/**',
108
+ '.github/**',
130
109
  '.gitignore',
131
- 'build'
110
+ 'build/**'
132
111
  ]
133
112
  const injectArchivePaths = [
134
- locateFunctionEntryScript()
113
+ functionEntryScriptPath
135
114
  ]
136
115
  await createZip(buildDirectoryPath, injectArchivePaths, ignoreArchivePaths, buildArchivePath)
137
- const uploadUrl = await uploadSource(buildArchivePath)
138
- await uploadDirectory(bucketName, assetsDirectoryPath, assetsDestPath)
139
- await deployFunction('genoacms', uploadUrl)
116
+ const functionStorageSource = await uploadSource(buildArchivePath)
117
+ await deployFunction('genoacms', functionStorageSource)
140
118
  }
141
119
 
142
120
  export default deploy
@@ -4,6 +4,7 @@ import type {
4
4
  } from '@genoacms/cloudabstraction/storage'
5
5
  import { type File } from '@google-cloud/storage'
6
6
  import { getBucket } from './storage.js'
7
+ import { join } from 'path'
7
8
 
8
9
  const getObject: Adapter.getObject = async ({ bucket, name }) => {
9
10
  const bucketInstance = getBucket(bucket)
@@ -46,7 +47,7 @@ const listDirectory: Adapter.listDirectory = async ({ bucket, name }, listingPar
46
47
  const bucketInstance = getBucket(bucket)
47
48
  const options = {
48
49
  autoPaginate: false,
49
- prefix: name,
50
+ prefix: join(name, '/'),
50
51
  maxResults: listingParams?.limit,
51
52
  startOffset: listingParams?.startAfter,
52
53
  delimiter: '/'
@@ -65,7 +66,7 @@ const listDirectory: Adapter.listDirectory = async ({ bucket, name }, listingPar
65
66
  lastModified: new Date(file.metadata.updated as string)
66
67
  } satisfies StorageObject
67
68
  }),
68
- directories: apiResponse?.prefixes ?? []
69
+ directories: (apiResponse?.prefixes ?? []).filter((item) => item !== name)
69
70
  }
70
71
  }
71
72
 
@@ -1,8 +0,0 @@
1
- import { HttpFunction } from '@google-cloud/functions-framework'
2
- import { handler } from './build/handler.js'
3
-
4
- const svelteKitApp = new HttpFunction(handler)
5
-
6
- export {
7
- svelteKitApp
8
- }