@electric-ax/agents-server 0.4.20 → 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 +1003 -834
- package/dist/index.cjs +241 -72
- package/dist/index.d.cts +2507 -2440
- package/dist/index.d.ts +2506 -2441
- package/dist/index.js +242 -73
- package/drizzle/0016_entity_type_externally_writable_collections.sql +1 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +5 -5
- package/src/db/schema.ts +4 -0
- package/src/electric-agents-types.ts +23 -0
- package/src/entity-manager.ts +157 -7
- package/src/entity-registry.ts +25 -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 +112 -30
- package/src/routing/entity-types-router.ts +56 -0
- 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@electric-ax/agents-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Electric Agents entity runtime server",
|
|
5
5
|
"author": "Durable Stream contributors",
|
|
6
6
|
"bin": {
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"pino-pretty": "^13.0.0",
|
|
55
55
|
"postgres": "^3.4.0",
|
|
56
56
|
"undici": "^7.24.7",
|
|
57
|
-
"@electric-ax/agents-runtime": "0.
|
|
57
|
+
"@electric-ax/agents-runtime": "0.4.1"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@types/node": "^22.19.15",
|
|
@@ -65,9 +65,9 @@
|
|
|
65
65
|
"tsx": "^4.19.0",
|
|
66
66
|
"typescript": "^5.0.0",
|
|
67
67
|
"vitest": "^4.1.0",
|
|
68
|
-
"@electric-ax/agents": "0.
|
|
69
|
-
"@electric-ax/agents
|
|
70
|
-
"@electric-ax/agents-server-
|
|
68
|
+
"@electric-ax/agents-server-ui": "0.5.1",
|
|
69
|
+
"@electric-ax/agents": "0.4.19",
|
|
70
|
+
"@electric-ax/agents-server-conformance-tests": "0.1.12"
|
|
71
71
|
},
|
|
72
72
|
"files": [
|
|
73
73
|
"dist",
|
package/src/db/schema.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
timestamp,
|
|
15
15
|
unique,
|
|
16
16
|
} from 'drizzle-orm/pg-core'
|
|
17
|
+
import type { ExternallyWritableCollectionConfig } from '../electric-agents-types.js'
|
|
17
18
|
|
|
18
19
|
export const entityTypes = pgTable(
|
|
19
20
|
`entity_types`,
|
|
@@ -24,6 +25,9 @@ export const entityTypes = pgTable(
|
|
|
24
25
|
creationSchema: jsonb(`creation_schema`),
|
|
25
26
|
inboxSchemas: jsonb(`inbox_schemas`),
|
|
26
27
|
stateSchemas: jsonb(`state_schemas`),
|
|
28
|
+
externallyWritableCollections: jsonb(
|
|
29
|
+
`externally_writable_collections`
|
|
30
|
+
).$type<Record<string, ExternallyWritableCollectionConfig>>(),
|
|
27
31
|
slashCommands: jsonb(`slash_commands`),
|
|
28
32
|
serveEndpoint: text(`serve_endpoint`),
|
|
29
33
|
defaultDispatchPolicy: jsonb(`default_dispatch_policy`),
|
|
@@ -494,12 +494,31 @@ export function toPublicEntity(
|
|
|
494
494
|
}
|
|
495
495
|
}
|
|
496
496
|
|
|
497
|
+
/** Per-collection config making an entity-state collection externally writable via the router. */
|
|
498
|
+
export interface ExternallyWritableCollectionConfig {
|
|
499
|
+
/** Durable-stream event type for this collection, e.g. `state:comments`. */
|
|
500
|
+
type: string
|
|
501
|
+
/** Well-known contract this collection implements, e.g. `comments/v1`. */
|
|
502
|
+
contract?: string
|
|
503
|
+
/**
|
|
504
|
+
* Allowlist of external write operations. When set, the router rejects any
|
|
505
|
+
* operation not listed (403). When unset, only `insert` is permitted — the
|
|
506
|
+
* safe default, since open update/delete lets a client overwrite or remove
|
|
507
|
+
* another principal's rows by key.
|
|
508
|
+
*/
|
|
509
|
+
operations?: Array<`insert` | `update` | `delete`>
|
|
510
|
+
}
|
|
511
|
+
|
|
497
512
|
export interface ElectricAgentsEntityType {
|
|
498
513
|
name: string
|
|
499
514
|
description: string
|
|
500
515
|
creation_schema?: Record<string, unknown>
|
|
501
516
|
inbox_schemas?: Record<string, Record<string, unknown>>
|
|
502
517
|
state_schemas?: Record<string, Record<string, unknown>>
|
|
518
|
+
externally_writable_collections?: Record<
|
|
519
|
+
string,
|
|
520
|
+
ExternallyWritableCollectionConfig
|
|
521
|
+
>
|
|
503
522
|
slash_commands?: Array<SlashCommandDefinition>
|
|
504
523
|
serve_endpoint?: string
|
|
505
524
|
default_dispatch_policy?: DispatchPolicy
|
|
@@ -514,6 +533,10 @@ export interface RegisterEntityTypeRequest {
|
|
|
514
533
|
creation_schema?: Record<string, unknown>
|
|
515
534
|
inbox_schemas?: Record<string, Record<string, unknown>>
|
|
516
535
|
state_schemas?: Record<string, Record<string, unknown>>
|
|
536
|
+
externally_writable_collections?: Record<
|
|
537
|
+
string,
|
|
538
|
+
ExternallyWritableCollectionConfig
|
|
539
|
+
>
|
|
517
540
|
slash_commands?: Array<SlashCommandDefinition>
|
|
518
541
|
serve_endpoint?: string
|
|
519
542
|
default_dispatch_policy?: DispatchPolicy
|
package/src/entity-manager.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getCronStreamPath,
|
|
8
8
|
getSharedStateStreamPath,
|
|
9
9
|
getNextCronFireAt,
|
|
10
|
-
|
|
10
|
+
webhookSourceSubscriptionManifestKey,
|
|
11
11
|
manifestChildKey,
|
|
12
12
|
manifestSharedStateKey,
|
|
13
13
|
manifestSourceKey,
|
|
@@ -56,7 +56,7 @@ import type { queueAsPromised } from 'fastq'
|
|
|
56
56
|
import type { SchedulerClient } from './scheduler.js'
|
|
57
57
|
import type { WakeEvalResult, WakeRegistry } from './wake-registry.js'
|
|
58
58
|
import type { WakeMessage } from '@electric-ax/agents-runtime'
|
|
59
|
-
import type {
|
|
59
|
+
import type { WebhookSourceSubscription } from '@electric-ax/agents-runtime'
|
|
60
60
|
import type { PostgresRegistry } from './entity-registry.js'
|
|
61
61
|
import type { SchemaValidator } from './electric-agents/schema-validator.js'
|
|
62
62
|
import type { StreamClient } from './stream-client.js'
|
|
@@ -71,6 +71,7 @@ import type {
|
|
|
71
71
|
SignalRequest,
|
|
72
72
|
SignalResponse,
|
|
73
73
|
TypedSpawnRequest,
|
|
74
|
+
ExternallyWritableCollectionConfig,
|
|
74
75
|
} from './electric-agents-types.js'
|
|
75
76
|
import type { EntityBridgeCoordinator } from './entity-bridge-manager.js'
|
|
76
77
|
import type { Principal } from './principal.js'
|
|
@@ -131,6 +132,23 @@ export interface CreateAttachmentRequest {
|
|
|
131
132
|
meta?: Record<string, unknown>
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
export interface WriteCollectionPrincipal {
|
|
136
|
+
url: string
|
|
137
|
+
kind: string
|
|
138
|
+
id: string
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface WriteCollectionRequest {
|
|
142
|
+
operation: `insert` | `update` | `delete`
|
|
143
|
+
key?: string
|
|
144
|
+
value?: Record<string, unknown>
|
|
145
|
+
principal: WriteCollectionPrincipal
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface WriteCollectionResult {
|
|
149
|
+
key: string
|
|
150
|
+
}
|
|
151
|
+
|
|
134
152
|
export interface ReadAttachmentResult {
|
|
135
153
|
attachment: ManifestAttachmentEntry
|
|
136
154
|
bytes: Uint8Array
|
|
@@ -488,6 +506,7 @@ export class EntityManager {
|
|
|
488
506
|
creation_schema: req.creation_schema,
|
|
489
507
|
inbox_schemas: req.inbox_schemas,
|
|
490
508
|
state_schemas: req.state_schemas,
|
|
509
|
+
externally_writable_collections: req.externally_writable_collections,
|
|
491
510
|
slash_commands: req.slash_commands,
|
|
492
511
|
serve_endpoint: req.serve_endpoint,
|
|
493
512
|
default_dispatch_policy: defaultDispatchPolicy,
|
|
@@ -2434,6 +2453,106 @@ export class EntityManager {
|
|
|
2434
2453
|
}
|
|
2435
2454
|
}
|
|
2436
2455
|
|
|
2456
|
+
async writeCollection(
|
|
2457
|
+
entityUrl: string,
|
|
2458
|
+
collection: string,
|
|
2459
|
+
req: WriteCollectionRequest
|
|
2460
|
+
): Promise<WriteCollectionResult> {
|
|
2461
|
+
const entity = await this.registry.getEntity(entityUrl)
|
|
2462
|
+
if (!entity) {
|
|
2463
|
+
throw new ElectricAgentsError(ErrCodeNotFound, `Entity not found`, 404)
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
const { externallyWritableCollections } =
|
|
2467
|
+
await this.getEffectiveSchemas(entity)
|
|
2468
|
+
const config = externallyWritableCollections?.[collection]
|
|
2469
|
+
if (!config) {
|
|
2470
|
+
throw new ElectricAgentsError(
|
|
2471
|
+
ErrCodeUnauthorized,
|
|
2472
|
+
`Collection "${collection}" is not writable`,
|
|
2473
|
+
403
|
|
2474
|
+
)
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
const allowedOperations = config.operations ?? [`insert`]
|
|
2478
|
+
if (!allowedOperations.includes(req.operation)) {
|
|
2479
|
+
throw new ElectricAgentsError(
|
|
2480
|
+
ErrCodeUnauthorized,
|
|
2481
|
+
`Operation "${req.operation}" is not allowed on collection "${collection}"`,
|
|
2482
|
+
403
|
|
2483
|
+
)
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
if (rejectsNormalWrites(entity.status)) {
|
|
2487
|
+
throw new ElectricAgentsError(
|
|
2488
|
+
ErrCodeNotRunning,
|
|
2489
|
+
`Entity is not accepting writes`,
|
|
2490
|
+
409
|
|
2491
|
+
)
|
|
2492
|
+
}
|
|
2493
|
+
if (this.isForkWorkLockedEntity(entityUrl)) {
|
|
2494
|
+
this.assertEntityNotForkWorkLocked(entityUrl)
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
if (
|
|
2498
|
+
req.operation !== `delete` &&
|
|
2499
|
+
(req.value === undefined || req.value === null)
|
|
2500
|
+
) {
|
|
2501
|
+
throw new ElectricAgentsError(
|
|
2502
|
+
ErrCodeInvalidRequest,
|
|
2503
|
+
`value is required for ${req.operation}`,
|
|
2504
|
+
400
|
|
2505
|
+
)
|
|
2506
|
+
}
|
|
2507
|
+
if (req.operation !== `insert` && !req.key) {
|
|
2508
|
+
throw new ElectricAgentsError(
|
|
2509
|
+
ErrCodeInvalidRequest,
|
|
2510
|
+
`key is required for ${req.operation}`,
|
|
2511
|
+
400
|
|
2512
|
+
)
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
const key = req.key ?? `${collection}-${randomUUID()}`
|
|
2516
|
+
|
|
2517
|
+
const event: Record<string, unknown> = {
|
|
2518
|
+
type: config.type,
|
|
2519
|
+
key,
|
|
2520
|
+
headers: {
|
|
2521
|
+
operation: req.operation,
|
|
2522
|
+
timestamp: new Date().toISOString(),
|
|
2523
|
+
principal: req.principal,
|
|
2524
|
+
},
|
|
2525
|
+
}
|
|
2526
|
+
if (req.operation !== `delete`) {
|
|
2527
|
+
event.value = req.value
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
const validationError = await this.validateWriteEvent(entity, event)
|
|
2531
|
+
if (validationError) {
|
|
2532
|
+
throw new ElectricAgentsError(
|
|
2533
|
+
validationError.code,
|
|
2534
|
+
validationError.message,
|
|
2535
|
+
validationError.status
|
|
2536
|
+
)
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
const encoded = this.encodeChangeEvent(event)
|
|
2540
|
+
try {
|
|
2541
|
+
await this.streamClient.append(entity.streams.main, encoded)
|
|
2542
|
+
} catch (err) {
|
|
2543
|
+
if (this.isClosedStreamError(err)) {
|
|
2544
|
+
throw new ElectricAgentsError(
|
|
2545
|
+
ErrCodeNotRunning,
|
|
2546
|
+
`Entity is stopped`,
|
|
2547
|
+
409
|
|
2548
|
+
)
|
|
2549
|
+
}
|
|
2550
|
+
throw err
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
return { key }
|
|
2554
|
+
}
|
|
2555
|
+
|
|
2437
2556
|
async updateInboxMessage(
|
|
2438
2557
|
entityUrl: string,
|
|
2439
2558
|
key: string,
|
|
@@ -3023,13 +3142,13 @@ export class EntityManager {
|
|
|
3023
3142
|
return { txid }
|
|
3024
3143
|
}
|
|
3025
3144
|
|
|
3026
|
-
async
|
|
3145
|
+
async upsertWebhookSourceSubscription(
|
|
3027
3146
|
entityUrl: string,
|
|
3028
3147
|
req: {
|
|
3029
|
-
subscription:
|
|
3148
|
+
subscription: WebhookSourceSubscription
|
|
3030
3149
|
manifest: Record<string, unknown>
|
|
3031
3150
|
}
|
|
3032
|
-
): Promise<{ txid: string; subscription:
|
|
3151
|
+
): Promise<{ txid: string; subscription: WebhookSourceSubscription }> {
|
|
3033
3152
|
const manifestKey = req.subscription.manifestKey
|
|
3034
3153
|
const txid = randomUUID()
|
|
3035
3154
|
await this.writeManifestEntry(
|
|
@@ -3065,11 +3184,35 @@ export class EntityManager {
|
|
|
3065
3184
|
return { txid, subscription: req.subscription }
|
|
3066
3185
|
}
|
|
3067
3186
|
|
|
3068
|
-
async
|
|
3187
|
+
async deleteWebhookSourceSubscription(
|
|
3069
3188
|
entityUrl: string,
|
|
3070
3189
|
req: { id: string }
|
|
3071
3190
|
): Promise<{ txid: string }> {
|
|
3072
|
-
const manifestKey =
|
|
3191
|
+
const manifestKey = webhookSourceSubscriptionManifestKey(req.id)
|
|
3192
|
+
const txid = randomUUID()
|
|
3193
|
+
await this.writeManifestEntry(entityUrl, manifestKey, `delete`, undefined, {
|
|
3194
|
+
txid,
|
|
3195
|
+
})
|
|
3196
|
+
|
|
3197
|
+
await this.wakeRegistry.unregisterByManifestKey(
|
|
3198
|
+
entityUrl,
|
|
3199
|
+
manifestKey,
|
|
3200
|
+
this.tenantId
|
|
3201
|
+
)
|
|
3202
|
+
|
|
3203
|
+
return { txid }
|
|
3204
|
+
}
|
|
3205
|
+
|
|
3206
|
+
/**
|
|
3207
|
+
* Stop this entity observing a pg-sync source: drop its manifest entry and
|
|
3208
|
+
* the wake it anchors. The shared pg-sync bridge (keyed by sourceRef, not by
|
|
3209
|
+
* subscriber) is intentionally left running for any other observers.
|
|
3210
|
+
*/
|
|
3211
|
+
async deletePgSyncObservation(
|
|
3212
|
+
entityUrl: string,
|
|
3213
|
+
req: { sourceRef: string }
|
|
3214
|
+
): Promise<{ txid: string }> {
|
|
3215
|
+
const manifestKey = `source:pgSync:${req.sourceRef}`
|
|
3073
3216
|
const txid = randomUUID()
|
|
3074
3217
|
await this.writeManifestEntry(entityUrl, manifestKey, `delete`, undefined, {
|
|
3075
3218
|
txid,
|
|
@@ -3876,11 +4019,16 @@ export class EntityManager {
|
|
|
3876
4019
|
private async getEffectiveSchemas(entity: ElectricAgentsEntity): Promise<{
|
|
3877
4020
|
inboxSchemas?: Record<string, Record<string, unknown>>
|
|
3878
4021
|
stateSchemas?: Record<string, Record<string, unknown>>
|
|
4022
|
+
externallyWritableCollections?: Record<
|
|
4023
|
+
string,
|
|
4024
|
+
ExternallyWritableCollectionConfig
|
|
4025
|
+
>
|
|
3879
4026
|
}> {
|
|
3880
4027
|
if (!entity.type) {
|
|
3881
4028
|
return {
|
|
3882
4029
|
inboxSchemas: entity.inbox_schemas,
|
|
3883
4030
|
stateSchemas: entity.state_schemas,
|
|
4031
|
+
externallyWritableCollections: undefined,
|
|
3884
4032
|
}
|
|
3885
4033
|
}
|
|
3886
4034
|
|
|
@@ -3893,6 +4041,8 @@ export class EntityManager {
|
|
|
3893
4041
|
stateSchemas: latestType?.state_schemas
|
|
3894
4042
|
? { ...(entity.state_schemas ?? {}), ...latestType.state_schemas }
|
|
3895
4043
|
: entity.state_schemas,
|
|
4044
|
+
externallyWritableCollections:
|
|
4045
|
+
latestType?.externally_writable_collections,
|
|
3896
4046
|
}
|
|
3897
4047
|
}
|
|
3898
4048
|
|
package/src/entity-registry.ts
CHANGED
|
@@ -43,6 +43,7 @@ import type {
|
|
|
43
43
|
EntityTypePermission,
|
|
44
44
|
EntityTypePermissionGrant,
|
|
45
45
|
PermissionSubjectKind,
|
|
46
|
+
ExternallyWritableCollectionConfig,
|
|
46
47
|
} from './electric-agents-types.js'
|
|
47
48
|
import type { EntityTags, PgSyncOptions } from '@electric-ax/agents-runtime'
|
|
48
49
|
import type { Principal } from './principal.js'
|
|
@@ -654,6 +655,8 @@ export class PostgresRegistry {
|
|
|
654
655
|
creationSchema: et.creation_schema ?? null,
|
|
655
656
|
inboxSchemas: et.inbox_schemas ?? null,
|
|
656
657
|
stateSchemas: et.state_schemas ?? null,
|
|
658
|
+
externallyWritableCollections:
|
|
659
|
+
et.externally_writable_collections ?? null,
|
|
657
660
|
slashCommands: et.slash_commands ?? null,
|
|
658
661
|
serveEndpoint: et.serve_endpoint ?? null,
|
|
659
662
|
defaultDispatchPolicy: et.default_dispatch_policy ?? null,
|
|
@@ -668,6 +671,8 @@ export class PostgresRegistry {
|
|
|
668
671
|
creationSchema: et.creation_schema ?? null,
|
|
669
672
|
inboxSchemas: et.inbox_schemas ?? null,
|
|
670
673
|
stateSchemas: et.state_schemas ?? null,
|
|
674
|
+
externallyWritableCollections:
|
|
675
|
+
et.externally_writable_collections ?? null,
|
|
671
676
|
slashCommands: et.slash_commands ?? null,
|
|
672
677
|
serveEndpoint: et.serve_endpoint ?? null,
|
|
673
678
|
defaultDispatchPolicy: et.default_dispatch_policy ?? null,
|
|
@@ -691,6 +696,8 @@ export class PostgresRegistry {
|
|
|
691
696
|
creationSchema: et.creation_schema ?? null,
|
|
692
697
|
inboxSchemas: et.inbox_schemas ?? null,
|
|
693
698
|
stateSchemas: et.state_schemas ?? null,
|
|
699
|
+
externallyWritableCollections:
|
|
700
|
+
et.externally_writable_collections ?? null,
|
|
694
701
|
slashCommands: et.slash_commands ?? null,
|
|
695
702
|
serveEndpoint: et.serve_endpoint ?? null,
|
|
696
703
|
defaultDispatchPolicy: et.default_dispatch_policy ?? null,
|
|
@@ -733,6 +740,8 @@ export class PostgresRegistry {
|
|
|
733
740
|
creationSchema: et.creation_schema ?? null,
|
|
734
741
|
inboxSchemas: et.inbox_schemas ?? null,
|
|
735
742
|
stateSchemas: et.state_schemas ?? null,
|
|
743
|
+
externallyWritableCollections:
|
|
744
|
+
et.externally_writable_collections ?? null,
|
|
736
745
|
slashCommands: et.slash_commands ?? null,
|
|
737
746
|
serveEndpoint: et.serve_endpoint ?? null,
|
|
738
747
|
defaultDispatchPolicy: et.default_dispatch_policy ?? null,
|
|
@@ -1566,10 +1575,16 @@ export class PostgresRegistry {
|
|
|
1566
1575
|
})
|
|
1567
1576
|
.onConflictDoUpdate({
|
|
1568
1577
|
target: [pgSyncBridges.tenantId, pgSyncBridges.sourceRef],
|
|
1578
|
+
// A conflict means the sourceRef matched, i.e. the shape-identity
|
|
1579
|
+
// options are identical, so the persisted cursor and bootstrap state
|
|
1580
|
+
// are still valid. Re-registration is the common path now that the
|
|
1581
|
+
// sourceRef ignores per-request metadata; resetting
|
|
1582
|
+
// initialSnapshotComplete here would make a later restart resume from
|
|
1583
|
+
// the saved cursor while re-skipping changes until up-to-date, dropping
|
|
1584
|
+
// real changes that arrived during downtime.
|
|
1569
1585
|
set: {
|
|
1570
1586
|
options: row.options,
|
|
1571
1587
|
streamUrl: row.streamUrl,
|
|
1572
|
-
initialSnapshotComplete: false,
|
|
1573
1588
|
lastTouchedAt: new Date(),
|
|
1574
1589
|
updatedAt: new Date(),
|
|
1575
1590
|
},
|
|
@@ -1641,6 +1656,10 @@ export class PostgresRegistry {
|
|
|
1641
1656
|
.where(this.pgSyncBridgeWhere(sourceRef))
|
|
1642
1657
|
}
|
|
1643
1658
|
|
|
1659
|
+
async deletePgSyncBridge(sourceRef: string): Promise<void> {
|
|
1660
|
+
await this.db.delete(pgSyncBridges).where(this.pgSyncBridgeWhere(sourceRef))
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1644
1663
|
async upsertEntityBridge(row: {
|
|
1645
1664
|
sourceRef: string
|
|
1646
1665
|
tags: EntityTags
|
|
@@ -1957,6 +1976,11 @@ export class PostgresRegistry {
|
|
|
1957
1976
|
state_schemas: row.stateSchemas as
|
|
1958
1977
|
| Record<string, Record<string, unknown>>
|
|
1959
1978
|
| undefined,
|
|
1979
|
+
externally_writable_collections:
|
|
1980
|
+
(row.externallyWritableCollections as Record<
|
|
1981
|
+
string,
|
|
1982
|
+
ExternallyWritableCollectionConfig
|
|
1983
|
+
> | null) ?? undefined,
|
|
1960
1984
|
slash_commands:
|
|
1961
1985
|
(row.slashCommands as ElectricAgentsEntityType[`slash_commands`]) ??
|
|
1962
1986
|
undefined,
|
package/src/index.ts
CHANGED
|
@@ -65,17 +65,17 @@ export type {
|
|
|
65
65
|
AuthorizeRequest,
|
|
66
66
|
} from './electric-agents-types.js'
|
|
67
67
|
export type {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
WebhookSourceBucket,
|
|
69
|
+
WebhookSourceContract,
|
|
70
|
+
WebhookSourceFilter,
|
|
71
|
+
WebhookSourceSubscription,
|
|
72
|
+
WebhookSourceSubscriptionInput,
|
|
73
73
|
SubscriptionLifetime,
|
|
74
74
|
} from '@electric-ax/agents-runtime'
|
|
75
75
|
export type { Principal, PrincipalKind } from './principal.js'
|
|
76
76
|
export { globalRouter } from './routing/global-router.js'
|
|
77
77
|
export type { GlobalRoutes } from './routing/global-router.js'
|
|
78
|
-
export type {
|
|
78
|
+
export type { WebhookSourceCatalog, TenantContext } from './routing/context.js'
|
|
79
79
|
export {
|
|
80
80
|
streamRootDurableStreamsRoutingAdapter,
|
|
81
81
|
pathPrefixedSingleTenantDurableStreamsRoutingAdapter,
|
|
@@ -10,10 +10,6 @@ export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
10
10
|
return typeof value === `object` && value !== null && !Array.isArray(value)
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
function getPgSyncManifestStreamPath(sourceRef: string): string {
|
|
14
|
-
return `/_electric/pg-sync/${sourceRef}`
|
|
15
|
-
}
|
|
16
|
-
|
|
17
13
|
export function extractManifestSourceUrl(
|
|
18
14
|
manifest: Record<string, unknown> | undefined
|
|
19
15
|
): string | undefined {
|
|
@@ -62,8 +58,8 @@ export function extractManifestSourceUrl(
|
|
|
62
58
|
}
|
|
63
59
|
|
|
64
60
|
if (manifest.sourceType === `pgSync`) {
|
|
65
|
-
return typeof
|
|
66
|
-
?
|
|
61
|
+
return typeof config?.streamUrl === `string`
|
|
62
|
+
? config.streamUrl
|
|
67
63
|
: undefined
|
|
68
64
|
}
|
|
69
65
|
|