t3code-cli 0.4.0 → 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.
Files changed (44) hide show
  1. package/dist/bin.js +4 -2
  2. package/dist/index.js +12 -2
  3. package/dist/{runtime-Cq64iuZr.js → runtime-KQVRmRk-.js} +229 -174
  4. package/dist/src/application/layer.d.ts +2 -2
  5. package/dist/src/auth/layer.d.ts +4 -2
  6. package/dist/src/auth/local-base-dir.d.ts +7 -0
  7. package/dist/src/auth/local-origin.d.ts +18 -0
  8. package/dist/src/auth/local-token.d.ts +26 -0
  9. package/dist/src/auth/local.d.ts +8 -11
  10. package/dist/src/auth/pairing.d.ts +6 -6
  11. package/dist/src/auth/service.d.ts +2 -1
  12. package/dist/src/auth/transport.d.ts +6 -3
  13. package/dist/src/auth/type.d.ts +18 -0
  14. package/dist/src/connection/error.d.ts +8 -0
  15. package/dist/src/connection/layer.d.ts +3 -0
  16. package/dist/src/connection/node.d.ts +2 -0
  17. package/dist/src/connection/service.d.ts +13 -0
  18. package/dist/src/connection/type.d.ts +10 -0
  19. package/dist/src/connection.d.ts +5 -0
  20. package/dist/src/index.d.ts +23 -1
  21. package/dist/src/rpc/error.d.ts +4 -3
  22. package/dist/src/rpc/layer.d.ts +5 -4
  23. package/dist/src/runtime.d.ts +9 -2
  24. package/package.json +1 -1
  25. package/src/auth/layer.ts +17 -0
  26. package/src/auth/local-base-dir.ts +22 -0
  27. package/src/auth/local-origin.ts +62 -0
  28. package/src/auth/local-token.ts +302 -0
  29. package/src/auth/local.ts +13 -348
  30. package/src/auth/pairing.ts +8 -19
  31. package/src/auth/service.ts +2 -1
  32. package/src/auth/transport.ts +17 -11
  33. package/src/auth/type.ts +22 -0
  34. package/src/cli/auth.ts +2 -0
  35. package/src/connection/error.ts +9 -0
  36. package/src/connection/layer.ts +10 -0
  37. package/src/connection/node.ts +12 -0
  38. package/src/connection/service.ts +26 -0
  39. package/src/connection/type.ts +12 -0
  40. package/src/connection.ts +9 -0
  41. package/src/index.ts +75 -1
  42. package/src/rpc/error.ts +4 -11
  43. package/src/rpc/layer.ts +25 -15
  44. package/src/runtime.ts +45 -7
@@ -3,8 +3,7 @@ import * as Effect from "effect/Effect";
3
3
  import * as Layer from "effect/Layer";
4
4
  import { Url } from "effect/unstable/http";
5
5
 
6
- import { T3Config } from "../config/service.ts";
7
- import { AuthConfigError, AuthPairingUrlError, AuthTransportError } from "./error.ts";
6
+ import { AuthPairingUrlError, AuthTransportError } from "./error.ts";
8
7
  import { T3AuthTransport } from "./transport.ts";
9
8
  import type { PairingUrl, PairResult } from "./type.ts";
10
9
 
@@ -13,32 +12,22 @@ export class T3AuthPairing extends Context.Service<
13
12
  {
14
13
  readonly pair: (
15
14
  pairingUrl: string,
16
- ) => Effect.Effect<PairResult, AuthConfigError | AuthPairingUrlError | AuthTransportError>;
15
+ ) => Effect.Effect<PairResult, AuthPairingUrlError | AuthTransportError>;
17
16
  }
18
17
  >()("t3cli/T3AuthPairing") {}
19
18
 
