@electric-ax/agents-server 0.4.0 → 0.4.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 +379 -94
- package/dist/index.cjs +489 -196
- package/dist/index.d.cts +286 -244
- package/dist/index.d.ts +286 -244
- package/dist/index.js +489 -196
- package/drizzle/0006_principals.sql +5 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +6 -6
- package/src/authenticated-user-format.ts +4 -14
- package/src/db/schema.ts +2 -0
- package/src/electric-agents-types.ts +10 -7
- package/src/entity-bridge-manager.ts +1 -1
- package/src/entity-manager.ts +223 -41
- package/src/entity-registry.ts +29 -0
- package/src/entrypoint-lib.ts +0 -9
- package/src/host.ts +4 -0
- package/src/index.ts +2 -1
- package/src/principal.ts +124 -0
- package/src/routing/context.ts +2 -2
- package/src/routing/dispatch-policy.ts +10 -10
- package/src/routing/entities-router.ts +179 -6
- package/src/routing/hooks.ts +1 -1
- package/src/routing/runners-router.ts +10 -18
- package/src/runtime.ts +4 -1
- package/src/scheduler.ts +2 -0
- package/src/server.ts +59 -7
- package/src/dev-asserted-auth.ts +0 -46
package/src/runtime.ts
CHANGED
|
@@ -435,6 +435,8 @@ export class ElectricAgentsTenantRuntime {
|
|
|
435
435
|
const fireAtRaw = value.fireAt
|
|
436
436
|
const producerId = value.producerId
|
|
437
437
|
const targetUrl = value.targetUrl
|
|
438
|
+
const senderUrl =
|
|
439
|
+
typeof value.senderUrl === `string` ? value.senderUrl : ownerEntityUrl
|
|
438
440
|
if (
|
|
439
441
|
typeof fireAtRaw !== `string` ||
|
|
440
442
|
typeof producerId !== `string` ||
|
|
@@ -459,7 +461,7 @@ export class ElectricAgentsTenantRuntime {
|
|
|
459
461
|
manifestKey,
|
|
460
462
|
{
|
|
461
463
|
entityUrl: targetUrl,
|
|
462
|
-
from:
|
|
464
|
+
from: senderUrl,
|
|
463
465
|
payload: value.payload,
|
|
464
466
|
key: `scheduled-${producerId}`,
|
|
465
467
|
type:
|
|
@@ -474,6 +476,7 @@ export class ElectricAgentsTenantRuntime {
|
|
|
474
476
|
kind: `schedule`,
|
|
475
477
|
scheduleType: `future_send`,
|
|
476
478
|
targetUrl,
|
|
479
|
+
senderUrl,
|
|
477
480
|
fireAt: fireAt.toISOString(),
|
|
478
481
|
producerId,
|
|
479
482
|
status: `pending`,
|
package/src/scheduler.ts
CHANGED
package/src/server.ts
CHANGED
|
@@ -12,6 +12,13 @@ import { ossServerRouter } from './routing/oss-server-router.js'
|
|
|
12
12
|
import { startStandaloneAgentsRuntime } from './standalone-runtime.js'
|
|
13
13
|
import { StreamClient, durableStreamsServiceUrl } from './stream-client.js'
|
|
14
14
|
import { DEFAULT_TENANT_ID } from './tenant.js'
|
|
15
|
+
import { getDevPrincipal, getPrincipalFromRequest } from './principal.js'
|
|
16
|
+
import { apiError } from './electric-agents-http.js'
|
|
17
|
+
import {
|
|
18
|
+
ErrCodeInvalidRequest,
|
|
19
|
+
ErrCodeUnauthorized,
|
|
20
|
+
} from './electric-agents-types.js'
|
|
21
|
+
import { ElectricAgentsError } from './entity-manager.js'
|
|
15
22
|
import { serverLog } from './utils/log.js'
|
|
16
23
|
import type { DrizzleDB, PgClient } from './db/index.js'
|
|
17
24
|
import type { Server } from 'node:http'
|
|
@@ -22,7 +29,7 @@ import type {
|
|
|
22
29
|
EntityRegistry,
|
|
23
30
|
RuntimeHandler,
|
|
24
31
|
} from '@electric-ax/agents-runtime'
|
|
25
|
-
import type {
|
|
32
|
+
import type { Principal } from './principal.js'
|
|
26
33
|
import type { EntityBridgeCoordinator } from './entity-bridge-manager.js'
|
|
27
34
|
import type { DurableStreamsRoutingAdapter } from './routing/durable-streams-routing-adapter.js'
|
|
28
35
|
import type { OssServerContext } from './routing/oss-server-router.js'
|
|
@@ -46,7 +53,10 @@ export interface ElectricAgentsServerOptions {
|
|
|
46
53
|
postgresUrl: string
|
|
47
54
|
electricUrl?: string
|
|
48
55
|
electricSecret?: string
|
|
49
|
-
authenticateRequest?:
|
|
56
|
+
authenticateRequest?: (
|
|
57
|
+
request: Request
|
|
58
|
+
) => Promise<Principal | null> | Principal | null
|
|
59
|
+
allowDevPrincipalFallback?: boolean
|
|
50
60
|
/**
|
|
51
61
|
* Disabled by default. When set to a positive interval, periodically
|
|
52
62
|
* recovers expired dispatch claims and stale outstanding wakes.
|
|
@@ -207,6 +217,7 @@ export class ElectricAgentsServer {
|
|
|
207
217
|
})
|
|
208
218
|
this.electricAgentsManager = this.standaloneRuntime.manager
|
|
209
219
|
this.entityBridgeManager = this.standaloneRuntime.entityBridgeManager
|
|
220
|
+
await this.electricAgentsManager.ensurePrincipalEntityType()
|
|
210
221
|
|
|
211
222
|
const serverAdapter = createServerAdapter((request) =>
|
|
212
223
|
this.handleRequest(request)
|
|
@@ -323,9 +334,27 @@ export class ElectricAgentsServer {
|
|
|
323
334
|
return new Response(null, { status: 503 })
|
|
324
335
|
}
|
|
325
336
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
337
|
+
try {
|
|
338
|
+
return await ossServerRouter.fetch(
|
|
339
|
+
request as Parameters<typeof ossServerRouter.fetch>[0],
|
|
340
|
+
await this.buildTenantContext(request)
|
|
341
|
+
)
|
|
342
|
+
} catch (error) {
|
|
343
|
+
if (error instanceof ElectricAgentsError) {
|
|
344
|
+
return apiError(error.status, error.code, error.message, error.details)
|
|
345
|
+
}
|
|
346
|
+
throw error
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
private allowDevPrincipalFallback(): boolean {
|
|
351
|
+
if (this.options.allowDevPrincipalFallback !== undefined) {
|
|
352
|
+
return this.options.allowDevPrincipalFallback
|
|
353
|
+
}
|
|
354
|
+
return (
|
|
355
|
+
process.env.ELECTRIC_INSECURE === `true` ||
|
|
356
|
+
process.env.NODE_ENV !== `production` ||
|
|
357
|
+
Boolean(this.options.durableStreamsServer)
|
|
329
358
|
)
|
|
330
359
|
}
|
|
331
360
|
|
|
@@ -343,10 +372,33 @@ export class ElectricAgentsServer {
|
|
|
343
372
|
throw new Error(`agents-server runtime is not started`)
|
|
344
373
|
}
|
|
345
374
|
|
|
375
|
+
let principal: Principal | null
|
|
376
|
+
try {
|
|
377
|
+
principal =
|
|
378
|
+
(await this.options.authenticateRequest?.(request)) ??
|
|
379
|
+
getPrincipalFromRequest(request)
|
|
380
|
+
} catch (error) {
|
|
381
|
+
throw new ElectricAgentsError(
|
|
382
|
+
ErrCodeInvalidRequest,
|
|
383
|
+
error instanceof Error ? error.message : `Invalid principal`,
|
|
384
|
+
400
|
|
385
|
+
)
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (!principal && this.allowDevPrincipalFallback()) {
|
|
389
|
+
principal = getDevPrincipal()
|
|
390
|
+
}
|
|
391
|
+
if (!principal) {
|
|
392
|
+
throw new ElectricAgentsError(
|
|
393
|
+
ErrCodeUnauthorized,
|
|
394
|
+
`Missing Electric-Principal`,
|
|
395
|
+
401
|
|
396
|
+
)
|
|
397
|
+
}
|
|
398
|
+
|
|
346
399
|
return {
|
|
347
400
|
service: this.tenantId,
|
|
348
|
-
|
|
349
|
-
(await this.options.authenticateRequest?.(request)) ?? undefined,
|
|
401
|
+
principal,
|
|
350
402
|
publicUrl: this.publicUrl,
|
|
351
403
|
localUrl: this._url,
|
|
352
404
|
durableStreamsUrl: this.options.durableStreamsUrl,
|
package/src/dev-asserted-auth.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AuthenticateRequest,
|
|
3
|
-
AuthenticatedRequestUser,
|
|
4
|
-
} from './electric-agents-types.js'
|
|
5
|
-
|
|
6
|
-
export interface DevAssertedAuthOptions {
|
|
7
|
-
enabled?: boolean
|
|
8
|
-
defaultEmail?: string
|
|
9
|
-
defaultName?: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const DEV_ASSERTED_EMAIL_HEADER = `x-electric-asserted-email`
|
|
13
|
-
export const DEV_ASSERTED_NAME_HEADER = `x-electric-asserted-name`
|
|
14
|
-
|
|
15
|
-
function clean(value: string | undefined | null): string | undefined {
|
|
16
|
-
const trimmed = value?.trim()
|
|
17
|
-
return trimmed || undefined
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function createDevAssertedAuthenticateRequest(
|
|
21
|
-
options: DevAssertedAuthOptions
|
|
22
|
-
): AuthenticateRequest | undefined {
|
|
23
|
-
if (!options.enabled) return undefined
|
|
24
|
-
|
|
25
|
-
return (request): AuthenticatedRequestUser | null => {
|
|
26
|
-
const email =
|
|
27
|
-
clean(request.headers.get(DEV_ASSERTED_EMAIL_HEADER)) ??
|
|
28
|
-
clean(options.defaultEmail)
|
|
29
|
-
const name =
|
|
30
|
-
clean(request.headers.get(DEV_ASSERTED_NAME_HEADER)) ??
|
|
31
|
-
clean(options.defaultName)
|
|
32
|
-
const userId = email ?? name
|
|
33
|
-
if (!userId) return null
|
|
34
|
-
return { userId, email, name }
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function devAssertedAuthOptionsFromEnv(
|
|
39
|
-
env: Record<string, string | undefined> = process.env
|
|
40
|
-
): DevAssertedAuthOptions {
|
|
41
|
-
return {
|
|
42
|
-
enabled: env.ELECTRIC_AGENTS_DEV_ASSERTED_AUTH === `1`,
|
|
43
|
-
defaultEmail: env.ELECTRIC_ASSERTED_AUTH_EMAIL,
|
|
44
|
-
defaultName: env.ELECTRIC_ASSERTED_AUTH_NAME,
|
|
45
|
-
}
|
|
46
|
-
}
|