@absolutejs/absolute 0.20.0-beta.81 → 0.20.0-beta.82

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/dist/cli/index.js CHANGED
@@ -203,7 +203,7 @@ if (command === "dev") {
203
203
  sendTelemetryEvent("cli:command", {
204
204
  command: `mobile:${workspaceCommand ?? "unknown"}`
205
205
  });
206
- const { runMobile } = await import("./mobile-rdwdcks1.js");
206
+ const { runMobile } = await import("./mobile-hkxh2ab5.js");
207
207
  try {
208
208
  await runMobile(args);
209
209
  } catch (error) {
@@ -19292,11 +19292,29 @@ var loadAbsoluteMobileUpdateServerModule = async (projectRoot, requestedModulePa
19292
19292
  const registry = loaded.default ?? loaded.registry;
19293
19293
  if (!isRegistry(registry))
19294
19294
  throw new TypeError("Mobile update registry must implement publication, promotion, rollback, resolution, and file reads.");
19295
+ const metadata = serverMetadata(loaded.absoluteMobileUpdateServer);
19296
+ const verifier = loaded.verifyAbsoluteMobileUpdateServer;
19297
+ if (metadata.storage === "durable" && typeof verifier !== "function")
19298
+ throw new TypeError("Mobile update registries marked durable must export verifyAbsoluteMobileUpdateServer(). Re-run `absolute mobile update provision --storage s3 --force` or provide an active durability check.");
19295
19299
  return {
19296
- metadata: serverMetadata(loaded.absoluteMobileUpdateServer),
19297
- registry
19300
+ metadata,
19301
+ registry,
19302
+ ...typeof verifier === "function" ? {
19303
+ verifyDurability: async () => {
19304
+ await verifier();
19305
+ }
19306
+ } : {}
19298
19307
  };
19299
19308
  };
19309
+ var verifyDurableModule = async (module) => {
19310
+ if (module.metadata.storage !== "durable")
19311
+ throw new TypeError("Mobile production updates require durable object storage. Re-run `absolute mobile update provision --storage s3 --force` or configure a durable adapter.");
19312
+ try {
19313
+ await module.verifyDurability?.();
19314
+ } catch (error) {
19315
+ throw new TypeError(`Durable mobile update storage verification failed for ${module.metadata.provider}. Check the bucket, endpoint, credentials, and read/write/delete permissions.`, { cause: error });
19316
+ }
19317
+ };
19300
19318
  var expoSigningOptions = (config) => {
19301
19319
  if (!config.updates?.expoCodeSigning)
19302
19320
  return;
@@ -19328,8 +19346,7 @@ var inspectAbsoluteMobileUpdateServer = async (config, projectRoot) => {
19328
19346
  if (!config.updates)
19329
19347
  return;
19330
19348
  const module = await loadAbsoluteMobileUpdateServerModule(projectRoot, config.updateServer?.registryModule);
19331
- if (module.metadata.storage !== "durable")
19332
- throw new TypeError("Mobile production updates require durable object storage; the configured registry is local-only.");
19349
+ await verifyDurableModule(module);
19333
19350
  if (config.engine === "expo")
19334
19351
  expoSigningOptions(config);
19335
19352
  return module.metadata;
@@ -19358,7 +19375,8 @@ export default createMobileUpdateRegistry({
19358
19375
  store
19359
19376
  });
19360
19377
  `;
19361
- return `import { S3Client } from '@aws-sdk/client-s3';
19378
+ return `import { randomUUID } from 'node:crypto';
19379
+ import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
19362
19380
  import { awsS3BlobStore } from '@absolutejs/blob/aws-s3';
19363
19381
  import { createMobileUpdateRegistry } from '@absolutejs/deploy/mobile-update';
19364
19382
 
@@ -19370,6 +19388,7 @@ const required = (name: string) => {
19370
19388
  return value;
19371
19389
  };
19372
19390
 
19391
+ const bucket = required('ABSOLUTE_MOBILE_UPDATE_S3_BUCKET');
19373
19392
  const client = new S3Client({
19374
19393
  region: process.env.ABSOLUTE_MOBILE_UPDATE_S3_REGION ?? 'auto',
19375
19394
  forcePathStyle: process.env.ABSOLUTE_MOBILE_UPDATE_S3_FORCE_PATH_STYLE === '1',
@@ -19377,10 +19396,22 @@ const client = new S3Client({
19377
19396
  ? { endpoint: process.env.ABSOLUTE_MOBILE_UPDATE_S3_ENDPOINT }
19378
19397
  : {})
19379
19398
  });
19380
- const store = awsS3BlobStore({
19381
- bucket: required('ABSOLUTE_MOBILE_UPDATE_S3_BUCKET'),
19382
- client
19383
- });
19399
+ const store = awsS3BlobStore({ bucket, client });
19400
+
19401
+ export const verifyAbsoluteMobileUpdateServer = async () => {
19402
+ const key = \`absolutejs/mobile-updates/_health/\${randomUUID()}\`;
19403
+ const expected = randomUUID();
19404
+ let stored = false;
19405
+ try {
19406
+ await client.send(new PutObjectCommand({ Bucket: bucket, Key: key, Body: expected }));
19407
+ stored = true;
19408
+ const response = await client.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
19409
+ if ((await response.Body?.transformToString()) !== expected)
19410
+ throw new Error('Durability probe read did not match its write.');
19411
+ } finally {
19412
+ if (stored) await client.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
19413
+ }
19414
+ };
19384
19415
 
19385
19416
  export default createMobileUpdateRegistry({
19386
19417
  publicKeys: ${publicKeysSource(options.publicKeys)},
@@ -19468,7 +19499,7 @@ var mobileUpdateServerCheck = async (config, projectRoot) => {
19468
19499
  return;
19469
19500
  try {
19470
19501
  const metadata = await inspectAbsoluteMobileUpdateServer(config, projectRoot);
19471
- return pass("updates.trusted-server", `The trusted update server uses durable ${metadata?.provider ?? "object"} storage, supports publish/promote/rollback, and has valid server-only signing material.`, config.updateServer?.registryModule);
19502
+ return pass("updates.trusted-server", `The trusted update server proved durable ${metadata?.provider ?? "object"} storage read/write/delete access, supports publish/promote/rollback, and has valid server-only signing material.`, config.updateServer?.registryModule);
19472
19503
  } catch (error) {
19473
19504
  return fail("updates.trusted-server", error instanceof Error ? error.message : "The trusted mobile update server is not release-ready.", config.updateServer?.registryModule ?? "mobile.update.ts", "Run `absolute mobile update provision --storage s3 --force`, provision its environment variables on the trusted server, and rerun the release doctor.");
19474
19505
  }
@@ -22710,7 +22741,7 @@ var provisionMobileUpdate = async (args) => {
22710
22741
  throw new TypeError("--storage must be local or s3.");
22711
22742
  const modulePath = valueAfter(args, "--registry") ?? mobile.updateServer.registryModule;
22712
22743
  const packages = [
22713
- "@absolutejs/deploy@0.25.5",
22744
+ "@absolutejs/deploy@0.25.6",
22714
22745
  "@absolutejs/blob@0.5.2",
22715
22746
  ...requestedStorage === "s3" ? [
22716
22747
  "@aws-sdk/client-s3@3.1095.0",
package/dist/index.js CHANGED
@@ -12580,10 +12580,10 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12580
12580
  cacheControl: "public, max-age=31536000, immutable",
12581
12581
  contentType: "application/octet-stream",
12582
12582
  maxBytes: file2.bytes,
12583
- metadata: { releaseId: manifest.releaseId, sha256: file2.sha256 },
12583
+ metadata: { releaseid: manifest.releaseId, sha256: file2.sha256 },
12584
12584
  signal: input.signal
12585
12585
  });
12586
- } else if (stored.size !== file2.bytes || stored.metadata?.sha256 !== file2.sha256 || stored.metadata?.releaseId !== manifest.releaseId)
12586
+ } else if (stored.size !== file2.bytes || stored.metadata?.sha256 !== file2.sha256 || (stored.metadata?.releaseid ?? stored.metadata?.releaseId) !== manifest.releaseId)
12587
12587
  throw new MobileUpdateRegistryError("Stored mobile update file identity changed");
12588
12588
  }
12589
12589
  const bytes = json(manifest);
@@ -12591,7 +12591,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12591
12591
  cacheControl: "public, max-age=31536000, immutable",
12592
12592
  contentType: "application/json",
12593
12593
  maxBytes: bytes.byteLength,
12594
- metadata: { releaseId: manifest.releaseId, sha256: digest(bytes) },
12594
+ metadata: { releaseid: manifest.releaseId, sha256: digest(bytes) },
12595
12595
  signal: input.signal
12596
12596
  });
12597
12597
  if (!await readManifest(manifest.appId, manifest.releaseId))
@@ -12664,7 +12664,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12664
12664
  ]);
12665
12665
  if (!bytes || !head)
12666
12666
  return null;
12667
- if (bytes.byteLength !== file2.bytes || head.size !== file2.bytes || head.metadata?.sha256 !== file2.sha256 || head.metadata?.releaseId !== release.manifest.releaseId || digest(bytes) !== file2.sha256)
12667
+ if (bytes.byteLength !== file2.bytes || head.size !== file2.bytes || head.metadata?.sha256 !== file2.sha256 || (head.metadata?.releaseid ?? head.metadata?.releaseId) !== release.manifest.releaseId || digest(bytes) !== file2.sha256)
12668
12668
  throw new MobileUpdateRegistryError("Stored mobile update file integrity failed");
12669
12669
  return { bytes, file: file2 };
12670
12670
  }
@@ -13023,10 +13023,27 @@ var ABSOLUTE_MOBILE_UPDATE_SERVER_FORMAT = 1, DEFAULT_MOBILE_UPDATE_REGISTRY_MOD
13023
13023
  const registry2 = loaded.default ?? loaded.registry;
13024
13024
  if (!isRegistry2(registry2))
13025
13025
  throw new TypeError("Mobile update registry must implement publication, promotion, rollback, resolution, and file reads.");
13026
+ const metadata2 = serverMetadata(loaded.absoluteMobileUpdateServer);
13027
+ const verifier = loaded.verifyAbsoluteMobileUpdateServer;
13028
+ if (metadata2.storage === "durable" && typeof verifier !== "function")
13029
+ throw new TypeError("Mobile update registries marked durable must export verifyAbsoluteMobileUpdateServer(). Re-run `absolute mobile update provision --storage s3 --force` or provide an active durability check.");
13026
13030
  return {
13027
- metadata: serverMetadata(loaded.absoluteMobileUpdateServer),
13028
- registry: registry2
13031
+ metadata: metadata2,
13032
+ registry: registry2,
13033
+ ...typeof verifier === "function" ? {
13034
+ verifyDurability: async () => {
13035
+ await verifier();
13036
+ }
13037
+ } : {}
13029
13038
  };
13039
+ }, verifyDurableModule = async (module) => {
13040
+ if (module.metadata.storage !== "durable")
13041
+ throw new TypeError("Mobile production updates require durable object storage. Re-run `absolute mobile update provision --storage s3 --force` or configure a durable adapter.");
13042
+ try {
13043
+ await module.verifyDurability?.();
13044
+ } catch (error) {
13045
+ throw new TypeError(`Durable mobile update storage verification failed for ${module.metadata.provider}. Check the bucket, endpoint, credentials, and read/write/delete permissions.`, { cause: error });
13046
+ }
13030
13047
  }, expoSigningOptions = (config) => {
13031
13048
  if (!config.updates?.expoCodeSigning)
13032
13049
  return;
@@ -13058,8 +13075,8 @@ var ABSOLUTE_MOBILE_UPDATE_SERVER_FORMAT = 1, DEFAULT_MOBILE_UPDATE_REGISTRY_MOD
13058
13075
  if (!updates || !server?.autoMount)
13059
13076
  return new Elysia4({ name: "absolutejs-mobile-updates-disabled" });
13060
13077
  const module = await loadAbsoluteMobileUpdateServerModule(projectRoot, server.registryModule);
13061
- if (options.production && module.metadata.storage !== "durable")
13062
- throw new TypeError("Mobile production updates require durable object storage. Re-run `absolute mobile update provision --storage s3 --force` or configure a durable adapter.");
13078
+ if (options.production)
13079
+ await verifyDurableModule(module);
13063
13080
  const manifest = new URL(updates.manifestUrl);
13064
13081
  if (!manifest.pathname.endsWith("/update.json"))
13065
13082
  throw new TypeError("Auto-mounted mobile update manifests must end in /update.json.");
@@ -13077,8 +13094,7 @@ var ABSOLUTE_MOBILE_UPDATE_SERVER_FORMAT = 1, DEFAULT_MOBILE_UPDATE_REGISTRY_MOD
13077
13094
  if (!config.updates)
13078
13095
  return;
13079
13096
  const module = await loadAbsoluteMobileUpdateServerModule(projectRoot, config.updateServer?.registryModule);
13080
- if (module.metadata.storage !== "durable")
13081
- throw new TypeError("Mobile production updates require durable object storage; the configured registry is local-only.");
13097
+ await verifyDurableModule(module);
13082
13098
  if (config.engine === "expo")
13083
13099
  expoSigningOptions(config);
13084
13100
  return module.metadata;
@@ -13105,7 +13121,8 @@ export default createMobileUpdateRegistry({
13105
13121
  store
13106
13122
  });
13107
13123
  `;
13108
- return `import { S3Client } from '@aws-sdk/client-s3';
13124
+ return `import { randomUUID } from 'node:crypto';
13125
+ import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
13109
13126
  import { awsS3BlobStore } from '@absolutejs/blob/aws-s3';
13110
13127
  import { createMobileUpdateRegistry } from '@absolutejs/deploy/mobile-update';
13111
13128
 
@@ -13117,6 +13134,7 @@ const required = (name: string) => {
13117
13134
  return value;
13118
13135
  };
13119
13136
 
13137
+ const bucket = required('ABSOLUTE_MOBILE_UPDATE_S3_BUCKET');
13120
13138
  const client = new S3Client({
13121
13139
  region: process.env.ABSOLUTE_MOBILE_UPDATE_S3_REGION ?? 'auto',
13122
13140
  forcePathStyle: process.env.ABSOLUTE_MOBILE_UPDATE_S3_FORCE_PATH_STYLE === '1',
@@ -13124,10 +13142,22 @@ const client = new S3Client({
13124
13142
  ? { endpoint: process.env.ABSOLUTE_MOBILE_UPDATE_S3_ENDPOINT }
13125
13143
  : {})
13126
13144
  });
13127
- const store = awsS3BlobStore({
13128
- bucket: required('ABSOLUTE_MOBILE_UPDATE_S3_BUCKET'),
13129
- client
13130
- });
13145
+ const store = awsS3BlobStore({ bucket, client });
13146
+
13147
+ export const verifyAbsoluteMobileUpdateServer = async () => {
13148
+ const key = \`absolutejs/mobile-updates/_health/\${randomUUID()}\`;
13149
+ const expected = randomUUID();
13150
+ let stored = false;
13151
+ try {
13152
+ await client.send(new PutObjectCommand({ Bucket: bucket, Key: key, Body: expected }));
13153
+ stored = true;
13154
+ const response = await client.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
13155
+ if ((await response.Body?.transformToString()) !== expected)
13156
+ throw new Error('Durability probe read did not match its write.');
13157
+ } finally {
13158
+ if (stored) await client.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
13159
+ }
13160
+ };
13131
13161
 
13132
13162
  export default createMobileUpdateRegistry({
13133
13163
  publicKeys: ${publicKeysSource(options.publicKeys)},
@@ -44557,5 +44587,5 @@ export {
44557
44587
  wrapPageHandlerWithStreamingSlots
44558
44588
  };
44559
44589
 
44560
- //# debugId=3A3B05A58CB535F264756E2164756E21
44590
+ //# debugId=D254EAF4F11DFBA864756E2164756E21
44561
44591
  //# sourceMappingURL=index.js.map