@absolutejs/absolute 0.20.0-beta.13 → 0.20.0-beta.15

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.
@@ -167,6 +167,389 @@ var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-
167
167
  return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
168
168
  };
169
169
 
170
+ // node_modules/@absolutejs/sync/dist/client/index.js
171
+ var RUNTIME_TRANSPORT, host, isRegistry = (value) => typeof value === "object" && value !== null && Array.isArray(Reflect.get(value, "installations")), registry, SyncLocalDataPolicyError, SyncLocalStoreSchemaError, positiveVersion = (value, label) => {
172
+ if (!Number.isSafeInteger(value) || value < 1)
173
+ throw new SyncLocalStoreSchemaError("INVALID_PLAN", `${label} must be a positive safe integer`);
174
+ return value;
175
+ }, isSchemaBundle = (schema) => ("components" in schema), validatePolicyMatch = (match, label) => {
176
+ if (match.length === 0 || match.trim() !== match || /^\*+$/.test(match) || match.includes("**"))
177
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.match must be an exact name or a non-empty glob without adjacent wildcards.`);
178
+ }, validateSyncLocalDataPolicy = (policy, label = "localData") => {
179
+ if (policy.maxBytesPerNamespace !== undefined && (!Number.isSafeInteger(policy.maxBytesPerNamespace) || policy.maxBytesPerNamespace < 1))
180
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.maxBytesPerNamespace must be a positive safe integer.`);
181
+ for (const [index, rule] of (policy.collections ?? []).entries()) {
182
+ validatePolicyMatch(rule.match, `${label}.collections[${index}]`);
183
+ if (rule.maxAgeMs !== undefined && (!Number.isSafeInteger(rule.maxAgeMs) || rule.maxAgeMs < 1))
184
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}].maxAgeMs must be a positive safe integer.`);
185
+ if (rule.persistence === "memory-only" && rule.protection === "required")
186
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] cannot require at-rest protection when it is memory-only.`);
187
+ if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
188
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] declares ${rule.sensitivity} data without required protection or memory-only persistence.`);
189
+ }
190
+ for (const [index, rule] of (policy.mutations ?? []).entries()) {
191
+ validatePolicyMatch(rule.match, `${label}.mutations[${index}]`);
192
+ if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
193
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] declares ${rule.sensitivity} arguments without required protection.`);
194
+ }
195
+ return policy;
196
+ }, normalizeSyncLocalSchemaComponents = (schema = { version: 1 }) => {
197
+ const components = isSchemaBundle(schema) ? [...schema.components] : [{ ...schema, id: "@absolutejs/app" }];
198
+ const ids = new Set;
199
+ for (const component of components) {
200
+ if (typeof component.id !== "string" || component.id.trim() !== component.id || component.id.length === 0)
201
+ throw new SyncLocalStoreSchemaError("INVALID_PLAN", "Sync schema component id must be non-empty and trimmed");
202
+ if (ids.has(component.id))
203
+ throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync schema component "${component.id}" is declared more than once`);
204
+ ids.add(component.id);
205
+ if (component.localData)
206
+ validateSyncLocalDataPolicy(component.localData, `${component.id}.localData`);
207
+ }
208
+ return components.sort((a, b) => a.id.localeCompare(b.id));
209
+ }, resolveSyncLocalSchemaComponents = (storedVersions, schema = { version: 1 }) => {
210
+ const components = normalizeSyncLocalSchemaComponents(schema).map((component) => {
211
+ const current = resolveSyncLocalMigrations(component.version, component);
212
+ return {
213
+ id: component.id,
214
+ ...resolveSyncLocalMigrations(storedVersions[component.id] ?? current.minimumCompatibleVersion, component)
215
+ };
216
+ });
217
+ const active = new Set(components.map((component) => component.id));
218
+ const orphanedComponents = Object.keys(storedVersions).filter((id) => !active.has(id)).sort();
219
+ return { components, orphanedComponents };
220
+ }, resolveSyncLocalMigrations = (storedVersion, schema = { version: 1 }) => {
221
+ positiveVersion(storedVersion, "Stored Sync schema version");
222
+ const targetVersion = positiveVersion(schema.version, "Target Sync schema version");
223
+ const migrations = [...schema.migrations ?? []].sort((a, b) => a.toVersion - b.toVersion);
224
+ const versions = new Set;
225
+ for (const migration of migrations) {
226
+ positiveVersion(migration.toVersion, "Sync migration toVersion");
227
+ if (versions.has(migration.toVersion))
228
+ throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync migration ${migration.toVersion} is declared more than once`);
229
+ versions.add(migration.toVersion);
230
+ }
231
+ const inferredMinimum = migrations[0] ? migrations[0].toVersion - 1 : targetVersion;
232
+ const minimumCompatibleVersion = positiveVersion(schema.minimumCompatibleVersion ?? inferredMinimum, "Minimum compatible Sync schema version");
233
+ if (minimumCompatibleVersion > targetVersion)
234
+ throw new SyncLocalStoreSchemaError("INVALID_PLAN", "Minimum compatible Sync schema version cannot exceed its target");
235
+ if (storedVersion > targetVersion)
236
+ throw new SyncLocalStoreSchemaError("SCHEMA_TOO_NEW", `Stored Sync schema ${storedVersion} is newer than this runtime's schema ${targetVersion}`, { storedVersion, targetVersion });
237
+ if (storedVersion < minimumCompatibleVersion)
238
+ throw new SyncLocalStoreSchemaError("SCHEMA_TOO_OLD", `Stored Sync schema ${storedVersion} is older than the minimum compatible schema ${minimumCompatibleVersion}`, { storedVersion, targetVersion });
239
+ const steps = [];
240
+ for (let version = storedVersion + 1;version <= targetVersion; version++) {
241
+ const migration = migrations.find((candidate) => candidate.toVersion === version);
242
+ if (migration === undefined)
243
+ throw new SyncLocalStoreSchemaError("MIGRATION_MISSING", `Sync migration ${version - 1} -> ${version} is missing`, { storedVersion, targetVersion });
244
+ steps.push(migration);
245
+ }
246
+ return { minimumCompatibleVersion, steps, targetVersion };
247
+ };
248
+ var init_client = __esm(() => {
249
+ RUNTIME_TRANSPORT = Symbol.for("@absolutejs/sync/client-runtime-transport");
250
+ host = globalThis;
251
+ registry = (() => {
252
+ const existing = host[RUNTIME_TRANSPORT];
253
+ if (isRegistry(existing))
254
+ return existing;
255
+ const created = { installations: [] };
256
+ Object.defineProperty(host, RUNTIME_TRANSPORT, {
257
+ configurable: false,
258
+ enumerable: false,
259
+ value: created,
260
+ writable: false
261
+ });
262
+ return created;
263
+ })();
264
+ SyncLocalDataPolicyError = class SyncLocalDataPolicyError extends Error {
265
+ code;
266
+ constructor(code, message) {
267
+ super(message);
268
+ this.name = "SyncLocalDataPolicyError";
269
+ this.code = code;
270
+ }
271
+ };
272
+ SyncLocalStoreSchemaError = class SyncLocalStoreSchemaError extends Error {
273
+ code;
274
+ storedVersion;
275
+ targetVersion;
276
+ constructor(code, message, versions = {}) {
277
+ super(message);
278
+ this.name = "SyncLocalStoreSchemaError";
279
+ this.code = code;
280
+ this.storedVersion = versions.storedVersion;
281
+ this.targetVersion = versions.targetVersion;
282
+ }
283
+ };
284
+ });
285
+
286
+ // src/mobile/syncSchema.ts
287
+ import { readFileSync as readFileSync3 } from "fs";
288
+ import { dirname as dirname9, join as join12, resolve as resolve10 } from "path";
289
+ var object = (value) => typeof value === "object" && value !== null && !Array.isArray(value), manifestAt = (path) => {
290
+ try {
291
+ const value = JSON.parse(readFileSync3(path, "utf8"));
292
+ return object(value) ? value : undefined;
293
+ } catch {
294
+ return;
295
+ }
296
+ }, localSchemaMetadata = (manifest) => {
297
+ const absolutejs = Reflect.get(manifest, "absolutejs");
298
+ if (!object(absolutejs))
299
+ return;
300
+ const sync = Reflect.get(absolutejs, "sync");
301
+ if (!object(sync))
302
+ return;
303
+ return Reflect.get(sync, "localSchema");
304
+ }, packageManifestPath = (projectRoot, packageName) => {
305
+ let directory = resolve10(projectRoot);
306
+ while (true) {
307
+ const candidate = join12(directory, "node_modules", packageName, "package.json");
308
+ const manifest = manifestAt(candidate);
309
+ if (manifest && Reflect.get(manifest, "name") === packageName)
310
+ return candidate;
311
+ const parent = dirname9(directory);
312
+ if (parent === directory)
313
+ return;
314
+ directory = parent;
315
+ }
316
+ }, metadataError = (id, detail) => new TypeError(`Invalid AbsoluteJS Sync schema metadata for ${id}: ${detail}`), positiveVersion2 = (value, id, field) => {
317
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)
318
+ throw metadataError(id, `${field} must be a positive safe integer.`);
319
+ return value;
320
+ }, nonEmpty = (value, id, field) => {
321
+ if (typeof value !== "string" || value.trim() !== value || value.length === 0)
322
+ throw metadataError(id, `${field} must be a non-empty trimmed string.`);
323
+ return value;
324
+ }, requireObject = (value, id, detail) => {
325
+ if (!object(value))
326
+ throw metadataError(id, detail);
327
+ return value;
328
+ }, unknownField = (record, key) => record[key], normalizeJsonValue2 = (value, id, field) => {
329
+ if (value === null || typeof value === "string" || typeof value === "boolean")
330
+ return value;
331
+ if (typeof value === "number" && Number.isFinite(value))
332
+ return value;
333
+ if (Array.isArray(value))
334
+ return value.map((entry) => normalizeJsonValue2(entry, id, field));
335
+ if (object(value))
336
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
337
+ key,
338
+ normalizeJsonValue2(entry, id, field)
339
+ ]));
340
+ throw metadataError(id, `${field} must be JSON-safe.`);
341
+ }, operation = (value, id, index) => {
342
+ const record = requireObject(value, id, `migration operation ${index} must be an object.`);
343
+ const type = Reflect.get(record, "type");
344
+ const collection = nonEmpty(Reflect.get(record, "collection"), id, `operation ${index}.collection`);
345
+ if (type === "delete-collection")
346
+ return { collection, type };
347
+ if (type === "rename-field")
348
+ return {
349
+ collection,
350
+ from: nonEmpty(Reflect.get(record, "from"), id, `operation ${index}.from`),
351
+ to: nonEmpty(Reflect.get(record, "to"), id, `operation ${index}.to`),
352
+ type
353
+ };
354
+ const field = nonEmpty(Reflect.get(record, "field"), id, `operation ${index}.field`);
355
+ if (type === "remove-field")
356
+ return { collection, field, type };
357
+ if (type === "set-default")
358
+ return {
359
+ collection,
360
+ field,
361
+ type,
362
+ value: normalizeJsonValue2(Reflect.get(record, "value"), id, `operation ${index}.value`)
363
+ };
364
+ throw metadataError(id, `operation ${index}.type is not supported.`);
365
+ }, migration = (value, id, index) => {
366
+ const record = requireObject(value, id, `migration ${index} must be an object.`);
367
+ const allowed = new Set(["operations", "toVersion"]);
368
+ const unsupported = Object.keys(record).find((key) => !allowed.has(key));
369
+ if (unsupported)
370
+ throw metadataError(id, `migration ${index}.${unsupported} is not declarative metadata.`);
371
+ const declaredOperations = Reflect.get(record, "operations");
372
+ if (declaredOperations !== undefined && !Array.isArray(declaredOperations))
373
+ throw metadataError(id, `migration ${index}.operations must be an array.`);
374
+ const operations = Array.isArray(declaredOperations) ? declaredOperations : [];
375
+ return {
376
+ operations: operations.map((entry, operationIndex) => operation(entry, id, operationIndex)),
377
+ toVersion: positiveVersion2(Reflect.get(record, "toVersion"), id, `migration ${index}.toVersion`)
378
+ };
379
+ }, localDataPolicy = (value, id) => {
380
+ const record = requireObject(value, id, "localData must be an object.");
381
+ const allowed = new Set([
382
+ "collections",
383
+ "maxBytesPerNamespace",
384
+ "mutations"
385
+ ]);
386
+ const unsupported = Object.keys(record).find((key) => !allowed.has(key));
387
+ if (unsupported)
388
+ throw metadataError(id, `localData.${unsupported} is not supported.`);
389
+ const collectionRules = Reflect.get(record, "collections");
390
+ const mutationRules = Reflect.get(record, "mutations");
391
+ if (collectionRules !== undefined && !Array.isArray(collectionRules))
392
+ throw metadataError(id, "localData.collections must be an array.");
393
+ if (mutationRules !== undefined && !Array.isArray(mutationRules))
394
+ throw metadataError(id, "localData.mutations must be an array.");
395
+ const collections = Array.isArray(collectionRules) ? collectionRules.map((entry, index) => {
396
+ const rule = requireObject(entry, id, `localData.collections[${index}] must be an object.`);
397
+ const allowedRuleKeys = new Set([
398
+ "evictionPriority",
399
+ "match",
400
+ "maxAgeMs",
401
+ "onProtectionUnavailable",
402
+ "persistence",
403
+ "protection",
404
+ "sensitivity"
405
+ ]);
406
+ const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
407
+ if (unsupportedRuleKey)
408
+ throw metadataError(id, `localData.collections[${index}].${unsupportedRuleKey} is not supported.`);
409
+ const match = nonEmpty(Reflect.get(rule, "match"), id, `localData.collections[${index}].match`);
410
+ const persistence = unknownField(rule, "persistence");
411
+ const sensitivity = unknownField(rule, "sensitivity");
412
+ const protection = unknownField(rule, "protection");
413
+ const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
414
+ const evictionPriority = unknownField(rule, "evictionPriority");
415
+ const maxAge = unknownField(rule, "maxAgeMs");
416
+ if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
417
+ throw metadataError(id, `localData.collections[${index}].persistence is invalid.`);
418
+ if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
419
+ throw metadataError(id, `localData.collections[${index}].sensitivity is invalid.`);
420
+ if (protection !== undefined && protection !== "none" && protection !== "required")
421
+ throw metadataError(id, `localData.collections[${index}].protection is invalid.`);
422
+ if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
423
+ throw metadataError(id, `localData.collections[${index}].onProtectionUnavailable is invalid.`);
424
+ if (evictionPriority !== undefined && evictionPriority !== "critical" && evictionPriority !== "normal" && evictionPriority !== "disposable")
425
+ throw metadataError(id, `localData.collections[${index}].evictionPriority is invalid.`);
426
+ return {
427
+ match,
428
+ ...sensitivity ? { sensitivity } : {},
429
+ ...persistence ? { persistence } : {},
430
+ ...protection ? { protection } : {},
431
+ ...onProtectionUnavailable ? {
432
+ onProtectionUnavailable
433
+ } : {},
434
+ ...evictionPriority ? { evictionPriority } : {},
435
+ ...maxAge === undefined ? {} : {
436
+ maxAgeMs: positiveVersion2(maxAge, id, `localData.collections[${index}].maxAgeMs`)
437
+ }
438
+ };
439
+ }) : undefined;
440
+ const mutations = Array.isArray(mutationRules) ? mutationRules.map((entry, index) => {
441
+ const rule = requireObject(entry, id, `localData.mutations[${index}] must be an object.`);
442
+ const allowedRuleKeys = new Set([
443
+ "match",
444
+ "persistence",
445
+ "protection",
446
+ "sensitivity"
447
+ ]);
448
+ const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
449
+ if (unsupportedRuleKey)
450
+ throw metadataError(id, `localData.mutations[${index}].${unsupportedRuleKey} is not supported.`);
451
+ const protection = unknownField(rule, "protection");
452
+ const sensitivity = unknownField(rule, "sensitivity");
453
+ const persistence = unknownField(rule, "persistence");
454
+ if (protection !== undefined && protection !== "none" && protection !== "required")
455
+ throw metadataError(id, `localData.mutations[${index}].protection is invalid.`);
456
+ if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
457
+ throw metadataError(id, `localData.mutations[${index}].sensitivity is invalid.`);
458
+ if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
459
+ throw metadataError(id, `localData.mutations[${index}].persistence is invalid.`);
460
+ return {
461
+ match: nonEmpty(Reflect.get(rule, "match"), id, `localData.mutations[${index}].match`),
462
+ ...sensitivity ? { sensitivity } : {},
463
+ ...persistence ? {
464
+ persistence
465
+ } : {},
466
+ ...protection ? { protection } : {}
467
+ };
468
+ }) : undefined;
469
+ const quota = Reflect.get(record, "maxBytesPerNamespace");
470
+ return {
471
+ ...collections ? { collections } : {},
472
+ ...mutations ? { mutations } : {},
473
+ ...quota === undefined ? {} : {
474
+ maxBytesPerNamespace: positiveVersion2(quota, id, "localData.maxBytesPerNamespace")
475
+ }
476
+ };
477
+ }, component = (id, value) => {
478
+ const record = requireObject(value, id, "localSchema must be an object.");
479
+ const allowed = new Set([
480
+ "localData",
481
+ "migrations",
482
+ "minimumCompatibleVersion",
483
+ "version"
484
+ ]);
485
+ const unsupported = Object.keys(record).find((key) => !allowed.has(key));
486
+ if (unsupported)
487
+ throw metadataError(id, `${unsupported} is not supported.`);
488
+ const version = positiveVersion2(Reflect.get(record, "version"), id, "version");
489
+ const declaredMinimum = Reflect.get(record, "minimumCompatibleVersion");
490
+ const minimumCompatibleVersion = declaredMinimum === undefined ? Math.max(1, version - 2) : positiveVersion2(declaredMinimum, id, "minimumCompatibleVersion");
491
+ const declaredMigrations = Reflect.get(record, "migrations");
492
+ const declaredLocalData = Reflect.get(record, "localData");
493
+ if (declaredMigrations !== undefined && !Array.isArray(declaredMigrations))
494
+ throw metadataError(id, "migrations must be an array.");
495
+ const migrations = Array.isArray(declaredMigrations) ? declaredMigrations : undefined;
496
+ return {
497
+ id,
498
+ ...declaredLocalData === undefined ? {} : { localData: localDataPolicy(declaredLocalData, id) },
499
+ minimumCompatibleVersion,
500
+ ...Array.isArray(migrations) ? {
501
+ migrations: migrations.map((entry, index) => migration(entry, id, index))
502
+ } : {},
503
+ version
504
+ };
505
+ }, dependencyNames = (manifest) => [
506
+ Reflect.get(manifest, "dependencies"),
507
+ Reflect.get(manifest, "optionalDependencies"),
508
+ Reflect.get(manifest, "devDependencies"),
509
+ Reflect.get(manifest, "peerDependencies")
510
+ ].flatMap((dependencies) => object(dependencies) ? Object.keys(dependencies) : []).filter((name, index, names) => names.indexOf(name) === index).sort(), discoverAbsoluteSyncSchema = (projectRoot) => {
511
+ const appManifestPath = join12(resolve10(projectRoot), "package.json");
512
+ const appManifest = manifestAt(appManifestPath);
513
+ if (!appManifest)
514
+ return {
515
+ components: [
516
+ {
517
+ id: "@absolutejs/app",
518
+ minimumCompatibleVersion: 1,
519
+ version: 1
520
+ }
521
+ ],
522
+ sources: []
523
+ };
524
+ const appMetadata = localSchemaMetadata(appManifest);
525
+ const components = [
526
+ appMetadata === undefined ? { id: "@absolutejs/app", minimumCompatibleVersion: 1, version: 1 } : component("@absolutejs/app", appMetadata)
527
+ ];
528
+ const sources = [
529
+ { id: "@absolutejs/app", manifestPath: appManifestPath }
530
+ ];
531
+ for (const name of dependencyNames(appManifest)) {
532
+ const manifestPath = packageManifestPath(projectRoot, name);
533
+ if (!manifestPath)
534
+ continue;
535
+ const manifest = manifestAt(manifestPath);
536
+ if (!manifest)
537
+ continue;
538
+ const metadata = localSchemaMetadata(manifest);
539
+ if (metadata === undefined)
540
+ continue;
541
+ components.push(component(name, metadata));
542
+ sources.push({ id: name, manifestPath });
543
+ }
544
+ components.sort((left, right) => left.id.localeCompare(right.id));
545
+ sources.sort((left, right) => left.id.localeCompare(right.id));
546
+ resolveSyncLocalSchemaComponents({}, { components });
547
+ return { components, sources };
548
+ };
549
+ var init_syncSchema = __esm(() => {
550
+ init_client();
551
+ });
552
+
170
553
  // src/mobile/artifactStore.ts
