@ohos-ports/redux-devtools-cli 5.0.0-beta.0

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 (43) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +162 -0
  3. package/app/electron.cjs +29 -0
  4. package/app/index.html +46 -0
  5. package/app/package.json +8 -0
  6. package/bin/redux-devtools.js +3 -0
  7. package/defaultDbOptions.json +7 -0
  8. package/dist/api/schema.d.ts +16 -0
  9. package/dist/api/schema.js +12 -0
  10. package/dist/api/schema_def.graphql +60 -0
  11. package/dist/bin/injectServer.d.ts +6 -0
  12. package/dist/bin/injectServer.js +78 -0
  13. package/dist/bin/openApp.d.ts +2 -0
  14. package/dist/bin/openApp.js +40 -0
  15. package/dist/bin/redux-devtools.d.ts +2 -0
  16. package/dist/bin/redux-devtools.js +73 -0
  17. package/dist/db/connector.d.ts +3 -0
  18. package/dist/db/connector.js +49 -0
  19. package/dist/db/migrations/index.d.ts +3 -0
  20. package/dist/db/migrations/index.js +84 -0
  21. package/dist/db/seeds/index.d.ts +2 -0
  22. package/dist/db/seeds/index.js +10 -0
  23. package/dist/index.d.ts +6 -0
  24. package/dist/index.js +125 -0
  25. package/dist/options.d.ts +29 -0
  26. package/dist/options.js +29 -0
  27. package/dist/routes.d.ts +5 -0
  28. package/dist/routes.js +100 -0
  29. package/dist/store.d.ts +57 -0
  30. package/dist/store.js +97 -0
  31. package/package.json +97 -0
  32. package/src/api/schema.ts +26 -0
  33. package/src/api/schema_def.graphql +60 -0
  34. package/src/bin/injectServer.ts +104 -0
  35. package/src/bin/openApp.ts +53 -0
  36. package/src/bin/redux-devtools.ts +94 -0
  37. package/src/db/connector.ts +67 -0
  38. package/src/db/migrations/index.ts +87 -0
  39. package/src/db/seeds/index.ts +12 -0
  40. package/src/index.ts +137 -0
  41. package/src/options.ts +68 -0
  42. package/src/routes.ts +144 -0
  43. package/src/store.ts +164 -0
