@basis-theory-labs/cli 1.3.2 → 1.4.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.
package/README.md CHANGED
@@ -19,7 +19,7 @@ $ npm install -g @basis-theory-labs/cli
19
19
  $ bt COMMAND
20
20
  running command...
21
21
  $ bt (--version)
22
- @basis-theory-labs/cli/1.3.2 linux-x64 node-v18.16.1
22
+ @basis-theory-labs/cli/1.4.0 linux-x64 node-v18.16.1
23
23
  $ bt --help [COMMAND]
24
24
  USAGE
25
25
  $ bt COMMAND
@@ -54,7 +54,7 @@ EXAMPLES
54
54
  $ bt proxies
55
55
  ```
56
56
 
57
- _See code: [dist/commands/proxies/index.ts](https://github.com/Basis-Theory-Labs/basistheory-cli/blob/v1.3.2/dist/commands/proxies/index.ts)_
57
+ _See code: [dist/commands/proxies/index.ts](https://github.com/Basis-Theory-Labs/basistheory-cli/blob/v1.4.0/dist/commands/proxies/index.ts)_
58
58
 
59
59
  ## `bt proxies create`
60
60
 
@@ -115,7 +115,7 @@ Updates an existing Pre-Configured Proxy. Requires `proxy:update` Management App
115
115
  ```
116
116
  USAGE
117
117
  $ bt proxies update ID -x <value> [-n <value>] [-u <value>] [-q <value>] [-s <value>] [-i <value>] [-c <value>]
118
- [-a]
118
+ [-a] [-w]
119
119
 
120
120
  ARGUMENTS
121
121
  ID Proxy id to update
@@ -129,6 +129,7 @@ FLAGS
129
129
  -q, --request-transform-code=<value> path to JavaScript file containing a Request Transform code
130
130
  -s, --response-transform-code=<value> path to JavaScript file containing a Response Transform code
131
131
  -u, --destination-url=<value> URL to which requests will be proxied
132
+ -w, --watch Watch for changes in informed files
132
133
  -x, --management-key=<value> (required) management key used for connecting with the reactor / proxy
133
134
 
134
135
  DESCRIPTION
@@ -163,7 +164,7 @@ EXAMPLES
163
164
  $ bt reactors
