lecodes-cli 0.19.0 → 0.19.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 (254) hide show
  1. package/dist/index.js +730 -235
  2. package/package.json +14 -13
  3. package/runtime/scene-harness.json +1 -1
  4. package/runtime/sdk-types.json +1 -1
  5. package/src/api.ts +302 -0
  6. package/src/browserAuth.ts +87 -0
  7. package/src/cmgenTool.ts +104 -0
  8. package/src/commands/app.ts +891 -0
  9. package/src/commands/appAndroid.ts +603 -0
  10. package/src/commands/appDesktop.ts +326 -0
  11. package/src/commands/appDesktopMac.ts +470 -0
  12. package/src/commands/appIcon.ts +187 -0
  13. package/src/commands/appShared.ts +448 -0
  14. package/src/commands/appTemplates.ts +883 -0
  15. package/src/commands/appTemplatesAndroid.ts +599 -0
  16. package/src/commands/appTemplatesGradlew.ts +9 -0
  17. package/src/commands/assets.ts +28 -0
  18. package/src/commands/clone.ts +60 -0
  19. package/src/commands/compile.ts +253 -0
  20. package/src/commands/create.ts +59 -0
  21. package/src/commands/design.ts +863 -0
  22. package/src/commands/designTemplates.ts +11 -0
  23. package/src/commands/desktop.ts +122 -0
  24. package/src/commands/dev.ts +214 -0
  25. package/src/commands/diff.ts +59 -0
  26. package/src/commands/init.ts +191 -0
  27. package/src/commands/install.ts +198 -0
  28. package/src/commands/lightmap.ts +290 -0
  29. package/src/commands/link.ts +147 -0
  30. package/src/commands/login.ts +24 -0
  31. package/src/commands/navmesh.ts +225 -0
  32. package/src/commands/pn.ts +305 -0
  33. package/src/commands/projectTemplates.ts +129 -0
  34. package/src/commands/pull.ts +109 -0
  35. package/src/commands/push.ts +173 -0
  36. package/src/commands/render.ts +414 -0
  37. package/src/commands/scene.ts +148 -0
  38. package/src/commands/shaders.ts +157 -0
  39. package/src/commands/status.ts +29 -0
  40. package/src/commands/test.ts +370 -0
  41. package/src/commands/thumbs.ts +178 -0
  42. package/src/commands/types.ts +87 -0
  43. package/src/commands/update.ts +190 -0
  44. package/src/compile/assetIcons.ts +214 -0
  45. package/src/compile/collect.ts +46 -0
  46. package/src/compile/collectLocal.ts +37 -0
  47. package/src/compile/designCompile.ts +104 -0
  48. package/src/compile/fonts.ts +156 -0
  49. package/src/compile/headlessBundle.ts +129 -0
  50. package/src/compile/nativeStack.ts +21 -0
  51. package/src/compile/projectCompile.ts +109 -0
  52. package/src/compile/sceneCompile.ts +113 -0
  53. package/src/compile/screenEntry.ts +127 -0
  54. package/src/compile/shaders.ts +245 -0
  55. package/src/config.ts +42 -0
  56. package/src/designMeta.ts +35 -0
  57. package/src/desktopRenderer.ts +532 -0
  58. package/src/desktopScript.ts +276 -0
  59. package/src/dev/clientTemplates.ts +160 -0
  60. package/src/dev/devServer.ts +292 -0
  61. package/src/dev/wsServer.ts +144 -0
  62. package/src/distRoot.ts +20 -0
  63. package/src/ignore.ts +163 -0
  64. package/src/index.ts +491 -0
  65. package/src/lecodes-3d-editor.d.ts +41 -0
  66. package/src/lecodes-assets.d.ts +7 -0
  67. package/src/lecodes-design.d.ts +191 -0
  68. package/src/lecodes-renderer.d.ts +131 -0
  69. package/src/localFiles.ts +144 -0
  70. package/src/manifest.ts +46 -0
  71. package/src/matcTool.ts +137 -0
  72. package/src/peers.ts +40 -0
  73. package/src/project.ts +61 -0
  74. package/src/projectEnv.ts +94 -0
  75. package/src/qrcode-terminal.d.ts +9 -0
  76. package/src/releases.ts +125 -0
  77. package/src/serverDiff.ts +78 -0
  78. package/src/textDiff.ts +103 -0
  79. package/src/types.ts +0 -0
  80. package/src/util.ts +146 -0
  81. package/runtime/sdk/animate/animate.ts +0 -238
  82. package/runtime/sdk/animate/bezier.ts +0 -138
  83. package/runtime/sdk/animate/easings.ts +0 -126
  84. package/runtime/sdk/canvas/Canvas.ts +0 -305
  85. package/runtime/sdk/compile/aspectMacro.ts +0 -86
  86. package/runtime/sdk/compile/assetIconMacro.ts +0 -384
  87. package/runtime/sdk/compile/assetMacro.ts +0 -146
  88. package/runtime/sdk/compile/assetName.ts +0 -50
  89. package/runtime/sdk/compile/bundler.ts +0 -287
  90. package/runtime/sdk/compile/compileProject.ts +0 -129
  91. package/runtime/sdk/compile/detectEntry.ts +0 -128
  92. package/runtime/sdk/compile/fontMacro.ts +0 -459
  93. package/runtime/sdk/compile/fontRegistry.ts +0 -78
  94. package/runtime/sdk/compile/header.ts +0 -67
  95. package/runtime/sdk/compile/index.ts +0 -100
  96. package/runtime/sdk/compile/libraryImports.ts +0 -52
  97. package/runtime/sdk/compile/liteMaterial.ts +0 -247
  98. package/runtime/sdk/compile/sceneEditor.ts +0 -88
  99. package/runtime/sdk/compile/serverSplit.ts +0 -233
  100. package/runtime/sdk/compile/serverTypes.ts +0 -227
  101. package/runtime/sdk/compile/sfnt.ts +0 -98
  102. package/runtime/sdk/compile/shaderSchema.ts +0 -202
  103. package/runtime/sdk/compile/shaderTargets.ts +0 -81
  104. package/runtime/sdk/compile/sourcemap.ts +0 -25
  105. package/runtime/sdk/core/Aspect.ts +0 -568
  106. package/runtime/sdk/core/InspectorUI.ts +0 -212
  107. package/runtime/sdk/core/StateMachine.ts +0 -308
  108. package/runtime/sdk/core/color.ts +0 -66
  109. package/runtime/sdk/core/compWrite.ts +0 -42
  110. package/runtime/sdk/core/events.ts +0 -38
  111. package/runtime/sdk/core/fields.ts +0 -120
  112. package/runtime/sdk/core/registry.ts +0 -23
  113. package/runtime/sdk/core/signals.ts +0 -277
  114. package/runtime/sdk/core/time.ts +0 -84
  115. package/runtime/sdk/g2/Camera2D.ts +0 -40
  116. package/runtime/sdk/g2/CharacterController2D.ts +0 -276
  117. package/runtime/sdk/g2/Node2D.ts +0 -267
  118. package/runtime/sdk/g2/OneWay2D.ts +0 -66
  119. package/runtime/sdk/g2/Physics2D.ts +0 -346
  120. package/runtime/sdk/g2/Scene2D.ts +0 -209
  121. package/runtime/sdk/g2/Shape2D.ts +0 -259
  122. package/runtime/sdk/g2/Sprite.ts +0 -89
  123. package/runtime/sdk/g2/SpriteAnimation.ts +0 -171
  124. package/runtime/sdk/g2/SpriteSheet.ts +0 -166
  125. package/runtime/sdk/g2/Texture2D.ts +0 -47
  126. package/runtime/sdk/g2/Tilemap.ts +0 -41
  127. package/runtime/sdk/g2/Tileset.ts +0 -71
  128. package/runtime/sdk/g2/Trigger2D.ts +0 -77
  129. package/runtime/sdk/g2/autotile.ts +0 -433
  130. package/runtime/sdk/g2/cells.ts +0 -91
  131. package/runtime/sdk/g2/defineScene2d.ts +0 -381
  132. package/runtime/sdk/g2/groups2d.ts +0 -106
  133. package/runtime/sdk/g2/loop.ts +0 -50
  134. package/runtime/sdk/g2/scenarios2d.ts +0 -69
  135. package/runtime/sdk/g2/touch.ts +0 -83
  136. package/runtime/sdk/gl/Camera.ts +0 -160
  137. package/runtime/sdk/gl/CameraPlace.ts +0 -52
  138. package/runtime/sdk/gl/CharacterController.ts +0 -238
  139. package/runtime/sdk/gl/Gearbox.ts +0 -212
  140. package/runtime/sdk/gl/Geometry.ts +0 -279
  141. package/runtime/sdk/gl/IK.ts +0 -193
  142. package/runtime/sdk/gl/InstancedMesh.ts +0 -132
  143. package/runtime/sdk/gl/Light.ts +0 -107
  144. package/runtime/sdk/gl/Lightmap.ts +0 -256
  145. package/runtime/sdk/gl/Material.ts +0 -260
  146. package/runtime/sdk/gl/Mesh.ts +0 -83
  147. package/runtime/sdk/gl/Model.ts +0 -124
  148. package/runtime/sdk/gl/NavAgent.ts +0 -337
  149. package/runtime/sdk/gl/NavMesh.ts +0 -397
  150. package/runtime/sdk/gl/Node.ts +0 -350
  151. package/runtime/sdk/gl/Noise.ts +0 -30
  152. package/runtime/sdk/gl/Particles.ts +0 -676
  153. package/runtime/sdk/gl/Physics.ts +0 -222
  154. package/runtime/sdk/gl/Plane.ts +0 -53
  155. package/runtime/sdk/gl/Ragdoll.ts +0 -270
  156. package/runtime/sdk/gl/Ray.ts +0 -16
  157. package/runtime/sdk/gl/Scene.ts +0 -486
  158. package/runtime/sdk/gl/Shape.ts +0 -409
  159. package/runtime/sdk/gl/Terrain.ts +0 -1092
  160. package/runtime/sdk/gl/Texture.ts +0 -63
  161. package/runtime/sdk/gl/Trigger.ts +0 -45
  162. package/runtime/sdk/gl/Vehicle.ts +0 -473
  163. package/runtime/sdk/gl/Wheel.ts +0 -240
  164. package/runtime/sdk/gl/animation/AnimationClip.ts +0 -204
  165. package/runtime/sdk/gl/animation/Animator.ts +0 -120
  166. package/runtime/sdk/gl/animation/Layer.ts +0 -31
  167. package/runtime/sdk/gl/animation/Loop.ts +0 -30
  168. package/runtime/sdk/gl/animation/Playback.ts +0 -44
  169. package/runtime/sdk/gl/animation/core.ts +0 -336
  170. package/runtime/sdk/gl/controls.ts +0 -95
  171. package/runtime/sdk/gl/physicsEvents.ts +0 -20
  172. package/runtime/sdk/gl/scenarios.ts +0 -291
  173. package/runtime/sdk/gl/state.ts +0 -6
  174. package/runtime/sdk/gl/terrainMesh.ts +0 -219
  175. package/runtime/sdk/gl/touch.ts +0 -68
  176. package/runtime/sdk/inject.ts +0 -197
  177. package/runtime/sdk/math/Mathf.ts +0 -118
  178. package/runtime/sdk/math/mat4.ts +0 -278
  179. package/runtime/sdk/math/quat.ts +0 -232
  180. package/runtime/sdk/math/vec.ts +0 -255
  181. package/runtime/sdk/net/codec.ts +0 -119
  182. package/runtime/sdk/net/core.ts +0 -384
  183. package/runtime/sdk/net/index.ts +0 -181
  184. package/runtime/sdk/net/replication.ts +0 -622
  185. package/runtime/sdk/plugins/camera.ts +0 -81
  186. package/runtime/sdk/plugins/geolocation.ts +0 -123
  187. package/runtime/sdk/plugins/oauth.ts +0 -61
  188. package/runtime/sdk/plugins/permission.ts +0 -7
  189. package/runtime/sdk/plugins/push.ts +0 -132
  190. package/runtime/sdk/plugins/qr.ts +0 -73
  191. package/runtime/sdk/plugins/service.ts +0 -47
  192. package/runtime/sdk/runtime/app.ts +0 -101
  193. package/runtime/sdk/runtime/appEvents.ts +0 -54
  194. package/runtime/sdk/runtime/channel.ts +0 -61
  195. package/runtime/sdk/runtime/clipboard.ts +0 -20
  196. package/runtime/sdk/runtime/datetime.ts +0 -329
  197. package/runtime/sdk/runtime/device.ts +0 -293
  198. package/runtime/sdk/runtime/fetch.ts +0 -77
  199. package/runtime/sdk/runtime/files.ts +0 -23
  200. package/runtime/sdk/runtime/input.ts +0 -175
  201. package/runtime/sdk/runtime/media.ts +0 -111
  202. package/runtime/sdk/runtime/misc.ts +0 -16
  203. package/runtime/sdk/runtime/net.ts +0 -36
  204. package/runtime/sdk/runtime/rpc.ts +0 -218
  205. package/runtime/sdk/runtime/service.ts +0 -83
  206. package/runtime/sdk/runtime/share.ts +0 -9
  207. package/runtime/sdk/runtime/storage.ts +0 -13
  208. package/runtime/sdk/runtime/touch.ts +0 -76
  209. package/runtime/sdk/scene/defineScene.ts +0 -1353
  210. package/runtime/sdk/scene/editorPlugins.ts +0 -110
  211. package/runtime/sdk/scene/gizmos.ts +0 -148
  212. package/runtime/sdk/scene/grammar.ts +0 -120
  213. package/runtime/sdk/scene/material.ts +0 -188
  214. package/runtime/sdk/server/auth/appConfig.ts +0 -12
  215. package/runtime/sdk/server/auth/global.ts +0 -80
  216. package/runtime/sdk/server/auth/host.ts +0 -318
  217. package/runtime/sdk/server/auth/models.ts +0 -83
  218. package/runtime/sdk/server/auth/types.ts +0 -50
  219. package/runtime/sdk/server/channel.ts +0 -56
  220. package/runtime/sdk/server/context.ts +0 -36
  221. package/runtime/sdk/server/db/defineDb.ts +0 -237
  222. package/runtime/sdk/server/db/fields.ts +0 -132
  223. package/runtime/sdk/server/db/httpTransport.ts +0 -93
  224. package/runtime/sdk/server/db/index.ts +0 -7
  225. package/runtime/sdk/server/db/marci/query.ts +0 -412
  226. package/runtime/sdk/server/db/types.ts +0 -202
  227. package/runtime/sdk/server/errors.ts +0 -12
  228. package/runtime/sdk/server/host.ts +0 -74
  229. package/runtime/sdk/server/inject.ts +0 -13
  230. package/runtime/sdk/server/runtime.ts +0 -133
  231. package/runtime/sdk/server/validate.ts +0 -87
  232. package/runtime/sdk/ui/NativeView.ts +0 -142
  233. package/runtime/sdk/ui/UI.ts +0 -39
  234. package/runtime/sdk/ui/UIBottomSheet.ts +0 -139
  235. package/runtime/sdk/ui/UIButton.ts +0 -101
  236. package/runtime/sdk/ui/UIContainer.ts +0 -60
  237. package/runtime/sdk/ui/UIImage.ts +0 -83
  238. package/runtime/sdk/ui/UIInput.ts +0 -185
  239. package/runtime/sdk/ui/UIModal.ts +0 -139
  240. package/runtime/sdk/ui/UINode.ts +0 -830
  241. package/runtime/sdk/ui/UIPager.ts +0 -362
  242. package/runtime/sdk/ui/UIPopover.ts +0 -100
  243. package/runtime/sdk/ui/UIScreen.ts +0 -123
  244. package/runtime/sdk/ui/UIScrollable.ts +0 -87
  245. package/runtime/sdk/ui/UISpacer.ts +0 -14
  246. package/runtime/sdk/ui/UITabs.ts +0 -236
  247. package/runtime/sdk/ui/UIText.ts +0 -51
  248. package/runtime/sdk/ui/UIVideo.ts +0 -88
  249. package/runtime/sdk/ui/UIVirtualizedList.ts +0 -241
  250. package/runtime/sdk/ui/UIWidget.ts +0 -127
  251. package/runtime/sdk/ui/fonts.ts +0 -13
  252. package/runtime/sdk/ui/presentable.ts +0 -117
  253. package/runtime/sdk/ui/router.ts +0 -132
  254. package/runtime/sdk/ui/theme.ts +0 -84
