pxt-core 11.1.4 → 11.1.5
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 +6 -0
- package/built/pxt.js +95 -26
- package/built/pxtlib.js +1 -1
- package/built/pxtsim.d.ts +9 -0
- package/built/pxtsim.js +88 -25
- package/built/server.d.ts +1 -0
- package/built/server.js +37 -0
- package/built/target.js +1 -1
- package/built/web/main.js +1 -1
- package/built/web/pxtapp.js +1 -1
- package/built/web/pxtembed.js +1 -1
- package/built/web/pxtlib.js +1 -1
- package/built/web/pxtsim.js +1 -1
- package/built/web/pxtworker.js +1 -1
- package/common-docs/extensions/simulator-extensions.md +18 -0
- package/localtypings/pxtarget.d.ts +17 -0
- package/package.json +1 -1
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
|
|
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
|
}
|
|
@@ -153913,11 +153913,13 @@ var pxsim;
|
|
|
153913
153913
|
return isPxtElectron() || isIpcRenderer();
|
|
153914
153914
|
}
|
|
153915
153915
|
U.isElectron = isElectron;
|
|
153916
|
+
function testLocalhost(url) {
|
|
153917
|
+
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);
|
|
153918
|
+
}
|
|
153919
|
+
U.testLocalhost = testLocalhost;
|
|
153916
153920
|
function isLocalHost() {
|
|
153917
153921
|
try {
|
|
153918
|
-
return typeof window !== "undefined"
|
|
153919
|
-
&& /^http:\/\/(localhost|127\.0\.0\.1):\d+\//.test(window.location.href)
|
|
153920
|
-
&& !/nolocalhost=1/.test(window.location.href);
|
|
153922
|
+
return typeof window !== "undefined" && testLocalhost(window.location.href);
|
|
153921
153923
|
}
|
|
153922
153924
|
catch (e) {
|
|
153923
153925
|
return false;
|
|
@@ -153941,6 +153943,14 @@ var pxsim;
|
|
|
153941
153943
|
return v;
|
|
153942
153944
|
}
|
|
153943
153945
|
U.unique = unique;
|
|
153946
|
+
function sanitizeCssName(name) {
|
|
153947
|
+
let sanitized = name.replace(/[^a-zA-Z0-9-_]/g, '_');
|
|
153948
|
+
if (!/^[a-zA-Z_]/.test(sanitized)) {
|
|
153949
|
+
sanitized = 'cls_' + sanitized;
|
|
153950
|
+
}
|
|
153951
|
+
return sanitized;
|
|
153952
|
+
}
|
|
153953
|
+
U.sanitizeCssName = sanitizeCssName;
|
|
153944
153954
|
})(U = pxsim.U || (pxsim.U = {}));
|
|
153945
153955
|
class BreakLoopException {
|
|
153946
153956
|
}
|
|
@@ -155317,16 +155327,42 @@ var pxsim;
|
|
|
155317
155327
|
this._allowedOrigins.push(options.parentOrigin);
|
|
155318
155328
|
}
|
|
155319
155329
|
this._allowedOrigins.push(this.getSimUrl().origin);
|
|
155320
|
-
|
|
155321
|
-
|
|
155322
|
-
|
|
155323
|
-
|
|
155324
|
-
|
|
155325
|
-
|
|
155326
|
-
|
|
155327
|
-
|
|
155328
|
-
|
|
155329
|
-
|
|
155330
|
+
// Legacy support for message simulators
|
|
155331
|
+
const messageSimulators = (options === null || options === void 0 ? void 0 : options.messageSimulators) || {};
|
|
155332
|
+
Object.keys(messageSimulators)
|
|
155333
|
+
.map(channel => messageSimulators[channel])
|
|
155334
|
+
.forEach(messageSimulator => {
|
|
155335
|
+
this._allowedOrigins.push(new URL(messageSimulator.url).origin);
|
|
155336
|
+
if (messageSimulator.localHostUrl)
|
|
155337
|
+
this._allowedOrigins.push(new URL(messageSimulator.localHostUrl).origin);
|
|
155338
|
+
});
|
|
155339
|
+
// Preprocess simulator extensions
|
|
155340
|
+
const simXDevMode = pxsim.U.isLocalHost() && /[?&]simxdev(?:[=&#]|$)/i.test(window.location.href);
|
|
155341
|
+
Object.entries((options === null || options === void 0 ? void 0 : options.simulatorExtensions) || {}).forEach(([key, simx]) => {
|
|
155342
|
+
// Verify essential `simx` config was provided
|
|
155343
|
+
if (!simx ||
|
|
155344
|
+
!simx.index ||
|
|
155345
|
+
!simx.aspectRatio ||
|
|
155346
|
+
simx.permanent === undefined) {
|
|
155347
|
+
return;
|
|
155348
|
+
}
|
|
155349
|
+
// Compute the effective URL
|
|
155350
|
+
if (simXDevMode && simx.devUrl) {
|
|
155351
|
+
// Use the dev URL if the dev flag is set (and we're on localhost)
|
|
155352
|
+
simx.url = new URL(simx.index, simx.devUrl).toString();
|
|
155353
|
+
}
|
|
155354
|
+
else {
|
|
155355
|
+
const simUrl = this.getSimUrl();
|
|
155356
|
+
// Ensure we preserve upload target path (/app/<sha>---simulator)
|
|
155357
|
+
const simPath = simUrl.pathname.replace(/---?.*/, "");
|
|
155358
|
+
// Construct the path. The "-" element delineates the extension key from the resource name.
|
|
155359
|
+
const simxPath = [simPath, "simx", key, "-", simx.index].join("/");
|
|
155360
|
+
// Create the fully-qualified URL, preserving the origin by removing all leading slashes
|
|
155361
|
+
simx.url = new URL(simxPath.replace(/^\/+/, ""), simUrl.origin).toString();
|
|
155362
|
+
}
|
|
155363
|
+
// Add the origin to the allowed origins
|
|
155364
|
+
this._allowedOrigins.push(new URL(simx.url).origin);
|
|
155365
|
+
});
|
|
155330
155366
|
this._allowedOrigins = pxsim.U.unique(this._allowedOrigins, f => f);
|
|
155331
155367
|
}
|
|
155332
155368
|
isDebug() {
|
|
@@ -155533,8 +155569,44 @@ var pxsim;
|
|
|
155533
155569
|
const messageSimulator = messageChannel &&
|
|
155534
155570
|
this.options.messageSimulators &&
|
|
155535
155571
|
this.options.messageSimulators[messageChannel];
|
|
155536
|
-
|
|
155537
|
-
|
|
155572
|
+
const simulatorExtension = messageChannel &&
|
|
155573
|
+
this.options.simulatorExtensions &&
|
|
155574
|
+
this.options.simulatorExtensions[messageChannel];
|
|
155575
|
+
const startSimulatorExtension = (url, permanent, aspectRatio) => {
|
|
155576
|
+
var _a;
|
|
155577
|
+
aspectRatio = aspectRatio || ((_a = this._runOptions) === null || _a === void 0 ? void 0 : _a.aspectRatio) || 1.22;
|
|
155578
|
+
let wrapper = this.createFrame(url);
|
|
155579
|
+
this.container.appendChild(wrapper);
|
|
155580
|
+
const messageFrame = wrapper.firstElementChild;
|
|
155581
|
+
messageFrame.dataset[FRAME_DATA_MESSAGE_CHANNEL] = messageChannel;
|
|
155582
|
+
messageFrame.dataset[FRAME_ASPECT_RATIO] = aspectRatio + "";
|
|
155583
|
+
pxsim.U.addClass(wrapper, "simmsg");
|
|
155584
|
+
pxsim.U.addClass(wrapper, "simmsg" + pxsim.U.sanitizeCssName(messageChannel));
|
|
155585
|
+
if (permanent)
|
|
155586
|
+
messageFrame.dataset[PERMANENT] = "true";
|
|
155587
|
+
this.startFrame(messageFrame);
|
|
155588
|
+
frames = this.simFrames(); // refresh
|
|
155589
|
+
};
|
|
155590
|
+
// should we start a simulator extension for this message?
|
|
155591
|
+
if (simulatorExtension) {
|
|
155592
|
+
// find a frame already running that simulator
|
|
155593
|
+
let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
|
|
155594
|
+
// not found, spin a new one
|
|
155595
|
+
if (!messageFrame) {
|
|
155596
|
+
const url = new URL(simulatorExtension.url);
|
|
155597
|
+
if (this.options.parentOrigin)
|
|
155598
|
+
url.searchParams.set("parentOrigin", encodeURIComponent(this.options.parentOrigin));
|
|
155599
|
+
if (this.options.userLanguage)
|
|
155600
|
+
url.searchParams.set("language", encodeURIComponent(this.options.userLanguage));
|
|
155601
|
+
startSimulatorExtension(url.toString(), simulatorExtension.permanent, simulatorExtension.aspectRatio);
|
|
155602
|
+
}
|
|
155603
|
+
// not running the current run, restart
|
|
155604
|
+
else if (messageFrame.dataset['runid'] != this.runId) {
|
|
155605
|
+
this.startFrame(messageFrame);
|
|
155606
|
+
}
|
|
155607
|
+
}
|
|
155608
|
+
// (legacy: messageSimulator) should we start a message simulator for this message?
|
|
155609
|
+
else if (messageSimulator) {
|
|
155538
155610
|
// find a frame already running that simulator
|
|
155539
155611
|
let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
|
|
155540
155612
|
// not found, spin a new one
|
|
@@ -155543,16 +155615,7 @@ var pxsim;
|
|
|
155543
155615
|
const url = ((useLocalHost && messageSimulator.localHostUrl) || messageSimulator.url)
|
|
155544
155616
|
.replace("$PARENT_ORIGIN$", encodeURIComponent(this.options.parentOrigin || ""))
|
|
155545
155617
|
.replace("$LANGUAGE$", encodeURIComponent(this.options.userLanguage));
|
|
155546
|
-
|
|
155547
|
-
this.container.appendChild(wrapper);
|
|
155548
|
-
messageFrame = wrapper.firstElementChild;
|
|
155549
|
-
messageFrame.dataset[FRAME_DATA_MESSAGE_CHANNEL] = messageChannel;
|
|
155550
|
-
pxsim.U.addClass(wrapper, "simmsg");
|
|
155551
|
-
pxsim.U.addClass(wrapper, "simmsg" + messageChannel);
|
|
155552
|
-
if (messageSimulator.permanent)
|
|
155553
|
-
messageFrame.dataset[PERMANENT] = "true";
|
|
155554
|
-
this.startFrame(messageFrame);
|
|
155555
|
-
frames = this.simFrames(); // refresh
|
|
155618
|
+
startSimulatorExtension(url, messageSimulator.permanent, messageSimulator.aspectRatio);
|
|
155556
155619
|
}
|
|
155557
155620
|
// not running the curren run, restart
|
|
155558
155621
|
else if (messageFrame.dataset['runid'] != this.runId) {
|
|
@@ -163160,6 +163223,7 @@ function serveAsync(parsed) {
|
|
|
163160
163223
|
browser: parsed.flags["browser"],
|
|
163161
163224
|
serial: !parsed.flags["noSerial"] && !exports.globalConfig.noSerial,
|
|
163162
163225
|
noauth: parsed.flags["noauth"] || false,
|
|
163226
|
+
backport: parsed.flags["backport"] || 0,
|
|
163163
163227
|
}));
|
|
163164
163228
|
}
|
|
163165
163229
|
exports.serveAsync = serveAsync;
|
|
@@ -166877,6 +166941,11 @@ ${pxt.crowdin.KEY_VARIABLE} - crowdin key
|
|
|
166877
166941
|
noauth: {
|
|
166878
166942
|
description: "disable localtoken-based authentication",
|
|
166879
166943
|
aliases: ["na"],
|
|
166944
|
+
},
|
|
166945
|
+
backport: {
|
|
166946
|
+
description: "port where the locally running backend is listening.",
|
|
166947
|
+
argument: "backport",
|
|
166948
|
+
type: "number",
|
|
166880
166949
|
}
|
|
166881
166950
|
}
|
|
166882
166951
|
}, 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
|
|
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,9 +1059,11 @@ 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[];
|
|
1066
|
+
function sanitizeCssName(name: string): string;
|
|
1065
1067
|
}
|
|
1066
1068
|
export interface Map<T> {
|
|
1067
1069
|
[index: string]: T;
|
|
@@ -1308,6 +1310,13 @@ declare namespace pxsim {
|
|
|
1308
1310
|
aspectRatio?: number;
|
|
1309
1311
|
permanent?: boolean;
|
|
1310
1312
|
}>;
|
|
1313
|
+
simulatorExtensions?: pxt.Map<{
|
|
1314
|
+
aspectRatio?: number;
|
|
1315
|
+
permanent?: boolean;
|
|
1316
|
+
index?: string;
|
|
1317
|
+
devUrl?: string;
|
|
1318
|
+
url?: string;
|
|
1319
|
+
}>;
|
|
1311
1320
|
userLanguage?: string;
|
|
1312
1321
|
}
|
|
1313
1322
|
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;
|
|
@@ -4740,6 +4742,14 @@ var pxsim;
|
|
|
4740
4742
|
return v;
|
|
4741
4743
|
}
|
|
4742
4744
|
U.unique = unique;
|
|
4745
|
+
function sanitizeCssName(name) {
|
|
4746
|
+
let sanitized = name.replace(/[^a-zA-Z0-9-_]/g, '_');
|
|
4747
|
+
if (!/^[a-zA-Z_]/.test(sanitized)) {
|
|
4748
|
+
sanitized = 'cls_' + sanitized;
|
|
4749
|
+
}
|
|
4750
|
+
return sanitized;
|
|
4751
|
+
}
|
|
4752
|
+
U.sanitizeCssName = sanitizeCssName;
|
|
4743
4753
|
})(U = pxsim.U || (pxsim.U = {}));
|
|
4744
4754
|
class BreakLoopException {
|
|
4745
4755
|
}
|
|
@@ -6116,16 +6126,42 @@ var pxsim;
|
|
|
6116
6126
|
this._allowedOrigins.push(options.parentOrigin);
|
|
6117
6127
|
}
|
|
6118
6128
|
this._allowedOrigins.push(this.getSimUrl().origin);
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
+
// Legacy support for message simulators
|
|
6130
|
+
const messageSimulators = (options === null || options === void 0 ? void 0 : options.messageSimulators) || {};
|
|
6131
|
+
Object.keys(messageSimulators)
|
|
6132
|
+
.map(channel => messageSimulators[channel])
|
|
6133
|
+
.forEach(messageSimulator => {
|
|
6134
|
+
this._allowedOrigins.push(new URL(messageSimulator.url).origin);
|
|
6135
|
+
if (messageSimulator.localHostUrl)
|
|
6136
|
+
this._allowedOrigins.push(new URL(messageSimulator.localHostUrl).origin);
|
|
6137
|
+
});
|
|
6138
|
+
// Preprocess simulator extensions
|
|
6139
|
+
const simXDevMode = pxsim.U.isLocalHost() && /[?&]simxdev(?:[=&#]|$)/i.test(window.location.href);
|
|
6140
|
+
Object.entries((options === null || options === void 0 ? void 0 : options.simulatorExtensions) || {}).forEach(([key, simx]) => {
|
|
6141
|
+
// Verify essential `simx` config was provided
|
|
6142
|
+
if (!simx ||
|
|
6143
|
+
!simx.index ||
|
|
6144
|
+
!simx.aspectRatio ||
|
|
6145
|
+
simx.permanent === undefined) {
|
|
6146
|
+
return;
|
|
6147
|
+
}
|
|
6148
|
+
// Compute the effective URL
|
|
6149
|
+
if (simXDevMode && simx.devUrl) {
|
|
6150
|
+
// Use the dev URL if the dev flag is set (and we're on localhost)
|
|
6151
|
+
simx.url = new URL(simx.index, simx.devUrl).toString();
|
|
6152
|
+
}
|
|
6153
|
+
else {
|
|
6154
|
+
const simUrl = this.getSimUrl();
|
|
6155
|
+
// Ensure we preserve upload target path (/app/<sha>---simulator)
|
|
6156
|
+
const simPath = simUrl.pathname.replace(/---?.*/, "");
|
|
6157
|
+
// Construct the path. The "-" element delineates the extension key from the resource name.
|
|
6158
|
+
const simxPath = [simPath, "simx", key, "-", simx.index].join("/");
|
|
6159
|
+
// Create the fully-qualified URL, preserving the origin by removing all leading slashes
|
|
6160
|
+
simx.url = new URL(simxPath.replace(/^\/+/, ""), simUrl.origin).toString();
|
|
6161
|
+
}
|
|
6162
|
+
// Add the origin to the allowed origins
|
|
6163
|
+
this._allowedOrigins.push(new URL(simx.url).origin);
|
|
6164
|
+
});
|
|
6129
6165
|
this._allowedOrigins = pxsim.U.unique(this._allowedOrigins, f => f);
|
|
6130
6166
|
}
|
|
6131
6167
|
isDebug() {
|
|
@@ -6332,8 +6368,44 @@ var pxsim;
|
|
|
6332
6368
|
const messageSimulator = messageChannel &&
|
|
6333
6369
|
this.options.messageSimulators &&
|
|
6334
6370
|
this.options.messageSimulators[messageChannel];
|
|
6335
|
-
|
|
6336
|
-
|
|
6371
|
+
const simulatorExtension = messageChannel &&
|
|
6372
|
+
this.options.simulatorExtensions &&
|
|
6373
|
+
this.options.simulatorExtensions[messageChannel];
|
|
6374
|
+
const startSimulatorExtension = (url, permanent, aspectRatio) => {
|
|
6375
|
+
var _a;
|
|
6376
|
+
aspectRatio = aspectRatio || ((_a = this._runOptions) === null || _a === void 0 ? void 0 : _a.aspectRatio) || 1.22;
|
|
6377
|
+
let wrapper = this.createFrame(url);
|
|
6378
|
+
this.container.appendChild(wrapper);
|
|
6379
|
+
const messageFrame = wrapper.firstElementChild;
|
|
6380
|
+
messageFrame.dataset[FRAME_DATA_MESSAGE_CHANNEL] = messageChannel;
|
|
6381
|
+
messageFrame.dataset[FRAME_ASPECT_RATIO] = aspectRatio + "";
|
|
6382
|
+
pxsim.U.addClass(wrapper, "simmsg");
|
|
6383
|
+
pxsim.U.addClass(wrapper, "simmsg" + pxsim.U.sanitizeCssName(messageChannel));
|
|
6384
|
+
if (permanent)
|
|
6385
|
+
messageFrame.dataset[PERMANENT] = "true";
|
|
6386
|
+
this.startFrame(messageFrame);
|
|
6387
|
+
frames = this.simFrames(); // refresh
|
|
6388
|
+
};
|
|
6389
|
+
// should we start a simulator extension for this message?
|
|
6390
|
+
if (simulatorExtension) {
|
|
6391
|
+
// find a frame already running that simulator
|
|
6392
|
+
let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
|
|
6393
|
+
// not found, spin a new one
|
|
6394
|
+
if (!messageFrame) {
|
|
6395
|
+
const url = new URL(simulatorExtension.url);
|
|
6396
|
+
if (this.options.parentOrigin)
|
|
6397
|
+
url.searchParams.set("parentOrigin", encodeURIComponent(this.options.parentOrigin));
|
|
6398
|
+
if (this.options.userLanguage)
|
|
6399
|
+
url.searchParams.set("language", encodeURIComponent(this.options.userLanguage));
|
|
6400
|
+
startSimulatorExtension(url.toString(), simulatorExtension.permanent, simulatorExtension.aspectRatio);
|
|
6401
|
+
}
|
|
6402
|
+
// not running the current run, restart
|
|
6403
|
+
else if (messageFrame.dataset['runid'] != this.runId) {
|
|
6404
|
+
this.startFrame(messageFrame);
|
|
6405
|
+
}
|
|
6406
|
+
}
|
|
6407
|
+
// (legacy: messageSimulator) should we start a message simulator for this message?
|
|
6408
|
+
else if (messageSimulator) {
|
|
6337
6409
|
// find a frame already running that simulator
|
|
6338
6410
|
let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
|
|
6339
6411
|
// not found, spin a new one
|
|
@@ -6342,16 +6414,7 @@ var pxsim;
|
|
|
6342
6414
|
const url = ((useLocalHost && messageSimulator.localHostUrl) || messageSimulator.url)
|
|
6343
6415
|
.replace("$PARENT_ORIGIN$", encodeURIComponent(this.options.parentOrigin || ""))
|
|
6344
6416
|
.replace("$LANGUAGE$", encodeURIComponent(this.options.userLanguage));
|
|
6345
|
-
|
|
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
|
|
6417
|
+
startSimulatorExtension(url, messageSimulator.permanent, messageSimulator.aspectRatio);
|
|
6355
6418
|
}
|
|
6356
6419
|
// not running the curren run, restart
|
|
6357
6420
|
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` });
|