@strapi/data-transfer 4.9.0-alpha.0 → 4.9.0-beta.2

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 (48) hide show
  1. package/lib/engine/index.d.ts +2 -1
  2. package/lib/engine/index.js +67 -7
  3. package/lib/errors/constants.d.ts +1 -1
  4. package/lib/file/providers/destination/index.js +7 -0
  5. package/lib/strapi/index.d.ts +0 -1
  6. package/lib/strapi/index.js +1 -6
  7. package/lib/strapi/providers/index.d.ts +1 -0
  8. package/lib/strapi/providers/index.js +1 -0
  9. package/lib/strapi/providers/local-destination/index.d.ts +1 -1
  10. package/lib/strapi/providers/local-destination/index.js +9 -4
  11. package/lib/strapi/providers/remote-destination/index.d.ts +5 -8
  12. package/lib/strapi/providers/remote-destination/index.js +157 -59
  13. package/lib/strapi/providers/remote-source/index.d.ts +36 -0
  14. package/lib/strapi/providers/remote-source/index.js +228 -0
  15. package/lib/strapi/providers/{remote-destination/utils.d.ts → utils.d.ts} +3 -3
  16. package/lib/strapi/providers/{remote-destination/utils.js → utils.js} +2 -2
  17. package/lib/strapi/remote/constants.d.ts +4 -2
  18. package/lib/strapi/remote/constants.js +1 -1
  19. package/lib/strapi/remote/flows/default.d.ts +3 -0
  20. package/lib/strapi/remote/flows/default.js +41 -0
  21. package/lib/strapi/remote/flows/index.d.ts +18 -0
  22. package/lib/strapi/remote/flows/index.js +59 -0
  23. package/lib/strapi/remote/handlers/abstract.d.ts +62 -0
  24. package/lib/strapi/remote/handlers/abstract.js +3 -0
  25. package/lib/strapi/remote/handlers/constants.d.ts +2 -0
  26. package/lib/strapi/remote/handlers/constants.js +5 -0
  27. package/lib/strapi/remote/handlers/index.d.ts +3 -0
  28. package/lib/strapi/remote/handlers/index.js +10 -0
  29. package/lib/strapi/remote/handlers/pull.d.ts +22 -0
  30. package/lib/strapi/remote/handlers/pull.js +186 -0
  31. package/lib/strapi/remote/handlers/push.d.ts +75 -0
  32. package/lib/strapi/remote/handlers/push.js +297 -0
  33. package/lib/strapi/remote/handlers/utils.d.ts +25 -0
  34. package/lib/strapi/remote/handlers/utils.js +181 -0
  35. package/lib/strapi/remote/index.d.ts +1 -2
  36. package/lib/strapi/remote/index.js +2 -3
  37. package/lib/utils/transaction.js +21 -3
  38. package/package.json +8 -7
  39. package/lib/strapi/register.d.ts +0 -7
  40. package/lib/strapi/register.js +0 -13
  41. package/lib/strapi/remote/controllers/index.d.ts +0 -1
  42. package/lib/strapi/remote/controllers/index.js +0 -18
  43. package/lib/strapi/remote/controllers/push.d.ts +0 -25
  44. package/lib/strapi/remote/controllers/push.js +0 -95
  45. package/lib/strapi/remote/handlers.d.ts +0 -3
  46. package/lib/strapi/remote/handlers.js +0 -193
  47. package/lib/strapi/remote/routes.d.ts +0 -21
  48. package/lib/strapi/remote/routes.js +0 -22
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handlerControllerFactory = exports.handleWSUpgrade = exports.isDataTransferMessage = exports.assertValidHeader = exports.transformUpgradeHeader = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const ws_1 = require("ws");
6
+ const providers_1 = require("../../../errors/providers");
7
+ const constants_1 = require("./constants");
8
+ const transformUpgradeHeader = (header = '') => {
9
+ return header.split(',').map((s) => s.trim().toLowerCase());
10
+ };
11
+ exports.transformUpgradeHeader = transformUpgradeHeader;
12
+ /**
13
+ * Make sure that the upgrade header is a valid websocket one
14
+ */
15
+ const assertValidHeader = (ctx) => {
16
+ const upgradeHeader = (0, exports.transformUpgradeHeader)(ctx.headers.upgrade);
17
+ if (!upgradeHeader.includes('websocket')) {
18
+ throw new Error('Invalid Header');
19
+ }
20
+ };
21
+ exports.assertValidHeader = assertValidHeader;
22
+ const isDataTransferMessage = (message) => {
23
+ if (!message || typeof message !== 'object') {
24
+ return false;
25
+ }
26
+ const { uuid, type } = message;
27
+ if (typeof uuid !== 'string' || typeof type !== 'string') {
28
+ return false;
29
+ }
30
+ if (!['command', 'transfer'].includes(type)) {
31
+ return false;
32
+ }
33
+ return true;
34
+ };
35
+ exports.isDataTransferMessage = isDataTransferMessage;
36
+ /**
37
+ * Handle the upgrade to ws connection
38
+ */
39
+ const handleWSUpgrade = (wss, ctx, callback) => {
40
+ (0, exports.assertValidHeader)(ctx);
41
+ wss.handleUpgrade(ctx.req, ctx.request.socket, Buffer.alloc(0), (client, request) => {
42
+ // Create a connection between the client & the server
43
+ wss.emit('connection', client, ctx.req);
44
+ // Invoke the ws callback
45
+ callback(client, request);
46
+ });
47
+ ctx.respond = false;
48
+ };
49
+ exports.handleWSUpgrade = handleWSUpgrade;
50
+ // Protocol related functions
51
+ const handlerControllerFactory = (implementation) => (options) => {
52
+ const { verify, server: serverOptions } = options ?? {};
53
+ const wss = new ws_1.WebSocket.Server({ ...serverOptions, noServer: true });
54
+ return async (ctx) => {
55
+ (0, exports.handleWSUpgrade)(wss, ctx, (ws) => {
56
+ const state = { id: undefined };
57
+ const prototype = {
58
+ // Transfer ID
59
+ get transferID() {
60
+ return state.id;
61
+ },
62
+ set transferID(id) {
63
+ state.id = id;
64
+ },
65
+ // Started at
66
+ get startedAt() {
67
+ return state.startedAt;
68
+ },
69
+ set startedAt(timestamp) {
70
+ state.startedAt = timestamp;
71
+ },
72
+ isTransferStarted() {
73
+ return this.transferID !== undefined && this.startedAt !== undefined;
74
+ },
75
+ assertValidTransfer() {
76
+ const isStarted = this.isTransferStarted();
77
+ if (!isStarted) {
78
+ throw new Error('Invalid Transfer Process');
79
+ }
80
+ },
81
+ assertValidTransferCommand(command) {
82
+ const isDefined = typeof this[command] === 'function';
83
+ const isValidTransferCommand = constants_1.VALID_TRANSFER_COMMANDS.includes(command);
84
+ if (!isDefined || !isValidTransferCommand) {
85
+ throw new Error('Invalid transfer command');
86
+ }
87
+ },
88
+ respond(uuid, e, data) {
89
+ return new Promise((resolve, reject) => {
90
+ if (!uuid && !e) {
91
+ reject(new Error('Missing uuid for this message'));
92
+ return;
93
+ }
94
+ const payload = JSON.stringify({
95
+ uuid,
96
+ data: data ?? null,
97
+ error: e
98
+ ? {
99
+ code: e?.name ?? 'ERR',
100
+ message: e?.message,
101
+ }
102
+ : null,
103
+ });
104
+ this.send(payload, (error) => (error ? reject(error) : resolve()));
105
+ });
106
+ },
107
+ send(message, cb) {
108
+ ws.send(message, cb);
109
+ },
110
+ confirm(message) {
111
+ return new Promise((resolve, reject) => {
112
+ const uuid = (0, crypto_1.randomUUID)();
113
+ const payload = JSON.stringify({ uuid, data: message });
114
+ this.send(payload, (error) => {
115
+ if (error) {
116
+ reject(error);
117
+ }
118
+ });
119
+ const onResponse = (raw) => {
120
+ const response = JSON.parse(raw.toString());
121
+ if (response.uuid === uuid) {
122
+ if (response.error) {
123
+ return reject(new Error(response.error.message));
124
+ }
125
+ resolve(response.data ?? null);
126
+ }
127
+ else {
128
+ ws.once('message', onResponse);
129
+ }
130
+ };
131
+ ws.once('message', onResponse);
132
+ });
133
+ },
134
+ async executeAndRespond(uuid, fn) {
135
+ try {
136
+ const response = await fn();
137
+ this.respond(uuid, null, response);
138
+ }
139
+ catch (e) {
140
+ if (e instanceof Error) {
141
+ this.respond(uuid, e);
142
+ }
143
+ else if (typeof e === 'string') {
144
+ this.respond(uuid, new providers_1.ProviderTransferError(e));
145
+ }
146
+ else {
147
+ this.respond(uuid, new providers_1.ProviderTransferError('Unexpected error', {
148
+ error: e,
149
+ }));
150
+ }
151
+ }
152
+ },
153
+ cleanup() {
154
+ this.transferID = undefined;
155
+ this.startedAt = undefined;
156
+ },
157
+ teardown() {
158
+ this.cleanup();
159
+ },
160
+ verifyAuth(scope) {
161
+ return verify(ctx, scope);
162
+ },
163
+ // Transfer commands
164
+ init() { },
165
+ end() { },
166
+ status() { },
167
+ // Default prototype implementation for events
168
+ onMessage() { },
169
+ onError() { },
170
+ onClose() { },
171
+ };
172
+ const handler = Object.assign(Object.create(prototype), implementation(prototype));
173
+ // Bind ws events to handler methods
174
+ ws.on('close', (...args) => handler.onClose(...args));
175
+ ws.on('error', (...args) => handler.onError(...args));
176
+ ws.on('message', (...args) => handler.onMessage(...args));
177
+ });
178
+ };
179
+ };
180
+ exports.handlerControllerFactory = handlerControllerFactory;
181
+ //# sourceMappingURL=utils.js.map
@@ -1,3 +1,2 @@
1
- export * as controllers from './controllers';
2
- export * as routes from './routes';
3
1
  export * as constants from './constants';
