@hot-updater/azure 1.1.4 → 1.2.0-rc.1
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/functions/index.mjs +894 -418
- package/dist/index.cjs +73 -28
- package/dist/index.mjs +73 -28
- package/dist/init/index.cjs +40 -15
- package/dist/init/index.mjs +40 -15
- package/package.json +6 -6
package/dist/functions/index.mjs
CHANGED
|
@@ -4039,7 +4039,7 @@ const bundleMetadataToRow = (metadata) => {
|
|
|
4039
4039
|
return metadata;
|
|
4040
4040
|
};
|
|
4041
4041
|
//#endregion
|
|
4042
|
-
//#region ../../packages/protocol/dist/
|
|
4042
|
+
//#region ../../packages/protocol/dist/uuid-kZvLA0Ly.mjs
|
|
4043
4043
|
const LETTER_DASH_NUMBER$2 = "[a-zA-Z0-9-]";
|
|
4044
4044
|
const NUMERIC_IDENTIFIER$2 = String.raw`0|[1-9]\d*`;
|
|
4045
4045
|
const NUMERIC_IDENTIFIER_LOOSE$2 = String.raw`\d+`;
|
|
@@ -4146,128 +4146,6 @@ function canonicalizeAppVersion(appVersion) {
|
|
|
4146
4146
|
const version = coerce$1(appVersion);
|
|
4147
4147
|
return version ? normalizeFull(version) : null;
|
|
4148
4148
|
}
|
|
4149
|
-
const getManifestStorageUri = (bundle) => bundle.manifestStorageUri;
|
|
4150
|
-
const getManifestFileHash = (bundle) => bundle.manifestFileHash;
|
|
4151
|
-
const getAssetBaseStorageUri = (bundle) => bundle.assetBaseStorageUri;
|
|
4152
|
-
const isBundlePatchArtifact = (value) => {
|
|
4153
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
4154
|
-
const candidate = value;
|
|
4155
|
-
return typeof candidate.baseBundleId === "string" && typeof candidate.baseFileHash === "string" && typeof candidate.patchFileHash === "string" && typeof candidate.patchStorageUri === "string";
|
|
4156
|
-
};
|
|
4157
|
-
const readBundlePatchArray = (patches) => {
|
|
4158
|
-
if (!Array.isArray(patches)) return [];
|
|
4159
|
-
return patches.filter(isBundlePatchArtifact);
|
|
4160
|
-
};
|
|
4161
|
-
const getBundlePatches = (bundle) => {
|
|
4162
|
-
const patches = readBundlePatchArray(bundle.patches);
|
|
4163
|
-
const seenBaseBundleIds = /* @__PURE__ */ new Set();
|
|
4164
|
-
return patches.filter((patch) => {
|
|
4165
|
-
if (seenBaseBundleIds.has(patch.baseBundleId)) return false;
|
|
4166
|
-
seenBaseBundleIds.add(patch.baseBundleId);
|
|
4167
|
-
return true;
|
|
4168
|
-
});
|
|
4169
|
-
};
|
|
4170
|
-
const getBundlePatch = (bundle, baseBundleId) => {
|
|
4171
|
-
return getBundlePatches(bundle).find((patch) => patch.baseBundleId === baseBundleId) ?? null;
|
|
4172
|
-
};
|
|
4173
|
-
const NUMERIC_COHORT_SIZE = 1e3;
|
|
4174
|
-
const DEFAULT_ROLLOUT_COHORT_COUNT = NUMERIC_COHORT_SIZE;
|
|
4175
|
-
const CUSTOM_COHORT_PATTERN = /^[a-z0-9-]+$/;
|
|
4176
|
-
function parseNumericCohortValue(cohort) {
|
|
4177
|
-
if (!/^\d+$/.test(cohort)) return null;
|
|
4178
|
-
const parsed = Number.parseInt(cohort, 10);
|
|
4179
|
-
if (Number.isNaN(parsed) || parsed < 1 || parsed > 1e3) return null;
|
|
4180
|
-
return parsed;
|
|
4181
|
-
}
|
|
4182
|
-
function positiveMod(value, modulus) {
|
|
4183
|
-
return (value % modulus + modulus) % modulus;
|
|
4184
|
-
}
|
|
4185
|
-
function hashString(value) {
|
|
4186
|
-
let hash = 0;
|
|
4187
|
-
for (let i = 0; i < value.length; i++) {
|
|
4188
|
-
const char = value.charCodeAt(i);
|
|
4189
|
-
hash = (hash << 5) - hash + char;
|
|
4190
|
-
hash |= 0;
|
|
4191
|
-
}
|
|
4192
|
-
return hash;
|
|
4193
|
-
}
|
|
4194
|
-
function gcd(a, b) {
|
|
4195
|
-
let x = Math.abs(a);
|
|
4196
|
-
let y = Math.abs(b);
|
|
4197
|
-
while (y !== 0) {
|
|
4198
|
-
const next = x % y;
|
|
4199
|
-
x = y;
|
|
4200
|
-
y = next;
|
|
4201
|
-
}
|
|
4202
|
-
return x;
|
|
4203
|
-
}
|
|
4204
|
-
function modularInverse(value, modulus) {
|
|
4205
|
-
let t = 0;
|
|
4206
|
-
let newT = 1;
|
|
4207
|
-
let r = modulus;
|
|
4208
|
-
let newR = positiveMod(value, modulus);
|
|
4209
|
-
while (newR !== 0) {
|
|
4210
|
-
const quotient = Math.floor(r / newR);
|
|
4211
|
-
[t, newT] = [newT, t - quotient * newT];
|
|
4212
|
-
[r, newR] = [newR, r - quotient * newR];
|
|
4213
|
-
}
|
|
4214
|
-
if (r > 1) throw new Error(`No modular inverse for ${value} mod ${modulus}`);
|
|
4215
|
-
return positiveMod(t, modulus);
|
|
4216
|
-
}
|
|
4217
|
-
function getRolloutShuffleParameters(bundleId) {
|
|
4218
|
-
let multiplier = positiveMod(hashString(`${bundleId}:multiplier`), 997);
|
|
4219
|
-
if (multiplier === 0) multiplier = 1;
|
|
4220
|
-
while (gcd(multiplier, NUMERIC_COHORT_SIZE) !== 1) {
|
|
4221
|
-
multiplier = positiveMod(multiplier + 1, NUMERIC_COHORT_SIZE);
|
|
4222
|
-
if (multiplier === 0) multiplier = 1;
|
|
4223
|
-
}
|
|
4224
|
-
const offset = positiveMod(hashString(`${bundleId}:offset`), NUMERIC_COHORT_SIZE);
|
|
4225
|
-
return {
|
|
4226
|
-
multiplier,
|
|
4227
|
-
offset,
|
|
4228
|
-
inverseMultiplier: modularInverse(multiplier, NUMERIC_COHORT_SIZE)
|
|
4229
|
-
};
|
|
4230
|
-
}
|
|
4231
|
-
function normalizeRolloutCohortCount(rolloutCohortCount) {
|
|
4232
|
-
if (rolloutCohortCount === null || rolloutCohortCount === void 0) return DEFAULT_ROLLOUT_COHORT_COUNT;
|
|
4233
|
-
if (rolloutCohortCount <= 0) return 0;
|
|
4234
|
-
if (rolloutCohortCount >= 1e3) return NUMERIC_COHORT_SIZE;
|
|
4235
|
-
return Math.floor(rolloutCohortCount);
|
|
4236
|
-
}
|
|
4237
|
-
function normalizeCohortValue(cohort) {
|
|
4238
|
-
const normalized = cohort.trim().toLowerCase();
|
|
4239
|
-
const numericCohort = parseNumericCohortValue(normalized);
|
|
4240
|
-
if (numericCohort !== null) return String(numericCohort);
|
|
4241
|
-
return normalized;
|
|
4242
|
-
}
|
|
4243
|
-
function getNumericCohortValue(cohort) {
|
|
4244
|
-
return parseNumericCohortValue(normalizeCohortValue(cohort));
|
|
4245
|
-
}
|
|
4246
|
-
function isNumericCohort(cohort) {
|
|
4247
|
-
return getNumericCohortValue(cohort) !== null;
|
|
4248
|
-
}
|
|
4249
|
-
function isCustomCohort(cohort) {
|
|
4250
|
-
const normalized = normalizeCohortValue(cohort);
|
|
4251
|
-
return normalized.length > 0 && normalized.length <= 64 && !/^\d+$/.test(normalized) && CUSTOM_COHORT_PATTERN.test(normalized);
|
|
4252
|
-
}
|
|
4253
|
-
function isValidCohort(cohort) {
|
|
4254
|
-
const normalized = normalizeCohortValue(cohort);
|
|
4255
|
-
return isNumericCohort(normalized) || isCustomCohort(normalized);
|
|
4256
|
-
}
|
|
4257
|
-
function getNumericCohortRolloutPosition(bundleId, cohortValue) {
|
|
4258
|
-
if (cohortValue < 1 || cohortValue > 1e3) throw new Error(`Invalid numeric cohort: ${cohortValue}`);
|
|
4259
|
-
const { offset, inverseMultiplier } = getRolloutShuffleParameters(bundleId);
|
|
4260
|
-
return positiveMod(inverseMultiplier * (cohortValue - 1 - offset), NUMERIC_COHORT_SIZE);
|
|
4261
|
-
}
|
|
4262
|
-
function getRolledOutNumericCohorts(bundleId, rolloutCohortCount) {
|
|
4263
|
-
const normalizedRolloutCount = normalizeRolloutCohortCount(rolloutCohortCount);
|
|
4264
|
-
if (normalizedRolloutCount <= 0) return [];
|
|
4265
|
-
if (normalizedRolloutCount >= 1e3) return Array.from({ length: NUMERIC_COHORT_SIZE }, (_, index) => index + 1);
|
|
4266
|
-
const { multiplier, offset } = getRolloutShuffleParameters(bundleId);
|
|
4267
|
-
return Array.from({ length: normalizedRolloutCount }, (_, position) => positiveMod(multiplier * position + offset, NUMERIC_COHORT_SIZE)).map((zeroBasedCohort) => zeroBasedCohort + 1).sort((left, right) => left - right);
|
|
4268
|
-
}
|
|
4269
|
-
const RELEASE_CATALOG_FALLBACK_POLICY = "BUILTIN_IF_ACTIVE_INELIGIBLE";
|
|
4270
|
-
const MAX_COMPILED_CATALOG_BYTES = 262144;
|
|
4271
4149
|
const BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
4272
4150
|
const MAX_CATALOG_SEGMENT_LENGTH = 255;
|
|
4273
4151
|
function assertCatalogSegment(value, name) {
|
|
@@ -4392,6 +4270,130 @@ const NIL_UUID = "00000000-0000-0000-0000-000000000000";
|
|
|
4392
4270
|
const UUID_V7_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
4393
4271
|
const isUUIDv7 = (value) => typeof value === "string" && UUID_V7_PATTERN.test(value);
|
|
4394
4272
|
//#endregion
|
|
4273
|
+
//#region ../../packages/protocol/dist/index.mjs
|
|
4274
|
+
const getManifestStorageUri = (bundle) => bundle.manifestStorageUri;
|
|
4275
|
+
const getManifestFileHash = (bundle) => bundle.manifestFileHash;
|
|
4276
|
+
const getAssetBaseStorageUri = (bundle) => bundle.assetBaseStorageUri;
|
|
4277
|
+
const isBundlePatchArtifact = (value) => {
|
|
4278
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
4279
|
+
const candidate = value;
|
|
4280
|
+
return typeof candidate.baseBundleId === "string" && typeof candidate.baseFileHash === "string" && typeof candidate.patchFileHash === "string" && typeof candidate.patchStorageUri === "string";
|
|
4281
|
+
};
|
|
4282
|
+
const readBundlePatchArray = (patches) => {
|
|
4283
|
+
if (!Array.isArray(patches)) return [];
|
|
4284
|
+
return patches.filter(isBundlePatchArtifact);
|
|
4285
|
+
};
|
|
4286
|
+
const getBundlePatches = (bundle) => {
|
|
4287
|
+
const patches = readBundlePatchArray(bundle.patches);
|
|
4288
|
+
const seenBaseBundleIds = /* @__PURE__ */ new Set();
|
|
4289
|
+
return patches.filter((patch) => {
|
|
4290
|
+
if (seenBaseBundleIds.has(patch.baseBundleId)) return false;
|
|
4291
|
+
seenBaseBundleIds.add(patch.baseBundleId);
|
|
4292
|
+
return true;
|
|
4293
|
+
});
|
|
4294
|
+
};
|
|
4295
|
+
const getBundlePatch = (bundle, baseBundleId) => {
|
|
4296
|
+
return getBundlePatches(bundle).find((patch) => patch.baseBundleId === baseBundleId) ?? null;
|
|
4297
|
+
};
|
|
4298
|
+
const NUMERIC_COHORT_SIZE = 1e3;
|
|
4299
|
+
const DEFAULT_ROLLOUT_COHORT_COUNT = NUMERIC_COHORT_SIZE;
|
|
4300
|
+
const CUSTOM_COHORT_PATTERN = /^[a-z0-9-]+$/;
|
|
4301
|
+
function parseNumericCohortValue(cohort) {
|
|
4302
|
+
if (!/^\d+$/.test(cohort)) return null;
|
|
4303
|
+
const parsed = Number.parseInt(cohort, 10);
|
|
4304
|
+
if (Number.isNaN(parsed) || parsed < 1 || parsed > 1e3) return null;
|
|
4305
|
+
return parsed;
|
|
4306
|
+
}
|
|
4307
|
+
function positiveMod(value, modulus) {
|
|
4308
|
+
return (value % modulus + modulus) % modulus;
|
|
4309
|
+
}
|
|
4310
|
+
function hashString(value) {
|
|
4311
|
+
let hash = 0;
|
|
4312
|
+
for (let i = 0; i < value.length; i++) {
|
|
4313
|
+
const char = value.charCodeAt(i);
|
|
4314
|
+
hash = (hash << 5) - hash + char;
|
|
4315
|
+
hash |= 0;
|
|
4316
|
+
}
|
|
4317
|
+
return hash;
|
|
4318
|
+
}
|
|
4319
|
+
function gcd(a, b) {
|
|
4320
|
+
let x = Math.abs(a);
|
|
4321
|
+
let y = Math.abs(b);
|
|
4322
|
+
while (y !== 0) {
|
|
4323
|
+
const next = x % y;
|
|
4324
|
+
x = y;
|
|
4325
|
+
y = next;
|
|
4326
|
+
}
|
|
4327
|
+
return x;
|
|
4328
|
+
}
|
|
4329
|
+
function modularInverse(value, modulus) {
|
|
4330
|
+
let t = 0;
|
|
4331
|
+
let newT = 1;
|
|
4332
|
+
let r = modulus;
|
|
4333
|
+
let newR = positiveMod(value, modulus);
|
|
4334
|
+
while (newR !== 0) {
|
|
4335
|
+
const quotient = Math.floor(r / newR);
|
|
4336
|
+
[t, newT] = [newT, t - quotient * newT];
|
|
4337
|
+
[r, newR] = [newR, r - quotient * newR];
|
|
4338
|
+
}
|
|
4339
|
+
if (r > 1) throw new Error(`No modular inverse for ${value} mod ${modulus}`);
|
|
4340
|
+
return positiveMod(t, modulus);
|
|
4341
|
+
}
|
|
4342
|
+
function getRolloutShuffleParameters(bundleId) {
|
|
4343
|
+
let multiplier = positiveMod(hashString(`${bundleId}:multiplier`), 997);
|
|
4344
|
+
if (multiplier === 0) multiplier = 1;
|
|
4345
|
+
while (gcd(multiplier, NUMERIC_COHORT_SIZE) !== 1) {
|
|
4346
|
+
multiplier = positiveMod(multiplier + 1, NUMERIC_COHORT_SIZE);
|
|
4347
|
+
if (multiplier === 0) multiplier = 1;
|
|
4348
|
+
}
|
|
4349
|
+
const offset = positiveMod(hashString(`${bundleId}:offset`), NUMERIC_COHORT_SIZE);
|
|
4350
|
+
return {
|
|
4351
|
+
multiplier,
|
|
4352
|
+
offset,
|
|
4353
|
+
inverseMultiplier: modularInverse(multiplier, NUMERIC_COHORT_SIZE)
|
|
4354
|
+
};
|
|
4355
|
+
}
|
|
4356
|
+
function normalizeRolloutCohortCount(rolloutCohortCount) {
|
|
4357
|
+
if (rolloutCohortCount === null || rolloutCohortCount === void 0) return DEFAULT_ROLLOUT_COHORT_COUNT;
|
|
4358
|
+
if (rolloutCohortCount <= 0) return 0;
|
|
4359
|
+
if (rolloutCohortCount >= 1e3) return NUMERIC_COHORT_SIZE;
|
|
4360
|
+
return Math.floor(rolloutCohortCount);
|
|
4361
|
+
}
|
|
4362
|
+
function normalizeCohortValue(cohort) {
|
|
4363
|
+
const normalized = cohort.trim().toLowerCase();
|
|
4364
|
+
const numericCohort = parseNumericCohortValue(normalized);
|
|
4365
|
+
if (numericCohort !== null) return String(numericCohort);
|
|
4366
|
+
return normalized;
|
|
4367
|
+
}
|
|
4368
|
+
function getNumericCohortValue(cohort) {
|
|
4369
|
+
return parseNumericCohortValue(normalizeCohortValue(cohort));
|
|
4370
|
+
}
|
|
4371
|
+
function isNumericCohort(cohort) {
|
|
4372
|
+
return getNumericCohortValue(cohort) !== null;
|
|
4373
|
+
}
|
|
4374
|
+
function isCustomCohort(cohort) {
|
|
4375
|
+
const normalized = normalizeCohortValue(cohort);
|
|
4376
|
+
return normalized.length > 0 && normalized.length <= 64 && !/^\d+$/.test(normalized) && CUSTOM_COHORT_PATTERN.test(normalized);
|
|
4377
|
+
}
|
|
4378
|
+
function isValidCohort(cohort) {
|
|
4379
|
+
const normalized = normalizeCohortValue(cohort);
|
|
4380
|
+
return isNumericCohort(normalized) || isCustomCohort(normalized);
|
|
4381
|
+
}
|
|
4382
|
+
function getNumericCohortRolloutPosition(bundleId, cohortValue) {
|
|
4383
|
+
if (cohortValue < 1 || cohortValue > 1e3) throw new Error(`Invalid numeric cohort: ${cohortValue}`);
|
|
4384
|
+
const { offset, inverseMultiplier } = getRolloutShuffleParameters(bundleId);
|
|
4385
|
+
return positiveMod(inverseMultiplier * (cohortValue - 1 - offset), NUMERIC_COHORT_SIZE);
|
|
4386
|
+
}
|
|
4387
|
+
function getRolledOutNumericCohorts(bundleId, rolloutCohortCount) {
|
|
4388
|
+
const normalizedRolloutCount = normalizeRolloutCohortCount(rolloutCohortCount);
|
|
4389
|
+
if (normalizedRolloutCount <= 0) return [];
|
|
4390
|
+
if (normalizedRolloutCount >= 1e3) return Array.from({ length: NUMERIC_COHORT_SIZE }, (_, index) => index + 1);
|
|
4391
|
+
const { multiplier, offset } = getRolloutShuffleParameters(bundleId);
|
|
4392
|
+
return Array.from({ length: normalizedRolloutCount }, (_, position) => positiveMod(multiplier * position + offset, NUMERIC_COHORT_SIZE)).map((zeroBasedCohort) => zeroBasedCohort + 1).sort((left, right) => left - right);
|
|
4393
|
+
}
|
|
4394
|
+
const RELEASE_CATALOG_FALLBACK_POLICY = "BUILTIN_IF_ACTIVE_INELIGIBLE";
|
|
4395
|
+
const MAX_COMPILED_CATALOG_BYTES = 262144;
|
|
4396
|
+
//#endregion
|
|
4395
4397
|
//#region ../plugin-core/dist/databaseRows.mjs
|
|
4396
4398
|
const releaseRowToRelease = (row) => ({
|
|
4397
4399
|
id: row.id,
|
|
@@ -5631,10 +5633,11 @@ const SETTINGS_TABLE = {
|
|
|
5631
5633
|
const ENGINE_SCHEMA_KEY = "schema.engine";
|
|
5632
5634
|
const CORE_SCHEMA_KEY = "schema.core";
|
|
5633
5635
|
const stored = ({ key, expected, found }) => `"${key}" is ${found === null ? "missing" : `"${found}"`}; expected "${expected}"`;
|
|
5634
|
-
const
|
|
5636
|
+
const MIGRATE_SCHEMA_FIX = "Run `npx hot-updater doctor` in the project whose hot-updater.config.ts names this database: it names the command that migrates it. In a server project, `hot-updater db migrate` migrates the database its server file names.";
|
|
5637
|
+
const settingMessage = (adapterName, { key, expected, found }) => `Hot Updater schema setting "${key}" for ${adapterName} is ${found === null ? "missing" : `"${found}"`}; expected "${expected}". ${MIGRATE_SCHEMA_FIX}`;
|
|
5635
5638
|
const pluginOf = ({ key }) => key.startsWith("schema.") && key !== "schema.engine" && key !== CORE_SCHEMA_KEY ? key.slice(7) : void 0;
|
|
5636
5639
|
const listed = (items) => items.length < 2 ? items.join("") : `${items.slice(0, -1).join(", ")} and ${items.at(-1)}`;
|
|
5637
|
-
const
|
|
5640
|
+
const settingsMessage = (adapterName, settings) => `Hot Updater schema settings for ${adapterName} are not migrated: ${settings.map(stored).join(", and ")}. ${MIGRATE_SCHEMA_FIX}`;
|
|
5638
5641
|
const pluginsMessage = (adapterName, plugins, settings, fix) => `The tables of ${plugins.length === 1 ? "plugin" : "plugins"} ${listed(plugins.map((id) => `"${id}"`))} are not migrated on ${adapterName}: schema ${settings.length === 1 ? "setting" : "settings"} ${settings.map(stored).join(", and ")}. ${fix}`;
|
|
5639
5642
|
var HotUpdaterSchemaMigrationRequiredError = class extends Error {
|
|
5640
5643
|
adapterName;
|
|
@@ -5645,7 +5648,7 @@ var HotUpdaterSchemaMigrationRequiredError = class extends Error {
|
|
|
5645
5648
|
constructor(adapterName, currentVersion, setting, options) {
|
|
5646
5649
|
const settings = options?.settings ?? (setting === void 0 ? [] : [setting]);
|
|
5647
5650
|
const plugins = settings.flatMap((mismatch) => pluginOf(mismatch) ?? []);
|
|
5648
|
-
super(setting === void 0 ? currentVersion === void 0 ? `Hot Updater database schema is not initialized for ${adapterName}.
|
|
5651
|
+
super(setting === void 0 ? currentVersion === void 0 ? `Hot Updater database schema is not initialized for ${adapterName}. ${MIGRATE_SCHEMA_FIX}` : `Hot Updater v1 cannot migrate schema ${currentVersion} in place. Create a new empty database and run \`hot-updater db migrate\`.` : plugins.length > 0 && plugins.length === settings.length ? pluginsMessage(adapterName, plugins, settings, options?.fix ?? MIGRATE_SCHEMA_FIX) : settings.length > 1 && !(setting.key === "schema.engine" && setting.found === null) ? settingsMessage(adapterName, settings) : settingMessage(adapterName, setting), options?.cause === void 0 ? void 0 : { cause: options.cause });
|
|
5649
5652
|
this.adapterName = adapterName;
|
|
5650
5653
|
this.currentVersion = currentVersion;
|
|
5651
5654
|
this.setting = setting;
|
|
@@ -5698,11 +5701,23 @@ const checkSchemaFence = async (adapter, adapterName, expected, fix) => {
|
|
|
5698
5701
|
});
|
|
5699
5702
|
};
|
|
5700
5703
|
const FENCED = Symbol.for("@hot-updater/server/schema-fence");
|
|
5704
|
+
const FENCED_SETTINGS = Symbol.for("@hot-updater/server/schema-fence-settings");
|
|
5701
5705
|
const fencedName = (adapter) => adapter[FENCED];
|
|
5702
5706
|
const withSchemaFence = (adapter, adapterName, expected, fix) => {
|
|
5707
|
+
const inner = adapter[FENCED_SETTINGS];
|
|
5708
|
+
const settings = inner === void 0 ? {
|
|
5709
|
+
adapter,
|
|
5710
|
+
expected
|
|
5711
|
+
} : {
|
|
5712
|
+
adapter: inner.adapter,
|
|
5713
|
+
expected: {
|
|
5714
|
+
...inner.expected,
|
|
5715
|
+
...expected
|
|
5716
|
+
}
|
|
5717
|
+
};
|
|
5703
5718
|
let ready;
|
|
5704
5719
|
const fence = () => {
|
|
5705
|
-
ready ??= checkSchemaFence(adapter, adapterName, expected, fix).catch((error) => {
|
|
5720
|
+
ready ??= checkSchemaFence(settings.adapter, adapterName, settings.expected, fix).catch((error) => {
|
|
5706
5721
|
ready = void 0;
|
|
5707
5722
|
throw error;
|
|
5708
5723
|
});
|
|
@@ -5711,6 +5726,7 @@ const withSchemaFence = (adapter, adapterName, expected, fix) => {
|
|
|
5711
5726
|
return {
|
|
5712
5727
|
...adapter,
|
|
5713
5728
|
[FENCED]: adapterName,
|
|
5729
|
+
[FENCED_SETTINGS]: settings,
|
|
5714
5730
|
get: (table, keys) => fence().then(() => adapter.get(table, keys)),
|
|
5715
5731
|
query: (table, request) => fence().then(() => adapter.query(table, request)),
|
|
5716
5732
|
write: (ops) => fence().then(() => adapter.write(ops)),
|
|
@@ -5765,257 +5781,360 @@ const CHANNEL_ID = {
|
|
|
5765
5781
|
maxLength: 1408,
|
|
5766
5782
|
ascii: true
|
|
5767
5783
|
};
|
|
5768
|
-
const HOT_UPDATER_SCHEMA_VERSION = "1.
|
|
5784
|
+
const HOT_UPDATER_SCHEMA_VERSION = "1.2.0";
|
|
5785
|
+
const bundles = defineTable({
|
|
5786
|
+
id: {
|
|
5787
|
+
type: "string",
|
|
5788
|
+
maxLength: 36
|
|
5789
|
+
},
|
|
5790
|
+
platform: {
|
|
5791
|
+
type: "string",
|
|
5792
|
+
maxLength: 16
|
|
5793
|
+
},
|
|
5794
|
+
git_commit_hash: {
|
|
5795
|
+
type: "string",
|
|
5796
|
+
maxLength: 255,
|
|
5797
|
+
required: false
|
|
5798
|
+
},
|
|
5799
|
+
metadata: { type: "json" },
|
|
5800
|
+
manifest_storage_uri: { type: "string" },
|
|
5801
|
+
manifest_file_hash: { type: "string" },
|
|
5802
|
+
asset_base_storage_uri: { type: "string" }
|
|
5803
|
+
}, {
|
|
5804
|
+
key: ["id"],
|
|
5805
|
+
indexes: {
|
|
5806
|
+
byPlatform: {
|
|
5807
|
+
eq: ["platform"],
|
|
5808
|
+
sort: ["id"]
|
|
5809
|
+
},
|
|
5810
|
+
all: {
|
|
5811
|
+
eq: [],
|
|
5812
|
+
sort: ["id"]
|
|
5813
|
+
}
|
|
5814
|
+
}
|
|
5815
|
+
});
|
|
5816
|
+
const bundlePatches = defineTable({
|
|
5817
|
+
id: {
|
|
5818
|
+
type: "string",
|
|
5819
|
+
maxLength: 255
|
|
5820
|
+
},
|
|
5821
|
+
bundle_id: {
|
|
5822
|
+
type: "string",
|
|
5823
|
+
maxLength: 36,
|
|
5824
|
+
references: {
|
|
5825
|
+
model: "bundles",
|
|
5826
|
+
onDelete: "cascade"
|
|
5827
|
+
}
|
|
5828
|
+
},
|
|
5829
|
+
base_bundle_id: {
|
|
5830
|
+
type: "string",
|
|
5831
|
+
maxLength: 36,
|
|
5832
|
+
references: {
|
|
5833
|
+
model: "bundles",
|
|
5834
|
+
onDelete: "cascade"
|
|
5835
|
+
}
|
|
5836
|
+
},
|
|
5837
|
+
base_file_hash: { type: "string" },
|
|
5838
|
+
patch_file_hash: { type: "string" },
|
|
5839
|
+
patch_storage_uri: { type: "string" },
|
|
5840
|
+
byte_size: { type: "integer" },
|
|
5841
|
+
order_index: { type: "integer" }
|
|
5842
|
+
}, {
|
|
5843
|
+
key: ["id"],
|
|
5844
|
+
indexes: {
|
|
5845
|
+
pair: {
|
|
5846
|
+
eq: ["bundle_id", "base_bundle_id"],
|
|
5847
|
+
sort: [],
|
|
5848
|
+
unique: true
|
|
5849
|
+
},
|
|
5850
|
+
byBundle: {
|
|
5851
|
+
eq: ["bundle_id"],
|
|
5852
|
+
sort: ["order_index"],
|
|
5853
|
+
root: { model: "bundles" }
|
|
5854
|
+
},
|
|
5855
|
+
byBase: {
|
|
5856
|
+
eq: ["base_bundle_id"],
|
|
5857
|
+
sort: ["bundle_id"]
|
|
5858
|
+
}
|
|
5859
|
+
}
|
|
5860
|
+
});
|
|
5861
|
+
const releases = defineTable({
|
|
5862
|
+
id: {
|
|
5863
|
+
type: "string",
|
|
5864
|
+
maxLength: 36
|
|
5865
|
+
},
|
|
5866
|
+
revision: { type: "integer" },
|
|
5867
|
+
scope_key: {
|
|
5868
|
+
type: "string",
|
|
5869
|
+
maxLength: 2048,
|
|
5870
|
+
ascii: true
|
|
5871
|
+
},
|
|
5872
|
+
channel_id: {
|
|
5873
|
+
...CHANNEL_ID,
|
|
5874
|
+
references: {
|
|
5875
|
+
model: "channels",
|
|
5876
|
+
onDelete: "restrict"
|
|
5877
|
+
}
|
|
5878
|
+
},
|
|
5879
|
+
platform: {
|
|
5880
|
+
type: "string",
|
|
5881
|
+
maxLength: 16
|
|
5882
|
+
},
|
|
5883
|
+
kind: {
|
|
5884
|
+
type: "string",
|
|
5885
|
+
maxLength: 16
|
|
5886
|
+
},
|
|
5887
|
+
bundle_id: {
|
|
5888
|
+
type: "string",
|
|
5889
|
+
maxLength: 36,
|
|
5890
|
+
required: false,
|
|
5891
|
+
references: {
|
|
5892
|
+
model: "bundles",
|
|
5893
|
+
onDelete: "restrict"
|
|
5894
|
+
}
|
|
5895
|
+
},
|
|
5896
|
+
strategy: {
|
|
5897
|
+
type: "string",
|
|
5898
|
+
maxLength: 16
|
|
5899
|
+
},
|
|
5900
|
+
target_app_version: {
|
|
5901
|
+
type: "string",
|
|
5902
|
+
required: false
|
|
5903
|
+
},
|
|
5904
|
+
fingerprint_hash: {
|
|
5905
|
+
type: "string",
|
|
5906
|
+
maxLength: 255,
|
|
5907
|
+
required: false
|
|
5908
|
+
},
|
|
5909
|
+
enabled: { type: "boolean" },
|
|
5910
|
+
should_force_update: { type: "boolean" },
|
|
5911
|
+
message: {
|
|
5912
|
+
type: "string",
|
|
5913
|
+
required: false
|
|
5914
|
+
},
|
|
5915
|
+
rollout_cohort_count: { type: "integer" },
|
|
5916
|
+
target_cohorts: { type: "json" },
|
|
5917
|
+
operation: {
|
|
5918
|
+
type: "string",
|
|
5919
|
+
maxLength: 16
|
|
5920
|
+
},
|
|
5921
|
+
source_release_id: {
|
|
5922
|
+
type: "string",
|
|
5923
|
+
maxLength: 36,
|
|
5924
|
+
required: false,
|
|
5925
|
+
references: {
|
|
5926
|
+
model: "releases",
|
|
5927
|
+
onDelete: "none"
|
|
5928
|
+
}
|
|
5929
|
+
},
|
|
5930
|
+
created_at_ms: { type: "integer" },
|
|
5931
|
+
updated_at_ms: { type: "integer" }
|
|
5932
|
+
}, {
|
|
5933
|
+
key: ["id"],
|
|
5934
|
+
indexes: {
|
|
5935
|
+
byScope: {
|
|
5936
|
+
eq: ["scope_key"],
|
|
5937
|
+
sort: ["id"],
|
|
5938
|
+
root: { model: "release_catalogs" }
|
|
5939
|
+
},
|
|
5940
|
+
byScopeEnabled: {
|
|
5941
|
+
eq: ["scope_key", "enabled"],
|
|
5942
|
+
sort: ["id"],
|
|
5943
|
+
root: { model: "release_catalogs" }
|
|
5944
|
+
},
|
|
5945
|
+
byChannelPlatform: {
|
|
5946
|
+
eq: ["channel_id", "platform"],
|
|
5947
|
+
sort: ["id"]
|
|
5948
|
+
},
|
|
5949
|
+
byChannelPlatformEnabled: {
|
|
5950
|
+
eq: [
|
|
5951
|
+
"channel_id",
|
|
5952
|
+
"platform",
|
|
5953
|
+
"enabled"
|
|
5954
|
+
],
|
|
5955
|
+
sort: ["id"]
|
|
5956
|
+
},
|
|
5957
|
+
byBundle: {
|
|
5958
|
+
eq: ["bundle_id"],
|
|
5959
|
+
sort: ["id"]
|
|
5960
|
+
},
|
|
5961
|
+
all: {
|
|
5962
|
+
eq: [],
|
|
5963
|
+
sort: ["id"]
|
|
5964
|
+
}
|
|
5965
|
+
}
|
|
5966
|
+
});
|
|
5967
|
+
const releaseCatalogs = defineTable({
|
|
5968
|
+
scope_key: {
|
|
5969
|
+
type: "string",
|
|
5970
|
+
maxLength: 2048,
|
|
5971
|
+
ascii: true
|
|
5972
|
+
},
|
|
5973
|
+
catalog_id: {
|
|
5974
|
+
type: "string",
|
|
5975
|
+
maxLength: 255
|
|
5976
|
+
},
|
|
5977
|
+
strategy: {
|
|
5978
|
+
type: "string",
|
|
5979
|
+
maxLength: 16
|
|
5980
|
+
},
|
|
5981
|
+
channel_id: {
|
|
5982
|
+
...CHANNEL_ID,
|
|
5983
|
+
references: {
|
|
5984
|
+
model: "channels",
|
|
5985
|
+
onDelete: "none"
|
|
5986
|
+
}
|
|
5987
|
+
},
|
|
5988
|
+
channel_key: {
|
|
5989
|
+
type: "string",
|
|
5990
|
+
maxLength: 1400,
|
|
5991
|
+
ascii: true
|
|
5992
|
+
},
|
|
5993
|
+
platform: {
|
|
5994
|
+
type: "string",
|
|
5995
|
+
maxLength: 16
|
|
5996
|
+
},
|
|
5997
|
+
fingerprint_hash: {
|
|
5998
|
+
type: "string",
|
|
5999
|
+
maxLength: 255,
|
|
6000
|
+
required: false
|
|
6001
|
+
},
|
|
6002
|
+
generation: { type: "integer" },
|
|
6003
|
+
payload: { type: "string" },
|
|
6004
|
+
catalog_hash: {
|
|
6005
|
+
type: "string",
|
|
6006
|
+
maxLength: 71
|
|
6007
|
+
},
|
|
6008
|
+
byte_size: { type: "integer" },
|
|
6009
|
+
is_tombstone: { type: "boolean" },
|
|
6010
|
+
updated_at_ms: { type: "integer" }
|
|
6011
|
+
}, {
|
|
6012
|
+
key: ["scope_key"],
|
|
6013
|
+
indexes: { all: {
|
|
6014
|
+
eq: [],
|
|
6015
|
+
sort: ["scope_key"]
|
|
6016
|
+
} }
|
|
6017
|
+
});
|
|
6018
|
+
const channels = defineTable({
|
|
6019
|
+
id: CHANNEL_ID,
|
|
6020
|
+
name: {
|
|
6021
|
+
type: "string",
|
|
6022
|
+
maxLength: 255,
|
|
6023
|
+
unique: true
|
|
6024
|
+
}
|
|
6025
|
+
}, {
|
|
6026
|
+
key: ["id"],
|
|
6027
|
+
indexes: { all: {
|
|
6028
|
+
eq: [],
|
|
6029
|
+
sort: ["name"]
|
|
6030
|
+
} }
|
|
6031
|
+
});
|
|
6032
|
+
const nativeBuilds = defineTable({
|
|
6033
|
+
id: {
|
|
6034
|
+
type: "string",
|
|
6035
|
+
maxLength: 36
|
|
6036
|
+
},
|
|
6037
|
+
scope_key: {
|
|
6038
|
+
type: "string",
|
|
6039
|
+
maxLength: 2048,
|
|
6040
|
+
ascii: true
|
|
6041
|
+
},
|
|
6042
|
+
platform: {
|
|
6043
|
+
type: "string",
|
|
6044
|
+
maxLength: 16
|
|
6045
|
+
},
|
|
6046
|
+
channel_id: {
|
|
6047
|
+
...CHANNEL_ID,
|
|
6048
|
+
references: {
|
|
6049
|
+
model: "channels",
|
|
6050
|
+
onDelete: "none"
|
|
6051
|
+
}
|
|
6052
|
+
},
|
|
6053
|
+
fingerprint_hash: {
|
|
6054
|
+
type: "string",
|
|
6055
|
+
maxLength: 255,
|
|
6056
|
+
required: false
|
|
6057
|
+
},
|
|
6058
|
+
app_version: {
|
|
6059
|
+
type: "string",
|
|
6060
|
+
required: false
|
|
6061
|
+
},
|
|
6062
|
+
min_bundle_id: {
|
|
6063
|
+
type: "string",
|
|
6064
|
+
maxLength: 36,
|
|
6065
|
+
unique: true,
|
|
6066
|
+
references: {
|
|
6067
|
+
model: "bundles",
|
|
6068
|
+
onDelete: "none"
|
|
6069
|
+
}
|
|
6070
|
+
},
|
|
6071
|
+
artifact_kind: {
|
|
6072
|
+
type: "string",
|
|
6073
|
+
maxLength: 16
|
|
6074
|
+
},
|
|
6075
|
+
artifact_storage_uri: { type: "string" },
|
|
6076
|
+
byte_size: { type: "integer" },
|
|
6077
|
+
git_commit_hash: {
|
|
6078
|
+
type: "string",
|
|
6079
|
+
maxLength: 255,
|
|
6080
|
+
required: false
|
|
6081
|
+
},
|
|
6082
|
+
created_at_ms: { type: "integer" },
|
|
6083
|
+
build_key: {
|
|
6084
|
+
type: "string",
|
|
6085
|
+
maxLength: 69,
|
|
6086
|
+
ascii: true,
|
|
6087
|
+
required: false
|
|
6088
|
+
},
|
|
6089
|
+
build_number: {
|
|
6090
|
+
type: "string",
|
|
6091
|
+
maxLength: 64,
|
|
6092
|
+
required: false
|
|
6093
|
+
},
|
|
6094
|
+
submitted_to: {
|
|
6095
|
+
type: "string",
|
|
6096
|
+
maxLength: 16,
|
|
6097
|
+
required: false
|
|
6098
|
+
},
|
|
6099
|
+
submitted_at_ms: {
|
|
6100
|
+
type: "integer",
|
|
6101
|
+
required: false
|
|
6102
|
+
},
|
|
6103
|
+
submitted_version: {
|
|
6104
|
+
type: "string",
|
|
6105
|
+
maxLength: 255,
|
|
6106
|
+
required: false
|
|
6107
|
+
}
|
|
6108
|
+
}, {
|
|
6109
|
+
key: ["id"],
|
|
6110
|
+
indexes: {
|
|
6111
|
+
byScope: {
|
|
6112
|
+
eq: ["scope_key"],
|
|
6113
|
+
sort: ["id"]
|
|
6114
|
+
},
|
|
6115
|
+
byBuildKey: {
|
|
6116
|
+
eq: ["scope_key", "build_key"],
|
|
6117
|
+
sort: ["id"]
|
|
6118
|
+
},
|
|
6119
|
+
byChannel: {
|
|
6120
|
+
eq: ["channel_id"],
|
|
6121
|
+
sort: ["id"],
|
|
6122
|
+
root: { model: "channels" }
|
|
6123
|
+
},
|
|
6124
|
+
all: {
|
|
6125
|
+
eq: [],
|
|
6126
|
+
sort: ["id"]
|
|
6127
|
+
}
|
|
6128
|
+
}
|
|
6129
|
+
});
|
|
5769
6130
|
const coreModule = {
|
|
5770
6131
|
id: "core",
|
|
5771
6132
|
schema: {
|
|
5772
|
-
bundles
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
platform: {
|
|
5778
|
-
type: "string",
|
|
5779
|
-
maxLength: 16
|
|
5780
|
-
},
|
|
5781
|
-
git_commit_hash: {
|
|
5782
|
-
type: "string",
|
|
5783
|
-
maxLength: 255,
|
|
5784
|
-
required: false
|
|
5785
|
-
},
|
|
5786
|
-
metadata: { type: "json" },
|
|
5787
|
-
manifest_storage_uri: { type: "string" },
|
|
5788
|
-
manifest_file_hash: { type: "string" },
|
|
5789
|
-
asset_base_storage_uri: { type: "string" }
|
|
5790
|
-
}, {
|
|
5791
|
-
key: ["id"],
|
|
5792
|
-
indexes: {
|
|
5793
|
-
byPlatform: {
|
|
5794
|
-
eq: ["platform"],
|
|
5795
|
-
sort: ["id"]
|
|
5796
|
-
},
|
|
5797
|
-
all: {
|
|
5798
|
-
eq: [],
|
|
5799
|
-
sort: ["id"]
|
|
5800
|
-
}
|
|
5801
|
-
}
|
|
5802
|
-
}),
|
|
5803
|
-
bundle_patches: defineTable({
|
|
5804
|
-
id: {
|
|
5805
|
-
type: "string",
|
|
5806
|
-
maxLength: 255
|
|
5807
|
-
},
|
|
5808
|
-
bundle_id: {
|
|
5809
|
-
type: "string",
|
|
5810
|
-
maxLength: 36,
|
|
5811
|
-
references: {
|
|
5812
|
-
model: "bundles",
|
|
5813
|
-
onDelete: "cascade"
|
|
5814
|
-
}
|
|
5815
|
-
},
|
|
5816
|
-
base_bundle_id: {
|
|
5817
|
-
type: "string",
|
|
5818
|
-
maxLength: 36,
|
|
5819
|
-
references: {
|
|
5820
|
-
model: "bundles",
|
|
5821
|
-
onDelete: "cascade"
|
|
5822
|
-
}
|
|
5823
|
-
},
|
|
5824
|
-
base_file_hash: { type: "string" },
|
|
5825
|
-
patch_file_hash: { type: "string" },
|
|
5826
|
-
patch_storage_uri: { type: "string" },
|
|
5827
|
-
byte_size: { type: "integer" },
|
|
5828
|
-
order_index: { type: "integer" }
|
|
5829
|
-
}, {
|
|
5830
|
-
key: ["id"],
|
|
5831
|
-
indexes: {
|
|
5832
|
-
pair: {
|
|
5833
|
-
eq: ["bundle_id", "base_bundle_id"],
|
|
5834
|
-
sort: [],
|
|
5835
|
-
unique: true
|
|
5836
|
-
},
|
|
5837
|
-
byBundle: {
|
|
5838
|
-
eq: ["bundle_id"],
|
|
5839
|
-
sort: ["order_index"],
|
|
5840
|
-
root: { model: "bundles" }
|
|
5841
|
-
},
|
|
5842
|
-
byBase: {
|
|
5843
|
-
eq: ["base_bundle_id"],
|
|
5844
|
-
sort: ["bundle_id"]
|
|
5845
|
-
}
|
|
5846
|
-
}
|
|
5847
|
-
}),
|
|
5848
|
-
releases: defineTable({
|
|
5849
|
-
id: {
|
|
5850
|
-
type: "string",
|
|
5851
|
-
maxLength: 36
|
|
5852
|
-
},
|
|
5853
|
-
revision: { type: "integer" },
|
|
5854
|
-
scope_key: {
|
|
5855
|
-
type: "string",
|
|
5856
|
-
maxLength: 2048,
|
|
5857
|
-
ascii: true
|
|
5858
|
-
},
|
|
5859
|
-
channel_id: {
|
|
5860
|
-
...CHANNEL_ID,
|
|
5861
|
-
references: {
|
|
5862
|
-
model: "channels",
|
|
5863
|
-
onDelete: "restrict"
|
|
5864
|
-
}
|
|
5865
|
-
},
|
|
5866
|
-
platform: {
|
|
5867
|
-
type: "string",
|
|
5868
|
-
maxLength: 16
|
|
5869
|
-
},
|
|
5870
|
-
kind: {
|
|
5871
|
-
type: "string",
|
|
5872
|
-
maxLength: 16
|
|
5873
|
-
},
|
|
5874
|
-
bundle_id: {
|
|
5875
|
-
type: "string",
|
|
5876
|
-
maxLength: 36,
|
|
5877
|
-
required: false,
|
|
5878
|
-
references: {
|
|
5879
|
-
model: "bundles",
|
|
5880
|
-
onDelete: "restrict"
|
|
5881
|
-
}
|
|
5882
|
-
},
|
|
5883
|
-
strategy: {
|
|
5884
|
-
type: "string",
|
|
5885
|
-
maxLength: 16
|
|
5886
|
-
},
|
|
5887
|
-
target_app_version: {
|
|
5888
|
-
type: "string",
|
|
5889
|
-
required: false
|
|
5890
|
-
},
|
|
5891
|
-
fingerprint_hash: {
|
|
5892
|
-
type: "string",
|
|
5893
|
-
maxLength: 255,
|
|
5894
|
-
required: false
|
|
5895
|
-
},
|
|
5896
|
-
enabled: { type: "boolean" },
|
|
5897
|
-
should_force_update: { type: "boolean" },
|
|
5898
|
-
message: {
|
|
5899
|
-
type: "string",
|
|
5900
|
-
required: false
|
|
5901
|
-
},
|
|
5902
|
-
rollout_cohort_count: { type: "integer" },
|
|
5903
|
-
target_cohorts: { type: "json" },
|
|
5904
|
-
operation: {
|
|
5905
|
-
type: "string",
|
|
5906
|
-
maxLength: 16
|
|
5907
|
-
},
|
|
5908
|
-
source_release_id: {
|
|
5909
|
-
type: "string",
|
|
5910
|
-
maxLength: 36,
|
|
5911
|
-
required: false,
|
|
5912
|
-
references: {
|
|
5913
|
-
model: "releases",
|
|
5914
|
-
onDelete: "none"
|
|
5915
|
-
}
|
|
5916
|
-
},
|
|
5917
|
-
created_at_ms: { type: "integer" },
|
|
5918
|
-
updated_at_ms: { type: "integer" }
|
|
5919
|
-
}, {
|
|
5920
|
-
key: ["id"],
|
|
5921
|
-
indexes: {
|
|
5922
|
-
byScope: {
|
|
5923
|
-
eq: ["scope_key"],
|
|
5924
|
-
sort: ["id"],
|
|
5925
|
-
root: { model: "release_catalogs" }
|
|
5926
|
-
},
|
|
5927
|
-
byScopeEnabled: {
|
|
5928
|
-
eq: ["scope_key", "enabled"],
|
|
5929
|
-
sort: ["id"],
|
|
5930
|
-
root: { model: "release_catalogs" }
|
|
5931
|
-
},
|
|
5932
|
-
byChannelPlatform: {
|
|
5933
|
-
eq: ["channel_id", "platform"],
|
|
5934
|
-
sort: ["id"]
|
|
5935
|
-
},
|
|
5936
|
-
byChannelPlatformEnabled: {
|
|
5937
|
-
eq: [
|
|
5938
|
-
"channel_id",
|
|
5939
|
-
"platform",
|
|
5940
|
-
"enabled"
|
|
5941
|
-
],
|
|
5942
|
-
sort: ["id"]
|
|
5943
|
-
},
|
|
5944
|
-
byBundle: {
|
|
5945
|
-
eq: ["bundle_id"],
|
|
5946
|
-
sort: ["id"]
|
|
5947
|
-
},
|
|
5948
|
-
all: {
|
|
5949
|
-
eq: [],
|
|
5950
|
-
sort: ["id"]
|
|
5951
|
-
}
|
|
5952
|
-
}
|
|
5953
|
-
}),
|
|
5954
|
-
release_catalogs: defineTable({
|
|
5955
|
-
scope_key: {
|
|
5956
|
-
type: "string",
|
|
5957
|
-
maxLength: 2048,
|
|
5958
|
-
ascii: true
|
|
5959
|
-
},
|
|
5960
|
-
catalog_id: {
|
|
5961
|
-
type: "string",
|
|
5962
|
-
maxLength: 255
|
|
5963
|
-
},
|
|
5964
|
-
strategy: {
|
|
5965
|
-
type: "string",
|
|
5966
|
-
maxLength: 16
|
|
5967
|
-
},
|
|
5968
|
-
channel_id: {
|
|
5969
|
-
...CHANNEL_ID,
|
|
5970
|
-
references: {
|
|
5971
|
-
model: "channels",
|
|
5972
|
-
onDelete: "none"
|
|
5973
|
-
}
|
|
5974
|
-
},
|
|
5975
|
-
channel_key: {
|
|
5976
|
-
type: "string",
|
|
5977
|
-
maxLength: 1400,
|
|
5978
|
-
ascii: true
|
|
5979
|
-
},
|
|
5980
|
-
platform: {
|
|
5981
|
-
type: "string",
|
|
5982
|
-
maxLength: 16
|
|
5983
|
-
},
|
|
5984
|
-
fingerprint_hash: {
|
|
5985
|
-
type: "string",
|
|
5986
|
-
maxLength: 255,
|
|
5987
|
-
required: false
|
|
5988
|
-
},
|
|
5989
|
-
generation: { type: "integer" },
|
|
5990
|
-
payload: { type: "string" },
|
|
5991
|
-
catalog_hash: {
|
|
5992
|
-
type: "string",
|
|
5993
|
-
maxLength: 71
|
|
5994
|
-
},
|
|
5995
|
-
byte_size: { type: "integer" },
|
|
5996
|
-
is_tombstone: { type: "boolean" },
|
|
5997
|
-
updated_at_ms: { type: "integer" }
|
|
5998
|
-
}, {
|
|
5999
|
-
key: ["scope_key"],
|
|
6000
|
-
indexes: { all: {
|
|
6001
|
-
eq: [],
|
|
6002
|
-
sort: ["scope_key"]
|
|
6003
|
-
} }
|
|
6004
|
-
}),
|
|
6005
|
-
channels: defineTable({
|
|
6006
|
-
id: CHANNEL_ID,
|
|
6007
|
-
name: {
|
|
6008
|
-
type: "string",
|
|
6009
|
-
maxLength: 255,
|
|
6010
|
-
unique: true
|
|
6011
|
-
}
|
|
6012
|
-
}, {
|
|
6013
|
-
key: ["id"],
|
|
6014
|
-
indexes: { all: {
|
|
6015
|
-
eq: [],
|
|
6016
|
-
sort: ["name"]
|
|
6017
|
-
} }
|
|
6018
|
-
}),
|
|
6133
|
+
bundles,
|
|
6134
|
+
bundle_patches: bundlePatches,
|
|
6135
|
+
releases,
|
|
6136
|
+
release_catalogs: releaseCatalogs,
|
|
6137
|
+
channels,
|
|
6019
6138
|
bundle_totals: defineAggregate({ platform_key: {
|
|
6020
6139
|
type: "string",
|
|
6021
6140
|
maxLength: 16
|
|
@@ -6026,7 +6145,8 @@ const coreModule = {
|
|
|
6026
6145
|
eq: ["platform_key"],
|
|
6027
6146
|
sort: []
|
|
6028
6147
|
} }
|
|
6029
|
-
})
|
|
6148
|
+
}),
|
|
6149
|
+
native_builds: nativeBuilds
|
|
6030
6150
|
}
|
|
6031
6151
|
};
|
|
6032
6152
|
//#endregion
|
|
@@ -6995,14 +7115,14 @@ const createEngineMigrator = (options) => {
|
|
|
6995
7115
|
return {
|
|
6996
7116
|
getVersion,
|
|
6997
7117
|
getNameVariants: async () => void 0,
|
|
6998
|
-
next: async () => await getVersion() === "1.
|
|
7118
|
+
next: async () => await getVersion() === "1.2.0" ? void 0 : { version: HOT_UPDATER_SCHEMA_VERSION },
|
|
6999
7119
|
previous: async () => void 0,
|
|
7000
7120
|
up: makeResult,
|
|
7001
7121
|
down: async () => {
|
|
7002
7122
|
throw new Error("No previous schema to migrate to.");
|
|
7003
7123
|
},
|
|
7004
7124
|
migrateTo: async (version, migrate) => {
|
|
7005
|
-
if (version !== "1.
|
|
7125
|
+
if (version !== "1.2.0") throw new Error(`Invalid version ${version}`);
|
|
7006
7126
|
return makeResult(migrate);
|
|
7007
7127
|
},
|
|
7008
7128
|
migrateToLatest: makeResult
|
|
@@ -7697,9 +7817,9 @@ const createDatabaseEngine = ({ batching, now = Date.now, meter, ...options }) =
|
|
|
7697
7817
|
//#region ../plugin-core/dist/engine/createEngine.mjs
|
|
7698
7818
|
const pluginTablesFix = (database) => {
|
|
7699
7819
|
const { createMigrator, generateSchema } = database;
|
|
7700
|
-
const
|
|
7820
|
+
const doctor = "Run `npx hot-updater doctor` in the project whose hot-updater.config.ts names this database: it names the command that migrates it.";
|
|
7701
7821
|
const serverProject = "Run `hot-updater db` commands in the server's project: they load the server file named on the command line, or src/hotUpdater.* or src/db.*, and don't read hot-updater.config.ts.";
|
|
7702
|
-
return createMigrator !== void 0 ?
|
|
7822
|
+
return createMigrator !== void 0 ? `${doctor} In a server project, run \`hot-updater db migrate\`. ${serverProject}` : generateSchema !== void 0 ? `${doctor} On a database \`hot-updater init\` created, that is init again with its saved inputs; for your own server, run \`hot-updater db generate\` and apply the file it writes. ${serverProject}` : `${doctor} On a database \`hot-updater init\` created, that is init again with its saved inputs.`;
|
|
7703
7823
|
};
|
|
7704
7824
|
const createEngine = (database, { plugins = [], now = Date.now } = {}) => {
|
|
7705
7825
|
const modules = /* @__PURE__ */ new Map();
|
|
@@ -7998,7 +8118,7 @@ const createKvAdapter = ({ store, tablePrefix = "" }) => {
|
|
|
7998
8118
|
};
|
|
7999
8119
|
//#endregion
|
|
8000
8120
|
//#region ../../packages/server/dist/version.mjs
|
|
8001
|
-
const HOT_UPDATER_SERVER_VERSION = "1.1
|
|
8121
|
+
const HOT_UPDATER_SERVER_VERSION = "1.2.0-rc.1";
|
|
8002
8122
|
//#endregion
|
|
8003
8123
|
//#region ../../packages/server/dist/handlerVersionRoutes.mjs
|
|
8004
8124
|
const createVersionRouteHandlers = (plugins = []) => {
|
|
@@ -8731,8 +8851,8 @@ const baseBundleIdsOf = (row, range, bundleId, limit) => {
|
|
|
8731
8851
|
//#endregion
|
|
8732
8852
|
//#region ../../packages/server/dist/core/reads.mjs
|
|
8733
8853
|
const PAGE$3 = 500;
|
|
8734
|
-
const pick = (fields) => (row) => Object.fromEntries(fields.map((field) => [field, row[field]]));
|
|
8735
|
-
const toBundleRow = pick([
|
|
8854
|
+
const pick$1 = (fields) => (row) => Object.fromEntries(fields.map((field) => [field, row[field]]));
|
|
8855
|
+
const toBundleRow = pick$1([
|
|
8736
8856
|
"id",
|
|
8737
8857
|
"platform",
|
|
8738
8858
|
"git_commit_hash",
|
|
@@ -8741,7 +8861,7 @@ const toBundleRow = pick([
|
|
|
8741
8861
|
"manifest_file_hash",
|
|
8742
8862
|
"asset_base_storage_uri"
|
|
8743
8863
|
]);
|
|
8744
|
-
const toPatchRow = pick([
|
|
8864
|
+
const toPatchRow = pick$1([
|
|
8745
8865
|
"id",
|
|
8746
8866
|
"bundle_id",
|
|
8747
8867
|
"base_bundle_id",
|
|
@@ -8751,7 +8871,7 @@ const toPatchRow = pick([
|
|
|
8751
8871
|
"byte_size",
|
|
8752
8872
|
"order_index"
|
|
8753
8873
|
]);
|
|
8754
|
-
const toReleaseRow = pick([
|
|
8874
|
+
const toReleaseRow = pick$1([
|
|
8755
8875
|
"id",
|
|
8756
8876
|
"revision",
|
|
8757
8877
|
"scope_key",
|
|
@@ -8772,7 +8892,7 @@ const toReleaseRow = pick([
|
|
|
8772
8892
|
"created_at_ms",
|
|
8773
8893
|
"updated_at_ms"
|
|
8774
8894
|
]);
|
|
8775
|
-
const toCatalogRow = pick([
|
|
8895
|
+
const toCatalogRow = pick$1([
|
|
8776
8896
|
"scope_key",
|
|
8777
8897
|
"catalog_id",
|
|
8778
8898
|
"strategy",
|
|
@@ -8787,7 +8907,7 @@ const toCatalogRow = pick([
|
|
|
8787
8907
|
"is_tombstone",
|
|
8788
8908
|
"updated_at_ms"
|
|
8789
8909
|
]);
|
|
8790
|
-
const toChannelRow = pick(["id", "name"]);
|
|
8910
|
+
const toChannelRow = pick$1(["id", "name"]);
|
|
8791
8911
|
const drain$1 = async (read) => {
|
|
8792
8912
|
const rows = [];
|
|
8793
8913
|
let cursor;
|
|
@@ -8798,6 +8918,7 @@ const drain$1 = async (read) => {
|
|
|
8798
8918
|
} while (cursor !== void 0);
|
|
8799
8919
|
return rows;
|
|
8800
8920
|
};
|
|
8921
|
+
const after = (input) => input.after === void 0 ? {} : { range: (input.order ?? "asc") === "asc" ? { gt: input.after } : { lt: input.after } };
|
|
8801
8922
|
const createCoreReads = (db, storage) => {
|
|
8802
8923
|
const detail = async (row) => {
|
|
8803
8924
|
const count = row._refs_bundle_patches_bundle_id ?? 0;
|
|
@@ -8820,7 +8941,6 @@ const createCoreReads = (db, storage) => {
|
|
|
8820
8941
|
childCount: row._refs_bundle_patches_base_bundle_id ?? 0
|
|
8821
8942
|
};
|
|
8822
8943
|
};
|
|
8823
|
-
const after = (input) => input.after === void 0 ? {} : { range: (input.order ?? "asc") === "asc" ? { gt: input.after } : { lt: input.after } };
|
|
8824
8944
|
return {
|
|
8825
8945
|
async getReleaseCatalog(input) {
|
|
8826
8946
|
const scopeKey = releaseCatalogScopeKeyOf(input);
|
|
@@ -8998,9 +9118,9 @@ const insertBundle = (tx, row) => {
|
|
|
8998
9118
|
tx.create("bundles", row);
|
|
8999
9119
|
countBundle(tx, row.platform, 1);
|
|
9000
9120
|
};
|
|
9001
|
-
const updateBundle = (tx, current, set) => {
|
|
9121
|
+
const updateBundle = (tx, current, set, { counted = true } = {}) => {
|
|
9002
9122
|
tx.update("bundles", current, set);
|
|
9003
|
-
if (set.platform !== void 0 && set.platform !== current.platform) {
|
|
9123
|
+
if (counted && set.platform !== void 0 && set.platform !== current.platform) {
|
|
9004
9124
|
countBundle(tx, current.platform, -1);
|
|
9005
9125
|
countBundle(tx, set.platform, 1);
|
|
9006
9126
|
}
|
|
@@ -9065,10 +9185,223 @@ const deleteChannel = (db, id) => db.transaction(async (tx) => {
|
|
|
9065
9185
|
deleted: false,
|
|
9066
9186
|
reason: "not_empty"
|
|
9067
9187
|
};
|
|
9188
|
+
const { rows: builds } = await tx.findMany("native_builds", {
|
|
9189
|
+
index: "byChannel",
|
|
9190
|
+
where: { channel_id: id },
|
|
9191
|
+
limit: 1
|
|
9192
|
+
});
|
|
9193
|
+
if (builds.length > 0) return {
|
|
9194
|
+
deleted: false,
|
|
9195
|
+
reason: "not_empty"
|
|
9196
|
+
};
|
|
9068
9197
|
await tx.delete("channels", row);
|
|
9069
9198
|
return { deleted: true };
|
|
9070
9199
|
});
|
|
9071
9200
|
//#endregion
|
|
9201
|
+
//#region ../../packages/server/dist/core/nativeBuilds.mjs
|
|
9202
|
+
const ARTIFACT_KINDS = {
|
|
9203
|
+
android: ["apk", "aab"],
|
|
9204
|
+
ios: ["ipa", "app"]
|
|
9205
|
+
};
|
|
9206
|
+
const SCOPE_KEY_MAX_LENGTH = 2048;
|
|
9207
|
+
const GIT_COMMIT_HASH_MAX_LENGTH = 255;
|
|
9208
|
+
const BUILD_KEY = /^nbk1:[0-9a-f]{64}$/;
|
|
9209
|
+
var NativeBuildInputError = class extends TypeError {
|
|
9210
|
+
name = "NativeBuildInputError";
|
|
9211
|
+
};
|
|
9212
|
+
const pick = (row) => ({
|
|
9213
|
+
id: row.id,
|
|
9214
|
+
scope_key: row.scope_key,
|
|
9215
|
+
platform: row.platform,
|
|
9216
|
+
channel_id: row.channel_id,
|
|
9217
|
+
fingerprint_hash: row.fingerprint_hash ?? null,
|
|
9218
|
+
app_version: row.app_version ?? null,
|
|
9219
|
+
min_bundle_id: row.min_bundle_id,
|
|
9220
|
+
artifact_kind: row.artifact_kind,
|
|
9221
|
+
artifact_storage_uri: row.artifact_storage_uri,
|
|
9222
|
+
byte_size: row.byte_size,
|
|
9223
|
+
git_commit_hash: row.git_commit_hash ?? null,
|
|
9224
|
+
created_at_ms: row.created_at_ms,
|
|
9225
|
+
build_key: row.build_key ?? null,
|
|
9226
|
+
build_number: row.build_number ?? null,
|
|
9227
|
+
submitted_to: row.submitted_to ?? null,
|
|
9228
|
+
submitted_at_ms: row.submitted_at_ms ?? null,
|
|
9229
|
+
submitted_version: row.submitted_version ?? null
|
|
9230
|
+
});
|
|
9231
|
+
const SUBMISSION_DESTINATIONS = {
|
|
9232
|
+
android: "play-internal",
|
|
9233
|
+
ios: "testflight"
|
|
9234
|
+
};
|
|
9235
|
+
const BUILD_NUMBER_MAX_LENGTH = 64;
|
|
9236
|
+
const SUBMITTED_VERSION_MAX_LENGTH = 255;
|
|
9237
|
+
const nativeBuildScopeKey = (scope) => {
|
|
9238
|
+
let scopeKey;
|
|
9239
|
+
try {
|
|
9240
|
+
const channelKey = encodeChannelKey(scope.channel);
|
|
9241
|
+
scopeKey = scope.fingerprintHash === null ? `${createReleaseCatalogScopeKey({
|
|
9242
|
+
channelKey,
|
|
9243
|
+
platform: scope.platform,
|
|
9244
|
+
strategy: "APP_VERSION"
|
|
9245
|
+
})}:${encodeURIComponent(scope.appVersion)}` : createReleaseCatalogScopeKey({
|
|
9246
|
+
channelKey,
|
|
9247
|
+
fingerprintHash: scope.fingerprintHash,
|
|
9248
|
+
platform: scope.platform,
|
|
9249
|
+
strategy: "FINGERPRINT"
|
|
9250
|
+
});
|
|
9251
|
+
} catch (error) {
|
|
9252
|
+
throw new NativeBuildInputError(`Invalid native build scope: ${error instanceof Error ? error.message : String(error)}.`);
|
|
9253
|
+
}
|
|
9254
|
+
if (scopeKey.length > SCOPE_KEY_MAX_LENGTH) throw new NativeBuildInputError(`Invalid native build scope: its key is longer than ${SCOPE_KEY_MAX_LENGTH} characters; shorten the channel or app version.`);
|
|
9255
|
+
return scopeKey;
|
|
9256
|
+
};
|
|
9257
|
+
const isBuiltInBundle = async (db, bundleId) => await db.findOne("native_builds", { min_bundle_id: bundleId }) !== null;
|
|
9258
|
+
const problemOf = ({ id, minBundleId, platform, channel, fingerprintHash, appVersion, gitCommitHash, buildKey, buildNumber, artifact }) => {
|
|
9259
|
+
if (!isUUIDv7(id)) return "id must be a UUIDv7";
|
|
9260
|
+
if (!isUUIDv7(minBundleId)) return "minBundleId must be the UUIDv7 a release build compiles in";
|
|
9261
|
+
if (platform !== "ios" && platform !== "android") return "platform must be ios or android";
|
|
9262
|
+
if (channel.trim().length === 0) return "channel is required";
|
|
9263
|
+
if (gitCommitHash !== null && gitCommitHash.length > GIT_COMMIT_HASH_MAX_LENGTH) return `gitCommitHash must be at most ${GIT_COMMIT_HASH_MAX_LENGTH} characters`;
|
|
9264
|
+
if (fingerprintHash === null === (appVersion === null)) return "exactly one of fingerprintHash and appVersion is required";
|
|
9265
|
+
if (buildKey !== null && !BUILD_KEY.test(buildKey)) return "buildKey must be nbk1: and a SHA-256, or null";
|
|
9266
|
+
if (buildNumber !== void 0 && buildNumber !== null && (buildNumber.trim().length === 0 || buildNumber.length > BUILD_NUMBER_MAX_LENGTH)) return `buildNumber must be the artifact's build number, up to ${BUILD_NUMBER_MAX_LENGTH} characters, or null`;
|
|
9267
|
+
const kinds = ARTIFACT_KINDS[platform];
|
|
9268
|
+
if (!kinds.includes(artifact.kind)) return `artifact.kind of an ${platform} build must be ${kinds.join(" or ")}`;
|
|
9269
|
+
if (!Number.isSafeInteger(artifact.byteSize) || artifact.byteSize < 0) return "artifact.byteSize must be a byte count";
|
|
9270
|
+
return null;
|
|
9271
|
+
};
|
|
9272
|
+
const createNativeBuildApi = (db, { now = Date.now } = {}) => ({
|
|
9273
|
+
async registerNativeBuild(registration) {
|
|
9274
|
+
const problem = problemOf(registration);
|
|
9275
|
+
if (problem !== null) throw new NativeBuildInputError(`Invalid native build: ${problem}.`);
|
|
9276
|
+
const scopeKey = nativeBuildScopeKey(registration);
|
|
9277
|
+
const channelId = `channel:${encodeChannelKey(registration.channel)}`;
|
|
9278
|
+
const { embeddedBundle } = registration;
|
|
9279
|
+
const row = {
|
|
9280
|
+
id: registration.id,
|
|
9281
|
+
scope_key: scopeKey,
|
|
9282
|
+
platform: registration.platform,
|
|
9283
|
+
channel_id: channelId,
|
|
9284
|
+
fingerprint_hash: registration.fingerprintHash,
|
|
9285
|
+
app_version: registration.appVersion,
|
|
9286
|
+
min_bundle_id: registration.minBundleId,
|
|
9287
|
+
artifact_kind: registration.artifact.kind,
|
|
9288
|
+
artifact_storage_uri: registration.artifact.storageUri,
|
|
9289
|
+
byte_size: registration.artifact.byteSize,
|
|
9290
|
+
git_commit_hash: registration.gitCommitHash,
|
|
9291
|
+
created_at_ms: now(),
|
|
9292
|
+
build_key: registration.buildKey,
|
|
9293
|
+
build_number: registration.buildNumber ?? null,
|
|
9294
|
+
submitted_to: null,
|
|
9295
|
+
submitted_at_ms: null,
|
|
9296
|
+
submitted_version: null
|
|
9297
|
+
};
|
|
9298
|
+
for (let attempt = 1;; attempt += 1) {
|
|
9299
|
+
await insertChannel(db, {
|
|
9300
|
+
id: channelId,
|
|
9301
|
+
name: registration.channel
|
|
9302
|
+
});
|
|
9303
|
+
try {
|
|
9304
|
+
await db.transaction(async (tx) => {
|
|
9305
|
+
tx.create("bundles", {
|
|
9306
|
+
id: registration.minBundleId,
|
|
9307
|
+
platform: registration.platform,
|
|
9308
|
+
git_commit_hash: registration.gitCommitHash,
|
|
9309
|
+
metadata: embeddedBundle.metadata ?? {},
|
|
9310
|
+
manifest_storage_uri: embeddedBundle.manifestStorageUri,
|
|
9311
|
+
manifest_file_hash: embeddedBundle.manifestFileHash,
|
|
9312
|
+
asset_base_storage_uri: embeddedBundle.assetBaseStorageUri
|
|
9313
|
+
});
|
|
9314
|
+
tx.create("native_builds", row);
|
|
9315
|
+
});
|
|
9316
|
+
break;
|
|
9317
|
+
} catch (error) {
|
|
9318
|
+
if (!(error instanceof DatabaseConstraintError)) throw error;
|
|
9319
|
+
if (error.reason === "exists" || error.reason === "unique") throw new DatabaseConstraintError(error.reason, "native_builds");
|
|
9320
|
+
if (attempt < 3 && error.reason === "not_found" && error.model === "channels") continue;
|
|
9321
|
+
throw error;
|
|
9322
|
+
}
|
|
9323
|
+
}
|
|
9324
|
+
return row;
|
|
9325
|
+
},
|
|
9326
|
+
async getNativeBuild(id) {
|
|
9327
|
+
const row = await db.findOne("native_builds", { id });
|
|
9328
|
+
return row === null ? null : pick(row);
|
|
9329
|
+
},
|
|
9330
|
+
async findNativeBuild(scope, options) {
|
|
9331
|
+
const scopeKey = nativeBuildScopeKey(scope);
|
|
9332
|
+
const buildKey = options?.buildKey;
|
|
9333
|
+
if (buildKey !== void 0 && !BUILD_KEY.test(buildKey)) throw new NativeBuildInputError("Invalid native build key: it must be nbk1: and a SHA-256.");
|
|
9334
|
+
const { rows } = buildKey === void 0 ? await db.findMany("native_builds", {
|
|
9335
|
+
index: "byScope",
|
|
9336
|
+
where: { scope_key: scopeKey },
|
|
9337
|
+
order: "desc",
|
|
9338
|
+
limit: 1
|
|
9339
|
+
}) : await db.findMany("native_builds", {
|
|
9340
|
+
index: "byBuildKey",
|
|
9341
|
+
where: {
|
|
9342
|
+
scope_key: scopeKey,
|
|
9343
|
+
build_key: buildKey
|
|
9344
|
+
},
|
|
9345
|
+
order: "desc",
|
|
9346
|
+
limit: 1
|
|
9347
|
+
});
|
|
9348
|
+
return rows[0] === void 0 ? null : pick(rows[0]);
|
|
9349
|
+
},
|
|
9350
|
+
async recordNativeBuildSubmission(id, { destination, version }) {
|
|
9351
|
+
if (version.trim().length === 0 || version.length > SUBMITTED_VERSION_MAX_LENGTH) throw new NativeBuildInputError(`Invalid native build submission: version must be the store's label of the build, up to ${SUBMITTED_VERSION_MAX_LENGTH} characters.`);
|
|
9352
|
+
return db.transaction(async (tx) => {
|
|
9353
|
+
const row = await tx.findOne("native_builds", { id });
|
|
9354
|
+
if (row === null) return null;
|
|
9355
|
+
const build = pick(row);
|
|
9356
|
+
if (SUBMISSION_DESTINATIONS[build.platform] !== destination) throw new NativeBuildInputError(`Invalid native build submission: an ${build.platform} build is submitted to ${SUBMISSION_DESTINATIONS[build.platform]}, not ${destination}.`);
|
|
9357
|
+
const set = {
|
|
9358
|
+
submitted_to: destination,
|
|
9359
|
+
submitted_at_ms: now(),
|
|
9360
|
+
submitted_version: version
|
|
9361
|
+
};
|
|
9362
|
+
tx.update("native_builds", row, set);
|
|
9363
|
+
return {
|
|
9364
|
+
...build,
|
|
9365
|
+
...set
|
|
9366
|
+
};
|
|
9367
|
+
});
|
|
9368
|
+
},
|
|
9369
|
+
async deleteNativeBuild(id) {
|
|
9370
|
+
return db.transaction(async (tx) => {
|
|
9371
|
+
const row = await tx.findOne("native_builds", { id });
|
|
9372
|
+
if (row === null) return {
|
|
9373
|
+
deleted: false,
|
|
9374
|
+
reason: "not_found"
|
|
9375
|
+
};
|
|
9376
|
+
await tx.delete("native_builds", row);
|
|
9377
|
+
const bundle = await tx.findOne("bundles", { id: row.min_bundle_id });
|
|
9378
|
+
if (bundle !== null) await tx.delete("bundles", bundle);
|
|
9379
|
+
return {
|
|
9380
|
+
deleted: true,
|
|
9381
|
+
nativeBuild: pick(row)
|
|
9382
|
+
};
|
|
9383
|
+
});
|
|
9384
|
+
},
|
|
9385
|
+
async listNativeBuilds(input) {
|
|
9386
|
+
const page = {
|
|
9387
|
+
order: input.order ?? "asc",
|
|
9388
|
+
limit: input.limit
|
|
9389
|
+
};
|
|
9390
|
+
const { rows } = input.channelId === void 0 ? await db.findMany("native_builds", {
|
|
9391
|
+
index: "all",
|
|
9392
|
+
where: {},
|
|
9393
|
+
...page,
|
|
9394
|
+
...after(input)
|
|
9395
|
+
}) : await db.findMany("native_builds", {
|
|
9396
|
+
index: "byChannel",
|
|
9397
|
+
where: { channel_id: input.channelId },
|
|
9398
|
+
...page,
|
|
9399
|
+
...after(input)
|
|
9400
|
+
});
|
|
9401
|
+
return rows.map(pick);
|
|
9402
|
+
}
|
|
9403
|
+
});
|
|
9404
|
+
//#endregion
|
|
9072
9405
|
//#region ../../packages/server/dist/core/releases.mjs
|
|
9073
9406
|
const PAGE$1 = 500;
|
|
9074
9407
|
const fail$1 = (code, message) => {
|
|
@@ -9355,6 +9688,7 @@ const createCoreOperations = (db, { now = Date.now } = {}) => {
|
|
|
9355
9688
|
if (!("bundleId" in deployment) || platforms.has(deployment.bundleId)) continue;
|
|
9356
9689
|
const row = await db.findOne("bundles", { id: deployment.bundleId });
|
|
9357
9690
|
if (row === null) throw new DatabaseBundleNotFoundError(deployment.bundleId);
|
|
9691
|
+
if (await isBuiltInBundle(db, deployment.bundleId)) throw new ReleaseManagementError("TARGET_RELEASE_INVALID", `Bundle "${deployment.bundleId}" is a native build's built-in bundle, which no release publishes.`);
|
|
9358
9692
|
platforms.set(deployment.bundleId, toBundleRow(row).platform);
|
|
9359
9693
|
}
|
|
9360
9694
|
const updatedAtMs = now();
|
|
@@ -9550,7 +9884,8 @@ const createCoreOperations = (db, { now = Date.now } = {}) => {
|
|
|
9550
9884
|
id
|
|
9551
9885
|
};
|
|
9552
9886
|
const { id: _id, ...set } = bundleToRow(next);
|
|
9553
|
-
|
|
9887
|
+
const counted = set.platform === current.platform || !await isBuiltInBundle(tx, id);
|
|
9888
|
+
updateBundle(tx, current, set, { counted });
|
|
9554
9889
|
if (patches !== void 0) await replaceBundlePatches(tx, current, bundleToPatchRows({
|
|
9555
9890
|
...next,
|
|
9556
9891
|
patches
|
|
@@ -9561,7 +9896,9 @@ const createCoreOperations = (db, { now = Date.now } = {}) => {
|
|
|
9561
9896
|
await db.transaction(async (tx) => {
|
|
9562
9897
|
for (const id of new Set(ids)) {
|
|
9563
9898
|
const current = await tx.findOne("bundles", { id });
|
|
9564
|
-
if (current
|
|
9899
|
+
if (current === null) continue;
|
|
9900
|
+
if (await isBuiltInBundle(tx, id)) throw new DatabaseRowReferencedError();
|
|
9901
|
+
await deleteBundle(tx, current);
|
|
9565
9902
|
}
|
|
9566
9903
|
});
|
|
9567
9904
|
} catch (error) {
|
|
@@ -9607,6 +9944,7 @@ const createCoreApi = (db, storage, options = {}) => {
|
|
|
9607
9944
|
return {
|
|
9608
9945
|
...reads,
|
|
9609
9946
|
...createCoreOperations(purgingCachedRoutes(db, options.onCachedRoutesChange), options),
|
|
9947
|
+
...createNativeBuildApi(db, options),
|
|
9610
9948
|
ready: async () => {
|
|
9611
9949
|
await reads.listReleaseCatalogs({ limit: 1 });
|
|
9612
9950
|
}
|
|
@@ -9798,6 +10136,10 @@ const answer = async (operation) => {
|
|
|
9798
10136
|
code: "REFERENCED",
|
|
9799
10137
|
error: error.message
|
|
9800
10138
|
}, 409);
|
|
10139
|
+
if (error instanceof DatabaseConstraintError && error.model === "native_builds") return json$2({
|
|
10140
|
+
code: "NATIVE_BUILD_EXISTS",
|
|
10141
|
+
error: "A native build with this ID or built-in bundle ID is already registered."
|
|
10142
|
+
}, 409);
|
|
9801
10143
|
throw error;
|
|
9802
10144
|
}
|
|
9803
10145
|
};
|
|
@@ -9893,6 +10235,40 @@ const bundleUpdateOf = (value, bundleId) => {
|
|
|
9893
10235
|
if (id !== void 0 && id !== bundleId) throw new HandlerBadRequestError("Bundle id mismatch");
|
|
9894
10236
|
return update;
|
|
9895
10237
|
};
|
|
10238
|
+
const NATIVE_BUILD_ARTIFACT_KINDS = /* @__PURE__ */ new Set([
|
|
10239
|
+
"apk",
|
|
10240
|
+
"aab",
|
|
10241
|
+
"ipa",
|
|
10242
|
+
"app"
|
|
10243
|
+
]);
|
|
10244
|
+
const nativeBuildScopeOf = (url) => {
|
|
10245
|
+
const params = url.searchParams;
|
|
10246
|
+
const platform = platformOf(url);
|
|
10247
|
+
const channel = params.get("channel");
|
|
10248
|
+
const fingerprintHash = params.get("fingerprintHash");
|
|
10249
|
+
const appVersion = params.get("appVersion");
|
|
10250
|
+
if (platform === void 0 || !isText$2(channel) || fingerprintHash === null === (appVersion === null) || fingerprintHash === "" || appVersion === "") throw new HandlerBadRequestError("A native build lookup needs platform, channel, and fingerprintHash or appVersion.");
|
|
10251
|
+
return fingerprintHash !== null ? {
|
|
10252
|
+
platform,
|
|
10253
|
+
channel,
|
|
10254
|
+
fingerprintHash,
|
|
10255
|
+
appVersion: null
|
|
10256
|
+
} : {
|
|
10257
|
+
platform,
|
|
10258
|
+
channel,
|
|
10259
|
+
fingerprintHash: null,
|
|
10260
|
+
appVersion
|
|
10261
|
+
};
|
|
10262
|
+
};
|
|
10263
|
+
const refusingInvalid = async (operation) => {
|
|
10264
|
+
try {
|
|
10265
|
+
return await operation();
|
|
10266
|
+
} catch (error) {
|
|
10267
|
+
if (error instanceof NativeBuildInputError) throw new HandlerBadRequestError(error.message);
|
|
10268
|
+
throw error;
|
|
10269
|
+
}
|
|
10270
|
+
};
|
|
10271
|
+
const isNativeBuildRegistration = (value) => isRecord$5(value) && isText$2(value.id) && isText$2(value.minBundleId) && typeof value.platform === "string" && isPlatform(value.platform) && isText$2(value.channel) && isTextOrNull$1(value.fingerprintHash) && isTextOrNull$1(value.appVersion) && value.fingerprintHash === null !== (value.appVersion === null) && isTextOrNull$1(value.gitCommitHash) && isTextOrNull$1(value.buildKey) && (value.buildNumber === void 0 || isTextOrNull$1(value.buildNumber)) && isRecord$5(value.artifact) && typeof value.artifact.kind === "string" && NATIVE_BUILD_ARTIFACT_KINDS.has(value.artifact.kind) && isText$2(value.artifact.storageUri) && Number.isSafeInteger(value.artifact.byteSize) && value.artifact.byteSize >= 0 && isRecord$5(value.embeddedBundle) && isText$2(value.embeddedBundle.manifestStorageUri) && isText$2(value.embeddedBundle.manifestFileHash) && isText$2(value.embeddedBundle.assetBaseStorageUri) && (value.embeddedBundle.metadata === void 0 || isRecord$5(value.embeddedBundle.metadata));
|
|
9896
10272
|
const scopeKeyOf = (params) => decodeMaybe(requireRouteParam(params, "scopeKey")) ?? "";
|
|
9897
10273
|
const createAdminRouteHandlers = () => ({
|
|
9898
10274
|
listBundles: onCore(async (core, request) => {
|
|
@@ -10007,6 +10383,37 @@ const createAdminRouteHandlers = () => ({
|
|
|
10007
10383
|
}) });
|
|
10008
10384
|
}),
|
|
10009
10385
|
preflightReleaseCatalogRebuild: onCore(async (core, _request, params) => json$2({ data: await core.preflightReleaseCatalogRebuild(scopeKeyOf(params)) })),
|
|
10386
|
+
registerNativeBuild: onCore(async (core, request) => {
|
|
10387
|
+
const input = await body$1(request);
|
|
10388
|
+
if (!isNativeBuildRegistration(input)) throw new HandlerBadRequestError("Invalid native build");
|
|
10389
|
+
return json$2({ data: await refusingInvalid(() => core.registerNativeBuild(input)) }, 201);
|
|
10390
|
+
}),
|
|
10391
|
+
findNativeBuild: onCore(async (core, request) => {
|
|
10392
|
+
const url = new URL(request.url);
|
|
10393
|
+
const scope = nativeBuildScopeOf(url);
|
|
10394
|
+
const buildKey = url.searchParams.get("buildKey");
|
|
10395
|
+
return json$2({ data: await refusingInvalid(() => buildKey === null ? core.findNativeBuild(scope) : core.findNativeBuild(scope, { buildKey })) });
|
|
10396
|
+
}),
|
|
10397
|
+
getNativeBuild: onCore(async (core, _request, params) => json$2({ data: await core.getNativeBuild(requireRouteParam(params, "id")) })),
|
|
10398
|
+
listNativeBuilds: onCore(async (core, request) => {
|
|
10399
|
+
const url = new URL(request.url);
|
|
10400
|
+
const input = keyset(url);
|
|
10401
|
+
const channelId = url.searchParams.get("channelId");
|
|
10402
|
+
return page(await core.listNativeBuilds({
|
|
10403
|
+
...input,
|
|
10404
|
+
...channelId === null ? {} : { channelId }
|
|
10405
|
+
}), input, ({ id }) => id);
|
|
10406
|
+
}),
|
|
10407
|
+
recordNativeBuildSubmission: onCore(async (core, request, params) => {
|
|
10408
|
+
const input = await body$1(request);
|
|
10409
|
+
if (!isRecord$5(input) || input.destination !== "testflight" && input.destination !== "play-internal" || !isText$2(input.version)) throw new HandlerBadRequestError("A native build submission needs destination (testflight or play-internal) and version.");
|
|
10410
|
+
const submission = {
|
|
10411
|
+
destination: input.destination,
|
|
10412
|
+
version: input.version
|
|
10413
|
+
};
|
|
10414
|
+
return json$2({ data: await refusingInvalid(() => core.recordNativeBuildSubmission(requireRouteParam(params, "id"), submission)) });
|
|
10415
|
+
}),
|
|
10416
|
+
deleteNativeBuild: onCore(async (core, _request, params) => json$2({ data: await core.deleteNativeBuild(requireRouteParam(params, "id")) })),
|
|
10010
10417
|
deleteBundles: onCore(async (core, request) => {
|
|
10011
10418
|
const { ids } = await body$1(request);
|
|
10012
10419
|
if (!Array.isArray(ids) || !ids.every((id) => typeof id === "string" && id.length > 0)) throw new HandlerBadRequestError("Bundle deletion needs ids");
|
|
@@ -10124,6 +10531,36 @@ const ADMIN_ROUTES = [
|
|
|
10124
10531
|
method: "GET",
|
|
10125
10532
|
path: "/base-candidates/:candidateKey",
|
|
10126
10533
|
handler: "findBaseCandidates"
|
|
10534
|
+
},
|
|
10535
|
+
{
|
|
10536
|
+
method: "POST",
|
|
10537
|
+
path: "/native-builds",
|
|
10538
|
+
handler: "registerNativeBuild"
|
|
10539
|
+
},
|
|
10540
|
+
{
|
|
10541
|
+
method: "GET",
|
|
10542
|
+
path: "/native-builds/latest",
|
|
10543
|
+
handler: "findNativeBuild"
|
|
10544
|
+
},
|
|
10545
|
+
{
|
|
10546
|
+
method: "GET",
|
|
10547
|
+
path: "/native-builds/:id",
|
|
10548
|
+
handler: "getNativeBuild"
|
|
10549
|
+
},
|
|
10550
|
+
{
|
|
10551
|
+
method: "GET",
|
|
10552
|
+
path: "/native-builds",
|
|
10553
|
+
handler: "listNativeBuilds"
|
|
10554
|
+
},
|
|
10555
|
+
{
|
|
10556
|
+
method: "POST",
|
|
10557
|
+
path: "/native-builds/:id/submission",
|
|
10558
|
+
handler: "recordNativeBuildSubmission"
|
|
10559
|
+
},
|
|
10560
|
+
{
|
|
10561
|
+
method: "DELETE",
|
|
10562
|
+
path: "/native-builds/:id",
|
|
10563
|
+
handler: "deleteNativeBuild"
|
|
10127
10564
|
}
|
|
10128
10565
|
];
|
|
10129
10566
|
//#endregion
|
|
@@ -56981,8 +57418,9 @@ const isNotFound = (error) => error instanceof RestError && error.statusCode ===
|
|
|
56981
57418
|
const serviceOf = (config) => "connectionString" in config ? BlobServiceClient.fromConnectionString(config.connectionString) : new BlobServiceClient(config.accountUrl, config.credential);
|
|
56982
57419
|
function azureBlobStorage(config) {
|
|
56983
57420
|
const { containerName, basePath, getDownloadUrl } = config;
|
|
56984
|
-
|
|
56985
|
-
const
|
|
57421
|
+
let client;
|
|
57422
|
+
const service = () => client ??= serviceOf(config);
|
|
57423
|
+
const container = () => service().getContainerClient(containerName);
|
|
56986
57424
|
const normalizedBasePath = basePath?.replace(/^\/+|\/+$/g, "") ?? "";
|
|
56987
57425
|
const getStorageKey = createStorageKeyBuilder(normalizedBasePath);
|
|
56988
57426
|
const getListPrefix = (prefix = "") => {
|
|
@@ -57013,7 +57451,7 @@ function azureBlobStorage(config) {
|
|
|
57013
57451
|
const delegationKey = () => {
|
|
57014
57452
|
const now = Date.now();
|
|
57015
57453
|
if (delegation === void 0 || delegation.renewAt <= now) {
|
|
57016
|
-
const key = service.getUserDelegationKey(/* @__PURE__ */ new Date(now - 3e5), new Date(now + DELEGATION_KEY_LIFETIME_MS));
|
|
57454
|
+
const key = service().getUserDelegationKey(/* @__PURE__ */ new Date(now - 3e5), new Date(now + DELEGATION_KEY_LIFETIME_MS));
|
|
57017
57455
|
key.catch(() => {
|
|
57018
57456
|
delegation = void 0;
|
|
57019
57457
|
});
|
|
@@ -57025,7 +57463,7 @@ function azureBlobStorage(config) {
|
|
|
57025
57463
|
return delegation.key;
|
|
57026
57464
|
};
|
|
57027
57465
|
const signedUrl = async (key) => {
|
|
57028
|
-
const blob = container.getBlobClient(key);
|
|
57466
|
+
const blob = container().getBlobClient(key);
|
|
57029
57467
|
const expiresOn = new Date(Date.now() + SAS_EXPIRES_IN_MS);
|
|
57030
57468
|
const permissions = BlobSASPermissions.parse("r");
|
|
57031
57469
|
if (blob.credential instanceof StorageSharedKeyCredential) return blob.generateSasUrl({
|
|
@@ -57046,7 +57484,7 @@ function azureBlobStorage(config) {
|
|
|
57046
57484
|
protocol: PROTOCOL,
|
|
57047
57485
|
async listObjects(prefix) {
|
|
57048
57486
|
const objects = [];
|
|
57049
|
-
for await (const blob of container.listBlobsFlat({ prefix: getListPrefix(prefix) })) {
|
|
57487
|
+
for await (const blob of container().listBlobsFlat({ prefix: getListPrefix(prefix) })) {
|
|
57050
57488
|
const storageUri = getListedStorageUri(blob.name);
|
|
57051
57489
|
if (storageUri === null) continue;
|
|
57052
57490
|
objects.push({
|
|
@@ -57063,17 +57501,36 @@ function azureBlobStorage(config) {
|
|
|
57063
57501
|
for (let offset = 0; offset < keys.length; offset += 256) {
|
|
57064
57502
|
const batch = keys.slice(offset, offset + 256);
|
|
57065
57503
|
if (batch.length === 0) continue;
|
|
57066
|
-
const failed = (await container.getBlobBatchClient().deleteBlobs(batch.map((key) => container.getBlobClient(key)))).subResponses.filter(({ status }) => status >= 300 && status !== 404);
|
|
57504
|
+
const failed = (await container().getBlobBatchClient().deleteBlobs(batch.map((key) => container().getBlobClient(key)))).subResponses.filter(({ status }) => status >= 300 && status !== 404);
|
|
57067
57505
|
if (failed.length > 0) throw new Error(`Failed to delete ${failed.length} Azure blob(s).`);
|
|
57068
57506
|
}
|
|
57069
57507
|
},
|
|
57070
|
-
async put({ key, body, contentType }) {
|
|
57508
|
+
async put({ key, body, contentLength, contentType }) {
|
|
57071
57509
|
const storageKey = getStorageKey(key);
|
|
57072
|
-
const
|
|
57073
|
-
await container.getBlockBlobClient(storageKey).uploadData(bytes, { blobHTTPHeaders: {
|
|
57510
|
+
const options = { blobHTTPHeaders: {
|
|
57074
57511
|
blobContentType: contentType,
|
|
57075
57512
|
blobCacheControl: "max-age=31536000"
|
|
57076
|
-
} }
|
|
57513
|
+
} };
|
|
57514
|
+
const blob = container().getBlockBlobClient(storageKey);
|
|
57515
|
+
if (contentLength === void 0) await blob.uploadData(new Uint8Array(await new Response(body).arrayBuffer()), options);
|
|
57516
|
+
else {
|
|
57517
|
+
const { Readable } = await import("node:stream");
|
|
57518
|
+
const source = Readable.fromWeb(body);
|
|
57519
|
+
const aborted = new AbortController();
|
|
57520
|
+
let failure;
|
|
57521
|
+
source.once("error", (error) => {
|
|
57522
|
+
failure = error;
|
|
57523
|
+
aborted.abort(error);
|
|
57524
|
+
});
|
|
57525
|
+
try {
|
|
57526
|
+
await blob.upload(source, contentLength, {
|
|
57527
|
+
...options,
|
|
57528
|
+
abortSignal: aborted.signal
|
|
57529
|
+
});
|
|
57530
|
+
} catch (error) {
|
|
57531
|
+
throw failure ?? error;
|
|
57532
|
+
}
|
|
57533
|
+
}
|
|
57077
57534
|
return { storageUri: createStorageUri({
|
|
57078
57535
|
bucket: containerName,
|
|
57079
57536
|
key: storageKey,
|
|
@@ -57083,7 +57540,7 @@ function azureBlobStorage(config) {
|
|
|
57083
57540
|
async get({ storageUri }) {
|
|
57084
57541
|
const { key } = parseAndValidate(storageUri);
|
|
57085
57542
|
try {
|
|
57086
|
-
const download = await container.getBlobClient(key).download();
|
|
57543
|
+
const download = await container().getBlobClient(key).download();
|
|
57087
57544
|
const body = download.readableStreamBody;
|
|
57088
57545
|
if (body === void 0) return { response: null };
|
|
57089
57546
|
const headers = new Headers();
|
|
@@ -57103,11 +57560,11 @@ function azureBlobStorage(config) {
|
|
|
57103
57560
|
},
|
|
57104
57561
|
async exists({ storageUri }) {
|
|
57105
57562
|
const { key } = parseAndValidate(storageUri);
|
|
57106
|
-
return { exists: await container.getBlobClient(key).exists() };
|
|
57563
|
+
return { exists: await container().getBlobClient(key).exists() };
|
|
57107
57564
|
},
|
|
57108
57565
|
async delete({ storageUri }) {
|
|
57109
57566
|
const { key } = parseAndValidate(storageUri);
|
|
57110
|
-
await container.getBlobClient(key).deleteIfExists();
|
|
57567
|
+
await container().getBlobClient(key).deleteIfExists();
|
|
57111
57568
|
return { deleted: true };
|
|
57112
57569
|
}
|
|
57113
57570
|
});
|
|
@@ -70399,11 +70856,19 @@ const assertCosmosContainerReusable = async (container, expected) => {
|
|
|
70399
70856
|
const isWideAdd = (op) => op.type === "add" && Object.keys(op.by).length + (op.expiresAt === void 0 ? 0 : 2) > PATCH_OPERATIONS;
|
|
70400
70857
|
const emulatorAborted = (error) => statusOf(error) === 500 && /PostgresError\(SqlState\(E(25P02|40001|40P01)\)/.test(String(error instanceof Error ? error.message : error));
|
|
70401
70858
|
const createCosmosStore = ({ client, databaseId, containerId, engine, nativePageSize }) => {
|
|
70402
|
-
|
|
70859
|
+
let opened;
|
|
70860
|
+
const open = () => opened ??= (() => {
|
|
70861
|
+
const account = typeof client === "function" ? client() : client;
|
|
70862
|
+
return {
|
|
70863
|
+
client: account,
|
|
70864
|
+
container: account.database(databaseId).container(containerId)
|
|
70865
|
+
};
|
|
70866
|
+
})();
|
|
70867
|
+
const container = () => open().container;
|
|
70403
70868
|
const readStates = async (ids, rowIds) => {
|
|
70404
70869
|
const states = /* @__PURE__ */ new Map();
|
|
70405
70870
|
for (const [group, projection] of [[ids.filter((id) => !rowIds.has(id)), ""], [ids.filter((id) => rowIds.has(id)), ", c.row"]]) for (let at = 0; at < group.length; at += GET_BATCH) {
|
|
70406
|
-
const { resources } = await container.items.query(`SELECT c.id, c._etag AS etag, c.row._v AS v, c.expireAt${projection} FROM c WHERE c.id IN (${idList(group.slice(at, at + GET_BATCH))})`, { partitionKey: COSMOS_PARTITION }).fetchAll().catch(missingContainer);
|
|
70871
|
+
const { resources } = await container().items.query(`SELECT c.id, c._etag AS etag, c.row._v AS v, c.expireAt${projection} FROM c WHERE c.id IN (${idList(group.slice(at, at + GET_BATCH))})`, { partitionKey: COSMOS_PARTITION }).fetchAll().catch(missingContainer);
|
|
70407
70872
|
for (const { id, etag, v, expireAt, row } of resources) states.set(id, {
|
|
70408
70873
|
etag,
|
|
70409
70874
|
v,
|
|
@@ -70535,7 +71000,7 @@ const createCosmosStore = ({ client, databaseId, containerId, engine, nativePage
|
|
|
70535
71000
|
const found = /* @__PURE__ */ new Map();
|
|
70536
71001
|
const ids = [...new Set(keys.map(cosmosItemId))];
|
|
70537
71002
|
for (let at = 0; at < ids.length; at += GET_BATCH) {
|
|
70538
|
-
const { resources } = await container.items.query(`SELECT c.id, c.row FROM c WHERE c.id IN (${idList(ids.slice(at, at + GET_BATCH))})`, { partitionKey: COSMOS_PARTITION }).fetchAll().catch(missingContainer);
|
|
71003
|
+
const { resources } = await container().items.query(`SELECT c.id, c.row FROM c WHERE c.id IN (${idList(ids.slice(at, at + GET_BATCH))})`, { partitionKey: COSMOS_PARTITION }).fetchAll().catch(missingContainer);
|
|
70539
71004
|
for (const resource of resources) found.set(resource.id, toRow(resource.row));
|
|
70540
71005
|
}
|
|
70541
71006
|
return keys.map((key) => found.get(cosmosItemId(key)) ?? null);
|
|
@@ -70571,7 +71036,7 @@ const createCosmosStore = ({ client, databaseId, containerId, engine, nativePage
|
|
|
70571
71036
|
value: after
|
|
70572
71037
|
});
|
|
70573
71038
|
}
|
|
70574
|
-
const { resources } = await container.items.query({
|
|
71039
|
+
const { resources } = await container().items.query({
|
|
70575
71040
|
query: `SELECT TOP @size c.sk, c.row FROM c WHERE ${filters.join(" AND ")} ORDER BY c.pk ${order === "asc" ? "ASC" : "DESC"}, c.sk ${order === "asc" ? "ASC" : "DESC"}`,
|
|
70576
71041
|
parameters
|
|
70577
71042
|
}, {
|
|
@@ -70621,7 +71086,7 @@ const createCosmosStore = ({ client, databaseId, containerId, engine, nativePage
|
|
|
70621
71086
|
if (planned.length > BATCH_OPERATIONS) throw new Error(`A Cosmos DB batch takes ${BATCH_OPERATIONS} operations; this write needs ${planned.length}.`);
|
|
70622
71087
|
let results;
|
|
70623
71088
|
try {
|
|
70624
|
-
const response = await container.items.batch(planned.map(({ operation }) => operation), COSMOS_PARTITION);
|
|
71089
|
+
const response = await container().items.batch(planned.map(({ operation }) => operation), COSMOS_PARTITION);
|
|
70625
71090
|
if (response.result === void 0) throw Object.assign(/* @__PURE__ */ new Error(`Cosmos DB refused the batch with status ${response.code}`), { code: response.code });
|
|
70626
71091
|
results = response.result;
|
|
70627
71092
|
} catch (error) {
|
|
@@ -70654,7 +71119,7 @@ const createCosmosStore = ({ client, databaseId, containerId, engine, nativePage
|
|
|
70654
71119
|
async deleteConsumed(keys) {
|
|
70655
71120
|
let remaining = [...new Set(keys.map(cosmosItemId))];
|
|
70656
71121
|
for (let attempt = 0; remaining.length > 0; attempt += 1) {
|
|
70657
|
-
const failed = (await container.items.executeBulkOperations(remaining.map((id) => ({
|
|
71122
|
+
const failed = (await container().items.executeBulkOperations(remaining.map((id) => ({
|
|
70658
71123
|
operationType: "Delete",
|
|
70659
71124
|
id,
|
|
70660
71125
|
partitionKey: COSMOS_PARTITION
|
|
@@ -70673,8 +71138,8 @@ const createCosmosStore = ({ client, databaseId, containerId, engine, nativePage
|
|
|
70673
71138
|
}
|
|
70674
71139
|
},
|
|
70675
71140
|
migrations: { async apply() {
|
|
70676
|
-
if (engine !== void 0) await assertCosmosContainerReusable(container, engine);
|
|
70677
|
-
const { database } = await client.databases.createIfNotExists({ id: databaseId });
|
|
71141
|
+
if (engine !== void 0) await assertCosmosContainerReusable(container(), engine);
|
|
71142
|
+
const { database } = await open().client.databases.createIfNotExists({ id: databaseId });
|
|
70678
71143
|
const { resource } = await database.containers.createIfNotExists({
|
|
70679
71144
|
id: containerId,
|
|
70680
71145
|
partitionKey: { paths: [COSMOS_PARTITION_KEY_PATH] },
|
|
@@ -70710,29 +71175,40 @@ const createCosmosStore = ({ client, databaseId, containerId, engine, nativePage
|
|
|
70710
71175
|
const adapterOf = (config) => {
|
|
70711
71176
|
const { databaseId = AZURE_COSMOS_V1_DATABASE, containerId = AZURE_COSMOS_V1_CONTAINER, aggregateBatching: _, ...connection } = config;
|
|
70712
71177
|
if (connection.consistencyLevel !== void 0 && connection.consistencyLevel !== "Strong") throw new Error(`cosmosDatabase reads with strong consistency; consistencyLevel "${String(connection.consistencyLevel)}" is weaker.`);
|
|
70713
|
-
|
|
71178
|
+
let client;
|
|
70714
71179
|
const store = createCosmosStore({
|
|
70715
|
-
client,
|
|
71180
|
+
client: () => client ??= new CosmosClient(connection),
|
|
70716
71181
|
databaseId,
|
|
70717
71182
|
containerId,
|
|
70718
71183
|
engine: currentCosmosEngine()
|
|
70719
71184
|
});
|
|
70720
71185
|
return {
|
|
70721
|
-
client,
|
|
71186
|
+
dispose: () => client?.dispose(),
|
|
70722
71187
|
adapter: createKvAdapter({ store })
|
|
70723
71188
|
};
|
|
70724
71189
|
};
|
|
71190
|
+
const DATABASE_TARGET = Symbol.for("@hot-updater/database-target");
|
|
71191
|
+
const accountHostOf = ({ endpoint, connectionString }) => {
|
|
71192
|
+
const url = endpoint ?? connectionString?.match(/AccountEndpoint=([^;]+)/iu)?.[1];
|
|
71193
|
+
try {
|
|
71194
|
+
return url === void 0 ? void 0 : new URL(url).hostname;
|
|
71195
|
+
} catch {
|
|
71196
|
+
return;
|
|
71197
|
+
}
|
|
71198
|
+
};
|
|
70725
71199
|
const cosmosDatabase = (config) => {
|
|
70726
|
-
const {
|
|
71200
|
+
const { dispose, adapter } = adapterOf(config);
|
|
71201
|
+
const host = accountHostOf(config);
|
|
70727
71202
|
return {
|
|
70728
71203
|
...createEngineDatabase({
|
|
70729
71204
|
name: "cosmosDatabase",
|
|
70730
71205
|
adapter,
|
|
70731
71206
|
aggregateBatching: config.aggregateBatching ?? {}
|
|
70732
71207
|
}),
|
|
71208
|
+
...host === void 0 ? {} : { [DATABASE_TARGET]: `cosmos/${host}` },
|
|
70733
71209
|
async dispose() {
|
|
70734
71210
|
await adapter.dispose?.();
|
|
70735
|
-
|
|
71211
|
+
dispose();
|
|
70736
71212
|
}
|
|
70737
71213
|
};
|
|
70738
71214
|
};
|