cloudcommerce 0.0.26 → 0.0.29

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 (48) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/CONTRIBUTING.md +1 -0
  3. package/package.json +4 -4
  4. package/packages/api/lib/index.d.ts +9988 -29
  5. package/packages/api/lib/index.js +47 -20
  6. package/packages/api/lib/index.js.map +1 -1
  7. package/packages/api/lib/types/applications.d.ts +1 -1
  8. package/packages/api/lib/types/authentications.d.ts +1 -1
  9. package/packages/api/lib/types/brands.d.ts +1 -1
  10. package/packages/api/lib/types/carts.d.ts +3 -3
  11. package/packages/api/lib/types/categories.d.ts +1 -1
  12. package/packages/api/lib/types/collections.d.ts +1 -1
  13. package/packages/api/lib/types/customers.d.ts +2 -2
  14. package/packages/api/lib/types/grids.d.ts +1 -1
  15. package/packages/api/lib/types/orders.d.ts +5 -5
  16. package/packages/api/lib/types/products.d.ts +2 -2
  17. package/packages/api/lib/types/stores.d.ts +1 -1
  18. package/packages/api/lib/types.d.ts +25 -8
  19. package/packages/api/package.json +1 -1
  20. package/packages/api/src/index.ts +78 -29
  21. package/packages/api/src/types/applications.d.ts +1 -1
  22. package/packages/api/src/types/authentications.d.ts +1 -1
  23. package/packages/api/src/types/brands.d.ts +1 -1
  24. package/packages/api/src/types/carts.d.ts +3 -3
  25. package/packages/api/src/types/categories.d.ts +1 -1
  26. package/packages/api/src/types/collections.d.ts +1 -1
  27. package/packages/api/src/types/customers.d.ts +2 -2
  28. package/packages/api/src/types/grids.d.ts +1 -1
  29. package/packages/api/src/types/orders.d.ts +5 -5
  30. package/packages/api/src/types/products.d.ts +2 -2
  31. package/packages/api/src/types/stores.d.ts +1 -1
  32. package/packages/api/src/types.ts +56 -17
  33. package/packages/api/tests/index.test.ts +16 -0
  34. package/packages/apps/discounts/package.json +1 -1
  35. package/packages/cli/create-auth.js +5 -0
  36. package/packages/cli/lib/create-auth.js +48 -0
  37. package/packages/cli/lib/index.js +39 -2
  38. package/packages/cli/lib/login.js +41 -0
  39. package/packages/cli/package.json +7 -1
  40. package/packages/cli/src/create-auth.ts +53 -0
  41. package/packages/cli/src/index.ts +52 -2
  42. package/packages/cli/src/login.ts +48 -0
  43. package/packages/firebase/lib/index.js +7 -2
  44. package/packages/firebase/lib/index.js.map +1 -1
  45. package/packages/firebase/package.json +1 -1
  46. package/packages/firebase/src/index.ts +8 -2
  47. package/packages/storefront/package.json +1 -1
  48. package/pnpm-lock.yaml +99 -63
@@ -9,7 +9,7 @@
9
9
  * Customer object model
10
10
  */
