node_modules ignore

This commit is contained in:
2025-05-08 23:43:47 +02:00
parent e19d52f172
commit 4574544c9f
65041 changed files with 10593536 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
/// <reference types="node" />
import { Writable } from 'stream';
import type { Core, Struct } from '@strapi/types';
import type { IDestinationProvider, IMetadata, ProviderType, Transaction } from '../../../../types';
import type { IDiagnosticReporter } from '../../../utils/diagnostic';
import { restore } from './strategies';
export declare const VALID_CONFLICT_STRATEGIES: string[];
export declare const DEFAULT_CONFLICT_STRATEGY = "restore";
export interface ILocalStrapiDestinationProviderOptions {
getStrapi(): Core.Strapi | Promise<Core.Strapi>;
autoDestroy?: boolean;
restore?: restore.IRestoreOptions;
strategy: 'restore';
}
declare class LocalStrapiDestinationProvider implements IDestinationProvider {
#private;
name: string;
type: ProviderType;
options: ILocalStrapiDestinationProviderOptions;
strapi?: Core.Strapi;
transaction?: Transaction;
uploadsBackupDirectoryName: string;
onWarning?: ((message: string) => void) | undefined;
constructor(options: ILocalStrapiDestinationProviderOptions);
bootstrap(diagnostics?: IDiagnosticReporter): Promise<void>;
close(): Promise<void>;
rollback(): Promise<void>;
beforeTransfer(): Promise<void>;
getMetadata(): IMetadata;
getSchemas(): Record<string, Struct.Schema>;
createEntitiesWriteStream(): Writable;
createAssetsWriteStream(): Promise<Writable>;
createConfigurationWriteStream(): Promise<Writable>;
createLinksWriteStream(): Promise<Writable>;
}
export declare const createLocalStrapiDestinationProvider: (options: ILocalStrapiDestinationProviderOptions) => LocalStrapiDestinationProvider;
export {};
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/strapi/providers/local-destination/index.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAY,MAAM,QAAQ,CAAC;AAI5C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAEV,oBAAoB,EAEpB,SAAS,EACT,YAAY,EACZ,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AASvC,eAAO,MAAM,yBAAyB,UAAc,CAAC;AACrD,eAAO,MAAM,yBAAyB,YAAY,CAAC;AAEnD,MAAM,WAAW,sCAAsC;IACrD,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IAClC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,cAAM,8BAA+B,YAAW,oBAAoB;;IAClE,IAAI,SAA+B;IAEnC,IAAI,EAAE,YAAY,CAAiB;IAEnC,OAAO,EAAE,sCAAsC,CAAC;IAEhD,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC;IAErB,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B,0BAA0B,EAAE,MAAM,CAAC;IAEnC,SAAS,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;gBASxC,OAAO,EAAE,sCAAsC;IAMrD,SAAS,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC3D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmEtB,QAAQ;IAMR,cAAc;IAkBpB,WAAW,IAAI,SAAS;IAcxB,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;IAY3C,yBAAyB,IAAI,QAAQ;IA2F/B,uBAAuB,IAAI,OAAO,CAAC,QAAQ,CAAC;IA2F5C,8BAA8B,IAAI,OAAO,CAAC,QAAQ,CAAC;IAgBnD,sBAAsB,IAAI,OAAO,CAAC,QAAQ,CAAC;CAmBlD;AAED,eAAO,MAAM,oCAAoC,YACtC,sCAAsC,mCAGhD,CAAC"}

View File