2
+ export * as handlers from './handlers';
@@ -23,8 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.constants = exports.routes = exports.controllers = void 0;
27
- exports.controllers = __importStar(require("./controllers"));
28
- exports.routes = __importStar(require("./routes"));
26
+ exports.handlers = exports.constants = void 0;
29
27
  exports.constants = __importStar(require("./constants"));
28
+ exports.handlers = __importStar(require("./handlers"));
30
29
  //# sourceMappingURL=index.js.map
@@ -13,12 +13,26 @@ const createTransaction = (strapi) => {
13
13
  resume?.();
14
14
  });
15
15
  e.on('close', () => {
16
+ e.removeAllListeners('rollback');
17
+ e.removeAllListeners('spawn');
16
18
  done = true;
17
19
  resume?.();
18
20
  });
19
21
  strapi.db.transaction(async ({ trx, rollback }) => {
20
- e.on('rollback', async () => {
21
- await rollback();
22
+ e.once('rollback', async () => {
23
+ e.removeAllListeners('close');
24
+ e.removeAllListeners('spawn');
25
+ try {
26
+ await rollback();
27
+ e.emit('rollback_completed');
28
+ }
29
+ catch {
30
+ e.emit('rollback_failed');
31
+ }
32
+ finally {
33
+ done = true;
34
+ resume?.();
35
+ }
22
36
  });
23
37
  while (!done) {
24
38
  while (fns.length) {
@@ -62,7 +76,11 @@ const createTransaction = (strapi) => {
62
76
  return e.emit('close');
63
77
  },
64
78
  rollback() {
65
- return e.emit('rollback');
79
+ return new Promise((resolve) => {
80
+ e.emit('rollback');
81
+ e.once('rollback_failed', () => resolve(false));
82
+ e.once('rollback_completed', () => resolve(true));
83
+ });
66
84
  },
67
85
  };
68
86
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/data-transfer",
3
- "version": "4.9.0-alpha.0",
3
+ "version": "4.9.0-beta.2",
4
4
  "description": "Data transfer capabilities for Strapi",
5
5
  "keywords": [
6
6
  "strapi",
@@ -39,16 +39,15 @@
39
39
  "lib": "./lib"
40
40
  },
41
41
  "dependencies": {
42
- "@strapi/logger": "4.9.0-alpha.0",
43
- "@strapi/strapi": "4.9.0-alpha.0",
42
+ "@strapi/logger": "4.9.0-beta.2",
43
+ "@strapi/strapi": "4.9.0-beta.2",
44
44
  "chalk": "4.1.2",
45
45
  "fs-extra": "10.0.0",
46
46
  "lodash": "4.17.21",
47
- "prettier": "2.7.1",
48
47
  "semver": "7.3.8",
49
48
  "stream-chain": "2.2.5",
50
49
  "stream-json": "1.7.4",
51
- "tar": "6.1.12",
50
+ "tar": "6.1.13",
52
51
  "tar-stream": "2.2.0",
53
52
  "uuid": "9.0.0",
54
53
  "ws": "8.11.0"
@@ -58,12 +57,14 @@
58
57
  "@types/fs-extra": "9.0.13",
59
58
  "@types/jest": "29.2.0",
60
59
  "@types/koa": "2.13.4",
60
+ "@types/lodash": "^4.14.191",
61
61
  "@types/semver": "7.3.13",
62
62
  "@types/stream-chain": "2.0.1",
63
63
  "@types/stream-json": "1.7.3",
64
- "@types/tar": "6.1.3",
64
+ "@types/tar": "6.1.4",
65
65
  "@types/tar-stream": "2.2.2",
66
66
  "@types/uuid": "9.0.0",
67
+ "@types/ws": "^8.5.4",
67
68
  "knex": "2.4.0",
68
69
  "koa": "2.13.4",
69
70
  "rimraf": "3.0.2",
@@ -73,5 +74,5 @@
73
74
  "node": ">=14.19.1 <=18.x.x",
74
75
  "npm": ">=6.0.0"
75
76
  },
76
- "gitHead": "35f783d0dc07db101e7e62cb4d682f751551f452"
77
+ "gitHead": "d893ead642592a15a95fefb71c544aaabe4db20b"
77
78
  }
@@ -1,7 +0,0 @@
1
- /**
2
- * This is intended to be called on Strapi register phase.
3
- *
4
- * It registers a transfer route in the Strapi admin router.
5
- */
6
- declare const register: (strapi: Strapi.Strapi) => void;
7
- export default register;
@@ -1,13 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const remote_1 = require("./remote");
4
- /**
5
- * This is intended to be called on Strapi register phase.
6
- *
7
- * It registers a transfer route in the Strapi admin router.
8
- */
9
- const register = (strapi) => {
10
- remote_1.routes.registerAdminTransferRoute(strapi);
11
- };
12
- exports.default = register;
13
- //# sourceMappingURL=register.js.map
@@ -1 +0,0 @@
1
- export * from './push';
@@ -1,18 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./push"), exports);
18
- //# sourceMappingURL=index.js.map
@@ -1,25 +0,0 @@
1
- /// <reference types="node" />
2
- import { Writable } from 'stream-chain';
3
- import type { IMetadata } from '../../../../types';
4
- import type { TransferPushMessage, TransferPushStep } from '../../../../types/remote/protocol/client';
5
- import { ILocalStrapiDestinationProviderOptions } from '../../providers';
6
- export interface IPushController {
7
- streams: {
8
- [stage in TransferPushStep]?: Writable;
9
- };
10
- actions: {
11
- getMetadata(): Promise<IMetadata>;
12
- getSchemas(): Strapi.Schemas;
13
- bootstrap(): Promise<void>;
14
- close(): Promise<void>;
15
- beforeTransfer(): Promise<void>;
16
- };
17
- transfer: {
18
- [key in TransferPushStep]: <T extends TransferPushMessage>(value: T extends {
19
- step: key;
20
- data: infer U;
21
- } ? U : never) => Promise<void>;
22
- };
23
- }
24
- declare const createPushController: (options: ILocalStrapiDestinationProviderOptions) => IPushController;
25
- export default createPushController;
@@ -1,95 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const stream_chain_1 = require("stream-chain");
4
- const providers_1 = require("../../providers");
5
- const createPushController = (options) => {
6
- const provider = (0, providers_1.createLocalStrapiDestinationProvider)(options);
7
- const streams = {};
8
- const assets = {};
9
- const writeAsync = (stream, data) => {
10
- return new Promise((resolve, reject) => {
11
- stream.write(data, (error) => {
12
- if (error) {
13
- reject(error);
14
- }
15
- resolve();
16
- });
17
- });
18
- };
19
- return {
20
- streams,
21
- actions: {
22
- async getSchemas() {
23
- return provider.getSchemas();
24
- },
25
- async getMetadata() {
26
- return provider.getMetadata();
27
- },
28
- async bootstrap() {
29
- return provider.bootstrap();
30
- },
31
- async close() {
32
- return provider.close();
33
- },
34
- async beforeTransfer() {
35
- return provider.beforeTransfer();
36
- },
37
- },
38
- transfer: {
39
- async entities(entity) {
40
- if (!streams.entities) {
41
- streams.entities = provider.createEntitiesWriteStream();
42
- }
43
- await writeAsync(streams.entities, entity);
44
- },
45
- async links(link) {
46
- if (!streams.links) {
47
- streams.links = await provider.createLinksWriteStream();
48
- }
49
- await writeAsync(streams.links, link);
50
- },
51
- async configuration(config) {
52
- if (!streams.configuration) {
53
- streams.configuration = await provider.createConfigurationWriteStream();
54
- }
55
- await writeAsync(streams.configuration, config);
56
- },
57
- async assets(payload) {
58
- // TODO: close the stream upong receiving an 'end' event instead
59
- if (payload === null) {
60
- streams.assets?.end();
61
- return;
62
- }
63
- const { action, assetID } = payload;
64
- if (!streams.assets) {
65
- streams.assets = await provider.createAssetsWriteStream();
66
- }
67
- if (action === 'start') {
68
- assets[assetID] = { ...payload.data, stream: new stream_chain_1.PassThrough() };
69
- writeAsync(streams.assets, assets[assetID]);
70
- }
71
- if (action === 'stream') {
72
- // The buffer has gone through JSON operations and is now of shape { type: "Buffer"; data: UInt8Array }
73
- // We need to transform it back into a Buffer instance
74
- const rawBuffer = payload.data;
75
- const chunk = Buffer.from(rawBuffer.data);
76
- await writeAsync(assets[assetID].stream, chunk);
77
- }
78
- if (action === 'end') {
79
- await new Promise((resolve, reject) => {
80
- const { stream } = assets[assetID];
81
- stream
82
- .on('close', () => {
83
- delete assets[assetID];
84
- resolve();
85
- })
86
- .on('error', reject)
87
- .end();
88
- });
89
- }
90
- },
91
- },
92
- };
93
- };
94
- exports.default = createPushController;
95
- //# sourceMappingURL=push.js.map
@@ -1,3 +0,0 @@
1
- import type { Context } from 'koa';
2
- import type { ServerOptions } from 'ws';
3
- export declare const createTransferHandler: (options?: ServerOptions) => (ctx: Context) => Promise<void>;
@@ -1,193 +0,0 @@
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.createTransferHandler = void 0;
7
- const crypto_1 = require("crypto");
8
- const ws_1 = require("ws");
9
- const push_1 = __importDefault(require("./controllers/push"));
10
- const providers_1 = require("../../errors/providers");
11
- const constants_1 = require("./constants");
12
- const createTransferHandler = (options = {}) => async (ctx) => {
13
- const upgradeHeader = (ctx.request.headers.upgrade || '')
14
- .split(',')
15
- .map((s) => s.trim().toLowerCase());
16
- // Create the websocket server
17
- const wss = new ws_1.WebSocket.Server({ ...options, noServer: true });
18
- if (upgradeHeader.includes('websocket')) {
19
- wss.handleUpgrade(ctx.req, ctx.request.socket, Buffer.alloc(0), (ws) => {
20
- // Create a connection between the client & the server
21
- wss.emit('connection', ws, ctx.req);
22
- const state = {};
23
- let uuid;
24
- /**
25
- * Format error & message to follow the remote transfer protocol
26
- */
27
- const callback = (e = null, data) => {
28
- return new Promise((resolve, reject) => {
29
- if (!uuid) {
30
- reject(new Error('Missing uuid for this message'));
31
- return;
32
- }
33
- const payload = JSON.stringify({
34
- uuid,
35
- data: data ?? null,
36
- error: e
37
- ? {
38
- code: 'ERR',
39
- message: e?.message,
40
- }
41
- : null,
42
- });
43
- ws.send(payload, (error) => (error ? reject(error) : resolve()));
44
- });
45
- };
46
- /**
47
- * Wrap a function call to catch errors and answer the request with the correct format
48
- */
49
- const answer = async (fn) => {
50
- try {
51
- const response = await fn();
52
- callback(null, response);
53
- }
54
- catch (e) {
55
- if (e instanceof Error) {
56
- callback(e);
57
- }
58
- else if (typeof e === 'string') {
59
- callback(new providers_1.ProviderTransferError(e));
60
- }
61
- else {
62
- callback(new providers_1.ProviderTransferError('Unexpected error', {
63
- error: e,
64
- }));
65
- }
66
- }
67
- };
68
- const teardown = () => {
69
- delete state.controller;
70
- delete state.transfer;
71
- return { ok: true };
72
- };
73
- const init = (msg) => {
74
- // TODO: this only checks for this instance of node: we should consider a database lock
75
- if (state.controller) {
76
- throw new providers_1.ProviderInitializationError('Transfer already in progres');
77
- }
78
- const { transfer } = msg.params;
79
- // Push transfer
80
- if (transfer === 'push') {
81
- const { options: controllerOptions } = msg.params;
82
- state.controller = (0, push_1.default)({
83
- ...controllerOptions,
84
- autoDestroy: false,
85
- getStrapi: () => strapi,
86
- });
87
- }
88
- // Pull or any other string
89
- else {
90
- throw new providers_1.ProviderTransferError(`Transfer type not implemented: "${transfer}"`, {
91
- transfer,
92
- validTransfers: constants_1.TRANSFER_METHODS,
93
- });
94
- }
95
- state.transfer = { id: (0, crypto_1.randomUUID)(), kind: transfer };
96
- return { transferID: state.transfer.id };
97
- };
98
- /**
99
- * On command message (init, end, status, ...)
100
- */
101
- const onCommand = async (msg) => {
102
- const { command } = msg;
103
- if (command === 'init') {
104
- await answer(() => init(msg));
105
- }
106
- if (command === 'end') {
107
- await answer(teardown);
108
- }
109
- if (command === 'status') {
110
- await callback(new providers_1.ProviderTransferError('Command not implemented: "status"', {
111
- command,
112
- validCommands: ['init', 'end', 'status'],
113
- }));
114
- }
115
- };
116
- const onTransferCommand = async (msg) => {
117
- const { transferID, kind } = msg;
118
- const { controller } = state;
119
- // TODO: (re)move this check
120
- // It shouldn't be possible to start a pull transfer for now, so reaching
121
- // this code should be impossible too, but this has been added by security
122
- if (state.transfer?.kind === 'pull') {
123
- return callback(new providers_1.ProviderTransferError('Pull transfer not implemented'));
124
- }
125
- if (!controller) {
126
- return callback(new providers_1.ProviderTransferError("The transfer hasn't been initialized"));
127
- }
128
- if (!transferID) {
129
- return callback(new providers_1.ProviderTransferError('Missing transfer ID'));
130
- }
131
- // Action
132
- if (kind === 'action') {
133
- const { action } = msg;
134
- if (!(action in controller.actions)) {
135
- return callback(new providers_1.ProviderTransferError(`Invalid action provided: "${action}"`, {
136
- action,
137
- validActions: Object.keys(controller.actions),
138
- }));
139
- }
140
- await answer(() => controller.actions[action]());
141
- }
142
- // Transfer
143
- else if (kind === 'step') {
144
- // We can only have push transfer message for the moment
145
- const message = msg;
146
- // TODO: lock transfer process
147
- if (message.action === 'start') {
148
- // console.log('Starting transfer for ', message.step);
149
- }
150
- // Stream step
151
- else if (message.action === 'stream') {
152
- await answer(() => controller.transfer[message.step]?.(message.data));
153
- }
154
- // TODO: unlock transfer process
155
- else if (message.action === 'end') {
156
- // console.log('Ending transfer for ', message.step);
157
- }
158
- }
159
- };
160
- ws.on('close', () => {
161
- teardown();
162
- });
163
- ws.on('error', (e) => {
164
- teardown();
165
- // TODO: is logging a console error to the running instance of Strapi ok to do? Should we check for an existing strapi.logger to use?
166
- console.error(e);
167
- });
168
- ws.on('message', async (raw) => {
169
- const msg = JSON.parse(raw.toString());
170
- if (!msg.uuid) {
171
- await callback(new providers_1.ProviderTransferError('Missing uuid in message'));
172
- return;
173
- }
174
- uuid = msg.uuid;
175
- // Regular command message (init, end, status)
176
- if (msg.type === 'command') {
177
- await onCommand(msg);
178
- }
179
- // Transfer message (the transfer must be initialized first)
180
- else if (msg.type === 'transfer') {
181
- await onTransferCommand(msg);
182
- }
183
- // Invalid messages
184
- else {
185
- await callback(new providers_1.ProviderTransferError('Bad request'));
186
- }
187
- });
188
- });
189
- ctx.respond = false;
190
- }
191
- };
192
- exports.createTransferHandler = createTransferHandler;
193
- //# sourceMappingURL=handlers.js.map
@@ -1,21 +0,0 @@
1
- import type { Context } from 'koa';
2
- declare module '@strapi/strapi' {
3
- interface Strapi {
4
- admin: {
5
- routes: {
6
- method: string;
7
- path: string;
8
- handler: (ctx: Context) => Promise<void>;
9
- config: unknown;
10
- }[];
11
- };
12
- }
13
- }
14
- /**
15
- * Register a transfer route in the Strapi admin router.
16
- *
17
- * It exposes a WS server that can be used to run and manage transfer processes.
18
- *
19
- * @param strapi - A Strapi instance
20
- */
21
- export declare const registerAdminTransferRoute: (strapi: Strapi.Strapi) => void;