164
165
  ```
165
166
 
166
- _See code: [dist/commands/reactors/index.ts](https://github.com/Basis-Theory-Labs/basistheory-cli/blob/v1.3.2/dist/commands/reactors/index.ts)_
167
+ _See code: [dist/commands/reactors/index.ts](https://github.com/Basis-Theory-Labs/basistheory-cli/blob/v1.4.0/dist/commands/reactors/index.ts)_
167
168
 
168
169
  ## `bt reactors logs [ID]`
169
170
 
@@ -4,6 +4,7 @@ export default class Update extends BaseCommand {
4
4
  static description: string;
5
5
  static examples: string[];
6
6
  static flags: {
7
+ watch: import("@oclif/core/lib/interfaces/parser").BooleanFlag<boolean>;
7
8
  name: import("@oclif/core/lib/interfaces/parser").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
9
  'destination-url': import("@oclif/core/lib/interfaces/parser").OptionFlag<import("url").URL | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
10
  'request-transform-code': import("@oclif/core/lib/interfaces/parser").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
@@ -2,12 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const base_1 = require("../../base");
5
+ const files_1 = require("../../files");
5
6
  const management_1 = require("../../proxies/management");
6
7
  const utils_1 = require("../../proxies/utils");
7
8
  class Update extends base_1.BaseCommand {
8
9
  async run() {
9
10
  var _a, _b;
10
- const { bt, args: { id }, flags: { name, 'destination-url': destinationUrl, 'response-transform-code': responseTransformCode, 'request-transform-code': requestTransformCode, 'application-id': applicationId, configuration, 'require-auth': requireAuth, }, metadata, } = await this.parse(Update);
11
+ const { bt, args: { id }, flags: { name, 'destination-url': destinationUrl, 'response-transform-code': responseTransformCode, 'request-transform-code': requestTransformCode, 'application-id': applicationId, configuration, 'require-auth': requireAuth, watch, }, metadata, } = await this.parse(Update);
11
12
  const model = (0, utils_1.createModelFromFlags)({
12
13
  name,
13
14
  destinationUrl: destinationUrl === null || destinationUrl === void 0 ? void 0 : destinationUrl.toString(),
@@ -21,6 +22,25 @@ class Update extends base_1.BaseCommand {
21
22
  });
22
23
  await (0, management_1.patchProxy)(bt, id, model);
23
24
  this.log('Proxy updated successfully!');
25
+ if (watch) {
26
+ const files = [
27
+ requestTransformCode,
28
+ responseTransformCode,
29
+ configuration,
30
+ ].filter((flag) => flag);
31
+ if (files.length) {
32
+ this.log(`Watching files for changes: ${files.join(', ')} `);
33
+ }
34
+ files.forEach((file) => {
35
+ (0, files_1.watchForChanges)(file, async () => {
36
+ core_1.ux.action.start(`Detected change in ${file}. Pushing changes`);
37
+ await (0, management_1.patchProxy)(bt, id, (0, utils_1.createModelFromFlags)({
38
+ responseTransformCode,
39
+ }));
40
+ core_1.ux.action.stop('✅\t');
41
+ });
42
+ });
43
+ }
24
44
  }
25
45
  }
26
46
  exports.default = Update;
@@ -33,6 +53,12 @@ Update.examples = [
33
53
  ];
34
54
  Update.flags = {
35
55
  ...utils_1.PROXY_FLAGS,
56
+ watch: core_1.Flags.boolean({
57
+ char: 'w',
58
+ description: 'Watch for changes in informed files',
59
+ default: false,
60
+ required: false,
61
+ }),
36
62
  };
37
63
  Update.args = {
38
64
  id: core_1.Args.string({
@@ -0,0 +1,4 @@
1
+ import * as fs from 'fs';
2
+ declare const readFileContents: (filePath: string) => string;
3
+ declare const watchForChanges: (filePath: string, handler: (contents: string) => unknown) => fs.FSWatcher;
4
+ export { readFileContents, watchForChanges };
package/dist/files.js ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.watchForChanges = exports.readFileContents = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs = tslib_1.__importStar(require("fs"));
6
+ const lodash_debounce_1 = tslib_1.__importDefault(require("lodash.debounce"));
7
+ const path = tslib_1.__importStar(require("path"));
8
+ const readFileContents = (filePath) => fs.readFileSync(path.resolve(process.cwd(), filePath)).toString();
9
+ exports.readFileContents = readFileContents;
10
+ const FILE_WATCH_DEBOUNCE_DELAY = 1000;
11
+ const watchForChanges = (filePath, handler) => {
12
+ let lastContents = '';
13
+ const debounced = (0, lodash_debounce_1.default)(() => {
14
+ const currentContents = readFileContents(filePath);
15
+ if (lastContents !== currentContents) {
16
+ lastContents = currentContents;
17
+ handler(currentContents);
18
+ }
19
+ }, FILE_WATCH_DEBOUNCE_DELAY, {
20
+ trailing: true,
21
+ });
22
+ return fs.watch(filePath, debounced);
23
+ };
24
+ exports.watchForChanges = watchForChanges;
@@ -0,0 +1,4 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ import type { Logger } from 'pino';
3
+ declare const createHttpServer: (logger: Logger) => FastifyInstance;
4
+ export { createHttpServer };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createHttpServer = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fastify_1 = tslib_1.__importDefault(require("fastify"));
6
+ const http_1 = tslib_1.__importDefault(require("http"));
7
+ const parse_1 = require("./parse");
8
+ const debug = require('debug')('logs:http');
9
+ const createHttpServer = (logger) => {
10
+ const fastify = (0, fastify_1.default)({
11
+ serverFactory: (handler) => http_1.default.createServer(handler),
12
+ });
13
+ fastify.post('/logs', (request, reply) => {
14
+ debug('received "log" request');
15
+ reply.code(204).send();
16
+ (0, parse_1.parseLogEvent)(logger, request.body);
17
+ });
18
+ return fastify;
19
+ };
20
+ exports.createHttpServer = createHttpServer;
@@ -7,4 +7,5 @@ interface LogEvent {
7
7
  time: number;
8
8
  }
9
9
  declare const parseLogEvent: (logger: pino.Logger, event: LogEvent) => Promise<void>;
10
+ export type { LogEvent };
10
11
  export { parseLogEvent };
@@ -3,32 +3,37 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseLogEvent = void 0;
4
4
  const debug = require('debug')('logs:parse');
5
5
  const parseLogEvent = async (logger, event) => {
6
- debug(event);
7
- const { deserializeError } = await import('serialize-error');
8
- const [arg1, arg2, ...args] = event.args.map((arg) => {
9
- // eslint-disable-next-line unicorn/no-null
10
- if (arg === null || arg === undefined || typeof arg === 'number') {
11
- return String(arg);
6
+ try {
7
+ debug(event);
8
+ const { deserializeError } = await import('serialize-error');
9
+ const [obj, msg, ...args] = event.args.map((arg) => {
10
+ // eslint-disable-next-line unicorn/no-null
11
+ if (arg === null || arg === undefined || typeof arg === 'number') {
12
+ return String(arg);
13
+ }
14
+ if ((arg === null || arg === void 0 ? void 0 : arg.name) && (arg === null || arg === void 0 ? void 0 : arg.stack)) {
15
+ return deserializeError(arg);
16
+ }
17
+ return arg;
18
+ });
19
+ switch (event.level) {
20
+ case 'INFO': {
21
+ logger.info(obj, msg, ...args);
22
+ break;
23
+ }
24
+ case 'WARN': {
25
+ logger.warn(obj, msg, ...args);
26
+ break;
27
+ }
28
+ case 'ERROR': {
29
+ logger.error(obj, msg, ...args);
30
+ break;
31
+ }
32
+ // No default
12
33
  }
13
- if ((arg === null || arg === void 0 ? void 0 : arg.name) && (arg === null || arg === void 0 ? void 0 : arg.stack)) {
14
- return deserializeError(arg);
15
- }
16
- return arg;
17
- });
18
- switch (event.level) {
19
- case 'INFO': {
20
- logger.info(arg1, arg2, ...args);
21
- break;
22
- }
23
- case 'WARN': {
24
- logger.warn(arg1, arg2, ...args);
25
- break;
26
- }
27
- case 'ERROR': {
28
- logger.error(arg1, arg2, ...args);
29
- break;
30
- }
31
- // No default
34
+ }
35
+ catch (error) {
36
+ debug('Error trying to parse log event', error);
32
37
  }
33
38
  };
34
39
  exports.parseLogEvent = parseLogEvent;
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createLogServer = void 0;
4
+ const tslib_1 = require("tslib");
4
5
  const core_1 = require("@oclif/core");
5
6
  const cloudflared_1 = require("cloudflared");
6
- const fs = require("node:fs");
7
- const node_http_1 = require("node:http");
8
- const pino_1 = require("pino");
9
- const socket_io_1 = require("socket.io");
10
- const parse_1 = require("./parse");
7
+ const fs = tslib_1.__importStar(require("node:fs"));
8
+ const pino_1 = tslib_1.__importDefault(require("pino"));
9
+ const http_1 = require("./http");
10
+ const socket_1 = require("./socket");
11
11
  const debug = require('debug')('logs:server');
12
12
  const runTunnel = async (port) => {
13
13
  if (!fs.existsSync(cloudflared_1.bin)) {
@@ -34,27 +34,11 @@ const createLogServer = async (port) => {
34
34
  },
35
35
  });
36
36
  debug('creating http server');
37
- const server = (0, node_http_1.createServer)();
37
+ const fastify = (0, http_1.createHttpServer)(logger);
38
38
  debug('creating socket server');
39
- const io = new socket_io_1.Server(server);
40
- io.on('connection', (client) => {
41
- debug(`socket client connected: ${client.handshake.address}`);
42
- client.on('log', (data, callback) => {
43
- debug('received "log" event');
44
- if (typeof callback === 'function') {
45
- debug('ack expected');
46
- // eslint-disable-next-line node/callback-return,node/no-callback-literal
47
- callback('ack');
48
- debug('ack sent');
49
- }
50
- (0, parse_1.parseLogEvent)(logger, data);
51
- });
52
- client.on('disconnect', (reason) => {
53
- debug(`socket client disconnected ${client.handshake.address}: ${reason}`);
54
- });
55
- });
39
+ (0, socket_1.createSocketServer)(fastify.server, logger);
56
40
  debug(`server listening on port ${port}`);
57
- server.listen(port);
41
+ await fastify.listen({ port });
58
42
  core_1.ux.action.stop(`✅\tListening at http://localhost:${port}`);
59
43
  core_1.ux.action.start('Starting tunnel');
60
44
  const url = await runTunnel(port);
@@ -0,0 +1,5 @@
1
+ import type { Server as HttpServer } from 'http';
2
+ import type { Logger } from 'pino';
3
+ import { Server } from 'socket.io';
4
+ declare const createSocketServer: (httpServer: HttpServer, logger: Logger) => Server;
5
+ export { createSocketServer };
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSocketServer = void 0;
4
+ const socket_io_1 = require("socket.io");
5
+ const parse_1 = require("./parse");
6
+ const debug = require('debug')('logs:socket');
7
+ const createSocketServer = (httpServer, logger) => {
8
+ const io = new socket_io_1.Server(httpServer);
9
+ io.on('connection', (client) => {
10
+ debug(`socket client connected: ${client.handshake.address}`);
11
+ client.on('log', (data, callback) => {
12
+ debug('received "log" event');
13
+ if (typeof callback === 'function') {
14
+ debug('ack expected');
15
+ // eslint-disable-next-line node/callback-return,node/no-callback-literal
16
+ callback('ack');
17
+ debug('ack sent');
18
+ }
19
+ (0, parse_1.parseLogEvent)(logger, data);
20
+ });
21
+ client.on('disconnect', (reason) => {
22
+ debug(`socket client disconnected ${client.handshake.address}: ${reason}`);
23
+ });
24
+ });
25
+ return io;
26
+ };
27
+ exports.createSocketServer = createSocketServer;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createModelFromFlags = exports.PROXY_FLAGS = void 0;
4
4
  const core_1 = require("@oclif/core");
