@swizzyweb/swerve-manager 0.1.4 → 0.1.7

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
@@ -3,6 +3,10 @@
3
3
  swizzy-swerve is a bootstrapper for swizzy web services. This package will bootstrap and run
4
4
  independent swizzy web services.
5
5
 
6
+ ## Docs
7
+
8
+ https://swizzyweb.github.io/swerve-manager/
9
+
6
10
  ### Supported commands
7
11
 
8
12
  swerve: synonym for swerven
@@ -201,7 +205,7 @@ appDataPath: "/appDataRoot/appdata/serviceName/"
201
205
  },
202
206
  "friendlyImportServiceName": {
203
207
  "port": 3002,
204
- "servicePath": "@swizzyweb/dyn-serve-web-service" // running installed web service package
208
+ "packageName": "@swizzyweb/dyn-serve-web-service" // running installed web service package
205
209
  },
206
210
  "friendlyNeighborServiceName": {
207
211
  "port": 3002,
@@ -217,3 +221,9 @@ appDataPath: "/appDataRoot/appdata/serviceName/"
217
221
  ```
218
222
  swerve --config my-web-service-config.json
219
223
  ```
224
+
225
+ # Generate Docs
226
+
227
+ ```
228
+ npx typedoc
229
+ ```
package/dist/swerve.d.ts CHANGED
@@ -50,6 +50,8 @@ export type Apps = {
50
50
  export interface SwerveManagerProps {
51
51
  apps?: Apps;
52
52
  webServices?: WebService<any>[];
53
+ nodeModulesPath?: string;
54
+ logger?: ILogger<any> | undefined;
53
55
  }
54
56
  export interface WebServiceConfiguration {
55
57
  }
@@ -60,13 +62,15 @@ export declare class SwerveManager implements ISwerveManager {
60
62
  apps: Apps;
61
63
  webServices: WebService<any>[];
62
64
  configurations: WebServiceConfigurations;
65
+ nodeModulesPath: string;
66
+ logger: ILogger<any>;
63
67
  constructor(props: SwerveManagerProps);
64
68
  run(request: RunRequest): Promise<RunResponse>;
65
69
  runWithArgs(request: RunRequest): Promise<WebService<any>[]>;
66
70
  private runWithApp;
67
71
  installWebService(props: {
68
72
  serviceKey: string;
69
- importPathOrName: string;
73
+ servicePath: string;
70
74
  app: Application;
71
75
  appDataRoot: string;
72
76
  packageName: string;
@@ -76,6 +80,7 @@ export declare class SwerveManager implements ISwerveManager {
76
80
  [key: string]: any;
77
81
  };
78
82
  }): Promise<any>;
83
+ getImportName(packageName: string, servicePath: string): Promise<string>;
79
84
  stop(request: StopRequest): Promise<void>;
80
85
  getRunningWebServices(props: GetRunningWebServiceRequest): Promise<GetRunningWebServiceResponse>;
81
86
  }
package/dist/swerve.js CHANGED
@@ -1,11 +1,12 @@
1
1
  // @ts-ignore
2
2
  import express from "@swizzyweb/express";
3
- import { getFullImportPath, getLoggerForService, } from "./utils/index.js";
3
+ import { getLoggerForService, } from "./utils/index.js";
4
4
  import { SwizzyWinstonLogger, } from "@swizzyweb/swizzy-web-service";
5
5
  import os from "node:os";
6
6
  import process from "node:process";
7
7
  import path from "node:path";
8
8
  import { mkdirSync } from "node:fs";
9
+ import { getFullImportPath, resolvePackageEntry, } from "./utils/getFullImportPath.js";
9
10
  export var InstanceType;
10
11
  (function (InstanceType) {
11
12
  InstanceType["webservice"] = "webservice";
@@ -15,9 +16,19 @@ export class SwerveManager {
15
16
  apps;
16
17
  webServices;
17
18
  configurations;
19
+ nodeModulesPath;
20
+ logger;
18
21
  constructor(props) {
19
22
  this.apps = props.apps ?? {};
20
23
  this.webServices = props.webServices ?? [];
24
+ this.nodeModulesPath = props.nodeModulesPath;
25
+ this.logger =
26
+ props.logger ??
27
+ new SwizzyWinstonLogger({
28
+ appName: "swerve-manager",
29
+ port: -1,
30
+ hostName: os.hostname(),
31
+ });
21
32
  }
22
33
  async run(request) {
23
34
  const { args } = request;
@@ -50,18 +61,18 @@ export class SwerveManager {
50
61
  }
51
62
  const app = this.apps[`${port}`].app;
52
63
  const service = serviceEntry[1];
53
- const packageName = serviceEntry[0];
54
- const importPathOrName = service.servicePath ?? service.packageName;
55
- gLogger.debug(`importPathOrName ${importPathOrName}`);
64
+ const serviceName = serviceEntry[0];
65
+ const packageName = service.packageName;
66
+ gLogger.debug(`servicePath: ${service.servicePath}`);
56
67
  const serviceArgs = {
57
68
  ...service,
58
69
  ...service.serviceConfiguration,
59
70
  ...args.serviceArgs,
60
71
  };
61
72
  const webservice = await this.installWebService({
62
- serviceKey: serviceEntry[0],
73
+ serviceKey: serviceName,
63
74
  packageName,
64
- importPathOrName,
75
+ servicePath: service.servicePath,
65
76
  port,
66
77
  app,
67
78
  appDataRoot: args.appDataRoot,
@@ -118,11 +129,10 @@ export class SwerveManager {
118
129
  for (const serviceEntry of Object.entries(args.services)) {
119
130
  const service = serviceEntry[1];
120
131
  const packageName = service.packageName;
121
- const importPathOrName = service.servicePath ?? service.serviceArgs.servicePath ?? packageName;
122
132
  const webservice = await this.installWebService({
123
133
  serviceKey: serviceEntry[0],
124
134
  packageName,
125
- importPathOrName,
135
+ servicePath: service.servicePath,
126
136
  port: PORT,
127
137
  app,
128
138
  appDataRoot: args.appDataRoot,
@@ -142,13 +152,17 @@ export class SwerveManager {
142
152
  }
143
153
  }
144
154
  async installWebService(props) {
145
- // const packageName = importPathOrName;
146
- const { app, appDataRoot, packageName, port, gLogger, serviceArgs, importPathOrName, serviceKey, } = props;
155
+ const { app, appDataRoot, packageName, port, gLogger, serviceArgs, servicePath, serviceKey, } = props;
147
156
  try {
148
157
  gLogger.info(`Getting webservice package ${packageName} and will run on port ${port}`);
149
- gLogger.debug(`Getting tool with path: ${importPathOrName}`);
150
- const fullPath = await getFullImportPath(importPathOrName);
151
- const tool = await import(fullPath); //require(fullPath); //require(packageName as string);
158
+ if (packageName) {
159
+ gLogger.debug(`Getting web service with name ${packageName}`);
160
+ }
161
+ else {
162
+ gLogger.debug(`Getting webservice with path: ${servicePath}`);
163
+ }
164
+ const fullPath = await this.getImportName(packageName, servicePath);
165
+ const tool = await import(fullPath);
152
166
  gLogger.debug(`Got service with require: ${JSON.stringify(tool)}`);
153
167
  gLogger.debug(`Getting web service from tool...`);
154
168
  const appDataPath = path.join(appDataRoot, "appdata", serviceKey);
@@ -161,6 +175,7 @@ export class SwerveManager {
161
175
  port,
162
176
  app,
163
177
  packageName,
178
+ servicePath,
164
179
  serviceArgs: { ...serviceArgs },
165
180
  logger,
166
181
  });
@@ -184,6 +199,22 @@ Failed to install web service, is it installed with NPM? Check package exists in
184
199
  throw e; //new Error(exceptionMessage);
185
200
  }
186
201
  }
202
+ async getImportName(packageName, servicePath) {
203
+ const nodeModulesPath = this.nodeModulesPath;
204
+ this.logger.debug(`getImportPathName: modulesPath: ${nodeModulesPath}`);
205
+ if (servicePath) {
206
+ return await getFullImportPath(servicePath);
207
+ }
208
+ else {
209
+ if (nodeModulesPath) {
210
+ this.logger.debug(`Getting path with nodeModulesPath and packageName ${nodeModulesPath} ${packageName}`);
211
+ return await resolvePackageEntry(path.join(nodeModulesPath, packageName));
212
+ }
213
+ else {
214
+ return packageName;
215
+ }
216
+ }
217
+ }
187
218
  async stop(request) {
188
219
  const { instanceDetails } = request;
189
220
  const { instanceId, instanceType } = instanceDetails;
@@ -0,0 +1,2 @@
1
+ export declare function getFullImportPath(importPathOrName: string): Promise<string>;
2
+ export declare function resolvePackageEntry(pkgDir: string): Promise<string>;
@@ -0,0 +1,82 @@
1
+ // cross-runtime getFullImportPath.ts
2
+ import { promises as fs } from "node:fs";
3
+ import { pathToFileURL } from "node:url";
4
+ // Runtime detection
5
+ // @ts-ignore
6
+ const isDeno = typeof Deno !== "undefined" && "cwd" in Deno;
7
+ // @ts-ignore
8
+ const isBun = typeof Bun !== "undefined";
9
+ // @ts-ignore
10
+ const isNode = !isDeno && !isBun;
11
+ let join;
12
+ let cwd;
13
+ let fromFileUrl;
14
+ // --- Runtime-specific shims ---
15
+ if (isDeno) {
16
+ // @ts-ignore
17
+ // const path = await import("https://deno.land/std@0.203.0/path/mod.ts");
18
+ const path = await import("node:path");
19
+ join = path.join;
20
+ const url = await import("node:url");
21
+ // @ts-ignore
22
+ cwd = Deno.cwd;
23
+ fromFileUrl = url.fileURLToPath;
24
+ // fromFileUrl = path.fromFileUrl;
25
+ }
26
+ else if (isNode) {
27
+ const path = await import("node:path");
28
+ const processMod = await import("node:process");
29
+ const url = await import("node:url");
30
+ join = path.join;
31
+ cwd = processMod.cwd;
32
+ fromFileUrl = url.fileURLToPath;
33
+ }
34
+ else if (isBun) {
35
+ const path = await import("path");
36
+ join = path.join;
37
+ cwd = () => process.cwd();
38
+ fromFileUrl = (u) => new URL(u).pathname; // Bun auto normalizes
39
+ }
40
+ // --- Universal function ---
41
+ export async function getFullImportPath(importPathOrName) {
42
+ let importPath;
43
+ if (importPathOrName.startsWith(".")) {
44
+ importPath = join(cwd(), importPathOrName);
45
+ }
46
+ else {
47
+ importPath = importPathOrName;
48
+ }
49
+ if (importPathOrName === importPath) {
50
+ // Turn into a full absolute path
51
+ const fullUrl = new URL(importPath, import.meta.url).href;
52
+ return fromFileUrl(fullUrl);
53
+ }
54
+ return importPath;
55
+ }
56
+ export async function resolvePackageEntry(pkgDir) {
57
+ const pkgJsonPath = join(pkgDir, "package.json");
58
+ let entry;
59
+ try {
60
+ const pkgJsonRaw = await fs.readFile(pkgJsonPath, "utf-8");
61
+ const pkgJson = JSON.parse(pkgJsonRaw);
62
+ if (pkgJson.exports && typeof pkgJson.exports === "string") {
63
+ // Simple "exports": "./esm/index.js"
64
+ entry = pkgJson.exports;
65
+ }
66
+ else if (pkgJson.module) {
67
+ entry = pkgJson.module;
68
+ }
69
+ else if (pkgJson.main) {
70
+ entry = pkgJson.main;
71
+ }
72
+ }
73
+ catch {
74
+ // no package.json, fallback below
75
+ }
76
+ if (!entry) {
77
+ // fallback to index.js
78
+ entry = "index.js";
79
+ }
80
+ const absPath = join(pkgDir, entry);
81
+ return pathToFileURL(absPath).href; // usable in await import()
82
+ }
@@ -1,2 +1,3 @@
1
1
  export * from "./getArgs.js";
2
2
  export * from "./installWebservice.js";
3
+ export * from "./getFullImportPath.js";
@@ -1,2 +1,3 @@
1
1
  export * from "./getArgs.js";
2
2
  export * from "./installWebservice.js";
3
+ export * from "./getFullImportPath.js";
@@ -1,4 +1,3 @@
1
1
  import { ILogger } from "@swizzyweb/swizzy-common";
2
2
  export declare function installWebService(appName: string, importPathOrName: string, port: number, expressApp: any, serviceArgs: any, gLogger: ILogger<any>): Promise<any>;
3
- export declare function getFullImportPath(importPathOrName: string): Promise<string>;
4
3
  export declare function getLoggerForService(serviceArgs: any, appName: string, port: number, gLogger: ILogger<any>): ILogger<any>;
@@ -45,7 +45,7 @@ Failed to install web service, is it installed with NPM? Check package exists in
45
45
  throw Error(exceptionMessage); //new Error(exceptionMessage);
46
46
  }
47
47
  }
48
- export async function getFullImportPath(importPathOrName) {
48
+ async function getFullImportPath(importPathOrName) {
49
49
  const importPath = importPathOrName.startsWith(".")
50
50
  ? path.join(process.cwd(), importPathOrName)
51
51
  : importPathOrName;
package/package.json CHANGED
@@ -1,37 +1,35 @@
1
1
  {
2
2
  "name": "@swizzyweb/swerve-manager",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
4
4
  "description": "swizzy-swerve is a bootstrapper for swizzy web services. This package will bootstrap and run independent swizzy web services.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "type": "module",
8
8
  "scripts": {
9
9
  "build": "tsc",
10
- "server:ts": "ts-node ./src/bootstrap.ts",
11
10
  "server": "node dist/bootstrap.js",
12
- "test": "node --test ./test**/*.spec.ts",
11
+ "test": "npm run test:node && npm run test:bun && npm run test:deno",
12
+ "test:node": "node --test ./test**/*.spec.ts",
13
+ "test:deno": "deno test test/** --allow-env --allow-write --allow-read",
14
+ "test:bun": "bun test",
13
15
  "coverage": "jest --coverage"
14
16
  },
15
17
  "author": "Jason Gallagher",
16
18
  "license": "Apache-2.0",
17
19
  "devDependencies": {
18
20
  "@swizzyweb/express": "^4.19.2",
19
- "@types/jest": "^29.5.14",
20
21
  "@types/node": "^22.7.7",
21
- "jest": "^29.7.0",
22
- "ts-jest": "^29.3.2",
23
22
  "typescript": "^5.6.3"
24
23
  },
25
24
  "dependencies": {
26
25
  "@swizzyweb/swizzy-common": "^0.3.2",
27
26
  "@swizzyweb/swizzy-web-service": "^0.5.3",
28
27
  "bun": "^1.2.15",
29
- "deno": "^2.3.6",
30
- "ts-node": "^10.9.2"
28
+ "deno": "^2.3.6"
31
29
  },
32
30
  "repository": {
33
31
  "type": "git",
34
- "url": "git+https://github.com/swizzyweb/swerve.git"
32
+ "url": "git+https://github.com/swizzyweb/swerve-manager.git"
35
33
  },
36
34
  "keywords": [
37
35
  "swizzy",
@@ -43,7 +41,7 @@
43
41
  "runner"
44
42
  ],
45
43
  "bugs": {
46
- "url": "https://github.com/swizzyweb/swerve/issues"
44
+ "url": "https://github.com/swizzyweb/swerve-manager/issues"
47
45
  },
48
- "homepage": "https://github.com/swizzyweb/swerve#readme"
46
+ "homepage": "https://github.com/swizzyweb/swerve-manager#readme"
49
47
  }
package/src/swerve.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  // @ts-ignore
2
2
  import express, { Application } from "@swizzyweb/express";
3
3
  import {
4
- getFullImportPath,
5
4
  getLoggerForService,
6
5
  installWebService,
7
6
  SwerveArgs,
@@ -17,6 +16,10 @@ import process from "node:process";
17
16
  import { ILogger } from "@swizzyweb/swizzy-common";
18
17
  import path from "node:path";
19
18
  import { mkdirSync } from "node:fs";
19
+ import {
20
+ getFullImportPath,
21
+ resolvePackageEntry,
22
+ } from "./utils/getFullImportPath.js";
20
23
 
21
24
  export interface ISwerveManager {
22
25
  run(request: RunRequest): Promise<RunResponse>;
@@ -74,6 +77,8 @@ export type Apps = {
74
77
  export interface SwerveManagerProps {
75
78
  apps?: Apps;
76
79
  webServices?: WebService<any>[];
80
+ nodeModulesPath?: string;
81
+ logger?: ILogger<any> | undefined;
77
82
  }
78
83
 
79
84
  export interface WebServiceConfiguration {}
@@ -86,9 +91,19 @@ export class SwerveManager implements ISwerveManager {
86
91
  apps: Apps;
87
92
  webServices: WebService<any>[];
88
93
  configurations: WebServiceConfigurations;
94
+ nodeModulesPath: string;
95
+ logger: ILogger<any>;
89
96
  constructor(props: SwerveManagerProps) {
90
97
  this.apps = props.apps ?? {};
91
98
  this.webServices = props.webServices ?? [];
99
+ this.nodeModulesPath = props.nodeModulesPath;
100
+ this.logger =
101
+ props.logger ??
102
+ new SwizzyWinstonLogger({
103
+ appName: "swerve-manager",
104
+ port: -1,
105
+ hostName: os.hostname(),
106
+ });
92
107
  }
93
108
 
94
109
  async run(request: RunRequest): Promise<RunResponse> {
@@ -126,9 +141,9 @@ export class SwerveManager implements ISwerveManager {
126
141
  const app = this.apps[`${port}`].app;
127
142
 
128
143
  const service = serviceEntry[1];
129
- const packageName = serviceEntry[0];
130
- const importPathOrName = service.servicePath ?? service.packageName;
131
- gLogger.debug(`importPathOrName ${importPathOrName}`);
144
+ const serviceName = serviceEntry[0];
145
+ const packageName = service.packageName;
146
+ gLogger.debug(`servicePath: ${service.servicePath}`);
132
147
  const serviceArgs: SwerveArgs = {
133
148
  ...service,
134
149
  ...service.serviceConfiguration,
@@ -136,9 +151,9 @@ export class SwerveManager implements ISwerveManager {
136
151
  };
137
152
 
138
153
  const webservice = await this.installWebService({
139
- serviceKey: serviceEntry[0],
154
+ serviceKey: serviceName,
140
155
  packageName,
141
- importPathOrName,
156
+ servicePath: service.servicePath,
142
157
  port,
143
158
  app,
144
159
  appDataRoot: args.appDataRoot,
@@ -203,12 +218,10 @@ export class SwerveManager implements ISwerveManager {
203
218
  for (const serviceEntry of Object.entries(args.services)) {
204
219
  const service = serviceEntry[1];
205
220
  const packageName = service.packageName;
206
- const importPathOrName =
207
- service.servicePath ?? service.serviceArgs.servicePath ?? packageName;
208
221
  const webservice = await this.installWebService({
209
222
  serviceKey: serviceEntry[0],
210
223
  packageName,
211
- importPathOrName,
224
+ servicePath: service.servicePath,
212
225
  port: PORT,
213
226
  app,
214
227
  appDataRoot: args.appDataRoot,
@@ -232,7 +245,7 @@ export class SwerveManager implements ISwerveManager {
232
245
  async installWebService(props: {
233
246
  //
234
247
  serviceKey: string;
235
- importPathOrName: string;
248
+ servicePath: string;
236
249
  app: Application;
237
250
  appDataRoot: string;
238
251
  packageName: string;
@@ -240,7 +253,6 @@ export class SwerveManager implements ISwerveManager {
240
253
  gLogger: ILogger<any>;
241
254
  serviceArgs: { [key: string]: any };
242
255
  }) {
243
- // const packageName = importPathOrName;
244
256
  const {
245
257
  app,
246
258
  appDataRoot,
@@ -248,7 +260,7 @@ export class SwerveManager implements ISwerveManager {
248
260
  port,
249
261
  gLogger,
250
262
  serviceArgs,
251
- importPathOrName,
263
+ servicePath,
252
264
  serviceKey,
253
265
  } = props;
254
266
 
@@ -257,10 +269,14 @@ export class SwerveManager implements ISwerveManager {
257
269
  `Getting webservice package ${packageName} and will run on port ${port}`,
258
270
  );
259
271
 
260
- gLogger.debug(`Getting tool with path: ${importPathOrName}`);
272
+ if (packageName) {
273
+ gLogger.debug(`Getting web service with name ${packageName}`);
274
+ } else {
275
+ gLogger.debug(`Getting webservice with path: ${servicePath}`);
276
+ }
261
277
 
262
- const fullPath = await getFullImportPath(importPathOrName);
263
- const tool = await import(fullPath); //require(fullPath); //require(packageName as string);
278
+ const fullPath = await this.getImportName(packageName, servicePath);
279
+ const tool = await import(fullPath);
264
280
 
265
281
  gLogger.debug(`Got service with require: ${JSON.stringify(tool)}`);
266
282
  gLogger.debug(`Getting web service from tool...`);
@@ -281,6 +297,7 @@ export class SwerveManager implements ISwerveManager {
281
297
  port,
282
298
  app,
283
299
  packageName,
300
+ servicePath,
284
301
  serviceArgs: { ...serviceArgs },
285
302
  logger,
286
303
  });
@@ -309,6 +326,25 @@ Failed to install web service, is it installed with NPM? Check package exists in
309
326
  }
310
327
  }
311
328
 
329
+ async getImportName(packageName: string, servicePath: string) {
330
+ const nodeModulesPath = this.nodeModulesPath;
331
+ this.logger.debug(`getImportPathName: modulesPath: ${nodeModulesPath}`);
332
+ if (servicePath) {
333
+ return await getFullImportPath(servicePath);
334
+ } else {
335
+ if (nodeModulesPath) {
336
+ this.logger.debug(
337
+ `Getting path with nodeModulesPath and packageName ${nodeModulesPath} ${packageName}`,
338
+ );
339
+ return await resolvePackageEntry(
340
+ path.join(nodeModulesPath, packageName),
341
+ );
342
+ } else {
343
+ return packageName;
344
+ }
345
+ }
346
+ }
347
+
312
348
  async stop(request: StopRequest) {
313
349
  const { instanceDetails } = request;
314
350
  const { instanceId, instanceType } = instanceDetails;
@@ -0,0 +1,91 @@
1
+ // cross-runtime getFullImportPath.ts
2
+ import { promises as fs } from "node:fs";
3
+ import { pathToFileURL } from "node:url";
4
+
5
+ // Runtime detection
6
+ // @ts-ignore
7
+ const isDeno = typeof Deno !== "undefined" && "cwd" in Deno;
8
+ // @ts-ignore
9
+ const isBun = typeof Bun !== "undefined";
10
+ // @ts-ignore
11
+ const isNode = !isDeno && !isBun;
12
+
13
+ let join: (a: string, b: string) => string;
14
+ let cwd: () => string;
15
+ let fromFileUrl: (url: string) => string;
16
+
17
+ // --- Runtime-specific shims ---
18
+ if (isDeno) {
19
+ // @ts-ignore
20
+ // const path = await import("https://deno.land/std@0.203.0/path/mod.ts");
21
+
22
+ const path = await import("node:path");
23
+ join = path.join;
24
+ const url = await import("node:url");
25
+ // @ts-ignore
26
+ cwd = Deno.cwd;
27
+ fromFileUrl = url.fileURLToPath;
28
+ // fromFileUrl = path.fromFileUrl;
29
+ } else if (isNode) {
30
+ const path = await import("node:path");
31
+ const processMod = await import("node:process");
32
+ const url = await import("node:url");
33
+ join = path.join;
34
+ cwd = processMod.cwd;
35
+ fromFileUrl = url.fileURLToPath;
36
+ } else if (isBun) {
37
+ const path = await import("path");
38
+ join = path.join;
39
+ cwd = () => process.cwd();
40
+ fromFileUrl = (u: string) => new URL(u).pathname; // Bun auto normalizes
41
+ }
42
+
43
+ // --- Universal function ---
44
+ export async function getFullImportPath(
45
+ importPathOrName: string,
46
+ ): Promise<string> {
47
+ let importPath: string;
48
+
49
+ if (importPathOrName.startsWith(".")) {
50
+ importPath = join(cwd(), importPathOrName);
51
+ } else {
52
+ importPath = importPathOrName;
53
+ }
54
+
55
+ if (importPathOrName === importPath) {
56
+ // Turn into a full absolute path
57
+ const fullUrl = new URL(importPath, import.meta.url).href;
58
+ return fromFileUrl(fullUrl);
59
+ }
60
+
61
+ return importPath;
62
+ }
63
+
64
+ export async function resolvePackageEntry(pkgDir: string): Promise<string> {
65
+ const pkgJsonPath = join(pkgDir, "package.json");
66
+ let entry: string | undefined;
67
+
68
+ try {
69
+ const pkgJsonRaw = await fs.readFile(pkgJsonPath, "utf-8");
70
+ const pkgJson = JSON.parse(pkgJsonRaw);
71
+
72
+ if (pkgJson.exports && typeof pkgJson.exports === "string") {
73
+ // Simple "exports": "./esm/index.js"
74
+ entry = pkgJson.exports;
75
+ } else if (pkgJson.module) {
76
+ entry = pkgJson.module;
77
+ } else if (pkgJson.main) {
78
+ entry = pkgJson.main;
79
+ }
80
+ } catch {
81
+ // no package.json, fallback below
82
+ }
83
+
84
+ if (!entry) {
85
+ // fallback to index.js
86
+ entry = "index.js";
87
+ }
88
+
89
+ const absPath = join(pkgDir, entry);
90
+ return pathToFileURL(absPath).href; // usable in await import()
91
+ }
@@ -1,2 +1,3 @@
1
1
  export * from "./getArgs.js";
2
2
  export * from "./installWebservice.js";
3
+ export * from "./getFullImportPath.js";
@@ -79,9 +79,7 @@ Failed to install web service, is it installed with NPM? Check package exists in
79
79
  }
80
80
  }
81
81
 
82
- export async function getFullImportPath(
83
- importPathOrName: string,
84
- ): Promise<string> {
82
+ async function getFullImportPath(importPathOrName: string): Promise<string> {
85
83
  const importPath = importPathOrName.startsWith(".")
86
84
  ? path.join(process.cwd(), importPathOrName)
87
85
  : importPathOrName;
@@ -15,67 +15,95 @@ const logger = new SwizzyWinstonLogger({
15
15
  pid: process.pid,
16
16
  });
17
17
 
18
- test("getArgs", () => {
19
- test.it("Sets port and custom arg", async () => {
20
- const args = [
21
- "/path/to/package/",
22
- "run.js",
23
- "--port",
24
- "80",
25
- //"--appDataRoot",
26
- // ".",
27
- "--someCustomArg",
28
- "JasonIsTheBest",
29
- ];
30
- let result = await getArgs(args, logger);
31
- assert.equal(result.port, 80);
32
- assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
33
- });
18
+ test.it("Sets port and custom arg", async () => {
19
+ const args = [
20
+ "/path/to/package/",
21
+ "run.js",
22
+ "--port",
23
+ "80",
24
+ //"--appDataRoot",
25
+ // ".",
26
+ "--someCustomArg",
27
+ "JasonIsTheBest",
28
+ ];
29
+ let result: any = await getArgs(args, logger);
30
+ assert.equal(result.port, 80);
31
+ assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
32
+ });
34
33
 
35
- test.it("sets appDataRoot", async () => {
36
- const args = [
37
- "/path/to/package/",
38
- "run.js",
39
- "--port",
40
- "80",
41
- "--appDataRoot",
42
- ".",
43
- "--someCustomArg",
44
- "JasonIsTheBest",
45
- ];
46
- let result = await getArgs(args, logger);
47
- assert.equal(result.port, 80);
48
- assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
49
- });
34
+ test.it("sets appDataRoot", async () => {
35
+ const args = [
36
+ "/path/to/package/",
37
+ "run.js",
38
+ "--port",
39
+ "80",
40
+ "--appDataRoot",
41
+ ".",
42
+ "--someCustomArg",
43
+ "JasonIsTheBest",
44
+ ];
45
+ let result: any = await getArgs(args, logger);
46
+ assert.equal(result.port, 80);
47
+ assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
48
+ });
50
49
 
51
- test.it("Throws on invalid config file path", async () => {
52
- const configPath = "/some/invalid/path";
53
- const args = [
54
- "/path/to/package/",
55
- "run.js",
56
- "--port",
57
- "80",
58
- "--appDataRoot",
59
- ".",
60
- "--someCustomArg",
61
- "JasonIsTheBest",
62
- "--config",
63
- configPath,
64
- ];
65
- try {
66
- let result = await getArgs(args, logger);
67
- } catch (e) {
68
- assert.deepEqual(
69
- { message: e.message, configFilePath: configPath },
70
- {
71
- message:
72
- "Unexpected error occurred when attempting to read serviceConfiguration file",
73
- configFilePath: configPath,
74
- },
75
- );
76
- }
50
+ test.it("Throws on invalid config file path", async () => {
51
+ const configPath = "/some/invalid/path";
52
+ const args = [
53
+ "/path/to/package/",
54
+ "run.js",
55
+ "--port",
56
+ "80",
57
+ "--appDataRoot",
58
+ ".",
59
+ "--someCustomArg",
60
+ "JasonIsTheBest",
61
+ "--config",
62
+ configPath,
63
+ ];
64
+ try {
65
+ let result: any = await getArgs(args, logger);
66
+ } catch (e: any) {
67
+ assert.deepEqual(
68
+ { message: e?.message, configFilePath: configPath },
69
+ {
70
+ message:
71
+ "Unexpected error occurred when attempting to read serviceConfiguration file",
72
+ configFilePath: configPath,
73
+ },
74
+ );
75
+ }
76
+ });
77
+ test.it("Should read config values from config", async () => {
78
+ const configPath = path.join(__dirname, "./config/serviceConfig.json");
79
+ const args = [
80
+ "/path/to/package/",
81
+ "run.js",
82
+ "--port",
83
+ "80",
84
+ "--appDataRoot",
85
+ ".",
86
+ "--someCustomArg",
87
+ "JasonIsTheBest",
88
+ "--config",
89
+ configPath,
90
+ ];
91
+ let result: any = await getArgs(args, logger);
92
+ assert.equal(result.port, 3000);
93
+ const service = result.services["my-first-web-service1"];
94
+ assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
95
+
96
+ assert.equal(service.someOtherArgFromConfig, "ThisIsTheArgValue");
97
+ assert.equal(service.shouldTimeout, true);
98
+ assert.deepEqual(service.nestedJson, {
99
+ hello: "world",
100
+ none: false,
77
101
  });
78
- test.it("Should read config values from config", async () => {
102
+ });
103
+
104
+ test.it(
105
+ "Should override parameters in order of args, config file last",
106
+ async () => {
79
107
  const configPath = path.join(__dirname, "./config/serviceConfig.json");
80
108
  const args = [
81
109
  "/path/to/package/",
@@ -86,246 +114,216 @@ test("getArgs", () => {
86
114
  ".",
87
115
  "--someCustomArg",
88
116
  "JasonIsTheBest",
117
+ "--someNumberINeed",
118
+ "1000",
89
119
  "--config",
90
120
  configPath,
91
121
  ];
92
- let result = await getArgs(args, logger);
93
- assert.equal(result.port, 3000);
122
+ let result: any = await getArgs(args, logger);
123
+
94
124
  const service = result.services["my-first-web-service1"];
125
+ assert.equal(service.someOtherArgFromConfig, "ThisIsTheArgValue");
126
+
127
+ assert.equal(result.port, 3000);
95
128
  assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
96
129
 
97
- assert.equal(service.someOtherArgFromConfig, "ThisIsTheArgValue");
130
+ assert.equal(result.serviceArgs?.someNumberINeed, 1000);
98
131
  assert.equal(service.shouldTimeout, true);
99
132
  assert.deepEqual(service.nestedJson, {
100
133
  hello: "world",
101
134
  none: false,
102
135
  });
103
- });
104
-
105
- test.it(
106
- "Should override parameters in order of args, config file last",
107
- async () => {
108
- const configPath = path.join(__dirname, "./config/serviceConfig.json");
109
- const args = [
110
- "/path/to/package/",
111
- "run.js",
112
- "--port",
113
- "80",
114
- "--appDataRoot",
115
- ".",
116
- "--someCustomArg",
117
- "JasonIsTheBest",
118
- "--someNumberINeed",
119
- "1000",
120
- "--config",
121
- configPath,
122
- ];
123
- let result = await getArgs(args, logger);
124
-
125
- const service = result.services["my-first-web-service1"];
126
- assert.equal(service.someOtherArgFromConfig, "ThisIsTheArgValue");
127
-
128
- assert.equal(result.port, 3000);
129
- assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
136
+ },
137
+ );
130
138
 
131
- assert.equal(result.serviceArgs?.someNumberINeed, 1000);
132
- assert.equal(service.shouldTimeout, true);
133
- assert.deepEqual(service.nestedJson, {
134
- hello: "world",
135
- none: false,
136
- });
137
- },
138
- );
139
-
140
- test.it(
141
- "Should override parameters in order of args, config file first",
142
- async () => {
143
- const configPath = path.join(__dirname, "./config/serviceConfig.json");
144
- const args = [
145
- "/path/to/package/",
146
- "run.js",
147
- "--port",
148
- "80",
149
- "--appDataRoot",
150
- ".",
151
- "--someCustomArg",
152
- "JasonIsTheBest",
153
- "--config",
154
- configPath,
155
- "--someNumberINeed",
156
- "1000",
157
- ];
158
- let result = await getArgs(args, logger);
159
- const service = result.services["my-first-web-service1"];
160
- assert.equal(service.someOtherArgFromConfig, "ThisIsTheArgValue");
161
- assert.equal(result.port, 3000);
162
- assert.equal(result.appDataRoot, path.join(__dirname, ".."));
163
- assert.equal(result.appDataRoot, path.join(__dirname, ".."));
164
- assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
165
-
166
- assert.equal(result.serviceArgs?.someNumberINeed, 1000);
167
- assert.equal(service.shouldTimeout, true);
168
- assert.deepEqual(service.nestedJson, {
169
- hello: "world",
170
- none: false,
171
- });
172
- },
173
- );
174
-
175
- test.it("Should getService from args", async () => {
139
+ test.it(
140
+ "Should override parameters in order of args, config file first",
141
+ async () => {
142
+ const configPath = path.join(__dirname, "./config/serviceConfig.json");
176
143
  const args = [
177
144
  "/path/to/package/",
178
145
  "run.js",
179
- path.join(__dirname, "../package.json"),
180
146
  "--port",
181
147
  "80",
182
148
  "--appDataRoot",
183
149
  ".",
184
150
  "--someCustomArg",
185
151
  "JasonIsTheBest",
152
+ "--config",
153
+ configPath,
154
+ "--someNumberINeed",
155
+ "1000",
186
156
  ];
187
- let result = await getArgs(args, logger);
188
- assert.equal(result.port, 80);
189
-
157
+ let result: any = await getArgs(args, logger);
190
158
  const service = result.services["my-first-web-service1"];
191
- // expect(result.serviceArgs.appDataRoot, ".");
159
+ assert.equal(service.someOtherArgFromConfig, "ThisIsTheArgValue");
160
+ assert.equal(result.port, 3000);
161
+ assert.equal(result.appDataRoot, path.join(__dirname, ".."));
162
+ assert.equal(result.appDataRoot, path.join(__dirname, ".."));
192
163
  assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
193
- });
194
164
 
195
- test.it(
196
- "Should set appDataRoot to current package root by default",
197
- async () => {
198
- const configPath = path.join(__dirname, "./config/serviceConfig.json");
199
- const args = [
200
- "/path/to/package/",
201
- "run.js",
202
- "--port",
203
- "80",
204
- "--someCustomArg",
205
- "JasonIsTheBest",
206
- "--config",
207
- configPath,
208
- "--someNumberINeed",
209
- "1000",
210
- ];
211
- let result = await getArgs(args, logger);
165
+ assert.equal(result.serviceArgs?.someNumberINeed, 1000);
166
+ assert.equal(service.shouldTimeout, true);
167
+ assert.deepEqual(service.nestedJson, {
168
+ hello: "world",
169
+ none: false,
170
+ });
171
+ },
172
+ );
212
173
 
213
- const service = result.services["my-first-web-service1"];
214
- assert.equal(service.someOtherArgFromConfig, "ThisIsTheArgValue");
215
- assert.equal(result.port, 3000);
216
- assert.equal(result.appDataRoot, path.join(__dirname, ".."));
217
- assert.equal(result.serviceArgs?.someCustomArg!, "JasonIsTheBest");
174
+ test.it("Should getService from args", async () => {
175
+ const args = [
176
+ "/path/to/package/",
177
+ "run.js",
178
+ path.join(__dirname, "../package.json"),
179
+ "--port",
180
+ "80",
181
+ "--appDataRoot",
182
+ ".",
183
+ "--someCustomArg",
184
+ "JasonIsTheBest",
185
+ ];
186
+ let result: any = await getArgs(args, logger);
187
+ assert.equal(result.port, 80);
218
188
 
219
- assert.equal(result.serviceArgs?.someNumberINeed!, 1000);
220
- assert.equal(service.shouldTimeout, true);
221
- assert.deepEqual(service.nestedJson, {
222
- hello: "world",
223
- none: false,
224
- });
225
- },
226
- );
227
- test.it("Should create multiple services", async () => {
189
+ const service = result.services["my-first-web-service1"];
190
+ // expect(result.serviceArgs.appDataRoot, ".");
191
+ assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
192
+ });
193
+
194
+ test.it(
195
+ "Should set appDataRoot to current package root by default",
196
+ async () => {
228
197
  const configPath = path.join(__dirname, "./config/serviceConfig.json");
229
198
  const args = [
230
199
  "/path/to/package/",
231
200
  "run.js",
232
- ".",
233
201
  "--port",
234
202
  "80",
235
203
  "--someCustomArg",
236
204
  "JasonIsTheBest",
237
- // "--config",
238
- // configPath,
205
+ "--config",
206
+ configPath,
239
207
  "--someNumberINeed",
240
208
  "1000",
241
- ".",
242
- "--port",
243
- "91",
244
209
  ];
245
- let result = await getArgs(args, logger);
210
+ let result: any = await getArgs(args, logger);
246
211
 
247
212
  const service = result.services["my-first-web-service1"];
248
- assert.equal(result.port, 91);
213
+ assert.equal(service.someOtherArgFromConfig, "ThisIsTheArgValue");
214
+ assert.equal(result.port, 3000);
249
215
  assert.equal(result.appDataRoot, path.join(__dirname, ".."));
250
- // expect(service.someCustomArg, "JasonIsTheBest");
216
+ assert.equal(result.serviceArgs?.someCustomArg!, "JasonIsTheBest");
251
217
 
252
- // expect(service.someNumberINeed, 1000);
253
- // expect(service.shouldTimeout, true);
254
- // expect(service.nestedJson, {
255
- // hello: "world",
256
- // none: false,
257
- // });
258
- // expect(result.services.length, 2);
259
- });
260
- test.it("Should create absolute path appdata directory", async () => {
261
- const configPath = path.join(__dirname, "./config/serviceConfig.json");
262
- const appDataRoot = "/tmp/swizzy-dyn-serve-web-service";
263
- const args = [
264
- "/path/to/package/",
265
- "run.js",
266
- ".",
267
- "--port",
268
- "80",
269
- "--someCustomArg",
270
- "JasonIsTheBest",
271
- //"--config",
272
- //configPath,
273
- "--someNumberINeed",
274
- "1000",
275
- ".",
276
- "--port",
277
- "91",
278
- "--appDataRoot",
279
- appDataRoot,
280
- ];
281
- let result = await getArgs(args, logger);
282
- assert.equal(result.appDataRoot, appDataRoot);
283
- });
218
+ assert.equal(result.serviceArgs?.someNumberINeed!, 1000);
219
+ assert.equal(service.shouldTimeout, true);
220
+ assert.deepEqual(service.nestedJson, {
221
+ hello: "world",
222
+ none: false,
223
+ });
224
+ },
225
+ );
226
+ test.it("Should create multiple services", async () => {
227
+ const configPath = path.join(__dirname, "./config/serviceConfig.json");
228
+ const args = [
229
+ "/path/to/package/",
230
+ "run.js",
231
+ ".",
232
+ "--port",
233
+ "80",
234
+ "--someCustomArg",
235
+ "JasonIsTheBest",
236
+ // "--config",
237
+ // configPath,
238
+ "--someNumberINeed",
239
+ "1000",
240
+ ".",
241
+ "--port",
242
+ "91",
243
+ ];
244
+ let result: any = await getArgs(args, logger);
284
245
 
285
- test.it("Should resolve package.json from package name", async () => {
286
- const config = await getArgs(["@swizzyweb/swerve-manager"], logger);
287
- assert(config.services["@swizzyweb/swerve-manager"].packageJson);
288
- assert.equal(
289
- config.services["@swizzyweb/swerve-manager"].packageJson.name,
290
- "@swizzyweb/swerve-manager",
291
- );
292
- });
246
+ const service = result.services["my-first-web-service1"];
247
+ assert.equal(result.port, 91);
248
+ assert.equal(result.appDataRoot, path.join(__dirname, ".."));
249
+ // expect(service.someCustomArg, "JasonIsTheBest");
293
250
 
294
- test.it("Should resolve package.json from absolute path", async () => {
295
- const config = await getArgs([path.join(__dirname, "..")], logger);
296
- assert(config.services["@swizzyweb/swerve-manager"].packageJson);
297
- assert.equal(
298
- config.services["@swizzyweb/swerve-manager"].packageJson.name,
299
- "@swizzyweb/swerve-manager",
300
- );
301
- });
302
- test.it("Should not throw with no args", async () => {
303
- const config = await getArgs([], logger);
304
- assert(config.services["@swizzyweb/swerve-manager"].packageJson);
305
- assert.equal(
306
- config.services["@swizzyweb/swerve-manager"].packageJson.name,
307
- "@swizzyweb/swerve-manager",
308
- );
309
- });
310
- test.it("Should work with no port", async () => {
311
- const configPath = path.join(__dirname, "./config/serviceConfig.json");
312
- const args = [
313
- "/path/to/package/",
314
- "run.js",
315
- "--appDataRoot",
316
- ".",
317
- "--someCustomArg",
318
- "JasonIsTheBest",
319
- "--someNumberINeed",
320
- "1000",
321
- ];
322
- let result = await getArgs(args, logger);
323
- const service = result.services["my-first-web-service1"];
324
- assert.equal(result.port, 3005);
325
- assert.equal(result.appDataRoot, path.join(__dirname, ".."));
326
- assert.equal(result.appDataRoot, path.join(__dirname, ".."));
327
- assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
251
+ // expect(service.someNumberINeed, 1000);
252
+ // expect(service.shouldTimeout, true);
253
+ // expect(service.nestedJson, {
254
+ // hello: "world",
255
+ // none: false,
256
+ // });
257
+ // expect(result.services.length, 2);
258
+ });
259
+ test.it("Should create absolute path appdata directory", async () => {
260
+ const configPath = path.join(__dirname, "./config/serviceConfig.json");
261
+ const appDataRoot = "/tmp/swizzy-dyn-serve-web-service";
262
+ const args = [
263
+ "/path/to/package/",
264
+ "run.js",
265
+ ".",
266
+ "--port",
267
+ "80",
268
+ "--someCustomArg",
269
+ "JasonIsTheBest",
270
+ //"--config",
271
+ //configPath,
272
+ "--someNumberINeed",
273
+ "1000",
274
+ ".",
275
+ "--port",
276
+ "91",
277
+ "--appDataRoot",
278
+ appDataRoot,
279
+ ];
280
+ let result: any = await getArgs(args, logger);
281
+ assert.equal(result.appDataRoot, appDataRoot);
282
+ });
328
283
 
329
- assert.equal(result.serviceArgs?.someNumberINeed, 1000);
330
- });
284
+ test.it("Should resolve package.json from package name", async () => {
285
+ const config: any = await getArgs(["@swizzyweb/swerve-manager"], logger);
286
+ assert(config.services["@swizzyweb/swerve-manager"].packageJson);
287
+ assert.equal(
288
+ config.services["@swizzyweb/swerve-manager"].packageJson.name,
289
+ "@swizzyweb/swerve-manager",
290
+ );
291
+ });
292
+
293
+ test.it("Should resolve package.json from absolute path", async () => {
294
+ const config: any = await getArgs([path.join(__dirname, "..")], logger);
295
+ assert(config.services["@swizzyweb/swerve-manager"].packageJson);
296
+ assert.equal(
297
+ config.services["@swizzyweb/swerve-manager"].packageJson.name,
298
+ "@swizzyweb/swerve-manager",
299
+ );
300
+ });
301
+ test.it("Should not throw with no args", async () => {
302
+ const config: any = await getArgs([], logger);
303
+ assert(config.services["@swizzyweb/swerve-manager"].packageJson);
304
+ assert.equal(
305
+ config.services["@swizzyweb/swerve-manager"].packageJson.name,
306
+ "@swizzyweb/swerve-manager",
307
+ );
308
+ });
309
+ test.it("Should work with no port", async () => {
310
+ const configPath = path.join(__dirname, "./config/serviceConfig.json");
311
+ const args = [
312
+ "/path/to/package/",
313
+ "run.js",
314
+ "--appDataRoot",
315
+ ".",
316
+ "--someCustomArg",
317
+ "JasonIsTheBest",
318
+ "--someNumberINeed",
319
+ "1000",
320
+ ];
321
+ let result: any = await getArgs(args, logger);
322
+ const service = result.services["my-first-web-service1"];
323
+ assert.equal(result.port, 3005);
324
+ assert.equal(result.appDataRoot, path.join(__dirname, ".."));
325
+ assert.equal(result.appDataRoot, path.join(__dirname, ".."));
326
+ assert.equal(result.serviceArgs?.someCustomArg, "JasonIsTheBest");
327
+
328
+ assert.equal(result.serviceArgs?.someNumberINeed, 1000);
331
329
  });
@@ -0,0 +1,16 @@
1
+ import test from "node:test";
2
+ import { getFullImportPath } from "../dist/utils/getFullImportPath.js";
3
+ import assert from "node:assert";
4
+ import path from "node:path";
5
+
6
+ test("Should get full path with relative path", async () => {
7
+ const fullPath = await getFullImportPath("../");
8
+ assert(path.isAbsolute(fullPath));
9
+ });
10
+
11
+ test("Should get full path from packageName", async () => {
12
+ const fullPath = await getFullImportPath(
13
+ "@swizzyweb/swap-cache-db-web-service",
14
+ );
15
+ assert(path.isAbsolute(fullPath));
16
+ });
package/jest.config.js DELETED
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- preset: "ts-jest",
3
- testEnvironment: "node",
4
- };