@electric-ax/agents-server 0.4.4 → 0.4.6
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/entrypoint.js +197 -33
- package/dist/index.cjs +193 -32
- package/dist/index.d.cts +46 -8
- package/dist/index.d.ts +46 -8
- package/dist/index.js +192 -34
- package/package.json +8 -8
- package/src/entity-registry.ts +17 -4
- package/src/entrypoint-lib.ts +5 -0
- package/src/index.ts +13 -0
- package/src/routing/context.ts +6 -0
- package/src/routing/durable-streams-router.ts +62 -13
- package/src/routing/internal-router.ts +142 -21
- package/src/server.ts +18 -0
- package/src/stream-client.ts +10 -4
- package/src/webhook-signing.ts +173 -0
package/dist/index.cjs
CHANGED
|
@@ -600,7 +600,7 @@ var PostgresRegistry = class {
|
|
|
600
600
|
const heartbeatAt = input.heartbeatAt ?? new Date();
|
|
601
601
|
await this.db.update(consumerClaims).set({
|
|
602
602
|
lastHeartbeatAt: heartbeatAt,
|
|
603
|
-
leaseExpiresAt: input.leaseExpiresAt
|
|
603
|
+
...input.leaseExpiresAt !== void 0 ? { leaseExpiresAt: input.leaseExpiresAt } : {},
|
|
604
604
|
updatedAt: heartbeatAt
|
|
605
605
|
}).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(consumerClaims.tenantId, this.tenantId), (0, drizzle_orm.eq)(consumerClaims.consumerId, input.consumerId), (0, drizzle_orm.eq)(consumerClaims.epoch, input.epoch)));
|
|
606
606
|
}
|
|
@@ -613,17 +613,24 @@ var PostgresRegistry = class {
|
|
|
613
613
|
updatedAt: releasedAt
|
|
614
614
|
}).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(consumerClaims.tenantId, this.tenantId), (0, drizzle_orm.eq)(consumerClaims.consumerId, input.consumerId), (0, drizzle_orm.eq)(consumerClaims.epoch, input.epoch))).returning();
|
|
615
615
|
const claim = rows[0] ? this.rowToConsumerClaim(rows[0]) : null;
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
616
|
+
let entityCleared = false;
|
|
617
|
+
if (claim) {
|
|
618
|
+
const cleared = await this.db.update(entityDispatchState).set({
|
|
619
|
+
activeConsumerId: null,
|
|
620
|
+
activeRunnerId: null,
|
|
621
|
+
activeEpoch: null,
|
|
622
|
+
activeClaimedAt: null,
|
|
623
|
+
activeLeaseExpiresAt: null,
|
|
624
|
+
lastReleasedAt: releasedAt,
|
|
625
|
+
lastCompletedAt: releasedAt,
|
|
626
|
+
updatedAt: releasedAt
|
|
627
|
+
}).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(entityDispatchState.tenantId, this.tenantId), (0, drizzle_orm.eq)(entityDispatchState.entityUrl, claim.entity_url), (0, drizzle_orm.eq)(entityDispatchState.activeConsumerId, input.consumerId), (0, drizzle_orm.eq)(entityDispatchState.activeEpoch, input.epoch))).returning({ entityUrl: entityDispatchState.entityUrl });
|
|
628
|
+
entityCleared = cleared.length > 0;
|
|
629
|
+
}
|
|
630
|
+
return {
|
|
631
|
+
claim,
|
|
632
|
+
entityCleared
|
|
633
|
+
};
|
|
627
634
|
}
|
|
628
635
|
async getActiveClaimsForRunner(runnerId) {
|
|
629
636
|
const rows = await this.db.select().from(consumerClaims).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(consumerClaims.tenantId, this.tenantId), (0, drizzle_orm.eq)(consumerClaims.runnerId, runnerId), (0, drizzle_orm.eq)(consumerClaims.status, `active`)));
|
|
@@ -6144,6 +6151,87 @@ function sqlStringLiteral(value) {
|
|
|
6144
6151
|
return `'${value.replace(/'/g, `''`)}'`;
|
|
6145
6152
|
}
|
|
6146
6153
|
|
|
6154
|
+
//#endregion
|
|
6155
|
+
//#region src/webhook-signing.ts
|
|
6156
|
+
const encoder = new TextEncoder();
|
|
6157
|
+
const defaultWebhookSigner = createEd25519WebhookSigner();
|
|
6158
|
+
function createEd25519WebhookSigner(options = {}) {
|
|
6159
|
+
const privateKey = options.privateKey ? importPrivateKey(options.privateKey) : (0, node_crypto.generateKeyPairSync)(`ed25519`).privateKey;
|
|
6160
|
+
if (privateKey.asymmetricKeyType !== `ed25519`) throw new Error(`Webhook signing key must be an Ed25519 private key`);
|
|
6161
|
+
const publicJwk = buildPublicJwk(privateKey, options.kid);
|
|
6162
|
+
return {
|
|
6163
|
+
sign: (body) => signWebhookBody(privateKey, publicJwk.kid, body),
|
|
6164
|
+
jwks: () => ({ keys: [{ ...publicJwk }] })
|
|
6165
|
+
};
|
|
6166
|
+
}
|
|
6167
|
+
function getDefaultWebhookSigner() {
|
|
6168
|
+
return defaultWebhookSigner;
|
|
6169
|
+
}
|
|
6170
|
+
async function webhookSigningMetadata(signer, streamRootUrl) {
|
|
6171
|
+
const jwks = await signer.jwks();
|
|
6172
|
+
const key = jwks.keys[0];
|
|
6173
|
+
if (!key) throw new Error(`Webhook signer did not provide any public keys`);
|
|
6174
|
+
return {
|
|
6175
|
+
alg: `ed25519`,
|
|
6176
|
+
kid: key.kid,
|
|
6177
|
+
jwks_url: (0, __electric_ax_agents_runtime.appendPathToUrl)(streamRootUrl, `/__ds/jwks.json`)
|
|
6178
|
+
};
|
|
6179
|
+
}
|
|
6180
|
+
function signWebhookBody(privateKey, kid, body) {
|
|
6181
|
+
const timestamp$1 = Math.floor(Date.now() / 1e3);
|
|
6182
|
+
const payload = bytesWithTimestamp(timestamp$1, body);
|
|
6183
|
+
const signature = (0, node_crypto.sign)(null, payload, privateKey).toString(`base64url`);
|
|
6184
|
+
return `t=${timestamp$1},kid=${kid},ed25519=${signature}`;
|
|
6185
|
+
}
|
|
6186
|
+
function bytesWithTimestamp(timestamp$1, body) {
|
|
6187
|
+
const prefix = encoder.encode(`${timestamp$1}.`);
|
|
6188
|
+
const bodyBytes = typeof body === `string` ? encoder.encode(body) : body;
|
|
6189
|
+
return Buffer.concat([Buffer.from(prefix), Buffer.from(bodyBytes)]);
|
|
6190
|
+
}
|
|
6191
|
+
function importPrivateKey(input) {
|
|
6192
|
+
if (isKeyObject(input)) return input;
|
|
6193
|
+
if (typeof input === `string`) {
|
|
6194
|
+
const trimmed = input.trim();
|
|
6195
|
+
if (trimmed.startsWith(`{`)) return (0, node_crypto.createPrivateKey)({
|
|
6196
|
+
key: JSON.parse(trimmed),
|
|
6197
|
+
format: `jwk`
|
|
6198
|
+
});
|
|
6199
|
+
return (0, node_crypto.createPrivateKey)(trimmed.replace(/\\n/g, `\n`));
|
|
6200
|
+
}
|
|
6201
|
+
if (Buffer.isBuffer(input)) return (0, node_crypto.createPrivateKey)(input);
|
|
6202
|
+
return (0, node_crypto.createPrivateKey)({
|
|
6203
|
+
key: input,
|
|
6204
|
+
format: `jwk`
|
|
6205
|
+
});
|
|
6206
|
+
}
|
|
6207
|
+
function isKeyObject(input) {
|
|
6208
|
+
return typeof input === `object` && `type` in input && input.type === `private`;
|
|
6209
|
+
}
|
|
6210
|
+
function buildPublicJwk(privateKey, kid) {
|
|
6211
|
+
const exported = (0, node_crypto.createPublicKey)(privateKey).export({ format: `jwk` });
|
|
6212
|
+
if (exported.kty !== `OKP` || exported.crv !== `Ed25519` || !exported.x) throw new Error(`Failed to export Ed25519 webhook signing key`);
|
|
6213
|
+
return {
|
|
6214
|
+
kty: `OKP`,
|
|
6215
|
+
crv: `Ed25519`,
|
|
6216
|
+
x: exported.x,
|
|
6217
|
+
kid: kid ?? deriveKeyId({
|
|
6218
|
+
kty: exported.kty,
|
|
6219
|
+
crv: exported.crv,
|
|
6220
|
+
x: exported.x
|
|
6221
|
+
}),
|
|
6222
|
+
use: `sig`,
|
|
6223
|
+
alg: `EdDSA`
|
|
6224
|
+
};
|
|
6225
|
+
}
|
|
6226
|
+
function deriveKeyId(jwk) {
|
|
6227
|
+
const thumbprintInput = JSON.stringify({
|
|
6228
|
+
crv: jwk.crv,
|
|
6229
|
+
kty: jwk.kty,
|
|
6230
|
+
x: jwk.x
|
|
6231
|
+
});
|
|
6232
|
+
return `ds_${(0, node_crypto.createHash)(`sha256`).update(thumbprintInput).digest(`base64url`)}`;
|
|
6233
|
+
}
|
|
6234
|
+
|
|
6147
6235
|
//#endregion
|
|
6148
6236
|
//#region src/routing/durable-streams-router.ts
|
|
6149
6237
|
const subscriptionProxyBodySchema = __sinclair_typebox.Type.Object({ webhook: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.Object({ url: __sinclair_typebox.Type.String() }, { additionalProperties: true })) }, { additionalProperties: true });
|
|
@@ -6160,6 +6248,7 @@ durableStreamsRouter.delete(`/__ds/subscriptions/:subscriptionId`, deleteSubscri
|
|
|
6160
6248
|
durableStreamsRouter.post(`/__ds/subscriptions/:subscriptionId/streams`, postSubscriptionStreams);
|
|
6161
6249
|
durableStreamsRouter.delete(`/__ds/subscriptions/:subscriptionId/streams/:streamPath+`, deleteSubscriptionStream);
|
|
6162
6250
|
for (const action of subscriptionControlActions) durableStreamsRouter.post(`/__ds/subscriptions/:subscriptionId/${action}`, subscriptionAction(action));
|
|
6251
|
+
durableStreamsRouter.get(`/__ds/jwks.json`, webhookJwks);
|
|
6163
6252
|
durableStreamsRouter.all(`/__ds`, controlPassThrough);
|
|
6164
6253
|
durableStreamsRouter.all(`/__ds/*`, controlPassThrough);
|
|
6165
6254
|
durableStreamsRouter.post(`*`, streamAppend);
|
|
@@ -6168,12 +6257,16 @@ function bodyFromBytes$1(body) {
|
|
|
6168
6257
|
return body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength);
|
|
6169
6258
|
}
|
|
6170
6259
|
function responseFromUpstream$1(response, body) {
|
|
6171
|
-
|
|
6260
|
+
const responseBody = forbidsResponseBody$1(response.status) ? null : body !== void 0 ? bodyFromBytes$1(body) : response.body;
|
|
6261
|
+
return new Response(responseBody, {
|
|
6172
6262
|
status: response.status,
|
|
6173
6263
|
statusText: response.statusText,
|
|
6174
6264
|
headers: responseHeaders(response)
|
|
6175
6265
|
});
|
|
6176
6266
|
}
|
|
6267
|
+
function forbidsResponseBody$1(status$4) {
|
|
6268
|
+
return status$4 === 204 || status$4 === 205 || status$4 === 304;
|
|
6269
|
+
}
|
|
6177
6270
|
async function forwardToDurableStreams(ctx, request, body, route = `stream`, urlOverride, durableStreamsBearerMode = `overwrite`) {
|
|
6178
6271
|
const headers = new Headers(request.headers);
|
|
6179
6272
|
headers.delete(`host`);
|
|
@@ -6207,28 +6300,32 @@ function rewriteSubscriptionBodyForBackend(payload, service, routingAdapter) {
|
|
|
6207
6300
|
return next;
|
|
6208
6301
|
});
|
|
6209
6302
|
}
|
|
6210
|
-
function rewriteSubscriptionResponseForClient(bytes, response,
|
|
6303
|
+
async function rewriteSubscriptionResponseForClient(bytes, response, ctx, routingAdapter) {
|
|
6211
6304
|
if (!response.headers.get(`content-type`)?.includes(`application/json`)) return bytes;
|
|
6212
6305
|
const payload = decodeJson(bytes);
|
|
6213
6306
|
if (!payload) return bytes;
|
|
6214
|
-
if (typeof payload.pattern === `string`) payload.pattern = routingAdapter.toRuntimeStreamPath(service, payload.pattern);
|
|
6307
|
+
if (typeof payload.pattern === `string`) payload.pattern = routingAdapter.toRuntimeStreamPath(ctx.service, payload.pattern);
|
|
6215
6308
|
if (Array.isArray(payload.streams)) payload.streams = payload.streams.map((stream) => {
|
|
6216
|
-
if (typeof stream === `string`) return routingAdapter.toRuntimeStreamPath(service, stream);
|
|
6309
|
+
if (typeof stream === `string`) return routingAdapter.toRuntimeStreamPath(ctx.service, stream);
|
|
6217
6310
|
if (stream && typeof stream === `object` && typeof stream.path === `string`) return {
|
|
6218
6311
|
...stream,
|
|
6219
|
-
path: routingAdapter.toRuntimeStreamPath(service, stream.path)
|
|
6312
|
+
path: routingAdapter.toRuntimeStreamPath(ctx.service, stream.path)
|
|
6220
6313
|
};
|
|
6221
6314
|
return stream;
|
|
6222
6315
|
});
|
|
6223
|
-
if (typeof payload.wake_stream === `string`) payload.wake_stream = routingAdapter.toRuntimeStreamPath(service, payload.wake_stream);
|
|
6224
|
-
if (typeof payload.stream === `string`) payload.stream = routingAdapter.toRuntimeStreamPath(service, payload.stream);
|
|
6316
|
+
if (typeof payload.wake_stream === `string`) payload.wake_stream = routingAdapter.toRuntimeStreamPath(ctx.service, payload.wake_stream);
|
|
6317
|
+
if (typeof payload.stream === `string`) payload.stream = routingAdapter.toRuntimeStreamPath(ctx.service, payload.stream);
|
|
6225
6318
|
if (Array.isArray(payload.acks)) payload.acks = payload.acks.map((ack) => {
|
|
6226
6319
|
if (!ack || typeof ack !== `object`) return ack;
|
|
6227
6320
|
const next = { ...ack };
|
|
6228
|
-
if (typeof next.stream === `string`) next.stream = routingAdapter.toRuntimeStreamPath(service, next.stream);
|
|
6229
|
-
if (typeof next.path === `string`) next.path = routingAdapter.toRuntimeStreamPath(service, next.path);
|
|
6321
|
+
if (typeof next.stream === `string`) next.stream = routingAdapter.toRuntimeStreamPath(ctx.service, next.stream);
|
|
6322
|
+
if (typeof next.path === `string`) next.path = routingAdapter.toRuntimeStreamPath(ctx.service, next.path);
|
|
6230
6323
|
return next;
|
|
6231
6324
|
});
|
|
6325
|
+
if (payload.webhook && typeof payload.webhook === `object` && !Array.isArray(payload.webhook)) {
|
|
6326
|
+
const webhook = payload.webhook;
|
|
6327
|
+
webhook.signing = await webhookSigningMetadata(resolveWebhookSigner$1(ctx), ctx.publicUrl);
|
|
6328
|
+
}
|
|
6232
6329
|
return new TextEncoder().encode(JSON.stringify(payload));
|
|
6233
6330
|
}
|
|
6234
6331
|
function decodeJson(bytes) {
|
|
@@ -6247,6 +6344,9 @@ function routeParam$2(request, name) {
|
|
|
6247
6344
|
function subscriptionRoutingAdapter(ctx) {
|
|
6248
6345
|
return resolveDurableStreamsRoutingAdapter(ctx.durableStreamsRouting, ctx.durableStreamsUrl);
|
|
6249
6346
|
}
|
|
6347
|
+
function resolveWebhookSigner$1(ctx) {
|
|
6348
|
+
return ctx.webhookSigner ?? getDefaultWebhookSigner();
|
|
6349
|
+
}
|
|
6250
6350
|
async function rewriteSubscriptionRequestBody(request, ctx, subscriptionId, routingAdapter) {
|
|
6251
6351
|
const body = await readRequestBody(request);
|
|
6252
6352
|
if (body.length === 0) return {
|
|
@@ -6275,7 +6375,7 @@ async function rewriteSubscriptionRequestBody(request, ctx, subscriptionId, rout
|
|
|
6275
6375
|
async function forwardSubscriptionRequest(request, ctx, routingAdapter, opts = {}) {
|
|
6276
6376
|
const upstream = await forwardToDurableStreams(ctx, request, opts.body, `control`, opts.requestUrl, opts.bearerMode ?? `overwrite`);
|
|
6277
6377
|
let responseBytes = upstream.body ? new Uint8Array(await upstream.arrayBuffer()) : new Uint8Array();
|
|
6278
|
-
responseBytes = rewriteSubscriptionResponseForClient(responseBytes, upstream, ctx
|
|
6378
|
+
responseBytes = await rewriteSubscriptionResponseForClient(responseBytes, upstream, ctx, routingAdapter);
|
|
6279
6379
|
return {
|
|
6280
6380
|
upstream,
|
|
6281
6381
|
response: responseFromUpstream$1(upstream, responseBytes)
|
|
@@ -6348,6 +6448,15 @@ async function controlPassThrough(request, ctx) {
|
|
|
6348
6448
|
const upstream = await forwardToDurableStreams(ctx, request, void 0, `control`);
|
|
6349
6449
|
return responseFromUpstream$1(upstream);
|
|
6350
6450
|
}
|
|
6451
|
+
async function webhookJwks(_request, ctx) {
|
|
6452
|
+
return new Response(JSON.stringify(await resolveWebhookSigner$1(ctx).jwks()), {
|
|
6453
|
+
status: 200,
|
|
6454
|
+
headers: {
|
|
6455
|
+
"content-type": `application/jwk-set+json`,
|
|
6456
|
+
"cache-control": `public, max-age=300`
|
|
6457
|
+
}
|
|
6458
|
+
});
|
|
6459
|
+
}
|
|
6351
6460
|
async function streamAppend(request, ctx) {
|
|
6352
6461
|
return await electricAgentsStreamAppendRouter.fetch(createStreamAppendRouteRequest(request), ctx.runtime, (req, body) => forwardFetchRequest({
|
|
6353
6462
|
request: {
|
|
@@ -7338,12 +7447,16 @@ function bodyFromBytes(body) {
|
|
|
7338
7447
|
return body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength);
|
|
7339
7448
|
}
|
|
7340
7449
|
function responseFromUpstream(response, body) {
|
|
7341
|
-
|
|
7450
|
+
const responseBody = forbidsResponseBody(response.status) ? null : body !== void 0 ? bodyFromBytes(body) : response.body;
|
|
7451
|
+
return new Response(responseBody, {
|
|
7342
7452
|
status: response.status,
|
|
7343
7453
|
statusText: response.statusText,
|
|
7344
7454
|
headers: responseHeaders(response)
|
|
7345
7455
|
});
|
|
7346
7456
|
}
|
|
7457
|
+
function forbidsResponseBody(status$4) {
|
|
7458
|
+
return status$4 === 204 || status$4 === 205 || status$4 === 304;
|
|
7459
|
+
}
|
|
7347
7460
|
function forwardHeadersFromRequest(request) {
|
|
7348
7461
|
const headers = new Headers(request.headers);
|
|
7349
7462
|
headers.delete(`host`);
|
|
@@ -7352,6 +7465,45 @@ function forwardHeadersFromRequest(request) {
|
|
|
7352
7465
|
function durableStreamsSubscriptionCallback(value) {
|
|
7353
7466
|
return value.startsWith(DS_SUBSCRIPTION_CALLBACK_PREFIX) ? value.slice(DS_SUBSCRIPTION_CALLBACK_PREFIX.length) : null;
|
|
7354
7467
|
}
|
|
7468
|
+
function resolveWebhookSigner(ctx) {
|
|
7469
|
+
return ctx.webhookSigner ?? getDefaultWebhookSigner();
|
|
7470
|
+
}
|
|
7471
|
+
function durableStreamsWebhookJwksUrl(ctx) {
|
|
7472
|
+
if (!ctx.durableStreamsRouting) return (0, __electric_ax_agents_runtime.appendPathToUrl)(ctx.durableStreamsUrl, `/__ds/jwks.json`);
|
|
7473
|
+
return resolveDurableStreamsRoutingAdapter(ctx.durableStreamsRouting, ctx.durableStreamsUrl).controlUrl({
|
|
7474
|
+
durableStreamsUrl: ctx.durableStreamsUrl,
|
|
7475
|
+
serviceId: ctx.service,
|
|
7476
|
+
requestUrl: (0, __electric_ax_agents_runtime.appendPathToUrl)(ctx.publicUrl, `/__ds/jwks.json`)
|
|
7477
|
+
}).toString();
|
|
7478
|
+
}
|
|
7479
|
+
function durableStreamsJwksFetchClient(ctx) {
|
|
7480
|
+
return async (input, init) => {
|
|
7481
|
+
const headers = new Headers(init?.headers);
|
|
7482
|
+
await applyDurableStreamsBearer(headers, ctx.durableStreamsBearer, { overwrite: false });
|
|
7483
|
+
const nextInit = {
|
|
7484
|
+
...init ?? {},
|
|
7485
|
+
headers
|
|
7486
|
+
};
|
|
7487
|
+
if (ctx.durableStreamsDispatcher) nextInit.dispatcher = ctx.durableStreamsDispatcher;
|
|
7488
|
+
return await fetch(input, nextInit);
|
|
7489
|
+
};
|
|
7490
|
+
}
|
|
7491
|
+
function resolveDurableStreamsWebhookSignature(ctx) {
|
|
7492
|
+
if (ctx.durableStreamsWebhookSignature === false) return false;
|
|
7493
|
+
return {
|
|
7494
|
+
jwksUrl: ctx.durableStreamsWebhookSignature?.jwksUrl ?? durableStreamsWebhookJwksUrl(ctx),
|
|
7495
|
+
toleranceSeconds: ctx.durableStreamsWebhookSignature?.toleranceSeconds,
|
|
7496
|
+
cacheTtlMs: ctx.durableStreamsWebhookSignature?.cacheTtlMs,
|
|
7497
|
+
fetchClient: ctx.durableStreamsWebhookSignature?.fetchClient ?? durableStreamsJwksFetchClient(ctx)
|
|
7498
|
+
};
|
|
7499
|
+
}
|
|
7500
|
+
async function verifyDurableStreamsWebhook(request, ctx, body) {
|
|
7501
|
+
const config = resolveDurableStreamsWebhookSignature(ctx);
|
|
7502
|
+
if (config === false) return null;
|
|
7503
|
+
const verification = await (0, __electric_ax_agents_runtime.verifyWebhookSignature)(body, request.headers.get(`webhook-signature`), config);
|
|
7504
|
+
if (verification.ok) return null;
|
|
7505
|
+
return apiError(verification.status, verification.status === 401 ? ErrCodeUnauthorized : `WEBHOOK_SIGNATURE_UNAVAILABLE`, verification.error);
|
|
7506
|
+
}
|
|
7355
7507
|
function claimTokenFromRequest(request) {
|
|
7356
7508
|
const electricClaimToken = request.headers.get(`electric-claim-token`)?.trim();
|
|
7357
7509
|
if (electricClaimToken) return electricClaimToken;
|
|
@@ -7385,7 +7537,10 @@ async function webhookForward(request, ctx) {
|
|
|
7385
7537
|
const rootSpan = getRequestSpan(request);
|
|
7386
7538
|
rootSpan?.updateName(`webhook-forward`);
|
|
7387
7539
|
rootSpan?.setAttribute(`electric_agents.webhook.subscription_id`, subscriptionId);
|
|
7388
|
-
const
|
|
7540
|
+
const body = await readRequestBody(request);
|
|
7541
|
+
const signatureError = await verifyDurableStreamsWebhook(request, ctx, body);
|
|
7542
|
+
if (signatureError) return signatureError;
|
|
7543
|
+
const targetWebhookUrl = await tracer.startActiveSpan(`db.lookupSubscription`, async (span) => {
|
|
7389
7544
|
try {
|
|
7390
7545
|
const rows = await ctx.pgDb.select().from(subscriptionWebhooks).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(subscriptionWebhooks.tenantId, ctx.service), (0, drizzle_orm.eq)(subscriptionWebhooks.subscriptionId, subscriptionId))).limit(1);
|
|
7391
7546
|
return rows[0]?.webhookUrl ?? null;
|
|
@@ -7393,7 +7548,6 @@ async function webhookForward(request, ctx) {
|
|
|
7393
7548
|
span.end();
|
|
7394
7549
|
}
|
|
7395
7550
|
});
|
|
7396
|
-
const [targetWebhookUrl, body] = await Promise.all([lookupPromise, readRequestBody(request)]);
|
|
7397
7551
|
if (!targetWebhookUrl) return apiError(404, ErrCodeSubscriptionNotFound, `Unknown webhook subscription`);
|
|
7398
7552
|
const parsedBodyResult = validateOptionalJsonBody(webhookForwardBodySchema, body, request.headers.get(`content-type`));
|
|
7399
7553
|
if (!parsedBodyResult.ok) return parsedBodyResult.response;
|
|
@@ -7482,6 +7636,7 @@ async function webhookForward(request, ctx) {
|
|
|
7482
7636
|
const headers = forwardHeadersFromRequest(request);
|
|
7483
7637
|
headers.set(`content-type`, `application/json`);
|
|
7484
7638
|
headers.delete(`content-length`);
|
|
7639
|
+
headers.set(`webhook-signature`, await resolveWebhookSigner(ctx).sign(forwardBody));
|
|
7485
7640
|
let upstream;
|
|
7486
7641
|
try {
|
|
7487
7642
|
upstream = await tracer.startActiveSpan(`fetch.agent-handler`, async (span) => {
|
|
@@ -7569,8 +7724,9 @@ async function callbackForward(request, ctx) {
|
|
|
7569
7724
|
serverLog.info(`[callback-forward] done received for stream=${target.primaryStream} consumer=${consumerId}`);
|
|
7570
7725
|
const stillOwnsClaim = ctx.runtime.claimWriteTokens.owns(ctx.service, target.primaryStream, consumerId);
|
|
7571
7726
|
const entity = await ctx.entityManager.registry.getEntityByStream(target.primaryStream);
|
|
7572
|
-
|
|
7573
|
-
|
|
7727
|
+
let entityCleared = false;
|
|
7728
|
+
if (epoch !== void 0) {
|
|
7729
|
+
const result = await ctx.entityManager.registry.materializeReleasedClaim?.({
|
|
7574
7730
|
consumerId,
|
|
7575
7731
|
epoch,
|
|
7576
7732
|
ackedStreams: Array.isArray(requestBody?.acks) ? requestBody.acks.flatMap((ack) => {
|
|
@@ -7582,13 +7738,15 @@ async function callbackForward(request, ctx) {
|
|
|
7582
7738
|
}] : [];
|
|
7583
7739
|
}) : void 0
|
|
7584
7740
|
});
|
|
7741
|
+
entityCleared = result?.entityCleared ?? false;
|
|
7742
|
+
}
|
|
7743
|
+
if (entity && (entityCleared || stillOwnsClaim)) {
|
|
7585
7744
|
await ctx.entityManager.registry.updateStatus(entity.url, `idle`);
|
|
7586
|
-
ctx.runtime.claimWriteTokens.clearStream(ctx.service, target.primaryStream);
|
|
7587
7745
|
await ctx.entityBridgeManager.onEntityChanged(entity.url);
|
|
7588
7746
|
serverLog.info(`[callback-forward] status updated to idle for ${entity.url}`);
|
|
7589
|
-
} else if (
|
|
7590
|
-
|
|
7591
|
-
else serverLog.
|
|
7747
|
+
} else if (!entity) serverLog.warn(`[callback-forward] done received but no entity found for stream=${target.primaryStream}`);
|
|
7748
|
+
if (stillOwnsClaim) ctx.runtime.claimWriteTokens.clearStream(ctx.service, target.primaryStream);
|
|
7749
|
+
else if (entity) serverLog.info(`[callback-forward] done arrived after in-memory token evicted (stream=${target.primaryStream} consumer=${consumerId})`);
|
|
7592
7750
|
} else if (requestBody?.done === true) serverLog.warn(`[callback-forward] done received but skipped: upstream.ok=${upstream.ok} primaryStream=${target.primaryStream ?? `null`} consumer=${consumerId}`);
|
|
7593
7751
|
} catch (err) {
|
|
7594
7752
|
serverLog.error(`[callback-forward] error processing done for consumer=${consumerId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -7646,9 +7804,12 @@ exports.DEFAULT_TENANT_ID = DEFAULT_TENANT_ID
|
|
|
7646
7804
|
exports.StreamClient = StreamClient
|
|
7647
7805
|
exports.UnregisteredTenantError = UnregisteredTenantError
|
|
7648
7806
|
exports.createDb = createDb
|
|
7807
|
+
exports.createEd25519WebhookSigner = createEd25519WebhookSigner
|
|
7808
|
+
exports.getDefaultWebhookSigner = getDefaultWebhookSigner
|
|
7649
7809
|
exports.globalRouter = globalRouter
|
|
7650
7810
|
exports.isUnregisteredTenantError = isUnregisteredTenantError
|
|
7651
7811
|
exports.pathPrefixedSingleTenantDurableStreamsRoutingAdapter = pathPrefixedSingleTenantDurableStreamsRoutingAdapter
|
|
7652
7812
|
exports.runMigrations = runMigrations
|
|
7653
7813
|
exports.streamRootDurableStreamsRoutingAdapter = streamRootDurableStreamsRoutingAdapter
|
|
7654
|
-
exports.tenantRootDurableStreamsRoutingAdapter = tenantRootDurableStreamsRoutingAdapter
|
|
7814
|
+
exports.tenantRootDurableStreamsRoutingAdapter = tenantRootDurableStreamsRoutingAdapter
|
|
7815
|
+
exports.webhookSigningMetadata = webhookSigningMetadata
|
package/dist/index.d.cts
CHANGED
|
@@ -187,11 +187,12 @@ import * as drizzle_orm_pg_core238 from "drizzle-orm/pg-core";
|
|
|
187
187
|
import * as drizzle_orm_pg_core239 from "drizzle-orm/pg-core";
|
|
188
188
|
import * as drizzle_orm73 from "drizzle-orm";
|
|
189
189
|
import * as drizzle_orm74 from "drizzle-orm";
|
|
190
|
-
import { EntityTags, WebhookNotification } from "@electric-ax/agents-runtime";
|
|
190
|
+
import { EntityTags, WebhookNotification, WebhookSignatureVerifierConfig } from "@electric-ax/agents-runtime";
|
|
191
191
|
import "@sinclair/typebox";
|
|
192
192
|
import { MaybePromise } from "@durable-streams/client";
|
|
193
193
|
import { AutoRouterType, IRequest } from "itty-router";
|
|
194
194
|
import { Agent } from "undici";
|
|
195
|
+
import { JsonWebKey, KeyObject } from "node:crypto";
|
|
195
196
|
|
|
196
197
|
//#region rolldown:runtime
|
|
197
198
|
declare namespace schema_d_exports {
|
|
@@ -3523,7 +3524,10 @@ declare class PostgresRegistry {
|
|
|
3523
3524
|
setRunnerAdminStatus(runnerId: string, adminStatus: RunnerAdminStatus): Promise<ElectricAgentsRunner | null>;
|
|
3524
3525
|
materializeActiveClaim(input: MaterializeActiveClaimInput): Promise<void>;
|
|
3525
3526
|
materializeHeartbeatClaim(input: MaterializeHeartbeatClaimInput): Promise<void>;
|
|
3526
|
-
materializeReleasedClaim(input: MaterializeReleasedClaimInput): Promise<
|
|
3527
|
+
materializeReleasedClaim(input: MaterializeReleasedClaimInput): Promise<{
|
|
3528
|
+
claim: ConsumerClaim | null;
|
|
3529
|
+
entityCleared: boolean;
|
|
3530
|
+
}>;
|
|
3527
3531
|
getActiveClaimsForRunner(runnerId: string): Promise<Array<ConsumerClaim>>;
|
|
3528
3532
|
getDispatchStatsForRunner(runnerId: string): Promise<{
|
|
3529
3533
|
entities_with_active_claim: number;
|
|
@@ -3631,11 +3635,15 @@ interface SubscriptionResponse {
|
|
|
3631
3635
|
streams?: Array<string | SubscriptionStreamInfo>;
|
|
3632
3636
|
webhook?: {
|
|
3633
3637
|
url?: string;
|
|
3638
|
+
signing?: {
|
|
3639
|
+
alg?: string;
|
|
3640
|
+
kid?: string;
|
|
3641
|
+
jwks_url?: string;
|
|
3642
|
+
};
|
|
3634
3643
|
};
|
|
3635
3644
|
wake_stream?: string;
|
|
3636
3645
|
callback_url?: string;
|
|
3637
3646
|
callback_token?: string;
|
|
3638
|
-
webhook_secret?: string;
|
|
3639
3647
|
}
|
|
3640
3648
|
interface SubscriptionCreateInput {
|
|
3641
3649
|
type: `webhook` | `pull-wake`;
|
|
@@ -3691,10 +3699,7 @@ declare class StreamClient {
|
|
|
3691
3699
|
contentType: string;
|
|
3692
3700
|
}): Promise<void>;
|
|
3693
3701
|
exists(path: string): Promise<boolean>;
|
|
3694
|
-
createSubscription(pattern: string, subscriptionId: string, webhookUrl: string, description?: string): Promise<
|
|
3695
|
-
subscription_id: string;
|
|
3696
|
-
webhook_secret?: string;
|
|
3697
|
-
}>;
|
|
3702
|
+
createSubscription(pattern: string, subscriptionId: string, webhookUrl: string, description?: string): Promise<SubscriptionResponse>;
|
|
3698
3703
|
putSubscription(subscriptionId: string, input: SubscriptionCreateInput): Promise<SubscriptionResponse>;
|
|
3699
3704
|
getSubscription(subscriptionId: string): Promise<SubscriptionResponse | null>;
|
|
3700
3705
|
deleteSubscription(subscriptionId: string): Promise<void>;
|
|
@@ -4368,6 +4373,37 @@ declare const streamRootDurableStreamsRoutingAdapter: DurableStreamsRoutingAdapt
|
|
|
4368
4373
|
declare const pathPrefixedSingleTenantDurableStreamsRoutingAdapter: DurableStreamsRoutingAdapter;
|
|
4369
4374
|
declare const tenantRootDurableStreamsRoutingAdapter: DurableStreamsRoutingAdapter;
|
|
4370
4375
|
|
|
4376
|
+
//#endregion
|
|
4377
|
+
//#region src/webhook-signing.d.ts
|
|
4378
|
+
interface WebhookPublicJwk {
|
|
4379
|
+
kty: `OKP`;
|
|
4380
|
+
crv: `Ed25519`;
|
|
4381
|
+
x: string;
|
|
4382
|
+
kid: string;
|
|
4383
|
+
use: `sig`;
|
|
4384
|
+
alg: `EdDSA`;
|
|
4385
|
+
}
|
|
4386
|
+
interface WebhookJwks {
|
|
4387
|
+
keys: Array<WebhookPublicJwk>;
|
|
4388
|
+
}
|
|
4389
|
+
interface WebhookSigningMetadata {
|
|
4390
|
+
alg: `ed25519`;
|
|
4391
|
+
kid: string;
|
|
4392
|
+
jwks_url: string;
|
|
4393
|
+
}
|
|
4394
|
+
interface WebhookSigner {
|
|
4395
|
+
sign: (body: Uint8Array | string) => string | Promise<string>;
|
|
4396
|
+
jwks: () => WebhookJwks | Promise<WebhookJwks>;
|
|
4397
|
+
}
|
|
4398
|
+
type WebhookSigningKeyInput = string | Buffer | JsonWebKey | KeyObject;
|
|
4399
|
+
interface Ed25519WebhookSignerOptions {
|
|
4400
|
+
privateKey?: WebhookSigningKeyInput;
|
|
4401
|
+
kid?: string;
|
|
4402
|
+
}
|
|
4403
|
+
declare function createEd25519WebhookSigner(options?: Ed25519WebhookSignerOptions): WebhookSigner;
|
|
4404
|
+
declare function getDefaultWebhookSigner(): WebhookSigner;
|
|
4405
|
+
declare function webhookSigningMetadata(signer: WebhookSigner, streamRootUrl: string): Promise<WebhookSigningMetadata>;
|
|
4406
|
+
|
|
4371
4407
|
//#endregion
|
|
4372
4408
|
//#region src/routing/context.d.ts
|
|
4373
4409
|
/**
|
|
@@ -4386,6 +4422,8 @@ interface TenantContext {
|
|
|
4386
4422
|
durableStreamsBearer?: DurableStreamsBearerProvider;
|
|
4387
4423
|
durableStreamsRouting?: DurableStreamsRoutingAdapter;
|
|
4388
4424
|
durableStreamsDispatcher: Agent;
|
|
4425
|
+
durableStreamsWebhookSignature?: false | Partial<WebhookSignatureVerifierConfig>;
|
|
4426
|
+
webhookSigner?: WebhookSigner;
|
|
4389
4427
|
electricUrl?: string;
|
|
4390
4428
|
electricSecret?: string;
|
|
4391
4429
|
ownAgentHandlerPaths?: ReadonlyArray<string>;
|
|
@@ -4413,4 +4451,4 @@ declare class UnregisteredTenantError extends Error {
|
|
|
4413
4451
|
declare function isUnregisteredTenantError(error: unknown): error is UnregisteredTenantError;
|
|
4414
4452
|
|
|
4415
4453
|
//#endregion
|
|
4416
|
-
export { AgentsHost, AgentsHostOptions, AgentsHostTenantConfig, AgentsHostTenantRuntime, AuthenticateRequest, ConsumerClaim, DEFAULT_TENANT_ID, DispatchPolicy, DispatchTarget, DrizzleDB, DurableStreamsBearerProvider, DurableStreamsRoutingAdapter, DurableStreamsRoutingInput, ElectricAgentsRunner, ElectricAgentsUser, EntityBridgeCoordinator, EntityDispatchState, GlobalRoutes, PgClient, Principal, PrincipalKind, PublicWakeNotification, RegisterRunnerRequest, RequestPrincipal, RunnerAdminStatus, RunnerHeartbeatRequest, RunnerKind, RunnerLiveness, SourceStreamOffset, StreamClient, StreamClientOptions, SubscriptionClaimResponse, SubscriptionCreateInput, SubscriptionResponse, SubscriptionStreamInfo, TenantContext, UnregisteredTenantError, WakeNotificationRow, createDb, globalRouter, isUnregisteredTenantError, pathPrefixedSingleTenantDurableStreamsRoutingAdapter, runMigrations, streamRootDurableStreamsRoutingAdapter, tenantRootDurableStreamsRoutingAdapter };
|
|
4454
|
+
export { AgentsHost, AgentsHostOptions, AgentsHostTenantConfig, AgentsHostTenantRuntime, AuthenticateRequest, ConsumerClaim, DEFAULT_TENANT_ID, DispatchPolicy, DispatchTarget, DrizzleDB, DurableStreamsBearerProvider, DurableStreamsRoutingAdapter, DurableStreamsRoutingInput, Ed25519WebhookSignerOptions, ElectricAgentsRunner, ElectricAgentsUser, EntityBridgeCoordinator, EntityDispatchState, GlobalRoutes, PgClient, Principal, PrincipalKind, PublicWakeNotification, RegisterRunnerRequest, RequestPrincipal, RunnerAdminStatus, RunnerHeartbeatRequest, RunnerKind, RunnerLiveness, SourceStreamOffset, StreamClient, StreamClientOptions, SubscriptionClaimResponse, SubscriptionCreateInput, SubscriptionResponse, SubscriptionStreamInfo, TenantContext, UnregisteredTenantError, WakeNotificationRow, WebhookJwks, WebhookPublicJwk, WebhookSigner, WebhookSigningKeyInput, WebhookSigningMetadata, createDb, createEd25519WebhookSigner, getDefaultWebhookSigner, globalRouter, isUnregisteredTenantError, pathPrefixedSingleTenantDurableStreamsRoutingAdapter, runMigrations, streamRootDurableStreamsRoutingAdapter, tenantRootDurableStreamsRoutingAdapter, webhookSigningMetadata };
|
package/dist/index.d.ts
CHANGED
|
@@ -188,7 +188,8 @@ import * as drizzle_orm_pg_core236 from "drizzle-orm/pg-core";
|
|
|
188
188
|
import * as drizzle_orm_pg_core237 from "drizzle-orm/pg-core";
|
|
189
189
|
import * as drizzle_orm_pg_core238 from "drizzle-orm/pg-core";
|
|
190
190
|
import * as drizzle_orm_pg_core239 from "drizzle-orm/pg-core";
|
|
191
|
-
import {
|
|
191
|
+
import { JsonWebKey, KeyObject } from "node:crypto";
|
|
192
|
+
import { EntityTags, WebhookNotification, WebhookSignatureVerifierConfig } from "@electric-ax/agents-runtime";
|
|
192
193
|
import { MaybePromise } from "@durable-streams/client";
|
|
193
194
|
import "@sinclair/typebox";
|
|
194
195
|
import { AutoRouterType, IRequest } from "itty-router";
|
|
@@ -3524,7 +3525,10 @@ declare class PostgresRegistry {
|
|
|
3524
3525
|
setRunnerAdminStatus(runnerId: string, adminStatus: RunnerAdminStatus): Promise<ElectricAgentsRunner | null>;
|
|
3525
3526
|
materializeActiveClaim(input: MaterializeActiveClaimInput): Promise<void>;
|
|
3526
3527
|
materializeHeartbeatClaim(input: MaterializeHeartbeatClaimInput): Promise<void>;
|
|
3527
|
-
materializeReleasedClaim(input: MaterializeReleasedClaimInput): Promise<
|
|
3528
|
+
materializeReleasedClaim(input: MaterializeReleasedClaimInput): Promise<{
|
|
3529
|
+
claim: ConsumerClaim | null;
|
|
3530
|
+
entityCleared: boolean;
|
|
3531
|
+
}>;
|
|
3528
3532
|
getActiveClaimsForRunner(runnerId: string): Promise<Array<ConsumerClaim>>;
|
|
3529
3533
|
getDispatchStatsForRunner(runnerId: string): Promise<{
|
|
3530
3534
|
entities_with_active_claim: number;
|
|
@@ -3632,11 +3636,15 @@ interface SubscriptionResponse {
|
|
|
3632
3636
|
streams?: Array<string | SubscriptionStreamInfo>;
|
|
3633
3637
|
webhook?: {
|
|
3634
3638
|
url?: string;
|
|
3639
|
+
signing?: {
|
|
3640
|
+
alg?: string;
|
|
3641
|
+
kid?: string;
|
|
3642
|
+
jwks_url?: string;
|
|
3643
|
+
};
|
|
3635
3644
|
};
|
|
3636
3645
|
wake_stream?: string;
|
|
3637
3646
|
callback_url?: string;
|
|
3638
3647
|
callback_token?: string;
|
|
3639
|
-
webhook_secret?: string;
|
|
3640
3648
|
}
|
|
3641
3649
|
interface SubscriptionCreateInput {
|
|
3642
3650
|
type: `webhook` | `pull-wake`;
|
|
@@ -3692,10 +3700,7 @@ declare class StreamClient {
|
|
|
3692
3700
|
contentType: string;
|
|
3693
3701
|
}): Promise<void>;
|
|
3694
3702
|
exists(path: string): Promise<boolean>;
|
|
3695
|
-
createSubscription(pattern: string, subscriptionId: string, webhookUrl: string, description?: string): Promise<
|
|
3696
|
-
subscription_id: string;
|
|
3697
|
-
webhook_secret?: string;
|
|
3698
|
-
}>;
|
|
3703
|
+
createSubscription(pattern: string, subscriptionId: string, webhookUrl: string, description?: string): Promise<SubscriptionResponse>;
|
|
3699
3704
|
putSubscription(subscriptionId: string, input: SubscriptionCreateInput): Promise<SubscriptionResponse>;
|
|
3700
3705
|
getSubscription(subscriptionId: string): Promise<SubscriptionResponse | null>;
|
|
3701
3706
|
deleteSubscription(subscriptionId: string): Promise<void>;
|
|
@@ -4369,6 +4374,37 @@ declare const streamRootDurableStreamsRoutingAdapter: DurableStreamsRoutingAdapt
|
|
|
4369
4374
|
declare const pathPrefixedSingleTenantDurableStreamsRoutingAdapter: DurableStreamsRoutingAdapter;
|
|
4370
4375
|
declare const tenantRootDurableStreamsRoutingAdapter: DurableStreamsRoutingAdapter;
|
|
4371
4376
|
|
|
4377
|
+
//#endregion
|
|
4378
|
+
//#region src/webhook-signing.d.ts
|
|
4379
|
+
interface WebhookPublicJwk {
|
|
4380
|
+
kty: `OKP`;
|
|
4381
|
+
crv: `Ed25519`;
|
|
4382
|
+
x: string;
|
|
4383
|
+
kid: string;
|
|
4384
|
+
use: `sig`;
|
|
4385
|
+
alg: `EdDSA`;
|
|
4386
|
+
}
|
|
4387
|
+
interface WebhookJwks {
|
|
4388
|
+
keys: Array<WebhookPublicJwk>;
|
|
4389
|
+
}
|
|
4390
|
+
interface WebhookSigningMetadata {
|
|
4391
|
+
alg: `ed25519`;
|
|
4392
|
+
kid: string;
|
|
4393
|
+
jwks_url: string;
|
|
4394
|
+
}
|
|
4395
|
+
interface WebhookSigner {
|
|
4396
|
+
sign: (body: Uint8Array | string) => string | Promise<string>;
|
|
4397
|
+
jwks: () => WebhookJwks | Promise<WebhookJwks>;
|
|
4398
|
+
}
|
|
4399
|
+
type WebhookSigningKeyInput = string | Buffer | JsonWebKey | KeyObject;
|
|
4400
|
+
interface Ed25519WebhookSignerOptions {
|
|
4401
|
+
privateKey?: WebhookSigningKeyInput;
|
|
4402
|
+
kid?: string;
|
|
4403
|
+
}
|
|
4404
|
+
declare function createEd25519WebhookSigner(options?: Ed25519WebhookSignerOptions): WebhookSigner;
|
|
4405
|
+
declare function getDefaultWebhookSigner(): WebhookSigner;
|
|
4406
|
+
declare function webhookSigningMetadata(signer: WebhookSigner, streamRootUrl: string): Promise<WebhookSigningMetadata>;
|
|
4407
|
+
|
|
4372
4408
|
//#endregion
|
|
4373
4409
|
//#region src/routing/context.d.ts
|
|
4374
4410
|
/**
|
|
@@ -4387,6 +4423,8 @@ interface TenantContext {
|
|
|
4387
4423
|
durableStreamsBearer?: DurableStreamsBearerProvider;
|
|
4388
4424
|
durableStreamsRouting?: DurableStreamsRoutingAdapter;
|
|
4389
4425
|
durableStreamsDispatcher: Agent;
|
|
4426
|
+
durableStreamsWebhookSignature?: false | Partial<WebhookSignatureVerifierConfig>;
|
|
4427
|
+
webhookSigner?: WebhookSigner;
|
|
4390
4428
|
electricUrl?: string;
|
|
4391
4429
|
electricSecret?: string;
|
|
4392
4430
|
ownAgentHandlerPaths?: ReadonlyArray<string>;
|
|
@@ -4414,4 +4452,4 @@ declare class UnregisteredTenantError extends Error {
|
|
|
4414
4452
|
declare function isUnregisteredTenantError(error: unknown): error is UnregisteredTenantError;
|
|
4415
4453
|
|
|
4416
4454
|
//#endregion
|
|
4417
|
-
export { AgentsHost, AgentsHostOptions, AgentsHostTenantConfig, AgentsHostTenantRuntime, AuthenticateRequest, ConsumerClaim, DEFAULT_TENANT_ID, DispatchPolicy, DispatchTarget, DrizzleDB, DurableStreamsBearerProvider, DurableStreamsRoutingAdapter, DurableStreamsRoutingInput, ElectricAgentsRunner, ElectricAgentsUser, EntityBridgeCoordinator, EntityDispatchState, GlobalRoutes, PgClient, Principal, PrincipalKind, PublicWakeNotification, RegisterRunnerRequest, RequestPrincipal, RunnerAdminStatus, RunnerHeartbeatRequest, RunnerKind, RunnerLiveness, SourceStreamOffset, StreamClient, StreamClientOptions, SubscriptionClaimResponse, SubscriptionCreateInput, SubscriptionResponse, SubscriptionStreamInfo, TenantContext, UnregisteredTenantError, WakeNotificationRow, createDb, globalRouter, isUnregisteredTenantError, pathPrefixedSingleTenantDurableStreamsRoutingAdapter, runMigrations, streamRootDurableStreamsRoutingAdapter, tenantRootDurableStreamsRoutingAdapter };
|
|
4455
|
+
export { AgentsHost, AgentsHostOptions, AgentsHostTenantConfig, AgentsHostTenantRuntime, AuthenticateRequest, ConsumerClaim, DEFAULT_TENANT_ID, DispatchPolicy, DispatchTarget, DrizzleDB, DurableStreamsBearerProvider, DurableStreamsRoutingAdapter, DurableStreamsRoutingInput, Ed25519WebhookSignerOptions, ElectricAgentsRunner, ElectricAgentsUser, EntityBridgeCoordinator, EntityDispatchState, GlobalRoutes, PgClient, Principal, PrincipalKind, PublicWakeNotification, RegisterRunnerRequest, RequestPrincipal, RunnerAdminStatus, RunnerHeartbeatRequest, RunnerKind, RunnerLiveness, SourceStreamOffset, StreamClient, StreamClientOptions, SubscriptionClaimResponse, SubscriptionCreateInput, SubscriptionResponse, SubscriptionStreamInfo, TenantContext, UnregisteredTenantError, WakeNotificationRow, WebhookJwks, WebhookPublicJwk, WebhookSigner, WebhookSigningKeyInput, WebhookSigningMetadata, createDb, createEd25519WebhookSigner, getDefaultWebhookSigner, globalRouter, isUnregisteredTenantError, pathPrefixedSingleTenantDurableStreamsRoutingAdapter, runMigrations, streamRootDurableStreamsRoutingAdapter, tenantRootDurableStreamsRoutingAdapter, webhookSigningMetadata };
|