Socket
Socket
Sign inDemoInstall

@stackblitz/sdk

Package Overview
Dependencies
0
Maintainers
4
Versions
43
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.9.0 to 1.8.2

typings/connection.d.ts

516

bundles/sdk.js

@@ -1,516 +0,2 @@

"use strict";
const CONNECT_INTERVAL = 500;
const CONNECT_MAX_ATTEMPTS = 20;
const DEFAULT_FRAME_HEIGHT = 300;
const DEFAULT_ORIGIN = "https://stackblitz.com";
const PROJECT_TEMPLATES = [
"angular-cli",
"create-react-app",
"html",
"javascript",
"node",
"polymer",
"typescript",
"vue"
];
const UI_SIDEBAR_VIEWS = ["project", "search", "ports", "settings"];
const UI_THEMES = ["light", "dark"];
const UI_VIEWS = ["editor", "preview"];
const generators = {
clickToLoad: (value) => trueParam("ctl", value),
devToolsHeight: (value) => percentParam("devtoolsheight", value),
forceEmbedLayout: (value) => trueParam("embed", value),
hideDevTools: (value) => trueParam("hidedevtools", value),
hideExplorer: (value) => trueParam("hideExplorer", value),
hideNavigation: (value) => trueParam("hideNavigation", value),
openFile: (value) => stringParams("file", value),
showSidebar: (value) => booleanParam("showSidebar", value),
sidebarView: (value) => enumParam("sidebarView", value, UI_SIDEBAR_VIEWS),
startScript: (value) => stringParams("startScript", value),
terminalHeight: (value) => percentParam("terminalHeight", value),
theme: (value) => enumParam("theme", value, UI_THEMES),
view: (value) => enumParam("view", value, UI_VIEWS),
zenMode: (value) => trueParam("zenMode", value)
};
function buildParams(options = {}) {
const params = Object.entries(options).map(([key, value]) => {
if (value != null && generators.hasOwnProperty(key)) {
return generators[key](value);
}
return "";
}).filter(Boolean);
return params.length ? `?${params.join("&")}` : "";
}
function trueParam(name, value) {
if (value === true) {
return `${name}=1`;
}
return "";
}
function booleanParam(name, value) {
if (typeof value === "boolean") {
return `${name}=${value ? "1" : "0"}`;
}
return "";
}
function percentParam(name, value) {
if (typeof value === "number" && !Number.isNaN(value)) {
const clamped = Math.min(100, Math.max(0, value));
return `${name}=${encodeURIComponent(Math.round(clamped))}`;
}
return "";
}
function enumParam(name, value = "", allowList = []) {
if (allowList.includes(value)) {
return `${name}=${encodeURIComponent(value)}`;
}
return "";
}
function stringParams(name, value) {
const values = Array.isArray(value) ? value : [value];
return values.filter((val) => typeof val === "string" && val.trim() !== "").map((val) => `${name}=${encodeURIComponent(val)}`).join("&");
}
function genID() {
return Math.random().toString(36).slice(2, 6) + Math.random().toString(36).slice(2, 6);
}
function openUrl(route, options) {
return `${getOrigin(options)}${route}${buildParams(options)}`;
}
function embedUrl(route, options) {
const config = {
forceEmbedLayout: true
};
if (options && typeof options === "object") {
Object.assign(config, options);
}
return `${getOrigin(config)}${route}${buildParams(config)}`;
}
function getOrigin(options = {}) {
const origin = typeof options.origin === "string" ? options.origin : DEFAULT_ORIGIN;
return origin.replace(/\/$/, "");
}
function replaceAndEmbed(target, frame, options) {
if (!frame || !target || !target.parentNode) {
throw new Error("Invalid Element");
}
if (target.id) {
frame.id = target.id;
}
if (target.className) {
frame.className = target.className;
}
setFrameDimensions(frame, options);
target.replaceWith(frame);
}
function findElement(elementOrId) {
if (typeof elementOrId === "string") {
const element = document.getElementById(elementOrId);
if (!element) {
throw new Error(`Could not find element with id '${elementOrId}'`);
}
return element;
} else if (elementOrId instanceof HTMLElement) {
return elementOrId;
}
throw new Error(`Invalid element: ${elementOrId}`);
}
function openTarget(options) {
return options && options.newWindow === false ? "_self" : "_blank";
}
function setFrameDimensions(frame, options = {}) {
const height = Object.hasOwnProperty.call(options, "height") ? `${options.height}` : `${DEFAULT_FRAME_HEIGHT}`;
const width = Object.hasOwnProperty.call(options, "width") ? `${options.width}` : void 0;
frame.setAttribute("height", height);
if (width) {
frame.setAttribute("width", width);
} else {
frame.setAttribute("style", "width:100%;");
}
}
class RDC {
constructor(port) {
this.pending = {};
this.port = port;
this.port.onmessage = this.messageListener.bind(this);
}
request({ type, payload }) {
return new Promise((resolve, reject) => {
const id = genID();
this.pending[id] = { resolve, reject };
this.port.postMessage({
type,
payload: {
...payload,
// Ensure the payload object includes the request ID
__reqid: id
}
});
});
}
messageListener(event) {
if (typeof event.data.payload?.__reqid !== "string") {
return;
}
const { type, payload } = event.data;
const { __reqid: id, __success: success, __error: error } = payload;
if (this.pending[id]) {
if (success) {
this.pending[id].resolve(this.cleanResult(payload));
} else {
this.pending[id].reject(error ? `${type}: ${error}` : type);
}
delete this.pending[id];
}
}
cleanResult(payload) {
const result = { ...payload };
delete result.__reqid;
delete result.__success;
delete result.__error;
return Object.keys(result).length ? result : null;
}
}
class VM {
constructor(port, config) {
this.editor = {
/**
* Open one of several files in tabs and/or split panes.
*
* @since 1.7.0 Added support for opening multiple files
*/
openFile: (path) => {
return this._rdc.request({
type: "SDK_OPEN_FILE",
payload: { path }
});
},
/**
* Set a project file as the currently selected file.
*
* - This may update the highlighted file in the file explorer,
* and the currently open and/or focused editor tab.
* - It will _not_ open a new editor tab if the provided path does not
* match a currently open tab. See `vm.editor.openFile` to open files.
*
* @since 1.7.0
* @experimental
*/
setCurrentFile: (path) => {
return this._rdc.request({
type: "SDK_SET_CURRENT_FILE",
payload: { path }
});
},
/**
* Change the color theme
*
* @since 1.7.0
*/
setTheme: (theme) => {
return this._rdc.request({
type: "SDK_SET_UI_THEME",
payload: { theme }
});
},
/**
* Change the display mode of the project:
*
* - `default`: show the editor and preview pane
* - `editor`: show the editor pane only
* - `preview`: show the preview pane only
*
* @since 1.7.0
*/
setView: (view) => {
return this._rdc.request({
type: "SDK_SET_UI_VIEW",
payload: { view }
});
},
/**
* Change the display mode of the sidebar:
*
* - `true`: show the sidebar
* - `false`: hide the sidebar
*
* @since 1.7.0
*/
showSidebar: (visible = true) => {
return this._rdc.request({
type: "SDK_TOGGLE_SIDEBAR",
payload: { visible }
});
}
};
this.preview = {
/**
* The origin (protocol and domain) of the preview iframe.
*
* In WebContainers-based projects, the origin will always be `null`;
* try using `vm.preview.getUrl` instead.
*
* @see https://developer.stackblitz.com/guides/user-guide/available-environments
*/
origin: "",
/**
* Get the current preview URL.
*
* In both and EngineBlock and WebContainers-based projects, the preview URL
* may not reflect the exact path of the current page, after user navigation.
*
* In WebContainers-based projects, the preview URL will be `null` initially,
* and until the project starts a web server.
*
* @since 1.7.0
* @experimental
*/
getUrl: () => {
return this._rdc.request({
type: "SDK_GET_PREVIEW_URL",
payload: {}
}).then((data) => data?.url ?? null);
},
/**
* Change the path of the preview URL.
*
* In WebContainers-based projects, this will be ignored if there is no
* currently running web server.
*
* @since 1.7.0
* @experimental
*/
setUrl: (path = "/") => {
if (typeof path !== "string" || !path.startsWith("/")) {
throw new Error(`Invalid argument: expected a path starting with '/', got '${path}'`);
}
return this._rdc.request({
type: "SDK_SET_PREVIEW_URL",
payload: { path }
});
}
};
this._rdc = new RDC(port);
Object.defineProperty(this.preview, "origin", {
value: typeof config.previewOrigin === "string" ? config.previewOrigin : null,
writable: false
});
}
/**
* Apply batch updates to the project files in one call.
*/
applyFsDiff(diff) {
const isObject = (val) => val !== null && typeof val === "object";
if (!isObject(diff) || !isObject(diff.create)) {
throw new Error("Invalid diff object: expected diff.create to be an object.");
} else if (!Array.isArray(diff.destroy)) {
throw new Error("Invalid diff object: expected diff.destroy to be an array.");
}
return this._rdc.request({
type: "SDK_APPLY_FS_DIFF",
payload: diff
});
}
/**
* Get the project’s defined dependencies.
*
* In EngineBlock projects, version numbers represent the resolved dependency versions.
* In WebContainers-based projects, returns data from the project’s `package.json` without resolving installed version numbers.
*/
getDependencies() {
return this._rdc.request({
type: "SDK_GET_DEPS_SNAPSHOT",
payload: {}
});
}
/**
* Get a snapshot of the project files and their content.
*/
getFsSnapshot() {
return this._rdc.request({
type: "SDK_GET_FS_SNAPSHOT",
payload: {}
});
}
}
const connections = [];
class Connection {
constructor(element) {
this.id = genID();
this.element = element;
this.pending = new Promise((resolve, reject) => {
const listenForSuccess = ({ data, ports }) => {
if (data?.action === "SDK_INIT_SUCCESS" && data.id === this.id) {
this.vm = new VM(ports[0], data.payload);
resolve(this.vm);
cleanup();
}
};
const pingFrame = () => {
this.element.contentWindow?.postMessage(
{
action: "SDK_INIT",
id: this.id
},
"*"
);
};
function cleanup() {
window.clearInterval(interval);
window.removeEventListener("message", listenForSuccess);
}
window.addEventListener("message", listenForSuccess);
pingFrame();
let attempts = 0;
const interval = window.setInterval(() => {
if (this.vm) {
cleanup();
return;
}
if (attempts >= CONNECT_MAX_ATTEMPTS) {
cleanup();
reject("Timeout: Unable to establish a connection with the StackBlitz VM");
connections.forEach((connection, index) => {
if (connection.id === this.id) {
connections.splice(index, 1);
}
});
return;
}
attempts++;
pingFrame();
}, CONNECT_INTERVAL);
});
connections.push(this);
}
}
const getConnection = (identifier) => {
const key = identifier instanceof Element ? "element" : "id";
return connections.find((c) => c[key] === identifier) ?? null;
};
function createHiddenInput(name, value) {
const input = document.createElement("input");
input.type = "hidden";
input.name = name;
input.value = value;
return input;
}
function encodeFilePath(path) {
return path.replace(/\[/g, "%5B").replace(/\]/g, "%5D");
}
function createProjectForm({
template,
title,
description,
dependencies,
files,
settings
}) {
if (!PROJECT_TEMPLATES.includes(template)) {
const names = PROJECT_TEMPLATES.map((t) => `'${t}'`).join(", ");
console.warn(`Unsupported project.template: must be one of ${names}`);
}
const inputs = [];
const addInput = (name, value, defaultValue = "") => {
inputs.push(createHiddenInput(name, typeof value === "string" ? value : defaultValue));
};
addInput("project[title]", title);
if (typeof description === "string" && description.length > 0) {
addInput("project[description]", description);
}
addInput("project[template]", template, "javascript");
if (dependencies) {
if (template === "node") {
console.warn(
`Invalid project.dependencies: dependencies must be provided as a 'package.json' file when using the 'node' template.`
);
} else {
addInput("project[dependencies]", JSON.stringify(dependencies));
}
}
if (settings) {
addInput("project[settings]", JSON.stringify(settings));
}
Object.entries(files).forEach(([path, contents]) => {
addInput(`project[files][${encodeFilePath(path)}]`, contents);
});
const form = document.createElement("form");
form.method = "POST";
form.setAttribute("style", "display:none!important;");
form.append(...inputs);
return form;
}
function createProjectFrameHTML(project, options) {
const form = createProjectForm(project);
form.action = embedUrl("/run", options);
form.id = "sb_run";
const html = `<!doctype html>
<html>
<head><title></title></head>
<body>
${form.outerHTML}
<script>document.getElementById('${form.id}').submit();<\/script>
</body>
</html>`;
return html;
}
function openNewProject(project, options) {
const form = createProjectForm(project);
form.action = openUrl("/run", options);
form.target = openTarget(options);
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
}
function connect(frameEl) {
if (!frameEl?.contentWindow) {
return Promise.reject("Provided element is not an iframe.");
}
const connection = getConnection(frameEl) ?? new Connection(frameEl);
return connection.pending;
}
function openProject(project, options) {
openNewProject(project, options);
}
function openProjectId(projectId, options) {
const url = openUrl(`/edit/${projectId}`, options);
const target = openTarget(options);
window.open(url, target);
}
function openGithubProject(repoSlug, options) {
const url = openUrl(`/github/${repoSlug}`, options);
const target = openTarget(options);
window.open(url, target);
}
function embedProject(elementOrId, project, options) {
const element = findElement(elementOrId);
const html = createProjectFrameHTML(project, options);
const frame = document.createElement("iframe");
replaceAndEmbed(element, frame, options);
frame.contentDocument?.write(html);
return connect(frame);
}
function embedProjectId(elementOrId, projectId, options) {
const element = findElement(elementOrId);
const frame = document.createElement("iframe");
frame.src = embedUrl(`/edit/${projectId}`, options);
replaceAndEmbed(element, frame, options);
return connect(frame);
}
function embedGithubProject(elementOrId, repoSlug, options) {
const element = findElement(elementOrId);
const frame = document.createElement("iframe");
frame.src = embedUrl(`/github/${repoSlug}`, options);
replaceAndEmbed(element, frame, options);
return connect(frame);
}
const StackBlitzSDK = {
connect,
embedGithubProject,
embedProject,
embedProjectId,
openGithubProject,
openProject,
openProjectId
};
module.exports = StackBlitzSDK;
var e=["angular-cli","create-react-app","html","javascript","node","polymer","typescript","vue"],t={clickToLoad:function(e){return r("ctl",e)},devToolsHeight:function(e){return i("devtoolsheight",e)},forceEmbedLayout:function(e){return r("embed",e)},hideDevTools:function(e){return r("hidedevtools",e)},hideExplorer:function(e){return r("hideExplorer",e)},hideNavigation:function(e){return r("hideNavigation",e)},showSidebar:function(e){return function(e,t){return"boolean"==typeof t?"showSidebar="+(t?"1":"0"):""}(0,e)},openFile:function(e){return function(e,t){return(Array.isArray(t)?t:[t]).filter(function(e){return"string"==typeof e&&""!==e.trim()}).map(function(e){return"file="+encodeURIComponent(e.trim())})}(0,e).join("&")},terminalHeight:function(e){return i("terminalHeight",e)},theme:function(e){return o("theme",["light","dark"],e)},view:function(e){return o("view",["preview","editor"],e)}};function n(e){void 0===e&&(e={});var n=Object.entries(e).map(function(e){var n=e[0],r=e[1];return null!=r&&t.hasOwnProperty(n)?t[n](r):""}).filter(Boolean);return n.length?"?"+n.join("&"):""}function r(e,t){return!0===t?e+"=1":""}function i(e,t){return"number"==typeof t&&t>=0&&t<=100?e+"="+Math.round(t):""}function o(e,t,n){return"string"==typeof n&&t.includes(n)?e+"="+n:""}function a(){return Math.random().toString(36).slice(2,6)+Math.random().toString(36).slice(2,6)}function d(e,t){return""+u(t)+e+n(t)}function c(e,t){var r={forceEmbedLayout:!0};return t&&"object"==typeof t&&Object.assign(r,t),""+u(r)+e+n(r)}function u(e){return void 0===e&&(e={}),"string"==typeof e.origin?e.origin:"https://stackblitz.com"}function s(e,t,n){if(!t||!e||!e.parentNode)throw new Error("Invalid Element");e.id&&(t.id=e.id),e.className&&(t.className=e.className),function(e,t){t&&"object"==typeof t&&(Object.hasOwnProperty.call(t,"height")&&(e.height=""+t.height),Object.hasOwnProperty.call(t,"width")&&(e.width=""+t.width)),e.height||(e.height="300"),e.width||e.setAttribute("style","width:100%;")}(t,n),e.parentNode.replaceChild(t,e)}function l(e){if("string"==typeof e){var t=document.getElementById(e);if(!t)throw new Error("Could not find element with id '"+e+"'");return t}if(e instanceof HTMLElement)return e;throw new Error("Invalid element: "+e)}function p(e){return e&&!1===e.newWindow?"_self":"_blank"}function f(){return f=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},f.apply(this,arguments)}var h=/*#__PURE__*/function(){function e(e){this.port=void 0,this.pending={},this.port=e,this.port.onmessage=this.messageListener.bind(this)}var t=e.prototype;return t.request=function(e){var t=this,n=e.type,r=e.payload,i=a();return new Promise(function(e,o){t.pending[i]={resolve:e,reject:o},t.port.postMessage({type:n,payload:f({},r,{__reqid:i})})})},t.messageListener=function(e){var t;if("string"==typeof(null==(t=e.data.payload)?void 0:t.__reqid)){var n=e.data,r=n.type,i=n.payload,o=i.__reqid,a=i.__error;this.pending[o]&&(i.__success?this.pending[o].resolve(function(e){var t=f({},e);return delete t.__reqid,delete t.__success,delete t.__error,Object.keys(t).length?t:null}(i)):this.pending[o].reject(a?r+": "+a:r),delete this.pending[o])}},e}(),m=/*#__PURE__*/function(){function e(e,t){var n=this;this._rdc=void 0,this.editor={openFile:function(e){return n._rdc.request({type:"SDK_OPEN_FILE",payload:{path:e}})},setCurrentFile:function(e){return n._rdc.request({type:"SDK_SET_CURRENT_FILE",payload:{path:e}})},setTheme:function(e){return n._rdc.request({type:"SDK_SET_UI_THEME",payload:{theme:e}})},setView:function(e){return n._rdc.request({type:"SDK_SET_UI_VIEW",payload:{view:e}})},showSidebar:function(e){return void 0===e&&(e=!0),n._rdc.request({type:"SDK_TOGGLE_SIDEBAR",payload:{visible:e}})}},this.preview={origin:"",getUrl:function(){return n._rdc.request({type:"SDK_GET_PREVIEW_URL",payload:{}}).then(function(e){var t;return null!=(t=null==e?void 0:e.url)?t:null})},setUrl:function(e){if(void 0===e&&(e="/"),"string"!=typeof e||!e.startsWith("/"))throw new Error("Invalid argument: expected a path starting with '/', got '"+e+"'");return n._rdc.request({type:"SDK_SET_PREVIEW_URL",payload:{path:e}})}},this._rdc=new h(e),Object.defineProperty(this.preview,"origin",{value:"string"==typeof t.previewOrigin?t.previewOrigin:null,writable:!1})}var t=e.prototype;return t.applyFsDiff=function(e){var t=function(e){return null!==e&&"object"==typeof e};if(!t(e)||!t(e.create))throw new Error("Invalid diff object: expected diff.create to be an object.");if(!Array.isArray(e.destroy))throw new Error("Invalid diff object: expected diff.create to be an array.");return this._rdc.request({type:"SDK_APPLY_FS_DIFF",payload:e})},t.getDependencies=function(){return this._rdc.request({type:"SDK_GET_DEPS_SNAPSHOT",payload:{}})},t.getFsSnapshot=function(){return this._rdc.request({type:"SDK_GET_FS_SNAPSHOT",payload:{}})},e}(),v=[],y=function(e){var t=this;this.element=void 0,this.id=void 0,this.pending=void 0,this.vm=void 0,this.id=a(),this.element=e,this.pending=new Promise(function(e,n){var r=function(n){var r=n.data;"SDK_INIT_SUCCESS"===(null==r?void 0:r.action)&&r.id===t.id&&(t.vm=new m(n.ports[0],r.payload),e(t.vm),o())},i=function(){var e;null==(e=t.element.contentWindow)||e.postMessage({action:"SDK_INIT",id:t.id},"*")};function o(){window.clearInterval(d),window.removeEventListener("message",r)}window.addEventListener("message",r),i();var a=0,d=window.setInterval(function(){if(t.vm)o();else{if(a>=20)return o(),n("Timeout: Unable to establish a connection with the StackBlitz VM"),void v.forEach(function(e,n){e.id===t.id&&v.splice(n,1)});a++,i()}},500)}),v.push(this)};function g(e,t){var n=document.createElement("input");return n.type="hidden",n.name=e,n.value=t,n}function w(t){if(!e.includes(t.template)){var n=e.map(function(e){return"'"+e+"'"}).join(", ");console.warn("Unsupported project.template: must be one of "+n)}var r="node"===t.template,i=document.createElement("form");return i.method="POST",i.setAttribute("style","display:none!important;"),i.appendChild(g("project[title]",t.title)),i.appendChild(g("project[description]",t.description)),i.appendChild(g("project[template]",t.template)),t.dependencies&&(r?console.warn("Invalid project.dependencies: dependencies must be provided as a 'package.json' file when using the 'node' template."):i.appendChild(g("project[dependencies]",JSON.stringify(t.dependencies)))),t.settings&&i.appendChild(g("project[settings]",JSON.stringify(t.settings))),Object.keys(t.files).forEach(function(e){var n="project[files]"+function(e){return"["+e.replace(/\[/g,"%5B").replace(/\]/g,"%5D")+"]"}(e),r=t.files[e];"string"==typeof r&&i.appendChild(g(n,r))}),i}function _(e){var t,n,r,i;return null!=e&&e.contentWindow?(null!=(i=(n=e)instanceof Element?"element":"id",t=null!=(r=v.find(function(e){return e[i]===n}))?r:null)?t:new y(e)).pending:Promise.reject("Provided element is not an iframe.")}module.exports={connect:_,embedGithubProject:function(e,t,n){var r=l(e),i=document.createElement("iframe");return i.src=c("/github/"+t,n),s(r,i,n),_(i)},embedProject:function(e,t,n){var r,i=l(e),o=function(e,t){var n=w(e);return n.action=c("/run",t),n.id="sb","<html><head><title></title></head><body>"+n.outerHTML+"<script>document.getElementById('"+n.id+"').submit();<\/script></body></html>"}(t,n),a=document.createElement("iframe");return s(i,a,n),null==(r=a.contentDocument)||r.write(o),_(a)},embedProjectId:function(e,t,n){var r=l(e),i=document.createElement("iframe");return i.src=c("/edit/"+t,n),s(r,i,n),_(i)},openGithubProject:function(e,t){var n=d("/github/"+e,t),r=p(t);window.open(n,r)},openProject:function(e,t){!function(e,t){var n=w(e);n.action=d("/run",t),n.target=p(t),document.body.appendChild(n),n.submit(),document.body.removeChild(n)}(e,t)},openProjectId:function(e,t){var n=d("/edit/"+e,t),r=p(t);window.open(n,r)}};
//# sourceMappingURL=sdk.js.map

