@scout9/app 1.0.0-alpha.0.2.1 → 1.0.0-alpha.0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scout9/app",
3
- "version": "1.0.0-alpha.0.2.1",
3
+ "version": "1.0.0-alpha.0.2.2",
4
4
  "description": "Build and deploy your Scout9 app for SMS auto replies",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -19,7 +19,7 @@
19
19
  "postinstall": "node postinstall.js",
20
20
  "prepublishOnly": "npm run build",
21
21
  "generate:types": "node scripts/generate-dts.js",
22
- "prebuild": "rimraf dist/",
22
+ "prebuild": "rimraf dist/ && rimraf types/index.d.ts && rimraf types/index.d.ts.map",
23
23
  "build": "rollup -c",
24
24
  "postbuild": "npm run generate:types && node scripts/post-build.js && npx tsc --noEmit",
25
25
  "build-no-test": "npm run prebuild && rollup -c"
@@ -6,12 +6,13 @@ import colors from 'kleur';
6
6
  import { config as dotenv } from 'dotenv';
7
7
  import { Configuration, Scout9Api } from '@scout9/admin';
8
8
  import { EventResponse, WorkflowEventSchema } from '@scout9/app';
9
- import path from 'node:path';
9
+ import path, { resolve } from 'node:path';
10
10
  import fs from 'node:fs';
11
11
  import https from 'node:https';
12
12
  import { fileURLToPath, pathToFileURL } from 'node:url';
13
13
  import projectApp from './src/app.js';
14
14
  import config from './config.js';
15
+ import { readdir } from 'fs/promises';
15
16
 
16
17
  const __filename = fileURLToPath(import.meta.url);
17
18
  const __dirname = path.dirname(__filename);
@@ -229,6 +230,7 @@ async function resolveEntityApi(entity, method) {
229
230
 
230
231
  }
231
232
 
233
+
232
234
  function extractParamsFromPath(path) {
233
235
  const segments = path.split('/').filter(Boolean); // Split and remove empty segments
234
236
  let params = {};
@@ -284,6 +286,86 @@ async function runEntityApi(req, res) {
284
286
  }
285
287
  }
286
288
 
289
+ async function getFilesRecursive(dir) {
290
+ let results = [];
291
+ const list = await readdir(dir, { withFileTypes: true });
292
+
293
+ for (const dirent of list) {
294
+ const res = resolve(dir, dirent.name);
295
+ if (dirent.isDirectory()) {
296
+ results = results.concat(await getFilesRecursive(res)); // Recursively get files from subdirectories
297
+ } else {
298
+ results.push(res); // Add file to results
299
+ }
300
+ }
301
+
302
+ return results;
303
+ }
304
+
305
+ async function runCommandApi(req, res) {
306
+ let file;
307
+ const {body, url} = req;
308
+ const params = url.split('/').slice(2).filter(Boolean);
309
+ const commandsDir = resolve(__dirname, `./src/commands`);
310
+
311
+ try {
312
+ const files = await getFilesRecursive(commandsDir).then(files => files.map(file => file.replace(commandsDir, '.')).filter(file => params.every(p => file.includes(p))))
313
+ file = files?.[0];
314
+ } catch (e) {
315
+ console.log('No commands found', e.message)
316
+ }
317
+
318
+
319
+ if (!file) {
320
+ throw new Error(`Unable to find command for ${url}`);
321
+ }
322
+
323
+ let mod;
324
+ try {
325
+ mod = await import(pathToFileURL(path.resolve(commandsDir, file)).href)
326
+ console.log(mod);
327
+ } catch (e) {
328
+ if ('code' in e) {
329
+ switch (e.code) {
330
+ case 'ERR_MODULE_NOT_FOUND':
331
+ case 'MODULE_NOT_FOUND':
332
+ console.error(e);
333
+ throw new Error(`Invalid command: no API method`);
334
+ }
335
+ }
336
+ console.error(e);
337
+ throw new Error(`Invalid command: Internal system error`);
338
+ }
339
+
340
+ if (!mod || !mod.default) {
341
+ throw new Error(`Command file "${file}" does not export a default command function`);
342
+ }
343
+
344
+ console.log(mod);
345
+
346
+ let result;
347
+
348
+ try {
349
+ result = await mod.default(body);
350
+ } catch (e) {
351
+ console.error('Failed to run command', e);
352
+ throw new Error(`Failed to run command: ${e.message}`)
353
+ }
354
+
355
+ if (result) {
356
+ if (typeof result === 'string') {
357
+ return {message: result};
358
+ } else if (typeof result === 'object' && 'message' in result) {
359
+ return result;
360
+ } else {
361
+ throw new Error(`Invalid Command Response, must either return a string or {"message": "<your message>"}`);
362
+ }
363
+ }
364
+ return {message: `${mod.default.name} Complete`};
365
+ }
366
+
367
+ app.post('/commands/:command', runCommandApi);
368
+ app.post('/commands/:command/*', runCommandApi);
287
369
  app.get('/entity/:entity', runEntityApi);
288
370
  app.put('/entity/:entity', runEntityApi);
289
371
  app.patch('/entity/:entity', runEntityApi);