@dreamboard-games/cli 0.1.30-alpha.3 → 0.1.30-alpha.31

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 (173) hide show
  1. package/README.md +27 -108
  2. package/dist/agent-verifier/agent-workspace-verifier.mjs +1988 -57
  3. package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -1
  4. package/dist/agent-verifier/{chunk-XQXDOBYB.mjs → chunk-4I2WWAPK.mjs} +27 -10
  5. package/dist/agent-verifier/chunk-4I2WWAPK.mjs.map +1 -0
  6. package/dist/agent-verifier/{chunk-O4YCPU7C.mjs → chunk-BWBN2TDJ.mjs} +539 -641
  7. package/dist/agent-verifier/chunk-BWBN2TDJ.mjs.map +1 -0
  8. package/dist/agent-verifier/{chunk-TAEQKBJB.mjs → chunk-GWRZRWCF.mjs} +1 -1
  9. package/dist/agent-verifier/chunk-GWRZRWCF.mjs.map +1 -0
  10. package/dist/agent-verifier/chunk-H6XDQJ3N.mjs +11 -0
  11. package/dist/agent-verifier/chunk-HUBV22JQ.mjs +89 -0
  12. package/dist/agent-verifier/chunk-HUBV22JQ.mjs.map +1 -0
  13. package/dist/agent-verifier/{chunk-VS573ERH.mjs → chunk-JZTH3EMV.mjs} +2 -2
  14. package/dist/agent-verifier/{chunk-XGWCY624.mjs → chunk-KDAQ4CZY.mjs} +34 -27
  15. package/dist/agent-verifier/chunk-KDAQ4CZY.mjs.map +1 -0
  16. package/dist/agent-verifier/{chunk-IAYRNVUC.mjs → chunk-LMW66VBH.mjs} +2 -13
  17. package/dist/agent-verifier/{chunk-IAYRNVUC.mjs.map → chunk-LMW66VBH.mjs.map} +1 -1
  18. package/dist/agent-verifier/{chunk-776W3UGV.mjs → chunk-M6YNQZCC.mjs} +4 -13
  19. package/dist/agent-verifier/chunk-M6YNQZCC.mjs.map +1 -0
  20. package/dist/agent-verifier/{chunk-H76MT5UR.mjs → chunk-M7UVBANQ.mjs} +2 -1
  21. package/dist/agent-verifier/chunk-M7UVBANQ.mjs.map +1 -0
  22. package/dist/agent-verifier/{chunk-SH5JKYOB.mjs → chunk-MIRGCMUC.mjs} +112 -26
  23. package/dist/agent-verifier/chunk-MIRGCMUC.mjs.map +1 -0
  24. package/dist/agent-verifier/{chunk-NAK77WXW.mjs → chunk-MYMVXTZT.mjs} +4 -5
  25. package/dist/agent-verifier/chunk-MYMVXTZT.mjs.map +1 -0
  26. package/dist/agent-verifier/{chunk-7WWGFAAU.mjs → chunk-NBRUEJUK.mjs} +215 -223
  27. package/dist/agent-verifier/chunk-NBRUEJUK.mjs.map +1 -0
  28. package/dist/agent-verifier/chunk-OJFZVGEL.mjs +492 -0
  29. package/dist/agent-verifier/chunk-OJFZVGEL.mjs.map +1 -0
  30. package/dist/agent-verifier/{chunk-LUZ7KE6H.mjs → chunk-QD4SQNUP.mjs} +4 -8
  31. package/dist/agent-verifier/{chunk-LUZ7KE6H.mjs.map → chunk-QD4SQNUP.mjs.map} +1 -1
  32. package/dist/agent-verifier/chunk-TTB7AIHZ.mjs +214 -0
  33. package/dist/agent-verifier/chunk-TTB7AIHZ.mjs.map +1 -0
  34. package/dist/agent-verifier/{chunk-F2DIOJJZ.mjs → chunk-XCQQIPCO.mjs} +5 -46
  35. package/dist/agent-verifier/chunk-XCQQIPCO.mjs.map +1 -0
  36. package/dist/agent-verifier/{global-config-Y2NTSK4R.mjs → global-config-2NUESNEQ.mjs} +6 -6
  37. package/dist/agent-verifier/{keychain-backend-SPQWGKZN.mjs → keychain-backend-FF4I6ODB.mjs} +12 -7
  38. package/dist/agent-verifier/keychain-backend-FF4I6ODB.mjs.map +1 -0
  39. package/dist/agent-verifier/{local-files-JFOQQZDL.mjs → local-files-OF4QFISU.mjs} +10 -10
  40. package/dist/agent-verifier/{chunk-UIOLGH4A.mjs → local-typecheck-DHVLM37Z.mjs} +4 -4
  41. package/dist/agent-verifier/local-typecheck-DHVLM37Z.mjs.map +1 -0
  42. package/dist/agent-verifier/{materialize-workspace-ZAVGQQSF.mjs → materialize-workspace-MAGKDMK5.mjs} +23 -22
  43. package/dist/agent-verifier/materialize-workspace-MAGKDMK5.mjs.map +1 -0
  44. package/dist/agent-verifier/{project-state-K576C2TE.mjs → project-state-XKUSCFSV.mjs} +2 -2
  45. package/dist/agent-verifier/{prompt-MJRJMOGQ.mjs → prompt-VKHMCQT6.mjs} +2 -2
  46. package/dist/agent-verifier/{chunk-A64ZZUZV.mjs → reducer-bundle-preflight-GLUJKTWU.mjs} +76 -25
  47. package/dist/agent-verifier/reducer-bundle-preflight-GLUJKTWU.mjs.map +1 -0
  48. package/dist/agent-verifier/{chunk-JGT4P4UD.mjs → reducer-contract-preflight-WVQQPW5F.mjs} +7 -6
  49. package/dist/agent-verifier/reducer-contract-preflight-WVQQPW5F.mjs.map +1 -0
  50. package/dist/agent-verifier/{chunk-E7SSWJXJ.mjs → reducer-native-test-harness-UFMSNNDY.mjs} +463 -686
  51. package/dist/agent-verifier/reducer-native-test-harness-UFMSNNDY.mjs.map +1 -0
  52. package/dist/agent-verifier/static-scaffold-CLRRWXON.mjs +24 -0
  53. package/dist/agent-verifier/workspace-codegen-SPPVHURX.mjs +10 -0
  54. package/dist/agent-verifier/{workspace-dependencies-NOOQBK6I.mjs → workspace-dependencies-5HEEKZFP.mjs} +6 -4
  55. package/dist/authoring-compatibility-internal.js +12 -0
  56. package/dist/chunk-2H7UOFLK.js +11 -0
  57. package/dist/chunk-6NYVJYN4.js +313 -0
  58. package/dist/chunk-6NYVJYN4.js.map +1 -0
  59. package/dist/chunk-EQNBQVIW.js +204 -0
  60. package/dist/chunk-EQNBQVIW.js.map +1 -0
  61. package/dist/chunk-X244CUU4.js +3815 -0
  62. package/dist/chunk-X244CUU4.js.map +1 -0
  63. package/dist/{chunk-TAQKH67O.js → chunk-YNJVKC2T.js} +2587 -7278
  64. package/dist/chunk-YNJVKC2T.js.map +1 -0
  65. package/dist/{global-config-S4ZIPECE.js → global-config-RBMW7IVA.js} +4 -3
  66. package/dist/index.js +3099 -6187
  67. package/dist/index.js.map +1 -1
  68. package/dist/internal.js +36 -10
  69. package/dist/internal.js.map +1 -1
  70. package/dist/{keychain-backend-HDF4TZDL.js → keychain-backend-FSNTNTZE.js} +12 -7
  71. package/dist/keychain-backend-FSNTNTZE.js.map +1 -0
  72. package/dist/{prompt-NDV3AE5L.js → prompt-GMZABCJC.js} +2 -2
  73. package/package.json +9 -19
  74. package/release/authoring-release-set.json +38 -0
  75. package/skills/dreamboard/SKILL.md +30 -28
  76. package/skills/dreamboard/references/building-your-first-game.md +15 -15
  77. package/skills/dreamboard/references/cli.md +46 -47
  78. package/skills/dreamboard/references/manifest-authoring.md +11 -3
  79. package/skills/dreamboard/references/quickstart.md +16 -13
  80. package/skills/dreamboard/references/testing.md +6 -13
  81. package/dist/agent-verifier/chunk-3UKQVWLV.mjs +0 -1744
  82. package/dist/agent-verifier/chunk-3UKQVWLV.mjs.map +0 -1
  83. package/dist/agent-verifier/chunk-776W3UGV.mjs.map +0 -1
  84. package/dist/agent-verifier/chunk-7WWGFAAU.mjs.map +0 -1
  85. package/dist/agent-verifier/chunk-A64ZZUZV.mjs.map +0 -1
  86. package/dist/agent-verifier/chunk-E7SSWJXJ.mjs.map +0 -1
  87. package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +0 -1
  88. package/dist/agent-verifier/chunk-G42BGGG2.mjs +0 -70
  89. package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +0 -1
  90. package/dist/agent-verifier/chunk-H76MT5UR.mjs.map +0 -1
  91. package/dist/agent-verifier/chunk-HGMUAL33.mjs +0 -39
  92. package/dist/agent-verifier/chunk-HGMUAL33.mjs.map +0 -1
  93. package/dist/agent-verifier/chunk-JGT4P4UD.mjs.map +0 -1
  94. package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +0 -1
  95. package/dist/agent-verifier/chunk-O4YCPU7C.mjs.map +0 -1
  96. package/dist/agent-verifier/chunk-S34FRJHS.mjs +0 -222
  97. package/dist/agent-verifier/chunk-S34FRJHS.mjs.map +0 -1
  98. package/dist/agent-verifier/chunk-SH5JKYOB.mjs.map +0 -1
  99. package/dist/agent-verifier/chunk-SKI2ESE5.mjs +0 -44
  100. package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +0 -1
  101. package/dist/agent-verifier/chunk-UIOLGH4A.mjs.map +0 -1
  102. package/dist/agent-verifier/chunk-UIZNWRM6.mjs +0 -2432
  103. package/dist/agent-verifier/chunk-UIZNWRM6.mjs.map +0 -1
  104. package/dist/agent-verifier/chunk-W3N3QJ4V.mjs +0 -624
  105. package/dist/agent-verifier/chunk-W3N3QJ4V.mjs.map +0 -1
  106. package/dist/agent-verifier/chunk-XGWCY624.mjs.map +0 -1
  107. package/dist/agent-verifier/chunk-XQXDOBYB.mjs.map +0 -1
  108. package/dist/agent-verifier/compile-TEQVA46V.mjs +0 -312
  109. package/dist/agent-verifier/compile-TEQVA46V.mjs.map +0 -1
  110. package/dist/agent-verifier/keychain-backend-SPQWGKZN.mjs.map +0 -1
  111. package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs +0 -10
  112. package/dist/agent-verifier/materialize-workspace-ZAVGQQSF.mjs.map +0 -1
  113. package/dist/agent-verifier/reducer-bundle-preflight-LXNJUBKL.mjs +0 -20
  114. package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs +0 -11
  115. package/dist/agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs +0 -50
  116. package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs +0 -27
  117. package/dist/agent-verifier/sync-THAI546U.mjs +0 -588
  118. package/dist/agent-verifier/sync-THAI546U.mjs.map +0 -1
  119. package/dist/agent-verifier/test-AFAQFKOB.mjs +0 -353
  120. package/dist/agent-verifier/test-AFAQFKOB.mjs.map +0 -1
  121. package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs +0 -10
  122. package/dist/agent-verifier/workspace-dependencies-NOOQBK6I.mjs.map +0 -1
  123. package/dist/chunk-N7XPNNUI.js +0 -432
  124. package/dist/chunk-N7XPNNUI.js.map +0 -1
  125. package/dist/chunk-SEGVTWSK.js +0 -44
  126. package/dist/chunk-SEGVTWSK.js.map +0 -1
  127. package/dist/chunk-TAQKH67O.js.map +0 -1
  128. package/dist/dev-host/components/drawer.tsx +0 -132
  129. package/dist/dev-host/components/input.tsx +0 -21
  130. package/dist/dev-host/dev-api-proxy-plugin.ts +0 -328
  131. package/dist/dev-host/dev-author-dom-warnings.ts +0 -100
  132. package/dist/dev-host/dev-diagnostics.ts +0 -62
  133. package/dist/dev-host/dev-fallback-stylesheet.ts +0 -53
  134. package/dist/dev-host/dev-hmr-guard-plugin.ts +0 -47
  135. package/dist/dev-host/dev-host-controller.ts +0 -674
  136. package/dist/dev-host/dev-host-player-query.ts +0 -17
  137. package/dist/dev-host/dev-host-session-transport.ts +0 -52
  138. package/dist/dev-host/dev-host-storage.ts +0 -56
  139. package/dist/dev-host/dev-log-relay-plugin.ts +0 -510
  140. package/dist/dev-host/dev-runtime-config.ts +0 -14
  141. package/dist/dev-host/dev-runtime-platform.ts +0 -335
  142. package/dist/dev-host/dev-virtual-modules-plugin.ts +0 -64
  143. package/dist/dev-host/host-main.css +0 -224
  144. package/dist/dev-host/host-main.tsx +0 -948
  145. package/dist/dev-host/index.html +0 -56
  146. package/dist/dev-host/lib/utils.ts +0 -6
  147. package/dist/dev-host/plugin-main.ts +0 -61
  148. package/dist/dev-host/plugin.html +0 -24
  149. package/dist/dev-host/shared-styles.css +0 -144
  150. package/dist/dev-host/start-dev-server.ts +0 -140
  151. package/dist/dev-host/virtual-modules.d.ts +0 -27
  152. package/dist/global-config-S4ZIPECE.js.map +0 -1
  153. package/dist/keychain-backend-HDF4TZDL.js.map +0 -1
  154. package/skills/dreamboard/scripts/events-extract.mjs +0 -218
  155. /package/dist/agent-verifier/{chunk-SKI2ESE5.mjs.map → chunk-H6XDQJ3N.mjs.map} +0 -0
  156. /package/dist/agent-verifier/{chunk-VS573ERH.mjs.map → chunk-JZTH3EMV.mjs.map} +0 -0
  157. /package/dist/agent-verifier/{global-config-Y2NTSK4R.mjs.map → global-config-2NUESNEQ.mjs.map} +0 -0
  158. /package/dist/agent-verifier/{local-files-JFOQQZDL.mjs.map → local-files-OF4QFISU.mjs.map} +0 -0
  159. /package/dist/agent-verifier/{local-typecheck-XVGWI75X.mjs.map → project-state-XKUSCFSV.mjs.map} +0 -0
  160. /package/dist/agent-verifier/{prompt-MJRJMOGQ.mjs.map → prompt-VKHMCQT6.mjs.map} +0 -0
  161. /package/dist/agent-verifier/{project-state-K576C2TE.mjs.map → static-scaffold-CLRRWXON.mjs.map} +0 -0
  162. /package/dist/agent-verifier/{reducer-bundle-preflight-LXNJUBKL.mjs.map → workspace-codegen-SPPVHURX.mjs.map} +0 -0
  163. /package/dist/agent-verifier/{reducer-contract-preflight-TUMQ43JV.mjs.map → workspace-dependencies-5HEEKZFP.mjs.map} +0 -0
  164. /package/dist/{agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs.map → authoring-compatibility-internal.js.map} +0 -0
  165. /package/dist/{agent-verifier/static-scaffold-R7SVDRQI.mjs.map → chunk-2H7UOFLK.js.map} +0 -0
  166. /package/dist/{agent-verifier/workspace-codegen-2ZMQRIKJ.mjs.map → global-config-RBMW7IVA.js.map} +0 -0
  167. /package/dist/{prompt-NDV3AE5L.js.map → prompt-GMZABCJC.js.map} +0 -0
  168. /package/{dist/scaffold → scaffold}/assets/static/app/tsconfig.framework.json +0 -0
  169. /package/{dist/scaffold → scaffold}/assets/static/app/tsconfig.json +0 -0
  170. /package/{dist/scaffold → scaffold}/assets/static/ui/index.tsx +0 -0
  171. /package/{dist/scaffold → scaffold}/assets/static/ui/style.css +0 -0
  172. /package/{dist/scaffold → scaffold}/assets/static/ui/tsconfig.framework.json +0 -0
  173. /package/{dist/scaffold → scaffold}/assets/static/ui/tsconfig.json +0 -0