171
554
  import { createHash as createHash2 } from "crypto";
172
555
  import {
@@ -2576,6 +2959,7 @@ var ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION = 1;
2576
2959
 
2577
2960
  // src/mobile/remoteMacProtocol.ts
2578
2961
  var PROFILE_FORMAT = 1;
2962
+ var REMOTE_STDIN_FLUSH_ATTEMPTS = 3;
2579
2963
  var PROFILE_NAME = /^[a-z0-9](?:[a-z0-9._-]{0,62}[a-z0-9])?$/u;
2580
2964
  var SSH_DESTINATION = /^(?:[A-Za-z0-9._-]+@)?[A-Za-z0-9._:-]+$/u;
2581
2965
  var defaultProfilePath = () => join7(homedir2(), ".absolutejs", "mobile", "remote-macs.json");
@@ -3067,8 +3451,17 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
3067
3451
  const response = new Promise((resolve6, reject) => pending.set(id, { reject, resolve: resolve6 }));
3068
3452
  process2.stdin.write(`${JSON.stringify({ command: commandName, id, v: 1 })}
3069
3453
  `);
3070
- process2.stdin.flush();
3071
- return response;
3454
+ const flush = async () => {
3455
+ for (let attempt = 0;attempt < REMOTE_STDIN_FLUSH_ATTEMPTS; attempt++) {
3456
+ try {
3457
+ await process2.stdin.flush();
3458
+ return;
3459
+ } catch {
3460
+ await Promise.resolve();
3461
+ }
3462
+ }
3463
+ };
3464
+ return flush().then(() => response);
3072
3465
  };