20
19
  export const makeT3AuthPairing = Effect.fn("makeT3AuthPairing")(function* () {
21
- const config = yield* T3Config;
22
20
  const transport = yield* T3AuthTransport;
23
21
 
24
22
  const pair = Effect.fn("T3AuthPairingLive.pair")(function* (pairingUrl: string) {
25
23
  const parsed = yield* parsePairingUrl(pairingUrl);
26
24
  const result = yield* transport.bootstrapBearer(parsed);
27
- const existing = yield* config.readStored().pipe(
28
- Effect.catchTags({
29
- ConfigError: (error) =>
30
- Effect.fail(new AuthConfigError({ message: "auth config failed", cause: error })),
31
- }),
32
- );
33
- yield* config
34
- .writeStored({ ...existing, url: parsed.baseUrl, token: result.sessionToken })
35
- .pipe(
36
- Effect.catchTags({
37
- ConfigError: (error) =>
38
- Effect.fail(new AuthConfigError({ message: "auth config failed", cause: error })),
39
- }),
40
- );
41
- return { url: parsed.baseUrl, role: result.role, expiresAt: result.expiresAt };
25
+ return {
26
+ url: parsed.baseUrl,
27
+ token: result.sessionToken,
28
+ role: result.role,
29
+ expiresAt: result.expiresAt,
30
+ };
42
31
  });
43
32
 
44
33
  return { pair };
@@ -3,13 +3,14 @@ import type * as Effect from "effect/Effect";
3
3
 
4
4
  import type { AuthSessionState, AuthWebSocketTicketResult } from "./schema.ts";
5
5
  import type { AuthError } from "./error.ts";
6
- import type { LocalAuthInput, LocalAuthResult, PairResult } from "./type.ts";
6
+ import type { AuthConfigInput, LocalAuthInput, LocalAuthResult, PairResult } from "./type.ts";
7
7
 
8
8
  export class T3Auth extends Context.Service<
9
9
  T3Auth,
10
10
  {
11
11
  readonly pair: (value: string) => Effect.Effect<PairResult, AuthError>;
12
12
  readonly local: (input: LocalAuthInput) => Effect.Effect<LocalAuthResult, AuthError>;
13
+ readonly writeConfig: (input: AuthConfigInput) => Effect.Effect<void, AuthError>;
13
14
  readonly status: () => Effect.Effect<AuthSessionState, AuthError>;
14
15
  readonly issueWebSocketTicket: () => Effect.Effect<AuthWebSocketTicketResult, AuthError>;
15
16
  }
@@ -9,7 +9,6 @@ import * as Effect from "effect/Effect";
9
9
  import * as Layer from "effect/Layer";
10
10
  import { HttpClient, HttpClientError, HttpClientRequest } from "effect/unstable/http";
11
11
 
12
- import type { ResolvedConfig } from "../config/service.ts";
13
12
  import { toHttpEndpointUrl } from "../config/url.ts";
14
13
  import { AuthTransportError } from "./error.ts";
15
14
  import {
@@ -21,6 +20,11 @@ import {
21
20
  decodeAuthWebSocketTicketResult,
22
21
  } from "./schema.ts";
23
22
 
23
+ export type AuthTransportConnection = {
24
+ readonly url: string;
25
+ readonly token: string;
26
+ };
27
+
24
28
  export class T3AuthTransport extends Context.Service<
25
29
  T3AuthTransport,
26
30
  {
@@ -29,10 +33,10 @@ export class T3AuthTransport extends Context.Service<
29
33
  readonly credential: string;
30
34
  }) => Effect.Effect<AuthBearerBootstrapResult, AuthTransportError>;
31
35
  readonly getSession: (
32
- config: ResolvedConfig,
36
+ connection: AuthTransportConnection,
33
37
  ) => Effect.Effect<AuthSessionState, AuthTransportError>;
34
38
  readonly issueWebSocketTicket: (
35
- config: ResolvedConfig,
39
+ connection: AuthTransportConnection,
36
40
  ) => Effect.Effect<AuthWebSocketTicketResult, AuthTransportError>;
37
41
  }
38
42
  >()("t3cli/T3AuthTransport") {}
@@ -91,9 +95,11 @@ const makeT3AuthTransport = Effect.fn("makeT3AuthTransport")(function* () {
91
95
  } satisfies AuthBearerBootstrapResult;
92
96
  });
