@strapi/data-transfer 4.7.0 → 4.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/encryption/decrypt.d.ts +3 -0
  2. package/dist/encryption/decrypt.js +39 -0
  3. package/dist/encryption/encrypt.d.ts +3 -0
  4. package/dist/encryption/encrypt.js +39 -0
  5. package/dist/encryption/index.d.ts +2 -0
  6. package/dist/encryption/index.js +19 -0
  7. package/dist/engine/index.d.ts +29 -0
  8. package/dist/engine/index.js +324 -0
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.js +19 -0
  11. package/dist/providers/index.d.ts +4 -0
  12. package/dist/providers/index.js +23 -0
  13. package/dist/providers/local-file-destination-provider.d.ts +41 -0
  14. package/dist/providers/local-file-destination-provider.js +195 -0
  15. package/dist/providers/local-file-source-provider.d.ts +43 -0
  16. package/dist/providers/local-file-source-provider.js +162 -0
  17. package/dist/providers/local-strapi-destination-provider.d.ts +22 -0
  18. package/dist/providers/local-strapi-destination-provider.js +78 -0
  19. package/dist/providers/local-strapi-source-provider/configuration.d.ts +5 -0
  20. package/dist/providers/local-strapi-source-provider/configuration.js +37 -0
  21. package/dist/providers/local-strapi-source-provider/entities.d.ts +10 -0
  22. package/dist/providers/local-strapi-source-provider/entities.js +58 -0
  23. package/dist/providers/local-strapi-source-provider/index.d.ts +26 -0
  24. package/dist/providers/local-strapi-source-provider/index.js +83 -0
  25. package/dist/providers/local-strapi-source-provider/links/index.d.ts +5 -0
  26. package/dist/providers/local-strapi-source-provider/links/index.js +37 -0
  27. package/dist/providers/local-strapi-source-provider/links/utils.d.ts +27 -0
  28. package/dist/providers/local-strapi-source-provider/links/utils.js +155 -0
  29. package/dist/strategies/index.d.ts +7 -0
  30. package/dist/strategies/index.js +29 -0
  31. package/dist/utils.d.ts +10 -0
  32. package/dist/utils.js +90 -0
  33. package/package.json +4 -4
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ var _LocalFileDestinationProvider_instances, _LocalFileDestinationProvider_providersMetadata, _LocalFileDestinationProvider_archive, _LocalFileDestinationProvider_archivePath_get, _LocalFileDestinationProvider_getDataTransformers, _LocalFileDestinationProvider_writeMetadata, _LocalFileDestinationProvider_getMetadataStream;
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.createLocalFileDestinationProvider = void 0;
13
+ const fs_extra_1 = __importDefault(require("fs-extra"));
14
+ const path_1 = __importDefault(require("path"));
15
+ const tar_stream_1 = __importDefault(require("tar-stream"));
16
+ const zlib_1 = __importDefault(require("zlib"));
17
+ const stream_1 = require("stream");
18
+ const Stringer_1 = require("stream-json/jsonl/Stringer");
19
+ const stream_chain_1 = require("stream-chain");
20
+ const encrypt_1 = require("../encryption/encrypt");
21
+ const createLocalFileDestinationProvider = (options) => {
22
+ return new LocalFileDestinationProvider(options);
23
+ };
24
+ exports.createLocalFileDestinationProvider = createLocalFileDestinationProvider;
25
+ class LocalFileDestinationProvider {
26
+ constructor(options) {
27
+ _LocalFileDestinationProvider_instances.add(this);
28
+ this.name = 'destination::local-file';
29
+ this.type = 'destination';
30
+ this.results = {};
31
+ _LocalFileDestinationProvider_providersMetadata.set(this, {});
32
+ _LocalFileDestinationProvider_archive.set(this, {});
33
+ this.options = options;
34
+ }
35
+ setMetadata(target, metadata) {
36
+ __classPrivateFieldGet(this, _LocalFileDestinationProvider_providersMetadata, "f")[target] = metadata;
37
+ return this;
38
+ }
39
+ bootstrap() {
40
+ const { compression, encryption } = this.options;
41
+ if (encryption.enabled && !encryption.key) {
42
+ throw new Error("Can't encrypt without a key");
43
+ }
44
+ __classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f").stream = tar_stream_1.default.pack();
45
+ const outStream = fs_extra_1.default.createWriteStream(__classPrivateFieldGet(this, _LocalFileDestinationProvider_instances, "a", _LocalFileDestinationProvider_archivePath_get));
46
+ const archiveTransforms = [];
47
+ if (compression.enabled) {
48
+ archiveTransforms.push(zlib_1.default.createGzip());
49
+ }
50
+ if (encryption.enabled && encryption.key) {
51
+ archiveTransforms.push((0, encrypt_1.createEncryptionCipher)(encryption.key));
52
+ }
53
+ __classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f").pipeline = (0, stream_chain_1.chain)([__classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f").stream, ...archiveTransforms, outStream]);
54
+ this.results.file = { path: __classPrivateFieldGet(this, _LocalFileDestinationProvider_instances, "a", _LocalFileDestinationProvider_archivePath_get) };
55
+ }
56
+ async close() {
57
+ const { stream, pipeline } = __classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f");
58
+ if (!stream) {
59
+ return;
60
+ }
61
+ await __classPrivateFieldGet(this, _LocalFileDestinationProvider_instances, "m", _LocalFileDestinationProvider_writeMetadata).call(this);
62
+ stream.finalize();
63
+ if (pipeline && !pipeline.closed) {
64
+ await new Promise((resolve, reject) => {
65
+ pipeline.on('close', resolve).on('error', reject);
66
+ });
67
+ }
68
+ }
69
+ async rollback() {
70
+ await this.close();
71
+ fs_extra_1.default.rmSync(__classPrivateFieldGet(this, _LocalFileDestinationProvider_instances, "a", _LocalFileDestinationProvider_archivePath_get), { force: true });
72
+ }
73
+ getMetadata() {
74
+ return null;
75
+ }
76
+ getSchemasStream() {
77
+ if (!__classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f").stream) {
78
+ throw new Error('Archive stream is unavailable');
79
+ }
80
+ const filePathFactory = createFilePathFactory('schemas');
81
+ const entryStream = createTarEntryStream(__classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f").stream, filePathFactory, this.options.file.maxSize);
82
+ return (0, stream_chain_1.chain)([(0, Stringer_1.stringer)(), entryStream]);
83
+ }
84
+ getEntitiesStream() {
85
+ if (!__classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f").stream) {
86
+ throw new Error('Archive stream is unavailable');
87
+ }
88
+ const filePathFactory = createFilePathFactory('entities');
89
+ const entryStream = createTarEntryStream(__classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f").stream, filePathFactory, this.options.file.maxSize);
90
+ return (0, stream_chain_1.chain)([(0, Stringer_1.stringer)(), entryStream]);
91
+ }
92
+ getLinksStream() {
93
+ if (!__classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f").stream) {
94
+ throw new Error('Archive stream is unavailable');
95
+ }
96
+ const filePathFactory = createFilePathFactory('links');
97
+ const entryStream = createTarEntryStream(__classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f").stream, filePathFactory, this.options.file.maxSize);
98
+ return (0, stream_chain_1.chain)([(0, Stringer_1.stringer)(), entryStream]);
99
+ }
100
+ getConfigurationStream() {
101
+ if (!__classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f").stream) {
102
+ throw new Error('Archive stream is unavailable');
103
+ }
104
+ const filePathFactory = createFilePathFactory('configuration');
105
+ const entryStream = createTarEntryStream(__classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f").stream, filePathFactory, this.options.file.maxSize);
106
+ return (0, stream_chain_1.chain)([(0, Stringer_1.stringer)(), entryStream]);
107
+ }
108
+ }
109
+ _LocalFileDestinationProvider_providersMetadata = new WeakMap(), _LocalFileDestinationProvider_archive = new WeakMap(), _LocalFileDestinationProvider_instances = new WeakSet(), _LocalFileDestinationProvider_archivePath_get = function _LocalFileDestinationProvider_archivePath_get() {
110
+ const { encryption, compression, file } = this.options;
111
+ let path = `${file.path}.tar`;
112
+ if (compression.enabled) {
113
+ path += '.gz';
114
+ }
115
+ if (encryption.enabled) {
116
+ path += '.enc';
117
+ }
118
+ return path;
119
+ }, _LocalFileDestinationProvider_getDataTransformers = function _LocalFileDestinationProvider_getDataTransformers(options = {}) {
120
+ const { jsonl = true } = options;
121
+ const transforms = [];
122
+ if (jsonl) {
123
+ // Convert to stringified JSON lines
124
+ transforms.push((0, Stringer_1.stringer)());
125
+ }
126
+ return transforms;
127
+ }, _LocalFileDestinationProvider_writeMetadata = async function _LocalFileDestinationProvider_writeMetadata() {
128
+ const metadata = __classPrivateFieldGet(this, _LocalFileDestinationProvider_providersMetadata, "f").source;
129
+ if (metadata) {
130
+ await new Promise((resolve) => {
131
+ const outStream = __classPrivateFieldGet(this, _LocalFileDestinationProvider_instances, "m", _LocalFileDestinationProvider_getMetadataStream).call(this);
132
+ const data = JSON.stringify(metadata, null, 2);
133
+ stream_1.Readable.from(data).pipe(outStream).on('close', resolve);
134
+ });
135
+ }
136
+ }, _LocalFileDestinationProvider_getMetadataStream = function _LocalFileDestinationProvider_getMetadataStream() {
137
+ const { stream } = __classPrivateFieldGet(this, _LocalFileDestinationProvider_archive, "f");
138
+ if (!stream) {
139
+ throw new Error('Archive stream is unavailable');
140
+ }
141
+ return createTarEntryStream(stream, () => 'metadata.json');
142
+ };
143
+ /**
144
+ * Create a file path factory for a given path & prefix.
145
+ * Upon being called, the factory will return a file path for a given index
146
+ */
147
+ const createFilePathFactory = (type) => (fileIndex = 0) => {
148
+ return path_1.default.join(
149
+ // "{type}" directory
150
+ type,
151
+ // "${type}_XXXXX.jsonl" file
152
+ `${type}_${String(fileIndex).padStart(5, '0')}.jsonl`);
153
+ };
154
+ const createTarEntryStream = (archive, pathFactory, maxSize = 2.56e8) => {
155
+ let fileIndex = 0;
156
+ let buffer = '';
157
+ const flush = async () => {
158
+ if (!buffer) {
159
+ return;
160
+ }
161
+ const name = pathFactory(fileIndex++);
162
+ const size = buffer.length;
163
+ await new Promise((resolve, reject) => {
164
+ archive.entry({ name, size }, buffer, (err) => {
165
+ if (err) {
166
+ reject(err);
167
+ }
168
+ resolve();
169
+ });
170
+ });
171
+ buffer = '';
172
+ };
173
+ const push = (chunk) => {
174
+ buffer += chunk;
175
+ };
176
+ return new stream_1.Writable({
177
+ async destroy(err, callback) {
178
+ await flush();
179
+ callback(err);
180
+ },
181
+ async write(chunk, _encoding, callback) {
182
+ const size = chunk.length;
183
+ if (chunk.length > maxSize) {
184
+ callback(new Error(`payload too large: ${chunk.length}>${maxSize}`));
185
+ return;
186
+ }
187
+ if (buffer.length + size > maxSize) {
188
+ await flush();
189
+ }
190
+ push(chunk);
191
+ callback(null);
192
+ },
193
+ });
194
+ };
195
+ //# sourceMappingURL=local-file-destination-provider.js.map
@@ -0,0 +1,43 @@
1
+ /// <reference types="lodash" />
2
+ /// <reference types="node" />
3
+ import type { IMetadata, ISourceProvider, ProviderType } from '../../types';
4
+ /**
5
+ * Provider options
6
+ */
7
+ export interface ILocalFileSourceProviderOptions {
8
+ /**
9
+ * Path to the backup archive
10
+ */
11
+ backupFilePath: string;
12
+ /**
13
+ * Whether the backup data is encrypted or not
14
+ */
15
+ encrypted?: boolean;
16
+ /**
17
+ * Encryption key used to decrypt the encrypted data (if necessary)
18
+ */
19
+ encryptionKey?: string;
20
+ /**
21
+ * Whether the backup data is compressed or not
22
+ */
23
+ compressed?: boolean;
24
+ }
25
+ export declare const createLocalFileSourceProvider: (options: ILocalFileSourceProviderOptions) => LocalFileSourceProvider;
26
+ declare class LocalFileSourceProvider implements ISourceProvider {
27
+ #private;
28
+ type: ProviderType;
29
+ name: string;
30
+ options: ILocalFileSourceProviderOptions;
31
+ constructor(options: ILocalFileSourceProviderOptions);
32
+ /**
33
+ * Pre flight checks regarding the provided options (making sure that the provided path is correct, etc...)
34
+ */
35
+ bootstrap(): void;
36
+ getMetadata(): Promise<IMetadata>;
37
+ getSchemas(): Promise<import("lodash").Dictionary<unknown>>;
38
+ streamEntities(): NodeJS.ReadableStream;
39
+ streamSchemas(): NodeJS.ReadableStream | Promise<NodeJS.ReadableStream>;
40
+ streamLinks(): NodeJS.ReadableStream;
41
+ streamConfiguration(): NodeJS.ReadableStream;
42
+ }
43
+ export {};
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ var _LocalFileSourceProvider_instances, _LocalFileSourceProvider_getBackupStream, _LocalFileSourceProvider_streamJsonlDirectory, _LocalFileSourceProvider_parseJSONFile;
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.createLocalFileSourceProvider = void 0;
13
+ const fs_1 = __importDefault(require("fs"));
14
+ const zlib_1 = __importDefault(require("zlib"));
15
+ const tar_1 = __importDefault(require("tar"));
16
+ const fp_1 = require("lodash/fp");
17
+ const stream_chain_1 = require("stream-chain");
18
+ const stream_1 = require("stream");
19
+ const Parser_1 = require("stream-json/jsonl/Parser");
20
+ const encryption_1 = require("../encryption");
21
+ const utils_1 = require("../utils");
22
+ /**
23
+ * Constant for the metadata file path
24
+ */
25
+ const METADATA_FILE_PATH = 'metadata.json';
26
+ const createLocalFileSourceProvider = (options) => {
27
+ return new LocalFileSourceProvider(options);
28
+ };
29
+ exports.createLocalFileSourceProvider = createLocalFileSourceProvider;
30
+ class LocalFileSourceProvider {
31
+ constructor(options) {
32
+ _LocalFileSourceProvider_instances.add(this);
33
+ this.type = 'source';
34
+ this.name = 'source::local-file';
35
+ this.options = options;
36
+ if (this.options.encrypted && this.options.encryptionKey === undefined) {
37
+ throw new Error('Missing encryption key');
38
+ }
39
+ }
40
+ /**
41
+ * Pre flight checks regarding the provided options (making sure that the provided path is correct, etc...)
42
+ */
43
+ bootstrap() {
44
+ const path = this.options.backupFilePath;
45
+ const isValidBackupPath = fs_1.default.existsSync(path);
46
+ // Check if the provided path exists
47
+ if (!isValidBackupPath) {
48
+ throw new Error(`Invalid backup file path provided. "${path}" does not exist on the filesystem.`);
49
+ }
50
+ }
51
+ getMetadata() {
52
+ // TODO: need to read the file & extract the metadata json file
53
+ // => we might also need to read the schema.jsonl files & implements a custom stream-check
54
+ const backupStream = __classPrivateFieldGet(this, _LocalFileSourceProvider_instances, "m", _LocalFileSourceProvider_getBackupStream).call(this);
55
+ return __classPrivateFieldGet(this, _LocalFileSourceProvider_instances, "m", _LocalFileSourceProvider_parseJSONFile).call(this, backupStream, METADATA_FILE_PATH);
56
+ }
57
+ async getSchemas() {
58
+ const schemas = await (0, utils_1.collect)(this.streamSchemas());
59
+ return (0, fp_1.keyBy)('uid', schemas);
60
+ }
61
+ streamEntities() {
62
+ return __classPrivateFieldGet(this, _LocalFileSourceProvider_instances, "m", _LocalFileSourceProvider_streamJsonlDirectory).call(this, 'entities');
63
+ }
64
+ streamSchemas() {
65
+ return __classPrivateFieldGet(this, _LocalFileSourceProvider_instances, "m", _LocalFileSourceProvider_streamJsonlDirectory).call(this, 'schemas');
66
+ }
67
+ streamLinks() {
68
+ return __classPrivateFieldGet(this, _LocalFileSourceProvider_instances, "m", _LocalFileSourceProvider_streamJsonlDirectory).call(this, 'links');
69
+ }
70
+ streamConfiguration() {
71
+ // NOTE: TBD
72
+ return __classPrivateFieldGet(this, _LocalFileSourceProvider_instances, "m", _LocalFileSourceProvider_streamJsonlDirectory).call(this, 'configuration');
73
+ }
74
+ }
75
+ _LocalFileSourceProvider_instances = new WeakSet(), _LocalFileSourceProvider_getBackupStream = function _LocalFileSourceProvider_getBackupStream(decompress = true) {
76
+ const path = this.options.backupFilePath;
77
+ const readStream = fs_1.default.createReadStream(path);
78
+ const streams = [readStream];
79
+ // Handle decompression
80
+ if (decompress) {
81
+ streams.push(zlib_1.default.createGunzip());
82
+ }
83
+ return (0, stream_chain_1.chain)(streams);
84
+ }, _LocalFileSourceProvider_streamJsonlDirectory = function _LocalFileSourceProvider_streamJsonlDirectory(directory) {
85
+ const options = this.options;
86
+ const inStream = __classPrivateFieldGet(this, _LocalFileSourceProvider_instances, "m", _LocalFileSourceProvider_getBackupStream).call(this);
87
+ const outStream = new stream_1.PassThrough({ objectMode: true });
88
+ (0, stream_1.pipeline)([
89
+ inStream,
90
+ new tar_1.default.Parse({
91
+ filter(path, entry) {
92
+ if (entry.type !== 'File') {
93
+ return false;
94
+ }
95
+ const parts = path.split('/');
96
+ if (parts.length !== 2) {
97
+ return false;
98
+ }
99
+ return parts[0] === directory;
100
+ },
101
+ onentry(entry) {
102
+ const transforms = [];
103
+ if (options.encrypted) {
104
+ transforms.push((0, encryption_1.createDecryptionCipher)(options.encryptionKey));
105
+ }
106
+ if (options.compressed) {
107
+ transforms.push(zlib_1.default.createGunzip());
108
+ }
109
+ transforms.push(
110
+ // JSONL parser to read the data chunks one by one (line by line)
111
+ (0, Parser_1.parser)(),
112
+ // The JSONL parser returns each line as key/value
113
+ (line) => line.value);
114
+ entry
115
+ // Pipe transforms
116
+ .pipe((0, stream_chain_1.chain)(transforms))
117
+ // Pipe the out stream to the whole pipeline
118
+ // DO NOT send the 'end' event when this entry has finished
119
+ // emitting data, so that it doesn't close the out stream
120
+ .pipe(outStream, { end: false });
121
+ },
122
+ }),
123
+ ], () => {
124
+ // Manually send the 'end' event to the out stream
125
+ // once every entry has finished streaming its content
126
+ outStream.end();
127
+ });
128
+ return outStream;
129
+ }, _LocalFileSourceProvider_parseJSONFile = async function _LocalFileSourceProvider_parseJSONFile(fileStream, filePath) {
130
+ return new Promise((resolve, reject) => {
131
+ (0, stream_1.pipeline)([
132
+ fileStream,
133
+ // Custom backup archive parsing
134
+ new tar_1.default.Parse({
135
+ /**
136
+ * Filter the parsed entries to only keep the one that matches the given filepath
137
+ */
138
+ filter(path, entry) {
139
+ return path === filePath && entry.type === 'File';
140
+ },
141
+ /**
142
+ * Whenever an entry passes the filter method, process it
143
+ */
144
+ async onentry(entry) {
145
+ // Collect all the content of the entry file
146
+ const content = await entry.collect();
147
+ // Parse from buffer to string to JSON
148
+ const parsedContent = JSON.parse(content.toString());
149
+ // Resolve the Promise with the parsed content
150
+ resolve(parsedContent);
151
+ // Cleanup (close the stream associated to the entry)
152
+ entry.destroy();
153
+ },
154
+ }),
155
+ ], () => {
156
+ // If the promise hasn't been resolved and we've parsed all
157
+ // the archive entries, then the file doesn't exist
158
+ reject(`${filePath} not found in the archive stream`);
159
+ });
160
+ });
161
+ };
162
+ //# sourceMappingURL=local-file-source-provider.js.map
@@ -0,0 +1,22 @@
1
+ /// <reference types="node" />
2
+ import type { IDestinationProvider, IMetadata, ProviderType } from '../../types';
3
+ import { Duplex } from 'stream';
4
+ interface ILocalStrapiDestinationProviderOptions {
5
+ getStrapi(): Promise<Strapi.Strapi>;
6
+ }
7
+ export declare const createLocalStrapiDestinationProvider: (options: ILocalStrapiDestinationProviderOptions) => LocalStrapiDestinationProvider;
8
+ declare class LocalStrapiDestinationProvider implements IDestinationProvider {
9
+ name: string;
10
+ type: ProviderType;
11
+ options: ILocalStrapiDestinationProviderOptions;
12
+ strapi?: Strapi.Strapi;
13
+ constructor(options: ILocalStrapiDestinationProviderOptions);
14
+ bootstrap(): Promise<void>;
15
+ close(): Promise<void>;
16
+ getMetadata(): IMetadata | Promise<IMetadata>;
17
+ getSchemas(): {
18
+ [x: string]: Partial<any>;
19
+ };
20
+ getEntitiesStream(): Duplex;
21
+ }
22
+ export {};
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createLocalStrapiDestinationProvider = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const stream_1 = require("stream");
9
+ const utils_1 = require("../utils");
10
+ // TODO: getting some type errors with @strapi/logger that need to be resolved first
11
+ // const log = createLogger();
12
+ const log = console;
13
+ const createLocalStrapiDestinationProvider = (options) => {
14
+ return new LocalStrapiDestinationProvider(options);
15
+ };
16
+ exports.createLocalStrapiDestinationProvider = createLocalStrapiDestinationProvider;
17
+ class LocalStrapiDestinationProvider {
18
+ constructor(options) {
19
+ this.name = 'destination::local-strapi';
20
+ this.type = 'destination';
21
+ this.options = options;
22
+ }
23
+ async bootstrap() {
24
+ this.strapi = await this.options.getStrapi();
25
+ }
26
+ async close() {
27
+ await this.strapi?.destroy?.();
28
+ }
29
+ // TODO
30
+ getMetadata() {
31
+ return {};
32
+ }
33
+ getSchemas() {
34
+ if (!this.strapi) {
35
+ throw new Error('Not able to get Schemas. Strapi instance not found');
36
+ }
37
+ const schemas = {
38
+ ...this.strapi.contentTypes,
39
+ ...this.strapi.components,
40
+ };
41
+ return (0, utils_1.mapSchemasValues)(schemas);
42
+ }
43
+ getEntitiesStream() {
44
+ const self = this;
45
+ return new stream_1.Duplex({
46
+ objectMode: true,
47
+ async write(entity, _encoding, callback) {
48
+ if (!self.strapi) {
49
+ callback(new Error('Strapi instance not found'));
50
+ }
51
+ const { type: uid, id, data } = entity;
52
+ try {
53
+ await strapi.entityService.create(uid, { data });
54
+ }
55
+ catch (e) {
56
+ // TODO: remove "any" cast
57
+ log.warn(chalk_1.default.bold(`Failed to import ${chalk_1.default.yellowBright(uid)} (${chalk_1.default.greenBright(id)})`));
58
+ e.details.errors
59
+ .map((err, i) => {
60
+ // TODO: add correct error type
61
+ const info = {
62
+ uid: chalk_1.default.yellowBright(`[${uid}]`),
63
+ path: chalk_1.default.blueBright(`[${err.path.join('.')}]`),
64
+ id: chalk_1.default.greenBright(`[${id}]`),
65
+ message: err.message,
66
+ };
67
+ return `(${i}) ${info.uid}${info.id}${info.path}: ${info.message}`;
68
+ })
69
+ .forEach((message) => log.warn(message));
70
+ }
71
+ finally {
72
+ callback();
73
+ }
74
+ },
75
+ });
76
+ }
77
+ }
78
+ //# sourceMappingURL=local-strapi-destination-provider.js.map
@@ -0,0 +1,5 @@
1
+ import { Readable } from 'stream';
2
+ /**
3
+ * Create a readable stream that export the Strapi app configuration
4
+ */
5
+ export declare const createConfigurationStream: (strapi: Strapi.Strapi) => Readable;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createConfigurationStream = void 0;
4
+ const stream_chain_1 = require("stream-chain");
5
+ const stream_1 = require("stream");
6
+ const fp_1 = require("lodash/fp");
7
+ /**
8
+ * Create a readable stream that export the Strapi app configuration
9
+ */
10
+ const createConfigurationStream = (strapi) => {
11
+ // Core Store
12
+ const coreStoreStream = (0, stream_chain_1.chain)([
13
+ strapi.db.queryBuilder('strapi::core-store').stream(),
14
+ (data) => (0, fp_1.set)('value', JSON.parse(data.value), data),
15
+ wrapConfigurationItem('core-store'),
16
+ ]);
17
+ // Webhook
18
+ const webhooksStream = (0, stream_chain_1.chain)([
19
+ strapi.db.queryBuilder('webhook').stream(),
20
+ wrapConfigurationItem('webhook'),
21
+ ]);
22
+ const streams = [coreStoreStream, webhooksStream];
23
+ // Readable configuration stream
24
+ return stream_1.Readable.from((async function* () {
25
+ for (const stream of streams) {
26
+ for await (const item of stream) {
27
+ yield item;
28
+ }
29
+ }
30
+ })());
31
+ };
32
+ exports.createConfigurationStream = createConfigurationStream;
33
+ const wrapConfigurationItem = (type) => (value) => ({
34
+ type,
35
+ value,
36
+ });
37
+ //# sourceMappingURL=configuration.js.map
@@ -0,0 +1,10 @@
1
+ import { Readable, PassThrough } from 'stream';
2
+ /**
3
+ * Generate and consume content-types streams in order to stream each entity individually
4
+ */
5
+ export declare const createEntitiesStream: (strapi: Strapi.Strapi) => Readable;
6
+ /**
7
+ * Create an entity transform stream which convert the output of
8
+ * the multi-content-types stream to the transfer entity format
9
+ */
10
+ export declare const createEntitiesTransformStream: () => PassThrough;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createEntitiesTransformStream = exports.createEntitiesStream = void 0;
4
+ const stream_1 = require("stream");
5
+ /**
6
+ * Generate and consume content-types streams in order to stream each entity individually
7
+ */
8
+ const createEntitiesStream = (strapi) => {
9
+ const contentTypes = Object.values(strapi.contentTypes);
10
+ async function* contentTypeStreamGenerator() {
11
+ for (const contentType of contentTypes) {
12
+ const stream = strapi.db
13
+ // Create a query builder instance (default type is 'select')
14
+ .queryBuilder(contentType.uid)
15
+ // Apply the populate
16
+ .populate(getPopulateAttributes(contentType))
17
+ // Get a readable stream
18
+ .stream();
19
+ yield { contentType, stream };
20
+ }
21
+ }
22
+ return stream_1.Readable.from((async function* () {
23
+ for await (const { stream, contentType } of contentTypeStreamGenerator()) {
24
+ for await (const entity of stream) {
25
+ yield { entity, contentType };
26
+ }
27
+ stream.destroy();
28
+ }
29
+ })());
30
+ };
31
+ exports.createEntitiesStream = createEntitiesStream;
32
+ /**
33
+ * Create an entity transform stream which convert the output of
34
+ * the multi-content-types stream to the transfer entity format
35
+ */
36
+ const createEntitiesTransformStream = () => {
37
+ return new stream_1.PassThrough({
38
+ objectMode: true,
39
+ transform(data, _encoding, callback) {
40
+ const { entity, contentType } = data;
41
+ const { id, ...attributes } = entity;
42
+ callback(null, {
43
+ type: contentType.uid,
44
+ id,
45
+ data: attributes,
46
+ });
47
+ },
48
+ });
49
+ };
50
+ exports.createEntitiesTransformStream = createEntitiesTransformStream;
51
+ /**
52
+ * Get the list of attributes that needs to be populated for the entities streaming
53
+ */
54
+ const getPopulateAttributes = (contentType) => {
55
+ const { attributes } = contentType;
56
+ return Object.keys(attributes).filter((key) => ['component', 'dynamiczone'].includes(attributes[key].type));
57
+ };
58
+ //# sourceMappingURL=entities.js.map
@@ -0,0 +1,26 @@
1
+ /// <reference types="node" />
2
+ import type { IMetadata, ISourceProvider, ProviderType } from '../../../types';
3
+ export interface ILocalStrapiSourceProviderOptions {
4
+ getStrapi(): Strapi.Strapi | Promise<Strapi.Strapi>;
5
+ autoDestroy?: boolean;
6
+ }
7
+ export declare const createLocalStrapiSourceProvider: (options: ILocalStrapiSourceProviderOptions) => LocalStrapiSourceProvider;
8
+ declare class LocalStrapiSourceProvider implements ISourceProvider {
9
+ name: string;
10
+ type: ProviderType;
11
+ options: ILocalStrapiSourceProviderOptions;
12
+ strapi?: Strapi.Strapi;
13
+ constructor(options: ILocalStrapiSourceProviderOptions);
14
+ bootstrap(): Promise<void>;
15
+ close(): Promise<void>;
16
+ getMetadata(): IMetadata;
17
+ streamEntities(): Promise<NodeJS.ReadableStream>;
18
+ streamLinks(): NodeJS.ReadableStream;
19
+ streamConfiguration(): NodeJS.ReadableStream;
20
+ getSchemas(): {
21
+ [x: string]: Partial<any>;
22
+ };
23
+ streamSchemas(): NodeJS.ReadableStream;
24
+ }
25
+ export declare type ILocalStrapiSourceProvider = InstanceType<typeof LocalStrapiSourceProvider>;
26
+ export {};