3073
3466
  let closed = false;
3074
3467
  const close = async () => {
@@ -3495,7 +3888,7 @@ var parseAbsoluteMobileBuildPageMetadata = (value) => {
3495
3888
  };
3496
3889
  // src/mobile/buildPipeline.ts
3497
3890
  import { readFile as readFile13 } from "fs/promises";
3498
- import { join as join12, resolve as resolve10 } from "path";
3891
+ import { join as join13, resolve as resolve11 } from "path";
3499
3892
  import { pathToFileURL as pathToFileURL2 } from "url";
3500
3893
 
3501
3894
  // src/mobile/buildRelease.ts
@@ -4325,7 +4718,12 @@ var materializeAbsoluteCapacitorWebBundle = async (options) => {
4325
4718
  endpoint: new URL("/__absolute/sync/background", options.config.productionOrigin).href,
4326
4719
  intervalMinutes: 15
4327
4720
  },
4328
- socketTickets: true
4721
+ socketTickets: true,
4722
+ storageSchema: options.syncSchema ?? {
4723
+ components: [
4724
+ { id: "@absolutejs/app", version: 1 }
4725
+ ]
4726
+ }
4329
4727
  }
4330
4728
  } : {}
4331
4729
  };
@@ -4573,6 +4971,7 @@ var serializeAbsoluteMobileAuthEnvironment = (config, auth) => auth === undefine
4573
4971
  ]);
4574
4972
 
4575
4973
  // src/mobile/buildPipeline.ts
4974
+ init_syncSchema();
4576
4975
  var isElysiaApp = (value) => typeof value === "object" && value !== null && typeof Reflect.get(value, "compile") === "function" && Array.isArray(Reflect.get(value, "routes"));
4577
4976
  var isStringRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.values(value).every((entry) => typeof entry === "string");
4578
4977
  var serverExportName = (loaded, app) => {
@@ -4606,11 +5005,11 @@ var loadServerApp = async (producerPath) => {
4606
5005
  return { app, exportName };
4607
5006
  };
4608
5007
  var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
4609
- const buildDirectory = resolve10(options.buildDirectory);
5008
+ const buildDirectory = resolve11(options.buildDirectory);
4610
5009
  const mobile = normalizeAbsoluteMobileConfig(options.mobile, options.projectRoot);
4611
- const root = join12(buildDirectory, ".absolutejs", "mobile-compatibility");
5010
+ const root = join13(buildDirectory, ".absolutejs", "mobile-compatibility");
4612
5011
  const [manifestSource, previous] = await Promise.all([
4613
- readFile13(join12(buildDirectory, "manifest.json"), "utf8"),
5012
+ readFile13(join13(buildDirectory, "manifest.json"), "utf8"),
4614
5013
  readAbsoluteMobileMaterializedReleases(root)
4615
5014
  ]);
4616
5015
  const manifest = JSON.parse(manifestSource);
@@ -4623,11 +5022,11 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
4623
5022
  process.env.ABSOLUTE_BUILD_DIR = buildDirectory;
4624
5023
  process.env.ABSOLUTE_COMPILED_RUNTIME = "1";
4625
5024
  if (options.configPath) {
4626
- process.env.ABSOLUTE_CONFIG = resolve10(options.projectRoot, options.configPath);
5025
+ process.env.ABSOLUTE_CONFIG = resolve11(options.projectRoot, options.configPath);
4627
5026
  }
4628
5027
  let loaded;
4629
5028
  try {
4630
- loaded = await loadServerApp(resolve10(options.producerPath));
5029
+ loaded = await loadServerApp(resolve11(options.producerPath));
4631
5030
  } finally {
4632
5031
  restoreEnvironmentVariable("ABSOLUTE_BUILD_DIR", previousBuildDirectory);
4633
5032
  restoreEnvironmentVariable("ABSOLUTE_COMPILED_RUNTIME", previousCompiledRuntime);
@@ -4640,11 +5039,12 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
4640
5039
  manifest,
4641
5040
  previousArtifacts: previous.map(({ artifact }) => artifact),
4642
5041
  producerExport: loaded.exportName,
4643
- producerPath: resolve10(options.producerPath),
5042
+ producerPath: resolve11(options.producerPath),
4644
5043
  runtime: String(ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION)
4645
5044
  });
