@simplysm/service-common 13.0.99 → 14.0.1
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/dist/define-event.d.ts +7 -7
- package/dist/define-event.d.ts.map +1 -1
- package/dist/define-event.js +21 -10
- package/dist/define-event.js.map +1 -6
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -6
- package/dist/protocol/create-service-protocol.d.ts +20 -20
- package/dist/protocol/create-service-protocol.d.ts.map +1 -1
- package/dist/protocol/create-service-protocol.js +149 -112
- package/dist/protocol/create-service-protocol.js.map +1 -6
- package/dist/protocol/protocol.types.d.ts +17 -17
- package/dist/protocol/protocol.types.d.ts.map +1 -1
- package/dist/protocol/protocol.types.js +16 -15
- package/dist/protocol/protocol.types.js.map +1 -6
- package/dist/service-types/auto-update-service.types.d.ts +5 -5
- package/dist/service-types/auto-update-service.types.js +2 -1
- package/dist/service-types/auto-update-service.types.js.map +1 -6
- package/dist/service-types/orm-service.types.d.ts +7 -5
- package/dist/service-types/orm-service.types.d.ts.map +1 -1
- package/dist/service-types/orm-service.types.js +2 -1
- package/dist/service-types/orm-service.types.js.map +1 -6
- package/dist/types.d.ts +5 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -1
- package/dist/types.js.map +1 -6
- package/package.json +6 -8
- package/src/define-event.ts +7 -7
- package/src/index.ts +4 -6
- package/src/protocol/create-service-protocol.ts +45 -38
- package/src/protocol/protocol.types.ts +39 -39
- package/src/service-types/auto-update-service.types.ts +5 -5
- package/src/service-types/orm-service.types.ts +5 -5
- package/src/types.ts +5 -5
- package/README.md +0 -111
- package/dist/service-types/smtp-client-service.types.d.ts +0 -38
- package/dist/service-types/smtp-client-service.types.d.ts.map +0 -1
- package/dist/service-types/smtp-client-service.types.js +0 -1
- package/dist/service-types/smtp-client-service.types.js.map +0 -6
- package/docs/events.md +0 -51
- package/docs/protocol.md +0 -252
- package/docs/service-types.md +0 -162
- package/src/service-types/smtp-client-service.types.ts +0 -41
- package/tests/define-event.spec.ts +0 -11
- package/tests/protocol/service-protocol.spec.ts +0 -251
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export interface SmtpClientSendAttachment {
|
|
2
|
-
filename: string;
|
|
3
|
-
content?: string | Uint8Array;
|
|
4
|
-
path?: any;
|
|
5
|
-
contentType?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface SmtpClientSendByDefaultOption {
|
|
9
|
-
to: string;
|
|
10
|
-
cc?: string;
|
|
11
|
-
bcc?: string;
|
|
12
|
-
subject: string;
|
|
13
|
-
html: string;
|
|
14
|
-
attachments?: SmtpClientSendAttachment[];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface SmtpClientSendOption {
|
|
18
|
-
host: string;
|
|
19
|
-
port?: number;
|
|
20
|
-
secure?: boolean;
|
|
21
|
-
user?: string;
|
|
22
|
-
pass?: string;
|
|
23
|
-
|
|
24
|
-
from: string;
|
|
25
|
-
to: string;
|
|
26
|
-
cc?: string;
|
|
27
|
-
bcc?: string;
|
|
28
|
-
subject: string;
|
|
29
|
-
html: string;
|
|
30
|
-
attachments?: SmtpClientSendAttachment[];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface SmtpClientDefaultOptions {
|
|
34
|
-
senderName: string;
|
|
35
|
-
senderEmail?: string;
|
|
36
|
-
user?: string;
|
|
37
|
-
pass?: string;
|
|
38
|
-
host: string;
|
|
39
|
-
port?: number;
|
|
40
|
-
secure?: boolean;
|
|
41
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
// packages/service-common/tests/define-event.spec.ts
|
|
2
|
-
import { describe, it, expect } from "vitest";
|
|
3
|
-
import { defineEvent } from "@simplysm/service-common";
|
|
4
|
-
|
|
5
|
-
describe("defineEvent", () => {
|
|
6
|
-
it("create event definition with given name", () => {
|
|
7
|
-
const evt = defineEvent<{ channel: string }, string>("OrderUpdated");
|
|
8
|
-
expect(evt.eventName).toBe("OrderUpdated");
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
});
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { createServiceProtocol, type ServiceProtocol } from "../../src/protocol/create-service-protocol";
|
|
3
|
-
import type { ServiceMessage } from "../../src/protocol/protocol.types";
|
|
4
|
-
import { Uuid } from "@simplysm/core-common";
|
|
5
|
-
|
|
6
|
-
describe("ServiceProtocol", () => {
|
|
7
|
-
let protocol: ServiceProtocol;
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
protocol = createServiceProtocol();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
protocol.dispose();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
describe("Encoding", () => {
|
|
18
|
-
it("encode single message", () => {
|
|
19
|
-
const uuid = Uuid.generate().toString();
|
|
20
|
-
const message: ServiceMessage = { name: "test.method", body: [{ test: "data" }] };
|
|
21
|
-
|
|
22
|
-
const result = protocol.encode(uuid, message);
|
|
23
|
-
|
|
24
|
-
expect(result.chunks.length).toBe(1);
|
|
25
|
-
expect(result.totalSize).toBeGreaterThan(0);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("throw error when message exceeds 100MB", () => {
|
|
29
|
-
const uuid = Uuid.generate().toString();
|
|
30
|
-
// Generate data larger than 100MB
|
|
31
|
-
const largeData = "x".repeat(101 * 1024 * 1024);
|
|
32
|
-
const message: ServiceMessage = { name: "test.method", body: [largeData] };
|
|
33
|
-
|
|
34
|
-
expect(() => protocol.encode(uuid, message)).toThrow("Message size exceeds the limit.");
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
describe("Decoding", () => {
|
|
39
|
-
it("decode single message", () => {
|
|
40
|
-
const uuid = Uuid.generate().toString();
|
|
41
|
-
const message: ServiceMessage = { name: "test.method", body: [{ value: 123 }] };
|
|
42
|
-
|
|
43
|
-
const encoded = protocol.encode(uuid, message);
|
|
44
|
-
const result = protocol.decode(encoded.chunks[0]);
|
|
45
|
-
|
|
46
|
-
expect(result.type).toBe("complete");
|
|
47
|
-
if (result.type === "complete") {
|
|
48
|
-
expect(result.message.name).toBe("test.method");
|
|
49
|
-
expect(result.message.body).toEqual([{ value: 123 }]);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it("throw error when buffer size is smaller than header size", () => {
|
|
54
|
-
const smallBytes = new Uint8Array(20);
|
|
55
|
-
|
|
56
|
-
expect(() => protocol.decode(smallBytes)).toThrow("Buffer size is smaller than header size.");
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it("throw error when decoded message exceeds 100MB", () => {
|
|
60
|
-
// Manually create header with totalSize exceeding 100MB
|
|
61
|
-
const headerBytes = new Uint8Array(28);
|
|
62
|
-
const uuidBytes = new Uuid(Uuid.generate().toString()).toBytes();
|
|
63
|
-
headerBytes.set(uuidBytes, 0);
|
|
64
|
-
|
|
65
|
-
const headerView = new DataView(
|
|
66
|
-
headerBytes.buffer,
|
|
67
|
-
headerBytes.byteOffset,
|
|
68
|
-
headerBytes.byteLength,
|
|
69
|
-
);
|
|
70
|
-
headerView.setBigUint64(16, BigInt(101 * 1024 * 1024), false); // 101MB
|
|
71
|
-
headerView.setUint32(24, 0, false);
|
|
72
|
-
|
|
73
|
-
expect(() => protocol.decode(headerBytes)).toThrow("Message size exceeds the limit.");
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe("Chunking", () => {
|
|
78
|
-
it("chunk message larger than 3MB", () => {
|
|
79
|
-
const uuid = Uuid.generate().toString();
|
|
80
|
-
// Create 4MB data
|
|
81
|
-
const largeData = "x".repeat(4 * 1024 * 1024);
|
|
82
|
-
const message: ServiceMessage = { name: "test.method", body: [largeData] };
|
|
83
|
-
|
|
84
|
-
const result = protocol.encode(uuid, message);
|
|
85
|
-
|
|
86
|
-
expect(result.chunks.length).toBeGreaterThan(1);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it("assemble chunked message in order", () => {
|
|
90
|
-
const uuid = Uuid.generate().toString();
|
|
91
|
-
// 4MB data
|
|
92
|
-
const largeData = "x".repeat(4 * 1024 * 1024);
|
|
93
|
-
const message: ServiceMessage = { name: "test.method", body: [largeData] };
|
|
94
|
-
|
|
95
|
-
const encoded = protocol.encode(uuid, message);
|
|
96
|
-
expect(encoded.chunks.length).toBeGreaterThan(1);
|
|
97
|
-
|
|
98
|
-
// Decode chunks in order
|
|
99
|
-
let result!: ReturnType<typeof protocol.decode>;
|
|
100
|
-
for (let i = 0; i < encoded.chunks.length; i++) {
|
|
101
|
-
result = protocol.decode(encoded.chunks[i]);
|
|
102
|
-
if (i < encoded.chunks.length - 1) {
|
|
103
|
-
expect(result.type).toBe("progress");
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
expect(result.type).toBe("complete");
|
|
108
|
-
if (result.type === "complete") {
|
|
109
|
-
expect(result.message.body).toEqual([largeData]);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it("assemble chunked message in reverse order", () => {
|
|
114
|
-
const uuid = Uuid.generate().toString();
|
|
115
|
-
// 4MB data
|
|
116
|
-
const largeData = "x".repeat(4 * 1024 * 1024);
|
|
117
|
-
const message: ServiceMessage = { name: "test.method", body: [largeData] };
|
|
118
|
-
|
|
119
|
-
const encoded = protocol.encode(uuid, message);
|
|
120
|
-
const reversedChunks = [...encoded.chunks].reverse();
|
|
121
|
-
|
|
122
|
-
// Decode in reverse order
|
|
123
|
-
let result!: ReturnType<typeof protocol.decode>;
|
|
124
|
-
for (let i = 0; i < reversedChunks.length; i++) {
|
|
125
|
-
result = protocol.decode(reversedChunks[i]);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Should complete at the end
|
|
129
|
-
expect(result.type).toBe("complete");
|
|
130
|
-
if (result.type === "complete") {
|
|
131
|
-
expect(result.message.body).toEqual([largeData]);
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("prevent duplicate packets", () => {
|
|
136
|
-
const uuid = Uuid.generate().toString();
|
|
137
|
-
// 4MB data
|
|
138
|
-
const largeData = "x".repeat(4 * 1024 * 1024);
|
|
139
|
-
const message: ServiceMessage = { name: "test.method", body: [largeData] };
|
|
140
|
-
|
|
141
|
-
const encoded = protocol.encode(uuid, message);
|
|
142
|
-
|
|
143
|
-
// Send first chunk twice
|
|
144
|
-
protocol.decode(encoded.chunks[0]);
|
|
145
|
-
const result1 = protocol.decode(encoded.chunks[0]); // Duplicate
|
|
146
|
-
|
|
147
|
-
// Should be in progress state, and completedSize should not increase from duplicate
|
|
148
|
-
expect(result1.type).toBe("progress");
|
|
149
|
-
|
|
150
|
-
// Send remaining chunks
|
|
151
|
-
let result!: ReturnType<typeof protocol.decode>;
|
|
152
|
-
for (let i = 1; i < encoded.chunks.length; i++) {
|
|
153
|
-
result = protocol.decode(encoded.chunks[i]);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
expect(result.type).toBe("complete");
|
|
157
|
-
if (result.type === "complete") {
|
|
158
|
-
expect(result.message.body).toEqual([largeData]);
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
describe("UUID interleaving", () => {
|
|
164
|
-
it("receive chunks from multiple UUIDs in interleaved order", () => {
|
|
165
|
-
const uuid1 = Uuid.generate().toString();
|
|
166
|
-
const uuid2 = Uuid.generate().toString();
|
|
167
|
-
|
|
168
|
-
// Each with 4MB data to trigger chunking
|
|
169
|
-
const largeData1 = "A".repeat(4 * 1024 * 1024);
|
|
170
|
-
const largeData2 = "B".repeat(4 * 1024 * 1024);
|
|
171
|
-
const message1: ServiceMessage = { name: "test.method1", body: [largeData1] };
|
|
172
|
-
const message2: ServiceMessage = { name: "test.method2", body: [largeData2] };
|
|
173
|
-
|
|
174
|
-
const encoded1 = protocol.encode(uuid1, message1);
|
|
175
|
-
const encoded2 = protocol.encode(uuid2, message2);
|
|
176
|
-
|
|
177
|
-
expect(encoded1.chunks.length).toBeGreaterThan(1);
|
|
178
|
-
expect(encoded2.chunks.length).toBeGreaterThan(1);
|
|
179
|
-
|
|
180
|
-
// Decode chunks in interleaved order (uuid1[0], uuid2[0], uuid1[1], uuid2[1], ...)
|
|
181
|
-
const maxChunks = Math.max(encoded1.chunks.length, encoded2.chunks.length);
|
|
182
|
-
let result1!: ReturnType<typeof protocol.decode>;
|
|
183
|
-
let result2!: ReturnType<typeof protocol.decode>;
|
|
184
|
-
|
|
185
|
-
for (let i = 0; i < maxChunks; i++) {
|
|
186
|
-
if (i < encoded1.chunks.length) {
|
|
187
|
-
result1 = protocol.decode(encoded1.chunks[i]);
|
|
188
|
-
}
|
|
189
|
-
if (i < encoded2.chunks.length) {
|
|
190
|
-
result2 = protocol.decode(encoded2.chunks[i]);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Both messages should complete
|
|
195
|
-
expect(result1.type).toBe("complete");
|
|
196
|
-
expect(result2.type).toBe("complete");
|
|
197
|
-
|
|
198
|
-
if (result1.type === "complete" && result2.type === "complete") {
|
|
199
|
-
expect(result1.message.name).toBe("test.method1");
|
|
200
|
-
expect(result1.message.body).toEqual([largeData1]);
|
|
201
|
-
expect(result2.message.name).toBe("test.method2");
|
|
202
|
-
expect(result2.message.body).toEqual([largeData2]);
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
describe("Edge cases", () => {
|
|
209
|
-
it("handle null body", () => {
|
|
210
|
-
const uuid = Uuid.generate().toString();
|
|
211
|
-
const message: ServiceMessage = { name: "test.method", body: [null] };
|
|
212
|
-
|
|
213
|
-
const encoded = protocol.encode(uuid, message);
|
|
214
|
-
const decoded = protocol.decode(encoded.chunks[0]);
|
|
215
|
-
|
|
216
|
-
expect(decoded.type).toBe("complete");
|
|
217
|
-
if (decoded.type === "complete") {
|
|
218
|
-
// JsonConvert.stringify/parse converts null to undefined
|
|
219
|
-
expect(decoded.message.body).toEqual([undefined]);
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it("handle message at exactly 3MB boundary", () => {
|
|
224
|
-
const uuid = Uuid.generate().toString();
|
|
225
|
-
// Exactly 3MB
|
|
226
|
-
const data = "x".repeat(3 * 1024 * 1024 - 50); // Account for some JSON overhead
|
|
227
|
-
const message: ServiceMessage = { name: "test.method", body: [data] };
|
|
228
|
-
|
|
229
|
-
const encoded = protocol.encode(uuid, message);
|
|
230
|
-
// Messages up to 3MB should not be chunked
|
|
231
|
-
expect(encoded.chunks.length).toBe(1);
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it("include correct information in progress response", () => {
|
|
235
|
-
const uuid = Uuid.generate().toString();
|
|
236
|
-
const largeData = "x".repeat(4 * 1024 * 1024);
|
|
237
|
-
const message: ServiceMessage = { name: "test.method", body: [largeData] };
|
|
238
|
-
|
|
239
|
-
const encoded = protocol.encode(uuid, message);
|
|
240
|
-
const result = protocol.decode(encoded.chunks[0]);
|
|
241
|
-
|
|
242
|
-
expect(result.type).toBe("progress");
|
|
243
|
-
if (result.type === "progress") {
|
|
244
|
-
expect(result.uuid).toBe(uuid);
|
|
245
|
-
expect(result.totalSize).toBe(encoded.totalSize);
|
|
246
|
-
expect(result.completedSize).toBeGreaterThan(0);
|
|
247
|
-
expect(result.completedSize).toBeLessThan(result.totalSize);
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
});
|
|
251
|
-
});
|