pxt-core 11.2.2 → 11.2.4

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/built/cli.js CHANGED
@@ -2520,6 +2520,7 @@ function serveAsync(parsed) {
2520
2520
  browser: parsed.flags["browser"],
2521
2521
  serial: !parsed.flags["noSerial"] && !exports.globalConfig.noSerial,
2522
2522
  noauth: parsed.flags["noauth"] || false,
2523
+ backport: parsed.flags["backport"] || 0,
2523
2524
  }));
2524
2525
  }
2525
2526
  exports.serveAsync = serveAsync;
@@ -6237,6 +6238,11 @@ ${pxt.crowdin.KEY_VARIABLE} - crowdin key
6237
6238
  noauth: {
6238
6239
  description: "disable localtoken-based authentication",
6239
6240
  aliases: ["na"],
6241
+ },
6242
+ backport: {
6243
+ description: "port where the locally running backend is listening.",
6244
+ argument: "backport",
6245
+ type: "number",
6240
6246
  }
6241
6247
  }
6242
6248
  }, serveAsync);
package/built/pxt.js CHANGED
@@ -102515,7 +102515,7 @@ var pxt;
102515
102515
  var _a;
102516
102516
  try {
102517
102517
  return typeof window !== "undefined"
102518
- && /^http:\/\/(localhost|127\.0\.0\.1|192\.168\.\d+\.\d+):\d+\//.test(window.location.href)
102518
+ && /^http:\/\/(?:localhost|127\.0\.0\.1|192\.168\.\d{1,3}\.\d{1,3}|[a-zA-Z0-9.-]+\.local):\d+\/?/.test(window.location.href)
102519
102519
  && (ignoreFlags || !/nolocalhost=1/.test(window.location.href))
102520
102520
  && !((_a = pxt === null || pxt === void 0 ? void 0 : pxt.webConfig) === null || _a === void 0 ? void 0 : _a.isStatic);
102521
102521
  }
@@ -153917,11 +153917,13 @@ var pxsim;
153917
153917
  return isPxtElectron() || isIpcRenderer();
153918
153918
  }
153919
153919
  U.isElectron = isElectron;
