effect-start 0.26.0 → 0.27.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.
Files changed (58) hide show
  1. package/package.json +4 -2
  2. package/src/Entity.ts +6 -6
  3. package/src/FileRouterCodegen.ts +4 -4
  4. package/src/FileSystem.ts +4 -8
  5. package/src/RouteHook.ts +1 -1
  6. package/src/RouteSse.ts +3 -3
  7. package/src/SqlIntrospect.ts +2 -2
  8. package/src/Start.ts +102 -2
  9. package/src/Values.ts +11 -0
  10. package/src/bun/BunRoute.ts +1 -1
  11. package/src/bun/BunRuntime.ts +5 -5
  12. package/src/hyper/HyperHtml.ts +11 -7
  13. package/src/hyper/jsx.d.ts +1 -1
  14. package/src/lint/plugin.js +174 -4
  15. package/src/sql/SqlClient.ts +355 -0
  16. package/src/sql/bun/index.ts +117 -50
  17. package/src/sql/index.ts +1 -1
  18. package/src/sql/libsql/index.ts +91 -77
  19. package/src/sql/libsql/libsql.d.ts +4 -1
  20. package/src/sql/mssql/index.ts +141 -108
  21. package/src/sql/mssql/mssql.d.ts +1 -0
  22. package/src/testing/TestLogger.ts +4 -4
  23. package/src/x/tailwind/compile.ts +6 -14
  24. package/src/console/Console.ts +0 -42
  25. package/src/console/ConsoleErrors.ts +0 -213
  26. package/src/console/ConsoleLogger.ts +0 -56
  27. package/src/console/ConsoleMetrics.ts +0 -72
  28. package/src/console/ConsoleProcess.ts +0 -59
  29. package/src/console/ConsoleStore.ts +0 -187
  30. package/src/console/ConsoleTracer.ts +0 -107
  31. package/src/console/Simulation.ts +0 -814
  32. package/src/console/console.html +0 -340
  33. package/src/console/index.ts +0 -3
  34. package/src/console/routes/errors/route.tsx +0 -97
  35. package/src/console/routes/fiberDetail.tsx +0 -54
  36. package/src/console/routes/fibers/route.tsx +0 -45
  37. package/src/console/routes/git/route.tsx +0 -64
  38. package/src/console/routes/layout.tsx +0 -4
  39. package/src/console/routes/logs/route.tsx +0 -77
  40. package/src/console/routes/metrics/route.tsx +0 -36
  41. package/src/console/routes/route.tsx +0 -8
  42. package/src/console/routes/routes/route.tsx +0 -30
  43. package/src/console/routes/services/route.tsx +0 -21
  44. package/src/console/routes/system/route.tsx +0 -43
  45. package/src/console/routes/traceDetail.tsx +0 -22
  46. package/src/console/routes/traces/route.tsx +0 -81
  47. package/src/console/routes/tree.ts +0 -30
  48. package/src/console/ui/Errors.tsx +0 -76
  49. package/src/console/ui/Fibers.tsx +0 -321
  50. package/src/console/ui/Git.tsx +0 -182
  51. package/src/console/ui/Logs.tsx +0 -46
  52. package/src/console/ui/Metrics.tsx +0 -78
  53. package/src/console/ui/Routes.tsx +0 -125
  54. package/src/console/ui/Services.tsx +0 -273
  55. package/src/console/ui/Shell.tsx +0 -62
  56. package/src/console/ui/System.tsx +0 -131
  57. package/src/console/ui/Traces.tsx +0 -426
  58. package/src/sql/Sql.ts +0 -51
@@ -5,7 +5,8 @@ import * as GlobalValue from "effect/GlobalValue"
5
5
  import * as Layer from "effect/Layer"
6
6
  import * as Option from "effect/Option"
7
7
  import type * as Libsql from "@libsql/client"
8
- import * as Sql from "../Sql.ts"
8
+ import * as Sql from "../SqlClient.ts"
9
+ import * as Values from "../../Values.ts"
9
10
 
