effect-start 0.32.0 → 0.34.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 (200) hide show
  1. package/dist/Entity.d.ts +6 -1
  2. package/dist/Entity.d.ts.map +1 -1
  3. package/dist/Entity.js +43 -5
  4. package/dist/Entity.js.map +1 -1
  5. package/dist/Fetch.js.map +1 -1
  6. package/dist/FileRouterCodegen.js +2 -2
  7. package/dist/FileRouterCodegen.js.map +1 -1
  8. package/dist/Html.d.ts +5 -11
  9. package/dist/Html.d.ts.map +1 -1
  10. package/dist/Html.js +21 -1
  11. package/dist/Html.js.map +1 -1
  12. package/dist/KeyValueStore.d.ts +37 -0
  13. package/dist/KeyValueStore.d.ts.map +1 -0
  14. package/dist/KeyValueStore.js +99 -0
  15. package/dist/KeyValueStore.js.map +1 -0
  16. package/dist/Route.d.ts +2 -2
  17. package/dist/Route.d.ts.map +1 -1
  18. package/dist/Route.js +1 -1
  19. package/dist/Route.js.map +1 -1
  20. package/dist/RouteBody.d.ts +2 -2
  21. package/dist/RouteBody.d.ts.map +1 -1
  22. package/dist/RouteHttp.d.ts.map +1 -1
  23. package/dist/RouteHttp.js +45 -35
  24. package/dist/RouteHttp.js.map +1 -1
  25. package/dist/RouteMount.d.ts +20 -31
  26. package/dist/RouteMount.d.ts.map +1 -1
  27. package/dist/RouteMount.js +0 -15
  28. package/dist/RouteMount.js.map +1 -1
  29. package/dist/Start.d.ts.map +1 -1
  30. package/dist/Start.js +4 -0
  31. package/dist/Start.js.map +1 -1
  32. package/dist/StaticFiles.d.ts +2 -2
  33. package/dist/StaticFiles.d.ts.map +1 -1
  34. package/dist/StaticFiles.js +7 -8
  35. package/dist/StaticFiles.js.map +1 -1
  36. package/dist/bun/BunRoute.d.ts.map +1 -1
  37. package/dist/bun/BunRoute.js +90 -78
  38. package/dist/bun/BunRoute.js.map +1 -1
  39. package/dist/bun/BunServer.d.ts +1 -1
  40. package/dist/bun/BunServer.d.ts.map +1 -1
  41. package/dist/bun/BunServer.js +8 -1
  42. package/dist/bun/BunServer.js.map +1 -1
  43. package/dist/bundler/BundleRoute.d.ts +4 -4
  44. package/dist/bundler/BundleRoute.d.ts.map +1 -1
  45. package/dist/datastar/attributes/computed.js +3 -3
  46. package/dist/datastar/attributes/computed.js.map +1 -1
  47. package/dist/datastar/attributes/on.js +11 -36
  48. package/dist/datastar/attributes/on.js.map +1 -1
  49. package/dist/datastar/engine.d.ts +9 -7
  50. package/dist/datastar/engine.d.ts.map +1 -1
  51. package/dist/datastar/engine.js +45 -29
  52. package/dist/datastar/engine.js.map +1 -1
  53. package/dist/datastar/jsx.d.ts +70 -0
  54. package/dist/datastar/jsx.d.ts.map +1 -0
  55. package/dist/datastar/jsx.js +2 -0
  56. package/dist/datastar/jsx.js.map +1 -0
  57. package/dist/datastar/window.d.ts +8 -0
  58. package/dist/datastar/window.d.ts.map +1 -0
  59. package/dist/datastar/window.js +4 -0
  60. package/dist/datastar/window.js.map +1 -0
  61. package/dist/experimental/KeyValueStore.d.ts +37 -0
  62. package/dist/experimental/KeyValueStore.d.ts.map +1 -0
  63. package/dist/experimental/KeyValueStore.js +99 -0
  64. package/dist/experimental/KeyValueStore.js.map +1 -0
  65. package/dist/experimental/SqlCache.d.ts +19 -0
  66. package/dist/experimental/SqlCache.d.ts.map +1 -0
  67. package/dist/experimental/SqlCache.js +35 -0
  68. package/dist/experimental/SqlCache.js.map +1 -0
  69. package/dist/experimental/SqlIntrospect.d.ts +92 -0
  70. package/dist/experimental/SqlIntrospect.d.ts.map +1 -0
  71. package/dist/experimental/SqlIntrospect.js +478 -0
  72. package/dist/experimental/SqlIntrospect.js.map +1 -0
  73. package/dist/index.d.ts +1 -0
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +1 -0
  76. package/dist/index.js.map +1 -1
  77. package/dist/jsx-runtime.d.ts +2 -2
  78. package/dist/jsx-runtime.d.ts.map +1 -1
  79. package/dist/jsx.d.ts +3216 -0
  80. package/dist/jsx.d.ts.map +1 -0
  81. package/dist/jsx.js +6 -0
  82. package/dist/jsx.js.map +1 -0
  83. package/dist/lint/plugin.d.ts +4 -3
  84. package/dist/lint/plugin.js +56 -17
  85. package/dist/lint/plugin.js.map +1 -1
  86. package/dist/sql/index.d.ts +0 -2
  87. package/dist/sql/index.d.ts.map +1 -1
  88. package/dist/sql/index.js +0 -2
  89. package/dist/sql/index.js.map +1 -1
  90. package/dist/studio/StudioLogger.d.ts.map +1 -1
  91. package/dist/studio/StudioLogger.js +2 -1
  92. package/dist/studio/StudioLogger.js.map +1 -1
  93. package/dist/studio/StudioStore.d.ts +3 -0
  94. package/dist/studio/StudioStore.d.ts.map +1 -1
  95. package/dist/studio/StudioStore.js +13 -0
  96. package/dist/studio/StudioStore.js.map +1 -1
  97. package/dist/studio/_Pretty.d.ts +4 -0
  98. package/dist/studio/_Pretty.d.ts.map +1 -0
  99. package/dist/studio/_Pretty.js +56 -0
  100. package/dist/studio/_Pretty.js.map +1 -0
  101. package/dist/studio/routes/errors/route.d.ts +2 -2
  102. package/dist/studio/routes/fiberDetail.d.ts +2 -2
  103. package/dist/studio/routes/fibers/route.d.ts +2 -2
  104. package/dist/studio/routes/layout.d.ts +2 -0
  105. package/dist/studio/routes/layout.d.ts.map +1 -1
  106. package/dist/studio/routes/layout.html +3 -12
  107. package/dist/studio/routes/layout.js +6 -1
  108. package/dist/studio/routes/layout.js.map +1 -1
  109. package/dist/studio/routes/logs/route.d.ts +2 -2
  110. package/dist/studio/routes/metrics/route.d.ts +2 -2
  111. package/dist/studio/routes/route.d.ts +2 -2
  112. package/dist/studio/routes/routes/route.d.ts +2 -2
  113. package/dist/studio/routes/services/route.d.ts +2 -2
  114. package/dist/studio/routes/system/route.d.ts +2 -2
  115. package/dist/studio/routes/traceDetail.d.ts +2 -2
  116. package/dist/studio/routes/traces/route.d.ts +2 -2
  117. package/dist/studio/routes/traces/route.d.ts.map +1 -1
  118. package/dist/studio/routes/traces/route.js +5 -2
  119. package/dist/studio/routes/traces/route.js.map +1 -1
  120. package/dist/studio/routes/tree.d.ts +22 -0
  121. package/dist/studio/routes/tree.d.ts.map +1 -1
  122. package/dist/studio/ui/Errors.d.ts +1 -1
  123. package/dist/studio/ui/Errors.js +1 -1
  124. package/dist/studio/ui/Errors.js.map +1 -1
  125. package/dist/studio/ui/Fibers.d.ts +2 -2
  126. package/dist/studio/ui/Fibers.d.ts.map +1 -1
  127. package/dist/studio/ui/Fibers.js +4 -3
  128. package/dist/studio/ui/Fibers.js.map +1 -1
  129. package/dist/studio/ui/Logs.d.ts +1 -1
  130. package/dist/studio/ui/Logs.d.ts.map +1 -1
  131. package/dist/studio/ui/Logs.js +2 -1
  132. package/dist/studio/ui/Logs.js.map +1 -1
  133. package/dist/studio/ui/Metrics.d.ts +1 -1
  134. package/dist/studio/ui/Routes.d.ts +1 -1
  135. package/dist/studio/ui/Routes.d.ts.map +1 -1
  136. package/dist/studio/ui/Services.d.ts +1 -1
  137. package/dist/studio/ui/Services.d.ts.map +1 -1
  138. package/dist/studio/ui/Shell.d.ts +2 -2
  139. package/dist/studio/ui/Shell.d.ts.map +1 -1
  140. package/dist/studio/ui/System.d.ts +1 -1
  141. package/dist/studio/ui/Traces.d.ts +3 -3
  142. package/dist/studio/ui/Traces.d.ts.map +1 -1
  143. package/dist/studio/ui/Traces.js +5 -11
  144. package/dist/studio/ui/Traces.js.map +1 -1
  145. package/dist/studio/ui/_PrettyValue.d.ts +10 -0
  146. package/dist/studio/ui/_PrettyValue.d.ts.map +1 -0
  147. package/dist/studio/ui/_PrettyValue.js +27 -0
  148. package/dist/studio/ui/_PrettyValue.js.map +1 -0
  149. package/dist/tailwind/TailwindPlugin.d.ts.map +1 -1
  150. package/dist/tailwind/TailwindPlugin.js +89 -62
  151. package/dist/tailwind/TailwindPlugin.js.map +1 -1
  152. package/dist/ts/import-plugin.cjs +388 -0
  153. package/dist/ts/import-plugin.cjs.map +1 -0
  154. package/dist/ts/import-plugin.d.cts +87 -0
  155. package/dist/ts/import-plugin.d.cts.map +1 -0
  156. package/dist/ts/import-plugin.d.ts +87 -0
  157. package/dist/ts/import-plugin.d.ts.map +1 -0
  158. package/dist/ts/import-plugin.js +390 -0
  159. package/dist/ts/import-plugin.js.map +1 -0
  160. package/package.json +109 -8
  161. package/src/Entity.ts +62 -8
  162. package/src/Fetch.ts +1 -1
  163. package/src/FileRouterCodegen.ts +2 -2
  164. package/src/Html.ts +28 -21
  165. package/src/Route.ts +2 -2
  166. package/src/RouteBody.ts +2 -2
  167. package/src/RouteHttp.ts +45 -47
  168. package/src/RouteMount.ts +23 -65
  169. package/src/Start.ts +4 -0
  170. package/src/StaticFiles.ts +7 -10
  171. package/src/bun/BunRoute.ts +117 -95
  172. package/src/bun/BunServer.ts +9 -2
  173. package/src/datastar/README.md +24 -8
  174. package/src/datastar/attributes/computed.ts +3 -3
  175. package/src/datastar/attributes/on.ts +11 -37
  176. package/src/datastar/engine.ts +61 -37
  177. package/src/datastar/jsx.d.ts +12 -26
  178. package/src/datastar/types.d.ts +8 -0
  179. package/src/experimental/KeyValueStore.ts +161 -0
  180. package/src/{sql → experimental}/SqlCache.ts +1 -1
  181. package/src/{sql → experimental}/SqlIntrospect.ts +1 -1
  182. package/src/index.ts +1 -0
  183. package/src/jsx-runtime.ts +1 -1
  184. package/src/jsx.d.ts +17 -2
  185. package/src/lint/plugin.js +54 -19
  186. package/src/sql/index.ts +0 -2
  187. package/src/studio/StudioLogger.ts +2 -1
  188. package/src/studio/StudioStore.ts +18 -0
  189. package/src/studio/_Pretty.ts +59 -0
  190. package/src/studio/routes/layout.html +3 -12
  191. package/src/studio/routes/layout.tsx +9 -1
  192. package/src/studio/routes/traces/route.tsx +5 -1
  193. package/src/studio/ui/Errors.tsx +1 -1
  194. package/src/studio/ui/Fibers.tsx +14 -10
  195. package/src/studio/ui/Logs.tsx +15 -10
  196. package/src/studio/ui/Traces.tsx +40 -68
  197. package/src/studio/ui/_PrettyValue.tsx +34 -0
  198. package/src/tailwind/TailwindPlugin.ts +102 -75
  199. package/src/RouteTrie.ts +0 -205
  200. package/src/experimental/index.ts +0 -1
@@ -0,0 +1,161 @@
1
+ import * as Context from "effect/Context"
2
+ import * as Data from "effect/Data"
3
+ import * as Effect from "effect/Effect"
4
+ import * as Either from "effect/Either"
5
+ import * as Encoding from "effect/Encoding"
6
+ import * as Function from "effect/Function"
7
+ import * as Layer from "effect/Layer"
8
+ import * as Predicate from "effect/Predicate"
9
+
10
+ const TypeId = "effect-start/KeyValueStore" as const
11
+
12
+ export interface KeyValueStore {
13
+ readonly [TypeId]: typeof TypeId
14
+ readonly get: (key: string) => Effect.Effect<string | undefined, KeyValueStoreError>
15
+ readonly getUint8Array: (key: string) => Effect.Effect<Uint8Array | undefined, KeyValueStoreError>
16
+ readonly set: (key: string, value: string | Uint8Array) => Effect.Effect<void, KeyValueStoreError>
17
+ readonly remove: (key: string) => Effect.Effect<void, KeyValueStoreError>
18
+ readonly clear: Effect.Effect<void, KeyValueStoreError>
19
+ readonly size: Effect.Effect<number, KeyValueStoreError>
20
+ readonly modify: (
21
+ key: string,
22
+ f: (value: string) => string,
23
+ ) => Effect.Effect<string | undefined, KeyValueStoreError>
24
+ readonly modifyUint8Array: (
25
+ key: string,
26
+ f: (value: Uint8Array) => Uint8Array,
27
+ ) => Effect.Effect<Uint8Array | undefined, KeyValueStoreError>
28
+ readonly has: (key: string) => Effect.Effect<boolean, KeyValueStoreError>
29
+ readonly isEmpty: Effect.Effect<boolean, KeyValueStoreError>
30
+ }
31
+
32
+ type MakeOptions = Partial<KeyValueStore> & {
33
+ readonly get: (key: string) => Effect.Effect<string | undefined, KeyValueStoreError>
34
+ readonly getUint8Array: (key: string) => Effect.Effect<Uint8Array | undefined, KeyValueStoreError>
35
+ readonly set: (key: string, value: string | Uint8Array) => Effect.Effect<void, KeyValueStoreError>
36
+ readonly remove: (key: string) => Effect.Effect<void, KeyValueStoreError>
37
+ readonly clear: Effect.Effect<void, KeyValueStoreError>
38
+ readonly size: Effect.Effect<number, KeyValueStoreError>
39
+ }
40
+
41
+ type MakeStringOptions = Partial<Omit<KeyValueStore, "set">> & {
42
+ readonly get: (key: string) => Effect.Effect<string | undefined, KeyValueStoreError>
43
+ readonly set: (key: string, value: string) => Effect.Effect<void, KeyValueStoreError>
44
+ readonly remove: (key: string) => Effect.Effect<void, KeyValueStoreError>
45
+ readonly clear: Effect.Effect<void, KeyValueStoreError>
46
+ readonly size: Effect.Effect<number, KeyValueStoreError>
47
+ }
48
+
49
+ export class KeyValueStoreError extends Data.TaggedError("KeyValueStoreError")<{
50
+ message: string
51
+ method: string
52
+ key?: string
53
+ cause?: unknown
54
+ }> {}
55
+
56
+ export const KeyValueStore: Context.Tag<KeyValueStore, KeyValueStore> = Context.GenericTag<KeyValueStore>(
57
+ "effect-start/KeyValueStore",
58
+ )
59
+
60
+ const make = (options: MakeOptions): KeyValueStore => ({
61
+ [TypeId]: TypeId,
62
+ has: (key) => Effect.map(options.get(key), Predicate.isNotUndefined),
63
+ isEmpty: Effect.map(options.size, (size) => size === 0),
64
+ modify: (key, f) =>
65
+ Effect.flatMap(options.get(key), (o) => {
66
+ if (o === undefined) return Effect.succeed(undefined)
67
+ const newValue = f(o)
68
+ return Effect.as(options.set(key, newValue), newValue)
69
+ }),
70
+ modifyUint8Array: (key, f) =>
71
+ Effect.flatMap(options.getUint8Array(key), (o) => {
72
+ if (o === undefined) return Effect.succeed(undefined)
73
+ const newValue = f(o)
74
+ return Effect.as(options.set(key, newValue), newValue)
75
+ }),
76
+ ...options,
77
+ })
78
+
79
+ const makeStringOnly = (options: MakeStringOptions): KeyValueStore => {
80
+ const encoder = new TextEncoder()
81
+ return make({
82
+ ...options,
83
+ getUint8Array: (key) =>
84
+ Effect.map(options.get(key), (value) => {
85
+ if (value === undefined) return undefined
86
+ const decoded = Encoding.decodeBase64(value)
87
+ return Either.isRight(decoded) ? decoded.right : encoder.encode(value)
88
+ }),
89
+ set: (key, value) =>
90
+ typeof value === "string"
91
+ ? options.set(key, value)
92
+ : Effect.suspend(() => options.set(key, Encoding.encodeBase64(value))),
93
+ })
94
+ }
95
+
96
+ export const prefix: {
97
+ (prefix: string): (self: KeyValueStore) => KeyValueStore
98
+ (self: KeyValueStore, prefix: string): KeyValueStore
99
+ } = Function.dual(2, (self: KeyValueStore, prefix: string): KeyValueStore => ({
100
+ ...self,
101
+ get: (key) => self.get(`${prefix}${key}`),
102
+ getUint8Array: (key) => self.getUint8Array(`${prefix}${key}`),
103
+ set: (key, value) => self.set(`${prefix}${key}`, value),
104
+ remove: (key) => self.remove(`${prefix}${key}`),
105
+ has: (key) => self.has(`${prefix}${key}`),
106
+ modify: (key, f) => self.modify(`${prefix}${key}`, f),
107
+ modifyUint8Array: (key, f) => self.modifyUint8Array(`${prefix}${key}`, f),
108
+ }))
109
+
110
+ export const layerMemory: Layer.Layer<KeyValueStore> = Layer.sync(KeyValueStore, () => {
111
+ const store = new Map<string, string | Uint8Array>()
112
+ const encoder = new TextEncoder()
113
+
114
+ return make({
115
+ get: (key: string) =>
116
+ Effect.sync(() => {
117
+ const value = store.get(key)
118
+ return value === undefined ? undefined : typeof value === "string" ? value : Encoding.encodeBase64(value)
119
+ }),
120
+ getUint8Array: (key: string) =>
121
+ Effect.sync(() => {
122
+ const value = store.get(key)
123
+ return value === undefined ? undefined : typeof value === "string" ? encoder.encode(value) : value
124
+ }),
125
+ set: (key: string, value: string | Uint8Array) => Effect.sync(() => store.set(key, value)),
126
+ remove: (key: string) => Effect.sync(() => store.delete(key)),
127
+ clear: Effect.sync(() => store.clear()),
128
+ size: Effect.sync(() => store.size),
129
+ })
130
+ })
131
+
132
+ export const layerStorage = (evaluate: Function.LazyArg<Storage>): Layer.Layer<KeyValueStore> =>
133
+ Layer.sync(KeyValueStore, () => {
134
+ const storage = evaluate()
135
+ return makeStringOnly({
136
+ get: (key: string) =>
137
+ Effect.try({
138
+ try: () => storage.getItem(key) ?? undefined,
139
+ catch: () => new KeyValueStoreError({ key, method: "get", message: `Unable to get item with key ${key}` }),
140
+ }),
141
+ set: (key: string, value: string) =>
142
+ Effect.try({
143
+ try: () => storage.setItem(key, value),
144
+ catch: () => new KeyValueStoreError({ key, method: "set", message: `Unable to set item with key ${key}` }),
145
+ }),
146
+ remove: (key: string) =>
147
+ Effect.try({
148
+ try: () => storage.removeItem(key),
149
+ catch: () =>
150
+ new KeyValueStoreError({ key, method: "remove", message: `Unable to remove item with key ${key}` }),
151
+ }),
152
+ clear: Effect.try({
153
+ try: () => storage.clear(),
154
+ catch: () => new KeyValueStoreError({ method: "clear", message: `Unable to clear storage` }),
155
+ }),
156
+ size: Effect.try({
157
+ try: () => storage.length,
158
+ catch: () => new KeyValueStoreError({ method: "size", message: `Unable to get size` }),
159
+ }),
160
+ })
161
+ })
@@ -3,7 +3,7 @@ import * as Context from "effect/Context"
3
3
  import type * as Duration from "effect/Duration"
4
4
  import * as Effect from "effect/Effect"
5
5
  import * as Layer from "effect/Layer"
6
- import type * as SqlClient from "./SqlClient.ts"
6
+ import type * as SqlClient from "../sql/SqlClient.ts"
7
7
 
8
8
  type SqlCacheInstance = Cache.Cache<string, ReadonlyArray<any>>
9
9
 
@@ -1,6 +1,6 @@
1
1
  import * as Effect from "effect/Effect"
2
2
  import * as Schema from "effect/Schema"
3
- import * as SqlClient from "./SqlClient.ts"
3
+ import * as SqlClient from "../sql/SqlClient.ts"
4
4
 
5
5
  export interface Column {
6
6
  readonly tableSchema: string
package/src/index.ts CHANGED
@@ -8,3 +8,4 @@ export * as Route from "./Route.ts"
8
8
  export * as Start from "./Start.ts"
9
9
  export * as System from "./System.ts"
10
10
  export * as Unique from "./Unique.ts"
11
+ export * as Cookies from "./Cookies.ts"
@@ -1,5 +1,5 @@
1
1
  import * as Html from "./Html.ts"
2
- import type { JSX } from "./jsx.d.ts"
2
+ import type { JSX } from "../src/jsx.d.ts"
3
3
 
4
4
  function Fragment(props: { children: JSX.Element }) {
5
5
  return props.children
package/src/jsx.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import type * as Html from "./Html.ts"
2
1
  import type { DatastarAttributes } from "./datastar/jsx.d.ts"
3
2
 
4
3
  /**
@@ -16,8 +15,24 @@ import type { DatastarAttributes } from "./datastar/jsx.d.ts"
16
15
  */
17
16
  type DOMElement = never
18
17
 
18
+ type HtmlPrimitive = string | number | boolean | null | undefined
19
+ export type HtmlElementType = string | HtmlComponent
20
+ export type HtmlElemenetProps = {
21
+ [key: string]:
22
+ | HtmlPrimitive
23
+ | HtmlElement
24
+ | Iterable<HtmlPrimitive | HtmlElement>
25
+ | Record<string, unknown>
26
+ | ((window: Window) => void)
27
+ }
28
+ export type HtmlComponent = (props: HtmlElemenetProps) => HtmlElement | HtmlPrimitive
29
+ export interface HtmlElement {
30
+ type: HtmlElementType
31
+ props: HtmlElemenetProps
32
+ }
33
+
19
34
  export namespace JSX {
20
- type Element = Html.Element
35
+ type Element = HtmlElement
21
36
  type Child = Element | string | number | bigint
22
37
  type Children = Child | SilentChild | Iterable<Children>
23
38
 
@@ -146,35 +146,39 @@ export default {
146
146
  },
147
147
  },
148
148
 
149
- // this doens't work reliably and may cause runtime errors
150
- "export-default-before-functions": {
149
+ "schema-type-helpers": {
151
150
  meta: {
152
151
  type: "suggestion",
153
152
  docs: {
154
- description: "Enforce export default appears before any function declarations",
153
+ description:
154
+ "Prefer `typeof User.Type` over `Schema.Schema.Type<typeof User>`",
155
155
  },
156
+ fixable: "code",
156
157
  schema: [],
157
158
  messages: {
158
- defaultAfterFunction: "export default should appear before function declarations",
159
+ preferTypeof:
160
+ 'Use `typeof {{name}}.Type` instead of `Schema.Schema.Type<typeof {{name}}>`',
159
161
  },
160
162
  },
161
163
  create(context) {
164
+ function walk(node) {
165
+ if (!node || typeof node !== "object") return
166
+ if (Array.isArray(node)) {
167
+ for (const child of node) walk(child)
168
+ return
169
+ }
170
+ if (node.type === "TSTypeReference") {
171
+ checkTypeRef(context, node)
172
+ return
173
+ }
174
+ for (const key of Object.keys(node)) {
175
+ if (key === "parent") continue
176
+ walk(node[key])
177
+ }
178
+ }
162
179
  return {
163
- Program(node) {
164
- let seenFunction = false
165
-
166
- for (const stmt of node.body) {
167
- if (!seenFunction && isFunction(stmt)) {
168
- seenFunction = true
169
- }
170
-
171
- if (seenFunction && stmt.type === "ExportDefaultDeclaration") {
172
- context.report({
173
- node: stmt,
174
- messageId: "defaultAfterFunction",
175
- })
176
- }
177
- }
180
+ TSTypeAliasDeclaration(node) {
181
+ walk(node.typeAnnotation)
178
182
  },
179
183
  }
180
184
  },
@@ -579,6 +583,37 @@ export default {
579
583
  },
580
584
  }
581
585
 
586
+ function checkTypeRef(context, node) {
587
+ const typeName = node.typeName
588
+ if (typeName.type !== "TSQualifiedName") return
589
+ if (typeName.right.type !== "Identifier" || typeName.right.name !== "Type") return
590
+
591
+ const mid = typeName.left
592
+ if (mid.type !== "TSQualifiedName") return
593
+ if (mid.right.type !== "Identifier" || mid.right.name !== "Schema") return
594
+ if (mid.left.type !== "Identifier" || mid.left.name !== "Schema") return
595
+
596
+ const args = node.typeArguments
597
+ if (!args || args.params.length !== 1) return
598
+
599
+ const param = args.params[0]
600
+ if (param.type !== "TSTypeQuery") return
601
+
602
+ const exprName = param.exprName
603
+ if (exprName.type !== "Identifier") return
604
+
605
+ const name = exprName.name
606
+
607
+ context.report({
608
+ node,
609
+ messageId: "preferTypeof",
610
+ data: { name },
611
+ fix(fixer) {
612
+ return fixer.replaceTextRange(node.range, "typeof " + name + ".Type")
613
+ },
614
+ })
615
+ }
616
+
582
617
  function getBaseName(source) {
583
618
  // Handle node: and bun: protocols
584
619
  if (source.startsWith("node:")) {
package/src/sql/index.ts CHANGED
@@ -1,3 +1 @@
1
- export * as SqlCache from "./SqlCache.ts"
2
1
  export * as SqlClient from "./SqlClient.ts"
3
- export * as SqlIntrospect from "./SqlIntrospect.ts"
@@ -5,6 +5,7 @@ import * as HashMap from "effect/HashMap"
5
5
  import * as List from "effect/List"
6
6
  import * as Logger from "effect/Logger"
7
7
  import * as PubSub from "effect/PubSub"
8
+ import * as Pretty from "./_Pretty.ts"
8
9
  import * as StudioStore from "./StudioStore.ts"
9
10
 
10
11
  const studioLogger = Logger.make((options) => {
@@ -32,7 +33,7 @@ const studioLogger = Logger.make((options) => {
32
33
  const log: StudioStore.StudioLog = {
33
34
  id: StudioStore.nextLogId(),
34
35
  level,
35
- message: String(options.message),
36
+ message: Pretty.formatLogMessage(options.message),
36
37
  fiberId: FiberId.threadName(options.fiberId),
37
38
  cause: causeStr,
38
39
  spans: spanNames,
@@ -32,6 +32,24 @@ export const nextSpanId = () => nextPackedId()
32
32
 
33
33
  export const nextTraceId = () => nextPackedId()
34
34
 
35
+ export const studioTraceAttribute = "effect-start.studio.internal"
36
+
37
+ export function isStudioTrace(spans: Array<StudioSpan>): boolean {
38
+ return spans.some((span) => span.attributes[studioTraceAttribute] === true)
39
+ }
40
+
41
+ export function filterOutStudioSpans(spans: Array<StudioSpan>): Array<StudioSpan> {
42
+ const hiddenTraceIds = new Set<bigint>()
43
+
44
+ for (const span of spans) {
45
+ if (span.attributes[studioTraceAttribute] === true) {
46
+ hiddenTraceIds.add(span.traceId)
47
+ }
48
+ }
49
+
50
+ return spans.filter((span) => !hiddenTraceIds.has(span.traceId))
51
+ }
52
+
35
53
  export interface StudioSpan {
36
54
  readonly spanId: bigint
37
55
  readonly traceId: bigint
@@ -0,0 +1,59 @@
1
+ function jsonReplacer() {
2
+ const seen = new WeakSet<object>()
3
+
4
+ return (_key: string, value: unknown): unknown => {
5
+ if (typeof value === "bigint") return String(value)
6
+ if (value instanceof Error) {
7
+ return {
8
+ name: value.name,
9
+ message: value.message,
10
+ stack: value.stack,
11
+ }
12
+ }
13
+ if (value !== null && typeof value === "object") {
14
+ if (seen.has(value)) return "[Circular]"
15
+ seen.add(value)
16
+ }
17
+ return value
18
+ }
19
+ }
20
+
21
+ export function isStructuredValue(value: unknown): value is object {
22
+ return value !== null && typeof value === "object"
23
+ }
24
+
25
+ export function prettyPrintJson(value: unknown): string {
26
+ try {
27
+ const json = JSON.stringify(value, jsonReplacer(), 2)
28
+ return json ?? String(value)
29
+ } catch {
30
+ return String(value)
31
+ }
32
+ }
33
+
34
+ export function formatLogMessage(message: unknown): string {
35
+ if (!Array.isArray(message)) {
36
+ return isStructuredValue(message) ? prettyPrintJson(message) : String(message)
37
+ }
38
+
39
+ const lines: Array<string> = []
40
+ let inlineParts: Array<string> = []
41
+
42
+ for (const part of message) {
43
+ if (isStructuredValue(part)) {
44
+ if (inlineParts.length > 0) {
45
+ lines.push(inlineParts.join(" "))
46
+ inlineParts = []
47
+ }
48
+ lines.push(prettyPrintJson(part))
49
+ } else {
50
+ inlineParts.push(String(part))
51
+ }
52
+ }
53
+
54
+ if (inlineParts.length > 0) {
55
+ lines.push(inlineParts.join(" "))
56
+ }
57
+
58
+ return lines.join("\n")
59
+ }
@@ -261,21 +261,12 @@
261
261
  }
262
262
  .tl-row {
263
263
  border-bottom: 1px solid #1e293b;
264
+ color: inherit;
265
+ text-decoration: none;
264
266
  }
265
- .tl-row[open] {
267
+ .tl-row:hover {
266
268
  background: #111827;
267
269
  }
268
- .tl-summary {
269
- cursor: pointer;
270
- user-select: none;
271
- list-style: none;
272
- }
273
- .tl-summary::-webkit-details-marker {
274
- display: none;
275
- }
276
- .tl-summary:hover {
277
- background: #1e293b;
278
- }
279
270
  .tl-cell {
280
271
  padding: 6px 8px;
281
272
  display: flex;
@@ -1,4 +1,12 @@
1
+ import * as Effect from "effect/Effect"
1
2
  import * as BunRoute from "../../bun/BunRoute.ts"
2
3
  import * as Route from "../../Route.ts"
4
+ import * as StudioStore from "../StudioStore.ts"
3
5
 
4
- export default Route.use(BunRoute.htmlBundle(() => import("./layout.html")))
6
+ export default Route.use(
7
+ Route.filter(function* () {
8
+ yield* Effect.annotateCurrentSpan(StudioStore.studioTraceAttribute, true)
9
+ return { context: {} }
10
+ }),
11
+ BunRoute.htmlBundle(() => import("./layout.html")),
12
+ )
@@ -12,7 +12,7 @@ export default Route.get(
12
12
  Route.html(function* (ctx) {
13
13
  const url = new URL(ctx.request.url)
14
14
  const search = url.searchParams.get("traceSearch") || ""
15
- const allSpans = yield* StudioStore.allSpans()
15
+ const allSpans = StudioStore.filterOutStudioSpans(yield* StudioStore.allSpans())
16
16
  const names = Array.from(new Set(allSpans.map((s) => s.name))).sort()
17
17
  let spans = allSpans
18
18
  if (search) {
@@ -56,6 +56,9 @@ export default Route.get(
56
56
  Stream.mapEffect((e) =>
57
57
  Effect.gen(function* () {
58
58
  const traceSpans = yield* StudioStore.spansByTraceId(e.traceId)
59
+ if (StudioStore.isStudioTrace(traceSpans)) {
60
+ return undefined
61
+ }
59
62
  const traceHtml = Html.renderToString(
60
63
  <Traces.TraceGroup id={e.traceId} spans={traceSpans} />,
61
64
  )
@@ -66,6 +69,7 @@ export default Route.get(
66
69
  }
67
70
  }),
68
71
  ),
72
+ Stream.filter((event): event is { event: string; data: string } => event !== undefined),
69
73
  ),
70
74
  ),
71
75
  )
@@ -31,7 +31,7 @@ export function ErrorLine(options: { error: StudioStore.StudioError }) {
31
31
  <span style="color:#64748b">tag </span>
32
32
  <span
33
33
  style="color:#fca5a5;text-decoration:underline;cursor:copy"
34
- data-on:click={`(e) => { e.signals.errorTag.value = '${t}'; e.actions.get(location.href, { contentType: 'form' }) }`}
34
+ data-on:click={`(e) => { e.signals.errorTag = '${t}'; e.actions.get(location.href, { contentType: 'form' }) }`}
35
35
  >
36
36
  {t}
37
37
  </span>
@@ -1,6 +1,7 @@
1
1
  import * as Unique from "../../Unique.ts"
2
2
  import * as StudioStore from "../StudioStore.ts"
3
3
  import * as Logs from "./Logs.tsx"
4
+ import * as PrettyValue from "./_PrettyValue.tsx"
4
5
 
5
6
  function formatDuration(ms: number | undefined): string {
6
7
  if (ms == null) return "..."
@@ -9,14 +10,20 @@ function formatDuration(ms: number | undefined): string {
9
10
  return `${(ms / 1000).toFixed(2)}s`
10
11
  }
11
12
 
12
- function KeyValue(options: { label: string; value: string | number | bigint | undefined | null }) {
13
+ function KeyValue(options: { label: string; value: unknown }) {
13
14
  if (options.value == null) return null
14
15
  return (
15
- <div style="display:flex;gap:8px;padding:4px 0;border-bottom:1px solid #1e293b;font-size:12px">
16
+ <div
17
+ style="display:flex;align-items:flex-start;gap:8px;padding:4px 0;border-bottom:1px solid #1e293b;font-size:12px"
18
+ >
16
19
  <span style="color:#64748b;min-width:120px">{options.label}</span>
17
- <span style="color:#e2e8f0;font-family:monospace;word-break:break-all">
18
- {String(options.value)}
19
- </span>
20
+ <div style="flex:1;min-width:0">
21
+ <PrettyValue.PrettyValue
22
+ value={options.value}
23
+ style="color:#e2e8f0;font-family:monospace;word-break:break-all"
24
+ preStyle="color:#e2e8f0;font-family:monospace;word-break:break-all;white-space:pre-wrap;margin:0"
25
+ />
26
+ </div>
20
27
  </div>
21
28
  )
22
29
  }
@@ -276,10 +283,7 @@ export function FiberDetail(options: {
276
283
  </div>
277
284
  )}
278
285
  {Object.entries(options.context.annotations).map(([k, v]) => (
279
- <KeyValue
280
- label={k}
281
- value={typeof v === "object" ? JSON.stringify(v) : String(v)}
282
- />
286
+ <KeyValue label={k} value={v} />
283
287
  ))}
284
288
  </div>
285
289
  </div>
@@ -310,7 +314,7 @@ export function FiberDetail(options: {
310
314
  {Object.entries(s.attributes)
311
315
  .filter(([k]) => k !== "code.stacktrace")
312
316
  .map(([k, v]) => (
313
- <KeyValue label={k} value={String(v)} />
317
+ <KeyValue label={k} value={v} />
314
318
  ))}
315
319
  </div>
316
320
  )
@@ -1,5 +1,6 @@
1
1
  import * as Unique from "../../Unique.ts"
2
2
  import * as StudioStore from "../StudioStore.ts"
3
+ import * as PrettyValue from "./_PrettyValue.tsx"
3
4
 
4
5
  function levelColor(level: string): string {
5
6
  if (level === "DEBUG") return "#94a3b8"
@@ -25,26 +26,30 @@ export function LogLine(options: { log: StudioStore.StudioLog }) {
25
26
  return (
26
27
  <div
27
28
  id={`log-${options.log.id}`}
28
- style="padding:3px 8px;border-bottom:1px solid #1f2937;font-family:monospace;font-size:12px;display:flex;align-items:baseline"
29
+ style="padding:6px 8px;border-bottom:1px solid #1f2937;font-family:monospace;font-size:12px;display:flex;align-items:flex-start;gap:8px"
29
30
  >
30
31
  <span style="color:#6b7280;white-space:nowrap">{time}</span>
31
32
  <span style={`color:${color};font-weight:600;width:56px;text-align:center;flex-shrink:0`}>
32
33
  {options.log.level}
33
34
  </span>
34
- <span style="color:#e5e7eb;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis">
35
- {options.log.message}
36
- </span>
35
+ <div style="flex:1;min-width:0;display:flex;flex-direction:column;gap:4px">
36
+ <PrettyValue.PreformattedText
37
+ text={options.log.message}
38
+ style="color:#e5e7eb;margin:0;white-space:pre-wrap;word-break:break-word;font:inherit"
39
+ />
40
+ {options.log.cause && (
41
+ <PrettyValue.PreformattedText
42
+ text={options.log.cause}
43
+ style="color:#ef4444;font-size:11px;margin:0;white-space:pre-wrap;word-break:break-word;font:inherit"
44
+ />
45
+ )}
46
+ </div>
37
47
  <a
38
48
  href={`${StudioStore.store.prefix}/fibers/${options.log.fiberId.replace("#", "")}`}
39
- style="color:#6b7280;white-space:nowrap;margin-left:8px;text-decoration:none"
49
+ style="color:#6b7280;white-space:nowrap;text-decoration:none;flex-shrink:0"
40
50
  >
41
51
  {options.log.fiberId}
42
52
  </a>
43
- {options.log.cause && (
44
- <div style="color:#ef4444;font-size:11px;padding:2px 0 0 0;white-space:pre-wrap;width:100%">
45
- {options.log.cause}
46
- </div>
47
- )}
48
53
  </div>
49
54
  )
50
55
  }