@@ -0,0 +1,419 @@
'use strict';
var stream = require('stream');
var path = require('path');
var fse = require('fs-extra');
var index = require('./strategies/restore/index.js');
require('crypto');
require('lodash/fp');
var schema = require('../../../utils/schema.js');
var transaction = require('../../../utils/transaction.js');
require('events');
var providers = require('../../../errors/providers.js');
var providers$1 = require('../../../utils/providers.js');
var entities = require('./strategies/restore/entities.js');
var configuration = require('./strategies/restore/configuration.js');
var links = require('./strategies/restore/links.js');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var fse__namespace = /*#__PURE__*/_interopNamespaceDefault(fse);
function _class_private_field_loose_base(receiver, privateKey) {
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
throw new TypeError("attempted to use private field on non-instance");
}
return receiver;
}
var id = 0;
function _class_private_field_loose_key(name) {
return "__private_" + id++ + "_" + name;
}
const VALID_CONFLICT_STRATEGIES = [
'restore'
];
const DEFAULT_CONFLICT_STRATEGY = 'restore';
var _diagnostics = /*#__PURE__*/ _class_private_field_loose_key("_diagnostics"), /**
* The entities mapper is used to map old entities to their new IDs
*/ _entitiesMapper = /*#__PURE__*/ _class_private_field_loose_key("_entitiesMapper"), // TODO: either move this to restore strategy, or restore strategy should given access to these instead of repeating the logic possibly in a different way
_areAssetsIncluded = /*#__PURE__*/ _class_private_field_loose_key("_areAssetsIncluded"), _isContentTypeIncluded = /*#__PURE__*/ _class_private_field_loose_key("_isContentTypeIncluded"), _reportInfo = /*#__PURE__*/ _class_private_field_loose_key("_reportInfo"), _validateOptions = /*#__PURE__*/ _class_private_field_loose_key("_validateOptions"), _deleteFromRestoreOptions = /*#__PURE__*/ _class_private_field_loose_key("_deleteFromRestoreOptions"), _deleteAllAssets = /*#__PURE__*/ _class_private_field_loose_key("_deleteAllAssets"), _handleAssetsBackup = /*#__PURE__*/ _class_private_field_loose_key("_handleAssetsBackup"), _removeAssetsBackup = /*#__PURE__*/ _class_private_field_loose_key("_removeAssetsBackup");
class LocalStrapiDestinationProvider {
async bootstrap(diagnostics) {
_class_private_field_loose_base(this, _diagnostics)[_diagnostics] = diagnostics;
_class_private_field_loose_base(this, _validateOptions)[_validateOptions]();
this.strapi = await this.options.getStrapi();
if (!this.strapi) {
throw new providers.ProviderInitializationError('Could not access local strapi');
}
this.strapi.db.lifecycles.disable();
this.transaction = transaction.createTransaction(this.strapi);
}
async close() {
const { autoDestroy } = this.options;
providers$1.assertValidStrapi(this.strapi);
this.transaction?.end();
this.strapi.db.lifecycles.enable();
// Basically `!== false` but more deterministic
if (autoDestroy === undefined || autoDestroy === true) {
await this.strapi?.destroy();
}
}
async rollback() {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('Rolling back transaction');
await this.transaction?.rollback();
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('Rolled back transaction');
}
async beforeTransfer() {
if (!this.strapi) {
throw new Error('Strapi instance not found');
}
await this.transaction?.attach(async (trx)=>{
try {
if (this.options.strategy === 'restore') {
await _class_private_field_loose_base(this, _handleAssetsBackup)[_handleAssetsBackup]();
await _class_private_field_loose_base(this, _deleteAllAssets)[_deleteAllAssets](trx);
await _class_private_field_loose_base(this, _deleteFromRestoreOptions)[_deleteFromRestoreOptions]();
}
} catch (error) {
throw new Error(`restore failed ${error}`);
}
});
}
getMetadata() {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('getting metadata');
providers$1.assertValidStrapi(this.strapi, 'Not able to get Schemas');
const strapiVersion = this.strapi.config.get('info.strapi');
const createdAt = new Date().toISOString();
return {
createdAt,
strapi: {
version: strapiVersion
}
};
}
getSchemas() {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('getting schema');
providers$1.assertValidStrapi(this.strapi, 'Not able to get Schemas');
const schemas = schema.schemasToValidJSON({
...this.strapi.contentTypes,
...this.strapi.components
});
return schema.mapSchemasValues(schemas);
}
createEntitiesWriteStream() {
providers$1.assertValidStrapi(this.strapi, 'Not able to import entities');
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('creating entities stream');
const { strategy } = this.options;
const updateMappingTable = (type, oldID, newID)=>{
if (!_class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper][type]) {
_class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper][type] = {};
}
Object.assign(_class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper][type], {
[oldID]: newID
});
};
if (strategy === 'restore') {
return entities.createEntitiesWriteStream({
strapi: this.strapi,
updateMappingTable,
transaction: this.transaction
});
}
throw new providers.ProviderValidationError(`Invalid strategy ${this.options.strategy}`, {
check: 'strategy',
strategy: this.options.strategy,
validStrategies: VALID_CONFLICT_STRATEGIES
});
}
// TODO: Move this logic to the restore strategy
async createAssetsWriteStream() {
providers$1.assertValidStrapi(this.strapi, 'Not able to stream Assets');
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('creating assets write stream');
if (!_class_private_field_loose_base(this, _areAssetsIncluded)[_areAssetsIncluded]()) {
throw new providers.ProviderTransferError('Attempting to transfer assets when `assets` is not set in restore options');
}
const removeAssetsBackup = _class_private_field_loose_base(this, _removeAssetsBackup)[_removeAssetsBackup].bind(this);
const strapi = this.strapi;
const transaction = this.transaction;
const fileEntitiesMapper = _class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper]['plugin::upload.file'];
const restoreMediaEntitiesContent = _class_private_field_loose_base(this, _isContentTypeIncluded)[_isContentTypeIncluded]('plugin::upload.file');
return new stream.Writable({
objectMode: true,
async final (next) {
// Delete the backup folder
await removeAssetsBackup();
next();
},
async write (chunk, _encoding, callback) {
await transaction?.attach(async ()=>{
const uploadData = {
...chunk.metadata,
stream: stream.Readable.from(chunk.stream),
buffer: chunk?.buffer
};
const provider = strapi.config.get('plugin::upload').provider;
const fileId = fileEntitiesMapper?.[uploadData.id];
if (!fileId) {
return callback(new Error(`File ID not found for ID: ${uploadData.id}`));
}
try {
await strapi.plugin('upload').provider.uploadStream(uploadData);
// if we're not supposed to transfer the associated entities, stop here
if (!restoreMediaEntitiesContent) {
return callback();
}
// Files formats are stored within the parent file entity
if (uploadData?.type) {
const entry = await strapi.db.query('plugin::upload.file').findOne({
where: {
id: fileId
}
});
if (!entry) {
throw new Error('file not found');
}
const specificFormat = entry?.formats?.[uploadData.type];
if (specificFormat) {
specificFormat.url = uploadData.url;
}
await strapi.db.query('plugin::upload.file').update({
where: {
id: entry.id
},
data: {
formats: entry.formats,
provider
}
});
return callback();
}
const entry = await strapi.db.query('plugin::upload.file').findOne({
where: {
id: fileId
}
});
if (!entry) {
throw new Error('file not found');
}
entry.url = uploadData.url;
await strapi.db.query('plugin::upload.file').update({
where: {
id: entry.id
},
data: {
url: entry.url,
provider
}
});
return callback();
} catch (error) {
return callback(new Error(`Error while uploading asset ${chunk.filename} ${error}`));
}
});
}
});
}
async createConfigurationWriteStream() {
providers$1.assertValidStrapi(this.strapi, 'Not able to stream Configurations');
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('creating configuration write stream');
const { strategy } = this.options;
if (strategy === 'restore') {
return configuration.createConfigurationWriteStream(this.strapi, this.transaction);
}
throw new providers.ProviderValidationError(`Invalid strategy ${strategy}`, {
check: 'strategy',
strategy,
validStrategies: VALID_CONFLICT_STRATEGIES
});
}
async createLinksWriteStream() {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('creating links write stream');
if (!this.strapi) {
throw new Error('Not able to stream links. Strapi instance not found');
}
const { strategy } = this.options;
const mapID = (uid, id)=>_class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper][uid]?.[id];
if (strategy === 'restore') {
return links.createLinksWriteStream(mapID, this.strapi, this.transaction, this.onWarning);
}
throw new providers.ProviderValidationError(`Invalid strategy ${strategy}`, {
check: 'strategy',
strategy,
validStrategies: VALID_CONFLICT_STRATEGIES
});
}
constructor(options){
Object.defineProperty(this, _reportInfo, {
value: reportInfo
});
Object.defineProperty(this, _validateOptions, {
value: validateOptions
});
Object.defineProperty(this, _deleteFromRestoreOptions, {
value: deleteFromRestoreOptions
});
Object.defineProperty(this, _deleteAllAssets, {
value: deleteAllAssets
});
Object.defineProperty(this, _handleAssetsBackup, {
value: handleAssetsBackup
});
Object.defineProperty(this, _removeAssetsBackup, {
value: removeAssetsBackup
});
Object.defineProperty(this, _diagnostics, {
writable: true,
value: void 0
});
Object.defineProperty(this, _entitiesMapper, {
writable: true,
value: void 0
});
Object.defineProperty(this, _areAssetsIncluded, {
writable: true,
value: void 0
});
Object.defineProperty(this, _isContentTypeIncluded, {
writable: true,
value: void 0
});
this.name = 'destination::local-strapi';
this.type = 'destination';
_class_private_field_loose_base(this, _areAssetsIncluded)[_areAssetsIncluded] = ()=>{
return this.options.restore?.assets;
};
_class_private_field_loose_base(this, _isContentTypeIncluded)[_isContentTypeIncluded] = (type)=>{
const notIncluded = this.options.restore?.entities?.include && !this.options.restore?.entities?.include?.includes(type);
const excluded = this.options.restore?.entities?.exclude && this.options.restore?.entities.exclude.includes(type);
return !excluded && !notIncluded;
};
this.options = options;
_class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper] = {};
this.uploadsBackupDirectoryName = `uploads_backup_${Date.now()}`;
}
}
function reportInfo(message) {
_class_private_field_loose_base(this, _diagnostics)[_diagnostics]?.report({
details: {
createdAt: new Date(),
message,
origin: 'local-destination-provider'
},
kind: 'info'
});
}
function validateOptions() {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('validating options');
if (!VALID_CONFLICT_STRATEGIES.includes(this.options.strategy)) {
throw new providers.ProviderValidationError(`Invalid strategy ${this.options.strategy}`, {
check: 'strategy',
strategy: this.options.strategy,
validStrategies: VALID_CONFLICT_STRATEGIES
});
}
// require restore options when using restore
if (this.options.strategy === 'restore' && !this.options.restore) {
throw new providers.ProviderValidationError('Missing restore options');
}
}
async function deleteFromRestoreOptions() {
providers$1.assertValidStrapi(this.strapi);
if (!this.options.restore) {
throw new providers.ProviderValidationError('Missing restore options');
}
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('deleting record ');
return index.deleteRecords(this.strapi, this.options.restore);
}
async function deleteAllAssets(trx) {
providers$1.assertValidStrapi(this.strapi);
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('deleting all assets');
// if we're not restoring files, don't touch the files
if (!_class_private_field_loose_base(this, _areAssetsIncluded)[_areAssetsIncluded]()) {
return;
}
const stream = this.strapi.db// Create a query builder instance (default type is 'select')
.queryBuilder('plugin::upload.file')// Fetch all columns
.select('*')// Attach the transaction
.transacting(trx)// Get a readable stream
.stream();
// TODO use bulk delete when exists in providers
for await (const file of stream){
await this.strapi.plugin('upload').provider.delete(file);
if (file.formats) {
for (const fileFormat of Object.values(file.formats)){
await this.strapi.plugin('upload').provider.delete(fileFormat);
}
}
}
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('deleted all assets');
}
async function handleAssetsBackup() {
providers$1.assertValidStrapi(this.strapi, 'Not able to create the assets backup');
// if we're not restoring assets, don't back them up because they won't be touched
if (!_class_private_field_loose_base(this, _areAssetsIncluded)[_areAssetsIncluded]()) {
return;
}
if (this.strapi.config.get('plugin::upload').provider === 'local') {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('creating assets backup directory');
const assetsDirectory = path.join(this.strapi.dirs.static.public, 'uploads');
const backupDirectory = path.join(this.strapi.dirs.static.public, this.uploadsBackupDirectoryName);
try {
// Check access before attempting to do anything
await fse__namespace.access(assetsDirectory, // eslint-disable-next-line no-bitwise
fse__namespace.constants.W_OK | fse__namespace.constants.R_OK | fse__namespace.constants.F_OK);
// eslint-disable-next-line no-bitwise
await fse__namespace.access(path.join(assetsDirectory, '..'), fse__namespace.constants.W_OK | fse__namespace.constants.R_OK);
await fse__namespace.move(assetsDirectory, backupDirectory);
await fse__namespace.mkdir(assetsDirectory);
// Create a .gitkeep file to ensure the directory is not empty
await fse__namespace.outputFile(path.join(assetsDirectory, '.gitkeep'), '');
_class_private_field_loose_base(this, _reportInfo)[_reportInfo](`created assets backup directory ${backupDirectory}`);
} catch (err) {
throw new providers.ProviderTransferError('The backup folder for the assets could not be created inside the public folder. Please ensure Strapi has write permissions on the public directory', {
code: 'ASSETS_DIRECTORY_ERR'
});
}
return backupDirectory;
}
}
async function removeAssetsBackup() {
providers$1.assertValidStrapi(this.strapi, 'Not able to remove Assets');
// if we're not restoring assets, don't back them up because they won't be touched
if (!_class_private_field_loose_base(this, _areAssetsIncluded)[_areAssetsIncluded]()) {
return;
}
// TODO: this should catch all thrown errors and bubble it up to engine so it can be reported as a non-fatal diagnostic message telling the user they may need to manually delete assets
if (this.strapi.config.get('plugin::upload').provider === 'local') {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('removing assets backup');
providers$1.assertValidStrapi(this.strapi);
const backupDirectory = path.join(this.strapi.dirs.static.public, this.uploadsBackupDirectoryName);
await fse__namespace.rm(backupDirectory, {
recursive: true,
force: true
});
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('successfully removed assets backup');
}
}
const createLocalStrapiDestinationProvider = (options)=>{
return new LocalStrapiDestinationProvider(options);
};
exports.DEFAULT_CONFLICT_STRATEGY = DEFAULT_CONFLICT_STRATEGY;
exports.VALID_CONFLICT_STRATEGIES = VALID_CONFLICT_STRATEGIES;
exports.createLocalStrapiDestinationProvider = createLocalStrapiDestinationProvider;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,396 @@
import { Writable, Readable } from 'stream';
import path from 'path';
import * as fse from 'fs-extra';
import { deleteRecords } from './strategies/restore/index.mjs';
import 'crypto';
import 'lodash/fp';
import { schemasToValidJSON, mapSchemasValues } from '../../../utils/schema.mjs';
import { createTransaction } from '../../../utils/transaction.mjs';
import 'events';
import { ProviderInitializationError, ProviderValidationError, ProviderTransferError } from '../../../errors/providers.mjs';
import { assertValidStrapi } from '../../../utils/providers.mjs';
import { createEntitiesWriteStream } from './strategies/restore/entities.mjs';
import { createConfigurationWriteStream } from './strategies/restore/configuration.mjs';
import { createLinksWriteStream } from './strategies/restore/links.mjs';
function _class_private_field_loose_base(receiver, privateKey) {
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
throw new TypeError("attempted to use private field on non-instance");
}
return receiver;
}
var id = 0;
function _class_private_field_loose_key(name) {
return "__private_" + id++ + "_" + name;
}
const VALID_CONFLICT_STRATEGIES = [
'restore'
];
const DEFAULT_CONFLICT_STRATEGY = 'restore';
var _diagnostics = /*#__PURE__*/ _class_private_field_loose_key("_diagnostics"), /**
* The entities mapper is used to map old entities to their new IDs
*/ _entitiesMapper = /*#__PURE__*/ _class_private_field_loose_key("_entitiesMapper"), // TODO: either move this to restore strategy, or restore strategy should given access to these instead of repeating the logic possibly in a different way
_areAssetsIncluded = /*#__PURE__*/ _class_private_field_loose_key("_areAssetsIncluded"), _isContentTypeIncluded = /*#__PURE__*/ _class_private_field_loose_key("_isContentTypeIncluded"), _reportInfo = /*#__PURE__*/ _class_private_field_loose_key("_reportInfo"), _validateOptions = /*#__PURE__*/ _class_private_field_loose_key("_validateOptions"), _deleteFromRestoreOptions = /*#__PURE__*/ _class_private_field_loose_key("_deleteFromRestoreOptions"), _deleteAllAssets = /*#__PURE__*/ _class_private_field_loose_key("_deleteAllAssets"), _handleAssetsBackup = /*#__PURE__*/ _class_private_field_loose_key("_handleAssetsBackup"), _removeAssetsBackup = /*#__PURE__*/ _class_private_field_loose_key("_removeAssetsBackup");
class LocalStrapiDestinationProvider {
async bootstrap(diagnostics) {
_class_private_field_loose_base(this, _diagnostics)[_diagnostics] = diagnostics;
_class_private_field_loose_base(this, _validateOptions)[_validateOptions]();
this.strapi = await this.options.getStrapi();
if (!this.strapi) {
throw new ProviderInitializationError('Could not access local strapi');
}
this.strapi.db.lifecycles.disable();
this.transaction = createTransaction(this.strapi);
}
async close() {
const { autoDestroy } = this.options;
assertValidStrapi(this.strapi);
this.transaction?.end();
this.strapi.db.lifecycles.enable();
// Basically `!== false` but more deterministic
if (autoDestroy === undefined || autoDestroy === true) {
await this.strapi?.destroy();
}
}
async rollback() {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('Rolling back transaction');
await this.transaction?.rollback();
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('Rolled back transaction');
}
async beforeTransfer() {
if (!this.strapi) {
throw new Error('Strapi instance not found');
}
await this.transaction?.attach(async (trx)=>{
try {
if (this.options.strategy === 'restore') {
await _class_private_field_loose_base(this, _handleAssetsBackup)[_handleAssetsBackup]();
await _class_private_field_loose_base(this, _deleteAllAssets)[_deleteAllAssets](trx);
await _class_private_field_loose_base(this, _deleteFromRestoreOptions)[_deleteFromRestoreOptions]();
}
} catch (error) {
throw new Error(`restore failed ${error}`);
}
});
}
getMetadata() {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('getting metadata');
assertValidStrapi(this.strapi, 'Not able to get Schemas');
const strapiVersion = this.strapi.config.get('info.strapi');
const createdAt = new Date().toISOString();
return {
createdAt,
strapi: {
version: strapiVersion
}
};
}
getSchemas() {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('getting schema');
assertValidStrapi(this.strapi, 'Not able to get Schemas');
const schemas = schemasToValidJSON({
...this.strapi.contentTypes,
...this.strapi.components
});
return mapSchemasValues(schemas);
}
createEntitiesWriteStream() {
assertValidStrapi(this.strapi, 'Not able to import entities');
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('creating entities stream');
const { strategy } = this.options;
const updateMappingTable = (type, oldID, newID)=>{
if (!_class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper][type]) {
_class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper][type] = {};
}
Object.assign(_class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper][type], {
[oldID]: newID
});
};
if (strategy === 'restore') {
return createEntitiesWriteStream({
strapi: this.strapi,
updateMappingTable,
transaction: this.transaction
});
}
throw new ProviderValidationError(`Invalid strategy ${this.options.strategy}`, {
check: 'strategy',
strategy: this.options.strategy,
validStrategies: VALID_CONFLICT_STRATEGIES
});
}
// TODO: Move this logic to the restore strategy
async createAssetsWriteStream() {
assertValidStrapi(this.strapi, 'Not able to stream Assets');
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('creating assets write stream');
if (!_class_private_field_loose_base(this, _areAssetsIncluded)[_areAssetsIncluded]()) {
throw new ProviderTransferError('Attempting to transfer assets when `assets` is not set in restore options');
}
const removeAssetsBackup = _class_private_field_loose_base(this, _removeAssetsBackup)[_removeAssetsBackup].bind(this);
const strapi = this.strapi;
const transaction = this.transaction;
const fileEntitiesMapper = _class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper]['plugin::upload.file'];
const restoreMediaEntitiesContent = _class_private_field_loose_base(this, _isContentTypeIncluded)[_isContentTypeIncluded]('plugin::upload.file');
return new Writable({
objectMode: true,
async final (next) {
// Delete the backup folder
await removeAssetsBackup();
next();
},
async write (chunk, _encoding, callback) {
await transaction?.attach(async ()=>{
const uploadData = {
...chunk.metadata,
stream: Readable.from(chunk.stream),
buffer: chunk?.buffer
};
const provider = strapi.config.get('plugin::upload').provider;
const fileId = fileEntitiesMapper?.[uploadData.id];
if (!fileId) {
return callback(new Error(`File ID not found for ID: ${uploadData.id}`));
}
try {
await strapi.plugin('upload').provider.uploadStream(uploadData);
// if we're not supposed to transfer the associated entities, stop here
if (!restoreMediaEntitiesContent) {
return callback();
}
// Files formats are stored within the parent file entity
if (uploadData?.type) {
const entry = await strapi.db.query('plugin::upload.file').findOne({
where: {
id: fileId
}
});
if (!entry) {
throw new Error('file not found');
}
const specificFormat = entry?.formats?.[uploadData.type];
if (specificFormat) {
specificFormat.url = uploadData.url;
}
await strapi.db.query('plugin::upload.file').update({
where: {
id: entry.id
},
data: {
formats: entry.formats,
provider
}
});
return callback();
}
const entry = await strapi.db.query('plugin::upload.file').findOne({
where: {
id: fileId
}
});
if (!entry) {
throw new Error('file not found');
}
entry.url = uploadData.url;
await strapi.db.query('plugin::upload.file').update({
where: {
id: entry.id
},
data: {
url: entry.url,
provider
}
});
return callback();
} catch (error) {
return callback(new Error(`Error while uploading asset ${chunk.filename} ${error}`));
}
});
}
});
}
async createConfigurationWriteStream() {
assertValidStrapi(this.strapi, 'Not able to stream Configurations');
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('creating configuration write stream');
const { strategy } = this.options;
if (strategy === 'restore') {
return createConfigurationWriteStream(this.strapi, this.transaction);
}
throw new ProviderValidationError(`Invalid strategy ${strategy}`, {
check: 'strategy',
strategy,
validStrategies: VALID_CONFLICT_STRATEGIES
});
}
async createLinksWriteStream() {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('creating links write stream');
if (!this.strapi) {
throw new Error('Not able to stream links. Strapi instance not found');
}
const { strategy } = this.options;
const mapID = (uid, id)=>_class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper][uid]?.[id];
if (strategy === 'restore') {
return createLinksWriteStream(mapID, this.strapi, this.transaction, this.onWarning);
}
throw new ProviderValidationError(`Invalid strategy ${strategy}`, {
check: 'strategy',
strategy,
validStrategies: VALID_CONFLICT_STRATEGIES
});
}
constructor(options){
Object.defineProperty(this, _reportInfo, {
value: reportInfo
});
Object.defineProperty(this, _validateOptions, {
value: validateOptions
});
Object.defineProperty(this, _deleteFromRestoreOptions, {
value: deleteFromRestoreOptions
});
Object.defineProperty(this, _deleteAllAssets, {
value: deleteAllAssets
});
Object.defineProperty(this, _handleAssetsBackup, {
value: handleAssetsBackup
});
Object.defineProperty(this, _removeAssetsBackup, {
value: removeAssetsBackup
});
Object.defineProperty(this, _diagnostics, {
writable: true,
value: void 0
});
Object.defineProperty(this, _entitiesMapper, {
writable: true,
value: void 0
});
Object.defineProperty(this, _areAssetsIncluded, {
writable: true,
value: void 0
});
Object.defineProperty(this, _isContentTypeIncluded, {
writable: true,
value: void 0
});
this.name = 'destination::local-strapi';
this.type = 'destination';
_class_private_field_loose_base(this, _areAssetsIncluded)[_areAssetsIncluded] = ()=>{
return this.options.restore?.assets;
};
_class_private_field_loose_base(this, _isContentTypeIncluded)[_isContentTypeIncluded] = (type)=>{
const notIncluded = this.options.restore?.entities?.include && !this.options.restore?.entities?.include?.includes(type);
const excluded = this.options.restore?.entities?.exclude && this.options.restore?.entities.exclude.includes(type);
return !excluded && !notIncluded;
};
this.options = options;
_class_private_field_loose_base(this, _entitiesMapper)[_entitiesMapper] = {};
this.uploadsBackupDirectoryName = `uploads_backup_${Date.now()}`;
}
}
function reportInfo(message) {
_class_private_field_loose_base(this, _diagnostics)[_diagnostics]?.report({
details: {
createdAt: new Date(),
message,
origin: 'local-destination-provider'
},
kind: 'info'
});
}
function validateOptions() {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('validating options');
if (!VALID_CONFLICT_STRATEGIES.includes(this.options.strategy)) {
throw new ProviderValidationError(`Invalid strategy ${this.options.strategy}`, {
check: 'strategy',
strategy: this.options.strategy,
validStrategies: VALID_CONFLICT_STRATEGIES
});
}
// require restore options when using restore
if (this.options.strategy === 'restore' && !this.options.restore) {
throw new ProviderValidationError('Missing restore options');
}
}
async function deleteFromRestoreOptions() {
assertValidStrapi(this.strapi);
if (!this.options.restore) {
throw new ProviderValidationError('Missing restore options');
}
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('deleting record ');
return deleteRecords(this.strapi, this.options.restore);
}
async function deleteAllAssets(trx) {
assertValidStrapi(this.strapi);
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('deleting all assets');
// if we're not restoring files, don't touch the files
if (!_class_private_field_loose_base(this, _areAssetsIncluded)[_areAssetsIncluded]()) {
return;
}
const stream = this.strapi.db// Create a query builder instance (default type is 'select')
.queryBuilder('plugin::upload.file')// Fetch all columns
.select('*')// Attach the transaction
.transacting(trx)// Get a readable stream
.stream();
// TODO use bulk delete when exists in providers
for await (const file of stream){
await this.strapi.plugin('upload').provider.delete(file);
if (file.formats) {
for (const fileFormat of Object.values(file.formats)){
await this.strapi.plugin('upload').provider.delete(fileFormat);
}
}
}
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('deleted all assets');
}
async function handleAssetsBackup() {
assertValidStrapi(this.strapi, 'Not able to create the assets backup');
// if we're not restoring assets, don't back them up because they won't be touched
if (!_class_private_field_loose_base(this, _areAssetsIncluded)[_areAssetsIncluded]()) {
return;
}
if (this.strapi.config.get('plugin::upload').provider === 'local') {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('creating assets backup directory');
const assetsDirectory = path.join(this.strapi.dirs.static.public, 'uploads');
const backupDirectory = path.join(this.strapi.dirs.static.public, this.uploadsBackupDirectoryName);
try {
// Check access before attempting to do anything
await fse.access(assetsDirectory, // eslint-disable-next-line no-bitwise
fse.constants.W_OK | fse.constants.R_OK | fse.constants.F_OK);
// eslint-disable-next-line no-bitwise
await fse.access(path.join(assetsDirectory, '..'), fse.constants.W_OK | fse.constants.R_OK);
await fse.move(assetsDirectory, backupDirectory);
await fse.mkdir(assetsDirectory);
// Create a .gitkeep file to ensure the directory is not empty
await fse.outputFile(path.join(assetsDirectory, '.gitkeep'), '');
_class_private_field_loose_base(this, _reportInfo)[_reportInfo](`created assets backup directory ${backupDirectory}`);
} catch (err) {
throw new ProviderTransferError('The backup folder for the assets could not be created inside the public folder. Please ensure Strapi has write permissions on the public directory', {
code: 'ASSETS_DIRECTORY_ERR'
});
}
return backupDirectory;
}
}
async function removeAssetsBackup() {
assertValidStrapi(this.strapi, 'Not able to remove Assets');
// if we're not restoring assets, don't back them up because they won't be touched
if (!_class_private_field_loose_base(this, _areAssetsIncluded)[_areAssetsIncluded]()) {
return;
}
// TODO: this should catch all thrown errors and bubble it up to engine so it can be reported as a non-fatal diagnostic message telling the user they may need to manually delete assets
if (this.strapi.config.get('plugin::upload').provider === 'local') {
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('removing assets backup');
assertValidStrapi(this.strapi);
const backupDirectory = path.join(this.strapi.dirs.static.public, this.uploadsBackupDirectoryName);
await fse.rm(backupDirectory, {
recursive: true,
force: true
});
_class_private_field_loose_base(this, _reportInfo)[_reportInfo]('successfully removed assets backup');
}
}
const createLocalStrapiDestinationProvider = (options)=>{
return new LocalStrapiDestinationProvider(options);
};
export { DEFAULT_CONFLICT_STRATEGY, VALID_CONFLICT_STRATEGIES, createLocalStrapiDestinationProvider };
//# sourceMappingURL=index.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export * as restore from './restore';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/strapi/providers/local-destination/strategies/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,WAAW,CAAC"}