@@ -0,0 +1,60 @@
1
+ # A list of options for the type of the report
2
+ enum ReportType {
3
+ STATE
4
+ ACTION
5
+ STATES
6
+ ACTIONS
7
+ }
8
+
9
+ type Report {
10
+ # Report ID
11
+ id: ID!
12
+ # Type of the report, can be: STATE, ACTION, STATES, ACTIONS
13
+ type: ReportType
14
+ # Briefly what happened
15
+ title: String
16
+ # Details supplied by the user
17
+ description: String
18
+ # The last dispatched action before the report was sent
19
+ action: String
20
+ # Stringified actions or the state or both, which should be loaded the application to reproduce the exact behavior
21
+ payload: String
22
+ # Stringified preloaded state object. Could be the initial state of the app or committed state (after dispatching COMMIT action or reaching maxAge)
23
+ preloadedState: String
24
+ # Screenshot url or blob as a string
25
+ screenshot: String
26
+ # User Agent String
27
+ userAgent: String
28
+ # Application version to group the reports and versioning
29
+ version: String
30
+ # Used to identify the user who sent the report
31
+ userId: String
32
+ # More detailed data about the user, usually it's a stringified object
33
+ user: String
34
+ # Everything else you want to send
35
+ meta: String
36
+ # Error message which invoked sending the report
37
+ exception: String
38
+ # Id to identify the store in case there are multiple stores
39
+ instanceId: String
40
+ # Timestamp when the report was added
41
+ added: String
42
+ # Id to identify the application (from apps table)
43
+ appId: ID
44
+ }
45
+
46
+ # Explore GraphQL query schema
47
+ type Query {
48
+ # List all reports
49
+ reports: [Report]
50
+ # Get a report by ID
51
+ report(
52
+ # Report ID
53
+ id: ID!
54
+ ): Report
55
+ }
56
+
57
+ schema {
58
+ query: Query
59
+ #mutation: Mutation
60
+ }
@@ -0,0 +1,104 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import semver from 'semver';
4
+ import type { Options } from '../options.js';
5
+
6
+ const name = '@redux-devtools/cli';
7
+ const startFlag = '/* ' + name + ' start */';
8
+ const endFlag = '/* ' + name + ' end */';
9
+ const serverFlags: { [moduleName: string]: { [version: string]: string } } = {
10
+ 'react-native': {
11
+ '0.0.1': ' _server(argv, config, resolve, reject);',
12
+ '0.31.0':
13
+ " runServer(args, config, () => console.log('\\nReact packager ready.\\n'));",
14
+ '0.44.0-rc.0': ' runServer(args, config, startedCallback, readyCallback);',
15
+ '0.46.0-rc.0':
16
+ ' runServer(runServerArgs, configT, startedCallback, readyCallback);',
17
+ '0.57.0': ' runServer(args, configT);',
18
+ },
19
+ 'react-native-desktop': {
20
+ '0.0.1': ' _server(argv, config, resolve, reject);',
21
+ },
22
+ };
23
+
24
+ function getModuleVersion(modulePath: string): string {
25
+ return JSON.parse(
26
+ fs.readFileSync(path.join(modulePath, 'package.json'), 'utf-8'),
27
+ ).version;
28
+ }
29
+
30
+ function getServerFlag(moduleName: string, version: string): string {
31
+ const flags = serverFlags[moduleName || 'react-native'];
32
+ const versions = Object.keys(flags);
33
+ let flag;
34
+ for (let i = 0; i < versions.length; i++) {
35
+ if (semver.gte(version, versions[i])) {
36
+ flag = flags[versions[i]];
37
+ }
38
+ }
39
+ return flag as string;
40
+ }
41
+
42
+ export const dir = 'local-cli/server';
43
+ export const file = 'server.js';
44
+ export const fullPath = path.join(dir, file);
45
+
46
+ export function inject(
47
+ modulePath: string,
48
+ options: Options,
49
+ moduleName: string,
50
+ ) {
51
+ const filePath = path.join(modulePath, fullPath);
52
+ if (!fs.existsSync(filePath)) return false;
53
+
54
+ const serverFlag = getServerFlag(moduleName, getModuleVersion(modulePath));
55
+ const code = [
56
+ startFlag,
57
+ ' require("' + name + '")(' + JSON.stringify(options) + ')',
58
+ ' .then(_remotedev =>',
59
+ ' _remotedev.ready.then(() => {',
60
+ ' if (!_remotedev.portAlreadyUsed) console.log("-".repeat(80));',
61
+ ' ' + serverFlag,
62
+ ' })',
63
+ ' );',
64
+ endFlag,
65
+ ].join('\n');
66
+
67
+ const serverCode = fs.readFileSync(filePath, 'utf-8');
68
+ let start = serverCode.indexOf(startFlag); // already injected ?
69
+ let end = serverCode.indexOf(endFlag) + endFlag.length;
70
+ if (start === -1) {
71
+ start = serverCode.indexOf(serverFlag);
72
+ end = start + serverFlag.length;
73
+ }
74
+ fs.writeFileSync(
75
+ filePath,
76
+ serverCode.substr(0, start) +
77
+ code +
78
+ serverCode.substr(end, serverCode.length),
79
+ );
80
+ return true;
81
+ }
82
+
83
+ export function revert(
84
+ modulePath: string,
85
+ options: Options,
86
+ moduleName: string,
87
+ ) {
88
+ const filePath = path.join(modulePath, fullPath);
89
+ if (!fs.existsSync(filePath)) return false;
90
+
91
+ const serverFlag = getServerFlag(moduleName, getModuleVersion(modulePath));
92
+ const serverCode = fs.readFileSync(filePath, 'utf-8');
93
+ const start = serverCode.indexOf(startFlag); // already injected ?
94
+ const end = serverCode.indexOf(endFlag) + endFlag.length;
95
+ if (start !== -1) {
96
+ fs.writeFileSync(
97
+ filePath,
98
+ serverCode.substr(0, start) +
99
+ serverFlag +
100
+ serverCode.substr(end, serverCode.length),
101
+ );
102
+ }
103
+ return true;
104
+ }
@@ -0,0 +1,53 @@
1
+ import open from 'open';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { createRequire } from 'module';
5
+ import spawn from 'cross-spawn';
6
+ import type { Options } from '../options.js';
7
+
8
+ const require = createRequire(import.meta.url);
9
+
10
+ export default async function openApp(app: true | string, options: Options) {
11
+ if (app === true || app === 'electron') {
12
+ try {
13
+ const port = options.port ? `--port=${options.port}` : '';
14
+ const host = options.host ? `--host=${options.host}` : '';
15
+ const protocol = options.protocol ? `--protocol=${options.protocol}` : '';
16
+
17
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
18
+ spawn(require('electron') as string, [
19
+ path.join(
20
+ path.dirname(fileURLToPath(import.meta.url)),
21
+ '..',
22
+ '..',
23
+ 'app',
24
+ ),
25
+ port,
26
+ host,
27
+ protocol,
28
+ ]);
29
+ } catch (error) {
30
+ /* eslint-disable no-console */
31
+ if ((error as Error).message === "Cannot find module 'electron'") {
32
+ // TODO: Move electron to dev-dependences to make our package installation faster when not needed.
33
+ console.log(
34
+ ' \x1b[1;31m[Warn]\x1b[0m Electron module not installed.\n',
35
+ );
36
+ /*
37
+ We will use "npm" to install Electron via "npm install -D".
38
+ Do you want to install 'electron' (yes/no): yes
39
+ Installing 'electron' (running 'npm install -D webpack-cli')...
40
+ */
41
+ } else {
42
+ console.log(error);
43
+ }
44
+ /* eslint-enable no-console */
45
+ }
46
+ return;
47
+ }
48
+
49
+ await open(
50
+ `${options.protocol}://${options.host ?? 'localhost'}:${options.port}/`,
51
+ app !== 'browser' ? { app: { name: app } } : undefined,
52
+ );
53
+ }
@@ -0,0 +1,94 @@
1
+ #! /usr/bin/env node
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import parseArgs from 'minimist';
5
+ import chalk from 'chalk';
6
+ import * as injectServer from './injectServer.js';
7
+ import getOptions from '../options.js';
8
+ import server from '../index.js';
9
+ import openApp from './openApp.js';
10
+
11
+ const argv = parseArgs(process.argv.slice(2));
12
+
13
+ const options = getOptions(argv);
14
+
15
+ function readFile(filePath: string) {
16
+ return fs.readFileSync(path.resolve(process.cwd(), filePath), 'utf-8');
17
+ }
18
+
19
+ if (argv.protocol === 'https') {
20
+ argv.key = argv.key ? readFile(argv.key as string) : null;
21
+ argv.cert = argv.cert ? readFile(argv.cert as string) : null;
22
+ }
23
+
24
+ function log(pass: boolean, msg: string) {
25
+ const prefix = pass ? chalk.green.bgBlack('PASS') : chalk.red.bgBlack('FAIL');
26
+ const color = pass ? chalk.blue : chalk.red;
27
+ console.log(prefix, color(msg)); // eslint-disable-line no-console
28
+ }
29
+
30
+ function getModuleName(type: string) {
31
+ switch (type) {
32
+ case 'macos':
33
+ return 'react-native-macos';
34
+ // react-native-macos is renamed from react-native-desktop
35
+ case 'desktop':
36
+ return 'react-native-desktop';
37
+ case 'reactnative':
38
+ default:
39
+ return 'react-native';
40
+ }
41
+ }
42
+
43
+ function getModulePath(moduleName: string) {
44
+ return path.join(process.cwd(), 'node_modules', moduleName);
45
+ }
46
+
47
+ function getModule(type: string) {
48
+ let moduleName = getModuleName(type);
49
+ let modulePath = getModulePath(moduleName);
50
+ if (type === 'desktop' && !fs.existsSync(modulePath)) {
51
+ moduleName = getModuleName('macos');
52
+ modulePath = getModulePath(moduleName);
53
+ }
54
+ return {
55
+ name: moduleName,
56
+ path: modulePath,
57
+ };
58
+ }
59
+
60
+ function injectRN(type: string, msg: string) {
61
+ const module = getModule(type);
62
+ const fn = type === 'revert' ? injectServer.revert : injectServer.inject;
63
+ const pass = fn(module.path, options, module.name);
64
+ log(
65
+ pass,
66
+ msg +
67
+ (pass
68
+ ? '.'
69
+ : ', the file `' +
70
+ path.join(module.name, injectServer.fullPath) +
71
+ '` not found.'),
72
+ );
73
+
74
+ process.exit(pass ? 0 : 1);
75
+ }
76
+
77
+ if (argv.revert) {
78
+ injectRN(
79
+ argv.revert as string,
80
+ 'Revert injection of ReduxDevTools server from React Native local server',
81
+ );
82
+ }
83
+ if (argv.injectserver) {
84
+ injectRN(
85
+ argv.injectserver as string,
86
+ 'Inject ReduxDevTools server into React Native local server',
87
+ );
88
+ }
89
+
90
+ const response = await server(argv);
91
+ if (argv.open && argv.open !== 'false') {
92
+ await response.ready;
93
+ await openApp(argv.open as string, options);
94
+ }
@@ -0,0 +1,67 @@
1
+ import path from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import knex from 'knex';
4
+ import type { Knex } from 'knex';
5
+ import { AGServer } from 'socketcluster-server';
6
+
7
+ // HarmonyOS compatibility: knex's sqlite3 dialect hardcodes require('sqlite3'),
8
+ // but on HarmonyOS the driver is published as '@ohos-ports/sqlite3'. Install a
9
+ // module resolver alias so knex resolves 'sqlite3' to the HarmonyOS driver.
10
+ import { createRequire } from 'module';
11
+ const nodeRequire = createRequire(import.meta.url);
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ const nodeModule = nodeRequire('module') as any;
14
+ const originalResolveFilename = nodeModule._resolveFilename as (
15
+ request: string,
16
+ ...args: unknown[]
17
+ ) => string;
18
+ nodeModule._resolveFilename = function (request: string, ...args: unknown[]) {
19
+ if (request === 'sqlite3') {
20
+ try {
21
+ request = nodeRequire.resolve('@ohos-ports/sqlite3');
22
+ } catch {
23
+ // driver unavailable; fall through to the original resolver
24
+ }
25
+ }
26
+ return originalResolveFilename.call(this, request, ...args);
27
+ };
28
+
29
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
30
+ type KnexFunction = <TRecord extends {} = any, TResult = unknown[]>(
31
+ config: Knex.Config | string,
32
+ ) => Knex<TRecord, TResult>;
33
+
34
+ export default function connector(options: AGServer.AGServerOptions) {
35
+ const dbOptions = options.dbOptions as Knex.Config;
36
+ dbOptions.useNullAsDefault = true;
37
+ if (!(dbOptions as any).migrate) {
38
+ return (knex as unknown as KnexFunction)(dbOptions);
39
+ }
40
+
41
+ dbOptions.migrations = {
42
+ directory: path.join(
43
+ path.dirname(fileURLToPath(import.meta.url)),
44
+ 'migrations',
45
+ ),
46
+ };
47
+ dbOptions.seeds = {
48
+ directory: path.join(path.dirname(fileURLToPath(import.meta.url)), 'seeds'),
49
+ };
50
+ const knexInstance = (knex as unknown as KnexFunction)(dbOptions);
51
+
52
+ /* eslint-disable no-console */
53
+ knexInstance.migrate
54
+ .latest({ loadExtensions: ['.js'] })
55
+ .then(function () {
56
+ return knexInstance.seed.run({ loadExtensions: ['.js'] });
57
+ })
58
+ .then(function () {
59
+ console.log(' \x1b[0;32m[Done]\x1b[0m Migrations are finished\n');
60
+ })
61
+ .catch(function (error) {
62
+ console.error(error);
63
+ });
64
+ /* eslint-enable no-console */
65
+
66
+ return knexInstance;
67
+ }
@@ -0,0 +1,87 @@
1
+ import { Knex } from 'knex';
2
+
3
+ export function up(knex: Knex) {
4
+ return Promise.all([
5
+ knex.schema.createTable('remotedev_reports', function (table) {
6
+ table.uuid('id').primary();
7
+ table.string('type');
8
+ table.string('title');
9
+ table.string('description');
10
+ table.string('action');
11
+ table.text('payload', 'longtext');
12
+ table.text('preloadedState', 'longtext');
13
+ table.text('screenshot', 'longtext');
14
+ table.string('userAgent');
15
+ table.string('version');
16
+ table.string('user');
17
+ table.string('userId');
18
+ table.string('instanceId');
19
+ table.string('meta');
20
+ table.string('exception');
21
+ table.timestamp('added').defaultTo(knex.fn.now());
22
+ table
23
+ .uuid('appId')
24
+ .references('id')
25
+ .inTable('remotedev_apps')
26
+ .onDelete('CASCADE')
27
+ .onUpdate('CASCADE')
28
+ .defaultTo('78626c31-e16b-4528-b8e5-f81301b627f4');
29
+ }),
30
+ knex.schema.createTable('remotedev_payloads', function (table) {
31
+ table.uuid('id').primary();
32
+ table.text('state');
33
+ table.text('action');
34
+ table.timestamp('added').defaultTo(knex.fn.now());
35
+ table
36
+ .uuid('reportId')
37
+ .references('id')
38
+ .inTable('remotedev_reports')
39
+ .onDelete('CASCADE')
40
+ .onUpdate('CASCADE');
41
+ }),
42
+ knex.schema.createTable('remotedev_apps', function (table) {
43
+ table.uuid('id').primary();
44
+ table.string('title');
45
+ table.string('description');
46
+ table.string('url');
47
+ table.timestamps(false, true);
48
+ }),
49
+ knex.schema.createTable('remotedev_users', function (table) {
50
+ table.uuid('id').primary();
51
+ table.string('name');
52
+ table.string('login');
53
+ table.string('email');
54
+ table.string('avatarUrl');
55
+ table.string('profileUrl');
56
+ table.string('oauthId');
57
+ table.string('oauthType');
58
+ table.string('token');
59
+ table.timestamps(false, true);
60
+ }),
61
+ knex.schema.createTable('remotedev_users_apps', function (table) {
62
+ table.boolean('readOnly').defaultTo(false);
63
+ table.uuid('userId');
64
+ table.uuid('appId');
65
+ table.primary(['userId', 'appId']);
66
+ table
67
+ .foreign('userId')
68
+ .references('id')
69
+ .inTable('remotedev_users')
70
+ .onDelete('CASCADE')
71
+ .onUpdate('CASCADE');
72
+ table
73
+ .foreign('appId')
74
+ .references('id')
75
+ .inTable('remotedev_apps')
76
+ .onDelete('CASCADE')
77
+ .onUpdate('CASCADE');
78
+ }),
79
+ ]);
80
+ }
81
+
82
+ export function down(knex: Knex) {
83
+ return Promise.all([
84
+ knex.schema.dropTable('remotedev_reports'),
85
+ knex.schema.dropTable('remotedev_apps'),
86
+ ]);
87
+ }
@@ -0,0 +1,12 @@
1
+ import { Knex } from 'knex';
2
+
3
+ export function seed(knex: Knex) {
4
+ return Promise.all([knex('remotedev_apps').del()]).then(function () {
5
+ return Promise.all([
6
+ knex('remotedev_apps').insert({
7
+ id: '78626c31-e16b-4528-b8e5-f81301b627f4',
8
+ title: 'Default',
9
+ }),
10
+ ]);
11
+ });
12
+ }
package/src/index.ts ADDED
@@ -0,0 +1,137 @@
1
+ import express from 'express';
2
+ import http from 'http';
3
+ import getPort from 'get-port';
4
+ import socketClusterServer from 'socketcluster-server';
5
+ import getOptions from './options.js';
6
+ import routes from './routes.js';
7
+ import createStore from './store.js';
8
+
9
+ // const LOG_LEVEL_NONE = 0;
10
+ // const LOG_LEVEL_ERROR = 1;
11
+ const LOG_LEVEL_WARN = 2;
12
+ const LOG_LEVEL_INFO = 3;
13
+
14
+ export default async function (argv: { [arg: string]: any }): Promise<{
15
+ portAlreadyUsed?: boolean;
16
+ ready: Promise<void>;
17
+ }> {
18
+ const options = Object.assign(getOptions(argv), {
19
+ allowClientPublish: false,
20
+ });
21
+ const port = options.port;
22
+ const logLevel =
23
+ options.logLevel === undefined ? LOG_LEVEL_INFO : options.logLevel;
24
+ // Check port already used
25
+ const p = await getPort({ port });
26
+ if (port !== p) {
27
+ if (logLevel >= LOG_LEVEL_WARN) {
28
+ console.log(`[ReduxDevTools] Server port ${port} is already used.`);
29
+ }
30
+ return {
31
+ portAlreadyUsed: true,
32
+ ready: Promise.resolve(),
33
+ };
34
+ }
35
+
36
+ if (logLevel >= LOG_LEVEL_INFO) {
37
+ console.log('[ReduxDevTools] Start server...');
38
+ console.log('-'.repeat(80) + '\n');
39
+ }
40
+ const httpServer = http.createServer();
41
+ const agServer = socketClusterServer.attach(httpServer, options);
42
+
43
+ const app = express();
44
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
45
+ httpServer.on('request', app);
46
+ const store = createStore(options);
47
+ app.use(routes(options, store, agServer));
48
+
49
+ agServer.setMiddleware(
50
+ agServer.MIDDLEWARE_INBOUND,
51
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
52
+ async (middlewareStream) => {
53
+ for await (const action of middlewareStream) {
54
+ if (action.type === action.TRANSMIT) {
55
+ const channel = action.receiver;
56
+ const data = action.data;
57
+ if (
58
+ channel.substring(0, 3) === 'sc-' ||
59
+ channel === 'respond' ||
60
+ channel === 'log'
61
+ ) {
62
+ void agServer.exchange.transmitPublish(channel, data);
63
+ } else if (channel === 'log-noid') {
64
+ void agServer.exchange.transmitPublish('log', {
65
+ id: action.socket.id,
66
+ data: data,
67
+ });
68
+ }
69
+ } else if (action.type === action.SUBSCRIBE) {
70
+ if (action.channel === 'report') {
71
+ store
72
+ .list()
73
+ .then(function (data) {
74
+ void agServer.exchange.transmitPublish('report', {
75
+ type: 'list',
76
+ data: data,
77
+ });
78
+ })
79
+ .catch(function (error) {
80
+ console.error(error);
81
+ });
82
+ }
83
+ }
84
+ action.allow();
85
+ }
86
+ },
87
+ );
88
+
89
+ void (async () => {
90
+ for await (const { socket } of agServer.listener('connection')) {
91
+ let channelToWatch: string, channelToEmit: string;
92
+ void (async () => {
93
+ for await (const request of socket.procedure('login')) {
94
+ const credentials = request.data;
95
+ if (credentials === 'master') {
96
+ channelToWatch = 'respond';
97
+ channelToEmit = 'log';
98
+ } else {
99
+ channelToWatch = 'log';
100
+ channelToEmit = 'respond';
101
+ }
102
+ request.end(channelToWatch);
103
+ }
104
+ })();
105
+ void (async () => {
106
+ for await (const request of socket.procedure('getReport')) {
107
+ const id = request.data as string;
108
+ store
109
+ .get(id)
110
+ .then(function (data) {
111
+ request.end(data);
112
+ })
113
+ .catch(function (error) {
114
+ console.error(error);
115
+ });
116
+ }
117
+ })();
118
+ void (async () => {
119
+ for await (const data of socket.listener('disconnect')) {
120
+ const channel = agServer.exchange.channel('sc-' + socket.id);
121
+ channel.unsubscribe();
122
+ void agServer.exchange.transmitPublish(channelToEmit!, {
123
+ id: socket.id,
124
+ type: 'DISCONNECTED',
125
+ });
126
+ }
127
+ })();
128
+ }
129
+ })();
130
+
131
+ httpServer.listen(options.port);
132
+ return {
133
+ ready: (async () => {
134
+ await agServer.listener('ready' as 'error').once();
135
+ })(),
136
+ };
137
+ }
package/src/options.ts ADDED
@@ -0,0 +1,68 @@
1
+ import fs from 'fs';
2
+
3
+ interface ProtocolOptions {
4
+ key: string | undefined;
5
+ cert: string | undefined;
6
+ passphrase: string | undefined;
7
+ }
8
+
9
+ interface DbOptions {
10
+ client: string;
11
+ connection: {
12
+ filename: string;
13
+ };
14
+ useNullAsDefault: boolean;
15
+ debug: boolean;
16
+ migrate: boolean;
17
+ }
18
+
19
+ export interface Options {
20
+ host: string | undefined;
21
+ port: number;
22
+ protocol: 'http' | 'https';
23
+ protocolOptions: ProtocolOptions | undefined;
24
+ dbOptions: DbOptions;
25
+ maxRequestBody: string;
26
+ logHTTPRequests?: boolean;
27
+ logLevel: 0 | 1 | 3 | 2;
28
+ wsEngine: string;
29
+ }
30
+
31
+ export default function getOptions(argv: { [arg: string]: any }): Options {
32
+ let dbOptions = argv.dbOptions;
33
+ if (typeof dbOptions === 'string') {
34
+ dbOptions = JSON.parse(fs.readFileSync(dbOptions, 'utf8'));
35
+ } else if (typeof dbOptions === 'undefined') {
36
+ dbOptions = JSON.parse(
37
+ fs.readFileSync(
38
+ new URL('../defaultDbOptions.json', import.meta.url),
39
+ 'utf8',
40
+ ),
41
+ );
42
+ }
43
+
44
+ return {
45
+ host:
46
+ argv.hostname || process.env.npm_package_remotedev_hostname || undefined,
47
+ port: Number(argv.port || process.env.npm_package_remotedev_port) || 8000,
48
+ protocol:
49
+ argv.protocol || process.env.npm_package_remotedev_protocol || 'http',
50
+ protocolOptions: !(argv.protocol === 'https')
51
+ ? undefined
52
+ : {
53
+ key: argv.key || process.env.npm_package_remotedev_key || undefined,
54
+ cert:
55
+ argv.cert || process.env.npm_package_remotedev_cert || undefined,
56
+ passphrase:
57
+ argv.passphrase ||
58
+ process.env.npm_package_remotedev_passphrase ||
59
+ undefined,
60
+ },
61
+ dbOptions: dbOptions,
62
+ maxRequestBody: argv.passphrase || '16mb',
63
+ logHTTPRequests: argv.logHTTPRequests,
64
+ logLevel: argv.logLevel || 3,
65
+ wsEngine:
66
+ argv.wsEngine || process.env.npm_package_remotedev_wsengine || 'ws',
67
+ };
68
+ }