UNPKG

forest-cli

Version:

The Lumberjacks' toolbelt is the Forest CLI which makes easy to manage your back office application directly from the terminal.

171 lines 15.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const context_1 = __importDefault(require("@forestadmin/context")); const superagent_1 = __importDefault(require("superagent")); const errors_1 = require("./errors"); /** * Read/write access to a rendering's layout, folders and workflows documents. * * The "layout" is the server-side rendering. There is no raw GET for the * layout domain (GET /api/layout returns []); the source of truth is the * JSON:API rendering document, read by name through * `GET /api/renderings/:project/:env/:team` — the same route the frontend uses. * * This adapter intentionally returns the raw response body (snake_case * attributes, `included` graph) so the rendering mapper can invert the * serialization itself. It reuses the toolbelt authenticator/env exactly like * the other managers (TeamManager, EnvironmentManager) — no auth is * re-implemented here. Later milestones (diff/apply) add the * `PATCH /api/:domain` write path on top of the same headers. */ class LayoutManager { constructor() { const { assertPresent, authenticator, env } = context_1.default.inject(); assertPresent({ authenticator, env }); this.authenticator = authenticator; this.serverUrl = env.FOREST_SERVER_URL; } /** GET /api/renderings/:project/:env/:team — the rendering as JSON:API. */ async getRendering(scope) { const path = [scope.projectName, scope.environmentName, scope.teamName] .map(segment => encodeURIComponent(segment)) .join('/'); try { const response = await superagent_1.default .get(`${this.serverUrl}/api/renderings/${path}`) .set('Authorization', `Bearer ${this.authenticator.getAuthToken()}`) .set('forest-project-id', String(scope.projectId)) .set('forest-environment-id', String(scope.environmentId)) .set('forest-team-id', String(scope.teamId)) .send(); return response.body; } catch (error) { throw (0, errors_1.toLayoutApiError)(error); } } /** * GET /api/:domain/:project/:env/:team — the raw patchable document for a * non-layout domain (folders, workflows). The layout domain has no usable raw * GET (it returns []), so use {@link getRendering} for it instead. */ async getLayoutDomain(domain, scope) { const path = [domain, scope.projectName, scope.environmentName, scope.teamName] .map(segment => encodeURIComponent(segment)) .join('/'); try { const response = await superagent_1.default .get(`${this.serverUrl}/api/${path}`) .set('Authorization', `Bearer ${this.authenticator.getAuthToken()}`) .set('forest-project-id', String(scope.projectId)) .set('forest-environment-id', String(scope.environmentId)) .set('forest-team-id', String(scope.teamId)) .send(); return (response.body ?? []); } catch (error) { throw (0, errors_1.toLayoutApiError)(error); } } /** * PATCH /api/:domain — apply an RFC 6902 JSON-Patch array, scoped by the * environment/team headers. The patch is atomic server-side; a 204 is * expected on success. Only `op`/`path`/`value` are sent (planner metadata * is dropped). A no-op array is skipped entirely. */ async patchDomain(domain, ops, scope) { if (ops.length === 0) return; const body = ops.map(({ op, path, value }) => value === undefined ? { op, path } : { op, path, value }); try { await superagent_1.default .patch(`${this.serverUrl}/api/${domain}`) .set('Authorization', `Bearer ${this.authenticator.getAuthToken()}`) .set('forest-project-id', String(scope.projectId)) .set('forest-environment-id', String(scope.environmentId)) .set('forest-team-id', String(scope.teamId)) .send(body); } catch (error) { throw (0, errors_1.toLayoutApiError)(error); } } /** The numeric rendering id for this scope (needed by the workflow presigned request). */ async getRenderingId(scope) { const rendering = await this.getRendering(scope); return Number(rendering.data.id); } /** * Download the currently-stored BPMN of a workflow version, to diff against a * freshly compiled one (idempotency). The server returns a presigned S3 GET * URL; the bytes are then fetched straight from S3 (no Forest auth there). */ async getWorkflowBpmn(scope, workflowId, collectionId, version, renderingId) { try { const meta = await superagent_1.default .get(`${this.serverUrl}/api/workflows/${workflowId}/bpmn`) .query({ collectionId, version }) .set('Authorization', `Bearer ${this.authenticator.getAuthToken()}`) .set('forest-project-id', String(scope.projectId)) .set('forest-environment-id', String(scope.environmentId)) .set('forest-team-id', String(scope.teamId)) .set('forest-rendering-id', String(renderingId)); const { signedUrl } = meta.body; if (!signedUrl) return ''; const file = await superagent_1.default.get(signedUrl).buffer(true); return file.text ?? ''; } catch (error) { throw (0, errors_1.toLayoutApiError)(error); } } /** * Upload a workflow's compiled BPMN and return its S3 version id (to store in * `bpmnAwsS3Identifier`). Mirrors the Forest UI exactly: ask the server for a * presigned S3 POST, multipart-upload the BPMN to S3, read `x-amz-version-id`. */ async uploadWorkflowBpmn(scope, workflowId, collectionId, renderingId, bpmn) { const size = Buffer.byteLength(bpmn); let presigned; try { const response = await superagent_1.default .post(`${this.serverUrl}/api/workflows/${workflowId}/generate-presigned-request`) .query({ collectionId }) .set('Authorization', `Bearer ${this.authenticator.getAuthToken()}`) .set('forest-project-id', String(scope.projectId)) .set('forest-environment-id', String(scope.environmentId)) .set('forest-team-id', String(scope.teamId)) .set('forest-rendering-id', String(renderingId)) .send({ name: `${workflowId}.bpmn`, size, type: 'text/xml' }); presigned = response.body; } catch (error) { throw (0, errors_1.toLayoutApiError)(error); } // Presigned S3 POST: send the returned policy fields, then the file last. No // Forest auth here — the presigned signature authorizes the upload. let response; try { const upload = superagent_1.default.post(presigned.url); Object.entries(presigned.fields).forEach(([key, value]) => upload.field(key, value)); response = await upload.attach('file', Buffer.from(bpmn), { contentType: 'text/xml', filename: `${workflowId}.bpmn`, }); } catch (error) { throw (0, errors_1.toLayoutApiError)(error); } const versionId = response.headers['x-amz-version-id']; if (!versionId) { throw new Error('S3 did not return a version id for the uploaded BPMN (bucket versioning off?).'); } return versionId; } } exports.default = LayoutManager; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGF5b3V0LW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvbGF5b3V0L2xheW91dC1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBRUEsbUVBQTJDO0FBQzNDLDREQUErQjtBQUUvQixxQ0FBNEM7QUFFNUM7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxNQUFxQixhQUFhO0lBS2hDO1FBQ0UsTUFBTSxFQUFFLGFBQWEsRUFBRSxhQUFhLEVBQUUsR0FBRyxFQUFFLEdBQUcsaUJBQU8sQ0FBQyxNQUFNLEVBSTNELENBQUM7UUFDRixhQUFhLENBQUMsRUFBRSxhQUFhLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUV0QyxJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztRQUNuQyxJQUFJLENBQUMsU0FBUyxHQUFHLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQztJQUN6QyxDQUFDO0lBRUQsMkVBQTJFO0lBQzNFLEtBQUssQ0FBQyxZQUFZLENBQUMsS0FBa0I7UUFDbkMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxLQUFLLENBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQyxlQUFlLEVBQUUsS0FBSyxDQUFDLFFBQVEsQ0FBQzthQUNwRSxHQUFHLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQzthQUMzQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFYixJQUFJO1lBQ0YsTUFBTSxRQUFRLEdBQUcsTUFBTSxvQkFBSztpQkFDekIsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLFNBQVMsbUJBQW1CLElBQUksRUFBRSxDQUFDO2lCQUMvQyxHQUFHLENBQUMsZUFBZSxFQUFFLFVBQVUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDO2lCQUNuRSxHQUFHLENBQUMsbUJBQW1CLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztpQkFDakQsR0FBRyxDQUFDLHVCQUF1QixFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUM7aUJBQ3pELEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO2lCQUMzQyxJQUFJLEVBQUUsQ0FBQztZQUVWLE9BQU8sUUFBUSxDQUFDLElBQXVCLENBQUM7U0FDekM7UUFBQyxPQUFPLEtBQUssRUFBRTtZQUNkLE1BQU0sSUFBQSx5QkFBZ0IsRUFBQyxLQUFLLENBQUMsQ0FBQztTQUMvQjtJQUNILENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLGVBQWUsQ0FDbkIsTUFBdUMsRUFDdkMsS0FBa0I7UUFFbEIsTUFBTSxJQUFJLEdBQUcsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLFdBQVcsRUFBRSxLQUFLLENBQUMsZUFBZSxFQUFFLEtBQUssQ0FBQyxRQUFRLENBQUM7YUFDNUUsR0FBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsa0JBQWtCLENBQUMsT0FBTyxDQUFDLENBQUM7YUFDM0MsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRWIsSUFBSTtZQUNGLE1BQU0sUUFBUSxHQUFHLE1BQU0sb0JBQUs7aUJBQ3pCLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLFFBQVEsSUFBSSxFQUFFLENBQUM7aUJBQ3BDLEdBQUcsQ0FBQyxlQUFlLEVBQUUsVUFBVSxJQUFJLENBQUMsYUFBYSxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUM7aUJBQ25FLEdBQUcsQ0FBQyxtQkFBbUIsRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2lCQUNqRCxHQUFHLENBQUMsdUJBQXVCLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztpQkFDekQsR0FBRyxDQUFDLGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7aUJBQzNDLElBQUksRUFBRSxDQUFDO1lBRVYsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFjLENBQUM7U0FDM0M7UUFBQyxPQUFPLEtBQUssRUFBRTtZQUNkLE1BQU0sSUFBQSx5QkFBZ0IsRUFBQyxLQUFLLENBQUMsQ0FBQztTQUMvQjtJQUNILENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyxXQUFXLENBQUMsTUFBb0IsRUFBRSxHQUFrQixFQUFFLEtBQWtCO1FBQzVFLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQUUsT0FBTztRQUU3QixNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FDM0MsS0FBSyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FDekQsQ0FBQztRQUVGLElBQUk7WUFDRixNQUFNLG9CQUFLO2lCQUNSLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLFFBQVEsTUFBTSxFQUFFLENBQUM7aUJBQ3hDLEdBQUcsQ0FBQyxlQUFlLEVBQUUsVUFBVSxJQUFJLENBQUMsYUFBYSxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUM7aUJBQ25FLEdBQUcsQ0FBQyxtQkFBbUIsRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2lCQUNqRCxHQUFHLENBQUMsdUJBQXVCLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztpQkFDekQsR0FBRyxDQUFDLGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7aUJBQzNDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUNmO1FBQUMsT0FBTyxLQUFLLEVBQUU7WUFDZCxNQUFNLElBQUEseUJBQWdCLEVBQUMsS0FBSyxDQUFDLENBQUM7U0FDL0I7SUFDSCxDQUFDO0lBRUQsMEZBQTBGO0lBQzFGLEtBQUssQ0FBQyxjQUFjLENBQUMsS0FBa0I7UUFDckMsTUFBTSxTQUFTLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRWpELE9BQU8sTUFBTSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsZUFBZSxDQUNuQixLQUFrQixFQUNsQixVQUFrQixFQUNsQixZQUFvQixFQUNwQixPQUFlLEVBQ2YsV0FBbUI7UUFFbkIsSUFBSTtZQUNGLE1BQU0sSUFBSSxHQUFHLE1BQU0sb0JBQUs7aUJBQ3JCLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLGtCQUFrQixVQUFVLE9BQU8sQ0FBQztpQkFDekQsS0FBSyxDQUFDLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxDQUFDO2lCQUNoQyxHQUFHLENBQUMsZUFBZSxFQUFFLFVBQVUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDO2lCQUNuRSxHQUFHLENBQUMsbUJBQW1CLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztpQkFDakQsR0FBRyxDQUFDLHVCQUF1QixFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUM7aUJBQ3pELEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO2lCQUMzQyxHQUFHLENBQUMscUJBQXFCLEVBQUUsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7WUFFbkQsTUFBTSxFQUFFLFNBQVMsRUFBRSxHQUFHLElBQUksQ0FBQyxJQUE4QixDQUFDO1lBQzFELElBQUksQ0FBQyxTQUFTO2dCQUFFLE9BQU8sRUFBRSxDQUFDO1lBRTFCLE1BQU0sSUFBSSxHQUFHLE1BQU0sb0JBQUssQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBRXJELE9BQU8sSUFBSSxDQUFDLElBQUksSUFBSSxFQUFFLENBQUM7U0FDeEI7UUFBQyxPQUFPLEtBQUssRUFBRTtZQUNkLE1BQU0sSUFBQSx5QkFBZ0IsRUFBQyxLQUFLLENBQUMsQ0FBQztTQUMvQjtJQUNILENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLGtCQUFrQixDQUN0QixLQUFrQixFQUNsQixVQUFrQixFQUNsQixZQUFvQixFQUNwQixXQUFtQixFQUNuQixJQUFZO1FBRVosTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUVyQyxJQUFJLFNBQTBELENBQUM7UUFDL0QsSUFBSTtZQUNGLE1BQU0sUUFBUSxHQUFHLE1BQU0sb0JBQUs7aUJBQ3pCLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLGtCQUFrQixVQUFVLDZCQUE2QixDQUFDO2lCQUNoRixLQUFLLENBQUMsRUFBRSxZQUFZLEVBQUUsQ0FBQztpQkFDdkIsR0FBRyxDQUFDLGVBQWUsRUFBRSxVQUFVLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQztpQkFDbkUsR0FBRyxDQUFDLG1CQUFtQixFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7aUJBQ2pELEdBQUcsQ0FBQyx1QkFBdUIsRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDO2lCQUN6RCxHQUFHLENBQUMsZ0JBQWdCLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztpQkFDM0MsR0FBRyxDQUFDLHFCQUFxQixFQUFFLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztpQkFDL0MsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLEdBQUcsVUFBVSxPQUFPLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDO1lBQ2hFLFNBQVMsR0FBRyxRQUFRLENBQUMsSUFBdUQsQ0FBQztTQUM5RTtRQUFDLE9BQU8sS0FBSyxFQUFFO1lBQ2QsTUFBTSxJQUFBLHlCQUFnQixFQUFDLEtBQUssQ0FBQyxDQUFDO1NBQy9CO1FBRUQsNkVBQTZFO1FBQzdFLG9FQUFvRTtRQUNwRSxJQUFJLFFBQVEsQ0FBQztRQUNiLElBQUk7WUFDRixNQUFNLE1BQU0sR0FBRyxvQkFBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDekMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFDckYsUUFBUSxHQUFHLE1BQU0sTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRTtnQkFDeEQsV0FBVyxFQUFFLFVBQVU7Z0JBQ3ZCLFFBQVEsRUFBRSxHQUFHLFVBQVUsT0FBTzthQUMvQixDQUFDLENBQUM7U0FDSjtRQUFDLE9BQU8sS0FBSyxFQUFFO1lBQ2QsTUFBTSxJQUFBLHlCQUFnQixFQUFDLEtBQUssQ0FBQyxDQUFDO1NBQy9CO1FBRUQsTUFBTSxTQUFTLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBQ3ZELElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDZCxNQUFNLElBQUksS0FBSyxDQUNiLGdGQUFnRixDQUNqRixDQUFDO1NBQ0g7UUFFRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0NBQ0Y7QUF6TEQsZ0NBeUxDIn0=