alink-cli 0.8.6 → 0.8.7

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/bin.mjs CHANGED
@@ -52350,6 +52350,7 @@ function isEnvelope(value) {
52350
52350
  //#endregion
52351
52351
  //#region src/tunnel/bridge.ts
52352
52352
  const TUNNEL_SCOPES = [AuthOrchestrationReadScope, AuthOrchestrationOperateScope];
52353
+ const hubFrameDecoder = new TextDecoder();
52353
52354
  const ResponseDefectEncoded = (cause) => ({
52354
52355
  _tag: "Defect",
52355
52356
  defect: cause instanceof Error ? {
@@ -52433,6 +52434,12 @@ const splitHubFrame = (text) => {
52433
52434
  rest: text.slice(spaceAt + 1)
52434
52435
  };
52435
52436
  };
52437
+ function isHttpTunnelRequestFrame(value) {
52438
+ return typeof value === "object" && value !== null && value._tag === "HttpRequest" && typeof value.id === "string" && typeof value.method === "string" && typeof value.path === "string" && Array.isArray(value.headers) && (value.body === null || typeof value.body === "string");
52439
+ }
52440
+ function encodeHttpTunnelResponseFrame(frame) {
52441
+ return JSON.stringify(frame);
52442
+ }
52436
52443
  const makeTunnelSocket = (input) => {
52437
52444
  const runRaw = (handler, options) => scopedWith((scope) => gen(function* () {
52438
52445
  const fiberSet = yield* make$62().pipe(provide$2(scope));
@@ -52478,7 +52485,7 @@ const runHubTunnel = (config) => gen(function* () {
52478
52485
  const writeRaw = yield* socket.writer;
52479
52486
  yield* forever(take$1(outbox).pipe(flatMap$1(writeRaw)));
52480
52487
  }));
52481
- const attachTunnel = (tunnelId, live) => gen(function* () {
52488
+ const attachRpcTunnel = (tunnelId, live) => gen(function* () {
52482
52489
  yield* addFinalizer(() => sync(() => {
52483
52490
  if (tunnels.get(tunnelId) !== live) return;
52484
52491
  tunnels.delete(tunnelId);
@@ -52515,14 +52522,121 @@ const runHubTunnel = (config) => gen(function* () {
52515
52522
  type: "tunnel_open",
52516
52523
  tunnelId
52517
52524
  }))) dropTunnel(tunnelId);
52518
- yield* logInfo("hub tunnel: attached", { tunnelId });
52525
+ yield* logInfo("hub tunnel: attached", {
52526
+ tunnelId,
52527
+ purpose: live.purpose
52528
+ });
52519
52529
  yield* _await(live.closed);
52520
52530
  }).pipe(catch_((error) => logWarning$1("hub tunnel: attach failed", {
52521
52531
  tunnelId,
52522
52532
  error
52523
52533
  })));
52524
- yield* socket.runRaw((data) => {
52525
- if (typeof data !== "string") return;
52534
+ const attachHttpTunnel = (tunnelId, live) => gen(function* () {
52535
+ yield* addFinalizer(() => sync(() => {
52536
+ if (tunnels.get(tunnelId) !== live) return;
52537
+ tunnels.delete(tunnelId);
52538
+ writeHub(JSON.stringify({
52539
+ type: "tunnel_close",
52540
+ tunnelId,
52541
+ code: 1011,
52542
+ reason: "daemon http tunnel ended"
52543
+ }));
52544
+ }));
52545
+ const issued = yield* serverAuth.issueSession({
52546
+ subject: "hub-tunnel-http",
52547
+ label: "AgentLink hub tunnel HTTP proxy",
52548
+ scopes: [...TUNNEL_SCOPES]
52549
+ });
52550
+ yield* addFinalizer(() => sessionsStore.markDisconnected(issued.sessionId).pipe(andThen(serverAuth.revokeSession(issued.sessionId)), ignore$1));
52551
+ yield* sessionsStore.markConnected(issued.sessionId);
52552
+ const serverConfig = yield* ServerConfig;
52553
+ const httpClient = yield* HttpClient;
52554
+ const localBaseUrl = `http://127.0.0.1:${serverConfig.port}`;
52555
+ const sendEncrypted = (frame) => {
52556
+ try {
52557
+ const envelope = utf8ToEnvelope(config.enckey, encodeHttpTunnelResponseFrame(frame));
52558
+ if (!writeHub(`${tunnelId} ${JSON.stringify(envelope)}`)) dropTunnel(tunnelId);
52559
+ } catch {
52560
+ dropTunnel(tunnelId);
52561
+ }
52562
+ };
52563
+ live.onDecryptedFrame = (frame) => {
52564
+ let requestFrame;
52565
+ try {
52566
+ const parsed = JSON.parse(frame);
52567
+ if (!isHttpTunnelRequestFrame(parsed)) {
52568
+ sendEncrypted({
52569
+ _tag: "HttpResponse",
52570
+ id: typeof parsed?.id === "string" ? parsed.id : "unknown",
52571
+ status: 400,
52572
+ statusText: "Bad Request",
52573
+ headers: [["content-type", "text/plain"]],
52574
+ body: Buffer.from("Invalid HTTP tunnel request frame").toString("base64")
52575
+ });
52576
+ return;
52577
+ }
52578
+ requestFrame = parsed;
52579
+ } catch {
52580
+ sendEncrypted({
52581
+ _tag: "HttpResponse",
52582
+ id: "unknown",
52583
+ status: 400,
52584
+ statusText: "Bad Request",
52585
+ headers: [["content-type", "text/plain"]],
52586
+ body: Buffer.from("Malformed HTTP tunnel request frame").toString("base64")
52587
+ });
52588
+ return;
52589
+ }
52590
+ runFork(gen(function* () {
52591
+ const targetUrl = `${localBaseUrl}${requestFrame.path}`;
52592
+ const headers = { authorization: `Bearer ${issued.token}` };
52593
+ for (const [key, value] of requestFrame.headers) {
52594
+ const lower = key.toLowerCase();
52595
+ if (lower === "authorization" || lower === "cookie") continue;
52596
+ headers[lower] = value;
52597
+ }
52598
+ let request = make$61(requestFrame.method)(targetUrl).pipe(setHeaders(headers));
52599
+ if (requestFrame.body !== null) request = setBody(uint8Array(Buffer.from(requestFrame.body, "base64")))(request);
52600
+ const response = yield* httpClient.execute(request);
52601
+ const responseBody = yield* response.arrayBuffer;
52602
+ const responseHeaders = [];
52603
+ for (const [key, value] of Object.entries(response.headers)) if (typeof value === "string") responseHeaders.push([key, value]);
52604
+ return {
52605
+ _tag: "HttpResponse",
52606
+ id: requestFrame.id,
52607
+ status: response.status,
52608
+ statusText: "",
52609
+ headers: responseHeaders,
52610
+ body: Buffer.from(responseBody).toString("base64")
52611
+ };
52612
+ }).pipe(match$2({
52613
+ onFailure: (cause) => ({
52614
+ _tag: "HttpResponse",
52615
+ id: requestFrame.id,
52616
+ status: 502,
52617
+ statusText: "Bad Gateway",
52618
+ headers: [["content-type", "text/plain"]],
52619
+ body: Buffer.from(cause instanceof Error ? cause.message : String(cause)).toString("base64")
52620
+ }),
52621
+ onSuccess: (response) => response
52622
+ }), tap((frame) => sync(() => sendEncrypted(frame)))));
52623
+ };
52624
+ if (!writeHub(JSON.stringify({
52625
+ type: "tunnel_open",
52626
+ tunnelId
52627
+ }))) dropTunnel(tunnelId);
52628
+ yield* logInfo("hub tunnel: attached", {
52629
+ tunnelId,
52630
+ purpose: live.purpose
52631
+ });
52632
+ yield* _await(live.closed);
52633
+ }).pipe(catch_((error) => logWarning$1("hub tunnel: attach failed", {
52634
+ tunnelId,
52635
+ error
52636
+ })));
52637
+ yield* socket.runRaw((rawData) => {
52638
+ const data = typeof rawData === "string" ? rawData : rawData instanceof Uint8Array ? hubFrameDecoder.decode(rawData) : null;
52639
+ if (data === null) return;
52526
52640
  if (data.startsWith("{")) {
52527
52641
  let control;
52528
52642
  try {
@@ -52534,13 +52648,16 @@ const runHubTunnel = (config) => gen(function* () {
52534
52648
  const tunnelId = control.tunnelId;
52535
52649
  if (tunnels.has(tunnelId)) return;
52536
52650
  return gen(function* () {
52651
+ const closed = yield* make$70();
52652
+ const purpose = control.purpose === "http" ? "http" : "rpc";
52537
52653
  const live = {
52538
- closed: yield* make$70(),
52654
+ closed,
52539
52655
  pendingFrames: [],
52656
+ purpose,
52540
52657
  onDecryptedFrame: null
52541
52658
  };
52542
52659
  tunnels.set(tunnelId, live);
52543
- yield* forkScoped(scoped(attachTunnel(tunnelId, live)));
52660
+ yield* forkScoped(scoped((purpose === "http" ? attachHttpTunnel : attachRpcTunnel)(tunnelId, live)));
52544
52661
  });
52545
52662
  }
52546
52663
  if (control.type === "tunnel_close" && typeof control.tunnelId === "string") dropTunnel(control.tunnelId);