@statorjs/stator 2.6.0 → 2.8.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.
- package/package.json +2 -2
- package/src/build/islands-esbuild.ts +175 -0
- package/src/build/islands-vite.ts +88 -0
- package/src/build/islands.ts +15 -82
- package/src/client/inspector.css +198 -0
- package/src/client/inspector.ts +330 -7
- package/src/engine/describe.ts +129 -0
- package/src/engine/index.ts +6 -0
- package/src/server/dev-native.ts +1 -0
- package/src/server/dev-vite.ts +1 -0
- package/src/server/http.ts +58 -1
- package/src/server/index.ts +2 -0
- package/src/server/inspect.ts +101 -0
- package/src/server/route-discovery.ts +6 -4
package/src/server/index.ts
CHANGED
|
@@ -52,6 +52,8 @@ export {
|
|
|
52
52
|
export { scheduleSessionEffects, wireAppEffects } from './effects.ts'
|
|
53
53
|
export type { HttpConfig } from './http.ts'
|
|
54
54
|
export { buildHonoApp } from './http.ts'
|
|
55
|
+
export type { InspectPayload, InspectRoute, InspectRouteMethod } from './inspect.ts'
|
|
56
|
+
export { buildInspectPayload } from './inspect.ts'
|
|
55
57
|
export type { InstanceHandle } from './instance-proxy.ts'
|
|
56
58
|
export { createInstanceProxy, defForProxy } from './instance-proxy.ts'
|
|
57
59
|
export { logger, scopedLogger, setLogLevel } from './logger.ts'
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev state inspection — the data feed for the inspector's Machines view.
|
|
3
|
+
*
|
|
4
|
+
* Serves the caller's OWN session: the payload is scoped to the session the
|
|
5
|
+
* request's cookie addresses (app-lifecycle machines are process-global and
|
|
6
|
+
* labeled as such by their lifecycle). Registered only by the dev servers —
|
|
7
|
+
* machine context is working state and may hold anything, so this endpoint
|
|
8
|
+
* never exists in production.
|
|
9
|
+
*
|
|
10
|
+
* Read-only by construction: no actors are instantiated, no session lock is
|
|
11
|
+
* taken, nothing is dispatched. Session snapshots come straight from the
|
|
12
|
+
* persistence store — a machine never touched by this session reads as null
|
|
13
|
+
* (it would start from the def's initial context on first dispatch).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { describeMachine, type MachineDescription } from '../engine/describe.ts'
|
|
17
|
+
import type { Snapshot } from '../engine/types.ts'
|
|
18
|
+
import { codeHashOf } from './machine-hash.ts'
|
|
19
|
+
import type { MachineStore } from './machine-store.ts'
|
|
20
|
+
import { type DiscoveredRoute, HTTP_METHODS } from './route-discovery.ts'
|
|
21
|
+
import { isStatorQueryRoute, isStatorRoute } from './routing.ts'
|
|
22
|
+
|
|
23
|
+
export interface InspectRouteMethod {
|
|
24
|
+
/** `page` = defineRoute, `data` = defineApiRoute({method:'GET'}), `api` = the rest. */
|
|
25
|
+
kind: 'page' | 'data' | 'api'
|
|
26
|
+
reads: string[]
|
|
27
|
+
/** Page routes only: whether the route opened an SSE live channel. */
|
|
28
|
+
live?: boolean
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface InspectRoute {
|
|
32
|
+
urlPath: string
|
|
33
|
+
methods: Record<string, InspectRouteMethod>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface InspectPayload {
|
|
37
|
+
buildId?: string
|
|
38
|
+
/** All registered machines, described + their running code hash. */
|
|
39
|
+
machines: Array<MachineDescription & { hash?: string }>
|
|
40
|
+
/** The caller's session's persisted snapshots (null = never touched). */
|
|
41
|
+
session: Record<string, Snapshot<unknown> | null>
|
|
42
|
+
/** App-lifecycle live snapshots — process-global, same for every caller. */
|
|
43
|
+
app: Record<string, Snapshot<unknown>>
|
|
44
|
+
routes: InspectRoute[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function buildInspectPayload(opts: {
|
|
48
|
+
store: MachineStore
|
|
49
|
+
routes: DiscoveredRoute[]
|
|
50
|
+
sessionId?: string
|
|
51
|
+
buildId?: string
|
|
52
|
+
}): Promise<InspectPayload> {
|
|
53
|
+
const defs = [...opts.store.allDefs()].sort((a, b) => a.name.localeCompare(b.name))
|
|
54
|
+
|
|
55
|
+
const machines = defs.map((def) => {
|
|
56
|
+
const hash = codeHashOf(def)
|
|
57
|
+
return { ...describeMachine(def), ...(hash !== undefined ? { hash } : {}) }
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const session: Record<string, Snapshot<unknown> | null> = {}
|
|
61
|
+
if (opts.sessionId !== undefined) {
|
|
62
|
+
for (const def of defs) {
|
|
63
|
+
if (def.lifecycle !== 'session') continue
|
|
64
|
+
session[def.name] =
|
|
65
|
+
((await opts.store.persistence.get(
|
|
66
|
+
opts.sessionId,
|
|
67
|
+
def.name,
|
|
68
|
+
)) as Snapshot<unknown> | null) ?? null
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const app: Record<string, Snapshot<unknown>> = {}
|
|
73
|
+
for (const def of defs) {
|
|
74
|
+
if (def.lifecycle !== 'app') continue
|
|
75
|
+
const handle = opts.store.appInstance(def.name)
|
|
76
|
+
if (handle) app[def.name] = handle.actor.getSnapshot()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const routes = opts.routes.map((route): InspectRoute => {
|
|
80
|
+
const methods: Record<string, InspectRouteMethod> = {}
|
|
81
|
+
for (const method of HTTP_METHODS) {
|
|
82
|
+
const def = route[method]
|
|
83
|
+
if (!def) continue
|
|
84
|
+
const reads = def.reads.map((d) => d.name)
|
|
85
|
+
if (isStatorRoute(def)) {
|
|
86
|
+
methods[method] = { kind: 'page', reads, live: def.live }
|
|
87
|
+
} else {
|
|
88
|
+
methods[method] = { kind: isStatorQueryRoute(def) ? 'data' : 'api', reads }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { urlPath: route.urlPath, methods }
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
...(opts.buildId !== undefined ? { buildId: opts.buildId } : {}),
|
|
96
|
+
machines,
|
|
97
|
+
session,
|
|
98
|
+
app,
|
|
99
|
+
routes,
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -41,10 +41,12 @@ export interface DiscoveredRoute {
|
|
|
41
41
|
* Walk the routes directory recursively and build URL patterns from file
|
|
42
42
|
* paths. Conventions:
|
|
43
43
|
*
|
|
44
|
-
* - `routes/foo.ts`
|
|
45
|
-
* - `routes/foo/index.ts`
|
|
46
|
-
* - `routes/foo/[id].ts`
|
|
47
|
-
* - `routes/[a]/[b].ts`
|
|
44
|
+
* - `routes/foo.ts` → `/foo`
|
|
45
|
+
* - `routes/foo/index.ts` → `/foo`
|
|
46
|
+
* - `routes/foo/[id].ts` → `/foo/:id` (path param `id`)
|
|
47
|
+
* - `routes/[a]/[b].ts` → `/:a/:b`
|
|
48
|
+
* - `routes/foo/[...rest].ts` → `/foo/*rest` (catch-all: terminal, matches
|
|
49
|
+
* zero+ segments, param is the raw remainder incl. slashes)
|
|
48
50
|
*
|
|
49
51
|
* Files may export any combination of `GET`/`POST`/`PUT`/`PATCH`/`DELETE`.
|
|
50
52
|
* GET is a `defineRoute` (page renderer) or a `defineApiRoute` declaring
|