t3code-cli 0.1.3 → 0.2.0
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.js +2 -2
- package/dist/index.js +1 -1
- package/dist/{runtime-0wuYCEoH.js → runtime-CMPZpQaG.js} +35 -31
- package/package.json +1 -1
- package/src/auth/error.ts +5 -1
- package/src/auth/pairing.ts +6 -2
- package/src/auth/transport.ts +21 -10
- package/src/config/url.ts +46 -2
- package/src/rpc/layer.ts +2 -2
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as fromIterable, $n as isNotNull, $t as scoped, A as Crypto, An as map$3, At as catchTags, B as make$8, Bn as getOrElse, Bt as ignore, C as decodeUnknownEffect, Cn as doneUnsafe, Ct as acquireRelease, D as optionalKey, Dn as succeed$1, Dt as asVoid, E as optional$3, En as isSuccess, Et as as, F as make$7, Fn as empty$1, Ft as fn, G as FileSystem, Gn as match, Gt as mapError, H as Path$1, Hn as isNone, Ht as isEffect, I as parseFdName, In as make$13, It as fnUntraced, J as WatchBackend, Jn as Prototype, Jt as provide$1, K as FileTypeId, Kn as none, Kt as matchEffect, L as ChildProcessSpawner, Ln as flatMap$1, Lt as forEach, M as fromReadable, Mn as succeed$3, Mt as effectify, N as fromWritable, Nn as Reference, Nt as fail, O as tag, On as ConsoleRef, Ot as callback, P as fdName, Pn as Service, Pt as flatMap, Q as empty, Qn as hasProperty, Qt as runFork, R as ExitCode, Rn as fromNullishOr, Rt as forkScoped, S as decodeTo, Sn as _await, St as transform$1, T as is, Tn as makeUnsafe, Tt as andThen, U as TypeId$6, Un as isSome, Ut as logError, V as makeHandle, Vn as getOrUndefined, Vt as interrupt, W as FileDescriptor, Wn as map$4, Wt as map$2, X as callback$1, Xn as withFiber, Xt as provideService, Y as make$10, Yn as PipeInspectableProto, Yt as provideContext, Z as decodeText, Zn as format, Zt as result, _ as Literals, _n as provide, _t as offer, a as latestAssistantMessage, an as tapError, ar as identity, at as runLast, b as TaggedErrorClass, bn as sync$2, bt as badArgument, c as Environment, cn as try_, cr as __commonJSMin, ct as transduce, d as ArraySchema, dn as TaggedError, dt as make$11, en as serviceOption, er as isNotUndefined, et as isStream, f as Boolean$2, fn as fail$1, ft as drain, g as Literal, gn as mergeAll, gt as make$12, h as Int, hn as effect, ht as failCauseUnsafe, i as ThreadSessionError, in as tapCause, ir as dual, it as runFold, j as make$9, jn as fail$2, jt as catch_, k as toCodecStringTree, kn as sync$1, kt as catchFilter, l as T3Config, ln as uninterruptible, lr as __require, lt as unwrap, m as ErrorClass, mn as squash, mt as endUnsafe, nn as suspend, nr as isUndefined, nt as run$1, o as threadStatus, on as timeoutOrElse, or as pipe, ot as succeed$4, p as Defect, pn as hasInterruptsOnly, pt as isSink, q as Size, qn as some, qt as orDie, r as NodeEnvironmentLive, rn as sync, rr as constVoid, rt as runDrain, s as T3Application, sn as tryPromise, sr as pipeArguments, st as tap, t as AppLayer, tn as succeed, tr as isNullish, tt as merge, u as T3Auth, un as void_, ut as get, v as String$1, vn as provideMerge, vt as offerUnsafe, w as fromJsonString, wn as isDone, wt as addFinalizer, x as Union, xn as MinimumLogLevel, xt as systemError, y as Struct, yn as succeed$2, yt as BadArgument, z as ProcessId, zn as fromUndefinedOr, zt as gen } from "./runtime-
|
|
2
|
+
import { $ as fromIterable, $n as isNotNull, $t as scoped, A as Crypto, An as map$3, At as catchTags, B as make$8, Bn as getOrElse, Bt as ignore, C as decodeUnknownEffect, Cn as doneUnsafe, Ct as acquireRelease, D as optionalKey, Dn as succeed$1, Dt as asVoid, E as optional$3, En as isSuccess, Et as as, F as make$7, Fn as empty$1, Ft as fn, G as FileSystem, Gn as match, Gt as mapError, H as Path$1, Hn as isNone, Ht as isEffect, I as parseFdName, In as make$13, It as fnUntraced, J as WatchBackend, Jn as Prototype, Jt as provide$1, K as FileTypeId, Kn as none, Kt as matchEffect, L as ChildProcessSpawner, Ln as flatMap$1, Lt as forEach, M as fromReadable, Mn as succeed$3, Mt as effectify, N as fromWritable, Nn as Reference, Nt as fail, O as tag, On as ConsoleRef, Ot as callback, P as fdName, Pn as Service, Pt as flatMap, Q as empty, Qn as hasProperty, Qt as runFork, R as ExitCode, Rn as fromNullishOr, Rt as forkScoped, S as decodeTo, Sn as _await, St as transform$1, T as is, Tn as makeUnsafe, Tt as andThen, U as TypeId$6, Un as isSome, Ut as logError, V as makeHandle, Vn as getOrUndefined, Vt as interrupt, W as FileDescriptor, Wn as map$4, Wt as map$2, X as callback$1, Xn as withFiber, Xt as provideService, Y as make$10, Yn as PipeInspectableProto, Yt as provideContext, Z as decodeText, Zn as format, Zt as result, _ as Literals, _n as provide, _t as offer, a as latestAssistantMessage, an as tapError, ar as identity, at as runLast, b as TaggedErrorClass, bn as sync$2, bt as badArgument, c as Environment, cn as try_, cr as __commonJSMin, ct as transduce, d as ArraySchema, dn as TaggedError, dt as make$11, en as serviceOption, er as isNotUndefined, et as isStream, f as Boolean$2, fn as fail$1, ft as drain, g as Literal, gn as mergeAll, gt as make$12, h as Int, hn as effect, ht as failCauseUnsafe, i as ThreadSessionError, in as tapCause, ir as dual, it as runFold, j as make$9, jn as fail$2, jt as catch_, k as toCodecStringTree, kn as sync$1, kt as catchFilter, l as T3Config, ln as uninterruptible, lr as __require, lt as unwrap, m as ErrorClass, mn as squash, mt as endUnsafe, nn as suspend, nr as isUndefined, nt as run$1, o as threadStatus, on as timeoutOrElse, or as pipe, ot as succeed$4, p as Defect, pn as hasInterruptsOnly, pt as isSink, q as Size, qn as some, qt as orDie, r as NodeEnvironmentLive, rn as sync, rr as constVoid, rt as runDrain, s as T3Application, sn as tryPromise, sr as pipeArguments, st as tap, t as AppLayer, tn as succeed, tr as isNullish, tt as merge, u as T3Auth, un as void_, ut as get, v as String$1, vn as provideMerge, vt as offerUnsafe, w as fromJsonString, wn as isDone, wt as addFinalizer, x as Union, xn as MinimumLogLevel, xt as systemError, y as Struct, yn as succeed$2, yt as BadArgument, z as ProcessId, zn as fromUndefinedOr, zt as gen } from "./runtime-CMPZpQaG.js";
|
|
3
3
|
import * as NodeChildProcess from "node:child_process";
|
|
4
4
|
import * as NodeCrypto from "node:crypto";
|
|
5
5
|
import * as NFS from "node:fs";
|
|
@@ -17822,7 +17822,7 @@ var T3Version = class extends Service()("t3cli/T3Version") {};
|
|
|
17822
17822
|
//#endregion
|
|
17823
17823
|
//#region src/version/layer.ts
|
|
17824
17824
|
const PackageJsonSchema = fromJsonString(Struct({ version: String$1 }));
|
|
17825
|
-
const T3VersionBundledLive = sync$2(T3Version, () => ({ version: "0.
|
|
17825
|
+
const T3VersionBundledLive = sync$2(T3Version, () => ({ version: "0.2.0" }));
|
|
17826
17826
|
effect(T3Version, gen(function* () {
|
|
17827
17827
|
const packageJson = yield* (yield* FileSystem).readFileString(fileURLToPath(new URL("../../package.json", import.meta.url)));
|
|
17828
17828
|
return { version: (yield* decodeUnknownEffect(PackageJsonSchema)(packageJson)).version };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as AuthAppLayer, r as NodeEnvironmentLive, s as T3Application, t as AppLayer } from "./runtime-
|
|
1
|
+
import { n as AuthAppLayer, r as NodeEnvironmentLive, s as T3Application, t as AppLayer } from "./runtime-CMPZpQaG.js";
|
|
2
2
|
export { AppLayer, AuthAppLayer, NodeEnvironmentLive, T3Application };
|
|
@@ -31476,21 +31476,6 @@ const setUrl = /*#__PURE__*/ dual(2, (self, url) => {
|
|
|
31476
31476
|
return makeWith$1(self.method, clone.toString(), urlParams, hash, self.headers, self.body);
|
|
31477
31477
|
});
|
|
31478
31478
|
/**
|
|
31479
|
-
* Appends a URL segment to the request URL, inserting or trimming one slash as needed.
|
|
31480
|
-
*
|
|
31481
|
-
* @category combinators
|
|
31482
|
-
* @since 4.0.0
|
|
31483
|
-
*/
|
|
31484
|
-
const appendUrl = /*#__PURE__*/ dual(2, (self, path) => {
|
|
31485
|
-
if (path === "") return self;
|
|
31486
|
-
return makeWith$1(self.method, joinSegments(self.url, path), self.urlParams, self.hash, self.headers, self.body);
|
|
31487
|
-
});
|
|
31488
|
-
const joinSegments = (first, second) => {
|
|
31489
|
-
const endsWithSlash = first.endsWith("/");
|
|
31490
|
-
const startsWithSlash = second.startsWith("/");
|
|
31491
|
-
return endsWithSlash && startsWithSlash ? first + second.slice(1) : !endsWithSlash && !startsWithSlash ? first + "/" + second : first + second;
|
|
31492
|
-
};
|
|
31493
|
-
/**
|
|
31494
31479
|
* Sets one query parameter, replacing existing values for that parameter name.
|
|
31495
31480
|
*
|
|
31496
31481
|
* @category combinators
|
|
@@ -64342,7 +64327,11 @@ var AuthConfigError = class extends TaggedErrorClass()("AuthConfigError", {
|
|
|
64342
64327
|
}) {};
|
|
64343
64328
|
var AuthTransportError = class extends TaggedErrorClass()("AuthTransportError", {
|
|
64344
64329
|
message: String$1,
|
|
64345
|
-
cause: optionalKey(Union([
|
|
64330
|
+
cause: optionalKey(Union([
|
|
64331
|
+
HttpClientErrorSchema,
|
|
64332
|
+
instanceOf(SchemaError),
|
|
64333
|
+
UrlError
|
|
64334
|
+
]))
|
|
64346
64335
|
}) {};
|
|
64347
64336
|
const AuthLocalErrorCauseSchema = Union([
|
|
64348
64337
|
instanceOf(PlatformError),
|
|
@@ -64358,10 +64347,13 @@ var AuthLocalError = class extends TaggedErrorClass()("AuthLocalError", {
|
|
|
64358
64347
|
function normalizeHttpBaseUrl(value) {
|
|
64359
64348
|
return parseUrl$1(value).pipe(flatMap$2((url) => succeed$2(normalizeBaseUrl$1(url))));
|
|
64360
64349
|
}
|
|
64361
|
-
function
|
|
64350
|
+
function toHttpEndpointUrl(httpBaseUrl, pathname) {
|
|
64351
|
+
return parseUrl$1(httpBaseUrl).pipe(flatMap$2((url) => succeed$2(withPathname(url, pathname).toString())));
|
|
64352
|
+
}
|
|
64353
|
+
function toWebSocketEndpointUrl(httpBaseUrl, pathname) {
|
|
64362
64354
|
return parseUrl$1(httpBaseUrl).pipe(flatMap$2((url) => {
|
|
64363
|
-
if (url.protocol === "http:") return succeed$2(
|
|
64364
|
-
if (url.protocol === "https:") return succeed$2(
|
|
64355
|
+
if (url.protocol === "http:") return succeed$2(withPathname(url, pathname, "ws:").toString());
|
|
64356
|
+
if (url.protocol === "https:") return succeed$2(withPathname(url, pathname, "wss:").toString());
|
|
64365
64357
|
return fail$2(new UrlError({
|
|
64366
64358
|
message: `unsupported server url protocol: ${url.protocol}`,
|
|
64367
64359
|
protocol: url.protocol
|
|
@@ -64378,16 +64370,22 @@ function normalizeBaseUrl$1(url) {
|
|
|
64378
64370
|
return mutate(url, (current) => {
|
|
64379
64371
|
current.hash = "";
|
|
64380
64372
|
current.search = "";
|
|
64381
|
-
current.pathname =
|
|
64373
|
+
current.pathname = normalizePathname(current.pathname);
|
|
64382
64374
|
}).toString().replace(/\/$/, "");
|
|
64383
64375
|
}
|
|
64384
|
-
function
|
|
64376
|
+
function withPathname(url, pathname, protocol) {
|
|
64385
64377
|
return mutate(url, (current) => {
|
|
64386
|
-
current.protocol = protocol;
|
|
64387
|
-
current.pathname =
|
|
64378
|
+
if (protocol !== void 0) current.protocol = protocol;
|
|
64379
|
+
current.pathname = appendPathname(current.pathname, pathname);
|
|
64388
64380
|
current.search = "";
|
|
64389
64381
|
current.hash = "";
|
|
64390
|
-
})
|
|
64382
|
+
});
|
|
64383
|
+
}
|
|
64384
|
+
function normalizePathname(pathname) {
|
|
64385
|
+
return pathname === "/" ? "" : pathname.replace(/\/+$/u, "");
|
|
64386
|
+
}
|
|
64387
|
+
function appendPathname(basePathname, pathname) {
|
|
64388
|
+
return `${normalizePathname(basePathname)}${pathname.startsWith("/") ? pathname : `/${pathname}`}`;
|
|
64391
64389
|
}
|
|
64392
64390
|
//#endregion
|
|
64393
64391
|
//#region src/auth/schema.ts
|
|
@@ -64558,7 +64556,7 @@ function parsePairingUrl(value) {
|
|
|
64558
64556
|
if (token.length === 0) return yield* fail$2(new AuthPairingUrlError({ message: "pairing url missing token" }));
|
|
64559
64557
|
const hostedHost = url.searchParams.get("host")?.trim();
|
|
64560
64558
|
return {
|
|
64561
|
-
baseUrl: normalizeBaseUrl(yield* parseUrl(hostedHost !== void 0 && hostedHost.length > 0 ? hostedHost : url.
|
|
64559
|
+
baseUrl: normalizeBaseUrl(yield* parseUrl(hostedHost !== void 0 && hostedHost.length > 0 ? hostedHost : new URL(".", url).toString())),
|
|
64562
64560
|
credential: token
|
|
64563
64561
|
};
|
|
64564
64562
|
});
|
|
@@ -64573,7 +64571,7 @@ function normalizeBaseUrl(url) {
|
|
|
64573
64571
|
return mutate(url, (current) => {
|
|
64574
64572
|
current.hash = "";
|
|
64575
64573
|
current.search = "";
|
|
64576
|
-
current.pathname = "";
|
|
64574
|
+
current.pathname = current.pathname === "/" ? "" : current.pathname.replace(/\/+$/u, "");
|
|
64577
64575
|
}).toString().replace(/\/$/, "");
|
|
64578
64576
|
}
|
|
64579
64577
|
function readPairingToken(url) {
|
|
@@ -64589,7 +64587,7 @@ const makeAuthTransport = fn("makeAuthTransport")(function* () {
|
|
|
64589
64587
|
const client = filterStatusOk(yield* HttpClient);
|
|
64590
64588
|
return {
|
|
64591
64589
|
bootstrapBearer: fn("AuthTransport.bootstrapBearer")(function* (input) {
|
|
64592
|
-
const request = post$1(input.baseUrl
|
|
64590
|
+
const request = post$1(yield* makeHttpEndpointUrl(input.baseUrl, "/api/auth/bootstrap/bearer")).pipe(acceptJson, bodyJsonUnsafe({ credential: input.credential }));
|
|
64593
64591
|
return yield* (yield* client.execute(request).pipe(catchTags$1({ HttpClientError: (error) => fail$2(new AuthTransportError({
|
|
64594
64592
|
message: "auth request failed",
|
|
64595
64593
|
cause: HttpClientErrorSchema.fromHttpClientError(error)
|
|
@@ -64605,7 +64603,7 @@ const makeAuthTransport = fn("makeAuthTransport")(function* () {
|
|
|
64605
64603
|
}));
|
|
64606
64604
|
}),
|
|
64607
64605
|
getSession: fn("AuthTransport.getSession")(function* (config) {
|
|
64608
|
-
const request = authenticatedRequest(config, "/api/auth/session", "get");
|
|
64606
|
+
const request = yield* authenticatedRequest(config, "/api/auth/session", "get");
|
|
64609
64607
|
return yield* (yield* client.execute(request).pipe(catchTags$1({ HttpClientError: (error) => fail$2(new AuthTransportError({
|
|
64610
64608
|
message: "auth request failed",
|
|
64611
64609
|
cause: HttpClientErrorSchema.fromHttpClientError(error)
|
|
@@ -64621,7 +64619,7 @@ const makeAuthTransport = fn("makeAuthTransport")(function* () {
|
|
|
64621
64619
|
}));
|
|
64622
64620
|
}),
|
|
64623
64621
|
issueWebSocketToken: fn("AuthTransport.issueWebSocketToken")(function* (config) {
|
|
64624
|
-
const request = authenticatedRequest(config, "/api/auth/ws-token", "post");
|
|
64622
|
+
const request = yield* authenticatedRequest(config, "/api/auth/ws-token", "post");
|
|
64625
64623
|
return yield* (yield* client.execute(request).pipe(catchTags$1({ HttpClientError: (error) => fail$2(new AuthTransportError({
|
|
64626
64624
|
message: "auth request failed",
|
|
64627
64625
|
cause: HttpClientErrorSchema.fromHttpClientError(error)
|
|
@@ -64639,7 +64637,13 @@ const makeAuthTransport = fn("makeAuthTransport")(function* () {
|
|
|
64639
64637
|
};
|
|
64640
64638
|
});
|
|
64641
64639
|
function authenticatedRequest(config, path, method) {
|
|
64642
|
-
return (method === "get" ? get$1(
|
|
64640
|
+
return makeHttpEndpointUrl(config.url, path).pipe(map$3((url) => method === "get" ? get$1(url) : post$1(url)), map$3((request) => request.pipe(acceptJson, bearerToken(config.token))));
|
|
64641
|
+
}
|
|
64642
|
+
function makeHttpEndpointUrl(baseUrl, path) {
|
|
64643
|
+
return toHttpEndpointUrl(baseUrl, path).pipe(catchTags$1({ UrlError: (error) => fail$2(new AuthTransportError({
|
|
64644
|
+
message: "auth request failed",
|
|
64645
|
+
cause: error
|
|
64646
|
+
})) }));
|
|
64643
64647
|
}
|
|
64644
64648
|
const T3AuthLive = effect(T3Auth, fn("makeT3Auth")(function* () {
|
|
64645
64649
|
const config = yield* T3Config;
|
|
@@ -68693,7 +68697,7 @@ const makeT3RpcLayer = fn("makeT3RpcLayer")(function* () {
|
|
|
68693
68697
|
const makeWsUrl = fn("makeWsUrl")(function* (input) {
|
|
68694
68698
|
const resolved = yield* input.config.resolve();
|
|
68695
68699
|
const wsToken = yield* input.auth.issueWebSocketToken();
|
|
68696
|
-
return getOrThrow(toUrl(get$1(yield*
|
|
68700
|
+
return getOrThrow(toUrl(get$1(yield* toWebSocketEndpointUrl(resolved.url, "/ws")).pipe(setUrlParam("wsToken", wsToken.token)))).toString();
|
|
68697
68701
|
});
|
|
68698
68702
|
function makeProtocolLayer(url) {
|
|
68699
68703
|
const socketLayer = layerWebSocket(url).pipe(provide$2(layerWebSocketConstructor));
|
package/package.json
CHANGED
package/src/auth/error.ts
CHANGED
|
@@ -23,7 +23,11 @@ export class AuthTransportError extends Schema.TaggedErrorClass<AuthTransportErr
|
|
|
23
23
|
{
|
|
24
24
|
message: Schema.String,
|
|
25
25
|
cause: Schema.optionalKey(
|
|
26
|
-
Schema.Union([
|
|
26
|
+
Schema.Union([
|
|
27
|
+
HttpClientError.HttpClientErrorSchema,
|
|
28
|
+
Schema.instanceOf(Schema.SchemaError),
|
|
29
|
+
UrlError,
|
|
30
|
+
]),
|
|
27
31
|
),
|
|
28
32
|
},
|
|
29
33
|
) {}
|
package/src/auth/pairing.ts
CHANGED
|
@@ -14,7 +14,11 @@ export function parsePairingUrl(value: string): Effect.Effect<PairingUrl, AuthPa
|
|
|
14
14
|
|
|
15
15
|
const hostedHost = url.searchParams.get("host")?.trim();
|
|
16
16
|
const baseUrl = normalizeBaseUrl(
|
|
17
|
-
yield* parseUrl(
|
|
17
|
+
yield* parseUrl(
|
|
18
|
+
hostedHost !== undefined && hostedHost.length > 0
|
|
19
|
+
? hostedHost
|
|
20
|
+
: new URL(".", url).toString(),
|
|
21
|
+
),
|
|
18
22
|
);
|
|
19
23
|
return { baseUrl, credential: token };
|
|
20
24
|
});
|
|
@@ -33,7 +37,7 @@ function normalizeBaseUrl(url: URL) {
|
|
|
33
37
|
return Url.mutate(url, (current) => {
|
|
34
38
|
current.hash = "";
|
|
35
39
|
current.search = "";
|
|
36
|
-
current.pathname = "";
|
|
40
|
+
current.pathname = current.pathname === "/" ? "" : current.pathname.replace(/\/+$/u, "");
|
|
37
41
|
})
|
|
38
42
|
.toString()
|
|
39
43
|
.replace(/\/$/, "");
|
package/src/auth/transport.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as Effect from "effect/Effect";
|
|
|
2
2
|
import { HttpClient, HttpClientError, HttpClientRequest } from "effect/unstable/http";
|
|
3
3
|
|
|
4
4
|
import type { ResolvedConfig } from "../config/service.ts";
|
|
5
|
+
import { toHttpEndpointUrl } from "../config/url.ts";
|
|
5
6
|
import { AuthTransportError } from "./error.ts";
|
|
6
7
|
import {
|
|
7
8
|
decodeAuthBearerBootstrapResult,
|
|
@@ -16,8 +17,8 @@ export const makeAuthTransport = Effect.fn("makeAuthTransport")(function* () {
|
|
|
16
17
|
readonly baseUrl: string;
|
|
17
18
|
readonly credential: string;
|
|
18
19
|
}) {
|
|
19
|
-
const
|
|
20
|
-
|
|
20
|
+
const url = yield* makeHttpEndpointUrl(input.baseUrl, "/api/auth/bootstrap/bearer");
|
|
21
|
+
const request = HttpClientRequest.post(url).pipe(
|
|
21
22
|
HttpClientRequest.acceptJson,
|
|
22
23
|
HttpClientRequest.bodyJsonUnsafe({ credential: input.credential }),
|
|
23
24
|
);
|
|
@@ -51,7 +52,7 @@ export const makeAuthTransport = Effect.fn("makeAuthTransport")(function* () {
|
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
const getSession = Effect.fn("AuthTransport.getSession")(function* (config: ResolvedConfig) {
|
|
54
|
-
const request = authenticatedRequest(config, "/api/auth/session", "get");
|
|
55
|
+
const request = yield* authenticatedRequest(config, "/api/auth/session", "get");
|
|
55
56
|
const response = yield* client.execute(request).pipe(
|
|
56
57
|
Effect.catchTags({
|
|
57
58
|
HttpClientError: (error) =>
|
|
@@ -84,7 +85,7 @@ export const makeAuthTransport = Effect.fn("makeAuthTransport")(function* () {
|
|
|
84
85
|
const issueWebSocketToken = Effect.fn("AuthTransport.issueWebSocketToken")(function* (
|
|
85
86
|
config: ResolvedConfig,
|
|
86
87
|
) {
|
|
87
|
-
const request = authenticatedRequest(config, "/api/auth/ws-token", "post");
|
|
88
|
+
const request = yield* authenticatedRequest(config, "/api/auth/ws-token", "post");
|
|
88
89
|
const response = yield* client.execute(request).pipe(
|
|
89
90
|
Effect.catchTags({
|
|
90
91
|
HttpClientError: (error) =>
|
|
@@ -122,11 +123,21 @@ export const makeAuthTransport = Effect.fn("makeAuthTransport")(function* () {
|
|
|
122
123
|
});
|
|
123
124
|
|
|
124
125
|
function authenticatedRequest(config: ResolvedConfig, path: string, method: "get" | "post") {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
return makeHttpEndpointUrl(config.url, path).pipe(
|
|
127
|
+
Effect.map((url) =>
|
|
128
|
+
method === "get" ? HttpClientRequest.get(url) : HttpClientRequest.post(url),
|
|
129
|
+
),
|
|
130
|
+
Effect.map((request) =>
|
|
131
|
+
request.pipe(HttpClientRequest.acceptJson, HttpClientRequest.bearerToken(config.token)),
|
|
132
|
+
),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function makeHttpEndpointUrl(baseUrl: string, path: string) {
|
|
137
|
+
return toHttpEndpointUrl(baseUrl, path).pipe(
|
|
138
|
+
Effect.catchTags({
|
|
139
|
+
UrlError: (error) =>
|
|
140
|
+
Effect.fail(new AuthTransportError({ message: "auth request failed", cause: error })),
|
|
141
|
+
}),
|
|
131
142
|
);
|
|
132
143
|
}
|
package/src/config/url.ts
CHANGED
|
@@ -26,6 +26,31 @@ export function toWebSocketBaseUrl(httpBaseUrl: string) {
|
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
export function toHttpEndpointUrl(httpBaseUrl: string, pathname: string) {
|
|
30
|
+
return parseUrl(httpBaseUrl).pipe(
|
|
31
|
+
Effect.flatMap((url) => Effect.succeed(withPathname(url, pathname).toString())),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function toWebSocketEndpointUrl(httpBaseUrl: string, pathname: string) {
|
|
36
|
+
return parseUrl(httpBaseUrl).pipe(
|
|
37
|
+
Effect.flatMap((url) => {
|
|
38
|
+
if (url.protocol === "http:") {
|
|
39
|
+
return Effect.succeed(withPathname(url, pathname, "ws:").toString());
|
|
40
|
+
}
|
|
41
|
+
if (url.protocol === "https:") {
|
|
42
|
+
return Effect.succeed(withPathname(url, pathname, "wss:").toString());
|
|
43
|
+
}
|
|
44
|
+
return Effect.fail(
|
|
45
|
+
new UrlError({
|
|
46
|
+
message: `unsupported server url protocol: ${url.protocol}`,
|
|
47
|
+
protocol: url.protocol,
|
|
48
|
+
}),
|
|
49
|
+
);
|
|
50
|
+
}),
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
29
54
|
function parseUrl(value: string): Effect.Effect<URL, UrlError> {
|
|
30
55
|
return Effect.fromResult(Url.fromString(value)).pipe(
|
|
31
56
|
Effect.catchTags({
|
|
@@ -39,7 +64,7 @@ function normalizeBaseUrl(url: URL) {
|
|
|
39
64
|
return Url.mutate(url, (current) => {
|
|
40
65
|
current.hash = "";
|
|
41
66
|
current.search = "";
|
|
42
|
-
current.pathname =
|
|
67
|
+
current.pathname = normalizePathname(current.pathname);
|
|
43
68
|
})
|
|
44
69
|
.toString()
|
|
45
70
|
.replace(/\/$/, "");
|
|
@@ -48,8 +73,27 @@ function normalizeBaseUrl(url: URL) {
|
|
|
48
73
|
function makeWebSocketUrl(url: URL, protocol: "ws:" | "wss:") {
|
|
49
74
|
return Url.mutate(url, (current) => {
|
|
50
75
|
current.protocol = protocol;
|
|
51
|
-
current.pathname = "/ws";
|
|
76
|
+
current.pathname = appendPathname(current.pathname, "/ws");
|
|
52
77
|
current.search = "";
|
|
53
78
|
current.hash = "";
|
|
54
79
|
}).toString();
|
|
55
80
|
}
|
|
81
|
+
|
|
82
|
+
function withPathname(url: URL, pathname: string, protocol?: "ws:" | "wss:") {
|
|
83
|
+
return Url.mutate(url, (current) => {
|
|
84
|
+
if (protocol !== undefined) {
|
|
85
|
+
current.protocol = protocol;
|
|
86
|
+
}
|
|
87
|
+
current.pathname = appendPathname(current.pathname, pathname);
|
|
88
|
+
current.search = "";
|
|
89
|
+
current.hash = "";
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function normalizePathname(pathname: string) {
|
|
94
|
+
return pathname === "/" ? "" : pathname.replace(/\/+$/u, "");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function appendPathname(basePathname: string, pathname: string) {
|
|
98
|
+
return `${normalizePathname(basePathname)}${pathname.startsWith("/") ? pathname : `/${pathname}`}`;
|
|
99
|
+
}
|
package/src/rpc/layer.ts
CHANGED
|
@@ -13,7 +13,7 @@ import * as Socket from "effect/unstable/socket/Socket";
|
|
|
13
13
|
|
|
14
14
|
import { T3Auth } from "../auth/service.ts";
|
|
15
15
|
import { T3Config } from "../config/service.ts";
|
|
16
|
-
import {
|
|
16
|
+
import { toWebSocketEndpointUrl } from "../config/url.ts";
|
|
17
17
|
import { CliWsRpcGroup } from "./ws-group.ts";
|
|
18
18
|
import { RpcError } from "./error.ts";
|
|
19
19
|
import { T3Rpc, type WsClient } from "./service.ts";
|
|
@@ -77,7 +77,7 @@ const makeWsUrl = Effect.fn("makeWsUrl")(function* (input: {
|
|
|
77
77
|
}) {
|
|
78
78
|
const resolved = yield* input.config.resolve();
|
|
79
79
|
const wsToken = yield* input.auth.issueWebSocketToken();
|
|
80
|
-
const wsUrl = yield*
|
|
80
|
+
const wsUrl = yield* toWebSocketEndpointUrl(resolved.url, "/ws");
|
|
81
81
|
const request = HttpClientRequest.get(wsUrl).pipe(
|
|
82
82
|
HttpClientRequest.setUrlParam("wsToken", wsToken.token),
|
|
83
83
|
);
|