cloudcommerce 0.0.58 → 0.0.59

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.
Files changed (32) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/package.json +1 -1
  3. package/packages/api/package.json +1 -1
  4. package/packages/apps/discounts/package.json +1 -1
  5. package/packages/apps/tiny-erp/CHANGELOG.md +1 -0
  6. package/packages/apps/tiny-erp/README.md +1 -0
  7. package/packages/apps/tiny-erp/package.json +27 -0
  8. package/packages/apps/tiny-erp/src/firebase.ts +0 -0
  9. package/packages/apps/tiny-erp/src/index.ts +0 -0
  10. package/packages/apps/tiny-erp/tsconfig.json +3 -0
  11. package/packages/cli/config/firebase.json +6 -3
  12. package/packages/cli/lib/index.js +23 -4
  13. package/packages/cli/lib/{config-gcloud.js → setup-gcloud.js} +2 -2
  14. package/packages/cli/lib/setup-gh.js +59 -0
  15. package/packages/cli/package.json +2 -1
  16. package/packages/cli/src/index.ts +30 -3
  17. package/packages/cli/src/{config-gcloud.ts → setup-gcloud.ts} +2 -2
  18. package/packages/cli/src/setup-gh.ts +83 -0
  19. package/packages/events/package.json +2 -1
  20. package/packages/firebase/lib/config.js +1 -1
  21. package/packages/firebase/lib/config.js.map +1 -1
  22. package/packages/firebase/lib/handlers/check-store-events.d.ts +1 -1
  23. package/packages/firebase/lib/handlers/check-store-events.js +51 -10
  24. package/packages/firebase/lib/handlers/check-store-events.js.map +1 -1
  25. package/packages/firebase/package.json +2 -1
  26. package/packages/firebase/src/config.ts +1 -1
  27. package/packages/firebase/src/handlers/check-store-events.ts +59 -10
  28. package/packages/modules/package.json +1 -1
  29. package/packages/passport/package.json +1 -1
  30. package/packages/ssr/package.json +1 -1
  31. package/packages/storefront/package.json +3 -2
  32. package/packages/types/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [0.0.59](https://github.com/ecomplus/cloud-commerce/compare/v0.0.58...v0.0.59) (2022-08-24)
6
+
7
+
8
+ ### Features
9
+
10
+ * **cli:** Use `GITHUB_TOKEN` env to auto set secrets on setup ([#43](https://github.com/ecomplus/cloud-commerce/issues/43)) ([8949070](https://github.com/ecomplus/cloud-commerce/commit/89490703cba52affdbb69c63d8b459cb609f5130))
11
+ * **events:** Start publishing PubSub messages for each topic/app/event [[#29](https://github.com/ecomplus/cloud-commerce/issues/29)] ([9575d25](https://github.com/ecomplus/cloud-commerce/commit/9575d25d4ca27fcc19acbd0118b0140f8b484316))
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * **cli:** Do not create `GH_TOKEN` secret (set by default) ([8e50e37](https://github.com/ecomplus/cloud-commerce/commit/8e50e371477bdf67ec0cef380f2c6488d3d588a5))
17
+ * **deps:** Add `@google-cloud/pubsub` to core `@cloudcommerce/firebase` dependencies ([0b35b0e](https://github.com/ecomplus/cloud-commerce/commit/0b35b0edb560329a21869e8b6a75abaed9c4cd34))
18
+ * **events:** Save last run state and timestamp to Firestore ([7183a55](https://github.com/ecomplus/cloud-commerce/commit/7183a55694ca0e5cc6968be9ca4e965772937e2a))
19
+ * Set default GCloud region to `southamerica-east1` (São Paulo) ([212d04d](https://github.com/ecomplus/cloud-commerce/commit/212d04d72ace4cffe54489dae5b74c2dbfa4e0d0))
20
+
5
21
  ### [0.0.58](https://github.com/ecomplus/cloud-commerce/compare/v0.0.57...v0.0.58) (2022-08-23)
6
22
 
7
23
  ### [0.0.57](https://github.com/ecomplus/cloud-commerce/compare/v0.0.56...v0.0.57) (2022-08-23)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cloudcommerce",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.59",
5
5
  "description": "Open fair-code headless commerce platform: API-first, microservices based, event driven and cloud native",
6
6
  "main": "packages/api/lib/index.js",
7
7
  "author": "E-Com Club Softwares para E-commerce <ti@e-com.club>",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/api",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.59",
5
5
  "description": "E-Com Plus Cloud Commerce APIs client/adapter",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/app-discounts",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.59",
5
5
  "description": "E-Com Plus Cloud Commerce app for complex discount rules",
6
6
  "main": "lib/discounts.js",
7
7
  "repository": {
@@ -0,0 +1 @@
1
+ Please refer to GitHub [repository releases](https://github.com/ecomplus/cloud-commerce/releases) or monorepo unified [CHANGELOG.md](https://github.com/ecomplus/cloud-commerce/blob/main/CHANGELOG.md).
@@ -0,0 +1 @@
1
+ # `@cloudcommerce/tiny-erp`
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@cloudcommerce/app-tiny-erp",
3
+ "type": "module",
4
+ "version": "0.0.59",
5
+ "description": "E-Com Plus Cloud Commerce",
6
+ "main": "lib/index.js",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/ecomplus/cloud-commerce.git",
10
+ "directory": "packages/apps/tiny-erp"
11
+ },
12
+ "author": "E-Com Club Softwares para E-commerce <ti@e-com.club>",
13
+ "license": "Apache 2.0 with Commons Clause",
14
+ "bugs": {
15
+ "url": "https://github.com/ecomplus/cloud-commerce/issues"
16
+ },
17
+ "homepage": "https://github.com/ecomplus/cloud-commerce/tree/main/packages/apps/tiny-erp#readme",
18
+ "scripts": {
19
+ "build": "echo '@ecomplus/tiny-erp'"
20
+ },
21
+ "dependencies": {
22
+ "@cloudcommerce/api": "workspace:*"
23
+ },
24
+ "devDependencies": {
25
+ "@cloudcommerce/types": "workspace:*"
26
+ }
27
+ }
File without changes
File without changes
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../../tsconfig.json"
3
+ }
@@ -40,15 +40,18 @@
40
40
  "rewrites": [
41
41
  {
42
42
  "source": "/api/modules/**",
43
- "function": "modules"
43
+ "function": "modules",
44
+ "region": "southamerica-east1"
44
45
  },
45
46
  {
46
47
  "source": "/api/passport/**",
47
- "function": "passport"
48
+ "function": "passport",
49
+ "region": "southamerica-east1"
48
50
  },
49
51
  {
50
52
  "source": "**/!(*(*.)js|*(*.)css|*(*.)ico|*(*.)png|*(*.)gif|*(*.)jpg|*(*.)jpeg|*(*.)webp|*(*.)avif|*(*.)svg|*(*.)woff|*(*.)woff2|*(*.)otf|*(*.)ttf|*(*.)eot)",
51
- "function": "ssr"
53
+ "function": "ssr",
54
+ "region": "southamerica-east1"
52
55
  }
53
56
  ],
54
57
  "cleanUrls": true
@@ -5,9 +5,10 @@ import {
5
5
  } from 'zx';
6
6
  import login from './login.js';
7
7
  import build from './build.js';
8
- import { siginGcloudAndSetIAM, createKeyServiceAccount } from './config-gcloud.js';
8
+ import { siginGcloudAndSetIAM, createServiceAccountKey } from './setup-gcloud.js';
9
+ import createGhSecrets from './setup-gh.js';
9
10
 
10
- const { FIREBASE_PROJECT_ID, GOOGLE_APPLICATION_CREDENTIALS } = process.env;
11
+ const { FIREBASE_PROJECT_ID, GOOGLE_APPLICATION_CREDENTIALS, GITHUB_TOKEN } = process.env;
11
12
  const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
12
13
  const pwd = process.cwd();
13
14
  let projectId = FIREBASE_PROJECT_ID;
@@ -29,7 +30,7 @@ if (projectId) {
29
30
  const firebaserc = fs.readJSONSync(path.join(pwd, '.firebaserc'));
30
31
  projectId = firebaserc.projects.default;
31
32
  } catch (e) {
32
- projectId = 'ecom2-001';
33
+ projectId = 'ecom2-002';
33
34
  }
34
35
  }
35
36
  }
@@ -102,11 +103,29 @@ ECOM_STORE_ID=${storeId}
102
103
  if (argv.gcloud !== false) {
103
104
  try {
104
105
  await siginGcloudAndSetIAM(projectId, pwd);
105
- serviceAccountJSON = await createKeyServiceAccount(projectId, pwd);
106
+ serviceAccountJSON = await createServiceAccountKey(projectId, pwd);
106
107
  } catch (e) {
107
108
  //
108
109
  }
109
110
  }
111
+ let hasCreatedAllSecrets = false;
112
+ if (GITHUB_TOKEN && argv.github !== false) {
113
+ try {
114
+ hasCreatedAllSecrets = await createGhSecrets(apiKey, authenticationId, serviceAccountJSON, GITHUB_TOKEN);
115
+ } catch (e) {
116
+ //
117
+ }
118
+ }
119
+ if (hasCreatedAllSecrets) {
120
+ return echo`
121
+ ****
122
+
123
+ CloudCommerce setup completed successfully.
124
+ Your store repository on GitHub is ready, the first deploy will automatically start with GH Actions.
125
+
126
+ -- More info at https://github.com/ecomplus/store#getting-started
127
+ `;
128
+ }
110
129
  return echo`
111
130
  ****
112
131
 
@@ -78,7 +78,7 @@ const siginGcloudAndSetIAM = async (projectId, pwd) => {
78
78
  }
79
79
  return null;
80
80
  };
81
- const createKeyServiceAccount = async (projectId, pwd) => {
81
+ const createServiceAccountKey = async (projectId, pwd) => {
82
82
  try {
83
83
  const pathFileKey = path.join(pwd, '.cloudcommerce', 'serviceAccountKey.json');
84
84
  await $`gcloud iam service-accounts keys create ${pathFileKey} \
@@ -91,4 +91,4 @@ const createKeyServiceAccount = async (projectId, pwd) => {
91
91
 
92
92
  export default siginGcloudAndSetIAM;
93
93
 
94
- export { siginGcloudAndSetIAM, createKeyServiceAccount };
94
+ export { siginGcloudAndSetIAM, createServiceAccountKey };
@@ -0,0 +1,59 @@
1
+ import { fetch, $ } from 'zx';
2
+ import libsodium from 'libsodium-wrappers';
3
+
4
+ const getRemoteRepo = async () => {
5
+ try {
6
+ return (await $`git config --get remote.origin.url`).stdout
7
+ .replace(/.*github.com[/:]/, '')
8
+ .replace('.git', '')
9
+ .replace('\n', '');
10
+ } catch (e) {
11
+ return null;
12
+ }
13
+ };
14
+ const createGhSecrets = async (ecomApiKey, ecomAuthentication, firebaseServiceAccount, ghToken, ghRepo) => {
15
+ const remoteRepo = ghRepo || await getRemoteRepo();
16
+ if (!remoteRepo) {
17
+ throw new Error("Can't define remote Git repository");
18
+ }
19
+ const baseUrl = `https://api.github.com/repos/${remoteRepo}/actions/secrets`;
20
+ const fetchGhSecrets = async (resource, body, method = 'GET') => {
21
+ const url = `${baseUrl}${resource}`;
22
+ const headers = {
23
+ Accept: 'application/vnd.github+json',
24
+ Authorization: `token ${ghToken}`,
25
+ };
26
+ return fetch(url, {
27
+ method,
28
+ headers,
29
+ body,
30
+ });
31
+ };
32
+ // https:// docs.github.com/pt/rest/actions/secrets#get-a-repository-public-key
33
+ const ghPublicKey = await (await fetchGhSecrets('/public-key')).json();
34
+ const ghKeyBuffer = Buffer.from(ghPublicKey.key, 'base64');
35
+ await libsodium.ready;
36
+ const createGhSecret = async (secretName, secretValue) => {
37
+ // https://docs.github.com/pt/rest/actions/secrets#example-encrypting-a-secret-using-nodejs
38
+ // Encryption example: https://github.com/github/tweetsodium
39
+ const encryptedBytes = libsodium.crypto_box_seal(Buffer.from(secretValue), ghKeyBuffer);
40
+ const body = {
41
+ encrypted_value: Buffer.from(encryptedBytes).toString('base64'),
42
+ key_id: ghPublicKey.key_id,
43
+ };
44
+ return fetchGhSecrets(`/${secretName}`, JSON.stringify(body), 'PUT');
45
+ };
46
+ try {
47
+ await createGhSecret('ECOM_API_KEY', ecomApiKey);
48
+ await createGhSecret('ECOM_AUTHENTICATION_ID', ecomAuthentication);
49
+ if (firebaseServiceAccount) {
50
+ await createGhSecret('FIREBASE_SERVICE_ACCOUNT', firebaseServiceAccount);
51
+ return true;
52
+ }
53
+ } catch (e) {
54
+ //
55
+ }
56
+ return false;
57
+ };
58
+
59
+ export default createGhSecrets;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/cli",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.59",
5
5
  "description": "E-Com Plus Cloud Commerce CLI tools",
6
6
  "bin": {
7
7
  "cloudcommerce": "./bin/run.mjs"
@@ -27,6 +27,7 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@cloudcommerce/api": "workspace:*",
30
+ "libsodium-wrappers": "^0.7.10",
30
31
  "md5": "^2.3.0",
31
32
  "zx": "^7.0.8"
32
33
  }
@@ -9,11 +9,13 @@ import {
9
9
  } from 'zx';
10
10
  import login from './login';
11
11
  import build from './build';
12
- import { siginGcloudAndSetIAM, createKeyServiceAccount } from './config-gcloud';
12
+ import { siginGcloudAndSetIAM, createServiceAccountKey } from './setup-gcloud';
13
+ import createGhSecrets from './setup-gh';
13
14
 
14
15
  const {
15
16
  FIREBASE_PROJECT_ID,
16
17
  GOOGLE_APPLICATION_CREDENTIALS,
18
+ GITHUB_TOKEN,
17
19
  } = process.env;
18
20
 
19
21
  const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
@@ -41,7 +43,7 @@ if (projectId) {
41
43
  const firebaserc = fs.readJSONSync(path.join(pwd, '.firebaserc'));
42
44
  projectId = firebaserc.projects.default;
43
45
  } catch (e) {
44
- projectId = 'ecom2-001';
46
+ projectId = 'ecom2-002';
45
47
  }
46
48
  }
47
49
  }
@@ -103,6 +105,7 @@ ECOM_API_KEY=${apiKey}
103
105
  ECOM_STORE_ID=${storeId}
104
106
  `,
105
107
  );
108
+
106
109
  if (argv.deploy !== false) {
107
110
  await $firebase('deploy');
108
111
  }
@@ -111,6 +114,7 @@ ECOM_STORE_ID=${storeId}
111
114
  path.join(pwd, 'functions', 'config.json'),
112
115
  JSON.stringify({ storeId }, null, 2),
113
116
  );
117
+
114
118
  await build();
115
119
  try {
116
120
  await $`git add .firebaserc functions/config.json`;
@@ -124,12 +128,35 @@ ECOM_STORE_ID=${storeId}
124
128
  if (argv.gcloud !== false) {
125
129
  try {
126
130
  await siginGcloudAndSetIAM(projectId as string, pwd);
127
- serviceAccountJSON = await createKeyServiceAccount(projectId as string, pwd);
131
+ serviceAccountJSON = await createServiceAccountKey(projectId as string, pwd);
132
+ } catch (e) {
133
+ //
134
+ }
135
+ }
136
+ let hasCreatedAllSecrets = false;
137
+ if (GITHUB_TOKEN && argv.github !== false) {
138
+ try {
139
+ hasCreatedAllSecrets = await createGhSecrets(
140
+ apiKey,
141
+ authenticationId,
142
+ serviceAccountJSON,
143
+ GITHUB_TOKEN,
144
+ );
128
145
  } catch (e) {
129
146
  //
130
147
  }
131
148
  }
132
149
 
150
+ if (hasCreatedAllSecrets) {
151
+ return echo`
152
+ ****
153
+
154
+ CloudCommerce setup completed successfully.
155
+ Your store repository on GitHub is ready, the first deploy will automatically start with GH Actions.
156
+
157
+ -- More info at https://github.com/ecomplus/store#getting-started
158
+ `;
159
+ }
133
160
  return echo`
134
161
  ****
135
162
 
@@ -84,7 +84,7 @@ const siginGcloudAndSetIAM = async (projectId: string, pwd: string) => {
84
84
  return null;
85
85
  };
86
86
 
87
- const createKeyServiceAccount = async (projectId: string, pwd: string) => {
87
+ const createServiceAccountKey = async (projectId: string, pwd: string) => {
88
88
  try {
89
89
  const pathFileKey = path.join(pwd, '.cloudcommerce', 'serviceAccountKey.json');
90
90
  await $`gcloud iam service-accounts keys create ${pathFileKey} \
@@ -99,5 +99,5 @@ export default siginGcloudAndSetIAM;
99
99
 
100
100
  export {
101
101
  siginGcloudAndSetIAM,
102
- createKeyServiceAccount,
102
+ createServiceAccountKey,
103
103
  };
@@ -0,0 +1,83 @@
1
+ import { fetch, $ } from 'zx';
2
+ import libsodium from 'libsodium-wrappers';
3
+
4
+ const getRemoteRepo = async () => {
5
+ try {
6
+ return (await $`git config --get remote.origin.url`).stdout
7
+ .replace(/.*github.com[/:]/, '')
8
+ .replace('.git', '')
9
+ .replace('\n', '');
10
+ } catch (e) {
11
+ return null;
12
+ }
13
+ };
14
+
15
+ const createGhSecrets = async (
16
+ ecomApiKey: string,
17
+ ecomAuthentication: string,
18
+ firebaseServiceAccount: string | null,
19
+ ghToken: string,
20
+ ghRepo?: string,
21
+ ) => {
22
+ const remoteRepo = ghRepo || await getRemoteRepo();
23
+ if (!remoteRepo) {
24
+ throw new Error("Can't define remote Git repository");
25
+ }
26
+ const baseUrl = `https://api.github.com/repos/${remoteRepo}/actions/secrets`;
27
+
28
+ const fetchGhSecrets = async (
29
+ resource: string,
30
+ body?: string,
31
+ method: string = 'GET',
32
+ ) => {
33
+ const url = `${baseUrl}${resource}`;
34
+ const headers = {
35
+ Accept: 'application/vnd.github+json',
36
+ Authorization: `token ${ghToken}`,
37
+ };
38
+ return fetch(url, {
39
+ method,
40
+ headers,
41
+ body,
42
+ });
43
+ };
44
+
45
+ // https:// docs.github.com/pt/rest/actions/secrets#get-a-repository-public-key
46
+ const ghPublicKey = await (await fetchGhSecrets('/public-key')).json() as {
47
+ key_id: string,
48
+ key: string,
49
+ };
50
+ const ghKeyBuffer = Buffer.from(ghPublicKey.key, 'base64');
51
+ await libsodium.ready;
52
+
53
+ const createGhSecret = async (
54
+ secretName: string,
55
+ secretValue: string,
56
+ ) => {
57
+ // https://docs.github.com/pt/rest/actions/secrets#example-encrypting-a-secret-using-nodejs
58
+ // Encryption example: https://github.com/github/tweetsodium
59
+ const encryptedBytes = libsodium.crypto_box_seal(
60
+ Buffer.from(secretValue),
61
+ ghKeyBuffer,
62
+ );
63
+ const body = {
64
+ encrypted_value: Buffer.from(encryptedBytes).toString('base64'),
65
+ key_id: ghPublicKey.key_id,
66
+ };
67
+ return fetchGhSecrets(`/${secretName}`, JSON.stringify(body), 'PUT');
68
+ };
69
+
70
+ try {
71
+ await createGhSecret('ECOM_API_KEY', ecomApiKey);
72
+ await createGhSecret('ECOM_AUTHENTICATION_ID', ecomAuthentication);
73
+ if (firebaseServiceAccount) {
74
+ await createGhSecret('FIREBASE_SERVICE_ACCOUNT', firebaseServiceAccount);
75
+ return true;
76
+ }
77
+ } catch (e) {
78
+ //
79
+ }
80
+ return false;
81
+ };
82
+
83
+ export default createGhSecrets;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/events",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.59",
5
5
  "description": "E-Com Plus Cloud Commerce app events",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -24,6 +24,7 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@cloudcommerce/api": "workspace:*",
27
+ "@cloudcommerce/app-tiny-erp": "workspace:*",
27
28
  "@cloudcommerce/firebase": "workspace:*",
28
29
  "firebase-admin": "^11.0.1",
29
30
  "firebase-functions": "^3.22.0",
@@ -17,7 +17,7 @@ const self = {
17
17
  countryCode: env.ECOM_COUNTRY_CODE || DEFAULT_COUNTRY_CODE,
18
18
  storeId: Number(env.ECOM_STORE_ID),
19
19
  httpsFunctionOptions: {
20
- region: env.DEPLOY_REGION || 'us-central1',
20
+ region: env.DEPLOY_REGION || 'southamerica-east1',
21
21
  },
22
22
  apps: {
23
23
  discounts: {
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,aAAa;AACb,MAAM,GAAG,GAA8B,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,EAAE,GAAG,CAAC;OAC/E,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC;OACtC,EAAE,CAAC;AAER,MAAM,SAAS,GAAG,SAAS,EAAE,CAAC;AAE9B,MAAM,IAAI,GAAG;IACX,QAAQ,EAAE;QACR,KAAK,EAAE,8BAA8B;QACrC,IAAI,EAAE,GAAG,CAAC,SAAS,IAAI,YAAY;QACnC,QAAQ,EAAE,GAAG,CAAC,aAAa,IAAI,gBAAgB;QAC/C,cAAc,EAAE,GAAG,CAAC,oBAAoB,IAAI,uBAAuB;QACnE,WAAW,EAAE,GAAG,CAAC,iBAAiB,IAAI,oBAAoB;QAC1D,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC;QAClC,oBAAoB,EAAE;YACpB,MAAM,EAAE,GAAG,CAAC,aAAa,IAAI,aAAa;SAC3C;QACD,IAAI,EAAE;YACJ,SAAS,EAAE;gBACT,KAAK,EAAE,IAAI;aACZ;YACD,OAAO,EAAE;gBACP,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE;oBACN,qBAAqB;oBACrB,cAAc;oBACd,mBAAmB;iBACA;aACtB;SACF;KACF;CACF,CAAC;AAEF,eAAe;IACb,GAAG;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IACD,GAAG,CAAC,MAAM;QACR,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,MAAM,CAAC,OAAO,EAAE;YAClB,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC;SACpC;IACH,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,aAAa;AACb,MAAM,GAAG,GAA8B,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,EAAE,GAAG,CAAC;OAC/E,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC;OACtC,EAAE,CAAC;AAER,MAAM,SAAS,GAAG,SAAS,EAAE,CAAC;AAE9B,MAAM,IAAI,GAAG;IACX,QAAQ,EAAE;QACR,KAAK,EAAE,8BAA8B;QACrC,IAAI,EAAE,GAAG,CAAC,SAAS,IAAI,YAAY;QACnC,QAAQ,EAAE,GAAG,CAAC,aAAa,IAAI,gBAAgB;QAC/C,cAAc,EAAE,GAAG,CAAC,oBAAoB,IAAI,uBAAuB;QACnE,WAAW,EAAE,GAAG,CAAC,iBAAiB,IAAI,oBAAoB;QAC1D,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC;QAClC,oBAAoB,EAAE;YACpB,MAAM,EAAE,GAAG,CAAC,aAAa,IAAI,oBAAoB;SAClD;QACD,IAAI,EAAE;YACJ,SAAS,EAAE;gBACT,KAAK,EAAE,IAAI;aACZ;YACD,OAAO,EAAE;gBACP,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE;oBACN,qBAAqB;oBACrB,cAAc;oBACd,mBAAmB;iBACA;aACtB;SACF;KACF;CACF,CAAC;AAEF,eAAe;IACb,GAAG;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IACD,GAAG,CAAC,MAAM;QACR,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,MAAM,CAAC,OAAO,EAAE;YAClB,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC;SACpC;IACH,CAAC;CACF,CAAC"}
@@ -1,2 +1,2 @@
1
- declare const _default: () => Promise<boolean>;
1
+ declare const _default: () => Promise<FirebaseFirestore.WriteResult>;
2
2
  export default _default;
@@ -1,12 +1,15 @@
1
+ // eslint-disable-next-line import/no-unresolved
2
+ import { getFirestore } from 'firebase-admin/firestore';
1
3
  import logger from 'firebase-functions/lib/logger';
4
+ import { PubSub } from '@google-cloud/pubsub';
2
5
  import api from '@cloudcommerce/api';
3
6
  import getEnv from '../env.js';
4
7
  import config from '../config.js';
5
8
 
6
- const parseEventsTopic = (eventsTopic) => {
9
+ const parseEventsTopic = (eventsTopic, baseApiEventsFilter) => {
7
10
  const [resource, eventName] = eventsTopic.split('-');
8
11
  const params = {};
9
- const bodySet = {};
12
+ const bodySet = { ...baseApiEventsFilter };
10
13
  if (eventName === 'new') {
11
14
  params.action = 'create';
12
15
  } else {
@@ -50,8 +53,30 @@ const parseEventsTopic = (eventsTopic) => {
50
53
  });
51
54
  return { resource, params };
52
55
  };
56
+ const pubSubClient = new PubSub();
57
+ const tryPubSubPublish = (topicName, messageObj, retries = 0) => {
58
+ pubSubClient.topic(topicName).publishMessage(messageObj)
59
+ .catch((err) => {
60
+ // eslint-disable-next-line no-param-reassign
61
+ err.retries = retries;
62
+ logger.error(err);
63
+ if (retries <= 3) {
64
+ setTimeout(() => {
65
+ tryPubSubPublish(topicName, messageObj, retries + 1);
66
+ }, 1000 * (2 ** retries));
67
+ }
68
+ });
69
+ };
53
70
 
54
71
  export default async () => {
72
+ const timestamp = Date.now();
73
+ const documentRef = getFirestore().doc('storeEvents/last');
74
+ const lastRunTimestamp = (await documentRef.get()).get('timestamp')
75
+ || Date.now() - 1000 * 60 * 5;
76
+ const baseApiEventsFilter = {
77
+ 'timestamp>': new Date(lastRunTimestamp - 1).toISOString(),
78
+ 'timestamp<': new Date(timestamp).toISOString(),
79
+ };
55
80
  const { apps } = config.get();
56
81
  const { apiAuth } = getEnv();
57
82
  const subscribersApps = [];
@@ -61,25 +86,25 @@ export default async () => {
61
86
  subscribersApps.push(appObj);
62
87
  }
63
88
  });
64
- const activeSubscribersApps = (await api.get('applications', {
89
+ const activeAppsIds = (await api.get('applications', {
65
90
  params: {
66
91
  state: 'active',
67
92
  app_id: subscribersApps.map(({ appId }) => appId),
68
93
  fields: 'app_id',
69
94
  },
70
- })).data.result;
71
- logger.info({ activeSubscribersApps });
95
+ })).data.result.map((app) => app.app_id);
72
96
  const listenedEvents = [];
73
97
  subscribersApps.forEach(({ appId, events }) => {
74
- if (activeSubscribersApps.find((app) => app.app_id === appId)) {
98
+ if (activeAppsIds.includes(appId)) {
75
99
  events.forEach((eventsTopic) => {
76
- listenedEvents.push(eventsTopic);
100
+ if (!listenedEvents.includes(eventsTopic)) {
101
+ listenedEvents.push(eventsTopic);
102
+ }
77
103
  });
78
104
  }
79
105
  });
80
- logger.info({ listenedEvents });
81
106
  listenedEvents.forEach(async (eventsTopic) => {
82
- const { resource, params } = parseEventsTopic(eventsTopic);
107
+ const { resource, params } = parseEventsTopic(eventsTopic, baseApiEventsFilter);
83
108
  let { data: { result } } = await api.get(`events/${resource}`, {
84
109
  ...apiAuth,
85
110
  params,
@@ -99,8 +124,24 @@ export default async () => {
99
124
  if (typeof middleware === 'function') {
100
125
  result = await middleware(resource, result);
101
126
  }
127
+ result.forEach((apiEvent) => {
128
+ subscribersApps.forEach(({ appId, events }) => {
129
+ if (events.includes(eventsTopic) && activeAppsIds.includes(appId)) {
130
+ const topicName = `app${appId}_${eventsTopic}`;
131
+ const messageObj = {
132
+ messageId: `${eventsTopic}_${apiEvent.timestamp}`,
133
+ json: apiEvent,
134
+ };
135
+ tryPubSubPublish(topicName, messageObj);
136
+ }
137
+ });
138
+ });
102
139
  logger.info(`> '${eventsTopic}' events: `, result);
103
140
  });
104
- return true;
141
+ return documentRef.set({
142
+ timestamp,
143
+ activeAppsIds,
144
+ listenedEvents,
145
+ });
105
146
  };
106
147
  // # sourceMappingURL=check-store-events.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"check-store-events.js","sourceRoot":"","sources":["../../src/handlers/check-store-events.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"check-store-events.js","sourceRoot":"","sources":["../../src/handlers/check-store-events.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/firebase",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.59",
5
5
  "description": "E-Com Plus Cloud Commerce on Firebase",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
@@ -28,6 +28,7 @@
28
28
  "dependencies": {
29
29
  "@cloudcommerce/api": "workspace:*",
30
30
  "@fastify/deepmerge": "^1.1.0",
31
+ "@google-cloud/pubsub": "^3.1.0",
31
32
  "firebase-admin": "^11.0.1",
32
33
  "firebase-functions": "^3.22.0",
33
34
  "node-fetch": "^3.2.10",
@@ -23,7 +23,7 @@ const self = {
23
23
  countryCode: env.ECOM_COUNTRY_CODE || DEFAULT_COUNTRY_CODE,
24
24
  storeId: Number(env.ECOM_STORE_ID),
25
25
  httpsFunctionOptions: {
26
- region: env.DEPLOY_REGION || 'us-central1',
26
+ region: env.DEPLOY_REGION || 'southamerica-east1',
27
27
  },
28
28
  apps: {
29
29
  discounts: {
@@ -1,13 +1,19 @@
1
1
  import type { Resource, AppEventsTopic } from '@cloudcommerce/types';
2
+ // eslint-disable-next-line import/no-unresolved
3
+ import { getFirestore } from 'firebase-admin/firestore';
2
4
  import logger from 'firebase-functions/lib/logger';
5
+ import { PubSub } from '@google-cloud/pubsub';
3
6
  import api, { ApiConfig } from '@cloudcommerce/api';
4
7
  import getEnv from '../env';
5
8
  import config from '../config';
6
9
 
7
- const parseEventsTopic = (eventsTopic: AppEventsTopic) => {
10
+ const parseEventsTopic = (
11
+ eventsTopic: AppEventsTopic,
12
+ baseApiEventsFilter: Record<string, string>,
13
+ ) => {
8
14
  const [resource, eventName] = eventsTopic.split('-');
9
15
  const params: ApiConfig['params'] = {};
10
- const bodySet: { [key: string]: any } = {};
16
+ const bodySet: { [key: string]: any } = { ...baseApiEventsFilter };
11
17
  if (eventName === 'new') {
12
18
  params.action = 'create';
13
19
  } else {
@@ -55,7 +61,34 @@ const parseEventsTopic = (eventsTopic: AppEventsTopic) => {
55
61
  };
56
62
  };
57
63
 
64
+ const pubSubClient = new PubSub();
65
+ const tryPubSubPublish = (
66
+ topicName: string,
67
+ messageObj: { messageId: string, json: any },
68
+ retries = 0,
69
+ ) => {
70
+ pubSubClient.topic(topicName).publishMessage(messageObj)
71
+ .catch((err) => {
72
+ // eslint-disable-next-line no-param-reassign
73
+ err.retries = retries;
74
+ logger.error(err);
75
+ if (retries <= 3) {
76
+ setTimeout(() => {
77
+ tryPubSubPublish(topicName, messageObj, retries + 1);
78
+ }, 1000 * (2 ** retries));
79
+ }
80
+ });
81
+ };
82
+
58
83
  export default async () => {
84
+ const timestamp = Date.now();
85
+ const documentRef = getFirestore().doc('storeEvents/last');
86
+ const lastRunTimestamp: number = (await documentRef.get()).get('timestamp')
87
+ || Date.now() - 1000 * 60 * 5;
88
+ const baseApiEventsFilter = {
89
+ 'timestamp>': new Date(lastRunTimestamp - 1).toISOString(),
90
+ 'timestamp<': new Date(timestamp).toISOString(),
91
+ };
59
92
  const { apps } = config.get();
60
93
  const { apiAuth } = getEnv();
61
94
  const subscribersApps: Array<{ appId: number, events: AppEventsTopic[] }> = [];
@@ -65,25 +98,25 @@ export default async () => {
65
98
  subscribersApps.push(appObj);
66
99
  }
67
100
  });
68
- const activeSubscribersApps = (await api.get('applications', {
101
+ const activeAppsIds = (await api.get('applications', {
69
102
  params: {
70
103
  state: 'active',
71
104
  app_id: subscribersApps.map(({ appId }) => appId),
72
105
  fields: 'app_id',
73
106
  },
74
- })).data.result;
75
- logger.info({ activeSubscribersApps });
107
+ })).data.result.map((app) => app.app_id);
76
108
  const listenedEvents: AppEventsTopic[] = [];
77
109
  subscribersApps.forEach(({ appId, events }) => {
78
- if (activeSubscribersApps.find((app) => app.app_id === appId)) {
110
+ if (activeAppsIds.includes(appId)) {
79
111
  events.forEach((eventsTopic) => {
80
- listenedEvents.push(eventsTopic);
112
+ if (!listenedEvents.includes(eventsTopic)) {
113
+ listenedEvents.push(eventsTopic);
114
+ }
81
115
  });
82
116
  }
83
117
  });
84
- logger.info({ listenedEvents });
85
118
  listenedEvents.forEach(async (eventsTopic) => {
86
- const { resource, params } = parseEventsTopic(eventsTopic);
119
+ const { resource, params } = parseEventsTopic(eventsTopic, baseApiEventsFilter);
87
120
  let { data: { result } } = await api.get(`events/${resource}`, {
88
121
  ...apiAuth,
89
122
  params,
@@ -103,7 +136,23 @@ export default async () => {
103
136
  if (typeof middleware === 'function') {
104
137
  result = await middleware(resource, result);
105
138
  }
139
+ result.forEach((apiEvent) => {
140
+ subscribersApps.forEach(({ appId, events }) => {
141
+ if (events.includes(eventsTopic) && activeAppsIds.includes(appId)) {
142
+ const topicName = `app${appId}_${eventsTopic}`;
143
+ const messageObj = {
144
+ messageId: `${eventsTopic}_${apiEvent.timestamp}`,
145
+ json: apiEvent,
146
+ };
147
+ tryPubSubPublish(topicName, messageObj);
148
+ }
149
+ });
150
+ });
106
151
  logger.info(`> '${eventsTopic}' events: `, result);
107
152
  });
108
- return true;
153
+ return documentRef.set({
154
+ timestamp,
155
+ activeAppsIds,
156
+ listenedEvents,
157
+ });
109
158
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/modules",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.59",
5
5
  "description": "E-Com Plus Cloud Commerce modules API",
6
6
  "main": "lib/index.cjs",
7
7
  "exports": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/passport",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.59",
5
5
  "description": "E-Com Plus Cloud Commerce customers authentication (passport) API",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/ssr",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.59",
5
5
  "description": "E-Com Plus Cloud Commerce storefront SSR",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/storefront",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.59",
5
5
  "description": "E-Com Plus Cloud Commerce storefront with Astro",
6
6
  "main": "src/index.js",
7
7
  "repository": {
@@ -24,12 +24,13 @@
24
24
  "@astrojs/partytown": "^1.0.0",
25
25
  "@astrojs/prefetch": "^0.0.7",
26
26
  "@astrojs/sitemap": "^1.0.0",
27
- "@astrojs/tailwind": "^1.0.0",
28
27
  "@astrojs/vue": "^1.0.0",
29
28
  "@cloudcommerce/api": "workspace:*",
30
29
  "@picocss/pico": "^1.5.3",
31
30
  "astro": "^1.0.6",
32
31
  "rollup": "^2.78.1",
32
+ "unocss": "^0.45.12",
33
+ "vite": "^3.0.9",
33
34
  "vue": "^3.2.37"
34
35
  }
35
36
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/types",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.59",
5
5
  "description": "E-Com Plus Cloud Commerce reusable type definitions",
6
6
  "main": "index.ts",
7
7
  "repository": {