View File

@@ -0,0 +1,7 @@
/// <reference types="node" />
import { Writable } from 'stream';
import type { Core } from '@strapi/types';
import { IConfiguration, Transaction } from '../../../../../../types';
export declare const restoreConfigs: (strapi: Core.Strapi, config: IConfiguration) => Promise<any>;
export declare const createConfigurationWriteStream: (strapi: Core.Strapi, transaction?: Transaction) => Promise<Writable>;
//# sourceMappingURL=configuration.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"configuration.d.ts","sourceRoot":"","sources":["../../../../../../src/strapi/providers/local-destination/strategies/restore/configuration.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAGlC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAmBtE,eAAO,MAAM,cAAc,WAAkB,KAAK,MAAM,UAAU,cAAc,iBAQ/E,CAAC;AAEF,eAAO,MAAM,8BAA8B,WACjC,KAAK,MAAM,gBACL,WAAW,sBAyB1B,CAAC"}

View File

@@ -0,0 +1,52 @@
'use strict';
var stream = require('stream');
var fp = require('lodash/fp');
var chalk = require('chalk');
var providers = require('../../../../../errors/providers.js');
const omitInvalidCreationAttributes = fp.omit([
'id'
]);
const restoreCoreStore = async (strapi, values)=>{
const data = omitInvalidCreationAttributes(values);
return strapi.db.query('strapi::core-store').create({
data: {
...data,
value: JSON.stringify(data.value)
}
});
};
const restoreWebhooks = async (strapi, values)=>{
const data = omitInvalidCreationAttributes(values);
return strapi.db.query('strapi::webhook').create({
data
});
};
const restoreConfigs = async (strapi, config)=>{
if (config.type === 'core-store') {
return restoreCoreStore(strapi, config.value);
}
if (config.type === 'webhook') {
return restoreWebhooks(strapi, config.value);
}
};
const createConfigurationWriteStream = async (strapi, transaction)=>{
return new stream.Writable({
objectMode: true,
async write (config, _encoding, callback) {
await transaction?.attach(async ()=>{
try {
await restoreConfigs(strapi, config);
} catch (error) {
return callback(new providers.ProviderTransferError(`Failed to import ${chalk.yellowBright(config.type)} (${chalk.greenBright(config.value.id)}`));
}
callback();
});
}
});
};
exports.createConfigurationWriteStream = createConfigurationWriteStream;
exports.restoreConfigs = restoreConfigs;
//# sourceMappingURL=configuration.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"configuration.js","sources":["../../../../../../src/strapi/providers/local-destination/strategies/restore/configuration.ts"],"sourcesContent":["import { Writable } from 'stream';\nimport { omit } from 'lodash/fp';\nimport chalk from 'chalk';\nimport type { Core } from '@strapi/types';\nimport { ProviderTransferError } from '../../../../../errors/providers';\nimport { IConfiguration, Transaction } from '../../../../../../types';\n\nconst omitInvalidCreationAttributes = omit(['id']);\n\nconst restoreCoreStore = async <T extends { value: unknown }>(strapi: Core.Strapi, values: T) => {\n const data = omitInvalidCreationAttributes(values);\n return strapi.db.query('strapi::core-store').create({\n data: {\n ...data,\n value: JSON.stringify(data.value),\n },\n });\n};\n\nconst restoreWebhooks = async <T extends { value: unknown }>(strapi: Core.Strapi, values: T) => {\n const data = omitInvalidCreationAttributes(values);\n return strapi.db.query('strapi::webhook').create({ data });\n};\n\nexport const restoreConfigs = async (strapi: Core.Strapi, config: IConfiguration) => {\n if (config.type === 'core-store') {\n return restoreCoreStore(strapi, config.value as { value: unknown });\n }\n\n if (config.type === 'webhook') {\n return restoreWebhooks(strapi, config.value as { value: unknown });\n }\n};\n\nexport const createConfigurationWriteStream = async (\n strapi: Core.Strapi,\n transaction?: Transaction\n) => {\n return new Writable({\n objectMode: true,\n async write<T extends { id: number }>(\n config: IConfiguration<T>,\n _encoding: BufferEncoding,\n callback: (error?: Error | null) => void\n ) {\n await transaction?.attach(async () => {\n try {\n await restoreConfigs(strapi, config);\n } catch (error) {\n return callback(\n new ProviderTransferError(\n `Failed to import ${chalk.yellowBright(config.type)} (${chalk.greenBright(\n config.value.id\n )}`\n )\n );\n }\n callback();\n });\n },\n });\n};\n"],"names":["omitInvalidCreationAttributes","omit","restoreCoreStore","strapi","values","data","db","query","create","value","JSON","stringify","restoreWebhooks","restoreConfigs","config","type","createConfigurationWriteStream","transaction","Writable","objectMode","write","_encoding","callback","attach","error","ProviderTransferError","chalk","yellowBright","greenBright","id"],"mappings":";;;;;;;AAOA,MAAMA,gCAAgCC,OAAK,CAAA;AAAC,IAAA;AAAK,CAAA,CAAA;AAEjD,MAAMC,gBAAAA,GAAmB,OAAqCC,MAAqBC,EAAAA,MAAAA,GAAAA;AACjF,IAAA,MAAMC,OAAOL,6BAA8BI,CAAAA,MAAAA,CAAAA;AAC3C,IAAA,OAAOD,OAAOG,EAAE,CAACC,KAAK,CAAC,oBAAA,CAAA,CAAsBC,MAAM,CAAC;QAClDH,IAAM,EAAA;AACJ,YAAA,GAAGA,IAAI;AACPI,YAAAA,KAAAA,EAAOC,IAAKC,CAAAA,SAAS,CAACN,IAAAA,CAAKI,KAAK;AAClC;AACF,KAAA,CAAA;AACF,CAAA;AAEA,MAAMG,eAAAA,GAAkB,OAAqCT,MAAqBC,EAAAA,MAAAA,GAAAA;AAChF,IAAA,MAAMC,OAAOL,6BAA8BI,CAAAA,MAAAA,CAAAA;AAC3C,IAAA,OAAOD,OAAOG,EAAE,CAACC,KAAK,CAAC,iBAAA,CAAA,CAAmBC,MAAM,CAAC;AAAEH,QAAAA;AAAK,KAAA,CAAA;AAC1D,CAAA;AAEO,MAAMQ,cAAiB,GAAA,OAAOV,MAAqBW,EAAAA,MAAAA,GAAAA;IACxD,IAAIA,MAAAA,CAAOC,IAAI,KAAK,YAAc,EAAA;QAChC,OAAOb,gBAAAA,CAAiBC,MAAQW,EAAAA,MAAAA,CAAOL,KAAK,CAAA;AAC9C;IAEA,IAAIK,MAAAA,CAAOC,IAAI,KAAK,SAAW,EAAA;QAC7B,OAAOH,eAAAA,CAAgBT,MAAQW,EAAAA,MAAAA,CAAOL,KAAK,CAAA;AAC7C;AACF;AAEO,MAAMO,8BAAiC,GAAA,OAC5Cb,MACAc,EAAAA,WAAAA,GAAAA;AAEA,IAAA,OAAO,IAAIC,eAAS,CAAA;QAClBC,UAAY,EAAA,IAAA;AACZ,QAAA,MAAMC,KACJN,CAAAA,CAAAA,MAAyB,EACzBO,SAAyB,EACzBC,QAAwC,EAAA;AAExC,YAAA,MAAML,aAAaM,MAAO,CAAA,UAAA;gBACxB,IAAI;AACF,oBAAA,MAAMV,eAAeV,MAAQW,EAAAA,MAAAA,CAAAA;AAC/B,iBAAA,CAAE,OAAOU,KAAO,EAAA;oBACd,OAAOF,QAAAA,CACL,IAAIG,+BACF,CAAA,CAAC,iBAAiB,EAAEC,KAAAA,CAAMC,YAAY,CAACb,MAAOC,CAAAA,IAAI,EAAE,EAAE,EAAEW,MAAME,WAAW,CACvEd,OAAOL,KAAK,CAACoB,EAAE,CAAA,CACf,CAAC,CAAA,CAAA;AAGT;AACAP,gBAAAA,QAAAA,EAAAA;AACF,aAAA,CAAA;AACF;AACF,KAAA,CAAA;AACF;;;;;"}

