kiru 1.4.0 → 1.5.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 (110) hide show
  1. package/dist/components/derive.d.ts +1 -1
  2. package/dist/components/derive.d.ts.map +1 -1
  3. package/dist/constants.d.ts +2 -1
  4. package/dist/constants.d.ts.map +1 -1
  5. package/dist/constants.js +2 -1
  6. package/dist/constants.js.map +1 -1
  7. package/dist/devtools.d.ts +1 -1
  8. package/dist/devtools.d.ts.map +1 -1
  9. package/dist/dom/nodes.d.ts +1 -1
  10. package/dist/dom/nodes.d.ts.map +1 -1
  11. package/dist/dom/nodes.js.map +1 -1
  12. package/dist/dom/props.js.map +1 -1
  13. package/dist/globalContext.d.ts +2 -2
  14. package/dist/globalContext.d.ts.map +1 -1
  15. package/dist/headlessRender.d.ts.map +1 -1
  16. package/dist/headlessRender.js +3 -0
  17. package/dist/headlessRender.js.map +1 -1
  18. package/dist/hooks/onCleanup.d.ts.map +1 -1
  19. package/dist/hooks/onCleanup.js +3 -1
  20. package/dist/hooks/onCleanup.js.map +1 -1
  21. package/dist/hooks/setup.d.ts.map +1 -1
  22. package/dist/hooks/setup.js +108 -63
  23. package/dist/hooks/setup.js.map +1 -1
  24. package/dist/hooks/utils.d.ts.map +1 -1
  25. package/dist/hooks/utils.js +2 -1
  26. package/dist/hooks/utils.js.map +1 -1
  27. package/dist/hydration.d.ts +1 -1
  28. package/dist/hydration.d.ts.map +1 -1
  29. package/dist/index.d.ts +1 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/profiling.d.ts +1 -1
  32. package/dist/profiling.d.ts.map +1 -1
  33. package/dist/reconciler.d.ts.map +1 -1
  34. package/dist/reconciler.js +38 -6
  35. package/dist/reconciler.js.map +1 -1
  36. package/dist/resource.d.ts +11 -5
  37. package/dist/resource.d.ts.map +1 -1
  38. package/dist/resource.js +83 -39
  39. package/dist/resource.js.map +1 -1
  40. package/dist/router/client/index.d.ts +1 -1
  41. package/dist/router/client/index.d.ts.map +1 -1
  42. package/dist/router/globals.d.ts +2 -2
  43. package/dist/router/globals.d.ts.map +1 -1
  44. package/dist/router/link.d.ts +1 -1
  45. package/dist/router/link.d.ts.map +1 -1
  46. package/dist/router/pageConfig.d.ts +1 -1
  47. package/dist/router/pageConfig.d.ts.map +1 -1
  48. package/dist/router/types.d.ts +3 -3
  49. package/dist/router/types.d.ts.map +1 -1
  50. package/dist/router/types.internal.d.ts +2 -2
  51. package/dist/router/types.internal.d.ts.map +1 -1
  52. package/dist/router/utils/index.d.ts +2 -2
  53. package/dist/router/utils/index.d.ts.map +1 -1
  54. package/dist/scheduler.d.ts.map +1 -1
  55. package/dist/scheduler.js +15 -2
  56. package/dist/scheduler.js.map +1 -1
  57. package/dist/signals/base.d.ts +1 -0
  58. package/dist/signals/base.d.ts.map +1 -1
  59. package/dist/signals/base.js +14 -2
  60. package/dist/signals/base.js.map +1 -1
  61. package/dist/signals/effect.d.ts.map +1 -1
  62. package/dist/signals/effect.js +8 -0
  63. package/dist/signals/effect.js.map +1 -1
  64. package/dist/signals/tracking.d.ts.map +1 -1
  65. package/dist/signals/tracking.js +13 -14
  66. package/dist/signals/tracking.js.map +1 -1
  67. package/dist/ssr/client.d.ts +1 -1
  68. package/dist/ssr/client.d.ts.map +1 -1
  69. package/dist/types.d.ts +31 -7
  70. package/dist/types.d.ts.map +1 -1
  71. package/dist/types.dom.d.ts +190 -2
  72. package/dist/types.dom.d.ts.map +1 -1
  73. package/dist/types.utils.d.ts +28 -21
  74. package/dist/types.utils.d.ts.map +1 -1
  75. package/dist/utils/vdom.d.ts.map +1 -1
  76. package/dist/utils/vdom.js +5 -2
  77. package/dist/utils/vdom.js.map +1 -1
  78. package/package.json +1 -1
  79. package/src/components/derive.ts +1 -1
  80. package/src/constants.ts +2 -0
  81. package/src/devtools.ts +1 -1
  82. package/src/dom/commit.ts +1 -1
  83. package/src/dom/nodes.ts +8 -3
  84. package/src/dom/props.ts +6 -6
  85. package/src/globalContext.ts +2 -2
  86. package/src/headlessRender.ts +4 -1
  87. package/src/hooks/onCleanup.ts +3 -1
  88. package/src/hooks/setup.ts +133 -80
  89. package/src/hooks/utils.ts +2 -1
  90. package/src/hydration.ts +1 -1
  91. package/src/index.ts +1 -1
  92. package/src/profiling.ts +1 -1
  93. package/src/reconciler.ts +51 -9
  94. package/src/resource.ts +112 -44
  95. package/src/router/client/index.ts +2 -2
  96. package/src/router/globals.ts +2 -2
  97. package/src/router/link.ts +1 -1
  98. package/src/router/pageConfig.ts +1 -1
  99. package/src/router/types.internal.ts +2 -2
  100. package/src/router/types.ts +3 -3
  101. package/src/router/utils/index.ts +1 -1
  102. package/src/scheduler.ts +20 -3
  103. package/src/signals/base.ts +20 -2
  104. package/src/signals/effect.ts +8 -0
  105. package/src/signals/tracking.ts +17 -15
  106. package/src/ssr/client.ts +1 -1
  107. package/src/types.dom.ts +270 -53
  108. package/src/types.ts +36 -32
  109. package/src/types.utils.ts +56 -22
  110. package/src/utils/vdom.ts +7 -1
package/src/resource.ts CHANGED
@@ -1,23 +1,20 @@
1
1
  import { $HMR_ACCEPT, STREAMED_DATA_EVENT } from "./constants.js"
2
2
  import { hydrationMode, node, renderMode } from "./globals.js"
3
3
  import { Signal, signal } from "./signals/base.js"
4
+ import { executeWithTracking } from "./signals/tracking.js"
4
5
  import { createVNodeId, registerVNodeCleanup } from "./utils/vdom.js"
5
6
  import { generateRandomID } from "./utils/generateId.js"
6
7
  import { __DEV__, isBrowser } from "./env.js"
7
8
  import { GenericHMRAcceptor, performHmrAccept } from "./hmr.js"
8
9
 
9
- /**
10
- * Returns true if the value is a {@link Resource}
11
- */
12
- export function isResource(thing: unknown): thing is Resource<unknown> {
13
- return (
14
- Signal.isSignal(thing) &&
15
- "promise" in thing &&
16
- thing["promise"] instanceof Promise
17
- )
18
- }
10
+ export type ResourceSource = Record<string, Signal<unknown>> | Signal<unknown>
19
11
 
20
- const resourceMeta = new WeakMap<Kiru.VNode, { id: string; index: number }>()
12
+ type InnerOf<T> = T extends Kiru.Signal<infer V> ? V : never
13
+
14
+ type UnwrapResourceSource<T extends ResourceSource> =
15
+ T extends Kiru.Signal<unknown>
16
+ ? InnerOf<T>
17
+ : { [K in keyof T]: InnerOf<T[K]> }
21
18
 
22
19
  interface ResourceState<T> {
23
20
  error: Signal<Error | null>
@@ -32,14 +29,31 @@ export interface ResourceLoaderContext {
32
29
  signal: AbortSignal
33
30
  }
34
31
 
35
- export function resource<T, Source>(
36
- source: Kiru.Signal<Source>,
37
- callback: (source: Source, ctx: ResourceLoaderContext) => Promise<T>
32
+ const resourceMeta = new WeakMap<Kiru.VNode, { id: string; index: number }>()
33
+
34
+ export function resource<T>(
35
+ callback: (ctx: ResourceLoaderContext) => Promise<T>
36
+ ): Resource<T>
37
+ export function resource<T, Source extends ResourceSource>(
38
+ source: Source,
39
+ callback: (
40
+ source: UnwrapResourceSource<Source>,
41
+ ctx: ResourceLoaderContext
42
+ ) => Promise<T>
43
+ ): Resource<T>
44
+ export function resource<T, Source extends ResourceSource>(
45
+ callbackOrSource: Source | ((ctx: ResourceLoaderContext) => Promise<T>),
46
+ callback?: (
47
+ source: UnwrapResourceSource<Source>,
48
+ ctx: ResourceLoaderContext
49
+ ) => Promise<T>
38
50
  ): Resource<T> {
39
51
  const data = signal(void 0 as T)
40
52
  const error = signal<Error | null>(null)
41
53
  const isPending = signal(true)
42
54
 
55
+ let controller = new AbortController()
56
+
43
57
  let promiseId = ""
44
58
  const vNode = node.current
45
59
  if (!vNode) {
@@ -62,17 +76,34 @@ export function resource<T, Source>(
62
76
  promiseId = generateRandomID()
63
77
  }
64
78
 
65
- const unsub = source.subscribe((src) => {
66
- resource.promise = createPromise(src)
79
+ const updateResource = () => {
80
+ resource.promise = createPromise()
67
81
  resource.notify()
68
- })
82
+ }
69
83
 
70
- let controller = new AbortController()
84
+ let unsubFromSource: (() => void) | undefined
85
+ if (typeof callbackOrSource === "object") {
86
+ if (Signal.isSignal(callbackOrSource)) {
87
+ unsubFromSource = callbackOrSource.subscribe(updateResource)
88
+ } else {
89
+ const unsubs: (() => void)[] = []
90
+ for (const key in callbackOrSource) {
91
+ if (!Signal.isSignal(callbackOrSource[key])) continue
92
+ unsubs.push(callbackOrSource[key].subscribe(updateResource))
93
+ }
94
+ unsubFromSource = () => {
95
+ unsubs.forEach((unsub) => unsub())
96
+ }
97
+ }
98
+ }
99
+
100
+ const observedSignalUnsubs = new Map<string, () => void>()
71
101
  const dispose = () => {
72
102
  if (!controller.signal.aborted) controller.abort()
73
103
  Signal.dispose(data)
74
104
  Signal.dispose(isPending)
75
- unsub()
105
+ observedSignalUnsubs.forEach((unsub) => unsub())
106
+ unsubFromSource?.()
76
107
  }
77
108
 
78
109
  if (vNode) {
@@ -85,7 +116,7 @@ export function resource<T, Source>(
85
116
  promise: undefined as unknown as Kiru.StatefulPromise<T>,
86
117
  refetch() {
87
118
  data.value = void 0 as T
88
- this.promise = createPromise(source.peek())
119
+ this.promise = createPromise()
89
120
  },
90
121
  dispose,
91
122
  })
@@ -111,33 +142,38 @@ export function resource<T, Source>(
111
142
  }
112
143
  }
113
144
 
114
- if (__DEV__ && isBrowser && window.__kiru.HMRContext?.isReplacement()) {
115
- queueMicrotask(() => {
116
- resource.promise = createPromise(source.peek())
117
- })
118
- } else {
119
- resource.promise = createPromise(source.peek())
120
- }
121
-
122
- function createPromise(source: Source): Kiru.StatefulPromise<T> {
145
+ function createPromise(): Kiru.StatefulPromise<T> {
123
146
  controller.abort()
124
147
  const ctrl = (controller = new AbortController())
125
148
  isPending.value = true
126
- let newPromise: Promise<T>
127
- if (renderMode.current === "string") {
128
- // if we're rendering to a string, there's no need to fire the callback
129
- newPromise = Promise.resolve() as Promise<T>
130
- } else if (
131
- renderMode.current === "hydrate" &&
132
- hydrationMode.current === "dynamic"
133
- ) {
134
- // if we're hydrating and the hydration mode is not static,
135
- // we need to resolve the promise from cache/event
136
- newPromise = resolveDeferredPromise<T>(promiseId, ctrl.signal)
137
- } else {
138
- // stream / dom / (hydrate + static)
139
- newPromise = callback(source, { signal: ctrl.signal })
140
- }
149
+ const newPromise = executeWithTracking({
150
+ fn: () => {
151
+ let promise: Promise<T>
152
+ if (renderMode.current === "string") {
153
+ // if we're rendering to a string, there's no need to fire the callback
154
+ promise = Promise.resolve() as Promise<T>
155
+ } else if (
156
+ renderMode.current === "hydrate" &&
157
+ hydrationMode.current === "dynamic"
158
+ ) {
159
+ // if we're hydrating and the hydration mode is not static,
160
+ // we need to resolve the promise from cache/event
161
+ promise = resolveDeferredPromise<T>(promiseId, ctrl.signal)
162
+ } else {
163
+ // stream / dom / (hydrate + static)
164
+ if (typeof callbackOrSource === "function") {
165
+ promise = callbackOrSource({ signal: ctrl.signal })
166
+ } else {
167
+ const source = unwrapResourceSource(callbackOrSource)
168
+ promise = callback!(source, { signal: ctrl.signal })
169
+ }
170
+ }
171
+ return promise
172
+ },
173
+ id: Signal.id(resource),
174
+ onDepChanged: updateResource,
175
+ subs: observedSignalUnsubs,
176
+ })
141
177
 
142
178
  const statefulPromise: Kiru.StatefulPromise<T> = Object.assign(newPromise, {
143
179
  id: promiseId,
@@ -162,6 +198,12 @@ export function resource<T, Source>(
162
198
  return statefulPromise
163
199
  }
164
200
 
201
+ if (__DEV__ && isBrowser && window.__kiru.HMRContext?.isReplacement()) {
202
+ queueMicrotask(() => (resource.promise = createPromise()))
203
+ } else {
204
+ resource.promise = createPromise()
205
+ }
206
+
165
207
  return resource
166
208
  }
167
209
 
@@ -205,3 +247,29 @@ function resolveDeferredPromise<T>(
205
247
  })
206
248
  })
207
249
  }
250
+
251
+ /**
252
+ * Returns true if the value is a {@link Resource}
253
+ */
254
+ export function isResource(thing: unknown): thing is Resource<unknown> {
255
+ return (
256
+ Signal.isSignal(thing) &&
257
+ "promise" in thing &&
258
+ thing["promise"] instanceof Promise
259
+ )
260
+ }
261
+
262
+ function unwrapResourceSource<T extends ResourceSource>(
263
+ source: T
264
+ ): UnwrapResourceSource<T> {
265
+ if (Signal.isSignal(source)) {
266
+ return source.peek() as UnwrapResourceSource<T>
267
+ }
268
+ const out: Record<string, unknown> = {}
269
+ for (const key in source) {
270
+ if (Signal.isSignal(source[key])) {
271
+ out[key] = source[key].peek()
272
+ }
273
+ }
274
+ return out as UnwrapResourceSource<T>
275
+ }
@@ -9,8 +9,8 @@ import {
9
9
  match404Route,
10
10
  parseQuery,
11
11
  } from "../utils/index.js"
12
- import type { FormattedViteImportMap, PageModule } from "../types.internal"
13
- import type { FileRouterConfig, FileRouterPreloadConfig } from "../types"
12
+ import type { FormattedViteImportMap, PageModule } from "../types.internal.js"
13
+ import type { FileRouterConfig, FileRouterPreloadConfig } from "../types.js"
14
14
  import { fileRouterInstance, fileRouterRoute, routerCache } from "../globals.js"
15
15
  import { FileRouterController } from "../fileRouterController.js"
16
16
  import { FileRouterDataLoadError } from "../errors.js"
@@ -1,5 +1,5 @@
1
- import type { RouterCache } from "./cache"
2
- import type { FileRouterController } from "./fileRouterController"
1
+ import type { RouterCache } from "./cache.js"
2
+ import type { FileRouterController } from "./fileRouterController.js"
3
3
 
4
4
  export const fileRouterInstance = {
5
5
  current: null as FileRouterController | null,
@@ -1,4 +1,4 @@
1
- import type { ElementProps } from "../types"
1
+ import type { ElementProps } from "../types.js"
2
2
  import { createElement } from "../element.js"
3
3
  import { useFileRouter } from "./context.js"
4
4
 
@@ -1,6 +1,6 @@
1
1
  import { __DEV__, isBrowser } from "../env.js"
2
2
  import { fileRouterInstance } from "./globals.js"
3
- import type { PageConfig } from "./types"
3
+ import type { PageConfig } from "./types.js"
4
4
 
5
5
  export function definePageConfig<T>(config: PageConfig<T>): PageConfig<T> {
6
6
  if (__DEV__ && isBrowser) {
@@ -1,5 +1,5 @@
1
- import type { FileRouterContextType } from "./context"
2
- import type { PageConfig } from "./types"
1
+ import type { FileRouterContextType } from "./context.js"
2
+ import type { PageConfig } from "./types.js"
3
3
 
4
4
  export interface CurrentPage {
5
5
  component: Kiru.FC<any>
@@ -1,10 +1,10 @@
1
- import type { AsyncTaskState } from "../types.utils"
2
- import type { FileRouterDataLoadError } from "./errors"
1
+ import type { AsyncTaskState } from "../types.utils.js"
2
+ import type { FileRouterDataLoadError } from "./errors.js"
3
3
  import type {
4
4
  DefaultComponentModule,
5
5
  FormattedViteImportMap,
6
6
  PageModule,
7
- } from "./types.internal"
7
+ } from "./types.internal.js"
8
8
 
9
9
  export interface FileRouterPreloadConfig {
10
10
  pages: FormattedViteImportMap
@@ -4,7 +4,7 @@ import type {
4
4
  FormattedViteImportMap,
5
5
  RouteMatch,
6
6
  ViteImportMap,
7
- } from "../types.internal"
7
+ } from "../types.internal.js"
8
8
 
9
9
  export {
10
10
  formatViteImportMap,
package/src/scheduler.ts CHANGED
@@ -1,6 +1,12 @@
1
- import type { DomVNode, ErrorBoundaryNode, FunctionVNode } from "./types.utils"
1
+ import type {
2
+ DomVNode,
3
+ ErrorBoundaryNode,
4
+ FunctionVNode,
5
+ InlineFnNode,
6
+ } from "./types.utils.js"
2
7
  import {
3
8
  $ERROR_BOUNDARY,
9
+ $INLINE_FN,
4
10
  CONSECUTIVE_DIRTY_LIMIT,
5
11
  FLAG_DELETION,
6
12
  FLAG_DIRTY,
@@ -30,7 +36,7 @@ import { node, postEffectCleanups, renderMode, setups } from "./globals.js"
30
36
  import { hydrationStack } from "./hydration.js"
31
37
  import { reconcileChildren } from "./reconciler.js"
32
38
  import { isHmrUpdate } from "./hmr.js"
33
- import type { AppHandle } from "./appHandle"
39
+ import type { AppHandle } from "./appHandle.js"
34
40
 
35
41
  type VNode = Kiru.VNode
36
42
 
@@ -298,7 +304,18 @@ function updateExoticComponent(vNode: VNode): VNode | null {
298
304
  const { props, type } = vNode
299
305
  let children = props.children
300
306
 
301
- if (type === $ERROR_BOUNDARY) {
307
+ if (type === $INLINE_FN) {
308
+ node.current = vNode
309
+ let render = (props as InlineFnNode["props"]).expr
310
+ if (__DEV__) {
311
+ render = latest(render)
312
+ }
313
+ try {
314
+ children = render()
315
+ } finally {
316
+ node.current = null
317
+ }
318
+ } else if (type === $ERROR_BOUNDARY) {
302
319
  const n = vNode as ErrorBoundaryNode
303
320
  const { error } = n
304
321
  if (error) {
@@ -5,8 +5,14 @@ import {
5
5
  generateRandomID,
6
6
  registerVNodeCleanup,
7
7
  } from "../utils/index.js"
8
- import { $DEV_FILE_LINK, $HMR_ACCEPT, $SIGNAL } from "../constants.js"
8
+ import {
9
+ $DEV_FILE_LINK,
10
+ $HMR_ACCEPT,
11
+ $INLINE_FN,
12
+ $SIGNAL,
13
+ } from "../constants.js"
9
14
  import { __DEV__, isBrowser } from "../env.js"
15
+ import { KiruError } from "../error.js"
10
16
  import { node } from "../globals.js"
11
17
  import { requestUpdate } from "../scheduler.js"
12
18
  import { tracking } from "./tracking.js"
@@ -58,7 +64,15 @@ export class Signal<T> {
58
64
 
59
65
  const n = node.current
60
66
  if (n) {
61
- registerVNodeCleanup(n, this.$id, Signal.dispose.bind(null, this))
67
+ if (__DEV__ && n.type === $INLINE_FN) {
68
+ throw new KiruError({
69
+ message: "Signals cannot be created inside inline functions",
70
+ vNode: n,
71
+ })
72
+ }
73
+ if (sideEffectsEnabled()) {
74
+ registerVNodeCleanup(n, this.$id, Signal.dispose.bind(null, this))
75
+ }
62
76
  }
63
77
  }
64
78
 
@@ -151,6 +165,10 @@ export class Signal<T> {
151
165
  return typeof x === "object" && !!x && $SIGNAL in x
152
166
  }
153
167
 
168
+ static id(signal: Signal<any>) {
169
+ return signal.$id
170
+ }
171
+
154
172
  static subscribers(signal: Signal<any>) {
155
173
  return signal.$subs
156
174
  }
@@ -11,6 +11,8 @@ import {
11
11
  import type { Signal } from "./base.js"
12
12
  import type { SignalValues } from "./types.js"
13
13
  import { node } from "../globals.js"
14
+ import { $INLINE_FN } from "../constants.js"
15
+ import { KiruError } from "../error.js"
14
16
 
15
17
  type EffectCallbackReturn = (() => void) | void
16
18
 
@@ -37,6 +39,12 @@ export class Effect<const Deps extends readonly Signal<unknown>[] = []> {
37
39
  }
38
40
  const n = node.current
39
41
  if (n) {
42
+ if (__DEV__ && n.type === $INLINE_FN) {
43
+ throw new KiruError({
44
+ message: "Effects cannot be created inside inline functions",
45
+ vNode: n,
46
+ })
47
+ }
40
48
  if (!sideEffectsEnabled()) return // prevent side effects in non-browser environments
41
49
  registerVNodeCleanup(n, this.id, this.stop.bind(this))
42
50
  }
@@ -32,25 +32,19 @@ export function executeWithTracking<T, Deps extends readonly Signal<unknown>[]>(
32
32
  ctx: TrackedExecutionContext<T, Deps>
33
33
  ): T {
34
34
  const { id, subs, fn, deps = [], onDepChanged } = ctx
35
- let observations: Map<string, Signal<unknown>> | undefined
35
+ let observations: TrackingStackObservations | undefined
36
36
 
37
37
  effectQueue.delete(id)
38
- const isServer = !!node.current && !sideEffectsEnabled()
39
38
 
40
- if (!isServer) {
41
- observations = new Map<string, Signal<unknown>>()
39
+ // Prevent side effects in non-browser environments while rendering
40
+ if (!node.current || sideEffectsEnabled()) {
41
+ observations = new Map()
42
42
  tracking.stack.push(observations)
43
43
  }
44
44
 
45
45
  const result = fn(...(deps.map((s) => s.value) as SignalValues<Deps>))
46
46
 
47
- if (!isServer) {
48
- for (const [id, unsub] of subs) {
49
- if (observations!.has(id)) continue
50
- unsub()
51
- subs.delete(id)
52
- }
53
-
47
+ if (observations) {
54
48
  const effect = () => {
55
49
  if (!effectQueue.size) {
56
50
  queueMicrotask(tick)
@@ -58,11 +52,19 @@ export function executeWithTracking<T, Deps extends readonly Signal<unknown>[]>(
58
52
  effectQueue.set(id, onDepChanged)
59
53
  }
60
54
 
61
- for (const [id, sig] of observations!) {
62
- if (subs.has(id)) continue
63
- const unsub = sig.subscribe(effect)
64
- subs.set(id, unsub)
55
+ for (const [id, signal] of observations) {
56
+ if (!subs.has(id)) {
57
+ subs.set(id, signal.subscribe(effect))
58
+ }
65
59
  }
60
+
61
+ for (const [id, unsub] of subs) {
62
+ if (!observations.has(id)) {
63
+ unsub()
64
+ subs.delete(id)
65
+ }
66
+ }
67
+
66
68
  tracking.stack.pop()
67
69
  }
68
70
 
package/src/ssr/client.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AppHandle, AppHandleOptions } from "../appHandle"
1
+ import type { AppHandle, AppHandleOptions } from "../appHandle.js"
2
2
  import { hydrationStack } from "../hydration.js"
3
3
  import { hydrationMode, renderMode } from "../globals.js"
4
4
  import { mount } from "../index.js"