@simplysm/service-server 13.0.71 → 13.0.74
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 +55 -72
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/services/smtp-client-service.d.ts +8 -0
- package/dist/services/smtp-client-service.d.ts.map +1 -0
- package/dist/services/smtp-client-service.js +46 -0
- package/dist/services/smtp-client-service.js.map +6 -0
- package/package.json +9 -7
- package/src/index.ts +1 -0
- package/src/services/smtp-client-service.ts +59 -0
package/README.md
CHANGED
|
@@ -2,78 +2,61 @@
|
|
|
2
2
|
|
|
3
3
|
Simplysm package - service module (server)
|
|
4
4
|
|
|
5
|
+
Provides a full-featured HTTP/WebSocket server built on Fastify for hosting Simplysm services. Includes JWT-based authentication, ORM integration, file upload/static serving, SMTP email, and auto-update capabilities.
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
9
|
+
```bash
|
|
7
10
|
pnpm add @simplysm/service-server
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
|
41
|
-
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
|
49
|
-
|
|
50
|
-
| `
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
| Source | Exports | Description | Test |
|
|
62
|
-
|--------|---------|-------------|------|
|
|
63
|
-
| `src/utils/config-manager.ts` | `getConfig` | Load and cache JSON config files with live-reload via file watcher | - |
|
|
64
|
-
|
|
65
|
-
### Legacy
|
|
66
|
-
|
|
67
|
-
| Source | Exports | Description | Test |
|
|
68
|
-
|--------|---------|-------------|------|
|
|
69
|
-
| `src/legacy/v1-auto-update-handler.ts` | `handleV1Connection` | Handle V1 legacy WebSocket clients for auto-update only | - |
|
|
70
|
-
|
|
71
|
-
### Main
|
|
72
|
-
|
|
73
|
-
| Source | Exports | Description | Test |
|
|
74
|
-
|--------|---------|-------------|------|
|
|
75
|
-
| `src/service-server.ts` | `ServiceServer`, `createServiceServer` | Main Fastify-based HTTP/WebSocket server with routing and graceful shutdown | - |
|
|
76
|
-
|
|
77
|
-
## License
|
|
78
|
-
|
|
79
|
-
Apache-2.0
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Architecture Overview
|
|
14
|
+
|
|
15
|
+
The package is organized into four areas:
|
|
16
|
+
|
|
17
|
+
- **Auth** — JWT token signing, verification, and decoding (`signJwt`, `verifyJwt`, `decodeJwt`, `AuthTokenPayload`).
|
|
18
|
+
- **Services** — Service definition API (`defineService`, `auth`, `ServiceContext`, `runServiceMethod`) and three ready-to-use built-in services (`OrmService`, `AutoUpdateService`, `SmtpClientService`).
|
|
19
|
+
- **Transport** — WebSocket connection management (`WebSocketHandler`, `ServiceSocket`), HTTP route handlers (`handleHttpRequest`, `handleUpload`, `handleStaticFile`), and the binary protocol layer (`ProtocolWrapper`). Also includes the legacy v1 compatibility handler.
|
|
20
|
+
- **Server** — The `ServiceServer` class and `createServiceServer` factory that wire everything together, plus the `getConfig` utility for reading `.config.json`.
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { createServiceServer, defineService, OrmService } from "@simplysm/service-server";
|
|
26
|
+
|
|
27
|
+
const GreetService = defineService("Greet", (ctx) => ({
|
|
28
|
+
hello: (name: string) => `Hello, ${name}!`,
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
const server = createServiceServer({
|
|
32
|
+
rootPath: "./dist",
|
|
33
|
+
port: 3000,
|
|
34
|
+
auth: { jwtSecret: "my-secret" },
|
|
35
|
+
services: [GreetService, OrmService],
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await server.listen();
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Exported Types
|
|
42
|
+
|
|
43
|
+
| Type | Description |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `ServiceServerOptions` | Options object for `ServiceServer` / `createServiceServer` |
|
|
46
|
+
| `AuthTokenPayload<TAuthInfo>` | JWT payload with `roles` and typed `data` |
|
|
47
|
+
| `ServiceContext<TAuthInfo>` | Context injected into every service factory |
|
|
48
|
+
| `ServiceDefinition<TMethods>` | Return type of `defineService` |
|
|
49
|
+
| `ServiceMethods<TDefinition>` | Extracts method map type from a `ServiceDefinition` |
|
|
50
|
+
| `WebSocketHandler` | Manages all active WebSocket connections |
|
|
51
|
+
| `ServiceSocket` | Represents a single active WebSocket connection |
|
|
52
|
+
| `ProtocolWrapper` | Encode/decode service messages with optional worker offload |
|
|
53
|
+
| `OrmServiceType` | Method map type for `OrmService` |
|
|
54
|
+
| `AutoUpdateServiceType` | Method map type for `AutoUpdateService` |
|
|
55
|
+
| `SmtpClientServiceType` | Method map type for `SmtpClientService` |
|
|
56
|
+
|
|
57
|
+
## Detailed Documentation
|
|
58
|
+
|
|
59
|
+
- [docs/auth.md](docs/auth.md) — `AuthTokenPayload`, `signJwt`, `verifyJwt`, `decodeJwt`
|
|
60
|
+
- [docs/services.md](docs/services.md) — `defineService`, `auth`, `ServiceContext`, `runServiceMethod`, `OrmService`, `AutoUpdateService`, `SmtpClientService`
|
|
61
|
+
- [docs/transport.md](docs/transport.md) — `WebSocketHandler`, `ServiceSocket`, `handleHttpRequest`, `handleUpload`, `handleStaticFile`, `ProtocolWrapper`, legacy handler
|
|
62
|
+
- [docs/server.md](docs/server.md) — `ServiceServerOptions`, `ServiceServer`, `createServiceServer`, `getConfig`
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export * from "./transport/http/static-file-handler";
|
|
|
11
11
|
export * from "./protocol/protocol-wrapper";
|
|
12
12
|
export * from "./services/orm-service";
|
|
13
13
|
export * from "./services/auto-update-service";
|
|
14
|
+
export * from "./services/smtp-client-service";
|
|
14
15
|
export * from "./utils/config-manager";
|
|
15
16
|
export * from "./legacy/v1-auto-update-handler";
|
|
16
17
|
export * from "./service-server";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["..\\src\\index.ts"],"names":[],"mappings":"AACA,cAAc,wBAAwB,CAAC;AAGvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AAGnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAGlD,cAAc,uCAAuC,CAAC;AACtD,cAAc,iCAAiC,CAAC;AAChD,cAAc,sCAAsC,CAAC;AAGrD,cAAc,6BAA6B,CAAC;AAG5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAG/C,cAAc,wBAAwB,CAAC;AAGvC,cAAc,iCAAiC,CAAC;AAGhD,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["..\\src\\index.ts"],"names":[],"mappings":"AACA,cAAc,wBAAwB,CAAC;AAGvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AAGnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAGlD,cAAc,uCAAuC,CAAC;AACtD,cAAc,iCAAiC,CAAC;AAChD,cAAc,sCAAsC,CAAC;AAGrD,cAAc,6BAA6B,CAAC;AAG5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAG/C,cAAc,wBAAwB,CAAC;AAGvC,cAAc,iCAAiC,CAAC;AAGhD,cAAc,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export * from "./transport/http/static-file-handler.js";
|
|
|
11
11
|
export * from "./protocol/protocol-wrapper.js";
|
|
12
12
|
export * from "./services/orm-service.js";
|
|
13
13
|
export * from "./services/auto-update-service.js";
|
|
14
|
+
export * from "./services/smtp-client-service.js";
|
|
14
15
|
export * from "./utils/config-manager.js";
|
|
15
16
|
export * from "./legacy/v1-auto-update-handler.js";
|
|
16
17
|
export * from "./service-server.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"mappings": "AACA,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AAGd,cAAc;",
|
|
4
|
+
"mappings": "AACA,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AAGd,cAAc;",
|
|
5
5
|
"names": []
|
|
6
6
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ServiceMethods } from "../core/define-service";
|
|
2
|
+
import type { SmtpClientSendByDefaultOption, SmtpClientSendOption } from "@simplysm/service-common";
|
|
3
|
+
export declare const SmtpClientService: import("..").ServiceDefinition<{
|
|
4
|
+
send(options: SmtpClientSendOption): Promise<string>;
|
|
5
|
+
sendByConfig(configName: string, options: SmtpClientSendByDefaultOption): Promise<string>;
|
|
6
|
+
}>;
|
|
7
|
+
export type SmtpClientServiceType = ServiceMethods<typeof SmtpClientService>;
|
|
8
|
+
//# sourceMappingURL=smtp-client-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smtp-client-service.d.ts","sourceRoot":"","sources":["..\\..\\src\\services\\smtp-client-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,KAAK,EAEV,6BAA6B,EAC7B,oBAAoB,EACrB,MAAM,0BAA0B,CAAC;AAElC,eAAO,MAAM,iBAAiB;kBACR,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;6BA6B3B,MAAM,WAAW,6BAA6B,GAAG,OAAO,CAAC,MAAM,CAAC;EAkB9F,CAAC;AAEJ,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import nodemailer from "nodemailer";
|
|
2
|
+
import { defineService } from "../core/define-service.js";
|
|
3
|
+
const SmtpClientService = defineService("SmtpClient", (ctx) => ({
|
|
4
|
+
async send(options) {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
const transport = nodemailer.createTransport({
|
|
7
|
+
host: options.host,
|
|
8
|
+
port: options.port,
|
|
9
|
+
secure: options.secure,
|
|
10
|
+
auth: options.user != null ? {
|
|
11
|
+
user: options.user,
|
|
12
|
+
pass: options.pass
|
|
13
|
+
} : void 0,
|
|
14
|
+
tls: {
|
|
15
|
+
rejectUnauthorized: false
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
transport.sendMail(options, (err, info) => {
|
|
19
|
+
if (err) {
|
|
20
|
+
reject(err);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
resolve(info.messageId);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
async sendByConfig(configName, options) {
|
|
28
|
+
const config = (await ctx.getConfig("smtp"))[configName];
|
|
29
|
+
if (config == null) {
|
|
30
|
+
throw new Error(`SMTP config not found: ${configName}`);
|
|
31
|
+
}
|
|
32
|
+
return this.send({
|
|
33
|
+
user: config.user,
|
|
34
|
+
pass: config.pass,
|
|
35
|
+
host: config.host,
|
|
36
|
+
port: config.port,
|
|
37
|
+
secure: config.secure,
|
|
38
|
+
from: `"${config.senderName}" <${config.senderEmail ?? config.user}>`,
|
|
39
|
+
...options
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}));
|
|
43
|
+
export {
|
|
44
|
+
SmtpClientService
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=smtp-client-service.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/services/smtp-client-service.ts"],
|
|
4
|
+
"mappings": "AAAA,OAAO,gBAAgB;AACvB,SAAS,qBAA0C;AAO5C,MAAM,oBAAoB,cAAc,cAAc,CAAC,SAAS;AAAA,EACrE,MAAM,KAAK,SAAgD;AACzD,WAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,YAAM,YAAY,WAAW,gBAAgB;AAAA,QAC3C,MAAM,QAAQ;AAAA,QACd,MAAM,QAAQ;AAAA,QACd,QAAQ,QAAQ;AAAA,QAChB,MACE,QAAQ,QAAQ,OACZ;AAAA,UACE,MAAM,QAAQ;AAAA,UACd,MAAM,QAAQ;AAAA,QAChB,IACA;AAAA,QACN,KAAK;AAAA,UACH,oBAAoB;AAAA,QACtB;AAAA,MACF,CAAC;AAED,gBAAU,SAAS,SAAuC,CAAC,KAAK,SAAS;AACvE,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AAEA,gBAAQ,KAAK,SAAS;AAAA,MACxB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aAAa,YAAoB,SAAyD;AAC9F,UAAM,UACJ,MAAM,IAAI,UAA+D,MAAM,GAC/E,UAAU;AACZ,QAAI,UAAU,MAAM;AAClB,YAAM,IAAI,MAAM,0BAA0B,UAAU,EAAE;AAAA,IACxD;AAEA,WAAO,KAAK,KAAK;AAAA,MACf,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,QAAQ,OAAO;AAAA,MACf,MAAM,IAAI,OAAO,UAAU,MAAM,OAAO,eAAe,OAAO,IAAI;AAAA,MAClE,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AACF,EAAE;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/service-server",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.74",
|
|
4
4
|
"description": "Simplysm package - service module (server)",
|
|
5
5
|
"author": "simplysm",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@fastify/cors": "^11.2.0",
|
|
23
23
|
"@fastify/helmet": "^13.0.2",
|
|
24
|
-
"@fastify/middie": "^9.
|
|
24
|
+
"@fastify/middie": "^9.2.0",
|
|
25
25
|
"@fastify/multipart": "^9.4.0",
|
|
26
26
|
"@fastify/reply-from": "^12.6.0",
|
|
27
27
|
"@fastify/static": "^9.0.0",
|
|
@@ -31,16 +31,18 @@
|
|
|
31
31
|
"fastify": "^5.7.4",
|
|
32
32
|
"jose": "^6.1.3",
|
|
33
33
|
"mime": "^4.1.0",
|
|
34
|
+
"nodemailer": "^8.0.1",
|
|
34
35
|
"semver": "^7.7.4",
|
|
35
36
|
"utf-8-validate": "^6.0.6",
|
|
36
37
|
"ws": "^8.19.0",
|
|
37
|
-
"@simplysm/core-
|
|
38
|
-
"@simplysm/core-
|
|
39
|
-
"@simplysm/orm-common": "13.0.
|
|
40
|
-
"@simplysm/orm-node": "13.0.
|
|
41
|
-
"@simplysm/service-common": "13.0.
|
|
38
|
+
"@simplysm/core-common": "13.0.74",
|
|
39
|
+
"@simplysm/core-node": "13.0.74",
|
|
40
|
+
"@simplysm/orm-common": "13.0.74",
|
|
41
|
+
"@simplysm/orm-node": "13.0.74",
|
|
42
|
+
"@simplysm/service-common": "13.0.74"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
45
|
+
"@types/nodemailer": "^6.4.23",
|
|
44
46
|
"@types/semver": "^7.7.1",
|
|
45
47
|
"@types/ws": "^8.18.1"
|
|
46
48
|
}
|
package/src/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ export * from "./protocol/protocol-wrapper";
|
|
|
24
24
|
// Services
|
|
25
25
|
export * from "./services/orm-service";
|
|
26
26
|
export * from "./services/auto-update-service";
|
|
27
|
+
export * from "./services/smtp-client-service";
|
|
27
28
|
|
|
28
29
|
// Utils
|
|
29
30
|
export * from "./utils/config-manager";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import nodemailer from "nodemailer";
|
|
2
|
+
import { defineService, type ServiceMethods } from "../core/define-service";
|
|
3
|
+
import type {
|
|
4
|
+
SmtpClientDefaultConfig,
|
|
5
|
+
SmtpClientSendByDefaultOption,
|
|
6
|
+
SmtpClientSendOption,
|
|
7
|
+
} from "@simplysm/service-common";
|
|
8
|
+
|
|
9
|
+
export const SmtpClientService = defineService("SmtpClient", (ctx) => ({
|
|
10
|
+
async send(options: SmtpClientSendOption): Promise<string> {
|
|
11
|
+
return new Promise<string>((resolve, reject) => {
|
|
12
|
+
const transport = nodemailer.createTransport({
|
|
13
|
+
host: options.host,
|
|
14
|
+
port: options.port,
|
|
15
|
+
secure: options.secure,
|
|
16
|
+
auth:
|
|
17
|
+
options.user != null
|
|
18
|
+
? {
|
|
19
|
+
user: options.user,
|
|
20
|
+
pass: options.pass,
|
|
21
|
+
}
|
|
22
|
+
: undefined,
|
|
23
|
+
tls: {
|
|
24
|
+
rejectUnauthorized: false,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
transport.sendMail(options as nodemailer.SendMailOptions, (err, info) => {
|
|
29
|
+
if (err) {
|
|
30
|
+
reject(err);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
resolve(info.messageId);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
async sendByConfig(configName: string, options: SmtpClientSendByDefaultOption): Promise<string> {
|
|
40
|
+
const config = (
|
|
41
|
+
await ctx.getConfig<Record<string, SmtpClientDefaultConfig | undefined>>("smtp")
|
|
42
|
+
)[configName];
|
|
43
|
+
if (config == null) {
|
|
44
|
+
throw new Error(`SMTP config not found: ${configName}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return this.send({
|
|
48
|
+
user: config.user,
|
|
49
|
+
pass: config.pass,
|
|
50
|
+
host: config.host,
|
|
51
|
+
port: config.port,
|
|
52
|
+
secure: config.secure,
|
|
53
|
+
from: `"${config.senderName}" <${config.senderEmail ?? config.user}>`,
|
|
54
|
+
...options,
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
export type SmtpClientServiceType = ServiceMethods<typeof SmtpClientService>;
|