@elizaos/capacitor-location 1.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/ElizaosCapacitorLocation.podspec +17 -0
- package/android/build.gradle +45 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/java/ai/eliza/plugins/location/LocationPlugin.kt +346 -0
- package/dist/esm/definitions.d.ts +133 -0
- package/dist/esm/definitions.d.ts.map +1 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +20 -0
- package/dist/esm/web.d.ts.map +1 -0
- package/dist/esm/web.js +133 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +148 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +151 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/LocationPlugin/LocationPlugin.swift +391 -0
- package/package.json +83 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
import CoreLocation
|
|
4
|
+
|
|
5
|
+
/// Native iOS implementation of the ElizaLocation Capacitor plugin.
|
|
6
|
+
///
|
|
7
|
+
/// Bridges CLLocationManager to the TypeScript LocationPlugin interface, providing:
|
|
8
|
+
/// - getCurrentPosition (one-shot with accuracy, maxAge cache, timeout)
|
|
9
|
+
/// - watchPosition (continuous updates with minDistance + minInterval throttle)
|
|
10
|
+
/// - clearWatch (stop a running watch)
|
|
11
|
+
/// - checkPermissions / requestPermissions (whenInUse or always)
|
|
12
|
+
/// - Events: locationChange, error
|
|
13
|
+
@objc(ElizaLocationPlugin)
|
|
14
|
+
public class ElizaLocationPlugin: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelegate {
|
|
15
|
+
public let identifier = "ElizaLocationPlugin"
|
|
16
|
+
public let jsName = "ElizaLocation"
|
|
17
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
18
|
+
CAPPluginMethod(name: "getCurrentPosition", returnType: CAPPluginReturnPromise),
|
|
19
|
+
CAPPluginMethod(name: "watchPosition", returnType: CAPPluginReturnPromise),
|
|
20
|
+
CAPPluginMethod(name: "clearWatch", returnType: CAPPluginReturnPromise),
|
|
21
|
+
CAPPluginMethod(name: "checkPermissions", returnType: CAPPluginReturnPromise),
|
|
22
|
+
CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise),
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
// MARK: - State
|
|
26
|
+
|
|
27
|
+
/// Primary manager used for permission requests and cached-location reads.
|
|
28
|
+
private var locationManager: CLLocationManager!
|
|
29
|
+
|
|
30
|
+
/// Retained manager for an in-flight one-shot location request.
|
|
31
|
+
/// Must be kept alive until the delegate fires or the timeout expires.
|
|
32
|
+
private var singleRequestManager: CLLocationManager?
|
|
33
|
+
private var singleRequestTimer: DispatchWorkItem?
|
|
34
|
+
|
|
35
|
+
/// Active watch sessions keyed by watch ID.
|
|
36
|
+
private var watches: [String: WatchState] = [:]
|
|
37
|
+
|
|
38
|
+
/// A pending plugin call waiting for authorization before it can proceed.
|
|
39
|
+
private var pendingCall: CAPPluginCall?
|
|
40
|
+
private var pendingAction: PendingAction?
|
|
41
|
+
|
|
42
|
+
private enum PendingAction {
|
|
43
|
+
case getCurrentPosition
|
|
44
|
+
case watchPosition
|
|
45
|
+
case requestPermissions
|
|
46
|
+
case singleLocation
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/// Per-watch bookkeeping.
|
|
50
|
+
private struct WatchState {
|
|
51
|
+
let manager: CLLocationManager
|
|
52
|
+
/// Minimum interval (seconds) between emitted events. 0 = no throttle.
|
|
53
|
+
let minInterval: TimeInterval
|
|
54
|
+
/// Timestamp of the last emitted locationChange for this watch.
|
|
55
|
+
var lastEmitted: Date?
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// MARK: - Lifecycle
|
|
59
|
+
|
|
60
|
+
public override func load() {
|
|
61
|
+
locationManager = CLLocationManager()
|
|
62
|
+
locationManager.delegate = self
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// MARK: - getCurrentPosition
|
|
66
|
+
|
|
67
|
+
@objc func getCurrentPosition(_ call: CAPPluginCall) {
|
|
68
|
+
guard CLLocationManager.locationServicesEnabled() else {
|
|
69
|
+
call.reject("Location services disabled", "POSITION_UNAVAILABLE")
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let status = currentAuthStatus()
|
|
74
|
+
|
|
75
|
+
if status == .notDetermined {
|
|
76
|
+
pendingCall = call
|
|
77
|
+
pendingAction = .getCurrentPosition
|
|
78
|
+
locationManager.requestWhenInUseAuthorization()
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
guard status == .authorizedWhenInUse || status == .authorizedAlways else {
|
|
83
|
+
call.reject("Location permission denied", "PERMISSION_DENIED")
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
getCurrentPositionInternal(call)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private func getCurrentPositionInternal(_ call: CAPPluginCall) {
|
|
91
|
+
let accuracy = call.getString("accuracy") ?? "high"
|
|
92
|
+
let timeout = call.getDouble("timeout") ?? 10000
|
|
93
|
+
let maxAge = call.getDouble("maxAge") ?? 0
|
|
94
|
+
|
|
95
|
+
// Return a cached location if fresh enough (mirrors classic LocationService).
|
|
96
|
+
if maxAge > 0, let cached = locationManager.location {
|
|
97
|
+
let ageMs = Date().timeIntervalSince(cached.timestamp) * 1000
|
|
98
|
+
if ageMs <= maxAge {
|
|
99
|
+
call.resolve(buildLocationResult(from: cached, cached: true))
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Spin up a dedicated manager so desiredAccuracy is isolated.
|
|
105
|
+
let manager = CLLocationManager()
|
|
106
|
+
manager.delegate = self
|
|
107
|
+
manager.desiredAccuracy = clAccuracy(from: accuracy)
|
|
108
|
+
|
|
109
|
+
// Retain to prevent dealloc before the delegate fires.
|
|
110
|
+
singleRequestManager = manager
|
|
111
|
+
pendingCall = call
|
|
112
|
+
pendingAction = .singleLocation
|
|
113
|
+
|
|
114
|
+
manager.requestLocation()
|
|
115
|
+
|
|
116
|
+
// Timeout guard.
|
|
117
|
+
let timer = DispatchWorkItem { [weak self] in
|
|
118
|
+
guard let self, self.pendingAction == .singleLocation else { return }
|
|
119
|
+
self.cleanupSingleRequest()?.reject("Location request timed out", "TIMEOUT")
|
|
120
|
+
}
|
|
121
|
+
singleRequestTimer = timer
|
|
122
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + timeout / 1000, execute: timer)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/// Cancel in-flight single-request state and return the call (if any) for the caller to resolve/reject.
|
|
126
|
+
@discardableResult
|
|
127
|
+
private func cleanupSingleRequest() -> CAPPluginCall? {
|
|
128
|
+
singleRequestTimer?.cancel()
|
|
129
|
+
singleRequestTimer = nil
|
|
130
|
+
singleRequestManager?.delegate = nil
|
|
131
|
+
singleRequestManager = nil
|
|
132
|
+
let call = pendingCall
|
|
133
|
+
pendingCall = nil
|
|
134
|
+
pendingAction = nil
|
|
135
|
+
return call
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// MARK: - watchPosition
|
|
139
|
+
|
|
140
|
+
@objc func watchPosition(_ call: CAPPluginCall) {
|
|
141
|
+
guard CLLocationManager.locationServicesEnabled() else {
|
|
142
|
+
call.reject("Location services disabled", "POSITION_UNAVAILABLE")
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let status = currentAuthStatus()
|
|
147
|
+
|
|
148
|
+
if status == .notDetermined {
|
|
149
|
+
pendingCall = call
|
|
150
|
+
pendingAction = .watchPosition
|
|
151
|
+
locationManager.requestWhenInUseAuthorization()
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
guard status == .authorizedWhenInUse || status == .authorizedAlways else {
|
|
156
|
+
call.reject("Location permission denied", "PERMISSION_DENIED")
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
watchPositionInternal(call)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private func watchPositionInternal(_ call: CAPPluginCall) {
|
|
164
|
+
let accuracy = call.getString("accuracy") ?? "high"
|
|
165
|
+
let minDistance = call.getDouble("minDistance") ?? 0
|
|
166
|
+
let minInterval = call.getDouble("minInterval") ?? 0
|
|
167
|
+
|
|
168
|
+
let watchId = UUID().uuidString
|
|
169
|
+
let manager = CLLocationManager()
|
|
170
|
+
manager.delegate = self
|
|
171
|
+
manager.desiredAccuracy = clAccuracy(from: accuracy)
|
|
172
|
+
manager.distanceFilter = minDistance > 0 ? minDistance : kCLDistanceFilterNone
|
|
173
|
+
|
|
174
|
+
watches[watchId] = WatchState(
|
|
175
|
+
manager: manager,
|
|
176
|
+
minInterval: minInterval / 1000, // ms → seconds
|
|
177
|
+
lastEmitted: nil
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
manager.startUpdatingLocation()
|
|
181
|
+
|
|
182
|
+
call.resolve(["watchId": watchId])
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// MARK: - clearWatch
|
|
186
|
+
|
|
187
|
+
@objc func clearWatch(_ call: CAPPluginCall) {
|
|
188
|
+
guard let watchId = call.getString("watchId") else {
|
|
189
|
+
call.reject("Missing watchId")
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if let state = watches.removeValue(forKey: watchId) {
|
|
194
|
+
state.manager.stopUpdatingLocation()
|
|
195
|
+
state.manager.delegate = nil
|
|
196
|
+
}
|
|
197
|
+
call.resolve()
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// MARK: - Permissions
|
|
201
|
+
|
|
202
|
+
@objc public override func checkPermissions(_ call: CAPPluginCall) {
|
|
203
|
+
call.resolve(buildPermissionResult())
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
@objc public override func requestPermissions(_ call: CAPPluginCall) {
|
|
207
|
+
guard CLLocationManager.locationServicesEnabled() else {
|
|
208
|
+
call.reject("Location services disabled", "POSITION_UNAVAILABLE")
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
let status = currentAuthStatus()
|
|
213
|
+
let level = call.getString("level") ?? "whenInUse"
|
|
214
|
+
|
|
215
|
+
if status == .notDetermined {
|
|
216
|
+
pendingCall = call
|
|
217
|
+
pendingAction = .requestPermissions
|
|
218
|
+
if level == "always" {
|
|
219
|
+
locationManager.requestAlwaysAuthorization()
|
|
220
|
+
} else {
|
|
221
|
+
locationManager.requestWhenInUseAuthorization()
|
|
222
|
+
}
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Escalate whenInUse → always if requested (mirrors classic ensureAuthorization).
|
|
227
|
+
if level == "always" && status == .authorizedWhenInUse {
|
|
228
|
+
pendingCall = call
|
|
229
|
+
pendingAction = .requestPermissions
|
|
230
|
+
locationManager.requestAlwaysAuthorization()
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Already determined — return current state.
|
|
235
|
+
call.resolve(buildPermissionResult())
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// MARK: - CLLocationManagerDelegate
|
|
239
|
+
|
|
240
|
+
public func locationManager(
|
|
241
|
+
_ manager: CLLocationManager,
|
|
242
|
+
didUpdateLocations locations: [CLLocation]
|
|
243
|
+
) {
|
|
244
|
+
guard let location = locations.last else { return }
|
|
245
|
+
|
|
246
|
+
// One-shot request?
|
|
247
|
+
if pendingAction == .singleLocation, manager === singleRequestManager {
|
|
248
|
+
cleanupSingleRequest()?.resolve(buildLocationResult(from: location, cached: false))
|
|
249
|
+
return
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Watch update — find the matching watch and apply minInterval throttle.
|
|
253
|
+
for (watchId, var state) in watches where state.manager === manager {
|
|
254
|
+
if state.minInterval > 0, let last = state.lastEmitted,
|
|
255
|
+
Date().timeIntervalSince(last) < state.minInterval
|
|
256
|
+
{
|
|
257
|
+
return // throttled
|
|
258
|
+
}
|
|
259
|
+
state.lastEmitted = Date()
|
|
260
|
+
watches[watchId] = state
|
|
261
|
+
notifyListeners("locationChange", data: buildLocationResult(from: location, cached: false))
|
|
262
|
+
return
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
public func locationManager(
|
|
267
|
+
_ manager: CLLocationManager,
|
|
268
|
+
didFailWithError error: Error
|
|
269
|
+
) {
|
|
270
|
+
// One-shot request?
|
|
271
|
+
if pendingAction == .singleLocation, manager === singleRequestManager {
|
|
272
|
+
cleanupSingleRequest()?.reject(
|
|
273
|
+
"Location error: \(error.localizedDescription)", "POSITION_UNAVAILABLE"
|
|
274
|
+
)
|
|
275
|
+
return
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Watch error — emit event.
|
|
279
|
+
for (_, state) in watches where state.manager === manager {
|
|
280
|
+
notifyListeners("error", data: [
|
|
281
|
+
"code": "POSITION_UNAVAILABLE",
|
|
282
|
+
"message": error.localizedDescription,
|
|
283
|
+
])
|
|
284
|
+
return
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
public func locationManager(
|
|
289
|
+
_ manager: CLLocationManager,
|
|
290
|
+
didChangeAuthorization status: CLAuthorizationStatus
|
|
291
|
+
) {
|
|
292
|
+
guard let call = pendingCall, let action = pendingAction else { return }
|
|
293
|
+
|
|
294
|
+
// Still waiting for user to decide.
|
|
295
|
+
if status == .notDetermined { return }
|
|
296
|
+
|
|
297
|
+
// Clear pending state *before* calling internal methods — they may set new values.
|
|
298
|
+
pendingCall = nil
|
|
299
|
+
pendingAction = nil
|
|
300
|
+
|
|
301
|
+
switch action {
|
|
302
|
+
case .getCurrentPosition:
|
|
303
|
+
if status == .authorizedWhenInUse || status == .authorizedAlways {
|
|
304
|
+
getCurrentPositionInternal(call)
|
|
305
|
+
} else {
|
|
306
|
+
call.reject("Location permission denied", "PERMISSION_DENIED")
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
case .watchPosition:
|
|
310
|
+
if status == .authorizedWhenInUse || status == .authorizedAlways {
|
|
311
|
+
watchPositionInternal(call)
|
|
312
|
+
} else {
|
|
313
|
+
call.reject("Location permission denied", "PERMISSION_DENIED")
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
case .requestPermissions:
|
|
317
|
+
call.resolve(buildPermissionResult())
|
|
318
|
+
|
|
319
|
+
case .singleLocation:
|
|
320
|
+
// Shouldn't happen — singleLocation is set after auth is granted.
|
|
321
|
+
break
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// MARK: - Helpers
|
|
326
|
+
|
|
327
|
+
private func currentAuthStatus() -> CLAuthorizationStatus {
|
|
328
|
+
CLLocationManager.authorizationStatus()
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/// Map the TypeScript LocationAccuracy string to a CLLocationAccuracy constant.
|
|
332
|
+
private func clAccuracy(from accuracy: String) -> CLLocationAccuracy {
|
|
333
|
+
switch accuracy {
|
|
334
|
+
case "best": return kCLLocationAccuracyBest
|
|
335
|
+
case "high": return kCLLocationAccuracyNearestTenMeters
|
|
336
|
+
case "medium": return kCLLocationAccuracyHundredMeters
|
|
337
|
+
case "low": return kCLLocationAccuracyKilometer
|
|
338
|
+
case "passive": return kCLLocationAccuracyThreeKilometers
|
|
339
|
+
default: return kCLLocationAccuracyNearestTenMeters
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/// Build the permission result matching LocationPermissionStatus in definitions.ts.
|
|
344
|
+
private func buildPermissionResult() -> JSObject {
|
|
345
|
+
let status = currentAuthStatus()
|
|
346
|
+
let location: String
|
|
347
|
+
let background: String
|
|
348
|
+
|
|
349
|
+
switch status {
|
|
350
|
+
case .authorizedAlways:
|
|
351
|
+
location = "granted"
|
|
352
|
+
background = "granted"
|
|
353
|
+
case .authorizedWhenInUse:
|
|
354
|
+
location = "granted"
|
|
355
|
+
background = "prompt"
|
|
356
|
+
case .denied, .restricted:
|
|
357
|
+
location = "denied"
|
|
358
|
+
background = "denied"
|
|
359
|
+
default:
|
|
360
|
+
location = "prompt"
|
|
361
|
+
background = "prompt"
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return ["location": location, "background": background]
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/// Build a LocationResult matching the TypeScript interface:
|
|
368
|
+
/// `{ coords: LocationCoordinates, cached: boolean }`
|
|
369
|
+
private func buildLocationResult(from location: CLLocation, cached: Bool) -> JSObject {
|
|
370
|
+
var coords: JSObject = [
|
|
371
|
+
"latitude": location.coordinate.latitude,
|
|
372
|
+
"longitude": location.coordinate.longitude,
|
|
373
|
+
"accuracy": location.horizontalAccuracy,
|
|
374
|
+
"timestamp": location.timestamp.timeIntervalSince1970 * 1000,
|
|
375
|
+
]
|
|
376
|
+
|
|
377
|
+
// Altitude data is valid when verticalAccuracy >= 0.
|
|
378
|
+
if location.verticalAccuracy >= 0 {
|
|
379
|
+
coords["altitude"] = location.altitude
|
|
380
|
+
coords["altitudeAccuracy"] = location.verticalAccuracy
|
|
381
|
+
}
|
|
382
|
+
if location.speed >= 0 {
|
|
383
|
+
coords["speed"] = location.speed
|
|
384
|
+
}
|
|
385
|
+
if location.course >= 0 {
|
|
386
|
+
coords["heading"] = location.course
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return ["coords": coords, "cached": cached]
|
|
390
|
+
}
|
|
391
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elizaos/capacitor-location",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Reads current location, watches movement, and manages geolocation permissions.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"location",
|
|
7
|
+
"geolocation",
|
|
8
|
+
"device",
|
|
9
|
+
"permissions"
|
|
10
|
+
],
|
|
11
|
+
"main": "./dist/plugin.cjs.js",
|
|
12
|
+
"module": "./dist/esm/index.js",
|
|
13
|
+
"types": "./dist/esm/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/esm/index.d.ts",
|
|
17
|
+
"import": "./dist/esm/index.js",
|
|
18
|
+
"require": "./dist/plugin.cjs.js"
|
|
19
|
+
},
|
|
20
|
+
"./package.json": "./package.json"
|
|
21
|
+
},
|
|
22
|
+
"unpkg": "dist/plugin.js",
|
|
23
|
+
"files": [
|
|
24
|
+
"android/src/main/",
|
|
25
|
+
"android/build.gradle",
|
|
26
|
+
"dist/",
|
|
27
|
+
"ios/Sources/",
|
|
28
|
+
"*.podspec"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "npm run clean && tsc && rollup -c rollup.config.mjs",
|
|
32
|
+
"build:docs": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
|
33
|
+
"clean": "rimraf ./dist",
|
|
34
|
+
"prepublishOnly": "npm run build",
|
|
35
|
+
"docgen": "docgen --api LocationPlugin --output-readme README.md --output-json dist/docs.json"
|
|
36
|
+
},
|
|
37
|
+
"author": "elizaOS",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@elizaos/app-core": "2.0.0-alpha.537"
|
|
41
|
+
},
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/elizaOS/eliza.git",
|
|
45
|
+
"directory": "apps/app/plugins/location"
|
|
46
|
+
},
|
|
47
|
+
"capacitor": {
|
|
48
|
+
"ios": {
|
|
49
|
+
"src": "ios",
|
|
50
|
+
"podName": "ElizaCapacitorLocation"
|
|
51
|
+
},
|
|
52
|
+
"android": {
|
|
53
|
+
"src": "android"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@capacitor/cli": "^8.0.0",
|
|
58
|
+
"@capacitor/core": "^8.3.1",
|
|
59
|
+
"@capacitor/docgen": "^0.3.0",
|
|
60
|
+
"rimraf": "^6.0.0",
|
|
61
|
+
"rollup": "^4.60.2",
|
|
62
|
+
"typescript": "^6.0.0"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"@capacitor/core": "^8.3.1"
|
|
66
|
+
},
|
|
67
|
+
"publishConfig": {
|
|
68
|
+
"access": "public"
|
|
69
|
+
},
|
|
70
|
+
"elizaos": {
|
|
71
|
+
"platforms": [
|
|
72
|
+
"browser",
|
|
73
|
+
"node"
|
|
74
|
+
],
|
|
75
|
+
"runtime": "both",
|
|
76
|
+
"platformDetails": {
|
|
77
|
+
"browser": "Full support via Geolocation API (current position, watch position, permissions)",
|
|
78
|
+
"node": "Full support via Electrobun with native geolocation services",
|
|
79
|
+
"ios": true,
|
|
80
|
+
"android": true
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|