View File

@@ -0,0 +1,49 @@
import { Writable } from 'stream';
import { omit } from 'lodash/fp';
import chalk from 'chalk';
import { ProviderTransferError } from '../../../../../errors/providers.mjs';
const omitInvalidCreationAttributes = omit([
'id'
]);
const restoreCoreStore = async (strapi, values)=>{
const data = omitInvalidCreationAttributes(values);
return strapi.db.query('strapi::core-store').create({
data: {
...data,
value: JSON.stringify(data.value)
}
});
};
const restoreWebhooks = async (strapi, values)=>{
const data = omitInvalidCreationAttributes(values);
return strapi.db.query('strapi::webhook').create({
data
});
};
const restoreConfigs = async (strapi, config)=>{
if (config.type === 'core-store') {
return restoreCoreStore(strapi, config.value);
}
if (config.type === 'webhook') {
return restoreWebhooks(strapi, config.value);
}
};
const createConfigurationWriteStream = async (strapi, transaction)=>{
return new Writable({
objectMode: true,
async write (config, _encoding, callback) {
await transaction?.attach(async ()=>{
try {
await restoreConfigs(strapi, config);
} catch (error) {
return callback(new ProviderTransferError(`Failed to import ${chalk.yellowBright(config.type)} (${chalk.greenBright(config.value.id)}`));
}
callback();
});
}
});
};
export { createConfigurationWriteStream, restoreConfigs };
//# sourceMappingURL=configuration.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"configuration.mjs","sources":["../../../../../../src/strapi/providers/local-destination/strategies/restore/configuration.ts"],"sourcesContent":["import { Writable } from 'stream';\nimport { omit } from 'lodash/fp';\nimport chalk from 'chalk';\nimport type { Core } from '@strapi/types';\nimport { ProviderTransferError } from '../../../../../errors/providers';\nimport { IConfiguration, Transaction } from '../../../../../../types';\n\nconst omitInvalidCreationAttributes = omit(['id']);\n\nconst restoreCoreStore = async <T extends { value: unknown }>(strapi: Core.Strapi, values: T) => {\n const data = omitInvalidCreationAttributes(values);\n return strapi.db.query('strapi::core-store').create({\n data: {\n ...data,\n value: JSON.stringify(data.value),\n },\n });\n};\n\nconst restoreWebhooks = async <T extends { value: unknown }>(strapi: Core.Strapi, values: T) => {\n const data = omitInvalidCreationAttributes(values);\n return strapi.db.query('strapi::webhook').create({ data });\n};\n\nexport const restoreConfigs = async (strapi: Core.Strapi, config: IConfiguration) => {\n if (config.type === 'core-store') {\n return restoreCoreStore(strapi, config.value as { value: unknown });\n }\n\n if (config.type === 'webhook') {\n return restoreWebhooks(strapi, config.value as { value: unknown });\n }\n};\n\nexport const createConfigurationWriteStream = async (\n strapi: Core.Strapi,\n transaction?: Transaction\n) => {\n return new Writable({\n objectMode: true,\n async write<T extends { id: number }>(\n config: IConfiguration<T>,\n _encoding: BufferEncoding,\n callback: (error?: Error | null) => void\n ) {\n await transaction?.attach(async () => {\n try {\n await restoreConfigs(strapi, config);\n } catch (error) {\n return callback(\n new ProviderTransferError(\n `Failed to import ${chalk.yellowBright(config.type)} (${chalk.greenBright(\n config.value.id\n )}`\n )\n );\n }\n callback();\n });\n },\n });\n};\n"],"names":["omitInvalidCreationAttributes","omit","restoreCoreStore","strapi","values","data","db","query","create","value","JSON","stringify","restoreWebhooks","restoreConfigs","config","type","createConfigurationWriteStream","transaction","Writable","objectMode","write","_encoding","callback","attach","error","ProviderTransferError","chalk","yellowBright","greenBright","id"],"mappings":";;;;;AAOA,MAAMA,gCAAgCC,IAAK,CAAA;AAAC,IAAA;AAAK,CAAA,CAAA;AAEjD,MAAMC,gBAAAA,GAAmB,OAAqCC,MAAqBC,EAAAA,MAAAA,GAAAA;AACjF,IAAA,MAAMC,OAAOL,6BAA8BI,CAAAA,MAAAA,CAAAA;AAC3C,IAAA,OAAOD,OAAOG,EAAE,CAACC,KAAK,CAAC,oBAAA,CAAA,CAAsBC,MAAM,CAAC;QAClDH,IAAM,EAAA;AACJ,YAAA,GAAGA,IAAI;AACPI,YAAAA,KAAAA,EAAOC,IAAKC,CAAAA,SAAS,CAACN,IAAAA,CAAKI,KAAK;AAClC;AACF,KAAA,CAAA;AACF,CAAA;AAEA,MAAMG,eAAAA,GAAkB,OAAqCT,MAAqBC,EAAAA,MAAAA,GAAAA;AAChF,IAAA,MAAMC,OAAOL,6BAA8BI,CAAAA,MAAAA,CAAAA;AAC3C,IAAA,OAAOD,OAAOG,EAAE,CAACC,KAAK,CAAC,iBAAA,CAAA,CAAmBC,MAAM,CAAC;AAAEH,QAAAA;AAAK,KAAA,CAAA;AAC1D,CAAA;AAEO,MAAMQ,cAAiB,GAAA,OAAOV,MAAqBW,EAAAA,MAAAA,GAAAA;IACxD,IAAIA,MAAAA,CAAOC,IAAI,KAAK,YAAc,EAAA;QAChC,OAAOb,gBAAAA,CAAiBC,MAAQW,EAAAA,MAAAA,CAAOL,KAAK,CAAA;AAC9C;IAEA,IAAIK,MAAAA,CAAOC,IAAI,KAAK,SAAW,EAAA;QAC7B,OAAOH,eAAAA,CAAgBT,MAAQW,EAAAA,MAAAA,CAAOL,KAAK,CAAA;AAC7C;AACF;AAEO,MAAMO,8BAAiC,GAAA,OAC5Cb,MACAc,EAAAA,WAAAA,GAAAA;AAEA,IAAA,OAAO,IAAIC,QAAS,CAAA;QAClBC,UAAY,EAAA,IAAA;AACZ,QAAA,MAAMC,KACJN,CAAAA,CAAAA,MAAyB,EACzBO,SAAyB,EACzBC,QAAwC,EAAA;AAExC,YAAA,MAAML,aAAaM,MAAO,CAAA,UAAA;gBACxB,IAAI;AACF,oBAAA,MAAMV,eAAeV,MAAQW,EAAAA,MAAAA,CAAAA;AAC/B,iBAAA,CAAE,OAAOU,KAAO,EAAA;oBACd,OAAOF,QAAAA,CACL,IAAIG,qBACF,CAAA,CAAC,iBAAiB,EAAEC,KAAAA,CAAMC,YAAY,CAACb,MAAOC,CAAAA,IAAI,EAAE,EAAE,EAAEW,MAAME,WAAW,CACvEd,OAAOL,KAAK,CAACoB,EAAE,CAAA,CACf,CAAC,CAAA,CAAA;AAGT;AACAP,gBAAAA,QAAAA,EAAAA;AACF,aAAA,CAAA;AACF;AACF,KAAA,CAAA;AACF;;;;"}

