@arrirpc/server 0.84.1 → 0.85.0
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 +68 -0
- package/dist/index.cjs +151 -0
- package/dist/index.d.cts +35 -3
- package/dist/index.d.mts +35 -3
- package/dist/index.d.ts +35 -3
- package/dist/index.mjs +150 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -385,6 +385,74 @@ declare module '@arrirpc/server' {
|
|
|
385
385
|
}
|
|
386
386
|
```
|
|
387
387
|
|
|
388
|
+
### Background Workers & Lifecycle Hooks
|
|
389
|
+
|
|
390
|
+
You can register background workers and lifecycle hooks on `ArriApp`. Workers and lifecycle hooks do not run when the app is imported during codegen (`arri build`); they only start when the web server begins listening.
|
|
391
|
+
|
|
392
|
+
```ts
|
|
393
|
+
import { ArriApp, defineWorker } from '@arrirpc/server';
|
|
394
|
+
|
|
395
|
+
const app = new ArriApp({
|
|
396
|
+
onStart() {
|
|
397
|
+
console.log('Server is starting up');
|
|
398
|
+
},
|
|
399
|
+
onStop() {
|
|
400
|
+
console.log('Server is shutting down');
|
|
401
|
+
},
|
|
402
|
+
onWorkerError(err, worker) {
|
|
403
|
+
logger.error({ err, worker: worker.name }, 'Worker error');
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// Registering a worker with a continuous loop and AbortSignal
|
|
408
|
+
app.registerWorker(
|
|
409
|
+
defineWorker({
|
|
410
|
+
name: 'queue-consumer',
|
|
411
|
+
async start(signal) {
|
|
412
|
+
while (!signal.aborted) {
|
|
413
|
+
const job = await queue.pop({ signal });
|
|
414
|
+
if (job) await processJob(job);
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
async stop() {
|
|
418
|
+
// Optional: cleanup or drain
|
|
419
|
+
},
|
|
420
|
+
}),
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
// Registering a third-party worker (e.g. BullMQ)
|
|
424
|
+
app.registerWorker(
|
|
425
|
+
defineWorker({
|
|
426
|
+
name: 'bullmq-emails',
|
|
427
|
+
async start() {
|
|
428
|
+
worker = new Worker('emails', async (job) => {
|
|
429
|
+
await sendEmail(job.data);
|
|
430
|
+
});
|
|
431
|
+
},
|
|
432
|
+
async stop() {
|
|
433
|
+
await worker.close();
|
|
434
|
+
},
|
|
435
|
+
}),
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
// Function shorthand
|
|
439
|
+
app.registerWorker(async (signal) => {
|
|
440
|
+
while (!signal.aborted) {
|
|
441
|
+
await heartbeat();
|
|
442
|
+
await delay(5000, signal);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Services can also register workers:
|
|
448
|
+
|
|
449
|
+
```ts
|
|
450
|
+
const authService = new ArriService('auth');
|
|
451
|
+
authService.registerWorker(tokenCleanupWorker);
|
|
452
|
+
|
|
453
|
+
app.use(authService); // Workers will be registered on the app
|
|
454
|
+
```
|
|
455
|
+
|
|
388
456
|
### Adding Client Generators
|
|
389
457
|
|
|
390
458
|
```ts
|
package/dist/index.cjs
CHANGED
|
@@ -804,6 +804,18 @@ class ArriRouter {
|
|
|
804
804
|
}
|
|
805
805
|
}
|
|
806
806
|
|
|
807
|
+
function defineWorker(worker) {
|
|
808
|
+
if (typeof worker === "function") {
|
|
809
|
+
return {
|
|
810
|
+
start: worker
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
return worker;
|
|
814
|
+
}
|
|
815
|
+
function isWorker(input) {
|
|
816
|
+
return typeof input === "object" && input !== null && "start" in input && typeof input.start === "function";
|
|
817
|
+
}
|
|
818
|
+
|
|
807
819
|
class ArriService {
|
|
808
820
|
name;
|
|
809
821
|
constructor(name) {
|
|
@@ -811,10 +823,14 @@ class ArriService {
|
|
|
811
823
|
}
|
|
812
824
|
procedures = [];
|
|
813
825
|
definitions = {};
|
|
826
|
+
workers = [];
|
|
814
827
|
rpc(name, procedure) {
|
|
815
828
|
procedure.name = `${this.name}.${name}`;
|
|
816
829
|
this.procedures.push(procedure);
|
|
817
830
|
}
|
|
831
|
+
registerWorker(worker) {
|
|
832
|
+
this.workers.push(defineWorker(worker));
|
|
833
|
+
}
|
|
818
834
|
registerDefinitions(models) {
|
|
819
835
|
for (const key of Object.keys(models)) {
|
|
820
836
|
this.definitions[key] = models[key];
|
|
@@ -826,6 +842,9 @@ class ArriService {
|
|
|
826
842
|
getDefinitions() {
|
|
827
843
|
return this.definitions;
|
|
828
844
|
}
|
|
845
|
+
getWorkers() {
|
|
846
|
+
return this.workers;
|
|
847
|
+
}
|
|
829
848
|
}
|
|
830
849
|
function defineService(name, procedures) {
|
|
831
850
|
const service = new ArriService(name);
|
|
@@ -846,6 +865,12 @@ class ArriApp {
|
|
|
846
865
|
_procedures = {};
|
|
847
866
|
_definitions = {};
|
|
848
867
|
_middlewares = [];
|
|
868
|
+
_workers = [];
|
|
869
|
+
_onStartHooks = [];
|
|
870
|
+
_onStopHooks = [];
|
|
871
|
+
_workerErrorHooks = [];
|
|
872
|
+
_abortController = null;
|
|
873
|
+
_isRunning = false;
|
|
849
874
|
_onRequest;
|
|
850
875
|
_onAfterResponse;
|
|
851
876
|
_onBeforeResponse;
|
|
@@ -863,6 +888,15 @@ class ArriApp {
|
|
|
863
888
|
this._onError = opts.onError;
|
|
864
889
|
this._onAfterResponse = opts.onAfterResponse;
|
|
865
890
|
this._onBeforeResponse = opts.onBeforeResponse;
|
|
891
|
+
if (opts.onStart) {
|
|
892
|
+
this.onStart(opts.onStart);
|
|
893
|
+
}
|
|
894
|
+
if (opts.onStop) {
|
|
895
|
+
this.onStop(opts.onStop);
|
|
896
|
+
}
|
|
897
|
+
if (opts.onWorkerError) {
|
|
898
|
+
this.onWorkerError(opts.onWorkerError);
|
|
899
|
+
}
|
|
866
900
|
this._heartbeatMs = opts.heartbeatMs ?? 2e4;
|
|
867
901
|
this._rpcRoutePrefix = opts?.rpcRoutePrefix ?? "";
|
|
868
902
|
this._rpcDefinitionPath = opts?.rpcDefinitionPath ?? "__definition";
|
|
@@ -937,6 +971,9 @@ class ArriApp {
|
|
|
937
971
|
this.rpc(rpc.name, rpc);
|
|
938
972
|
}
|
|
939
973
|
this.registerDefinitions(input.getDefinitions());
|
|
974
|
+
for (const worker of input.getWorkers()) {
|
|
975
|
+
this.registerWorker(worker);
|
|
976
|
+
}
|
|
940
977
|
return;
|
|
941
978
|
}
|
|
942
979
|
this._middlewares.push(input);
|
|
@@ -1012,6 +1049,118 @@ class ArriApp {
|
|
|
1012
1049
|
}
|
|
1013
1050
|
return appDef;
|
|
1014
1051
|
}
|
|
1052
|
+
registerWorker(worker) {
|
|
1053
|
+
const w = defineWorker(worker);
|
|
1054
|
+
this._workers.push(w);
|
|
1055
|
+
if (this._isRunning && this._abortController) {
|
|
1056
|
+
void (async () => {
|
|
1057
|
+
try {
|
|
1058
|
+
await w.start(this._abortController.signal);
|
|
1059
|
+
} catch (err) {
|
|
1060
|
+
await this._handleWorkerError(w, err);
|
|
1061
|
+
}
|
|
1062
|
+
})();
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
onStart(hook) {
|
|
1066
|
+
this._onStartHooks.push(hook);
|
|
1067
|
+
}
|
|
1068
|
+
onStop(hook) {
|
|
1069
|
+
this._onStopHooks.push(hook);
|
|
1070
|
+
}
|
|
1071
|
+
onWorkerError(hook) {
|
|
1072
|
+
this._workerErrorHooks.push(hook);
|
|
1073
|
+
}
|
|
1074
|
+
async _handleWorkerError(worker, error) {
|
|
1075
|
+
let handled = false;
|
|
1076
|
+
if (worker.onError) {
|
|
1077
|
+
try {
|
|
1078
|
+
await worker.onError(error);
|
|
1079
|
+
handled = true;
|
|
1080
|
+
} catch (hookErr) {
|
|
1081
|
+
console.error(
|
|
1082
|
+
`[Arri] Error in worker.onError hook for worker ${worker.name ?? "unnamed"}:`,
|
|
1083
|
+
hookErr
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
for (const hook of this._workerErrorHooks) {
|
|
1088
|
+
try {
|
|
1089
|
+
await hook(error, worker);
|
|
1090
|
+
handled = true;
|
|
1091
|
+
} catch (hookErr) {
|
|
1092
|
+
console.error(
|
|
1093
|
+
`[Arri] Error in onWorkerError hook for worker ${worker.name ?? "unnamed"}:`,
|
|
1094
|
+
hookErr
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
if (!handled) {
|
|
1099
|
+
console.error(
|
|
1100
|
+
`[Arri] Unhandled error in worker ${worker.name ?? "unnamed"}:`,
|
|
1101
|
+
error
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
async start() {
|
|
1106
|
+
if (this._isRunning) {
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
this._isRunning = true;
|
|
1110
|
+
const controller = new AbortController();
|
|
1111
|
+
this._abortController = controller;
|
|
1112
|
+
try {
|
|
1113
|
+
for (const hook of this._onStartHooks) {
|
|
1114
|
+
await hook();
|
|
1115
|
+
}
|
|
1116
|
+
} catch (err) {
|
|
1117
|
+
this._isRunning = false;
|
|
1118
|
+
controller.abort();
|
|
1119
|
+
this._abortController = null;
|
|
1120
|
+
throw err;
|
|
1121
|
+
}
|
|
1122
|
+
for (const worker of this._workers) {
|
|
1123
|
+
void (async () => {
|
|
1124
|
+
try {
|
|
1125
|
+
await worker.start(controller.signal);
|
|
1126
|
+
} catch (err) {
|
|
1127
|
+
await this._handleWorkerError(worker, err);
|
|
1128
|
+
}
|
|
1129
|
+
})();
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
async stop() {
|
|
1133
|
+
if (!this._isRunning) {
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
this._isRunning = false;
|
|
1137
|
+
this._abortController?.abort();
|
|
1138
|
+
const stopPromises = this._workers.map(async (worker) => {
|
|
1139
|
+
try {
|
|
1140
|
+
if (worker.stop) {
|
|
1141
|
+
await worker.stop();
|
|
1142
|
+
}
|
|
1143
|
+
} catch (err) {
|
|
1144
|
+
await this._handleWorkerError(worker, err);
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
const hookPromises = this._onStopHooks.map(async (hook) => {
|
|
1148
|
+
try {
|
|
1149
|
+
await hook();
|
|
1150
|
+
} catch (err) {
|
|
1151
|
+
if (this._debug) {
|
|
1152
|
+
console.error("Error in onStop hook:", err);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
});
|
|
1156
|
+
await Promise.allSettled([...stopPromises, ...hookPromises]);
|
|
1157
|
+
}
|
|
1158
|
+
get workers() {
|
|
1159
|
+
return [...this._workers];
|
|
1160
|
+
}
|
|
1161
|
+
get isRunning() {
|
|
1162
|
+
return this._isRunning;
|
|
1163
|
+
}
|
|
1015
1164
|
}
|
|
1016
1165
|
|
|
1017
1166
|
const defineMiddleware = (middleware) => middleware;
|
|
@@ -1030,6 +1179,7 @@ exports.defineMiddleware = defineMiddleware;
|
|
|
1030
1179
|
exports.defineRoute = defineRoute;
|
|
1031
1180
|
exports.defineRpc = defineRpc;
|
|
1032
1181
|
exports.defineService = defineService;
|
|
1182
|
+
exports.defineWorker = defineWorker;
|
|
1033
1183
|
exports.errorResponseFromValidationErrors = errorResponseFromValidationErrors;
|
|
1034
1184
|
exports.getRpcParamName = getRpcParamName;
|
|
1035
1185
|
exports.getRpcPath = getRpcPath;
|
|
@@ -1041,6 +1191,7 @@ exports.handleRoute = handleRoute;
|
|
|
1041
1191
|
exports.isEventStreamRpc = isEventStreamRpc;
|
|
1042
1192
|
exports.isRpc = isRpc;
|
|
1043
1193
|
exports.isRpcParamSchema = isRpcParamSchema;
|
|
1194
|
+
exports.isWorker = isWorker;
|
|
1044
1195
|
exports.registerEventStreamRpc = registerEventStreamRpc;
|
|
1045
1196
|
exports.registerRoute = registerRoute;
|
|
1046
1197
|
exports.registerRpc = registerRpc;
|
package/dist/index.d.cts
CHANGED
|
@@ -186,15 +186,29 @@ type RequestValidator<T = any> = {
|
|
|
186
186
|
declare function getSchemaValidator<T extends Record<string, any> = any>(rpcName: string, type: 'params' | 'response', schema: RpcParamSchema<T>): RequestValidator<T> | undefined;
|
|
187
187
|
declare function getSchemaName(rpcName: string, type: 'params' | 'response', schema: RpcParamSchema<any>): string;
|
|
188
188
|
|
|
189
|
+
type WorkerHandler = (signal: AbortSignal) => Promise<void> | void;
|
|
190
|
+
type WorkerErrorHandler = (error: unknown, worker: ArriWorker) => void | Promise<void>;
|
|
191
|
+
interface ArriWorker {
|
|
192
|
+
name?: string;
|
|
193
|
+
start: (signal: AbortSignal) => Promise<void> | void;
|
|
194
|
+
stop?: () => Promise<void> | void;
|
|
195
|
+
onError?: (error: unknown) => void | Promise<void>;
|
|
196
|
+
}
|
|
197
|
+
declare function defineWorker(worker: ArriWorker | WorkerHandler): ArriWorker;
|
|
198
|
+
declare function isWorker(input: unknown): input is ArriWorker;
|
|
199
|
+
|
|
189
200
|
declare class ArriService {
|
|
190
201
|
name: string;
|
|
191
202
|
constructor(name: string);
|
|
192
203
|
private readonly procedures;
|
|
193
204
|
private readonly definitions;
|
|
205
|
+
private readonly workers;
|
|
194
206
|
rpc(name: string, procedure: Rpc<any, any, any>): void;
|
|
207
|
+
registerWorker(worker: ArriWorker | WorkerHandler): void;
|
|
195
208
|
registerDefinitions(models: DefinitionMap): void;
|
|
196
209
|
getProcedures(): NamedHttpRpc<any, any, any>[];
|
|
197
210
|
getDefinitions(): DefinitionMap;
|
|
211
|
+
getWorkers(): ArriWorker[];
|
|
198
212
|
}
|
|
199
213
|
declare function defineService(name: string, procedures?: Record<string, HttpRpc<any, any, any>>): ArriService;
|
|
200
214
|
|
|
@@ -207,9 +221,15 @@ declare class ArriApp {
|
|
|
207
221
|
private readonly _rpcDefinitionPath;
|
|
208
222
|
private readonly _rpcRoutePrefix;
|
|
209
223
|
appInfo: AppDefinition['info'];
|
|
210
|
-
private _procedures;
|
|
224
|
+
private readonly _procedures;
|
|
211
225
|
private _definitions;
|
|
212
226
|
private readonly _middlewares;
|
|
227
|
+
private readonly _workers;
|
|
228
|
+
private readonly _onStartHooks;
|
|
229
|
+
private readonly _onStopHooks;
|
|
230
|
+
private readonly _workerErrorHooks;
|
|
231
|
+
private _abortController;
|
|
232
|
+
private _isRunning;
|
|
213
233
|
private readonly _onRequest;
|
|
214
234
|
private readonly _onAfterResponse;
|
|
215
235
|
private readonly _onBeforeResponse;
|
|
@@ -225,6 +245,15 @@ declare class ArriApp {
|
|
|
225
245
|
route<TPath extends string, TQuery extends AObjectSchema<any, any>, TBody extends ASchema<any>, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>): void;
|
|
226
246
|
registerDefinitions(definitions: DefinitionMap): void;
|
|
227
247
|
getAppDefinition(): AppDefinition;
|
|
248
|
+
registerWorker(worker: ArriWorker | WorkerHandler): void;
|
|
249
|
+
onStart(hook: () => Promise<void> | void): void;
|
|
250
|
+
onStop(hook: () => Promise<void> | void): void;
|
|
251
|
+
onWorkerError(hook: WorkerErrorHandler): void;
|
|
252
|
+
private _handleWorkerError;
|
|
253
|
+
start(): Promise<void>;
|
|
254
|
+
stop(): Promise<void>;
|
|
255
|
+
get workers(): ArriWorker[];
|
|
256
|
+
get isRunning(): boolean;
|
|
228
257
|
}
|
|
229
258
|
interface ArriOptions {
|
|
230
259
|
debug?: boolean;
|
|
@@ -245,10 +274,13 @@ interface ArriOptions {
|
|
|
245
274
|
onAfterResponse?: (event: RequestHookEvent) => void | Promise<void>;
|
|
246
275
|
onBeforeResponse?: (event: RequestHookEvent) => void | Promise<void>;
|
|
247
276
|
onError?: (error: arriError, event: RequestHookEvent) => void | Promise<void>;
|
|
277
|
+
onStart?: () => Promise<void> | void;
|
|
278
|
+
onStop?: () => Promise<void> | void;
|
|
279
|
+
onWorkerError?: WorkerErrorHandler;
|
|
248
280
|
}
|
|
249
281
|
interface RequestHookEvent extends Omit<H3Event, 'context'> {
|
|
250
282
|
context: RequestHookContext;
|
|
251
283
|
}
|
|
252
284
|
|
|
253
|
-
export { ArriApp, ArriRouter, ArriService, EventStreamConnection, arriError, arriErrorResponse, createAppDefinition, createHttpRpcDefinition, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineService, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, getSchemaName, getSchemaValidator, handleH3Error, handleRoute, isEventStreamRpc, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
|
|
254
|
-
export type { ArriEventContext, ArriOptions, ArriRoute, DefinitionMap, EventStreamConnectionOptions, EventStreamRpc, EventStreamRpcHandler, EventStreamRpcHandlerContext, ExtractParam, ExtractParams, HttpRpc, Middleware, MiddlewareEvent, MiddlewareEventContext, NamedHttpRpc, PostRouteEvent, RequestHookContext, RequestHookEvent, RequestValidator, RouteEvent, RouteEventContext, RouteOptions, RoutePostEventContext, Rpc, RpcEvent, RpcEventContext, RpcHandler, RpcParamSchema, RpcPostEvent, RpcPostEventContext, RpcPostHandler, SsePushResult };
|
|
285
|
+
export { ArriApp, ArriRouter, ArriService, EventStreamConnection, arriError, arriErrorResponse, createAppDefinition, createHttpRpcDefinition, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineService, defineWorker, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, getSchemaName, getSchemaValidator, handleH3Error, handleRoute, isEventStreamRpc, isRpc, isRpcParamSchema, isWorker, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
|
|
286
|
+
export type { ArriEventContext, ArriOptions, ArriRoute, ArriWorker, DefinitionMap, EventStreamConnectionOptions, EventStreamRpc, EventStreamRpcHandler, EventStreamRpcHandlerContext, ExtractParam, ExtractParams, HttpRpc, Middleware, MiddlewareEvent, MiddlewareEventContext, NamedHttpRpc, PostRouteEvent, RequestHookContext, RequestHookEvent, RequestValidator, RouteEvent, RouteEventContext, RouteOptions, RoutePostEventContext, Rpc, RpcEvent, RpcEventContext, RpcHandler, RpcParamSchema, RpcPostEvent, RpcPostEventContext, RpcPostHandler, SsePushResult, WorkerErrorHandler, WorkerHandler };
|
package/dist/index.d.mts
CHANGED
|
@@ -186,15 +186,29 @@ type RequestValidator<T = any> = {
|
|
|
186
186
|
declare function getSchemaValidator<T extends Record<string, any> = any>(rpcName: string, type: 'params' | 'response', schema: RpcParamSchema<T>): RequestValidator<T> | undefined;
|
|
187
187
|
declare function getSchemaName(rpcName: string, type: 'params' | 'response', schema: RpcParamSchema<any>): string;
|
|
188
188
|
|
|
189
|
+
type WorkerHandler = (signal: AbortSignal) => Promise<void> | void;
|
|
190
|
+
type WorkerErrorHandler = (error: unknown, worker: ArriWorker) => void | Promise<void>;
|
|
191
|
+
interface ArriWorker {
|
|
192
|
+
name?: string;
|
|
193
|
+
start: (signal: AbortSignal) => Promise<void> | void;
|
|
194
|
+
stop?: () => Promise<void> | void;
|
|
195
|
+
onError?: (error: unknown) => void | Promise<void>;
|
|
196
|
+
}
|
|
197
|
+
declare function defineWorker(worker: ArriWorker | WorkerHandler): ArriWorker;
|
|
198
|
+
declare function isWorker(input: unknown): input is ArriWorker;
|
|
199
|
+
|
|
189
200
|
declare class ArriService {
|
|
190
201
|
name: string;
|
|
191
202
|
constructor(name: string);
|
|
192
203
|
private readonly procedures;
|
|
193
204
|
private readonly definitions;
|
|
205
|
+
private readonly workers;
|
|
194
206
|
rpc(name: string, procedure: Rpc<any, any, any>): void;
|
|
207
|
+
registerWorker(worker: ArriWorker | WorkerHandler): void;
|
|
195
208
|
registerDefinitions(models: DefinitionMap): void;
|
|
196
209
|
getProcedures(): NamedHttpRpc<any, any, any>[];
|
|
197
210
|
getDefinitions(): DefinitionMap;
|
|
211
|
+
getWorkers(): ArriWorker[];
|
|
198
212
|
}
|
|
199
213
|
declare function defineService(name: string, procedures?: Record<string, HttpRpc<any, any, any>>): ArriService;
|
|
200
214
|
|
|
@@ -207,9 +221,15 @@ declare class ArriApp {
|
|
|
207
221
|
private readonly _rpcDefinitionPath;
|
|
208
222
|
private readonly _rpcRoutePrefix;
|
|
209
223
|
appInfo: AppDefinition['info'];
|
|
210
|
-
private _procedures;
|
|
224
|
+
private readonly _procedures;
|
|
211
225
|
private _definitions;
|
|
212
226
|
private readonly _middlewares;
|
|
227
|
+
private readonly _workers;
|
|
228
|
+
private readonly _onStartHooks;
|
|
229
|
+
private readonly _onStopHooks;
|
|
230
|
+
private readonly _workerErrorHooks;
|
|
231
|
+
private _abortController;
|
|
232
|
+
private _isRunning;
|
|
213
233
|
private readonly _onRequest;
|
|
214
234
|
private readonly _onAfterResponse;
|
|
215
235
|
private readonly _onBeforeResponse;
|
|
@@ -225,6 +245,15 @@ declare class ArriApp {
|
|
|
225
245
|
route<TPath extends string, TQuery extends AObjectSchema<any, any>, TBody extends ASchema<any>, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>): void;
|
|
226
246
|
registerDefinitions(definitions: DefinitionMap): void;
|
|
227
247
|
getAppDefinition(): AppDefinition;
|
|
248
|
+
registerWorker(worker: ArriWorker | WorkerHandler): void;
|
|
249
|
+
onStart(hook: () => Promise<void> | void): void;
|
|
250
|
+
onStop(hook: () => Promise<void> | void): void;
|
|
251
|
+
onWorkerError(hook: WorkerErrorHandler): void;
|
|
252
|
+
private _handleWorkerError;
|
|
253
|
+
start(): Promise<void>;
|
|
254
|
+
stop(): Promise<void>;
|
|
255
|
+
get workers(): ArriWorker[];
|
|
256
|
+
get isRunning(): boolean;
|
|
228
257
|
}
|
|
229
258
|
interface ArriOptions {
|
|
230
259
|
debug?: boolean;
|
|
@@ -245,10 +274,13 @@ interface ArriOptions {
|
|
|
245
274
|
onAfterResponse?: (event: RequestHookEvent) => void | Promise<void>;
|
|
246
275
|
onBeforeResponse?: (event: RequestHookEvent) => void | Promise<void>;
|
|
247
276
|
onError?: (error: arriError, event: RequestHookEvent) => void | Promise<void>;
|
|
277
|
+
onStart?: () => Promise<void> | void;
|
|
278
|
+
onStop?: () => Promise<void> | void;
|
|
279
|
+
onWorkerError?: WorkerErrorHandler;
|
|
248
280
|
}
|
|
249
281
|
interface RequestHookEvent extends Omit<H3Event, 'context'> {
|
|
250
282
|
context: RequestHookContext;
|
|
251
283
|
}
|
|
252
284
|
|
|
253
|
-
export { ArriApp, ArriRouter, ArriService, EventStreamConnection, arriError, arriErrorResponse, createAppDefinition, createHttpRpcDefinition, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineService, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, getSchemaName, getSchemaValidator, handleH3Error, handleRoute, isEventStreamRpc, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
|
|
254
|
-
export type { ArriEventContext, ArriOptions, ArriRoute, DefinitionMap, EventStreamConnectionOptions, EventStreamRpc, EventStreamRpcHandler, EventStreamRpcHandlerContext, ExtractParam, ExtractParams, HttpRpc, Middleware, MiddlewareEvent, MiddlewareEventContext, NamedHttpRpc, PostRouteEvent, RequestHookContext, RequestHookEvent, RequestValidator, RouteEvent, RouteEventContext, RouteOptions, RoutePostEventContext, Rpc, RpcEvent, RpcEventContext, RpcHandler, RpcParamSchema, RpcPostEvent, RpcPostEventContext, RpcPostHandler, SsePushResult };
|
|
285
|
+
export { ArriApp, ArriRouter, ArriService, EventStreamConnection, arriError, arriErrorResponse, createAppDefinition, createHttpRpcDefinition, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineService, defineWorker, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, getSchemaName, getSchemaValidator, handleH3Error, handleRoute, isEventStreamRpc, isRpc, isRpcParamSchema, isWorker, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
|
|
286
|
+
export type { ArriEventContext, ArriOptions, ArriRoute, ArriWorker, DefinitionMap, EventStreamConnectionOptions, EventStreamRpc, EventStreamRpcHandler, EventStreamRpcHandlerContext, ExtractParam, ExtractParams, HttpRpc, Middleware, MiddlewareEvent, MiddlewareEventContext, NamedHttpRpc, PostRouteEvent, RequestHookContext, RequestHookEvent, RequestValidator, RouteEvent, RouteEventContext, RouteOptions, RoutePostEventContext, Rpc, RpcEvent, RpcEventContext, RpcHandler, RpcParamSchema, RpcPostEvent, RpcPostEventContext, RpcPostHandler, SsePushResult, WorkerErrorHandler, WorkerHandler };
|
package/dist/index.d.ts
CHANGED
|
@@ -186,15 +186,29 @@ type RequestValidator<T = any> = {
|
|
|
186
186
|
declare function getSchemaValidator<T extends Record<string, any> = any>(rpcName: string, type: 'params' | 'response', schema: RpcParamSchema<T>): RequestValidator<T> | undefined;
|
|
187
187
|
declare function getSchemaName(rpcName: string, type: 'params' | 'response', schema: RpcParamSchema<any>): string;
|
|
188
188
|
|
|
189
|
+
type WorkerHandler = (signal: AbortSignal) => Promise<void> | void;
|
|
190
|
+
type WorkerErrorHandler = (error: unknown, worker: ArriWorker) => void | Promise<void>;
|
|
191
|
+
interface ArriWorker {
|
|
192
|
+
name?: string;
|
|
193
|
+
start: (signal: AbortSignal) => Promise<void> | void;
|
|
194
|
+
stop?: () => Promise<void> | void;
|
|
195
|
+
onError?: (error: unknown) => void | Promise<void>;
|
|
196
|
+
}
|
|
197
|
+
declare function defineWorker(worker: ArriWorker | WorkerHandler): ArriWorker;
|
|
198
|
+
declare function isWorker(input: unknown): input is ArriWorker;
|
|
199
|
+
|
|
189
200
|
declare class ArriService {
|
|
190
201
|
name: string;
|
|
191
202
|
constructor(name: string);
|
|
192
203
|
private readonly procedures;
|
|
193
204
|
private readonly definitions;
|
|
205
|
+
private readonly workers;
|
|
194
206
|
rpc(name: string, procedure: Rpc<any, any, any>): void;
|
|
207
|
+
registerWorker(worker: ArriWorker | WorkerHandler): void;
|
|
195
208
|
registerDefinitions(models: DefinitionMap): void;
|
|
196
209
|
getProcedures(): NamedHttpRpc<any, any, any>[];
|
|
197
210
|
getDefinitions(): DefinitionMap;
|
|
211
|
+
getWorkers(): ArriWorker[];
|
|
198
212
|
}
|
|
199
213
|
declare function defineService(name: string, procedures?: Record<string, HttpRpc<any, any, any>>): ArriService;
|
|
200
214
|
|
|
@@ -207,9 +221,15 @@ declare class ArriApp {
|
|
|
207
221
|
private readonly _rpcDefinitionPath;
|
|
208
222
|
private readonly _rpcRoutePrefix;
|
|
209
223
|
appInfo: AppDefinition['info'];
|
|
210
|
-
private _procedures;
|
|
224
|
+
private readonly _procedures;
|
|
211
225
|
private _definitions;
|
|
212
226
|
private readonly _middlewares;
|
|
227
|
+
private readonly _workers;
|
|
228
|
+
private readonly _onStartHooks;
|
|
229
|
+
private readonly _onStopHooks;
|
|
230
|
+
private readonly _workerErrorHooks;
|
|
231
|
+
private _abortController;
|
|
232
|
+
private _isRunning;
|
|
213
233
|
private readonly _onRequest;
|
|
214
234
|
private readonly _onAfterResponse;
|
|
215
235
|
private readonly _onBeforeResponse;
|
|
@@ -225,6 +245,15 @@ declare class ArriApp {
|
|
|
225
245
|
route<TPath extends string, TQuery extends AObjectSchema<any, any>, TBody extends ASchema<any>, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>): void;
|
|
226
246
|
registerDefinitions(definitions: DefinitionMap): void;
|
|
227
247
|
getAppDefinition(): AppDefinition;
|
|
248
|
+
registerWorker(worker: ArriWorker | WorkerHandler): void;
|
|
249
|
+
onStart(hook: () => Promise<void> | void): void;
|
|
250
|
+
onStop(hook: () => Promise<void> | void): void;
|
|
251
|
+
onWorkerError(hook: WorkerErrorHandler): void;
|
|
252
|
+
private _handleWorkerError;
|
|
253
|
+
start(): Promise<void>;
|
|
254
|
+
stop(): Promise<void>;
|
|
255
|
+
get workers(): ArriWorker[];
|
|
256
|
+
get isRunning(): boolean;
|
|
228
257
|
}
|
|
229
258
|
interface ArriOptions {
|
|
230
259
|
debug?: boolean;
|
|
@@ -245,10 +274,13 @@ interface ArriOptions {
|
|
|
245
274
|
onAfterResponse?: (event: RequestHookEvent) => void | Promise<void>;
|
|
246
275
|
onBeforeResponse?: (event: RequestHookEvent) => void | Promise<void>;
|
|
247
276
|
onError?: (error: arriError, event: RequestHookEvent) => void | Promise<void>;
|
|
277
|
+
onStart?: () => Promise<void> | void;
|
|
278
|
+
onStop?: () => Promise<void> | void;
|
|
279
|
+
onWorkerError?: WorkerErrorHandler;
|
|
248
280
|
}
|
|
249
281
|
interface RequestHookEvent extends Omit<H3Event, 'context'> {
|
|
250
282
|
context: RequestHookContext;
|
|
251
283
|
}
|
|
252
284
|
|
|
253
|
-
export { ArriApp, ArriRouter, ArriService, EventStreamConnection, arriError, arriErrorResponse, createAppDefinition, createHttpRpcDefinition, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineService, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, getSchemaName, getSchemaValidator, handleH3Error, handleRoute, isEventStreamRpc, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
|
|
254
|
-
export type { ArriEventContext, ArriOptions, ArriRoute, DefinitionMap, EventStreamConnectionOptions, EventStreamRpc, EventStreamRpcHandler, EventStreamRpcHandlerContext, ExtractParam, ExtractParams, HttpRpc, Middleware, MiddlewareEvent, MiddlewareEventContext, NamedHttpRpc, PostRouteEvent, RequestHookContext, RequestHookEvent, RequestValidator, RouteEvent, RouteEventContext, RouteOptions, RoutePostEventContext, Rpc, RpcEvent, RpcEventContext, RpcHandler, RpcParamSchema, RpcPostEvent, RpcPostEventContext, RpcPostHandler, SsePushResult };
|
|
285
|
+
export { ArriApp, ArriRouter, ArriService, EventStreamConnection, arriError, arriErrorResponse, createAppDefinition, createHttpRpcDefinition, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineService, defineWorker, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, getSchemaName, getSchemaValidator, handleH3Error, handleRoute, isEventStreamRpc, isRpc, isRpcParamSchema, isWorker, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
|
|
286
|
+
export type { ArriEventContext, ArriOptions, ArriRoute, ArriWorker, DefinitionMap, EventStreamConnectionOptions, EventStreamRpc, EventStreamRpcHandler, EventStreamRpcHandlerContext, ExtractParam, ExtractParams, HttpRpc, Middleware, MiddlewareEvent, MiddlewareEventContext, NamedHttpRpc, PostRouteEvent, RequestHookContext, RequestHookEvent, RequestValidator, RouteEvent, RouteEventContext, RouteOptions, RoutePostEventContext, Rpc, RpcEvent, RpcEventContext, RpcHandler, RpcParamSchema, RpcPostEvent, RpcPostEventContext, RpcPostHandler, SsePushResult, WorkerErrorHandler, WorkerHandler };
|
package/dist/index.mjs
CHANGED
|
@@ -803,6 +803,18 @@ class ArriRouter {
|
|
|
803
803
|
}
|
|
804
804
|
}
|
|
805
805
|
|
|
806
|
+
function defineWorker(worker) {
|
|
807
|
+
if (typeof worker === "function") {
|
|
808
|
+
return {
|
|
809
|
+
start: worker
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
return worker;
|
|
813
|
+
}
|
|
814
|
+
function isWorker(input) {
|
|
815
|
+
return typeof input === "object" && input !== null && "start" in input && typeof input.start === "function";
|
|
816
|
+
}
|
|
817
|
+
|
|
806
818
|
class ArriService {
|
|
807
819
|
name;
|
|
808
820
|
constructor(name) {
|
|
@@ -810,10 +822,14 @@ class ArriService {
|
|
|
810
822
|
}
|
|
811
823
|
procedures = [];
|
|
812
824
|
definitions = {};
|
|
825
|
+
workers = [];
|
|
813
826
|
rpc(name, procedure) {
|
|
814
827
|
procedure.name = `${this.name}.${name}`;
|
|
815
828
|
this.procedures.push(procedure);
|
|
816
829
|
}
|
|
830
|
+
registerWorker(worker) {
|
|
831
|
+
this.workers.push(defineWorker(worker));
|
|
832
|
+
}
|
|
817
833
|
registerDefinitions(models) {
|
|
818
834
|
for (const key of Object.keys(models)) {
|
|
819
835
|
this.definitions[key] = models[key];
|
|
@@ -825,6 +841,9 @@ class ArriService {
|
|
|
825
841
|
getDefinitions() {
|
|
826
842
|
return this.definitions;
|
|
827
843
|
}
|
|
844
|
+
getWorkers() {
|
|
845
|
+
return this.workers;
|
|
846
|
+
}
|
|
828
847
|
}
|
|
829
848
|
function defineService(name, procedures) {
|
|
830
849
|
const service = new ArriService(name);
|
|
@@ -845,6 +864,12 @@ class ArriApp {
|
|
|
845
864
|
_procedures = {};
|
|
846
865
|
_definitions = {};
|
|
847
866
|
_middlewares = [];
|
|
867
|
+
_workers = [];
|
|
868
|
+
_onStartHooks = [];
|
|
869
|
+
_onStopHooks = [];
|
|
870
|
+
_workerErrorHooks = [];
|
|
871
|
+
_abortController = null;
|
|
872
|
+
_isRunning = false;
|
|
848
873
|
_onRequest;
|
|
849
874
|
_onAfterResponse;
|
|
850
875
|
_onBeforeResponse;
|
|
@@ -862,6 +887,15 @@ class ArriApp {
|
|
|
862
887
|
this._onError = opts.onError;
|
|
863
888
|
this._onAfterResponse = opts.onAfterResponse;
|
|
864
889
|
this._onBeforeResponse = opts.onBeforeResponse;
|
|
890
|
+
if (opts.onStart) {
|
|
891
|
+
this.onStart(opts.onStart);
|
|
892
|
+
}
|
|
893
|
+
if (opts.onStop) {
|
|
894
|
+
this.onStop(opts.onStop);
|
|
895
|
+
}
|
|
896
|
+
if (opts.onWorkerError) {
|
|
897
|
+
this.onWorkerError(opts.onWorkerError);
|
|
898
|
+
}
|
|
865
899
|
this._heartbeatMs = opts.heartbeatMs ?? 2e4;
|
|
866
900
|
this._rpcRoutePrefix = opts?.rpcRoutePrefix ?? "";
|
|
867
901
|
this._rpcDefinitionPath = opts?.rpcDefinitionPath ?? "__definition";
|
|
@@ -936,6 +970,9 @@ class ArriApp {
|
|
|
936
970
|
this.rpc(rpc.name, rpc);
|
|
937
971
|
}
|
|
938
972
|
this.registerDefinitions(input.getDefinitions());
|
|
973
|
+
for (const worker of input.getWorkers()) {
|
|
974
|
+
this.registerWorker(worker);
|
|
975
|
+
}
|
|
939
976
|
return;
|
|
940
977
|
}
|
|
941
978
|
this._middlewares.push(input);
|
|
@@ -1011,8 +1048,120 @@ class ArriApp {
|
|
|
1011
1048
|
}
|
|
1012
1049
|
return appDef;
|
|
1013
1050
|
}
|
|
1051
|
+
registerWorker(worker) {
|
|
1052
|
+
const w = defineWorker(worker);
|
|
1053
|
+
this._workers.push(w);
|
|
1054
|
+
if (this._isRunning && this._abortController) {
|
|
1055
|
+
void (async () => {
|
|
1056
|
+
try {
|
|
1057
|
+
await w.start(this._abortController.signal);
|
|
1058
|
+
} catch (err) {
|
|
1059
|
+
await this._handleWorkerError(w, err);
|
|
1060
|
+
}
|
|
1061
|
+
})();
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
onStart(hook) {
|
|
1065
|
+
this._onStartHooks.push(hook);
|
|
1066
|
+
}
|
|
1067
|
+
onStop(hook) {
|
|
1068
|
+
this._onStopHooks.push(hook);
|
|
1069
|
+
}
|
|
1070
|
+
onWorkerError(hook) {
|
|
1071
|
+
this._workerErrorHooks.push(hook);
|
|
1072
|
+
}
|
|
1073
|
+
async _handleWorkerError(worker, error) {
|
|
1074
|
+
let handled = false;
|
|
1075
|
+
if (worker.onError) {
|
|
1076
|
+
try {
|
|
1077
|
+
await worker.onError(error);
|
|
1078
|
+
handled = true;
|
|
1079
|
+
} catch (hookErr) {
|
|
1080
|
+
console.error(
|
|
1081
|
+
`[Arri] Error in worker.onError hook for worker ${worker.name ?? "unnamed"}:`,
|
|
1082
|
+
hookErr
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
for (const hook of this._workerErrorHooks) {
|
|
1087
|
+
try {
|
|
1088
|
+
await hook(error, worker);
|
|
1089
|
+
handled = true;
|
|
1090
|
+
} catch (hookErr) {
|
|
1091
|
+
console.error(
|
|
1092
|
+
`[Arri] Error in onWorkerError hook for worker ${worker.name ?? "unnamed"}:`,
|
|
1093
|
+
hookErr
|
|
1094
|
+
);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
if (!handled) {
|
|
1098
|
+
console.error(
|
|
1099
|
+
`[Arri] Unhandled error in worker ${worker.name ?? "unnamed"}:`,
|
|
1100
|
+
error
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
async start() {
|
|
1105
|
+
if (this._isRunning) {
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
this._isRunning = true;
|
|
1109
|
+
const controller = new AbortController();
|
|
1110
|
+
this._abortController = controller;
|
|
1111
|
+
try {
|
|
1112
|
+
for (const hook of this._onStartHooks) {
|
|
1113
|
+
await hook();
|
|
1114
|
+
}
|
|
1115
|
+
} catch (err) {
|
|
1116
|
+
this._isRunning = false;
|
|
1117
|
+
controller.abort();
|
|
1118
|
+
this._abortController = null;
|
|
1119
|
+
throw err;
|
|
1120
|
+
}
|
|
1121
|
+
for (const worker of this._workers) {
|
|
1122
|
+
void (async () => {
|
|
1123
|
+
try {
|
|
1124
|
+
await worker.start(controller.signal);
|
|
1125
|
+
} catch (err) {
|
|
1126
|
+
await this._handleWorkerError(worker, err);
|
|
1127
|
+
}
|
|
1128
|
+
})();
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
async stop() {
|
|
1132
|
+
if (!this._isRunning) {
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
this._isRunning = false;
|
|
1136
|
+
this._abortController?.abort();
|
|
1137
|
+
const stopPromises = this._workers.map(async (worker) => {
|
|
1138
|
+
try {
|
|
1139
|
+
if (worker.stop) {
|
|
1140
|
+
await worker.stop();
|
|
1141
|
+
}
|
|
1142
|
+
} catch (err) {
|
|
1143
|
+
await this._handleWorkerError(worker, err);
|
|
1144
|
+
}
|
|
1145
|
+
});
|
|
1146
|
+
const hookPromises = this._onStopHooks.map(async (hook) => {
|
|
1147
|
+
try {
|
|
1148
|
+
await hook();
|
|
1149
|
+
} catch (err) {
|
|
1150
|
+
if (this._debug) {
|
|
1151
|
+
console.error("Error in onStop hook:", err);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
});
|
|
1155
|
+
await Promise.allSettled([...stopPromises, ...hookPromises]);
|
|
1156
|
+
}
|
|
1157
|
+
get workers() {
|
|
1158
|
+
return [...this._workers];
|
|
1159
|
+
}
|
|
1160
|
+
get isRunning() {
|
|
1161
|
+
return this._isRunning;
|
|
1162
|
+
}
|
|
1014
1163
|
}
|
|
1015
1164
|
|
|
1016
1165
|
const defineMiddleware = (middleware) => middleware;
|
|
1017
1166
|
|
|
1018
|
-
export { ArriApp, ArriRouter, ArriService, EventStreamConnection, arriError, arriErrorResponse, createAppDefinition, createHttpRpcDefinition, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineService, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, getSchemaName, getSchemaValidator, handleH3Error, handleRoute, isEventStreamRpc, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
|
|
1167
|
+
export { ArriApp, ArriRouter, ArriService, EventStreamConnection, arriError, arriErrorResponse, createAppDefinition, createHttpRpcDefinition, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineService, defineWorker, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, getSchemaName, getSchemaValidator, handleH3Error, handleRoute, isEventStreamRpc, isRpc, isRpcParamSchema, isWorker, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arrirpc/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.85.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"scule": "^1.3.0",
|
|
29
29
|
"source-map-support": "^0.5.21",
|
|
30
30
|
"uncrypto": "^0.1.3",
|
|
31
|
-
"@arrirpc/codegen-utils": "0.
|
|
32
|
-
"@arrirpc/schema": "0.
|
|
33
|
-
"arri": "0.
|
|
31
|
+
"@arrirpc/codegen-utils": "0.85.0",
|
|
32
|
+
"@arrirpc/schema": "0.85.0",
|
|
33
|
+
"arri": "0.85.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"bun-types": "^1.3.8"
|