@swizzyweb/swerve 0.6.1 → 0.6.3

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.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/dist/main.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swizzyweb/swerve",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
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
  "type": "module",
@@ -37,10 +37,10 @@
37
37
  "typescript": "^5.9.2"
38
38
  },
39
39
  "dependencies": {
40
- "@swizzyweb/express-unuse": "^1.0.1",
41
- "@swizzyweb/swerve-manager": "^0.3.1",
40
+ "@swizzyweb/swerve": "^0.6.2",
41
+ "@swizzyweb/swerve-manager": "^0.3.4",
42
42
  "@swizzyweb/swizzy-common": "^0.3.3",
43
- "@swizzyweb/swizzy-web-service": "^0.6.1",
43
+ "@swizzyweb/swizzy-web-service": "^0.6.2",
44
44
  "bun": "^1.2.22",
45
45
  "deno": "^2.5.2"
46
46
  },
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env deno
2
- import { run } from "./main.ts";
3
-
4
- run();
@@ -1,39 +0,0 @@
1
- #!/usr/bin/env deno
2
-
3
- import cluster from "node:cluster";
4
- import http from "node:http";
5
- import os from "node:os";
6
- import { run } from "./main.js";
7
- import process from "node:process";
8
- import { BrowserLogger } from "@swizzyweb/swizzy-common";
9
- import { getArgs } from "npm:@swizzyweb/swerve-manager";
10
-
11
- async function exec() {
12
- const args = await getArgs(process.argv, new BrowserLogger());
13
-
14
- const numThreads = args.serviceArgs?.numThreads ?? os.availableParallelism();
15
- if (cluster.isPrimary) {
16
- console.log(`Primary ${process.pid} is running`);
17
- console.log(`forking ${numThreads} threads`);
18
- // Fork workers.
19
- for (let i = 0; i < numThreads; i++) {
20
- cluster.fork();
21
- }
22
-
23
- cluster.on("exit", (worker, code, signal) => {
24
- console.log(`worker ${worker.process.pid} died`);
25
- });
26
- } else {
27
- // Workers can share any TCP connection
28
- // In this case it is an HTTP server
29
- /* http
30
- .createServer((req, res) => {
31
- res.writeHead(200);
32
- res.end("hello world\n");
33
- })
34
- .listen(8000);*/
35
- run();
36
- console.log(`Worker ${process.pid} started`);
37
- }
38
- }
39
- exec();
@@ -1,17 +0,0 @@
1
- import { IConfig } from "./config.js";
2
- export interface IAsyncConfigParser<CONFIG> {
3
- parse(path: string): Promise<CONFIG>;
4
- }
5
- export interface ISwerveConfigException {
6
- message: string;
7
- stack: any;
8
- }
9
- export declare class SwerveConfigException implements ISwerveConfigException {
10
- message: string;
11
- stack: any;
12
- constructor(message: string);
13
- }
14
- export declare class SwerveConfigParser implements IAsyncConfigParser<IConfig> {
15
- parse(configPath: string): Promise<IConfig>;
16
- validateConfig(config: any): void;
17
- }
@@ -1,43 +0,0 @@
1
- import { readFile } from "fs/promises";
2
- import path from "path";
3
- export class SwerveConfigException {
4
- message;
5
- stack;
6
- constructor(message) {
7
- this.message = message;
8
- this.stack = new Error(message).stack;
9
- }
10
- }
11
- export class SwerveConfigParser {
12
- async parse(configPath) {
13
- let actualPath;
14
- if (configPath.startsWith(".")) {
15
- actualPath = path.join(configPath);
16
- }
17
- else {
18
- actualPath = configPath;
19
- }
20
- const content = await readFile(actualPath, {
21
- encoding: "utf-8",
22
- });
23
- try {
24
- const config = JSON.parse(content);
25
- this.validateConfig(config);
26
- return config;
27
- }
28
- catch (e) {
29
- throw {
30
- message: `Error parsing config, ${e.message}`,
31
- stack: e.stack ?? new Error("Error parsing config").stack,
32
- };
33
- }
34
- }
35
- validateConfig(config) {
36
- if (typeof config.port !== "number") {
37
- throw new SwerveConfigException("Invalid port");
38
- }
39
- if (typeof config.services !== "object") {
40
- throw new SwerveConfigException("Invalid services configuration");
41
- }
42
- }
43
- }
@@ -1,15 +0,0 @@
1
- export type KeyValue<VALUE> = {
2
- [k: string]: VALUE;
3
- };
4
- export interface IService {
5
- packageName?: string;
6
- servicePath?: string;
7
- packageJson?: any;
8
- logLevel?: string;
9
- [key: string]: any;
10
- }
11
- export interface IConfig {
12
- port?: number;
13
- services: KeyValue<IService>;
14
- [key: string]: any;
15
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,2 +0,0 @@
1
- export * from "./config.js";
2
- export * from "./config-parser.js";
@@ -1,2 +0,0 @@
1
- export * from "./config.js";
2
- export * from "./config-parser.js";
@@ -1,3 +0,0 @@
1
- {"label":"jmoney-Laptop-16-AMD-Ryzen-7040-Series:::swerve:121451:swerve:","level":"info","message":"Getting webservice package @swizzyweb/swerve and will run on port 3005","timestamp":"2025-08-11T03:55:34.252Z"}
2
- {"label":"jmoney-Laptop-16-AMD-Ryzen-7040-Series:::swerve:121451:swerve:","level":"error","message":"Failed to install web service","timestamp":"2025-08-11T03:55:34.253Z"}
3
- {"label":"jmoney-Laptop-16-AMD-Ryzen-7040-Series:::swerve:121451:swerve:","level":"error","message":"Error occurred initializing service\n Invalid arguments\n TypeError: Invalid arguments\n at getFullImportPath (file:///home/jmoney/repos/BrowserToolkitWorkspace/swerve/node_modules/@swizzyweb/swerve-manager/dist/utils/installWebservice.js:54:37)\n at SwerveManager.installWebService (file:///home/jmoney/repos/BrowserToolkitWorkspace/swerve/node_modules/@swizzyweb/swerve-manager/dist/swerve.js:150:36)\n at SwerveManager.runWithArgs (file:///home/jmoney/repos/BrowserToolkitWorkspace/swerve/node_modules/@swizzyweb/swerve-manager/dist/swerve.js:61:47)\n at async SwerveManager.run (file:///home/jmoney/repos/BrowserToolkitWorkspace/swerve/node_modules/@swizzyweb/swerve-manager/dist/swerve.js:24:32)\n at async runV2 (file:///home/jmoney/repos/BrowserToolkitWorkspace/swerve/dist/bootstrapDeno.js:24:9)\n at async run (file:///home/jmoney/repos/BrowserToolkitWorkspace/swerve/dist/bootstrapDeno.js:34:16)","timestamp":"2025-08-11T03:55:34.253Z"}
@@ -1,2 +0,0 @@
1
- {"label":"jmoney-Laptop-16-AMD-Ryzen-7040-Series:::swerve:121451:swerve:","level":"info","message":"swerveArgs.services.length < 1","timestamp":"2025-08-11T03:55:34.243Z"}
2
- {"label":"jmoney-Laptop-16-AMD-Ryzen-7040-Series:::swerve:121451:swerve:","level":"error","message":"Exception running v2 TypeError: newWebServices is not iterable (cannot read property undefined)","timestamp":"2025-08-11T03:55:34.254Z"}
package/dist/main.ts DELETED
@@ -1,129 +0,0 @@
1
- // @ts-ignore
2
- import express, { Application } from "../node_modules/@swizzyweb/express";
3
- import {
4
- getArgs,
5
- installWebService,
6
- SwerveArgs,
7
- ISwerveManager,
8
- SwerveManager,
9
- } from "../node_modules/@swizzyweb/swerve-manager";
10
- import { SwizzyWinstonLogger } from "../node_modules/@swizzyweb/swizzy-web-service";
11
- import os from "node:os";
12
- import process from "node:process";
13
-
14
- export async function runV2(): Promise<ISwerveManager> {
15
- let gLogger = new SwizzyWinstonLogger({
16
- port: 0,
17
- logLevel: process.env.LOG_LEVEL ?? "info",
18
- appDataRoot: ".",
19
- appName: `swerve`,
20
- ownerName: "swerve",
21
- hostName: os.hostname(),
22
- pid: process.pid,
23
- });
24
-
25
- const swerveManager: ISwerveManager = new SwerveManager({});
26
- try {
27
- const args = await getArgs(process.argv, gLogger);
28
- await swerveManager.run({ args });
29
- return swerveManager;
30
- } catch (e) {
31
- gLogger.error(`Exception running v2 ${e}`);
32
- throw e;
33
- }
34
- }
35
- export async function run() {
36
- if (true) {
37
- return await runV2();
38
- }
39
- let gLogger = new SwizzyWinstonLogger({
40
- port: 0,
41
- logLevel: process.env.LOG_LEVEL ?? "info",
42
- appDataRoot: ".",
43
- appName: `swerve`,
44
- hostName: os.hostname(),
45
- pid: process.pid,
46
- });
47
-
48
- try {
49
- const args = await getArgs(process.argv, gLogger);
50
-
51
- const app = express();
52
- const webServices = await runWithApp({ app, args });
53
- const port = args.serviceArgs.port ?? 3005;
54
- gLogger.debug(`Starting express app...`);
55
- await app.listen(port, (err) => {
56
- if (err) {
57
- gLogger.log(err);
58
- }
59
- gLogger.info(
60
- `${webServices
61
- .map((service) => {
62
- return service.name;
63
- })
64
- .join(",")} running on port ${port}`,
65
- );
66
- });
67
- } catch (e) {
68
- gLogger.error(
69
- `Error occurred initializing service\n ${e.message}\n ${e.stack ?? {}}`,
70
- );
71
- }
72
- }
73
-
74
- interface RunWithAppArgs {
75
- app: Application;
76
- args: SwerveArgs;
77
- }
78
-
79
- export async function runWithApp(props: RunWithAppArgs) {
80
- const { app, args } = props;
81
- let gLogger = new SwizzyWinstonLogger({
82
- port: 0,
83
- logLevel: process.env.LOG_LEVEL ?? "info",
84
- appDataRoot: args.appDataRoot,
85
- appName: `swerve`,
86
- hostName: os.hostname(),
87
- pid: process.pid,
88
- });
89
-
90
- try {
91
- gLogger = new SwizzyWinstonLogger({
92
- logLevel: args.serviceArgs.logLevel ?? process.env.LOG_LEVEL ?? "info",
93
- port: args.port,
94
- logDir: args.appDataRoot,
95
- appName: `swerve`,
96
- hostName: os.hostname(),
97
- pid: process.pid,
98
- });
99
-
100
- gLogger.debug(`Swerve Args: ${JSON.stringify(args)}`);
101
-
102
- const PORT = args.port ?? 3005;
103
- const webServices = [];
104
- for (const serviceEntry of Object.entries(args.services)) {
105
- const service = serviceEntry[1];
106
- const packageName = service.packageName;
107
- const importPathOrName = service.servicePath;
108
- const webservice = await installWebService(
109
- packageName,
110
- importPathOrName,
111
- PORT,
112
- app,
113
- {
114
- appDataRoot: args.appDataRoot,
115
- ...service,
116
- ...service.serviceConfiguration,
117
- ...args.serviceArgs,
118
- },
119
- gLogger,
120
- );
121
- webServices.push(webservice);
122
- }
123
- return webServices;
124
- } catch (e) {
125
- gLogger.error(
126
- `Error occurred initializing service\n ${e.message}\n ${e.stack ?? {}}`,
127
- );
128
- }
129
- }
@@ -1,46 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import cluster from "node:cluster";
4
- import http from "node:http";
5
- import os from "node:os";
6
- import { run } from "./main.js";
7
- import process from "node:process";
8
- import { BrowserLogger } from "@swizzyweb/swizzy-common";
9
- import { SwizzyWinstonLogger } from "@swizzyweb/swizzy-web-service";
10
-
11
- import { getArgs } from "./utils/index.js";
12
- /**
13
- * extra arg:
14
- * numThreads - number, default to num cpu cores from os
15
- * */
16
- async function runCluster() {
17
- const args = await getArgs(process.argv, new BrowserLogger());
18
- const logger = new SwizzyWinstonLogger({
19
- port: args.port,
20
- // appDataRoot: args.appDataRoot,
21
- appName: `swerve-root`,
22
- hostName: os.hostname(),
23
- pid: process.pid,
24
- });
25
- const numThreads = args.serviceArgs?.numThreads ?? os.availableParallelism();
26
- if (cluster.isPrimary) {
27
- logger.info(`[ParentThread]: Primary ${process.pid} is running`);
28
- logger.info(`[ParentThread]: forking ${numThreads} threads`);
29
- // Fork workers.
30
- for (let i = 0; i < numThreads; i++) {
31
- cluster.fork();
32
- }
33
-
34
- cluster.on("exit", (worker, code, signal) => {
35
- logger.info(
36
- `[ParentThread]: worker ${worker.process.pid} died with code ${code} and singal ${signal}`,
37
- );
38
- });
39
- } else {
40
- // Workers can share any TCP connection
41
- // In this case it is an HTTP server
42
-
43
- run();
44
- console.log(`Worker ${process.pid} started`);
45
- }
46
- }
package/dist/swerve.d.ts DELETED
@@ -1,82 +0,0 @@
1
- import { Application } from "@swizzyweb/express";
2
- import { SwerveArgs } from "./utils/index.js";
3
- import { AnyServer, IWebService, WebService } from "@swizzyweb/swizzy-web-service";
4
- import { ILogger } from "@swizzyweb/swizzy-common";
5
- export interface ISwerveManager {
6
- run(request: RunRequest): Promise<RunResponse>;
7
- stop(request: StopRequest): Promise<void>;
8
- getRunningWebServices(props: GetRunningWebServiceRequest): Promise<GetRunningWebServiceResponse>;
9
- }
10
- export interface GetRunningWebServiceRequest {
11
- }
12
- export interface GetRunningWebServiceResponse {
13
- webServices: {
14
- [instanceId: string]: {
15
- webService: any;
16
- serviceConfig: any;
17
- };
18
- };
19
- }
20
- export declare enum InstanceType {
21
- webservice = "webservice",
22
- stack = "stack"
23
- }
24
- export interface InstanceDetails {
25
- instanceType: InstanceType;
26
- instanceId: string;
27
- }
28
- export interface StopRequest {
29
- instanceDetails: InstanceDetails;
30
- }
31
- export interface RunRequest {
32
- args?: SwerveArgs;
33
- }
34
- export interface RunResponse {
35
- webServices: WebService<any>[];
36
- }
37
- export type Apps = {
38
- [key: number]: {
39
- app: Application;
40
- server?: AnyServer;
41
- services: {
42
- [instanceId: string]: {
43
- webService: IWebService;
44
- serviceArgs: SwerveArgs;
45
- runRequest: RunRequest;
46
- };
47
- };
48
- };
49
- };
50
- export interface SwerveManagerProps {
51
- apps?: Apps;
52
- webServices?: WebService<any>[];
53
- }
54
- export interface WebServiceConfiguration {
55
- }
56
- type WebServiceConfigurations = {
57
- [instanceId: string]: WebServiceConfiguration;
58
- };
59
- export declare class SwerveManager implements ISwerveManager {
60
- apps: Apps;
61
- webServices: WebService<any>[];
62
- configurations: WebServiceConfigurations;
63
- constructor(props: SwerveManagerProps);
64
- run(request: RunRequest): Promise<RunResponse>;
65
- runWithArgs(request: RunRequest): Promise<WebService<any>[]>;
66
- private runWithApp;
67
- installWebService(props: {
68
- serviceKey: string;
69
- importPathOrName: string;
70
- app: Application;
71
- appDataRoot: string;
72
- packageName: string;
73
- port: number;
74
- gLogger: ILogger<any>;
75
- serviceArgs: {
76
- [key: string]: any;
77
- };
78
- }): Promise<any>;
79
- stop(request: StopRequest): Promise<void>;
80
- getRunningWebServices(props: GetRunningWebServiceRequest): Promise<GetRunningWebServiceResponse>;
81
- }
82
- export {};
package/dist/swerve.js DELETED
@@ -1,282 +0,0 @@
1
- // @ts-ignore
2
- import express from "@swizzyweb/express";
3
- import { getFullImportPath, getLoggerForService, } from "./utils/index.js";
4
- import { SwizzyWinstonLogger, } from "@swizzyweb/swizzy-web-service";
5
- import os from "node:os";
6
- import process from "node:process";
7
- import path from "path";
8
- import { mkdirSync } from "node:fs";
9
- export var InstanceType;
10
- (function (InstanceType) {
11
- InstanceType["webservice"] = "webservice";
12
- InstanceType["stack"] = "stack";
13
- })(InstanceType || (InstanceType = {}));
14
- export class SwerveManager {
15
- apps;
16
- webServices;
17
- configurations;
18
- constructor(props) {
19
- this.apps = props.apps ?? {};
20
- this.webServices = props.webServices ?? [];
21
- }
22
- async run(request) {
23
- const { args } = request;
24
- const newWebServices = await this.runWithArgs({
25
- args,
26
- });
27
- this.webServices.push(...newWebServices);
28
- return { webServices: newWebServices };
29
- }
30
- async runWithArgs(request) {
31
- const { args } = request;
32
- const logLevel = process.env.LOG_LEVEL ?? args.logLevel ?? "info";
33
- let gLogger = new SwizzyWinstonLogger({
34
- port: 0,
35
- logLevel,
36
- appDataRoot: args.appDataRoot ?? ".",
37
- appName: `swerve`,
38
- hostName: os.hostname(),
39
- ownerName: "swerve",
40
- pid: process.pid,
41
- });
42
- try {
43
- const webServices = [];
44
- const newApps = {};
45
- for (const serviceEntry of Object.entries(args.services)) {
46
- const port = serviceEntry[1].port ?? args.port;
47
- if (!this.apps[`${port}`]) {
48
- this.apps[`${port}`] = { app: await express(), services: {} };
49
- newApps[`${port}`] = this.apps[`${port}`];
50
- }
51
- const app = this.apps[`${port}`].app;
52
- const service = serviceEntry[1];
53
- const packageName = serviceEntry[0];
54
- const importPathOrName = service.servicePath ?? service.packageName;
55
- gLogger.debug(`importPathOrName ${importPathOrName}`);
56
- const serviceArgs = {
57
- ...service,
58
- ...service.serviceConfiguration,
59
- ...args.serviceArgs,
60
- };
61
- const webservice = await this.installWebService({
62
- serviceKey: serviceEntry[0],
63
- packageName,
64
- importPathOrName,
65
- port,
66
- app,
67
- appDataRoot: args.appDataRoot,
68
- serviceArgs,
69
- gLogger,
70
- });
71
- this.apps[`${port}`].services[webservice.instanceId] = {
72
- webService: webservice,
73
- serviceArgs,
74
- runRequest: request,
75
- };
76
- webServices.push(webservice);
77
- }
78
- for (const newAppEntry of Object.entries(newApps)) {
79
- const [port, appRecord] = newAppEntry;
80
- const newApp = appRecord.app;
81
- const server = await newApp.listen(port, () => {
82
- // this.apps[port].services[newApp.instanceId] = {};
83
- gLogger.debug(`New app listening on port ${port}`);
84
- });
85
- this.apps[`${port}`].server = server;
86
- }
87
- for (const webService of webServices) {
88
- gLogger.info(`${webService.name} running on port ${webService.port}`);
89
- }
90
- return webServices;
91
- }
92
- catch (e) {
93
- gLogger.error(`Error occurred initializing service\n ${e.message}\n ${e.stack ?? {}}`);
94
- }
95
- }
96
- async runWithApp(props) {
97
- const { app, args } = props;
98
- let gLogger = new SwizzyWinstonLogger({
99
- port: 0,
100
- logLevel: process.env.LOG_LEVEL ?? "info",
101
- appDataRoot: args.appDataRoot,
102
- appName: `swerve`,
103
- hostName: os.hostname(),
104
- pid: process.pid,
105
- });
106
- try {
107
- gLogger = new SwizzyWinstonLogger({
108
- logLevel: args.serviceArgs.logLevel ?? process.env.LOG_LEVEL ?? "info",
109
- port: args.port,
110
- logDir: args.appDataRoot,
111
- appName: `swerve`,
112
- hostName: os.hostname(),
113
- pid: process.pid,
114
- });
115
- gLogger.debug(`Swerve Args: ${JSON.stringify(args)}`);
116
- const PORT = args.port ?? 3005;
117
- const webServices = [];
118
- for (const serviceEntry of Object.entries(args.services)) {
119
- const service = serviceEntry[1];
120
- const packageName = service.packageName;
121
- const importPathOrName = service.servicePath ?? service.serviceArgs.servicePath ?? packageName;
122
- const webservice = await this.installWebService({
123
- serviceKey: serviceEntry[0],
124
- packageName,
125
- importPathOrName,
126
- port: PORT,
127
- app,
128
- appDataRoot: args.appDataRoot,
129
- serviceArgs: {
130
- ...service,
131
- ...service.serviceConfiguration,
132
- ...args.serviceArgs,
133
- },
134
- gLogger,
135
- });
136
- webServices.push(webservice);
137
- }
138
- return webServices;
139
- }
140
- catch (e) {
141
- gLogger.error(`Error occurred initializing service\n ${e.message}\n ${e.stack ?? {}}`);
142
- }
143
- }
144
- async installWebService(props) {
145
- // const packageName = importPathOrName;
146
- const { app, appDataRoot, packageName, port, gLogger, serviceArgs, importPathOrName, serviceKey, } = props;
147
- try {
148
- gLogger.info(`Getting webservice package ${packageName} and will run on port ${port}`);
149
- gLogger.debug(`Getting tool with path: ${importPathOrName}`);
150
- let tool;
151
- try {
152
- gLogger.debug(`Got service with require: ${JSON.stringify(tool)}`);
153
- gLogger.debug(`Getting web service from tool...`);
154
- tool = await import(importPathOrName);
155
- }
156
- catch (e) {
157
- gLogger.warn(`Error importing raw import path ${importPathOrName}, attempting again with fullImportPath. Err: ${e?.message}, stack: ${e?.stack}`);
158
- const fullPath = await getFullImportPath(importPathOrName);
159
- tool = await import(fullPath); //require(fullPath); //require(packageName as string);
160
- }
161
- const appDataPath = path.join(appDataRoot, "appdata", serviceKey);
162
- mkdirSync(appDataPath, { recursive: true });
163
- const logger = getLoggerForService(serviceArgs, serviceKey, port, gLogger);
164
- gLogger.debug(`serviceArgs for ${packageName}: ${serviceArgs}`);
165
- const service = await tool.getWebservice({
166
- appDataPath,
167
- port,
168
- ...serviceArgs,
169
- app,
170
- packageName,
171
- serviceArgs: { ...serviceArgs },
172
- logger,
173
- });
174
- logger.debug(`Got web service`);
175
- gLogger.debug(`Installing web service...`);
176
- await service.install({});
177
- gLogger.debug(`Installed web service ${packageName}`);
178
- return service;
179
- }
180
- catch (e) {
181
- const exceptionMessage = `exception: ${e}
182
- Failed to install web service, is it installed with NPM? Check package exists in node_modules
183
- To add, run:
184
- npm install ${packageName ?? "packageName"}
185
- args:
186
- packageName: ${packageName}
187
- port: ${port}
188
- `;
189
- // ${getHelpText}`;
190
- gLogger.error(`Failed to install web service`);
191
- throw e; //new Error(exceptionMessage);
192
- }
193
- }
194
- async stop(request) {
195
- const { instanceDetails } = request;
196
- const { instanceId, instanceType } = instanceDetails;
197
- const instanceIds = [];
198
- if (!instanceId) {
199
- throw new Error(`Instance id required to stop web service`);
200
- }
201
- if (instanceType === InstanceType.webservice) {
202
- // console.log(`Matched instance type`);
203
- instanceIds.push(`${instanceId}`);
204
- }
205
- else if (instanceType === InstanceType.stack) {
206
- // TODO: implement
207
- throw new Error(`Stack instance type is not yet supported`);
208
- }
209
- else {
210
- // this.logger.error(`Invalid instance details ${instanceDetails}`);
211
- throw new Error(`Invalid instance details provided`);
212
- }
213
- // console.log(`instanceIds: ${instanceIds}`);
214
- const webServices = this.webServices.filter((service) => {
215
- // console.log(`instanceId ${service.instanceId}`);
216
- return instanceIds.includes(`${service.instanceId}`);
217
- });
218
- if (!webServices || webServices.length < 1) {
219
- //console.error(webServices); //this.webServices);
220
- throw new Error(`WebService with instanceId ${instanceId} not found while attempting to stop`);
221
- }
222
- const ports = [];
223
- for (const webService of webServices) {
224
- const port = webService.port;
225
- ports.push(port);
226
- //console.log(webService);
227
- await webService.uninstall({});
228
- const indexes = this.webServices.map((val, index, array) => {
229
- //console.log(
230
- // `instanceInSwerve: ${val.instanceId} instanceInWebService ${webService.instanceId}`,
231
- // );
232
- if (val.instanceId == webService.instanceId) {
233
- return index;
234
- }
235
- });
236
- //.filter((val) => val);
237
- if (indexes.length > 1) {
238
- throw new Error(`Found multiple indexes for webservice instance ${webService.instanceId}`);
239
- }
240
- else if (indexes.length == 0) {
241
- throw new Error(`No indexes for webservice instance ${webService.instanceId}`);
242
- }
243
- const index = indexes[0];
244
- this.webServices.splice(index, 1);
245
- if (!this.apps[`${port}`]?.services[webService.instanceId]) {
246
- //console.log(`Apps does not contain service`);
247
- // TODO: DO SOMETHING, log, throw maybe.
248
- }
249
- else {
250
- delete this.apps[`${port}`].services[webService.instanceId];
251
- }
252
- }
253
- //cleanup apps if no more services
254
- for (const port of ports) {
255
- const { services, server, app } = this.apps[`${port}`];
256
- if (!services || Object.keys(services).length == 0) {
257
- if (server) {
258
- server.close();
259
- }
260
- else {
261
- continue;
262
- // TODO: do something, log throw etc
263
- }
264
- delete this.apps[`${port}`];
265
- }
266
- }
267
- }
268
- async getRunningWebServices(props) {
269
- const webservices = {};
270
- for (const webservice of this.webServices) {
271
- const instanceId = webservice.instanceId;
272
- const { runRequest, serviceArgs } = this.apps[webservice.port].services[instanceId];
273
- webservices[instanceId] = {
274
- webService: webservice.toJson(),
275
- serviceConfig: runRequest?.args,
276
- };
277
- }
278
- return {
279
- webServices: webservices,
280
- };
281
- }
282
- }
@@ -1,12 +0,0 @@
1
- import { ILogger } from "@swizzyweb/swizzy-common";
2
- import { IConfig, IService, KeyValue } from "../config/index.js";
3
- export declare function getServiceNameFromCurrentDirPackage(logger: ILogger<any>): string;
4
- export interface SwerveArgs extends IConfig {
5
- services: KeyValue<IService>;
6
- port: number;
7
- appDataRoot?: string;
8
- serviceArgs?: KeyValue<any>;
9
- logLevel: string;
10
- [key: string]: any;
11
- }
12
- export declare function getArgs(args: string[], logger: ILogger<any>): Promise<SwerveArgs>;
@@ -1,208 +0,0 @@
1
- import path from "path";
2
- import process from "node:process";
3
- import { SwerveConfigParser } from "../config/config-parser.js";
4
- import { deepMerge } from "@swizzyweb/swizzy-common";
5
- import { getPackageJson } from "./getPackageJson.js";
6
- function getHelpText() {
7
- return `Help --
8
- npm run server <serviceName> <port (optional)>
9
- `;
10
- }
11
- export function getServiceNameFromCurrentDirPackage(logger) {
12
- try {
13
- return process.cwd();
14
- }
15
- catch (e) {
16
- logger.debug(`Error getting package from current dir package.json ${e}`);
17
- throw e;
18
- }
19
- }
20
- function getAppDataRoot(appDataRootPath, logger) {
21
- try {
22
- let directory;
23
- if (!appDataRootPath || appDataRootPath === ".") {
24
- directory = getServiceNameFromCurrentDirPackage(logger);
25
- }
26
- else {
27
- directory = appDataRootPath;
28
- }
29
- return directory;
30
- }
31
- catch (e) {
32
- throw {
33
- message: `Unable to get app data root ${appDataRootPath}`,
34
- exception: e,
35
- };
36
- }
37
- }
38
- function getService(serviceName, logger) {
39
- try {
40
- let directory;
41
- let packageJson;
42
- if (!serviceName || serviceName === ".") {
43
- directory = getServiceNameFromCurrentDirPackage(logger);
44
- // packageJson = getPackageJsonFromDirectory(directory);
45
- const packageResult = getPackageJson(directory);
46
- packageJson = packageResult.packageJson;
47
- directory = packageResult.servicePath;
48
- }
49
- else if (serviceName && serviceName.startsWith(".")) {
50
- // directory = serviceName;
51
- // const jsonPath = path.join(serviceName);
52
- // packageJson = getPackageJsonFromDirectory(path.resolve(jsonPath));
53
- const packageResult = getPackageJson(serviceName);
54
- packageJson = packageResult.packageJson;
55
- directory = packageResult.servicePath;
56
- }
57
- else {
58
- return getPackageJson(serviceName);
59
- }
60
- const response = {
61
- servicePath: directory,
62
- packageJson,
63
- };
64
- logger.debug(`response ${response}`);
65
- return response;
66
- }
67
- catch (e) {
68
- const ex = {
69
- message: "Error getting service name",
70
- serviceName,
71
- error: e,
72
- };
73
- throw ex;
74
- }
75
- }
76
- function getDefaultArgs() {
77
- let currentServiceName = undefined;
78
- return {
79
- logLevel: "info",
80
- services: {},
81
- port: 3005,
82
- serviceArgs: {},
83
- };
84
- }
85
- const ARG_PREFIX = "--";
86
- const CONFIG_ARG_KEY = "config";
87
- function cliArgToPropertyName(rawArg) {
88
- return rawArg.replace(ARG_PREFIX, "");
89
- }
90
- const configParser = new SwerveConfigParser();
91
- async function getConfigValuesFromPath(configPath, logger) {
92
- try {
93
- return await configParser.parse(configPath);
94
- }
95
- catch (e) {
96
- logger.error(`Error occurred parsing config values from path`);
97
- throw {
98
- message: "Unexpected error occurred when attempting to read serviceConfiguration file",
99
- configFilePath: configPath,
100
- error: e,
101
- };
102
- }
103
- }
104
- const topLevelArgs = new Set();
105
- topLevelArgs.add("port");
106
- function isTopLevelArg(key) {
107
- return topLevelArgs.has(key);
108
- }
109
- function tryParseNumberArg(val) {
110
- try {
111
- return parseInt(val);
112
- }
113
- catch (e) {
114
- return false;
115
- }
116
- }
117
- function parseArgValue(val, logger) {
118
- try {
119
- return JSON.parse(val);
120
- }
121
- catch (e) {
122
- logger.warn(`Exception occurred while parsing arg value ${val}. This is sometimes expected. Error ${e}`);
123
- }
124
- return val;
125
- }
126
- const DEFAULT_PORT = 3005;
127
- export async function getArgs(args, logger) {
128
- let argKey = undefined;
129
- let swerveArgs = getDefaultArgs();
130
- let configFromFile;
131
- const serviceCounts = new Map();
132
- for (let i = 2; i < args.length; i++) {
133
- const nextVal = args[i];
134
- if (argKey) {
135
- if (argKey == CONFIG_ARG_KEY) {
136
- if (configFromFile) {
137
- throw new Error(`Config file already specified, you can only specify one config file with the --config arg`);
138
- }
139
- configFromFile = await getConfigValuesFromPath(nextVal, logger);
140
- argKey = undefined;
141
- continue;
142
- }
143
- swerveArgs.serviceArgs[argKey] = parseArgValue(nextVal, logger);
144
- argKey = undefined;
145
- continue;
146
- }
147
- if (nextVal.startsWith(ARG_PREFIX)) {
148
- argKey = cliArgToPropertyName(nextVal);
149
- continue;
150
- }
151
- const serviceDetails = getService(nextVal, logger);
152
- const serviceName = serviceDetails.packageJson.name;
153
- const serviceIndex = serviceCounts.get(serviceName) ?? 0;
154
- serviceCounts.set(serviceName, serviceIndex + 1);
155
- swerveArgs.services[`${serviceDetails.packageJson.name}-${serviceIndex}`] =
156
- {
157
- serviceConfiguration: {},
158
- ...serviceDetails,
159
- };
160
- }
161
- swerveArgs.port =
162
- configFromFile?.port ?? swerveArgs.serviceArgs?.port ?? DEFAULT_PORT;
163
- logger.debug(`configFromFile ${configFromFile}`);
164
- if (configFromFile?.services) {
165
- logger.debug(`ConfigFromFile has service`);
166
- for (const serviceEntry of Object.entries(configFromFile.services)) {
167
- let { servicePath, packageName } = serviceEntry[1];
168
- // serviceEntry[1].servicePath ?? serviceEntry[1].packageName;
169
- if (!servicePath) {
170
- serviceEntry[1].servicePath = packageName;
171
- // throw new Error(
172
- // `servicePath or packageName must be set in service configurations`,
173
- // );
174
- }
175
- else {
176
- const serviceData = getService(servicePath, logger);
177
- serviceEntry[1].packageName = serviceData.packageJson?.name;
178
- serviceEntry[1].servicePath = serviceData.servicePath;
179
- }
180
- // logger.debug(`ServiceName: ${}`);
181
- swerveArgs.services[serviceEntry[0]] = await deepMerge(await deepMerge(swerveArgs.serviceArgs ?? {}, serviceEntry.values() ?? {}), configFromFile.services[serviceEntry[0]]);
182
- }
183
- logger.debug(`packagedConfigFromFile into services`);
184
- }
185
- swerveArgs = deepMerge(swerveArgs, configFromFile ?? {});
186
- logger.debug(`${JSON.stringify(swerveArgs)}`);
187
- if (swerveArgs.serviceArgs?.appDataRoot?.startsWith(".") ||
188
- swerveArgs.serviceArgs?.appDataRoot == undefined) {
189
- const appDataRootPath = path.join(process.cwd());
190
- swerveArgs.appDataRoot = appDataRootPath;
191
- swerveArgs.serviceArgs.appDataRoot = appDataRootPath;
192
- }
193
- else {
194
- swerveArgs.appDataRoot = swerveArgs.serviceArgs.appDataRoot;
195
- }
196
- if (Object.keys(swerveArgs.services).length < 1) {
197
- logger.info(`swerveArgs.services.length < 1`);
198
- const { servicePath, packageJson } = getService(".", logger);
199
- swerveArgs.services[packageJson.name] = {
200
- servicePath,
201
- packageJson,
202
- appDataRoot: swerveArgs.appDataRoot,
203
- ...swerveArgs.serviceArgs,
204
- };
205
- }
206
- logger.debug(`getArgs complete with parsed swerveArgs: ${JSON.stringify(swerveArgs)}`);
207
- return swerveArgs;
208
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * Resolves the package.json file for a given package name or path.
3
- * @param packageNameOrPath Package name (e.g., 'lodash', '@nestjs/core') or path (e.g., './node_modules/lodash')
4
- * @returns Parsed package.json content or null
5
- */
6
- export declare function getPackageJson(packageNameOrPath: string): {
7
- packageJson: Record<string, any>;
8
- servicePath: string;
9
- } | null;
10
- /**
11
- * Get the nearest package.json of a given import name.
12
- * @param packageName The name of the imported package (e.g. "lodash")
13
- */
14
- export declare function getPackageJsonOrig(packageName: string): Record<string, any> | null;
@@ -1,74 +0,0 @@
1
- import * as fs from "fs";
2
- import * as path from "path";
3
- import { fileURLToPath, pathToFileURL } from "url";
4
- /**
5
- * Determines whether the input string is a relative or absolute path.
6
- */
7
- function isPath(input) {
8
- return input.startsWith(".") || path.isAbsolute(input);
9
- }
10
- /**
11
- * Resolves the package.json file for a given package name or path.
12
- * @param packageNameOrPath Package name (e.g., 'lodash', '@nestjs/core') or path (e.g., './node_modules/lodash')
13
- * @returns Parsed package.json content or null
14
- */
15
- export function getPackageJson(packageNameOrPath) {
16
- try {
17
- // Step 1: Resolve to an absolute path
18
- // const resolvedEntry = isPath(packageNameOrPath)
19
- // ? require.resolve(path.resolve(packageNameOrPath))
20
- // : // : require.resolve(packageNameOrPath);
21
- // require.resolve(packageNameOrPath, { paths: [process.cwd()] });
22
- const resolvedEntry = isPath(packageNameOrPath)
23
- ? pathToFileURL(path.resolve(packageNameOrPath)).href
24
- : import.meta.resolve(packageNameOrPath);
25
- // Step 2: Traverse upward to find the nearest package.json
26
- let dir = fileURLToPath(resolvedEntry); //path.dirname(resolvedEntry);
27
- while (dir !== path.parse(dir).root) {
28
- const pkgPath = path.join(dir, "package.json");
29
- if (fs.existsSync(pkgPath)) {
30
- const content = fs.readFileSync(pkgPath, "utf-8");
31
- const packageJson = JSON.parse(content);
32
- if (!dir || dir === ".") {
33
- dir = process.cwd();
34
- }
35
- else if (dir.startsWith(".")) {
36
- dir = path.join(process.cwd(), dir);
37
- }
38
- const entrypoint = path.join(dir, packageJson.main);
39
- // throw `Entrypoint is ${entrypoint}`;
40
- return { packageJson, servicePath: entrypoint };
41
- }
42
- dir = path.dirname(dir);
43
- }
44
- throw new Error(`Could not parse package.json`);
45
- }
46
- catch (err) {
47
- throw new Error(`Could not resolve package.json for "${packageNameOrPath}"`);
48
- }
49
- }
50
- /**
51
- * Get the nearest package.json of a given import name.
52
- * @param packageName The name of the imported package (e.g. "lodash")
53
- */
54
- export function getPackageJsonOrig(packageName) {
55
- try {
56
- // Resolve the entry file of the package
57
- const entryPath = import.meta.resolve(packageName); //require.resolve(packageName);
58
- // Traverse up from the resolved file to find package.json
59
- let dir = path.dirname(entryPath);
60
- while (dir !== path.parse(dir).root) {
61
- const pkgPath = path.join(dir, "package.json");
62
- if (fs.existsSync(pkgPath)) {
63
- const content = fs.readFileSync(pkgPath, "utf8");
64
- return { packageJson: JSON.parse(content), servicePath: dir };
65
- }
66
- dir = path.dirname(dir);
67
- }
68
- return null;
69
- }
70
- catch (error) {
71
- //console.error(`Failed to resolve package "${packageName}":`, error);
72
- return null;
73
- }
74
- }
@@ -1,2 +0,0 @@
1
- export * from "./getArgs.js";
2
- export * from "./installWebservice.js";
@@ -1,2 +0,0 @@
1
- export * from "./getArgs.js";
2
- export * from "./installWebservice.js";
@@ -1,4 +0,0 @@
1
- import { ILogger } from "@swizzyweb/swizzy-common";
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
- export declare function getLoggerForService(serviceArgs: any, appName: string, port: number, gLogger: ILogger<any>): ILogger<any>;
@@ -1,87 +0,0 @@
1
- import path from "path";
2
- import os from "node:os";
3
- import process from "node:process";
4
- import { mkdirSync } from "node:fs";
5
- import { fileURLToPath } from "node:url";
6
- export async function installWebService(appName, importPathOrName, port, expressApp, serviceArgs, gLogger) {
7
- const packageName = importPathOrName;
8
- try {
9
- gLogger.info(`Getting webservice package ${packageName} and will run on port ${port}`);
10
- gLogger.debug(`Getting tool with path: ${importPathOrName}`);
11
- const fullPath = importPathOrName; //await getFullImportPath(importPathOrName);
12
- const tool = await import(fullPath); //require(fullPath); //require(packageName as string);
13
- gLogger.debug(`Got service with require: ${JSON.stringify(tool)}`);
14
- gLogger.debug(`Getting web service from tool...`);
15
- const appDataPath = path.join(serviceArgs.appDataRoot, "appdata", appName);
16
- mkdirSync(appDataPath, { recursive: true });
17
- const logger = getLoggerForService(serviceArgs, serviceArgs.appName, port, gLogger);
18
- gLogger.debug(`serviceArgs for ${packageName}: ${serviceArgs}`);
19
- const service = await tool.getWebservice({
20
- appDataPath,
21
- ...serviceArgs,
22
- port,
23
- app: expressApp,
24
- packageName,
25
- serviceArgs: { ...serviceArgs },
26
- logger,
27
- });
28
- logger.debug(`Got web service`);
29
- gLogger.debug(`Installing web service...`);
30
- await service.install({});
31
- gLogger.debug(`Installed web service ${packageName}`);
32
- return service;
33
- }
34
- catch (e) {
35
- const exceptionMessage = `exception: ${e}
36
- Failed to install web service, is it installed with NPM? Check package exists in node_modules
37
- To add, run:
38
- npm install ${packageName ?? "packageName"}
39
- args:
40
- packageName: ${packageName}
41
- port: ${port}
42
- `;
43
- // ${getHelpText}`;
44
- gLogger.error(`Failed to install web service`);
45
- throw e; //new Error(exceptionMessage);
46
- }
47
- }
48
- export async function getFullImportPath(importPathOrName) {
49
- const importPath = importPathOrName.startsWith(".")
50
- ? path.join(process.cwd(), importPathOrName)
51
- : importPathOrName;
52
- let fullPath;
53
- if (importPathOrName === importPath) {
54
- const fullUrl = import.meta.resolve(importPath, import.meta.url);
55
- fullPath = fileURLToPath(fullUrl);
56
- // const pkg = await import(fullUrl, {
57
- // assert: { type: "json" },
58
- // });
59
- // await require.resolve(importPath, {
60
- // paths: [process.cwd()],
61
- // });
62
- }
63
- else {
64
- fullPath = importPath;
65
- }
66
- return fullPath;
67
- }
68
- export function getLoggerForService(serviceArgs, appName, port, gLogger) {
69
- const logLevel = serviceArgs.logLevel ?? gLogger.getLoggerProps().logLevel;
70
- const logFileName = serviceArgs.logFileName ?? undefined;
71
- const ownerName = appName;
72
- const pid = process.pid;
73
- const hostName = os.hostname();
74
- const logDir = serviceArgs.logDir;
75
- const appDataRoot = serviceArgs.appDataRoot;
76
- return gLogger.clone({
77
- port,
78
- appName,
79
- appDataRoot,
80
- logDir,
81
- hostName,
82
- pid,
83
- logLevel,
84
- ownerName,
85
- logFileName,
86
- });
87
- }