View File

@@ -0,0 +1,12 @@
/// <reference types="node" />
import { Writable } from 'stream';
import type { Core, UID } from '@strapi/types';
import type { Transaction } from '../../../../../../types';
interface IEntitiesRestoreStreamOptions {
strapi: Core.Strapi;
updateMappingTable<TSchemaUID extends UID.Schema>(type: TSchemaUID, oldID: number, newID: number): void;
transaction?: Transaction;
}
export declare const createEntitiesWriteStream: (options: IEntitiesRestoreStreamOptions) => Writable;
export {};
//# sourceMappingURL=entities.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../../../../../../src/strapi/providers/local-destination/strategies/restore/entities.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAK/C,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAKpE,UAAU,6BAA6B;IACrC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IACpB,kBAAkB,CAAC,UAAU,SAAS,GAAG,CAAC,MAAM,EAC9C,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,IAAI,CAAC;IACR,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,eAAO,MAAM,yBAAyB,YAAa,6BAA6B,aAqD/E,CAAC"}

View File

@@ -0,0 +1,64 @@
'use strict';
var stream = require('stream');
var fp = require('lodash/fp');
var providers = require('../../../../../errors/providers.js');
require('crypto');
var json = require('../../../../../utils/json.js');
require('events');
var entity = require('../../../../queries/entity.js');
var components = require('../../../../../utils/components.js');
const createEntitiesWriteStream = (options)=>{
const { strapi, updateMappingTable, transaction } = options;
const query = entity.createEntityQuery(strapi);
return new stream.Writable({
objectMode: true,
async write (entity, _encoding, callback) {
await transaction?.attach(async ()=>{
const { type, id, data } = entity;
const { create, getDeepPopulateComponentLikeQuery } = query(type);
const contentType = strapi.getModel(type);
try {
const created = await create({
data,
populate: getDeepPopulateComponentLikeQuery(contentType, {
select: 'id'
}),
select: 'id'
});
// Compute differences between original & new entities
const diffs = json.diff(data, created);
updateMappingTable(type, id, created.id);
// For each difference found on an ID attribute,
// update the mapping the table accordingly
diffs.forEach((diff)=>{
if (diff.kind === 'modified' && fp.last(diff.path) === 'id' && 'kind' in contentType) {
const target = components.resolveComponentUID({
paths: diff.path,
data,
contentType,
strapi
});
// If no type is found for the given path, then ignore the diff
if (!target) {
return;
}
const [oldID, newID] = diff.values;
updateMappingTable(target, oldID, newID);
}
});
} catch (e) {
if (e instanceof Error) {
return callback(e);
}
return callback(new providers.ProviderTransferError(`Failed to create "${type}" (${id})`));
}
return callback(null);
});
}
});
};
exports.createEntitiesWriteStream = createEntitiesWriteStream;
//# sourceMappingURL=entities.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"entities.js","sources":["../../../../../../src/strapi/providers/local-destination/strategies/restore/entities.ts"],"sourcesContent":["import { Writable } from 'stream';\nimport type { Core, UID } from '@strapi/types';\n\nimport { last } from 'lodash/fp';\n\nimport { ProviderTransferError } from '../../../../../errors/providers';\nimport type { IEntity, Transaction } from '../../../../../../types';\nimport { json } from '../../../../../utils';\nimport * as queries from '../../../../queries';\nimport { resolveComponentUID } from '../../../../../utils/components';\n\ninterface IEntitiesRestoreStreamOptions {\n strapi: Core.Strapi;\n updateMappingTable<TSchemaUID extends UID.Schema>(\n type: TSchemaUID,\n oldID: number,\n newID: number\n ): void;\n transaction?: Transaction;\n}\n\nexport const createEntitiesWriteStream = (options: IEntitiesRestoreStreamOptions) => {\n const { strapi, updateMappingTable, transaction } = options;\n const query = queries.entity.createEntityQuery(strapi);\n\n return new Writable({\n objectMode: true,\n\n async write(entity: IEntity, _encoding, callback) {\n await transaction?.attach(async () => {\n const { type, id, data } = entity;\n const { create, getDeepPopulateComponentLikeQuery } = query(type);\n const contentType = strapi.getModel(type);\n\n try {\n const created = await create({\n data,\n populate: getDeepPopulateComponentLikeQuery(contentType, { select: 'id' }),\n select: 'id',\n });\n\n // Compute differences between original & new entities\n const diffs = json.diff(data, created);\n\n updateMappingTable(type, id, created.id);\n\n // For each difference found on an ID attribute,\n // update the mapping the table accordingly\n diffs.forEach((diff) => {\n if (diff.kind === 'modified' && last(diff.path) === 'id' && 'kind' in contentType) {\n const target = resolveComponentUID({ paths: diff.path, data, contentType, strapi });\n\n // If no type is found for the given path, then ignore the diff\n if (!target) {\n return;\n }\n\n const [oldID, newID] = diff.values as [number, number];\n\n updateMappingTable(target, oldID, newID);\n }\n });\n } catch (e) {\n if (e instanceof Error) {\n return callback(e);\n }\n\n return callback(new ProviderTransferError(`Failed to create \"${type}\" (${id})`));\n }\n\n return callback(null);\n });\n },\n });\n};\n"],"names":["createEntitiesWriteStream","options","strapi","updateMappingTable","transaction","query","queries","Writable","objectMode","write","entity","_encoding","callback","attach","type","id","data","create","getDeepPopulateComponentLikeQuery","contentType","getModel","created","populate","select","diffs","json","forEach","diff","kind","last","path","target","resolveComponentUID","paths","oldID","newID","values","e","Error","ProviderTransferError"],"mappings":";;;;;;;;;;;AAqBO,MAAMA,4BAA4B,CAACC,OAAAA,GAAAA;AACxC,IAAA,MAAM,EAAEC,MAAM,EAAEC,kBAAkB,EAAEC,WAAW,EAAE,GAAGH,OAAAA;AACpD,IAAA,MAAMI,KAAQC,GAAAA,wBAAgC,CAACJ,MAAAA,CAAAA;AAE/C,IAAA,OAAO,IAAIK,eAAS,CAAA;QAClBC,UAAY,EAAA,IAAA;AAEZ,QAAA,MAAMC,KAAMC,CAAAA,CAAAA,MAAe,EAAEC,SAAS,EAAEC,QAAQ,EAAA;AAC9C,YAAA,MAAMR,aAAaS,MAAO,CAAA,UAAA;AACxB,gBAAA,MAAM,EAAEC,IAAI,EAAEC,EAAE,EAAEC,IAAI,EAAE,GAAGN,MAAAA;AAC3B,gBAAA,MAAM,EAAEO,MAAM,EAAEC,iCAAiC,EAAE,GAAGb,KAAMS,CAAAA,IAAAA,CAAAA;gBAC5D,MAAMK,WAAAA,GAAcjB,MAAOkB,CAAAA,QAAQ,CAACN,IAAAA,CAAAA;gBAEpC,IAAI;oBACF,MAAMO,OAAAA,GAAU,MAAMJ,MAAO,CAAA;AAC3BD,wBAAAA,IAAAA;AACAM,wBAAAA,QAAAA,EAAUJ,kCAAkCC,WAAa,EAAA;4BAAEI,MAAQ,EAAA;AAAK,yBAAA,CAAA;wBACxEA,MAAQ,EAAA;AACV,qBAAA,CAAA;;AAGA,oBAAA,MAAMC,KAAQC,GAAAA,SAAS,CAACT,IAAMK,EAAAA,OAAAA,CAAAA;oBAE9BlB,kBAAmBW,CAAAA,IAAAA,EAAMC,EAAIM,EAAAA,OAAAA,CAAQN,EAAE,CAAA;;;oBAIvCS,KAAME,CAAAA,OAAO,CAAC,CAACC,IAAAA,GAAAA;wBACb,IAAIA,IAAAA,CAAKC,IAAI,KAAK,UAAcC,IAAAA,OAAAA,CAAKF,KAAKG,IAAI,CAAA,KAAM,IAAQ,IAAA,MAAA,IAAUX,WAAa,EAAA;AACjF,4BAAA,MAAMY,SAASC,8BAAoB,CAAA;AAAEC,gCAAAA,KAAAA,EAAON,KAAKG,IAAI;AAAEd,gCAAAA,IAAAA;AAAMG,gCAAAA,WAAAA;AAAajB,gCAAAA;AAAO,6BAAA,CAAA;;AAGjF,4BAAA,IAAI,CAAC6B,MAAQ,EAAA;AACX,gCAAA;AACF;AAEA,4BAAA,MAAM,CAACG,KAAAA,EAAOC,KAAM,CAAA,GAAGR,KAAKS,MAAM;AAElCjC,4BAAAA,kBAAAA,CAAmB4B,QAAQG,KAAOC,EAAAA,KAAAA,CAAAA;AACpC;AACF,qBAAA,CAAA;AACF,iBAAA,CAAE,OAAOE,CAAG,EAAA;AACV,oBAAA,IAAIA,aAAaC,KAAO,EAAA;AACtB,wBAAA,OAAO1B,QAASyB,CAAAA,CAAAA,CAAAA;AAClB;oBAEA,OAAOzB,QAAAA,CAAS,IAAI2B,+BAAAA,CAAsB,CAAC,kBAAkB,EAAEzB,IAAAA,CAAK,GAAG,EAAEC,EAAG,CAAA,CAAC,CAAC,CAAA,CAAA;AAChF;AAEA,gBAAA,OAAOH,QAAS,CAAA,IAAA,CAAA;AAClB,aAAA,CAAA;AACF;AACF,KAAA,CAAA;AACF;;;;"}

View File

