@slicemachine/manager 0.1.1-dev-ci.0 → 0.1.1-dev-plugins-m2.0
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.
- package/dist/constants/API_ENDPOINTS.cjs +2 -2
- package/dist/constants/API_ENDPOINTS.cjs.map +1 -1
- package/dist/constants/API_ENDPOINTS.js +2 -2
- package/dist/constants/API_ENDPOINTS.js.map +1 -1
- package/dist/managers/customTypes/CustomTypesManager.cjs +13 -5
- package/dist/managers/customTypes/CustomTypesManager.cjs.map +1 -1
- package/dist/managers/customTypes/CustomTypesManager.d.ts +8 -2
- package/dist/managers/customTypes/CustomTypesManager.js +13 -5
- package/dist/managers/customTypes/CustomTypesManager.js.map +1 -1
- package/dist/managers/prismicRepository/PrismicRepositoryManager.cjs +5 -2
- package/dist/managers/prismicRepository/PrismicRepositoryManager.cjs.map +1 -1
- package/dist/managers/prismicRepository/PrismicRepositoryManager.js +5 -2
- package/dist/managers/prismicRepository/PrismicRepositoryManager.js.map +1 -1
- package/dist/managers/screenshots/ScreenshotsManager.cjs +29 -13
- package/dist/managers/screenshots/ScreenshotsManager.cjs.map +1 -1
- package/dist/managers/screenshots/ScreenshotsManager.d.ts +5 -0
- package/dist/managers/screenshots/ScreenshotsManager.js +25 -9
- package/dist/managers/screenshots/ScreenshotsManager.js.map +1 -1
- package/dist/managers/slices/SlicesManager.cjs +53 -5
- package/dist/managers/slices/SlicesManager.cjs.map +1 -1
- package/dist/managers/slices/SlicesManager.d.ts +10 -2
- package/dist/managers/slices/SlicesManager.js +53 -5
- package/dist/managers/slices/SlicesManager.js.map +1 -1
- package/package.json +3 -3
- package/src/constants/API_ENDPOINTS.ts +2 -2
- package/src/managers/customTypes/CustomTypesManager.ts +27 -12
- package/src/managers/prismicRepository/PrismicRepositoryManager.ts +6 -2
- package/src/managers/screenshots/ScreenshotsManager.ts +41 -11
- package/src/managers/slices/SlicesManager.ts +94 -12
|
@@ -31,7 +31,7 @@ const t = require("io-ts");
|
|
|
31
31
|
require("node:buffer");
|
|
32
32
|
require("readable-web-to-node-stream");
|
|
33
33
|
const core = require('./../../_node_modules/file-type/core.cjs');
|
|
34
|
-
const index = require('./../../_node_modules/node-fetch/src/index.cjs');
|
|
34
|
+
const index$1 = require('./../../_node_modules/node-fetch/src/index.cjs');
|
|
35
35
|
const checkIsURLAccessible = require("../../lib/checkIsURLAccessible.cjs");
|
|
36
36
|
const createContentDigest = require("../../lib/createContentDigest.cjs");
|
|
37
37
|
const decode = require("../../lib/decode.cjs");
|
|
@@ -40,7 +40,7 @@ const API_ENDPOINTS = require("../../constants/API_ENDPOINTS.cjs");
|
|
|
40
40
|
const errors = require("../../errors.cjs");
|
|
41
41
|
const BaseManager = require("../BaseManager.cjs");
|
|
42
42
|
const esm_min = require('./../../_node_modules/formdata-polyfill/esm.min.cjs');
|
|
43
|
-
const index
|
|
43
|
+
const index = require('./../../_node_modules/fetch-blob/index.cjs');
|
|
44
44
|
require("node:fs");
|
|
45
45
|
require("node:path");
|
|
46
46
|
require('./../../_node_modules/node-domexception/index.cjs');
|
|
@@ -104,16 +104,8 @@ class ScreenshotsManager extends BaseManager.BaseManager {
|
|
|
104
104
|
if (this._s3ACL) {
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
|
-
const sliceMachineConfig = await this.project.getSliceMachineConfig();
|
|
108
|
-
const authenticationToken = await this.user.getAuthenticationToken();
|
|
109
107
|
const awsACLURL = new URL("create", API_ENDPOINTS.API_ENDPOINTS.AwsAclProvider);
|
|
110
|
-
const awsACLRes = await
|
|
111
|
-
headers: {
|
|
112
|
-
Authorization: `Bearer ${authenticationToken}`,
|
|
113
|
-
"User-Agent": SLICE_MACHINE_USER_AGENT.SLICE_MACHINE_USER_AGENT,
|
|
114
|
-
Repository: sliceMachineConfig.repositoryName
|
|
115
|
-
}
|
|
116
|
-
});
|
|
108
|
+
const awsACLRes = await this._fetch({ url: awsACLURL });
|
|
117
109
|
const awsACLText = await awsACLRes.text();
|
|
118
110
|
let awsACLJSON;
|
|
119
111
|
try {
|
|
@@ -209,8 +201,8 @@ class ScreenshotsManager extends BaseManager.BaseManager {
|
|
|
209
201
|
if (fileType) {
|
|
210
202
|
formData.set("Content-Type", fileType.mime);
|
|
211
203
|
}
|
|
212
|
-
formData.set("file", new index
|
|
213
|
-
const res = await index.default(this._s3ACL.uploadEndpoint, {
|
|
204
|
+
formData.set("file", new index.default([args.data], { type: fileType == null ? void 0 : fileType.mime }));
|
|
205
|
+
const res = await index$1.default(this._s3ACL.uploadEndpoint, {
|
|
214
206
|
method: "POST",
|
|
215
207
|
body: formData
|
|
216
208
|
});
|
|
@@ -224,6 +216,30 @@ class ScreenshotsManager extends BaseManager.BaseManager {
|
|
|
224
216
|
throw new Error(`Unable to upload screenshot with status code: ${res.status}`);
|
|
225
217
|
}
|
|
226
218
|
}
|
|
219
|
+
async deleteScreenshotFolder(args) {
|
|
220
|
+
const res = await this._fetch({
|
|
221
|
+
body: { sliceId: args.sliceID },
|
|
222
|
+
method: "POST",
|
|
223
|
+
url: new URL("delete-folder", API_ENDPOINTS.API_ENDPOINTS.AwsAclProvider)
|
|
224
|
+
});
|
|
225
|
+
if (!res.ok) {
|
|
226
|
+
throw new Error(`Unable to delete screenshot folder with status code: ${res.status}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async _fetch(args) {
|
|
230
|
+
const authenticationToken = await this.user.getAuthenticationToken();
|
|
231
|
+
const sliceMachineConfig = await this.project.getSliceMachineConfig();
|
|
232
|
+
return await index$1.default(args.url, {
|
|
233
|
+
body: args.body ? JSON.stringify(args.body) : void 0,
|
|
234
|
+
headers: {
|
|
235
|
+
Authorization: `Bearer ${authenticationToken}`,
|
|
236
|
+
Repository: sliceMachineConfig.repositoryName,
|
|
237
|
+
"User-Agent": SLICE_MACHINE_USER_AGENT.SLICE_MACHINE_USER_AGENT,
|
|
238
|
+
...args.body ? { "Content-Type": "application/json" } : {}
|
|
239
|
+
},
|
|
240
|
+
method: args.method
|
|
241
|
+
});
|
|
242
|
+
}
|
|
227
243
|
}
|
|
228
244
|
exports.ScreenshotsManager = ScreenshotsManager;
|
|
229
245
|
//# sourceMappingURL=ScreenshotsManager.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScreenshotsManager.cjs","sources":["../../../../src/managers/screenshots/ScreenshotsManager.ts"],"sourcesContent":["import * as t from \"io-ts\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport fetch, { FormData, Blob } from \"node-fetch\";\n// puppeteer is lazy-loaded in captureSliceSimulatorScreenshot\nimport type { BrowserContext, Viewport } from \"puppeteer\";\n\nimport { checkIsURLAccessible } from \"../../lib/checkIsURLAccessible\";\nimport { createContentDigest } from \"../../lib/createContentDigest\";\nimport { decode } from \"../../lib/decode\";\n\nimport { S3ACL } from \"../../types\";\nimport { SLICE_MACHINE_USER_AGENT } from \"../../constants/SLICE_MACHINE_USER_AGENT\";\nimport { API_ENDPOINTS } from \"../../constants/API_ENDPOINTS\";\nimport { InternalError } from \"../../errors\";\n\nimport { BaseManager } from \"../BaseManager\";\n\nconst SLICE_SIMULATOR_WAIT_FOR_TIMEOUT = 10_000; // ms\nconst SLICE_SIMULATOR_WAIT_FOR_SELECTOR = \"#__iframe-ready\";\nconst SLICE_SIMULATOR_SCREENSHOT_SELECTOR = \"#__iframe-renderer\";\n\nconst DEFAULT_SCREENSHOT_VIEWPORT: Viewport = {\n\twidth: 1200,\n\theight: 800,\n};\n\nfunction assertS3ACLInitialized(\n\ts3ACL: S3ACL | undefined,\n): asserts s3ACL is NonNullable<typeof s3ACL> {\n\tif (s3ACL == undefined) {\n\t\tthrow new Error(\n\t\t\t\"An S3 ACL has not been initialized. Run `SliceMachineManager.screenshots.prototype.initS3ACL()` before re-calling this method.\",\n\t\t);\n\t}\n}\n\nfunction assertBrowserContextInitialized(\n\tbrowserContext: BrowserContext | undefined,\n): asserts browserContext is NonNullable<typeof browserContext> {\n\tif (browserContext == undefined) {\n\t\tthrow new Error(\n\t\t\t\"A browser context has not been initialized. Run `SliceMachineManager.screenshots.prototype.initBrowserContext()` before re-calling this method.\",\n\t\t);\n\t}\n}\n\n/**\n * Encodes a part of a Slice Simulator URL to ensure it can be added to a URL\n * safely.\n *\n * The encoding logic must match Slice Machine UI's URL encoding practices.\n * Today, that requires the following:\n *\n * - Replace \"/\" with \"--\" (e.g. a Slice Library ID of \"./slices\" should turn into\n * \".--slices\")\n *\n * @param urlPart - A part of the URL.\n *\n * @returns `urlPart` encoded for use in a URL.\n */\nconst encodeSliceSimulatorURLPart = (urlPart: string): string => {\n\treturn urlPart.replace(/\\//g, \"--\");\n};\n\ntype ScreenshotsManagerCaptureSliceSimulatorScreenshotArgs = {\n\tsliceMachineUIOrigin: string;\n\tlibraryID: string;\n\tsliceID: string;\n\tvariationID: string;\n\tviewport?: Viewport;\n};\n\ntype ScreenshotsManagerCaptureSliceSimulatorScreenshotReturnType = {\n\tdata: Buffer;\n};\n\ntype ScreenshotsManagerUploadScreenshotArgs = {\n\tdata: Buffer;\n\tkeyPrefix?: string;\n};\n\ntype ScreenshotsManagerUploadScreenshotReturnType = {\n\turl: string;\n};\n\nexport class ScreenshotsManager extends BaseManager {\n\tprivate _browserContext: BrowserContext | undefined;\n\tprivate _s3ACL: S3ACL | undefined;\n\n\tasync initBrowserContext(): Promise<void> {\n\t\tif (this._browserContext) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet puppeteer: typeof import(\"puppeteer\");\n\t\ttry {\n\t\t\t// Lazy-load Puppeteer only once it is needed.\n\t\t\tpuppeteer = await import(\"puppeteer\");\n\t\t} catch {\n\t\t\tthrow new InternalError(\n\t\t\t\t\"Screenshots require Puppeteer but Puppeteer was not found. Check that the `puppeteer` package is installed before trying again.\",\n\t\t\t);\n\t\t}\n\n\t\tconst browser = await puppeteer.launch();\n\n\t\tthis._browserContext = await browser.createIncognitoBrowserContext();\n\t}\n\n\tasync initS3ACL(): Promise<void> {\n\t\tif (this._s3ACL) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\t\tconst authenticationToken = await this.user.getAuthenticationToken();\n\n\t\tconst awsACLURL = new URL(\"create\", API_ENDPOINTS.AwsAclProvider);\n\t\tconst awsACLRes = await fetch(awsACLURL.toString(), {\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${authenticationToken}`,\n\t\t\t\t\"User-Agent\": SLICE_MACHINE_USER_AGENT,\n\t\t\t\tRepository: sliceMachineConfig.repositoryName,\n\t\t\t},\n\t\t});\n\n\t\tconst awsACLText = await awsACLRes.text();\n\t\tlet awsACLJSON: unknown;\n\t\ttry {\n\t\t\tawsACLJSON = JSON.parse(awsACLText);\n\t\t} catch (error) {\n\t\t\t// Response is not JSON\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid AWS ACL response from ${awsACLURL}: ${awsACLText}`,\n\t\t\t);\n\t\t}\n\n\t\tconst { value: awsACL, error } = decode(\n\t\t\tt.intersection([\n\t\t\t\tt.type({\n\t\t\t\t\tvalues: t.type({\n\t\t\t\t\t\turl: t.string,\n\t\t\t\t\t\tfields: t.record(t.string, t.string),\n\t\t\t\t\t}),\n\t\t\t\t\timgixEndpoint: t.string,\n\t\t\t\t}),\n\t\t\t\tt.partial({\n\t\t\t\t\tmessage: t.string,\n\t\t\t\t\tMessage: t.string,\n\t\t\t\t\terror: t.string,\n\t\t\t\t}),\n\t\t\t]),\n\t\t\tawsACLJSON,\n\t\t);\n\n\t\tif (error) {\n\t\t\tthrow new Error(`Invalid AWS ACL response from ${awsACLURL}`);\n\t\t}\n\n\t\tconst errorMessage = awsACL.error || awsACL.message || awsACL.Message;\n\t\tif (errorMessage) {\n\t\t\tthrow new Error(`Failed to create an AWS ACL: ${errorMessage}`);\n\t\t}\n\n\t\tthis._s3ACL = {\n\t\t\tuploadEndpoint: awsACL.values.url,\n\t\t\trequiredFormDataFields: awsACL.values.fields,\n\t\t\timgixEndpoint: awsACL.imgixEndpoint,\n\t\t};\n\t}\n\n\t// TODO: Abstract to a generic `captureScreenshot()` method that is\n\t// used within a Slice-specific method in SliceManager.\n\tasync captureSliceSimulatorScreenshot(\n\t\targs: ScreenshotsManagerCaptureSliceSimulatorScreenshotArgs,\n\t): Promise<ScreenshotsManagerCaptureSliceSimulatorScreenshotReturnType> {\n\t\tassertBrowserContextInitialized(this._browserContext);\n\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\tif (!sliceMachineConfig.localSliceSimulatorURL) {\n\t\t\t// TODO: Provide a more helpful error message.\n\t\t\tthrow new Error(\n\t\t\t\t\"A local Slice Simulator URL must be configured in your Slice Machine configuration file.\",\n\t\t\t);\n\t\t}\n\n\t\tconst { model } = await this.slices.readSlice({\n\t\t\tlibraryID: args.libraryID,\n\t\t\tsliceID: args.sliceID,\n\t\t});\n\t\tif (!model) {\n\t\t\tthrow new Error(\n\t\t\t\t`Did not find a Slice in library \"${args.libraryID}\" with ID \"${args.sliceID}\".`,\n\t\t\t);\n\t\t}\n\n\t\tconst viewport = args.viewport || DEFAULT_SCREENSHOT_VIEWPORT;\n\n\t\t// TODO: Change `model.name` to `args.sliceID`?\n\t\t// Making that change would require changing the screenshot\n\t\t// page path in Slice Machine UI.\n\t\tconst url = new URL(\n\t\t\t`./${encodeSliceSimulatorURLPart(args.libraryID)}/${model.name}/${\n\t\t\t\targs.variationID\n\t\t\t}/screenshot`,\n\t\t\targs.sliceMachineUIOrigin,\n\t\t);\n\t\turl.searchParams.set(\"screenWidth\", viewport.width.toString());\n\t\turl.searchParams.set(\"screenHeight\", viewport.height.toString());\n\n\t\tconst isURLAccessible = await checkIsURLAccessible(url.toString());\n\n\t\tif (!isURLAccessible) {\n\t\t\tthrow new Error(\n\t\t\t\t`Slice Simulator screenshot URL is not accessible: ${url}`,\n\t\t\t);\n\t\t}\n\n\t\tconst page = await this._browserContext.newPage();\n\t\tpage.setViewport(viewport);\n\n\t\tawait page.goto(url.toString(), { waitUntil: \"load\" });\n\t\tawait page.waitForSelector(SLICE_SIMULATOR_WAIT_FOR_SELECTOR, {\n\t\t\ttimeout: SLICE_SIMULATOR_WAIT_FOR_TIMEOUT,\n\t\t});\n\n\t\tconst element = await page.$(SLICE_SIMULATOR_SCREENSHOT_SELECTOR);\n\t\tif (!element) {\n\t\t\tconst baseURL = new URL(url.pathname, url.origin);\n\n\t\t\tthrow new Error(\n\t\t\t\t`Slice Simulator did not find ${SLICE_SIMULATOR_WAIT_FOR_SELECTOR} on the page. Verify the URL is correct: ${baseURL}`,\n\t\t\t);\n\t\t}\n\n\t\tconst data = (await element.screenshot({\n\t\t\tencoding: \"binary\",\n\t\t\tclip: {\n\t\t\t\twidth: viewport.width,\n\t\t\t\theight: viewport.height,\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t},\n\t\t})) as Buffer;\n\n\t\treturn {\n\t\t\tdata,\n\t\t};\n\t}\n\n\tasync uploadScreenshot(\n\t\targs: ScreenshotsManagerUploadScreenshotArgs,\n\t): Promise<ScreenshotsManagerUploadScreenshotReturnType> {\n\t\tassertS3ACLInitialized(this._s3ACL);\n\n\t\tconst formData = new FormData();\n\n\t\tfor (const requiredFormDataFieldKey in this._s3ACL.requiredFormDataFields) {\n\t\t\tformData.append(\n\t\t\t\trequiredFormDataFieldKey,\n\t\t\t\tthis._s3ACL.requiredFormDataFields[requiredFormDataFieldKey],\n\t\t\t);\n\t\t}\n\n\t\tconst contentDigest = createContentDigest(args.data);\n\t\tconst fileType = await fileTypeFromBuffer(args.data);\n\t\tconst fileName = fileType\n\t\t\t? `${contentDigest}.${fileType.ext}`\n\t\t\t: contentDigest;\n\t\tconst key = args.keyPrefix ? `${args.keyPrefix}/${fileName}` : fileName;\n\n\t\tformData.set(\"key\", key);\n\n\t\tif (fileType) {\n\t\t\tformData.set(\"Content-Type\", fileType.mime);\n\t\t}\n\n\t\tformData.set(\"file\", new Blob([args.data], { type: fileType?.mime }));\n\n\t\tconst res = await fetch(this._s3ACL.uploadEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: formData,\n\t\t});\n\n\t\tif (res.ok) {\n\t\t\tconst url = new URL(key, this._s3ACL.imgixEndpoint);\n\t\t\turl.searchParams.set(\"auto\", \"compress,format\");\n\n\t\t\treturn {\n\t\t\t\turl: url.toString(),\n\t\t\t};\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Unable to upload screenshot with status code: ${res.status}`,\n\t\t\t);\n\t\t}\n\t}\n}\n"],"names":["BaseManager","InternalError","API_ENDPOINTS","fetch","SLICE_MACHINE_USER_AGENT","error","decode","t","checkIsURLAccessible","FormData","createContentDigest","fileTypeFromBuffer","Blob"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ScreenshotsManager.cjs","sources":["../../../../src/managers/screenshots/ScreenshotsManager.ts"],"sourcesContent":["import * as t from \"io-ts\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport fetch, { FormData, Blob, Response } from \"node-fetch\";\n// puppeteer is lazy-loaded in captureSliceSimulatorScreenshot\nimport type { BrowserContext, Viewport } from \"puppeteer\";\n\nimport { checkIsURLAccessible } from \"../../lib/checkIsURLAccessible\";\nimport { createContentDigest } from \"../../lib/createContentDigest\";\nimport { decode } from \"../../lib/decode\";\n\nimport { S3ACL } from \"../../types\";\nimport { SLICE_MACHINE_USER_AGENT } from \"../../constants/SLICE_MACHINE_USER_AGENT\";\nimport { API_ENDPOINTS } from \"../../constants/API_ENDPOINTS\";\nimport { InternalError } from \"../../errors\";\n\nimport { BaseManager } from \"../BaseManager\";\n\nconst SLICE_SIMULATOR_WAIT_FOR_TIMEOUT = 10_000; // ms\nconst SLICE_SIMULATOR_WAIT_FOR_SELECTOR = \"#__iframe-ready\";\nconst SLICE_SIMULATOR_SCREENSHOT_SELECTOR = \"#__iframe-renderer\";\n\nconst DEFAULT_SCREENSHOT_VIEWPORT: Viewport = {\n\twidth: 1200,\n\theight: 800,\n};\n\nfunction assertS3ACLInitialized(\n\ts3ACL: S3ACL | undefined,\n): asserts s3ACL is NonNullable<typeof s3ACL> {\n\tif (s3ACL == undefined) {\n\t\tthrow new Error(\n\t\t\t\"An S3 ACL has not been initialized. Run `SliceMachineManager.screenshots.prototype.initS3ACL()` before re-calling this method.\",\n\t\t);\n\t}\n}\n\nfunction assertBrowserContextInitialized(\n\tbrowserContext: BrowserContext | undefined,\n): asserts browserContext is NonNullable<typeof browserContext> {\n\tif (browserContext == undefined) {\n\t\tthrow new Error(\n\t\t\t\"A browser context has not been initialized. Run `SliceMachineManager.screenshots.prototype.initBrowserContext()` before re-calling this method.\",\n\t\t);\n\t}\n}\n\n/**\n * Encodes a part of a Slice Simulator URL to ensure it can be added to a URL\n * safely.\n *\n * The encoding logic must match Slice Machine UI's URL encoding practices.\n * Today, that requires the following:\n *\n * - Replace \"/\" with \"--\" (e.g. a Slice Library ID of \"./slices\" should turn into\n * \".--slices\")\n *\n * @param urlPart - A part of the URL.\n *\n * @returns `urlPart` encoded for use in a URL.\n */\nconst encodeSliceSimulatorURLPart = (urlPart: string): string => {\n\treturn urlPart.replace(/\\//g, \"--\");\n};\n\ntype ScreenshotsManagerCaptureSliceSimulatorScreenshotArgs = {\n\tsliceMachineUIOrigin: string;\n\tlibraryID: string;\n\tsliceID: string;\n\tvariationID: string;\n\tviewport?: Viewport;\n};\n\ntype ScreenshotsManagerCaptureSliceSimulatorScreenshotReturnType = {\n\tdata: Buffer;\n};\n\ntype ScreenshotsManagerUploadScreenshotArgs = {\n\tdata: Buffer;\n\tkeyPrefix?: string;\n};\n\ntype ScreenshotsManagerUploadScreenshotReturnType = {\n\turl: string;\n};\n\ntype ScreenshotsManagerDeleteScreenshotFolderArgs = {\n\tsliceID: string;\n};\n\nexport class ScreenshotsManager extends BaseManager {\n\tprivate _browserContext: BrowserContext | undefined;\n\tprivate _s3ACL: S3ACL | undefined;\n\n\tasync initBrowserContext(): Promise<void> {\n\t\tif (this._browserContext) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet puppeteer: typeof import(\"puppeteer\");\n\t\ttry {\n\t\t\t// Lazy-load Puppeteer only once it is needed.\n\t\t\tpuppeteer = await import(\"puppeteer\");\n\t\t} catch {\n\t\t\tthrow new InternalError(\n\t\t\t\t\"Screenshots require Puppeteer but Puppeteer was not found. Check that the `puppeteer` package is installed before trying again.\",\n\t\t\t);\n\t\t}\n\n\t\tconst browser = await puppeteer.launch();\n\n\t\tthis._browserContext = await browser.createIncognitoBrowserContext();\n\t}\n\n\tasync initS3ACL(): Promise<void> {\n\t\tif (this._s3ACL) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst awsACLURL = new URL(\"create\", API_ENDPOINTS.AwsAclProvider);\n\t\tconst awsACLRes = await this._fetch({ url: awsACLURL });\n\n\t\tconst awsACLText = await awsACLRes.text();\n\t\tlet awsACLJSON: unknown;\n\t\ttry {\n\t\t\tawsACLJSON = JSON.parse(awsACLText);\n\t\t} catch (error) {\n\t\t\t// Response is not JSON\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid AWS ACL response from ${awsACLURL}: ${awsACLText}`,\n\t\t\t);\n\t\t}\n\n\t\tconst { value: awsACL, error } = decode(\n\t\t\tt.intersection([\n\t\t\t\tt.type({\n\t\t\t\t\tvalues: t.type({\n\t\t\t\t\t\turl: t.string,\n\t\t\t\t\t\tfields: t.record(t.string, t.string),\n\t\t\t\t\t}),\n\t\t\t\t\timgixEndpoint: t.string,\n\t\t\t\t}),\n\t\t\t\tt.partial({\n\t\t\t\t\tmessage: t.string,\n\t\t\t\t\tMessage: t.string,\n\t\t\t\t\terror: t.string,\n\t\t\t\t}),\n\t\t\t]),\n\t\t\tawsACLJSON,\n\t\t);\n\n\t\tif (error) {\n\t\t\tthrow new Error(`Invalid AWS ACL response from ${awsACLURL}`);\n\t\t}\n\n\t\tconst errorMessage = awsACL.error || awsACL.message || awsACL.Message;\n\t\tif (errorMessage) {\n\t\t\tthrow new Error(`Failed to create an AWS ACL: ${errorMessage}`);\n\t\t}\n\n\t\tthis._s3ACL = {\n\t\t\tuploadEndpoint: awsACL.values.url,\n\t\t\trequiredFormDataFields: awsACL.values.fields,\n\t\t\timgixEndpoint: awsACL.imgixEndpoint,\n\t\t};\n\t}\n\n\t// TODO: Abstract to a generic `captureScreenshot()` method that is\n\t// used within a Slice-specific method in SliceManager.\n\tasync captureSliceSimulatorScreenshot(\n\t\targs: ScreenshotsManagerCaptureSliceSimulatorScreenshotArgs,\n\t): Promise<ScreenshotsManagerCaptureSliceSimulatorScreenshotReturnType> {\n\t\tassertBrowserContextInitialized(this._browserContext);\n\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\tif (!sliceMachineConfig.localSliceSimulatorURL) {\n\t\t\t// TODO: Provide a more helpful error message.\n\t\t\tthrow new Error(\n\t\t\t\t\"A local Slice Simulator URL must be configured in your Slice Machine configuration file.\",\n\t\t\t);\n\t\t}\n\n\t\tconst { model } = await this.slices.readSlice({\n\t\t\tlibraryID: args.libraryID,\n\t\t\tsliceID: args.sliceID,\n\t\t});\n\t\tif (!model) {\n\t\t\tthrow new Error(\n\t\t\t\t`Did not find a Slice in library \"${args.libraryID}\" with ID \"${args.sliceID}\".`,\n\t\t\t);\n\t\t}\n\n\t\tconst viewport = args.viewport || DEFAULT_SCREENSHOT_VIEWPORT;\n\n\t\t// TODO: Change `model.name` to `args.sliceID`?\n\t\t// Making that change would require changing the screenshot\n\t\t// page path in Slice Machine UI.\n\t\tconst url = new URL(\n\t\t\t`./${encodeSliceSimulatorURLPart(args.libraryID)}/${model.name}/${\n\t\t\t\targs.variationID\n\t\t\t}/screenshot`,\n\t\t\targs.sliceMachineUIOrigin,\n\t\t);\n\t\turl.searchParams.set(\"screenWidth\", viewport.width.toString());\n\t\turl.searchParams.set(\"screenHeight\", viewport.height.toString());\n\n\t\tconst isURLAccessible = await checkIsURLAccessible(url.toString());\n\n\t\tif (!isURLAccessible) {\n\t\t\tthrow new Error(\n\t\t\t\t`Slice Simulator screenshot URL is not accessible: ${url}`,\n\t\t\t);\n\t\t}\n\n\t\tconst page = await this._browserContext.newPage();\n\t\tpage.setViewport(viewport);\n\n\t\tawait page.goto(url.toString(), { waitUntil: \"load\" });\n\t\tawait page.waitForSelector(SLICE_SIMULATOR_WAIT_FOR_SELECTOR, {\n\t\t\ttimeout: SLICE_SIMULATOR_WAIT_FOR_TIMEOUT,\n\t\t});\n\n\t\tconst element = await page.$(SLICE_SIMULATOR_SCREENSHOT_SELECTOR);\n\t\tif (!element) {\n\t\t\tconst baseURL = new URL(url.pathname, url.origin);\n\n\t\t\tthrow new Error(\n\t\t\t\t`Slice Simulator did not find ${SLICE_SIMULATOR_WAIT_FOR_SELECTOR} on the page. Verify the URL is correct: ${baseURL}`,\n\t\t\t);\n\t\t}\n\n\t\tconst data = (await element.screenshot({\n\t\t\tencoding: \"binary\",\n\t\t\tclip: {\n\t\t\t\twidth: viewport.width,\n\t\t\t\theight: viewport.height,\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t},\n\t\t})) as Buffer;\n\n\t\treturn {\n\t\t\tdata,\n\t\t};\n\t}\n\n\tasync uploadScreenshot(\n\t\targs: ScreenshotsManagerUploadScreenshotArgs,\n\t): Promise<ScreenshotsManagerUploadScreenshotReturnType> {\n\t\tassertS3ACLInitialized(this._s3ACL);\n\n\t\tconst formData = new FormData();\n\n\t\tfor (const requiredFormDataFieldKey in this._s3ACL.requiredFormDataFields) {\n\t\t\tformData.append(\n\t\t\t\trequiredFormDataFieldKey,\n\t\t\t\tthis._s3ACL.requiredFormDataFields[requiredFormDataFieldKey],\n\t\t\t);\n\t\t}\n\n\t\tconst contentDigest = createContentDigest(args.data);\n\t\tconst fileType = await fileTypeFromBuffer(args.data);\n\t\tconst fileName = fileType\n\t\t\t? `${contentDigest}.${fileType.ext}`\n\t\t\t: contentDigest;\n\t\tconst key = args.keyPrefix ? `${args.keyPrefix}/${fileName}` : fileName;\n\n\t\tformData.set(\"key\", key);\n\n\t\tif (fileType) {\n\t\t\tformData.set(\"Content-Type\", fileType.mime);\n\t\t}\n\n\t\tformData.set(\"file\", new Blob([args.data], { type: fileType?.mime }));\n\n\t\tconst res = await fetch(this._s3ACL.uploadEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: formData,\n\t\t});\n\n\t\tif (res.ok) {\n\t\t\tconst url = new URL(key, this._s3ACL.imgixEndpoint);\n\t\t\turl.searchParams.set(\"auto\", \"compress,format\");\n\n\t\t\treturn {\n\t\t\t\turl: url.toString(),\n\t\t\t};\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Unable to upload screenshot with status code: ${res.status}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync deleteScreenshotFolder(\n\t\targs: ScreenshotsManagerDeleteScreenshotFolderArgs,\n\t): Promise<void> {\n\t\tconst res = await this._fetch({\n\t\t\tbody: { sliceId: args.sliceID },\n\t\t\tmethod: \"POST\",\n\t\t\turl: new URL(\"delete-folder\", API_ENDPOINTS.AwsAclProvider),\n\t\t});\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unable to delete screenshot folder with status code: ${res.status}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async _fetch(args: {\n\t\turl: URL;\n\t\tmethod?: \"GET\" | \"POST\";\n\t\tbody?: unknown;\n\t}): Promise<Response> {\n\t\tconst authenticationToken = await this.user.getAuthenticationToken();\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\treturn await fetch(args.url, {\n\t\t\tbody: args.body ? JSON.stringify(args.body) : undefined,\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${authenticationToken}`,\n\t\t\t\tRepository: sliceMachineConfig.repositoryName,\n\t\t\t\t\"User-Agent\": SLICE_MACHINE_USER_AGENT,\n\t\t\t\t...(args.body ? { \"Content-Type\": \"application/json\" } : {}),\n\t\t\t},\n\t\t\tmethod: args.method,\n\t\t});\n\t}\n}\n"],"names":["BaseManager","InternalError","API_ENDPOINTS","error","decode","t","checkIsURLAccessible","FormData","createContentDigest","fileTypeFromBuffer","Blob","fetch","SLICE_MACHINE_USER_AGENT"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBA,MAAM,mCAAmC;AACzC,MAAM,oCAAoC;AAC1C,MAAM,sCAAsC;AAE5C,MAAM,8BAAwC;AAAA,EAC7C,OAAO;AAAA,EACP,QAAQ;;AAGT,SAAS,uBACR,OAAwB;AAExB,MAAI,SAAS,QAAW;AACjB,UAAA,IAAI,MACT,gIAAgI;AAAA,EAEjI;AACF;AAEA,SAAS,gCACR,gBAA0C;AAE1C,MAAI,kBAAkB,QAAW;AAC1B,UAAA,IAAI,MACT,iJAAiJ;AAAA,EAElJ;AACF;AAgBA,MAAM,8BAA8B,CAAC,YAA2B;AACxD,SAAA,QAAQ,QAAQ,OAAO,IAAI;AACnC;AA2BM,MAAO,2BAA2BA,YAAAA,YAAW;AAAA,EAA7C;AAAA;AACG;AACA;AAAA;AAAA,EAER,MAAM,qBAAkB;AACvB,QAAI,KAAK,iBAAiB;AACzB;AAAA,IACA;AAEG,QAAA;AACA,QAAA;AAES,kBAAA,MAAM,OAAO,WAAW;AAAA,IAAA,QACnC;AACK,YAAA,IAAIC,OAAAA,cACT,iIAAiI;AAAA,IAElI;AAEK,UAAA,UAAU,MAAM,UAAU;AAE3B,SAAA,kBAAkB,MAAM,QAAQ;EACtC;AAAA,EAEA,MAAM,YAAS;AACd,QAAI,KAAK,QAAQ;AAChB;AAAA,IACA;AAED,UAAM,YAAY,IAAI,IAAI,UAAUC,4BAAc,cAAc;AAChE,UAAM,YAAY,MAAM,KAAK,OAAO,EAAE,KAAK,WAAW;AAEhD,UAAA,aAAa,MAAM,UAAU;AAC/B,QAAA;AACA,QAAA;AACU,mBAAA,KAAK,MAAM,UAAU;AAAA,aAC1BC;AAER,YAAM,IAAI,MACT,iCAAiC,cAAc,YAAY;AAAA,IAE5D;AAED,UAAM,EAAE,OAAO,QAAQ,MAAU,IAAAC,OAAA,OAChCC,aAAE,aAAa;AAAA,MACdA,aAAE,KAAK;AAAA,QACN,QAAQA,aAAE,KAAK;AAAA,UACd,KAAKA,aAAE;AAAA,UACP,QAAQA,aAAE,OAAOA,aAAE,QAAQA,aAAE,MAAM;AAAA,QAAA,CACnC;AAAA,QACD,eAAeA,aAAE;AAAA,MAAA,CACjB;AAAA,MACDA,aAAE,QAAQ;AAAA,QACT,SAASA,aAAE;AAAA,QACX,SAASA,aAAE;AAAA,QACX,OAAOA,aAAE;AAAA,MAAA,CACT;AAAA,IAAA,CACD,GACD,UAAU;AAGX,QAAI,OAAO;AACJ,YAAA,IAAI,MAAM,iCAAiC,WAAW;AAAA,IAC5D;AAED,UAAM,eAAe,OAAO,SAAS,OAAO,WAAW,OAAO;AAC9D,QAAI,cAAc;AACX,YAAA,IAAI,MAAM,gCAAgC,cAAc;AAAA,IAC9D;AAED,SAAK,SAAS;AAAA,MACb,gBAAgB,OAAO,OAAO;AAAA,MAC9B,wBAAwB,OAAO,OAAO;AAAA,MACtC,eAAe,OAAO;AAAA,IAAA;AAAA,EAExB;AAAA;AAAA;AAAA,EAIA,MAAM,gCACL,MAA2D;AAE3D,oCAAgC,KAAK,eAAe;AAEpD,UAAM,qBAAqB,MAAM,KAAK,QAAQ,sBAAqB;AAE/D,QAAA,CAAC,mBAAmB,wBAAwB;AAEzC,YAAA,IAAI,MACT,0FAA0F;AAAA,IAE3F;AAED,UAAM,EAAE,MAAK,IAAK,MAAM,KAAK,OAAO,UAAU;AAAA,MAC7C,WAAW,KAAK;AAAA,MAChB,SAAS,KAAK;AAAA,IAAA,CACd;AACD,QAAI,CAAC,OAAO;AACX,YAAM,IAAI,MACT,oCAAoC,KAAK,uBAAuB,KAAK,WAAW;AAAA,IAEjF;AAEK,UAAA,WAAW,KAAK,YAAY;AAKlC,UAAM,MAAM,IAAI,IACf,KAAK,4BAA4B,KAAK,SAAS,KAAK,MAAM,QACzD,KAAK,0BAEN,KAAK,oBAAoB;AAE1B,QAAI,aAAa,IAAI,eAAe,SAAS,MAAM,UAAU;AAC7D,QAAI,aAAa,IAAI,gBAAgB,SAAS,OAAO,UAAU;AAE/D,UAAM,kBAAkB,MAAMC,qBAAAA,qBAAqB,IAAI,SAAU,CAAA;AAEjE,QAAI,CAAC,iBAAiB;AACf,YAAA,IAAI,MACT,qDAAqD,KAAK;AAAA,IAE3D;AAED,UAAM,OAAO,MAAM,KAAK,gBAAgB,QAAO;AAC/C,SAAK,YAAY,QAAQ;AAEnB,UAAA,KAAK,KAAK,IAAI,YAAY,EAAE,WAAW,QAAQ;AAC/C,UAAA,KAAK,gBAAgB,mCAAmC;AAAA,MAC7D,SAAS;AAAA,IAAA,CACT;AAED,UAAM,UAAU,MAAM,KAAK,EAAE,mCAAmC;AAChE,QAAI,CAAC,SAAS;AACb,YAAM,UAAU,IAAI,IAAI,IAAI,UAAU,IAAI,MAAM;AAEhD,YAAM,IAAI,MACT,gCAAgC,6EAA6E,SAAS;AAAA,IAEvH;AAEK,UAAA,OAAQ,MAAM,QAAQ,WAAW;AAAA,MACtC,UAAU;AAAA,MACV,MAAM;AAAA,QACL,OAAO,SAAS;AAAA,QAChB,QAAQ,SAAS;AAAA,QACjB,GAAG;AAAA,QACH,GAAG;AAAA,MACH;AAAA,IAAA,CACD;AAEM,WAAA;AAAA,MACN;AAAA,IAAA;AAAA,EAEF;AAAA,EAEA,MAAM,iBACL,MAA4C;AAE5C,2BAAuB,KAAK,MAAM;AAE5B,UAAA,WAAW,IAAIC,QAAAA;AAEV,eAAA,4BAA4B,KAAK,OAAO,wBAAwB;AAC1E,eAAS,OACR,0BACA,KAAK,OAAO,uBAAuB,wBAAwB,CAAC;AAAA,IAE7D;AAEK,UAAA,gBAAgBC,oBAAAA,oBAAoB,KAAK,IAAI;AACnD,UAAM,WAAW,MAAMC,KAAAA,mBAAmB,KAAK,IAAI;AACnD,UAAM,WAAW,WACd,GAAG,iBAAiB,SAAS,QAC7B;AACH,UAAM,MAAM,KAAK,YAAY,GAAG,KAAK,aAAa,aAAa;AAEtD,aAAA,IAAI,OAAO,GAAG;AAEvB,QAAI,UAAU;AACJ,eAAA,IAAI,gBAAgB,SAAS,IAAI;AAAA,IAC1C;AAED,aAAS,IAAI,QAAQ,IAAIC,MAAAA,QAAK,CAAC,KAAK,IAAI,GAAG,EAAE,MAAM,qCAAU,KAAA,CAAM,CAAC;AAEpE,UAAM,MAAM,MAAMC,QAAAA,QAAM,KAAK,OAAO,gBAAgB;AAAA,MACnD,QAAQ;AAAA,MACR,MAAM;AAAA,IAAA,CACN;AAED,QAAI,IAAI,IAAI;AACX,YAAM,MAAM,IAAI,IAAI,KAAK,KAAK,OAAO,aAAa;AAC9C,UAAA,aAAa,IAAI,QAAQ,iBAAiB;AAEvC,aAAA;AAAA,QACN,KAAK,IAAI,SAAU;AAAA,MAAA;AAAA,WAEd;AACN,YAAM,IAAI,MACT,iDAAiD,IAAI,QAAQ;AAAA,IAE9D;AAAA,EACF;AAAA,EAEA,MAAM,uBACL,MAAkD;AAE5C,UAAA,MAAM,MAAM,KAAK,OAAO;AAAA,MAC7B,MAAM,EAAE,SAAS,KAAK,QAAS;AAAA,MAC/B,QAAQ;AAAA,MACR,KAAK,IAAI,IAAI,iBAAiBT,cAAAA,cAAc,cAAc;AAAA,IAAA,CAC1D;AACG,QAAA,CAAC,IAAI,IAAI;AACZ,YAAM,IAAI,MACT,wDAAwD,IAAI,QAAQ;AAAA,IAErE;AAAA,EACF;AAAA,EAEQ,MAAM,OAAO,MAIpB;AACA,UAAM,sBAAsB,MAAM,KAAK,KAAK,uBAAsB;AAClE,UAAM,qBAAqB,MAAM,KAAK,QAAQ,sBAAqB;AAE5D,WAAA,MAAMS,QAAAA,QAAM,KAAK,KAAK;AAAA,MAC5B,MAAM,KAAK,OAAO,KAAK,UAAU,KAAK,IAAI,IAAI;AAAA,MAC9C,SAAS;AAAA,QACR,eAAe,UAAU;AAAA,QACzB,YAAY,mBAAmB;AAAA,QAC/B,cAAcC,yBAAA;AAAA,QACd,GAAI,KAAK,OAAO,EAAE,gBAAgB,uBAAuB;MACzD;AAAA,MACD,QAAQ,KAAK;AAAA,IAAA,CACb;AAAA,EACF;AACA;;"}
|
|
@@ -18,6 +18,9 @@ type ScreenshotsManagerUploadScreenshotArgs = {
|
|
|
18
18
|
type ScreenshotsManagerUploadScreenshotReturnType = {
|
|
19
19
|
url: string;
|
|
20
20
|
};
|
|
21
|
+
type ScreenshotsManagerDeleteScreenshotFolderArgs = {
|
|
22
|
+
sliceID: string;
|
|
23
|
+
};
|
|
21
24
|
export declare class ScreenshotsManager extends BaseManager {
|
|
22
25
|
private _browserContext;
|
|
23
26
|
private _s3ACL;
|
|
@@ -25,5 +28,7 @@ export declare class ScreenshotsManager extends BaseManager {
|
|
|
25
28
|
initS3ACL(): Promise<void>;
|
|
26
29
|
captureSliceSimulatorScreenshot(args: ScreenshotsManagerCaptureSliceSimulatorScreenshotArgs): Promise<ScreenshotsManagerCaptureSliceSimulatorScreenshotReturnType>;
|
|
27
30
|
uploadScreenshot(args: ScreenshotsManagerUploadScreenshotArgs): Promise<ScreenshotsManagerUploadScreenshotReturnType>;
|
|
31
|
+
deleteScreenshotFolder(args: ScreenshotsManagerDeleteScreenshotFolderArgs): Promise<void>;
|
|
32
|
+
private _fetch;
|
|
28
33
|
}
|
|
29
34
|
export {};
|
|
@@ -64,16 +64,8 @@ class ScreenshotsManager extends BaseManager {
|
|
|
64
64
|
if (this._s3ACL) {
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
67
|
-
const sliceMachineConfig = await this.project.getSliceMachineConfig();
|
|
68
|
-
const authenticationToken = await this.user.getAuthenticationToken();
|
|
69
67
|
const awsACLURL = new URL("create", API_ENDPOINTS.AwsAclProvider);
|
|
70
|
-
const awsACLRes = await
|
|
71
|
-
headers: {
|
|
72
|
-
Authorization: `Bearer ${authenticationToken}`,
|
|
73
|
-
"User-Agent": SLICE_MACHINE_USER_AGENT,
|
|
74
|
-
Repository: sliceMachineConfig.repositoryName
|
|
75
|
-
}
|
|
76
|
-
});
|
|
68
|
+
const awsACLRes = await this._fetch({ url: awsACLURL });
|
|
77
69
|
const awsACLText = await awsACLRes.text();
|
|
78
70
|
let awsACLJSON;
|
|
79
71
|
try {
|
|
@@ -184,6 +176,30 @@ class ScreenshotsManager extends BaseManager {
|
|
|
184
176
|
throw new Error(`Unable to upload screenshot with status code: ${res.status}`);
|
|
185
177
|
}
|
|
186
178
|
}
|
|
179
|
+
async deleteScreenshotFolder(args) {
|
|
180
|
+
const res = await this._fetch({
|
|
181
|
+
body: { sliceId: args.sliceID },
|
|
182
|
+
method: "POST",
|
|
183
|
+
url: new URL("delete-folder", API_ENDPOINTS.AwsAclProvider)
|
|
184
|
+
});
|
|
185
|
+
if (!res.ok) {
|
|
186
|
+
throw new Error(`Unable to delete screenshot folder with status code: ${res.status}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async _fetch(args) {
|
|
190
|
+
const authenticationToken = await this.user.getAuthenticationToken();
|
|
191
|
+
const sliceMachineConfig = await this.project.getSliceMachineConfig();
|
|
192
|
+
return await fetch(args.url, {
|
|
193
|
+
body: args.body ? JSON.stringify(args.body) : void 0,
|
|
194
|
+
headers: {
|
|
195
|
+
Authorization: `Bearer ${authenticationToken}`,
|
|
196
|
+
Repository: sliceMachineConfig.repositoryName,
|
|
197
|
+
"User-Agent": SLICE_MACHINE_USER_AGENT,
|
|
198
|
+
...args.body ? { "Content-Type": "application/json" } : {}
|
|
199
|
+
},
|
|
200
|
+
method: args.method
|
|
201
|
+
});
|
|
202
|
+
}
|
|
187
203
|
}
|
|
188
204
|
export {
|
|
189
205
|
ScreenshotsManager
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScreenshotsManager.js","sources":["../../../../src/managers/screenshots/ScreenshotsManager.ts"],"sourcesContent":["import * as t from \"io-ts\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport fetch, { FormData, Blob } from \"node-fetch\";\n// puppeteer is lazy-loaded in captureSliceSimulatorScreenshot\nimport type { BrowserContext, Viewport } from \"puppeteer\";\n\nimport { checkIsURLAccessible } from \"../../lib/checkIsURLAccessible\";\nimport { createContentDigest } from \"../../lib/createContentDigest\";\nimport { decode } from \"../../lib/decode\";\n\nimport { S3ACL } from \"../../types\";\nimport { SLICE_MACHINE_USER_AGENT } from \"../../constants/SLICE_MACHINE_USER_AGENT\";\nimport { API_ENDPOINTS } from \"../../constants/API_ENDPOINTS\";\nimport { InternalError } from \"../../errors\";\n\nimport { BaseManager } from \"../BaseManager\";\n\nconst SLICE_SIMULATOR_WAIT_FOR_TIMEOUT = 10_000; // ms\nconst SLICE_SIMULATOR_WAIT_FOR_SELECTOR = \"#__iframe-ready\";\nconst SLICE_SIMULATOR_SCREENSHOT_SELECTOR = \"#__iframe-renderer\";\n\nconst DEFAULT_SCREENSHOT_VIEWPORT: Viewport = {\n\twidth: 1200,\n\theight: 800,\n};\n\nfunction assertS3ACLInitialized(\n\ts3ACL: S3ACL | undefined,\n): asserts s3ACL is NonNullable<typeof s3ACL> {\n\tif (s3ACL == undefined) {\n\t\tthrow new Error(\n\t\t\t\"An S3 ACL has not been initialized. Run `SliceMachineManager.screenshots.prototype.initS3ACL()` before re-calling this method.\",\n\t\t);\n\t}\n}\n\nfunction assertBrowserContextInitialized(\n\tbrowserContext: BrowserContext | undefined,\n): asserts browserContext is NonNullable<typeof browserContext> {\n\tif (browserContext == undefined) {\n\t\tthrow new Error(\n\t\t\t\"A browser context has not been initialized. Run `SliceMachineManager.screenshots.prototype.initBrowserContext()` before re-calling this method.\",\n\t\t);\n\t}\n}\n\n/**\n * Encodes a part of a Slice Simulator URL to ensure it can be added to a URL\n * safely.\n *\n * The encoding logic must match Slice Machine UI's URL encoding practices.\n * Today, that requires the following:\n *\n * - Replace \"/\" with \"--\" (e.g. a Slice Library ID of \"./slices\" should turn into\n * \".--slices\")\n *\n * @param urlPart - A part of the URL.\n *\n * @returns `urlPart` encoded for use in a URL.\n */\nconst encodeSliceSimulatorURLPart = (urlPart: string): string => {\n\treturn urlPart.replace(/\\//g, \"--\");\n};\n\ntype ScreenshotsManagerCaptureSliceSimulatorScreenshotArgs = {\n\tsliceMachineUIOrigin: string;\n\tlibraryID: string;\n\tsliceID: string;\n\tvariationID: string;\n\tviewport?: Viewport;\n};\n\ntype ScreenshotsManagerCaptureSliceSimulatorScreenshotReturnType = {\n\tdata: Buffer;\n};\n\ntype ScreenshotsManagerUploadScreenshotArgs = {\n\tdata: Buffer;\n\tkeyPrefix?: string;\n};\n\ntype ScreenshotsManagerUploadScreenshotReturnType = {\n\turl: string;\n};\n\nexport class ScreenshotsManager extends BaseManager {\n\tprivate _browserContext: BrowserContext | undefined;\n\tprivate _s3ACL: S3ACL | undefined;\n\n\tasync initBrowserContext(): Promise<void> {\n\t\tif (this._browserContext) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet puppeteer: typeof import(\"puppeteer\");\n\t\ttry {\n\t\t\t// Lazy-load Puppeteer only once it is needed.\n\t\t\tpuppeteer = await import(\"puppeteer\");\n\t\t} catch {\n\t\t\tthrow new InternalError(\n\t\t\t\t\"Screenshots require Puppeteer but Puppeteer was not found. Check that the `puppeteer` package is installed before trying again.\",\n\t\t\t);\n\t\t}\n\n\t\tconst browser = await puppeteer.launch();\n\n\t\tthis._browserContext = await browser.createIncognitoBrowserContext();\n\t}\n\n\tasync initS3ACL(): Promise<void> {\n\t\tif (this._s3ACL) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\t\tconst authenticationToken = await this.user.getAuthenticationToken();\n\n\t\tconst awsACLURL = new URL(\"create\", API_ENDPOINTS.AwsAclProvider);\n\t\tconst awsACLRes = await fetch(awsACLURL.toString(), {\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${authenticationToken}`,\n\t\t\t\t\"User-Agent\": SLICE_MACHINE_USER_AGENT,\n\t\t\t\tRepository: sliceMachineConfig.repositoryName,\n\t\t\t},\n\t\t});\n\n\t\tconst awsACLText = await awsACLRes.text();\n\t\tlet awsACLJSON: unknown;\n\t\ttry {\n\t\t\tawsACLJSON = JSON.parse(awsACLText);\n\t\t} catch (error) {\n\t\t\t// Response is not JSON\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid AWS ACL response from ${awsACLURL}: ${awsACLText}`,\n\t\t\t);\n\t\t}\n\n\t\tconst { value: awsACL, error } = decode(\n\t\t\tt.intersection([\n\t\t\t\tt.type({\n\t\t\t\t\tvalues: t.type({\n\t\t\t\t\t\turl: t.string,\n\t\t\t\t\t\tfields: t.record(t.string, t.string),\n\t\t\t\t\t}),\n\t\t\t\t\timgixEndpoint: t.string,\n\t\t\t\t}),\n\t\t\t\tt.partial({\n\t\t\t\t\tmessage: t.string,\n\t\t\t\t\tMessage: t.string,\n\t\t\t\t\terror: t.string,\n\t\t\t\t}),\n\t\t\t]),\n\t\t\tawsACLJSON,\n\t\t);\n\n\t\tif (error) {\n\t\t\tthrow new Error(`Invalid AWS ACL response from ${awsACLURL}`);\n\t\t}\n\n\t\tconst errorMessage = awsACL.error || awsACL.message || awsACL.Message;\n\t\tif (errorMessage) {\n\t\t\tthrow new Error(`Failed to create an AWS ACL: ${errorMessage}`);\n\t\t}\n\n\t\tthis._s3ACL = {\n\t\t\tuploadEndpoint: awsACL.values.url,\n\t\t\trequiredFormDataFields: awsACL.values.fields,\n\t\t\timgixEndpoint: awsACL.imgixEndpoint,\n\t\t};\n\t}\n\n\t// TODO: Abstract to a generic `captureScreenshot()` method that is\n\t// used within a Slice-specific method in SliceManager.\n\tasync captureSliceSimulatorScreenshot(\n\t\targs: ScreenshotsManagerCaptureSliceSimulatorScreenshotArgs,\n\t): Promise<ScreenshotsManagerCaptureSliceSimulatorScreenshotReturnType> {\n\t\tassertBrowserContextInitialized(this._browserContext);\n\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\tif (!sliceMachineConfig.localSliceSimulatorURL) {\n\t\t\t// TODO: Provide a more helpful error message.\n\t\t\tthrow new Error(\n\t\t\t\t\"A local Slice Simulator URL must be configured in your Slice Machine configuration file.\",\n\t\t\t);\n\t\t}\n\n\t\tconst { model } = await this.slices.readSlice({\n\t\t\tlibraryID: args.libraryID,\n\t\t\tsliceID: args.sliceID,\n\t\t});\n\t\tif (!model) {\n\t\t\tthrow new Error(\n\t\t\t\t`Did not find a Slice in library \"${args.libraryID}\" with ID \"${args.sliceID}\".`,\n\t\t\t);\n\t\t}\n\n\t\tconst viewport = args.viewport || DEFAULT_SCREENSHOT_VIEWPORT;\n\n\t\t// TODO: Change `model.name` to `args.sliceID`?\n\t\t// Making that change would require changing the screenshot\n\t\t// page path in Slice Machine UI.\n\t\tconst url = new URL(\n\t\t\t`./${encodeSliceSimulatorURLPart(args.libraryID)}/${model.name}/${\n\t\t\t\targs.variationID\n\t\t\t}/screenshot`,\n\t\t\targs.sliceMachineUIOrigin,\n\t\t);\n\t\turl.searchParams.set(\"screenWidth\", viewport.width.toString());\n\t\turl.searchParams.set(\"screenHeight\", viewport.height.toString());\n\n\t\tconst isURLAccessible = await checkIsURLAccessible(url.toString());\n\n\t\tif (!isURLAccessible) {\n\t\t\tthrow new Error(\n\t\t\t\t`Slice Simulator screenshot URL is not accessible: ${url}`,\n\t\t\t);\n\t\t}\n\n\t\tconst page = await this._browserContext.newPage();\n\t\tpage.setViewport(viewport);\n\n\t\tawait page.goto(url.toString(), { waitUntil: \"load\" });\n\t\tawait page.waitForSelector(SLICE_SIMULATOR_WAIT_FOR_SELECTOR, {\n\t\t\ttimeout: SLICE_SIMULATOR_WAIT_FOR_TIMEOUT,\n\t\t});\n\n\t\tconst element = await page.$(SLICE_SIMULATOR_SCREENSHOT_SELECTOR);\n\t\tif (!element) {\n\t\t\tconst baseURL = new URL(url.pathname, url.origin);\n\n\t\t\tthrow new Error(\n\t\t\t\t`Slice Simulator did not find ${SLICE_SIMULATOR_WAIT_FOR_SELECTOR} on the page. Verify the URL is correct: ${baseURL}`,\n\t\t\t);\n\t\t}\n\n\t\tconst data = (await element.screenshot({\n\t\t\tencoding: \"binary\",\n\t\t\tclip: {\n\t\t\t\twidth: viewport.width,\n\t\t\t\theight: viewport.height,\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t},\n\t\t})) as Buffer;\n\n\t\treturn {\n\t\t\tdata,\n\t\t};\n\t}\n\n\tasync uploadScreenshot(\n\t\targs: ScreenshotsManagerUploadScreenshotArgs,\n\t): Promise<ScreenshotsManagerUploadScreenshotReturnType> {\n\t\tassertS3ACLInitialized(this._s3ACL);\n\n\t\tconst formData = new FormData();\n\n\t\tfor (const requiredFormDataFieldKey in this._s3ACL.requiredFormDataFields) {\n\t\t\tformData.append(\n\t\t\t\trequiredFormDataFieldKey,\n\t\t\t\tthis._s3ACL.requiredFormDataFields[requiredFormDataFieldKey],\n\t\t\t);\n\t\t}\n\n\t\tconst contentDigest = createContentDigest(args.data);\n\t\tconst fileType = await fileTypeFromBuffer(args.data);\n\t\tconst fileName = fileType\n\t\t\t? `${contentDigest}.${fileType.ext}`\n\t\t\t: contentDigest;\n\t\tconst key = args.keyPrefix ? `${args.keyPrefix}/${fileName}` : fileName;\n\n\t\tformData.set(\"key\", key);\n\n\t\tif (fileType) {\n\t\t\tformData.set(\"Content-Type\", fileType.mime);\n\t\t}\n\n\t\tformData.set(\"file\", new Blob([args.data], { type: fileType?.mime }));\n\n\t\tconst res = await fetch(this._s3ACL.uploadEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: formData,\n\t\t});\n\n\t\tif (res.ok) {\n\t\t\tconst url = new URL(key, this._s3ACL.imgixEndpoint);\n\t\t\turl.searchParams.set(\"auto\", \"compress,format\");\n\n\t\t\treturn {\n\t\t\t\turl: url.toString(),\n\t\t\t};\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Unable to upload screenshot with status code: ${res.status}`,\n\t\t\t);\n\t\t}\n\t}\n}\n"],"names":["error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ScreenshotsManager.js","sources":["../../../../src/managers/screenshots/ScreenshotsManager.ts"],"sourcesContent":["import * as t from \"io-ts\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport fetch, { FormData, Blob, Response } from \"node-fetch\";\n// puppeteer is lazy-loaded in captureSliceSimulatorScreenshot\nimport type { BrowserContext, Viewport } from \"puppeteer\";\n\nimport { checkIsURLAccessible } from \"../../lib/checkIsURLAccessible\";\nimport { createContentDigest } from \"../../lib/createContentDigest\";\nimport { decode } from \"../../lib/decode\";\n\nimport { S3ACL } from \"../../types\";\nimport { SLICE_MACHINE_USER_AGENT } from \"../../constants/SLICE_MACHINE_USER_AGENT\";\nimport { API_ENDPOINTS } from \"../../constants/API_ENDPOINTS\";\nimport { InternalError } from \"../../errors\";\n\nimport { BaseManager } from \"../BaseManager\";\n\nconst SLICE_SIMULATOR_WAIT_FOR_TIMEOUT = 10_000; // ms\nconst SLICE_SIMULATOR_WAIT_FOR_SELECTOR = \"#__iframe-ready\";\nconst SLICE_SIMULATOR_SCREENSHOT_SELECTOR = \"#__iframe-renderer\";\n\nconst DEFAULT_SCREENSHOT_VIEWPORT: Viewport = {\n\twidth: 1200,\n\theight: 800,\n};\n\nfunction assertS3ACLInitialized(\n\ts3ACL: S3ACL | undefined,\n): asserts s3ACL is NonNullable<typeof s3ACL> {\n\tif (s3ACL == undefined) {\n\t\tthrow new Error(\n\t\t\t\"An S3 ACL has not been initialized. Run `SliceMachineManager.screenshots.prototype.initS3ACL()` before re-calling this method.\",\n\t\t);\n\t}\n}\n\nfunction assertBrowserContextInitialized(\n\tbrowserContext: BrowserContext | undefined,\n): asserts browserContext is NonNullable<typeof browserContext> {\n\tif (browserContext == undefined) {\n\t\tthrow new Error(\n\t\t\t\"A browser context has not been initialized. Run `SliceMachineManager.screenshots.prototype.initBrowserContext()` before re-calling this method.\",\n\t\t);\n\t}\n}\n\n/**\n * Encodes a part of a Slice Simulator URL to ensure it can be added to a URL\n * safely.\n *\n * The encoding logic must match Slice Machine UI's URL encoding practices.\n * Today, that requires the following:\n *\n * - Replace \"/\" with \"--\" (e.g. a Slice Library ID of \"./slices\" should turn into\n * \".--slices\")\n *\n * @param urlPart - A part of the URL.\n *\n * @returns `urlPart` encoded for use in a URL.\n */\nconst encodeSliceSimulatorURLPart = (urlPart: string): string => {\n\treturn urlPart.replace(/\\//g, \"--\");\n};\n\ntype ScreenshotsManagerCaptureSliceSimulatorScreenshotArgs = {\n\tsliceMachineUIOrigin: string;\n\tlibraryID: string;\n\tsliceID: string;\n\tvariationID: string;\n\tviewport?: Viewport;\n};\n\ntype ScreenshotsManagerCaptureSliceSimulatorScreenshotReturnType = {\n\tdata: Buffer;\n};\n\ntype ScreenshotsManagerUploadScreenshotArgs = {\n\tdata: Buffer;\n\tkeyPrefix?: string;\n};\n\ntype ScreenshotsManagerUploadScreenshotReturnType = {\n\turl: string;\n};\n\ntype ScreenshotsManagerDeleteScreenshotFolderArgs = {\n\tsliceID: string;\n};\n\nexport class ScreenshotsManager extends BaseManager {\n\tprivate _browserContext: BrowserContext | undefined;\n\tprivate _s3ACL: S3ACL | undefined;\n\n\tasync initBrowserContext(): Promise<void> {\n\t\tif (this._browserContext) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet puppeteer: typeof import(\"puppeteer\");\n\t\ttry {\n\t\t\t// Lazy-load Puppeteer only once it is needed.\n\t\t\tpuppeteer = await import(\"puppeteer\");\n\t\t} catch {\n\t\t\tthrow new InternalError(\n\t\t\t\t\"Screenshots require Puppeteer but Puppeteer was not found. Check that the `puppeteer` package is installed before trying again.\",\n\t\t\t);\n\t\t}\n\n\t\tconst browser = await puppeteer.launch();\n\n\t\tthis._browserContext = await browser.createIncognitoBrowserContext();\n\t}\n\n\tasync initS3ACL(): Promise<void> {\n\t\tif (this._s3ACL) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst awsACLURL = new URL(\"create\", API_ENDPOINTS.AwsAclProvider);\n\t\tconst awsACLRes = await this._fetch({ url: awsACLURL });\n\n\t\tconst awsACLText = await awsACLRes.text();\n\t\tlet awsACLJSON: unknown;\n\t\ttry {\n\t\t\tawsACLJSON = JSON.parse(awsACLText);\n\t\t} catch (error) {\n\t\t\t// Response is not JSON\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid AWS ACL response from ${awsACLURL}: ${awsACLText}`,\n\t\t\t);\n\t\t}\n\n\t\tconst { value: awsACL, error } = decode(\n\t\t\tt.intersection([\n\t\t\t\tt.type({\n\t\t\t\t\tvalues: t.type({\n\t\t\t\t\t\turl: t.string,\n\t\t\t\t\t\tfields: t.record(t.string, t.string),\n\t\t\t\t\t}),\n\t\t\t\t\timgixEndpoint: t.string,\n\t\t\t\t}),\n\t\t\t\tt.partial({\n\t\t\t\t\tmessage: t.string,\n\t\t\t\t\tMessage: t.string,\n\t\t\t\t\terror: t.string,\n\t\t\t\t}),\n\t\t\t]),\n\t\t\tawsACLJSON,\n\t\t);\n\n\t\tif (error) {\n\t\t\tthrow new Error(`Invalid AWS ACL response from ${awsACLURL}`);\n\t\t}\n\n\t\tconst errorMessage = awsACL.error || awsACL.message || awsACL.Message;\n\t\tif (errorMessage) {\n\t\t\tthrow new Error(`Failed to create an AWS ACL: ${errorMessage}`);\n\t\t}\n\n\t\tthis._s3ACL = {\n\t\t\tuploadEndpoint: awsACL.values.url,\n\t\t\trequiredFormDataFields: awsACL.values.fields,\n\t\t\timgixEndpoint: awsACL.imgixEndpoint,\n\t\t};\n\t}\n\n\t// TODO: Abstract to a generic `captureScreenshot()` method that is\n\t// used within a Slice-specific method in SliceManager.\n\tasync captureSliceSimulatorScreenshot(\n\t\targs: ScreenshotsManagerCaptureSliceSimulatorScreenshotArgs,\n\t): Promise<ScreenshotsManagerCaptureSliceSimulatorScreenshotReturnType> {\n\t\tassertBrowserContextInitialized(this._browserContext);\n\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\tif (!sliceMachineConfig.localSliceSimulatorURL) {\n\t\t\t// TODO: Provide a more helpful error message.\n\t\t\tthrow new Error(\n\t\t\t\t\"A local Slice Simulator URL must be configured in your Slice Machine configuration file.\",\n\t\t\t);\n\t\t}\n\n\t\tconst { model } = await this.slices.readSlice({\n\t\t\tlibraryID: args.libraryID,\n\t\t\tsliceID: args.sliceID,\n\t\t});\n\t\tif (!model) {\n\t\t\tthrow new Error(\n\t\t\t\t`Did not find a Slice in library \"${args.libraryID}\" with ID \"${args.sliceID}\".`,\n\t\t\t);\n\t\t}\n\n\t\tconst viewport = args.viewport || DEFAULT_SCREENSHOT_VIEWPORT;\n\n\t\t// TODO: Change `model.name` to `args.sliceID`?\n\t\t// Making that change would require changing the screenshot\n\t\t// page path in Slice Machine UI.\n\t\tconst url = new URL(\n\t\t\t`./${encodeSliceSimulatorURLPart(args.libraryID)}/${model.name}/${\n\t\t\t\targs.variationID\n\t\t\t}/screenshot`,\n\t\t\targs.sliceMachineUIOrigin,\n\t\t);\n\t\turl.searchParams.set(\"screenWidth\", viewport.width.toString());\n\t\turl.searchParams.set(\"screenHeight\", viewport.height.toString());\n\n\t\tconst isURLAccessible = await checkIsURLAccessible(url.toString());\n\n\t\tif (!isURLAccessible) {\n\t\t\tthrow new Error(\n\t\t\t\t`Slice Simulator screenshot URL is not accessible: ${url}`,\n\t\t\t);\n\t\t}\n\n\t\tconst page = await this._browserContext.newPage();\n\t\tpage.setViewport(viewport);\n\n\t\tawait page.goto(url.toString(), { waitUntil: \"load\" });\n\t\tawait page.waitForSelector(SLICE_SIMULATOR_WAIT_FOR_SELECTOR, {\n\t\t\ttimeout: SLICE_SIMULATOR_WAIT_FOR_TIMEOUT,\n\t\t});\n\n\t\tconst element = await page.$(SLICE_SIMULATOR_SCREENSHOT_SELECTOR);\n\t\tif (!element) {\n\t\t\tconst baseURL = new URL(url.pathname, url.origin);\n\n\t\t\tthrow new Error(\n\t\t\t\t`Slice Simulator did not find ${SLICE_SIMULATOR_WAIT_FOR_SELECTOR} on the page. Verify the URL is correct: ${baseURL}`,\n\t\t\t);\n\t\t}\n\n\t\tconst data = (await element.screenshot({\n\t\t\tencoding: \"binary\",\n\t\t\tclip: {\n\t\t\t\twidth: viewport.width,\n\t\t\t\theight: viewport.height,\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t},\n\t\t})) as Buffer;\n\n\t\treturn {\n\t\t\tdata,\n\t\t};\n\t}\n\n\tasync uploadScreenshot(\n\t\targs: ScreenshotsManagerUploadScreenshotArgs,\n\t): Promise<ScreenshotsManagerUploadScreenshotReturnType> {\n\t\tassertS3ACLInitialized(this._s3ACL);\n\n\t\tconst formData = new FormData();\n\n\t\tfor (const requiredFormDataFieldKey in this._s3ACL.requiredFormDataFields) {\n\t\t\tformData.append(\n\t\t\t\trequiredFormDataFieldKey,\n\t\t\t\tthis._s3ACL.requiredFormDataFields[requiredFormDataFieldKey],\n\t\t\t);\n\t\t}\n\n\t\tconst contentDigest = createContentDigest(args.data);\n\t\tconst fileType = await fileTypeFromBuffer(args.data);\n\t\tconst fileName = fileType\n\t\t\t? `${contentDigest}.${fileType.ext}`\n\t\t\t: contentDigest;\n\t\tconst key = args.keyPrefix ? `${args.keyPrefix}/${fileName}` : fileName;\n\n\t\tformData.set(\"key\", key);\n\n\t\tif (fileType) {\n\t\t\tformData.set(\"Content-Type\", fileType.mime);\n\t\t}\n\n\t\tformData.set(\"file\", new Blob([args.data], { type: fileType?.mime }));\n\n\t\tconst res = await fetch(this._s3ACL.uploadEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: formData,\n\t\t});\n\n\t\tif (res.ok) {\n\t\t\tconst url = new URL(key, this._s3ACL.imgixEndpoint);\n\t\t\turl.searchParams.set(\"auto\", \"compress,format\");\n\n\t\t\treturn {\n\t\t\t\turl: url.toString(),\n\t\t\t};\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Unable to upload screenshot with status code: ${res.status}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync deleteScreenshotFolder(\n\t\targs: ScreenshotsManagerDeleteScreenshotFolderArgs,\n\t): Promise<void> {\n\t\tconst res = await this._fetch({\n\t\t\tbody: { sliceId: args.sliceID },\n\t\t\tmethod: \"POST\",\n\t\t\turl: new URL(\"delete-folder\", API_ENDPOINTS.AwsAclProvider),\n\t\t});\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unable to delete screenshot folder with status code: ${res.status}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async _fetch(args: {\n\t\turl: URL;\n\t\tmethod?: \"GET\" | \"POST\";\n\t\tbody?: unknown;\n\t}): Promise<Response> {\n\t\tconst authenticationToken = await this.user.getAuthenticationToken();\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\treturn await fetch(args.url, {\n\t\t\tbody: args.body ? JSON.stringify(args.body) : undefined,\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${authenticationToken}`,\n\t\t\t\tRepository: sliceMachineConfig.repositoryName,\n\t\t\t\t\"User-Agent\": SLICE_MACHINE_USER_AGENT,\n\t\t\t\t...(args.body ? { \"Content-Type\": \"application/json\" } : {}),\n\t\t\t},\n\t\t\tmethod: args.method,\n\t\t});\n\t}\n}\n"],"names":["error"],"mappings":"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"}
|
|
@@ -144,13 +144,31 @@ class SlicesManager extends BaseManager.BaseManager {
|
|
|
144
144
|
errors: hookResult.errors
|
|
145
145
|
};
|
|
146
146
|
}
|
|
147
|
-
// TODO: Disallow until Slices can be deleted.
|
|
148
147
|
async deleteSlice(args) {
|
|
149
148
|
assertPluginsInitialized.assertPluginsInitialized(this.sliceMachinePluginRunner);
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
};
|
|
149
|
+
const { model, errors: readSliceErrors } = await this.readSlice({
|
|
150
|
+
libraryID: args.libraryID,
|
|
151
|
+
sliceID: args.sliceID
|
|
152
|
+
});
|
|
153
|
+
if (model) {
|
|
154
|
+
const { errors: deleteSliceErrors } = await this.sliceMachinePluginRunner.callHook("slice:delete", {
|
|
155
|
+
model,
|
|
156
|
+
libraryID: args.libraryID
|
|
157
|
+
});
|
|
158
|
+
if (deleteSliceErrors.length > 0) {
|
|
159
|
+
return {
|
|
160
|
+
errors: deleteSliceErrors
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
const { errors: updateCustomTypeErrors } = await this._removeSliceFromCustomTypes(args.sliceID);
|
|
164
|
+
return {
|
|
165
|
+
errors: updateCustomTypeErrors
|
|
166
|
+
};
|
|
167
|
+
} else {
|
|
168
|
+
return {
|
|
169
|
+
errors: readSliceErrors
|
|
170
|
+
};
|
|
171
|
+
}
|
|
154
172
|
}
|
|
155
173
|
/**
|
|
156
174
|
* @returns Record of variation IDs mapped to uploaded screenshot URLs.
|
|
@@ -361,6 +379,36 @@ class SlicesManager extends BaseManager.BaseManager {
|
|
|
361
379
|
variations
|
|
362
380
|
};
|
|
363
381
|
}
|
|
382
|
+
async _removeSliceFromCustomTypes(sliceID) {
|
|
383
|
+
const { models, errors: customTypeReadErrors } = await this.customTypes.readAllCustomTypes();
|
|
384
|
+
await Promise.all(models.map(async (customType) => {
|
|
385
|
+
const updatedJsonModel = Object.entries(customType.model.json).reduce((tabAccumulator, [tabKey, tab]) => {
|
|
386
|
+
const updatedTabFields = Object.entries(tab).reduce((fieldAccumulator, [fieldKey, field]) => {
|
|
387
|
+
if (field.config === void 0 || field.type !== "Slices" || field.config.choices === void 0) {
|
|
388
|
+
return { ...fieldAccumulator, [fieldKey]: field };
|
|
389
|
+
}
|
|
390
|
+
const filteredChoices = Object.entries(field.config.choices).reduce((choiceAccumulator, [choiceKey, choice]) => {
|
|
391
|
+
if (choiceKey === sliceID) {
|
|
392
|
+
return choiceAccumulator;
|
|
393
|
+
}
|
|
394
|
+
return { ...choiceAccumulator, [choiceKey]: choice };
|
|
395
|
+
}, {});
|
|
396
|
+
return {
|
|
397
|
+
...fieldAccumulator,
|
|
398
|
+
[fieldKey]: {
|
|
399
|
+
...field,
|
|
400
|
+
config: { ...field.config, choices: filteredChoices }
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
}, {});
|
|
404
|
+
return { ...tabAccumulator, [tabKey]: updatedTabFields };
|
|
405
|
+
}, {});
|
|
406
|
+
await this.customTypes.updateCustomType({
|
|
407
|
+
model: { ...customType.model, json: updatedJsonModel }
|
|
408
|
+
});
|
|
409
|
+
}));
|
|
410
|
+
return { errors: customTypeReadErrors };
|
|
411
|
+
}
|
|
364
412
|
}
|
|
365
413
|
exports.SlicesManager = SlicesManager;
|
|
366
414
|
//# sourceMappingURL=SlicesManager.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SlicesManager.cjs","sources":["../../../../src/managers/slices/SlicesManager.ts"],"sourcesContent":["import * as t from \"io-ts\";\nimport fetch from \"node-fetch\";\nimport * as prismicCustomTypesClient from \"@prismicio/custom-types-client\";\nimport { CustomTypes } from \"@prismicio/types-internal\";\nimport { SharedSliceContent } from \"@prismicio/types-internal/lib/content\";\nimport {\n\tCallHookReturnType,\n\tHookError,\n\tSliceAssetUpdateHook,\n\tSliceCreateHook,\n\tSliceCreateHookData,\n\tSliceDeleteHook,\n\tSliceDeleteHookData,\n\tSliceLibraryReadHookData,\n\tSliceReadHookData,\n\tSliceRenameHook,\n\tSliceRenameHookData,\n\tSliceUpdateHook,\n\tSliceUpdateHookData,\n} from \"@slicemachine/plugin-kit\";\n\nimport { DecodeError } from \"../../lib/DecodeError\";\nimport { assertPluginsInitialized } from \"../../lib/assertPluginsInitialized\";\nimport { bufferCodec } from \"../../lib/bufferCodec\";\nimport { decodeHookResult } from \"../../lib/decodeHookResult\";\n\nimport { OnlyHookErrors } from \"../../types\";\nimport { DEFAULT_SLICE_SCREENSHOT_URL } from \"../../constants/DEFAULT_SLICE_SCREENSHOT_URL\";\nimport { API_ENDPOINTS } from \"../../constants/API_ENDPOINTS\";\nimport { UnauthenticatedError, UnauthorizedError } from \"../../errors\";\n\nimport { BaseManager } from \"../BaseManager\";\nimport { createContentDigest } from \"../../lib/createContentDigest\";\n\ntype SlicesManagerReadSliceLibraryReturnType = {\n\tsliceIDs: string[];\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SlicesManagerReadAllSliceLibrariesReturnType = {\n\tlibraries: {\n\t\tlibraryID: string;\n\t\tsliceIDs: string[] | undefined;\n\t}[];\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerReadAllSlicesForLibraryArgs = {\n\tlibraryID: string;\n};\n\ntype SliceMachineManagerReadAllSlicesForLibraryReturnType = {\n\tmodels: { model: CustomTypes.Widgets.Slices.SharedSlice }[];\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerReadAllSlicesReturnType = {\n\tmodels: {\n\t\tlibraryID: string;\n\t\tmodel: CustomTypes.Widgets.Slices.SharedSlice;\n\t}[];\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerReadSliceReturnType = {\n\tmodel: CustomTypes.Widgets.Slices.SharedSlice | undefined;\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerPushSliceArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n};\n\nexport type SliceMachineManagerPushSliceReturnType = {\n\t/**\n\t * A record of Slice variation IDs mapped to uploaded screenshot URLs.\n\t */\n\tscreenshotURLs: Record<string, string> | undefined;\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerReadSliceScreenshotArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n\tvariationID: string;\n};\n\ntype SliceMachineManagerReadSliceScreenshotReturnType = {\n\tdata: Buffer | undefined;\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerUpdateSliceScreenshotArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n\tvariationID: string;\n\tdata: Buffer;\n};\n\ntype SliceMachineManagerReadSliceMocksArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n};\n\ntype SliceMachineManagerReadSliceMocksReturnType = {\n\tmocks?: SharedSliceContent[];\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerReadSliceMocksConfigArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n};\n\ntype SliceMachineManagerReadSliceMocksConfigArgsReturnType = {\n\t// TODO\n\tmocksConfig?: Record<string, unknown>;\n\terrors: HookError[];\n};\n\ntype SliceMachineManagerUpdateSliceMocksArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n\tmocks: SharedSliceContent[];\n};\n\ntype SliceMachineManagerUpdateSliceMocksArgsReturnType = {\n\terrors: HookError[];\n};\n\ntype SlicesManagerUpsertHostedSliceScrenshotsArgs = {\n\tlibraryID: string;\n\tmodel: CustomTypes.Widgets.Slices.SharedSlice;\n};\n\nexport class SlicesManager extends BaseManager {\n\tasync readSliceLibrary(\n\t\targs: SliceLibraryReadHookData,\n\t): Promise<SlicesManagerReadSliceLibraryReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\t// TODO: Should validation happen at the `callHook` level?\n\t\t// Including validation at the hook level would ensure\n\t\t// hook-based actions are validated.\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice-library:read\",\n\t\t\targs,\n\t\t);\n\t\tconst { data, errors } = decodeHookResult(\n\t\t\tt.type({\n\t\t\t\tid: t.string,\n\t\t\t\tsliceIDs: t.array(t.string),\n\t\t\t}),\n\t\t\thookResult,\n\t\t);\n\n\t\treturn {\n\t\t\tsliceIDs: data[0]?.sliceIDs ?? [],\n\t\t\terrors: errors,\n\t\t};\n\t}\n\n\tasync readAllSliceLibraries(): Promise<SlicesManagerReadAllSliceLibrariesReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\t\tconst libraryIDs = sliceMachineConfig.libraries || [];\n\n\t\tconst res: SlicesManagerReadAllSliceLibrariesReturnType = {\n\t\t\tlibraries: [],\n\t\t\terrors: [],\n\t\t};\n\n\t\tfor (const libraryID of libraryIDs) {\n\t\t\tconst { sliceIDs, errors } = await this.readSliceLibrary({\n\t\t\t\tlibraryID,\n\t\t\t});\n\t\t\tres.errors = [...res.errors, ...errors];\n\n\t\t\tres.libraries.push({\n\t\t\t\tlibraryID,\n\t\t\t\tsliceIDs,\n\t\t\t});\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tasync readAllSlicesForLibrary(\n\t\targs: SliceMachineManagerReadAllSlicesForLibraryArgs,\n\t): Promise<SliceMachineManagerReadAllSlicesForLibraryReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst res: SliceMachineManagerReadAllSlicesForLibraryReturnType = {\n\t\t\tmodels: [],\n\t\t\terrors: [],\n\t\t};\n\n\t\tconst { sliceIDs, errors } = await this.readSliceLibrary({\n\t\t\tlibraryID: args.libraryID,\n\t\t});\n\t\tres.errors.push(...errors);\n\n\t\tif (sliceIDs) {\n\t\t\tfor (const sliceID of sliceIDs) {\n\t\t\t\tconst { model, errors } = await this.readSlice({\n\t\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\t\tsliceID,\n\t\t\t\t});\n\t\t\t\tres.errors.push(...errors);\n\n\t\t\t\tif (model) {\n\t\t\t\t\tres.models.push({ model });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tasync readAllSlices(): Promise<SliceMachineManagerReadAllSlicesReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\t\tconst libraryIDs = sliceMachineConfig.libraries || [];\n\n\t\tconst res: SliceMachineManagerReadAllSlicesReturnType = {\n\t\t\tmodels: [],\n\t\t\terrors: [],\n\t\t};\n\n\t\tfor (const libraryID of libraryIDs) {\n\t\t\tconst { models, errors } = await this.readAllSlicesForLibrary({\n\t\t\t\tlibraryID,\n\t\t\t});\n\t\t\tres.errors.push(...errors);\n\n\t\t\tfor (const model of models) {\n\t\t\t\tres.models.push({\n\t\t\t\t\tlibraryID,\n\t\t\t\t\tmodel: model.model,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tasync createSlice(\n\t\targs: SliceCreateHookData,\n\t): Promise<OnlyHookErrors<CallHookReturnType<SliceCreateHook>>> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:create\",\n\t\t\targs,\n\t\t);\n\n\t\treturn {\n\t\t\terrors: hookResult.errors,\n\t\t};\n\t}\n\n\tasync readSlice(\n\t\targs: SliceReadHookData,\n\t): Promise<SliceMachineManagerReadSliceReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:read\",\n\t\t\targs,\n\t\t);\n\t\tconst { data, errors } = decodeHookResult(\n\t\t\tt.type({\n\t\t\t\tmodel: CustomTypes.Widgets.Slices.SharedSlice,\n\t\t\t}),\n\t\t\thookResult,\n\t\t);\n\n\t\treturn {\n\t\t\tmodel: data[0]?.model,\n\t\t\terrors,\n\t\t};\n\t}\n\n\tasync updateSlice(\n\t\targs: SliceUpdateHookData,\n\t): Promise<OnlyHookErrors<CallHookReturnType<SliceUpdateHook>>> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:update\",\n\t\t\targs,\n\t\t);\n\n\t\treturn {\n\t\t\terrors: hookResult.errors,\n\t\t};\n\t}\n\n\tasync renameSlice(\n\t\targs: SliceRenameHookData,\n\t): Promise<OnlyHookErrors<CallHookReturnType<SliceRenameHook>>> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:rename\",\n\t\t\targs,\n\t\t);\n\n\t\treturn {\n\t\t\terrors: hookResult.errors,\n\t\t};\n\t}\n\n\t// TODO: Disallow until Slices can be deleted.\n\tasync deleteSlice(\n\t\targs: SliceDeleteHookData,\n\t): Promise<OnlyHookErrors<CallHookReturnType<SliceDeleteHook>>> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:delete\",\n\t\t\targs,\n\t\t);\n\n\t\treturn {\n\t\t\terrors: hookResult.errors,\n\t\t};\n\t}\n\n\t/**\n\t * @returns Record of variation IDs mapped to uploaded screenshot URLs.\n\t */\n\tasync pushSlice(\n\t\targs: SliceMachineManagerPushSliceArgs,\n\t): Promise<SliceMachineManagerPushSliceReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tif (!(await this.user.checkIsLoggedIn())) {\n\t\t\tthrow new UnauthenticatedError();\n\t\t}\n\n\t\tconst { model, errors: readSliceErrors } = await this.readSlice({\n\t\t\tlibraryID: args.libraryID,\n\t\t\tsliceID: args.sliceID,\n\t\t});\n\n\t\tif (model) {\n\t\t\tconst modelWithScreenshots =\n\t\t\t\tawait this.updateSliceModelScreenshotsInPlace({\n\t\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\t\tmodel,\n\t\t\t\t});\n\n\t\t\tconst { errors: updateSliceErrors } = await this.updateSlice({\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tmodel: modelWithScreenshots,\n\t\t\t});\n\n\t\t\tconst authenticationToken = await this.user.getAuthenticationToken();\n\t\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\t\t// TODO: Create a single shared client.\n\t\t\tconst client = prismicCustomTypesClient.createClient({\n\t\t\t\tendpoint: API_ENDPOINTS.PrismicModels,\n\t\t\t\trepositoryName: sliceMachineConfig.repositoryName,\n\t\t\t\ttoken: authenticationToken,\n\t\t\t\tfetch,\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\t// Check if Slice already exists on the repository.\n\t\t\t\tawait client.getSharedSliceByID(args.sliceID);\n\n\t\t\t\t// If it exists on the repository, update it.\n\t\t\t\tawait client.updateSharedSlice(modelWithScreenshots);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof prismicCustomTypesClient.NotFoundError) {\n\t\t\t\t\t// If the Slice doesn't exist on the repository, insert it.\n\t\t\t\t\tawait client.insertSharedSlice(modelWithScreenshots);\n\t\t\t\t} else if (error instanceof prismicCustomTypesClient.ForbiddenError) {\n\t\t\t\t\tthrow new UnauthorizedError(\n\t\t\t\t\t\t\"You do not have access to push Slices to this Prismic repository.\",\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Pass the error through if it isn't the one we were expecting.\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst screenshotURLs: Record<string, string> = {};\n\t\t\tfor (const variation of modelWithScreenshots.variations) {\n\t\t\t\tscreenshotURLs[variation.id] = variation.imageUrl;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tscreenshotURLs,\n\t\t\t\terrors: [...readSliceErrors, ...updateSliceErrors],\n\t\t\t};\n\t\t} else {\n\t\t\treturn {\n\t\t\t\tscreenshotURLs: undefined,\n\t\t\t\terrors: readSliceErrors,\n\t\t\t};\n\t\t}\n\t}\n\n\tasync readSliceScreenshot(\n\t\targs: SliceMachineManagerReadSliceScreenshotArgs,\n\t): Promise<SliceMachineManagerReadSliceScreenshotReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:asset:read\",\n\t\t\t{\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tsliceID: args.sliceID,\n\t\t\t\tassetID: `screenshot-${args.variationID}.png`,\n\t\t\t},\n\t\t);\n\t\tconst { data, errors } = decodeHookResult(\n\t\t\tt.type({\n\t\t\t\tdata: bufferCodec,\n\t\t\t}),\n\t\t\thookResult,\n\t\t);\n\n\t\treturn {\n\t\t\tdata: data[0]?.data,\n\t\t\terrors: errors,\n\t\t};\n\t}\n\n\tasync updateSliceScreenshot(\n\t\targs: SliceMachineManagerUpdateSliceScreenshotArgs,\n\t): Promise<OnlyHookErrors<CallHookReturnType<SliceAssetUpdateHook>>> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:asset:update\",\n\t\t\t{\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tsliceID: args.sliceID,\n\t\t\t\tasset: {\n\t\t\t\t\tid: `screenshot-${args.variationID}.png`,\n\t\t\t\t\tdata: args.data,\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\n\t\treturn {\n\t\t\terrors: hookResult.errors,\n\t\t};\n\t}\n\n\tasync readSliceMocks(\n\t\targs: SliceMachineManagerReadSliceMocksArgs,\n\t): Promise<SliceMachineManagerReadSliceMocksReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:asset:read\",\n\t\t\t{\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tsliceID: args.sliceID,\n\t\t\t\tassetID: `mocks.json`,\n\t\t\t},\n\t\t);\n\t\tconst { data, errors } = decodeHookResult(\n\t\t\tt.type({\n\t\t\t\tdata: t.array(SharedSliceContent),\n\t\t\t}),\n\t\t\t{\n\t\t\t\t...hookResult,\n\t\t\t\t// Convert the asset data from a Buffer to JSON\n\t\t\t\t// to prepare it for validation.\n\t\t\t\tdata: hookResult.data.map((result) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...result,\n\t\t\t\t\t\t\tdata: JSON.parse(result.data.toString()),\n\t\t\t\t\t\t};\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tif (data) {\n\t\t\treturn {\n\t\t\t\tmocks: data[0]?.data,\n\t\t\t\terrors,\n\t\t\t};\n\t\t} else {\n\t\t\treturn {\n\t\t\t\tmocks: [],\n\t\t\t\terrors,\n\t\t\t};\n\t\t}\n\t}\n\n\tasync updateSliceMocks(\n\t\targs: SliceMachineManagerUpdateSliceMocksArgs,\n\t): Promise<SliceMachineManagerUpdateSliceMocksArgsReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:asset:update\",\n\t\t\t{\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tsliceID: args.sliceID,\n\t\t\t\tasset: {\n\t\t\t\t\tid: \"mocks.json\",\n\t\t\t\t\tdata: Buffer.from(JSON.stringify(args.mocks, null, \"\\t\")),\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\n\t\treturn {\n\t\t\terrors: hookResult.errors,\n\t\t};\n\t}\n\n\t// TODO: Remove\n\tasync readSliceMocksConfig(\n\t\targs: SliceMachineManagerReadSliceMocksConfigArgs,\n\t): Promise<SliceMachineManagerReadSliceMocksConfigArgsReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:asset:read\",\n\t\t\t{\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tsliceID: args.sliceID,\n\t\t\t\tassetID: \"mocks.config.json\",\n\t\t\t},\n\t\t);\n\t\tconst data = hookResult.data[0]?.data;\n\n\t\t// TODO: Validate the returned data.\n\n\t\tif (data) {\n\t\t\treturn {\n\t\t\t\tmocksConfig: JSON.parse(data.toString()),\n\t\t\t\terrors: hookResult.errors,\n\t\t\t};\n\t\t} else {\n\t\t\treturn {\n\t\t\t\tmocksConfig: undefined,\n\t\t\t\terrors: hookResult.errors,\n\t\t\t};\n\t\t}\n\t}\n\n\tasync fetchRemoteSlices(): Promise<CustomTypes.Widgets.Slices.SharedSlice[]> {\n\t\tconst authenticationToken = await this.user.getAuthenticationToken();\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\tconst client = prismicCustomTypesClient.createClient({\n\t\t\tendpoint: API_ENDPOINTS.PrismicModels,\n\t\t\trepositoryName: sliceMachineConfig.repositoryName,\n\t\t\ttoken: authenticationToken,\n\t\t\tfetch,\n\t\t});\n\n\t\treturn await client.getAllSharedSlices();\n\t}\n\n\tasync updateSliceModelScreenshotsInPlace(\n\t\targs: SlicesManagerUpsertHostedSliceScrenshotsArgs,\n\t): Promise<CustomTypes.Widgets.Slices.SharedSlice> {\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\tconst variations = await Promise.all(\n\t\t\targs.model.variations.map(async (variation) => {\n\t\t\t\tconst screenshot = await this.readSliceScreenshot({\n\t\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\t\tsliceID: args.model.id,\n\t\t\t\t\tvariationID: variation.id,\n\t\t\t\t});\n\n\t\t\t\t// If there's no screenshot, delete it by replacing it with the default screenshot\n\t\t\t\tif (!screenshot.data) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...variation,\n\t\t\t\t\t\timageUrl: DEFAULT_SLICE_SCREENSHOT_URL,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst hasScreenshotChanged = !variation.imageUrl?.includes(\n\t\t\t\t\tcreateContentDigest(screenshot.data),\n\t\t\t\t);\n\n\t\t\t\t// If screenshot hasn't changed, do nothing\n\t\t\t\tif (!hasScreenshotChanged) {\n\t\t\t\t\treturn variation;\n\t\t\t\t}\n\n\t\t\t\tconst keyPrefix = [\n\t\t\t\t\tsliceMachineConfig.repositoryName,\n\t\t\t\t\t\"shared-slices\",\n\t\t\t\t\targs.model.id,\n\t\t\t\t\tvariation.id,\n\t\t\t\t].join(\"/\");\n\n\t\t\t\tconst uploadedScreenshot = await this.screenshots.uploadScreenshot({\n\t\t\t\t\tdata: screenshot.data,\n\t\t\t\t\tkeyPrefix,\n\t\t\t\t});\n\n\t\t\t\treturn {\n\t\t\t\t\t...variation,\n\t\t\t\t\timageUrl: uploadedScreenshot.url,\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\n\t\treturn {\n\t\t\t...args.model,\n\t\t\tvariations,\n\t\t};\n\t}\n}\n"],"names":["BaseManager","assertPluginsInitialized","errors","decodeHookResult","t","CustomTypes","UnauthenticatedError","prismicCustomTypesClient","API_ENDPOINTS","fetch","UnauthorizedError","bufferCodec","SharedSliceContent","DEFAULT_SLICE_SCREENSHOT_URL","createContentDigest"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SlicesManager.cjs","sources":["../../../../src/managers/slices/SlicesManager.ts"],"sourcesContent":["import * as t from \"io-ts\";\nimport fetch from \"node-fetch\";\nimport * as prismicCustomTypesClient from \"@prismicio/custom-types-client\";\nimport { CustomTypes } from \"@prismicio/types-internal\";\nimport { SharedSliceContent } from \"@prismicio/types-internal/lib/content\";\nimport {\n\tCallHookReturnType,\n\tHookError,\n\tSliceAssetUpdateHook,\n\tSliceCreateHook,\n\tSliceCreateHookData,\n\tSliceLibraryReadHookData,\n\tSliceReadHookData,\n\tSliceRenameHook,\n\tSliceRenameHookData,\n\tSliceUpdateHook,\n\tSliceUpdateHookData,\n} from \"@slicemachine/plugin-kit\";\n\nimport { DecodeError } from \"../../lib/DecodeError\";\nimport { assertPluginsInitialized } from \"../../lib/assertPluginsInitialized\";\nimport { bufferCodec } from \"../../lib/bufferCodec\";\nimport { decodeHookResult } from \"../../lib/decodeHookResult\";\n\nimport { OnlyHookErrors } from \"../../types\";\nimport { DEFAULT_SLICE_SCREENSHOT_URL } from \"../../constants/DEFAULT_SLICE_SCREENSHOT_URL\";\nimport { API_ENDPOINTS } from \"../../constants/API_ENDPOINTS\";\nimport { UnauthenticatedError, UnauthorizedError } from \"../../errors\";\n\nimport { BaseManager } from \"../BaseManager\";\nimport { createContentDigest } from \"../../lib/createContentDigest\";\n\ntype SlicesManagerReadSliceLibraryReturnType = {\n\tsliceIDs: string[];\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SlicesManagerReadAllSliceLibrariesReturnType = {\n\tlibraries: {\n\t\tlibraryID: string;\n\t\tsliceIDs: string[] | undefined;\n\t}[];\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerReadAllSlicesForLibraryArgs = {\n\tlibraryID: string;\n};\n\ntype SliceMachineManagerReadAllSlicesForLibraryReturnType = {\n\tmodels: { model: CustomTypes.Widgets.Slices.SharedSlice }[];\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerReadAllSlicesReturnType = {\n\tmodels: {\n\t\tlibraryID: string;\n\t\tmodel: CustomTypes.Widgets.Slices.SharedSlice;\n\t}[];\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerReadSliceReturnType = {\n\tmodel: CustomTypes.Widgets.Slices.SharedSlice | undefined;\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerPushSliceArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n};\n\nexport type SliceMachineManagerPushSliceReturnType = {\n\t/**\n\t * A record of Slice variation IDs mapped to uploaded screenshot URLs.\n\t */\n\tscreenshotURLs: Record<string, string> | undefined;\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerReadSliceScreenshotArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n\tvariationID: string;\n};\n\ntype SliceMachineManagerReadSliceScreenshotReturnType = {\n\tdata: Buffer | undefined;\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerUpdateSliceScreenshotArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n\tvariationID: string;\n\tdata: Buffer;\n};\n\ntype SliceMachineManagerReadSliceMocksArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n};\n\ntype SliceMachineManagerReadSliceMocksReturnType = {\n\tmocks?: SharedSliceContent[];\n\terrors: (DecodeError | HookError)[];\n};\n\ntype SliceMachineManagerReadSliceMocksConfigArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n};\n\ntype SliceMachineManagerReadSliceMocksConfigArgsReturnType = {\n\t// TODO\n\tmocksConfig?: Record<string, unknown>;\n\terrors: HookError[];\n};\n\ntype SliceMachineManagerUpdateSliceMocksArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n\tmocks: SharedSliceContent[];\n};\n\ntype SliceMachineManagerUpdateSliceMocksArgsReturnType = {\n\terrors: HookError[];\n};\n\ntype SlicesManagerUpsertHostedSliceScrenshotsArgs = {\n\tlibraryID: string;\n\tmodel: CustomTypes.Widgets.Slices.SharedSlice;\n};\n\ntype SliceMachineManagerDeleteSliceArgs = {\n\tlibraryID: string;\n\tsliceID: string;\n};\n\ntype SliceMachineManagerDeleteSliceReturnType = {\n\terrors: (DecodeError | HookError)[];\n};\n\nexport class SlicesManager extends BaseManager {\n\tasync readSliceLibrary(\n\t\targs: SliceLibraryReadHookData,\n\t): Promise<SlicesManagerReadSliceLibraryReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\t// TODO: Should validation happen at the `callHook` level?\n\t\t// Including validation at the hook level would ensure\n\t\t// hook-based actions are validated.\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice-library:read\",\n\t\t\targs,\n\t\t);\n\t\tconst { data, errors } = decodeHookResult(\n\t\t\tt.type({\n\t\t\t\tid: t.string,\n\t\t\t\tsliceIDs: t.array(t.string),\n\t\t\t}),\n\t\t\thookResult,\n\t\t);\n\n\t\treturn {\n\t\t\tsliceIDs: data[0]?.sliceIDs ?? [],\n\t\t\terrors: errors,\n\t\t};\n\t}\n\n\tasync readAllSliceLibraries(): Promise<SlicesManagerReadAllSliceLibrariesReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\t\tconst libraryIDs = sliceMachineConfig.libraries || [];\n\n\t\tconst res: SlicesManagerReadAllSliceLibrariesReturnType = {\n\t\t\tlibraries: [],\n\t\t\terrors: [],\n\t\t};\n\n\t\tfor (const libraryID of libraryIDs) {\n\t\t\tconst { sliceIDs, errors } = await this.readSliceLibrary({\n\t\t\t\tlibraryID,\n\t\t\t});\n\t\t\tres.errors = [...res.errors, ...errors];\n\n\t\t\tres.libraries.push({\n\t\t\t\tlibraryID,\n\t\t\t\tsliceIDs,\n\t\t\t});\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tasync readAllSlicesForLibrary(\n\t\targs: SliceMachineManagerReadAllSlicesForLibraryArgs,\n\t): Promise<SliceMachineManagerReadAllSlicesForLibraryReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst res: SliceMachineManagerReadAllSlicesForLibraryReturnType = {\n\t\t\tmodels: [],\n\t\t\terrors: [],\n\t\t};\n\n\t\tconst { sliceIDs, errors } = await this.readSliceLibrary({\n\t\t\tlibraryID: args.libraryID,\n\t\t});\n\t\tres.errors.push(...errors);\n\n\t\tif (sliceIDs) {\n\t\t\tfor (const sliceID of sliceIDs) {\n\t\t\t\tconst { model, errors } = await this.readSlice({\n\t\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\t\tsliceID,\n\t\t\t\t});\n\t\t\t\tres.errors.push(...errors);\n\n\t\t\t\tif (model) {\n\t\t\t\t\tres.models.push({ model });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tasync readAllSlices(): Promise<SliceMachineManagerReadAllSlicesReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\t\tconst libraryIDs = sliceMachineConfig.libraries || [];\n\n\t\tconst res: SliceMachineManagerReadAllSlicesReturnType = {\n\t\t\tmodels: [],\n\t\t\terrors: [],\n\t\t};\n\n\t\tfor (const libraryID of libraryIDs) {\n\t\t\tconst { models, errors } = await this.readAllSlicesForLibrary({\n\t\t\t\tlibraryID,\n\t\t\t});\n\t\t\tres.errors.push(...errors);\n\n\t\t\tfor (const model of models) {\n\t\t\t\tres.models.push({\n\t\t\t\t\tlibraryID,\n\t\t\t\t\tmodel: model.model,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tasync createSlice(\n\t\targs: SliceCreateHookData,\n\t): Promise<OnlyHookErrors<CallHookReturnType<SliceCreateHook>>> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:create\",\n\t\t\targs,\n\t\t);\n\n\t\treturn {\n\t\t\terrors: hookResult.errors,\n\t\t};\n\t}\n\n\tasync readSlice(\n\t\targs: SliceReadHookData,\n\t): Promise<SliceMachineManagerReadSliceReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:read\",\n\t\t\targs,\n\t\t);\n\t\tconst { data, errors } = decodeHookResult(\n\t\t\tt.type({\n\t\t\t\tmodel: CustomTypes.Widgets.Slices.SharedSlice,\n\t\t\t}),\n\t\t\thookResult,\n\t\t);\n\n\t\treturn {\n\t\t\tmodel: data[0]?.model,\n\t\t\terrors,\n\t\t};\n\t}\n\n\tasync updateSlice(\n\t\targs: SliceUpdateHookData,\n\t): Promise<OnlyHookErrors<CallHookReturnType<SliceUpdateHook>>> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:update\",\n\t\t\targs,\n\t\t);\n\n\t\treturn {\n\t\t\terrors: hookResult.errors,\n\t\t};\n\t}\n\n\tasync renameSlice(\n\t\targs: SliceRenameHookData,\n\t): Promise<OnlyHookErrors<CallHookReturnType<SliceRenameHook>>> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:rename\",\n\t\t\targs,\n\t\t);\n\n\t\treturn {\n\t\t\terrors: hookResult.errors,\n\t\t};\n\t}\n\n\tasync deleteSlice(\n\t\targs: SliceMachineManagerDeleteSliceArgs,\n\t): Promise<SliceMachineManagerDeleteSliceReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst { model, errors: readSliceErrors } = await this.readSlice({\n\t\t\tlibraryID: args.libraryID,\n\t\t\tsliceID: args.sliceID,\n\t\t});\n\n\t\tif (model) {\n\t\t\tconst { errors: deleteSliceErrors } =\n\t\t\t\tawait this.sliceMachinePluginRunner.callHook(\"slice:delete\", {\n\t\t\t\t\tmodel,\n\t\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\t});\n\n\t\t\t// Do not update custom types if slice deletion failed\n\t\t\tif (deleteSliceErrors.length > 0) {\n\t\t\t\treturn {\n\t\t\t\t\terrors: deleteSliceErrors,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst { errors: updateCustomTypeErrors } =\n\t\t\t\tawait this._removeSliceFromCustomTypes(args.sliceID);\n\n\t\t\treturn {\n\t\t\t\terrors: updateCustomTypeErrors,\n\t\t\t};\n\t\t} else {\n\t\t\treturn {\n\t\t\t\terrors: readSliceErrors,\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * @returns Record of variation IDs mapped to uploaded screenshot URLs.\n\t */\n\tasync pushSlice(\n\t\targs: SliceMachineManagerPushSliceArgs,\n\t): Promise<SliceMachineManagerPushSliceReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tif (!(await this.user.checkIsLoggedIn())) {\n\t\t\tthrow new UnauthenticatedError();\n\t\t}\n\n\t\tconst { model, errors: readSliceErrors } = await this.readSlice({\n\t\t\tlibraryID: args.libraryID,\n\t\t\tsliceID: args.sliceID,\n\t\t});\n\n\t\tif (model) {\n\t\t\tconst modelWithScreenshots =\n\t\t\t\tawait this.updateSliceModelScreenshotsInPlace({\n\t\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\t\tmodel,\n\t\t\t\t});\n\n\t\t\tconst { errors: updateSliceErrors } = await this.updateSlice({\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tmodel: modelWithScreenshots,\n\t\t\t});\n\n\t\t\tconst authenticationToken = await this.user.getAuthenticationToken();\n\t\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\t\t// TODO: Create a single shared client.\n\t\t\tconst client = prismicCustomTypesClient.createClient({\n\t\t\t\tendpoint: API_ENDPOINTS.PrismicModels,\n\t\t\t\trepositoryName: sliceMachineConfig.repositoryName,\n\t\t\t\ttoken: authenticationToken,\n\t\t\t\tfetch,\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\t// Check if Slice already exists on the repository.\n\t\t\t\tawait client.getSharedSliceByID(args.sliceID);\n\n\t\t\t\t// If it exists on the repository, update it.\n\t\t\t\tawait client.updateSharedSlice(modelWithScreenshots);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof prismicCustomTypesClient.NotFoundError) {\n\t\t\t\t\t// If the Slice doesn't exist on the repository, insert it.\n\t\t\t\t\tawait client.insertSharedSlice(modelWithScreenshots);\n\t\t\t\t} else if (error instanceof prismicCustomTypesClient.ForbiddenError) {\n\t\t\t\t\tthrow new UnauthorizedError(\n\t\t\t\t\t\t\"You do not have access to push Slices to this Prismic repository.\",\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Pass the error through if it isn't the one we were expecting.\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst screenshotURLs: Record<string, string> = {};\n\t\t\tfor (const variation of modelWithScreenshots.variations) {\n\t\t\t\tscreenshotURLs[variation.id] = variation.imageUrl;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tscreenshotURLs,\n\t\t\t\terrors: [...readSliceErrors, ...updateSliceErrors],\n\t\t\t};\n\t\t} else {\n\t\t\treturn {\n\t\t\t\tscreenshotURLs: undefined,\n\t\t\t\terrors: readSliceErrors,\n\t\t\t};\n\t\t}\n\t}\n\n\tasync readSliceScreenshot(\n\t\targs: SliceMachineManagerReadSliceScreenshotArgs,\n\t): Promise<SliceMachineManagerReadSliceScreenshotReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:asset:read\",\n\t\t\t{\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tsliceID: args.sliceID,\n\t\t\t\tassetID: `screenshot-${args.variationID}.png`,\n\t\t\t},\n\t\t);\n\t\tconst { data, errors } = decodeHookResult(\n\t\t\tt.type({\n\t\t\t\tdata: bufferCodec,\n\t\t\t}),\n\t\t\thookResult,\n\t\t);\n\n\t\treturn {\n\t\t\tdata: data[0]?.data,\n\t\t\terrors: errors,\n\t\t};\n\t}\n\n\tasync updateSliceScreenshot(\n\t\targs: SliceMachineManagerUpdateSliceScreenshotArgs,\n\t): Promise<OnlyHookErrors<CallHookReturnType<SliceAssetUpdateHook>>> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:asset:update\",\n\t\t\t{\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tsliceID: args.sliceID,\n\t\t\t\tasset: {\n\t\t\t\t\tid: `screenshot-${args.variationID}.png`,\n\t\t\t\t\tdata: args.data,\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\n\t\treturn {\n\t\t\terrors: hookResult.errors,\n\t\t};\n\t}\n\n\tasync readSliceMocks(\n\t\targs: SliceMachineManagerReadSliceMocksArgs,\n\t): Promise<SliceMachineManagerReadSliceMocksReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:asset:read\",\n\t\t\t{\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tsliceID: args.sliceID,\n\t\t\t\tassetID: `mocks.json`,\n\t\t\t},\n\t\t);\n\t\tconst { data, errors } = decodeHookResult(\n\t\t\tt.type({\n\t\t\t\tdata: t.array(SharedSliceContent),\n\t\t\t}),\n\t\t\t{\n\t\t\t\t...hookResult,\n\t\t\t\t// Convert the asset data from a Buffer to JSON\n\t\t\t\t// to prepare it for validation.\n\t\t\t\tdata: hookResult.data.map((result) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...result,\n\t\t\t\t\t\t\tdata: JSON.parse(result.data.toString()),\n\t\t\t\t\t\t};\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tif (data) {\n\t\t\treturn {\n\t\t\t\tmocks: data[0]?.data,\n\t\t\t\terrors,\n\t\t\t};\n\t\t} else {\n\t\t\treturn {\n\t\t\t\tmocks: [],\n\t\t\t\terrors,\n\t\t\t};\n\t\t}\n\t}\n\n\tasync updateSliceMocks(\n\t\targs: SliceMachineManagerUpdateSliceMocksArgs,\n\t): Promise<SliceMachineManagerUpdateSliceMocksArgsReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:asset:update\",\n\t\t\t{\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tsliceID: args.sliceID,\n\t\t\t\tasset: {\n\t\t\t\t\tid: \"mocks.json\",\n\t\t\t\t\tdata: Buffer.from(JSON.stringify(args.mocks, null, \"\\t\")),\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\n\t\treturn {\n\t\t\terrors: hookResult.errors,\n\t\t};\n\t}\n\n\t// TODO: Remove\n\tasync readSliceMocksConfig(\n\t\targs: SliceMachineManagerReadSliceMocksConfigArgs,\n\t): Promise<SliceMachineManagerReadSliceMocksConfigArgsReturnType> {\n\t\tassertPluginsInitialized(this.sliceMachinePluginRunner);\n\n\t\tconst hookResult = await this.sliceMachinePluginRunner.callHook(\n\t\t\t\"slice:asset:read\",\n\t\t\t{\n\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\tsliceID: args.sliceID,\n\t\t\t\tassetID: \"mocks.config.json\",\n\t\t\t},\n\t\t);\n\t\tconst data = hookResult.data[0]?.data;\n\n\t\t// TODO: Validate the returned data.\n\n\t\tif (data) {\n\t\t\treturn {\n\t\t\t\tmocksConfig: JSON.parse(data.toString()),\n\t\t\t\terrors: hookResult.errors,\n\t\t\t};\n\t\t} else {\n\t\t\treturn {\n\t\t\t\tmocksConfig: undefined,\n\t\t\t\terrors: hookResult.errors,\n\t\t\t};\n\t\t}\n\t}\n\n\tasync fetchRemoteSlices(): Promise<CustomTypes.Widgets.Slices.SharedSlice[]> {\n\t\tconst authenticationToken = await this.user.getAuthenticationToken();\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\tconst client = prismicCustomTypesClient.createClient({\n\t\t\tendpoint: API_ENDPOINTS.PrismicModels,\n\t\t\trepositoryName: sliceMachineConfig.repositoryName,\n\t\t\ttoken: authenticationToken,\n\t\t\tfetch,\n\t\t});\n\n\t\treturn await client.getAllSharedSlices();\n\t}\n\n\tasync updateSliceModelScreenshotsInPlace(\n\t\targs: SlicesManagerUpsertHostedSliceScrenshotsArgs,\n\t): Promise<CustomTypes.Widgets.Slices.SharedSlice> {\n\t\tconst sliceMachineConfig = await this.project.getSliceMachineConfig();\n\n\t\tconst variations = await Promise.all(\n\t\t\targs.model.variations.map(async (variation) => {\n\t\t\t\tconst screenshot = await this.readSliceScreenshot({\n\t\t\t\t\tlibraryID: args.libraryID,\n\t\t\t\t\tsliceID: args.model.id,\n\t\t\t\t\tvariationID: variation.id,\n\t\t\t\t});\n\n\t\t\t\t// If there's no screenshot, delete it by replacing it with the default screenshot\n\t\t\t\tif (!screenshot.data) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...variation,\n\t\t\t\t\t\timageUrl: DEFAULT_SLICE_SCREENSHOT_URL,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst hasScreenshotChanged = !variation.imageUrl?.includes(\n\t\t\t\t\tcreateContentDigest(screenshot.data),\n\t\t\t\t);\n\n\t\t\t\t// If screenshot hasn't changed, do nothing\n\t\t\t\tif (!hasScreenshotChanged) {\n\t\t\t\t\treturn variation;\n\t\t\t\t}\n\n\t\t\t\tconst keyPrefix = [\n\t\t\t\t\tsliceMachineConfig.repositoryName,\n\t\t\t\t\t\"shared-slices\",\n\t\t\t\t\targs.model.id,\n\t\t\t\t\tvariation.id,\n\t\t\t\t].join(\"/\");\n\n\t\t\t\tconst uploadedScreenshot = await this.screenshots.uploadScreenshot({\n\t\t\t\t\tdata: screenshot.data,\n\t\t\t\t\tkeyPrefix,\n\t\t\t\t});\n\n\t\t\t\treturn {\n\t\t\t\t\t...variation,\n\t\t\t\t\timageUrl: uploadedScreenshot.url,\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\n\t\treturn {\n\t\t\t...args.model,\n\t\t\tvariations,\n\t\t};\n\t}\n\n\tprivate async _removeSliceFromCustomTypes(sliceID: string) {\n\t\tconst { models, errors: customTypeReadErrors } =\n\t\t\tawait this.customTypes.readAllCustomTypes();\n\n\t\t// Successfully update all custom types or throw\n\t\tawait Promise.all(\n\t\t\tmodels.map(async (customType) => {\n\t\t\t\tconst updatedJsonModel = Object.entries(customType.model.json).reduce(\n\t\t\t\t\t(tabAccumulator, [tabKey, tab]) => {\n\t\t\t\t\t\tconst updatedTabFields = Object.entries(tab).reduce(\n\t\t\t\t\t\t\t(fieldAccumulator, [fieldKey, field]) => {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\tfield.config === undefined ||\n\t\t\t\t\t\t\t\t\tfield.type !== \"Slices\" ||\n\t\t\t\t\t\t\t\t\tfield.config.choices === undefined\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\treturn { ...fieldAccumulator, [fieldKey]: field };\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst filteredChoices = Object.entries(\n\t\t\t\t\t\t\t\t\tfield.config.choices,\n\t\t\t\t\t\t\t\t).reduce((choiceAccumulator, [choiceKey, choice]) => {\n\t\t\t\t\t\t\t\t\tif (choiceKey === sliceID) {\n\t\t\t\t\t\t\t\t\t\treturn choiceAccumulator;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturn { ...choiceAccumulator, [choiceKey]: choice };\n\t\t\t\t\t\t\t\t}, {});\n\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t...fieldAccumulator,\n\t\t\t\t\t\t\t\t\t[fieldKey]: {\n\t\t\t\t\t\t\t\t\t\t...field,\n\t\t\t\t\t\t\t\t\t\tconfig: { ...field.config, choices: filteredChoices },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{},\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn { ...tabAccumulator, [tabKey]: updatedTabFields };\n\t\t\t\t\t},\n\t\t\t\t\t{},\n\t\t\t\t);\n\n\t\t\t\tawait this.customTypes.updateCustomType({\n\t\t\t\t\tmodel: { ...customType.model, json: updatedJsonModel },\n\t\t\t\t});\n\t\t\t}),\n\t\t);\n\n\t\treturn { errors: customTypeReadErrors };\n\t}\n}\n"],"names":["BaseManager","assertPluginsInitialized","errors","decodeHookResult","t","CustomTypes","UnauthenticatedError","prismicCustomTypesClient","API_ENDPOINTS","fetch","UnauthorizedError","bufferCodec","SharedSliceContent","DEFAULT_SLICE_SCREENSHOT_URL","createContentDigest"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { CustomTypes } from "@prismicio/types-internal";
|
|
3
3
|
import { SharedSliceContent } from "@prismicio/types-internal/lib/content";
|
|
4
|
-
import { CallHookReturnType, HookError, SliceAssetUpdateHook, SliceCreateHook, SliceCreateHookData,
|
|
4
|
+
import { CallHookReturnType, HookError, SliceAssetUpdateHook, SliceCreateHook, SliceCreateHookData, SliceLibraryReadHookData, SliceReadHookData, SliceRenameHook, SliceRenameHookData, SliceUpdateHook, SliceUpdateHookData } from "@slicemachine/plugin-kit";
|
|
5
5
|
import { DecodeError } from "../../lib/DecodeError";
|
|
6
6
|
import { OnlyHookErrors } from "../../types";
|
|
7
7
|
import { BaseManager } from "../BaseManager";
|
|
@@ -90,6 +90,13 @@ type SlicesManagerUpsertHostedSliceScrenshotsArgs = {
|
|
|
90
90
|
libraryID: string;
|
|
91
91
|
model: CustomTypes.Widgets.Slices.SharedSlice;
|
|
92
92
|
};
|
|
93
|
+
type SliceMachineManagerDeleteSliceArgs = {
|
|
94
|
+
libraryID: string;
|
|
95
|
+
sliceID: string;
|
|
96
|
+
};
|
|
97
|
+
type SliceMachineManagerDeleteSliceReturnType = {
|
|
98
|
+
errors: (DecodeError | HookError)[];
|
|
99
|
+
};
|
|
93
100
|
export declare class SlicesManager extends BaseManager {
|
|
94
101
|
readSliceLibrary(args: SliceLibraryReadHookData): Promise<SlicesManagerReadSliceLibraryReturnType>;
|
|
95
102
|
readAllSliceLibraries(): Promise<SlicesManagerReadAllSliceLibrariesReturnType>;
|
|
@@ -99,7 +106,7 @@ export declare class SlicesManager extends BaseManager {
|
|
|
99
106
|
readSlice(args: SliceReadHookData): Promise<SliceMachineManagerReadSliceReturnType>;
|
|
100
107
|
updateSlice(args: SliceUpdateHookData): Promise<OnlyHookErrors<CallHookReturnType<SliceUpdateHook>>>;
|
|
101
108
|
renameSlice(args: SliceRenameHookData): Promise<OnlyHookErrors<CallHookReturnType<SliceRenameHook>>>;
|
|
102
|
-
deleteSlice(args:
|
|
109
|
+
deleteSlice(args: SliceMachineManagerDeleteSliceArgs): Promise<SliceMachineManagerDeleteSliceReturnType>;
|
|
103
110
|
/**
|
|
104
111
|
* @returns Record of variation IDs mapped to uploaded screenshot URLs.
|
|
105
112
|
*/
|
|
@@ -111,5 +118,6 @@ export declare class SlicesManager extends BaseManager {
|
|
|
111
118
|
readSliceMocksConfig(args: SliceMachineManagerReadSliceMocksConfigArgs): Promise<SliceMachineManagerReadSliceMocksConfigArgsReturnType>;
|
|
112
119
|
fetchRemoteSlices(): Promise<CustomTypes.Widgets.Slices.SharedSlice[]>;
|
|
113
120
|
updateSliceModelScreenshotsInPlace(args: SlicesManagerUpsertHostedSliceScrenshotsArgs): Promise<CustomTypes.Widgets.Slices.SharedSlice>;
|
|
121
|
+
private _removeSliceFromCustomTypes;
|
|
114
122
|
}
|
|
115
123
|
export {};
|
|
@@ -124,13 +124,31 @@ class SlicesManager extends BaseManager {
|
|
|
124
124
|
errors: hookResult.errors
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
|
-
// TODO: Disallow until Slices can be deleted.
|
|
128
127
|
async deleteSlice(args) {
|
|
129
128
|
assertPluginsInitialized(this.sliceMachinePluginRunner);
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
};
|
|
129
|
+
const { model, errors: readSliceErrors } = await this.readSlice({
|
|
130
|
+
libraryID: args.libraryID,
|
|
131
|
+
sliceID: args.sliceID
|
|
132
|
+
});
|
|
133
|
+
if (model) {
|
|
134
|
+
const { errors: deleteSliceErrors } = await this.sliceMachinePluginRunner.callHook("slice:delete", {
|
|
135
|
+
model,
|
|
136
|
+
libraryID: args.libraryID
|
|
137
|
+
});
|
|
138
|
+
if (deleteSliceErrors.length > 0) {
|
|
139
|
+
return {
|
|
140
|
+
errors: deleteSliceErrors
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const { errors: updateCustomTypeErrors } = await this._removeSliceFromCustomTypes(args.sliceID);
|
|
144
|
+
return {
|
|
145
|
+
errors: updateCustomTypeErrors
|
|
146
|
+
};
|
|
147
|
+
} else {
|
|
148
|
+
return {
|
|
149
|
+
errors: readSliceErrors
|
|
150
|
+
};
|
|
151
|
+
}
|
|
134
152
|
}
|
|
135
153
|
/**
|
|
136
154
|
* @returns Record of variation IDs mapped to uploaded screenshot URLs.
|
|
@@ -341,6 +359,36 @@ class SlicesManager extends BaseManager {
|
|
|
341
359
|
variations
|
|
342
360
|
};
|
|
343
361
|
}
|
|
362
|
+
async _removeSliceFromCustomTypes(sliceID) {
|
|
363
|
+
const { models, errors: customTypeReadErrors } = await this.customTypes.readAllCustomTypes();
|
|
364
|
+
await Promise.all(models.map(async (customType) => {
|
|
365
|
+
const updatedJsonModel = Object.entries(customType.model.json).reduce((tabAccumulator, [tabKey, tab]) => {
|
|
366
|
+
const updatedTabFields = Object.entries(tab).reduce((fieldAccumulator, [fieldKey, field]) => {
|
|
367
|
+
if (field.config === void 0 || field.type !== "Slices" || field.config.choices === void 0) {
|
|
368
|
+
return { ...fieldAccumulator, [fieldKey]: field };
|
|
369
|
+
}
|
|
370
|
+
const filteredChoices = Object.entries(field.config.choices).reduce((choiceAccumulator, [choiceKey, choice]) => {
|
|
371
|
+
if (choiceKey === sliceID) {
|
|
372
|
+
return choiceAccumulator;
|
|
373
|
+
}
|
|
374
|
+
return { ...choiceAccumulator, [choiceKey]: choice };
|
|
375
|
+
}, {});
|
|
376
|
+
return {
|
|
377
|
+
...fieldAccumulator,
|
|
378
|
+
[fieldKey]: {
|
|
379
|
+
...field,
|
|
380
|
+
config: { ...field.config, choices: filteredChoices }
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
}, {});
|
|
384
|
+
return { ...tabAccumulator, [tabKey]: updatedTabFields };
|
|
385
|
+
}, {});
|
|
386
|
+
await this.customTypes.updateCustomType({
|
|
387
|
+
model: { ...customType.model, json: updatedJsonModel }
|
|
388
|
+
});
|
|
389
|
+
}));
|
|
390
|
+
return { errors: customTypeReadErrors };
|
|
391
|
+
}
|
|
344
392
|
}
|
|
345
393
|
export {
|
|
346
394
|
SlicesManager
|