@ordergroove/smi-serve 1.7.3 → 1.7.4
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 +11 -0
- package/__mocks__/fs/promises.js +2 -0
- package/__mocks__/fs.js +2 -0
- package/jest.config.js +7 -0
- package/package.json +6 -3
- package/smi-serve.js +4 -2
- package/smi-serve.spec.js +118 -0
- package/src/auth.js +3 -99
- package/src/deploy.js +3 -3
- package/src/init.js +9 -8
- package/src/login.js +102 -0
- package/src/serve.js +14 -12
- package/src/utils.js +12 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.7.4](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.7.3...@ordergroove/smi-serve@1.7.4) (2024-04-22)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* use cwd when constructing filepaths ([9dd0743](https://github.com/ordergroove/plush-toys/commit/9dd0743ade2daad9deb0f0c551162db4c52d6f03))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## [1.7.3](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.7.2...@ordergroove/smi-serve@1.7.3) (2024-04-19)
|
|
7
18
|
|
|
8
19
|
|
package/__mocks__/fs.js
ADDED
package/jest.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ordergroove/smi-serve",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.4",
|
|
4
4
|
"description": "Utility to serve a SMI template locally",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "Eugenio Lattanzio <eugenio.lattanzio@ordergroove.com>",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"url": "git+https://github.com/ordergroove/plush-toys.git"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"test": "
|
|
14
|
+
"test": "../../node_modules/.bin/jest"
|
|
15
15
|
},
|
|
16
16
|
"bugs": {
|
|
17
17
|
"url": "https://github.com/ordergroove/plush-toys/issues"
|
|
@@ -32,5 +32,8 @@
|
|
|
32
32
|
"ora": "^5.4.1",
|
|
33
33
|
"yargs": "^17.7.2"
|
|
34
34
|
},
|
|
35
|
-
"
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"memfs": "^4.8.2"
|
|
37
|
+
},
|
|
38
|
+
"gitHead": "150aa71aa473d76c6738352fafef37970aab7e36"
|
|
36
39
|
}
|
package/smi-serve.js
CHANGED
|
@@ -25,7 +25,7 @@ ${text
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
async function initOrServe(args) {
|
|
28
|
-
const files = await glob(`${getcwd()}/**/*.*`, { ignore: ['**/node_modules/**', 'node_modules/**'] });
|
|
28
|
+
const files = await glob(`${getcwd(args)}/**/*.*`, { ignore: ['**/node_modules/**', 'node_modules/**'] });
|
|
29
29
|
const mainLiquid = files.find(it => it.includes('main.liquid'));
|
|
30
30
|
if (!mainLiquid) {
|
|
31
31
|
const { initialize } = await inquirer.prompt([
|
|
@@ -82,7 +82,7 @@ try force fetch by using -f modifier
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
async function program() {
|
|
85
|
-
yargs(hideBin(process.argv))
|
|
85
|
+
return yargs(hideBin(process.argv))
|
|
86
86
|
.command({
|
|
87
87
|
command: 'select-merchant',
|
|
88
88
|
describe: 'Select a different Ordergroove merchant',
|
|
@@ -167,3 +167,5 @@ async function program() {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
if (require.main === module) program();
|
|
170
|
+
|
|
171
|
+
module.exports = program;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// mock Node fs to be in memory
|
|
2
|
+
jest.mock('fs');
|
|
3
|
+
jest.mock('fs/promises');
|
|
4
|
+
const { vol } = require('memfs');
|
|
5
|
+
|
|
6
|
+
// mock all fetch calls
|
|
7
|
+
jest.mock('node-fetch', () => require('fetch-mock').sandbox());
|
|
8
|
+
const fetchMock = require('node-fetch');
|
|
9
|
+
|
|
10
|
+
// don't run local dev server logic
|
|
11
|
+
jest.mock('./src/serve');
|
|
12
|
+
// mock login function to return a mock token
|
|
13
|
+
jest.mock('./src/login', () => ({
|
|
14
|
+
...jest.requireActual('./src/login'),
|
|
15
|
+
login: jest.fn().mockReturnValue(Promise.resolve('mock-auth'))
|
|
16
|
+
}));
|
|
17
|
+
jest.mock('./src/utils', () => ({
|
|
18
|
+
...jest.requireActual('./src/utils'),
|
|
19
|
+
exec: jest.fn() // don't attempt to spawn new processes
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
const smiServe = require('./smi-serve');
|
|
23
|
+
|
|
24
|
+
function runCommand(command) {
|
|
25
|
+
// the first two args don't matter, but it sends the correct number of CLI args
|
|
26
|
+
process.argv = ['node', 'smi-serve.js', ...command.split(' ')];
|
|
27
|
+
return smiServe();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('smi-serve', () => {
|
|
31
|
+
let originalArgv;
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
// wipe mock filesystem
|
|
35
|
+
vol.fromJSON({}, '/');
|
|
36
|
+
originalArgv = process.argv;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
afterEach(() => {
|
|
40
|
+
process.argv = originalArgv;
|
|
41
|
+
fetchMock.reset();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('inits with expected files', async () => {
|
|
45
|
+
fetchMock.get('https://rc3.ordergroove.com/api/merchants/', mockSingleMerchantResponse());
|
|
46
|
+
fetchMock.get('https://rc3.ordergroove.com/configs/msi/?merchant_public_id=yum-id', mockMSIConfig());
|
|
47
|
+
|
|
48
|
+
await runCommand('init --cwd / -y');
|
|
49
|
+
|
|
50
|
+
const files = vol.toJSON();
|
|
51
|
+
for (const file of Object.keys(files)) {
|
|
52
|
+
if (file.endsWith('.json')) {
|
|
53
|
+
files[file] = JSON.parse(files[file]);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
expect(files).toEqual({
|
|
57
|
+
'/.gitignore': '.ogrc.json\nnode_modules/\n',
|
|
58
|
+
'/.ogrc.json': {
|
|
59
|
+
prod: {
|
|
60
|
+
token: 'mock-auth'
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
'/package.json': {
|
|
64
|
+
author: '',
|
|
65
|
+
description: 'Ordergroove SMI for test merchant on shopify platform (yum-id)}',
|
|
66
|
+
keywords: ['Ordergroove SMI', 'test merchant', 'yum-id'],
|
|
67
|
+
main: 'views/main.liquid',
|
|
68
|
+
ordergroove: {
|
|
69
|
+
coreVersion: '0.31.6',
|
|
70
|
+
templatesVersion: '0.40.1'
|
|
71
|
+
},
|
|
72
|
+
scripts: {
|
|
73
|
+
deploy: 'smi-serve deploy',
|
|
74
|
+
start: 'smi-serve'
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
'/styles/main.less': '* { color: red; }',
|
|
78
|
+
'/views/main.liquid': '<h1>Hello world</h1>'
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
function mockSingleMerchantResponse() {
|
|
84
|
+
return [
|
|
85
|
+
{
|
|
86
|
+
name: 'test merchant',
|
|
87
|
+
public_id: 'yum-id',
|
|
88
|
+
ecommerce_platform: 'shopify'
|
|
89
|
+
}
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function mockMSIConfig() {
|
|
94
|
+
return {
|
|
95
|
+
configs: {
|
|
96
|
+
smi: {
|
|
97
|
+
files: [
|
|
98
|
+
{
|
|
99
|
+
name: '/views/main.liquid',
|
|
100
|
+
content: '<h1>Hello world</h1>'
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: '/styles/main.less',
|
|
104
|
+
content: '* { color: red; }'
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
provisioned_with: {
|
|
109
|
+
'@ordergroove/smi-templates': '0.40.1'
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
meta_fields: {
|
|
113
|
+
dependencies: {
|
|
114
|
+
'@ordergroove/smi-core': '0.31.6'
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
package/src/auth.js
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
const http = require('http');
|
|
2
1
|
const inquirer = require('inquirer');
|
|
3
2
|
const inquirerPrompt = require('inquirer-autocomplete-prompt');
|
|
4
3
|
|
|
5
|
-
const {
|
|
4
|
+
const { readRcEnv, writeRcEnv, isValidToken } = require('./utils');
|
|
5
|
+
const { login, getRC3Url } = require('./login');
|
|
6
6
|
|
|
7
7
|
inquirer.registerPrompt('autocomplete', inquirerPrompt);
|
|
8
8
|
|
|
9
|
-
function getRC3Url({ env }) {
|
|
10
|
-
if (env.startsWith('st')) return `https://rc3.stg.ordergroove.com/`;
|
|
11
|
-
if (env.startsWith('l')) return `http://0.0.0.0:3000/`;
|
|
12
|
-
return `https://rc3.ordergroove.com/`;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
exports.getRC3Url = getRC3Url;
|
|
16
|
-
|
|
17
9
|
async function getValidLoginAndCurrentMerchant(args) {
|
|
18
10
|
const existingSettings = await readRcEnv(args);
|
|
19
11
|
let token, merchant;
|
|
@@ -35,92 +27,4 @@ async function getValidLoginAndCurrentMerchant(args) {
|
|
|
35
27
|
}
|
|
36
28
|
exports.getValidLoginAndCurrentMerchant = getValidLoginAndCurrentMerchant;
|
|
37
29
|
|
|
38
|
-
|
|
39
|
-
/* eslint-disable no-async-promise-executor */
|
|
40
|
-
return await new Promise(async (resolveAuth, rejectAuth) => {
|
|
41
|
-
const port = await getNetFreePort();
|
|
42
|
-
|
|
43
|
-
let server;
|
|
44
|
-
|
|
45
|
-
const sockets = new Set();
|
|
46
|
-
/**
|
|
47
|
-
* Forcefully terminates HTTP server.
|
|
48
|
-
*/
|
|
49
|
-
const terminateServer = () => {
|
|
50
|
-
clearTimeout(authRejectTimeout);
|
|
51
|
-
return new Promise((resolve, reject) => {
|
|
52
|
-
[...sockets].forEach(socket => {
|
|
53
|
-
socket.destroy();
|
|
54
|
-
sockets.delete(socket);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
server.close(err => {
|
|
58
|
-
process.nextTick(() => {
|
|
59
|
-
if (err) {
|
|
60
|
-
reject(err);
|
|
61
|
-
} else {
|
|
62
|
-
resolve();
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
async function requestListener(req, res) {
|
|
70
|
-
if (req.method === 'POST' && req.headers['content-type'] === 'application/x-www-form-urlencoded') {
|
|
71
|
-
let body = '';
|
|
72
|
-
|
|
73
|
-
req.on('data', chunk => {
|
|
74
|
-
body += chunk.toString();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
req.on('end', async () => {
|
|
78
|
-
const params = new URLSearchParams(body);
|
|
79
|
-
const token = params.get('token');
|
|
80
|
-
|
|
81
|
-
if (!isValidToken(token)) {
|
|
82
|
-
res.writeHead(400);
|
|
83
|
-
res.end('Invalid request\n');
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
resolveAuth(token);
|
|
88
|
-
|
|
89
|
-
res.writeHead(302, { Location: getRC3Url(args) });
|
|
90
|
-
res.end();
|
|
91
|
-
await terminateServer();
|
|
92
|
-
});
|
|
93
|
-
} else {
|
|
94
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
95
|
-
res.end('Invalid request\n');
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
server = http.createServer(requestListener);
|
|
100
|
-
server.on('connection', socket => {
|
|
101
|
-
sockets.add(socket);
|
|
102
|
-
|
|
103
|
-
server.once('close', () => {
|
|
104
|
-
sockets.delete(socket);
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
server.listen(port, '127.0.0.1', () => {
|
|
109
|
-
const loginUrl = `${getRC3Url(args)}?${new URLSearchParams([
|
|
110
|
-
['login_redirect', `http://localhost:${port}`],
|
|
111
|
-
['sm_local_dev', 'true']
|
|
112
|
-
])}`;
|
|
113
|
-
console.log('A browser window has been opened to Ordergroove. Please log in through your browser to continue.');
|
|
114
|
-
console.log(`Browsing ${loginUrl}`);
|
|
115
|
-
open(loginUrl);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// terminate the program after 5 minutes waiting for auth.
|
|
119
|
-
const authRejectTimeout = setTimeout(
|
|
120
|
-
() => {
|
|
121
|
-
rejectAuth(new Error('Auth timeout'));
|
|
122
|
-
},
|
|
123
|
-
5 * 60 * 1000
|
|
124
|
-
);
|
|
125
|
-
});
|
|
126
|
-
}
|
|
30
|
+
exports.getRC3Url = getRC3Url;
|
package/src/deploy.js
CHANGED
|
@@ -63,11 +63,11 @@ async function deploy(args) {
|
|
|
63
63
|
'**/package-lock.json'
|
|
64
64
|
];
|
|
65
65
|
|
|
66
|
-
const files = await glob(`${getcwd()}/**/*.*`, { ignore: ignoreFiles });
|
|
66
|
+
const files = await glob(`${getcwd(args)}/**/*.*`, { ignore: ignoreFiles });
|
|
67
67
|
|
|
68
68
|
const fileList = await Promise.all(
|
|
69
69
|
files.map(async file => ({
|
|
70
|
-
name: file.substring(getcwd().length),
|
|
70
|
+
name: file.substring(getcwd(args).length),
|
|
71
71
|
content: await fs.promises.readFile(file, 'utf8')
|
|
72
72
|
}))
|
|
73
73
|
);
|
|
@@ -90,7 +90,7 @@ async function deploy(args) {
|
|
|
90
90
|
console.log(err);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
const packageJson = readPackageJson();
|
|
93
|
+
const packageJson = readPackageJson(getcwd(args));
|
|
94
94
|
const smiTemplatesVersion = packageJson[packageJsonKeys.OG_SECTION]?.[packageJsonKeys.TEMPLATES_VERSION];
|
|
95
95
|
|
|
96
96
|
const newRequest = {
|
package/src/init.js
CHANGED
|
@@ -46,7 +46,7 @@ async function updateJsonFile(filename, config) {
|
|
|
46
46
|
await fs.promises.writeFile(filename, JSON.stringify(original, null, 4), { encoding: 'utf8' });
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
const downloadAndExtract = async url => {
|
|
49
|
+
const downloadAndExtract = async (url, args) => {
|
|
50
50
|
try {
|
|
51
51
|
console.log(`Downloading ZIP file from ${url}`);
|
|
52
52
|
const response = await fetch(url);
|
|
@@ -54,7 +54,7 @@ const downloadAndExtract = async url => {
|
|
|
54
54
|
if (!response.ok) {
|
|
55
55
|
throw new Error(`Failed to download ZIP file. Status code: ${response.status}`);
|
|
56
56
|
}
|
|
57
|
-
const cwd = getcwd();
|
|
57
|
+
const cwd = getcwd(args);
|
|
58
58
|
const zipFileName = path.basename(url);
|
|
59
59
|
const zipFilePath = path.join(cwd, zipFileName);
|
|
60
60
|
|
|
@@ -62,7 +62,7 @@ const downloadAndExtract = async url => {
|
|
|
62
62
|
|
|
63
63
|
console.log('ZIP file downloaded successfully');
|
|
64
64
|
|
|
65
|
-
await unzip(zipFilePath,
|
|
65
|
+
await unzip(zipFilePath, cwd);
|
|
66
66
|
} catch (error) {
|
|
67
67
|
console.error('Error:', error.message);
|
|
68
68
|
}
|
|
@@ -117,7 +117,7 @@ async function init(args) {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
(msiConfigs.smi.files || []).forEach(({ content, name }) => {
|
|
120
|
-
const filepath =
|
|
120
|
+
const filepath = path.join(args.cwd, name);
|
|
121
121
|
fs.mkdirSync(path.dirname(filepath), { recursive: true });
|
|
122
122
|
fs.writeFileSync(filepath, content, { encoding: 'utf8' });
|
|
123
123
|
});
|
|
@@ -129,7 +129,8 @@ async function init(args) {
|
|
|
129
129
|
smiTemplateVersion = await getMerchantTemplatesVersion(smiVersion);
|
|
130
130
|
|
|
131
131
|
await downloadAndExtract(
|
|
132
|
-
`https://static.ordergroove.com/@ordergroove/smi-templates/${smiTemplateVersion}/dist/smi-template.zip
|
|
132
|
+
`https://static.ordergroove.com/@ordergroove/smi-templates/${smiTemplateVersion}/dist/smi-template.zip`,
|
|
133
|
+
args
|
|
133
134
|
);
|
|
134
135
|
}
|
|
135
136
|
|
|
@@ -169,14 +170,14 @@ export const auth_config = ${JSON.stringify(auth_config)};
|
|
|
169
170
|
|
|
170
171
|
// write a .gitignore just in case
|
|
171
172
|
fs.writeFileSync(
|
|
172
|
-
'.gitignore',
|
|
173
|
+
path.join(args.cwd, '.gitignore'),
|
|
173
174
|
`\
|
|
174
175
|
${OG_RC_FILE}
|
|
175
176
|
node_modules/
|
|
176
177
|
`
|
|
177
178
|
);
|
|
178
179
|
|
|
179
|
-
await updateJsonFile('package.json', {
|
|
180
|
+
await updateJsonFile(path.join(args.cwd, 'package.json'), {
|
|
180
181
|
scripts: {
|
|
181
182
|
start: 'smi-serve',
|
|
182
183
|
deploy: 'smi-serve deploy'
|
|
@@ -192,7 +193,7 @@ node_modules/
|
|
|
192
193
|
});
|
|
193
194
|
|
|
194
195
|
// initialize it as npm package
|
|
195
|
-
await exec('npm', 'init', '-y');
|
|
196
|
+
await exec(args.cwd, 'npm', 'init', '-y');
|
|
196
197
|
|
|
197
198
|
// install used smi-serve to allow dev
|
|
198
199
|
// await exec('npm', 'install', '--save-dev', '@ordergroove/smi-serve');
|
package/src/login.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const http = require('http');
|
|
2
|
+
const { open, getNetFreePort, isValidToken } = require('./utils');
|
|
3
|
+
|
|
4
|
+
async function login(args) {
|
|
5
|
+
/* eslint-disable no-async-promise-executor */
|
|
6
|
+
return await new Promise(async (resolveAuth, rejectAuth) => {
|
|
7
|
+
const port = await getNetFreePort();
|
|
8
|
+
|
|
9
|
+
let server;
|
|
10
|
+
|
|
11
|
+
const sockets = new Set();
|
|
12
|
+
/**
|
|
13
|
+
* Forcefully terminates HTTP server.
|
|
14
|
+
*/
|
|
15
|
+
const terminateServer = () => {
|
|
16
|
+
clearTimeout(authRejectTimeout);
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
[...sockets].forEach(socket => {
|
|
19
|
+
socket.destroy();
|
|
20
|
+
sockets.delete(socket);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
server.close(err => {
|
|
24
|
+
process.nextTick(() => {
|
|
25
|
+
if (err) {
|
|
26
|
+
reject(err);
|
|
27
|
+
} else {
|
|
28
|
+
resolve();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
async function requestListener(req, res) {
|
|
36
|
+
if (req.method === 'POST' && req.headers['content-type'] === 'application/x-www-form-urlencoded') {
|
|
37
|
+
let body = '';
|
|
38
|
+
|
|
39
|
+
req.on('data', chunk => {
|
|
40
|
+
body += chunk.toString();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
req.on('end', async () => {
|
|
44
|
+
const params = new URLSearchParams(body);
|
|
45
|
+
const token = params.get('token');
|
|
46
|
+
|
|
47
|
+
if (!isValidToken(token)) {
|
|
48
|
+
res.writeHead(400);
|
|
49
|
+
res.end('Invalid request\n');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
resolveAuth(token);
|
|
54
|
+
|
|
55
|
+
res.writeHead(302, { Location: getRC3Url(args) });
|
|
56
|
+
res.end();
|
|
57
|
+
await terminateServer();
|
|
58
|
+
});
|
|
59
|
+
} else {
|
|
60
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
61
|
+
res.end('Invalid request\n');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
server = http.createServer(requestListener);
|
|
66
|
+
server.on('connection', socket => {
|
|
67
|
+
sockets.add(socket);
|
|
68
|
+
|
|
69
|
+
server.once('close', () => {
|
|
70
|
+
sockets.delete(socket);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
server.listen(port, '127.0.0.1', () => {
|
|
75
|
+
const loginUrl = `${getRC3Url(args)}?${new URLSearchParams([
|
|
76
|
+
['login_redirect', `http://localhost:${port}`],
|
|
77
|
+
['sm_local_dev', 'true']
|
|
78
|
+
])}`;
|
|
79
|
+
console.log('A browser window has been opened to Ordergroove. Please log in through your browser to continue.');
|
|
80
|
+
console.log(`Browsing ${loginUrl}`);
|
|
81
|
+
open(loginUrl);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// terminate the program after 5 minutes waiting for auth.
|
|
85
|
+
const authRejectTimeout = setTimeout(
|
|
86
|
+
() => {
|
|
87
|
+
rejectAuth(new Error('Auth timeout'));
|
|
88
|
+
},
|
|
89
|
+
5 * 60 * 1000
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
exports.login = login;
|
|
95
|
+
|
|
96
|
+
function getRC3Url({ env }) {
|
|
97
|
+
if (env.startsWith('st')) return `https://rc3.stg.ordergroove.com/`;
|
|
98
|
+
if (env.startsWith('l')) return `http://0.0.0.0:3000/`;
|
|
99
|
+
return `https://rc3.ordergroove.com/`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
exports.getRC3Url = getRC3Url;
|
package/src/serve.js
CHANGED
|
@@ -20,7 +20,7 @@ async function getGlobals(argv) {
|
|
|
20
20
|
hmacAuth = customer && [customer.merchant_user_id, customer.ts, customer.hash].join('|');
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const packageJson = readPackageJson();
|
|
23
|
+
const packageJson = readPackageJson(getcwd(argv));
|
|
24
24
|
const smiCoreVersion = packageJson[packageJsonKeys.OG_SECTION]?.[packageJsonKeys.CORE_VERSION] || 'latest';
|
|
25
25
|
|
|
26
26
|
return {
|
|
@@ -31,20 +31,21 @@ async function getGlobals(argv) {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const smiDevModePlugin = globals => {
|
|
34
|
+
const smiDevModePlugin = (globals, args) => {
|
|
35
|
+
const cwd = getcwd(args);
|
|
35
36
|
/** @type {import('esbuild').Plugin} */
|
|
36
37
|
const plugin = {
|
|
37
38
|
name: 'resolve_smi_templates',
|
|
38
39
|
setup(build) {
|
|
39
40
|
build.onLoad({ filter: /main\.liquid/ }, async () => {
|
|
40
41
|
// load only liquid,js,json files (less files are handled by lessPlugin)
|
|
41
|
-
const files = await glob(`${
|
|
42
|
+
const files = await glob(`${cwd}/**/*.{liquid,json,js}`, {
|
|
42
43
|
ignore: ['**/node_modules/**', 'node_modules/**']
|
|
43
44
|
});
|
|
44
45
|
|
|
45
46
|
const fileList = await Promise.all(
|
|
46
47
|
files.map(async file => ({
|
|
47
|
-
name: file.substring(
|
|
48
|
+
name: file.substring(cwd.length),
|
|
48
49
|
content: await fs.promises.readFile(file, 'utf8').catch(() => '')
|
|
49
50
|
}))
|
|
50
51
|
);
|
|
@@ -77,7 +78,7 @@ const smiDevModePlugin = globals => {
|
|
|
77
78
|
build.onResolve({ filter: /^~\// }, args => {
|
|
78
79
|
return build.resolve(args.path.replace('~/', './'), {
|
|
79
80
|
kind: 'import-statement',
|
|
80
|
-
resolveDir:
|
|
81
|
+
resolveDir: cwd
|
|
81
82
|
});
|
|
82
83
|
});
|
|
83
84
|
}
|
|
@@ -96,9 +97,10 @@ async function serve(argv) {
|
|
|
96
97
|
throw new Error('main.liquid not found, please create a main.liquid file under src/views/main.liquid');
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
const cwd = getcwd(argv);
|
|
101
|
+
fs.mkdirSync(path.join(cwd, outdir), { recursive: true });
|
|
100
102
|
|
|
101
|
-
const smiIndexFile = path.join(
|
|
103
|
+
const smiIndexFile = path.join(cwd, outdir, 'index.html');
|
|
102
104
|
const smiIndexSource = fs.readFileSync(`${__dirname}/partials/index.html`, 'utf8');
|
|
103
105
|
fs.writeFileSync(smiIndexFile, smiIndexSource, { encoding: 'utf8' });
|
|
104
106
|
|
|
@@ -110,7 +112,7 @@ async function serve(argv) {
|
|
|
110
112
|
entryNames: '[name]',
|
|
111
113
|
|
|
112
114
|
logLevel: verbose ? 'verbose' : 'error',
|
|
113
|
-
nodePaths: [path.join(
|
|
115
|
+
nodePaths: [path.join(cwd, 'node_modules')],
|
|
114
116
|
format: 'esm',
|
|
115
117
|
globalName: 'smiTemplate',
|
|
116
118
|
loader: {
|
|
@@ -120,8 +122,8 @@ async function serve(argv) {
|
|
|
120
122
|
legalComments: 'none',
|
|
121
123
|
sourcemap: true,
|
|
122
124
|
|
|
123
|
-
outdir: path.join(
|
|
124
|
-
plugins: [smiDevModePlugin(globals), lessLoader()]
|
|
125
|
+
outdir: path.join(cwd, outdir),
|
|
126
|
+
plugins: [smiDevModePlugin(globals, argv), lessLoader()]
|
|
125
127
|
};
|
|
126
128
|
|
|
127
129
|
if (!mainLess) {
|
|
@@ -133,7 +135,7 @@ async function serve(argv) {
|
|
|
133
135
|
await ctx.watch();
|
|
134
136
|
|
|
135
137
|
const { port: actualPort, host: actualHost } = await ctx.serve({
|
|
136
|
-
servedir: path.join(
|
|
138
|
+
servedir: path.join(cwd, outdir),
|
|
137
139
|
// host,
|
|
138
140
|
port
|
|
139
141
|
});
|
|
@@ -149,7 +151,7 @@ async function serve(argv) {
|
|
|
149
151
|
const text = await esbuild.analyzeMetafile(result.metafile, {
|
|
150
152
|
verbose: true
|
|
151
153
|
});
|
|
152
|
-
fs.writeFileSync(path.join(
|
|
154
|
+
fs.writeFileSync(path.join(cwd, outdir, 'bundle-report.html'), `<pre id="esbuild-metadata">${text}</pre>`);
|
|
153
155
|
|
|
154
156
|
return result;
|
|
155
157
|
}
|
package/src/utils.js
CHANGED
|
@@ -10,8 +10,8 @@ const fetch = require('node-fetch');
|
|
|
10
10
|
|
|
11
11
|
exports.glob = util.promisify(require('glob'));
|
|
12
12
|
|
|
13
|
-
function getcwd() {
|
|
14
|
-
return process.cwd();
|
|
13
|
+
function getcwd(argv) {
|
|
14
|
+
return path.join(process.cwd(), argv.cwd);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
exports.getcwd = getcwd;
|
|
@@ -50,9 +50,11 @@ exports.open = function open(loginUrl) {
|
|
|
50
50
|
* @param {...any} args
|
|
51
51
|
* @returns
|
|
52
52
|
*/
|
|
53
|
-
exports.exec = async function exec(cmd, ...args) {
|
|
53
|
+
exports.exec = async function exec(cwd, cmd, ...args) {
|
|
54
54
|
return new Promise((resolve, reject) => {
|
|
55
|
-
const child = spawn(cmd, args
|
|
55
|
+
const child = spawn(cmd, args, {
|
|
56
|
+
cwd
|
|
57
|
+
});
|
|
56
58
|
const stdout = '';
|
|
57
59
|
const stderr = '';
|
|
58
60
|
|
|
@@ -94,9 +96,10 @@ exports.unzip = async function unzip(zipFilePath, outdir) {
|
|
|
94
96
|
};
|
|
95
97
|
|
|
96
98
|
async function readRc(args) {
|
|
97
|
-
|
|
99
|
+
const configPath = path.join(args.cwd, args.configFile);
|
|
100
|
+
if (fs.existsSync(configPath)) {
|
|
98
101
|
try {
|
|
99
|
-
const source = await fs.promises.readFile(
|
|
102
|
+
const source = await fs.promises.readFile(configPath, 'utf8');
|
|
100
103
|
return JSON.parse(source);
|
|
101
104
|
} catch (err) {
|
|
102
105
|
console.error(err);
|
|
@@ -114,7 +117,7 @@ exports.readRcEnv = readRcEnv;
|
|
|
114
117
|
|
|
115
118
|
async function writeRc(args, settings) {
|
|
116
119
|
await fs.promises.writeFile(
|
|
117
|
-
args.configFile,
|
|
120
|
+
path.join(args.cwd, args.configFile),
|
|
118
121
|
JSON.stringify(
|
|
119
122
|
{
|
|
120
123
|
...(await readRc(args)),
|
|
@@ -134,9 +137,9 @@ async function writeRcEnv(args, settings) {
|
|
|
134
137
|
|
|
135
138
|
exports.writeRcEnv = writeRcEnv;
|
|
136
139
|
|
|
137
|
-
function readPackageJson() {
|
|
140
|
+
function readPackageJson(cwd) {
|
|
138
141
|
try {
|
|
139
|
-
const packageJson = fs.readFileSync(path.join(
|
|
142
|
+
const packageJson = fs.readFileSync(path.join(cwd, 'package.json'), 'utf8');
|
|
140
143
|
return JSON.parse(packageJson);
|
|
141
144
|
} catch {
|
|
142
145
|
return {};
|