@@ -0,0 +1,62 @@
import { Writable } from 'stream';
import { last } from 'lodash/fp';
import { ProviderTransferError } from '../../../../../errors/providers.mjs';
import 'crypto';
import { diff } from '../../../../../utils/json.mjs';
import 'events';
import { createEntityQuery } from '../../../../queries/entity.mjs';
import { resolveComponentUID } from '../../../../../utils/components.mjs';
const createEntitiesWriteStream = (options)=>{
const { strapi, updateMappingTable, transaction } = options;
const query = createEntityQuery(strapi);
return new Writable({
objectMode: true,
async write (entity, _encoding, callback) {
await transaction?.attach(async ()=>{
const { type, id, data } = entity;
const { create, getDeepPopulateComponentLikeQuery } = query(type);
const contentType = strapi.getModel(type);
try {
const created = await create({
data,
populate: getDeepPopulateComponentLikeQuery(contentType, {
select: 'id'
}),
select: 'id'
});
// Compute differences between original & new entities
const diffs = diff(data, created);
updateMappingTable(type, id, created.id);
// For each difference found on an ID attribute,
// update the mapping the table accordingly
diffs.forEach((diff)=>{
if (diff.kind === 'modified' && last(diff.path) === 'id' && 'kind' in contentType) {
const target = resolveComponentUID({
paths: diff.path,
data,
contentType,
strapi
});
// If no type is found for the given path, then ignore the diff
if (!target) {
return;
}
const [oldID, newID] = diff.values;
updateMappingTable(target, oldID, newID);
}
});
} catch (e) {
if (e instanceof Error) {
return callback(e);
}
return callback(new ProviderTransferError(`Failed to create "${type}" (${id})`));
}
return callback(null);
});
}
});
};
export { createEntitiesWriteStream };
//# sourceMappingURL=entities.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"entities.mjs","sources":["../../../../../../src/strapi/providers/local-destination/strategies/restore/entities.ts"],"sourcesContent":["import { Writable } from 'stream';\nimport type { Core, UID } from '@strapi/types';\n\nimport { last } from 'lodash/fp';\n\nimport { ProviderTransferError } from '../../../../../errors/providers';\nimport type { IEntity, Transaction } from '../../../../../../types';\nimport { json } from '../../../../../utils';\nimport * as queries from '../../../../queries';\nimport { resolveComponentUID } from '../../../../../utils/components';\n\ninterface IEntitiesRestoreStreamOptions {\n strapi: Core.Strapi;\n updateMappingTable<TSchemaUID extends UID.Schema>(\n type: TSchemaUID,\n oldID: number,\n newID: number\n ): void;\n transaction?: Transaction;\n}\n\nexport const createEntitiesWriteStream = (options: IEntitiesRestoreStreamOptions) => {\n const { strapi, updateMappingTable, transaction } = options;\n const query = queries.entity.createEntityQuery(strapi);\n\n return new Writable({\n objectMode: true,\n\n async write(entity: IEntity, _encoding, callback) {\n await transaction?.attach(async () => {\n const { type, id, data } = entity;\n const { create, getDeepPopulateComponentLikeQuery } = query(type);\n const contentType = strapi.getModel(type);\n\n try {\n const created = await create({\n data,\n populate: getDeepPopulateComponentLikeQuery(contentType, { select: 'id' }),\n select: 'id',\n });\n\n // Compute differences between original & new entities\n const diffs = json.diff(data, created);\n\n updateMappingTable(type, id, created.id);\n\n // For each difference found on an ID attribute,\n // update the mapping the table accordingly\n diffs.forEach((diff) => {\n if (diff.kind === 'modified' && last(diff.path) === 'id' && 'kind' in contentType) {\n const target = resolveComponentUID({ paths: diff.path, data, contentType, strapi });\n\n // If no type is found for the given path, then ignore the diff\n if (!target) {\n return;\n }\n\n const [oldID, newID] = diff.values as [number, number];\n\n updateMappingTable(target, oldID, newID);\n }\n });\n } catch (e) {\n if (e instanceof Error) {\n return callback(e);\n }\n\n return callback(new ProviderTransferError(`Failed to create \"${type}\" (${id})`));\n }\n\n return callback(null);\n });\n },\n });\n};\n"],"names":["createEntitiesWriteStream","options","strapi","updateMappingTable","transaction","query","queries","Writable","objectMode","write","entity","_encoding","callback","attach","type","id","data","create","getDeepPopulateComponentLikeQuery","contentType","getModel","created","populate","select","diffs","json","forEach","diff","kind","last","path","target","resolveComponentUID","paths","oldID","newID","values","e","Error","ProviderTransferError"],"mappings":";;;;;;;;;AAqBO,MAAMA,4BAA4B,CAACC,OAAAA,GAAAA;AACxC,IAAA,MAAM,EAAEC,MAAM,EAAEC,kBAAkB,EAAEC,WAAW,EAAE,GAAGH,OAAAA;AACpD,IAAA,MAAMI,KAAQC,GAAAA,iBAAgC,CAACJ,MAAAA,CAAAA;AAE/C,IAAA,OAAO,IAAIK,QAAS,CAAA;QAClBC,UAAY,EAAA,IAAA;AAEZ,QAAA,MAAMC,KAAMC,CAAAA,CAAAA,MAAe,EAAEC,SAAS,EAAEC,QAAQ,EAAA;AAC9C,YAAA,MAAMR,aAAaS,MAAO,CAAA,UAAA;AACxB,gBAAA,MAAM,EAAEC,IAAI,EAAEC,EAAE,EAAEC,IAAI,EAAE,GAAGN,MAAAA;AAC3B,gBAAA,MAAM,EAAEO,MAAM,EAAEC,iCAAiC,EAAE,GAAGb,KAAMS,CAAAA,IAAAA,CAAAA;gBAC5D,MAAMK,WAAAA,GAAcjB,MAAOkB,CAAAA,QAAQ,CAACN,IAAAA,CAAAA;gBAEpC,IAAI;oBACF,MAAMO,OAAAA,GAAU,MAAMJ,MAAO,CAAA;AAC3BD,wBAAAA,IAAAA;AACAM,wBAAAA,QAAAA,EAAUJ,kCAAkCC,WAAa,EAAA;4BAAEI,MAAQ,EAAA;AAAK,yBAAA,CAAA;wBACxEA,MAAQ,EAAA;AACV,qBAAA,CAAA;;AAGA,oBAAA,MAAMC,KAAQC,GAAAA,IAAS,CAACT,IAAMK,EAAAA,OAAAA,CAAAA;oBAE9BlB,kBAAmBW,CAAAA,IAAAA,EAAMC,EAAIM,EAAAA,OAAAA,CAAQN,EAAE,CAAA;;;oBAIvCS,KAAME,CAAAA,OAAO,CAAC,CAACC,IAAAA,GAAAA;wBACb,IAAIA,IAAAA,CAAKC,IAAI,KAAK,UAAcC,IAAAA,IAAAA,CAAKF,KAAKG,IAAI,CAAA,KAAM,IAAQ,IAAA,MAAA,IAAUX,WAAa,EAAA;AACjF,4BAAA,MAAMY,SAASC,mBAAoB,CAAA;AAAEC,gCAAAA,KAAAA,EAAON,KAAKG,IAAI;AAAEd,gCAAAA,IAAAA;AAAMG,gCAAAA,WAAAA;AAAajB,gCAAAA;AAAO,6BAAA,CAAA;;AAGjF,4BAAA,IAAI,CAAC6B,MAAQ,EAAA;AACX,gCAAA;AACF;AAEA,4BAAA,MAAM,CAACG,KAAAA,EAAOC,KAAM,CAAA,GAAGR,KAAKS,MAAM;AAElCjC,4BAAAA,kBAAAA,CAAmB4B,QAAQG,KAAOC,EAAAA,KAAAA,CAAAA;AACpC;AACF,qBAAA,CAAA;AACF,iBAAA,CAAE,OAAOE,CAAG,EAAA;AACV,oBAAA,IAAIA,aAAaC,KAAO,EAAA;AACtB,wBAAA,OAAO1B,QAASyB,CAAAA,CAAAA,CAAAA;AAClB;oBAEA,OAAOzB,QAAAA,CAAS,IAAI2B,qBAAAA,CAAsB,CAAC,kBAAkB,EAAEzB,IAAAA,CAAK,GAAG,EAAEC,EAAG,CAAA,CAAC,CAAC,CAAA,CAAA;AAChF;AAEA,gBAAA,OAAOH,QAAS,CAAA,IAAA,CAAA;AAClB,aAAA,CAAA;AACF;AACF,KAAA,CAAA;AACF;;;;"}

View File

@@ -0,0 +1,33 @@
import type { Core, Struct } from '@strapi/types';
export interface IRestoreOptions {
assets?: boolean;
configuration?: {
webhook?: boolean;
coreStore?: boolean;
};
entities?: {
include?: string[];
exclude?: string[];
filters?: ((contentType: Struct.ContentTypeSchema) => boolean)[];
params?: {
[uid: string]: unknown;
};
};
}
interface IDeleteResults {
count: number;
aggregate: {
[uid: string]: {
count: number;
};
};
}
export declare const deleteRecords: (strapi: Core.Strapi, options: IRestoreOptions) => Promise<{
count: number;
entities: IDeleteResults;
configuration: IDeleteResults;
}>;
export * from './entities';
export * from './configuration';
export * from './links';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/strapi/providers/local-destination/strategies/restore/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAO,MAAM,EAAE,MAAM,eAAe,CAAC;AAKvD,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,iBAAiB,KAAK,OAAO,CAAC,EAAE,CAAC;QACjE,MAAM,CAAC,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC;KACrC,CAAC;CACH;AAED,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CACjD;AAED,eAAO,MAAM,aAAa,WAAkB,KAAK,MAAM,WAAW,eAAe;;;;EAShF,CAAC;AAsIF,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC"}

View File

