diff --git a/localtypings/pxtarget.d.ts b/localtypings/pxtarget.d.ts index 6465b7110e3d..47301685cfdd 100644 --- a/localtypings/pxtarget.d.ts +++ b/localtypings/pxtarget.d.ts @@ -58,6 +58,8 @@ declare namespace pxt { upgrades?: string[]; // This repo's simulator extension configuration simx?: SimulatorExtensionConfig; + // if true, this repo will not be shown in extension search results + hidden?: boolean; } interface SimulatorExtensionConfig { diff --git a/pxtlib/github.ts b/pxtlib/github.ts index 706299bb0eaa..93812599b9c1 100644 --- a/pxtlib/github.ts +++ b/pxtlib/github.ts @@ -997,6 +997,21 @@ namespace pxt.github { : GitRepoStatus.Unknown; } + export function isRepoHidden(repo: ParsedRepo, config: pxt.PackagesConfig): boolean { + if (!repo || !config) return true; + + const repoFull = repo.fullName?.toLowerCase(); + const repoSlug = repo.slug?.toLowerCase(); + + const entry = config.approvedRepoLib[repoFull] || config.approvedRepoLib[repoSlug]; + + if (entry && entry.hidden) { + return true; + } + + return false; + } + function isOrgBanned(repo: ParsedRepo, config: pxt.PackagesConfig): boolean { if (!config) return false; // don't know if (!repo || !repo.owner) return true; @@ -1204,12 +1219,33 @@ namespace pxt.github { return null } - export function upgradedPackageReference(cfg: PackagesConfig, id: string) { + export async function upgradedPackageReferenceAsync(cfg: PackagesConfig, id: string) { const rules = upgradeRules(cfg, id) if (!rules) return null for (const upgr of rules) { + const mv = /^move:(.*)$/.exec(upgr); + if (mv) { + const new_repo = parseRepoId(mv[1]) + if (new_repo) { + if (!new_repo.tag) { + new_repo.tag = await latestVersionAsync(mv[1],cfg) + } + const repo = parseRepoId(id) + if (!new_repo.fileName && repo.fileName) { + new_repo.fileName = repo.fileName + new_repo.fullName = join(new_repo.owner, new_repo.project, new_repo.fileName) + } + const new_repo_s = stringifyRepo(new_repo) + pxt.debug(`upgrading ${id} to ${new_repo_s}}`) + const np: string = await upgradedPackageReferenceAsync(cfg, new_repo_s) + if (np) return np + else return new_repo_s + } else { + pxt.log(`cannot parse move target: ${mv[1]}`) + } + } const m = /^min:(.*)/.exec(upgr) const minV = m && pxt.semver.tryParse(m[1]); if (minV) { diff --git a/pxtlib/package.ts b/pxtlib/package.ts index f88f7321cfd7..3bf0b90d79f1 100644 --- a/pxtlib/package.ts +++ b/pxtlib/package.ts @@ -385,20 +385,25 @@ namespace pxt { if (!this.config) this.loadConfig(); return pxt.packagesConfigAsync() - .then(packagesConfig => { + .then(async packagesConfig => { let numfixes = 0 let fixes: pxt.Map = {}; + const promises: Promise[] = [] U.iterMap(this.config.dependencies, (pkg, ver) => { - if (pxt.github.isGithubId(ver)) { - const upgraded = pxt.github.upgradedPackageReference(packagesConfig, ver) - if (upgraded && upgraded != ver) { - pxt.log(`upgrading dep ${pkg}: ${ver} -> ${upgraded}`); - fixes[ver] = upgraded; - this.config.dependencies[pkg] = upgraded - numfixes++ + const doit = async () => { + if (pxt.github.isGithubId(ver)) { + const upgraded = await pxt.github.upgradedPackageReferenceAsync(packagesConfig, ver) + if (upgraded && upgraded != ver) { + pxt.log(`upgrading dep ${pkg}: ${ver} -> ${upgraded}`); + fixes[ver] = upgraded; + this.config.dependencies[pkg] = upgraded + numfixes++ + } } } + promises.push(doit()) }) + await Promise.all(promises) if (numfixes) this.saveConfig() return numfixes && fixes; @@ -654,7 +659,7 @@ namespace pxt { // if we are installing this script, we haven't yet downloaded the config // do upgrade later - if (this.level == 0 && !isInstall) { + if (!isInstall) { await this.upgradePackagesAsync(); } @@ -672,7 +677,7 @@ namespace pxt { // we are installing the script, and we've download the original version and we haven't upgraded it yet // do upgrade and reload as needed - if (this.level == 0 && isInstall) { + if (isInstall) { const fixes = await this.upgradePackagesAsync(); if (fixes) { @@ -680,6 +685,7 @@ namespace pxt { Object.keys(fixes).forEach(key => pxt.tickEvent("package.doubleload", { "extension": key })) pxt.log(`upgraded, downloading again`); pxt.debug(fixes); + // TODO: we should cache await this.downloadAsync(); } } diff --git a/pxtsim/simdriver.ts b/pxtsim/simdriver.ts index f031d987e368..371a57f771c9 100644 --- a/pxtsim/simdriver.ts +++ b/pxtsim/simdriver.ts @@ -160,10 +160,8 @@ namespace pxsim { simx.url = new URL(simx.index, simx.devUrl).toString(); } else { const simUrl = this.getSimUrl(); - // Ensure we preserve upload target path (/app/---simulator) - const simPath = simUrl.pathname.replace(/---?.*/, ""); // Construct the path. The "-" element delineates the extension key from the resource name. - const simxPath = [simPath, "simx", key, "-", simx.index].join("/"); + const simxPath = ["simx", key, "-", simx.index].join("/"); // Create the fully-qualified URL, preserving the origin by removing all leading slashes simx.url = new URL(simxPath.replace(/^\/+/, ""), simUrl.origin).toString(); } @@ -352,6 +350,9 @@ namespace pxsim { this.singleSimulator = true } + // BEGIN TEMPORARY: jacdac simulator + newJacdacSimulator: boolean = false; + // END TEMPORARY: jacdac simulator public postMessage(msg: pxsim.SimulatorMessage, source?: Window, frameID?: string) { if (this.hwdbg) { this.hwdbg.postMessage(msg) @@ -413,11 +414,14 @@ namespace pxsim { this.startFrame(messageFrame); frames = this.simFrames(); // refresh } - // should we start a simulator extension for this message? if (simulatorExtension) { // find a frame already running that simulator let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel); + // BEGIN TEMPORARY: jacdac simulator + if (messageChannel === "jacdac/pxt-jacdac") + this.newJacdacSimulator = true; + // END TEMPORARY: jacdac simulator // not found, spin a new one if (!messageFrame) { const url = new URL(simulatorExtension.url); @@ -438,11 +442,13 @@ namespace pxsim { let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel); // not found, spin a new one if (!messageFrame) { - const useLocalHost = U.isLocalHost() && /localhostmessagesims=1/i.test(window.location.href) - const url = ((useLocalHost && messageSimulator.localHostUrl) || messageSimulator.url) - .replace("$PARENT_ORIGIN$", encodeURIComponent(this.options.parentOrigin || "")) - .replace("$LANGUAGE$", encodeURIComponent(this.options.userLanguage)) - startSimulatorExtension(url, messageSimulator.permanent, messageSimulator.aspectRatio); + if (messageChannel !== "jacdac" || !this.newJacdacSimulator) { // TEMPORARY: jacdac simulator + const useLocalHost = U.isLocalHost() && /localhostmessagesims=1/i.test(window.location.href) + const url = ((useLocalHost && messageSimulator.localHostUrl) || messageSimulator.url) + .replace("$PARENT_ORIGIN$", encodeURIComponent(this.options.parentOrigin || "")) + .replace("$LANGUAGE$", encodeURIComponent(this.options.userLanguage)) + startSimulatorExtension(url, messageSimulator.permanent, messageSimulator.aspectRatio); + } } // not running the curren run, restart else if (messageFrame.dataset['runid'] != this.runId) { @@ -452,7 +458,12 @@ namespace pxsim { isDeferrableBroadcastMessage = true; // start secondary frame if needed const mkcdFrames = frames.filter(frame => !frame.dataset[FRAME_DATA_MESSAGE_CHANNEL]); - if (mkcdFrames.length == 0 || mkcdFrames.length == 1 && !this.singleSimulator) { + if (!messageChannel && + (mkcdFrames.length == 0 || mkcdFrames.length == 1 && !this.singleSimulator)) { + // messageChannel is set to false whenever msg.type !== "messagepacket" + // for example, in the case of msg.type === "radiopacket". However, in the case + // where we have msg.type === "messagepacket" and msg.channel is not matched by an + // extension, we don't want a second simulator to be created. this.container.appendChild(this.createFrame()); frames = this.simFrames(); // there might be an old frame diff --git a/webapp/src/app.tsx b/webapp/src/app.tsx index fa95e5439a09..763ca88d3366 100644 --- a/webapp/src/app.tsx +++ b/webapp/src/app.tsx @@ -5560,23 +5560,19 @@ function initPacketIO() { } }, (type, payload) => { - const messageSimulators = pxt.appTarget.simulator?.messageSimulators; - if (messageSimulators?.[type]) { - window.postMessage({ - type: "messagepacket", - broadcast: false, - channel: type, - data: payload, - sender: "packetio", - }, "*") - } + window.postMessage({ + type: "messagepacket", + broadcast: false, + channel: type, + data: payload, + sender: "packetio", + }, "*") }); window.addEventListener('message', (ev: MessageEvent) => { const msg = ev.data if (msg.type === 'messagepacket' && msg.sender !== "packetio" - && pxt.appTarget.simulator?.messageSimulators?.[msg.channel] && msg.channel === pxt.HF2.CUSTOM_EV_JACDAC) pxt.packetio.sendCustomEventAsync(msg.channel, msg.data) .then(() => { }, err => { diff --git a/webapp/src/extensionsBrowser.tsx b/webapp/src/extensionsBrowser.tsx index f1c1f459b2f4..0eb848711f58 100644 --- a/webapp/src/extensionsBrowser.tsx +++ b/webapp/src/extensionsBrowser.tsx @@ -78,7 +78,11 @@ export const ExtensionsBrowser = (props: ExtensionsProps) => { setSelectedTag("") setSearchComplete(false) setExtensionsToShow([emptyCard, emptyCard, emptyCard, emptyCard]) - const exts = await fetchGithubDataAsync([searchFor]) + + const config = await pxt.packagesConfigAsync(); + + let exts = await fetchGithubDataAsync([searchFor]) + exts = exts?.filter(e => !pxt.github.isRepoHidden(e, config)); const parsedExt = exts?.map(repo => parseGithubRepo(repo)) ?? []; //Search bundled extensions as well fetchBundled().forEach(e => {