@absolutejs/absolute 0.20.0-beta.44 → 0.20.0-beta.45

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.
@@ -307,7 +307,7 @@ var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-
307
307
  // src/mobile/nativeAuth.ts
308
308
  import { readFileSync as readFileSync2 } from "fs";
309
309
  import { join as join11 } from "path";
310
- var ABSOLUTE_AUTH_PACKAGE = "@absolutejs/auth", ABSOLUTE_EXPO_AUTH_CORE_VERSION = "0.75.6", ABSOLUTE_EXPO_AUTH_PACKAGE = "@absolutejs/auth-expo", ABSOLUTE_EXPO_AUTH_VERSION = "0.0.2", ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV = "ABSOLUTE_AUTH_NATIVE_CLIENTS", ABSOLUTE_NATIVE_AUTH_SCOPES, ABSOLUTE_SYNC_PACKAGE = "@absolutejs/sync", readPackageManifest = (projectRoot) => {
310
+ var ABSOLUTE_AUTH_PACKAGE = "@absolutejs/auth", ABSOLUTE_EXPO_AUTH_CORE_VERSION = "0.75.6", ABSOLUTE_EXPO_AUTH_PACKAGE = "@absolutejs/auth-expo", ABSOLUTE_EXPO_AUTH_VERSION = "0.0.2", ABSOLUTE_EXPO_SYNC_CORE_VERSION = "2.31.0", ABSOLUTE_EXPO_SYNC_PACKAGE = "@absolutejs/sync-expo", ABSOLUTE_EXPO_SYNC_VERSION = "0.0.2", ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV = "ABSOLUTE_AUTH_NATIVE_CLIENTS", ABSOLUTE_NATIVE_AUTH_SCOPES, ABSOLUTE_SYNC_PACKAGE = "@absolutejs/sync", readPackageManifest = (projectRoot) => {
311
311
  try {
312
312
  return JSON.parse(readFileSync2(join11(projectRoot, "package.json"), "utf8"));
313
313
  } catch {
@@ -349,7 +349,7 @@ var init_nativeAuth = __esm(() => {
349
349
  });
350
350
 
351
351
  // node_modules/@absolutejs/sync/dist/client/index.js
352
- var RUNTIME_TRANSPORT, host, isRegistry = (value) => typeof value === "object" && value !== null && Array.isArray(Reflect.get(value, "installations")) && Array.isArray(Reflect.get(value, "clients")), registry, SyncLocalDataPolicyError, SyncLocalStoreSchemaError, positiveVersion = (value, label) => {
352
+ var RUNTIME_TRANSPORT, host, isRegistry = (value) => typeof value === "object" && value !== null && Array.isArray(Reflect.get(value, "installations")) && Array.isArray(Reflect.get(value, "clients")), registry, pools, SyncLocalDataPolicyError, SyncLocalStoreSchemaError, positiveVersion = (value, label) => {
353
353
  if (!Number.isSafeInteger(value) || value < 1)
354
354
  throw new SyncLocalStoreSchemaError("INVALID_PLAN", `${label} must be a positive safe integer`);
355
355
  return value;
@@ -454,6 +454,7 @@ var init_client = __esm(() => {
454
454
  });
455
455
  return created;
456
456
  })();
457
+ pools = new Map;
457
458
  SyncLocalDataPolicyError = class SyncLocalDataPolicyError extends Error {
458
459
  code;
459
460
  constructor(code, message) {
@@ -5615,6 +5616,12 @@ var shellSyncModule = () => {
5615
5616
  return candidate;
5616
5617
  throw new TypeError("AbsoluteJS mobile Sync shell module is missing.");
5617
5618
  };
5619
+ var shellExpoSyncModule = () => {
5620
+ const candidate = ["js", "ts"].map((extension) => join9(import.meta.dir, `shellExpoSync.${extension}`)).find(existsSync2);
5621
+ if (candidate)
5622
+ return candidate;
5623
+ throw new TypeError("AbsoluteJS Expo Sync bridge module is missing.");
5624
+ };
5618
5625
  var shellPushModule = () => {
5619
5626
  const candidate = ["js", "ts"].map((extension) => join9(import.meta.dir, `shellPush.${extension}`)).find(existsSync2);
5620
5627
  if (candidate)
@@ -5692,10 +5699,11 @@ var buildShellBootstrap = async (staging, auth, sync, storagePrefix, engine, dev
5692
5699
  const shellCapabilities = capacitor ? deviceCapabilities.capabilities : [];
5693
5700
  const modulePath = shellBootstrapModule();
5694
5701
  const authFactory = capacitor ? "createAbsoluteMobileShellAuth" : "createAbsoluteExpoShellAuth";
5702
+ const syncFactory = capacitor ? "installAbsoluteMobileShellSync" : "installAbsoluteExpoShellSync";
5695
5703
  const authImport = auth ? `import { ${authFactory} } from ${JSON.stringify(capacitor ? shellAuthModule() : shellExpoAuthModule())};
5696
5704
  ` : "";
5697
- const options = auth ? `{ createAuth: ${authFactory}${sync ? ", installSync: installAbsoluteMobileShellSync" : ""} }` : "";
5698
- const syncImport = sync ? `import { installAbsoluteMobileShellSync } from ${JSON.stringify(shellSyncModule())};
5705
+ const options = auth ? `{ createAuth: ${authFactory}${sync ? `, installSync: ${syncFactory}` : ""} }` : "";
5706
+ const syncImport = sync ? `import { ${syncFactory} } from ${JSON.stringify(capacitor ? shellSyncModule() : shellExpoSyncModule())};
5699
5707
  ` : "";
5700
5708
  const pushIndex = shellCapabilities.indexOf("pushNotifications");
5701
5709
  const push = pushIndex !== -1;
@@ -5720,7 +5728,7 @@ const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absolu
5720
5728
  if (capacitor)
5721
5729
  shellOptions = options;
5722
5730
  if (push) {
5723
- shellOptions = `{ createAuth: (config, options) => createAbsoluteMobileShellAuth(config, options), beforeSignOut: absoluteMobilePush.beforeSignOut, connectPush: (auth) => absoluteMobilePush.connect(auth, absoluteMobilePushCapability)${sync ? ", installSync: installAbsoluteMobileShellSync" : ""} }`;
5731
+ shellOptions = `{ createAuth: (config, options) => createAbsoluteMobileShellAuth(config, options), beforeSignOut: absoluteMobilePush.beforeSignOut, connectPush: (auth) => absoluteMobilePush.connect(auth, absoluteMobilePushCapability)${sync ? `, installSync: ${syncFactory}` : ""} }`;
5724
5732
  }
5725
5733
  await writeFile10(entryPath, `import { startAbsoluteMobileShell } from ${JSON.stringify(modulePath)};
5726
5734
  ${adapterImport}
@@ -6087,6 +6095,7 @@ init_deviceCapabilities();
6087
6095
 
6088
6096
  // src/mobile/expoProject.ts
6089
6097
  init_nativeAuth();
6098
+ init_syncSchema();
6090
6099
  import {
6091
6100
  access as access9,
6092
6101
  cp as cp2,
@@ -6125,12 +6134,16 @@ var routeSegments = (route) => route.split("/").filter(Boolean).map((segment) =>
6125
6134
  return segment;
6126
6135
  });
6127
6136
  var routeFile = (project, route) => join14(project, "app", ...routeSegments(route), "index.tsx");
6128
- var expoPackage = (auth) => ({
6137
+ var expoPackage = (auth, sync) => ({
6129
6138
  dependencies: {
6130
6139
  ...auth ? {
6131
6140
  "@absolutejs/auth": ABSOLUTE_EXPO_AUTH_CORE_VERSION,
6132
6141
  [ABSOLUTE_EXPO_AUTH_PACKAGE]: ABSOLUTE_EXPO_AUTH_VERSION
6133
6142
  } : {},
6143
+ ...sync ? {
6144
+ "@absolutejs/sync": ABSOLUTE_EXPO_SYNC_CORE_VERSION,
6145
+ [ABSOLUTE_EXPO_SYNC_PACKAGE]: ABSOLUTE_EXPO_SYNC_VERSION
6146
+ } : {},
6134
6147
  expo: "~57.0.9",
6135
6148
  "expo-asset": "~57.0.15",
6136
6149
  "expo-constants": "~57.0.16",
@@ -6138,6 +6151,13 @@ var expoPackage = (auth) => ({
6138
6151
  "expo-file-system": "~57.0.6",
6139
6152
  "expo-haptics": "~57.0.2",
6140
6153
  "expo-linking": "~57.0.8",
6154
+ ...sync ? {
6155
+ "expo-background-task": "~57.0.14",
6156
+ "expo-network": "~57.0.1",
6157
+ "expo-sqlite": "~57.0.2",
6158
+ "expo-task-manager": "~57.0.14",
6159
+ "expo-updates": "~57.0.19"
6160
+ } : {},
6141
6161
  "expo-router": "~57.0.17",
6142
6162
  ...auth ? {
6143
6163
  "expo-secure-store": "~57.0.2",
@@ -6163,7 +6183,7 @@ var expoPackage = (auth) => ({
6163
6183
  },
6164
6184
  version: "0.0.0"
6165
6185
  });
6166
- var expoAppConfig = (config, auth) => ({
6186
+ var expoAppConfig = (config, auth, sync) => ({
6167
6187
  expo: {
6168
6188
  android: {
6169
6189
  intentFilters: config.deepLinkHosts.map((host2) => ({
@@ -6184,7 +6204,8 @@ var expoAppConfig = (config, auth) => ({
6184
6204
  plugins: [
6185
6205
  "expo-router",
6186
6206
  ["expo-dev-client", { launchMode: "most-recent" }],
6187
- ...auth ? ["expo-secure-store"] : []
6207
+ ...auth ? ["expo-secure-store"] : [],
6208
+ ...sync ? ["expo-sqlite", "expo-background-task", "expo-task-manager"] : []
6188
6209
  ],
6189
6210
  runtimeVersion: { policy: "appVersion" },
6190
6211
  scheme: config.deepLinkScheme,
@@ -6258,14 +6279,19 @@ config.watchFolders = [appRoot];
6258
6279
 
6259
6280
  module.exports = config;
6260
6281
  `;
6261
- var layoutSource = (auth) => `${EXPO_GENERATED_HEADER}import { Stack } from 'expo-router';
6262
- ${auth ? `import { useEffect } from 'react';
6282
+ var layoutSource = (auth, sync) => `${EXPO_GENERATED_HEADER}import { Stack } from 'expo-router';
6283
+ ${auth ? `import { useEffect, useState } from 'react';
6263
6284
  import { startAbsoluteExpoAuth } from '../src/generated/AbsoluteAuth';` : ""}
6285
+ ${sync ? "import { startAbsoluteExpoSync } from '../src/generated/AbsoluteSync';" : ""}
6264
6286
 
6265
6287
  export default function AbsoluteLayout() {
6266
- ${auth ? `useEffect(() => {
6267
- void startAbsoluteExpoAuth();
6268
- }, []);` : ""}
6288
+ ${auth ? `const [ready, setReady] = useState(false);
6289
+ useEffect(() => {
6290
+ let active = true;
6291
+ void ${sync ? "startAbsoluteExpoSync" : "startAbsoluteExpoAuth"}().then(() => { if (active) setReady(true); });
6292
+ return () => { active = false; };
6293
+ }, []);
6294
+ if (!ready) return null;` : ""}
6269
6295
  return <Stack screenOptions={{ headerShown: false }} />;
6270
6296
  }
6271
6297
  `;
@@ -6325,14 +6351,112 @@ export const getAbsoluteExpoAuthPrincipal = () => currentPrincipal;
6325
6351
  let startPromise: Promise<void> | undefined;
6326
6352
  export const startAbsoluteExpoAuth = () => {
6327
6353
  startPromise ??= absoluteExpoAuth.start().then(async () => {
6328
- await absoluteExpoAuth.principal();
6354
+ currentPrincipal = await absoluteExpoAuth.principal();
6329
6355
  });
6330
6356
 
6331
6357
  return startPromise;
6332
6358
  };
6333
6359
  `;
6334
6360
  };
6335
- var webHostSource = (config, auth) => {
6361
+ var syncRuntimeSource = (config, schema) => {
6362
+ const storageIdentity = createHash10("sha256").update(config.appId).digest("hex").slice(0, 24);
6363
+ const backgroundEndpoint = new URL("/__absolute/sync/background", config.productionOrigin).href;
6364
+ const backgroundTask = `${config.appId}.absolutejs.sync`;
6365
+ return `${EXPO_GENERATED_HEADER}import { runHeadlessSync } from '@absolutejs/sync/client/headless';
6366
+ import type { SyncLocalStoreSchemaBundle } from '@absolutejs/sync/client';
6367
+ import { installSyncClientRuntimeTransport } from '@absolutejs/sync/client/runtime';
6368
+ import {
6369
+ createExpoSyncBridgeHost,
6370
+ createExpoSyncLocalStore,
6371
+ createExpoSyncProtection,
6372
+ createExpoSyncSocketBridgeHost,
6373
+ defineExpoSyncBackgroundTask,
6374
+ installExpoSyncLifecycle,
6375
+ registerExpoSyncBackgroundTask
6376
+ } from '@absolutejs/sync-expo';
6377
+ import * as Updates from 'expo-updates';
6378
+ import { absoluteExpoAuth, startAbsoluteExpoAuth } from './AbsoluteAuth';
6379
+
6380
+ const BACKGROUND_TASK = ${JSON.stringify(backgroundTask)};
6381
+ const BACKGROUND_ENDPOINT = ${JSON.stringify(backgroundEndpoint)};
6382
+ const PRODUCTION_ORIGIN = ${JSON.stringify(config.productionOrigin)};
6383
+ const STORAGE_SCHEMA: SyncLocalStoreSchemaBundle = ${JSON.stringify(schema)};
6384
+ const store = createExpoSyncLocalStore({
6385
+ databaseName: ${JSON.stringify(`absolutejs-sync-${storageIdentity}.db`)},
6386
+ protection: createExpoSyncProtection({ storagePrefix: ${JSON.stringify(`absolutejs.sync.${storageIdentity}`)} }),
6387
+ storageSchema: STORAGE_SCHEMA
6388
+ });
6389
+
6390
+ const runBackgroundSync = async () => {
6391
+ await startAbsoluteExpoAuth();
6392
+ const principal = await absoluteExpoAuth.principal();
6393
+ if (!principal) return;
6394
+ await runHeadlessSync({
6395
+ endpoint: BACKGROUND_ENDPOINT,
6396
+ fetch: (url, init) => absoluteExpoAuth.fetch(url, init),
6397
+ namespace: principal.namespace,
6398
+ store
6399
+ });
6400
+ };
6401
+ defineExpoSyncBackgroundTask(BACKGROUND_TASK, runBackgroundSync);
6402
+
6403
+ let activeNamespace: string | undefined;
6404
+ let started = false;
6405
+ let startPromise: Promise<void> | undefined;
6406
+ export const startAbsoluteExpoSync = () => {
6407
+ startPromise ??= (async () => {
6408
+ await startAbsoluteExpoAuth();
6409
+ const principal = await absoluteExpoAuth.principal();
6410
+ activeNamespace = principal?.namespace;
6411
+ installSyncClientRuntimeTransport({
6412
+ ...(principal ? { durable: { namespace: principal.namespace, store }, socketTicket: () => absoluteExpoAuth.socketTicket() } : {}),
6413
+ registerClient: client => installExpoSyncLifecycle({ client })
6414
+ });
6415
+ await registerExpoSyncBackgroundTask(BACKGROUND_TASK, { minimumInterval: 15 });
6416
+ started = true;
6417
+ })();
6418
+
6419
+ return startPromise;
6420
+ };
6421
+
6422
+ absoluteExpoAuth.onPrincipalChange(principal => {
6423
+ if (!started || principal?.namespace === activeNamespace) return;
6424
+ void Updates.reloadAsync();
6425
+ });
6426
+
6427
+ export const createAbsoluteExpoSyncBridge = async (
6428
+ emit: (event: 'sync.socket' | 'sync.wake', payload: Record<string, unknown>) => void
6429
+ ) => {
6430
+ await startAbsoluteExpoSync();
6431
+ const principal = await absoluteExpoAuth.principal();
6432
+ if (!principal) return {
6433
+ close: () => undefined,
6434
+ request: async () => { throw new Error('Expo Sync requires an authenticated principal.'); }
6435
+ };
6436
+ const transactions = createExpoSyncBridgeHost({ namespace: principal.namespace, store });
6437
+ const sockets = createExpoSyncSocketBridgeHost({
6438
+ allowedOrigin: PRODUCTION_ORIGIN,
6439
+ emit: payload => emit('sync.socket', payload),
6440
+ socketTicket: audience => absoluteExpoAuth.socketTicket(audience)
6441
+ });
6442
+ const removeLifecycle = installExpoSyncLifecycle({
6443
+ client: { reconnect: () => emit('sync.wake', {}) }
6444
+ });
6445
+
6446
+ return {
6447
+ close: async () => {
6448
+ removeLifecycle();
6449
+ await Promise.all([transactions.close(), sockets.close()]);
6450
+ },
6451
+ request: (method: string, params: Record<string, unknown>) =>
6452
+ method.startsWith('sync.socket.')
6453
+ ? sockets.request(method, params)
6454
+ : transactions.request(method, params)
6455
+ };
6456
+ };
6457
+ `;
6458
+ };
6459
+ var webHostSource = (config, auth, sync) => {
6336
6460
  const nativeRoutes = [
6337
6461
  "/__absolute/native",
6338
6462
  ...Object.keys(config.expoNativeRoutes)
@@ -6345,8 +6469,9 @@ import { ActivityIndicator, BackHandler, Platform, StyleSheet, View } from 'reac
6345
6469
  import { WebView, type WebViewMessageEvent } from 'react-native-webview';
6346
6470
  import { materializeAbsoluteWebBundle } from './webAssets';
6347
6471
  ${auth ? "import { absoluteExpoAuth, getAbsoluteExpoAuthPrincipal, startAbsoluteExpoAuth } from './AbsoluteAuth';" : ""}
6472
+ ${sync ? "import { createAbsoluteExpoSyncBridge, startAbsoluteExpoSync } from './AbsoluteSync';" : ""}
6348
6473
 
6349
- const BRIDGE_FORMAT = 2;
6474
+ const BRIDGE_FORMAT = 3;
6350
6475
  const MAX_MESSAGE_BYTES = 64 * 1024;
6351
6476
  const MAX_HTTP_BODY_BYTES = 48 * 1024;
6352
6477
  const NATIVE_ROUTES = new Set(${JSON.stringify(nativeRoutes)});
@@ -6356,6 +6481,7 @@ const DEV_ORIGIN = Platform.OS === 'android'
6356
6481
  : process.env.EXPO_PUBLIC_ABSOLUTE_DEV_IOS_ORIGIN;
6357
6482
  const HMR_TARGET = Platform.OS === 'android' ? 'expo-android' : 'expo-ios';
6358
6483
  const AUTH_ENABLED = ${auth ? "true" : "false"};
6484
+ const SYNC_ENABLED = ${sync ? "true" : "false"};
6359
6485
 
6360
6486
  const bridgeBootstrap = (path: string) => {
6361
6487
  const initialPath = DEV_ORIGIN
@@ -6395,7 +6521,7 @@ const bridgeBootstrap = (path: string) => {
6395
6521
  },
6396
6522
  request(method, params) {
6397
6523
  const id = 'web_' + Date.now().toString(36) + '_' + (++sequence).toString(36);
6398
- send({ format: 2, id, kind: 'request', method, params, path: currentPath });
6524
+ send({ format: 3, id, kind: 'request', method, params, path: currentPath });
6399
6525
  return new Promise((resolve, reject) => {
6400
6526
  const timer = setTimeout(() => {
6401
6527
  pending.delete(id);
@@ -6406,7 +6532,7 @@ const bridgeBootstrap = (path: string) => {
6406
6532
  },
6407
6533
  setPath(path) {
6408
6534
  currentPath = path;
6409
- send({ format: 2, kind: 'event', event: 'navigation', path });
6535
+ send({ format: 3, kind: 'event', event: 'navigation', path });
6410
6536
  }
6411
6537
  };
6412
6538
  if (\${DEV_ORIGIN ? 'true' : 'false'}) {
@@ -6414,7 +6540,7 @@ const bridgeBootstrap = (path: string) => {
6414
6540
  const path = location.pathname + location.search + location.hash;
6415
6541
  if (path === currentPath) return;
6416
6542
  currentPath = path;
6417
- send({ format: 2, kind: 'event', event: 'navigation', path });
6543
+ send({ format: 3, kind: 'event', event: 'navigation', path });
6418
6544
  };
6419
6545
  for (const method of ['pushState', 'replaceState']) {
6420
6546
  const original = history[method];
@@ -6433,9 +6559,9 @@ const bridgeBootstrap = (path: string) => {
6433
6559
  const url = new URL(anchor.href, location.href);
6434
6560
  if (!${JSON.stringify(nativeRoutes)}.includes(url.pathname)) return;
6435
6561
  event.preventDefault();
6436
- send({ format: 2, kind: 'event', event: 'navigation', path: url.pathname + url.search + url.hash });
6562
+ send({ format: 3, kind: 'event', event: 'navigation', path: url.pathname + url.search + url.hash });
6437
6563
  }, true);
6438
- send({ format: 2, kind: 'event', event: 'ready', path: currentPath });
6564
+ send({ format: 3, kind: 'event', event: 'ready', path: currentPath });
6439
6565
  })(); true;\`;
6440
6566
  };
6441
6567
 
@@ -6481,21 +6607,34 @@ const authStatus = async () => {
6481
6607
  export function AbsoluteWebHost() {
6482
6608
  const pathname = usePathname() || '/';
6483
6609
  const webView = useRef<WebView>(null);
6610
+ const syncBridge = useRef<{ close(): void | Promise<void>; request(method: string, params: Record<string, unknown>): Promise<unknown> } | undefined>(undefined);
6484
6611
  const [indexUri, setIndexUri] = useState<string>();
6485
6612
  const [canGoBack, setCanGoBack] = useState(false);
6486
- const [authReady, setAuthReady] = useState(!AUTH_ENABLED);
6613
+ const [runtimeReady, setRuntimeReady] = useState(!AUTH_ENABLED && !SYNC_ENABLED);
6487
6614
  const activeWebPath = useRef(pathname);
6488
6615
 
6489
6616
  useEffect(() => {
6490
- if (!AUTH_ENABLED) return;
6617
+ if (!AUTH_ENABLED && !SYNC_ENABLED) return;
6491
6618
  let active = true;
6492
6619
  ${auth ? `const stop = absoluteExpoAuth.onPrincipalChange(principal => {
6493
6620
  if (!active) return;
6494
6621
  const source = JSON.stringify({ event: 'auth.principal', format: BRIDGE_FORMAT, kind: 'event', path: activeWebPath.current, payload: { principal: principal ? { namespace: principal.namespace } : null } });
6495
6622
  webView.current?.injectJavaScript(\`globalThis.__absoluteExpoReceive(\${JSON.stringify(source)}); true;\`);
6496
6623
  });
6497
- void startAbsoluteExpoAuth().then(() => { if (active) setAuthReady(true); });
6498
- return () => { active = false; stop(); };` : ""}
6624
+ void ${sync ? "startAbsoluteExpoSync" : "startAbsoluteExpoAuth"}().then(async () => {
6625
+ ${sync ? `syncBridge.current = await createAbsoluteExpoSyncBridge((event, payload) => {
6626
+ const source = JSON.stringify({ event, format: BRIDGE_FORMAT, kind: 'event', path: activeWebPath.current, payload });
6627
+ webView.current?.injectJavaScript(\`globalThis.__absoluteExpoReceive(\${JSON.stringify(source)}); true;\`);
6628
+ });` : ""}
6629
+ if (active) setRuntimeReady(true);
6630
+ });
6631
+ return () => {
6632
+ active = false;
6633
+ stop();
6634
+ const bridge = syncBridge.current;
6635
+ syncBridge.current = undefined;
6636
+ void bridge?.close();
6637
+ };` : ""}
6499
6638
  }, []);
6500
6639
 
6501
6640
  useEffect(() => {
@@ -6557,6 +6696,9 @@ export function AbsoluteWebHost() {
6557
6696
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: null });` : "throw new Error('Expo Auth is not configured.');"}
6558
6697
  } else if (message.method === 'auth.status') {
6559
6698
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await authStatus() });
6699
+ } else if (typeof message.method === 'string' && message.method.startsWith('sync.')) {
6700
+ if (!syncBridge.current) throw new Error('Expo Sync bridge is unavailable.');
6701
+ respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await syncBridge.current.request(message.method, message.params as Record<string, unknown>) });
6560
6702
  } else {
6561
6703
  throw new Error('Expo bridge method is not allowed.');
6562
6704
  }
@@ -6565,7 +6707,7 @@ export function AbsoluteWebHost() {
6565
6707
  }
6566
6708
  };
6567
6709
 
6568
- if (!indexUri || !authReady) return <View style={styles.loading}><ActivityIndicator /></View>;
6710
+ if (!indexUri || !runtimeReady) return <View style={styles.loading}><ActivityIndicator /></View>;
6569
6711
  return <WebView
6570
6712
  allowFileAccess
6571
6713
  allowFileAccessFromFileURLs
@@ -6598,7 +6740,7 @@ export default AbsoluteWebHost;
6598
6740
  `;
6599
6741
  var nativeWrapperSource = (wrapper, module) => `${EXPO_GENERATED_HEADER}export { default } from ${JSON.stringify(portableRelative2(dirname10(wrapper), module).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
6600
6742
  `;
6601
- var expoTsConfig = (projectRoot, project, auth) => ({
6743
+ var expoTsConfig = (projectRoot, project, auth, sync) => ({
6602
6744
  compilerOptions: {
6603
6745
  paths: {
6604
6746
  ...auth ? {
@@ -6609,6 +6751,20 @@ var expoTsConfig = (projectRoot, project, auth) => ({
6609
6751
  "./node_modules/@absolutejs/auth/dist/*"
6610
6752
  ]
6611
6753
  } : {},
6754
+ ...sync ? {
6755
+ "@absolutejs/sync": [
6756
+ "./node_modules/@absolutejs/sync/dist/index.d.ts"
6757
+ ],
6758
+ "@absolutejs/sync-expo": [
6759
+ "./node_modules/@absolutejs/sync-expo/dist/index.d.ts"
6760
+ ],
6761
+ "@absolutejs/sync-expo/*": [
6762
+ "./node_modules/@absolutejs/sync-expo/dist/*"
6763
+ ],
6764
+ "@absolutejs/sync/*": [
6765
+ "./node_modules/@absolutejs/sync/dist/*"
6766
+ ]
6767
+ } : {},
6612
6768
  "*": [
6613
6769
  "./node_modules/*",
6614
6770
  `${portableRelative2(project, projectRoot)}/node_modules/*`
@@ -6647,6 +6803,8 @@ var writeAbsoluteExpoProject = async (config, options) => {
6647
6803
  const projectRoot = resolve12(options.projectRoot);
6648
6804
  const project = config.nativeProjectDirectory;
6649
6805
  const auth = resolveAbsoluteMobileAuthManifest(projectRoot, config);
6806
+ const syncEnabled = Boolean(auth && projectUsesAbsoluteSync(projectRoot));
6807
+ const syncSchema = syncEnabled ? { components: discoverAbsoluteSyncSchema(projectRoot).components } : undefined;
6650
6808
  const routeModules = Object.entries(config.expoNativeRoutes);
6651
6809
  const moduleChecks = await Promise.all(routeModules.map(async ([route, module]) => ({
6652
6810
  exists: await exists3(module),
@@ -6679,10 +6837,13 @@ node_modules/
6679
6837
  ],
6680
6838
  [
6681
6839
  join14(project, "app.json"),
6682
- jsonSource(expoAppConfig(config, authEnabled))
6840
+ jsonSource(expoAppConfig(config, authEnabled, syncEnabled))
6683
6841
  ],
6684
6842
  [join14(project, "app.config.js"), expoDynamicAppConfig],
6685
- [join14(project, "package.json"), jsonSource(expoPackage(authEnabled))],
6843
+ [
6844
+ join14(project, "package.json"),
6845
+ jsonSource(expoPackage(authEnabled, syncEnabled))
6846
+ ],
6686
6847
  [join14(project, "metro.config.js"), metroConfig(projectRoot)],
6687
6848
  [
6688
6849
  join14(project, "plugins", "withAbsoluteDevelopmentCa.js"),
@@ -6690,21 +6851,27 @@ node_modules/
6690
6851
  ],
6691
6852
  [
6692
6853
  join14(project, "tsconfig.json"),
6693
- jsonSource(expoTsConfig(projectRoot, project, authEnabled))
6854
+ jsonSource(expoTsConfig(projectRoot, project, authEnabled, syncEnabled))
6855
+ ],
6856
+ [
6857
+ join14(project, "app", "_layout.tsx"),
6858
+ layoutSource(authEnabled, syncEnabled)
6694
6859
  ],
6695
- [join14(project, "app", "_layout.tsx"), layoutSource(authEnabled)],
6696
6860
  [
6697
6861
  join14(project, "app", "__absolute", "native", "index.tsx"),
6698
6862
  nativeDiagnosticSource
6699
6863
  ],
6700
6864
  [
6701
6865
  join14(project, "src", "generated", "AbsoluteWebHost.tsx"),
6702
- webHostSource(config, auth)
6866
+ webHostSource(config, auth, syncEnabled)
6703
6867
  ]
6704
6868
  ]);
6705
6869
  if (auth) {
6706
6870
  files.set(join14(project, "src", "generated", "AbsoluteAuth.ts"), authRuntimeSource(auth, config.appId));
6707
6871
  }
6872
+ if (syncSchema) {
6873
+ files.set(join14(project, "src", "generated", "AbsoluteSync.ts"), syncRuntimeSource(config, syncSchema));
6874
+ }
6708
6875
  const webAssetsPath = join14(project, "src", "generated", "webAssets.ts");
6709
6876
  if (!await exists3(webAssetsPath)) {
6710
6877
  files.set(webAssetsPath, emptyWebAssetsSource);
@@ -6904,9 +7071,6 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
6904
7071
  });
6905
7072
  const auth = resolveAbsoluteMobileAuthManifest(options.projectRoot, mobile);
6906
7073
  const sync = auth !== undefined && projectUsesAbsoluteSync(options.projectRoot);
6907
- if (mobile.engine === "expo" && sync) {
6908
- throw new TypeError("Expo mobile Sync is not released yet. Auth and authenticated HTTP are available, but @absolutejs/sync requires @absolutejs/sync-expo for shared durable state.");
6909
- }
6910
7074
  const syncSchema = sync ? discoverAbsoluteSyncSchema(options.projectRoot) : undefined;
6911
7075
  const deviceCapabilities = resolveAbsoluteDeviceCapabilityPlan(options.projectRoot);
6912
7076
  const usesPush = deviceCapabilities.capabilities.includes("pushNotifications");
@@ -7067,14 +7231,31 @@ var installAbsoluteMobileSyncRemediation = (bridge = {
7067
7231
  init_deviceCapabilities();
7068
7232
 
7069
7233
  // src/mobile/expoBridge.ts
7070
- var ABSOLUTE_EXPO_BRIDGE_FORMAT = 2;
7234
+ var ABSOLUTE_EXPO_BRIDGE_FORMAT = 3;
7071
7235
  var ABSOLUTE_EXPO_BRIDGE_MAX_BYTES = 64 * 1024;
7072
7236
  var ABSOLUTE_EXPO_BRIDGE_METHODS = [
7073
7237
  "devices.haptics.impact",
7074
7238
  "http.fetch",
7075
7239
  "auth.signIn",
7076
7240
  "auth.signOut",
7077
- "auth.status"
7241
+ "auth.status",
7242
+ "sync.store.begin",
7243
+ "sync.store.deleteNamespace",
7244
+ "sync.store.end",
7245
+ "sync.store.schema",
7246
+ "sync.tx.deleteCollection",
7247
+ "sync.tx.deleteMutation",
7248
+ "sync.tx.getCollection",
7249
+ "sync.tx.getInstallationId",
7250
+ "sync.tx.getMutation",
7251
+ "sync.tx.listCollections",
7252
+ "sync.tx.listMutations",
7253
+ "sync.tx.putCollection",
7254
+ "sync.tx.putMutation",
7255
+ "sync.tx.setInstallationId",
7256
+ "sync.socket.close",
7257
+ "sync.socket.open",
7258
+ "sync.socket.sendChunk"
7078
7259
  ];
7079
7260
  var isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
7080
7261
  var validId = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,80}$/u.test(value);
@@ -7173,7 +7354,7 @@ var parseResponse = (value) => {
7173
7354
  };
7174
7355
  };
7175
7356
  var parseEvent = (value) => {
7176
- if (value.event !== "ready" && value.event !== "navigation" && value.event !== "auth.principal") {
7357
+ if (value.event !== "ready" && value.event !== "navigation" && value.event !== "auth.principal" && value.event !== "sync.socket" && value.event !== "sync.wake") {
7177
7358
  throw new TypeError("Expo bridge event is not allowed.");
7178
7359
  }
7179
7360
  if (typeof value.path !== "string" || !validPath(value.path))
@@ -9634,6 +9815,9 @@ export {
9634
9815
  ABSOLUTE_EXPO_BRIDGE_FORMAT,
9635
9816
  ABSOLUTE_EXPO_BRIDGE_MAX_BYTES,
9636
9817
  ABSOLUTE_EXPO_BRIDGE_METHODS,
9818
+ ABSOLUTE_EXPO_SYNC_CORE_VERSION,
9819
+ ABSOLUTE_EXPO_SYNC_PACKAGE,
9820
+ ABSOLUTE_EXPO_SYNC_VERSION,
9637
9821
  ABSOLUTE_IOS_RELEASE_FORMAT,
9638
9822
  ABSOLUTE_IOS_SIMULATOR_NAME,
9639
9823
  ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT,
@@ -9781,5 +9965,5 @@ export {
9781
9965
  writeAbsoluteMobileGithubWorkflow
9782
9966
  };
9783
9967
 
9784
- //# debugId=609EFE7CD27840A164756E2164756E21
9968
+ //# debugId=735330FB398C20EB64756E2164756E21
9785
9969
  //# sourceMappingURL=index.js.map