lecodes-cli 0.18.2 → 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.
- package/dist/index.js +1866 -301
- package/package.json +14 -12
- package/runtime/scene-harness.json +1 -1
- package/runtime/sdk-types.json +1 -1
- package/src/api.ts +302 -0
- package/src/browserAuth.ts +87 -0
- package/src/cmgenTool.ts +104 -0
- package/src/commands/app.ts +891 -0
- package/src/commands/appAndroid.ts +603 -0
- package/src/commands/appDesktop.ts +326 -0
- package/src/commands/appDesktopMac.ts +470 -0
- package/src/commands/appIcon.ts +187 -0
- package/src/commands/appShared.ts +448 -0
- package/src/commands/appTemplates.ts +883 -0
- package/src/commands/appTemplatesAndroid.ts +599 -0
- package/src/commands/appTemplatesGradlew.ts +9 -0
- package/src/commands/assets.ts +28 -0
- package/src/commands/clone.ts +60 -0
- package/src/commands/compile.ts +253 -0
- package/src/commands/create.ts +59 -0
- package/src/commands/design.ts +863 -0
- package/src/commands/designTemplates.ts +11 -0
- package/src/commands/desktop.ts +122 -0
- package/src/commands/dev.ts +214 -0
- package/src/commands/diff.ts +59 -0
- package/src/commands/init.ts +191 -0
- package/src/commands/install.ts +198 -0
- package/src/commands/lightmap.ts +290 -0
- package/src/commands/link.ts +147 -0
- package/src/commands/login.ts +24 -0
- package/src/commands/navmesh.ts +225 -0
- package/src/commands/pn.ts +305 -0
- package/src/commands/projectTemplates.ts +129 -0
- package/src/commands/pull.ts +109 -0
- package/src/commands/push.ts +173 -0
- package/src/commands/render.ts +414 -0
- package/src/commands/scene.ts +148 -0
- package/src/commands/shaders.ts +157 -0
- package/src/commands/status.ts +29 -0
- package/src/commands/test.ts +370 -0
- package/src/commands/thumbs.ts +178 -0
- package/src/commands/types.ts +87 -0
- package/src/commands/update.ts +190 -0
- package/src/compile/assetIcons.ts +214 -0
- package/src/compile/collect.ts +46 -0
- package/src/compile/collectLocal.ts +37 -0
- package/src/compile/designCompile.ts +104 -0
- package/src/compile/fonts.ts +156 -0
- package/src/compile/headlessBundle.ts +129 -0
- package/src/compile/nativeStack.ts +21 -0
- package/src/compile/projectCompile.ts +109 -0
- package/src/compile/sceneCompile.ts +113 -0
- package/src/compile/screenEntry.ts +127 -0
- package/src/compile/shaders.ts +245 -0
- package/src/config.ts +42 -0
- package/src/designMeta.ts +35 -0
- package/src/desktopRenderer.ts +532 -0
- package/src/desktopScript.ts +276 -0
- package/src/dev/clientTemplates.ts +160 -0
- package/src/dev/devServer.ts +292 -0
- package/src/dev/wsServer.ts +144 -0
- package/src/distRoot.ts +20 -0
- package/src/ignore.ts +163 -0
- package/src/index.ts +491 -0
- package/src/lecodes-3d-editor.d.ts +41 -0
- package/src/lecodes-assets.d.ts +7 -0
- package/src/lecodes-design.d.ts +191 -0
- package/src/lecodes-renderer.d.ts +131 -0
- package/src/localFiles.ts +144 -0
- package/src/manifest.ts +46 -0
- package/src/matcTool.ts +137 -0
- package/src/peers.ts +40 -0
- package/src/project.ts +61 -0
- package/src/projectEnv.ts +94 -0
- package/src/qrcode-terminal.d.ts +9 -0
- package/src/releases.ts +125 -0
- package/src/serverDiff.ts +78 -0
- package/src/textDiff.ts +103 -0
- package/src/types.ts +0 -0
- package/src/util.ts +146 -0
- package/runtime/sdk/animate/animate.ts +0 -238
- package/runtime/sdk/animate/bezier.ts +0 -138
- package/runtime/sdk/animate/easings.ts +0 -126
- package/runtime/sdk/canvas/Canvas.ts +0 -305
- package/runtime/sdk/core/Aspect.ts +0 -512
- package/runtime/sdk/core/InspectorUI.ts +0 -212
- package/runtime/sdk/core/color.ts +0 -66
- package/runtime/sdk/core/compWrite.ts +0 -42
- package/runtime/sdk/core/events.ts +0 -38
- package/runtime/sdk/core/fields.ts +0 -120
- package/runtime/sdk/core/registry.ts +0 -23
- package/runtime/sdk/core/signals.ts +0 -277
- package/runtime/sdk/core/time.ts +0 -81
- package/runtime/sdk/g2/Camera2D.ts +0 -40
- package/runtime/sdk/g2/CharacterController2D.ts +0 -276
- package/runtime/sdk/g2/Node2D.ts +0 -267
- package/runtime/sdk/g2/OneWay2D.ts +0 -66
- package/runtime/sdk/g2/Physics2D.ts +0 -346
- package/runtime/sdk/g2/Scene2D.ts +0 -209
- package/runtime/sdk/g2/Shape2D.ts +0 -259
- package/runtime/sdk/g2/Sprite.ts +0 -89
- package/runtime/sdk/g2/SpriteAnimation.ts +0 -171
- package/runtime/sdk/g2/SpriteSheet.ts +0 -166
- package/runtime/sdk/g2/Texture2D.ts +0 -47
- package/runtime/sdk/g2/Tilemap.ts +0 -41
- package/runtime/sdk/g2/Tileset.ts +0 -71
- package/runtime/sdk/g2/Trigger2D.ts +0 -77
- package/runtime/sdk/g2/autotile.ts +0 -433
- package/runtime/sdk/g2/cells.ts +0 -91
- package/runtime/sdk/g2/defineScene2d.ts +0 -381
- package/runtime/sdk/g2/groups2d.ts +0 -106
- package/runtime/sdk/g2/loop.ts +0 -50
- package/runtime/sdk/g2/scenarios2d.ts +0 -69
- package/runtime/sdk/g2/touch.ts +0 -83
- package/runtime/sdk/gl/Camera.ts +0 -160
- package/runtime/sdk/gl/CameraPlace.ts +0 -52
- package/runtime/sdk/gl/CharacterController.ts +0 -238
- package/runtime/sdk/gl/Gearbox.ts +0 -212
- package/runtime/sdk/gl/Geometry.ts +0 -279
- package/runtime/sdk/gl/IK.ts +0 -193
- package/runtime/sdk/gl/InstancedMesh.ts +0 -132
- package/runtime/sdk/gl/Light.ts +0 -99
- package/runtime/sdk/gl/Lightmap.ts +0 -179
- package/runtime/sdk/gl/Material.ts +0 -245
- package/runtime/sdk/gl/Mesh.ts +0 -83
- package/runtime/sdk/gl/Model.ts +0 -64
- package/runtime/sdk/gl/Node.ts +0 -350
- package/runtime/sdk/gl/Noise.ts +0 -30
- package/runtime/sdk/gl/Particles.ts +0 -676
- package/runtime/sdk/gl/Physics.ts +0 -222
- package/runtime/sdk/gl/Plane.ts +0 -53
- package/runtime/sdk/gl/Ray.ts +0 -16
- package/runtime/sdk/gl/Scene.ts +0 -479
- package/runtime/sdk/gl/Shape.ts +0 -377
- package/runtime/sdk/gl/Texture.ts +0 -46
- package/runtime/sdk/gl/Trigger.ts +0 -45
- package/runtime/sdk/gl/Vehicle.ts +0 -473
- package/runtime/sdk/gl/Wheel.ts +0 -240
- package/runtime/sdk/gl/animation/AnimationClip.ts +0 -204
- package/runtime/sdk/gl/animation/Animator.ts +0 -87
- package/runtime/sdk/gl/animation/Layer.ts +0 -29
- package/runtime/sdk/gl/animation/Loop.ts +0 -25
- package/runtime/sdk/gl/animation/Playback.ts +0 -43
- package/runtime/sdk/gl/animation/core.ts +0 -294
- package/runtime/sdk/gl/controls.ts +0 -95
- package/runtime/sdk/gl/physicsEvents.ts +0 -20
- package/runtime/sdk/gl/scenarios.ts +0 -291
- package/runtime/sdk/gl/state.ts +0 -6
- package/runtime/sdk/gl/touch.ts +0 -68
- package/runtime/sdk/inject.ts +0 -186
- package/runtime/sdk/math/Mathf.ts +0 -118
- package/runtime/sdk/math/mat4.ts +0 -278
- package/runtime/sdk/math/quat.ts +0 -232
- package/runtime/sdk/math/vec.ts +0 -255
- package/runtime/sdk/plugins/camera.ts +0 -81
- package/runtime/sdk/plugins/geolocation.ts +0 -123
- package/runtime/sdk/plugins/oauth.ts +0 -61
- package/runtime/sdk/plugins/permission.ts +0 -7
- package/runtime/sdk/plugins/push.ts +0 -132
- package/runtime/sdk/plugins/qr.ts +0 -73
- package/runtime/sdk/plugins/service.ts +0 -47
- package/runtime/sdk/runtime/app.ts +0 -101
- package/runtime/sdk/runtime/appEvents.ts +0 -54
- package/runtime/sdk/runtime/channel.ts +0 -61
- package/runtime/sdk/runtime/clipboard.ts +0 -20
- package/runtime/sdk/runtime/datetime.ts +0 -329
- package/runtime/sdk/runtime/device.ts +0 -293
- package/runtime/sdk/runtime/fetch.ts +0 -77
- package/runtime/sdk/runtime/files.ts +0 -23
- package/runtime/sdk/runtime/input.ts +0 -175
- package/runtime/sdk/runtime/media.ts +0 -111
- package/runtime/sdk/runtime/misc.ts +0 -16
- package/runtime/sdk/runtime/net.ts +0 -36
- package/runtime/sdk/runtime/rpc.ts +0 -218
- package/runtime/sdk/runtime/service.ts +0 -83
- package/runtime/sdk/runtime/share.ts +0 -9
- package/runtime/sdk/runtime/storage.ts +0 -13
- package/runtime/sdk/runtime/touch.ts +0 -76
- package/runtime/sdk/scene/defineScene.ts +0 -1227
- package/runtime/sdk/scene/editorPlugins.ts +0 -92
- package/runtime/sdk/scene/gizmos.ts +0 -148
- package/runtime/sdk/scene/grammar.ts +0 -120
- package/runtime/sdk/scene/material.ts +0 -188
- package/runtime/sdk/server/auth/appConfig.ts +0 -12
- package/runtime/sdk/server/auth/global.ts +0 -80
- package/runtime/sdk/server/auth/host.ts +0 -318
- package/runtime/sdk/server/auth/models.ts +0 -83
- package/runtime/sdk/server/auth/types.ts +0 -50
- package/runtime/sdk/server/channel.ts +0 -56
- package/runtime/sdk/server/context.ts +0 -36
- package/runtime/sdk/server/db/defineDb.ts +0 -237
- package/runtime/sdk/server/db/fields.ts +0 -132
- package/runtime/sdk/server/db/httpTransport.ts +0 -93
- package/runtime/sdk/server/db/index.ts +0 -7
- package/runtime/sdk/server/db/marci/query.ts +0 -412
- package/runtime/sdk/server/db/types.ts +0 -202
- package/runtime/sdk/server/errors.ts +0 -12
- package/runtime/sdk/server/host.ts +0 -74
- package/runtime/sdk/server/inject.ts +0 -13
- package/runtime/sdk/server/runtime.ts +0 -133
- package/runtime/sdk/server/validate.ts +0 -87
- package/runtime/sdk/ui/NativeView.ts +0 -142
- package/runtime/sdk/ui/UI.ts +0 -39
- package/runtime/sdk/ui/UIBottomSheet.ts +0 -139
- package/runtime/sdk/ui/UIButton.ts +0 -101
- package/runtime/sdk/ui/UIContainer.ts +0 -60
- package/runtime/sdk/ui/UIImage.ts +0 -83
- package/runtime/sdk/ui/UIInput.ts +0 -185
- package/runtime/sdk/ui/UIModal.ts +0 -139
- package/runtime/sdk/ui/UINode.ts +0 -826
- package/runtime/sdk/ui/UIPager.ts +0 -362
- package/runtime/sdk/ui/UIPopover.ts +0 -100
- package/runtime/sdk/ui/UIScreen.ts +0 -123
- package/runtime/sdk/ui/UIScrollable.ts +0 -87
- package/runtime/sdk/ui/UISpacer.ts +0 -14
- package/runtime/sdk/ui/UITabs.ts +0 -236
- package/runtime/sdk/ui/UIText.ts +0 -51
- package/runtime/sdk/ui/UIVideo.ts +0 -88
- package/runtime/sdk/ui/UIVirtualizedList.ts +0 -241
- package/runtime/sdk/ui/UIWidget.ts +0 -127
- package/runtime/sdk/ui/fonts.ts +0 -13
- package/runtime/sdk/ui/presentable.ts +0 -117
- package/runtime/sdk/ui/router.ts +0 -132
- package/runtime/sdk/ui/theme.ts +0 -84
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
// QRScanner — the host's camera QR scanner as a Presentable. A typed wrapper over the
|
|
2
|
-
// `NativeView("qrScanner")` capability (docs/navigation-presentable-plan.md): open it fullscreen
|
|
3
|
-
// (`await scanner.open()`), push it (`Router.push(scanner)`), or embed it among a screen's
|
|
4
|
-
// children as a live preview node — everything a NativeView can do, plus a typed `onScan`.
|
|
5
|
-
//
|
|
6
|
-
// Host-OPTIONAL, like every plugin: it exists where the host registers a "qrScanner" view
|
|
7
|
-
// (Android; web can via `_creatorUI._registerView`) — gate on `QRScanner.isSupported`. Opening
|
|
8
|
-
// prepares first (camera permission) while the current destination stays visible — the same
|
|
9
|
-
// prepare-then-present contract as ARScene.
|
|
10
|
-
//
|
|
11
|
-
// The pre-Presentable `_creatorUtils.openScanner/closeScanner` bridges are gone from the ABI
|
|
12
|
-
// (2026-07-15): hosts keep their implementations only to serve previously compiled bundles.
|
|
13
|
-
|
|
14
|
-
import { _navEpoch, type PresentOptions } from "../ui/presentable"
|
|
15
|
-
import { NativeView, NativeViewElement } from "../ui/NativeView"
|
|
16
|
-
import { _requestCameraPermission } from "./permission"
|
|
17
|
-
|
|
18
|
-
export interface QRScanner extends NativeView {
|
|
19
|
-
/** Fires per decoded camera frame: the decoded string, or `null` for a frame with no readable
|
|
20
|
-
* code (expect those repeatedly while the user aims). The same code can be reported more than
|
|
21
|
-
* once — `close()` or debounce once you have what you need. */
|
|
22
|
-
onScan(callback: (data: string | null) => void): this
|
|
23
|
-
/** Request camera permission, then present the scanner. The current destination (and its
|
|
24
|
-
* loading state) stays visible until the scanner is ready; rejects if the camera is denied,
|
|
25
|
-
* the host can't scan, or another navigation superseded this one. */
|
|
26
|
-
open(options?: PresentOptions): Promise<void>
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
class QRScannerElement extends NativeViewElement {
|
|
30
|
-
constructor() {
|
|
31
|
-
super("qrScanner", {})
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
onScan(callback: (data: string | null) => void): this {
|
|
35
|
-
return this.on("scan", (payload?: { data?: string | null }) => callback(payload?.data ?? null))
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** @internal prepare-then-present: permission before the swap (see Presentable._prepare). */
|
|
39
|
-
async _prepare(): Promise<void> {
|
|
40
|
-
const epoch = _navEpoch()
|
|
41
|
-
await _requestCameraPermission()
|
|
42
|
-
if (_navEpoch() !== epoch) {
|
|
43
|
-
throw new Error("QRScanner.open() superseded: another destination was opened while preparing")
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
override async open(options?: PresentOptions): Promise<void> {
|
|
48
|
-
// Fail before prompting for the camera — a permission dialog for a scanner that can't exist
|
|
49
|
-
// would be worse than the error.
|
|
50
|
-
if (!NativeView.isSupported("qrScanner")) {
|
|
51
|
-
throw new Error("QRScanner isn't available on this host — it needs a registered \"qrScanner\" view.")
|
|
52
|
-
}
|
|
53
|
-
await this._prepare()
|
|
54
|
-
super.open(options)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Create a QR scanner view. `QRScanner.isSupported` reports whether this host can scan at all —
|
|
60
|
-
* check it before offering the feature.
|
|
61
|
-
*/
|
|
62
|
-
// PURE IIFE so an app that never scans tree-shakes the whole plugin away (see NativeView).
|
|
63
|
-
export const QRScanner: {
|
|
64
|
-
(): QRScanner
|
|
65
|
-
/** Whether this host registered a "qrScanner" view. */
|
|
66
|
-
readonly isSupported: boolean
|
|
67
|
-
} = /*#__PURE__*/ (() => {
|
|
68
|
-
const factory = (): QRScanner => new QRScannerElement() as unknown as QRScanner
|
|
69
|
-
Object.defineProperty(factory, "isSupported", {
|
|
70
|
-
get: (): boolean => NativeView.isSupported("qrScanner"),
|
|
71
|
-
})
|
|
72
|
-
return factory as any
|
|
73
|
-
})()
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// Raw access to host-registered headless services — the escape hatch for services that
|
|
2
|
-
// have no typed wrapper (yet). First-party services ship wrapped (Geolocation); app-local
|
|
3
|
-
// native code (an `engine.registerService` in the app shell) and third-party plugins are
|
|
4
|
-
// reachable through this global immediately, wrapper or not. Thin sugar over the internal
|
|
5
|
-
// ServiceClient (src/runtime/service.ts) — same JSON call/event channel, same lazy session.
|
|
6
|
-
|
|
7
|
-
import { ServiceClient } from "../runtime/service"
|
|
8
|
-
|
|
9
|
-
export interface Service {
|
|
10
|
-
/** Invoke a method on the service (`battery.call("level")`). Arguments and the result are
|
|
11
|
-
* JSON-serialized; rejects when the host has no such service or the method reports an
|
|
12
|
-
* error. The host session opens lazily on the first call. */
|
|
13
|
-
call(method: string, ...args: any[]): Promise<any>
|
|
14
|
-
/** Subscribe to an event the service emits while a session is open
|
|
15
|
-
* (`battery.on("change", data => …)`). Payloads are JSON-decoded. */
|
|
16
|
-
on(event: string, callback: (data?: any) => void): this
|
|
17
|
-
/** Remove a previously added listener. */
|
|
18
|
-
off(event: string, callback: (data?: any) => void): this
|
|
19
|
-
/** Close the host session (stops whatever the service was doing). Listeners stay
|
|
20
|
-
* registered — a later `call()` opens a fresh session that delivers to them again. */
|
|
21
|
-
close(): void
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* A host-registered headless service — the UI-less sibling of `NativeView`. Use it for
|
|
26
|
-
* services without a typed wrapper: native code registered in your app shell
|
|
27
|
-
* (`engine.registerService("app.battery") { … }`) or a third-party plugin's channel.
|
|
28
|
-
* **Host-optional** — gate on `Service.isSupported` (the web editor registers none of them).
|
|
29
|
-
*
|
|
30
|
-
* ```ts
|
|
31
|
-
* if (Service.isSupported("app.battery")) {
|
|
32
|
-
* const battery = Service("app.battery")
|
|
33
|
-
* battery.on("change", data => { level.text = data.level + "%" })
|
|
34
|
-
* const { level } = await battery.call("level")
|
|
35
|
-
* }
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
// PURE IIFE so an app that never touches raw services tree-shakes this away.
|
|
39
|
-
export const Service: {
|
|
40
|
-
(name: string, params?: any): Service
|
|
41
|
-
/** Whether this host registered a service under `name`. */
|
|
42
|
-
isSupported(name: string): boolean
|
|
43
|
-
} = /*#__PURE__*/ (() => {
|
|
44
|
-
const factory = (name: string, params: any = {}): Service => new ServiceClient(name, params) as unknown as Service
|
|
45
|
-
factory.isSupported = (name: string): boolean => ServiceClient.isSupported(name)
|
|
46
|
-
return factory as any
|
|
47
|
-
})()
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
// The app's own lifecycle + how it was opened (docs/app-lifecycle-plan.md). Events are semantic —
|
|
2
|
-
// "pause"/"resume", never Activity/Scene vocabulary — and the current values are synchronous pulls
|
|
3
|
-
// so render-loop code can read them without subscribing.
|
|
4
|
-
|
|
5
|
-
import { appEventsOn, appEventsOff, keyboardEventsOn, keyboardEventsOff } from "./appEvents"
|
|
6
|
-
|
|
7
|
-
export type AppState = "active" | "background"
|
|
8
|
-
|
|
9
|
-
/** `"landscape"` — either landscape direction (sensor landscape), `"portrait"` — upright only,
|
|
10
|
-
* `"auto"` — released: the device's own rotation rules apply. */
|
|
11
|
-
export type OrientationLock = "auto" | "portrait" | "landscape"
|
|
12
|
-
|
|
13
|
-
type AppEventMap = {
|
|
14
|
-
/** The app left the foreground (home button, tab hidden, another app on top). Delivered before
|
|
15
|
-
* the host halts the frame loop — the last chance to persist state / pause work. */
|
|
16
|
-
pause: () => void
|
|
17
|
-
/** The app returned to the foreground; frames are running again. */
|
|
18
|
-
resume: () => void
|
|
19
|
-
/** A link arrived while the app was running (warm deep link). `app.launchUrl` is already
|
|
20
|
-
* updated to the same value when this fires. */
|
|
21
|
-
url: (url: string) => void
|
|
22
|
-
/** The on-screen keyboard changed. `height` mirrors `app.keyboardHeight` (the raw overlap, see
|
|
23
|
-
* there); `duration` is the platform's keyboard animation duration in ms (0 where none) — pass
|
|
24
|
-
* it to `animateTo` to move a composer in sync with the keyboard. */
|
|
25
|
-
keyboard: (height: number, duration: number) => void
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const app = {
|
|
29
|
-
/** Current lifecycle state. `"background"` while the app is not the foreground app / the tab is
|
|
30
|
-
* hidden. `"active"` on hosts that don't track it. */
|
|
31
|
-
get state(): AppState {
|
|
32
|
-
return _creatorUtils.appState?.() === "background" ? "background" : "active"
|
|
33
|
-
},
|
|
34
|
-
/** The URL the app was (most recently) opened with — the deep link — or `null` for a plain
|
|
35
|
-
* launch. Warm links update it and fire the `"url"` event. */
|
|
36
|
-
get launchUrl(): string | null {
|
|
37
|
-
return _creatorUtils.getLaunchUrl?.() ?? null
|
|
38
|
-
},
|
|
39
|
-
/** On-screen keyboard height in logical px currently overlapping the app viewport, `0` when
|
|
40
|
-
* hidden. This is the RAW overlap, independent of the focused input's `keyboardShrink` policy —
|
|
41
|
-
* with the default shrink the layout already avoids the keyboard; the main consumer is overlay
|
|
42
|
-
* mode (`keyboardShrink: false`), e.g. a chat composer's `pb`. `0` on hosts without an
|
|
43
|
-
* on-screen keyboard. */
|
|
44
|
-
get keyboardHeight(): number {
|
|
45
|
-
return _creatorUtils.keyboardHeight?.() ?? 0
|
|
46
|
-
},
|
|
47
|
-
/** Lock the screen orientation — `"landscape"` for a horizontal game (the device rotates to
|
|
48
|
-
* landscape right away and stays there whichever way it is held), `"portrait"` for upright
|
|
49
|
-
* only, `"auto"` to release. Call it once at startup; the lock is per app run (it resets
|
|
50
|
-
* when the app quits or restarts), so there is nothing to undo. The rotation arrives as an
|
|
51
|
-
* ordinary resize — layouts reflow, a scene's viewport follows. Silent no-op on hosts
|
|
52
|
-
* without a rotatable screen (desktop, headless, web). */
|
|
53
|
-
setOrientation(mode: OrientationLock): void {
|
|
54
|
-
_creatorUtils.setOrientation?.(mode)
|
|
55
|
-
},
|
|
56
|
-
/** Re-run this app's bundle in a fresh world — the platform's `location.reload()`. Pass `url`
|
|
57
|
-
* to reboot with different launch arguments (the new run reads them via `app.launchUrl`),
|
|
58
|
-
* `null` to reboot with a cleared one, or omit it to replay the current one. No-op on hosts
|
|
59
|
-
* without world control (headless). */
|
|
60
|
-
restart(url?: string | null): void {
|
|
61
|
-
_creatorUtils.restart?.(url)
|
|
62
|
-
},
|
|
63
|
-
/** Leave this app. Inside the LeCodes viewer that returns to the launcher (the LeCodes home
|
|
64
|
-
* screen); a standalone-built app leaves to the platform instead — Android backgrounds it,
|
|
65
|
-
* iOS ignores the call (the platform forbids programmatic exit). */
|
|
66
|
-
quit(): void {
|
|
67
|
-
_creatorUtils.quit?.()
|
|
68
|
-
},
|
|
69
|
-
/** Global back-press fallback (Android back button/gesture — iOS has no system back). Fires
|
|
70
|
-
* only when nothing else consumed the press: no open widget/modal claimed it, the current
|
|
71
|
-
* screen has no `onBackPressed`, every pager is at its tab root and the router is at its
|
|
72
|
-
* stack root. The place for app-wide policy — e.g. double-press-to-quit:
|
|
73
|
-
*
|
|
74
|
-
* ```ts
|
|
75
|
-
* let armedAt = 0
|
|
76
|
-
* app.onBackPressed(() => {
|
|
77
|
-
* if (Date.now() - armedAt < 2000) { app.quit(); return }
|
|
78
|
-
* armedAt = Date.now()
|
|
79
|
-
* toast("Press back again to exit")
|
|
80
|
-
* })
|
|
81
|
-
* ```
|
|
82
|
-
*
|
|
83
|
-
* Replaces the previous handler; pass `null` to remove. */
|
|
84
|
-
onBackPressed(callback: (() => void) | null): void {
|
|
85
|
-
_creatorUI._backButtonCallback = callback ?? undefined
|
|
86
|
-
},
|
|
87
|
-
addEventListener<E extends keyof AppEventMap>(event: E, callback: AppEventMap[E]): void {
|
|
88
|
-
if (event === "keyboard") {
|
|
89
|
-
keyboardEventsOn(callback as (height: number, duration: number) => void)
|
|
90
|
-
return
|
|
91
|
-
}
|
|
92
|
-
appEventsOn(event, callback as (data?: string) => void)
|
|
93
|
-
},
|
|
94
|
-
removeEventListener<E extends keyof AppEventMap>(event: E, callback: AppEventMap[E]): void {
|
|
95
|
-
if (event === "keyboard") {
|
|
96
|
-
keyboardEventsOff(callback as (height: number, duration: number) => void)
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
appEventsOff(event, callback as (data?: string) => void)
|
|
100
|
-
},
|
|
101
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
// The shared app-event dispatcher. The host exposes ONE registerAppEvent slot per JS world
|
|
2
|
-
// (docs/app-lifecycle-plan.md), so every SDK consumer (the `app` global's pause/resume/url, the
|
|
3
|
-
// `device` global's online/offline) subscribes here and this module registers with the host once,
|
|
4
|
-
// lazily on the first subscription — no top-level side effect, tree-shaking drops it when unused.
|
|
5
|
-
|
|
6
|
-
type AppEventCallback = (data?: string) => void
|
|
7
|
-
|
|
8
|
-
const listeners: Record<string, AppEventCallback[]> = {}
|
|
9
|
-
let registered = false
|
|
10
|
-
|
|
11
|
-
const dispatch = (event: string, data?: string): void => {
|
|
12
|
-
const arr = listeners[event]
|
|
13
|
-
if (arr) for (const cb of arr.slice()) cb(data)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const appEventsOn = (event: string, cb: AppEventCallback): void => {
|
|
17
|
-
;(listeners[event] ??= []).push(cb)
|
|
18
|
-
if (!registered) {
|
|
19
|
-
registered = true
|
|
20
|
-
_creatorUtils.registerAppEvent?.(dispatch)
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const appEventsOff = (event: string, cb: AppEventCallback): void => {
|
|
25
|
-
const arr = listeners[event]
|
|
26
|
-
if (!arr) return
|
|
27
|
-
const i = arr.indexOf(cb)
|
|
28
|
-
if (i >= 0) arr.splice(i, 1)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// The keyboard channel is a separate host slot (registerKeyboardEvent) — the registerAppEvent
|
|
32
|
-
// string channel can't carry the (height, duration) number pair. Same lazy single-slot pattern.
|
|
33
|
-
|
|
34
|
-
type KeyboardCallback = (height: number, duration: number) => void
|
|
35
|
-
|
|
36
|
-
const keyboardListeners: KeyboardCallback[] = []
|
|
37
|
-
let keyboardRegistered = false
|
|
38
|
-
|
|
39
|
-
const dispatchKeyboard = (height: number, duration: number): void => {
|
|
40
|
-
for (const cb of keyboardListeners.slice()) cb(height, duration)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export const keyboardEventsOn = (cb: KeyboardCallback): void => {
|
|
44
|
-
keyboardListeners.push(cb)
|
|
45
|
-
if (!keyboardRegistered) {
|
|
46
|
-
keyboardRegistered = true
|
|
47
|
-
_creatorUtils.registerKeyboardEvent?.(dispatchKeyboard)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export const keyboardEventsOff = (cb: KeyboardCallback): void => {
|
|
52
|
-
const i = keyboardListeners.indexOf(cb)
|
|
53
|
-
if (i >= 0) keyboardListeners.splice(i, 1)
|
|
54
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// The JSON wire protocol shared by the two host plugin channels — NativeView
|
|
2
|
-
// (`_creatorUI.viewCall`, see ui/NativeView.ts) and headless services
|
|
3
|
-
// (`_creatorUtils.serviceCall`, see runtime/service.ts). One protocol, two transports:
|
|
4
|
-
// `args`, results, and event payloads travel as JSON strings, and an absent/empty string
|
|
5
|
-
// decodes to `undefined`. Typed plugins (QRScanner, CameraView, Geolocation) layer methods
|
|
6
|
-
// over this — see src/plugins/.
|
|
7
|
-
|
|
8
|
-
/** @internal event-name → listeners. NativeView exposes it as `nvl` (host contract). */
|
|
9
|
-
export type ChannelListeners = Record<string, ((data?: any) => void)[]>
|
|
10
|
-
|
|
11
|
-
/** @internal */
|
|
12
|
-
export const _channelOn = (listeners: ChannelListeners, event: string, callback: (data?: any) => void): void => {
|
|
13
|
-
(listeners[event] ??= []).push(callback)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** @internal */
|
|
17
|
-
export const _channelOff = (listeners: ChannelListeners, event: string, callback: (data?: any) => void): void => {
|
|
18
|
-
const list = listeners[event]
|
|
19
|
-
if (!list) return
|
|
20
|
-
const i = list.indexOf(callback)
|
|
21
|
-
if (i >= 0) list.splice(i, 1)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** @internal deliver a host event: decode the JSON payload, fan out (copy-before-iterate). */
|
|
25
|
-
export const _channelEmit = (listeners: ChannelListeners, event: string, dataJson?: string): void => {
|
|
26
|
-
const list = listeners[event]
|
|
27
|
-
if (!list || list.length === 0) return
|
|
28
|
-
const data = dataJson === undefined || dataJson === "" ? undefined : JSON.parse(dataJson)
|
|
29
|
-
for (const cb of [...list]) cb(data)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
type ChannelCallBridge = (
|
|
33
|
-
id: number, method: string, args: string,
|
|
34
|
-
onComplete: (result?: string) => void, onError: (err: string) => void,
|
|
35
|
-
) => void
|
|
36
|
-
|
|
37
|
-
/** @internal one JSON call over a channel bridge.
|
|
38
|
-
*
|
|
39
|
-
* Takes the HANDLER OBJECT plus the member name — never a plucked-off function reference. On
|
|
40
|
-
* Apple hosts the bridge members are JSExport-ed Objective-C/Swift methods, and JavaScriptCore
|
|
41
|
-
* binds those to their native receiver: invoking a detached `handler.viewCall(…)` with no `this`
|
|
42
|
-
* fails at runtime with "self type check failed for Objective-C instance method". QuickJS and web
|
|
43
|
-
* hosts are plain functions that ignore `this`, so a detached call works there and the breakage
|
|
44
|
-
* looks iOS/macOS-only. Calling through `owner` keeps the receiver attached on every host.
|
|
45
|
-
*
|
|
46
|
-
* `bridgeName` may be absent from the host object (optional ABI member) — that's the
|
|
47
|
-
* unsupported-host path, not an error. */
|
|
48
|
-
export const _channelCall = (
|
|
49
|
-
owner: Record<string, any> | undefined, bridgeName: string, unsupportedError: string,
|
|
50
|
-
id: number, method: string, args: any[],
|
|
51
|
-
): Promise<any> =>
|
|
52
|
-
new Promise((res, rej) => {
|
|
53
|
-
const bridge = owner?.[bridgeName] as ChannelCallBridge | undefined
|
|
54
|
-
if (typeof bridge !== "function") {
|
|
55
|
-
rej(new Error(unsupportedError))
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
bridge.call(owner, id, method, JSON.stringify(args),
|
|
59
|
-
(result?: string) => res(result === undefined || result === "" ? undefined : JSON.parse(result)),
|
|
60
|
-
(err: string) => rej(new Error(err)))
|
|
61
|
-
})
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// System clipboard (docs/app-lifecycle-plan.md). Write is fire-and-forget; read is async because
|
|
2
|
-
// web gates it behind a permission prompt (native hosts complete synchronously).
|
|
3
|
-
|
|
4
|
-
export const clipboard = {
|
|
5
|
-
/** Put `text` on the system clipboard. Silent no-op on hosts without clipboard access. */
|
|
6
|
-
write(text: string): void {
|
|
7
|
-
_creatorUtils.clipboardWrite?.(text)
|
|
8
|
-
},
|
|
9
|
-
/** Read text from the system clipboard. Rejects when the platform has no clipboard access, the
|
|
10
|
-
* user denied it, or there is nothing readable. */
|
|
11
|
-
read(): Promise<string> {
|
|
12
|
-
return new Promise((resolve, reject) => {
|
|
13
|
-
if (typeof _creatorUtils.clipboardRead !== "function") {
|
|
14
|
-
reject(new Error("Clipboard is not supported on this platform"))
|
|
15
|
-
return
|
|
16
|
-
}
|
|
17
|
-
_creatorUtils.clipboardRead(resolve, (err: string) => reject(new Error(err)))
|
|
18
|
-
})
|
|
19
|
-
},
|
|
20
|
-
}
|