@@ -1,517 +0,2 @@

const CONNECT_INTERVAL = 500;
const CONNECT_MAX_ATTEMPTS = 20;
const DEFAULT_FRAME_HEIGHT = 300;
const DEFAULT_ORIGIN = "https://stackblitz.com";
const PROJECT_TEMPLATES = [
"angular-cli",
"create-react-app",
"html",
"javascript",
"node",
"polymer",
"typescript",
"vue"
];
const UI_SIDEBAR_VIEWS = ["project", "search", "ports", "settings"];
const UI_THEMES = ["light", "dark"];
const UI_VIEWS = ["editor", "preview"];
const generators = {
clickToLoad: (value) => trueParam("ctl", value),
devToolsHeight: (value) => percentParam("devtoolsheight", value),
forceEmbedLayout: (value) => trueParam("embed", value),
hideDevTools: (value) => trueParam("hidedevtools", value),
hideExplorer: (value) => trueParam("hideExplorer", value),
hideNavigation: (value) => trueParam("hideNavigation", value),
openFile: (value) => stringParams("file", value),
showSidebar: (value) => booleanParam("showSidebar", value),
sidebarView: (value) => enumParam("sidebarView", value, UI_SIDEBAR_VIEWS),
startScript: (value) => stringParams("startScript", value),
terminalHeight: (value) => percentParam("terminalHeight", value),
theme: (value) => enumParam("theme", value, UI_THEMES),
view: (value) => enumParam("view", value, UI_VIEWS),
zenMode: (value) => trueParam("zenMode", value)
};
function buildParams(options = {}) {
const params = Object.entries(options).map(([key, value]) => {
if (value != null && generators.hasOwnProperty(key)) {
return generators[key](value);
}
return "";
}).filter(Boolean);
return params.length ? `?${params.join("&")}` : "";
}
function trueParam(name, value) {
if (value === true) {
return `${name}=1`;
}
return "";
}
function booleanParam(name, value) {
if (typeof value === "boolean") {
return `${name}=${value ? "1" : "0"}`;
}
return "";
}
function percentParam(name, value) {
if (typeof value === "number" && !Number.isNaN(value)) {
const clamped = Math.min(100, Math.max(0, value));
return `${name}=${encodeURIComponent(Math.round(clamped))}`;
}
return "";
}
function enumParam(name, value = "", allowList = []) {
if (allowList.includes(value)) {
return `${name}=${encodeURIComponent(value)}`;
}
return "";
}
function stringParams(name, value) {
const values = Array.isArray(value) ? value : [value];
return values.filter((val) => typeof val === "string" && val.trim() !== "").map((val) => `${name}=${encodeURIComponent(val)}`).join("&");
}
function genID() {
return Math.random().toString(36).slice(2, 6) + Math.random().toString(36).slice(2, 6);
}
function openUrl(route, options) {
return `${getOrigin(options)}${route}${buildParams(options)}`;
}
function embedUrl(route, options) {
const config = {
forceEmbedLayout: true
};
if (options && typeof options === "object") {
Object.assign(config, options);
}
return `${getOrigin(config)}${route}${buildParams(config)}`;
}
function getOrigin(options = {}) {
const origin = typeof options.origin === "string" ? options.origin : DEFAULT_ORIGIN;
return origin.replace(/\/$/, "");
}
function replaceAndEmbed(target, frame, options) {
if (!frame || !target || !target.parentNode) {
throw new Error("Invalid Element");
}
if (target.id) {
frame.id = target.id;
}
if (target.className) {
frame.className = target.className;
}
setFrameDimensions(frame, options);
target.replaceWith(frame);
}
function findElement(elementOrId) {
if (typeof elementOrId === "string") {
const element = document.getElementById(elementOrId);
if (!element) {
throw new Error(`Could not find element with id '${elementOrId}'`);
}
return element;
} else if (elementOrId instanceof HTMLElement) {
return elementOrId;
}
throw new Error(`Invalid element: ${elementOrId}`);
}
function openTarget(options) {
return options && options.newWindow === false ? "_self" : "_blank";
}
function setFrameDimensions(frame, options = {}) {
const height = Object.hasOwnProperty.call(options, "height") ? `${options.height}` : `${DEFAULT_FRAME_HEIGHT}`;
const width = Object.hasOwnProperty.call(options, "width") ? `${options.width}` : void 0;
frame.setAttribute("height", height);
if (width) {
frame.setAttribute("width", width);
} else {
frame.setAttribute("style", "width:100%;");
}
}
class RDC {
constructor(port) {
this.pending = {};
this.port = port;
this.port.onmessage = this.messageListener.bind(this);
}
request({ type, payload }) {
return new Promise((resolve, reject) => {
const id = genID();
this.pending[id] = { resolve, reject };
this.port.postMessage({
type,
payload: {
...payload,
// Ensure the payload object includes the request ID
__reqid: id
}
});
});
}
messageListener(event) {
if (typeof event.data.payload?.__reqid !== "string") {
return;
}
const { type, payload } = event.data;
const { __reqid: id, __success: success, __error: error } = payload;
if (this.pending[id]) {
if (success) {
this.pending[id].resolve(this.cleanResult(payload));
} else {
this.pending[id].reject(error ? `${type}: ${error}` : type);
}
delete this.pending[id];
}
}
cleanResult(payload) {
const result = { ...payload };
delete result.__reqid;
delete result.__success;
delete result.__error;
return Object.keys(result).length ? result : null;
}
}
class VM {
constructor(port, config) {
this.editor = {
/**
* Open one of several files in tabs and/or split panes.
*
* @since 1.7.0 Added support for opening multiple files
*/
openFile: (path) => {
return this._rdc.request({
type: "SDK_OPEN_FILE",
payload: { path }
});
},
/**
* Set a project file as the currently selected file.
*
* - This may update the highlighted file in the file explorer,
* and the currently open and/or focused editor tab.
* - It will _not_ open a new editor tab if the provided path does not
* match a currently open tab. See `vm.editor.openFile` to open files.
*
* @since 1.7.0
* @experimental
*/
setCurrentFile: (path) => {
return this._rdc.request({
type: "SDK_SET_CURRENT_FILE",
payload: { path }
});
},
/**
* Change the color theme
*
* @since 1.7.0
*/
setTheme: (theme) => {
return this._rdc.request({
type: "SDK_SET_UI_THEME",
payload: { theme }
});
},
/**
* Change the display mode of the project:
*
* - `default`: show the editor and preview pane
* - `editor`: show the editor pane only
* - `preview`: show the preview pane only
*
* @since 1.7.0
*/
setView: (view) => {
return this._rdc.request({
type: "SDK_SET_UI_VIEW",
payload: { view }
});
},
/**
* Change the display mode of the sidebar:
*
* - `true`: show the sidebar
* - `false`: hide the sidebar
*
* @since 1.7.0
*/
showSidebar: (visible = true) => {
return this._rdc.request({
type: "SDK_TOGGLE_SIDEBAR",
payload: { visible }
});
}
};
this.preview = {
/**
* The origin (protocol and domain) of the preview iframe.
*
* In WebContainers-based projects, the origin will always be `null`;
* try using `vm.preview.getUrl` instead.
*
* @see https://developer.stackblitz.com/guides/user-guide/available-environments
*/
origin: "",
/**
* Get the current preview URL.
*
* In both and EngineBlock and WebContainers-based projects, the preview URL
* may not reflect the exact path of the current page, after user navigation.
*
* In WebContainers-based projects, the preview URL will be `null` initially,
* and until the project starts a web server.
*
* @since 1.7.0
* @experimental
*/
getUrl: () => {
return this._rdc.request({
type: "SDK_GET_PREVIEW_URL",
payload: {}
}).then((data) => data?.url ?? null);
},
/**
* Change the path of the preview URL.
*
* In WebContainers-based projects, this will be ignored if there is no
* currently running web server.
*
* @since 1.7.0
* @experimental
*/
setUrl: (path = "/") => {
if (typeof path !== "string" || !path.startsWith("/")) {
throw new Error(`Invalid argument: expected a path starting with '/', got '${path}'`);
}
return this._rdc.request({
type: "SDK_SET_PREVIEW_URL",
payload: { path }
});
}
};
this._rdc = new RDC(port);
Object.defineProperty(this.preview, "origin", {
value: typeof config.previewOrigin === "string" ? config.previewOrigin : null,
writable: false
});
}
/**
* Apply batch updates to the project files in one call.
*/
applyFsDiff(diff) {
const isObject = (val) => val !== null && typeof val === "object";
if (!isObject(diff) || !isObject(diff.create)) {
throw new Error("Invalid diff object: expected diff.create to be an object.");
} else if (!Array.isArray(diff.destroy)) {
throw new Error("Invalid diff object: expected diff.destroy to be an array.");
}
return this._rdc.request({
type: "SDK_APPLY_FS_DIFF",
payload: diff
});
}
/**
* Get the project’s defined dependencies.
*
* In EngineBlock projects, version numbers represent the resolved dependency versions.
* In WebContainers-based projects, returns data from the project’s `package.json` without resolving installed version numbers.
*/
getDependencies() {
return this._rdc.request({
type: "SDK_GET_DEPS_SNAPSHOT",
payload: {}
});
}
/**
* Get a snapshot of the project files and their content.
*/
getFsSnapshot() {
return this._rdc.request({
type: "SDK_GET_FS_SNAPSHOT",
payload: {}
});
}
}
const connections = [];
class Connection {
constructor(element) {
this.id = genID();
this.element = element;
this.pending = new Promise((resolve, reject) => {
const listenForSuccess = ({ data, ports }) => {
if (data?.action === "SDK_INIT_SUCCESS" && data.id === this.id) {
this.vm = new VM(ports[0], data.payload);
resolve(this.vm);
cleanup();
}
};
const pingFrame = () => {
this.element.contentWindow?.postMessage(
{
action: "SDK_INIT",
id: this.id
},
"*"
);
};
function cleanup() {
window.clearInterval(interval);
window.removeEventListener("message", listenForSuccess);
}
window.addEventListener("message", listenForSuccess);
pingFrame();
let attempts = 0;
const interval = window.setInterval(() => {
if (this.vm) {
cleanup();
return;
}
if (attempts >= CONNECT_MAX_ATTEMPTS) {
cleanup();
reject("Timeout: Unable to establish a connection with the StackBlitz VM");
connections.forEach((connection, index) => {
if (connection.id === this.id) {
connections.splice(index, 1);
}
});
return;
}
attempts++;
pingFrame();
}, CONNECT_INTERVAL);
});
connections.push(this);
}
}
const getConnection = (identifier) => {
const key = identifier instanceof Element ? "element" : "id";
return connections.find((c) => c[key] === identifier) ?? null;
};
function createHiddenInput(name, value) {
const input = document.createElement("input");
input.type = "hidden";
input.name = name;
input.value = value;
return input;
}
function encodeFilePath(path) {
return path.replace(/\[/g, "%5B").replace(/\]/g, "%5D");
}
function createProjectForm({
template,
title,
description,
dependencies,
files,
settings
}) {
if (!PROJECT_TEMPLATES.includes(template)) {
const names = PROJECT_TEMPLATES.map((t) => `'${t}'`).join(", ");
console.warn(`Unsupported project.template: must be one of ${names}`);
}
const inputs = [];
const addInput = (name, value, defaultValue = "") => {
inputs.push(createHiddenInput(name, typeof value === "string" ? value : defaultValue));
};
addInput("project[title]", title);
if (typeof description === "string" && description.length > 0) {
addInput("project[description]", description);
}
addInput("project[template]", template, "javascript");
if (dependencies) {
if (template === "node") {
console.warn(
`Invalid project.dependencies: dependencies must be provided as a 'package.json' file when using the 'node' template.`
);
} else {
addInput("project[dependencies]", JSON.stringify(dependencies));
}
}
if (settings) {
addInput("project[settings]", JSON.stringify(settings));
}
Object.entries(files).forEach(([path, contents]) => {
addInput(`project[files][${encodeFilePath(path)}]`, contents);
});
const form = document.createElement("form");
form.method = "POST";
form.setAttribute("style", "display:none!important;");
form.append(...inputs);
return form;
}
function createProjectFrameHTML(project, options) {
const form = createProjectForm(project);
form.action = embedUrl("/run", options);
form.id = "sb_run";
const html = `<!doctype html>
<html>
<head><title></title></head>
<body>
${form.outerHTML}
<script>document.getElementById('${form.id}').submit();<\/script>
</body>
</html>`;
return html;
}
function openNewProject(project, options) {
const form = createProjectForm(project);
form.action = openUrl("/run", options);
form.target = openTarget(options);
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
}
function connect(frameEl) {
if (!frameEl?.contentWindow) {
return Promise.reject("Provided element is not an iframe.");
}
const connection = getConnection(frameEl) ?? new Connection(frameEl);
return connection.pending;
}
function openProject(project, options) {
openNewProject(project, options);
}
function openProjectId(projectId, options) {
const url = openUrl(`/edit/${projectId}`, options);
const target = openTarget(options);
window.open(url, target);
}
function openGithubProject(repoSlug, options) {
const url = openUrl(`/github/${repoSlug}`, options);
const target = openTarget(options);
window.open(url, target);
}
function embedProject(elementOrId, project, options) {
const element = findElement(elementOrId);
const html = createProjectFrameHTML(project, options);
const frame = document.createElement("iframe");
replaceAndEmbed(element, frame, options);
frame.contentDocument?.write(html);
return connect(frame);
}
function embedProjectId(elementOrId, projectId, options) {
const element = findElement(elementOrId);
const frame = document.createElement("iframe");
frame.src = embedUrl(`/edit/${projectId}`, options);
replaceAndEmbed(element, frame, options);
return connect(frame);
}
function embedGithubProject(elementOrId, repoSlug, options) {
const element = findElement(elementOrId);
const frame = document.createElement("iframe");
frame.src = embedUrl(`/github/${repoSlug}`, options);
replaceAndEmbed(element, frame, options);
return connect(frame);
}
const StackBlitzSDK = {
connect,
embedGithubProject,
embedProject,
embedProjectId,
openGithubProject,
openProject,
openProjectId
};
export {
StackBlitzSDK as default
};
var e=["angular-cli","create-react-app","html","javascript","node","polymer","typescript","vue"],t={clickToLoad:function(e){return r("ctl",e)},devToolsHeight:function(e){return i("devtoolsheight",e)},forceEmbedLayout:function(e){return r("embed",e)},hideDevTools:function(e){return r("hidedevtools",e)},hideExplorer:function(e){return r("hideExplorer",e)},hideNavigation:function(e){return r("hideNavigation",e)},showSidebar:function(e){return function(e,t){return"boolean"==typeof t?"showSidebar="+(t?"1":"0"):""}(0,e)},openFile:function(e){return function(e,t){return(Array.isArray(t)?t:[t]).filter(function(e){return"string"==typeof e&&""!==e.trim()}).map(function(e){return"file="+encodeURIComponent(e.trim())})}(0,e).join("&")},terminalHeight:function(e){return i("terminalHeight",e)},theme:function(e){return o("theme",["light","dark"],e)},view:function(e){return o("view",["preview","editor"],e)}};function n(e){void 0===e&&(e={});var n=Object.entries(e).map(function(e){var n=e[0],r=e[1];return null!=r&&t.hasOwnProperty(n)?t[n](r):""}).filter(Boolean);return n.length?"?"+n.join("&"):""}function r(e,t){return!0===t?e+"=1":""}function i(e,t){return"number"==typeof t&&t>=0&&t<=100?e+"="+Math.round(t):""}function o(e,t,n){return"string"==typeof n&&t.includes(n)?e+"="+n:""}function a(){return Math.random().toString(36).slice(2,6)+Math.random().toString(36).slice(2,6)}function d(e,t){return""+u(t)+e+n(t)}function c(e,t){var r={forceEmbedLayout:!0};return t&&"object"==typeof t&&Object.assign(r,t),""+u(r)+e+n(r)}function u(e){return void 0===e&&(e={}),"string"==typeof e.origin?e.origin:"https://stackblitz.com"}function s(e,t,n){if(!t||!e||!e.parentNode)throw new Error("Invalid Element");e.id&&(t.id=e.id),e.className&&(t.className=e.className),function(e,t){t&&"object"==typeof t&&(Object.hasOwnProperty.call(t,"height")&&(e.height=""+t.height),Object.hasOwnProperty.call(t,"width")&&(e.width=""+t.width)),e.height||(e.height="300"),e.width||e.setAttribute("style","width:100%;")}(t,n),e.parentNode.replaceChild(t,e)}function l(e){if("string"==typeof e){var t=document.getElementById(e);if(!t)throw new Error("Could not find element with id '"+e+"'");return t}if(e instanceof HTMLElement)return e;throw new Error("Invalid element: "+e)}function p(e){return e&&!1===e.newWindow?"_self":"_blank"}function f(){return f=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},f.apply(this,arguments)}var h=/*#__PURE__*/function(){function e(e){this.port=void 0,this.pending={},this.port=e,this.port.onmessage=this.messageListener.bind(this)}var t=e.prototype;return t.request=function(e){var t=this,n=e.type,r=e.payload,i=a();return new Promise(function(e,o){t.pending[i]={resolve:e,reject:o},t.port.postMessage({type:n,payload:f({},r,{__reqid:i})})})},t.messageListener=function(e){var t;if("string"==typeof(null==(t=e.data.payload)?void 0:t.__reqid)){var n=e.data,r=n.type,i=n.payload,o=i.__reqid,a=i.__error;this.pending[o]&&(i.__success?this.pending[o].resolve(function(e){var t=f({},e);return delete t.__reqid,delete t.__success,delete t.__error,Object.keys(t).length?t:null}(i)):this.pending[o].reject(a?r+": "+a:r),delete this.pending[o])}},e}(),m=/*#__PURE__*/function(){function e(e,t){var n=this;this._rdc=void 0,this.editor={openFile:function(e){return n._rdc.request({type:"SDK_OPEN_FILE",payload:{path:e}})},setCurrentFile:function(e){return n._rdc.request({type:"SDK_SET_CURRENT_FILE",payload:{path:e}})},setTheme:function(e){return n._rdc.request({type:"SDK_SET_UI_THEME",payload:{theme:e}})},setView:function(e){return n._rdc.request({type:"SDK_SET_UI_VIEW",payload:{view:e}})},showSidebar:function(e){return void 0===e&&(e=!0),n._rdc.request({type:"SDK_TOGGLE_SIDEBAR",payload:{visible:e}})}},this.preview={origin:"",getUrl:function(){return n._rdc.request({type:"SDK_GET_PREVIEW_URL",payload:{}}).then(function(e){var t;return null!=(t=null==e?void 0:e.url)?t:null})},setUrl:function(e){if(void 0===e&&(e="/"),"string"!=typeof e||!e.startsWith("/"))throw new Error("Invalid argument: expected a path starting with '/', got '"+e+"'");return n._rdc.request({type:"SDK_SET_PREVIEW_URL",payload:{path:e}})}},this._rdc=new h(e),Object.defineProperty(this.preview,"origin",{value:"string"==typeof t.previewOrigin?t.previewOrigin:null,writable:!1})}var t=e.prototype;return t.applyFsDiff=function(e){var t=function(e){return null!==e&&"object"==typeof e};if(!t(e)||!t(e.create))throw new Error("Invalid diff object: expected diff.create to be an object.");if(!Array.isArray(e.destroy))throw new Error("Invalid diff object: expected diff.create to be an array.");return this._rdc.request({type:"SDK_APPLY_FS_DIFF",payload:e})},t.getDependencies=function(){return this._rdc.request({type:"SDK_GET_DEPS_SNAPSHOT",payload:{}})},t.getFsSnapshot=function(){return this._rdc.request({type:"SDK_GET_FS_SNAPSHOT",payload:{}})},e}(),v=[],y=function(e){var t=this;this.element=void 0,this.id=void 0,this.pending=void 0,this.vm=void 0,this.id=a(),this.element=e,this.pending=new Promise(function(e,n){var r=function(n){var r=n.data;"SDK_INIT_SUCCESS"===(null==r?void 0:r.action)&&r.id===t.id&&(t.vm=new m(n.ports[0],r.payload),e(t.vm),o())},i=function(){var e;null==(e=t.element.contentWindow)||e.postMessage({action:"SDK_INIT",id:t.id},"*")};function o(){window.clearInterval(d),window.removeEventListener("message",r)}window.addEventListener("message",r),i();var a=0,d=window.setInterval(function(){if(t.vm)o();else{if(a>=20)return o(),n("Timeout: Unable to establish a connection with the StackBlitz VM"),void v.forEach(function(e,n){e.id===t.id&&v.splice(n,1)});a++,i()}},500)}),v.push(this)};function g(e,t){var n=document.createElement("input");return n.type="hidden",n.name=e,n.value=t,n}function w(t){if(!e.includes(t.template)){var n=e.map(function(e){return"'"+e+"'"}).join(", ");console.warn("Unsupported project.template: must be one of "+n)}var r="node"===t.template,i=document.createElement("form");return i.method="POST",i.setAttribute("style","display:none!important;"),i.appendChild(g("project[title]",t.title)),i.appendChild(g("project[description]",t.description)),i.appendChild(g("project[template]",t.template)),t.dependencies&&(r?console.warn("Invalid project.dependencies: dependencies must be provided as a 'package.json' file when using the 'node' template."):i.appendChild(g("project[dependencies]",JSON.stringify(t.dependencies)))),t.settings&&i.appendChild(g("project[settings]",JSON.stringify(t.settings))),Object.keys(t.files).forEach(function(e){var n="project[files]"+function(e){return"["+e.replace(/\[/g,"%5B").replace(/\]/g,"%5D")+"]"}(e),r=t.files[e];"string"==typeof r&&i.appendChild(g(n,r))}),i}function _(e){var t,n,r,i;return null!=e&&e.contentWindow?(null!=(i=(n=e)instanceof Element?"element":"id",t=null!=(r=v.find(function(e){return e[i]===n}))?r:null)?t:new y(e)).pending:Promise.reject("Provided element is not an iframe.")}var b={connect:_,embedGithubProject:function(e,t,n){var r=l(e),i=document.createElement("iframe");return i.src=c("/github/"+t,n),s(r,i,n),_(i)},embedProject:function(e,t,n){var r,i=l(e),o=function(e,t){var n=w(e);return n.action=c("/run",t),n.id="sb","<html><head><title></title></head><body>"+n.outerHTML+"<script>document.getElementById('"+n.id+"').submit();<\/script></body></html>"}(t,n),a=document.createElement("iframe");return s(i,a,n),null==(r=a.contentDocument)||r.write(o),_(a)},embedProjectId:function(e,t,n){var r=l(e),i=document.createElement("iframe");return i.src=c("/edit/"+t,n),s(r,i,n),_(i)},openGithubProject:function(e,t){var n=d("/github/"+e,t),r=p(t);window.open(n,r)},openProject:function(e,t){!function(e,t){var n=w(e);n.action=d("/run",t),n.target=p(t),document.body.appendChild(n),n.submit(),document.body.removeChild(n)}(e,t)},openProjectId:function(e,t){var n=d("/edit/"+e,t),r=p(t);window.open(n,r)}};export{b as default};
//# sourceMappingURL=sdk.m.js.map

