kiru 0.50.0 → 0.50.2

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 (61) hide show
  1. package/dist/appContext.d.ts.map +1 -1
  2. package/dist/appContext.js +16 -6
  3. package/dist/appContext.js.map +1 -1
  4. package/dist/context.js.map +1 -1
  5. package/dist/dom.js +4 -4
  6. package/dist/dom.js.map +1 -1
  7. package/dist/globalContext.d.ts +3 -3
  8. package/dist/globalContext.d.ts.map +1 -1
  9. package/dist/globalContext.js +3 -15
  10. package/dist/globalContext.js.map +1 -1
  11. package/dist/hmr.js.map +1 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +0 -8
  14. package/dist/index.js.map +1 -1
  15. package/dist/reconciler.js +2 -2
  16. package/dist/reconciler.js.map +1 -1
  17. package/dist/router/fileRouter.d.ts +1 -28
  18. package/dist/router/fileRouter.d.ts.map +1 -1
  19. package/dist/router/fileRouter.js +2 -302
  20. package/dist/router/fileRouter.js.map +1 -1
  21. package/dist/router/fileRouterController.d.ts +28 -0
  22. package/dist/router/fileRouterController.d.ts.map +1 -0
  23. package/dist/router/fileRouterController.js +418 -0
  24. package/dist/router/fileRouterController.js.map +1 -0
  25. package/dist/router/globals.d.ts +1 -1
  26. package/dist/router/globals.d.ts.map +1 -1
  27. package/dist/router/index.d.ts +3 -3
  28. package/dist/router/index.d.ts.map +1 -1
  29. package/dist/router/index.js +2 -3
  30. package/dist/router/index.js.map +1 -1
  31. package/dist/router/{config.d.ts → pageConfig.d.ts} +1 -1
  32. package/dist/router/pageConfig.d.ts.map +1 -0
  33. package/dist/router/{config.js → pageConfig.js} +1 -1
  34. package/dist/router/pageConfig.js.map +1 -0
  35. package/dist/scheduler.js +7 -7
  36. package/dist/scheduler.js.map +1 -1
  37. package/dist/signals/watch.d.ts.map +1 -1
  38. package/dist/signals/watch.js +1 -2
  39. package/dist/signals/watch.js.map +1 -1
  40. package/dist/swr.js.map +1 -1
  41. package/dist/types.d.ts +1 -1
  42. package/dist/types.d.ts.map +1 -1
  43. package/package.json +1 -1
  44. package/src/appContext.ts +18 -7
  45. package/src/context.ts +1 -1
  46. package/src/dom.ts +4 -4
  47. package/src/globalContext.ts +7 -20
  48. package/src/hmr.ts +2 -2
  49. package/src/index.ts +0 -9
  50. package/src/reconciler.ts +2 -2
  51. package/src/router/fileRouter.ts +4 -442
  52. package/src/router/fileRouterController.ts +591 -0
  53. package/src/router/globals.ts +1 -1
  54. package/src/router/index.ts +3 -3
  55. package/src/scheduler.ts +8 -8
  56. package/src/signals/watch.ts +2 -5
  57. package/src/swr.ts +1 -1
  58. package/src/types.ts +1 -1
  59. package/dist/router/config.d.ts.map +0 -1
  60. package/dist/router/config.js.map +0 -1
  61. /package/src/router/{config.ts → pageConfig.ts} +0 -0
@@ -0,0 +1,591 @@
1
+ import { Signal, computed, flushSync } from "../index.js"
2
+ import { __DEV__ } from "../env.js"
3
+ import { createElement } from "../element.js"
4
+ import { type FileRouterContextType } from "./context.js"
5
+ import { FileRouterDataLoadError } from "./errors.js"
6
+ import { fileRouterInstance } from "./globals.js"
7
+ import type {
8
+ ErrorPageProps,
9
+ FileRouterConfig,
10
+ PageConfig,
11
+ PageProps,
12
+ RouteQuery,
13
+ RouterState,
14
+ } from "./types.js"
15
+ import type {
16
+ DefaultComponentModule,
17
+ PageModule,
18
+ ViteImportMap,
19
+ } from "./types.internal.js"
20
+
21
+ interface FormattedViteImportMap {
22
+ [key: string]: {
23
+ load: () => Promise<DefaultComponentModule>
24
+ specificity: number
25
+ segments: string[]
26
+ filePath?: string
27
+ }
28
+ }
29
+
30
+ export class FileRouterController {
31
+ private enableTransitions: boolean
32
+ private pages: FormattedViteImportMap
33
+ private layouts: FormattedViteImportMap
34
+ private abortController: AbortController
35
+ private currentPage: Signal<{
36
+ component: Kiru.FC<any>
37
+ config?: PageConfig
38
+ route: string
39
+ } | null>
40
+ private currentPageProps: Signal<PageProps<PageConfig>>
41
+ private currentLayouts: Signal<Kiru.FC[]>
42
+ private state: Signal<RouterState>
43
+ private contextValue: Signal<FileRouterContextType>
44
+ private cleanups: (() => void)[] = []
45
+ private filePathToPageRoute?: Map<
46
+ string,
47
+ { route: string; config: PageConfig }
48
+ >
49
+ private pageRouteToConfig?: Map<string, PageConfig>
50
+ private currentRoute: string | null
51
+
52
+ constructor(config: FileRouterConfig) {
53
+ fileRouterInstance.current = this
54
+ this.pages = {}
55
+ this.layouts = {}
56
+ this.abortController = new AbortController()
57
+ this.currentPage = new Signal(null)
58
+ this.currentPageProps = new Signal({})
59
+ this.currentLayouts = new Signal([])
60
+ this.state = new Signal<RouterState>({
61
+ path: window.location.pathname,
62
+ params: {},
63
+ query: {},
64
+ signal: this.abortController.signal,
65
+ })
66
+ this.contextValue = computed<FileRouterContextType>(() => ({
67
+ state: this.state.value,
68
+ navigate: this.navigate.bind(this),
69
+ setQuery: this.setQuery.bind(this),
70
+ reload: (options?: { transition?: boolean }) =>
71
+ this.loadRoute(void 0, void 0, options?.transition),
72
+ }))
73
+ if (__DEV__) {
74
+ this.filePathToPageRoute = new Map()
75
+ this.pageRouteToConfig = new Map()
76
+ }
77
+ this.currentRoute = null
78
+
79
+ const { pages, layouts, dir = "/pages", baseUrl = "/", transition } = config
80
+ this.enableTransitions = !!transition
81
+ const [normalizedDir, normalizedBaseUrl] = [
82
+ normalizePrefixPath(dir),
83
+ normalizePrefixPath(baseUrl),
84
+ ]
85
+ this.pages = formatViteImportMap(
86
+ pages as ViteImportMap,
87
+ normalizedDir,
88
+ normalizedBaseUrl
89
+ )
90
+ if (__DEV__) {
91
+ validateRoutes(this.pages)
92
+ }
93
+ this.layouts = formatViteImportMap(
94
+ layouts as ViteImportMap,
95
+ normalizedDir,
96
+ normalizedBaseUrl
97
+ )
98
+
99
+ this.loadRoute()
100
+
101
+ const handlePopState = () => this.loadRoute()
102
+ window.addEventListener("popstate", handlePopState)
103
+ this.cleanups.push(() =>
104
+ window.removeEventListener("popstate", handlePopState)
105
+ )
106
+ }
107
+
108
+ public onPageConfigDefined<T extends PageConfig>(fp: string, config: T) {
109
+ const existing = this.filePathToPageRoute?.get(fp)
110
+ if (existing === undefined) {
111
+ const route = this.currentRoute
112
+ if (!route) return
113
+ this.filePathToPageRoute?.set(fp, { route, config })
114
+ return
115
+ }
116
+ const curPage = this.currentPage.value
117
+ if (curPage?.route === existing.route && config.loader) {
118
+ const p = this.currentPageProps.value
119
+ let transition = this.enableTransitions
120
+ if (config.loader.transition !== undefined) {
121
+ transition = config.loader.transition
122
+ }
123
+ const props = {
124
+ ...p,
125
+ loading: true,
126
+ data: null,
127
+ error: null,
128
+ }
129
+ handleStateTransition(this.state.value.signal, transition, () => {
130
+ this.currentPageProps.value = props
131
+ })
132
+
133
+ this.loadRouteData(config.loader, props, this.state.value, transition)
134
+ }
135
+
136
+ this.pageRouteToConfig?.set(existing.route, config)
137
+ }
138
+
139
+ public getContextValue() {
140
+ return this.contextValue.value
141
+ }
142
+
143
+ public getChildren() {
144
+ const page = this.currentPage.value,
145
+ props = this.currentPageProps.value,
146
+ layouts = this.currentLayouts.value
147
+
148
+ if (page) {
149
+ // Wrap component with layouts (outermost first)
150
+ return layouts.reduceRight(
151
+ (children, Layout) => createElement(Layout, { children }),
152
+ createElement(page.component, props)
153
+ )
154
+ }
155
+
156
+ return null
157
+ }
158
+
159
+ public dispose() {
160
+ this.cleanups.forEach((cleanup) => cleanup())
161
+ }
162
+
163
+ private matchRoute(pathSegments: string[]) {
164
+ const matches: Array<{
165
+ route: string
166
+ pageEntry: FormattedViteImportMap[string]
167
+ params: Record<string, string>
168
+ routeSegments: string[]
169
+ }> = []
170
+
171
+ // Find all matching routes
172
+ outer: for (const [route, pageEntry] of Object.entries(this.pages)) {
173
+ const routeSegments = pageEntry.segments
174
+ const pathMatchingSegments = routeSegments.filter(
175
+ (seg) => !seg.startsWith("(") && !seg.endsWith(")")
176
+ )
177
+
178
+ const params: Record<string, string> = {}
179
+ let hasCatchall = false
180
+
181
+ // Check if route matches
182
+ for (
183
+ let i = 0;
184
+ i < pathMatchingSegments.length && i < pathSegments.length;
185
+ i++
186
+ ) {
187
+ const routeSeg = pathMatchingSegments[i]
188
+
189
+ if (routeSeg.startsWith(":")) {
190
+ const key = routeSeg.slice(1)
191
+
192
+ if (routeSeg.endsWith("*")) {
193
+ // Catchall route - matches remaining segments
194
+ hasCatchall = true
195
+ const catchallKey = key.slice(0, -1) // Remove the *
196
+ params[catchallKey] = pathSegments.slice(i).join("/")
197
+ break
198
+ } else {
199
+ // Regular dynamic segment
200
+ if (i >= pathSegments.length) {
201
+ continue outer
202
+ }
203
+ params[key] = pathSegments[i]
204
+ }
205
+ } else {
206
+ // Static segment
207
+ if (routeSeg !== pathSegments[i]) {
208
+ continue outer
209
+ }
210
+ }
211
+ }
212
+
213
+ // For non-catchall routes, ensure exact length match
214
+ if (!hasCatchall && pathMatchingSegments.length !== pathSegments.length) {
215
+ continue
216
+ }
217
+
218
+ matches.push({
219
+ route,
220
+ pageEntry,
221
+ params,
222
+ routeSegments,
223
+ })
224
+ }
225
+
226
+ // Sort by specificity (highest first) and return the best match
227
+ if (matches.length === 0) {
228
+ return null
229
+ }
230
+
231
+ matches.sort((a, b) => b.pageEntry.specificity - a.pageEntry.specificity)
232
+ const bestMatch = matches[0]
233
+
234
+ return bestMatch
235
+ }
236
+
237
+ private async loadRoute(
238
+ path: string = window.location.pathname,
239
+ props: PageProps<PageConfig> = {},
240
+ enableTransition = this.enableTransitions
241
+ ): Promise<void> {
242
+ this.abortController?.abort()
243
+ const signal = (this.abortController = new AbortController()).signal
244
+
245
+ try {
246
+ const pathSegments = path.split("/").filter(Boolean)
247
+ const routeMatch = this.matchRoute(pathSegments)
248
+
249
+ if (!routeMatch) {
250
+ const _404 = this.matchRoute(["404"])
251
+ if (!_404) {
252
+ if (__DEV__) {
253
+ console.error(
254
+ `[kiru/router]: No 404 route defined (path: ${path}).
255
+ See https://kirujs.dev/docs/api/file-router#404 for more information.`
256
+ )
257
+ }
258
+ return
259
+ }
260
+ const errorProps = {
261
+ source: { path },
262
+ } satisfies ErrorPageProps
263
+
264
+ return this.navigate("/404", { replace: true, props: errorProps })
265
+ }
266
+
267
+ const { route, pageEntry, params, routeSegments } = routeMatch
268
+
269
+ this.currentRoute = route
270
+ const pagePromise = pageEntry.load()
271
+
272
+ const layoutPromises = ["/", ...routeSegments].reduce((acc, _, i) => {
273
+ const layoutPath = "/" + routeSegments.slice(0, i).join("/")
274
+ const layout = this.layouts[layoutPath]
275
+
276
+ if (!layout) {
277
+ return acc
278
+ }
279
+
280
+ return [...acc, layout.load()]
281
+ }, [] as Promise<DefaultComponentModule>[])
282
+
283
+ const query = parseQuery(window.location.search)
284
+ const [page, ...layouts] = await Promise.all([
285
+ pagePromise,
286
+ ...layoutPromises,
287
+ ])
288
+
289
+ this.currentRoute = null
290
+ if (signal.aborted) return
291
+
292
+ if (typeof page.default !== "function") {
293
+ throw new Error(
294
+ "[kiru/router]: Route component must be a default exported function"
295
+ )
296
+ }
297
+
298
+ const routerState: RouterState = {
299
+ path,
300
+ params,
301
+ query,
302
+ signal,
303
+ }
304
+
305
+ let config = (page as unknown as PageModule).config
306
+ if (__DEV__) {
307
+ if (this.pageRouteToConfig?.has(route)) {
308
+ config = this.pageRouteToConfig.get(route)
309
+ }
310
+ }
311
+
312
+ if (config?.loader) {
313
+ props = { ...props, loading: true, data: null, error: null }
314
+ this.loadRouteData(config.loader, props, routerState, enableTransition)
315
+ }
316
+
317
+ this.state.value = routerState
318
+ handleStateTransition(signal, enableTransition, () => {
319
+ this.currentPage.value = {
320
+ component: page.default,
321
+ config,
322
+ route: "/" + routeSegments.join("/"),
323
+ }
324
+ this.currentPageProps.value = props
325
+ this.currentLayouts.value = layouts
326
+ .filter((m) => typeof m.default === "function")
327
+ .map((m) => m.default)
328
+ })
329
+ } catch (error) {
330
+ console.error("[kiru/router]: Failed to load route component:", error)
331
+ this.currentPage.value = null
332
+ }
333
+ }
334
+
335
+ private async loadRouteData(
336
+ loader: NonNullable<PageConfig["loader"]>,
337
+ props: PageProps<PageConfig>,
338
+ routerState: RouterState,
339
+ enableTransition = this.enableTransitions
340
+ ) {
341
+ loader
342
+ .load(routerState)
343
+ .then(
344
+ (data) => ({ data, error: null }),
345
+ (error) => ({
346
+ data: null,
347
+ error: new FileRouterDataLoadError(error),
348
+ })
349
+ )
350
+ .then(({ data, error }) => {
351
+ if (routerState.signal.aborted) return
352
+
353
+ let transition = enableTransition
354
+ if (loader.transition !== undefined) {
355
+ transition = loader.transition
356
+ }
357
+
358
+ handleStateTransition(routerState.signal, transition, () => {
359
+ this.currentPageProps.value = {
360
+ ...props,
361
+ loading: false,
362
+ data,
363
+ error,
364
+ }
365
+ })
366
+ })
367
+ }
368
+
369
+ private async navigate(
370
+ path: string,
371
+ options?: {
372
+ replace?: boolean
373
+ transition?: boolean
374
+ props?: Record<string, unknown>
375
+ }
376
+ ) {
377
+ const f = options?.replace ? "replaceState" : "pushState"
378
+ window.history[f]({}, "", path)
379
+ window.dispatchEvent(new PopStateEvent("popstate", { state: {} }))
380
+ return this.loadRoute(path, options?.props, options?.transition)
381
+ }
382
+
383
+ private setQuery(query: RouteQuery) {
384
+ const queryString = buildQueryString(query)
385
+ const newUrl = `${this.state.value.path}${
386
+ queryString ? `?${queryString}` : ""
387
+ }`
388
+ window.history.pushState(null, "", newUrl)
389
+ this.state.value = { ...this.state.value, query }
390
+ }
391
+ }
392
+
393
+ function parseQuery(
394
+ search: string
395
+ ): Record<string, string | string[] | undefined> {
396
+ const params = new URLSearchParams(search)
397
+ const query: Record<string, string | string[] | undefined> = {}
398
+
399
+ for (const [key, value] of params.entries()) {
400
+ if (query[key]) {
401
+ // Convert to array if multiple values
402
+ if (Array.isArray(query[key])) {
403
+ ;(query[key] as string[]).push(value)
404
+ } else {
405
+ query[key] = [query[key] as string, value]
406
+ }
407
+ } else {
408
+ query[key] = value
409
+ }
410
+ }
411
+
412
+ return query
413
+ }
414
+
415
+ function buildQueryString(
416
+ query: Record<string, string | string[] | undefined>
417
+ ): string {
418
+ const params = new URLSearchParams()
419
+
420
+ for (const [key, value] of Object.entries(query)) {
421
+ if (value !== undefined) {
422
+ if (Array.isArray(value)) {
423
+ value.forEach((v) => params.append(key, v))
424
+ } else {
425
+ params.set(key, value)
426
+ }
427
+ }
428
+ }
429
+
430
+ return params.toString()
431
+ }
432
+
433
+ function formatViteImportMap(
434
+ map: ViteImportMap,
435
+ dir: string,
436
+ baseUrl: string
437
+ ): FormattedViteImportMap {
438
+ return Object.keys(map).reduce<FormattedViteImportMap>((acc, key) => {
439
+ const dirIndex = key.indexOf(dir)
440
+ if (dirIndex === -1) {
441
+ return acc
442
+ }
443
+
444
+ let specificity = 0
445
+ let k = key.slice(dirIndex + dir.length)
446
+ while (k.startsWith("/")) {
447
+ k = k.slice(1)
448
+ }
449
+ const segments: string[] = []
450
+ const parts = k.split("/").slice(0, -1)
451
+
452
+ for (let i = 0; i < parts.length; i++) {
453
+ const part = parts[i]
454
+ if (part.startsWith("[...") && part.endsWith("]")) {
455
+ if (i !== parts.length - 1) {
456
+ throw new Error(
457
+ `[kiru/router]: Catchall must be the folder name. Got "${key}"`
458
+ )
459
+ }
460
+ segments.push(`:${part.slice(4, -1)}*`)
461
+ specificity += 1
462
+ break
463
+ }
464
+ if (part.startsWith("[") && part.endsWith("]")) {
465
+ segments.push(`:${part.slice(1, -1)}`)
466
+ specificity += 10
467
+ continue
468
+ }
469
+ specificity += 100
470
+ segments.push(part)
471
+ }
472
+
473
+ const value: FormattedViteImportMap[string] = {
474
+ load: map[key],
475
+ specificity,
476
+ segments,
477
+ }
478
+
479
+ if (__DEV__) {
480
+ value.filePath = key
481
+ }
482
+
483
+ return {
484
+ ...acc,
485
+ [baseUrl + segments.join("/")]: value,
486
+ }
487
+ }, {})
488
+ }
489
+
490
+ function normalizePrefixPath(path: string) {
491
+ while (path.startsWith(".")) {
492
+ path = path.slice(1)
493
+ }
494
+ path = `/${path}/`
495
+ while (path.startsWith("//")) {
496
+ path = path.slice(1)
497
+ }
498
+ while (path.endsWith("//")) {
499
+ path = path.slice(0, -1)
500
+ }
501
+ return path
502
+ }
503
+
504
+ function handleStateTransition(
505
+ signal: AbortSignal,
506
+ enableTransition: boolean,
507
+ callback: () => void
508
+ ) {
509
+ if (!enableTransition || typeof document.startViewTransition !== "function") {
510
+ return callback()
511
+ }
512
+ const vt = document.startViewTransition(() => {
513
+ callback()
514
+ flushSync()
515
+ })
516
+
517
+ signal.addEventListener("abort", () => vt.skipTransition())
518
+ }
519
+
520
+ function validateRoutes(pageMap: FormattedViteImportMap) {
521
+ type Entry = FormattedViteImportMap[string]
522
+ const routeConflicts: [Entry, Entry][] = []
523
+ const routes = Object.keys(pageMap)
524
+ for (let i = 0; i < routes.length; i++) {
525
+ for (let j = i + 1; j < routes.length; j++) {
526
+ const route1 = routes[i]
527
+ const route2 = routes[j]
528
+
529
+ if (routesConflict(route1, route2)) {
530
+ routeConflicts.push([pageMap[route1], pageMap[route2]])
531
+ }
532
+ }
533
+ }
534
+
535
+ if (routeConflicts.length > 0) {
536
+ let warning = "[kiru/router]: Route conflicts detected:\n"
537
+ warning += routeConflicts.map(([route1, route2]) => {
538
+ return ` - "${route1.filePath}" conflicts with "${route2.filePath}"\n`
539
+ })
540
+ warning += "Routes are ordered by specificity (higher specificity wins)"
541
+ console.warn(warning)
542
+ }
543
+ }
544
+
545
+ function routesConflict(route1: string, route2: string): boolean {
546
+ const segments1 = route1.split("/").filter(Boolean)
547
+ const segments2 = route2.split("/").filter(Boolean)
548
+
549
+ // Filter out route groups for comparison
550
+ const pathSegments1 = segments1.filter(
551
+ (seg) => !seg.startsWith("(") && !seg.endsWith(")")
552
+ )
553
+ const pathSegments2 = segments2.filter(
554
+ (seg) => !seg.startsWith("(") && !seg.endsWith(")")
555
+ )
556
+
557
+ // Routes conflict if they have the same path structure
558
+ if (pathSegments1.length !== pathSegments2.length) {
559
+ return false
560
+ }
561
+
562
+ for (let i = 0; i < pathSegments1.length; i++) {
563
+ const seg1 = pathSegments1[i]
564
+ const seg2 = pathSegments2[i]
565
+
566
+ // If both are static segments, they must match exactly
567
+ if (!seg1.startsWith(":") && !seg2.startsWith(":")) {
568
+ if (seg1 !== seg2) {
569
+ return false
570
+ }
571
+ }
572
+ // If one is static and one is dynamic, they conflict
573
+ else if (
574
+ (seg1.startsWith(":") && !seg2.startsWith(":")) ||
575
+ (!seg1.startsWith(":") && seg2.startsWith(":"))
576
+ ) {
577
+ return false
578
+ }
579
+ // If both are dynamic, they conflict
580
+ else if (seg1.startsWith(":") && seg2.startsWith(":")) {
581
+ // Both are dynamic, check if they're the same type
582
+ const isCatchall1 = seg1.endsWith("*")
583
+ const isCatchall2 = seg2.endsWith("*")
584
+ if (isCatchall1 !== isCatchall2) {
585
+ return false
586
+ }
587
+ }
588
+ }
589
+
590
+ return true
591
+ }
@@ -1,4 +1,4 @@
1
- import type { FileRouterController } from "./fileRouter"
1
+ import type { FileRouterController } from "./fileRouterController"
2
2
 
3
3
  export const fileRouterInstance = {
4
4
  current: null as FileRouterController | null,
@@ -1,6 +1,6 @@
1
- export * from "./config.js"
1
+ export { useFileRouter, type FileRouterContextType } from "./context.js"
2
2
  export * from "./errors.js"
3
3
  export { FileRouter, type FileRouterProps } from "./fileRouter.js"
4
- export { useFileRouter } from "./context.js"
5
4
  export * from "./link.js"
6
- export * from "./types.js"
5
+ export * from "./pageConfig.js"
6
+ export type * from "./types.js"
package/src/scheduler.ts CHANGED
@@ -112,7 +112,7 @@ function queueUpdate(vNode: VNode) {
112
112
  // If this node is currently being rendered, just mark it dirty
113
113
  if (node.current === vNode) {
114
114
  if (__DEV__) {
115
- window.__kiru?.profilingContext?.emit("updateDirtied", appCtx!)
115
+ window.__kiru.profilingContext?.emit("updateDirtied", appCtx!)
116
116
  }
117
117
  isRenderDirtied = true
118
118
  return
@@ -143,7 +143,7 @@ function doWork(): void {
143
143
  const n = deletions[0] ?? treesInProgress[0]
144
144
  if (n) {
145
145
  appCtx = getVNodeAppContext(n)!
146
- window.__kiru?.profilingContext?.beginTick(appCtx)
146
+ window.__kiru.profilingContext?.beginTick(appCtx)
147
147
  } else {
148
148
  appCtx = null
149
149
  }
@@ -186,8 +186,8 @@ function doWork(): void {
186
186
  immediateEffectDirtiedRender = false
187
187
  consecutiveDirtyCount++
188
188
  if (__DEV__) {
189
- window.__kiru?.profilingContext?.endTick(appCtx!)
190
- window.__kiru?.profilingContext?.emit("updateDirtied", appCtx!)
189
+ window.__kiru.profilingContext?.endTick(appCtx!)
190
+ window.__kiru.profilingContext?.emit("updateDirtied", appCtx!)
191
191
  }
192
192
  return flushSync()
193
193
  }
@@ -196,9 +196,9 @@ function doWork(): void {
196
196
  onWorkFinished()
197
197
  flushEffects(postEffects)
198
198
  if (__DEV__) {
199
- window.__kiru!.emit("update", appCtx!)
200
- window.__kiru?.profilingContext?.emit("update", appCtx!)
201
- window.__kiru?.profilingContext?.endTick(appCtx!)
199
+ window.__kiru.emit("update", appCtx!)
200
+ window.__kiru.profilingContext?.emit("update", appCtx!)
201
+ window.__kiru.profilingContext?.endTick(appCtx!)
202
202
  }
203
203
  }
204
204
 
@@ -214,7 +214,7 @@ function performUnitOfWork(vNode: VNode): VNode | void {
214
214
  }
215
215
  } catch (error) {
216
216
  if (__DEV__) {
217
- window.__kiru?.emit(
217
+ window.__kiru.emit(
218
218
  "error",
219
219
  appCtx!,
220
220
  error instanceof Error ? error : new Error(String(error))
@@ -41,7 +41,7 @@ export class WatchEffect<const Deps extends readonly Signal<unknown>[] = []> {
41
41
  },
42
42
  }
43
43
  if ("window" in globalThis) {
44
- const signals = window.__kiru!.HMRContext!.signals
44
+ const signals = window.__kiru.HMRContext!.signals
45
45
  if (signals.isWaitingForNextWatchCall()) {
46
46
  signals.pushWatch(this as WatchEffect)
47
47
  }
@@ -59,10 +59,7 @@ export class WatchEffect<const Deps extends readonly Signal<unknown>[] = []> {
59
59
 
60
60
  if (__DEV__) {
61
61
  // postpone execution during HMR
62
- if (
63
- "window" in globalThis &&
64
- window.__kiru?.HMRContext?.isReplacement()
65
- ) {
62
+ if ("window" in globalThis && window.__kiru.HMRContext?.isReplacement()) {
66
63
  return queueMicrotask(() => {
67
64
  if (this.isRunning) {
68
65
  WatchEffect.run(this as WatchEffect)
package/src/swr.ts CHANGED
@@ -95,7 +95,7 @@ const SWRGlobalState = {
95
95
 
96
96
  if ("window" in globalThis) {
97
97
  if (__DEV__) {
98
- SWRGlobalState.cache = window.__kiru!.SWRGlobalCache ??= new Map()
98
+ SWRGlobalState.cache = window.__kiru.SWRGlobalCache ??= new Map()
99
99
  } else {
100
100
  SWRGlobalState.cache = new Map()
101
101
  }
package/src/types.ts CHANGED
@@ -79,7 +79,7 @@ type ElementMap = {
79
79
 
80
80
  declare global {
81
81
  interface Window {
82
- __kiru: KiruGlobalContext | undefined
82
+ __kiru: KiruGlobalContext
83
83
  }
84
84
  namespace JSX {
85
85
  interface IntrinsicElements extends ElementMap {}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/router/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,UAAU,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAUnE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/router/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAGjD,MAAM,UAAU,gBAAgB,CAAuB,MAAS;IAC9D,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAA;QAChE,MAAM,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAA;QAC7C,IAAI,QAAQ,IAAI,UAAU,EAAE,CAAC;YAC3B,UAAU,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QAClD,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
File without changes