@@ -0,0 +1,126 @@
'use strict';
var providers = require('../../../../../errors/providers.js');
var entity = require('../../../../queries/entity.js');
require('lodash/fp');
require('stream');
require('crypto');
require('events');
require('lodash');
require('@strapi/utils');
var configuration = require('./configuration.js');
const deleteRecords = async (strapi, options)=>{
const entities = await deleteEntitiesRecords(strapi, options);
const configuration = await deleteConfigurationRecords(strapi, options);
return {
count: entities.count + configuration.count,
entities,
configuration
};
};
const deleteEntitiesRecords = async (strapi, options = {})=>{
const { entities } = options;
const models = strapi.get('models').get();
const contentTypes = Object.values(strapi.contentTypes);
const contentTypesToClear = contentTypes.filter((contentType)=>{
let removeThisContentType = true;
// include means "only include these types" so if it's not in here, it's not being included
if (entities?.include) {
removeThisContentType = entities.include.includes(contentType.uid);
}
// if something is excluded, remove it. But lack of being excluded doesn't mean it's kept
if (entities?.exclude && entities.exclude.includes(contentType.uid)) {
removeThisContentType = false;
}
if (entities?.filters) {
removeThisContentType = entities.filters.every((filter)=>filter(contentType));
}
return removeThisContentType;
}).map((contentType)=>contentType.uid);
const modelsToClear = models.filter((model)=>{
if (contentTypesToClear.includes(model.uid)) {
return false;
}
let removeThisModel = true;
// include means "only include these types" so if it's not in here, it's not being included
if (entities?.include) {
removeThisModel = entities.include.includes(model.uid);
}
// if something is excluded, remove it. But lack of being excluded doesn't mean it's kept
if (entities?.exclude && entities.exclude.includes(model.uid)) {
removeThisModel = false;
}
return removeThisModel;
}).map((model)=>model.uid);
const [results, updateResults] = useResults([
...contentTypesToClear,
...modelsToClear
]);
const contentTypeQuery = entity.createEntityQuery(strapi);
const contentTypePromises = contentTypesToClear.map(async (uid)=>{
const result = await contentTypeQuery(uid).deleteMany(entities?.params);
if (result) {
updateResults(result.count || 0, uid);
}
});
const modelsPromises = modelsToClear.map(async (uid)=>{
const result = await strapi.db.query(uid).deleteMany({});
if (result) {
updateResults(result.count || 0, uid);
}
});
await Promise.all([
...contentTypePromises,
...modelsPromises
]);
return results;
};
const deleteConfigurationRecords = async (strapi, options = {})=>{
const { coreStore = true, webhook = true } = options?.configuration ?? {};
const models = [];
if (coreStore) {
models.push('strapi::core-store');
}
if (webhook) {
models.push('strapi::webhook');
}
const [results, updateResults] = useResults(models);
const deletePromises = models.map(async (uid)=>{
const result = await strapi.db.query(uid).deleteMany({});
if (result) {
updateResults(result.count, uid);
}
});
await Promise.all(deletePromises);
return results;
};
const useResults = (keys)=>{
const results = {
count: 0,
aggregate: keys.reduce((acc, key)=>({
...acc,
[key]: {
count: 0
}
}), {})
};
const update = (count, key)=>{
if (key) {
if (!(key in results.aggregate)) {
throw new providers.ProviderTransferError(`Unknown key "${key}" provided in results update`);
}
results.aggregate[key].count += count;
}
results.count += count;
};
return [
results,
update
];
};
exports.createConfigurationWriteStream = configuration.createConfigurationWriteStream;
exports.restoreConfigs = configuration.restoreConfigs;
exports.deleteRecords = deleteRecords;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,122 @@
import { ProviderTransferError } from '../../../../../errors/providers.mjs';
import { createEntityQuery } from '../../../../queries/entity.mjs';
import 'lodash/fp';
import 'stream';
import 'crypto';
import 'events';
import 'lodash';
import '@strapi/utils';
export { createConfigurationWriteStream, restoreConfigs } from './configuration.mjs';
const deleteRecords = async (strapi, options)=>{
const entities = await deleteEntitiesRecords(strapi, options);
const configuration = await deleteConfigurationRecords(strapi, options);
return {
count: entities.count + configuration.count,
entities,
configuration
};
};
const deleteEntitiesRecords = async (strapi, options = {})=>{
const { entities } = options;
const models = strapi.get('models').get();
const contentTypes = Object.values(strapi.contentTypes);
const contentTypesToClear = contentTypes.filter((contentType)=>{
let removeThisContentType = true;
// include means "only include these types" so if it's not in here, it's not being included
if (entities?.include) {
removeThisContentType = entities.include.includes(contentType.uid);
}
// if something is excluded, remove it. But lack of being excluded doesn't mean it's kept
if (entities?.exclude && entities.exclude.includes(contentType.uid)) {
removeThisContentType = false;
}
if (entities?.filters) {
removeThisContentType = entities.filters.every((filter)=>filter(contentType));
}
return removeThisContentType;
}).map((contentType)=>contentType.uid);
const modelsToClear = models.filter((model)=>{
if (contentTypesToClear.includes(model.uid)) {
return false;
}
let removeThisModel = true;
// include means "only include these types" so if it's not in here, it's not being included
if (entities?.include) {
removeThisModel = entities.include.includes(model.uid);
}
// if something is excluded, remove it. But lack of being excluded doesn't mean it's kept
if (entities?.exclude && entities.exclude.includes(model.uid)) {
removeThisModel = false;
}
return removeThisModel;
}).map((model)=>model.uid);
const [results, updateResults] = useResults([
...contentTypesToClear,
...modelsToClear
]);
const contentTypeQuery = createEntityQuery(strapi);
const contentTypePromises = contentTypesToClear.map(async (uid)=>{
const result = await contentTypeQuery(uid).deleteMany(entities?.params);
if (result) {
updateResults(result.count || 0, uid);
}
});
const modelsPromises = modelsToClear.map(async (uid)=>{
const result = await strapi.db.query(uid).deleteMany({});
if (result) {
updateResults(result.count || 0, uid);
}
});
await Promise.all([
...contentTypePromises,
...modelsPromises
]);
return results;
};
const deleteConfigurationRecords = async (strapi, options = {})=>{
const { coreStore = true, webhook = true } = options?.configuration ?? {};
const models = [];
if (coreStore) {
models.push('strapi::core-store');
}
if (webhook) {
models.push('strapi::webhook');
}
const [results, updateResults] = useResults(models);
const deletePromises = models.map(async (uid)=>{
const result = await strapi.db.query(uid).deleteMany({});
if (result) {
updateResults(result.count, uid);
}
});
await Promise.all(deletePromises);
return results;
};
const useResults = (keys)=>{
const results = {
count: 0,
aggregate: keys.reduce((acc, key)=>({
...acc,
[key]: {
count: 0
}
}), {})
};
const update = (count, key)=>{
if (key) {
if (!(key in results.aggregate)) {
throw new ProviderTransferError(`Unknown key "${key}" provided in results update`);
}
results.aggregate[key].count += count;
}
results.count += count;
};
return [
results,
update
];
};
export { deleteRecords };
//# sourceMappingURL=index.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
/// <reference types="node" />
import { Writable } from 'stream';
import type { Core } from '@strapi/types';
import { Transaction } from '../../../../../../types';
export declare const createLinksWriteStream: (mapID: (uid: string, id: number) => number | undefined, strapi: Core.Strapi, transaction?: Transaction, onWarning?: (message: string) => void) => Writable;
//# sourceMappingURL=links.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../../../../../src/strapi/providers/local-destination/strategies/restore/links.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAS,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAuB7D,eAAO,MAAM,sBAAsB,UAC1B,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,UAC9C,KAAK,MAAM,gBACL,WAAW,cACb,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,aAwCtC,CAAC"}

View File

@@ -0,0 +1,60 @@
'use strict';
var stream = require('stream');
var providers = require('../../../../../errors/providers.js');
var link = require('../../../../queries/link.js');
const isErrorWithCode = (error)=>{
return error && typeof error.code === 'string';
};
const isForeignKeyConstraintError = (e)=>{
const MYSQL_FK_ERROR_CODES = [
'1452',
'1557',
'1216',
'1217',
'1451'
];
const POSTGRES_FK_ERROR_CODE = '23503';
const SQLITE_FK_ERROR_CODE = 'SQLITE_CONSTRAINT_FOREIGNKEY';
if (isErrorWithCode(e) && e.code) {
return [
SQLITE_FK_ERROR_CODE,
POSTGRES_FK_ERROR_CODE,
...MYSQL_FK_ERROR_CODES
].includes(e.code);
}
return e.message.toLowerCase().includes('foreign key constraint');
};
const createLinksWriteStream = (mapID, strapi, transaction, onWarning)=>{
return new stream.Writable({
objectMode: true,
async write (link$1, _encoding, callback) {
await transaction?.attach(async (trx)=>{
const { left, right } = link$1;
const query = link.createLinkQuery(strapi, trx);
const originalLeftRef = left.ref;
const originalRightRef = right.ref;
// Map IDs if needed
left.ref = mapID(left.type, originalLeftRef) ?? originalLeftRef;
right.ref = mapID(right.type, originalRightRef) ?? originalRightRef;
try {
await query().insert(link$1);
} catch (e) {
if (e instanceof Error) {
if (isForeignKeyConstraintError(e)) {
onWarning?.(`Skipping link ${left.type}:${originalLeftRef} -> ${right.type}:${originalRightRef} due to a foreign key constraint.`);
return callback(null);
}
return callback(e);
}
return callback(new providers.ProviderTransferError(`An error happened while trying to import a ${left.type} link.`));
}
callback(null);
});
}
});
};
exports.createLinksWriteStream = createLinksWriteStream;
//# sourceMappingURL=links.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"links.js","sources":["../../../../../../src/strapi/providers/local-destination/strategies/restore/links.ts"],"sourcesContent":["import { Writable } from 'stream';\nimport type { Core } from '@strapi/types';\nimport { ProviderTransferError } from '../../../../../errors/providers';\nimport { ILink, Transaction } from '../../../../../../types';\nimport { createLinkQuery } from '../../../../queries/link';\n\ninterface ErrorWithCode extends Error {\n code: string;\n}\n\nconst isErrorWithCode = (error: any): error is ErrorWithCode => {\n return error && typeof error.code === 'string';\n};\n\nconst isForeignKeyConstraintError = (e: Error) => {\n const MYSQL_FK_ERROR_CODES = ['1452', '1557', '1216', '1217', '1451'];\n const POSTGRES_FK_ERROR_CODE = '23503';\n const SQLITE_FK_ERROR_CODE = 'SQLITE_CONSTRAINT_FOREIGNKEY';\n\n if (isErrorWithCode(e) && e.code) {\n return [SQLITE_FK_ERROR_CODE, POSTGRES_FK_ERROR_CODE, ...MYSQL_FK_ERROR_CODES].includes(e.code);\n }\n\n return e.message.toLowerCase().includes('foreign key constraint');\n};\n\nexport const createLinksWriteStream = (\n mapID: (uid: string, id: number) => number | undefined,\n strapi: Core.Strapi,\n transaction?: Transaction,\n onWarning?: (message: string) => void\n) => {\n return new Writable({\n objectMode: true,\n async write(link: ILink, _encoding, callback) {\n await transaction?.attach(async (trx) => {\n const { left, right } = link;\n const query = createLinkQuery(strapi, trx);\n\n const originalLeftRef = left.ref;\n const originalRightRef = right.ref;\n\n // Map IDs if needed\n left.ref = mapID(left.type, originalLeftRef) ?? originalLeftRef;\n right.ref = mapID(right.type, originalRightRef) ?? originalRightRef;\n\n try {\n await query().insert(link);\n } catch (e) {\n if (e instanceof Error) {\n if (isForeignKeyConstraintError(e)) {\n onWarning?.(\n `Skipping link ${left.type}:${originalLeftRef} -> ${right.type}:${originalRightRef} due to a foreign key constraint.`\n );\n return callback(null);\n }\n return callback(e);\n }\n\n return callback(\n new ProviderTransferError(\n `An error happened while trying to import a ${left.type} link.`\n )\n );\n }\n\n callback(null);\n });\n },\n });\n};\n"],"names":["isErrorWithCode","error","code","isForeignKeyConstraintError","e","MYSQL_FK_ERROR_CODES","POSTGRES_FK_ERROR_CODE","SQLITE_FK_ERROR_CODE","includes","message","toLowerCase","createLinksWriteStream","mapID","strapi","transaction","onWarning","Writable","objectMode","write","link","_encoding","callback","attach","trx","left","right","query","createLinkQuery","originalLeftRef","ref","originalRightRef","type","insert","Error","ProviderTransferError"],"mappings":";;;;;;AAUA,MAAMA,kBAAkB,CAACC,KAAAA,GAAAA;AACvB,IAAA,OAAOA,KAAS,IAAA,OAAOA,KAAMC,CAAAA,IAAI,KAAK,QAAA;AACxC,CAAA;AAEA,MAAMC,8BAA8B,CAACC,CAAAA,GAAAA;AACnC,IAAA,MAAMC,oBAAuB,GAAA;AAAC,QAAA,MAAA;AAAQ,QAAA,MAAA;AAAQ,QAAA,MAAA;AAAQ,QAAA,MAAA;AAAQ,QAAA;AAAO,KAAA;AACrE,IAAA,MAAMC,sBAAyB,GAAA,OAAA;AAC/B,IAAA,MAAMC,oBAAuB,GAAA,8BAAA;AAE7B,IAAA,IAAIP,eAAgBI,CAAAA,CAAAA,CAAAA,IAAMA,CAAEF,CAAAA,IAAI,EAAE;QAChC,OAAO;AAACK,YAAAA,oBAAAA;AAAsBD,YAAAA,sBAAAA;AAA2BD,YAAAA,GAAAA;SAAqB,CAACG,QAAQ,CAACJ,CAAAA,CAAEF,IAAI,CAAA;AAChG;AAEA,IAAA,OAAOE,EAAEK,OAAO,CAACC,WAAW,EAAA,CAAGF,QAAQ,CAAC,wBAAA,CAAA;AAC1C,CAAA;AAEaG,MAAAA,sBAAAA,GAAyB,CACpCC,KAAAA,EACAC,QACAC,WACAC,EAAAA,SAAAA,GAAAA;AAEA,IAAA,OAAO,IAAIC,eAAS,CAAA;QAClBC,UAAY,EAAA,IAAA;AACZ,QAAA,MAAMC,KAAMC,CAAAA,CAAAA,MAAW,EAAEC,SAAS,EAAEC,QAAQ,EAAA;YAC1C,MAAMP,WAAAA,EAAaQ,OAAO,OAAOC,GAAAA,GAAAA;AAC/B,gBAAA,MAAM,EAAEC,IAAI,EAAEC,KAAK,EAAE,GAAGN,MAAAA;gBACxB,MAAMO,KAAAA,GAAQC,qBAAgBd,MAAQU,EAAAA,GAAAA,CAAAA;gBAEtC,MAAMK,eAAAA,GAAkBJ,KAAKK,GAAG;gBAChC,MAAMC,gBAAAA,GAAmBL,MAAMI,GAAG;;AAGlCL,gBAAAA,IAAAA,CAAKK,GAAG,GAAGjB,KAAAA,CAAMY,IAAKO,CAAAA,IAAI,EAAEH,eAAoBA,CAAAA,IAAAA,eAAAA;AAChDH,gBAAAA,KAAAA,CAAMI,GAAG,GAAGjB,KAAAA,CAAMa,KAAMM,CAAAA,IAAI,EAAED,gBAAqBA,CAAAA,IAAAA,gBAAAA;gBAEnD,IAAI;oBACF,MAAMJ,KAAAA,EAAAA,CAAQM,MAAM,CAACb,MAAAA,CAAAA;AACvB,iBAAA,CAAE,OAAOf,CAAG,EAAA;AACV,oBAAA,IAAIA,aAAa6B,KAAO,EAAA;AACtB,wBAAA,IAAI9B,4BAA4BC,CAAI,CAAA,EAAA;AAClCW,4BAAAA,SAAAA,GACE,CAAC,cAAc,EAAES,KAAKO,IAAI,CAAC,CAAC,EAAEH,eAAAA,CAAgB,IAAI,EAAEH,MAAMM,IAAI,CAAC,CAAC,EAAED,gBAAAA,CAAiB,iCAAiC,CAAC,CAAA;AAEvH,4BAAA,OAAOT,QAAS,CAAA,IAAA,CAAA;AAClB;AACA,wBAAA,OAAOA,QAASjB,CAAAA,CAAAA,CAAAA;AAClB;oBAEA,OAAOiB,QAAAA,CACL,IAAIa,+BAAAA,CACF,CAAC,2CAA2C,EAAEV,IAAKO,CAAAA,IAAI,CAAC,MAAM,CAAC,CAAA,CAAA;AAGrE;gBAEAV,QAAS,CAAA,IAAA,CAAA;AACX,aAAA,CAAA;AACF;AACF,KAAA,CAAA;AACF;;;;"}