11
11
  export interface Customers {
12
- _id: string;
12
+ _id: string & { length: 24 };
13
13
  created_at: string;
14
14
  updated_at: string;
15
15
  store_id: number;
@@ -365,7 +365,7 @@ export interface Customers {
365
365
  /**
366
366
  * Order ID (ObjectID)
367
367
  */
368
- _id: string;
368
+ _id: string & { length: 24 };
369
369
  /**
370
370
  * When order was saved, date and time in ISO 8601 standard representation
371
371
  */
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  export interface Grids {
9
- _id: string;
9
+ _id: string & { length: 24 };
10
10
  created_at: string;
11
11
  updated_at: string;
12
12
  store_id: number;
@@ -9,7 +9,7 @@
9
9
  * Order object model
10
10
  */
11
11
  export interface Orders {
12
- _id: string;
12
+ _id: string & { length: 24 };
13
13
  created_at: string;
14
14
  updated_at: string;
15
15
  store_id: number;
@@ -229,7 +229,7 @@ export interface Orders {
229
229
  /**
230
230
  * Customer ID (ObjectID)
231
231
  */
232
- _id: string;
232
+ _id: string & { length: 24 };
233
233
  /**
234
234
  * Customer language two letter code, sometimes with region, e.g. 'pt_br', 'fr', 'en_us'
235
235
  */
@@ -1229,7 +1229,7 @@ export interface Orders {
1229
1229
  /**
1230
1230
  * Kit product ID (ObjectID)
1231
1231
  */
1232
- _id: string;
1232
+ _id: string & { length: 24 };
1233
1233
  /**
1234
1234
  * Kit product full name
1235
1235
  */
@@ -1251,7 +1251,7 @@ export interface Orders {
1251
1251
  /**
1252
1252
  * Product ID (ObjectID)
1253
1253
  */
1254
- _id: string;
1254
+ _id: string & { length: 24 };
1255
1255
  /**
1256
1256
  * Selected variation ID (ObjectID) if any
1257
1257
  */
@@ -1345,7 +1345,7 @@ export interface Orders {
1345
1345
  /**
1346
1346
  * Subscription order ID (ObjectID)
1347
1347
  */
1348
- _id: string;
1348
+ _id: string & { length: 24 };
1349
1349
  /**
1350
1350
  * Subscription order number
1351
1351
  */
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  export interface Products {
9
- _id: string;
9
+ _id: string & { length: 24 };
10
10
  created_at: string;
11
11
  updated_at: string;
12
12
  store_id: number;
@@ -1179,7 +1179,7 @@ export interface Products {
1179
1179
  /**
1180
1180
  * Product ID (ObjectID)
1181
1181
  */
1182
- _id: string;
1182
+ _id: string & { length: 24 };
1183
1183
  /**
1184
1184
  * Product quantity
1185
1185
  */
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  export interface Stores {
9
- _id: string;
9
+ _id: string & { length: 24 };
10
10
  created_at: string;
11
11
  updated_at: string;
12
12
  store_id: number;
@@ -8,6 +8,7 @@ import type { Orders } from './types/orders';
8
8
  import type { Customers } from './types/customers';
9
9
  import type { Stores } from './types/stores';
10
10
  import type { Applications } from './types/applications';
11
+ import type { Authentications } from './types/authentications';
11
12
 
12
13
  type Resource = 'products'
13
14
  | 'categories'
@@ -18,17 +19,20 @@ type Resource = 'products'
18
19
  | 'orders'
19
20
  | 'customers'
20
21
  | 'stores'
21
- | 'applications';
22
+ | 'applications'
23
+ | 'authentications';
22
24
 
23
25
  type ResourceId = string & { length: 24 };
24
26
 
25
27
  type ResourceAndId = `${Resource}/${ResourceId}`;
26
28
 
29
+ type ResourceOpQuery = Resource | `${Resource}?${string}`;
30
+
27
31
  type EventsEndpoint = `events/${Resource}`
28
32
  | `events/${ResourceAndId}`
29
33
  | 'events/me';
30
34
 
31
- type Endpoint = Resource
35
+ type Endpoint = ResourceOpQuery
32
36
  | ResourceAndId
33
37
  | `${ResourceAndId}/${string}`
34
38
  | `slugs/${string}`
@@ -38,7 +42,7 @@ type Endpoint = Resource
38
42
  | 'authenticate'
39
43
  | 'ask-auth-callback'
40
44
  | 'check-username'
41
- | `$aggregate/${Exclude<Resource, 'stores' | 'applications'>}`
45
+ | `$aggregate/${Exclude<Resource, 'stores' | 'applications' | 'authentications'>}`
42
46
  | `schemas/${Resource}`;
43
47
 
44
48
  type Method = 'get' | 'post' | 'put' | 'patch' | 'delete';
@@ -46,11 +50,14 @@ type Method = 'get' | 'post' | 'put' | 'patch' | 'delete';
46
50
  type Config = {
47
51
  baseUrl?: string,
48
52
  storeId?: number,
53
+ accessToken?: string,
54
+ authenticationId?: string,
55
+ apiKey?: string,
49
56
  lang?: string,
50
57
  method?: Method,
51
58
  endpoint: Endpoint,
52
59
  params?: Record<string, string | number>,
53
- headers?: Record<string, string>,
60
+ headers?: Headers | Record<string, string>,
54
61
  timeout?: number,
55
62
  maxRetries?: number,
56
63
  fetch?: typeof fetch,
@@ -62,18 +69,21 @@ type BaseListResultMeta = {
62
69
  fields: Array<string>,
63
70
  };
64
71
 
65
- type ResourceListResult<TResource extends Resource> = {
72
+ type ListEndpoint<TResource extends Resource> = TResource | `${TResource}?${string}`;
73
+
74
+ type ResourceListResult<TEndpoint extends ResourceOpQuery> = {
66
75
  result:
67
- TResource extends 'products' ? Products[] :
68
- TResource extends 'categories' ? Categories[] :
69
- TResource extends 'brands' ? Brands[] :
70
- TResource extends 'collections' ? Collections[] :
71
- TResource extends 'grids' ? Grids[] :
72
- TResource extends 'carts' ? Carts[] :
73
- TResource extends 'orders' ? Orders[] :
74
- TResource extends 'customers' ? Customers[] :
75
- TResource extends 'stores' ? Stores[] :
76
- TResource extends 'applications' ? Applications[] :
76
+ TEndpoint extends ListEndpoint<'products'> ? Products[] :
77
+ TEndpoint extends ListEndpoint<'categories'> ? Categories[] :
78
+ TEndpoint extends ListEndpoint<'brands'> ? Brands[] :
79
+ TEndpoint extends ListEndpoint<'collections'> ? Collections[] :
80
+ TEndpoint extends ListEndpoint<'grids'> ? Grids[] :
81
+ TEndpoint extends ListEndpoint<'carts'> ? Carts[] :
82
+ TEndpoint extends ListEndpoint<'orders'> ? Orders[] :
83
+ TEndpoint extends ListEndpoint<'customers'> ? Customers[] :
84
+ TEndpoint extends ListEndpoint<'stores'> ? Stores[] :
85
+ TEndpoint extends ListEndpoint<'applications'> ? Applications[] :
86
+ TEndpoint extends ListEndpoint<'authentications'> ? Authentications[] :
77
87
  never,
78
88
  meta: BaseListResultMeta & {
79
89
  count?: number,
@@ -117,9 +127,13 @@ type EventsResult<TEndpoint extends EventsEndpoint> = {
117
127
  };
118
128
 
119
129
  type ResponseBody<TConfig extends Config> =
120
- TConfig['method'] extends 'post' ? { _id: ResourceId } :
130
+ TConfig['method'] extends 'post' ?
131
+ TConfig['endpoint'] extends 'login' ? { _id: ResourceId, store_ids: number[], api_key: string } :
132
+ TConfig['endpoint'] extends 'authenticate' ? { my_id: string, access_token: string, expires: string } :
133
+ { _id: ResourceId } :
121
134
  TConfig['method'] extends 'put' | 'patch' | 'delete' ? null :
122
135
  // method?: 'get'
136
+ TConfig['endpoint'] extends `${string}/${ResourceId}/${string}` ? any :
123
137
  TConfig['endpoint'] extends `products/${ResourceId}` ? Products :
124
138
  TConfig['endpoint'] extends `categories/${ResourceId}` ? Categories :
125
139
  TConfig['endpoint'] extends `brands/${ResourceId}` ? Brands :
@@ -130,10 +144,33 @@ type ResponseBody<TConfig extends Config> =
130
144
  TConfig['endpoint'] extends `customers/${ResourceId}` ? Customers :
131
145
  TConfig['endpoint'] extends `stores/${ResourceId}` ? Stores :
132
146
  TConfig['endpoint'] extends `applications/${ResourceId}` ? Applications :
133
- TConfig['endpoint'] extends Resource ? ResourceListResult<TConfig['endpoint']> :
147
+ TConfig['endpoint'] extends `authentications/${ResourceId}` ? Authentications :
148
+ TConfig['endpoint'] extends ResourceOpQuery ? ResourceListResult<TConfig['endpoint']> :
134
149
  TConfig['endpoint'] extends EventsEndpoint ? EventsResult<TConfig['endpoint']> :
135
150
  any;
136
151
 
152
+ type DocSchema<Document extends any> =
153
+ Omit<Document, '_id' | 'store_id' | 'store_ids' | 'created_at' | 'updated_at'>;
154
+
155
+ type SetDocEndpoint<TResource extends Resource> = TResource | `${TResource}/${ResourceId}`;
156
+
157
+ type RequestBody<TConfig extends Config> =
158
+ TConfig['method'] extends undefined | 'get' | 'delete' ? undefined :
159
+ TConfig['method'] extends 'patch' ? any : // TODO: partial body
160
+ // method: 'post' | 'put'
161
+ TConfig['endpoint'] extends SetDocEndpoint<'products'> ? DocSchema<Products> :
162
+ TConfig['endpoint'] extends SetDocEndpoint<'categories'> ? DocSchema<Categories> :
163
+ TConfig['endpoint'] extends SetDocEndpoint<'brands'> ? DocSchema<Brands> :
164
+ TConfig['endpoint'] extends SetDocEndpoint<'collections'> ? DocSchema<Collections> :
165
+ TConfig['endpoint'] extends SetDocEndpoint<'grids'> ? DocSchema<Grids> :
166
+ TConfig['endpoint'] extends SetDocEndpoint<'carts'> ? DocSchema<Carts> :
167
+ TConfig['endpoint'] extends SetDocEndpoint<'orders'> ? DocSchema<Orders> :
168
+ TConfig['endpoint'] extends SetDocEndpoint<'customers'> ? DocSchema<Customers> :
169
+ TConfig['endpoint'] extends SetDocEndpoint<'stores'> ? DocSchema<Stores> :
170
+ TConfig['endpoint'] extends SetDocEndpoint<'applications'> ? DocSchema<Applications> :
171
+ TConfig['endpoint'] extends SetDocEndpoint<'authentications'> ? DocSchema<Authentications> :
172
+ any;
173
+
137
174
  export type {
138
175
  Products,
139
176
  Categories,
@@ -147,8 +184,10 @@ export type {
147
184
  Applications,
148
185
  Resource,
149
186
  ResourceAndId,
187
+ ResourceOpQuery,
150
188
  Endpoint,
151
189
  Method,
152
190
  Config,
153
191
  ResponseBody,
192
+ RequestBody,
154
193
  };
@@ -52,3 +52,19 @@ test('401 trying to list API events', async () => {
52
52
  expect(error.response?.status).toBe(401);
53
53
  }
54
54
  });
55
+
56
+ test('401 to create category and body typecheck', async () => {
57
+ try {
58
+ const { data } = await api.post('categories', {
59
+ name: 'Test category',
60
+ }, {
61
+ accessToken: 'invalid',
62
+ });
63
+ console.log(data._id);
64
+ throw new Error('Should have thrown unauthorized');
65
+ } catch (err: any) {
66
+ const error = err as ApiError;
67
+ expect(error.statusCode).toBe(401);
68
+ expect(error.response?.status).toBe(401);
69
+ }
70
+ });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/app-discounts",
3
3
  "type": "module",
4
- "version": "0.0.26",
4
+ "version": "0.0.29",
5
5
  "description": "E-Com Plus Cloud Commerce app for complex discount rules",
6
6
  "main": "functions/dist/index.js",
7
7
  "repository": {
@@ -0,0 +1,5 @@
1
+ import createAuth from './lib/create-auth.js';
2
+
3
+ export default createAuth;
4
+
5
+ export { createAuth };
@@ -0,0 +1,48 @@
1
+ import { fetch } from 'zx';
2
+ import api from '@cloudcommerce/api';
3
+
4
+ const defaultAgent = {
5
+ name: 'Cloud Commerce default agent',
6
+ email: 'cloudcommerce-noreply@e-com.plus',
7
+ };
8
+
9
+ export default async (storeId, accessToken) => {
10
+ const apiConfig = {
11
+ storeId,
12
+ accessToken,
13
+ fetch,
14
+ };
15
+ const { data } = await api.get('authentications', {
16
+ ...apiConfig,
17
+ params: {
18
+ email: defaultAgent.email,
19
+ limit: 1,
20
+ },
21
+ });
22
+ let authenticationId = data.result[0]?._id;
23
+ if (!authenticationId) {
24
+ const { data: { _id } } = await api.post('authentications', {
25
+ ...defaultAgent,
26
+ username: `cloudcomm${Date.now()}`,
27
+ permissions: {
28
+ applications: ['all'],
29
+ brands: ['GET'],
30
+ carts: ['all'],
31
+ categories: ['GET'],
32
+ collections: ['GET'],
33
+ customers: ['all'],
34
+ grids: ['GET'],
35
+ orders: ['GET', 'POST', 'PATCH'],
36
+ products: ['GET', 'PATCH'],
37
+ stores: ['GET'],
38
+ },
39
+ }, apiConfig);
40
+ authenticationId = _id;
41
+ }
42
+ const { data: apiKey } = await api.get(`authentications/${authenticationId}/api_key`, apiConfig);
43
+ return {
44
+ storeId,
45
+ authenticationId,
46
+ apiKey,
47
+ };
48
+ };
@@ -1,6 +1,9 @@
1
1
  import url from 'url';
2
2
  import path from 'path';
3
- import { $, argv, fs } from 'zx';
3
+ import {
4
+ $, argv, fs, echo, chalk,
5
+ } from 'zx';
6
+ import login from './login.js';
4
7
 
5
8
  const { FIREBASE_PROJECT_ID, GOOGLE_APPLICATION_CREDENTIALS } = process.env;
6
9
  const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
@@ -32,7 +35,7 @@ if (projectId) {
32
35
  export default async () => {
33
36
  fs.copySync(path.join(__dirname, '..', 'config'), pwd);
34
37
  const options = Object.keys(argv).reduce((opts, key) => {
35
- if (key !== '_') {
38
+ if (key !== '_' && key !== 'deploy' && key !== 'commit') {
36
39
  // eslint-disable-next-line no-param-reassign
37
40
  opts += ` --${key} ${argv[key]}`;
38
41
  }
@@ -53,5 +56,39 @@ export default async () => {
53
56
  if (argv._.includes('deploy')) {
54
57
  return $firebase('deploy');
55
58
  }
59
+ if (argv._.includes('login')) {
60
+ await $firebase('login');
61
+ return login();
62
+ }
63
+ if (argv._.includes('setup')) {
64
+ const { storeId, authenticationId, apiKey } = await login();
65
+ fs.writeFileSync(path.join(pwd, 'functions', 'config.json'), JSON.stringify({ storeId }, null, 2));
66
+ fs.writeFileSync(path.join(pwd, 'functions', '.env'), `ECOM_AUTHENTICATION_ID=${authenticationId}\nECOM_API_KEY=${apiKey}\n`);
67
+ if (argv.deploy !== false) {
68
+ await $firebase('deploy');
69
+ }
70
+ if (argv.commit !== false) {
71
+ try {
72
+ await $`git add .firebaserc functions/config.json`;
73
+ await $`git commit -m "Setup store [skip ci]"`;
74
+ await $`git push`;
75
+ } catch (e) {
76
+ //
77
+ }
78
+ }
79
+ return echo`
80
+ ****
81
+
82
+ Finish by saving the following secrets to your GitHub repository:
83
+
84
+ ${chalk.bold('ECOM_AUTHENTICATION_ID')} = ${chalk.bgMagenta(authenticationId)}
85
+
86
+ ${chalk.bold('ECOM_API_KEY')} = ${chalk.bgMagenta(apiKey)}
87
+
88
+ ${chalk.bold('FIREBASE_SERVICE_ACCOUNT')} = {YOUR_SERVICE_ACCOUNT_JSON}
89
+
90
+ -- More info at https://github.com/ecomplus/store#getting-started
91
+ `;
92
+ }
56
93
  return $`echo 'Hello from @cloudcommerce/cli'`;
57
94
  };
@@ -0,0 +1,41 @@
1
+ import * as readline from 'node:readline';
2
+ import { question, echo, fetch } from 'zx';
3
+ import md5 from 'md5';
4
+ import api from '@cloudcommerce/api';
5
+ import createAuth from './create-auth.js';
6
+
7
+ export default async () => {
8
+ await echo`-- Login with your E-Com Plus store admin account.
9
+ (i) same credentials used to enter the dashboard (https://ecomplus.app/)
10
+ `;
11
+ const username = await question('E-Com Plus username: ');
12
+ const passMd5 = await new Promise((resolve) => {
13
+ const rl = readline.createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout,
16
+ });
17
+ rl.stdoutMuted = true;
18
+ rl.question('Password: ', (password) => {
19
+ rl.close();
20
+ rl.history = rl.history.slice(1);
21
+ resolve(md5(password));
22
+ });
23
+ rl._writeToOutput = function _writeToOutput(stringToWrite) {
24
+ if (rl.stdoutMuted) {
25
+ rl.output.write('*');
26
+ } else {
27
+ rl.output.write(stringToWrite);
28
+ }
29
+ };
30
+ });
31
+ const apiConfig = {
32
+ fetch,
33
+ };
34
+ const { data: login } = await api.post('login', {
35
+ username,
36
+ pass_md5_hash: passMd5,
37
+ }, apiConfig);
38
+ const storeId = login.store_ids[0];
39
+ const { data: { access_token: accessToken } } = await api.post('authenticate', login, apiConfig);
40
+ return createAuth(storeId, accessToken);
41
+ };
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@cloudcommerce/cli",
3
3
  "type": "module",
4
- "version": "0.0.26",
4
+ "version": "0.0.29",
5
5
  "description": "E-Com Plus Cloud Commerce CLI tools",
6
6
  "bin": {
7
7
  "cloudcommerce": "./bin/run.mjs"
8
8
  },
9
9
  "main": "lib/index.js",
10
+ "exports": {
11
+ ".": "./lib/index.js",
12
+ "./create-auth": "./create-auth.js"
13
+ },
10
14
  "repository": {
11
15
  "type": "git",
12
16
  "url": "git+https://github.com/ecomplus/cloud-commerce.git",
@@ -22,6 +26,8 @@
22
26
  "build": "sh ../../scripts/build-lib.sh"
23
27
  },
24
28
  "dependencies": {
29
+ "@cloudcommerce/api": "workspace:*",
30
+ "md5": "^2.3.0",
25
31
  "zx": "^7.0.7"
26
32
  }
27
33
  }
@@ -0,0 +1,53 @@
1
+ import { fetch } from 'zx';
2
+ import api from '@cloudcommerce/api';
3
+
4
+ const defaultAgent = {
5
+ name: 'Cloud Commerce default agent',
6
+ email: 'cloudcommerce-noreply@e-com.plus',
7
+ };
8
+
9
+ export default async (storeId: number, accessToken: string) => {
10
+ const apiConfig = {
11
+ storeId,
12
+ accessToken,
13
+ fetch: fetch as Window['fetch'],
14
+ };
15
+ const { data } = await api.get('authentications', {
16
+ ...apiConfig,
17
+ params: {
18
+ email: defaultAgent.email,
19
+ limit: 1,
20
+ },
21
+ });
22
+
23
+ let authenticationId = data.result[0]?._id;
24
+ if (!authenticationId) {
25
+ const { data: { _id } } = await api.post('authentications', {
26
+ ...defaultAgent,
27
+ username: `cloudcomm${Date.now()}`,
28
+ permissions: {
29
+ applications: ['all'],
30
+ brands: ['GET'],
31
+ carts: ['all'],
32
+ categories: ['GET'],
33
+ collections: ['GET'],
34
+ customers: ['all'],
35
+ grids: ['GET'],
36
+ orders: ['GET', 'POST', 'PATCH'],
37
+ products: ['GET', 'PATCH'],
38
+ stores: ['GET'],
39
+ },
40
+ }, apiConfig);
41
+ authenticationId = _id;
42
+ }
43
+
44
+ const { data: apiKey } = await api.get(
45
+ `authentications/${authenticationId}/api_key`,
46
+ apiConfig,
47
+ ) as { data: string };
48
+ return {
49
+ storeId,
50
+ authenticationId,
51
+ apiKey,
52
+ };
53
+ };
@@ -1,6 +1,13 @@
1
1
  import url from 'url';
2
2
  import path from 'path';
3
- import { $, argv, fs } from 'zx';
3
+ import {
4
+ $,
5
+ argv,
6
+ fs,
7
+ echo,
8
+ chalk,
9
+ } from 'zx';
10
+ import login from './login';
4
11
 
5
12
  const {
6
13
  FIREBASE_PROJECT_ID,
@@ -41,7 +48,7 @@ export default async () => {
41
48
  fs.copySync(path.join(__dirname, '..', 'config'), pwd);
42
49
 
43
50
  const options = Object.keys(argv).reduce((opts, key) => {
44
- if (key !== '_') {
51
+ if (key !== '_' && key !== 'deploy' && key !== 'commit') {
45
52
  // eslint-disable-next-line no-param-reassign
46
53
  opts += ` --${key} ${argv[key]}`;
47
54
  }
@@ -63,5 +70,48 @@ export default async () => {
63
70
  if (argv._.includes('deploy')) {
64
71
  return $firebase('deploy');
65
72
  }
73
+
74
+ if (argv._.includes('login')) {
75
+ await $firebase('login');
76
+ return login();
77
+ }
78
+
79
+ if (argv._.includes('setup')) {
80
+ const { storeId, authenticationId, apiKey } = await login();
81
+ fs.writeFileSync(
82
+ path.join(pwd, 'functions', 'config.json'),
83
+ JSON.stringify({ storeId }, null, 2),
84
+ );
85
+ fs.writeFileSync(
86
+ path.join(pwd, 'functions', '.env'),
87
+ `ECOM_AUTHENTICATION_ID=${authenticationId}\nECOM_API_KEY=${apiKey}\n`,
88
+ );
89
+ if (argv.deploy !== false) {
90
+ await $firebase('deploy');
91
+ }
92
+ if (argv.commit !== false) {
93
+ try {
94
+ await $`git add .firebaserc functions/config.json`;
95
+ await $`git commit -m "Setup store [skip ci]"`;
96
+ await $`git push`;
97
+ } catch (e) {
98
+ //
99
+ }
100
+ }
101
+ return echo`
102
+ ****
103
+
104
+ Finish by saving the following secrets to your GitHub repository:
105
+
106
+ ${chalk.bold('ECOM_AUTHENTICATION_ID')} = ${chalk.bgMagenta(authenticationId)}
107
+
108
+ ${chalk.bold('ECOM_API_KEY')} = ${chalk.bgMagenta(apiKey)}
109
+
110
+ ${chalk.bold('FIREBASE_SERVICE_ACCOUNT')} = {YOUR_SERVICE_ACCOUNT_JSON}
111
+
112
+ -- More info at https://github.com/ecomplus/store#getting-started
113
+ `;
114
+ }
115
+
66
116
  return $`echo 'Hello from @cloudcommerce/cli'`;
67
117
  };
@@ -0,0 +1,48 @@
1
+ import * as readline from 'node:readline';
2
+ import { question, echo, fetch } from 'zx';
3
+ import md5 from 'md5';
4
+ import api from '@cloudcommerce/api';
5
+ import createAuth from './create-auth';
6
+
7
+ export default async () => {
8
+ await echo`-- Login with your E-Com Plus store admin account.
9
+ (i) same credentials used to enter the dashboard (https://ecomplus.app/)
10
+ `;
11
+ const username = await question('E-Com Plus username: ');
12
+ const passMd5 = await new Promise((resolve) => {
13
+ const rl = readline.createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout,
16
+ }) as any;
17
+ rl.stdoutMuted = true;
18
+ rl.question('Password: ', (password) => {
19
+ rl.close();
20
+ rl.history = rl.history.slice(1);
21
+ resolve(md5(password));
22
+ });
23
+ rl._writeToOutput = function _writeToOutput(stringToWrite) {
24
+ if (rl.stdoutMuted) {
25
+ rl.output.write('*');
26
+ } else {
27
+ rl.output.write(stringToWrite);
28
+ }
29
+ };
30
+ });
31
+
32
+ const apiConfig = {
33
+ fetch: fetch as Window['fetch'],
34
+ };
35
+ const { data: login } = await api.post('login', {
36
+ username,
37
+ pass_md5_hash: passMd5,
38
+ }, apiConfig);
39
+ const storeId = login.store_ids[0];
40
+
41
+ const {
42
+ data: {
43
+ access_token: accessToken,
44
+ },
45
+ } = await api.post('authenticate', login, apiConfig);
46
+
47
+ return createAuth(storeId, accessToken);
48
+ };
@@ -7,15 +7,20 @@ import config from './config.js';
7
7
  const options = {
8
8
  region: process.env.DEPLOY_REGION || 'us-east1',
9
9
  };
10
+ const processId = String(Date.now());
10
11
 
11
- export const z = onRequest(options, (request, response) => {
12
- if (request.url === '/hello') {
12
+ export const z = onRequest(options, ({ url }, response) => {
13
+ if (url === '/hello') {
13
14
  logger.info('Hello logs!', {
14
15
  structuredData: true,
15
16
  });
16
17
  response.send(config.get().hello);
17
18
  return;
18
19
  }
20
+ if (url === '/pid') {
21
+ response.send(processId);
22
+ return;
23
+ }
19
24
  response.send({
20
25
  config: config.get(),
21
26
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,gCAAgC,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,gDAAgD;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,MAAM,MAAM,UAAU,CAAC;AAE9B,MAAM,OAAO,GAAG;IACd,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,UAAU;CAChD,CAAC;AAEF,MAAM,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;IACxD,IAAI,OAAO,CAAC,GAAG,KAAK,QAAQ,EAAE;QAC5B,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE;YACzB,cAAc,EAAE,IAAI;SACrB,CAAC,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;QAClC,OAAO;KACR;IACD,QAAQ,CAAC,IAAI,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE;KACrB,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;IAC1D,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;AACvC,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,gCAAgC,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,gDAAgD;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,MAAM,MAAM,UAAU,CAAC;AAE9B,MAAM,OAAO,GAAG;IACd,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,UAAU;CAChD,CAAC;AAEF,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;AAErC,MAAM,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,EAAE;IACxD,IAAI,GAAG,KAAK,QAAQ,EAAE;QACpB,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE;YACzB,cAAc,EAAE,IAAI;SACrB,CAAC,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;QAClC,OAAO;KACR;IACD,IAAI,GAAG,KAAK,MAAM,EAAE;QAClB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzB,OAAO;KACR;IACD,QAAQ,CAAC,IAAI,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE;KACrB,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;IAC1D,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;AACvC,CAAC,CAAC,CAAC"}