fix(core): Refactor filesystem usage to smartfs async provider, update dependencies, tests and nginx config paths

This commit is contained in:
2025-11-27 13:14:58 +00:00
parent 5700522b8a
commit 5781204c88
16 changed files with 7766 additions and 4139 deletions

View File

@@ -1,119 +0,0 @@
# gitzone ci_default
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
cache:
paths:
- .npmci_cache/
key: "$CI_BUILD_STAGE"
stages:
- security
- test
- release
- metadata
# ====================
# security stage
# ====================
mirror:
stage: security
script:
- npmci git mirror
tags:
- docker
- notpriv
snyk:
stage: security
script:
- npmci npm prepare
- npmci command npm install -g snyk
- npmci command npm install --ignore-scripts
- npmci command snyk test
tags:
- docker
- notpriv
# ====================
# test stage
# ====================
testLTS:
stage: test
script:
- npmci npm prepare
- npmci node install lts
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- priv
testBuild:
stage: test
script:
- npmci npm prepare
- npmci node install lts
- npmci npm install
- npmci command npm run build
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv
release:
stage: release
script:
- npmci node install lts
- npmci npm publish
only:
- tags
tags:
- docker
- notpriv
# ====================
# metadata stage
# ====================
codequality:
stage: metadata
allow_failure: true
script:
- npmci command npm install -g tslint typescript
- npmci npm install
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
tags:
- docker
- priv
trigger:
stage: metadata
script:
- npmci trigger
only:
- tags
tags:
- docker
- notpriv
pages:
image: hosttoday/ht-docker-dbase:npmci
services:
- docker:18-dind
stage: metadata
script:
- npmci command npm install -g @gitzone/tsdoc
- npmci npm prepare
- npmci npm install
- npmci command tsdoc
tags:
- docker
- notpriv
only:
- tags
artifacts:
expire_in: 1 week
paths:
- public
allow_failure: true

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2016 Lossless GmbH
Copyright (c) 2016 Task Venture Capital GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

59
changelog.md Normal file
View File