4646
5045
  const auth = resolveAbsoluteMobileAuthManifest(options.projectRoot, mobile);
4647
5046
  const sync = auth !== undefined && projectUsesAbsoluteSync(options.projectRoot);
5047
+ const syncSchema = sync ? discoverAbsoluteSyncSchema(options.projectRoot) : undefined;
4648
5048
  if (auth && !loaded.app.routes.some((route) => route.path === "/.well-known/openid-configuration")) {
4649
5049
  throw new TypeError("@absolutejs/auth is installed, but its OIDC provider is not mounted. Native authentication requires the auth oidc configuration so AbsoluteJS can provision a public PKCE client.");
4650
5050
  }
@@ -4663,10 +5063,15 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
4663
5063
  ...auth ? { auth } : {},
4664
5064
  buildDirectory,
4665
5065
  config: mobile,
4666
- ...sync ? { sync: true } : {}
5066
+ ...sync ? { sync: true } : {},
5067
+ ...syncSchema ? { syncSchema: { components: syncSchema.components } } : {}
4667
5068
  });
4668
5069
  return current.artifact;
4669
5070
  };
5071
+
5072
+ // src/mobile/index.ts
5073
+ init_syncSchema();
5074
+
4670
5075
  // src/mobile/compatibilityDispatcher.ts