View File

@@ -0,0 +1,58 @@
import { Writable } from 'stream';
import { ProviderTransferError } from '../../../../../errors/providers.mjs';
import { createLinkQuery } from '../../../../queries/link.mjs';
const isErrorWithCode = (error)=>{
return error && typeof error.code === 'string';
};
const isForeignKeyConstraintError = (e)=>{
const MYSQL_FK_ERROR_CODES = [
'1452',
'1557',
'1216',
'1217',
'1451'
];
const POSTGRES_FK_ERROR_CODE = '23503';
const SQLITE_FK_ERROR_CODE = 'SQLITE_CONSTRAINT_FOREIGNKEY';
if (isErrorWithCode(e) && e.code) {
return [
SQLITE_FK_ERROR_CODE,
POSTGRES_FK_ERROR_CODE,
...MYSQL_FK_ERROR_CODES
].includes(e.code);
}
return e.message.toLowerCase().includes('foreign key constraint');
};
const createLinksWriteStream = (mapID, strapi, transaction, onWarning)=>{
return new Writable({
objectMode: true,
async write (link, _encoding, callback) {
await transaction?.attach(async (trx)=>{
const { left, right } = link;
const query = createLinkQuery(strapi, trx);
const originalLeftRef = left.ref;
const originalRightRef = right.ref;
// Map IDs if needed
left.ref = mapID(left.type, originalLeftRef) ?? originalLeftRef;
right.ref = mapID(right.type, originalRightRef) ?? originalRightRef;
try {
await query().insert(link);
} catch (e) {
if (e instanceof Error) {
if (isForeignKeyConstraintError(e)) {
onWarning?.(`Skipping link ${left.type}:${originalLeftRef} -> ${right.type}:${originalRightRef} due to a foreign key constraint.`);
return callback(null);
}
return callback(e);
}
return callback(new ProviderTransferError(`An error happened while trying to import a ${left.type} link.`));
}
callback(null);
});
}
});
};
export { createLinksWriteStream };
//# sourceMappingURL=links.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"links.mjs","sources":["../../../../../../src/strapi/providers/local-destination/strategies/restore/links.ts"],"sourcesContent":["import { Writable } from 'stream';\nimport type { Core } from '@strapi/types';\nimport { ProviderTransferError } from '../../../../../errors/providers';\nimport { ILink, Transaction } from '../../../../../../types';\nimport { createLinkQuery } from '../../../../queries/link';\n\ninterface ErrorWithCode extends Error {\n code: string;\n}\n\nconst isErrorWithCode = (error: any): error is ErrorWithCode => {\n return error && typeof error.code === 'string';\n};\n\nconst isForeignKeyConstraintError = (e: Error) => {\n const MYSQL_FK_ERROR_CODES = ['1452', '1557', '1216', '1217', '1451'];\n const POSTGRES_FK_ERROR_CODE = '23503';\n const SQLITE_FK_ERROR_CODE = 'SQLITE_CONSTRAINT_FOREIGNKEY';\n\n if (isErrorWithCode(e) && e.code) {\n return [SQLITE_FK_ERROR_CODE, POSTGRES_FK_ERROR_CODE, ...MYSQL_FK_ERROR_CODES].includes(e.code);\n }\n\n return e.message.toLowerCase().includes('foreign key constraint');\n};\n\nexport const createLinksWriteStream = (\n mapID: (uid: string, id: number) => number | undefined,\n strapi: Core.Strapi,\n transaction?: Transaction,\n onWarning?: (message: string) => void\n) => {\n return new Writable({\n objectMode: true,\n async write(link: ILink, _encoding, callback) {\n await transaction?.attach(async (trx) => {\n const { left, right } = link;\n const query = createLinkQuery(strapi, trx);\n\n const originalLeftRef = left.ref;\n const originalRightRef = right.ref;\n\n // Map IDs if needed\n left.ref = mapID(left.type, originalLeftRef) ?? originalLeftRef;\n right.ref = mapID(right.type, originalRightRef) ?? originalRightRef;\n\n try {\n await query().insert(link);\n } catch (e) {\n if (e instanceof Error) {\n if (isForeignKeyConstraintError(e)) {\n onWarning?.(\n `Skipping link ${left.type}:${originalLeftRef} -> ${right.type}:${originalRightRef} due to a foreign key constraint.`\n );\n return callback(null);\n }\n return callback(e);\n }\n\n return callback(\n new ProviderTransferError(\n `An error happened while trying to import a ${left.type} link.`\n )\n );\n }\n\n callback(null);\n });\n },\n });\n};\n"],"names":["isErrorWithCode","error","code","isForeignKeyConstraintError","e","MYSQL_FK_ERROR_CODES","POSTGRES_FK_ERROR_CODE","SQLITE_FK_ERROR_CODE","includes","message","toLowerCase","createLinksWriteStream","mapID","strapi","transaction","onWarning","Writable","objectMode","write","link","_encoding","callback","attach","trx","left","right","query","createLinkQuery","originalLeftRef","ref","originalRightRef","type","insert","Error","ProviderTransferError"],"mappings":";;;;AAUA,MAAMA,kBAAkB,CAACC,KAAAA,GAAAA;AACvB,IAAA,OAAOA,KAAS,IAAA,OAAOA,KAAMC,CAAAA,IAAI,KAAK,QAAA;AACxC,CAAA;AAEA,MAAMC,8BAA8B,CAACC,CAAAA,GAAAA;AACnC,IAAA,MAAMC,oBAAuB,GAAA;AAAC,QAAA,MAAA;AAAQ,QAAA,MAAA;AAAQ,QAAA,MAAA;AAAQ,QAAA,MAAA;AAAQ,QAAA;AAAO,KAAA;AACrE,IAAA,MAAMC,sBAAyB,GAAA,OAAA;AAC/B,IAAA,MAAMC,oBAAuB,GAAA,8BAAA;AAE7B,IAAA,IAAIP,eAAgBI,CAAAA,CAAAA,CAAAA,IAAMA,CAAEF,CAAAA,IAAI,EAAE;QAChC,OAAO;AAACK,YAAAA,oBAAAA;AAAsBD,YAAAA,sBAAAA;AAA2BD,YAAAA,GAAAA;SAAqB,CAACG,QAAQ,CAACJ,CAAAA,CAAEF,IAAI,CAAA;AAChG;AAEA,IAAA,OAAOE,EAAEK,OAAO,CAACC,WAAW,EAAA,CAAGF,QAAQ,CAAC,wBAAA,CAAA;AAC1C,CAAA;AAEaG,MAAAA,sBAAAA,GAAyB,CACpCC,KAAAA,EACAC,QACAC,WACAC,EAAAA,SAAAA,GAAAA;AAEA,IAAA,OAAO,IAAIC,QAAS,CAAA;QAClBC,UAAY,EAAA,IAAA;AACZ,QAAA,MAAMC,KAAMC,CAAAA,CAAAA,IAAW,EAAEC,SAAS,EAAEC,QAAQ,EAAA;YAC1C,MAAMP,WAAAA,EAAaQ,OAAO,OAAOC,GAAAA,GAAAA;AAC/B,gBAAA,MAAM,EAAEC,IAAI,EAAEC,KAAK,EAAE,GAAGN,IAAAA;gBACxB,MAAMO,KAAAA,GAAQC,gBAAgBd,MAAQU,EAAAA,GAAAA,CAAAA;gBAEtC,MAAMK,eAAAA,GAAkBJ,KAAKK,GAAG;gBAChC,MAAMC,gBAAAA,GAAmBL,MAAMI,GAAG;;AAGlCL,gBAAAA,IAAAA,CAAKK,GAAG,GAAGjB,KAAAA,CAAMY,IAAKO,CAAAA,IAAI,EAAEH,eAAoBA,CAAAA,IAAAA,eAAAA;AAChDH,gBAAAA,KAAAA,CAAMI,GAAG,GAAGjB,KAAAA,CAAMa,KAAMM,CAAAA,IAAI,EAAED,gBAAqBA,CAAAA,IAAAA,gBAAAA;gBAEnD,IAAI;oBACF,MAAMJ,KAAAA,EAAAA,CAAQM,MAAM,CAACb,IAAAA,CAAAA;AACvB,iBAAA,CAAE,OAAOf,CAAG,EAAA;AACV,oBAAA,IAAIA,aAAa6B,KAAO,EAAA;AACtB,wBAAA,IAAI9B,4BAA4BC,CAAI,CAAA,EAAA;AAClCW,4BAAAA,SAAAA,GACE,CAAC,cAAc,EAAES,KAAKO,IAAI,CAAC,CAAC,EAAEH,eAAAA,CAAgB,IAAI,EAAEH,MAAMM,IAAI,CAAC,CAAC,EAAED,gBAAAA,CAAiB,iCAAiC,CAAC,CAAA;AAEvH,4BAAA,OAAOT,QAAS,CAAA,IAAA,CAAA;AAClB;AACA,wBAAA,OAAOA,QAASjB,CAAAA,CAAAA,CAAAA;AAClB;oBAEA,OAAOiB,QAAAA,CACL,IAAIa,qBAAAA,CACF,CAAC,2CAA2C,EAAEV,IAAKO,CAAAA,IAAI,CAAC,MAAM,CAAC,CAAA,CAAA;AAGrE;gBAEAV,QAAS,CAAA,IAAA,CAAA;AACX,aAAA,CAAA;AACF;AACF,KAAA,CAAA;AACF;;;;"}