5
5
  const dotenv_1 = require("dotenv");
6
- const utils_1 = require("../utils");
6
+ const files_1 = require("../files");
7
7
  const PROXY_FLAGS = {
8
8
  name: core_1.Flags.string({
9
9
  char: 'n',
@@ -43,14 +43,14 @@ function createModelFromFlags({ name, destinationUrl, requestTransformCode, resp
43
43
  name,
44
44
  destinationUrl,
45
45
  requestTransform: requestTransformCode
46
- ? { code: (0, utils_1.readFileContents)(requestTransformCode) }
46
+ ? { code: (0, files_1.readFileContents)(requestTransformCode) }
47
47
  : undefined,
48
48
  responseTransform: responseTransformCode
49
- ? { code: (0, utils_1.readFileContents)(responseTransformCode) }
49
+ ? { code: (0, files_1.readFileContents)(responseTransformCode) }
50
50
  : undefined,
51
51
  application: applicationId ? { id: applicationId } : undefined,
52
52
  configuration: configuration
53
- ? (0, dotenv_1.parse)((0, utils_1.readFileContents)(configuration))
53
+ ? (0, dotenv_1.parse)((0, files_1.readFileContents)(configuration))
54
54
  : undefined,
55
55
  requireAuth,
56
56
  };
package/dist/utils.d.ts CHANGED
@@ -7,6 +7,5 @@ declare const selectOrNavigate: <T>(list: PaginatedList<T>, prop: string) => Pro
7
7
  declare const promptStringIfUndefined: (value: string | undefined, options: Parameters<typeof input>[0]) => Promise<string>;
8
8
  declare const promptUrlIfUndefined: (value: URL | undefined, options: Parameters<typeof input>[0]) => Promise<URL>;
9
9
  declare const promptBooleanIfUndefined: (value: boolean | undefined, options: Parameters<typeof confirm>[0]) => Promise<boolean>;
10
- declare const readFileContents: (filePath: string) => string;
11
10
  declare const cleanUpOnExit: (action: () => unknown) => typeof process;
12
- export { selectOrNavigate, promptStringIfUndefined, promptUrlIfUndefined, promptBooleanIfUndefined, readFileContents, cleanUpOnExit, };
11
+ export { selectOrNavigate, promptStringIfUndefined, promptUrlIfUndefined, promptBooleanIfUndefined, cleanUpOnExit, };
package/dist/utils.js CHANGED
@@ -1,11 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.cleanUpOnExit = exports.readFileContents = exports.promptBooleanIfUndefined = exports.promptUrlIfUndefined = exports.promptStringIfUndefined = exports.selectOrNavigate = void 0;
4
- const confirm_1 = require("@inquirer/confirm");
5
- const input_1 = require("@inquirer/input");
3
+ exports.cleanUpOnExit = exports.promptBooleanIfUndefined = exports.promptUrlIfUndefined = exports.promptStringIfUndefined = exports.selectOrNavigate = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const confirm_1 = tslib_1.__importDefault(require("@inquirer/confirm"));
6
+ const input_1 = tslib_1.__importDefault(require("@inquirer/input"));
6
7
  const core_1 = require("@oclif/core");
7
- const fs = require("fs");
8
- const path = require("path");
9
8
  const selectOrNavigate = async (list, prop) => {
10
9
  const { data, pagination } = list;
11
10
  let prompt = `Select one (${prop})`;
@@ -67,8 +66,6 @@ const promptBooleanIfUndefined = (value, options) => {
67
66
  return (0, confirm_1.default)(options);
68
67
  };
69
68
  exports.promptBooleanIfUndefined = promptBooleanIfUndefined;
70
- const readFileContents = (filePath) => fs.readFileSync(path.resolve(process.cwd(), filePath)).toString();
71
- exports.readFileContents = readFileContents;
72
69
  const cleanUpOnExit = (action) => process.on('SIGINT', async () => {
73
70
  await action();
74
71
  process.exit(1);
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.3.2",
2
+ "version": "1.4.0",
3
3
  "commands": {
4
4
  "proxies:create": {
5
5
  "id": "proxies:create",
@@ -241,6 +241,14 @@
241
241
  "char": "a",
242
242
  "description": "whether the Proxy requires Basis Theory authentication to be invoked. Default: true",
243
243
  "allowNo": true
244
+ },
245
+ "watch": {
246
+ "name": "watch",
247
+ "type": "boolean",
248
+ "char": "w",
249
+ "description": "Watch for changes in informed files",
250
+ "required": false,
251
+ "allowNo": false
244
252
  }
245
253
  },
246
254
  "args": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basis-theory-labs/cli",
3
- "version": "1.3.2",
3
+ "version": "1.4.0",
4
4
  "description": "Basis Theory CLI tool",
5
5
  "author": "Davi Aquino @djejaquino",
6
6
  "bin": {
@@ -28,6 +28,8 @@
28
28
  "cloudflared": "^0.4.0",
29
29
  "debug": "^4.3.4",
30
30
  "dotenv": "^16.3.1",
31
+ "fastify": "^4.19.2",
32
+ "lodash.debounce": "^4.0.8",
31
33
  "pino": "^8.14.1",
32
34
  "pino-pretty": "^10.0.0",
33
35
  "serialize-error": "^11.0.0",
@@ -44,6 +46,7 @@
44
46
  "@semantic-release/release-notes-generator": "^11.0.3",
45
47
  "@types/chai": "^4",
46
48
  "@types/debug": "^4.1.8",
49
+ "@types/lodash.debounce": "^4.0.7",
47
50
  "@types/mocha": "^9.0.0",
48
51
  "@types/node": "^16.18.36",
49
52
  "chai": "^4",