@ateam-ai-mobile/expo 0.1.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.
@@ -0,0 +1,12 @@
1
+ import { Bridge } from '@ateam-ai-mobile/plugin-runtime';
2
+
3
+ /**
4
+ * Native Bridge Factory
5
+ *
6
+ * Creates a Bridge instance that wraps Expo native modules.
7
+ * Each bridge is scoped to a specific connector ID for storage isolation.
8
+ */
9
+
10
+ declare function createBridge(connectorId: string, deviceId: string): Bridge;
11
+
12
+ export { createBridge };
@@ -0,0 +1,12 @@
1
+ import { Bridge } from '@ateam-ai-mobile/plugin-runtime';
2
+
3
+ /**
4
+ * Native Bridge Factory
5
+ *
6
+ * Creates a Bridge instance that wraps Expo native modules.
7
+ * Each bridge is scoped to a specific connector ID for storage isolation.
8
+ */
9
+
10
+ declare function createBridge(connectorId: string, deviceId: string): Bridge;
11
+
12
+ export { createBridge };
@@ -0,0 +1,644 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/createBridge.ts
31
+ var createBridge_exports = {};
32
+ __export(createBridge_exports, {
33
+ createBridge: () => createBridge
34
+ });
35
+ module.exports = __toCommonJS(createBridge_exports);
36
+ var import_async_storage = __toESM(require("@react-native-async-storage/async-storage"));
37
+ var ExpoCalendar = __toESM(require("expo-calendar"));
38
+ var ExpoContacts = __toESM(require("expo-contacts"));
39
+ var ExpoLocation = __toESM(require("expo-location"));
40
+ var ExpoBattery = __toESM(require("expo-battery"));
41
+ var ExpoNetwork = __toESM(require("expo-network"));
42
+ var ExpoNotifications = __toESM(require("expo-notifications"));
43
+ var ExpoSMS = __toESM(require("expo-sms"));
44
+ var ExpoLinking = __toESM(require("expo-linking"));
45
+ var import_react_native = require("react-native");
46
+ function createBridge(connectorId, deviceId) {
47
+ const storagePrefix = `connector:${connectorId}:`;
48
+ const log = {
49
+ info: (msg, data) => {
50
+ console.log(`[${connectorId}] ${msg}`, data || "");
51
+ },
52
+ warn: (msg, data) => {
53
+ console.warn(`[${connectorId}] ${msg}`, data || "");
54
+ },
55
+ error: (msg, data) => {
56
+ console.error(`[${connectorId}] ${msg}`, data || "");
57
+ }
58
+ };
59
+ const parseDateTime = (dateStr, timeStr) => {
60
+ const [year, month, day] = dateStr.split("-").map(Number);
61
+ const [hours, minutes] = timeStr.split(":").map(Number);
62
+ return new Date(year, month - 1, day, hours, minutes);
63
+ };
64
+ const formatDate = (date) => {
65
+ return date.toISOString().split("T")[0];
66
+ };
67
+ const getDayOfWeek = (date) => {
68
+ const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
69
+ return days[date.getDay()];
70
+ };
71
+ const addDays = (date, days) => {
72
+ const result = new Date(date);
73
+ result.setDate(result.getDate() + days);
74
+ return result;
75
+ };
76
+ const startOfDay = (date) => {
77
+ const result = new Date(date);
78
+ result.setHours(0, 0, 0, 0);
79
+ return result;
80
+ };
81
+ const endOfDay = (date) => {
82
+ const result = new Date(date);
83
+ result.setHours(23, 59, 59, 999);
84
+ return result;
85
+ };
86
+ const getCalendarIds = async () => {
87
+ try {
88
+ const calendars = await ExpoCalendar.getCalendarsAsync(ExpoCalendar.EntityTypes.EVENT);
89
+ return calendars.map((c) => c.id);
90
+ } catch (err) {
91
+ log.warn("Failed to get calendar IDs", err);
92
+ return [];
93
+ }
94
+ };
95
+ const getDefaultCalendarId = async () => {
96
+ try {
97
+ const calendars = await ExpoCalendar.getCalendarsAsync(ExpoCalendar.EntityTypes.EVENT);
98
+ return calendars.length > 0 ? calendars[0].id : "";
99
+ } catch (err) {
100
+ log.warn("Failed to get default calendar", err);
101
+ return "";
102
+ }
103
+ };
104
+ const formatCalendarEvent = (event) => {
105
+ return {
106
+ id: event.id,
107
+ title: event.title,
108
+ date: event.startDate ? formatDate(new Date(event.startDate)) : "",
109
+ start: event.startDate ? new Date(event.startDate).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" }) : "",
110
+ end: event.endDate ? new Date(event.endDate).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" }) : "",
111
+ location: event.location || "",
112
+ attendees: event.attendees ? event.attendees.map((a) => a.email || a.name) : [],
113
+ notes: event.notes || ""
114
+ };
115
+ };
116
+ const formatContact = (contact) => {
117
+ const phone = contact.phoneNumbers?.[0]?.number || null;
118
+ const email = contact.emails?.[0]?.email || null;
119
+ const birthday = contact.birthday ? `${contact.birthday.year}-${String(contact.birthday.month).padStart(2, "0")}-${String(contact.birthday.day).padStart(2, "0")}` : null;
120
+ return {
121
+ id: contact.id,
122
+ name: contact.name,
123
+ phone,
124
+ email,
125
+ relationship: contact.relationships?.[0]?.relationship || contact.contactType || "contact",
126
+ birthday,
127
+ notes: contact.note || ""
128
+ };
129
+ };
130
+ const classifyLocation = (geo) => {
131
+ const name = geo.name?.toLowerCase() || "";
132
+ if (name.includes("home")) return "home";
133
+ if (name.includes("work") || name.includes("office")) return "work";
134
+ if (name.includes("school") || name.includes("university")) return "school";
135
+ if (name.includes("gym") || name.includes("fitness")) return "fitness";
136
+ if (name.includes("hospital") || name.includes("clinic") || name.includes("medical")) return "medical";
137
+ return "other";
138
+ };
139
+ const formatPlace = (geo) => {
140
+ if (!geo) return "Unknown Location";
141
+ const name = geo.name || "";
142
+ const street = geo.street ? `${geo.street}` : "";
143
+ return name ? `${name} \u2014 ${street}` : street;
144
+ };
145
+ const formatAddress = (geo) => {
146
+ if (!geo) return "";
147
+ const parts = [geo.street, geo.city, geo.region, geo.postalCode].filter(Boolean);
148
+ return parts.join(", ");
149
+ };
150
+ const formatNotification = (notif) => {
151
+ return {
152
+ id: notif.request?.identifier || String(Math.random()),
153
+ app: notif.request?.content?.title || "Unknown",
154
+ title: notif.request?.content?.title || "",
155
+ body: notif.request?.content?.body || "",
156
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
157
+ sender: null,
158
+ priority: "medium",
159
+ read: false
160
+ };
161
+ };
162
+ const mapBatteryState = (state) => {
163
+ if (state === ExpoBattery.BatteryState.CHARGING) return "charging";
164
+ if (state === ExpoBattery.BatteryState.FULL) return "full";
165
+ return "unplugged";
166
+ };
167
+ const bridge = {
168
+ calendar: {
169
+ async getToday() {
170
+ try {
171
+ const start = startOfDay(/* @__PURE__ */ new Date());
172
+ const end = endOfDay(/* @__PURE__ */ new Date());
173
+ const calendarIds = await getCalendarIds();
174
+ const events = await ExpoCalendar.getEventsAsync(calendarIds, start, end);
175
+ return {
176
+ date: formatDate(/* @__PURE__ */ new Date()),
177
+ day_of_week: getDayOfWeek(/* @__PURE__ */ new Date()),
178
+ events: events.map(formatCalendarEvent),
179
+ count: events.length
180
+ };
181
+ } catch (err) {
182
+ log.error("Failed to get today's calendar events", err);
183
+ return { date: formatDate(/* @__PURE__ */ new Date()), day_of_week: getDayOfWeek(/* @__PURE__ */ new Date()), events: [], count: 0 };
184
+ }
185
+ },
186
+ async getUpcoming(days = 7) {
187
+ try {
188
+ const start = /* @__PURE__ */ new Date();
189
+ const end = addDays(start, Math.min(days, 14));
190
+ const calendarIds = await getCalendarIds();
191
+ const events = await ExpoCalendar.getEventsAsync(calendarIds, start, end);
192
+ return {
193
+ from: formatDate(start),
194
+ days_ahead: days,
195
+ events: events.map(formatCalendarEvent),
196
+ count: events.length
197
+ };
198
+ } catch (err) {
199
+ log.error("Failed to get upcoming calendar events", err);
200
+ return { from: formatDate(/* @__PURE__ */ new Date()), days_ahead: days, events: [], count: 0 };
201
+ }
202
+ },
203
+ async create(event) {
204
+ try {
205
+ const calendarId = await getDefaultCalendarId();
206
+ if (!calendarId) throw new Error("No default calendar found");
207
+ const eventId = await ExpoCalendar.createEventAsync(calendarId, {
208
+ title: event.title,
209
+ startDate: parseDateTime(event.date, event.start_time),
210
+ endDate: parseDateTime(event.date, event.end_time || event.start_time),
211
+ location: event.location,
212
+ notes: event.notes
213
+ });
214
+ return { event_id: eventId };
215
+ } catch (err) {
216
+ log.error("Failed to create calendar event", err);
217
+ throw err;
218
+ }
219
+ },
220
+ async reschedule(params) {
221
+ try {
222
+ const updates = {};
223
+ if (params.new_date && params.new_start_time) {
224
+ updates.startDate = parseDateTime(params.new_date, params.new_start_time);
225
+ }
226
+ if (params.new_date && params.new_end_time) {
227
+ updates.endDate = parseDateTime(params.new_date, params.new_end_time);
228
+ }
229
+ await ExpoCalendar.updateEventAsync(params.event_id, updates);
230
+ return { ok: true };
231
+ } catch (err) {
232
+ log.error("Failed to reschedule event", err);
233
+ throw err;
234
+ }
235
+ },
236
+ async cancel(event_id) {
237
+ try {
238
+ await ExpoCalendar.deleteEventAsync(event_id);
239
+ return { ok: true };
240
+ } catch (err) {
241
+ log.error("Failed to cancel event", err);
242
+ throw err;
243
+ }
244
+ }
245
+ },
246
+ contacts: {
247
+ async search(query) {
248
+ try {
249
+ const { data } = await ExpoContacts.getContactsAsync({
250
+ fields: [
251
+ ExpoContacts.Fields.PhoneNumbers,
252
+ ExpoContacts.Fields.Emails,
253
+ ExpoContacts.Fields.Birthday,
254
+ ExpoContacts.Fields.Note,
255
+ ExpoContacts.Fields.Relationships
256
+ ]
257
+ });
258
+ const q = query.toLowerCase();
259
+ const filtered = data.filter(
260
+ (c) => c.name?.toLowerCase().includes(q) || c.note?.toLowerCase().includes(q)
261
+ );
262
+ return { contacts: filtered.map(formatContact), count: filtered.length };
263
+ } catch (err) {
264
+ log.error("Failed to search contacts", err);
265
+ return { contacts: [], count: 0 };
266
+ }
267
+ },
268
+ async get(idOrName) {
269
+ try {
270
+ const { data } = await ExpoContacts.getContactsAsync({
271
+ fields: [
272
+ ExpoContacts.Fields.PhoneNumbers,
273
+ ExpoContacts.Fields.Emails,
274
+ ExpoContacts.Fields.Birthday,
275
+ ExpoContacts.Fields.Note
276
+ ]
277
+ });
278
+ const contact = data.find((c) => c.id === idOrName || c.name === idOrName);
279
+ return contact ? formatContact(contact) : null;
280
+ } catch (err) {
281
+ log.error("Failed to get contact", err);
282
+ return null;
283
+ }
284
+ },
285
+ async getAll() {
286
+ try {
287
+ const { data } = await ExpoContacts.getContactsAsync({
288
+ fields: [
289
+ ExpoContacts.Fields.PhoneNumbers,
290
+ ExpoContacts.Fields.Emails,
291
+ ExpoContacts.Fields.Birthday,
292
+ ExpoContacts.Fields.Note,
293
+ ExpoContacts.Fields.Relationships
294
+ ],
295
+ sort: ExpoContacts.SortTypes.LastName
296
+ });
297
+ return { contacts: data.map(formatContact), count: data.length };
298
+ } catch (err) {
299
+ log.error("Failed to get all contacts", err);
300
+ return { contacts: [], count: 0 };
301
+ }
302
+ },
303
+ async birthdays(days = 30) {
304
+ try {
305
+ const { data } = await ExpoContacts.getContactsAsync({
306
+ fields: [ExpoContacts.Fields.Birthday]
307
+ });
308
+ const today = /* @__PURE__ */ new Date();
309
+ const futureDate = addDays(today, days);
310
+ const birthdays = data.filter((c) => c.birthday).map((c) => {
311
+ const birthday = c.birthday;
312
+ const thisYearBday = new Date(today.getFullYear(), birthday.month - 1, birthday.day);
313
+ if (thisYearBday < today) {
314
+ thisYearBday.setFullYear(today.getFullYear() + 1);
315
+ }
316
+ return {
317
+ name: c.name,
318
+ relationship: c.relationships?.[0]?.relationship || "contact",
319
+ birthday: `${birthday.year || "????"}-${String(birthday.month).padStart(2, "0")}-${String(birthday.day).padStart(2, "0")}`,
320
+ days_until: Math.floor((thisYearBday.getTime() - today.getTime()) / (1e3 * 60 * 60 * 24)),
321
+ is_today: thisYearBday.toDateString() === today.toDateString()
322
+ };
323
+ }).filter((b) => b.days_until >= 0 && b.days_until <= days);
324
+ return { birthdays, count: birthdays.length };
325
+ } catch (err) {
326
+ log.error("Failed to get birthdays", err);
327
+ return { birthdays: [], count: 0 };
328
+ }
329
+ }
330
+ },
331
+ location: {
332
+ async getCurrent() {
333
+ try {
334
+ const location = await ExpoLocation.getCurrentPositionAsync({
335
+ accuracy: ExpoLocation.Accuracy.Balanced
336
+ });
337
+ const [geo] = await ExpoLocation.reverseGeocodeAsync({
338
+ latitude: location.coords.latitude,
339
+ longitude: location.coords.longitude
340
+ });
341
+ return {
342
+ lat: location.coords.latitude,
343
+ lng: location.coords.longitude,
344
+ place: formatPlace(geo),
345
+ address: formatAddress(geo),
346
+ type: classifyLocation(geo),
347
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
348
+ };
349
+ } catch (err) {
350
+ log.error("Failed to get current location", err);
351
+ throw err;
352
+ }
353
+ }
354
+ },
355
+ battery: {
356
+ async getStatus() {
357
+ try {
358
+ const [level, state, lowPower] = await Promise.all([
359
+ ExpoBattery.getBatteryLevelAsync(),
360
+ ExpoBattery.getBatteryStateAsync(),
361
+ ExpoBattery.isLowPowerModeEnabledAsync()
362
+ ]);
363
+ return {
364
+ ok: true,
365
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
366
+ battery: {
367
+ level: Math.round(level * 100),
368
+ state: mapBatteryState(state),
369
+ low_power_mode: lowPower
370
+ }
371
+ };
372
+ } catch (err) {
373
+ log.error("Failed to get battery status", err);
374
+ throw err;
375
+ }
376
+ }
377
+ },
378
+ network: {
379
+ async getStatus() {
380
+ try {
381
+ const state = await ExpoNetwork.getNetworkStateAsync();
382
+ return {
383
+ type: state.type === ExpoNetwork.NetworkStateType.WIFI ? "wifi" : state.type === ExpoNetwork.NetworkStateType.CELLULAR ? "cellular" : "none",
384
+ is_connected: state.isConnected ?? false,
385
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
386
+ };
387
+ } catch (err) {
388
+ log.error("Failed to get network status", err);
389
+ throw err;
390
+ }
391
+ }
392
+ },
393
+ notifications: {
394
+ async list() {
395
+ try {
396
+ const presented = await ExpoNotifications.getPresentedNotificationsAsync();
397
+ const notifications = presented.map(formatNotification);
398
+ return {
399
+ notifications,
400
+ total: notifications.length,
401
+ unread: notifications.filter((n) => !n.read).length
402
+ };
403
+ } catch (err) {
404
+ log.error("Failed to get notifications", err);
405
+ return { notifications: [], total: 0, unread: 0 };
406
+ }
407
+ }
408
+ },
409
+ sms: {
410
+ async isAvailable() {
411
+ try {
412
+ return await ExpoSMS.isAvailableAsync();
413
+ } catch (err) {
414
+ log.error("Failed to check SMS availability", err);
415
+ return false;
416
+ }
417
+ },
418
+ async send(phone, message) {
419
+ try {
420
+ const { result } = await ExpoSMS.sendSMSAsync([phone], message);
421
+ return {
422
+ ok: result === "sent" || result === "unknown",
423
+ status: result
424
+ };
425
+ } catch (err) {
426
+ log.error("Failed to send SMS", err);
427
+ throw err;
428
+ }
429
+ }
430
+ },
431
+ maps: {
432
+ async navigate(destination, mode = "driving") {
433
+ try {
434
+ const encoded = encodeURIComponent(destination);
435
+ const url = import_react_native.Platform.OS === "ios" ? `maps://maps.apple.com/?daddr=${encoded}&dirflg=${mode[0]}` : `google.navigation:q=${encoded}&mode=${mode}`;
436
+ const canOpen = await ExpoLinking.canOpenURL(url);
437
+ if (!canOpen) {
438
+ const fallbackUrl = `https://www.google.com/maps/search/${encoded}`;
439
+ await ExpoLinking.openURL(fallbackUrl);
440
+ } else {
441
+ await ExpoLinking.openURL(url);
442
+ }
443
+ return { ok: true, status: "navigating" };
444
+ } catch (err) {
445
+ log.error("Failed to navigate", err);
446
+ return { ok: false, status: "error" };
447
+ }
448
+ }
449
+ },
450
+ http: {
451
+ async get(url, headers = {}) {
452
+ try {
453
+ const res = await fetch(url, { headers });
454
+ const data = await res.json();
455
+ return {
456
+ ok: res.ok,
457
+ status: res.status,
458
+ data,
459
+ headers: Object.fromEntries(res.headers.entries())
460
+ };
461
+ } catch (err) {
462
+ log.error("HTTP GET failed", err);
463
+ throw err;
464
+ }
465
+ },
466
+ async post(url, body, headers = {}) {
467
+ try {
468
+ const res = await fetch(url, {
469
+ method: "POST",
470
+ headers: { "Content-Type": "application/json", ...headers },
471
+ body: JSON.stringify(body)
472
+ });
473
+ const data = await res.json();
474
+ return {
475
+ ok: res.ok,
476
+ status: res.status,
477
+ data,
478
+ headers: Object.fromEntries(res.headers.entries())
479
+ };
480
+ } catch (err) {
481
+ log.error("HTTP POST failed", err);
482
+ throw err;
483
+ }
484
+ },
485
+ async put(url, body, headers = {}) {
486
+ try {
487
+ const res = await fetch(url, {
488
+ method: "PUT",
489
+ headers: { "Content-Type": "application/json", ...headers },
490
+ body: JSON.stringify(body)
491
+ });
492
+ const data = await res.json();
493
+ return {
494
+ ok: res.ok,
495
+ status: res.status,
496
+ data,
497
+ headers: Object.fromEntries(res.headers.entries())
498
+ };
499
+ } catch (err) {
500
+ log.error("HTTP PUT failed", err);
501
+ throw err;
502
+ }
503
+ },
504
+ async delete(url, body, headers = {}) {
505
+ try {
506
+ const opts = {
507
+ method: "DELETE",
508
+ headers: { "Content-Type": "application/json", ...headers }
509
+ };
510
+ if (body) opts.body = JSON.stringify(body);
511
+ const res = await fetch(url, opts);
512
+ const data = await res.json();
513
+ return {
514
+ ok: res.ok,
515
+ status: res.status,
516
+ data,
517
+ headers: Object.fromEntries(res.headers.entries())
518
+ };
519
+ } catch (err) {
520
+ log.error("HTTP DELETE failed", err);
521
+ throw err;
522
+ }
523
+ }
524
+ },
525
+ storage: {
526
+ async get(key) {
527
+ try {
528
+ return await import_async_storage.default.getItem(storagePrefix + key);
529
+ } catch (err) {
530
+ log.error(`Failed to get storage key: ${key}`, err);
531
+ return null;
532
+ }
533
+ },
534
+ async set(key, value) {
535
+ try {
536
+ await import_async_storage.default.setItem(storagePrefix + key, value);
537
+ } catch (err) {
538
+ log.error(`Failed to set storage key: ${key}`, err);
539
+ }
540
+ },
541
+ async delete(key) {
542
+ try {
543
+ await import_async_storage.default.removeItem(storagePrefix + key);
544
+ } catch (err) {
545
+ log.error(`Failed to delete storage key: ${key}`, err);
546
+ }
547
+ },
548
+ async keys() {
549
+ try {
550
+ const allKeys = await import_async_storage.default.getAllKeys();
551
+ return allKeys.filter((k) => k.startsWith(storagePrefix)).map((k) => k.slice(storagePrefix.length));
552
+ } catch (err) {
553
+ log.error("Failed to list storage keys", err);
554
+ return [];
555
+ }
556
+ }
557
+ },
558
+ permissions: {
559
+ async check(capability) {
560
+ try {
561
+ switch (capability) {
562
+ case "calendar":
563
+ const cal = await ExpoCalendar.getCalendarPermissionsAsync();
564
+ return cal.status === "granted" ? "granted" : cal.status === "denied" ? "denied" : "not_requested";
565
+ case "contacts":
566
+ const con = await ExpoContacts.getPermissionsAsync();
567
+ return con.status === "granted" ? "granted" : con.status === "denied" ? "denied" : "not_requested";
568
+ case "location":
569
+ const loc = await ExpoLocation.getForegroundPermissionsAsync();
570
+ return loc.status === "granted" ? "granted" : loc.status === "denied" ? "denied" : "not_requested";
571
+ case "notifications":
572
+ const notif = await ExpoNotifications.getPermissionsAsync();
573
+ return notif.granted ? "granted" : notif.canAskAgain ? "not_requested" : "denied";
574
+ default:
575
+ return "not_requested";
576
+ }
577
+ } catch (err) {
578
+ log.error(`Failed to check permission: ${capability}`, err);
579
+ return "denied";
580
+ }
581
+ },
582
+ async request(capability) {
583
+ try {
584
+ switch (capability) {
585
+ case "calendar":
586
+ const cal = await ExpoCalendar.requestCalendarPermissionsAsync();
587
+ return cal.status === "granted";
588
+ case "contacts":
589
+ const con = await ExpoContacts.requestPermissionsAsync();
590
+ return con.status === "granted";
591
+ case "location":
592
+ const loc = await ExpoLocation.requestForegroundPermissionsAsync();
593
+ return loc.status === "granted";
594
+ case "notifications":
595
+ const notif = await ExpoNotifications.requestPermissionsAsync();
596
+ return notif.granted;
597
+ default:
598
+ return false;
599
+ }
600
+ } catch (err) {
601
+ log.error(`Failed to request permission: ${capability}`, err);
602
+ return false;
603
+ }
604
+ },
605
+ async getAll() {
606
+ try {
607
+ const [cal, con, loc, notif] = await Promise.allSettled([
608
+ ExpoCalendar.getCalendarPermissionsAsync(),
609
+ ExpoContacts.getPermissionsAsync(),
610
+ ExpoLocation.getForegroundPermissionsAsync(),
611
+ ExpoNotifications.getPermissionsAsync()
612
+ ]);
613
+ return {
614
+ calendar: cal.status === "fulfilled" ? cal.value.status === "granted" ? "granted" : cal.value.status === "denied" ? "denied" : "not_requested" : "denied",
615
+ contacts: con.status === "fulfilled" ? con.value.status === "granted" ? "granted" : con.value.status === "denied" ? "denied" : "not_requested" : "denied",
616
+ location: loc.status === "fulfilled" ? loc.value.status === "granted" ? "granted" : loc.value.status === "denied" ? "denied" : "not_requested" : "denied",
617
+ notifications: notif.status === "fulfilled" ? notif.value.granted ? "granted" : notif.value.canAskAgain ? "not_requested" : "denied" : "denied"
618
+ };
619
+ } catch (err) {
620
+ log.error("Failed to get all permissions", err);
621
+ return { calendar: "denied", contacts: "denied", location: "denied", notifications: "denied" };
622
+ }
623
+ }
624
+ },
625
+ device: {
626
+ getDeviceId() {
627
+ return deviceId;
628
+ },
629
+ getPlatform() {
630
+ return {
631
+ os: import_react_native.Platform.OS,
632
+ version: import_react_native.Platform.Version ? String(import_react_native.Platform.Version) : "unknown"
633
+ };
634
+ }
635
+ },
636
+ log
637
+ };
638
+ return bridge;
639
+ }
640
+ // Annotate the CommonJS export names for ESM import in node:
641
+ 0 && (module.exports = {
642
+ createBridge
643
+ });
644
+ //# sourceMappingURL=createBridge.js.map