@@ -1,520 +0,2 @@

(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, global.StackBlitzSDK = factory());
})(this, function() {
"use strict";
const CONNECT_INTERVAL = 500;
const CONNECT_MAX_ATTEMPTS = 20;
const DEFAULT_FRAME_HEIGHT = 300;
const DEFAULT_ORIGIN = "https://stackblitz.com";
const PROJECT_TEMPLATES = [
"angular-cli",
"create-react-app",
"html",
"javascript",
"node",
"polymer",
"typescript",
"vue"
];
const UI_SIDEBAR_VIEWS = ["project", "search", "ports", "settings"];
const UI_THEMES = ["light", "dark"];
const UI_VIEWS = ["editor", "preview"];
const generators = {
clickToLoad: (value) => trueParam("ctl", value),
devToolsHeight: (value) => percentParam("devtoolsheight", value),
forceEmbedLayout: (value) => trueParam("embed", value),
hideDevTools: (value) => trueParam("hidedevtools", value),
hideExplorer: (value) => trueParam("hideExplorer", value),
hideNavigation: (value) => trueParam("hideNavigation", value),
openFile: (value) => stringParams("file", value),
showSidebar: (value) => booleanParam("showSidebar", value),
sidebarView: (value) => enumParam("sidebarView", value, UI_SIDEBAR_VIEWS),
startScript: (value) => stringParams("startScript", value),
terminalHeight: (value) => percentParam("terminalHeight", value),
theme: (value) => enumParam("theme", value, UI_THEMES),
view: (value) => enumParam("view", value, UI_VIEWS),
zenMode: (value) => trueParam("zenMode", value)
};
function buildParams(options = {}) {
const params = Object.entries(options).map(([key, value]) => {
if (value != null && generators.hasOwnProperty(key)) {
return generators[key](value);
}
return "";
}).filter(Boolean);
return params.length ? `?${params.join("&")}` : "";
}
function trueParam(name, value) {
if (value === true) {
return `${name}=1`;
}
return "";
}
function booleanParam(name, value) {
if (typeof value === "boolean") {
return `${name}=${value ? "1" : "0"}`;
}
return "";
}
function percentParam(name, value) {
if (typeof value === "number" && !Number.isNaN(value)) {
const clamped = Math.min(100, Math.max(0, value));
return `${name}=${encodeURIComponent(Math.round(clamped))}`;
}
return "";
}
function enumParam(name, value = "", allowList = []) {
if (allowList.includes(value)) {
return `${name}=${encodeURIComponent(value)}`;
}
return "";
}
function stringParams(name, value) {
const values = Array.isArray(value) ? value : [value];
return values.filter((val) => typeof val === "string" && val.trim() !== "").map((val) => `${name}=${encodeURIComponent(val)}`).join("&");
}
function genID() {
return Math.random().toString(36).slice(2, 6) + Math.random().toString(36).slice(2, 6);
}
function openUrl(route, options) {
return `${getOrigin(options)}${route}${buildParams(options)}`;
}
function embedUrl(route, options) {
const config = {
forceEmbedLayout: true
};
if (options && typeof options === "object") {
Object.assign(config, options);
}
return `${getOrigin(config)}${route}${buildParams(config)}`;
}
function getOrigin(options = {}) {
const origin = typeof options.origin === "string" ? options.origin : DEFAULT_ORIGIN;
return origin.replace(/\/$/, "");
}
function replaceAndEmbed(target, frame, options) {
if (!frame || !target || !target.parentNode) {
throw new Error("Invalid Element");
}
if (target.id) {
frame.id = target.id;
}
if (target.className) {
frame.className = target.className;
}
setFrameDimensions(frame, options);
target.replaceWith(frame);
}
function findElement(elementOrId) {
if (typeof elementOrId === "string") {
const element = document.getElementById(elementOrId);
if (!element) {
throw new Error(`Could not find element with id '${elementOrId}'`);
}
return element;
} else if (elementOrId instanceof HTMLElement) {
return elementOrId;
}
throw new Error(`Invalid element: ${elementOrId}`);
}
function openTarget(options) {
return options && options.newWindow === false ? "_self" : "_blank";
}
function setFrameDimensions(frame, options = {}) {
const height = Object.hasOwnProperty.call(options, "height") ? `${options.height}` : `${DEFAULT_FRAME_HEIGHT}`;
const width = Object.hasOwnProperty.call(options, "width") ? `${options.width}` : void 0;
frame.setAttribute("height", height);
if (width) {
frame.setAttribute("width", width);
} else {
frame.setAttribute("style", "width:100%;");
}
}
class RDC {
constructor(port) {
this.pending = {};
this.port = port;
this.port.onmessage = this.messageListener.bind(this);
}
request({ type, payload }) {
return new Promise((resolve, reject) => {
const id = genID();
this.pending[id] = { resolve, reject };
this.port.postMessage({
type,
payload: {
...payload,
// Ensure the payload object includes the request ID
__reqid: id
}
});
});
}
messageListener(event) {
if (typeof event.data.payload?.__reqid !== "string") {
return;
}
const { type, payload } = event.data;
const { __reqid: id, __success: success, __error: error } = payload;
if (this.pending[id]) {
if (success) {
this.pending[id].resolve(this.cleanResult(payload));
} else {
this.pending[id].reject(error ? `${type}: ${error}` : type);
}
delete this.pending[id];
}
}
cleanResult(payload) {
const result = { ...payload };
delete result.__reqid;
delete result.__success;
delete result.__error;
return Object.keys(result).length ? result : null;
}
}
class VM {
constructor(port, config) {
this.editor = {
/**
* Open one of several files in tabs and/or split panes.
*
* @since 1.7.0 Added support for opening multiple files
*/
openFile: (path) => {
return this._rdc.request({
type: "SDK_OPEN_FILE",
payload: { path }
});
},
/**
* Set a project file as the currently selected file.
*
* - This may update the highlighted file in the file explorer,
* and the currently open and/or focused editor tab.
* - It will _not_ open a new editor tab if the provided path does not
* match a currently open tab. See `vm.editor.openFile` to open files.
*
* @since 1.7.0
* @experimental
*/
setCurrentFile: (path) => {
return this._rdc.request({
type: "SDK_SET_CURRENT_FILE",
payload: { path }
});
},
/**
* Change the color theme
*
* @since 1.7.0
*/
setTheme: (theme) => {
return this._rdc.request({
type: "SDK_SET_UI_THEME",
payload: { theme }
});
},
/**
* Change the display mode of the project:
*
* - `default`: show the editor and preview pane
* - `editor`: show the editor pane only
* - `preview`: show the preview pane only
*
* @since 1.7.0
*/
setView: (view) => {
return this._rdc.request({
type: "SDK_SET_UI_VIEW",
payload: { view }
});
},
/**
* Change the display mode of the sidebar:
*
* - `true`: show the sidebar
* - `false`: hide the sidebar
*
* @since 1.7.0
*/
showSidebar: (visible = true) => {
return this._rdc.request({
type: "SDK_TOGGLE_SIDEBAR",
payload: { visible }
});
}
};
this.preview = {
/**
* The origin (protocol and domain) of the preview iframe.
*
* In WebContainers-based projects, the origin will always be `null`;
* try using `vm.preview.getUrl` instead.
*
* @see https://developer.stackblitz.com/guides/user-guide/available-environments
*/
origin: "",
/**
* Get the current preview URL.
*
* In both and EngineBlock and WebContainers-based projects, the preview URL
* may not reflect the exact path of the current page, after user navigation.
*
* In WebContainers-based projects, the preview URL will be `null` initially,
* and until the project starts a web server.
*
* @since 1.7.0
* @experimental
*/
getUrl: () => {
return this._rdc.request({
type: "SDK_GET_PREVIEW_URL",
payload: {}
}).then((data) => data?.url ?? null);
},
/**
* Change the path of the preview URL.
*
* In WebContainers-based projects, this will be ignored if there is no
* currently running web server.
*
* @since 1.7.0
* @experimental
*/
setUrl: (path = "/") => {
if (typeof path !== "string" || !path.startsWith("/")) {
throw new Error(`Invalid argument: expected a path starting with '/', got '${path}'`);
}
return this._rdc.request({
type: "SDK_SET_PREVIEW_URL",
payload: { path }
});
}
};
this._rdc = new RDC(port);
Object.defineProperty(this.preview, "origin", {
value: typeof config.previewOrigin === "string" ? config.previewOrigin : null,
writable: false
});
}
/**
* Apply batch updates to the project files in one call.
*/
applyFsDiff(diff) {
const isObject = (val) => val !== null && typeof val === "object";
if (!isObject(diff) || !isObject(diff.create)) {
throw new Error("Invalid diff object: expected diff.create to be an object.");
} else if (!Array.isArray(diff.destroy)) {
throw new Error("Invalid diff object: expected diff.destroy to be an array.");
}
return this._rdc.request({
type: "SDK_APPLY_FS_DIFF",
payload: diff
});
}
/**
* Get the project’s defined dependencies.
*
* In EngineBlock projects, version numbers represent the resolved dependency versions.
* In WebContainers-based projects, returns data from the project’s `package.json` without resolving installed version numbers.
*/
getDependencies() {
return this._rdc.request({
type: "SDK_GET_DEPS_SNAPSHOT",
payload: {}
});
}
/**
* Get a snapshot of the project files and their content.
*/
getFsSnapshot() {
return this._rdc.request({
type: "SDK_GET_FS_SNAPSHOT",
payload: {}
});
}
}
const connections = [];
class Connection {
constructor(element) {
this.id = genID();
this.element = element;
this.pending = new Promise((resolve, reject) => {
const listenForSuccess = ({ data, ports }) => {
if (data?.action === "SDK_INIT_SUCCESS" && data.id === this.id) {
this.vm = new VM(ports[0], data.payload);
resolve(this.vm);
cleanup();
}
};
const pingFrame = () => {
this.element.contentWindow?.postMessage(
{
action: "SDK_INIT",
id: this.id
},
"*"
);
};
function cleanup() {
window.clearInterval(interval);
window.removeEventListener("message", listenForSuccess);
}
window.addEventListener("message", listenForSuccess);
pingFrame();
let attempts = 0;
const interval = window.setInterval(() => {
if (this.vm) {
cleanup();
return;
}
if (attempts >= CONNECT_MAX_ATTEMPTS) {
cleanup();
reject("Timeout: Unable to establish a connection with the StackBlitz VM");
connections.forEach((connection, index) => {
if (connection.id === this.id) {
connections.splice(index, 1);
}
});
return;
}
attempts++;
pingFrame();
}, CONNECT_INTERVAL);
});
connections.push(this);
}
}
const getConnection = (identifier) => {
const key = identifier instanceof Element ? "element" : "id";
return connections.find((c) => c[key] === identifier) ?? null;
};
function createHiddenInput(name, value) {
const input = document.createElement("input");
input.type = "hidden";
input.name = name;
input.value = value;
return input;
}
function encodeFilePath(path) {
return path.replace(/\[/g, "%5B").replace(/\]/g, "%5D");
}
function createProjectForm({
template,
title,
description,
dependencies,
files,
settings
}) {
if (!PROJECT_TEMPLATES.includes(template)) {
const names = PROJECT_TEMPLATES.map((t) => `'${t}'`).join(", ");
console.warn(`Unsupported project.template: must be one of ${names}`);
}
const inputs = [];
const addInput = (name, value, defaultValue = "") => {
inputs.push(createHiddenInput(name, typeof value === "string" ? value : defaultValue));
};
addInput("project[title]", title);
if (typeof description === "string" && description.length > 0) {
addInput("project[description]", description);
}
addInput("project[template]", template, "javascript");
if (dependencies) {
if (template === "node") {
console.warn(
`Invalid project.dependencies: dependencies must be provided as a 'package.json' file when using the 'node' template.`
);
} else {
addInput("project[dependencies]", JSON.stringify(dependencies));
}
}
if (settings) {
addInput("project[settings]", JSON.stringify(settings));
}
Object.entries(files).forEach(([path, contents]) => {
addInput(`project[files][${encodeFilePath(path)}]`, contents);
});
const form = document.createElement("form");
form.method = "POST";
form.setAttribute("style", "display:none!important;");
form.append(...inputs);
return form;
}
function createProjectFrameHTML(project, options) {
const form = createProjectForm(project);
form.action = embedUrl("/run", options);
form.id = "sb_run";
const html = `<!doctype html>
<html>
<head><title></title></head>
<body>
${form.outerHTML}
<script>document.getElementById('${form.id}').submit();<\/script>
</body>
</html>`;
return html;
}
function openNewProject(project, options) {
const form = createProjectForm(project);
form.action = openUrl("/run", options);
form.target = openTarget(options);
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
}
function connect(frameEl) {
if (!frameEl?.contentWindow) {
return Promise.reject("Provided element is not an iframe.");
}
const connection = getConnection(frameEl) ?? new Connection(frameEl);
return connection.pending;
}
function openProject(project, options) {
openNewProject(project, options);
}
function openProjectId(projectId, options) {
const url = openUrl(`/edit/${projectId}`, options);
const target = openTarget(options);
window.open(url, target);
}
function openGithubProject(repoSlug, options) {
const url = openUrl(`/github/${repoSlug}`, options);
const target = openTarget(options);
window.open(url, target);
}
function embedProject(elementOrId, project, options) {
const element = findElement(elementOrId);
const html = createProjectFrameHTML(project, options);
const frame = document.createElement("iframe");
replaceAndEmbed(element, frame, options);
frame.contentDocument?.write(html);
return connect(frame);
}
function embedProjectId(elementOrId, projectId, options) {
const element = findElement(elementOrId);
const frame = document.createElement("iframe");
frame.src = embedUrl(`/edit/${projectId}`, options);
replaceAndEmbed(element, frame, options);
return connect(frame);
}
function embedGithubProject(elementOrId, repoSlug, options) {
const element = findElement(elementOrId);
const frame = document.createElement("iframe");
frame.src = embedUrl(`/github/${repoSlug}`, options);
replaceAndEmbed(element, frame, options);
return connect(frame);
}
const StackBlitzSDK = {
connect,
embedGithubProject,
embedProject,
embedProjectId,
openGithubProject,
openProject,
openProjectId
};
return StackBlitzSDK;
});
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e||self).StackBlitzSDK=t()}(this,function(){var e=["angular-cli","create-react-app","html","javascript","node","polymer","typescript","vue"],t={clickToLoad:function(e){return r("ctl",e)},devToolsHeight:function(e){return i("devtoolsheight",e)},forceEmbedLayout:function(e){return r("embed",e)},hideDevTools:function(e){return r("hidedevtools",e)},hideExplorer:function(e){return r("hideExplorer",e)},hideNavigation:function(e){return r("hideNavigation",e)},showSidebar:function(e){return function(e,t){return"boolean"==typeof t?"showSidebar="+(t?"1":"0"):""}(0,e)},openFile:function(e){return function(e,t){return(Array.isArray(t)?t:[t]).filter(function(e){return"string"==typeof e&&""!==e.trim()}).map(function(e){return"file="+encodeURIComponent(e.trim())})}(0,e).join("&")},terminalHeight:function(e){return i("terminalHeight",e)},theme:function(e){return o("theme",["light","dark"],e)},view:function(e){return o("view",["preview","editor"],e)}};function n(e){void 0===e&&(e={});var n=Object.entries(e).map(function(e){var n=e[0],r=e[1];return null!=r&&t.hasOwnProperty(n)?t[n](r):""}).filter(Boolean);return n.length?"?"+n.join("&"):""}function r(e,t){return!0===t?e+"=1":""}function i(e,t){return"number"==typeof t&&t>=0&&t<=100?e+"="+Math.round(t):""}function o(e,t,n){return"string"==typeof n&&t.includes(n)?e+"="+n:""}function a(){return Math.random().toString(36).slice(2,6)+Math.random().toString(36).slice(2,6)}function d(e,t){return""+c(t)+e+n(t)}function u(e,t){var r={forceEmbedLayout:!0};return t&&"object"==typeof t&&Object.assign(r,t),""+c(r)+e+n(r)}function c(e){return void 0===e&&(e={}),"string"==typeof e.origin?e.origin:"https://stackblitz.com"}function s(e,t,n){if(!t||!e||!e.parentNode)throw new Error("Invalid Element");e.id&&(t.id=e.id),e.className&&(t.className=e.className),function(e,t){t&&"object"==typeof t&&(Object.hasOwnProperty.call(t,"height")&&(e.height=""+t.height),Object.hasOwnProperty.call(t,"width")&&(e.width=""+t.width)),e.height||(e.height="300"),e.width||e.setAttribute("style","width:100%;")}(t,n),e.parentNode.replaceChild(t,e)}function l(e){if("string"==typeof e){var t=document.getElementById(e);if(!t)throw new Error("Could not find element with id '"+e+"'");return t}if(e instanceof HTMLElement)return e;throw new Error("Invalid element: "+e)}function p(e){return e&&!1===e.newWindow?"_self":"_blank"}function f(){return f=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},f.apply(this,arguments)}var h=/*#__PURE__*/function(){function e(e){this.port=void 0,this.pending={},this.port=e,this.port.onmessage=this.messageListener.bind(this)}var t=e.prototype;return t.request=function(e){var t=this,n=e.type,r=e.payload,i=a();return new Promise(function(e,o){t.pending[i]={resolve:e,reject:o},t.port.postMessage({type:n,payload:f({},r,{__reqid:i})})})},t.messageListener=function(e){var t;if("string"==typeof(null==(t=e.data.payload)?void 0:t.__reqid)){var n=e.data,r=n.type,i=n.payload,o=i.__reqid,a=i.__error;this.pending[o]&&(i.__success?this.pending[o].resolve(function(e){var t=f({},e);return delete t.__reqid,delete t.__success,delete t.__error,Object.keys(t).length?t:null}(i)):this.pending[o].reject(a?r+": "+a:r),delete this.pending[o])}},e}(),m=/*#__PURE__*/function(){function e(e,t){var n=this;this._rdc=void 0,this.editor={openFile:function(e){return n._rdc.request({type:"SDK_OPEN_FILE",payload:{path:e}})},setCurrentFile:function(e){return n._rdc.request({type:"SDK_SET_CURRENT_FILE",payload:{path:e}})},setTheme:function(e){return n._rdc.request({type:"SDK_SET_UI_THEME",payload:{theme:e}})},setView:function(e){return n._rdc.request({type:"SDK_SET_UI_VIEW",payload:{view:e}})},showSidebar:function(e){return void 0===e&&(e=!0),n._rdc.request({type:"SDK_TOGGLE_SIDEBAR",payload:{visible:e}})}},this.preview={origin:"",getUrl:function(){return n._rdc.request({type:"SDK_GET_PREVIEW_URL",payload:{}}).then(function(e){var t;return null!=(t=null==e?void 0:e.url)?t:null})},setUrl:function(e){if(void 0===e&&(e="/"),"string"!=typeof e||!e.startsWith("/"))throw new Error("Invalid argument: expected a path starting with '/', got '"+e+"'");return n._rdc.request({type:"SDK_SET_PREVIEW_URL",payload:{path:e}})}},this._rdc=new h(e),Object.defineProperty(this.preview,"origin",{value:"string"==typeof t.previewOrigin?t.previewOrigin:null,writable:!1})}var t=e.prototype;return t.applyFsDiff=function(e){var t=function(e){return null!==e&&"object"==typeof e};if(!t(e)||!t(e.create))throw new Error("Invalid diff object: expected diff.create to be an object.");if(!Array.isArray(e.destroy))throw new Error("Invalid diff object: expected diff.create to be an array.");return this._rdc.request({type:"SDK_APPLY_FS_DIFF",payload:e})},t.getDependencies=function(){return this._rdc.request({type:"SDK_GET_DEPS_SNAPSHOT",payload:{}})},t.getFsSnapshot=function(){return this._rdc.request({type:"SDK_GET_FS_SNAPSHOT",payload:{}})},e}(),v=[],y=function(e){var t=this;this.element=void 0,this.id=void 0,this.pending=void 0,this.vm=void 0,this.id=a(),this.element=e,this.pending=new Promise(function(e,n){var r=function(n){var r=n.data;"SDK_INIT_SUCCESS"===(null==r?void 0:r.action)&&r.id===t.id&&(t.vm=new m(n.ports[0],r.payload),e(t.vm),o())},i=function(){var e;null==(e=t.element.contentWindow)||e.postMessage({action:"SDK_INIT",id:t.id},"*")};function o(){window.clearInterval(d),window.removeEventListener("message",r)}window.addEventListener("message",r),i();var a=0,d=window.setInterval(function(){if(t.vm)o();else{if(a>=20)return o(),n("Timeout: Unable to establish a connection with the StackBlitz VM"),void v.forEach(function(e,n){e.id===t.id&&v.splice(n,1)});a++,i()}},500)}),v.push(this)};function g(e,t){var n=document.createElement("input");return n.type="hidden",n.name=e,n.value=t,n}function w(t){if(!e.includes(t.template)){var n=e.map(function(e){return"'"+e+"'"}).join(", ");console.warn("Unsupported project.template: must be one of "+n)}var r="node"===t.template,i=document.createElement("form");return i.method="POST",i.setAttribute("style","display:none!important;"),i.appendChild(g("project[title]",t.title)),i.appendChild(g("project[description]",t.description)),i.appendChild(g("project[template]",t.template)),t.dependencies&&(r?console.warn("Invalid project.dependencies: dependencies must be provided as a 'package.json' file when using the 'node' template."):i.appendChild(g("project[dependencies]",JSON.stringify(t.dependencies)))),t.settings&&i.appendChild(g("project[settings]",JSON.stringify(t.settings))),Object.keys(t.files).forEach(function(e){var n="project[files]"+function(e){return"["+e.replace(/\[/g,"%5B").replace(/\]/g,"%5D")+"]"}(e),r=t.files[e];"string"==typeof r&&i.appendChild(g(n,r))}),i}function _(e){var t,n,r,i;return null!=e&&e.contentWindow?(null!=(i=(n=e)instanceof Element?"element":"id",t=null!=(r=v.find(function(e){return e[i]===n}))?r:null)?t:new y(e)).pending:Promise.reject("Provided element is not an iframe.")}return{connect:_,embedGithubProject:function(e,t,n){var r=l(e),i=document.createElement("iframe");return i.src=u("/github/"+t,n),s(r,i,n),_(i)},embedProject:function(e,t,n){var r,i=l(e),o=function(e,t){var n=w(e);return n.action=u("/run",t),n.id="sb","<html><head><title></title></head><body>"+n.outerHTML+"<script>document.getElementById('"+n.id+"').submit();<\/script></body></html>"}(t,n),a=document.createElement("iframe");return s(i,a,n),null==(r=a.contentDocument)||r.write(o),_(a)},embedProjectId:function(e,t,n){var r=l(e),i=document.createElement("iframe");return i.src=u("/edit/"+t,n),s(r,i,n),_(i)},openGithubProject:function(e,t){var n=d("/github/"+e,t),r=p(t);window.open(n,r)},openProject:function(e,t){!function(e,t){var n=w(e);n.action=d("/run",t),n.target=p(t),document.body.appendChild(n),n.submit(),document.body.removeChild(n)}(e,t)},openProjectId:function(e,t){var n=d("/edit/"+e,t),r=p(t);window.open(n,r)}}});
//# sourceMappingURL=sdk.umd.js.map
# @stackblitz/sdk changelog
## v1.9.0 (2023-04-04)
- Moved the StackBlitz SDK to a dedicated repository: https://github.com/stackblitz/sdk.
- Added support for new options: `startScript`, `sidebarView` and `zenMode`. (https://github.com/stackblitz/sdk/pull/4)
- Changed `project.description` to be optional. (https://github.com/stackblitz/sdk/pull/5)
## v1.8.2 (2023-01-26)
- Fixed using the characters `[]` in file paths with the `embedProject` and `openProject` methods. (https://github.com/stackblitz/core/pull/2295)
- Fixed using the characters `[]` in file paths with the `embedProject` and `openProject` methods. (#2295)
## v1.8.1 (2022-11-10)
- Fixed the case of the URL query parameters for the `hideDevTools` and `devToolsHeight` options, for backwards compatibility with StackBlitz EE. (https://github.com/stackblitz/core/pull/2154)
- Fixed the case of the URL query parameters for the `hideDevTools` and `devToolsHeight` options, for backwards compatibility with StackBlitz EE. (#2154)
## v1.8.0 (2022-06-09)
- Added a `terminalHeight` option, used to set a preferred height for the Terminal in WebContainers-based projects. (https://github.com/stackblitz/core/pull/1891)
- Added a `terminalHeight` option, used to set a preferred height for the Terminal in WebContainers-based projects. (#1891)
## v1.7.0 (2022-05-09)
- TypeScript: improved the precision and inline documentation of types such as `Project`, `EmbedOptions`, `OpenOptions` and `VM`. Made those types directly importable with `import type { Project } from '@stackblitz/sdk'`. (https://github.com/stackblitz/core/pull/1775, https://github.com/stackblitz/core/pull/1779, https://github.com/stackblitz/core/pull/1837)
- Added support for opening multiple files in an embedded projects with the `vm.editor.openFile` method. (https://github.com/stackblitz/core/pull/1810)
- Added new methods to the `VM` class for controlling the embedded editor’s UI: `vm.editor.setCurrentFile`, `vm.editor.setTheme`, `vm.editor.setView`, `vm.editor.showSidebar`, `vm.preview.getUrl`, `vm.preview.setUrl`. (https://github.com/stackblitz/core/pull/1810, https://github.com/stackblitz/core/pull/1837)
- Added new `showSidebar` option. (https://github.com/stackblitz/core/pull/1837)
- Added source maps to the published bundle files. (https://github.com/stackblitz/core/pull/1776)
- Fixed the default value of the `forceEmbedLayout` option. (https://github.com/stackblitz/core/pull/1817)
- TypeScript: improved the precision and inline documentation of types such as `Project`, `EmbedOptions`, `OpenOptions` and `VM`. Made those types directly importable with `import type { Project } from '@stackblitz/sdk'`. (#1775, #1779, #1837)
- Added support for opening multiple files in an embedded projects with the `vm.editor.openFile` method. (#1810)
- Added new methods to the `VM` class for controlling the embedded editor’s UI: `vm.editor.setCurrentFile`, `vm.editor.setTheme`, `vm.editor.setView`, `vm.editor.showSidebar`, `vm.preview.getUrl`, `vm.preview.setUrl`. (#1810, #1837)
- Added new `showSidebar` option. (#1837)
- Added source maps to the published bundle files. (#1776)
- Fixed the default value of the `forceEmbedLayout` option. (#1817)
## v1.6.0 (2022-03-02)
- Add support for opening multiple files with the openFile parameter, with support for multiple tabs (`openFile: 'index.html,src/index.js'`) and split editor panes (`openFile: ['index.html', 'src/index.js]`). (https://github.com/stackblitz/core/pull/1758)
- Add support for opening multiple files with the openFile parameter, with support for multiple tabs (`openFile: 'index.html,src/index.js'`) and split editor panes (`openFile: ['index.html', 'src/index.js]`). (#1758)
## v1.5.6 (2022-02-04)
- Add `template: 'html'` to the allowed project templates. (https://github.com/stackblitz/core/pull/1728)
- Add `template: 'html'` to the allowed project templates. (#1728)
## v1.5.5 (2022-01-26)
- Fix broken type declarations in previous v1.5.4. (https://github.com/stackblitz/core/pull/1722)
- Fix broken type declarations in previous v1.5.4. (#1722)
## v1.5.4 (2022-01-20)
- Add `template: 'node'` to the allowed project templates. (https://github.com/stackblitz/core/pull/1714)
- Remove support for the `tags` option when creating new projects. (https://github.com/stackblitz/core/pull/1714)
- Add `template: 'node'` to the allowed project templates. (#1714)
- Remove support for the `tags` option when creating new projects. (#1714)
## v1.5.3 (2021-11-05)
- Fix: correct type for `EmbedOptions['view']`. (https://github.com/stackblitz/core/pull/1655)
- Fix: set the `EmbedOptions`’s `hideNavigation` UI option correctly. (https://github.com/stackblitz/core/pull/1654)
- Fix: correct type for `EmbedOptions['view']`. (#1655)
- Fix: set the `EmbedOptions`’s `hideNavigation` UI option correctly. (#1654)

@@ -58,15 +52,15 @@ ## v1.5.2 (2020-12-07)

- Add `template: 'vue'` to the allowed project templates. (https://github.com/stackblitz/core/pull/1307)
- Add `template: 'vue'` to the allowed project templates. (#1307)
## v1.5.0 (2020-07-16)
- Add a `theme` option to `ProjectOptions` to set the editor’s color theme. (https://github.com/stackblitz/core/pull/1269)
- Add a `theme` option to `ProjectOptions` to set the editor’s color theme. (#1269)
## v1.4.0 (2020-05-13)
- Add `origin` option to `ProjectOptions` to allow embedding projects from StackBlitz Enterprise Edition. (https://github.com/stackblitz/core/pull/1236)
- Add `origin` option to `ProjectOptions` to allow embedding projects from StackBlitz Enterprise Edition. (#1236)
## v1.3.0 (2019-02-06)
- Add `template: 'polymer'` to the allowed project templates. (https://github.com/stackblitz/core/pull/859)
- Add `template: 'polymer'` to the allowed project templates. (#859)

@@ -73,0 +67,0 @@ ## v1.2.0 (2018-05-03)

{
"name": "@stackblitz/sdk",
"version": "1.9.0",
"version": "1.8.2",
"description": "SDK for generating and embedding StackBlitz projects.",
"license": "MIT",
"author": "Eric Simons",
"homepage": "https://github.com/stackblitz/sdk",
"repository": {
"type": "git",
"url": "https://github.com/stackblitz/sdk.git"
},
"main": "./bundles/sdk.js",

@@ -16,6 +9,11 @@ "module": "./bundles/sdk.m.js",

"jsdelivr": "./bundles/sdk.umd.js",
"types": "./types/index.d.ts",
"types": "./typings/index.d.ts",
"scripts": {
"build": "microbundle --entry src/index.ts --name StackBlitzSDK --format esm,cjs,umd",
"clean": "rimraf bundles typings",
"prepack": "npm run clean && npm run build"
},
"files": [
"bundles",
"types",
"typings",
"CHANGELOG.md",

@@ -25,32 +23,9 @@ "LICENSE.md",

],
"scripts": {
"build": "npm run build:clean && npm run build:types && npm run build:lib",
"build:clean": "rimraf bundles temp types",
"build:lib": "vite build --mode lib",
"build:types": "tsc -p tsconfig.lib.json",
"format": "prettier --write 'src/**/*.ts' 'test/**/*.ts' vite.*.ts",
"prepack": "npm run test:unit && npm run build",
"start": "vite dev --mode dev --open /examples/",
"start:e2e": "vite dev --mode e2e",
"test": "vitest run --mode test --coverage",
"test:unit": "vitest run --mode test",
"test:e2e": "npx playwright test"
},
"author": "Eric Simons",
"license": "MIT",
"devDependencies": {
"@playwright/test": "^1.32.2",
"@rollup/plugin-replace": "^5.0.2",
"@types/body-parser": "^1.19.2",
"@types/lodash": "^4.14.192",
"@vitest/coverage-c8": "^0.29.8",
"@vitest/ui": "^0.29.8",
"body-parser": "^1.20.2",
"happy-dom": "^9.1.0",
"lodash": "^4.17.21",
"prettier": "^2.8.7",
"rimraf": "^4.4.1",
"typescript": "~4.4.4",
"vite": "^4.2.1",
"vite-tsconfig-paths": "^4.0.8",
"vitest": "^0.29.8"
"microbundle": "~0.14.2",
"rimraf": "^3.0.2",
"typescript": "~4.4.0"
}
}
# StackBlitz SDK
The StackBlitz JavaScript SDK lets you programmatically create StackBlitz projects to be opened in a new window or embedded in your docs, example pages, or blog posts.
Wouldn't it be great if you could create StackBlitz projects on-demand from your docs, examples, blog posts?
## Documentation
This is exactly what the StackBlitz SDK allows you to do. Even better, the SDK even gives you full control of the StackBlitz VM - allowing you to build rich & interactive experiences around your projects. 😮 🙌
Check out our SDK documentation on developer.stackblitz.com:
The SDK is **3kB gzipped** (!) and you can install it from npm:
- [SDK overview](https://developer.stackblitz.com/platform/api/javascript-sdk)
- [Options reference](https://developer.stackblitz.com/platform/api/javascript-sdk-options)
- [Controlling embeds](https://developer.stackblitz.com/platform/api/javascript-sdk-vm)
## Reporting issues
- Issues with the SDK can be filed at https://github.com/stackblitz/sdk/issues
- Other issues with StackBlitz can be filed at https://github.com/stackblitz/core/issues
## Development
We use `npm` and Node 16+.
```sh
# Install dependencies
npm install
npm install --save @stackblitz/sdk
```
# Start a development server to explore examples
npm start
Or add a script tag to the UMD build on jsDelivr/Unpkg — the SDK will be available on `window` as `StackBlitzSDK`:
# Run unit tests
npm test
```html
<script src="https://unpkg.com/@stackblitz/sdk/bundles/sdk.umd.js"></script>
```
# Run end-to-end tests with mock server
npm run test:e2e
# Run end-to-end tests against stackblitz.com
STACKBLITZ_SERVER_ORIGIN=https://stackblitz.com npm run test:e2e
# Generate the 'bundles' and 'types' folders
npm run build
```
**Learn more on [developer.stackblitz.com](https://developer.stackblitz.com/docs/platform/javascript-sdk)**

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc