Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/scratch-frame/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@raspberrypifoundation/scratch-frame",
"private": true,
"dependencies": {
"@RaspberryPiFoundation/scratch-gui": "13.7.3-code-classroom.20260522151700",
"@scratch/scratch-gui": "15.1.1",
"@vitejs/plugin-react": "^6.0.2",
"react": "18.3.1",
"react-dom": "18.3.1",
Expand Down
5 changes: 0 additions & 5 deletions apps/scratch-frame/src/ScratchEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ import { useCallback, useRef, useEffect, useState } from "react";
import WrapperdScratchGui from "./WrappedScratchGui.jsx";
import { postScratchGuiEvent, allowedParentOrigin } from "./utils/events.js";

/** Scratch library picker assets (not project save/load — those use editor-api). */
export const SCRATCH_LIBRARY_ASSET_URL_TEMPLATE =
"https://editor-assets.raspberrypi.org/internalapi/asset/{assetPath}/get/";

const handleUpdateProjectId = (updatedProjectId) => {
postScratchGuiEvent("scratch-gui-project-id-updated", {
projectId: updatedProjectId,
Expand Down Expand Up @@ -86,7 +82,6 @@ const ScratchEditor = ({
noBeforeUnloadHandler={true}
projectHost={`${apiUrl}/api/scratch/projects`}
assetHost={`${apiUrl}/api/scratch/assets`}
libraryAssetUrlTemplate={SCRATCH_LIBRARY_ASSET_URL_TEMPLATE}
basePath={`${import.meta.env.REACT_APP_SCRATCH_FRAME_URL}/scratch-gui/`}
onStorageInit={(storage) => {
scratchFetchApiRef.current = storage.scratchFetch;
Expand Down
5 changes: 1 addition & 4 deletions apps/scratch-frame/src/ScratchEditor.test.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React from "react";
import { render, cleanup, act } from "@testing-library/react";
import ScratchEditor, {
SCRATCH_LIBRARY_ASSET_URL_TEMPLATE,
} from "./ScratchEditor.jsx";
import ScratchEditor from "./ScratchEditor.jsx";

const { mockWrappedScratchGui, mockScratchProjectSave } = vi.hoisted(() => ({
mockWrappedScratchGui: vi.fn(),
Expand Down Expand Up @@ -43,7 +41,6 @@ describe("ScratchEditor", () => {
expect.objectContaining({
assetHost: "https://api.example.com/api/scratch/assets",
projectHost: "https://api.example.com/api/scratch/projects",
libraryAssetUrlTemplate: SCRATCH_LIBRARY_ASSET_URL_TEMPLATE,
}),
);
});
Expand Down
3 changes: 3 additions & 0 deletions apps/scratch-frame/src/WrappedScratchGui.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, { useState } from "react";
import PropTypes from "prop-types";
import { Provider } from "react-redux";
import { combineReducers, createStore } from "redux";
import { buildLibraryAssetUrl } from "./utils/libraryAssetUrl.js";

const scratchGui = window.GUI;
const ScratchComponent = scratchGui.default;
Expand All @@ -11,6 +12,8 @@ const appTarget = document.getElementById("app");
scratchGui.setAppElement(appTarget);
const ScratchGuiWithIntegration = ScratchIntegrationHOC(ScratchComponent);

scratchGui.legacyConfig.storage.getLibraryAssetUrl = buildLibraryAssetUrl;

export const createScratchStore = (locale) =>
createStore(
combineReducers(scratchGui.guiReducers),
Expand Down
12 changes: 11 additions & 1 deletion apps/scratch-frame/src/WrappedScratchGui.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe("WrappedScratchGui", () => {
scratchGui: (state = {}) => state,
},
buildInitialState: vi.fn(() => ({ projectState: {} })),
legacyConfig: {},
legacyConfig: { storage: {} },
guiMiddleware: undefined,
};
});
Expand Down Expand Up @@ -70,4 +70,14 @@ describe("WrappedScratchGui", () => {
"es-419",
);
});

it("points Scratch's library thumbnails at our own asset host", async () => {
await import("./WrappedScratchGui.jsx");

expect(
window.GUI.legacyConfig.storage.getLibraryAssetUrl("abc123", "svg"),
).toBe(
"https://editor-assets.raspberrypi.org/internalapi/asset/abc123.svg/get/",
);
});
});
14 changes: 14 additions & 0 deletions apps/scratch-frame/src/utils/libraryAssetUrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const SCRATCH_LIBRARY_ASSET_HOST =
"https://editor-assets.raspberrypi.org";

/**
* Builds the URL a library thumbnail is fetched from, in the shape Scratch's
* asset service uses. Supplied to Scratch GUI as GUIStorage.getLibraryAssetUrl,
* which it calls when rendering sprite, costume and backdrop library items.
*
* @param {string} assetId - the md5 of the asset.
* @param {string} dataFormat - the asset's file extension.
* @returns {string} the URL to fetch the asset from.
*/
export const buildLibraryAssetUrl = (assetId, dataFormat) =>
`${SCRATCH_LIBRARY_ASSET_HOST}/internalapi/asset/${assetId}.${dataFormat}/get/`;
18 changes: 18 additions & 0 deletions apps/scratch-frame/src/utils/libraryAssetUrl.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {
SCRATCH_LIBRARY_ASSET_HOST,
buildLibraryAssetUrl,
} from "./libraryAssetUrl.js";

describe("buildLibraryAssetUrl", () => {
test("builds an asset service URL on our own host", () => {
expect(buildLibraryAssetUrl("abc123", "svg")).toBe(
`${SCRATCH_LIBRARY_ASSET_HOST}/internalapi/asset/abc123.svg/get/`,
);
});

test("does not fall back to the Scratch CDN", () => {
expect(buildLibraryAssetUrl("abc123", "png")).not.toContain(
"cdn.assets.scratch.mit.edu",
);
});
});
11 changes: 7 additions & 4 deletions apps/scratch-frame/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default defineConfig(({ mode }) => {
);
const cspAssetOrigin = toOrigin("ASSETS_URL", env.ASSETS_URL);

// Keep in sync with SCRATCH_LIBRARY_ASSET_URL_TEMPLATE in ScratchEditor.jsx
// Keep in sync with SCRATCH_LIBRARY_ASSET_HOST in utils/libraryAssetUrl.js
const cspScratchLibraryAssetOrigin = "https://editor-assets.raspberrypi.org";

// When present these override cspApiOrigin for CSP API/connect-src origins.
Expand Down Expand Up @@ -68,9 +68,7 @@ export default defineConfig(({ mode }) => {
const resolveFromApp = (request) =>
require.resolve(request, { paths: [__dirname] });

const scratchDistDir = path.dirname(
resolveFromApp("@RaspberryPiFoundation/scratch-gui"),
);
const scratchDistDir = path.dirname(resolveFromApp("@scratch/scratch-gui"));

const scratchStaticDir = path.resolve(scratchDistDir, "static");
const scratchChunkDir = path.resolve(scratchDistDir, "chunks");
Expand All @@ -97,6 +95,11 @@ export default defineConfig(({ mode }) => {
dest: "scratch-gui/static",
rename: { stripBase: 5 },
},
{
src: `${scratchChunkDir}/**/*`,
dest: "scratch-gui/chunks",
rename: { stripBase: 5 },
},
{
src: `${scratchChunkDir}/**/*`,
dest: "chunks",
Expand Down
Loading
Loading