@electric-ax/agents-server 0.4.2 → 0.4.3
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 +178 -157
- package/dist/index.cjs +161 -136
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +159 -136
- package/package.json +5 -5
- package/src/index.ts +5 -1
- package/src/routing/context.ts +1 -0
- package/src/routing/durable-streams-router.ts +286 -116
- package/src/routing/durable-streams-routing-adapter.ts +26 -58
- package/src/routing/entities-router.ts +1 -1
- package/src/routing/internal-router.ts +6 -2
- package/src/routing/runners-router.ts +1 -0
- package/src/runtime.ts +3 -1
- package/src/server.ts +8 -7
- package/src/standalone-runtime.ts +3 -1
- package/src/stream-client.ts +24 -32
- package/src/utils/server-utils.ts +5 -4
package/src/server.ts
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
createRuntimeHandler,
|
|
8
8
|
} from '@electric-ax/agents-runtime'
|
|
9
9
|
import { createDb, runMigrations } from './db/index.js'
|
|
10
|
-
import { pathPrefixedSingleTenantDurableStreamsRoutingAdapter } from './routing/durable-streams-routing-adapter.js'
|
|
11
10
|
import { ossServerRouter } from './routing/oss-server-router.js'
|
|
12
11
|
import { startStandaloneAgentsRuntime } from './standalone-runtime.js'
|
|
13
12
|
import { StreamClient, durableStreamsServiceUrl } from './stream-client.js'
|
|
@@ -145,7 +144,9 @@ export class ElectricAgentsServer {
|
|
|
145
144
|
this.options = options
|
|
146
145
|
this.streamClient = options.durableStreamsUrl
|
|
147
146
|
? new StreamClient(
|
|
148
|
-
durableStreamsServiceUrl(options.durableStreamsUrl, this.tenantId
|
|
147
|
+
durableStreamsServiceUrl(options.durableStreamsUrl, this.tenantId, {
|
|
148
|
+
scope: `stream-root`,
|
|
149
|
+
}),
|
|
149
150
|
{ bearer: options.durableStreamsBearer }
|
|
150
151
|
)
|
|
151
152
|
: null!
|
|
@@ -186,7 +187,9 @@ export class ElectricAgentsServer {
|
|
|
186
187
|
)
|
|
187
188
|
this.options.durableStreamsUrl = streamsUrl
|
|
188
189
|
this.streamClient = new StreamClient(
|
|
189
|
-
durableStreamsServiceUrl(streamsUrl, this.tenantId
|
|
190
|
+
durableStreamsServiceUrl(streamsUrl, this.tenantId, {
|
|
191
|
+
scope: `stream-root`,
|
|
192
|
+
}),
|
|
190
193
|
{ bearer: this.options.durableStreamsBearer }
|
|
191
194
|
)
|
|
192
195
|
}
|
|
@@ -401,11 +404,9 @@ export class ElectricAgentsServer {
|
|
|
401
404
|
principal,
|
|
402
405
|
publicUrl: this.publicUrl,
|
|
403
406
|
localUrl: this._url,
|
|
404
|
-
durableStreamsUrl: this.
|
|
407
|
+
durableStreamsUrl: this.streamClient.baseUrl,
|
|
405
408
|
durableStreamsBearer: this.options.durableStreamsBearer,
|
|
406
|
-
durableStreamsRouting:
|
|
407
|
-
this.options.durableStreamsRouting ??
|
|
408
|
-
pathPrefixedSingleTenantDurableStreamsRoutingAdapter,
|
|
409
|
+
durableStreamsRouting: this.options.durableStreamsRouting,
|
|
409
410
|
durableStreamsDispatcher: this.streamsAgent,
|
|
410
411
|
electricUrl: this.options.electricUrl,
|
|
411
412
|
electricSecret: this.options.electricSecret,
|
|
@@ -58,7 +58,9 @@ export async function startStandaloneAgentsRuntime(
|
|
|
58
58
|
options.streamClient ??
|
|
59
59
|
(options.durableStreamsUrl
|
|
60
60
|
? new StreamClient(
|
|
61
|
-
durableStreamsServiceUrl(options.durableStreamsUrl, serviceId
|
|
61
|
+
durableStreamsServiceUrl(options.durableStreamsUrl, serviceId, {
|
|
62
|
+
scope: `stream-root`,
|
|
63
|
+
}),
|
|
62
64
|
{ bearer: options.durableStreamsBearer }
|
|
63
65
|
)
|
|
64
66
|
: undefined)
|
package/src/stream-client.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface StreamClientOptions {
|
|
|
14
14
|
bearer?: DurableStreamsBearerProvider
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
type DurableStreamsUrlScope = `service` | `stream-root`
|
|
18
|
+
|
|
17
19
|
export interface StreamAppendResult {
|
|
18
20
|
offset: string
|
|
19
21
|
}
|
|
@@ -141,14 +143,29 @@ function durableStreamsBearerHeaders(
|
|
|
141
143
|
|
|
142
144
|
export function durableStreamsServiceUrl(
|
|
143
145
|
baseUrl: string,
|
|
144
|
-
serviceId: string
|
|
146
|
+
serviceId: string,
|
|
147
|
+
options: { scope?: DurableStreamsUrlScope } = {}
|
|
145
148
|
): string {
|
|
146
149
|
const url = new URL(baseUrl)
|
|
147
|
-
if (
|
|
150
|
+
if (/\/v1\/streams\/[^/]+\/?$/.test(url.pathname)) {
|
|
151
|
+
return baseUrl.replace(/\/+$/, ``)
|
|
152
|
+
}
|
|
153
|
+
if (/\/v1\/stream\/[^/]+\/?$/.test(url.pathname)) {
|
|
148
154
|
return baseUrl.replace(/\/+$/, ``)
|
|
149
155
|
}
|
|
150
|
-
const
|
|
151
|
-
|
|
156
|
+
const scope = options.scope ?? `service`
|
|
157
|
+
const encodedServiceId = encodeURIComponent(serviceId)
|
|
158
|
+
const path = url.pathname.replace(/\/+$/, ``) || `/`
|
|
159
|
+
if (path.endsWith(`/v1/streams`)) {
|
|
160
|
+
url.pathname = `${path}/${encodedServiceId}`
|
|
161
|
+
} else if (path.endsWith(`/v1/stream`)) {
|
|
162
|
+
url.pathname = scope === `service` ? `${path}/${encodedServiceId}` : path
|
|
163
|
+
} else if (scope === `stream-root`) {
|
|
164
|
+
url.pathname = `${path === `/` ? `` : path}/v1/stream`
|
|
165
|
+
} else {
|
|
166
|
+
url.pathname = `${path === `/` ? `` : path}/v1/stream/${encodedServiceId}`
|
|
167
|
+
}
|
|
168
|
+
return url.toString().replace(/\/+$/, ``)
|
|
152
169
|
}
|
|
153
170
|
|
|
154
171
|
function isNotFoundError(err: unknown): boolean {
|
|
@@ -202,42 +219,17 @@ export class StreamClient {
|
|
|
202
219
|
return headers
|
|
203
220
|
}
|
|
204
221
|
|
|
205
|
-
private subscriptionServiceId(): string | null {
|
|
206
|
-
const url = new URL(this.baseUrl)
|
|
207
|
-
const match = /^(.*)\/v1\/stream\/([^/]+)\/?$/.exec(url.pathname)
|
|
208
|
-
return match ? decodeURIComponent(match[2]!) : null
|
|
209
|
-
}
|
|
210
|
-
|
|
211
222
|
private backendSubscriptionPath(path: string): string {
|
|
212
|
-
|
|
213
|
-
const serviceId = this.subscriptionServiceId()
|
|
214
|
-
if (!serviceId) return normalized
|
|
215
|
-
if (normalized === serviceId || normalized.startsWith(`${serviceId}/`)) {
|
|
216
|
-
return normalized
|
|
217
|
-
}
|
|
218
|
-
return `${serviceId}/${normalized}`
|
|
223
|
+
return normalizeSubscriptionPath(path)
|
|
219
224
|
}
|
|
220
225
|
|
|
221
226
|
private runtimeSubscriptionPath(path: string): string {
|
|
222
|
-
|
|
223
|
-
const serviceId = this.subscriptionServiceId()
|
|
224
|
-
if (!serviceId) return normalized
|
|
225
|
-
return normalized.startsWith(`${serviceId}/`)
|
|
226
|
-
? normalized.slice(serviceId.length + 1)
|
|
227
|
-
: normalized
|
|
227
|
+
return normalizeSubscriptionPath(path)
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
private subscriptionUrl(subscriptionId: string): string {
|
|
231
231
|
const url = new URL(this.baseUrl)
|
|
232
|
-
|
|
233
|
-
if (match) {
|
|
234
|
-
const [, prefix = ``, serviceId] = match
|
|
235
|
-
url.pathname = `${prefix}/v1/stream-meta/subscriptions/${encodeURIComponent(subscriptionId)}`
|
|
236
|
-
url.searchParams.set(`service`, decodeURIComponent(serviceId!))
|
|
237
|
-
return url.toString()
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
url.pathname = `${url.pathname.replace(/\/+$/, ``)}/v1/stream-meta/subscriptions/${encodeURIComponent(subscriptionId)}`
|
|
232
|
+
url.pathname = `${url.pathname.replace(/\/+$/, ``)}/__ds/subscriptions/${encodeURIComponent(subscriptionId)}`
|
|
241
233
|
return url.toString()
|
|
242
234
|
}
|
|
243
235
|
|
|
@@ -167,12 +167,13 @@ export async function forwardFetchRequest(options: {
|
|
|
167
167
|
serviceId: string
|
|
168
168
|
body?: Uint8Array
|
|
169
169
|
dispatcher?: Agent
|
|
170
|
-
route?: `stream` | `
|
|
170
|
+
route?: `stream` | `control`
|
|
171
171
|
durableStreamsBearer?: DurableStreamsBearerProvider
|
|
172
172
|
durableStreamsBearerMode?: `overwrite` | `if-missing` | `none`
|
|
173
173
|
}): Promise<Response> {
|
|
174
174
|
const routingAdapter = resolveDurableStreamsRoutingAdapter(
|
|
175
|
-
options.durableStreamsRouting
|
|
175
|
+
options.durableStreamsRouting,
|
|
176
|
+
options.durableStreamsUrl
|
|
176
177
|
)
|
|
177
178
|
const routingInput = {
|
|
178
179
|
durableStreamsUrl: options.durableStreamsUrl,
|
|
@@ -180,8 +181,8 @@ export async function forwardFetchRequest(options: {
|
|
|
180
181
|
requestUrl: options.request.url,
|
|
181
182
|
}
|
|
182
183
|
const upstreamUrl =
|
|
183
|
-
options.route === `
|
|
184
|
-
? routingAdapter.
|
|
184
|
+
options.route === `control`
|
|
185
|
+
? routingAdapter.controlUrl(routingInput)
|
|
185
186
|
: routingAdapter.streamUrl(routingInput)
|
|
186
187
|
|
|
187
188
|
const headers = new Headers(options.request.headers)
|