153920
+ function testLocalhost(url) {
153921
+ return /^http:\/\/(?:localhost|127\.0\.0\.1|192\.168\.\d{1,3}\.\d{1,3}|[a-zA-Z0-9.-]+\.local):\d+\/?/.test(url) && !/nolocalhost=1/.test(url);
153922
+ }
153923
+ U.testLocalhost = testLocalhost;
153920
153924
  function isLocalHost() {
153921
153925
  try {
153922
- return typeof window !== "undefined"
153923
- && /^http:\/\/(localhost|127\.0\.0\.1):\d+\//.test(window.location.href)
153924
- && !/nolocalhost=1/.test(window.location.href);
153926
+ return typeof window !== "undefined" && testLocalhost(window.location.href);
153925
153927
  }
153926
153928
  catch (e) {
153927
153929
  return false;
@@ -155321,16 +155323,41 @@ var pxsim;
155321
155323
  this._allowedOrigins.push(options.parentOrigin);
155322
155324
  }
155323
155325
  this._allowedOrigins.push(this.getSimUrl().origin);
155324
- const messageSimulators = options === null || options === void 0 ? void 0 : options.messageSimulators;
155325
- if (messageSimulators) {
155326
- Object.keys(messageSimulators)
155327
- .map(channel => messageSimulators[channel])
155328
- .forEach(messageSimulator => {
155329
- this._allowedOrigins.push(new URL(messageSimulator.url).origin);
155330
- if (messageSimulator.localHostUrl)
155331
- this._allowedOrigins.push(new URL(messageSimulator.localHostUrl).origin);
155332
- });
155333
- }
155326
+ // Legacy support for message simulators
155327
+ const messageSimulators = (options === null || options === void 0 ? void 0 : options.messageSimulators) || {};
155328
+ Object.keys(messageSimulators)
155329
+ .map(channel => messageSimulators[channel])
155330
+ .forEach(messageSimulator => {
155331
+ this._allowedOrigins.push(new URL(messageSimulator.url).origin);
155332
+ if (messageSimulator.localHostUrl)
155333
+ this._allowedOrigins.push(new URL(messageSimulator.localHostUrl).origin);
155334
+ });
155335
+ // Preprocess simulator extensions
155336
+ const simXDevMode = pxsim.U.isLocalHost() && /[?&]simxdev(?:[=&#]|$)/i.test(window.location.href);
155337
+ Object.entries((options === null || options === void 0 ? void 0 : options.simulatorExtensions) || {}).forEach(([key, simx]) => {
155338
+ // Verify essential `simx` config was provided
155339
+ if (!simx ||
155340
+ !simx.index ||
155341
+ !simx.aspectRatio ||
155342
+ simx.permanent === undefined) {
155343
+ return;
155344
+ }
155345
+ // Compute the effective URL
155346
+ if (simXDevMode && simx.devUrl) {
155347
+ // Use the dev URL if the dev flag is set (and we're on localhost)
155348
+ simx.url = new URL(simx.index, simx.devUrl).toString();
155349
+ }
155350
+ else {
155351
+ const simUrl = this.getSimUrl();
155352
+ // Ensure we preserve upload target path (/app/<sha>---simulator)
155353
+ const simPath = simUrl.pathname.replace(/---?.*/, "");
155354
+ // Construct the path. The "-" element delineates the extension key from the resource name.
155355
+ const simxPath = [simPath, "simx", key, "-", simx.index].join("/");
155356
+ simx.url = new URL(simxPath, simUrl.origin).toString();
155357
+ }
155358
+ // Add the origin to the allowed origins
155359
+ this._allowedOrigins.push(new URL(simx.url).origin);
155360
+ });
155334
155361
  this._allowedOrigins = pxsim.U.unique(this._allowedOrigins, f => f);
155335
155362
  }
155336
155363
  isDebug() {
@@ -155537,8 +155564,41 @@ var pxsim;
155537
155564
  const messageSimulator = messageChannel &&
155538
155565
  this.options.messageSimulators &&
155539
155566
  this.options.messageSimulators[messageChannel];
155540
- // should we start an extension editor?
155541
- if (messageSimulator) {
155567
+ const simulatorExtension = messageChannel &&
155568
+ this.options.simulatorExtensions &&
155569
+ this.options.simulatorExtensions[messageChannel];
155570
+ const startSimulatorExtension = (url, permanent) => {
155571
+ let wrapper = this.createFrame(url);
155572
+ this.container.appendChild(wrapper);
155573
+ const messageFrame = wrapper.firstElementChild;
155574
+ messageFrame.dataset[FRAME_DATA_MESSAGE_CHANNEL] = messageChannel;
155575
+ pxsim.U.addClass(wrapper, "simmsg");
155576
+ pxsim.U.addClass(wrapper, "simmsg" + messageChannel);
155577
+ if (permanent)
155578
+ messageFrame.dataset[PERMANENT] = "true";
155579
+ this.startFrame(messageFrame);
155580
+ frames = this.simFrames(); // refresh
155581
+ };
155582
+ // should we start a simulator extension for this message?
155583
+ if (simulatorExtension) {
155584
+ // find a frame already running that simulator
155585
+ let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
155586
+ // not found, spin a new one
155587
+ if (!messageFrame) {
155588
+ const url = new URL(simulatorExtension.url);
155589
+ if (this.options.parentOrigin)
155590
+ url.searchParams.set("parentOrigin", encodeURIComponent(this.options.parentOrigin));
155591
+ if (this.options.userLanguage)
155592
+ url.searchParams.set("language", encodeURIComponent(this.options.userLanguage));
155593
+ startSimulatorExtension(url.toString(), simulatorExtension.permanent);
155594
+ }
155595
+ // not running the current run, restart
155596
+ else if (messageFrame.dataset['runid'] != this.runId) {
155597
+ this.startFrame(messageFrame);
155598
+ }
155599
+ }
155600
+ // (legacy: messageSimulator) should we start a message simulator for this message?
155601
+ else if (messageSimulator) {
155542
155602
  // find a frame already running that simulator
155543
155603
  let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
155544
155604
  // not found, spin a new one
@@ -155547,16 +155607,7 @@ var pxsim;
155547
155607
  const url = ((useLocalHost && messageSimulator.localHostUrl) || messageSimulator.url)
155548
155608
  .replace("$PARENT_ORIGIN$", encodeURIComponent(this.options.parentOrigin || ""))
155549
155609
  .replace("$LANGUAGE$", encodeURIComponent(this.options.userLanguage));
155550
- let wrapper = this.createFrame(url);
155551
- this.container.appendChild(wrapper);
155552
- messageFrame = wrapper.firstElementChild;
155553
- messageFrame.dataset[FRAME_DATA_MESSAGE_CHANNEL] = messageChannel;
155554
- pxsim.U.addClass(wrapper, "simmsg");
155555
- pxsim.U.addClass(wrapper, "simmsg" + messageChannel);
155556
- if (messageSimulator.permanent)
155557
- messageFrame.dataset[PERMANENT] = "true";
155558
- this.startFrame(messageFrame);
155559
- frames = this.simFrames(); // refresh
155610
+ startSimulatorExtension(url, messageSimulator.permanent);
155560
155611
  }
155561
155612
  // not running the curren run, restart
155562
155613
  else if (messageFrame.dataset['runid'] != this.runId) {
@@ -163164,6 +163215,7 @@ function serveAsync(parsed) {
163164
163215
  browser: parsed.flags["browser"],
163165
163216
  serial: !parsed.flags["noSerial"] && !exports.globalConfig.noSerial,
163166
163217
  noauth: parsed.flags["noauth"] || false,
163218
+ backport: parsed.flags["backport"] || 0,
163167
163219
  }));
163168
163220
  }
163169
163221
  exports.serveAsync = serveAsync;
@@ -166881,6 +166933,11 @@ ${pxt.crowdin.KEY_VARIABLE} - crowdin key
166881
166933
  noauth: {
166882
166934
  description: "disable localtoken-based authentication",
166883
166935
  aliases: ["na"],
166936
+ },
166937
+ backport: {
166938
+ description: "port where the locally running backend is listening.",
166939
+ argument: "backport",
166940
+ type: "number",
166884
166941
  }
166885
166942
  }
166886
166943
  }, serveAsync);