93
97
 
94
- const getSession = Effect.fn("AuthTransport.getSession")(function* (config: ResolvedConfig) {
95
- const url = yield* makeHttpEndpointUrl(config.url, "/api/auth/session");
96
- const request = HttpClientRequest.get(url).pipe(authenticatedRequest(config));
98
+ const getSession = Effect.fn("AuthTransport.getSession")(function* (
99
+ connection: AuthTransportConnection,
100
+ ) {
101
+ const url = yield* makeHttpEndpointUrl(connection.url, "/api/auth/session");
102
+ const request = HttpClientRequest.get(url).pipe(authenticatedRequest(connection));
97
103
  const response = yield* client.execute(request).pipe(
98
104
  Effect.catchTags({
99
105
  HttpClientError: (error) =>
@@ -124,10 +130,10 @@ const makeT3AuthTransport = Effect.fn("makeT3AuthTransport")(function* () {
124
130
  });
125
131
 
126
132
  const issueWebSocketTicket = Effect.fn("AuthTransport.issueWebSocketTicket")(function* (
127
- config: ResolvedConfig,
133
+ connection: AuthTransportConnection,
128
134
  ) {
129
- const url = yield* makeHttpEndpointUrl(config.url, "/api/auth/websocket-ticket");
130
- const request = HttpClientRequest.post(url).pipe(authenticatedRequest(config));
135
+ const url = yield* makeHttpEndpointUrl(connection.url, "/api/auth/websocket-ticket");
136
+ const request = HttpClientRequest.post(url).pipe(authenticatedRequest(connection));
131
137
  const response = yield* client.execute(request).pipe(
132
138
  Effect.catchTags({
133
139
  HttpClientError: (error) =>
@@ -167,8 +173,8 @@ const makeT3AuthTransport = Effect.fn("makeT3AuthTransport")(function* () {
167
173
  export const T3AuthTransportLive = Layer.effect(T3AuthTransport, makeT3AuthTransport());
168
174
 
169
175
  const authenticatedRequest =
170
- (config: ResolvedConfig) => (request: HttpClientRequest.HttpClientRequest) =>
171
- request.pipe(HttpClientRequest.acceptJson, HttpClientRequest.bearerToken(config.token));
176
+ (connection: AuthTransportConnection) => (request: HttpClientRequest.HttpClientRequest) =>
177
+ request.pipe(HttpClientRequest.acceptJson, HttpClientRequest.bearerToken(connection.token));
172
178
 
173
179
  function makeHttpEndpointUrl(baseUrl: string, path: string) {
174
180
  return toHttpEndpointUrl(baseUrl, path).pipe(
package/src/auth/type.ts CHANGED
@@ -7,8 +7,14 @@ export type PairingUrl = {
7
7
  readonly credential: string;
8
8
  };
9
9
 
10
+ export type AuthConfigInput = {
11
+ readonly url: string;
12
+ readonly token: string;
13
+ };
14
+
10
15
  export type PairResult = {
11
16
  readonly url: string;
17
+ readonly token: string;
12
18
  readonly role: AuthBearerBootstrapResult["role"];
13
19
  readonly expiresAt: string;
14
20
  };
@@ -21,8 +27,24 @@ export type LocalAuthInput = {
21
27
  readonly subject: string;
22
28
  };
23
29
 
30
+ export type LocalAuthTokenInput = Omit<LocalAuthInput, "origin">;
31
+
32
+ export type LocalAuthOriginInput = {
33
+ readonly baseDir?: string;
34
+ readonly origin?: string;
35
+ };
36
+
37
+ export type LocalAuthTokenResult = {
38
+ readonly token: string;
39
+ readonly role: AuthSessionRole;
40
+ readonly expiresAt: string;
41
+ readonly source: "local";
42
+ readonly baseDir: string;
43
+ };
44
+
24
45
  export type LocalAuthResult = {
25
46
  readonly url: string;
47
+ readonly token: string;
26
48
  readonly role: AuthSessionRole;
27
49
  readonly expiresAt: string;
28
50
  readonly source: "local";
package/src/cli/auth.ts CHANGED
@@ -35,6 +35,7 @@ const pairCommand = Command.make(
35
35
  const output = yield* T3Output;
36
36
  const resolvedFormat = resolveOutputFormat(format, environment, "json");
37
37
  const result = yield* auth.pair(url);
38
+ yield* auth.writeConfig(result);
38
39
  if (resolvedFormat === "json") {
39
40
  yield* output.printJson(result);
40
41
  } else {
@@ -66,6 +67,7 @@ const localCommand = Command.make(
66
67
  ...(Option.isSome(baseDir) ? { baseDir: baseDir.value } : {}),
67
68
  ...(Option.isSome(origin) ? { origin: origin.value } : {}),
68
69
  });
70
+ yield* auth.writeConfig(result);
69
71
  if (resolvedFormat === "json") {
70
72
  yield* output.printJson(formatAuthLocalJson(result));
71
73
  } else {
@@ -0,0 +1,9 @@
1
+ import * as Schema from "effect/Schema";
2
+
3
+ export class T3CodeConnectionError extends Schema.TaggedErrorClass<T3CodeConnectionError>()(
4
+ "T3CodeConnectionError",
5
+ {
6
+ message: Schema.String,
7
+ cause: Schema.optionalKey(Schema.Unknown),
8
+ },
9
+ ) {}
@@ -0,0 +1,10 @@
1
+ import * as Layer from "effect/Layer";
2
+
3
+ import { T3AuthTransportLive } from "../auth/transport.ts";
4
+ import { T3RpcLive } from "../rpc/layer.ts";
5
+
6
+ export function makeT3CodeRpcLayer() {
7
+ return T3RpcLive.pipe(Layer.provide(T3AuthTransportLive));
8
+ }
9
+
10
+ export const T3CodeRpcLayer = makeT3CodeRpcLayer();
@@ -0,0 +1,12 @@
1
+ import * as Layer from "effect/Layer";
2
+ import * as NodeHttpClient from "@effect/platform-node/NodeHttpClient";
3
+ import * as NodeSocket from "@effect/platform-node/NodeSocket";
4
+
5
+ import { T3CodeRpcLayer } from "./layer.ts";
6
+
7
+ const NodeConnectionPlatformLayer = Layer.mergeAll(
8
+ NodeHttpClient.layerUndici,
9
+ NodeSocket.layerWebSocketConstructor,
10
+ );
11
+
12
+ export const T3CodeNodeRpcLayer = T3CodeRpcLayer.pipe(Layer.provide(NodeConnectionPlatformLayer));
@@ -0,0 +1,26 @@
1
+ import * as Context from "effect/Context";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Layer from "effect/Layer";
4
+
5
+ import type { T3CodeConnectionError } from "./error.ts";
6
+ import type { T3CodeConnection } from "./type.ts";
7
+
8
+ export class T3CodeConnectionProvider extends Context.Service<
9
+ T3CodeConnectionProvider,
10
+ {
11
+ readonly get: Effect.Effect<T3CodeConnection, T3CodeConnectionError>;
12
+ }
13
+ >()("t3cli/T3CodeConnectionProvider") {}
14
+
15
+ export function makeT3CodeConnectionProvider(
16
+ get: Effect.Effect<T3CodeConnection, T3CodeConnectionError>,
17
+ ): T3CodeConnectionProvider["Service"] {
18
+ return { get };
19
+ }
20
+
21
+ export function T3CodeConnectionProviderLive(connection: T3CodeConnection) {
22
+ return Layer.succeed(
23
+ T3CodeConnectionProvider,
24
+ makeT3CodeConnectionProvider(Effect.succeed(connection)),
25
+ );
26
+ }
@@ -0,0 +1,12 @@
1
+ export type T3CodeOrigin = {
2
+ readonly url: string;
3
+ };
4
+
5
+ export type T3CodeAuth = {
6
+ readonly token: string;
7
+ };
8
+
9
+ export type T3CodeConnection = {
10
+ readonly origin: T3CodeOrigin;
11
+ readonly auth: T3CodeAuth;
12
+ };
@@ -0,0 +1,9 @@
1
+ export { T3CodeConnectionError } from "./connection/error.ts";
2
+ export { T3CodeRpcLayer, makeT3CodeRpcLayer } from "./connection/layer.ts";
3
+ export { T3CodeNodeRpcLayer } from "./connection/node.ts";
4
+ export {
5
+ T3CodeConnectionProvider,
6
+ T3CodeConnectionProviderLive,
7
+ makeT3CodeConnectionProvider,
8
+ } from "./connection/service.ts";
9
+ export type { T3CodeAuth, T3CodeConnection, T3CodeOrigin } from "./connection/type.ts";
package/src/index.ts CHANGED
@@ -6,8 +6,82 @@ export type {
6
6
  WaitEvent,
7
7
  } from "./application/service.ts";
8
8
  export type { ApplicationError } from "./application/error.ts";
9
+ export { T3Auth } from "./auth/service.ts";
10
+ export { T3AuthLive, makeT3Auth } from "./auth/layer.ts";
11
+ export { T3LocalAuth, T3LocalAuthLive, makeT3LocalAuth } from "./auth/local.ts";
12
+ export {
13
+ T3LocalAuthOrigin,
14
+ T3LocalAuthOriginLive,
15
+ makeT3LocalAuthOrigin,
16
+ } from "./auth/local-origin.ts";
17
+ export {
18
+ T3LocalAuthToken,
19
+ T3LocalAuthTokenLive,
20
+ makeT3LocalAuthToken,
21
+ } from "./auth/local-token.ts";
22
+ export {
23
+ T3AuthPairing,
24
+ T3AuthPairingLive,
25
+ makeT3AuthPairing,
26
+ parsePairingUrl,
27
+ } from "./auth/pairing.ts";
28
+ export {
29
+ AuthConfigError,
30
+ AuthLocalDatabaseError,
31
+ AuthLocalError,
32
+ AuthLocalSecretError,
33
+ AuthLocalSigningError,
34
+ AuthPairingUrlError,
35
+ AuthTransportError,
36
+ } from "./auth/error.ts";
37
+ export type { AuthError } from "./auth/error.ts";
38
+ export type { AuthSessionState, AuthWebSocketTicketResult } from "./auth/schema.ts";
39
+ export type {
40
+ AuthConfigInput,
41
+ AuthSessionRole,
42
+ LocalAuthInput,
43
+ LocalAuthOriginInput,
44
+ LocalAuthResult,
45
+ LocalAuthTokenInput,
46
+ LocalAuthTokenResult,
47
+ PairingUrl,
48
+ PairResult,
49
+ } from "./auth/type.ts";
50
+ export { T3Config } from "./config/service.ts";
51
+ export type { ResolvedConfig, StoredConfig } from "./config/service.ts";
52
+ export { T3ConfigLive, makeT3Config } from "./config/layer.ts";
53
+ export { ConfigError, UrlError } from "./config/error.ts";
54
+ export type { ConfigServiceError } from "./config/error.ts";
55
+ export {
56
+ makeT3CodeConnectionProvider,
57
+ makeT3CodeRpcLayer,
58
+ T3CodeConnectionProvider,
59
+ T3CodeConnectionProviderLive,
60
+ T3CodeNodeRpcLayer,
61
+ T3CodeRpcLayer,
62
+ T3CodeConnectionError,
63
+ } from "./connection.ts";
64
+ export type { T3CodeAuth, T3CodeConnection, T3CodeOrigin } from "./connection.ts";
65
+ export { Environment } from "./environment/service.ts";
66
+ export type { EnvironmentShape } from "./environment/service.ts";
9
67
  export { NodeEnvironmentLive } from "./environment/layer.ts";
10
- export { AppLayer, AuthAppLayer } from "./runtime.ts";
68
+ export {
69
+ AppLayer,
70
+ AuthAppLayer,
71
+ T3AuthLayer,
72
+ T3AuthPairingLayer,
73
+ T3AuthTransportLayer,
74
+ T3LocalAuthLayer,
75
+ T3LocalAuthOriginLayer,
76
+ T3LocalAuthTokenLayer,
77
+ } from "./runtime.ts";
78
+ export { SqlClientFactory } from "./sql/service.ts";
79
+ export type { SqlClientFactoryShape, SqliteClientConfig } from "./sql/service.ts";
80
+ export {
81
+ NodeSqlClientFactoryLive,
82
+ NodeSqliteClientLive,
83
+ makeNodeSqliteClient,
84
+ } from "./sql/node-sqlite-client.ts";
11
85
  export type {
12
86
  OrchestrationMessage,
13
87
  OrchestrationProjectShell,
package/src/rpc/error.ts CHANGED
@@ -9,13 +9,9 @@ import {
9
9
  import { HttpClientError } from "effect/unstable/http";
10
10
  import { RpcClientError } from "effect/unstable/rpc";
11
11
 
12
- import {
13
- AuthConfigError,
14
- AuthLocalError,
15
- AuthPairingUrlError,
16
- AuthTransportError,
17
- } from "../auth/error.ts";
18
- import { ConfigError, UrlError } from "../config/error.ts";
12
+ import { AuthTransportError } from "../auth/error.ts";
13
+ import { T3CodeConnectionError } from "../connection/error.ts";
14
+ import { UrlError } from "../config/error.ts";
19
15
 
20
16
  const RpcErrorCauseSchema = Schema.Union([
21
17
  RpcClientError.RpcClientError,
@@ -24,11 +20,8 @@ const RpcErrorCauseSchema = Schema.Union([
24
20
  OrchestrationDispatchCommandError,
25
21
  OrchestrationGetSnapshotError,
26
22
  ServerSettingsError,
27
- AuthConfigError,
28
- AuthLocalError,
29
- AuthPairingUrlError,
30
23
  AuthTransportError,
31
- ConfigError,
24
+ T3CodeConnectionError,
32
25
  HttpClientError.HttpClientErrorSchema,
33
26
  UrlError,
34
27
  Schema.instanceOf(Schema.SchemaError),
package/src/rpc/layer.ts CHANGED
@@ -6,14 +6,13 @@ import * as Option from "effect/Option";
6
6
  import * as Schedule from "effect/Schedule";
7
7
  import * as Scope from "effect/Scope";
8
8
  import * as SynchronizedRef from "effect/SynchronizedRef";
9
- import * as NodeSocket from "@effect/platform-node/NodeSocket";
10
9
  import { HttpClientRequest } from "effect/unstable/http";
11
10
  import { RpcClient, RpcSerialization } from "effect/unstable/rpc";
12
11
  import * as Socket from "effect/unstable/socket/Socket";
13
12
 
14
- import { T3Auth } from "../auth/service.ts";
15
- import { T3Config } from "../config/service.ts";
16
- import { toWebSocketEndpointUrl } from "../config/url.ts";
13
+ import { T3AuthTransport } from "../auth/transport.ts";
14
+ import { T3CodeConnectionProvider } from "../connection/service.ts";
15
+ import { normalizeHttpBaseUrl, toWebSocketEndpointUrl } from "../config/url.ts";
17
16
  import { CliWsRpcGroup } from "./ws-group.ts";
18
17
  import { RpcError } from "./error.ts";
19
18
  import { T3Rpc, type WsClient } from "./service.ts";
@@ -27,15 +26,19 @@ type Connection = {
27
26
  };
28
27
 
29
28
  export const makeT3RpcLayer = Effect.fn("makeT3RpcLayer")(function* () {
30
- const config = yield* T3Config;
31
- const auth = yield* T3Auth;
29
+ const connectionProvider = yield* T3CodeConnectionProvider;
30
+ const authTransport = yield* T3AuthTransport;
31
+ const webSocketConstructor = yield* Socket.WebSocketConstructor;
32
32
  const parentScope = yield* Scope.Scope;
33
33
  const connection = yield* SynchronizedRef.make(Option.none<Connection>());
34
34
  const openConnection = Effect.fn("T3RpcLive.openConnection")(function* () {
35
35
  const scope = yield* Scope.fork(parentScope);
36
36
  return yield* Effect.gen(function* () {
37
- const url = yield* makeWsUrl({ auth, config });
38
- const protocol = yield* Layer.buildWithScope(makeProtocolLayer(url), scope);
37
+ const url = yield* makeWsUrl({ authTransport, connectionProvider });
38
+ const protocol = yield* Layer.buildWithScope(
39
+ makeProtocolLayer(url, webSocketConstructor),
40
+ scope,
41
+ );
39
42
  const client = yield* makeClient.pipe(
40
43
  Effect.provide(protocol),
41
44
  Effect.provideService(Scope.Scope, scope),
@@ -72,21 +75,28 @@ export const makeT3RpcLayer = Effect.fn("makeT3RpcLayer")(function* () {
72
75
  });
73
76
 
74
77
  const makeWsUrl = Effect.fn("makeWsUrl")(function* (input: {
75
- readonly config: T3Config["Service"];
76
- readonly auth: T3Auth["Service"];
78
+ readonly authTransport: T3AuthTransport["Service"];
79
+ readonly connectionProvider: T3CodeConnectionProvider["Service"];
77
80
  }) {
78
- const resolved = yield* input.config.resolve();
79
- const wsTicket = yield* input.auth.issueWebSocketTicket();
80
- const wsUrl = yield* toWebSocketEndpointUrl(resolved.url, "/ws");
81
+ const connection = yield* input.connectionProvider.get;
82
+ const origin = yield* normalizeHttpBaseUrl(connection.origin.url);
83
+ const wsTicket = yield* input.authTransport.issueWebSocketTicket({
84
+ url: origin,
85
+ token: connection.auth.token,
86
+ });
87
+ const wsUrl = yield* toWebSocketEndpointUrl(origin, "/ws");
81
88
  const request = HttpClientRequest.get(wsUrl).pipe(
82
89
  HttpClientRequest.setUrlParam("wsTicket", wsTicket.ticket),
83
90
  );
84
91
  return Option.getOrThrow(HttpClientRequest.toUrl(request)).toString();
85
92
  });
86
93
 
87
- function makeProtocolLayer(url: string) {
94
+ function makeProtocolLayer(
95
+ url: string,
96
+ webSocketConstructor: Socket.WebSocketConstructor["Service"],
97
+ ) {
88
98
  const socketLayer = Socket.layerWebSocket(url).pipe(
89
- Layer.provide(NodeSocket.layerWebSocketConstructor),
99
+ Layer.provide(Layer.succeed(Socket.WebSocketConstructor, webSocketConstructor)),
90
100
  );
91
101
  return RpcClient.layerProtocolSocket({ retryTransientErrors: true }).pipe(
92
102
  Layer.provide(socketLayer),
package/src/runtime.ts CHANGED
@@ -1,31 +1,69 @@
1
+ import * as Effect from "effect/Effect";
1
2
  import * as Layer from "effect/Layer";
2
3
  import * as NodeHttpClient from "@effect/platform-node/NodeHttpClient";
3
4
  import * as NodeSocket from "@effect/platform-node/NodeSocket";
4
5
 
5
6
  import { T3AuthLive } from "./auth/layer.ts";
6
7
  import { T3LocalAuthLive } from "./auth/local.ts";
8
+ import { T3LocalAuthOriginLive } from "./auth/local-origin.ts";
9
+ import { T3LocalAuthTokenLive } from "./auth/local-token.ts";
7
10
  import { T3AuthPairingLive } from "./auth/pairing.ts";
8
11
  import { T3AuthTransportLive } from "./auth/transport.ts";
12
+ import { T3CodeConnectionError } from "./connection/error.ts";
13
+ import { T3CodeConnectionProvider, makeT3CodeConnectionProvider } from "./connection/service.ts";
9
14
  import { T3ConfigLive } from "./config/layer.ts";
15
+ import { T3Config } from "./config/service.ts";
10
16
  import { T3ApplicationLive } from "./application/layer.ts";
11
17
  import { T3OrchestrationLive } from "./orchestration/layer.ts";
12
18
  import { T3RpcLive } from "./rpc/layer.ts";
13
19
  import { NodeSqlClientFactoryLive } from "./sql/node-sqlite-client.ts";
14
20
 
15
- const T3AuthTransportLayer = T3AuthTransportLive.pipe(Layer.provide(NodeHttpClient.layerUndici));
16
- const T3LocalAuthLayer = T3LocalAuthLive.pipe(
17
- Layer.provide(Layer.mergeAll(T3ConfigLive, NodeSqlClientFactoryLive)),
21
+ export const T3AuthTransportLayer = T3AuthTransportLive.pipe(
22
+ Layer.provide(NodeHttpClient.layerUndici),
18
23
  );
19
- const T3AuthPairingLayer = T3AuthPairingLive.pipe(
20
- Layer.provide(Layer.mergeAll(T3ConfigLive, T3AuthTransportLayer)),
24
+ export const T3LocalAuthOriginLayer = T3LocalAuthOriginLive;
25
+ export const T3LocalAuthTokenLayer = T3LocalAuthTokenLive.pipe(
26
+ Layer.provide(NodeSqlClientFactoryLive),
21
27
  );
22
- const T3AuthLayer = T3AuthLive.pipe(
28
+ export const T3LocalAuthLayer = T3LocalAuthLive.pipe(
29
+ Layer.provide(Layer.mergeAll(T3LocalAuthOriginLayer, T3LocalAuthTokenLayer)),
30
+ );
31
+ export const T3AuthPairingLayer = T3AuthPairingLive.pipe(Layer.provide(T3AuthTransportLayer));
32
+ export const T3AuthLayer = T3AuthLive.pipe(
23
33
  Layer.provide(
24
34
  Layer.mergeAll(T3ConfigLive, T3AuthTransportLayer, T3LocalAuthLayer, T3AuthPairingLayer),
25
35
  ),
26
36
  );
37
+ const T3ConfigConnectionProviderLayer = Layer.effect(
38
+ T3CodeConnectionProvider,
39
+ Effect.gen(function* () {
40
+ const config = yield* T3Config;
41
+ return makeT3CodeConnectionProvider(
42
+ config.resolve().pipe(
43
+ Effect.map((resolved) => ({
44
+ origin: { url: resolved.url },
45
+ auth: { token: resolved.token },
46
+ })),
47
+ Effect.mapError(
48
+ (error) =>
49
+ new T3CodeConnectionError({
50
+ message: "failed to resolve T3 Code connection from CLI config",
51
+ cause: error,
52
+ }),
53
+ ),
54
+ ),
55
+ );
56
+ }),
57
+ ).pipe(Layer.provide(T3ConfigLive));
58
+
27
59
  const T3RpcLayer = T3RpcLive.pipe(
28
- Layer.provide(Layer.mergeAll(T3ConfigLive, T3AuthLayer, NodeSocket.layerWebSocketConstructor)),
60
+ Layer.provide(
61
+ Layer.mergeAll(
62
+ T3ConfigConnectionProviderLayer,
63
+ T3AuthTransportLayer,
64
+ NodeSocket.layerWebSocketConstructor,
65
+ ),
66
+ ),
29
67
  );
30
68
  const T3OrchestrationLayer = T3OrchestrationLive.pipe(Layer.provide(T3RpcLayer));
31
69
  const T3ApplicationLayer = T3ApplicationLive.pipe(Layer.provide(T3OrchestrationLayer));