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.
- package/CHANGELOG.md +30 -0
- package/CONTRIBUTING.md +1 -0
- package/package.json +4 -4
- package/packages/api/lib/index.d.ts +9988 -29
- package/packages/api/lib/index.js +47 -20
- package/packages/api/lib/index.js.map +1 -1
- package/packages/api/lib/types/applications.d.ts +1 -1
- package/packages/api/lib/types/authentications.d.ts +1 -1
- package/packages/api/lib/types/brands.d.ts +1 -1
- package/packages/api/lib/types/carts.d.ts +3 -3
- package/packages/api/lib/types/categories.d.ts +1 -1
- package/packages/api/lib/types/collections.d.ts +1 -1
- package/packages/api/lib/types/customers.d.ts +2 -2
- package/packages/api/lib/types/grids.d.ts +1 -1
- package/packages/api/lib/types/orders.d.ts +5 -5
- package/packages/api/lib/types/products.d.ts +2 -2
- package/packages/api/lib/types/stores.d.ts +1 -1
- package/packages/api/lib/types.d.ts +25 -8
- package/packages/api/package.json +1 -1
- package/packages/api/src/index.ts +78 -29
- package/packages/api/src/types/applications.d.ts +1 -1
- package/packages/api/src/types/authentications.d.ts +1 -1
- package/packages/api/src/types/brands.d.ts +1 -1
- package/packages/api/src/types/carts.d.ts +3 -3
- package/packages/api/src/types/categories.d.ts +1 -1
- package/packages/api/src/types/collections.d.ts +1 -1
- package/packages/api/src/types/customers.d.ts +2 -2
- package/packages/api/src/types/grids.d.ts +1 -1
- package/packages/api/src/types/orders.d.ts +5 -5
- package/packages/api/src/types/products.d.ts +2 -2
- package/packages/api/src/types/stores.d.ts +1 -1
- package/packages/api/src/types.ts +56 -17
- package/packages/api/tests/index.test.ts +16 -0
- package/packages/apps/discounts/package.json +1 -1
- package/packages/cli/create-auth.js +5 -0
- package/packages/cli/lib/create-auth.js +48 -0
- package/packages/cli/lib/index.js +39 -2
- package/packages/cli/lib/login.js +41 -0
- package/packages/cli/package.json +7 -1
- package/packages/cli/src/create-auth.ts +53 -0
- package/packages/cli/src/index.ts +52 -2
- package/packages/cli/src/login.ts +48 -0
- package/packages/firebase/lib/index.js +7 -2
- package/packages/firebase/lib/index.js.map +1 -1
- package/packages/firebase/package.json +1 -1
- package/packages/firebase/src/index.ts +8 -2
- package/packages/storefront/package.json +1 -1
- 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
|
*/
|
|
@@ -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
|
*/
|
|
@@ -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 =
|
|
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
|
|
72
|
+
type ListEndpoint<TResource extends Resource> = TResource | `${TResource}?${string}`;
|
|
73
|
+
|
|
74
|
+
type ResourceListResult<TEndpoint extends ResourceOpQuery> = {
|
|
66
75
|
result:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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' ?
|
|
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
|
|
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
|
+
});
|
|
@@ -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 {
|
|
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.
|
|
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 {
|
|
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, (
|
|
12
|
-
if (
|
|
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,
|
|
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"}
|