@qlever-llc/trellis 0.10.5 → 0.10.8
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/esm/auth/protocol.d.ts +120 -3
- package/esm/auth/protocol.d.ts.map +1 -1
- package/esm/auth/protocol.js +43 -1
- package/esm/generated-sdk/auth/client.d.ts +137 -76
- package/esm/generated-sdk/auth/client.d.ts.map +1 -1
- package/esm/generated-sdk/auth/contract.d.ts +1 -1
- package/esm/generated-sdk/auth/contract.d.ts.map +1 -1
- package/esm/generated-sdk/auth/contract.js +2 -2
- package/esm/generated-sdk/auth/mod.d.ts +1 -1
- package/esm/generated-sdk/auth/mod.d.ts.map +1 -1
- package/esm/generated-sdk/auth/schemas.d.ts +329 -2
- package/esm/generated-sdk/auth/schemas.d.ts.map +1 -1
- package/esm/generated-sdk/auth/schemas.js +3 -3
- package/esm/generated-sdk/auth/types.d.ts +47 -3
- package/esm/generated-sdk/auth/types.d.ts.map +1 -1
- package/esm/generated-sdk/auth/types.js +1 -1
- package/esm/generated-sdk/health/client.d.ts +27 -4
- package/esm/generated-sdk/health/client.d.ts.map +1 -1
- package/esm/generated-sdk/health/mod.d.ts +1 -1
- package/esm/generated-sdk/health/mod.d.ts.map +1 -1
- package/esm/generated-sdk/jobs/client.d.ts +38 -15
- package/esm/generated-sdk/jobs/client.d.ts.map +1 -1
- package/esm/generated-sdk/jobs/mod.d.ts +1 -1
- package/esm/generated-sdk/jobs/mod.d.ts.map +1 -1
- package/esm/generated-sdk/state/client.d.ts +36 -13
- package/esm/generated-sdk/state/client.d.ts.map +1 -1
- package/esm/generated-sdk/state/mod.d.ts +1 -1
- package/esm/generated-sdk/state/mod.d.ts.map +1 -1
- package/esm/generated-sdk/trellis-core/client.d.ts +17 -7
- package/esm/generated-sdk/trellis-core/client.d.ts.map +1 -1
- package/esm/generated-sdk/trellis-core/mod.d.ts +1 -1
- package/esm/generated-sdk/trellis-core/mod.d.ts.map +1 -1
- package/esm/index.d.ts +1 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/server/service.d.ts +80 -2
- package/esm/server/service.d.ts.map +1 -1
- package/esm/server/service.js +100 -3
- package/esm/service/deno.d.ts +1 -1
- package/esm/service/deno.d.ts.map +1 -1
- package/esm/service/mod.d.ts +1 -1
- package/esm/service/mod.d.ts.map +1 -1
- package/esm/service/node.d.ts +1 -1
- package/esm/service/node.d.ts.map +1 -1
- package/esm/trellis.d.ts +17 -2
- package/esm/trellis.d.ts.map +1 -1
- package/esm/trellis.js +39 -3
- package/package.json +2 -2
- package/script/auth/protocol.d.ts +120 -3
- package/script/auth/protocol.d.ts.map +1 -1
- package/script/auth/protocol.js +47 -5
- package/script/generated-sdk/auth/client.d.ts +137 -76
- package/script/generated-sdk/auth/client.d.ts.map +1 -1
- package/script/generated-sdk/auth/contract.d.ts +1 -1
- package/script/generated-sdk/auth/contract.d.ts.map +1 -1
- package/script/generated-sdk/auth/contract.js +2 -2
- package/script/generated-sdk/auth/mod.d.ts +1 -1
- package/script/generated-sdk/auth/mod.d.ts.map +1 -1
- package/script/generated-sdk/auth/schemas.d.ts +329 -2
- package/script/generated-sdk/auth/schemas.d.ts.map +1 -1
- package/script/generated-sdk/auth/schemas.js +3 -3
- package/script/generated-sdk/auth/types.d.ts +47 -3
- package/script/generated-sdk/auth/types.d.ts.map +1 -1
- package/script/generated-sdk/auth/types.js +1 -1
- package/script/generated-sdk/health/client.d.ts +27 -4
- package/script/generated-sdk/health/client.d.ts.map +1 -1
- package/script/generated-sdk/health/mod.d.ts +1 -1
- package/script/generated-sdk/health/mod.d.ts.map +1 -1
- package/script/generated-sdk/jobs/client.d.ts +38 -15
- package/script/generated-sdk/jobs/client.d.ts.map +1 -1
- package/script/generated-sdk/jobs/mod.d.ts +1 -1
- package/script/generated-sdk/jobs/mod.d.ts.map +1 -1
- package/script/generated-sdk/state/client.d.ts +36 -13
- package/script/generated-sdk/state/client.d.ts.map +1 -1
- package/script/generated-sdk/state/mod.d.ts +1 -1
- package/script/generated-sdk/state/mod.d.ts.map +1 -1
- package/script/generated-sdk/trellis-core/client.d.ts +17 -7
- package/script/generated-sdk/trellis-core/client.d.ts.map +1 -1
- package/script/generated-sdk/trellis-core/mod.d.ts +1 -1
- package/script/generated-sdk/trellis-core/mod.d.ts.map +1 -1
- package/script/index.d.ts +1 -1
- package/script/index.d.ts.map +1 -1
- package/script/server/service.d.ts +80 -2
- package/script/server/service.d.ts.map +1 -1
- package/script/server/service.js +99 -2
- package/script/service/deno.d.ts +1 -1
- package/script/service/deno.d.ts.map +1 -1
- package/script/service/mod.d.ts +1 -1
- package/script/service/mod.d.ts.map +1 -1
- package/script/service/node.d.ts +1 -1
- package/script/service/node.d.ts.map +1 -1
- package/script/trellis.d.ts +17 -2
- package/script/trellis.d.ts.map +1 -1
- package/script/trellis.js +39 -3
- package/src/auth/protocol.ts +55 -1
- package/src/index.ts +1 -0
- package/src/sdk/_generated/auth/client.ts +100 -72
- package/src/sdk/_generated/auth/contract.ts +2 -2
- package/src/sdk/_generated/auth/mod.ts +1 -1
- package/src/sdk/_generated/auth/schemas.ts +3 -3
- package/src/sdk/_generated/auth/types.ts +4 -4
- package/src/sdk/_generated/core/client.ts +25 -8
- package/src/sdk/_generated/core/mod.ts +1 -1
- package/src/sdk/_generated/health/client.ts +26 -5
- package/src/sdk/_generated/health/mod.ts +1 -1
- package/src/sdk/_generated/jobs/client.ts +35 -14
- package/src/sdk/_generated/jobs/mod.ts +1 -1
- package/src/sdk/_generated/state/client.ts +33 -12
- package/src/sdk/_generated/state/mod.ts +1 -1
- package/src/server/service.ts +485 -2
- package/src/service/deno.ts +1 -0
- package/src/service/mod.ts +1 -0
- package/src/service/node.ts +1 -0
- package/src/trellis.ts +80 -5
package/src/server/service.ts
CHANGED
|
@@ -40,16 +40,24 @@ import {
|
|
|
40
40
|
CONTRACT_JOBS_METADATA,
|
|
41
41
|
CONTRACT_KV_METADATA,
|
|
42
42
|
} from "../contract_support/mod.js";
|
|
43
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
AsyncResult,
|
|
45
|
+
type BaseError,
|
|
46
|
+
isErr,
|
|
47
|
+
type MaybeAsync,
|
|
48
|
+
Result,
|
|
49
|
+
} from "@qlever-llc/result";
|
|
44
50
|
import { Type } from "typebox";
|
|
45
51
|
import { Value } from "typebox/value";
|
|
46
52
|
import { type HealthCheckFn, ServiceHealth } from "./health.js";
|
|
47
53
|
import { mountStandardHealthRpc } from "./health_rpc.js";
|
|
48
|
-
import type { RPCDesc } from "../contracts.js";
|
|
54
|
+
import type { EventDesc, RPCDesc } from "../contracts.js";
|
|
49
55
|
import type {
|
|
50
56
|
AcceptedOperation,
|
|
51
57
|
ActiveEventFacade,
|
|
52
58
|
ActiveEventPublishFacade,
|
|
59
|
+
EventListenerContext,
|
|
60
|
+
EventOpts,
|
|
53
61
|
FeedEventOf,
|
|
54
62
|
FeedInputOf,
|
|
55
63
|
FeedRegistration as RootFeedRegistration,
|
|
@@ -60,6 +68,7 @@ import type {
|
|
|
60
68
|
OperationRegistration as RootOperationRegistration,
|
|
61
69
|
OperationRuntimeHandle,
|
|
62
70
|
OperationTransferContextOf,
|
|
71
|
+
PreparedTrellisEvent,
|
|
63
72
|
RpcHandlerContext,
|
|
64
73
|
RpcHandlerErrorOf,
|
|
65
74
|
} from "../trellis.js";
|
|
@@ -1097,6 +1106,268 @@ export type JobsFacadeOf<
|
|
|
1097
1106
|
>;
|
|
1098
1107
|
};
|
|
1099
1108
|
|
|
1109
|
+
type ServiceEventName<TA extends TrellisAPI> = keyof TA["events"] & string;
|
|
1110
|
+
type ServiceEventOf<
|
|
1111
|
+
TA extends TrellisAPI,
|
|
1112
|
+
E extends ServiceEventName<TA>,
|
|
1113
|
+
> = TA["events"][E] extends EventDesc<infer TEvent> ? InferSchemaType<TEvent>
|
|
1114
|
+
: never;
|
|
1115
|
+
type ServiceEventPayloadOf<
|
|
1116
|
+
TA extends TrellisAPI,
|
|
1117
|
+
E extends ServiceEventName<TA>,
|
|
1118
|
+
> = Omit<ServiceEventOf<TA, E>, "header">;
|
|
1119
|
+
|
|
1120
|
+
type BoundEventHandleFn<
|
|
1121
|
+
TEventApi extends TrellisAPI,
|
|
1122
|
+
TTrellisApi extends TrellisAPI,
|
|
1123
|
+
E extends ServiceEventName<TEventApi>,
|
|
1124
|
+
TKv extends ContractKvMetadata,
|
|
1125
|
+
TJobs extends ContractJobsMetadata,
|
|
1126
|
+
TDeps,
|
|
1127
|
+
> = (args: {
|
|
1128
|
+
event: ServiceEventOf<TEventApi, E>;
|
|
1129
|
+
context: EventListenerContext;
|
|
1130
|
+
client: Trellis<TTrellisApi, TKv, TJobs>;
|
|
1131
|
+
deps: TDeps;
|
|
1132
|
+
}) => MaybeAsync<void, BaseError>;
|
|
1133
|
+
|
|
1134
|
+
type BoundActiveEventFacade<
|
|
1135
|
+
TEventApi extends TrellisAPI,
|
|
1136
|
+
TTrellisApi extends TrellisAPI,
|
|
1137
|
+
TKv extends ContractKvMetadata,
|
|
1138
|
+
TJobs extends ContractJobsMetadata,
|
|
1139
|
+
TDeps,
|
|
1140
|
+
> = {
|
|
1141
|
+
readonly [TGroup in SurfaceGroupName<ServiceEventName<TEventApi>>]: {
|
|
1142
|
+
readonly [
|
|
1143
|
+
E in SurfaceKeysForGroup<
|
|
1144
|
+
ServiceEventName<TEventApi>,
|
|
1145
|
+
TGroup
|
|
1146
|
+
> as SurfaceLeafName<E>
|
|
1147
|
+
]: {
|
|
1148
|
+
prepare(
|
|
1149
|
+
event: ServiceEventPayloadOf<TEventApi, E>,
|
|
1150
|
+
): Result<
|
|
1151
|
+
PreparedTrellisEvent<ServiceEventPayloadOf<TEventApi, E>>,
|
|
1152
|
+
ValidationError | UnexpectedError
|
|
1153
|
+
>;
|
|
1154
|
+
publish(
|
|
1155
|
+
event: ServiceEventPayloadOf<TEventApi, E>,
|
|
1156
|
+
): AsyncResult<void, ValidationError | UnexpectedError>;
|
|
1157
|
+
listen(
|
|
1158
|
+
handler: BoundEventHandleFn<
|
|
1159
|
+
TEventApi,
|
|
1160
|
+
TTrellisApi,
|
|
1161
|
+
E,
|
|
1162
|
+
TKv,
|
|
1163
|
+
TJobs,
|
|
1164
|
+
TDeps
|
|
1165
|
+
>,
|
|
1166
|
+
subjectData?: Record<string, unknown>,
|
|
1167
|
+
opts?: EventOpts,
|
|
1168
|
+
): AsyncResult<void, ValidationError | UnexpectedError>;
|
|
1169
|
+
};
|
|
1170
|
+
};
|
|
1171
|
+
};
|
|
1172
|
+
|
|
1173
|
+
type BoundRpcHandleFn<
|
|
1174
|
+
TOwnedApi extends TrellisAPI,
|
|
1175
|
+
TTrellisApi extends TrellisAPI,
|
|
1176
|
+
M extends RpcMethodName<TOwnedApi>,
|
|
1177
|
+
TKv extends ContractKvMetadata,
|
|
1178
|
+
TJobs extends ContractJobsMetadata,
|
|
1179
|
+
TDeps,
|
|
1180
|
+
> = (args: {
|
|
1181
|
+
input: RpcMethodInput<TOwnedApi, M>;
|
|
1182
|
+
context: RpcHandlerContext;
|
|
1183
|
+
client: Trellis<TTrellisApi, TKv, TJobs>;
|
|
1184
|
+
deps: TDeps;
|
|
1185
|
+
}) =>
|
|
1186
|
+
| Promise<
|
|
1187
|
+
Result<RpcMethodOutput<TOwnedApi, M>, RpcHandlerErrorOf<TOwnedApi, M>>
|
|
1188
|
+
>
|
|
1189
|
+
| Result<RpcMethodOutput<TOwnedApi, M>, RpcHandlerErrorOf<TOwnedApi, M>>;
|
|
1190
|
+
|
|
1191
|
+
type BoundFeedHandleFn<
|
|
1192
|
+
TOwnedApi extends TrellisAPI,
|
|
1193
|
+
TTrellisApi extends TrellisAPI,
|
|
1194
|
+
F extends keyof TOwnedApi["feeds"] & string,
|
|
1195
|
+
TKv extends ContractKvMetadata,
|
|
1196
|
+
TJobs extends ContractJobsMetadata,
|
|
1197
|
+
TDeps,
|
|
1198
|
+
> = (context: {
|
|
1199
|
+
input: FeedInputOf<TOwnedApi, F>;
|
|
1200
|
+
caller: unknown;
|
|
1201
|
+
signal: AbortSignal;
|
|
1202
|
+
emit(
|
|
1203
|
+
event: FeedEventOf<TOwnedApi, F>,
|
|
1204
|
+
): AsyncResult<void, ValidationError | UnexpectedError>;
|
|
1205
|
+
client: Trellis<TTrellisApi, TKv, TJobs>;
|
|
1206
|
+
deps: TDeps;
|
|
1207
|
+
}) => unknown | Promise<unknown>;
|
|
1208
|
+
|
|
1209
|
+
type BoundOperationHandleFn<
|
|
1210
|
+
TOwnedApi extends TrellisAPI,
|
|
1211
|
+
TTrellisApi extends TrellisAPI,
|
|
1212
|
+
O extends keyof TOwnedApi["operations"] & string,
|
|
1213
|
+
TKv extends ContractKvMetadata,
|
|
1214
|
+
TJobs extends ContractJobsMetadata,
|
|
1215
|
+
TDeps,
|
|
1216
|
+
> =
|
|
1217
|
+
& ((
|
|
1218
|
+
handler: (
|
|
1219
|
+
context:
|
|
1220
|
+
& OperationHandlerContext<
|
|
1221
|
+
InferSchemaType<TOwnedApi["operations"][O]["input"]>,
|
|
1222
|
+
OperationProgressOf<TOwnedApi, O>,
|
|
1223
|
+
OperationOutputOf<TOwnedApi, O>,
|
|
1224
|
+
OperationTransferContextOf<TOwnedApi, O>
|
|
1225
|
+
>
|
|
1226
|
+
& {
|
|
1227
|
+
client: Trellis<TTrellisApi, TKv, TJobs>;
|
|
1228
|
+
deps: TDeps;
|
|
1229
|
+
},
|
|
1230
|
+
) => unknown | Promise<unknown>,
|
|
1231
|
+
) => Promise<void>)
|
|
1232
|
+
& Pick<
|
|
1233
|
+
OperationHandleFn<TOwnedApi, TTrellisApi, O, TKv, TJobs>,
|
|
1234
|
+
"accept" | "control"
|
|
1235
|
+
>;
|
|
1236
|
+
|
|
1237
|
+
type BoundTypedServiceHandleFacade<
|
|
1238
|
+
TOwnedApi extends TrellisAPI,
|
|
1239
|
+
TTrellisApi extends TrellisAPI,
|
|
1240
|
+
TKv extends ContractKvMetadata,
|
|
1241
|
+
TJobs extends ContractJobsMetadata,
|
|
1242
|
+
TDeps,
|
|
1243
|
+
> = {
|
|
1244
|
+
readonly rpc: {
|
|
1245
|
+
readonly [TGroup in SurfaceGroupName<RpcMethodName<TOwnedApi>>]: {
|
|
1246
|
+
readonly [
|
|
1247
|
+
M in SurfaceKeysForGroup<
|
|
1248
|
+
RpcMethodName<TOwnedApi>,
|
|
1249
|
+
TGroup
|
|
1250
|
+
> as SurfaceLeafName<M>
|
|
1251
|
+
]: (
|
|
1252
|
+
handler: BoundRpcHandleFn<TOwnedApi, TTrellisApi, M, TKv, TJobs, TDeps>,
|
|
1253
|
+
) => Promise<void>;
|
|
1254
|
+
};
|
|
1255
|
+
};
|
|
1256
|
+
readonly feed: {
|
|
1257
|
+
readonly [TGroup in SurfaceGroupName<keyof TOwnedApi["feeds"] & string>]: {
|
|
1258
|
+
readonly [
|
|
1259
|
+
F in SurfaceKeysForGroup<
|
|
1260
|
+
keyof TOwnedApi["feeds"] & string,
|
|
1261
|
+
TGroup
|
|
1262
|
+
> as SurfaceLeafName<F>
|
|
1263
|
+
]: (
|
|
1264
|
+
handler: BoundFeedHandleFn<
|
|
1265
|
+
TOwnedApi,
|
|
1266
|
+
TTrellisApi,
|
|
1267
|
+
F,
|
|
1268
|
+
TKv,
|
|
1269
|
+
TJobs,
|
|
1270
|
+
TDeps
|
|
1271
|
+
>,
|
|
1272
|
+
) => Promise<void>;
|
|
1273
|
+
};
|
|
1274
|
+
};
|
|
1275
|
+
readonly operation: {
|
|
1276
|
+
readonly [
|
|
1277
|
+
TGroup in SurfaceGroupName<keyof TOwnedApi["operations"] & string>
|
|
1278
|
+
]: {
|
|
1279
|
+
readonly [
|
|
1280
|
+
O in SurfaceKeysForGroup<
|
|
1281
|
+
keyof TOwnedApi["operations"] & string,
|
|
1282
|
+
TGroup
|
|
1283
|
+
> as SurfaceLeafName<O>
|
|
1284
|
+
]: BoundOperationHandleFn<TOwnedApi, TTrellisApi, O, TKv, TJobs, TDeps>;
|
|
1285
|
+
};
|
|
1286
|
+
};
|
|
1287
|
+
};
|
|
1288
|
+
|
|
1289
|
+
type BoundJobQueue<
|
|
1290
|
+
TPayload,
|
|
1291
|
+
TResult,
|
|
1292
|
+
TTrellisApi extends TrellisAPI,
|
|
1293
|
+
TKv extends ContractKvMetadata,
|
|
1294
|
+
TJobs extends ContractJobsMetadata,
|
|
1295
|
+
TDeps,
|
|
1296
|
+
> = {
|
|
1297
|
+
create(payload: TPayload): AsyncResult<JobRef<TPayload, TResult>, BaseError>;
|
|
1298
|
+
handle(
|
|
1299
|
+
handler: (args: {
|
|
1300
|
+
job: PublicActiveJob<TPayload, TResult>;
|
|
1301
|
+
client: Trellis<TTrellisApi, TKv, TJobs>;
|
|
1302
|
+
deps: TDeps;
|
|
1303
|
+
}) => Promise<Result<TResult, BaseError>>,
|
|
1304
|
+
): void;
|
|
1305
|
+
};
|
|
1306
|
+
|
|
1307
|
+
type BoundJobsFacadeOf<
|
|
1308
|
+
TJobs extends ContractJobsMetadata,
|
|
1309
|
+
TTrellisApi extends TrellisAPI,
|
|
1310
|
+
TKv extends ContractKvMetadata,
|
|
1311
|
+
TDeps,
|
|
1312
|
+
> = {
|
|
1313
|
+
[K in keyof TJobs]: BoundJobQueue<
|
|
1314
|
+
TJobs[K]["payload"],
|
|
1315
|
+
TJobs[K]["result"],
|
|
1316
|
+
TTrellisApi,
|
|
1317
|
+
TKv,
|
|
1318
|
+
TJobs,
|
|
1319
|
+
TDeps
|
|
1320
|
+
>;
|
|
1321
|
+
};
|
|
1322
|
+
|
|
1323
|
+
/** Service wrapper returned by `TrellisService.with(deps)`. */
|
|
1324
|
+
export type BoundTrellisService<
|
|
1325
|
+
TOwnedApi extends TrellisAPI = TrellisAPI,
|
|
1326
|
+
TTrellisApi extends TrellisAPI = TOwnedApi,
|
|
1327
|
+
TJobs extends ContractJobsMetadata = {},
|
|
1328
|
+
TKv extends ContractKvMetadata = ContractKvMetadata,
|
|
1329
|
+
TDeps = unknown,
|
|
1330
|
+
> =
|
|
1331
|
+
& Pick<
|
|
1332
|
+
TrellisService<TOwnedApi, TTrellisApi, TJobs, TKv>,
|
|
1333
|
+
| "name"
|
|
1334
|
+
| "auth"
|
|
1335
|
+
| "nc"
|
|
1336
|
+
| "kv"
|
|
1337
|
+
| "store"
|
|
1338
|
+
| "health"
|
|
1339
|
+
| "connection"
|
|
1340
|
+
| "createTransfer"
|
|
1341
|
+
| "completeOperation"
|
|
1342
|
+
| "wait"
|
|
1343
|
+
| "stop"
|
|
1344
|
+
>
|
|
1345
|
+
& {
|
|
1346
|
+
readonly event: BoundActiveEventFacade<
|
|
1347
|
+
TTrellisApi,
|
|
1348
|
+
TTrellisApi,
|
|
1349
|
+
TKv,
|
|
1350
|
+
TJobs,
|
|
1351
|
+
TDeps
|
|
1352
|
+
>;
|
|
1353
|
+
readonly jobs: BoundJobsFacadeOf<TJobs, TTrellisApi, TKv, TDeps>;
|
|
1354
|
+
readonly handle: BoundTypedServiceHandleFacade<
|
|
1355
|
+
TOwnedApi,
|
|
1356
|
+
TTrellisApi,
|
|
1357
|
+
TKv,
|
|
1358
|
+
TJobs,
|
|
1359
|
+
TDeps
|
|
1360
|
+
>;
|
|
1361
|
+
/** Returns a new bound wrapper that injects the provided dependencies. */
|
|
1362
|
+
with<TNextDeps>(deps: TNextDeps): BoundTrellisService<
|
|
1363
|
+
TOwnedApi,
|
|
1364
|
+
TTrellisApi,
|
|
1365
|
+
TJobs,
|
|
1366
|
+
TKv,
|
|
1367
|
+
TNextDeps
|
|
1368
|
+
>;
|
|
1369
|
+
};
|
|
1370
|
+
|
|
1100
1371
|
const MANAGED_JOB_WORKERS = Symbol("trellis.managedJobWorkers");
|
|
1101
1372
|
|
|
1102
1373
|
type ManagedJobWorkers = {
|
|
@@ -1147,6 +1418,30 @@ type ServiceEventPublishLeaf = {
|
|
|
1147
1418
|
): ReturnType<HandlerTrellis<TrellisAPI>["publish"]>;
|
|
1148
1419
|
};
|
|
1149
1420
|
|
|
1421
|
+
type ServiceEventLeaf = ServiceEventPublishLeaf & {
|
|
1422
|
+
listen(
|
|
1423
|
+
handler: (
|
|
1424
|
+
event: unknown,
|
|
1425
|
+
context: EventListenerContext,
|
|
1426
|
+
) => MaybeAsync<void, BaseError>,
|
|
1427
|
+
subjectData?: Record<string, unknown>,
|
|
1428
|
+
opts?: EventOpts,
|
|
1429
|
+
): AsyncResult<void, ValidationError | UnexpectedError>;
|
|
1430
|
+
};
|
|
1431
|
+
|
|
1432
|
+
type BoundServiceEventLeaf<TDeps> = ServiceEventPublishLeaf & {
|
|
1433
|
+
listen(
|
|
1434
|
+
handler: (args: {
|
|
1435
|
+
event: unknown;
|
|
1436
|
+
context: EventListenerContext;
|
|
1437
|
+
client: unknown;
|
|
1438
|
+
deps: TDeps;
|
|
1439
|
+
}) => MaybeAsync<void, BaseError>,
|
|
1440
|
+
subjectData?: Record<string, unknown>,
|
|
1441
|
+
opts?: EventOpts,
|
|
1442
|
+
): AsyncResult<void, ValidationError | UnexpectedError>;
|
|
1443
|
+
};
|
|
1444
|
+
|
|
1150
1445
|
function createServiceEventPublishFacade<TA extends TrellisAPI>(outbound: {
|
|
1151
1446
|
readonly api: TA;
|
|
1152
1447
|
prepare(
|
|
@@ -2255,6 +2550,47 @@ function createJobsFacade<
|
|
|
2255
2550
|
return jobsFacade as ManagedJobsFacade<TJobs, TTrellisApi, TKv>;
|
|
2256
2551
|
}
|
|
2257
2552
|
|
|
2553
|
+
function createBoundJobsFacade<
|
|
2554
|
+
TJobs extends ContractJobsMetadata,
|
|
2555
|
+
TTrellisApi extends TrellisAPI,
|
|
2556
|
+
TKv extends ContractKvMetadata,
|
|
2557
|
+
TDeps,
|
|
2558
|
+
>(args: {
|
|
2559
|
+
jobs: JobsFacadeOf<TJobs, TTrellisApi, TKv>;
|
|
2560
|
+
deps: TDeps;
|
|
2561
|
+
}): BoundJobsFacadeOf<TJobs, TTrellisApi, TKv, TDeps> {
|
|
2562
|
+
const boundJobs: Record<string, unknown> = {};
|
|
2563
|
+
const jobs = args.jobs as Record<
|
|
2564
|
+
string,
|
|
2565
|
+
JobQueue<unknown, unknown, TTrellisApi, TKv, TJobs>
|
|
2566
|
+
>;
|
|
2567
|
+
|
|
2568
|
+
for (const queueType of Object.keys(jobs)) {
|
|
2569
|
+
const queue = jobs[queueType];
|
|
2570
|
+
if (!queue) continue;
|
|
2571
|
+
boundJobs[queueType] = {
|
|
2572
|
+
create: (payload) => queue.create(payload),
|
|
2573
|
+
handle: (handler) =>
|
|
2574
|
+
queue.handle(({ job, client }) =>
|
|
2575
|
+
handler({
|
|
2576
|
+
job,
|
|
2577
|
+
client,
|
|
2578
|
+
deps: args.deps,
|
|
2579
|
+
})
|
|
2580
|
+
),
|
|
2581
|
+
} satisfies BoundJobQueue<
|
|
2582
|
+
unknown,
|
|
2583
|
+
unknown,
|
|
2584
|
+
TTrellisApi,
|
|
2585
|
+
TKv,
|
|
2586
|
+
TJobs,
|
|
2587
|
+
TDeps
|
|
2588
|
+
>;
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
return boundJobs as BoundJobsFacadeOf<TJobs, TTrellisApi, TKv, TDeps>;
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2258
2594
|
export class TrellisService<
|
|
2259
2595
|
TOwnedApi extends TrellisAPI = TrellisAPI,
|
|
2260
2596
|
TTrellisApi extends TrellisAPI = TOwnedApi,
|
|
@@ -2340,6 +2676,77 @@ export class TrellisService<
|
|
|
2340
2676
|
this.#stopHealthPublishing = stopHealthPublishing;
|
|
2341
2677
|
}
|
|
2342
2678
|
|
|
2679
|
+
/**
|
|
2680
|
+
* Returns a service wrapper that injects application dependencies into
|
|
2681
|
+
* service-owned handler argument objects as `args.deps`.
|
|
2682
|
+
*/
|
|
2683
|
+
with<TDeps>(
|
|
2684
|
+
deps: TDeps,
|
|
2685
|
+
): BoundTrellisService<TOwnedApi, TTrellisApi, TJobs, TKv, TDeps> {
|
|
2686
|
+
return {
|
|
2687
|
+
name: this.name,
|
|
2688
|
+
auth: this.auth,
|
|
2689
|
+
nc: this.nc,
|
|
2690
|
+
event: this.#createBoundEventFacade(deps),
|
|
2691
|
+
kv: this.kv,
|
|
2692
|
+
store: this.store,
|
|
2693
|
+
jobs: createBoundJobsFacade({ jobs: this.jobs, deps }),
|
|
2694
|
+
health: this.health,
|
|
2695
|
+
handle: this.#createBoundHandleFacade(deps),
|
|
2696
|
+
connection: this.connection,
|
|
2697
|
+
createTransfer: (args) => this.createTransfer(args),
|
|
2698
|
+
completeOperation: (operationId, output) =>
|
|
2699
|
+
this.completeOperation(operationId, output),
|
|
2700
|
+
wait: () => this.wait(),
|
|
2701
|
+
stop: () => this.stop(),
|
|
2702
|
+
with: (nextDeps) => this.with(nextDeps),
|
|
2703
|
+
};
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
#createBoundEventFacade<TDeps>(
|
|
2707
|
+
deps: TDeps,
|
|
2708
|
+
): BoundActiveEventFacade<TTrellisApi, TTrellisApi, TKv, TJobs, TDeps> {
|
|
2709
|
+
const event = {} as BoundActiveEventFacade<
|
|
2710
|
+
TTrellisApi,
|
|
2711
|
+
TTrellisApi,
|
|
2712
|
+
TKv,
|
|
2713
|
+
TJobs,
|
|
2714
|
+
TDeps
|
|
2715
|
+
>;
|
|
2716
|
+
const source = this.event as Record<
|
|
2717
|
+
string,
|
|
2718
|
+
Record<string, ServiceEventLeaf>
|
|
2719
|
+
>;
|
|
2720
|
+
for (const [groupName, leaves] of Object.entries(source)) {
|
|
2721
|
+
const group: Record<string, BoundServiceEventLeaf<TDeps>> = {};
|
|
2722
|
+
for (const [leafName, leaf] of Object.entries(leaves)) {
|
|
2723
|
+
group[leafName] = {
|
|
2724
|
+
prepare: (payload) => leaf.prepare(payload),
|
|
2725
|
+
publish: (payload) => leaf.publish(payload),
|
|
2726
|
+
listen: (handler, subjectData, opts) =>
|
|
2727
|
+
leaf.listen(
|
|
2728
|
+
(payload, context) =>
|
|
2729
|
+
handler({
|
|
2730
|
+
event: payload,
|
|
2731
|
+
context,
|
|
2732
|
+
client: this.#handlerTrellis,
|
|
2733
|
+
deps,
|
|
2734
|
+
}),
|
|
2735
|
+
subjectData,
|
|
2736
|
+
opts,
|
|
2737
|
+
),
|
|
2738
|
+
};
|
|
2739
|
+
}
|
|
2740
|
+
Object.defineProperty(event, groupName, {
|
|
2741
|
+
value: group,
|
|
2742
|
+
enumerable: true,
|
|
2743
|
+
configurable: true,
|
|
2744
|
+
});
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
return event;
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2343
2750
|
#createHandleFacade(): ServiceHandleFacade {
|
|
2344
2751
|
const rpc: ServiceHandleFacade["rpc"] = {};
|
|
2345
2752
|
for (const method of Object.keys(this.#server.api.rpc ?? {})) {
|
|
@@ -2405,6 +2812,82 @@ export class TrellisService<
|
|
|
2405
2812
|
return { rpc, feed, operation };
|
|
2406
2813
|
}
|
|
2407
2814
|
|
|
2815
|
+
#createBoundHandleFacade<TDeps>(
|
|
2816
|
+
deps: TDeps,
|
|
2817
|
+
): BoundTypedServiceHandleFacade<TOwnedApi, TTrellisApi, TKv, TJobs, TDeps> {
|
|
2818
|
+
const rpc: ServiceHandleFacade["rpc"] = {};
|
|
2819
|
+
for (const method of Object.keys(this.#server.api.rpc ?? {})) {
|
|
2820
|
+
addSurfaceLeaf(rpc, method, (handler) =>
|
|
2821
|
+
this.#server.mountRuntime(
|
|
2822
|
+
method,
|
|
2823
|
+
async ({ input, context }) =>
|
|
2824
|
+
await Promise.resolve(
|
|
2825
|
+
(handler as (
|
|
2826
|
+
args: unknown,
|
|
2827
|
+
) =>
|
|
2828
|
+
| Promise<Result<unknown, BaseError>>
|
|
2829
|
+
| Result<unknown, BaseError>)({
|
|
2830
|
+
input,
|
|
2831
|
+
context,
|
|
2832
|
+
client: this.#handlerTrellis,
|
|
2833
|
+
deps,
|
|
2834
|
+
}),
|
|
2835
|
+
),
|
|
2836
|
+
));
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
const feed: ServiceHandleFacade["feed"] = {};
|
|
2840
|
+
for (const feedName of Object.keys(this.#server.api.feeds ?? {})) {
|
|
2841
|
+
addSurfaceLeaf(
|
|
2842
|
+
feed,
|
|
2843
|
+
feedName,
|
|
2844
|
+
(handler) =>
|
|
2845
|
+
this.#server.feedHandle(feedName).handle((context) =>
|
|
2846
|
+
(handler as (args: unknown) => unknown | Promise<unknown>)({
|
|
2847
|
+
...context,
|
|
2848
|
+
client: this.#handlerTrellis,
|
|
2849
|
+
deps,
|
|
2850
|
+
})
|
|
2851
|
+
),
|
|
2852
|
+
);
|
|
2853
|
+
}
|
|
2854
|
+
|
|
2855
|
+
const operation: Record<
|
|
2856
|
+
string,
|
|
2857
|
+
Record<string, ServiceHandleOperationLeaf>
|
|
2858
|
+
> = {};
|
|
2859
|
+
for (
|
|
2860
|
+
const operationName of Object.keys(this.#server.api.operations ?? {})
|
|
2861
|
+
) {
|
|
2862
|
+
const registration = this.#operation(
|
|
2863
|
+
operationName as keyof TOwnedApi["operations"] & string,
|
|
2864
|
+
);
|
|
2865
|
+
const leaf = Object.assign(
|
|
2866
|
+
(handler: (context: unknown) => unknown) =>
|
|
2867
|
+
registration.handle((context) =>
|
|
2868
|
+
handler({
|
|
2869
|
+
...context,
|
|
2870
|
+
client: this.#handlerTrellis,
|
|
2871
|
+
deps,
|
|
2872
|
+
})
|
|
2873
|
+
),
|
|
2874
|
+
{
|
|
2875
|
+
accept: (args: { sessionKey: string }) => registration.accept(args),
|
|
2876
|
+
control: (operationId: string) => registration.control(operationId),
|
|
2877
|
+
},
|
|
2878
|
+
) as ServiceHandleOperationLeaf;
|
|
2879
|
+
addSurfaceLeaf(operation, operationName, leaf);
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
return { rpc, feed, operation } as BoundTypedServiceHandleFacade<
|
|
2883
|
+
TOwnedApi,
|
|
2884
|
+
TTrellisApi,
|
|
2885
|
+
TKv,
|
|
2886
|
+
TJobs,
|
|
2887
|
+
TDeps
|
|
2888
|
+
>;
|
|
2889
|
+
}
|
|
2890
|
+
|
|
2408
2891
|
/**
|
|
2409
2892
|
* Creates a short-lived receive transfer grant for a caller session.
|
|
2410
2893
|
*/
|
package/src/service/deno.ts
CHANGED
package/src/service/mod.ts
CHANGED
package/src/service/node.ts
CHANGED
package/src/trellis.ts
CHANGED
|
@@ -1009,6 +1009,50 @@ export type EventOpts = {
|
|
|
1009
1009
|
signal?: AbortSignal;
|
|
1010
1010
|
};
|
|
1011
1011
|
|
|
1012
|
+
/** Context provided to event listener callbacks. */
|
|
1013
|
+
export type EventListenerContext = {
|
|
1014
|
+
/** Stable event id from the Trellis event header. */
|
|
1015
|
+
id: string;
|
|
1016
|
+
/** Event creation time from the Trellis event header. */
|
|
1017
|
+
time: Date;
|
|
1018
|
+
/** NATS subject that delivered the event. */
|
|
1019
|
+
subject: string;
|
|
1020
|
+
/** Runtime listener mode that delivered the event. */
|
|
1021
|
+
mode: "durable" | "ephemeral";
|
|
1022
|
+
/** Durable event consumer group, when delivered through a group. */
|
|
1023
|
+
group?: string;
|
|
1024
|
+
/** JetStream sequence number, when available. */
|
|
1025
|
+
sequence?: number;
|
|
1026
|
+
};
|
|
1027
|
+
|
|
1028
|
+
function createEventListenerContext(args: {
|
|
1029
|
+
payload: unknown;
|
|
1030
|
+
subject: string;
|
|
1031
|
+
mode: "durable" | "ephemeral";
|
|
1032
|
+
group?: string;
|
|
1033
|
+
message: object;
|
|
1034
|
+
}): EventListenerContext {
|
|
1035
|
+
const header = typeof args.payload === "object" && args.payload !== null
|
|
1036
|
+
? Reflect.get(args.payload, "header")
|
|
1037
|
+
: undefined;
|
|
1038
|
+
const id = typeof header === "object" && header !== null
|
|
1039
|
+
? Reflect.get(header, "id")
|
|
1040
|
+
: undefined;
|
|
1041
|
+
const time = typeof header === "object" && header !== null
|
|
1042
|
+
? Reflect.get(header, "time")
|
|
1043
|
+
: undefined;
|
|
1044
|
+
const sequence = Reflect.get(args.message, "seq");
|
|
1045
|
+
|
|
1046
|
+
return {
|
|
1047
|
+
id: typeof id === "string" ? id : "",
|
|
1048
|
+
time: new Date(typeof time === "string" ? time : 0),
|
|
1049
|
+
subject: args.subject,
|
|
1050
|
+
mode: args.mode,
|
|
1051
|
+
...(args.group ? { group: args.group } : {}),
|
|
1052
|
+
...(typeof sequence === "number" ? { sequence } : {}),
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1012
1056
|
type RuntimeEventConsumers = {
|
|
1013
1057
|
metadata?: ContractEventConsumers;
|
|
1014
1058
|
bindings?: Record<string, EventConsumerResourceBinding>;
|
|
@@ -1224,7 +1268,10 @@ export type FeedSurface<
|
|
|
1224
1268
|
type MaybePromise<T> = T | Promise<T>;
|
|
1225
1269
|
|
|
1226
1270
|
type EventCallback<TMessage> = {
|
|
1227
|
-
bivarianceHack(
|
|
1271
|
+
bivarianceHack(
|
|
1272
|
+
message: TMessage,
|
|
1273
|
+
context: EventListenerContext,
|
|
1274
|
+
): MaybeAsync<void, BaseError>;
|
|
1228
1275
|
}["bivarianceHack"];
|
|
1229
1276
|
|
|
1230
1277
|
export type RpcHandlerContext = {
|
|
@@ -1731,7 +1778,10 @@ export type EventPayload<
|
|
|
1731
1778
|
export type EventHandler<
|
|
1732
1779
|
TContract,
|
|
1733
1780
|
E extends EventName<TContract>,
|
|
1734
|
-
> = (
|
|
1781
|
+
> = (
|
|
1782
|
+
event: EventType<TContract, E>,
|
|
1783
|
+
context: EventListenerContext,
|
|
1784
|
+
) => MaybeAsync<void, BaseError>;
|
|
1735
1785
|
|
|
1736
1786
|
type DeepRecord<T> = {
|
|
1737
1787
|
[k: string]: T | DeepRecord<T>;
|
|
@@ -3664,7 +3714,15 @@ export class Trellis<
|
|
|
3664
3714
|
}
|
|
3665
3715
|
|
|
3666
3716
|
const handlerResult = await AsyncResult.lift(
|
|
3667
|
-
fn(
|
|
3717
|
+
fn(
|
|
3718
|
+
m as EventOf<TA, EventsOf<TA>>,
|
|
3719
|
+
createEventListenerContext({
|
|
3720
|
+
payload: m,
|
|
3721
|
+
subject: msg.subject,
|
|
3722
|
+
mode: "ephemeral",
|
|
3723
|
+
message: msg,
|
|
3724
|
+
}),
|
|
3725
|
+
),
|
|
3668
3726
|
);
|
|
3669
3727
|
if (handlerResult.isErr()) {
|
|
3670
3728
|
this.#log.error(
|
|
@@ -3887,7 +3945,15 @@ export class Trellis<
|
|
|
3887
3945
|
}
|
|
3888
3946
|
|
|
3889
3947
|
const handlerResult = await AsyncResult.lift(
|
|
3890
|
-
fn(
|
|
3948
|
+
fn(
|
|
3949
|
+
m as EventOf<TA, EventsOf<TA>>,
|
|
3950
|
+
createEventListenerContext({
|
|
3951
|
+
payload: m,
|
|
3952
|
+
subject: msg.subject,
|
|
3953
|
+
mode: "durable",
|
|
3954
|
+
message: msg,
|
|
3955
|
+
}),
|
|
3956
|
+
),
|
|
3891
3957
|
);
|
|
3892
3958
|
if (handlerResult.isErr()) {
|
|
3893
3959
|
this.#log.error(
|
|
@@ -3949,7 +4015,16 @@ export class Trellis<
|
|
|
3949
4015
|
}
|
|
3950
4016
|
|
|
3951
4017
|
const handlerResult = await AsyncResult.lift(
|
|
3952
|
-
registration.fn(
|
|
4018
|
+
registration.fn(
|
|
4019
|
+
eventPayload as EventOf<TA, EventsOf<TA>>,
|
|
4020
|
+
createEventListenerContext({
|
|
4021
|
+
payload: eventPayload,
|
|
4022
|
+
subject: msg.subject,
|
|
4023
|
+
mode: "durable",
|
|
4024
|
+
group,
|
|
4025
|
+
message: msg,
|
|
4026
|
+
}),
|
|
4027
|
+
),
|
|
3953
4028
|
);
|
|
3954
4029
|
if (handlerResult.isErr()) {
|
|
3955
4030
|
this.#log.error(
|