10
11
  export interface LibsqlConfig {
11
12
  readonly url: string
@@ -13,6 +14,7 @@ export interface LibsqlConfig {
13
14
  readonly syncUrl?: string
14
15
  readonly syncInterval?: number
15
16
  readonly encryptionKey?: string
17
+ readonly spanAttributes?: Record<string, unknown>
16
18
  }
17
19
 
18
20
  const wrapError = (error: unknown): Sql.SqlError =>
@@ -25,12 +27,28 @@ const wrapError = (error: unknown): Sql.SqlError =>
25
27
  const wrap = <T>(fn: () => PromiseLike<T>): Effect.Effect<T, Sql.SqlError> =>
26
28
  Effect.tryPromise({ try: () => Promise.resolve(fn()), catch: wrapError })
27
29
 
28
- const makeValues: Sql.SqlQuery["values"] = (obj: any, ...columns: Array<string>) => {
29
- const items = Array.isArray(obj) ? obj : [obj]
30
- const cols = columns.length > 0 ? columns : Object.keys(items[0])
31
- return { value: items, columns: cols }
30
+ const dialect = Sql.sqliteDialect
31
+ const makeSpanAttributes = (config: LibsqlConfig): ReadonlyArray<readonly [string, unknown]> => {
32
+ const parsed = (() => {
33
+ try {
34
+ return new URL(config.url)
35
+ } catch {
36
+ return undefined
37
+ }
38
+ })()
39
+ const dbFromPath = parsed?.pathname.replace(/^\/+/, "") || undefined
40
+ const parsedPort = parsed?.port ? Number(parsed.port) : undefined
41
+
42
+ return Object.entries(
43
+ Values.compact({
44
+ ...(config.spanAttributes ?? {}),
45
+ "db.system.name": "sqlite",
46
+ "db.namespace": dbFromPath,
47
+ "server.address": parsed?.hostname,
48
+ "server.port": parsedPort,
49
+ }),
50
+ )
32
51
  }
33
-
34
52
  const resultSetToRows = <T>(result: Libsql.ResultSet): ReadonlyArray<T> => {
35
53
  const { columns, rows } = result
36
54
  return rows.map((row) => {
@@ -40,13 +58,14 @@ const resultSetToRows = <T>(result: Libsql.ResultSet): ReadonlyArray<T> => {
40
58
  })
41
59
  }
42
60
 
43
- const buildQuery = (strings: TemplateStringsArray, values: Array<unknown>) => {
44
- let sql = strings[0]
45
- for (let i = 0; i < values.length; i++) sql += "?" + strings[i + 1]
46
- return { sql, args: values }
47
- }
61
+ const executeQuery = <T>(
62
+ client: Libsql.Client,
63
+ sql: string,
64
+ args: Array<unknown>,
65
+ ): Effect.Effect<ReadonlyArray<T>, Sql.SqlError> =>
66
+ wrap(() => client.execute({ sql, args })).pipe(Effect.map(resultSetToRows<T>))
48
67
 
49
- interface TxState {
68
+ interface TransactionConnection {
50
69
  readonly depth: number
51
70
  }
52
71
 
@@ -58,34 +77,39 @@ const loadLibsql = () => import("@libsql/client") as Promise<LibsqlModule>
58
77
 
59
78
  const currentTransaction = GlobalValue.globalValue(
60
79
  Symbol.for("effect-start/sql/libsql/currentTransaction"),
61
- () => FiberRef.unsafeMake<Option.Option<TxState>>(Option.none()),
80
+ () => FiberRef.unsafeMake<Option.Option<TransactionConnection>>(Option.none()),
62
81
  )
63
82
 
64
- const executeQuery = <T>(
65
- client: Libsql.Client,
66
- sql: string,
67
- args: Array<unknown>,
68
- ): Effect.Effect<ReadonlyArray<T>, Sql.SqlError> =>
69
- wrap(() => client.execute({ sql, args })).pipe(Effect.map(resultSetToRows<T>))
70
-
71
- const runQuery = <T>(
72
- client: Libsql.Client,
73
- strings: TemplateStringsArray,
74
- values: Array<unknown>,
75
- ): Effect.Effect<ReadonlyArray<T>, Sql.SqlError> => {
76
- const { sql, args } = buildQuery(strings, values)
77
- return executeQuery(client, sql, args)
83
+ const exec = (client: Libsql.Client, sql: string) => wrap(() => client.execute(sql))
84
+
85
+ const makeTaggedTemplate = (client: Libsql.Client) => {
86
+ const unsafeFn = <T = any>(query: string, values?: Array<unknown>) =>
87
+ executeQuery<T>(client, query, values ?? [])
88
+
89
+ return <T = any>(
90
+ strings: TemplateStringsArray,
91
+ ...values: Array<unknown>
92
+ ): Effect.Effect<ReadonlyArray<T>, Sql.SqlError> => {
93
+ if (Sql.hasFragments(values)) {
94
+ const compiled = Sql.interpolate(dialect, strings, values)
95
+ return unsafeFn<T>(compiled.sql, compiled.parameters)
96
+ }
97
+
98
+ let sqlText = strings[0]
99
+ for (let i = 0; i < values.length; i++) sqlText += "?" + strings[i + 1]
100
+ return executeQuery<T>(client, sqlText, values)
101
+ }
78
102
  }
79
103
 
80
- const runUnsafe = <T>(
104
+ const makeQuery = (
81
105
  client: Libsql.Client,
82
- query: string,
83
- values?: Array<unknown>,
84
- ): Effect.Effect<ReadonlyArray<T>, Sql.SqlError> =>
85
- executeQuery(client, query, values ?? [])
86
-
87
- const exec = (client: Libsql.Client, sql: string) =>
88
- wrap(() => client.execute(sql))
106
+ spanAttributes: ReadonlyArray<readonly [string, unknown]>,
107
+ ): Sql.Connection => {
108
+ const query = makeTaggedTemplate(client)
109
+ const unsafe: Sql.Connection["unsafe"] = <T = any>(query: string, values?: Array<unknown>) =>
110
+ executeQuery<T>(client, query, values ?? [])
111
+ return Sql.connection(query, unsafe, { spanAttributes, dialect })
112
+ }
89
113
 
90
114
  const makeWithTransaction =
91
115
  (client: Libsql.Client) =>
@@ -98,9 +122,7 @@ const makeWithTransaction =
98
122
  return Effect.gen(function* () {
99
123
  yield* exec(client, `SAVEPOINT ${name}`)
100
124
  const exit = yield* Effect.exit(
101
- restore(
102
- Effect.locally(self, currentTransaction, Option.some({ depth: depth + 1 })),
103
- ),
125
+ restore(Effect.locally(self, currentTransaction, Option.some({ depth: depth + 1 }))),
104
126
  )
105
127
  if (Exit.isSuccess(exit)) {
106
128
  yield* exec(client, `RELEASE SAVEPOINT ${name}`)
@@ -129,45 +151,37 @@ const makeWithTransaction =
129
151
  export const layer = (config: LibsqlConfig): Layer.Layer<Sql.SqlClient, Sql.SqlError> =>
130
152
  Layer.scoped(
131
153
  Sql.SqlClient,
132
- Effect.acquireRelease(
133
- wrap(() => loadLibsql()).pipe(
134
- Effect.map((libsql) => {
135
- const client = libsql.createClient(config)
136
- const use: Sql.SqlClient["use"] = (fn) =>
137
- Effect.tryPromise({ try: () => Promise.resolve(fn(client)), catch: wrapError })
138
- return Object.assign(
139
- <T = any>(strings: TemplateStringsArray, ...values: Array<unknown>) =>
140
- runQuery<T>(client, strings, values),
141
- {
142
- unsafe: <T = any>(query: string, values?: Array<unknown>) =>
143
- runUnsafe<T>(client, query, values),
144
- values: makeValues,
145
- withTransaction: makeWithTransaction(client),
146
- reserve: Effect.acquireRelease(
147
- wrap(() => loadLibsql()).pipe(
148
- Effect.map((m) => m.createClient(config)),
149
- ),
150
- (reserved: Libsql.Client) => Effect.sync(() => reserved.close()),
151
- ).pipe(
152
- Effect.map(
153
- (reserved): Sql.SqlQuery =>
154
- Object.assign(
155
- <T = any>(strings: TemplateStringsArray, ...values: Array<unknown>) =>
156
- runQuery<T>(reserved, strings, values),
157
- {
158
- unsafe: <T = any>(query: string, values?: Array<unknown>) =>
159
- runUnsafe<T>(reserved, query, values),
160
- values: makeValues,
161
- },
162
- ),
163
- ),
164
- ),
165
- close: () => Effect.sync(() => client.close()),
166
- use,
167
- },
168
- ) satisfies Sql.SqlClient
169
- }),
154
+ Effect.map(
155
+ Effect.acquireRelease(
156
+ wrap(() => loadLibsql()).pipe(
157
+ Effect.map((libsql) => {
158
+ const client = libsql.createClient(config)
159
+ const spanAttributes = makeSpanAttributes(config)
160
+ const query = makeTaggedTemplate(client)
161
+ const unsafeFn: Sql.Connection["unsafe"] = <T = any>(
162
+ query: string,
163
+ values?: Array<unknown>,
164
+ ) => executeQuery<T>(client, query, values ?? [])
165
+ const use: Sql.SqlClient["use"] = (fn) =>
166
+ Effect.tryPromise({ try: () => Promise.resolve(fn(client)), catch: wrapError })
167
+
168
+ return {
169
+ client: Sql.make({
170
+ query,
171
+ unsafe: unsafeFn,
172
+ withTransaction: makeWithTransaction(client),
173
+ spanAttributes,
174
+ dialect,
175
+ // libsql has no connection pool — reuse the existing client
176
+ reserve: Effect.succeed(makeQuery(client, spanAttributes)),
177
+ use,
178
+ }),
179
+ close: Effect.sync(() => client.close()),
180
+ }
181
+ }),
182
+ ),
183
+ (handle) => handle.close.pipe(Effect.orDie),
170
184
  ),
171
- (client) => client.close().pipe(Effect.orDie),
185
+ (handle) => handle.client,
172
186
  ),
173
187
  )
@@ -21,7 +21,10 @@ declare module "@libsql/client" {
21
21
 
22
22
  export interface Client {
23
23
  execute(stmt: InStatement | string): Promise<ResultSet>
24
- batch(stmts: ReadonlyArray<InStatement | string>, mode?: TransactionMode): Promise<ReadonlyArray<ResultSet>>
24
+ batch(
25
+ stmts: ReadonlyArray<InStatement | string>,
26
+ mode?: TransactionMode,
27
+ ): Promise<ReadonlyArray<ResultSet>>
25
28
  transaction(mode?: TransactionMode): Promise<Transaction>
26
29
  close(): void
27
30
  }
@@ -5,26 +5,8 @@ import * as GlobalValue from "effect/GlobalValue"
5
5
  import * as Layer from "effect/Layer"
6
6
  import * as Option from "effect/Option"
7
7
  import type * as Mssql from "mssql"
8
- import * as Sql from "../Sql.ts"
9
-
10
- export interface MssqlConfig {
11
- readonly server: string
12
- readonly database?: string
13
- readonly user?: string
14
- readonly password?: string
15
- readonly port?: number
16
- readonly pool?: {
17
- readonly max?: number
18
- readonly min?: number
19
- readonly idleTimeoutMillis?: number
20
- }
21
- readonly options?: {
22
- readonly encrypt?: boolean
23
- readonly trustServerCertificate?: boolean
24
- readonly requestTimeout?: number
25
- readonly connectionTimeout?: number
26
- }
27
- }
8
+ import * as Sql from "../SqlClient.ts"
9
+ import * as Values from "../../Values.ts"
28
10
 
29
11
  const wrapError = (error: unknown): Sql.SqlError =>
30
12
  new Sql.SqlError({
@@ -35,17 +17,33 @@ const wrapError = (error: unknown): Sql.SqlError =>
35
17
  cause: error,
36
18
  })
37
19
 
38
- const makeValues: Sql.SqlQuery["values"] = (obj: any, ...columns: Array<string>) => {
39
- const items = Array.isArray(obj) ? obj : [obj]
40
- const cols = columns.length > 0 ? columns : Object.keys(items[0])
41
- return { value: items, columns: cols }
42
- }
20
+ const dialect = Sql.mssqlDialect
21
+ const makeSpanAttributes = (
22
+ config: Mssql.config & {
23
+ readonly url?: string
24
+ readonly spanAttributes?: Record<string, unknown>
25
+ },
26
+ ): Record<string, unknown> =>
27
+ {
28
+ const parsed = (() => {
29
+ if (typeof config.url !== "string") return undefined
30
+ try {
31
+ return new URL(config.url)
32
+ } catch {
33
+ return undefined
34
+ }
35
+ })()
36
+ const dbFromPath = parsed?.pathname.replace(/^\/+/, "") || undefined
37
+ const parsedPort = parsed?.port ? Number(parsed.port) : undefined
43
38
 
44
- const buildQuery = (strings: TemplateStringsArray, values: Array<unknown>) => {
45
- let text = strings[0]
46
- for (let i = 0; i < values.length; i++) text += `@p${i + 1}` + strings[i + 1]
47
- return { text, values }
48
- }
39
+ return Values.compact({
40
+ ...(config.spanAttributes ?? {}),
41
+ "db.system.name": "microsoft.sql_server",
42
+ "db.namespace": config.database ?? dbFromPath,
43
+ "server.address": config.server ?? parsed?.hostname,
44
+ "server.port": config.port ?? parsedPort,
45
+ })
46
+ }
49
47
 
50
48
  const addInputs = (request: Mssql.Request, values: Array<unknown>) => {
51
49
  for (let i = 0; i < values.length; i++) {
@@ -53,7 +51,7 @@ const addInputs = (request: Mssql.Request, values: Array<unknown>) => {
53
51
  }
54
52
  }
55
53
 
56
- interface TxState {
54
+ interface TransactionConnection {
57
55
  readonly transaction: Mssql.Transaction
58
56
  readonly depth: number
59
57
  }
@@ -66,45 +64,71 @@ const loadMssql = () => import("mssql") as Promise<MssqlModule>
66
64
 
67
65
  const currentTransaction = GlobalValue.globalValue(
68
66
  Symbol.for("effect-start/sql/mssql/currentTransaction"),
69
- () => FiberRef.unsafeMake<Option.Option<TxState>>(Option.none()),
67
+ () => FiberRef.unsafeMake<Option.Option<TransactionConnection>>(Option.none()),
70
68
  )
71
69
 
70
+ const makeRequest = (
71
+ pool: Mssql.ConnectionPool,
72
+ txOpt: Option.Option<TransactionConnection>,
73
+ values: Array<unknown>,
74
+ ): Mssql.Request => {
75
+ const request = Option.isSome(txOpt) ? txOpt.value.transaction.request() : pool.request()
76
+ addInputs(request, values)
77
+ return request
78
+ }
79
+
72
80
  const executeQuery = <T>(
73
81
  pool: Mssql.ConnectionPool,
74
82
  text: string,
75
83
  values: Array<unknown>,
76
84
  ): Effect.Effect<ReadonlyArray<T>, Sql.SqlError> =>
77
- Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) => {
78
- const request = Option.isSome(txOpt) ? txOpt.value.transaction.request() : pool.request()
79
- addInputs(request, values)
80
- return Effect.tryPromise({
81
- try: () => request.query<T>(text),
85
+ Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) =>
86
+ Effect.tryPromise({
87
+ try: () => makeRequest(pool, txOpt, values).query<T>(text),
82
88
  catch: wrapError,
83
- }).pipe(Effect.map((result) => result.recordset ?? []))
84
- })
85
-
86
- const runQuery = <T>(
87
- pool: Mssql.ConnectionPool,
88
- strings: TemplateStringsArray,
89
- values: Array<unknown>,
90
- ): Effect.Effect<ReadonlyArray<T>, Sql.SqlError> => {
91
- const { text, values: params } = buildQuery(strings, values)
92
- return executeQuery(pool, text, params)
93
- }
89
+ }).pipe(Effect.map((result) => result.recordset ?? [])),
90
+ )
94
91
 
95
92
  const runUnsafe = <T>(
96
93
  pool: Mssql.ConnectionPool,
97
94
  query: string,
98
95
  values?: Array<unknown>,
99
96
  ): Effect.Effect<ReadonlyArray<T>, Sql.SqlError> =>
100
- Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) => {
101
- const request = Option.isSome(txOpt) ? txOpt.value.transaction.request() : pool.request()
102
- if (values) addInputs(request, values)
103
- return Effect.tryPromise({
104
- try: () => request.query<T>(query),
97
+ Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) =>
98
+ Effect.tryPromise({
99
+ try: () => makeRequest(pool, txOpt, values ?? []).query<T>(query),
105
100
  catch: wrapError,
106
- }).pipe(Effect.map((result) => result.recordset ?? []))
107
- })
101
+ }).pipe(Effect.map((result) => result.recordset ?? [])),
102
+ )
103
+
104
+ const makeTaggedTemplate = (pool: Mssql.ConnectionPool) => {
105
+ const unsafeFn = <T = any>(query: string, values?: Array<unknown>) =>
106
+ runUnsafe<T>(pool, query, values)
107
+
108
+ return <T = any>(
109
+ strings: TemplateStringsArray,
110
+ ...values: Array<unknown>
111
+ ): Effect.Effect<ReadonlyArray<T>, Sql.SqlError> => {
112
+ if (Sql.hasFragments(values)) {
113
+ const compiled = Sql.interpolate(dialect, strings, values)
114
+ return unsafeFn<T>(compiled.sql, compiled.parameters)
115
+ }
116
+
117
+ let text = strings[0]
118
+ for (let i = 0; i < values.length; i++) text += `@p${i + 1}` + strings[i + 1]
119
+ return executeQuery<T>(pool, text, values)
120
+ }
121
+ }
122
+
123
+ const makeQuery = (
124
+ pool: Mssql.ConnectionPool,
125
+ spanAttributes: ReadonlyArray<readonly [string, unknown]>,
126
+ ): Sql.Connection => {
127
+ const query = makeTaggedTemplate(pool)
128
+ const unsafe: Sql.Connection["unsafe"] = <T = any>(query: string, values?: Array<unknown>) =>
129
+ runUnsafe<T>(pool, query, values)
130
+ return Sql.connection(query, unsafe, { spanAttributes, dialect })
131
+ }
108
132
 
109
133
  const makeWithTransaction =
110
134
  (pool: Mssql.ConnectionPool) =>
@@ -161,63 +185,72 @@ const makeWithTransaction =
161
185
  }),
162
186
  )
163
187
 
164
- export const layer = (config: MssqlConfig): Layer.Layer<Sql.SqlClient, Sql.SqlError> =>
188
+ export const layer = (
189
+ config: Mssql.config & {
190
+ readonly url?: string
191
+ readonly spanAttributes?: Record<string, unknown>
192
+ },
193
+ ): Layer.Layer<Sql.SqlClient, Sql.SqlError> =>
165
194
  Layer.scoped(
166
195
  Sql.SqlClient,
167
- Effect.acquireRelease(
168
- Effect.tryPromise({
169
- try: async () => {
170
- const mssql = await loadMssql()
171
- const pool = await new mssql.ConnectionPool(config as Mssql.config).connect()
172
- return { mssql, pool }
173
- },
174
- catch: wrapError,
175
- }).pipe(
176
- Effect.map(({ mssql, pool }) => {
177
- const use: Sql.SqlClient["use"] = (fn) =>
178
- Effect.tryPromise({ try: () => Promise.resolve(fn(pool)), catch: wrapError })
179
- return Object.assign(
180
- <T = any>(strings: TemplateStringsArray, ...values: Array<unknown>) =>
181
- runQuery<T>(pool, strings, values),
182
- {
183
- unsafe: <T = any>(query: string, values?: Array<unknown>) =>
184
- runUnsafe<T>(pool, query, values),
185
- values: makeValues,
186
- withTransaction: makeWithTransaction(pool),
187
- reserve: Effect.acquireRelease(
188
- Effect.tryPromise({
189
- try: () =>
190
- new mssql.ConnectionPool({
191
- ...config,
192
- pool: { max: 1, min: 1 },
193
- } as Mssql.config).connect(),
194
- catch: wrapError,
195
- }),
196
- (reserved: Mssql.ConnectionPool) =>
197
- Effect.tryPromise({ try: () => reserved.close(), catch: () => void 0 }).pipe(
198
- Effect.asVoid,
199
- Effect.orDie,
200
- ),
201
- ).pipe(
202
- Effect.map(
203
- (reserved): Sql.SqlQuery =>
204
- Object.assign(
205
- <T = any>(strings: TemplateStringsArray, ...values: Array<unknown>) =>
206
- runQuery<T>(reserved, strings, values),
207
- {
208
- unsafe: <T = any>(query: string, values?: Array<unknown>) =>
209
- runUnsafe<T>(reserved, query, values),
210
- values: makeValues,
211
- },
196
+ Effect.map(
197
+ Effect.acquireRelease(
198
+ Effect.tryPromise({
199
+ try: async () => {
200
+ const mssql = await loadMssql()
201
+ const driverConfig = { ...config } as Record<string, unknown>
202
+ delete driverConfig.spanAttributes
203
+ delete driverConfig.url
204
+ const pool = await new mssql.ConnectionPool(driverConfig as unknown as Mssql.config).connect()
205
+ return { mssql, pool }
206
+ },
207
+ catch: wrapError,
208
+ }).pipe(
209
+ Effect.map((options) => {
210
+ const driverConfig = { ...config } as Record<string, unknown>
211
+ delete driverConfig.spanAttributes
212
+ delete driverConfig.url
213
+ const spanAttributes = Object.entries(makeSpanAttributes(config))
214
+ const query = makeTaggedTemplate(options.pool)
215
+ const unsafeFn: Sql.Connection["unsafe"] = <T = any>(
216
+ query: string,
217
+ values?: Array<unknown>,
218
+ ) => runUnsafe<T>(options.pool, query, values)
219
+ const use: Sql.SqlClient["use"] = (fn) =>
220
+ Effect.tryPromise({ try: () => Promise.resolve(fn(options.pool)), catch: wrapError })
221
+
222
+ return {
223
+ client: Sql.make({
224
+ query,
225
+ unsafe: unsafeFn,
226
+ withTransaction: makeWithTransaction(options.pool),
227
+ spanAttributes,
228
+ dialect,
229
+ reserve: Effect.acquireRelease(
230
+ Effect.tryPromise({
231
+ try: () =>
232
+ new options.mssql.ConnectionPool({
233
+ ...driverConfig,
234
+ pool: { max: 1, min: 1 },
235
+ } as unknown as Mssql.config).connect(),
236
+ catch: wrapError,
237
+ }),
238
+ (reserved: Mssql.ConnectionPool) =>
239
+ Effect.tryPromise({ try: () => reserved.close(), catch: () => void 0 }).pipe(
240
+ Effect.asVoid,
241
+ Effect.orDie,
212
242
  ),
243
+ ).pipe(
244
+ Effect.map((reserved): Sql.Connection => makeQuery(reserved, spanAttributes)),
213
245
  ),
214
- ),
215
- close: () => use((pool) => pool.close()),
216
- use,
217
- },
218
- ) satisfies Sql.SqlClient
219
- }),
246
+ use,
247
+ }),
248
+ close: use((pool) => pool.close()),
249
+ }
250
+ }),
251
+ ),
252
+ (handle) => handle.close.pipe(Effect.orDie),
220
253
  ),
221
- (client) => client.close().pipe(Effect.orDie),
254
+ (handle) => handle.client,
222
255
  ),
223
256
  )
@@ -1,3 +1,4 @@
1
+ // types from @types/mssql@9.1.9
1
2
  declare module "mssql" {
2
3
  export interface config {
3
4
  readonly server: string
@@ -24,13 +24,13 @@ export function layer(): Layer.Layer<TestLogger> {
24
24
  const messages = yield* Ref.make<Array<string>>([])
25
25
  const mutableRef = (messages as any).ref as MutableRef.MutableRef<Array<string>>
26
26
 
27
- const customLogger = Logger.make(({ message, logLevel, cause }) => {
28
- const causeStr = !Cause.isEmpty(cause)
29
- ? ` ${Cause.pretty(cause, { renderErrorCause: true })}`
27
+ const customLogger = Logger.make((options) => {
28
+ const causeStr = !Cause.isEmpty(options.cause)
29
+ ? ` ${Cause.pretty(options.cause, { renderErrorCause: true })}`
30
30
  : ""
31
31
  MutableRef.update(mutableRef, (msgs) => [
32
32
  ...msgs,
33
- `[${logLevel._tag}] ${String(message)}${causeStr}`,
33
+ `[${options.logLevel._tag}] ${String(options.message)}${causeStr}`,
34
34
  ])
35
35
  })
36
36
 
@@ -20,24 +20,16 @@ export interface CompileOptions {
20
20
  customJsResolver?: Resolver
21
21
  }
22
22
 
23
- function createCompileOptions({
24
- base,
25
- from,
26
- polyfills,
27
- onDependency,
28
-
29
- customCssResolver,
30
- customJsResolver,
31
- }: CompileOptions) {
23
+ function createCompileOptions(options: CompileOptions) {
32
24
  return {
33
- base,
34
- polyfills,
35
- from,
25
+ base: options.base,
26
+ polyfills: options.polyfills,
27
+ from: options.from,
36
28
  async loadModule(id: string, base: string) {
37
- return loadModule(id, base, onDependency, customJsResolver)
29
+ return loadModule(id, base, options.onDependency, options.customJsResolver)
38
30
  },
39
31
  async loadStylesheet(id: string, sheetBase: string) {
40
- let sheet = await loadStylesheet(id, sheetBase, onDependency, customCssResolver)
32
+ let sheet = await loadStylesheet(id, sheetBase, options.onDependency, options.customCssResolver)
41
33
 
42
34
  return sheet
43
35
  },
@@ -1,42 +0,0 @@
1
- import * as Effect from "effect/Effect"
2
- import * as Layer from "effect/Layer"
3
- import * as Route from "../Route.ts"
4
- import * as RouteTree from "../RouteTree.ts"
5
- import * as ConsoleErrors from "./ConsoleErrors.ts"
6
- import * as ConsoleLogger from "./ConsoleLogger.ts"
7
- import * as ConsoleMetrics from "./ConsoleMetrics.ts"
8
- import * as ConsoleProcess from "./ConsoleProcess.ts"
9
- import * as ConsoleStore from "./ConsoleStore.ts"
10
- import * as ConsoleTracer from "./ConsoleTracer.ts"
11
- import consoleRoutes from "./routes/tree.ts"
12
-
13
- export { ConsoleStore } from "./ConsoleStore.ts"
14
-
15
- export function layer(
16
- options?: ConsoleStore.ConsoleStoreOptions,
17
- ): Layer.Layer<ConsoleStore.ConsoleStore> {
18
- const store = ConsoleStore.layer(options)
19
- return Layer.mergeAll(
20
- ConsoleTracer.layer,
21
- ConsoleLogger.layer,
22
- ConsoleMetrics.layer,
23
- ConsoleErrors.layer,
24
- ConsoleProcess.layer,
25
- ).pipe(Layer.provideMerge(store))
26
- }
27
-
28
- export function routeLayer(
29
- prefix: string,
30
- ): Layer.Layer<Route.Routes, never, Route.Routes | ConsoleStore.ConsoleStore> {
31
- return Layer.effect(
32
- Route.Routes,
33
- Effect.gen(function* () {
34
- const existing = yield* Route.Routes
35
- ConsoleStore.store.prefix = prefix
36
- const tree = Route.tree({
37
- [prefix as "/"]: consoleRoutes,
38
- })
39
- return RouteTree.merge(existing, tree)
40
- }),
41
- )
42
- }