@@ -1,16 +0,0 @@
1
- // Small platform globals that are real (not engine-specific). Grown in Phase 1.
2
-
3
- /** Show a transient toast notification. */
4
- export const toast = (msg: string): void => _creatorUI.toast(msg)
5
-
6
- /** Open `url` in the system browser / external handler (fire-and-forget, like `share`). Silent
7
- * no-op on hosts without one (headless). */
8
- export const openURL = (url: string): void => _creatorUtils.openUrl?.(url)
9
-
10
- export type SvgSourceValue = {
11
- readonly svg: string
12
- tintColor: string | null
13
- }
14
-
15
- /** Wrap raw SVG XML so it can be used as an image source. */
16
- export const SvgSource = (svg: string): SvgSourceValue => ({ svg, tintColor: null })
@@ -1,36 +0,0 @@
1
- // WebSocket over the host bridge. Same event surface as the browser's (open/message/close/error)
2
- // via the shared Emitter. Ported from worker/src/WebSocket.ts.
3
-
4
- import { Emitter } from "../core/events"
5
-
6
- type SocketEvents = {
7
- open: () => void
8
- message: (data: any) => void
9
- close: (code?: number) => void
10
- error: () => void
11
- }
12
-
13
- export class WebSocket extends Emitter<SocketEvents> {
14
- private _id: number | null = null
15
-
16
- constructor(url: string, headers?: Record<string, string>) {
17
- super()
18
- this._id = _creatorUtils.websocketOpen(url, (channel, data) => this._onMessage(channel, data), headers)
19
- }
20
-
21
- send(message: string | ArrayBuffer): void {
22
- if (this._id !== null) _creatorUtils.websocketSend(this._id, message)
23
- }
24
-
25
- close(): void {
26
- if (this._id !== null) {
27
- _creatorUtils.websocketClose(this._id)
28
- this._id = null
29
- }
30
- }
31
-
32
- private _onMessage(channel: string, data: any): void {
33
- if (data !== undefined && data !== null) this.dispatch(channel as keyof SocketEvents, data)
34
- else this.dispatch(channel as keyof SocketEvents)
35
- }
36
- }
@@ -1,218 +0,0 @@
1
- /**
2
- * Client transport for the app backend (docs/backend-plan.md §3.2 / §3.3). The compiler replaces
3
- * every `*.server.ts` module in the client bundle with a stub whose exports are built by the three
4
- * globals below — user code never calls them; it imports the server function and calls it.
5
- *
6
- * export const listNotes = __rpc("<serverUrl>", "notes.server.ts#listNotes")
7
- * export const chat = __channel("<serverUrl>", "chat.server.ts#chat")
8
- * export const db = __serverOnly("schema.server.ts#db")
9
- *
10
- * Wire (implemented by the runner):
11
- * POST <serverUrl>/api/<id> body {"args":[…]}, `authorization: Bearer <session>` when known
12
- * → 200 {"ok":true,"result":…,"session"?:"…"} | {"ok":false,"status":n,"message":"…","session"?:"…"}
13
- * WS <serverUrl>/ws frames: → {t:"hello",session} {t:"sub",id,ch,topic} {t:"unsub",id}
14
- * ← {t:"session",session} {t:"ok",id} {t:"err",id,status,message} {t:"ev",ch,topic,event,data}
15
- * (`ev` is addressed by channel + topic, not by subscription id, so the server can fan one publish out
16
- * to every socket of a topic natively; the client delivers it to each matching subscription.)
17
- *
18
- * The session token is transport-owned (cookie-like): stored under `lecodes.session:<serverUrl>` in
19
- * localStorage, sent on every call and on the socket, replaced whenever a response carries `session`.
20
- * User code never sees it — "am I logged in" is an endpoint (`me()`), see the plan.
21
- */
22
-
23
- import { fetch } from "./fetch"
24
- import { localStorage } from "./storage"
25
- import { WebSocket } from "./net"
26
-
27
- /** Rejection value of a failed endpoint call: `status` mirrors the server's `ApiError`
28
- * (0 = the request itself failed: no network / no server). */
29
- export class RpcError extends Error {
30
- readonly status: number
31
- constructor(status: number, message: string) {
32
- super(message)
33
- this.name = "RpcError"
34
- this.status = status
35
- }
36
- }
37
-
38
- // ───────────────────────────── session token ─────────────────────────────
39
-
40
- const sessionKey = (serverUrl: string) => `lecodes.session:${serverUrl}`
41
- const getSession = (serverUrl: string): string | null => {
42
- try { return localStorage.getItem(sessionKey(serverUrl)) } catch { return null }
43
- }
44
- const setSession = (serverUrl: string, token: string | null) => {
45
- try {
46
- if (token) localStorage.setItem(sessionKey(serverUrl), token)
47
- else localStorage.removeItem(sessionKey(serverUrl))
48
- } catch { /* storage-less host: the session lives for this run only */ }
49
- sockets.get(serverUrl)?.onSessionChanged(token)
50
- }
51
-
52
- // ───────────────────────────── endpoints ─────────────────────────────
53
-
54
- const noServer = (id: string) => new RpcError(0, `Endpoint ${id}: the project has no deployed server (compile with serverUrl)`)
55
-
56
- /** Build the client proxy of endpoint `id`. Positional args travel as a JSON array. */
57
- export const __rpc = (serverUrl: string, id: string) => {
58
- const call = async (...args: unknown[]): Promise<any> => {
59
- if (!serverUrl) throw noServer(id)
60
- const headers: Record<string, string> = { "content-type": "application/json" }
61
- const session = getSession(serverUrl)
62
- if (session) headers.authorization = `Bearer ${session}`
63
- let res
64
- try {
65
- res = await fetch(`${serverUrl}/api/${encodeURIComponent(id)}`, { method: "POST", headers, body: JSON.stringify({ args }) })
66
- } catch (e) {
67
- throw new RpcError(0, `Endpoint ${id}: request failed (${(e as Error)?.message ?? e})`)
68
- }
69
- let body: any
70
- try { body = res.json() } catch { body = null }
71
- res.dispose()
72
- if (body && typeof body === "object" && "session" in body) setSession(serverUrl, body.session ?? null)
73
- if (body && body.ok === true) return body.result
74
- if (body && body.ok === false) throw new RpcError(body.status ?? res.status, body.message ?? "")
75
- throw new RpcError(res.status, `Endpoint ${id}: unexpected response (HTTP ${res.status})`)
76
- }
77
- return call
78
- }
79
-
80
- /** A server-only export (db, models, helpers) referenced from client code: any use throws. */
81
- export const __serverOnly = (id: string): any =>
82
- new Proxy(function () {} as any, {
83
- get: (_t, prop) => { if (prop === "then") return undefined; throw new RpcError(0, `${id} is server-only — it can't be used in client code`) },
84
- apply: () => { throw new RpcError(0, `${id} is server-only — it can't be used in client code`) },
85
- })
86
-
87
- // ───────────────────────────── channels ─────────────────────────────
88
-
89
- type Handlers = Record<string, ((payload: any) => void) | undefined> & {
90
- /** The socket dropped and came back: subscriptions were re-sent, but events in between are lost — refetch. */
91
- reconnect?: () => void
92
- /** The subscription was refused (`onJoin` threw) or the socket can't connect. */
93
- error?: (e: RpcError) => void
94
- }
95
- type Sub = { id: number, ch: string, topic: string, handlers: Handlers, ready: boolean }
96
-
97
- const BACKOFF_MS = [1000, 2000, 5000, 10000, 30000]
98
-
99
- /** One multiplexed socket per server URL, shared by every channel of the app. */
100
- class ChannelSocket {
101
- private ws: WebSocket | null = null
102
- private open = false
103
- private subs = new Map<number, Sub>()
104
- private nextId = 1
105
- private attempts = 0
106
- private timer: ReturnType<typeof setTimeout> | null = null
107
- private closedByUs = false
108
- private everOpened = false
109
- private serverUrl: string
110
-
111
- constructor(serverUrl: string) { this.serverUrl = serverUrl }
112
-
113
- subscribe(ch: string, topic: string, handlers: Handlers): { close(): void } {
114
- const sub: Sub = { id: this.nextId++, ch, topic, handlers, ready: false }
115
- this.subs.set(sub.id, sub)
116
- if (this.open) this.send({ t: "sub", id: sub.id, ch, topic })
117
- else this.connect()
118
- return {
119
- close: () => {
120
- if (!this.subs.delete(sub.id)) return
121
- if (this.open) this.send({ t: "unsub", id: sub.id })
122
- if (this.subs.size === 0) this.shutdown()
123
- },
124
- }
125
- }
126
-
127
- onSessionChanged(token: string | null) {
128
- if (this.open) this.send({ t: "hello", session: token })
129
- }
130
-
131
- private connect() {
132
- if (this.ws || this.timer !== null) return
133
- this.closedByUs = false
134
- const url = this.serverUrl.replace(/^http/, "ws") + "/ws"
135
- const session = getSession(this.serverUrl)
136
- const ws = new WebSocket(url, session ? { authorization: `Bearer ${session}` } : undefined)
137
- this.ws = ws
138
- ws.addEventListener("open", () => {
139
- this.open = true
140
- this.attempts = 0
141
- this.send({ t: "hello", session: getSession(this.serverUrl) })
142
- const reconnected = this.everOpened
143
- this.everOpened = true
144
- for (const sub of this.subs.values()) {
145
- sub.ready = false
146
- this.send({ t: "sub", id: sub.id, ch: sub.ch, topic: sub.topic })
147
- if (reconnected) sub.handlers.reconnect?.()
148
- }
149
- })
150
- ws.addEventListener("message", (data) => {
151
- if (typeof data !== "string") return
152
- let msg: any
153
- try { msg = JSON.parse(data) } catch { return }
154
- this.onFrame(msg)
155
- })
156
- const onDown = () => {
157
- if (this.ws !== ws) return
158
- this.ws = null
159
- this.open = false
160
- if (this.closedByUs || this.subs.size === 0) return
161
- const delay = BACKOFF_MS[Math.min(this.attempts++, BACKOFF_MS.length - 1)]
162
- this.timer = setTimeout(() => { this.timer = null; this.connect() }, delay)
163
- }
164
- ws.addEventListener("close", onDown)
165
- ws.addEventListener("error", onDown)
166
- }
167
-
168
- private onFrame(msg: any) {
169
- switch (msg?.t) {
170
- case "session": setSession(this.serverUrl, msg.session ?? null); break
171
- case "ok": { const s = this.subs.get(msg.id); if (s) s.ready = true; break }
172
- case "err": {
173
- const s = this.subs.get(msg.id)
174
- if (!s) break
175
- this.subs.delete(msg.id)
176
- s.handlers.error?.(new RpcError(msg.status ?? 0, msg.message ?? "subscription refused"))
177
- break
178
- }
179
- case "ev": {
180
- for (const s of this.subs.values()) {
181
- if (s.ch === msg.ch && s.topic === msg.topic) s.handlers[msg.event]?.(msg.data)
182
- }
183
- break
184
- }
185
- }
186
- }
187
-
188
- private send(frame: unknown) { this.ws?.send(JSON.stringify(frame)) }
189
-
190
- private shutdown() {
191
- this.closedByUs = true
192
- if (this.timer !== null) { clearTimeout(this.timer); this.timer = null }
193
- this.ws?.close()
194
- this.ws = null
195
- this.open = false
196
- sockets.delete(this.serverUrl)
197
- }
198
- }
199
-
200
- const sockets = new Map<string, ChannelSocket>()
201
- const socketFor = (serverUrl: string) => {
202
- let s = sockets.get(serverUrl)
203
- if (!s) { s = new ChannelSocket(serverUrl); sockets.set(serverUrl, s) }
204
- return s
205
- }
206
-
207
- export interface ClientChannel<E extends Record<string, unknown> = Record<string, unknown>> {
208
- /** Subscribe to `topic`; handlers are keyed by event name (+ `reconnect`/`error`). Returns `{ close }`. */
209
- subscribe(topic: string, handlers: { [K in keyof E]?: (payload: E[K]) => void } & { reconnect?: () => void, error?: (e: RpcError) => void }): { close(): void }
210
- }
211
-
212
- /** Build the client proxy of channel `id`. */
213
- export const __channel = (serverUrl: string, id: string): ClientChannel<any> => ({
214
- subscribe(topic, handlers) {
215
- if (!serverUrl) throw noServer(id)
216
- return socketFor(serverUrl).subscribe(id, topic, handlers as Handlers)
217
- },
218
- })
@@ -1,83 +0,0 @@
1
- // A host-registered headless service (geolocation, bluetooth, contacts, …) — the UI-less sibling
2
- // of NativeView (docs/service-channel-plan.md). The host registers a *capability*
3
- // (`registerService("geolocation") { params, channel -> ... }`); the SDK talks to it over the
4
- // shared JSON call/event protocol (runtime/channel.ts) via `_creatorUtils.service*`.
5
- //
6
- // Not a public global itself: apps meet services through typed plugin wrappers (Geolocation —
7
- // src/plugins/) or the raw `Service(name)` global (src/plugins/service.ts), both thin layers
8
- // over this exactly like QRScanner wraps NativeViewElement.
9
-
10
- import { _channelCall, _channelEmit, _channelOff, _channelOn, type ChannelListeners } from "./channel"
11
-
12
- /** @internal Base for typed service plugins. The host session opens lazily on the first `call()`
13
- * (`on()` only records listeners), and `close()` releases it — a later `call()` reopens a fresh
14
- * session. Session ids are host-allocated (websocket model): the `onEvent` callback is handed
15
- * over at open, so no SDK-side ref registry is needed. */
16
- export class ServiceClient {
17
- readonly serviceName: string
18
- readonly params: any
19
- private _serviceId: number | null = null
20
- private readonly _listeners: ChannelListeners = {}
21
-
22
- constructor(serviceName: string, params: any = {}) {
23
- this.serviceName = serviceName
24
- this.params = params
25
- }
26
-
27
- /** Whether this host registered a `registerService` factory under `name`. */
28
- static isSupported(name: string): boolean {
29
- return typeof _creatorUtils !== "undefined" && typeof _creatorUtils.isServiceSupported === "function"
30
- && _creatorUtils.isServiceSupported(name)
31
- }
32
-
33
- /** @internal open (or reuse) the host session; throws when the host has no channel/factory. */
34
- private _ensureOpen(): number {
35
- if (this._serviceId !== null) return this._serviceId
36
- if (typeof _creatorUtils === "undefined" || typeof _creatorUtils.serviceOpen !== "function") {
37
- throw new Error(`Service("${this.serviceName}") is not supported on this host (requires _creatorUtils.serviceOpen)`)
38
- }
39
- const id = _creatorUtils.serviceOpen(this.serviceName, JSON.stringify(this.params ?? {}),
40
- (event: string, dataJson?: string) => _channelEmit(this._listeners, event, dataJson))
41
- if (id < 0) {
42
- throw new Error(`Service("${this.serviceName}") is not registered on this host`)
43
- }
44
- this._serviceId = id
45
- return id
46
- }
47
-
48
- /** Invoke a method on the service (`geo.call("getCurrent", options)`). Args and the result are
49
- * JSON-serialized. Rejects if the host has no such service/method. */
50
- call(method: string, ...args: any[]): Promise<any> {
51
- let id: number
52
- try {
53
- id = this._ensureOpen()
54
- } catch (e) {
55
- return Promise.reject(e)
56
- }
57
- return _channelCall(
58
- typeof _creatorUtils !== "undefined" ? _creatorUtils : undefined, "serviceCall",
59
- `Service("${this.serviceName}") is not supported on this host (requires _creatorUtils.serviceCall)`,
60
- id, method, args)
61
- }
62
-
63
- /** Subscribe to an event the service emits (`geo.on("position", cb)`). */
64
- on(event: string, callback: (data?: any) => void): this {
65
- _channelOn(this._listeners, event, callback)
66
- return this
67
- }
68
- off(event: string, callback: (data?: any) => void): this {
69
- _channelOff(this._listeners, event, callback)
70
- return this
71
- }
72
-
73
- /** Close the host session (stops whatever the service was doing). Listeners stay registered —
74
- * a later `call()` opens a fresh session that delivers to them again. */
75
- close(): void {
76
- if (this._serviceId === null) return
77
- const id = this._serviceId
78
- this._serviceId = null
79
- if (typeof _creatorUtils !== "undefined" && typeof _creatorUtils.serviceClose === "function") {
80
- _creatorUtils.serviceClose(id)
81
- }
82
- }
83
- }
@@ -1,9 +0,0 @@
1
- // Share a media File (image/video) via the OS share sheet. Wraps `_creatorUtils.shareMedia`, which
2
- // takes the host buffer id behind the File. On iOS the sheet also lets the user save to Files/Photos;
3
- // on web it saves (downloads) the file. `text` is an optional caption/message.
4
-
5
- import type { File, FetchResponse } from "./fetch"
6
-
7
- export function share(media: File | FetchResponse, text?: string): void {
8
- _creatorUtils.shareMedia((media as any)._id, text)
9
- }
@@ -1,13 +0,0 @@
1
- // Key/value persistence backed by the host. Same shape as the web localStorage subset projects use.
2
-
3
- export const localStorage = {
4
- getItem(key: string): string | null {
5
- return _creatorUtils.localStorageGetValue(key)
6
- },
7
- setItem(key: string, value: string): void {
8
- _creatorUtils.localStorageSetValue(key, value)
9
- },
10
- removeItem(key: string): void {
11
- _creatorUtils.localStorageRemoveValue(key)
12
- },
13
- }
@@ -1,76 +0,0 @@
1
- // Pointer event objects delivered to 3D scene/node touch handlers. Ported from worker/src/TouchEvent.ts.
2
- // The dispatch wiring (reading the active scene, hit entity) is set up in Phase 4 with the 3D Scene;
3
- // these classes are the injected globals user code receives. `target` is the hit Node (typed loosely
4
- // here to avoid a forward dependency on gl/).
5
-
6
- export class ClickEvent<T = any> {
7
- readonly type = "click"
8
- readonly pointerId: number
9
- readonly clientX: number
10
- readonly clientY: number
11
- /** World-space hit position (2D scenes only; undefined in 3D). */
12
- worldX?: number
13
- worldY?: number
14
- target!: T
15
- constructor(clientX: number, clientY: number, pointerId: number) {
16
- this.clientX = clientX
17
- this.clientY = clientY
18
- this.pointerId = pointerId
19
- }
20
- }
21
-
22
- export interface TrackHandler {
23
- onMove?(pos: { clientX: number, clientY: number, deltaX: number, deltaY: number }): void
24
- onEnd?(pos: { clientX: number, clientY: number, deltaX: number, deltaY: number }): void
25
- onCancel?(): void
26
- claim?: boolean | "pan-x" | "pan-y" | "pan-down" | "pan-up" | "pan-left" | "pan-right"
27
- }
28
-
29
- export class TouchStartEvent<T = any> {
30
- readonly type = "touchstart"
31
- readonly pointerId: number
32
- readonly clientX: number
33
- readonly clientY: number
34
- /** World-space hit position (2D scenes only; undefined in 3D). */
35
- worldX?: number
36
- worldY?: number
37
- target!: T
38
- /** @internal — read by the dispatch system after the handler runs. */
39
- _trackHandler?: TrackHandler
40
- constructor(clientX: number, clientY: number, pointerId: number) {
41
- this.clientX = clientX
42
- this.clientY = clientY
43
- this.pointerId = pointerId
44
- }
45
-
46
- /** Capture subsequent moves/end for this pointer (drag/pan gestures). */
47
- track(handler: TrackHandler): void {
48
- this._trackHandler = handler
49
- }
50
- }
51
-
52
- /** Delivered to a `UIButton` `onLongPress` handler when a finger is held on the button past the
53
- * host's long-press threshold. Like `TouchStartEvent` it can `track(...)` the rest of the gesture —
54
- * so the common "press-and-hold, then drag to move" flow is one handler: start the drag from here. */
55
- export class LongPressEvent<T = any> {
56
- readonly type = "longpress"
57
- readonly pointerId: number
58
- readonly clientX: number
59
- readonly clientY: number
60
- /** World-space hit position (2D scenes only; undefined in 3D). */
61
- worldX?: number
62
- worldY?: number
63
- target!: T
64
- /** @internal — read by the dispatch system after the handler runs. */
65
- _trackHandler?: TrackHandler
66
- constructor(clientX: number, clientY: number, pointerId: number) {
67
- this.clientX = clientX
68
- this.clientY = clientY
69
- this.pointerId = pointerId
70
- }
71
-
72
- /** Capture subsequent moves/end for this pointer — drag the element after the hold. */
73
- track(handler: TrackHandler): void {
74
- this._trackHandler = handler
75
- }
76
- }