@@ -0,0 +1,59 @@
# Changelog
## 2025-11-27 - 2.0.53 - fix(core)
Refactor filesystem usage to smartfs async provider, update dependencies, tests and nginx config paths
- Replace @push.rocks/smartfile usage with @push.rocks/smartfs and introduce a shared SmartFs instance in plugins
- Convert sync file operations to async fs APIs (plugins.fs.file(...).write / plugins.fs.directory(...).create) in SmartNginx and NginxHost
- Adjust package.json: update test/build scripts, replace dependencies/devDependencies to new packages (@push.rocks/smartfs, @git.zone/*), and update versions
- Update test imports to new tapbundle path and node:path; export default tap.start() and remove unused Qenv instantiation
- Update internal path imports to 'node:path' and refactor smartnginx.plugins exports
- Change generated nginx certificate/config paths in configs from /mnt/HC_Volume_11396573/... to /mnt/data/... and regenerate default cert files
- Remove CI config (.gitlab-ci.yml) from repository
## 2024-05-29 - 2.0.52 - maintenance
Various metadata and TypeScript configuration updates; release 2.0.52.
- Update package description.
- Update tsconfig.
- Update npmextra.json (githost) entries across multiple commits.
- Release tag for 2.0.52.
## 2023-07-26 - 2.0.51 - maintenance
Org migration and core fixes; release 2.0.51.
- Switch to new organization scheme.
- fix(core): miscellaneous updates.
- Release tag for 2.0.51.
## 2019-01-09..2019-08-20 - 2.0.19..2.0.50 - maintenance (multiple patch releases)
Series of incremental patch releases with small fixes and cleanups.
- Many patch releases across the 2.0.x line (2.0.19 through 2.0.50).
- Multiple "fix(core): update" commits addressing internal issues.
- CI and cleanup fixes (including 2.0.38 cleanup).
- Release tags for each patch.
## 2018-08-10 - 2.0.0 - breaking
Major release and scope / packaging changes.
- 2.0.0 release with core updates.
- BREAKING CHANGE: change scope to @pushrocks (package scope/name changed).
- Various CI and core fixes accompanying the major release.
## 2016-08-03..2016-07-25 - 1.0.6..1.0.0 - release / maintenance
1.x series consolidations, dependency updates and interface exports.
- Update dependencies and types.
- Consolidate naming and start exporting interfaces.
- Add license.
- Release tags for 1.0.0 through 1.0.6.
## 2016-07-06..2016-07-25 - 0.0.0..0.1.0 - initial development
Initial implementation and feature work establishing core functionality.
- Initial project setup, README and CI added.
- Implement nginx communication and child process handling.
- Start storing generated configs to filesystem and improve config handling.
- Add snippets support and tests; multiple README improvements.
- Early releases and version tags (0.0.0 through 0.1.0).

View File

@@ -1,15 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@@ -1,13 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIB/zCCAWigAwIBAgIJH3Pl1mivagGCMA0GCSqGSIb3DQEBBQUAMB4xHDAaBgNV
BAMTE3NlbGZzaWduZWQuZ2l0LnpvbmUwHhcNMjMwNzI2MTQwNTIwWhcNMjQwNzI1
MTQwNTIwWjAeMRwwGgYDVQQDExNzZWxmc2lnbmVkLmdpdC56b25lMIGfMA0GCSqG
SIb3DQEBAQUAA4GNADCBiQKBgQD5b6wtr4xHY5gxH0SR+V9XIQPH6DGe2PXlKWN0
2dgvg7Ej/4uA7MmOnem2SUpWE2GwuKCAUCeZkj+riEmky0EWFexaM3BmcvWLSHZ6
MAYg5FxTsUG8IXxNYUdTPpUBxaCX/yp/dvpiDqSMH67y9LwI85oWHx/zk1jMixaZ
XvOCXwIDAQABo0UwQzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIC9DAmBgNVHREE
HzAdhhtodHRwOi8vZXhhbXBsZS5vcmcvd2ViaWQjbWUwDQYJKoZIhvcNAQEFBQAD
gYEAQ0pJ279EDgvsY+YjslMdUaJbZcF9rFgUE3t8vDDZH99kth8gqNddahcLqEV2
8hyx7qcnplpKNVx8DYvDWoTGRdXBhCP/TBBW3jdsqaBHJey+yfAISBk4pbOow260
tNQngsMDf+PZQMLm2bT1Pxk2KXd0rFMkVWprcRs2qx3Yz0Q=
MIIDBDCCAeygAwIBAgIJZid+XT7/NTaWMA0GCSqGSIb3DQEBBQUAMB4xHDAaBgNV
BAMTE3NlbGZzaWduZWQuZ2l0LnpvbmUwHhcNMjUxMTI3MTMxMzM0WhcNMjYxMTI3
MTMxMzM0WjAeMRwwGgYDVQQDExNzZWxmc2lnbmVkLmdpdC56b25lMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuO16Nu4tMkmBqsNWezt3ENqnsbWNUqC+
curHyXURaoIH2wQ16DIZaBIbO/WndNisMy6TnxJtiMVbKGKjkRH4w3qegthIRCKL
D3+Yl1ffqpHRz19hkNxVg4HfXRQMfH0Pnvd/4wB7g2mapk8SMwsTuEZ0j/7dAwc0
dqw94g+aehgZlvxUDFQjI/4kU9EiheDZ9TPREBMfeIb82zapINekKq5TkN/euWfs
fpbZZ6qWZvTX8NegulKOtDCCFauXKv2LNqy4jxWQef2XfMT8Jr4Txud3F8zqfexJ
Yq5ywjH07ecsyi7a/ifv7VLNXUEgwI6OFJHYnFZ314S6KlurocQUWQIDAQABo0Uw
QzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIC9DAmBgNVHREEHzAdhhtodHRwOi8v
ZXhhbXBsZS5vcmcvd2ViaWQjbWUwDQYJKoZIhvcNAQEFBQADggEBAH3qUHaBnNn+
e1qlZ0gUooJlLXU5tLGR9cVFV1dKuE5yxZhT0qal4A6Vif1mGKYXmHC4q0/atNsQ
RBvrbpoVtJxWpb6iIh1L5WWeP5OxqeLwZ8gp2Qj67CkwmccjIS66kkpwHBkBmXU9
nRlmGOj9OBHczqE0cp4dW6pCVvRtzC+wTX9oqAdmjyD8S8oo8I2fjCL4pJTPQtbV
RlaryWxlxscXYArA7iE9A5Cl5DdJtkOKS48Rbfw3BEQpgL0J4VeF8Lbb+ryk6BbG
XXkkH570cIdTs588gdfhkS8T6NIl+1Aicqmf+v6j3MHrzyLK3SZTQ83hoCRAEMfW
SPkrHSeL6h8=
-----END CERTIFICATE-----

View File

@@ -15,8 +15,8 @@ server {
server {
listen *:443 ssl;
server_name test100.bleu.de;
ssl_certificate /mnt/HC_Volume_11396573/lossless/push.rocks/smartnginx/nginxconfig/hosts/test100.bleu.de.public.pem;
ssl_certificate_key /mnt/HC_Volume_11396573/lossless/push.rocks/smartnginx/nginxconfig/hosts/test100.bleu.de.private.pem;
ssl_certificate /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/test100.bleu.de.public.pem;
ssl_certificate_key /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/test100.bleu.de.private.pem;
location / {
proxy_http_version 1.1;
proxy_buffering off;

View File

@@ -15,8 +15,8 @@ server {
server {
listen *:443 ssl;
server_name test102.bleu.de;
ssl_certificate /mnt/HC_Volume_11396573/lossless/push.rocks/smartnginx/nginxconfig/hosts/test102.bleu.de.public.pem;
ssl_certificate_key /mnt/HC_Volume_11396573/lossless/push.rocks/smartnginx/nginxconfig/hosts/test102.bleu.de.private.pem;
ssl_certificate /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/test102.bleu.de.public.pem;
ssl_certificate_key /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/test102.bleu.de.private.pem;
location / {
proxy_http_version 1.1;
proxy_buffering off;

View File

@@ -68,12 +68,12 @@ http {
server {
listen *:443 ssl default_server;
server_name selfsigned.git.zone;
ssl_certificate /mnt/HC_Volume_11396573/lossless/push.rocks/smartnginx/nginxconfig/hosts/default.public.pem;
ssl_certificate_key /mnt/HC_Volume_11396573/lossless/push.rocks/smartnginx/nginxconfig/hosts/default.private.pem;
ssl_certificate /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/default.public.pem;
ssl_certificate_key /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/default.private.pem;
rewrite ^ https://git.zone redirect;
}
include /mnt/HC_Volume_11396573/lossless/push.rocks/smartnginx/nginxconfig/hosts/*.conf;
include /mnt/data/lossless/push.rocks/smartnginx/nginxconfig/hosts/*.conf;
include /etc/nginx/sites-enabled/*;
}
daemon off;

View File

@@ -6,9 +6,9 @@
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
"scripts": {
"test": "tstest test/",
"test": "tstest test/ --verbose",
"cleanTest": "(rm -r nginxconfig) && npm run test",
"build": "(tsbuild --allowimplicitany)"
"build": "(tsbuild tsfolders --allowimplicitany)"
},
"repository": {
"type": "git",
@@ -30,22 +30,21 @@
},
"homepage": "https://code.foss.global/push.rocks/smartnginx",
"dependencies": {
"@push.rocks/lik": "^6.0.2",
"@push.rocks/smartfile": "^10.0.26",
"@push.rocks/smartlog": "^3.0.2",
"@push.rocks/smartpath": "^5.0.11",
"@push.rocks/smartpromise": "^4.0.2",
"@push.rocks/smartshell": "^3.0.3",
"@push.rocks/smartstring": "^4.0.7",
"@push.rocks/smartunique": "^3.0.3",
"selfsigned": "^2.1.1"
"@push.rocks/lik": "^6.2.2",
"@push.rocks/smartfs": "^1.1.0",
"@push.rocks/smartlog": "^3.1.10",
"@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartshell": "^3.3.0",
"@push.rocks/smartstring": "^4.1.0",
"@push.rocks/smartunique": "^3.0.9",
"selfsigned": "^4.0.0"
},
"devDependencies": {
"@gitzone/tsbuild": "^2.1.66",
"@gitzone/tsrun": "^1.2.44",
"@gitzone/tstest": "^1.0.77",
"@push.rocks/qenv": "^5.0.2",
"@push.rocks/tapbundle": "^5.0.8"
"@git.zone/tsbuild": "^3.1.0",
"@git.zone/tsrun": "^2.0.0",
"@git.zone/tstest": "^3.1.3",
"@push.rocks/qenv": "^6.1.3"
},
"files": [
"ts/**/*",

11280
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

270
readme.md
View File

@@ -1,81 +1,255 @@
# @push.rocks/smartnginx
control nginx from node, TypeScript ready
Control Nginx programmatically from Node.js with full TypeScript support 🚀
## Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
## Features
- 🎯 **Dynamic Configuration** - Generate and manage Nginx configs on the fly
- 🔒 **SSL/TLS Ready** - Built-in support for SSL certificates with automatic HTTP→HTTPS redirects
- 🔄 **Hot Reload** - Apply configuration changes without downtime
- 📦 **Zero-Config Defaults** - Self-signed certificates auto-generated for immediate testing
- 🎛️ **Reverse Proxy Made Easy** - Set up proxy hosts with a single method call
- 🧠 **Smart Diffing** - Only reloads Nginx when configurations actually change
- 📝 **TypeScript First** - Full type definitions included
## Install
To install `@push.rocks/smartnginx`, you can use npm (Node Package Manager). Open your terminal and run:
```bash
npm install @push.rocks/smartnginx --save
pnpm add @push.rocks/smartnginx
# or
npm install @push.rocks/smartnginx
```
This will download and install `@push.rocks/smartnginx` and its dependencies into your project's `node_modules` folder and save it as a dependency in your project's `package.json` file.
> **Prerequisites**: Nginx must be installed and available in your system PATH.
## Quick Start
```typescript
import { SmartNginx } from '@push.rocks/smartnginx';
// Create a SmartNginx instance with a default fallback URL
const nginx = new SmartNginx({
defaultProxyUrl: 'https://your-default-site.com'
});
// Add a reverse proxy host
nginx.addHostCandidate({
hostName: 'api.example.com',
destination: 'localhost',
destinationPort: 3000,
privateKey: '<your-ssl-private-key>',
publicKey: '<your-ssl-certificate>'
});
// Deploy and start Nginx
await nginx.deploy();
```
That's it! Your reverse proxy is now running 🎉
## Usage
`@push.rocks/smartnginx` is a powerful library for interacting with Nginx programmatically using Node.js and TypeScript. It simplifies tasks such as configuring hosts, deploying configurations, and managing SSL certificates. Below is a comprehensive guide to using the library effectively in your TypeScript projects.
### Getting Started
First, ensure you have imported the library into your TypeScript file. Use ESM syntax as shown:
```typescript
import { SmartNginx, NginxHost } from '@push.rocks/smartnginx';
```
### Creating the SmartNginx Instance
The `SmartNginx` class is your main interface for managing Nginx:
### Initialize SmartNginx
Before you interact with Nginx, you need to create an instance of `SmartNginx`. This object acts as the main interface to your Nginx server. You can specify a default proxy URL that requests will be redirected to if no matching host is found.
```typescript
const smartNginx = new SmartNginx({
defaultProxyUrl: 'https://your-default-url.com'
import { SmartNginx } from '@push.rocks/smartnginx';
const nginx = new SmartNginx({
defaultProxyUrl: 'https://fallback.example.com', // Where unmatched requests go
logger: myCustomLogger // Optional: pass a @push.rocks/smartlog instance
});
```
### Add Host Candidates
To serve content or applications via Nginx, you will define hosts. Each host corresponds to a domain or subdomain and can be configured with specific rules. Here's how to add host candidates:
### Adding Host Configurations
Each host represents a domain/subdomain with its proxy rules and SSL certificates:
```typescript
const myHost = smartNginx.addHostCandidate({
hostName: 'example.com',
// Add a host using addHostCandidate()
const myHost = nginx.addHostCandidate({
hostName: 'app.example.com', // Domain name
destination: '127.0.0.1', // Backend server address
destinationPort: 8080, // Backend port
privateKey: sslPrivateKeyPem, // SSL private key (PEM format)
publicKey: sslCertificatePem // SSL certificate (PEM format)
});
```
### Multi-Host Setup
Run multiple sites through a single Nginx instance:
```typescript
// Production API
nginx.addHostCandidate({
hostName: 'api.myapp.com',
destination: 'localhost',
destinationPort: 3000,
privateKey: apiPrivateKey,
publicKey: apiCertificate
});
// Admin panel
nginx.addHostCandidate({
hostName: 'admin.myapp.com',
destination: 'localhost',
destinationPort: 4000,
privateKey: adminPrivateKey,
publicKey: adminCertificate
});
// Staging environment
nginx.addHostCandidate({
hostName: 'staging.myapp.com',
destination: '192.168.1.100',
destinationPort: 8080,
privateKey: '<Your SSL Private Key>',
publicKey: '<Your SSL Public Key>'
privateKey: stagingPrivateKey,
publicKey: stagingCertificate
});
// Deploy all at once
await nginx.deploy();
```
Replace `'example.com'`, `'localhost'`, `8080`, `'<Your SSL Private Key>'`, and `'<Your SSL Public Key>'` with your actual host name, destination IP or hostname, port number, and SSL keys respectively.
### Deploying Configuration
After adding all your host candidates, you will need to apply these configurations for Nginx to recognize and use them. Deploy the configuration as follows:
### Deploying Configurations
The `deploy()` method is smart about changes:
```typescript
await smartNginx.deploy();
```
This method checks for any changes in your host configurations compared to what's currently deployed and updates the Nginx configuration accordingly.
// First deploy - writes configs and starts Nginx
await nginx.deploy();
### Managing SSL Certificates
When setting up SSL for your hosts, you will provide the paths to the private key and public certificate. It's essential to ensure these files are securely stored and accessible by the library during deployment.
### Handling Multiple Hosts
You can add multiple host candidates using `addHostCandidate` method for different domains or subdomains, each with unique configurations. Here's an example of adding another host:
```typescript
const anotherHost = smartNginx.addHostCandidate({
hostName: 'sub.example.com',
// Add more hosts dynamically
nginx.addHostCandidate({
hostName: 'newsite.example.com',
destination: 'localhost',
destinationPort: 9090,
privateKey: '<Another SSL Private Key>',
publicKey: '<Another SSL Public Key>'
destinationPort: 5000,
privateKey: newPrivateKey,
publicKey: newCertificate
});
// Second deploy - detects changes, updates configs, hot-reloads Nginx
await nginx.deploy();
// If you call deploy() with no changes, it skips the reload (efficient!)
await nginx.deploy(); // → "hosts have not diverged, skipping nginx reload"
```
### Reloading Configurations
If at any time you make changes to your host configurations and need to apply these changes, simply call the `deploy` method again. `@push.rocks/smartnginx` efficiently detects changes and reloads Nginx with the new configurations.
### Querying Deployed Hosts
### Stopping SmartNginx
To stop the Nginx process managed by `@push.rocks/smartnginx`, use:
```typescript
await smartNginx.stop();
```
Bear in mind that this might affect your web services if they rely on the Nginx instance you are stopping.
// Get all deployed hosts
const hosts = await nginx.listDeployedHosts();
console.log(`Running ${hosts.length} hosts`);
### Conclusion
`@push.rocks/smartnginx` abstracts away much of the complexity involved in managing Nginx configurations, offering a TypeScript-ready solution for Node.js projects. With simple method calls, you can automate and manage your Nginx server programmatically, making it an excellent tool for developers seeking to integrate Nginx management into their applications or deployment workflows.
// Find a specific host by domain
const apiHost = nginx.getDeployedNginxHostByHostName('api.example.com');
if (apiHost) {
console.log(`API proxying to ${apiHost.destination}:${apiHost.destinationPort}`);
}
```
### Removing Hosts
```typescript
const hostToRemove = nginx.getDeployedNginxHostByHostName('staging.myapp.com');
if (hostToRemove) {
await nginx.removeDeployedHost(hostToRemove);
// Nginx automatically reloaded with updated config
}
```
### Stopping Nginx
```typescript
// Gracefully stop the Nginx process
await nginx.stop();
```
## Generated Configuration
SmartNginx generates production-ready Nginx configurations:
**For each host, you get:**
- HTTP (port 80) → HTTPS (port 443) automatic redirect
- Upstream with keepalive connections (100 idle connections)
- WebSocket-friendly proxy settings (HTTP/1.1, no buffering)
- Proper proxy headers (`X-Real-IP`, `X-Forwarded-For`, `X-Forwarded-Proto`)
- Smart failover (`proxy_next_upstream` on errors, timeouts, 404/429/500/502)
**Default server:**
- Self-signed certificate for unmatched domains
- Redirects to your configured `defaultProxyUrl`
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ SmartNginx │
├─────────────────────────────────────────────────────────────┤
│ hostCandidates[] → deploy() → deployedHosts[] │
│ ↓ │
│ NginxProcess │
│ (start/reload/stop) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Generated Files │
├─────────────────────────────────────────────────────────────┤
│ nginxconfig/ │
│ ├── nginx.conf (main config) │
│ └── hosts/ │
│ ├── default.private.pem (self-signed key) │
│ ├── default.public.pem (self-signed cert) │
│ ├── api.example.com.conf │
│ ├── api.example.com.private.pem │
│ └── api.example.com.public.pem │
└─────────────────────────────────────────────────────────────┘
```
## API Reference
### SmartNginx
| Method | Description |
|--------|-------------|
| `addHostCandidate(config)` | Add a new host configuration |
| `deploy()` | Write configs and start/reload Nginx |
| `listDeployedHosts()` | Get all currently deployed hosts |
| `getDeployedNginxHostByHostName(hostname)` | Find a host by domain name |
| `removeDeployedHost(host)` | Remove a host and reload Nginx |
| `stop()` | Gracefully stop Nginx |
### IHostConfig
```typescript
interface IHostConfig {
hostName: string; // Domain name (e.g., 'api.example.com')
destination: string; // Backend server IP/hostname
destinationPort: number; // Backend port
privateKey: string; // SSL private key (PEM)
publicKey: string; // SSL certificate (PEM)
}
```
### NginxHost
Each host instance exposes:
- `hostName` - The configured domain
- `destination` - Backend address
- `destinationPort` - Backend port
- `configString` - The generated Nginx config (after deploy)
- `deploy()` - Write this host's config files
## License and Legal Information
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
@@ -85,7 +259,7 @@ This project is owned and maintained by Task Venture Capital GmbH. The names and
### Company Information
Task Venture Capital GmbH
Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.

View File

@@ -1,8 +1,7 @@
import { tap, expect } from '@push.rocks/tapbundle';
import path = require('path');
import { tap, expect } from '@git.zone/tstest/tapbundle';
import * as path from 'node:path';
import { Qenv } from '@push.rocks/qenv';
const testQenv = new Qenv('./', './.nogit/');
import * as smartnginx from '../ts/index.js';
@@ -52,4 +51,4 @@ tap.test('.stop() should end the process', async () => {
testSmartNginx.nginxProcess.stop();
});
tap.start();
export default tap.start();

View File

@@ -1,8 +1,8 @@
/**
* autocreated commitinfo by @pushrocks/commitinfo
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@push.rocks/smartnginx',
version: '2.0.52',
description: 'control nginx from node, TypeScript ready'
version: '2.0.53',
description: 'A TypeScript library for controlling Nginx from Node.js, with support for generating and managing Nginx configurations dynamically.'
}

View File

@@ -53,10 +53,10 @@ export class NginxHost implements IHostConfig {
this.destination,
this.destinationPort
);
plugins.smartfile.memory.toFsSync(this.configString, filePathConfig);
await plugins.fs.file(filePathConfig).write(this.configString);
// write ssl
plugins.smartfile.memory.toFsSync(this.privateKey, filePathPrivate);
plugins.smartfile.memory.toFsSync(this.publicKey, filePathPublic);
await plugins.fs.file(filePathPrivate).write(this.privateKey);
await plugins.fs.file(filePathPublic).write(this.publicKey);
}
}

View File

@@ -116,10 +116,9 @@ export class SmartNginx {
this.hostCandidates.wipe();
// write base config
plugins.smartfile.fs.ensureDirSync(paths.nginxConfigDirPath);
plugins.smartfile.memory.toFsSync(
snippets.getBaseConfigString(this.options.defaultProxyUrl),
paths.nginxConfFile
await plugins.fs.directory(paths.nginxConfigDirPath).recursive().create();
await plugins.fs.file(paths.nginxConfFile).write(
snippets.getBaseConfigString(this.options.defaultProxyUrl)
);
// write standard self signed certificate
@@ -129,15 +128,13 @@ export class SmartNginx {
);
// deploy hosts
plugins.smartfile.fs.ensureDirSync(paths.nginxHostDirPath);
plugins.smartfile.memory.toFsSync(
selfsignedCert.private,
await plugins.fs.directory(paths.nginxHostDirPath).recursive().create();
await plugins.fs.file(
plugins.path.join(paths.nginxHostDirPath, './default.private.pem')
);
plugins.smartfile.memory.toFsSync(
selfsignedCert.cert,
).write(selfsignedCert.private);
await plugins.fs.file(
plugins.path.join(paths.nginxHostDirPath, './default.public.pem')
);
).write(selfsignedCert.cert);
for (const host of this.deployedHosts.getArray()) {
await host.deploy();
this.logger.log('info', `Host ${host.hostName} deployed!`);

View File

@@ -1,19 +1,23 @@
// native
import * as path from 'path';
import * as path from 'node:path';
export { path };
// @pushrocks scope
import * as lik from '@push.rocks/lik';
import * as smartfile from '@push.rocks/smartfile';
import * as smartlog from '@push.rocks/smartlog';
import * as smartpath from '@push.rocks/smartpath';
import * as smartpromise from '@push.rocks/smartpromise';
import * as smartshell from '@push.rocks/smartshell';
import * as smartstring from '@push.rocks/smartstring';
import * as smartunique from '@push.rocks/smartunique';
// @push.rocks scope
import * as lik from '@push.rocks/lik';
import * as smartfs from '@push.rocks/smartfs';
import * as smartlog from '@push.rocks/smartlog';
import * as smartpath from '@push.rocks/smartpath';
import * as smartpromise from '@push.rocks/smartpromise';
import * as smartshell from '@push.rocks/smartshell';
import * as smartstring from '@push.rocks/smartstring';
import * as smartunique from '@push.rocks/smartunique';
export { lik, smartfile, smartlog, smartpath, smartpromise, smartshell, smartstring, smartunique };
export { lik, smartfs, smartlog, smartpath, smartpromise, smartshell, smartstring, smartunique };
// Shared filesystem instance
const fsProvider = new smartfs.SmartFsProviderNode();
export const fs = new smartfs.SmartFs(fsProvider);
// thirdparty scope
import * as selfsigned from 'selfsigned';