package/built/pxtlib.js CHANGED
@@ -4829,7 +4829,7 @@ var pxt;
4829
4829
  var _a;
4830
4830
  try {
4831
4831
  return typeof window !== "undefined"
4832
- && /^http:\/\/(localhost|127\.0\.0\.1|192\.168\.\d+\.\d+):\d+\//.test(window.location.href)
4832
+ && /^http:\/\/(?:localhost|127\.0\.0\.1|192\.168\.\d{1,3}\.\d{1,3}|[a-zA-Z0-9.-]+\.local):\d+\/?/.test(window.location.href)
4833
4833
  && (ignoreFlags || !/nolocalhost=1/.test(window.location.href))
4834
4834
  && !((_a = pxt === null || pxt === void 0 ? void 0 : pxt.webConfig) === null || _a === void 0 ? void 0 : _a.isStatic);
4835
4835
  }
package/built/pxtsim.d.ts CHANGED
@@ -1059,6 +1059,7 @@ declare namespace pxsim {
1059
1059
  function isPxtElectron(): boolean;
1060
1060
  function isIpcRenderer(): boolean;
1061
1061
  function isElectron(): boolean;
1062
+ function testLocalhost(url: string): boolean;
1062
1063
  function isLocalHost(): boolean;
1063
1064
  function isLocalHostDev(): boolean;
1064
1065
  function unique<T>(arr: T[], f: (t: T) => string): T[];
@@ -1308,6 +1309,13 @@ declare namespace pxsim {
1308
1309
  aspectRatio?: number;
1309
1310
  permanent?: boolean;
1310
1311
  }>;
1312
+ simulatorExtensions?: pxt.Map<{
1313
+ aspectRatio?: number;
1314
+ permanent?: boolean;
1315
+ index?: string;
1316
+ devUrl?: string;
1317
+ url?: string;
1318
+ }>;
1311
1319
  userLanguage?: string;
1312
1320
  }