4671
5076
  import { Elysia as Elysia2 } from "elysia";
4672
5077
 
@@ -4808,7 +5213,7 @@ var createAbsoluteMobileCompatibilityDispatcher = (options) => {
4808
5213
  };
4809
5214
  // src/mobile/nativeDeepLinks.ts
4810
5215
  import { readFile as readFile14, rename as rename11, writeFile as writeFile12 } from "fs/promises";
4811
- import { join as join13 } from "path";
5216
+ import { join as join14 } from "path";
4812
5217
  var START_MARKER = "<!-- absolutejs:deep-links:start -->";
4813
5218
  var END_MARKER = "<!-- absolutejs:deep-links:end -->";
4814
5219
  var IOS_ENTITLEMENTS = "App/AbsoluteJS.entitlements";
@@ -4844,7 +5249,7 @@ var replaceManagedRegion = (source, region, insertAt) => {
4844
5249
  return `${source.slice(0, index)}${region}${source.slice(index)}`;
4845
5250
  };
4846
5251
  var androidRegion = (config) => {
4847
- const hosts = config.deepLinkHosts.map((host) => ` <data android:scheme="https" android:host="${escapeXml(host)}" />`).join(`
5252
+ const hosts = config.deepLinkHosts.map((host2) => ` <data android:scheme="https" android:host="${escapeXml(host2)}" />`).join(`
4848
5253
  `);
4849
5254
  const customScheme = config.deepLinkScheme ? `
4850
5255
 
@@ -4865,7 +5270,7 @@ ${hosts}
4865
5270
  `;
4866
5271
  };
4867
5272
  var configureAndroid = async (config) => {
4868
- const path = join13(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
5273
+ const path = join14(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
4869
5274
  const source = await readFile14(path, "utf8");
4870
5275
  const mainActivity = source.indexOf('android:name=".MainActivity"');
4871
5276
  if (mainActivity === NOT_FOUND) {
@@ -4891,7 +5296,7 @@ var iosSchemeRegion = (scheme) => ` ${START_MARKER}
4891
5296
  ${END_MARKER}
4892
5297
  `;
4893
5298
  var configureIosInfo = async (config) => {
4894
- const path = join13(config.nativeProjectDirectory, "ios/App/App/Info.plist");
5299
+ const path = join14(config.nativeProjectDirectory, "ios/App/App/Info.plist");
4895
5300
  const source = await readFile14(path, "utf8");
4896
5301
  const region = config.deepLinkScheme ? iosSchemeRegion(config.deepLinkScheme) : ` ${START_MARKER}
4897
5302
  ${END_MARKER}
@@ -4900,7 +5305,7 @@ var configureIosInfo = async (config) => {
4900
5305
  return writeChangedFile(path, updated);
4901
5306
  };
4902
5307
  var iosEntitlementsSource = (config) => {
4903
- const domains = config.deepLinkHosts.map((host) => ` <string>applinks:${escapeXml(host)}</string>`).join(`
5308
+ const domains = config.deepLinkHosts.map((host2) => ` <string>applinks:${escapeXml(host2)}</string>`).join(`
4904
5309
  `);
4905
5310
  return `<?xml version="1.0" encoding="UTF-8"?>
4906
5311
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -4915,7 +5320,7 @@ ${domains}
4915
5320
  `;
4916
5321
  };
4917
5322
  var configureIosEntitlements = async (config) => {
4918
- const path = join13(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
5323
+ const path = join14(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
4919
5324
  let current = "";
4920
5325
  try {
4921
5326
  current = await readFile14(path, "utf8");
@@ -4933,7 +5338,7 @@ var configureIosEntitlements = async (config) => {
4933
5338
  return true;
4934
5339
  };
4935
5340
  var configureIosProject = async (config) => {
4936
- const path = join13(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
5341
+ const path = join14(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
4937
5342
  const source = await readFile14(path, "utf8");
4938
5343
  const declarations = [
4939
5344
  ...source.matchAll(/CODE_SIGN_ENTITLEMENTS = ([^;]+);/g)
@@ -4973,7 +5378,7 @@ var applyAbsoluteNativeDeepLinks = async (config, platforms = config.platforms)
4973
5378
  };
4974
5379
  // src/mobile/releasePublisher.ts
4975
5380
  import { access as access9 } from "fs/promises";
4976
- import { isAbsolute as isAbsolute6, relative as relative9, resolve as resolve11, sep as sep6 } from "path";
5381
+ import { isAbsolute as isAbsolute6, relative as relative9, resolve as resolve12, sep as sep6 } from "path";
4977
5382
  import { pathToFileURL as pathToFileURL3 } from "url";
4978
5383
  var prepareAbsoluteIosRelease = async (publisher, options) => {
4979
5384
  if (typeof publisher.prepareIosRelease !== "function") {
@@ -4999,8 +5404,8 @@ var prepareAbsoluteAndroidRelease = async (publisher, options) => {
4999
5404
  var isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
5000
5405
  var isPublisher = (value) => isRecord8(value) && typeof value.publish === "function";
5001
5406
  var publisherModulePath = (projectRoot, requested) => {
5002
- const root = resolve11(projectRoot);
5003
- const path = resolve11(root, requested);
5407
+ const root = resolve12(projectRoot);
5408
+ const path = resolve12(root, requested);
5004
5409
  const projectRelative = relative9(root, path);
5005
5410
  if (projectRelative === ".." || projectRelative.startsWith(`..${sep6}`) || isAbsolute6(projectRelative)) {
5006
5411
  throw new TypeError("mobile publish --registry must remain inside the project.");
@@ -5070,8 +5475,8 @@ var publishAbsoluteIosRelease = async (options) => {
5070
5475
  return publication;
5071
5476
  };
5072
5477
  // src/mobile/routeMetadataTransform.ts
5073
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
5074
- import { dirname as dirname9, extname as extname3, relative as relative10, resolve as resolve12 } from "path";
5478
+ import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
5479
+ import { dirname as dirname10, extname as extname3, relative as relative10, resolve as resolve13 } from "path";
5075
5480
  import ts from "typescript";
5076
5481
  var ROUTE_METHODS = new Set(["get", "head"]);
5077
5482
  var SOURCE_FILTER = /\.[cm]?[jt]sx?$/;
@@ -5122,7 +5527,7 @@ var PAGE_HANDLERS = new Map([
5122
5527
  ]
5123
5528
  ]);
5124
5529
  var posixPath = (value) => value.replace(/\\/g, "/");
5125
- var findTsconfig = (entry, projectRoot) => ts.findConfigFile(dirname9(entry), existsSync3, "tsconfig.json") ?? ts.findConfigFile(projectRoot, existsSync3, "tsconfig.json");
5530
+ var findTsconfig = (entry, projectRoot) => ts.findConfigFile(dirname10(entry), existsSync3, "tsconfig.json") ?? ts.findConfigFile(projectRoot, existsSync3, "tsconfig.json");
5126
5531
  var createProgram = (entry, projectRoot) => {
5127
5532
  const configPath = findTsconfig(entry, projectRoot);
5128
5533
  if (!configPath) {
@@ -5134,7 +5539,7 @@ var createProgram = (entry, projectRoot) => {
5134
5539
  target: ts.ScriptTarget.ESNext
5135
5540
  });
5136
5541
  }
5137
- const parsed = ts.parseJsonConfigFileContent(ts.readConfigFile(configPath, (path) => readFileSync3(path, "utf8")).config, ts.sys, dirname9(configPath));
5542
+ const parsed = ts.parseJsonConfigFileContent(ts.readConfigFile(configPath, (path) => readFileSync4(path, "utf8")).config, ts.sys, dirname10(configPath));
5138
5543
  if (!parsed.fileNames.includes(entry))
5139
5544
  parsed.fileNames.push(entry);
5140
5545
  return ts.createProgram(parsed.fileNames, parsed.options);
@@ -5148,8 +5553,8 @@ var propertyName = (property) => {
5148
5553
  return property.name.text;
5149
5554
  return;
5150
5555
  };
5151
- var objectPropertyExpression = (object, name) => {
5152
- const property = object.properties.find((candidate) => propertyName(candidate) === name);
5556
+ var objectPropertyExpression = (object2, name) => {
5557
+ const property = object2.properties.find((candidate) => propertyName(candidate) === name);
5153
5558
  if (property && ts.isPropertyAssignment(property)) {
5154
5559
  return property.initializer;
5155
5560
  }
@@ -5345,8 +5750,8 @@ var spreadObject = (expression, checker, bindings) => {
5345
5750
  return;
5346
5751
  return callableObject(expression, checker);
5347
5752
  };
5348
- var objectAssetKey = (object, name, checker, bindings = new Map) => {
5349
- for (const property of [...object.properties].reverse()) {
5753
+ var objectAssetKey = (object2, name, checker, bindings = new Map) => {
5754
+ for (const property of [...object2.properties].reverse()) {
5350
5755
  if (propertyName(property) === name && ts.isShorthandPropertyAssignment(property)) {
5351
5756
  return assetKeyWithBindings(property.name, checker, bindings);
5352
5757
  }
@@ -5479,7 +5884,7 @@ var analyzeProgram = (program, projectRoot) => {
5479
5884
  const checker = program.getTypeChecker();
5480
5885
  const analyzed = new Map;
5481
5886
  for (const sourceFile of program.getSourceFiles()) {
5482
- const resolvedFile = resolve12(sourceFile.fileName);
5887
+ const resolvedFile = resolve13(sourceFile.fileName);
5483
5888
  if (!isProjectSource(sourceFile, resolvedFile, projectRoot))
5484
5889
  continue;
5485
5890
  const analysis = analyzeSourceFile(sourceFile, checker, projectRoot);
@@ -5572,14 +5977,14 @@ var transformFile = (source, fileName, analysis) => {
5572
5977
  };
5573
5978
  var ABSOLUTE_MOBILE_TRANSFORM_PROTOCOL = ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION;
5574
5979
  var createAbsoluteMobileRouteMetadataPlugin = (options) => {
5575
- const projectRoot = resolve12(options.projectRoot ?? process.cwd());
5576
- const entry = resolve12(options.entry);
5980
+ const projectRoot = resolve13(options.projectRoot ?? process.cwd());
5981
+ const entry = resolve13(options.entry);
5577
5982
  const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
5578
5983
  return {
5579
5984
  name: "absolute-mobile-route-metadata",
5580
5985
  setup(build) {
5581
5986
  build.onLoad({ filter: SOURCE_FILTER }, async ({ path }) => {
5582
- const analysis = analyzed.get(resolve12(path));
5987
+ const analysis = analyzed.get(resolve13(path));
5583
5988
  if (!analysis)
5584
5989
  return;
5585
5990
  const source = await Bun.file(path).text();
@@ -5592,8 +5997,8 @@ var createAbsoluteMobileRouteMetadataPlugin = (options) => {
5592
5997
  };
5593
5998
  };
5594
5999
  var inspectAbsoluteMobileRouteMetadata = (options) => {
5595
- const projectRoot = resolve12(options.projectRoot ?? process.cwd());
5596
- const entry = resolve12(options.entry);
6000
+ const projectRoot = resolve13(options.projectRoot ?? process.cwd());
6001
+ const entry = resolve13(options.entry);
5597
6002
  const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
5598
6003
  return [...analyzed.entries()].flatMap(([file, analysis]) => [...analysis.byRouteCall.values()].map(({ metadata }) => ({
5599
6004
  file: posixPath(relative10(projectRoot, file)),
@@ -5663,6 +6068,7 @@ export {
5663
6068
  finalizeAbsoluteMobileCompatibilityBuild,
5664
6069
  fetchAbsoluteMobilePage,
5665
6070
  disposeAbsoluteMobilePage,
6071
+ discoverAbsoluteSyncSchema,
5666
6072
  createAbsoluteRemoteIosDevProject,
5667
6073
  createAbsoluteMobileUpgradeResponse,
5668
6074
  createAbsoluteMobileRouteMetadataPlugin,
@@ -5710,5 +6116,5 @@ export {
5710
6116
  ABSOLUTE_ANDROID_RELEASE_FORMAT
5711
6117
  };
5712
6118
 
5713
- //# debugId=712D22B2B8D89AC264756E2164756E21
6119
+ //# debugId=924628517A2DD9D064756E2164756E21
5714
6120
  //# sourceMappingURL=index.js.map