@@ -1,132 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import { Drawer as DrawerPrimitive } from "vaul";
5
-
6
- import { cn } from "../lib/utils.js";
7
-
8
- function Drawer({
9
- ...props
10
- }: React.ComponentProps<typeof DrawerPrimitive.Root>) {
11
- return <DrawerPrimitive.Root data-slot="drawer" {...props} />;
12
- }
13
-
14
- function DrawerTrigger({
15
- ...props
16
- }: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {
17
- return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} />;
18
- }
19
-
20
- function DrawerPortal({
21
- ...props
22
- }: React.ComponentProps<typeof DrawerPrimitive.Portal>) {
23
- return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} />;
24
- }
25
-
26
- function DrawerClose({
27
- ...props
28
- }: React.ComponentProps<typeof DrawerPrimitive.Close>) {
29
- return <DrawerPrimitive.Close data-slot="drawer-close" {...props} />;
30
- }
31
-
32
- function DrawerOverlay({
33
- className,
34
- ...props
35
- }: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {
36
- return (
37
- <DrawerPrimitive.Overlay
38
- data-slot="drawer-overlay"
39
- className={cn(
40
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
41
- className,
42
- )}
43
- {...props}
44
- />
45
- );
46
- }
47
-
48
- function DrawerContent({
49
- className,
50
- children,
51
- ...props
52
- }: React.ComponentProps<typeof DrawerPrimitive.Content>) {
53
- return (
54
- <DrawerPortal data-slot="drawer-portal">
55
- <DrawerOverlay />
56
- <DrawerPrimitive.Content
57
- data-slot="drawer-content"
58
- className={cn(
59
- "group/drawer-content bg-background fixed z-50 flex h-auto flex-col",
60
- "data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b",
61
- "data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t",
62
- "data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm",
63
- "data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm",
64
- className,
65
- )}
66
- {...props}
67
- >
68
- <div className="bg-muted mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
69
- {children}
70
- </DrawerPrimitive.Content>
71
- </DrawerPortal>
72
- );
73
- }
74
-
75
- function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
76
- return (
77
- <div
78
- data-slot="drawer-header"
79
- className={cn("flex flex-col gap-1.5 p-4", className)}
80
- {...props}
81
- />
82
- );
83
- }
84
-
85
- function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
86
- return (
87
- <div
88
- data-slot="drawer-footer"
89
- className={cn("mt-auto flex flex-col gap-2 p-4", className)}
90
- {...props}
91
- />
92
- );
93
- }
94
-
95
- function DrawerTitle({
96
- className,
97
- ...props
98
- }: React.ComponentProps<typeof DrawerPrimitive.Title>) {
99
- return (
100
- <DrawerPrimitive.Title
101
- data-slot="drawer-title"
102
- className={cn("text-foreground font-semibold", className)}
103
- {...props}
104
- />
105
- );
106
- }
107
-
108
- function DrawerDescription({
109
- className,
110
- ...props
111
- }: React.ComponentProps<typeof DrawerPrimitive.Description>) {
112
- return (
113
- <DrawerPrimitive.Description
114
- data-slot="drawer-description"
115
- className={cn("text-muted-foreground text-sm", className)}
116
- {...props}
117
- />
118
- );
119
- }
120
-
121
- export {
122
- Drawer,
123
- DrawerPortal,
124
- DrawerOverlay,
125
- DrawerTrigger,
126
- DrawerClose,
127
- DrawerContent,
128
- DrawerHeader,
129
- DrawerFooter,
130
- DrawerTitle,
131
- DrawerDescription,
132
- };
@@ -1,21 +0,0 @@
1
- import * as React from "react";
2
-
3
- import { cn } from "../lib/utils.js";
4
-
5
- function Input({ className, type, ...props }: React.ComponentProps<"input">) {
6
- return (
7
- <input
8
- type={type}
9
- data-slot="input"
10
- className={cn(
11
- "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-white h-12 w-full min-w-0 border-2 border-border bg-white px-4 py-2 text-base font-sans outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-lg wobbly-border-md",
12
- "focus-visible:border-ring focus-visible:ring-ring/20 focus-visible:ring-[4px]",
13
- "aria-invalid:ring-destructive/20 aria-invalid:border-destructive",
14
- className,
15
- )}
16
- {...props}
17
- />
18
- );
19
- }
20
-
21
- export { Input };
@@ -1,328 +0,0 @@
1
- /**
2
- * Reverse-proxy plugin for the `dreamboard dev` Vite server.
3
- *
4
- * Every `/api/*` request the browser makes is intercepted here, run
5
- * through the Clerk OAuth refresh flow when needed, then forwarded to the configured upstream
6
- * backend with an `Authorization: Bearer <fresh-token>` header injected
7
- * on the wire. The access and refresh tokens never reach the browser.
8
- *
9
- * Failure contract:
10
- * - Permanent refresh failure (stored refresh token invalid) responds
11
- * with `401 { error: "session_invalid", message }` so the browser can
12
- * show a "Run dreamboard login" overlay instead of surfacing a
13
- * confusing upstream 401.
14
- * - Transient refresh failure (network blip) falls back to the snapshot
15
- * access token in `ResolvedConfig` when we still have one - this lets
16
- * a short outage degrade to "existing token" behavior instead of
17
- * blocking the iframe outright.
18
- * - Upstream connection failure responds with `502 { error:
19
- * "upstream_unavailable", message }`.
20
- *
21
- * The proxy is deliberately unaware of the session file / persist
22
- * endpoint / log relay; those live in `dev-log-relay-plugin.ts`.
23
- */
24
-
25
- import http, { type IncomingMessage, type ServerResponse } from "node:http";
26
- import https from "node:https";
27
- import { EventEmitter } from "node:events";
28
- import consola from "consola";
29
- import type { Plugin } from "vite";
30
- import {
31
- getAuthTokenExpiry,
32
- refreshResolvedAuthSession,
33
- } from "../config/resolve.js";
34
- import { resolveLocalHarnessAccessToken } from "../config/local-harness-auth.js";
35
- import type { ResolvedConfig } from "../types.js";
36
-
37
- export type ResolvedBearerOk = {
38
- readonly kind: "ok";
39
- readonly token: string | null;
40
- };
41
- export type ResolvedBearerPermanentFailure = {
42
- readonly kind: "permanent_invalid";
43
- readonly message: string;
44
- };
45
- export type ResolvedBearer = ResolvedBearerOk | ResolvedBearerPermanentFailure;
46
-
47
- export interface DevApiProxyPluginDeps {
48
- /**
49
- * Hook point for tests: resolve the bearer token (or a permanent
50
- * failure) synchronously once per request.
51
- */
52
- resolveBearer?: (config: ResolvedConfig) => Promise<ResolvedBearer>;
53
- /**
54
- * Hook point for tests: construct the underlying proxy. Allows
55
- * injecting an in-memory proxy that talks to a fake upstream.
56
- */
57
- createProxy?: (target: string) => DevApiProxy;
58
- }
59
-
60
- type DevApiProxy = {
61
- on(event: "error", listener: ProxyErrorListener): DevApiProxy;
62
- web(
63
- req: IncomingMessage,
64
- res: ServerResponse,
65
- options?: Record<string, never>,
66
- callback?: (err?: Error) => void,
67
- ): void;
68
- close(): void;
69
- };
70
-
71
- type ProxyErrorListener = (
72
- err: Error,
73
- req: IncomingMessage,
74
- res: ServerResponse,
75
- ) => void;
76
-
77
- export function createDevApiProxyPlugin(options: {
78
- config: ResolvedConfig;
79
- deps?: DevApiProxyPluginDeps;
80
- }): Plugin {
81
- const { config, deps } = options;
82
- const target = config.apiBaseUrl;
83
-
84
- return {
85
- name: "dreamboard-dev-api-proxy",
86
- configureServer(server) {
87
- const createProxy =
88
- deps?.createProxy ??
89
- ((proxyTarget: string) => createStreamingProxy(proxyTarget));
90
-
91
- const proxy = createProxy(target);
92
-
93
- proxy.on("error", (err, _req, res) => {
94
- consola.debug(`[dev-proxy] upstream error: ${formatUnknown(err)}`);
95
- if (res instanceof Object && "writeHead" in res && !res.headersSent) {
96
- respondUpstreamUnavailable(res as ServerResponse, err);
97
- } else if (res && "destroy" in res) {
98
- (res as { destroy: () => void }).destroy();
99
- }
100
- });
101
-
102
- const resolveBearer = deps?.resolveBearer ?? resolveDevBearer;
103
-
104
- // NOTE: we intentionally do NOT mount this middleware on `/api`.
105
- // Connect-style `middlewares.use(path, handler)` strips the mount
106
- // prefix from `req.url` before invoking the handler, which would
107
- // cause the proxy to forward `/sessions/.../status` instead of
108
- // `/api/sessions/.../status` and the backend would respond 404.
109
- // Filtering inside the handler keeps the full path intact.
110
- server.middlewares.use((req, res, next) => {
111
- if (!req.url || !isApiRequest(req.url)) {
112
- next();
113
- return;
114
- }
115
- void handleApiRequest({ req, res, config, proxy, resolveBearer });
116
- });
117
-
118
- server.httpServer?.once("close", () => {
119
- proxy.close();
120
- });
121
- },
122
- };
123
- }
124
-
125
- async function handleApiRequest(options: {
126
- req: IncomingMessage;
127
- res: ServerResponse;
128
- config: ResolvedConfig;
129
- proxy: DevApiProxy;
130
- resolveBearer: (config: ResolvedConfig) => Promise<ResolvedBearer>;
131
- }): Promise<void> {
132
- const { req, res, config, proxy, resolveBearer } = options;
133
- try {
134
- const bearer = await resolveBearer(config);
135
- if (bearer.kind === "permanent_invalid") {
136
- respondSessionInvalid(res, bearer.message);
137
- return;
138
- }
139
-
140
- if (bearer.token) {
141
- req.headers.authorization = `Bearer ${bearer.token}`;
142
- } else {
143
- delete req.headers.authorization;
144
- }
145
-
146
- proxy.web(req, res, {}, (err) => {
147
- if (!err) return;
148
- consola.debug(`[dev-proxy] forward error: ${formatUnknown(err)}`);
149
- if (!res.headersSent) {
150
- respondUpstreamUnavailable(res, err);
151
- }
152
- });
153
- } catch (err) {
154
- consola.debug(`[dev-proxy] pre-forward error: ${formatUnknown(err)}`);
155
- respondRefreshFailed(res, err);
156
- }
157
- }
158
-
159
- function createStreamingProxy(target: string): DevApiProxy {
160
- const targetUrl = new URL(target);
161
- const events = new EventEmitter();
162
- const activeRequests = new Set<http.ClientRequest>();
163
-
164
- const proxy: DevApiProxy = {
165
- on(event, listener) {
166
- events.on(event, listener);
167
- return proxy;
168
- },
169
- web(req, res, _options, callback) {
170
- const upstreamUrl = new URL(req.url ?? "/", targetUrl);
171
- const headers = createForwardHeaders(req, targetUrl);
172
-
173
- const client = targetUrl.protocol === "https:" ? https : http;
174
- const upstreamReq = client.request(
175
- upstreamUrl,
176
- {
177
- method: req.method,
178
- headers,
179
- },
180
- (upstreamRes) => {
181
- res.writeHead(
182
- upstreamRes.statusCode ?? 502,
183
- upstreamRes.statusMessage,
184
- upstreamRes.headers,
185
- );
186
- upstreamRes.pipe(res);
187
- },
188
- );
189
-
190
- activeRequests.add(upstreamReq);
191
-
192
- const handleError = (err: Error) => {
193
- activeRequests.delete(upstreamReq);
194
- callback?.(err);
195
- events.emit("error", err, req, res);
196
- };
197
-
198
- upstreamReq.on("error", handleError);
199
- upstreamReq.on("close", () => activeRequests.delete(upstreamReq));
200
- req.on("aborted", () => upstreamReq.destroy());
201
- req.pipe(upstreamReq);
202
- },
203
- close() {
204
- for (const request of activeRequests) {
205
- request.destroy();
206
- }
207
- activeRequests.clear();
208
- events.removeAllListeners();
209
- },
210
- };
211
-
212
- return proxy;
213
- }
214
-
215
- function createForwardHeaders(
216
- req: IncomingMessage,
217
- targetUrl: URL,
218
- ): http.OutgoingHttpHeaders {
219
- const headers: http.OutgoingHttpHeaders = { ...req.headers };
220
-
221
- // Browser requests are same-origin with the dev host. Once the CLI proxies
222
- // them to the backend, they are server-to-server requests; forwarding the
223
- // browser Origin from a Cloudflare/LAN host makes backend CORS reject valid
224
- // dev traffic.
225
- delete headers.origin;
226
- delete headers["access-control-request-headers"];
227
- delete headers["access-control-request-method"];
228
-
229
- headers.host = targetUrl.host;
230
- headers["x-forwarded-host"] = req.headers.host;
231
- headers["x-forwarded-proto"] = targetUrl.protocol.replace(":", "");
232
-
233
- return headers;
234
- }
235
-
236
- export async function resolveDevBearer(
237
- config: ResolvedConfig,
238
- ): Promise<ResolvedBearer> {
239
- const localHarnessToken = resolveLocalHarnessAccessToken(config);
240
- if (localHarnessToken) {
241
- return { kind: "ok", token: localHarnessToken };
242
- }
243
-
244
- // Env/flag-provided tokens are not owned by `CredentialStore` and must
245
- // not be rotated. Forward them as-is.
246
- if (!usesStoredSession(config)) {
247
- return { kind: "ok", token: config.authToken ?? null };
248
- }
249
-
250
- const expiry = getAuthTokenExpiry(config.authToken);
251
- const isExpired = expiry !== null && expiry.getTime() <= Date.now();
252
- if (!isExpired) {
253
- return { kind: "ok", token: config.authToken ?? null };
254
- }
255
-
256
- if (!config.refreshToken) {
257
- return {
258
- kind: "permanent_invalid",
259
- message:
260
- "Stored Dreamboard session is expired or invalid. Run `dreamboard login` to authenticate again.",
261
- };
262
- }
263
-
264
- const refreshed = await refreshResolvedAuthSession(config);
265
- return {
266
- kind: "ok",
267
- token: refreshed?.accessToken ?? config.authToken ?? null,
268
- };
269
- }
270
-
271
- function usesStoredSession(config: ResolvedConfig): boolean {
272
- return (
273
- config.authTokenSource === "global" &&
274
- config.refreshTokenSource === "global"
275
- );
276
- }
277
-
278
- function respondSessionInvalid(res: ServerResponse, message: string): void {
279
- if (res.headersSent) return;
280
- res.statusCode = 401;
281
- res.setHeader("content-type", "application/json");
282
- res.end(
283
- JSON.stringify({
284
- error: "session_invalid",
285
- message,
286
- }),
287
- );
288
- }
289
-
290
- function respondUpstreamUnavailable(res: ServerResponse, error: unknown): void {
291
- if (res.headersSent) return;
292
- res.statusCode = 502;
293
- res.setHeader("content-type", "application/json");
294
- res.end(
295
- JSON.stringify({
296
- error: "upstream_unavailable",
297
- message: formatUnknown(error),
298
- }),
299
- );
300
- }
301
-
302
- function respondRefreshFailed(res: ServerResponse, error: unknown): void {
303
- if (res.headersSent) return;
304
- res.statusCode = 502;
305
- res.setHeader("content-type", "application/json");
306
- res.end(
307
- JSON.stringify({
308
- error: "refresh_failed",
309
- message: formatUnknown(error),
310
- }),
311
- );
312
- }
313
-
314
- function isApiRequest(url: string): boolean {
315
- return url === "/api" || url.startsWith("/api/") || url.startsWith("/api?");
316
- }
317
-
318
- function formatUnknown(value: unknown): string {
319
- if (value instanceof Error) {
320
- return value.message || value.name || "Unknown error";
321
- }
322
- if (typeof value === "string") return value;
323
- try {
324
- return JSON.stringify(value);
325
- } catch {
326
- return String(value);
327
- }
328
- }
@@ -1,100 +0,0 @@
1
- type ZoneItemElement = Pick<Element, "getAttribute" | "querySelector">;
2
-
3
- type ZoneItemRoot = Pick<ParentNode, "querySelectorAll">;
4
-
5
- export interface PlayableZoneItemWarning {
6
- key: string;
7
- message: string;
8
- }
9
-
10
- const PLAYABLE_ZONE_ITEM_SELECTOR =
11
- '[data-dreamboard-zone-item][data-playable="true"]';
12
- const INTERACTION_CARD_INPUT_SELECTOR =
13
- "[data-dreamboard-interaction-card-input]";
14
-
15
- export function collectPlayableZoneItemWarnings(
16
- root: ZoneItemRoot,
17
- ): PlayableZoneItemWarning[] {
18
- const warnings: PlayableZoneItemWarning[] = [];
19
- for (const item of root.querySelectorAll(PLAYABLE_ZONE_ITEM_SELECTOR)) {
20
- const element = item as ZoneItemElement;
21
- if (element.querySelector(INTERACTION_CARD_INPUT_SELECTOR)) {
22
- continue;
23
- }
24
-
25
- const zone = element.getAttribute("data-zone") ?? "unknown";
26
- const cardId = element.getAttribute("data-card-id") ?? "unknown";
27
- const cardType = element.getAttribute("data-card-type") ?? null;
28
- const key = `${zone}:${cardId}`;
29
- const cardLabel =
30
- cardType && cardType !== cardId
31
- ? `'${cardId}' (${cardType})`
32
- : `'${cardId}'`;
33
- warnings.push({
34
- key,
35
- message: [
36
- `[dreamboard] Playable card ${cardLabel} in zone '${zone}' rendered without an interaction card input.`,
37
- "This usually means the UI rendered a raw Card/custom tile instead of <handSurface.Card>.",
38
- "Render the surface card consistently and let Dreamboard disable unavailable interactions.",
39
- ].join(" "),
40
- });
41
- }
42
- return warnings;
43
- }
44
-
45
- export function installPlayableZoneItemWarnings(
46
- options: {
47
- root?: Document;
48
- warn?: (...args: unknown[]) => void;
49
- MutationObserverImpl?: typeof MutationObserver;
50
- schedule?: (callback: () => void) => void;
51
- } = {},
52
- ): () => void {
53
- const root = options.root ?? document;
54
- const warn = options.warn ?? console.warn.bind(console);
55
- const MutationObserverImpl =
56
- options.MutationObserverImpl ?? window.MutationObserver;
57
- const schedule =
58
- options.schedule ??
59
- ((callback) => {
60
- window.requestAnimationFrame(callback);
61
- });
62
- const emitted = new Set<string>();
63
- let scheduled = false;
64
-
65
- const scan = () => {
66
- scheduled = false;
67
- for (const warning of collectPlayableZoneItemWarnings(root)) {
68
- if (emitted.has(warning.key)) {
69
- continue;
70
- }
71
- emitted.add(warning.key);
72
- warn(warning.message);
73
- }
74
- };
75
-
76
- const requestScan = () => {
77
- if (scheduled) {
78
- return;
79
- }
80
- scheduled = true;
81
- schedule(scan);
82
- };
83
-
84
- const observer = new MutationObserverImpl(requestScan);
85
- observer.observe(root.documentElement, {
86
- childList: true,
87
- subtree: true,
88
- attributes: true,
89
- attributeFilter: [
90
- "data-dreamboard-zone-item",
91
- "data-playable",
92
- "data-dreamboard-interaction-card-input",
93
- ],
94
- });
95
- requestScan();
96
-
97
- return () => {
98
- observer.disconnect();
99
- };
100
- }
@@ -1,62 +0,0 @@
1
- import type { LoggerLike } from "@dreamboard-games/ui-host-runtime/runtime";
2
-
3
- export type DevLogEnvelope = {
4
- source: "host" | "plugin" | "sse";
5
- level: "log" | "warn" | "error" | "info";
6
- message: string;
7
- };
8
-
9
- export type DevDiagnosticsLevel = "errors" | "verbose";
10
-
11
- export function resolveDevDiagnosticsLevel(
12
- debug: boolean,
13
- ): DevDiagnosticsLevel {
14
- return debug ? "verbose" : "errors";
15
- }
16
-
17
- export function createDevDiagnosticsLogger(
18
- level: DevDiagnosticsLevel,
19
- ): LoggerLike {
20
- if (level === "verbose") {
21
- return {
22
- log: (...args) => console.log(...args),
23
- warn: (...args) => console.warn(...args),
24
- error: (...args) => console.error(...args),
25
- };
26
- }
27
-
28
- return {
29
- log: () => {},
30
- warn: () => {},
31
- error: (...args) => console.error(...args),
32
- };
33
- }
34
-
35
- export function shouldRelayDevLog(
36
- diagnosticsLevel: DevDiagnosticsLevel,
37
- payload: DevLogEnvelope,
38
- ): boolean {
39
- return (
40
- diagnosticsLevel === "verbose" ||
41
- payload.level === "warn" ||
42
- payload.level === "error"
43
- );
44
- }
45
-
46
- export function formatConsoleArgs(args: unknown[]): string {
47
- return args.map((value) => stringifyForRelay(value)).join(" ");
48
- }
49
-
50
- export function stringifyForRelay(value: unknown): string {
51
- if (typeof value === "string") {
52
- return value;
53
- }
54
- if (value instanceof Error) {
55
- return value.stack ?? value.message;
56
- }
57
- try {
58
- return JSON.stringify(value);
59
- } catch {
60
- return String(value);
61
- }
62
- }
@@ -1,53 +0,0 @@
1
- import { createHash, randomUUID } from "node:crypto";
2
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
3
- import path from "node:path";
4
- import { normalizePath } from "vite";
5
-
6
- export function prepareFallbackStylesheet(options: {
7
- projectRoot: string;
8
- repoRoot: string;
9
- }): string | null {
10
- const projectStylePath = path.resolve(options.projectRoot, "ui/style.css");
11
- if (existsSync(projectStylePath)) {
12
- return null;
13
- }
14
-
15
- const generatedDir = path.resolve(options.repoRoot, ".dreamboard-dev");
16
- mkdirSync(generatedDir, { recursive: true });
17
-
18
- const fingerprint = createHash("sha256")
19
- .update(options.projectRoot, "utf8")
20
- .digest("hex")
21
- .slice(0, 8);
22
- const instanceId = randomUUID().replaceAll("-", "").slice(0, 8);
23
- const generatedPath = path.join(
24
- generatedDir,
25
- `plugin-styles-${fingerprint}-${instanceId}.css`,
26
- );
27
- const sharedStylesPath = normalizePath(
28
- path.resolve(
29
- options.repoRoot,
30
- "node_modules/@dreamboard-games/sdk/dist/ui/plugin-styles.css",
31
- ),
32
- );
33
- const uiSourcePath = normalizePath(
34
- path.resolve(options.projectRoot, "ui/**/*.{ts,tsx}"),
35
- );
36
- const sharedSourcePath = normalizePath(
37
- path.resolve(options.projectRoot, "shared/**/*.{ts,tsx}"),
38
- );
39
-
40
- writeFileSync(
41
- generatedPath,
42
- [
43
- `@import "/@fs/${sharedStylesPath}";`,
44
- "",
45
- `@source "${uiSourcePath}";`,
46
- `@source "${sharedSourcePath}";`,
47
- "",
48
- ].join("\n"),
49
- "utf8",
50
- );
51
-
52
- return generatedPath;
53
- }