@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/entrypoint.js +938 -869
- package/dist/index.cjs +135 -66
- package/dist/index.d.cts +26 -12
- package/dist/index.d.ts +26 -12
- package/dist/index.js +136 -67
- package/package.json +5 -5
- package/src/entity-manager.ts +31 -7
- package/src/entity-registry.ts +11 -1
- package/src/index.ts +6 -6
- package/src/manifest-side-effects.ts +2 -6
- package/src/pg-sync-bridge-manager.ts +147 -47
- package/src/routing/context.ts +11 -11
- package/src/routing/entities-router.ts +51 -28
- package/src/routing/internal-router.ts +9 -7
- package/src/routing/pg-sync-router.ts +14 -1
- package/src/server.ts +8 -8
- package/src/wake-registry.ts +2 -0
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
|
|
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
|
|
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
|
|
4926
|
-
const manifestKey = (0, __electric_ax_agents_runtime.
|
|
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
|
-
|
|
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
|
|
6115
|
+
function pgSyncMessageToDurableEvent(message) {
|
|
6076
6116
|
const operation = message.headers.operation;
|
|
6077
6117
|
if (operation !== `insert` && operation !== `update` && operation !== `delete`) return null;
|
|
6078
|
-
const
|
|
6079
|
-
|
|
6080
|
-
const
|
|
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
|
|
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
|
-
|
|
6105
|
-
|
|
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
|
|
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.
|
|
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(
|
|
6268
|
-
|
|
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
|
-
|
|
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
|
|
8699
|
-
|
|
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/
|
|
8733
|
-
entitiesRouter.delete(`/:type/:instanceId/
|
|
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
|
|
8985
|
-
const principalMutationError = rejectPrincipalEntityMutation(request, `subscribed to
|
|
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.
|
|
8988
|
-
if (!catalog) return apiError(404, ErrCodeNotFound, `No
|
|
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.
|
|
8992
|
-
if (!source) return apiError(404, ErrCodeNotFound, `
|
|
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.
|
|
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.
|
|
9012
|
-
const result = await ctx.entityManager.
|
|
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.
|
|
9073
|
+
manifest: (0, __electric_ax_agents_runtime.buildWebhookSourceManifestEntry)(resolved)
|
|
9015
9074
|
});
|
|
9016
9075
|
return (0, itty_router.json)(result);
|
|
9017
9076
|
}
|
|
9018
|
-
async function
|
|
9019
|
-
const principalMutationError = rejectPrincipalEntityMutation(request, `unsubscribed from
|
|
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.
|
|
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.
|
|
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(`/
|
|
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
|
|
10171
|
-
const
|
|
10172
|
-
return (0, itty_router.json)({
|
|
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
|
|
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,
|
|
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
|
-
|
|
5750
|
-
subscription:
|
|
5750
|
+
upsertWebhookSourceSubscription(entityUrl: string, req: {
|
|
5751
|
+
subscription: WebhookSourceSubscription$1;
|
|
5751
5752
|
manifest: Record<string, unknown>;
|
|
5752
5753
|
}): Promise<{
|
|
5753
5754
|
txid: string;
|
|
5754
|
-
subscription:
|
|
5755
|
+
subscription: WebhookSourceSubscription$1;
|
|
5755
5756
|
}>;
|
|
5756
|
-
|
|
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
|
|
6037
|
-
|
|
6038
|
-
|
|
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
|
-
|
|
6068
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
5749
|
-
subscription:
|
|
5749
|
+
upsertWebhookSourceSubscription(entityUrl: string, req: {
|
|
5750
|
+
subscription: WebhookSourceSubscription$1;
|
|
5750
5751
|
manifest: Record<string, unknown>;
|
|
5751
5752
|
}): Promise<{
|
|
5752
5753
|
txid: string;
|
|
5753
|
-
subscription:
|
|
5754
|
+
subscription: WebhookSourceSubscription$1;
|
|
5754
5755
|
}>;
|
|
5755
|
-
|
|
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
|
|
6036
|
-
|
|
6037
|
-
|
|
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
|
-
|
|
6067
|
-
|
|
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,
|
|
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 };
|