@electric-ax/agents-server 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1373,7 +1373,6 @@ var PostgresRegistry = class {
1373
1373
  set: {
1374
1374
  options: row.options,
1375
1375
  streamUrl: row.streamUrl,
1376
- initialSnapshotComplete: false,
1377
1376
  lastTouchedAt: new Date(),
1378
1377
  updatedAt: new Date()
1379
1378
  }
@@ -1412,6 +1411,9 @@ var PostgresRegistry = class {
1412
1411
  updatedAt: new Date()
1413
1412
  }).where(this.pgSyncBridgeWhere(sourceRef));
1414
1413
  }
1414
+ async deletePgSyncBridge(sourceRef) {
1415
+ await this.db.delete(pgSyncBridges).where(this.pgSyncBridgeWhere(sourceRef));
1416
+ }
1415
1417
  async upsertEntityBridge(row) {
1416
1418
  await this.db.insert(entityBridges).values({
1417
1419
  tenantId: this.tenantId,
@@ -3293,9 +3295,6 @@ function assertSharedSandboxColocated(key, chosenIsRemote, dispatchPolicy) {
3293
3295
  function isRecord$1(value) {
3294
3296
  return typeof value === `object` && value !== null && !Array.isArray(value);
3295
3297
  }
3296
- function getPgSyncManifestStreamPath(sourceRef) {
3297
- return `/_electric/pg-sync/${sourceRef}`;
3298
- }
3299
3298
  function extractManifestSourceUrl(manifest) {
3300
3299
  if (!manifest) return void 0;
3301
3300
  if (manifest.kind === `child` || manifest.kind === `observe`) return typeof manifest.entity_url === `string` ? manifest.entity_url : void 0;
@@ -3308,7 +3307,7 @@ function extractManifestSourceUrl(manifest) {
3308
3307
  }
3309
3308
  if (manifest.sourceType === `entities`) return typeof manifest.sourceRef === `string` ? `/_entities/${manifest.sourceRef}` : void 0;
3310
3309
  if (manifest.sourceType === `db`) return typeof manifest.sourceRef === `string` ? (0, __electric_ax_agents_runtime.getSharedStateStreamPath)(manifest.sourceRef) : void 0;
3311
- if (manifest.sourceType === `pgSync`) return typeof manifest.sourceRef === `string` ? getPgSyncManifestStreamPath(manifest.sourceRef) : void 0;
3310
+ if (manifest.sourceType === `pgSync`) return typeof config?.streamUrl === `string` ? config.streamUrl : void 0;
3312
3311
  if (manifest.sourceType === `webhook`) {
3313
3312
  if (typeof config?.streamUrl === `string`) return config.streamUrl;
3314
3313
  if (typeof config?.endpointKey === `string`) return (0, __electric_ax_agents_runtime.getWebhookStreamPath)(config.endpointKey, typeof config.bucket === `string` ? config.bucket : void 0);
@@ -4900,7 +4899,7 @@ var EntityManager = class {
4900
4899
  await this.writeManifestEntry(entityUrl, manifestKey, `delete`, void 0, { txid });
4901
4900
  return { txid };
4902
4901
  }
4903
- async upsertEventSourceSubscription(entityUrl, req) {
4902
+ async upsertWebhookSourceSubscription(entityUrl, req) {
4904
4903
  const manifestKey = req.subscription.manifestKey;
4905
4904
  const txid = (0, node_crypto.randomUUID)();
4906
4905
  await this.writeManifestEntry(entityUrl, manifestKey, `upsert`, req.manifest, { txid });
@@ -4922,8 +4921,20 @@ var EntityManager = class {
4922
4921
  subscription: req.subscription
4923
4922
  };
4924
4923
  }
4925
- async deleteEventSourceSubscription(entityUrl, req) {
4926
- const manifestKey = (0, __electric_ax_agents_runtime.eventSourceSubscriptionManifestKey)(req.id);
4924
+ async deleteWebhookSourceSubscription(entityUrl, req) {
4925
+ const manifestKey = (0, __electric_ax_agents_runtime.webhookSourceSubscriptionManifestKey)(req.id);
4926
+ const txid = (0, node_crypto.randomUUID)();
4927
+ await this.writeManifestEntry(entityUrl, manifestKey, `delete`, void 0, { txid });
4928
+ await this.wakeRegistry.unregisterByManifestKey(entityUrl, manifestKey, this.tenantId);
4929
+ return { txid };
4930
+ }
4931
+ /**
4932
+ * Stop this entity observing a pg-sync source: drop its manifest entry and
4933
+ * the wake it anchors. The shared pg-sync bridge (keyed by sourceRef, not by
4934
+ * subscriber) is intentionally left running for any other observers.
4935
+ */
4936
+ async deletePgSyncObservation(entityUrl, req) {
4937
+ const manifestKey = `source:pgSync:${req.sourceRef}`;
4927
4938
  const txid = (0, node_crypto.randomUUID)();
4928
4939
  await this.writeManifestEntry(entityUrl, manifestKey, `delete`, void 0, { txid });
4929
4940
  await this.wakeRegistry.unregisterByManifestKey(entityUrl, manifestKey, this.tenantId);
@@ -6029,9 +6040,13 @@ var Scheduler = class {
6029
6040
 
6030
6041
  //#endregion
6031
6042
  //#region src/pg-sync-bridge-manager.ts
6032
- const PG_SYNC_ELECTRIC_SHAPE_URL = process.env.ELECTRIC_AGENTS_PG_SYNC_ELECTRIC_URL ?? `http://localhost:3000/v1/shape`;
6043
+ /** Registration was rejected because the source itself is invalid — map to a 4xx. */
6044
+ var PgSyncSourceValidationError = class extends Error {
6045
+ name = `PgSyncSourceValidationError`;
6046
+ };
6033
6047
  const DEFAULT_RETRY_INITIAL_DELAY_MS = 1e3;
6034
6048
  const DEFAULT_RETRY_MAX_DELAY_MS = 3e4;
6049
+ const DEFAULT_PROBE_TIMEOUT_MS = 1e4;
6035
6050
  function buildElectricShapeParams(options) {
6036
6051
  return {
6037
6052
  table: options.table,
@@ -6051,6 +6066,31 @@ function buildElectricShapeParams(options) {
6051
6066
  ...options.metadata?.wakeId ? { electric_agents_wake_id: options.metadata.wakeId } : {}
6052
6067
  };
6053
6068
  }
6069
+ /**
6070
+ * Build the one-shot URL used to validate a shape source at registration
6071
+ * time. Approximates the query-param encoding of the Electric TS client
6072
+ * (arrays comma-joined, where-clause params as `params[n]`) — unlike the
6073
+ * client it does not quote column identifiers, so probe and stream encoding
6074
+ * can diverge for exotic column names.
6075
+ */
6076
+ function buildShapeProbeUrl(sourceUrl, options) {
6077
+ let url;
6078
+ try {
6079
+ url = new URL(sourceUrl);
6080
+ } catch {
6081
+ throw new PgSyncSourceValidationError(`pgSync url "${sourceUrl}" is not a valid URL`);
6082
+ }
6083
+ if (url.protocol !== `http:` && url.protocol !== `https:`) throw new PgSyncSourceValidationError(`pgSync url "${sourceUrl}" must be an HTTP(S) Electric shape endpoint, not a database connection string`);
6084
+ for (const [key, value] of Object.entries(buildElectricShapeParams(options))) {
6085
+ if (value === void 0 || value === null) continue;
6086
+ if (Array.isArray(value)) if (key === `params`) value.forEach((item, index$1) => url.searchParams.set(`params[${index$1 + 1}]`, String(item)));
6087
+ else url.searchParams.set(key, value.join(`,`));
6088
+ else if (typeof value === `object`) for (const [k, v] of Object.entries(value)) url.searchParams.set(`${key}[${k}]`, String(v));
6089
+ else url.searchParams.set(key, String(value));
6090
+ }
6091
+ url.searchParams.set(`offset`, `now`);
6092
+ return url;
6093
+ }
6054
6094
  function jsonSafe(value) {
6055
6095
  if (typeof value === `bigint`) return value.toString();
6056
6096
  if (value === null || typeof value !== `object`) return value;
@@ -6072,37 +6112,19 @@ function rowKeyForMessage(message) {
6072
6112
  const candidate = headers.key ?? headers.rowKey ?? message.value?.id ?? message.value?.key ?? message.old_value?.id ?? message.old_value?.key;
6073
6113
  return candidate === void 0 ? void 0 : stableJson(candidate);
6074
6114
  }
6075
- function pgSyncMessageToDurableEvent(message, optionsOrSourceRef) {
6115
+ function pgSyncMessageToDurableEvent(message) {
6076
6116
  const operation = message.headers.operation;
6077
6117
  if (operation !== `insert` && operation !== `update` && operation !== `delete`) return null;
6078
- const sourceRef = typeof optionsOrSourceRef === `string` ? optionsOrSourceRef : (0, __electric_ax_agents_runtime.sourceRefForPgSync)(optionsOrSourceRef);
6079
- const rowKey = rowKeyForMessage(message);
6080
- const offset = message.headers.offset;
6081
- if (typeof offset !== `string` || offset.length === 0) return null;
6082
- const messageKeyPart = offset;
6083
- const messageKey = `${sourceRef}:${operation}:${messageKeyPart}`;
6084
- const timestamp$1 = new Date().toISOString();
6085
- const oldValue = message.old_value;
6086
- const safeValue = jsonSafe(message.value);
6087
- const safeOldValue = jsonSafe(oldValue);
6088
- const safeHeaders = jsonSafe(message.headers);
6118
+ const key = message.key ?? (typeof message.headers.key === `string` ? message.headers.key : void 0) ?? rowKeyForMessage(message);
6119
+ if (!key) return null;
6120
+ const safeMessage = jsonSafe(message);
6089
6121
  return {
6090
6122
  type: `pg_sync_change`,
6091
- key: messageKey,
6092
- value: {
6093
- key: messageKey,
6094
- table: typeof optionsOrSourceRef === `string` ? void 0 : optionsOrSourceRef.table,
6095
- operation,
6096
- ...rowKey !== void 0 ? { rowKey } : {},
6097
- ...message.value !== void 0 ? { value: safeValue } : {},
6098
- ...oldValue !== void 0 ? { oldValue: safeOldValue } : {},
6099
- headers: safeHeaders,
6100
- ...typeof offset === `string` ? { offset } : {},
6101
- receivedAt: timestamp$1
6102
- },
6123
+ key,
6124
+ value: safeMessage,
6103
6125
  headers: {
6104
- operation,
6105
- timestamp: timestamp$1
6126
+ ...jsonSafe(message.headers),
6127
+ operation
6106
6128
  }
6107
6129
  };
6108
6130
  }
@@ -6192,13 +6214,13 @@ var PgSyncBridge = class {
6192
6214
  }
6193
6215
  if (!(0, __electric_sql_client.isChangeMessage)(message)) continue;
6194
6216
  if (!this.skipChangesUntilUpToDate) {
6195
- const event = pgSyncMessageToDurableEvent(message, this.options);
6217
+ const event = pgSyncMessageToDurableEvent(message);
6196
6218
  if (event) {
6197
6219
  if (!this.producer) throw new Error(`pg-sync producer is not started`);
6198
6220
  await this.producer.append(JSON.stringify(event));
6199
6221
  await this.producer.flush?.();
6200
6222
  await this.evaluateWakes?.(this.streamUrl, event);
6201
- }
6223
+ } else serverLog.warn(`[pg-sync-bridge] dropped change message for ${this.sourceRef} (unknown operation or missing row key):`, message.headers);
6202
6224
  }
6203
6225
  await this.persistCursor(stream);
6204
6226
  this.retryAttempt = 0;
@@ -6247,13 +6269,15 @@ var PgSyncBridge = class {
6247
6269
  var PgSyncBridgeManager = class {
6248
6270
  bridges = new Map();
6249
6271
  starting = new Map();
6250
- url;
6251
6272
  retry;
6273
+ fetchFn;
6274
+ probeTimeoutMs;
6252
6275
  constructor(streamClient, evaluateWakes, registry, options = {}) {
6253
6276
  this.streamClient = streamClient;
6254
6277
  this.evaluateWakes = evaluateWakes;
6255
6278
  this.registry = registry;
6256
- this.url = options.url ?? PG_SYNC_ELECTRIC_SHAPE_URL;
6279
+ this.fetchFn = options.fetchFn;
6280
+ this.probeTimeoutMs = options.probeTimeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
6257
6281
  this.retry = {
6258
6282
  initialDelayMs: options.retry?.initialDelayMs ?? DEFAULT_RETRY_INITIAL_DELAY_MS,
6259
6283
  maxDelayMs: options.retry?.maxDelayMs ?? DEFAULT_RETRY_MAX_DELAY_MS,
@@ -6264,9 +6288,16 @@ var PgSyncBridgeManager = class {
6264
6288
  async start() {
6265
6289
  const rows = await this.registry?.listPgSyncBridges?.();
6266
6290
  if (!rows) return;
6267
- await Promise.all(rows.map((row) => this.ensureBridge(row).catch((error) => {
6268
- serverLog.warn(`[pg-sync-bridge] failed to start ${row.sourceRef}:`, error);
6269
- })));
6291
+ await Promise.all(rows.map(async (row) => {
6292
+ if (!row.options.url) {
6293
+ serverLog.warn(`[pg-sync-bridge] deleting registration ${row.sourceRef}: it predates required source URLs; re-register the observation with an explicit Electric shape URL`);
6294
+ await this.registry?.deletePgSyncBridge?.(row.sourceRef);
6295
+ return;
6296
+ }
6297
+ await this.ensureBridge(row).catch((error) => {
6298
+ serverLog.warn(`[pg-sync-bridge] failed to start ${row.sourceRef}:`, error);
6299
+ });
6300
+ }));
6270
6301
  }
6271
6302
  async register(options, metadata) {
6272
6303
  const mergedMetadata = {
@@ -6280,6 +6311,7 @@ var PgSyncBridgeManager = class {
6280
6311
  const resolvedSource = this.resolveSource(canonicalOptions);
6281
6312
  const sourceRef = (0, __electric_ax_agents_runtime.sourceRefForPgSync)(canonicalOptions);
6282
6313
  const streamUrl = (0, __electric_ax_agents_runtime.getPgSyncStreamPath)(sourceRef, this.registry?.tenantId);
6314
+ if (!this.bridges.has(sourceRef) && !this.starting.has(sourceRef)) await this.probeSource(resolvedSource, canonicalOptions);
6283
6315
  const row = await this.registry?.upsertPgSyncBridge({
6284
6316
  sourceRef,
6285
6317
  options: canonicalOptions,
@@ -6320,7 +6352,32 @@ var PgSyncBridgeManager = class {
6320
6352
  await start;
6321
6353
  }
6322
6354
  resolveSource(options) {
6323
- return { url: options.url ?? this.url };
6355
+ if (!options.url) throw new PgSyncSourceValidationError(`pgSync source url is required; no server default is configured`);
6356
+ return { url: options.url };
6357
+ }
6358
+ /**
6359
+ * One-shot fetch of the shape log before a bridge is created, so a bad
6360
+ * URL or rejected shape fails the registration instead of dying silently
6361
+ * in the bridge's retry loop.
6362
+ */
6363
+ async probeSource(source, options) {
6364
+ const probeUrl = buildShapeProbeUrl(source.url, options);
6365
+ const fetchFn = this.fetchFn ?? globalThis.fetch;
6366
+ let response;
6367
+ try {
6368
+ response = await fetchFn(probeUrl, { signal: AbortSignal.timeout(this.probeTimeoutMs) });
6369
+ } catch (error) {
6370
+ throw new PgSyncSourceValidationError(`pgSync source at ${source.url} is unreachable: ${error instanceof Error ? error.message : String(error)}`);
6371
+ }
6372
+ if (!response.ok) {
6373
+ const body = (await response.text().catch(() => `<failed to read body>`)).slice(0, 500);
6374
+ throw new PgSyncSourceValidationError(`pgSync source at ${source.url} rejected the shape request (${response.status})${body ? `: ${body}` : ``}`);
6375
+ }
6376
+ if (!response.headers.get(`electric-handle`)) {
6377
+ const suggestion = new URL(source.url);
6378
+ suggestion.pathname = `/v1/shape`;
6379
+ throw new PgSyncSourceValidationError(`pgSync source at ${source.url} responded but is not a shape log (missing electric-handle header) — the Electric shape API is usually served at ${suggestion.origin}/v1/shape`);
6380
+ }
6324
6381
  }
6325
6382
  async stop() {
6326
6383
  await Promise.allSettled(this.starting.values());
@@ -7282,6 +7339,7 @@ var WakeRegistry = class {
7282
7339
  };
7283
7340
  if (value && `value` in value) change.value = value.value;
7284
7341
  if (value && `oldValue` in value) change.oldValue = value.oldValue;
7342
+ else if (value && `old_value` in value) change.oldValue = value.old_value;
7285
7343
  if (eventType === `inbox`) {
7286
7344
  if (typeof value?.from === `string`) change.from = value.from;
7287
7345
  if (typeof value?.from_principal === `string`) change.from_principal = value.from_principal;
@@ -8695,8 +8753,8 @@ const subscriptionLifetimeSchema = __sinclair_typebox.Type.Union([
8695
8753
  }),
8696
8754
  __sinclair_typebox.Type.Object({ kind: __sinclair_typebox.Type.Literal(`manual`) })
8697
8755
  ]);
8698
- const eventSourceSubscriptionBodySchema = __sinclair_typebox.Type.Object({
8699
- sourceKey: __sinclair_typebox.Type.String(),
8756
+ const webhookSourceSubscriptionBodySchema = __sinclair_typebox.Type.Object({
8757
+ webhookKey: __sinclair_typebox.Type.String(),
8700
8758
  bucketKey: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.String()),
8701
8759
  params: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.Record(__sinclair_typebox.Type.String(), __sinclair_typebox.Type.Unknown())),
8702
8760
  filterKey: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.String()),
@@ -8729,8 +8787,9 @@ entitiesRouter.post(`/:type/:instanceId/tags/:tagKey`, withExistingEntity, withS
8729
8787
  entitiesRouter.delete(`/:type/:instanceId/tags/:tagKey`, withExistingEntity, withEntityPermission(`write`), deleteTag);
8730
8788
  entitiesRouter.put(`/:type/:instanceId/schedules/:scheduleId`, withExistingEntity, withSchema(scheduleBodySchema), withEntityPermission(`schedule`), upsertSchedule);
8731
8789
  entitiesRouter.delete(`/:type/:instanceId/schedules/:scheduleId`, withExistingEntity, withEntityPermission(`schedule`), deleteSchedule);
8732
- entitiesRouter.put(`/:type/:instanceId/event-source-subscriptions/:subscriptionId`, withExistingEntity, withSchema(eventSourceSubscriptionBodySchema), withEntityPermission(`write`), upsertEventSourceSubscription);
8733
- entitiesRouter.delete(`/:type/:instanceId/event-source-subscriptions/:subscriptionId`, withExistingEntity, withEntityPermission(`write`), deleteEventSourceSubscription);
8790
+ entitiesRouter.put(`/:type/:instanceId/webhook-source-subscriptions/:subscriptionId`, withExistingEntity, withSchema(webhookSourceSubscriptionBodySchema), withEntityPermission(`write`), upsertWebhookSourceSubscription);
8791
+ entitiesRouter.delete(`/:type/:instanceId/webhook-source-subscriptions/:subscriptionId`, withExistingEntity, withEntityPermission(`write`), deleteWebhookSourceSubscription);
8792
+ entitiesRouter.delete(`/:type/:instanceId/pg-sync-observations/:sourceRef`, withExistingEntity, withEntityPermission(`write`), deletePgSyncObservation);
8734
8793
  entitiesRouter.get(`/:type/:instanceId/grants`, withExistingEntity, withEntityPermission(`manage`), listEntityPermissionGrants);
8735
8794
  entitiesRouter.post(`/:type/:instanceId/grants`, withExistingEntity, withSchema(entityPermissionGrantInputSchema), withEntityPermission(`manage`), createEntityPermissionGrant);
8736
8795
  entitiesRouter.delete(`/:type/:instanceId/grants/:grantId`, withExistingEntity, withEntityPermission(`manage`), deleteEntityPermissionGrant);
@@ -8981,22 +9040,22 @@ async function deleteSchedule(request, ctx) {
8981
9040
  const result = await ctx.entityManager.deleteSchedule(entityUrl, { id: decodeURIComponent(request.params.scheduleId) });
8982
9041
  return (0, itty_router.json)(result);
8983
9042
  }
8984
- async function upsertEventSourceSubscription(request, ctx) {
8985
- const principalMutationError = rejectPrincipalEntityMutation(request, `subscribed to event sources`);
9043
+ async function upsertWebhookSourceSubscription(request, ctx) {
9044
+ const principalMutationError = rejectPrincipalEntityMutation(request, `subscribed to webhook sources`);
8986
9045
  if (principalMutationError) return principalMutationError;
8987
- const catalog = ctx.eventSources;
8988
- if (!catalog) return apiError(404, ErrCodeNotFound, `No event source catalog is configured`);
9046
+ const catalog = ctx.webhookSources;
9047
+ if (!catalog) return apiError(404, ErrCodeNotFound, `No webhook source catalog is configured`);
8989
9048
  const { entityUrl } = requireExistingEntityRoute(request);
8990
9049
  const parsed = routeBody(request);
8991
- const source = await catalog.getEventSource(parsed.sourceKey);
8992
- if (!source) return apiError(404, ErrCodeNotFound, `Event source "${parsed.sourceKey}" not found`);
9050
+ const source = await catalog.getWebhookSource(parsed.webhookKey);
9051
+ if (!source) return apiError(404, ErrCodeNotFound, `Webhook source "${parsed.webhookKey}" not found`);
8993
9052
  if (parsed.lifetime?.kind === `expires_at`) {
8994
9053
  const expiresAt = new Date(parsed.lifetime.at);
8995
9054
  if (Number.isNaN(expiresAt.getTime())) return apiError(400, ErrCodeInvalidRequest, `Invalid expires_at lifetime timestamp`);
8996
9055
  }
8997
9056
  let resolved;
8998
9057
  try {
8999
- resolved = (0, __electric_ax_agents_runtime.resolveEventSourceSubscription)({
9058
+ resolved = (0, __electric_ax_agents_runtime.resolveWebhookSourceSubscription)({
9000
9059
  contract: source,
9001
9060
  entityUrl,
9002
9061
  request: {
@@ -9008,18 +9067,25 @@ async function upsertEventSourceSubscription(request, ctx) {
9008
9067
  } catch (error) {
9009
9068
  return apiError(400, ErrCodeInvalidRequest, error instanceof Error ? error.message : String(error));
9010
9069
  }
9011
- await ctx.ensureEventSourceWakeSource?.(resolved.subscription.sourceUrl);
9012
- const result = await ctx.entityManager.upsertEventSourceSubscription(entityUrl, {
9070
+ await ctx.ensureWebhookSourceWakeSource?.(resolved.subscription.sourceUrl);
9071
+ const result = await ctx.entityManager.upsertWebhookSourceSubscription(entityUrl, {
9013
9072
  subscription: resolved.subscription,
9014
- manifest: (0, __electric_ax_agents_runtime.buildEventSourceManifestEntry)(resolved)
9073
+ manifest: (0, __electric_ax_agents_runtime.buildWebhookSourceManifestEntry)(resolved)
9015
9074
  });
9016
9075
  return (0, itty_router.json)(result);
9017
9076
  }
9018
- async function deleteEventSourceSubscription(request, ctx) {
9019
- const principalMutationError = rejectPrincipalEntityMutation(request, `unsubscribed from event sources`);
9077
+ async function deleteWebhookSourceSubscription(request, ctx) {
9078
+ const principalMutationError = rejectPrincipalEntityMutation(request, `unsubscribed from webhook sources`);
9020
9079
  if (principalMutationError) return principalMutationError;
9021
9080
  const { entityUrl } = requireExistingEntityRoute(request);
9022
- const result = await ctx.entityManager.deleteEventSourceSubscription(entityUrl, { id: decodeURIComponent(request.params.subscriptionId) });
9081
+ const result = await ctx.entityManager.deleteWebhookSourceSubscription(entityUrl, { id: decodeURIComponent(request.params.subscriptionId) });
9082
+ return (0, itty_router.json)(result);
9083
+ }
9084
+ async function deletePgSyncObservation(request, ctx) {
9085
+ const principalMutationError = rejectPrincipalEntityMutation(request, `unobserved a pg-sync source`);
9086
+ if (principalMutationError) return principalMutationError;
9087
+ const { entityUrl } = requireExistingEntityRoute(request);
9088
+ const result = await ctx.entityManager.deletePgSyncObservation(entityUrl, { sourceRef: decodeURIComponent(request.params.sourceRef) });
9023
9089
  return (0, itty_router.json)(result);
9024
9090
  }
9025
9091
  function tagResponseBody(entity) {
@@ -9485,7 +9551,7 @@ function toPublicEntityType(entityType) {
9485
9551
  //#endregion
9486
9552
  //#region src/routing/pg-sync-router.ts
9487
9553
  const pgSyncOptionsSchema = __sinclair_typebox.Type.Object({
9488
- url: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.String()),
9554
+ url: __sinclair_typebox.Type.String(),
9489
9555
  table: __sinclair_typebox.Type.String(),
9490
9556
  columns: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.Array(__sinclair_typebox.Type.String())),
9491
9557
  where: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.String()),
@@ -9507,6 +9573,7 @@ const pgSyncRouter = (0, itty_router.Router)({ base: `/_electric/pg-sync` });
9507
9573
  pgSyncRouter.post(`/register`, withSchema(pgSyncRegisterBodySchema), registerPgSync);
9508
9574
  async function registerPgSync(request, ctx) {
9509
9575
  const { options, metadata } = routeBody(request);
9576
+ if (options.url.trim() === ``) return apiError(400, ErrCodeInvalidRequest, `pgSync url must be non-empty`);
9510
9577
  if (options.table.trim() === ``) return apiError(400, ErrCodeInvalidRequest, `pgSync table must be non-empty`);
9511
9578
  if (!ctx.pgSyncBridgeManager) return apiError(503, ErrCodeInvalidRequest, `pgSync bridge manager is not configured`);
9512
9579
  try {
@@ -9521,6 +9588,8 @@ async function registerPgSync(request, ctx) {
9521
9588
  const result = await ctx.pgSyncBridgeManager.register(options, requestMetadata$1);
9522
9589
  return (0, itty_router.json)(result);
9523
9590
  } catch (error) {
9591
+ if (error instanceof PgSyncSourceValidationError) return apiError(400, ErrCodeInvalidRequest, error.message);
9592
+ serverLog.error(`[pg-sync] registration failed for table "${options.table}":`, error);
9524
9593
  return apiError(500, ErrCodeInvalidRequest, `pgSync registration failed: ${error instanceof Error ? error.message : String(error)}`);
9525
9594
  }
9526
9595
  }
@@ -10045,7 +10114,7 @@ const wakeCallbackBodySchema = __sinclair_typebox.Type.Object({
10045
10114
  const DS_SUBSCRIPTION_CALLBACK_PREFIX = `ds-subscription:`;
10046
10115
  const internalRouter = (0, itty_router.Router)({ base: `/_electric` });
10047
10116
  internalRouter.get(`/health`, () => (0, itty_router.json)({ status: `ok` }));
10048
- internalRouter.get(`/event-sources`, listEventSources);
10117
+ internalRouter.get(`/webhook-sources`, listWebhookSources);
10049
10118
  internalRouter.post(`/wake`, withSchema(wakeRegistrationBodySchema), registerWake);
10050
10119
  internalRouter.post(`/subscription-webhooks/:subscriptionId`, subscriptionWebhook);
10051
10120
  internalRouter.post(`/wake-callbacks/:consumerId`, wakeCallback);
@@ -10167,11 +10236,11 @@ async function registerWake(request, ctx) {
10167
10236
  await ctx.entityManager.registerWake(opts);
10168
10237
  return (0, itty_router.status)(204);
10169
10238
  }
10170
- async function listEventSources(_request, ctx) {
10171
- const eventSources = ctx.eventSources ? await ctx.eventSources.listEventSources() : [];
10172
- return (0, itty_router.json)({ eventSources: eventSources.filter(isAgentVisibleEventSource) });
10239
+ async function listWebhookSources(_request, ctx) {
10240
+ const webhookSources = ctx.webhookSources ? await ctx.webhookSources.listWebhookSources() : [];
10241
+ return (0, itty_router.json)({ webhookSources: webhookSources.filter(isAgentVisibleWebhookSource) });
10173
10242
  }
10174
- function isAgentVisibleEventSource(source) {
10243
+ function isAgentVisibleWebhookSource(source) {
10175
10244
  return source.agentVisible === true && source.status === `active`;
10176
10245
  }
10177
10246
  async function subscriptionWebhook(request, ctx) {
package/dist/index.d.cts CHANGED
@@ -252,7 +252,7 @@ import * as drizzle_orm_pg_core303 from "drizzle-orm/pg-core";
252
252
  import * as drizzle_orm_pg_core304 from "drizzle-orm/pg-core";
253
253
  import * as drizzle_orm75 from "drizzle-orm";
254
254
  import * as drizzle_orm76 from "drizzle-orm";
255
- import { EntityTags, EventPointer, EventSourceBucket, EventSourceContract, EventSourceContract as EventSourceContract$1, EventSourceFilter, EventSourceSubscription, EventSourceSubscription as EventSourceSubscription$1, EventSourceSubscriptionInput, PgSyncOptions, PgSyncRequestMetadata, SlashCommandDefinition, SubscriptionLifetime, WebhookNotification, WebhookSignatureVerifierConfig } from "@electric-ax/agents-runtime";
255
+ import { EntityTags, EventPointer, PgSyncOptions, PgSyncRequestMetadata, SlashCommandDefinition, SubscriptionLifetime, WebhookNotification, WebhookSignatureVerifierConfig, WebhookSourceBucket, WebhookSourceContract, WebhookSourceContract as WebhookSourceContract$1, WebhookSourceFilter, WebhookSourceSubscription, WebhookSourceSubscription as WebhookSourceSubscription$1, WebhookSourceSubscriptionInput } from "@electric-ax/agents-runtime";
256
256
  import "@sinclair/typebox";
257
257
  import { MaybePromise } from "@durable-streams/client";
258
258
  import { AutoRouterType, IRequest } from "itty-router";
@@ -4969,6 +4969,7 @@ declare class PostgresRegistry {
4969
4969
  touchPgSyncBridge(sourceRef: string): Promise<void>;
4970
4970
  updatePgSyncBridgeCursor(sourceRef: string, shapeHandle: string, shapeOffset: string, initialSnapshotComplete?: boolean): Promise<void>;
4971
4971
  clearPgSyncBridgeCursor(sourceRef: string): Promise<void>;
4972
+ deletePgSyncBridge(sourceRef: string): Promise<void>;
4972
4973
  upsertEntityBridge(row: {
4973
4974
  sourceRef: string;
4974
4975
  tags: EntityTags;
@@ -5746,18 +5747,28 @@ declare class EntityManager {
5746
5747
  }): Promise<{
5747
5748
  txid: string;
5748
5749
  }>;
5749
- upsertEventSourceSubscription(entityUrl: string, req: {
5750
- subscription: EventSourceSubscription$1;
5750
+ upsertWebhookSourceSubscription(entityUrl: string, req: {
5751
+ subscription: WebhookSourceSubscription$1;
5751
5752
  manifest: Record<string, unknown>;
5752
5753
  }): Promise<{
5753
5754
  txid: string;
5754
- subscription: EventSourceSubscription$1;
5755
+ subscription: WebhookSourceSubscription$1;
5755
5756
  }>;
5756
- deleteEventSourceSubscription(entityUrl: string, req: {
5757
+ deleteWebhookSourceSubscription(entityUrl: string, req: {
5757
5758
  id: string;
5758
5759
  }): Promise<{
5759
5760
  txid: string;
5760
5761
  }>;
5762
+ /**
5763
+ * Stop this entity observing a pg-sync source: drop its manifest entry and
5764
+ * the wake it anchors. The shared pg-sync bridge (keyed by sourceRef, not by
5765
+ * subscriber) is intentionally left running for any other observers.
5766
+ */
5767
+ deletePgSyncObservation(entityUrl: string, req: {
5768
+ sourceRef: string;
5769
+ }): Promise<{
5770
+ txid: string;
5771
+ }>;
5761
5772
  /**
5762
5773
  * Register a wake subscription from a subscriber to a source entity.
5763
5774
  */
@@ -5836,14 +5847,17 @@ declare class EntityManager {
5836
5847
  //#endregion
5837
5848
  //#region src/pg-sync-bridge-manager.d.ts
5838
5849
  interface PgSyncBridgeManagerOptions {
5839
- url?: string;
5840
5850
  retry?: {
5841
5851
  initialDelayMs?: number;
5842
5852
  maxDelayMs?: number;
5843
5853
  random?: () => number;
5844
5854
  sleep?: (ms: number) => Promise<void>;
5845
5855
  };
5856
+ fetchFn?: typeof fetch;
5857
+ probeTimeoutMs?: number;
5846
5858
  }
5859
+ /** Registration was rejected because the source itself is invalid — map to a 4xx. */
5860
+
5847
5861
  interface PgSyncBridgeCoordinator {
5848
5862
  start?(): Promise<void>;
5849
5863
  register(options: PgSyncOptions, metadata?: PgSyncRequestMetadata): Promise<{
@@ -6033,9 +6047,9 @@ declare function webhookSigningMetadata(signer: WebhookSigner, streamRootUrl: st
6033
6047
 
6034
6048
  //#endregion
6035
6049
  //#region src/routing/context.d.ts
6036
- interface EventSourceCatalog {
6037
- listEventSources: () => Array<EventSourceContract$1> | Promise<Array<EventSourceContract$1>>;
6038
- getEventSource: (sourceKey: string) => EventSourceContract$1 | undefined | Promise<EventSourceContract$1 | undefined>;
6050
+ interface WebhookSourceCatalog {
6051
+ listWebhookSources: () => Array<WebhookSourceContract$1> | Promise<Array<WebhookSourceContract$1>>;
6052
+ getWebhookSource: (webhookKey: string) => WebhookSourceContract$1 | undefined | Promise<WebhookSourceContract$1 | undefined>;
6039
6053
  }
6040
6054
  /**
6041
6055
  * Per-request tenant context passed through every router and handler.
@@ -6064,8 +6078,8 @@ interface TenantContext {
6064
6078
  runtime: ElectricAgentsTenantRuntime;
6065
6079
  entityBridgeManager: EntityBridgeCoordinator;
6066
6080
  pgSyncBridgeManager?: PgSyncBridgeCoordinator;
6067
- eventSources?: EventSourceCatalog;
6068
- ensureEventSourceWakeSource?: (sourceUrl: string) => Promise<void> | void;
6081
+ webhookSources?: WebhookSourceCatalog;
6082
+ ensureWebhookSourceWakeSource?: (sourceUrl: string) => Promise<void> | void;
6069
6083
  authorizeRequest?: AuthorizeRequest;
6070
6084
  isShuttingDown: () => boolean;
6071
6085
  }
@@ -6086,4 +6100,4 @@ declare class UnregisteredTenantError extends Error {
6086
6100
  declare function isUnregisteredTenantError(error: unknown): error is UnregisteredTenantError;
6087
6101
 
6088
6102
  //#endregion
6089
- export { AgentsHost, AgentsHostOptions, AgentsHostTenantConfig, AgentsHostTenantRuntime, AuthenticateRequest, AuthorizationDecision, AuthorizationResource, AuthorizeRequest, ConsumerClaim, DEFAULT_TENANT_ID, DispatchPolicy, DispatchTarget, DrizzleDB, DurableStreamsBearerProvider, DurableStreamsRoutingAdapter, DurableStreamsRoutingInput, Ed25519WebhookSignerOptions, ElectricAgentsEntity, ElectricAgentsEntityRow, ElectricAgentsEntityType, ElectricAgentsRunner, ElectricAgentsUser, EntityBridgeCoordinator, EntityDispatchState, EntityListFilter, EntityPermission, EntityPermissionGrant, EntityPermissionPropagation, EntitySignal, EntityStatus, EntityTypePermission, EntityTypePermissionGrant, EntityTypePermissionGrantInput, EventSourceBucket, EventSourceCatalog, EventSourceContract, EventSourceFilter, EventSourceSubscription, EventSourceSubscriptionInput, GlobalRoutes, PermissionSubject, PermissionSubjectKind, PgClient, Principal, PrincipalKind, PublicElectricAgentsEntity, PublicWakeNotification, RegisterEntityTypeRequest, RegisterRunnerRequest, RequestPrincipal, RunnerAdminStatus, RunnerHeartbeatRequest, RunnerKind, RunnerLiveness, SendRequest, SignalRequest, SignalResponse, SourceStreamOffset, StreamClient, StreamClientOptions, SubscriptionClaimResponse, SubscriptionCreateInput, SubscriptionLifetime, SubscriptionResponse, SubscriptionStreamInfo, TenantContext, TypedSpawnRequest, UnregisteredTenantError, WakeNotificationRow, WebhookJwks, WebhookPublicJwk, WebhookSigner, WebhookSigningKeyInput, WebhookSigningMetadata, assertEntitySignal, assertEntityStatus, createDb, createEd25519WebhookSigner, expectedSignalStatus, getDefaultWebhookSigner, globalRouter, isTerminalEntityStatus, isUnregisteredTenantError, pathPrefixedSingleTenantDurableStreamsRoutingAdapter, rejectsNormalWrites, runMigrations, streamRootDurableStreamsRoutingAdapter, tenantRootDurableStreamsRoutingAdapter, toPublicEntity, webhookSigningMetadata };
6103
+ export { AgentsHost, AgentsHostOptions, AgentsHostTenantConfig, AgentsHostTenantRuntime, AuthenticateRequest, AuthorizationDecision, AuthorizationResource, AuthorizeRequest, ConsumerClaim, DEFAULT_TENANT_ID, DispatchPolicy, DispatchTarget, DrizzleDB, DurableStreamsBearerProvider, DurableStreamsRoutingAdapter, DurableStreamsRoutingInput, Ed25519WebhookSignerOptions, ElectricAgentsEntity, ElectricAgentsEntityRow, ElectricAgentsEntityType, ElectricAgentsRunner, ElectricAgentsUser, EntityBridgeCoordinator, EntityDispatchState, EntityListFilter, EntityPermission, EntityPermissionGrant, EntityPermissionPropagation, EntitySignal, EntityStatus, EntityTypePermission, EntityTypePermissionGrant, EntityTypePermissionGrantInput, GlobalRoutes, PermissionSubject, PermissionSubjectKind, PgClient, Principal, PrincipalKind, PublicElectricAgentsEntity, PublicWakeNotification, RegisterEntityTypeRequest, RegisterRunnerRequest, RequestPrincipal, RunnerAdminStatus, RunnerHeartbeatRequest, RunnerKind, RunnerLiveness, SendRequest, SignalRequest, SignalResponse, SourceStreamOffset, StreamClient, StreamClientOptions, SubscriptionClaimResponse, SubscriptionCreateInput, SubscriptionLifetime, SubscriptionResponse, SubscriptionStreamInfo, TenantContext, TypedSpawnRequest, UnregisteredTenantError, WakeNotificationRow, WebhookJwks, WebhookPublicJwk, WebhookSigner, WebhookSigningKeyInput, WebhookSigningMetadata, WebhookSourceBucket, WebhookSourceCatalog, WebhookSourceContract, WebhookSourceFilter, WebhookSourceSubscription, WebhookSourceSubscriptionInput, assertEntitySignal, assertEntityStatus, createDb, createEd25519WebhookSigner, expectedSignalStatus, getDefaultWebhookSigner, globalRouter, isTerminalEntityStatus, isUnregisteredTenantError, pathPrefixedSingleTenantDurableStreamsRoutingAdapter, rejectsNormalWrites, runMigrations, streamRootDurableStreamsRoutingAdapter, tenantRootDurableStreamsRoutingAdapter, toPublicEntity, webhookSigningMetadata };
package/dist/index.d.ts CHANGED
@@ -254,7 +254,7 @@ import * as drizzle_orm_pg_core302 from "drizzle-orm/pg-core";
254
254
  import * as drizzle_orm_pg_core303 from "drizzle-orm/pg-core";
255
255
  import * as drizzle_orm_pg_core304 from "drizzle-orm/pg-core";
256
256
  import { JsonWebKey, KeyObject } from "node:crypto";
257
- import { EntityTags, EventPointer, EventSourceBucket, EventSourceContract, EventSourceContract as EventSourceContract$1, EventSourceFilter, EventSourceSubscription, EventSourceSubscription as EventSourceSubscription$1, EventSourceSubscriptionInput, PgSyncOptions, PgSyncRequestMetadata, SlashCommandDefinition, SubscriptionLifetime, WebhookNotification, WebhookSignatureVerifierConfig } from "@electric-ax/agents-runtime";
257
+ import { EntityTags, EventPointer, PgSyncOptions, PgSyncRequestMetadata, SlashCommandDefinition, SubscriptionLifetime, WebhookNotification, WebhookSignatureVerifierConfig, WebhookSourceBucket, WebhookSourceContract, WebhookSourceContract as WebhookSourceContract$1, WebhookSourceFilter, WebhookSourceSubscription, WebhookSourceSubscription as WebhookSourceSubscription$1, WebhookSourceSubscriptionInput } from "@electric-ax/agents-runtime";
258
258
  import { MaybePromise } from "@durable-streams/client";
259
259
  import "@sinclair/typebox";
260
260
  import { AutoRouterType, IRequest } from "itty-router";
@@ -4968,6 +4968,7 @@ declare class PostgresRegistry {
4968
4968
  touchPgSyncBridge(sourceRef: string): Promise<void>;
4969
4969
  updatePgSyncBridgeCursor(sourceRef: string, shapeHandle: string, shapeOffset: string, initialSnapshotComplete?: boolean): Promise<void>;
4970
4970
  clearPgSyncBridgeCursor(sourceRef: string): Promise<void>;
4971
+ deletePgSyncBridge(sourceRef: string): Promise<void>;
4971
4972
  upsertEntityBridge(row: {
4972
4973
  sourceRef: string;
4973
4974
  tags: EntityTags;
@@ -5745,18 +5746,28 @@ declare class EntityManager {
5745
5746
  }): Promise<{
5746
5747
  txid: string;
5747
5748
  }>;
5748
- upsertEventSourceSubscription(entityUrl: string, req: {
5749
- subscription: EventSourceSubscription$1;
5749
+ upsertWebhookSourceSubscription(entityUrl: string, req: {
5750
+ subscription: WebhookSourceSubscription$1;
5750
5751
  manifest: Record<string, unknown>;
5751
5752
  }): Promise<{
5752
5753
  txid: string;
5753
- subscription: EventSourceSubscription$1;
5754
+ subscription: WebhookSourceSubscription$1;
5754
5755
  }>;
5755
- deleteEventSourceSubscription(entityUrl: string, req: {
5756
+ deleteWebhookSourceSubscription(entityUrl: string, req: {
5756
5757
  id: string;
5757
5758
  }): Promise<{
5758
5759
  txid: string;
5759
5760
  }>;
5761
+ /**
5762
+ * Stop this entity observing a pg-sync source: drop its manifest entry and
5763
+ * the wake it anchors. The shared pg-sync bridge (keyed by sourceRef, not by
5764
+ * subscriber) is intentionally left running for any other observers.
5765
+ */
5766
+ deletePgSyncObservation(entityUrl: string, req: {
5767
+ sourceRef: string;
5768
+ }): Promise<{
5769
+ txid: string;
5770
+ }>;
5760
5771
  /**
5761
5772
  * Register a wake subscription from a subscriber to a source entity.
5762
5773
  */
@@ -5835,14 +5846,17 @@ declare class EntityManager {
5835
5846
  //#endregion
5836
5847
  //#region src/pg-sync-bridge-manager.d.ts
5837
5848
  interface PgSyncBridgeManagerOptions {
5838
- url?: string;
5839
5849
  retry?: {
5840
5850
  initialDelayMs?: number;
5841
5851
  maxDelayMs?: number;
5842
5852
  random?: () => number;
5843
5853
  sleep?: (ms: number) => Promise<void>;
5844
5854
  };
5855
+ fetchFn?: typeof fetch;
5856
+ probeTimeoutMs?: number;
5845
5857
  }
5858
+ /** Registration was rejected because the source itself is invalid — map to a 4xx. */
5859
+
5846
5860
  interface PgSyncBridgeCoordinator {
5847
5861
  start?(): Promise<void>;
5848
5862
  register(options: PgSyncOptions, metadata?: PgSyncRequestMetadata): Promise<{
@@ -6032,9 +6046,9 @@ declare function webhookSigningMetadata(signer: WebhookSigner, streamRootUrl: st
6032
6046
 
6033
6047
  //#endregion
6034
6048
  //#region src/routing/context.d.ts
6035
- interface EventSourceCatalog {
6036
- listEventSources: () => Array<EventSourceContract$1> | Promise<Array<EventSourceContract$1>>;
6037
- getEventSource: (sourceKey: string) => EventSourceContract$1 | undefined | Promise<EventSourceContract$1 | undefined>;
6049
+ interface WebhookSourceCatalog {
6050
+ listWebhookSources: () => Array<WebhookSourceContract$1> | Promise<Array<WebhookSourceContract$1>>;
6051
+ getWebhookSource: (webhookKey: string) => WebhookSourceContract$1 | undefined | Promise<WebhookSourceContract$1 | undefined>;
6038
6052
  }
6039
6053
  /**
6040
6054
  * Per-request tenant context passed through every router and handler.
@@ -6063,8 +6077,8 @@ interface TenantContext {
6063
6077
  runtime: ElectricAgentsTenantRuntime;
6064
6078
  entityBridgeManager: EntityBridgeCoordinator;
6065
6079
  pgSyncBridgeManager?: PgSyncBridgeCoordinator;
6066
- eventSources?: EventSourceCatalog;
6067
- ensureEventSourceWakeSource?: (sourceUrl: string) => Promise<void> | void;
6080
+ webhookSources?: WebhookSourceCatalog;
6081
+ ensureWebhookSourceWakeSource?: (sourceUrl: string) => Promise<void> | void;
6068
6082
  authorizeRequest?: AuthorizeRequest;
6069
6083
  isShuttingDown: () => boolean;
6070
6084
  }
@@ -6085,4 +6099,4 @@ declare class UnregisteredTenantError extends Error {
6085
6099
  declare function isUnregisteredTenantError(error: unknown): error is UnregisteredTenantError;
6086
6100
 
6087
6101
  //#endregion
6088
- export { AgentsHost, AgentsHostOptions, AgentsHostTenantConfig, AgentsHostTenantRuntime, AuthenticateRequest, AuthorizationDecision, AuthorizationResource, AuthorizeRequest, ConsumerClaim, DEFAULT_TENANT_ID, DispatchPolicy, DispatchTarget, DrizzleDB, DurableStreamsBearerProvider, DurableStreamsRoutingAdapter, DurableStreamsRoutingInput, Ed25519WebhookSignerOptions, ElectricAgentsEntity, ElectricAgentsEntityRow, ElectricAgentsEntityType, ElectricAgentsRunner, ElectricAgentsUser, EntityBridgeCoordinator, EntityDispatchState, EntityListFilter, EntityPermission, EntityPermissionGrant, EntityPermissionPropagation, EntitySignal, EntityStatus, EntityTypePermission, EntityTypePermissionGrant, EntityTypePermissionGrantInput, EventSourceBucket, EventSourceCatalog, EventSourceContract, EventSourceFilter, EventSourceSubscription, EventSourceSubscriptionInput, GlobalRoutes, PermissionSubject, PermissionSubjectKind, PgClient, Principal, PrincipalKind, PublicElectricAgentsEntity, PublicWakeNotification, RegisterEntityTypeRequest, RegisterRunnerRequest, RequestPrincipal, RunnerAdminStatus, RunnerHeartbeatRequest, RunnerKind, RunnerLiveness, SendRequest, SignalRequest, SignalResponse, SourceStreamOffset, StreamClient, StreamClientOptions, SubscriptionClaimResponse, SubscriptionCreateInput, SubscriptionLifetime, SubscriptionResponse, SubscriptionStreamInfo, TenantContext, TypedSpawnRequest, UnregisteredTenantError, WakeNotificationRow, WebhookJwks, WebhookPublicJwk, WebhookSigner, WebhookSigningKeyInput, WebhookSigningMetadata, assertEntitySignal, assertEntityStatus, createDb, createEd25519WebhookSigner, expectedSignalStatus, getDefaultWebhookSigner, globalRouter, isTerminalEntityStatus, isUnregisteredTenantError, pathPrefixedSingleTenantDurableStreamsRoutingAdapter, rejectsNormalWrites, runMigrations, streamRootDurableStreamsRoutingAdapter, tenantRootDurableStreamsRoutingAdapter, toPublicEntity, webhookSigningMetadata };
6102
+ export { AgentsHost, AgentsHostOptions, AgentsHostTenantConfig, AgentsHostTenantRuntime, AuthenticateRequest, AuthorizationDecision, AuthorizationResource, AuthorizeRequest, ConsumerClaim, DEFAULT_TENANT_ID, DispatchPolicy, DispatchTarget, DrizzleDB, DurableStreamsBearerProvider, DurableStreamsRoutingAdapter, DurableStreamsRoutingInput, Ed25519WebhookSignerOptions, ElectricAgentsEntity, ElectricAgentsEntityRow, ElectricAgentsEntityType, ElectricAgentsRunner, ElectricAgentsUser, EntityBridgeCoordinator, EntityDispatchState, EntityListFilter, EntityPermission, EntityPermissionGrant, EntityPermissionPropagation, EntitySignal, EntityStatus, EntityTypePermission, EntityTypePermissionGrant, EntityTypePermissionGrantInput, GlobalRoutes, PermissionSubject, PermissionSubjectKind, PgClient, Principal, PrincipalKind, PublicElectricAgentsEntity, PublicWakeNotification, RegisterEntityTypeRequest, RegisterRunnerRequest, RequestPrincipal, RunnerAdminStatus, RunnerHeartbeatRequest, RunnerKind, RunnerLiveness, SendRequest, SignalRequest, SignalResponse, SourceStreamOffset, StreamClient, StreamClientOptions, SubscriptionClaimResponse, SubscriptionCreateInput, SubscriptionLifetime, SubscriptionResponse, SubscriptionStreamInfo, TenantContext, TypedSpawnRequest, UnregisteredTenantError, WakeNotificationRow, WebhookJwks, WebhookPublicJwk, WebhookSigner, WebhookSigningKeyInput, WebhookSigningMetadata, WebhookSourceBucket, WebhookSourceCatalog, WebhookSourceContract, WebhookSourceFilter, WebhookSourceSubscription, WebhookSourceSubscriptionInput, assertEntitySignal, assertEntityStatus, createDb, createEd25519WebhookSigner, expectedSignalStatus, getDefaultWebhookSigner, globalRouter, isTerminalEntityStatus, isUnregisteredTenantError, pathPrefixedSingleTenantDurableStreamsRoutingAdapter, rejectsNormalWrites, runMigrations, streamRootDurableStreamsRoutingAdapter, tenantRootDurableStreamsRoutingAdapter, toPublicEntity, webhookSigningMetadata };