@youcan/cli-kit 1.1.0-beta.0 → 1.1.0-beta.2
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/dist/common/string.d.ts +1 -0
- package/dist/common/string.js +10 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +15 -0
- package/dist/internal/node/constants.d.ts +3 -2
- package/dist/internal/node/constants.js +4 -3
- package/dist/node/callback.d.ts +5 -0
- package/dist/node/callback.js +58 -0
- package/dist/node/config.d.ts +20 -0
- package/dist/node/config.js +27 -0
- package/dist/node/context/local.js +2 -2
- package/dist/node/crypto.d.ts +9 -0
- package/dist/node/crypto.js +28 -0
- package/dist/node/env.d.ts +6 -0
- package/dist/node/env.js +51 -0
- package/dist/node/filesystem.d.ts +20 -0
- package/dist/node/filesystem.js +66 -2
- package/dist/node/form.d.ts +9 -0
- package/dist/node/form.js +45 -0
- package/dist/node/http.d.ts +3 -0
- package/dist/node/http.js +51 -0
- package/dist/node/path.d.ts +2 -0
- package/dist/node/path.js +7 -1
- package/dist/node/session.d.ts +8 -0
- package/dist/node/session.js +105 -0
- package/dist/node/system.d.ts +4 -0
- package/dist/node/system.js +18 -1
- package/dist/node/tasks.d.ts +1 -1
- package/dist/node/tasks.js +8 -7
- package/package.json +18 -3
package/dist/common/string.d.ts
CHANGED
package/dist/common/string.js
CHANGED
|
@@ -2,6 +2,15 @@ import { paramCase } from 'change-case';
|
|
|
2
2
|
|
|
3
3
|
function hyphenate(value) {
|
|
4
4
|
return paramCase(value);
|
|
5
|
+
}
|
|
6
|
+
function isJson(subject) {
|
|
7
|
+
try {
|
|
8
|
+
JSON.parse(subject);
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
5
14
|
}
|
|
6
15
|
|
|
7
|
-
export { hyphenate };
|
|
16
|
+
export { hyphenate, isJson };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
export * as Cli from './node/cli';
|
|
2
2
|
export * as Git from './node/git';
|
|
3
|
+
export * as Env from './node/env';
|
|
3
4
|
export * as Path from './node/path';
|
|
5
|
+
export * as Http from './node/http';
|
|
6
|
+
export * as Form from './node/form';
|
|
4
7
|
export * as Tasks from './node/tasks';
|
|
5
8
|
export * as Github from './node/github';
|
|
6
9
|
export * as System from './node/system';
|
|
10
|
+
export * as Config from './node/config';
|
|
11
|
+
export * as Crypto from './node/crypto';
|
|
12
|
+
export * as Session from './node/session';
|
|
13
|
+
export * as Callback from './node/callback';
|
|
7
14
|
export * as Filesystem from './node/filesystem';
|
|
8
15
|
export * as String from './common/string';
|
|
16
|
+
export { default as Color } from 'kleur';
|
package/dist/index.js
CHANGED
|
@@ -2,15 +2,30 @@ import * as cli from './node/cli.js';
|
|
|
2
2
|
export { cli as Cli };
|
|
3
3
|
import * as git from './node/git.js';
|
|
4
4
|
export { git as Git };
|
|
5
|
+
import * as env from './node/env.js';
|
|
6
|
+
export { env as Env };
|
|
5
7
|
import * as path from './node/path.js';
|
|
6
8
|
export { path as Path };
|
|
9
|
+
import * as http from './node/http.js';
|
|
10
|
+
export { http as Http };
|
|
11
|
+
import * as form from './node/form.js';
|
|
12
|
+
export { form as Form };
|
|
7
13
|
import * as tasks from './node/tasks.js';
|
|
8
14
|
export { tasks as Tasks };
|
|
9
15
|
import * as github from './node/github.js';
|
|
10
16
|
export { github as Github };
|
|
11
17
|
import * as system from './node/system.js';
|
|
12
18
|
export { system as System };
|
|
19
|
+
import * as config from './node/config.js';
|
|
20
|
+
export { config as Config };
|
|
21
|
+
import * as crypto from './node/crypto.js';
|
|
22
|
+
export { crypto as Crypto };
|
|
23
|
+
import * as session from './node/session.js';
|
|
24
|
+
export { session as Session };
|
|
25
|
+
import * as callback from './node/callback.js';
|
|
26
|
+
export { callback as Callback };
|
|
13
27
|
import * as filesystem from './node/filesystem.js';
|
|
14
28
|
export { filesystem as Filesystem };
|
|
15
29
|
import * as string from './common/string.js';
|
|
16
30
|
export { string as String };
|
|
31
|
+
export { default as Color } from 'kleur';
|
|
@@ -7,8 +7,9 @@ function cachedir() {
|
|
|
7
7
|
}
|
|
8
8
|
return envpaths(identifier).cache;
|
|
9
9
|
}
|
|
10
|
-
const
|
|
11
|
-
|
|
10
|
+
const ENV_VARS = {
|
|
11
|
+
ENV: 'YC_CLI_ENV',
|
|
12
|
+
HOST_ENV: 'YC_CLI_HOST_ENV',
|
|
12
13
|
};
|
|
13
14
|
|
|
14
|
-
export {
|
|
15
|
+
export { ENV_VARS, cachedir };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
|
|
3
|
+
class CallbackListener {
|
|
4
|
+
port;
|
|
5
|
+
host;
|
|
6
|
+
server;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.port = options.port;
|
|
9
|
+
this.host = options.host;
|
|
10
|
+
this.server = this.create(options.callback);
|
|
11
|
+
}
|
|
12
|
+
start() {
|
|
13
|
+
this.server.listen({ port: this.port, host: this.host }, () => { });
|
|
14
|
+
}
|
|
15
|
+
stop() {
|
|
16
|
+
this.server.close();
|
|
17
|
+
}
|
|
18
|
+
create(callback) {
|
|
19
|
+
const server = async (request, response) => {
|
|
20
|
+
const respond = async (contents, error, state, code) => {
|
|
21
|
+
response.write(contents);
|
|
22
|
+
response.end();
|
|
23
|
+
return callback(this, error, state, code);
|
|
24
|
+
};
|
|
25
|
+
const query = new URL(request.url, `http://${request.headers.host}`).searchParams;
|
|
26
|
+
if (!query.has('code')) {
|
|
27
|
+
return respond('missing code in authorization callback');
|
|
28
|
+
}
|
|
29
|
+
if (!query.has('state')) {
|
|
30
|
+
return respond('missing state in authorization callback');
|
|
31
|
+
}
|
|
32
|
+
return respond('Successfully authenticated, you can now close this window.', undefined, query.get('code'), query.get('state'));
|
|
33
|
+
};
|
|
34
|
+
return createServer(server);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function listen(command, host, port, url) {
|
|
38
|
+
return await new Promise((resolve, reject) => {
|
|
39
|
+
const timeout = setTimeout(() => {
|
|
40
|
+
command.output.info('Auto-open timed out, click below to open the login page:');
|
|
41
|
+
command.output.url('Log in to YouCan Partners', url);
|
|
42
|
+
}, 10_000);
|
|
43
|
+
const callback = (listener, error, code, state) => {
|
|
44
|
+
clearTimeout(timeout);
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
listener.stop();
|
|
47
|
+
if (error) {
|
|
48
|
+
return reject(error);
|
|
49
|
+
}
|
|
50
|
+
return resolve({ code: code, state: state });
|
|
51
|
+
}, 500);
|
|
52
|
+
};
|
|
53
|
+
const listener = new CallbackListener({ host, port, callback });
|
|
54
|
+
listener.start();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { listen };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
declare class Manager<T extends {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
}> {
|
|
4
|
+
private readonly store;
|
|
5
|
+
constructor(options: {
|
|
6
|
+
projectName?: string;
|
|
7
|
+
cwd?: string;
|
|
8
|
+
});
|
|
9
|
+
get<TKey extends keyof T>(key: TKey): T[TKey];
|
|
10
|
+
set<TKey extends keyof T>(key: TKey, value?: T[TKey]): void;
|
|
11
|
+
delete<TKey extends keyof T>(key: TKey): void;
|
|
12
|
+
clear(): void;
|
|
13
|
+
}
|
|
14
|
+
export declare function manager(options: {
|
|
15
|
+
projectName?: string;
|
|
16
|
+
cwd?: string;
|
|
17
|
+
}): Manager<{
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}>;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
4
|
+
/** @ts-expect-error */
|
|
5
|
+
class Manager {
|
|
6
|
+
store;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.store = new Conf(options);
|
|
9
|
+
}
|
|
10
|
+
get(key) {
|
|
11
|
+
return this.store.get(key);
|
|
12
|
+
}
|
|
13
|
+
set(key, value) {
|
|
14
|
+
this.store.set(key, value);
|
|
15
|
+
}
|
|
16
|
+
delete(key) {
|
|
17
|
+
this.store.delete(key);
|
|
18
|
+
}
|
|
19
|
+
clear() {
|
|
20
|
+
this.store.clear();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function manager(options) {
|
|
24
|
+
return new Manager(options);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { manager };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ENV_VARS } from '../../internal/node/constants.js';
|
|
2
2
|
|
|
3
3
|
function isDevelopment(env = process.env) {
|
|
4
|
-
return env[
|
|
4
|
+
return env[ENV_VARS.ENV] === 'development';
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export { isDevelopment };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export declare function randomHex(size: number): string;
|
|
3
|
+
export declare function base64URLEncode(str: Buffer): string;
|
|
4
|
+
export declare function sha256(str: string): Buffer;
|
|
5
|
+
export declare function sha1(str: Buffer | string): string;
|
|
6
|
+
export declare function hashString(str: string): string;
|
|
7
|
+
export declare function fileHash(buff: Buffer): string;
|
|
8
|
+
export declare function randomBytes(size: number): Buffer;
|
|
9
|
+
export declare function randomUUID(): string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
function randomHex(size) {
|
|
4
|
+
return crypto.randomBytes(size).toString('hex');
|
|
5
|
+
}
|
|
6
|
+
function base64URLEncode(str) {
|
|
7
|
+
return str.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/[=]/g, '');
|
|
8
|
+
}
|
|
9
|
+
function sha256(str) {
|
|
10
|
+
return crypto.createHash('sha256').update(str).digest();
|
|
11
|
+
}
|
|
12
|
+
function sha1(str) {
|
|
13
|
+
return crypto.createHash('sha1').update(str).digest('hex');
|
|
14
|
+
}
|
|
15
|
+
function hashString(str) {
|
|
16
|
+
return crypto.createHash('sha1').update(str).digest('hex');
|
|
17
|
+
}
|
|
18
|
+
function fileHash(buff) {
|
|
19
|
+
return crypto.createHash('md5').update(buff).digest('hex');
|
|
20
|
+
}
|
|
21
|
+
function randomBytes(size) {
|
|
22
|
+
return crypto.randomBytes(size);
|
|
23
|
+
}
|
|
24
|
+
function randomUUID() {
|
|
25
|
+
return crypto.randomUUID();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { base64URLEncode, fileHash, hashString, randomBytes, randomHex, randomUUID, sha1, sha256 };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ENV_VARS } from '@/internal/node/constants';
|
|
2
|
+
export declare function get(key: keyof typeof ENV_VARS): string;
|
|
3
|
+
export declare function oauthClientId(): string;
|
|
4
|
+
export declare function oauthClientSecret(): string;
|
|
5
|
+
export declare function sellerAreaHostname(): string;
|
|
6
|
+
export declare function apiHostname(): string;
|
package/dist/node/env.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ENV_VARS } from '../internal/node/constants.js';
|
|
2
|
+
|
|
3
|
+
function get(key) {
|
|
4
|
+
return process.env[ENV_VARS[key]];
|
|
5
|
+
}
|
|
6
|
+
function oauthClientId() {
|
|
7
|
+
switch (get('HOST_ENV')) {
|
|
8
|
+
case 'dev':
|
|
9
|
+
return '3';
|
|
10
|
+
case 'test':
|
|
11
|
+
return '8';
|
|
12
|
+
case 'prod':
|
|
13
|
+
default:
|
|
14
|
+
return '8';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function oauthClientSecret() {
|
|
18
|
+
switch (get('HOST_ENV')) {
|
|
19
|
+
case 'dev':
|
|
20
|
+
return 'kvvtjXFCeuvvNX2nwD30SAfh7DMbVXm16E0MPCTu';
|
|
21
|
+
case 'test':
|
|
22
|
+
return '8';
|
|
23
|
+
case 'prod':
|
|
24
|
+
default:
|
|
25
|
+
return 'lvUw2mQ7nXp4WqZ9CZlURMgRGAra3KuOrYhFlU7X';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function sellerAreaHostname() {
|
|
29
|
+
switch (get('HOST_ENV')) {
|
|
30
|
+
case 'dev':
|
|
31
|
+
return 'seller-area.dotshop.com';
|
|
32
|
+
case 'test':
|
|
33
|
+
return 'seller-area.testyoucan.shop';
|
|
34
|
+
case 'prod':
|
|
35
|
+
default:
|
|
36
|
+
return 'seller-area.youcan.shop';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function apiHostname() {
|
|
40
|
+
switch (get('HOST_ENV')) {
|
|
41
|
+
case 'dev':
|
|
42
|
+
return 'api.dotshop.com';
|
|
43
|
+
case 'test':
|
|
44
|
+
return 'api.testyoucan.shop';
|
|
45
|
+
case 'prod':
|
|
46
|
+
default:
|
|
47
|
+
return 'api.youcan.shop';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { apiHostname, get, oauthClientId, oauthClientSecret, sellerAreaHostname };
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import type { Mode, OpenMode, PathLike } from 'fs';
|
|
4
|
+
import type { Options as GlobOptions, Pattern } from 'fast-glob';
|
|
5
|
+
import chokidar from 'chokidar';
|
|
1
6
|
export declare function exists(path: string): Promise<boolean>;
|
|
2
7
|
export declare function tapIntoTmp<T>(callback: (tmp: string) => T | Promise<T>): Promise<T>;
|
|
3
8
|
export declare function mkdir(path: string): Promise<void>;
|
|
@@ -5,4 +10,19 @@ interface MoveFileOptions {
|
|
|
5
10
|
overwrite?: boolean;
|
|
6
11
|
}
|
|
7
12
|
export declare function move(src: string, dest: string, options?: MoveFileOptions): Promise<void>;
|
|
13
|
+
export declare function readFile(path: PathLike, options?: {
|
|
14
|
+
encoding?: BufferEncoding;
|
|
15
|
+
flag?: OpenMode;
|
|
16
|
+
}): Promise<Buffer | string>;
|
|
17
|
+
export declare function writeFile(path: PathLike, data: string, options?: {
|
|
18
|
+
encoding: BufferEncoding;
|
|
19
|
+
flag: Mode;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
export declare function readJsonFile<T = Record<string, unknown>>(path: PathLike): Promise<T>;
|
|
22
|
+
export declare function writeJsonFile(path: PathLike, data: Record<string, unknown>): Promise<void>;
|
|
23
|
+
export declare function glob(pattern: Pattern | Pattern[], options?: GlobOptions): Promise<string[]>;
|
|
24
|
+
export declare function archived(path: string, name: string): Promise<string>;
|
|
25
|
+
export declare function unlink(path: string): Promise<void>;
|
|
26
|
+
export declare function readdir(path: string): Promise<string[]>;
|
|
27
|
+
export declare const watch: typeof chokidar.watch;
|
|
8
28
|
export {};
|
package/dist/node/filesystem.js
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
import FilesystemPromises from 'node:fs/promises';
|
|
2
|
+
import { createWriteStream } from 'node:fs';
|
|
2
3
|
import { temporaryDirectoryTask } from 'tempy';
|
|
3
4
|
import FsExtra from 'fs-extra';
|
|
5
|
+
import archiver from 'archiver';
|
|
6
|
+
import chokidar from 'chokidar';
|
|
7
|
+
import './cli.js';
|
|
8
|
+
import 'simple-git';
|
|
9
|
+
import 'execa';
|
|
10
|
+
import 'tcp-port-used';
|
|
11
|
+
import 'find-process';
|
|
12
|
+
import 'env-paths';
|
|
13
|
+
import { resolve } from './path.js';
|
|
14
|
+
import 'node-fetch';
|
|
15
|
+
import 'ramda';
|
|
16
|
+
import 'change-case';
|
|
17
|
+
import 'formdata-node';
|
|
18
|
+
import 'formdata-node/file-from-path';
|
|
19
|
+
import 'kleur';
|
|
20
|
+
import 'conf';
|
|
4
21
|
|
|
5
22
|
async function exists(path) {
|
|
6
23
|
try {
|
|
@@ -19,6 +36,53 @@ async function mkdir(path) {
|
|
|
19
36
|
}
|
|
20
37
|
async function move(src, dest, options = {}) {
|
|
21
38
|
await FsExtra.move(src, dest, options);
|
|
22
|
-
}
|
|
39
|
+
}
|
|
40
|
+
async function readFile(path, options = { encoding: 'utf-8', flag: 'r' }) {
|
|
41
|
+
return await FilesystemPromises.readFile(path, options);
|
|
42
|
+
}
|
|
43
|
+
async function writeFile(path, data, options = { encoding: 'utf-8', flag: 'w' }) {
|
|
44
|
+
return await FilesystemPromises.writeFile(path, data, options);
|
|
45
|
+
}
|
|
46
|
+
async function readJsonFile(path) {
|
|
47
|
+
const file = await readFile(path);
|
|
48
|
+
return JSON.parse(file instanceof Buffer ? file.toString() : file);
|
|
49
|
+
}
|
|
50
|
+
async function writeJsonFile(path, data) {
|
|
51
|
+
return writeFile(path, JSON.stringify(data, null, 4));
|
|
52
|
+
}
|
|
53
|
+
async function glob(pattern, options) {
|
|
54
|
+
const { default: _glob } = await import('fast-glob');
|
|
55
|
+
let _options = options;
|
|
56
|
+
if (options?.dot == null) {
|
|
57
|
+
_options = { ...options, dot: true };
|
|
58
|
+
}
|
|
59
|
+
return _glob(pattern, _options);
|
|
60
|
+
}
|
|
61
|
+
async function archived(path$1, name) {
|
|
62
|
+
return new Promise((resolve$1, reject) => {
|
|
63
|
+
try {
|
|
64
|
+
const archivePath = resolve(path$1, `${name}.zip`);
|
|
65
|
+
const output = createWriteStream(archivePath);
|
|
66
|
+
const _archiver = archiver('zip', { zlib: { level: 9 } });
|
|
67
|
+
output.on('close', () => resolve$1(archivePath));
|
|
68
|
+
_archiver.on('error', () => (err) => reject(err));
|
|
69
|
+
_archiver.pipe(output);
|
|
70
|
+
_archiver.directory(resolve(path$1, name), false);
|
|
71
|
+
_archiver.finalize();
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
reject(err);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
async function unlink(path) {
|
|
79
|
+
if (await exists(path)) {
|
|
80
|
+
await FilesystemPromises.unlink(path);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function readdir(path) {
|
|
84
|
+
return await FilesystemPromises.readdir(path);
|
|
85
|
+
}
|
|
86
|
+
const watch = chokidar.watch;
|
|
23
87
|
|
|
24
|
-
export { exists, mkdir, move, tapIntoTmp };
|
|
88
|
+
export { archived, exists, glob, mkdir, move, readFile, readJsonFile, readdir, tapIntoTmp, unlink, watch, writeFile, writeJsonFile };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { FormData } from 'formdata-node';
|
|
3
|
+
import type { FormDataEntryValue } from 'formdata-node';
|
|
4
|
+
import { fileFromPath } from 'formdata-node/file-from-path';
|
|
5
|
+
export type FormDataResolvable = Array<FormDataResolvable> | {
|
|
6
|
+
[key: string]: FormDataResolvable;
|
|
7
|
+
} | FormDataEntryValue | undefined | boolean | number | Blob | Date | null;
|
|
8
|
+
export declare const file: typeof fileFromPath;
|
|
9
|
+
export declare function convert(source: Record<string, FormDataResolvable>, form?: FormData, parentKey?: string | null): FormData;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { FormData, File } from 'formdata-node';
|
|
2
|
+
import { fileFromPath } from 'formdata-node/file-from-path';
|
|
3
|
+
|
|
4
|
+
const file = fileFromPath;
|
|
5
|
+
function convert(source, form = new FormData(), parentKey = null) {
|
|
6
|
+
source = source || {};
|
|
7
|
+
for (const key in source) {
|
|
8
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
9
|
+
append(form, toKey(parentKey, key), source[key]);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return form;
|
|
13
|
+
}
|
|
14
|
+
function append(form, key, value) {
|
|
15
|
+
if (Array.isArray(value)) {
|
|
16
|
+
return Array.from(value.keys()).forEach(index => append(form, toKey(key, index.toString()), value[index]));
|
|
17
|
+
}
|
|
18
|
+
else if (value instanceof Date) {
|
|
19
|
+
return form.append(key, value.toISOString());
|
|
20
|
+
}
|
|
21
|
+
else if (value instanceof File) {
|
|
22
|
+
return form.append(key, value, value.name);
|
|
23
|
+
}
|
|
24
|
+
else if (value instanceof Blob) {
|
|
25
|
+
return form.append(key, value);
|
|
26
|
+
}
|
|
27
|
+
else if (typeof value === 'boolean') {
|
|
28
|
+
return form.append(key, value ? '1' : '0');
|
|
29
|
+
}
|
|
30
|
+
else if (typeof value === 'string') {
|
|
31
|
+
return form.append(key, value);
|
|
32
|
+
}
|
|
33
|
+
else if (typeof value === 'number') {
|
|
34
|
+
return form.append(key, `${value}`);
|
|
35
|
+
}
|
|
36
|
+
else if (value === null || value === undefined) {
|
|
37
|
+
return form.append(key, '');
|
|
38
|
+
}
|
|
39
|
+
convert(value, form, key);
|
|
40
|
+
}
|
|
41
|
+
function toKey(parent, key) {
|
|
42
|
+
return parent ? `${parent}[${key}]` : key;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { convert, file };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fetch from 'node-fetch';
|
|
2
|
+
import { is, mergeDeepLeft } from 'ramda';
|
|
3
|
+
import './cli.js';
|
|
4
|
+
import 'simple-git';
|
|
5
|
+
import 'execa';
|
|
6
|
+
import 'tcp-port-used';
|
|
7
|
+
import 'find-process';
|
|
8
|
+
import { get as get$1 } from './env.js';
|
|
9
|
+
import 'formdata-node';
|
|
10
|
+
import 'formdata-node/file-from-path';
|
|
11
|
+
import 'kleur';
|
|
12
|
+
import 'conf';
|
|
13
|
+
import { get as get$2 } from './session.js';
|
|
14
|
+
import './filesystem.js';
|
|
15
|
+
import { isJson } from '../common/string.js';
|
|
16
|
+
|
|
17
|
+
function scheme() {
|
|
18
|
+
return get$1('HOST_ENV') === 'dev' ? 'http' : 'https';
|
|
19
|
+
}
|
|
20
|
+
async function agent() {
|
|
21
|
+
const { Agent } = await import(scheme());
|
|
22
|
+
return new Agent({ keepAlive: true, keepAliveMsecs: 5 * 60 * 1000 });
|
|
23
|
+
}
|
|
24
|
+
async function defaults() {
|
|
25
|
+
const session$1 = await get$2();
|
|
26
|
+
return {
|
|
27
|
+
agent: await agent(),
|
|
28
|
+
headers: {
|
|
29
|
+
Accept: 'application/json',
|
|
30
|
+
Authorization: session$1 ? `Bearer ${session$1.access_token}` : undefined,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
async function request(endpoint, options = {}) {
|
|
35
|
+
if (is(String)(options.body) && isJson(options.body)) {
|
|
36
|
+
options = mergeDeepLeft(options, { headers: { 'Content-Type': 'application/json' } });
|
|
37
|
+
}
|
|
38
|
+
const response = await fetch(endpoint, mergeDeepLeft(options, await defaults()));
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
throw new Error(await response.text(), { cause: response });
|
|
41
|
+
}
|
|
42
|
+
return response.json();
|
|
43
|
+
}
|
|
44
|
+
async function get(endpoint, options = {}) {
|
|
45
|
+
return request(`${scheme()}://${endpoint}`, { ...options, method: 'GET' });
|
|
46
|
+
}
|
|
47
|
+
async function post(endpoint, options = {}) {
|
|
48
|
+
return request(`${scheme()}://${endpoint}`, { ...options, method: 'POST' });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { get, post };
|
package/dist/node/path.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export declare function resolve(...paths: string[]): string;
|
|
2
2
|
export declare function cwd(): string;
|
|
3
3
|
export declare function join(...paths: string[]): string;
|
|
4
|
+
export declare function dirname(filepath: string): string;
|
|
5
|
+
export declare function basename(filepath: string): string;
|
package/dist/node/path.js
CHANGED
|
@@ -8,6 +8,12 @@ function cwd() {
|
|
|
8
8
|
}
|
|
9
9
|
function join(...paths) {
|
|
10
10
|
return path.join(...paths);
|
|
11
|
+
}
|
|
12
|
+
function dirname(filepath) {
|
|
13
|
+
return path.dirname(filepath);
|
|
14
|
+
}
|
|
15
|
+
function basename(filepath) {
|
|
16
|
+
return path.basename(filepath);
|
|
11
17
|
}
|
|
12
18
|
|
|
13
|
-
export { cwd, join, resolve };
|
|
19
|
+
export { basename, cwd, dirname, join, resolve };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Cli } from '..';
|
|
2
|
+
export interface StoreSession {
|
|
3
|
+
id: string;
|
|
4
|
+
slug: string;
|
|
5
|
+
access_token: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function get(): Promise<StoreSession | null>;
|
|
8
|
+
export declare function authenticate(command: Cli.Command): Promise<StoreSession>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import './cli.js';
|
|
2
|
+
import 'simple-git';
|
|
3
|
+
import { isPortAvailable, getPortProcessName, killPortProcess, open } from './system.js';
|
|
4
|
+
import { apiHostname, oauthClientId, oauthClientSecret, sellerAreaHostname } from './env.js';
|
|
5
|
+
import { get as get$1, post } from './http.js';
|
|
6
|
+
import 'formdata-node';
|
|
7
|
+
import 'formdata-node/file-from-path';
|
|
8
|
+
import 'kleur';
|
|
9
|
+
import { manager } from './config.js';
|
|
10
|
+
import { randomHex } from './crypto.js';
|
|
11
|
+
import { listen } from './callback.js';
|
|
12
|
+
import './filesystem.js';
|
|
13
|
+
import 'change-case';
|
|
14
|
+
|
|
15
|
+
const LS_PORT = 3000;
|
|
16
|
+
const LS_HOST = 'localhost';
|
|
17
|
+
async function isSessionValid(session) {
|
|
18
|
+
try {
|
|
19
|
+
const store = await get$1(`${apiHostname()}/me`, { headers: { Authorization: `Bearer ${session.access_token}` } });
|
|
20
|
+
return store.is_active;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function exchange(code) {
|
|
27
|
+
const params = {
|
|
28
|
+
code,
|
|
29
|
+
client_id: oauthClientId(),
|
|
30
|
+
grant_type: 'authorization_code',
|
|
31
|
+
client_secret: oauthClientSecret(),
|
|
32
|
+
redirect_uri: `http://${LS_HOST}:${LS_PORT}/`,
|
|
33
|
+
};
|
|
34
|
+
const result = await post(`${apiHostname()}/oauth/token`, {
|
|
35
|
+
body: new URLSearchParams(Object.entries(params)),
|
|
36
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
37
|
+
});
|
|
38
|
+
return result.access_token;
|
|
39
|
+
}
|
|
40
|
+
async function authorize(command, state = randomHex(30)) {
|
|
41
|
+
const AUTHORIZATION_URL = sellerAreaHostname();
|
|
42
|
+
if (!await isPortAvailable(LS_PORT)) {
|
|
43
|
+
command.output.warn(`Port ${LS_PORT} is unavailable, but it is required for authentication.`);
|
|
44
|
+
const { confirmed } = await command.prompt({
|
|
45
|
+
type: 'confirm',
|
|
46
|
+
name: 'confirmed',
|
|
47
|
+
initial: true,
|
|
48
|
+
message: `Would you like to terminate ${await getPortProcessName(LS_PORT)}?`,
|
|
49
|
+
});
|
|
50
|
+
if (!confirmed) {
|
|
51
|
+
throw new Error('Exiting..');
|
|
52
|
+
}
|
|
53
|
+
await killPortProcess(LS_PORT);
|
|
54
|
+
}
|
|
55
|
+
const params = {
|
|
56
|
+
state,
|
|
57
|
+
response_type: 'code',
|
|
58
|
+
scope: '*',
|
|
59
|
+
client_id: oauthClientId(),
|
|
60
|
+
redirect_url: `http://${LS_HOST}:${LS_PORT}/`,
|
|
61
|
+
};
|
|
62
|
+
await command.output.anykey('Press any key to open the login page on your browser..');
|
|
63
|
+
const url = `http://${AUTHORIZATION_URL}/admin/oauth/authorize?${new URLSearchParams(params).toString()}`;
|
|
64
|
+
open(url);
|
|
65
|
+
const result = await listen(command, LS_HOST, LS_PORT, url);
|
|
66
|
+
if (result.state !== state) {
|
|
67
|
+
throw new Error('Authorization state mismatch..');
|
|
68
|
+
}
|
|
69
|
+
return result.code;
|
|
70
|
+
}
|
|
71
|
+
async function get() {
|
|
72
|
+
return manager({ projectName: 'youcan-cli' })
|
|
73
|
+
.get('store_session') ?? null;
|
|
74
|
+
}
|
|
75
|
+
async function authenticate(command) {
|
|
76
|
+
const existingSession = manager({ projectName: 'youcan-cli' })
|
|
77
|
+
.get('store_session');
|
|
78
|
+
if (existingSession && await isSessionValid(existingSession)) {
|
|
79
|
+
return existingSession;
|
|
80
|
+
}
|
|
81
|
+
const accessToken = await exchange(await authorize(command));
|
|
82
|
+
const { stores } = await get$1(`${apiHostname()}/stores`, { headers: { Authorization: `Bearer ${accessToken}` } });
|
|
83
|
+
const active = stores.filter(s => s.is_active);
|
|
84
|
+
if (!active.length) {
|
|
85
|
+
throw new Error('No active stores found');
|
|
86
|
+
}
|
|
87
|
+
const { selected } = await command.prompt({
|
|
88
|
+
type: 'select',
|
|
89
|
+
name: 'selected',
|
|
90
|
+
message: 'Select a store to log into',
|
|
91
|
+
choices: active.map(s => ({ title: s.slug, value: s.store_id })),
|
|
92
|
+
});
|
|
93
|
+
const store = stores.find(s => s.store_id === selected);
|
|
94
|
+
const { token: storeAccessToken } = await post(`${apiHostname()}/switch-store/${store.store_id}`, { headers: { Authorization: `Bearer ${accessToken}` } });
|
|
95
|
+
const session = {
|
|
96
|
+
slug: store.slug,
|
|
97
|
+
id: store.store_id,
|
|
98
|
+
access_token: storeAccessToken,
|
|
99
|
+
};
|
|
100
|
+
manager({ projectName: 'youcan-cli' })
|
|
101
|
+
.set('store_session', session);
|
|
102
|
+
return session;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { authenticate, get };
|
package/dist/node/system.d.ts
CHANGED
|
@@ -15,3 +15,7 @@ export interface ExecOptions {
|
|
|
15
15
|
errorHandler?: (error: unknown) => Promise<void>;
|
|
16
16
|
}
|
|
17
17
|
export declare function exec(command: string, args: string[], options?: ExecOptions): Promise<void>;
|
|
18
|
+
export declare function isPortAvailable(port: number): Promise<boolean>;
|
|
19
|
+
export declare function getPortProcessName(port: number): Promise<string>;
|
|
20
|
+
export declare function killPortProcess(port: number): Promise<void>;
|
|
21
|
+
export declare function open(url: string): Promise<void>;
|
package/dist/node/system.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { execa } from 'execa';
|
|
2
|
+
import tpu from 'tcp-port-used';
|
|
3
|
+
import findProcess from 'find-process';
|
|
2
4
|
|
|
3
5
|
function buildExec(command, args, options) {
|
|
4
6
|
const env = options?.env ?? process.env;
|
|
@@ -42,6 +44,21 @@ async function exec(command, args, options) {
|
|
|
42
44
|
}
|
|
43
45
|
throw err;
|
|
44
46
|
}
|
|
47
|
+
}
|
|
48
|
+
async function isPortAvailable(port) {
|
|
49
|
+
return !await tpu.check(port);
|
|
50
|
+
}
|
|
51
|
+
async function getPortProcessName(port) {
|
|
52
|
+
const info = await findProcess('port', port);
|
|
53
|
+
return (info && info.length > 0) ? `(${info[0]?.name})` : '';
|
|
54
|
+
}
|
|
55
|
+
async function killPortProcess(port) {
|
|
56
|
+
const { killPortProcess: kill } = await import('kill-port-process');
|
|
57
|
+
await kill(port);
|
|
58
|
+
}
|
|
59
|
+
async function open(url) {
|
|
60
|
+
const _open = await import('open');
|
|
61
|
+
await _open.default(url);
|
|
45
62
|
}
|
|
46
63
|
|
|
47
|
-
export { exec };
|
|
64
|
+
export { exec, getPortProcessName, isPortAvailable, killPortProcess, open };
|
package/dist/node/tasks.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export interface Task<T = unknown> {
|
|
|
4
4
|
skip?: (ctx: T) => boolean;
|
|
5
5
|
task: (context: T, task: Task<T>) => Promise<void | Task<T>[]>;
|
|
6
6
|
}
|
|
7
|
-
export declare function run<T = unknown>(tasks: Task[]): Promise<
|
|
7
|
+
export declare function run<T = unknown>(ctx: T, tasks: Task<T>[]): Promise<T>;
|
package/dist/node/tasks.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { exit } from 'node:process';
|
|
1
2
|
import { Loader } from '../internal/node/ui.js';
|
|
2
3
|
|
|
3
4
|
async function runTask(task, ctx) {
|
|
@@ -6,25 +7,25 @@ async function runTask(task, ctx) {
|
|
|
6
7
|
}
|
|
7
8
|
return await task.task(ctx, task);
|
|
8
9
|
}
|
|
9
|
-
async function run(tasks) {
|
|
10
|
-
const
|
|
11
|
-
for (const task of tasks) {
|
|
10
|
+
async function run(ctx, tasks) {
|
|
11
|
+
for await (const task of tasks) {
|
|
12
12
|
await Loader.exec(task.title, async (loader) => {
|
|
13
13
|
try {
|
|
14
|
-
const subtasks = await runTask(task,
|
|
14
|
+
const subtasks = await runTask(task, ctx);
|
|
15
15
|
if (Array.isArray(subtasks) && subtasks.length > 0 && subtasks.every(t => 'task' in t)) {
|
|
16
|
-
for (const subtask of subtasks) {
|
|
17
|
-
await runTask(subtask,
|
|
16
|
+
for await (const subtask of subtasks) {
|
|
17
|
+
await runTask(subtask, ctx);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
loader.stop();
|
|
21
21
|
}
|
|
22
22
|
catch (err) {
|
|
23
23
|
loader.error(String(err));
|
|
24
|
-
|
|
24
|
+
exit(1);
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
|
+
return ctx;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export { run };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@youcan/cli-kit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.1.0-beta.
|
|
4
|
+
"version": "1.1.0-beta.2",
|
|
5
5
|
"description": "Utilities for the YouCan CLI",
|
|
6
6
|
"author": "YouCan <contact@youcan.shop> (https://youcan.shop)",
|
|
7
7
|
"license": "MIT",
|
|
@@ -20,24 +20,39 @@
|
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@oclif/core": "^2.15.0",
|
|
23
|
+
"archiver": "^5.3.2",
|
|
23
24
|
"change-case": "^4.1.2",
|
|
25
|
+
"chokidar": "^3.5.3",
|
|
26
|
+
"conf": "^11.0.2",
|
|
24
27
|
"env-paths": "^3.0.0",
|
|
25
28
|
"execa": "^6.1.0",
|
|
29
|
+
"fast-glob": "^3.3.1",
|
|
30
|
+
"find-process": "^1.4.7",
|
|
31
|
+
"formdata-node": "^5.0.1",
|
|
26
32
|
"fs-extra": "^11.1.1",
|
|
33
|
+
"kill-port-process": "^3.2.0",
|
|
27
34
|
"kleur": "^4.1.5",
|
|
35
|
+
"node-fetch": "^3.3.2",
|
|
36
|
+
"open": "^9.1.0",
|
|
28
37
|
"prompts": "^2.4.2",
|
|
38
|
+
"ramda": "^0.28.0",
|
|
29
39
|
"simple-git": "^3.20.0",
|
|
30
|
-
"
|
|
40
|
+
"tcp-port-used": "^1.0.2",
|
|
41
|
+
"tempy": "^3.1.0",
|
|
42
|
+
"worker": "^0.4.0"
|
|
31
43
|
},
|
|
32
44
|
"devDependencies": {
|
|
45
|
+
"@types/archiver": "^5.3.3",
|
|
33
46
|
"@types/fs-extra": "^11.0.2",
|
|
34
47
|
"@types/node": "^18.18.0",
|
|
35
48
|
"@types/prompts": "^2.4.5",
|
|
49
|
+
"@types/ramda": "^0.28.25",
|
|
50
|
+
"@types/tcp-port-used": "^1.0.2",
|
|
36
51
|
"shx": "^0.3.4"
|
|
37
52
|
},
|
|
38
53
|
"scripts": {
|
|
39
54
|
"build": "shx rm -rf dist && tsc --noEmit && rollup --config rollup.config.js",
|
|
40
|
-
"dev": "rollup --config rollup.config.js --watch",
|
|
55
|
+
"dev": "shx rm -rf dist && rollup --config rollup.config.js --watch",
|
|
41
56
|
"release": "pnpm publish --access public",
|
|
42
57
|
"type-check": "tsc --noEmit"
|
|
43
58
|
}
|