Skip to content

Commit f82c5b0

Browse files
committed
fix typing issues
1 parent 3ef5dd4 commit f82c5b0

File tree

9 files changed

+124
-41
lines changed

9 files changed

+124
-41
lines changed

template/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,9 @@ typings/
6262

6363
# JetBrains IDE
6464
.idea
65+
66+
# Built files
67+
dist
68+
69+
# Data folder
70+
data

template/mixins/db.mixin.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import type { Context, Service, ServiceSchema } from "moleculer";
2-
2+
import type { DatabaseMethods } from "../moleculer-types.js";
33
import { Service as DbService } from "@moleculer/database";
44

55
export type DbServiceMethods = {
6-
seedDb?(): Promise<void>;
6+
seedDB?(): Promise<void>;
77
};
88

99
type DbServiceSchema = Partial<ServiceSchema>;
1010

11-
export type DbServiceThis = Service & DbServiceMethods;
11+
export type DbServiceThis = Service & DbServiceMethods & DatabaseMethods;
1212

1313
export default function (collection: string): DbServiceSchema {
1414
const cacheCleanEventName = `cache.clean.${collection}`;

template/moleculer-types.d.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import "moleculer";
2+
3+
declare module "moleculer" {
4+
interface ActionSchema {
5+
graphql?: {
6+
query?: string;
7+
mutation?: string;
8+
};
9+
10+
auth?: "required" | null | undefined;
11+
}
12+
13+
interface ServiceBroker {
14+
sendToChannel(channelName: string, payload: unknown, opts?: { ctx?: Context });
15+
}
16+
17+
interface ServiceSchema {
18+
channels?: {
19+
[key: string]: {
20+
context?: boolean;
21+
handler: (this: Service, ctx: Context<P, M, L, H>) => Promise<void>;
22+
};
23+
};
24+
}
25+
}
26+
27+
interface ApolloServiceSettings {
28+
graphql?: {
29+
type?: string;
30+
};
31+
}
32+
33+
interface DatabaseSettings {
34+
fields: {
35+
[key: string]: {
36+
type: string;
37+
primaryKey?: boolean;
38+
columnName?: string;
39+
required?: boolean;
40+
min?: number;
41+
max?: number;
42+
}
43+
}
44+
}
45+
46+
interface DatabaseAdapter {
47+
findById<TEntity>(id: string): Promise<TEntity>;
48+
count(): Promise<number>;
49+
insertMany<TEntity>(entities: TEntity[]): Promise<TEntity[]>;
50+
}
51+
52+
interface DatabaseMethods {
53+
getAdapter(ctx?: Context): Promise<DatabaseAdapter>;
54+
updateEntity<TEntity>(ctx: Context, entity: Partial<TEntity>): Promise<TEntity>;
55+
}
56+
57+
58+
declare module '@moleculer/database' {
59+
export function Service(options?: object): ServiceSchema;
60+
}

template/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "{{projectName}}",
33
"version": "1.0.0",
44
"description": "My Moleculer-based microservices project",
5-
"type": "module",
5+
"type": "commonjs",
66
"scripts": {
77
"build": "tsc --project tsconfig.build.json",
88
"dev": "tsx ./node_modules/moleculer/bin/moleculer-runner.js --config moleculer.config.ts --hot --repl services/**/*.service.ts",

template/services/api.service.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import type { Context, ServiceSchema } from "moleculer";
2-
import type { IncomingMessage, ServerResponse } from "http";
32

43
import ApiGateway from "moleculer-web";
5-
import type { ApiSettingsSchema } from "moleculer-web";
4+
import type { ApiSettingsSchema, Route, IncomingRequest, GatewayResponse } from "moleculer-web";
65
{{#apiIO}}
76
import SocketIOService from "moleculer-io";
87
{{/apiIO}}
@@ -11,9 +10,14 @@ import { ApolloService } from "moleculer-apollo-server";
1110
import { GraphQLJSONObject } from "graphql-type-json";
1211
{{/apiGQL}}
1312

13+
interface MetaUser {
14+
id: number;
15+
name: string;
16+
}
17+
1418
interface Meta {
1519
userAgent?: string | null | undefined;
16-
user?: object | null | undefined;
20+
user?: MetaUser | null | undefined;
1721
}
1822

1923
const ApiService: ServiceSchema<ApiSettingsSchema> = {
@@ -50,7 +54,7 @@ const ApiService: ServiceSchema<ApiSettingsSchema> = {
5054
/** More info: https://moleculer.services/docs/0.15/moleculer-web.html */
5155
settings: {
5256
// Exposed port
53-
port: process.env.PORT || 3000,
57+
port: process.env.PORT ? parseInt(process.env.PORT) : 3000,
5458

5559
// Exposed IP
5660
ip: "0.0.0.0",
@@ -88,7 +92,7 @@ const ApiService: ServiceSchema<ApiSettingsSchema> = {
8892
onBeforeCall(
8993
ctx: Context<unknown, Meta>,
9094
route: Route,
91-
req: IncomingMessage,
95+
req: IncomingRequest,
9296
res: GatewayResponse,
9397
): void {
9498
// Set request headers to context meta
@@ -101,7 +105,7 @@ const ApiService: ServiceSchema<ApiSettingsSchema> = {
101105
onAfterCall(
102106
ctx: Context,
103107
route: Route,
104-
req: IncomingMessage,
108+
req: IncomingRequest,
105109
res: GatewayResponse,
106110
data: unknown,
107111
): unknown {
@@ -163,8 +167,8 @@ const ApiService: ServiceSchema<ApiSettingsSchema> = {
163167
authenticate(
164168
ctx: Context,
165169
route: Route,
166-
req: IncomingMessage,
167-
): Record<string, unknown> | null {
170+
req: IncomingRequest,
171+
): MetaUser | null {
168172
// Read the token from header
169173
const auth = req.headers["authorization"];
170174

@@ -193,7 +197,7 @@ const ApiService: ServiceSchema<ApiSettingsSchema> = {
193197
*
194198
* PLEASE NOTE, IT'S JUST AN EXAMPLE IMPLEMENTATION. DO NOT USE IN PRODUCTION!
195199
*/
196-
authorize(ctx: Context<null, Meta>, route: Route, req: IncomingMessage) {
200+
authorize(ctx: Context<null, Meta>, route: Route, req: IncomingRequest) {
197201
// Get the authenticated user.
198202
const user = ctx.meta.user;
199203

template/services/inventory.service.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ const InventoryService: ServiceSchema = {
1414
*/
1515
"inventory.reserve": {
1616
context: true,
17-
async handler(ctx: Context) {
17+
async handler(this: Service, ctx: Context<{ productId: string; quantity: number }>) {
1818
// Simulate external API call to reserve the quantity...
19-
await this.Promise.delay(1000);
19+
await new Promise(resolve => setTimeout(resolve, 1000));
2020

2121
this.logger.info(
2222
`Reserve ${ctx.params.quantity} pieces of the ${ctx.params.productId} product in the inventory.`
@@ -46,7 +46,7 @@ const InventoryService: ServiceSchema = {
4646
productId: { type: "string" },
4747
quantity: { type: "number" }
4848
},
49-
async handler(ctx: Context) {
49+
async handler(ctx: Context<{ productId: string; quantity: number }>) {
5050
await this.broker.sendToChannel(
5151
"inventory.reserve",
5252
{

template/services/orders.service.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
import type { Context, Service, ServiceSchema, ServiceSettingSchema } from "moleculer";
22

3+
interface WorkflowPayload {
4+
card?: string;
5+
amount?: number;
6+
productId?: string;
7+
quantity?: number;
8+
address?: string;
9+
}
10+
11+
interface PaymentResult {
12+
status: "wait" | "success" | "failed";
13+
transactionId: string;
14+
}
15+
316
const OrdersService: ServiceSchema = {
417
name: "orders",
518

@@ -8,10 +21,10 @@ const OrdersService: ServiceSchema = {
821
*/
922
workflows: {
1023
process: {
11-
async handler(ctx: Context) {
12-
this.logger.info("Start processing order", ctx.params);
24+
async handler(this: Service, ctx: Context<WorkflowPayload>) {
25+
this.logger.info("Start processing order. Job ID:", ctx.wf.jobId, ctx.params);
1326

14-
const paymentResult = await ctx.call("orders.payment", {
27+
const paymentResult = await ctx.call<PaymentResult, Partial<WorkflowPayload>>("orders.payment", {
1528
card: ctx.params.card,
1629
amount: ctx.params.amount
1730
});
@@ -76,7 +89,7 @@ const OrdersService: ServiceSchema = {
7689
card: { type: "string" },
7790
amount: { type: "number" }
7891
},
79-
async handler(ctx: Context) {
92+
async handler(ctx: Context<{ card: string; amount: number }>) {
8093
this.logger.info("Waiting for payment finishing...", ctx.params);
8194
// Simulate payment processing
8295
return { status: "wait", transactionId: "12345" };
@@ -95,7 +108,7 @@ const OrdersService: ServiceSchema = {
95108
params: {
96109
transactionId: { type: "string", default: "12345" }
97110
},
98-
async handler(ctx: Context) {
111+
async handler(ctx: Context<{ transactionId: string }>) {
99112
this.logger.info("Payment finished for transaction", ctx.params.transactionId);
100113

101114
// Simulate payment completion
@@ -113,7 +126,7 @@ const OrdersService: ServiceSchema = {
113126
productId: "string",
114127
quantity: "number"
115128
},
116-
async handler(ctx: Context) {
129+
async handler(ctx: Context<{ productId: string; quantity: number }>) {
117130
this.logger.info("Reserving inventory for product", ctx.params.productId);
118131
// Simulate inventory update
119132
return {
@@ -131,7 +144,7 @@ const OrdersService: ServiceSchema = {
131144
params: {
132145
address: "string"
133146
},
134-
async handler(ctx: Context) {
147+
async handler(ctx: Context<{ productId: string; address: string }>) {
135148
this.logger.info("Scheduling delivery for product", ctx.params.productId);
136149
// Simulate delivery scheduling
137150
return {

template/services/products.service.ts

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import type { Context, Service, ServiceSchema } from "moleculer";
2-
import type { DbAdapter, DbServiceSettings, MoleculerDbMethods } from "@moleculer/database";
3-
import type { DbServiceMethods } from "../mixins/db.mixin";
4-
import DbMixin from "../mixins/db.mixin";
2+
import type { DatabaseMethods, DatabaseSettings, ApolloServiceSettings } from "../moleculer-types.js";
3+
import DbMixin from "../mixins/db.mixin.js";
54

65
export interface ProductEntity {
7-
_id: string;
6+
id: string;
87
name: string;
98
price: number;
109
quantity: number;
@@ -17,15 +16,11 @@ export interface ActionQuantityParams {
1716
value: number;
1817
}
1918

20-
interface ProductSettings extends DbServiceSettings {
21-
indexes?: Record<string, number>[];
22-
}
19+
interface ProductSettings extends DatabaseSettings, ApolloServiceSettings {}
2320

24-
interface ProductsThis extends Service<ProductSettings>, MoleculerDbMethods {
25-
adapter: DbAdapter;
26-
}
21+
interface ProductsThis extends Service<ProductSettings>, DatabaseMethods {};
2722

28-
const ProductsService: ServiceSchema<ProductSettings> & { methods: DbServiceMethods } = {
23+
const ProductsService: ServiceSchema<ProductSettings> = {
2924
name: "products",
3025
// version: 1
3126

@@ -166,16 +161,16 @@ const ProductsService: ServiceSchema<ProductSettings> & { methods: DbServiceMeth
166161
{{#apiGQL}}graphql: {
167162
mutation: "increaseQuantity(id: String!, value: Int!): Product"
168163
},{{/apiGQL}}
169-
async handler(this: ProductsThis, ctx: Context<ActionQuantityParams>): Promise<object> {
164+
async handler(this: ProductsThis, ctx: Context<ActionQuantityParams>): Promise<ProductEntity> {
170165
// Get current quantity
171166
const adapter = await this.getAdapter(ctx);
172-
const dbEntry = await adapter.findById(ctx.params.id);
167+
const dbEntry = await adapter.findById<ProductEntity>(ctx.params.id);
173168

174169
// Compute new quantity
175170
const newQuantity = dbEntry.quantity + ctx.params.value;
176171

177172
// Update DB entry. Will emit an event to clear the cache
178-
const doc = await this.updateEntity(ctx, {
173+
const doc = await this.updateEntity<ProductEntity>(ctx, {
179174
id: ctx.params.id,
180175
quantity: newQuantity
181176
});
@@ -196,18 +191,18 @@ const ProductsService: ServiceSchema<ProductSettings> & { methods: DbServiceMeth
196191
{{#apiGQL}}graphql: {
197192
mutation: "decreaseQuantity(id: String!, value: Int!): Product"
198193
},{{/apiGQL}}
199-
async handler(this: ProductsThis, ctx: Context<ActionQuantityParams>): Promise<object> {
194+
async handler(this: ProductsThis, ctx: Context<ActionQuantityParams>): Promise<ProductEntity> {
200195
// Get current quantity
201196
const adapter = await this.getAdapter(ctx);
202-
const dbEntry = await adapter.findById(ctx.params.id);
197+
const dbEntry = await adapter.findById<ProductEntity>(ctx.params.id);
203198

204199
// Compute new quantity
205200
const newQuantity = dbEntry.quantity - ctx.params.value;
206201

207202
if (newQuantity < 0) throw new Error("Quantity cannot be negative");
208203

209204
// Update DB entry. Will emit an event to clear the cache
210-
const doc = await this.updateEntity(ctx, {
205+
const doc = await this.updateEntity<ProductEntity>(ctx, {
211206
id: ctx.params.id,
212207
quantity: newQuantity
213208
});

template/tsconfig.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,5 +99,10 @@
9999
/* Completeness */
100100
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
101101
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
102-
}
102+
},
103+
104+
"include": [
105+
"./**/*.ts",
106+
"moleculer-types.d.ts"
107+
],
103108
}

0 commit comments

Comments
 (0)