1313
1321
  enum SimulatorState {
package/built/pxtsim.js CHANGED
@@ -4712,11 +4712,13 @@ var pxsim;
4712
4712
  return isPxtElectron() || isIpcRenderer();
4713
4713
  }
4714
4714
  U.isElectron = isElectron;
4715
+ function testLocalhost(url) {
4716
+ return /^http:\/\/(?:localhost|127\.0\.0\.1|192\.168\.\d{1,3}\.\d{1,3}|[a-zA-Z0-9.-]+\.local):\d+\/?/.test(url) && !/nolocalhost=1/.test(url);
4717
+ }
4718
+ U.testLocalhost = testLocalhost;
4715
4719
  function isLocalHost() {
4716
4720
  try {
4717
- return typeof window !== "undefined"
4718
- && /^http:\/\/(localhost|127\.0\.0\.1):\d+\//.test(window.location.href)
4719
- && !/nolocalhost=1/.test(window.location.href);
4721
+ return typeof window !== "undefined" && testLocalhost(window.location.href);
4720
4722
  }
4721
4723
  catch (e) {
4722
4724
  return false;
@@ -6116,16 +6118,41 @@ var pxsim;
6116
6118
  this._allowedOrigins.push(options.parentOrigin);
6117
6119
  }
6118
6120
  this._allowedOrigins.push(this.getSimUrl().origin);
6119
- const messageSimulators = options === null || options === void 0 ? void 0 : options.messageSimulators;
6120
- if (messageSimulators) {
6121
- Object.keys(messageSimulators)
6122
- .map(channel => messageSimulators[channel])
6123
- .forEach(messageSimulator => {
6124
- this._allowedOrigins.push(new URL(messageSimulator.url).origin);
6125
- if (messageSimulator.localHostUrl)
6126
- this._allowedOrigins.push(new URL(messageSimulator.localHostUrl).origin);
6127
- });
6128
- }
6121
+ // Legacy support for message simulators
6122
+ const messageSimulators = (options === null || options === void 0 ? void 0 : options.messageSimulators) || {};
6123
+ Object.keys(messageSimulators)
6124
+ .map(channel => messageSimulators[channel])
6125
+ .forEach(messageSimulator => {
6126
+ this._allowedOrigins.push(new URL(messageSimulator.url).origin);
6127
+ if (messageSimulator.localHostUrl)
6128
+ this._allowedOrigins.push(new URL(messageSimulator.localHostUrl).origin);
6129
+ });
6130
+ // Preprocess simulator extensions
6131
+ const simXDevMode = pxsim.U.isLocalHost() && /[?&]simxdev(?:[=&#]|$)/i.test(window.location.href);
6132
+ Object.entries((options === null || options === void 0 ? void 0 : options.simulatorExtensions) || {}).forEach(([key, simx]) => {
6133
+ // Verify essential `simx` config was provided
6134
+ if (!simx ||
6135
+ !simx.index ||
6136
+ !simx.aspectRatio ||
6137
+ simx.permanent === undefined) {
6138
+ return;
6139
+ }
6140
+ // Compute the effective URL
6141
+ if (simXDevMode && simx.devUrl) {
6142
+ // Use the dev URL if the dev flag is set (and we're on localhost)
6143
+ simx.url = new URL(simx.index, simx.devUrl).toString();
6144
+ }
6145
+ else {
6146
+ const simUrl = this.getSimUrl();
6147
+ // Ensure we preserve upload target path (/app/<sha>---simulator)
6148
+ const simPath = simUrl.pathname.replace(/---?.*/, "");
6149
+ // Construct the path. The "-" element delineates the extension key from the resource name.
6150
+ const simxPath = [simPath, "simx", key, "-", simx.index].join("/");
6151
+ simx.url = new URL(simxPath, simUrl.origin).toString();
6152
+ }
6153
+ // Add the origin to the allowed origins
6154
+ this._allowedOrigins.push(new URL(simx.url).origin);
6155
+ });
6129
6156
  this._allowedOrigins = pxsim.U.unique(this._allowedOrigins, f => f);
6130
6157
  }
6131
6158
  isDebug() {
@@ -6332,8 +6359,41 @@ var pxsim;
6332
6359
  const messageSimulator = messageChannel &&
6333
6360
  this.options.messageSimulators &&
6334
6361
  this.options.messageSimulators[messageChannel];
6335
- // should we start an extension editor?
6336
- if (messageSimulator) {
6362
+ const simulatorExtension = messageChannel &&
6363
+ this.options.simulatorExtensions &&
6364
+ this.options.simulatorExtensions[messageChannel];
6365
+ const startSimulatorExtension = (url, permanent) => {
6366
+ let wrapper = this.createFrame(url);
6367
+ this.container.appendChild(wrapper);
6368
+ const messageFrame = wrapper.firstElementChild;
6369
+ messageFrame.dataset[FRAME_DATA_MESSAGE_CHANNEL] = messageChannel;
6370
+ pxsim.U.addClass(wrapper, "simmsg");
6371
+ pxsim.U.addClass(wrapper, "simmsg" + messageChannel);
6372
+ if (permanent)
6373
+ messageFrame.dataset[PERMANENT] = "true";
6374
+ this.startFrame(messageFrame);
6375
+ frames = this.simFrames(); // refresh
6376
+ };
6377
+ // should we start a simulator extension for this message?
6378
+ if (simulatorExtension) {
6379
+ // find a frame already running that simulator
6380
+ let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
6381
+ // not found, spin a new one
6382
+ if (!messageFrame) {
6383
+ const url = new URL(simulatorExtension.url);
6384
+ if (this.options.parentOrigin)
6385
+ url.searchParams.set("parentOrigin", encodeURIComponent(this.options.parentOrigin));
6386
+ if (this.options.userLanguage)
6387
+ url.searchParams.set("language", encodeURIComponent(this.options.userLanguage));
6388
+ startSimulatorExtension(url.toString(), simulatorExtension.permanent);
6389
+ }
6390
+ // not running the current run, restart
6391
+ else if (messageFrame.dataset['runid'] != this.runId) {
6392
+ this.startFrame(messageFrame);
6393
+ }
6394
+ }
6395
+ // (legacy: messageSimulator) should we start a message simulator for this message?
6396
+ else if (messageSimulator) {
6337
6397
  // find a frame already running that simulator
6338
6398
  let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
6339
6399
  // not found, spin a new one
@@ -6342,16 +6402,7 @@ var pxsim;
6342
6402
  const url = ((useLocalHost && messageSimulator.localHostUrl) || messageSimulator.url)
6343
6403
  .replace("$PARENT_ORIGIN$", encodeURIComponent(this.options.parentOrigin || ""))
6344
6404
  .replace("$LANGUAGE$", encodeURIComponent(this.options.userLanguage));
6345
- let wrapper = this.createFrame(url);
6346
- this.container.appendChild(wrapper);
6347
- messageFrame = wrapper.firstElementChild;
6348
- messageFrame.dataset[FRAME_DATA_MESSAGE_CHANNEL] = messageChannel;
6349
- pxsim.U.addClass(wrapper, "simmsg");
6350
- pxsim.U.addClass(wrapper, "simmsg" + messageChannel);
6351
- if (messageSimulator.permanent)
6352
- messageFrame.dataset[PERMANENT] = "true";
6353
- this.startFrame(messageFrame);
6354
- frames = this.simFrames(); // refresh
6405
+ startSimulatorExtension(url, messageSimulator.permanent);
6355
6406
  }
6356
6407
  // not running the curren run, restart
6357
6408
  else if (messageFrame.dataset['runid'] != this.runId) {
package/built/server.d.ts CHANGED
@@ -12,6 +12,7 @@ export interface ServeOptions {
12
12
  wsPort?: number;
13
13
  serial?: boolean;
14
14
  noauth?: boolean;
15
+ backport?: number;
15
16
  }
16
17
  export declare function compileScriptAsync(id: string): Promise<string>;
17
18
  export declare function serveAsync(options: ServeOptions): Promise<void>;
package/built/server.js CHANGED
@@ -932,6 +932,10 @@ function serveAsync(options) {
932
932
  error(404, "File missing: " + filename);
933
933
  }
934
934
  };
935
+ // Strip /app/hash-sig from URL.
936
+ // This can happen when the locally running backend is serving an uploaded target,
937
+ // but has been configured to route simulator urls to port 3232.
938
+ req.url = req.url.replace(/^\/app\/[0-9a-f]{40}(?:-[0-9a-f]{10})?(.*)$/i, "$1");
935
939
  let uri = url.parse(req.url);
936
940
  let pathname = decodeURI(uri.pathname);
937
941
  const opts = querystring.parse(url.parse(req.url).query);
@@ -1071,6 +1075,26 @@ function serveAsync(options) {
1071
1075
  return error(400, "Invalid asset path");
1072
1076
  }
1073
1077
  }
1078
+ if (elts[0] == "simx" && serveOptions.backport) {
1079
+ // Proxy requests for simulator extensions to the locally running backend.
1080
+ // Should only get here when the backend is running locally and configured to serve the simulator from the cli (via LOCAL_SIM_PORT setting).
1081
+ const passthruOpts = {
1082
+ hostname: uri.hostname,
1083
+ port: serveOptions.backport,
1084
+ path: uri.path,
1085
+ method: req.method,
1086
+ headers: req.headers
1087
+ };
1088
+ const passthruReq = http.request(passthruOpts, passthruRes => {
1089
+ res.writeHead(passthruRes.statusCode, passthruRes.headers);
1090
+ passthruRes.pipe(res);
1091
+ });
1092
+ passthruReq.on("error", e => {
1093
+ console.error(`Error proxying request to port ${serveOptions.backport} .. ${e.message}`);
1094
+ return error(500, e.message);
1095
+ });
1096
+ return req.pipe(passthruReq);
1097
+ }
1074
1098
  if (options.packaged) {
1075
1099
  let filename = path.resolve(path.join(packagedDir, pathname));
1076
1100
  if (nodeutil.fileExistsSync(filename)) {
@@ -1164,6 +1188,19 @@ function serveAsync(options) {
1164
1188
  return;
1165
1189
  }
1166
1190
  }
1191
+ // Look for an .html file corresponding to `/---<pathname>`
1192
+ // Handles serving of `trg-<target>.sim.local:<port>/---simulator`
1193
+ let match = /^\/?---?(.*)/.exec(pathname);
1194
+ if (match && match[1]) {
1195
+ const htmlPathname = `/${match[1]}.html`;
1196
+ for (let dir of dd) {
1197
+ const filename = path.resolve(path.join(dir, htmlPathname));
1198
+ if (nodeutil.fileExistsSync(filename)) {
1199
+ const html = expandHtml(fs.readFileSync(filename, "utf8"), htmlParams);
1200
+ return sendHtml(html);
1201
+ }
1202
+ }
1203
+ }
1167
1204
  if (/simulator\.html/.test(pathname)) {
1168
1205
  // Special handling for missing simulator: redirect to the live sim
1169
1206
  res.writeHead(302, { location: `https://trg-${pxt.appTarget.id}.userpxt.io/---simulator` });