lecodes-sdk 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/editor.d.ts +12 -0
- package/dist/global.d.ts +4 -8
- package/dist/host.d.ts +2 -3
- package/dist/types/animate/tween/Animation.d.ts +0 -3
- package/dist/types/animate/tween/animateValue.d.ts +4 -2
- package/dist/types/animate/tween/easing.d.ts +8 -0
- package/dist/types/animate/tween/spec.d.ts +15 -7
- package/dist/types/audio/audio.d.ts +2 -1
- package/dist/types/canvas/Canvas.d.ts +40 -108
- package/dist/types/canvas/gen/cssColor.d.ts +17 -0
- package/dist/types/canvas/gen/recorder.d.ts +118 -0
- package/dist/types/canvas/gen/spec.d.ts +144 -0
- package/dist/types/core/color.d.ts +3 -1
- package/dist/types/core/pins.d.ts +18 -0
- package/dist/types/g2/Node2D.d.ts +5 -8
- package/dist/types/g2/Scene2D.d.ts +6 -2
- package/dist/types/gl/Foliage.d.ts +30 -7
- package/dist/types/gl/Light.d.ts +11 -0
- package/dist/types/gl/Lightmap.d.ts +13 -2
- package/dist/types/gl/Material.d.ts +17 -3
- package/dist/types/gl/Model.d.ts +6 -2
- package/dist/types/gl/Node.d.ts +3 -6
- package/dist/types/gl/Particles.d.ts +15 -0
- package/dist/types/gl/Scene.d.ts +41 -13
- package/dist/types/gl/Texture.d.ts +1 -1
- package/dist/types/gl/animation/Locomotion.d.ts +59 -3
- package/dist/types/gl/terrain/Terrain.d.ts +8 -0
- package/dist/types/inject.d.ts +11 -11
- package/dist/types/inject.editor.d.ts +1 -0
- package/dist/types/net/core.d.ts +7 -0
- package/dist/types/plugin.d.ts +76 -0
- package/dist/types/plugins/gen/camera/sdk/camera.d.ts +24 -0
- package/dist/types/plugins/gen/camera/sdk/camera.gen.d.ts +25 -0
- package/dist/types/plugins/{geolocation.d.ts → gen/geolocation/sdk/geolocation.d.ts} +2 -20
- package/dist/types/plugins/gen/geolocation/sdk/geolocation.gen.d.ts +31 -0
- package/dist/types/plugins/{map.d.ts → gen/map/sdk/map.d.ts} +9 -50
- package/dist/types/plugins/gen/map/sdk/map.gen.d.ts +53 -0
- package/dist/types/plugins/gen/push/sdk/push.d.ts +23 -0
- package/dist/types/plugins/gen/push/sdk/push.gen.d.ts +35 -0
- package/dist/types/plugins/{qr.d.ts → gen/qr-scanner/sdk/qr-scanner.d.ts} +2 -3
- package/dist/types/plugins/gen/qr-scanner/sdk/qr-scanner.gen.d.ts +15 -0
- package/dist/types/runtime/app.d.ts +9 -2
- package/dist/types/runtime/fetch.d.ts +2 -0
- package/dist/types/runtime/input.d.ts +8 -1
- package/dist/types/runtime/media.d.ts +6 -10
- package/dist/types/runtime/misc.d.ts +4 -1
- package/dist/types/runtime/net.d.ts +3 -2
- package/dist/types/runtime/touch.d.ts +32 -0
- package/dist/types/scene/defineScene.d.ts +43 -2
- package/dist/types/scene/editor.d.ts +52 -0
- package/dist/types/scene/gizmos.d.ts +7 -4
- package/dist/types/ui/NativeView.d.ts +6 -4
- package/dist/types/ui/UI.d.ts +1 -1
- package/dist/types/ui/UIBottomSheet.d.ts +6 -12
- package/dist/types/ui/UIButton.d.ts +12 -14
- package/dist/types/ui/UIContainer.d.ts +0 -6
- package/dist/types/ui/UIImage.d.ts +1 -4
- package/dist/types/ui/UIInput.d.ts +8 -24
- package/dist/types/ui/UIModal.d.ts +0 -2
- package/dist/types/ui/UINode.d.ts +70 -56
- package/dist/types/ui/UIPager.d.ts +28 -27
- package/dist/types/ui/UIPopover.d.ts +0 -2
- package/dist/types/ui/UIScreen.d.ts +12 -17
- package/dist/types/ui/UIScrollable.d.ts +1 -4
- package/dist/types/ui/UIText.d.ts +0 -2
- package/dist/types/ui/UIVideo.d.ts +3 -5
- package/dist/types/ui/UIVirtualizedList.d.ts +14 -16
- package/dist/types/ui/UIWidget.d.ts +10 -9
- package/dist/types/ui/colorKeys.gen.d.ts +9 -0
- package/dist/types/ui/presentable.d.ts +46 -32
- package/dist/types/ui/router.d.ts +18 -7
- package/dist/types/ui/styleColor.d.ts +1 -0
- package/dist/types/ui/transitions.d.ts +18 -0
- package/dist/types/ui/tree.d.ts +75 -0
- package/dist/types/version.d.ts +10 -0
- package/dist/types.json +1 -1
- package/package.json +12 -3
- package/prompts/2d.md +2 -6
- package/prompts/3d.md +1 -5
- package/prompts/README.md +142 -142
- package/prompts/canvas.md +9 -8
- package/prompts/compose.ts +1 -1
- package/prompts/core.md +3 -3
- package/prompts/design.md +1 -1
- package/prompts/dist/2d-game.md +77 -54
- package/prompts/dist/3d-app.md +75 -52
- package/prompts/dist/ar-app.md +74 -51
- package/prompts/dist/design.md +30 -8
- package/prompts/dist/ui-app.md +73 -46
- package/prompts/ui-design.md +2 -3
- package/prompts/ui.md +45 -37
- package/src/animate/tween/Animation.ts +262 -378
- package/src/animate/tween/animateValue.ts +103 -100
- package/src/animate/tween/easing.ts +10 -3
- package/src/animate/tween/spec.ts +505 -479
- package/src/audio/Sound.ts +3 -3
- package/src/audio/audio.ts +162 -161
- package/src/bridges/2d.d.ts +317 -0
- package/src/bridges/app.d.ts +91 -0
- package/src/bridges/audio.d.ts +97 -0
- package/src/bridges/canvas.d.ts +79 -0
- package/src/bridges/device.d.ts +72 -0
- package/src/bridges/fetch.d.ts +80 -0
- package/src/bridges/files.d.ts +70 -0
- package/src/bridges/gl.d.ts +1133 -0
- package/src/bridges/input.d.ts +72 -0
- package/src/bridges/media.d.ts +55 -0
- package/src/bridges/nav.d.ts +71 -0
- package/src/bridges/net.d.ts +52 -0
- package/src/bridges/service.d.ts +52 -0
- package/src/bridges/socket.d.ts +31 -0
- package/src/bridges/storage.d.ts +33 -0
- package/src/bridges/tree.d.ts +301 -0
- package/src/bridges/types.d.ts +49 -0
- package/src/canvas/Canvas.ts +114 -159
- package/src/canvas/gen/cssColor.ts +224 -0
- package/src/canvas/gen/recorder.ts +212 -0
- package/src/canvas/gen/spec.ts +201 -0
- package/src/chisel.ts +193 -0
- package/src/compile/assetMacro.ts +1 -1
- package/src/compile/bundler.ts +11 -2
- package/src/compile/compileProject.ts +43 -4
- package/src/compile/fontMacro.ts +3 -4
- package/src/compile/header.ts +26 -5
- package/src/compile/index.ts +3 -1
- package/src/compile/liteMaterial.ts +1 -1
- package/src/compile/sceneEditor.ts +11 -26
- package/src/core/color.ts +73 -30
- package/src/core/pins.ts +51 -0
- package/src/core/signals.ts +8 -1
- package/src/g2/CharacterController2D.ts +3 -3
- package/src/g2/Node2D.ts +57 -39
- package/src/g2/Physics2D.ts +2 -2
- package/src/g2/Scene2D.ts +35 -23
- package/src/g2/Texture2D.ts +1 -1
- package/src/g2/loop.ts +4 -4
- package/src/gl/Foliage.ts +72 -17
- package/src/gl/Geometry.ts +1 -2
- package/src/gl/Light.ts +13 -0
- package/src/gl/Lightmap.ts +45 -29
- package/src/gl/Material.ts +95 -51
- package/src/gl/Model.ts +172 -167
- package/src/gl/Node.ts +91 -24
- package/src/gl/Particles.ts +20 -1
- package/src/gl/Scene.ts +100 -44
- package/src/gl/Texture.ts +8 -7
- package/src/gl/animation/AnimationClip.ts +1 -1
- package/src/gl/animation/Locomotion.ts +77 -8
- package/src/gl/nav/NavMesh.ts +3 -4
- package/src/gl/physics/Physics.ts +2 -2
- package/src/gl/physics/physicsEvents.ts +3 -3
- package/src/gl/terrain/Terrain.ts +33 -5
- package/src/gl/touch.ts +14 -15
- package/src/host.d.ts +2 -3
- package/src/inject.editor.ts +7 -0
- package/src/inject.ts +233 -236
- package/src/net/core.ts +6 -5
- package/src/net/index.ts +1 -1
- package/src/net/replication.ts +1 -1
- package/src/plugin.ts +191 -0
- package/src/plugins/gen/camera/contract.d.ts +27 -0
- package/src/plugins/gen/camera/sdk/camera.gen.ts +46 -0
- package/src/plugins/gen/camera/sdk/camera.ts +57 -0
- package/src/plugins/gen/geolocation/contract.d.ts +50 -0
- package/src/plugins/gen/geolocation/sdk/geolocation.gen.ts +54 -0
- package/src/plugins/{geolocation.ts → gen/geolocation/sdk/geolocation.ts} +22 -43
- package/src/plugins/gen/map/contract.d.ts +144 -0
- package/src/plugins/gen/map/sdk/map.gen.ts +88 -0
- package/src/plugins/{map.ts → gen/map/sdk/map.ts} +68 -102
- package/src/plugins/gen/push/contract.d.ts +61 -0
- package/src/plugins/gen/push/sdk/push.gen.ts +60 -0
- package/src/plugins/gen/push/sdk/push.ts +105 -0
- package/src/plugins/gen/qr-scanner/contract.d.ts +16 -0
- package/src/plugins/gen/qr-scanner/sdk/qr-scanner.gen.ts +29 -0
- package/src/plugins/gen/qr-scanner/sdk/qr-scanner.ts +52 -0
- package/src/plugins/permission.ts +5 -4
- package/src/runtime/app.ts +20 -9
- package/src/runtime/appEvents.ts +5 -4
- package/src/runtime/channel.ts +18 -15
- package/src/runtime/clipboard.ts +4 -3
- package/src/runtime/datetime.ts +2 -1
- package/src/runtime/device.ts +17 -15
- package/src/runtime/fetch.ts +30 -20
- package/src/runtime/files.ts +16 -15
- package/src/runtime/input.ts +21 -8
- package/src/runtime/media.ts +50 -46
- package/src/runtime/misc.ts +7 -3
- package/src/runtime/net.ts +8 -7
- package/src/runtime/rpc.ts +1 -3
- package/src/runtime/service.ts +19 -14
- package/src/runtime/share.ts +4 -3
- package/src/runtime/storage.ts +6 -4
- package/src/runtime/touch.ts +32 -0
- package/src/scene/defineScene.ts +61 -365
- package/src/scene/editor.ts +408 -0
- package/src/scene/editorPlugins.ts +3 -3
- package/src/scene/gizmos.ts +154 -148
- package/src/server/db/marci/query.ts +1 -1
- package/src/server/host.ts +1 -1
- package/src/server/runtime.ts +1 -1
- package/src/ui/NativeView.ts +72 -25
- package/src/ui/UI.ts +3 -3
- package/src/ui/UIBottomSheet.ts +16 -17
- package/src/ui/UIButton.ts +54 -16
- package/src/ui/UIContainer.ts +0 -6
- package/src/ui/UIImage.ts +34 -30
- package/src/ui/UIInput.ts +29 -37
- package/src/ui/UIModal.ts +1 -3
- package/src/ui/UINode.ts +347 -297
- package/src/ui/UIPager.ts +93 -78
- package/src/ui/UIPopover.ts +0 -2
- package/src/ui/UIScreen.ts +41 -36
- package/src/ui/UIScrollable.ts +19 -13
- package/src/ui/UISpacer.ts +1 -1
- package/src/ui/UITabs.ts +8 -6
- package/src/ui/UIText.ts +7 -17
- package/src/ui/UIVideo.ts +30 -27
- package/src/ui/UIVirtualizedList.ts +58 -59
- package/src/ui/UIWidget.ts +38 -18
- package/src/ui/colorKeys.gen.ts +37 -0
- package/src/ui/fonts.ts +2 -2
- package/src/ui/presentable.ts +59 -42
- package/src/ui/router.ts +52 -35
- package/src/ui/styleColor.ts +56 -0
- package/src/ui/theme.ts +7 -6
- package/src/ui/transitions.ts +249 -0
- package/src/ui/tree.ts +346 -0
- package/src/version.ts +24 -0
- package/tests/helpers/engineWorld.ts +11 -0
- package/tests/helpers/fakeTree.ts +353 -0
- package/tests/helpers/hostStubs.ts +31 -0
- package/tests/helpers/index.ts +14 -0
- package/tests/helpers/memoryMarci.ts +124 -0
- package/tests/helpers/phases.ts +23 -0
- package/tests/helpers/preload.ts +18 -0
- package/tests/helpers/stubApp.ts +2 -0
- package/tests/helpers/stubDevice.ts +2 -0
- package/tests/helpers/stubFetch.ts +2 -0
- package/tests/helpers/stubInput.ts +2 -0
- package/dist/inject.js +0 -4730
- package/dist/types/core/registry.d.ts +0 -7
- package/dist/types/plugins/camera.d.ts +0 -25
- package/dist/types/plugins/push.d.ts +0 -46
- package/src/bridges.d.ts +0 -1760
- package/src/compile/__tests__/assetIconMacro.test.ts +0 -219
- package/src/compile/__tests__/assetMacro.test.ts +0 -100
- package/src/compile/__tests__/assetName.test.ts +0 -55
- package/src/compile/__tests__/compile.test.ts +0 -310
- package/src/compile/__tests__/detectEntry.test.ts +0 -151
- package/src/compile/__tests__/fontMacro.test.ts +0 -199
- package/src/compile/__tests__/serverSplit.test.ts +0 -27
- package/src/core/__tests__/stateMachine.test.ts +0 -132
- package/src/core/registry.ts +0 -23
- package/src/plugins/camera.ts +0 -81
- package/src/plugins/push.ts +0 -132
- package/src/plugins/qr.ts +0 -73
package/src/net/replication.ts
CHANGED
|
@@ -407,7 +407,7 @@ const sendSnapshots = (): void => {
|
|
|
407
407
|
|
|
408
408
|
// ---- client: snapshots in, inputs out, the clock, interpolation, correction ----------------------------
|
|
409
409
|
|
|
410
|
-
const rttTicks = (): number => (bridge()?.clientInfo(0)
|
|
410
|
+
const rttTicks = (): number => (bridge()?.clientInfo(0)?.rtt ?? 0) / TICK_MS
|
|
411
411
|
|
|
412
412
|
const onClientBinary = (channel: number, data: ArrayBuffer): void => {
|
|
413
413
|
if (data.byteLength < 12) return
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// `lecodes-sdk/plugin` — the one entry a PLUGIN imports the SDK through (docs/plans/plugins-plan.md).
|
|
2
|
+
// Two readers:
|
|
3
|
+
// - a plugin's `contract.d.ts`: the channel markers and the precise value types the generator maps
|
|
4
|
+
// to Swift / Kotlin;
|
|
5
|
+
// - its `sdk/` wrapper, generated (`<id>.gen.ts`) and hand-written (`<id>.ts`): the two channel
|
|
6
|
+
// bases and the few SDK internals a wrapper needs.
|
|
7
|
+
//
|
|
8
|
+
// A contract describes the WIRE of one channel, never the app-facing API: three interfaces per
|
|
9
|
+
// channel — the methods (it extends a marker), the params, the events.
|
|
10
|
+
|
|
11
|
+
import { File as HostFile } from "./runtime/fetch"
|
|
12
|
+
import { ServiceClient } from "./runtime/service"
|
|
13
|
+
import { NativeView, NativeViewElement } from "./ui/NativeView"
|
|
14
|
+
import { _navEpoch } from "./ui/presentable"
|
|
15
|
+
import { _requestCameraPermission } from "./plugins/permission"
|
|
16
|
+
|
|
17
|
+
export type { PresentOptions } from "./ui/presentable"
|
|
18
|
+
export type { NativeView } from "./ui/NativeView"
|
|
19
|
+
export type { FetchResponse } from "./runtime/fetch"
|
|
20
|
+
|
|
21
|
+
// ---- the contract's vocabulary ---------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
/** Signed 32-bit integer on the wire. */
|
|
24
|
+
export type i32 = number
|
|
25
|
+
/** Double on the wire — also every integer that can leave 32 bits (a millisecond time stamp). */
|
|
26
|
+
export type f64 = number
|
|
27
|
+
|
|
28
|
+
/** Bytes that STAY in the host's buffer table: the native half hands over its bytes + a name, the
|
|
29
|
+
* app gets the SDK's `File` handle (a texture source, a `FormData` value, a share) and the bytes
|
|
30
|
+
* never enter the JS heap. For bytes the app must read itself, a contract says `Uint8Array`. */
|
|
31
|
+
export type File = HostFile
|
|
32
|
+
|
|
33
|
+
/** Any JSON value, opaque to the generator (GeoJSON, a developer's own payload): it crosses as is
|
|
34
|
+
* and the native half receives the platform's untyped value. */
|
|
35
|
+
export type Json = null | boolean | number | string | Json[] | { [key: string]: Json }
|
|
36
|
+
|
|
37
|
+
declare const channel: unique symbol
|
|
38
|
+
|
|
39
|
+
/** Marks a contract interface as a NativeView channel. `Name` is what the halves register under
|
|
40
|
+
* (`registerView(name)`); `Params` is what a factory receives; `Events` maps an event's name to
|
|
41
|
+
* its payload (`void` = no payload). */
|
|
42
|
+
export interface View<Name extends string, Params extends object = {}, Events extends object = {}> {
|
|
43
|
+
readonly [channel]?: { kind: "view", name: Name, params: Params, events: Events }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Marks a contract interface as a headless Service channel — see {@link View}. */
|
|
47
|
+
export interface Service<Name extends string, Params extends object = {}, Events extends object = {}> {
|
|
48
|
+
readonly [channel]?: { kind: "service", name: Name, params: Params, events: Events }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ---- the wrapper's bases ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
/** A listener of the event `K`: no argument for a `void` payload. */
|
|
54
|
+
export type Listener<Events, K extends keyof Events> = Events[K] extends void ? () => void : (payload: Events[K]) => void
|
|
55
|
+
|
|
56
|
+
/** A method the host's half is too old for (`@since`): refused HERE, by what it needs, before the
|
|
57
|
+
* half is asked. `version` = the half's contract version (0 = the host has none: the channel's own
|
|
58
|
+
* "not supported" speaks then). */
|
|
59
|
+
const tooOld = (iface: string, name: string, method: string, since: number, version: number): Error | null =>
|
|
60
|
+
since > 1 && version > 0 && version < since
|
|
61
|
+
? new Error(`${iface}.${method} needs the "${name}" plugin at contract version ${since} — this host's is ${version}`)
|
|
62
|
+
: null
|
|
63
|
+
|
|
64
|
+
/** An optional argument the caller left out is ABSENT on the wire, not a null in its place. */
|
|
65
|
+
const present = (args: any[]): any[] => {
|
|
66
|
+
let n = args.length
|
|
67
|
+
while (n > 0 && args[n - 1] === undefined) n--
|
|
68
|
+
return n === args.length ? args : args.slice(0, n)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** What an event's payload is read with when it is not on the wire what it is for the app (it
|
|
72
|
+
* holds a File): by the event's name. */
|
|
73
|
+
export type EventReaders = { [event: string]: (wire: any) => any }
|
|
74
|
+
|
|
75
|
+
/** The listeners of the events that have a reader: the app's callback → the one that reads first,
|
|
76
|
+
* so `off` finds what `on` registered. */
|
|
77
|
+
class Readers {
|
|
78
|
+
private readonly wrapped = new Map<string, Map<Function, (data?: any) => void>>()
|
|
79
|
+
private readonly readers: EventReaders | undefined
|
|
80
|
+
constructor(readers: EventReaders | undefined) { this.readers = readers }
|
|
81
|
+
|
|
82
|
+
on(event: string, callback: (data?: any) => void): (data?: any) => void {
|
|
83
|
+
const read = this.readers?.[event]
|
|
84
|
+
if (!read) return callback
|
|
85
|
+
let byCallback = this.wrapped.get(event)
|
|
86
|
+
if (!byCallback) this.wrapped.set(event, byCallback = new Map())
|
|
87
|
+
let listener = byCallback.get(callback)
|
|
88
|
+
if (!listener) byCallback.set(callback, listener = (wire?: any) => callback(read(wire)))
|
|
89
|
+
return listener
|
|
90
|
+
}
|
|
91
|
+
off(event: string, callback: (data?: any) => void): (data?: any) => void {
|
|
92
|
+
const byCallback = this.wrapped.get(event)
|
|
93
|
+
const listener = byCallback?.get(callback)
|
|
94
|
+
if (!listener) return callback
|
|
95
|
+
byCallback!.delete(callback)
|
|
96
|
+
return listener
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** The element of a view plugin: a `NativeView` whose events are the contract's. Generated wrappers
|
|
101
|
+
* extend it (`<Name>Base`); a hand-written one extends that, or this when its API is not the wire's. */
|
|
102
|
+
export class ViewChannel<Events extends object = {}> extends NativeViewElement {
|
|
103
|
+
/** @internal The contract interface's name, for messages. */
|
|
104
|
+
readonly _iface: string
|
|
105
|
+
private readonly _readers: Readers
|
|
106
|
+
|
|
107
|
+
constructor(iface: string, name: string, params: object, readers?: EventReaders) {
|
|
108
|
+
super(name, params)
|
|
109
|
+
this._iface = iface
|
|
110
|
+
this._readers = new Readers(readers)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Whether this host registered a view under `name` — at contract version `since` or later, when
|
|
114
|
+
* one is given (a method's `@since`). */
|
|
115
|
+
static supports(name: string, since = 1): boolean { return since <= 1 ? NativeView.isSupported(name) : NativeView.version(name) >= since }
|
|
116
|
+
|
|
117
|
+
override on<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this {
|
|
118
|
+
return super.on(event, this._readers.on(event, callback as (data?: any) => void))
|
|
119
|
+
}
|
|
120
|
+
override off<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this {
|
|
121
|
+
return super.off(event, this._readers.off(event, callback as (data?: any) => void))
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** @internal One call over the wire — what the generated functions are made of. */
|
|
125
|
+
_call(method: string, args: any[], since = 1): Promise<any> {
|
|
126
|
+
const old = since > 1 ? tooOld(this._iface, this.viewName, method, since, NativeView.version(this.viewName)) : null
|
|
127
|
+
return old ? Promise.reject(old) : this._channelSend(method, present(args))
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The client of a service plugin: a session that opens on the first call, with the contract's
|
|
132
|
+
* events. The service twin of {@link ViewChannel}. */
|
|
133
|
+
export class ServiceChannel<Events extends object = {}> extends ServiceClient {
|
|
134
|
+
/** @internal */
|
|
135
|
+
readonly _iface: string
|
|
136
|
+
private readonly _readers: Readers
|
|
137
|
+
|
|
138
|
+
constructor(iface: string, name: string, params: object = {}, readers?: EventReaders) {
|
|
139
|
+
super(name, params)
|
|
140
|
+
this._iface = iface
|
|
141
|
+
this._readers = new Readers(readers)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Whether this host registered a service under `name` — at contract version `since` or later,
|
|
145
|
+
* when one is given (a method's `@since`). */
|
|
146
|
+
static supports(name: string, since = 1): boolean { return since <= 1 ? ServiceClient.isSupported(name) : ServiceClient.version(name) >= since }
|
|
147
|
+
|
|
148
|
+
override on<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this {
|
|
149
|
+
return super.on(event, this._readers.on(event, callback as (data?: any) => void))
|
|
150
|
+
}
|
|
151
|
+
override off<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this {
|
|
152
|
+
return super.off(event, this._readers.off(event, callback as (data?: any) => void))
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** @internal */
|
|
156
|
+
_call(method: string, args: any[], since = 1): Promise<any> {
|
|
157
|
+
const old = since > 1 ? tooOld(this._iface, this.serviceName, method, since, ServiceClient.version(this.serviceName)) : null
|
|
158
|
+
return old ? Promise.reject(old) : this._channelSend(method, present(args))
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ---- what a wrapper reads off the wire -------------------------------------------------------------
|
|
163
|
+
|
|
164
|
+
/** @internal A `File` of the contract as it crosses: the host buffer's id, the name, the size. */
|
|
165
|
+
export const _toFile = (wire: { systemId: number, name: string, size: number }): File =>
|
|
166
|
+
new HostFile(wire.systemId, wire.name, wire.size)
|
|
167
|
+
|
|
168
|
+
/** @internal …and the other way: a File the app hands a half. The bytes stay where they are — the
|
|
169
|
+
* half reads them out of the host's buffer table. */
|
|
170
|
+
export const _fromFile = (file: File): { systemId: number, name: string, size: number } =>
|
|
171
|
+
({ systemId: file._h.id, name: file.name, size: file.size })
|
|
172
|
+
|
|
173
|
+
// ---- for the hand-written part ---------------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
/** The text of a host buffer — what a bundled `asset()` is in a shell compile (`"id:N"`): the host
|
|
176
|
+
* already holds the bytes. Empty when there is no such buffer. */
|
|
177
|
+
export const bufferText = (systemId: number): string => _creatorFetch.toText(systemId)
|
|
178
|
+
|
|
179
|
+
/** Prepare-then-present for a view that needs the camera: fail before any prompt on a host without
|
|
180
|
+
* the view, ask for the permission while the current destination stays visible, give up when
|
|
181
|
+
* another navigation superseded this one. Resolves when the view may open. */
|
|
182
|
+
export const prepareCamera = async (view: ViewChannel<any>): Promise<void> => {
|
|
183
|
+
if (!NativeView.isSupported(view.viewName)) {
|
|
184
|
+
throw new Error(`${view._iface} isn't available on this host — it needs a registered "${view.viewName}" view.`)
|
|
185
|
+
}
|
|
186
|
+
const epoch = _navEpoch()
|
|
187
|
+
await _requestCameraPermission()
|
|
188
|
+
if (_navEpoch() !== epoch) {
|
|
189
|
+
throw new Error(`${view._iface}.open() superseded: another destination was opened while preparing`)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// GENERATED by scripts/vendor-plugins.ts from lecodes-plugins/plugins/camera/contract.d.ts — do not edit here.
|
|
2
|
+
// Change it in the plugin repo and run `bun run vendor:plugins`; `bun run check:plugins` fails when this copy is stale.
|
|
3
|
+
// camera — a live camera preview with still capture.
|
|
4
|
+
// The contract of the WIRE: what the app-facing `CameraView` (sdk/) and the halves (ios/, android/,
|
|
5
|
+
// web/) agree on. The generator reads this file; nothing else describes the channel.
|
|
6
|
+
|
|
7
|
+
import type { File, View } from "../../../plugin"
|
|
8
|
+
|
|
9
|
+
export type Facing = "front" | "back"
|
|
10
|
+
|
|
11
|
+
export interface CameraParams {
|
|
12
|
+
/** Default "back". */
|
|
13
|
+
facingMode?: Facing
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface CameraEvents {
|
|
17
|
+
/** The preview could not start or stopped (no camera, the stream was refused). */
|
|
18
|
+
error: { message: string }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface CameraView extends View<"camera", CameraParams, CameraEvents> {
|
|
22
|
+
/** Capture a still frame as a JPEG.
|
|
23
|
+
* @rejects failed */
|
|
24
|
+
takePhoto(): Promise<File>
|
|
25
|
+
/** Switch the camera while the preview is live. */
|
|
26
|
+
setFacingMode(mode: Facing): Promise<void>
|
|
27
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// GENERATED by scripts/vendor-plugins.ts from lecodes-plugins/plugins/camera/sdk/camera.gen.ts — do not edit here.
|
|
2
|
+
// Change it in the plugin repo and run `bun run vendor:plugins`; `bun run check:plugins` fails when this copy is stale.
|
|
3
|
+
// GENERATED by `lecodes plugin gen` from contract.d.ts — do not edit.
|
|
4
|
+
// camera: the view "camera", contract version 1.
|
|
5
|
+
|
|
6
|
+
import { ViewChannel, _toFile, type File } from "../../../../plugin"
|
|
7
|
+
import type { CameraEvents, CameraParams, Facing } from "../contract"
|
|
8
|
+
|
|
9
|
+
/** What the halves register under. */
|
|
10
|
+
export const NAME = "camera"
|
|
11
|
+
/** The contract's version: the highest `@since` of its members. */
|
|
12
|
+
export const VERSION = 1
|
|
13
|
+
|
|
14
|
+
// ---- the wire, call by call ----------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
/** Capture a still frame as a JPEG.
|
|
17
|
+
* Rejects with "failed". */
|
|
18
|
+
export const takePhoto = (view: ViewChannel<CameraEvents>): Promise<File> =>
|
|
19
|
+
view._call("takePhoto", []).then((w: any) => _toFile(w))
|
|
20
|
+
|
|
21
|
+
/** Switch the camera while the preview is live. */
|
|
22
|
+
export const setFacingMode = (view: ViewChannel<CameraEvents>, mode: Facing): Promise<void> =>
|
|
23
|
+
view._call("setFacingMode", [mode])
|
|
24
|
+
|
|
25
|
+
// ---- what the host's half has --------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
/** A method of the contract. */
|
|
28
|
+
export type Method = "takePhoto" | "setFacingMode"
|
|
29
|
+
|
|
30
|
+
/** Whether this host has the view "camera" — and, given a method, a half new enough for it
|
|
31
|
+
* (a method added after the first version of the contract is tagged `@since`). */
|
|
32
|
+
export const supports = (method?: Method): boolean =>
|
|
33
|
+
ViewChannel.supports(NAME) // every method is of version 1
|
|
34
|
+
|
|
35
|
+
// ---- the element ----------------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
/** The view "camera" with the wire's methods as its own. */
|
|
38
|
+
export class CameraViewBase extends ViewChannel<CameraEvents> {
|
|
39
|
+
constructor(params: CameraParams = {}) { super("CameraView", NAME, params) }
|
|
40
|
+
|
|
41
|
+
/** Capture a still frame as a JPEG.
|
|
42
|
+
* Rejects with "failed". */
|
|
43
|
+
takePhoto(): Promise<File> { return takePhoto(this) }
|
|
44
|
+
/** Switch the camera while the preview is live. */
|
|
45
|
+
setFacingMode(mode: Facing): Promise<void> { return setFacingMode(this, mode) }
|
|
46
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// GENERATED by scripts/vendor-plugins.ts from lecodes-plugins/plugins/camera/sdk/camera.ts — do not edit here.
|
|
2
|
+
// Change it in the plugin repo and run `bun run vendor:plugins`; `bun run check:plugins` fails when this copy is stale.
|
|
3
|
+
// CameraView — the device camera (a live preview + still capture) as a view the app opens
|
|
4
|
+
// fullscreen (`await camera.open()`), pushes (`Router.push(camera)`) or embeds among a screen's
|
|
5
|
+
// children. `takePhoto()` returns a `File`: a texture source, a `FormData` value, a share.
|
|
6
|
+
//
|
|
7
|
+
// Hand-written over the generated wire for ONE reason: the permission is asked BEFORE the view is
|
|
8
|
+
// presented, while the current destination stays visible.
|
|
9
|
+
|
|
10
|
+
import { prepareCamera, type File, type NativeView, type PresentOptions } from "../../../../plugin"
|
|
11
|
+
import { CameraViewBase, NAME } from "./camera.gen"
|
|
12
|
+
import type { Facing } from "../contract"
|
|
13
|
+
|
|
14
|
+
export type CameraFacing = Facing
|
|
15
|
+
|
|
16
|
+
export interface CameraView extends NativeView {
|
|
17
|
+
/** Request the camera permission, then present the preview. The current destination stays
|
|
18
|
+
* visible until the camera is ready; rejects if the permission is denied, the host has no
|
|
19
|
+
* camera, or another navigation superseded this one. */
|
|
20
|
+
open(options?: PresentOptions): Promise<void>
|
|
21
|
+
/** Capture a still frame as an image `File` (host-encoded). */
|
|
22
|
+
takePhoto(): Promise<File>
|
|
23
|
+
/** Switch between the front and the back camera while the preview is live. */
|
|
24
|
+
setFacingMode(facingMode: CameraFacing): Promise<void>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class CameraViewElement extends CameraViewBase {
|
|
28
|
+
constructor(options: { facingMode?: CameraFacing } = {}) {
|
|
29
|
+
super({ facingMode: options.facingMode ?? "back" })
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** @internal prepare-then-present (see Presentable._prepare). */
|
|
33
|
+
_prepare(): Promise<void> { return prepareCamera(this) }
|
|
34
|
+
|
|
35
|
+
override async open(options?: PresentOptions): Promise<void> {
|
|
36
|
+
await this._prepare()
|
|
37
|
+
super.open(options)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Create a camera view (default: the back camera). `CameraView.isSupported` reports whether this
|
|
43
|
+
* host has the capability — check it before offering the feature.
|
|
44
|
+
*/
|
|
45
|
+
// PURE IIFE so an app that never uses the camera tree-shakes the whole plugin away.
|
|
46
|
+
export const CameraView: {
|
|
47
|
+
(options?: { facingMode?: CameraFacing }): CameraView
|
|
48
|
+
/** Whether this host registered a "camera" view. */
|
|
49
|
+
readonly isSupported: boolean
|
|
50
|
+
} = /*#__PURE__*/ (() => {
|
|
51
|
+
const factory = (options?: { facingMode?: CameraFacing }): CameraView =>
|
|
52
|
+
new CameraViewElement(options) as unknown as CameraView
|
|
53
|
+
Object.defineProperty(factory, "isSupported", {
|
|
54
|
+
get: (): boolean => CameraViewBase.supports(NAME),
|
|
55
|
+
})
|
|
56
|
+
return factory as any
|
|
57
|
+
})()
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// GENERATED by scripts/vendor-plugins.ts from lecodes-plugins/plugins/geolocation/contract.d.ts — do not edit here.
|
|
2
|
+
// Change it in the plugin repo and run `bun run vendor:plugins`; `bun run check:plugins` fails when this copy is stale.
|
|
3
|
+
// geolocation — the device position.
|
|
4
|
+
// The wire has ONE watch per session (startWatch / stopWatch + the `position` event); the
|
|
5
|
+
// app-facing `Geolocation.watch(callback)` fans it out to its subscribers in sdk/.
|
|
6
|
+
//
|
|
7
|
+
// A session opens without a prompt. The OS permission prompt belongs to the first call that needs
|
|
8
|
+
// the position.
|
|
9
|
+
|
|
10
|
+
import type { Service, f64 } from "../../../plugin"
|
|
11
|
+
|
|
12
|
+
export interface GeoOptions {
|
|
13
|
+
/** Prefer the precise (GPS) provider — slower first fix, more battery. Default false. */
|
|
14
|
+
highAccuracy?: boolean
|
|
15
|
+
/** getCurrent only: reject with "timeout" when no fix arrives in this many ms. */
|
|
16
|
+
timeout?: f64
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface GeoPosition {
|
|
20
|
+
latitude: f64
|
|
21
|
+
longitude: f64
|
|
22
|
+
/** Horizontal accuracy radius, meters. */
|
|
23
|
+
accuracy: f64
|
|
24
|
+
/** Meters above sea level; null when the provider does not know. */
|
|
25
|
+
altitude: f64 | null
|
|
26
|
+
/** Direction of travel, degrees clockwise from north; null when stationary or unknown. */
|
|
27
|
+
heading: f64 | null
|
|
28
|
+
/** Ground speed, m/s; null when unknown. */
|
|
29
|
+
speed: f64 | null
|
|
30
|
+
/** When the fix was taken, ms since the epoch. */
|
|
31
|
+
timestamp: f64
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface GeolocationParams {}
|
|
35
|
+
|
|
36
|
+
export interface GeolocationEvents {
|
|
37
|
+
/** A fix of the live watch. */
|
|
38
|
+
position: GeoPosition
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Geolocation extends Service<"geolocation", GeolocationParams, GeolocationEvents> {
|
|
42
|
+
/** One fix.
|
|
43
|
+
* @rejects denied unavailable timeout */
|
|
44
|
+
getCurrent(options?: GeoOptions): Promise<GeoPosition>
|
|
45
|
+
/** Start the session's watch; resolves once it is live (permission granted, provider started).
|
|
46
|
+
* A second call while watching resolves at once and keeps the first call's options.
|
|
47
|
+
* @rejects denied unavailable */
|
|
48
|
+
startWatch(options?: GeoOptions): Promise<void>
|
|
49
|
+
stopWatch(): Promise<void>
|
|
50
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// GENERATED by scripts/vendor-plugins.ts from lecodes-plugins/plugins/geolocation/sdk/geolocation.gen.ts — do not edit here.
|
|
2
|
+
// Change it in the plugin repo and run `bun run vendor:plugins`; `bun run check:plugins` fails when this copy is stale.
|
|
3
|
+
// GENERATED by `lecodes plugin gen` from contract.d.ts — do not edit.
|
|
4
|
+
// geolocation: the service "geolocation", contract version 1.
|
|
5
|
+
|
|
6
|
+
import { ServiceChannel } from "../../../../plugin"
|
|
7
|
+
import type { GeoOptions, GeoPosition, GeolocationEvents, GeolocationParams } from "../contract"
|
|
8
|
+
|
|
9
|
+
/** What the halves register under. */
|
|
10
|
+
export const NAME = "geolocation"
|
|
11
|
+
/** The contract's version: the highest `@since` of its members. */
|
|
12
|
+
export const VERSION = 1
|
|
13
|
+
|
|
14
|
+
// ---- the wire, call by call ----------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
/** One fix.
|
|
17
|
+
* Rejects with "denied" / "unavailable" / "timeout". */
|
|
18
|
+
export const getCurrent = (service: ServiceChannel<GeolocationEvents>, options?: GeoOptions): Promise<GeoPosition> =>
|
|
19
|
+
service._call("getCurrent", [options])
|
|
20
|
+
|
|
21
|
+
/** Start the session's watch; resolves once it is live (permission granted, provider started).
|
|
22
|
+
* A second call while watching resolves at once and keeps the first call's options.
|
|
23
|
+
* Rejects with "denied" / "unavailable". */
|
|
24
|
+
export const startWatch = (service: ServiceChannel<GeolocationEvents>, options?: GeoOptions): Promise<void> =>
|
|
25
|
+
service._call("startWatch", [options])
|
|
26
|
+
|
|
27
|
+
export const stopWatch = (service: ServiceChannel<GeolocationEvents>): Promise<void> =>
|
|
28
|
+
service._call("stopWatch", [])
|
|
29
|
+
|
|
30
|
+
// ---- what the host's half has --------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
/** A method of the contract. */
|
|
33
|
+
export type Method = "getCurrent" | "startWatch" | "stopWatch"
|
|
34
|
+
|
|
35
|
+
/** Whether this host has the service "geolocation" — and, given a method, a half new enough for it
|
|
36
|
+
* (a method added after the first version of the contract is tagged `@since`). */
|
|
37
|
+
export const supports = (method?: Method): boolean =>
|
|
38
|
+
ServiceChannel.supports(NAME) // every method is of version 1
|
|
39
|
+
|
|
40
|
+
// ---- the client -----------------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
/** The service "geolocation" with the wire's methods as its own. */
|
|
43
|
+
export class GeolocationBase extends ServiceChannel<GeolocationEvents> {
|
|
44
|
+
constructor(params: GeolocationParams = {}) { super("Geolocation", NAME, params) }
|
|
45
|
+
|
|
46
|
+
/** One fix.
|
|
47
|
+
* Rejects with "denied" / "unavailable" / "timeout". */
|
|
48
|
+
getCurrent(options?: GeoOptions): Promise<GeoPosition> { return getCurrent(this, options) }
|
|
49
|
+
/** Start the session's watch; resolves once it is live (permission granted, provider started).
|
|
50
|
+
* A second call while watching resolves at once and keeps the first call's options.
|
|
51
|
+
* Rejects with "denied" / "unavailable". */
|
|
52
|
+
startWatch(options?: GeoOptions): Promise<void> { return startWatch(this, options) }
|
|
53
|
+
stopWatch(): Promise<void> { return stopWatch(this) }
|
|
54
|
+
}
|
|
@@ -1,39 +1,18 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// just `getCurrent()` and `watch()`.
|
|
1
|
+
// GENERATED by scripts/vendor-plugins.ts from lecodes-plugins/plugins/geolocation/sdk/geolocation.ts — do not edit here.
|
|
2
|
+
// Change it in the plugin repo and run `bun run vendor:plugins`; `bun run check:plugins` fails when this copy is stale.
|
|
3
|
+
// Geolocation — the device position: `getCurrent()` and `watch()`.
|
|
5
4
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// rejection. Both methods reject immediately on unsupported hosts, BEFORE any permission path.
|
|
5
|
+
// Hand-written over the generated wire because the public API is not the wire's: the wire has ONE
|
|
6
|
+
// watch per session (startWatch / stopWatch + the `position` event), the app gets `watch(callback)`
|
|
7
|
+
// — any number of subscribers on that one watch, each with its own `stop()`.
|
|
10
8
|
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
9
|
+
// The OS permission prompt happens on the first call that needs it (host-side); a denial is a
|
|
10
|
+
// rejection. Both methods reject on a host without the service BEFORE any permission path.
|
|
13
11
|
|
|
14
|
-
import {
|
|
12
|
+
import { GeolocationBase, NAME } from "./geolocation.gen"
|
|
13
|
+
import type { GeoOptions, GeoPosition } from "../contract"
|
|
15
14
|
|
|
16
|
-
export
|
|
17
|
-
latitude: number
|
|
18
|
-
longitude: number
|
|
19
|
-
/** Horizontal accuracy radius, meters. */
|
|
20
|
-
accuracy: number
|
|
21
|
-
/** Meters above sea level, or null when the provider doesn't know. */
|
|
22
|
-
altitude: number | null
|
|
23
|
-
/** Direction of travel in degrees clockwise from north, or null when stationary/unknown. */
|
|
24
|
-
heading: number | null
|
|
25
|
-
/** Ground speed in m/s, or null when unknown. */
|
|
26
|
-
speed: number | null
|
|
27
|
-
/** When this fix was taken, ms epoch. */
|
|
28
|
-
timestamp: number
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface GeoOptions {
|
|
32
|
-
/** Prefer the precise (GPS) provider — slower first fix, more battery. Default false. */
|
|
33
|
-
highAccuracy?: boolean
|
|
34
|
-
/** getCurrent only: reject with "timeout" if no fix arrives in this many ms. */
|
|
35
|
-
timeout?: number
|
|
36
|
-
}
|
|
15
|
+
export type { GeoOptions, GeoPosition }
|
|
37
16
|
|
|
38
17
|
/** A live `Geolocation.watch()` subscription — `stop()` it when the screen goes away. */
|
|
39
18
|
export interface GeoWatch {
|
|
@@ -44,7 +23,7 @@ export interface GeoWatch {
|
|
|
44
23
|
* The device position. `Geolocation.isSupported` reports whether this host registered the
|
|
45
24
|
* service — check it before offering location features.
|
|
46
25
|
*/
|
|
47
|
-
// PURE IIFE so an app that never uses location tree-shakes the whole plugin away
|
|
26
|
+
// PURE IIFE so an app that never uses location tree-shakes the whole plugin away.
|
|
48
27
|
export const Geolocation: {
|
|
49
28
|
/** Whether this host registered a "geolocation" service. */
|
|
50
29
|
readonly isSupported: boolean
|
|
@@ -56,18 +35,18 @@ export const Geolocation: {
|
|
|
56
35
|
* subscriber; the options of the watch that starts it win. Always `stop()` when done. */
|
|
57
36
|
watch(callback: (position: GeoPosition) => void, options?: GeoOptions): Promise<GeoWatch>
|
|
58
37
|
} = /*#__PURE__*/ (() => {
|
|
59
|
-
let client:
|
|
60
|
-
const service = ():
|
|
38
|
+
let client: GeolocationBase | null = null
|
|
39
|
+
const service = (): GeolocationBase => client ??= new GeolocationBase()
|
|
61
40
|
|
|
62
|
-
// Watch state: one host watch fans out to N subscribers
|
|
41
|
+
// Watch state: one host watch fans out to N subscribers, the last stop() releases it.
|
|
63
42
|
const watchers: ((position: GeoPosition) => void)[] = []
|
|
64
43
|
let positionHooked = false
|
|
65
44
|
let startPromise: Promise<void> | null = null
|
|
66
45
|
|
|
67
46
|
const assertSupported = (): void => {
|
|
68
47
|
// Fail before the host is touched — a permission dialog for a feature that can't exist
|
|
69
|
-
// would be worse than the error
|
|
70
|
-
if (!
|
|
48
|
+
// would be worse than the error.
|
|
49
|
+
if (!GeolocationBase.supports(NAME)) {
|
|
71
50
|
throw new Error('Geolocation isn\'t available on this host — it needs a registered "geolocation" service.')
|
|
72
51
|
}
|
|
73
52
|
}
|
|
@@ -77,26 +56,26 @@ export const Geolocation: {
|
|
|
77
56
|
if (i >= 0) watchers.splice(i, 1)
|
|
78
57
|
if (watchers.length === 0 && startPromise !== null) {
|
|
79
58
|
startPromise = null
|
|
80
|
-
service().
|
|
59
|
+
service().stopWatch().catch(() => {})
|
|
81
60
|
}
|
|
82
61
|
}
|
|
83
62
|
|
|
84
63
|
const geolocation = {
|
|
85
64
|
async getCurrent(options?: GeoOptions): Promise<GeoPosition> {
|
|
86
65
|
assertSupported()
|
|
87
|
-
return await service().
|
|
66
|
+
return await service().getCurrent(options ?? {})
|
|
88
67
|
},
|
|
89
68
|
|
|
90
69
|
async watch(callback: (position: GeoPosition) => void, options?: GeoOptions): Promise<GeoWatch> {
|
|
91
70
|
assertSupported()
|
|
92
71
|
if (!positionHooked) {
|
|
93
72
|
positionHooked = true
|
|
94
|
-
service().on("position",
|
|
73
|
+
service().on("position", position => {
|
|
95
74
|
if (position) for (const cb of [...watchers]) cb(position)
|
|
96
75
|
})
|
|
97
76
|
}
|
|
98
77
|
watchers.push(callback)
|
|
99
|
-
startPromise ??= service().
|
|
78
|
+
startPromise ??= service().startWatch(options ?? {})
|
|
100
79
|
try {
|
|
101
80
|
await startPromise
|
|
102
81
|
} catch (e) {
|
|
@@ -117,7 +96,7 @@ export const Geolocation: {
|
|
|
117
96
|
},
|
|
118
97
|
}
|
|
119
98
|
Object.defineProperty(geolocation, "isSupported", {
|
|
120
|
-
get: (): boolean =>
|
|
99
|
+
get: (): boolean => GeolocationBase.supports(NAME),
|
|
121
100
|
})
|
|
122
101
|
return geolocation as any
|
|
123
102
|
})()
|