From 247a6bb5e55a3ea73780de45959aaed3a4778e20 Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Thu, 28 May 2026 17:07:19 +0200 Subject: [PATCH 01/15] =?UTF-8?q?=E2=9C=A8=20implement=20CRR=20multi-site?= =?UTF-8?q?=20V2=20replication=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- CRR/ReplicationStatusUpdater.js | 234 ++++++++++++++- tests/unit/CRR/ReplicationStatusUpdater.js | 332 +++++++++++++++++++++ tests/utils/crr.js | 32 ++ 3 files changed, 588 insertions(+), 10 deletions(-) diff --git a/CRR/ReplicationStatusUpdater.js b/CRR/ReplicationStatusUpdater.js index eafd9083..29f437da 100644 --- a/CRR/ReplicationStatusUpdater.js +++ b/CRR/ReplicationStatusUpdater.js @@ -117,6 +117,78 @@ class ReplicationStatusUpdater { } + /** + * Returns true if the replication config uses the legacy V1 format (any rule has a + * comma-separated StorageClass, e.g. "dest-A,dest-B"). + * @private + * @param {Object} repConfig - The replication configuration from GetBucketReplicationCommand. + * @returns {boolean} + */ + _isLegacyFormat(repConfig) { + // Comma-separated StorageClass is always V1 (multiple destinations in one rule) + if (repConfig.Rules.some(r => r.Destination.StorageClass?.includes(','))) { + return true; + } + // V2 rules carry Filter (object), Priority, or Destination.Account; V1 rules have none of these + return repConfig.Rules.every(r => + r.Filter === undefined && + r.Priority === undefined && + r.Destination.Account === undefined + ); + } + + /** + * Returns the subset of rules whose prefix matches the given key, deduplicated by site + * (highest Priority wins when two rules target the same StorageClass). + * @private + * @param {string} key - The object key. + * @param {Array} rules - The replication rules from GetBucketReplicationCommand. + * @returns {Array} + */ + _getMatchingRules(key, rules) { + const siteMap = new Map(); + for (const rule of rules) { + if (rule.Status !== 'Enabled') { continue; } + const prefix = rule.Prefix || (rule.Filter && rule.Filter.Prefix) || ''; + if (!key.startsWith(prefix)) { continue; } + const site = rule.Destination.StorageClass; + const existing = siteMap.get(site); + const priority = rule.Priority || 0; + if (!existing || priority > (existing.Priority || 0)) { + siteMap.set(site, rule); + } + } + return [...siteMap.values()]; + } + + /** + * Derives the per-rule destination role ARN by substituting the account ID. + * If baseRole is "src,dest" format, uses the dest part as the template. + * @private + * @param {string} baseRole - The top-level Role from the replication config. + * @param {string} [account] - The account ID from Destination.Account. + * @returns {string} + */ + _deriveRuleRole(baseRole, account) { + const roles = baseRole.split(','); + const destRole = roles.length > 1 ? roles[1].trim() : roles[0].trim(); + if (!account) { return destRole; } + return destRole.replace(/(arn:aws:iam::)[^:]*(:)/, `$1${account}$2`); + } + + /** + * Computes the aggregate top-level replication status from all backends per the V2 rules: + * any FAILED → FAILED; else any PENDING → PROCESSING; else COMPLETED. + * @private + * @param {Array} backends - The backends array from replicationInfo. + * @returns {string} + */ + _computeTopLevelStatus(backends) { + if (backends.some(b => b.status === 'FAILED')) { return 'FAILED'; } + if (backends.some(b => b.status === 'PENDING')) { return 'PROCESSING'; } + return 'COMPLETED'; + } + /** * Determines if an object should be updated based on its replication metadata properties. * @private @@ -270,6 +342,124 @@ class ReplicationStatusUpdater { }); } + /** + * Marks an object as pending for replication using the V2 multi-destination format. + * Writes per-backend destination and role; strips legacy top-level storageClass/storageType/destination. + * @private + * @param {string} bucket - The bucket name. + * @param {string} key - The object key. + * @param {string} versionId - The object version ID. + * @param {Array} matchingRules - Rules already matched to this key (prefix-filtered, deduped by site). + * @param {Object} repConfig - The full replication configuration. + * @param {Function} cb - Callback function. + * @returns {void} + */ + _markObjectPendingV2(bucket, key, versionId, matchingRules, repConfig, cb) { + let objMD; + let skip = false; + return waterfall([ + next => this.cloudserverclient.getMetadata({ + Bucket: bucket, + Key: key, + VersionId: versionId, + }, next), + (mdRes, next) => { + const originalMD = JSON.parse(mdRes.Body); + const originalMDVersion = originalMD['md-model-version']; + objMD = new ObjectMD(originalMD); + const newMDVersion = objMD.getModelVersion(); + + if (newMDVersion < originalMDVersion) { + this.log.error('model version regression: newMDVersion < originalMDVersion', { + bucket, key, versionId, newMDVersion, originalMDVersion, + }); + return next(new Error('model version regression: refusing to overwrite newer metadata')); + } + + const rulesToUpdate = matchingRules.filter(rule => + this._objectShouldBeUpdated(objMD, rule.Destination.StorageClass) + ); + + if (rulesToUpdate.length === 0) { + skip = true; + return process.nextTick(next); + } + + const sourceRole = repConfig.Role.split(',')[0].trim(); + let replicationInfo = objMD.getReplicationInfo(); + if (!replicationInfo || !replicationInfo.status) { + const ops = objMD.getContentLength() === 0 ? ['METADATA'] : ['METADATA', 'DATA']; + objMD.setReplicationInfo({ + status: 'PENDING', + role: sourceRole, + backends: [], + content: ops, + isNFS: null, + }); + replicationInfo = objMD.getReplicationInfo(); + } + // Remove legacy top-level fields that don't belong in V2 format + delete replicationInfo.destination; + delete replicationInfo.storageClass; + delete replicationInfo.storageType; + delete replicationInfo.dataStoreVersionId; + + const backends = objMD.getReplicationBackends(); + + for (const rule of rulesToUpdate) { + const site = rule.Destination.StorageClass; + const destination = rule.Destination.Bucket; + const role = this._deriveRuleRole(repConfig.Role, rule.Destination.Account); + const existing = backends.find(b => b.site === site); + if (existing) { + existing.status = 'PENDING'; + existing.destination = destination; + existing.role = role; + } else { + backends.push({ site, status: 'PENDING', destination, role, dataStoreVersionId: '' }); + } + } + objMD.setReplicationBackends(backends); + + if (this.forceUsingConfiguration) { + for (const backend of backends) { + const rule = matchingRules.find(r => r.Destination.StorageClass === backend.site); + if (rule) { + backend.destination = rule.Destination.Bucket; + backend.role = this._deriveRuleRole(repConfig.Role, rule.Destination.Account); + } + } + } + + objMD.setReplicationStatus(this._computeTopLevelStatus(backends)); + objMD.updateMicroVersionId(); + const md = objMD.getSerialized(); + return this.cloudserverclient.putMetadata({ + Bucket: bucket, + Key: key, + VersionId: versionId, + Body: md, + }, next); + }, + ], err => { + ++this._nProcessed; + if (err) { + ++this._nErrors; + this.log.error('error updating object', { + bucket, key, versionId, error: err.message, + }); + cb(); + return; + } + if (skip) { + ++this._nSkipped; + } else { + ++this._nUpdated; + } + cb(); + }); + } + /** * Lists object versions for a bucket. * @private @@ -312,16 +502,31 @@ class ReplicationStatusUpdater { }, (repConfig, next) => { const { Rules } = repConfig; - const storageClass = this.siteName || Rules[0].Destination.StorageClass; - if (!storageClass) { - const errMsg = 'missing SITE_NAME environment variable, must be set to' - + ' the value of "site" property in the CRR configuration'; - this.log.error(errMsg); - return next(new Error(errMsg)); - } - if (!this.siteName) { - this.log.warn(`missing SITE_NAME environment variable, triggering replication to the ${storageClass} storage class`); + + if (this._isLegacyFormat(repConfig)) { + // V1: single storage class (possibly comma-separated, handled by _markObjectPending) + const storageClass = this.siteName || Rules[0].Destination.StorageClass; + if (!storageClass) { + const errMsg = 'missing SITE_NAME environment variable, must be set to' + + ' the value of "site" property in the CRR configuration'; + this.log.error(errMsg); + return next(new Error(errMsg)); + } + if (!this.siteName) { + this.log.warn(`missing SITE_NAME environment variable, triggering replication to the ${storageClass} storage class`); + } + return eachLimit(versions, this.workers, (i, apply) => { + const { Key, VersionId, IsLatest } = i; + if (this.currentVersionOnly && !IsLatest) { + ++this._nSkipped; + apply(); + return; + } + this._markObjectPending(bucket, Key, VersionId, storageClass, repConfig, apply); + }, next); } + + // V2: one rule per destination, prefix-matched per object return eachLimit(versions, this.workers, (i, apply) => { const { Key, VersionId, IsLatest } = i; if (this.currentVersionOnly && !IsLatest) { @@ -329,7 +534,16 @@ class ReplicationStatusUpdater { apply(); return; } - this._markObjectPending(bucket, Key, VersionId, storageClass, repConfig, apply); + let matchingRules = this._getMatchingRules(Key, Rules); + if (this.siteName) { + matchingRules = matchingRules.filter(r => r.Destination.StorageClass === this.siteName); + } + if (matchingRules.length === 0) { + ++this._nSkipped; + apply(); + return; + } + this._markObjectPendingV2(bucket, Key, VersionId, matchingRules, repConfig, apply); }, next); }, ], cb); diff --git a/tests/unit/CRR/ReplicationStatusUpdater.js b/tests/unit/CRR/ReplicationStatusUpdater.js index a03141dc..bc592f9a 100644 --- a/tests/unit/CRR/ReplicationStatusUpdater.js +++ b/tests/unit/CRR/ReplicationStatusUpdater.js @@ -8,6 +8,7 @@ const { listVersionsRes, listVersionWithMarkerRes, getMetadataRes, + getBucketReplicationV2Res, objectMd, } = require('../../utils/crr'); @@ -905,3 +906,334 @@ describe('ReplicationStatusUpdater model version guard', () => { }); }); }); + +describe('ReplicationStatusUpdater V2 format', () => { + // V2 config: rule1 (prefix='', dest-A) and rule2 (prefix='docs/', dest-B) + // Object key 'key0' matches only rule1 (dest-A) + it('should mark object pending for matching V2 rule (single match)', done => { + const crr = initializeCrrWithMocks({ + buckets: ['bucket0'], + workers: 10, + replicationStatusToProcess: ['NEW'], + }, logger, { + GetBucketReplicationCommand: getBucketReplicationV2Res, + }); + + crr.run(err => { + assert.ifError(err); + + expect(crr.cloudserverclient.putMetadata).toHaveBeenCalledTimes(1); + const body = JSON.parse(crr.cloudserverclient.putMetadata.mock.calls[0][0].Body); + const repInfo = body.replicationInfo; + + // V2 metadata: no top-level destination/storageClass/storageType + expect(repInfo.destination).toBeUndefined(); + expect(repInfo.storageClass).toBeUndefined(); + expect(repInfo.storageType).toBeUndefined(); + + // Source role only at top level + expect(repInfo.role).toBe('arn:aws:iam::8765432:role/sourceRole'); + + // Backend has per-entry destination and role (account replaced) + expect(repInfo.backends).toHaveLength(1); + expect(repInfo.backends[0]).toMatchObject({ + site: 'dest-A', + status: 'PENDING', + destination: 'arn:aws:s3:::bucket-a', + role: 'arn:aws:iam::222222222222:role/repRule', + dataStoreVersionId: '', + }); + + // All pending → top-level PROCESSING (mixed) or PENDING (all same) + expect(repInfo.status).toBe('PROCESSING'); + + assert.strictEqual(crr._nProcessed, 1); + assert.strictEqual(crr._nUpdated, 1); + assert.strictEqual(crr._nSkipped, 0); + done(); + }); + }); + + it('should mark object pending for both V2 rules when key matches both prefixes', done => { + const listVersionDocsKey = { + IsTruncated: false, + Versions: [{ + ETag: '"abc"', + ChecksumAlgorithm: [], + Size: 100, + StorageClass: 'STANDARD', + Key: 'docs/report.pdf', + VersionId: 'aJdO148N3LjN00000000001I4j3QKItW', + IsLatest: true, + LastModified: '2024-01-05T13:11:31.861Z', + Owner: { DisplayName: 'bart', ID: '0' }, + }], + DeleteMarkers: [], + Name: 'bucket0', + MaxKeys: 1000, + CommonPrefixes: [], + }; + + const crr = initializeCrrWithMocks({ + buckets: ['bucket0'], + workers: 10, + replicationStatusToProcess: ['NEW'], + }, logger, { + ListObjectVersionsCommand: listVersionDocsKey, + GetBucketReplicationCommand: getBucketReplicationV2Res, + }); + + crr.run(err => { + assert.ifError(err); + + expect(crr.cloudserverclient.putMetadata).toHaveBeenCalledTimes(1); + const body = JSON.parse(crr.cloudserverclient.putMetadata.mock.calls[0][0].Body); + const repInfo = body.replicationInfo; + + // Both backends present + expect(repInfo.backends).toHaveLength(2); + const siteA = repInfo.backends.find(b => b.site === 'dest-A'); + const siteB = repInfo.backends.find(b => b.site === 'dest-B'); + expect(siteA).toMatchObject({ + status: 'PENDING', + destination: 'arn:aws:s3:::bucket-a', + role: 'arn:aws:iam::222222222222:role/repRule', + }); + expect(siteB).toMatchObject({ + status: 'PENDING', + destination: 'arn:aws:s3:::bucket-b', + role: 'arn:aws:iam::333333333333:role/repRule', + }); + + expect(repInfo.destination).toBeUndefined(); + expect(repInfo.storageClass).toBeUndefined(); + expect(repInfo.storageType).toBeUndefined(); + + assert.strictEqual(crr._nUpdated, 1); + done(); + }); + }); + + it('should skip object when no V2 rule matches its key prefix', done => { + const listVersionLogsKey = { + IsTruncated: false, + Versions: [{ + ETag: '"abc"', + ChecksumAlgorithm: [], + Size: 100, + StorageClass: 'STANDARD', + Key: 'logs/app.log', + VersionId: 'aJdO148N3LjN00000000001I4j3QKItW', + IsLatest: true, + LastModified: '2024-01-05T13:11:31.861Z', + Owner: { DisplayName: 'bart', ID: '0' }, + }], + DeleteMarkers: [], + Name: 'bucket0', + MaxKeys: 1000, + CommonPrefixes: [], + }; + + // V2 config with only a 'docs/' prefix rule (no empty-prefix catch-all) + const v2DocsOnly = { + ReplicationConfiguration: { + Role: 'arn:aws:iam::8765432:role/sourceRole', + Rules: [{ + ID: 'rule-docs', + Filter: { Prefix: 'docs/' }, + Priority: 1, + Status: 'Enabled', + Destination: { + Bucket: 'arn:aws:s3:::bucket-b', + StorageClass: 'dest-B', + Account: '333333333333', + }, + }], + }, + }; + + const crr = initializeCrrWithMocks({ + buckets: ['bucket0'], + workers: 10, + replicationStatusToProcess: ['NEW'], + }, logger, { + ListObjectVersionsCommand: listVersionLogsKey, + GetBucketReplicationCommand: v2DocsOnly, + }); + + crr.run(err => { + assert.ifError(err); + + expect(crr.cloudserverclient.getMetadata).not.toHaveBeenCalled(); + expect(crr.cloudserverclient.putMetadata).not.toHaveBeenCalled(); + + assert.strictEqual(crr._nProcessed, 0); + assert.strictEqual(crr._nSkipped, 1); + assert.strictEqual(crr._nUpdated, 0); + done(); + }); + }); + + it('should filter to SITE_NAME when set in V2 mode', done => { + const crr = initializeCrrWithMocks({ + buckets: ['bucket0'], + workers: 10, + replicationStatusToProcess: ['NEW'], + siteName: 'dest-A', + }, logger, { + GetBucketReplicationCommand: getBucketReplicationV2Res, + }); + + crr.run(err => { + assert.ifError(err); + + expect(crr.cloudserverclient.putMetadata).toHaveBeenCalledTimes(1); + const body = JSON.parse(crr.cloudserverclient.putMetadata.mock.calls[0][0].Body); + const repInfo = body.replicationInfo; + + // Only dest-A backend, not dest-B + expect(repInfo.backends).toHaveLength(1); + expect(repInfo.backends[0].site).toBe('dest-A'); + done(); + }); + }); + + it('should skip V2 object when all applicable sites already match the existing status', done => { + // key0 only matches rule1 (prefix='', dest-A); dest-A is already COMPLETED; filter is NEW → skip + const crr = initializeCrrWithMocks({ + buckets: ['bucket0'], + workers: 10, + replicationStatusToProcess: ['NEW'], + }, logger, { + GetBucketReplicationCommand: getBucketReplicationV2Res, + }); + + crr.cloudserverclient.getMetadata = jest.fn((p, cb) => { + const md = JSON.parse(getMetadataRes.Body); + md.replicationInfo = { + status: 'COMPLETED', + role: 'arn:aws:iam::8765432:role/sourceRole', + backends: [{ + site: 'dest-A', + status: 'COMPLETED', + destination: 'arn:aws:s3:::bucket-a', + role: 'arn:aws:iam::222222222222:role/repRule', + dataStoreVersionId: '', + }], + content: ['METADATA', 'DATA'], + }; + cb(null, { Body: JSON.stringify(md) }); + }); + + crr.run(err => { + assert.ifError(err); + + expect(crr.cloudserverclient.putMetadata).not.toHaveBeenCalled(); + assert.strictEqual(crr._nProcessed, 1); + assert.strictEqual(crr._nSkipped, 1); + assert.strictEqual(crr._nUpdated, 0); + done(); + }); + }); + + it('should compute PROCESSING top-level status for docs key with mixed backend statuses in V2', done => { + const listVersionDocsKey = { + IsTruncated: false, + Versions: [{ + ETag: '"abc"', ChecksumAlgorithm: [], Size: 100, + StorageClass: 'STANDARD', Key: 'docs/report.pdf', + VersionId: 'aJdO148N3LjN00000000001I4j3QKItW', IsLatest: true, + LastModified: '2024-01-05T13:11:31.861Z', + Owner: { DisplayName: 'bart', ID: '0' }, + }], + DeleteMarkers: [], Name: 'bucket0', MaxKeys: 1000, CommonPrefixes: [], + }; + + const crr = initializeCrrWithMocks({ + buckets: ['bucket0'], + workers: 10, + replicationStatusToProcess: ['NEW'], + }, logger, { + ListObjectVersionsCommand: listVersionDocsKey, + GetBucketReplicationCommand: getBucketReplicationV2Res, + }); + + // dest-A already COMPLETED; dest-B is NEW → both rules match 'docs/report.pdf' + crr.cloudserverclient.getMetadata = jest.fn((p, cb) => { + const md = JSON.parse(getMetadataRes.Body); + md.replicationInfo = { + status: 'COMPLETED', + role: 'arn:aws:iam::8765432:role/sourceRole', + backends: [{ + site: 'dest-A', + status: 'COMPLETED', + destination: 'arn:aws:s3:::bucket-a', + role: 'arn:aws:iam::222222222222:role/repRule', + dataStoreVersionId: '', + }], + content: ['METADATA', 'DATA'], + }; + cb(null, { Body: JSON.stringify(md) }); + }); + + crr.run(err => { + assert.ifError(err); + + expect(crr.cloudserverclient.putMetadata).toHaveBeenCalledTimes(1); + const body = JSON.parse(crr.cloudserverclient.putMetadata.mock.calls[0][0].Body); + const repInfo = body.replicationInfo; + + // dest-A COMPLETED, dest-B PENDING → PROCESSING + expect(repInfo.status).toBe('PROCESSING'); + expect(repInfo.backends).toHaveLength(2); + const destA = repInfo.backends.find(b => b.site === 'dest-A'); + const destB = repInfo.backends.find(b => b.site === 'dest-B'); + expect(destA.status).toBe('COMPLETED'); + expect(destB.status).toBe('PENDING'); + done(); + }); + }); + + it('should update per-backend destination and role when forceUsingConfiguration is true in V2', done => { + // Use COMPLETED filter so the object (dest-A COMPLETED) is re-processed with forceUsingConfiguration + const crr = initializeCrrWithMocks({ + buckets: ['bucket0'], + workers: 10, + replicationStatusToProcess: ['COMPLETED'], + forceUsingConfiguration: true, + }, logger, { + GetBucketReplicationCommand: getBucketReplicationV2Res, + }); + + // Object has dest-A with stale destination/role + crr.cloudserverclient.getMetadata = jest.fn((p, cb) => { + const md = JSON.parse(getMetadataRes.Body); + md.replicationInfo = { + status: 'COMPLETED', + role: 'arn:aws:iam::8765432:role/sourceRole', + backends: [{ + site: 'dest-A', + status: 'COMPLETED', + destination: 'arn:aws:s3:::old-bucket', + role: 'arn:aws:iam::999999999999:role/oldRole', + dataStoreVersionId: '', + }], + content: ['METADATA', 'DATA'], + }; + cb(null, { Body: JSON.stringify(md) }); + }); + + crr.run(err => { + assert.ifError(err); + + expect(crr.cloudserverclient.putMetadata).toHaveBeenCalledTimes(1); + const body = JSON.parse(crr.cloudserverclient.putMetadata.mock.calls[0][0].Body); + const repInfo = body.replicationInfo; + + const destA = repInfo.backends.find(b => b.site === 'dest-A'); + expect(destA.destination).toBe('arn:aws:s3:::bucket-a'); + expect(destA.role).toBe('arn:aws:iam::222222222222:role/repRule'); + done(); + }); + }); +}); diff --git a/tests/utils/crr.js b/tests/utils/crr.js index 7d45718f..83e1532f 100644 --- a/tests/utils/crr.js +++ b/tests/utils/crr.js @@ -154,6 +154,37 @@ const getMetadataRes = { const putMetadataRes = { versionId: '98295539708053999999RG001 ' }; +// V2 bucket replication config: one rule per destination, each with an Account field +const getBucketReplicationV2Res = { + ReplicationConfiguration: { + Role: 'arn:aws:iam::8765432:role/sourceRole,arn:aws:iam::111111111111:role/repRule', + Rules: [ + { + ID: 'rule1-dest-A', + Filter: { Prefix: '' }, + Priority: 1, + Status: 'Enabled', + Destination: { + Bucket: 'arn:aws:s3:::bucket-a', + StorageClass: 'dest-A', + Account: '222222222222', + }, + }, + { + ID: 'rule1-dest-B', + Filter: { Prefix: 'docs/' }, + Priority: 2, + Status: 'Enabled', + Destination: { + Bucket: 'arn:aws:s3:::bucket-b', + StorageClass: 'dest-B', + Account: '333333333333', + }, + }, + ], + }, +}; + /** * Initializes the ReplicationStatusUpdater class with mock methods for testing. * @@ -206,6 +237,7 @@ module.exports = { listVersionsRes, listVersionWithMarkerRes, getBucketReplicationRes, + getBucketReplicationV2Res, getMetadataRes, putMetadataRes, objectMd, From f9fca0c5455f652bf00fb51bfc9f63178c2ccadb Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Mon, 1 Jun 2026 22:17:16 +0200 Subject: [PATCH 02/15] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20simplify=20code=20by?= =?UTF-8?q?=20extracting=20logic=20v1=20and=20remove=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- CRR/ReplicationStatusUpdater.js | 113 +++++++++++++-------- tests/unit/CRR/ReplicationStatusUpdater.js | 42 +++++++- 2 files changed, 113 insertions(+), 42 deletions(-) diff --git a/CRR/ReplicationStatusUpdater.js b/CRR/ReplicationStatusUpdater.js index 29f437da..996568d4 100644 --- a/CRR/ReplicationStatusUpdater.js +++ b/CRR/ReplicationStatusUpdater.js @@ -118,18 +118,16 @@ class ReplicationStatusUpdater { /** - * Returns true if the replication config uses the legacy V1 format (any rule has a + * Returns true if the replication config uses the V1 format (any rule has a * comma-separated StorageClass, e.g. "dest-A,dest-B"). * @private * @param {Object} repConfig - The replication configuration from GetBucketReplicationCommand. * @returns {boolean} */ - _isLegacyFormat(repConfig) { - // Comma-separated StorageClass is always V1 (multiple destinations in one rule) + _isV1Format(repConfig) { if (repConfig.Rules.some(r => r.Destination.StorageClass?.includes(','))) { return true; } - // V2 rules carry Filter (object), Priority, or Destination.Account; V1 rules have none of these return repConfig.Rules.every(r => r.Filter === undefined && r.Priority === undefined && @@ -176,6 +174,72 @@ class ReplicationStatusUpdater { return destRole.replace(/(arn:aws:iam::)[^:]*(:)/, `$1${account}$2`); } + /** + * Removes V1-only top-level fields from replicationInfo that have no meaning in V2 format. + * @private + * @param {Object} replicationInfo - The replication info object to mutate. + * @returns {void} + */ + _removeV1Fields(replicationInfo) { + // eslint-disable-next-line no-param-reassign + delete replicationInfo.destination; + // eslint-disable-next-line no-param-reassign + delete replicationInfo.storageClass; + // eslint-disable-next-line no-param-reassign + delete replicationInfo.storageType; + // eslint-disable-next-line no-param-reassign + delete replicationInfo.dataStoreVersionId; + } + + /** + * Initializes V2 replication info on objMD if it is missing or has no status. + * @private + * @param {ObjectMD} objMD - The object metadata. + * @param {string} sourceRole - The source-side IAM role ARN. + * @returns {Object} The (possibly newly created) replicationInfo object. + */ + _initV2ReplicationInfo(objMD, sourceRole) { + let replicationInfo = objMD.getReplicationInfo(); + if (!replicationInfo || !replicationInfo.status) { + const ops = objMD.getContentLength() === 0 ? ['METADATA'] : ['METADATA', 'DATA']; + objMD.setReplicationInfo({ + status: 'PENDING', + role: sourceRole, + backends: [], + content: ops, + isNFS: null, + }); + replicationInfo = objMD.getReplicationInfo(); + } + return replicationInfo; + } + + /** + * Applies matching rules to the backends list on objMD, setting each matched site to PENDING. + * @private + * @param {ObjectMD} objMD - The object metadata. + * @param {Array} rulesToUpdate - Pre-filtered rules to apply. + * @param {Object} repConfig - The full replication configuration. + * @returns {Array} The updated backends array. + */ + _applyRulesToBackends(objMD, rulesToUpdate, repConfig) { + const backends = objMD.getReplicationBackends(); + for (const rule of rulesToUpdate) { + const site = rule.Destination.StorageClass; + const destination = rule.Destination.Bucket; + const role = this._deriveRuleRole(repConfig.Role, rule.Destination.Account); + const existing = backends.find(b => b.site === site); + if (existing) { + existing.status = 'PENDING'; + existing.destination = destination; + existing.role = role; + } else { + backends.push({ site, status: 'PENDING', destination, role, dataStoreVersionId: '' }); + } + } + return backends; + } + /** * Computes the aggregate top-level replication status from all backends per the V2 rules: * any FAILED → FAILED; else any PENDING → PROCESSING; else COMPLETED. @@ -386,40 +450,9 @@ class ReplicationStatusUpdater { } const sourceRole = repConfig.Role.split(',')[0].trim(); - let replicationInfo = objMD.getReplicationInfo(); - if (!replicationInfo || !replicationInfo.status) { - const ops = objMD.getContentLength() === 0 ? ['METADATA'] : ['METADATA', 'DATA']; - objMD.setReplicationInfo({ - status: 'PENDING', - role: sourceRole, - backends: [], - content: ops, - isNFS: null, - }); - replicationInfo = objMD.getReplicationInfo(); - } - // Remove legacy top-level fields that don't belong in V2 format - delete replicationInfo.destination; - delete replicationInfo.storageClass; - delete replicationInfo.storageType; - delete replicationInfo.dataStoreVersionId; - - const backends = objMD.getReplicationBackends(); - - for (const rule of rulesToUpdate) { - const site = rule.Destination.StorageClass; - const destination = rule.Destination.Bucket; - const role = this._deriveRuleRole(repConfig.Role, rule.Destination.Account); - const existing = backends.find(b => b.site === site); - if (existing) { - existing.status = 'PENDING'; - existing.destination = destination; - existing.role = role; - } else { - backends.push({ site, status: 'PENDING', destination, role, dataStoreVersionId: '' }); - } - } - objMD.setReplicationBackends(backends); + const replicationInfo = this._initV2ReplicationInfo(objMD, sourceRole); + this._removeV1Fields(replicationInfo); + const backends = this._applyRulesToBackends(objMD, rulesToUpdate, repConfig); if (this.forceUsingConfiguration) { for (const backend of backends) { @@ -503,8 +536,7 @@ class ReplicationStatusUpdater { (repConfig, next) => { const { Rules } = repConfig; - if (this._isLegacyFormat(repConfig)) { - // V1: single storage class (possibly comma-separated, handled by _markObjectPending) + if (this._isV1Format(repConfig)) { const storageClass = this.siteName || Rules[0].Destination.StorageClass; if (!storageClass) { const errMsg = 'missing SITE_NAME environment variable, must be set to' @@ -526,7 +558,6 @@ class ReplicationStatusUpdater { }, next); } - // V2: one rule per destination, prefix-matched per object return eachLimit(versions, this.workers, (i, apply) => { const { Key, VersionId, IsLatest } = i; if (this.currentVersionOnly && !IsLatest) { diff --git a/tests/unit/CRR/ReplicationStatusUpdater.js b/tests/unit/CRR/ReplicationStatusUpdater.js index bc592f9a..83be4d3a 100644 --- a/tests/unit/CRR/ReplicationStatusUpdater.js +++ b/tests/unit/CRR/ReplicationStatusUpdater.js @@ -907,6 +907,46 @@ describe('ReplicationStatusUpdater model version guard', () => { }); }); +describe('ReplicationStatusUpdater _removeV1Fields', () => { + it('should delete V1-only top-level fields from replicationInfo', () => { + const crr = initializeCrrWithMocks({ + buckets: ['bucket0'], + workers: 1, + replicationStatusToProcess: ['NEW'], + }, logger); + + const repInfo = { + status: 'PENDING', + destination: 'arn:aws:s3:::bucket', + storageClass: 'dest-A', + storageType: 'aws_s3', + dataStoreVersionId: 'v1', + role: 'arn:aws:iam::123:role/r', + backends: [], + }; + crr._removeV1Fields(repInfo); + expect(repInfo.destination).toBeUndefined(); + expect(repInfo.storageClass).toBeUndefined(); + expect(repInfo.storageType).toBeUndefined(); + expect(repInfo.dataStoreVersionId).toBeUndefined(); + expect(repInfo.status).toBe('PENDING'); + expect(repInfo.role).toBe('arn:aws:iam::123:role/r'); + }); + + it('should be a no-op when V1 fields are already absent', () => { + const crr = initializeCrrWithMocks({ + buckets: ['bucket0'], + workers: 1, + replicationStatusToProcess: ['NEW'], + }, logger); + + const repInfo = { status: 'PENDING', role: 'arn:aws:iam::123:role/r', backends: [] }; + expect(() => crr._removeV1Fields(repInfo)).not.toThrow(); + expect(repInfo.destination).toBeUndefined(); + expect(repInfo.storageClass).toBeUndefined(); + }); +}); + describe('ReplicationStatusUpdater V2 format', () => { // V2 config: rule1 (prefix='', dest-A) and rule2 (prefix='docs/', dest-B) // Object key 'key0' matches only rule1 (dest-A) @@ -944,7 +984,7 @@ describe('ReplicationStatusUpdater V2 format', () => { dataStoreVersionId: '', }); - // All pending → top-level PROCESSING (mixed) or PENDING (all same) + // All pending → top-level PROCESSING expect(repInfo.status).toBe('PROCESSING'); assert.strictEqual(crr._nProcessed, 1); From a8756dd1e196febc04c4c6e6f3a4a1fd7ec71af4 Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Mon, 8 Jun 2026 17:26:15 +0200 Subject: [PATCH 03/15] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20use=20Arsenal=20stat?= =?UTF-8?q?ic=20methods=20for=20CRR=20multi-site=20V2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- CRR/ReplicationStatusUpdater.js | 140 ++--- package.json | 2 +- tests/utils/index.js | 12 +- yarn.lock | 924 +++++++++++++++++++++++++++++++- 4 files changed, 977 insertions(+), 101 deletions(-) diff --git a/CRR/ReplicationStatusUpdater.js b/CRR/ReplicationStatusUpdater.js index 996568d4..17bb63e3 100644 --- a/CRR/ReplicationStatusUpdater.js +++ b/CRR/ReplicationStatusUpdater.js @@ -1,7 +1,7 @@ const { doWhilst, eachSeries, eachLimit, waterfall, } = require('async'); -const { ObjectMD } = require('arsenal').models; +const { ObjectMD, ReplicationConfiguration } = require('arsenal').models; const { ListObjectVersionsCommand, GetBucketReplicationCommand @@ -118,21 +118,14 @@ class ReplicationStatusUpdater { /** - * Returns true if the replication config uses the V1 format (any rule has a - * comma-separated StorageClass, e.g. "dest-A,dest-B"). + * Returns true if the replication config uses the V1 format. + * V2 rules carry a Filter element; V1 rules do not. * @private * @param {Object} repConfig - The replication configuration from GetBucketReplicationCommand. * @returns {boolean} */ _isV1Format(repConfig) { - if (repConfig.Rules.some(r => r.Destination.StorageClass?.includes(','))) { - return true; - } - return repConfig.Rules.every(r => - r.Filter === undefined && - r.Priority === undefined && - r.Destination.Account === undefined - ); + return repConfig.Rules.every(r => !r.Filter); } /** @@ -159,21 +152,6 @@ class ReplicationStatusUpdater { return [...siteMap.values()]; } - /** - * Derives the per-rule destination role ARN by substituting the account ID. - * If baseRole is "src,dest" format, uses the dest part as the template. - * @private - * @param {string} baseRole - The top-level Role from the replication config. - * @param {string} [account] - The account ID from Destination.Account. - * @returns {string} - */ - _deriveRuleRole(baseRole, account) { - const roles = baseRole.split(','); - const destRole = roles.length > 1 ? roles[1].trim() : roles[0].trim(); - if (!account) { return destRole; } - return destRole.replace(/(arn:aws:iam::)[^:]*(:)/, `$1${account}$2`); - } - /** * Removes V1-only top-level fields from replicationInfo that have no meaning in V2 format. * @private @@ -196,10 +174,10 @@ class ReplicationStatusUpdater { * @private * @param {ObjectMD} objMD - The object metadata. * @param {string} sourceRole - The source-side IAM role ARN. - * @returns {Object} The (possibly newly created) replicationInfo object. + * @returns {void} */ _initV2ReplicationInfo(objMD, sourceRole) { - let replicationInfo = objMD.getReplicationInfo(); + const replicationInfo = objMD.getReplicationInfo(); if (!replicationInfo || !replicationInfo.status) { const ops = objMD.getContentLength() === 0 ? ['METADATA'] : ['METADATA', 'DATA']; objMD.setReplicationInfo({ @@ -209,35 +187,7 @@ class ReplicationStatusUpdater { content: ops, isNFS: null, }); - replicationInfo = objMD.getReplicationInfo(); } - return replicationInfo; - } - - /** - * Applies matching rules to the backends list on objMD, setting each matched site to PENDING. - * @private - * @param {ObjectMD} objMD - The object metadata. - * @param {Array} rulesToUpdate - Pre-filtered rules to apply. - * @param {Object} repConfig - The full replication configuration. - * @returns {Array} The updated backends array. - */ - _applyRulesToBackends(objMD, rulesToUpdate, repConfig) { - const backends = objMD.getReplicationBackends(); - for (const rule of rulesToUpdate) { - const site = rule.Destination.StorageClass; - const destination = rule.Destination.Bucket; - const role = this._deriveRuleRole(repConfig.Role, rule.Destination.Account); - const existing = backends.find(b => b.site === site); - if (existing) { - existing.status = 'PENDING'; - existing.destination = destination; - existing.role = role; - } else { - backends.push({ site, status: 'PENDING', destination, role, dataStoreVersionId: '' }); - } - } - return backends; } /** @@ -266,10 +216,10 @@ class ReplicationStatusUpdater { // Either site specific replication info is missing // or are initialized with empty fields. return (!objMD.getReplicationInfo() - || !objMD.getReplicationSiteStatus(site)); + || !objMD.getReplicationSiteStatus({ site })); } return (objMD.getReplicationInfo() - && objMD.getReplicationSiteStatus(site) === filter); + && objMD.getReplicationSiteStatus({ site }) === filter); }); } @@ -337,34 +287,34 @@ class ReplicationStatusUpdater { : ['METADATA', 'DATA']; replicationInfo = { status: 'PENDING', - content: ops, backends: [], + content: ops, destination, storageClass: '', role: Role, storageType: '', + dataStoreVersionId: '', }; objMD.setReplicationInfo(replicationInfo); } // Force reset object's replication configuration to match bucket's configuration if (this.forceUsingConfiguration) { - objMD.setReplicationTargetBucket(destination); + objMD.getReplicationInfo().destination = destination; objMD.setReplicationRoles(Role); } // Update replication info with site specific info - if (!objMD.getReplicationSiteStatus(storageClass)) { + if (!objMD.getReplicationSiteStatus({ site: storageClass })) { // When replicating to multiple destinations, // the storageClass and storageType properties // become comma-separated lists of the storage // classes and types of the replication destinations. - const storageClasses = objMD.getReplicationStorageClass() - ? `${objMD.getReplicationStorageClass()},${storageClass}` : storageClass; - objMD.setReplicationStorageClass(storageClasses); + const ri = objMD.getReplicationInfo(); + ri.storageClass = ri.storageClass + ? `${ri.storageClass},${storageClass}` : storageClass; if (this.storageType) { - const storageTypes = objMD.getReplicationStorageType() - ? `${objMD.getReplicationStorageType()},${this.storageType}` : this.storageType; - objMD.setReplicationStorageType(storageTypes); + ri.storageType = ri.storageType + ? `${ri.storageType},${this.storageType}` : this.storageType; } // Add site to the list of replication backends const backends = objMD.getReplicationBackends(); @@ -376,7 +326,7 @@ class ReplicationStatusUpdater { objMD.setReplicationBackends(backends); } - objMD.setReplicationSiteStatus(storageClass, 'PENDING'); + objMD.setReplicationSiteStatus({ site: storageClass }, 'PENDING'); objMD.setReplicationStatus('PENDING'); objMD.updateMicroVersionId(); const md = objMD.getSerialized(); @@ -440,31 +390,53 @@ class ReplicationStatusUpdater { return next(new Error('model version regression: refusing to overwrite newer metadata')); } - const rulesToUpdate = matchingRules.filter(rule => - this._objectShouldBeUpdated(objMD, rule.Destination.StorageClass) + // Adapt AWS SDK rules to arsenal's ReplicationConfigurationMetadata shape + const arsenalConfig = { + role: repConfig.Role, + destination: matchingRules[0]?.Destination.Bucket ?? '', + rules: matchingRules.map(r => ({ + enabled: r.Status === 'Enabled', + prefix: r.Filter?.Prefix ?? r.Prefix ?? '', + storageClass: r.Destination.StorageClass, + destination: r.Destination.Bucket, + account: r.Destination.Account, + priority: r.Priority, + id: r.ID ?? '', + })), + }; + + // Capture existing backends before any initialization (to carry forward dataStoreVersionId) + const existingBackends = objMD.getReplicationInfo()?.backends; + + // resolveBackends handles prefix matching, priority dedup, and per-backend destination/role + const candidateBackends = ReplicationConfiguration.resolveBackends( + arsenalConfig, key, () => false, existingBackends, + ); + + const backendsToUpdate = candidateBackends.filter(b => + this._objectShouldBeUpdated(objMD, b.site) ); - if (rulesToUpdate.length === 0) { + if (backendsToUpdate.length === 0) { skip = true; return process.nextTick(next); } - const sourceRole = repConfig.Role.split(',')[0].trim(); - const replicationInfo = this._initV2ReplicationInfo(objMD, sourceRole); + const sourceRole = ReplicationConfiguration.resolveSourceRole(repConfig.Role); + this._initV2ReplicationInfo(objMD, sourceRole); + const replicationInfo = objMD.getReplicationInfo(); this._removeV1Fields(replicationInfo); - const backends = this._applyRulesToBackends(objMD, rulesToUpdate, repConfig); + objMD.setReplicationInfo(replicationInfo); - if (this.forceUsingConfiguration) { - for (const backend of backends) { - const rule = matchingRules.find(r => r.Destination.StorageClass === backend.site); - if (rule) { - backend.destination = rule.Destination.Bucket; - backend.role = this._deriveRuleRole(repConfig.Role, rule.Destination.Account); - } - } - } + // Merge: preserve existing backends for non-updated sites + const updatedSites = new Set(backendsToUpdate.map(b => b.site)); + const finalBackends = [ + ...(existingBackends ?? []).filter(b => !updatedSites.has(b.site)), + ...backendsToUpdate, + ]; + objMD.setReplicationBackends(finalBackends); - objMD.setReplicationStatus(this._computeTopLevelStatus(backends)); + objMD.setReplicationStatus(this._computeTopLevelStatus(finalBackends)); objMD.updateMicroVersionId(); const md = objMD.getSerialized(); return this.cloudserverclient.putMetadata({ diff --git a/package.json b/package.json index 886bb11a..ad94b04c 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@senx/warp10": "^2.0.3", "@smithy/util-retry": "^4.0.7", "JSONStream": "^1.3.5", - "arsenal": "git+https://github.com/scality/arsenal#8.2.36", + "arsenal": "git+https://github.com/scality/Arsenal#improvement/ARSN-571/crr-multi", "async": "^3.2.6", "bucketclient": "scality/bucketclient#8.2.6", "express": "^5.1.0", diff --git a/tests/utils/index.js b/tests/utils/index.js index 7456d785..b3f16c23 100644 --- a/tests/utils/index.js +++ b/tests/utils/index.js @@ -18,6 +18,11 @@ function generateKeyId(isMaster, key, versionId) { function generateMD(isMaster, objectKey, lastModified, storageClasses) { const keyId = generateKeyId(isMaster, objectKey, testVersion); + const objMD = new ObjectMD() + .setKey(objectKey) + .setLastModified(lastModified) + .setVersionId(testVersion); + objMD.setReplicationInfo({ storageClass: storageClasses }); return { _id: { id: keyId, @@ -25,12 +30,7 @@ function generateMD(isMaster, objectKey, lastModified, storageClasses) { storageClasses, versionId: testVersion, }, - value: new ObjectMD() - .setKey(objectKey) - .setLastModified(lastModified) - .setVersionId(testVersion) - .setReplicationStorageClass(storageClasses) - .getValue(), + value: objMD.getValue(), }; } diff --git a/yarn.lock b/yarn.lock index 078b44b0..bfa58aef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -80,6 +80,36 @@ "@smithy/util-utf8" "^2.0.0" tslib "^2.6.2" +"@aws-sdk/checksums@^3.1000.2": + version "3.1000.2" + resolved "https://registry.yarnpkg.com/@aws-sdk/checksums/-/checksums-3.1000.2.tgz#be7ac8cdf05d9d7bde93ae1b771d7042cee2cd92" + integrity sha512-PIha+kauTbp6IRmOpYktPTrlfrrSqDVixvhO/EUOFOf62DPX81CaJoHJreuA1m9HYpSKyXf99BKjU1dvJPeUfw== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@aws-crypto/crc32c" "5.2.0" + "@aws-crypto/util" "5.2.0" + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + +"@aws-sdk/client-cognito-identity@3.1063.0": + version "3.1063.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.1063.0.tgz#284bf99108718fcf6afb375b99f95da5c338d078" + integrity sha512-fLwNblkowkRyuxdVehlHVOnr/7bBf8Y1UGYdhhpuMPHOQL2QTY6kLcQ+EV1BhTQG1p4ATwaONNJsIk44hxEGMA== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/credential-provider-node" "^3.972.52" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/fetch-http-handler" "^5.4.6" + "@smithy/node-http-handler" "^4.7.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/client-iam@^3.962.0": version "3.1030.0" resolved "https://registry.yarnpkg.com/@aws-sdk/client-iam/-/client-iam-3.1030.0.tgz#bd45127b2f35e02f8be97ff8f3da1afc2caff285" @@ -126,6 +156,22 @@ "@smithy/util-waiter" "^4.2.15" tslib "^2.6.2" +"@aws-sdk/client-kms@^3.975.0": + version "3.1063.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-kms/-/client-kms-3.1063.0.tgz#9dbae3e1e447c6808d30c208f15bcb3baeb44c56" + integrity sha512-nRq2Hcyxh6nl3dZ6dVXIF5lh650u8eIcpVZ1Ur6Lk/IiuQw9OFCP7KL4TDRpePzpIDL15aUFPjc9gLMmI6Q1zw== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/credential-provider-node" "^3.972.52" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/fetch-http-handler" "^5.4.6" + "@smithy/node-http-handler" "^4.7.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/client-s3@^3.1009.0": version "3.1030.0" resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.1030.0.tgz#f5c593deb0e32fbd0a174d00feae9c69c0e7cccf" @@ -248,6 +294,26 @@ "@smithy/util-waiter" "^4.2.5" tslib "^2.6.2" +"@aws-sdk/client-s3@^3.975.0": + version "3.1063.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.1063.0.tgz#b5e10c8db7fee96c326768d97221b8f674a17446" + integrity sha512-ETn+vvmZVK1MmOZwVBXmWANpmD5iTbzojIqyEIoZ86qo+8oWy35S8QyQNE/ZDI+WHgMU1dS+VSYbpRl1QkEySg== + dependencies: + "@aws-crypto/sha1-browser" "5.2.0" + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/credential-provider-node" "^3.972.52" + "@aws-sdk/middleware-flexible-checksums" "^3.974.27" + "@aws-sdk/middleware-sdk-s3" "^3.972.48" + "@aws-sdk/signature-v4-multi-region" "^3.996.32" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/fetch-http-handler" "^5.4.6" + "@smithy/node-http-handler" "^4.7.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/client-sso@3.940.0": version "3.940.0" resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.940.0.tgz#23a6b156d9ba0144c01eb1d0c1654600b35fc708" @@ -330,6 +396,20 @@ "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" +"@aws-sdk/core@^3.974.18": + version "3.974.18" + resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.974.18.tgz#add4817784a3d96d19057701c40fc4ae76e21506" + integrity sha512-JDYCPI0j7zGrzXTDFsLB346cxss7J/AxH7+O0MzWlqppJBEyB9Qe6TQXRL6iwLUo/xZkNv9KFmBL2hqElmwW0g== + dependencies: + "@aws-sdk/types" "^3.973.11" + "@aws-sdk/xml-builder" "^3.972.28" + "@aws/lambda-invoke-store" "^0.2.2" + "@smithy/core" "^3.24.6" + "@smithy/signature-v4" "^5.4.6" + "@smithy/types" "^4.14.3" + bowser "^2.11.0" + tslib "^2.6.2" + "@aws-sdk/crc64-nvme@^3.972.6": version "3.972.6" resolved "https://registry.yarnpkg.com/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.6.tgz#4e023b3e3b5f67d3129c97c5caa3e18699d3d550" @@ -338,6 +418,17 @@ "@smithy/types" "^4.14.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-cognito-identity@^3.972.42": + version "3.972.42" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.42.tgz#050eb06d91d51100cd785df16f2ea052a6af8db8" + integrity sha512-94W7f8xVsdLEjv3TY8R+beoFL0pIRduiGZdqMfIVMvQfn6q9IA3SgE2mIQluu3VCULn8PopB/gx7Fns8ETn/1Q== + dependencies: + "@aws-sdk/nested-clients" "^3.997.17" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/credential-provider-env@3.940.0": version "3.940.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.940.0.tgz#e04dc17300de228d572d5783c825a55d18851ecf" @@ -360,6 +451,17 @@ "@smithy/types" "^4.14.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-env@^3.972.44": + version "3.972.44" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.44.tgz#123bf8b3131ac308898b15181478ce14e5e19fe9" + integrity sha512-3hKJVrZ7bqXzDAXCQp+OaQ1ASN+vWstaNuEH418wQVl//cRZhqhfR9Bjk1qIWmgUGe8/D3gdO73PgidRj378EQ== + dependencies: + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/credential-provider-http@3.940.0": version "3.940.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.940.0.tgz#0888b39befaef297d67dcecd35d9237dbb5ab1c0" @@ -392,6 +494,19 @@ "@smithy/util-stream" "^4.5.22" tslib "^2.6.2" +"@aws-sdk/credential-provider-http@^3.972.46": + version "3.972.46" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.46.tgz#d54eb35e09b0e5ccd7e7171b1bdf2b384b823ea9" + integrity sha512-VhwC9pGAZHhiQ2xSViyOPDFqvr9aRxGCAXZtADsUhU3R65nad7y//CwynE6mQnWNR+suRlqE79W36IVayL+m1g== + dependencies: + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/fetch-http-handler" "^5.4.6" + "@smithy/node-http-handler" "^4.7.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/credential-provider-ini@3.940.0": version "3.940.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.940.0.tgz#b7a46fae4902f545e4f2cbcbd4f71dfae783de30" @@ -432,6 +547,25 @@ "@smithy/types" "^4.14.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-ini@^3.972.50": + version "3.972.50" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.50.tgz#bb99cebe7dc335a6c262e43022ead6fde2f0035d" + integrity sha512-09Xi6ovxiK42+De/qBGF71sT5F2bWgYM+1fFyDwSOpy1xpsQ5R/naIu7MVDpH6Dic36QNc8dAv4KADtMGK2JYg== + dependencies: + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/credential-provider-env" "^3.972.44" + "@aws-sdk/credential-provider-http" "^3.972.46" + "@aws-sdk/credential-provider-login" "^3.972.49" + "@aws-sdk/credential-provider-process" "^3.972.44" + "@aws-sdk/credential-provider-sso" "^3.972.49" + "@aws-sdk/credential-provider-web-identity" "^3.972.49" + "@aws-sdk/nested-clients" "^3.997.17" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/credential-provider-imds" "^4.3.7" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/credential-provider-login@3.940.0": version "3.940.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-login/-/credential-provider-login-3.940.0.tgz#d235cad516fd4a58fb261bc1291b7077efcbf58d" @@ -460,6 +594,18 @@ "@smithy/types" "^4.14.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-login@^3.972.49": + version "3.972.49" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.49.tgz#f3d04fc835cd1c670441023f3509c0b8c73e3041" + integrity sha512-EfJF/1Fh9mI4pZyoheU2RY9xUhTcugIZNkD63+orXMkYj/QXacJNbKVDUK90Yv5hE+aX+rt9J/EZ9Qr3vKOa7g== + dependencies: + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/nested-clients" "^3.997.17" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/credential-provider-node@3.940.0": version "3.940.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.940.0.tgz#5c4b3d13532f51528f769f8a87b4c7e7709ca0ad" @@ -496,6 +642,23 @@ "@smithy/types" "^4.14.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-node@^3.972.52": + version "3.972.52" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.52.tgz#9963981d5d043c9d7b5558e8d8586bfe15b29570" + integrity sha512-7QX+PbyiWBEOVipJq8Nke/TqXT6lAPLE7fvTaopa39/IVWuLfS+Fzdy71sZJONf/mLGgmtj6aU17+REw3+aRrw== + dependencies: + "@aws-sdk/credential-provider-env" "^3.972.44" + "@aws-sdk/credential-provider-http" "^3.972.46" + "@aws-sdk/credential-provider-ini" "^3.972.50" + "@aws-sdk/credential-provider-process" "^3.972.44" + "@aws-sdk/credential-provider-sso" "^3.972.49" + "@aws-sdk/credential-provider-web-identity" "^3.972.49" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/credential-provider-imds" "^4.3.7" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/credential-provider-process@3.940.0": version "3.940.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.940.0.tgz#47a11224c1a9d179f67cbd0873c9e99fe0cd0e85" @@ -520,6 +683,17 @@ "@smithy/types" "^4.14.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-process@^3.972.44": + version "3.972.44" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.44.tgz#fe9b358351570e6cd6df38aaba8b7304b89ce879" + integrity sha512-V+UUhZpRP7QDRhi+qgBDisM9tUBnYmMje8Bk77A6MZsfeGeGdMsQXmaHP1CDYFcept0o/Rz5g2Y0TMeVlG9dzg== + dependencies: + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/credential-provider-sso@3.940.0": version "3.940.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.940.0.tgz#fabadb014fd5c7b043b8b7ccb4e1bda66a2e88cc" @@ -548,6 +722,19 @@ "@smithy/types" "^4.14.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-sso@^3.972.49": + version "3.972.49" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.49.tgz#15e53221a59a4c656923acb4c976460fa81ab53b" + integrity sha512-9QqOYGuh5tZ76OzaT68kwI78AH+5lS/uZGGvkfxb3fc8FzRrIz2jOufNTliEBEeSAwmgK2rWLNsK+IB3zbtNPA== + dependencies: + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/nested-clients" "^3.997.17" + "@aws-sdk/token-providers" "3.1063.0" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/credential-provider-web-identity@3.940.0": version "3.940.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.940.0.tgz#25e83aa96c414608795e5d3c7be0e6d94bab6630" @@ -574,6 +761,41 @@ "@smithy/types" "^4.14.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-web-identity@^3.972.49": + version "3.972.49" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.49.tgz#9adcc1411d8156df4b521c1ed316ffcdaaf140c4" + integrity sha512-IYx1lN38MnnPXv+NBLpuATu0cZakbZ321TAfjW+aVkw7HIJF38YnEwdeEO55MSl3pl7hIX1IvvnD6EmnAzmAJw== + dependencies: + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/nested-clients" "^3.997.17" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + +"@aws-sdk/credential-providers@^3.975.0": + version "3.1063.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-providers/-/credential-providers-3.1063.0.tgz#f059026edabe1bc0dcaf980d35b6608d94be9680" + integrity sha512-ApW861WX8h7wKDKRNj7Dyne7awtq/PHrJVSdr3NsE/rmuFUxSha6BFJJ1H0S1MD7hCqZjYqz2VPPmCXo3IKC9A== + dependencies: + "@aws-sdk/client-cognito-identity" "3.1063.0" + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/credential-provider-cognito-identity" "^3.972.42" + "@aws-sdk/credential-provider-env" "^3.972.44" + "@aws-sdk/credential-provider-http" "^3.972.46" + "@aws-sdk/credential-provider-ini" "^3.972.50" + "@aws-sdk/credential-provider-login" "^3.972.49" + "@aws-sdk/credential-provider-node" "^3.972.52" + "@aws-sdk/credential-provider-process" "^3.972.44" + "@aws-sdk/credential-provider-sso" "^3.972.49" + "@aws-sdk/credential-provider-web-identity" "^3.972.49" + "@aws-sdk/nested-clients" "^3.997.17" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/credential-provider-imds" "^4.3.7" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/hash-node@^3.110.0": version "3.374.0" resolved "https://registry.yarnpkg.com/@aws-sdk/hash-node/-/hash-node-3.374.0.tgz#fad2ddb51ae7091b91ed1308836fe3385d128f9e" @@ -582,6 +804,18 @@ "@smithy/hash-node" "^1.0.1" tslib "^2.5.0" +"@aws-sdk/lib-storage@^3.975.0": + version "3.1063.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/lib-storage/-/lib-storage-3.1063.0.tgz#6335cd5b317c8840902693f4201b2dd26c93cbd8" + integrity sha512-WfDUIna6HicL8oTs26etBIr7yGwHIkadr8ecp/SjQAhX3t5xM/PLJCl0ZJ+bcLtYyjmWrO3Ydyf/EUyraEz8Qw== + dependencies: + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + buffer "5.6.0" + events "3.3.0" + stream-browserify "3.0.0" + tslib "^2.6.2" + "@aws-sdk/middleware-bucket-endpoint@3.936.0": version "3.936.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.936.0.tgz#3c2d9935a2a388fb74f8318d620e2da38d360970" @@ -647,6 +881,14 @@ "@smithy/util-utf8" "^4.2.0" tslib "^2.6.2" +"@aws-sdk/middleware-flexible-checksums@^3.974.27": + version "3.974.27" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.27.tgz#3d4999d33d973f701c1cc4d894daee16fd2ec533" + integrity sha512-bZqezPLdllFC4VAeV/f+EIc/hz56ab3TD/+4zNCgOgmG5ZHAE5dMHrX1gtTwdcQXbPr3KR7x3zTC3zuCTE6+ng== + dependencies: + "@aws-sdk/checksums" "^3.1000.2" + tslib "^2.6.2" + "@aws-sdk/middleware-flexible-checksums@^3.974.7": version "3.974.7" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.7.tgz#cc2c8efc5932e7bb55d58d717fe60c45fbf21a41" @@ -785,6 +1027,18 @@ "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" +"@aws-sdk/middleware-sdk-s3@^3.972.48": + version "3.972.48" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.48.tgz#1ece6df31ab1f6fc83181412db17fa5451191b7d" + integrity sha512-MRTqx8wD/T3REt6LTT3/yN8rrp6+xIHrbUekkDYJTYWVch70mwtdJBovR4qKJz1jIPlbN+9R/Sn6R04BfsglzA== + dependencies: + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/signature-v4-multi-region" "^3.996.32" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/middleware-ssec@3.936.0": version "3.936.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.936.0.tgz#7a56e6946a86ce4f4489459e5188091116e8ddba" @@ -918,6 +1172,22 @@ "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" +"@aws-sdk/nested-clients@^3.997.17": + version "3.997.17" + resolved "https://registry.yarnpkg.com/@aws-sdk/nested-clients/-/nested-clients-3.997.17.tgz#9b2c8f2280bd67dea777d4f31eff74083d9b326f" + integrity sha512-lDRgraoTfKRawUyc176Ow93mrNrOho/x+EoK4C+lKU+vKkHWhNhzvSMVAx0WEJUJoeQxxDN5ZdKMfiGEyNejig== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/signature-v4-multi-region" "^3.996.32" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/fetch-http-handler" "^5.4.6" + "@smithy/node-http-handler" "^4.7.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/node-http-handler@^3.374.0": version "3.374.0" resolved "https://registry.yarnpkg.com/@aws-sdk/node-http-handler/-/node-http-handler-3.374.0.tgz#8cd58b4d9814713e26034c12eabc119c113a5bc4" @@ -972,6 +1242,16 @@ "@smithy/types" "^4.14.0" tslib "^2.6.2" +"@aws-sdk/signature-v4-multi-region@^3.996.32": + version "3.996.32" + resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.32.tgz#1a4c96af7090a423c42c3658119abf2c8168e8f9" + integrity sha512-llvApLcsWtmRFhG2wT3WIp1CmDeRaIYutqty1ZZXoMzK7TiJ6MOLOimk9eXUS8PwgG4ew4pa4QAbt0lfhn++1w== + dependencies: + "@aws-sdk/types" "^3.973.11" + "@smithy/signature-v4" "^5.4.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/token-providers@3.1026.0": version "3.1026.0" resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.1026.0.tgz#af571864ad4ff3ab2a81ce38cc6d2fa58019df70" @@ -985,6 +1265,18 @@ "@smithy/types" "^4.14.0" tslib "^2.6.2" +"@aws-sdk/token-providers@3.1063.0": + version "3.1063.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.1063.0.tgz#5460afd8c787fcafcf39efcc7aa2e0a9646de6dc" + integrity sha512-nYDaWWdzjKiDP5xj8k4oUgcYd4WPgzfAOgdU5vJsaqH/07Dfvm7ffisHCFJ+NEl7kUC9JEIUxh0kznvenbo3NQ== + dependencies: + "@aws-sdk/core" "^3.974.18" + "@aws-sdk/nested-clients" "^3.997.17" + "@aws-sdk/types" "^3.973.11" + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/token-providers@3.940.0": version "3.940.0" resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.940.0.tgz#b89893d7cd0a5ed22ca180e33b6eaf7ca644c7f1" @@ -1006,6 +1298,14 @@ "@smithy/types" "^4.9.0" tslib "^2.6.2" +"@aws-sdk/types@^3.973.11": + version "3.973.11" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.973.11.tgz#40689661e7cca5bc285d44afe946160d5a7767a7" + integrity sha512-YjS0qFuECClRh4qhEyW8XagW0fwEPBeZ1cfsW/gU73Kh/ExFILxbzxOfPCmzF/2DwEvhvsHYt0b0qnvStwKYrg== + dependencies: + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@aws-sdk/types@^3.973.7": version "3.973.7" resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.973.7.tgz#0dc48b436638d9f19ca52f686912edda2d5d6dee" @@ -1118,6 +1418,15 @@ fast-xml-parser "5.5.8" tslib "^2.6.2" +"@aws-sdk/xml-builder@^3.972.28": + version "3.972.28" + resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.972.28.tgz#989480c71277d945fc5788df0acd32cc2ea98be5" + integrity sha512-lI/l3c/vPvsxmspzV63NfS3x9q4CkMmdhJy4QiM+NThAufVkDvi/PZZQ6xETnICL0UD7jI808pY83gllf86RFg== + dependencies: + "@smithy/types" "^4.14.3" + fast-xml-parser "5.7.3" + tslib "^2.6.2" + "@aws/lambda-invoke-store@^0.2.0": version "0.2.1" resolved "https://registry.yarnpkg.com/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.1.tgz#ceecff9ebe1f6199369e6911f38633fac3322811" @@ -1266,7 +1575,7 @@ jsonwebtoken "^9.0.0" uuid "^8.3.0" -"@azure/storage-blob@^12.25.0", "@azure/storage-blob@^12.28.0": +"@azure/storage-blob@^12.25.0": version "12.29.1" resolved "https://registry.yarnpkg.com/@azure/storage-blob/-/storage-blob-12.29.1.tgz#d9588b3f56f3621f92936fa3e7f268e00a34548a" integrity sha512-7ktyY0rfTM0vo7HvtK6E3UvYnI9qfd6Oz6z/+92VhGRveWng3kJwMKeUpqmW/NmwcDNbxHpSlldG+vsUnRFnBg== @@ -1286,6 +1595,26 @@ events "^3.0.0" tslib "^2.8.1" +"@azure/storage-blob@^12.31.0": + version "12.32.0" + resolved "https://registry.yarnpkg.com/@azure/storage-blob/-/storage-blob-12.32.0.tgz#2950bbfed33e5dbf990c912924ce1d4cb1d4b8eb" + integrity sha512-80LzSNnFQye2LCCBFghAJS6jJQJ7N4bfgZ6qDMgVGRtugZ7TLDKQZ2hczMigmZH3jAcMRdma/IygsC5+0gT7Tw== + dependencies: + "@azure/abort-controller" "^2.1.2" + "@azure/core-auth" "^1.9.0" + "@azure/core-client" "^1.9.3" + "@azure/core-http-compat" "^2.2.0" + "@azure/core-lro" "^2.2.0" + "@azure/core-paging" "^1.6.2" + "@azure/core-rest-pipeline" "^1.19.1" + "@azure/core-tracing" "^1.2.0" + "@azure/core-util" "^1.11.0" + "@azure/core-xml" "^1.4.5" + "@azure/logger" "^1.1.4" + "@azure/storage-common" "^12.4.0" + events "^3.0.0" + tslib "^2.8.1" + "@azure/storage-common@^12.1.1": version "12.1.1" resolved "https://registry.yarnpkg.com/@azure/storage-common/-/storage-common-12.1.1.tgz#cd0768188f7cf8ea7202d584067ad5f3eba89744" @@ -1301,6 +1630,21 @@ events "^3.3.0" tslib "^2.8.1" +"@azure/storage-common@^12.4.0": + version "12.4.0" + resolved "https://registry.yarnpkg.com/@azure/storage-common/-/storage-common-12.4.0.tgz#901cd66dc87694cbf93af48fcb915cb0198df32e" + integrity sha512-kNhJKMxQb374KOVt63CZnGIpDcrKNzJeyANLJymxE9mCJSdRGzb+Iv9oSIiCj6tNMLypr530b9ObOiA/5OvwOg== + dependencies: + "@azure/abort-controller" "^2.1.2" + "@azure/core-auth" "^1.9.0" + "@azure/core-http-compat" "^2.2.0" + "@azure/core-rest-pipeline" "^1.19.1" + "@azure/core-tracing" "^1.2.0" + "@azure/core-util" "^1.11.0" + "@azure/logger" "^1.1.4" + events "^3.3.0" + tslib "^2.8.1" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" @@ -1652,6 +1996,24 @@ "@eslint/core" "^0.17.0" levn "^0.4.1" +"@grpc/grpc-js@^1.14.3": + version "1.14.4" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.14.4.tgz#e73ff57d97802f063999545f43ebb2b1eca65d9d" + integrity sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ== + dependencies: + "@grpc/proto-loader" "^0.8.0" + "@js-sdsl/ordered-map" "^4.4.2" + +"@grpc/proto-loader@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.8.1.tgz#5a6b290ccbfb1ae2f6775afb74e9898bd8c5d4e8" + integrity sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.5.5" + yargs "^17.7.2" + "@hapi/address@^5.1.1": version "5.1.1" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-5.1.1.tgz#e9925fc1b65f5cc3fbea821f2b980e4652e84cb6" @@ -1987,6 +2349,11 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + "@js-sdsl/ordered-set@^4.4.2": version "4.4.2" resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-set/-/ordered-set-4.4.2.tgz#ab857eb63cf358b5a0f74fdd458b4601423779b7" @@ -2004,6 +2371,11 @@ resolved "https://registry.yarnpkg.com/@nodable/entities/-/entities-1.1.0.tgz#f98e5ee5a6e987b4cad56eb97be81043d9b8d31d" integrity sha512-bidpxmTBP0pOsxULw6XlxzQpTgrAGLDHGBK/JuWhPDL6ZV0GZ/PmN9CA9do6e+A9lYI6qx6ikJUtJYRxup141g== +"@nodable/entities@^2.1.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@nodable/entities/-/entities-2.1.1.tgz#ce41931e9b72606d7f0598d665e46e889285d78a" + integrity sha512-Pig3HxDIoMgjdEH8OCf/dkcTmLFjJRjWuq8jSnklu284/TKOPibSRERmOykiwmyXTtv61mP+44f3GMx0tLAyjg== + "@npmcli/agent@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-3.0.0.tgz#1685b1fbd4a1b7bb4f930cbb68ce801edfe7aa44" @@ -2022,16 +2394,361 @@ dependencies: semver "^7.3.5" +"@opentelemetry/api-logs@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.218.0.tgz#7b9818e8dfdf1d3dcab88bfe4d6724f2f831f7ec" + integrity sha512-fmEWp5kXlGEc3i/lR698Hz41DfGyN4Tbe4g7L1AxSc7fF8Xeh/FQ9Quqpa9dVA413Q1Ad43QOLzU4JoXgbFPWw== + dependencies: + "@opentelemetry/api" "^1.3.0" + +"@opentelemetry/api@^1.3.0", "@opentelemetry/api@^1.9.0": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.1.tgz#c1b0346de336ba55af2d5a7970882037baedec05" + integrity sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q== + "@opentelemetry/api@^1.4.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== +"@opentelemetry/configuration@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/configuration/-/configuration-0.218.0.tgz#a5fdd50ec9cfa0adb3bb41202cb39f79c5f4e7d9" + integrity sha512-W8wIz7H2R1pufR5jfjb3gU2XkMpm2x/7b1RJcsuzvd70Il/rWWE+g5/Od7hQKrxRTSrTrOWlru101PWXz5I1EQ== + dependencies: + "@opentelemetry/core" "2.7.1" + yaml "^2.0.0" + +"@opentelemetry/context-async-hooks@2.7.1": + version "2.7.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-2.7.1.tgz#1555a6fb269596416d8c626fd020c3f2c38e071f" + integrity sha512-OPFBYuXEn1E4ja3Y6eeA7O+ZnLBNcXTV5Cgsn1VaqBZ6hC5FnpZPLBNme1LJY8ZtF4aOujPKFoeWN4ik487KuQ== + +"@opentelemetry/core@2.7.1": + version "2.7.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-2.7.1.tgz#162bfab46d6ff4da1bef240ea52e23a926b0fdbc" + integrity sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw== + dependencies: + "@opentelemetry/semantic-conventions" "^1.29.0" + +"@opentelemetry/exporter-logs-otlp-grpc@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.218.0.tgz#7e5a7e624074d6449590c851d58efe60096314b3" + integrity sha512-hoxrNH1l/Xy6F9WTJ5IK+6j1r9nQFlPOmrnTlhYHTySdunfXLmUCPv3bQtKYntxag9h3wLYBZQ2HI6FOx+BT2g== + dependencies: + "@grpc/grpc-js" "^1.14.3" + "@opentelemetry/core" "2.7.1" + "@opentelemetry/otlp-exporter-base" "0.218.0" + "@opentelemetry/otlp-grpc-exporter-base" "0.218.0" + "@opentelemetry/otlp-transformer" "0.218.0" + "@opentelemetry/sdk-logs" "0.218.0" + +"@opentelemetry/exporter-logs-otlp-http@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.218.0.tgz#0996cb45e0ebc6c7465445430a018edcac9871b4" + integrity sha512-Qx+4rpVHzgg89dawcWRHyt+XRXeLnhFz/qBtvggmjkcgPUdr+NAB0/u/eIPA8yAeJV0J80Vz43JZCh/XFvZFGw== + dependencies: + "@opentelemetry/api-logs" "0.218.0" + "@opentelemetry/core" "2.7.1" + "@opentelemetry/otlp-exporter-base" "0.218.0" + "@opentelemetry/otlp-transformer" "0.218.0" + "@opentelemetry/sdk-logs" "0.218.0" + +"@opentelemetry/exporter-logs-otlp-proto@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.218.0.tgz#e539720b2e145e85a7a4901a1eabb0b2e77990f8" + integrity sha512-1/noQNsp9gXD75HPzgjBrcF1+XTtry7pFAUfxVEJgg7mPv2AawKQuYkhMmJ8qjxz4Ubc3Y8bwvfxevXsKTq4cg== + dependencies: + "@opentelemetry/api-logs" "0.218.0" + "@opentelemetry/core" "2.7.1" + "@opentelemetry/otlp-exporter-base" "0.218.0" + "@opentelemetry/otlp-transformer" "0.218.0" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/sdk-logs" "0.218.0" + "@opentelemetry/sdk-trace-base" "2.7.1" + +"@opentelemetry/exporter-metrics-otlp-grpc@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.218.0.tgz#6d66c2638702489d063b8857741eee9cea1d21d6" + integrity sha512-YapQ9vNMX0NSZF6LK5pWAFfjpJleV2O9uYWfYGeb/5F1Kb9rPGK8tZDMJFa/sOksgdFuflDvYuA0B4qjDB4fjQ== + dependencies: + "@grpc/grpc-js" "^1.14.3" + "@opentelemetry/core" "2.7.1" + "@opentelemetry/exporter-metrics-otlp-http" "0.218.0" + "@opentelemetry/otlp-exporter-base" "0.218.0" + "@opentelemetry/otlp-grpc-exporter-base" "0.218.0" + "@opentelemetry/otlp-transformer" "0.218.0" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/sdk-metrics" "2.7.1" + +"@opentelemetry/exporter-metrics-otlp-http@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.218.0.tgz#c205581585d04c5106d1ca766e23632006e46a2c" + integrity sha512-bV7d2OuMpZu2+gAaxUAhzfZ0h3WVZk8ETQUEE3DNSntbTaMpuITjtm8I0rNyHFdm7Ax57K6ty7SgFXlBmOLIvQ== + dependencies: + "@opentelemetry/core" "2.7.1" + "@opentelemetry/otlp-exporter-base" "0.218.0" + "@opentelemetry/otlp-transformer" "0.218.0" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/sdk-metrics" "2.7.1" + +"@opentelemetry/exporter-metrics-otlp-proto@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-proto/-/exporter-metrics-otlp-proto-0.218.0.tgz#66642b8bb5e654ca7a5944a4f0b490814fc875fd" + integrity sha512-ubLddKjWULhla9YZRCj/rTBeppjJYE4e9w0icx5mTu3eFhWjQzbV75NYjXuIlEG+NJsBl6d+sTFw5Qu+oej4oQ== + dependencies: + "@opentelemetry/core" "2.7.1" + "@opentelemetry/exporter-metrics-otlp-http" "0.218.0" + "@opentelemetry/otlp-exporter-base" "0.218.0" + "@opentelemetry/otlp-transformer" "0.218.0" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/sdk-metrics" "2.7.1" + +"@opentelemetry/exporter-prometheus@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.218.0.tgz#41bddc97d34cd9d9993382b9c10fed19a8de63f4" + integrity sha512-RT5oEyu1kddZJ1vt7/BUo5wV+P7hpNAESsR3dUd3+8deHuX7gWNoCOZn+SfDT+hJHlIJ5h/AxiCLXIrutswDJg== + dependencies: + "@opentelemetry/core" "2.7.1" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/sdk-metrics" "2.7.1" + "@opentelemetry/semantic-conventions" "^1.29.0" + +"@opentelemetry/exporter-trace-otlp-grpc@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.218.0.tgz#5d5532ab94d5514bec8aedc19ce3170b6381eed1" + integrity sha512-3fXxVQEj9TNAFaCi79JeFKfeLd0sDtInaR3gaZDVlzNSPHtz8PZuCV34JKWjD4XXzT20IdMe8IpX6mRVNDA4Tw== + dependencies: + "@grpc/grpc-js" "^1.14.3" + "@opentelemetry/core" "2.7.1" + "@opentelemetry/otlp-exporter-base" "0.218.0" + "@opentelemetry/otlp-grpc-exporter-base" "0.218.0" + "@opentelemetry/otlp-transformer" "0.218.0" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/sdk-trace-base" "2.7.1" + +"@opentelemetry/exporter-trace-otlp-http@0.218.0", "@opentelemetry/exporter-trace-otlp-http@^0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.218.0.tgz#36d6abf6d639b9ea861603c61f434751c0b1a0ea" + integrity sha512-8dqezsmPhtKitIK/eTipZhYl9EX2/gNQ5zUMhaz3uxEURwfkNf8IPvo6yNfrzbxdtpAOybS/+h7wmIWYqFSpiw== + dependencies: + "@opentelemetry/core" "2.7.1" + "@opentelemetry/otlp-exporter-base" "0.218.0" + "@opentelemetry/otlp-transformer" "0.218.0" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/sdk-trace-base" "2.7.1" + +"@opentelemetry/exporter-trace-otlp-proto@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.218.0.tgz#de0b2b3545149dafedd2b948fb891f9bf962940c" + integrity sha512-r1Msf8SNLRmwh9J6XQ5uh82D7CdDWMNHnPB7LAVHjzut0TkSeKc5KcIvr4SvHvfk/xwN5gxC+VLKQ1k0o8PSPw== + dependencies: + "@opentelemetry/core" "2.7.1" + "@opentelemetry/otlp-exporter-base" "0.218.0" + "@opentelemetry/otlp-transformer" "0.218.0" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/sdk-trace-base" "2.7.1" + +"@opentelemetry/exporter-zipkin@2.7.1": + version "2.7.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-zipkin/-/exporter-zipkin-2.7.1.tgz#3b79d223adc8c097ba3323e4de4ed8abb83c789e" + integrity sha512-mfsD9bKAxcKrh5+y08TPodvClBO0CznBE3p79YAGnO81WI4LrdsGA65T53e4iTSbCalW4WaUpkbeJcbpyIUHfg== + dependencies: + "@opentelemetry/core" "2.7.1" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/sdk-trace-base" "2.7.1" + "@opentelemetry/semantic-conventions" "^1.29.0" + +"@opentelemetry/instrumentation@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.218.0.tgz#fcceb4ffb45f99c0d292600769150fc5944dc3e9" + integrity sha512-mIZil8Es+sYDK5m+DQiwAwF57F14TF2YlEqvIjZ/RQWcxDBwRGsKfdK2Tv65OU9meQKCMzSIFS9mxAcnAb6Bkg== + dependencies: + "@opentelemetry/api-logs" "0.218.0" + import-in-the-middle "^3.0.0" + require-in-the-middle "^8.0.0" + +"@opentelemetry/otlp-exporter-base@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.218.0.tgz#f33e3217ce568756baa132fabe30f0c9345db086" + integrity sha512-ZwqpkNL5W7RyGJPDZ9g06DvKp8KFTWPJPN12anpMQYSKpTSU0z3EIZuPq9vPGpS8siFyOqDYDAuCwlNO9FqgbA== + dependencies: + "@opentelemetry/core" "2.7.1" + "@opentelemetry/otlp-transformer" "0.218.0" + +"@opentelemetry/otlp-grpc-exporter-base@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.218.0.tgz#dc5a1fec716245d84dc4167de9b1c607e07fb6a7" + integrity sha512-H/lCGJ536N98VpYJOaWTQOkv4Dx6TnmStK6Rqfu1W7KkFbPAx04hjdYEMZF/YbnHzPUSIK4kM6OE2GKGBTpV9A== + dependencies: + "@grpc/grpc-js" "^1.14.3" + "@opentelemetry/core" "2.7.1" + "@opentelemetry/otlp-exporter-base" "0.218.0" + "@opentelemetry/otlp-transformer" "0.218.0" + +"@opentelemetry/otlp-transformer@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.218.0.tgz#6784d0ddd13803c63a1b24072606c02fc21b9071" + integrity sha512-CFaKH87WAzjuJ4awowTTLzUvMfaRfiOFG5+qm5S5ncyalRtN4ecQ+YmuANJSCrVPuvZFEkUgKhBPBndxi3rHsQ== + dependencies: + "@opentelemetry/api-logs" "0.218.0" + "@opentelemetry/core" "2.7.1" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/sdk-logs" "0.218.0" + "@opentelemetry/sdk-metrics" "2.7.1" + "@opentelemetry/sdk-trace-base" "2.7.1" + +"@opentelemetry/propagator-b3@2.7.1": + version "2.7.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-b3/-/propagator-b3-2.7.1.tgz#107fe3e16d0728c489edbad221c402ee197514a4" + integrity sha512-RJid6E2CKyeGfKBzXKF21ejabGMHypFkPAh3qZ+NvI+SGjuIye79t3PmiqcDgtRzdKH6ynXzbfslQ8DfpRUg2A== + dependencies: + "@opentelemetry/core" "2.7.1" + +"@opentelemetry/propagator-jaeger@2.7.1": + version "2.7.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.7.1.tgz#e8ebf3f6c0e9aa525cf041893425889cf3e69125" + integrity sha512-KMjVBHzP4N60bOzxja76M1F1hZZ43lGPga5ix+mkv9+kk1nx9SbkxSvJsMbuVUxdPQmsPTqGShmhN8ulrMOg6Q== + dependencies: + "@opentelemetry/core" "2.7.1" + +"@opentelemetry/resources@2.7.1", "@opentelemetry/resources@^2.7.1": + version "2.7.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-2.7.1.tgz#3b2a9179f6119bb1f2cddefe41ba9b2855504a5d" + integrity sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ== + dependencies: + "@opentelemetry/core" "2.7.1" + "@opentelemetry/semantic-conventions" "^1.29.0" + +"@opentelemetry/sdk-logs@0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.218.0.tgz#78886fe300b82802cee9963208b2af326b928af5" + integrity sha512-QvnNdugatFTVCJXH0Mcu7GOOJSylA9j127kIezOE4YwTI4YbowRons2K4WZTv5FMS8T4q9P0NdaRHdkSmeAIag== + dependencies: + "@opentelemetry/api-logs" "0.218.0" + "@opentelemetry/core" "2.7.1" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/semantic-conventions" "^1.29.0" + +"@opentelemetry/sdk-metrics@2.7.1": + version "2.7.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-2.7.1.tgz#b713f69dd67933ecc9c61357f1d452cdc9f4e281" + integrity sha512-MpDJdkiFDs3Pm1RHO3KByuZbuBdJEXEAkiC0+yJdsZGVCdf1RpHR6n+LHDcS7ffmfrt5kVCzJSCfm4z2C7v0uQ== + dependencies: + "@opentelemetry/core" "2.7.1" + "@opentelemetry/resources" "2.7.1" + +"@opentelemetry/sdk-node@^0.218.0": + version "0.218.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-node/-/sdk-node-0.218.0.tgz#cf8bdc0c993387189c7c474612e0f801505feb97" + integrity sha512-tPMjHrLV5gsfNdYqoRHjeGbCAZBXXD9c1Qo/2ut7VwnUABDNh76xNxrT0SEhkIIJuCN45bbN1vZnYL1gY0IkOg== + dependencies: + "@opentelemetry/api-logs" "0.218.0" + "@opentelemetry/configuration" "0.218.0" + "@opentelemetry/context-async-hooks" "2.7.1" + "@opentelemetry/core" "2.7.1" + "@opentelemetry/exporter-logs-otlp-grpc" "0.218.0" + "@opentelemetry/exporter-logs-otlp-http" "0.218.0" + "@opentelemetry/exporter-logs-otlp-proto" "0.218.0" + "@opentelemetry/exporter-metrics-otlp-grpc" "0.218.0" + "@opentelemetry/exporter-metrics-otlp-http" "0.218.0" + "@opentelemetry/exporter-metrics-otlp-proto" "0.218.0" + "@opentelemetry/exporter-prometheus" "0.218.0" + "@opentelemetry/exporter-trace-otlp-grpc" "0.218.0" + "@opentelemetry/exporter-trace-otlp-http" "0.218.0" + "@opentelemetry/exporter-trace-otlp-proto" "0.218.0" + "@opentelemetry/exporter-zipkin" "2.7.1" + "@opentelemetry/instrumentation" "0.218.0" + "@opentelemetry/otlp-exporter-base" "0.218.0" + "@opentelemetry/propagator-b3" "2.7.1" + "@opentelemetry/propagator-jaeger" "2.7.1" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/sdk-logs" "0.218.0" + "@opentelemetry/sdk-metrics" "2.7.1" + "@opentelemetry/sdk-trace-base" "2.7.1" + "@opentelemetry/sdk-trace-node" "2.7.1" + "@opentelemetry/semantic-conventions" "^1.29.0" + +"@opentelemetry/sdk-trace-base@2.7.1", "@opentelemetry/sdk-trace-base@^2.7.1": + version "2.7.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.7.1.tgz#9160c3af9ef2219c26563abd136e22fb7d19b34f" + integrity sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw== + dependencies: + "@opentelemetry/core" "2.7.1" + "@opentelemetry/resources" "2.7.1" + "@opentelemetry/semantic-conventions" "^1.29.0" + +"@opentelemetry/sdk-trace-node@2.7.1": + version "2.7.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.7.1.tgz#54dedb8e77fa51a6d02fc2192097739266c82168" + integrity sha512-pCpQxU68lV+I9s9svqMyVu5iHdDDUnqUpSxqwyCU8A9ejEsSnMPCbearwsUO4yk08ZJzAIUCFuReMdVQvHrdvg== + dependencies: + "@opentelemetry/context-async-hooks" "2.7.1" + "@opentelemetry/core" "2.7.1" + "@opentelemetry/sdk-trace-base" "2.7.1" + +"@opentelemetry/semantic-conventions@^1.29.0": + version "1.41.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz#b04e7151c5913a7a006d4f465479da75efb98a7a" + integrity sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA== + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.5.tgz#d9315ad7cf3f30aac70bda3c068443dc6f143659" + integrity sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g== + +"@protobufjs/eventemitter@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz#d512cb26c0ae026091ee2c1167f1be6faf5c842a" + integrity sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg== + +"@protobufjs/fetch@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.1.tgz#4d6fc00c8fb64016a5c81b469d549046350f1065" + integrity sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.2.tgz#ae64fbc014ff44c8bfad03dd4c93cd2d6a4c82db" + integrity sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.1.tgz#eaee5900122c110a3dbcb728c0597014a2621774" + integrity sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg== + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" @@ -2061,6 +2778,14 @@ httpagent "github:scality/httpagent#1.1.0" werelogs "github:scality/werelogs#8.2.2" +"@scality/hdclient@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@scality/hdclient/-/hdclient-1.3.2.tgz#544d08a5b88869a9c30107c05d774e13595966fb" + integrity sha512-voy67AlH1irNmaXno0KP/KpiEBYzzdW8EoGjBXsVztLFjGe+RQnNtAyzCn05secZZy43jBYLOrZ7032gorxvrg== + dependencies: + httpagent "github:scality/httpagent#1.1.0" + werelogs "github:scality/werelogs#8.2.2" + "@senx/warp10@^2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@senx/warp10/-/warp10-2.0.3.tgz#dcce3890d491c6380f2967abcf126909ed208969" @@ -2233,6 +2958,15 @@ "@smithy/uuid" "^1.1.2" tslib "^2.6.2" +"@smithy/core@^3.24.6": + version "3.24.6" + resolved "https://registry.yarnpkg.com/@smithy/core/-/core-3.24.6.tgz#72891bad85d577b2e43f30a8fc67adf36d577798" + integrity sha512-wBXDRup6UU97VKyaiRo8AssnfStPtG0oAAfpq/bC0a1YYau8pM86YB4kM6ccoVi1mS8l/UHbn9oDM+7uozr/ug== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@smithy/credential-provider-imds@^4.2.13": version "4.2.13" resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.13.tgz#c0533f362dec6644f403c7789d8e81233f78c63f" @@ -2255,6 +2989,15 @@ "@smithy/url-parser" "^4.2.5" tslib "^2.6.2" +"@smithy/credential-provider-imds@^4.3.7": + version "4.3.8" + resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-4.3.8.tgz#d22f0ed81bac46017fa2f8f848ad89ab506892bb" + integrity sha512-5cAM+KZC02sTqDt6NaLXyu50M/GNMd1eTzDVR8Lb0BBsVtu7RWHo47VPPEEv1vt3Yub6uzr+M5FHC+GtoT0USg== + dependencies: + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@smithy/eventstream-codec@^4.2.13": version "4.2.13" resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-4.2.13.tgz#7fcdf18bc1acaec395b5d387d65136973bd3e1cc" @@ -2367,6 +3110,15 @@ "@smithy/util-base64" "^4.3.0" tslib "^2.6.2" +"@smithy/fetch-http-handler@^5.4.6": + version "5.4.6" + resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-5.4.6.tgz#745cdf8b6c333632672f8f48360bde04b8955b47" + integrity sha512-FEwEYJ1jlBKdhe9TPzfghEi1bP55ZeEImlDkEa62bBBYzUcnB6RUCyuiS2mqKt6ZVjUbBgcNhzfIctH+Hevx9g== + dependencies: + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@smithy/hash-blob-browser@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.14.tgz#c32a6a5b70fa94e324f2ca04296e2355ddfe4c9b" @@ -2647,6 +3399,15 @@ "@smithy/types" "^1.2.0" tslib "^2.5.0" +"@smithy/node-http-handler@^4.3.0", "@smithy/node-http-handler@^4.7.6": + version "4.7.7" + resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-4.7.7.tgz#cd0669141c5ee10c8b0516b652326ca4c28d643a" + integrity sha512-ZAFvHXrEk6K180EVhmZVg8GU5pUH5BSFqRs27JW3j1qEFx9YyYwWFx17x/MHcjALYimGAji7qEOlF1++be+G5A== + dependencies: + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@smithy/node-http-handler@^4.4.5": version "4.4.5" resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-4.4.5.tgz#2aea598fdf3dc4e32667d673d48abd4a073665f4" @@ -2831,6 +3592,15 @@ "@smithy/util-utf8" "^4.2.0" tslib "^2.6.2" +"@smithy/signature-v4@^5.4.6": + version "5.4.6" + resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-5.4.6.tgz#5d2b98aa10e629b6aef36f2289226df81ba4c98e" + integrity sha512-Ojg4B6oIDlIr1R86xCDJt1zJWnYa0VINmqdjfe9qxWjdRivHalZ3iSlQgVqYbW0MdpFOC5XfHEWsnbmdnpIILQ== + dependencies: + "@smithy/core" "^3.24.6" + "@smithy/types" "^4.14.3" + tslib "^2.6.2" + "@smithy/smithy-client@^4.12.9": version "4.12.9" resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-4.12.9.tgz#2eb54ee07050a8bcd3792f8b8c4e03fac4bfb422" @@ -2878,6 +3648,13 @@ dependencies: tslib "^2.6.2" +"@smithy/types@^4.14.3": + version "4.14.3" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.14.3.tgz#784e6d556231645744edf3fea85daaac9054eb40" + integrity sha512-YupL0ZWmFtJexUN2cHzkvvF/b9pKrtAIfT1o7/oY/Ppu8IYeZ+lDPM5vZdQJaSeA132dJCqojjGC9NhXeF71VQ== + dependencies: + tslib "^2.6.2" + "@smithy/types@^4.9.0": version "4.9.0" resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.9.0.tgz#c6636ddfa142e1ddcb6e4cf5f3e1a628d420486f" @@ -3360,6 +4137,13 @@ dependencies: undici-types "~7.16.0" +"@types/node@>=13.7.0": + version "25.9.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-25.9.2.tgz#fc8958e757994b71fee516f9634bdb03d1b19e9f" + integrity sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw== + dependencies: + undici-types ">=7.24.0 <7.24.7" + "@types/stack-utils@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" @@ -3541,6 +4325,11 @@ accepts@~1.3.4: mime-types "~2.1.34" negotiator "0.6.3" +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -3749,19 +4538,25 @@ arraybuffer.prototype.slice@^1.0.4: optionalDependencies: ioctl "^2.0.2" -"arsenal@git+https://github.com/scality/arsenal#8.2.36": - version "8.2.36" - resolved "git+https://github.com/scality/arsenal#cd72c49fdfe47440680142ece0b268e35c3e1691" +"arsenal@git+https://github.com/scality/Arsenal#improvement/ARSN-571/crr-multi": + version "8.4.5" + resolved "git+https://github.com/scality/Arsenal#c3f3bffde6eeb935e03847df010ac37ac7ba8944" dependencies: + "@aws-sdk/client-kms" "^3.975.0" + "@aws-sdk/client-s3" "^3.975.0" + "@aws-sdk/credential-providers" "^3.975.0" + "@aws-sdk/lib-storage" "^3.975.0" "@azure/identity" "^4.13.0" - "@azure/storage-blob" "^12.28.0" + "@azure/storage-blob" "^12.31.0" "@js-sdsl/ordered-set" "^4.4.2" - "@scality/hdclient" "^1.3.1" + "@opentelemetry/api" "^1.9.0" + "@scality/hdclient" "^1.3.2" + "@smithy/node-http-handler" "^4.3.0" + "@smithy/protocol-http" "^5.3.5" JSONStream "^1.3.5" agentkeepalive "^4.6.0" ajv "6.12.3" async "~2.6.4" - aws-sdk "^2.1691.0" backo "^1.1.0" base-x "3.0.8" base62 "^2.0.2" @@ -3786,6 +4581,10 @@ arraybuffer.prototype.slice@^1.0.4: werelogs scality/werelogs#8.2.2 xml2js "^0.6.2" optionalDependencies: + "@opentelemetry/exporter-trace-otlp-http" "^0.218.0" + "@opentelemetry/resources" "^2.7.1" + "@opentelemetry/sdk-node" "^0.218.0" + "@opentelemetry/sdk-trace-base" "^2.7.1" ioctl "^2.0.2" assert-plus@1.0.0, assert-plus@^1.0.0: @@ -4089,6 +4888,14 @@ buffer@4.9.2: ieee754 "^1.1.4" isarray "^1.0.0" +buffer@5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" + integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + buffer@^5.5.0, buffer@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" @@ -4224,6 +5031,11 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== +cjs-module-lexer@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz#b3ca5101843389259ade7d88c77bd06ce55849ca" + integrity sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ== + classic-level@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-2.0.0.tgz#6fd9ca686bbcd645e35caaf403c3f3a56495d11b" @@ -4923,7 +5735,7 @@ events@1.1.1: resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" integrity sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw== -events@^3.0.0, events@^3.3.0: +events@3.3.0, events@^3.0.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -5039,6 +5851,14 @@ fast-xml-builder@^1.1.4: dependencies: path-expression-matcher "^1.1.3" +fast-xml-builder@^1.1.7: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz#abd2363145a7625d9789ad96da375fabe3cff28c" + integrity sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q== + dependencies: + path-expression-matcher "^1.5.0" + xml-naming "^0.1.0" + fast-xml-parser@5.2.5: version "5.2.5" resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz#4809fdfb1310494e341098c25cb1341a01a9144a" @@ -5055,6 +5875,16 @@ fast-xml-parser@5.5.8: path-expression-matcher "^1.2.0" strnum "^2.2.0" +fast-xml-parser@5.7.3: + version "5.7.3" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz#309b04b08d835defc62ab657a0bb340c0e0fbe6a" + integrity sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg== + dependencies: + "@nodable/entities" "^2.1.0" + fast-xml-builder "^1.1.7" + path-expression-matcher "^1.5.0" + strnum "^2.2.3" + fast-xml-parser@^5.0.7: version "5.3.2" resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-5.3.2.tgz#78a51945fbf7312e1ff6726cb173f515b4ea11d8" @@ -5502,6 +6332,16 @@ import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" +import-in-the-middle@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-3.0.1.tgz#8a0a1230c9b865c0e12698171646ae1e3fff691d" + integrity sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA== + dependencies: + acorn "^8.15.0" + acorn-import-attributes "^1.9.5" + cjs-module-lexer "^2.2.0" + module-details-from-path "^1.0.4" + import-local@^3.0.2: version "3.2.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" @@ -6610,6 +7450,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" @@ -6685,6 +7530,11 @@ long-timeout@0.1.1: resolved "https://registry.yarnpkg.com/long-timeout/-/long-timeout-0.1.1.tgz#9721d788b47e0bcb5a24c2e2bee1a0da55dab514" integrity sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w== +long@^5.0.0, long@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== + looper@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/looper/-/looper-2.0.0.tgz#66cd0c774af3d4fedac53794f742db56da8f09ec" @@ -6938,6 +7788,11 @@ minizlib@^3.0.1, minizlib@^3.1.0: dependencies: minipass "^7.1.2" +module-details-from-path@^1.0.3, module-details-from-path@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.4.tgz#b662fdcd93f6c83d3f25289da0ce81c8d9685b94" + integrity sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w== + module-error@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" @@ -7425,6 +8280,24 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" +protobufjs@^7.5.5: + version "7.6.2" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.6.2.tgz#2659f77bd8d54778814c274dc0df808f54c88918" + integrity sha512-N9EiLovGEQOJSPF26Ij7qUGvahfEnq0eeYZ02aigIedkmz1qZSwjnP9SBITHJuF/6MYbIW4HDN8zdYjsjqJKXQ== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.5" + "@protobufjs/eventemitter" "^1.1.1" + "@protobufjs/fetch" "^1.1.1" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.2" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.1" + "@types/node" ">=13.7.0" + long "^5.3.2" + proxy-addr@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -7547,7 +8420,7 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== -readable-stream@^3.4.0: +readable-stream@^3.4.0, readable-stream@^3.5.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -7609,6 +8482,14 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-in-the-middle@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz#dbde2587f669398626d56b20c868ab87bf01cce4" + integrity sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ== + dependencies: + debug "^4.3.5" + module-details-from-path "^1.0.3" + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -8017,6 +8898,14 @@ stop-iteration-iterator@^1.1.0: es-errors "^1.3.0" internal-slot "^1.1.0" +stream-browserify@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + stream-to-pull-stream@^1.7.1: version "1.7.3" resolved "https://registry.yarnpkg.com/stream-to-pull-stream/-/stream-to-pull-stream-1.7.3.tgz#4161aa2d2eb9964de60bfa1af7feaf917e874ece" @@ -8394,6 +9283,11 @@ unbox-primitive@^1.1.0: has-symbols "^1.1.0" which-boxed-primitive "^1.1.1" +"undici-types@>=7.24.0 <7.24.7": + version "7.24.6" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.24.6.tgz#61275b485d7fd4e9d269c7cf04ec2873c9cc0f91" + integrity sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg== + undici-types@~7.16.0: version "7.16.0" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46" @@ -8682,6 +9576,11 @@ wsl-utils@^0.1.0: dependencies: is-wsl "^3.1.0" +xml-naming@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/xml-naming/-/xml-naming-0.1.0.tgz#8ab7106c5b8d23caa2fabac1cadf17136379fbd8" + integrity sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw== + xml2js@0.6.2, xml2js@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" @@ -8730,12 +9629,17 @@ yallist@^5.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== +yaml@^2.0.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.9.0.tgz#78274afd93598a1dfdd6130df6a566defcbf9aa4" + integrity sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA== + yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^17.3.1: +yargs@^17.3.1, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== From 82575ce3733b93cce2cb82fea1c162b2df7c1fe5 Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Mon, 8 Jun 2026 19:06:59 +0200 Subject: [PATCH 04/15] =?UTF-8?q?=F0=9F=90=9B=20fix=20functional=20test=20?= =?UTF-8?q?using=20removed=20arsenal=20setter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- tests/functional/stalled.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/functional/stalled.js b/tests/functional/stalled.js index a9d1b845..1685d0e4 100644 --- a/tests/functional/stalled.js +++ b/tests/functional/stalled.js @@ -70,13 +70,12 @@ function createStalledObject(objName, lastModified) { backends: [], content: [], destination: '', - storageClass: '', + storageClass: 'location-1,location-2', role: '', storageType: '', dataStoreVersionId: '', isNFS: null, }) - .setReplicationStorageClass('location-1,location-2') .getValue(); } From 8202a73cba5bf2c8418bac483ef614ffef0b7717 Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Mon, 15 Jun 2026 11:16:21 +0200 Subject: [PATCH 05/15] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20chain=20method=20to?= =?UTF-8?q?=20follow=20same=20pattern?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- tests/utils/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/utils/index.js b/tests/utils/index.js index b3f16c23..ff9dcb7b 100644 --- a/tests/utils/index.js +++ b/tests/utils/index.js @@ -21,8 +21,8 @@ function generateMD(isMaster, objectKey, lastModified, storageClasses) { const objMD = new ObjectMD() .setKey(objectKey) .setLastModified(lastModified) - .setVersionId(testVersion); - objMD.setReplicationInfo({ storageClass: storageClasses }); + .setVersionId(testVersion) + .setReplicationInfo({ storageClass: storageClasses }); return { _id: { id: keyId, From c03ea05b9ccc20df847f1587cfcb69bc28390069 Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Mon, 15 Jun 2026 15:18:07 +0200 Subject: [PATCH 06/15] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20extract=20=5FbuildAr?= =?UTF-8?q?senalConfig=20and=20fix=20V1=20backend=20shape=20on=20merge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- CRR/ReplicationStatusUpdater.js | 65 ++++++++----- tests/unit/CRR/ReplicationStatusUpdater.js | 103 +++++++++++++++++++++ 2 files changed, 147 insertions(+), 21 deletions(-) diff --git a/CRR/ReplicationStatusUpdater.js b/CRR/ReplicationStatusUpdater.js index 17bb63e3..4830a4e5 100644 --- a/CRR/ReplicationStatusUpdater.js +++ b/CRR/ReplicationStatusUpdater.js @@ -356,9 +356,32 @@ class ReplicationStatusUpdater { }); } + /** + * Adapts matched AWS SDK rules to arsenal's ReplicationConfigurationMetadata shape. + * @private + * @param {Array} matchingRules - Rules already matched to this key. + * @param {Object} repConfig - The full replication configuration. + * @returns {Object} + */ + _buildArsenalConfig(matchingRules, repConfig) { + return { + role: repConfig.Role, + destination: matchingRules[0]?.Destination.Bucket ?? '', + rules: matchingRules.map(r => ({ + enabled: r.Status === 'Enabled', + prefix: r.Filter?.Prefix ?? r.Prefix ?? '', + storageClass: r.Destination.StorageClass, + destination: r.Destination.Bucket, + account: r.Destination.Account, + priority: r.Priority, + id: r.ID ?? '', + })), + }; + } + /** * Marks an object as pending for replication using the V2 multi-destination format. - * Writes per-backend destination and role; strips legacy top-level storageClass/storageType/destination. + * Writes per-backend destination and role; strips V1-only top-level storageClass/storageType/destination. * @private * @param {string} bucket - The bucket name. * @param {string} key - The object key. @@ -390,25 +413,11 @@ class ReplicationStatusUpdater { return next(new Error('model version regression: refusing to overwrite newer metadata')); } - // Adapt AWS SDK rules to arsenal's ReplicationConfigurationMetadata shape - const arsenalConfig = { - role: repConfig.Role, - destination: matchingRules[0]?.Destination.Bucket ?? '', - rules: matchingRules.map(r => ({ - enabled: r.Status === 'Enabled', - prefix: r.Filter?.Prefix ?? r.Prefix ?? '', - storageClass: r.Destination.StorageClass, - destination: r.Destination.Bucket, - account: r.Destination.Account, - priority: r.Priority, - id: r.ID ?? '', - })), - }; + const arsenalConfig = this._buildArsenalConfig(matchingRules, repConfig); // Capture existing backends before any initialization (to carry forward dataStoreVersionId) const existingBackends = objMD.getReplicationInfo()?.backends; - // resolveBackends handles prefix matching, priority dedup, and per-backend destination/role const candidateBackends = ReplicationConfiguration.resolveBackends( arsenalConfig, key, () => false, existingBackends, ); @@ -428,12 +437,26 @@ class ReplicationStatusUpdater { this._removeV1Fields(replicationInfo); objMD.setReplicationInfo(replicationInfo); - // Merge: preserve existing backends for non-updated sites const updatedSites = new Set(backendsToUpdate.map(b => b.site)); - const finalBackends = [ - ...(existingBackends ?? []).filter(b => !updatedSites.has(b.site)), - ...backendsToUpdate, - ]; + // Use candidateBackends (always V2-shaped) for skipped sites, but restore + // original status and dataStoreVersionId: resolveBackends forces PENDING on every + // entry, and can't match V1-format existing backends (missing destination/role), + // so it resets dataStoreVersionId to ''. + const skippedBackends = candidateBackends + .filter(b => !updatedSites.has(b.site)) + .map(b => { + const orig = (existingBackends ?? []).find(e => e.site === b.site); + if (!orig) { + return b; + } + + return { + ...b, + status: orig.status, + dataStoreVersionId: orig.dataStoreVersionId ?? b.dataStoreVersionId, + }; + }); + const finalBackends = [...skippedBackends, ...backendsToUpdate]; objMD.setReplicationBackends(finalBackends); objMD.setReplicationStatus(this._computeTopLevelStatus(finalBackends)); diff --git a/tests/unit/CRR/ReplicationStatusUpdater.js b/tests/unit/CRR/ReplicationStatusUpdater.js index 83be4d3a..7f12a9e7 100644 --- a/tests/unit/CRR/ReplicationStatusUpdater.js +++ b/tests/unit/CRR/ReplicationStatusUpdater.js @@ -947,6 +947,43 @@ describe('ReplicationStatusUpdater _removeV1Fields', () => { }); }); +describe('ReplicationStatusUpdater._buildArsenalConfig', () => { + it('should map AWS SDK rules to arsenal ReplicationConfigurationMetadata shape', () => { + const crr = initializeCrrWithMocks({ buckets: [], workers: 1, replicationStatusToProcess: ['NEW'] }, logger); + const matchingRules = [ + { + ID: 'rule1', + Status: 'Enabled', + Filter: { Prefix: '' }, + Priority: 1, + Destination: { Bucket: 'arn:aws:s3:::bucket-a', StorageClass: 'dest-A', Account: '111111111111' }, + }, + { + ID: 'rule2', + Status: 'Enabled', + Filter: { Prefix: 'docs/' }, + Priority: 2, + Destination: { Bucket: 'arn:aws:s3:::bucket-b', StorageClass: 'dest-B', Account: '222222222222' }, + }, + ]; + const repConfig = { Role: 'arn:aws:iam::root:role/src,arn:aws:iam::root:role/dst' }; + + const result = crr._buildArsenalConfig(matchingRules, repConfig); + + expect(result.role).toBe(repConfig.Role); + expect(result.destination).toBe('arn:aws:s3:::bucket-a'); + expect(result.rules).toHaveLength(2); + expect(result.rules[0]).toMatchObject({ + enabled: true, prefix: '', storageClass: 'dest-A', + destination: 'arn:aws:s3:::bucket-a', account: '111111111111', priority: 1, id: 'rule1', + }); + expect(result.rules[1]).toMatchObject({ + enabled: true, prefix: 'docs/', storageClass: 'dest-B', + destination: 'arn:aws:s3:::bucket-b', account: '222222222222', priority: 2, id: 'rule2', + }); + }); +}); + describe('ReplicationStatusUpdater V2 format', () => { // V2 config: rule1 (prefix='', dest-A) and rule2 (prefix='docs/', dest-B) // Object key 'key0' matches only rule1 (dest-A) @@ -1234,6 +1271,72 @@ describe('ReplicationStatusUpdater V2 format', () => { }); }); + it('should upgrade V1-format skipped backends to V2 shape when processing mixed status', done => { + // dest-A is COMPLETED in V1 format (no per-backend destination/role) — skipped by NEW filter + // dest-B is NEW and matches 'docs/' prefix — should be set to PENDING + // After processing, dest-A must have V2-shaped destination/role and its COMPLETED status preserved + const listVersionDocsKey = { + IsTruncated: false, + Versions: [{ + ETag: '"abc"', ChecksumAlgorithm: [], Size: 100, + StorageClass: 'STANDARD', Key: 'docs/report.pdf', + VersionId: 'aJdO148N3LjN00000000001I4j3QKItW', IsLatest: true, + LastModified: '2024-01-05T13:11:31.861Z', + Owner: { DisplayName: 'bart', ID: '0' }, + }], + DeleteMarkers: [], Name: 'bucket0', MaxKeys: 1000, CommonPrefixes: [], + }; + + const crr = initializeCrrWithMocks({ + buckets: ['bucket0'], + workers: 10, + replicationStatusToProcess: ['NEW'], + }, logger, { + ListObjectVersionsCommand: listVersionDocsKey, + GetBucketReplicationCommand: getBucketReplicationV2Res, + }); + + // V1-format existing backend for dest-A: no destination/role per backend + crr.cloudserverclient.getMetadata = jest.fn((p, cb) => { + const md = JSON.parse(getMetadataRes.Body); + md.replicationInfo = { + status: 'PROCESSING', + role: 'arn:aws:iam::8765432:role/sourceRole', + storageClass: 'dest-A', + destination: 'arn:aws:s3:::bucket-a', + backends: [{ + site: 'dest-A', + status: 'COMPLETED', + dataStoreVersionId: 'v1-stored-id', + }], + content: ['METADATA', 'DATA'], + }; + cb(null, { Body: JSON.stringify(md) }); + }); + + crr.run(err => { + assert.ifError(err); + + expect(crr.cloudserverclient.putMetadata).toHaveBeenCalledTimes(1); + const body = JSON.parse(crr.cloudserverclient.putMetadata.mock.calls[0][0].Body); + const repInfo = body.replicationInfo; + + expect(repInfo.backends).toHaveLength(2); + const destA = repInfo.backends.find(b => b.site === 'dest-A'); + const destB = repInfo.backends.find(b => b.site === 'dest-B'); + + // dest-A: status preserved, V2 fields populated from config + expect(destA.status).toBe('COMPLETED'); + expect(destA.dataStoreVersionId).toBe('v1-stored-id'); + expect(destA.destination).toBe('arn:aws:s3:::bucket-a'); + expect(destA.role).toBe('arn:aws:iam::222222222222:role/repRule'); + + // dest-B: newly queued + expect(destB.status).toBe('PENDING'); + done(); + }); + }); + it('should update per-backend destination and role when forceUsingConfiguration is true in V2', done => { // Use COMPLETED filter so the object (dest-A COMPLETED) is re-processed with forceUsingConfiguration const crr = initializeCrrWithMocks({ From f2b2906dd8234025da8861f30561cca44c5c4ea6 Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Mon, 15 Jun 2026 16:29:54 +0200 Subject: [PATCH 07/15] =?UTF-8?q?=F0=9F=90=9B=20refresh=20top-level=20role?= =?UTF-8?q?=20on=20forceUsingConfiguration=20in=20V2=20path?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- CRR/ReplicationStatusUpdater.js | 3 +++ tests/unit/CRR/ReplicationStatusUpdater.js | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CRR/ReplicationStatusUpdater.js b/CRR/ReplicationStatusUpdater.js index 4830a4e5..919c70e3 100644 --- a/CRR/ReplicationStatusUpdater.js +++ b/CRR/ReplicationStatusUpdater.js @@ -435,6 +435,9 @@ class ReplicationStatusUpdater { this._initV2ReplicationInfo(objMD, sourceRole); const replicationInfo = objMD.getReplicationInfo(); this._removeV1Fields(replicationInfo); + if (this.forceUsingConfiguration) { + replicationInfo.role = sourceRole; + } objMD.setReplicationInfo(replicationInfo); const updatedSites = new Set(backendsToUpdate.map(b => b.site)); diff --git a/tests/unit/CRR/ReplicationStatusUpdater.js b/tests/unit/CRR/ReplicationStatusUpdater.js index 7f12a9e7..b568b0be 100644 --- a/tests/unit/CRR/ReplicationStatusUpdater.js +++ b/tests/unit/CRR/ReplicationStatusUpdater.js @@ -1348,12 +1348,12 @@ describe('ReplicationStatusUpdater V2 format', () => { GetBucketReplicationCommand: getBucketReplicationV2Res, }); - // Object has dest-A with stale destination/role + // Object has dest-A with stale top-level role and stale backend destination/role crr.cloudserverclient.getMetadata = jest.fn((p, cb) => { const md = JSON.parse(getMetadataRes.Body); md.replicationInfo = { status: 'COMPLETED', - role: 'arn:aws:iam::8765432:role/sourceRole', + role: 'arn:aws:iam::OLD:role/staleSourceRole', backends: [{ site: 'dest-A', status: 'COMPLETED', @@ -1373,6 +1373,7 @@ describe('ReplicationStatusUpdater V2 format', () => { const body = JSON.parse(crr.cloudserverclient.putMetadata.mock.calls[0][0].Body); const repInfo = body.replicationInfo; + expect(repInfo.role).toBe('arn:aws:iam::8765432:role/sourceRole'); const destA = repInfo.backends.find(b => b.site === 'dest-A'); expect(destA.destination).toBe('arn:aws:s3:::bucket-a'); expect(destA.role).toBe('arn:aws:iam::222222222222:role/repRule'); From cfa6d805d6150d04856f3db9c638ed1e13a6e5c9 Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Tue, 16 Jun 2026 15:01:40 +0200 Subject: [PATCH 08/15] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20apply=20review=20fee?= =?UTF-8?q?dback:=20extract=20=5FupdateObjectMD=20and=20simplify=20V2=20pa?= =?UTF-8?q?th?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- CRR/ReplicationStatusUpdater.js | 322 +++++++-------------- tests/unit/CRR/ReplicationStatusUpdater.js | 39 --- 2 files changed, 105 insertions(+), 256 deletions(-) diff --git a/CRR/ReplicationStatusUpdater.js b/CRR/ReplicationStatusUpdater.js index 919c70e3..c7d67c87 100644 --- a/CRR/ReplicationStatusUpdater.js +++ b/CRR/ReplicationStatusUpdater.js @@ -152,44 +152,6 @@ class ReplicationStatusUpdater { return [...siteMap.values()]; } - /** - * Removes V1-only top-level fields from replicationInfo that have no meaning in V2 format. - * @private - * @param {Object} replicationInfo - The replication info object to mutate. - * @returns {void} - */ - _removeV1Fields(replicationInfo) { - // eslint-disable-next-line no-param-reassign - delete replicationInfo.destination; - // eslint-disable-next-line no-param-reassign - delete replicationInfo.storageClass; - // eslint-disable-next-line no-param-reassign - delete replicationInfo.storageType; - // eslint-disable-next-line no-param-reassign - delete replicationInfo.dataStoreVersionId; - } - - /** - * Initializes V2 replication info on objMD if it is missing or has no status. - * @private - * @param {ObjectMD} objMD - The object metadata. - * @param {string} sourceRole - The source-side IAM role ARN. - * @returns {void} - */ - _initV2ReplicationInfo(objMD, sourceRole) { - const replicationInfo = objMD.getReplicationInfo(); - if (!replicationInfo || !replicationInfo.status) { - const ops = objMD.getContentLength() === 0 ? ['METADATA'] : ['METADATA', 'DATA']; - objMD.setReplicationInfo({ - status: 'PENDING', - role: sourceRole, - backends: [], - content: ops, - isNFS: null, - }); - } - } - /** * Computes the aggregate top-level replication status from all backends per the V2 rules: * any FAILED → FAILED; else any PENDING → PROCESSING; else COMPLETED. @@ -211,41 +173,26 @@ class ReplicationStatusUpdater { * @returns {boolean} True if the object should be updated. */ _objectShouldBeUpdated(objMD, site) { - return this.replicationStatusToProcess.some(filter => { - if (filter === 'NEW') { - // Either site specific replication info is missing - // or are initialized with empty fields. - return (!objMD.getReplicationInfo() - || !objMD.getReplicationSiteStatus({ site })); - } - return (objMD.getReplicationInfo() - && objMD.getReplicationSiteStatus({ site }) === filter); - }); + const info = objMD.getReplicationInfo(); + const siteStatus = info && objMD.getReplicationSiteStatus({ site }); + return this.replicationStatusToProcess.some(filter => + filter === 'NEW' ? (!info || !siteStatus) : (info && siteStatus === filter)); } /** - * Marks an object as pending for replication. + * Fetches, validates, mutates, and writes back object metadata. * @private - * @param {string} bucket - The bucket name. - * @param {string} key - The object key. - * @param {string} versionId - The object version ID. - * @param {string} storageClass - The storage class for replication. - * @param {Object} repConfig - The replication configuration. - * @param {Function} cb - Callback function. + * @param {string} bucket + * @param {string} key + * @param {string} versionId + * @param {Function} mutate - Receives objMD; return { skip: true } to skip the write. + * @param {Function} cb * @returns {void} */ - _markObjectPending( - bucket, - key, - versionId, - storageClass, - repConfig, - cb, - ) { + _updateObjectMD(bucket, key, versionId, mutate, cb) { let objMD; let skip = false; return waterfall([ - // get object blob next => this.cloudserverclient.getMetadata({ Bucket: bucket, Key: key, @@ -257,77 +204,19 @@ class ReplicationStatusUpdater { objMD = new ObjectMD(originalMD); const newMDVersion = objMD.getModelVersion(); - // Prevent schema downgrade: do not write metadata if this model version - // is older than the object's original version, to avoid losing newer fields. if (newMDVersion < originalMDVersion) { this.log.error('model version regression: newMDVersion < originalMDVersion', { - bucket, - key, - versionId, - newMDVersion, - originalMDVersion, + bucket, key, versionId, newMDVersion, originalMDVersion, }); return next(new Error('model version regression: refusing to overwrite newer metadata')); } - if (!this._objectShouldBeUpdated(objMD, storageClass)) { + const result = mutate(objMD); + if (result?.skip) { skip = true; return process.nextTick(next); } - // Initialize replication info, if missing - // This is particularly important if the object was created before - // enabling replication on the bucket. - let replicationInfo = objMD.getReplicationInfo(); - const { Rules, Role } = repConfig; - const destination = Rules[0].Destination.Bucket; - - if (!replicationInfo || !replicationInfo.status) { - // set replication properties - const ops = objMD.getContentLength() === 0 ? ['METADATA'] - : ['METADATA', 'DATA']; - replicationInfo = { - status: 'PENDING', - backends: [], - content: ops, - destination, - storageClass: '', - role: Role, - storageType: '', - dataStoreVersionId: '', - }; - objMD.setReplicationInfo(replicationInfo); - } - - // Force reset object's replication configuration to match bucket's configuration - if (this.forceUsingConfiguration) { - objMD.getReplicationInfo().destination = destination; - objMD.setReplicationRoles(Role); - } - // Update replication info with site specific info - if (!objMD.getReplicationSiteStatus({ site: storageClass })) { - // When replicating to multiple destinations, - // the storageClass and storageType properties - // become comma-separated lists of the storage - // classes and types of the replication destinations. - const ri = objMD.getReplicationInfo(); - ri.storageClass = ri.storageClass - ? `${ri.storageClass},${storageClass}` : storageClass; - if (this.storageType) { - ri.storageType = ri.storageType - ? `${ri.storageType},${this.storageType}` : this.storageType; - } - // Add site to the list of replication backends - const backends = objMD.getReplicationBackends(); - backends.push({ - site: storageClass, - status: 'PENDING', - dataStoreVersionId: '', - }); - objMD.setReplicationBackends(backends); - } - objMD.setReplicationSiteStatus({ site: storageClass }, 'PENDING'); - objMD.setReplicationStatus('PENDING'); objMD.updateMicroVersionId(); const md = objMD.getSerialized(); return this.cloudserverclient.putMetadata({ @@ -356,6 +245,65 @@ class ReplicationStatusUpdater { }); } + /** + * Marks an object as pending for replication. + * @private + * @param {string} bucket - The bucket name. + * @param {string} key - The object key. + * @param {string} versionId - The object version ID. + * @param {string} storageClass - The storage class for replication. + * @param {Object} repConfig - The replication configuration. + * @param {Function} cb - Callback function. + * @returns {void} + */ + _markObjectPending(bucket, key, versionId, storageClass, repConfig, cb) { + this._updateObjectMD(bucket, key, versionId, objMD => { + if (!this._objectShouldBeUpdated(objMD, storageClass)) { + return { skip: true }; + } + + let replicationInfo = objMD.getReplicationInfo(); + const { Rules, Role } = repConfig; + const destination = Rules[0].Destination.Bucket; + + if (!replicationInfo || !replicationInfo.status) { + const ops = objMD.getContentLength() === 0 ? ['METADATA'] : ['METADATA', 'DATA']; + replicationInfo = { + status: 'PENDING', + backends: [], + content: ops, + destination, + storageClass: '', + role: Role, + storageType: '', + dataStoreVersionId: '', + }; + objMD.setReplicationInfo(replicationInfo); + } + + if (this.forceUsingConfiguration) { + objMD.getReplicationInfo().destination = destination; + objMD.setReplicationRoles(Role); + } + + if (!objMD.getReplicationSiteStatus({ site: storageClass })) { + const ri = objMD.getReplicationInfo(); + ri.storageClass = ri.storageClass + ? `${ri.storageClass},${storageClass}` : storageClass; + if (this.storageType) { + ri.storageType = ri.storageType + ? `${ri.storageType},${this.storageType}` : this.storageType; + } + const backends = objMD.getReplicationBackends(); + backends.push({ site: storageClass, status: 'PENDING', dataStoreVersionId: '' }); + objMD.setReplicationBackends(backends); + } + + objMD.setReplicationSiteStatus({ site: storageClass }, 'PENDING'); + objMD.setReplicationStatus('PENDING'); + }, cb); + } + /** * Adapts matched AWS SDK rules to arsenal's ReplicationConfigurationMetadata shape. * @private @@ -392,103 +340,43 @@ class ReplicationStatusUpdater { * @returns {void} */ _markObjectPendingV2(bucket, key, versionId, matchingRules, repConfig, cb) { - let objMD; - let skip = false; - return waterfall([ - next => this.cloudserverclient.getMetadata({ - Bucket: bucket, - Key: key, - VersionId: versionId, - }, next), - (mdRes, next) => { - const originalMD = JSON.parse(mdRes.Body); - const originalMDVersion = originalMD['md-model-version']; - objMD = new ObjectMD(originalMD); - const newMDVersion = objMD.getModelVersion(); + this._updateObjectMD(bucket, key, versionId, objMD => { + const arsenalConfig = this._buildArsenalConfig(matchingRules, repConfig); + const prev = objMD.getReplicationInfo(); + const existingBackends = prev?.backends; - if (newMDVersion < originalMDVersion) { - this.log.error('model version regression: newMDVersion < originalMDVersion', { - bucket, key, versionId, newMDVersion, originalMDVersion, - }); - return next(new Error('model version regression: refusing to overwrite newer metadata')); - } + const candidateBackends = ReplicationConfiguration.resolveBackends( + arsenalConfig, key, () => false, existingBackends, + ); - const arsenalConfig = this._buildArsenalConfig(matchingRules, repConfig); + const backendsToUpdate = candidateBackends.filter(b => + this._objectShouldBeUpdated(objMD, b.site) + ); - // Capture existing backends before any initialization (to carry forward dataStoreVersionId) - const existingBackends = objMD.getReplicationInfo()?.backends; - - const candidateBackends = ReplicationConfiguration.resolveBackends( - arsenalConfig, key, () => false, existingBackends, - ); - - const backendsToUpdate = candidateBackends.filter(b => - this._objectShouldBeUpdated(objMD, b.site) - ); - - if (backendsToUpdate.length === 0) { - skip = true; - return process.nextTick(next); - } - - const sourceRole = ReplicationConfiguration.resolveSourceRole(repConfig.Role); - this._initV2ReplicationInfo(objMD, sourceRole); - const replicationInfo = objMD.getReplicationInfo(); - this._removeV1Fields(replicationInfo); - if (this.forceUsingConfiguration) { - replicationInfo.role = sourceRole; - } - objMD.setReplicationInfo(replicationInfo); - - const updatedSites = new Set(backendsToUpdate.map(b => b.site)); - // Use candidateBackends (always V2-shaped) for skipped sites, but restore - // original status and dataStoreVersionId: resolveBackends forces PENDING on every - // entry, and can't match V1-format existing backends (missing destination/role), - // so it resets dataStoreVersionId to ''. - const skippedBackends = candidateBackends - .filter(b => !updatedSites.has(b.site)) - .map(b => { - const orig = (existingBackends ?? []).find(e => e.site === b.site); - if (!orig) { - return b; - } + if (backendsToUpdate.length === 0) { + return { skip: true }; + } - return { - ...b, - status: orig.status, - dataStoreVersionId: orig.dataStoreVersionId ?? b.dataStoreVersionId, - }; - }); - const finalBackends = [...skippedBackends, ...backendsToUpdate]; - objMD.setReplicationBackends(finalBackends); + const sourceRole = ReplicationConfiguration.resolveSourceRole(repConfig.Role); + const updatedSites = new Set(backendsToUpdate.map(b => b.site)); + // resolveBackends can't match V1-format existing backends (no destination/role), + // so it resets dataStoreVersionId to '' for those — restore it from the original. + const finalBackends = candidateBackends.map(c => { + if (updatedSites.has(c.site)) return c; + const orig = existingBackends?.find(e => e.site === c.site); + return orig + ? { ...c, status: orig.status, dataStoreVersionId: orig.dataStoreVersionId ?? c.dataStoreVersionId } + : c; + }); - objMD.setReplicationStatus(this._computeTopLevelStatus(finalBackends)); - objMD.updateMicroVersionId(); - const md = objMD.getSerialized(); - return this.cloudserverclient.putMetadata({ - Bucket: bucket, - Key: key, - VersionId: versionId, - Body: md, - }, next); - }, - ], err => { - ++this._nProcessed; - if (err) { - ++this._nErrors; - this.log.error('error updating object', { - bucket, key, versionId, error: err.message, - }); - cb(); - return; - } - if (skip) { - ++this._nSkipped; - } else { - ++this._nUpdated; - } - cb(); - }); + objMD.setReplicationInfo({ + status: this._computeTopLevelStatus(finalBackends), + role: this.forceUsingConfiguration ? sourceRole : (prev?.role || sourceRole), + backends: finalBackends, + content: prev?.content ?? (objMD.getContentLength() === 0 ? ['METADATA'] : ['METADATA', 'DATA']), + isNFS: prev?.isNFS ?? null, + }); + }, cb); } /** diff --git a/tests/unit/CRR/ReplicationStatusUpdater.js b/tests/unit/CRR/ReplicationStatusUpdater.js index b568b0be..a70f80d6 100644 --- a/tests/unit/CRR/ReplicationStatusUpdater.js +++ b/tests/unit/CRR/ReplicationStatusUpdater.js @@ -907,45 +907,6 @@ describe('ReplicationStatusUpdater model version guard', () => { }); }); -describe('ReplicationStatusUpdater _removeV1Fields', () => { - it('should delete V1-only top-level fields from replicationInfo', () => { - const crr = initializeCrrWithMocks({ - buckets: ['bucket0'], - workers: 1, - replicationStatusToProcess: ['NEW'], - }, logger); - - const repInfo = { - status: 'PENDING', - destination: 'arn:aws:s3:::bucket', - storageClass: 'dest-A', - storageType: 'aws_s3', - dataStoreVersionId: 'v1', - role: 'arn:aws:iam::123:role/r', - backends: [], - }; - crr._removeV1Fields(repInfo); - expect(repInfo.destination).toBeUndefined(); - expect(repInfo.storageClass).toBeUndefined(); - expect(repInfo.storageType).toBeUndefined(); - expect(repInfo.dataStoreVersionId).toBeUndefined(); - expect(repInfo.status).toBe('PENDING'); - expect(repInfo.role).toBe('arn:aws:iam::123:role/r'); - }); - - it('should be a no-op when V1 fields are already absent', () => { - const crr = initializeCrrWithMocks({ - buckets: ['bucket0'], - workers: 1, - replicationStatusToProcess: ['NEW'], - }, logger); - - const repInfo = { status: 'PENDING', role: 'arn:aws:iam::123:role/r', backends: [] }; - expect(() => crr._removeV1Fields(repInfo)).not.toThrow(); - expect(repInfo.destination).toBeUndefined(); - expect(repInfo.storageClass).toBeUndefined(); - }); -}); describe('ReplicationStatusUpdater._buildArsenalConfig', () => { it('should map AWS SDK rules to arsenal ReplicationConfigurationMetadata shape', () => { From f7c6c33b2fd1a563ef6fcb137a444e914e30a7b9 Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Tue, 16 Jun 2026 15:16:40 +0200 Subject: [PATCH 09/15] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20drop=20=5FgetMatchin?= =?UTF-8?q?gRules,=20make=20resolveBackends=20the=20single=20source=20of?= =?UTF-8?q?=20truth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- CRR/ReplicationStatusUpdater.js | 60 ++++++++-------------- tests/unit/CRR/ReplicationStatusUpdater.js | 40 ++++++++------- 2 files changed, 41 insertions(+), 59 deletions(-) diff --git a/CRR/ReplicationStatusUpdater.js b/CRR/ReplicationStatusUpdater.js index c7d67c87..7eecb868 100644 --- a/CRR/ReplicationStatusUpdater.js +++ b/CRR/ReplicationStatusUpdater.js @@ -128,30 +128,6 @@ class ReplicationStatusUpdater { return repConfig.Rules.every(r => !r.Filter); } - /** - * Returns the subset of rules whose prefix matches the given key, deduplicated by site - * (highest Priority wins when two rules target the same StorageClass). - * @private - * @param {string} key - The object key. - * @param {Array} rules - The replication rules from GetBucketReplicationCommand. - * @returns {Array} - */ - _getMatchingRules(key, rules) { - const siteMap = new Map(); - for (const rule of rules) { - if (rule.Status !== 'Enabled') { continue; } - const prefix = rule.Prefix || (rule.Filter && rule.Filter.Prefix) || ''; - if (!key.startsWith(prefix)) { continue; } - const site = rule.Destination.StorageClass; - const existing = siteMap.get(site); - const priority = rule.Priority || 0; - if (!existing || priority > (existing.Priority || 0)) { - siteMap.set(site, rule); - } - } - return [...siteMap.values()]; - } - /** * Computes the aggregate top-level replication status from all backends per the V2 rules: * any FAILED → FAILED; else any PENDING → PROCESSING; else COMPLETED. @@ -305,17 +281,17 @@ class ReplicationStatusUpdater { } /** - * Adapts matched AWS SDK rules to arsenal's ReplicationConfigurationMetadata shape. + * Adapts AWS SDK replication config to arsenal's ReplicationConfigurationMetadata shape. * @private - * @param {Array} matchingRules - Rules already matched to this key. * @param {Object} repConfig - The full replication configuration. * @returns {Object} */ - _buildArsenalConfig(matchingRules, repConfig) { + _buildArsenalConfig(repConfig) { + const { Role, Rules } = repConfig; return { - role: repConfig.Role, - destination: matchingRules[0]?.Destination.Bucket ?? '', - rules: matchingRules.map(r => ({ + role: Role, + destination: Rules[0]?.Destination.Bucket ?? '', + rules: Rules.map(r => ({ enabled: r.Status === 'Enabled', prefix: r.Filter?.Prefix ?? r.Prefix ?? '', storageClass: r.Destination.StorageClass, @@ -334,21 +310,24 @@ class ReplicationStatusUpdater { * @param {string} bucket - The bucket name. * @param {string} key - The object key. * @param {string} versionId - The object version ID. - * @param {Array} matchingRules - Rules already matched to this key (prefix-filtered, deduped by site). * @param {Object} repConfig - The full replication configuration. * @param {Function} cb - Callback function. * @returns {void} */ - _markObjectPendingV2(bucket, key, versionId, matchingRules, repConfig, cb) { + _markObjectPendingV2(bucket, key, versionId, repConfig, cb) { this._updateObjectMD(bucket, key, versionId, objMD => { - const arsenalConfig = this._buildArsenalConfig(matchingRules, repConfig); + const arsenalConfig = this._buildArsenalConfig(repConfig); const prev = objMD.getReplicationInfo(); const existingBackends = prev?.backends; - const candidateBackends = ReplicationConfiguration.resolveBackends( + let candidateBackends = ReplicationConfiguration.resolveBackends( arsenalConfig, key, () => false, existingBackends, ); + if (this.siteName) { + candidateBackends = candidateBackends.filter(b => b.site === this.siteName); + } + const backendsToUpdate = candidateBackends.filter(b => this._objectShouldBeUpdated(objMD, b.site) ); @@ -451,16 +430,17 @@ class ReplicationStatusUpdater { apply(); return; } - let matchingRules = this._getMatchingRules(Key, Rules); - if (this.siteName) { - matchingRules = matchingRules.filter(r => r.Destination.StorageClass === this.siteName); - } - if (matchingRules.length === 0) { + const hasMatchingRule = Rules.some(r => + r.Status === 'Enabled' && + (!this.siteName || r.Destination.StorageClass === this.siteName) && + Key.startsWith(r.Prefix || r.Filter?.Prefix || '') + ); + if (!hasMatchingRule) { ++this._nSkipped; apply(); return; } - this._markObjectPendingV2(bucket, Key, VersionId, matchingRules, repConfig, apply); + this._markObjectPendingV2(bucket, Key, VersionId, repConfig, apply); }, next); }, ], cb); diff --git a/tests/unit/CRR/ReplicationStatusUpdater.js b/tests/unit/CRR/ReplicationStatusUpdater.js index a70f80d6..2972f4b8 100644 --- a/tests/unit/CRR/ReplicationStatusUpdater.js +++ b/tests/unit/CRR/ReplicationStatusUpdater.js @@ -909,27 +909,29 @@ describe('ReplicationStatusUpdater model version guard', () => { describe('ReplicationStatusUpdater._buildArsenalConfig', () => { - it('should map AWS SDK rules to arsenal ReplicationConfigurationMetadata shape', () => { + it('should map AWS SDK replication config to arsenal ReplicationConfigurationMetadata shape', () => { const crr = initializeCrrWithMocks({ buckets: [], workers: 1, replicationStatusToProcess: ['NEW'] }, logger); - const matchingRules = [ - { - ID: 'rule1', - Status: 'Enabled', - Filter: { Prefix: '' }, - Priority: 1, - Destination: { Bucket: 'arn:aws:s3:::bucket-a', StorageClass: 'dest-A', Account: '111111111111' }, - }, - { - ID: 'rule2', - Status: 'Enabled', - Filter: { Prefix: 'docs/' }, - Priority: 2, - Destination: { Bucket: 'arn:aws:s3:::bucket-b', StorageClass: 'dest-B', Account: '222222222222' }, - }, - ]; - const repConfig = { Role: 'arn:aws:iam::root:role/src,arn:aws:iam::root:role/dst' }; + const repConfig = { + Role: 'arn:aws:iam::root:role/src,arn:aws:iam::root:role/dst', + Rules: [ + { + ID: 'rule1', + Status: 'Enabled', + Filter: { Prefix: '' }, + Priority: 1, + Destination: { Bucket: 'arn:aws:s3:::bucket-a', StorageClass: 'dest-A', Account: '111111111111' }, + }, + { + ID: 'rule2', + Status: 'Enabled', + Filter: { Prefix: 'docs/' }, + Priority: 2, + Destination: { Bucket: 'arn:aws:s3:::bucket-b', StorageClass: 'dest-B', Account: '222222222222' }, + }, + ], + }; - const result = crr._buildArsenalConfig(matchingRules, repConfig); + const result = crr._buildArsenalConfig(repConfig); expect(result.role).toBe(repConfig.Role); expect(result.destination).toBe('arn:aws:s3:::bucket-a'); From 45ce9cda669e36d8e526d65efca8d1120b003055 Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Tue, 16 Jun 2026 15:49:44 +0200 Subject: [PATCH 10/15] =?UTF-8?q?=F0=9F=94=A7=20fix=20lint=20warnings=20af?= =?UTF-8?q?ter=20refactor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- CRR/ReplicationStatusUpdater.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CRR/ReplicationStatusUpdater.js b/CRR/ReplicationStatusUpdater.js index 7eecb868..d69de6e7 100644 --- a/CRR/ReplicationStatusUpdater.js +++ b/CRR/ReplicationStatusUpdater.js @@ -258,7 +258,8 @@ class ReplicationStatusUpdater { } if (this.forceUsingConfiguration) { - objMD.getReplicationInfo().destination = destination; + const ri = objMD.getReplicationInfo(); + ri.destination = destination; objMD.setReplicationRoles(Role); } @@ -277,6 +278,7 @@ class ReplicationStatusUpdater { objMD.setReplicationSiteStatus({ site: storageClass }, 'PENDING'); objMD.setReplicationStatus('PENDING'); + return { skip: false }; }, cb); } @@ -341,7 +343,7 @@ class ReplicationStatusUpdater { // resolveBackends can't match V1-format existing backends (no destination/role), // so it resets dataStoreVersionId to '' for those — restore it from the original. const finalBackends = candidateBackends.map(c => { - if (updatedSites.has(c.site)) return c; + if (updatedSites.has(c.site)) { return c; } const orig = existingBackends?.find(e => e.site === c.site); return orig ? { ...c, status: orig.status, dataStoreVersionId: orig.dataStoreVersionId ?? c.dataStoreVersionId } @@ -355,6 +357,7 @@ class ReplicationStatusUpdater { content: prev?.content ?? (objMD.getContentLength() === 0 ? ['METADATA'] : ['METADATA', 'DATA']), isNFS: prev?.isNFS ?? null, }); + return { skip: false }; }, cb); } From dcbdaa0e645329f254602eaf8597163cb0d2a28f Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Wed, 17 Jun 2026 16:25:47 +0200 Subject: [PATCH 11/15] =?UTF-8?q?=F0=9F=94=92=20fix=20moderate=20vulnerabi?= =?UTF-8?q?lities=20via=20resolutions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- package.json | 2 ++ yarn.lock | 22 ++++++++-------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index ad94b04c..0967d725 100644 --- a/package.json +++ b/package.json @@ -50,8 +50,10 @@ "xml2js": "^0.6.2" }, "resolutions": { + "@opentelemetry/core": "^2.8.0", "ioctl": "2.0.2", "jsprim": "1.4.2", + "protobufjs": "^7.6.4", "string-width": "4.2.3" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index bfa58aef..6fdfe6e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2424,10 +2424,10 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-2.7.1.tgz#1555a6fb269596416d8c626fd020c3f2c38e071f" integrity sha512-OPFBYuXEn1E4ja3Y6eeA7O+ZnLBNcXTV5Cgsn1VaqBZ6hC5FnpZPLBNme1LJY8ZtF4aOujPKFoeWN4ik487KuQ== -"@opentelemetry/core@2.7.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-2.7.1.tgz#162bfab46d6ff4da1bef240ea52e23a926b0fdbc" - integrity sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw== +"@opentelemetry/core@2.7.1", "@opentelemetry/core@^2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-2.8.0.tgz#f6e86de3688bdb54a6ca8f4935363a5b588ae91c" + integrity sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww== dependencies: "@opentelemetry/semantic-conventions" "^1.29.0" @@ -2729,11 +2729,6 @@ resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== -"@protobufjs/inquire@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.2.tgz#ae64fbc014ff44c8bfad03dd4c93cd2d6a4c82db" - integrity sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw== - "@protobufjs/path@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" @@ -8280,10 +8275,10 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -protobufjs@^7.5.5: - version "7.6.2" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.6.2.tgz#2659f77bd8d54778814c274dc0df808f54c88918" - integrity sha512-N9EiLovGEQOJSPF26Ij7qUGvahfEnq0eeYZ02aigIedkmz1qZSwjnP9SBITHJuF/6MYbIW4HDN8zdYjsjqJKXQ== +protobufjs@^7.5.5, protobufjs@^7.6.4: + version "7.6.4" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.6.4.tgz#8bb000300026efd63eb7951d26e5dbb38f5658f2" + integrity sha512-RJJPTTpvFfHcWLkIa2JFWK4XvtSzS0yEWDmunqHXli1h3JlkbcQZXDZdcWxv+JK3Xsl5/UFDPZ0iGm7DAengYw== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -8291,7 +8286,6 @@ protobufjs@^7.5.5: "@protobufjs/eventemitter" "^1.1.1" "@protobufjs/fetch" "^1.1.1" "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.2" "@protobufjs/path" "^1.1.2" "@protobufjs/pool" "^1.1.0" "@protobufjs/utf8" "^1.1.1" From d64440f39a2770f5af49be7779e2facbf32c7ffa Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Wed, 17 Jun 2026 16:40:27 +0200 Subject: [PATCH 12/15] =?UTF-8?q?=F0=9F=93=8C=20upgrade=20arsenal=20to=20l?= =?UTF-8?q?atest=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- package.json | 2 +- yarn.lock | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0967d725..bdfb3ef2 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@senx/warp10": "^2.0.3", "@smithy/util-retry": "^4.0.7", "JSONStream": "^1.3.5", - "arsenal": "git+https://github.com/scality/Arsenal#improvement/ARSN-571/crr-multi", + "arsenal": "git+https://github.com/scality/arsenal#8.4.7", "async": "^3.2.6", "bucketclient": "scality/bucketclient#8.2.6", "express": "^5.1.0", diff --git a/yarn.lock b/yarn.lock index 6fdfe6e5..11b57c9a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4533,9 +4533,9 @@ arraybuffer.prototype.slice@^1.0.4: optionalDependencies: ioctl "^2.0.2" -"arsenal@git+https://github.com/scality/Arsenal#improvement/ARSN-571/crr-multi": - version "8.4.5" - resolved "git+https://github.com/scality/Arsenal#c3f3bffde6eeb935e03847df010ac37ac7ba8944" +"arsenal@git+https://github.com/scality/arsenal#8.4.7": + version "8.4.7" + resolved "git+https://github.com/scality/arsenal#096cb33f1092b35113a11521bbbb62ef615aed79" dependencies: "@aws-sdk/client-kms" "^3.975.0" "@aws-sdk/client-s3" "^3.975.0" @@ -6248,7 +6248,6 @@ http-proxy-agent@^7.0.0: "httpagent@git+https://github.com/scality/httpagent#1.1.0": version "1.1.0" - uid "8f9958eb9cde086db7819a86582fba640a5f8876" resolved "git+https://github.com/scality/httpagent#8f9958eb9cde086db7819a86582fba640a5f8876" dependencies: agentkeepalive "^4.5.0" From 72be12d3a382976b4577ef19cf4f428d186c22a0 Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Wed, 17 Jun 2026 16:47:19 +0200 Subject: [PATCH 13/15] =?UTF-8?q?=F0=9F=90=9B=20preserve=20non-targeted=20?= =?UTF-8?q?backends=20when=20SITE=5FNAME=20is=20set=20in=20V2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- CRR/ReplicationStatusUpdater.js | 11 ++-- tests/unit/CRR/ReplicationStatusUpdater.js | 63 ++++++++++++++++++++++ 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/CRR/ReplicationStatusUpdater.js b/CRR/ReplicationStatusUpdater.js index d69de6e7..59f5ed0a 100644 --- a/CRR/ReplicationStatusUpdater.js +++ b/CRR/ReplicationStatusUpdater.js @@ -342,18 +342,23 @@ class ReplicationStatusUpdater { const updatedSites = new Set(backendsToUpdate.map(b => b.site)); // resolveBackends can't match V1-format existing backends (no destination/role), // so it resets dataStoreVersionId to '' for those — restore it from the original. - const finalBackends = candidateBackends.map(c => { + const candidateSites = new Set(candidateBackends.map(b => b.site)); + const updatedBackends = candidateBackends.map(c => { if (updatedSites.has(c.site)) { return c; } const orig = existingBackends?.find(e => e.site === c.site); return orig ? { ...c, status: orig.status, dataStoreVersionId: orig.dataStoreVersionId ?? c.dataStoreVersionId } : c; }); + // Preserve backends for sites not targeted by this run (e.g. when SITE_NAME is set), + // so they are not silently dropped from the metadata. + const preservedBackends = (existingBackends || []).filter(b => !candidateSites.has(b.site)); + const allBackends = [...updatedBackends, ...preservedBackends]; objMD.setReplicationInfo({ - status: this._computeTopLevelStatus(finalBackends), + status: this._computeTopLevelStatus(allBackends), role: this.forceUsingConfiguration ? sourceRole : (prev?.role || sourceRole), - backends: finalBackends, + backends: allBackends, content: prev?.content ?? (objMD.getContentLength() === 0 ? ['METADATA'] : ['METADATA', 'DATA']), isNFS: prev?.isNFS ?? null, }); diff --git a/tests/unit/CRR/ReplicationStatusUpdater.js b/tests/unit/CRR/ReplicationStatusUpdater.js index 2972f4b8..92ee0bd2 100644 --- a/tests/unit/CRR/ReplicationStatusUpdater.js +++ b/tests/unit/CRR/ReplicationStatusUpdater.js @@ -1343,4 +1343,67 @@ describe('ReplicationStatusUpdater V2 format', () => { done(); }); }); + + it('should preserve backends for sites outside SITE_NAME when updating', done => { + // docs/report.pdf matches both rule1 (prefix='', dest-A) and rule2 (prefix='docs/', dest-B) + // dest-A is NEW (will be queued); dest-B is COMPLETED (must be preserved) + // With SITE_NAME=dest-A, candidateBackends is filtered to dest-A only. + // Without the fix, setReplicationInfo replaces backends with [dest-A], silently dropping dest-B. + const listVersionDocsKey = { + IsTruncated: false, + Versions: [{ + ETag: '"abc"', ChecksumAlgorithm: [], Size: 100, + StorageClass: 'STANDARD', Key: 'docs/report.pdf', + VersionId: 'aJdO148N3LjN00000000001I4j3QKItW', IsLatest: true, + LastModified: '2024-01-05T13:11:31.861Z', + Owner: { DisplayName: 'bart', ID: '0' }, + }], + DeleteMarkers: [], Name: 'bucket0', MaxKeys: 1000, CommonPrefixes: [], + }; + + const crr = initializeCrrWithMocks({ + buckets: ['bucket0'], + workers: 10, + replicationStatusToProcess: ['NEW'], + siteName: 'dest-A', + }, logger, { + ListObjectVersionsCommand: listVersionDocsKey, + GetBucketReplicationCommand: getBucketReplicationV2Res, + }); + + crr.cloudserverclient.getMetadata = jest.fn((p, cb) => { + const md = JSON.parse(getMetadataRes.Body); + // Only dest-B exists in metadata (dest-A was never replicated to) + md.replicationInfo = { + status: 'COMPLETED', + role: 'arn:aws:iam::8765432:role/sourceRole', + backends: [{ + site: 'dest-B', + status: 'COMPLETED', + destination: 'arn:aws:s3:::bucket-b', + role: 'arn:aws:iam::333333333333:role/repRule', + dataStoreVersionId: 'dest-b-version-id', + }], + content: ['METADATA', 'DATA'], + }; + cb(null, { Body: JSON.stringify(md) }); + }); + + crr.run(err => { + assert.ifError(err); + + expect(crr.cloudserverclient.putMetadata).toHaveBeenCalledTimes(1); + const body = JSON.parse(crr.cloudserverclient.putMetadata.mock.calls[0][0].Body); + const repInfo = body.replicationInfo; + + expect(repInfo.backends).toHaveLength(2); + const destA = repInfo.backends.find(b => b.site === 'dest-A'); + const destB = repInfo.backends.find(b => b.site === 'dest-B'); + + expect(destA.status).toBe('PENDING'); + expect(destB.status).toBe('COMPLETED'); + expect(destB.dataStoreVersionId).toBe('dest-b-version-id'); + done(); + }); + }); }); From b781b84fbcf333b600ed2ed31b82b2bc0409d107 Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Wed, 17 Jun 2026 16:55:50 +0200 Subject: [PATCH 14/15] =?UTF-8?q?=F0=9F=94=A7=20align=20prefix=20coalescin?= =?UTF-8?q?g=20in=20V2=20rule=20pre-fetch=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- CRR/ReplicationStatusUpdater.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CRR/ReplicationStatusUpdater.js b/CRR/ReplicationStatusUpdater.js index 59f5ed0a..c1a0495f 100644 --- a/CRR/ReplicationStatusUpdater.js +++ b/CRR/ReplicationStatusUpdater.js @@ -441,7 +441,7 @@ class ReplicationStatusUpdater { const hasMatchingRule = Rules.some(r => r.Status === 'Enabled' && (!this.siteName || r.Destination.StorageClass === this.siteName) && - Key.startsWith(r.Prefix || r.Filter?.Prefix || '') + Key.startsWith(r.Filter?.Prefix ?? r.Prefix ?? '') ); if (!hasMatchingRule) { ++this._nSkipped; From d120e31cee5bc0e853ca75fc9dab4c44acb2404d Mon Sep 17 00:00:00 2001 From: DarkIsDude Date: Tue, 23 Jun 2026 16:56:02 +0200 Subject: [PATCH 15/15] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20arsenal=20?= =?UTF-8?q?to=20latest=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: S3UTILS-230 --- package.json | 2 +- yarn.lock | 499 ++++++++++++++++++++++++++------------------------- 2 files changed, 251 insertions(+), 250 deletions(-) diff --git a/package.json b/package.json index bdfb3ef2..e4f5677a 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@senx/warp10": "^2.0.3", "@smithy/util-retry": "^4.0.7", "JSONStream": "^1.3.5", - "arsenal": "git+https://github.com/scality/arsenal#8.4.7", + "arsenal": "git+https://github.com/scality/arsenal#8.5.0", "async": "^3.2.6", "bucketclient": "scality/bucketclient#8.2.6", "express": "^5.1.0", diff --git a/yarn.lock b/yarn.lock index 11b57c9a..6bd800ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2394,14 +2394,14 @@ dependencies: semver "^7.3.5" -"@opentelemetry/api-logs@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.218.0.tgz#7b9818e8dfdf1d3dcab88bfe4d6724f2f831f7ec" - integrity sha512-fmEWp5kXlGEc3i/lR698Hz41DfGyN4Tbe4g7L1AxSc7fF8Xeh/FQ9Quqpa9dVA413Q1Ad43QOLzU4JoXgbFPWw== +"@opentelemetry/api-logs@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.219.0.tgz#3303f10f43e6ff1741f8f6019e43a92723781630" + integrity sha512-FFx7YnaYJlIjqWW/AG/yAZ0L/NEY724PipXXXQLdtZPbLwBGbUMTGL1i/esI56TWfTUXxhLfpgrnWJCG8aUJyg== dependencies: "@opentelemetry/api" "^1.3.0" -"@opentelemetry/api@^1.3.0", "@opentelemetry/api@^1.9.0": +"@opentelemetry/api@^1.3.0", "@opentelemetry/api@^1.9.1": version "1.9.1" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.1.tgz#c1b0346de336ba55af2d5a7970882037baedec05" integrity sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q== @@ -2411,281 +2411,282 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== -"@opentelemetry/configuration@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/configuration/-/configuration-0.218.0.tgz#a5fdd50ec9cfa0adb3bb41202cb39f79c5f4e7d9" - integrity sha512-W8wIz7H2R1pufR5jfjb3gU2XkMpm2x/7b1RJcsuzvd70Il/rWWE+g5/Od7hQKrxRTSrTrOWlru101PWXz5I1EQ== +"@opentelemetry/configuration@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/configuration/-/configuration-0.219.0.tgz#cb950aaa77bdb921a3fd636dc792f8beb712be17" + integrity sha512-wXZUYv4ngu43nA4WEhuXNacm46LW+17LRM8nKyIhBzroRA24PBYjMnakwzR/w777nFUB5xlgsYTTeuXxumZM1Q== dependencies: - "@opentelemetry/core" "2.7.1" + "@opentelemetry/core" "2.8.0" yaml "^2.0.0" -"@opentelemetry/context-async-hooks@2.7.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-2.7.1.tgz#1555a6fb269596416d8c626fd020c3f2c38e071f" - integrity sha512-OPFBYuXEn1E4ja3Y6eeA7O+ZnLBNcXTV5Cgsn1VaqBZ6hC5FnpZPLBNme1LJY8ZtF4aOujPKFoeWN4ik487KuQ== +"@opentelemetry/context-async-hooks@2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-2.8.0.tgz#24381ef388bc28d53fa8dad72dfd1429acc82016" + integrity sha512-/3FIraneMcng67SUJCxvyInk/oxzwsxyadufk0wwfOBLf5wqtAGX4MoQASwSbndBPeARzBryUM9Azr5kHIdWLw== -"@opentelemetry/core@2.7.1", "@opentelemetry/core@^2.8.0": +"@opentelemetry/core@2.8.0", "@opentelemetry/core@^2.8.0": version "2.8.0" resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-2.8.0.tgz#f6e86de3688bdb54a6ca8f4935363a5b588ae91c" integrity sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww== dependencies: "@opentelemetry/semantic-conventions" "^1.29.0" -"@opentelemetry/exporter-logs-otlp-grpc@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.218.0.tgz#7e5a7e624074d6449590c851d58efe60096314b3" - integrity sha512-hoxrNH1l/Xy6F9WTJ5IK+6j1r9nQFlPOmrnTlhYHTySdunfXLmUCPv3bQtKYntxag9h3wLYBZQ2HI6FOx+BT2g== +"@opentelemetry/exporter-logs-otlp-grpc@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.219.0.tgz#d828e7495d05c54fd51a6495094eaf9e485805c1" + integrity sha512-7SvzDCIclHWAcCwZ1MTOLcwn4BVNPGI3QxS/DJraPNe1TTL+4TvUBq5zeQV8tsnYvtDN7wKW2qocVmaCP2l7sQ== dependencies: "@grpc/grpc-js" "^1.14.3" - "@opentelemetry/core" "2.7.1" - "@opentelemetry/otlp-exporter-base" "0.218.0" - "@opentelemetry/otlp-grpc-exporter-base" "0.218.0" - "@opentelemetry/otlp-transformer" "0.218.0" - "@opentelemetry/sdk-logs" "0.218.0" - -"@opentelemetry/exporter-logs-otlp-http@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.218.0.tgz#0996cb45e0ebc6c7465445430a018edcac9871b4" - integrity sha512-Qx+4rpVHzgg89dawcWRHyt+XRXeLnhFz/qBtvggmjkcgPUdr+NAB0/u/eIPA8yAeJV0J80Vz43JZCh/XFvZFGw== - dependencies: - "@opentelemetry/api-logs" "0.218.0" - "@opentelemetry/core" "2.7.1" - "@opentelemetry/otlp-exporter-base" "0.218.0" - "@opentelemetry/otlp-transformer" "0.218.0" - "@opentelemetry/sdk-logs" "0.218.0" - -"@opentelemetry/exporter-logs-otlp-proto@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.218.0.tgz#e539720b2e145e85a7a4901a1eabb0b2e77990f8" - integrity sha512-1/noQNsp9gXD75HPzgjBrcF1+XTtry7pFAUfxVEJgg7mPv2AawKQuYkhMmJ8qjxz4Ubc3Y8bwvfxevXsKTq4cg== - dependencies: - "@opentelemetry/api-logs" "0.218.0" - "@opentelemetry/core" "2.7.1" - "@opentelemetry/otlp-exporter-base" "0.218.0" - "@opentelemetry/otlp-transformer" "0.218.0" - "@opentelemetry/resources" "2.7.1" - "@opentelemetry/sdk-logs" "0.218.0" - "@opentelemetry/sdk-trace-base" "2.7.1" - -"@opentelemetry/exporter-metrics-otlp-grpc@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.218.0.tgz#6d66c2638702489d063b8857741eee9cea1d21d6" - integrity sha512-YapQ9vNMX0NSZF6LK5pWAFfjpJleV2O9uYWfYGeb/5F1Kb9rPGK8tZDMJFa/sOksgdFuflDvYuA0B4qjDB4fjQ== + "@opentelemetry/core" "2.8.0" + "@opentelemetry/otlp-exporter-base" "0.219.0" + "@opentelemetry/otlp-grpc-exporter-base" "0.219.0" + "@opentelemetry/otlp-transformer" "0.219.0" + "@opentelemetry/sdk-logs" "0.219.0" + +"@opentelemetry/exporter-logs-otlp-http@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.219.0.tgz#3a4764ec408efdf9c573cfc3e4ffc41392694d3b" + integrity sha512-mhl2HL6GmZI8b8PwPfqMws/5ovJfbRTxwc9Y5agVVHiQ+e5SL1btsFr/kJDgt7YCexDtsUn5HAreHQO9szFS0A== + dependencies: + "@opentelemetry/api-logs" "0.219.0" + "@opentelemetry/core" "2.8.0" + "@opentelemetry/otlp-exporter-base" "0.219.0" + "@opentelemetry/otlp-transformer" "0.219.0" + "@opentelemetry/sdk-logs" "0.219.0" + +"@opentelemetry/exporter-logs-otlp-proto@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.219.0.tgz#de0431c17a944928471ffab1dcea9e02e70271ac" + integrity sha512-Ayw4Gf71PS9jhBVaYywa4WsajnqfDehMkTdVH3TSAVHqPcsAv/AhH/wTNRYNt99szeYr6Gbd/D6RjZD77wAxHg== + dependencies: + "@opentelemetry/api-logs" "0.219.0" + "@opentelemetry/core" "2.8.0" + "@opentelemetry/otlp-exporter-base" "0.219.0" + "@opentelemetry/otlp-transformer" "0.219.0" + "@opentelemetry/resources" "2.8.0" + "@opentelemetry/sdk-logs" "0.219.0" + "@opentelemetry/sdk-trace-base" "2.8.0" + +"@opentelemetry/exporter-metrics-otlp-grpc@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.219.0.tgz#b9d1ede26f45adfbcbf087dd7d4065dfc1268121" + integrity sha512-6LaaSrPxK5L55bXevWajvOMxGOpNm0n12tG53TeZaUeNzXwLPg6d2KCC1zAlGsojan+xRG71mA4Qqs9K2VVrKQ== dependencies: "@grpc/grpc-js" "^1.14.3" - "@opentelemetry/core" "2.7.1" - "@opentelemetry/exporter-metrics-otlp-http" "0.218.0" - "@opentelemetry/otlp-exporter-base" "0.218.0" - "@opentelemetry/otlp-grpc-exporter-base" "0.218.0" - "@opentelemetry/otlp-transformer" "0.218.0" - "@opentelemetry/resources" "2.7.1" - "@opentelemetry/sdk-metrics" "2.7.1" - -"@opentelemetry/exporter-metrics-otlp-http@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.218.0.tgz#c205581585d04c5106d1ca766e23632006e46a2c" - integrity sha512-bV7d2OuMpZu2+gAaxUAhzfZ0h3WVZk8ETQUEE3DNSntbTaMpuITjtm8I0rNyHFdm7Ax57K6ty7SgFXlBmOLIvQ== - dependencies: - "@opentelemetry/core" "2.7.1" - "@opentelemetry/otlp-exporter-base" "0.218.0" - "@opentelemetry/otlp-transformer" "0.218.0" - "@opentelemetry/resources" "2.7.1" - "@opentelemetry/sdk-metrics" "2.7.1" - -"@opentelemetry/exporter-metrics-otlp-proto@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-proto/-/exporter-metrics-otlp-proto-0.218.0.tgz#66642b8bb5e654ca7a5944a4f0b490814fc875fd" - integrity sha512-ubLddKjWULhla9YZRCj/rTBeppjJYE4e9w0icx5mTu3eFhWjQzbV75NYjXuIlEG+NJsBl6d+sTFw5Qu+oej4oQ== - dependencies: - "@opentelemetry/core" "2.7.1" - "@opentelemetry/exporter-metrics-otlp-http" "0.218.0" - "@opentelemetry/otlp-exporter-base" "0.218.0" - "@opentelemetry/otlp-transformer" "0.218.0" - "@opentelemetry/resources" "2.7.1" - "@opentelemetry/sdk-metrics" "2.7.1" - -"@opentelemetry/exporter-prometheus@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.218.0.tgz#41bddc97d34cd9d9993382b9c10fed19a8de63f4" - integrity sha512-RT5oEyu1kddZJ1vt7/BUo5wV+P7hpNAESsR3dUd3+8deHuX7gWNoCOZn+SfDT+hJHlIJ5h/AxiCLXIrutswDJg== - dependencies: - "@opentelemetry/core" "2.7.1" - "@opentelemetry/resources" "2.7.1" - "@opentelemetry/sdk-metrics" "2.7.1" + "@opentelemetry/core" "2.8.0" + "@opentelemetry/exporter-metrics-otlp-http" "0.219.0" + "@opentelemetry/otlp-exporter-base" "0.219.0" + "@opentelemetry/otlp-grpc-exporter-base" "0.219.0" + "@opentelemetry/otlp-transformer" "0.219.0" + "@opentelemetry/resources" "2.8.0" + "@opentelemetry/sdk-metrics" "2.8.0" + +"@opentelemetry/exporter-metrics-otlp-http@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.219.0.tgz#aed2238678486434cff020cbdfef07b24f1370b6" + integrity sha512-6CaDRbMVHZSDWzNXwrR8y/H4B/Z1eMNnkHiPQlTx3Ojz2OHY4X/aff/UC4P/3pHUQSuTfi3oh2UsPPZppw+Vrg== + dependencies: + "@opentelemetry/core" "2.8.0" + "@opentelemetry/otlp-exporter-base" "0.219.0" + "@opentelemetry/otlp-transformer" "0.219.0" + "@opentelemetry/resources" "2.8.0" + "@opentelemetry/sdk-metrics" "2.8.0" + +"@opentelemetry/exporter-metrics-otlp-proto@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-proto/-/exporter-metrics-otlp-proto-0.219.0.tgz#7a7a20dba913f00c115fb48901502680c41e23dc" + integrity sha512-DUS7XyIiEnoeccQUvuKy0G2/YqeKhpN8FVIrGbrLNIVMj10yeIFLRzRv0tibCI2kXXvlTTABVexGAk78wHk2ug== + dependencies: + "@opentelemetry/core" "2.8.0" + "@opentelemetry/exporter-metrics-otlp-http" "0.219.0" + "@opentelemetry/otlp-exporter-base" "0.219.0" + "@opentelemetry/otlp-transformer" "0.219.0" + "@opentelemetry/resources" "2.8.0" + "@opentelemetry/sdk-metrics" "2.8.0" + +"@opentelemetry/exporter-prometheus@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.219.0.tgz#8ea911269156f3cd4f08a1e8e5727df3f316b687" + integrity sha512-TxOnJ85eWJY5JyOJsNMXiRTYlkDcOv0u3KbXEzWCc+tUS9sjL/BC6BcdxZ0B9r2OFVqsrZFXUzSD2sZUy42Ucw== + dependencies: + "@opentelemetry/core" "2.8.0" + "@opentelemetry/resources" "2.8.0" + "@opentelemetry/sdk-metrics" "2.8.0" "@opentelemetry/semantic-conventions" "^1.29.0" -"@opentelemetry/exporter-trace-otlp-grpc@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.218.0.tgz#5d5532ab94d5514bec8aedc19ce3170b6381eed1" - integrity sha512-3fXxVQEj9TNAFaCi79JeFKfeLd0sDtInaR3gaZDVlzNSPHtz8PZuCV34JKWjD4XXzT20IdMe8IpX6mRVNDA4Tw== +"@opentelemetry/exporter-trace-otlp-grpc@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.219.0.tgz#ef421636a3e360b4e8e1d26a2cae0d6f49c5187a" + integrity sha512-BkDNv1UD6BscW19MxbAxVmSYSSFuyeqR6buV2/HTYqA7GrR0EbTFzqG6h86T3PtXmpdbsWjMGLDdjG2rikG27Q== dependencies: "@grpc/grpc-js" "^1.14.3" - "@opentelemetry/core" "2.7.1" - "@opentelemetry/otlp-exporter-base" "0.218.0" - "@opentelemetry/otlp-grpc-exporter-base" "0.218.0" - "@opentelemetry/otlp-transformer" "0.218.0" - "@opentelemetry/resources" "2.7.1" - "@opentelemetry/sdk-trace-base" "2.7.1" - -"@opentelemetry/exporter-trace-otlp-http@0.218.0", "@opentelemetry/exporter-trace-otlp-http@^0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.218.0.tgz#36d6abf6d639b9ea861603c61f434751c0b1a0ea" - integrity sha512-8dqezsmPhtKitIK/eTipZhYl9EX2/gNQ5zUMhaz3uxEURwfkNf8IPvo6yNfrzbxdtpAOybS/+h7wmIWYqFSpiw== - dependencies: - "@opentelemetry/core" "2.7.1" - "@opentelemetry/otlp-exporter-base" "0.218.0" - "@opentelemetry/otlp-transformer" "0.218.0" - "@opentelemetry/resources" "2.7.1" - "@opentelemetry/sdk-trace-base" "2.7.1" - -"@opentelemetry/exporter-trace-otlp-proto@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.218.0.tgz#de0b2b3545149dafedd2b948fb891f9bf962940c" - integrity sha512-r1Msf8SNLRmwh9J6XQ5uh82D7CdDWMNHnPB7LAVHjzut0TkSeKc5KcIvr4SvHvfk/xwN5gxC+VLKQ1k0o8PSPw== - dependencies: - "@opentelemetry/core" "2.7.1" - "@opentelemetry/otlp-exporter-base" "0.218.0" - "@opentelemetry/otlp-transformer" "0.218.0" - "@opentelemetry/resources" "2.7.1" - "@opentelemetry/sdk-trace-base" "2.7.1" - -"@opentelemetry/exporter-zipkin@2.7.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-zipkin/-/exporter-zipkin-2.7.1.tgz#3b79d223adc8c097ba3323e4de4ed8abb83c789e" - integrity sha512-mfsD9bKAxcKrh5+y08TPodvClBO0CznBE3p79YAGnO81WI4LrdsGA65T53e4iTSbCalW4WaUpkbeJcbpyIUHfg== - dependencies: - "@opentelemetry/core" "2.7.1" - "@opentelemetry/resources" "2.7.1" - "@opentelemetry/sdk-trace-base" "2.7.1" + "@opentelemetry/core" "2.8.0" + "@opentelemetry/otlp-exporter-base" "0.219.0" + "@opentelemetry/otlp-grpc-exporter-base" "0.219.0" + "@opentelemetry/otlp-transformer" "0.219.0" + "@opentelemetry/resources" "2.8.0" + "@opentelemetry/sdk-trace-base" "2.8.0" + +"@opentelemetry/exporter-trace-otlp-http@0.219.0", "@opentelemetry/exporter-trace-otlp-http@^0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.219.0.tgz#37ad13bd871fe5d983754bb2ad2e2ac2f3e167ec" + integrity sha512-9t6SvBXXBEjOBcIzgozvBbd3jWrv3Gt3ngGhl1fhdZ/zRc7oZDVOFEqbi2zlBpW9BXhgDMKv422J0DL/3iQWfw== + dependencies: + "@opentelemetry/core" "2.8.0" + "@opentelemetry/otlp-exporter-base" "0.219.0" + "@opentelemetry/otlp-transformer" "0.219.0" + "@opentelemetry/resources" "2.8.0" + "@opentelemetry/sdk-trace-base" "2.8.0" + +"@opentelemetry/exporter-trace-otlp-proto@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.219.0.tgz#cec3c1da46bb3ac5774461830634d6509b797bf1" + integrity sha512-lF/LUBfhOFmxJa+SQsLN7ziV4MHa2pyKgOM6JNehSOfU+npjM4gwm9oIKEJrzrWcexMcqydiyoFy0XCb1Ql3wQ== + dependencies: + "@opentelemetry/core" "2.8.0" + "@opentelemetry/otlp-exporter-base" "0.219.0" + "@opentelemetry/otlp-transformer" "0.219.0" + "@opentelemetry/resources" "2.8.0" + "@opentelemetry/sdk-trace-base" "2.8.0" + +"@opentelemetry/exporter-zipkin@2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-zipkin/-/exporter-zipkin-2.8.0.tgz#03f5ca641f611fc15b9530d2a2ec6238a167bda1" + integrity sha512-Mj84UkEa17BK2o903VTXW3wM8CrSZexGs4tRGVZVIMM9ni1T6TuGx5IrRfoWKAbshx42D5/kc7YV+axypLPYyA== + dependencies: + "@opentelemetry/core" "2.8.0" + "@opentelemetry/resources" "2.8.0" + "@opentelemetry/sdk-trace-base" "2.8.0" "@opentelemetry/semantic-conventions" "^1.29.0" -"@opentelemetry/instrumentation@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.218.0.tgz#fcceb4ffb45f99c0d292600769150fc5944dc3e9" - integrity sha512-mIZil8Es+sYDK5m+DQiwAwF57F14TF2YlEqvIjZ/RQWcxDBwRGsKfdK2Tv65OU9meQKCMzSIFS9mxAcnAb6Bkg== +"@opentelemetry/instrumentation@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.219.0.tgz#84399affd8ee4a12cb199f325c4858654d8dedee" + integrity sha512-X5t7I8GyIO9rmGHwoedZLREpQqrF1WW2nxzNNym6HOKpFiE+rvqV3ngC0xcZVO2YwIGf3KKmRdWrYwdwz3H9RQ== dependencies: - "@opentelemetry/api-logs" "0.218.0" + "@opentelemetry/api-logs" "0.219.0" import-in-the-middle "^3.0.0" require-in-the-middle "^8.0.0" -"@opentelemetry/otlp-exporter-base@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.218.0.tgz#f33e3217ce568756baa132fabe30f0c9345db086" - integrity sha512-ZwqpkNL5W7RyGJPDZ9g06DvKp8KFTWPJPN12anpMQYSKpTSU0z3EIZuPq9vPGpS8siFyOqDYDAuCwlNO9FqgbA== +"@opentelemetry/otlp-exporter-base@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.219.0.tgz#68f4908f45f6df577d8e1c5b42761645f01cffc5" + integrity sha512-zvIxQX/AZUVKDU+hCuYx+7UkiP7GRdnk1ZbFQRYzHvYp47cAWR4j3IhoPhV9KaeXEv2xdGq3IA6PnpzDmLcmSA== dependencies: - "@opentelemetry/core" "2.7.1" - "@opentelemetry/otlp-transformer" "0.218.0" + "@opentelemetry/core" "2.8.0" + "@opentelemetry/otlp-transformer" "0.219.0" -"@opentelemetry/otlp-grpc-exporter-base@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.218.0.tgz#dc5a1fec716245d84dc4167de9b1c607e07fb6a7" - integrity sha512-H/lCGJ536N98VpYJOaWTQOkv4Dx6TnmStK6Rqfu1W7KkFbPAx04hjdYEMZF/YbnHzPUSIK4kM6OE2GKGBTpV9A== +"@opentelemetry/otlp-grpc-exporter-base@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.219.0.tgz#626713dc38a8879cbc95304832971e6daa889248" + integrity sha512-iIk/s8QQu39zpTrRRmsW/Eg3SE2+Hg8tLWepr2FLRgmwUpNd0IpCTLJEHJ77hpt4hgIS8MAh44UYI4xQPZwWlw== dependencies: "@grpc/grpc-js" "^1.14.3" - "@opentelemetry/core" "2.7.1" - "@opentelemetry/otlp-exporter-base" "0.218.0" - "@opentelemetry/otlp-transformer" "0.218.0" - -"@opentelemetry/otlp-transformer@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.218.0.tgz#6784d0ddd13803c63a1b24072606c02fc21b9071" - integrity sha512-CFaKH87WAzjuJ4awowTTLzUvMfaRfiOFG5+qm5S5ncyalRtN4ecQ+YmuANJSCrVPuvZFEkUgKhBPBndxi3rHsQ== - dependencies: - "@opentelemetry/api-logs" "0.218.0" - "@opentelemetry/core" "2.7.1" - "@opentelemetry/resources" "2.7.1" - "@opentelemetry/sdk-logs" "0.218.0" - "@opentelemetry/sdk-metrics" "2.7.1" - "@opentelemetry/sdk-trace-base" "2.7.1" - -"@opentelemetry/propagator-b3@2.7.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-b3/-/propagator-b3-2.7.1.tgz#107fe3e16d0728c489edbad221c402ee197514a4" - integrity sha512-RJid6E2CKyeGfKBzXKF21ejabGMHypFkPAh3qZ+NvI+SGjuIye79t3PmiqcDgtRzdKH6ynXzbfslQ8DfpRUg2A== - dependencies: - "@opentelemetry/core" "2.7.1" - -"@opentelemetry/propagator-jaeger@2.7.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.7.1.tgz#e8ebf3f6c0e9aa525cf041893425889cf3e69125" - integrity sha512-KMjVBHzP4N60bOzxja76M1F1hZZ43lGPga5ix+mkv9+kk1nx9SbkxSvJsMbuVUxdPQmsPTqGShmhN8ulrMOg6Q== - dependencies: - "@opentelemetry/core" "2.7.1" - -"@opentelemetry/resources@2.7.1", "@opentelemetry/resources@^2.7.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-2.7.1.tgz#3b2a9179f6119bb1f2cddefe41ba9b2855504a5d" - integrity sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ== - dependencies: - "@opentelemetry/core" "2.7.1" + "@opentelemetry/core" "2.8.0" + "@opentelemetry/otlp-exporter-base" "0.219.0" + "@opentelemetry/otlp-transformer" "0.219.0" + +"@opentelemetry/otlp-transformer@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.219.0.tgz#86305b29f564220666f6e410b7eded57bb5e6c3a" + integrity sha512-aaYKAyXhw9VchKZVGOopD3Gw/kPsyrX2c6IQ0AW32mTjqmZOh5Y6Gf5OYqTNqVktAeBjmFinhyFaCwW6GYK9YQ== + dependencies: + "@opentelemetry/api-logs" "0.219.0" + "@opentelemetry/core" "2.8.0" + "@opentelemetry/resources" "2.8.0" + "@opentelemetry/sdk-logs" "0.219.0" + "@opentelemetry/sdk-metrics" "2.8.0" + "@opentelemetry/sdk-trace-base" "2.8.0" + +"@opentelemetry/propagator-b3@2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-b3/-/propagator-b3-2.8.0.tgz#d8dadd951831cc96bc2e44eadf04d2b3d1a9b320" + integrity sha512-SazlvuSKi5533rPHTW2TwBwdMakhjZST4SYs0YauuvfGDkT13KbG1gJS75hV0uWVeevhtVP9sAIlaZLTHdSbMg== + dependencies: + "@opentelemetry/core" "2.8.0" + +"@opentelemetry/propagator-jaeger@2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.8.0.tgz#b8866476fd4a3953dd660a6ab5dc8e2b618dd9e8" + integrity sha512-Xnz9zZvvQzUw+9DrOn0MomR7BxFCkA2pcfXBQuHC28ndJpSbjLs7knzYb05kw5SyCjSsEWombkZMgGcJSk8JVg== + dependencies: + "@opentelemetry/core" "2.8.0" + +"@opentelemetry/resources@2.8.0", "@opentelemetry/resources@^2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-2.8.0.tgz#9bcb658ab6254f33099f4a95544b40d6f53cc946" + integrity sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg== + dependencies: + "@opentelemetry/core" "2.8.0" "@opentelemetry/semantic-conventions" "^1.29.0" -"@opentelemetry/sdk-logs@0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.218.0.tgz#78886fe300b82802cee9963208b2af326b928af5" - integrity sha512-QvnNdugatFTVCJXH0Mcu7GOOJSylA9j127kIezOE4YwTI4YbowRons2K4WZTv5FMS8T4q9P0NdaRHdkSmeAIag== +"@opentelemetry/sdk-logs@0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.219.0.tgz#002433237908d24fa9e7f17eb4963f25f03d655c" + integrity sha512-s6lTKRakaPClvKoWHRChxnXjDMkM/TQ30ff78jN6EBGf7MI7VzANE5PU3f4z9qDUudWjvZjOLHG0rBnBKYvoXA== dependencies: - "@opentelemetry/api-logs" "0.218.0" - "@opentelemetry/core" "2.7.1" - "@opentelemetry/resources" "2.7.1" + "@opentelemetry/api-logs" "0.219.0" + "@opentelemetry/core" "2.8.0" + "@opentelemetry/resources" "2.8.0" "@opentelemetry/semantic-conventions" "^1.29.0" -"@opentelemetry/sdk-metrics@2.7.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-2.7.1.tgz#b713f69dd67933ecc9c61357f1d452cdc9f4e281" - integrity sha512-MpDJdkiFDs3Pm1RHO3KByuZbuBdJEXEAkiC0+yJdsZGVCdf1RpHR6n+LHDcS7ffmfrt5kVCzJSCfm4z2C7v0uQ== - dependencies: - "@opentelemetry/core" "2.7.1" - "@opentelemetry/resources" "2.7.1" - -"@opentelemetry/sdk-node@^0.218.0": - version "0.218.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-node/-/sdk-node-0.218.0.tgz#cf8bdc0c993387189c7c474612e0f801505feb97" - integrity sha512-tPMjHrLV5gsfNdYqoRHjeGbCAZBXXD9c1Qo/2ut7VwnUABDNh76xNxrT0SEhkIIJuCN45bbN1vZnYL1gY0IkOg== - dependencies: - "@opentelemetry/api-logs" "0.218.0" - "@opentelemetry/configuration" "0.218.0" - "@opentelemetry/context-async-hooks" "2.7.1" - "@opentelemetry/core" "2.7.1" - "@opentelemetry/exporter-logs-otlp-grpc" "0.218.0" - "@opentelemetry/exporter-logs-otlp-http" "0.218.0" - "@opentelemetry/exporter-logs-otlp-proto" "0.218.0" - "@opentelemetry/exporter-metrics-otlp-grpc" "0.218.0" - "@opentelemetry/exporter-metrics-otlp-http" "0.218.0" - "@opentelemetry/exporter-metrics-otlp-proto" "0.218.0" - "@opentelemetry/exporter-prometheus" "0.218.0" - "@opentelemetry/exporter-trace-otlp-grpc" "0.218.0" - "@opentelemetry/exporter-trace-otlp-http" "0.218.0" - "@opentelemetry/exporter-trace-otlp-proto" "0.218.0" - "@opentelemetry/exporter-zipkin" "2.7.1" - "@opentelemetry/instrumentation" "0.218.0" - "@opentelemetry/otlp-exporter-base" "0.218.0" - "@opentelemetry/propagator-b3" "2.7.1" - "@opentelemetry/propagator-jaeger" "2.7.1" - "@opentelemetry/resources" "2.7.1" - "@opentelemetry/sdk-logs" "0.218.0" - "@opentelemetry/sdk-metrics" "2.7.1" - "@opentelemetry/sdk-trace-base" "2.7.1" - "@opentelemetry/sdk-trace-node" "2.7.1" +"@opentelemetry/sdk-metrics@2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-2.8.0.tgz#c3f908d9e7e02fb855673fcfd4b298ce279e61f1" + integrity sha512-UDBGaj6W0Rgy5rTTaoxs8gVGF/aGkAKyjurJv7se6wjRxJu7FoquTLT/vt54DZfo4crbprYfhX/SOK9+BPw1qg== + dependencies: + "@opentelemetry/core" "2.8.0" + "@opentelemetry/resources" "2.8.0" + +"@opentelemetry/sdk-node@^0.219.0": + version "0.219.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-node/-/sdk-node-0.219.0.tgz#a269bfbe122249bcc2027b67cfdcca4bded254b5" + integrity sha512-NWLpWLEb8gV3+JBHYoIrktbM385wyHpRJoh3J/4Q52d4PR+AlPMNGJT3DzBUrDSUEVbKAXoHR+EDAPxtiNcj8g== + dependencies: + "@opentelemetry/api-logs" "0.219.0" + "@opentelemetry/configuration" "0.219.0" + "@opentelemetry/context-async-hooks" "2.8.0" + "@opentelemetry/core" "2.8.0" + "@opentelemetry/exporter-logs-otlp-grpc" "0.219.0" + "@opentelemetry/exporter-logs-otlp-http" "0.219.0" + "@opentelemetry/exporter-logs-otlp-proto" "0.219.0" + "@opentelemetry/exporter-metrics-otlp-grpc" "0.219.0" + "@opentelemetry/exporter-metrics-otlp-http" "0.219.0" + "@opentelemetry/exporter-metrics-otlp-proto" "0.219.0" + "@opentelemetry/exporter-prometheus" "0.219.0" + "@opentelemetry/exporter-trace-otlp-grpc" "0.219.0" + "@opentelemetry/exporter-trace-otlp-http" "0.219.0" + "@opentelemetry/exporter-trace-otlp-proto" "0.219.0" + "@opentelemetry/exporter-zipkin" "2.8.0" + "@opentelemetry/instrumentation" "0.219.0" + "@opentelemetry/otlp-exporter-base" "0.219.0" + "@opentelemetry/otlp-grpc-exporter-base" "0.219.0" + "@opentelemetry/propagator-b3" "2.8.0" + "@opentelemetry/propagator-jaeger" "2.8.0" + "@opentelemetry/resources" "2.8.0" + "@opentelemetry/sdk-logs" "0.219.0" + "@opentelemetry/sdk-metrics" "2.8.0" + "@opentelemetry/sdk-trace-base" "2.8.0" + "@opentelemetry/sdk-trace-node" "2.8.0" "@opentelemetry/semantic-conventions" "^1.29.0" -"@opentelemetry/sdk-trace-base@2.7.1", "@opentelemetry/sdk-trace-base@^2.7.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.7.1.tgz#9160c3af9ef2219c26563abd136e22fb7d19b34f" - integrity sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw== +"@opentelemetry/sdk-trace-base@2.8.0", "@opentelemetry/sdk-trace-base@^2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.8.0.tgz#ec9c1d69e2e6fba256c9df0c8e8d67d42386d52b" + integrity sha512-mhU4jp+vW0mGbFRd+GeXHvmfA4aDqWjBjLC3pE5XMpLs0IE2ryYb019Ts2AQrOq67gaTF25D91+fgvEHDZEnuQ== dependencies: - "@opentelemetry/core" "2.7.1" - "@opentelemetry/resources" "2.7.1" + "@opentelemetry/core" "2.8.0" + "@opentelemetry/resources" "2.8.0" "@opentelemetry/semantic-conventions" "^1.29.0" -"@opentelemetry/sdk-trace-node@2.7.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.7.1.tgz#54dedb8e77fa51a6d02fc2192097739266c82168" - integrity sha512-pCpQxU68lV+I9s9svqMyVu5iHdDDUnqUpSxqwyCU8A9ejEsSnMPCbearwsUO4yk08ZJzAIUCFuReMdVQvHrdvg== +"@opentelemetry/sdk-trace-node@2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.8.0.tgz#cbf68f817a15bf4ca5d9ff9fb60ef3a73f61337d" + integrity sha512-nZt9OGufioAc3AfoLTqA9bsAeaMJAictYDdI2VcNQ+PmT+3rfKjAZDZvgPfd8VPX0O5Bw1hdQF6kDK8VSpZiWg== dependencies: - "@opentelemetry/context-async-hooks" "2.7.1" - "@opentelemetry/core" "2.7.1" - "@opentelemetry/sdk-trace-base" "2.7.1" + "@opentelemetry/context-async-hooks" "2.8.0" + "@opentelemetry/core" "2.8.0" + "@opentelemetry/sdk-trace-base" "2.8.0" "@opentelemetry/semantic-conventions@^1.29.0": version "1.41.1" @@ -4533,9 +4534,9 @@ arraybuffer.prototype.slice@^1.0.4: optionalDependencies: ioctl "^2.0.2" -"arsenal@git+https://github.com/scality/arsenal#8.4.7": - version "8.4.7" - resolved "git+https://github.com/scality/arsenal#096cb33f1092b35113a11521bbbb62ef615aed79" +"arsenal@git+https://github.com/scality/arsenal#8.5.0": + version "8.5.0" + resolved "git+https://github.com/scality/arsenal#016072dac337eb64d602f40588cd6c22cf185625" dependencies: "@aws-sdk/client-kms" "^3.975.0" "@aws-sdk/client-s3" "^3.975.0" @@ -4544,7 +4545,7 @@ arraybuffer.prototype.slice@^1.0.4: "@azure/identity" "^4.13.0" "@azure/storage-blob" "^12.31.0" "@js-sdsl/ordered-set" "^4.4.2" - "@opentelemetry/api" "^1.9.0" + "@opentelemetry/api" "^1.9.1" "@scality/hdclient" "^1.3.2" "@smithy/node-http-handler" "^4.3.0" "@smithy/protocol-http" "^5.3.5" @@ -4576,10 +4577,10 @@ arraybuffer.prototype.slice@^1.0.4: werelogs scality/werelogs#8.2.2 xml2js "^0.6.2" optionalDependencies: - "@opentelemetry/exporter-trace-otlp-http" "^0.218.0" - "@opentelemetry/resources" "^2.7.1" - "@opentelemetry/sdk-node" "^0.218.0" - "@opentelemetry/sdk-trace-base" "^2.7.1" + "@opentelemetry/exporter-trace-otlp-http" "^0.219.0" + "@opentelemetry/resources" "^2.8.0" + "@opentelemetry/sdk-node" "^0.219.0" + "@opentelemetry/sdk-trace-base" "^2.8.0" ioctl "^2.0.2" assert-plus@1.0.0, assert-plus@^1.0.0: